From 9efd521ea67c73cfbe30120a7b7f65550549b904 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 18 Mar 2024 10:40:42 -0600 Subject: [PATCH] (GDK) keep our own record of invalidated rectangles for GdkQuartzView macOS has broken its exposure/redraw model at least twice by always providing the entire area of an NSView for every call to drawRect, and cannot provide the list of rects. This change expands the tracking done using the needs_display_region, and does so directly via the objective C methods of an NSView (and its derived children like GdkQuartzView). The result is that when we send an expose signal, GDK/GTK code can obtain an accurate list of the invalidated rects if desired, and thus avoiding redrawing the entire contents of a window --- libs/tk/ydk/quartz/GdkQuartzView.c | 153 +++++++++++++++++++++++--- libs/tk/ydk/quartz/gdkwindow-quartz.c | 10 -- 2 files changed, 136 insertions(+), 27 deletions(-) diff --git a/libs/tk/ydk/quartz/GdkQuartzView.c b/libs/tk/ydk/quartz/GdkQuartzView.c index bf7b5d3a04..f6682e68ed 100644 --- a/libs/tk/ydk/quartz/GdkQuartzView.c +++ b/libs/tk/ydk/quartz/GdkQuartzView.c @@ -602,6 +602,72 @@ gdk_screen_get_rgba_colormap (_gdk_screen); } +- (void) setNeedsDisplay:(BOOL)yn +{ + GdkWindowObject *private; + GdkWindowImplQuartz *impl; + NSRect nsrect = [self bounds]; + GdkRectangle r = { nsrect.origin.x, nsrect.origin.y, nsrect.size.width, nsrect.size.height }; + + private = GDK_WINDOW_OBJECT (gdk_window); + impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); + + if (!impl->needs_display_region) + impl->needs_display_region = gdk_region_rectangle (&r); + else + gdk_region_union_with_rect (impl->needs_display_region, &r); + +#if 0 + gint nrects; + GdkRectangle* rects; + + gdk_region_get_rectangles (impl->needs_display_region, &rects, &nrects); + printf ("SND %p INVALID with %d rects\n", impl, nrects); + for (gint n = 0; n < nrects; ++n) { + printf ("\t%d,%d %d x %d\n", rects[n].x, rects[n].y, rects[n].width, rects[n].height); + } +#endif + + [super setNeedsDisplay:yn]; +} + +- (void) setNeedsDisplayInRect:(NSRect)rect +{ + GdkWindowObject *private; + GdkWindowImplQuartz *impl; + GdkRectangle r = { rect.origin.x, rect.origin.y, rect.size.width, rect.size.height }; + + if (r.width >= 2147483647 || r.height >= 2147483647) { + NSRect bounds = [self bounds]; + r.x = 0; + r.y = 0; + r.width = bounds.size.width; + r.height = bounds.size.height; + } + + private = GDK_WINDOW_OBJECT (gdk_window); + impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); + + if (!impl->needs_display_region) + impl->needs_display_region = gdk_region_rectangle (&r); + else + gdk_region_union_with_rect (impl->needs_display_region, &r); + +#if 0 + gint nrects; + GdkRectangle* rects; + + gdk_region_get_rectangles (impl->needs_display_region, &rects, &nrects); + printf ("SNDiR %p INVALID with %d rects\n", impl, nrects); + for (gint n = 0; n < nrects; ++n) { + printf ("\t%d,%d %d x %d\n", rects[n].x, rects[n].y, rects[n].width, rects[n].height); + } +#endif + + + [super setNeedsDisplayInRect:rect]; +} + -(void)drawRect: (NSRect)rect { GdkRectangle gdk_rect; @@ -647,31 +713,44 @@ return; } - /* Clear our own bookkeeping of regions that need display */ - if (impl->needs_display_region) - { - gdk_region_destroy (impl->needs_display_region); - impl->needs_display_region = NULL; + if (!impl->needs_display_region) { + [self getRectsBeingDrawn: &drawn_rects count: &count]; + region = gdk_region_new (); + + for (i = 0; i < count; i++) + { + gdk_rect.x = drawn_rects[i].origin.x; + gdk_rect.y = drawn_rects[i].origin.y; + gdk_rect.width = drawn_rects[i].size.width; + gdk_rect.height = drawn_rects[i].size.height; + + gdk_region_union_with_rect (region, &gdk_rect); } + } else { + region = impl->needs_display_region; + } - [self getRectsBeingDrawn: &drawn_rects count: &count]; - region = gdk_region_new (); - - for (i = 0; i < count; i++) - { - gdk_rect.x = drawn_rects[i].origin.x; - gdk_rect.y = drawn_rects[i].origin.y; - gdk_rect.width = drawn_rects[i].size.width; - gdk_rect.height = drawn_rects[i].size.height; - - gdk_region_union_with_rect (region, &gdk_rect); - } +#if 0 + gint nrects; + GdkRectangle* rects; + gdk_region_get_rectangles (region, &rects, &nrects); + printf ("%p drawRect with %d rects\n", impl, nrects); + for (gint n = 0; n < nrects; ++n) { + printf ("\t%d,%d %d x %d\n", rects[n].x, rects[n].y, rects[n].width, rects[n].height); + } +#endif + impl->in_paint_rect_count++; /* this essentially generates an expose event */ _gdk_window_process_updates_recurse (gdk_window, region); impl->in_paint_rect_count--; + if (impl->needs_display_region) + { + impl->needs_display_region = NULL; + } + gdk_region_destroy (region); if (needsInvalidateShadow) @@ -681,6 +760,46 @@ } } +- (void) reshape +{ + GdkWindowObject *private; + GdkWindowImplQuartz *impl; + GdkRectangle r; + + [super reshape]; + + NSRect bounds = [self bounds]; + + private = GDK_WINDOW_OBJECT (gdk_window); + impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); + + if (impl->needs_display_region) { + gdk_region_destroy (impl->needs_display_region); + } + + r.x = 0; + r.y = 0; + r.width = bounds.size.width; + r.height = bounds.size.height; + + if (impl->needs_display_region) + gdk_region_destroy (impl->needs_display_region); + + impl->needs_display_region = gdk_region_rectangle (&r); + +#if 0 + gint nrects; + GdkRectangle* rects; + + gdk_region_get_rectangles (impl->needs_display_region, &rects, &nrects); + printf ("RS %p INVALID with %d rects\n", impl, nrects); + for (gint n = 0; n < nrects; ++n) { + printf ("\t%d,%d %d x %d\n", rects[n].x, rects[n].y, rects[n].width, rects[n].height); + } +#endif + +} + -(void)setNeedsInvalidateShadow: (BOOL)invalidate { needsInvalidateShadow = invalidate; diff --git a/libs/tk/ydk/quartz/gdkwindow-quartz.c b/libs/tk/ydk/quartz/gdkwindow-quartz.c index 4660d2629d..9ae5afb4d9 100644 --- a/libs/tk/ydk/quartz/gdkwindow-quartz.c +++ b/libs/tk/ydk/quartz/gdkwindow-quartz.c @@ -282,11 +282,6 @@ _gdk_quartz_window_set_needs_display_in_rect (GdkWindow *window, private = GDK_WINDOW_OBJECT (window); impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); - if (!impl->needs_display_region) - impl->needs_display_region = gdk_region_new (); - - gdk_region_union_with_rect (impl->needs_display_region, rect); - [impl->view setNeedsDisplayInRect:NSMakeRect (rect->x, rect->y, rect->width, rect->height)]; @@ -304,11 +299,6 @@ _gdk_quartz_window_set_needs_display_in_region (GdkWindow *window, private = GDK_WINDOW_OBJECT (window); impl = GDK_WINDOW_IMPL_QUARTZ (private->impl); - if (!impl->needs_display_region) - impl->needs_display_region = gdk_region_new (); - - gdk_region_union (impl->needs_display_region, region); - gdk_region_get_rectangles (region, &rects, &n_rects); for (i = 0; i < n_rects; i++)