i3 - improved tiling WM


Feature: send complete config on barconfig_update

Patch status: merged

Patch by Tony Crisci

Long description:

Send all the options in the bar block on the barconfig_update event.

This will eventually allow for dynamically updating bar colors with the
`reload` command.

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

b/docs/ipc

21
@@ -637,7 +637,7 @@ window (3)::
22
 	focus or when a window title has been updated.
23
 barconfig_update (4)::
24
     Sent when the hidden_state or mode field in the barconfig of any bar
25
-    instance was updated.
26
+    instance was updated and when the config is reloaded.
27
 
28
 *Example:*
29
 --------------------------------------------------------------------
30
@@ -738,20 +738,8 @@ this point get the window title as "urxvt").
31
 === barconfig_update event
32
 
33
 This event consists of a single serialized map reporting on options from the
34
-barconfig of the specified bar_id that were updated in i3. The map always
35
-consists of a property +id (string)+, which specifies to which bar instance the
36
-sent config update belongs, a property +hidden_state (string)+, which indicates
37
-the hidden_state of an i3bar instance, and a property +mode (string)+, which
38
-corresponds to the current mode.
39
-
40
-*Example:*
41
----------------------------
42
-{
43
-    "id": "bar-0",
44
-    "hidden_state": "hide"
45
-    "mode": "hide"
46
-}
47
----------------------------
48
+barconfig of the specified bar_id that were updated in i3. This event is the
49
+same as a +GET_BAR_CONFIG+ reply for the bar with the given id.
50
 
51
 == See also (existing libraries)
52
 

b/include/config.h

57
@@ -317,9 +317,9 @@ void ungrab_all_keys(xcb_connection_t *conn);
58
 
59
 /**
60
  * Sends the current bar configuration as an event to all barconfig_update listeners.
61
- * This update mechnism currently only includes the hidden_state and the mode in the config.
62
  *
63
- */void update_barconfig();
64
+ */
65
+void update_barconfig();
66
 
67
 /**
68
  * Kills the configerror i3-nagbar process, if any.

b/include/ipc.h

73
@@ -16,6 +16,7 @@
74
 
75
 #include "data.h"
76
 #include "tree.h"
77
+#include "config.h"
78
 
79
 #include "i3/ipc.h"
80
 
81
@@ -93,3 +94,8 @@ void ipc_send_workspace_focus_event(Con *current, Con *old);
82
  * also the window container, in "container".
83
  */
84
 void ipc_send_window_event(const char *property, Con *con);
85
+
86
+/**
87
+ * For the barconfig update events, we send the serialized barconfig.
88
+ */
89
+void ipc_send_barconfig_update_event(Barconfig *barconfig);

b/src/config.c

94
@@ -32,44 +32,12 @@ void ungrab_all_keys(xcb_connection_t *conn) {
95
 
96
 /*
97
  * Sends the current bar configuration as an event to all barconfig_update listeners.
98
- * This update mechnism currently only includes the hidden_state and the mode in the config.
99
  *
100
  */
101
 void update_barconfig() {
102
     Barconfig *current;
103
     TAILQ_FOREACH(current, &barconfigs, configs) {
104
-        /* Build json message */
105
-        char *hidden_state;
106
-        switch (current->hidden_state) {
107
-            case S_SHOW:
108
-                hidden_state ="show";
109
-                break;
110
-            case S_HIDE:
111
-            default:
112
-                hidden_state = "hide";
113
-                break;
114
-        }
115
-
116
-        char *mode;
117
-        switch (current->mode) {
118
-            case M_HIDE:
119
-                mode ="hide";
120
-                break;
121
-            case M_INVISIBLE:
122
-                mode ="invisible";
123
-                break;
124
-            case M_DOCK:
125
-            default:
126
-                mode = "dock";
127
-                break;
128
-        }
129
-
130
-        /* Send an event to all barconfig listeners*/
131
-        char *event_msg;
132
-        sasprintf(&event_msg, "{ \"id\":\"%s\", \"hidden_state\":\"%s\", \"mode\":\"%s\" }", current->id, hidden_state, mode);
133
-
134
-        ipc_send_event("barconfig_update", I3_IPC_EVENT_BARCONFIG_UPDATE, event_msg);
135
-        FREE(event_msg);
136
+        ipc_send_barconfig_update_event(current);
137
     }
138
 }
139
 

b/src/ipc.c

144
@@ -423,6 +423,135 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
145
     y(map_close);
146
 }
147
 
