]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve xwidget event handling on XI2
authorPo Lu <luangruo@yahoo.com>
Wed, 29 Dec 2021 06:37:49 +0000 (14:37 +0800)
committerPo Lu <luangruo@yahoo.com>
Wed, 29 Dec 2021 06:41:07 +0000 (14:41 +0800)
* src/xterm.c (handle_one_xevent): Pass XI2 entry and leave
events to xwidgets and fix scroll valuator reset logic for
xwidgets.

* src/xwidget.c (xwidget_button_1): Stop ungrabbing all devices
XI2 builds.
(xwidget_motion_or_crossing): Learn to pass through XI2 crossing
events.
(x_draw_xwidget_glyph_string): Add crossing events to the XI2
event mask.

src/xterm.c
src/xwidget.c

index a986681ab7792c8c4d2e5a282fffb4978a647b1c..e3079727d5da6b85ccb4f1f2d0a1031a9505d03b 100644 (file)
@@ -9928,9 +9928,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
        XIValuatorState *states;
        double *values;
        bool found_valuator = false;
-#ifdef HAVE_XWIDGETS
-       bool any_stop_p = false;
-#endif /* HAVE_XWIDGETS */
 
        /* A fake XMotionEvent for x_note_mouse_movement. */
        XMotionEvent ev;
@@ -9981,28 +9978,46 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
            x_display_set_last_user_time (dpyinfo, xi_event->time);
            x_detect_focus_change (dpyinfo, any, event, &inev.ie);
+           {
+#ifdef HAVE_XWIDGETS
+             struct xwidget_view *xwidget_view = xwidget_view_from_window (enter->event);
+#else
+             bool xwidget_view = false;
+#endif
+
+             /* One problem behind the design of XInput 2 scrolling is
+                that valuators are not unique to each window, but only
+                the window that has grabbed the valuator's device or
+                the window that the device's pointer is on top of can
+                receive motion events.  There is also no way to
+                retrieve the value of a valuator outside of each motion
+                event.
+
+                As such, to prevent wildly inaccurate results when the
+                valuators have changed outside Emacs, we reset our
+                records of each valuator's value whenever the pointer
+                re-enters a frame after its valuators have potentially
+                been changed elsewhere.  */
+             if (enter->detail != XINotifyInferior
+                 && enter->mode != XINotifyPassiveUngrab
+                 /* See the comment under FocusIn in
+                    `x_detect_focus_change'.  The main relevant culprit
+                    these days seems to be XFCE.  */
+                 && enter->mode != XINotifyUngrab
+                 && (xwidget_view
+                     || (any && enter->event == FRAME_X_WINDOW (any))))
+               xi_reset_scroll_valuators_for_device_id (dpyinfo, enter->deviceid);
 
-           /* One problem behind the design of XInput 2 scrolling is
-              that valuators are not unique to each window, but only
-              the window that has grabbed the valuator's device or
-              the window that the device's pointer is on top of can
-              receive motion events.  There is also no way to
-              retrieve the value of a valuator outside of each motion
-              event.
-
-              As such, to prevent wildly inaccurate results when the
-              valuators have changed outside Emacs, we reset our
-              records of each valuator's value whenever the pointer
-              re-enters a frame after its valuators have potentially
-              been changed elsewhere.  */
-           if (enter->detail != XINotifyInferior
-               && enter->mode != XINotifyPassiveUngrab
-               /* See the comment under FocusIn in
-                  `x_detect_focus_change'.  The main relevant culprit
-                  these days seems to be XFCE.  */
-               && enter->mode != XINotifyUngrab
-               && any && enter->event == FRAME_X_WINDOW (any))
-             xi_reset_scroll_valuators_for_device_id (dpyinfo, enter->deviceid);
+#ifdef HAVE_XWIDGETS
+             if (xwidget_view)
+               {
+                 *finish = X_EVENT_DROP;
+                 xwidget_motion_or_crossing (xwidget_view, event);
+
+                 goto XI_OTHER;
+               }
+#endif
+           }
 
            f = any;
 
@@ -10026,6 +10041,21 @@ handle_one_xevent (struct x_display_info *dpyinfo,
            ev.window = leave->event;
            any = x_any_window_to_frame (dpyinfo, leave->event);
 
+#ifdef HAVE_XWIDGETS
+           {
+             struct xwidget_view *xvw
+               = xwidget_view_from_window (leave->event);
+
+             if (xvw)
+               {
+                 *finish = X_EVENT_DROP;
+                 xwidget_motion_or_crossing (xvw, event);
+
+                 goto XI_OTHER;
+               }
+           }
+#endif
+
            x_display_set_last_user_time (dpyinfo, xi_event->time);
            x_detect_focus_change (dpyinfo, any, event, &inev.ie);
 
@@ -10105,16 +10135,19 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #ifdef HAVE_XWIDGETS
                          if (xv)
                            {
+                             /* FIXME: figure out what in GTK is
+                                causing interval values to jump by
+                                >100 at the end of a touch sequence
+                                when an xwidget gets a scroll event
+                                where is_stop is TRUE.  */
+                             if (fabs (delta) > 100)
+                               continue;
                              if (val->horizontal)
                                xv_total_x += delta;
                              else
                                xv_total_y += delta;
 
                              found_valuator = true;
-
-                             if (delta == 0.0)
-                               any_stop_p = true;
-
                              continue;
                            }
 #endif
@@ -10224,8 +10257,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
                  if (found_valuator)
                    xwidget_scroll (xv, xev->event_x, xev->event_y,
-                                   xv_total_x, xv_total_y, state,
-                                   xev->time, any_stop_p);
+                                   -xv_total_x, -xv_total_y, state,
+                                   xev->time, (xv_total_x == 0.0
+                                               && xv_total_y == 0.0));
                  else
                    xwidget_motion_notify (xv, xev->event_x, xev->event_y,
                                           state, xev->time);
