From 856728ea1074457a426c3cc9224800551849360e Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Sun, 27 Feb 2022 23:31:28 -0800 Subject: [PATCH] macos: support mix-rate monitors Previously, a single CVDisplayLink was used to drive updates for all surfaces across all monitors. It used a 'best guess' rate which would allow for updates across monitors of mixed rates. This is undesirable for situations where you might have a 144hz monitor as it does not allow for reaching up to that frame rate. Instead, we want to use a per-monitor CVDisplayLink which will fire at the rate of the monitor down to the level of updates we require. This commit does just that. When a surface crosses onto a new monitor, that monitor is used to drive the GdkFrameClock. Fixes #4732 --- gdk/macos/gdkmacosdisplay-private.h | 15 --- gdk/macos/gdkmacosdisplay.c | 105 ------------------- gdk/macos/gdkmacosmonitor-private.h | 14 ++- gdk/macos/gdkmacosmonitor.c | 139 ++++++++++++++++++++++++- gdk/macos/gdkmacossurface-private.h | 7 +- gdk/macos/gdkmacossurface.c | 151 +++++++++++++++++----------- 6 files changed, 242 insertions(+), 189 deletions(-) diff --git a/gdk/macos/gdkmacosdisplay-private.h b/gdk/macos/gdkmacosdisplay-private.h index b9f33fe20e..ef17618d61 100644 --- a/gdk/macos/gdkmacosdisplay-private.h +++ b/gdk/macos/gdkmacosdisplay-private.h @@ -68,16 +68,6 @@ struct _GdkMacosDisplay */ GQueue sorted_surfaces; - /* Our CVDisplayLink based GSource which we use to freeze/thaw the - * GdkFrameClock for the surface. - */ - GSource *frame_source; - - /* A queue of surfaces which we know are awaiting frames to be drawn. This - * uses the GdkMacosSurface.frame link. - */ - GQueue awaiting_frames; - /* The surface that is receiving keyboard events */ GdkMacosSurface *keyboard_surface; @@ -138,10 +128,6 @@ GdkMacosSurface *_gdk_macos_display_get_surface_at_display_coords (GdkMacosDisp void _gdk_macos_display_reload_monitors (GdkMacosDisplay *self); void _gdk_macos_display_surface_removed (GdkMacosDisplay *self, GdkMacosSurface *surface); -void _gdk_macos_display_add_frame_callback (GdkMacosDisplay *self, - GdkMacosSurface *surface); -void _gdk_macos_display_remove_frame_callback (GdkMacosDisplay *self, - GdkMacosSurface *surface); NSWindow *_gdk_macos_display_find_native_under_pointer (GdkMacosDisplay *self, int *x, int *y); @@ -157,7 +143,6 @@ void _gdk_macos_display_surface_resigned_key (GdkMacosDisp GdkMacosSurface *surface); void _gdk_macos_display_surface_became_key (GdkMacosDisplay *self, GdkMacosSurface *surface); -int _gdk_macos_display_get_nominal_refresh_rate (GdkMacosDisplay *self); void _gdk_macos_display_clear_sorting (GdkMacosDisplay *self); const GList *_gdk_macos_display_get_surfaces (GdkMacosDisplay *self); void _gdk_macos_display_send_button_event (GdkMacosDisplay *self, diff --git a/gdk/macos/gdkmacosdisplay.c b/gdk/macos/gdkmacosdisplay.c index 5501a16318..cb0331419d 100644 --- a/gdk/macos/gdkmacosdisplay.c +++ b/gdk/macos/gdkmacosdisplay.c @@ -231,56 +231,6 @@ gdk_macos_display_load_seat (GdkMacosDisplay *self) g_object_unref (seat); } -static gboolean -gdk_macos_display_frame_cb (gpointer data) -{ - GdkMacosDisplay *self = data; - GdkDisplayLinkSource *source; - gint64 presentation_time; - gint64 now; - GList *iter; - - g_assert (GDK_IS_MACOS_DISPLAY (self)); - - source = (GdkDisplayLinkSource *)self->frame_source; - - presentation_time = source->presentation_time; - now = g_source_get_time ((GSource *)source); - - iter = self->awaiting_frames.head; - - while (iter != NULL) - { - GdkMacosSurface *surface = iter->data; - - g_assert (GDK_IS_MACOS_SURFACE (surface)); - - iter = iter->next; - - _gdk_macos_surface_publish_timings (surface, - source->presentation_time, - source->refresh_interval); - - _gdk_macos_display_remove_frame_callback (self, surface); - - if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (surface))) - gdk_surface_thaw_updates (GDK_SURFACE (surface)); - } - - return G_SOURCE_CONTINUE; -} - -static void -gdk_macos_display_load_display_link (GdkMacosDisplay *self) -{ - self->frame_source = gdk_display_link_source_new (CGMainDisplayID ()); - g_source_set_callback (self->frame_source, - gdk_macos_display_frame_cb, - self, - NULL); - g_source_attach (self->frame_source, NULL); -} - static const char * gdk_macos_display_get_name (GdkDisplay *display) { @@ -384,7 +334,6 @@ _gdk_macos_display_surface_added (GdkMacosDisplay *self, g_assert (GDK_IS_MACOS_SURFACE (surface)); g_assert (!queue_contains (&self->sorted_surfaces, &surface->sorted)); g_assert (!queue_contains (&self->main_surfaces, &surface->main)); - g_assert (!queue_contains (&self->awaiting_frames, &surface->frame)); g_assert (surface->sorted.data == surface); g_assert (surface->main.data == surface); g_assert (surface->frame.data == surface); @@ -411,9 +360,6 @@ _gdk_macos_display_surface_removed (GdkMacosDisplay *self, if (queue_contains (&self->main_surfaces, &surface->main)) _gdk_macos_display_surface_resigned_main (self, surface); - if (queue_contains (&self->awaiting_frames, &surface->frame)) - g_queue_unlink (&self->awaiting_frames, &surface->frame); - g_return_if_fail (self->keyboard_surface != surface); } @@ -649,7 +595,6 @@ gdk_macos_display_finalize (GObject *object) g_clear_pointer (&self->active_drags, g_hash_table_unref); g_clear_pointer (&self->active_drops, g_hash_table_unref); g_clear_object (&GDK_DISPLAY (self)->clipboard); - g_clear_pointer (&self->frame_source, g_source_unref); g_clear_object (&self->monitors); g_clear_pointer (&self->name, g_free); @@ -724,9 +669,6 @@ _gdk_macos_display_open (const char *display_name) gdk_macos_display_load_seat (self); gdk_macos_display_load_clipboard (self); - - /* Load CVDisplayLink before monitors to access refresh rates */ - gdk_macos_display_load_display_link (self); _gdk_macos_display_reload_monitors (self); /* Initialize feedback from display server */ @@ -972,42 +914,6 @@ _gdk_macos_display_get_surface_at_display_coords (GdkMacosDisplay *self, return _gdk_macos_display_get_surface_at_coords (self, x_gdk, y_gdk, surface_x, surface_y); } -void -_gdk_macos_display_add_frame_callback (GdkMacosDisplay *self, - GdkMacosSurface *surface) -{ - g_return_if_fail (GDK_IS_MACOS_DISPLAY (self)); - g_return_if_fail (GDK_IS_MACOS_SURFACE (surface)); - - if (!queue_contains (&self->awaiting_frames, &surface->frame)) - { - /* Processing frames is always head to tail, so push to the - * head so that we don't possibly re-enter this right after - * adding to the queue. - */ - g_queue_push_head_link (&self->awaiting_frames, &surface->frame); - - if (self->awaiting_frames.length == 1) - gdk_display_link_source_unpause ((GdkDisplayLinkSource *)self->frame_source); - } -} - -void -_gdk_macos_display_remove_frame_callback (GdkMacosDisplay *self, - GdkMacosSurface *surface) -{ - g_return_if_fail (GDK_IS_MACOS_DISPLAY (self)); - g_return_if_fail (GDK_IS_MACOS_SURFACE (surface)); - - if (queue_contains (&self->awaiting_frames, &surface->frame)) - { - g_queue_unlink (&self->awaiting_frames, &surface->frame); - - if (self->awaiting_frames.length == 0) - gdk_display_link_source_pause ((GdkDisplayLinkSource *)self->frame_source); - } -} - NSWindow * _gdk_macos_display_find_native_under_pointer (GdkMacosDisplay *self, int *x, @@ -1027,17 +933,6 @@ _gdk_macos_display_find_native_under_pointer (GdkMacosDisplay *self, return NULL; } -int -_gdk_macos_display_get_nominal_refresh_rate (GdkMacosDisplay *self) -{ - g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), 60 * 1000); - - if (self->frame_source == NULL) - return 60 * 1000; - - return ((GdkDisplayLinkSource *)self->frame_source)->refresh_rate; -} - void _gdk_macos_display_clear_sorting (GdkMacosDisplay *self) { diff --git a/gdk/macos/gdkmacosmonitor-private.h b/gdk/macos/gdkmacosmonitor-private.h index e15f17352d..fee511d057 100644 --- a/gdk/macos/gdkmacosmonitor-private.h +++ b/gdk/macos/gdkmacosmonitor-private.h @@ -29,11 +29,15 @@ G_BEGIN_DECLS -GdkMacosMonitor *_gdk_macos_monitor_new (GdkMacosDisplay *display, - CGDirectDisplayID screen_id); -CGDirectDisplayID _gdk_macos_monitor_get_screen_id (GdkMacosMonitor *self); -gboolean _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self); -CGColorSpaceRef _gdk_macos_monitor_copy_colorspace (GdkMacosMonitor *self); +GdkMacosMonitor *_gdk_macos_monitor_new (GdkMacosDisplay *display, + CGDirectDisplayID screen_id); +CGDirectDisplayID _gdk_macos_monitor_get_screen_id (GdkMacosMonitor *self); +gboolean _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self); +CGColorSpaceRef _gdk_macos_monitor_copy_colorspace (GdkMacosMonitor *self); +void _gdk_macos_monitor_add_frame_callback (GdkMacosMonitor *self, + GdkMacosSurface *surface); +void _gdk_macos_monitor_remove_frame_callback (GdkMacosMonitor *self, + GdkMacosSurface *surface); G_END_DECLS diff --git a/gdk/macos/gdkmacosmonitor.c b/gdk/macos/gdkmacosmonitor.c index 6df1da0edc..3773ec5355 100644 --- a/gdk/macos/gdkmacosmonitor.c +++ b/gdk/macos/gdkmacosmonitor.c @@ -22,16 +22,21 @@ #include #include +#include "gdkdisplaylinksource.h" #include "gdkmacosdisplay-private.h" #include "gdkmacosmonitor-private.h" +#include "gdkmacossurface-private.h" #include "gdkmacosutils-private.h" struct _GdkMacosMonitor { - GdkMonitor parent_instance; - CGDirectDisplayID screen_id; - NSRect workarea; - guint has_opengl : 1; + GdkMonitor parent_instance; + CGDirectDisplayID screen_id; + GdkDisplayLinkSource *display_link; + NSRect workarea; + GQueue awaiting_frames; + guint has_opengl : 1; + guint in_frame : 1; }; struct _GdkMacosMonitorClass @@ -75,9 +80,26 @@ gdk_macos_monitor_get_workarea (GdkMonitor *monitor, geometry->height = self->workarea.size.height; } +static void +gdk_macos_monitor_dispose (GObject *object) +{ + GdkMacosMonitor *self = (GdkMacosMonitor *)object; + + if (self->display_link) + { + g_source_destroy ((GSource *)self->display_link); + g_clear_pointer ((GSource **)&self->display_link, g_source_unref); + } + + G_OBJECT_CLASS (gdk_macos_monitor_parent_class)->dispose (object); +} + static void gdk_macos_monitor_class_init (GdkMacosMonitorClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = gdk_macos_monitor_dispose; } static void @@ -188,6 +210,68 @@ find_screen (CGDirectDisplayID screen_id) return screen; } +static gboolean +gdk_macos_monitor_display_link_cb (GdkMacosMonitor *self) +{ + gint64 presentation_time; + gint64 refresh_interval; + gint64 now; + GList *iter; + + g_assert (GDK_IS_MACOS_MONITOR (self)); + g_assert (!self->display_link->paused); + + self->in_frame = TRUE; + + presentation_time = self->display_link->presentation_time; + refresh_interval = self->display_link->refresh_interval; + now = g_source_get_time ((GSource *)self->display_link); + + iter = self->awaiting_frames.head; + + while (iter != NULL) + { + GdkMacosSurface *surface = iter->data; + + g_assert (GDK_IS_MACOS_SURFACE (surface)); + + iter = iter->next; + + g_queue_unlink (&self->awaiting_frames, &surface->frame); + _gdk_macos_surface_frame_presented (surface, presentation_time, refresh_interval); + } + + if (self->awaiting_frames.length == 0 && !self->display_link->paused) + gdk_display_link_source_pause (self->display_link); + + self->in_frame = FALSE; + + return G_SOURCE_CONTINUE; +} + +static void +_gdk_macos_monitor_reset_display_link (GdkMacosMonitor *self, + CGDisplayModeRef mode) +{ + GSource *source; + + g_assert (GDK_IS_MACOS_MONITOR (self)); + + if (self->display_link) + { + g_source_destroy ((GSource *)self->display_link); + g_clear_pointer ((GSource **)&self->display_link, g_source_unref); + } + + source = gdk_display_link_source_new (self->screen_id, mode); + self->display_link = (GdkDisplayLinkSource *)source; + g_source_set_callback (source, + (GSourceFunc) gdk_macos_monitor_display_link_cb, + self, + NULL); + g_source_attach (source, NULL); +} + gboolean _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self) { @@ -241,7 +325,7 @@ _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self) * setting (which is also used by the frame clock). */ if (!(refresh_rate = CGDisplayModeGetRefreshRate (mode))) - refresh_rate = _gdk_macos_display_get_nominal_refresh_rate (display); + refresh_rate = 60 * 1000; gdk_monitor_set_connector (GDK_MONITOR (self), connector); gdk_monitor_set_model (GDK_MONITOR (self), name); @@ -261,6 +345,9 @@ _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self) */ self->has_opengl = !!has_opengl; + /* Create a new display link to receive feedback about when to render */ + _gdk_macos_monitor_reset_display_link (self, mode); + CGDisplayModeRelease (mode); g_free (name); g_free (connector); @@ -302,3 +389,45 @@ _gdk_macos_monitor_copy_colorspace (GdkMacosMonitor *self) return CGDisplayCopyColorSpace (self->screen_id); } + +void +_gdk_macos_monitor_add_frame_callback (GdkMacosMonitor *self, + GdkMacosSurface *surface) +{ + g_return_if_fail (GDK_IS_MACOS_MONITOR (self)); + g_return_if_fail (GDK_IS_MACOS_SURFACE (surface)); + g_return_if_fail (surface->frame.data == (gpointer)surface); + g_return_if_fail (surface->frame.prev == NULL); + g_return_if_fail (surface->frame.next == NULL); + g_return_if_fail (self->awaiting_frames.head != &surface->frame); + g_return_if_fail (self->awaiting_frames.tail != &surface->frame); + + /* Processing frames is always head to tail, so push to the + * head so that we don't possibly re-enter this right after + * adding to the queue. + */ + if (!queue_contains (&self->awaiting_frames, &surface->frame)) + { + g_queue_push_head_link (&self->awaiting_frames, &surface->frame); + + if (!self->in_frame && self->awaiting_frames.length == 1) + gdk_display_link_source_unpause (self->display_link); + } +} + +void +_gdk_macos_monitor_remove_frame_callback (GdkMacosMonitor *self, + GdkMacosSurface *surface) +{ + g_return_if_fail (GDK_IS_MACOS_MONITOR (self)); + g_return_if_fail (GDK_IS_MACOS_SURFACE (surface)); + g_return_if_fail (surface->frame.data == (gpointer)surface); + + if (queue_contains (&self->awaiting_frames, &surface->frame)) + { + g_queue_unlink (&self->awaiting_frames, &surface->frame); + + if (!self->in_frame && self->awaiting_frames.length == 0) + gdk_display_link_source_pause (self->display_link); + } +} diff --git a/gdk/macos/gdkmacossurface-private.h b/gdk/macos/gdkmacossurface-private.h index 5ac4201a42..15a7442c17 100644 --- a/gdk/macos/gdkmacossurface-private.h +++ b/gdk/macos/gdkmacossurface-private.h @@ -75,6 +75,8 @@ struct _GdkMacosSurface guint geometry_dirty : 1; guint next_frame_set : 1; guint show_on_next_swap : 1; + guint in_frame : 1; + guint awaiting_frame : 1; }; struct _GdkMacosSurfaceClass @@ -116,10 +118,11 @@ void _gdk_macos_surface_resize (GdkMacosSurface int width, int height); void _gdk_macos_surface_update_fullscreen_state (GdkMacosSurface *self); -void _gdk_macos_surface_show (GdkMacosSurface *self); -void _gdk_macos_surface_publish_timings (GdkMacosSurface *self, +void _gdk_macos_surface_request_frame (GdkMacosSurface *self); +void _gdk_macos_surface_frame_presented (GdkMacosSurface *self, gint64 predicted_presentation_time, gint64 refresh_interval); +void _gdk_macos_surface_show (GdkMacosSurface *self); void _gdk_macos_surface_synthesize_null_key (GdkMacosSurface *self); void _gdk_macos_surface_move (GdkMacosSurface *self, int x, diff --git a/gdk/macos/gdkmacossurface.c b/gdk/macos/gdkmacossurface.c index cf9d7067f8..ac2353dd03 100644 --- a/gdk/macos/gdkmacossurface.c +++ b/gdk/macos/gdkmacossurface.c @@ -63,6 +63,73 @@ window_is_fullscreen (GdkMacosSurface *self) return ([self->window styleMask] & NSWindowStyleMaskFullScreen) != 0; } +void +_gdk_macos_surface_request_frame (GdkMacosSurface *self) +{ + g_assert (GDK_IS_MACOS_SURFACE (self)); + + if (self->awaiting_frame) + return; + + self->awaiting_frame = TRUE; + _gdk_macos_monitor_add_frame_callback (GDK_MACOS_MONITOR (self->best_monitor), self); + gdk_surface_freeze_updates (GDK_SURFACE (self)); +} + +static void +_gdk_macos_surface_cancel_frame (GdkMacosSurface *self) +{ + g_assert (GDK_IS_MACOS_SURFACE (self)); + + if (!self->awaiting_frame) + return; + + self->awaiting_frame = FALSE; + _gdk_macos_monitor_remove_frame_callback (GDK_MACOS_MONITOR (self->best_monitor), self); + gdk_surface_thaw_updates (GDK_SURFACE (self)); +} + +void +_gdk_macos_surface_frame_presented (GdkMacosSurface *self, + gint64 presentation_time, + gint64 refresh_interval) +{ + GdkFrameTimings *timings; + GdkFrameClock *frame_clock; + + g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); + + self->awaiting_frame = FALSE; + + if (GDK_SURFACE_DESTROYED (self)) + return; + + frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self)); + + if (self->pending_frame_counter) + { + timings = gdk_frame_clock_get_timings (frame_clock, self->pending_frame_counter); + + if (timings != NULL) + { + timings->presentation_time = presentation_time - refresh_interval; + timings->complete = TRUE; + } + + self->pending_frame_counter = 0; + } + + timings = gdk_frame_clock_get_current_timings (frame_clock); + + if (timings != NULL) + { + timings->refresh_interval = refresh_interval; + timings->predicted_presentation_time = presentation_time; + } + + if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self))) + gdk_surface_thaw_updates (GDK_SURFACE (self)); +} void _gdk_macos_surface_reposition_children (GdkMacosSurface *self) @@ -131,8 +198,6 @@ gdk_macos_surface_hide (GdkSurface *surface) self->show_on_next_swap = FALSE; - _gdk_macos_display_remove_frame_callback (GDK_MACOS_DISPLAY (surface->display), self); - was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)); was_key = [self->window isKeyWindow]; @@ -157,8 +222,12 @@ gdk_macos_surface_hide (GdkSurface *surface) } } - if (was_mapped) - gdk_surface_freeze_updates (GDK_SURFACE (self)); + if (self->awaiting_frame) + { + self->awaiting_frame = FALSE; + _gdk_macos_monitor_remove_frame_callback (GDK_MACOS_MONITOR (self->best_monitor), self); + gdk_surface_freeze_updates (surface); + } } static int @@ -202,6 +271,7 @@ gdk_macos_surface_begin_frame (GdkMacosSurface *self) { g_assert (GDK_IS_MACOS_SURFACE (self)); + self->in_frame = TRUE; } static void @@ -222,11 +292,9 @@ gdk_macos_surface_end_frame (GdkMacosSurface *self) if ((timings = gdk_frame_clock_get_current_timings (frame_clock))) self->pending_frame_counter = timings->frame_counter; - if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self))) - { - _gdk_macos_display_add_frame_callback (GDK_MACOS_DISPLAY (display), self); - gdk_surface_freeze_updates (GDK_SURFACE (self)); - } + self->in_frame = FALSE; + + _gdk_macos_surface_request_frame (self); } static void @@ -400,7 +468,16 @@ gdk_macos_surface_destroy (GdkSurface *surface, GdkMacosWindow *window = g_steal_pointer (&self->window); GdkFrameClock *frame_clock; - g_clear_object (&self->best_monitor); + if (self->best_monitor) + { + if (self->awaiting_frame) + { + _gdk_macos_monitor_remove_frame_callback (GDK_MACOS_MONITOR (self->best_monitor), self); + self->awaiting_frame = FALSE; + } + + g_clear_object (&self->best_monitor); + } if ((frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self)))) { @@ -787,41 +864,6 @@ _gdk_macos_surface_configure (GdkMacosSurface *self) _gdk_macos_surface_reposition_children (self); } -void -_gdk_macos_surface_publish_timings (GdkMacosSurface *self, - gint64 presentation_time, - gint64 refresh_interval) -{ - GdkFrameTimings *timings; - GdkFrameClock *frame_clock; - - g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); - - if (!(frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self)))) - return; - - if (self->pending_frame_counter) - { - timings = gdk_frame_clock_get_timings (frame_clock, self->pending_frame_counter); - - if (timings != NULL) - { - timings->presentation_time = presentation_time - refresh_interval; - timings->complete = TRUE; - } - - self->pending_frame_counter = 0; - } - - timings = gdk_frame_clock_get_current_timings (frame_clock); - - if (timings != NULL) - { - timings->refresh_interval = refresh_interval; - timings->predicted_presentation_time = presentation_time; - } -} - void _gdk_macos_surface_show (GdkMacosSurface *self) { @@ -832,22 +874,15 @@ _gdk_macos_surface_show (GdkMacosSurface *self) if (GDK_SURFACE_DESTROYED (self)) return; - was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)); - - if (!was_mapped) - gdk_surface_set_is_mapped (GDK_SURFACE (self), TRUE); - _gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display)); - self->show_on_next_swap = TRUE; + was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)); + if (!was_mapped) { - if (gdk_surface_get_mapped (GDK_SURFACE (self))) - { - _gdk_macos_surface_configure (self); - gdk_surface_thaw_updates (GDK_SURFACE (self)); - } + gdk_surface_set_is_mapped (GDK_SURFACE (self), TRUE); + gdk_surface_thaw_updates (GDK_SURFACE (self)); } } @@ -994,6 +1029,8 @@ _gdk_macos_surface_monitor_changed (GdkMacosSurface *self) g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); + _gdk_macos_surface_cancel_frame (self); + rect.x = self->root_x; rect.y = self->root_y; rect.width = GDK_SURFACE (self)->width; @@ -1056,8 +1093,8 @@ _gdk_macos_surface_monitor_changed (GdkMacosSurface *self) } _gdk_macos_surface_configure (self); - gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL); + _gdk_macos_surface_request_frame (self); } GdkMonitor * -- 2.30.2