aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2022-01-08 15:21:51 +0800
committerPo Lu2022-01-08 15:21:51 +0800
commitd76fb0c11e9859db0d03d6496f5a720d304f4ca9 (patch)
tree89035fe1de1c0835716c45c9747e74128308e039 /src
parent63c83e40dad88036d5ceef17eace51056a18b55f (diff)
downloademacs-d76fb0c11e9859db0d03d6496f5a720d304f4ca9.tar.gz
emacs-d76fb0c11e9859db0d03d6496f5a720d304f4ca9.zip
Allow using GTK+ to handle input methods on X
* doc/emacs/xresources.texi (Table of Resources): Document new value of `inputStyle'. * etc/NEWS: Announce new option. * lisp/cus-start.el (standard): Add `x-gtk-use-native-input'. * src/gtkutil.c (xg_mark_data): Mark xg_pending_quit_event. (xg_add_virtual_mods): (xg_im_context_commit): (xg_im_context_preedit_changed): (xg_im_context_preedit_end): (xg_widget_key_press_event_cb): (xg_filter_key): New functions. * src/gtkutil.h: Add prototype for `xg_filter_key'. * src/xfns.c (xic_set_preeditarea): Set cursor location for the GTK IM context as well. * src/xterm.c (xg_pending_quit_event): New variable. (x_focus_changed): Set focus on the GTK input context as well. (x_filter_event): Filter events through GTK if the user asked for it. (handle_one_xevent): Likewise. (XTread_socket): Set hold_quit to xg_pending_quit_event if it exists. (x_draw_window_cursor): Always set preedit area even if XIC doesn't exist. * src/xterm.h (struct x_display_info): New field `prefer_native_input'. (struct x_output): New field `im_context'.
Diffstat (limited to 'src')
-rw-r--r--src/gtkutil.c354
-rw-r--r--src/gtkutil.h2
-rw-r--r--src/xfns.c37
-rw-r--r--src/xterm.c114
-rw-r--r--src/xterm.h10
5 files changed, 500 insertions, 17 deletions
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 93f51d77962..4c516a4479a 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -76,6 +76,13 @@ typedef struct pgtk_output xp_output;
76#define XG_TEXT_OPEN GTK_STOCK_OPEN 76#define XG_TEXT_OPEN GTK_STOCK_OPEN
77#endif 77#endif
78 78
79#ifndef HAVE_PGTK
80static void xg_im_context_commit (GtkIMContext *, gchar *, gpointer);
81static void xg_im_context_preedit_changed (GtkIMContext *, gpointer);
82static void xg_im_context_preedit_end (GtkIMContext *, gpointer);
83static bool xg_widget_key_press_event_cb (GtkWidget *, GdkEvent *, gpointer);
84#endif
85
79#ifndef HAVE_GTK3 86#ifndef HAVE_GTK3
80 87
81#ifdef HAVE_FREETYPE 88#ifdef HAVE_FREETYPE
@@ -1437,6 +1444,9 @@ xg_create_frame_widgets (struct frame *f)
1437#ifndef HAVE_GTK3 1444#ifndef HAVE_GTK3
1438 GtkRcStyle *style; 1445 GtkRcStyle *style;
1439#endif 1446#endif
1447#ifndef HAVE_PGTK
1448 GtkIMContext *imc;
1449#endif
1440 GtkWindowType type = GTK_WINDOW_TOPLEVEL; 1450 GtkWindowType type = GTK_WINDOW_TOPLEVEL;
1441 char *title = 0; 1451 char *title = 0;
1442 1452
@@ -1621,6 +1631,22 @@ xg_create_frame_widgets (struct frame *f)
1621#ifndef HAVE_PGTK 1631#ifndef HAVE_PGTK
1622 gtk_widget_set_tooltip_text (wtop, "Dummy text"); 1632 gtk_widget_set_tooltip_text (wtop, "Dummy text");
1623 g_signal_connect (wtop, "query-tooltip", G_CALLBACK (qttip_cb), f); 1633 g_signal_connect (wtop, "query-tooltip", G_CALLBACK (qttip_cb), f);
1634
1635 imc = gtk_im_multicontext_new ();
1636 g_object_ref (imc);
1637 gtk_im_context_set_use_preedit (imc, TRUE);
1638
1639 g_signal_connect (G_OBJECT (imc), "commit",
1640 G_CALLBACK (xg_im_context_commit), f);
1641 g_signal_connect (G_OBJECT (imc), "preedit-changed",
1642 G_CALLBACK (xg_im_context_preedit_changed), NULL);
1643 g_signal_connect (G_OBJECT (imc), "preedit-end",
1644 G_CALLBACK (xg_im_context_preedit_end), NULL);
1645 FRAME_X_OUTPUT (f)->im_context = imc;
1646
1647 g_signal_connect (G_OBJECT (wfixed), "key-press-event",
1648 G_CALLBACK (xg_widget_key_press_event_cb),
1649 NULL);
1624#endif 1650#endif
1625 1651
1626 { 1652 {
@@ -1761,6 +1787,7 @@ xg_free_frame_widgets (struct frame *f)
1761 /* x_free_frame_resources should have taken care of it */ 1787 /* x_free_frame_resources should have taken care of it */
1762#ifndef HAVE_PGTK 1788#ifndef HAVE_PGTK
1763 eassert (!FRAME_X_DOUBLE_BUFFERED_P (f)); 1789 eassert (!FRAME_X_DOUBLE_BUFFERED_P (f));
1790 g_object_unref (FRAME_X_OUTPUT (f)->im_context);
1764#endif 1791#endif
1765 gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f)); 1792 gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f));
1766 FRAME_X_WINDOW (f) = 0; /* Set to avoid XDestroyWindow in xterm.c */ 1793 FRAME_X_WINDOW (f) = 0; /* Set to avoid XDestroyWindow in xterm.c */
@@ -2928,6 +2955,14 @@ xg_mark_data (void)
2928 } 2955 }
2929 } 2956 }
2930 } 2957 }
2958
2959 if (xg_pending_quit_event.kind != NO_EVENT)
2960 {
2961 eassert (xg_pending_quit_event.kind == ASCII_KEYSTROKE_EVENT);
2962
2963 mark_object (xg_pending_quit_event.frame_or_window);
2964 mark_object (xg_pending_quit_event.arg);
2965 }
2931} 2966}
2932 2967
2933/* Callback called when a menu item is destroyed. Used to free data. 2968/* Callback called when a menu item is destroyed. Used to free data.
@@ -5963,4 +5998,323 @@ xg_initialize (void)
5963#endif 5998#endif
5964} 5999}
5965 6000
6001#ifndef HAVE_PGTK
6002static void
6003xg_add_virtual_mods (struct x_display_info *dpyinfo, GdkEventKey *key)
6004{
6005 guint modifiers = key->state;
6006
6007 if (modifiers & dpyinfo->meta_mod_mask)
6008 {
6009 /* GDK always assumes Mod1 is alt, but that's no reason for
6010 us to make that mistake as well. */
6011 if (!dpyinfo->alt_mod_mask)
6012 key->state |= GDK_MOD1_MASK;
6013 else
6014 key->state |= GDK_META_MASK;
6015 }
6016
6017 if (modifiers & dpyinfo->alt_mod_mask)
6018 key->state |= GDK_MOD1_MASK;
6019 if (modifiers & dpyinfo->super_mod_mask)
6020 key->state |= GDK_SUPER_MASK;
6021 if (modifiers & dpyinfo->hyper_mod_mask)
6022 key->state |= GDK_HYPER_MASK;
6023}
6024
6025static void
6026xg_im_context_commit (GtkIMContext *imc, gchar *str,
6027 gpointer user_data)
6028{
6029 struct frame *f = user_data;
6030 struct input_event ie;
6031 gunichar *ucs4_str;
6032
6033 ucs4_str = g_utf8_to_ucs4_fast (str, -1, NULL);
6034
6035 if (!ucs4_str)
6036 return;
6037
6038 for (gunichar *c = ucs4_str; *c; c++)
6039 {
6040 EVENT_INIT (ie);
6041 ie.kind = (SINGLE_BYTE_CHAR_P (*c)
6042 ? ASCII_KEYSTROKE_EVENT
6043 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
6044 ie.arg = Qnil;
6045 ie.code = *c;
6046 XSETFRAME (ie.frame_or_window, f);
6047 ie.modifiers = 0;
6048 ie.timestamp = 0;
6049
6050 kbd_buffer_store_event (&ie);
6051 }
6052
6053 g_free (ucs4_str);
6054}
6055
6056static void
6057xg_im_context_preedit_changed (GtkIMContext *imc, gpointer user_data)
6058{
6059 PangoAttrList *list;
6060 gchar *str;
6061 gint cursor;
6062 struct input_event inev;
6063
6064 gtk_im_context_get_preedit_string (imc, &str, &list, &cursor);
6065
6066 EVENT_INIT (inev);
6067 inev.kind = PREEDIT_TEXT_EVENT;
6068 inev.arg = build_string_from_utf8 (str);
6069 kbd_buffer_store_event (&inev);
6070
6071 g_free (str);
6072 pango_attr_list_unref (list);
6073}
6074
6075static void
6076xg_im_context_preedit_end (GtkIMContext *imc, gpointer user_data)
6077{
6078 struct input_event inev;
6079
6080 EVENT_INIT (inev);
6081 inev.kind = PREEDIT_TEXT_EVENT;
6082 inev.arg = Qnil;
6083 kbd_buffer_store_event (&inev);
6084}
6085
6086static bool
6087xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event,
6088 gpointer user_data)
6089{
6090 Lisp_Object tail, tem;
6091 struct frame *f = NULL;
6092 union buffered_input_event inev;
6093 guint keysym = event->key.keyval;
6094 gunichar *cb;
6095 ptrdiff_t i;
6096 glong len;
6097
6098 FOR_EACH_FRAME (tail, tem)
6099 {
6100 if (FRAME_X_P (XFRAME (tem))
6101 && (FRAME_GTK_WIDGET (XFRAME (tem)) == widget))
6102 {
6103 f = XFRAME (tem);
6104 break;
6105 }
6106 }
6107
6108 if (!f)
6109 return true;
6110
6111 if (!x_gtk_use_native_input
6112 && !FRAME_DISPLAY_INFO (f)->prefer_native_input)
6113 return true;
6114
6115 EVENT_INIT (inev.ie);
6116 XSETFRAME (inev.ie.frame_or_window, f);
6117
6118 inev.ie.modifiers |= x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f),
6119 event->key.state);
6120
6121 /* First deal with keysyms which have defined
6122 translations to characters. */
6123 if (keysym >= 32 && keysym < 128)
6124 /* Avoid explicitly decoding each ASCII character. */
6125 {
6126 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
6127 inev.ie.code = keysym;
6128 goto done;
6129 }
6130
6131 /* Keysyms directly mapped to Unicode characters. */
6132 if (keysym >= 0x01000000 && keysym <= 0x0110FFFF)
6133 {
6134 if (keysym < 0x01000080)
6135 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
6136 else
6137 inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
6138 inev.ie.code = keysym & 0xFFFFFF;
6139 goto done;
6140 }
6141
6142 /* Random non-modifier sorts of keysyms. */
6143 if (((keysym >= GDK_KEY_BackSpace && keysym <= GDK_KEY_Escape)
6144 || keysym == GDK_KEY_Delete
6145#ifdef GDK_KEY_ISO_Left_Tab
6146 || (keysym >= GDK_KEY_ISO_Left_Tab && keysym <= GDK_KEY_ISO_Enter)
6147#endif
6148 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
6149 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
6150#ifdef GDK_KEY_dead_circumflex
6151 || keysym == GDK_KEY_dead_circumflex
6152#endif
6153#ifdef GDK_KEY_dead_grave
6154 || keysym == GDK_KEY_dead_grave
6155#endif
6156#ifdef GDK_KEY_dead_tilde
6157 || keysym == GDK_KEY_dead_tilde
6158#endif
6159#ifdef GDK_KEY_dead_diaeresis
6160 || keysym == GDK_KEY_dead_diaeresis
6161#endif
6162#ifdef GDK_KEY_dead_macron
6163 || keysym == GDK_KEY_dead_macron
6164#endif
6165#ifdef GDK_KEY_dead_degree
6166 || keysym == GDK_KEY_dead_degree
6167#endif
6168#ifdef GDK_KEY_dead_acute
6169 || keysym == GDK_KEY_dead_acute
6170#endif
6171#ifdef GDK_KEY_dead_cedilla
6172 || keysym == GDK_KEY_dead_cedilla
6173#endif
6174#ifdef GDK_KEY_dead_breve
6175 || keysym == GDK_KEY_dead_breve
6176#endif
6177#ifdef GDK_KEY_dead_ogonek
6178 || keysym == GDK_KEY_dead_ogonek
6179#endif
6180#ifdef GDK_KEY_dead_caron
6181 || keysym == GDK_KEY_dead_caron
6182#endif
6183#ifdef GDK_KEY_dead_doubleacute
6184 || keysym == GDK_KEY_dead_doubleacute
6185#endif
6186#ifdef GDK_KEY_dead_abovedot
6187 || keysym == GDK_KEY_dead_abovedot
6188#endif
6189 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
6190 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
6191 /* Any "vendor-specific" key is ok. */
6192 || (keysym & (1 << 28))
6193 || (keysym != GDK_KEY_VoidSymbol && !event->key.string))
6194 && !(event->key.is_modifier))
6195 {
6196 inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT;
6197 inev.ie.code = keysym;
6198 goto done;
6199 }
6200
6201 if (event->key.string)
6202 {
6203 cb = g_utf8_to_ucs4_fast (event->key.string, -1, &len);
6204
6205 for (i = 0; i < len; ++i)
6206 {
6207 inev.ie.kind = (SINGLE_BYTE_CHAR_P (cb[i])
6208 ? ASCII_KEYSTROKE_EVENT
6209 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
6210 inev.ie.code = cb[i];
6211
6212 kbd_buffer_store_buffered_event (&inev, &xg_pending_quit_event);
6213 }
6214
6215 g_free (cb);
6216
6217 inev.ie.kind = NO_EVENT;
6218 }
6219
6220 done:
6221 if (inev.ie.kind != NO_EVENT)
6222 {
6223 xg_pending_quit_event.kind = NO_EVENT;
6224 kbd_buffer_store_buffered_event (&inev, &xg_pending_quit_event);
6225 }
6226 return true;
6227}
6228
6229bool
6230xg_filter_key (struct frame *frame, XEvent *xkey)
6231{
6232 GdkEvent *xg_event = gdk_event_new (GDK_KEY_PRESS);
6233 GdkDisplay *dpy = gtk_widget_get_display (FRAME_GTK_WIDGET (frame));
6234 GdkKeymap *keymap = gdk_keymap_get_for_display (dpy);
6235 GdkModifierType consumed;
6236 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
6237 bool result;
6238
6239 xg_event->any.window = gtk_widget_get_window (FRAME_GTK_WIDGET (frame));
6240 g_object_ref (xg_event->any.window);
6241
6242#if GTK_CHECK_VERSION (3, 20, 0)
6243 GdkSeat *seat = gdk_display_get_default_seat (dpy);
6244
6245 gdk_event_set_device (xg_event,
6246 gdk_seat_get_keyboard (seat));
6247#elif GTK_CHECK_VERSION (3, 16, 0)
6248 GdkDeviceManager *manager = gdk_display_get_device_manager (dpy);
6249 GList *devices = gdk_device_manager_list_devices (manager,
6250 GDK_DEVICE_TYPE_MASTER);
6251 GdkDevice *device;
6252 GList *tem;
6253 for (tem = devices; tem; tem = tem->next)
6254 {
6255 device = GDK_DEVICE (tem->data);
6256
6257 if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
6258 {
6259 gdk_event_set_device (xg_event, device);
6260 break;
6261 }
6262 }
6263
6264 g_list_free (devices);
6265#endif
6266
6267#ifdef HAVE_XINPUT2
6268 if (xkey->type != GenericEvent)
6269 {
6270#endif
6271 xg_event->key.hardware_keycode = xkey->xkey.keycode;
6272
6273#ifdef HAVE_XKB
6274 if (dpyinfo->supports_xkb)
6275 xg_event->key.group = XkbGroupForCoreState (xkey->xkey.state);
6276#endif
6277 xg_event->key.state = xkey->xkey.state;
6278 gdk_keymap_translate_keyboard_state (keymap,
6279 xkey->xkey.keycode,
6280 xkey->xkey.state,
6281 xg_event->key.group,
6282 &xg_event->key.keyval,
6283 NULL, NULL, &consumed);
6284 xg_add_virtual_mods (dpyinfo, &xg_event->key);
6285 xg_event->key.state &= ~consumed;
6286#if GTK_CHECK_VERSION (3, 6, 0)
6287 xg_event->key.is_modifier = gdk_x11_keymap_key_is_modifier (keymap,
6288 xg_event->key.hardware_keycode);
6289#endif
6290#ifdef HAVE_XINPUT2
6291 }
6292 else
6293 {
6294 XIDeviceEvent *xev = (XIDeviceEvent *) xkey->xcookie.data;
6295
6296 xg_event->key.hardware_keycode = xev->detail;
6297 xg_event->key.group = xev->group.effective;
6298 xg_event->key.state = xev->mods.effective;
6299 gdk_keymap_translate_keyboard_state (keymap,
6300 xev->detail,
6301 xev->mods.effective,
6302 xg_event->key.group,
6303 &xg_event->key.keyval,
6304 NULL, NULL, &consumed);
6305 xg_add_virtual_mods (dpyinfo, &xg_event->key);
6306 xg_event->key.state &= ~consumed;
6307 xg_event->key.is_modifier = gdk_x11_keymap_key_is_modifier (keymap,
6308 xg_event->key.hardware_keycode);
6309 }
6310#endif
6311
6312 result = gtk_im_context_filter_keypress (FRAME_X_OUTPUT (frame)->im_context,
6313 &xg_event->key);
6314
6315 gdk_event_free (xg_event);
6316
6317 return result;
6318}
6319#endif
5966#endif /* USE_GTK */ 6320#endif /* USE_GTK */
diff --git a/src/gtkutil.h b/src/gtkutil.h
index 5a918259280..a1dd281f1d3 100644
--- a/src/gtkutil.h
+++ b/src/gtkutil.h
@@ -217,6 +217,8 @@ extern void xg_print_frames_dialog (Lisp_Object);
217extern bool xg_is_menu_window (Display *dpy, Window); 217extern bool xg_is_menu_window (Display *dpy, Window);
218#endif 218#endif
219 219
220extern bool xg_filter_key (struct frame *frame, XEvent *xkey);
221
220/* Mark all callback data that are Lisp_object:s during GC. */ 222/* Mark all callback data that are Lisp_object:s during GC. */
221extern void xg_mark_data (void); 223extern void xg_mark_data (void);
222 224
diff --git a/src/xfns.c b/src/xfns.c
index 705fa548a21..073200ff75a 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -2820,16 +2820,33 @@ xic_set_preeditarea (struct window *w, int x, int y)
2820 XVaNestedList attr; 2820 XVaNestedList attr;
2821 XPoint spot; 2821 XPoint spot;
2822 2822
2823 spot.x = WINDOW_TO_FRAME_PIXEL_X (w, x) + WINDOW_LEFT_FRINGE_WIDTH (w) + WINDOW_LEFT_MARGIN_WIDTH(w); 2823 if (FRAME_XIC (WINDOW_XFRAME (w)))
2824 spot.y = WINDOW_TO_FRAME_PIXEL_Y (w, y) + FONT_BASE (FRAME_FONT (f)); 2824 {
2825 attr = XVaCreateNestedList (0, XNSpotLocation, &spot, 2825 spot.x = WINDOW_TO_FRAME_PIXEL_X (w, x) + WINDOW_LEFT_FRINGE_WIDTH (w) + WINDOW_LEFT_MARGIN_WIDTH(w);
2826 XNPreeditStartCallback, &Xxic_preedit_start_callback, 2826 spot.y = WINDOW_TO_FRAME_PIXEL_Y (w, y) + FONT_BASE (FRAME_FONT (f));
2827 XNPreeditDoneCallback, &Xxic_preedit_done_callback, 2827 attr = XVaCreateNestedList (0, XNSpotLocation, &spot,
2828 XNPreeditDrawCallback, &Xxic_preedit_draw_callback, 2828 XNPreeditStartCallback, &Xxic_preedit_start_callback,
2829 XNPreeditCaretCallback, &Xxic_preedit_caret_callback, 2829 XNPreeditDoneCallback, &Xxic_preedit_done_callback,
2830 NULL); 2830 XNPreeditDrawCallback, &Xxic_preedit_draw_callback,
2831 XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL); 2831 XNPreeditCaretCallback, &Xxic_preedit_caret_callback,
2832 XFree (attr); 2832 NULL);
2833 XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
2834 XFree (attr);
2835 }
2836#ifdef USE_GTK
2837 GdkRectangle rect;
2838 rect.x = (WINDOW_TO_FRAME_PIXEL_X (w, x)
2839 + WINDOW_LEFT_FRINGE_WIDTH (w)
2840 + WINDOW_LEFT_MARGIN_WIDTH (w));
2841 rect.y = (WINDOW_TO_FRAME_PIXEL_Y (w, y)
2842 + FRAME_TOOLBAR_HEIGHT (f)
2843 + FRAME_MENUBAR_HEIGHT (f));
2844 rect.width = w->phys_cursor_width;
2845 rect.height = w->phys_cursor_height;
2846
2847 gtk_im_context_set_cursor_location (FRAME_X_OUTPUT (f)->im_context,
2848 &rect);
2849#endif
2833} 2850}
2834 2851
2835 2852
diff --git a/src/xterm.c b/src/xterm.c
index b284fdd3123..9b4bd4b8db2 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -147,6 +147,17 @@ bool use_xim = true;
147bool use_xim = false; /* configure --without-xim */ 147bool use_xim = false; /* configure --without-xim */
148#endif 148#endif
149 149
150#ifdef USE_GTK
151/* GTK can't tolerate a call to `handle_interrupt' inside an event
152 signal handler, but we have to store input events inside the
153 handler for native input to work.
154
155 This acts as a `hold_quit', and it is stored in the keyboard buffer
156 (thereby causing the call to `handle_interrupt') after the GTK
157 signal handler exits and control returns to XTread_socket. */
158struct input_event xg_pending_quit_event = { .kind = NO_EVENT };
159#endif
160
150/* Non-zero means that a HELP_EVENT has been generated since Emacs 161/* Non-zero means that a HELP_EVENT has been generated since Emacs
151 start. */ 162 start. */
152 163
@@ -4931,7 +4942,8 @@ x_new_focus_frame (struct x_display_info *dpyinfo, struct frame *frame)
4931 a FOCUS_IN_EVENT into *BUFP. */ 4942 a FOCUS_IN_EVENT into *BUFP. */
4932 4943
4933static void 4944static void
4934x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct frame *frame, struct input_event *bufp) 4945x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct frame *frame,
4946 struct input_event *bufp)
4935{ 4947{
4936 if (type == FocusIn) 4948 if (type == FocusIn)
4937 { 4949 {
@@ -4947,7 +4959,15 @@ x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct fra
4947 4959
4948#ifdef HAVE_X_I18N 4960#ifdef HAVE_X_I18N
4949 if (FRAME_XIC (frame)) 4961 if (FRAME_XIC (frame))
4950 XSetICFocus (FRAME_XIC (frame)); 4962 XSetICFocus (FRAME_XIC (frame));
4963#ifdef USE_GTK
4964 GtkWidget *widget;
4965
4966 gtk_im_context_focus_in (FRAME_X_OUTPUT (frame)->im_context);
4967 widget = FRAME_GTK_OUTER_WIDGET (frame);
4968 gtk_im_context_set_client_window (FRAME_X_OUTPUT (frame)->im_context,
4969 gtk_widget_get_window (widget));
4970#endif
4951#endif 4971#endif
4952 } 4972 }
4953 else if (type == FocusOut) 4973 else if (type == FocusOut)
@@ -4966,6 +4986,10 @@ x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct fra
4966#ifdef HAVE_X_I18N 4986#ifdef HAVE_X_I18N
4967 if (FRAME_XIC (frame)) 4987 if (FRAME_XIC (frame))
4968 XUnsetICFocus (FRAME_XIC (frame)); 4988 XUnsetICFocus (FRAME_XIC (frame));
4989#ifdef USE_GTK
4990 gtk_im_context_focus_out (FRAME_X_OUTPUT (frame)->im_context);
4991 gtk_im_context_set_client_window (FRAME_X_OUTPUT (frame)->im_context, NULL);
4992#endif
4969#endif 4993#endif
4970 if (frame->pointer_invisible) 4994 if (frame->pointer_invisible)
4971 XTtoggle_invisible_pointer (frame, false); 4995 XTtoggle_invisible_pointer (frame, false);
@@ -8229,10 +8253,52 @@ x_filter_event (struct x_display_info *dpyinfo, XEvent *event)
8229 XFilterEvent because that's the one for which the IC 8253 XFilterEvent because that's the one for which the IC
8230 was created. */ 8254 was created. */
8231 8255
8232 struct frame *f1 = x_any_window_to_frame (dpyinfo, 8256 struct frame *f1;
8233 event->xclient.window);
8234 8257
8235 return XFilterEvent (event, f1 ? FRAME_X_WINDOW (f1) : None); 8258#if defined HAVE_XINPUT2 && defined USE_GTK
8259 bool xinput_event = false;
8260 if (dpyinfo->supports_xi2
8261 && event->type == GenericEvent
8262 && (event->xgeneric.extension
8263 == dpyinfo->xi2_opcode)
8264 && (event->xgeneric.evtype
8265 == XI_KeyPress))
8266 {
8267 f1 = x_any_window_to_frame (dpyinfo,
8268 ((XIDeviceEvent *)
8269 event->xcookie.data)->event);
8270 xinput_event = true;
8271 }
8272 else
8273#endif
8274 f1 = x_any_window_to_frame (dpyinfo,
8275 event->xclient.window);
8276
8277#ifdef USE_GTK
8278 if (!x_gtk_use_native_input
8279 && !dpyinfo->prefer_native_input)
8280 {
8281#endif
8282 return XFilterEvent (event, f1 ? FRAME_X_WINDOW (f1) : None);
8283#ifdef USE_GTK
8284 }
8285 else if (f1 && (event->type == KeyPress
8286#ifdef HAVE_XINPUT2
8287 || xinput_event
8288#endif
8289 ))
8290 {
8291 bool result;
8292
8293 block_input ();
8294 result = xg_filter_key (f1, event);
8295 unblock_input ();
8296
8297 return result;
8298 }
8299
8300 return 0;
8301#endif
8236} 8302}
8237#endif 8303#endif
8238 8304
@@ -10679,12 +10745,23 @@ handle_one_xevent (struct x_display_info *dpyinfo,
10679 xkey.keycode = xev->detail; 10745 xkey.keycode = xev->detail;
10680 xkey.same_screen = True; 10746 xkey.same_screen = True;
10681 10747
10748#ifdef USE_GTK
10749 if ((!x_gtk_use_native_input
10750 && x_filter_event (dpyinfo, (XEvent *) &xkey))
10751 || (x_gtk_use_native_input
10752 && x_filter_event (dpyinfo, event)))
10753 {
10754 *finish = X_EVENT_DROP;
10755 goto XI_OTHER;
10756 }
10757#else
10682 if (x_filter_event (dpyinfo, (XEvent *) &xkey)) 10758 if (x_filter_event (dpyinfo, (XEvent *) &xkey))
10683 { 10759 {
10684 *finish = X_EVENT_DROP; 10760 *finish = X_EVENT_DROP;
10685 goto XI_OTHER; 10761 goto XI_OTHER;
10686 } 10762 }
10687#endif 10763#endif
10764#endif
10688 10765
10689#ifdef HAVE_XKB 10766#ifdef HAVE_XKB
10690 if (dpyinfo->xkb_desc) 10767 if (dpyinfo->xkb_desc)
@@ -11421,6 +11498,20 @@ XTread_socket (struct terminal *terminal, struct input_event *hold_quit)
11421 if (current_finish == X_EVENT_GOTO_OUT) 11498 if (current_finish == X_EVENT_GOTO_OUT)
11422 break; 11499 break;
11423 } 11500 }
11501
11502 /* Now see if `xg_pending_quit_event' was set. */
11503 if (xg_pending_quit_event.kind != NO_EVENT)
11504 {
11505 /* Check that the frame is still valid. It could have been
11506 deleted between now and the time the event was recorded. */
11507 if (FRAME_LIVE_P (XFRAME (xg_pending_quit_event.frame_or_window)))
11508 /* Store that event into hold_quit and clear the pending quit
11509 event. */
11510 *hold_quit = xg_pending_quit_event;
11511
11512 /* If the frame is invalid, just clear the event as well. */
11513 xg_pending_quit_event.kind = NO_EVENT;
11514 }
11424#endif /* USE_GTK */ 11515#endif /* USE_GTK */
11425 11516
11426 /* On some systems, an X bug causes Emacs to get no more events 11517 /* On some systems, an X bug causes Emacs to get no more events
@@ -11726,8 +11817,7 @@ x_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, int x,
11726 11817
11727#ifdef HAVE_X_I18N 11818#ifdef HAVE_X_I18N
11728 if (w == XWINDOW (f->selected_window)) 11819 if (w == XWINDOW (f->selected_window))
11729 if (FRAME_XIC (f)) 11820 xic_set_preeditarea (w, x, y);
11730 xic_set_preeditarea (w, x, y);
11731#endif 11821#endif
11732 } 11822 }
11733 11823
@@ -15299,6 +15389,10 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
15299 dpyinfo->preferred_xim_style = STYLE_OFFTHESPOT; 15389 dpyinfo->preferred_xim_style = STYLE_OFFTHESPOT;
15300 else if (!strcmp (SSDATA (value), "root")) 15390 else if (!strcmp (SSDATA (value), "root"))
15301 dpyinfo->preferred_xim_style = STYLE_ROOT; 15391 dpyinfo->preferred_xim_style = STYLE_ROOT;
15392#ifdef USE_GTK
15393 else if (!strcmp (SSDATA (value), "native"))
15394 dpyinfo->prefer_native_input = true;
15395#endif
15302 } 15396 }
15303#endif 15397#endif
15304 } 15398 }
@@ -15846,4 +15940,10 @@ always uses gtk_window_move and ignores the value of this variable. */);
15846This option is only effective when Emacs is built with XInput 2 15940This option is only effective when Emacs is built with XInput 2
15847support. */); 15941support. */);
15848 Vx_scroll_event_delta_factor = make_float (1.0); 15942 Vx_scroll_event_delta_factor = make_float (1.0);
15943
15944 DEFVAR_BOOL ("x-gtk-use-native-input", x_gtk_use_native_input,
15945 doc: /* Non-nil means to use GTK for input method support.
15946This provides better support for some modern input methods, and is
15947only effective when Emacs is built with GTK. */);
15948 x_gtk_use_native_input = false;
15849} 15949}
diff --git a/src/xterm.h b/src/xterm.h
index a796f69ddc1..fc47fe0c6ea 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -527,6 +527,10 @@ struct x_display_info
527 int xkb_event_type; 527 int xkb_event_type;
528 XkbDescPtr xkb_desc; 528 XkbDescPtr xkb_desc;
529#endif 529#endif
530
531#ifdef USE_GTK
532 bool prefer_native_input;
533#endif
530}; 534};
531 535
532#ifdef HAVE_X_I18N 536#ifdef HAVE_X_I18N
@@ -643,6 +647,8 @@ struct x_output
643 GtkTooltip *ttip_widget; 647 GtkTooltip *ttip_widget;
644 GtkWidget *ttip_lbl; 648 GtkWidget *ttip_lbl;
645 GtkWindow *ttip_window; 649 GtkWindow *ttip_window;
650
651 GtkIMContext *im_context;
646#endif /* USE_GTK */ 652#endif /* USE_GTK */
647 653
648 /* If >=0, a bitmap index. The indicated bitmap is used for the 654 /* If >=0, a bitmap index. The indicated bitmap is used for the
@@ -1340,6 +1346,10 @@ extern void x_session_close (void);
1340#define STYLE_NONE (XIMPreeditNothing | XIMStatusNothing) 1346#define STYLE_NONE (XIMPreeditNothing | XIMStatusNothing)
1341#endif 1347#endif
1342 1348
1349#ifdef USE_GTK
1350extern struct input_event xg_pending_quit_event;
1351#endif
1352
1343/* Is the frame embedded into another application? */ 1353/* Is the frame embedded into another application? */
1344 1354
1345#define FRAME_X_EMBEDDED_P(f) (FRAME_X_OUTPUT(f)->explicit_parent != 0) 1355#define FRAME_X_EMBEDDED_P(f) (FRAME_X_OUTPUT(f)->explicit_parent != 0)