Implement 'all' matching criterion

This criterion matches all open windows, as a more readable (and
correct) version of the 'class=".*"' criterion (more correct because
it'll also match windows which don't have WM_CLASS set yet).
This commit is contained in:
Isaac Garzon 2021-07-23 14:19:36 +03:00
parent abbf6a85d7
commit 3a818c0f20
7 changed files with 116 additions and 3 deletions

View File

@ -41,6 +41,7 @@ option is enabled and only then sets a screenshot as background.
• Add %machine placeholder (WM_CLIENT_MACHINE) to title_format
• Allow multiple output names in 'move container|workspace to output'
• Add 'move container|workspace to output next'
• Add 'all' window matching criterion
┌────────────────────────────┐
│ Bugfixes │

View File

@ -1959,12 +1959,17 @@ bindsym $mod+x [class="Firefox" window_role="About"] kill
# enable floating mode and move container to workspace 4
for_window [class="^evil-app$"] floating enable, move container to workspace 4
# enable window icons for all windows with extra horizontal padding of 1px
for_window [all] title_window_icon padding 1px
# move all floating windows to the scratchpad
bindsym $mod+x [floating] move scratchpad
------------------------------------
The criteria which are currently implemented are:
all::
Matches all windows. This criterion requires no value.
class::
Compares the window class (the second part of WM_CLASS). Use the
special value +\_\_focused__+ to match all windows having the same window

View File

@ -530,6 +530,7 @@ struct Match {
WM_FLOATING_USER,
WM_FLOATING } window_mode;
Con *con_id;
bool match_all_windows;
/* Where the window looking for a match should be inserted:
*

View File

@ -56,7 +56,7 @@ state CRITERIA:
ctype = 'urgent' -> CRITERION
ctype = 'workspace' -> CRITERION
ctype = 'machine' -> CRITERION
ctype = 'tiling', 'floating'
ctype = 'tiling', 'floating', 'all'
-> call cmd_criteria_add($ctype, NULL); CRITERIA
']' -> call cmd_criteria_match_windows(); INITIAL

View File

@ -200,7 +200,7 @@ state CRITERIA:
ctype = 'machine' -> CRITERION
ctype = 'floating_from' -> CRITERION_FROM
ctype = 'tiling_from' -> CRITERION_FROM
ctype = 'tiling', 'floating'
ctype = 'tiling', 'floating', 'all'
-> call cfg_criteria_add($ctype, NULL); CRITERIA
']'
-> call cfg_criteria_pop_state()

View File

@ -53,7 +53,8 @@ bool match_is_empty(Match *match) {
match->window_type == UINT32_MAX &&
match->con_id == NULL &&
match->dock == M_NODOCK &&
match->window_mode == WM_ANY);
match->window_mode == WM_ANY &&
match->match_all_windows == false);
}
/*
@ -260,6 +261,10 @@ bool match_matches_window(Match *match, i3Window *window) {
LOG("window_mode matches\n");
}
/* NOTE: See the comment regarding 'all' in match_parse_property()
* for an explanation of why match_all_windows isn't explicitly
* checked. */
return true;
}
@ -438,5 +443,16 @@ void match_parse_property(Match *match, const char *ctype, const char *cvalue) {
return;
}
/* match_matches_window() only checks negatively, so match_all_windows
* won't actually be used there, but that's OK because if no negative
* match is found (e.g. because of a more restrictive criterion) the
* return value of match_matches_window() is true.
* Setting it here only serves to cause match_is_empty() to return false,
* otherwise empty criteria rules apply, and that's not what we want. */
if (strcmp(ctype, "all") == 0) {
match->match_all_windows = true;
return;
}
ELOG("Unknown criterion: %s\n", ctype);
}

View File

@ -0,0 +1,90 @@
#!perl
# vim:ts=4:sw=4:expandtab
#
# Please read the following documents before working on tests:
# • https://build.i3wm.org/docs/testsuite.html
# (or docs/testsuite)
#
# • https://build.i3wm.org/docs/lib-i3test.html
# (alternatively: perldoc ./testcases/lib/i3test.pm)
#
# • https://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 all kinds of matching methods
#
use i3test;
my $tmp = fresh_workspace;
ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
# Open a new window
my $window = open_window;
my $content = get_ws_content($tmp);
ok(@{$content} == 1, 'window mapped');
my $win = $content->[0];
######################################################################
# check that simple matching works.
######################################################################
cmd '[all] kill';
sync_with_i3;
is_num_children($tmp, 0, 'window killed');
######################################################################
# check that simple matching against multiple windows works.
######################################################################
$tmp = fresh_workspace;
my $left = open_window;
ok($left->mapped, 'left window mapped');
my $right = open_window;
ok($right->mapped, 'right window mapped');
# two windows should be here
is_num_children($tmp, 2, 'two windows opened');
cmd '[all] kill';
sync_with_i3;
is_num_children($tmp, 0, 'two windows killed');
######################################################################
# check that multiple criteria work are checked with a logical AND,
# not a logical OR (that is, matching is not cancelled after the first
# criterion matches).
######################################################################
$tmp = fresh_workspace;
my $left = open_window(name => 'left');
ok($left->mapped, 'left window mapped');
my $right = open_window(name => 'right');
ok($right->mapped, 'right window mapped');
# two windows should be here
is_num_children($tmp, 2, 'two windows opened');
cmd '[all title="left"] kill';
sync_with_i3;
is_num_children($tmp, 1, 'one window still there');
cmd '[all] kill';
sync_with_i3;
is_num_children($tmp, 0, 'all windows killed');
done_testing;