Merge pull request #1921 from tcatm/fix-no-randr-output

randr: use root window in case of no randr outputs
This commit is contained in:
Michael Stapelberg 2015-09-21 10:17:21 +02:00
commit 72b9909942
11 changed files with 66 additions and 167 deletions

View File

@ -1011,31 +1011,6 @@ force_display_urgency_hint <timeout> ms
force_display_urgency_hint 500 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 <timeout> ms
----------------------------------------
*Example*:
----------------------------------
delay_exit_on_zero_displays 500 ms
----------------------------------
=== Focus on window activation === Focus on window activation
[[focus_on_window_activation]] [[focus_on_window_activation]]

View File

@ -167,10 +167,6 @@ struct Config {
* flag can be delayed using an urgency timer. */ * flag can be delayed using an urgency timer. */
float workspace_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. */ /** Behavior when a window sends a NET_ACTIVE_WINDOW message. */
enum { enum {
/* Focus if the target workspace is visible, set urgency hint otherwise. */ /* Focus if the target workspace is visible, set urgency hint otherwise. */

View File

@ -51,7 +51,6 @@ CFGFUN(force_focus_wrapping, const char *value);
CFGFUN(force_xinerama, const char *value); CFGFUN(force_xinerama, const char *value);
CFGFUN(fake_outputs, const char *outputs); CFGFUN(fake_outputs, const char *outputs);
CFGFUN(force_display_urgency_hint, const long duration_ms); 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(focus_on_window_activation, const char *mode);
CFGFUN(show_marks, const char *value); CFGFUN(show_marks, const char *value);
CFGFUN(hide_edge_borders, const char *borders); CFGFUN(hide_edge_borders, const char *borders);

View File

@ -29,13 +29,6 @@ typedef enum {
*/ */
void randr_init(int *event_base); 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 * Initializes a CT_OUTPUT Con (searches existing ones from inplace restart
* before) to use for the given Output. * 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); 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);

View File

@ -39,7 +39,6 @@ state INITIAL:
'workspace_auto_back_and_forth' -> WORKSPACE_BACK_AND_FORTH 'workspace_auto_back_and_forth' -> WORKSPACE_BACK_AND_FORTH
'fake_outputs', 'fake-outputs' -> FAKE_OUTPUTS 'fake_outputs', 'fake-outputs' -> FAKE_OUTPUTS
'force_display_urgency_hint' -> FORCE_DISPLAY_URGENCY_HINT '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 'focus_on_window_activation' -> FOCUS_ON_WINDOW_ACTIVATION
'show_marks' -> SHOW_MARKS 'show_marks' -> SHOW_MARKS
'workspace' -> WORKSPACE 'workspace' -> WORKSPACE
@ -228,17 +227,6 @@ state FORCE_DISPLAY_URGENCY_HINT_MS:
end end
-> call cfg_force_display_urgency_hint(&duration_ms) -> call cfg_force_display_urgency_hint(&duration_ms)
# delay_exit_on_zero_displays <delay> 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 <smart|urgent|focus|none> # focus_on_window_activation <smart|urgent|focus|none>
state FOCUS_ON_WINDOW_ACTIVATION: state FOCUS_ON_WINDOW_ACTIVATION:
mode = word mode = word

View File

@ -206,10 +206,6 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
if (config.workspace_urgency_timer == 0) if (config.workspace_urgency_timer == 0)
config.workspace_urgency_timer = 0.5; 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); parse_configuration(override_configpath, true);
if (reload) { if (reload) {

View File

@ -367,10 +367,6 @@ CFGFUN(force_display_urgency_hint, const long duration_ms) {
config.workspace_urgency_timer = duration_ms / 1000.0; 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) { CFGFUN(focus_on_window_activation, const char *mode) {
if (strcmp(mode, "smart") == 0) if (strcmp(mode, "smart") == 0)
config.focus_on_window_activation = FOWA_SMART; config.focus_on_window_activation = FOWA_SMART;

View File

@ -655,8 +655,6 @@ int main(int argc, char *argv[]) {
ELOG("ERROR: No screen at (%d, %d), starting on the first screen\n", ELOG("ERROR: No screen at (%d, %d), starting on the first screen\n",
pointerreply->root_x, pointerreply->root_y); pointerreply->root_x, pointerreply->root_y);
output = get_first_output(); output = get_first_output();
if (!output)
die("No usable outputs available.\n");
} }
con_focus(con_descend_focused(output_get_content(output->con))); con_focus(con_descend_focused(output_get_content(output->con)));

View File

@ -27,7 +27,8 @@ xcb_randr_get_output_primary_reply_t *primary;
/* Stores all outputs available in your current session. */ /* Stores all outputs available in your current session. */
struct outputs_head outputs = TAILQ_HEAD_INITIALIZER(outputs); 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 * Get a specific output by its internal X11 id. Used by randr_query_outputs
@ -69,7 +70,22 @@ Output *get_first_output(void) {
if (output->active) if (output->active)
return output; return output;
return NULL; 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;
} }
/* /*
@ -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 * Creates an output covering the root window.
* X11 screen.
* *
*/ */
void disable_randr(xcb_connection_t *conn) { void create_root_output(xcb_connection_t *conn) {
DLOG("RandR extension unusable, disabling.\n"); 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; TAILQ_INSERT_TAIL(&outputs, root_output, outputs);
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;
} }
/* /*
@ -564,8 +575,6 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id,
if (!new->active) { if (!new->active) {
DLOG("width/height 0/0, disabling output\n"); DLOG("width/height 0/0, disabling output\n");
return; return;
} else {
new->to_be_disabled = false;
} }
DLOG("mode: %dx%d+%d+%d\n", new->rect.width, new->rect.height, DLOG("mode: %dx%d+%d+%d\n", new->rect.width, new->rect.height,
@ -587,7 +596,13 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id,
new->changed = true; new->changed = true;
} }
static bool __randr_query_outputs(void) { /*
* (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; Output *output, *other, *first;
xcb_randr_get_output_primary_cookie_t pcookie; xcb_randr_get_output_primary_cookie_t pcookie;
xcb_randr_get_screen_resources_current_cookie_t rcookie; xcb_randr_get_screen_resources_current_cookie_t rcookie;
@ -600,9 +615,6 @@ static bool __randr_query_outputs(void) {
/* an output is VGA-1, LVDS-1, etc. (usually physical video outputs) */ /* an output is VGA-1, LVDS-1, etc. (usually physical video outputs) */
xcb_randr_output_t *randr_outputs; xcb_randr_output_t *randr_outputs;
if (randr_disabled)
return true;
/* Get screen resources (primary output, crtcs, outputs, modes) */ /* Get screen resources (primary output, crtcs, outputs, modes) */
rcookie = xcb_randr_get_screen_resources_current(conn, root); rcookie = xcb_randr_get_screen_resources_current(conn, root);
pcookie = xcb_randr_get_output_primary(conn, root); pcookie = xcb_randr_get_output_primary(conn, root);
@ -611,10 +623,9 @@ static bool __randr_query_outputs(void) {
ELOG("Could not get RandR primary output\n"); ELOG("Could not get RandR primary output\n");
else else
DLOG("primary output is %08x\n", primary->output); DLOG("primary output is %08x\n", primary->output);
if ((res = xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL)) == NULL) { if ((res = xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL)) == NULL)
disable_randr(conn); return;
return true;
}
cts = res->config_timestamp; cts = res->config_timestamp;
int len = xcb_randr_get_screen_resources_current_outputs_length(res); int len = xcb_randr_get_screen_resources_current_outputs_length(res);
@ -636,6 +647,16 @@ static bool __randr_query_outputs(void) {
free(output); 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 /* Check for clones, disable the clones and reduce the mode to the
* lowest common mode */ * lowest common mode */
TAILQ_FOREACH(output, &outputs, outputs) { TAILQ_FOREACH(output, &outputs, outputs) {
@ -695,11 +716,6 @@ static bool __randr_query_outputs(void) {
DLOG("Output %s disabled, re-assigning workspaces/docks\n", output->name); DLOG("Output %s disabled, re-assigning workspaces/docks\n", output->name);
first = get_first_output(); first = get_first_output();
if (!first) {
FREE(res);
FREE(primary);
return false;
}
/* TODO: refactor the following code into a nice function. maybe /* TODO: refactor the following code into a nice function. maybe
* use an on_destroy callback which is implement differently for * use an on_destroy callback which is implement differently for
@ -782,11 +798,6 @@ static bool __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 */ /* Just go through each active output and assign one workspace */
TAILQ_FOREACH(output, &outputs, outputs) { TAILQ_FOREACH(output, &outputs, outputs) {
if (!output->active) if (!output->active)
@ -812,32 +823,6 @@ static bool __randr_query_outputs(void) {
FREE(res); FREE(res);
FREE(primary); 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");
}
}
} }
/* /*
@ -848,11 +833,12 @@ void randr_query_outputs(void) {
void randr_init(int *event_base) { void randr_init(int *event_base) {
const xcb_query_extension_reply_t *extreply; const xcb_query_extension_reply_t *extreply;
create_root_output(conn);
extreply = xcb_get_extension_data(conn, &xcb_randr_id); extreply = xcb_get_extension_data(conn, &xcb_randr_id);
if (!extreply->present) { if (!extreply->present)
disable_randr(conn);
return; return;
} else
randr_query_outputs(); randr_query_outputs();
if (event_base != NULL) if (event_base != NULL)

View File

@ -94,15 +94,15 @@ static void query_screens(xcb_connection_t *conn) {
*/ */
void xinerama_init(void) { void xinerama_init(void) {
if (!xcb_get_extension_data(conn, &xcb_xinerama_id)->present) { if (!xcb_get_extension_data(conn, &xcb_xinerama_id)->present) {
DLOG("Xinerama extension not found, disabling.\n"); DLOG("Xinerama extension not found, using root output.\n");
disable_randr(conn); create_root_output(conn);
} else { } else {
xcb_xinerama_is_active_reply_t *reply; xcb_xinerama_is_active_reply_t *reply;
reply = xcb_xinerama_is_active_reply(conn, xcb_xinerama_is_active(conn), NULL); reply = xcb_xinerama_is_active_reply(conn, xcb_xinerama_is_active(conn), NULL);
if (reply == NULL || !reply->state) { if (reply == NULL || !reply->state) {
DLOG("Xinerama is not active (in your X-Server), disabling.\n"); DLOG("Xinerama is not active (in your X-Server), using root output.\n");
disable_randr(conn); create_root_output(conn);
} else } else
query_screens(conn); query_screens(conn);

View File

@ -369,40 +369,6 @@ is(parser_calls($config),
$expected, $expected,
'force_display_urgency_hint ok'); '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 # workspace
################################################################################ ################################################################################
@ -475,7 +441,7 @@ client.focused #4c7899 #285577 #ffffff #2e9ef4
EOT EOT
my $expected_all_tokens = <<'EOT'; my $expected_all_tokens = <<'EOT';
ERROR: CONFIG: Expected one of these tokens: <end>, '#', '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: <end>, '#', '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 EOT
my $expected_end = <<'EOT'; my $expected_end = <<'EOT';