From f9bc434e2a20a7aa8dec1dd0c37513f175d9fbf1 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 22 Jan 2012 11:22:15 +0000 Subject: [PATCH] Implement highlighting right/bottom borders of splitted windows Fixes #299 --- docs/userguide | 22 ++++++++++++++-------- include/config.h | 1 + src/cfgparse.l | 14 ++++++++++---- src/cfgparse.y | 9 +++++++++ src/config.c | 21 ++++++++++++--------- src/x.c | 17 +++++++++++++++++ 6 files changed, 63 insertions(+), 21 deletions(-) diff --git a/docs/userguide b/docs/userguide index 270627ab..19410209 100644 --- a/docs/userguide +++ b/docs/userguide @@ -591,7 +591,7 @@ You can change all colors which i3 uses to draw the window decorations. *Syntax*: -------------------------------------------- -colorclass border background text +colorclass border background text indicator -------------------------------------------- Where colorclass can be one of: @@ -624,18 +624,24 @@ area of the terminal and the i3 border. Colors are in HTML hex format (#rrggbb), see the following example: *Examples (default colors)*: ------------------------------------------------ -# class border backgr. text -client.focused #4c7899 #285577 #ffffff -client.focused_inactive #333333 #5f676a #ffffff -client.unfocused #333333 #222222 #888888 -client.urgent #2f343a #900000 #ffffff ------------------------------------------------ +--------------------------------------------------------- +# class border backgr. text indicator +client.focused #4c7899 #285577 #ffffff #2e9ef4 +client.focused_inactive #333333 #5f676a #ffffff #484e50 +client.unfocused #333333 #222222 #888888 #292d2e +client.urgent #2f343a #900000 #ffffff #900000 +--------------------------------------------------------- Note that for the window decorations, the color around the child window is the background color, and the border color is only the two thin lines at the top of the window. +The indicator color is used for indicating where a new window will be opened. +For horizontal split containers, the right border will be painted in indicator +color, for vertical split containers, the bottom border. This only applies to +single windows within a split container, which are otherwise indistinguishable +from single windows outside of a split container. + === Interprocess communication i3 uses unix sockets to provide an IPC interface. This allows third-party diff --git a/include/config.h b/include/config.h index 2d72283d..680830fd 100644 --- a/include/config.h +++ b/include/config.h @@ -54,6 +54,7 @@ struct Colortriple { uint32_t border; uint32_t background; uint32_t text; + uint32_t indicator; }; /** diff --git a/src/cfgparse.l b/src/cfgparse.l index 2ba81d33..aa090447 100644 --- a/src/cfgparse.l +++ b/src/cfgparse.l @@ -160,6 +160,12 @@ EOL (\r?\n) [a-zA-Z0-9_-]+ { yy_pop_state(); yylval.string = sstrdup(yytext); return OUTPUT; } ^[ \t]*#[^\n]* { return TOKCOMMENT; } #[0-9a-fA-F]+ { yy_pop_state(); yylval.string = sstrdup(yytext); return HEXCOLOR; } +{EOL} { + yy_pop_state(); + FREE(context->line_copy); + context->line_number++; + yy_push_state(BUFFER_LINE); + } [ \t]*→[ \t]* { BEGIN(WANT_STRING); } [ \t]+ { BEGIN(WANT_STRING); } --no-startup-id { printf("no startup id\n"); yy_pop_state(); return TOK_NO_STARTUP_ID; } @@ -220,10 +226,10 @@ rows { /* yylval.number = STACK_LIMIT_ROWS; */return exec { WS_STRING; yy_push_state(EXEC); yy_push_state(EAT_WHITESPACE); return TOKEXEC; } exec_always { WS_STRING; yy_push_state(EXEC); yy_push_state(EAT_WHITESPACE); return TOKEXEC_ALWAYS; } client.background { yy_push_state(COLOR_COND); yylval.single_color = &config.client.background; return TOKSINGLECOLOR; } -client.focused { yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yylval.color = &config.client.focused; return TOKCOLOR; } -client.focused_inactive { yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yylval.color = &config.client.focused_inactive; return TOKCOLOR; } -client.unfocused { yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yylval.color = &config.client.unfocused; return TOKCOLOR; } -client.urgent { yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yylval.color = &config.client.urgent; return TOKCOLOR; } +client.focused { yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yylval.color = &config.client.focused; return TOKCOLOR; } +client.focused_inactive { yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yylval.color = &config.client.focused_inactive; return TOKCOLOR; } +client.unfocused { yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yylval.color = &config.client.unfocused; return TOKCOLOR; } +client.urgent { yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yy_push_state(COLOR_COND); yylval.color = &config.client.urgent; return TOKCOLOR; } bar.focused { yy_push_state(COLOR_COND); yylval.color = &config.bar.focused; return TOKCOLOR; } bar.unfocused { yy_push_state(COLOR_COND); yylval.color = &config.bar.unfocused; return TOKCOLOR; } bar.urgent { yy_push_state(COLOR_COND); yylval.color = &config.bar.urgent; return TOKCOLOR; } diff --git a/src/cfgparse.y b/src/cfgparse.y index d245db3f..86d92829 100644 --- a/src/cfgparse.y +++ b/src/cfgparse.y @@ -1649,6 +1649,15 @@ color: dest->background = $3; dest->text = $4; } + | TOKCOLOR colorpixel colorpixel colorpixel colorpixel + { + struct Colortriple *dest = $1; + + dest->border = $2; + dest->background = $3; + dest->text = $4; + dest->indicator = $5; + } ; colorpixel: diff --git a/src/config.c b/src/config.c index 130df6af..3ffd11c4 100644 --- a/src/config.c +++ b/src/config.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) * * config.c: Configuration file (calling the parser (src/cfgparse.y) with the * correct path, switching key bindings mode). @@ -361,21 +361,24 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, memset(&config, 0, sizeof(config)); /* Initialize default colors */ -#define INIT_COLOR(x, cborder, cbackground, ctext) \ +#define INIT_COLOR(x, cborder, cbackground, ctext, cindicator) \ do { \ x.border = get_colorpixel(cborder); \ x.background = get_colorpixel(cbackground); \ x.text = get_colorpixel(ctext); \ + x.indicator = get_colorpixel(cindicator); \ } while (0) config.client.background = get_colorpixel("#000000"); - INIT_COLOR(config.client.focused, "#4c7899", "#285577", "#ffffff"); - INIT_COLOR(config.client.focused_inactive, "#333333", "#5f676a", "#ffffff"); - INIT_COLOR(config.client.unfocused, "#333333", "#222222", "#888888"); - INIT_COLOR(config.client.urgent, "#2f343a", "#900000", "#ffffff"); - INIT_COLOR(config.bar.focused, "#4c7899", "#285577", "#ffffff"); - INIT_COLOR(config.bar.unfocused, "#333333", "#222222", "#888888"); - INIT_COLOR(config.bar.urgent, "#2f343a", "#900000", "#ffffff"); + INIT_COLOR(config.client.focused, "#4c7899", "#285577", "#ffffff", "#2e9ef4"); + INIT_COLOR(config.client.focused_inactive, "#333333", "#5f676a", "#ffffff", "#484e50"); + INIT_COLOR(config.client.unfocused, "#333333", "#222222", "#888888", "#292d2e"); + INIT_COLOR(config.client.urgent, "#2f343a", "#900000", "#ffffff", "#900000"); + + /* the last argument (indicator color) is ignored for bar colors */ + INIT_COLOR(config.bar.focused, "#4c7899", "#285577", "#ffffff", "#000000"); + INIT_COLOR(config.bar.unfocused, "#333333", "#222222", "#888888", "#000000"); + INIT_COLOR(config.bar.urgent, "#2f343a", "#900000", "#ffffff", "#000000"); config.default_border = BS_NORMAL; config.default_floating_border = BS_NORMAL; diff --git a/src/x.c b/src/x.c index 3ef4df0a..e4e768ea 100644 --- a/src/x.c +++ b/src/x.c @@ -382,6 +382,23 @@ void x_draw_decoration(Con *con) { xcb_rectangle_t topline = { br.x, 0, con->rect.width + br.width + br.x, br.y }; xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 1, &topline); } + + /* Highlight the side of the border at which the next window will be + * opened if we are rendering a single window within a split container + * (which is undistinguishable from a single window outside a split + * container otherwise. */ + if (TAILQ_NEXT(con, nodes) == NULL && + TAILQ_PREV(con, nodes_head, nodes) == NULL && + con->parent->type != CT_FLOATING_CON) { + xcb_change_gc(conn, con->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){ p->color->indicator }); + if (con_orientation(con->parent) == HORIZ) + xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 1, (xcb_rectangle_t[]){ + { r->width + br.width + br.x, 0, r->width, r->height + br.height } }); + else + xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 1, (xcb_rectangle_t[]){ + { br.x, r->height + br.height + br.y, r->width - (2 * br.x), r->height } }); + } + } /* if this is a borderless/1pixel window, we don’t need to render the