Diff
1diff --git a/CHANGELOG.md b/CHANGELOG.md
2index f23978f187f0a42b48fd34d7ed2b4840376d682e..bd12816c474bc586f1daf8411ba51531bcc53f40 100644
3--- a/CHANGELOG.md
4+++ b/CHANGELOG.md
5@@ -2,9 +2,9 @@
6
7 # Upcoming
8
9-- Added configurable borders to tabs
10+- Added configurable borders and blurred backgrounds to tabs.
11 - Renamed `hy3:tabs:rounding` to `hy3:tabs:radius`.
12-- Changed default tab style
13+- Changed default tab style.
14
15 # hl0.46.0 and before
16
17diff --git a/CMakeLists.txt b/CMakeLists.txt
18index 59297b5ca850b34b6b86628cc8292e5c6b10c3ad..12d2a4b0c5818b99a402a945ec4ae3db9eb4787c 100644
19--- a/CMakeLists.txt
20+++ b/CMakeLists.txt
21@@ -24,11 +24,11 @@ add_library(hy3 SHARED
22 src/render.cpp
23 )
24
25-configure_file(src/simple_quad.vert ${CMAKE_CURRENT_BINARY_DIR}/src/simple_quad.vert COPYONLY)
26-file(READ ${CMAKE_CURRENT_BINARY_DIR}/src/simple_quad.vert SHADER_SIMPLE_QUAD)
27+configure_file(src/tab.vert ${CMAKE_CURRENT_BINARY_DIR}/src/tab.vert COPYONLY)
28+file(READ ${CMAKE_CURRENT_BINARY_DIR}/src/tab.vert SHADER_TAB_VERT)
29
30-configure_file(src/border_rect.frag ${CMAKE_CURRENT_BINARY_DIR}/src/border_rect.frag COPYONLY)
31-file(READ ${CMAKE_CURRENT_BINARY_DIR}/src/border_rect.frag SHADER_BORDER_RECT)
32+configure_file(src/tab.frag ${CMAKE_CURRENT_BINARY_DIR}/src/tab.frag COPYONLY)
33+file(READ ${CMAKE_CURRENT_BINARY_DIR}/src/tab.frag SHADER_TAB_FRAG)
34
35 configure_file(src/shader_content.hpp.in src/shader_content.hpp @ONLY)
36 target_include_directories(hy3 PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
37diff --git a/README.md b/README.md
38index 740215e64d5f8d37b04e08f4b8c99dd85c79f23d..16b5c13bc23da36afcd14b83332e4f277df1ce27 100644
39--- a/README.md
40+++ b/README.md
41@@ -280,6 +280,14 @@ plugin {
42 col.inactive = <color> # default: rgba(30303090)
43 col.border.inactive = <color> # default: rgba(505050b0)
44 col.text.inactive = <color> # default: rgba(ffffffff)
45+
46+ # if tab backgrounds should be blurred
47+ # Blur is only visible when the above colors are not opaque.
48+ blur = <bool> # default: true
49+
50+ # opacity multiplier for tabs
51+ # Applies to blur as well as the given colors.
52+ opacity = <float> # default: 1.0
53 }
54
55 # autotiling settings
56diff --git a/src/TabGroup.cpp b/src/TabGroup.cpp
57index 01b0695e3412e75557a73933fb8a4448c3249283..c9ac3250bb2ca53b47e20fa5ca8cf5c57a87e238 100644
58--- a/src/TabGroup.cpp
59+++ b/src/TabGroup.cpp
60@@ -125,6 +125,8 @@ void Hy3TabBarEntry::render(float scale, CBox& box, float opacity_mul) {
61 // clang-format off
62 static const auto s_radius = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:radius");
63 static const auto border_width = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:border_width");
64+ static const auto s_opacity = ConfigValue<Hyprlang::FLOAT>("plugin:hy3:tabs:opacity");
65+ static const auto blur = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:blur");
66 static const auto col_active = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.active");
67 static const auto col_border_active = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.border.active");
68 static const auto col_urgent = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.urgent");
69@@ -157,15 +159,21 @@ void Hy3TabBarEntry::render(float scale, CBox& box, float opacity_mul) {
70 CHyprColor(*col_border_inactive)
71 );
72
73- color.a *= opacity;
74- border_color.a *= opacity;
75-
76 box.round();
77
78 // sometimes enabled before our renderer is called
79 glDisable(GL_SCISSOR_TEST);
80
81- Hy3Render::renderBorderRect(box, color, border_color, *border_width, radius);
82+ Hy3Render::renderTab(
83+ box,
84+ opacity * *s_opacity,
85+ *blur,
86+ color,
87+ border_color,
88+ *border_width,
89+ radius
90+ );
91+
92 this->renderText(scale, box, opacity);
93 }
94
95diff --git a/src/main.cpp b/src/main.cpp
96index 87c39b0b54d1058b63c55b7b2d20740b4048f009..f984a67f52f1e443505402eac659ca0e962f86fc 100644
97--- a/src/main.cpp
98+++ b/src/main.cpp
99@@ -2,6 +2,7 @@
100 #include <hyprland/src/config/ConfigDataValues.hpp>
101 #include <hyprland/src/plugins/PluginAPI.hpp>
102 #include <hyprland/src/version.h>
103+#include <hyprlang.hpp>
104
105 #include "SelectionHook.hpp"
106 #include "dispatchers.hpp"
107@@ -30,6 +31,7 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
108 #define CONF(NAME, TYPE, VALUE) \
109 HyprlandAPI::addConfigValue(PHANDLE, "plugin:hy3:" NAME, Hyprlang::CConfigValue((TYPE) VALUE))
110
111+ using Hyprlang::FLOAT;
112 using Hyprlang::INT;
113 using Hyprlang::STRING;
114
115@@ -50,12 +52,14 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
116 CONF("tabs:text_font", STRING, "Sans");
117 CONF("tabs:text_height", INT, 8);
118 CONF("tabs:text_padding", INT, 3);
119- CONF("tabs:col.active", INT, 0xb050a0e0);
120- CONF("tabs:col.border.active", INT, 0xb070b0c0);
121- CONF("tabs:col.urgent", INT, 0xb0ff4f4f);
122- CONF("tabs:col.border.urgent", INT, 0xb0ff8080);
123- CONF("tabs:col.inactive", INT, 0x90303030);
124- CONF("tabs:col.border.inactive", INT, 0xb0505050);
125+ CONF("tabs:opacity", FLOAT, 1.0);
126+ CONF("tabs:blur", INT, 1);
127+ CONF("tabs:col.active", INT, 0xff50a0e0);
128+ CONF("tabs:col.border.active", INT, 0xff70b0c0);
129+ CONF("tabs:col.urgent", INT, 0xffff4f4f);
130+ CONF("tabs:col.border.urgent", INT, 0xffff8080);
131+ CONF("tabs:col.inactive", INT, 0x50303030);
132+ CONF("tabs:col.border.inactive", INT, 0x90505050);
133 CONF("tabs:col.text.active", INT, 0xff000000);
134 CONF("tabs:col.text.urgent", INT, 0xff000000);
135 CONF("tabs:col.text.inactive", INT, 0xffffffff);
136diff --git a/src/render.cpp b/src/render.cpp
137index db30cea440f777252aaec9e330fe6488ce46e7d3..a557a1777a65e2cac7b719f22ebe5aa1b26f2558 100644
138--- a/src/render.cpp
139+++ b/src/render.cpp
140@@ -3,26 +3,32 @@
141 #include <GLES2/gl2.h>
142 #include <hyprland/src/helpers/math/Math.hpp>
143 #include <hyprland/src/render/OpenGL.hpp>
144+#include <hyprutils/math/Vector2D.hpp>
145
146 #include "shaders.hpp"
147
148-void Hy3Render::renderBorderRect(
149+void Hy3Render::renderTab(
150 const CBox& box,
151+ float opacity,
152+ bool blur,
153 const CHyprColor& fillColor,
154 const CHyprColor& borderColor,
155 int borderWidth,
156 int radius
157 ) {
158- static auto& shader = Hy3Shaders::instance()->border_rect;
159+ static auto& shader = Hy3Shaders::instance()->tab;
160 auto& rdata = g_pHyprOpenGL->m_RenderData;
161
162 auto rbox = box;
163 rdata.renderModif.applyToBox(rbox);
164
165+ const auto& monitorSize = rdata.pMonitor->vecTransformedSize;
166+ auto monitorBox = CBox {Vector2D(), monitorSize};
167+
168 auto matrix = rdata.monitorProjection.projectBox(
169- rbox,
170+ monitorBox,
171 wlTransformToHyprutils(invertTransform(rdata.pMonitor->transform)),
172- rbox.rot
173+ monitorBox.rot
174 );
175
176 auto glMatrix = rdata.projection.copy().multiply(matrix);
177@@ -36,6 +42,18 @@ void Hy3Render::renderBorderRect(
178 glUniformMatrix3fv(shader.proj, 1, GL_FALSE, glMatrix.getMatrix().data());
179 #endif
180
181+ WP<CTexture> blurTex;
182+
183+ if (blur) {
184+ blurTex = rdata.pCurrentMonData->blurFB.getTexture();
185+
186+ glActiveTexture(GL_TEXTURE0);
187+ glBindTexture(blurTex->m_iTarget, blurTex->m_iTexID);
188+ glUniform1i(shader.blurTex, 0);
189+ }
190+
191+ glUniform1i(shader.applyBlur, blur);
192+
193 // premultiplied
194 glUniform4f(
195 shader.fillColor,
196@@ -55,7 +73,10 @@ void Hy3Render::renderBorderRect(
197 );
198 }
199
200+ glUniform2f(shader.monitorSize, monitorSize.x, monitorSize.y);
201+ glUniform2f(shader.pixelOffset, rbox.x, rbox.y);
202 glUniform2f(shader.pixelSize, rbox.w, rbox.h);
203+ glUniform1f(shader.opacity, opacity);
204 glUniform1f(shader.outerRadius, radius);
205 glUniform1f(shader.borderWidth, borderWidth);
206
207@@ -65,4 +86,8 @@ void Hy3Render::renderBorderRect(
208 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
209
210 glDisableVertexAttribArray(shader.posAttrib);
211+
212+ if (blur) {
213+ glBindTexture(blurTex->m_iTarget, 0);
214+ }
215 }
216diff --git a/src/render.hpp b/src/render.hpp
217index 6efdf1d1e27dc60163d88c4be424d1f5b0744236..f9aefe8fa4a2d5e7e2560b38c5665ddee608563e 100644
218--- a/src/render.hpp
219+++ b/src/render.hpp
220@@ -4,8 +4,10 @@
221
222 class Hy3Render {
223 public:
224- static void renderBorderRect(
225+ static void renderTab(
226 const CBox& box,
227+ float opacity,
228+ bool blur,
229 const CHyprColor& fillColor,
230 const CHyprColor& borderColor,
231 int borderWidth,
232diff --git a/src/shader_content.hpp.in b/src/shader_content.hpp.in
233index 6e242a452fe1910df06988b1c4ba869ae2418239..8d1d84ae897a9054d38584753da4cd80405bb1fe 100644
234--- a/src/shader_content.hpp.in
235+++ b/src/shader_content.hpp.in
236@@ -1,4 +1,4 @@
237 #include <string_view>
238
239-constexpr std::string_view SHADER_SIMPLE_QUAD = R"(@SHADER_SIMPLE_QUAD@)";
240-constexpr std::string_view SHADER_BORDER_RECT_FRAG = R"(@SHADER_BORDER_RECT@)";
241+constexpr std::string_view SHADER_TAB_VERT = R"(@SHADER_TAB_VERT@)";
242+constexpr std::string_view SHADER_TAB_FRAG = R"(@SHADER_TAB_FRAG@)";
243diff --git a/src/shaders.cpp b/src/shaders.cpp
244index 88f02f407f817da6cb0608f0dcdfb676e533c059..e5e011d9a11739246c08757e43a0e7c221002f14 100644
245--- a/src/shaders.cpp
246+++ b/src/shaders.cpp
247@@ -8,19 +8,24 @@
248
249 Hy3Shaders::Hy3Shaders() {
250 {
251- auto& s = this->border_rect;
252- s.program = Hy3Shaders::createProgram(SHADER_SIMPLE_QUAD, SHADER_BORDER_RECT_FRAG);
253+ auto& s = this->tab;
254+ s.program = Hy3Shaders::createProgram(SHADER_TAB_VERT, SHADER_TAB_FRAG);
255 s.posAttrib = glGetAttribLocation(s.program, "pos");
256 s.proj = glGetUniformLocation(s.program, "proj");
257+ s.monitorSize = glGetUniformLocation(s.program, "monitorSize");
258+ s.pixelOffset = glGetUniformLocation(s.program, "pixelOffset");
259 s.pixelSize = glGetUniformLocation(s.program, "pixelSize");
260+ s.applyBlur = glGetUniformLocation(s.program, "applyBlur");
261+ s.blurTex = glGetUniformLocation(s.program, "blurTex");
262+ s.opacity = glGetUniformLocation(s.program, "opacity");
263 s.fillColor = glGetUniformLocation(s.program, "fillColor");
264 s.borderColor = glGetUniformLocation(s.program, "borderColor");
265- s.outerRadius = glGetUniformLocation(s.program, "outerRadius");
266 s.borderWidth = glGetUniformLocation(s.program, "borderWidth");
267+ s.outerRadius = glGetUniformLocation(s.program, "outerRadius");
268 }
269 }
270
271-Hy3Shaders::~Hy3Shaders() { glDeleteProgram(this->border_rect.program); }
272+Hy3Shaders::~Hy3Shaders() { glDeleteProgram(this->tab.program); }
273
274 Hy3Shaders* Hy3Shaders::instance() {
275 static auto* INSTANCE = new Hy3Shaders();
276diff --git a/src/shaders.hpp b/src/shaders.hpp
277index 1fb39a003909a8f1e97bdd8f46a5d64f5db980ca..07d331b3e03c3168779403fb82c35f7c0dc8ab19 100644
278--- a/src/shaders.hpp
279+++ b/src/shaders.hpp
280@@ -11,12 +11,17 @@ public:
281 GLuint program;
282 GLuint posAttrib;
283 GLint proj;
284+ GLint monitorSize;
285+ GLint pixelOffset;
286+ GLint pixelSize;
287+ GLint applyBlur;
288+ GLint blurTex;
289+ GLint opacity;
290 GLint fillColor;
291 GLint borderColor;
292- GLint pixelSize;
293- GLint outerRadius;
294 GLint borderWidth;
295- } border_rect;
296+ GLint outerRadius;
297+ } tab;
298
299 static Hy3Shaders* instance();
300
301diff --git a/src/simple_quad.vert b/src/simple_quad.vert
302deleted file mode 100644
303index 0398200e810f607690ba2a0880851c7f8377da64..0000000000000000000000000000000000000000
304--- a/src/simple_quad.vert
305+++ /dev/null
306@@ -1,11 +0,0 @@
307-attribute highp vec2 pos;
308-attribute highp vec2 texcoord;
309-
310-uniform mat3 proj;
311-
312-varying highp vec2 v_texcoord;
313-
314-void main() {
315- gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);
316- v_texcoord = pos;
317-}
318diff --git a/src/border_rect.frag b/src/tab.frag
319rename from src/border_rect.frag
320rename to src/tab.frag
321index e2d6684aa8721bcb98f2a6e5f07bc11dfda2c468..49ea01ac5ef35022605afd0ef6a703fdd298aa6b 100644
322--- a/src/border_rect.frag
323+++ b/src/tab.frag
324@@ -1,15 +1,20 @@
325 precision highp float;
326-varying highp vec4 v_color;
327-varying highp vec2 v_texcoord;
328
329+uniform highp vec2 pixelSize;
330+uniform float opacity;
331 uniform highp vec4 fillColor;
332 uniform highp vec4 borderColor;
333-uniform highp vec2 pixelSize;
334 uniform float outerRadius;
335 uniform float borderWidth;
336
337+uniform bool applyBlur;
338+uniform sampler2D blurTex;
339+
340+varying highp vec2 pixCoord;
341+varying highp vec2 monitorTexCoord;
342+
343 void main() {
344- highp vec2 pixCoord = v_texcoord * pixelSize;
345+ float opacityMul = opacity;
346 highp vec2 cornerDist = min(pixCoord, pixelSize - pixCoord);
347
348 gl_FragColor = fillColor;
349@@ -37,7 +42,8 @@ void main() {
350 dist = sqrt(distSq);
351 calculatedDist = true;
352 float normalized = 1.0 - smoothstep(0.0, 1.0, (dist - outerRadius + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT_2X));
353- gl_FragColor = borderColor * normalized;
354+ gl_FragColor = borderColor;
355+ opacityMul *= normalized;
356 } else if (distSq > innerTest2 * innerTest2) {
357 gl_FragColor = borderColor;
358 }
359@@ -50,4 +56,10 @@ void main() {
360 } else if (cornerDist.x <= borderWidth || cornerDist.y <= borderWidth) {
361 gl_FragColor = borderColor;
362 }
363+
364+ if (applyBlur && gl_FragColor.a != 1.0) {
365+ gl_FragColor = gl_FragColor + texture2D(blurTex, monitorTexCoord) * (1.0 - gl_FragColor.a);
366+ }
367+
368+ gl_FragColor *= opacityMul;
369 }
370diff --git a/src/tab.vert b/src/tab.vert
371new file mode 100644
372index 0000000000000000000000000000000000000000..4db84bf136db2133ab038b0c8beb7e2b592263a0
373--- /dev/null
374+++ b/src/tab.vert
375@@ -0,0 +1,15 @@
376+attribute highp vec2 pos;
377+
378+uniform mat3 proj;
379+uniform highp vec2 pixelOffset;
380+uniform highp vec2 pixelSize;
381+uniform highp vec2 monitorSize;
382+
383+varying highp vec2 pixCoord;
384+varying highp vec2 monitorTexCoord;
385+
386+void main() {
387+ pixCoord = pos * pixelSize;
388+ monitorTexCoord = (pixelOffset + pixCoord) / monitorSize;
389+ gl_Position = vec4(proj * vec3(monitorTexCoord, 1.0), 1.0);
390+}