Add "focus_wrapping" option

Fixes #2352.
This commit is contained in:
Vladimir Panteleev 2017-09-15 02:57:55 +00:00
parent 536f60e230
commit 28f7e14650
No known key found for this signature in database
GPG Key ID: 5004F0FAD051576D
9 changed files with 96 additions and 7 deletions

View File

@ -1039,12 +1039,28 @@ popup_during_fullscreen smart
=== Focus wrapping === Focus wrapping
When in a container with several windows or child containers, the opposite By default, when in a container with several windows or child containers, the
window will be focused when trying to move the focus over the edge of a opposite window will be focused when trying to move the focus over the edge of
container (and there are no other containers in that direction) -- the focus a container (and there are no other containers in that direction) -- the focus
wraps. If however there is another window or container in that direction, focus wraps.
will be set on that window or container. This is the default behavior so you
can navigate to all your windows without having to use +focus parent+. If desired, you can disable this behavior using the +focus_wrapping+
configuration directive:
*Syntax*:
---------------------
focus_wrapping yes|no
---------------------
*Example*:
-----------------
focus_wrapping no
-----------------
By default, focus wrapping does not occur if there is another window or
container in the specified direction, and focus will instead be set on that
window or container. This is the default behavior so you can navigate to all
your windows without having to use +focus parent+.
If you want the focus to *always* wrap and you are aware of using +focus If you want the focus to *always* wrap and you are aware of using +focus
parent+ to switch to different containers, you can use the parent+ to switch to different containers, you can use the

View File

@ -49,6 +49,7 @@ CFGFUN(workspace_layout, const char *layout);
CFGFUN(workspace_back_and_forth, const char *value); CFGFUN(workspace_back_and_forth, const char *value);
CFGFUN(focus_follows_mouse, const char *value); CFGFUN(focus_follows_mouse, const char *value);
CFGFUN(mouse_warping, const char *value); CFGFUN(mouse_warping, const char *value);
CFGFUN(focus_wrapping, const char *value);
CFGFUN(force_focus_wrapping, const char *value); CFGFUN(force_focus_wrapping, const char *value);
CFGFUN(force_xinerama, const char *value); CFGFUN(force_xinerama, const char *value);
CFGFUN(disable_randr15, const char *value); CFGFUN(disable_randr15, const char *value);

View File

@ -137,6 +137,14 @@ struct Config {
* comes with i3. Thus, you can turn it off entirely. */ * comes with i3. Thus, you can turn it off entirely. */
bool disable_workspace_bar; bool disable_workspace_bar;
/** When focus wrapping is enabled (the default), attempting to
* move focus past the edge of the screen (in other words, in a
* direction in which there are no more containers to focus) will
* cause the focus to wrap to the opposite edge of the current
* container. When it is disabled, nothing happens; the current
* focus is preserved. */
bool focus_wrapping;
/** Think of the following layout: Horizontal workspace with a tabbed /** Think of the following layout: Horizontal workspace with a tabbed
* con on the left of the screen and a terminal on the right of the * con on the left of the screen and a terminal on the right of the
* screen. You are in the second container in the tabbed container and * screen. You are in the second container in the tabbed container and

View File

@ -36,6 +36,7 @@ state INITIAL:
'no_focus' -> NO_FOCUS 'no_focus' -> NO_FOCUS
'focus_follows_mouse' -> FOCUS_FOLLOWS_MOUSE 'focus_follows_mouse' -> FOCUS_FOLLOWS_MOUSE
'mouse_warping' -> MOUSE_WARPING 'mouse_warping' -> MOUSE_WARPING
'focus_wrapping' -> FOCUS_WRAPPING
'force_focus_wrapping' -> FORCE_FOCUS_WRAPPING 'force_focus_wrapping' -> FORCE_FOCUS_WRAPPING
'force_xinerama', 'force-xinerama' -> FORCE_XINERAMA 'force_xinerama', 'force-xinerama' -> FORCE_XINERAMA
'disable_randr15', 'disable-randr15' -> DISABLE_RANDR15 'disable_randr15', 'disable-randr15' -> DISABLE_RANDR15
@ -203,6 +204,11 @@ state MOUSE_WARPING:
value = 'none', 'output' value = 'none', 'output'
-> call cfg_mouse_warping($value) -> call cfg_mouse_warping($value)
# focus_wrapping
state FOCUS_WRAPPING:
value = word
-> call cfg_focus_wrapping($value)
# force_focus_wrapping # force_focus_wrapping
state FORCE_FOCUS_WRAPPING: state FORCE_FOCUS_WRAPPING:
value = word value = word

View File

@ -227,6 +227,8 @@ 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;
config.focus_wrapping = true;
parse_configuration(override_configpath, true); parse_configuration(override_configpath, true);
if (reload) { if (reload) {

View File

@ -264,6 +264,10 @@ CFGFUN(disable_randr15, const char *value) {
config.disable_randr15 = eval_boolstr(value); config.disable_randr15 = eval_boolstr(value);
} }
CFGFUN(focus_wrapping, const char *value) {
config.focus_wrapping = eval_boolstr(value);
}
CFGFUN(force_focus_wrapping, const char *value) { CFGFUN(force_focus_wrapping, const char *value) {
config.force_focus_wrapping = eval_boolstr(value); config.force_focus_wrapping = eval_boolstr(value);
} }

View File

@ -675,7 +675,7 @@ static bool _tree_next(Con *con, char way, orientation_t orientation, bool wrap)
* *
*/ */
void tree_next(char way, orientation_t orientation) { void tree_next(char way, orientation_t orientation) {
_tree_next(focused, way, orientation, true); _tree_next(focused, way, orientation, config.focus_wrapping);
} }
/* /*

View File

@ -470,6 +470,7 @@ my $expected_all_tokens = "ERROR: CONFIG: Expected one of these tokens: <end>, '
no_focus no_focus
focus_follows_mouse focus_follows_mouse
mouse_warping mouse_warping
focus_wrapping
force_focus_wrapping force_focus_wrapping
force_xinerama force_xinerama
force-xinerama force-xinerama

View File

@ -0,0 +1,51 @@
#!perl
# vim:ts=4:sw=4:expandtab
#
# Please read the following documents before working on tests:
# • http://build.i3wm.org/docs/testsuite.html
# (or docs/testsuite)
#
# • http://build.i3wm.org/docs/lib-i3test.html
# (alternatively: perldoc ./testcases/lib/i3test.pm)
#
# • http://build.i3wm.org/docs/ipc.html
# (or docs/ipc)
#
# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
# (unless you are already familiar with Perl)
#
# Tests that focus does not wrap when focus_wrapping is disabled in
# the configuration.
# Ticket: #2352
# Bug still in: 4.14-72-g6411130c
use i3test i3_config => <<EOT;
# i3 config file (v4)
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
focus_wrapping no
EOT
sub test_orientation {
my ($orientation, $prev, $next) = @_;
my $tmp = fresh_workspace;
cmd "split $orientation";
my $win1 = open_window;
my $win2 = open_window;
is($x->input_focus, $win2->id, "Second window focused initially");
cmd "focus $prev";
is($x->input_focus, $win1->id, "First window focused");
cmd "focus $prev";
is($x->input_focus, $win1->id, "First window still focused");
cmd "focus $next";
is($x->input_focus, $win2->id, "Second window focused");
cmd "focus $next";
is($x->input_focus, $win2->id, "Second window still focused");
}
test_orientation('v', 'up', 'down');
test_orientation('h', 'left', 'right');
done_testing;