=== modified file 'gdk/x11/gdkdnd-x11.c'
--- gdk/x11/gdkdnd-x11.c	2010-01-28 15:57:52 +0000
+++ gdk/x11/gdkdnd-x11.c	2010-01-31 20:42:19 +0000
@@ -27,6 +27,8 @@
 #include "config.h"
 #include <X11/Xlib.h>
 #include <X11/Xatom.h>
+#include <X11/extensions/shape.h>
+
 #include <string.h>
 
 #include "gdk.h"          /* For gdk_flush() */
@@ -53,6 +55,9 @@
   guint32 xid;
   gint x, y, width, height;
   gboolean mapped;
+  gboolean mask_checked;
+  gboolean mask_valid;
+  GdkRegion *input_mask;
 } GdkCacheChild;
 
 typedef struct {
@@ -305,6 +310,22 @@
 /* Utility functions */
 
 static void
+free_cache_child (GdkCacheChild *child, GdkDisplay *display)
+{
+  if (child->input_mask)
+    gdk_region_destroy (child->input_mask);
+
+  if (child->mask_checked && display)
+    {
+      GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+      XShapeSelectInput (display_x11->xdisplay, child->xid, 0);
+    }
+
+  g_free (child);
+}
+
+static void
 gdk_window_cache_add (GdkWindowCache *cache,
 		      guint32 xid,
 		      gint x, gint y, gint width, gint height, 
@@ -318,6 +339,9 @@
   child->width = width;
   child->height = height;
   child->mapped = mapped;
+  child->mask_checked = FALSE;
+  child->mask_valid = FALSE;
+  child->input_mask = NULL;
 
   cache->children = g_list_prepend (cache->children, child);
   g_hash_table_insert (cache->child_hash, GUINT_TO_POINTER (xid), 
@@ -325,6 +349,52 @@
 }
 
 static GdkFilterReturn
+gdk_window_cache_shape_filter (GdkXEvent *xev,
+			 GdkEvent  *event,
+			 gpointer   data)
+{
+  static int shape_event_base = 0;
+  XEvent *xevent = (XEvent *)xev;
+  GdkWindowCache *cache = data;
+
+  if (shape_event_base == 0)
+    {
+      GdkDisplayX11 *display = GDK_DISPLAY_X11 (gdk_screen_get_display (cache->screen));
+      int ignore;
+
+      XShapeQueryExtension (display->xdisplay, &shape_event_base, &ignore);
+    }
+
+  if (xevent->type == shape_event_base + ShapeNotify)
+    {
+      XShapeEvent *xse = (XShapeEvent*)xevent;
+      GList *node;
+
+      if (xse->kind != ShapeInput)
+        {
+          return GDK_FILTER_REMOVE;
+        }
+
+      node = g_hash_table_lookup (cache->child_hash, 
+                                  GUINT_TO_POINTER (xse->window));
+      if (node)
+        {
+          GdkCacheChild *child = node->data;
+          child->mask_valid = !xse->shaped;
+          if (child->input_mask)
+            {
+              gdk_region_destroy (child->input_mask);
+              child->input_mask = NULL;
+            }
+        }
+
+      return GDK_FILTER_REMOVE;
+    }
+
+  return GDK_FILTER_CONTINUE;
+}
+
+static GdkFilterReturn
 gdk_window_cache_filter (GdkXEvent *xev,
 			 GdkEvent  *event,
 			 gpointer   data)
@@ -399,10 +469,13 @@
 				    GUINT_TO_POINTER (xdwe->window));
 	if (node) 
 	  {
+	    GdkCacheChild *child = node->data;
+
 	    g_hash_table_remove (cache->child_hash,
 				 GUINT_TO_POINTER (xdwe->window));
 	    cache->children = g_list_remove_link (cache->children, node);
-	    g_free (node->data);
+      // window is destroyed, no need to disable ShapeNotify
+	    free_cache_child (child, NULL);
 	    g_list_free_1 (node);
 	  }
 	break;
@@ -430,7 +503,7 @@
 
 	node = g_hash_table_lookup (cache->child_hash, 
 				    GUINT_TO_POINTER (xume->window));
-	if (node) 
+	if (node)
 	  {
 	    GdkCacheChild *child = node->data;
 	    child->mapped = FALSE;
@@ -482,6 +555,9 @@
   XSelectInput (xdisplay, GDK_WINDOW_XWINDOW (root_window),
 		result->old_event_mask | SubstructureNotifyMask);
   gdk_window_add_filter (root_window, gdk_window_cache_filter, result);
+#ifdef ShapeInput
+  gdk_window_add_filter (NULL, gdk_window_cache_shape_filter, result);
+#endif
 
   if (!_gdk_x11_get_window_child_info (gdk_screen_get_display (screen),
 				       GDK_WINDOW_XWINDOW (root_window),
@@ -510,14 +586,88 @@
 		GDK_WINDOW_XWINDOW (root_window),
 		cache->old_event_mask);
   gdk_window_remove_filter (root_window, gdk_window_cache_filter, cache);
+#ifdef ShapeInput
+  gdk_window_remove_filter (NULL, gdk_window_cache_shape_filter, cache);
+#endif
 
-  g_list_foreach (cache->children, (GFunc)g_free, NULL);
+  g_list_foreach (cache->children, (GFunc)free_cache_child, 
+      gdk_screen_get_display (cache->screen));
   g_list_free (cache->children);
   g_hash_table_destroy (cache->child_hash);
 
   g_free (cache);
 }
 
+static GdkRegion *
+xwindow_get_shape (Display *xdisplay,
+       Window window,
+       gint shape_type)
+{
+  GdkRegion *shape;
+  GdkRectangle *rl;
+  XRectangle *xrl;
+  gint rn, ord, i;
+
+  shape = NULL;
+  
+  xrl = XShapeGetRectangles (xdisplay,
+           window,
+           shape_type, &rn, &ord);
+  
+  if (rn == 0)
+    return gdk_region_new (); /* Empty */
+  
+  if (ord != YXBanded)
+    {
+      /* This really shouldn't happen with any xserver, as they
+   generally convert regions to YXBanded internally */
+      g_warning ("non YXBanded shape masks not supported");
+      XFree (xrl);
+      return NULL;
+    }
+
+  rl = g_new (GdkRectangle, rn);
+  for (i = 0; i < rn; i++)
+    {
+      rl[i].x = xrl[i].x;
+      rl[i].y = xrl[i].y;
+      rl[i].width = xrl[i].width;
+      rl[i].height = xrl[i].height;
+    }
+  XFree (xrl);
+  
+  shape = _gdk_region_new_from_yxbanded_rects (rl, rn);
+  g_free (rl);
+  
+  return shape;
+}
+
+static gboolean
+is_pointer_within_input_shape (GdkDisplay *display,
+                               GdkCacheChild *child,
+                               int x_pos, int y_pos)
+{
+  if (!child->mask_checked)
+    {
+      GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+      XShapeSelectInput (display_x11->xdisplay, child->xid, ShapeNotifyMask);
+      child->mask_checked = TRUE;
+    }
+  if (!child->mask_valid)
+    {
+      // fetch the input mask
+      GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+      child->input_mask = xwindow_get_shape (display_x11->xdisplay,
+                                             child->xid, ShapeInput);
+      child->mask_valid = TRUE;
+    }
+
+  return child->input_mask == NULL ||
+         gdk_region_point_in (child->input_mask, x_pos, y_pos);
+}
+
 static Window
 get_client_window_at_coords_recurse (GdkDisplay *display,
 				     Window      win,
@@ -590,19 +740,30 @@
       GdkCacheChild *child = tmp_list->data;
 
       if ((child->xid != ignore) && (child->mapped))
-	{
-	  if ((x_root >= child->x) && (x_root < child->x + child->width) &&
-	      (y_root >= child->y) && (y_root < child->y + child->height))
-	    {
-	      retval = get_client_window_at_coords_recurse (gdk_screen_get_display (cache->screen),
-							    child->xid, TRUE,
-							    x_root - child->x,
-							    y_root - child->y);
-	      if (!retval)
-		retval = child->xid;
-	    }
+        {
+          if ((x_root >= child->x) && (x_root < child->x + child->width) &&
+              (y_root >= child->y) && (y_root < child->y + child->height))
+            {
+              GdkDisplay *display = gdk_screen_get_display (cache->screen);
+
+#ifdef ShapeInput
+              if (!is_pointer_within_input_shape (display, child,
+                                                  x_root - child->x,
+                                                  y_root - child->y))
+                {
+                  tmp_list = tmp_list->next;
+                  continue;
+                }
+#endif
+              retval = get_client_window_at_coords_recurse (display,
+                  child->xid, TRUE,
+                  x_root - child->x,
+                  y_root - child->y);
+              if (!retval)
+                retval = child->xid;
+            }
 	  
-	}
+        }
       tmp_list = tmp_list->next;
     }
 

