? frut
? global-motion-1.patch
Index: gdkevents.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkevents.h,v
retrieving revision 1.23
diff -u -p -u -r1.23 gdkevents.h
--- gdkevents.h	28 Nov 2004 06:45:52 -0000	1.23
+++ gdkevents.h	29 Apr 2005 20:51:53 -0000
@@ -120,7 +120,8 @@ typedef enum
   GDK_SCROLL            = 31,
   GDK_WINDOW_STATE      = 32,
   GDK_SETTING           = 33,
-  GDK_OWNER_CHANGE      = 34
+  GDK_OWNER_CHANGE      = 34,
+  GDK_LAST_EVENT	= 34
 } GdkEventType;
 
 /* Event masks. (Used to select what types of events a window
Index: gdkwindow.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkwindow.h,v
retrieving revision 1.51
diff -u -p -u -r1.51 gdkwindow.h
--- gdkwindow.h	11 Jul 2004 13:26:57 -0000	1.51
+++ gdkwindow.h	29 Apr 2005 20:51:53 -0000
@@ -215,6 +215,14 @@ struct _GdkPointerHooks 
 typedef struct _GdkWindowObject GdkWindowObject;
 typedef struct _GdkWindowObjectClass GdkWindowObjectClass;
 
+typedef void (* GdkMotionHandler) (GdkWindow *	window,
+				   gint		x,
+				   gint		y,
+				   gdouble	x_root,
+				   gdouble	y_root,
+				   gint		mask,
+				   gpointer	data);
+
 #define GDK_TYPE_WINDOW              (gdk_window_object_get_type ())
 #define GDK_WINDOW(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WINDOW, GdkWindow))
 #define GDK_WINDOW_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WINDOW, GdkWindowObjectClass))
@@ -333,6 +341,9 @@ void          gdk_window_remove_filter  
 void          gdk_window_scroll                (GdkWindow *window,
                                                 gint       dx,
                                                 gint       dy);
+void	      gdk_set_motion_handler	       (GdkWindow	 *window,
+						GdkMotionHandler  handler,
+						gpointer	  data);
 
 /* 
  * This allows for making shaped (partially transparent) windows
Index: x11/gdkevents-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkevents-x11.c,v
retrieving revision 1.146
diff -u -p -u -r1.146 gdkevents-x11.c
--- x11/gdkevents-x11.c	16 Mar 2005 03:17:27 -0000	1.146
+++ x11/gdkevents-x11.c	29 Apr 2005 20:51:53 -0000
@@ -84,6 +84,20 @@ struct _GdkEventTypeX11
   gint n_events;
 };
 
+
+/* An internal event to signify that the next motion event
+ * should be dispatched to the application with ->hint set
+ * to TRUE
+ */
+
+#define GDK_INTERNAL_SEND_NEXT_MOTION  (GDK_LAST_EVENT + 1)
+
+struct _GdkEventInternalSendNextMotion
+{
+  GdkEventType type;
+  GdkWindow *window;
+};
+
 /* 
  * Private function declarations
  */
@@ -197,6 +211,16 @@ _gdk_x11_events_uninit_screen (GdkScreen
   screen_x11->xsettings_client = NULL;
 }
 
+void
+_gdk_x11_events_queue_send_motion_hint (GdkWindow *window)
+{
+  GdkEvent *event = gdk_event_new (GDK_INTERNAL_SEND_NEXT_MOTION);
+  event->any.window = g_object_ref (window);
+  event->any.send_event = FALSE;
+  
+  _gdk_event_queue_append (GDK_WINDOW_DISPLAY (window), event);
+}
+
 void 
 _gdk_events_init (GdkDisplay *display)
 {
@@ -227,7 +251,6 @@ _gdk_events_init (GdkDisplay *display)
 					 NULL);
 }
 
