summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Andreev <andreevmaxim@gmail.com>2026-05-05 19:31:09 +0400
committerGitHub <noreply@github.com>2026-05-05 16:31:09 +0100
commitd6aa6af5b3b3cc7c086423cb12c6f2bb76bd15c2 (patch)
tree71500ba1cacf2c3ee4500071a08b9452fcf1aada
parent497b48e8520e4beac16a1a209551c3db46a6d917 (diff)
groups: add groupbar middle_click_close option (#14242)
-rw-r--r--hyprtester/src/tests/main/groups.cpp39
-rw-r--r--meta/hl.meta.lua2
-rw-r--r--src/config/values/ConfigValues.cpp1
-rw-r--r--src/render/decorations/CHyprGroupBarDecoration.cpp10
4 files changed, 49 insertions, 3 deletions
diff --git a/hyprtester/src/tests/main/groups.cpp b/hyprtester/src/tests/main/groups.cpp
index e1d4dd9b..aeb43330 100644
--- a/hyprtester/src/tests/main/groups.cpp
+++ b/hyprtester/src/tests/main/groups.cpp
@@ -400,4 +400,43 @@ TEST_CASE(groups) {
Tests::killAllWindows();
ASSERT(Tests::windowCount(), 0);
+
+ // Test groupbar middle click close config
+ {
+ OK(getFromSocket("/eval hl.config({ group = { auto_group = true, groupbar = { enabled = true, middle_click_close = false } } })"));
+
+ auto kittyA = Tests::spawnKitty("kittyA");
+ if (!kittyA) {
+ FAIL_TEST("Could not spawn kitty");
+ }
+
+ OK(getFromSocket("/dispatch hl.dsp.group.toggle()"));
+
+ auto kittyB = Tests::spawnKitty("kittyB");
+ if (!kittyB) {
+ FAIL_TEST("Could not spawn kitty");
+ }
+
+ EXPECT(Tests::windowCount(), 2);
+
+ OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 80, y = 32 })"));
+ OK(getFromSocket("/eval hl.plugin.test.click(274, 1)"));
+ OK(getFromSocket("/eval hl.plugin.test.click(274, 0)"));
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ EXPECT(Tests::windowCount(), 2);
+
+ OK(getFromSocket("/eval hl.config({ group = { groupbar = { middle_click_close = true } } })"));
+ OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 80, y = 32 })"));
+ OK(getFromSocket("/eval hl.plugin.test.click(274, 1)"));
+ OK(getFromSocket("/eval hl.plugin.test.click(274, 0)"));
+
+ Tests::waitUntilWindowsN(1);
+ EXPECT(Tests::windowCount(), 1);
+
+ OK(getFromSocket("/eval hl.config({ group = { groupbar = { enabled = 0 } } })"));
+ }
+
+ Tests::killAllWindows();
+ ASSERT(Tests::windowCount(), 0);
}
diff --git a/meta/hl.meta.lua b/meta/hl.meta.lua
index cf247ba6..6ea875ae 100644
--- a/meta/hl.meta.lua
+++ b/meta/hl.meta.lua
@@ -212,6 +212,7 @@
---| "group.groupbar.indicator_gap"
---| "group.groupbar.indicator_height"
---| "group.groupbar.keep_upper_gap"
+---| "group.groupbar.middle_click_close"
---| "group.groupbar.priority"
---| "group.groupbar.render_titles"
---| "group.groupbar.round_only_edges"
@@ -1047,6 +1048,7 @@ hl = {}
---@field ['group.groupbar.indicator_gap'] integer|boolean
---@field ['group.groupbar.indicator_height'] integer|boolean
---@field ['group.groupbar.keep_upper_gap'] boolean
+---@field ['group.groupbar.middle_click_close'] boolean
---@field ['group.groupbar.priority'] integer|boolean
---@field ['group.groupbar.render_titles'] boolean
---@field ['group.groupbar.round_only_edges'] boolean
diff --git a/src/config/values/ConfigValues.cpp b/src/config/values/ConfigValues.cpp
index 0214ba86..2c44b172 100644
--- a/src/config/values/ConfigValues.cpp
+++ b/src/config/values/ConfigValues.cpp
@@ -412,6 +412,7 @@ std::vector<SP<IValue>> Values::getConfigValues() {
MS<Int>("group:groupbar:priority", "sets the decoration priority for groupbars", 3, {.min = 0, .max = 6}),
MS<Bool>("group:groupbar:render_titles", "whether to render titles in the group bar decoration", true),
MS<Bool>("group:groupbar:scrolling", "whether scrolling in the groupbar changes group active window", true),
+ MS<Bool>("group:groupbar:middle_click_close", "whether middle clicking the groupbar closes the clicked window", true),
MS<Int>("group:groupbar:rounding", "how much to round the groupbar", 1, {.min = 0, .max = 20}),
MS<Float>("group:groupbar:rounding_power", "rounding power of groupbar corners (2 is a circle)", 2, {.min = 2, .max = 10}),
MS<Int>("group:groupbar:gradient_rounding", "how much to round the groupbar gradient", 2, {.min = 0, .max = 20}),
diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp
index fa4b157e..50b89545 100644
--- a/src/render/decorations/CHyprGroupBarDecoration.cpp
+++ b/src/render/decorations/CHyprGroupBarDecoration.cpp
@@ -431,9 +431,10 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND
}
bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, const IPointer::SButtonEvent& e) {
- static auto PSTACKED = CConfigValue<Config::INTEGER>("group:groupbar:stacked");
- static auto POUTERGAP = CConfigValue<Config::INTEGER>("group:groupbar:gaps_out");
- static auto PINNERGAP = CConfigValue<Config::INTEGER>("group:groupbar:gaps_in");
+ static auto PSTACKED = CConfigValue<Config::INTEGER>("group:groupbar:stacked");
+ static auto POUTERGAP = CConfigValue<Config::INTEGER>("group:groupbar:gaps_out");
+ static auto PINNERGAP = CConfigValue<Config::INTEGER>("group:groupbar:gaps_in");
+ static auto PMIDDLECLICKCLOSE = CConfigValue<Config::INTEGER>("group:groupbar:middle_click_close");
if (m_window->isEffectiveInternalFSMode(FSMODE_FULLSCREEN))
return true;
@@ -444,6 +445,9 @@ bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, const IPo
// close window on middle click
if (e.button == 274) {
+ if (!*PMIDDLECLICKCLOSE)
+ return true;
+
static Vector2D pressedCursorPos;
if (e.state == WL_POINTER_BUTTON_STATE_PRESSED)