i3 User’s Guide
===============
Michael Stapelberg <michael+i3@stapelberg.de>
-January 2012
+April 2012
This document contains all the information you need to configure and use the i3
window manager. If it does not, please contact us on IRC (preferred) or post your
it has. This is useful in case you are changing the workspace’s name
dynamically.
+=== Renaming workspaces
+
+You can rename workspaces. This might be useful to start with the default
+numbered workspaces, do your work, and rename the workspaces afterwards to
+reflect what’s actually on them.
+
+*Syntax*:
+----------------------------------------------------
+rename workspace <old_name> to <new_name>
+----------------------------------------------------
+
+*Examples*:
+------------------------------------------------
+i3-msg 'rename workspace 5 to 6'
+i3-msg 'rename workspace 1 to "1: www"'
+i3-msg 'rename workspace "1: www" to "10: www"'
+------------------------------------------------
+
[[resizingconfig]]
=== Resizing containers/windows
*/
void cmd_scratchpad_show(I3_CMD);
+/**
+ * Implementation of 'rename workspace <name> to <name>'
+ *
+ */
+void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name);
+
#endif
'floating' -> FLOATING
'mark' -> MARK
'resize' -> RESIZE
+ 'rename' -> RENAME
'nop' -> NOP
'scratchpad' -> SCRATCHPAD
'mode' -> MODE
end
-> call cmd_resize($way, $direction, $resize_px, $resize_ppt)
+# rename workspace <name> to <name>
+state RENAME:
+ 'workspace'
+ -> RENAME_WORKSPACE
+
+state RENAME_WORKSPACE:
+ old_name = word
+ -> RENAME_WORKSPACE_TO
+
+state RENAME_WORKSPACE_TO:
+ 'to'
+ ->
+ new_name = string
+ -> call cmd_rename_workspace($old_name, $new_name)
+
# move <direction> [<pixels> [px]]
# move [window|container] [to] workspace <str>
# move [window|container] [to] output <str>
// XXX: default reply for now, make this a better reply
cmd_output->json_output = sstrdup("{\"success\": true}");
}
+
+/*
+ * Implementation of 'rename workspace <name> to <name>'
+ *
+ */
+void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) {
+ LOG("Renaming workspace \"%s\" to \"%s\"\n", old_name, new_name);
+
+ Con *output, *workspace = NULL;
+ TAILQ_FOREACH(output, &(croot->nodes_head), nodes)
+ GREP_FIRST(workspace, output_get_content(output),
+ !strcasecmp(child->name, old_name));
+
+ if (!workspace) {
+ // TODO: we should include the old workspace name here and use yajl for
+ // generating the reply.
+ cmd_output->json_output = sstrdup("{\"success\": false, "
+ "\"error\":\"Old workspace not found\"}");
+ return;
+ }
+
+ Con *check_dest = NULL;
+ TAILQ_FOREACH(output, &(croot->nodes_head), nodes)
+ GREP_FIRST(check_dest, output_get_content(output),
+ !strcasecmp(child->name, new_name));
+
+ if (check_dest != NULL) {
+ // TODO: we should include the new workspace name here and use yajl for
+ // generating the reply.
+ cmd_output->json_output = sstrdup("{\"success\": false, "
+ "\"error\":\"New workspace already exists\"}");
+ return;
+ }
+
+ /* Change the name and try to parse it as a number. */
+ FREE(workspace->name);
+ workspace->name = sstrdup(new_name);
+ char *endptr = NULL;
+ long parsed_num = strtol(new_name, &endptr, 10);
+ if (parsed_num == LONG_MIN ||
+ parsed_num == LONG_MAX ||
+ parsed_num < 0 ||
+ endptr == new_name)
+ workspace->num = -1;
+ else workspace->num = parsed_num;
+ LOG("num = %d\n", workspace->num);
+
+ /* By re-attaching, the sort order will be correct afterwards. */
+ Con *previously_focused = focused;
+ Con *parent = workspace->parent;
+ con_detach(workspace);
+ con_attach(workspace, parent, false);
+ /* Restore the previous focus since con_attach messes with the focus. */
+ con_focus(previously_focused);
+
+ cmd_output->needs_tree_render = true;
+ cmd_output->json_output = sstrdup("{\"success\": true}");
+
+ ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"rename\"}");
+}
workspace->type = CT_WORKSPACE;
FREE(workspace->name);
workspace->name = sstrdup(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. */
+ /* We set ->num to the number if this workspace’s name begins with a
+ * 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 ||
is(focused_ws(), '4: foo', 'now on workspace 4: foo');
ok(!workspace_exists('4'), 'workspace 4 still does not exist');
+################################################################################
+# Verify that renaming workspaces works.
+################################################################################
+
+sub workspace_numbers_sorted {
+ my ($name) = @_;
+ my $i3 = i3(get_socket_path());
+ my $tree = $i3->get_tree->recv;
+
+ my @outputs = @{$tree->{nodes}};
+ my @workspaces;
+ for my $output (@outputs) {
+ # get the first CT_CON of each output
+ my $content = first { $_->{type} == 2 } @{$output->{nodes}};
+ @workspaces = (@workspaces, @{$content->{nodes}});
+ }
+
+ my @numbers = grep { $_ != -1 } map { $_->{num} } @workspaces;
+ is_deeply(
+ [ sort { $a <=> $b } @numbers ],
+ \@numbers,
+ 'workspace numbers sorted');
+}
+
+# 1: numbered workspace
+cmd 'workspace 10';
+cmd 'open';
+cmd 'workspace 13';
+cmd 'open';
+
+workspace_numbers_sorted();
+
+cmd 'workspace 9';
+is(focused_ws(), '9', 'now on workspace 9');
+
+ok(!workspace_exists('12'), 'workspace 12 does not exist yet');
+cmd 'rename workspace 9 to 12';
+ok(!workspace_exists('9'), 'workspace 9 does not exist anymore');
+is(focused_ws(), '12', 'now on workspace 12');
+$ws = get_ws('12');
+is($ws->{num}, 12, 'number correctly changed');
+
+workspace_numbers_sorted();
+
+# 2: numbered + named workspace
+cmd 'workspace 9: foo';
+is(focused_ws(), '9: foo', 'now on workspace 9: foo');
+
+ok(!workspace_exists('11: bar'), 'workspace 11: bar does not exist yet');
+cmd 'rename workspace "9: foo" to "11: bar"';
+ok(!workspace_exists('9: foo'), 'workspace 9 does not exist anymore');
+is(focused_ws(), '11: bar', 'now on workspace 10');
+$ws = get_ws('11: bar');
+is($ws->{num}, 11, 'number correctly changed');
+workspace_numbers_sorted();
+# keep that one open, we need it later
+cmd 'open';
+
+# 3: named workspace
+cmd 'workspace bleh';
+is(focused_ws(), 'bleh', 'now on workspace bleh');
+
+ok(!workspace_exists('qux'), 'workspace qux does not exist yet');
+cmd 'rename workspace bleh to qux';
+ok(!workspace_exists('bleh'), 'workspace 9 does not exist anymore');
+is(focused_ws(), 'qux', 'now on workspace qux');
+$ws = get_ws('qux');
+is($ws->{num}, -1, 'number correctly changed');
+workspace_numbers_sorted();
+
+# 5: already existing workspace
+my $result = cmd 'rename workspace qux to 11: bar';
+ok(!$result->[0]->{success}, 'renaming workspace to an already existing one failed');
+
+# 6: non-existing old workspace (verify command result)
+$result = cmd 'rename workspace notexistant to bleh';
+ok(!$result->[0]->{success}, 'renaming workspace which does not exist failed');
+
+
done_testing;
################################################################################
is(parser_calls('unknown_literal'),
- "Expected one of these tokens: <end>, '[', 'move', 'exec', 'exit', 'restart', 'reload', 'border', 'layout', 'append_layout', 'workspace', 'focus', 'kill', 'open', 'fullscreen', 'split', 'floating', 'mark', 'resize', 'nop', 'scratchpad', 'mode'\n" .
+ "Expected one of these tokens: <end>, '[', 'move', 'exec', 'exit', 'restart', 'reload', 'border', 'layout', 'append_layout', 'workspace', 'focus', 'kill', 'open', 'fullscreen', 'split', 'floating', 'mark', 'resize', 'rename', 'nop', 'scratchpad', 'mode'\n" .
"Your command: unknown_literal\n" .
" ^^^^^^^^^^^^^^^",
'error for unknown literal ok');