From: Christian Hergert Date: Wed, 16 Feb 2022 10:50:51 +0000 (-0800) Subject: macos: fix configure, move-resize, and compute-size X-Git-Tag: archive/raspbian/4.6.5+ds-1+rpi1~1^2~19^2~3^2~84^2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=4c08d1643f4b92b5e3c53c5f02a3508d42625cba;p=gtk4.git macos: fix configure, move-resize, and compute-size This significantly cleans up how we handle various move-resize, compute- size, and configure (notification of changes) in the macOS GDK backend. Originally when prototyping this backend, there were some bits that came over from the quartz backend and some bits which did not. It got confusing and so this makes an attempt to knock down all that technical debt. It is much simpler now in that the GdkMacosSurface makes requests of the GdkMacosWindow, and the GdkMacosWindow notifies the GdkMacosSurface of changes that happen. User resizes are delayed until the next compute-size so that we are much closer to the layout phase, reducing chances for in-between frames. This also improves the situation of leaving maximized state so that a grab and drag feels like you'd expect on other platforms. I removed the opacity hack we had in before, because that is all coming out anyway and it's a bit obnoxious to maintain through the async flows here. --- diff --git a/gdk/macos/GdkMacosWindow.c b/gdk/macos/GdkMacosWindow.c index 8dda79ab4d..0bb7521f16 100644 --- a/gdk/macos/GdkMacosWindow.c +++ b/gdk/macos/GdkMacosWindow.c @@ -203,76 +203,20 @@ typedef NSString *CALayerContentsGravity; } } --(void)windowDidUnmaximize +-(void)setFrame:(NSRect)frame display:(BOOL)display { - NSWindowStyleMask style_mask = [self styleMask]; - - gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), GDK_TOPLEVEL_STATE_MAXIMIZED, 0); + NSRect contentRect = [self contentRectForFrameRect:frame]; + GdkSurface *surface = GDK_SURFACE (gdk_surface); + gboolean maximized = (surface->state & GDK_TOPLEVEL_STATE_MAXIMIZED) != 0; - /* If we are using CSD, then we transitioned to an opaque - * window while we were maximized. Now we need to drop that - * as we are leaving maximized state. - */ - if ((style_mask & NSWindowStyleMaskTitled) == 0 && [self isOpaque]) + if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, frame)) { - GdkSurface *surface = GDK_SURFACE ([self gdkSurface]); - - [self setOpaque:NO]; - - /* Force updating of various styling, regions, etc */ + gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_MAXIMIZED, 0); _gdk_surface_update_size (surface); } -} --(void)windowDidMove:(NSNotification *)aNotification -{ - GdkSurface *surface = GDK_SURFACE (gdk_surface); - gboolean maximized = (surface->state & GDK_TOPLEVEL_STATE_MAXIMIZED) != 0; - - /* In case the window is changed when maximized remove the maximized state */ - if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, [self frame])) - [self windowDidUnmaximize]; - - _gdk_macos_surface_update_position (gdk_surface); - _gdk_macos_surface_reposition_children (gdk_surface); - - [self checkSendEnterNotify]; -} - --(void)windowDidResize:(NSNotification *)aNotification -{ - NSRect content_rect; - GdkSurface *surface; - GdkDisplay *display; - gboolean maximized; - - surface = GDK_SURFACE (gdk_surface); - display = gdk_surface_get_display (surface); - - content_rect = [self contentRectForFrameRect:[self frame]]; - maximized = (surface->state & GDK_TOPLEVEL_STATE_MAXIMIZED) != 0; - - /* see same in windowDidMove */ - if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, [self frame])) - [self windowDidUnmaximize]; - - surface->width = content_rect.size.width; - surface->height = content_rect.size.height; - - /* Certain resize operations (e.g. going fullscreen), also move the - * origin of the window. - */ - _gdk_macos_surface_update_position (GDK_MACOS_SURFACE (surface)); - - [[self contentView] setFrame:NSMakeRect (0, 0, surface->width, surface->height)]; - - _gdk_surface_update_size (surface); - - gdk_surface_request_layout (surface); - - _gdk_macos_surface_reposition_children (gdk_surface); - - [self checkSendEnterNotify]; + [super setFrame:frame display:display]; + [[self contentView] setFrame:NSMakeRect (0, 0, contentRect.size.width, contentRect.size.height)]; } -(id)initWithContentRect:(NSRect)contentRect @@ -418,12 +362,23 @@ typedef NSString *CALayerContentsGravity; windowFrame.origin.x = new_origin.x; windowFrame.origin.y = new_origin.y; - /* And now apply the frame to the window */ - [self setFrameOrigin:NSMakePoint(new_origin.x, new_origin.y)]; + [self setFrame:NSMakeRect (new_origin.x, new_origin.y, + window_gdk.width, window_gdk.height) + display:YES]; return YES; } +-(void)windowDidMove:(NSNotification *)notification +{ + _gdk_macos_surface_configure ([self gdkSurface]); +} + +- (void)windowDidResize:(NSNotification *)notification +{ + _gdk_macos_surface_configure ([self gdkSurface]); +} + /* Used by gdkmacosdisplay-translate.c to decide if our sendEvent() handler * above will see the event or if it will be subjected to standard processing * by GDK. @@ -435,6 +390,7 @@ typedef NSString *CALayerContentsGravity; -(void)beginManualMove { + gboolean maximized = GDK_SURFACE (gdk_surface)->state & GDK_TOPLEVEL_STATE_MAXIMIZED; NSPoint initialMoveLocation; GdkPoint point; GdkMonitor *monitor; @@ -453,6 +409,13 @@ typedef NSString *CALayerContentsGravity; initialMoveLocation = [NSEvent mouseLocation]; + if (maximized) + [self setFrame:NSMakeRect (initialMoveLocation.x - (int)lastUnmaximizedFrame.size.width/2, + initialMoveLocation.y, + lastUnmaximizedFrame.size.width, + lastUnmaximizedFrame.size.height) + display:YES]; + _gdk_macos_display_from_display_coords ([self gdkDisplay], initialMoveLocation.x, initialMoveLocation.y, @@ -544,15 +507,7 @@ typedef NSString *CALayerContentsGravity; new_frame.size.height = min_size.height; } - /* We could also apply aspect ratio: - new_frame.size.height = new_frame.size.width / [self aspectRatio].width * [self aspectRatio].height; - */ - - [self setFrame:new_frame display:YES]; - - /* Let the resizing be handled by GTK. */ - if (g_main_context_pending (NULL)) - g_main_context_iteration (NULL, FALSE); + _gdk_macos_surface_user_resize ([self gdkSurface], new_frame); inTrackManualResize = NO; @@ -561,49 +516,46 @@ typedef NSString *CALayerContentsGravity; -(void)beginManualResize:(GdkSurfaceEdge)edge { + CALayerContentsGravity gravity = kCAGravityBottomLeft; + if (inMove || inManualMove || inManualResize) return; inManualResize = YES; resizeEdge = edge; - if (GDK_IS_MACOS_GL_VIEW ([self contentView])) + switch (edge) { - CALayerContentsGravity gravity = kCAGravityBottomLeft; + default: + case GDK_SURFACE_EDGE_NORTH: + gravity = kCAGravityTopLeft; + break; - switch (edge) - { - default: - case GDK_SURFACE_EDGE_NORTH: - gravity = kCAGravityTopLeft; - break; - - case GDK_SURFACE_EDGE_NORTH_WEST: - gravity = kCAGravityTopRight; - break; - - case GDK_SURFACE_EDGE_SOUTH_WEST: - case GDK_SURFACE_EDGE_WEST: - gravity = kCAGravityBottomRight; - break; - - case GDK_SURFACE_EDGE_SOUTH: - case GDK_SURFACE_EDGE_SOUTH_EAST: - gravity = kCAGravityBottomLeft; - break; - - case GDK_SURFACE_EDGE_EAST: - gravity = kCAGravityBottomLeft; - break; - - case GDK_SURFACE_EDGE_NORTH_EAST: - gravity = kCAGravityTopLeft; - break; - } + case GDK_SURFACE_EDGE_NORTH_WEST: + gravity = kCAGravityTopRight; + break; + + case GDK_SURFACE_EDGE_SOUTH_WEST: + case GDK_SURFACE_EDGE_WEST: + gravity = kCAGravityBottomRight; + break; + + case GDK_SURFACE_EDGE_SOUTH: + case GDK_SURFACE_EDGE_SOUTH_EAST: + gravity = kCAGravityBottomLeft; + break; + + case GDK_SURFACE_EDGE_EAST: + gravity = kCAGravityBottomLeft; + break; - [[[self contentView] layer] setContentsGravity:gravity]; + case GDK_SURFACE_EDGE_NORTH_EAST: + gravity = kCAGravityTopLeft; + break; } + [[[self contentView] layer] setContentsGravity:gravity]; + initialResizeFrame = [self frame]; initialResizeLocation = convert_nspoint_to_screen (self, [self mouseLocationOutsideOfEventStream]); } @@ -767,7 +719,6 @@ typedef NSString *CALayerContentsGravity; if (state & GDK_TOPLEVEL_STATE_MAXIMIZED) { lastMaximizedFrame = newFrame; - [self windowDidUnmaximize]; } else { @@ -782,16 +733,7 @@ typedef NSString *CALayerContentsGravity; -(void)windowDidEndLiveResize:(NSNotification *)aNotification { - gboolean maximized = GDK_SURFACE (gdk_surface)->state & GDK_TOPLEVEL_STATE_MAXIMIZED; - inMaximizeTransition = NO; - - /* Even if this is CSD, we want to be opaque while maximized - * to speed up compositing by allowing the display server to - * avoid costly blends. - */ - if (maximized) - [self setOpaque:YES]; } -(NSSize)window:(NSWindow *)window willUseFullScreenContentSize:(NSSize)proposedSize diff --git a/gdk/macos/gdkmacosdisplay.c b/gdk/macos/gdkmacosdisplay.c index 8d3aa0224e..656ceb8097 100644 --- a/gdk/macos/gdkmacosdisplay.c +++ b/gdk/macos/gdkmacosdisplay.c @@ -185,7 +185,7 @@ gdk_macos_display_monitors_changed_cb (CFNotificationCenterRef center, g_assert (GDK_IS_MACOS_SURFACE (surface)); if (GDK_IS_TOPLEVEL (surface)) - _gdk_macos_surface_update_position (surface); + _gdk_macos_surface_configure (surface); } } diff --git a/gdk/macos/gdkmacossurface-private.h b/gdk/macos/gdkmacossurface-private.h index ccb8a83179..0cfe0a8a2f 100644 --- a/gdk/macos/gdkmacossurface-private.h +++ b/gdk/macos/gdkmacossurface-private.h @@ -53,6 +53,13 @@ struct _GdkMacosSurface int root_x; int root_y; + struct { + int root_x; + int root_y; + int width; + int height; + } next_layout; + int shadow_top; int shadow_right; int shadow_bottom; @@ -102,7 +109,6 @@ void _gdk_macos_surface_resize (GdkMacosSurface int width, int height); void _gdk_macos_surface_update_fullscreen_state (GdkMacosSurface *self); -void _gdk_macos_surface_update_position (GdkMacosSurface *self); void _gdk_macos_surface_show (GdkMacosSurface *self); void _gdk_macos_surface_publish_timings (GdkMacosSurface *self, gint64 predicted_presentation_time, @@ -121,6 +127,9 @@ void _gdk_macos_surface_move_resize (GdkMacosSurface int y, int width, int height); +void _gdk_macos_surface_configure (GdkMacosSurface *self); +void _gdk_macos_surface_user_resize (GdkMacosSurface *self, + CGRect new_frame); gboolean _gdk_macos_surface_is_tracking (GdkMacosSurface *self, NSTrackingArea *area); void _gdk_macos_surface_monitor_changed (GdkMacosSurface *self); diff --git a/gdk/macos/gdkmacossurface.c b/gdk/macos/gdkmacossurface.c index c5cf05edf8..967cbd94b4 100644 --- a/gdk/macos/gdkmacossurface.c +++ b/gdk/macos/gdkmacossurface.c @@ -419,15 +419,6 @@ gdk_macos_surface_constructed (GObject *object) G_OBJECT_CLASS (gdk_macos_surface_parent_class)->constructed (object); - if (self->window != NULL) - { - NSRect bounds = [[self->window contentView] bounds]; - - GDK_SURFACE (self)->width = bounds.size.width; - GDK_SURFACE (self)->height = bounds.size.height; - _gdk_macos_surface_update_position (self); - } - if ((frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self)))) { g_signal_connect_object (frame_clock, @@ -441,6 +432,9 @@ gdk_macos_surface_constructed (GObject *object) self, G_CONNECT_SWAPPED); } + + if (self->window != NULL) + _gdk_macos_surface_configure (self); } static void @@ -699,12 +693,21 @@ _gdk_macos_surface_update_fullscreen_state (GdkMacosSurface *self) } void -_gdk_macos_surface_update_position (GdkMacosSurface *self) +_gdk_macos_surface_configure (GdkMacosSurface *self) { - GdkSurface *surface = GDK_SURFACE (self); - GdkDisplay *display = gdk_surface_get_display (surface); - NSRect frame_rect = [self->window frame]; - NSRect content_rect = [self->window contentRectForFrameRect:frame_rect]; + GdkMacosDisplay *display; + GdkSurface *surface = (GdkSurface *)self; + NSRect frame_rect; + NSRect content_rect; + + g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); + + if (GDK_SURFACE_DESTROYED (self)) + return; + + display = GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display); + frame_rect = [self->window frame]; + content_rect = [self->window contentRectForFrameRect:frame_rect]; _gdk_macos_display_from_display_coords (GDK_MACOS_DISPLAY (display), content_rect.origin.x, @@ -721,6 +724,19 @@ _gdk_macos_surface_update_position (GdkMacosSurface *self) surface->x = self->root_x; surface->y = self->root_y; } + + if (surface->width != content_rect.size.width || + surface->height != content_rect.size.height) + { + surface->width = content_rect.size.width; + surface->height = content_rect.size.height; + + _gdk_surface_update_size (surface); + gdk_surface_request_layout (surface); + gdk_surface_invalidate_rect (surface, NULL); + } + + _gdk_macos_surface_reposition_children (self); } void @@ -781,8 +797,7 @@ _gdk_macos_surface_show (GdkMacosSurface *self) { if (gdk_surface_get_mapped (GDK_SURFACE (self))) { - _gdk_macos_surface_update_position (self); - gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL); + _gdk_macos_surface_configure (self); gdk_surface_thaw_updates (GDK_SURFACE (self)); } } @@ -882,7 +897,6 @@ _gdk_macos_surface_move_resize (GdkMacosSurface *self, GdkDisplay *display; NSRect content_rect; NSRect frame_rect; - gboolean size_changed; g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); @@ -906,28 +920,43 @@ _gdk_macos_surface_move_resize (GdkMacosSurface *self, if (y == -1) y = self->root_y; - size_changed = height != surface->height || width != surface->width; - - if (GDK_IS_MACOS_SURFACE (surface->parent)) - { - surface->x = x - GDK_MACOS_SURFACE (surface->parent)->root_x; - surface->y = y - GDK_MACOS_SURFACE (surface->parent)->root_y; - } - else - { - surface->x = x; - surface->y = y; - } - _gdk_macos_display_to_display_coords (GDK_MACOS_DISPLAY (display), - x, y + height, &x, &y); + x, y + height, + &x, &y); content_rect = NSMakeRect (x, y, width, height); frame_rect = [self->window frameRectForContentRect:content_rect]; [self->window setFrame:frame_rect display:YES]; +} + +void +_gdk_macos_surface_user_resize (GdkMacosSurface *self, + CGRect new_frame) +{ + GdkMacosDisplay *display; + CGRect content_rect; + int root_x, root_y; + + g_return_if_fail (GDK_IS_MACOS_SURFACE (self)); + g_return_if_fail (GDK_IS_TOPLEVEL (self)); + + if (GDK_SURFACE_DESTROYED (self)) + return; + + display = GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display); + content_rect = [self->window contentRectForFrameRect:new_frame]; + + _gdk_macos_display_from_display_coords (display, + new_frame.origin.x, + new_frame.origin.y + new_frame.size.height, + &root_x, &root_y); - if (size_changed) - gdk_surface_invalidate_rect (surface, NULL); + self->next_layout.root_x = root_x; + self->next_layout.root_y = root_y; + self->next_layout.width = content_rect.size.width; + self->next_layout.height = content_rect.size.height; + + gdk_surface_request_layout (GDK_SURFACE (self)); } gboolean @@ -995,7 +1024,8 @@ _gdk_macos_surface_monitor_changed (GdkMacosSurface *self) g_object_unref (monitor); } - _gdk_surface_update_size (GDK_SURFACE (self)); + _gdk_macos_surface_configure (self); + gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL); } diff --git a/gdk/macos/gdkmacostoplevelsurface-private.h b/gdk/macos/gdkmacostoplevelsurface-private.h index b0bddfa0c1..1404aa14fe 100644 --- a/gdk/macos/gdkmacostoplevelsurface-private.h +++ b/gdk/macos/gdkmacostoplevelsurface-private.h @@ -35,6 +35,8 @@ struct _GdkMacosToplevelSurface { GdkMacosSurface parent_instance; GdkToplevelLayout *layout; + int last_computed_width; + int last_computed_height; guint decorated : 1; }; diff --git a/gdk/macos/gdkmacostoplevelsurface.c b/gdk/macos/gdkmacostoplevelsurface.c index 17b1cec708..bb2a77f256 100644 --- a/gdk/macos/gdkmacostoplevelsurface.c +++ b/gdk/macos/gdkmacostoplevelsurface.c @@ -381,11 +381,11 @@ static gboolean _gdk_macos_toplevel_surface_compute_size (GdkSurface *surface) { GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)surface; + GdkMacosSurface *macos_surface = (GdkMacosSurface *)surface; GdkToplevelSize size; GdkDisplay *display; GdkMonitor *monitor; int bounds_width, bounds_height; - int width, height; GdkGeometry geometry; GdkSurfaceHints mask; @@ -419,9 +419,6 @@ _gdk_macos_toplevel_surface_compute_size (GdkSurface *surface) g_warn_if_fail (size.width > 0); g_warn_if_fail (size.height > 0); - width = surface->width; - height = surface->height; - if (self->layout != NULL && gdk_toplevel_layout_get_resizable (self->layout)) { @@ -437,16 +434,63 @@ _gdk_macos_toplevel_surface_compute_size (GdkSurface *surface) } if (size.shadow.is_valid) - _gdk_macos_surface_set_shadow (GDK_MACOS_SURFACE (surface), + _gdk_macos_surface_set_shadow (macos_surface, size.shadow.top, size.shadow.right, size.shadow.bottom, size.shadow.left); - gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height); + _gdk_macos_surface_set_geometry_hints (macos_surface, &geometry, mask); - _gdk_macos_surface_set_geometry_hints (GDK_MACOS_SURFACE (self), &geometry, mask); - _gdk_macos_surface_resize (GDK_MACOS_SURFACE (self), width, height); + if (surface->state & (GDK_TOPLEVEL_STATE_FULLSCREEN | + GDK_TOPLEVEL_STATE_MAXIMIZED | + GDK_TOPLEVEL_STATE_TILED | + GDK_TOPLEVEL_STATE_TOP_TILED | + GDK_TOPLEVEL_STATE_RIGHT_TILED | + GDK_TOPLEVEL_STATE_BOTTOM_TILED | + GDK_TOPLEVEL_STATE_LEFT_TILED | + GDK_TOPLEVEL_STATE_MINIMIZED)) + return FALSE; + + /* If we delayed a user resize until the beginning of the frame, + * apply it now so we can start processing updates for it. + */ + if (macos_surface->next_layout.width > 0 && + macos_surface->next_layout.height > 0) + { + int root_x = macos_surface->next_layout.root_x; + int root_y = macos_surface->next_layout.root_y; + int width = macos_surface->next_layout.width; + int height = macos_surface->next_layout.height; + + gdk_surface_constrain_size (&geometry, mask, + width, height, + &width, &height); + + macos_surface->next_layout.width = 0; + macos_surface->next_layout.height = 0; + + _gdk_macos_surface_move_resize (macos_surface, + root_x, root_y, + width, height); + + return FALSE; + } + + gdk_surface_constrain_size (&geometry, mask, + size.width, size.height, + &size.width, &size.height); + + if ((size.width != self->last_computed_width || + size.height != self->last_computed_height) && + (size.width != surface->width || + size.height != surface->height)) + { + self->last_computed_width = size.width; + self->last_computed_height = size.height; + + _gdk_macos_surface_resize (macos_surface, size.width, size.height); + } return FALSE; }