-
 /**
  * gdk_events_pending:
  * 
@@ -1023,6 +1046,9 @@ gdk_event_translate (GdkDisplay *display
       yoffset = 0;
     }
 
+  if (xevent->type != MotionNotify && window)
+      _gdk_x11_events_queue_send_motion_hint (window);
+  
   switch (xevent->type)
     {
     case KeyPress:
@@ -1109,7 +1135,6 @@ gdk_event_translate (GdkDisplay *display
 	  event->scroll.device = display->core_pointer;
 
 	  set_screen_from_root (display, event, xevent->xbutton.root);
-	  
           break;
           
         default:
@@ -2202,6 +2227,119 @@ gdk_event_check (GSource *source) 
   return retval;
 }
 
+static gboolean
+skip_event (GdkDisplay *display, GdkEvent *event)
+{
+  GdkWindowObject *obj;
+  GdkWindowImplX11 *impl;
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  if (!event->any.window || display_x11->pointer_xgrab_window == (GdkWindowObject *)event->any.window)
+    return FALSE;
+  
+  obj = (GdkWindowObject *)event->any.window;
+  impl = GDK_WINDOW_IMPL_X11 (obj->impl);
+
+  if (event->type == GDK_MOTION_NOTIFY && (obj->event_mask & GDK_POINTER_MOTION_HINT_MASK))
+    {
+      if (impl->skip_motion)
+	{
+	  return TRUE;
+	}
+      else
+	{
+	  event->motion.is_hint = TRUE;
+	  impl->skip_motion = TRUE;
+	  return FALSE;
+	}
+    }
+
+  if (event->type == GDK_ENTER_NOTIFY && !(obj->event_mask & GDK_ENTER_NOTIFY_MASK))
+    return TRUE;
+
+  if (event->type == GDK_LEAVE_NOTIFY && !(obj->event_mask & GDK_LEAVE_NOTIFY_MASK))
+    return TRUE;
+
+  if (event->type == GDK_BUTTON_PRESS && !(obj->event_mask & GDK_BUTTON_PRESS_MASK))
+    return TRUE;
+
+  if (event->type == GDK_BUTTON_RELEASE && !(obj->event_mask & GDK_BUTTON_RELEASE_MASK))
+    return TRUE;
+
+  if (event->type == GDK_KEY_PRESS && (!obj->event_mask & GDK_KEY_PRESS_MASK))
+    return TRUE;
+
+  if (event->type == GDK_KEY_RELEASE && (!obj->event_mask & GDK_KEY_RELEASE_MASK))
+    return TRUE;
+
+  if (event->type == GDK_MOTION_NOTIFY &&
+      (!(obj->event_mask & (GDK_POINTER_MOTION_MASK |
+			    GDK_POINTER_MOTION_HINT_MASK |
+			    GDK_BUTTON_MOTION_MASK |
+			    GDK_BUTTON1_MOTION_MASK |
+			    GDK_BUTTON2_MOTION_MASK |
+			    GDK_BUTTON3_MOTION_MASK))))
+    {
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+propagate_global_motion (GdkWindowObject *obj, int mask,
+			 int x, int y,
+			 double x_root, double y_root)
+{
+  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (obj->impl);
+  
+  if (impl->motion_handler)
+    impl->motion_handler ((GdkWindow *)obj, x, y, x_root, y_root, mask, impl->motion_handler_data);
+  
+  if (obj->parent)
+    {
+      x += obj->x;
+      y += obj->y;
+      
+      propagate_global_motion (obj->parent, mask, x, y, x_root, y_root);
+    }
+}
+
+static void
+generate_global_motion (GdkEvent *event)
+{
+  gint mask;
+  gint x, y;
+  gdouble x_root, y_root;
+  
+  if (!event->any.window)
+    return;
+  
+  if (event->type == GDK_MOTION_NOTIFY)
+    {
+      mask = event->motion.state;
+      x = event->motion.x;
+      y = event->motion.y;
+      x_root = event->motion.x_root;
+      y_root = event->motion.y_root;
+    }
+  else if (event->type == GDK_ENTER_NOTIFY ||
+	   event->type == GDK_LEAVE_NOTIFY)
+    {
+      mask = event->crossing.state;
+      x = event->crossing.x;
+      y = event->crossing.y;
+      x_root = event->crossing.x_root;
+      y_root = event->crossing.y_root;
+    }
+  else
+    {
+      return;
+    }
+  
+  propagate_global_motion (event->any.window, mask, x, y, x_root, y_root);
+}
+
 static gboolean  
 gdk_event_dispatch (GSource    *source,
 		    GSourceFunc callback,
@@ -2217,8 +2355,24 @@ gdk_event_dispatch (GSource    *source,
 
   if (event)
     {
-      if (_gdk_event_func)
-	(*_gdk_event_func) (event, _gdk_event_data);
+      if (event->type == GDK_INTERNAL_SEND_NEXT_MOTION)
+	{
+	  GdkWindowObject *obj = (GdkWindowObject *)event->any.window;
+	  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (obj->impl);
+	  
+	  if (obj->event_mask & GDK_POINTER_MOTION_HINT_MASK)
+	    impl->skip_motion = FALSE;
+	}
+      else
+	{
+	  if (!skip_event (display, event))
+	    {
+	      if (_gdk_event_func)
+		(*_gdk_event_func) (event, _gdk_event_data);
+	    }
+
+	  generate_global_motion (event);
+	}
       
       gdk_event_free (event);
     }
Index: x11/gdkprivate-x11.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkprivate-x11.h,v
retrieving revision 1.36
diff -u -p -u -r1.36 gdkprivate-x11.h
--- x11/gdkprivate-x11.h	17 Mar 2005 01:54:39 -0000	1.36
+++ x11/gdkprivate-x11.h	29 Apr 2005 20:51:53 -0000
@@ -167,6 +167,8 @@ void _gdk_x11_precache_atoms (GdkDisplay
 void _gdk_x11_events_init_screen   (GdkScreen *screen);
 void _gdk_x11_events_uninit_screen (GdkScreen *screen);
 
+void _gdk_x11_events_queue_send_motion_hint (GdkWindow *window);
+
 void _gdk_events_init           (GdkDisplay *display);
 void _gdk_windowing_window_init (GdkScreen *screen);
 void _gdk_visual_init           (GdkScreen *screen);
Index: x11/gdkwindow-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkwindow-x11.c,v
retrieving revision 1.236
diff -u -p -u -r1.236 gdkwindow-x11.c
--- x11/gdkwindow-x11.c	17 Mar 2005 01:54:39 -0000	1.236
+++ x11/gdkwindow-x11.c	29 Apr 2005 20:51:53 -0000
@@ -644,6 +644,39 @@ setup_toplevel_window (GdkWindow *window
   ensure_sync_counter (window);
 }
 
+static gint
+gdk_event_mask_to_x_event_mask (GdkWindowImplX11 *impl,
+				gint		  gdk_mask)
+{
+  gint result, i;
+
+  result = 0;
+  for (i = 0; i < _gdk_nenvent_masks; i++)
+    {
+      if (gdk_mask & (1 << (i + 1)))
+	result |= _gdk_event_mask_table[i];
+    }
+
+  if (gdk_mask & GDK_POINTER_MOTION_HINT_MASK)
+    {
+      result &= ~PointerMotionHintMask;
+
+      result |= KeyPressMask;
+      result |= KeyReleaseMask;
+      result |= ButtonPressMask;
+      result |= ButtonReleaseMask;
+    }
+
+  /* We need to select for enter/leave events on all windows
+   * so that we can generate global motion events
+   */
+  result |= LeaveWindowMask;
+  result |= EnterWindowMask;
+  result |= PointerMotionMask;
+  
+  return result;
+}
+
 /**
  * gdk_window_new:
  * @parent: a #GdkWindow, or %NULL to create the window as a child of
@@ -683,7 +716,6 @@ gdk_window_new (GdkWindow     *parent,
   
   unsigned int class;
   const char *title;
-  int i;
   
   g_return_val_if_fail (attributes != NULL, NULL);
   
@@ -769,11 +801,7 @@ gdk_window_new (GdkWindow     *parent,
   xvisual = ((GdkVisualPrivate*) visual)->xvisual;
   
   xattributes.event_mask = StructureNotifyMask | PropertyChangeMask;
-  for (i = 0; i < _gdk_nenvent_masks; i++)
-    {
-      if (attributes->event_mask & (1 << (i + 1)))
-	xattributes.event_mask |= _gdk_event_mask_table[i];
-    }
+  xattributes.event_mask = gdk_event_mask_to_x_event_mask (impl, attributes->event_mask);
   private->event_mask = attributes->event_mask;
   
   if (xattributes.event_mask)
@@ -3290,6 +3318,9 @@ _gdk_windowing_window_get_pointer (GdkDi
   
   _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
 
+  if (window)
+    _gdk_x11_events_queue_send_motion_hint (window);
+
   return_val = NULL;
   if (!GDK_WINDOW_DESTROYED (window) &&
       XQueryPointer (GDK_WINDOW_XDISPLAY (window),
@@ -3450,12 +3481,8 @@ gdk_window_set_events (GdkWindow       *
   if (!GDK_WINDOW_DESTROYED (window))
     {
       GDK_WINDOW_OBJECT (window)->event_mask = event_mask;
-      xevent_mask = StructureNotifyMask | PropertyChangeMask;
-      for (i = 0; i < _gdk_nenvent_masks; i++)
-	{
-	  if (event_mask & (1 << (i + 1)))
-	    xevent_mask |= _gdk_event_mask_table[i];
-	}
+
+      xevent_mask = gdk_event_mask_to_x_event_mask (((GdkWindowObject *)window)->impl, event_mask);
       
       XSelectInput (GDK_WINDOW_XDISPLAY (window),
 		    GDK_WINDOW_XID (window),
@@ -5888,6 +5915,33 @@ gdk_window_configure_finished (GdkWindow
 	}
     }
 #endif
+}
+
+/**
+ * gdk_set_motion_handler:
+ * @window: a #GdkWindow
+ * @handler: the address of a function that is called when the mouse cursor moves inside this window
+ * @data: a pointer that is passed to @handler.
+ * 
+ * This function sets a motion handler that is called every time the mouse cursor
+ * moves inside @window or one of @window's children. The callback is called
+ * regardless of whether GDK_MOTION_NOTIFY_MASK is in the event_mask for @window,
+ * 
+ * Since: 2.8
+ **/
+void
+gdk_window_set_motion_handler (GdkWindow	 *window,
+			       GdkMotionHandler  handler,
+			       gpointer		 data)
+{
+  GdkWindowImplX11 *impl;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  impl = GDK_WINDOW_IMPL_X11 (((GdkWindowObject *)window)->impl);
+
+  impl->motion_handler = handler;
+  impl->motion_handler_data = data;
 }
 
 #define __GDK_WINDOW_X11_C__
Index: x11/gdkwindow-x11.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkwindow-x11.h,v
retrieving revision 1.18
diff -u -p -u -r1.18 gdkwindow-x11.h
--- x11/gdkwindow-x11.h	18 Oct 2004 21:02:37 -0000	1.18
+++ x11/gdkwindow-x11.h	29 Apr 2005 20:51:53 -0000
@@ -78,6 +78,10 @@ struct _GdkWindowImplX11
   gint8 toplevel_window_type;
   guint override_redirect : 1;
   guint use_synchronized_configure : 1;
+  guint skip_motion : 1;
+
+  GdkMotionHandler motion_handler;
+  gpointer motion_handler_data;
 };
  
 struct _GdkWindowImplX11Class 
@@ -114,7 +118,7 @@ struct _GdkToplevelX11
   guint have_fullscreen : 1;    /* _NET_WM_STATE_FULLSCREEN */
 
   guint is_leader : 1;
-  
+
   gulong map_serial;	/* Serial of last transition from unmapped */
   
   GdkPixmap *icon_pixmap;