148
+static void dump_bar_config(yajl_gen gen, Barconfig *config) {
149
+    y(map_open);
150
+
151
+    ystr("id");
152
+    ystr(config->id);
153
+
154
+    if (config->num_outputs > 0) {
155
+        ystr("outputs");
156
+        y(array_open);
157
+        for (int c = 0; c < config->num_outputs; c++)
158
+            ystr(config->outputs[c]);
159
+        y(array_close);
160
+    }
161
+
162
+#define YSTR_IF_SET(name) \
163
+    do { \
164
+        if (config->name) { \
165
+            ystr( # name); \
166
+            ystr(config->name); \
167
+        } \
168
+    } while (0)
169
+
170
+    YSTR_IF_SET(tray_output);
171
+    YSTR_IF_SET(socket_path);
172
+
173
+    ystr("mode");
174
+    switch (config->mode) {
175
+        case M_HIDE:
176
+            ystr("hide");
177
+            break;
178
+        case M_INVISIBLE:
179
+            ystr("invisible");
180
+            break;
181
+        case M_DOCK:
182
+        default:
183
+            ystr("dock");
184
+            break;
185
+    }
186
+
187
+    ystr("hidden_state");
188
+    switch (config->hidden_state) {
189
+        case S_SHOW:
190
+            ystr("show");
191
+            break;
192
+        case S_HIDE:
193
+        default:
194
+            ystr("hide");
195
+            break;
196
+    }
197
+
198
+    ystr("modifier");
199
+    switch (config->modifier) {
200
+        case M_CONTROL:
201
+            ystr("ctrl");
202
+            break;
203
+        case M_SHIFT:
204
+            ystr("shift");
205
+            break;
206
+        case M_MOD1:
207
+            ystr("Mod1");
208
+            break;
209
+        case M_MOD2:
210
+            ystr("Mod2");
211
+            break;
212
+        case M_MOD3:
213
+            ystr("Mod3");
214
+            break;
215
+            /*
216
+               case M_MOD4:
217
+               ystr("Mod4");
218
+               break;
219
+               */
220
+        case M_MOD5:
221
+            ystr("Mod5");
222
+            break;
223
+        default:
224
+            ystr("Mod4");
225
+            break;
226
+    }
227
+
228
+    ystr("position");
229
+    if (config->position == P_BOTTOM)
230
+        ystr("bottom");
231
+    else ystr("top");
232
+
233
+    YSTR_IF_SET(status_command);
234
+    YSTR_IF_SET(font);
235
+
236
+    ystr("workspace_buttons");
237
+    y(bool, !config->hide_workspace_buttons);
238
+
239
+    ystr("binding_mode_indicator");
240
+    y(bool, !config->hide_binding_mode_indicator);
241
+
242
+    ystr("verbose");
243
+    y(bool, config->verbose);
244
+
245
+#undef YSTR_IF_SET
246
+#define YSTR_IF_SET(name) \
247
+    do { \
248
+        if (config->colors.name) { \
249
+            ystr( # name); \
250
+            ystr(config->colors.name); \
251
+        } \
252
+    } while (0)
253
+
254
+    ystr("colors");
255
+    y(map_open);
256
+    YSTR_IF_SET(background);
257
+    YSTR_IF_SET(statusline);
258
+    YSTR_IF_SET(separator);
259
+    YSTR_IF_SET(focused_workspace_border);
260
+    YSTR_IF_SET(focused_workspace_bg);
261
+    YSTR_IF_SET(focused_workspace_text);
262
+    YSTR_IF_SET(active_workspace_border);
263
+    YSTR_IF_SET(active_workspace_bg);
264
+    YSTR_IF_SET(active_workspace_text);
265
+    YSTR_IF_SET(inactive_workspace_border);
266
+    YSTR_IF_SET(inactive_workspace_bg);
267
+    YSTR_IF_SET(inactive_workspace_text);
268
+    YSTR_IF_SET(urgent_workspace_border);
269
+    YSTR_IF_SET(urgent_workspace_bg);
270
+    YSTR_IF_SET(urgent_workspace_text);
271
+    y(map_close);
272
+
273
+    y(map_close);
274
+#undef YSTR_IF_SET
275
+}
276
+
277
 IPC_HANDLER(tree) {
278
     setlocale(LC_NUMERIC, "C");
279
     yajl_gen gen = ygenalloc();
280
@@ -651,141 +780,19 @@ IPC_HANDLER(get_bar_config) {
281
         break;
282
     }
283
 
284
-    y(map_open);
285
-
286
     if (!config) {
287
         /* If we did not find a config for the given ID, the reply will contain
288
          * a null 'id' field. */
289
+        y(map_open);
290
+
291
         ystr("id");
292
         y(null);
293
-    } else {
294
-        ystr("id");
295
-        ystr(config->id);
296
-
297
-        if (config->num_outputs > 0) {
298
-            ystr("outputs");
299
-            y(array_open);
300
-            for (int c = 0; c < config->num_outputs; c++)
301
-                ystr(config->outputs[c]);
302
-            y(array_close);
303
-        }
304
-
305
-#define YSTR_IF_SET(name) \
306
-        do { \
307
-            if (config->name) { \
308
-                ystr( # name); \
309
-                ystr(config->name); \
310
-            } \
311
-        } while (0)
312
-
313
-        YSTR_IF_SET(tray_output);
314
-        YSTR_IF_SET(socket_path);
315
-
316
-        ystr("mode");
317
-        switch (config->mode) {
318
-            case M_HIDE:
319
-                ystr("hide");
320
-                break;
321
-            case M_INVISIBLE:
322
-                ystr("invisible");
323
-                break;
324
-            case M_DOCK:
325
-            default:
326
-                ystr("dock");
327
-                break;
328
-        }
329
-
330
-        ystr("hidden_state");
331
-        switch (config->hidden_state) {
332
-            case S_SHOW:
333
-                ystr("show");
334
-                break;
335
-            case S_HIDE:
336
-            default:
337
-                ystr("hide");
338
-                break;
339
-        }
340
-
341
-        ystr("modifier");
342
-        switch (config->modifier) {
343
-            case M_CONTROL:
344
-                ystr("ctrl");
345
-                break;
346
-            case M_SHIFT:
347
-                ystr("shift");
348
-                break;
349
-            case M_MOD1:
350
-                ystr("Mod1");
351
-                break;
352
-            case M_MOD2:
353
-                ystr("Mod2");
354
-                break;
355
-            case M_MOD3:
356
-                ystr("Mod3");
357
-                break;
358
-            /*
359
-            case M_MOD4:
360
-                ystr("Mod4");
361
-                break;
362
-            */
363
-            case M_MOD5:
364
-                ystr("Mod5");
365
-                break;
366
-            default:
367
-                ystr("Mod4");
368
-                break;
369
-        }
370
-
371
-        ystr("position");
372
-        if (config->position == P_BOTTOM)
373
-            ystr("bottom");
374
-        else ystr("top");
375
-
376
-        YSTR_IF_SET(status_command);
377
-        YSTR_IF_SET(font);
378
-
379
-        ystr("workspace_buttons");
380
-        y(bool, !config->hide_workspace_buttons);
381
-
382
-        ystr("binding_mode_indicator");
383
-        y(bool, !config->hide_binding_mode_indicator);
384
-
385
-        ystr("verbose");
386
-        y(bool, config->verbose);
387
 
388
-#undef YSTR_IF_SET
389
-#define YSTR_IF_SET(name) \
390
-        do { \
391
-            if (config->colors.name) { \
392
-                ystr( # name); \
393
-                ystr(config->colors.name); \
394
-            } \
395
-        } while (0)
396
-
397
-        ystr("colors");
398
-        y(map_open);
399
-        YSTR_IF_SET(background);
400
-        YSTR_IF_SET(statusline);
401
-        YSTR_IF_SET(separator);
402
-        YSTR_IF_SET(focused_workspace_border);
403
-        YSTR_IF_SET(focused_workspace_bg);
404
-        YSTR_IF_SET(focused_workspace_text);
405
-        YSTR_IF_SET(active_workspace_border);
406
-        YSTR_IF_SET(active_workspace_bg);
407
-        YSTR_IF_SET(active_workspace_text);
408
-        YSTR_IF_SET(inactive_workspace_border);
409
-        YSTR_IF_SET(inactive_workspace_bg);
410
-        YSTR_IF_SET(inactive_workspace_text);
411
-        YSTR_IF_SET(urgent_workspace_border);
412
-        YSTR_IF_SET(urgent_workspace_bg);
413
-        YSTR_IF_SET(urgent_workspace_text);
414
         y(map_close);
415
-
416
-#undef YSTR_IF_SET
417
+    } else {
418
+        dump_bar_config(gen, config);
419
     }
420
 
421
-    y(map_close);
422
-
423
     const unsigned char *payload;
424
     ylength length;
425
     y(get_buf, &payload, &length);
426
@@ -1090,3 +1097,22 @@ void ipc_send_window_event(const char *property, Con *con) {
427
     y(free);
428
     setlocale(LC_NUMERIC, "");
429
 }
430
+
431
+/**
432
+ * For the barconfig update events, we send the serialized barconfig.
433
+ */
434
+void ipc_send_barconfig_update_event(Barconfig *barconfig) {
435
+    DLOG("Issue barconfig_update event for id = %s\n", barconfig->id);
436
+    setlocale(LC_NUMERIC, "C");
437
+    yajl_gen gen = ygenalloc();
438
+
439
+    dump_bar_config(gen, barconfig);
440
+
441
+    const unsigned char *payload;
442
+    ylength length;
443
+    y(get_buf, &payload, &length);
444
+
445
+    ipc_send_event("barconfig_update", I3_IPC_EVENT_BARCONFIG_UPDATE, (const char *)payload);
446
+    y(free);
447
+    setlocale(LC_NUMERIC, "");
448
+}