diff --git a/gdk/gdkdraw.c b/gdk/gdkdraw.c index 869d535..44652bc 100644 --- a/gdk/gdkdraw.c +++ b/gdk/gdkdraw.c @@ -752,9 +752,6 @@ gdk_draw_image (GdkDrawable *drawable, * On older X servers, rendering pixbufs with an alpha channel involves round * trips to the X server, and may be somewhat slow. * - * The clip mask of @gc is ignored, but clip rectangles and clip regions work - * fine. - * * If GDK is built with the Sun mediaLib library, the gdk_draw_pixbuf * function is accelerated using mediaLib, which provides hardware * acceleration on Intel, AMD, and Sparc chipsets. If desired, mediaLib diff --git a/gdk/gdkgc.c b/gdk/gdkgc.c index b4c6f81..699cebf 100644 --- a/gdk/gdkgc.c +++ b/gdk/gdkgc.c @@ -646,24 +646,49 @@ _gdk_gc_add_drawable_clip (GdkGC *gc, GdkPixmap *new_mask; GdkGC *tmp_gc; GdkColor black = {0, 0, 0, 0}; + GdkRectangle r; + GdkOverlapType overlap; - priv->old_clip_mask = g_object_ref (priv->clip_mask); - gdk_drawable_get_size (priv->old_clip_mask, &w, &h); - - new_mask = gdk_pixmap_new (priv->old_clip_mask, w, h, -1); - tmp_gc = _gdk_drawable_get_scratch_gc ((GdkDrawable *)new_mask, FALSE); - - gdk_gc_set_foreground (tmp_gc, &black); - gdk_draw_rectangle (new_mask, tmp_gc, TRUE, 0, 0, -1, -1); - _gdk_gc_set_clip_region_internal (tmp_gc, region, TRUE); /* Takes ownership of region */ - gdk_draw_drawable (new_mask, - tmp_gc, - priv->old_clip_mask, - 0, 0, - 0, 0, - -1, -1); - gdk_gc_set_clip_region (tmp_gc, NULL); - gdk_gc_set_clip_mask (gc, new_mask); + gdk_drawable_get_size (priv->clip_mask, &w, &h); + + r.x = 0; + r.y = 0; + r.width = w; + r.height = h; + + /* Its quite common to expose areas that are completely in or outside + * the region, so we try to avoid allocating bitmaps that are just fully + * set or completely unset. + */ + overlap = gdk_region_rect_in (region, &r); + if (overlap == GDK_OVERLAP_RECTANGLE_PART) + { + /* The region and the mask intersect, create a new clip mask that + includes both areas */ + priv->old_clip_mask = g_object_ref (priv->clip_mask); + new_mask = gdk_pixmap_new (priv->old_clip_mask, w, h, -1); + tmp_gc = _gdk_drawable_get_scratch_gc ((GdkDrawable *)new_mask, FALSE); + + gdk_gc_set_foreground (tmp_gc, &black); + gdk_draw_rectangle (new_mask, tmp_gc, TRUE, 0, 0, -1, -1); + _gdk_gc_set_clip_region_internal (tmp_gc, region, TRUE); /* Takes ownership of region */ + gdk_draw_drawable (new_mask, + tmp_gc, + priv->old_clip_mask, + 0, 0, + 0, 0, + -1, -1); + gdk_gc_set_clip_region (tmp_gc, NULL); + gdk_gc_set_clip_mask (gc, new_mask); + } + else if (overlap == GDK_OVERLAP_RECTANGLE_OUT) + { + GdkRegion *empty = gdk_region_new (); + + priv->old_clip_mask = g_object_ref (priv->clip_mask); + _gdk_windowing_gc_set_clip_region (gc, empty, FALSE); + gdk_region_destroy (empty); + } } else { @@ -775,6 +800,24 @@ _gdk_gc_get_clip_region (GdkGC *gc) } /** + * _gdk_gc_get_clip_mask: + * @gc: a #GdkGC + * + * Gets the current clip mask for @gc, if any. + * + * Return value: the clip mask for the GC, or %NULL. + * (if a clip region is set, the return will be %NULL) + * This value is owned by the GC and must not be freed. + **/ +GdkBitmap * +_gdk_gc_get_clip_mask (GdkGC *gc) +{ + g_return_val_if_fail (GDK_IS_GC (gc), NULL); + + return GDK_GC_GET_PRIVATE (gc)->clip_mask; +} + +/** * _gdk_gc_get_fill: * @gc: a #GdkGC * diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index 946c3f9..c984386 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -399,6 +399,7 @@ void _gdk_gc_init (GdkGC *gc, GdkGCValuesMask values_mask); GdkRegion *_gdk_gc_get_clip_region (GdkGC *gc); +GdkBitmap *_gdk_gc_get_clip_mask (GdkGC *gc); gboolean _gdk_gc_get_exposures (GdkGC *gc); GdkFill _gdk_gc_get_fill (GdkGC *gc); GdkPixmap *_gdk_gc_get_tile (GdkGC *gc); diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 6e72cab..d9b1e5b 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -639,7 +639,12 @@ remove_child_area (GdkWindowObject *private, child_region = gdk_region_rectangle (&r); if (child->shape) - gdk_region_intersect (child_region, child->shape); + { + /* Adjust shape region to parent window coords */ + gdk_region_offset (child->shape, child->x, child->y); + gdk_region_intersect (child_region, child->shape); + gdk_region_offset (child->shape, -child->x, -child->y); + } else if (private->window_type == GDK_WINDOW_FOREIGN) { shape = _gdk_windowing_window_get_shape ((GdkWindow *)child); @@ -4660,7 +4665,12 @@ _gdk_window_process_updates_recurse (GdkWindow *window, child_region = gdk_region_rectangle (&r); if (child->shape) - gdk_region_intersect (child_region, child->shape); + { + /* Adjust shape region to parent window coords */ + gdk_region_offset (child->shape, child->x, child->y); + gdk_region_intersect (child_region, child->shape); + gdk_region_offset (child->shape, -child->x, -child->y); + } if (child->impl == private->impl) { diff --git a/gdk/x11/gdkdrawable-x11.c b/gdk/x11/gdkdrawable-x11.c index 537a47e..b2cac29 100644 --- a/gdk/x11/gdkdrawable-x11.c +++ b/gdk/x11/gdkdrawable-x11.c @@ -388,9 +388,22 @@ gdk_x11_drawable_update_picture_clip (GdkDrawable *drawable, else { XRenderPictureAttributes pa; - pa.clip_mask = None; + GdkBitmap *mask; + gulong pa_mask; + + pa_mask = CPClipMask; + if (gc && (mask = _gdk_gc_get_clip_mask (gc))) + { + pa.clip_mask = GDK_PIXMAP_XID (mask); + pa.clip_x_origin = gc->clip_x_origin; + pa.clip_y_origin = gc->clip_y_origin; + pa_mask |= CPClipXOrigin | CPClipYOrigin; + } + else + pa.clip_mask = None; + XRenderChangePicture (xdisplay, picture, - CPClipMask, &pa); + pa_mask, &pa); } }