]> git.sur5r.net Git - i3/i3/blobdiff - src/commands.c
Merge branch 'master' into next
[i3/i3] / src / commands.c
index 535324359dddc5703c80a13767ff9b54b8de7ddc..538e2dbc617fe87f8980fdbde66bb0bff1a4d3e7 100644 (file)
@@ -38,7 +38,6 @@
     } \
 } while (0)
 
-static owindows_head owindows;
 
 /*
  * Returns true if a is definitely greater than b (using the given epsilon)
@@ -56,23 +55,15 @@ static bool definitelyGreaterThan(float a, float b, float epsilon) {
 static Output *get_output_from_string(Output *current_output, const char *output_str) {
     Output *output;
 
-    if (strcasecmp(output_str, "left") == 0) {
-        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, 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, 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, CLOSEST_OUTPUT);
-        if (!output)
-            output = get_output_most(D_UP, current_output);
-    } else output = get_output_by_name(output_str);
+    if (strcasecmp(output_str, "left") == 0)
+        output = get_output_next_wrap(D_LEFT, current_output);
+    else if (strcasecmp(output_str, "right") == 0)
+        output = get_output_next_wrap(D_RIGHT, current_output);
+    else if (strcasecmp(output_str, "up") == 0)
+        output = get_output_next_wrap(D_UP, current_output);
+    else if (strcasecmp(output_str, "down") == 0)
+        output = get_output_next_wrap(D_DOWN, current_output);
+    else output = get_output_by_name(output_str);
 
     return output;
 }
@@ -222,6 +213,20 @@ void cmd_MIGRATION_start_nagbar(void) {
  * Criteria functions.
  ******************************************************************************/
 
+/*
+ * Helper data structure for an operation window (window on which the operation
+ * will be performed). Used to build the TAILQ owindows.
+ *
+ */
+typedef struct owindow {
+    Con *con;
+    TAILQ_ENTRY(owindow) owindows;
+} owindow;
+
+typedef TAILQ_HEAD(owindows_head, owindow) owindows_head;
+
+static owindows_head owindows;
+
 /*
  * Initializes the specified 'Match' data structure and the initial state of
  * commands.c for matching target windows of a command.
@@ -389,7 +394,7 @@ void cmd_move_con_to_workspace(I3_CMD, char *which) {
      *  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 &&
-        con_is_leaf(focused))) {
+        !con_has_children(focused))) {
         ysuccess(false);
         return;
     }
@@ -478,7 +483,7 @@ void cmd_move_con_to_workspace_name(I3_CMD, char *name) {
         return;
     }
     else if (match_is_empty(current_match) && focused->type == CT_WORKSPACE &&
-        con_is_leaf(focused)) {
+        !con_has_children(focused)) {
         ysuccess(false);
         return;
     }
@@ -513,7 +518,7 @@ void cmd_move_con_to_workspace_number(I3_CMD, char *which) {
      *  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 &&
-        con_is_leaf(focused))) {
+        !con_has_children(focused))) {
         ysuccess(false);
         return;
     }
@@ -563,17 +568,51 @@ void cmd_move_con_to_workspace_number(I3_CMD, char *which) {
 
 static void cmd_resize_floating(I3_CMD, char *way, char *direction, Con *floating_con, int px) {
     LOG("floating resize\n");
+    Rect old_rect = floating_con->rect;
+    Con *focused_con = con_descend_focused(floating_con);
+
+    /* ensure that resize will take place even if pixel increment is smaller than
+     * height increment or width increment.
+     * fixes #1011 */
+    if (strcmp(direction, "up") == 0 || strcmp(direction, "down") == 0 ||
+        strcmp(direction, "height") == 0) {
+        if (px < 0)
+            px = (-px < focused_con->height_increment) ? -focused_con->height_increment : px;
+        else
+            px = (px < focused_con->height_increment) ? focused_con->height_increment : px;
+    } else if (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0) {
+        if (px < 0)
+            px = (-px < focused_con->width_increment) ? -focused_con->width_increment : px;
+        else
+            px = (px < focused_con->width_increment) ? focused_con->width_increment : px;
+    }
+
     if (strcmp(direction, "up") == 0) {
-        floating_con->rect.y -= px;
         floating_con->rect.height += px;
     } else if (strcmp(direction, "down") == 0 || strcmp(direction, "height") == 0) {
         floating_con->rect.height += px;
     } else if (strcmp(direction, "left") == 0) {
-        floating_con->rect.x -= px;
         floating_con->rect.width += px;
     } else {
         floating_con->rect.width += px;
     }
+
+    floating_check_size(floating_con);
+
+    /* Did we actually resize anything or did the size constraints prevent us?
+     * If we could not resize, exit now to not move the window. */
+    if (memcmp(&old_rect, &(floating_con->rect), sizeof(Rect)) == 0)
+        return;
+
+    if (strcmp(direction, "up") == 0) {
+        floating_con->rect.y -= (floating_con->rect.height - old_rect.height);
+    } else if (strcmp(direction, "left") == 0) {
+        floating_con->rect.x -= (floating_con->rect.width - old_rect.width);
+    }
+
+    /* If this is a scratchpad window, don't auto center it from now on. */
+    if (floating_con->scratchpad_state == SCRATCHPAD_FRESH)
+        floating_con->scratchpad_state = SCRATCHPAD_CHANGED;
 }
 
 static bool cmd_resize_tiling_direction(I3_CMD, Con *current, char *way, char *direction, int ppt) {
@@ -1026,13 +1065,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, CLOSEST_OUTPUT);
+        output = get_output_next_wrap(D_UP, current_output);
     else if (strcasecmp(name, "down") == 0)
