From: Po Lu Date: Sun, 21 Nov 2021 03:04:29 +0000 (+0800) Subject: Allow handling smooth scroll events in xwidgets X-Git-Tag: emacs-29.0.90~2852^2~150 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=39f3604e229ff349742dab0d6a5c7b4500530c07;p=emacs.git Allow handling smooth scroll events in xwidgets * 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. --- diff --git a/src/xterm.c b/src/xterm.c index 6a35b11d054..b78cfa70531 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -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; diff --git a/src/xwidget.c b/src/xwidget.c index 1ab953d3c82..35e359458bc 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -40,10 +40,15 @@ along with GNU Emacs. If not, see . */ #include #include #include +#ifdef HAVE_XINPUT2 +#include +#endif #elif defined NS_IMPL_COCOA #include "nsxwidget.h" #endif +#include + 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, diff --git a/src/xwidget.h b/src/xwidget.h index 78fe865dd84..f2d497c0920 100644 --- a/src/xwidget.h +++ b/src/xwidget.h @@ -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