diff options
author | Ronan Pigott <rpigott@berkeley.edu> | 2020-12-04 19:56:51 -0700 |
---|---|---|
committer | Tudor Brindus <me@tbrindus.ca> | 2020-12-20 00:58:42 -0500 |
commit | 5f1fe33d369b88539c9fb434703c1c00cd26c903 (patch) | |
tree | c59850f93654d8916226c9402409efdd0871af61 | |
parent | commands/move: reset geometry of promoted containers (diff) | |
download | sway-5f1fe33d369b88539c9fb434703c1c00cd26c903.tar.gz sway-5f1fe33d369b88539c9fb434703c1c00cd26c903.tar.zst sway-5f1fe33d369b88539c9fb434703c1c00cd26c903.zip |
workspace: rework workspace prev|next like i3
Changes workspace prev|next commands to visit each numbered or named
workspace first before considering workspace from the other category
-rw-r--r-- | sway/tree/workspace.c | 176 |
1 files changed, 142 insertions, 34 deletions
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 62549434..921b7d19 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -382,6 +382,148 @@ struct sway_workspace *workspace_by_name(const char *name) { | |||
382 | } | 382 | } |
383 | } | 383 | } |
384 | 384 | ||
385 | static int workspace_get_number(struct sway_workspace *workspace) { | ||
386 | char *endptr = NULL; | ||
387 | errno = 0; | ||
388 | long long n = strtoll(workspace->name, &endptr, 10); | ||
389 | if (errno != 0 || n > INT32_MAX || n < 0 || endptr == workspace->name) { | ||
390 | n = -1; | ||
391 | } | ||
392 | return n; | ||
393 | } | ||
394 | |||
395 | struct sway_workspace *workspace_prev(struct sway_workspace *workspace) { | ||
396 | int n = workspace_get_number(workspace); | ||
397 | struct sway_workspace *prev = NULL, *last = NULL, *other = NULL; | ||
398 | bool found = false; | ||
399 | if (n < 0) { | ||
400 | // Find the prev named workspace | ||
401 | int othern = -1; | ||
402 | for (int i = root->outputs->length - 1; i >= 0; i--) { | ||
403 | struct sway_output *output = root->outputs->items[i]; | ||
404 | for (int j = output->workspaces->length - 1; j >= 0; j--) { | ||
405 | struct sway_workspace *ws = output->workspaces->items[j]; | ||
406 | int wsn = workspace_get_number(ws); | ||
407 | if (!last) { | ||
408 | // The first workspace in reverse order | ||
409 | last = ws; | ||
410 | } | ||
411 | if (!other || (wsn >= 0 && wsn > othern)) { | ||
412 | // The last (greatest) numbered workspace. | ||
413 | other = ws; | ||
414 | othern = workspace_get_number(other); | ||
415 | } | ||
416 | if (ws == workspace) { | ||
417 | found = true; | ||
418 | } else if (wsn < 0 && found) { | ||
419 | // Found a non-numbered workspace before current | ||
420 | return ws; | ||
421 | } | ||
422 | } | ||
423 | } | ||
424 | } else { | ||
425 | // Find the prev numbered workspace | ||
426 | int prevn = -1, lastn = -1; | ||
427 | for (int i = root->outputs->length - 1; i >= 0; i--) { | ||
428 | struct sway_output *output = root->outputs->items[i]; | ||
429 | for (int j = output->workspaces->length - 1; j >= 0; j--) { | ||
430 | struct sway_workspace *ws = output->workspaces->items[j]; | ||
431 | int wsn = workspace_get_number(ws); | ||
432 | if (!last || (wsn >= 0 && wsn > lastn)) { | ||
433 | // The greatest numbered (or last) workspace | ||
434 | last = ws; | ||
435 | lastn = workspace_get_number(last); | ||
436 | } | ||
437 | if (!other && wsn < 0) { | ||
438 | // The last named workspace | ||
439 | other = ws; | ||
440 | } | ||
441 | if (wsn < 0) { | ||
442 | // Haven't reached the numbered workspaces | ||
443 | continue; | ||
444 | } | ||
445 | if (wsn < n && (!prev || wsn > prevn)) { | ||
446 | // The closest workspace before the current | ||
447 | prev = ws; | ||
448 | prevn = workspace_get_number(prev); | ||
449 | } | ||
450 | } | ||
451 | } | ||
452 | } | ||
453 | |||
454 | if (!prev) { | ||
455 | prev = other ? other : last; | ||
456 | } | ||
457 | return prev; | ||
458 | } | ||
459 | |||
460 | struct sway_workspace *workspace_next(struct sway_workspace *workspace) { | ||
461 | int n = workspace_get_number(workspace); | ||
462 | struct sway_workspace *next = NULL, *first = NULL, *other = NULL; | ||
463 | bool found = false; | ||
464 | if (n < 0) { | ||
465 | // Find the next named workspace | ||
466 | int othern = -1; | ||
467 | for (int i = 0; i < root->outputs->length; i++) { | ||
468 | struct sway_output *output = root->outputs->items[i]; | ||
469 | for (int j = 0; j < output->workspaces->length; j++) { | ||
470 | struct sway_workspace *ws = output->workspaces->items[j]; | ||
471 | int wsn = workspace_get_number(ws); | ||
472 | if (!first) { | ||
473 | // The first named workspace | ||
474 | first = ws; | ||
475 | } | ||
476 | if (!other || (wsn >= 0 && wsn < othern)) { | ||
477 | // The first (least) numbered workspace | ||
478 | other = ws; | ||
479 | othern = workspace_get_number(other); | ||
480 | } | ||
481 | if (ws == workspace) { | ||
482 | found = true; | ||
483 | } else if (wsn < 0 && found) { | ||
484 | // The first non-numbered workspace after the current | ||
485 | return ws; | ||
486 | } | ||
487 | } | ||
488 | } | ||
489 | } else { | ||
490 | // Find the next numbered workspace | ||
491 | int nextn = -1, firstn = -1; | ||
492 | for (int i = 0; i < root->outputs->length; i++) { | ||
493 | struct sway_output *output = root->outputs->items[i]; | ||
494 | for (int j = 0; j < output->workspaces->length; j++) { | ||
495 | struct sway_workspace *ws = output->workspaces->items[j]; | ||
496 | int wsn = workspace_get_number(ws); | ||
497 | if (!first || (wsn >= 0 && wsn < firstn)) { | ||
498 | // The first (or least numbered) workspace | ||
499 | first = ws; | ||
500 | firstn = workspace_get_number(first); | ||
501 | } | ||
502 | if (!other && wsn < 0) { | ||
503 | // The first non-numbered workspace | ||
504 | other = ws; | ||
505 | } | ||
506 | if (wsn < 0) { | ||
507 | // Checked all the numbered workspaces | ||
508 | break; | ||
509 | } | ||
510 | if (n < wsn && (!next || wsn < nextn)) { | ||
511 | // The first workspace numerically after the current | ||
512 | next = ws; | ||
513 | nextn = workspace_get_number(next); | ||
514 | } | ||
515 | } | ||
516 | } | ||
517 | } | ||
518 | |||
519 | if (!next) { | ||
520 | // If there is no next workspace from the same category, return the | ||
521 | // first from this category. | ||
522 | next = other ? other : first; | ||
523 | } | ||
524 | return next; | ||
525 | } | ||
526 | |||
385 | /** | 527 | /** |
386 | * Get the previous or next workspace on the specified output. Wraps around at | 528 | * Get the previous or next workspace on the specified output. Wraps around at |
387 | * the end and beginning. If next is false, the previous workspace is returned, | 529 | * the end and beginning. If next is false, the previous workspace is returned, |
@@ -409,50 +551,16 @@ static struct sway_workspace *workspace_output_prev_next_impl( | |||
409 | return output->workspaces->items[new_index]; | 551 | return output->workspaces->items[new_index]; |
410 | } | 552 | } |
411 | 553 | ||
412 | /** | ||
413 | * Get the previous or next workspace. If the first/last workspace on an output | ||
414 | * is active, proceed to the previous/next output's previous/next workspace. | ||
415 | */ | ||
416 | static struct sway_workspace *workspace_prev_next_impl( | ||
417 | struct sway_workspace *workspace, int dir) { | ||
418 | struct sway_output *output = workspace->output; | ||
419 | int index = list_find(output->workspaces, workspace); | ||
420 | int new_index = index + dir; | ||
421 | |||
422 | if (new_index >= 0 && new_index < output->workspaces->length) { | ||
423 | return output->workspaces->items[new_index]; | ||
424 | } | ||
425 | |||
426 | // Look on a different output | ||
427 | int output_index = list_find(root->outputs, output); | ||
428 | new_index = wrap(output_index + dir, root->outputs->length); | ||
429 | output = root->outputs->items[new_index]; | ||
430 | |||
431 | if (dir == 1) { | ||
432 | return output->workspaces->items[0]; | ||
433 | } else { | ||
434 | return output->workspaces->items[output->workspaces->length - 1]; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | struct sway_workspace *workspace_output_next( | 554 | struct sway_workspace *workspace_output_next( |
439 | struct sway_workspace *current, bool create) { | 555 | struct sway_workspace *current, bool create) { |
440 | return workspace_output_prev_next_impl(current->output, 1, create); | 556 | return workspace_output_prev_next_impl(current->output, 1, create); |
441 | } | 557 | } |
442 | 558 | ||
443 | struct sway_workspace *workspace_next(struct sway_workspace *current) { | ||
444 | return workspace_prev_next_impl(current, 1); | ||
445 | } | ||
446 | |||
447 | struct sway_workspace *workspace_output_prev( | 559 | struct sway_workspace *workspace_output_prev( |
448 | struct sway_workspace *current, bool create) { | 560 | struct sway_workspace *current, bool create) { |
449 | return workspace_output_prev_next_impl(current->output, -1, create); | 561 | return workspace_output_prev_next_impl(current->output, -1, create); |
450 | } | 562 | } |
451 | 563 | ||
452 | struct sway_workspace *workspace_prev(struct sway_workspace *current) { | ||
453 | return workspace_prev_next_impl(current, -1); | ||
454 | } | ||
455 | |||
456 | bool workspace_switch(struct sway_workspace *workspace, | 564 | bool workspace_switch(struct sway_workspace *workspace, |
457 | bool no_auto_back_and_forth) { | 565 | bool no_auto_back_and_forth) { |
458 | struct sway_seat *seat = input_manager_current_seat(); | 566 | struct sway_seat *seat = input_manager_current_seat(); |