Skip to content

Commit db997fd

Browse files
committed
desktop: rewrite reserved area handling
1 parent c249a9f commit db997fd

File tree

21 files changed

+588
-354
lines changed

21 files changed

+588
-354
lines changed

hyprtester/src/tests/main/window.cpp

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -214,22 +214,40 @@ static bool test() {
214214

215215
NLog::log("{}Testing window split ratios", Colors::YELLOW);
216216
{
217-
const double RATIO = 1.25;
218-
const double PERCENT = RATIO / 2.0 * 100.0;
219-
const int GAPSIN = 5;
220-
const int GAPSOUT = 20;
221-
const int BORDERS = 2 * 2;
222-
const int WTRIM = BORDERS + GAPSIN + GAPSOUT;
223-
const int HEIGHT = 1080 - (BORDERS + (GAPSOUT * 2));
224-
const int WIDTH1 = std::round(1920.0 / 2.0 * (2 - RATIO)) - WTRIM;
225-
const int WIDTH2 = std::round(1920.0 / 2.0 * RATIO) - WTRIM;
217+
const double INITIAL_RATIO = 1.25;
218+
const int GAPSIN = 5;
219+
const int GAPSOUT = 20;
220+
const int BORDERSIZE = 2;
221+
const int BORDERS = BORDERSIZE * 2;
222+
const int MONITOR_W = 1920;
223+
const int MONITOR_H = 1080;
224+
225+
const float totalAvailableHeight = MONITOR_H - (GAPSOUT * 2);
226+
const int HEIGHT = std::floor(totalAvailableHeight) - BORDERS;
227+
const float availableWidthForSplit = MONITOR_W - (GAPSOUT * 2) - GAPSIN;
228+
229+
auto calculateFinalWidth = [&](double boxWidth, bool isLeftWindow) {
230+
double gapLeft = isLeftWindow ? GAPSOUT : GAPSIN;
231+
double gapRight = isLeftWindow ? GAPSIN : GAPSOUT;
232+
return std::floor(boxWidth - gapLeft - gapRight - BORDERS);
233+
};
234+
235+
double geomBoxWidthA_R1 = (availableWidthForSplit * INITIAL_RATIO / 2.0) + GAPSOUT + (GAPSIN / 2.0);
236+
double geomBoxWidthB_R1 = MONITOR_W - geomBoxWidthA_R1;
237+
const int WIDTH1 = calculateFinalWidth(geomBoxWidthB_R1, false);
238+
239+
const double INVERTED_RATIO = 0.75;
240+
double geomBoxWidthA_R2 = (availableWidthForSplit * INVERTED_RATIO / 2.0) + GAPSOUT + (GAPSIN / 2.0);
241+
double geomBoxWidthB_R2 = MONITOR_W - geomBoxWidthA_R2;
242+
const int WIDTH2 = calculateFinalWidth(geomBoxWidthB_R2, false);
243+
const int WIDTH_A_FINAL = calculateFinalWidth(geomBoxWidthA_R2, true);
226244

227245
OK(getFromSocket("/keyword dwindle:default_split_ratio 1.25"));
228246

229247
if (!spawnKitty("kitty_B"))
230248
return false;
231249

232-
NLog::log("{}Expecting kitty_B to take up roughly {}% of screen width", Colors::YELLOW, 100 - PERCENT);
250+
NLog::log("{}Expecting kitty_B size: {},{}", Colors::YELLOW, WIDTH1, HEIGHT);
233251
EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("size: {},{}", WIDTH1, HEIGHT));
234252

235253
OK(getFromSocket("/dispatch killwindow activewindow"));
@@ -241,12 +259,12 @@ static bool test() {
241259
if (!spawnKitty("kitty_B"))
242260
return false;
243261

244-
NLog::log("{}Expecting kitty_B to take up roughly {}% of screen width", Colors::YELLOW, PERCENT);
262+
NLog::log("{}Expecting kitty_B size: {},{}", Colors::YELLOW, WIDTH2, HEIGHT);
245263
EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("size: {},{}", WIDTH2, HEIGHT));
246264

247265
OK(getFromSocket("/dispatch focuswindow class:kitty_A"));
248-
NLog::log("{}Expecting kitty_A to have the same width as the previous kitty_B", Colors::YELLOW);
249-
EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("size: {},{}", WIDTH1, HEIGHT));
266+
NLog::log("{}Expecting kitty_A size: {},{}", Colors::YELLOW, WIDTH_A_FINAL, HEIGHT);
267+
EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("size: {},{}", WIDTH_A_FINAL, HEIGHT));
250268

