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);
*
*/
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
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);
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 */
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);
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, …).
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) {
}
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;
}
}
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
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);
}
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;
}
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
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
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)
}
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);
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);
}
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);