Properly close disabled outputs restored during a restart. (#2337)
If an output is disabled during a restart, for example because a binding such as bindsym $mod+Shift+r exec "xrandr --auto", restart is used, it can happen that we first write the layout to disk and only then receive the RandR change events. This leads to a situation where the restored tree will contain these outputs, but the restarted i3 process will not receive the RandR events, thus the internal output in i3 is marked disabled. This patch finds these cases after a restart and force-disables the affected outputs. fixes #2326
This commit is contained in:
parent
a8757625c3
commit
dbafb3cf23
|
@ -60,6 +60,12 @@ void init_ws_for_output(Output *output, Con *content);
|
|||
*/
|
||||
void randr_query_outputs(void);
|
||||
|
||||
/**
|
||||
* Disables the output and moves its content.
|
||||
*
|
||||
*/
|
||||
void randr_disable_output(Output *output);
|
||||
|
||||
/**
|
||||
* Returns the first output which is active.
|
||||
*
|
||||
|
|
30
src/main.c
30
src/main.c
|
@ -623,7 +623,7 @@ int main(int argc, char *argv[]) {
|
|||
grab_all_keys(conn);
|
||||
|
||||
bool needs_tree_init = true;
|
||||
if (layout_path) {
|
||||
if (layout_path != NULL) {
|
||||
LOG("Trying to restore the layout from \"%s\".\n", layout_path);
|
||||
needs_tree_init = !tree_restore(layout_path, greply);
|
||||
if (delete_layout_path) {
|
||||
|
@ -633,7 +633,6 @@ int main(int argc, char *argv[]) {
|
|||
* sockets) left. */
|
||||
rmdir(dir);
|
||||
}
|
||||
free(layout_path);
|
||||
}
|
||||
if (needs_tree_init)
|
||||
tree_init(greply);
|
||||
|
@ -658,6 +657,33 @@ int main(int argc, char *argv[]) {
|
|||
randr_init(&randr_base);
|
||||
}
|
||||
|
||||
/* We need to force disabling outputs which have been loaded from the
|
||||
* layout file but are no longer active. This can happen if the output has
|
||||
* been disabled in the short time between writing the restart layout file
|
||||
* and restarting i3. See #2326. */
|
||||
if (layout_path != NULL && randr_base > -1) {
|
||||
Con *con;
|
||||
TAILQ_FOREACH(con, &(croot->nodes_head), nodes) {
|
||||
Output *output;
|
||||
TAILQ_FOREACH(output, &outputs, outputs) {
|
||||
if (output->active || strcmp(con->name, output->name) != 0)
|
||||
continue;
|
||||
|
||||
/* This will correctly correlate the output with its content
|
||||
* container. We need to make the connection to properly
|
||||
* disable the output. */
|
||||
if (output->con == NULL) {
|
||||
output_init_con(output);
|
||||
output->changed = false;
|
||||
}
|
||||
|
||||
output->to_be_disabled = true;
|
||||
randr_disable_output(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
FREE(layout_path);
|
||||
|
||||
scratchpad_fix_resolution();
|
||||
|
||||
xcb_query_pointer_reply_t *pointerreply;
|
||||
|
|
83
src/randr.c
83
src/randr.c
|
@ -622,7 +622,7 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id,
|
|||
*
|
||||
*/
|
||||
void randr_query_outputs(void) {
|
||||
Output *output, *other, *first;
|
||||
Output *output, *other;
|
||||
xcb_randr_get_output_primary_cookie_t pcookie;
|
||||
xcb_randr_get_screen_resources_current_cookie_t rcookie;
|
||||
|
||||
|
@ -733,10 +733,53 @@ void randr_query_outputs(void) {
|
|||
* because the user disabled them or because they are clones) */
|
||||
TAILQ_FOREACH(output, &outputs, outputs) {
|
||||
if (output->to_be_disabled) {
|
||||
randr_disable_output(output);
|
||||
}
|
||||
|
||||
if (output->changed) {
|
||||
output_change_mode(conn, output);
|
||||
output->changed = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Just go through each active output and assign one workspace */
|
||||
TAILQ_FOREACH(output, &outputs, outputs) {
|
||||
if (!output->active)
|
||||
continue;
|
||||
Con *content = output_get_content(output->con);
|
||||
if (!TAILQ_EMPTY(&(content->nodes_head)))
|
||||
continue;
|
||||
DLOG("Should add ws for output %s\n", output->name);
|
||||
init_ws_for_output(output, content);
|
||||
}
|
||||
|
||||
/* Focus the primary screen, if possible */
|
||||
TAILQ_FOREACH(output, &outputs, outputs) {
|
||||
if (!output->primary || !output->con)
|
||||
continue;
|
||||
|
||||
DLOG("Focusing primary output %s\n", output->name);
|
||||
con_focus(con_descend_focused(output->con));
|
||||
}
|
||||
|
||||
/* render_layout flushes */
|
||||
tree_render();
|
||||
|
||||
FREE(res);
|
||||
FREE(primary);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disables the output and moves its content.
|
||||
*
|
||||
*/
|
||||
void randr_disable_output(Output *output) {
|
||||
assert(output->to_be_disabled);
|
||||
|
||||
output->active = false;
|
||||
DLOG("Output %s disabled, re-assigning workspaces/docks\n", output->name);
|
||||
|
||||
first = get_first_output();
|
||||
Output *first = get_first_output();
|
||||
|
||||
/* TODO: refactor the following code into a nice function. maybe
|
||||
* use an on_destroy callback which is implement differently for
|
||||
|
@ -771,8 +814,9 @@ void randr_query_outputs(void) {
|
|||
con_attach(current, first_content, false);
|
||||
DLOG("Fixing the coordinates of floating containers\n");
|
||||
Con *floating_con;
|
||||
TAILQ_FOREACH(floating_con, &(current->floating_head), floating_windows)
|
||||
TAILQ_FOREACH(floating_con, &(current->floating_head), floating_windows) {
|
||||
floating_fix_coordinates(floating_con, &(output->con->rect), &(first->con->rect));
|
||||
}
|
||||
DLOG("Done, next\n");
|
||||
}
|
||||
DLOG("re-attached all workspaces\n");
|
||||
|
@ -813,39 +857,6 @@ void randr_query_outputs(void) {
|
|||
output->changed = false;
|
||||
}
|
||||
|
||||
if (output->changed) {
|
||||
output_change_mode(conn, output);
|
||||
output->changed = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Just go through each active output and assign one workspace */
|
||||
TAILQ_FOREACH(output, &outputs, outputs) {
|
||||
if (!output->active)
|
||||
continue;
|
||||
Con *content = output_get_content(output->con);
|
||||
if (!TAILQ_EMPTY(&(content->nodes_head)))
|
||||
continue;
|
||||
DLOG("Should add ws for output %s\n", output->name);
|
||||
init_ws_for_output(output, content);
|
||||
}
|
||||
|
||||
/* Focus the primary screen, if possible */
|
||||
TAILQ_FOREACH(output, &outputs, outputs) {
|
||||
if (!output->primary || !output->con)
|
||||
continue;
|
||||
|
||||
DLOG("Focusing primary output %s\n", output->name);
|
||||
con_focus(con_descend_focused(output->con));
|
||||
}
|
||||
|
||||
/* render_layout flushes */
|
||||
tree_render();
|
||||
|
||||
FREE(res);
|
||||
FREE(primary);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have just established a connection to the X server and need the initial
|
||||
* XRandR information to setup workspaces for each screen.
|
||||
|
|
Loading…
Reference in New Issue