0bdf28f3bc70b099ee61bd151531f179b6e40413

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

Message

WIP Window Movement

Code is bad but it does mostly work

Diff

This diff is truncated to protect this page.

  1diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp
  2index c0217fcea010ad0b49b7d83884378da398d47ce4..6782798eeedf33e4d97c42c84ff0aee9a6accbfe 100644
  3--- a/src/Hy3Layout.cpp
  4+++ b/src/Hy3Layout.cpp
  5@@ -1,14 +1,5 @@
  6 #include "Hy3Layout.hpp"
  7-#include "src/Window.hpp"
  8-#include "src/debug/Log.hpp"
  9-#include "src/helpers/Vector2D.hpp"
 10-#include "src/helpers/Workspace.hpp"
 11-#include "src/managers/XWaylandManager.hpp"
 12-#include "src/managers/input/InputManager.hpp"
 13-#include "src/render/Renderer.hpp"
 14-#include <cairo/cairo.h>
 15-#include <ctime>
 16-#include <memory>
 17+
 18 #include <src/Compositor.hpp>
 19 
 20 Hy3GroupData::Hy3GroupData(Hy3GroupLayout layout): layout(layout) {}
 21@@ -23,6 +14,8 @@ Hy3NodeData::Hy3NodeData(Hy3GroupData group): type(Hy3NodeData::Group) {
 22 	new(&this->as_group) Hy3GroupData(std::move(group));
 23 }
 24 
 25+Hy3NodeData::Hy3NodeData(Hy3GroupLayout layout): Hy3NodeData(Hy3GroupData(layout)) {}
 26+
 27 Hy3NodeData::~Hy3NodeData() {
 28 	switch (this->type) {
 29 	case Hy3NodeData::Window:
 30@@ -80,6 +73,18 @@ Hy3NodeData& Hy3NodeData::operator=(const Hy3NodeData& from) {
 31 	return *this;
 32 }
 33 
 34+Hy3NodeData& Hy3NodeData::operator=(CWindow* window) {
 35+	*this = Hy3NodeData(window);
 36+
 37+	return *this;
 38+}
 39+
 40+Hy3NodeData& Hy3NodeData::operator=(Hy3GroupLayout layout) {
 41+	*this = Hy3NodeData(layout);
 42+
 43+	return *this;
 44+}
 45+
 46 bool Hy3NodeData::operator==(const Hy3NodeData& rhs) const {
 47 	if (this->type != rhs.type) return false;
 48 	switch (this->type) {
 49@@ -185,6 +190,59 @@ void Hy3Node::recalcSizePosRecursive(bool force) {
 50 	}
 51 }
 52 
 53+bool Hy3GroupData::hasChild(Hy3Node* node) {
 54+	Debug::log(LOG, "Searching for child %p of %p", this, node);
 55+	for (auto child: this->children) {
 56+		if (child == node) return true;
 57+
 58+		if (child->data.type == Hy3NodeData::Group) {
 59+			if (child->data.as_group.hasChild(node)) return true;
 60+		}
 61+	}
 62+
 63+	return false;
 64+}
 65+
 66+bool Hy3Node::removeChild(Hy3Node* child, bool childSwallows) {
 67+	if (this->data.type != Hy3NodeData::Group) return false;
 68+	Hy3GroupData& group = this->data.as_group;
 69+
 70+	if (group.children.remove(child)) {
 71+		if (group.children.empty()) {
 72+			Debug::log(LOG, "Group %p is empty, removing", this);
 73+			this->parent->removeChild(this, childSwallows);
 74+			this->layout->nodes.remove(*this);
 75+		} else if (childSwallows && group.children.size() == 1) {
 76+			auto remaining = group.children.front();
 77+			Debug::log(LOG, "Group %p has only one child(%p), swallowing", this, remaining);
 78+			swapNodeData(*this, *remaining);
 79+			this->layout->nodes.remove(*remaining);
 80+		}
 81+
 82+		return true;
 83+	}
 84+
 85+	return false;
 86+}
 87+
 88+void swapNodeData(Hy3Node& a, Hy3Node& b) {
 89+	Hy3NodeData aData = std::move(a.data);
 90+	a.data = b.data;
 91+	b.data = aData;
 92+
 93+	if (a.data.type == Hy3NodeData::Group) {
 94+		for (auto child: a.data.as_group.children) {
 95+			child->parent = &a;
 96+		}
 97+	}
 98+
 99+	if (b.data.type == Hy3NodeData::Group) {
100+		for (auto child: b.data.as_group.children) {
101+			child->parent = &b;
102+		}
103+	}
104+}
105diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp
106index c6907cb45544d0fcc6e6d99b8103a336d5ea1f18..37aab20603be1236c3d7e2e54d5d67c78d9a1acf 100644
107--- a/src/Hy3Layout.hpp
108+++ b/src/Hy3Layout.hpp
109@@ -12,14 +12,32 @@ enum class Hy3GroupLayout {
110 	Tabbed,
111 };
112 
113+enum class ShiftDirection {
114+	Left,
115+	Up,
116+	Down,
117+	Right,
118+};
119+
120 struct Hy3GroupData {
121 	Hy3GroupLayout layout = Hy3GroupLayout::SplitH;
122 	std::list<Hy3Node*> children;
123 
124+	bool hasChild(Hy3Node* child);
125+
126 	Hy3GroupData(Hy3GroupLayout layout);
127+
128+private:
129+	Hy3GroupData(Hy3GroupData&&) = default;
130+	Hy3GroupData(const Hy3GroupData&) = default;
131+
132+	friend class Hy3NodeData;
133 };
134 
135-struct Hy3NodeData {
136+void swapNodeData(Hy3Node& a, Hy3Node& b);
137+
138+class Hy3NodeData {
139+public:
140 	enum { Group, Window } type;
141 	union {
142 		Hy3GroupData as_group;
143@@ -29,12 +47,19 @@ struct Hy3NodeData {
144 	bool operator==(const Hy3NodeData&) const;
145 
146 	Hy3NodeData();
147-	Hy3NodeData(CWindow* window);
148-	Hy3NodeData(Hy3GroupData group);
149+	~Hy3NodeData();
150+	Hy3NodeData(CWindow*);
151+	Hy3NodeData(Hy3GroupLayout);
152+	Hy3NodeData& operator=(CWindow*);
153+	Hy3NodeData& operator=(Hy3GroupLayout);
154+
155+	//private: - I give up, C++ wins
156+	Hy3NodeData(Hy3GroupData);
157 	Hy3NodeData(const Hy3NodeData&);
158 	Hy3NodeData(Hy3NodeData&&);
159 	Hy3NodeData& operator=(const Hy3NodeData&);
160-	~Hy3NodeData();
161+
162+	friend void swapNodeData(Hy3Node&, Hy3Node&);
163 };
164 
165 struct Hy3Node {
166@@ -48,6 +73,11 @@ struct Hy3Node {
167 	Hy3Layout* layout = nullptr;
168 
169 	void recalcSizePosRecursive(bool force = false);
170+	// remove a child node, returns true on success.
171+	// fails if not a group
172+	// if only a single child node remains && childSwallows, replace this group with said child.
173+	// if no children remain, remove this node from its parent.
174+	bool removeChild(Hy3Node* child, bool childSwallows = false);
175 
176 	bool operator==(const Hy3Node&) const;
177 };
178@@ -72,9 +102,12 @@ public:
179 	virtual void onEnable();
180 	virtual void onDisable();
181 
182+	void makeGroupOn(CWindow*, Hy3GroupLayout);
183+	void shiftWindow(CWindow*, ShiftDirection);
184+
185+	Hy3Node* findCommonParentNode(Hy3Node&, Hy3Node&);
186+
187 private:
188-	// std::list is used over std::vector because it does not invalidate references
189-	// when mutated.
190 	std::list<Hy3Node> nodes;
191 	CWindow* lastActiveWindow = nullptr;
192 
193diff --git a/src/main.cpp b/src/main.cpp
194index 350e61ca9c8999d0fc9d305a1b87ad2fb1ba13ab..2bda5ec22e9ae90bee7707f2948537a4c190c38d 100644
195--- a/src/main.cpp
196+++ b/src/main.cpp
197@@ -10,28 +10,44 @@ APICALL EXPORT std::string PLUGIN_API_VERSION() {
198 	return HYPRLAND_API_VERSION;
199 }
200 
201-void splith(std::string) {
202-	SLayoutMessageHeader header;
203-	header.pWindow = g_pCompositor->m_pLastWindow;
204+// return a window if a window action makes sense now
205+CWindow* window_for_action() {
206+	if (g_pLayoutManager->getCurrentLayout() != g_Hy3Layout.get()) return nullptr;
207 
208-	if (!header.pWindow) return;
209+	auto* window = g_pCompositor->m_pLastWindow;
210 
211-	const auto workspace = g_pCompositor->getWorkspaceByID(header.pWindow->m_iWorkspaceID);
212-	if (workspace->m_bHasFullscreenWindow) return;
213+	if (!window) return nullptr;
214 
215-	g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "splith");
216-}
217+	const auto workspace = g_pCompositor->getWorkspaceByID(window->m_iWorkspaceID);
218+	if (workspace->m_bHasFullscreenWindow) return nullptr;
219 
220-void splitv(std::string) {
221-	SLayoutMessageHeader header;
222-	header.pWindow = g_pCompositor->m_pLastWindow;
223+	return window;
224+}
225 
226-	if (!header.pWindow) return;
227+void dispatch_makegroup(std::string arg) {
228+	CWindow* window = window_for_action();
229+	if (window == nullptr) return;
230 
231-	const auto workspace = g_pCompositor->getWorkspaceByID(header.pWindow->m_iWorkspaceID);
232-	if (workspace->m_bHasFullscreenWindow) return;
233+	if (arg == "h") {
234+		g_Hy3Layout->makeGroupOn(window, Hy3GroupLayout::SplitH);
235+	} else if (arg == "v") {
236+		g_Hy3Layout->makeGroupOn(window, Hy3GroupLayout::SplitV);
237+	}
238+}
239 
240-	g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "splitv");
241+void dispatch_movewindow(std::string arg) {
242+	CWindow* window = window_for_action();
243+	if (window == nullptr) return;
244+
245+	if (arg == "l") {
246+		g_Hy3Layout->shiftWindow(window, ShiftDirection::Left);
247+	} else if (arg == "u") {
248+		g_Hy3Layout->shiftWindow(window, ShiftDirection::Up);
249+	} else if (arg == "d") {
250+		g_Hy3Layout->shiftWindow(window, ShiftDirection::Down);
251+	} else if (arg == "r") {
252+		g_Hy3Layout->shiftWindow(window, ShiftDirection::Right);
253+	}
254 }
255 
256 APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
257@@ -40,8 +56,8 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
258 	g_Hy3Layout = std::make_unique<Hy3Layout>();
259 	HyprlandAPI::addLayout(PHANDLE, "hy3", g_Hy3Layout.get());
260 
261-	HyprlandAPI::addDispatcher(PHANDLE, "splith", splith);
262-	HyprlandAPI::addDispatcher(PHANDLE, "splitv", splitv);
263+	HyprlandAPI::addDispatcher(PHANDLE, "hy3_makegroup", dispatch_makegroup);
264+	HyprlandAPI::addDispatcher(PHANDLE, "hy3_movewindow", dispatch_movewindow);
265 
266 	return {"hy3", "i3 like layout for hyprland", "outfoxxed", "0.1"};
267 }