correctly sort numbered workspaces (+testcase)

Numbered workspaces (workspaces with a name containing only digits) will be
inserted in the correct order now. Named workspaces are always sorted after
numbered workspaces and in the order of creation.
next
Michael Stapelberg 2010-11-21 23:35:49 +01:00
parent fab8b84db7
commit 1de97a1f1f
7 changed files with 117 additions and 6 deletions

View File

@ -281,6 +281,10 @@ struct Con {
char *name;
/** the workspace number, if this Con is of type CT_WORKSPACE and the
* workspace is not a named workspace (for named workspaces, num == -1) */
int num;
/* a sticky-group is an identifier which bundles several containers to a
* group. The contents are shared between all of them, that is they are
* displayed on whichever of the containers is currently visible */

View File

@ -72,6 +72,35 @@ void con_attach(Con *con, Con *parent) {
con->parent = parent;
Con *loop;
Con *current = NULL;
struct nodes_head *nodes_head = &(parent->nodes_head);
/* Workspaces are handled differently: they need to be inserted at the
* right position. */
if (con->type == CT_WORKSPACE) {
DLOG("it's a workspace. num = %d\n", con->num);
if (con->num == -1 || TAILQ_EMPTY(nodes_head)) {
TAILQ_INSERT_TAIL(nodes_head, con, nodes);
} else {
current = TAILQ_FIRST(nodes_head);
if (con->num < current->num) {
/* we need to insert the container at the beginning */
TAILQ_INSERT_HEAD(nodes_head, con, nodes);
return;
}
while (current->num != -1 && con->num > current->num) {
current = TAILQ_NEXT(current, nodes);
if (current == TAILQ_END(nodes_head)) {
current = NULL;
break;
}
}
/* we need to insert con after current, if current is not NULL */
if (current)
TAILQ_INSERT_BEFORE(current, con, nodes);
else TAILQ_INSERT_TAIL(nodes_head, con, nodes);
}
goto add_to_focus_head;
}
/* Get the first tiling container in focus stack */
TAILQ_FOREACH(loop, &(parent->focus_head), focused) {
@ -85,9 +114,10 @@ void con_attach(Con *con, Con *parent) {
if (current) {
DLOG("Inserting con = %p after last focused tiling con %p\n",
con, current);
TAILQ_INSERT_AFTER(&(parent->nodes_head), current, con, nodes);
} else TAILQ_INSERT_TAIL(&(parent->nodes_head), con, nodes);
TAILQ_INSERT_AFTER(nodes_head, current, con, nodes);
} else TAILQ_INSERT_TAIL(nodes_head, con, nodes);
add_to_focus_head:
/* We insert to the TAIL because con_focus() will correct this.
* This way, we have the option to insert Cons without having
* to focus them. */

View File

@ -269,7 +269,9 @@ IPC_HANDLER(get_workspaces) {
y(map_open);
ystr("num");
y(integer, con_num_children(ws));
if (ws->num == -1)
y(null);
else y(integer, ws->num);
ystr("name");
ystr(ws->name);

View File

@ -77,10 +77,12 @@ void tree_init() {
free(name);
/* add a workspace to this output */
ws = con_new(oc);
ws = con_new(NULL);
ws->type = CT_WORKSPACE;
ws->num = c;
asprintf(&(ws->name), "%d", c);
c++;
con_attach(ws, oc);
asprintf(&name, "[i3 con] workspace %s", ws->name);
x_set_name(ws, name);

View File

@ -38,14 +38,28 @@ Con *workspace_get(const char *num) {
LOG("need to create this one\n");
output = con_get_output(focused);
LOG("got output %p\n", output);
workspace = con_new(output);
/* We need to attach this container after setting its type. con_attach
* will handle CT_WORKSPACEs differently */
workspace = con_new(NULL);
char *name;
asprintf(&name, "[i3 con] workspace %s", num);
x_set_name(workspace, name);
free(name);
workspace->type = CT_WORKSPACE;
workspace->name = strdup(num);
/* We set ->num to the number if this workspaces name consists only of
* a positive number. Otherwise its a named ws and num will be -1. */
char *end;
long parsed_num = strtol(num, &end, 10);
if (parsed_num == LONG_MIN ||
parsed_num == LONG_MAX ||
parsed_num < 0 ||
(end && *end != '\0'))
workspace->num = -1;
else workspace->num = parsed_num;
LOG("num = %d\n", workspace->num);
workspace->orientation = HORIZ;
con_attach(workspace, output);
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}");
}

View File

@ -0,0 +1,59 @@
#!perl
# vim:ts=4:sw=4:expandtab
# Check if numbered workspaces and named workspaces are sorted in the right way
# in get_workspaces IPC output (necessary for i3bar etc.).
use i3test tests => 9;
use X11::XCB qw(:all);
use Time::HiRes qw(sleep);
BEGIN {
use_ok('X11::XCB::Window');
}
my $i3 = i3("/tmp/nestedcons");
my $x = X11::XCB::Connection->new;
sub check_order {
my ($msg) = @_;
my @ws = @{$i3->get_workspaces->recv};
my @nums = map { $_->{num} } grep { defined($_->{num}) } @ws;
my @sorted = sort @nums;
cmp_deeply(\@nums, \@sorted, $msg);
}
check_order('workspace order alright before testing');
#############################################################################
# open a window to keep this ws open
#############################################################################
$i3->command("workspace 93")->recv;
open_standard_window($x);
my @ws = @{$i3->get_workspaces->recv};
my @f = grep { defined($_->{num}) && $_->{num} == 93 } @ws;
is(@f, 1, 'ws 93 found by num');
check_order('workspace order alright after opening 93');
$i3->command("workspace 92")->recv;
open_standard_window($x);
check_order('workspace order alright after opening 92');
$i3->command("workspace 94")->recv;
open_standard_window($x);
check_order('workspace order alright after opening 94');
$i3->command("workspace 96")->recv;
open_standard_window($x);
check_order('workspace order alright after opening 96');
$i3->command("workspace foo")->recv;
open_standard_window($x);
check_order('workspace order alright after opening foo');
$i3->command("workspace 91")->recv;
open_standard_window($x);
check_order('workspace order alright after opening 91');

View File

@ -10,7 +10,7 @@ use List::Util qw(first);
use v5.10;
use Exporter ();
our @EXPORT = qw(get_workspace_names get_unused_workspace get_ws_content get_ws get_focused open_empty_con);
our @EXPORT = qw(get_workspace_names get_unused_workspace get_ws_content get_ws get_focused open_empty_con open_standard_window);
BEGIN {
my $window_count = 0;