From 7f4f5f5c4c4d52183a6b3113901c3fcfbdd9e824 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Thu, 15 Mar 2018 18:14:43 -0400 Subject: [PATCH] window: ensure window titlebars are drawn in sync during resize mutter synchronizes drawing and resizes with Xwayland applications using XSYNC counters, but it doesn't synchronize drawing and resizes with its own titlebar painting code. This commit makes mutter wait until the titlebar finishes drawing before it unfreezes the corresponding window actor. This ensures the titlebar and client area don't get out of sync with each other. --- src/core/window-private.h | 6 ++++++ src/core/window.c | 12 ++++++++++++ src/ui/frames.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/src/core/window-private.h b/src/core/window-private.h index afaa499e5..9964c8595 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -410,6 +410,9 @@ struct _MetaWindow /* if TRUE, the X server hasn't yet committed a new buffer following resize of the frame/client window */ guint resize_pending : 1; + /* if TRUE, the window frame has a redraw queued */ + guint frame_redraw_pending : 1; + /* if non-NULL, the bounds of the window frame */ cairo_region_t *frame_bounds; @@ -788,6 +791,9 @@ void meta_window_set_resize_pending (MetaWindow *window, gboolean is_resize_pending); gboolean meta_window_resize_is_pending (MetaWindow *window); +void meta_window_set_frame_redraw_pending (MetaWindow *window, + gboolean is_frame_redraw_pending); + void meta_window_grab_op_began (MetaWindow *window, MetaGrabOp op); void meta_window_grab_op_ended (MetaWindow *window, MetaGrabOp op); diff --git a/src/core/window.c b/src/core/window.c index 34f48712f..eaab29d2e 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -3730,6 +3730,9 @@ meta_window_updates_are_frozen (MetaWindow *window) if (window->sync_request_serial < window->sync_request_wait_serial) return TRUE; + if (window->frame_redraw_pending) + return TRUE; + return FALSE; } @@ -6324,6 +6327,15 @@ meta_window_resize_is_pending (MetaWindow *window) return window->resize_pending; } +void +meta_window_set_frame_redraw_pending (MetaWindow *window, + gboolean is_frame_redraw_pending) +{ + window->frame_redraw_pending = is_frame_redraw_pending; + + meta_compositor_sync_updates_frozen (window->display->compositor, window); +} + static void end_grab_op (MetaWindow *window, const ClutterEvent *event) diff --git a/src/ui/frames.c b/src/ui/frames.c index 129a9e59b..471bfa0c7 100644 --- a/src/ui/frames.c +++ b/src/ui/frames.c @@ -149,6 +149,7 @@ static void invalidate_whole_window (MetaUIFrame *frame) { gdk_window_invalidate_rect (frame->window, NULL, FALSE); + meta_window_set_frame_redraw_pending (frame->meta_window, TRUE); } static MetaStyleInfo * @@ -484,6 +485,27 @@ meta_ui_frame_attach_style (MetaUIFrame *frame) variant)); } +static void +after_paint (GdkFrameClock *frame_clock, + MetaUIFrame *frame) +{ + MetaFrames *frames = frame->frames; + MetaWindow *window = frame->meta_window; + + /* Make sure the damage is posted to the X server before + * we mark the frame redraw finished and unfreeze, so there's + * a wayland surface commit waiting for us at unfreeze time + */ + if (meta_is_wayland_compositor ()) + gdk_display_sync (gtk_widget_get_display (GTK_WIDGET (frames))); + + meta_window_set_frame_redraw_pending (window, FALSE); + + g_signal_handlers_disconnect_by_func (G_OBJECT (gdk_window_get_frame_clock (frame->window)), + G_CALLBACK (after_paint), + frame); +} + MetaUIFrame * meta_frames_manage_window (MetaFrames *frames, MetaWindow *meta_window, @@ -531,6 +553,10 @@ meta_ui_frame_unmanage (MetaUIFrame *frame) frame->xwindow, META_CURSOR_DEFAULT); + g_signal_handlers_disconnect_by_func (G_OBJECT (gdk_window_get_frame_clock (frame->window)), + G_CALLBACK (after_paint), + frame); + gdk_window_set_user_data (frame->window, NULL); g_hash_table_remove (frames->frames, &frame->xwindow); @@ -1396,6 +1422,11 @@ meta_frames_draw (GtkWidget *widget, meta_ui_frame_paint (frame, cr); cairo_region_destroy (region); + g_signal_connect (G_OBJECT (gdk_window_get_frame_clock (frame->window)), + "after-paint", + G_CALLBACK (after_paint), + frame); + return TRUE; }