[gtk+/xi2: 131/148] Make GtkWidget pointer window bookkeeping multidevice-aware.



commit 5f9abb4f5d3c03eded8264ef7c46812cb1d6f2d7
Author: Carlos Garnacho <carlos gnome org>
Date:   Fri Dec 4 10:26:59 2009 +0100

    Make GtkWidget pointer window bookkeeping multidevice-aware.

 gtk/gtkmain.c    |   40 +++++++-----
 gtk/gtkprivate.h |    1 -
 gtk/gtkwidget.c  |  195 +++++++++++++++++++++++++++++++++++++----------------
 gtk/gtkwidget.h  |   10 ++-
 4 files changed, 166 insertions(+), 80 deletions(-)
---
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index 0bca3da..f44061f 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1616,14 +1616,12 @@ gtk_main_do_event (GdkEvent *event)
       break;
       
     case GDK_ENTER_NOTIFY:
-      GTK_PRIVATE_SET_FLAG (event_widget, GTK_HAS_POINTER);
-      _gtk_widget_set_pointer_window (event_widget, event->any.window);
+      _gtk_widget_set_device_window (event_widget, event->crossing.device, event->any.window);
       if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
 	gtk_widget_event (grab_widget, event);
       break;
       
     case GDK_LEAVE_NOTIFY:
-      GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_HAS_POINTER);
       if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
 	gtk_widget_event (grab_widget, event);
       break;
@@ -1703,11 +1701,10 @@ typedef struct
 static void
 gtk_grab_notify_foreach (GtkWidget *child,
 			 gpointer   data)
