XSyncSetCounter(display, counter, sync_value);
}
+static void
+window_pre_damage (GdkWindow *window)
+{
+ GdkWindow *toplevel_window = gdk_window_get_toplevel (window);
+ GdkWindowImplX11 *impl;
+
+ if (!toplevel_window || !WINDOW_IS_TOPLEVEL (toplevel_window))
+ return;
+
+ impl = GDK_WINDOW_IMPL_X11 (toplevel_window->impl);
+
+ if (impl->toplevel->in_frame &&
+ impl->toplevel->current_counter_value % 2 == 0)
+ {
+ 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
+on_surface_changed (void *data)
+{
+ GdkWindow *window = data;
+
+ window_pre_damage (window);
+}
+
+/* We want to know when cairo drawing causes damage to the window,
+ * so we engage in the _NET_WM_FRAME_DRAWN protocol with the
+ * window only when there actually is drawing. To do that we use
+ * a technique (hack) suggested by Uli Schlachter - if we set
+ * a dummy "mime data" on the cairo surface (this facility is
+ * used to attach JPEG data to an imager), then cairo wil flush
+ * and remove the mime data before making any changes to the window.
+ */
+
+static void
+hook_surface_changed (GdkWindow *window)
+{
+ GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
+
+ if (impl->cairo_surface)
+ cairo_surface_set_mime_data (impl->cairo_surface,
+ "x-gdk/change-notify",
+ (unsigned char *)"X",
+ 1,
+ on_surface_changed,
+ window);
+}
+
+static void
+unhook_surface_changed (GdkWindow *window)
+{
+ GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
+
+ if (impl->cairo_surface)
+ cairo_surface_set_mime_data (impl->cairo_surface,
+ "x-gdk/change-notify",
+ NULL, 0,
+ NULL, NULL);
+}
+
+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->in_frame = TRUE;
+
+ hook_surface_changed (window);
+}
+
+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 ||
+ !impl->toplevel->in_frame)
+ return;
+
+ impl->toplevel->in_frame = FALSE;
+
+ if (impl->toplevel->current_counter_value % 2 == 1)
+ {
+ 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));
+ }
+ }
+
+ unhook_surface_changed (window);
+}
+
/*****************************************************
* X11 specific implementations of generic functions *
*****************************************************/
if (impl->cairo_surface)
cairo_surface_set_user_data (impl->cairo_surface, &gdk_x11_cairo_key,
impl, gdk_x11_cairo_surface_destroy);
+
+ if (WINDOW_IS_TOPLEVEL (window) && impl->toplevel->in_frame)
+ hook_surface_changed (window);
}
else
cairo_surface_reference (impl->cairo_surface);
wrapper = impl->wrapper;
+ if (WINDOW_IS_TOPLEVEL (wrapper) && impl->toplevel->in_frame)
+ unhook_surface_changed (wrapper);
+
_gdk_x11_window_grab_check_destroy (wrapper);
if (!GDK_WINDOW_DESTROYED (wrapper))
{
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)
{
gdk_x11_window_set_user_time (window, GDK_X11_DISPLAY (x11_screen->display)->user_time);
ensure_sync_counter (window);
+
+ /* Start off in a frozen state - we'll finish this when we first paint */
+ gdk_x11_window_begin_frame (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
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);
+
+ if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD)
+ gdk_window_freeze_toplevel_updates_libgtk_only (window);
}
static GdkEventMask
if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
{
+ /* The window isn't actually damaged, but it's parent is */
+ window_pre_damage (window);
_gdk_x11_window_move_resize_child (window,
x, y,
window->width, window->height);
if (height < 1)
height = 1;
+ window_pre_damage (window);
+
if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
{
_gdk_x11_window_move_resize_child (window,
if (height < 1)
height = 1;
+ window_pre_damage (window);
+
if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
{
_gdk_x11_window_move_resize_child (window, x, y, width, height);