Allow multiple tray_output directives.
This patch introduces the possibility to specify the tray_output directive multiple times. All values will be used by i3bar, in the order they are given. This way, a single bar configuration can be used for several machines with internal output names "eDP1" and "LVDS-0" by specifying tray_output for both. Any external output (e.g., "DP-0") will still not receive the tray. The same effect can be achieved by using "primary", but forces the user to couple the tray display to the primary output which may not be desirable behavior. relates to #555
This commit is contained in:
@ -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;
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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 {
|
||||
|
Reference in New Issue
Block a user