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.
This commit is contained in:
Ray Strode 2018-03-15 18:14:43 -04:00 committed by Ray Strode
parent 0d1cee5123
commit 7f4f5f5c4c
3 changed files with 49 additions and 0 deletions

View File

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

View File

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

View File

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