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
parent
fab8b84db7
commit
1de97a1f1f
|
@ -281,6 +281,10 @@ struct Con {
|
||||||
|
|
||||||
char *name;
|
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
|
/* 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
|
* group. The contents are shared between all of them, that is they are
|
||||||
* displayed on whichever of the containers is currently visible */
|
* displayed on whichever of the containers is currently visible */
|
||||||
|
|
34
src/con.c
34
src/con.c
|
@ -72,6 +72,35 @@ void con_attach(Con *con, Con *parent) {
|
||||||
con->parent = parent;
|
con->parent = parent;
|
||||||
Con *loop;
|
Con *loop;
|
||||||
Con *current = NULL;
|
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 */
|
/* Get the first tiling container in focus stack */
|
||||||
TAILQ_FOREACH(loop, &(parent->focus_head), focused) {
|
TAILQ_FOREACH(loop, &(parent->focus_head), focused) {
|
||||||
|
@ -85,9 +114,10 @@ void con_attach(Con *con, Con *parent) {
|
||||||
if (current) {
|
if (current) {
|
||||||
DLOG("Inserting con = %p after last focused tiling con %p\n",
|
DLOG("Inserting con = %p after last focused tiling con %p\n",
|
||||||
con, current);
|
con, current);
|
||||||
TAILQ_INSERT_AFTER(&(parent->nodes_head), current, con, nodes);
|
TAILQ_INSERT_AFTER(nodes_head, current, con, nodes);
|
||||||
} else TAILQ_INSERT_TAIL(&(parent->nodes_head), 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.
|
/* We insert to the TAIL because con_focus() will correct this.
|
||||||
* This way, we have the option to insert Cons without having
|
* This way, we have the option to insert Cons without having
|
||||||
* to focus them. */
|
* to focus them. */
|
||||||
|
|
|
@ -269,7 +269,9 @@ IPC_HANDLER(get_workspaces) {
|
||||||
y(map_open);
|
y(map_open);
|
||||||
|
|
||||||
ystr("num");
|
ystr("num");
|
||||||
y(integer, con_num_children(ws));
|
if (ws->num == -1)
|
||||||
|
y(null);
|
||||||
|
else y(integer, ws->num);
|
||||||
|
|
||||||
ystr("name");
|
ystr("name");
|
||||||
ystr(ws->name);
|
ystr(ws->name);
|
||||||
|
|
|
@ -77,10 +77,12 @@ void tree_init() {
|
||||||
free(name);
|
free(name);
|
||||||
|
|
||||||
/* add a workspace to this output */
|
/* add a workspace to this output */
|
||||||
ws = con_new(oc);
|
ws = con_new(NULL);
|
||||||
ws->type = CT_WORKSPACE;
|
ws->type = CT_WORKSPACE;
|
||||||
|
ws->num = c;
|
||||||
asprintf(&(ws->name), "%d", c);
|
asprintf(&(ws->name), "%d", c);
|
||||||
c++;
|
c++;
|
||||||
|
con_attach(ws, oc);
|
||||||
|
|
||||||
asprintf(&name, "[i3 con] workspace %s", ws->name);
|
asprintf(&name, "[i3 con] workspace %s", ws->name);
|
||||||
x_set_name(ws, name);
|
x_set_name(ws, name);
|
||||||
|
|
|
@ -38,14 +38,28 @@ Con *workspace_get(const char *num) {
|
||||||
LOG("need to create this one\n");
|
LOG("need to create this one\n");
|
||||||
output = con_get_output(focused);
|
output = con_get_output(focused);
|
||||||
LOG("got output %p\n", output);
|
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;
|
char *name;
|
||||||
asprintf(&name, "[i3 con] workspace %s", num);
|
asprintf(&name, "[i3 con] workspace %s", num);
|
||||||
x_set_name(workspace, name);
|
x_set_name(workspace, name);
|
||||||
free(name);
|
free(name);
|
||||||
workspace->type = CT_WORKSPACE;
|
workspace->type = CT_WORKSPACE;
|
||||||
workspace->name = strdup(num);
|
workspace->name = strdup(num);
|
||||||
|
/* We set ->num to the number if this workspace’s name consists only of
|
||||||
|
* a positive number. Otherwise it’s 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;
|
workspace->orientation = HORIZ;
|
||||||
|
con_attach(workspace, output);
|
||||||
|
|
||||||
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}");
|
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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');
|
|
@ -10,7 +10,7 @@ use List::Util qw(first);
|
||||||
use v5.10;
|
use v5.10;
|
||||||
|
|
||||||
use Exporter ();
|
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 {
|
BEGIN {
|
||||||
my $window_count = 0;
|
my $window_count = 0;
|
||||||
|
|
Loading…
Reference in New Issue