[gtk/wip/chergert/macos-fix-toplevel-resize: 7/7] macos: fix configure, move-resize, and compute-size
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/chergert/macos-fix-toplevel-resize: 7/7] macos: fix configure, move-resize, and compute-size
- Date: Wed, 16 Feb 2022 10:57:33 +0000 (UTC)
commit 0f1efff785013a33e7b66c447b406b2fa9345230
Author: Christian Hergert <christian hergert me>
Date: Wed Feb 16 02:50:51 2022 -0800
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.
gdk/macos/GdkMacosWindow.c | 166 +++++++++-------------------
gdk/macos/gdkmacosdisplay.c | 2 +-
gdk/macos/gdkmacossurface-private.h | 11 +-
gdk/macos/gdkmacossurface.c | 98 ++++++++++------
gdk/macos/gdkmacostoplevelsurface-private.h | 2 +
gdk/macos/gdkmacostoplevelsurface.c | 60 ++++++++--
6 files changed, 179 insertions(+), 160 deletions(-)
---
diff --git a/gdk/macos/GdkMacosWindow.c b/gdk/macos/GdkMacosWindow.c
index 8dda79ab4d..8dcccf5434 100644
--- a/gdk/macos/GdkMacosWindow.c
+++ b/gdk/macos/GdkMacosWindow.c
@@ -203,76 +203,22 @@ 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);
+ [super setFrame:frame display:display];
+ [[self contentView] setFrame:NSMakeRect (0, 0, contentRect.size.width, contentRect.size.height)];
- gdk_surface_request_layout (surface);
-
- _gdk_macos_surface_reposition_children (gdk_surface);
-
- [self checkSendEnterNotify];
+ _gdk_macos_surface_configure ([self gdkSurface]);
}
-(id)initWithContentRect:(NSRect)contentRect
@@ -418,8 +364,9 @@ 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;
}
@@ -435,6 +382,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 +401,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 +499,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 +508,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;
- [[[self contentView] layer] setContentsGravity:gravity];
+ 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;
}
+ [[[self contentView] layer] setContentsGravity:gravity];
+
initialResizeFrame = [self frame];
initialResizeLocation = convert_nspoint_to_screen (self, [self mouseLocationOutsideOfEventStream]);
}
@@ -767,7 +711,6 @@ typedef NSString *CALayerContentsGravity;
if (state & GDK_TOPLEVEL_STATE_MAXIMIZED)
{
lastMaximizedFrame = newFrame;
- [self windowDidUnmaximize];
}
else
{
@@ -782,16 +725,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;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]