Merge branch 'new-assign' into next

This commit is contained in:
Michael Stapelberg 2011-09-11 22:15:51 +01:00
commit 2ef54057e6
5 changed files with 156 additions and 25 deletions

View File

@ -431,7 +431,7 @@ change their border style, for example.
*Syntax*:
-----------------------------
for_window [criteria] command
for_window <criteria> command
-----------------------------
*Examples*:
@ -478,37 +478,59 @@ configuration file and run it before starting i3 (for example in your
[[assign_workspace]]
Specific windows can be matched by window class and/or window title. It is
recommended that you match on window classes instead of window titles whenever
possible because some applications first create their window, and then worry
about setting the correct title. Firefox with Vimperator comes to mind. The
window starts up being named Firefox, and only when Vimperator is loaded does
the title change. As i3 will get the title as soon as the application maps the
To automatically make a specific window show up on a specific workspace, you
can use an *assignment*. You can match windows by using any criteria,
see <<command_criteria>>. It is recommended that you match on window classes
(and instances, when appropriate) instead of window titles whenever possible
because some applications first create their window, and then worry about
setting the correct title. Firefox with Vimperator comes to mind. The window
starts up being named Firefox, and only when Vimperator is loaded does the
title change. As i3 will get the title as soon as the application maps the
window (mapping means actually displaying it on the screen), youd need to have
to match on 'Firefox' in this case.
You can prefix or suffix workspaces with a `~` to specify that matching clients
should be put into floating mode. If you specify only a `~`, the client will
not be put onto any workspace, but will be set floating on the current one.
*Syntax*:
------------------------------------------------------------
assign ["]window class[/window title]["] [→] [workspace]
assign <criteria> [→] workspace
------------------------------------------------------------
*Examples*:
----------------------
assign urxvt 2
assign urxvt → 2
assign urxvt → work
assign "urxvt" → 2
assign "urxvt/VIM" → 3
assign "gecko" → 4
# Assign URxvt terminals to workspace 2
assign [class="URxvt"] 2
# Same thing, but more precise (exact match instead of substring)
assign [class="^URxvt$"] 2
# Same thing, but with a beautiful arrow :)
assign [class="^URxvt$"] → 2
# Assignment to a named workspace
assign [class="^URxvt$"] → work
# Start urxvt -name irssi
assign [class="^URxvt$" instance="^irssi$"] → 3
----------------------
Note that the arrow is not required, it just looks good :-). If you decide to
use it, it has to be a UTF-8 encoded arrow, not `->` or something like that.
To get the class and instance, you can use +xprop+. After clicking on the
window, you will see the following output:
*xwininfo*:
-----------------------------------
WM_CLASS(STRING) = "irssi", "URxvt"
-----------------------------------
The first part of the WM_CLASS is the instance ("irssi" in this example), the
second part is the class ("URxvt" in this example).
Should you have any problems with assignments, make sure to check the i3
logfile first (see http://i3wm.org/docs/debugging.html). It includes more
details about the matching process and the windows actual class, instance and
title when starting up.
=== Automatically starting applications on i3 startup
By using the +exec+ keyword outside a keybinding, you can configure
@ -721,6 +743,9 @@ which have the class Firefox, use:
*Example*:
------------------------------------
bindsym mod+x [class="Firefox"] kill
# same thing, but case-insensitive
bindsym mod+x [class="(?i)firefox"] kill
------------------------------------
The criteria which are currently implemented are:

View File

@ -75,6 +75,14 @@ EOL (\r?\n)
<FOR_WINDOW_COND>"]" { yy_pop_state(); return ']'; }
<ASSIGN_COND>"[" {
/* this is the case for the new assign syntax
* that uses criteria */
yy_pop_state();
yy_push_state(FOR_WINDOW_COND);
/* afterwards we will be in ASSIGN_TARGET_COND */
return '[';
}
<EAT_WHITESPACE>[ \t]* { yy_pop_state(); }
<WANT_QSTRING>\"[^\"]+\" {
yy_pop_state();
@ -194,7 +202,7 @@ title { yy_push_state(WANT_QSTRING); return TOK_TITLE;
yylval.string = copy;
return QUOTEDSTRING;
}
<ASSIGN_COND>[^ \t\"]+ { BEGIN(ASSIGN_TARGET_COND); yylval.string = sstrdup(yytext); return STR_NG; }
<ASSIGN_COND>[^ \t\"\[]+ { BEGIN(ASSIGN_TARGET_COND); yylval.string = sstrdup(yytext); return STR_NG; }
<BINDSYM_COND>[a-zA-Z0-9_]+ { yylval.string = sstrdup(yytext); return WORD; }
[a-zA-Z]+ { yylval.string = sstrdup(yytext); return WORD; }
. { return (int)yytext[0]; }

View File

@ -240,6 +240,18 @@ static void nagbar_exited(EV_P_ ev_child *watcher, int revents) {
configerror_pid = -1;
}
/*
* Cleanup handler. Will be called when i3 exits. Kills i3-nagbar with signal
* SIGKILL (9) to make sure there are no left-over i3-nagbar processes.
*
*/
static void nagbar_cleanup(EV_P_ ev_cleanup *watcher, int revent) {
if (configerror_pid != -1) {
LOG("Sending SIGKILL (9) to i3-nagbar with PID %d\n", configerror_pid);
kill(configerror_pid, SIGKILL);
}
}
/*
* Starts an i3-nagbar process which alerts the user that his configuration
* file contains one or more errors. Also offers two buttons: One to launch an
@ -283,6 +295,12 @@ static void start_configerror_nagbar(const char *config_path) {
ev_child *child = smalloc(sizeof(ev_child));
ev_child_init(child, &nagbar_exited, configerror_pid, 0);
ev_child_start(main_loop, child);
/* install a cleanup watcher (will be called when i3 exits and i3-nagbar is
* still running) */
ev_cleanup *cleanup = smalloc(sizeof(ev_cleanup));
ev_cleanup_init(cleanup, nagbar_cleanup);
ev_cleanup_start(main_loop, cleanup);
}
/*
@ -1058,8 +1076,13 @@ workspace_name:
assign:
TOKASSIGN window_class STR
{
/* TODO: the assign command also needs some kind of new syntax where we
* just use criteria. Then deprecate the old form */
/* This is the old, deprecated form of assignments. Its provided for
* compatibility in version (4.1, 4.2, 4.3) and will be removed
* afterwards. It triggers an i3-nagbar warning starting from 4.1. */
ELOG("You are using the old assign syntax (without criteria). "
"Please see the User's Guide for the new syntax and fix "
"your config file.\n");
context->has_errors = true;
printf("assignment of %s to *%s*\n", $2, $3);
char *workspace = $3;
char *criteria = $2;
@ -1071,11 +1094,23 @@ assign:
char *separator = NULL;
if ((separator = strchr(criteria, '/')) != NULL) {
*(separator++) = '\0';
match->title = regex_new(separator);
char *pattern;
if (asprintf(&pattern, "(?i)%s", separator) == -1) {
ELOG("asprintf failed\n");
break;
}
match->title = regex_new(pattern);
free(pattern);
printf(" title = %s\n", separator);
}
if (*criteria != '\0') {
match->class = regex_new(criteria);
char *pattern;
if (asprintf(&pattern, "(?i)%s", criteria) == -1) {
ELOG("asprintf failed\n");
break;
}
match->class = regex_new(pattern);
free(pattern);
printf(" class = %s\n", criteria);
}
free(criteria);
@ -1107,6 +1142,15 @@ assign:
assignment->dest.workspace = workspace;
TAILQ_INSERT_TAIL(&assignments, assignment, assignments);
}
| TOKASSIGN match STR
{
printf("new assignment, using above criteria, to workspace %s\n", $3);
Assignment *assignment = scalloc(sizeof(Assignment));
assignment->match = current_match;
assignment->type = A_TO_WORKSPACE;
assignment->dest.workspace = $3;
TAILQ_INSERT_TAIL(&assignments, assignment, assignments);
}
;
window_class:

View File

@ -163,6 +163,14 @@ static void xkb_got_event(EV_P_ struct ev_io *w, int revents) {
DLOG("Done\n");
}
/*
* Exit handler which destroys the main_loop. Will trigger cleanup handlers.
*
*/
static void i3_exit() {
ev_loop_destroy(main_loop);
}
int main(int argc, char *argv[]) {
//parse_cmd("[ foo ] attach, attach ; focus");
int screens;
@ -529,5 +537,9 @@ int main(int argc, char *argv[]) {
start_application(exec_always->command);
}
/* Make sure to destroy the event loop to invoke the cleeanup callbacks
* when calling exit() */
atexit(i3_exit);
ev_loop(main_loop, 0);
}

View File

@ -182,6 +182,46 @@ exit_gracefully($process->pid);
sleep 0.25;
#####################################################################
# make sure that assignments are case-insensitive in the old syntax.
#####################################################################
$config = <<EOT;
# i3 config file (v4)
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
assign "special" ~
EOT
$process = launch_with_config($config);
$tmp = fresh_workspace;
ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
my $workspaces = get_workspace_names;
ok(!("targetws" ~~ @{$workspaces}), 'targetws does not exist yet');
my $window = $x->root->create_child(
class => WINDOW_CLASS_INPUT_OUTPUT,
rect => [ 0, 0, 30, 30 ],
background_color => '#0000ff',
);
$window->_create;
set_wm_class($window->id, 'SPEcial', 'SPEcial');
$window->name('special window');
$window->map;
sleep 0.25;
my $content = get_ws($tmp);
ok(@{$content->{nodes}} == 0, 'no tiling cons');
ok(@{$content->{floating_nodes}} == 1, 'one floating con');
$window->destroy;
exit_gracefully($process->pid);
sleep 0.25;
#####################################################################
# regression test: dock clients with floating assignments should not crash
# (instead, nothing should happen - dock clients cant float)
@ -200,7 +240,9 @@ $tmp = fresh_workspace;
ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
my @docked = get_dock_clients;
is(@docked, 0, 'no dock clients yet');
# We expect i3-nagbar as the first dock client due to using the old assign
# syntax
is(@docked, 1, 'one dock client yet');
my $window = $x->root->create_child(
class => WINDOW_CLASS_INPUT_OUTPUT,
@ -219,7 +261,7 @@ my $content = get_ws($tmp);
ok(@{$content->{nodes}} == 0, 'no tiling cons');
ok(@{$content->{floating_nodes}} == 0, 'one floating con');
@docked = get_dock_clients;
is(@docked, 1, 'no dock clients yet');
is(@docked, 2, 'two dock clients now');
$window->destroy;