From ccb09d1c6fc1beeb2d371d4e427af71cfc7d6de6 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 10 Jul 2009 17:30:42 +0200 Subject: [PATCH] Manually update toplevel_under_pointer when a grab changes to owner_events When we ungrab the pointer we don't get enter events for the window the pointer is in at the time of the ungrab, so we manually query for the window the pointer is in. The same thing actually happens on re-grab if the previous grab was !owner_events (meaning we don't get crossing events for windows other than the grab) but the new grab is owner_events (and thus non-grab windows need to get crossing events). This factors out some common code and enables it also for the re-grab to owner_events case. --- gdk/gdkdisplay.c | 133 ++++++++++++++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 49 deletions(-) diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c index 399d193999..ff11f086fc 100644 --- a/gdk/gdkdisplay.c +++ b/gdk/gdkdisplay.c @@ -903,6 +903,42 @@ synthesize_crossing_events (GdkDisplay *display, } } +static GdkWindow * +get_current_toplevel (GdkDisplay *display, + int *x_out, int *y_out, + GdkModifierType *state_out) +{ + GdkWindow *pointer_window; + GdkWindowObject *w; + int x, y; + GdkModifierType state; + + pointer_window = _gdk_windowing_window_at_pointer (display, &x, &y, &state); + if (pointer_window != NULL && + (GDK_WINDOW_DESTROYED (pointer_window) || + GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT || + GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_FOREIGN)) + pointer_window = NULL; + + w = (GdkWindowObject *)pointer_window; + if (w) + { + /* Convert to toplevel */ + while (w->parent != NULL && + w->parent->window_type != GDK_WINDOW_ROOT) + { + x += w->x; + y += w->y; + w = w->parent; + } + } + + *x_out = x; + *y_out = y; + *state_out = state; + return (GdkWindow *)w; +} + static void switch_to_pointer_grab (GdkDisplay *display, GdkPointerGrabInfo *grab, @@ -910,8 +946,7 @@ switch_to_pointer_grab (GdkDisplay *display, guint32 time, gulong serial) { - GdkWindow *src_window, *pointer_window; - GdkWindowObject *w; + GdkWindow *src_window, *pointer_window, *new_toplevel; GList *old_grabs; GdkModifierType state; int x, y; @@ -944,66 +979,66 @@ switch_to_pointer_grab (GdkDisplay *display, src_window, grab->window, GDK_CROSSING_GRAB, time, serial); } - + /* !owner_event Grabbing a window that we're not inside, current status is now NULL (i.e. outside grabbed window) */ if (!grab->owner_events && display->pointer_info.window_under_pointer != grab->window) _gdk_display_set_window_under_pointer (display, NULL); } - + grab->activated = TRUE; } - else if (last_grab) + + if (last_grab) { - pointer_window = _gdk_windowing_window_at_pointer (display, &x, &y, &state); - if (pointer_window != NULL && - (GDK_WINDOW_DESTROYED (pointer_window) || - GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT || - GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_FOREIGN)) - pointer_window = NULL; - - /* We force checked what window we're in, so we need to - * update the toplevel_under_pointer info, as that won't get told of - * this change. - */ - if (display->pointer_info.toplevel_under_pointer) - g_object_unref (display->pointer_info.toplevel_under_pointer); - display->pointer_info.toplevel_under_pointer = NULL; - - if (pointer_window) + new_toplevel = NULL; + + if (grab == NULL /* ungrab */ || + (!last_grab->owner_events && grab->owner_events) /* switched to owner_events */ ) { - /* Convert to toplevel */ - w = (GdkWindowObject *)pointer_window; - while (/*w->parent != NULL && */ - w->parent->window_type != GDK_WINDOW_ROOT) + /* We force check what window we're in, and update the toplevel_under_pointer info, + * as that won't get told of this change with toplevel enter events. + */ + if (display->pointer_info.toplevel_under_pointer) + g_object_unref (display->pointer_info.toplevel_under_pointer); + display->pointer_info.toplevel_under_pointer = NULL; + + new_toplevel = get_current_toplevel (display, &x, &y, &state); + if (new_toplevel) { - x += w->x; - y += w->y; - w = w->parent; + /* w is now toplevel and x,y in toplevel coords */ + display->pointer_info.toplevel_under_pointer = g_object_ref (new_toplevel); + display->pointer_info.toplevel_x = x; + display->pointer_info.toplevel_y = y; + display->pointer_info.state = state; } - - /* w is now toplevel and x,y in toplevel coords */ - display->pointer_info.toplevel_under_pointer = g_object_ref (w); - - /* Find (possibly virtual) child window */ - pointer_window = - _gdk_window_find_descendant_at ((GdkWindow *)w, - x, y, - NULL, NULL); } - if (pointer_window != last_grab->window) - synthesize_crossing_events (display, - last_grab->window, pointer_window, - GDK_CROSSING_UNGRAB, time, serial); - - /* We're now ungrabbed, update the window_under_pointer */ - _gdk_display_set_window_under_pointer (display, pointer_window); - - if (last_grab->implicit_ungrab) - generate_grab_broken_event (last_grab->window, - FALSE, TRUE, - NULL); + if (grab == NULL) /* Ungrabbed, send events */ + { + pointer_window = NULL; + if (new_toplevel) + { + /* Find (possibly virtual) child window */ + pointer_window = + _gdk_window_find_descendant_at (new_toplevel, + x, y, + NULL, NULL); + } + + if (pointer_window != last_grab->window) + synthesize_crossing_events (display, + last_grab->window, pointer_window, + GDK_CROSSING_UNGRAB, time, serial); + + /* We're now ungrabbed, update the window_under_pointer */ + _gdk_display_set_window_under_pointer (display, pointer_window); + + if (last_grab->implicit_ungrab) + generate_grab_broken_event (last_grab->window, + FALSE, TRUE, + NULL); + } } display->pointer_grabs = old_grabs;