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 */
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) {
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. */
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);
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);
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 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;
+ con_attach(workspace, output);
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}");
}
--- /dev/null
+#!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');
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;