From: Po Lu Date: Wed, 29 Dec 2021 06:37:49 +0000 (+0800) Subject: Improve xwidget event handling on XI2 X-Git-Tag: emacs-29.0.90~3378 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=2b7d33e30b4b66bca405fed5b5483e864db6b1e5;p=emacs.git Improve xwidget event handling on XI2 * 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. --- diff --git a/src/xterm.c b/src/xterm.c index a986681ab77..e3079727d5d 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -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); diff --git a/src/xwidget.c b/src/xwidget.c index 22c42382bbf..c05cefde4b5 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -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