[gtk+/client-side-windows: 57/284] Implement shaped windows



commit 4ba2b181bfdac308e5f10f707c5a493ad93d1679
Author: Alexander Larsson <alexl redhat com>
Date:   Tue Dec 16 20:09:20 2008 +0100

    Implement shaped windows
---
 gdk/gdkinternals.h      |    2 +
 gdk/gdkwindow.c         |   98 ++++++++++++++++++++++++++++++++++--------
 gdk/gdkwindow.h         |    2 +
 gdk/x11/gdkwindow-x11.c |  108 +++++++++++++++++++++++++++++++++--------------
 4 files changed, 159 insertions(+), 51 deletions(-)

diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index 2766c8d..7c119a4 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -336,6 +336,8 @@ void     _gdk_windowing_window_get_offsets      (GdkWindow  *window,
 						 gint       *x_offset,
 						 gint       *y_offset);
 GdkRegion *_gdk_windowing_window_get_shape      (GdkWindow  *window);
+GdkRegion *_gdk_windowing_get_shape_for_mask    (GdkBitmap *mask);
+
 
 void       _gdk_windowing_get_pointer        (GdkDisplay       *display,
 					      GdkScreen       **screen,
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 9655e31..6ea81d0 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -457,10 +457,25 @@ remove_child_area (GdkWindowObject *private,
       r.y = child->y;
       r.width = child->width;
       r.height = child->height;
-      
+
       child_region = gdk_region_rectangle (&r);
+      
+      if (child->shape)
+	gdk_region_intersect (child_region, child->shape);
+      else if (private->window_type == GDK_WINDOW_FOREIGN)
+	{
+	  GdkRegion *shape;
+	  shape = _gdk_windowing_window_get_shape ((GdkWindow *)child);
+	  if (shape)
+	    {
+	      gdk_region_intersect (child_region, shape);
+	      gdk_region_destroy (shape);
+	    }
+	}
+      
       gdk_region_subtract (region, child_region);
       gdk_region_destroy (child_region);
+
     }
 }
 
