dwindle: simplify split_bias logic and set of possible values. (#11448)

This commit is contained in:
Mike Will
2025-08-19 14:32:37 -04:00
committed by GitHub
parent d0d728c6a6
commit 10cec2b7e2
5 changed files with 79 additions and 56 deletions

View File

@@ -46,17 +46,17 @@ static void expectSnapMove(const Vector2D FROM, const Vector2D* TO) {
}
static void testWindowSnap(const bool RESPECTGAPS) {
const double BORDERSIZE = 2;
const double WINDOWSIZE = 100;
const int BORDERSIZE = 2;
const int WINDOWSIZE = 100;
const double OTHER = 500;
const double WINDOWGAP = 8;
const double GAPSIN = 5;
const double GAP = (RESPECTGAPS ? 2 * GAPSIN : 0) + (2 * BORDERSIZE);
const double END = GAP + WINDOWSIZE;
const int OTHER = 500;
const int WINDOWGAP = 8;
const int GAPSIN = 5;
const int GAP = (RESPECTGAPS ? 2 * GAPSIN : 0) + (2 * BORDERSIZE);
const int END = GAP + WINDOWSIZE;
double x;
Vector2D predict;
int x;
Vector2D predict;
x = WINDOWGAP + END;
expectSnapMove({OTHER + x, OTHER}, nullptr);
@@ -71,17 +71,17 @@ static void testWindowSnap(const bool RESPECTGAPS) {
}
static void testMonitorSnap(const bool RESPECTGAPS, const bool OVERLAP) {
const double BORDERSIZE = 2;
const double WINDOWSIZE = 100;
const int BORDERSIZE = 2;
const int WINDOWSIZE = 100;
const double MONITORGAP = 10;
const double GAPSOUT = 20;
const double RESP = (RESPECTGAPS ? GAPSOUT : 0);
const double GAP = RESP + (OVERLAP ? 0 : BORDERSIZE);
const double END = GAP + WINDOWSIZE;
const int MONITORGAP = 10;
const int GAPSOUT = 20;
const int RESP = (RESPECTGAPS ? GAPSOUT : 0);
const int GAP = RESP + (OVERLAP ? 0 : BORDERSIZE);
const int END = GAP + WINDOWSIZE;
double x;
Vector2D predict;
int x;
Vector2D predict;
x = MONITORGAP + GAP;
expectSnapMove({x, x}, nullptr);
@@ -94,9 +94,9 @@ static void testMonitorSnap(const bool RESPECTGAPS, const bool OVERLAP) {
expectSnapMove({1920 - x, 1080 - x}, &(predict = {1920 - END, 1080 - END}));
// test reserved area
const double RESERVED = 200;
const double RGAP = RESERVED + RESP + BORDERSIZE;
const double REND = RGAP + WINDOWSIZE;
const int RESERVED = 200;
const int RGAP = RESERVED + RESP + BORDERSIZE;
const int REND = RGAP + WINDOWSIZE;
x = MONITORGAP + RGAP;
expectSnapMove({x, x}, nullptr);

View File

@@ -1,22 +1,24 @@
#include "tests.hpp"
#include "../../shared.hpp"
#include "../../hyprctlCompat.hpp"
#include <print>
#include <cmath>
#include <thread>
#include <chrono>
#include <hyprutils/os/Process.hpp>
#include <hyprutils/memory/WeakPtr.hpp>
#include <csignal>
#include <cerrno>
#include "../../shared.hpp"
#include "../../hyprctlCompat.hpp"
#include "../shared.hpp"
#include "tests.hpp"
static int ret = 0;
static int ret = 0;
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
#define UP CUniquePointer
#define SP CSharedPointer
static bool spawnKitty(const std::string& class_) {
NLog::log("{}Spawning {}", Colors::YELLOW, class_);
if (!Tests::spawnKitty(class_)) {
NLog::log("{}Error: {} did not spawn", Colors::RED, class_);
return false;
}
return true;
}
static bool test() {
NLog::log("{}Testing windows", Colors::GREEN);
@@ -25,19 +27,11 @@ static bool test() {
NLog::log("{}Switching to workspace `window`", Colors::YELLOW);
getFromSocket("/dispatch workspace name:window");
NLog::log("{}Spawning kittyProcA", Colors::YELLOW);
auto kittyProcA = Tests::spawnKitty();
if (!kittyProcA) {
NLog::log("{}Error: kitty did not spawn", Colors::RED);
if (!spawnKitty("kitty_A"))
return false;
}
NLog::log("{}Expecting 1 window", Colors::YELLOW);
EXPECT(Tests::windowCount(), 1);
// check kitty properties. One kitty should take the entire screen, as this is smart gaps
NLog::log("{}Expecting kitty to take up the whole screen", Colors::YELLOW);
NLog::log("{}Expecting kitty_A to take up the whole screen", Colors::YELLOW);
{
auto str = getFromSocket("/clients");
EXPECT(str.contains("at: 0,0"), true);
@@ -45,15 +39,44 @@ static bool test() {
EXPECT(str.contains("fullscreen: 0"), true);
}
NLog::log("{}Spawning kittyProcB", Colors::YELLOW);
auto kittyProcB = Tests::spawnKitty();
if (!kittyProcB) {
NLog::log("{}Error: kitty did not spawn", Colors::RED);
return false;
}
NLog::log("{}Testing window split ratios", Colors::YELLOW);
{
const double RATIO = 1.25;
const double PERCENT = RATIO / 2.0 * 100.0;
const int GAPSIN = 5;
const int GAPSOUT = 20;
const int BORDERS = 2 * 2;
const int WTRIM = BORDERS + GAPSIN + GAPSOUT;
const int HEIGHT = 1080 - (BORDERS + (GAPSOUT * 2));
const int WIDTH1 = std::round(1920.0 / 2.0 * (2 - RATIO)) - WTRIM;
const int WIDTH2 = std::round(1920.0 / 2.0 * RATIO) - WTRIM;
NLog::log("{}Expecting 2 windows", Colors::YELLOW);
EXPECT(Tests::windowCount(), 2);
OK(getFromSocket("/keyword dwindle:default_split_ratio 1.25"));
if (!spawnKitty("kitty_B"))
return false;
NLog::log("{}Expecting kitty_B to take up roughly {}% of screen width", Colors::YELLOW, 100 - PERCENT);
EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("size: {},{}", WIDTH1, HEIGHT));
OK(getFromSocket("/dispatch killwindow activewindow"));
Tests::waitUntilWindowsN(1);
NLog::log("{}Inverting the split ratio", Colors::YELLOW);
OK(getFromSocket("/keyword dwindle:default_split_ratio 0.75"));
if (!spawnKitty("kitty_B"))
return false;
NLog::log("{}Expecting kitty_B to take up roughly {}% of screen width", Colors::YELLOW, PERCENT);
EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("size: {},{}", WIDTH2, HEIGHT));
OK(getFromSocket("/dispatch focuswindow class:kitty_A"));
NLog::log("{}Expecting kitty_A to have the same width as the previous kitty_B", Colors::YELLOW);
EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("size: {},{}", WIDTH1, HEIGHT));
OK(getFromSocket("/keyword dwindle:default_split_ratio 1"));
}
// open xeyes
NLog::log("{}Spawning xeyes", Colors::YELLOW);

View File

@@ -165,6 +165,7 @@ animations {
dwindle {
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
preserve_split = true # You probably want this
split_bias = 1
}
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more

View File

@@ -1827,9 +1827,9 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
},
SConfigOptionDescription{
.value = "dwindle:split_bias",
.description = "specifies which window will receive the larger half of a split. positional - 0, current window - 1, opening window - 2 [0/1/2]",
.description = "specifies which window will receive the split ratio. 0 -> directional (the top or left window), 1 -> the current window",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "positional,current,opening"},
.data = SConfigOptionDescription::SChoiceData{0, "directional,current"},
},
SConfigOptionDescription{
.value = "dwindle:precise_mouse_move",

View File

@@ -347,6 +347,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
static auto PFORCESPLIT = CConfigValue<Hyprlang::INT>("dwindle:force_split");
static auto PERMANENTDIRECTIONOVERRIDE = CConfigValue<Hyprlang::INT>("dwindle:permanent_direction_override");
static auto PSMARTSPLIT = CConfigValue<Hyprlang::INT>("dwindle:smart_split");
static auto PSPLITBIAS = CConfigValue<Hyprlang::INT>("dwindle:split_bias");
bool horizontalOverride = false;
bool verticalOverride = false;
@@ -427,9 +428,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
}
// split in favor of a specific window
const auto first = NEWPARENT->children[0];
static auto PSPLITBIAS = CConfigValue<Hyprlang::INT>("dwindle:split_bias");
if ((*PSPLITBIAS == 1 && first == PNODE) || (*PSPLITBIAS == 2 && first == OPENINGON))
if (*PSPLITBIAS && NEWPARENT->children[0] == PNODE)
NEWPARENT->splitRatio = 2.f - NEWPARENT->splitRatio;
// and update the previous parent if it exists