783c7ae0cf1fc263446f7114f068df03466310e4

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

Message

Add hy3:movetoworkspace, which moves a node to a workspace

Diff

This diff is truncated to protect this page.

  1diff --git a/README.md b/README.md
  2index 701c8167c190f9556115f394dcf0e5da47706274..bd96816bea6a0989fcce902bae7243f780f469a8 100644
  3--- a/README.md
  4+++ b/README.md
  5@@ -317,6 +317,8 @@ plugin {
  6  - `hy3:movewindow, <l | u | d | r | left | down | up | right>, [once], [visible]` - move a window left, up, down, or right
  7    - `once` - only move directly to the neighboring group, without moving into any of its subgroups
  8    - `visible` - only move between visible nodes, not hidden tabs
  9+ - `hy3:movetoworkspace, <workspace>, [follow]` - move the active node to the given workspace
 10+   - `follow` - change focus to the given workspace when moving the selected node
 11  - `hy3:killactive` - close all windows in the focused node
 12  - `hy3:changefocus, <top | bottom | raise | lower | tab | tabnode>`
 13    - `top` - focus all nodes in the workspace
 14diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp
 15index d29d801ff7cd0845f594a0c0866d1b1971316b4b..bca5224ae5f9878c7c7260386b242f6ff58c0a80 100644
 16--- a/src/Hy3Layout.cpp
 17+++ b/src/Hy3Layout.cpp
 18@@ -94,12 +94,47 @@ void Hy3Layout::onWindowCreatedTiling(CWindow* window, eDirection) {
 19 		return;
 20 	}
 21 
 22-	auto* monitor = g_pCompositor->getMonitorFromID(window->m_iMonitorID);
 23+	this->nodes.push_back({
 24+	    .parent = nullptr,
 25+	    .data = window,
 26+	    .workspace_id = window->m_iWorkspaceID,
 27+	    .layout = this,
 28+	});
 29+
 30+	this->insertNode(this->nodes.back());
 31+}
 32+
 33+void Hy3Layout::insertNode(Hy3Node& node) {
 34+	if (node.parent != nullptr) {
 35+		hy3_log(
 36+		    ERR,
 37+		    "insertNode called for node {:x} which already has a parent ({:x})",
 38+		    (uintptr_t) &node,
 39+		    (uintptr_t) node.parent
 40+		);
 41+		return;
 42+	}
 43+
 44+	auto* workspace = g_pCompositor->getWorkspaceByID(node.workspace_id);
 45+
 46+	if (workspace == nullptr) {
 47+		hy3_log(
 48+		    ERR,
 49+		    "insertNode called for node {:x} with invalid workspace id {}",
 50+		    (uintptr_t) &node,
 51+		    node.workspace_id
 52+		);
 53+		return;
 54+	}
 55+
 56+	node.reparenting = true;
 57+
 58+	auto* monitor = g_pCompositor->getMonitorFromID(workspace->m_iMonitorID);
 59 
 60 	Hy3Node* opening_into;
 61 	Hy3Node* opening_after = nullptr;
 62 
 63-	auto* root = this->getWorkspaceRootGroup(window->m_iWorkspaceID);
 64+	auto* root = this->getWorkspaceRootGroup(node.workspace_id);
 65 
 66 	if (root != nullptr) {
 67 		opening_after = root->getFocusedNode();
 68@@ -112,27 +147,36 @@ void Hy3Layout::onWindowCreatedTiling(CWindow* window, eDirection) {
 69 	}
 70 
 71 	if (opening_after == nullptr) {
 72-		if (g_pCompositor->m_pLastWindow != nullptr && !g_pCompositor->m_pLastWindow->m_bIsFloating
 73-		    && g_pCompositor->m_pLastWindow != window
 74-		    && g_pCompositor->m_pLastWindow->m_iWorkspaceID == window->m_iWorkspaceID
 75+		if (g_pCompositor->m_pLastWindow != nullptr
 76+		    && g_pCompositor->m_pLastWindow->m_iWorkspaceID == node.workspace_id
 77+		    && !g_pCompositor->m_pLastWindow->m_bIsFloating
 78+		    && (node.data.type == Hy3NodeType::Window
 79+		        || g_pCompositor->m_pLastWindow != node.data.as_window)
 80 		    && g_pCompositor->m_pLastWindow->m_bIsMapped)
 81 		{
 82 			opening_after = this->getNodeFromWindow(g_pCompositor->m_pLastWindow);
 83 		} else {
 84-			opening_after = this->getNodeFromWindow(
 85-			    g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal())
 86-			);
 87+			auto* mouse_window =
 88+			    g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal());
 89+
 90+			if (mouse_window != nullptr && mouse_window->m_iWorkspaceID == node.workspace_id) {
 91+				opening_after = this->getNodeFromWindow(mouse_window);
 92+			}
 93 		}
 94 	}
 95 
 96-	if (opening_after != nullptr && opening_after->workspace_id != window->m_iWorkspaceID) {
 97+	if (opening_after != nullptr
 98+	    && ((node.data.type == Hy3NodeType::Group
 99+	         && (opening_after == &node || node.data.as_group.hasChild(opening_after)))
100+	        || opening_after->reparenting))
101+	{
102 		opening_after = nullptr;
103 	}
104 
105 	if (opening_after != nullptr) {
106 		opening_into = opening_after->parent;
107 	} else {
108-		if ((opening_into = this->getWorkspaceRootGroup(window->m_iWorkspaceID)) == nullptr) {
109+		if ((opening_into = this->getWorkspaceRootGroup(node.workspace_id)) == nullptr) {
110 			static const auto* tab_first_window =
111 			    &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tab_first_window")->intValue;
112 
113@@ -140,7 +184,7 @@ void Hy3Layout::onWindowCreatedTiling(CWindow* window, eDirection) {
114 			    .data = Hy3GroupLayout::SplitH,
115 			    .position = monitor->vecPosition + monitor->vecReservedTopLeft,
116 			    .size = monitor->vecSize - monitor->vecReservedTopLeft - monitor->vecReservedBottomRight,
117-			    .workspace_id = window->m_iWorkspaceID,
118diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp
119index a165dcedfc7c5d070d1a64147d2714ca75a41986..9409be8df029da446cca43cdf6f7be8bb03bb6d4 100644
120--- a/src/Hy3Layout.hpp
121+++ b/src/Hy3Layout.hpp
122@@ -91,6 +91,7 @@ public:
123 	virtual void onEnable();
124 	virtual void onDisable();
125 
126+	void insertNode(Hy3Node& node);
127 	void makeGroupOnWorkspace(int workspace, Hy3GroupLayout, GroupEphemeralityOption);
128 	void makeOppositeGroupOnWorkspace(int workspace, GroupEphemeralityOption);
129 	void changeGroupOnWorkspace(int workspace, Hy3GroupLayout);
130@@ -108,6 +109,7 @@ public:
131 	void shiftNode(Hy3Node&, ShiftDirection, bool once, bool visible);
132 	void shiftWindow(int workspace, ShiftDirection, bool once, bool visible);
133 	void shiftFocus(int workspace, ShiftDirection, bool visible);
134+	void moveNodeToWorkspace(int origin, std::string wsname, bool follow);
135 	void changeFocus(int workspace, FocusShift);
136 	void focusTab(int workspace, TabFocus target, TabFocusMousePriority, bool wrap_scroll, int index);
137 	void setNodeSwallow(int workspace, SetSwallowOption);
138diff --git a/src/Hy3Node.cpp b/src/Hy3Node.cpp
139index 99c2b47b98306087229e71f9d298864daaf42ff0..35fd75294cab4943c663245c2d22f0cebff4c641 100644
140--- a/src/Hy3Node.cpp
141+++ b/src/Hy3Node.cpp
142@@ -759,6 +759,7 @@ Hy3Node* Hy3Node::removeFromParentRecursive(Hy3Node** expand_actor) {
143 		}
144 	}
145 
146+	this->parent = nullptr;
147 	return parent;
148 }
149 
150diff --git a/src/Hy3Node.hpp b/src/Hy3Node.hpp
151index 4b17d824100c3a5b4e90890cc0f433984947a79e..bd25556f106e4ddd43b0c0f3baaa482f20998619 100644
152--- a/src/Hy3Node.hpp
153+++ b/src/Hy3Node.hpp
154@@ -79,6 +79,7 @@ public:
155 
156 struct Hy3Node {
157 	Hy3Node* parent = nullptr;
158+	bool reparenting = false;
159 	Hy3NodeData data;
160 	Vector2D position;
161 	Vector2D size;
162diff --git a/src/dispatchers.cpp b/src/dispatchers.cpp
163index f4d663ce574065082edfdaf0ff25c513a238aba9..3d721bc62ca624f284001c66a4d846fe77f906c4 100644
164--- a/src/dispatchers.cpp
165+++ b/src/dispatchers.cpp
166@@ -119,6 +119,20 @@ void dispatch_movefocus(std::string value) {
167 	}
168 }
169 
170+void dispatch_move_to_workspace(std::string value) {
171+	int origin_workspace = workspace_for_action();
172+	if (origin_workspace == -1) return;
173+
174+	auto args = CVarList(value);
175+
176+	auto workspace = args[0];
177+	if (workspace == "") return;
178+
179+	bool follow = args[1] == "follow";
180+
181+	g_Hy3Layout->moveNodeToWorkspace(origin_workspace, workspace, follow);
182+}
183+
184 void dispatch_changefocus(std::string arg) {
185 	int workspace = workspace_for_action();
186 	if (workspace == -1) return;
187@@ -237,6 +251,7 @@ void registerDispatchers() {
188 	HyprlandAPI::addDispatcher(PHANDLE, "hy3:setephemeral", dispatch_setephemeral);
189 	HyprlandAPI::addDispatcher(PHANDLE, "hy3:movefocus", dispatch_movefocus);
190 	HyprlandAPI::addDispatcher(PHANDLE, "hy3:movewindow", dispatch_movewindow);
191+	HyprlandAPI::addDispatcher(PHANDLE, "hy3:movetoworkspace", dispatch_move_to_workspace);
192 	HyprlandAPI::addDispatcher(PHANDLE, "hy3:changefocus", dispatch_changefocus);
193 	HyprlandAPI::addDispatcher(PHANDLE, "hy3:focustab", dispatch_focustab);
194 	HyprlandAPI::addDispatcher(PHANDLE, "hy3:setswallow", dispatch_setswallow);