[gtk+/wip/frame-synchronization: 835/857] GdkWindowX11: Only start a frame when we emit damage
- From: Owen Taylor <otaylor src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/frame-synchronization: 835/857] GdkWindowX11: Only start a frame when we emit damage
- Date: Wed, 13 Feb 2013 06:13:43 +0000 (UTC)
commit 439f52937c80845aa9202eaeb585ee3e3944e45a
Author: Owen W. Taylor <otaylor fishsoup net>
Date: Wed Nov 14 12:23:41 2012 -0500
GdkWindowX11: Only start a frame when we emit damage
Instead of communicating the start of a frame to the window manager
as soon as we begin a frame, start a frame only when we know we've
actually created damage to the contents of a window.
(This uses cairo_set_mime_data() as a notification mechanism - a
clever suggestion from Uli Schlachter.)
The advantage of this is that we aren't forcing the compositor to
do a frame cycle and send _NET_WM_FRAME_DRAWN - depending on how the
compositor is structured that might either cause it to do extra
work or it might send _NET_WM_FRAME_DRAWN early and upset frame
timing.
https://bugzilla.gnome.org/show_bug.cgi?id=685460
gdk/x11/gdkwindow-x11.c | 93 +++++++++++++++++++++++++++++++++++++++++++----
gdk/x11/gdkwindow-x11.h | 2 +
2 files changed, 87 insertions(+), 8 deletions(-)
---
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index fbc13b5..f2c5735 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -214,6 +214,70 @@ set_sync_counter(Display *display,
}
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;
@@ -226,13 +290,9 @@ gdk_x11_window_begin_frame (GdkWindow *window)
impl->toplevel->extended_update_counter == None)
return;
- if (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);
- }
+ impl->toplevel->in_frame = TRUE;
+
+ hook_surface_changed (window);
}
static void
@@ -245,9 +305,12 @@ gdk_x11_window_end_frame (GdkWindow *window)
impl = GDK_WINDOW_IMPL_X11 (window->impl);
if (!WINDOW_IS_TOPLEVEL (window) ||
- impl->toplevel->extended_update_counter == None)
+ 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;
@@ -262,6 +325,8 @@ gdk_x11_window_end_frame (GdkWindow *window)
gdk_frame_clock_freeze (gdk_window_get_frame_clock (window));
}
}
+
+ unhook_surface_changed (window);
}
/*****************************************************
@@ -307,6 +372,9 @@ gdk_x11_ref_cairo_surface (GdkWindow *window)
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);
@@ -326,6 +394,9 @@ gdk_window_impl_x11_finalize (GObject *object)
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))
@@ -1569,6 +1640,8 @@ window_x11_move (GdkWindow *window,
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);
@@ -1598,6 +1671,8 @@ window_x11_resize (GdkWindow *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,
@@ -1641,6 +1716,8 @@ window_x11_move_resize (GdkWindow *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);
diff --git a/gdk/x11/gdkwindow-x11.h b/gdk/x11/gdkwindow-x11.h
index c423652..8dde335 100644
--- a/gdk/x11/gdkwindow-x11.h
+++ b/gdk/x11/gdkwindow-x11.h
@@ -127,6 +127,8 @@ struct _GdkToplevelX11
*/
guint have_focused : 1;
+ guint in_frame : 1;
+
/* If we're expecting a response from the compositor after painting a frame */
guint frame_pending : 1;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]