diff --git a/RELEASE-NOTES-next b/RELEASE-NOTES-next index 3b6de2711..77e290cf9 100644 --- a/RELEASE-NOTES-next +++ b/RELEASE-NOTES-next @@ -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 │ diff --git a/docs/userguide b/docs/userguide index 3216ca1d9..cc5388af6 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1976,12 +1976,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 diff --git a/include/data.h b/include/data.h index 685d48d8f..ed0931cec 100644 --- a/include/data.h +++ b/include/data.h @@ -549,6 +549,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: * diff --git a/libi3/get_process_filename.c b/libi3/get_process_filename.c index 21429ec36..d29f8db1b 100644 --- a/libi3/get_process_filename.c +++ b/libi3/get_process_filename.c @@ -27,15 +27,14 @@ char *get_process_filename(const char *prefix) { char *tmp; sasprintf(&tmp, "%s/i3", dir); dir = tmp; - struct stat buf; - if (stat(dir, &buf) != 0) { - if (mkdir(dir, 0700) == -1) { - warn("Could not mkdir(%s)", dir); - errx(EXIT_FAILURE, "Check permissions of $XDG_RUNTIME_DIR = '%s'", - getenv("XDG_RUNTIME_DIR")); - perror("mkdir()"); - return NULL; - } + /* mkdirp() should prevent race between multiple i3 instances started + * in parallel from causing problem */ + if (mkdirp(dir, 0700) == -1) { + warn("Could not mkdirp(%s)", dir); + errx(EXIT_FAILURE, "Check permissions of $XDG_RUNTIME_DIR = '%s'", + getenv("XDG_RUNTIME_DIR")); + perror("mkdirp()"); + return NULL; } } else { /* If not, we create a (secure) temp directory using the template diff --git a/parser-specs/commands.spec b/parser-specs/commands.spec index ff3a7cc7b..d53945d4c 100644 --- a/parser-specs/commands.spec +++ b/parser-specs/commands.spec @@ -57,7 +57,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 diff --git a/parser-specs/config.spec b/parser-specs/config.spec index cae21556a..2bd3434ef 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -227,7 +227,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() diff --git a/src/match.c b/src/match.c index 65646f9e5..34314e256 100644 --- a/src/match.c +++ b/src/match.c @@ -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); } diff --git a/testcases/t/315-all-criterion.t b/testcases/t/315-all-criterion.t new file mode 100644 index 000000000..f11410fdb --- /dev/null +++ b/testcases/t/315-all-criterion.t @@ -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;