i3 - improved tiling WM


Add new bar.binding_mode_indicator configuration.

Patch status: merged

Patch by syl20bnr

Long description:

i3 current behavior hides the binding mode indicator when
workspace buttons are disabled.
This patch adds a new configuration for i3bar called
'binding_mode_indicator' which acts like the workspace_buttons.
It is now possible to configure i3bar to hide the
workspace buttons and keep showing the binding mode indicator.
This should make the hide workspace buttons configuration
more convenient for those who are heavily using binding
modes.
Default value for binding_mode_indicator is true.

To apply this patch, use:
curl http://cr.i3wm.org/patch/220/raw.patch | git am

b/docs/ipc

34
@@ -494,6 +494,8 @@ font (string)::
35
 	The font to use for text on the bar.
36
 workspace_buttons (boolean)::
37
 	Display workspace buttons or not? Defaults to true.
38
+binding_mode_indicator (boolean)::
39
+	Display the mode indicator or not? Defaults to true.
40
 verbose (boolean)::
41
 	Should the bar enable verbose output for debugging? Defaults to false.
42
 colors (map)::
43
@@ -539,6 +541,7 @@ urgent_workspace_text/urgent_workspace_bar::
44
  "status_command": "i3status",
45
  "font": "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1",
46
  "workspace_buttons": true,
47
+ "binding_mode_indicator": true,
48
  "verbose": false,
