aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authoroldosfan2021-11-01 08:19:32 +0800
committerPo Lu2021-11-10 13:27:01 +0800
commit346cfc81247e6bf8e727a27b42f44f2389bd1269 (patch)
tree424eb046da6c0b2e2e75651226d2c613f6da640e /src
parent68a2a3307d1703ac8abe4b54c8e1ef9dda677c12 (diff)
downloademacs-346cfc81247e6bf8e727a27b42f44f2389bd1269.tar.gz
emacs-346cfc81247e6bf8e727a27b42f44f2389bd1269.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 * 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 (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
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.c78
-rw-r--r--src/xmenu.c4
-rw-r--r--src/xterm.c1086
-rw-r--r--src/xterm.h42
7 files changed, 1286 insertions, 7 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index 4c5535f8ad9..4795ade3eaa 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 $(WEBKIT_CFLAGS) $(WEBP_CFLAGS) $(LCMS2_CFLAGS) $(XINPUT_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..c792826e6be 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
@@ -3074,6 +3078,43 @@ x_window (struct frame *f, long window_prompting)
3074 class_hints.res_class = SSDATA (Vx_resource_class); 3078 class_hints.res_class = SSDATA (Vx_resource_class);
3075 XSetClassHint (FRAME_X_DISPLAY (f), XtWindow (shell_widget), &class_hints); 3079 XSetClassHint (FRAME_X_DISPLAY (f), XtWindow (shell_widget), &class_hints);
3076 3080
3081#ifdef HAVE_XINPUT2
3082 if (FRAME_DISPLAY_INFO (f)->supports_xi2)
3083 {
3084 XIEventMask mask;
3085 ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
3086 unsigned char *m;
3087 mask.mask = m = alloca (l);
3088 memset (m, 0, l);
3089 mask.mask_len = l;
3090 mask.deviceid = XIAllMasterDevices;
3091
3092 XISetMask (m, XI_ButtonPress);
3093 XISetMask (m, XI_ButtonRelease);
3094 XISetMask (m, XI_KeyPress);
3095 XISetMask (m, XI_KeyRelease);
3096 XISetMask (m, XI_Motion);
3097 XISetMask (m, XI_Enter);
3098 XISetMask (m, XI_Leave);
3099 XISetMask (m, XI_FocusIn);
3100 XISetMask (m, XI_FocusOut);
3101 XISetMask (m, XI_DeviceChanged);
3102
3103 XISelectEvents (FRAME_X_DISPLAY (f),
3104 FRAME_X_WINDOW (f),
3105 &mask, 1);
3106
3107 mask.deviceid = XIAllDevices;
3108 memset (m, 0, l);
3109 XISetMask (m, XI_PropertyEvent);
3110 XISetMask (m, XI_HierarchyChanged);
3111
3112 XISelectEvents (FRAME_X_DISPLAY (f),
3113 FRAME_X_WINDOW (f),
3114 &mask, 1);
3115 }
3116#endif
3117
3077#ifdef HAVE_X_I18N 3118#ifdef HAVE_X_I18N
3078 FRAME_XIC (f) = NULL; 3119 FRAME_XIC (f) = NULL;
3079 if (use_xim) 3120 if (use_xim)
@@ -3254,6 +3295,43 @@ x_window (struct frame *f)
3254 } 3295 }
3255#endif /* HAVE_X_I18N */ 3296#endif /* HAVE_X_I18N */
3256 3297
3298#ifdef HAVE_XINPUT2
3299 if (FRAME_DISPLAY_INFO (f)->supports_xi2)
3300 {
3301 XIEventMask mask;
3302 ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
3303 unsigned char *m;
3304 mask.mask = m = alloca (l);
3305 memset (m, 0, l);
3306 mask.mask_len = l;
3307 mask.deviceid = XIAllMasterDevices;
3308
3309 XISetMask (m, XI_ButtonPress);
3310 XISetMask (m, XI_ButtonRelease);
3311 XISetMask (m, XI_KeyPress);
3312 XISetMask (m, XI_KeyRelease);
3313 XISetMask (m, XI_Motion);
3314 XISetMask (m, XI_Enter);
3315 XISetMask (m, XI_Leave);
3316 XISetMask (m, XI_FocusIn);
3317 XISetMask (m, XI_FocusOut);
3318 XISetMask (m, XI_DeviceChanged);
3319
3320 XISelectEvents (FRAME_X_DISPLAY (f),
3321 FRAME_X_WINDOW (f),
3322 &mask, 1);
3323
3324 mask.deviceid = XIAllDevices;
3325 memset (m, 0, l);
3326 XISetMask (m, XI_PropertyEvent);
3327 XISetMask (m, XI_HierarchyChanged);
3328
3329 XISelectEvents (FRAME_X_DISPLAY (f),
3330 FRAME_X_WINDOW (f),
3331 &mask, 1);
3332 }
3333#endif
3334
3257 validate_x_resource_name (); 3335 validate_x_resource_name ();
3258 3336
3259 class_hints.res_name = SSDATA (Vx_resource_name); 3337 class_hints.res_name = SSDATA (Vx_resource_name);
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 172abe919dd..d0da6ad6a6d 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,156 @@ 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 xfree (dpyinfo->devices[i].valuators);
361
362 xfree (dpyinfo->devices);
363 dpyinfo->devices = NULL;
364 dpyinfo->num_devices = 0;
365 }
366
367 unblock_input ();
368}
369
370/* Setup valuator tracking for XI2 master devices on
371 DPYINFO->display. */
372
373static void
374x_init_master_valuators (struct x_display_info *dpyinfo)
375{
376 int ndevices;
377 XIDeviceInfo *infos;
378
379 block_input ();
380 x_free_xi_devices (dpyinfo);
381 infos = XIQueryDevice (dpyinfo->display,
382 XIAllMasterDevices,
383 &ndevices);
384
385 if (!ndevices)
386 {
387 XIFreeDeviceInfo (infos);
388 unblock_input ();
389 return;
390 }
391
392 int actual_devices = 0;
393 dpyinfo->devices = xmalloc (sizeof *dpyinfo->devices * ndevices);
394
395 for (int i = 0; i < ndevices; ++i)
396 {
397 XIDeviceInfo *device = &infos[i];
398
399 if (device->enabled)
400 {
401 int actual_valuator_count = 0;
402 struct xi_device_t *xi_device =
403 &dpyinfo->devices[actual_devices++];
404 xi_device->device_id = device->deviceid;
405 xi_device->valuators =
406 xmalloc (sizeof *xi_device->valuators * device->num_classes);
407
408 for (int c = 0; c < device->num_classes; ++c)
409 {
410 switch (device->classes[c]->type)
411 {
412#ifdef XIScrollClass /* XInput 2.1 */
413 case XIScrollClass:
414 {
415 XIScrollClassInfo *info =
416 (XIScrollClassInfo *) device->classes[c];
417 struct xi_scroll_valuator_t *valuator =
418 &xi_device->valuators[actual_valuator_count++];
419
420 valuator->horizontal = (info->scroll_type == XIScrollTypeHorizontal);
421 valuator->invalid_p = true;
422 valuator->emacs_value = DBL_MIN;
423 valuator->increment = info->increment;
424 valuator->number = info->number;
425 break;
426 }
427#endif
428 default:
429 break;
430 }
431 }
432 xi_device->scroll_valuator_count = actual_valuator_count;
433 }
434 }
435
436 dpyinfo->num_devices = actual_devices;
437 XIFreeDeviceInfo (infos);
438 unblock_input ();
439}
440
441/* Return the delta of the scroll valuator VALUATOR_NUMBER under
442 DEVICE_ID in the display DPYINFO with VALUE. The valuator's
443 valuator will be set to VALUE afterwards. In case no scroll
444 valuator is found, or if device_id is not known to Emacs, DBL_MAX
445 is returned. Otherwise, the valuator is returned in
446 VALUATOR_RETURN. */
447static double
448x_get_scroll_valuator_delta (struct x_display_info *dpyinfo, int device_id,
449 int valuator_number, double value,
450 struct xi_scroll_valuator_t **valuator_return)
451{
452 block_input ();
453
454 for (int i = 0; i < dpyinfo->num_devices; ++i)
455 {
456 struct xi_device_t *device = &dpyinfo->devices[i];
457
458 if (device->device_id == device_id)
459 {
460 for (int j = 0; j < device->scroll_valuator_count; ++j)
461 {
462 struct xi_scroll_valuator_t *sv = &device->valuators[j];
463
464 if (sv->number == valuator_number)
465 {
466 if (sv->invalid_p)
467 {
468 sv->current_value = value;
469 sv->invalid_p = false;
470 *valuator_return = sv;
471
472 unblock_input ();
473 return 0.0;
474 }
475 else
476 {
477 double delta = sv->current_value - value;
478 sv->current_value = value;
479 *valuator_return = sv;
480
481 unblock_input ();
482 return delta / sv->increment;
483 }
484 }
485 }
486
487 unblock_input ();
488 return DBL_MAX;
489 }
490 }
491
492 unblock_input ();
493 return DBL_MAX;
494}
495
496#endif
497
338void 498void
339x_cr_destroy_frame_context (struct frame *f) 499x_cr_destroy_frame_context (struct frame *f)
340{ 500{
@@ -4768,7 +4928,16 @@ static struct frame *
4768x_menubar_window_to_frame (struct x_display_info *dpyinfo, 4928x_menubar_window_to_frame (struct x_display_info *dpyinfo,
4769 const XEvent *event) 4929 const XEvent *event)
4770{ 4930{
4771 Window wdesc = event->xany.window; 4931 Window wdesc;
4932#ifdef HAVE_XINPUT2
4933 if (event->type == GenericEvent
4934 && dpyinfo->supports_xi2
4935 && (event->xcookie.evtype == XI_ButtonPress
4936 || event->xcookie.evtype == XI_ButtonRelease))
4937 wdesc = ((XIDeviceEvent *) event->xcookie.data)->event;
4938 else
4939#endif
4940 wdesc = event->xany.window;
4772 Lisp_Object tail, frame; 4941 Lisp_Object tail, frame;
4773 struct frame *f; 4942 struct frame *f;
4774 struct x_output *x; 4943 struct x_output *x;
@@ -4871,6 +5040,29 @@ x_detect_focus_change (struct x_display_info *dpyinfo, struct frame *frame,
4871 } 5040 }
4872 break; 5041 break;
4873 5042
5043#ifdef HAVE_XINPUT2
5044 case GenericEvent:
5045 {
5046 XIEvent *xi_event = (XIEvent *) event;
5047
5048 struct frame *focus_frame = dpyinfo->x_focus_event_frame;
5049 int focus_state
5050 = focus_frame ? focus_frame->output_data.x->focus_state : 0;
5051
5052 if (!((xi_event->evtype == XI_Enter
5053 || xi_event->evtype == XI_Leave)
5054 && (focus_state & FOCUS_EXPLICIT)))
5055 x_focus_changed ((xi_event->evtype == XI_Enter
5056 || xi_event->evtype == XI_FocusIn
5057 ? FocusIn : FocusOut),
5058 (xi_event->evtype == XI_Enter
5059 || xi_event->evtype == XI_Leave
5060 ? FOCUS_IMPLICIT : FOCUS_EXPLICIT),
5061 dpyinfo, frame, bufp);
5062 break;
5063 }
5064#endif
5065
4874 case FocusIn: 5066 case FocusIn:
4875 case FocusOut: 5067 case FocusOut:
4876 /* Ignore transient focus events from hotkeys, window manager 5068 /* Ignore transient focus events from hotkeys, window manager
@@ -7975,7 +8167,11 @@ mouse_or_wdesc_frame (struct x_display_info *dpyinfo, int wdesc)
7975 8167
7976static int 8168static int
7977handle_one_xevent (struct x_display_info *dpyinfo, 8169handle_one_xevent (struct x_display_info *dpyinfo,
8170#ifndef HAVE_XINPUT2
7978 const XEvent *event, 8171 const XEvent *event,
8172#else
8173 XEvent *event,
8174#endif
7979 int *finish, struct input_event *hold_quit) 8175 int *finish, struct input_event *hold_quit)
7980{ 8176{
7981 union buffered_input_event inev; 8177 union buffered_input_event inev;
@@ -8001,7 +8197,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
8001 inev.ie.kind = NO_EVENT; 8197 inev.ie.kind = NO_EVENT;
8002 inev.ie.arg = Qnil; 8198 inev.ie.arg = Qnil;
8003 8199
8004 any = x_any_window_to_frame (dpyinfo, event->xany.window); 8200#ifdef HAVE_XINPUT2
8201 if (event->type != GenericEvent)
8202#endif
8203 any = x_any_window_to_frame (dpyinfo, event->xany.window);
8204#ifdef HAVE_XINPUT2
8205 else
8206 any = NULL;
8207#endif
8005 8208
8006 if (any && any->wait_event_type == event->type) 8209 if (any && any->wait_event_type == event->type)
8007 any->wait_event_type = 0; /* Indicates we got it. */ 8210 any->wait_event_type = 0; /* Indicates we got it. */
@@ -8480,6 +8683,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
8480 goto OTHER; 8683 goto OTHER;
8481 8684
8482 case MapNotify: 8685 case MapNotify:
8686#if defined HAVE_XINPUT2 && defined HAVE_GTK3
8687 if (xg_is_menu_window (dpyinfo->display, event->xmap.window))
8688 popup_activated_flag = 1;
8689#endif
8483 /* We use x_top_window_to_frame because map events can 8690 /* We use x_top_window_to_frame because map events can
8484 come for sub-windows and they don't mean that the 8691 come for sub-windows and they don't mean that the
8485 frame is visible. */ 8692 frame is visible. */
@@ -9518,6 +9725,832 @@ handle_one_xevent (struct x_display_info *dpyinfo,
9518 case DestroyNotify: 9725 case DestroyNotify:
9519 xft_settings_event (dpyinfo, event); 9726 xft_settings_event (dpyinfo, event);
9520 break; 9727 break;
9728#ifdef HAVE_XINPUT2
9729 case GenericEvent:
9730 {
9731 if (!dpyinfo->supports_xi2)
9732 goto OTHER;
9733 if (event->xgeneric.extension != dpyinfo->xi2_opcode)
9734 /* Not an XI2 event. */
9735 goto OTHER;
9736 bool must_free_data = false;
9737 XIEvent *xi_event = (XIEvent *) event->xcookie.data;
9738 /* Sometimes the event is already claimed by GTK, which
9739 will free its data in due course. */
9740 if (!xi_event && XGetEventData (dpyinfo->display, &event->xcookie))
9741 {
9742 must_free_data = true;
9743 xi_event = (XIEvent *) event->xcookie.data;
9744 }
9745
9746 XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
9747 XILeaveEvent *leave = (XILeaveEvent *) xi_event;
9748 XIEnterEvent *enter = (XIEnterEvent *) xi_event;
9749 XIFocusInEvent *focusin = (XIFocusInEvent *) xi_event;
9750 XIFocusOutEvent *focusout = (XIFocusOutEvent *) xi_event;
9751 XIValuatorState *states;
9752 double *values;
9753 bool found_valuator = false;
9754
9755 /* A fake XMotionEvent for x_note_mouse_movement. */
9756 XMotionEvent ev;
9757 /* A fake XButtonEvent for x_construct_mouse_click. */
9758 XButtonEvent bv;
9759
9760 if (!xi_event)
9761 {
9762 eassert (!must_free_data);
9763 goto OTHER;
9764 }
9765
9766 switch (event->xcookie.evtype)
9767 {
9768 case XI_FocusIn:
9769 any = x_any_window_to_frame (dpyinfo, focusin->event);
9770#ifndef USE_GTK
9771 /* Some WMs (e.g. Mutter in Gnome Shell), don't unmap
9772 minimized/iconified windows; thus, for those WMs we won't get
9773 a MapNotify when unminimizing/deconifying. Check here if we
9774 are deiconizing a window (Bug42655).
9775
9776 But don't do that on GTK since it may cause a plain invisible
9777 frame get reported as iconified, compare
9778 https://lists.gnu.org/archive/html/emacs-devel/2017-02/msg00133.html.
9779 That is fixed above but bites us here again. */
9780 f = any;
9781 if (f && FRAME_ICONIFIED_P (f))
9782 {
9783 SET_FRAME_VISIBLE (f, 1);
9784 SET_FRAME_ICONIFIED (f, false);
9785 f->output_data.x->has_been_visible = true;
9786 inev.ie.kind = DEICONIFY_EVENT;
9787 XSETFRAME (inev.ie.frame_or_window, f);
9788 }
9789#endif /* USE_GTK */
9790 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
9791 goto XI_OTHER;
9792 case XI_FocusOut:
9793 any = x_any_window_to_frame (dpyinfo, focusout->event);
9794 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
9795 goto XI_OTHER;
9796 case XI_Enter:
9797 any = x_any_window_to_frame (dpyinfo, enter->event);
9798 ev.x = lrint (enter->event_x);
9799 ev.y = lrint (enter->event_y);
9800 ev.window = leave->event;
9801
9802 x_display_set_last_user_time (dpyinfo, xi_event->time);
9803 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
9804 f = any;
9805
9806 if (f && x_mouse_click_focus_ignore_position)
9807 ignore_next_mouse_click_timeout = xi_event->time + 200;
9808
9809 /* EnterNotify counts as mouse movement,
9810 so update things that depend on mouse position. */
9811 if (f && !f->output_data.x->hourglass_p)
9812 x_note_mouse_movement (f, &ev);
9813#ifdef USE_GTK
9814 /* We may get an EnterNotify on the buttons in the toolbar. In that
9815 case we moved out of any highlighted area and need to note this. */
9816 if (!f && dpyinfo->last_mouse_glyph_frame)
9817 x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &ev);
9818#endif
9819 goto XI_OTHER;
9820 case XI_Leave:
9821 ev.x = lrint (leave->event_x);
9822 ev.y = lrint (leave->event_y);
9823 ev.window = leave->event;
9824 any = x_any_window_to_frame (dpyinfo, leave->event);
9825
9826 x_display_set_last_user_time (dpyinfo, xi_event->time);
9827 x_detect_focus_change (dpyinfo, any, event, &inev.ie);
9828
9829 f = x_top_window_to_frame (dpyinfo, leave->event);
9830 if (f)
9831 {
9832 if (f == hlinfo->mouse_face_mouse_frame)
9833 {
9834 /* If we move outside the frame, then we're
9835 certainly no longer on any text in the frame. */
9836 clear_mouse_face (hlinfo);
9837 hlinfo->mouse_face_mouse_frame = 0;
9838 }
9839
9840 /* Generate a nil HELP_EVENT to cancel a help-echo.
9841 Do it only if there's something to cancel.
9842 Otherwise, the startup message is cleared when
9843 the mouse leaves the frame. */
9844 if (any_help_event_p)
9845 do_help = -1;
9846 }
9847#ifdef USE_GTK
9848 /* See comment in EnterNotify above */
9849 else if (dpyinfo->last_mouse_glyph_frame)
9850 x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &ev);
9851#endif
9852 goto XI_OTHER;
9853 case XI_Motion:
9854 /* First test if there is some kind of scroll event
9855 here! */
9856 states = &xev->valuators;
9857 values = states->values;
9858
9859 x_display_set_last_user_time (dpyinfo, xi_event->time);
9860
9861 for (int i = 0; i < states->mask_len * 8; i++)
9862 {
9863 if (XIMaskIsSet (states->mask, i))
9864 {
9865 block_input ();
9866
9867 struct xi_scroll_valuator_t *val;
9868 double delta =
9869 x_get_scroll_valuator_delta (dpyinfo, xev->deviceid,
9870 i, *values, &val);
9871
9872 if (delta != DBL_MAX)
9873 {
9874 /* TODO: Figure out how pixelwise scrolling should work.
9875 Until that happens, this will have to do. */
9876 delta *= 10;
9877
9878 f = mouse_or_wdesc_frame (dpyinfo, xev->event);
9879 found_valuator = true;
9880 if (signbit (delta) != signbit (val->emacs_value))
9881 val->emacs_value = DBL_MIN;
9882
9883 val->emacs_value += delta;
9884
9885 if (!f)
9886 {
9887 f = x_any_window_to_frame (dpyinfo, xev->event);
9888
9889 if (!f)
9890 {
9891 unblock_input ();
9892 goto XI_OTHER;
9893 }
9894 }
9895
9896 if ((val->horizontal
9897 && fabs (val->emacs_value) >= FRAME_COLUMN_WIDTH (f))
9898 || (!val->horizontal
9899 && fabs (val->emacs_value) >= FRAME_LINE_HEIGHT (f)))
9900 {
9901 Lisp_Object tab_bar_arg = Qnil;
9902 bool tab_bar_p = false;
9903 bool tool_bar_p = false;
9904 bool s = signbit (val->emacs_value);
9905
9906 bv.button = !val->horizontal ? (s ? 5 : 4) : (s ? 7 : 6);
9907 bv.type = ButtonPress;
9908
9909 bv.x = lrint (xev->event_x);
9910 bv.y = lrint (xev->event_y);
9911 bv.window = xev->event;
9912 bv.state = xev->mods.base
9913 | xev->mods.effective
9914 | xev->mods.latched
9915 | xev->mods.locked;
9916
9917 /* Is this in the tab-bar? */
9918 if (WINDOWP (f->tab_bar_window)
9919 && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)))
9920 {
9921 Lisp_Object window;
9922 int x = bv.x;
9923 int y = bv.y;
9924
9925 window = window_from_coordinates (f, x, y, 0, true, true);
9926 tab_bar_p = EQ (window, f->tab_bar_window);
9927
9928 if (tab_bar_p)
9929 {
9930 tab_bar_arg = handle_tab_bar_click
9931 (f, x, y, true, x_x_to_emacs_modifiers (dpyinfo, bv.state));
9932 tab_bar_arg = handle_tab_bar_click
9933 (f, x, y, false, x_x_to_emacs_modifiers (dpyinfo, bv.state));
9934 }
9935 }
9936
9937 if (!NILP (tab_bar_arg))
9938 inev.ie.arg = tab_bar_arg;
9939
9940 if (!tool_bar_p && !(NILP (tab_bar_arg) && tab_bar_p))
9941 {
9942 if (ignore_next_mouse_click_timeout)
9943 {
9944 if (xev->time > ignore_next_mouse_click_timeout)
9945 {
9946 /* XXX: Wouldn't it be better
9947 to just use wheel events
9948 instead of pretending to be
9949 X here? */
9950 x_construct_mouse_click (&inev.ie, &bv, f);
9951 if (!NILP (tab_bar_arg))
9952 inev.ie.arg = tab_bar_arg;
9953 kbd_buffer_store_event (&inev.ie);
9954 inev.ie.modifiers &= ~down_modifier;
9955 inev.ie.modifiers |= up_modifier;
9956 kbd_buffer_store_event (&inev.ie);
9957 }
9958 ignore_next_mouse_click_timeout = 0;
9959 }
9960 else
9961 {
9962 x_construct_mouse_click (&inev.ie, &bv, f);
9963 kbd_buffer_store_event (&inev.ie);
9964 inev.ie.modifiers &= ~down_modifier;
9965 inev.ie.modifiers |= up_modifier;
9966 kbd_buffer_store_event (&inev.ie);
9967 }
9968 }
9969
9970 val->emacs_value = DBL_MIN;
9971 }
9972 }
9973 unblock_input ();
9974 values++;
9975 }
9976
9977 inev.ie.kind = NO_EVENT;
9978 }
9979
9980 if (found_valuator)
9981 goto XI_OTHER;
9982
9983 ev.x = lrint (xev->event_x);
9984 ev.y = lrint (xev->event_y);
9985 ev.window = xev->event;
9986
9987 previous_help_echo_string = help_echo_string;
9988 help_echo_string = Qnil;
9989
9990 if (hlinfo->mouse_face_hidden)
9991 {
9992 hlinfo->mouse_face_hidden = false;
9993 clear_mouse_face (hlinfo);
9994 }
9995
9996 f = mouse_or_wdesc_frame (dpyinfo, xev->event);
9997
9998#ifdef USE_GTK
9999 if (f && xg_event_is_for_scrollbar (f, event))
10000 f = 0;
10001#endif
10002 if (f)
10003 {
10004 /* Maybe generate a SELECT_WINDOW_EVENT for
10005 `mouse-autoselect-window' but don't let popup menus
10006 interfere with this (Bug#1261). */
10007 if (!NILP (Vmouse_autoselect_window)
10008 && !popup_activated ()
10009 /* Don't switch if we're currently in the minibuffer.
10010 This tries to work around problems where the
10011 minibuffer gets unselected unexpectedly, and where
10012 you then have to move your mouse all the way down to
10013 the minibuffer to select it. */
10014 && !MINI_WINDOW_P (XWINDOW (selected_window))
10015 /* With `focus-follows-mouse' non-nil create an event
10016 also when the target window is on another frame. */
10017 && (f == XFRAME (selected_frame)
10018 || !NILP (focus_follows_mouse)))
10019 {
10020 static Lisp_Object last_mouse_window;
10021 Lisp_Object window = window_from_coordinates (f, ev.x, ev.y, 0, false, false);
10022
10023 /* A window will be autoselected only when it is not
10024 selected now and the last mouse movement event was
10025 not in it. The remainder of the code is a bit vague
10026 wrt what a "window" is. For immediate autoselection,
10027 the window is usually the entire window but for GTK
10028 where the scroll bars don't count. For delayed
10029 autoselection the window is usually the window's text
10030 area including the margins. */
10031 if (WINDOWP (window)
10032 && !EQ (window, last_mouse_window)
10033 && !EQ (window, selected_window))
10034 {
10035 inev.ie.kind = SELECT_WINDOW_EVENT;
10036 inev.ie.frame_or_window = window;
10037 }
10038
10039 /* Remember the last window where we saw the mouse. */
10040 last_mouse_window = window;
10041 }
10042
10043 if (!x_note_mouse_movement (f, &ev))
10044 help_echo_string = previous_help_echo_string;
10045 }
10046 else
10047 {
10048#ifndef USE_TOOLKIT_SCROLL_BARS
10049 struct scroll_bar *bar
10050 = x_window_to_scroll_bar (xi_event->display, xev->event, 2);
10051
10052 if (bar)
10053 x_scroll_bar_note_movement (bar, &ev);
10054#endif /* USE_TOOLKIT_SCROLL_BARS */
10055
10056 /* If we move outside the frame, then we're
10057 certainly no longer on any text in the frame. */
10058 clear_mouse_face (hlinfo);
10059 }
10060
10061 /* If the contents of the global variable help_echo_string
10062 has changed, generate a HELP_EVENT. */
10063 if (!NILP (help_echo_string)
10064 || !NILP (previous_help_echo_string))
10065 do_help = 1;
10066 goto XI_OTHER;
10067 case XI_ButtonRelease:
10068 case XI_ButtonPress:
10069 {
10070 /* If we decide we want to generate an event to be seen
10071 by the rest of Emacs, we put it here. */
10072 Lisp_Object tab_bar_arg = Qnil;
10073 bool tab_bar_p = false;
10074 bool tool_bar_p = false;
10075
10076 /* Ignore emulated scroll events when XI2 native
10077 scroll events are present. */
10078 if (dpyinfo->xi2_version >= 1 && xev->detail >= 4
10079 && xev->detail <= 8)
10080 goto XI_OTHER;
10081
10082 bv.button = xev->detail;
10083 bv.type = xev->evtype == XI_ButtonPress ? ButtonPress : ButtonRelease;
10084 bv.x = lrint (xev->event_x);
10085 bv.y = lrint (xev->event_y);
10086 bv.window = xev->event;
10087 bv.state = xev->mods.base
10088 | xev->mods.effective
10089 | xev->mods.latched
10090 | xev->mods.locked;
10091
10092 memset (&compose_status, 0, sizeof (compose_status));
10093 dpyinfo->last_mouse_glyph_frame = NULL;
10094 x_display_set_last_user_time (dpyinfo, xev->time);
10095
10096 f = mouse_or_wdesc_frame (dpyinfo, xev->event);
10097
10098 if (f && xev->evtype == XI_ButtonPress
10099 && !popup_activated ()
10100 && !x_window_to_scroll_bar (xev->display, xev->event, 2)
10101 && !FRAME_NO_ACCEPT_FOCUS (f))
10102 {
10103 /* When clicking into a child frame or when clicking
10104 into a parent frame with the child frame selected and
10105 `no-accept-focus' is not set, select the clicked
10106 frame. */
10107 struct frame *hf = dpyinfo->highlight_frame;
10108
10109 if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf)))
10110 {
10111 block_input ();
10112 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
10113 RevertToParent, CurrentTime);
10114 if (FRAME_PARENT_FRAME (f))
10115 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
10116 unblock_input ();
10117 }
10118 }
10119
10120#ifdef USE_GTK
10121 if (f && xg_event_is_for_scrollbar (f, event))
10122 f = 0;
10123#endif
10124
10125 if (f)
10126 {
10127 /* Is this in the tab-bar? */
10128 if (WINDOWP (f->tab_bar_window)
10129 && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)))
10130 {
10131 Lisp_Object window;
10132 int x = bv.x;
10133 int y = bv.y;
10134
10135 window = window_from_coordinates (f, x, y, 0, true, true);
10136 tab_bar_p = EQ (window, f->tab_bar_window);
10137
10138 if (tab_bar_p)
10139 tab_bar_arg = handle_tab_bar_click
10140 (f, x, y, xev->evtype == XI_ButtonPress,
10141 x_x_to_emacs_modifiers (dpyinfo, bv.state));
10142 }
10143
10144#if ! defined (USE_GTK)
10145 /* Is this in the tool-bar? */
10146 if (WINDOWP (f->tool_bar_window)
10147 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
10148 {
10149 Lisp_Object window;
10150 int x = bv.x;
10151 int y = bv.y;
10152
10153 window = window_from_coordinates (f, x, y, 0, true, true);
10154 tool_bar_p = EQ (window, f->tool_bar_window);
10155
10156 if (tool_bar_p && xev->detail < 4)
10157 handle_tool_bar_click
10158 (f, x, y, xev->evtype == XI_ButtonPress,
10159 x_x_to_emacs_modifiers (dpyinfo, bv.state));
10160 }
10161#endif /* !USE_GTK */
10162
10163 if (!(tab_bar_p && NILP (tab_bar_arg)) && !tool_bar_p)
10164#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
10165 if (! popup_activated ())
10166#endif
10167 {
10168 if (ignore_next_mouse_click_timeout)
10169 {
10170 if (xev->evtype == XI_ButtonPress
10171 && xev->time > ignore_next_mouse_click_timeout)
10172 {
10173 ignore_next_mouse_click_timeout = 0;
10174 x_construct_mouse_click (&inev.ie, &bv, f);
10175 }
10176 if (xev->evtype == XI_ButtonRelease)
10177 ignore_next_mouse_click_timeout = 0;
10178 }
10179 else
10180 x_construct_mouse_click (&inev.ie, &bv, f);
10181
10182 if (!NILP (tab_bar_arg))
10183 inev.ie.arg = tab_bar_arg;
10184 }
10185 if (FRAME_X_EMBEDDED_P (f))
10186 xembed_send_message (f, xev->time,
10187 XEMBED_REQUEST_FOCUS, 0, 0, 0);
10188 }
10189
10190 if (xev->evtype == XI_ButtonPress)
10191 {
10192 dpyinfo->grabbed |= (1 << xev->detail);
10193 dpyinfo->last_mouse_frame = f;
10194 if (f && !tab_bar_p)
10195 f->last_tab_bar_item = -1;
10196#if ! defined (USE_GTK)
10197 if (f && !tool_bar_p)
10198 f->last_tool_bar_item = -1;
10199#endif /* not USE_GTK */
10200
10201 }
10202 else
10203 dpyinfo->grabbed &= ~(1 << xev->detail);
10204
10205 if (f)
10206 f->mouse_moved = false;
10207
10208#if defined (USE_GTK)
10209 /* No Xt toolkit currently available has support for XI2.
10210 So the code here assumes use of GTK. */
10211 f = x_menubar_window_to_frame (dpyinfo, event);
10212 if (f /* Gtk+ menus only react to the first three buttons. */
10213 && xev->detail < 3)
10214 {
10215 /* What is done with Core Input ButtonPressed is not
10216 possible here, because GenericEvents cannot be saved. */
10217 bool was_waiting_for_input = waiting_for_input;
10218 /* This hack was adopted from the NS port. Whether
10219 or not it is actually safe is a different story
10220 altogether. */
10221 if (waiting_for_input)
10222 waiting_for_input = 0;
10223 set_frame_menubar (f, true);
10224 waiting_for_input = was_waiting_for_input;
10225 }
10226#endif
10227 goto XI_OTHER;
10228 }
10229 case XI_KeyPress:
10230 {
10231 int state = xev->mods.base
10232 | xev->mods.effective
10233 | xev->mods.latched
10234 | xev->mods.locked;
10235 Lisp_Object c;
10236#ifdef HAVE_XKB
10237 unsigned int mods_rtrn;
10238#endif
10239 int keycode = xev->detail;
10240 KeySym keysym;
10241 char copy_buffer[81];
10242 char *copy_bufptr = copy_buffer;
10243 unsigned char *copy_ubufptr;
10244#ifdef HAVE_XKB
10245 int copy_bufsiz = sizeof (copy_buffer);
10246#endif
10247 ptrdiff_t i;
10248 int nchars, len;
10249
10250#ifdef HAVE_XKB
10251 if (dpyinfo->xkb_desc)
10252 {
10253 if (!XkbTranslateKeyCode (dpyinfo->xkb_desc, keycode,
10254 state, &mods_rtrn, &keysym))
10255 goto XI_OTHER;
10256 }
10257 else
10258 {
10259#endif
10260 int keysyms_per_keycode_return;
10261 KeySym *ksms = XGetKeyboardMapping (dpyinfo->display, keycode, 1,
10262 &keysyms_per_keycode_return);
10263 if (!(keysym = ksms[0]))
10264 {
10265 XFree (ksms);
10266 goto XI_OTHER;
10267 }
10268 XFree (ksms);
10269#ifdef HAVE_XKB
10270 }
10271#endif
10272
10273 if (keysym == NoSymbol)
10274 goto XI_OTHER;
10275
10276 x_display_set_last_user_time (dpyinfo, xev->time);
10277 ignore_next_mouse_click_timeout = 0;
10278
10279#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
10280 /* Dispatch XI_KeyPress events when in menu. */
10281 if (popup_activated ())
10282 goto XI_OTHER;
10283#endif
10284
10285 f = x_any_window_to_frame (dpyinfo, xev->event);
10286
10287 /* If mouse-highlight is an integer, input clears out
10288 mouse highlighting. */
10289 if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight)
10290 && (f == 0
10291#if ! defined (USE_GTK)
10292 || !EQ (f->tool_bar_window, hlinfo->mouse_face_window)
10293#endif
10294 || !EQ (f->tab_bar_window, hlinfo->mouse_face_window))
10295 )
10296 {
10297 clear_mouse_face (hlinfo);
10298 hlinfo->mouse_face_hidden = true;
10299 }
10300
10301 if (f != 0)
10302 {
10303#ifdef USE_GTK
10304 /* Don't pass keys to GTK. A Tab will shift focus to the
10305 tool bar in GTK 2.4. Keys will still go to menus and
10306 dialogs because in that case popup_activated is nonzero
10307 (see above). */
10308 *finish = X_EVENT_DROP;
10309#endif
10310 /* If not using XIM/XIC, and a compose sequence is in progress,
10311 we break here. Otherwise, chars_matched is always 0. */
10312 if (compose_status.chars_matched > 0 && nbytes == 0)
10313 goto XI_OTHER;
10314
10315 memset (&compose_status, 0, sizeof (compose_status));
10316
10317 XSETFRAME (inev.ie.frame_or_window, f);
10318 inev.ie.modifiers
10319 = x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), state);
10320 inev.ie.timestamp = xev->time;
10321
10322 /* First deal with keysyms which have defined
10323 translations to characters. */
10324 if (keysym >= 32 && keysym < 128)
10325 /* Avoid explicitly decoding each ASCII character. */
10326 {
10327 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
10328 inev.ie.code = keysym;
10329
10330 goto xi_done_keysym;
10331 }
10332
10333 /* Keysyms directly mapped to Unicode characters. */
10334 if (keysym >= 0x01000000 && keysym <= 0x0110FFFF)
10335 {
10336 if (keysym < 0x01000080)
10337 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
10338 else
10339 inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
10340 inev.ie.code = keysym & 0xFFFFFF;
10341 goto xi_done_keysym;
10342 }
10343
10344 /* Now non-ASCII. */
10345 if (HASH_TABLE_P (Vx_keysym_table)
10346 && (c = Fgethash (make_fixnum (keysym),
10347 Vx_keysym_table,
10348 Qnil),
10349 FIXNATP (c)))
10350 {
10351 inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c))
10352 ? ASCII_KEYSTROKE_EVENT
10353 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
10354 inev.ie.code = XFIXNAT (c);
10355 goto xi_done_keysym;
10356 }
10357
10358 /* Random non-modifier sorts of keysyms. */
10359 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
10360 || keysym == XK_Delete
10361#ifdef XK_ISO_Left_Tab
10362 || (keysym >= XK_ISO_Left_Tab
10363 && keysym <= XK_ISO_Enter)
10364#endif
10365 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
10366 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
10367#ifdef HPUX
10368 /* This recognizes the "extended function
10369 keys". It seems there's no cleaner way.
10370 Test IsModifierKey to avoid handling
10371 mode_switch incorrectly. */
10372 || (XK_Select <= keysym && keysym < XK_KP_Space)
10373#endif
10374#ifdef XK_dead_circumflex
10375 || keysym == XK_dead_circumflex
10376#endif
10377#ifdef XK_dead_grave
10378 || keysym == XK_dead_grave
10379#endif
10380#ifdef XK_dead_tilde
10381 || keysym == XK_dead_tilde
10382#endif
10383#ifdef XK_dead_diaeresis
10384 || keysym == XK_dead_diaeresis
10385#endif
10386#ifdef XK_dead_macron
10387 || keysym == XK_dead_macron
10388#endif
10389#ifdef XK_dead_degree
10390 || keysym == XK_dead_degree
10391#endif
10392#ifdef XK_dead_acute
10393 || keysym == XK_dead_acute
10394#endif
10395#ifdef XK_dead_cedilla
10396 || keysym == XK_dead_cedilla
10397#endif
10398#ifdef XK_dead_breve
10399 || keysym == XK_dead_breve
10400#endif
10401#ifdef XK_dead_ogonek
10402 || keysym == XK_dead_ogonek
10403#endif
10404#ifdef XK_dead_caron
10405 || keysym == XK_dead_caron
10406#endif
10407#ifdef XK_dead_doubleacute
10408 || keysym == XK_dead_doubleacute
10409#endif
10410#ifdef XK_dead_abovedot
10411 || keysym == XK_dead_abovedot
10412#endif
10413 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
10414 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
10415 /* Any "vendor-specific" key is ok. */
10416 || (keysym & (1 << 28))
10417 || (keysym != NoSymbol && nbytes == 0))
10418 && ! (IsModifierKey (keysym)
10419 /* The symbols from XK_ISO_Lock
10420 to XK_ISO_Last_Group_Lock
10421 don't have real modifiers but
10422 should be treated similarly to
10423 Mode_switch by Emacs. */
10424#if defined XK_ISO_Lock && defined XK_ISO_Last_Group_Lock
10425 || (XK_ISO_Lock <= keysym
10426 && keysym <= XK_ISO_Last_Group_Lock)
10427#endif
10428 ))
10429 {
10430 STORE_KEYSYM_FOR_DEBUG (keysym);
10431 /* make_lispy_event will convert this to a symbolic
10432 key. */
10433 inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT;
10434 inev.ie.code = keysym;
10435 goto xi_done_keysym;
10436 }
10437
10438#ifdef HAVE_XKB
10439 int overflow = 0;
10440 KeySym sym = keysym;
10441
10442 if (dpyinfo->xkb_desc)
10443 {
10444 if (!(nbytes = XkbTranslateKeySym (dpyinfo->display, &sym,
10445 state & ~mods_rtrn, copy_bufptr,
10446 copy_bufsiz, &overflow)))
10447 goto XI_OTHER;
10448 }
10449 else
10450#else
10451 {
10452 block_input ();
10453 char *str = XKeysymToString (keysym);
10454 if (!str)
10455 {
10456 unblock_input ();
10457 goto XI_OTHER;
10458 }
10459 nbytes = strlen (str) + 1;
10460 copy_bufptr = alloca (nbytes);
10461 strcpy (copy_bufptr, str);
10462 unblock_input ();
10463 }
10464#endif
10465#ifdef HAVE_XKB
10466 if (overflow)
10467 {
10468 overflow = 0;
10469 copy_bufptr = alloca (copy_bufsiz + overflow);
10470 keysym = sym;
10471 if (!(nbytes = XkbTranslateKeySym (dpyinfo->display, &sym,
10472 state & ~mods_rtrn, copy_bufptr,
10473 copy_bufsiz + overflow, &overflow)))
10474 goto XI_OTHER;
10475
10476 if (overflow)
10477 goto XI_OTHER;
10478 }
10479#endif
10480
10481 for (i = 0, nchars = 0; i < nbytes; i++)
10482 {
10483 if (ASCII_CHAR_P (copy_bufptr[i]))
10484 nchars++;
10485 STORE_KEYSYM_FOR_DEBUG (copy_bufptr[i]);
10486 }
10487
10488 if (nchars < nbytes)
10489 {
10490 /* Decode the input data. */
10491
10492 setup_coding_system (Vlocale_coding_system, &coding);
10493 coding.src_multibyte = false;
10494 coding.dst_multibyte = true;
10495 /* The input is converted to events, thus we can't
10496 handle composition. Anyway, there's no XIM that
10497 gives us composition information. */
10498 coding.common_flags &= ~CODING_ANNOTATION_MASK;
10499
10500 SAFE_NALLOCA (coding.destination, MAX_MULTIBYTE_LENGTH,
10501 nbytes);
10502 coding.dst_bytes = MAX_MULTIBYTE_LENGTH * nbytes;
10503 coding.mode |= CODING_MODE_LAST_BLOCK;
10504 decode_coding_c_string (&coding, (unsigned char *) copy_bufptr, nbytes, Qnil);
10505 nbytes = coding.produced;
10506 nchars = coding.produced_char;
10507 copy_bufptr = (char *) coding.destination;
10508 }
10509
10510 copy_ubufptr = (unsigned char *) copy_bufptr;
10511
10512 /* Convert the input data to a sequence of
10513 character events. */
10514 for (i = 0; i < nbytes; i += len)
10515 {
10516 int ch;
10517 if (nchars == nbytes)
10518 ch = copy_ubufptr[i], len = 1;
10519 else
10520 ch = string_char_and_length (copy_ubufptr + i, &len);
10521 inev.ie.kind = (SINGLE_BYTE_CHAR_P (ch)
10522 ? ASCII_KEYSTROKE_EVENT
10523 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
10524 inev.ie.code = ch;
10525 kbd_buffer_store_buffered_event (&inev, hold_quit);
10526 }
10527
10528 inev.ie.kind = NO_EVENT;
10529 goto xi_done_keysym;
10530 }
10531 goto XI_OTHER;
10532 }
10533 case XI_KeyRelease:
10534 x_display_set_last_user_time (dpyinfo, xev->time);
10535 goto XI_OTHER;
10536 case XI_PropertyEvent:
10537 case XI_HierarchyChanged:
10538 case XI_DeviceChanged:
10539 x_init_master_valuators (dpyinfo);
10540 goto XI_OTHER;
10541 default:
10542 goto XI_OTHER;
10543 }
10544 xi_done_keysym:
10545 if (must_free_data)
10546 XFreeEventData (dpyinfo->display, &event->xcookie);
10547 goto done_keysym;
10548 XI_OTHER:
10549 if (must_free_data)
10550 XFreeEventData (dpyinfo->display, &event->xcookie);
10551 goto OTHER;
10552 }
10553#endif
9521 10554
9522 default: 10555 default:
9523 OTHER: 10556 OTHER:
@@ -13192,6 +14225,40 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
13192 dpyinfo->supports_xdbe = true; 14225 dpyinfo->supports_xdbe = true;
13193#endif 14226#endif
13194 14227
14228#ifdef HAVE_XINPUT2
14229 dpyinfo->supports_xi2 = false;
14230 int rc;
14231 int major = 2;
14232#ifdef XI_BarrierHit /* XInput 2.3 */
14233 int minor = 3;
14234#elif defined XI_TouchBegin /* XInput 2.2 */
14235 int minor = 2;
14236#elif defined XIScrollClass /* XInput 1.1 */
14237 int minor = 1;
14238#else /* Some old version of XI2 we're not interested in. */
14239 int minor = 0;
14240#endif
14241 int fer, fee;
14242
14243 if (XQueryExtension (dpyinfo->display, "XInputExtension",
14244 &dpyinfo->xi2_opcode, &fer, &fee))
14245 {
14246 rc = XIQueryVersion (dpyinfo->display, &major, &minor);
14247 if (rc == Success)
14248 {
14249 dpyinfo->supports_xi2 = true;
14250 x_init_master_valuators (dpyinfo);
14251 }
14252 }
14253 dpyinfo->xi2_version = minor;
14254#endif
14255
14256#ifdef HAVE_XKB
14257 dpyinfo->xkb_desc = XkbGetMap (dpyinfo->display,
14258 XkbAllComponentsMask,
14259 XkbUseCoreKbd);
14260#endif
14261
13195#if defined USE_CAIRO || defined HAVE_XFT 14262#if defined USE_CAIRO || defined HAVE_XFT
13196 { 14263 {
13197 /* If we are using Xft, the following precautions should be made: 14264 /* If we are using Xft, the following precautions should be made:
@@ -13624,6 +14691,14 @@ x_delete_terminal (struct terminal *terminal)
13624 XrmDestroyDatabase (dpyinfo->rdb); 14691 XrmDestroyDatabase (dpyinfo->rdb);
13625#endif 14692#endif
13626 14693
14694#ifdef HAVE_XKB
14695 if (dpyinfo->xkb_desc)
14696 XkbFreeKeyboard (dpyinfo->xkb_desc, XkbAllComponentsMask, True);
14697#endif
14698#ifdef HAVE_XINPUT2
14699 if (dpyinfo->supports_xi2)
14700 x_free_xi_devices (dpyinfo);
14701#endif
13627#ifdef USE_GTK 14702#ifdef USE_GTK
13628 xg_display_close (dpyinfo->display); 14703 xg_display_close (dpyinfo->display);
13629#else 14704#else
@@ -13783,9 +14858,12 @@ x_initialize (void)
13783void 14858void
13784init_xterm (void) 14859init_xterm (void)
13785{ 14860{
13786 /* Emacs can handle only core input events, so make sure 14861#ifndef HAVE_XINPUT2
13787 Gtk doesn't use Xinput or Xinput2 extensions. */ 14862 /* Emacs can handle only core input events when built without XI2
14863 support, so make sure Gtk doesn't use Xinput or Xinput2
14864 extensions. */
13788 xputenv ("GDK_CORE_DEVICE_EVENTS=1"); 14865 xputenv ("GDK_CORE_DEVICE_EVENTS=1");
14866#endif
13789} 14867}
13790#endif 14868#endif
13791 14869
diff --git a/src/xterm.h b/src/xterm.h
index 9d9534dd629..25eddf8bf28 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,26 @@ 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 struct xi_scroll_valuator_t *valuators;
187};
188#endif
189
166Status x_parse_color (struct frame *f, const char *color_name, 190Status x_parse_color (struct frame *f, const char *color_name,
167 XColor *color); 191 XColor *color);
168 192
@@ -474,6 +498,19 @@ struct x_display_info
474#ifdef HAVE_XDBE 498#ifdef HAVE_XDBE
475 bool supports_xdbe; 499 bool supports_xdbe;
476#endif 500#endif
501
502#ifdef HAVE_XINPUT2
503 bool supports_xi2;
504 int xi2_version;
505 int xi2_opcode;
506
507 int num_devices;
508 struct xi_device_t *devices;
509#endif
510
511#ifdef HAVE_XKB
512 XkbDescPtr xkb_desc;
513#endif
477}; 514};
478 515
479#ifdef HAVE_X_I18N 516#ifdef HAVE_X_I18N
@@ -481,6 +518,11 @@ struct x_display_info
481extern bool use_xim; 518extern bool use_xim;
482#endif 519#endif
483 520
521#ifdef HAVE_XINPUT2
522/* Defined in xmenu.c. */
523extern int popup_activated_flag;
524#endif
525
484/* This is a chain of structures for all the X displays currently in use. */ 526/* This is a chain of structures for all the X displays currently in use. */
485extern struct x_display_info *x_display_list; 527extern struct x_display_info *x_display_list;
486 528