index 22c42382bbf382037498a5368fc1ba47704b7f58..c05cefde4b5a5a964d59221733405bf5ca1c782c 100644 (file)
@@ -1052,12 +1052,6 @@ xwidget_button_1 (struct xwidget_view *view,
   GdkEvent *xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE);
   struct xwidget *model = XXWIDGET (view->model);
   GtkWidget *target;
-#ifdef HAVE_XINPUT2
-  struct x_display_info *dpyinfo;
-  struct xi_device_t *xi_device;
-  GdkSeat *seat;
-  GdkDevice *device;
-#endif
 
   /* X and Y should be relative to the origin of view->wdesc.  */
   x += view->clip_left;
@@ -1081,24 +1075,6 @@ xwidget_button_1 (struct xwidget_view *view,
   xg_event->button.time = time;
   xg_event->button.device = find_suitable_pointer (view->frame);
 
-#ifdef HAVE_XINPUT2
-  dpyinfo = FRAME_DISPLAY_INFO (view->frame);
-  device = xg_event->button.device;
-
-  for (int idx = 0; idx < dpyinfo->num_devices; ++idx)
-    {
-      xi_device = &dpyinfo->devices[idx];
-
-      XIUngrabDevice (view->dpy, xi_device->device_id, CurrentTime);
-    }
-
-  if (device)
-    {
-      seat = gdk_device_get_seat (device);
-      gdk_seat_ungrab (seat);
-    }
-#endif
-
   gtk_main_do_event (xg_event);
   gdk_event_free (xg_event);
 }
@@ -1260,24 +1236,47 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
   int x;
   int y;
   GtkWidget *target;
+#ifdef HAVE_XINPUT2
+  XIEnterEvent *xev = NULL;
+#endif
 
   if (NILP (model->buffer))
     return;
 
-  xg_event = gdk_event_new (event->type == MotionNotify
-                           ? GDK_MOTION_NOTIFY
-                           : (event->type == LeaveNotify
-                              ? GDK_LEAVE_NOTIFY
-                              : GDK_ENTER_NOTIFY));
+#ifdef HAVE_XINPUT2
+  if (event->type != GenericEvent)
+#endif
+    {
+      xg_event = gdk_event_new (event->type == MotionNotify
+                               ? GDK_MOTION_NOTIFY
+                               : (event->type == LeaveNotify
+                                  ? GDK_LEAVE_NOTIFY
+                                  : GDK_ENTER_NOTIFY));
+      target = find_widget_at_pos (model->widgetwindow_osr,
+                                  (event->type == MotionNotify
+                                   ? event->xmotion.x + view->clip_left
+                                   : event->xcrossing.x + view->clip_left),
+                                  (event->type == MotionNotify
+                                   ? event->xmotion.y + view->clip_top
+                                   : event->xcrossing.y + view->clip_top),
+                                  &x, &y);
+    }
+#ifdef HAVE_XINPUT2
+  else
+    {
+      eassert (event->xcookie.evtype == XI_Enter
+              || event->xcookie.evtype == XI_Leave);
 
-  target = find_widget_at_pos (model->widgetwindow_osr,
-                              (event->type == MotionNotify
-                               ? event->xmotion.x + view->clip_left
-                               : event->xcrossing.x + view->clip_left),
-                              (event->type == MotionNotify
-                               ? event->xmotion.y + view->clip_top
-                               : event->xcrossing.y + view->clip_top),
-                              &x, &y);
+      xev = (XIEnterEvent *) event->xcookie.data;
+      xg_event = gdk_event_new (event->type == XI_Enter
+                               ? GDK_ENTER_NOTIFY
+                               : GDK_LEAVE_NOTIFY);
+      target = find_widget_at_pos (model->widgetwindow_osr,
+                                  lrint (xev->event_x + view->clip_left),
+                                  lrint (xev->event_y + view->clip_top),
+                                  &x, &y);
+    }
+#endif
 
   if (!target)
     target = model->widget_osr;
@@ -1297,6 +1296,18 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
       xg_event->motion.state = event->xmotion.state;
       xg_event->motion.device = find_suitable_pointer (view->frame);
     }
+#ifdef HAVE_XINPUT2
+  else if (event->type == GenericEvent)
+    {
+      xg_event->crossing.x = (gdouble) xev->event_x;
+      xg_event->crossing.y = (gdouble) xev->event_y;
+      xg_event->crossing.x_root = (gdouble) xev->root_x;
+      xg_event->crossing.y_root = (gdouble) xev->root_y;
+      xg_event->crossing.time = xev->time;
+      xg_event->crossing.focus = xev->focus;
+      gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
+    }
+#endif
   else
     {
       xg_event->crossing.detail = min (5, event->xcrossing.detail);
@@ -1305,6 +1316,7 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
       xg_event->crossing.y = y;
       xg_event->crossing.x_root = event->xcrossing.x_root;
       xg_event->crossing.y_root = event->xcrossing.y_root;
+      xg_event->crossing.focus = event->xcrossing.focus;
       gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
     }
 
@@ -2108,6 +2120,8 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
          XISetMask (m, XI_Motion);
          XISetMask (m, XI_ButtonPress);
          XISetMask (m, XI_ButtonRelease);
+         XISetMask (m, XI_Enter);
+         XISetMask (m, XI_Leave);
          XISelectEvents (xv->dpy, xv->wdesc, &mask, 1);
        }
 #endif