]> git.sur5r.net Git - i3/i3/commitdiff
Merge pull request #2001 from Airblader/feature-multiple-tray-output
authorMichael Stapelberg <stapelberg@users.noreply.github.com>
Mon, 2 Nov 2015 08:18:26 +0000 (09:18 +0100)
committerMichael Stapelberg <stapelberg@users.noreply.github.com>
Mon, 2 Nov 2015 08:18:26 +0000 (09:18 +0100)
Allow multiple tray_output directives.

docs/userguide
i3bar/include/config.h
i3bar/src/config.c
i3bar/src/xcb.c
include/config.h
src/config.c
src/config_directives.c
src/ipc.c
testcases/t/177-bar-config.t

index ca39757aca41de2ce6100e35a62baa7003d466fe..e596aeae08c82d71af985d1b35a5d3aaa7e8d764 100644 (file)
@@ -1369,6 +1369,11 @@ NetworkManager, VLC, Pidgin, etc. can place little icons.
 You can configure on which output (monitor) the icons should be displayed or
 you can turn off the functionality entirely.
 
+You can use mutliple +tray_output+ directives in your config to specify a list
+of outputs on which you want the tray to appear. The first available output in
+that list as defined by the order of the directives will be used for the tray
+output.
+
 *Syntax*:
 ---------------------------------
 tray_output none|primary|<output>
index 1ce5dfa6e4bebaaf930114d61081498a1f77ce55..2a059046298e6fdd9f56958f0c0059fb9ae3057f 100644 (file)
@@ -29,6 +29,12 @@ typedef struct binding_t {
     TAILQ_ENTRY(binding_t) bindings;
 } binding_t;
 
