Diff
1diff --git a/README.md b/README.md
2index 466fe9e004b49298ace4865cf63521d5f1b11d8d..36cbc0e93eae0d389ffbc6c405b0f6b6af72cdc3 100644
3--- a/README.md
4+++ b/README.md
5@@ -390,3 +390,6 @@ plugin {
6 - `expand` - expand by one node
7 - `shrink` - shrink by one node
8 - `base` - undo all expansions
9+ - `hy3:equalize, [workspace]` - equalize window sizes in group
10+ - no argument: equalizes immediate siblings of the focused window
11+ - `workspace`: equalizes all windows across the entire workspace tree
12diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp
13index 0e120100fe83a848feeca71a9b078ca64a4e7d71..5b379f5f91c6d0acd33441bbc5c744513caf6a10 100644
14--- a/src/Hy3Layout.cpp
15+++ b/src/Hy3Layout.cpp
16@@ -1514,6 +1514,39 @@ void Hy3Layout::setTabLock(const CWorkspace* workspace, TabLockMode mode) {
17 node->updateTabBar();
18 }
19
20+static void equalizeRecursive(Hy3Node* node, bool recursive) {
21+ node->size_ratio = 1.0f;
22+
23+ if (recursive && node->data.is_group()) {
24+ for (auto* child: node->data.as_group().children) {
25+ equalizeRecursive(child, true);
26+ }
27+ }
28+}
29+
30+void Hy3Layout::equalize(const CWorkspace* workspace, bool recursive) {
31+ auto* focused = this->getWorkspaceFocusedNode(workspace);
32+ if (focused == nullptr) return;
33+
34+ Hy3Node* target = nullptr;
35+
36+ if (recursive) {
37+ target = this->getWorkspaceRootGroup(workspace);
38+ if (target != nullptr) {
39+ equalizeRecursive(target, true);
40+ }
41+ } else {
42+ if (focused->parent == nullptr) return;
43+ auto* parent = focused->parent;
44+ equalizeRecursive(parent, false);
45+ target = parent;
46+ }
47+
48+ if (target != nullptr) {
49+ target->recalcSizePosRecursive();
50+ }
51+}
52+
53 void Hy3Layout::warpCursorToBox(const Vector2D& pos, const Vector2D& size) {
54 auto cursorpos = g_pPointerManager->position();
55
56diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp
57index 784c0ac51f832769ff742f0e50d910974d53f603..f894ec580dedb5b21d677478d223fa3a3c527bcf 100644
58--- a/src/Hy3Layout.hpp
59+++ b/src/Hy3Layout.hpp
60@@ -151,6 +151,7 @@ public:
61 void killFocusedNode(const CWorkspace* workspace);
62 void expand(const CWorkspace* workspace, ExpandOption, ExpandFullscreenOption);
63 void setTabLock(const CWorkspace* workspace, TabLockMode);
64+ void equalize(const CWorkspace* workspace, bool recursive = false);
65 static void warpCursorToBox(const Vector2D& pos, const Vector2D& size);
66 static void warpCursorWithFocus(const Vector2D& pos, bool force = false);
67
68diff --git a/src/dispatchers.cpp b/src/dispatchers.cpp
69index e0c359fdf317b8f7acea8da1470c53403d006292..847417d4c6042aeb63062ce838d72b2f689f2a56 100644
70--- a/src/dispatchers.cpp
71+++ b/src/dispatchers.cpp
72@@ -264,6 +264,14 @@ void dispatch_locktab(std::string arg) {
73 g_Hy3Layout->setTabLock(workspace.get(), mode);
74 }
75
76+void dispatch_equalize(std::string arg) {
77+ auto workspace = workspace_for_action();
78+ if (!valid(workspace)) return;
79+
80+ bool recursive = (arg == "workspace");
81+ g_Hy3Layout->equalize(workspace.get(), recursive);
82+}
83+
84 SDispatchResult dispatch_debug(std::string arg) {
85 auto workspace = workspace_for_action();
86
87@@ -292,5 +300,6 @@ void registerDispatchers() {
88 HyprlandAPI::addDispatcher(PHANDLE, "hy3:killactive", dispatch_killactive);
89 HyprlandAPI::addDispatcher(PHANDLE, "hy3:expand", dispatch_expand);
90 HyprlandAPI::addDispatcher(PHANDLE, "hy3:locktab", dispatch_locktab);
91+ HyprlandAPI::addDispatcher(PHANDLE, "hy3:equalize", dispatch_equalize);
92 HyprlandAPI::addDispatcherV2(PHANDLE, "hy3:debugnodes", dispatch_debug);
93 }