mirror of
https://github.com/hyprwm/Hyprland.git
synced 2026-08-24 02:24:14 -05:00
config: Add cursor:warp_on_monitor_change (#15844)
Allow to control cursor warping when switching to a workspace on a different monitor.
This commit is contained in:
@@ -173,11 +173,13 @@ inline std::map<std::string, std::shared_ptr<CTestCase>> testCases;
|
||||
} while (0)
|
||||
|
||||
#define EXPECT_NOT(expr, val) \
|
||||
if (const auto RESULT = expr; RESULT == (val)) { \
|
||||
MARK_TEST_FAILED("{}, expected not {}, got {}", #expr, val, RESULT); \
|
||||
} else { \
|
||||
LOG_OK("{}. Got {}", #expr, val); \
|
||||
}
|
||||
do { \
|
||||
if (const auto RESULT = expr; RESULT == (val)) { \
|
||||
MARK_TEST_FAILED("{}, expected not {}, got {}", #expr, val, RESULT); \
|
||||
} else { \
|
||||
LOG_OK("{}. Got {}", #expr, val); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define EXPECT_VECTOR2D(expr, val) \
|
||||
do { \
|
||||
|
||||
@@ -225,10 +225,7 @@ TEST_CASE(globalWindowMoveState) {
|
||||
}
|
||||
|
||||
TEST_CASE(pointerNoWarpsFocusesMonitorOnly) {
|
||||
CScopeGuard guard = {[&]() {
|
||||
OK(getFromSocket("/eval hl.config({ cursor = { no_warps = false } })"));
|
||||
cleanupRefactorStateMonitors();
|
||||
}};
|
||||
CScopeGuard guard = {[&]() { cleanupRefactorStateMonitors(); }};
|
||||
|
||||
ASSERT(prepareRefactorStateMonitors(), true);
|
||||
Tests::killAllWindows();
|
||||
@@ -253,3 +250,72 @@ TEST_CASE(pointerNoWarpsFocusesMonitorOnly) {
|
||||
OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 2000, y = 10 })"));
|
||||
EXPECT_NOT(getFromSocket("/cursorpos"), originalCursor);
|
||||
}
|
||||
|
||||
SUBTEST(checkCursorWarpWhenSwitchingMonitor, bool noWarps, int warpOnChangeWorkspace, int warpOnMonitorChange, bool expectMove) {
|
||||
auto conf = std::format("/eval hl.config({{ cursor = {{ no_warps = {}, warp_on_change_workspace = {}, warp_on_monitor_change = {} }} }})", noWarps, warpOnChangeWorkspace,
|
||||
warpOnMonitorChange);
|
||||
NLog::yellow("{}", conf);
|
||||
OK(getFromSocket(conf));
|
||||
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = 300 })"));
|
||||
OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 5, y = 5 })"));
|
||||
ASSERT(getFromSocket("/cursorpos"), "5, 5");
|
||||
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = 301 })"));
|
||||
if (expectMove)
|
||||
EXPECT_NOT(getFromSocket("/cursorpos"), "5, 5");
|
||||
else
|
||||
EXPECT(getFromSocket("/cursorpos"), "5, 5");
|
||||
|
||||
// TODO: uncomment after #15649 is resolved. Might need an additional fix in ConfigActions to pass:
|
||||
// focusing with `hl.dsp.focus({ monitor = ... })` should trigger proper workspace switching.
|
||||
/*
|
||||
OK(getFromSocket(std::format("/dispatch hl.dsp.focus({{ monitor = '{}' }})", TEST_MONITOR_LEFT)));
|
||||
OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 5, y = 5 })"));
|
||||
ASSERT(getFromSocket("/cursorpos"), "5, 5");
|
||||
|
||||
OK(getFromSocket(std::format("/dispatch hl.dsp.focus({{ monitor = '{}' }})", TEST_MONITOR_RIGHT)));
|
||||
if (expectMove)
|
||||
EXPECT_NOT(getFromSocket("/cursorpos"), "5, 5");
|
||||
else
|
||||
EXPECT(getFromSocket("/cursorpos"), "5, 5");
|
||||
*/
|
||||
}
|
||||
|
||||
TEST_CASE(cursorWarpFocusOnMonitorChange) {
|
||||
CScopeGuard guard = {[&]() { cleanupRefactorStateMonitors(); }};
|
||||
ASSERT(prepareRefactorStateMonitors(), true);
|
||||
|
||||
OK(getFromSocket(std::format("/dispatch hl.dsp.focus({{ monitor = '{}' }})", TEST_MONITOR_RIGHT)));
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '301' })"));
|
||||
SPAWN_KITTY("kitty301"); // A window must exist on the workspace (bug #15649)
|
||||
OK(getFromSocket(std::format("/dispatch hl.dsp.focus({{ monitor = '{}' }})", TEST_MONITOR_LEFT)));
|
||||
SPAWN_KITTY("kitty300"); // A window must exist on the workspace (bug #15649)
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '300' })"));
|
||||
|
||||
// no_warps, W, M, expect_move
|
||||
//CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, false, 0, -1, false); // BUG: fails!
|
||||
//CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, false, 0, 0, false); // BUG: fails!
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, false, 0, 1, true);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, false, 0, 2, true);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, false, 1, -1, true);
|
||||
//CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, false, 1, 0, false); // BUG: fails!
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, false, 1, 1, true);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, false, 1, 2, true);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, false, 2, -1, true);
|
||||
//CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, false, 2, 0, false); // BUG: fails!
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, false, 2, 1, true);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, false, 2, 2, true);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, true, 0, -1, false);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, true, 0, 0, false);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, true, 0, 1, false);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, true, 0, 2, true);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, true, 1, -1, false);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, true, 1, 0, false);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, true, 1, 1, false);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, true, 1, 2, true);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, true, 2, -1, true);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, true, 2, 0, false);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, true, 2, 1, false);
|
||||
CALL_SUBTEST(checkCursorWarpWhenSwitchingMonitor, true, 2, 2, true);
|
||||
}
|
||||
|
||||
@@ -90,6 +90,8 @@ static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO, bool forceFSCycle = fals
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This fucntion should probably just find a workspace and call `Actions::changeWorkspace`.
|
||||
// Can be refactored after #15649 is resolved.
|
||||
static bool tryMoveFocusToMonitor(PHLMONITOR monitor) {
|
||||
if (!monitor)
|
||||
return false;
|
||||
@@ -985,13 +987,16 @@ ActionResult Actions::changeWorkspace(PHLWORKSPACE ws) {
|
||||
}
|
||||
|
||||
const static auto PWARPONWORKSPACECHANGE = CConfigValue<Config::INTEGER>("cursor:warp_on_change_workspace");
|
||||
const static auto PWARPONMONITORCHANGE = CConfigValue<Config::INTEGER>("cursor:warp_on_monitor_change");
|
||||
|
||||
if (*PWARPONWORKSPACECHANGE > 0) {
|
||||
const auto WARP = ws->monitorID() == PMONITOR->id() || *PWARPONMONITORCHANGE == -1 ? *PWARPONWORKSPACECHANGE : *PWARPONMONITORCHANGE;
|
||||
|
||||
if (WARP > 0) {
|
||||
auto PLAST = ws->getLastFocusedWindow();
|
||||
auto HLSurface = Desktop::View::CWLSurface::fromResource(g_pSeatManager->m_state.pointerFocus.lock());
|
||||
|
||||
if (PLAST && (!HLSurface || HLSurface->view()->type() == Desktop::View::VIEW_TYPE_WINDOW))
|
||||
PLAST->warpCursor(*PWARPONWORKSPACECHANGE == 2);
|
||||
PLAST->warpCursor(WARP == 2);
|
||||
}
|
||||
|
||||
return {};
|
||||
|
||||
@@ -613,6 +613,8 @@ std::vector<SP<IValue>> Values::getConfigValues() {
|
||||
MS<Bool>("cursor:persistent_warps", "When a window is refocused, the cursor returns to its last position relative to that window.", false),
|
||||
MS<Int>("cursor:warp_on_change_workspace", "Move the cursor to the last focused window after changing the workspace.", 0,
|
||||
{.min = 0, .max = 2, .map = OptionMap{{"disable", 0}, {"enable", 1}, {"force", 2}}}),
|
||||
MS<Int>("cursor:warp_on_monitor_change", "Move the cursor to the last focused window when focusing a different monitor.", -1,
|
||||
{.min = -1, .max = 2, .map = OptionMap{{"same_as_warp_on_change_workspace", -1}, {"disable", 0}, {"enable", 1}, {"force", 2}}}),
|
||||
MS<Int>("cursor:warp_on_toggle_special", "Move the cursor to the last focused window when toggling a special workspace.", 0,
|
||||
{.min = 0, .max = 2, .map = OptionMap{{"disable", 0}, {"enable", 1}, {"force", 2}}}),
|
||||
MS<String>("cursor:default_monitor", "the name of a default monitor for the cursor to be set to on startup", STRVAL_EMPTY),
|
||||
|
||||
Reference in New Issue
Block a user