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.
This commit is contained in:
parent
22a9a20513
commit
2b7d33e30b
2 changed files with 114 additions and 66 deletions
92
src/xterm.c
92
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.
|
||||
/* 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);
|
||||
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);
|
||||
|
||||
#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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue