Merge pull request #1621 from Airblader/feature-1416
Added no_focus directive
This commit is contained in:
commit
d6f1e0c568
|
@ -589,6 +589,27 @@ for_window [title="x200: ~/work"] floating enable
|
||||||
|
|
||||||
The valid criteria are the same as those for commands, see <<command_criteria>>.
|
The valid criteria are the same as those for commands, see <<command_criteria>>.
|
||||||
|
|
||||||
|
=== Don't focus window upon opening
|
||||||
|
|
||||||
|
[[no_focus]]
|
||||||
|
|
||||||
|
When a new window appears, it will be focused. The +no_focus+ directive allows preventing
|
||||||
|
this from happening and can be used in combination with <<command_criteria>>.
|
||||||
|
|
||||||
|
Note that this does not apply to all cases, e.g., when feeding data into a running application
|
||||||
|
causing it to request being focused. To configure the behavior in such cases, refer to
|
||||||
|
<<focus_on_window_activation>>.
|
||||||
|
|
||||||
|
*Syntax*:
|
||||||
|
-------------------
|
||||||
|
no_focus <criteria>
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
*Example*:
|
||||||
|
-------------------------------
|
||||||
|
no_focus [window_role="pop-up"]
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
=== Variables
|
=== Variables
|
||||||
|
|
||||||
As you learned in the section about keyboard bindings, you will have
|
As you learned in the section about keyboard bindings, you will have
|
||||||
|
@ -983,11 +1004,13 @@ force_display_urgency_hint 500 ms
|
||||||
|
|
||||||
=== Focus on window activation
|
=== Focus on window activation
|
||||||
|
|
||||||
|
[[focus_on_window_activation]]
|
||||||
|
|
||||||
If a window is activated, e.g., via +google-chrome www.google.com+, it may request
|
If a window is activated, e.g., via +google-chrome www.google.com+, it may request
|
||||||
to take focus. Since this may not preferable, different reactions can be configured.
|
to take focus. Since this may not preferable, different reactions can be configured.
|
||||||
|
|
||||||
Note that this does not apply to any window that is opened, i.e., typically opening
|
Note that this may not affect windows that are being opened. To prevent new windows
|
||||||
an application will focus that window independent of this configuration.
|
from being focused, see <<no_focus>>.
|
||||||
|
|
||||||
*Syntax*:
|
*Syntax*:
|
||||||
----------------------------------------------------
|
----------------------------------------------------
|
||||||
|
|
|
@ -55,6 +55,7 @@ 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);
|
||||||
CFGFUN(assign, const char *workspace);
|
CFGFUN(assign, const char *workspace);
|
||||||
|
CFGFUN(no_focus);
|
||||||
CFGFUN(ipc_socket, const char *path);
|
CFGFUN(ipc_socket, const char *path);
|
||||||
CFGFUN(restart_state, const char *path);
|
CFGFUN(restart_state, const char *path);
|
||||||
CFGFUN(popup_during_fullscreen, const char *value);
|
CFGFUN(popup_during_fullscreen, const char *value);
|
||||||
|
|
|
@ -460,6 +460,7 @@ struct Assignment {
|
||||||
*
|
*
|
||||||
* A_COMMAND = run the specified command for the matching window
|
* A_COMMAND = run the specified command for the matching window
|
||||||
* A_TO_WORKSPACE = assign the matching window to the specified workspace
|
* A_TO_WORKSPACE = assign the matching window to the specified workspace
|
||||||
|
* A_NO_FOCUS = don't focus matched window when it is managed
|
||||||
*
|
*
|
||||||
* While the type is a bitmask, only one value can be set at a time. It is
|
* While the type is a bitmask, only one value can be set at a time. It is
|
||||||
* a bitmask to allow filtering for multiple types, for example in the
|
* a bitmask to allow filtering for multiple types, for example in the
|
||||||
|
@ -469,7 +470,8 @@ struct Assignment {
|
||||||
enum {
|
enum {
|
||||||
A_ANY = 0,
|
A_ANY = 0,
|
||||||
A_COMMAND = (1 << 0),
|
A_COMMAND = (1 << 0),
|
||||||
A_TO_WORKSPACE = (1 << 1)
|
A_TO_WORKSPACE = (1 << 1),
|
||||||
|
A_NO_FOCUS = (1 << 2)
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
/** the criteria to check if a window matches */
|
/** the criteria to check if a window matches */
|
||||||
|
|
|
@ -31,6 +31,7 @@ state INITIAL:
|
||||||
'hide_edge_borders' -> HIDE_EDGE_BORDERS
|
'hide_edge_borders' -> HIDE_EDGE_BORDERS
|
||||||
'for_window' -> FOR_WINDOW
|
'for_window' -> FOR_WINDOW
|
||||||
'assign' -> ASSIGN
|
'assign' -> ASSIGN
|
||||||
|
'no_focus' -> NO_FOCUS
|
||||||
'focus_follows_mouse' -> FOCUS_FOLLOWS_MOUSE
|
'focus_follows_mouse' -> FOCUS_FOLLOWS_MOUSE
|
||||||
'mouse_warping' -> MOUSE_WARPING
|
'mouse_warping' -> MOUSE_WARPING
|
||||||
'force_focus_wrapping' -> FORCE_FOCUS_WRAPPING
|
'force_focus_wrapping' -> FORCE_FOCUS_WRAPPING
|
||||||
|
@ -150,6 +151,15 @@ state ASSIGN_WORKSPACE:
|
||||||
workspace = string
|
workspace = string
|
||||||
-> call cfg_assign($workspace)
|
-> call cfg_assign($workspace)
|
||||||
|
|
||||||
|
# no_focus <criteria>
|
||||||
|
state NO_FOCUS:
|
||||||
|
'['
|
||||||
|
-> call cfg_criteria_init(NO_FOCUS_END); CRITERIA
|
||||||
|
|
||||||
|
state NO_FOCUS_END:
|
||||||
|
end
|
||||||
|
-> call cfg_no_focus()
|
||||||
|
|
||||||
# Criteria: Used by for_window and assign.
|
# Criteria: Used by for_window and assign.
|
||||||
state CRITERIA:
|
state CRITERIA:
|
||||||
ctype = 'class' -> CRITERION
|
ctype = 'class' -> CRITERION
|
||||||
|
|
|
@ -431,6 +431,19 @@ CFGFUN(assign, const char *workspace) {
|
||||||
TAILQ_INSERT_TAIL(&assignments, assignment, assignments);
|
TAILQ_INSERT_TAIL(&assignments, assignment, assignments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFGFUN(no_focus) {
|
||||||
|
if (match_is_empty(current_match)) {
|
||||||
|
ELOG("Match is empty, ignoring this assignment\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DLOG("new assignment, using above criteria, to ignore focus on manage");
|
||||||
|
Assignment *assignment = scalloc(sizeof(Assignment));
|
||||||
|
match_copy(&(assignment->match), current_match);
|
||||||
|
assignment->type = A_NO_FOCUS;
|
||||||
|
TAILQ_INSERT_TAIL(&assignments, assignment, assignments);
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Bar configuration (i3bar)
|
* Bar configuration (i3bar)
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
|
@ -512,9 +512,11 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
||||||
/* Defer setting focus after the 'new' event has been sent to ensure the
|
/* Defer setting focus after the 'new' event has been sent to ensure the
|
||||||
* proper window event sequence. */
|
* proper window event sequence. */
|
||||||
if (set_focus && !nc->window->doesnt_accept_focus && nc->mapped) {
|
if (set_focus && !nc->window->doesnt_accept_focus && nc->mapped) {
|
||||||
|
if (assignment_for(cwindow, A_NO_FOCUS) == NULL) {
|
||||||
DLOG("Now setting focus.\n");
|
DLOG("Now setting focus.\n");
|
||||||
con_focus(nc);
|
con_focus(nc);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tree_render();
|
tree_render();
|
||||||
|
|
||||||
|
|
|
@ -433,7 +433,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', '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'
|
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';
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
#!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)
|
||||||
|
#
|
||||||
|
# Test the 'no_focus' directive.
|
||||||
|
# Ticket: #1416
|
||||||
|
use i3test i3_autostart => 0;
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# 1: open a window and check that it takes focus
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
my $config = <<EOT;
|
||||||
|
# i3 config file (v4)
|
||||||
|
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||||
|
EOT
|
||||||
|
|
||||||
|
my $pid = launch_with_config($config);
|
||||||
|
|
||||||
|
my $ws = fresh_workspace;
|
||||||
|
my $first = open_window;
|
||||||
|
my $focused = get_focused($ws);
|
||||||
|
my $second = open_window;
|
||||||
|
|
||||||
|
isnt(get_focused($ws), $focused, 'focus has changed');
|
||||||
|
|
||||||
|
exit_gracefully($pid);
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# 2: open a window matched by a no_focus directive and check that
|
||||||
|
# it doesn't take focus
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
my $config = <<EOT;
|
||||||
|
# i3 config file (v4)
|
||||||
|
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||||
|
|
||||||
|
no_focus [instance=notme]
|
||||||
|
EOT
|
||||||
|
|
||||||
|
my $pid = launch_with_config($config);
|
||||||
|
|
||||||
|
my $ws = fresh_workspace;
|
||||||
|
my $first = open_window;
|
||||||
|
my $focused = get_focused($ws);
|
||||||
|
my $second = open_window(wm_class => 'notme');
|
||||||
|
|
||||||
|
is(get_focused($ws), $focused, 'focus has not changed');
|
||||||
|
|
||||||
|
exit_gracefully($pid);
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
done_testing;
|
Loading…
Reference in New Issue