Feature: Workspace assignment by number
Workspace assignments with bare numbers assign all workspaces with that number to the specified output. Workspace assignment by number is overridden by workspace assignment by name.
This commit is contained in:
parent
cfd06718fc
commit
f41e81bd96
@ -158,7 +158,7 @@ struct deco_render_params {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores which workspace (by name) goes to which output.
|
* Stores which workspace (by name or number) goes to which output.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct Workspace_Assignment {
|
struct Workspace_Assignment {
|
||||||
|
@ -58,6 +58,19 @@ int max(int a, int b);
|
|||||||
bool rect_contains(Rect rect, uint32_t x, uint32_t y);
|
bool rect_contains(Rect rect, uint32_t x, uint32_t y);
|
||||||
Rect rect_add(Rect a, Rect b);
|
Rect rect_add(Rect a, Rect b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the name consists of only digits.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
__attribute__((pure)) bool name_is_digits(const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the workspace name as a number. Returns -1 if the workspace should be
|
||||||
|
* interpreted as a "named workspace".
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
long ws_name_to_number(const char *name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates *destination with new_value and returns true if it was changed or false
|
* Updates *destination with new_value and returns true if it was changed or false
|
||||||
* if it was the same
|
* if it was the same
|
||||||
|
33
src/util.c
33
src/util.c
@ -21,6 +21,7 @@
|
|||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <yajl/yajl_version.h>
|
#include <yajl/yajl_version.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#define SN_API_NOT_YET_FROZEN 1
|
#define SN_API_NOT_YET_FROZEN 1
|
||||||
#include <libsn/sn-launcher.h>
|
#include <libsn/sn-launcher.h>
|
||||||
@ -47,6 +48,38 @@ Rect rect_add(Rect a, Rect b) {
|
|||||||
a.height + b.height};
|
a.height + b.height};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns true if the name consists of only digits.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
__attribute__ ((pure)) bool name_is_digits(const char *name) {
|
||||||
|
/* positive integers and zero are interpreted as numbers */
|
||||||
|
for (int i = 0; i < strlen(name); i++)
|
||||||
|
if (!isdigit(name[i]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parses the workspace name as a number. Returns -1 if the workspace should be
|
||||||
|
* interpreted as a "named workspace".
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
long ws_name_to_number(const char *name) {
|
||||||
|
/* positive integers and zero are interpreted as numbers */
|
||||||
|
char *endptr = NULL;
|
||||||
|
long parsed_num = strtol(name, &endptr, 10);
|
||||||
|
if (parsed_num == LONG_MIN ||
|
||||||
|
parsed_num == LONG_MAX ||
|
||||||
|
parsed_num < 0 ||
|
||||||
|
endptr == name) {
|
||||||
|
parsed_num = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed_num;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Updates *destination with new_value and returns true if it was changed or false
|
* Updates *destination with new_value and returns true if it was changed or false
|
||||||
* if it was the same
|
* if it was the same
|
||||||
|
@ -53,14 +53,25 @@ Con *workspace_get(const char *num, bool *created) {
|
|||||||
output = con_get_output(focused);
|
output = con_get_output(focused);
|
||||||
/* look for assignments */
|
/* look for assignments */
|
||||||
struct Workspace_Assignment *assignment;
|
struct Workspace_Assignment *assignment;
|
||||||
TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) {
|
|
||||||
if (strcmp(assignment->name, num) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
LOG("Found workspace assignment to output \"%s\"\n", assignment->output);
|
/* We set workspace->num to the number if this workspace’s name begins
|
||||||
GREP_FIRST(output, croot, !strcmp(child->name, assignment->output));
|
* with a positive number. Otherwise it’s a named ws and num will be
|
||||||
break;
|
* -1. */
|
||||||
|
long parsed_num = ws_name_to_number(num);
|
||||||
|
|
||||||
|
TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) {
|
||||||
|
if (strcmp(assignment->name, num) == 0) {
|
||||||
|
DLOG("Found workspace name assignment to output \"%s\"\n", assignment->output);
|
||||||
|
GREP_FIRST(output, croot, !strcmp(child->name, assignment->output));
|
||||||
|
break;
|
||||||
|
} else if (parsed_num != -1
|
||||||
|
&& name_is_digits(assignment->name)
|
||||||
|
&& ws_name_to_number(assignment->name) == parsed_num) {
|
||||||
|
DLOG("Found workspace number assignment to output \"%s\"\n", assignment->output);
|
||||||
|
GREP_FIRST(output, croot, !strcmp(child->name, assignment->output));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Con *content = output_get_content(output);
|
Con *content = output_get_content(output);
|
||||||
LOG("got output %p with content %p\n", output, content);
|
LOG("got output %p with content %p\n", output, content);
|
||||||
/* We need to attach this container after setting its type. con_attach
|
/* We need to attach this container after setting its type. con_attach
|
||||||
@ -74,16 +85,7 @@ Con *workspace_get(const char *num, bool *created) {
|
|||||||
FREE(workspace->name);
|
FREE(workspace->name);
|
||||||
workspace->name = sstrdup(num);
|
workspace->name = sstrdup(num);
|
||||||
workspace->workspace_layout = config.default_layout;
|
workspace->workspace_layout = config.default_layout;
|
||||||
/* We set ->num to the number if this workspace’s name begins with a
|
workspace->num = parsed_num;
|
||||||
* positive number. Otherwise it’s a named ws and num will be -1. */
|
|
||||||
char *endptr = NULL;
|
|
||||||
long parsed_num = strtol(num, &endptr, 10);
|
|
||||||
if (parsed_num == LONG_MIN ||
|
|
||||||
parsed_num == LONG_MAX ||
|
|
||||||
parsed_num < 0 ||
|
|
||||||
endptr == num)
|
|
||||||
workspace->num = -1;
|
|
||||||
else workspace->num = parsed_num;
|
|
||||||
LOG("num = %d\n", workspace->num);
|
LOG("num = %d\n", workspace->num);
|
||||||
|
|
||||||
workspace->parent = content;
|
workspace->parent = content;
|
||||||
|
77
testcases/t/518-interpret-workspace-numbers.t
Normal file
77
testcases/t/518-interpret-workspace-numbers.t
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#!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 that workspace assignment config directives for plain numbers will
|
||||||
|
# assign any workspace of that number to the specified output.
|
||||||
|
# Ticket: #1238
|
||||||
|
# Bug still in: 4.7.2-147-g3760a48
|
||||||
|
use i3test i3_autostart => 0;
|
||||||
|
|
||||||
|
my $config = <<EOT;
|
||||||
|
# i3 config file (v4)
|
||||||
|
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||||
|
|
||||||
|
workspace 1:override output fake-0
|
||||||
|
workspace 2 output fake-0
|
||||||
|
workspace 1 output fake-1
|
||||||
|
workspace 2:override output fake-1
|
||||||
|
|
||||||
|
fake-outputs 1024x768+0+0,1024x768+1024+0
|
||||||
|
EOT
|
||||||
|
|
||||||
|
my $pid = launch_with_config($config);
|
||||||
|
my $i3 = i3(get_socket_path());
|
||||||
|
$i3->connect->recv;
|
||||||
|
|
||||||
|
# Returns the name of the output on which this workspace resides
|
||||||
|
sub get_output_for_workspace {
|
||||||
|
my $ws_name = shift @_;
|
||||||
|
|
||||||
|
foreach (grep { not $_->{name} =~ /^__/ } @{$i3->get_tree->recv->{nodes}}) {
|
||||||
|
my $output = $_->{name};
|
||||||
|
foreach (grep { $_->{name} =~ "content" } @{$_->{nodes}}) {
|
||||||
|
return $output if $_->{nodes}[0]->{name} =~ $ws_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Workspace assignments with bare numbers should be interpreted as `workspace
|
||||||
|
# number` config directives. Any workspace beginning with that number should be
|
||||||
|
# assigned to the specified output.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
cmd 'focus output fake-1';
|
||||||
|
cmd 'workspace "2:foo"';
|
||||||
|
is(get_output_for_workspace('2:foo'), 'fake-0',
|
||||||
|
'Workspaces should be assigned by number when the assignment is a plain number')
|
||||||
|
or diag 'Since workspace number 2 is assigned to fake-0, 2:foo should open on fake-0';
|
||||||
|
|
||||||
|
cmd 'focus output fake-0';
|
||||||
|
cmd 'workspace "2:override"';
|
||||||
|
is(get_output_for_workspace('2:override'), 'fake-1',
|
||||||
|
'Workspace assignments by name should override numbered assignments')
|
||||||
|
or diag 'Since workspace "2:override" is assigned by name to fake-1, it should open on fake-1';
|
||||||
|
|
||||||
|
cmd 'focus output fake-1';
|
||||||
|
cmd 'workspace "1:override"';
|
||||||
|
is(get_output_for_workspace('1:override'), 'fake-0',
|
||||||
|
'Assignment rules should not be affected by the order assignments are declared')
|
||||||
|
or diag 'Since workspace "1:override" is assigned by name to fake-0, it should open on fake-0';
|
||||||
|
|
||||||
|
exit_gracefully($pid);
|
||||||
|
|
||||||
|
done_testing;
|
Loading…
Reference in New Issue
Block a user