Close & reopen tray selwin when needed
Fixes #1329 Fixes #3317 (duplicate) Examples where the tray "disappeared": - Start without a "tray_output", reload config with "tray_output none", remove "tray_output none" and reload. - Start with "tray_output primary" (or "tray_output <output>"), disable the primary output and then reconnect it. Fixes #2010 Cached in output_for_tray
This commit is contained in:
parent
ffc7ea8c50
commit
e240c118c7
173
i3bar/src/xcb.c
173
i3bar/src/xcb.c
|
@ -92,6 +92,9 @@ static mode binding;
|
|||
/* Indicates whether a new binding mode was recently activated */
|
||||
bool activated_mode = false;
|
||||
|
||||
/* The output in which the tray should be displayed. */
|
||||
static i3_output *output_for_tray;
|
||||
|
||||
/* The parsed colors */
|
||||
struct xcb_colors_t {
|
||||
color_t bar_fg;
|
||||
|
@ -758,58 +761,16 @@ static void handle_client_message(xcb_client_message_event_t *event) {
|
|||
}
|
||||
|
||||
DLOG("X window %08x requested docking\n", client);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we found an output, we're done. */
|
||||
if (output != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If no tray_output has been specified, we fall back to the first
|
||||
* available output. */
|
||||
if (output == NULL && TAILQ_EMPTY(&(config.tray_outputs))) {
|
||||
SLIST_FOREACH(walk, outputs, slist) {
|
||||
if (!walk->active)
|
||||
continue;
|
||||
DLOG("Falling back to output %s because no primary output is configured\n", walk->name);
|
||||
output = walk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (output == NULL) {
|
||||
ELOG("No output found\n");
|
||||
if (output_for_tray == NULL) {
|
||||
ELOG("No output found for tray\n");
|
||||
return;
|
||||
}
|
||||
|
||||
xcb_void_cookie_t rcookie = xcb_reparent_window(xcb_connection,
|
||||
client,
|
||||
output->bar.id,
|
||||
output->rect.w - icon_size - logical_px(config.tray_padding),
|
||||
output_for_tray->bar.id,
|
||||
output_for_tray->rect.w - icon_size - logical_px(config.tray_padding),
|
||||
logical_px(config.tray_padding));
|
||||
if (xcb_request_failed(rcookie, "Could not reparent window. Maybe it is using an incorrect depth/visual?"))
|
||||
return;
|
||||
|
@ -836,7 +797,7 @@ static void handle_client_message(xcb_client_message_event_t *event) {
|
|||
ev->format = 32;
|
||||
ev->data.data32[0] = XCB_CURRENT_TIME;
|
||||
ev->data.data32[1] = XEMBED_EMBEDDED_NOTIFY;
|
||||
ev->data.data32[2] = output->bar.id;
|
||||
ev->data.data32[2] = output_for_tray->bar.id;
|
||||
ev->data.data32[3] = xe_version;
|
||||
xcb_send_event(xcb_connection,
|
||||
0,
|
||||
|
@ -856,7 +817,7 @@ static void handle_client_message(xcb_client_message_event_t *event) {
|
|||
tc->win = client;
|
||||
tc->xe_version = xe_version;
|
||||
tc->mapped = false;
|
||||
TAILQ_INSERT_TAIL(output->trayclients, tc, tailq);
|
||||
TAILQ_INSERT_TAIL(output_for_tray->trayclients, tc, tailq);
|
||||
|
||||
if (map_it) {
|
||||
DLOG("Mapping dock client\n");
|
||||
|
@ -1609,6 +1570,56 @@ static xcb_void_cookie_t config_strut_partial(i3_output *output) {
|
|||
&strut_partial);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the output which should hold the tray, if one exists.
|
||||
*
|
||||
* An output is returned in these scenarios:
|
||||
* 1. A specific output was listed in tray_outputs which is also in the list
|
||||
* of outputs managed by this bar.
|
||||
* 2. No tray_output directive was specified. In this case, we use the first
|
||||
* available output.
|
||||
* 3. 'tray_output primary' was specified. In this case we use the primary
|
||||
* output.
|
||||
*
|
||||
* Three scenarios in which we specifically don't want to use a tray:
|
||||
* 1. 'tray_output none' was specified.
|
||||
* 2. A specific output was listed as a tray_output, but is not one of the
|
||||
* outputs managed by this bar. For example, consider tray_outputs == [VGA-1],
|
||||
* but outputs == [HDMI-1].
|
||||
* 3. 'tray_output primary' was specified and no output in the list is
|
||||
* primary.
|
||||
*/
|
||||
static i3_output *get_tray_output(void) {
|
||||
i3_output *output = NULL;
|
||||
if (TAILQ_EMPTY(&(config.tray_outputs))) {
|
||||
/* No tray_output specified, use first active output. */
|
||||
SLIST_FOREACH(output, outputs, slist) {
|
||||
if (output->active) {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
} else if (strcasecmp(TAILQ_FIRST(&(config.tray_outputs))->output, "none") == 0) {
|
||||
/* Check for "tray_output none" */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
SLIST_FOREACH(output, outputs, slist) {
|
||||
if (output->active &&
|
||||
(strcasecmp(output->name, tray_output->output) == 0 ||
|
||||
(strcasecmp(tray_output->output, "primary") == 0 && output->primary))) {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reconfigure all bars and create new bars for recently activated outputs
|
||||
*
|
||||
|
@ -1616,7 +1627,6 @@ static xcb_void_cookie_t config_strut_partial(i3_output *output) {
|
|||
void reconfig_windows(bool redraw_bars) {
|
||||
uint32_t mask;
|
||||
uint32_t values[6];
|
||||
static bool tray_configured = false;
|
||||
|
||||
i3_output *walk;
|
||||
SLIST_FOREACH(walk, outputs, slist) {
|
||||
|
@ -1744,58 +1754,6 @@ void reconfig_windows(bool redraw_bars) {
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Unless "tray_output none" was specified, we need to initialize the tray. */
|
||||
bool no_tray = false;
|
||||
if (!(TAILQ_EMPTY(&(config.tray_outputs)))) {
|
||||
no_tray = strcasecmp(TAILQ_FIRST(&(config.tray_outputs))->output, "none") == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are three scenarios in which we need to initialize the tray:
|
||||
* 1. A specific output was listed in tray_outputs which is also
|
||||
* in the list of outputs managed by this bar.
|
||||
* 2. No tray_output directive was specified. In this case, we
|
||||
* use the first available output.
|
||||
* 3. 'tray_output primary' was specified. In this case we use the
|
||||
* primary output.
|
||||
*
|
||||
* Three scenarios in which we specifically don't want to
|
||||
* initialize the tray are:
|
||||
* 1. 'tray_output none' was specified.
|
||||
* 2. A specific output was listed as a tray_output, but is not
|
||||
* one of the outputs managed by this bar. For example, consider
|
||||
* tray_outputs == [VGA-1], but outputs == [HDMI-1].
|
||||
* 3. 'tray_output primary' was specified and no output in the list
|
||||
* is primary.
|
||||
*/
|
||||
if (!tray_configured && !no_tray) {
|
||||
/* 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 {
|
||||
/* We already have a bar, so we just reconfigure it */
|
||||
mask = XCB_CONFIG_WINDOW_X |
|
||||
|
@ -1889,6 +1847,19 @@ void reconfig_windows(bool redraw_bars) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally, check if we want to initialize the tray or destroy the selection
|
||||
* window. The result of get_tray_output() is cached. */
|
||||
output_for_tray = get_tray_output();
|
||||
if (output_for_tray) {
|
||||
if (selwin == XCB_NONE) {
|
||||
init_tray();
|
||||
}
|
||||
} else if (selwin != XCB_NONE) {
|
||||
DLOG("Destroying tray selection window\n");
|
||||
xcb_destroy_window(xcb_connection, selwin);
|
||||
selwin = XCB_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue