]> git.sur5r.net Git - i3/i3/blobdiff - src/x.c
cmdparse: s/direction/split_direction to be more clear
[i3/i3] / src / x.c
diff --git a/src/x.c b/src/x.c
index 4fd8a8ba5fa2993f90f0012f37c68856138949b7..0228cd23100e802cfc82c9bf5ff660177bb8d018 100644 (file)
--- a/src/x.c
+++ b/src/x.c
@@ -162,6 +162,8 @@ void x_con_kill(Con *con) {
     con_state *state;
 
     xcb_destroy_window(conn, con->frame);
+    xcb_free_pixmap(conn, con->pixmap);
+    xcb_free_gc(conn, con->pm_gc);
     state = state_for_frame(con->frame);
     CIRCLEQ_REMOVE(&state_head, state, state);
     CIRCLEQ_REMOVE(&old_state_head, state, old_state);
@@ -233,7 +235,7 @@ void x_window_kill(xcb_window_t window, kill_window_t kill_window) {
  *
  */
 void x_draw_decoration(Con *con) {
-    const Con *parent = con->parent;
+    Con *parent = con->parent;
     /* This code needs to run for:
      *  • leaf containers
      *  • non-leaf containers which are in a stacked/tabbed container
@@ -280,7 +282,8 @@ void x_draw_decoration(Con *con) {
 
     if (con->deco_render_params != NULL &&
         (con->window == NULL || !con->window->name_x_changed) &&
-        !con->parent->pixmap_recreated &&
+        !parent->pixmap_recreated &&
+        !con->pixmap_recreated &&
         memcmp(p, con->deco_render_params, sizeof(struct deco_render_params)) == 0) {
         DLOG("CACHE HIT, not re-rendering\n");
         free(p);
@@ -300,11 +303,12 @@ void x_draw_decoration(Con *con) {
     if (con->window != NULL && con->window->name_x_changed)
         con->window->name_x_changed = false;
 
-    con->parent->pixmap_recreated = false;
+    parent->pixmap_recreated = false;
+    con->pixmap_recreated = false;
 
     /* If the con is in fullscreen mode, the decoration height we work with is set to 0 */
     Rect deco_rect = con->deco_rect;
-    if (con_get_fullscreen_con(con->parent) == con)
+    if (con_get_fullscreen_con(parent) == con)
         deco_rect.height = 0;
 
     /* 2: draw the client.background, but only for the parts around the client_rect */
@@ -409,7 +413,7 @@ void x_draw_decoration(Con *con) {
 
     int indent_level = 0,
         indent_mult = 0;
-    Con *il_parent = con->parent;
+    Con *il_parent = parent;
     if (il_parent->layout != L_STACKED) {
         while (1) {
             DLOG("il_parent = %p, layout = %d\n", il_parent, il_parent->layout);
@@ -450,6 +454,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, …).
@@ -461,7 +485,7 @@ void x_push_node(Con *con) {
     con_state *state;
     Rect rect = con->rect;
 
-    DLOG("Pushing changes for node %p / %s\n", con, con->name);
+    //DLOG("Pushing changes for node %p / %s\n", con, con->name);
     state = state_for_frame(con->frame);
 
     if (state->name != NULL) {
@@ -485,7 +509,7 @@ void x_push_node(Con *con) {
         }
         rect.height = max_y + max_height;
         if (rect.height == 0) {
-            DLOG("Unmapping container because it does not contain anything atm.\n");
+            DLOG("Unmapping container %p because it does not contain anything.\n", con);
             con->mapped = false;
         }
     }
@@ -520,8 +544,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
@@ -530,7 +555,9 @@ void x_push_node(Con *con) {
         if (rect.height > 0 &&
             (state->rect.width != rect.width ||
             state->rect.height != rect.height)) {
-            DLOG("CACHE: creating new pixmap\n");
+            DLOG("CACHE: creating new pixmap for con %p (old: %d x %d, new: %d x %d)\n",
+                    con, state->rect.width, state->rect.height,
+                    rect.width, rect.height);
             if (con->pixmap == 0) {
                 con->pixmap = xcb_generate_id(conn);
                 con->pm_gc = xcb_generate_id(conn);
@@ -540,10 +567,21 @@ 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);
+
+            con->pixmap_recreated = true;
+
+            /* 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;
     }
@@ -601,26 +639,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
@@ -634,7 +652,7 @@ static void x_push_node_unmaps(Con *con) {
     Con *current;
     con_state *state;
 
-    DLOG("Pushing changes (with unmaps) for node %p / %s\n", con, con->name);
+    //DLOG("Pushing changes (with unmaps) for node %p / %s\n", con, con->name);
     state = state_for_frame(con->frame);
 
     /* map/unmap if map state changed, also ensure that the child window
@@ -687,16 +705,16 @@ void x_push_changes(Con *con) {
     con_state *state;
 
     DLOG("-- PUSHING WINDOW STACK --\n");
-    DLOG("Disabling EnterNotify\n");
+    //DLOG("Disabling EnterNotify\n");
     uint32_t values[1] = { XCB_NONE };
     CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {
         xcb_change_window_attributes(conn, state->id, XCB_CW_EVENT_MASK, values);
     }
-    DLOG("Done, EnterNotify disabled\n");
+    //DLOG("Done, EnterNotify disabled\n");
     bool order_changed = false;
     /* X11 correctly represents the stack if we push it from bottom to top */
     CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {
-        DLOG("stack: 0x%08x\n", state->id);
+        //DLOG("stack: 0x%08x\n", state->id);
         con_state *prev = CIRCLEQ_PREV(state, state);
         con_state *old_prev = CIRCLEQ_PREV(state, old_state);
         if (prev != old_prev)
@@ -712,12 +730,12 @@ void x_push_changes(Con *con) {
         }
         state->initial = false;
     }
-    DLOG("Re-enabling EnterNotify\n");
+    //DLOG("Re-enabling EnterNotify\n");
     values[0] = FRAME_EVENT_MASK;
     CIRCLEQ_FOREACH_REVERSE(state, &state_head, state) {
         xcb_change_window_attributes(conn, state->id, XCB_CW_EVENT_MASK, values);
     }
-    DLOG("Done, EnterNotify re-enabled\n");
+    //DLOG("Done, EnterNotify re-enabled\n");
 
     DLOG("\n\n PUSHING CHANGES\n\n");
     x_push_node(con);
@@ -774,9 +792,9 @@ void x_push_changes(Con *con) {
         CIRCLEQ_REMOVE(&old_state_head, state, old_state);
         CIRCLEQ_INSERT_TAIL(&old_state_head, state, old_state);
     }
-    CIRCLEQ_FOREACH(state, &old_state_head, old_state) {
-        DLOG("old stack: 0x%08x\n", state->id);
-    }
+    //CIRCLEQ_FOREACH(state, &old_state_head, old_state) {
+    //    DLOG("old stack: 0x%08x\n", state->id);
+    //}
 
     xcb_flush(conn);
 }
@@ -789,7 +807,7 @@ void x_push_changes(Con *con) {
 void x_raise_con(Con *con) {
     con_state *state;
     state = state_for_frame(con->frame);
-    DLOG("raising in new stack: %p / %s / %s / xid %08x\n", con, con->name, con->window ? con->window->name_json : "", state->id);
+    //DLOG("raising in new stack: %p / %s / %s / xid %08x\n", con, con->name, con->window ? con->window->name_json : "", state->id);
 
     CIRCLEQ_REMOVE(&state_head, state, state);
     CIRCLEQ_INSERT_HEAD(&state_head, state, state);