]> git.eshelyaron.com Git - emacs.git/commitdiff
Expose the name of an event's input device to Lisp
authorPo Lu <luangruo@yahoo.com>
Thu, 7 Apr 2022 13:16:11 +0000 (21:16 +0800)
committerPo Lu <luangruo@yahoo.com>
Thu, 7 Apr 2022 13:16:11 +0000 (21:16 +0800)
This name can be used to identify the device for special
treatment, i.e. only interpolating scrolls coming from mice and
not touchpads inside pixel-scroll-precision-mode.

* doc/lispref/commands.texi (Command Loop Info): Document new
variable `last-event-device'.
* etc/NEWS: Announce new variable `last-event-device'.
* src/frame.h (struct frame): New field `last_mouse_device'.
* src/keyboard.c (read_char): Clear last-event-device.
(kbd_buffer_get_event): Set last-event-device to the event's
recorded device.
(init_keyboard): Clear last-event-device.
(syms_of_keyboard): New defvar `last-event-device'.
* src/termhooks.h (struct input_event): New field `device'.
(EVENT_INIT): Set it to the special value `Qt' by default.
* src/xterm.c (x_init_master_valuators): Record the device's
name.
(x_dnd_begin_drag_and_drop): Only preserve last event device if
the mouse ended up in the source frame.
(x_note_mouse_movement): New argument `source'.
(handle_one_xevent): Set input event sources whenever
appropriate.
(mark_xterm): Mark device names.

* src/xterm.h (struct xi_device_t): New field `name'.

doc/lispref/commands.texi
etc/NEWS
src/frame.h
src/keyboard.c
src/termhooks.h
src/xterm.c
src/xterm.h

index a4ae68af5b2c539db72c02e986ddb36760920391..74bf0f48692b8b9746187661be6fb10ef1dda757 100644 (file)
@@ -1127,6 +1127,20 @@ frame, the value is the frame to which the event was redirected.
 If the last event came from a keyboard macro, the value is @code{macro}.
 @end defvar
 
