3
0
mirror of https://github.com/hyprwm/Hyprland.git synced 2026-08-18 11:02:10 +00:00

groups: add groupbar disable_when_only option (#15009)

* groups: add groupbar disable_when_only option

* groups: improve `groups` test

`groups_disable_when_only` test fails because it checks windows sizes after
`disable_when_only` option changed. Changing option currently don't
trigger window size update.

Same problem with `groups` test, but it worked because it or:
- didn't checked window size after changing option.
- called `hl.dsp.group.toggle()`, which trigger size update
- at the begining set `enable = 1` while it `== 1` by default
Now it fails too :D

Seems it works in usual Hyprland usage because:
- `CHyprGroupBarDecoration::draw` calls
- `g_pDecorationPositioner->repositionDeco(this)`,
  which will invalidate cache and update sizes.

* groups: fix `disable_when_only` and `groups` tests

REFRESH_LAYOUTS is not required 'cause REFRESH_WINDOW_STATES will
trigger update of window position too.

* groups: fix groupbar drawing
This commit is contained in:
feelamee
2026-07-14 15:32:22 +00:00
committed by GitHub
parent f2eafdf105
commit 79bc0ca16e
5 changed files with 98 additions and 10 deletions

View File

@ -109,7 +109,15 @@ TEST_CASE(groups) {
// disable the groupbar for ease of testing for now
NLog::log("{}Disable groupbar", Colors::YELLOW);
OK(getFromSocket("r/eval hl.config({ group = { groupbar = { enabled = 0 } } })"));
OK(getFromSocket("/eval hl.config({ group = { groupbar = { enabled = 0 } } })"));
// check the height of the window now
NLog::log("{}Recheck kitty dimensions", Colors::YELLOW);
{
auto str = getFromSocket("/clients");
EXPECT_CONTAINS(str, "at: 22,22");
EXPECT_CONTAINS(str, "size: 1876,1036");
}
// kill all
NLog::log("{}Kill windows", Colors::YELLOW);
@ -647,3 +655,75 @@ TEST_CASE(groupsLuaApiFullscreen) {
Tests::killAllWindows();
ASSERT(Tests::windowCount(), 0);
}
TEST_CASE(groups_disable_when_only) {
ASSERT(Tests::windowCount(), 0);
NLog::log("{}Testing disable_when_only ", Colors::YELLOW);
auto kittyA = Tests::spawnKitty("kittyA");
if (!kittyA) {
FAIL_TEST("Could not spawn kitty");
}
ASSERT(Tests::windowCount(), 1);
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kittyA' })"));
// check kitty properties. One kitty should take the entire screen, minus the gaps.
NLog::log("{}Check kittyA dimensions", Colors::YELLOW);
{
auto str = getFromSocket("/activewindow");
EXPECT_COUNT_STRING(str, "at: 22,22", 1);
EXPECT_COUNT_STRING(str, "size: 1876,1036", 1);
}
OK(getFromSocket("/dispatch hl.dsp.group.toggle()"));
OK(getFromSocket("/eval hl.config({ group = { groupbar = { disable_when_only = true } } })"));
// check kittyA properties. groupbar should be hidden due to disable_when_only
NLog::log("{}Check kittyA dimensions", Colors::YELLOW);
{
auto str = getFromSocket("/activewindow");
EXPECT_COUNT_STRING(str, "at: 22,22", 1);
EXPECT_COUNT_STRING(str, "size: 1876,1036", 1);
}
auto kittyB = Tests::spawnKitty("kittyB");
if (!kittyB) {
FAIL_TEST("Could not spawn kitty");
}
ASSERT(Tests::windowCount(), 2);
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kittyB' })"));
// check kittyB properties. groupbar is visible
NLog::log("{}Check kittyB dimensions", Colors::YELLOW);
{
auto str = getFromSocket("/activewindow");
EXPECT_CONTAINS(str, "at: 22,43");
EXPECT_COUNT_STRING(str, "size: 1876,1015", 1);
}
OK(getFromSocket("/dispatch hl.dsp.window.kill()"));
Tests::waitUntilWindowsN(1);
ASSERT(Tests::windowCount(), 1);
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kittyA' })"));
// check kittyA properties. groupbar should be hidden due to disable_when_only
NLog::log("{}Check kittyA dimensions", Colors::YELLOW);
{
auto str = getFromSocket("/activewindow");
EXPECT_COUNT_STRING(str, "at: 22,22", 1);
EXPECT_COUNT_STRING(str, "size: 1876,1036", 1);
}
OK(getFromSocket("/eval hl.config({ group = { groupbar = { disable_when_only = false } } })"));
// check kittyA properties. groupbar should be visible due to disable_when_only == false
NLog::log("{}Check kittyA dimensions", Colors::YELLOW);
{
auto str = getFromSocket("/activewindow");
EXPECT_COUNT_STRING(str, "at: 22,43", 1);
EXPECT_COUNT_STRING(str, "size: 1876,1015", 1);
}
Tests::killAllWindows();
ASSERT(Tests::windowCount(), 0);
}

View File

@ -89,6 +89,9 @@ void CPropRefresher::refreshProp(const bool execdAsScheduled) {
if (m_propsTripped & REFRESH_WINDOW_STATES) {
Desktop::Rule::ruleEngine()->updateAllRules();
for (auto const& w : Desktop::windowState()->windows())
w->uncacheWindowDecos();
for (const auto& ws : State::workspaceState()->workspaces()) {
if (!ws)
continue;

View File

@ -433,7 +433,9 @@ std::vector<SP<IValue>> Values::getConfigValues() {
* group:groupbar:
*/
MS<Bool>("group:groupbar:enabled", "enables groupbars", true),
MS<Bool>("group:groupbar:enabled", "enables groupbars", true, {.refresh = Supplementary::REFRESH_WINDOW_STATES}),
MS<Bool>("group:groupbar:disable_when_only", "disable if contains single window. Considered only if enabled == true", false,
{.refresh = Supplementary::REFRESH_WINDOW_STATES}),
MS<String>("group:groupbar:font_family", "font used to display groupbar titles", "[[EMPTY]]"),
MS<FontWeight>("group:groupbar:font_weight_active", "weight of the font used to display active groupbar titles"),
MS<FontWeight>("group:groupbar:font_weight_inactive", "weight of the font used to display inactive groupbar titles"),

View File

@ -25,8 +25,8 @@ static SP<ITexture> m_tGradientLockedInactive;
constexpr int BAR_TEXT_PAD = 2;
CHyprGroupBarDecoration::CHyprGroupBarDecoration(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow), m_window(pWindow) {
static auto PGRADIENTS = CConfigValue<Config::INTEGER>("group:groupbar:enabled");
static auto PENABLED = CConfigValue<Config::INTEGER>("group:groupbar:gradients");
static auto PENABLED = CConfigValue<Config::INTEGER>("group:groupbar:enabled");
static auto PGRADIENTS = CConfigValue<Config::INTEGER>("group:groupbar:gradients");
if (*PENABLED && *PGRADIENTS)
refreshGroupBarGradients();
@ -101,8 +101,10 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) {
const bool VISIBLE = visible();
if (VISIBLE != m_bLastVisibilityStatus)
if (!m_bLastVisibilityStatus.has_value() || VISIBLE != *m_bLastVisibilityStatus) {
g_pDecorationPositioner->repositionDeco(this);
m_bLastVisibilityStatus = VISIBLE;
}
if (!VISIBLE)
return;
@ -353,8 +355,8 @@ static SP<ITexture> renderGradient(Config::CGradientValueData* grad) {
}
void refreshGroupBarGradients() {
static auto PGRADIENTS = CConfigValue<Config::INTEGER>("group:groupbar:enabled");
static auto PENABLED = CConfigValue<Config::INTEGER>("group:groupbar:gradients");
static auto PENABLED = CConfigValue<Config::BOOL>("group:groupbar:enabled");
static auto PGRADIENTS = CConfigValue<Config::BOOL>("group:groupbar:gradients");
static auto PGROUPCOLACTIVE = CConfigValue<Config::IComplexConfigValue>("group:groupbar:col.active");
static auto PGROUPCOLINACTIVE = CConfigValue<Config::IComplexConfigValue>("group:groupbar:col.inactive");
@ -535,6 +537,7 @@ CBox CHyprGroupBarDecoration::assignedBoxGlobal() {
}
bool CHyprGroupBarDecoration::visible() {
static auto PENABLED = CConfigValue<Config::INTEGER>("group:groupbar:enabled");
return *PENABLED && m_window->m_ruleApplicator->decorate().valueOrDefault();
static auto PENABLED = CConfigValue<Config::BOOL>("group:groupbar:enabled");
static auto PDISABLE = CConfigValue<Config::BOOL>("group:groupbar:disable_when_only");
return *PENABLED && (!*PDISABLE || m_dwGroupMembers.size() > 1) && m_window->m_ruleApplicator->decorate().valueOrDefault();
}

View File

@ -58,7 +58,7 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration {
float m_barWidth;
float m_barHeight;
bool m_bLastVisibilityStatus = true;
std::optional<bool> m_bLastVisibilityStatus;
CTitleTex* textureFromTitle(const std::string&);
void invalidateTextures();