From bcdd282e9c18dd5f830415f61b08183125c0073f Mon Sep 17 00:00:00 2001 From: Sebastian Keller Date: Wed, 21 Feb 2024 23:38:58 +0100 Subject: [PATCH] frames: Update _MUTTER_FRAME_EXTENTS from frame size_allocate Relying on the content size_allocate() to determine the content position can fail in situations where the position of the content has changed, but not its size. This happens for example when the window initially is sized fullscreen height + headerbar height while not considered fullscreen yet. Then when the window is resized to just the fullscreen height and marked as fullscreen, the content size has not changed and size_allocate() is not called on the content. Thus the previous position which assumes the presence of a headerbar still applies. As a result the window is shifted down, revealing a headerbar sized area showing the gtk window background color. This issue can be avoided by using the frame's size_allocate(), which gets called in response to all relevant events, such as any headerbar size changes, headerbar visibility changes, window resizes and fullscreen status changes. Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2937 Part-of: --- src/frames/meta-frame.c | 55 +++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/src/frames/meta-frame.c b/src/frames/meta-frame.c index 9eea99f00..f7fe27cfa 100644 --- a/src/frames/meta-frame.c +++ b/src/frames/meta-frame.c @@ -30,6 +30,8 @@ struct _MetaFrame { GtkWindow parent_instance; + GtkBorder extents; + Atom atom__NET_WM_VISIBLE_NAME; Atom atom__NET_WM_NAME; Atom atom__MOTIF_WM_HINTS; @@ -187,20 +189,8 @@ update_extents (MetaFrame *frame, (guchar *) &data, 4); gdk_x11_display_error_trap_pop_ignored (display); -} -static void -on_border_changed (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - MetaFrame *frame = user_data; - GtkWidget *content; - GtkBorder border; - - content = gtk_window_get_child (GTK_WINDOW (frame)); - border = meta_frame_content_get_border (META_FRAME_CONTENT (content)); - update_extents (frame, border); + frame->extents = border; } static char * @@ -484,11 +474,47 @@ meta_frame_finalize (GObject *object) G_OBJECT_CLASS (meta_frame_parent_class)->finalize (object); } +static void +meta_frame_size_allocate (GtkWidget *widget, + int width, + int height, + int baseline) +{ + MetaFrame *frame = META_FRAME (widget); + GtkWidget *content; + GtkBorder extents; + graphene_point_t point = {}; + double scale; + + GTK_WIDGET_CLASS (meta_frame_parent_class)->size_allocate (widget, width, height, baseline); + + content = gtk_window_get_child (GTK_WINDOW (frame)); + if (!content) + return; + + if (!gtk_widget_compute_point (content, widget, &point, &point)) + return; + + scale = gdk_surface_get_scale_factor (gtk_native_get_surface (GTK_NATIVE (widget))); + /* FIXME: right/bottom are broken, if they are ever other than 0. */ + extents = (GtkBorder) { point.x * scale, 0, point.y * scale, 0 }; + + if (frame->extents.left == extents.left && + frame->extents.right == extents.right && + frame->extents.top == extents.top && + frame->extents.bottom == extents.bottom) + return; + + update_extents (frame, extents); +} + static void meta_frame_class_init (MetaFrameClass *klass) { + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); + widget_class->size_allocate = meta_frame_size_allocate; object_class->constructed = meta_frame_constructed; object_class->finalize = meta_frame_finalize; } @@ -518,9 +544,6 @@ meta_frame_new (Window window) content = meta_frame_content_new (window); gtk_window_set_child (GTK_WINDOW (frame), content); - g_signal_connect (content, "notify::border", - G_CALLBACK (on_border_changed), frame); - gtk_widget_realize (GTK_WIDGET (frame)); surface = gtk_native_get_surface (GTK_NATIVE (frame)); gdk_x11_surface_set_frame_sync_enabled (surface, TRUE);