From 80da100ac84890890594f8df951cc20a522d7922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Tue, 24 Mar 2015 23:07:25 +0100 Subject: [PATCH] Add support for a custom separator symbol This introduces a "separator_symbol" property for the i3bar configuration. If set, the specified string will be used as a separator instead of a vertical line. Since it is an optional configuration, complete backwards compatibility is given. fixes #1472 --- docs/userguide | 18 +++++++++++++ i3bar/include/config.h | 1 + i3bar/src/config.c | 7 +++++ i3bar/src/xcb.c | 46 +++++++++++++++++++++++++-------- include/config.h | 3 +++ include/config_directives.h | 1 + parser-specs/config.spec | 5 ++++ src/config_directives.c | 5 ++++ src/ipc.c | 5 ++++ testcases/t/201-config-parser.t | 2 +- 10 files changed, 81 insertions(+), 12 deletions(-) diff --git a/docs/userguide b/docs/userguide index 45b05a06..d60eefb2 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1249,6 +1249,24 @@ bar { } -------------------------------------------------------------- +=== Custom separator symbol + +Specifies a custom symbol to be used for the separator as opposed to the vertical, +one pixel thick separator. Note that you may have to adjust the +sep_block_width+ +property. + +*Syntax*: +------------------------- +separator_symbol +------------------------- + +*Example*: +------------------------ +bar { + separator_symbol ":|:" +} +------------------------ + === Workspace buttons Specifies whether workspace buttons should be shown or not. This is useful if diff --git a/i3bar/include/config.h b/i3bar/include/config.h index fe04bf31..fdc37445 100644 --- a/i3bar/include/config.h +++ b/i3bar/include/config.h @@ -35,6 +35,7 @@ typedef struct config_t { char *bar_id; char *command; char *fontname; + i3String *separator_symbol; char *tray_output; int num_outputs; char **outputs; diff --git a/i3bar/src/config.c b/i3bar/src/config.c index c568ac5b..a83ca0aa 100644 --- a/i3bar/src/config.c +++ b/i3bar/src/config.c @@ -144,6 +144,13 @@ static int config_string_cb(void *params_, const unsigned char *val, size_t _len return 1; } + if (!strcmp(cur_key, "separator_symbol")) { + DLOG("separator = %.*s\n", len, val); + I3STRING_FREE(config.separator_symbol); + config.separator_symbol = i3string_from_utf8_with_length((const char *)val, len); + return 1; + } + if (!strcmp(cur_key, "outputs")) { DLOG("+output %.*s\n", len, val); int new_num_outputs = config.num_outputs + 1; diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index d87e56e4..85efd88b 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -63,6 +63,9 @@ static i3Font font; /* Overall height of the bar (based on font size) */ int bar_height; +/* Cached width of the custom separator if one was set */ +int separator_symbol_width; + /* These are only relevant for XKB, which we only need for grabbing modifiers */ int xkb_base; int mod_pressed = 0; @@ -155,6 +158,33 @@ int get_tray_width(struct tc_head *trayclients) { return tray_width; } +/* + * Draws a separator for the given block if necessary. + * + */ +static void draw_separator(uint32_t x, struct status_block *block) { + uint32_t sep_offset = get_sep_offset(block); + if (TAILQ_NEXT(block, blocks) == NULL || sep_offset == 0) + return; + + uint32_t center_x = x - sep_offset; + if (config.separator_symbol == NULL) { + /* Draw a classic one pixel, vertical separator. */ + uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_LINE_WIDTH; + uint32_t values[] = {colors.sep_fg, colors.bar_bg, logical_px(1)}; + xcb_change_gc(xcb_connection, statusline_ctx, mask, values); + xcb_poly_line(xcb_connection, XCB_COORD_MODE_ORIGIN, statusline_pm, statusline_ctx, 2, + (xcb_point_t[]){{center_x, logical_px(sep_voff_px)}, + {center_x, bar_height - logical_px(sep_voff_px)}}); + } else { + /* Draw a custom separator. */ + uint32_t separator_x = MAX(x - block->sep_block_width, center_x - separator_symbol_width / 2); + set_font_colors(statusline_ctx, colors.sep_fg, colors.bar_bg); + draw_text(config.separator_symbol, statusline_pm, statusline_ctx, + separator_x, logical_px(ws_voff_px), x - separator_x); + } +} + /* * Redraws the statusline to the buffer * @@ -245,17 +275,8 @@ void refresh_statusline(bool use_short_text) { draw_text(block->full_text, statusline_pm, statusline_ctx, x + block->x_offset, logical_px(ws_voff_px), block->width); x += block->width + block->sep_block_width + block->x_offset + block->x_append; - uint32_t sep_offset = get_sep_offset(block); - if (TAILQ_NEXT(block, blocks) != NULL && sep_offset > 0) { - /* This is not the last block, draw a separator. */ - uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_LINE_WIDTH; - uint32_t values[] = {colors.sep_fg, colors.bar_bg, logical_px(1)}; - xcb_change_gc(xcb_connection, statusline_ctx, mask, values); - xcb_poly_line(xcb_connection, XCB_COORD_MODE_ORIGIN, statusline_pm, - statusline_ctx, 2, - (xcb_point_t[]){{x - sep_offset, logical_px(sep_voff_px)}, - {x - sep_offset, bar_height - logical_px(sep_voff_px)}}); - } + /* If this is not the last block, draw a separator. */ + draw_separator(x, block); } } @@ -1198,6 +1219,9 @@ void init_xcb_late(char *fontname) { DLOG("Calculated font height: %d\n", font.height); bar_height = font.height + 2 * logical_px(ws_voff_px); + if (config.separator_symbol) + separator_symbol_width = predict_text_width(config.separator_symbol); + xcb_flush(xcb_connection); if (config.hide_on_modifier == M_HIDE) diff --git a/include/config.h b/include/config.h index afafb64b..9a0af0e6 100644 --- a/include/config.h +++ b/include/config.h @@ -285,6 +285,9 @@ struct Barconfig { /** Font specification for all text rendered on the bar. */ char *font; + /** A custom separator to use instead of a vertical line. */ + char *separator_symbol; + /** Hide workspace buttons? Configuration option is 'workspace_buttons no' * but we invert the bool to get the correct default when initializing with * zero. */ diff --git a/include/config_directives.h b/include/config_directives.h index 0f1a6620..6c960b1f 100644 --- a/include/config_directives.h +++ b/include/config_directives.h @@ -67,6 +67,7 @@ CFGFUN(enter_mode, const char *mode); CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *whole_window, const char *command); CFGFUN(bar_font, const char *font); +CFGFUN(bar_separator_symbol, const char *separator); CFGFUN(bar_mode, const char *mode); CFGFUN(bar_hidden_state, const char *hidden_state); CFGFUN(bar_id, const char *bar_id); diff --git a/parser-specs/config.spec b/parser-specs/config.spec index dbdf83c2..25be5cf1 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -370,6 +370,7 @@ state BAR: 'output' -> BAR_OUTPUT 'tray_output' -> BAR_TRAY_OUTPUT 'font' -> BAR_FONT + 'separator_symbol' -> BAR_SEPARATOR_SYMBOL 'binding_mode_indicator' -> BAR_BINDING_MODE_INDICATOR 'workspace_buttons' -> BAR_WORKSPACE_BUTTONS 'strip_workspace_numbers' -> BAR_STRIP_WORKSPACE_NUMBERS @@ -435,6 +436,10 @@ state BAR_FONT: font = string -> call cfg_bar_font($font); BAR +state BAR_SEPARATOR_SYMBOL: + separator = string + -> call cfg_bar_separator_symbol($separator); BAR + state BAR_BINDING_MODE_INDICATOR: value = word -> call cfg_bar_binding_mode_indicator($value); BAR diff --git a/src/config_directives.c b/src/config_directives.c index 80d7876b..c8b25c76 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -421,6 +421,11 @@ CFGFUN(bar_font, const char *font) { current_bar.font = sstrdup(font); } +CFGFUN(bar_separator_symbol, const char *separator) { + FREE(current_bar.separator_symbol); + current_bar.separator_symbol = sstrdup(separator); +} + CFGFUN(bar_mode, const char *mode) { current_bar.mode = (strcmp(mode, "dock") == 0 ? M_DOCK : (strcmp(mode, "hide") == 0 ? M_HIDE : M_INVISIBLE)); } diff --git a/src/ipc.c b/src/ipc.c index acd2267b..ea6a7de9 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -594,6 +594,11 @@ static void dump_bar_config(yajl_gen gen, Barconfig *config) { YSTR_IF_SET(status_command); YSTR_IF_SET(font); + if (config->separator_symbol) { + ystr("separator_symbol"); + ystr(config->separator_symbol); + } + ystr("workspace_buttons"); y(bool, !config->hide_workspace_buttons); diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t index 9643aa42..1e91d47f 100644 --- a/testcases/t/201-config-parser.t +++ b/testcases/t/201-config-parser.t @@ -647,7 +647,7 @@ EOT $expected = <<'EOT'; cfg_bar_output(LVDS-1) -ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'i3bar_command', 'status_command', 'socket_path', 'mode', 'hidden_state', 'id', 'modifier', 'wheel_up_cmd', 'wheel_down_cmd', 'position', 'output', 'tray_output', 'font', 'binding_mode_indicator', 'workspace_buttons', 'strip_workspace_numbers', 'verbose', 'colors', '}' +ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'i3bar_command', 'status_command', 'socket_path', 'mode', 'hidden_state', 'id', 'modifier', 'wheel_up_cmd', 'wheel_down_cmd', 'position', 'output', 'tray_output', 'font', 'separator_symbol', 'binding_mode_indicator', 'workspace_buttons', 'strip_workspace_numbers', 'verbose', 'colors', '}' ERROR: CONFIG: (in file ) ERROR: CONFIG: Line 1: bar { ERROR: CONFIG: Line 2: output LVDS-1