i3 - improved tiling WM


Add support for double-sided i3bar, background colors and centered text

Patch status: rejected

Patch by S0lll0s

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

b/i3bar/include/common.h

20
@@ -16,8 +16,10 @@
21
 typedef struct rect_t rect;
22
 
23
 struct ev_loop* main_loop;
24
-char            *statusline;
25
-char            *statusline_buffer;
26
+char            *l_statusline;
27
+char            *r_statusline;
28
+char            *l_statusline_buffer;
29
+char            *r_statusline_buffer;
30
 
31
 struct rect_t {
32
     int x;
33
@@ -38,6 +40,7 @@ struct status_block {
34
     i3String *full_text;
35
 
36
     char *color;
37
+    char *bgcolor;
38
     uint32_t min_width;
39
     blockalign_t align;
40
 
41
@@ -60,7 +63,7 @@ struct status_block {
42
     TAILQ_ENTRY(status_block) blocks;
43
 };
44
 
45
-TAILQ_HEAD(statusline_head, status_block) statusline_head;
46
+TAILQ_HEAD(statusline_head, status_block) l_statusline_head, r_statusline_head;
47
 
48
 #include "child.h"
49
 #include "ipc.h"

b/i3bar/include/config.h

54
@@ -27,6 +27,7 @@ typedef struct config_t {
55
     struct xcb_color_strings_t colors;
56
     bool         disable_binding_mode_indicator;
57
     bool         disable_ws;
58
+    bool         custom_ws;
59
     char         *bar_id;
60
     char         *command;
61
     char         *fontname;

b/i3bar/src/child.c

66
@@ -30,6 +30,8 @@
67
 /* Global variables for child_*() */
68
 i3bar_child child;
69
 
70
+int inbar = 0;
71
+
72
 /* stdin- and sigchild-watchers */
73
 ev_io    *stdin_io;
74
 ev_child *child_sig;
75
@@ -55,8 +57,10 @@ typedef struct parser_ctx {
76
 parser_ctx parser_context;
77
 
78
 /* The buffer statusline points to */
79
-struct statusline_head statusline_head = TAILQ_HEAD_INITIALIZER(statusline_head);
80
-char *statusline_buffer = NULL;
81
+struct statusline_head l_statusline_head = TAILQ_HEAD_INITIALIZER(l_statusline_head);
82
+struct statusline_head r_statusline_head = TAILQ_HEAD_INITIALIZER(r_statusline_head);
83
+char *l_statusline_buffer = NULL;
84
+char *r_statusline_buffer = NULL;
85
 
86
 int child_stdin;
87
 
88
@@ -66,10 +70,16 @@ int child_stdin;
89
  */
90
 static void clear_status_blocks() {
91
     struct status_block *first;
92
-    while (!TAILQ_EMPTY(&statusline_head)) {
93
-        first = TAILQ_FIRST(&statusline_head);
94
+    while (!TAILQ_EMPTY(&l_statusline_head)) {
95
+        first = TAILQ_FIRST(&l_statusline_head);
96
         I3STRING_FREE(first->full_text);
97
-        TAILQ_REMOVE(&statusline_head, first, blocks);
98
+        TAILQ_REMOVE(&l_statusline_head, first, blocks);
99
+        free(first);
100
+    }
101
+    while (!TAILQ_EMPTY(&r_statusline_head)) {
102
+        first = TAILQ_FIRST(&r_statusline_head);
103
+        I3STRING_FREE(first->full_text);
104
+        TAILQ_REMOVE(&r_statusline_head, first, blocks);
105
         free(first);
106
     }
107
 }
108
@@ -100,8 +110,8 @@ __attribute__ ((format (printf, 1, 2))) static void set_statusline_error(const c
109
     message_block->color = "red";
110
     message_block->no_separator = true;
111
 
112
-    TAILQ_INSERT_HEAD(&statusline_head, err_block, blocks);
113
-    TAILQ_INSERT_TAIL(&statusline_head, message_block, blocks);
114
+    TAILQ_INSERT_HEAD(&r_statusline_head, err_block, blocks);
115
+    TAILQ_INSERT_TAIL(&r_statusline_head, message_block, blocks);
116
 
117
     FREE(message);
118
     va_end(args);
119
@@ -115,9 +125,11 @@ void cleanup(void) {
120
     if (stdin_io != NULL) {
121
         ev_io_stop(main_loop, stdin_io);
122
         FREE(stdin_io);
123
-        FREE(statusline_buffer);
124
+        FREE(l_statusline_buffer);
125
+        FREE(r_statusline_buffer);
126
         /* statusline pointed to memory within statusline_buffer */
127
-        statusline = NULL;
128
+        l_statusline = NULL;
129
+        r_statusline = NULL;
130
     }
131
 
132
     if (child_sig != NULL) {
133
@@ -134,16 +146,27 @@ void cleanup(void) {
134
  *
135
  */
136
 static int stdin_start_array(void *context) {
137
-    struct status_block *first;
138
-    while (!TAILQ_EMPTY(&statusline_head)) {
139
-        first = TAILQ_FIRST(&statusline_head);
140
-        I3STRING_FREE(first->full_text);
141
-        FREE(first->color);
142
-        FREE(first->name);
143
-        FREE(first->instance);
144
-        TAILQ_REMOVE(&statusline_head, first, blocks);
145
-        free(first);
146
-    }
147
+	if ( inbar || !config.custom_ws ) { 
148
+    	struct status_block *first;
149
+		struct statusline_head *head;
150
+
151
+		if ( inbar == 2 || !config.custom_ws )
152
+			head = &r_statusline_head;
153
+		else
154
+			head = &l_statusline_head;
155
+
156
+    	while (!TAILQ_EMPTY(head)) {
157
+	        first = TAILQ_FIRST(head);
158
+    	    I3STRING_FREE(first->full_text);
159
+	        FREE(first->color);
160
+	        FREE(first->name);
161
+	        FREE(first->instance);
162
+	        TAILQ_REMOVE(head, first, blocks);
163
+	        free(first);
164
+	    }
165
+	} else {
166
+		inbar = 2;
167
+	}
168
     return 1;
169
 }
170
 
171
@@ -195,6 +218,9 @@ static int stdin_string(void *context, const unsigned char *val, unsigned int le
172
     if (strcasecmp(ctx->last_map_key, "color") == 0) {
173
         sasprintf(&(ctx->block.color), "%.*s", len, val);
174
     }
175
+    if (strcasecmp(ctx->last_map_key, "background_color") == 0) {
176
+        sasprintf(&(ctx->block.bgcolor), "%.*s", len, val);
177
+    }
178
     if (strcasecmp(ctx->last_map_key, "align") == 0) {
179
         if (len == strlen("left") && !strncmp((const char*)val, "left", strlen("left"))) {
180
             ctx->block.align = ALIGN_LEFT;
181
@@ -248,18 +274,23 @@ static int stdin_end_map(void *context) {
182
         new_block->full_text = i3string_from_utf8("SPEC VIOLATION (null)");
183
     if (new_block->urgent)
184
         ctx->has_urgent = true;
185
-    TAILQ_INSERT_TAIL(&statusline_head, new_block, blocks);
186
+	if ( inbar == 2 || !config.custom_ws )
187
+    	TAILQ_INSERT_TAIL(&r_statusline_head, new_block, blocks);
188
+	else
189
+    	TAILQ_INSERT_TAIL(&l_statusline_head, new_block, blocks);
190
     return 1;
191
 }
192
 
193
 static int stdin_end_array(void *context) {
194
     DLOG("dumping statusline:\n");
195
     struct status_block *current;
196
-    TAILQ_FOREACH(current, &statusline_head, blocks) {
197
+    TAILQ_FOREACH(current, &r_statusline_head, blocks) {
198
         DLOG("full_text = %s\n", i3string_as_utf8(current->full_text));
199
         DLOG("color = %s\n", current->color);
200
     }
201
     DLOG("end of dump\n");
202
+	if ( inbar )
203
+		inbar--;
204
     return 1;
205
 }
206
 
207
@@ -307,7 +338,7 @@ static unsigned char *get_buffer(ev_io *watcher, int *ret_buffer_len) {
208
 }
209
 
210
 static void read_flat_input(char *buffer, int length) {
211
-    struct status_block *first = TAILQ_FIRST(&statusline_head);
212
+    struct status_block *first = TAILQ_FIRST(&r_statusline_head);
213
     /* Clear the old buffer if any. */
214
     I3STRING_FREE(first->full_text);
215
     /* Remove the trailing newline and terminate the string at the same
216
@@ -391,7 +422,7 @@ void stdin_io_first_line_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
217
         /* In case of plaintext, we just add a single block and change its
218
          * full_text pointer later. */
219
         struct status_block *new_block = scalloc(sizeof(struct status_block));
220
-        TAILQ_INSERT_TAIL(&statusline_head, new_block, blocks);
221
+        TAILQ_INSERT_TAIL(&r_statusline_head, new_block, blocks);
222
         read_flat_input((char*)buffer, rec);
223
     }
224
     free(buffer);

b/i3bar/src/main.c

229
@@ -172,7 +172,8 @@ int main(int argc, char **argv) {
230
 
231
     kill_child();
232
 
233
-    FREE(statusline_buffer);
234
+    FREE(l_statusline_buffer);
235
+    FREE(r_statusline_buffer);
236
 
237
     clean_xcb();
238
     ev_default_destroy();

b/i3bar/src/parse_json_header.c

243
@@ -32,6 +32,7 @@ static enum {
244
     KEY_STOP_SIGNAL,
245
     KEY_CONT_SIGNAL,
246
     KEY_CLICK_EVENTS,
247
+	KEY_CUSTOM_WS,
248
     NO_KEY
249
 } current_key;
250
 
251
@@ -66,6 +67,9 @@ static int header_boolean(void *ctx, int val) {
252
         case KEY_CLICK_EVENTS:
253
             child->click_events = val;
254
             break;
255
+		case KEY_CUSTOM_WS:
256
+            config.custom_ws = (bool)val;
257
+            break;
258
         default:
259
             break;
260
     }
261
@@ -89,6 +93,8 @@ static int header_map_key(void *ctx, const unsigned char *stringval, unsigned in
262
         current_key = KEY_CONT_SIGNAL;
263
     } else if (CHECK_KEY("click_events")) {
264
         current_key = KEY_CLICK_EVENTS;
265
+    } else if (CHECK_KEY("custom_workspace")) {
266
+        current_key = KEY_CUSTOM_WS;
267
     }
268
     return 1;
269
 }

b/i3bar/src/xcb.c

274
@@ -69,10 +69,14 @@ int              mod_pressed = 0;
275
 
276
 /* Because the statusline is the same on all outputs, we have
277
  * global buffer to render it on */
278
-xcb_gcontext_t   statusline_ctx;
279
-xcb_gcontext_t   statusline_clear;
280
-xcb_pixmap_t     statusline_pm;
281
-uint32_t         statusline_width;
282
+xcb_gcontext_t   l_statusline_ctx;
283
+xcb_gcontext_t   r_statusline_ctx;
284
+xcb_gcontext_t   l_statusline_clear;
285
+xcb_gcontext_t   r_statusline_clear;
286
+xcb_pixmap_t     l_statusline_pm;
287
+xcb_pixmap_t     r_statusline_pm;
288
+uint32_t         l_statusline_width;
289
+uint32_t         r_statusline_width;
290
 
291
 /* Event-Watchers, to interact with the user */
292
 ev_prepare *xcb_prep;
293
@@ -121,14 +125,28 @@ int _xcb_request_failed(xcb_void_cookie_t cookie, char *err_msg, int line) {
294
  * Redraws the statusline to the buffer
295
  *
296
  */
297
-void refresh_statusline(void) {
298
+void refresh_statusline( bool left ) {
299
     struct status_block *block;
300
 
301
-    uint32_t old_statusline_width = statusline_width;
302
-    statusline_width = 0;
303
+	xcb_gcontext_t	*statusline_ctx		= &r_statusline_ctx;
304
+	xcb_gcontext_t  *statusline_clear	= &r_statusline_clear;
305
+	xcb_pixmap_t    *statusline_pm		= &r_statusline_pm;
306
+	uint32_t        *statusline_width	= &r_statusline_width;
307
+	struct statusline_head *statusline_head	= &r_statusline_head;
308
+
309
+	if ( left ) {
310
+		statusline_ctx		= &l_statusline_ctx;
311
+		statusline_clear	= &l_statusline_clear;
312
+		statusline_pm		= &l_statusline_pm;
313
+		statusline_width	= &l_statusline_width;
314
+		statusline_head		= &l_statusline_head;
315
+	}
316
+
317
+    uint32_t old_statusline_width = (*statusline_width);
318
+    (*statusline_width) = 0;
319
 
320
     /* Predict the text width of all blocks (in pixels). */
321
-    TAILQ_FOREACH(block, &statusline_head, blocks) {
322
+    TAILQ_FOREACH(block, statusline_head, blocks) {
323
         if (i3string_get_num_bytes(block->full_text) == 0)
324
             continue;
325
 
326
@@ -158,28 +176,29 @@ void refresh_statusline(void) {
327
         if (TAILQ_NEXT(block, blocks) != NULL)
328
             block->width += block->sep_block_width;
329
 
330
-        statusline_width += block->width + block->x_offset + block->x_append;
331
+        (*statusline_width) += block->width + block->x_offset + block->x_append;
332
     }
333
 
334
     /* If the statusline is bigger than our screen we need to make sure that
335
      * the pixmap provides enough space, so re-allocate if the width grew */
336
-    if (statusline_width > root_screen->width_in_pixels &&
337
-        statusline_width > old_statusline_width)
338
+    if ((*statusline_width) > root_screen->width_in_pixels &&
339
+        (*statusline_width) > old_statusline_width)
340
         realloc_sl_buffer();
341
 
342
     /* Clear the statusline pixmap. */
343
     xcb_rectangle_t rect = { 0, 0, root_screen->width_in_pixels, font.height + 2 };
344
-    xcb_poly_fill_rectangle(xcb_connection, statusline_pm, statusline_clear, 1, &rect);
345
+    xcb_poly_fill_rectangle(xcb_connection, (*statusline_pm), (*statusline_clear), 1, &rect);
346
 
347
     /* Draw the text of each block. */
348
     uint32_t x = 0;
349
-    TAILQ_FOREACH(block, &statusline_head, blocks) {
350
+    TAILQ_FOREACH(block, statusline_head, blocks) {
351
         if (i3string_get_num_bytes(block->full_text) == 0)
352
             continue;
353
 
354
         uint32_t colorpixel = (block->color ? get_colorpixel(block->color) : colors.bar_fg);
355
-        set_font_colors(statusline_ctx, colorpixel, colors.bar_bg);
356
-        draw_text(block->full_text, statusline_pm, statusline_ctx, x + block->x_offset, 1, block->width);
357
+		uint32_t bgcolorpix = (block->bgcolor ? get_colorpixel(block->bgcolor) : colors.bar_bg);
358
+        set_font_colors((*statusline_ctx), colorpixel, bgcolorpix);
359
+        draw_text(block->full_text, (*statusline_pm), (*statusline_ctx), x + block->x_offset, 1, block->width);
360
         x += block->width + block->x_offset + block->x_append;
361
 
362
         if (TAILQ_NEXT(block, blocks) != NULL && !block->no_separator && block->sep_block_width > 0) {
363
@@ -187,9 +206,9 @@ void refresh_statusline(void) {
364
             uint32_t sep_offset = block->sep_block_width/2 + block->sep_block_width % 2;
365
             uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
366
             uint32_t values[] = { colors.sep_fg, colors.bar_bg };
367
-            xcb_change_gc(xcb_connection, statusline_ctx, mask, values);
368
-            xcb_poly_line(xcb_connection, XCB_COORD_MODE_ORIGIN, statusline_pm,
369
-                          statusline_ctx, 2,
370
+            xcb_change_gc(xcb_connection, (*statusline_ctx), mask, values);
371
+            xcb_poly_line(xcb_connection, XCB_COORD_MODE_ORIGIN, (*statusline_pm),
372
+                          (*statusline_ctx), 2,
373
                           (xcb_point_t[]){ { x - sep_offset, 2 },
374
                                            { x - sep_offset, font.height - 2 } });
375
         }
376
@@ -376,7 +395,7 @@ void handle_button(xcb_button_press_event_t *event) {
377
                 }
378
 
379
                 int block_x = 0, last_block_x;
380
-                int offset = (walk->rect.w - (statusline_width + tray_width)) - 10;
381
+                int offset = (walk->rect.w - (r_statusline_width + tray_width)) - 10;
382
 
383
                 x = original_x - offset;
384
                 if (x < 0)
385
@@ -384,7 +403,7 @@ void handle_button(xcb_button_press_event_t *event) {
386
 
387
                 struct status_block *block;
388
 
389
-                TAILQ_FOREACH(block, &statusline_head, blocks) {
390
+                TAILQ_FOREACH(block, &r_statusline_head, blocks) {
391
                     last_block_x = block_x;
392
                     block_x += block->width + block->x_offset + block->x_append;
393
 
394
@@ -983,24 +1002,43 @@ char *init_xcb_early() {
395
     uint32_t mask = XCB_GC_FOREGROUND;
396
     uint32_t vals[] = { colors.bar_bg, colors.bar_bg };
397
 
398
-    statusline_clear = xcb_generate_id(xcb_connection);
399
-    xcb_void_cookie_t clear_ctx_cookie = xcb_create_gc_checked(xcb_connection,
400
-                                                               statusline_clear,
401
+    l_statusline_clear = xcb_generate_id(xcb_connection);
402
+    r_statusline_clear = xcb_generate_id(xcb_connection);
403
+    xcb_void_cookie_t l_clear_ctx_cookie = xcb_create_gc_checked(xcb_connection,
404
+                                                               l_statusline_clear,
405
+                                                               xcb_root,
406
+                                                               mask,
407
+                                                               vals);
408
+    xcb_void_cookie_t r_clear_ctx_cookie = xcb_create_gc_checked(xcb_connection,
409
+                                                               r_statusline_clear,
410
                                                                xcb_root,
411
                                                                mask,
412
                                                                vals);
413
 
414
-    statusline_ctx = xcb_generate_id(xcb_connection);
415
-    xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection,
416
-                                                            statusline_ctx,
417
+    l_statusline_ctx = xcb_generate_id(xcb_connection);
418
+    r_statusline_ctx = xcb_generate_id(xcb_connection);
419
+    xcb_void_cookie_t l_sl_ctx_cookie = xcb_create_gc_checked(xcb_connection,
420
+                                                            l_statusline_ctx,
421
+                                                            xcb_root,
422
+                                                            0,
423
+                                                            NULL);
424
+    xcb_void_cookie_t r_sl_ctx_cookie = xcb_create_gc_checked(xcb_connection,
425
+                                                            r_statusline_ctx,
426
                                                             xcb_root,
427
                                                             0,
428
                                                             NULL);
429
 
430
-    statusline_pm = xcb_generate_id(xcb_connection);
431
-    xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
432
+    l_statusline_pm = xcb_generate_id(xcb_connection);
433
+    r_statusline_pm = xcb_generate_id(xcb_connection);
434
+    xcb_void_cookie_t l_sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
435
                                                                root_screen->root_depth,
436
-                                                               statusline_pm,
437
+                                                               l_statusline_pm,
438
+                                                               xcb_root,
439
+                                                               root_screen->width_in_pixels,
440
+                                                               root_screen->height_in_pixels);
441
+    xcb_void_cookie_t r_sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
442
+                                                               root_screen->root_depth,
443
+                                                               r_statusline_pm,
444
                                                                xcb_root,
445
                                                                root_screen->width_in_pixels,
446
                                                                root_screen->height_in_pixels);
447
@@ -1024,9 +1062,14 @@ char *init_xcb_early() {
448
 
449
     char *path = root_atom_contents("I3_SOCKET_PATH", xcb_connection, screen);
450
 
451
-    if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer") ||
452
-        xcb_request_failed(clear_ctx_cookie, "Could not allocate statusline-buffer-clearcontext") ||
453
-        xcb_request_failed(sl_ctx_cookie, "Could not allocate statusline-buffer-context")) {
454
+    if (xcb_request_failed(l_sl_pm_cookie, "Could not allocate statusline-buffer") ||
455
+        xcb_request_failed(l_clear_ctx_cookie, "Could not allocate statusline-buffer-clearcontext") ||
456
+        xcb_request_failed(l_sl_ctx_cookie, "Could not allocate statusline-buffer-context")) {
457
+        exit(EXIT_FAILURE);
458
+    }
459
+    if (xcb_request_failed(r_sl_pm_cookie, "Could not allocate statusline-buffer") ||
460
+        xcb_request_failed(r_clear_ctx_cookie, "Could not allocate statusline-buffer-clearcontext") ||
461
+        xcb_request_failed(r_sl_ctx_cookie, "Could not allocate statusline-buffer-context")) {
462
         exit(EXIT_FAILURE);
463
     }
464
 
465
@@ -1373,39 +1416,66 @@ void destroy_window(i3_output *output) {
466
  */
467
 void realloc_sl_buffer(void) {
468
     DLOG("Re-allocating statusline-buffer, statusline_width = %d, root_screen->width_in_pixels = %d\n",
469
-         statusline_width, root_screen->width_in_pixels);
470
-    xcb_free_pixmap(xcb_connection, statusline_pm);
471
-    statusline_pm = xcb_generate_id(xcb_connection);
472
-    xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
473
+         r_statusline_width, root_screen->width_in_pixels);
474
+    xcb_free_pixmap(xcb_connection, l_statusline_pm);
475
+    xcb_free_pixmap(xcb_connection, r_statusline_pm);
476
+    l_statusline_pm = xcb_generate_id(xcb_connection);
477
+    r_statusline_pm = xcb_generate_id(xcb_connection);
478
+    xcb_void_cookie_t l_sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
479
                                                                root_screen->root_depth,
480
-                                                               statusline_pm,
481
+                                                               l_statusline_pm,
482
                                                                xcb_root,
483
-                                                               MAX(root_screen->width_in_pixels, statusline_width),
484
+                                                               MAX(root_screen->width_in_pixels, l_statusline_width),
485
+                                                               bar_height);
486
+    xcb_void_cookie_t r_sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
487
+                                                               root_screen->root_depth,
488
+                                                               r_statusline_pm,
489
+                                                               xcb_root,
490
+                                                               MAX(root_screen->width_in_pixels, r_statusline_width),
491
                                                                bar_height);
492
 
493
     uint32_t mask = XCB_GC_FOREGROUND;
494
     uint32_t vals[2] = { colors.bar_bg, colors.bar_bg };
495
-    xcb_free_gc(xcb_connection, statusline_clear);
496
-    statusline_clear = xcb_generate_id(xcb_connection);
497
-    xcb_void_cookie_t clear_ctx_cookie = xcb_create_gc_checked(xcb_connection,
498
-                                                               statusline_clear,
499
+    xcb_free_gc(xcb_connection, l_statusline_clear);
500
+    xcb_free_gc(xcb_connection, r_statusline_clear);
501
+    l_statusline_clear = xcb_generate_id(xcb_connection);
502
+    r_statusline_clear = xcb_generate_id(xcb_connection);
503
+    xcb_void_cookie_t l_clear_ctx_cookie = xcb_create_gc_checked(xcb_connection,
504
+                                                               l_statusline_clear,
505
+                                                               xcb_root,
506
+                                                               mask,
507
+                                                               vals);
508
+    xcb_void_cookie_t r_clear_ctx_cookie = xcb_create_gc_checked(xcb_connection,
509
+                                                               r_statusline_clear,
510
                                                                xcb_root,
511
                                                                mask,
512
                                                                vals);
513
 
514
     mask |= XCB_GC_BACKGROUND;
515
     vals[0] = colors.bar_fg;
516
-    xcb_free_gc(xcb_connection, statusline_ctx);
517
-    statusline_ctx = xcb_generate_id(xcb_connection);
518
-    xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection,
519
-                                                            statusline_ctx,
520
+    l_statusline_ctx = xcb_generate_id(xcb_connection);
521
+    r_statusline_ctx = xcb_generate_id(xcb_connection);
522
+    xcb_free_gc(xcb_connection, l_statusline_ctx);
523
+    xcb_free_gc(xcb_connection, r_statusline_ctx);
524
+    xcb_void_cookie_t l_sl_ctx_cookie = xcb_create_gc_checked(xcb_connection,
525
+                                                            l_statusline_ctx,
526
+                                                            xcb_root,
527
+                                                            mask,
528
+                                                            vals);
529
+    xcb_void_cookie_t r_sl_ctx_cookie = xcb_create_gc_checked(xcb_connection,
530
+                                                            r_statusline_ctx,
531
                                                             xcb_root,
532
                                                             mask,
533
                                                             vals);
534
 
535
-    if (xcb_request_failed(sl_pm_cookie, "Could not allocate statusline-buffer") ||
536
-        xcb_request_failed(clear_ctx_cookie, "Could not allocate statusline-buffer-clearcontext") ||
537
-        xcb_request_failed(sl_ctx_cookie, "Could not allocate statusline-buffer-context")) {
538
+    if (xcb_request_failed(l_sl_pm_cookie, "Could not allocate statusline-buffer") ||
539
+        xcb_request_failed(l_clear_ctx_cookie, "Could not allocate statusline-buffer-clearcontext") ||
540
+        xcb_request_failed(l_sl_ctx_cookie, "Could not allocate statusline-buffer-context")) {
541
+        exit(EXIT_FAILURE);
542
+    }
543
+    if (xcb_request_failed(r_sl_pm_cookie, "Could not allocate statusline-buffer") ||
544
+        xcb_request_failed(r_clear_ctx_cookie, "Could not allocate statusline-buffer-clearcontext") ||
545
+        xcb_request_failed(r_sl_ctx_cookie, "Could not allocate statusline-buffer-context")) {
546
         exit(EXIT_FAILURE);
547
     }
548
 
549
@@ -1669,7 +1739,9 @@ void draw_bars(bool unhide) {
550
     DLOG("Drawing Bars...\n");
551
     int i = 0;
552
 
553
-    refresh_statusline();
554
+	if ( config.custom_ws )
555
+		refresh_statusline( 1 );
556
+    refresh_statusline( 0 );
557
 
558
     i3_output *outputs_walk;
559
     SLIST_FOREACH(outputs_walk, outputs, slist) {
560
@@ -1694,7 +1766,7 @@ void draw_bars(bool unhide) {
561
                                 1,
562
                                 &rect);
563
 
564
-        if (!TAILQ_EMPTY(&statusline_head)) {
565
+        if (!TAILQ_EMPTY(&r_statusline_head)) {
566
             DLOG("Printing statusline!\n");
567
 
568
             /* Luckily we already prepared a seperate pixmap containing the rendered
569
@@ -1714,17 +1786,27 @@ void draw_bars(bool unhide) {
570
             if (traypx > 0)
571
                 traypx += 2;
572
             xcb_copy_area(xcb_connection,
573
-                          statusline_pm,
574
+                          r_statusline_pm,
575
                           outputs_walk->buffer,
576
                           outputs_walk->bargc,
577
-                          MAX(0, (int16_t)(statusline_width - outputs_walk->rect.w + 4)), 0,
578
-                          MAX(0, (int16_t)(outputs_walk->rect.w - statusline_width - traypx - 4)), 3,
579
-                          MIN(outputs_walk->rect.w - traypx - 4, (int)statusline_width), font.height + 2);
580
+                          MAX(0, (int16_t)(r_statusline_width - outputs_walk->rect.w + 4)), 0,
581
+                          MAX(0, (int16_t)(outputs_walk->rect.w - r_statusline_width - traypx - 4)), 2,
582
+                          MIN(outputs_walk->rect.w - traypx - 4, r_statusline_width), font.height + 2);
583
         }
584
 
585
         if (!config.disable_ws) {
586
             i3_ws *ws_walk;
587
-            TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
588
+
589
+        	TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
590
+			if (config.custom_ws) {
591
+				xcb_copy_area(xcb_connection,
592
+							  l_statusline_pm,
593
+							  outputs_walk->buffer,
594
+							  outputs_walk->bargc,
595
+							  0, 0,
596
+							  0, 2,
597
+							  l_statusline_width, font.height + 2 );
598
+			} else {
599
                 DLOG("Drawing Button for WS %s at x = %d, len = %d\n",
600
                      i3string_as_utf8(ws_walk->name), i, ws_walk->name_width);
601
                 uint32_t fg_color = colors.inactive_ws_fg;
602
@@ -1813,7 +1895,7 @@ void draw_bars(bool unhide) {
603
 
604
             unhide = true;
605
         }
606
-
607
+		}
608
         i = 0;
609
     }
610
 

b/libi3/font.c

615
@@ -29,6 +29,9 @@ static xcb_visualtype_t *root_visual_type;
616
 static double pango_font_red;
617
 static double pango_font_green;
618
 static double pango_font_blue;
619
+static double pango_bgfont_red;
620
+static double pango_bgfont_green;
621
+static double pango_bgfont_blue;
622
 
623
 /* Necessary to track whether the dpi changes and trigger a LOG() message,
624
  * which is more easily visible to users. */
625
@@ -120,6 +123,10 @@ static void draw_text_pango(const char *text, size_t text_len,
626
     pango_layout_set_text(layout, text, text_len);
627
 
628
     /* Do the drawing */
629
+	cairo_set_source_rgb(cr, pango_bgfont_red, pango_bgfont_green, pango_bgfont_blue);
630
+	cairo_rectangle(cr, x, y, max_width, savedFont->height); 
631
+	cairo_fill(cr);
632
+
633
     cairo_set_source_rgb(cr, pango_font_red, pango_font_green, pango_font_blue);
634
     pango_cairo_update_layout(cr, layout);
635
     pango_layout_get_pixel_size(layout, NULL, &height);
636
@@ -303,6 +310,11 @@ void set_font_colors(xcb_gcontext_t gc, uint32_t foreground, uint32_t background
637
             pango_font_red = ((foreground >> 16) & 0xff) / 255.0;
638
             pango_font_green = ((foreground >> 8) & 0xff) / 255.0;
639
             pango_font_blue = (foreground & 0xff) / 255.0;
640
+
641
+            /* Save the background font */
642
+            pango_bgfont_red = ((background >> 16) & 0xff) / 255.0;
643
+            pango_bgfont_green = ((background >> 8) & 0xff) / 255.0;
644
+            pango_bgfont_blue = (background & 0xff) / 255.0;
645
             break;
646
 #endif
647
         default: