Merge branch 'wip/chergert/macos-fix-toplevel-resize' into 'main'

macos: fix configure, move-resize, and compute-size

See merge request GNOME/gtk!4486
This commit is contained in:
Matthias Clasen 2022-02-22 13:10:34 +00:00
commit d35bac452b
6 changed files with 186 additions and 159 deletions

View File

@ -203,76 +203,20 @@ typedef NSString *CALayerContentsGravity;
}
}
-(void)windowDidUnmaximize
{
NSWindowStyleMask style_mask = [self styleMask];
gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), 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])
{
GdkSurface *surface = GDK_SURFACE ([self gdkSurface]);
[self setOpaque:NO];
/* Force updating of various styling, regions, etc */
_gdk_surface_update_size (surface);
}
}
-(void)windowDidMove:(NSNotification *)aNotification
-(void)setFrame:(NSRect)frame display:(BOOL)display
{
NSRect contentRect = [self contentRectForFrameRect:frame];
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];
if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, frame))
{
gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_MAXIMIZED, 0);
_gdk_surface_update_size (surface);
}
_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_NORTH_WEST:
gravity = kCAGravityTopRight;
break;
case GDK_SURFACE_EDGE_SOUTH_WEST:
case GDK_SURFACE_EDGE_WEST:
gravity = kCAGravityBottomRight;
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_SOUTH:
case GDK_SURFACE_EDGE_SOUTH_EAST:
gravity = kCAGravityBottomLeft;
break;
case GDK_SURFACE_EDGE_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];
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

View File

@ -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);
}
}

View File

@ -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);

View File

@ -430,15 +430,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,
@ -452,6 +443,9 @@ gdk_macos_surface_constructed (GObject *object)
self,
G_CONNECT_SWAPPED);
}
if (self->window != NULL)
_gdk_macos_surface_configure (self);
}
static void
@ -731,12 +725,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,
@ -753,6 +756,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
@ -813,8 +829,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));
}
}
@ -914,7 +929,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));
@ -938,28 +952,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];
}
if (size_changed)
gdk_surface_invalidate_rect (surface, NULL);
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);
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
@ -1027,7 +1056,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);
}

View File

@ -35,6 +35,8 @@ struct _GdkMacosToplevelSurface
{
GdkMacosSurface parent_instance;
GdkToplevelLayout *layout;
int last_computed_width;
int last_computed_height;
guint decorated : 1;
};

View File

@ -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;
}