aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sway/commands/layout.c202
-rw-r--r--sway/container.c7
-rw-r--r--sway/layout.c46
-rw-r--r--sway/sway.5.txt12
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