Switch to an extended form of _NET_WM_SYNC_REQUEST_COUNTER

By exporting two XSync counters on a toplevel window, we subscribe
to an extended form of the _NET_WM_SYNC_REQUEST_COUNTER protocol,
where the window manager can initiate an atomic frame, as previously,
but the application can also do so by incrementing the new counter to
an odd value, and then to an even value to finish the frame.

See:
https://mail.gnome.org/archives/wm-spec-list/2011-October/msg00006.html

The support for 64-bit integers that GLib requires is used to
simplify the logic.

https://bugzilla.gnome.org/show_bug.cgi?id=685460
This commit is contained in:
Owen W. Taylor 2012-09-18 09:31:17 -04:00
parent 1824796bfb
commit 69f457426a
3 changed files with 46 additions and 21 deletions

View File

@ -747,10 +747,10 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
} }
#ifdef HAVE_XSYNC #ifdef HAVE_XSYNC
if (!is_substructure && toplevel && display_x11->use_sync && !XSyncValueIsZero (toplevel->pending_counter_value)) if (!is_substructure && toplevel && display_x11->use_sync && toplevel->pending_counter_value != 0)
{ {
toplevel->current_counter_value = toplevel->pending_counter_value; toplevel->configure_counter_value = toplevel->pending_counter_value;
XSyncIntToValue (&toplevel->pending_counter_value, 0); toplevel->pending_counter_value = 0;
} }
#endif #endif
@ -1126,9 +1126,7 @@ _gdk_wm_protocols_filter (GdkXEvent *xev,
if (toplevel) if (toplevel)
{ {
#ifdef HAVE_XSYNC #ifdef HAVE_XSYNC
XSyncIntsToValue (&toplevel->pending_counter_value, toplevel->pending_counter_value = xevent->xclient.data.l[2] + ((gint64)xevent->xclient.data.l[3] << 32);
xevent->xclient.data.l[2],
xevent->xclient.data.l[3]);
#endif #endif
} }
return GDK_FILTER_REMOVE; return GDK_FILTER_REMOVE;

View File

@ -200,6 +200,19 @@ _gdk_x11_window_update_size (GdkWindowImplX11 *impl)
} }
} }
static void
set_sync_counter(Display *display,
XSyncCounter counter,
gint64 value)
{
XSyncValue sync_value;
XSyncIntsToValue(&sync_value,
value & G_GINT64_CONSTANT(0xFFFFFFFF),
value >> 32);
XSyncSetCounter(display, counter, sync_value);
}
/***************************************************** /*****************************************************
* X11 specific implementations of generic functions * * X11 specific implementations of generic functions *
*****************************************************/ *****************************************************/
@ -612,20 +625,24 @@ ensure_sync_counter (GdkWindow *window)
Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
XSyncValue value; XSyncValue value;
Atom atom; Atom atom;
XID counters[2];
XSyncIntToValue (&value, 0); XSyncIntToValue (&value, 0);
toplevel->update_counter = XSyncCreateCounter (xdisplay, value); toplevel->update_counter = XSyncCreateCounter (xdisplay, value);
toplevel->extended_update_counter = XSyncCreateCounter (xdisplay, value);
atom = gdk_x11_get_xatom_by_name_for_display (display, atom = gdk_x11_get_xatom_by_name_for_display (display,
"_NET_WM_SYNC_REQUEST_COUNTER"); "_NET_WM_SYNC_REQUEST_COUNTER");
counters[0] = toplevel->update_counter;
counters[1] = toplevel->extended_update_counter;
XChangeProperty (xdisplay, GDK_WINDOW_XID (window), XChangeProperty (xdisplay, GDK_WINDOW_XID (window),
atom, XA_CARDINAL, atom, XA_CARDINAL,
32, PropModeReplace, 32, PropModeReplace,
(guchar *)&toplevel->update_counter, 1); (guchar *)counters, 2);
XSyncIntToValue (&toplevel->current_counter_value, 0); toplevel->current_counter_value = 0;
} }
} }
#endif #endif
@ -1006,7 +1023,7 @@ gdk_toplevel_x11_free_contents (GdkDisplay *display,
toplevel->update_counter); toplevel->update_counter);
toplevel->update_counter = None; toplevel->update_counter = None;
XSyncIntToValue (&toplevel->current_counter_value, 0); toplevel->current_counter_value = 0;
} }
#endif #endif
} }
@ -4863,13 +4880,21 @@ gdk_x11_window_configure_finished (GdkWindow *window)
if (toplevel && toplevel->update_counter != None && if (toplevel && toplevel->update_counter != None &&
GDK_X11_DISPLAY (display)->use_sync && GDK_X11_DISPLAY (display)->use_sync &&
!XSyncValueIsZero (toplevel->current_counter_value)) toplevel->configure_counter_value != 0)
{ {
XSyncSetCounter (GDK_WINDOW_XDISPLAY (window), set_sync_counter (GDK_WINDOW_XDISPLAY (window),
toplevel->update_counter, toplevel->update_counter,
toplevel->current_counter_value); toplevel->configure_counter_value);
XSyncIntToValue (&toplevel->current_counter_value, 0); toplevel->current_counter_value = toplevel->configure_counter_value;
if ((toplevel->current_counter_value % 2) == 1)
toplevel->current_counter_value += 1;
toplevel->configure_counter_value = 0;
set_sync_counter (GDK_WINDOW_XDISPLAY (window),
toplevel->extended_update_counter,
toplevel->current_counter_value);
} }
} }
#endif #endif

View File

@ -144,11 +144,13 @@ struct _GdkToplevelX11
#ifdef HAVE_XSYNC #ifdef HAVE_XSYNC
XID update_counter; XID update_counter;
XSyncValue pending_counter_value; /* latest _NET_WM_SYNC_REQUEST value received */ XID extended_update_counter;
XSyncValue current_counter_value; /* Latest _NET_WM_SYNC_REQUEST value received gint64 pending_counter_value; /* latest _NET_WM_SYNC_REQUEST value received */
gint64 configure_counter_value; /* Latest _NET_WM_SYNC_REQUEST value received
* where we have also seen the corresponding * where we have also seen the corresponding
* ConfigureNotify * ConfigureNotify
*/ */
gint64 current_counter_value;
#endif #endif
}; };