aboutsummaryrefslogtreecommitdiffstats
path: root/sway/commands/resize.c
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-07-13 18:06:11 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-07-14 10:00:39 +1000
commit5940682f404a0c6bcf35ff838f2799d47d7c9955 (patch)
treed8c6e43105b8e84dc8061272081a33c5c0dbd7bb /sway/commands/resize.c
parentImplement resize command for floating views (diff)
downloadsway-5940682f404a0c6bcf35ff838f2799d47d7c9955.tar.gz
sway-5940682f404a0c6bcf35ff838f2799d47d7c9955.tar.zst
sway-5940682f404a0c6bcf35ff838f2799d47d7c9955.zip
Implement resize grow|shrink <direction> <amount> or <amount>
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 {
29 RESIZE_AXIS_INVALID, 29 RESIZE_AXIS_INVALID,
30}; 30};
31 31
32struct resize_amount {
33 int amount;
34 enum resize_unit unit;
35};
36
32static enum resize_unit parse_resize_unit(const char *unit) { 37static enum resize_unit parse_resize_unit(const char *unit) {
33 if (strcasecmp(unit, "px") == 0) { 38 if (strcasecmp(unit, "px") == 0) {
34 return RESIZE_UNIT_PX; 39 return RESIZE_UNIT_PX;
@@ -42,6 +47,30 @@ static enum resize_unit parse_resize_unit(const char *unit) {
42 return RESIZE_UNIT_INVALID; 47 return RESIZE_UNIT_INVALID;
43} 48}
44 49
50// Parse arguments such as "10", "10px" or "10 px".
51// Returns the number of arguments consumed.
52static int parse_resize_amount(int argc, char **argv,
53 struct resize_amount *amount) {
54 char *err;
55 amount->amount = (int)strtol(argv[0], &err, 10);
56 if (*err) {
57 // e.g. 10px
58 amount->unit = parse_resize_unit(err);
59 return 1;
60 }
61 if (argc == 1) {
62 amount->unit = RESIZE_UNIT_DEFAULT;
63 return 1;
64 }
65 // Try the second argument
66 amount->unit = parse_resize_unit(argv[1]);
67 if (amount->unit == RESIZE_UNIT_INVALID) {
68 amount->unit = RESIZE_UNIT_DEFAULT;
69 return 1;
70 }
71 return 2;
72}
73
45static enum resize_axis parse_resize_axis(const char *axis) { 74static enum resize_axis parse_resize_axis(const char *axis) {
46 if (strcasecmp(axis, "width") == 0 || strcasecmp(axis, "horizontal") == 0) { 75 if (strcasecmp(axis, "width") == 0 || strcasecmp(axis, "horizontal") == 0) {
47 return RESIZE_AXIS_HORIZONTAL; 76 return RESIZE_AXIS_HORIZONTAL;
@@ -202,36 +231,39 @@ static void resize_tiled(int amount, enum resize_axis axis) {
202 arrange_and_commit(parent->parent); 231 arrange_and_commit(parent->parent);
203} 232}
204 233
205static void resize_floating(int amount, enum resize_axis axis) { 234/**
235 * Implement `resize <grow|shrink>` for a floating container.
236 */
237static struct cmd_results *resize_adjust_floating(enum resize_axis axis,
238 struct resize_amount *amount) {
206 struct sway_container *con = config->handler_context.current_container; 239 struct sway_container *con = config->handler_context.current_container;
207 int grow_x = 0, grow_y = 0; 240 int grow_x = 0, grow_y = 0;
208 int grow_width = 0, grow_height = 0; 241 int grow_width = 0, grow_height = 0;
209 switch (axis) { 242 switch (axis) {
210 case RESIZE_AXIS_HORIZONTAL: 243 case RESIZE_AXIS_HORIZONTAL:
211 grow_x = -amount / 2; 244 grow_x = -amount->amount / 2;
212 grow_width = amount; 245 grow_width = amount->amount;
213 break; 246 break;
214 case RESIZE_AXIS_VERTICAL: 247 case RESIZE_AXIS_VERTICAL:
215 grow_y = -amount / 2; 248 grow_y = -amount->amount / 2;
216 grow_height = amount; 249 grow_height = amount->amount;
217 break; 250 break;
218 case RESIZE_AXIS_UP: 251 case RESIZE_AXIS_UP:
219 grow_y = -amount; 252 grow_y = -amount->amount;
220 grow_height = amount; 253 grow_height = amount->amount;
221 break; 254 break;
222 case RESIZE_AXIS_LEFT: 255 case RESIZE_AXIS_LEFT:
223 grow_x = -amount; 256 grow_x = -amount->amount;
224 grow_width = amount; 257 grow_width = amount->amount;
225 break; 258 break;
226 case RESIZE_AXIS_DOWN: 259 case RESIZE_AXIS_DOWN:
227 grow_height = amount; 260 grow_height = amount->amount;
228 break; 261 break;
229 case RESIZE_AXIS_RIGHT: 262 case RESIZE_AXIS_RIGHT:
230 grow_width = amount; 263 grow_width = amount->amount;
231 break; 264 break;
232 case RESIZE_AXIS_INVALID: 265 case RESIZE_AXIS_INVALID:
233 sway_assert(false, "Didn't expect RESIZE_AXIS_INVALID"); 266 return cmd_results_new(CMD_INVALID, "resize", "Invalid axis/direction");
234 return;
235 } 267 }
236 con->x += grow_x; 268 con->x += grow_x;
237 con->y += grow_y; 269 con->y += grow_y;
@@ -247,80 +279,64 @@ static void resize_floating(int amount, enum resize_axis axis) {
247 } 279 }
248 280
249 arrange_and_commit(con); 281 arrange_and_commit(con);
282
283 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
250} 284}
251 285
252static void resize(int amount, enum resize_axis axis, enum resize_unit unit) { 286/**
287 * Implement `resize <grow|shrink>` for a tiled container.
288 */
289static struct cmd_results *resize_adjust_tiled(enum resize_axis axis,
290 struct resize_amount *amount) {
253 struct sway_container *current = config->handler_context.current_container; 291 struct sway_container *current = config->handler_context.current_container;
254 if (container_is_floating(current)) {
255 return resize_floating(amount, axis);
256 }
257 292
258 if (unit == RESIZE_UNIT_DEFAULT) { 293 if (amount->unit == RESIZE_UNIT_DEFAULT) {
259 unit = RESIZE_UNIT_PPT; 294 amount->unit = RESIZE_UNIT_PPT;
260 } 295 }
261 if (unit == RESIZE_UNIT_PPT) { 296 if (amount->unit == RESIZE_UNIT_PPT) {
262 float pct = amount / 100.0f; 297 float pct = amount->amount / 100.0f;
298 // TODO: Make left/right/up/down resize in that direction?
263 switch (axis) { 299 switch (axis) {
300 case RESIZE_AXIS_LEFT:
301 case RESIZE_AXIS_RIGHT:
264 case RESIZE_AXIS_HORIZONTAL: 302 case RESIZE_AXIS_HORIZONTAL:
265 amount = (float)current->width * pct; 303 amount->amount = (float)current->width * pct;
266 break; 304 break;
305 case RESIZE_AXIS_UP:
306 case RESIZE_AXIS_DOWN:
267 case RESIZE_AXIS_VERTICAL: 307 case RESIZE_AXIS_VERTICAL:
268 amount = (float)current->height * pct; 308 amount->amount = (float)current->height * pct;
269 break; 309 break;
270 default: 310 case RESIZE_AXIS_INVALID:
271 sway_assert(0, "invalid resize axis"); 311 return cmd_results_new(CMD_INVALID, "resize",
272 return; 312 "Invalid resize axis/direction");
273 } 313 }
274 } 314 }
275 315
276 return resize_tiled(amount, axis); 316 resize_tiled(amount->amount, axis);
317 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
277} 318}
278 319
279// resize set <width> [px|ppt] <height> [px|ppt] 320/**
280static struct cmd_results *cmd_resize_set(int argc, char **argv) { 321 * Implement `resize set` for a tiled container.
281 struct cmd_results *error; 322 */
282 if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { 323static struct cmd_results *resize_set_tiled(struct sway_container *con,
283 return error; 324 struct resize_amount *width, struct resize_amount *height) {
284 } 325 return cmd_results_new(CMD_INVALID, "resize",
285 struct sway_container *con = config->handler_context.current_container; 326 "'resize set' is not implemented for tiled views");
286 if (!container_is_floating(con)) { 327}
287 return cmd_results_new(CMD_INVALID, "resize",
288 "resize set is not currently supported for tiled containers");
289 }
290 const char *usage = "Expected 'resize set <width> <height>'";
291
292 char *err;
293 size_t width = (int)strtol(*argv, &err, 10);
294 if (*err) {
295 // e.g. `resize set width 500px`
296 enum resize_unit unit = parse_resize_unit(err);
297 if (unit == RESIZE_UNIT_INVALID) {
298 return cmd_results_new(CMD_INVALID, "resize", usage);
299 }
300 }
301 --argc; ++argv;
302 if (parse_resize_unit(argv[0]) != RESIZE_UNIT_INVALID) {
303 --argc; ++argv;
304 }
305
306 if (!argc) {
307 return cmd_results_new(CMD_INVALID, "resize", usage);
308 }
309 size_t height = (int)strtol(*argv, &err, 10);
310 if (*err) {
311 // e.g. `resize set height 500px`
312 enum resize_unit unit = parse_resize_unit(err);
313 if (unit == RESIZE_UNIT_INVALID) {
314 return cmd_results_new(CMD_INVALID, "resize", usage);
315 }
316 }
317 328
318 int grow_width = width - con->width; 329/**
319 int grow_height = height - con->height; 330 * Implement `resize set` for a floating container.
331 */
332static struct cmd_results *resize_set_floating(struct sway_container *con,
333 struct resize_amount *width, struct resize_amount *height) {
334 int grow_width = width->amount - con->width;
335 int grow_height = height->amount - con->height;
320 con->x -= grow_width / 2; 336 con->x -= grow_width / 2;
321 con->y -= grow_height / 2; 337 con->y -= grow_height / 2;
322 con->width = width; 338 con->width = width->amount;
323 con->height = height; 339 con->height = height->amount;
324 340
325 if (con->type == C_VIEW) { 341 if (con->type == C_VIEW) {
326 struct sway_view *view = con->sway_view; 342 struct sway_view *view = con->sway_view;
@@ -335,73 +351,168 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) {
335 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 351 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
336} 352}
337 353
338struct cmd_results *cmd_resize(int argc, char **argv) { 354/**
339 struct sway_container *current = config->handler_context.current_container; 355 * resize set <args>
340 if (!current) { 356 *
341 return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing"); 357 * args: <width> [px|ppt] <height> [px|ppt]
342 } 358 */
343 if (current->type != C_VIEW && current->type != C_CONTAINER) { 359static struct cmd_results *cmd_resize_set(int argc, char **argv) {
344 return cmd_results_new(CMD_INVALID, "resize",
345 "Can only resize views/containers");
346 }
347
348 struct cmd_results *error; 360 struct cmd_results *error;
349 if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { 361 if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) {
350 return error; 362 return error;
351 } 363 }
364 const char *usage = "Expected 'resize set <width> <height>'";
352 365
353 if (strcasecmp(argv[0], "set") == 0) { 366 // Width
354 return cmd_resize_set(argc - 1, &argv[1]); 367 struct resize_amount width;
368 int num_consumed_args = parse_resize_amount(argc, argv, &width);
369 argc -= num_consumed_args;
370 argv += num_consumed_args;
371 if (width.unit == RESIZE_UNIT_INVALID) {
372 return cmd_results_new(CMD_INVALID, "resize", usage);
373 }
374 if (!argc) {
375 return cmd_results_new(CMD_INVALID, "resize", usage);
355 } 376 }
356 377
357 const char *usage = "Expected 'resize <shrink|grow> " 378 // Height
358 "<width|height|up|down|left|right> [<amount>] [px|ppt]'"; 379 struct resize_amount height;
359 380 num_consumed_args = parse_resize_amount(argc, argv, &height);
360 int multiplier = 0; 381 argc -= num_consumed_args;
361 if (strcasecmp(*argv, "grow") == 0) { 382 argv += num_consumed_args;
362 multiplier = 1; 383 if (height.unit == RESIZE_UNIT_INVALID) {
363 } else if (strcasecmp(*argv, "shrink") == 0) {
364 multiplier = -1;
365 } else {
366 return cmd_results_new(CMD_INVALID, "resize", usage); 384 return cmd_results_new(CMD_INVALID, "resize", usage);
367 } 385 }
368 --argc; ++argv;
369 386
387 // If 0, don't resize that dimension
388 struct sway_container *con = config->handler_context.current_container;
389 if (width.amount <= 0) {
390 width.amount = con->width;
391 }
392 if (height.amount <= 0) {
393 height.amount = con->height;
394 }
395
396 if (container_is_floating(con)) {
397 return resize_set_floating(con, &width, &height);
398 }
399 return resize_set_tiled(con, &width, &height);
400}
401
402/**
403 * resize <grow|shrink> <args>
404 *
405 * args: <direction>
406 * args: <direction> <amount> <unit>
407 * args: <direction> <amount> <unit> or <amount> <other_unit>
408 */
409static struct cmd_results *cmd_resize_adjust(int argc, char **argv,
410 int multiplier) {
411 const char *usage = "Expected 'resize grow|shrink <direction> "
412 "[<amount> px|ppt [or <amount> px|ppt]]'";
370 enum resize_axis axis = parse_resize_axis(*argv); 413 enum resize_axis axis = parse_resize_axis(*argv);
371 if (axis == RESIZE_AXIS_INVALID) { 414 if (axis == RESIZE_AXIS_INVALID) {
372 return cmd_results_new(CMD_INVALID, "resize", usage); 415 return cmd_results_new(CMD_INVALID, "resize", usage);
373 } 416 }
374 --argc; ++argv; 417 --argc; ++argv;
375 418
376 int amount = 10; // Default amount 419 // First amount
377 enum resize_unit unit = RESIZE_UNIT_DEFAULT; 420 struct resize_amount first_amount;
378
379 if (argc) { 421 if (argc) {
380 char *err; 422 int num_consumed_args = parse_resize_amount(argc, argv, &first_amount);
381 amount = (int)strtol(*argv, &err, 10); 423 argc -= num_consumed_args;
382 if (*err) { 424 argv += num_consumed_args;
383 // e.g. `resize grow width 10px` 425 if (first_amount.unit == RESIZE_UNIT_INVALID) {
384 unit = parse_resize_unit(err); 426 return cmd_results_new(CMD_INVALID, "resize", usage);
385 if (unit == RESIZE_UNIT_INVALID) {
386 return cmd_results_new(CMD_INVALID, "resize", usage);
387 }
388 } 427 }
389 --argc; ++argv; 428 } else {
429 first_amount.amount = 10;
430 first_amount.unit = RESIZE_UNIT_DEFAULT;
390 } 431 }
391 432
433 // "or"
392 if (argc) { 434 if (argc) {
393 unit = parse_resize_unit(*argv); 435 if (strcmp(*argv, "or") != 0) {
394 if (unit == RESIZE_UNIT_INVALID) {
395 return cmd_results_new(CMD_INVALID, "resize", usage); 436 return cmd_results_new(CMD_INVALID, "resize", usage);
396 } 437 }
397 --argc; ++argv; 438 --argc; ++argv;
398 } 439 }
399 440
441 // Second amount
442 struct resize_amount second_amount;
400 if (argc) { 443 if (argc) {
401 // Provied too many args, the bastard 444 int num_consumed_args = parse_resize_amount(argc, argv, &second_amount);
402 return cmd_results_new(CMD_INVALID, "resize", usage); 445 argc -= num_consumed_args;
446 argv += num_consumed_args;
447 if (second_amount.unit == RESIZE_UNIT_INVALID) {
448 return cmd_results_new(CMD_INVALID, "resize", usage);
449 }
450 } else {
451 second_amount.unit = RESIZE_UNIT_INVALID;
403 } 452 }
404 453
405 resize(amount * multiplier, axis, unit); 454 first_amount.amount *= multiplier;
406 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 455 second_amount.amount *= multiplier;
456
457 struct sway_container *con = config->handler_context.current_container;
458 if (container_is_floating(con)) {
459 // Floating containers can only resize in px. Choose an amount which
460 // uses px, with fallback to an amount that specified no unit.
461 if (first_amount.unit == RESIZE_UNIT_PX) {
462 return resize_adjust_floating(axis, &first_amount);
463 } else if (second_amount.unit == RESIZE_UNIT_PX) {
464 return resize_adjust_floating(axis, &second_amount);
465 } else if (first_amount.unit == RESIZE_UNIT_DEFAULT) {
466 return resize_adjust_floating(axis, &first_amount);
467 } else if (second_amount.unit == RESIZE_UNIT_DEFAULT) {
468 return resize_adjust_floating(axis, &second_amount);
469 } else {
470 return cmd_results_new(CMD_INVALID, "resize",
471 "Floating containers cannot use ppt measurements");
472 }
473 }
474
475 // For tiling, prefer ppt -> default -> px
476 if (first_amount.unit == RESIZE_UNIT_PPT) {
477 return resize_adjust_tiled(axis, &first_amount);
478 } else if (second_amount.unit == RESIZE_UNIT_PPT) {
479 return resize_adjust_tiled(axis, &second_amount);
480 } else if (first_amount.unit == RESIZE_UNIT_DEFAULT) {
481 return resize_adjust_tiled(axis, &first_amount);
482 } else if (second_amount.unit == RESIZE_UNIT_DEFAULT) {
483 return resize_adjust_tiled(axis, &second_amount);
484 } else {
485 return resize_adjust_tiled(axis, &first_amount);
486 }
487}
488
489struct cmd_results *cmd_resize(int argc, char **argv) {
490 struct sway_container *current = config->handler_context.current_container;
491 if (!current) {
492 return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing");
493 }
494 if (current->type != C_VIEW && current->type != C_CONTAINER) {
495 return cmd_results_new(CMD_INVALID, "resize",
496 "Can only resize views/containers");
497 }
498
499 struct cmd_results *error;
500 if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) {
501 return error;
502 }
503
504 if (strcasecmp(argv[0], "set") == 0) {
505 return cmd_resize_set(argc - 1, &argv[1]);
506 }
507 if (strcasecmp(argv[0], "grow") == 0) {
508 return cmd_resize_adjust(argc - 1, &argv[1], 1);
509 }
510 if (strcasecmp(argv[0], "shrink") == 0) {
511 return cmd_resize_adjust(argc - 1, &argv[1], -1);
512 }
513
514 const char *usage = "Expected 'resize <shrink|grow> "
515 "<width|height|up|down|left|right> [<amount>] [px|ppt]'";
516
517 return cmd_results_new(CMD_INVALID, "resize", usage);
407} 518}