@@ -512,7 +527,7 @@ recompute_visible_regions_internal (GdkWindowObject *private,
       r.width = private->width;
       r.height = private->height;
       new_clip = gdk_region_rectangle (&r);
-      
+
       if (private->parent != NULL && GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)
 	{
 	  gdk_region_intersect (new_clip, private->parent->clip_region);
@@ -524,6 +539,9 @@ recompute_visible_regions_internal (GdkWindowObject *private,
       /* Convert from parent coords to window coords */
       gdk_region_offset (new_clip, -private->x, -private->y);
 
+      if (private->shape)
+	gdk_region_intersect (new_clip, private->shape);
+
       if (private->clip_region == NULL ||
 	  !gdk_region_equal (private->clip_region, new_clip))
 	clip_region_changed = TRUE;
@@ -562,9 +580,10 @@ recompute_visible_regions_internal (GdkWindowObject *private,
       gdk_window_has_impl (private) &&
       /* Not for offscreens */
       private->window_type != GDK_WINDOW_OFFSCREEN &&
-      /* or for toplevels */
-      private->parent != NULL &&
-      GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT &&
+      /* or for non-shaped toplevels */
+      (private->shaped ||
+       (private->parent != NULL &&
+	GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)) &&
       /* or for foreign windows */
       GDK_WINDOW_TYPE (private) != GDK_WINDOW_FOREIGN
       )
@@ -6171,12 +6190,19 @@ gdk_window_shape_combine_mask (GdkWindow *window,
                                gint       y)
 {
   GdkWindowObject *private;
+  GdkRegion *region;
 
   g_return_if_fail (GDK_IS_WINDOW (window));
 
   private = (GdkWindowObject *) window;
 
-  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_mask (window, mask, x, y);
+  region = _gdk_windowing_get_shape_for_mask (mask);
+
+  gdk_window_shape_combine_region (window,
+				   region,
+				   x, y);
+
+  gdk_region_destroy (region);
 }
 
 /**
@@ -6214,7 +6240,47 @@ gdk_window_shape_combine_region (GdkWindow       *window,
 
   private = (GdkWindowObject *) window;
 
-  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region (window, shape_region, offset_x, offset_y);
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+
+  private->shaped = (shape_region != NULL);
+
+  if (private->shape)
+    gdk_region_destroy (private->shape);
+
+  if (shape_region)
+    {
+      private->shape = gdk_region_copy (shape_region);
+      gdk_region_offset (private->shape, offset_x, offset_y);      
+    }
+  else
+    private->shape = NULL;
+  
+  recompute_visible_regions (private, TRUE, FALSE);
+}
+
+static void
+do_child_shapes (GdkWindow *window,
+		 gboolean merge)
+{
+  GdkWindowObject *private;
+  GdkRectangle r;
+  GdkRegion *region;
+
+  private = (GdkWindowObject *) window;
+  
+  r.x = 0;
+  r.y = 0;
+  r.width = private->width;
+  r.height = private->height;
+  
+  region = gdk_region_rectangle (&r);
+  remove_child_area (private, NULL, region);
+
+  if (merge && private->shape)
+    gdk_region_subtract (region, private->shape);
+  
+  gdk_window_shape_combine_region (window, region, 0, 0);
 }
 
 /**
@@ -6229,13 +6295,9 @@ gdk_window_shape_combine_region (GdkWindow       *window,
 void
 gdk_window_set_child_shapes (GdkWindow *window)
 {
-  GdkWindowObject *private;
-
   g_return_if_fail (GDK_IS_WINDOW (window));
 
-  private = (GdkWindowObject *) window;
-
-  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_child_shapes (window);
+  do_child_shapes (window, FALSE);
 }
 
 /**
@@ -6254,13 +6316,9 @@ gdk_window_set_child_shapes (GdkWindow *window)
 void
 gdk_window_merge_child_shapes (GdkWindow *window)
 {
-  GdkWindowObject *private;
-
   g_return_if_fail (GDK_IS_WINDOW (window));
 
-  private = (GdkWindowObject *) window;
-
-  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->merge_child_shapes (window);
+  do_child_shapes (window, TRUE);
 }
 
 
@@ -6650,10 +6708,12 @@ static gboolean
 point_in_window (GdkWindowObject *window,
 		 double x, double y)
 {
-  /* TODO: Input Shape */
   return
     x >= 0 &&  x < window->width &&
-    y >= 0 && y < window->height;
+    y >= 0 && y < window->height &&
+    (window->shape == NULL ||
+     gdk_region_point_in (window->shape,
+			  x, y));
 }
 
 static void
diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h
index 5c47578..bc08cbc 100644
--- a/gdk/gdkwindow.h
+++ b/gdk/gdkwindow.h
@@ -337,6 +337,8 @@ struct _GdkWindowObject
   GdkWindowPaint *implicit_paint;
 
   GList *outstanding_moves;
+
+  GdkRegion *shape;
   
   cairo_surface_t *cairo_surface;
 };
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index 2b00d95..85f81e5 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -4757,48 +4757,92 @@ gdk_add_to_span (struct _gdk_span **s,
   return;
 }
 
-GdkRegion *
-_gdk_windowing_window_get_shape (GdkWindow *window)
+static GdkRegion *
+xwindow_get_shape (Display *xdisplay,
+		   Window window)
 {
   GdkRegion *shape;
+  GdkRectangle *rl;
+  XRectangle *xrl;
+  gint rn, ord, i;
 
   shape = NULL;
   
 #if defined(HAVE_SHAPE_EXT)
-  if (!GDK_WINDOW_DESTROYED (window) &&
-      gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)))
+  xrl = XShapeGetRectangles (xdisplay,
+			     window,
+			     ShapeBounding, &rn, &ord);
+
+  if (rn == 0)
+    return NULL;
+  
+  if (ord != YXBanded)
     {
-      GdkRectangle *rl;
-      XRectangle *xrl;
-      gint rn, ord, i;
-      
-      xrl = XShapeGetRectangles (GDK_WINDOW_XDISPLAY (window),
-				 GDK_WINDOW_XID (window),
-				 ShapeBounding, &rn, &ord);
-      
-      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 (rl);
-	  return NULL;
-	}
+      /* 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;
-	}
-      
-      shape = _gdk_region_new_from_yxbanded_rects (rl, rn);
-      g_free (rl);
-      XFree (rl);
+  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);
+#endif
+  
+  return shape;
+}
+
+
+GdkRegion *
+_gdk_windowing_get_shape_for_mask (GdkBitmap *mask)
+{
+  GdkDisplay *display;
+  Window window;
+  GdkRegion *region;
+
+  display = gdk_drawable_get_display (GDK_DRAWABLE (mask));
+
+  window = XCreateSimpleWindow (GDK_DISPLAY_XDISPLAY (display),
+				GDK_SCREEN_XROOTWIN (gdk_display_get_default_screen (display)),
+				-1, -1, 1, 1, 0,
+				0, 0);
+  XShapeCombineMask (GDK_DISPLAY_XDISPLAY (display),
+		     window,
+		     ShapeBounding,
+		     0, 0,
+		     GDK_PIXMAP_XID (mask),
+		     ShapeSet);
+  
+  region = xwindow_get_shape (GDK_DISPLAY_XDISPLAY (display),
+			      window);
+
+  XDestroyWindow (GDK_DISPLAY_XDISPLAY (display),
+		  window);
+
+  return region;
+}
+
+GdkRegion *
+_gdk_windowing_window_get_shape (GdkWindow *window)
+{
+#if defined(HAVE_SHAPE_EXT)
+  if (!GDK_WINDOW_DESTROYED (window) &&
+      gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)))
+    return xwindow_get_shape (GDK_WINDOW_XDISPLAY (window),
+			      GDK_WINDOW_XID (window));
 #endif
+
+  return NULL;
 }
 
 static void



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