-        output = get_output_next(D_DOWN, current_output, CLOSEST_OUTPUT);
+        output = get_output_next_wrap(D_DOWN, current_output);
     else if (strcasecmp(name, "left") == 0)
-        output = get_output_next(D_LEFT, current_output, CLOSEST_OUTPUT);
+        output = get_output_next_wrap(D_LEFT, current_output);
     else if (strcasecmp(name, "right") == 0)
-        output = get_output_next(D_RIGHT, current_output, CLOSEST_OUTPUT);
+        output = get_output_next_wrap(D_RIGHT, current_output);
     else
         output = get_output_by_name(name);
 
@@ -1229,7 +1268,7 @@ void cmd_split(I3_CMD, char *direction) {
 }
 
 /*
- * Implementaiton of 'kill [window|client]'.
+ * Implementation of 'kill [window|client]'.
  *
  */
 void cmd_kill(I3_CMD, char *kill_mode_str) {
@@ -1284,14 +1323,6 @@ void cmd_exec(I3_CMD, char *nosn, char *command) {
  *
  */
 void cmd_focus_direction(I3_CMD, char *direction) {
-    if (focused &&
-        focused->type != CT_WORKSPACE &&
-        focused->fullscreen_mode != CF_NONE) {
-        LOG("Cannot change focus while in fullscreen mode.\n");
-        ysuccess(false);
-        return;
-    }
-
     DLOG("direction = *%s*\n", direction);
 
     if (strcmp(direction, "left") == 0)
@@ -1318,14 +1349,6 @@ void cmd_focus_direction(I3_CMD, char *direction) {
  *
  */
 void cmd_focus_window_mode(I3_CMD, char *window_mode) {
-    if (focused &&
-        focused->type != CT_WORKSPACE &&
-        focused->fullscreen_mode != CF_NONE) {
-        LOG("Cannot change focus while in fullscreen mode.\n");
-        ysuccess(false);
-        return;
-    }
-
     DLOG("window_mode = %s\n", window_mode);
 
     Con *ws = con_get_workspace(focused);
@@ -1400,6 +1423,7 @@ void cmd_focus(I3_CMD) {
         return;
     }
 
+    Con *__i3_scratch = workspace_get("__i3_scratch", NULL);
     int count = 0;
     owindow *current;
     TAILQ_FOREACH(current, &owindows, owindows) {
@@ -1416,6 +1440,16 @@ void cmd_focus(I3_CMD) {
             return;
         }
 
+        /* In case this is a scratchpad window, call scratchpad_show(). */
+        if (ws == __i3_scratch) {
+            scratchpad_show(current->con);
+            count++;
+            /* While for the normal focus case we can change focus multiple
+             * times and only a single window ends up focused, we could show
+             * multiple scratchpad windows. So, rather break here. */
+            break;
+        }
+
         /* If the container is not on the current workspace,
          * workspace_show() will switch to a different workspace and (if
          * enabled) trigger a mouse pointer warp to the currently focused
@@ -1575,7 +1609,7 @@ void cmd_layout_toggle(I3_CMD, char *toggle_mode) {
 }
 
 /*
- * Implementaiton of 'exit'.
+ * Implementation of 'exit'.
  *
  */
 void cmd_exit(I3_CMD) {
@@ -1587,13 +1621,13 @@ void cmd_exit(I3_CMD) {
 }
 
 /*
- * Implementaiton of 'reload'.
+ * Implementation of 'reload'.
  *
  */
 void cmd_reload(I3_CMD) {
     LOG("reloading\n");
-    kill_configerror_nagbar(false);
-    kill_commanderror_nagbar(false);
+    kill_nagbar(&config_error_nagbar_pid, false);
+    kill_nagbar(&command_error_nagbar_pid, false);
     load_configuration(conn, NULL, true);
     x_set_i3_atoms();
     /* Send an IPC event just in case the ws names have changed */
@@ -1604,7 +1638,7 @@ void cmd_reload(I3_CMD) {
 }
 
 /*
- * Implementaiton of 'restart'.
+ * Implementation of 'restart'.
  *
  */
 void cmd_restart(I3_CMD) {
@@ -1616,7 +1650,7 @@ void cmd_restart(I3_CMD) {
 }
 
 /*
- * Implementaiton of 'open'.
+ * Implementation of 'open'.
  *
  */
 void cmd_open(I3_CMD) {
@@ -1805,16 +1839,24 @@ void cmd_scratchpad_show(I3_CMD) {
 }
 
 /*
- * Implementation of 'rename workspace <name> to <name>'
+ * Implementation of 'rename workspace [<name>] to <name>'
  *
  */
 void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) {
-    LOG("Renaming workspace \"%s\" to \"%s\"\n", old_name, new_name);
+    if (old_name) {
+        LOG("Renaming workspace \"%s\" to \"%s\"\n", old_name, new_name);
+    } else {
+        LOG("Renaming current workspace to \"%s\"\n", new_name);
+    }
 
     Con *output, *workspace = NULL;
-    TAILQ_FOREACH(output, &(croot->nodes_head), nodes)
-        GREP_FIRST(workspace, output_get_content(output),
-            !strcasecmp(child->name, old_name));
+    if (old_name) {
+        TAILQ_FOREACH(output, &(croot->nodes_head), nodes)
+            GREP_FIRST(workspace, output_get_content(output),
+                !strcasecmp(child->name, old_name));
+    } else {
+        workspace = con_get_workspace(focused);
+    }
 
     if (!workspace) {
         // TODO: we should include the old workspace name here and use yajl for