diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c index a8f027e73e..48d79e8542 100644 --- a/gdk/gdkdisplay.c +++ b/gdk/gdkdisplay.c @@ -750,228 +750,434 @@ generate_grab_broken_event (GdkWindow *window, } } -void -_gdk_display_set_has_pointer_grab (GdkDisplay *display, - GdkWindow *window, - GdkWindow *native_window, - gboolean owner_events, - GdkEventMask event_mask, - unsigned long serial, - guint32 time, - gboolean implicit) +/* Get the pointer grab in effects for events we just sent */ +GdkPointerGrabInfo * +_gdk_display_get_active_pointer_grab (GdkDisplay *display) { - GdkWindow *src_toplevel, *dest_toplevel, *src_window; + GdkPointerGrabInfo *info; + + if (display->pointer_grabs == NULL) + return NULL; + + info = display->pointer_grabs->data; + + if (info->activated) + return info; - if (display->pointer_grab.window != NULL && - display->pointer_grab.window != window) - { - generate_grab_broken_event (GDK_WINDOW (display->pointer_grab.window), - FALSE, display->pointer_grab.implicit, - window); - } - - /* We need to generate crossing events for the grab. - * However, there are never any crossing events for implicit grabs - * TODO: ... Actually, this could happen if the pointer window doesn't have button mask so a parent gets the event... - */ - if (!implicit) - { - int x, y; - GdkModifierType state; - - /* We send GRAB crossing events from the window under the pointer to the - grab window. Except if there is an old grab then we start from that */ - if (display->pointer_grab.window) - src_window = display->pointer_grab.window; - else - src_window = display->pointer_info.window_under_pointer; - - /* Unset any current grab to make sure we send the events */ - display->pointer_grab.window = NULL; - - if (src_window != window) - { - /* _gdk_syntesize_crossing_events only works inside one toplevel, split into two calls if needed */ - if (src_window) - src_toplevel = gdk_window_get_toplevel (src_window); - else - src_toplevel = NULL; - dest_toplevel = gdk_window_get_toplevel (window); - - if (src_toplevel == NULL || - src_toplevel == dest_toplevel) - { - _gdk_windowing_window_get_pointer (display, - dest_toplevel, - &x, &y, &state); - _gdk_syntesize_crossing_events (display, - src_window, - window, - GDK_CROSSING_GRAB, - x, y, state, - time, - NULL); - } - else - { - _gdk_windowing_window_get_pointer (display, - src_toplevel, - &x, &y, &state); - _gdk_syntesize_crossing_events (display, - src_window, - NULL, - GDK_CROSSING_GRAB, - x, y, state, - time, - NULL); - _gdk_windowing_window_get_pointer (display, - dest_toplevel, - &x, &y, &state); - _gdk_syntesize_crossing_events (display, - NULL, - window, - GDK_CROSSING_GRAB, - x, y, state, - time, - NULL); - } - } - - /* !owner_event Grabbing a window that we're not inside, current status is - now NULL (i.e. outside grabbed window) */ - if (!owner_events && display->pointer_info.window_under_pointer != window) - _gdk_display_set_window_under_pointer (display, NULL); - } - - display->pointer_grab.window = window; - display->pointer_grab.native_window = native_window; - display->pointer_grab.serial = serial; - display->pointer_grab.owner_events = owner_events; - display->pointer_grab.event_mask = event_mask; - display->pointer_grab.time = time; - display->pointer_grab.implicit = implicit; - display->pointer_grab.converted_implicit = FALSE; + return NULL; } -void -_gdk_display_unset_has_pointer_grab (GdkDisplay *display, - gboolean implicit, - gboolean do_grab_one_pointer_release_event, - guint32 time) + +GdkPointerGrabInfo * +_gdk_display_get_last_pointer_grab (GdkDisplay *display) { - GdkWindow *pointer_window, *src_toplevel, *dest_toplevel; - GdkWindow *old_grab_window; - GdkWindow *old_native_grab_window; - int x, y; - GdkModifierType state; - GdkWindowObject *w; + GList *l; - old_grab_window = display->pointer_grab.window; - old_native_grab_window = display->pointer_grab.native_window; + l = display->pointer_grabs; - if (old_grab_window == NULL) - return; /* This happens in the gdk_window_hide case */ + if (l == NULL) + return NULL; - if (do_grab_one_pointer_release_event) - display->pointer_grab.grab_one_pointer_release_event = display->pointer_grab.window; + while (l->next != NULL) + l = l->next; - /* Set first so crossing events get sent */ - display->pointer_grab.window = NULL; - - pointer_window = _gdk_windowing_window_at_pointer (display, &x, &y, &state); - - if (pointer_window != NULL && - (GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT || - GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_FOREIGN)) - pointer_window = NULL; + return (GdkPointerGrabInfo *)l->data; +} - /* 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) + +GdkPointerGrabInfo * +_gdk_display_add_pointer_grab (GdkDisplay *display, + GdkWindow *window, + GdkWindow *native_window, + gboolean owner_events, + GdkEventMask event_mask, + unsigned long serial_start, + guint32 time, + gboolean implicit) +{ + GdkPointerGrabInfo *info, *other_info; + GList *l; + + info = g_new0 (GdkPointerGrabInfo, 1); + + info->window = g_object_ref (window); + info->native_window = g_object_ref (native_window); + info->serial_start = serial_start; + info->serial_end = G_MAXULONG; + info->owner_events = owner_events; + info->event_mask = event_mask; + info->time = time; + info->implicit = implicit; + info->converted_implicit = FALSE; + + /* Find the first grab that has a larger start time (if any) and insert + * before that. I.E we insert after already existing grabs with same + * start time */ + for (l = display->pointer_grabs; l != NULL; l = l->next) { - /* Convert to toplevel */ - w = (GdkWindowObject *)pointer_window; - while (w->parent->window_type != GDK_WINDOW_ROOT) - { - 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 (w); + other_info = l->data; - /* Find child window */ - pointer_window = - _gdk_window_find_descendant_at ((GdkWindow *)w, - x, y, - NULL, NULL); + if (info->serial_start < other_info->serial_start) + break; + } + display->pointer_grabs = + g_list_insert_before (display->pointer_grabs, l, info); + + /* Make sure the new grab end before next grab */ + if (l) + { + other_info = l->data; + info->serial_end = other_info->serial_start; } - - if (pointer_window == NULL) + /* Find any previous grab and update its end time */ + l = g_list_find (display->pointer_grabs, info); + l = l->prev; + if (l) { + other_info = l->data; + other_info->serial_end = serial_start; + } + + return info; +} + +static void +free_pointer_grab (GdkPointerGrabInfo *info) +{ + g_object_unref (info->window); + g_object_unref (info->native_window); + g_free (info); +} + +/* _gdk_syntesize_crossing_events only works inside one toplevel. + This function splits things into two calls if needed, converting the + coordinates to the right toplevel */ +static void +synthesize_crossing_events (GdkDisplay *display, + GdkWindow *src_window, + GdkWindow *dest_window, + GdkCrossingMode crossing_mode, + guint32 time, + gulong serial) +{ + GdkWindow *src_toplevel, *dest_toplevel; + GdkModifierType state; + int x, y; + + if (src_window) + src_toplevel = gdk_window_get_toplevel (src_window); + else + src_toplevel = NULL; + if (dest_window) + dest_toplevel = gdk_window_get_toplevel (dest_window); + else + dest_toplevel = NULL; + + if (src_toplevel == NULL && dest_toplevel == NULL) + return; + + if (src_toplevel == NULL || + src_toplevel == dest_toplevel) + { + /* Same toplevels */ + _gdk_windowing_window_get_pointer (display, + dest_toplevel, + &x, &y, &state); _gdk_syntesize_crossing_events (display, - old_grab_window, - NULL, - GDK_CROSSING_UNGRAB, + src_window, + dest_window, + crossing_mode, x, y, state, time, - NULL); + NULL, + serial); + } + else if (dest_toplevel == NULL) + { + _gdk_windowing_window_get_pointer (display, + src_toplevel, + &x, &y, &state); + _gdk_syntesize_crossing_events (display, + src_window, + NULL, + crossing_mode, + x, y, state, + time, + NULL, + serial); } else { - if (pointer_window != old_grab_window) - { - /* _gdk_syntesize_crossing_events only works inside one toplevel, split into two calls if needed */ - src_toplevel = gdk_window_get_toplevel (old_grab_window); - dest_toplevel = gdk_window_get_toplevel (pointer_window); + /* Different toplevels */ + _gdk_windowing_window_get_pointer (display, + src_toplevel, + &x, &y, &state); + _gdk_syntesize_crossing_events (display, + src_window, + NULL, + crossing_mode, + x, y, state, + time, + NULL, + serial); + _gdk_windowing_window_get_pointer (display, + dest_toplevel, + &x, &y, &state); + _gdk_syntesize_crossing_events (display, + NULL, + dest_window, + crossing_mode, + x, y, state, + time, + NULL, + serial); + } +} - if (src_toplevel == dest_toplevel) - { - _gdk_syntesize_crossing_events (display, - display->pointer_info.window_under_pointer, - pointer_window, - GDK_CROSSING_UNGRAB, - x, y, state, - time, - NULL); - } + +static void +switch_to_pointer_grab (GdkDisplay *display, + GdkPointerGrabInfo *grab, + GdkPointerGrabInfo *last_grab, + guint32 time, + gulong serial) +{ + GdkWindow *src_window, *pointer_window; + GdkWindowObject *w; + GList *old_grabs; + GdkModifierType state; + int x, y; + + /* Temporarily unset pointer to make sure we send the crossing events below */ + old_grabs = display->pointer_grabs; + display->pointer_grabs = NULL; + + if (grab) + { + /* New grab is in effect */ + + /* We need to generate crossing events for the grab. + * However, there are never any crossing events for implicit grabs + * TODO: ... Actually, this could happen if the pointer window + * doesn't have button mask so a parent gets the event... + */ + if (!grab->implicit) + { + /* We send GRAB crossing events from the window under the pointer to the + grab window. Except if there is an old grab then we start from that */ + if (last_grab) + src_window = last_grab->window; else + src_window = display->pointer_info.window_under_pointer; + + if (src_window != grab->window) { - /* TODO: We're reporting the wrong coords here. They are in pointer_window toplevel coords */ - _gdk_syntesize_crossing_events (display, - display->pointer_info.window_under_pointer, - NULL, - GDK_CROSSING_UNGRAB, - x, y, state, - time, - NULL); - _gdk_syntesize_crossing_events (display, - NULL, - pointer_window, - GDK_CROSSING_UNGRAB, - x, y, state, - time, - NULL); + synthesize_crossing_events (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) + { + pointer_window = _gdk_windowing_window_at_pointer (display, &x, &y, &state); + if (pointer_window != NULL && + (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) + { + /* Convert to toplevel */ + w = (GdkWindowObject *)pointer_window; + while (w->parent->window_type != GDK_WINDOW_ROOT) + { + 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 (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); + } + + display->pointer_grabs = old_grabs; + +} + +void +_gdk_display_pointer_grab_update (GdkDisplay *display, + gulong current_serial) +{ + GdkPointerGrabInfo *current_grab, *next_grab; + guint32 time; + + time = display->last_event_time; + + while (display->pointer_grabs != NULL) + { + current_grab = display->pointer_grabs->data; + + if (current_grab->serial_start > current_serial) + return; /* Hasn't started yet */ + + if (current_grab->serial_end > current_serial || + (current_grab->serial_end == current_serial && + current_grab->grab_one_pointer_release_event)) + { + /* This one hasn't ended yet. + its the currently active one or scheduled to be active */ + + if (!current_grab->activated) + switch_to_pointer_grab (display, current_grab, NULL, time, current_serial); + + break; + } + + + next_grab = NULL; + if (display->pointer_grabs->next) + { + /* This is the next active grab */ + next_grab = display->pointer_grabs->next->data; + + if (next_grab->serial_start > current_serial) + next_grab = NULL; /* Actually its not yet active */ + } + + if (next_grab == NULL || + current_grab->window != next_grab->window) + generate_grab_broken_event (GDK_WINDOW (current_grab->window), + FALSE, current_grab->implicit, + next_grab? next_grab->window : NULL); + + + /* Remove old grab */ + display->pointer_grabs = + g_list_delete_link (display->pointer_grabs, + display->pointer_grabs); + + switch_to_pointer_grab (display, + next_grab, current_grab, + time, current_serial); + + free_pointer_grab (current_grab); + } +} + +static gboolean +is_parent_of (GdkWindow *parent, + GdkWindow *child) +{ + GdkWindow *w; + + w = child; + while (w != NULL) + { + if (w == parent) + return TRUE; + + w = gdk_window_get_parent (w); } - /* We're now ungrabbed, update the window_under_pointer */ - _gdk_display_set_window_under_pointer (display, pointer_window); + return FALSE; +} + +static GList * +find_pointer_grab (GdkDisplay *display, + gulong serial) +{ + GdkPointerGrabInfo *grab; + GList *l; + + for (l = display->pointer_grabs; l != NULL; l = l->next) + { + grab = l->data; + + if (serial >= grab->serial_start && serial < grab->serial_end) + return l; + } - if (implicit) - generate_grab_broken_event (old_grab_window, - FALSE, implicit, - NULL); + return NULL; +} + + + +GdkPointerGrabInfo * +_gdk_display_has_pointer_grab (GdkDisplay *display, + gulong serial) +{ + GList *l; + + l = find_pointer_grab (display, serial); + if (l) + return l->data; + + return NULL; +} + +/* Returns true if last grab was ended */ +gboolean +_gdk_display_end_pointer_grab (GdkDisplay *display, + gulong serial, + GdkWindow *if_child, + gboolean implicit) +{ + GdkPointerGrabInfo *grab; + GList *l; + + l = find_pointer_grab (display, serial); + + if (l == NULL) + return FALSE; + + grab = l->data; + if (grab && + (if_child == NULL || + is_parent_of (grab->window, if_child))) + { + grab->serial_end = serial; + grab->implicit_ungrab = implicit; + return l->next == NULL; + } + + return FALSE; } void @@ -1055,14 +1261,18 @@ gdk_pointer_grab_info_libgtk_only (GdkDisplay *display, GdkWindow **grab_window, gboolean *owner_events) { + GdkPointerGrabInfo *info; + g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE); - if (display->pointer_grab.window) + info = _gdk_display_get_active_pointer_grab (display); + + if (info) { if (grab_window) - *grab_window = (GdkWindow *)display->pointer_grab.window; + *grab_window = info->window; if (owner_events) - *owner_events = display->pointer_grab.owner_events; + *owner_events = info->owner_events; return TRUE; } @@ -1084,10 +1294,13 @@ gdk_pointer_grab_info_libgtk_only (GdkDisplay *display, gboolean gdk_display_pointer_is_grabbed (GdkDisplay *display) { - g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE); + GdkPointerGrabInfo *info; - return (display->pointer_grab.window != NULL && - !display->pointer_grab.implicit); + g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE); + + info = _gdk_display_get_active_pointer_grab (display); + + return (info && !info->implicit); } #define __GDK_DISPLAY_C__ diff --git a/gdk/gdkdisplay.h b/gdk/gdkdisplay.h index c3a7d62a66..3c7bde322f 100644 --- a/gdk/gdkdisplay.h +++ b/gdk/gdkdisplay.h @@ -43,21 +43,6 @@ typedef struct _GdkDisplayPointerHooks GdkDisplayPointerHooks; #define GDK_IS_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_DISPLAY)) #define GDK_DISPLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_DISPLAY, GdkDisplayClass)) -/* Tracks information about the pointer grab on this display */ -typedef struct -{ - GdkWindow *window; - GdkWindow *native_window; - gulong serial; - gboolean owner_events; - guint event_mask; - gboolean implicit; - gboolean converted_implicit; - guint32 time; - - GdkWindow *grab_one_pointer_release_event; -} GdkPointerGrabInfo; - /* Tracks information about the keyboard grab on this display */ typedef struct { @@ -68,7 +53,6 @@ typedef struct guint32 time; } GdkKeyboardGrabInfo; - /* Tracks information about which window and position the pointer last was in. * This is useful when we need to synthesize events later. * Note that we track toplevel_under_pointer using enter/leave events, @@ -112,9 +96,12 @@ struct _GdkDisplay gint button_x[2]; /* The last 2 button click positions. */ gint button_y[2]; - GdkPointerGrabInfo pointer_grab; + GList *pointer_grabs; GdkKeyboardGrabInfo keyboard_grab; GdkPointerWindowInfo pointer_info; + + /* Last reported event time from server */ + guint32 last_event_time; }; struct _GdkDisplayClass diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index dc7fec8c93..33822365ac 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -170,6 +170,24 @@ struct _GdkEventPrivate gpointer windowing_data; }; +/* Tracks information about the pointer grab on this display */ +typedef struct +{ + GdkWindow *window; + GdkWindow *native_window; + gulong serial_start; + gulong serial_end; /* exclusive, i.e. not active on serial_end */ + gboolean owner_events; + guint event_mask; + gboolean implicit; + gboolean converted_implicit; + guint32 time; + + gboolean activated; + gboolean implicit_ungrab; + gboolean grab_one_pointer_release_event; +} GdkPointerGrabInfo; + extern GdkEventFunc _gdk_event_func; /* Callback for events */ extern gpointer _gdk_event_data; extern GDestroyNotify _gdk_event_notify; @@ -464,18 +482,24 @@ char *_gdk_windowing_get_startup_notify_id (GAppLaunchContext *context, void _gdk_windowing_launch_failed (GAppLaunchContext *context, const char *startup_notify_id); -void _gdk_display_set_has_pointer_grab (GdkDisplay *display, - GdkWindow *window, - GdkWindow *native_window, - gboolean owner_events, - GdkEventMask event_mask, - unsigned long serial, - guint32 time, +GdkPointerGrabInfo *_gdk_display_get_active_pointer_grab (GdkDisplay *display); +void _gdk_display_pointer_grab_update (GdkDisplay *display, + gulong current_serial); +GdkPointerGrabInfo *_gdk_display_get_last_pointer_grab (GdkDisplay *display); +GdkPointerGrabInfo *_gdk_display_add_pointer_grab (GdkDisplay *display, + GdkWindow *window, + GdkWindow *native_window, + gboolean owner_events, + GdkEventMask event_mask, + unsigned long serial_start, + guint32 time, + gboolean implicit); +GdkPointerGrabInfo * _gdk_display_has_pointer_grab (GdkDisplay *display, + gulong serial); +gboolean _gdk_display_end_pointer_grab (GdkDisplay *display, + gulong serial, + GdkWindow *if_child, gboolean implicit); -void _gdk_display_unset_has_pointer_grab (GdkDisplay *display, - gboolean implicit, - gboolean do_grab_one_pointer_release_event, - guint32 time); void _gdk_display_set_has_keyboard_grab (GdkDisplay *display, GdkWindow *window, GdkWindow *native_window, @@ -518,7 +542,8 @@ void _gdk_syntesize_crossing_events (GdkDisplay *display, gint toplevel_y, GdkModifierType mask, guint32 time_, - GdkEvent *event_in_queue); + GdkEvent *event_in_queue, + gulong serial); void _gdk_display_set_window_under_pointer (GdkDisplay *display, GdkWindow *window); diff --git a/gdk/gdkoffscreenwindow.c b/gdk/gdkoffscreenwindow.c index 703dcfa7ff..69126537db 100644 --- a/gdk/gdkoffscreenwindow.c +++ b/gdk/gdkoffscreenwindow.c @@ -851,7 +851,9 @@ gdk_offscreen_window_hide (GdkWindow *window) /* May need to break grabs on children */ display = gdk_drawable_get_display (window); - + + /* TODO: This needs updating to the new grab world */ +#if 0 if (display->pointer_grab.window != NULL) { if (is_parent_of (window, display->pointer_grab.window)) @@ -866,6 +868,7 @@ gdk_offscreen_window_hide (GdkWindow *window) gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME); } } +#endif } static void diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 102fc903e7..604febac62 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -5725,20 +5725,11 @@ gdk_window_hide (GdkWindow *window) /* May need to break grabs on children */ display = gdk_drawable_get_display (window); - if (display->pointer_grab.window != NULL) - { - if (is_parent_of (window, display->pointer_grab.window)) - { - /* Call this ourselves, even though gdk_display_pointer_ungrab - does so too, since we want to pass implicit == TRUE so the - broken grab event is generated */ - _gdk_display_unset_has_pointer_grab (display, - TRUE, - FALSE, - GDK_CURRENT_TIME); - gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME); - } - } + if (_gdk_display_end_pointer_grab (display, + _gdk_windowing_window_get_next_serial (display), + window, + TRUE)) + gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME); if (display->keyboard_grab.window != NULL) { @@ -6561,6 +6552,7 @@ static void update_cursor (GdkDisplay *display) { GdkWindowObject *pointer_window, *cursor_window; + GdkPointerGrabInfo *grab; pointer_window = (GdkWindowObject *)display->pointer_info.window_under_pointer; @@ -6570,14 +6562,18 @@ update_cursor (GdkDisplay *display) cursor_window->parent->window_type != GDK_WINDOW_ROOT) cursor_window = cursor_window->parent; - if (display->pointer_grab.window != NULL && - !is_parent_of (display->pointer_grab.window, (GdkWindow *)cursor_window)) - cursor_window = (GdkWindowObject *)display->pointer_grab.window; + /* We ignore the serials here and just pick the last grab + we've sent, as that would shortly be used anyway. */ + grab = _gdk_display_get_last_pointer_grab (display); + if (grab != NULL && + !is_parent_of (grab->window, (GdkWindow *)cursor_window)) + cursor_window = (GdkWindowObject *)grab->window; /* Set all cursors on toplevel, otherwise its tricky to keep track of * which native window has what cursor set. */ - GDK_WINDOW_IMPL_GET_IFACE (pointer_window->impl)->set_cursor (gdk_window_get_toplevel ((GdkWindow *)pointer_window), - cursor_window->cursor); + GDK_WINDOW_IMPL_GET_IFACE (pointer_window->impl)->set_cursor + (gdk_window_get_toplevel ((GdkWindow *)pointer_window), + cursor_window->cursor); } /** @@ -7869,14 +7865,18 @@ send_crossing_event (GdkDisplay *display, gint toplevel_y, GdkModifierType mask, guint32 time_, - GdkEvent *event_in_queue) + GdkEvent *event_in_queue, + gulong serial) { GdkEvent *event; guint32 event_mask; - - if (display->pointer_grab.window != NULL && - !display->pointer_grab.owner_events && - (GdkWindow *)window != display->pointer_grab.window) + GdkPointerGrabInfo *grab; + + grab = _gdk_display_has_pointer_grab (display, serial); + + if (grab != NULL && + !grab->owner_events && + (GdkWindow *)window != grab->window) return; if (type == GDK_LEAVE_NOTIFY) @@ -7918,7 +7918,8 @@ _gdk_syntesize_crossing_events (GdkDisplay *display, gint toplevel_y, GdkModifierType mask, guint32 time_, - GdkEvent *event_in_queue) + GdkEvent *event_in_queue, + gulong serial) { GdkWindowObject *c; GdkWindowObject *win, *last, *next; @@ -7958,7 +7959,8 @@ _gdk_syntesize_crossing_events (GdkDisplay *display, NULL, toplevel_x, toplevel_y, mask, time_, - event_in_queue); + event_in_queue, + serial); if (c != a) { @@ -7978,7 +7980,8 @@ _gdk_syntesize_crossing_events (GdkDisplay *display, (GdkWindow *)last, toplevel_x, toplevel_y, mask, time_, - event_in_queue); + event_in_queue, + serial); last = win; win = win->parent; @@ -8023,7 +8026,8 @@ _gdk_syntesize_crossing_events (GdkDisplay *display, (GdkWindow *)next, toplevel_x, toplevel_y, mask, time_, - event_in_queue); + event_in_queue, + serial); } g_list_free (path); } @@ -8043,7 +8047,8 @@ _gdk_syntesize_crossing_events (GdkDisplay *display, NULL, toplevel_x, toplevel_y, mask, time_, - event_in_queue); + event_in_queue, + serial); } } @@ -8067,9 +8072,11 @@ static GdkWindow * get_pointer_window (GdkDisplay *display, GdkWindow *event_window, gdouble toplevel_x, - gdouble toplevel_y) + gdouble toplevel_y, + gulong serial) { GdkWindow *pointer_window; + GdkPointerGrabInfo *grab; if (event_window == display->pointer_info.toplevel_under_pointer) pointer_window = @@ -8079,9 +8086,10 @@ get_pointer_window (GdkDisplay *display, else pointer_window = NULL; - if (display->pointer_grab.window != NULL && - !display->pointer_grab.owner_events && - pointer_window != display->pointer_grab.window) + grab = _gdk_display_has_pointer_grab (display, serial); + if (grab != NULL && + !grab->owner_events && + pointer_window != grab->window) pointer_window = NULL; return pointer_window; @@ -8113,16 +8121,20 @@ _gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window) GdkDisplay *display; GdkWindow *changed_toplevel; GdkWindow *new_window_under_pointer; + gulong serial; + display = gdk_drawable_get_display (changed_window); + + serial = _gdk_windowing_window_get_next_serial (display); changed_toplevel = get_toplevel (changed_window); - display = gdk_drawable_get_display (changed_window); if (changed_toplevel == display->pointer_info.toplevel_under_pointer) { new_window_under_pointer = get_pointer_window (display, changed_toplevel, display->pointer_info.toplevel_x, - display->pointer_info.toplevel_y); + display->pointer_info.toplevel_y, + serial); if (new_window_under_pointer != display->pointer_info.window_under_pointer) { @@ -8134,7 +8146,8 @@ _gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window) display->pointer_info.toplevel_y, display->pointer_info.state, GDK_CURRENT_TIME, - NULL); + NULL, + serial); _gdk_display_set_window_under_pointer (display, new_window_under_pointer); } } @@ -8146,27 +8159,22 @@ get_event_window (GdkDisplay *display, GdkWindow *pointer_window, GdkEventType type, GdkModifierType mask, - guint *evmask_out) + guint *evmask_out, + gulong serial) { guint evmask; GdkWindow *grab_window; GdkWindowObject *w; + GdkPointerGrabInfo *grab; - if ((display->pointer_grab.window != NULL && !display->pointer_grab.owner_events) || - (type == GDK_BUTTON_RELEASE && display->pointer_grab.grab_one_pointer_release_event)) + grab = _gdk_display_has_pointer_grab (display, serial); + + if (grab != NULL && !grab->owner_events) { - evmask = display->pointer_grab.event_mask; + evmask = grab->event_mask; evmask = update_evmask_for_button_motion (evmask, mask); - if (type == GDK_BUTTON_RELEASE && - display->pointer_grab.grab_one_pointer_release_event) - { - grab_window = display->pointer_grab.grab_one_pointer_release_event; - display->pointer_grab.grab_one_pointer_release_event = NULL; - } - else - grab_window = display->pointer_grab.window; - + grab_window = grab->window; if (evmask & type_masks[type]) { @@ -8194,17 +8202,17 @@ get_event_window (GdkDisplay *display, w = w->parent; } - if (display->pointer_grab.window != NULL && - display->pointer_grab.owner_events) + if (grab != NULL && + grab->owner_events) { - evmask = display->pointer_grab.event_mask; + evmask = grab->event_mask; evmask = update_evmask_for_button_motion (evmask, mask); if (evmask & type_masks[type]) { if (evmask_out) *evmask_out = evmask; - return display->pointer_grab.window; + return grab->window; } else return NULL; @@ -8220,7 +8228,6 @@ proxy_pointer_event (GdkDisplay *display, { GdkWindow *toplevel_window; GdkWindow *pointer_window; - GdkWindow *cursor_window; GdkEvent *event; guint state; gdouble toplevel_x, toplevel_y; @@ -8231,7 +8238,7 @@ proxy_pointer_event (GdkDisplay *display, gdk_event_get_state (source_event, &state); time_ = gdk_event_get_time (source_event); - pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y); + pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y, serial); if (display->pointer_info.window_under_pointer != pointer_window) { /* Either a toplevel crossing notify that ended up inside a child window, @@ -8244,7 +8251,8 @@ proxy_pointer_event (GdkDisplay *display, GDK_CROSSING_NORMAL, toplevel_x, toplevel_y, state, time_, - source_event); + source_event, + serial); _gdk_display_set_window_under_pointer (display, pointer_window); } @@ -8258,7 +8266,8 @@ proxy_pointer_event (GdkDisplay *display, pointer_window, source_event->type, state, - &evmask); + &evmask, + serial); is_hint = FALSE; @@ -8291,22 +8300,14 @@ proxy_pointer_event (GdkDisplay *display, } } - /* TODO: set cursor from cursor_window, or grab cursor */ - cursor_window = pointer_window; - if (display->pointer_grab.window && - (pointer_window == NULL || - !is_parent_of (display->pointer_grab.window, pointer_window))) - cursor_window = display->pointer_grab.window; - /* Actually, this should probably happen in synthesize crossing so it works with geometry changes */ - - /* unlink all move events from queue. We handle our own, including our emulated masks. */ return TRUE; } static gboolean -proxy_button_event (GdkEvent *source_event) +proxy_button_event (GdkEvent *source_event, + gulong serial) { GdkWindow *toplevel_window; GdkWindow *event_win; @@ -8318,6 +8319,7 @@ proxy_button_event (GdkEvent *source_event) gdouble toplevel_x, toplevel_y; GdkDisplay *display; GdkWindowObject *w; + GdkPointerGrabInfo *grab; type = source_event->any.type; toplevel_window = source_event->any.window; @@ -8326,10 +8328,11 @@ proxy_button_event (GdkEvent *source_event) time_ = gdk_event_get_time (source_event); display = gdk_drawable_get_display (source_event->any.window); + grab = _gdk_display_get_active_pointer_grab (display); + if ((type == GDK_BUTTON_PRESS || type == GDK_SCROLL) && - display->pointer_grab.window == source_event->any.window && - display->pointer_grab.implicit && - !display->pointer_grab.converted_implicit) + grab && grab->window == toplevel_window && + grab->implicit && !grab->converted_implicit) { pointer_window = _gdk_window_find_descendant_at (toplevel_window, @@ -8347,25 +8350,25 @@ proxy_button_event (GdkEvent *source_event) pointer_window = (GdkWindow *)w; if (pointer_window != NULL && - pointer_window != source_event->any.window) - _gdk_display_set_has_pointer_grab (display, - pointer_window, - display->pointer_grab.native_window, - display->pointer_grab.owner_events, - gdk_window_get_events (pointer_window), - display->pointer_grab.serial, - display->pointer_grab.time, - display->pointer_grab.implicit); - display->pointer_grab.converted_implicit = TRUE; + pointer_window != toplevel_window) + { + g_object_ref (pointer_window); + g_object_unref (grab->window); + grab->window = pointer_window; + grab->event_mask = gdk_window_get_events (pointer_window); + } + + grab->converted_implicit = TRUE; } - pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y); + pointer_window = get_pointer_window (display, toplevel_window, + toplevel_x, toplevel_y, + serial); event_win = get_event_window (display, pointer_window, - type, - state, - NULL); + type, state, + NULL, serial); if (event_win == NULL) return TRUE; @@ -8478,7 +8481,14 @@ _gdk_windowing_got_event (GdkDisplay *display, gdouble x, y; gboolean unlink_event; guint old_state, old_button; + GdkPointerGrabInfo *button_release_grab; + if (gdk_event_get_time (event) != GDK_CURRENT_TIME) + display->last_event_time = gdk_event_get_time (event); + + _gdk_display_pointer_grab_update (display, + serial); + event_window = event->any.window; if (!event_window) return; @@ -8559,7 +8569,22 @@ _gdk_windowing_got_event (GdkDisplay *display, event, serial); else if (is_button_type (event->type)) - unlink_event = proxy_button_event (event); + unlink_event = proxy_button_event (event, + serial); + + if (event->type == GDK_BUTTON_RELEASE) + { + button_release_grab = + _gdk_display_has_pointer_grab (display, serial); + if (button_release_grab && + button_release_grab->grab_one_pointer_release_event) + { + button_release_grab->grab_one_pointer_release_event = FALSE; + button_release_grab->serial_end = serial; + button_release_grab->implicit_ungrab = TRUE; + _gdk_display_pointer_grab_update (display, serial); + } + } if (unlink_event) { diff --git a/gdk/x11/gdkasync.c b/gdk/x11/gdkasync.c index b230c1faba..e412ed2f7e 100644 --- a/gdk/x11/gdkasync.c +++ b/gdk/x11/gdkasync.c @@ -118,6 +118,7 @@ struct _RoundtripState Display *dpy; _XAsyncHandler async; gulong get_input_focus_req; + GdkDisplay *display; GdkRoundTripCallback callback; gpointer data; }; @@ -758,7 +759,7 @@ roundtrip_callback_idle (gpointer data) { RoundtripState *state = (RoundtripState *)data; - state->callback (state->data); + state->callback (state->display, state->data, state->get_input_focus_req); g_free (state); @@ -790,6 +791,7 @@ roundtrip_handler (Display *dpy, True); } + if (state->callback) gdk_threads_add_idle (roundtrip_callback_idle, state); @@ -813,6 +815,7 @@ _gdk_x11_roundtrip_async (GdkDisplay *display, state = g_new (RoundtripState, 1); + state->display = display; state->dpy = dpy; state->callback = callback; state->data = data; diff --git a/gdk/x11/gdkasync.h b/gdk/x11/gdkasync.h index 407e3c8473..44aa18c47c 100644 --- a/gdk/x11/gdkasync.h +++ b/gdk/x11/gdkasync.h @@ -31,8 +31,9 @@ typedef struct _GdkChildInfoX11 GdkChildInfoX11; typedef void (*GdkSendXEventCallback) (Window window, gboolean success, gpointer data); -typedef void (*GdkRoundTripCallback) (gpointer data); - +typedef void (*GdkRoundTripCallback) (GdkDisplay *display, + gpointer data, + gulong serial); struct _GdkChildInfoX11 { diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index a05bc511ce..a517404e1e 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -598,16 +598,11 @@ struct XPointerUngrabInfo { }; static void -pointer_ungrab_callback (gpointer _data) +pointer_ungrab_callback (GdkDisplay *display, + gpointer data, + gulong serial) { - struct XPointerUngrabInfo *data = _data; - - _gdk_display_unset_has_pointer_grab (data->display, - FALSE, - FALSE, - data->time); - - g_free (data); + _gdk_display_pointer_grab_update (display, serial); } @@ -631,30 +626,30 @@ gdk_display_pointer_ungrab (GdkDisplay *display, { Display *xdisplay; GdkDisplayX11 *display_x11; + GdkPointerGrabInfo *grab; + unsigned long serial; g_return_if_fail (GDK_IS_DISPLAY (display)); display_x11 = GDK_DISPLAY_X11 (display); xdisplay = GDK_DISPLAY_XDISPLAY (display); + + serial = NextRequest (xdisplay); _gdk_input_ungrab_pointer (display, time_); XUngrabPointer (xdisplay, time_); XFlush (xdisplay); - if (time_ == GDK_CURRENT_TIME || - display->pointer_grab.time == GDK_CURRENT_TIME || - !XSERVER_TIME_IS_LATER (display->pointer_grab.time, time_)) + grab = _gdk_display_get_last_pointer_grab (display); + if (grab && + (time_ == GDK_CURRENT_TIME || + grab->time == GDK_CURRENT_TIME || + !XSERVER_TIME_IS_LATER (grab->time, time_))) { - struct XPointerUngrabInfo *data; - - data = g_new (struct XPointerUngrabInfo, 1); - - data->display = GDK_DISPLAY_OBJECT (display_x11); - data->time = time_; - - _gdk_x11_roundtrip_async (data->display, + grab->serial_end = serial; + _gdk_x11_roundtrip_async (display, pointer_ungrab_callback, - data); + NULL); } } diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c index 617e87dc10..01ed9b65c5 100644 --- a/gdk/x11/gdkevents-x11.c +++ b/gdk/x11/gdkevents-x11.c @@ -2207,7 +2207,7 @@ gdk_event_translate (GdkDisplay *display, if (window) g_object_unref (window); - + return return_val; } diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c index aa11db38d0..b06b15e699 100644 --- a/gdk/x11/gdkmain-x11.c +++ b/gdk/x11/gdkmain-x11.c @@ -149,22 +149,11 @@ struct XPointerGrabInfo { }; static void -has_pointer_grab_callback (gpointer _data) +has_pointer_grab_callback (GdkDisplay *display, + gpointer data, + gulong serial) { - struct XPointerGrabInfo *data = _data; - - _gdk_display_set_has_pointer_grab (data->display, - data->window, - data->native_window, - data->owner_events, - data->event_mask, - data->serial, - data->time, - FALSE); - - g_object_unref (data->window); - g_object_unref (data->native_window); - g_free (data); + _gdk_display_pointer_grab_update (display, serial); } /* @@ -215,9 +204,17 @@ gdk_pointer_grab (GdkWindow * window, native = gdk_window_get_toplevel (window); + /* We need a native window for confine to to work, ensure we have one */ + if (confine_to) + gdk_window_set_has_native (confine_to, TRUE); + /* TODO: What do we do for offscreens and their children? We need to proxy the grab somehow */ if (!GDK_IS_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (native)->impl)) return GDK_GRAB_SUCCESS; + + if (!_gdk_window_has_impl (window) && + !gdk_window_is_viewable (window)) + return GDK_GRAB_NOT_VIEWABLE; if (confine_to) confine_to = _gdk_window_get_impl_window (confine_to); @@ -285,21 +282,18 @@ gdk_pointer_grab (GdkWindow * window, if (return_val == GrabSuccess) { - struct XPointerGrabInfo *data; + _gdk_display_add_pointer_grab (GDK_DISPLAY_OBJECT (display_x11), + window, + native, + owner_events, + event_mask, + serial, + time, + FALSE); - data = g_new (struct XPointerGrabInfo, 1); - - data->display = GDK_DISPLAY_OBJECT (display_x11); - data->window = g_object_ref (window); - data->native_window = g_object_ref (native); - data->owner_events = owner_events; - data->event_mask = event_mask; - data->serial = serial; - data->time = time; - - _gdk_x11_roundtrip_async (data->display, + _gdk_x11_roundtrip_async (GDK_DISPLAY_OBJECT (display_x11), has_pointer_grab_callback, - data); + NULL); } return gdk_x11_convert_grab_status (return_val); @@ -394,19 +388,8 @@ _gdk_xgrab_check_unmap (GdkWindow *window, gulong serial) { GdkDisplay *display = gdk_drawable_get_display (window); - - if (display->pointer_grab.window && - serial >= display->pointer_grab.serial) - { - GdkWindowObject *private = GDK_WINDOW_OBJECT (window); - GdkWindowObject *tmp = GDK_WINDOW_OBJECT (display->pointer_grab.native_window); - while (tmp && tmp != private) - tmp = tmp->parent; - - if (tmp) - _gdk_display_unset_has_pointer_grab (display, TRUE, FALSE, GDK_CURRENT_TIME); - } + _gdk_display_end_pointer_grab (display, serial, window, TRUE); if (display->keyboard_grab.window && serial >= display->keyboard_grab.serial) @@ -433,11 +416,21 @@ void _gdk_xgrab_check_destroy (GdkWindow *window) { GdkDisplay *display = gdk_drawable_get_display (window); - - if (window == display->pointer_grab.native_window && - display->pointer_grab.window != NULL) - _gdk_display_unset_has_pointer_grab (display, TRUE, FALSE, GDK_CURRENT_TIME); + GdkPointerGrabInfo *grab; + /* Make sure there is no lasting grab in this native + window */ + grab = _gdk_display_get_last_pointer_grab (display); + if (grab && grab->native_window == window) + { + /* We don't know the actual serial to end, but it + doesn't really matter as this only happens + after we get told of the destroy from the + server so we know its ended in the server, + just make sure its ended. */ + grab->serial_end = grab->serial_start; + } + if (window == display->keyboard_grab.native_window && display->keyboard_grab.window != NULL) _gdk_display_unset_has_keyboard_grab (display, TRUE); @@ -461,31 +454,31 @@ _gdk_xgrab_check_button_event (GdkWindow *window, XEvent *xevent) { GdkDisplay *display = gdk_drawable_get_display (window); + gulong serial = xevent->xany.serial; + GdkPointerGrabInfo *grab; /* track implicit grabs for button presses */ switch (xevent->type) { case ButtonPress: - if (!display->pointer_grab.window) + if (!_gdk_display_has_pointer_grab (display, serial)) { - _gdk_display_set_has_pointer_grab (display, - window, - window, - FALSE, - gdk_window_get_events (window), - xevent->xany.serial, - xevent->xbutton.time, - TRUE); + _gdk_display_add_pointer_grab (display, + window, + window, + FALSE, + gdk_window_get_events (window), + serial, + xevent->xbutton.time, + TRUE); } break; case ButtonRelease: - if (display->pointer_grab.window && - display->pointer_grab.implicit && + serial = serial; + grab = _gdk_display_has_pointer_grab (display, serial); + if (grab && grab->implicit && (xevent->xbutton.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (xevent->xbutton.button - 1))) == 0) - { - _gdk_display_unset_has_pointer_grab (display, TRUE, TRUE, - xevent->xbutton.time); - } + grab->grab_one_pointer_release_event = TRUE; break; default: g_assert_not_reached ();