diff options
-rw-r--r-- | sway/commands/layout.c | 202 | ||||
-rw-r--r-- | sway/container.c | 7 | ||||
-rw-r--r-- | sway/layout.c | 46 | ||||
-rw-r--r-- | sway/sway.5.txt | 12 |
4 files changed, 159 insertions, 108 deletions
diff --git a/sway/commands/layout.c b/sway/commands/layout.c index 0cdac1b4..ff097fef 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c @@ -3,6 +3,11 @@ #include "sway/container.h" #include "sway/layout.h" +/** + * handle "layout auto" command group + */ +static struct cmd_results *cmd_layout_auto(swayc_t *container, int argc, char **argv); + struct cmd_results *cmd_layout(int argc, char **argv) { struct cmd_results *error = NULL; if (config->reading) return cmd_results_new(CMD_FAILURE, "layout", "Can't be used in config file."); @@ -49,88 +54,14 @@ 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); } - } else if (strcasecmp(argv[0], "auto_left") == 0) { - swayc_change_layout(parent, L_AUTO_LEFT); - } else if (strcasecmp(argv[0], "auto_right") == 0) { - swayc_change_layout(parent, L_AUTO_RIGHT); - } else if (strcasecmp(argv[0], "auto_top") == 0) { - swayc_change_layout(parent, L_AUTO_TOP); - } else if (strcasecmp(argv[0], "auto_bot") == 0) { - swayc_change_layout(parent, L_AUTO_BOTTOM); - } else if (strcasecmp(argv[0], "incnmaster") == 0) { - const char *name = "layout incnmaster"; - if ((error = checkarg(argc, name, - EXPECTED_EQUAL_TO, 2))) { - return error; - } - char *end; - int inc = (int) strtol(argv[1], &end, 10); - if (*end) { - return cmd_results_new(CMD_INVALID, name, "Invalid %s command " - "(argument must be an integer)", name); - - } - swayc_t *container = get_focused_view(swayc_active_workspace()); - if (container && inc && - is_auto_layout(container->parent->layout) && - ((int)container->parent->nb_master + inc >= 0)) { - for (int i = container->parent->nb_master; - i >= 0 && i < container->parent->children->length && - i != (int) container->parent->nb_master + inc;) { - ((swayc_t *) container->parent->children->items[i])->height = -1; - ((swayc_t *) container->parent->children->items[i])->width = -1; - i += inc > 0 ? 1 : -1; - } - container->parent->nb_master += inc; - } - } else if ((strcasecmp(argv[0], "incncol") == 0) && argc ==2) { - const char *name = "layout incncol"; - if ((error = checkarg(argc, name, - EXPECTED_EQUAL_TO, 2))) { - return error; - } - char *end; - int inc = (int) strtol(argv[1], &end, 10); - if (*end) { - return cmd_results_new(CMD_INVALID, name, "Invalid %s command " - "(argument must be an integer)", name); - - } - swayc_t *container = get_focused_view(swayc_active_workspace()); - if (container && inc && is_auto_layout(container->parent->layout) && - ((int)container->parent->nb_slave_groups + inc >= 1)) { - container->parent->nb_slave_groups += inc; - } } else if (strcasecmp(argv[0], "auto") == 0) { - if ((error = checkarg(argc, "auto", EXPECTED_EQUAL_TO, 2))) { - return error; - } - swayc_t *container = get_focused_view(swayc_active_workspace()); - swayc_t *parent = container->parent; - enum swayc_layouts layout; - if (strcasecmp(argv[1], "next") == 0) { - if (is_auto_layout(parent->layout) && parent->layout < L_AUTO_LAST) { - layout = parent->layout + 1; - } else { - layout = L_AUTO_FIRST; - } - } else if (strcasecmp(argv[1], "prev") == 0) { - if (is_auto_layout(parent->layout) && parent->layout > L_AUTO_FIRST) { - layout = parent->layout - 1; - } else { - layout = L_AUTO_LAST; - } - } else { - return cmd_results_new(CMD_FAILURE, "layout auto", - "Must be one of <prev|next>."); - } - swayc_change_layout(parent, layout); + return cmd_layout_auto(parent, argc, argv); } } @@ -141,3 +72,120 @@ struct cmd_results *cmd_layout(int argc, char **argv) { return cmd_results_new(CMD_SUCCESS, NULL, NULL); } + +static struct cmd_results *cmd_layout_auto(swayc_t *container, int argc, char **argv) { + // called after checking that argv[0] is auto, so just continue parsing from there + struct cmd_results *error = NULL; + const char *cmd_name = "layout auto"; + const char *set_inc_cmd_name = "layout auto [master|ncol] [set|inc]"; + const char *err_msg = "Allowed arguments are <right|left|top|bot|next|prev|master|ncol>"; + + bool need_layout_update = false; + enum swayc_layouts old_layout = container->layout; + enum swayc_layouts layout = old_layout; + + if (strcasecmp(argv[1], "left") == 0) { + layout = L_AUTO_LEFT; + } else if (strcasecmp(argv[1], "right") == 0) { + layout = L_AUTO_RIGHT; + } else if (strcasecmp(argv[1], "top") == 0) { + layout = L_AUTO_TOP; + } else if (strcasecmp(argv[1], "bot") == 0) { + layout = L_AUTO_BOTTOM; + } else if (strcasecmp(argv[1], "next") == 0) { + if (is_auto_layout(container->layout) && container->layout < L_AUTO_LAST) { + layout = container->layout + 1; + } else { + layout = L_AUTO_FIRST; + } + } else if (strcasecmp(argv[1], "prev") == 0) { + if (is_auto_layout(container->layout) && container->layout > L_AUTO_FIRST) { + layout = container->layout - 1; + } else { + layout = L_AUTO_LAST; + } + } else { + bool is_nmaster; + bool is_set; + if (strcasecmp(argv[1], "master") == 0) { + is_nmaster = true; + } else if (strcasecmp(argv[1], "ncol") == 0) { + is_nmaster = false; + } else { + return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command. %s", + cmd_name, err_msg); + } + if ((error = checkarg(argc, "auto <master|ncol>", EXPECTED_EQUAL_TO, 4))) { + return error; + } + if (strcasecmp(argv[2], "set") == 0) { + is_set = true; + } else if (strcasecmp(argv[2], "inc") == 0) { + is_set = false; + } else { + return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command. %s, " + "Argument must be on of <set|inc>", + set_inc_cmd_name); + } + char *end; + int n = (int)strtol(argv[3], &end, 10); + if (*end) { + return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command " + "(argument must be an integer)", set_inc_cmd_name); + } + if (is_auto_layout(container->layout)) { + int inc = 0; /* difference between current master/ncol and requested value */ + if (is_nmaster) { + if (is_set) { + if (n < 0) { + return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command " + "(master must be >= 0)", set_inc_cmd_name); + } + inc = n - (int)container->nb_master; + } else { /* inc command */ + if ((int)container->nb_master + n >= 0) { + inc = n; + } + } + if (inc) { + for (int i = container->nb_master; + i >= 0 && i < container->children->length + && i != (int)container->nb_master + inc;) { + ((swayc_t *)container->children->items[i])->height = -1; + ((swayc_t *)container->children->items[i])->width = -1; + i += inc > 0 ? 1 : -1; + } + container->nb_master += inc; + need_layout_update = true; + } + } else { /* ncol modification */ + if (is_set) { + if (n <= 0) { + return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command " + "(ncol must be > 0)", set_inc_cmd_name); + } + inc = n - (int)container->nb_slave_groups; + } else { /* inc command */ + if ((int)container->nb_slave_groups + n > 0) { + inc = n; + } + } + if (inc) { + container->nb_slave_groups += inc; + need_layout_update = true; + } + } + } + } + + if (layout != old_layout) { + swayc_change_layout(container, layout); + update_layout_geometry(container, old_layout); + need_layout_update = true; + } + if (need_layout_update) { + update_geometry(container); + arrange_windows(container, container->width, container->height); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/container.c b/sway/container.c index 3bdc8b6c..cf7d7dda 100644 --- a/sway/container.c +++ b/sway/container.c @@ -965,10 +965,11 @@ swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout) { // if layout change modifies the auto layout's major axis, swap width and height // to preserve current ratios. if (is_auto_layout(layout) && is_auto_layout(container->layout)) { - enum swayc_layouts prev_major = (container->layout == L_AUTO_LEFT || - container->layout == L_AUTO_RIGHT) + enum swayc_layouts prev_major = + container->layout == L_AUTO_LEFT || container->layout == L_AUTO_RIGHT ? L_HORIZ : L_VERT; - enum swayc_layouts new_major = (layout == L_AUTO_LEFT || layout == L_AUTO_RIGHT) + enum swayc_layouts new_major = + layout == L_AUTO_LEFT || layout == L_AUTO_RIGHT ? L_HORIZ : L_VERT; if (new_major != prev_major) { for (int i = 0; i < container->children->length; ++i) { diff --git a/sway/layout.c b/sway/layout.c index e2f31848..fdd2fe6b 100644 --- a/sway/layout.c +++ b/sway/layout.c @@ -296,7 +296,7 @@ void move_container(swayc_t *container, enum movement_direction dir) { sway_log(L_DEBUG, "container:%p, parent:%p, child %p,", container,parent,child); if (parent->layout == layout - || layout == L_NONE /* accept any layout for next/prev direction */ + || (layout == L_NONE && parent->type == C_CONTAINER) /* accept any layout for next/prev direction */ || (parent->layout == L_TABBED && layout == L_HORIZ) || (parent->layout == L_STACKED && layout == L_VERT) || is_auto_layout(parent->layout)) { @@ -321,16 +321,16 @@ void move_container(swayc_t *container, enum movement_direction dir) { } // 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 && - (size_t) parent->children->length > parent->nb_master) { + if (parent->nb_master + && (size_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 && (size_t) desired == parent->nb_master - 1)) { + || (dir == MOVE_PREV && (size_t)desired == parent->nb_master - 1)) { swap_geom = parent->children->items[parent->nb_master - 1]; - } else if ((dir == MOVE_NEXT && (size_t) desired == parent->nb_master) - || (dir == MOVE_PREV && desired == parent->children->length - 1)) { + } else if ((dir == MOVE_NEXT && (size_t)desired == parent->nb_master) + || (dir == MOVE_PREV && desired == parent->children->length - 1)) { swap_geom = parent->children->items[parent->nb_master]; } if (swap_geom) { @@ -837,9 +837,9 @@ static void apply_tabbed_or_stacked_layout(swayc_t *container, double x, double height); static void apply_auto_layout(swayc_t *container, const double x, const double y, - const double width, const double height, - enum swayc_layouts group_layout, - bool master_first); + const double width, const double height, + enum swayc_layouts group_layout, + bool master_first); static void arrange_windows_r(swayc_t *container, double width, double height) { int i; @@ -972,11 +972,11 @@ static void arrange_windows_r(swayc_t *container, double width, double height) { case L_HORIZ: default: apply_horiz_layout(container, x, y, width, height, 0, - container->children->length); + container->children->length); break; case L_VERT: apply_vert_layout(container, x, y, width, height, 0, - container->children->length); + container->children->length); break; case L_TABBED: case L_STACKED: @@ -1007,7 +1007,7 @@ static void arrange_windows_r(swayc_t *container, double width, double height) { if (swayc_is_fullscreen(view)) { wlc_view_bring_to_front(view->handle); } else if (!container->focused || - !swayc_is_fullscreen(container->focused)) { + !swayc_is_fullscreen(container->focused)) { wlc_view_bring_to_front(view->handle); } } @@ -1068,8 +1068,8 @@ void apply_horiz_layout(swayc_t *container, const double x, const double y, } void apply_vert_layout(swayc_t *container, const double x, const double y, - const double width, const double height, const int start, - const int end) { + const double width, const double height, const int start, + const int end) { int i; double scale = 0; // Calculate total height @@ -1121,7 +1121,7 @@ void apply_vert_layout(swayc_t *container, const double x, const double y, } void apply_tabbed_or_stacked_layout(swayc_t *container, double x, double y, - double width, double height) { + double width, double height) { int i; swayc_t *focused = NULL; for (i = 0; i < container->children->length; ++i) { @@ -1141,9 +1141,9 @@ void apply_tabbed_or_stacked_layout(swayc_t *container, double x, double y, } void apply_auto_layout(swayc_t *container, const double x, const double y, - const double width, const double height, - enum swayc_layouts group_layout, - bool master_first) { + const double width, const double height, + enum swayc_layouts group_layout, + bool master_first) { // Auto layout "container" in width x height @ x, y // using "group_layout" for each of the groups in the container. // There is one "master" group, plus container->nb_slave_groups. @@ -1342,7 +1342,7 @@ swayc_t *get_swayc_in_direction_under(swayc_t *container, enum movement_directio return NULL; } else { int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) % - parent->children->length; + parent->children->length; if (desired < 0) { desired += parent->children->length; } @@ -1504,7 +1504,9 @@ bool is_auto_layout(enum swayc_layouts layout) { * Return the number of master elements in a container */ static inline size_t auto_master_count(const swayc_t *container) { - return MIN(container->nb_master, container->children->length); + sway_assert(container->children->length >= 0, "Container %p has (negative) children %d", + container, container->children->length); + return MIN(container->nb_master, (size_t)container->children->length); } /** @@ -1535,7 +1537,7 @@ size_t auto_group_count(const swayc_t *container) { */ int auto_group_start_index(const swayc_t *container, int index) { if (index < 0 || ! is_auto_layout(container->layout) - || (size_t) index < container->nb_master) { + || (size_t)index < container->nb_master) { return 0; } else { size_t nb_slaves = auto_slave_count(container); @@ -1591,7 +1593,7 @@ size_t auto_group_index(const swayc_t *container, int index) { } bool master_first = (container->layout == L_AUTO_LEFT || container->layout == L_AUTO_TOP); size_t nb_slaves = auto_slave_count(container); - if ((size_t) index < container->nb_master) { + if ((size_t)index < container->nb_master) { if (master_first || nb_slaves <= 0) { return 0; } else { diff --git a/sway/sway.5.txt b/sway/sway.5.txt index cbff6cef..5e0a07bd 100644 --- a/sway/sway.5.txt +++ b/sway/sway.5.txt @@ -84,13 +84,16 @@ They are expected to be used with **bindsym** or at runtime through **swaymsg**( **layout** <mode>:: Sets the layout mode of the focused container. _mode_ can be one of _splith_, - _splitv_, _toggle split_, _stacking_, _tabbed_, _auto_left_, _auto_right_, - _auto_top, _auto_bottom_. + _splitv_, _toggle split_, _stacking_, _tabbed_. + +**layout** auto <mode>:: + Sets layout to one of the auto modes, i.e. one of _left_, right_, _top_, + or _bot_. **layout** auto <next|prev>:: Cycles between available auto layouts. -**layout** <incnmaster|incncol> <n>:: +**layout** auto [master|ncol] [inc|set] <n>:: Modify the number of master elements, respectively slave columns, in the focused container. <n> can be a positive or negative integer. These commands only have an effect if the focused container uses one of the "auto" layouts. @@ -98,9 +101,6 @@ They are expected to be used with **bindsym** or at runtime through **swaymsg**( **layout** toggle split:: Cycles between available split layouts. -**layout** promote:: - Swap the focused element with the first in the one of the auto layouts. - **move** <left|right|up|down|next|prev|first>:: 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 |