sway icon indicating copy to clipboard operation
sway copied to clipboard

Add --no-wrap flag to next/prev[_on_output]

Open Lykos153 opened this issue 3 years ago • 4 comments

  • Description: Please add a --no-wrap flag to next, prev, next_on_output, prev_on_output. I have currently implemented this via a script, but it's noticeably slower than the native commands. Use case is to get quickly and reliably to the first resp. last workspace (on the output).

Lykos153 avatar Jan 10 '22 04:01 Lykos153

It's been "accepted" by i3 so if someone does the work to implement it there then it can be accepted over here as well for i3-compat reasons. Still requires someone to do the work though, but it might be trivial enough for you to give it ago.

https://github.com/i3/i3/issues/3900

ammgws avatar Jan 10 '22 07:01 ammgws

I quickly hacked it in, but getting it in there properly as --no-wrap will require some refactoring

untested patch
From 9b0393234beb5b6bc872cdc0577c9bedaa4dd692 Mon Sep 17 00:00:00 2001
From: minus <[email protected]>
Date: Sun, 21 Aug 2022 15:56:00 +0200
Subject: [PATCH] Add prev/next_on_output no-wrap variants

---
 common/util.c                 |  6 ++++++
 include/sway/tree/workspace.h |  4 ++--
 include/util.h                |  5 +++++
 sway/tree/workspace.c         | 28 +++++++++++++++++-----------
 4 files changed, 30 insertions(+), 13 deletions(-)

diff --git a/common/util.c b/common/util.c
index 5d4c0673..5f676d8b 100644
--- a/common/util.c
+++ b/common/util.c
@@ -14,6 +14,12 @@ int wrap(int i, int max) {
 	return ((i % max) + max) % max;
 }
 
+int clamp(int i, int max) {
+	if (i < 0) return 0;
+	else if (i > max) return max;
+	else return i;
+}
+
 bool parse_color(const char *color, uint32_t *result) {
 	if (color[0] == '#') {
 		++color;
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h
index b3d93a81..5f43c8a0 100644
--- a/include/sway/tree/workspace.h
+++ b/include/sway/tree/workspace.h
@@ -69,11 +69,11 @@ struct sway_workspace *workspace_by_number(const char* name);
 
 struct sway_workspace *workspace_by_name(const char*);
 
-struct sway_workspace *workspace_output_next(struct sway_workspace *current);
+struct sway_workspace *workspace_output_next(struct sway_workspace *current, bool wraparound);
 
 struct sway_workspace *workspace_next(struct sway_workspace *current);
 
-struct sway_workspace *workspace_output_prev(struct sway_workspace *current);
+struct sway_workspace *workspace_output_prev(struct sway_workspace *current, bool wraparound);
 
 struct sway_workspace *workspace_prev(struct sway_workspace *current);
 
diff --git a/include/util.h b/include/util.h
index f887d489..2e8fbc88 100644
--- a/include/util.h
+++ b/include/util.h
@@ -34,6 +34,11 @@ int parse_movement_amount(int argc, char **argv,
  */
 int wrap(int i, int max);
 
+/**
+ * Clamp i into the range [0, max]
+ */
+int clamp(int i, int max);
+
 /**
  * Given a string that represents an RGB(A) color, result will be set to a
  * uint32_t version of the color, as long as it is valid. If it is invalid,
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index c84320bd..bd103fd8 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -361,11 +361,15 @@ struct sway_workspace *workspace_by_name(const char *name) {
 	if (current && strcmp(name, "prev") == 0) {
 		return workspace_prev(current);
 	} else if (current && strcmp(name, "prev_on_output") == 0) {
-		return workspace_output_prev(current);
+		return workspace_output_prev(current, true);
+	} else if (current && strcmp(name, "prev_on_output_nowrap") == 0) {
+		return workspace_output_prev(current, false);
 	} else if (current && strcmp(name, "next") == 0) {
 		return workspace_next(current);
 	} else if (current && strcmp(name, "next_on_output") == 0) {
-		return workspace_output_next(current);
+		return workspace_output_next(current, true);
+	} else if (current && strcmp(name, "next_on_output_nowrap") == 0) {
+		return workspace_output_next(current, false);
 	} else if (strcmp(name, "current") == 0) {
 		return current;
 	} else if (strcasecmp(name, "back_and_forth") == 0) {
@@ -523,12 +527,12 @@ struct sway_workspace *workspace_next(struct sway_workspace *workspace) {
 }
 
 /**
- * Get the previous or next workspace on the specified output. Wraps around at
- * the end and beginning.  If next is false, the previous workspace is returned,
- * otherwise the next one is returned.
+ * Get the previous or next workspace on the specified output. Stops at the
+ * first and last workspace if wraparound is false, otherwise wraps around at
+ * the end and beginning.
  */
 static struct sway_workspace *workspace_output_prev_next_impl(
-		struct sway_output *output, int dir) {
+		struct sway_output *output, int dir, bool wraparound) {
 	struct sway_seat *seat = input_manager_current_seat();
 	struct sway_workspace *workspace = seat_get_focused_workspace(seat);
 	if (!workspace) {
@@ -538,17 +542,19 @@ static struct sway_workspace *workspace_output_prev_next_impl(
 	}
 
 	int index = list_find(output->workspaces, workspace);
-	size_t new_index = wrap(index + dir, output->workspaces->length);
+	size_t new_index = wraparound
+		? wrap(index + dir, output->workspaces->length)
+		: clamp(index + dir, output->workspaces->length);
 	return output->workspaces->items[new_index];
 }
 
 
-struct sway_workspace *workspace_output_next(struct sway_workspace *current) {
-	return workspace_output_prev_next_impl(current->output, 1);
+struct sway_workspace *workspace_output_next(struct sway_workspace *current, bool wraparound) {
+	return workspace_output_prev_next_impl(current->output, 1, wraparound);
 }
 
-struct sway_workspace *workspace_output_prev(struct sway_workspace *current) {
-	return workspace_output_prev_next_impl(current->output, -1);
+struct sway_workspace *workspace_output_prev(struct sway_workspace *current, bool wraparound) {
+	return workspace_output_prev_next_impl(current->output, -1, wraparound);
 }
 
 struct sway_workspace *workspace_auto_back_and_forth(
-- 
2.37.2

minus7 avatar Aug 21 '22 14:08 minus7

for reference, in i3 one can use focus_wrapping no to disable focus wrapping

Inc0n avatar Jul 05 '23 14:07 Inc0n

It would be great to have some way of separate wrapping control for directional and sequential (previous/next) focus changes. Wrapping control on focus command itself would be even more universal solution.

Vladimir-csp avatar Mar 24 '24 16:03 Vladimir-csp