49ae28631f133e1acad265b7af735b928ff60e63

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

Message

Allow window shifting to break the root group

Allow window shifting to break out of the root group by wrapping it in
a new root group and breaking from the old one.

Also fix not being able to shift windows into the root group from
nested groups.

Diff

 1diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp
 2index faaa283c29ca30d95277856ba6d221a0c38360e5..9e286fc79ed3793436a12d7d0568e0f84f0f069a 100644
 3--- a/src/Hy3Layout.cpp
 4+++ b/src/Hy3Layout.cpp
 5@@ -199,13 +199,15 @@ void Hy3Node::recalcSizePosRecursive(bool force) {
 6 
 7 bool Hy3Node::swallowGroups(Hy3Node* into) {
 8 	if (into == nullptr
 9-			|| into->parent == nullptr
10 			|| into->data.type != Hy3NodeData::Group
11 			|| into->data.as_group.children.size() != 1)
12 		return false;
13 
14 	auto* child = into->data.as_group.children.front();
15 
16+	// a lot of segfaulting happens once the assumption that the root node is a group is wrong.
17+	if (into->parent == nullptr && child->data.type != Hy3NodeData::Group) return false;
18+
19 	Debug::log(LOG, "Swallowing %p into %p", child, into);
20 	Hy3Node::swapData(*into, *child);
21 	into->layout->nodes.remove(*child);
22@@ -961,7 +963,7 @@ void Hy3Layout::shiftFocus(CWindow* window, ShiftDirection direction) {
23 	if (node == nullptr) return;
24 
25 	Hy3Node* target;
26-	if ((target = Hy3Layout::shiftOrGetFocus(*node, direction, false))) {
27+	if ((target = this->shiftOrGetFocus(*node, direction, false))) {
28 		g_pCompositor->focusWindow(target->data.as_window);
29 	}
30 }
31@@ -972,7 +974,7 @@ void Hy3Layout::shiftWindow(CWindow* window, ShiftDirection direction) {
32 	if (node == nullptr) return;
33 
34 
35-	Hy3Layout::shiftOrGetFocus(*node, direction, true);
36+	this->shiftOrGetFocus(*node, direction, true);
37 }
38 
39 bool shiftIsForward(ShiftDirection direction) {
40@@ -1009,7 +1011,28 @@ Hy3Node* Hy3Layout::shiftOrGetFocus(Hy3Node& node, ShiftDirection direction, boo
41 		}
42 
43 		if (break_parent->parent == nullptr) {
44-			return nullptr;
45+			if (!shift) return nullptr;
46+
47+			// if we haven't gone up any levels and the group is in the same direction
48+			// there's no reason to wrap the root group.
49+			if (shiftMatchesLayout(group.layout, direction)) break;
50+
51+			// wrap the root group in another group
52+			this->nodes.push_back({
53+				.parent = break_parent,
54+				.data = shiftIsVertical(direction) ? Hy3GroupLayout::SplitV : Hy3GroupLayout::SplitH,
55+				.position = break_parent->position,
56+				.size = break_parent->size,
57+				.workspace_id = break_parent->workspace_id,
58+				.layout = this,
59+			});
60+
61+			auto* newChild = &this->nodes.back();
62+			Hy3Node::swapData(*break_parent, *newChild);
63+			break_parent->data.as_group.children.push_back(newChild);
64+			break_parent->data.as_group.lastFocusedChild = newChild;
65+			break_origin = newChild;
66+			break;
67 		} else {
68 			break_origin = break_parent;
69 			break_parent = break_origin->parent;
70diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp
71index 7eb2cf00c9b59291fd9cf6afb6c171d52944527e..a4d33843556e36629e2b5ebd0d1cac5393f6d520 100644
72--- a/src/Hy3Layout.hpp
73+++ b/src/Hy3Layout.hpp
74@@ -125,7 +125,7 @@ private:
75 
76 	// if shift is true, shift the window in the given direction, returning nullptr,
77 	// if shift is false, return the window in the given direction or nullptr.
78-	static Hy3Node* shiftOrGetFocus(Hy3Node&, ShiftDirection, bool);
79+	Hy3Node* shiftOrGetFocus(Hy3Node&, ShiftDirection, bool);
80 
81 	friend struct Hy3Node;
82 };