aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2021-10-16 13:15:36 +0800
committerPo Lu2021-11-20 18:25:09 +0800
commit487ec3cf2a34496866153474507ab741d8dfea63 (patch)
treef8a04b4204418d06b1308d9186f32728b770bb13 /src
parentfbf361f593df52ff414a4483f105e2e4c1a921e2 (diff)
downloademacs-487ec3cf2a34496866153474507ab741d8dfea63.tar.gz
emacs-487ec3cf2a34496866153474507ab741d8dfea63.zip
Add support for event processing via XInput 2
* configure.ac: Add an option to use XInput 2 if available. * src/Makefile.in (XINPUT_LIBS, XINPUT_CFLAGS): New variables. (EMACS_CFLAGS): Add Xinput CFLAGS. (LIBES): Add XInput libs. * src/xmenu.c (popup_activated_flag): Expose flag if XInput 2 is available. * src/xfns.c (x_window): Set XInput 2 event mask. (setup_xi_event_mask): New function. (syms_of_xfns): Provide XInput 2 feature. * src/xterm.c (x_detect_focus_change): Handle XInput 2 GenericEvents. (handle_one_xevent): Handle XInput 2 events. (x_term_init): Ask the server for XInput 2 support and set xkb_desc if available. (x_delete_terminal): Free XKB kb desc if it exists, and free XI2 devices if they exist. (xi_grab_or_ungrab_device) (xi_reset_scroll_valuators_for_device_id) (x_free_xi_devices, x_init_master_valuators): New functions. (x_get_scroll_valuator_delta): New function. (init_xterm): Don't tell GTK to only use Core Input when built with XInput 2 support. * src/xterm.h (struct x_display_info): Add fields for XKB and XI2 support. * src/gtkutil.c (xg_event_is_for_menubar): Handle XIDeviceEvents. (xg_is_menu_window): New function. (xg_event_is_for_scrollbar): Handle XIDeviceEvents. * etc/NEWS: Document changes. * lisp/mwheel.el (mouse-wheel-down-alternate-event) (mouse-wheel-up-alternate-event) (mouse-wheel-left-alternate-event) (mouse-wheel-right-alternate-event): New user options. (mouse-wheel-text-scale) (mwheel-scroll): Test for alternate events. (mouse-wheel--setup-bindings): Set up bindings for alternate buttons.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in7
-rw-r--r--src/gtkutil.c72
-rw-r--r--src/gtkutil.h4
-rw-r--r--src/xfns.c50
-rw-r--r--src/xmenu.c4
-rw-r--r--src/xterm.c1107
-rw-r--r--src/xterm.h44
7 files changed, 1281 insertions, 7 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index 4c5535f8ad9..0aaaf91d392 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -258,6 +258,9 @@ XINERAMA_CFLAGS = @XINERAMA_CFLAGS@
258XFIXES_LIBS = @XFIXES_LIBS@ 258XFIXES_LIBS = @XFIXES_LIBS@
259XFIXES_CFLAGS = @XFIXES_CFLAGS@ 259XFIXES_CFLAGS = @XFIXES_CFLAGS@
260 260
261XINPUT_LIBS = @XINPUT_LIBS@
262XINPUT_CFLAGS = @XINPUT_CFLAGS@
263
261XDBE_LIBS = @XDBE_LIBS@ 264XDBE_LIBS = @XDBE_LIBS@
262XDBE_CFLAGS = @XDBE_CFLAGS@ 265XDBE_CFLAGS = @XDBE_CFLAGS@
263 266
@@ -374,7 +377,7 @@ EMACS_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
374 $(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \ 377 $(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \
375 $(PNG_CFLAGS) $(LIBXML2_CFLAGS) $(LIBGCCJIT_CFLAGS) $(DBUS_CFLAGS) \ 378 $(PNG_CFLAGS) $(LIBXML2_CFLAGS) $(LIBGCCJIT_CFLAGS) $(DBUS_CFLAGS) \
376 $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) $(XDBE_CFLAGS) \ 379 $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) $(XDBE_CFLAGS) \
377 $(WEBKIT_CFLAGS) $(WEBP_CFLAGS) $(LCMS2_CFLAGS) \ 380 $(XINPUT_CFLAGS) $(WEBP_CFLAGS) $(WEBKIT_CFLAGS) $(LCMS2_CFLAGS) \
378 $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \ 381 $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
379 $(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \ 382 $(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
380 $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \ 383 $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \
@@ -524,7 +527,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
524 $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(HARFBUZZ_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ 527 $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(HARFBUZZ_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
525 $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \ 528 $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \
526 $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \ 529 $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \
527 $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS) 530 $(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS) $(XINPUT_LIBS)
528 531
529## FORCE it so that admin/unidata can decide whether this file is 532## FORCE it so that admin/unidata can decide whether this file is
530## up-to-date. Although since charprop depends on bootstrap-emacs, 533## up-to-date. Although since charprop depends on bootstrap-emacs,
diff --git a/src/gtkutil.c b/src/gtkutil.c
index a9eabf47d8f..9e676cd025b 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -47,6 +47,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
47 47
48#include <gdk/gdkkeysyms.h> 48#include <gdk/gdkkeysyms.h>
49 49
50#ifdef HAVE_XINPUT2
51#include <X11/extensions/XInput2.h>
52#endif
53
50#ifdef HAVE_XFT 54#ifdef HAVE_XFT
51#include <X11/Xft/Xft.h> 55#include <X11/Xft/Xft.h>
52#endif 56#endif
@@ -839,6 +843,23 @@ my_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
839} 843}
840#endif 844#endif
841 845
846#if defined HAVE_GTK3 && defined HAVE_XINPUT2
847bool
848xg_is_menu_window (Display *dpy, Window wdesc)
849{
850 GtkWidget *gwdesc = xg_win_to_widget (dpy, wdesc);
851
852 if (GTK_IS_WINDOW (gwdesc))
853 {
854 GtkWidget *fw = gtk_bin_get_child (GTK_BIN (gwdesc));
855 if (GTK_IS_MENU (fw))
856 return true;
857 }
858
859 return false;
860}
861#endif
862
842/* Make a geometry string and pass that to GTK. It seems this is the 863/* Make a geometry string and pass that to GTK. It seems this is the
843 only way to get geometry position right if the user explicitly 864 only way to get geometry position right if the user explicitly
844 asked for a position when starting Emacs. 865 asked for a position when starting Emacs.
@@ -3589,6 +3610,18 @@ xg_event_is_for_menubar (struct frame *f, const XEvent *event)
3589 3610
3590 if (! x->menubar_widget) return 0; 3611 if (! x->menubar_widget) return 0;
3591 3612
3613#ifdef HAVE_XINPUT2
3614 XIDeviceEvent *xev = (XIDeviceEvent *) event->xcookie.data;
3615 if (event->type == GenericEvent) /* XI_ButtonPress or XI_ButtonRelease */
3616 {
3617 if (! (xev->event_x >= 0
3618 && xev->event_x < FRAME_PIXEL_WIDTH (f)
3619 && xev->event_y >= 0
3620 && xev->event_y < FRAME_MENUBAR_HEIGHT (f)))
3621 return 0;
3622 }
3623 else
3624#endif
3592 if (! (event->xbutton.x >= 0 3625 if (! (event->xbutton.x >= 0
3593 && event->xbutton.x < FRAME_PIXEL_WIDTH (f) 3626 && event->xbutton.x < FRAME_PIXEL_WIDTH (f)
3594 && event->xbutton.y >= 0 3627 && event->xbutton.y >= 0
@@ -3597,7 +3630,12 @@ xg_event_is_for_menubar (struct frame *f, const XEvent *event)
3597 return 0; 3630 return 0;
3598 3631
3599 gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f)); 3632 gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
3600 gw = gdk_x11_window_lookup_for_display (gdpy, event->xbutton.window); 3633#ifdef HAVE_XINPUT2
3634 if (event->type == GenericEvent)
3635 gw = gdk_x11_window_lookup_for_display (gdpy, xev->event);
3636 else
3637#endif
3638 gw = gdk_x11_window_lookup_for_display (gdpy, event->xbutton.window);
3601 if (! gw) return 0; 3639 if (! gw) return 0;
3602 gevent.any.window = gw; 3640 gevent.any.window = gw;
3603 gevent.any.type = GDK_NOTHING; 3641 gevent.any.type = GDK_NOTHING;
@@ -4244,7 +4282,20 @@ xg_event_is_for_scrollbar (struct frame *f, const XEvent *event)
4244{ 4282{
4245 bool retval = 0; 4283 bool retval = 0;
4246 4284
4285#ifdef HAVE_XINPUT2
4286 XIDeviceEvent *xev = (XIDeviceEvent *) event->xcookie.data;
4287 if (f && ((FRAME_DISPLAY_INFO (f)->supports_xi2
4288 && event->type == GenericEvent
4289 && (event->xgeneric.extension
4290 == FRAME_DISPLAY_INFO (f)->xi2_opcode)
4291 && ((event->xgeneric.evtype == XI_ButtonPress
4292 && xev->detail < 4)
4293 || (event->xgeneric.evtype == XI_Motion)))
4294 || (event->type == ButtonPress
4295 && event->xbutton.button < 4)))
4296#else
4247 if (f && event->type == ButtonPress && event->xbutton.button < 4) 4297 if (f && event->type == ButtonPress && event->xbutton.button < 4)
4298#endif /* HAVE_XINPUT2 */
4248 { 4299 {
4249 /* Check if press occurred outside the edit widget. */ 4300 /* Check if press occurred outside the edit widget. */
4250 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f)); 4301 GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
@@ -4262,10 +4313,29 @@ xg_event_is_for_scrollbar (struct frame *f, const XEvent *event)
4262 gwin = gdk_display_get_window_at_pointer (gdpy, NULL, NULL); 4313 gwin = gdk_display_get_window_at_pointer (gdpy, NULL, NULL);
4263#endif 4314#endif
4264 retval = gwin != gtk_widget_get_window (f->output_data.x->edit_widget); 4315 retval = gwin != gtk_widget_get_window (f->output_data.x->edit_widget);
4316#ifdef HAVE_XINPUT2
4317 GtkWidget *grab = gtk_grab_get_current ();
4318 if (event->type == GenericEvent
4319 && event->xgeneric.evtype == XI_Motion)
4320 retval = retval || (grab && GTK_IS_SCROLLBAR (grab));
4321#endif
4265 } 4322 }
4323#ifdef HAVE_XINPUT2
4324 else if (f && ((FRAME_DISPLAY_INFO (f)->supports_xi2
4325 && event->type == GenericEvent
4326 && (event->xgeneric.extension
4327 == FRAME_DISPLAY_INFO (f)->xi2_opcode)
4328 && ((event->xgeneric.evtype == XI_ButtonRelease
4329 && xev->detail < 4)
4330 || (event->xgeneric.evtype == XI_Motion)))
4331 || ((event->type == ButtonRelease
4332 && event->xbutton.button < 4)
4333 || event->type == MotionNotify)))
4334#else
4266 else if (f 4335 else if (f
4267 && ((event->type == ButtonRelease && event->xbutton.button < 4) 4336 && ((event->type == ButtonRelease && event->xbutton.button < 4)
4268 || event->type == MotionNotify)) 4337 || event->type == MotionNotify))
4338#endif /* HAVE_XINPUT2 */
4269 { 4339 {
4270 /* If we are releasing or moving the scroll bar, it has the grab. */ 4340 /* If we are releasing or moving the scroll bar, it has the grab. */
4271 GtkWidget *w = gtk_grab_get_current (); 4341 GtkWidget *w = gtk_grab_get_current ();
diff --git a/src/gtkutil.h b/src/gtkutil.h
index 31a12cd5d3c..95dd75b7fad 100644
--- a/src/gtkutil.h
+++ b/src/gtkutil.h
@@ -192,6 +192,10 @@ extern Lisp_Object xg_get_page_setup (void);
192extern void xg_print_frames_dialog (Lisp_Object); 192extern void xg_print_frames_dialog (Lisp_Object);
193#endif 193#endif
194 194
195#if defined HAVE_GTK3 && defined HAVE_XINPUT2
196extern bool xg_is_menu_window (Display *dpy, Window);
197#endif
198
195/* Mark all callback data that are Lisp_object:s during GC. */ 199/* Mark all callback data that are Lisp_object:s during GC. */
196extern void xg_mark_data (void); 200extern void xg_mark_data (void);
197 201
diff --git a/src/xfns.c b/src/xfns.c
index 785ae3baca5..b33b40b330b 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -57,6 +57,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
57#include <X11/extensions/Xdbe.h> 57#include <X11/extensions/Xdbe.h>
58#endif 58#endif
59 59
60#ifdef HAVE_XINPUT2
61#include <X11/extensions/XInput2.h>
62#endif
63
60#ifdef USE_X_TOOLKIT 64#ifdef USE_X_TOOLKIT
61#include <X11/Shell.h> 65#include <X11/Shell.h>
62 66
@@ -2912,6 +2916,37 @@ initial_set_up_x_back_buffer (struct frame *f)
2912 unblock_input (); 2916 unblock_input ();
2913} 2917}
2914 2918
2919#if defined HAVE_XINPUT2 && !defined USE_GTK
2920static void
2921setup_xi_event_mask (struct frame *f)
2922{
2923 XIEventMask mask;
2924 ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
2925 unsigned char *m;
2926
2927 mask.mask = m = alloca (l);
2928 memset (m, 0, l);
2929 mask.mask_len = l;
2930 mask.deviceid = XIAllMasterDevices;
2931
2932 XISetMask (m, XI_ButtonPress);
2933 XISetMask (m, XI_ButtonRelease);
2934 XISetMask (m, XI_KeyPress);
2935 XISetMask (m, XI_KeyRelease);
2936 XISetMask (m, XI_Motion);
2937 XISetMask (m, XI_Enter);
2938 XISetMask (m, XI_Leave);
2939 XISetMask (m, XI_FocusIn);
2940 XISetMask (m, XI_FocusOut);
2941 XISetMask (m, XI_PropertyEvent);
2942 XISetMask (m, XI_HierarchyChanged);
2943 XISetMask (m, XI_DeviceChanged);
2944 XISelectEvents (FRAME_X_DISPLAY (f),
2945 FRAME_X_WINDOW (f),
2946 &mask, 1);
2947}
2948#endif
2949
2915#ifdef USE_X_TOOLKIT 2950#ifdef USE_X_TOOLKIT
2916 2951
2917/* Create and set up the X widget for frame F. */ 2952/* Create and set up the X widget for frame F. */
@@ -3074,6 +3109,11 @@ x_window (struct frame *f, long window_prompting)
3074 class_hints.res_class = SSDATA (Vx_resource_class); 3109 class_hints.res_class = SSDATA (Vx_resource_class);
3075 XSetClassHint (FRAME_X_DISPLAY (f), XtWindow (shell_widget), &class_hints); 3110 XSetClassHint (FRAME_X_DISPLAY (f), XtWindow (shell_widget), &class_hints);
3076 3111
3112#ifdef HAVE_XINPUT2
3113 if (FRAME_DISPLAY_INFO (f)->supports_xi2)
3114 setup_xi_event_mask (f);
3115#endif
3116
3077#ifdef HAVE_X_I18N 3117#ifdef HAVE_X_I18N
3078 FRAME_XIC (f) = NULL; 3118 FRAME_XIC (f) = NULL;
3079 if (use_xim) 3119 if (use_xim)
@@ -3254,6 +3294,11 @@ x_window (struct frame *f)
3254 } 3294 }
3255#endif /* HAVE_X_I18N */ 3295#endif /* HAVE_X_I18N */
3256 3296
3297#ifdef HAVE_XINPUT2
3298 if (FRAME_DISPLAY_INFO (f)->supports_xi2)
3299 setup_xi_event_mask (f);
3300#endif
3301
3257 validate_x_resource_name (); 3302 validate_x_resource_name ();
3258 3303
3259 class_hints.res_name = SSDATA (Vx_resource_name); 3304 class_hints.res_name = SSDATA (Vx_resource_name);
@@ -8038,6 +8083,11 @@ eliminated in future versions of Emacs. */);
8038 /* Tell Emacs about this window system. */ 8083 /* Tell Emacs about this window system. */
8039 Fprovide (Qx, Qnil); 8084 Fprovide (Qx, Qnil);
8040 8085
8086#ifdef HAVE_XINPUT2
8087 DEFSYM (Qxinput2, "xinput2");
8088 Fprovide (Qxinput2, Qnil);
8089#endif
8090
8041#ifdef USE_X_TOOLKIT 8091#ifdef USE_X_TOOLKIT
8042 Fprovide (intern_c_string ("x-toolkit"), Qnil); 8092 Fprovide (intern_c_string ("x-toolkit"), Qnil);
8043#ifdef USE_MOTIF 8093#ifdef USE_MOTIF
diff --git a/src/xmenu.c b/src/xmenu.c
index ea2cbab2030..07255911f97 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -105,7 +105,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
105 105
106/* Flag which when set indicates a dialog or menu has been posted by 106/* Flag which when set indicates a dialog or menu has been posted by
107 Xt on behalf of one of the widget sets. */ 107 Xt on behalf of one of the widget sets. */
108#ifndef HAVE_XINPUT2
108static int popup_activated_flag; 109static int popup_activated_flag;
110#else
111int popup_activated_flag;
112#endif
109 113
110 114
111#ifdef USE_X_TOOLKIT 115#ifdef USE_X_TOOLKIT
diff --git a/src/xterm.c b/src/xterm.c
index 816b6dc5a8b..63754a2cb61 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -42,6 +42,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
42#include <X11/extensions/Xdbe.h> 42#include <X11/extensions/Xdbe.h>
43#endif 43#endif
44 44
45#ifdef HAVE_XINPUT2
46#include <X11/extensions/XInput2.h>
47#endif
48
45/* Load sys/types.h if not already loaded. 49/* Load sys/types.h if not already loaded.
46 In some systems loading it twice is suicidal. */ 50 In some systems loading it twice is suicidal. */
47#ifndef makedev 51#ifndef makedev
@@ -223,9 +227,15 @@ static bool x_handle_net_wm_state (struct frame *, const XPropertyEvent *);
223static void x_check_fullscreen (struct frame *); 227static void x_check_fullscreen (struct frame *);
224static void x_check_expected_move (struct frame *, int, int); 228static void x_check_expected_move (struct frame *, int, int);
225static void x_sync_with_move (struct frame *, int, int, bool); 229static void x_sync_with_move (struct frame *, int, int, bool);
230#ifndef HAVE_XINPUT2
226static int handle_one_xevent (struct x_display_info *, 231static int handle_one_xevent (struct x_display_info *,
227 const XEvent *, int *, 232 const XEvent *, int *,
228 struct input_event *); 233 struct input_event *);
234#else
235static int handle_one_xevent (struct x_display_info *,
236 XEvent *, int *,
237 struct input_event *);
238#endif
229#if ! (defined USE_X_TOOLKIT || defined USE_MOTIF) && defined USE_GTK 239#if ! (defined USE_X_TOOLKIT || defined USE_MOTIF) && defined USE_GTK
230static int x_dispatch_event (XEvent *, Display *); 240static int x_dispatch_event (XEvent *, Display *);
231#endif 241#endif
@@ -335,6 +345,224 @@ x_extension_initialize (struct x_display_info *dpyinfo)
335 dpyinfo->ext_codes = ext_codes; 345 dpyinfo->ext_codes = ext_codes;
336} 346}
337 347
348
349#ifdef HAVE_XINPUT2
350
351/* Free all XI2 devices on dpyinfo. */
352static void
353x_free_xi_devices (struct x_display_info *dpyinfo)
354{
355 block_input ();
356
357 if (dpyinfo->num_devices)
358 {
359 for (int i = 0; i < dpyinfo->num_devices; ++i)
360 {
361 XIUngrabDevice (dpyinfo->display, dpyinfo->devices[i].device_id,
362 CurrentTime);
363 xfree (dpyinfo->devices[i].valuators);
364 }
365
366 xfree (dpyinfo->devices);
367 dpyinfo->devices = NULL;
368 dpyinfo->num_devices = 0;
369 }
370
371 unblock_input ();
372}
373
374/* Setup valuator tracking for XI2 master devices on
375 DPYINFO->display. */
376
377static void
378x_init_master_valuators (struct x_display_info *dpyinfo)
379{
380 int ndevices;
381 XIDeviceInfo *infos;
382
383 block_input ();
384 x_free_xi_devices (dpyinfo);
385 infos = XIQueryDevice (dpyinfo->display,
386 XIAllMasterDevices,
387 &ndevices);
388
389 if (!ndevices)
390 {
391 XIFreeDeviceInfo (infos);
392 unblock_input ();
393 return;
394 }
395
396 int actual_devices = 0;
397 dpyinfo->devices = xmalloc (sizeof *dpyinfo->devices * ndevices);
398
399 for (int i = 0; i < ndevices; ++i)
400 {
401 XIDeviceInfo *device = &infos[i];
402
403 if (device->enabled)
404 {
405 int actual_valuator_count = 0;
406 struct xi_device_t *xi_device = &dpyinfo->devices[actual_devices++];
407 xi_device->device_id = device->deviceid;
408 xi_device->grab = 0;
409 xi_device->valuators =
410 xmalloc (sizeof *xi_device->valuators * device->num_classes);
411
412 for (int c = 0; c < device->num_classes; ++c)
413 {
414 switch (device->classes[c]->type)
415 {
416#ifdef XIScrollClass /* XInput 2.1 */
417 case XIScrollClass:
418 {
419 XIScrollClassInfo *info =
420 (XIScrollClassInfo *) device->classes[c];
421 struct xi_scroll_valuator_t *valuator =
422 &xi_device->valuators[actual_valuator_count++];
423
424 valuator->horizontal
425 = (info->scroll_type == XIScrollTypeHorizontal);
426 valuator->invalid_p = true;
427 valuator->emacs_value = DBL_MIN;
428 valuator->increment = info->increment;
429 valuator->number = info->number;
430 break;
431 }
432#endif
433 default:
434 break;
435 }
436 }
437 xi_device->scroll_valuator_count = actual_valuator_count;
438 }
439 }
440
441 dpyinfo->num_devices = actual_devices;
442 XIFreeDeviceInfo (infos);
443 unblock_input ();
444}
445
446/* Return the delta of the scroll valuator VALUATOR_NUMBER under
447 DEVICE_ID in the display DPYINFO with VALUE. The valuator's
448 valuator will be set to VALUE afterwards. In case no scroll
449 valuator is found, or if device_id is not known to Emacs, DBL_MAX
450 is returned. Otherwise, the valuator is returned in
451 VALUATOR_RETURN. */
452static double
453x_get_scroll_valuator_delta (struct x_display_info *dpyinfo, int device_id,
454 int valuator_number, double value,
455 struct xi_scroll_valuator_t **valuator_return)
456{
457 block_input ();
458
459 for (int i = 0; i < dpyinfo->num_devices; ++i)
460 {
461 struct xi_device_t *device = &dpyinfo->devices[i];
462
463 if (device->device_id == device_id)
464 {
465 for (int j = 0; j < device->scroll_valuator_count; ++j)
466 {
467 struct xi_scroll_valuator_t *sv = &device->valuators[j];
468
469 if (sv->number == valuator_number)
470 {
471 if (sv->invalid_p)
472 {
473 sv->current_value = value;
474 sv->invalid_p = false;
475 *valuator_return = sv;
476
477 unblock_input ();
478 return 0.0;
479 }
480 else
481 {
482 double delta = (sv->current_value - value) / sv->increment;
483 sv->current_value = value;
484 *valuator_return = sv;
485
486 unblock_input ();
487 return delta;
488 }
489 }
490 }
491
492 unblock_input ();
493 return DBL_MAX;
494 }
495 }
496
497 unblock_input ();
498 return DBL_MAX;
499}
500
501static struct xi_device_t *
502xi_device_from_id (struct x_display_info *dpyinfo, int deviceid)
503{
504 for (int i = 0; i < dpyinfo->num_devices; ++i)
505 {
506 if (dpyinfo->devices[i].device_id == deviceid)
507 return &dpyinfo->devices[i];
508 }
509
510 return NULL;
511}
512
513static void
514xi_grab_or_ungrab_device (struct xi_device_t *device,
515 struct x_display_info *dpyinfo,
516 Window window)
517{
518 XIEventMask mask;
519 ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
520 unsigned char *m;
521 mask.mask = m = alloca (l);
522 memset (m, 0, l);
523 mask.mask_len = l;
524
525 XISetMask (m, XI_ButtonPress);
526 XISetMask (m, XI_ButtonRelease);
527 XISetMask (m, XI_Motion);
528 XISetMask (m, XI_Enter);
529 XISetMask (m, XI_Leave);
530
531 if (device->grab)
532 {
533 XIGrabDevice (dpyinfo->display, device->device_id, window,
534 CurrentTime, None, GrabModeAsync,
535 GrabModeAsync, True, &mask);
536 }
537 else
538 {
539 XIUngrabDevice (dpyinfo->display, device->device_id, CurrentTime);
540 }
541}
542
543static void
544xi_reset_scroll_valuators_for_device_id (struct x_display_info *dpyinfo, int id)
545{
546 struct xi_device_t *device = xi_device_from_id (dpyinfo, id);
547 struct xi_scroll_valuator_t *valuator;
548
549 if (!device)
550 return;
551
552 if (!device->scroll_valuator_count)
553 return;
554
555 for (int i = 0; i < device->scroll_valuator_count; ++i)
556 {
557 valuator = &device->valuators[i];
558 valuator->invalid_p = true;
559 }
560
561 return;
562}
563
564#endif
565
338void 566void
339x_cr_destroy_frame_context (struct frame *f) 567x_cr_destroy_frame_context (struct frame *f)
340{ 568{
@@ -4768,7 +4996,16 @@ static struct frame *
4768x_menubar_window_to_frame (struct x_display_info *dpyinfo, 4996x_menubar_window_to_frame (struct x_display_info *dpyinfo,
4769 const XEvent *event) 4997 const XEvent *event)
4770{ 4998{
4771 Window wdesc = event->xany.window; 4999 Window wdesc;
5000#ifdef HAVE_XINPUT2
5001 if (event->type == GenericEvent
5002 && dpyinfo->supports_xi2
5003 && (event->xcookie.evtype == XI_ButtonPress
5004 || event->xcookie.evtype == XI_ButtonRelease))
5005 wdesc = ((XIDeviceEvent *) event->xcookie.data)->event;
5006 else
5007#endif
5008 wdesc = event->xany.window;
4772 Lisp_Object tail, frame; 5009 Lisp_Object tail, frame;
4773 struct frame *f; 5010 struct frame *f;
4774 struct x_output *x; 5011 struct x_output *x;
@@ -4871,6 +5108,29 @@ x_detect_focus_change (struct x_display_info *dpyinfo, struct frame *frame,
4871 } 5108 }
4872 break; 5109 break;
4873 5110
5111#ifdef HAVE_XINPUT2
5112 case GenericEvent:
5113 {
5114 XIEvent *xi_event = (XIEvent *) event;
5115
5116 struct frame *focus_frame = dpyinfo->x_focus_event_frame;
5117 int focus_state
5118 = focus_frame ? focus_frame->output_data.x->focus_state : 0;
5119
5120 if (!((xi_event->evtype == XI_Enter
5121 || xi_event->evtype == XI_Leave)
5122 && (focus_state & FOCUS_EXPLICIT)))
5123 x_focus_changed ((xi_event->evtype == XI_Enter
5124 || xi_event->evtype == XI_FocusIn
5125 ? FocusIn : FocusOut),
5126 (xi_event->evtype == XI_Enter
5127 || xi_event->evtype == XI_Leave
5128 ? FOCUS_IMPLICIT : FOCUS_EXPLICIT),
5129 dpyinfo, frame, bufp);
5130 break;
5131 }
5132#endif
5133
4874 case FocusIn: 5134 case FocusIn:
4875 case FocusOut: 5135 case FocusOut:
4876 /* Ignore transient focus events from hotkeys, window manager 5136 /* Ignore transient focus events from hotkeys, window manager
@@ -7975,7 +8235,11 @@ mouse_or_wdesc_frame (struct x_display_info *dpyinfo, int wdesc)
7975 8235
7976static int 8236static int
7977handle_one_xevent (struct x_display_info *dpyinfo, 8237handle_one_xevent (struct x_display_info *dpyinfo,
8238#ifndef HAVE_XINPUT2
7978 const XEvent *event, 8239 const XEvent *event,
8240#else
8241 XEvent *event,
8242#endif
7979 int *finish, struct input_event *hold_quit) 8243 int *finish, struct input_event *hold_quit)
7980{ 8244{
7981 union buffered_input_event inev; 8245 union buffered_input_event inev;
@@ -8001,7 +8265,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
8001 inev.ie.kind = NO_EVENT; 8265 inev.ie.kind = NO_EVENT;
8002 inev.ie.arg = Qnil; 8266 inev.ie.arg = Qnil;
8003 8267
8004 any = x_any_window_to_frame (dpyinfo, event->xany.window); 8268#ifdef HAVE_XINPUT2
8269 if (event->type != GenericEvent)
8270#endif
8271 any = x_any_window_to_frame (dpyinfo, event->xany.window);
8272#ifdef HAVE_XINPUT2
8273 else
8274 any = NULL;
8275#endif
8005 8276
8006 if (any && any->wait_event_type == event->type) 8277 if (any && any->wait_event_type == event->type)
8007 any->wait_event_type = 0; /* Indicates we got it. */ 8278 any->wait_event_type = 0; /* Indicates we got it. */
@@ -8480,6 +8751,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
8480 goto OTHER; 8751 goto OTHER;
8481 8752
8482 case MapNotify: 8753 case MapNotify:
8754#if defined HAVE_XINPUT2 && defined HAVE_GTK3
8755 if (xg_is_menu_window (dpyinfo->display, event->xmap.window))
8756 popup_activated_flag = 1;
8757#endif
8483 /* We use x_top_window_to_frame because map events can 8758 /* We use x_top_window_to_frame because map events can
8484 come for sub-windows and they don't mean that the 8759 come for sub-windows and they don't mean that the
8485 frame is visible. */ 8760 frame is visible. */
@@ -9518,6 +9793,785 @@ handle_one_xevent (struct x_display_info *dpyinfo,
9518 case DestroyNotify: 9793 case DestroyNotify:
9519 xft_settings_event (dpyinfo, event); 9794 xft_settings_event (dpyinfo, event);
9520 break; 9795 break;
9796#ifdef HAVE_XINPUT2
9797 case GenericEvent:
9798 {
9799 if (!dpyinfo->supports_xi2)
9800 goto OTHER;
9801 if (event->xgeneric.extension != dpyinfo->xi2_opcode)
9802 /* Not an XI2 event. */
9803 goto OTHER;
9804 bool must_free_data = false;
9805 XIEvent *xi_event = (XIEvent *) event->xcookie.data;
9806 /* Sometimes the event is already claimed by GTK, which
9807 will free its data in due course. */
9808 if (!xi_event && XGetEventData (dpyinfo->display, &event->xcookie))
9809 {
9810 must_free_data = true;
9811 xi_event = (XIEvent *) event->xcookie.data;
9812 }
9813
9814 XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
9815 XILeaveEvent *leave = (XILeaveEvent *) xi_event;
9816 XIEnterEvent *enter = (XIEnterEvent *) xi_event;
9817 XIFocusInEvent *focusin = (XIFocusInEvent *) xi_event;
9818 XIFocusOutEvent *focusout = (XIFocusOutEvent *) xi_event;
9819 XIValuatorState *states;
9820 double *values;
9821 bool found_valuator = false;
9822
9823 /* A fake XMotionEvent for x_note_mouse_movement. */
9824 XMotionEvent ev;
9825 /* A fake XButtonEvent for x_construct_mouse_click. */
9826 XButtonEvent bv;
9827
9828 if (!xi_event)
9829 {
9830 eassert (!must_free_data);
9831 goto OTHER;
9832 }
9833
9834 switch (event->xcookie.evtype)
9835 {
9836 case XI_FocusIn:
9837 any = x_any_window_to_frame (dpyinfo, focusin->event);
9838#ifndef USE_GTK
9839 /* Some WMs (e.g. Mutter in Gnome Shell), don't unmap
9840 minimized/iconified windows; thus, for those WMs we won't get
9841 a MapNotify when unminimizing/deconifying. Check here if we
9842 are deiconizing a window (Bug42655).
9843
9844 But don't do that on GTK since it may cause a plain invisible
9845 frame get reported as iconified, compare
9846 https://lists.gnu.org/archive/html/emacs-devel/2017-02/msg00133.html.
9847 That is fixed above but bites us here again. */
9848 f = any;
9849 if (f && FRAME_ICONIFIED_P (f))
9850 {
9851 SET_FRAME_VISIBLE (f, 1);
9852 SET_FRAME_ICONIFIED (f, false);
9853 f->output_data.x->has_been_visible = true;
9854 inev.ie.kind = DEICONIFY_EVENT;
9855 XSETFRAME (inev.ie.frame_or_window, f);
9856 }
9857#endif /* USE_GTK */
9858 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
9859 goto XI_OTHER;
9860 case XI_FocusOut:
9861 any = x_any_window_to_frame (dpyinfo, focusout->event);
9862 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
9863 goto XI_OTHER;
9864 case XI_Enter:
9865 any = x_any_window_to_frame (dpyinfo, enter->event);
9866 ev.x = lrint (enter->event_x);
9867 ev.y = lrint (enter->event_y);
9868 ev.window = leave->event;
9869
9870 x_display_set_last_user_time (dpyinfo, xi_event->time);
9871 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
9872 xi_reset_scroll_valuators_for_device_id (dpyinfo, enter->deviceid);
9873 f = any;
9874
9875 if (f && x_mouse_click_focus_ignore_position)
9876 ignore_next_mouse_click_timeout = xi_event->time + 200;
9877
9878 /* EnterNotify counts as mouse movement,
9879 so update things that depend on mouse position. */
9880 if (f && !f->output_data.x->hourglass_p)
9881 x_note_mouse_movement (f, &ev);
9882#ifdef USE_GTK
9883 /* We may get an EnterNotify on the buttons in the toolbar. In that
9884 case we moved out of any highlighted area and need to note this. */
9885 if (!f && dpyinfo->last_mouse_glyph_frame)
9886 x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &ev);
9887#endif
9888 goto XI_OTHER;
9889 case XI_Leave:
9890 ev.x = lrint (leave->event_x);
9891 ev.y = lrint (leave->event_y);
9892 ev.window = leave->event;
9893 any = x_any_window_to_frame (dpyinfo, leave->event);
9894
9895 x_display_set_last_user_time (dpyinfo, xi_event->time);
9896 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
9897 xi_reset_scroll_valuators_for_device_id (dpyinfo, leave->deviceid);
9898
9899 f = x_top_window_to_frame (dpyinfo, leave->event);
9900 if (f)
9901 {
9902 if (f == hlinfo->mouse_face_mouse_frame)
9903 {
9904 /* If we move outside the frame, then we're
9905 certainly no longer on any text in the frame. */
9906 clear_mouse_face (hlinfo);
9907 hlinfo->mouse_face_mouse_frame = 0;
9908 }
9909
9910 /* Generate a nil HELP_EVENT to cancel a help-echo.
9911 Do it only if there's something to cancel.
9912 Otherwise, the startup message is cleared when
9913 the mouse leaves the frame. */
9914 if (any_help_event_p)
9915 do_help = -1;
9916 }
9917#ifdef USE_GTK
9918 /* See comment in EnterNotify above */
9919 else if (dpyinfo->last_mouse_glyph_frame)
9920 x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &ev);
9921#endif
9922 goto XI_OTHER;
9923 case XI_Motion:
9924 /* First test if there is some kind of scroll event
9925 here! */
9926 states = &xev->valuators;
9927 values = states->values;
9928
9929 x_display_set_last_user_time (dpyinfo, xi_event->time);
9930
9931 for (int i = 0; i < states->mask_len * 8; i++)
9932 {
9933 if (XIMaskIsSet (states->mask, i))
9934 {
9935 block_input ();
9936
9937 struct xi_scroll_valuator_t *val;
9938 double delta;
9939
9940 delta = x_get_scroll_valuator_delta (dpyinfo, xev->deviceid,
9941 i, *values, &val);
9942
9943 if (delta != DBL_MAX)
9944 {
9945 f = mouse_or_wdesc_frame (dpyinfo, xev->event);
9946 found_valuator = true;
9947
9948 if (signbit (delta) != signbit (val->emacs_value))
9949 val->emacs_value = 0;
9950
9951 val->emacs_value += delta;
9952
9953 if (!f)
9954 {
9955 f = x_any_window_to_frame (dpyinfo, xev->event);
9956
9957 if (!f)
9958 {
9959 unblock_input ();
9960 goto XI_OTHER;
9961 }
9962 }
9963
9964 bool s = signbit (val->emacs_value);
9965 inev.ie.kind = (val->horizontal
9966 ? HORIZ_WHEEL_EVENT
9967 : WHEEL_EVENT);
9968 inev.ie.timestamp = xev->time;
9969
9970 XSETINT (inev.ie.x, lrint (xev->event_x));
9971 XSETINT (inev.ie.y, lrint (xev->event_y));
9972 XSETFRAME (inev.ie.frame_or_window, f);
9973
9974 inev.ie.modifiers = !s ? up_modifier : down_modifier;
9975 inev.ie.modifiers
9976 |= x_x_to_emacs_modifiers (dpyinfo,
9977 xev->mods.effective);
9978 inev.ie.arg = Qnil;
9979
9980 kbd_buffer_store_event_hold (&inev.ie, hold_quit);
9981
9982 val->emacs_value = 0;
9983 }
9984 unblock_input ();
9985 values++;
9986 }
9987
9988 inev.ie.kind = NO_EVENT;
9989 }
9990
9991 if (found_valuator)
9992 goto XI_OTHER;
9993
9994 ev.x = lrint (xev->event_x);
9995 ev.y = lrint (xev->event_y);
9996 ev.window = xev->event;
9997
9998 previous_help_echo_string = help_echo_string;
9999 help_echo_string = Qnil;
10000
10001 if (hlinfo->mouse_face_hidden)
10002 {
10003 hlinfo->mouse_face_hidden = false;
10004 clear_mouse_face (hlinfo);
10005 }
10006
10007 f = mouse_or_wdesc_frame (dpyinfo, xev->event);
10008
10009#ifdef USE_GTK
10010 if (f && xg_event_is_for_scrollbar (f, event))
10011 f = 0;
10012#endif
10013 if (f)
10014 {
10015 /* Maybe generate a SELECT_WINDOW_EVENT for
10016 `mouse-autoselect-window' but don't let popup menus
10017 interfere with this (Bug#1261). */
10018 if (!NILP (Vmouse_autoselect_window)
10019 && !popup_activated ()
10020 /* Don't switch if we're currently in the minibuffer.
10021 This tries to work around problems where the
10022 minibuffer gets unselected unexpectedly, and where
10023 you then have to move your mouse all the way down to
10024 the minibuffer to select it. */
10025 && !MINI_WINDOW_P (XWINDOW (selected_window))
10026 /* With `focus-follows-mouse' non-nil create an event
10027 also when the target window is on another frame. */
10028 && (f == XFRAME (selected_frame)
10029 || !NILP (focus_follows_mouse)))
10030 {
10031 static Lisp_Object last_mouse_window;
10032 Lisp_Object window = window_from_coordinates (f, ev.x, ev.y, 0, false, false);
10033
10034 /* A window will be autoselected only when it is not
10035 selected now and the last mouse movement event was
10036 not in it. The remainder of the code is a bit vague
10037 wrt what a "window" is. For immediate autoselection,
10038 the window is usually the entire window but for GTK
10039 where the scroll bars don't count. For delayed
10040 autoselection the window is usually the window's text
10041 area including the margins. */
10042 if (WINDOWP (window)
10043 && !EQ (window, last_mouse_window)
10044 && !EQ (window, selected_window))
10045 {
10046 inev.ie.kind = SELECT_WINDOW_EVENT;
10047 inev.ie.frame_or_window = window;
10048 }
10049
10050 /* Remember the last window where we saw the mouse. */
10051 last_mouse_window = window;
10052 }
10053
10054 if (!x_note_mouse_movement (f, &ev))
10055 help_echo_string = previous_help_echo_string;
10056 }
10057 else
10058 {
10059#ifndef USE_TOOLKIT_SCROLL_BARS
10060 struct scroll_bar *bar
10061 = x_window_to_scroll_bar (xi_event->display, xev->event, 2);
10062
10063 if (bar)
10064 x_scroll_bar_note_movement (bar, &ev);
10065#endif /* USE_TOOLKIT_SCROLL_BARS */
10066
10067 /* If we move outside the frame, then we're
10068 certainly no longer on any text in the frame. */
10069 clear_mouse_face (hlinfo);
10070 }
10071
10072 /* If the contents of the global variable help_echo_string
10073 has changed, generate a HELP_EVENT. */
10074 if (!NILP (help_echo_string)
10075 || !NILP (previous_help_echo_string))
10076 do_help = 1;
10077 goto XI_OTHER;
10078 case XI_ButtonRelease:
10079 case XI_ButtonPress:
10080 {
10081 /* If we decide we want to generate an event to be seen
10082 by the rest of Emacs, we put it here. */
10083 Lisp_Object tab_bar_arg = Qnil;
10084 bool tab_bar_p = false;
10085 bool tool_bar_p = false;
10086 struct xi_device_t *device;
10087
10088 /* Ignore emulated scroll events when XI2 native
10089 scroll events are present. */
10090 if (dpyinfo->xi2_version >= 1 && xev->detail >= 4
10091 && xev->detail <= 8)
10092 goto XI_OTHER;
10093
10094 device = xi_device_from_id (dpyinfo, xev->deviceid);
10095
10096 bv.button = xev->detail;
10097 bv.type = xev->evtype == XI_ButtonPress ? ButtonPress : ButtonRelease;
10098 bv.x = lrint (xev->event_x);
10099 bv.y = lrint (xev->event_y);
10100 bv.window = xev->event;
10101 bv.state = xev->mods.base
10102 | xev->mods.effective
10103 | xev->mods.latched
10104 | xev->mods.locked;
10105
10106 memset (&compose_status, 0, sizeof (compose_status));
10107 dpyinfo->last_mouse_glyph_frame = NULL;
10108 x_display_set_last_user_time (dpyinfo, xev->time);
10109
10110 f = mouse_or_wdesc_frame (dpyinfo, xev->event);
10111
10112 if (f && xev->evtype == XI_ButtonPress
10113 && !popup_activated ()
10114 && !x_window_to_scroll_bar (xev->display, xev->event, 2)
10115 && !FRAME_NO_ACCEPT_FOCUS (f))
10116 {
10117 /* When clicking into a child frame or when clicking
10118 into a parent frame with the child frame selected and
10119 `no-accept-focus' is not set, select the clicked
10120 frame. */
10121 struct frame *hf = dpyinfo->highlight_frame;
10122
10123 if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf)))
10124 {
10125 block_input ();
10126 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10127 RevertToParent, CurrentTime);
10128 if (FRAME_PARENT_FRAME (f))
10129 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
10130 unblock_input ();
10131 }
10132 }
10133
10134#ifdef USE_GTK
10135 if (f && xg_event_is_for_scrollbar (f, event))
10136 f = 0;
10137#endif
10138
10139 if (f)
10140 {
10141 /* Is this in the tab-bar? */
10142 if (WINDOWP (f->tab_bar_window)
10143 && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)))
10144 {
10145 Lisp_Object window;
10146 int x = bv.x;
10147 int y = bv.y;
10148
10149 window = window_from_coordinates (f, x, y, 0, true, true);
10150 tab_bar_p = EQ (window, f->tab_bar_window);
10151
10152 if (tab_bar_p)
10153 tab_bar_arg = handle_tab_bar_click
10154 (f, x, y, xev->evtype == XI_ButtonPress,
10155 x_x_to_emacs_modifiers (dpyinfo, bv.state));
10156 }
10157
10158#if ! defined (USE_GTK)
10159 /* Is this in the tool-bar? */
10160 if (WINDOWP (f->tool_bar_window)
10161 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
10162 {
10163 Lisp_Object window;
10164 int x = bv.x;
10165 int y = bv.y;
10166
10167 window = window_from_coordinates (f, x, y, 0, true, true);
10168 tool_bar_p = EQ (window, f->tool_bar_window);
10169
10170 if (tool_bar_p && xev->detail < 4)
10171 handle_tool_bar_click
10172 (f, x, y, xev->evtype == XI_ButtonPress,
10173 x_x_to_emacs_modifiers (dpyinfo, bv.state));
10174 }
10175#endif /* !USE_GTK */
10176
10177 if (!(tab_bar_p && NILP (tab_bar_arg)) && !tool_bar_p)
10178#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
10179 if (! popup_activated ())
10180#endif
10181 {
10182 if (ignore_next_mouse_click_timeout)
10183 {
10184 if (xev->evtype == XI_ButtonPress
10185 && xev->time > ignore_next_mouse_click_timeout)
10186 {
10187 ignore_next_mouse_click_timeout = 0;
10188 x_construct_mouse_click (&inev.ie, &bv, f);
10189 }
10190 if (xev->evtype == XI_ButtonRelease)
10191 ignore_next_mouse_click_timeout = 0;
10192 }
10193 else
10194 x_construct_mouse_click (&inev.ie, &bv, f);
10195
10196 if (!NILP (tab_bar_arg))
10197 inev.ie.arg = tab_bar_arg;
10198 }
10199 if (FRAME_X_EMBEDDED_P (f))
10200 xembed_send_message (f, xev->time,
10201 XEMBED_REQUEST_FOCUS, 0, 0, 0);
10202 }
10203
10204 if (xev->evtype == XI_ButtonPress)
10205 {
10206 dpyinfo->grabbed |= (1 << xev->detail);
10207 device->grab |= (1 << xev->detail);
10208 dpyinfo->last_mouse_frame = f;
10209 if (f && !tab_bar_p)
10210 f->last_tab_bar_item = -1;
10211#if ! defined (USE_GTK)
10212 if (f && !tool_bar_p)
10213 f->last_tool_bar_item = -1;
10214#endif /* not USE_GTK */
10215
10216 }
10217 else
10218 {
10219 dpyinfo->grabbed &= ~(1 << xev->detail);
10220 device->grab &= ~(1 << xev->detail);
10221 }
10222
10223 xi_grab_or_ungrab_device (device, dpyinfo, xev->event);
10224
10225 if (f)
10226 f->mouse_moved = false;
10227
10228#if defined (USE_GTK)
10229 /* No Xt toolkit currently available has support for XI2.
10230 So the code here assumes use of GTK. */
10231 f = x_menubar_window_to_frame (dpyinfo, event);
10232 if (f /* Gtk+ menus only react to the first three buttons. */
10233 && xev->detail < 3)
10234 {
10235 /* What is done with Core Input ButtonPressed is not
10236 possible here, because GenericEvents cannot be saved. */
10237 bool was_waiting_for_input = waiting_for_input;
10238 /* This hack was adopted from the NS port. Whether
10239 or not it is actually safe is a different story
10240 altogether. */
10241 if (waiting_for_input)
10242 waiting_for_input = 0;
10243 set_frame_menubar (f, true);
10244 waiting_for_input = was_waiting_for_input;
10245 }
10246#endif
10247 goto XI_OTHER;
10248 }
10249 case XI_KeyPress:
10250 {
10251 int state = xev->mods.base
10252 | xev->mods.effective
10253 | xev->mods.latched
10254 | xev->mods.locked;
10255 Lisp_Object c;
10256#ifdef HAVE_XKB
10257 unsigned int mods_rtrn;
10258#endif
10259 int keycode = xev->detail;
10260 KeySym keysym;
10261 char copy_buffer[81];
10262 char *copy_bufptr = copy_buffer;
10263 unsigned char *copy_ubufptr;
10264#ifdef HAVE_XKB
10265 int copy_bufsiz = sizeof (copy_buffer);
10266#endif
10267 ptrdiff_t i;
10268 int nchars, len;
10269
10270#ifdef HAVE_XKB
10271 if (dpyinfo->xkb_desc)
10272 {
10273 if (!XkbTranslateKeyCode (dpyinfo->xkb_desc, keycode,
10274 state, &mods_rtrn, &keysym))
10275 goto XI_OTHER;
10276 }
10277 else
10278 {
10279#endif
10280 int keysyms_per_keycode_return;
10281 KeySym *ksms = XGetKeyboardMapping (dpyinfo->display, keycode, 1,
10282 &keysyms_per_keycode_return);
10283 if (!(keysym = ksms[0]))
10284 {
10285 XFree (ksms);
10286 goto XI_OTHER;
10287 }
10288 XFree (ksms);
10289#ifdef HAVE_XKB
10290 }
10291#endif
10292
10293 if (keysym == NoSymbol)
10294 goto XI_OTHER;
10295
10296 x_display_set_last_user_time (dpyinfo, xev->time);
10297 ignore_next_mouse_click_timeout = 0;
10298
10299#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
10300 /* Dispatch XI_KeyPress events when in menu. */
10301 if (popup_activated ())
10302 goto XI_OTHER;
10303#endif
10304
10305 f = x_any_window_to_frame (dpyinfo, xev->event);
10306
10307 /* If mouse-highlight is an integer, input clears out
10308 mouse highlighting. */
10309 if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight)
10310 && (f == 0
10311#if ! defined (USE_GTK)
10312 || !EQ (f->tool_bar_window, hlinfo->mouse_face_window)
10313#endif
10314 || !EQ (f->tab_bar_window, hlinfo->mouse_face_window))
10315 )
10316 {
10317 clear_mouse_face (hlinfo);
10318 hlinfo->mouse_face_hidden = true;
10319 }
10320
10321 if (f != 0)
10322 {
10323#ifdef USE_GTK
10324 /* Don't pass keys to GTK. A Tab will shift focus to the
10325 tool bar in GTK 2.4. Keys will still go to menus and
10326 dialogs because in that case popup_activated is nonzero
10327 (see above). */
10328 *finish = X_EVENT_DROP;
10329#endif
10330 /* If not using XIM/XIC, and a compose sequence is in progress,
10331 we break here. Otherwise, chars_matched is always 0. */
10332 if (compose_status.chars_matched > 0 && nbytes == 0)
10333 goto XI_OTHER;
10334
10335 memset (&compose_status, 0, sizeof (compose_status));
10336
10337 XSETFRAME (inev.ie.frame_or_window, f);
10338 inev.ie.modifiers
10339 = x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), state);
10340 inev.ie.timestamp = xev->time;
10341
10342 /* First deal with keysyms which have defined
10343 translations to characters. */
10344 if (keysym >= 32 && keysym < 128)
10345 /* Avoid explicitly decoding each ASCII character. */
10346 {
10347 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
10348 inev.ie.code = keysym;
10349
10350 goto xi_done_keysym;
10351 }
10352
10353 /* Keysyms directly mapped to Unicode characters. */
10354 if (keysym >= 0x01000000 && keysym <= 0x0110FFFF)
10355 {
10356 if (keysym < 0x01000080)
10357 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
10358 else
10359 inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10360 inev.ie.code = keysym & 0xFFFFFF;
10361 goto xi_done_keysym;
10362 }
10363
10364 /* Now non-ASCII. */
10365 if (HASH_TABLE_P (Vx_keysym_table)
10366 && (c = Fgethash (make_fixnum (keysym),
10367 Vx_keysym_table,
10368 Qnil),
10369 FIXNATP (c)))
10370 {
10371 inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c))
10372 ? ASCII_KEYSTROKE_EVENT
10373 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
10374 inev.ie.code = XFIXNAT (c);
10375 goto xi_done_keysym;
10376 }
10377
10378 /* Random non-modifier sorts of keysyms. */
10379 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
10380 || keysym == XK_Delete
10381#ifdef XK_ISO_Left_Tab
10382 || (keysym >= XK_ISO_Left_Tab
10383 && keysym <= XK_ISO_Enter)
10384#endif
10385 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
10386 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
10387#ifdef HPUX
10388 /* This recognizes the "extended function
10389 keys". It seems there's no cleaner way.
10390 Test IsModifierKey to avoid handling
10391 mode_switch incorrectly. */
10392 || (XK_Select <= keysym && keysym < XK_KP_Space)
10393#endif
10394#ifdef XK_dead_circumflex
10395 || keysym == XK_dead_circumflex
10396#endif
10397#ifdef XK_dead_grave
10398 || keysym == XK_dead_grave
10399#endif
10400#ifdef XK_dead_tilde
10401 || keysym == XK_dead_tilde
10402#endif
10403#ifdef XK_dead_diaeresis
10404 || keysym == XK_dead_diaeresis
10405#endif
10406#ifdef XK_dead_macron
10407 || keysym == XK_dead_macron
10408#endif
10409#ifdef XK_dead_degree
10410 || keysym == XK_dead_degree
10411#endif
10412#ifdef XK_dead_acute
10413 || keysym == XK_dead_acute
10414#endif
10415#ifdef XK_dead_cedilla
10416 || keysym == XK_dead_cedilla
10417#endif
10418#ifdef XK_dead_breve
10419 || keysym == XK_dead_breve
10420#endif
10421#ifdef XK_dead_ogonek
10422 || keysym == XK_dead_ogonek
10423#endif
10424#ifdef XK_dead_caron
10425 || keysym == XK_dead_caron
10426#endif
10427#ifdef XK_dead_doubleacute
10428 || keysym == XK_dead_doubleacute
10429#endif
10430#ifdef XK_dead_abovedot
10431 || keysym == XK_dead_abovedot
10432#endif
10433 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
10434 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
10435 /* Any "vendor-specific" key is ok. */
10436 || (keysym & (1 << 28))
10437 || (keysym != NoSymbol && nbytes == 0))
10438 && ! (IsModifierKey (keysym)
10439 /* The symbols from XK_ISO_Lock
10440 to XK_ISO_Last_Group_Lock
10441 don't have real modifiers but
10442 should be treated similarly to
10443 Mode_switch by Emacs. */
10444#if defined XK_ISO_Lock && defined XK_ISO_Last_Group_Lock
10445 || (XK_ISO_Lock <= keysym
10446 && keysym <= XK_ISO_Last_Group_Lock)
10447#endif
10448 ))
10449 {
10450 STORE_KEYSYM_FOR_DEBUG (keysym);
10451 /* make_lispy_event will convert this to a symbolic
10452 key. */
10453 inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT;
10454 inev.ie.code = keysym;
10455 goto xi_done_keysym;
10456 }
10457
10458#ifdef HAVE_XKB
10459 int overflow = 0;
10460 KeySym sym = keysym;
10461
10462 if (dpyinfo->xkb_desc)
10463 {
10464 if (!(nbytes = XkbTranslateKeySym (dpyinfo->display, &sym,
10465 state & ~mods_rtrn, copy_bufptr,
10466 copy_bufsiz, &overflow)))
10467 goto XI_OTHER;
10468 }
10469 else
10470#else
10471 {
10472 block_input ();
10473 char *str = XKeysymToString (keysym);
10474 if (!str)
10475 {
10476 unblock_input ();
10477 goto XI_OTHER;
10478 }
10479 nbytes = strlen (str) + 1;
10480 copy_bufptr = alloca (nbytes);
10481 strcpy (copy_bufptr, str);
10482 unblock_input ();
10483 }
10484#endif
10485#ifdef HAVE_XKB
10486 if (overflow)
10487 {
10488 overflow = 0;
10489 copy_bufptr = alloca (copy_bufsiz + overflow);
10490 keysym = sym;
10491 if (!(nbytes = XkbTranslateKeySym (dpyinfo->display, &sym,
10492 state & ~mods_rtrn, copy_bufptr,
10493 copy_bufsiz + overflow, &overflow)))
10494 goto XI_OTHER;
10495
10496 if (overflow)
10497 goto XI_OTHER;
10498 }
10499#endif
10500
10501 for (i = 0, nchars = 0; i < nbytes; i++)
10502 {
10503 if (ASCII_CHAR_P (copy_bufptr[i]))
10504 nchars++;
10505 STORE_KEYSYM_FOR_DEBUG (copy_bufptr[i]);
10506 }
10507
10508 if (nchars < nbytes)
10509 {
10510 /* Decode the input data. */
10511
10512 setup_coding_system (Vlocale_coding_system, &coding);
10513 coding.src_multibyte = false;
10514 coding.dst_multibyte = true;
10515 /* The input is converted to events, thus we can't
10516 handle composition. Anyway, there's no XIM that
10517 gives us composition information. */
10518 coding.common_flags &= ~CODING_ANNOTATION_MASK;
10519
10520 SAFE_NALLOCA (coding.destination, MAX_MULTIBYTE_LENGTH,
10521 nbytes);
10522 coding.dst_bytes = MAX_MULTIBYTE_LENGTH * nbytes;
10523 coding.mode |= CODING_MODE_LAST_BLOCK;
10524 decode_coding_c_string (&coding, (unsigned char *) copy_bufptr,
10525 nbytes, Qnil);
10526 nbytes = coding.produced;
10527 nchars = coding.produced_char;
10528 copy_bufptr = (char *) coding.destination;
10529 }
10530
10531 copy_ubufptr = (unsigned char *) copy_bufptr;
10532
10533 /* Convert the input data to a sequence of
10534 character events. */
10535 for (i = 0; i < nbytes; i += len)
10536 {
10537 int ch;
10538 if (nchars == nbytes)
10539 ch = copy_ubufptr[i], len = 1;
10540 else
10541 ch = string_char_and_length (copy_ubufptr + i, &len);
10542 inev.ie.kind = (SINGLE_BYTE_CHAR_P (ch)
10543 ? ASCII_KEYSTROKE_EVENT
10544 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
10545 inev.ie.code = ch;
10546 kbd_buffer_store_buffered_event (&inev, hold_quit);
10547 }
10548
10549 inev.ie.kind = NO_EVENT;
10550 goto xi_done_keysym;
10551 }
10552 goto XI_OTHER;
10553 }
10554 case XI_KeyRelease:
10555 x_display_set_last_user_time (dpyinfo, xev->time);
10556 goto XI_OTHER;
10557 case XI_PropertyEvent:
10558 case XI_HierarchyChanged:
10559 case XI_DeviceChanged:
10560 x_init_master_valuators (dpyinfo);
10561 goto XI_OTHER;
10562 default:
10563 goto XI_OTHER;
10564 }
10565 xi_done_keysym:
10566 if (must_free_data)
10567 XFreeEventData (dpyinfo->display, &event->xcookie);
10568 goto done_keysym;
10569 XI_OTHER:
10570 if (must_free_data)
10571 XFreeEventData (dpyinfo->display, &event->xcookie);
10572 goto OTHER;
10573 }
10574#endif
9521 10575
9522 default: 10576 default:
9523 OTHER: 10577 OTHER:
@@ -13199,6 +14253,40 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
13199 dpyinfo->supports_xdbe = true; 14253 dpyinfo->supports_xdbe = true;
13200#endif 14254#endif
13201 14255
14256#ifdef HAVE_XINPUT2
14257 dpyinfo->supports_xi2 = false;
14258 int rc;
14259 int major = 2;
14260#ifdef XI_BarrierHit /* XInput 2.3 */
14261 int minor = 3;
14262#elif defined XI_TouchBegin /* XInput 2.2 */
14263 int minor = 2;
14264#elif defined XIScrollClass /* XInput 1.1 */
14265 int minor = 1;
14266#else /* Some old version of XI2 we're not interested in. */
14267 int minor = 0;
14268#endif
14269 int fer, fee;
14270
14271 if (XQueryExtension (dpyinfo->display, "XInputExtension",
14272 &dpyinfo->xi2_opcode, &fer, &fee))
14273 {
14274 rc = XIQueryVersion (dpyinfo->display, &major, &minor);
14275 if (rc == Success)
14276 {
14277 dpyinfo->supports_xi2 = true;
14278 x_init_master_valuators (dpyinfo);
14279 }
14280 }
14281 dpyinfo->xi2_version = minor;
14282#endif
14283
14284#ifdef HAVE_XKB
14285 dpyinfo->xkb_desc = XkbGetMap (dpyinfo->display,
14286 XkbAllComponentsMask,
14287 XkbUseCoreKbd);
14288#endif
14289
13202#if defined USE_CAIRO || defined HAVE_XFT 14290#if defined USE_CAIRO || defined HAVE_XFT
13203 { 14291 {
13204 /* If we are using Xft, the following precautions should be made: 14292 /* If we are using Xft, the following precautions should be made:
@@ -13631,6 +14719,14 @@ x_delete_terminal (struct terminal *terminal)
13631 XrmDestroyDatabase (dpyinfo->rdb); 14719 XrmDestroyDatabase (dpyinfo->rdb);
13632#endif 14720#endif
13633 14721
14722#ifdef HAVE_XKB
14723 if (dpyinfo->xkb_desc)
14724 XkbFreeKeyboard (dpyinfo->xkb_desc, XkbAllComponentsMask, True);
14725#endif
14726#ifdef HAVE_XINPUT2
14727 if (dpyinfo->supports_xi2)
14728 x_free_xi_devices (dpyinfo);
14729#endif
13634#ifdef USE_GTK 14730#ifdef USE_GTK
13635 xg_display_close (dpyinfo->display); 14731 xg_display_close (dpyinfo->display);
13636#else 14732#else
@@ -13790,9 +14886,12 @@ x_initialize (void)
13790void 14886void
13791init_xterm (void) 14887init_xterm (void)
13792{ 14888{
13793 /* Emacs can handle only core input events, so make sure 14889#ifndef HAVE_XINPUT2
13794 Gtk doesn't use Xinput or Xinput2 extensions. */ 14890 /* Emacs can handle only core input events when built without XI2
14891 support, so make sure Gtk doesn't use Xinput or Xinput2
14892 extensions. */
13795 xputenv ("GDK_CORE_DEVICE_EVENTS=1"); 14893 xputenv ("GDK_CORE_DEVICE_EVENTS=1");
14894#endif
13796} 14895}
13797#endif 14896#endif
13798 14897
diff --git a/src/xterm.h b/src/xterm.h
index 9d9534dd629..7abe168bc6f 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -88,6 +88,10 @@ typedef GtkWidget *xt_or_gtk_widget;
88#include <X11/Xlib-xcb.h> 88#include <X11/Xlib-xcb.h>
89#endif 89#endif
90 90
91#ifdef HAVE_XKB
92#include <X11/XKBlib.h>
93#endif
94
91#include "dispextern.h" 95#include "dispextern.h"
92#include "termhooks.h" 96#include "termhooks.h"
93 97
@@ -163,6 +167,28 @@ struct color_name_cache_entry
163 char *name; 167 char *name;
164}; 168};
165 169
170#ifdef HAVE_XINPUT2
171struct xi_scroll_valuator_t
172{
173 bool invalid_p;
174 double current_value;
175 double emacs_value;
176 double increment;
177
178 int number;
179 int horizontal;
180};
181
182struct xi_device_t
183{
184 int device_id;
185 int scroll_valuator_count;
186 int grab;
187
188 struct xi_scroll_valuator_t *valuators;
189};
190#endif
191
166Status x_parse_color (struct frame *f, const char *color_name, 192Status x_parse_color (struct frame *f, const char *color_name,
167 XColor *color); 193 XColor *color);
168 194
@@ -474,6 +500,19 @@ struct x_display_info
474#ifdef HAVE_XDBE 500#ifdef HAVE_XDBE
475 bool supports_xdbe; 501 bool supports_xdbe;
476#endif 502#endif
503
504#ifdef HAVE_XINPUT2
505 bool supports_xi2;
506 int xi2_version;
507 int xi2_opcode;
508
509 int num_devices;
510 struct xi_device_t *devices;
511#endif
512
513#ifdef HAVE_XKB
514 XkbDescPtr xkb_desc;
515#endif
477}; 516};
478 517
479#ifdef HAVE_X_I18N 518#ifdef HAVE_X_I18N
@@ -481,6 +520,11 @@ struct x_display_info
481extern bool use_xim; 520extern bool use_xim;
482#endif 521#endif
483 522
523#ifdef HAVE_XINPUT2
524/* Defined in xmenu.c. */
525extern int popup_activated_flag;
526#endif
527
484/* This is a chain of structures for all the X displays currently in use. */ 528/* This is a chain of structures for all the X displays currently in use. */
485extern struct x_display_info *x_display_list; 529extern struct x_display_info *x_display_list;
486 530