diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index dd1aae99cf..9f845a4866 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -1859,120 +1859,6 @@ gtk_main_get_window_group (GtkWidget *widget) return gtk_window_get_group (NULL); } -typedef struct -{ - GtkWidget *old_grab_widget; - GtkWidget *new_grab_widget; - gboolean was_grabbed; - gboolean is_grabbed; - gboolean from_grab; - GList *notified_surfaces; -} GrabNotifyInfo; - -static void -synth_crossing_for_grab_notify (GtkWidget *from, - GtkWidget *to, - GrabNotifyInfo *info, - GdkDevice **devices, - guint n_devices, - GdkCrossingMode mode) -{ - guint i; - - for (i = 0; i < n_devices; i++) - { - GdkDevice *device = devices[i]; - GdkSurface *from_surface, *to_surface; - - if (!from) - from_surface = NULL; - else - from_surface = gtk_native_get_surface (gtk_widget_get_native (from)); - - if (!to) - to_surface = NULL; - else - to_surface = gtk_native_get_surface (gtk_widget_get_native (to)); - - if (from_surface || to_surface) - { - _gtk_widget_synthesize_crossing ((from_surface) ? from : NULL, - (to_surface) ? to : NULL, - device, mode); - - if (from_surface) - info->notified_surfaces = g_list_prepend (info->notified_surfaces, from_surface); - - if (to_surface) - info->notified_surfaces = g_list_prepend (info->notified_surfaces, to_surface); - } - } -} - -static void -gtk_grab_notify_foreach (GtkWidget *child, - gpointer data) -{ - GrabNotifyInfo *info = data; - gboolean was_grabbed, is_grabbed, was_shadowed, is_shadowed; - GdkDevice **devices; - guint n_devices; - - was_grabbed = info->was_grabbed; - is_grabbed = info->is_grabbed; - - info->was_grabbed = info->was_grabbed || (child == info->old_grab_widget); - info->is_grabbed = info->is_grabbed || (child == info->new_grab_widget); - - was_shadowed = info->old_grab_widget && !info->was_grabbed; - is_shadowed = info->new_grab_widget && !info->is_grabbed; - - g_object_ref (child); - - if (was_shadowed || is_shadowed) - { - GtkWidget *p; - - for (p = _gtk_widget_get_first_child (child); - p != NULL; - p = _gtk_widget_get_next_sibling (p)) - { - gtk_grab_notify_foreach (p, info); - } - } - - devices = _gtk_widget_list_devices (child, &n_devices); - - if (is_shadowed) - { - _gtk_widget_set_shadowed (child, TRUE); - if (!was_shadowed && devices && - gtk_widget_is_sensitive (child)) - synth_crossing_for_grab_notify (child, info->new_grab_widget, - info, devices, n_devices, - GDK_CROSSING_GTK_GRAB); - } - else - { - _gtk_widget_set_shadowed (child, FALSE); - if (was_shadowed && devices && - gtk_widget_is_sensitive (child)) - synth_crossing_for_grab_notify (info->old_grab_widget, child, - info, devices, n_devices, - info->from_grab ? GDK_CROSSING_GTK_GRAB : - GDK_CROSSING_GTK_UNGRAB); - } - - if (was_shadowed != is_shadowed) - _gtk_widget_grab_notify (child, was_shadowed); - - g_object_unref (child); - g_free (devices); - - info->was_grabbed = was_grabbed; - info->is_grabbed = is_grabbed; -} - static void gtk_grab_notify (GtkWindowGroup *group, GtkWidget *old_grab_widget, @@ -1980,15 +1866,10 @@ gtk_grab_notify (GtkWindowGroup *group, gboolean from_grab) { GList *toplevels; - GrabNotifyInfo info = { 0 }; if (old_grab_widget == new_grab_widget) return; - info.old_grab_widget = old_grab_widget; - info.new_grab_widget = new_grab_widget; - info.from_grab = from_grab; - g_object_ref (group); toplevels = gtk_window_list_toplevels (); @@ -1999,15 +1880,13 @@ gtk_grab_notify (GtkWindowGroup *group, GtkWindow *toplevel = toplevels->data; toplevels = g_list_delete_link (toplevels, toplevels); - info.was_grabbed = FALSE; - info.is_grabbed = FALSE; - - if (group == gtk_window_get_group (toplevel)) - gtk_grab_notify_foreach (GTK_WIDGET (toplevel), &info); + gtk_window_grab_notify (toplevel, + old_grab_widget, + new_grab_widget, + from_grab); g_object_unref (toplevel); } - g_list_free (info.notified_surfaces); g_object_unref (group); } diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index c9d3bfd33f..aeeb383088 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -7221,3 +7221,106 @@ gtk_window_get_foci_on_widget (GtkWindow *window, return (GdkDevice**) g_ptr_array_free (array, FALSE); } + +static void +gtk_grab_notify_foreach (GtkWidget *child, + GdkDevice *device, + GtkWidget *new_grab_widget, + GtkWidget *old_grab_widget, + gboolean from_grab, + gboolean was_shadowed, + gboolean is_shadowed) +{ + g_object_ref (child); + + if (is_shadowed) + { + _gtk_widget_set_shadowed (child, TRUE); + if (!was_shadowed && + gtk_widget_is_sensitive (child)) + _gtk_widget_synthesize_crossing (child, + new_grab_widget, + device, + GDK_CROSSING_GTK_GRAB); + } + else + { + _gtk_widget_set_shadowed (child, FALSE); + if (was_shadowed && + gtk_widget_is_sensitive (child)) + _gtk_widget_synthesize_crossing (old_grab_widget, child, + device, + from_grab ? GDK_CROSSING_GTK_GRAB : + GDK_CROSSING_GTK_UNGRAB); + } + + _gtk_widget_grab_notify (child, was_shadowed); + + g_object_unref (child); +} + +static void +gtk_window_propagate_grab_notify (GtkWindow *window, + GtkWidget *target, + GdkDevice *device, + GtkWidget *old_grab_widget, + GtkWidget *new_grab_widget, + gboolean from_grab) +{ + GList *l, *widgets = NULL; + gboolean was_grabbed = FALSE, is_grabbed = FALSE; + + while (target) + { + widgets = g_list_prepend (widgets, g_object_ref (target)); + target = gtk_widget_get_parent (target); + } + + widgets = g_list_reverse (widgets); + + for (l = widgets; l; l = l->next) + { + gboolean was_shadowed, is_shadowed; + + was_grabbed |= (l->data == old_grab_widget); + is_grabbed |= (l->data == new_grab_widget); + + was_shadowed = old_grab_widget && !was_grabbed; + is_shadowed = new_grab_widget && is_grabbed; + + if (was_shadowed == is_shadowed) + break; + + gtk_grab_notify_foreach (l->data, + device, + old_grab_widget, + new_grab_widget, + from_grab, + was_shadowed, + is_shadowed); + } + + g_list_free_full (widgets, g_object_unref); +} + +void +gtk_window_grab_notify (GtkWindow *window, + GtkWidget *old_grab_widget, + GtkWidget *new_grab_widget, + gboolean from_grab) +{ + GtkWindowPrivate *priv = gtk_window_get_instance_private (window); + GList *l; + + for (l = priv->foci; l; l = l->next) + { + GtkPointerFocus *focus = l->data; + + gtk_window_propagate_grab_notify (window, + gtk_pointer_focus_get_effective_target (focus), + focus->device, + old_grab_widget, + new_grab_widget, + from_grab); + } +} diff --git a/gtk/gtkwindowprivate.h b/gtk/gtkwindowprivate.h index 14a3f8617c..4cb31c3eed 100644 --- a/gtk/gtkwindowprivate.h +++ b/gtk/gtkwindowprivate.h @@ -127,6 +127,10 @@ GtkWidget * gtk_window_pick_popover (GtkWindow *window, GdkDevice** gtk_window_get_foci_on_widget (GtkWindow *window, GtkWidget *widget, guint *n_devices); +void gtk_window_grab_notify (GtkWindow *window, + GtkWidget *old_grab_widget, + GtkWidget *new_grab_widget, + gboolean from_grab); G_END_DECLS