mirror of
https://github.com/hyprwm/Hyprland.git
synced 2026-08-18 02:51:23 +00:00
config/lua: clean up HLMonitor:set_workspace() and set_special_workspace() (#15534)
* lua: make HLMonitor:set_workspace "silent" (no focus or mouse move) * lua: report correct function name when HLMonitor:set_special_workspace errors * monitor: allow setting special workspace on monitor without focusing that monitor * lua: make HLMonitor:set_special_workspace also "silent" * workspace: support not carrying focus with us in moveWorkspaceToMonitor This leaves focus on the same monitor, rather than carrying it along with the moved workspace as usual. * lua: fix HLMonitor:set_workspace placing the same WS on different monitors I thought this was already handled for me; apparently not. * lua: support creating new workspaces via HLMonitor:set_workspace(), set_special_workspace() * monitor: don't send workspace events on non-focusing workspace change * lua: better handle (non-)?special selectors in HLMonitor:set_workspace(), set_special_workspace() Both now check that they're given a workspace of the appropriate special-ness. * lua: don't require a table arg for HLMonitor:set_workspace(), set_special_workspace() Also, names given to `set_special_workspace()` no longer require a `special:` prefix, matching the toggle_special dispatcher's behavior. * misc: allow getting workspaces relative to a given monitor Not just the currently focused one. * lua: reference targeted monitor for relative WS selectors in set_workspace() Now, e.g. `m+1` selects the next workspace on the *targeted* monitor, rather than on the focused monitor. * tests: HLMonitor:set_workspace() behavior * tests: HLMonitor:set_special_workspace() behavior * tests: don't force unnecessary refreshes in luaGetWorkspace test * lua: return workspace name as selector for special workspaces Previously this would be the ID, which was negative and would then be interpreted later as a *relative* ID. Normal workspaces can still return their (positive) IDs, that's fine. * monitor: properly leave focus behind when stealing a special workspace
This commit is contained in:
@ -994,8 +994,8 @@ TEST_CASE(luaGetWorkspace) {
|
||||
}
|
||||
Tests::spawnKitty();
|
||||
|
||||
ASSERT(getFromSocket("r/repl hl.get_workspace('name:test')"), "HL.Workspace(-1337:test)");
|
||||
ASSERT(getFromSocket("r/repl hl.get_workspace('name:test') == hl.get_active_workspace()"), "true");
|
||||
ASSERT(getFromSocket("/repl hl.get_workspace('name:test')"), "HL.Workspace(-1337:test)");
|
||||
ASSERT(getFromSocket("/repl hl.get_workspace('name:test') == hl.get_active_workspace()"), "true");
|
||||
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = 1})"));
|
||||
{
|
||||
@ -1003,9 +1003,197 @@ TEST_CASE(luaGetWorkspace) {
|
||||
ASSERT_CONTAINS(str, "workspace ID 1 (1)");
|
||||
}
|
||||
|
||||
ASSERT(getFromSocket("r/repl hl.get_workspace('e-1')"), "HL.Workspace(-1337:test)");
|
||||
ASSERT(getFromSocket("r/repl hl.get_workspace('r+1')"), "nil");
|
||||
ASSERT(getFromSocket("r/repl hl.get_workspace(42)"), "nil");
|
||||
ASSERT(getFromSocket("/repl hl.get_workspace('e-1')"), "HL.Workspace(-1337:test)");
|
||||
ASSERT(getFromSocket("/repl hl.get_workspace('r+1')"), "nil");
|
||||
ASSERT(getFromSocket("/repl hl.get_workspace(42)"), "nil");
|
||||
}
|
||||
|
||||
SUBTEST(luaSetWorkspaceCreate) {
|
||||
// set up monitor 2, the workspace donor for future tests
|
||||
NLog::log("{}Creating four new workspaces on monitor 2", Colors::YELLOW);
|
||||
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = M2 })"));
|
||||
ASSERT_CONTAINS(getFromSocket("/activeworkspace"), "on monitor HEADLESS-3:");
|
||||
|
||||
OK(getFromSocket("/eval M2:set_workspace(100)"));
|
||||
Tests::spawnKitty("ws100");
|
||||
OK(getFromSocket("/eval M2:set_workspace(101)"));
|
||||
Tests::spawnKitty("ws101");
|
||||
|
||||
const auto workspaces = getFromSocket("/workspaces");
|
||||
ASSERT_CONTAINS(workspaces, "workspace ID 100 (100) on monitor HEADLESS-3:");
|
||||
ASSERT_CONTAINS(workspaces, "workspace ID 101 (101) on monitor HEADLESS-3:");
|
||||
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-2' })"));
|
||||
ASSERT_CONTAINS(getFromSocket("/activeworkspace"), "on monitor HEADLESS-2:");
|
||||
}
|
||||
|
||||
SUBTEST(luaSetWorkspaceInactiveToFocused) {
|
||||
NLog::log("{}Setting focused monitor 1 to a workspace currently inactive on monitor 2", Colors::YELLOW);
|
||||
|
||||
// steal workspace 100 from monitor 2
|
||||
OK(getFromSocket("/eval M1:set_workspace(100)"));
|
||||
ASSERT_CONTAINS(getFromSocket("/activewindow"), "class: ws100");
|
||||
ASSERT_CONTAINS(getFromSocket("/activeworkspace"), "workspace ID 100 (100) on monitor HEADLESS-2:");
|
||||
|
||||
// should leave workspace 101 active on monitor 2
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-3' })"));
|
||||
ASSERT_CONTAINS(getFromSocket("/activeworkspace"), "workspace ID 101 (101) on monitor HEADLESS-3:");
|
||||
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-2' })"));
|
||||
}
|
||||
|
||||
SUBTEST(luaSetWorkspaceActiveToFocused) {
|
||||
NLog::log("{}Setting focused monitor 1 to a workspace currently active on monitor 2", Colors::YELLOW);
|
||||
|
||||
// steal workspace 101 from monitor 2
|
||||
OK(getFromSocket("/eval M1:set_workspace(101)"));
|
||||
ASSERT_CONTAINS(getFromSocket("/activewindow"), "class: ws101");
|
||||
ASSERT_CONTAINS(getFromSocket("/activeworkspace"), "workspace ID 101 (101) on monitor HEADLESS-2:");
|
||||
|
||||
// should create workspace 2 on monitor 2
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-3' })"));
|
||||
ASSERT_CONTAINS(getFromSocket("/activeworkspace"), "workspace ID 2 (2) on monitor HEADLESS-3:");
|
||||
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-2' })"));
|
||||
}
|
||||
|
||||
SUBTEST(luaSetWorkspaceInactiveToUnfocused) {
|
||||
NLog::log("{}Setting unfocused monitor 2 to a workspace currently inactive on monitor 1", Colors::YELLOW);
|
||||
|
||||
// steal workspace 100 from monitor 1
|
||||
OK(getFromSocket("/eval M2:set_workspace(100)"));
|
||||
ASSERT_CONTAINS(getFromSocket("/activewindow"), "class: ws101");
|
||||
ASSERT_CONTAINS(getFromSocket("/activeworkspace"), "workspace ID 101 (101) on monitor HEADLESS-2:");
|
||||
|
||||
// should make workspace 100 active on monitor 2
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-3' })"));
|
||||
ASSERT_CONTAINS(getFromSocket("/activeworkspace"), "workspace ID 100 (100) on monitor HEADLESS-3:");
|
||||
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-2' })"));
|
||||
}
|
||||
|
||||
SUBTEST(luaSetWorkspaceActiveToUnfocused) {
|
||||
NLog::log("{}Setting unfocused monitor 2 to a workspace currently active on monitor 1", Colors::YELLOW);
|
||||
|
||||
// steal workspace 101 from monitor 1
|
||||
OK(getFromSocket("/eval M2:set_workspace(101)"));
|
||||
ASSERT_CONTAINS(getFromSocket("/activewindow"), "class: ws1");
|
||||
ASSERT_CONTAINS(getFromSocket("/activeworkspace"), "workspace ID 1 (1) on monitor HEADLESS-2:");
|
||||
|
||||
// should make workspace 101 active on monitor 2
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-3' })"));
|
||||
ASSERT_CONTAINS(getFromSocket("/activeworkspace"), "workspace ID 101 (101) on monitor HEADLESS-3:");
|
||||
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-2' })"));
|
||||
}
|
||||
|
||||
SUBTEST(luaSetWorkspaceUnfocusedRelative) {
|
||||
NLog::log("{}Setting unfocused monitor 2 via a relative workspace selector", Colors::YELLOW);
|
||||
|
||||
// relative workspace selector should be relative to the targeted monitor
|
||||
OK(getFromSocket("/eval M2:set_workspace('m-1')"));
|
||||
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-3' })"));
|
||||
ASSERT_CONTAINS(getFromSocket("/activewindow"), "class: ws100");
|
||||
ASSERT_CONTAINS(getFromSocket("/activeworkspace"), "workspace ID 100 (100) on monitor HEADLESS-3:");
|
||||
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-2' })"));
|
||||
}
|
||||
|
||||
TEST_CASE(luaSetWorkspace) {
|
||||
// add a new monitor
|
||||
NLog::log("{}Adding a new monitor", Colors::YELLOW);
|
||||
ASSERT(getFromSocket("/output create headless HEADLESS-3"), "ok");
|
||||
|
||||
// should take workspace 2
|
||||
{
|
||||
auto str = getFromSocket("/monitors");
|
||||
ASSERT_CONTAINS(str, "active workspace: 2 (2)");
|
||||
ASSERT_CONTAINS(str, "active workspace: 1 (1)");
|
||||
ASSERT_CONTAINS(str, "HEADLESS-3");
|
||||
}
|
||||
|
||||
// plonk a recognizable window on the first monitor
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-2' })"));
|
||||
Tests::spawnKitty("ws1");
|
||||
{
|
||||
auto str = getFromSocket("/activewindow");
|
||||
ASSERT_CONTAINS(str, "monitor: 1");
|
||||
ASSERT_CONTAINS(str, "workspace: 1 (1)");
|
||||
}
|
||||
|
||||
// for use in subtests
|
||||
OK(getFromSocket("/eval M1 = hl.get_monitors()[1]"));
|
||||
OK(getFromSocket("/eval M2 = hl.get_monitors()[2]"));
|
||||
|
||||
// order very much matters for these
|
||||
CALL_SUBTEST(luaSetWorkspaceCreate);
|
||||
CALL_SUBTEST(luaSetWorkspaceInactiveToFocused);
|
||||
CALL_SUBTEST(luaSetWorkspaceActiveToFocused);
|
||||
CALL_SUBTEST(luaSetWorkspaceInactiveToUnfocused);
|
||||
CALL_SUBTEST(luaSetWorkspaceActiveToUnfocused);
|
||||
CALL_SUBTEST(luaSetWorkspaceUnfocusedRelative);
|
||||
|
||||
// clean up
|
||||
Tests::killAllWindows();
|
||||
OK(getFromSocket("/output remove HEADLESS-3"));
|
||||
}
|
||||
|
||||
TEST_CASE(luaSetSpecialWorkspace) {
|
||||
// add a new monitor
|
||||
NLog::log("{}Adding a new monitor", Colors::YELLOW);
|
||||
ASSERT(getFromSocket("/output create headless HEADLESS-3"), "ok");
|
||||
|
||||
// should take workspace 2
|
||||
{
|
||||
auto str = getFromSocket("/monitors");
|
||||
ASSERT_CONTAINS(str, "active workspace: 2 (2)");
|
||||
ASSERT_CONTAINS(str, "active workspace: 1 (1)");
|
||||
ASSERT_CONTAINS(str, "HEADLESS-3");
|
||||
}
|
||||
|
||||
// for ease of access
|
||||
OK(getFromSocket("/eval M1 = hl.get_monitors()[1]"));
|
||||
OK(getFromSocket("/eval M2 = hl.get_monitors()[2]"));
|
||||
|
||||
// special workspace with a window
|
||||
NLog::log("{}Setting special workspace on active monitor", Colors::YELLOW);
|
||||
OK(getFromSocket("/eval M1:set_special_workspace(1)"));
|
||||
Tests::spawnKitty();
|
||||
{
|
||||
auto str = getFromSocket("/activewindow");
|
||||
ASSERT_CONTAINS(str, "monitor: 1");
|
||||
ASSERT_CONTAINS(str, "workspace: -98 (special:1)");
|
||||
}
|
||||
|
||||
// new special workspace on unfocused monitor
|
||||
NLog::log("{}Setting special workspace on inactive monitor", Colors::YELLOW);
|
||||
OK(getFromSocket("/eval M2:set_special_workspace(2)"));
|
||||
ASSERT_CONTAINS(getFromSocket("/workspaces"), "workspace ID -97 (special:2) on monitor HEADLESS-3:");
|
||||
|
||||
// move focused special to unfocused monitor
|
||||
NLog::log("{}Moving active special workspace to inactive monitor", Colors::YELLOW);
|
||||
OK(getFromSocket("/eval M2:set_special_workspace(1)"));
|
||||
ASSERT_CONTAINS(getFromSocket("/activeworkspace"), "workspace ID 1 (1) on monitor HEADLESS-2:");
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-3' })"));
|
||||
{
|
||||
auto str = getFromSocket("/activewindow");
|
||||
ASSERT_CONTAINS(str, "monitor: 2");
|
||||
ASSERT_CONTAINS(str, "workspace: -98 (special:1)");
|
||||
}
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-2' })"));
|
||||
|
||||
// unset special workspace on unfocused monitor
|
||||
NLog::log("{}Clearing special workspace on inactive monitor", Colors::YELLOW);
|
||||
OK(getFromSocket("/eval M2:set_special_workspace(nil)"));
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-3' })"));
|
||||
ASSERT_CONTAINS(getFromSocket("/activeworkspace"), "workspace ID 2 (2) on monitor HEADLESS-3:");
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ monitor = 'HEADLESS-2' })"));
|
||||
|
||||
// clean up
|
||||
Tests::killAllWindows();
|
||||
OK(getFromSocket("/output remove HEADLESS-3"));
|
||||
}
|
||||
|
||||
TEST_CASE(workspacesDistinctTiledAndFloatGaps) {
|
||||
|
||||
@ -198,6 +198,8 @@ std::optional<std::string> Internal::workspaceSelectorFromLuaSelectorOrObject(lu
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (ws->m_isSpecialWorkspace)
|
||||
return ws->m_name;
|
||||
return std::to_string(ws->m_id);
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include "../bindings/LuaBindingsInternal.hpp"
|
||||
#include "../../../output/Monitor.hpp"
|
||||
#include "../../../desktop/state/FocusState.hpp"
|
||||
#include "../../../state/WorkspacePlacementController.hpp"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
@ -36,35 +37,48 @@ static int monitorToString(lua_State* L) {
|
||||
}
|
||||
|
||||
static int monitorSetWorkspace(lua_State* L) {
|
||||
auto* ref = sc<PHLMONITORREF*>(luaL_checkudata(L, 1, MT));
|
||||
const auto id = Internal::requireTableFieldWorkspaceSelector(L, 2, "workspace", "HLMonitor.set_workspace");
|
||||
auto* ref = sc<PHLMONITORREF*>(luaL_checkudata(L, 1, MT));
|
||||
const auto selector = Internal::workspaceSelectorFromLuaSelectorOrObject(L, 2, "HLMonitor.set_workspace");
|
||||
|
||||
if (id.empty())
|
||||
if (!selector)
|
||||
return 0;
|
||||
|
||||
auto ws = State::workspaceState()->query().name(id).run();
|
||||
const auto& [id, name, _] = getWorkspaceIDNameFromString(*selector, ref->lock());
|
||||
if (id == WORKSPACE_INVALID || State::workspaceState()->isSpecial(id))
|
||||
return 0;
|
||||
|
||||
auto ws = State::workspaceState()->query().id(id).run();
|
||||
if (!ws)
|
||||
return 0;
|
||||
ws = State::workspaceState()->create(id, (*ref)->m_id, name);
|
||||
|
||||
(*ref)->changeWorkspace(ws->m_id);
|
||||
State::workspacePlacementController()->moveWorkspaceToMonitor(ws, ref->lock(), true, false);
|
||||
(*ref)->changeWorkspace(ws, false, true, Desktop::focusState()->monitor() != *ref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int monitorSetSpecialWorkspace(lua_State* L) {
|
||||
auto* ref = sc<PHLMONITORREF*>(luaL_checkudata(L, 1, MT));
|
||||
const auto id = Internal::tableOptWorkspaceSelector(L, 2, "workspace", "HLMonitor.set_workspace");
|
||||
auto* ref = sc<PHLMONITORREF*>(luaL_checkudata(L, 1, MT));
|
||||
std::optional<std::string> selector;
|
||||
if (lua_isstring(L, 2) || lua_isnumber(L, 2))
|
||||
selector = std::format("special:{}", Internal::argStr(L, 2));
|
||||
else
|
||||
selector = Internal::workspaceSelectorFromLuaSelectorOrObject(L, 2, "HLMonitor.set_special_workspace");
|
||||
|
||||
if (!id) {
|
||||
(*ref)->setSpecialWorkspace(WORKSPACE_INVALID);
|
||||
if (!selector) {
|
||||
(*ref)->setSpecialWorkspace(WORKSPACE_INVALID, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto ws = State::workspaceState()->query().name(*id).run();
|
||||
if (!ws)
|
||||
const auto& [id, name, _] = getWorkspaceIDNameFromString(*selector, ref->lock());
|
||||
if (id == WORKSPACE_INVALID || !State::workspaceState()->isSpecial(id))
|
||||
return 0;
|
||||
|
||||
(*ref)->setSpecialWorkspace(ws->m_id);
|
||||
auto ws = State::workspaceState()->query().id(id).run();
|
||||
if (!ws)
|
||||
ws = State::workspaceState()->create(id, (*ref)->m_id, name);
|
||||
|
||||
(*ref)->setSpecialWorkspace(ws->m_id, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -122,8 +122,9 @@ static bool isAutoIDdWorkspace(WORKSPACEID id) {
|
||||
return id < WORKSPACE_INVALID;
|
||||
}
|
||||
|
||||
SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
|
||||
SWorkspaceIDName result = {WORKSPACE_INVALID, ""};
|
||||
SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in, std::optional<PHLMONITOR> baseMon) {
|
||||
const auto BASEMONITOR = baseMon.value_or(Desktop::focusState()->monitor());
|
||||
SWorkspaceIDName result = {WORKSPACE_INVALID, ""};
|
||||
|
||||
if (in.starts_with("special")) {
|
||||
result.name = "special:special";
|
||||
@ -149,7 +150,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
|
||||
} else if (in.starts_with("empty")) {
|
||||
const bool same_mon = in.substr(5).contains("m");
|
||||
const bool next = in.substr(5).contains("n");
|
||||
if ((same_mon || next) && !Desktop::focusState()->monitor()) {
|
||||
if ((same_mon || next) && !BASEMONITOR) {
|
||||
Log::logger->log(Log::ERR, "Empty monitor workspace on monitor null!");
|
||||
return {WORKSPACE_INVALID};
|
||||
}
|
||||
@ -160,13 +161,13 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
|
||||
if (!rule->isEnabled())
|
||||
continue;
|
||||
|
||||
const auto PMONITOR = State::monitorState()->query().relativeTo(Desktop::focusState()->monitor()).configString(rule->m_monitor).run();
|
||||
if (PMONITOR && (PMONITOR->m_id != Desktop::focusState()->monitor()->m_id))
|
||||
const auto PMONITOR = State::monitorState()->query().relativeTo(BASEMONITOR).configString(rule->m_monitor).run();
|
||||
if (PMONITOR && (PMONITOR->m_id != BASEMONITOR->m_id))
|
||||
invalidWSes.insert(rule->m_workspaceId);
|
||||
}
|
||||
}
|
||||
|
||||
WORKSPACEID id = next ? Desktop::focusState()->monitor()->activeWorkspaceID() : 0;
|
||||
WORKSPACEID id = next ? BASEMONITOR->activeWorkspaceID() : 0;
|
||||
while (++id < LONG_MAX) {
|
||||
const auto PWORKSPACE = State::workspaceState()->query().id(id).run();
|
||||
if (!invalidWSes.contains(id) && (!PWORKSPACE || PWORKSPACE->getWindowCount() == 0)) {
|
||||
@ -175,11 +176,10 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
|
||||
}
|
||||
}
|
||||
} else if (in.starts_with("prev")) {
|
||||
auto monitor = Desktop::focusState()->monitor();
|
||||
if (!monitor)
|
||||
if (!BASEMONITOR)
|
||||
return {WORKSPACE_INVALID};
|
||||
|
||||
const auto PWORKSPACE = monitor->m_activeWorkspace;
|
||||
const auto PWORKSPACE = BASEMONITOR->m_activeWorkspace;
|
||||
|
||||
if (!valid(PWORKSPACE))
|
||||
return {WORKSPACE_INVALID};
|
||||
@ -198,12 +198,12 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
|
||||
|
||||
return {PLASTWORKSPACE->m_id, PLASTWORKSPACE->m_name};
|
||||
} else if (in == "next") {
|
||||
if (!Desktop::focusState()->monitor() || !Desktop::focusState()->monitor()->m_activeWorkspace) {
|
||||
if (!BASEMONITOR || !BASEMONITOR->m_activeWorkspace) {
|
||||
Log::logger->log(Log::ERR, "no active monitor or workspace for 'next'");
|
||||
return {WORKSPACE_INVALID};
|
||||
}
|
||||
|
||||
auto PCURRENTWORKSPACE = Desktop::focusState()->monitor()->m_activeWorkspace;
|
||||
auto PCURRENTWORKSPACE = BASEMONITOR->m_activeWorkspace;
|
||||
|
||||
WORKSPACEID nextId = PCURRENTWORKSPACE->m_id + 1;
|
||||
|
||||
@ -216,7 +216,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
|
||||
} else {
|
||||
if (in[0] == 'r' && (in[1] == '-' || in[1] == '+' || in[1] == '~') && isNumber(in.substr(2))) {
|
||||
bool absolute = in[1] == '~';
|
||||
if (!Desktop::focusState()->monitor()) {
|
||||
if (!BASEMONITOR) {
|
||||
Log::logger->log(Log::ERR, "Relative monitor workspace on monitor null!");
|
||||
return {WORKSPACE_INVALID};
|
||||
}
|
||||
@ -234,7 +234,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
|
||||
|
||||
// Collect all the workspaces we can't jump to.
|
||||
for (auto const& ws : State::workspaceState()->workspaces()) {
|
||||
if (ws->m_isSpecialWorkspace || (ws->m_monitor != Desktop::focusState()->monitor())) {
|
||||
if (ws->m_isSpecialWorkspace || (ws->m_monitor != BASEMONITOR)) {
|
||||
// Can't jump to this workspace
|
||||
invalidWSes.insert(ws->m_id);
|
||||
}
|
||||
@ -243,8 +243,8 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
|
||||
if (!rule->isEnabled())
|
||||
continue;
|
||||
|
||||
const auto PMONITOR = State::monitorState()->query().relativeTo(Desktop::focusState()->monitor()).configString(rule->m_monitor).run();
|
||||
if (!PMONITOR || PMONITOR->m_id == Desktop::focusState()->monitor()->m_id) {
|
||||
const auto PMONITOR = State::monitorState()->query().relativeTo(BASEMONITOR).configString(rule->m_monitor).run();
|
||||
if (!PMONITOR || PMONITOR->m_id == BASEMONITOR->m_id) {
|
||||
// Can't be invalid
|
||||
continue;
|
||||
}
|
||||
@ -255,7 +255,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
|
||||
// Prepare all named workspaces in case when we need them
|
||||
std::vector<WORKSPACEID> namedWSes;
|
||||
for (auto const& ws : State::workspaceState()->workspaces()) {
|
||||
if (ws->m_isSpecialWorkspace || (ws->m_monitor != Desktop::focusState()->monitor()) || ws->m_id >= 0)
|
||||
if (ws->m_isSpecialWorkspace || (ws->m_monitor != BASEMONITOR) || ws->m_id >= 0)
|
||||
continue;
|
||||
|
||||
namedWSes.push_back(ws->m_id);
|
||||
@ -282,7 +282,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
|
||||
} else {
|
||||
|
||||
// Just take a blind guess at where we'll probably end up
|
||||
WORKSPACEID activeWSID = Desktop::focusState()->monitor()->m_activeWorkspace ? Desktop::focusState()->monitor()->m_activeWorkspace->m_id : 1;
|
||||
WORKSPACEID activeWSID = BASEMONITOR->m_activeWorkspace ? BASEMONITOR->m_activeWorkspace->m_id : 1;
|
||||
WORKSPACEID predictedWSID = activeWSID + remains;
|
||||
int remainingWSes = 0;
|
||||
char walkDir = in[1];
|
||||
@ -381,7 +381,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
|
||||
bool onAllMonitors = in[0] == 'e';
|
||||
bool absolute = in[1] == '~';
|
||||
|
||||
if (!Desktop::focusState()->monitor()) {
|
||||
if (!BASEMONITOR) {
|
||||
Log::logger->log(Log::ERR, "Relative monitor workspace on monitor null!");
|
||||
return {WORKSPACE_INVALID};
|
||||
}
|
||||
@ -399,7 +399,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
|
||||
|
||||
std::vector<WORKSPACEID> validWSes;
|
||||
for (auto const& ws : State::workspaceState()->workspaces()) {
|
||||
if (ws->m_isSpecialWorkspace || (ws->m_monitor != Desktop::focusState()->monitor() && !onAllMonitors))
|
||||
if (ws->m_isSpecialWorkspace || (ws->m_monitor != BASEMONITOR && !onAllMonitors))
|
||||
continue;
|
||||
|
||||
validWSes.push_back(ws->m_id);
|
||||
@ -424,7 +424,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
|
||||
remains = remains < 0 ? -((-remains) % validWSes.size()) : remains % validWSes.size();
|
||||
|
||||
// get the current item
|
||||
WORKSPACEID activeWSID = Desktop::focusState()->monitor()->m_activeWorkspace ? Desktop::focusState()->monitor()->m_activeWorkspace->m_id : 1;
|
||||
WORKSPACEID activeWSID = BASEMONITOR->m_activeWorkspace ? BASEMONITOR->m_activeWorkspace->m_id : 1;
|
||||
for (ssize_t i = 0; i < sc<ssize_t>(validWSes.size()); i++) {
|
||||
if (validWSes[i] == activeWSID) {
|
||||
currentItem = i;
|
||||
@ -447,8 +447,8 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
|
||||
result.name = State::workspaceState()->query().id(validWSes[currentItem]).run()->m_name;
|
||||
} else {
|
||||
if (in[0] == '+' || in[0] == '-') {
|
||||
if (Desktop::focusState()->monitor()) {
|
||||
const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in, Desktop::focusState()->monitor()->activeWorkspaceID());
|
||||
if (BASEMONITOR) {
|
||||
const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in, BASEMONITOR->activeWorkspaceID());
|
||||
if (!PLUSMINUSRESULT.has_value())
|
||||
return {WORKSPACE_INVALID};
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include <hyprutils/os/FileDescriptor.hpp>
|
||||
#include "../SharedDefs.hpp"
|
||||
#include "../macros.hpp"
|
||||
#include "../desktop/DesktopTypes.hpp"
|
||||
|
||||
struct SCallstackFrameInfo {
|
||||
void* adr = nullptr;
|
||||
@ -24,7 +25,7 @@ struct SWorkspaceIDName {
|
||||
std::string absolutePath(const std::string&, const std::string&);
|
||||
std::string escapeJSONStrings(const std::string& str);
|
||||
bool isDirection(std::string_view);
|
||||
SWorkspaceIDName getWorkspaceIDNameFromString(const std::string&);
|
||||
SWorkspaceIDName getWorkspaceIDNameFromString(const std::string&, std::optional<PHLMONITOR> = std::nullopt);
|
||||
std::optional<std::string> cleanCmdForWorkspace(const std::string&, std::string);
|
||||
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
|
||||
std::string execAndGet(const char*);
|
||||
|
||||
@ -1446,7 +1446,7 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo
|
||||
if (pWorkspace->m_isSpecialWorkspace) {
|
||||
if (m_activeSpecialWorkspace != pWorkspace) {
|
||||
Log::logger->log(Log::DEBUG, "changeworkspace on special, togglespecialworkspace to id {}", pWorkspace->m_id);
|
||||
setSpecialWorkspace(pWorkspace);
|
||||
setSpecialWorkspace(pWorkspace, noFocus);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1505,9 +1505,11 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo
|
||||
|
||||
g_layoutManager->recalculateMonitor(m_self.lock(), Layout::CLayoutManager::RECALCULATE_MONITOR_REASON_WORKSPACE_CHANGE);
|
||||
|
||||
IPC::Socket2::sock()->postEvent({"workspace", pWorkspace->m_name});
|
||||
IPC::Socket2::sock()->postEvent({"workspacev2", std::format("{},{}", pWorkspace->m_id, pWorkspace->m_name)});
|
||||
Event::bus()->m_events.workspace.active.emit(pWorkspace);
|
||||
if (!noFocus) {
|
||||
IPC::Socket2::sock()->postEvent({"workspace", pWorkspace->m_name});
|
||||
IPC::Socket2::sock()->postEvent({"workspacev2", std::format("{},{}", pWorkspace->m_id, pWorkspace->m_name)});
|
||||
Event::bus()->m_events.workspace.active.emit(pWorkspace);
|
||||
}
|
||||
}
|
||||
|
||||
// set all LSes as not above fullscreen on workspace changes
|
||||
@ -1552,7 +1554,7 @@ void CMonitor::setSpecialWorkspaceVisualState(bool active) {
|
||||
*m_specialBlur = active && *PBLURSPECIAL && *PBLUR ? 1.F : 0.F;
|
||||
}
|
||||
|
||||
void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
|
||||
void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace, bool noFocus) {
|
||||
if (m_activeSpecialWorkspace == pWorkspace)
|
||||
return;
|
||||
|
||||
@ -1583,7 +1585,8 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
|
||||
|
||||
g_layoutManager->recalculateMonitor(m_self.lock(), Layout::CLayoutManager::RECALCULATE_MONITOR_REASON_TOGGLE_SPECIAL_WORKSPACE);
|
||||
|
||||
if (!(Desktop::focusState()->window() && Desktop::focusState()->window()->m_pinned && Desktop::focusState()->window()->m_monitor == m_self)) {
|
||||
if (!(noFocus && Desktop::focusState()->monitor() != m_self) &&
|
||||
!(Desktop::focusState()->window() && Desktop::focusState()->window()->m_pinned && Desktop::focusState()->window()->m_monitor == m_self)) {
|
||||
if (const auto PLAST = m_activeWorkspace->getLastFocusedWindow(); PLAST)
|
||||
Desktop::focusState()->fullWindowFocus(PLAST, Desktop::FOCUS_REASON_TOGGLE_SPECIAL_WORKSPACE);
|
||||
else
|
||||
@ -1616,6 +1619,15 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
|
||||
PMONITOR->m_activeSpecialWorkspace.reset();
|
||||
g_layoutManager->recalculateMonitor(PMONITOR, Layout::CLayoutManager::RECALCULATE_MONITOR_REASON_TOGGLE_SPECIAL_WORKSPACE);
|
||||
g_pHyprRenderer->damageMonitor(PMONITOR);
|
||||
if (noFocus &&
|
||||
(Desktop::focusState()->monitor() == PMONITOR &&
|
||||
!(Desktop::focusState()->window() && Desktop::focusState()->window()->m_pinned && Desktop::focusState()->window()->m_monitor == PMONITOR))) {
|
||||
// leave focus behind
|
||||
if (const auto PLAST = PMONITOR->m_activeWorkspace->getLastFocusedWindow(); PLAST)
|
||||
Desktop::focusState()->fullWindowFocus(PLAST, Desktop::FOCUS_REASON_TOGGLE_SPECIAL_WORKSPACE);
|
||||
else
|
||||
g_pInputManager->refocus();
|
||||
}
|
||||
IPC::Socket2::sock()->postEvent({"activespecial", std::format(",{}", PMONITOR->m_name)});
|
||||
IPC::Socket2::sock()->postEvent({"activespecialv2", std::format(",,{}", PMONITOR->m_name)});
|
||||
|
||||
@ -1681,7 +1693,10 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
|
||||
|
||||
g_layoutManager->recalculateMonitor(m_self.lock(), Layout::CLayoutManager::RECALCULATE_MONITOR_REASON_TOGGLE_SPECIAL_WORKSPACE);
|
||||
|
||||
if (!(Desktop::focusState()->window() && Desktop::focusState()->window()->m_pinned && Desktop::focusState()->window()->m_monitor == m_self)) {
|
||||
if (!noFocus ||
|
||||
(Desktop::focusState()->monitor() == m_self &&
|
||||
!(Desktop::focusState()->window() && Desktop::focusState()->window()->m_pinned && Desktop::focusState()->window()->m_monitor == m_self))) {
|
||||
// focus the workspace we just moved
|
||||
if (const auto PLAST = pWorkspace->getLastFocusedWindow(); PLAST)
|
||||
Desktop::focusState()->fullWindowFocus(PLAST, Desktop::FOCUS_REASON_TOGGLE_SPECIAL_WORKSPACE);
|
||||
else
|
||||
@ -1703,8 +1718,8 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
|
||||
Event::bus()->m_events.workspace.specialActive.emit(pWorkspace, m_self.lock());
|
||||
}
|
||||
|
||||
void CMonitor::setSpecialWorkspace(const WORKSPACEID& id) {
|
||||
setSpecialWorkspace(State::workspaceState()->query().id(id).run());
|
||||
void CMonitor::setSpecialWorkspace(const WORKSPACEID& id, bool noFocus) {
|
||||
setSpecialWorkspace(State::workspaceState()->query().id(id).run(), noFocus);
|
||||
}
|
||||
|
||||
PHLWORKSPACE CMonitor::getCurrentWorkspace() {
|
||||
|
||||
@ -271,8 +271,8 @@ namespace Monitor {
|
||||
float getDefaultScale();
|
||||
void changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false);
|
||||
void changeWorkspace(const WORKSPACEID& id, bool internal = false, bool noMouseMove = false, bool noFocus = false);
|
||||
void setSpecialWorkspace(const PHLWORKSPACE& pWorkspace);
|
||||
void setSpecialWorkspace(const WORKSPACEID& id);
|
||||
void setSpecialWorkspace(const PHLWORKSPACE& pWorkspace, bool noFocus = false);
|
||||
void setSpecialWorkspace(const WORKSPACEID& id, bool noFocus = false);
|
||||
PHLWORKSPACE getCurrentWorkspace();
|
||||
WORKSPACEID activeWorkspaceID();
|
||||
WORKSPACEID activeSpecialWorkspaceID();
|
||||
|
||||
@ -236,7 +236,7 @@ void CWorkspacePlacementController::swapActiveWorkspaces(PHLMONITOR pMonitorA, P
|
||||
Event::bus()->m_events.workspace.moveToMonitor.emit(PWORKSPACEB, pMonitorA);
|
||||
}
|
||||
|
||||
void CWorkspacePlacementController::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMonitor, bool noWarpCursor) const {
|
||||
void CWorkspacePlacementController::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMonitor, bool noWarpCursor, bool carryFocus) const {
|
||||
static auto PHIDESPECIALONWORKSPACECHANGE = CConfigValue<Config::INTEGER>("binds:hide_special_on_workspace_change");
|
||||
|
||||
if (!pWorkspace || !pMonitor)
|
||||
@ -287,7 +287,7 @@ void CWorkspacePlacementController::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspa
|
||||
|
||||
Log::logger->log(Log::DEBUG, "moveWorkspaceToMonitor: Plugging gap with existing {}", nextWorkspaceOnMonitorID);
|
||||
if (POLDMON)
|
||||
POLDMON->changeWorkspace(nextWorkspaceOnMonitorID, false, true, true);
|
||||
POLDMON->changeWorkspace(nextWorkspaceOnMonitorID, false, true, carryFocus || POLDMON != Desktop::focusState()->monitor());
|
||||
}
|
||||
|
||||
// move the workspace
|
||||
@ -325,7 +325,7 @@ void CWorkspacePlacementController::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspa
|
||||
}
|
||||
}
|
||||
|
||||
if (SWITCHINGISACTIVE && POLDMON == Desktop::focusState()->monitor()) { // if it was active, preserve its' status. If it wasn't, don't.
|
||||
if (carryFocus && SWITCHINGISACTIVE && POLDMON == Desktop::focusState()->monitor()) { // if it was active, preserve its' status. If it wasn't, don't.
|
||||
Log::logger->log(Log::DEBUG, "moveWorkspaceToMonitor: SWITCHINGISACTIVE, active {} -> {}", pMonitor->activeWorkspaceID(), pWorkspace->m_id);
|
||||
|
||||
if (valid(pMonitor->m_activeWorkspace)) {
|
||||
|
||||
@ -16,7 +16,7 @@ namespace State {
|
||||
void ensurePersistentWorkspacesPresent(PHLWORKSPACE pWorkspace, const FMoveWorkspace& moveWorkspace) const;
|
||||
void ensurePersistentWorkspacesPresent(const std::vector<SP<Config::CWorkspaceRule>>& rules, PHLWORKSPACE pWorkspace, const FMoveWorkspace& moveWorkspace) const;
|
||||
void ensureWorkspacesOnAssignedMonitors(const FMoveWorkspace& moveWorkspace) const;
|
||||
void moveWorkspaceToMonitor(PHLWORKSPACE, PHLMONITOR, bool noWarpCursor = false) const;
|
||||
void moveWorkspaceToMonitor(PHLWORKSPACE, PHLMONITOR, bool noWarpCursor = false, bool carryFocus = true) const;
|
||||
void swapActiveWorkspaces(PHLMONITOR, PHLMONITOR) const;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user