251269
OK(getFromSocket("/keyword dwindle:default_split_ratio 1"));
252270
}

hyprtester/src/tests/main/workspaces.cpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <chrono>
77
#include <hyprutils/os/Process.hpp>
88
#include <hyprutils/memory/WeakPtr.hpp>
9+
#include <hyprutils/utils/ScopeGuard.hpp>
910
#include <csignal>
1011
#include <cerrno>
1112
#include "../shared.hpp"
@@ -14,10 +15,99 @@ static int ret = 0;
1415

1516
using namespace Hyprutils::OS;
1617
using namespace Hyprutils::Memory;
18+
using namespace Hyprutils::Utils;
1719

1820
#define UP CUniquePointer
1921
#define SP CSharedPointer
2022

23+
static bool testAsymmetricGaps() {
24+
NLog::log("{}Testing asymmetric gap splits", Colors::YELLOW);
25+
{
26+
27+
CScopeGuard guard = {[&]() {
28+
NLog::log("{}Cleaning up asymmetric gap test", Colors::YELLOW);
29+
Tests::killAllWindows();
30+
OK(getFromSocket("/reload"));
31+
}};
32+
33+
OK(getFromSocket("/dispatch workspace name:gap_split_test"));
34+
OK(getFromSocket("r/keyword general:gaps_in 0"));
35+
OK(getFromSocket("r/keyword general:border_size 0"));
36+
OK(getFromSocket("r/keyword dwindle:split_width_multiplier 1.0"));
37+
OK(getFromSocket("r/keyword workspace name:gap_split_test,gapsout:0 1000 0 0"));
38+
39+
NLog::log("{}Testing default split (force_split = 0)", Colors::YELLOW);
40+
OK(getFromSocket("r/keyword dwindle:force_split 0"));
41+
42+
if (!Tests::spawnKitty("gaps_kitty_A") || !Tests::spawnKitty("gaps_kitty_B"))
43+
return false;
44+
45+
NLog::log("{}Expecting vertical split (B below A)", Colors::YELLOW);
46+
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_A"));
47+
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
48+
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_B"));
49+
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,540");
50+
51+
Tests::killAllWindows();
52+
EXPECT(Tests::windowCount(), 0);
53+
54+
NLog::log("{}Testing force_split = 1", Colors::YELLOW);
55+
OK(getFromSocket("r/keyword dwindle:force_split 1"));
56+
57+
if (!Tests::spawnKitty("gaps_kitty_A") || !Tests::spawnKitty("gaps_kitty_B"))
58+
return false;
59+
60+
NLog::log("{}Expecting vertical split (B above A)", Colors::YELLOW);
61+
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_B"));
62+
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
63+
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_A"));
64+
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,540");
65+
66+
NLog::log("{}Expecting horizontal split (C left of B)", Colors::YELLOW);
67+
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_B"));
68+
69+
if (!Tests::spawnKitty("gaps_kitty_C"))
70+
return false;
71+
72+
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_C"));
73+
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
74+
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_B"));
75+
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 460,0");
76+
77+
Tests::killAllWindows();
78+
EXPECT(Tests::windowCount(), 0);
79+
80+
NLog::log("{}Testing force_split = 2", Colors::YELLOW);
81+
OK(getFromSocket("r/keyword dwindle:force_split 2"));
82+
83+
if (!Tests::spawnKitty("gaps_kitty_A") || !Tests::spawnKitty("gaps_kitty_B"))
84+
return false;
85+
86+
NLog::log("{}Expecting vertical split (B below A)", Colors::YELLOW);
87+
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_A"));
88+
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
89+
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_B"));
90+
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,540");
91+
92+
NLog::log("{}Expecting horizontal split (C right of A)", Colors::YELLOW);
93+
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_A"));
94+
95+
if (!Tests::spawnKitty("gaps_kitty_C"))
96+
return false;
97+
98+
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_A"));
99+
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
100+
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_C"));
101+
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 460,0");
102+
}
103+
104+
// kill all
105+
NLog::log("{}Killing all windows", Colors::YELLOW);
106+
Tests::killAllWindows();
107+
108+
return true;
109+
}
110+
21111
static bool test() {
22112
NLog::log("{}Testing workspaces", Colors::GREEN);
23113

@@ -359,6 +449,8 @@ static bool test() {
359449
NLog::log("{}Killing all windows", Colors::YELLOW);
360450
Tests::killAllWindows();
361451

452+
testAsymmetricGaps();
453+
362454
NLog::log("{}Expecting 0 windows", Colors::YELLOW);
363455
EXPECT(Tests::windowCount(), 0);
364456

src/Compositor.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1796,10 +1796,13 @@ bool CCompositor::isPointOnAnyMonitor(const Vector2D& point) {
17961796
bool CCompositor::isPointOnReservedArea(const Vector2D& point, const PHLMONITOR pMonitor) {
17971797
const auto PMONITOR = pMonitor ? pMonitor : getMonitorFromVector(point);
17981798

1799-
const auto XY1 = PMONITOR->m_position + PMONITOR->m_reservedTopLeft;
1800-
const auto XY2 = PMONITOR->m_position + PMONITOR->m_size - PMONITOR->m_reservedBottomRight;
1799+
auto box = PMONITOR->logicalBox();
1800+
if (VECNOTINRECT(point, box.x - 1, box.y - 1, box.w + 2, box.h + 2))
1801+
return false;
1802+
1803+
PMONITOR->m_reservedArea.applyip(box);
18011804

1802-
return VECNOTINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y);
1805+
return VECNOTINRECT(point, box.x, box.y, box.x, box.y);
18031806
}
18041807

18051808
CBox CCompositor::calculateX11WorkArea() {
@@ -1809,11 +1812,7 @@ CBox CCompositor::calculateX11WorkArea() {
18091812

18101813
for (const auto& monitor : m_monitors) {
18111814
// we ignore monitor->m_position on purpose
1812-
auto x = monitor->m_reservedTopLeft.x;
1813-
auto y = monitor->m_reservedTopLeft.y;
1814-
auto w = monitor->m_size.x - monitor->m_reservedBottomRight.x - x;
1815-
auto h = monitor->m_size.y - monitor->m_reservedBottomRight.y - y;
1816-
CBox box = {x, y, w, h};
1815+
CBox box = monitor->logicalBoxMinusReserved().translate(-monitor->m_position);
18171816
if ((*PXWLFORCESCALEZERO))
18181817
box.scale(monitor->m_scale);
18191818

src/config/ConfigManager.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,6 @@ std::optional<std::string> CConfigManager::resetHLConfig() {
10921092
g_pAnimationManager->addBezierWithName("linear", Vector2D(0.0, 0.0), Vector2D(1.0, 1.0));
10931093
g_pTrackpadGestures->clearGestures();
10941094

1095-
m_mAdditionalReservedAreas.clear();
10961095
m_workspaceRules.clear();
10971096
setDefaultAnimationVars(); // reset anims
10981097
m_declaredPlugins.clear();
@@ -1136,7 +1135,8 @@ std::optional<std::string> CConfigManager::handleMonitorv2(const std::string& ou
11361135
if (VAL && VAL->m_bSetByUser) {
11371136
const auto ARGS = CVarList(std::any_cast<Hyprlang::STRING>(VAL->getValue()));
11381137
try {
1139-
parser.setReserved({.top = std::stoi(ARGS[0]), .bottom = std::stoi(ARGS[1]), .left = std::stoi(ARGS[2]), .right = std::stoi(ARGS[3])});
1138+
// top, right, bottom, left
1139+
parser.setReserved({std::stoi(ARGS[0]), std::stoi(ARGS[3]), std::stoi(ARGS[1]), std::stoi(ARGS[2])});
11401140
} catch (...) { return "parse error: invalid reserved area"; }
11411141
}
11421142
VAL = m_config->getSpecialConfigValuePtr("monitorv2", "mirror", output.c_str());
@@ -2190,8 +2190,8 @@ void CMonitorRuleParser::setMirror(const std::string& value) {
21902190
m_rule.mirrorOf = value;
21912191
}
21922192

2193-
bool CMonitorRuleParser::setReserved(const SMonitorAdditionalReservedArea& value) {
2194-
g_pConfigManager->m_mAdditionalReservedAreas[name()] = value;
2193+
bool CMonitorRuleParser::setReserved(const Desktop::CReservedArea& value) {
2194+
m_rule.reservedArea = value;
21952195
return true;
21962196
}
21972197

@@ -2222,7 +2222,8 @@ std::optional<std::string> CConfigManager::handleMonitor(const std::string& comm
22222222
return {};
22232223
} else if (ARGS[1] == "addreserved") {
22242224
try {
2225-
parser.setReserved({.top = std::stoi(ARGS[2]), .bottom = std::stoi(ARGS[3]), .left = std::stoi(ARGS[4]), .right = std::stoi(ARGS[5])});
2225+
// top, right, bottom, left
2226+
parser.setReserved({std::stoi(ARGS[2]), std::stoi(ARGS[5]), std::stoi(ARGS[3]), std::stoi(ARGS[4])});
22262227
} catch (...) { return "parse error: invalid reserved area"; }
22272228
return {};
22282229
} else {

src/config/ConfigManager.hpp

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "../SharedDefs.hpp"
1919
#include "../helpers/Color.hpp"
2020
#include "../desktop/DesktopTypes.hpp"
21+
#include "../desktop/reserved/ReservedArea.hpp"
2122
#include "../helpers/memory/Memory.hpp"
2223
#include "../managers/XWaylandManager.hpp"
2324
#include "../managers/KeybindManager.hpp"
@@ -48,13 +49,6 @@ struct SWorkspaceRule {
4849
std::map<std::string, std::string> layoutopts;
4950
};
5051

51-
struct SMonitorAdditionalReservedArea {
52-
int top = 0;
53-
int bottom = 0;
54-
int left = 0;
55-
int right = 0;
56-
};
57-
5852
struct SPluginKeyword {
5953
HANDLE handle = nullptr;
6054
std::string name = "";
@@ -185,7 +179,7 @@ class CMonitorRuleParser {
185179

186180
void setDisabled();
187181
void setMirror(const std::string& value);
188-
bool setReserved(const SMonitorAdditionalReservedArea& value);
182+
bool setReserved(const Desktop::CReservedArea& value);
189183

190184
private:
191185
SMonitorRule m_rule;
@@ -196,36 +190,34 @@ class CConfigManager {
196190
public:
197191
CConfigManager();
198192

199-
void init();
200-
void reload();
201-
std::string verify();
202-
203-
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
204-
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
205-
Vector2D getDeviceVec(const std::string&, const std::string&, const std::string& fallback = "");
206-
std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
207-
bool deviceConfigExplicitlySet(const std::string&, const std::string&);
208-
bool deviceConfigExists(const std::string&);
209-
Hyprlang::CConfigValue* getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback);
193+
void init();
194+
void reload();
195+
std::string verify();
210196

211-
void* const* getConfigValuePtr(const std::string&);
212-
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
213-
std::string getMainConfigPath();
214-
std::string getConfigString();
197+
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
198+
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
199+
Vector2D getDeviceVec(const std::string&, const std::string&, const std::string& fallback = "");
200+
std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
201+
bool deviceConfigExplicitlySet(const std::string&, const std::string&);
202+
bool deviceConfigExists(const std::string&);
203+
Hyprlang::CConfigValue* getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback);
215204

216-
SMonitorRule getMonitorRuleFor(const PHLMONITOR);
217-
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
218-
std::string getDefaultWorkspaceFor(const std::string&);
205+
void* const* getConfigValuePtr(const std::string&);
206+
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
207+
std::string getMainConfigPath();
208+
std::string getConfigString();
219209

220-
PHLMONITOR getBoundMonitorForWS(const std::string&);
221-
std::string getBoundMonitorStringForWS(const std::string&);
222-
const std::vector<SWorkspaceRule>& getAllWorkspaceRules();
210+
SMonitorRule getMonitorRuleFor(const PHLMONITOR);
211+
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
212+
std::string getDefaultWorkspaceFor(const std::string&);
223213

224-
void ensurePersistentWorkspacesPresent();
214+
PHLMONITOR getBoundMonitorForWS(const std::string&);
215+
std::string getBoundMonitorStringForWS(const std::string&);
216+
const std::vector<SWorkspaceRule>& getAllWorkspaceRules();
225217

226-
const std::vector<SConfigOptionDescription>& getAllDescriptions();
218+
void ensurePersistentWorkspacesPresent();
227219

228-
std::unordered_map<std::string, SMonitorAdditionalReservedArea> m_mAdditionalReservedAreas;
220+
const std::vector<SConfigOptionDescription>& getAllDescriptions();
229221

230222
const std::unordered_map<std::string, SP<Hyprutils::Animation::SAnimationPropertyConfig>>& getAnimationConfig();
231223

0 commit comments

Comments
 (0)