]> git.sur5r.net Git - i3/i3/blobdiff - src/commands.c
Merge branch 'master' into next
[i3/i3] / src / commands.c
index 66270f7599fd8e406bd1d5ba93e39d3a73373acf..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;
     }
@@ -504,6 +519,8 @@ static bool cmd_resize_tiling_direction(I3_CMD, char *way, char *direction, int
     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 bool 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 false;
-    }
+        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 false;
     }
+
     LOG("other->percent = %f\n", other->percent);
     LOG("current->percent before = %f\n", current->percent);
     if (current->percent == 0.0)
@@ -585,7 +612,7 @@ static bool 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 */
@@ -594,7 +621,7 @@ static bool 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) ||
@@ -1226,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);
 }
 
 /*
@@ -1275,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;
         }
@@ -1376,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))
@@ -1403,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 */
@@ -1421,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 */
@@ -1449,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);