]> git.sur5r.net Git - i3/i3/blobdiff - src/commands.c
Close empty workspaces after cross-output move (+test) (Thanks chrysn)
[i3/i3] / src / commands.c
index 8875b8d2bd93b87fd8f0090aa928756e21176d9f..2bbde9bff08c75560c5c57ed13a054643dfad161 100644 (file)
@@ -57,19 +57,19 @@ static Output *get_output_from_string(Output *current_output, const char *output
     Output *output;
 
     if (strcasecmp(output_str, "left") == 0) {
-        output = get_output_next(D_LEFT, current_output);
+        output = get_output_next(D_LEFT, current_output, CLOSEST_OUTPUT);
         if (!output)
             output = get_output_most(D_RIGHT, current_output);
     } else if (strcasecmp(output_str, "right") == 0) {
-        output = get_output_next(D_RIGHT, current_output);
+        output = get_output_next(D_RIGHT, current_output, CLOSEST_OUTPUT);
         if (!output)
             output = get_output_most(D_LEFT, current_output);
     } else if (strcasecmp(output_str, "up") == 0) {
-        output = get_output_next(D_UP, current_output);
+        output = get_output_next(D_UP, current_output, CLOSEST_OUTPUT);
         if (!output)
             output = get_output_most(D_DOWN, current_output);
     } else if (strcasecmp(output_str, "down") == 0) {
-        output = get_output_next(D_DOWN, current_output);
+        output = get_output_next(D_DOWN, current_output, CLOSEST_OUTPUT);
         if (!output)
             output = get_output_most(D_UP, current_output);
     } else output = get_output_by_name(output_str);
@@ -99,6 +99,29 @@ static bool maybe_back_and_forth(struct CommandResult *cmd_output, char *name) {
     return true;
 }
 
+/*
+ * Return the passed workspace unless it is the current one and auto back and
+ * forth is enabled, in which case the back_and_forth workspace is returned.
+ */
+static Con *maybe_auto_back_and_forth_workspace(Con *workspace) {
+    Con *current, *baf;
+
+    if (!config.workspace_auto_back_and_forth)
+        return workspace;
+
+    current = con_get_workspace(focused);
+
+    if (current == workspace) {
+        baf = workspace_back_and_forth_get();
+        if (baf != NULL) {
+            DLOG("Substituting workspace with back_and_forth, as it is focused.\n");
+            return baf;
+        }
+    }
+
+    return workspace;
+}
+
 // This code is commented out because we might recycle it for popping up error
 // messages on parser errors.
 #if 0
@@ -400,6 +423,38 @@ void cmd_move_con_to_workspace(I3_CMD, char *which) {
     ysuccess(true);
 }
 
+/**
+ * Implementation of 'move [window|container] [to] workspace back_and_forth'.
+ *
+ */
+void cmd_move_con_to_workspace_back_and_forth(I3_CMD) {
+    owindow *current;
+    Con *ws;
+
+    ws = workspace_back_and_forth_get();
+
+    if (ws == NULL) {
+        y(map_open);
+        ystr("success");
+        y(bool, false);
+        ystr("error");
+        ystr("No workspace was previously active.");
+        y(map_close);
+        return;
+    }
+
+    HANDLE_EMPTY_MATCH;
+
+    TAILQ_FOREACH(current, &owindows, owindows) {
+        DLOG("matching: %p / %s\n", current->con, current->con->name);
+        con_move_to_workspace(current->con, ws, true, false);
+    }
+
+    cmd_output->needs_tree_render = true;
+    // XXX: default reply for now, make this a better reply
+    ysuccess(true);
+}
+
 /*
  * Implementation of 'move [window|container] [to] workspace <name>'.
  *
@@ -432,6 +487,8 @@ void cmd_move_con_to_workspace_name(I3_CMD, char *name) {
     /* get the workspace */
     Con *ws = workspace_get(name, NULL);
 
+    ws = maybe_auto_back_and_forth_workspace(ws);
+
     HANDLE_EMPTY_MATCH;
 
     TAILQ_FOREACH(current, &owindows, owindows) {
@@ -445,7 +502,7 @@ void cmd_move_con_to_workspace_name(I3_CMD, char *name) {
 }
 
 /*
- * Implementation of 'move [window|container] [to] workspace number <number>'.
+ * Implementation of 'move [window|container] [to] workspace number <name>'.
  *
  */
 void cmd_move_con_to_workspace_number(I3_CMD, char *which) {
@@ -469,8 +526,8 @@ void cmd_move_con_to_workspace_number(I3_CMD, char *which) {
     if (parsed_num == LONG_MIN ||
         parsed_num == LONG_MAX ||
         parsed_num < 0 ||
-        *endptr != '\0') {
-        LOG("Could not parse \"%s\" as a number.\n", which);
+        endptr == which) {
+        LOG("Could not parse initial part of \"%s\" as a number.\n", which);
         y(map_open);
         ystr("success");
         y(bool, false);
@@ -489,6 +546,8 @@ void cmd_move_con_to_workspace_number(I3_CMD, char *which) {
         workspace = workspace_get(which, NULL);
     }
 
+    workspace = maybe_auto_back_and_forth_workspace(workspace);
+
     HANDLE_EMPTY_MATCH;
 
     TAILQ_FOREACH(current, &owindows, owindows) {
@@ -807,7 +866,7 @@ void cmd_workspace(I3_CMD, char *which) {
 }
 
 /*
- * Implementation of 'workspace number <number>'
+ * Implementation of 'workspace number <name>'
  *
  */
 void cmd_workspace_number(I3_CMD, char *which) {
@@ -818,8 +877,8 @@ void cmd_workspace_number(I3_CMD, char *which) {
     if (parsed_num == LONG_MIN ||
         parsed_num == LONG_MAX ||
         parsed_num < 0 ||
-        *endptr != '\0') {
-        LOG("Could not parse \"%s\" as a number.\n", which);
+        endptr == which) {
+        LOG("Could not parse initial part of \"%s\" as a number.\n", which);
         y(map_open);
         ystr("success");
         y(bool, false);
@@ -838,15 +897,11 @@ void cmd_workspace_number(I3_CMD, char *which) {
     if (!workspace) {
         LOG("There is no workspace with number %ld, creating a new one.\n", parsed_num);
         ysuccess(true);
-        /* terminate the which string after the endposition of the number */
-        *endptr = '\0';
-        if (maybe_back_and_forth(cmd_output, which))
-            return;
         workspace_show_by_name(which);
         cmd_output->needs_tree_render = true;
         return;
     }
-    if (maybe_back_and_forth(cmd_output, which))
+    if (maybe_back_and_forth(cmd_output, workspace->name))
         return;
     workspace_show(workspace);
 
@@ -951,13 +1006,13 @@ void cmd_move_con_to_output(I3_CMD, char *name) {
 
     // TODO: clean this up with commands.spec as soon as we switched away from the lex/yacc command parser
     if (strcasecmp(name, "up") == 0)
-        output = get_output_next(D_UP, current_output);
+        output = get_output_next(D_UP, current_output, CLOSEST_OUTPUT);
     else if (strcasecmp(name, "down") == 0)
-        output = get_output_next(D_DOWN, current_output);
+        output = get_output_next(D_DOWN, current_output, CLOSEST_OUTPUT);
     else if (strcasecmp(name, "left") == 0)
-        output = get_output_next(D_LEFT, current_output);
+        output = get_output_next(D_LEFT, current_output, CLOSEST_OUTPUT);
     else if (strcasecmp(name, "right") == 0)
-        output = get_output_next(D_RIGHT, current_output);
+        output = get_output_next(D_RIGHT, current_output, CLOSEST_OUTPUT);
     else
         output = get_output_by_name(name);
 
@@ -1044,8 +1099,12 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) {
         Con *content = output_get_content(output->con);
         LOG("got output %p with content %p\n", output, content);
 
+        Con *previously_visible_ws = TAILQ_FIRST(&(content->nodes_head));
+        LOG("Previously visible workspace = %p / %s\n", previously_visible_ws, previously_visible_ws->name);
+
         Con *ws = con_get_workspace(current->con);
         LOG("should move workspace %p / %s\n", ws, ws->name);
+        bool workspace_was_visible = workspace_is_visible(ws);
 
         if (con_num_children(ws->parent) == 1) {
             LOG("Creating a new workspace to replace \"%s\" (last on its output).\n", ws->name);
@@ -1082,7 +1141,6 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) {
         }
 
         /* detach from the old output and attach to the new output */
-        bool workspace_was_visible = workspace_is_visible(ws);
         Con *old_content = ws->parent;
         con_detach(ws);
         if (workspace_was_visible) {
@@ -1104,6 +1162,11 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) {
             /* Focus the moved workspace on the destination output. */
             workspace_show(ws);
         }
+
+        /* Call the on_remove_child callback of the workspace which previously
+         * was visible on the destination output. Since it is no longer
+         * visible, it might need to get cleaned up. */
+        CALL(previously_visible_ws, on_remove_child);
     }
 
     cmd_output->needs_tree_render = true;
@@ -1116,9 +1179,17 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) {
  *
  */
 void cmd_split(I3_CMD, char *direction) {
+    owindow *current;
     /* TODO: use matches */
     LOG("splitting in direction %c\n", direction[0]);
-    tree_split(focused, (direction[0] == 'v' ? VERT : HORIZ));
+    if (match_is_empty(current_match))
+        tree_split(focused, (direction[0] == 'v' ? VERT : HORIZ));
+    else {
+        TAILQ_FOREACH(current, &owindows, owindows) {
+            DLOG("matching: %p / %s\n", current->con, current->con->name);
+            tree_split(current->con, (direction[0] == 'v' ? VERT : HORIZ));
+        }
+    }
 
     cmd_output->needs_tree_render = true;
     // XXX: default reply for now, make this a better reply
@@ -1431,7 +1502,7 @@ void cmd_layout(I3_CMD, char *layout_str) {
 
     /* check if the match is empty, not if the result is empty */
     if (match_is_empty(current_match))
-        con_set_layout(focused->parent, layout);
+        con_set_layout(focused, layout);
     else {
         TAILQ_FOREACH(current, &owindows, owindows) {
             DLOG("matching: %p / %s\n", current->con, current->con->name);
@@ -1458,7 +1529,7 @@ void cmd_layout_toggle(I3_CMD, char *toggle_mode) {
 
     /* check if the match is empty, not if the result is empty */
     if (match_is_empty(current_match))
-        con_toggle_layout(focused->parent, toggle_mode);
+        con_toggle_layout(focused, toggle_mode);
     else {
         TAILQ_FOREACH(current, &owindows, owindows) {
             DLOG("matching: %p / %s\n", current->con, current->con->name);