1a490734bad8f5e0d8296374f40425585dbd3b46

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

Message

Add text in tab bars

Diff

This diff is truncated to protect this page.

  1diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp
  2index b93c18172b59de588eaaa12163d1749fdab01326..7c3956fcc4824f6606becb39e3ca9205ea598834 100644
  3--- a/src/Hy3Layout.cpp
  4+++ b/src/Hy3Layout.cpp
  5@@ -496,6 +496,7 @@ Hy3Node* Hy3Node::intoGroup(Hy3GroupLayout layout) {
  6 	this->data.as_group.group_focused = false;
  7 	this->data.as_group.focused_child = node;
  8 	this->recalcSizePosRecursive();
  9+	this->updateTabBarRecursive();
 10 
 11 	return node;
 12 }
 13@@ -583,6 +584,15 @@ void Hy3Node::updateTabBar() {
 14 	}
 15 }
 16 
 17+void Hy3Node::updateTabBarRecursive() {
 18+	auto* node = this;
 19+
 20+	while (node != nullptr) {
 21+		node->updateTabBar();
 22+		node = node->parent;
 23+	}
 24+}
 25+
 26 void Hy3Node::updateDecos() {
 27 	switch (this->data.type) {
 28 	case Hy3NodeData::Window:
 29@@ -1243,6 +1253,7 @@ void Hy3Layout::replaceWindowDataWith(CWindow* from, CWindow* to) {
 30 }
 31 
 32 std::unique_ptr<HOOK_CALLBACK_FN> renderHookPtr = std::make_unique<HOOK_CALLBACK_FN>(Hy3Layout::renderHook);
 33+std::unique_ptr<HOOK_CALLBACK_FN> windowTitleHookPtr = std::make_unique<HOOK_CALLBACK_FN>(Hy3Layout::windowTitleHook);
 34 std::unique_ptr<HOOK_CALLBACK_FN> tickHookPtr = std::make_unique<HOOK_CALLBACK_FN>(Hy3Layout::tickHook);
 35 
 36 void Hy3Layout::onEnable() {
 37@@ -1257,12 +1268,14 @@ void Hy3Layout::onEnable() {
 38 	}
 39 
 40 	HyprlandAPI::registerCallbackStatic(PHANDLE, "render", renderHookPtr.get());
 41+	HyprlandAPI::registerCallbackStatic(PHANDLE, "windowTitle", windowTitleHookPtr.get());
 42 	HyprlandAPI::registerCallbackStatic(PHANDLE, "tick", tickHookPtr.get());
 43 	selection_hook::enable();
 44 }
 45 
 46 void Hy3Layout::onDisable() {
 47 	HyprlandAPI::unregisterCallback(PHANDLE, renderHookPtr.get());
 48+	HyprlandAPI::unregisterCallback(PHANDLE, windowTitleHookPtr.get());
 49 	HyprlandAPI::unregisterCallback(PHANDLE, tickHookPtr.get());
 50 	selection_hook::disable();
 51 	this->nodes.clear();
 52@@ -1594,6 +1607,14 @@ void Hy3Layout::renderHook(void*, std::any data) {
 53 	}
 54 }
 55 
 56+void Hy3Layout::windowTitleHook(void*, std::any data) {
 57+	CWindow* window = std::any_cast<CWindow*>(data);
 58+	if (window == nullptr) return;
 59+	auto* node = g_Hy3Layout->getNodeFromWindow(window);
 60+
 61+	node->updateTabBarRecursive();
 62+}
 63+
 64 void Hy3Layout::tickHook(void*, std::any) {
 65 	auto& tab_groups = g_Hy3Layout->tab_groups;
 66 	auto entry = tab_groups.begin();
 67diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp
 68index a373fab7cb5a6046fdd591b704918c8f9d99e6e6..0a75f065713070c6bfc4ea1e85524092b5eb1ad2 100644
 69--- a/src/Hy3Layout.hpp
 70+++ b/src/Hy3Layout.hpp
 71@@ -84,6 +84,8 @@ struct Hy3Node {
 72 	Hy3Node* getFocusedNode();
 73 	void updateDecos();
 74 	void setHidden(bool hidden);
 75+	void updateTabBar();
 76+	void updateTabBarRecursive();
 77 	bool isUrgent();
 78 	bool isIndirectlyFocused();
 79 	std::string getTitle();
 80@@ -100,9 +102,6 @@ struct Hy3Node {
 81 	Hy3Node* intoGroup(Hy3GroupLayout);
 82 
 83 	static void swapData(Hy3Node&, Hy3Node&);
 84-
 85-private:
 86-	void updateTabBar();
 87 };
 88 
 89 class Hy3Layout: public IHyprLayout {
 90@@ -141,6 +140,7 @@ public:
 91 	Hy3Node* getWorkspaceFocusedNode(const int&);
 92 
 93 	static void renderHook(void*, std::any);
 94+	static void windowTitleHook(void*, std::any);
 95 	static void tickHook(void*, std::any);
 96 
 97 	std::list<Hy3Node> nodes;
 98diff --git a/src/TabGroup.cpp b/src/TabGroup.cpp
 99index 3c002a05620c5d4e117d77151b5521e500b1025d..90cc744bb0cc435280ebe954b9f40825e4dbeb71 100644
100--- a/src/TabGroup.cpp
101+++ b/src/TabGroup.cpp
102@@ -4,6 +4,7 @@
103 
104 #include <hyprland/src/Compositor.hpp>
105 #include <cairo/cairo.h>
106+#include <pango/pangocairo.h>
107 #include <hyprland/src/helpers/Color.hpp>
108 #include <hyprland/src/plugins/PluginAPI.hpp>
109 #include <hyprland/src/render/OpenGL.hpp>
110@@ -47,27 +48,63 @@ void Hy3TabBarEntry::setUrgent(bool urgent) {
111 	}
112 }
113 
114+void Hy3TabBarEntry::setWindowTitle(std::string title) {
115+	if (this->window_title != title) {
116+		this->window_title = title;
117+		this->tab_bar.dirty = true;
118+	}
119+}
120+
121 void Hy3TabBarEntry::prepareTexture(float scale, wlr_box& box) {
122-	static const auto* rounding_setting = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:rounding")->intValue;
123+	static const auto* s_rounding = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:rounding")->intValue;
124+	static const auto* render_text = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:render_text")->intValue;
125+	static const auto* text_font = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:text_font")->strValue;
126+	static const auto* text_height = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:text_height")->intValue;
127+	static const auto* text_padding = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:text_padding")->intValue;
128 	static const auto* col_active = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.active")->intValue;
129 	static const auto* col_urgent = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.urgent")->intValue;
130 	static const auto* col_inactive = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.inactive")->intValue;
131+	static const auto* col_text_active = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.text.active")->intValue;
132+	static const auto* col_text_urgent = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.text.urgent")->intValue;
133+	static const auto* col_text_inactive = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hy3:tabs:col.text.inactive")->intValue;
134 
135 	auto width = box.width;
136 	auto height = box.height;
137 
138-	auto rounding = std::min((double) *rounding_setting, std::min(width * 0.5, height * 0.5));
139+	auto rounding = std::min((double) *s_rounding, std::min(width * 0.5, height * 0.5));
140 
141 	if (this->texture.m_iTexID == 0
142-			|| this->last_render_rounding != rounding
143-			|| this->last_render_focused != focused
144-			|| this->last_render_urgent != urgent
145-			|| !wlr_box_equal(&this->last_render_box, &box)
146+			|| this->last_render.x != box.x
147+			|| this->last_render.y != box.y
148+			|| this->last_render.focused != this->focused
149+			|| this->last_render.urgent != this->urgent
150+			|| this->last_render.window_title != this->window_title
151+			|| this->last_render.rounding != rounding
152+			|| this->last_render.text_font != *text_font
153+			|| this->last_render.text_height != *text_height
154+			|| this->last_render.text_padding != *text_padding
155+			|| this->last_render.col_active != *col_active
156+			|| this->last_render.col_urgent != *col_urgent
157+			|| this->last_render.col_inactive != *col_inactive
158+			|| this->last_render.col_text_active != *col_text_active
159+			|| this->last_render.col_text_urgent != *col_text_urgent
160+			|| this->last_render.col_text_inactive != *col_text_inactive
161 	) {
162-		this->last_render_rounding = rounding;
163-		this->last_render_focused = this->focused;
164-		this->last_render_urgent = this->urgent;
165-		this->last_render_box = box;
166+		this->last_render.x = box.x;
167+		this->last_render.y = box.y;
168+		this->last_render.focused = this->focused;
169+		this->last_render.urgent = this->urgent;
170+		this->last_render.window_title = this->window_title;
171+		this->last_render.rounding = rounding;
172+		this->last_render.text_font = *text_font;
173+		this->last_render.text_height = *text_height;
174+		this->last_render.text_padding = *text_padding;
175+		this->last_render.col_active = *col_active;
176+		this->last_render.col_urgent = *col_urgent;
177+		this->last_render.col_inactive = *col_inactive;
178+		this->last_render.col_text_active = *col_text_active;
179+		this->last_render.col_text_urgent = *col_text_urgent;
180+		this->last_render.col_text_inactive = *col_text_inactive;
181 
182 		auto cairo_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
183 		auto cairo = cairo_create(cairo_surface);
184@@ -104,6 +141,45 @@ void Hy3TabBarEntry::prepareTexture(float scale, wlr_box& box) {
185 		// draw
186 		cairo_fill(cairo);
187 
188+		// render window title
189+		if (*render_text) {
190+			PangoLayout* layout = pango_cairo_create_layout(cairo);
191+			pango_layout_set_text(layout, this->window_title.c_str(), -1);
192+
193+			PangoFontDescription* font_desc = pango_font_description_from_string(text_font->c_str());
194+			pango_font_description_set_size(font_desc, *text_height * scale * PANGO_SCALE);
195+			pango_layout_set_font_description(layout, font_desc);
196+			pango_font_description_free(font_desc);
197+
198+			int padding = *text_padding * scale;
199+			int width = box.width - padding * 2;
200+
201+			pango_layout_set_width(layout, width * PANGO_SCALE);
202diff --git a/src/TabGroup.hpp b/src/TabGroup.hpp
203index 7e43e9575e4920562d7562f6404b928759b23f1b..e463f92030b523d5d50b80a0fe74c2b5e9f8ae90 100644
204--- a/src/TabGroup.hpp
205+++ b/src/TabGroup.hpp
206@@ -21,10 +21,25 @@ struct Hy3TabBarEntry {
207 	CAnimatedVariable width; // 0.0-1.0 of total bar
208 	Hy3TabBar& tab_bar;
209 	Hy3Node& node; // only used for comparioson. do not deref.
210-	wlr_box last_render_box;
211-	float last_render_rounding = 0.0;
212-	bool last_render_focused = false;
213-	bool last_render_urgent = false;
214+
215+	struct {
216+		int x, y;
217+		float rounding = 0.0;
218+		float scale = 0.0;
219+		bool focused = false;
220+		bool urgent = false;
221+		std::string window_title;
222+
223+		std::string text_font;
224+		int text_height = 0;
225+		int text_padding = 0;
226+		int col_active = 0;
227+		int col_urgent = 0;
228+		int col_inactive = 0;
229+		int col_text_active = 0;
230+		int col_text_urgent = 0;
231+		int col_text_inactive = 0;
232+	} last_render;
233 
234 	Hy3TabBarEntry(Hy3TabBar&, Hy3Node&);
235 	bool operator==(const Hy3Node&) const;
236@@ -32,6 +47,7 @@ struct Hy3TabBarEntry {
237 
238 	void setFocused(bool);
239 	void setUrgent(bool);
240+	void setWindowTitle(std::string);
241 	void prepareTexture(float, wlr_box&);
242 };
243 
244diff --git a/src/main.cpp b/src/main.cpp
245index e2cc10afa14bfecb3f9e1eb0b9900eedd3f7c04a..a572c6c8e69c980baafb558a5fedec4a63550778 100644
246--- a/src/main.cpp
247+++ b/src/main.cpp
248@@ -108,11 +108,18 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
249 	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:no_gaps_when_only", SConfigValue{.intValue = 0});
250 	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:height", SConfigValue{.intValue = 15});
251 	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:padding", SConfigValue{.intValue = 5});
252+	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:from_top", SConfigValue{.intValue = 0});
253+	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:rounding", SConfigValue{.intValue = 3});
254+	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:render_text", SConfigValue{.intValue = 1});
255+	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:text_font", SConfigValue{.strValue = "Sans"});
256+	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:text_height", SConfigValue{.intValue = 8});
257+	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:text_padding", SConfigValue{.intValue = 3});
258 	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:col.active", SConfigValue{.intValue = 0xff32b4ff});
259 	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:col.urgent", SConfigValue{.intValue = 0xffff4f4f});
260 	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:col.inactive", SConfigValue{.intValue = 0x80808080});
261-	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:from_top", SConfigValue{.intValue = 0});
262-	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:rounding", SConfigValue{.intValue = 3});
263+	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:col.text.active", SConfigValue{.intValue = 0xff000000});
264+	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:col.text.urgent", SConfigValue{.intValue = 0xff000000});
265+	HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:tabs:col.text.inactive", SConfigValue{.intValue = 0xff000000});
266 
267 	g_Hy3Layout = std::make_unique<Hy3Layout>();
268 	HyprlandAPI::addLayout(PHANDLE, "hy3", g_Hy3Layout.get());