]> git.sur5r.net Git - i3/i3/blobdiff - src/commands.c
Make cmd_resize_tiling_direction work with pixels
[i3/i3] / src / commands.c
index e023cd8f8632dc1ad8bf1d3eeb3950b419f07657..99c5368e0d7fc8ba647d3d659a0a06cbcf0f056c 100644 (file)
@@ -419,107 +419,101 @@ void cmd_move_con_to_workspace_number(I3_CMD, const char *which, const char *_no
     ysuccess(true);
 }
 
-static void cmd_resize_floating(I3_CMD, const char *way, const char *direction, Con *floating_con, int px) {
-    LOG("floating resize\n");
+/*
+ * Convert a string direction ("left", "right", etc.) to a direction_t. Assumes
+ * valid direction string.
+ */
+static direction_t parse_direction(const char *str) {
+    if (strcmp(str, "left") == 0) {
+        return D_LEFT;
+    } else if (strcmp(str, "right") == 0) {
+        return D_RIGHT;
+    } else if (strcmp(str, "up") == 0) {
+        return D_UP;
+    } else if (strcmp(str, "down") == 0) {
+        return D_DOWN;
+    } else {
+        ELOG("Invalid direction. This is a parser bug.\n");
+        assert(false);
+    }
+}
+
+static void cmd_resize_floating(I3_CMD, const char *way, const char *direction_str, Con *floating_con, int px) {
     Rect old_rect = floating_con->rect;
     Con *focused_con = con_descend_focused(floating_con);
 
+    direction_t direction;
+    if (strcmp(direction_str, "height") == 0) {
+        direction = D_DOWN;
+    } else if (strcmp(direction_str, "width") == 0) {
+        direction = D_RIGHT;
+    } else {
+        direction = parse_direction(direction_str);
+    }
+    orientation_t orientation = orientation_from_direction(direction);
+
     /* ensure that resize will take place even if pixel increment is smaller than
      * height increment or width increment.
      * fixes #1011 */
     const i3Window *window = focused_con->window;
     if (window != NULL) {
-        if (strcmp(direction, "up") == 0 || strcmp(direction, "down") == 0 ||
-            strcmp(direction, "height") == 0) {
-            if (px < 0)
+        if (orientation == VERT) {
+            if (px < 0) {
                 px = (-px < window->height_increment) ? -window->height_increment : px;
-            else
+            } else {
                 px = (px < window->height_increment) ? window->height_increment : px;
-        } else if (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0) {
-            if (px < 0)
+            }
+        } else {
+            if (px < 0) {
                 px = (-px < window->width_increment) ? -window->width_increment : px;
-            else
+            } else {
                 px = (px < window->width_increment) ? window->width_increment : px;
+            }
         }
     }
 
-    if (strcmp(direction, "up") == 0) {
+    if (orientation == VERT) {
         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.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)
+    if (memcmp(&old_rect, &(floating_con->rect), sizeof(Rect)) == 0) {
         return;
+    }
 
-    if (strcmp(direction, "up") == 0) {
+    if (direction == D_UP) {
         floating_con->rect.y -= (floating_con->rect.height - old_rect.height);
-    } else if (strcmp(direction, "left") == 0) {
+    } else if (direction == D_LEFT) {
         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)
+    if (floating_con->scratchpad_state == SCRATCHPAD_FRESH) {
         floating_con->scratchpad_state = SCRATCHPAD_CHANGED;
+    }
 }
 
-static bool cmd_resize_tiling_direction(I3_CMD, Con *current, const char *way, const char *direction, int ppt) {
-    LOG("tiling resize\n");
+static bool cmd_resize_tiling_direction(I3_CMD, Con *current, const char *way, const char *direction, int px, int ppt) {
     Con *second = NULL;
     Con *first = current;
-    direction_t search_direction;
-    if (!strcmp(direction, "left"))
-        search_direction = D_LEFT;
-    else if (!strcmp(direction, "right"))
-        search_direction = D_RIGHT;
-    else if (!strcmp(direction, "up"))
-        search_direction = D_UP;
-    else
-        search_direction = D_DOWN;
+    direction_t search_direction = parse_direction(direction);
 
     bool res = resize_find_tiling_participants(&first, &second, search_direction, false);
     if (!res) {
-        LOG("No second container in this direction found.\n");
-        ysuccess(false);
+        yerror("No second container found in this direction.\n");
         return false;
     }
 
-    /* get the default percentage */
-    int children = con_num_children(first->parent);
-    LOG("ins. %d children\n", children);
-    double percentage = 1.0 / children;
-    LOG("default percentage = %f\n", percentage);
-
-    /* resize */
-    LOG("first->percent before = %f\n", first->percent);
-    LOG("second->percent before = %f\n", second->percent);
-    if (first->percent == 0.0)
-        first->percent = percentage;
-    if (second->percent == 0.0)
-        second->percent = percentage;
-    double new_first_percent = first->percent + ((double)ppt / 100.0);
-    double new_second_percent = second->percent - ((double)ppt / 100.0);
-    LOG("new_first_percent = %f\n", new_first_percent);
-    LOG("new_second_percent = %f\n", new_second_percent);
-    /* Ensure that the new percentages are positive. */
-    if (new_first_percent > 0.0 && new_second_percent > 0.0) {
-        first->percent = new_first_percent;
-        second->percent = new_second_percent;
-        LOG("first->percent after = %f\n", first->percent);
-        LOG("second->percent after = %f\n", second->percent);
-    } else {
-        LOG("Not resizing, already at minimum size\n");
+    if (ppt) {
+        /* For backwards compatibility, 'X px or Y ppt' means that ppt is
+         * preferred. */
+        px = 0;
     }
-
-    return true;
+    return resize_neighboring_cons(first, second, px, ppt);
 }
 
 static bool cmd_resize_tiling_width_height(I3_CMD, Con *current, const char *way, const char *direction, int ppt) {
@@ -613,7 +607,8 @@ void cmd_resize(I3_CMD, const char *way, const char *direction, long resize_px,
                     return;
             } else {
                 if (!cmd_resize_tiling_direction(current_match, cmd_output,
-                                                 current->con, way, direction, resize_ppt))
+                                                 current->con, way, direction,
+                                                 resize_px, resize_ppt))
                     return;
             }
         }
@@ -644,12 +639,12 @@ void cmd_resize_set(I3_CMD, long cwidth, const char *mode_width, long cheight, c
         if ((floating_con = con_inside_floating(current->con))) {
             Con *output = con_get_output(floating_con);
             if (cwidth == 0) {
-                cwidth = output->rect.width;
+                cwidth = floating_con->rect.width;
             } else if (mode_width && strcmp(mode_width, "ppt") == 0) {
                 cwidth = output->rect.width * ((double)cwidth / 100.0);
             }
             if (cheight == 0) {
-                cheight = output->rect.height;
+                cheight = floating_con->rect.height;
             } else if (mode_height && strcmp(mode_height, "ppt") == 0) {
                 cheight = output->rect.height * ((double)cheight / 100.0);
             }
@@ -686,7 +681,7 @@ void cmd_resize_set(I3_CMD, long cwidth, const char *mode_width, long cheight, c
                 }
             }
 
-            if (cheight > 0 && mode_width && strcmp(mode_width, "ppt") == 0) {
+            if (cheight > 0 && mode_height && strcmp(mode_height, "ppt") == 0) {
                 /* get the appropriate current container (skip stacked/tabbed cons) */
                 Con *target = current->con;
                 Con *dummy;
@@ -1254,20 +1249,19 @@ void cmd_exec(I3_CMD, const char *nosn, const char *command) {
  *
  */
 void cmd_focus_direction(I3_CMD, const char *direction) {
-    DLOG("direction = *%s*\n", direction);
-
-    if (strcmp(direction, "left") == 0)
-        tree_next('p', HORIZ);
-    else if (strcmp(direction, "right") == 0)
-        tree_next('n', HORIZ);
-    else if (strcmp(direction, "up") == 0)
-        tree_next('p', VERT);
-    else if (strcmp(direction, "down") == 0)
-        tree_next('n', VERT);
-    else {
-        ELOG("Invalid focus direction (%s)\n", direction);
-        ysuccess(false);
-        return;
+    switch (parse_direction(direction)) {
+        case D_LEFT:
+            tree_next('p', HORIZ);
+            break;
+        case D_RIGHT:
+            tree_next('n', HORIZ);
+            break;
+        case D_UP:
+            tree_next('p', VERT);
+            break;
+        case D_DOWN:
+            tree_next('n', VERT);
+            break;
     }
 
     cmd_output->needs_tree_render = true;
@@ -1492,29 +1486,37 @@ void cmd_sticky(I3_CMD, const char *action) {
  * Implementation of 'move <direction> [<pixels> [px]]'.
  *
  */
-void cmd_move_direction(I3_CMD, const char *direction, long move_px) {
+void cmd_move_direction(I3_CMD, const char *direction_str, long move_px) {
     owindow *current;
     HANDLE_EMPTY_MATCH;
 
     Con *initially_focused = focused;
+    direction_t direction = parse_direction(direction_str);
 
     TAILQ_FOREACH(current, &owindows, owindows) {
-        DLOG("moving in direction %s, px %ld\n", direction, move_px);
+        DLOG("moving in direction %s, px %ld\n", direction_str, move_px);
         if (con_is_floating(current->con)) {
             DLOG("floating move with %ld pixels\n", move_px);
             Rect newrect = current->con->parent->rect;
-            if (strcmp(direction, "left") == 0) {
-                newrect.x -= move_px;
-            } else if (strcmp(direction, "right") == 0) {
-                newrect.x += move_px;
-            } else if (strcmp(direction, "up") == 0) {
-                newrect.y -= move_px;
-            } else if (strcmp(direction, "down") == 0) {
-                newrect.y += move_px;
+
+            switch (direction) {
+                case D_LEFT:
+                    newrect.x -= move_px;
+                    break;
+                case D_RIGHT:
+                    newrect.x += move_px;
+                    break;
+                case D_UP:
+                    newrect.y -= move_px;
+                    break;
+                case D_DOWN:
+                    newrect.y += move_px;
+                    break;
             }
+
             floating_reposition(current->con->parent, newrect);
         } else {
-            tree_move(current->con, (strcmp(direction, "right") == 0 ? D_RIGHT : (strcmp(direction, "left") == 0 ? D_LEFT : (strcmp(direction, "up") == 0 ? D_UP : D_DOWN))));
+            tree_move(current->con, direction);
             cmd_output->needs_tree_render = true;
         }
     }
@@ -1833,19 +1835,20 @@ void cmd_move_scratchpad(I3_CMD) {
 void cmd_scratchpad_show(I3_CMD) {
     DLOG("should show scratchpad window\n");
     owindow *current;
+    bool result = false;
 
     if (match_is_empty(current_match)) {
-        scratchpad_show(NULL);
+        result = scratchpad_show(NULL);
     } else {
         TAILQ_FOREACH(current, &owindows, owindows) {
             DLOG("matching: %p / %s\n", current->con, current->con->name);
-            scratchpad_show(current->con);
+            result |= scratchpad_show(current->con);
         }
     }
 
     cmd_output->needs_tree_render = true;
-    // XXX: default reply for now, make this a better reply
-    ysuccess(true);
+
+    ysuccess(result);
 }
 
 /*
@@ -1999,6 +2002,7 @@ void cmd_rename_workspace(I3_CMD, const char *old_name, const char *new_name) {
 
     /* By re-attaching, the sort order will be correct afterwards. */
     Con *previously_focused = focused;
+    Con *previously_focused_content = focused->type == CT_WORKSPACE ? focused->parent : NULL;
     Con *parent = workspace->parent;
     con_detach(workspace);
     con_attach(workspace, parent, false);
@@ -2017,16 +2021,31 @@ void cmd_rename_workspace(I3_CMD, const char *old_name, const char *new_name) {
             LOG("Could not get output named \"%s\"\n", assignment->output);
             continue;
         }
+        if (!output_triggers_assignment(target_output, assignment)) {
+            continue;
+        }
         workspace_move_to_output(workspace, target_output);
 
-        if (previously_focused)
-            workspace_show(con_get_workspace(previously_focused));
-
         break;
     }
 
-    /* Restore the previous focus since con_attach messes with the focus. */
-    con_activate(previously_focused);
+    bool can_restore_focus = previously_focused != NULL;
+    /* NB: If previously_focused is a workspace we can't work directly with it
+     * since it might have been cleaned up by workspace_show() already,
+     * depending on the focus order/number of other workspaces on the output.
+     * Instead, we loop through the available workspaces and only focus
+     * previously_focused if we still find it. */
+    if (previously_focused_content) {
+        Con *workspace = NULL;
+        GREP_FIRST(workspace, previously_focused_content, child == previously_focused);
+        can_restore_focus &= (workspace != NULL);
+    }
+
+    if (can_restore_focus) {
+        /* Restore the previous focus since con_attach messes with the focus. */
+        workspace_show(con_get_workspace(previously_focused));
+        con_focus(previously_focused);
+    }
 
     cmd_output->needs_tree_render = true;
     ysuccess(true);
@@ -2163,21 +2182,22 @@ void cmd_shmlog(I3_CMD, const char *argument) {
     else if (!strcmp(argument, "off"))
         shmlog_size = 0;
     else {
+        long new_size = 0;
+        if (!parse_long(argument, &new_size, 0)) {
+            yerror("Failed to parse %s into a shmlog size.\n", argument);
+            return;
+        }
         /* If shm logging now, restart logging with the new size. */
         if (shmlog_size > 0) {
             shmlog_size = 0;
             LOG("Restarting shm logging...\n");
             init_logging();
         }
-        shmlog_size = atoi(argument);
-        /* Make a weakly attempt at ensuring the argument is valid. */
-        if (shmlog_size <= 0)
-            shmlog_size = default_shmlog_size;
+        shmlog_size = (int)new_size;
     }
     LOG("%s shm logging\n", shmlog_size > 0 ? "Enabling" : "Disabling");
     init_logging();
     update_shmlog_atom();
-    // XXX: default reply for now, make this a better reply
     ysuccess(true);
 }