From bba18453af27ea00d0fedcbbd05f77d327d8bd89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Tue, 15 Dec 2015 07:38:56 -0500 Subject: [PATCH] Match on all criteria even if con_id or con_mark are given. Previously, if a match specification contained the con_id or con_mark criterion, all other criteria were ignored. However, a user may want to specify one of those two unique identifiers and still specify others as well, for example to match the currently focused window, but only if it has a certain WM_CLASS: [con_id=__focused__ class=special] kill We now check all specified criteria. fixes #2111 --- src/commands.c | 48 +++++++++++++---- src/match.c | 22 ++++++-- .../261-match-con_id-con_mark-combinations.t | 51 +++++++++++++++++++ 3 files changed, 107 insertions(+), 14 deletions(-) create mode 100644 testcases/t/261-match-con_id-con_mark-combinations.t diff --git a/src/commands.c b/src/commands.c index 78b1e993..d4b2d51c 100644 --- a/src/commands.c +++ b/src/commands.c @@ -294,33 +294,61 @@ void cmd_criteria_match_windows(I3_CMD) { next = TAILQ_NEXT(next, owindows); DLOG("checking if con %p / %s matches\n", current->con, current->con->name); + + /* We use this flag to prevent matching on window-less containers if + * only window-specific criteria were specified. */ + bool accept_match = false; + if (current_match->con_id != NULL) { + accept_match = true; + if (current_match->con_id == current->con) { - DLOG("matches container!\n"); - TAILQ_INSERT_TAIL(&owindows, current, owindows); + DLOG("con_id matched.\n"); } else { - DLOG("doesnt match\n"); - free(current); + DLOG("con_id does not match.\n"); + FREE(current); + continue; } - } else if (current_match->mark != NULL && !TAILQ_EMPTY(&(current->con->marks_head))) { + } + + if (current_match->mark != NULL && !TAILQ_EMPTY(&(current->con->marks_head))) { + accept_match = true; + bool matched_by_mark = false; + mark_t *mark; TAILQ_FOREACH(mark, &(current->con->marks_head), marks) { if (!regex_matches(current_match->mark, mark->name)) continue; DLOG("match by mark\n"); - TAILQ_INSERT_TAIL(&owindows, current, owindows); + matched_by_mark = true; break; } - } else { - if (current->con->window && match_matches_window(current_match, current->con->window)) { + + if (!matched_by_mark) { + DLOG("mark does not match.\n"); + FREE(current); + continue; + } + } + + if (current->con->window != NULL) { + if (match_matches_window(current_match, current->con->window)) { DLOG("matches window!\n"); - TAILQ_INSERT_TAIL(&owindows, current, owindows); + accept_match = true; } else { DLOG("doesnt match\n"); - free(current); + FREE(current); + continue; } } + + if (accept_match) { + TAILQ_INSERT_TAIL(&owindows, current, owindows); + } else { + FREE(current); + continue; + } } TAILQ_FOREACH(current, &owindows, owindows) { diff --git a/src/match.c b/src/match.c index caeb909f..a680ae70 100644 --- a/src/match.c +++ b/src/match.c @@ -223,11 +223,25 @@ bool match_matches_window(Match *match, i3Window *window) { } } - /* We don’t check the mark because this function is not even called when - * the mark would have matched - it is checked in cmdparse.y itself */ if (match->mark != NULL) { - LOG("mark does not match\n"); - return false; + if ((con = con_by_window_id(window->id)) == NULL) + return false; + + bool matched = false; + mark_t *mark; + TAILQ_FOREACH(mark, &(con->marks_head), marks) { + if (regex_matches(match->mark, mark->name)) { + matched = true; + break; + } + } + + if (matched) { + LOG("mark matches\n"); + } else { + LOG("mark does not match\n"); + return false; + } } return true; diff --git a/testcases/t/261-match-con_id-con_mark-combinations.t b/testcases/t/261-match-con_id-con_mark-combinations.t new file mode 100644 index 00000000..b255558e --- /dev/null +++ b/testcases/t/261-match-con_id-con_mark-combinations.t @@ -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) +# +# Ticket: #2111 +use i3test; + +my ($ws); + +############################################################################### +# Verify that con_id can be combined with other criteria +############################################################################### + +$ws = fresh_workspace; +open_window(wm_class => 'matchme'); + +cmd '[con_id=__focused__ class=doesnotmatch] kill'; +is(@{get_ws($ws)->{nodes}}, 1, 'window was not killed'); + +cmd '[con_id=__focused__ class=matchme] kill'; +is(@{get_ws($ws)->{nodes}}, 0, 'window was killed'); + +############################################################################### +# Verify that con_mark can be combined with other criteria +############################################################################### + +$ws = fresh_workspace; +open_window(wm_class => 'matchme'); +cmd 'mark marked'; + +cmd '[con_mark=marked class=doesnotmatch] kill'; +is(@{get_ws($ws)->{nodes}}, 1, 'window was not killed'); + +cmd '[con_mark=marked class=matchme] kill'; +is(@{get_ws($ws)->{nodes}}, 0, 'window was killed'); + +############################################################################### + +done_testing;