From c87b256200f8281092fbacb09f83164c6ae148b2 Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Mon, 14 Sep 2015 22:34:05 +0200 Subject: [PATCH 1/2] Revert "Add a timeout: delay_exit_on_zero_displays" This reverts commit 2c77d7ceed298caf17a78b382e23af2e48377021. --- docs/userguide | 25 ------------------ include/config.h | 4 --- include/config_directives.h | 1 - parser-specs/config.spec | 12 --------- src/config.c | 4 --- src/config_directives.c | 4 --- src/main.c | 2 -- src/randr.c | 45 ++++++--------------------------- testcases/t/201-config-parser.t | 36 +------------------------- 9 files changed, 9 insertions(+), 124 deletions(-) diff --git a/docs/userguide b/docs/userguide index d1660c49..13dae4fe 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1011,31 +1011,6 @@ force_display_urgency_hint ms force_display_urgency_hint 500 ms --------------------------------- -=== Delaying exiting on zero displays - -Outputs may disappear momentarily and come back later. For example, -using a docking station that does not announce the undock (e.g. ACPI Undock -event triggered through manually pushing a button before actually ejecting -the notebook). During the removal of the notebook from the docking station, -all outputs disappear momentarily. - -To prevent i3 from exiting when no output is available momentarily, you can -tell i3 to delay a certain time first and check available outputs again using -the +delay_exit_on_zero_displays+ directive. Setting the value to 0 disables -this feature. - -The default is 500ms. - -*Syntax*: ----------------------------------------- -delay_exit_on_zero_displays ms ----------------------------------------- - -*Example*: ----------------------------------- -delay_exit_on_zero_displays 500 ms ----------------------------------- - === Focus on window activation [[focus_on_window_activation]] diff --git a/include/config.h b/include/config.h index ff360bb5..fd6fe6c0 100644 --- a/include/config.h +++ b/include/config.h @@ -167,10 +167,6 @@ struct Config { * flag can be delayed using an urgency timer. */ float workspace_urgency_timer; - /** Use a timer to delay exiting when no output is available. - * This can prevent i3 from exiting when all outputs disappear momentarily. */ - float zero_disp_exit_timer_ms; - /** Behavior when a window sends a NET_ACTIVE_WINDOW message. */ enum { /* Focus if the target workspace is visible, set urgency hint otherwise. */ diff --git a/include/config_directives.h b/include/config_directives.h index 72646651..c0c70bb4 100644 --- a/include/config_directives.h +++ b/include/config_directives.h @@ -51,7 +51,6 @@ CFGFUN(force_focus_wrapping, const char *value); CFGFUN(force_xinerama, const char *value); CFGFUN(fake_outputs, const char *outputs); CFGFUN(force_display_urgency_hint, const long duration_ms); -CFGFUN(delay_exit_on_zero_displays, const long duration_ms); CFGFUN(focus_on_window_activation, const char *mode); CFGFUN(show_marks, const char *value); CFGFUN(hide_edge_borders, const char *borders); diff --git a/parser-specs/config.spec b/parser-specs/config.spec index 1191157c..b9542c8c 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -39,7 +39,6 @@ state INITIAL: 'workspace_auto_back_and_forth' -> WORKSPACE_BACK_AND_FORTH 'fake_outputs', 'fake-outputs' -> FAKE_OUTPUTS 'force_display_urgency_hint' -> FORCE_DISPLAY_URGENCY_HINT - 'delay_exit_on_zero_displays' -> DELAY_EXIT_ON_ZERO_DISPLAYS 'focus_on_window_activation' -> FOCUS_ON_WINDOW_ACTIVATION 'show_marks' -> SHOW_MARKS 'workspace' -> WORKSPACE @@ -228,17 +227,6 @@ state FORCE_DISPLAY_URGENCY_HINT_MS: end -> call cfg_force_display_urgency_hint(&duration_ms) -# delay_exit_on_zero_displays ms -state DELAY_EXIT_ON_ZERO_DISPLAYS: - duration_ms = number - -> DELAY_EXIT_ON_ZERO_DISPLAYS_MS - -state DELAY_EXIT_ON_ZERO_DISPLAYS_MS: - 'ms' - -> - end - -> call cfg_delay_exit_on_zero_displays(&duration_ms) - # focus_on_window_activation state FOCUS_ON_WINDOW_ACTIVATION: mode = word diff --git a/src/config.c b/src/config.c index 0dc59365..d8db85e6 100644 --- a/src/config.c +++ b/src/config.c @@ -206,10 +206,6 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath, if (config.workspace_urgency_timer == 0) config.workspace_urgency_timer = 0.5; - /* Set default zero displays exit delay to 500ms */ - if (config.zero_disp_exit_timer_ms == 0) - config.zero_disp_exit_timer_ms = 500; - parse_configuration(override_configpath, true); if (reload) { diff --git a/src/config_directives.c b/src/config_directives.c index 463b38e7..d772387d 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -367,10 +367,6 @@ CFGFUN(force_display_urgency_hint, const long duration_ms) { config.workspace_urgency_timer = duration_ms / 1000.0; } -CFGFUN(delay_exit_on_zero_displays, const long duration_ms) { - config.zero_disp_exit_timer_ms = duration_ms; -} - CFGFUN(focus_on_window_activation, const char *mode) { if (strcmp(mode, "smart") == 0) config.focus_on_window_activation = FOWA_SMART; diff --git a/src/main.c b/src/main.c index b4ec3720..0dc25936 100644 --- a/src/main.c +++ b/src/main.c @@ -655,8 +655,6 @@ int main(int argc, char *argv[]) { ELOG("ERROR: No screen at (%d, %d), starting on the first screen\n", pointerreply->root_x, pointerreply->root_y); output = get_first_output(); - if (!output) - die("No usable outputs available.\n"); } con_focus(con_descend_focused(output_get_content(output->con))); diff --git a/src/randr.c b/src/randr.c index 7cf9d99e..69a866ab 100644 --- a/src/randr.c +++ b/src/randr.c @@ -69,7 +69,7 @@ Output *get_first_output(void) { if (output->active) return output; - return NULL; + die("No usable outputs available.\n"); } /* @@ -564,8 +564,6 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, if (!new->active) { DLOG("width/height 0/0, disabling output\n"); return; - } else { - new->to_be_disabled = false; } DLOG("mode: %dx%d+%d+%d\n", new->rect.width, new->rect.height, @@ -587,7 +585,11 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, new->changed = true; } -static bool __randr_query_outputs(void) { +/* + * (Re-)queries the outputs via RandR and stores them in the list of outputs. + * + */ +void randr_query_outputs(void) { Output *output, *other, *first; xcb_randr_get_output_primary_cookie_t pcookie; xcb_randr_get_screen_resources_current_cookie_t rcookie; @@ -601,7 +603,7 @@ static bool __randr_query_outputs(void) { xcb_randr_output_t *randr_outputs; if (randr_disabled) - return true; + return; /* Get screen resources (primary output, crtcs, outputs, modes) */ rcookie = xcb_randr_get_screen_resources_current(conn, root); @@ -613,7 +615,7 @@ static bool __randr_query_outputs(void) { DLOG("primary output is %08x\n", primary->output); if ((res = xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL)) == NULL) { disable_randr(conn); - return true; + return; } cts = res->config_timestamp; @@ -695,11 +697,6 @@ static bool __randr_query_outputs(void) { DLOG("Output %s disabled, re-assigning workspaces/docks\n", output->name); first = get_first_output(); - if (!first) { - FREE(res); - FREE(primary); - return false; - } /* TODO: refactor the following code into a nice function. maybe * use an on_destroy callback which is implement differently for @@ -812,32 +809,6 @@ static bool __randr_query_outputs(void) { FREE(res); FREE(primary); - - return true; -} - -/* - * (Re-)queries the outputs via RandR and stores them in the list of outputs. - * - */ -void randr_query_outputs(void) { - static bool first_query = true; - - if (first_query) { - /* find monitors at least once via RandR */ - if (!__randr_query_outputs()) - die("No usable outputs available.\n"); - first_query = false; - } else { - /* requery */ - if (!__randr_query_outputs()) { - DLOG("sleep %f ms due to zero displays\n", config.zero_disp_exit_timer_ms); - usleep(config.zero_disp_exit_timer_ms * 1000); - - if (!__randr_query_outputs()) - die("No usable outputs available.\n"); - } - } } /* diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t index fbcc586a..a2b0a3a9 100644 --- a/testcases/t/201-config-parser.t +++ b/testcases/t/201-config-parser.t @@ -369,40 +369,6 @@ is(parser_calls($config), $expected, 'force_display_urgency_hint ok'); -################################################################################ -# delay_exit_on_zero_displays -################################################################################ - -is(parser_calls('delay_exit_on_zero_displays 300'), - "cfg_delay_exit_on_zero_displays(300)\n", - 'delay_exit_on_zero_displays ok'); - -is(parser_calls('delay_exit_on_zero_displays 500 ms'), - "cfg_delay_exit_on_zero_displays(500)\n", - 'delay_exit_on_zero_displays ok'); - -is(parser_calls('delay_exit_on_zero_displays 700ms'), - "cfg_delay_exit_on_zero_displays(700)\n", - 'delay_exit_on_zero_displays ok'); - -$config = <<'EOT'; -delay_exit_on_zero_displays 300 -delay_exit_on_zero_displays 500 ms -delay_exit_on_zero_displays 700ms -delay_exit_on_zero_displays 700 -EOT - -$expected = <<'EOT'; -cfg_delay_exit_on_zero_displays(300) -cfg_delay_exit_on_zero_displays(500) -cfg_delay_exit_on_zero_displays(700) -cfg_delay_exit_on_zero_displays(700) -EOT - -is(parser_calls($config), - $expected, - 'delay_exit_on_zero_displays ok'); - ################################################################################ # workspace ################################################################################ @@ -475,7 +441,7 @@ client.focused #4c7899 #285577 #ffffff #2e9ef4 EOT my $expected_all_tokens = <<'EOT'; -ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'no_focus', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'delay_exit_on_zero_displays', 'focus_on_window_activation', 'show_marks', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder' +ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'no_focus', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'focus_on_window_activation', 'show_marks', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent', 'client.placeholder' EOT my $expected_end = <<'EOT'; From 78decb565a465e1b07ab89a3e6b077a5fe49cf58 Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Mon, 14 Sep 2015 22:12:47 +0200 Subject: [PATCH 2/2] randr: use root window in case of no randr outputs This patch introduces a root output covering the root window. It is used in two cases: 1. RandR is not available. In this case, the previous behaviour of creating a single output covering the root window is preserved. 2. RandR is available, but there is no active output. In this case, the root output is enabled and will be the only active output. If any RandR output becomes available, the root output will be disabled again. Existing mechanisms for migrating workspaces will just work without modification. I've carefully slipped in a global variable `Output root_output` representing that output. Fixes #926 and #1489 --- include/randr.h | 13 ++++---- src/randr.c | 81 +++++++++++++++++++++++++++++-------------------- src/xinerama.c | 8 ++--- 3 files changed, 58 insertions(+), 44 deletions(-) diff --git a/include/randr.h b/include/randr.h index 823ddea4..2c379f6f 100644 --- a/include/randr.h +++ b/include/randr.h @@ -29,13 +29,6 @@ typedef enum { */ void randr_init(int *event_base); -/** - * Disables RandR support by creating exactly one output with the size of the - * X11 screen. - * - */ -void disable_randr(xcb_connection_t *conn); - /** * Initializes a CT_OUTPUT Con (searches existing ones from inplace restart * before) to use for the given Output. @@ -120,3 +113,9 @@ Output *get_output_next(direction_t direction, Output *current, output_close_far * */ Output *get_output_next_wrap(direction_t direction, Output *current); + +/* + * Creates an output covering the root window. + * + */ +void create_root_output(xcb_connection_t *conn); diff --git a/src/randr.c b/src/randr.c index 69a866ab..23dd98d5 100644 --- a/src/randr.c +++ b/src/randr.c @@ -27,7 +27,8 @@ xcb_randr_get_output_primary_reply_t *primary; /* Stores all outputs available in your current session. */ struct outputs_head outputs = TAILQ_HEAD_INITIALIZER(outputs); -static bool randr_disabled = false; +/* This is the output covering the root window */ +static Output *root_output; /* * Get a specific output by its internal X11 id. Used by randr_query_outputs @@ -72,6 +73,21 @@ Output *get_first_output(void) { die("No usable outputs available.\n"); } +/* + * Check whether there are any active outputs (excluding the root output). + * + */ +static bool any_randr_output_active(void) { + Output *output; + + TAILQ_FOREACH(output, &outputs, outputs) { + if (output != root_output && !output->to_be_disabled && output->active) + return true; + } + + return false; +} + /* * Returns the active (!) output which contains the coordinates x, y or NULL * if there is no output which contains these coordinates. @@ -220,27 +236,22 @@ Output *get_output_next(direction_t direction, Output *current, output_close_far } /* - * Disables RandR support by creating exactly one output with the size of the - * X11 screen. + * Creates an output covering the root window. * */ -void disable_randr(xcb_connection_t *conn) { - DLOG("RandR extension unusable, disabling.\n"); +void create_root_output(xcb_connection_t *conn) { + root_output = scalloc(1, sizeof(Output)); - Output *s = scalloc(1, sizeof(Output)); + root_output->active = true; + root_output->rect.x = 0; + root_output->rect.y = 0; + root_output->rect.width = root_screen->width_in_pixels; + root_output->rect.height = root_screen->height_in_pixels; + root_output->name = "xroot-0"; + output_init_con(root_output); + init_ws_for_output(root_output, output_get_content(root_output->con)); - s->active = true; - s->rect.x = 0; - s->rect.y = 0; - s->rect.width = root_screen->width_in_pixels; - s->rect.height = root_screen->height_in_pixels; - s->name = "xroot-0"; - output_init_con(s); - init_ws_for_output(s, output_get_content(s->con)); - - TAILQ_INSERT_TAIL(&outputs, s, outputs); - - randr_disabled = true; + TAILQ_INSERT_TAIL(&outputs, root_output, outputs); } /* @@ -588,6 +599,8 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, /* * (Re-)queries the outputs via RandR and stores them in the list of outputs. * + * If no outputs are found use the root window. + * */ void randr_query_outputs(void) { Output *output, *other, *first; @@ -602,9 +615,6 @@ void randr_query_outputs(void) { /* an output is VGA-1, LVDS-1, etc. (usually physical video outputs) */ xcb_randr_output_t *randr_outputs; - if (randr_disabled) - return; - /* Get screen resources (primary output, crtcs, outputs, modes) */ rcookie = xcb_randr_get_screen_resources_current(conn, root); pcookie = xcb_randr_get_output_primary(conn, root); @@ -613,10 +623,9 @@ void randr_query_outputs(void) { ELOG("Could not get RandR primary output\n"); else DLOG("primary output is %08x\n", primary->output); - if ((res = xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL)) == NULL) { - disable_randr(conn); + if ((res = xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL)) == NULL) return; - } + cts = res->config_timestamp; int len = xcb_randr_get_screen_resources_current_outputs_length(res); @@ -638,6 +647,16 @@ void randr_query_outputs(void) { free(output); } + /* If there's no randr output, enable the output covering the root window. */ + if (any_randr_output_active()) { + DLOG("Active RandR output found. Disabling root output.\n"); + if (root_output->active) + root_output->to_be_disabled = true; + } else { + DLOG("No active RandR output found. Enabling root output.\n"); + root_output->active = true; + } + /* Check for clones, disable the clones and reduce the mode to the * lowest common mode */ TAILQ_FOREACH(output, &outputs, outputs) { @@ -779,11 +798,6 @@ void randr_query_outputs(void) { } } - if (TAILQ_EMPTY(&outputs)) { - ELOG("No outputs found via RandR, disabling\n"); - disable_randr(conn); - } - /* Just go through each active output and assign one workspace */ TAILQ_FOREACH(output, &outputs, outputs) { if (!output->active) @@ -819,12 +833,13 @@ void randr_query_outputs(void) { void randr_init(int *event_base) { const xcb_query_extension_reply_t *extreply; + create_root_output(conn); + extreply = xcb_get_extension_data(conn, &xcb_randr_id); - if (!extreply->present) { - disable_randr(conn); + if (!extreply->present) return; - } else - randr_query_outputs(); + + randr_query_outputs(); if (event_base != NULL) *event_base = extreply->first_event; diff --git a/src/xinerama.c b/src/xinerama.c index cae71fc2..049e1bc4 100644 --- a/src/xinerama.c +++ b/src/xinerama.c @@ -94,15 +94,15 @@ static void query_screens(xcb_connection_t *conn) { */ void xinerama_init(void) { if (!xcb_get_extension_data(conn, &xcb_xinerama_id)->present) { - DLOG("Xinerama extension not found, disabling.\n"); - disable_randr(conn); + DLOG("Xinerama extension not found, using root output.\n"); + create_root_output(conn); } else { xcb_xinerama_is_active_reply_t *reply; reply = xcb_xinerama_is_active_reply(conn, xcb_xinerama_is_active(conn), NULL); if (reply == NULL || !reply->state) { - DLOG("Xinerama is not active (in your X-Server), disabling.\n"); - disable_randr(conn); + DLOG("Xinerama is not active (in your X-Server), using root output.\n"); + create_root_output(conn); } else query_screens(conn);