]> git.sur5r.net Git - i3/i3/commitdiff
Allow changing the layout of workspaces by storing it (Thanks mhcerri)
authorMichael Stapelberg <michael@stapelberg.de>
Sun, 16 Sep 2012 20:53:41 +0000 (22:53 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Sun, 16 Sep 2012 20:53:41 +0000 (22:53 +0200)
Before commit 4976fa33504907510f1ee9e44884c116af0d801b, setting the
layout of workspaces to something else than the default would just mess
up the parent container of the workspace (the content container).

After that commit, it would create an unnecessary split container when
you change the layout _before_ opening any containers. To avoid this, we
now store the layout (similar to how the 'workspace_layout'
configuration directive works) and apply it when the first container is
attached to the workspace.

Fixes #796

include/data.h
src/con.c
src/ipc.c
src/load_layout.c
src/workspace.c
testcases/t/116-nestedcons.t

index e8df78c7e65f5bc2d36aab4b36525f7d45a9c805..02f781c9356e0e06fb3ec8eb5bd56e2c53f5551e 100644 (file)
@@ -514,6 +514,20 @@ struct Con {
     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,
@@ -522,7 +536,7 @@ struct Con {
         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
index 1d86d73a9825f44d7cdb8ca7e98efcd4ad857e8d..f5ccfcddbed5b541566c12e80eb59cb7bfa9c404 100644 (file)
--- a/src/con.c
+++ b/src/con.c
@@ -135,7 +135,7 @@ void con_attach(Con *con, Con *parent, bool ignore_focus) {
          */
         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);
 
@@ -1105,39 +1105,43 @@ void con_set_layout(Con *con, int layout) {
      * 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;
     }
 
index 1c6de798803bf2f0b729558aef819f523448077e..7dfbc8713c19c9e44295441f880bf21350f7f504 100644 (file)
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -231,6 +231,23 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
             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:
index 795fb6d8ce516e86ecb9e40df40751bdae09b4a8..cce1a7127da9f660d4282e52cb8d521e743d6fa3 100644 (file)
@@ -211,6 +211,17 @@ static int json_string(void *ctx, const unsigned char *val, unsigned int len) {
                 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);
index 1749959aa20c9c416fa8dde3b57b1235a43ef67d..94efd47b6e2455cf0151f7a41b0366d9022aeed8 100644 (file)
@@ -73,6 +73,7 @@ Con *workspace_get(const char *num, bool *created) {
         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;
@@ -742,7 +743,7 @@ void ws_force_orientation(Con *ws, orientation_t orientation) {
 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;
     }
@@ -754,7 +755,7 @@ Con *workspace_attach_to(Con *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);
index 794473861f41af4b70e90fccb3a5c94933b0f0d0..70008801261c078d7433cd1784e729670e7146f2 100644 (file)
@@ -68,6 +68,7 @@ my $expected = {
     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