a1f892fa218f6def606ccb1f81ddc2e57d0551b8
- Author
- outfoxxed <outfoxxed@outfoxxed.me>
- Committer
- outfoxxed <outfoxxed@outfoxxed.me>
- Date
Message
Diff
This diff is truncated to protect this page.
1diff --git a/CHANGELOG.md b/CHANGELOG.md
2index 4354d4ab25254307cff0f168be95c72edeba4b2d..924faa9e54555096727dd9e19f04f31719e6c835 100644
3--- a/CHANGELOG.md
4+++ b/CHANGELOG.md
5@@ -2,6 +2,7 @@
6
7 # Upcoming
8 - Added `toggle` to `hy3:makegroup`
9+- Added `hy3:locktab`
10
11 # hl0.47.0-1 and before
12 - Added focused tab color, to mark selected tabs inside an unfocused container.
13diff --git a/README.md b/README.md
14index 5ce1d224013307ed6bf887b6776bbd78c6838d4e..ac70553d9125d6e6f2f6d164929f824829e9457f 100644
15--- a/README.md
16+++ b/README.md
17@@ -367,12 +367,13 @@ plugin {
18 - `tabnode` - raise focus to the nearest node under the tab
19 - `hy3:togglefocuslayer, [nowarp]` - toggle focus between tiled and floating layers
20 - `nowarp` - do not warp the mouse to the newly focused window
21- - `hy3:focustab [l | r | left | right | index, <index>], [prioritize_hovered | require_hovered], [wrap]`
22+ - `hy3:focustab, [l | r | left | right | index, <index>], [prioritize_hovered | require_hovered], [wrap]`
23 - `l | r | left | right` - direction to change focus towards
24 - `index, <index>` - select the `index`th tab
25 - `prioritize_hovered` - prioritize the tab group under the mouse when multiple are stacked. use the lowest group if none is under the mouse.
26 - `require_hovered` - affect the tab group under the mouse. do nothing if none are hovered.
27 - `wrap` - wrap to the opposite size of the tab bar if moving off the end
28+ - `hy3:locktab, [lock | unlock]` - lock the current tab, makingg it behave like a node
29 - `hy3:debugnodes` - print the node tree into the hyprland log
30 - :warning: **ALPHA QUALITY** `hy3:setswallow, <true | false | toggle>` - set the containing node's window swallow state
31 - :warning: **ALPHA QUALITY** `hy3:expand, <expand | shrink | base>` - expand the current node to cover other nodes
32diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp
33index 8e890090118715e4e7877dcaed745a9da6c05016..227a04910a0f7d8adeba6e4b32ed3ced7914c136 100644
34--- a/src/Hy3Layout.cpp
35+++ b/src/Hy3Layout.cpp
36@@ -130,6 +130,7 @@ void Hy3Layout::insertNode(Hy3Node& node) {
37
38 if (root != nullptr) {
39 opening_after = root->getFocusedNode();
40+ if (opening_after) opening_after = &opening_after->getPlacementActor();
41
42 // opening_after->parent cannot be nullptr
43 if (opening_after == root) {
44@@ -156,6 +157,8 @@ void Hy3Layout::insertNode(Hy3Node& node) {
45 opening_after = this->getNodeFromWindow(mouse_window.get());
46 }
47 }
48+
49+ if (opening_after) opening_after = &opening_after->getPlacementActor();
50 }
51
52 if (opening_after != nullptr
53@@ -713,6 +716,7 @@ void Hy3Layout::makeGroupOnWorkspace(
54 bool toggle
55 ) {
56 auto* node = this->getWorkspaceFocusedNode(workspace);
57+ if (node) node = &node->getPlacementActor();
58
59 if (node && toggle) {
60 auto* parent = node->parent;
61@@ -740,12 +744,14 @@ void Hy3Layout::makeOppositeGroupOnWorkspace(
62 GroupEphemeralityOption ephemeral
63 ) {
64 auto* node = this->getWorkspaceFocusedNode(workspace);
65+ if (node) node = &node->getPlacementActor();
66 this->makeOppositeGroupOn(node, ephemeral);
67 }
68
69 void Hy3Layout::changeGroupOnWorkspace(const CWorkspace* workspace, Hy3GroupLayout layout) {
70 auto* node = this->getWorkspaceFocusedNode(workspace);
71 if (node == nullptr) return;
72+ node = &node->getPlacementActor();
73
74 this->changeGroupOn(*node, layout);
75 }
76@@ -753,6 +759,7 @@ void Hy3Layout::changeGroupOnWorkspace(const CWorkspace* workspace, Hy3GroupLayo
77 void Hy3Layout::untabGroupOnWorkspace(const CWorkspace* workspace) {
78 auto* node = this->getWorkspaceFocusedNode(workspace);
79 if (node == nullptr) return;
80+ node = &node->getPlacementActor();
81
82 this->untabGroupOn(*node);
83 }
84@@ -760,6 +767,7 @@ void Hy3Layout::untabGroupOnWorkspace(const CWorkspace* workspace) {
85 void Hy3Layout::toggleTabGroupOnWorkspace(const CWorkspace* workspace) {
86 auto* node = this->getWorkspaceFocusedNode(workspace);
87 if (node == nullptr) return;
88+ node = &node->getPlacementActor();
89
90 this->toggleTabGroupOn(*node);
91 }
92@@ -767,6 +775,7 @@ void Hy3Layout::toggleTabGroupOnWorkspace(const CWorkspace* workspace) {
93 void Hy3Layout::changeGroupToOppositeOnWorkspace(const CWorkspace* workspace) {
94 auto* node = this->getWorkspaceFocusedNode(workspace);
95 if (node == nullptr) return;
96+ node = &node->getPlacementActor();
97
98 this->changeGroupToOppositeOn(*node);
99 }
100@@ -774,6 +783,7 @@ void Hy3Layout::changeGroupToOppositeOnWorkspace(const CWorkspace* workspace) {
101 void Hy3Layout::changeGroupEphemeralityOnWorkspace(const CWorkspace* workspace, bool ephemeral) {
102 auto* node = this->getWorkspaceFocusedNode(workspace);
103 if (node == nullptr) return;
104+ node = &node->getPlacementActor();
105
106 this->changeGroupEphemeralityOn(*node, ephemeral);
107 }
108@@ -876,20 +886,25 @@ void Hy3Layout::changeGroupEphemeralityOn(Hy3Node& node, bool ephemeral) {
109 }
110
111 void Hy3Layout::shiftNode(Hy3Node& node, ShiftDirection direction, bool once, bool visible) {
112- if (once && node.parent != nullptr && node.parent->data.as_group().children.size() == 1) {
113- if (node.parent->parent == nullptr) {
114- node.parent->data.as_group().setLayout(Hy3GroupLayout::SplitH);
115- node.parent->recalcSizePosRecursive();
116- } else {
117- auto* node2 = node.parent;
118- Hy3Node::swapData(node, *node2);
119- node2->layout->nodes.remove(node);
120- node2->updateTabBarRecursive();
121- node2->recalcSizePosRecursive();
122+ if (once) {
123+ auto& n = node.getPlacementActor();
124+ if (n.parent != nullptr && n.parent->data.as_group().children.size() == 1) {
125+ if (n.parent->parent == nullptr) {
126+ n.parent->data.as_group().setLayout(Hy3GroupLayout::SplitH);
127+ n.parent->recalcSizePosRecursive();
128+ } else {
129+ auto* n2 = n.parent;
130+ Hy3Node::swapData(n, *n2);
131+ n2->layout->nodes.remove(n);
132+ n2->updateTabBarRecursive();
133+ n2->recalcSizePosRecursive();
134+ }
135+
136diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp
137index 78316353c8bbb11551a014eba6ab74fea64327a3..784c0ac51f832769ff742f0e50d910974d53f603 100644
138--- a/src/Hy3Layout.hpp
139+++ b/src/Hy3Layout.hpp
140@@ -54,6 +54,12 @@ enum class TabFocusMousePriority {
141 Require,
142 };
143
144+enum class TabLockMode {
145+ Lock,
146+ Unlock,
147+ Toggle,
148+};
149+
150 enum class SetSwallowOption {
151 NoSwallow,
152 Swallow,
153@@ -105,7 +111,12 @@ public:
154 void onDisable() override;
155
156 void insertNode(Hy3Node& node);
157- void makeGroupOnWorkspace(const CWorkspace* workspace, Hy3GroupLayout, GroupEphemeralityOption, bool toggle);
158+ void makeGroupOnWorkspace(
159+ const CWorkspace* workspace,
160+ Hy3GroupLayout,
161+ GroupEphemeralityOption,
162+ bool toggle
163+ );
164 void makeOppositeGroupOnWorkspace(const CWorkspace* workspace, GroupEphemeralityOption);
165 void changeGroupOnWorkspace(const CWorkspace* workspace, Hy3GroupLayout);
166 void untabGroupOnWorkspace(const CWorkspace* workspace);
167@@ -139,6 +150,7 @@ public:
168 void setNodeSwallow(const CWorkspace* workspace, SetSwallowOption);
169 void killFocusedNode(const CWorkspace* workspace);
170 void expand(const CWorkspace* workspace, ExpandOption, ExpandFullscreenOption);
171+ void setTabLock(const CWorkspace* workspace, TabLockMode);
172 static void warpCursorToBox(const Vector2D& pos, const Vector2D& size);
173 static void warpCursorWithFocus(const Vector2D& pos, bool force = false);
174
175@@ -169,7 +181,7 @@ private:
176 // if shift is true, shift the window in the given direction, returning
177 // nullptr, if shift is false, return the window in the given direction or
178 // nullptr. if once is true, only one group will be broken out of / into
179- Hy3Node* shiftOrGetFocus(Hy3Node&, ShiftDirection, bool shift, bool once, bool visible);
180+ Hy3Node* shiftOrGetFocus(Hy3Node*, ShiftDirection, bool shift, bool once, bool visible);
181
182 void updateAutotileWorkspaces();
183 bool shouldAutotileWorkspace(const CWorkspace* workspace);
184diff --git a/src/Hy3Node.cpp b/src/Hy3Node.cpp
185index 6e5d7986f1ee43be79d09feac8eff09a41f6ed0b..20b687fd00ecbc0793c48cff799497013008e1f5 100644
186--- a/src/Hy3Node.cpp
187+++ b/src/Hy3Node.cpp
188@@ -26,6 +26,7 @@ Hy3GroupData::Hy3GroupData(Hy3GroupLayout layout): layout(layout) {
189
190 Hy3GroupData::Hy3GroupData(Hy3GroupData&& from) {
191 this->layout = from.layout;
192+ this->locked = from.locked;
193 this->previous_nontab_layout = from.previous_nontab_layout;
194 this->children = std::move(from.children);
195 this->group_focused = from.group_focused;
196@@ -301,6 +302,12 @@ Hy3Node& Hy3Node::getExpandActor() {
197 return *node;
198 }
199
200+Hy3Node& Hy3Node::getPlacementActor() {
201+ Hy3Node* node = &this->getExpandActor();
202+ while (node->parent && node->parent->data.as_group().locked) node = node->parent;
203+ return *node;
204+}
205+
206 void Hy3Node::recalcSizePosRecursive(bool no_animation) {
207 // clang-format off
208 static const auto p_gaps_in = ConfigValue<Hyprlang::CUSTOMTYPE, CCssGapData>("general:gaps_in");
209diff --git a/src/Hy3Node.hpp b/src/Hy3Node.hpp
210index ac4ca50a70ae5b4a661facc29179413a3c168df2..af5c1788de4c186fe2415d2b45fe685b954b1e57 100644
211--- a/src/Hy3Node.hpp
212+++ b/src/Hy3Node.hpp
213@@ -37,6 +37,7 @@ struct Hy3GroupData {
214 Hy3Node* focused_child = nullptr;
215 ExpandFocusType expand_focused = ExpandFocusType::NotExpanded;
216 bool ephemeral = false;
217+ bool locked = false;
218 bool containment = false;
219 Hy3TabGroup* tab_bar = nullptr;
220
221@@ -106,6 +107,7 @@ struct Hy3Node {
222 void resize(ShiftDirection, double, bool no_animation = false);
223 bool isIndirectlyFocused();
224 Hy3Node& getExpandActor();
225+ Hy3Node& getPlacementActor();
226
227 void recalcSizePosRecursive(bool no_animation = false);
228 void updateTabBar(bool no_animation = false);
229diff --git a/src/TabGroup.cpp b/src/TabGroup.cpp
230index 8fac8da8d8f6cb8d4463e1dc17f74f98d3a2651a..5d410a1636f4de53d001eed0b8980e9db181e943 100644
231--- a/src/TabGroup.cpp
232+++ b/src/TabGroup.cpp
233@@ -99,6 +99,7 @@ Hy3TabBarEntry::Hy3TabBarEntry(Hy3TabBar& tab_bar, Hy3Node& node): tab_bar(tab_b
234 this->active->setUpdateCallback(update_callback);
235 this->focused->setUpdateCallback(update_callback);
236 this->urgent->setUpdateCallback(update_callback);
237+ this->focused->setUpdateCallback(update_callback);
238 this->offset->setUpdateCallback(update_callback);
239 this->width->setUpdateCallback(update_callback);
240 this->vertical_pos->setUpdateCallback(update_callback);
241@@ -173,18 +174,22 @@ void Hy3TabBarEntry::render(float scale, CBox& box, float opacity_mul) {
242 static const auto col_border_focused = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.focused.border");
243 static const auto col_urgent = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.urgent");
244 static const auto col_border_urgent = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.urgent.border");
245+ static const auto col_locked = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.locked");
246+ static const auto col_border_locked = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.locked.border");
247 static const auto col_inactive = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.inactive");
248 static const auto col_border_inactive = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.inactive.border");
249 // clang-format on
250
251 auto radius = std::min((double) *s_radius * scale, std::min(box.width * 0.5, box.height * 0.5));
252
253- auto color = this->mergeColors(*col_active, *col_focused, *col_urgent, *col_inactive);
254+ auto color =
255+ this->mergeColors(*col_active, *col_focused, *col_urgent, *col_locked, *col_inactive);
256
257 auto border_color = this->mergeColors(
258 *col_border_active,
259 *col_border_focused,
260 *col_border_urgent,
261+ *col_border_locked,
262 *col_border_inactive
263 );
264
265@@ -216,6 +221,7 @@ void Hy3TabBarEntry::renderText(float scale, CBox& box, float opacity) {
266 static const auto col_text_active = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.active.text");
267 static const auto col_text_focused = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.active.text");
268 static const auto col_text_urgent = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.urgent.text");
269+ static const auto col_text_locked = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.locked.text");
270 static const auto col_text_inactive = ConfigValue<Hyprlang::INT>("plugin:hy3:tabs:col.inactive.text");
271 // clang-format on
272
273@@ -343,7 +349,13 @@ void Hy3TabBarEntry::renderText(float scale, CBox& box, float opacity) {
274
275 texture_box.round();
276
277- auto c = mergeColors(*col_text_active, *col_text_focused, *col_text_urgent, *col_text_inactive);
278+ auto c = mergeColors(
279+ *col_text_active,
280+ *col_text_focused,
281+ *col_text_urgent,
282+ *col_text_locked,
283+ *col_text_inactive
284+ );
285
286 glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_ALPHA);
287 glBlendColor(c.r, c.g, c.b, c.a);
288@@ -358,18 +370,20 @@ CHyprColor Hy3TabBarEntry::mergeColors(
289 const CHyprColor& active,
290 const CHyprColor& focused,
291 const CHyprColor& urgent,
292+ const CHyprColor& locked,
293 const CHyprColor& inactive
294 ) {
295- auto focused_av = this->focused->value();
296 auto active_v = this->active->value();
297- auto focused_v = focused_av - active_v;
298- auto urgent_v = this->urgent->value();
299- auto inactive_v = 1.0f - (focused_av + urgent_v);
300+ auto urgent_v = std::max(0.0f, this->urgent->value() - active_v);
301+ auto focused_v = std::max(0.0f, this->focused->value() - active_v - urgent_v);
302+ auto locked_v = std::max(0.0f, this->tab_bar.locked->value() - active_v - urgent_v - focused_v);
303+ auto inactive_v = 1.0f - (active_v + urgent_v + focused_v + locked_v);
304
305 return merge_colors(
306 std::make_pair(active_v, active),
307- std::make_pair(focused_v, focused),
308 std::make_pair(urgent_v, urgent),
309+ std::make_pair(focused_v, focused),
310+ std::make_pair(locked_v, locked),
311 std::make_pair(inactive_v, inactive)
312 );
313 }
314@@ -382,7 +396,15 @@ Hy3TabBar::Hy3TabBar() {
315 AVARDAMAGE_NONE
316 );
317
318+ g_pAnimationManager->createAnimation(
319+ 0.0F,
320+ this->locked,
321+ g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"),
322+ AVARDAMAGE_NONE
323+ );
324+
325 this->fade_opacity->setUpdateCallback([this](auto) { this->dirty = true; });
326+ this->locked->setUpdateCallback([this](auto) { this->dirty = true; });
327 }
328
329 void Hy3TabBar::beginDestroy() {
330@@ -572,6 +594,9 @@ void Hy3TabGroup::updateWithGroup(Hy3Node& node, bool warp) {
331 this->bar.updateNodeList(node.data.as_group().children);
332 this->bar.updateAnimations(warp);
333diff --git a/src/TabGroup.hpp b/src/TabGroup.hpp
334index dbc41299e4b0a5fe99818763b3ddede25bfe6d0d..ec254e92419defc07c5a6ac39f9467dfdaa7705c 100644
335--- a/src/TabGroup.hpp
336+++ b/src/TabGroup.hpp
337@@ -65,6 +65,7 @@ private:
338 const CHyprColor& active,
339 const CHyprColor& focused,
340 const CHyprColor& urgent,
341+ const CHyprColor& locked,
342 const CHyprColor& inactive
343 );
344 };
345@@ -75,6 +76,7 @@ public:
346 bool dirty = true;
347 bool damaged = true;
348 PHLANIMVAR<float> fade_opacity;
349+ PHLANIMVAR<float> locked;
350
351 Hy3TabBar();
352 void beginDestroy();
353diff --git a/src/dispatchers.cpp b/src/dispatchers.cpp
354index 3344e67947068ec5ff14d9bee089b7e4be3fac59..cb2fe383a5fb45161091412455b9caaa8f3824c3 100644
355--- a/src/dispatchers.cpp
356+++ b/src/dispatchers.cpp
357@@ -252,6 +252,17 @@ void dispatch_expand(std::string value) {
358 g_Hy3Layout->expand(workspace.get(), expand, fs_expand);
359 }
360
361+void dispatch_locktab(std::string arg) {
362+ auto workspace = workspace_for_action();
363+ if (!valid(workspace)) return;
364+
365+ auto mode = TabLockMode::Toggle;
366+ if (arg == "lock") mode = TabLockMode::Lock;
367+ else if (arg == "unlock") mode = TabLockMode::Unlock;
368+
369+ g_Hy3Layout->setTabLock(workspace.get(), mode);
370+}
371+
372 void dispatch_debug(std::string arg) {
373 auto workspace = workspace_for_action();
374
375@@ -277,5 +288,6 @@ void registerDispatchers() {
376 HyprlandAPI::addDispatcher(PHANDLE, "hy3:setswallow", dispatch_setswallow);
377 HyprlandAPI::addDispatcher(PHANDLE, "hy3:killactive", dispatch_killactive);
378 HyprlandAPI::addDispatcher(PHANDLE, "hy3:expand", dispatch_expand);
379+ HyprlandAPI::addDispatcher(PHANDLE, "hy3:locktab", dispatch_locktab);
380 HyprlandAPI::addDispatcher(PHANDLE, "hy3:debugnodes", dispatch_debug);
381 }
382diff --git a/src/main.cpp b/src/main.cpp
383index 4fa2de344482a686156ca9c2ca1e07f682cc2260..f74cca89cc5a0200ca64e25e5670f16cf3fc08ab 100644
384--- a/src/main.cpp
385+++ b/src/main.cpp
386@@ -66,6 +66,9 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
387 CONF("tabs:col.urgent", INT, 0x40ff2233);
388 CONF("tabs:col.urgent.border", INT, 0xeeff2233);
389 CONF("tabs:col.urgent.text", INT, 0xffffffff);
390+ CONF("tabs:col.locked", INT, 0x40909033);
391+ CONF("tabs:col.locked.border", INT, 0xee909033);
392+ CONF("tabs:col.locked.text", INT, 0xffffffff);
393
394 // autotiling
395 CONF("autotile:enable", INT, 0);
396diff --git a/src/render.cpp b/src/render.cpp
397index 74c5ddf8996bfd013286e4131579fd68dffd1900..bbd02b4575f6751759c70ef79807524123d29b1a 100644
398--- a/src/render.cpp
399+++ b/src/render.cpp
400@@ -31,7 +31,7 @@ void Hy3Render::renderTab(
401 auto monitorBox = CBox {Vector2D(), monitorSize};
402
403 auto matrix =
404- rdata.monitorProjection.projectBox(monitorBox, HYPRUTILS_TRANSFORM_NORMAL, monitorBox.rot);
405+ rdata.monitorProjection.projectBox(monitorBox, HYPRUTILS_TRANSFORM_NORMAL, monitorBox.rot);
406
407 auto glMatrix = rdata.projection.copy().multiply(matrix);
408