Use _NET_WM_FRAME_DRAWN to synchronize frame drawing

As part of the extended _NET_WM_SYNC_REQUEST_COUNTER protocol,
we get a _NET_WM_FRAME_DRAWN message for each frame we draw. Use this
to synchronize the updates we are doing with the compositing manager's
drawing, and ultimately with with display refresh.

We now set the sync request counters on all windows, including
override-redirect windows, since it is also useful to do synchronized,
atomic updates for such windows.

https://bugzilla.gnome.org/show_bug.cgi?id=685460
This commit is contained in:
Owen W. Taylor 2012-09-18 09:37:03 -04:00
parent 69f457426a
commit 8a6895fe52
3 changed files with 89 additions and 2 deletions

View File

@ -681,6 +681,13 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
GDK_WINDOW_STATE_ICONIFIED);
}
if (window_impl->toplevel &&
window_impl->toplevel->frame_pending)
{
window_impl->toplevel->frame_pending = FALSE;
gdk_frame_clock_thaw (gdk_window_get_frame_clock (event->any.window));
}
_gdk_x11_window_grab_check_unmap (window, xevent->xany.serial);
}
@ -1132,6 +1139,21 @@ _gdk_wm_protocols_filter (GdkXEvent *xev,
return GDK_FILTER_REMOVE;
}
else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_FRAME_DRAWN"))
{
GdkWindowImplX11 *window_impl;
window_impl = GDK_WINDOW_IMPL_X11 (event->any.window->impl);
if (window_impl->toplevel &&
window_impl->toplevel->frame_pending)
{
window_impl->toplevel->frame_pending = FALSE;
gdk_frame_clock_thaw (gdk_window_get_frame_clock (event->any.window));
}
return GDK_FILTER_REMOVE;
}
return GDK_FILTER_CONTINUE;
}

View File

@ -213,6 +213,51 @@ set_sync_counter(Display *display,
XSyncSetCounter(display, counter, sync_value);
}
static void
gdk_x11_window_begin_frame (GdkWindow *window)
{
GdkWindowImplX11 *impl;
g_return_if_fail (GDK_IS_WINDOW (window));
impl = GDK_WINDOW_IMPL_X11 (window->impl);
if (!WINDOW_IS_TOPLEVEL (window) ||
impl->toplevel->extended_update_counter == None)
return;
impl->toplevel->current_counter_value += 1;
set_sync_counter(GDK_WINDOW_XDISPLAY (impl->wrapper),
impl->toplevel->extended_update_counter,
impl->toplevel->current_counter_value);
}
static void
gdk_x11_window_end_frame (GdkWindow *window)
{
GdkWindowImplX11 *impl;
g_return_if_fail (GDK_IS_WINDOW (window));
impl = GDK_WINDOW_IMPL_X11 (window->impl);
if (!WINDOW_IS_TOPLEVEL (window) ||
impl->toplevel->extended_update_counter == None)
return;
impl->toplevel->current_counter_value += 1;
set_sync_counter(GDK_WINDOW_XDISPLAY (impl->wrapper),
impl->toplevel->extended_update_counter,
impl->toplevel->current_counter_value);
if (gdk_x11_screen_supports_net_wm_hint (gdk_window_get_screen (window),
gdk_atom_intern_static_string ("_NET_WM_FRAME_DRAWN")))
{
impl->toplevel->frame_pending = TRUE;
gdk_frame_clock_freeze (gdk_window_get_frame_clock (window));
}
}
/*****************************************************
* X11 specific implementations of generic functions *
*****************************************************/
@ -616,9 +661,8 @@ ensure_sync_counter (GdkWindow *window)
{
GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
if (toplevel && impl->use_synchronized_configure &&
if (toplevel &&
toplevel->update_counter == None &&
GDK_X11_DISPLAY (display)->use_sync)
{
@ -718,6 +762,20 @@ setup_toplevel_window (GdkWindow *window,
ensure_sync_counter (window);
}
static void
on_frame_clock_before_paint (GdkFrameClock *clock,
GdkWindow *window)
{
gdk_x11_window_begin_frame (window);
}
static void
on_frame_clock_after_paint (GdkFrameClock *clock,
GdkWindow *window)
{
gdk_x11_window_end_frame (window);
}
void
_gdk_x11_display_create_window_impl (GdkDisplay *display,
GdkWindow *window,
@ -878,6 +936,10 @@ _gdk_x11_display_create_window_impl (GdkDisplay *display,
clock = g_object_new (GDK_TYPE_FRAME_CLOCK_IDLE, NULL);
gdk_window_set_frame_clock (window, clock);
g_signal_connect (clock, "before-paint",
G_CALLBACK (on_frame_clock_before_paint), window);
g_signal_connect (clock, "after-paint",
G_CALLBACK (on_frame_clock_after_paint), window);
}
static GdkEventMask

View File

@ -126,6 +126,9 @@ struct _GdkToplevelX11
/* Set if the WM is presenting us as focused, i.e. with active decorations
*/
guint have_focused : 1;
/* If we're expecting a response from the compositor after painting a frame */
guint frame_pending : 1;
gulong map_serial; /* Serial of last transition from unmapped */