+@defvar last-event-device
+This variable records the name of the input device from which the last
+input event read was generated.  It is @code{nil} if no such device
+exists, i.e., the last input event was read from
+@code{unread-command-events}, or it came from a keyboard macro.
+
+When the X Input Extension is being used on X Windows, the device name
+is a string that is unique to each physical keyboard, pointing device
+and touchscreen attached to the X server.  Otherwise, it is either the
+string @samp{"Virtual core pointer"} or @samp{"Virtual core
+keyboard"}, depending on whether the event was generated by a pointing
+device (such as a mouse) or a keyboard.
+@end defvar
+
 @node Adjusting Point
 @section Adjusting Point After Commands
 @cindex adjusting point
index 564bd16022df11f127a1ac3799fb9276513b8536..85ed817e05e88f9fb1c8a4ca12a72180f57f788a 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1353,6 +1353,11 @@ functions.
 \f
 * Lisp Changes in Emacs 29.1
 
++++
+** New variable 'last-event-device'.
+On X Windows, this specifies the input extension device from which the
+last input event originated.
+
 +++
 ** 'track-mouse' can be a new value 'drag-source'.
 This means the same as 'dropping', but modifies the mouse position
index 61df57e966a39ce88bf3f253f521e926beaa263a..4942e640d27eb1bfaf245d4ac8424087ec836393 100644 (file)
@@ -102,6 +102,10 @@ struct frame
   Lisp_Object parent_frame;
 #endif /* HAVE_WINDOW_SYSTEM */
 
+  /* Last device to move over this frame.  Any value that isn't a
+     string means the "Virtual core pointer".  */
+  Lisp_Object last_mouse_device;
+
   /* The frame which should receive keystrokes that occur in this
      frame, or nil if they should go to the frame itself.  This is
      usually nil, but if the frame is minibufferless, we can use this
index d99fe4be09282490909102694a4d4ce3f2303f87..8142ffec2df7853c9f8be6811c0d5cdaac429ad1 100644 (file)
@@ -336,6 +336,11 @@ static struct timespec timer_idleness_start_time;
 
 static struct timespec timer_last_idleness_start_time;
 
+/* Predefined strings for core device names.  */
+
+static Lisp_Object virtual_core_pointer_name;
+static Lisp_Object virtual_core_keyboard_name;
+
 \f
 /* Global variable declarations.  */
 
@@ -2520,6 +2525,8 @@ read_char (int commandflag, Lisp_Object map,
       goto reread_for_input_method;
     }
 
+  Vlast_event_device = Qnil;
+
   if (!NILP (Vexecuting_kbd_macro))
     {
       /* We set this to Qmacro; since that's not a frame, nobody will
@@ -4118,6 +4125,15 @@ kbd_buffer_get_event (KBOARD **kbp,
            obj = make_lispy_switch_frame (frame);
          internal_last_event_frame = frame;
 
+         if (EQ (event->ie.device, Qt))
+           Vlast_event_device = ((event->ie.kind == ASCII_KEYSTROKE_EVENT
+                                  || event->ie.kind == MULTIBYTE_CHAR_KEYSTROKE_EVENT
+                                  || event->ie.kind == NON_ASCII_KEYSTROKE_EVENT)
+                                 ? virtual_core_keyboard_name
+                                 : virtual_core_pointer_name);
+         else
+           Vlast_event_device = event->ie.device;
+
          /* If we didn't decide to make a switch-frame event, go ahead
             and build a real event from the queue entry.  */
          if (NILP (obj))
@@ -4173,6 +4189,10 @@ kbd_buffer_get_event (KBOARD **kbp,
                      XSETCAR (Fnthcdr (make_fixnum (3),
                                        maybe_event->ie.arg),
                               make_float (fmod (pinch_angle, 360.0)));
+
+                     if (!EQ (maybe_event->ie.device, Qt))
+                       Vlast_event_device = maybe_event->ie.device;
+
                      maybe_event = next_kbd_event (event);
                    }
                }
@@ -4296,6 +4316,11 @@ kbd_buffer_get_event (KBOARD **kbp,
         return a mouse-motion event.  */
       if (!NILP (x) && NILP (obj))
        obj = make_lispy_movement (f, bar_window, part, x, y, t);
+
+      if (!NILP (obj))
+       Vlast_event_device = (STRINGP (f->last_mouse_device)
+                             ? f->last_mouse_device
+                             : virtual_core_pointer_name);
     }
   else
     /* We were promised by the above while loop that there was
@@ -11805,6 +11830,10 @@ init_keyboard (void)
   interrupt_input_blocked = 0;
   pending_signals = false;
 
+  virtual_core_pointer_name = build_string ("Virtual core pointer");
+  virtual_core_keyboard_name = build_string ("Virtual core keyboard");
+  Vlast_event_device = Qnil;
+
   /* This means that command_loop_1 won't try to select anything the first
      time through.  */
   internal_last_event_frame = Qnil;
@@ -12225,6 +12254,12 @@ syms_of_keyboard (void)
   staticpro (&poll_timer_time);
 #endif
 
+  virtual_core_pointer_name = Qnil;
+  staticpro (&virtual_core_pointer_name);
+
+  virtual_core_keyboard_name = Qnil;
+  staticpro (&virtual_core_keyboard_name);
+
   defsubr (&Scurrent_idle_time);
   defsubr (&Sevent_symbol_parse_modifiers);
   defsubr (&Sevent_convert_list);
@@ -12423,6 +12458,17 @@ This does not include events generated by keyboard macros.  */);
 If the last event came from a keyboard macro, this is set to `macro'.  */);
   Vlast_event_frame = Qnil;
 
+  DEFVAR_LISP ("last-event-device", Vlast_event_device,
+              doc: /* The name of the input device of the most recently read event.
+When the input extension is being used on X, this is the name of the X
+Input Extension device from which the last event was generated as a
+string.  Otherwise, this is "Virtual core keyboard" for keyboard input
+events, and "Virtual core pointer" for other events.
+
+It is nil if the last event did not come from an input device (i.e. it
+came from `unread-command-events' instead).  */);
+  Vlast_event_device = Qnil;
+
   /* This variable is set up in sysdep.c.  */
   DEFVAR_LISP ("tty-erase-char", Vtty_erase_char,
               doc: /* The ERASE character as set by the user with stty.  */);
