diff --git a/include/con.h b/include/con.h index 65e64212..bdf0b2a2 100644 --- a/include/con.h +++ b/include/con.h @@ -135,7 +135,7 @@ int con_orientation(Con *con); */ Con *con_next_focused(Con *con); -/* +/** * Returns a "relative" Rect which contains the amount of pixels that need to * be added to the original Rect to get the final position (obviously the * amount of pixels for normal, 1pixel and borderless are different). @@ -143,4 +143,14 @@ Con *con_next_focused(Con *con); */ Rect con_border_style_rect(Con *con); +/** + * Use this function to get a container’s border style. This is important + * because when inside a stack, the border style is always BS_NORMAL. + * For tabbed mode, the same applies, with one exception: when the container is + * borderless and the only element in the tabbed container, the border is not + * rendered. + * + */ +int con_border_style(Con *con); + #endif diff --git a/src/con.c b/src/con.c index 8121bf0e..e9232273 100644 --- a/src/con.c +++ b/src/con.c @@ -41,12 +41,10 @@ Con *con_new(Con *parent) { /* TODO: remove window coloring after test-phase */ LOG("color %s\n", colors[cnt]); new->name = strdup(colors[cnt]); -#if 0 - uint32_t cp = get_colorpixel(colors[cnt]); + //uint32_t cp = get_colorpixel(colors[cnt]); cnt++; if ((cnt % (sizeof(colors) / sizeof(char*))) == 0) cnt = 0; -#endif x_con_init(new); @@ -453,14 +451,32 @@ Con *con_next_focused(Con *con) { * */ Rect con_border_style_rect(Con *con) { - if (con->border_style == BS_NORMAL) + switch (con_border_style(con)) { + case BS_NORMAL: return (Rect){2, 0, -(2 * 2), -2}; - if (con->border_style == BS_1PIXEL) + case BS_1PIXEL: return (Rect){1, 1, -2, -2}; - if (con->border_style == BS_NONE) + case BS_NONE: return (Rect){0, 0, 0, 0}; - assert(false); + default: + assert(false); + } +} + +/* + * Use this function to get a container’s border style. This is important + * because when inside a stack, the border style is always BS_NORMAL. + * For tabbed mode, the same applies, with one exception: when the container is + * borderless and the only element in the tabbed container, the border is not + * rendered. + * + */ +int con_border_style(Con *con) { + if (con->parent->layout == L_STACKED) + return BS_NORMAL; + + return con->border_style; } diff --git a/src/render.c b/src/render.c index dcd5f58e..ddb3751a 100644 --- a/src/render.c +++ b/src/render.c @@ -167,8 +167,13 @@ void render_con(Con *con) { /* in a stacking container, we ensure the focused client is raised */ if (con->layout == L_STACKED) { Con *foc = TAILQ_FIRST(&(con->focus_head)); - if (foc != TAILQ_END(&(con->focus_head))) + if (foc != TAILQ_END(&(con->focus_head))) { + LOG("con %p is stacking, raising %p\n", con, foc); x_raise_con(foc); + /* by rendering the stacked container again, we handle the case + * that we have a non-leaf-container inside the stack. */ + render_con(foc); + } } TAILQ_FOREACH(child, &(con->floating_head), floating_windows) { diff --git a/src/tree.c b/src/tree.c index 244b5ba9..33788576 100644 --- a/src/tree.c +++ b/src/tree.c @@ -233,7 +233,7 @@ void tree_split(Con *con, orientation_t orientation) { /* if we are in a container whose parent contains only one * child and has the same orientation like we are trying to * set, this operation is a no-op to not confuse the user */ - if (parent->orientation == orientation && + if (con_orientation(parent) == orientation && TAILQ_NEXT(con, nodes) == TAILQ_END(&(parent->nodes_head))) { DLOG("Not splitting the same way again\n"); return; @@ -353,6 +353,7 @@ void tree_next(char way, orientation_t orientation) { while (!TAILQ_EMPTY(&(next->focus_head))) next = TAILQ_FIRST(&(next->focus_head)); + DLOG("focusing %p\n", next); con_focus(next); } diff --git a/src/x.c b/src/x.c index ae24f35b..566864ce 100644 --- a/src/x.c +++ b/src/x.c @@ -222,8 +222,13 @@ void x_window_kill(xcb_window_t window) { * */ void x_draw_decoration(Con *con) { - if (!con_is_leaf(con) || (con->type != CT_CON && con->type != CT_FLOATING_CON)) + /* this code needs to run for: + * • leaf containers + * • non-leaf containers which are in a stacking container + */ + if (!con_is_leaf(con) && con->parent->layout != L_STACKED) return; + DLOG("decoration should be rendered for con %p\n", con); /* 1: find out which colors to use */ struct Colortriple *color; @@ -237,15 +242,48 @@ void x_draw_decoration(Con *con) { color = &config.client.unfocused; Con *parent = con->parent; + int border_style = con_border_style(con); /* 2: draw a rectangle in border color around the client */ - if (con->border_style != BS_NONE) { + if (border_style != BS_NONE && con_is_leaf(con)) { + Rect br = con_border_style_rect(con); + Rect *r = &(con->rect); +#if 0 + DLOG("con->rect spans %d x %d\n", con->rect.width, con->rect.height); + DLOG("border_rect spans (%d, %d) with %d x %d\n", border_rect.x, border_rect.y, border_rect.width, border_rect.height); + DLOG("window_rect spans (%d, %d) with %d x %d\n", con->window_rect.x, con->window_rect.y, con->window_rect.width, con->window_rect.height); +#endif + + /* This polygon represents the border around the child window (left, + * bottom and right part). We don’t just fill the whole rectangle + * because some childs are not freely resizable and we want their + * background color to "shine through". */ xcb_change_gc_single(conn, con->gc, XCB_GC_FOREGROUND, color->background); - xcb_rectangle_t rect = { 0, 0, con->rect.width, con->rect.height }; - xcb_poly_fill_rectangle(conn, con->frame, con->gc, 1, &rect); + xcb_point_t points[] = { + { 0, 0 }, + { 0, r->height }, + { r->width, r->height }, + { r->width, 0 }, + { r->width + br.width + br.x, 0 }, + { r->width + br.width + br.x, r->height + br.height + br.y }, + { br.x, r->height + br.height }, + { br.x, 0 } + }; + xcb_fill_poly(conn, con->frame, con->gc, XCB_POLY_SHAPE_COMPLEX, XCB_COORD_MODE_ORIGIN, 8, points); + + /* 1pixel border needs an additional line at the top */ + if (border_style == BS_1PIXEL) { + xcb_rectangle_t topline = { br.x, 0, con->rect.width + br.width + br.x, br.y }; + xcb_poly_fill_rectangle(conn, con->frame, con->gc, 1, &topline); + } } - if (con->border_style != BS_NORMAL) + + /* if this is a borderless/1pixel window, we don’t * need to render the + * decoration. */ + if (border_style != BS_NORMAL) { + DLOG("border style not BS_NORMAL, aborting rendering of decoration\n"); return; + } /* 3: paint the bar */ xcb_change_gc_single(conn, parent->gc, XCB_GC_FOREGROUND, color->background); @@ -265,18 +303,49 @@ void x_draw_decoration(Con *con) { con->deco_rect.y + con->deco_rect.height - 1); /* to_y */ /* 5: draw the title */ - struct Window *win = con->window; - if (win == NULL || win ->name_x == NULL) - return; xcb_change_gc_single(conn, parent->gc, XCB_GC_BACKGROUND, color->background); xcb_change_gc_single(conn, parent->gc, XCB_GC_FOREGROUND, color->text); + + struct Window *win = con->window; + if (win == NULL || win->name_x == NULL) { + /* this is a non-leaf container, we need to make up a good description */ + // TODO: use a good description instead of just "another container" + xcb_image_text_8( + conn, + strlen("another container"), + parent->frame, + parent->gc, + con->deco_rect.x + 2, + con->deco_rect.y + 14, /* TODO: hardcoded */ + "another container" + ); + return; + } + + int indent_level = 0, + indent_mult = 0; + Con *il_parent = con->parent; + if (il_parent->type != L_STACKED) { + while (1) { + DLOG("il_parent = %p, layout = %d\n", il_parent, il_parent->layout); + if (il_parent->layout == L_STACKED) + indent_level++; + if (il_parent->type == CT_WORKSPACE) + break; + il_parent = il_parent->parent; + indent_mult++; + } + } + DLOG("indent_level = %d, indent_mult = %d\n", indent_level, indent_mult); + int indent_px = (indent_level * 5) * indent_mult; + if (win->uses_net_wm_name) xcb_image_text_16( conn, win->name_len, parent->frame, parent->gc, - con->deco_rect.x, + con->deco_rect.x + 2 + indent_px, con->deco_rect.y + 14, /* TODO: hardcoded */ (xcb_char2b_t*)win->name_x ); @@ -286,7 +355,7 @@ void x_draw_decoration(Con *con) { win->name_len, parent->frame, parent->gc, - con->deco_rect.x, + con->deco_rect.x + 2 + indent_px, con->deco_rect.y + 14, /* TODO: hardcoded */ win->name_x );