diff --git a/gdk/quartz/gdkdrawable-quartz.c b/gdk/quartz/gdkdrawable-quartz.c index 1bbf7c92a7..503ea83aa8 100644 --- a/gdk/quartz/gdkdrawable-quartz.c +++ b/gdk/quartz/gdkdrawable-quartz.c @@ -361,15 +361,90 @@ gdk_quartz_draw_drawable (GdkDrawable *drawable, { NSRect rect = NSMakeRect (xsrc, ysrc, width, height); NSSize offset = NSMakeSize (xdest - xsrc, ydest - ysrc); + GdkRectangle tmp_rect; + GdkRegion *orig_region, *offset_region, *need_display_region; + GdkWindow *window = GDK_DRAWABLE_IMPL_QUARTZ (drawable)->wrapper; - [window_impl->view scrollRect:rect by:offset]; + /* Origin region */ + tmp_rect.x = xsrc; + tmp_rect.y = ysrc; + tmp_rect.width = width; + tmp_rect.height = height; + orig_region = gdk_region_rectangle (&tmp_rect); - /* The scrollRect only "takes effect" on the next redraw, we must - * set that the offset rectangle needs display. - */ - rect.origin.x += offset.width; - rect.origin.y += offset.height; - [window_impl->view setNeedsDisplayInRect:rect]; + /* Destination region (or the offset region) */ + offset_region = gdk_region_copy (orig_region); + gdk_region_offset (offset_region, offset.width, offset.height); + + need_display_region = gdk_region_copy (orig_region); + + if (window_impl->in_paint_rect_count == 0) + { + GdkRegion *bottom_border_region; + + /* If we are not in drawRect:, we can use scrollRect:. + * We apply scrollRect on the rectangle to be moved and + * subtract this area from the rectangle that needs display. + * + * Note: any area in this moved region that already needed + * display will be handled by GDK (queue translation). + * + * Queuing the redraw below is important, otherwise the + * results from scrollRect will not take effect! + */ + [window_impl->view scrollRect:rect by:offset]; + + gdk_region_subtract (need_display_region, offset_region); + + /* Here we take special care with the bottom window border, + * which extents 4 pixels and typically draws rounded corners. + */ + tmp_rect.x = 0; + tmp_rect.y = gdk_window_get_height (window) - 4; + tmp_rect.width = gdk_window_get_width (window); + tmp_rect.height = 4; + + if (gdk_region_rect_in (offset_region, &tmp_rect) != + GDK_OVERLAP_RECTANGLE_OUT) + { + /* We are copying pixels to the bottom border, we need + * to submit this area for redisplay to get the rounded + * corners drawn. + */ + gdk_region_union_with_rect (need_display_region, + &tmp_rect); + } + + /* Compute whether the bottom border is moved elsewhere. + * Because this part will have rounded corners, we have + * to fill the contents of where the rounded corners used + * to be. We post this area for redisplay. + */ + bottom_border_region = gdk_region_rectangle (&tmp_rect); + gdk_region_intersect (bottom_border_region, + orig_region); + + gdk_region_offset (bottom_border_region, + offset.width, offset.height); + + gdk_region_union (need_display_region, bottom_border_region); + + gdk_region_destroy (bottom_border_region); + } + else + { + /* If we cannot handle things with a scroll, we must redisplay + * the union of the source area and the destination area. + */ + gdk_region_union (need_display_region, offset_region); + } + + _gdk_quartz_window_set_needs_display_in_region (window, + need_display_region); + + gdk_region_destroy (orig_region); + gdk_region_destroy (offset_region); + gdk_region_destroy (need_display_region); } else g_warning ("Drawing with window source != dest is not supported");