From c8d4eb3feff03fbd6d7d150e3fa29e2bbd016dab Mon Sep 17 00:00:00 2001
From: Daniel Mueller <deso@posteo.net>
Date: Fri, 29 Sep 2017 21:16:48 -0700
Subject: [PATCH 02/14] Create lower number workspaces as needed

It is very annoying that when switching to a workspace that this
workspace is created if it does not exist but not the ones with a lower
number.
This change adds a new function, workspace_select, that can be used
instead of workspace_show_by_name, for example, to show a workspace,
creating it and its lower number peers if necessary.
---
 include/workspace.h |  6 ++++++
 src/commands.c      |  9 ++++++---
 src/workspace.c     | 36 ++++++++++++++++++++++++++++++++++++
 3 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/include/workspace.h b/include/workspace.h
index 0b8304..2b29ab 100644
--- a/include/workspace.h
+++ b/include/workspace.h
@@ -186,3 +186,9 @@ Con *workspace_encapsulate(Con *ws);
  *
  */
 void workspace_move_to_output(Con *ws, Output *output);
+
+/**
+ * Select the workspace with the given number, automatically creating
+ * workspaces with lower numbers.
+ */
+Con *workspace_select(const char *num);
diff --git a/src/commands.c b/src/commands.c
index b421ab..c09b2d 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -323,7 +323,7 @@ void cmd_move_con_to_workspace_name(I3_CMD, const char *name, const char *no_aut
 
     LOG("should move window to workspace %s\n", name);
     /* get the workspace */
-    Con *ws = workspace_get(name);
+    Con *ws = workspace_select(name);
 
     if (no_auto_back_and_forth == NULL) {
         ws = maybe_auto_back_and_forth_workspace(ws);
@@ -872,7 +872,8 @@ void cmd_workspace_number(I3_CMD, const char *which, const char *no_auto_back_an
     if (!workspace) {
         LOG("There is no workspace with number %ld, creating a new one.\n", parsed_num);
         ysuccess(true);
-        workspace_show_by_name(which);
+        workspace = workspace_select(which);
+        workspace_show(workspace);
         cmd_output->needs_tree_render = true;
         return;
     }
@@ -907,6 +908,7 @@ void cmd_workspace_back_and_forth(I3_CMD) {
  */
 void cmd_workspace_name(I3_CMD, const char *name, const char *no_auto_back_and_forth_str) {
     const bool no_auto_back_and_forth = (no_auto_back_and_forth_str != NULL);
+    Con *workspace;
 
     if (strncasecmp(name, "__", strlen("__")) == 0) {
         yerror("You cannot switch to the i3-internal workspaces (\"%s\").", name);
@@ -920,7 +922,8 @@ void cmd_workspace_name(I3_CMD, const char *name, const char *no_auto_back_and_f
         ysuccess(true);
         return;
     }
-    workspace_show_by_name(name);
+    workspace = workspace_select(name);
+    workspace_show(workspace);
 
     cmd_output->needs_tree_render = true;
     // XXX: default reply for now, make this a better reply
diff --git a/src/workspace.c b/src/workspace.c
index 67dcd3..bda067 100644
--- a/src/workspace.c
+++ b/src/workspace.c
@@ -1131,3 +1131,39 @@ void workspace_move_to_output(Con *ws, Output *output) {
         break;
     }
 }
+
+Con *workspace_select(const char *num) {
+    bool created = (get_existing_workspace_by_name(num) == NULL);
+    Con *workspace = workspace_get(num);
+
+    /* If the workspace already exists we simply use it. */
+    if (!created) {
+        return workspace;
+    }
+
+    for (long num = workspace->num - 1; num >= 1 && created; num -= 1) {
+        int result;
+        /* 99 workspaces ought to be enough. */
+        char num_str[3];
+
+        /*
+         * It is very unfortunate that workspace_get works with string
+         * representations of numbers but that's what we have...
+         */
+        result = snprintf(num_str, sizeof(num_str), "%ld", num);
+        if (result >= sizeof(num_str)) {
+            ELOG("Workspace number too big: %ld\n", num);
+            /* Ups, that will make boom somewhere. */
+            return NULL;
+        }
+
+        /*
+         * Note that ideally we would batch create the workspaces here which
+         * would save us all those unnecessary calls to ewmh_update_*. But given
+         * the expected low frequency of those creations we should be fine.
+         */
+        created = (get_existing_workspace_by_name(num_str) == NULL);
+        (void)workspace_get(num_str);
+    }
+    return workspace;
+}
-- 
2.52.0

