Merge branch 'new-assign' into next
This commit is contained in:
commit
2ef54057e6
@ -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), you’d 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 window’s 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:
|
||||
|
@ -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]; }
|
||||
|
@ -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. It’s 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:
|
||||
|
12
src/main.c
12
src/main.c
@ -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);
|
||||
}
|
||||
|
@ -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 can’t 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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user