f72c5d0b480bf0ac77b0bf7e637d44be46045d63

Author
outfoxxed <outfoxxed@outfoxxed.me>
Committer
outfoxxed <outfoxxed@outfoxxed.me>
Date

Message

Add `once` option to movewindow

Diff

  1diff --git a/README.md b/README.md
  2index a89f0691db3d27b6f06075779a51d4805a95cd95..66a11467a3388fc82168f7291bdc11c4ffcb2597 100644
  3--- a/README.md
  4+++ b/README.md
  5@@ -33,8 +33,9 @@ You can use `hy3:makegroup` to create a new split.
  6 
  7 ### Dispatcher list
  8  - `hy3:makegroup, <h | v | opposite>` - make a vertical or horizontal split
  9- - `hy3:movefocus, <l | u | d | r>` - move the focus left, up, down, or right
 10- - `hy3:movewindow, <l | u | d | r>` - move a window left, up, down, or right
 11+ - `hy3:movefocus, <l | u | d | r | left | down | up | right>` - move the focus left, up, down, or right
 12+ - `hy3:movewindow, <l | u | d | r | left | down | up | right> [, once]` - move a window left, up, down, or right
 13+   - `once` - only move directly to the neighboring group, without moving into any of its subgroups
 14  - `hy3:raisefocus` - raise the active focus one level
 15  - `hy3:debugnodes` - print the node tree into the hyprland log
 16 
 17diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp
 18index 1237db355527eec83803901cdb2bdb06ee05916a..9d8b4bd579286ed5bccde0bab59b59328f29836a 100644
 19--- a/src/Hy3Layout.cpp
 20+++ b/src/Hy3Layout.cpp
 21@@ -1127,26 +1127,24 @@ void Hy3Layout::makeOppositeGroupOn(Hy3Node* node) {
 22 	}
 23 }
 24 
 25-Hy3Node* shiftOrGetFocus(Hy3Node& node, ShiftDirection direction, bool shift);
 26-
 27 void Hy3Layout::shiftFocus(int workspace, ShiftDirection direction) {
 28 	auto* node = this->getWorkspaceFocusedNode(workspace);
 29 	Debug::log(LOG, "ShiftFocus %p %d", node, direction);
 30 	if (node == nullptr) return;
 31 
 32 	Hy3Node* target;
 33-	if ((target = this->shiftOrGetFocus(*node, direction, false))) {
 34+	if ((target = this->shiftOrGetFocus(*node, direction, false, false))) {
 35 		g_pCompositor->focusWindow(target->data.as_window);
 36 	}
 37 }
 38 
 39-void Hy3Layout::shiftWindow(int workspace, ShiftDirection direction) {
 40+void Hy3Layout::shiftWindow(int workspace, ShiftDirection direction, bool once) {
 41 	auto* node = this->getWorkspaceFocusedNode(workspace);
 42 	Debug::log(LOG, "ShiftWindow %p %d", node, direction);
 43 	if (node == nullptr) return;
 44 
 45 
 46-	this->shiftOrGetFocus(*node, direction, true);
 47+	this->shiftOrGetFocus(*node, direction, true, once);
 48 }
 49 
 50 bool shiftIsForward(ShiftDirection direction) {
 51@@ -1162,16 +1160,20 @@ bool shiftMatchesLayout(Hy3GroupLayout layout, ShiftDirection direction) {
 52 		|| (layout != Hy3GroupLayout::SplitV && !shiftIsVertical(direction));
 53 }
 54 
 55-Hy3Node* Hy3Layout::shiftOrGetFocus(Hy3Node& node, ShiftDirection direction, bool shift) {
 56+Hy3Node* Hy3Layout::shiftOrGetFocus(Hy3Node& node, ShiftDirection direction, bool shift, bool once) {
 57 	auto* break_origin = &node;
 58 	auto* break_parent = break_origin->parent;
 59 
 60+	auto has_broken_once = false;
 61+
 62 	// break parents until we hit a container oriented the same way as the shift direction
 63 	while (true) {
 64 		if (break_parent == nullptr) return nullptr;
 65 
 66 		auto& group = break_parent->data.as_group; // must be a group in order to be a parent
 67 
 68+		if (has_broken_once) break;
 69+
 70 		if (shiftMatchesLayout(group.layout, direction)) {
 71 			// group has the correct orientation
 72 
 73@@ -1182,6 +1184,8 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(Hy3Node& node, ShiftDirection direction, boo
 74 				break;
 75 		}
 76 
 77+		has_broken_once = true;
 78+
 79 		if (break_parent->parent == nullptr) {
 80 			if (!shift) return nullptr;
 81 
 82@@ -1233,7 +1237,7 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(Hy3Node& node, ShiftDirection direction, boo
 83 		if (shiftIsForward(direction)) iter = std::next(iter);
 84 		else iter = std::prev(iter);
 85 
 86-		if ((*iter)->data.type == Hy3NodeData::Window) {
 87+		if ((*iter)->data.type == Hy3NodeData::Window || (shift && once && has_broken_once)) {
 88 			if (shift) {
 89 				if (target_group == node.parent) {
 90 					if (shiftIsForward(direction)) insert = std::next(iter);
 91@@ -1270,6 +1274,12 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(Hy3Node& node, ShiftDirection direction, boo
 92 					}
 93 				}
 94 
 95+				if (shift && once) {
 96+					if (shift_after) insert = std::next(iter);
 97+					else insert = iter;
 98+					break;
 99+				}
100+
101 				if ((*iter)->data.type == Hy3NodeData::Window) {
102 					if (shift) {
103 						if (shift_after) insert = std::next(iter);
104diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp
105index 02637afe8af3b9ad37c0338d502d986876698f6b..7b34ae69b6c1710c08461a545d1a13051b9e114a 100644
106--- a/src/Hy3Layout.hpp
107+++ b/src/Hy3Layout.hpp
108@@ -117,7 +117,7 @@ public:
109 	void makeOppositeGroupOnWorkspace(int);
110 	void makeGroupOn(Hy3Node*, Hy3GroupLayout);
111 	void makeOppositeGroupOn(Hy3Node*);
112-	void shiftWindow(int, ShiftDirection);
113+	void shiftWindow(int, ShiftDirection, bool);
114 	void shiftFocus(int, ShiftDirection);
115 	void raiseFocus(int);
116 
117@@ -140,7 +140,8 @@ private:
118 
119 	// if shift is true, shift the window in the given direction, returning nullptr,
120 	// if shift is false, return the window in the given direction or nullptr.
121-	Hy3Node* shiftOrGetFocus(Hy3Node&, ShiftDirection, bool);
122+	// if once is true, only one group will be broken out of / into
123+	Hy3Node* shiftOrGetFocus(Hy3Node&, ShiftDirection, bool, bool);
124 
125 	friend struct Hy3Node;
126 };
127diff --git a/src/main.cpp b/src/main.cpp
128index 6c6c47697344617a257aa2e308be26928bef5e22..f299fe92a18322710fded7165d77cb1897035d9a 100644
129--- a/src/main.cpp
130+++ b/src/main.cpp
131@@ -1,3 +1,5 @@
132+#include <optional>
133+
134 #include <hyprland/src/plugins/PluginAPI.hpp>
135 #include <hyprland/src/Compositor.hpp>
136 
137@@ -48,18 +50,23 @@ void dispatch_makegroup(std::string arg) {
138 	}
139 }
140 
141-void dispatch_movewindow(std::string arg) {
142+std::optional<ShiftDirection> parseShiftArg(std::string arg) {
143+	if (arg == "l" || arg == "left") return ShiftDirection::Left;
144+	else if (arg == "r" || arg == "right") return ShiftDirection::Right;
145+	else if (arg == "u" || arg == "up") return ShiftDirection::Up;
146+	else if (arg == "d" || arg == "down") return ShiftDirection::Down;
147+	else return {};
148+}
149+
150+void dispatch_movewindow(std::string value) {
151 	int workspace = workspace_for_action();
152 	if (workspace < 0) return;
153 
154-	if (arg == "l") {
155-		g_Hy3Layout->shiftWindow(workspace, ShiftDirection::Left);
156-	} else if (arg == "u") {
157-		g_Hy3Layout->shiftWindow(workspace, ShiftDirection::Up);
158-	} else if (arg == "d") {
159-		g_Hy3Layout->shiftWindow(workspace, ShiftDirection::Down);
160-	} else if (arg == "r") {
161-		g_Hy3Layout->shiftWindow(workspace, ShiftDirection::Right);
162+	auto args = CVarList(value);
163+
164+	if (auto shift = parseShiftArg(args[0])) {
165+		auto once = args[1] == "once";
166+		g_Hy3Layout->shiftWindow(workspace, shift.value(), once);
167 	}
168 }
169 
170@@ -67,14 +74,8 @@ void dispatch_movefocus(std::string arg) {
171 	int workspace = workspace_for_action();
172 	if (workspace < 0) return;
173 
174-	if (arg == "l") {
175-		g_Hy3Layout->shiftFocus(workspace, ShiftDirection::Left);
176-	} else if (arg == "u") {
177-		g_Hy3Layout->shiftFocus(workspace, ShiftDirection::Up);
178-	} else if (arg == "d") {
179-		g_Hy3Layout->shiftFocus(workspace, ShiftDirection::Down);
180-	} else if (arg == "r") {
181-		g_Hy3Layout->shiftFocus(workspace, ShiftDirection::Right);
182+	if (auto shift = parseShiftArg(arg)) {
183+		g_Hy3Layout->shiftFocus(workspace, shift.value());
184 	}
185 }
186