index 0f02b56e9ee6179da379a10b16b556482535381d..8c193914ba838b1fc409fcd79e779f401de35242 100644 (file)
@@ -392,9 +392,17 @@ struct input_event
      when building events.  Unfortunately some events have to pass much
      more data than it's reasonable to pack directly into this structure.  */
   Lisp_Object arg;
+
+  /* The name of the device from which this event originated.
+
+     It can either be a string, or Qt, which means to use the name
+     "Virtual core pointer" for all events other than keystroke
+     events, and "Virtual core keyboard" for those.  */
+  Lisp_Object device;
 };
 
-#define EVENT_INIT(event) memset (&(event), 0, sizeof (struct input_event))
+#define EVENT_INIT(event) (memset (&(event), 0, sizeof (struct input_event)), \
+                          (event).device = Qt)
 
 /* Bits in the modifiers member of the input_event structure.
    Note that reorder_modifiers assumes that the bits are in canonical
index 57a64cb5d12b6c2f59b016eea70eb74920a4c9e0..d4a5e0ab3dc71bdd13981c50fb64df9de37ed90a 100644 (file)
@@ -3922,6 +3922,7 @@ x_init_master_valuators (struct x_display_info *dpyinfo)
 #ifdef HAVE_XINPUT2_2
          xi_device->direct_p = false;
 #endif
+         xi_device->name = build_string (device->name);
 
          for (int c = 0; c < device->num_classes; ++c)
            {
@@ -9653,6 +9654,12 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
   if (x_dnd_return_frame == 3
       && FRAME_LIVE_P (x_dnd_return_frame_object))
     {
+      /* Deliberately preserve the last device if
+        x_dnd_return_frame_object is the drag source.  */
+
+      if (x_dnd_return_frame_object != x_dnd_frame)
+       x_dnd_return_frame_object->last_mouse_device = Qnil;
+
       x_dnd_return_frame_object->mouse_moved = true;
 
       XSETFRAME (action, x_dnd_return_frame_object);
