Improve correctness of generated xwidget events

* src/xwidget.c (xw_maybe_synthesize_crossing): Add new
parameters for controlling the crossing mode.  Also improve the
accuracy of generated crossing events when the mouse pointer
moves outside the toplevel from an inferior of it.  All callers
changed.
(xw_notify_virtual_upwards_until):
(xw_notify_virtual_downwards_until): New parameters for crossing
mode.  All callers changed.
This commit is contained in:
Po Lu 2022-02-02 19:05:54 +08:00
parent fded822c80
commit 70a184b141

View file

@ -265,10 +265,12 @@ xw_translate_x_modifiers (struct x_display_info *dpyinfo,
static bool xw_maybe_synthesize_crossing (struct xwidget_view *,
GdkWindow *, int, int, int,
Time, unsigned int);
Time, unsigned int,
GdkCrossingMode, GdkCrossingMode);
static void xw_notify_virtual_upwards_until (struct xwidget_view *, GdkWindow *,
GdkWindow *, GdkWindow *, unsigned int,
int, int, Time, GdkEventType, bool);
int, int, Time, GdkEventType, bool,
GdkCrossingMode);
static void window_coords_from_toplevel (GdkWindow *, GdkWindow *, int,
int, int *, int *);
#endif
@ -1219,7 +1221,8 @@ xwidget_button_1 (struct xwidget_view *view,
{
xw_maybe_synthesize_crossing (view, gtk_widget_get_window (ungrab_target),
view_x, view_y, XW_CROSSING_NONE,
time, modifier_state);
time, modifier_state, GDK_CROSSING_UNGRAB,
GDK_CROSSING_UNGRAB);
}
else
{
@ -1243,7 +1246,8 @@ xwidget_button_1 (struct xwidget_view *view,
xw_notify_virtual_upwards_until (view, target_window, toplevel, toplevel,
modifier_state, view_x, view_y, time,
GDK_LEAVE_NOTIFY, false);
GDK_LEAVE_NOTIFY, false,
GDK_CROSSING_UNGRAB);
if (target_window != toplevel)
{
@ -1370,7 +1374,11 @@ xwidget_motion_notify (struct xwidget_view *view,
}
else if (xw_maybe_synthesize_crossing (view, gtk_widget_get_window (target),
x + view->clip_left, y + view->clip_top,
XW_CROSSING_NONE, time, state))
XW_CROSSING_NONE, time, state,
(view->passive_grab
? GDK_CROSSING_GRAB
: GDK_CROSSING_NORMAL),
GDK_CROSSING_NORMAL))
return;
xg_event = gdk_event_new (GDK_MOTION_NOTIFY);
@ -1605,7 +1613,8 @@ xw_notify_virtual_upwards_until (struct xwidget_view *xv,
unsigned int state,
int x, int y, Time time,
GdkEventType type,
bool nonlinear_p)
bool nonlinear_p,
GdkCrossingMode crossing)
{
GdkEvent *xg_event;
GdkWindow *tem;
@ -1626,7 +1635,7 @@ xw_notify_virtual_upwards_until (struct xwidget_view *xv,
xg_event->crossing.detail = (nonlinear_p
? GDK_NOTIFY_NONLINEAR_VIRTUAL
: GDK_NOTIFY_VIRTUAL);
xg_event->crossing.mode = GDK_CROSSING_NORMAL;
xg_event->crossing.mode = crossing;
xg_event->crossing.window = g_object_ref (tem);
gtk_main_do_event (xg_event);
@ -1642,7 +1651,8 @@ xw_notify_virtual_downwards_until (struct xwidget_view *xv,
unsigned int state,
int x, int y, Time time,
GdkEventType type,
bool nonlinear_p)
bool nonlinear_p,
GdkCrossingMode crossing)
{
GdkEvent *xg_event;
GdkWindow *tem;
@ -1671,7 +1681,7 @@ xw_notify_virtual_downwards_until (struct xwidget_view *xv,
xg_event->crossing.detail = (nonlinear_p
? GDK_NOTIFY_NONLINEAR_VIRTUAL
: GDK_NOTIFY_VIRTUAL);
xg_event->crossing.mode = GDK_CROSSING_NORMAL;
xg_event->crossing.mode = crossing;
xg_event->crossing.window = g_object_ref (tem);
gtk_main_do_event (xg_event);
@ -1716,14 +1726,18 @@ static bool
xw_maybe_synthesize_crossing (struct xwidget_view *view,
GdkWindow *current_window,
int x, int y, int crossing,
Time time, unsigned int state)
Time time, unsigned int state,
GdkCrossingMode entry_crossing,
GdkCrossingMode exit_crossing)
{
GdkWindow *last_crossing, *toplevel, *ancestor;
GdkEvent *xg_event;
int cx, cy;
bool nonlinear_p;
bool retention_flag;
toplevel = gtk_widget_get_window (XXWIDGET (view->model)->widgetwindow_osr);
retention_flag = false;
if (crossing == XW_CROSSING_LEFT
&& (view->last_crossing_window
@ -1732,13 +1746,40 @@ xw_maybe_synthesize_crossing (struct xwidget_view *view,
xw_notify_virtual_upwards_until (view, view->last_crossing_window,
toplevel, toplevel,
state, x, y, time,
GDK_LEAVE_NOTIFY, false);
GDK_LEAVE_NOTIFY, false,
exit_crossing);
}
if (view->last_crossing_window
&& (gdk_window_is_destroyed (view->last_crossing_window)
|| crossing == XW_CROSSING_LEFT))
{
if (!gdk_window_is_destroyed (view->last_crossing_window)
&& view->last_crossing_window != toplevel)
{
xg_event = gdk_event_new (GDK_LEAVE_NOTIFY);
window_coords_from_toplevel (view->last_crossing_window,
toplevel, x, y, &cx, &cy);
xg_event->crossing.x = cx;
xg_event->crossing.y = cy;
xg_event->crossing.time = time;
xg_event->crossing.focus = FALSE;
xg_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
xg_event->crossing.mode = exit_crossing;
xg_event->crossing.window = g_object_ref (view->last_crossing_window);
gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
gtk_main_do_event (xg_event);
gdk_event_free (xg_event);
xw_notify_virtual_upwards_until (view, view->last_crossing_window,
gdk_window_get_parent (toplevel),
toplevel, state, x, y, time,
GDK_LEAVE_NOTIFY, false, exit_crossing);
retention_flag = true;
}
g_signal_handler_disconnect (view->last_crossing_window,
view->last_crossing_cursor_signal);
g_clear_pointer (&view->last_crossing_window,
@ -1760,9 +1801,9 @@ xw_maybe_synthesize_crossing (struct xwidget_view *view,
toplevel, toplevel,
state, x, y, time,
GDK_ENTER_NOTIFY,
false);
false, entry_crossing);
}
return false;
return retention_flag;
}
if (last_crossing != current_window)
@ -1787,7 +1828,8 @@ xw_maybe_synthesize_crossing (struct xwidget_view *view,
ancestor, toplevel,
state, x, y, time,
GDK_LEAVE_NOTIFY,
nonlinear_p);
nonlinear_p,
exit_crossing);
xg_event = gdk_event_new (GDK_LEAVE_NOTIFY);
gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
@ -1798,13 +1840,12 @@ xw_maybe_synthesize_crossing (struct xwidget_view *view,
xg_event->crossing.time = time;
xg_event->crossing.focus = FALSE;
xg_event->crossing.state = state;
/* TODO: actually calculate the event mode. */
xg_event->crossing.detail = (nonlinear_p
? GDK_NOTIFY_NONLINEAR
: (last_crossing == ancestor
? GDK_NOTIFY_INFERIOR
: GDK_NOTIFY_ANCESTOR));
xg_event->crossing.mode = GDK_CROSSING_NORMAL;
xg_event->crossing.mode = exit_crossing;
xg_event->crossing.window = g_object_ref (last_crossing);
gtk_main_do_event (xg_event);
@ -1815,7 +1856,8 @@ xw_maybe_synthesize_crossing (struct xwidget_view *view,
ancestor, toplevel,
state, x, y, time,
GDK_ENTER_NOTIFY,
nonlinear_p);
nonlinear_p,
entry_crossing);
xg_event = gdk_event_new (GDK_ENTER_NOTIFY);
gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
@ -1831,7 +1873,7 @@ xw_maybe_synthesize_crossing (struct xwidget_view *view,
: (current_window == ancestor
? GDK_NOTIFY_INFERIOR
: GDK_NOTIFY_ANCESTOR));
xg_event->crossing.mode = GDK_CROSSING_NORMAL;
xg_event->crossing.mode = entry_crossing;
xg_event->crossing.window = g_object_ref (current_window);
gtk_main_do_event (xg_event);
@ -1909,7 +1951,11 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
if (!xw_maybe_synthesize_crossing (view, xg_event->any.window,
toplevel_x, toplevel_y,
XW_CROSSING_NONE, event->xmotion.time,
event->xmotion.state))
event->xmotion.state,
(view->passive_grab
? GDK_CROSSING_GRAB
: GDK_CROSSING_NORMAL),
GDK_CROSSING_NORMAL))
{
xg_event->motion.x = x;
xg_event->motion.y = y;
@ -1954,7 +2000,11 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
(xev->type == XI_Enter
? XW_CROSSING_ENTERED
: XW_CROSSING_LEFT),
xev->time, xg_event->crossing.state))
xev->time, xg_event->crossing.state,
(view->passive_grab
? GDK_CROSSING_GRAB
: GDK_CROSSING_NORMAL),
GDK_CROSSING_NORMAL))
{
gdk_event_free (xg_event);
return;
@ -1972,7 +2022,11 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
? XW_CROSSING_ENTERED
: XW_CROSSING_LEFT),
event->xcrossing.time,
event->xcrossing.state))
event->xcrossing.state,
(view->passive_grab
? GDK_CROSSING_GRAB
: GDK_CROSSING_NORMAL),
GDK_CROSSING_NORMAL))
{
gdk_event_free (xg_event);
return;