910fcc0f257e260120dac0197293b0ecfa6e11cf

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

Message

Move tab create/update/delete to relevant locations

Also tab close animation

Diff

This diff is truncated to protect this page.

  1diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp
  2index e97898e6688d8c7309228267787748a1bb7ec36c..efe6b27bf23dd7530d1fb022464ef82ce34e604a 100644
  3--- a/src/Hy3Layout.cpp
  4+++ b/src/Hy3Layout.cpp
  5@@ -18,6 +18,20 @@ void errorNotif() {
  6 
  7 Hy3GroupData::Hy3GroupData(Hy3GroupLayout layout): layout(layout) {}
  8 
  9+Hy3GroupData::Hy3GroupData(Hy3GroupData&& from) {
 10+	this->layout = from.layout;
 11+	this->children = std::move(from.children);
 12+	this->group_focused = from.group_focused;
 13+	this->focused_child = from.focused_child;
 14+	from.focused_child = nullptr;
 15+	this->tab_bar = from.tab_bar;
 16+	from.tab_bar = nullptr;
 17+}
 18+
 19+Hy3GroupData::~Hy3GroupData() {
 20+	if (this->tab_bar != nullptr) this->tab_bar->bar.beginDestroy();
 21+}
 22+
 23 Hy3NodeData::Hy3NodeData(): Hy3NodeData((CWindow*)nullptr) {}
 24 
 25 Hy3NodeData::Hy3NodeData(CWindow *window): type(Hy3NodeData::Window) {
 26@@ -151,6 +165,8 @@ void Hy3Node::recalcSizePosRecursive(bool force) {
 27 			break;
 28 		}
 29 
 30+		this->updateTabBar();
 31+
 32 		child->recalcSizePosRecursive(force);
 33 		return;
 34 	}
 35@@ -200,6 +216,8 @@ void Hy3Node::recalcSizePosRecursive(bool force) {
 36 
 37 		child->recalcSizePosRecursive(force);
 38 	}
 39+
 40+	this->updateTabBar();
 41 }
 42 
 43 void Hy3Node::setHidden(bool hidden) {
 44@@ -227,6 +245,17 @@ bool Hy3Node::isUrgent() {
 45 	}
 46 }
 47 
 48+bool Hy3Node::isIndirectlyFocused() {
 49+	Hy3Node* node = this;
 50+
 51+	while (node->parent != nullptr) {
 52+		if (node->parent->data.as_group.focused_child != node) return false;
 53+		node = node->parent;
 54+	}
 55+
 56+	return true;
 57+}
 58+
 59 std::string Hy3Node::getTitle() {
 60 	switch (this->data.type) {
 61 	case Hy3NodeData::Window:
 62@@ -272,14 +301,30 @@ void Hy3Node::markFocused() {
 63 		this->data.as_group.focused_child = nullptr;
 64 	}
 65 
 66+	auto* node2 = node;
 67+	while (node2->parent != nullptr) {
 68+		node2->parent->data.as_group.focused_child = node2;
 69+		node2->parent->data.as_group.group_focused = false;
 70+		node2 = node2->parent;
 71+	}
 72+
 73 	while (node->parent != nullptr) {
 74-		node->parent->data.as_group.focused_child = node;
 75-		node->parent->data.as_group.group_focused = false;
 76+		node->parent->updateTabBar();
 77 		node = node->parent;
 78 	}
 79+	while (node2->parent != nullptr) {
 80+		node2->parent->data.as_group.focused_child = node2;
 81+		node2->parent->data.as_group.group_focused = false;
 82+		node2->parent->updateTabBar();
 83+		node2 = node2->parent;
 84+	}
 85 
 86 	if (oldfocus != nullptr) {
 87 		oldfocus->updateDecos();
 88+		while (oldfocus != nullptr) {
 89+			oldfocus->updateTabBar();
 90+			oldfocus = oldfocus->parent;
 91+		}
 92 	}
 93 }
 94 
 95@@ -462,6 +507,20 @@ void Hy3Node::swapData(Hy3Node& a, Hy3Node& b) {
 96 	}
 97 }
 98 
 99+void Hy3Node::updateTabBar() {
100+	if (this->data.type == Hy3NodeData::Group) {
101+		auto& group = this->data.as_group;
102+
103+		if (group.layout == Hy3GroupLayout::Tabbed) {
104+			if (group.tab_bar == nullptr) group.tab_bar = &this->layout->tab_groups.emplace_back(*this);
105diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp
106index 1dc286c5d9d582ba6a38827a70351f6116093994..1196471413edd4b9ae550e370eb16de9abfe8387 100644
107--- a/src/Hy3Layout.hpp
108+++ b/src/Hy3Layout.hpp
109@@ -27,14 +27,16 @@ struct Hy3GroupData {
110 	std::list<Hy3Node*> children;
111 	bool group_focused = true;
112 	Hy3Node* focused_child = nullptr;
113-	std::shared_ptr<Hy3TabGroup> tab_bar;
114+	Hy3TabGroup* tab_bar = nullptr;
115 
116 	bool hasChild(Hy3Node* child);
117 
118 	Hy3GroupData(Hy3GroupLayout layout);
119+	~Hy3GroupData();
120 
121 private:
122-	Hy3GroupData(Hy3GroupData&&) = default;
123+	Hy3GroupData(Hy3GroupData&&);
124+	Hy3GroupData(const Hy3GroupData&) = delete;
125 
126 	friend class Hy3NodeData;
127 };
128@@ -81,6 +83,7 @@ struct Hy3Node {
129 	void updateDecos();
130 	void setHidden(bool hidden);
131 	bool isUrgent();
132+	bool isIndirectlyFocused();
133 	std::string getTitle();
134 
135 	bool operator==(const Hy3Node&) const;
136@@ -95,6 +98,9 @@ struct Hy3Node {
137 	Hy3Node* intoGroup(Hy3GroupLayout);
138 
139 	static void swapData(Hy3Node&, Hy3Node&);
140+
141+private:
142+	void updateTabBar();
143 };
144 
145 class Hy3Layout: public IHyprLayout {
146@@ -135,6 +141,7 @@ public:
147 	static void renderHook(void*, std::any);
148 
149 	std::list<Hy3Node> nodes;
150+	std::list<Hy3TabGroup> tab_groups;
151 private:
152 	struct {
153 		bool started = false;
154diff --git a/src/TabGroup.cpp b/src/TabGroup.cpp
155index ce664f471055b88b3743825fc99f6d632bd20d25..5b3681b557965943889cfd29f1c1e9804e2c2c9b 100644
156--- a/src/TabGroup.cpp
157+++ b/src/TabGroup.cpp
158@@ -5,7 +5,7 @@
159 #include <hyprland/src/Compositor.hpp>
160 #include <cairo/cairo.h>
161 
162-Hy3TabBarEntry::Hy3TabBarEntry(std::shared_ptr<Hy3TabGroup> tab_group, Hy3Node& node): tab_group(tab_group), node(node) {
163+Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_bar), node(node) {
164 	this->offset.create(AVARTYPE_FLOAT, -1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE);
165 	this->width.create(AVARTYPE_FLOAT, -1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE);
166 
167@@ -24,25 +24,24 @@ bool Hy3TabBarEntry::operator==(const Hy3TabBarEntry& entry) const {
168 	return this->node == entry.node;
169 }
170 
171-void Hy3TabBarEntry::prepareTexture(float scale, Vector2D size) {
172+void Hy3TabBarEntry::prepareTexture(float scale, wlr_box& box) {
173 	static const auto* rounding_setting = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:rounding")->intValue;
174 
175-	auto width = size.x * scale;
176-	auto height = size.y * scale;
177+	auto width = box.width;
178+	auto height = box.height;
179 
180 	auto rounding = std::min((double) *rounding_setting, std::min(width * 0.5, height * 0.5));
181 
182-	if (this->needs_redraw
183-			|| this->texture.m_iTexID == 0
184-			|| this->last_render_rounding == rounding
185-			|| this->last_render_scale == scale
186-			|| this->last_render_size == size
187-			|| true // todo
188+	if (this->texture.m_iTexID == 0
189+			|| this->last_render_rounding != rounding
190+			|| this->last_render_focused != focused
191+			|| this->last_render_urgent != urgent
192+			|| !wlr_box_equal(&this->last_render_box, &box)
193 	) {
194-		this->needs_redraw = false;
195 		this->last_render_rounding = rounding;
196-		this->last_render_scale = scale;
197-		this->last_render_size = size;
198+		this->last_render_focused = this->focused;
199+		this->last_render_urgent = this->urgent;
200+		this->last_render_box = box;
201 
202 		auto cairo_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
203 		auto cairo = cairo_create(cairo_surface);
204@@ -95,17 +94,6 @@ void Hy3TabBarEntry::prepareTexture(float scale, Vector2D size) {
205 	}
206 }
207 
208-void Hy3TabBarEntry::animateRemoval() {
209-	if (this->width.goalf() == 0.0) return;
210-	this->width = 0.0;
211-
212-	// not removing the callback is required for soundness, as the animation will
213-	// be deleted once the callback ends.
214-	this->width.setCallbackOnEnd([this](void*) {
215-		this->tab_group->bar.entries.remove(*this);
216-	}, false);
217-}
218-
219 Hy3TabBar::Hy3TabBar() {
220 	this->vertical_pos.create(AVARTYPE_FLOAT, 1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE);
221 	this->fade_opacity.create(AVARTYPE_FLOAT, 1.0f, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), nullptr, AVARDAMAGE_NONE);
222@@ -120,6 +108,12 @@ Hy3TabBar::Hy3TabBar() {
223 	this->fade_opacity = 1.0;
224 }
225 
226+void Hy3TabBar::beginDestroy() {
227+	this->vertical_pos = 1.0;
228+	this->fade_opacity = 0.0;
229+	this->fade_opacity.setCallbackOnEnd([this](void*) { this->destroy = true; });
230+}
231+
232 void Hy3TabBar::focusNode(Hy3Node* node) {
233 	this->focused_node = node;
234 
235@@ -180,7 +174,7 @@ void Hy3TabBar::updateNodeList(std::list<Hy3Node*>& nodes) {
236 				entry = *moved;
237 				removed_entries.erase(moved);
238 			} else {
239-				entry = this->entries.emplace(entry, this->group.lock(), **node);
240+				entry = this->entries.emplace(entry, *this, **node);
241 			}
242 		}
243 
244@@ -190,10 +184,7 @@ void Hy3TabBar::updateNodeList(std::list<Hy3Node*>& nodes) {
245 		}
246 
247 		// set stats from node data
248-		auto* root = *node;
249-		while (root->parent != nullptr) root = root->parent;
250-		auto* focused = root->getFocusedNode();
251-		entry->focused = focused == *node;
252+		entry->focused = (*node)->isIndirectlyFocused();
253 		entry->urgent = (*node)->isUrgent();
254 
255 		node = std::next(node);
256@@ -202,7 +193,8 @@ void Hy3TabBar::updateNodeList(std::list<Hy3Node*>& nodes) {
257 
258diff --git a/src/TabGroup.hpp b/src/TabGroup.hpp
259index 7fa4ebd01b10efc445d74aa6ffc7c1df17b65e6c..e52667d031089a1728b54a6fa02cdd802c5203f1 100644
260--- a/src/TabGroup.hpp
261+++ b/src/TabGroup.hpp
262@@ -16,31 +16,31 @@ struct Hy3TabBarEntry {
263 	std::string window_title;
264 	bool focused = false;
265 	bool urgent = false;
266-	bool needs_redraw = false;
267 	CTexture texture;
268 	CAnimatedVariable offset; // offset 0, 0.0-1.0 of total bar
269 	CAnimatedVariable width; // 0.0-1.0 of total bar
270-	std::shared_ptr<Hy3TabGroup> tab_group;
271+	Hy3TabBar& tab_bar;
272 	Hy3Node& node; // only used for comparioson. do not deref.
273-	Vector2D last_render_size;
274-	float last_render_scale = 0.0;
275+	wlr_box last_render_box;
276 	float last_render_rounding = 0.0;
277+	bool last_render_focused = false;
278+	bool last_render_urgent = false;
279 
280-	Hy3TabBarEntry(std::shared_ptr<Hy3TabGroup>, Hy3Node&);
281+	Hy3TabBarEntry(Hy3TabBar&, Hy3Node&);
282 	bool operator==(const Hy3Node&) const;
283 	bool operator==(const Hy3TabBarEntry&) const;
284 
285-	void prepareTexture(float, Vector2D);
286-
287-	void animateRemoval();
288+	void prepareTexture(float, wlr_box&);
289 };
290 
291 class Hy3TabBar {
292 public:
293+	bool destroy = false;
294 	CAnimatedVariable vertical_pos;
295 	CAnimatedVariable fade_opacity;
296 
297 	Hy3TabBar();
298+	void beginDestroy();
299 
300 	void focusNode(Hy3Node*);
301 	void updateNodeList(std::list<Hy3Node*>& nodes);
302@@ -48,7 +48,6 @@ public:
303 	void setSize(Vector2D);
304 
305 	std::list<Hy3TabBarEntry> entries;
306-	std::weak_ptr<Hy3TabGroup> group;
307 private:
308 	Hy3Node* focused_node = nullptr;
309 	CAnimatedVariable focus_opacity;
310@@ -56,6 +55,10 @@ private:
311 	CAnimatedVariable focus_end;
312 
313 	Vector2D size;
314+
315+	// Tab bar entries take a reference to `this`.
316+	Hy3TabBar(Hy3TabBar&&) = delete;
317+	Hy3TabBar(const Hy3TabBar&) = delete;
318 };
319 
320 class Hy3TabGroup {
321@@ -65,7 +68,7 @@ public:
322 	CAnimatedVariable size;
323 
324 	// initialize a group with the given node. UB if node is not a group.
325-	static std::shared_ptr<Hy3TabGroup> new_(Hy3Node&);
326+	Hy3TabGroup(Hy3Node&);
327 
328 	// update tab bar with node position and data. UB if node is not a group.
329 	void updateWithGroup(Hy3Node&);
330@@ -73,7 +76,6 @@ public:
331 	void renderTabBar();
332 
333 private:
334-	std::weak_ptr<Hy3TabGroup> self;
335 	std::vector<CWindow*> stencil_windows;
336 
337 	Hy3TabGroup();