49
  "colors": {
50
    "background": "#c0c0c0",

b/docs/userguide

55
@@ -1180,11 +1180,32 @@ workspace_buttons <yes|no>
56
 --------------------------
57
 
58
 *Example*:
59
---------------------
60
+------------------------
61
 bar {
62
     workspace_buttons no
63
 }
64
---------------------
65
+------------------------
66
+
67
+=== Binding Mode indicator
68
+
69
+Specifies whether the current binding mode indicator should be shown or not.
70
+This is useful if you want to hide the workspace buttons but still be able
71
+to see the current binding mode indicator.
72
+For an example of a +mode+ definition, see <<resizingconfig>>.
73
+
74
+The default is to show the mode indicator.
75
+
76
+*Syntax*:
77
+-------------------------------
78
+binding_mode_indicator <yes|no>
79
+-------------------------------
80
+
81
+*Example*:
82
+-----------------------------
83
+bar {
84
+    binding_mode_indicator no
85
+}
86
+-----------------------------
87
 
88
 === Colors
89
 

b/i3bar/include/config.h

94
@@ -23,7 +23,8 @@ typedef struct config_t {
95
     position_t   position;
96
     int          verbose;
97
     struct xcb_color_strings_t colors;
98
-    int          disable_ws;
99
+    bool         disable_binding_mode_indicator;
100
+    bool         disable_ws;
101
     char         *bar_id;
102
     char         *command;
103
     char         *fontname;

b/i3bar/src/config.c

108
@@ -193,6 +193,12 @@ static int config_string_cb(void *params_, const unsigned char *val, unsigned in
109
  *
110
  */
111
 static int config_boolean_cb(void *params_, int val) {
112
+    if (!strcmp(cur_key, "binding_mode_indicator")) {
113
+        DLOG("binding_mode_indicator = %d\n", val);
114
+        config.disable_binding_mode_indicator = !val;
115
+        return 1;
116
+    }
117
+
118
     if (!strcmp(cur_key, "workspace_buttons")) {
119
         DLOG("workspace_buttons = %d\n", val);
120
         config.disable_ws = !val;

b/i3bar/src/xcb.c

125
@@ -1670,72 +1670,71 @@ void draw_bars(bool unhide) {
126
                           MIN(outputs_walk->rect.w - traypx - 4, statusline_width), font.height + 2);
127
         }
128
 
129
-        if (config.disable_ws) {
130
-            continue;
131
-        }
132
-
133
-        i3_ws *ws_walk;
134
-
135
-        TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
136
-            DLOG("Drawing Button for WS %s at x = %d, len = %d\n", i3string_as_utf8(ws_walk->name), i, ws_walk->name_width);
137
-            uint32_t fg_color = colors.inactive_ws_fg;
138
-            uint32_t bg_color = colors.inactive_ws_bg;
139
-            uint32_t border_color = colors.inactive_ws_border;
140
-            if (ws_walk->visible) {
141
-                if (!ws_walk->focused) {
142
-                    fg_color = colors.active_ws_fg;
143
-                    bg_color = colors.active_ws_bg;
144
-                    border_color = colors.active_ws_border;
145
-                } else {
146
-                    fg_color = colors.focus_ws_fg;
147
-                    bg_color = colors.focus_ws_bg;
148
-                    border_color = colors.focus_ws_border;
149
-                    if (last_urgent_ws && strcmp(i3string_as_utf8(ws_walk->name), last_urgent_ws) == 0)
150
-                        walks_away = false;
151
+        if (!config.disable_ws) {
152
+            i3_ws *ws_walk;
153
+            TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
154
+                DLOG("Drawing Button for WS %s at x = %d, len = %d\n",
155
+                     i3string_as_utf8(ws_walk->name), i, ws_walk->name_width);
156
+                uint32_t fg_color = colors.inactive_ws_fg;
157
+                uint32_t bg_color = colors.inactive_ws_bg;
158
+                uint32_t border_color = colors.inactive_ws_border;
159
+                if (ws_walk->visible) {
160
+                    if (!ws_walk->focused) {
161
+                        fg_color = colors.active_ws_fg;
162
+                        bg_color = colors.active_ws_bg;
163
+                        border_color = colors.active_ws_border;
164
+                    } else {
165
+                        fg_color = colors.focus_ws_fg;
166
+                        bg_color = colors.focus_ws_bg;
167
+                        border_color = colors.focus_ws_border;
168
+                        if (last_urgent_ws && strcmp(i3string_as_utf8(ws_walk->name),
169
+                                                     last_urgent_ws) == 0)
170
+                            walks_away = false;
171
+                    }
172
                 }
173
-            }
174
-            if (ws_walk->urgent) {
175
-                DLOG("WS %s is urgent!\n", i3string_as_utf8(ws_walk->name));
176
-                fg_color = colors.urgent_ws_fg;
177
-                bg_color = colors.urgent_ws_bg;
178
-                border_color = colors.urgent_ws_border;
179
-                unhide = true;
180
-                if (!ws_walk->focused) {
181
-                    FREE(last_urgent_ws);
182
-                    last_urgent_ws = sstrdup(i3string_as_utf8(ws_walk->name));
183
+                if (ws_walk->urgent) {
184
+                    DLOG("WS %s is urgent!\n", i3string_as_utf8(ws_walk->name));
185
+                    fg_color = colors.urgent_ws_fg;
186
+                    bg_color = colors.urgent_ws_bg;
187
+                    border_color = colors.urgent_ws_border;
188
+                    unhide = true;
189
+                    if (!ws_walk->focused) {
190
+                        FREE(last_urgent_ws);
191
+                        last_urgent_ws = sstrdup(i3string_as_utf8(ws_walk->name));
192
+                    }
193
                 }
194
-            }
195
-            uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
196
-            uint32_t vals_border[] = { border_color, border_color };
197
-            xcb_change_gc(xcb_connection,
198
-                          outputs_walk->bargc,
199
-                          mask,
200
-                          vals_border);
201
-            xcb_rectangle_t rect_border = { i, 1, ws_walk->name_width + 10, font.height + 4 };
202
-            xcb_poly_fill_rectangle(xcb_connection,
203
-                                    outputs_walk->buffer,
204
-                                    outputs_walk->bargc,
205
-                                    1,
206
-                                    &rect_border);
207
-            uint32_t vals[] = { bg_color, bg_color };
208
-            xcb_change_gc(xcb_connection,
209
-                          outputs_walk->bargc,
210
-                          mask,
211
-                          vals);
212
-            xcb_rectangle_t rect = { i + 1, 2, ws_walk->name_width + 8, font.height + 2 };
213
-            xcb_poly_fill_rectangle(xcb_connection,
214
-                                    outputs_walk->buffer,
215
-                                    outputs_walk->bargc,
216
-                                    1,
217
-                                    &rect);
218
-            set_font_colors(outputs_walk->bargc, fg_color, bg_color);
219
-            draw_text(ws_walk->name, outputs_walk->buffer, outputs_walk->bargc, i + 5, 3, ws_walk->name_width);
220
-            i += 10 + ws_walk->name_width + 1;
221
+                uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
222
+                uint32_t vals_border[] = { border_color, border_color };
223
+                xcb_change_gc(xcb_connection,
224
+                              outputs_walk->bargc,
225
+                              mask,
226
+                              vals_border);
227
+                xcb_rectangle_t rect_border = { i, 1, ws_walk->name_width + 10, font.height + 4 };
228
+                xcb_poly_fill_rectangle(xcb_connection,
229
+                                        outputs_walk->buffer,
230
+                                        outputs_walk->bargc,
231
+                                        1,
232
+                                        &rect_border);
233
+                uint32_t vals[] = { bg_color, bg_color };
234
+                xcb_change_gc(xcb_connection,
235
+                              outputs_walk->bargc,
236
+                              mask,
237
+                              vals);
238
+                xcb_rectangle_t rect = { i + 1, 2, ws_walk->name_width + 8, font.height + 2 };
239
+                xcb_poly_fill_rectangle(xcb_connection,
240
+                                        outputs_walk->buffer,
241
+                                        outputs_walk->bargc,
242
+                                        1,
243
+                                        &rect);
244
+                set_font_colors(outputs_walk->bargc, fg_color, bg_color);
245
+                draw_text(ws_walk->name, outputs_walk->buffer, outputs_walk->bargc,
246
+                          i + 5, 3, ws_walk->name_width);
247
+                i += 10 + ws_walk->name_width + 1;
248
 
249
+            }
250
         }
251
 
252
-        if (binding.name) {
253
-
254
+        if (binding.name && !config.disable_binding_mode_indicator) {
255
             uint32_t fg_color = colors.urgent_ws_fg;
256
             uint32_t bg_color = colors.urgent_ws_bg;
257
             uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;

b/include/config.h

262
@@ -267,6 +267,10 @@ struct Barconfig {
263
      * zero. */
264
     bool hide_workspace_buttons;
265
 
266
+    /** Hide mode button? Configuration option is 'binding_mode_indicator no'
267
+     * but we invert the bool for the same reason as hide_workspace_buttons.*/
268
+    bool hide_binding_mode_indicator;
269
+
270
     /** Enable verbose mode? Useful for debugging purposes. */
271
     bool verbose;
272
 

b/include/config_directives.h

277
@@ -74,6 +74,7 @@ CFGFUN(bar_socket_path, const char *socket_path);
278
 CFGFUN(bar_tray_output, const char *output);
279
 CFGFUN(bar_color_single, const char *colorclass, const char *color);
280
 CFGFUN(bar_status_command, const char *command);
281
+CFGFUN(bar_binding_mode_indicator, const char *value);
282
 CFGFUN(bar_workspace_buttons, const char *value);
283
 CFGFUN(bar_finish);
284
 

b/parser-specs/config.spec

289
@@ -345,20 +345,21 @@ state BAR:
290
   error ->
291
   '#' -> BAR_IGNORE_LINE
292
   'set' -> BAR_IGNORE_LINE
293
-  'i3bar_command'     -> BAR_BAR_COMMAND
294
-  'status_command'    -> BAR_STATUS_COMMAND
295
-  'socket_path'       -> BAR_SOCKET_PATH
296
-  'mode'              -> BAR_MODE
297
-  'hidden_state'      -> BAR_HIDDEN_STATE
298
-  'id'                -> BAR_ID
299
-  'modifier'          -> BAR_MODIFIER
300
-  'position'          -> BAR_POSITION
301
-  'output'            -> BAR_OUTPUT
302
-  'tray_output'       -> BAR_TRAY_OUTPUT
303
-  'font'              -> BAR_FONT
304
-  'workspace_buttons' -> BAR_WORKSPACE_BUTTONS
305
-  'verbose'           -> BAR_VERBOSE
306
-  'colors'            -> BAR_COLORS_BRACE
307
+  'i3bar_command'          -> BAR_BAR_COMMAND
308
+  'status_command'         -> BAR_STATUS_COMMAND
309
+  'socket_path'            -> BAR_SOCKET_PATH
310
+  'mode'                   -> BAR_MODE
311
+  'hidden_state'           -> BAR_HIDDEN_STATE
312
+  'id'                     -> BAR_ID
313
+  'modifier'               -> BAR_MODIFIER
314
+  'position'               -> BAR_POSITION
315
+  'output'                 -> BAR_OUTPUT
316
+  'tray_output'            -> BAR_TRAY_OUTPUT
317
+  'font'                   -> BAR_FONT
318
+  'binding_mode_indicator' -> BAR_BINDING_MODE_INDICATOR
319
+  'workspace_buttons'      -> BAR_WORKSPACE_BUTTONS
320
+  'verbose'                -> BAR_VERBOSE
321
+  'colors'                 -> BAR_COLORS_BRACE
322
   '}'
323
       -> call cfg_bar_finish(); INITIAL
324
 
325
@@ -411,6 +412,10 @@ state BAR_FONT:
326
   font = string
327
       -> call cfg_bar_font($font); BAR
328
 
329
+state BAR_BINDING_MODE_INDICATOR:
330
+  value = word
331
+      -> call cfg_bar_binding_mode_indicator($value); BAR
332
+
333
 state BAR_WORKSPACE_BUTTONS:
334
   value = word
335
       -> call cfg_bar_workspace_buttons($value); BAR

b/src/config_directives.c

340
@@ -550,6 +550,10 @@ CFGFUN(bar_status_command, const char *command) {
341
     current_bar.status_command = sstrdup(command);
342
 }
343
 
344
+CFGFUN(bar_binding_mode_indicator, const char *value) {
345
+    current_bar.hide_binding_mode_indicator = !eval_boolstr(value);
346
+}
347
+
348
 CFGFUN(bar_workspace_buttons, const char *value) {
349
     current_bar.hide_workspace_buttons = !eval_boolstr(value);
350
 }

b/src/ipc.c

355
@@ -686,6 +686,9 @@ IPC_HANDLER(get_bar_config) {
356
         ystr("workspace_buttons");
357
         y(bool, !config->hide_workspace_buttons);
358
 
359
+        ystr("binding_mode_indicator");
360
+        y(bool, !config->hide_binding_mode_indicator);
361
+
362
         ystr("verbose");
363
         y(bool, config->verbose);
364
 

b/testcases/t/177-bar-config.t

369
@@ -63,6 +63,7 @@ my $bar_config = $i3->get_bar_config($bar_id)->recv;
370
 is($bar_config->{status_command}, 'i3status --foo', 'status_command correct');
371
 ok(!$bar_config->{verbose}, 'verbose off by default');
372
 ok($bar_config->{workspace_buttons}, 'workspace buttons enabled per default');
373
+ok($bar_config->{binding_mode_indicator}, 'mode indicator enabled per default');
374
 is($bar_config->{mode}, 'dock', 'dock mode by default');
375
 is($bar_config->{position}, 'bottom', 'position bottom by default');
376
 
377
@@ -85,7 +86,8 @@ $config = <<EOT;
378
 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
379
 
380
 bar {
381
-    # Start a default instance of i3bar which provides workspace buttons.
382
+    # Start a default instance of i3bar which does not provide
383
+    # workspace buttons.
384
     # Additionally, i3status will provide a statusline.
385
     status_command i3status --bar
386
 
387
@@ -98,6 +100,7 @@ bar {
388
     mode dock
389
     font Terminus
390
     workspace_buttons no
391
+    binding_mode_indicator no
392
     verbose yes
393
     socket_path /tmp/foobar
394
 
395
@@ -125,6 +128,7 @@ $bar_config = $i3->get_bar_config($bar_id)->recv;
396
 is($bar_config->{status_command}, 'i3status --bar', 'status_command correct');
397
 ok($bar_config->{verbose}, 'verbose on');
398
 ok(!$bar_config->{workspace_buttons}, 'workspace buttons disabled');
399
+ok(!$bar_config->{binding_mode_indicator}, 'mode indicator disabled');
400
 is($bar_config->{mode}, 'dock', 'dock mode');
401
 is($bar_config->{position}, 'top', 'position top');
402
 is_deeply($bar_config->{outputs}, [ 'HDMI1', 'HDMI2' ], 'outputs ok');
403
@@ -230,7 +234,8 @@ $config = <<EOT;
404
 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
405
 
406
 bar {
407
-    # Start a default instance of i3bar which provides workspace buttons.
408
+    # Start a default instance of i3bar which does not provide
409
+    # workspace buttons.
410
     # Additionally, i3status will provide a statusline.
411
     status_command i3status --bar
412
 
413
@@ -243,6 +248,7 @@ bar {
414
     mode dock
415
     font Terminus
416
     workspace_buttons no
417
+    binding_mode_indicator yes
418
     verbose yes
419
     socket_path /tmp/foobar
420
 
421
@@ -271,6 +277,7 @@ $bar_config = $i3->get_bar_config($bar_id)->recv;
422
 is($bar_config->{status_command}, 'i3status --bar', 'status_command correct');
423
 ok($bar_config->{verbose}, 'verbose on');
424
 ok(!$bar_config->{workspace_buttons}, 'workspace buttons disabled');
425
+ok($bar_config->{binding_mode_indicator}, 'mode indicator enabled');
426
 is($bar_config->{mode}, 'dock', 'dock mode');
427
 is($bar_config->{position}, 'top', 'position top');
428
 is_deeply($bar_config->{outputs}, [ 'HDMI1', 'HDMI2' ], 'outputs ok');

b/testcases/t/201-config-parser.t

433
@@ -627,7 +627,7 @@ EOT
434
 
435
 $expected = <<'EOT';
436
 cfg_bar_output(LVDS-1)
437
-ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'i3bar_command', 'status_command', 'socket_path', 'mode', 'hidden_state', 'id', 'modifier', 'position', 'output', 'tray_output', 'font', 'workspace_buttons', 'verbose', 'colors', '}'
438
+ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'i3bar_command', 'status_command', 'socket_path', 'mode', 'hidden_state', 'id', 'modifier', 'position', 'output', 'tray_output', 'font', 'binding_mode_indicator', 'workspace_buttons', 'verbose', 'colors', '}'
439
 ERROR: CONFIG: (in file <stdin>)
440
 ERROR: CONFIG: Line   1: bar {
441
 ERROR: CONFIG: Line   2:     output LVDS-1