Separator color and width via config; separator off via ipc
Patch status: rejected
Patch by Artem Shinkarov
Long description:
This patch adds the following features: 1) Configure a color of the separator via config. It is done like bar { colors { separator #000000 } } 2) Configure a width of the gap between the items. In the middle of that gap separating line is being drawn. The syntax is the following: bar { separator_block_width 11 } which would set the width of the gap to 11 pixels. If not specified the default is 9 pixels. 3) A block can have a boolean entry "separator" and if it is set to false, then the drawing of the separating line would be disabled.
To apply this patch, use:
curl http://cr.i3wm.org/patch/34/raw.patch | git am
b/docs/i3bar-protocol
45 |
@@ -154,6 +154,11 @@ urgent:: |
46 |
A boolean which specifies whether the current value is urgent. Examples |
47 |
are battery charge values below 1 percent or no more available disk |
48 |
space (for non-root users). The presentation of urgency is up to i3bar. |
49 |
+separator:: |
50 |
+ The boolean value false disables drawing of a separating line after the |
51 |
+ block. If the field is not present then the separator will be still |
52 |
+ drawn. Keep in mind that absence of a separator is only responsible for |
53 |
+ the line itself, the gap between the items would be still present. |
54 |
|
55 |
If you want to put in your own entries into a block, prefix the key with an |
56 |
underscore (_). i3bar will ignore all keys it doesn’t understand, and prefixing |
b/docs/ipc
61 |
@@ -497,6 +497,9 @@ workspace_buttons (boolean):: |
62 |
Display workspace buttons or not? Defaults to true. |
63 |
verbose (boolean):: |
64 |
Should the bar enable verbose output for debugging? Defaults to false. |
65 |
+separator_block_width (integer):: |
66 |
+ The width of the gap between items. In the middle of the gap, a separating |
67 |
+ line is going to be drawn. |
68 |
colors (map):: |
69 |
Contains key/value pairs of colors. Each value is a color code in hex, |
70 |
formatted #rrggbb (like in HTML). |
71 |
@@ -507,6 +510,8 @@ background:: |
72 |
Background color of the bar. |
73 |
statusline:: |
74 |
Text color to be used for the statusline. |
75 |
+separator:: |
76 |
+ Text color to be used for the separator. |
77 |
focused_workspace_text/focused_workspace_bg:: |
78 |
Text color/background color for a workspace button when the workspace |
79 |
has focus. |
b/docs/userguide
84 |
@@ -1145,6 +1145,26 @@ bar { |
85 |
} |
86 |
-------------------- |
87 |
|
88 |
+=== Width of the gap between items |
89 |
+ |
90 |
+Specifies the width of the gap between the items in the statusline. The number |
91 |
+represents the width in pixels, value 0 means no gap. Please keep in mind that |
92 |
+the separating line is drawn in the middle of the gap, so it is recommended to |
93 |
+keep the value odd. If not specified, the default gap width is 9 pixels. |
94 |
+ |
95 |
+*Syntax*: |
96 |
+-------------------------- |
97 |
+separator_block_width <number> |
98 |
+-------------------------- |
99 |
+ |
100 |
+*Example*: |
101 |
+-------------------- |
102 |
+bar { |
103 |
+ separator_block_width 5 |
104 |
+} |
105 |
+-------------------- |
106 |
+ |
107 |
+ |
108 |
=== Colors |
109 |
|
110 |
As with i3, colors are in HTML hex format (#rrggbb). The following colors can |
111 |
@@ -1154,6 +1174,8 @@ background:: |
112 |
Background color of the bar. |
113 |
statusline:: |
114 |
Text color to be used for the statusline. |
115 |
+separator:: |
116 |
+ Text color to be used for the separator. |
117 |
focused_workspace:: |
118 |
Border, background and text color for a workspace button when the workspace |
119 |
has focus. |
120 |
@@ -1175,6 +1197,7 @@ urgent_workspace:: |
121 |
colors { |
122 |
background <color> |
123 |
statusline <color> |
124 |
+ separator <color> |
125 |
|
126 |
colorclass <border> <background> <text> |
127 |
} |
128 |
@@ -1186,6 +1209,7 @@ bar { |
129 |
colors { |
130 |
background #000000 |
131 |
statusline #ffffff |
132 |
+ separator #666666 |
133 |
|
134 |
focused_workspace #4c7899 #285577 #ffffff |
135 |
active_workspace #333333 #5f676a #ffffff |
b/i3bar/include/common.h
140 |
@@ -43,6 +43,7 @@ struct status_block { |
141 |
blockalign_t align; |
142 |
|
143 |
bool urgent; |
144 |
+ bool no_separator; |
145 |
|
146 |
/* The amount of pixels necessary to render this block. These variables are |
147 |
* only temporarily used in refresh_statusline(). */ |
b/i3bar/include/config.h
152 |
@@ -30,6 +30,7 @@ typedef struct config_t { |
153 |
char *fontname; |
154 |
char *tray_output; |
155 |
int num_outputs; |
156 |
+ uint32_t sep_block_width; |
157 |
char **outputs; |
158 |
} config_t; |
159 |
|
b/i3bar/include/xcb.h
164 |
@@ -28,6 +28,7 @@ |
165 |
struct xcb_color_strings_t { |
166 |
char *bar_fg; |
167 |
char *bar_bg; |
168 |
+ char *sep_fg; |
169 |
char *active_ws_fg; |
170 |
char *active_ws_bg; |
171 |
char *active_ws_border; |
172 |
@@ -65,6 +66,13 @@ void init_xcb_late(char *fontname); |
173 |
void init_colors(const struct xcb_color_strings_t *colors); |
174 |
|
175 |
/* |
176 |
+ * Initialize the sizes |
177 |
+ * |
178 |
+ */ |
179 |
+void init_sizes(const uint32_t _sep_block_width); |
180 |
+ |
181 |
+ |
182 |
+/* |
183 |
* Cleanup the xcb-stuff. |
184 |
* Called once, before the program terminates. |
185 |
* |
b/i3bar/src/child.c
190 |
@@ -117,6 +117,9 @@ static int stdin_boolean(void *context, int val) { |
191 |
if (strcasecmp(ctx->last_map_key, "urgent") == 0) { |
192 |
ctx->block.urgent = val; |
193 |
} |
194 |
+ if (strcasecmp(ctx->last_map_key, "separator") == 0) { |
195 |
+ ctx->block.no_separator = !val; |
196 |
+ } |
197 |
return 1; |
198 |
} |
199 |
|
b/i3bar/src/config.c
204 |
@@ -161,6 +161,7 @@ static int config_string_cb(void *params_, const unsigned char *val, unsigned in |
205 |
|
206 |
COLOR(statusline, bar_fg); |
207 |
COLOR(background, bar_bg); |
208 |
+ COLOR(separator, sep_fg); |
209 |
COLOR(focused_workspace_border, focus_ws_border); |
210 |
COLOR(focused_workspace_bg, focus_ws_bg); |
211 |
COLOR(focused_workspace_text, focus_ws_fg); |
212 |
@@ -199,11 +200,32 @@ static int config_boolean_cb(void *params_, int val) { |
213 |
return 0; |
214 |
} |
215 |
|
216 |
+/* |
217 |
+ * Parse an integer value |
218 |
+ * |
219 |
+ */ |
220 |
+#if YAJL_MAJOR >= 2 |
221 |
+static int config_integer_cb(void *params_, long long val) { |
222 |
+#else |
223 |
+static int config_integer_cb(void *params_, long val) { |
224 |
+#endif |
225 |
+ if (!strcmp(cur_key, "separator_block_width")) { |
226 |
+ uint32_t uval = val < 0 ? 0 : (uint32_t)val; |
227 |
+ |
228 |
+ DLOG("separator_block_width = %u\n", uval); |
229 |
+ config.sep_block_width = uval; |
230 |
+ return 1; |
231 |
+ } |
232 |
+ |
233 |
+ return 0; |
234 |
+} |
235 |
+ |
236 |
+ |
237 |
/* A datastructure to pass all these callbacks to yajl */ |
238 |
static yajl_callbacks outputs_callbacks = { |
239 |
&config_null_cb, |
240 |
&config_boolean_cb, |
241 |
- NULL, |
242 |
+ &config_integer_cb, |
243 |
NULL, |
244 |
NULL, |
245 |
&config_string_cb, |
246 |
@@ -260,6 +282,7 @@ void free_colors(struct xcb_color_strings_t *colors) { |
247 |
} while (0) |
248 |
FREE_COLOR(bar_fg); |
249 |
FREE_COLOR(bar_bg); |
250 |
+ FREE_COLOR(sep_fg); |
251 |
FREE_COLOR(active_ws_fg); |
252 |
FREE_COLOR(active_ws_bg); |
253 |
FREE_COLOR(active_ws_border); |
b/i3bar/src/ipc.c
258 |
@@ -100,6 +100,9 @@ void got_bar_config(char *reply) { |
259 |
/* Resolve color strings to colorpixels and save them, then free the strings. */ |
260 |
init_colors(&(config.colors)); |
261 |
|
262 |
+ /* Initialize sizes from config */ |
263 |
+ init_sizes(config.sep_block_width); |
264 |
+ |
265 |
/* The name of this function is actually misleading. Even if no command is |
266 |
* specified, this function initiates the watchers to listen on stdin and |
267 |
* react accordingly */ |
b/i3bar/src/xcb.c
272 |
@@ -71,6 +71,10 @@ xcb_gcontext_t statusline_clear; |
273 |
xcb_pixmap_t statusline_pm; |
274 |
uint32_t statusline_width; |
275 |
|
276 |
+/* Sizes obtained through config */ |
277 |
+/* 'sep_block_width' -- width of the gap between items (in px) */ |
278 |
+static uint32_t sep_block_width; |
279 |
+ |
280 |
/* Event-Watchers, to interact with the user */ |
281 |
ev_prepare *xcb_prep; |
282 |
ev_check *xcb_chk; |
283 |
@@ -84,6 +88,7 @@ static mode binding; |
284 |
struct xcb_colors_t { |
285 |
uint32_t bar_fg; |
286 |
uint32_t bar_bg; |
287 |
+ uint32_t sep_fg; |
288 |
uint32_t active_ws_fg; |
289 |
uint32_t active_ws_bg; |
290 |
uint32_t active_ws_border; |
291 |
@@ -149,7 +154,8 @@ void refresh_statusline(void) { |
292 |
|
293 |
/* If this is not the last block, add some pixels for a separator. */ |
294 |
if (TAILQ_NEXT(block, blocks) != NULL) |
295 |
- block->width += 9; |
296 |
+ block->width += sep_block_width; |
297 |
+ |
298 |
statusline_width += block->width + block->x_offset + block->x_append; |
299 |
} |
300 |
|
301 |
@@ -174,12 +180,14 @@ void refresh_statusline(void) { |
302 |
draw_text(block->full_text, statusline_pm, statusline_ctx, x + block->x_offset, 1, block->width); |
303 |
x += block->width + block->x_offset + block->x_append; |
304 |
|
305 |
- if (TAILQ_NEXT(block, blocks) != NULL) { |
306 |
+ if (TAILQ_NEXT(block, blocks) != NULL && !block->no_separator && sep_block_width > 0) { |
307 |
/* This is not the last block, draw a separator. */ |
308 |
- set_font_colors(statusline_ctx, get_colorpixel("#666666"), colors.bar_bg); |
309 |
+ uint32_t sep_offset = sep_block_width/2 + sep_block_width % 2; |
310 |
+ set_font_colors(statusline_ctx, colors.sep_fg, colors.bar_bg); |
311 |
xcb_poly_line(xcb_connection, XCB_COORD_MODE_ORIGIN, statusline_pm, |
312 |
statusline_ctx, 2, |
313 |
- (xcb_point_t[]){ { x - 5, 2 }, { x - 5, font.height - 2 } }); |
314 |
+ (xcb_point_t[]){ { x - sep_offset, 2 }, |
315 |
+ { x - sep_offset, font.height - 2 } }); |
316 |
} |
317 |
} |
318 |
} |
319 |
@@ -259,6 +267,7 @@ void init_colors(const struct xcb_color_strings_t *new_colors) { |
320 |
} while (0) |
321 |
PARSE_COLOR(bar_fg, "#FFFFFF"); |
322 |
PARSE_COLOR(bar_bg, "#000000"); |
323 |
+ PARSE_COLOR(sep_fg, "#666666"); |
324 |
PARSE_COLOR(active_ws_fg, "#FFFFFF"); |
325 |
PARSE_COLOR(active_ws_bg, "#333333"); |
326 |
PARSE_COLOR(active_ws_border, "#333333"); |
327 |
@@ -277,6 +286,10 @@ void init_colors(const struct xcb_color_strings_t *new_colors) { |
328 |
xcb_flush(xcb_connection); |
329 |
} |
330 |
|
331 |
+void init_sizes(const uint32_t _sep_block_width) { |
332 |
+ sep_block_width = _sep_block_width; |
333 |
+} |
334 |
+ |
335 |
/* |
336 |
* Handle a button-press-event (i.e. a mouse click on one of our bars). |
337 |
* We determine, whether the click occured on a ws-button or if the scroll- |
b/include/config.h
342 |
@@ -256,6 +256,9 @@ struct Barconfig { |
343 |
/** Font specification for all text rendered on the bar. */ |
344 |
char *font; |
345 |
|
346 |
+ /** Width of the gap between the items (in px). */ |
347 |
+ int32_t separator_block_width; |
348 |
+ |
349 |
/** Hide workspace buttons? Configuration option is 'workspace_buttons no' |
350 |
* but we invert the bool to get the correct default when initializing with |
351 |
* zero. */ |
352 |
@@ -267,6 +270,7 @@ struct Barconfig { |
353 |
struct bar_colors { |
354 |
char *background; |
355 |
char *statusline; |
356 |
+ char *separator; |
357 |
|
358 |
char *focused_workspace_border; |
359 |
char *focused_workspace_bg; |
b/include/config_directives.h
364 |
@@ -61,6 +61,7 @@ CFGFUN(enter_mode, const char *mode); |
365 |
CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *command); |
366 |
|
367 |
CFGFUN(bar_font, const char *font); |
368 |
+CFGFUN(bar_sep_block_width, const long width); |
369 |
CFGFUN(bar_mode, const char *mode); |
370 |
CFGFUN(bar_output, const char *output); |
371 |
CFGFUN(bar_verbose, const char *verbose); |
b/parser-specs/config.spec
376 |
@@ -345,18 +345,19 @@ state BAR: |
377 |
error -> |
378 |
'#' -> BAR_IGNORE_LINE |
379 |
'set' -> BAR_IGNORE_LINE |
380 |
- 'i3bar_command' -> BAR_BAR_COMMAND |
381 |
- 'status_command' -> BAR_STATUS_COMMAND |
382 |
- 'socket_path' -> BAR_SOCKET_PATH |
383 |
- 'mode' -> BAR_MODE |
384 |
- 'modifier' -> BAR_MODIFIER |
385 |
- 'position' -> BAR_POSITION |
386 |
- 'output' -> BAR_OUTPUT |
387 |
- 'tray_output' -> BAR_TRAY_OUTPUT |
388 |
- 'font' -> BAR_FONT |
389 |
- 'workspace_buttons' -> BAR_WORKSPACE_BUTTONS |
390 |
- 'verbose' -> BAR_VERBOSE |
391 |
- 'colors' -> BAR_COLORS_BRACE |
392 |
+ 'i3bar_command' -> BAR_BAR_COMMAND |
393 |
+ 'status_command' -> BAR_STATUS_COMMAND |
394 |
+ 'socket_path' -> BAR_SOCKET_PATH |
395 |
+ 'mode' -> BAR_MODE |
396 |
+ 'modifier' -> BAR_MODIFIER |
397 |
+ 'position' -> BAR_POSITION |
398 |
+ 'output' -> BAR_OUTPUT |
399 |
+ 'tray_output' -> BAR_TRAY_OUTPUT |
400 |
+ 'font' -> BAR_FONT |
401 |
+ 'separator_block_width' -> BAR_SEP_BLOCK_WIDTH |
402 |
+ 'workspace_buttons' -> BAR_WORKSPACE_BUTTONS |
403 |
+ 'verbose' -> BAR_VERBOSE |
404 |
+ 'colors' -> BAR_COLORS_BRACE |
405 |
'}' |
406 |
-> call cfg_bar_finish(); INITIAL |
407 |
|
408 |
@@ -401,6 +402,11 @@ state BAR_FONT: |
409 |
font = string |
410 |
-> call cfg_bar_font($font); BAR |
411 |
|
412 |
+state BAR_SEP_BLOCK_WIDTH: |
413 |
+ width = number |
414 |
+ -> call cfg_bar_sep_block_width(&width); BAR |
415 |
+ |
416 |
+ |
417 |
state BAR_WORKSPACE_BUTTONS: |
418 |
value = word |
419 |
-> call cfg_bar_workspace_buttons($value); BAR |
420 |
@@ -419,7 +425,7 @@ state BAR_COLORS: |
421 |
end -> |
422 |
'#' -> BAR_COLORS_IGNORE_LINE |
423 |
'set' -> BAR_COLORS_IGNORE_LINE |
424 |
- colorclass = 'background', 'statusline' |
425 |
+ colorclass = 'background', 'statusline', 'separator' |
426 |
-> BAR_COLORS_SINGLE |
427 |
colorclass = 'focused_workspace', 'active_workspace', 'inactive_workspace', 'urgent_workspace' |
428 |
-> BAR_COLORS_BORDER |
b/src/config_directives.c
433 |
@@ -439,13 +439,24 @@ CFGFUN(assign, const char *workspace) { |
434 |
* Bar configuration (i3bar) |
435 |
******************************************************************************/ |
436 |
|
437 |
-static Barconfig current_bar; |
438 |
+/* Initialize members that might not be set via config, |
439 |
+ but which need default values. */ |
440 |
+#define default_bar_config \ |
441 |
+{ \ |
442 |
+ .separator_block_width = 9 \ |
443 |
+} |
444 |
+ |
445 |
+static Barconfig current_bar = default_bar_config; |
446 |
|
447 |
CFGFUN(bar_font, const char *font) { |
448 |
FREE(current_bar.font); |
449 |
current_bar.font = sstrdup(font); |
450 |
} |
451 |
|
452 |
+CFGFUN(bar_sep_block_width, const long width) { |
453 |
+ current_bar.separator_block_width = width; |
454 |
+} |
455 |
+ |
456 |
CFGFUN(bar_mode, const char *mode) { |
457 |
current_bar.mode = (strcmp(mode, "hide") == 0 ? M_HIDE : M_DOCK); |
458 |
} |
459 |
@@ -526,7 +537,10 @@ CFGFUN(bar_tray_output, const char *output) { |
460 |
CFGFUN(bar_color_single, const char *colorclass, const char *color) { |
461 |
if (strcmp(colorclass, "background") == 0) |
462 |
current_bar.colors.background = sstrdup(color); |
463 |
- else current_bar.colors.statusline = sstrdup(color); |
464 |
+ else if (strcmp(colorclass, "separator") == 0) |
465 |
+ current_bar.colors.separator = sstrdup(color); |
466 |
+ else |
467 |
+ current_bar.colors.statusline = sstrdup(color); |
468 |
} |
469 |
|
470 |
CFGFUN(bar_status_command, const char *command) { |
471 |
@@ -561,4 +575,5 @@ CFGFUN(bar_finish) { |
472 |
TAILQ_INSERT_TAIL(&barconfigs, bar_config, configs); |
473 |
|
474 |
memset(¤t_bar, '\0', sizeof(Barconfig)); |
475 |
+ current_bar = (Barconfig) default_bar_config; |
476 |
} |
b/src/ipc.c
481 |
@@ -658,6 +658,9 @@ IPC_HANDLER(get_bar_config) { |
482 |
YSTR_IF_SET(status_command); |
483 |
YSTR_IF_SET(font); |
484 |
|
485 |
+ ystr("separator_block_width"); |
486 |
+ y(integer, config->separator_block_width); |
487 |
+ |
488 |
ystr("workspace_buttons"); |
489 |
y(bool, !config->hide_workspace_buttons); |
490 |
|
491 |
@@ -677,6 +680,7 @@ IPC_HANDLER(get_bar_config) { |
492 |
y(map_open); |
493 |
YSTR_IF_SET(background); |
494 |
YSTR_IF_SET(statusline); |
495 |
+ YSTR_IF_SET(separator); |
496 |
YSTR_IF_SET(focused_workspace_border); |
497 |
YSTR_IF_SET(focused_workspace_bg); |
498 |
YSTR_IF_SET(focused_workspace_text); |
b/testcases/t/201-config-parser.t
503 |
@@ -591,7 +591,7 @@ EOT |
504 |
|
505 |
$expected = <<'EOT'; |
506 |
cfg_bar_output(LVDS-1) |
507 |
-ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'i3bar_command', 'status_command', 'socket_path', 'mode', 'modifier', 'position', 'output', 'tray_output', 'font', 'workspace_buttons', 'verbose', 'colors', '}' |
508 |
+ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'i3bar_command', 'status_command', 'socket_path', 'mode', 'modifier', 'position', 'output', 'tray_output', 'font', 'separator_block_width', 'workspace_buttons', 'verbose', 'colors', '}' |
509 |
ERROR: CONFIG: (in file <stdin>) |
510 |
ERROR: CONFIG: Line 1: bar { |
511 |
ERROR: CONFIG: Line 2: output LVDS-1 |