From 70a184b141862a495befb8c47c4f344002118703 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Wed, 2 Feb 2022 19:05:54 +0800 Subject: [PATCH] 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. --- src/xwidget.c | 96 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 21 deletions(-) diff --git a/src/xwidget.c b/src/xwidget.c index 9b08d47a8e8..23031f9c93c 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -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; -- 2.39.5