Allow assign to workspace by number
Makes "assign [<criteria>] workspace number <number>" work in the same manner as "move to workspace number <number>" instead of assigning the window to a workspace named "number <number>". config.spec is modified to expect a 'number' string and an extra argument is used in cfg_assign. For workspaces that don't exist yet, workspace_get is used as a fallback. This also allows the user to assign to "<number> <workspace>" eg "2: work" and the full name will be used if workspace number 2 doesn't exist yet. Fixes #2590.
This commit is contained in:
parent
0f2bce3916
commit
eaf7a49e28
|
@ -766,7 +766,7 @@ considered.
|
|||
|
||||
*Syntax*:
|
||||
------------------------------------------------------------
|
||||
assign <criteria> [→] [workspace] <workspace>
|
||||
assign <criteria> [→] [workspace] [number] <workspace>
|
||||
------------------------------------------------------------
|
||||
|
||||
*Examples*:
|
||||
|
@ -783,6 +783,12 @@ assign [class="^URxvt$"] → 2
|
|||
# Assignment to a named workspace
|
||||
assign [class="^URxvt$"] → work
|
||||
|
||||
# Assign to the workspace with number 2, regardless of name
|
||||
assign [class="^URxvt$"] → number 2
|
||||
|
||||
# You can also specify a number + name. If the workspace with number 2 exists, assign will skip the text part.
|
||||
assign [class="^URxvt$"] → number "2: work"
|
||||
|
||||
# Start urxvt -name irssi
|
||||
assign [class="^URxvt$" instance="^irssi$"] → 3
|
||||
----------------------
|
||||
|
|
|
@ -57,7 +57,7 @@ CFGFUN(force_display_urgency_hint, const long duration_ms);
|
|||
CFGFUN(focus_on_window_activation, const char *mode);
|
||||
CFGFUN(show_marks, const char *value);
|
||||
CFGFUN(hide_edge_borders, const char *borders);
|
||||
CFGFUN(assign, const char *workspace);
|
||||
CFGFUN(assign, const char *workspace, bool is_number);
|
||||
CFGFUN(no_focus);
|
||||
CFGFUN(ipc_socket, const char *path);
|
||||
CFGFUN(restart_state, const char *path);
|
||||
|
|
|
@ -546,7 +546,8 @@ struct Assignment {
|
|||
A_ANY = 0,
|
||||
A_COMMAND = (1 << 0),
|
||||
A_TO_WORKSPACE = (1 << 1),
|
||||
A_NO_FOCUS = (1 << 2)
|
||||
A_NO_FOCUS = (1 << 2),
|
||||
A_TO_WORKSPACE_NUMBER = (1 << 3)
|
||||
} type;
|
||||
|
||||
/** the criteria to check if a window matches */
|
||||
|
|
|
@ -151,8 +151,14 @@ state ASSIGN_WORKSPACE:
|
|||
->
|
||||
'workspace'
|
||||
->
|
||||
'number'
|
||||
-> ASSIGN_WORKSPACE_NUMBER
|
||||
workspace = string
|
||||
-> call cfg_assign($workspace)
|
||||
-> call cfg_assign($workspace, 0)
|
||||
|
||||
state ASSIGN_WORKSPACE_NUMBER:
|
||||
number = string
|
||||
-> call cfg_assign($number, 1)
|
||||
|
||||
# no_focus <criteria>
|
||||
state NO_FOCUS:
|
||||
|
|
|
@ -377,15 +377,21 @@ CFGFUN(color, const char *colorclass, const char *border, const char *background
|
|||
#undef APPLY_COLORS
|
||||
}
|
||||
|
||||
CFGFUN(assign, const char *workspace) {
|
||||
CFGFUN(assign, const char *workspace, bool is_number) {
|
||||
if (match_is_empty(current_match)) {
|
||||
ELOG("Match is empty, ignoring this assignment\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_number && ws_name_to_number(workspace) == -1) {
|
||||
ELOG("Could not parse initial part of \"%s\" as a number.\n", workspace);
|
||||
return;
|
||||
}
|
||||
|
||||
DLOG("New assignment, using above criteria, to workspace \"%s\".\n", workspace);
|
||||
Assignment *assignment = scalloc(1, sizeof(Assignment));
|
||||
match_copy(&(assignment->match), current_match);
|
||||
assignment->type = A_TO_WORKSPACE;
|
||||
assignment->type = is_number ? A_TO_WORKSPACE_NUMBER : A_TO_WORKSPACE;
|
||||
assignment->dest.workspace = sstrdup(workspace);
|
||||
TAILQ_INSERT_TAIL(&assignments, assignment, assignments);
|
||||
}
|
||||
|
|
21
src/manage.c
21
src/manage.c
|
@ -259,9 +259,26 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
|||
Con *wm_desktop_ws = NULL;
|
||||
|
||||
/* If not, check if it is assigned to a specific workspace */
|
||||
if ((assignment = assignment_for(cwindow, A_TO_WORKSPACE))) {
|
||||
if ((assignment = assignment_for(cwindow, A_TO_WORKSPACE)) ||
|
||||
(assignment = assignment_for(cwindow, A_TO_WORKSPACE_NUMBER))) {
|
||||
DLOG("Assignment matches (%p)\n", match);
|
||||
Con *assigned_ws = workspace_get(assignment->dest.workspace, NULL);
|
||||
|
||||
Con *assigned_ws = NULL;
|
||||
if (assignment->type == A_TO_WORKSPACE_NUMBER) {
|
||||
Con *output = NULL;
|
||||
long parsed_num = ws_name_to_number(assignment->dest.workspace);
|
||||
|
||||
/* This will only work for workspaces that already exist. */
|
||||
TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
|
||||
GREP_FIRST(assigned_ws, output_get_content(output), child->num == parsed_num);
|
||||
}
|
||||
}
|
||||
/* A_TO_WORKSPACE type assignment or fallback from A_TO_WORKSPACE_NUMBER
|
||||
* when the target workspace number does not exist yet. */
|
||||
if (!assigned_ws) {
|
||||
assigned_ws = workspace_get(assignment->dest.workspace, NULL);
|
||||
}
|
||||
|
||||
nc = con_descend_tiling_focused(assigned_ws);
|
||||
DLOG("focused on ws %s: %p / %s\n", assigned_ws->name, nc, nc->name);
|
||||
if (nc->type == CT_WORKSPACE)
|
||||
|
|
|
@ -33,6 +33,33 @@ sub open_special {
|
|||
return $window;
|
||||
}
|
||||
|
||||
sub test_workspace_assignment {
|
||||
my $target_ws = "@_";
|
||||
|
||||
# initialize the target workspace, then go to a fresh one
|
||||
ok(!($target_ws ~~ @{get_workspace_names()}), "$target_ws does not exist yet");
|
||||
cmd "workspace $target_ws";
|
||||
cmp_ok(@{get_ws_content($target_ws)}, '==', 0, "no containers on $target_ws yet");
|
||||
cmd 'open';
|
||||
cmp_ok(@{get_ws_content($target_ws)}, '==', 1, "one container on $target_ws");
|
||||
my $tmp = fresh_workspace;
|
||||
|
||||
ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
|
||||
ok($target_ws ~~ @{get_workspace_names()}, "$target_ws does not exist yet");
|
||||
|
||||
# We use sync_with_i3 instead of wait_for_map here because i3 will not actually
|
||||
# map the window -- it will be assigned to a different workspace and will only
|
||||
# be mapped once you switch to that workspace
|
||||
my $window = open_special(dont_map => 1);
|
||||
$window->map;
|
||||
sync_with_i3;
|
||||
|
||||
ok(@{get_ws_content($tmp)} == 0, 'still no containers');
|
||||
ok(@{get_ws_content($target_ws)} == 2, "two containers on $target_ws");
|
||||
|
||||
return $window
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# start a window and see that it does not get assigned with an empty config
|
||||
#####################################################################
|
||||
|
@ -87,33 +114,67 @@ $window->destroy;
|
|||
exit_gracefully($pid);
|
||||
|
||||
#####################################################################
|
||||
# start a window and see that it gets assigned to a workspace which has content
|
||||
# already, next to the existing node.
|
||||
# start a window and see that it gets assigned to a formerly unused
|
||||
# numbered workspace
|
||||
#####################################################################
|
||||
|
||||
my $config_numbered = <<EOT;
|
||||
# i3 config file (v4)
|
||||
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||
assign [class="special"] → workspace number 2
|
||||
EOT
|
||||
|
||||
$pid = launch_with_config($config_numbered);
|
||||
|
||||
$tmp = fresh_workspace;
|
||||
|
||||
ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
|
||||
$workspaces = get_workspace_names;
|
||||
ok(!("2" ~~ @{$workspaces}), 'workspace number 2 does not exist yet');
|
||||
|
||||
$window = open_special;
|
||||
sync_with_i3;
|
||||
|
||||
ok(@{get_ws_content($tmp)} == 0, 'still no containers');
|
||||
ok("2" ~~ @{get_workspace_names()}, 'workspace number 2 exists');
|
||||
|
||||
$window->destroy;
|
||||
|
||||
exit_gracefully($pid);
|
||||
|
||||
#####################################################################
|
||||
# start a window and see that it gets assigned to a numbered
|
||||
# workspace which has content already, next to the existing node.
|
||||
#####################################################################
|
||||
|
||||
$pid = launch_with_config($config_numbered);
|
||||
|
||||
$window = test_workspace_assignment("2");
|
||||
$window->destroy;
|
||||
|
||||
exit_gracefully($pid);
|
||||
|
||||
#####################################################################
|
||||
# start a window and see that it gets assigned to a numbered workspace with
|
||||
# a name which has content already, next to the existing node.
|
||||
#####################################################################
|
||||
|
||||
$pid = launch_with_config($config_numbered);
|
||||
|
||||
cmd 'workspace 2'; # Make sure that we are not testing for "2" again.
|
||||
$window = test_workspace_assignment("2: targetws");
|
||||
$window->destroy;
|
||||
|
||||
exit_gracefully($pid);
|
||||
|
||||
#####################################################################
|
||||
# start a window and see that it gets assigned to a workspace which
|
||||
# has content already, next to the existing node.
|
||||
#####################################################################
|
||||
|
||||
$pid = launch_with_config($config);
|
||||
|
||||
# initialize the target workspace, then go to a fresh one
|
||||
ok(!("targetws" ~~ @{get_workspace_names()}), 'targetws does not exist yet');
|
||||
cmd 'workspace targetws';
|
||||
cmp_ok(@{get_ws_content('targetws')}, '==', 0, 'no containers on targetws yet');
|
||||
cmd 'open';
|
||||
cmp_ok(@{get_ws_content('targetws')}, '==', 1, 'one container on targetws');
|
||||
$tmp = fresh_workspace;
|
||||
|
||||
ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
|
||||
ok("targetws" ~~ @{get_workspace_names()}, 'targetws does not exist yet');
|
||||
|
||||
|
||||
# We use sync_with_i3 instead of wait_for_map here because i3 will not actually
|
||||
# map the window -- it will be assigned to a different workspace and will only
|
||||
# be mapped once you switch to that workspace
|
||||
$window = open_special(dont_map => 1);
|
||||
$window->map;
|
||||
sync_with_i3;
|
||||
|
||||
ok(@{get_ws_content($tmp)} == 0, 'still no containers');
|
||||
ok(@{get_ws_content('targetws')} == 2, 'two containers on targetws');
|
||||
test_workspace_assignment("targetws");
|
||||
|
||||
exit_gracefully($pid);
|
||||
|
||||
|
|
|
@ -116,6 +116,7 @@ is(parser_calls($config),
|
|||
|
||||
$config = <<'EOT';
|
||||
assign [class="^Chrome"] 4
|
||||
assign [class="^Chrome"] workspace number 3
|
||||
assign [class="^Chrome"] named workspace
|
||||
assign [class="^Chrome"] "quoted named workspace"
|
||||
assign [class="^Chrome"] → "quoted named workspace"
|
||||
|
@ -123,13 +124,15 @@ EOT
|
|||
|
||||
$expected = <<'EOT';
|
||||
cfg_criteria_add(class, ^Chrome)
|
||||
cfg_assign(4)
|
||||
cfg_assign(4, 0)
|
||||
cfg_criteria_add(class, ^Chrome)
|
||||
cfg_assign(named workspace)
|
||||
cfg_assign(3, 1)
|
||||
cfg_criteria_add(class, ^Chrome)
|
||||
cfg_assign(quoted named workspace)
|
||||
cfg_assign(named workspace, 0)
|
||||
cfg_criteria_add(class, ^Chrome)
|
||||
cfg_assign(quoted named workspace)
|
||||
cfg_assign(quoted named workspace, 0)
|
||||
cfg_criteria_add(class, ^Chrome)
|
||||
cfg_assign(quoted named workspace, 0)
|
||||
EOT
|
||||
|
||||
is(parser_calls($config),
|
||||
|
|
Loading…
Reference in New Issue