aboutsummaryrefslogtreecommitdiff
path: root/sway/commands/resize.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/commands/resize.c')
-rw-r--r--sway/commands/resize.c329
1 files changed, 220 insertions, 109 deletions
diff --git a/sway/commands/resize.c b/sway/commands/resize.c
index afb369c2..3f243cf7 100644
--- a/sway/commands/resize.c
+++ b/sway/commands/resize.c
@@ -29,6 +29,11 @@ enum resize_axis {
RESIZE_AXIS_INVALID,
};
+struct resize_amount {
+ int amount;
+ enum resize_unit unit;
+};
+
static enum resize_unit parse_resize_unit(const char *unit) {
if (strcasecmp(unit, "px") == 0) {
return RESIZE_UNIT_PX;
@@ -42,6 +47,30 @@ static enum resize_unit parse_resize_unit(const char *unit) {
return RESIZE_UNIT_INVALID;
}
+// Parse arguments such as "10", "10px" or "10 px".
+// Returns the number of arguments consumed.
+static int parse_resize_amount(int argc, char **argv,
+ struct resize_amount *amount) {
+ char *err;
+ amount->amount = (int)strtol(argv[0], &err, 10);
+ if (*err) {
+ // e.g. 10px
+ amount->unit = parse_resize_unit(err);
+ return 1;
+ }
+ if (argc == 1) {
+ amount->unit = RESIZE_UNIT_DEFAULT;
+ return 1;
+ }
+ // Try the second argument
+ amount->unit = parse_resize_unit(argv[1]);
+ if (amount->unit == RESIZE_UNIT_INVALID) {
+ amount->unit = RESIZE_UNIT_DEFAULT;
+ return 1;
+ }
+ return 2;
+}
+
static enum resize_axis parse_resize_axis(const char *axis) {
if (strcasecmp(axis, "width") == 0 || strcasecmp(axis, "horizontal") == 0) {
return RESIZE_AXIS_HORIZONTAL;
@@ -202,36 +231,39 @@ static void resize_tiled(int amount, enum resize_axis axis) {
arrange_and_commit(parent->parent);
}
-static void resize_floating(int amount, enum resize_axis axis) {
+/**
+ * Implement `resize <grow|shrink>` for a floating container.
+ */
+static struct cmd_results *resize_adjust_floating(enum resize_axis axis,
+ struct resize_amount *amount) {
struct sway_container *con = config->handler_context.current_container;
int grow_x = 0, grow_y = 0;
int grow_width = 0, grow_height = 0;
switch (axis) {
case RESIZE_AXIS_HORIZONTAL:
- grow_x = -amount / 2;
- grow_width = amount;
+ grow_x = -amount->amount / 2;
+ grow_width = amount->amount;
break;
case RESIZE_AXIS_VERTICAL:
- grow_y = -amount / 2;
- grow_height = amount;
+ grow_y = -amount->amount / 2;
+ grow_height = amount->amount;
break;
case RESIZE_AXIS_UP:
- grow_y = -amount;
- grow_height = amount;
+ grow_y = -amount->amount;
+ grow_height = amount->amount;
break;
case RESIZE_AXIS_LEFT:
- grow_x = -amount;
- grow_width = amount;
+ grow_x = -amount->amount;
+ grow_width = amount->amount;
break;
case RESIZE_AXIS_DOWN:
- grow_height = amount;
+ grow_height = amount->amount;
break;
case RESIZE_AXIS_RIGHT:
- grow_width = amount;
+ grow_width = amount->amount;
break;
case RESIZE_AXIS_INVALID:
- sway_assert(false, "Didn't expect RESIZE_AXIS_INVALID");
- return;
+ return cmd_results_new(CMD_INVALID, "resize", "Invalid axis/direction");
}
con->x += grow_x;
con->y += grow_y;
@@ -247,80 +279,64 @@ static void resize_floating(int amount, enum resize_axis axis) {
}
arrange_and_commit(con);
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
-static void resize(int amount, enum resize_axis axis, enum resize_unit unit) {
+/**
+ * Implement `resize <grow|shrink>` for a tiled container.
+ */
+static struct cmd_results *resize_adjust_tiled(enum resize_axis axis,
+ struct resize_amount *amount) {
struct sway_container *current = config->handler_context.current_container;
- if (container_is_floating(current)) {
- return resize_floating(amount, axis);
- }
- if (unit == RESIZE_UNIT_DEFAULT) {
- unit = RESIZE_UNIT_PPT;
+ if (amount->unit == RESIZE_UNIT_DEFAULT) {
+ amount->unit = RESIZE_UNIT_PPT;
}
- if (unit == RESIZE_UNIT_PPT) {
- float pct = amount / 100.0f;
+ if (amount->unit == RESIZE_UNIT_PPT) {
+ float pct = amount->amount / 100.0f;
+ // TODO: Make left/right/up/down resize in that direction?
switch (axis) {
+ case RESIZE_AXIS_LEFT:
+ case RESIZE_AXIS_RIGHT:
case RESIZE_AXIS_HORIZONTAL:
- amount = (float)current->width * pct;
+ amount->amount = (float)current->width * pct;
break;
+ case RESIZE_AXIS_UP:
+ case RESIZE_AXIS_DOWN:
case RESIZE_AXIS_VERTICAL:
- amount = (float)current->height * pct;
+ amount->amount = (float)current->height * pct;
break;
- default:
- sway_assert(0, "invalid resize axis");
- return;
+ case RESIZE_AXIS_INVALID:
+ return cmd_results_new(CMD_INVALID, "resize",
+ "Invalid resize axis/direction");
}
}
- return resize_tiled(amount, axis);
+ resize_tiled(amount->amount, axis);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
-// resize set <width> [px|ppt] <height> [px|ppt]
-static struct cmd_results *cmd_resize_set(int argc, char **argv) {
- struct cmd_results *error;
- if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) {
- return error;
- }
- struct sway_container *con = config->handler_context.current_container;
- if (!container_is_floating(con)) {
- return cmd_results_new(CMD_INVALID, "resize",
- "resize set is not currently supported for tiled containers");
- }
- const char *usage = "Expected 'resize set <width> <height>'";
-
- char *err;
- size_t width = (int)strtol(*argv, &err, 10);
- if (*err) {
- // e.g. `resize set width 500px`
- enum resize_unit unit = parse_resize_unit(err);
- if (unit == RESIZE_UNIT_INVALID) {
- return cmd_results_new(CMD_INVALID, "resize", usage);
- }
- }
- --argc; ++argv;
- if (parse_resize_unit(argv[0]) != RESIZE_UNIT_INVALID) {
- --argc; ++argv;
- }
-
- if (!argc) {
- return cmd_results_new(CMD_INVALID, "resize", usage);
- }
- size_t height = (int)strtol(*argv, &err, 10);
- if (*err) {
- // e.g. `resize set height 500px`
- enum resize_unit unit = parse_resize_unit(err);
- if (unit == RESIZE_UNIT_INVALID) {
- return cmd_results_new(CMD_INVALID, "resize", usage);
- }
- }
+/**
+ * Implement `resize set` for a tiled container.
+ */
+static struct cmd_results *resize_set_tiled(struct sway_container *con,
+ struct resize_amount *width, struct resize_amount *height) {
+ return cmd_results_new(CMD_INVALID, "resize",
+ "'resize set' is not implemented for tiled views");
+}
- int grow_width = width - con->width;
- int grow_height = height - con->height;
+/**
+ * Implement `resize set` for a floating container.
+ */
+static struct cmd_results *resize_set_floating(struct sway_container *con,
+ struct resize_amount *width, struct resize_amount *height) {
+ int grow_width = width->amount - con->width;
+ int grow_height = height->amount - con->height;
con->x -= grow_width / 2;
con->y -= grow_height / 2;
- con->width = width;
- con->height = height;
+ con->width = width->amount;
+ con->height = height->amount;
if (con->type == C_VIEW) {
struct sway_view *view = con->sway_view;
@@ -335,73 +351,168 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) {
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
-struct cmd_results *cmd_resize(int argc, char **argv) {
- struct sway_container *current = config->handler_context.current_container;
- if (!current) {
- return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing");
- }
- if (current->type != C_VIEW && current->type != C_CONTAINER) {
- return cmd_results_new(CMD_INVALID, "resize",
- "Can only resize views/containers");
- }
-
+/**
+ * resize set <args>
+ *
+ * args: <width> [px|ppt] <height> [px|ppt]
+ */
+static struct cmd_results *cmd_resize_set(int argc, char **argv) {
struct cmd_results *error;
if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) {
return error;
}
+ const char *usage = "Expected 'resize set <width> <height>'";
- if (strcasecmp(argv[0], "set") == 0) {
- return cmd_resize_set(argc - 1, &argv[1]);
+ // Width
+ struct resize_amount width;
+ int num_consumed_args = parse_resize_amount(argc, argv, &width);
+ argc -= num_consumed_args;
+ argv += num_consumed_args;
+ if (width.unit == RESIZE_UNIT_INVALID) {
+ return cmd_results_new(CMD_INVALID, "resize", usage);
+ }
+ if (!argc) {
+ return cmd_results_new(CMD_INVALID, "resize", usage);
}
- const char *usage = "Expected 'resize <shrink|grow> "
- "<width|height|up|down|left|right> [<amount>] [px|ppt]'";
-
- int multiplier = 0;
- if (strcasecmp(*argv, "grow") == 0) {
- multiplier = 1;
- } else if (strcasecmp(*argv, "shrink") == 0) {
- multiplier = -1;
- } else {
+ // Height
+ struct resize_amount height;
+ num_consumed_args = parse_resize_amount(argc, argv, &height);
+ argc -= num_consumed_args;
+ argv += num_consumed_args;
+ if (height.unit == RESIZE_UNIT_INVALID) {
return cmd_results_new(CMD_INVALID, "resize", usage);
}
- --argc; ++argv;
+ // If 0, don't resize that dimension
+ struct sway_container *con = config->handler_context.current_container;
+ if (width.amount <= 0) {
+ width.amount = con->width;
+ }
+ if (height.amount <= 0) {
+ height.amount = con->height;
+ }
+
+ if (container_is_floating(con)) {
+ return resize_set_floating(con, &width, &height);
+ }
+ return resize_set_tiled(con, &width, &height);
+}
+
+/**
+ * resize <grow|shrink> <args>
+ *
+ * args: <direction>
+ * args: <direction> <amount> <unit>
+ * args: <direction> <amount> <unit> or <amount> <other_unit>
+ */
+static struct cmd_results *cmd_resize_adjust(int argc, char **argv,
+ int multiplier) {
+ const char *usage = "Expected 'resize grow|shrink <direction> "
+ "[<amount> px|ppt [or <amount> px|ppt]]'";
enum resize_axis axis = parse_resize_axis(*argv);
if (axis == RESIZE_AXIS_INVALID) {
return cmd_results_new(CMD_INVALID, "resize", usage);
}
--argc; ++argv;
- int amount = 10; // Default amount
- enum resize_unit unit = RESIZE_UNIT_DEFAULT;
-
+ // First amount
+ struct resize_amount first_amount;
if (argc) {
- char *err;
- amount = (int)strtol(*argv, &err, 10);
- if (*err) {
- // e.g. `resize grow width 10px`
- unit = parse_resize_unit(err);
- if (unit == RESIZE_UNIT_INVALID) {
- return cmd_results_new(CMD_INVALID, "resize", usage);
- }
+ int num_consumed_args = parse_resize_amount(argc, argv, &first_amount);
+ argc -= num_consumed_args;
+ argv += num_consumed_args;
+ if (first_amount.unit == RESIZE_UNIT_INVALID) {
+ return cmd_results_new(CMD_INVALID, "resize", usage);
}
- --argc; ++argv;
+ } else {
+ first_amount.amount = 10;
+ first_amount.unit = RESIZE_UNIT_DEFAULT;
}
+ // "or"
if (argc) {
- unit = parse_resize_unit(*argv);
- if (unit == RESIZE_UNIT_INVALID) {
+ if (strcmp(*argv, "or") != 0) {
return cmd_results_new(CMD_INVALID, "resize", usage);
}
--argc; ++argv;
}
+ // Second amount
+ struct resize_amount second_amount;
if (argc) {
- // Provied too many args, the bastard
- return cmd_results_new(CMD_INVALID, "resize", usage);
+ int num_consumed_args = parse_resize_amount(argc, argv, &second_amount);
+ argc -= num_consumed_args;
+ argv += num_consumed_args;
+ if (second_amount.unit == RESIZE_UNIT_INVALID) {
+ return cmd_results_new(CMD_INVALID, "resize", usage);
+ }
+ } else {
+ second_amount.unit = RESIZE_UNIT_INVALID;
}
- resize(amount * multiplier, axis, unit);
- return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ first_amount.amount *= multiplier;
+ second_amount.amount *= multiplier;
+
+ struct sway_container *con = config->handler_context.current_container;
+ if (container_is_floating(con)) {
+ // Floating containers can only resize in px. Choose an amount which
+ // uses px, with fallback to an amount that specified no unit.
+ if (first_amount.unit == RESIZE_UNIT_PX) {
+ return resize_adjust_floating(axis, &first_amount);
+ } else if (second_amount.unit == RESIZE_UNIT_PX) {
+ return resize_adjust_floating(axis, &second_amount);
+ } else if (first_amount.unit == RESIZE_UNIT_DEFAULT) {
+ return resize_adjust_floating(axis, &first_amount);
+ } else if (second_amount.unit == RESIZE_UNIT_DEFAULT) {
+ return resize_adjust_floating(axis, &second_amount);
+ } else {
+ return cmd_results_new(CMD_INVALID, "resize",
+ "Floating containers cannot use ppt measurements");
+ }
+ }
+
+ // For tiling, prefer ppt -> default -> px
+ if (first_amount.unit == RESIZE_UNIT_PPT) {
+ return resize_adjust_tiled(axis, &first_amount);
+ } else if (second_amount.unit == RESIZE_UNIT_PPT) {
+ return resize_adjust_tiled(axis, &second_amount);
+ } else if (first_amount.unit == RESIZE_UNIT_DEFAULT) {
+ return resize_adjust_tiled(axis, &first_amount);
+ } else if (second_amount.unit == RESIZE_UNIT_DEFAULT) {
+ return resize_adjust_tiled(axis, &second_amount);
+ } else {
+ return resize_adjust_tiled(axis, &first_amount);
+ }
+}
+
+struct cmd_results *cmd_resize(int argc, char **argv) {
+ struct sway_container *current = config->handler_context.current_container;
+ if (!current) {
+ return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing");
+ }
+ if (current->type != C_VIEW && current->type != C_CONTAINER) {
+ return cmd_results_new(CMD_INVALID, "resize",
+ "Can only resize views/containers");
+ }
+
+ struct cmd_results *error;
+ if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) {
+ return error;
+ }
+
+ if (strcasecmp(argv[0], "set") == 0) {
+ return cmd_resize_set(argc - 1, &argv[1]);
+ }
+ if (strcasecmp(argv[0], "grow") == 0) {
+ return cmd_resize_adjust(argc - 1, &argv[1], 1);
+ }
+ if (strcasecmp(argv[0], "shrink") == 0) {
+ return cmd_resize_adjust(argc - 1, &argv[1], -1);
+ }
+
+ const char *usage = "Expected 'resize <shrink|grow> "
+ "<width|height|up|down|left|right> [<amount>] [px|ppt]'";
+
+ return cmd_results_new(CMD_INVALID, "resize", usage);
}