]> git.sur5r.net Git - i3/i3/commitdiff
x: first create/render pixmap, then change window sizes (reduces flickering for new...
authorMichael Stapelberg <michael@stapelberg.de>
Sun, 29 May 2011 09:31:22 +0000 (11:31 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Sun, 29 May 2011 09:31:22 +0000 (11:31 +0200)
Especially in stacked cons.

src/x.c

diff --git a/src/x.c b/src/x.c
index f37ef9330e19ee77142242d2c3dd418f59e87bf1..b166d6828b64ce3cbcae7f4fc236a183b73f9ed1 100644 (file)
--- a/src/x.c
+++ b/src/x.c
@@ -452,6 +452,26 @@ update_pixmaps:
     xcb_clear_area(conn, false, parent->frame, 0, 0, parent->rect.width, parent->rect.height);
 }
 
+/*
+ * Recursively calls x_draw_decoration. This cannot be done in x_push_node
+ * because x_push_node uses focus order to recurse (see the comment above)
+ * while drawing the decoration needs to happen in the actual order.
+ *
+ */
+static void x_deco_recurse(Con *con) {
+    Con *current;
+
+    TAILQ_FOREACH(current, &(con->nodes_head), nodes)
+        x_deco_recurse(current);
+
+    TAILQ_FOREACH(current, &(con->floating_head), floating_windows)
+        x_deco_recurse(current);
+
+    if ((con->type != CT_ROOT && con->type != CT_OUTPUT) &&
+        con->mapped)
+        x_draw_decoration(con);
+}
+
 /*
  * This function pushes the properties of each node of the layout tree to
  * X11 if they have changed (like the map state, position of the window, …).
@@ -522,8 +542,9 @@ void x_push_node(Con *con) {
     bool fake_notify = false;
     /* set new position if rect changed */
     if (memcmp(&(state->rect), &rect, sizeof(Rect)) != 0) {
-        DLOG("setting rect (%d, %d, %d, %d)\n", rect.x, rect.y, rect.width, rect.height);
-        xcb_set_window_rect(conn, con->frame, rect);
+        /* We first create the new pixmap, then render to it, set it as the
+         * background and only afterwards change the window size. This reduces
+         * flickering. */
 
         /* As the pixmap only depends on the size and not on the position, it
          * is enough to check if width/height have changed. Also, we don’t
@@ -542,10 +563,20 @@ void x_push_node(Con *con) {
             }
             xcb_create_pixmap(conn, root_depth, con->pixmap, con->frame, rect.width, rect.height);
             xcb_create_gc(conn, con->pm_gc, con->pixmap, 0, 0);
+
+            /* Render the decoration now to make the correct decoration visible
+             * from the very first moment. Later calls will be cached, so this
+             * doesn’t hurt performance. */
+            x_deco_recurse(con);
+
             uint32_t values[] = { con->pixmap };
             xcb_change_window_attributes(conn, con->frame, XCB_CW_BACK_PIXMAP, values);
             con->pixmap_recreated = true;
         }
+
+        DLOG("setting rect (%d, %d, %d, %d)\n", rect.x, rect.y, rect.width, rect.height);
+        xcb_set_window_rect(conn, con->frame, rect);
+
         memcpy(&(state->rect), &rect, sizeof(Rect));
         fake_notify = true;
     }
@@ -603,26 +634,6 @@ void x_push_node(Con *con) {
         x_push_node(current);
 }
 
-/*
- * Recursively calls x_draw_decoration. This cannot be done in x_push_node
- * because x_push_node uses focus order to recurse (see the comment above)
- * while drawing the decoration needs to happen in the actual order.
- *
- */
-static void x_deco_recurse(Con *con) {
-    Con *current;
-
-    TAILQ_FOREACH(current, &(con->nodes_head), nodes)
-        x_deco_recurse(current);
-
-    TAILQ_FOREACH(current, &(con->floating_head), floating_windows)
-        x_deco_recurse(current);
-
-    if ((con->type != CT_ROOT && con->type != CT_OUTPUT) &&
-        con->mapped)
-        x_draw_decoration(con);
-}
-
 /*
  * Same idea as in x_push_node(), but this function only unmaps windows. It is
  * necessary to split this up to handle new fullscreen clients properly: The