[gtk+] Use GDK's current window tracking when synthesizing events in GTK+



commit 40b6d907bf0e22fbb5cbb0ff91cada8f3264fc28
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Wed Mar 12 12:39:03 2014 -0400

    Use GDK's current window tracking when synthesizing events in GTK+
    
    Add gdk_device_get_last_event_window(), and use to implement the window
    tracking we need for synthesizing crossing events for sensitivity changes
    and gtk grabs, rather than keeping the information in qdata and updating
    it based when GTK+ gets events.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=726187

 docs/reference/gdk/gdk3-sections.txt |    1 +
 gdk/gdkdevice.c                      |   27 ++++++++
 gdk/gdkdevice.h                      |    2 +
 gtk/gtkmain.c                        |   10 ---
 gtk/gtkwidget.c                      |  109 +++++++++++++---------------------
 5 files changed, 71 insertions(+), 78 deletions(-)
---
diff --git a/docs/reference/gdk/gdk3-sections.txt b/docs/reference/gdk/gdk3-sections.txt
index d23183a..51963aa 100644
--- a/docs/reference/gdk/gdk3-sections.txt
+++ b/docs/reference/gdk/gdk3-sections.txt
@@ -736,6 +736,7 @@ GdkTimeCoord
 gdk_device_get_axis
 gdk_device_list_axes
 gdk_device_get_axis_value
+gdk_device_get_last_event_window
 
 <SUBSECTION Standard>
 GDK_TYPE_AXIS_USE
diff --git a/gdk/gdkdevice.c b/gdk/gdkdevice.c
index 9508a7b..24499d7 100644
--- a/gdk/gdkdevice.c
+++ b/gdk/gdkdevice.c
@@ -1717,3 +1717,30 @@ _gdk_device_window_at_position (GdkDevice        *device,
                                                             mask,
                                                             get_toplevel);
 }
+
+/**
+ * gdk_device_get_last_event_window:
+ * @device: a #GdkDevice, with a source other than %GDK_SOURCE_KEYBOARD
+ *
+ * Gets information about which window the given pointer device is in, based on
+ * that have been received so far from the display server. If another application
+ * has a pointer grab, or this application has a grab with owner_events = %FALSE,
+ * %NULL may be returned even if the pointer is physically over one of this
+ * application's windows.
+ *
+ * Returns: (transfer none) (allow-none): the last window the device
+ */
+GdkWindow *
+gdk_device_get_last_event_window (GdkDevice *device)
+{
+  GdkDisplay *display;
+  GdkPointerWindowInfo *info;
+
+  g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
+  g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, NULL);
+
+  display = gdk_device_get_display (device);
+  info = _gdk_display_get_pointer_info (display, device);
+
+  return info->window_under_pointer;
+}
diff --git a/gdk/gdkdevice.h b/gdk/gdkdevice.h
index a67f4b5..23b3551 100644
--- a/gdk/gdkdevice.h
+++ b/gdk/gdkdevice.h
@@ -271,6 +271,8 @@ gboolean gdk_device_grab_info_libgtk_only (GdkDisplay  *display,
                                            GdkWindow  **grab_window,
                                            gboolean    *owner_events);
 
+GDK_AVAILABLE_IN_3_12
+GdkWindow *gdk_device_get_last_event_window (GdkDevice *device);
 
 G_END_DECLS
 
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index c3367e1..9e8fea5 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1736,22 +1736,12 @@ gtk_main_do_event (GdkEvent *event)
       break;
 
     case GDK_ENTER_NOTIFY:
