diff --git a/include/sway/focus.h b/include/sway/focus.h index b532edc2..30c9e108 100644 --- a/include/sway/focus.h +++ b/include/sway/focus.h @@ -6,7 +6,9 @@ enum movement_direction { MOVE_UP, MOVE_DOWN, MOVE_PARENT, - MOVE_CHILD + MOVE_CHILD, + MOVE_NEXT, + MOVE_PREV }; #include "container.h" @@ -40,4 +42,3 @@ extern bool suspend_workspace_cleanup; bool move_focus(enum movement_direction direction); #endif - diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 8442305f..0be442ca 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -46,6 +46,10 @@ struct cmd_results *cmd_focus(int argc, char **argv) { move_focus(MOVE_PARENT); } else if (strcasecmp(argv[0], "child") == 0) { move_focus(MOVE_CHILD); + } else if (strcasecmp(argv[0], "next") == 0) { + move_focus(MOVE_NEXT); + } else if (strcasecmp(argv[0], "prev") == 0) { + move_focus(MOVE_PREV); } else if (strcasecmp(argv[0], "mode_toggle") == 0) { int i; swayc_t *workspace = swayc_active_workspace(); diff --git a/sway/commands/layout.c b/sway/commands/layout.c index 5e2e8efd..9e468c21 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c @@ -49,7 +49,8 @@ struct cmd_results *cmd_layout(int argc, char **argv) { } else if (strcasecmp(argv[0], "splitv") == 0) { swayc_change_layout(parent, L_VERT); } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) { - if (parent->layout == L_HORIZ && (parent->workspace_layout == L_NONE || parent->workspace_layout == L_HORIZ)) { + if (parent->layout == L_HORIZ && (parent->workspace_layout == L_NONE || + parent->workspace_layout == L_HORIZ)) { swayc_change_layout(parent, L_VERT); } else { swayc_change_layout(parent, L_HORIZ); diff --git a/sway/commands/move.c b/sway/commands/move.c index 4819d9ef..4f6bc76f 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -13,7 +13,7 @@ struct cmd_results *cmd_move(int argc, char **argv) { if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { return error; } - const char* expected_syntax = "Expected 'move ' or " + const char* expected_syntax = "Expected 'move ' or " "'move to workspace ' or " "'move to output ' or " "'move position mouse'"; @@ -27,6 +27,10 @@ struct cmd_results *cmd_move(int argc, char **argv) { move_container(view, MOVE_UP); } else if (strcasecmp(argv[0], "down") == 0) { move_container(view, MOVE_DOWN); + } else if (strcasecmp(argv[0], "next") == 0) { + move_container(view, MOVE_NEXT); + } else if (strcasecmp(argv[0], "prev") == 0) { + move_container(view, MOVE_PREV); } else if (strcasecmp(argv[0], "container") == 0 || strcasecmp(argv[0], "window") == 0) { // "move container ... if ((error = checkarg(argc, "move container/window", EXPECTED_AT_LEAST, 4))) { diff --git a/sway/layout.c b/sway/layout.c index 0428ecf9..a8ad7ed5 100644 --- a/sway/layout.c +++ b/sway/layout.c @@ -251,7 +251,7 @@ void swap_geometry(swayc_t *a, swayc_t *b) { } void move_container(swayc_t *container, enum movement_direction dir) { - enum swayc_layouts layout; + enum swayc_layouts layout = L_NONE; if (container->is_floating || (container->type != C_VIEW && container->type != C_CONTAINER)) { return; @@ -260,7 +260,7 @@ void move_container(swayc_t *container, enum movement_direction dir) { layout = L_VERT; } else if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { layout = L_HORIZ; - } else { + } else if (! (dir == MOVE_NEXT || dir == MOVE_PREV)) { return; } swayc_t *parent = container->parent; @@ -284,18 +284,51 @@ void move_container(swayc_t *container, enum movement_direction dir) { container,parent,child); if (parent->layout == layout || (parent->layout == L_TABBED && layout == L_HORIZ) - || (parent->layout == L_STACKED && layout == L_VERT)) { + || (parent->layout == L_STACKED && layout == L_VERT) + || is_auto_layout(parent->layout)) { int diff; // If it has ascended (parent has moved up), no container is removed // so insert it at index, or index+1. // if it has not, the moved container is removed, so it needs to be // inserted at index-1, or index+1 if (ascended) { - diff = dir == MOVE_LEFT || dir == MOVE_UP ? 0 : 1; + diff = dir == MOVE_LEFT || dir == MOVE_UP || dir == MOVE_PREV ? 0 : 1; } else { - diff = dir == MOVE_LEFT || dir == MOVE_UP ? -1 : 1; + diff = dir == MOVE_LEFT || dir == MOVE_UP || dir == MOVE_PREV ? -1 : 1; + } + int idx = index_child(child); + int desired = idx + diff; + if (dir == MOVE_NEXT || dir == MOVE_PREV) { + // Next/Prev always wrap. + if (desired < 0) { + desired += parent->children->length; + } else if (desired >= parent->children->length) { + desired = 0; + } + // if move command makes container change from master to slave + // (or the contrary), reset its geometry an the one of the replaced item. + if (parent->nb_master && + (uint_fast32_t) parent->children->length > parent->nb_master) { + swayc_t *swap_geom = NULL; + // if child is being promoted/demoted, it will swap geometry + // with the sibling being demoted/promoted. + if ((dir == MOVE_NEXT && desired == 0) + || (dir == MOVE_PREV && (uint_fast32_t) desired == parent->nb_master - 1)) { + swap_geom = parent->children->items[parent->nb_master - 1]; + } else if ((dir == MOVE_NEXT && (uint_fast32_t) desired == parent->nb_master) + || (dir == MOVE_PREV && desired == parent->children->length - 1)) { + swap_geom = parent->children->items[parent->nb_master]; + } + if (swap_geom) { + double h = child->height; + double w = child->width; + child->width = swap_geom->width; + child->height = swap_geom->height; + swap_geom->width = w; + swap_geom->height = h; + } + } } - int desired = index_child(child) + diff; // when it has ascended, legal insertion position is 0:len // when it has not, legal insertion position is 0:len-1 if (desired >= 0 && desired - ascended < parent->children->length) { @@ -308,7 +341,8 @@ void move_container(swayc_t *container, enum movement_direction dir) { // insert it next to focused container if (parent->layout == layout || (parent->layout == L_TABBED && layout == L_HORIZ) - || (parent->layout == L_STACKED && layout == L_VERT)) { + || (parent->layout == L_STACKED && layout == L_VERT) + || is_auto_layout(parent->layout)) { desired = (diff < 0) * parent->children->length; } else { desired = index_child(child->focused) + 1; @@ -325,7 +359,7 @@ void move_container(swayc_t *container, enum movement_direction dir) { } } // Change parent layout if we need to - if (parent->children->length == 1 && parent->layout != layout) { + if (parent->children->length == 1 && parent->layout != layout && layout != L_NONE) { /* swayc_change_layout(parent, layout); */ parent->layout = layout; continue; @@ -1310,6 +1344,21 @@ swayc_t *get_swayc_in_direction_under(swayc_t *container, enum movement_directio return parent; } } + + if (dir == MOVE_PREV || dir == MOVE_NEXT) { + int focused_idx = index_child(container); + if (focused_idx == -1) { + return NULL; + } else { + int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) % + parent->children->length; + if (desired < 0) { + desired += parent->children->length; + } + return parent->children->items[desired]; + } + } + // If moving to an adjacent output we need a starting position (since this // output might border to multiple outputs). struct wlc_point abs_pos; diff --git a/sway/sway.5.txt b/sway/sway.5.txt index 2fa5f32e..8f8302f0 100644 --- a/sway/sway.5.txt +++ b/sway/sway.5.txt @@ -92,8 +92,10 @@ They are expected to be used with **bindsym** or at runtime through **swaymsg**( focused container. can be a positive or negative integer. These commands only have an effect if the focused container uses one of the "auto" layouts. -**move** :: - Moves the focused container _left_, _right_, _up_, or _down_. +**move** :: + Moves the focused container _left_, _right_, _up_, or _down_. Moving + to _prev_ or _next_ swaps the container with its sibling in the same + container. **move** to workspace :: Moves the focused container to the workspace identified by _name_.