Commit ccb09d1c authored by Alexander Larsson's avatar Alexander Larsson

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.
parent 0ef74c93
......@@ -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 */ )
{
/* 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)
{
/* 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;
}
}
if (grab == NULL) /* Ungrabbed, send events */
{
/* Convert to toplevel */
w = (GdkWindowObject *)pointer_window;
while (/*w->parent != NULL && */
w->parent->window_type != GDK_WINDOW_ROOT)
pointer_window = NULL;
if (new_toplevel)
{
x += w->x;
y += w->y;
w = w->parent;
/* Find (possibly virtual) child window */
pointer_window =
_gdk_window_find_descendant_at (new_toplevel,
x, y,
NULL, NULL);
}
/* w is now toplevel and x,y in toplevel coords */
display->pointer_info.toplevel_under_pointer = g_object_ref (w);
if (pointer_window != last_grab->window)
synthesize_crossing_events (display,
last_grab->window, pointer_window,
GDK_CROSSING_UNGRAB, time, serial);
/* Find (possibly virtual) child window */
pointer_window =
_gdk_window_find_descendant_at ((GdkWindow *)w,
x, y,
NULL, NULL);
}
/* We're now ungrabbed, update the window_under_pointer */
_gdk_display_set_window_under_pointer (display, pointer_window);
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 (last_grab->implicit_ungrab)
generate_grab_broken_event (last_grab->window,
FALSE, TRUE,
NULL);
}
}
display->pointer_grabs = old_grabs;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment