From dc05d905c1ab0978ca98b3e15ff96d18df55c182 Mon Sep 17 00:00:00 2001 From: David Simon Date: Mon, 26 Oct 2015 16:55:01 -0400 Subject: [PATCH] Optionally change i3bar color on focused output, implements #2020 --- docs/ipc | 8 ++++++++ docs/userguide | 9 +++++++++ i3bar/include/outputs.h | 6 ++++++ i3bar/include/xcb.h | 3 +++ i3bar/src/config.c | 6 ++++++ i3bar/src/outputs.c | 14 +++++++++++++ i3bar/src/xcb.c | 38 ++++++++++++++++++++++++++---------- include/config.h | 4 ++++ parser-specs/config.spec | 2 +- src/config.c | 4 ++++ src/config_directives.c | 8 +++++++- src/ipc.c | 3 +++ testcases/t/177-bar-config.t | 6 ++++++ 13 files changed, 99 insertions(+), 12 deletions(-) diff --git a/docs/ipc b/docs/ipc index 1813e53a..5231c5ec 100644 --- a/docs/ipc +++ b/docs/ipc @@ -520,6 +520,14 @@ statusline:: Text color to be used for the statusline. separator:: Text color to be used for the separator. +focused_background:: + Background color of the bar on the currently focused monitor output. +focused_statusline:: + Text color to be used for the statusline on the currently focused + monitor output. +focused_separator:: + Text color to be used for the separator on the currently focused + monitor output. focused_workspace_text/focused_workspace_bg/focused_workspace_border:: Text/background/border color for a workspace button when the workspace has focus. diff --git a/docs/userguide b/docs/userguide index e866dfb1..ca39757a 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1529,6 +1529,15 @@ statusline:: Text color to be used for the statusline. separator:: Text color to be used for the separator. +focused_background:: + Background color of the bar on the currently focused monitor output. If + not used, the color will be taken from +background+. +focused_statusline:: + Text color to be used for the statusline on the currently focused + monitor output. If not used, the color will be taken from +statusline+. +focused_separator:: + Text color to be used for the separator on the currently focused + monitor output. If not used, the color will be taken from +separator+. focused_workspace:: Border, background and text color for a workspace button when the workspace has focus. diff --git a/i3bar/include/outputs.h b/i3bar/include/outputs.h index ec09e764..08adefd9 100644 --- a/i3bar/include/outputs.h +++ b/i3bar/include/outputs.h @@ -38,6 +38,12 @@ void init_outputs(void); */ i3_output* get_output_by_name(char* name); +/* + * Returns true if the output has the currently focused workspace + * + */ +bool output_has_focus(i3_output* output); + struct i3_output { char* name; /* Name of the output */ bool active; /* If the output is active */ diff --git a/i3bar/include/xcb.h b/i3bar/include/xcb.h index 3746204c..0a9bd7e4 100644 --- a/i3bar/include/xcb.h +++ b/i3bar/include/xcb.h @@ -34,6 +34,9 @@ struct xcb_color_strings_t { char *bar_fg; char *bar_bg; char *sep_fg; + char *focus_bar_fg; + char *focus_bar_bg; + char *focus_sep_fg; char *active_ws_fg; char *active_ws_bg; char *active_ws_border; diff --git a/i3bar/src/config.c b/i3bar/src/config.c index f3412719..6476d15f 100644 --- a/i3bar/src/config.c +++ b/i3bar/src/config.c @@ -214,6 +214,9 @@ static int config_string_cb(void *params_, const unsigned char *val, size_t _len COLOR(statusline, bar_fg); COLOR(background, bar_bg); COLOR(separator, sep_fg); + COLOR(focused_statusline, focus_bar_fg); + COLOR(focused_background, focus_bar_bg); + COLOR(focused_separator, focus_sep_fg); COLOR(focused_workspace_border, focus_ws_border); COLOR(focused_workspace_bg, focus_ws_bg); COLOR(focused_workspace_text, focus_ws_fg); @@ -343,6 +346,9 @@ void free_colors(struct xcb_color_strings_t *colors) { FREE_COLOR(bar_fg); FREE_COLOR(bar_bg); FREE_COLOR(sep_fg); + FREE_COLOR(focus_bar_fg); + FREE_COLOR(focus_bar_bg); + FREE_COLOR(focus_sep_fg); FREE_COLOR(active_ws_fg); FREE_COLOR(active_ws_bg); FREE_COLOR(active_ws_border); diff --git a/i3bar/src/outputs.c b/i3bar/src/outputs.c index df3bc69b..841a7565 100644 --- a/i3bar/src/outputs.c +++ b/i3bar/src/outputs.c @@ -302,3 +302,17 @@ i3_output *get_output_by_name(char *name) { return walk; } + +/* + * Returns true if the output has the currently focused workspace + * + */ +bool output_has_focus(i3_output *output) { + i3_ws *ws_walk; + TAILQ_FOREACH(ws_walk, output->workspaces, tailq) { + if (ws_walk->focused) { + return true; + } + } + return false; +} diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 841570e2..20206c8b 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -91,6 +91,9 @@ struct xcb_colors_t { color_t bar_fg; color_t bar_bg; color_t sep_fg; + color_t focus_bar_fg; + color_t focus_bar_bg; + color_t focus_sep_fg; color_t active_ws_fg; color_t active_ws_bg; color_t active_ws_border; @@ -160,7 +163,10 @@ int get_tray_width(struct tc_head *trayclients) { * Draws a separator for the given block if necessary. * */ -static void draw_separator(i3_output *output, uint32_t x, struct status_block *block) { +static void draw_separator(i3_output *output, uint32_t x, struct status_block *block, bool use_focus_colors) { + color_t sep_fg = (use_focus_colors ? colors.focus_sep_fg : colors.sep_fg); + color_t bar_bg = (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg); + uint32_t sep_offset = get_sep_offset(block); if (TAILQ_NEXT(block, blocks) == NULL || sep_offset == 0) return; @@ -168,7 +174,7 @@ static void draw_separator(i3_output *output, uint32_t x, struct status_block *b uint32_t center_x = x - sep_offset; if (config.separator_symbol == NULL) { /* Draw a classic one pixel, vertical separator. */ - draw_util_rectangle(&output->statusline_buffer, colors.sep_fg, + draw_util_rectangle(&output->statusline_buffer, sep_fg, center_x, logical_px(sep_voff_px), logical_px(1), @@ -176,7 +182,7 @@ static void draw_separator(i3_output *output, uint32_t x, struct status_block *b } else { /* Draw a custom separator. */ uint32_t separator_x = MAX(x - block->sep_block_width, center_x - separator_symbol_width / 2); - draw_util_text(config.separator_symbol, &output->statusline_buffer, colors.sep_fg, colors.bar_bg, + draw_util_text(config.separator_symbol, &output->statusline_buffer, sep_fg, bar_bg, separator_x, logical_px(ws_voff_px), x - separator_x); } } @@ -233,10 +239,11 @@ uint32_t predict_statusline_length(bool use_short_text) { /* * Redraws the statusline to the output's statusline_buffer */ -void draw_statusline(i3_output *output, uint32_t clip_left, bool use_short_text) { +void draw_statusline(i3_output *output, uint32_t clip_left, bool use_focus_colors, bool use_short_text) { struct status_block *block; - draw_util_clear_surface(&output->statusline_buffer, colors.bar_bg); + color_t bar_color = (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg); + draw_util_clear_surface(&output->statusline_buffer, bar_color); /* Use unsigned integer wraparound to clip off the left side. * For example, if clip_left is 75, then x will start at the very large @@ -263,17 +270,19 @@ void draw_statusline(i3_output *output, uint32_t clip_left, bool use_short_text) fg_color = colors.urgent_ws_fg; } else if (block->color) { fg_color = draw_util_hex_to_color(block->color); + } else if (use_focus_colors) { + fg_color = colors.focus_bar_fg; } else { fg_color = colors.bar_fg; } - color_t bg_color = colors.bar_bg; + color_t bg_color = bar_color; int border_width = (block->border) ? logical_px(1) : 0; int full_render_width = render->width + render->x_offset + render->x_append; if (block->border || block->background || block->urgent) { /* Let's determine the colors first. */ - color_t border_color = colors.bar_bg; + color_t border_color = bar_color; if (block->urgent) { border_color = colors.urgent_ws_border; bg_color = colors.urgent_ws_bg; @@ -306,7 +315,7 @@ void draw_statusline(i3_output *output, uint32_t clip_left, bool use_short_text) /* If this is not the last block, draw a separator. */ if (TAILQ_NEXT(block, blocks) != NULL) { x += block->sep_block_width; - draw_separator(output, x, block); + draw_separator(output, x, block, use_focus_colors); } } } @@ -412,6 +421,12 @@ void init_colors(const struct xcb_color_strings_t *new_colors) { PARSE_COLOR_FALLBACK(binding_mode_fg, urgent_ws_fg); PARSE_COLOR_FALLBACK(binding_mode_bg, urgent_ws_bg); PARSE_COLOR_FALLBACK(binding_mode_border, urgent_ws_border); + + /* Similarly, for unspecified focused bar colors, we fall back to the + * regular bar colors. */ + PARSE_COLOR_FALLBACK(focus_bar_fg, bar_fg); + PARSE_COLOR_FALLBACK(focus_bar_bg, bar_bg); + PARSE_COLOR_FALLBACK(focus_sep_fg, sep_fg); #undef PARSE_COLOR_FALLBACK init_tray_colors(); @@ -1826,8 +1841,11 @@ void draw_bars(bool unhide) { reconfig_windows(false); } + bool use_focus_colors = output_has_focus(outputs_walk); + /* First things first: clear the backbuffer */ - draw_util_clear_surface(&(outputs_walk->buffer), colors.bar_bg); + draw_util_clear_surface(&(outputs_walk->buffer), + (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg)); if (!config.disable_ws) { i3_ws *ws_walk; @@ -1928,7 +1946,7 @@ void draw_bars(bool unhide) { int16_t visible_statusline_width = MIN(statusline_width, max_statusline_width); int x_dest = outputs_walk->rect.w - tray_width - logical_px(sb_hoff_px) - visible_statusline_width; - draw_statusline(outputs_walk, clip_left, use_short_text); + draw_statusline(outputs_walk, clip_left, use_focus_colors, use_short_text); draw_util_copy_surface(&outputs_walk->statusline_buffer, &outputs_walk->buffer, 0, 0, x_dest, 0, visible_statusline_width, (int16_t)bar_height); diff --git a/include/config.h b/include/config.h index 6312d3d2..1c4ccce6 100644 --- a/include/config.h +++ b/include/config.h @@ -323,6 +323,10 @@ struct Barconfig { char *statusline; char *separator; + char *focused_background; + char *focused_statusline; + char *focused_separator; + char *focused_workspace_border; char *focused_workspace_bg; char *focused_workspace_text; diff --git a/parser-specs/config.spec b/parser-specs/config.spec index 2170ace3..882e81fb 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -520,7 +520,7 @@ state BAR_COLORS: end -> '#' -> BAR_COLORS_IGNORE_LINE 'set' -> BAR_COLORS_IGNORE_LINE - colorclass = 'background', 'statusline', 'separator' + colorclass = 'background', 'statusline', 'separator', 'focused_background', 'focused_statusline', 'focused_separator' -> BAR_COLORS_SINGLE colorclass = 'focused_workspace', 'active_workspace', 'inactive_workspace', 'urgent_workspace', 'binding_mode' -> BAR_COLORS_BORDER diff --git a/src/config.c b/src/config.c index d8db85e6..c1c31e30 100644 --- a/src/config.c +++ b/src/config.c @@ -118,6 +118,10 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, FREE(barconfig->font); FREE(barconfig->colors.background); FREE(barconfig->colors.statusline); + FREE(barconfig->colors.separator); + FREE(barconfig->colors.focused_background); + FREE(barconfig->colors.focused_statusline); + FREE(barconfig->colors.focused_separator); FREE(barconfig->colors.focused_workspace_border); FREE(barconfig->colors.focused_workspace_bg); FREE(barconfig->colors.focused_workspace_text); diff --git a/src/config_directives.c b/src/config_directives.c index 99b70db8..960dee5b 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -533,8 +533,14 @@ CFGFUN(bar_color_single, const char *colorclass, const char *color) { current_bar.colors.background = sstrdup(color); else if (strcmp(colorclass, "separator") == 0) current_bar.colors.separator = sstrdup(color); - else + else if (strcmp(colorclass, "statusline") == 0) current_bar.colors.statusline = sstrdup(color); + else if (strcmp(colorclass, "focused_background") == 0) + current_bar.colors.focused_background = sstrdup(color); + else if (strcmp(colorclass, "focused_separator") == 0) + current_bar.colors.focused_separator = sstrdup(color); + else + current_bar.colors.focused_statusline = sstrdup(color); } CFGFUN(bar_status_command, const char *command) { diff --git a/src/ipc.c b/src/ipc.c index 68cc417a..8e448c7c 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -663,6 +663,9 @@ static void dump_bar_config(yajl_gen gen, Barconfig *config) { YSTR_IF_SET(background); YSTR_IF_SET(statusline); YSTR_IF_SET(separator); + YSTR_IF_SET(focused_background); + YSTR_IF_SET(focused_statusline); + YSTR_IF_SET(focused_separator); YSTR_IF_SET(focused_workspace_border); YSTR_IF_SET(focused_workspace_bg); YSTR_IF_SET(focused_workspace_text); diff --git a/testcases/t/177-bar-config.t b/testcases/t/177-bar-config.t index cc4826c1..8ef94e57 100644 --- a/testcases/t/177-bar-config.t +++ b/testcases/t/177-bar-config.t @@ -109,6 +109,9 @@ bar { colors { background #ff0000 statusline #00ff00 + focused_background #cc0000 + focused_statusline #cccc00 + focused_separator #0000cc focused_workspace #4c7899 #285577 #ffffff active_workspace #333333 #222222 #888888 @@ -143,6 +146,9 @@ is_deeply($bar_config->{colors}, { background => '#ff0000', statusline => '#00ff00', + focused_background => '#cc0000', + focused_statusline=> '#cccc00', + focused_separator => '#0000cc', focused_workspace_border => '#4c7899', focused_workspace_text => '#ffffff', focused_workspace_bg => '#285577',