-      if (event->crossing.detail != GDK_NOTIFY_VIRTUAL &&
-          event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
-        _gtk_widget_set_device_window (event_widget,
-                                       gdk_event_get_device (event),
-                                       event->any.window);
       if (gtk_widget_is_sensitive (grab_widget) &&
           !_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
         gtk_widget_event (grab_widget, event);
       break;
 
     case GDK_LEAVE_NOTIFY:
-      if (event->crossing.detail != GDK_NOTIFY_VIRTUAL &&
-          event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
-        _gtk_widget_set_device_window (event_widget,
-                                       gdk_event_get_device (event),
-                                       NULL);
       if (gtk_widget_is_sensitive (grab_widget) &&
           !_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
         gtk_widget_event (grab_widget, event);
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 5c691a1..5488c66 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -855,7 +855,6 @@ static GQuark               quark_accel_closures = 0;
 static GQuark          quark_event_mask = 0;
 static GQuark           quark_device_event_mask = 0;
 static GQuark          quark_parent_window = 0;
-static GQuark          quark_pointer_window = 0;
 static GQuark          quark_shape_info = 0;
 static GQuark          quark_input_shape_info = 0;
 static GQuark          quark_pango_context = 0;
@@ -1022,7 +1021,6 @@ gtk_widget_class_init (GtkWidgetClass *klass)
   quark_event_mask = g_quark_from_static_string ("gtk-event-mask");
   quark_device_event_mask = g_quark_from_static_string ("gtk-device-event-mask");
   quark_parent_window = g_quark_from_static_string ("gtk-parent-window");
-  quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window");
   quark_shape_info = g_quark_from_static_string ("gtk-shape-info");
   quark_input_shape_info = g_quark_from_static_string ("gtk-input-shape-info");
   quark_pango_context = g_quark_from_static_string ("gtk-pango-context");
@@ -4627,9 +4625,6 @@ gtk_widget_unmap (GtkWidget *widget)
       g_signal_emit (widget, widget_signals[UNMAP], 0);
 
       gtk_widget_pop_verify_invariants (widget);
-
-      /* Unset pointer/window info */
-      g_object_set_qdata (G_OBJECT (widget), quark_pointer_window, NULL);
     }
 }
 
@@ -11780,49 +11775,14 @@ _gtk_widget_peek_request_cache (GtkWidget *widget)
   return &widget->priv->requests;
 }
 
-/*
- * _gtk_widget_set_device_window:
- * @widget: a #GtkWidget
- * @device: a #GdkDevice
- * @window: the new device window
- *
- * Sets pointer window for @widget and @device.
- * Does not ref @window.
- */
-void
-_gtk_widget_set_device_window (GtkWidget *widget,
-                               GdkDevice *device,
-                               GdkWindow *window)
+static gboolean
+is_my_window (GtkWidget *widget,
+              GdkWindow *window)
 {
-  GHashTable *device_window;
-
-  g_return_if_fail (GTK_IS_WIDGET (widget));
-  g_return_if_fail (GDK_IS_DEVICE (device));
-  g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
-
-  if (!gtk_widget_get_mapped (widget))
-    return;
-
-  device_window = g_object_get_qdata (G_OBJECT (widget), quark_pointer_window);
-
-  if (!device_window && window)
-    {
-      device_window = g_hash_table_new (NULL, NULL);
-      g_object_set_qdata_full (G_OBJECT (widget),
-                               quark_pointer_window,
-                               device_window,
-                               (GDestroyNotify) g_hash_table_destroy);
-    }
-
-  if (window)
-    g_hash_table_insert (device_window, device, window);
-  else if (device_window)
-    {
-      g_hash_table_remove (device_window, device);
+  gpointer user_data;
 
-      if (g_hash_table_size (device_window) == 0)
-        g_object_set_qdata (G_OBJECT (widget), quark_pointer_window, NULL);
-    }
+  gdk_window_get_user_data (window, &user_data);
+  return (user_data == widget);
 }
 
 /*
@@ -11830,26 +11790,44 @@ _gtk_widget_set_device_window (GtkWidget *widget,
  * @widget: a #GtkWidget
  * @device: a #GdkDevice
  *
- * Returns: the device window set on @widget, or %NULL
+ * Returns: the window of @widget that @device is in, or %NULL
  */
 GdkWindow *
 _gtk_widget_get_device_window (GtkWidget *widget,
                                GdkDevice *device)
 {
-  GHashTable *device_window;
+  GdkWindow *window;
 
   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
 
-  if (!gtk_widget_get_mapped (widget))
+  window = gdk_device_get_last_event_window (device);
+  if (window && is_my_window (widget, window))
+    return window;
+  else
     return NULL;
+}
 
-  device_window = g_object_get_qdata (G_OBJECT (widget), quark_pointer_window);
-
-  if (!device_window)
-    return NULL;
+static void
+list_devices (GtkWidget        *widget,
+              GdkDeviceManager *device_manager,
+              GdkDeviceType     device_type,
+              GList           **result)
+{
+  GList *devices = gdk_device_manager_list_devices (device_manager, device_type);
+  GList *l;
 
-  return g_hash_table_lookup (device_window, device);
+  for (l = devices; l; l = l->next)
+    {
+      GdkDevice *device = l->data;
+      if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
+        {
+          GdkWindow *window = gdk_device_get_last_event_window (device);
+          if (window && is_my_window (widget, window))
+            *result = g_list_prepend (*result, device);
+        }
+    }
+  g_list_free (devices);
 }
 
 /*
@@ -11864,27 +11842,22 @@ _gtk_widget_get_device_window (GtkWidget *widget,
 GList *
 _gtk_widget_list_devices (GtkWidget *widget)
 {
-  GHashTableIter iter;
-  GHashTable *device_window;
-  GList *devices = NULL;
-  gpointer key, value;
+  GdkDisplay *display;
+  GdkDeviceManager *device_manager;
+  GList *result = NULL;
 
   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
 
+  display = gtk_widget_get_display (widget);
+  device_manager = gdk_display_get_device_manager (display);
   if (!gtk_widget_get_mapped (widget))
     return NULL;
 
-  device_window = g_object_get_qdata (G_OBJECT (widget), quark_pointer_window);
+  list_devices (widget, device_manager, GDK_DEVICE_TYPE_MASTER, &result);
+  /* Rare, but we can get events for grabbed slave devices */
+  list_devices (widget, device_manager, GDK_DEVICE_TYPE_SLAVE, &result);
 
-  if (G_UNLIKELY (!device_window))
-    return NULL;
-
-  g_hash_table_iter_init (&iter, device_window);
-
-  while (g_hash_table_iter_next (&iter, &key, &value))
-    devices = g_list_prepend (devices, key);
-
-  return devices;
+  return result;
 }
 
 static void


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