Merge pull request #1871 from Airblader/feature-1770

Introduce command criterion value __focused__
This commit is contained in:
Michael Stapelberg 2015-08-30 21:55:37 +02:00
commit 768fe4ca69
3 changed files with 158 additions and 17 deletions

View File

@ -1604,25 +1604,35 @@ for_window [class="^evil-app$"] floating enable, move container to workspace 4
The criteria which are currently implemented are:
class::
Compares the window class (the second part of WM_CLASS)
Compares the window class (the second part of WM_CLASS). Use the
special value +__focused__+ to match all windows having the same window
class as the currently focused window.
instance::
Compares the window instance (the first part of WM_CLASS)
Compares the window instance (the first part of WM_CLASS). Use the
special value +__focused__+ to match all windows having the same window
instance as the currently focused window.
window_role::
Compares the window role (WM_WINDOW_ROLE).
Compares the window role (WM_WINDOW_ROLE). Use the special value
+__focused__+ to match all windows having the same window role as the
currently focused window.
window_type::
Compare the window type (_NET_WM_WINDOW_TYPE). Possible values are
+normal+, +dialog+, +utility+, +toolbar+, +splash+, +menu+, +dropdown_menu+,
+popup_menu+ and +toolti+.
Compare the window type (_NET_WM_WINDOW_TYPE). Possible values are
+normal+, +dialog+, +utility+, +toolbar+, +splash+, +menu+, +dropdown_menu+,
+popup_menu+ and +tooltip+.
id::
Compares the X11 window ID, which you can get via +xwininfo+ for example.
title::
Compares the X11 window title (_NET_WM_NAME or WM_NAME as fallback).
Use the special value +__focused__+ to match all windows having the
same window title as the currently focused window.
urgent::
Compares the urgent state of the window. Can be "latest" or "oldest".
Matches the latest or oldest urgent window, respectively.
(The following aliases are also available: newest, last, recent, first)
workspace::
Compares the workspace name of the workspace the window belongs to.
Compares the workspace name of the workspace the window belongs to. Use
the special value +__focused__+ to match all windows in the currently
focused workspace.
con_mark::
Compares the mark set for this container, see <<vim_like_marks>>.
con_id::

View File

