]> git.eshelyaron.com Git - emacs.git/commitdiff
Allow handling smooth scroll events in xwidgets
authorPo Lu <luangruo@yahoo.com>
Sun, 21 Nov 2021 03:04:29 +0000 (11:04 +0800)
committerPo Lu <luangruo@yahoo.com>
Sun, 21 Nov 2021 03:06:02 +0000 (11:06 +0800)
* src/xterm.c (handle_one_xevent): Pass through XI2 motion
events to xwidgets.
* src/xterm.c (xwidget_button): Don't handle legacy scroll
events on XInput 2.
(xwidget_motion_notify, xwidget_scroll): New functions.

src/xterm.c
src/xwidget.c
src/xwidget.h

index 6a35b11d05463efe9ef0b7e5f08d6d84a94b6035..b78cfa70531b85d2fa894f7370f4758e37ac5e22 100644 (file)
@@ -9927,6 +9927,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
            x_display_set_last_user_time (dpyinfo, xi_event->time);
 
+#ifdef HAVE_XWIDGETS
+           struct xwidget_view *xv = xwidget_view_from_window (xev->event);
+           double xv_total_x = 0.0;
+           double xv_total_y = 0.0;
+#endif
+
            for (int i = 0; i < states->mask_len * 8; i++)
              {
                if (XIMaskIsSet (states->mask, i))
@@ -9939,6 +9945,18 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
                    if (delta != DBL_MAX)
                      {
+#ifdef HAVE_XWIDGETS
+                       if (xv)
+                         {
+                           if (val->horizontal)
+                             xv_total_x += delta;
+                           else
+                             xv_total_y += -delta;
+
+                           found_valuator = true;
+                           continue;
+                         }
+#endif
                        if (!f)
                          {
                            f = x_any_window_to_frame (dpyinfo, xev->event);
@@ -9999,6 +10017,20 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                inev.ie.kind = NO_EVENT;
              }
 
+#ifdef HAVE_XWIDGETS
+           if (xv)
+             {
+               if (found_valuator)
+                 xwidget_scroll (xv, xev->event_x, xev->event_y,
+                                 xv_total_x, xv_total_y, xev->mods.effective,
+                                 xev->time);
+               else
+                 xwidget_motion_notify (xv, xev->event_x, xev->event_y,
+                                        xev->mods.effective, xev->time);
+
+               goto XI_OTHER;
+             }
+#endif
            if (found_valuator)
              goto XI_OTHER;
 
index 1ab953d3c826fd6ddfc83d2b2fa235c5dbf505de..35e359458bc07c380658d87c30c3dd2a4c1308e1 100644 (file)
@@ -40,10 +40,15 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include <JavaScriptCore/JavaScript.h>
 #include <cairo.h>
 #include <X11/Xlib.h>
+#ifdef HAVE_XINPUT2
+#include <X11/extensions/XInput2.h>
+#endif
 #elif defined NS_IMPL_COCOA
 #include "nsxwidget.h"
 #endif
 
+#include <math.h>
+
 static Lisp_Object id_to_xwidget_map;
 static Lisp_Object internal_xwidget_view_list;
 static Lisp_Object internal_xwidget_list;
@@ -912,7 +917,12 @@ xwidget_button (struct xwidget_view *view,
 
   if (button < 4 || button > 8)
     xwidget_button_1 (view, down_p, x, y, button, modifier_state, time);
+#ifndef HAVE_XINPUT2
   else
+#else
+  else if (!FRAME_DISPLAY_INFO (view->frame)->supports_xi2
+          || FRAME_DISPLAY_INFO (view->frame)->xi2_version < 1)
+#endif
     {
       GdkEvent *xg_event = gdk_event_new (GDK_SCROLL);
       struct xwidget *model = XXWIDGET (view->model);
@@ -955,6 +965,93 @@ xwidget_button (struct xwidget_view *view,
     }
 }
 
+#ifdef HAVE_XINPUT2
+void
+xwidget_motion_notify (struct xwidget_view *view,
+                      double x, double y, uint state, Time time)
+{
+  GdkEvent *xg_event;
+  GtkWidget *target;
+  struct xwidget *model = XXWIDGET (view->model);
+  int target_x, target_y;
+
+  if (NILP (model->buffer))
+    return;
+
+  record_osr_embedder (view);
+
+  target = find_widget_at_pos (model->widgetwindow_osr,
+                              lrint (x), lrint (y),
+                              &target_x, &target_y);
+
+  if (!target)
+    {
+      target_x = lrint (x);
+      target_y = lrint (y);
+      target = model->widget_osr;
+    }
+
+  xg_event = gdk_event_new (GDK_MOTION_NOTIFY);
+  xg_event->any.window = gtk_widget_get_window (target);
+  xg_event->motion.x = target_x;
+  xg_event->motion.y = target_y;
+  xg_event->motion.x_root = lrint (x);
+  xg_event->motion.y_root = lrint (y);
+  xg_event->motion.time = time;
+  xg_event->motion.state = state;
+  xg_event->motion.device = find_suitable_pointer (view->frame);
+
+  g_object_ref (xg_event->any.window);
+
+  gtk_main_do_event (xg_event);
+  gdk_event_free (xg_event);
+}
+
+void
+xwidget_scroll (struct xwidget_view *view, double x, double y,
+               double dx, double dy, uint state, Time time)
+{
+  GdkEvent *xg_event;
+  GtkWidget *target;
+  struct xwidget *model = XXWIDGET (view->model);
+  int target_x, target_y;
+
+  if (NILP (model->buffer))
+    return;
+
+  record_osr_embedder (view);
+
+  target = find_widget_at_pos (model->widgetwindow_osr,
+                              lrint (x), lrint (y),
+                              &target_x, &target_y);
+
+  if (!target)
+    {
+      target_x = lrint (x);
+      target_y = lrint (y);
+      target = model->widget_osr;
+    }
+
+  xg_event = gdk_event_new (GDK_SCROLL);
+  xg_event->any.window = gtk_widget_get_window (target);
+  xg_event->scroll.direction = GDK_SCROLL_SMOOTH;
+  xg_event->scroll.x = target_x;
+  xg_event->scroll.y = target_y;
+  xg_event->scroll.x_root = lrint (x);
+  xg_event->scroll.y_root = lrint (y);
+  xg_event->scroll.time = time;
+  xg_event->scroll.state = state;
+  xg_event->scroll.delta_x = dx;
+  xg_event->scroll.delta_y = dy;
+  xg_event->scroll.device = find_suitable_pointer (view->frame);
+
+  g_object_ref (xg_event->any.window);
+
+  gtk_main_do_event (xg_event);
+  gdk_event_free (xg_event);
+}
+#endif
+
 void
 xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
 {
@@ -1705,6 +1802,22 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
                                 clip_bottom - clip_top, 0,
                                 CopyFromParent, CopyFromParent,
                                 CopyFromParent, CWEventMask, &a);
+#ifdef HAVE_XINPUT2
+      XIEventMask mask;
+      ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
+      unsigned char *m;
+
+      if (FRAME_DISPLAY_INFO (s->f)->supports_xi2)
+       {
+         mask.mask = m = alloca (l);
+         memset (m, 0, l);
+         mask.mask_len = l;
+         mask.deviceid = XIAllMasterDevices;
+
+         XISetMask (m, XI_Motion);
+         XISelectEvents (xv->dpy, xv->wdesc, &mask, 1);
+       }
+#endif
       XLowerWindow (xv->dpy, xv->wdesc);
       XDefineCursor (xv->dpy, xv->wdesc, xv->cursor);
       xv->cr_surface = cairo_xlib_surface_create (xv->dpy,
index 78fe865dd843dc13916e5ce9e863ce2adeb6b528..f2d497c09206f298cd4e6c448fdd19dc79bdd204 100644 (file)
@@ -195,6 +195,12 @@ extern void xwidget_button (struct xwidget_view *, bool, int,
                            int, int, int, Time);
 extern void xwidget_motion_or_crossing (struct xwidget_view *,
                                        const XEvent *);
+#ifdef HAVE_XINPUT2
+extern void xwidget_motion_notify (struct xwidget_view *, double,
+                                  double, uint, Time);
+extern void xwidget_scroll (struct xwidget_view *, double, double,
+                            double, double, uint, Time);
+#endif
 #endif
 #else
 INLINE_HEADER_BEGIN