+typedef struct tray_output_t {
+    char *output;
+
+    TAILQ_ENTRY(tray_output_t) tray_outputs;
+} tray_output_t;
+
 typedef struct config_t {
     int modifier;
     TAILQ_HEAD(bindings_head, binding_t) bindings;
@@ -42,7 +48,7 @@ typedef struct config_t {
     char *command;
     char *fontname;
     i3String *separator_symbol;
-    char *tray_output;
+    TAILQ_HEAD(tray_outputs_head, tray_output_t) tray_outputs;
     int tray_padding;
     int num_outputs;
     char **outputs;
index 6476d15f44f6c34023612ff4de184a04e268ef3d..bc13f3d902f321f183a0c51ae66017a8869778cd 100644 (file)
@@ -21,6 +21,7 @@
 
 static char *cur_key;
 static bool parsing_bindings;
+static bool parsing_tray_outputs;
 
 /*
  * Parse a key.
@@ -32,14 +33,20 @@ static int config_map_key_cb(void *params_, const unsigned char *keyVal, size_t
     FREE(cur_key);
     sasprintf(&(cur_key), "%.*s", keyLen, keyVal);
 
-    if (strcmp(cur_key, "bindings") == 0)
+    if (strcmp(cur_key, "bindings") == 0) {
         parsing_bindings = true;
+    }
+
+    if (strcmp(cur_key, "tray_outputs") == 0) {
+        parsing_tray_outputs = true;
+    }
 
     return 1;
 }
 
 static int config_end_array_cb(void *params_) {
     parsing_bindings = false;
+    parsing_tray_outputs = false;
     return 1;
 }
 
@@ -90,6 +97,14 @@ static int config_string_cb(void *params_, const unsigned char *val, size_t _len
         return 0;
     }
 
+    if (parsing_tray_outputs) {
+        DLOG("Adding tray_output = %.*s to the list.\n", len, val);
+        tray_output_t *tray_output = scalloc(1, sizeof(tray_output_t));
+        sasprintf(&(tray_output->output), "%.*s", len, val);
+        TAILQ_INSERT_TAIL(&(config.tray_outputs), tray_output, tray_outputs);
+        return 1;
+    }
+
     if (!strcmp(cur_key, "mode")) {
         DLOG("mode = %.*s, len = %d\n", len, val, len);
         config.hide_on_modifier = (len == 4 && !strncmp((const char *)val, "dock", strlen("dock")) ? M_DOCK
@@ -195,10 +210,13 @@ static int config_string_cb(void *params_, const unsigned char *val, size_t _len
         return 1;
     }
 
+    /* We keep the old single tray_output working for users who only restart i3bar
+     * after updating. */
     if (!strcmp(cur_key, "tray_output")) {
-        DLOG("tray_output %.*s\n", len, val);
-        FREE(config.tray_output);
-        sasprintf(&config.tray_output, "%.*s", len, val);
+        DLOG("Found deprecated key tray_output %.*s.\n", len, val);
+        tray_output_t *tray_output = scalloc(1, sizeof(tray_output_t));
+        sasprintf(&(tray_output->output), "%.*s", len, val);
+        TAILQ_INSERT_TAIL(&(config.tray_outputs), tray_output, tray_outputs);
         return 1;
     }
 
@@ -317,6 +335,7 @@ void parse_config_json(char *json) {
     handle = yajl_alloc(&outputs_callbacks, NULL, NULL);
 
     TAILQ_INIT(&(config.bindings));
+    TAILQ_INIT(&(config.tray_outputs));
 
     state = yajl_parse(handle, (const unsigned char *)json, strlen(json));
 
index 20206c8bb556ec4a42d96b200e374a35d35c10a0..92b0d1abddc470af476d5139c84940a3bfa1a0be 100644 (file)
@@ -728,25 +728,50 @@ static void handle_client_message(xcb_client_message_event_t *event) {
             }
 
             DLOG("X window %08x requested docking\n", client);
-            i3_output *walk, *output = NULL;
-            SLIST_FOREACH(walk, outputs, slist) {
-                if (!walk->active)
-                    continue;
-                if (config.tray_output) {
-                    if ((strcasecmp(walk->name, config.tray_output) != 0) &&
-                        (!walk->primary || strcasecmp("primary", config.tray_output) != 0))
+            i3_output *output = NULL;
+            i3_output *walk = NULL;
+            tray_output_t *tray_output = NULL;
+            /* We need to iterate through the tray_output assignments first in
+             * order to prioritize them. Otherwise, if this bar manages two
+             * outputs and both are assigned as tray_output as well, the first
+             * output in our list would receive the tray rather than the first
+             * one defined via tray_output. */
+            TAILQ_FOREACH(tray_output, &(config.tray_outputs), tray_outputs) {
+                SLIST_FOREACH(walk, outputs, slist) {
+                    if (!walk->active)
                         continue;
+
+                    if (strcasecmp(walk->name, tray_output->output) == 0) {
+                        DLOG("Found tray_output assignment for output %s.\n", walk->name);
+                        output = walk;
+                        break;
+                    }
+
+                    if (walk->primary && strcasecmp("primary", tray_output->output) == 0) {
+                        DLOG("Found tray_output assignment on primary output %s.\n", walk->name);
+                        output = walk;
+                        break;
+                    }
                 }
 
-                DLOG("using output %s\n", walk->name);
-                output = walk;
-                break;
+                /* If we found an output, we're done. */
+                if (output != NULL)
+                    break;
+            }
+
+            /* Check whether any "tray_output primary" was defined for this bar. */
+            bool contains_primary = false;
+            TAILQ_FOREACH(tray_output, &(config.tray_outputs), tray_outputs) {
+                if (strcasecmp("primary", tray_output->output) == 0) {
+                    contains_primary = true;
+                    break;
+                }
             }
+
             /* In case of tray_output == primary and there is no primary output
-             * configured, we fall back to the first available output. */
-            if (output == NULL &&
-                config.tray_output &&
-                strcasecmp("primary", config.tray_output) == 0) {
+             * configured, we fall back to the first available output. We do the
+             * same if no tray_output was specified. */
+            if (output == NULL && (contains_primary || TAILQ_EMPTY(&(config.tray_outputs)))) {
                 SLIST_FOREACH(walk, outputs, slist) {
                     if (!walk->active)
                         continue;
@@ -1707,20 +1732,37 @@ void reconfig_windows(bool redraw_bars) {
                 exit(EXIT_FAILURE);
             }
 
-            const char *tray_output = (config.tray_output ? config.tray_output : SLIST_FIRST(outputs)->name);
-            if (!tray_configured && strcasecmp(tray_output, "none") != 0) {
-                /* Configuration sanity check: ensure this i3bar instance handles the output on
-                 * which the tray should appear (e.g. don’t initialize a tray if tray_output ==
-                 * VGA-1 but output == [HDMI-1]).
-                 */
-                i3_output *output;
-                SLIST_FOREACH(output, outputs, slist) {
-                    if (strcasecmp(output->name, tray_output) == 0 ||
-                        (strcasecmp(tray_output, "primary") == 0 && output->primary)) {
-                        init_tray();
-                        break;
+            /* Unless "tray_output none" was specified, we need to initialize the tray. */
+            const char *first = (TAILQ_EMPTY(&(config.tray_outputs))) ? SLIST_FIRST(outputs)->name : TAILQ_FIRST(&(config.tray_outputs))->output;
+            if (!tray_configured && strcasecmp(first, "none") != 0) {
+                /* We do a sanity check here to ensure that this i3bar instance actually handles
+                 * the output on which the tray should appear. For example,
+                 * consider tray_output == [VGA-1], but output == [HDMI-1]. */
+
+                /* If no tray_output was specified, we go ahead and initialize the tray as
+                 * we will be using the first available output. */
+                if (TAILQ_EMPTY(&(config.tray_outputs)))
+                    init_tray();
+
+                /* If one or more tray_output assignments were specified, we ensure that at least one of
+                 * them is actually an output managed by this instance. */
+                tray_output_t *tray_output;
+                TAILQ_FOREACH(tray_output, &(config.tray_outputs), tray_outputs) {
+                    i3_output *output;
+                    bool found = false;
+                    SLIST_FOREACH(output, outputs, slist) {
+                        if (strcasecmp(output->name, tray_output->output) == 0 ||
+                            (strcasecmp(tray_output->output, "primary") == 0 && output->primary)) {
+                            found = true;
+                            init_tray();
+                            break;
+                        }
                     }
+
+                    if (found)
+                        break;
                 }
+
                 tray_configured = true;
             }
         } else {
index 1c4ccce6905c68b8b6dd678b97e78b622b9648d1..5b98ce6ebf432e9dea04ab886d3a8329e912c406 100644 (file)
@@ -248,9 +248,10 @@ struct Barconfig {
      * simplicity (since we store just strings). */
     char **outputs;
 
-    /** Output on which the tray should be shown. The special value of 'no'
-     * disables the tray (it’s enabled by default). */
-    char *tray_output;
+    /* List of outputs on which the tray is allowed to be shown, in order.
+     * The special value "none" disables it (per default, it will be shown) and
+     * the special value "primary" enabled it on the primary output. */
+    TAILQ_HEAD(tray_outputs_head, tray_output_t) tray_outputs;
 
     /* Padding around the tray icons. */
     int tray_padding;
@@ -366,6 +367,12 @@ struct Barbinding {
     TAILQ_ENTRY(Barbinding) bindings;
 };
 
+struct tray_output_t {
+    char *output;
+
+    TAILQ_ENTRY(tray_output_t) tray_outputs;
+};
+
 /**
  * Finds the configuration file to use (either the one specified by
  * override_configpath), the user’s one or the system default) and calls
index c1c31e30a358168ecca5b053c0c8a41f6648633d..f146b906a4c9e5a042128d0601f5864a8df481d3 100644 (file)
@@ -75,20 +75,20 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
         ungrab_all_keys(conn);
 
         struct Mode *mode;
-        Binding *bind;
         while (!SLIST_EMPTY(&modes)) {
             mode = SLIST_FIRST(&modes);
             FREE(mode->name);
 
             /* Clear the old binding list */
-            bindings = mode->bindings;
-            while (!TAILQ_EMPTY(bindings)) {
-                bind = TAILQ_FIRST(bindings);
-                TAILQ_REMOVE(bindings, bind, bindings);
+            while (!TAILQ_EMPTY(mode->bindings)) {
+                Binding *bind = TAILQ_FIRST(mode->bindings);
+                TAILQ_REMOVE(mode->bindings, bind, bindings);
                 binding_free(bind);
             }
-            FREE(bindings);
+            FREE(mode->bindings);
+
             SLIST_REMOVE(&modes, mode, Mode, modes);
+            FREE(mode);
         }
 
         struct Assignment *assign;
@@ -110,8 +110,22 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
             FREE(barconfig->id);
             for (int c = 0; c < barconfig->num_outputs; c++)
                 free(barconfig->outputs[c]);
+
+            while (!TAILQ_EMPTY(&(barconfig->bar_bindings))) {
+                struct Barbinding *binding = TAILQ_FIRST(&(barconfig->bar_bindings));
+                FREE(binding->command);
+                TAILQ_REMOVE(&(barconfig->bar_bindings), binding, bindings);
+                FREE(binding);
+            }
+
+            while (!TAILQ_EMPTY(&(barconfig->tray_outputs))) {
+                struct tray_output_t *tray_output = TAILQ_FIRST(&(barconfig->tray_outputs));
+                FREE(tray_output->output);
+                TAILQ_REMOVE(&(barconfig->tray_outputs), tray_output, tray_outputs);
+                FREE(tray_output);
+            }
+
             FREE(barconfig->outputs);
-            FREE(barconfig->tray_output);
             FREE(barconfig->socket_path);
             FREE(barconfig->status_command);
             FREE(barconfig->i3bar_command);
index fb6ae94cc7a031d5bb0dfbf39dd1f9d54596f335..419d663a9fb2ec53b00ef9ecc6b341509ccc94fa 100644 (file)
@@ -399,57 +399,57 @@ CFGFUN(no_focus) {
  * Bar configuration (i3bar)
  ******************************************************************************/
 
-static Barconfig current_bar;
+static Barconfig *current_bar;
 
 CFGFUN(bar_font, const char *font) {
-    FREE(current_bar.font);
-    current_bar.font = sstrdup(font);
+    FREE(current_bar->font);
+    current_bar->font = sstrdup(font);
 }
 
 CFGFUN(bar_separator_symbol, const char *separator) {
-    FREE(current_bar.separator_symbol);
-    current_bar.separator_symbol = sstrdup(separator);
+    FREE(current_bar->separator_symbol);
+    current_bar->separator_symbol = sstrdup(separator);
 }
 
 CFGFUN(bar_mode, const char *mode) {
-    current_bar.mode = (strcmp(mode, "dock") == 0 ? M_DOCK : (strcmp(mode, "hide") == 0 ? M_HIDE : M_INVISIBLE));
+    current_bar->mode = (strcmp(mode, "dock") == 0 ? M_DOCK : (strcmp(mode, "hide") == 0 ? M_HIDE : M_INVISIBLE));
 }
 
 CFGFUN(bar_hidden_state, const char *hidden_state) {
-    current_bar.hidden_state = (strcmp(hidden_state, "hide") == 0 ? S_HIDE : S_SHOW);
+    current_bar->hidden_state = (strcmp(hidden_state, "hide") == 0 ? S_HIDE : S_SHOW);
 }
 
 CFGFUN(bar_id, const char *bar_id) {
-    current_bar.id = sstrdup(bar_id);
+    current_bar->id = sstrdup(bar_id);
 }
 
 CFGFUN(bar_output, const char *output) {
-    int new_outputs = current_bar.num_outputs + 1;
-    current_bar.outputs = srealloc(current_bar.outputs, sizeof(char *) * new_outputs);
-    current_bar.outputs[current_bar.num_outputs] = sstrdup(output);
-    current_bar.num_outputs = new_outputs;
+    int new_outputs = current_bar->num_outputs + 1;
+    current_bar->outputs = srealloc(current_bar->outputs, sizeof(char *) * new_outputs);
+    current_bar->outputs[current_bar->num_outputs] = sstrdup(output);
+    current_bar->num_outputs = new_outputs;
 }
 
 CFGFUN(bar_verbose, const char *verbose) {
-    current_bar.verbose = eval_boolstr(verbose);
+    current_bar->verbose = eval_boolstr(verbose);
 }
 
 CFGFUN(bar_modifier, const char *modifier) {
     if (strcmp(modifier, "Mod1") == 0)
-        current_bar.modifier = M_MOD1;
+        current_bar->modifier = M_MOD1;
     else if (strcmp(modifier, "Mod2") == 0)
-        current_bar.modifier = M_MOD2;
+        current_bar->modifier = M_MOD2;
     else if (strcmp(modifier, "Mod3") == 0)
-        current_bar.modifier = M_MOD3;
+        current_bar->modifier = M_MOD3;
     else if (strcmp(modifier, "Mod4") == 0)
-        current_bar.modifier = M_MOD4;
+        current_bar->modifier = M_MOD4;
     else if (strcmp(modifier, "Mod5") == 0)
-        current_bar.modifier = M_MOD5;
+        current_bar->modifier = M_MOD5;
     else if (strcmp(modifier, "Control") == 0 ||
              strcmp(modifier, "Ctrl") == 0)
-        current_bar.modifier = M_CONTROL;
+        current_bar->modifier = M_CONTROL;
     else if (strcmp(modifier, "Shift") == 0)
-        current_bar.modifier = M_SHIFT;
+        current_bar->modifier = M_SHIFT;
 }
 
 static void bar_configure_binding(const char *button, const char *command) {
@@ -465,7 +465,7 @@ static void bar_configure_binding(const char *button, const char *command) {
     }
 
     struct Barbinding *current;
-    TAILQ_FOREACH(current, &(current_bar.bar_bindings), bindings) {
+    TAILQ_FOREACH(current, &(current_bar->bar_bindings), bindings) {
         if (current->input_code == input_code) {
             ELOG("command for button %s was already specified, ignoring.\n", button);
             return;
@@ -475,7 +475,7 @@ static void bar_configure_binding(const char *button, const char *command) {
     struct Barbinding *new_binding = scalloc(1, sizeof(struct Barbinding));
     new_binding->input_code = input_code;
     new_binding->command = sstrdup(command);
-    TAILQ_INSERT_TAIL(&(current_bar.bar_bindings), new_binding, bindings);
+    TAILQ_INSERT_TAIL(&(current_bar->bar_bindings), new_binding, bindings);
 }
 
 CFGFUN(bar_wheel_up_cmd, const char *command) {
@@ -493,29 +493,29 @@ CFGFUN(bar_bindsym, const char *button, const char *command) {
 }
 
 CFGFUN(bar_position, const char *position) {
-    current_bar.position = (strcmp(position, "top") == 0 ? P_TOP : P_BOTTOM);
+    current_bar->position = (strcmp(position, "top") == 0 ? P_TOP : P_BOTTOM);
 }
 
 CFGFUN(bar_i3bar_command, const char *i3bar_command) {
-    FREE(current_bar.i3bar_command);
-    current_bar.i3bar_command = sstrdup(i3bar_command);
+    FREE(current_bar->i3bar_command);
+    current_bar->i3bar_command = sstrdup(i3bar_command);
 }
 
 CFGFUN(bar_color, const char *colorclass, const char *border, const char *background, const char *text) {
-#define APPLY_COLORS(classname)                                          \
-    do {                                                                 \
-        if (strcmp(colorclass, #classname) == 0) {                       \
-            if (text != NULL) {                                          \
-                /* New syntax: border, background, text */               \
-                current_bar.colors.classname##_border = sstrdup(border); \
-                current_bar.colors.classname##_bg = sstrdup(background); \
-                current_bar.colors.classname##_text = sstrdup(text);     \
-            } else {                                                     \
-                /* Old syntax: text, background */                       \
-                current_bar.colors.classname##_bg = sstrdup(background); \
-                current_bar.colors.classname##_text = sstrdup(border);   \
-            }                                                            \
-        }                                                                \
+#define APPLY_COLORS(classname)                                           \
+    do {                                                                  \
+        if (strcmp(colorclass, #classname) == 0) {                        \
+            if (text != NULL) {                                           \
+                /* New syntax: border, background, text */                \
+                current_bar->colors.classname##_border = sstrdup(border); \
+                current_bar->colors.classname##_bg = sstrdup(background); \
+                current_bar->colors.classname##_text = sstrdup(text);     \
+            } else {                                                      \
+                /* Old syntax: text, background */                        \
+                current_bar->colors.classname##_bg = sstrdup(background); \
+                current_bar->colors.classname##_text = sstrdup(border);   \
+            }                                                             \
+        }                                                                 \
     } while (0)
 
     APPLY_COLORS(focused_workspace);
@@ -528,73 +528,72 @@ CFGFUN(bar_color, const char *colorclass, const char *border, const char *backgr
 }
 
 CFGFUN(bar_socket_path, const char *socket_path) {
-    FREE(current_bar.socket_path);
-    current_bar.socket_path = sstrdup(socket_path);
+    FREE(current_bar->socket_path);
+    current_bar->socket_path = sstrdup(socket_path);
 }
 
 CFGFUN(bar_tray_output, const char *output) {
-    FREE(current_bar.tray_output);
-    current_bar.tray_output = sstrdup(output);
+    struct tray_output_t *tray_output = scalloc(1, sizeof(struct tray_output_t));
+    tray_output->output = sstrdup(output);
+    TAILQ_INSERT_TAIL(&(current_bar->tray_outputs), tray_output, tray_outputs);
 }
 
 CFGFUN(bar_tray_padding, const long padding_px) {
-    current_bar.tray_padding = padding_px;
+    current_bar->tray_padding = padding_px;
 }
 
 CFGFUN(bar_color_single, const char *colorclass, const char *color) {
     if (strcmp(colorclass, "background") == 0)
-        current_bar.colors.background = sstrdup(color);
+        current_bar->colors.background = sstrdup(color);
     else if (strcmp(colorclass, "separator") == 0)
-        current_bar.colors.separator = sstrdup(color);
+        current_bar->colors.separator = sstrdup(color);
     else if (strcmp(colorclass, "statusline") == 0)
-        current_bar.colors.statusline = sstrdup(color);
+        current_bar->colors.statusline = sstrdup(color);
     else if (strcmp(colorclass, "focused_background") == 0)
-        current_bar.colors.focused_background = sstrdup(color);
+        current_bar->colors.focused_background = sstrdup(color);
     else if (strcmp(colorclass, "focused_separator") == 0)
-        current_bar.colors.focused_separator = sstrdup(color);
+        current_bar->colors.focused_separator = sstrdup(color);
     else
-        current_bar.colors.focused_statusline = sstrdup(color);
+        current_bar->colors.focused_statusline = sstrdup(color);
 }
 
 CFGFUN(bar_status_command, const char *command) {
-    FREE(current_bar.status_command);
-    current_bar.status_command = sstrdup(command);
+    FREE(current_bar->status_command);
+    current_bar->status_command = sstrdup(command);
 }
 
 CFGFUN(bar_binding_mode_indicator, const char *value) {
-    current_bar.hide_binding_mode_indicator = !eval_boolstr(value);
+    current_bar->hide_binding_mode_indicator = !eval_boolstr(value);
 }
 
 CFGFUN(bar_workspace_buttons, const char *value) {
-    current_bar.hide_workspace_buttons = !eval_boolstr(value);
+    current_bar->hide_workspace_buttons = !eval_boolstr(value);
 }
 
 CFGFUN(bar_strip_workspace_numbers, const char *value) {
-    current_bar.strip_workspace_numbers = eval_boolstr(value);
+    current_bar->strip_workspace_numbers = eval_boolstr(value);
 }
 
 CFGFUN(bar_start) {
-    TAILQ_INIT(&(current_bar.bar_bindings));
-    current_bar.tray_padding = 2;
+    current_bar = scalloc(1, sizeof(struct Barconfig));
+    TAILQ_INIT(&(current_bar->bar_bindings));
+    TAILQ_INIT(&(current_bar->tray_outputs));
+    current_bar->tray_padding = 2;
 }
 
 CFGFUN(bar_finish) {
     DLOG("\t new bar configuration finished, saving.\n");
     /* Generate a unique ID for this bar if not already configured */
-    if (!current_bar.id)
-        sasprintf(&current_bar.id, "bar-%d", config.number_barconfigs);
+    if (current_bar->id == NULL)
+        sasprintf(&current_bar->id, "bar-%d", config.number_barconfigs);
 
     config.number_barconfigs++;
 
     /* If no font was explicitly set, we use the i3 font as default */
-    if (!current_bar.font && font_pattern)
-        current_bar.font = sstrdup(font_pattern);
+    if (current_bar->font == NULL && font_pattern != NULL)
+        current_bar->font = sstrdup(font_pattern);
 
-    /* Copy the current (static) structure into a dynamically allocated
-     * one, then cleanup our static one. */
-    Barconfig *bar_config = scalloc(1, sizeof(Barconfig));
-    memcpy(bar_config, &current_bar, sizeof(Barconfig));
-    TAILQ_INSERT_TAIL(&barconfigs, bar_config, configs);
-
-    memset(&current_bar, '\0', sizeof(Barconfig));
+    TAILQ_INSERT_TAIL(&barconfigs, current_bar, configs);
+    /* Simply reset the pointer, but don't free the resources. */
+    current_bar = NULL;
 }
index 8e448c7ce22f379a00121d12474ef88e894b7ea0..276a737a390245ec34040c6e309aef73b59468a2 100644 (file)
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -551,6 +551,18 @@ static void dump_bar_config(yajl_gen gen, Barconfig *config) {
         y(array_close);
     }
 
+    if (!TAILQ_EMPTY(&(config->tray_outputs))) {
+        ystr("tray_outputs");
+        y(array_open);
+
+        struct tray_output_t *tray_output;
+        TAILQ_FOREACH(tray_output, &(config->tray_outputs), tray_outputs) {
+            ystr(tray_output->output);
+        }
+
+        y(array_close);
+    }
+
 #define YSTR_IF_SET(name)       \
     do {                        \
         if (config->name) {     \
@@ -559,8 +571,6 @@ static void dump_bar_config(yajl_gen gen, Barconfig *config) {
         }                       \
     } while (0)
 
-    YSTR_IF_SET(tray_output);
-
     ystr("tray_padding");
     y(integer, config->tray_padding);
 
index 8ef94e57f15b800faf0024e61baba21ffc50fbe0..956b0caa9c0479b6309d88de16adbca6c32e6bd7 100644 (file)
@@ -138,7 +138,7 @@ ok(!$bar_config->{binding_mode_indicator}, 'mode indicator disabled');
 is($bar_config->{mode}, 'dock', 'dock mode');
 is($bar_config->{position}, 'top', 'position top');
 is_deeply($bar_config->{outputs}, [ 'HDMI1', 'HDMI2' ], 'outputs ok');
-is($bar_config->{tray_output}, 'HDMI2', 'tray_output ok');
+is_deeply($bar_config->{tray_outputs}, [ 'LVDS1', 'HDMI2' ], 'tray_output ok');
 is($bar_config->{tray_padding}, 0, 'tray_padding ok');
 is($bar_config->{font}, 'Terminus', 'font ok');
 is($bar_config->{socket_path}, '/tmp/foobar', 'socket_path ok');
@@ -294,7 +294,7 @@ ok($bar_config->{binding_mode_indicator}, 'mode indicator enabled');
 is($bar_config->{mode}, 'dock', 'dock mode');
 is($bar_config->{position}, 'top', 'position top');
 is_deeply($bar_config->{outputs}, [ 'HDMI1', 'HDMI2' ], 'outputs ok');
-is($bar_config->{tray_output}, 'HDMI2', 'tray_output ok');
+is_deeply($bar_config->{tray_outputs}, [ 'LVDS1', 'HDMI2' ], 'tray_output ok');
 is($bar_config->{font}, 'Terminus', 'font ok');
 is($bar_config->{socket_path}, '/tmp/foobar', 'socket_path ok');
 is_deeply($bar_config->{colors},