@ -90,8 +90,12 @@ bool match_matches_window(Match *match, i3Window *window) {
LOG("Checking window 0x%08x (class %s)\n", window->id, window->class_class);
if (match->class != NULL) {
if (window->class_class != NULL &&
regex_matches(match->class, window->class_class)) {
if (window->class_class == NULL)
return false;
if (strcmp(match->class->pattern, "__focused__") == 0 &&
strcmp(window->class_class, focused->window->class_class) == 0) {
LOG("window class matches focused window\n");
} else if (regex_matches(match->class, window->class_class)) {
LOG("window class matches (%s)\n", window->class_class);
} else {
return false;
@ -99,8 +103,12 @@ bool match_matches_window(Match *match, i3Window *window) {
}
if (match->instance != NULL) {
if (window->class_instance != NULL &&
regex_matches(match->instance, window->class_instance)) {
if (window->class_instance == NULL)
return false;
if (strcmp(match->instance->pattern, "__focused__") == 0 &&
strcmp(window->class_instance, focused->window->class_instance) == 0) {
LOG("window instance matches focused window\n");
} else if (regex_matches(match->instance, window->class_instance)) {
LOG("window instance matches (%s)\n", window->class_instance);
} else {
return false;
@ -117,17 +125,27 @@ bool match_matches_window(Match *match, i3Window *window) {
}
if (match->title != NULL) {
if (window->name != NULL &&
regex_matches(match->title, i3string_as_utf8(window->name))) {
LOG("title matches (%s)\n", i3string_as_utf8(window->name));
if (window->name == NULL)
return false;
const char *title = i3string_as_utf8(window->name);
if (strcmp(match->title->pattern, "__focused__") == 0 &&
strcmp(title, i3string_as_utf8(focused->window->name)) == 0) {
LOG("window title matches focused window\n");
} else if (regex_matches(match->title, title)) {
LOG("title matches (%s)\n", title);
} else {
return false;
}
}
if (match->window_role != NULL) {
if (window->role != NULL &&
regex_matches(match->window_role, window->role)) {
if (window->role == NULL)
return false;
if (strcmp(match->window_role->pattern, "__focused__") == 0 &&
strcmp(window->role, focused->window->role) == 0) {
LOG("window role matches focused window\n");
} else if (regex_matches(match->window_role, window->role)) {
LOG("window_role matches (%s)\n", window->role);
} else {
return false;
@ -182,7 +200,10 @@ bool match_matches_window(Match *match, i3Window *window) {
if (ws == NULL)
return false;
if (regex_matches(match->workspace, ws->name)) {
if (strcmp(match->workspace->pattern, "__focused__") == 0 &&
strcmp(ws->name, con_get_workspace(focused)->name) == 0) {
LOG("workspace matches focused workspace\n");
} else if (regex_matches(match->workspace, ws->name)) {
LOG("workspace matches (%s)\n", ws->name);
} else {
return false;

View File

@ -0,0 +1,110 @@
#!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 for the special value "__focused__" in command criteria.
# Ticket: #1770
use i3test;
use X11::XCB qw(PROP_MODE_REPLACE);
my ($ws);
sub open_window_with_role {
my ($role) = @_;
open_window(
before_map => sub {
my ($window) = @_;
my $atomname = $x->atom(name => 'WM_WINDOW_ROLE');
my $atomtype = $x->atom(name => 'STRING');
$x->change_property(
PROP_MODE_REPLACE,
$window->id,
$atomname->id,
$atomtype->id,
8,
length($role) + 1,
"$role\x00"
);
}
);
}
###############################################################################
# 1: Test __focused__ for window class.
###############################################################################
$ws = fresh_workspace;
open_window(wm_class => 'notme');
open_window(wm_class => 'magic');
open_window(wm_class => 'magic');
is(@{get_ws($ws)->{nodes}}, 3, 'sanity check: workspace contains three windows');
cmd '[class=__focused__] move to workspace trash';
is(@{get_ws($ws)->{nodes}}, 1, '__focused__ works for window class');
###############################################################################
# 2: Test __focused__ for window instance.
###############################################################################
$ws = fresh_workspace;
open_window(instance => 'notme', wm_class => 'test');
open_window(instance => 'magic', wm_class => 'test');
open_window(instance => 'magic', wm_class => 'test');
is(@{get_ws($ws)->{nodes}}, 3, 'sanity check: workspace contains three windows');
cmd '[instance=__focused__] move to workspace trash';
is(@{get_ws($ws)->{nodes}}, 1, '__focused__ works for window instance');
###############################################################################
# 3: Test __focused__ for window title.
###############################################################################
$ws = fresh_workspace;
open_window(name => 'notme');
open_window(name => 'magic');
open_window(name => 'magic');
is(@{get_ws($ws)->{nodes}}, 3, 'sanity check: workspace contains three windows');
cmd '[title=__focused__] move to workspace trash';
is(@{get_ws($ws)->{nodes}}, 1, '__focused__ works for title');
###############################################################################
# 4: Test __focused__ for window role.
###############################################################################
$ws = fresh_workspace;
open_window_with_role("notme");
open_window_with_role("magic");
open_window_with_role("magic");
is(@{get_ws($ws)->{nodes}}, 3, 'sanity check: workspace contains three windows');
cmd '[window_role=__focused__] move to workspace trash';
is(@{get_ws($ws)->{nodes}}, 1, '__focused__ works for window_role');
###############################################################################
# 5: Test __focused__ for workspace.
###############################################################################
$ws = fresh_workspace;
open_window;
open_window;
is(@{get_ws($ws)->{nodes}}, 2, 'sanity check: workspace contains two windows');
cmd '[workspace=__focused__] move to workspace trash';
is(@{get_ws($ws)->{nodes}}, 0, '__focused__ works for workspace');
###############################################################################
done_testing;