]> git.sur5r.net Git - i3/i3/blobdiff - src/commands.c
Merge branch 'master' into next
[i3/i3] / src / commands.c
index 1e1ee0ff243190aafa4d9f2a8e34256702618a4c..44e6a23d4533f275b6ddffd15c96dd905c3899ea 100644 (file)
@@ -23,7 +23,7 @@
 } while (0)
 
 /** When the command did not include match criteria (!), we use the currently
- * focused command. Do not confuse this case with a command which included
+ * focused container. Do not confuse this case with a command which included
  * criteria but which did not match any windows. This macro has to be called in
  * every command.
  */
@@ -351,7 +351,7 @@ void cmd_criteria_add(I3_CMD, char *ctype, char *cvalue) {
 
 /*
  * Implementation of 'move [window|container] [to] workspace
- * next|prev|next_on_output|prev_on_output'.
+ * next|prev|next_on_output|prev_on_output|current'.
  *
  */
 void cmd_move_con_to_workspace(I3_CMD, char *which) {
@@ -359,6 +359,15 @@ void cmd_move_con_to_workspace(I3_CMD, char *which) {
 
     DLOG("which=%s\n", which);
 
+    /* We have nothing to move:
+     *  when criteria was specified but didn't match any window or
+     *  when criteria wasn't specified and we don't have any window focused. */
+    if ((!match_is_empty(current_match) && TAILQ_EMPTY(&owindows)) ||
+        (match_is_empty(current_match) && focused->type == CT_WORKSPACE)) {
+        ysuccess(false);
+        return;
+    }
+
     HANDLE_EMPTY_MATCH;
 
     /* get the workspace */
@@ -371,6 +380,8 @@ void cmd_move_con_to_workspace(I3_CMD, char *which) {
         ws = workspace_next_on_output();
     else if (strcmp(which, "prev_on_output") == 0)
         ws = workspace_prev_on_output();
+    else if (strcmp(which, "current") == 0)
+        ws = con_get_workspace(focused);
     else {
         ELOG("BUG: called with which=%s\n", which);
         ysuccess(false);
@@ -400,9 +411,11 @@ void cmd_move_con_to_workspace_name(I3_CMD, char *name) {
 
     owindow *current;
 
-    /* Error out early to not create a non-existing workspace (in
-     * workspace_get()) if we are not actually able to move anything. */
-    if (match_is_empty(current_match) && focused->type == CT_WORKSPACE) {
+    /* We have nothing to move:
+     *  when criteria was specified but didn't match any window or
+     *  when criteria wasn't specified and we don't have any window focused. */
+    if ((!match_is_empty(current_match) && TAILQ_EMPTY(&owindows)) ||
+        (match_is_empty(current_match) && focused->type == CT_WORKSPACE)) {
         ysuccess(false);
         return;
     }
@@ -430,9 +443,11 @@ void cmd_move_con_to_workspace_name(I3_CMD, char *name) {
 void cmd_move_con_to_workspace_number(I3_CMD, char *which) {
     owindow *current;
 
-    /* Error out early to not create a non-existing workspace (in
-     * workspace_get()) if we are not actually able to move anything. */
-    if (match_is_empty(current_match) && focused->type == CT_WORKSPACE) {
+    /* We have nothing to move:
+     *  when criteria was specified but didn't match any window or
+     *  when criteria wasn't specified and we don't have any window focused. */
+    if ((!match_is_empty(current_match) && TAILQ_EMPTY(&owindows)) ||
+        (match_is_empty(current_match) && focused->type == CT_WORKSPACE)) {
         ysuccess(false);
         return;
     }
@@ -500,10 +515,12 @@ static void cmd_resize_floating(I3_CMD, char *way, char *direction, Con *floatin
     }
 }
 
-static void cmd_resize_tiling_direction(I3_CMD, char *way, char *direction, int ppt) {
+static bool cmd_resize_tiling_direction(I3_CMD, char *way, char *direction, int ppt) {
     LOG("tiling resize\n");
     /* get the appropriate current container (skip stacked/tabbed cons) */
     Con *current = focused;
+    Con *other = NULL;
+    double percentage = 0;
     while (current->parent->layout == L_STACKED ||
            current->parent->layout == L_TABBED)
         current = current->parent;
@@ -512,40 +529,50 @@ static void cmd_resize_tiling_direction(I3_CMD, char *way, char *direction, int
     orientation_t search_orientation =
         (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0 ? HORIZ : VERT);
 
-    while (current->type != CT_WORKSPACE &&
-           current->type != CT_FLOATING_CON &&
-           current->parent->orientation != search_orientation)
-        current = current->parent;
+    do {
+        if (con_orientation(current->parent) != search_orientation) {
+            current = current->parent;
+            continue;
+        }
 
-    /* get the default percentage */
-    int children = con_num_children(current->parent);
-    Con *other;
-    LOG("ins. %d children\n", children);
-    double percentage = 1.0 / children;
-    LOG("default percentage = %f\n", percentage);
+        /* get the default percentage */
+        int children = con_num_children(current->parent);
+        LOG("ins. %d children\n", children);
+        percentage = 1.0 / children;
+        LOG("default percentage = %f\n", percentage);
 
-    orientation_t orientation = current->parent->orientation;
+        orientation_t orientation = con_orientation(current->parent);
 
-    if ((orientation == HORIZ &&
-         (strcmp(direction, "up") == 0 || strcmp(direction, "down") == 0)) ||
-        (orientation == VERT &&
-         (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0))) {
-        LOG("You cannot resize in that direction. Your focus is in a %s split container currently.\n",
-            (orientation == HORIZ ? "horizontal" : "vertical"));
-        ysuccess(false);
-        return;
-    }
+        if ((orientation == HORIZ &&
+             (strcmp(direction, "up") == 0 || strcmp(direction, "down") == 0)) ||
+            (orientation == VERT &&
+             (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0))) {
+            LOG("You cannot resize in that direction. Your focus is in a %s split container currently.\n",
+                (orientation == HORIZ ? "horizontal" : "vertical"));
+            ysuccess(false);
+            return false;
+        }
 
-    if (strcmp(direction, "up") == 0 || strcmp(direction, "left") == 0) {
-        other = TAILQ_PREV(current, nodes_head, nodes);
-    } else {
-        other = TAILQ_NEXT(current, nodes);
-    }
-    if (other == TAILQ_END(workspaces)) {
-        LOG("No other container in this direction found, cannot resize.\n");
+        if (strcmp(direction, "up") == 0 || strcmp(direction, "left") == 0) {
+            other = TAILQ_PREV(current, nodes_head, nodes);
+        } else {
+            other = TAILQ_NEXT(current, nodes);
+        }
+        if (other == TAILQ_END(workspaces)) {
+            LOG("No other container in this direction found, trying to look further up in the tree...\n");
+            current = current->parent;
+            continue;
+        }
+        break;
+    } while (current->type != CT_WORKSPACE &&
+             current->type != CT_FLOATING_CON);
+
+    if (other == NULL) {
+        LOG("No other container in this direction found, trying to look further up in the tree...\n");
         ysuccess(false);
-        return;
+        return false;
     }
+
     LOG("other->percent = %f\n", other->percent);
     LOG("current->percent before = %f\n", current->percent);
     if (current->percent == 0.0)
@@ -567,9 +594,11 @@ static void cmd_resize_tiling_direction(I3_CMD, char *way, char *direction, int
     } else {
         LOG("Not resizing, already at minimum size\n");
     }
+
+    return true;
 }
 
-static void cmd_resize_tiling_width_height(I3_CMD, char *way, char *direction, int ppt) {
+static bool cmd_resize_tiling_width_height(I3_CMD, char *way, char *direction, int ppt) {
     LOG("width/height resize\n");
     /* get the appropriate current container (skip stacked/tabbed cons) */
     Con *current = focused;
@@ -583,7 +612,7 @@ static void cmd_resize_tiling_width_height(I3_CMD, char *way, char *direction, i
 
     while (current->type != CT_WORKSPACE &&
            current->type != CT_FLOATING_CON &&
-           current->parent->orientation != search_orientation)
+           con_orientation(current->parent) != search_orientation)
         current = current->parent;
 
     /* get the default percentage */
@@ -592,7 +621,7 @@ static void cmd_resize_tiling_width_height(I3_CMD, char *way, char *direction, i
     double percentage = 1.0 / children;
     LOG("default percentage = %f\n", percentage);
 
-    orientation_t orientation = current->parent->orientation;
+    orientation_t orientation = con_orientation(current->parent);
 
     if ((orientation == HORIZ &&
          strcmp(direction, "height") == 0) ||
@@ -601,13 +630,13 @@ static void cmd_resize_tiling_width_height(I3_CMD, char *way, char *direction, i
         LOG("You cannot resize in that direction. Your focus is in a %s split container currently.\n",
             (orientation == HORIZ ? "horizontal" : "vertical"));
         ysuccess(false);
-        return;
+        return false;
     }
 
     if (children == 1) {
         LOG("This is the only container, cannot resize.\n");
         ysuccess(false);
-        return;
+        return false;
     }
 
     /* Ensure all the other children have a percentage set. */
@@ -630,13 +659,13 @@ static void cmd_resize_tiling_width_height(I3_CMD, char *way, char *direction, i
         if (!definitelyGreaterThan(child->percent - subtract_percent, 0.05, DBL_EPSILON)) {
             LOG("Not resizing, already at minimum size (child %p would end up with a size of %.f\n", child, child->percent - subtract_percent);
             ysuccess(false);
-            return;
+            return false;
         }
     }
     if (!definitelyGreaterThan(new_current_percent, 0.05, DBL_EPSILON)) {
         LOG("Not resizing, already at minimum size\n");
         ysuccess(false);
-        return;
+        return false;
     }
 
     current->percent += ((double)ppt / 100.0);
@@ -648,6 +677,8 @@ static void cmd_resize_tiling_width_height(I3_CMD, char *way, char *direction, i
         child->percent -= subtract_percent;
         LOG("child->percent after (%p) = %f\n", child, child->percent);
     }
+
+    return true;
 }
 
 /*
@@ -670,9 +701,13 @@ void cmd_resize(I3_CMD, char *way, char *direction, char *resize_px, char *resiz
         cmd_resize_floating(current_match, cmd_output, way, direction, floating_con, px);
     } else {
         if (strcmp(direction, "width") == 0 ||
-            strcmp(direction, "height") == 0)
-            cmd_resize_tiling_width_height(current_match, cmd_output, way, direction, ppt);
-        else cmd_resize_tiling_direction(current_match, cmd_output, way, direction, ppt);
+            strcmp(direction, "height") == 0) {
+            if (!cmd_resize_tiling_width_height(current_match, cmd_output, way, direction, ppt))
+                return;
+        } else {
+            if (!cmd_resize_tiling_direction(current_match, cmd_output, way, direction, ppt))
+                return;
+        }
     }
 
     cmd_output->needs_tree_render = true;
@@ -993,9 +1028,14 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) {
     TAILQ_FOREACH(current, &owindows, owindows) {
         Output *current_output = get_output_containing(current->con->rect.x,
                                                        current->con->rect.y);
+        if (!current_output) {
+            ELOG("Cannot get current output. This is a bug in i3.\n");
+            ysuccess(false);
+            return;
+        }
         Output *output = get_output_from_string(current_output, name);
         if (!output) {
-            LOG("No such output\n");
+            ELOG("Could not get output from string \"%s\"\n", name);
             ysuccess(false);
             return;
         }
@@ -1213,23 +1253,26 @@ void cmd_focus_window_mode(I3_CMD, char *window_mode) {
  *
  */
 void cmd_focus_level(I3_CMD, char *level) {
-    if (focused &&
-        focused->type != CT_WORKSPACE &&
-        focused->fullscreen_mode != CF_NONE) {
-        LOG("Cannot change focus while in fullscreen mode.\n");
-        ysuccess(false);
-        return;
-    }
-
     DLOG("level = %s\n", level);
+    bool success = false;
+
+    /* Focusing the parent can only be allowed if the newly
+     * focused container won't escape the fullscreen container. */
+    if (strcmp(level, "parent") == 0) {
+        if (focused && focused->parent) {
+            if (con_fullscreen_permits_focusing(focused->parent))
+                success = level_up();
+            else
+                LOG("Currently in fullscreen, not going up\n");
+        }
+    }
 
-    if (strcmp(level, "parent") == 0)
-        level_up();
-    else level_down();
+    /* Focusing a child should always be allowed. */
+    else success = level_down();
 
-    cmd_output->needs_tree_render = true;
+    cmd_output->needs_tree_render = success;
     // XXX: default reply for now, make this a better reply
-    ysuccess(true);
+    ysuccess(success);
 }
 
 /*
@@ -1262,13 +1305,9 @@ void cmd_focus(I3_CMD) {
         if (!ws)
             continue;
 
-        /* Don't allow the focus switch if the focused and current
-         * containers are in the same workspace. */
-        if (focused &&
-            focused->type != CT_WORKSPACE &&
-            focused->fullscreen_mode != CF_NONE &&
-            con_get_workspace(focused) == ws) {
-            LOG("Cannot change focus while in fullscreen mode (same workspace).\n");
+        /* Check the fullscreen focus constraints. */
+        if (!con_fullscreen_permits_focusing(current->con)) {
+            LOG("Cannot change focus while in fullscreen mode (fullscreen rules).\n");
             ysuccess(false);
             return;
         }
@@ -1363,17 +1402,27 @@ void cmd_move_direction(I3_CMD, char *direction, char *move_px) {
 }
 
 /*
- * Implementation of 'layout default|stacked|stacking|tabbed'.
+ * Implementation of 'layout default|stacked|stacking|tabbed|splitv|splith'.
  *
  */
 void cmd_layout(I3_CMD, char *layout_str) {
     if (strcmp(layout_str, "stacking") == 0)
         layout_str = "stacked";
-    DLOG("changing layout to %s\n", layout_str);
     owindow *current;
-    int layout = (strcmp(layout_str, "default") == 0 ? L_DEFAULT :
-                  (strcmp(layout_str, "stacked") == 0 ? L_STACKED :
-                   L_TABBED));
+    int layout;
+    /* default is a special case which will be handled in con_set_layout(). */
+    if (strcmp(layout_str, "default") == 0)
+        layout = L_DEFAULT;
+    else if (strcmp(layout_str, "stacked") == 0)
+        layout = L_STACKED;
+    else if (strcmp(layout_str, "tabbed") == 0)
+        layout = L_TABBED;
+    else if (strcmp(layout_str, "splitv") == 0)
+        layout = L_SPLITV;
+    else if (strcmp(layout_str, "splith") == 0)
+        layout = L_SPLITH;
+
+    DLOG("changing layout to %s (%d)\n", layout_str, layout);
 
     /* check if the match is empty, not if the result is empty */
     if (match_is_empty(current_match))
@@ -1390,12 +1439,40 @@ void cmd_layout(I3_CMD, char *layout_str) {
     ysuccess(true);
 }
 
+/*
+ * Implementation of 'layout toggle [all|split]'.
+ *
+ */
+void cmd_layout_toggle(I3_CMD, char *toggle_mode) {
+    owindow *current;
+
+    if (toggle_mode == NULL)
+        toggle_mode = "default";
+
+    DLOG("toggling layout (mode = %s)\n", 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);
+    else {
+        TAILQ_FOREACH(current, &owindows, owindows) {
+            DLOG("matching: %p / %s\n", current->con, current->con->name);
+            con_toggle_layout(current->con, toggle_mode);
+        }
+    }
+
+    cmd_output->needs_tree_render = true;
+    // XXX: default reply for now, make this a better reply
+    ysuccess(true);
+}
+
 /*
  * Implementaiton of 'exit'.
  *
  */
 void cmd_exit(I3_CMD) {
     LOG("Exiting due to user command.\n");
+    xcb_disconnect(conn);
     exit(0);
 
     /* unreached */
@@ -1408,6 +1485,7 @@ void cmd_exit(I3_CMD) {
 void cmd_reload(I3_CMD) {
     LOG("reloading\n");
     kill_configerror_nagbar(false);
+    kill_commanderror_nagbar(false);
     load_configuration(conn, NULL, true);
     x_set_i3_atoms();
     /* Send an IPC event just in case the ws names have changed */
@@ -1436,6 +1514,7 @@ void cmd_restart(I3_CMD) {
 void cmd_open(I3_CMD) {
     LOG("opening new container\n");
     Con *con = tree_open_con(NULL, NULL);
+    con->layout = L_SPLITH;
     con_focus(con);
 
     y(map_open);