diff options
| author | Po Lu | 2022-01-07 14:35:29 +0800 |
|---|---|---|
| committer | Po Lu | 2022-01-07 14:42:08 +0800 |
| commit | 751789471cf04916bcfad358472625f382e596d8 (patch) | |
| tree | 329fa13c0e4972b34a1c1b95fa398a708bb246c5 /src | |
| parent | 48038cb2b2191980b3862be2c7d408e6ba6ee0d8 (diff) | |
| download | emacs-751789471cf04916bcfad358472625f382e596d8.tar.gz emacs-751789471cf04916bcfad358472625f382e596d8.zip | |
Display pre-edit information from X input methods
This also repurposes the `pgtk-preedit-text' event to be
meaningful on X, renames it `preedit-text', and documents it.
* doc/lispref/commands.texi (Misc Events): Document
`preedit-text'.
* lisp/term/pgtk-win.el (pgtk-preedit-text): Bind to
`preedit-text' instead.
* lisp/term/x-win.el (x-preedit-overlay): New variable.
(x-preedit-text): New command, bound as a special event to
`preedit-text'.
* src/keyboard.c (kbd_buffer_get_event):
(make_lispy_event): Rename PGTK_PREEDIT_TEXT_EVENT
PREEDIT_TEXT_EVENT.
(syms_of_keyboard): New defsym `preedit-text'.
* src/pgtkterm.c (pgtk_enqueue_preedit): Use PREEDIT_TEXT_EVENT
instead.
* src/termhooks.h (enum event_kind): Rename
`PGTK_PREEDIT_TEXT_EVENT' `PREEDIT_TEXT_EVENT'.
* src/xfns.c (Xxic_preedit_draw_callback):
(Xxic_preedit_caret_callback):
(Xxic_preedit_done_callback):
(Xxic_preedit_start_callback): New callback variables.
(STYLE_OFFTHESPOT, STYLE_OVERTHESPOT):
(STYLE_ROOT, STYLE_CALLBACK, STYLE_NONE): New macros.
(supported_xim_styles): Use reasonable values. This also serves
as a better fix for bug#10867.
(best_xim_style): Restore code deleted as part of the original
fix for bug#10867.
(create_frame_xic): Add preedit callbacks.
(xic_set_preeditarea): Add preedit callbacks.
(x_xic_to_frame):
(xic_preedit_start_callback):
(xic_preedit_caret_callback):
(xic_preedit_done_callback):
(x_xim_text_to_utf8_unix):
(xic_preedit_draw_callback): New functions.
* src/xterm.c (x_detect_focus_change): Fix type of XI event.
(x_free_frame_resources): Free preedit text buffer if still
present.
* src/xterm.h (struct x_output): New fields `preedit_size',
`preedit_chars' and `preedit_active'.
Diffstat (limited to 'src')
| -rw-r--r-- | src/keyboard.c | 14 | ||||
| -rw-r--r-- | src/pgtkterm.c | 2 | ||||
| -rw-r--r-- | src/termhooks.h | 4 | ||||
| -rw-r--r-- | src/xfns.c | 335 | ||||
| -rw-r--r-- | src/xterm.c | 5 | ||||
| -rw-r--r-- | src/xterm.h | 6 |
6 files changed, 345 insertions, 21 deletions
diff --git a/src/keyboard.c b/src/keyboard.c index ec1b7cd85d3..a9f3257282b 100644 --- a/src/keyboard.c +++ b/src/keyboard.c | |||
| @@ -3973,9 +3973,7 @@ kbd_buffer_get_event (KBOARD **kbp, | |||
| 3973 | *used_mouse_menu = true; | 3973 | *used_mouse_menu = true; |
| 3974 | FALLTHROUGH; | 3974 | FALLTHROUGH; |
| 3975 | #endif | 3975 | #endif |
| 3976 | #ifdef HAVE_PGTK | 3976 | case PREEDIT_TEXT_EVENT: |
| 3977 | case PGTK_PREEDIT_TEXT_EVENT: | ||
| 3978 | #endif | ||
| 3979 | #ifdef HAVE_NTGUI | 3977 | #ifdef HAVE_NTGUI |
| 3980 | case END_SESSION_EVENT: | 3978 | case END_SESSION_EVENT: |
| 3981 | case LANGUAGE_CHANGE_EVENT: | 3979 | case LANGUAGE_CHANGE_EVENT: |
| @@ -6289,10 +6287,8 @@ make_lispy_event (struct input_event *event) | |||
| 6289 | return list3 (Qconfig_changed_event, | 6287 | return list3 (Qconfig_changed_event, |
| 6290 | event->arg, event->frame_or_window); | 6288 | event->arg, event->frame_or_window); |
| 6291 | 6289 | ||
| 6292 | #ifdef HAVE_PGTK | 6290 | case PREEDIT_TEXT_EVENT: |
| 6293 | case PGTK_PREEDIT_TEXT_EVENT: | 6291 | return list2 (Qpreedit_text, event->arg); |
| 6294 | return list2 (intern ("pgtk-preedit-text"), event->arg); | ||
| 6295 | #endif | ||
| 6296 | 6292 | ||
| 6297 | /* The 'kind' field of the event is something we don't recognize. */ | 6293 | /* The 'kind' field of the event is something we don't recognize. */ |
| 6298 | default: | 6294 | default: |
| @@ -12003,6 +11999,8 @@ syms_of_keyboard (void) | |||
| 12003 | DEFSYM (Qno_record, "no-record"); | 11999 | DEFSYM (Qno_record, "no-record"); |
| 12004 | DEFSYM (Qencoded, "encoded"); | 12000 | DEFSYM (Qencoded, "encoded"); |
| 12005 | 12001 | ||
| 12002 | DEFSYM (Qpreedit_text, "preedit-text"); | ||
| 12003 | |||
| 12006 | button_down_location = make_nil_vector (5); | 12004 | button_down_location = make_nil_vector (5); |
| 12007 | staticpro (&button_down_location); | 12005 | staticpro (&button_down_location); |
| 12008 | staticpro (&frame_relative_event_pos); | 12006 | staticpro (&frame_relative_event_pos); |
| @@ -12771,8 +12769,6 @@ keys_of_keyboard (void) | |||
| 12771 | "ns-put-working-text"); | 12769 | "ns-put-working-text"); |
| 12772 | initial_define_lispy_key (Vspecial_event_map, "ns-unput-working-text", | 12770 | initial_define_lispy_key (Vspecial_event_map, "ns-unput-working-text", |
| 12773 | "ns-unput-working-text"); | 12771 | "ns-unput-working-text"); |
| 12774 | initial_define_lispy_key (Vspecial_event_map, "pgtk-preedit-text", | ||
| 12775 | "pgtk-preedit-text"); | ||
| 12776 | /* Here we used to use `ignore-event' which would simple set prefix-arg to | 12772 | /* Here we used to use `ignore-event' which would simple set prefix-arg to |
| 12777 | current-prefix-arg, as is done in `handle-switch-frame'. | 12773 | current-prefix-arg, as is done in `handle-switch-frame'. |
| 12778 | But `handle-switch-frame is not run from the special-map. | 12774 | But `handle-switch-frame is not run from the special-map. |
diff --git a/src/pgtkterm.c b/src/pgtkterm.c index 736fce09c4a..1d301d11f6f 100644 --- a/src/pgtkterm.c +++ b/src/pgtkterm.c | |||
| @@ -5259,7 +5259,7 @@ pgtk_enqueue_preedit (struct frame *f, Lisp_Object preedit) | |||
| 5259 | { | 5259 | { |
| 5260 | union buffered_input_event inev; | 5260 | union buffered_input_event inev; |
| 5261 | EVENT_INIT (inev.ie); | 5261 | EVENT_INIT (inev.ie); |
| 5262 | inev.ie.kind = PGTK_PREEDIT_TEXT_EVENT; | 5262 | inev.ie.kind = PREEDIT_TEXT_EVENT; |
| 5263 | inev.ie.arg = preedit; | 5263 | inev.ie.arg = preedit; |
| 5264 | inev.ie.code = 0; | 5264 | inev.ie.code = 0; |
| 5265 | XSETFRAME (inev.ie.frame_or_window, f); | 5265 | XSETFRAME (inev.ie.frame_or_window, f); |
diff --git a/src/termhooks.h b/src/termhooks.h index 55f7aa5d1ae..518e855eae1 100644 --- a/src/termhooks.h +++ b/src/termhooks.h | |||
| @@ -269,10 +269,8 @@ enum event_kind | |||
| 269 | , FILE_NOTIFY_EVENT | 269 | , FILE_NOTIFY_EVENT |
| 270 | #endif | 270 | #endif |
| 271 | 271 | ||
| 272 | #ifdef HAVE_PGTK | ||
| 273 | /* Pre-edit text was changed. */ | 272 | /* Pre-edit text was changed. */ |
| 274 | , PGTK_PREEDIT_TEXT_EVENT | 273 | , PREEDIT_TEXT_EVENT |
| 275 | #endif | ||
| 276 | 274 | ||
| 277 | /* Either the mouse wheel has been released without it being | 275 | /* Either the mouse wheel has been released without it being |
| 278 | clicked, or the user has lifted his finger from a touchpad. | 276 | clicked, or the user has lifted his finger from a touchpad. |
diff --git a/src/xfns.c b/src/xfns.c index b94fe179224..d87e67f95b1 100644 --- a/src/xfns.c +++ b/src/xfns.c | |||
| @@ -24,6 +24,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 24 | #include <unistd.h> | 24 | #include <unistd.h> |
| 25 | 25 | ||
| 26 | #include "lisp.h" | 26 | #include "lisp.h" |
| 27 | #include "character.h" | ||
| 27 | #include "xterm.h" | 28 | #include "xterm.h" |
| 28 | #include "frame.h" | 29 | #include "frame.h" |
| 29 | #include "window.h" | 30 | #include "window.h" |
| @@ -2330,8 +2331,19 @@ hack_wm_protocols (struct frame *f, Widget widget) | |||
| 2330 | 2331 | ||
| 2331 | #ifdef HAVE_X_I18N | 2332 | #ifdef HAVE_X_I18N |
| 2332 | 2333 | ||
| 2333 | static XFontSet xic_create_xfontset (struct frame *); | 2334 | static void xic_preedit_draw_callback (XIC, XPointer, XIMPreeditDrawCallbackStruct *); |
| 2334 | static XIMStyle best_xim_style (XIMStyles *); | 2335 | static void xic_preedit_caret_callback (XIC, XPointer, XIMPreeditCaretCallbackStruct *); |
| 2336 | static void xic_preedit_done_callback (XIC, XPointer, XPointer); | ||
| 2337 | static int xic_preedit_start_callback (XIC, XPointer, XPointer); | ||
| 2338 | |||
| 2339 | static XIMCallback Xxic_preedit_draw_callback = { NULL, | ||
| 2340 | (XIMProc) xic_preedit_draw_callback }; | ||
| 2341 | static XIMCallback Xxic_preedit_caret_callback = { NULL, | ||
| 2342 | (XIMProc) xic_preedit_caret_callback }; | ||
| 2343 | static XIMCallback Xxic_preedit_done_callback = { NULL, | ||
| 2344 | (XIMProc) xic_preedit_done_callback }; | ||
| 2345 | static XIMCallback Xxic_preedit_start_callback = { NULL, | ||
| 2346 | (void *) xic_preedit_start_callback }; | ||
| 2335 | 2347 | ||
| 2336 | #if defined HAVE_X_WINDOWS && defined USE_X_TOOLKIT | 2348 | #if defined HAVE_X_WINDOWS && defined USE_X_TOOLKIT |
| 2337 | /* Create an X fontset on frame F with base font name BASE_FONTNAME. */ | 2349 | /* Create an X fontset on frame F with base font name BASE_FONTNAME. */ |
| @@ -2608,6 +2620,23 @@ xic_free_xfontset (struct frame *f) | |||
| 2608 | FRAME_XIC_FONTSET (f) = NULL; | 2620 | FRAME_XIC_FONTSET (f) = NULL; |
| 2609 | } | 2621 | } |
| 2610 | 2622 | ||
| 2623 | /* Create XIC for frame F. */ | ||
| 2624 | |||
| 2625 | |||
| 2626 | #define STYLE_OFFTHESPOT (XIMPreeditArea | XIMStatusArea) | ||
| 2627 | #define STYLE_OVERTHESPOT (XIMPreeditPosition | XIMStatusNothing) | ||
| 2628 | #define STYLE_ROOT (XIMPreeditNothing | XIMStatusNothing) | ||
| 2629 | #define STYLE_CALLBACK (XIMPreeditCallbacks | XIMStatusNothing) | ||
| 2630 | #define STYLE_NONE (XIMPreeditNothing | XIMStatusNothing) | ||
| 2631 | |||
| 2632 | static const XIMStyle supported_xim_styles[] = | ||
| 2633 | { | ||
| 2634 | STYLE_CALLBACK, | ||
| 2635 | STYLE_NONE, | ||
| 2636 | STYLE_OVERTHESPOT, | ||
| 2637 | STYLE_OFFTHESPOT, | ||
| 2638 | STYLE_ROOT | ||
| 2639 | }; | ||
| 2611 | 2640 | ||
| 2612 | /* Value is the best input style, given user preferences USER (already | 2641 | /* Value is the best input style, given user preferences USER (already |
| 2613 | checked to be supported by Emacs), and styles supported by the | 2642 | checked to be supported by Emacs), and styles supported by the |
| @@ -2616,8 +2645,15 @@ xic_free_xfontset (struct frame *f) | |||
| 2616 | static XIMStyle | 2645 | static XIMStyle |
| 2617 | best_xim_style (XIMStyles *xim) | 2646 | best_xim_style (XIMStyles *xim) |
| 2618 | { | 2647 | { |
| 2619 | /* Return the default style. This is what GTK3 uses and | 2648 | int i, j; |
| 2620 | should work fine with all modern input methods. */ | 2649 | int nr_supported = ARRAYELTS (supported_xim_styles); |
| 2650 | |||
| 2651 | for (i = 0; i < nr_supported; ++i) | ||
| 2652 | for (j = 0; j < xim->count_styles; ++j) | ||
| 2653 | if (supported_xim_styles[i] == xim->supported_styles[j]) | ||
| 2654 | return supported_xim_styles[i]; | ||
| 2655 | |||
| 2656 | /* Return the default style. */ | ||
| 2621 | return XIMPreeditNothing | XIMStatusNothing; | 2657 | return XIMPreeditNothing | XIMStatusNothing; |
| 2622 | } | 2658 | } |
| 2623 | 2659 | ||
| @@ -2692,6 +2728,22 @@ create_frame_xic (struct frame *f) | |||
| 2692 | goto out; | 2728 | goto out; |
| 2693 | } | 2729 | } |
| 2694 | 2730 | ||
| 2731 | if (xic_style & XIMPreeditCallbacks) | ||
| 2732 | { | ||
| 2733 | spot.x = 0; | ||
| 2734 | spot.y = 0; | ||
| 2735 | preedit_attr = XVaCreateNestedList (0, | ||
| 2736 | XNSpotLocation, &spot, | ||
| 2737 | XNPreeditStartCallback, &Xxic_preedit_start_callback, | ||
| 2738 | XNPreeditDoneCallback, &Xxic_preedit_done_callback, | ||
| 2739 | XNPreeditDrawCallback, &Xxic_preedit_draw_callback, | ||
| 2740 | XNPreeditCaretCallback, &Xxic_preedit_caret_callback, | ||
| 2741 | NULL); | ||
| 2742 | |||
| 2743 | if (!preedit_attr) | ||
| 2744 | goto out; | ||
| 2745 | } | ||
| 2746 | |||
| 2695 | if (preedit_attr && status_attr) | 2747 | if (preedit_attr && status_attr) |
| 2696 | xic = XCreateIC (xim, | 2748 | xic = XCreateIC (xim, |
| 2697 | XNInputStyle, xic_style, | 2749 | XNInputStyle, xic_style, |
| @@ -2768,7 +2820,12 @@ xic_set_preeditarea (struct window *w, int x, int y) | |||
| 2768 | 2820 | ||
| 2769 | spot.x = WINDOW_TO_FRAME_PIXEL_X (w, x) + WINDOW_LEFT_FRINGE_WIDTH (w) + WINDOW_LEFT_MARGIN_WIDTH(w); | 2821 | spot.x = WINDOW_TO_FRAME_PIXEL_X (w, x) + WINDOW_LEFT_FRINGE_WIDTH (w) + WINDOW_LEFT_MARGIN_WIDTH(w); |
| 2770 | spot.y = WINDOW_TO_FRAME_PIXEL_Y (w, y) + FONT_BASE (FRAME_FONT (f)); | 2822 | spot.y = WINDOW_TO_FRAME_PIXEL_Y (w, y) + FONT_BASE (FRAME_FONT (f)); |
| 2771 | attr = XVaCreateNestedList (0, XNSpotLocation, &spot, NULL); | 2823 | attr = XVaCreateNestedList (0, XNSpotLocation, &spot, |
| 2824 | XNPreeditStartCallback, &Xxic_preedit_start_callback, | ||
| 2825 | XNPreeditDoneCallback, &Xxic_preedit_done_callback, | ||
| 2826 | XNPreeditDrawCallback, &Xxic_preedit_draw_callback, | ||
| 2827 | XNPreeditCaretCallback, &Xxic_preedit_caret_callback, | ||
| 2828 | NULL); | ||
| 2772 | XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL); | 2829 | XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL); |
| 2773 | XFree (attr); | 2830 | XFree (attr); |
| 2774 | } | 2831 | } |
| @@ -2816,9 +2873,273 @@ xic_set_statusarea (struct frame *f) | |||
| 2816 | XFree (attr); | 2873 | XFree (attr); |
| 2817 | } | 2874 | } |
| 2818 | 2875 | ||
| 2876 | static struct frame * | ||
| 2877 | x_xic_to_frame (XIC xic) | ||
| 2878 | { | ||
| 2879 | Lisp_Object tail, tem; | ||
| 2880 | struct frame *f; | ||
| 2881 | |||
| 2882 | FOR_EACH_FRAME (tail, tem) | ||
| 2883 | { | ||
| 2884 | f = XFRAME (tem); | ||
| 2885 | |||
| 2886 | if (FRAME_X_P (f) && FRAME_XIC (f) == xic) | ||
| 2887 | return f; | ||
| 2888 | } | ||
| 2889 | |||
| 2890 | return NULL; | ||
| 2891 | } | ||
| 2892 | |||
| 2893 | static int | ||
| 2894 | xic_preedit_start_callback (XIC xic, XPointer client_data, | ||
| 2895 | XPointer call_data) | ||
| 2896 | { | ||
| 2897 | struct frame *f = x_xic_to_frame (xic); | ||
| 2898 | struct x_output *output; | ||
| 2899 | |||
| 2900 | if (f) | ||
| 2901 | { | ||
| 2902 | output = FRAME_X_OUTPUT (f); | ||
| 2903 | |||
| 2904 | output->preedit_size = 0; | ||
| 2905 | output->preedit_active = true; | ||
| 2906 | |||
| 2907 | if (output->preedit_chars) | ||
| 2908 | xfree (output->preedit_chars); | ||
| 2909 | |||
| 2910 | output->preedit_chars = NULL; | ||
| 2911 | } | ||
| 2912 | |||
| 2913 | return -1; | ||
| 2914 | } | ||
| 2915 | |||
| 2916 | static void | ||
| 2917 | xic_preedit_caret_callback (XIC xic, XPointer client_data, | ||
| 2918 | XIMPreeditCaretCallbackStruct *call_data) | ||
| 2919 | { | ||
| 2920 | |||
| 2921 | } | ||
| 2922 | |||
| 2923 | |||
| 2924 | static void | ||
| 2925 | xic_preedit_done_callback (XIC xic, XPointer client_data, | ||
| 2926 | XPointer call_data) | ||
| 2927 | { | ||
| 2928 | struct frame *f = x_xic_to_frame (xic); | ||
| 2929 | struct x_output *output; | ||
| 2930 | struct input_event ie; | ||
| 2931 | |||
| 2932 | if (f) | ||
| 2933 | { | ||
| 2934 | ie.kind = PREEDIT_TEXT_EVENT; | ||
| 2935 | ie.arg = Qnil; | ||
| 2936 | XSETFRAME (ie.frame_or_window, f); | ||
| 2937 | XSETINT (ie.x, 0); | ||
| 2938 | XSETINT (ie.y, 0); | ||
| 2939 | kbd_buffer_store_event (&ie); | ||
| 2940 | |||
| 2941 | output = FRAME_X_OUTPUT (f); | ||
| 2942 | |||
| 2943 | if (output->preedit_chars) | ||
| 2944 | xfree (output->preedit_chars); | ||
| 2945 | |||
| 2946 | output->preedit_size = 0; | ||
| 2947 | output->preedit_active = false; | ||
| 2948 | output->preedit_chars = NULL; | ||
| 2949 | } | ||
| 2950 | } | ||
| 2951 | |||
| 2952 | /* The string returned is not null-terminated. */ | ||
| 2953 | static char * | ||
| 2954 | x_xim_text_to_utf8_unix (XIMText *text, ptrdiff_t *length) | ||
| 2955 | { | ||
| 2956 | unsigned char *wchar_buf; | ||
| 2957 | ptrdiff_t wchar_actual_length, i; | ||
| 2958 | ptrdiff_t nbytes; | ||
| 2959 | struct coding_system coding; | ||
| 2960 | |||
| 2961 | if (text->encoding_is_wchar) | ||
| 2962 | { | ||
| 2963 | wchar_buf = xmalloc ((text->length + 1) * MAX_MULTIBYTE_LENGTH); | ||
| 2964 | wchar_actual_length = 0; | ||
| 2965 | |||
| 2966 | for (i = 0; i < text->length; ++i) | ||
| 2967 | wchar_actual_length += CHAR_STRING (text->string.wide_char[i], | ||
| 2968 | wchar_buf + wchar_actual_length); | ||
| 2969 | *length = wchar_actual_length; | ||
| 2970 | |||
| 2971 | return (char *) wchar_buf; | ||
| 2972 | } | ||
| 2973 | |||
| 2974 | nbytes = strlen (text->string.multi_byte); | ||
| 2975 | setup_coding_system (Qutf_8_unix, &coding); | ||
| 2976 | coding.mode |= (CODING_MODE_LAST_BLOCK | ||
| 2977 | | CODING_MODE_SAFE_ENCODING); | ||
| 2978 | coding.source = (const unsigned char *) text->string.multi_byte; | ||
| 2979 | coding.dst_bytes = 2048; | ||
| 2980 | coding.destination = xmalloc (2048); | ||
| 2981 | decode_coding_object (&coding, Qnil, 0, 0, nbytes, nbytes, Qnil); | ||
| 2982 | |||
| 2983 | /* coding.destination has either been allocated by us, or | ||
| 2984 | reallocated by decode_coding_object. */ | ||
| 2985 | |||
| 2986 | *length = coding.produced; | ||
| 2987 | return (char *) coding.destination; | ||
| 2988 | } | ||
| 2989 | |||
| 2990 | static void | ||
| 2991 | xic_preedit_draw_callback (XIC xic, XPointer client_data, | ||
| 2992 | XIMPreeditDrawCallbackStruct *call_data) | ||
| 2993 | { | ||
| 2994 | struct frame *f = x_xic_to_frame (xic); | ||
| 2995 | struct x_output *output; | ||
| 2996 | ptrdiff_t text_length; | ||
| 2997 | ptrdiff_t charpos; | ||
| 2998 | ptrdiff_t original_size; | ||
| 2999 | char *text; | ||
| 3000 | char *chg_start, *chg_end; | ||
| 3001 | struct input_event ie; | ||
| 3002 | |||
| 3003 | if (f) | ||
| 3004 | { | ||
| 3005 | output = FRAME_X_OUTPUT (f); | ||
| 3006 | |||
| 3007 | if (!output->preedit_active) | ||
| 3008 | return; | ||
| 3009 | |||
| 3010 | if (call_data->text) | ||
| 3011 | text = x_xim_text_to_utf8_unix (call_data->text, &text_length); | ||
| 3012 | else | ||
| 3013 | text = NULL; | ||
| 3014 | |||
| 3015 | original_size = output->preedit_size; | ||
| 3016 | |||
| 3017 | /* This is an ordinary insertion: reallocate the buffer to hold | ||
| 3018 | enough for TEXT. */ | ||
| 3019 | if (!call_data->chg_length) | ||
| 3020 | { | ||
| 3021 | if (!text) | ||
| 3022 | goto im_abort; | ||
| 3023 | |||
| 3024 | if (output->preedit_chars) | ||
| 3025 | output->preedit_chars = xrealloc (output->preedit_chars, | ||
| 3026 | output->preedit_size += text_length); | ||
| 3027 | else | ||
| 3028 | output->preedit_chars = xmalloc (output->preedit_size += text_length); | ||
| 3029 | } | ||
| 3030 | |||
| 3031 | chg_start = output->preedit_chars; | ||
| 3032 | |||
| 3033 | /* The IM sent bad data: the buffer is empty, but the change | ||
| 3034 | position is more than 0. */ | ||
| 3035 | if (!output->preedit_chars && call_data->chg_first) | ||
| 3036 | goto im_abort; | ||
| 3037 | |||
| 3038 | /* Find the byte position for the character position where the | ||
| 3039 | first change is to be made. */ | ||
| 3040 | if (call_data->chg_first) | ||
| 3041 | { | ||
| 3042 | charpos = 0; | ||
| 3043 | |||
| 3044 | while (charpos < call_data->chg_first) | ||
| 3045 | { | ||
| 3046 | chg_start += BYTES_BY_CHAR_HEAD (*chg_start); | ||
| 3047 | |||
| 3048 | if ((chg_start - output->preedit_chars) > output->preedit_size) | ||
| 3049 | /* The IM sent bad data: chg_start is larger than the | ||
| 3050 | current buffer. */ | ||
| 3051 | goto im_abort; | ||
| 3052 | ++charpos; | ||
| 3053 | } | ||
| 3054 | } | ||
| 3055 | |||
| 3056 | if (!call_data->chg_length) | ||
| 3057 | { | ||
| 3058 | if (!text) | ||
| 3059 | goto im_abort; | ||
| 3060 | |||
| 3061 | memmove (chg_start + text_length, chg_start, | ||
| 3062 | original_size - (chg_start - output->preedit_chars)); | ||
| 3063 | memcpy (chg_start, text, text_length); | ||
| 3064 | } | ||
| 3065 | else | ||
| 3066 | { | ||
| 3067 | if (call_data->chg_length < 1) | ||
| 3068 | goto im_abort; | ||
| 3069 | |||
| 3070 | charpos = 0; | ||
| 3071 | chg_end = chg_start; | ||
| 3072 | |||
| 3073 | while (charpos < call_data->chg_length) | ||
| 3074 | { | ||
| 3075 | chg_end += BYTES_BY_CHAR_HEAD (*chg_end); | ||
| 3076 | |||
| 3077 | if ((chg_end - output->preedit_chars) > output->preedit_size) | ||
| 3078 | /* The IM sent bad data: chg_end ends someplace outside | ||
| 3079 | the current buffer. */ | ||
| 3080 | goto im_abort; | ||
| 3081 | ++charpos; | ||
| 3082 | } | ||
| 3083 | |||
| 3084 | memmove (chg_start, chg_end, ((output->preedit_chars | ||
| 3085 | + output->preedit_size) - chg_end)); | ||
| 3086 | output->preedit_size -= (chg_end - chg_start); | ||
| 3087 | |||
| 3088 | if (text) | ||
| 3089 | { | ||
| 3090 | original_size = output->preedit_size; | ||
| 3091 | output->preedit_chars = xrealloc (output->preedit_chars, | ||
| 3092 | output->preedit_size += text_length); | ||
| 3093 | |||
| 3094 | /* Find chg_start again, since preedit_chars was reallocated. */ | ||
| 3095 | |||
| 3096 | chg_start = output->preedit_chars; | ||
| 3097 | charpos = 0; | ||
| 2819 | 3098 | ||
| 2820 | /* Set X fontset for XIC of frame F, using base font name | 3099 | while (charpos < call_data->chg_first) |
| 2821 | BASE_FONTNAME. Called when a new Emacs fontset is chosen. */ | 3100 | { |
| 3101 | chg_start += BYTES_BY_CHAR_HEAD (*chg_start); | ||
| 3102 | |||
| 3103 | if ((chg_start - output->preedit_chars) > output->preedit_size) | ||
| 3104 | /* The IM sent bad data: chg_start is larger than the | ||
| 3105 | current buffer. */ | ||
| 3106 | goto im_abort; | ||
| 3107 | ++charpos; | ||
| 3108 | } | ||
| 3109 | |||
| 3110 | memmove (chg_start + text_length, chg_start, | ||
| 3111 | original_size - (chg_start - output->preedit_chars)); | ||
| 3112 | memcpy (chg_start, text, text_length); | ||
| 3113 | } | ||
| 3114 | } | ||
| 3115 | |||
| 3116 | if (text) | ||
| 3117 | xfree (text); | ||
| 3118 | |||
| 3119 | /* This is okay because this callback is called from the big XIM | ||
| 3120 | event filter, which runs inside XTread_socket. */ | ||
| 3121 | |||
| 3122 | ie.kind = PREEDIT_TEXT_EVENT; | ||
| 3123 | XSETFRAME (ie.frame_or_window, f); | ||
| 3124 | ie.arg = make_string_from_utf8 (output->preedit_chars, | ||
| 3125 | output->preedit_size); | ||
| 3126 | XSETINT (ie.x, 0); | ||
| 3127 | XSETINT (ie.y, 0); | ||
| 3128 | |||
| 3129 | kbd_buffer_store_event (&ie); | ||
| 3130 | } | ||
| 3131 | |||
| 3132 | return; | ||
| 3133 | |||
| 3134 | im_abort: | ||
| 3135 | if (text) | ||
| 3136 | xfree (text); | ||
| 3137 | if (output->preedit_chars) | ||
| 3138 | xfree (output->preedit_chars); | ||
| 3139 | output->preedit_chars = NULL; | ||
| 3140 | output->preedit_size = 0; | ||
| 3141 | output->preedit_active = false; | ||
| 3142 | } | ||
| 2822 | 3143 | ||
| 2823 | void | 3144 | void |
| 2824 | xic_set_xfontset (struct frame *f, const char *base_fontname) | 3145 | xic_set_xfontset (struct frame *f, const char *base_fontname) |
diff --git a/src/xterm.c b/src/xterm.c index 1d4c775753c..73c0bcf89ea 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -5198,7 +5198,7 @@ x_detect_focus_change (struct x_display_info *dpyinfo, struct frame *frame, | |||
| 5198 | #ifdef HAVE_XINPUT2 | 5198 | #ifdef HAVE_XINPUT2 |
| 5199 | case GenericEvent: | 5199 | case GenericEvent: |
| 5200 | { | 5200 | { |
| 5201 | XIEvent *xi_event = (XIEvent *) event; | 5201 | XIEvent *xi_event = (XIEvent *) event->xcookie.data; |
| 5202 | 5202 | ||
| 5203 | struct frame *focus_frame = dpyinfo->x_focus_event_frame; | 5203 | struct frame *focus_frame = dpyinfo->x_focus_event_frame; |
| 5204 | int focus_state | 5204 | int focus_state |
| @@ -14046,6 +14046,9 @@ x_free_frame_resources (struct frame *f) | |||
| 14046 | #ifdef HAVE_X_I18N | 14046 | #ifdef HAVE_X_I18N |
| 14047 | if (FRAME_XIC (f)) | 14047 | if (FRAME_XIC (f)) |
| 14048 | free_frame_xic (f); | 14048 | free_frame_xic (f); |
| 14049 | |||
| 14050 | if (f->output_data.x->preedit_chars) | ||
| 14051 | xfree (f->output_data.x->preedit_chars); | ||
| 14049 | #endif | 14052 | #endif |
| 14050 | 14053 | ||
| 14051 | #ifdef USE_CAIRO | 14054 | #ifdef USE_CAIRO |
diff --git a/src/xterm.h b/src/xterm.h index d4600bdf800..dcac5732527 100644 --- a/src/xterm.h +++ b/src/xterm.h | |||
| @@ -788,6 +788,12 @@ struct x_output | |||
| 788 | They are used when creating the cairo surface next time. */ | 788 | They are used when creating the cairo surface next time. */ |
| 789 | int cr_surface_desired_width, cr_surface_desired_height; | 789 | int cr_surface_desired_width, cr_surface_desired_height; |
| 790 | #endif | 790 | #endif |
| 791 | |||
| 792 | #ifdef HAVE_X_I18N | ||
| 793 | ptrdiff_t preedit_size; | ||
| 794 | char *preedit_chars; | ||
| 795 | bool preedit_active; | ||
| 796 | #endif | ||
| 791 | }; | 797 | }; |
| 792 | 798 | ||
| 793 | enum | 799 | enum |