TAILQ_HEAD(swallow_head, Match) swallow_head;
enum { CF_NONE = 0, CF_OUTPUT = 1, CF_GLOBAL = 2 } fullscreen_mode;
+ /* layout is the layout of this container: one of split[v|h], stacked or
+ * tabbed. Special containers in the tree (above workspaces) have special
+ * layouts like dockarea or output.
+ *
+ * last_split_layout is one of splitv or splith to support the old "layout
+ * default" command which by now should be "layout splitv" or "layout
+ * splith" explicitly.
+ *
+ * workspace_layout is only for type == CT_WORKSPACE cons. When you change
+ * the layout of a workspace without any children, i3 cannot just set the
+ * layout (because workspaces need to be splitv/splith to allow focus
+ * parent and opening new containers). Instead, it stores the requested
+ * layout in workspace_layout and creates a new split container with that
+ * layout whenever a new container is attached to the workspace. */
enum {
L_DEFAULT = 0,
L_STACKED = 1,
L_OUTPUT = 4,
L_SPLITV = 5,
L_SPLITH = 6
- } layout, last_split_layout;
+ } layout, last_split_layout, workspace_layout;
border_style_t border_style;
/** floating? (= not in tiling layout) This cannot be simply a bool
* because we want to keep track of whether the status was set by the
*/
if (con->window != NULL &&
parent->type == CT_WORKSPACE &&
- config.default_layout != L_DEFAULT) {
+ parent->workspace_layout != L_DEFAULT) {
DLOG("Parent is a workspace. Applying default layout...\n");
Con *target = workspace_attach_to(parent);
* need to create a new split container. */
if (con->type == CT_WORKSPACE &&
(layout == L_STACKED || layout == L_TABBED)) {
- DLOG("Creating new split container\n");
- /* 1: create a new split container */
- Con *new = con_new(NULL, NULL);
- new->parent = con;
-
- /* 2: Set the requested layout on the split container and mark it as
- * split. */
- new->layout = layout;
- new->last_split_layout = con->last_split_layout;
- new->split = true;
-
- Con *old_focused = TAILQ_FIRST(&(con->focus_head));
- if (old_focused == TAILQ_END(&(con->focus_head)))
- old_focused = NULL;
-
- /* 3: move the existing cons of this workspace below the new con */
- DLOG("Moving cons\n");
- Con *child;
- while (!TAILQ_EMPTY(&(con->nodes_head))) {
- child = TAILQ_FIRST(&(con->nodes_head));
- con_detach(child);
- con_attach(child, new, true);
- }
-
- /* 4: attach the new split container to the workspace */
- DLOG("Attaching new split to ws\n");
- con_attach(new, con, false);
+ if (con_num_children(con) == 0) {
+ DLOG("Setting workspace_layout to %d\n", layout);
+ con->workspace_layout = layout;
+ } else {
+ DLOG("Creating new split container\n");
+ /* 1: create a new split container */
+ Con *new = con_new(NULL, NULL);
+ new->parent = con;
+
+ /* 2: Set the requested layout on the split container and mark it as
+ * split. */
+ new->layout = layout;
+ new->last_split_layout = con->last_split_layout;
+ new->split = true;
+
+ Con *old_focused = TAILQ_FIRST(&(con->focus_head));
+ if (old_focused == TAILQ_END(&(con->focus_head)))
+ old_focused = NULL;
+
+ /* 3: move the existing cons of this workspace below the new con */
+ DLOG("Moving cons\n");
+ Con *child;
+ while (!TAILQ_EMPTY(&(con->nodes_head))) {
+ child = TAILQ_FIRST(&(con->nodes_head));
+ con_detach(child);
+ con_attach(child, new, true);
+ }
- if (old_focused)
- con_focus(old_focused);
+ /* 4: attach the new split container to the workspace */
+ DLOG("Attaching new split to ws\n");
+ con_attach(new, con, false);
- tree_flatten(croot);
+ if (old_focused)
+ con_focus(old_focused);
+ tree_flatten(croot);
+ }
return;
}
break;
}
+ ystr("workspace_layout");
+ switch (con->workspace_layout) {
+ case L_DEFAULT:
+ ystr("default");
+ break;
+ case L_STACKED:
+ ystr("stacked");
+ break;
+ case L_TABBED:
+ ystr("tabbed");
+ break;
+ default:
+ DLOG("About to dump workspace_layout=%d (none of default/stacked/tabbed), this is a bug.\n", con->workspace_layout);
+ assert(false);
+ break;
+ }
+
ystr("last_split_layout");
switch (con->layout) {
case L_SPLITV:
json_node->layout = L_SPLITV;
else LOG("Unhandled \"layout\": %s\n", buf);
free(buf);
+ } else if (strcasecmp(last_key, "workspace_layout") == 0) {
+ char *buf = NULL;
+ sasprintf(&buf, "%.*s", (int)len, val);
+ if (strcasecmp(buf, "default") == 0)
+ json_node->workspace_layout = L_DEFAULT;
+ else if (strcasecmp(buf, "stacked") == 0)
+ json_node->workspace_layout = L_STACKED;
+ else if (strcasecmp(buf, "tabbed") == 0)
+ json_node->workspace_layout = L_TABBED;
+ else LOG("Unhandled \"workspace_layout\": %s\n", buf);
+ free(buf);
} else if (strcasecmp(last_key, "last_split_layout") == 0) {
char *buf = NULL;
sasprintf(&buf, "%.*s", (int)len, val);
workspace->type = CT_WORKSPACE;
FREE(workspace->name);
workspace->name = sstrdup(num);
+ workspace->workspace_layout = config.default_layout;
/* 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;
Con *workspace_attach_to(Con *ws) {
DLOG("Attaching a window to workspace %p / %s\n", ws, ws->name);
- if (config.default_layout == L_DEFAULT) {
+ if (ws->workspace_layout == L_DEFAULT) {
DLOG("Default layout, just attaching it to the workspace itself.\n");
return ws;
}
new->split = true;
/* 2: set the requested layout on the split con */
- new->layout = config.default_layout;
+ new->layout = ws->workspace_layout;
/* 4: attach the new split container to the workspace */
DLOG("Attaching new split %p to workspace %p\n", new, ws);
urgent => JSON::XS::false,
border => 'normal',
'floating_nodes' => $ignore,
+ workspace_layout => 'default',
};
# a shallow copy is sufficient, since we only ignore values at the root