[gtk/wip/carlosg/input-cleanups: 21/26] gtkmain: Make grab-notify notifications more targeted



commit ddb3a4be3e7b993208a08bd72080bda3c53ff172
Author: Carlos Garnacho <carlosg gnome org>
Date:   Wed Jun 24 17:19:57 2020 +0200

    gtkmain: Make grab-notify notifications more targeted
    
    We only want to send grab-notify to widgets that might have been
    interacting with devices via events. Instead of going through all
    widgets in all toplevels, we have the window/pointer focus information,
    so we can just traverse the widget stacks for every involved foci.

 gtk/gtkmain.c          | 129 ++-----------------------------------------------
 gtk/gtkwindow.c        | 103 +++++++++++++++++++++++++++++++++++++++
 gtk/gtkwindowprivate.h |   4 ++
 3 files changed, 111 insertions(+), 125 deletions(-)
---
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
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]