x: first create/render pixmap, then change window sizes (reduces flickering for new windows)

Especially in stacked cons.
This commit is contained in:
Michael Stapelberg 2011-05-29 11:31:22 +02:00
parent bbddacd336
commit b49874dcb8
1 changed files with 33 additions and 22 deletions

55
src/x.c
View File

@ -452,6 +452,26 @@ update_pixmaps:
xcb_clear_area(conn, false, parent->frame, 0, 0, parent->rect.width, parent->rect.height); 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 * 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, ). * 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; bool fake_notify = false;
/* set new position if rect changed */ /* set new position if rect changed */
if (memcmp(&(state->rect), &rect, sizeof(Rect)) != 0) { if (memcmp(&(state->rect), &rect, sizeof(Rect)) != 0) {
DLOG("setting rect (%d, %d, %d, %d)\n", rect.x, rect.y, rect.width, rect.height); /* We first create the new pixmap, then render to it, set it as the
xcb_set_window_rect(conn, con->frame, rect); * 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 /* 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 dont * is enough to check if width/height have changed. Also, we dont
@ -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_pixmap(conn, root_depth, con->pixmap, con->frame, rect.width, rect.height);
xcb_create_gc(conn, con->pm_gc, con->pixmap, 0, 0); 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
* doesnt hurt performance. */
x_deco_recurse(con);
uint32_t values[] = { con->pixmap }; uint32_t values[] = { con->pixmap };
xcb_change_window_attributes(conn, con->frame, XCB_CW_BACK_PIXMAP, values); xcb_change_window_attributes(conn, con->frame, XCB_CW_BACK_PIXMAP, values);
con->pixmap_recreated = true; 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)); memcpy(&(state->rect), &rect, sizeof(Rect));
fake_notify = true; fake_notify = true;
} }
@ -603,26 +634,6 @@ void x_push_node(Con *con) {
x_push_node(current); 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 * 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 * necessary to split this up to handle new fullscreen clients properly: The