@@ -10170,7 +10177,8 @@ x_construct_mouse_click (struct input_event *result,
    XI_Enter and XI_Leave labels inside `handle_one_xevent'.  */
 
 static bool
-x_note_mouse_movement (struct frame *frame, const XMotionEvent *event)
+x_note_mouse_movement (struct frame *frame, const XMotionEvent *event,
+                      Lisp_Object device)
 {
   XRectangle *r;
   struct x_display_info *dpyinfo;
@@ -10187,6 +10195,7 @@ x_note_mouse_movement (struct frame *frame, const XMotionEvent *event)
   if (event->window != FRAME_X_WINDOW (frame))
     {
       frame->mouse_moved = true;
+      frame->last_mouse_device = device;
       dpyinfo->last_mouse_scroll_bar = NULL;
       note_mouse_highlight (frame, -1, -1);
       dpyinfo->last_mouse_glyph_frame = NULL;
@@ -10201,6 +10210,7 @@ x_note_mouse_movement (struct frame *frame, const XMotionEvent *event)
       || event->y < r->y || event->y >= r->y + r->height)
     {
       frame->mouse_moved = true;
+      frame->last_mouse_device = device;
       dpyinfo->last_mouse_scroll_bar = NULL;
       note_mouse_highlight (frame, event->x, event->y);
       /* Remember which glyph we're now on.  */
@@ -14788,12 +14798,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       /* EnterNotify counts as mouse movement,
         so update things that depend on mouse position.  */
       if (f && !f->output_data.x->hourglass_p)
-       x_note_mouse_movement (f, &event->xmotion);
+       x_note_mouse_movement (f, &event->xmotion, Qnil);
 #ifdef USE_GTK
       /* We may get an EnterNotify on the buttons in the toolbar.  In that
          case we moved out of any highlighted area and need to note this.  */
       if (!f && dpyinfo->last_mouse_glyph_frame)
-        x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &event->xmotion);
+        x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &event->xmotion,
+                              Qnil);
 #endif
       goto OTHER;
 
@@ -14884,7 +14895,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #ifdef USE_GTK
       /* See comment in EnterNotify above */
       else if (dpyinfo->last_mouse_glyph_frame)
-        x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &event->xmotion);
+        x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame,
+                              &event->xmotion, Qnil);
 #endif
       goto OTHER;
 
@@ -15123,7 +15135,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                last_mouse_window = window;
              }
 
-            if (!x_note_mouse_movement (f, &xmotion))
+            if (!x_note_mouse_movement (f, &xmotion, Qnil))
              help_echo_string = previous_help_echo_string;
           }
         else
@@ -15903,8 +15915,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
            {
              XIEnterEvent *enter = (XIEnterEvent *) xi_event;
              XMotionEvent ev;
+             struct xi_device_t *source;
 
              any = x_top_window_to_frame (dpyinfo, enter->event);
+             source = xi_device_from_id (dpyinfo, enter->sourceid);
              ev.x = lrint (enter->event_x);
              ev.y = lrint (enter->event_y);
              ev.window = enter->event;
@@ -15972,12 +15986,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              /* EnterNotify counts as mouse movement,
                 so update things that depend on mouse position.  */
              if (f && !f->output_data.x->hourglass_p)
-               x_note_mouse_movement (f, &ev);
+               x_note_mouse_movement (f, &ev, source ? source->name : Qnil);
 #ifdef USE_GTK
              /* We may get an EnterNotify on the buttons in the toolbar.  In that
                 case we moved out of any highlighted area and need to note this.  */
              if (!f && dpyinfo->last_mouse_glyph_frame)
-               x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &ev);
+               x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &ev,
+                                      source ? source->name : Qnil);
 #endif
              goto XI_OTHER;
            }
@@ -15985,6 +16000,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
          case XI_Leave:
            {
              XILeaveEvent *leave = (XILeaveEvent *) xi_event;
+             struct xi_device_t *source;
 #ifdef USE_GTK
              XMotionEvent ev;
 
@@ -15995,6 +16011,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #endif
 
              any = x_top_window_to_frame (dpyinfo, leave->event);
+             source = xi_device_from_id (dpyinfo, leave->sourceid);
 
              /* This allows us to catch LeaveNotify events generated by
                 popup menu grabs.  FIXME: this is right when there is a
@@ -16098,14 +16115,15 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #ifdef USE_GTK
              /* See comment in EnterNotify above */
              else if (dpyinfo->last_mouse_glyph_frame)
-               x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &ev);
+               x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &ev,
+                                      source ? source->name : Qnil);
 #endif
              goto XI_OTHER;
            }
 
          case XI_Motion:
            {
-             struct xi_device_t *device;
+             struct xi_device_t *device, *source;
 #ifdef HAVE_XINPUT2_1
              XIValuatorState *states;
              double *values;
@@ -16117,6 +16135,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              xm_top_level_enter_message emsg;
              xm_drag_motion_message dmsg;
 
+             source = xi_device_from_id (dpyinfo, xev->sourceid);
 
 #ifdef HAVE_XINPUT2_1
              states = &xev->valuators;
@@ -16333,6 +16352,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                          XSETFRAME (inev.ie.frame_or_window, f);
                        }
 
+                     if (source && source->name)
+                       inev.ie.device = source->name;
+
                      goto XI_OTHER;
                    }
 #ifdef HAVE_XWIDGETS
@@ -16588,13 +16610,16 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                        {
                          inev.ie.kind = SELECT_WINDOW_EVENT;
                          inev.ie.frame_or_window = window;
+
+                         if (source)
+                           inev.ie.device = source->name;
                        }
 
                      /* Remember the last window where we saw the mouse.  */
                      last_mouse_window = window;
                    }
 
-                 if (!x_note_mouse_movement (f, &ev))
+                 if (!x_note_mouse_movement (f, &ev, source ? source->name : Qnil))
                    help_echo_string = previous_help_echo_string;
                }
              else
@@ -16628,7 +16653,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              Lisp_Object tab_bar_arg = Qnil;
              bool tab_bar_p = false;
              bool tool_bar_p = false;
-             struct xi_device_t *device;
+             struct xi_device_t *device, *source;
 #ifdef HAVE_XWIDGETS
              struct xwidget_view *xvw;
 #endif
@@ -16837,6 +16862,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              if (xev->evtype == XI_ButtonPress)
                x_display_set_last_user_time (dpyinfo, xev->time);
 
+             source = xi_device_from_id (dpyinfo, xev->sourceid);
+
 #ifdef HAVE_XWIDGETS
              xvw = xwidget_view_from_window (xev->event);
              if (xvw)
@@ -16849,6 +16876,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                    {
                      inev.ie.kind = SELECT_WINDOW_EVENT;
                      inev.ie.frame_or_window = xvw->w;
+
+                     if (source)
+                       inev.ie.device = source->name;
                    }
 
                  *finish = X_EVENT_DROP;
@@ -16918,6 +16948,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                          else
                            inev.ie.kind = HORIZ_WHEEL_EVENT;
 
+                         if (source)
+                           inev.ie.device = source->name;
+
                          inev.ie.timestamp = xev->time;
 
                          XSETINT (inev.ie.x, real_x);
@@ -16953,6 +16986,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                          else
                            inev.ie.kind = HORIZ_WHEEL_EVENT;
 
+                         if (source)
+                           inev.ie.device = source->name;
+
                          inev.ie.timestamp = xev->time;
 
                          XSETINT (inev.ie.x, lrint (xev->event_x));
@@ -17070,6 +17106,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                  device->grab &= ~(1 << xev->detail);
                }
 
+             if (source && inev.ie.kind != NO_EVENT)
+               inev.ie.device = source->name;
+
              if (f)
                f->mouse_moved = false;
 
@@ -17108,11 +17147,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              char *copy_bufptr = copy_buffer;
              int copy_bufsiz = sizeof (copy_buffer);
              ptrdiff_t i;
-             struct xi_device_t *device;
+             struct xi_device_t *device, *source;
 
              coding = Qlatin_1;
 
              device = xi_device_from_id (dpyinfo, xev->deviceid);
+             source = xi_device_from_id (dpyinfo, xev->sourceid);
 
              if (!device)
                goto XI_OTHER;
@@ -17350,6 +17390,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                      inev.ie.kind = ASCII_KEYSTROKE_EVENT;
                      inev.ie.code = keysym;
 
+                     if (source)
+                       inev.ie.device = source->name;
+
                      goto xi_done_keysym;
                    }
 
@@ -17360,6 +17403,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                        inev.ie.kind = ASCII_KEYSTROKE_EVENT;
                      else
                        inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
+
+                     if (source)
+                       inev.ie.device = source->name;
+
                      inev.ie.code = keysym & 0xFFFFFF;
                      goto xi_done_keysym;
                    }
@@ -17375,6 +17422,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                      ? ASCII_KEYSTROKE_EVENT
                                      : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
                      inev.ie.code = XFIXNAT (c);
+
+                     if (source)
+                       inev.ie.device = source->name;
+
                      goto xi_done_keysym;
                    }
 
@@ -17479,6 +17530,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                         key.  */
                      inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT;
                      inev.ie.code = keysym;
+
+                     if (source)
+                       inev.ie.device = source->name;
+
                      goto xi_done_keysym;
                    }
 
@@ -17494,6 +17549,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
                      Fput_text_property (make_fixnum (0), make_fixnum (nbytes),
                                          Qcoding, coding, inev.ie.arg);
+
+                     if (source)
+                       inev.ie.device = source->name;
                    }
                  goto xi_done_keysym;
                }
@@ -17688,12 +17746,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #ifdef HAVE_XINPUT2_2
          case XI_TouchBegin:
            {
-             struct xi_device_t *device;
+             struct xi_device_t *device, *source;
              bool menu_bar_p = false, tool_bar_p = false;
 #ifdef HAVE_GTK3
              GdkRectangle test_rect;
 #endif
              device = xi_device_from_id (dpyinfo, xev->deviceid);
+             source = xi_device_from_id (dpyinfo, xev->sourceid);
              x_display_set_last_user_time (dpyinfo, xev->time);
 
              if (!device)
@@ -17741,6 +17800,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                          XSETINT (inev.ie.x, lrint (xev->event_x));
                          XSETINT (inev.ie.y, lrint (xev->event_y));
                          XSETINT (inev.ie.arg, xev->detail);
+
+                         if (source)
+                           inev.ie.device = source->name;
                        }
                      x_uncatch_errors_after_check ();
                    }
@@ -17774,11 +17836,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
          case XI_TouchUpdate:
            {
-             struct xi_device_t *device;
+             struct xi_device_t *device, *source;
              struct xi_touch_point_t *touchpoint;
              Lisp_Object arg = Qnil;
 
              device = xi_device_from_id (dpyinfo, xev->deviceid);
+             source = xi_device_from_id (dpyinfo, xev->sourceid);
              x_display_set_last_user_time (dpyinfo, xev->time);
 
              if (!device)
@@ -17809,6 +17872,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                   arg);
                    }
 
+                 if (source)
+                   inev.ie.device = source->name;
+
                  inev.ie.arg = arg;
                }
 
@@ -17817,10 +17883,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
          case XI_TouchEnd:
            {
-             struct xi_device_t *device;
+             struct xi_device_t *device, *source;
              bool unlinked_p;
 
              device = xi_device_from_id (dpyinfo, xev->deviceid);
+             source = xi_device_from_id (dpyinfo, xev->sourceid);
              x_display_set_last_user_time (dpyinfo, xev->time);
 
              if (!device)
@@ -17836,10 +17903,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                    {
                      inev.ie.kind = TOUCHSCREEN_END_EVENT;
                      inev.ie.timestamp = xev->time;
+
                      XSETFRAME (inev.ie.frame_or_window, f);
                      XSETINT (inev.ie.x, lrint (xev->event_x));
                      XSETINT (inev.ie.y, lrint (xev->event_y));
                      XSETINT (inev.ie.arg, xev->detail);
+
+                     if (source)
+                       inev.ie.device = source->name;
                    }
                }
 
@@ -17852,10 +17923,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
          case XI_GesturePinchBegin:
          case XI_GesturePinchUpdate:
            {
-             x_display_set_last_user_time (dpyinfo, xi_event->time);
-
              XIGesturePinchEvent *pev = (XIGesturePinchEvent *) xi_event;
-             struct xi_device_t *device = xi_device_from_id (dpyinfo, pev->deviceid);
+             struct xi_device_t *device, *source;
+
+             device = xi_device_from_id (dpyinfo, pev->deviceid);
+             source = xi_device_from_id (dpyinfo, pev->sourceid);
+             x_display_set_last_user_time (dpyinfo, xi_event->time);
 
              if (!device)
                goto XI_OTHER;
@@ -17884,6 +17957,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                       make_float (pev->delta_y),
                                       make_float (pev->scale),
                                       make_float (pev->delta_angle));
+
+                 if (source)
+                   inev.ie.device = source->name;
                }
 
              /* Once again GTK seems to crash when confronted by
@@ -23142,6 +23218,10 @@ void
 mark_xterm (void)
 {
   Lisp_Object val;
+#ifdef HAVE_XINPUT2
+  struct x_display_info *dpyinfo;
+  int i;
+#endif
 
   if (x_dnd_return_frame_object)
     {
@@ -23154,6 +23234,14 @@ mark_xterm (void)
       XSETFRAME (val, x_dnd_movement_frame);
       mark_object (val);
     }
+
+#ifdef HAVE_XINPUT2
+  for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
+    {
+      for (i = 0; i < dpyinfo->num_devices; ++i)
+       mark_object (dpyinfo->devices[i].name);
+    }
+#endif
 }
 
 void
index d8898162d110509f0b1b0941655a8b71628b0880..c12fd6c3fe12e47b52cc6515c733e8b20ef742c9 100644 (file)
@@ -244,6 +244,8 @@ struct xi_device_t
 #ifdef HAVE_XINPUT2_2
   struct xi_touch_point_t *touchpoints;
 #endif
+
+  Lisp_Object name;
 };
 #endif