-                        
 {
   GrabNotifyInfo *info = data;
- 
   gboolean was_grabbed, is_grabbed, was_shadowed, is_shadowed;
+  GList *devices, *d;
 
   was_grabbed = info->was_grabbed;
   is_grabbed = info->is_grabbed;
@@ -1722,30 +1719,39 @@ gtk_grab_notify_foreach (GtkWidget *child,
 
   if ((was_shadowed || is_shadowed) && GTK_IS_CONTAINER (child))
     gtk_container_forall (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
-  
+
+  devices = _gtk_widget_list_devices (child);
+
   if (is_shadowed)
     {
       GTK_PRIVATE_SET_FLAG (child, GTK_SHADOWED);
-      if (!was_shadowed && GTK_WIDGET_HAS_POINTER (child)
-	  && GTK_WIDGET_IS_SENSITIVE (child))
-	_gtk_widget_synthesize_crossing (child, info->new_grab_widget,
-					 GDK_CROSSING_GTK_GRAB);
+      if (!was_shadowed && devices &&
+	  GTK_WIDGET_IS_SENSITIVE (child))
+        {
+          for (d = devices; d; d = d->next)
+            _gtk_widget_synthesize_crossing (child, info->new_grab_widget,
+                                             d->data, GDK_CROSSING_GTK_GRAB);
+        }
     }
   else
     {
       GTK_PRIVATE_UNSET_FLAG (child, GTK_SHADOWED);
-      if (was_shadowed && GTK_WIDGET_HAS_POINTER (child)
-	  && GTK_WIDGET_IS_SENSITIVE (child))
-	_gtk_widget_synthesize_crossing (info->old_grab_widget, child,
-					 info->from_grab ? GDK_CROSSING_GTK_GRAB
-					 : GDK_CROSSING_GTK_UNGRAB);
+      if (was_shadowed && devices &&
+	  GTK_WIDGET_IS_SENSITIVE (child))
+        {
+          for (d = devices; d; d = d->next)
+            _gtk_widget_synthesize_crossing (info->old_grab_widget, child, d->data,
+                                             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_list_free (devices);
+
   info->was_grabbed = was_grabbed;
   info->is_grabbed = is_grabbed;
 }
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index 7ba5a5d..ded69e0 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -37,7 +37,6 @@ typedef enum
 {
   PRIVATE_GTK_USER_STYLE	= 1 <<  0,
   PRIVATE_GTK_RESIZE_PENDING	= 1 <<  2,
-  PRIVATE_GTK_HAS_POINTER	= 1 <<  3,   /* If the pointer is above a window belonging to the widget */
   PRIVATE_GTK_SHADOWED		= 1 <<  4,   /* If there is a grab in effect shadowing the widget */
   PRIVATE_GTK_HAS_SHAPE_MASK	= 1 <<  5,
   PRIVATE_GTK_IN_REPARENT       = 1 <<  6,
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index a34ef25..74fcec0 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -8661,48 +8661,132 @@ _gtk_widget_peek_colormap (void)
 }
 
 /*
- * _gtk_widget_set_pointer_window:
+ * _gtk_widget_set_device_window:
  * @widget: a #GtkWidget.
- * @pointer_window: the new pointer window.
+ * @device: a #GdkDevice.
+ * @window: the new device window.
  *
- * Sets pointer window for @widget.  Does not ref @pointer_window.
+ * Sets pointer window for @widget and @device.  Does not ref @window.
  * Actually stores it on the #GdkScreen, but you don't need to know that.
  */
 void
-_gtk_widget_set_pointer_window (GtkWidget *widget,
-                                GdkWindow *pointer_window)
+_gtk_widget_set_device_window (GtkWidget *widget,
+                               GdkDevice *device,
+                               GdkWindow *window)
 {
+  GdkScreen *screen;
+  GHashTable *device_window;
+
   g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (GDK_IS_DEVICE (device));
+  g_return_if_fail (GDK_IS_WINDOW (window));
 
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      GdkScreen *screen = gdk_drawable_get_screen (widget->window);
+  if (!GTK_WIDGET_REALIZED (widget))
+    return;
 
-      g_object_set_qdata (G_OBJECT (screen), quark_pointer_window,
-                          pointer_window);
+  screen = gdk_drawable_get_screen (widget->window);
+  device_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
+
+  if (G_UNLIKELY (!device_window))
+    {
+      device_window = g_hash_table_new (NULL, NULL);
+      g_object_set_qdata_full (G_OBJECT (screen),
+                               quark_pointer_window,
+                               device_window,
+                               (GDestroyNotify) g_hash_table_destroy);
     }
+
+  g_hash_table_insert (device_window, device, window);
 }
 
 /*
- * _gtk_widget_get_pointer_window:
+ * _gtk_widget_get_device_window:
  * @widget: a #GtkWidget.
+ * @device: a #GdkDevice.
  *
- * Return value: the pointer window set on the #GdkScreen @widget is attached
+ * Return value: the device window set on the #GdkScreen @widget is attached
  * to, or %NULL.
  */
 GdkWindow *
-_gtk_widget_get_pointer_window (GtkWidget *widget)
+_gtk_widget_get_device_window (GtkWidget *widget,
+                               GdkDevice *device)
 {
+  GdkScreen *screen;
+  GHashTable *device_window;
+  GdkWindow *window;
+  GtkWidget *w;
+
   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+  g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
 
-  if (GTK_WIDGET_REALIZED (widget))
+  if (!GTK_WIDGET_REALIZED (widget))
+    return NULL;
+
+  screen = gdk_drawable_get_screen (widget->window);
+  device_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
+
+  if (G_UNLIKELY (!device_window))
+    return NULL;
+
+  window = g_hash_table_lookup (device_window, device);
+
+  if (!window)
+    return NULL;
+
+  gdk_window_get_user_data (window, (gpointer *) &w);
+
+  if (widget != w)
+    return NULL;
+
+  return window;
+}
+
+/*
+ * _gtk_widget_list_devices:
+ * @widget: a #GtkWidget.
+ *
+ * Returns the list of #GdkDevices that is currently on top of any widget #GdkWindow.
+ * Free the list with g_list_free(), the elements are owned by GTK+ and must not
+ * be freed.
+ */
+GList *
+_gtk_widget_list_devices (GtkWidget *widget)
+{
+  GdkScreen *screen;
+  GHashTableIter iter;
+  GHashTable *device_window;
+  GList *devices = NULL;
+  gpointer key, value;
+
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+
+  if (!GTK_WIDGET_REALIZED (widget))
+    return NULL;
+
+  screen = gdk_drawable_get_screen (widget->window);
+  device_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
+
+  if (G_UNLIKELY (!device_window))
+    return NULL;
+
+  g_hash_table_iter_init (&iter, device_window);
+
+  while (g_hash_table_iter_next (&iter, &key, &value))
     {
-      GdkScreen *screen = gdk_drawable_get_screen (widget->window);
+      GdkDevice *device = key;
+      GdkWindow *window = value;
+      GtkWidget *w;
 
-      return g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
+      if (window)
+        {
+          gdk_window_get_user_data (window, (gpointer *) &w);
+
+          if (widget == w)
+            devices = g_list_prepend (devices, device);
+        }
     }
 
-  return NULL;
+  return devices;
 }
 
 static void
@@ -8737,32 +8821,6 @@ synth_crossing (GtkWidget      *widget,
 }
 
 /*
- * _gtk_widget_is_pointer_widget:
- * @widget: a #GtkWidget
- *
- * Returns %TRUE if the pointer window belongs to @widget.
- */
-gboolean
-_gtk_widget_is_pointer_widget (GtkWidget *widget)
-{
-  if (GTK_WIDGET_HAS_POINTER (widget))
-    {
-      GdkWindow *win;
-      GtkWidget *wid;
-
-      win = _gtk_widget_get_pointer_window (widget);
-      if (win)
-        {
-          gdk_window_get_user_data (win, (gpointer *)&wid);
-          if (wid == widget)
-            return TRUE;
-        }
-    }
-
-  return FALSE;
-}
-
-/*
  * _gtk_widget_synthesize_crossing:
  * @from: the #GtkWidget the virtual pointer is leaving.
  * @to: the #GtkWidget the virtual pointer is moving to.
@@ -8794,20 +8852,30 @@ _gtk_widget_is_pointer_widget (GtkWidget *widget)
  *   - enter notify on real pointer window, detail Ancestor
  */
 void
-_gtk_widget_synthesize_crossing (GtkWidget      *from,
-				 GtkWidget      *to,
-				 GdkCrossingMode mode)
+_gtk_widget_synthesize_crossing (GtkWidget       *from,
+				 GtkWidget       *to,
+                                 GdkDevice       *device,
+				 GdkCrossingMode  mode)
 {
   GdkWindow *from_window = NULL, *to_window = NULL;
 
   g_return_if_fail (from != NULL || to != NULL);
 
   if (from != NULL)
-    from_window = GTK_WIDGET_HAS_POINTER (from)
-      ? _gtk_widget_get_pointer_window (from) : from->window;
+    {
+      from_window = _gtk_widget_get_device_window (from, device);
+
+      if (!from_window)
+        from_window = from->window;
+    }
+
   if (to != NULL)
-    to_window = GTK_WIDGET_HAS_POINTER (to)
-      ? _gtk_widget_get_pointer_window (to) : to->window;
+    {
+      to_window = _gtk_widget_get_device_window (to, device);
+
+      if (!to_window)
+        to_window = to->window;
+    }
 
   if (from_window == NULL && to_window == NULL)
     ;
@@ -8997,15 +9065,24 @@ gtk_widget_propagate_state (GtkWidget           *widget,
 
       g_signal_emit (widget, widget_signals[STATE_CHANGED], 0, old_state);
 
-      if (GTK_WIDGET_HAS_POINTER (widget) && !GTK_WIDGET_SHADOWED (widget))
-	{
-	  if (!GTK_WIDGET_IS_SENSITIVE (widget))
-	    _gtk_widget_synthesize_crossing (widget, NULL, 
-					     GDK_CROSSING_STATE_CHANGED);
-	  else if (old_state == GTK_STATE_INSENSITIVE)
-	    _gtk_widget_synthesize_crossing (NULL, widget, 
-					     GDK_CROSSING_STATE_CHANGED);
-	}
+      if (!GTK_WIDGET_SHADOWED (widget))
+        {
+          GList *devices, *d;
+
+          devices = _gtk_widget_list_devices (widget);
+
+          for (d = devices; d; d = d->next)
+            {
+              if (!GTK_WIDGET_IS_SENSITIVE (widget))
+                _gtk_widget_synthesize_crossing (widget, NULL, d->data,
+                                                 GDK_CROSSING_STATE_CHANGED);
+              else if (old_state == GTK_STATE_INSENSITIVE)
+                _gtk_widget_synthesize_crossing (NULL, widget, d->data,
+                                                 GDK_CROSSING_STATE_CHANGED);
+            }
+
+          g_list_free (devices);
+        }
 
       if (GTK_IS_CONTAINER (widget))
 	{
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index daa20ae..cbe0873 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -906,12 +906,16 @@ void              _gtk_widget_propagate_screen_changed    (GtkWidget    *widget,
 							   GdkScreen    *previous_screen);
 void		  _gtk_widget_propagate_composited_changed (GtkWidget    *widget);
 
-void	   _gtk_widget_set_pointer_window  (GtkWidget      *widget,
+void	   _gtk_widget_set_device_window   (GtkWidget      *widget,
+                                            GdkDevice      *device,
 					    GdkWindow      *pointer_window);
-GdkWindow *_gtk_widget_get_pointer_window  (GtkWidget      *widget);
-gboolean   _gtk_widget_is_pointer_widget   (GtkWidget      *widget);
+GdkWindow *_gtk_widget_get_device_window   (GtkWidget      *widget,
+                                            GdkDevice      *device);
+GList *    _gtk_widget_list_devices        (GtkWidget      *widget);
+
 void       _gtk_widget_synthesize_crossing (GtkWidget      *from,
 					    GtkWidget      *to,
+                                            GdkDevice      *device,
 					    GdkCrossingMode mode);
 
 GdkColormap* _gtk_widget_peek_colormap (void);



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