From d8192013f3ee1eda0bb9de793acd64b4ef84c1ff Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Thu, 29 Oct 2020 19:37:27 -0700 Subject: [PATCH] macos: add more aggressive clip to transparent subview The Cairo implementation for the Macos backend uses a toplevel window with full transparency and a series of NSView to create opaque regions. This improves compositor performance because it allows the display server to avoid costly blends. However, we want to ensure we clip better when exposing the transparent region so that we only expose the shadows/corners as necessary. --- gdk/macos/GdkMacosCairoSubview.c | 31 +++++++++++++++++++++++++++++++ gdk/macos/GdkMacosCairoSubview.h | 2 ++ gdk/macos/GdkMacosCairoView.c | 12 ++++++++++++ 3 files changed, 45 insertions(+) diff --git a/gdk/macos/GdkMacosCairoSubview.c b/gdk/macos/GdkMacosCairoSubview.c index 425b52ac78..e52acdf168 100644 --- a/gdk/macos/GdkMacosCairoSubview.c +++ b/gdk/macos/GdkMacosCairoSubview.c @@ -32,6 +32,12 @@ @implementation GdkMacosCairoSubview +-(void)dealloc +{ + g_clear_pointer (&self->clip, cairo_region_destroy); + [super dealloc]; +} + -(BOOL)isOpaque { return _isOpaque; @@ -95,6 +101,21 @@ cr = cairo_create (dest); cairo_translate (cr, -abs_bounds.origin.x, -abs_bounds.origin.y); + /* Apply the clip if provided one */ + if (self->clip != NULL) + { + cairo_rectangle_int_t area; + + n_rects = cairo_region_num_rectangles (self->clip); + for (guint i = 0; i < n_rects; i++) + { + cairo_region_get_rectangle (self->clip, i, &area); + cairo_rectangle (cr, area.x, area.y, area.width, area.height); + } + + cairo_clip (cr); + } + /* Clip the cairo context based on the rectangles to be drawn * within the bounding box :rect. */ @@ -168,4 +189,14 @@ self->_isOpaque = opaque; } +-(void)setClip:(cairo_region_t*)region +{ + if (region != self->clip) + { + g_clear_pointer (&self->clip, cairo_region_destroy); + if (region != NULL) + self->clip = cairo_region_reference (region); + } +} + @end diff --git a/gdk/macos/GdkMacosCairoSubview.h b/gdk/macos/GdkMacosCairoSubview.h index 9255347566..5eae734f8f 100644 --- a/gdk/macos/GdkMacosCairoSubview.h +++ b/gdk/macos/GdkMacosCairoSubview.h @@ -26,10 +26,12 @@ { BOOL _isOpaque; cairo_surface_t *cairoSurface; + cairo_region_t *clip; } -(void)setOpaque:(BOOL)opaque; -(void)setCairoSurface:(cairo_surface_t *)cairoSurface withDamage:(cairo_region_t *)region; +-(void)setClip:(cairo_region_t*)region; @end diff --git a/gdk/macos/GdkMacosCairoView.c b/gdk/macos/GdkMacosCairoView.c index 2f82488912..81ac8af6a3 100644 --- a/gdk/macos/GdkMacosCairoView.c +++ b/gdk/macos/GdkMacosCairoView.c @@ -78,6 +78,7 @@ -(void)setOpaqueRegion:(cairo_region_t *)region { + cairo_region_t *transparent_clip; NSRect abs_bounds; guint n_rects; @@ -87,6 +88,17 @@ abs_bounds = [self convertRect:[self bounds] toView:nil]; n_rects = cairo_region_num_rectangles (region); + /* First, we create a clip region for the transparent region to use so that + * we dont end up exposing too much other than the corners on CSD. + */ + transparent_clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) { + abs_bounds.origin.x, abs_bounds.origin.y, + abs_bounds.size.width, abs_bounds.size.height + }); + cairo_region_subtract (transparent_clip, region); + [(GdkMacosCairoSubview *)self->transparent setClip:transparent_clip]; + cairo_region_destroy (transparent_clip); + /* The common case (at least for opaque windows and CSD) is that we will * have either one or two opaque rectangles. If we detect that the same * number of them are available as the previous, we can just resize the