diff options
Diffstat (limited to 'src/config/lua/bindings/LuaBindingsDispatchers.cpp')
| -rw-r--r-- | src/config/lua/bindings/LuaBindingsDispatchers.cpp | 1324 |
1 files changed, 1324 insertions, 0 deletions
diff --git a/src/config/lua/bindings/LuaBindingsDispatchers.cpp b/src/config/lua/bindings/LuaBindingsDispatchers.cpp new file mode 100644 index 00000000..61270f9c --- /dev/null +++ b/src/config/lua/bindings/LuaBindingsDispatchers.cpp @@ -0,0 +1,1324 @@ +#include "LuaBindingsInternal.hpp" + +#include <hyprutils/string/String.hpp> + +#include "../../supplementary/executor/Executor.hpp" + +#include "../../../managers/SeatManager.hpp" +#include "../../../devices/IKeyboard.hpp" +#include "../../../desktop/rule/windowRule/WindowRule.hpp" + +using namespace Config; +using namespace Config::Lua; +using namespace Config::Lua::Bindings; +using namespace Hyprutils::String; + +namespace CA = Config::Actions; + +static int dsp_moveCursorToCorner(lua_State* L) { + Internal::checkResult(L, CA::moveCursorToCorner((int)lua_tonumber(L, lua_upvalueindex(1)), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_moveCursor(lua_State* L) { + Internal::checkResult(L, CA::moveCursor(Vector2D{lua_tonumber(L, lua_upvalueindex(1)), lua_tonumber(L, lua_upvalueindex(2))})); + return 0; +} + +static int dsp_toggleGroup(lua_State* L) { + Internal::checkResult(L, CA::toggleGroup(Internal::windowFromUpval(L, 1))); + return 0; +} + +static int dsp_changeGroupActive(lua_State* L) { + Internal::checkResult(L, CA::changeGroupActive(lua_toboolean(L, lua_upvalueindex(1)), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_setGroupActive(lua_State* L) { + Internal::checkResult(L, CA::setGroupActive((int)lua_tonumber(L, lua_upvalueindex(1)), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_moveGroupWindow(lua_State* L) { + Internal::checkResult(L, CA::moveGroupWindow(lua_toboolean(L, lua_upvalueindex(1)))); + return 0; +} + +static int dsp_lockGroups(lua_State* L) { + Internal::checkResult(L, CA::lockGroups(sc<CA::eTogglableAction>((int)lua_tonumber(L, lua_upvalueindex(1))))); + return 0; +} + +static int dsp_lockActiveGroup(lua_State* L) { + Internal::checkResult(L, CA::lockActiveGroup(sc<CA::eTogglableAction>((int)lua_tonumber(L, lua_upvalueindex(1))))); + return 0; +} + +static int hlCursorMoveToCorner(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.cursor.move_to_corner: expected a table { corner, window? }"); + + lua_pushnumber(L, Internal::requireTableFieldNum(L, 1, "corner", "hl.cursor.move_to_corner")); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_moveCursorToCorner, 2); + return 1; +} + +static int hlCursorMove(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.cursor.move: expected a table { x, y }"); + + lua_pushnumber(L, Internal::requireTableFieldNum(L, 1, "x", "hl.cursor.move")); + lua_pushnumber(L, Internal::requireTableFieldNum(L, 1, "y", "hl.cursor.move")); + lua_pushcclosure(L, dsp_moveCursor, 2); + return 1; +} + +static int hlGroupToggle(lua_State* L) { + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_toggleGroup, 1); + return 1; +} + +static int hlGroupNext(lua_State* L) { + lua_pushboolean(L, true); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_changeGroupActive, 2); + return 1; +} + +static int hlGroupPrev(lua_State* L) { + lua_pushboolean(L, false); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_changeGroupActive, 2); + return 1; +} + +static int hlGroupMoveWindow(lua_State* L) { + bool forward = true; + if (lua_istable(L, 1)) { + auto f = Internal::tableOptBool(L, 1, "forward"); + if (f) + forward = *f; + } + lua_pushboolean(L, forward); + lua_pushcclosure(L, dsp_moveGroupWindow, 1); + return 1; +} + +static int hlGroupActive(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.group.active: expected a table { index, window? }"); + + lua_pushnumber(L, Internal::requireTableFieldNum(L, 1, "index", "hl.group.active")); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_setGroupActive, 2); + return 1; +} + +static int hlGroupLock(lua_State* L) { + const auto action = Internal::tableToggleAction(L, 1); + + lua_pushnumber(L, (int)action); + lua_pushcclosure(L, dsp_lockGroups, 1); + return 1; +} + +static int hlGroupLockActive(lua_State* L) { + const auto action = Internal::tableToggleAction(L, 1); + + lua_pushnumber(L, (int)action); + lua_pushcclosure(L, dsp_lockActiveGroup, 1); + return 1; +} + +static int dsp_execCmd(lua_State* L) { + auto proc = lua_tostring(L, lua_upvalueindex(1)); + + if (std::string_view{proc}.empty()) + return Internal::configError(L, "Invalid process string"); + + std::optional<uint64_t> pid; + auto ruleRet = Internal::buildRuleFromTable(L, lua_upvalueindex(2)); + + if (!ruleRet) + return ruleRet.error(); + + if (*ruleRet) + pid = Config::Supplementary::executor()->spawn(Config::Supplementary::SExecRequest{.exec = proc, .rule = std::move(*ruleRet)}); + else + pid = Config::Supplementary::executor()->spawn(proc); + + if (!pid.has_value()) + return Internal::configError(L, "Failed to start process"); + return 0; +} + +static int dsp_execRaw(lua_State* L) { + auto proc = Config::Supplementary::executor()->spawnRaw(lua_tostring(L, lua_upvalueindex(1))); + if (!proc || !*proc) + return Internal::configError(L, "Failed to start process"); + return 0; +} + +static int dsp_exit(lua_State* L) { + Internal::checkResult(L, CA::exit()); + return 0; +} + +static int dsp_submap(lua_State* L) { + Internal::checkResult(L, CA::setSubmap(lua_tostring(L, lua_upvalueindex(1)))); + return 0; +} + +static int dsp_pass(lua_State* L) { + const auto PWINDOW = g_pCompositor->getWindowByRegex(lua_tostring(L, lua_upvalueindex(1))); + if (!PWINDOW) + return Internal::configError(L, "hl.pass: window not found"); + Internal::checkResult(L, CA::pass(PWINDOW)); + return 0; +} + +static int dsp_layoutMsg(lua_State* L) { + Internal::checkResult(L, CA::layoutMessage(lua_tostring(L, lua_upvalueindex(1)))); + return 0; +} + +static int dsp_dpms(lua_State* L) { + auto action = sc<CA::eTogglableAction>((int)lua_tonumber(L, lua_upvalueindex(1))); + std::optional<PHLMONITOR> mon = std::nullopt; + + if (!lua_isnil(L, lua_upvalueindex(2))) { + auto m = g_pCompositor->getMonitorFromString(lua_tostring(L, lua_upvalueindex(2))); + if (m) + mon = m; + } + + Internal::checkResult(L, CA::dpms(action, mon)); + return 0; +} + +static int dsp_event(lua_State* L) { + Internal::checkResult(L, CA::event(lua_tostring(L, lua_upvalueindex(1)))); + return 0; +} + +static int dsp_global(lua_State* L) { + Internal::checkResult(L, CA::global(lua_tostring(L, lua_upvalueindex(1)))); + return 0; +} + +static int dsp_forceRendererReload(lua_State* L) { + Internal::checkResult(L, CA::forceRendererReload()); + return 0; +} + +static int dsp_forceIdle(lua_State* L) { + Internal::checkResult(L, CA::forceIdle((float)lua_tonumber(L, lua_upvalueindex(1)))); + return 0; +} + +static int hlExecCmd(lua_State* L) { + const auto proc = luaL_checkstring(L, 1); + const bool hasRuleArg = !lua_isnoneornil(L, 2); + + lua_pushstring(L, proc); + + if (hasRuleArg) + lua_pushvalue(L, 2); + else + lua_pushnil(L); + + lua_pushcclosure(L, dsp_execCmd, 2); + return 1; +} + +static int hlExecRaw(lua_State* L) { + lua_pushstring(L, luaL_checkstring(L, 1)); + lua_pushcclosure(L, dsp_execRaw, 1); + return 1; +} + +static int hlExit(lua_State* L) { + lua_pushcclosure(L, dsp_exit, 0); + return 1; +} + +static int hlSubmap(lua_State* L) { + lua_pushstring(L, luaL_checkstring(L, 1)); + lua_pushcclosure(L, dsp_submap, 1); + return 1; +} + +static int hlPass(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.pass: expected a table { window }"); + + const auto w = Internal::requireTableFieldWindowSelector(L, 1, "window", "hl.pass"); + lua_pushstring(L, w.c_str()); + lua_pushcclosure(L, dsp_pass, 1); + return 1; +} + +static int hlLayout(lua_State* L) { + lua_pushstring(L, luaL_checkstring(L, 1)); + lua_pushcclosure(L, dsp_layoutMsg, 1); + return 1; +} + +static int hlDpms(lua_State* L) { + CA::eTogglableAction action = Internal::tableToggleAction(L, 1); + std::optional<std::string> monStr; + + if (lua_istable(L, 1)) + monStr = Internal::tableOptMonitorSelector(L, 1, "monitor", "hl.dpms"); + + lua_pushnumber(L, (int)action); + if (monStr) + lua_pushstring(L, monStr->c_str()); + else + lua_pushnil(L); + lua_pushcclosure(L, dsp_dpms, 2); + return 1; +} + +static int hlEvent(lua_State* L) { + lua_pushstring(L, luaL_checkstring(L, 1)); + lua_pushcclosure(L, dsp_event, 1); + return 1; +} + +static int hlGlobal(lua_State* L) { + lua_pushstring(L, luaL_checkstring(L, 1)); + lua_pushcclosure(L, dsp_global, 1); + return 1; +} + +static int hlForceRendererReload(lua_State* L) { + lua_pushcclosure(L, dsp_forceRendererReload, 0); + return 1; +} + +static int hlForceIdle(lua_State* L) { + lua_pushnumber(L, luaL_checknumber(L, 1)); + lua_pushcclosure(L, dsp_forceIdle, 1); + return 1; +} + +static std::expected<uint32_t, std::string> resolveKeycode(const std::string& key) { + if (isNumber(key) && std::stoi(key) > 9) + return (uint32_t)std::stoi(key); + + if (key.starts_with("code:") && isNumber(key.substr(5))) + return (uint32_t)std::stoi(key.substr(5)); + + if (key.starts_with("mouse:") && isNumber(key.substr(6))) { + uint32_t code = std::stoi(key.substr(6)); + if (code < 272) + return std::unexpected("invalid mouse button"); + return code; + } + + const auto KEYSYM = xkb_keysym_from_name(key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); + + const auto KB = g_pSeatManager->m_keyboard; + if (!KB) + return std::unexpected("no keyboard"); + + const auto KEYPAIRSTRING = std::format("{}{}", rc<uintptr_t>(KB.get()), key); + + if (g_pKeybindManager->m_keyToCodeCache.contains(KEYPAIRSTRING)) + return g_pKeybindManager->m_keyToCodeCache[KEYPAIRSTRING]; + + xkb_keymap* km = KB->m_xkbKeymap; + xkb_state* ks = KB->m_xkbState; + xkb_keycode_t keycode_min = xkb_keymap_min_keycode(km); + xkb_keycode_t keycode_max = xkb_keymap_max_keycode(km); + uint32_t keycode = 0; + + for (xkb_keycode_t kc = keycode_min; kc <= keycode_max; ++kc) { + xkb_keysym_t sym = xkb_state_key_get_one_sym(ks, kc); + if (sym == KEYSYM) { + keycode = kc; + g_pKeybindManager->m_keyToCodeCache[KEYPAIRSTRING] = keycode; + } + } + + if (!keycode) + return std::unexpected("key not found"); + + return keycode; +} + +static int dsp_sendShortcut(lua_State* L) { + const uint32_t modMask = g_pKeybindManager->stringToModMask(lua_tostring(L, lua_upvalueindex(1))); + const std::string key = lua_tostring(L, lua_upvalueindex(2)); + + auto keycodeResult = resolveKeycode(key); + if (!keycodeResult) + return Internal::configError(L, "send_shortcut: {}", keycodeResult.error()); + + PHLWINDOW window = nullptr; + if (!lua_isnil(L, lua_upvalueindex(3))) { + window = g_pCompositor->getWindowByRegex(lua_tostring(L, lua_upvalueindex(3))); + if (!window) + return Internal::configError(L, "send_shortcut: window not found"); + } + + Internal::checkResult(L, CA::pass(modMask, *keycodeResult, window)); + return 0; +} + +static int dsp_sendKeyState(lua_State* L) { + const uint32_t modMask = g_pKeybindManager->stringToModMask(lua_tostring(L, lua_upvalueindex(1))); + const std::string key = lua_tostring(L, lua_upvalueindex(2)); + const uint32_t keyState = (uint32_t)lua_tonumber(L, lua_upvalueindex(3)); + + auto keycodeResult = resolveKeycode(key); + if (!keycodeResult) + return Internal::configError(L, "send_key_state: {}", keycodeResult.error()); + + PHLWINDOW window = nullptr; + if (!lua_isnil(L, lua_upvalueindex(4))) { + window = g_pCompositor->getWindowByRegex(lua_tostring(L, lua_upvalueindex(4))); + if (!window) + return Internal::configError(L, "send_key_state: window not found"); + } + + Internal::checkResult(L, CA::sendKeyState(modMask, *keycodeResult, keyState, window)); + return 0; +} + +static int hlSendShortcut(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "send_shortcut: expected a table { mods, key, window? }"); + + const auto mods = Internal::requireTableFieldStr(L, 1, "mods", "hl.send_shortcut"); + const auto key = Internal::requireTableFieldStr(L, 1, "key", "hl.send_shortcut"); + + lua_pushstring(L, mods.c_str()); + lua_pushstring(L, key.c_str()); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_sendShortcut, 3); + return 1; +} + +static int hlSendKeyState(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "send_key_state: expected a table { mods, key, state, window? }"); + + const auto mods = Internal::requireTableFieldStr(L, 1, "mods", "hl.send_key_state"); + const auto key = Internal::requireTableFieldStr(L, 1, "key", "hl.send_key_state"); + const auto stateStr = Internal::requireTableFieldStr(L, 1, "state", "hl.send_key_state"); + + uint32_t keyState = 0; + if (stateStr == "down") + keyState = 1; + else if (stateStr == "repeat") + keyState = 2; + else if (stateStr != "up") + return Internal::configError(L, "send_key_state: 'state' must be \"down\", \"up\", or \"repeat\""); + + lua_pushstring(L, mods.c_str()); + lua_pushstring(L, key.c_str()); + lua_pushnumber(L, keyState); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_sendKeyState, 4); + return 1; +} + +static int dsp_moveToWorkspace(lua_State* L) { + auto ws = Internal::resolveWorkspaceStr(lua_tostring(L, lua_upvalueindex(1))); + if (!ws) + return Internal::configError(L, "Invalid workspace"); + + bool silent = lua_toboolean(L, lua_upvalueindex(2)); + Internal::checkResult(L, CA::moveToWorkspace(ws, silent, Internal::windowFromUpval(L, 3))); + return 0; +} + +static int dsp_moveToMonitor(lua_State* L) { + auto mon = Internal::resolveMonitorStr(lua_tostring(L, lua_upvalueindex(1))); + if (!mon) + return Internal::configError(L, "Invalid monitor / monitor doesn't exist"); + + bool silent = lua_toboolean(L, lua_upvalueindex(2)); + Internal::checkResult(L, CA::moveToWorkspace(mon->m_activeWorkspace, silent, Internal::windowFromUpval(L, 3))); + return 0; +} + +static int dsp_closeWindow(lua_State* L) { + Internal::checkResult(L, CA::closeWindow(Internal::windowFromUpval(L, 1))); + return 0; +} + +static int dsp_killWindow(lua_State* L) { + Internal::checkResult(L, CA::killWindow(Internal::windowFromUpval(L, 1))); + return 0; +} + +static int dsp_signalWindow(lua_State* L) { + Internal::checkResult(L, CA::signalWindow((int)lua_tonumber(L, lua_upvalueindex(1)), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_floatWindow(lua_State* L) { + Internal::checkResult(L, CA::floatWindow(sc<CA::eTogglableAction>((int)lua_tonumber(L, lua_upvalueindex(1))), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_fullscreenWindow(lua_State* L) { + Internal::checkResult(L, CA::fullscreenWindow(sc<eFullscreenMode>((int)lua_tonumber(L, lua_upvalueindex(1))), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_fullscreenWindowWithAction(lua_State* L) { + const auto mode = sc<eFullscreenMode>((int)lua_tonumber(L, lua_upvalueindex(1))); + const int actionRaw = (int)lua_tonumber(L, lua_upvalueindex(2)); + auto maybeW = Internal::windowFromUpval(L, 3); + + if (actionRaw == 0) { + Internal::checkResult(L, CA::fullscreenWindow(mode, maybeW)); + return 0; + } + + const auto target = maybeW.value_or(Desktop::focusState()->window()); + if (!target) + return Internal::configError(L, "No target found."); + + const bool currentlyMode = target->isEffectiveInternalFSMode(mode); + + if (actionRaw == 1) { + if (!currentlyMode) + Internal::checkResult(L, CA::fullscreenWindow(mode, maybeW)); + return 0; + } + + if (actionRaw == 2) { + if (currentlyMode) + Internal::checkResult(L, CA::fullscreenWindow(mode, maybeW)); + return 0; + } + + return Internal::configError(L, "hl.window.fullscreen: invalid action"); +} + +static int dsp_fullscreenState(lua_State* L) { + const auto desiredInternal = sc<eFullscreenMode>((int)lua_tonumber(L, lua_upvalueindex(1))); + const auto desiredClient = sc<eFullscreenMode>((int)lua_tonumber(L, lua_upvalueindex(2))); + const int actionRaw = (int)lua_tonumber(L, lua_upvalueindex(3)); // 0: toggle, 1: set, 2: unset + auto maybeW = Internal::windowFromUpval(L, 4); + + const auto target = maybeW.value_or(Desktop::focusState()->window()); + if (!target) + return Internal::configError(L, "No target found."); + + const auto CURRENT = target->m_fullscreenState; + const bool atDesiredState = CURRENT.internal == desiredInternal && CURRENT.client == desiredClient; + + if (actionRaw == 0) { + Internal::checkResult(L, CA::fullscreenWindow(desiredInternal, desiredClient, maybeW)); + return 0; + } + + if (actionRaw == 1) { + if (!atDesiredState) + Internal::checkResult(L, CA::fullscreenWindow(desiredInternal, desiredClient, maybeW)); + return 0; + } + + if (actionRaw == 2) { + if (atDesiredState) + Internal::checkResult(L, CA::fullscreenWindow(desiredInternal, desiredClient, maybeW)); + return 0; + } + + return Internal::configError(L, "hl.window.fullscreen_state: invalid action"); +} + +static int dsp_pseudoWindow(lua_State* L) { + Internal::checkResult(L, CA::pseudoWindow(sc<CA::eTogglableAction>((int)lua_tonumber(L, lua_upvalueindex(1))), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_moveInDirection(lua_State* L) { + Internal::checkResult(L, CA::moveInDirection(sc<Math::eDirection>((int)lua_tonumber(L, lua_upvalueindex(1))), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_swapInDirection(lua_State* L) { + Internal::checkResult(L, CA::swapInDirection(sc<Math::eDirection>((int)lua_tonumber(L, lua_upvalueindex(1))), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_center(lua_State* L) { + Internal::checkResult(L, CA::center(Internal::windowFromUpval(L, 1))); + return 0; +} + +static int dsp_cycleNext(lua_State* L) { + bool next = lua_toboolean(L, lua_upvalueindex(1)); + int tiledRaw = (int)lua_tonumber(L, lua_upvalueindex(2)); + int floatingRaw = (int)lua_tonumber(L, lua_upvalueindex(3)); + std::optional<bool> tiled = tiledRaw < 0 ? std::nullopt : std::optional(tiledRaw > 0); + std::optional<bool> floating = floatingRaw < 0 ? std::nullopt : std::optional(floatingRaw > 0); + Internal::checkResult(L, CA::cycleNext(next, tiled, floating, Internal::windowFromUpval(L, 4))); + return 0; +} + +static int dsp_swapNext(lua_State* L) { + Internal::checkResult(L, CA::swapNext(lua_toboolean(L, lua_upvalueindex(1)), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_swapWithWindow(lua_State* L) { + auto source = Internal::windowFromUpval(L, 1); + + const auto targetSelector = lua_tostring(L, lua_upvalueindex(2)); + const auto target = g_pCompositor->getWindowByRegex(targetSelector); + if (!target) + return Internal::configError(L, "hl.window.swap: target window not found"); + + Internal::checkResult(L, CA::swapWith(target, source)); + return 0; +} + +static int dsp_tagWindow(lua_State* L) { + Internal::checkResult(L, CA::tag(lua_tostring(L, lua_upvalueindex(1)), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_toggleSwallow(lua_State* L) { + Internal::checkResult(L, CA::toggleSwallow()); + return 0; +} + +static int dsp_resize(lua_State* L) { + Vector2D value{lua_tonumber(L, lua_upvalueindex(1)), lua_tonumber(L, lua_upvalueindex(2))}; + Internal::checkResult(L, CA::resize(value, lua_toboolean(L, lua_upvalueindex(3)), Internal::windowFromUpval(L, 4))); + return 0; +} + +static int dsp_move(lua_State* L) { + Vector2D value{lua_tonumber(L, lua_upvalueindex(1)), lua_tonumber(L, lua_upvalueindex(2))}; + Internal::checkResult(L, CA::move(value, lua_toboolean(L, lua_upvalueindex(3)), Internal::windowFromUpval(L, 4))); + return 0; +} + +static int dsp_pinWindow(lua_State* L) { + Internal::checkResult(L, CA::pinWindow(sc<CA::eTogglableAction>((int)lua_tonumber(L, lua_upvalueindex(1))), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_bringToTop(lua_State* L) { + Internal::checkResult(L, CA::alterZOrder("top")); + return 0; +} + +static int dsp_alterZOrder(lua_State* L) { + Internal::checkResult(L, CA::alterZOrder(lua_tostring(L, lua_upvalueindex(1)), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_setProp(lua_State* L) { + Internal::checkResult(L, CA::setProp(lua_tostring(L, lua_upvalueindex(1)), lua_tostring(L, lua_upvalueindex(2)), Internal::windowFromUpval(L, 3))); + return 0; +} + +static int dsp_moveIntoGroup(lua_State* L) { + Internal::checkResult(L, CA::moveIntoGroup(sc<Math::eDirection>((int)lua_tonumber(L, lua_upvalueindex(1))), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_moveOutOfGroup(lua_State* L) { + Internal::checkResult(L, CA::moveOutOfGroup(sc<Math::eDirection>((int)lua_tonumber(L, lua_upvalueindex(1))), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_moveWindowOrGroup(lua_State* L) { + Internal::checkResult(L, CA::moveWindowOrGroup(sc<Math::eDirection>((int)lua_tonumber(L, lua_upvalueindex(1))), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_moveIntoOrCreateGroup(lua_State* L) { + Internal::checkResult(L, CA::moveIntoOrCreateGroup(sc<Math::eDirection>((int)lua_tonumber(L, lua_upvalueindex(1))), Internal::windowFromUpval(L, 2))); + return 0; +} + +static int dsp_denyFromGroup(lua_State* L) { + Internal::checkResult(L, CA::denyWindowFromGroup(sc<CA::eTogglableAction>((int)lua_tonumber(L, lua_upvalueindex(1))))); + return 0; +} + +static int dsp_mouseDrag(lua_State* L) { + Internal::checkResult(L, CA::mouse("movewindow")); + return 0; +} + +static int dsp_mouseResize(lua_State* L) { + Internal::checkResult(L, CA::mouse("resizewindow")); + return 0; +} + +static int hlWindowClose(lua_State* L) { + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_closeWindow, 1); + return 1; +} + +static int hlWindowKill(lua_State* L) { + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_killWindow, 1); + return 1; +} + +static int hlWindowSignal(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.window.signal: expected a table { signal, window? }"); + + lua_pushnumber(L, Internal::requireTableFieldNum(L, 1, "signal", "hl.window.signal")); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_signalWindow, 2); + return 1; +} + +static int hlWindowFloat(lua_State* L) { + const auto action = Internal::tableToggleAction(L, 1); + + lua_pushnumber(L, (int)action); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_floatWindow, 2); + return 1; +} + +static int hlWindowFullscreen(lua_State* L) { + eFullscreenMode mode = FSMODE_FULLSCREEN; + int action = 0; // 0: toggle, 1: set, 2: unset + if (lua_istable(L, 1)) { + auto m = Internal::tableOptStr(L, 1, "mode"); + if (m) { + if (*m == "maximized" || *m == "1") + mode = FSMODE_MAXIMIZED; + else if (*m == "fullscreen" || *m == "0") + mode = FSMODE_FULLSCREEN; + else + return Internal::configError(L, "hl.window.fullscreen: invalid mode \"{}\" (expected fullscreen/maximized)", *m); + } + + auto a = Internal::tableOptStr(L, 1, "action"); + if (a) { + if (*a == "toggle") + action = 0; + else if (*a == "set") + action = 1; + else if (*a == "unset") + action = 2; + else + return Internal::configError(L, "hl.window.fullscreen: invalid action \"{}\" (expected toggle/set/unset)", *a); + } + } + lua_pushnumber(L, (int)mode); + if (action == 0) { + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_fullscreenWindow, 2); + } else { + lua_pushnumber(L, action); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_fullscreenWindowWithAction, 3); + } + return 1; +} + +static int hlWindowFullscreenState(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.window.fullscreen_state: expected a table { internal, client, action?, window? }"); + + int action = 1; // default to set semantics + if (auto a = Internal::tableOptStr(L, 1, "action"); a) { + if (*a == "toggle") + action = 0; + else if (*a == "set") + action = 1; + else if (*a == "unset") + action = 2; + else + return Internal::configError(L, "hl.window.fullscreen_state: invalid action \"{}\" (expected toggle/set/unset)", *a); + } + + auto im = Internal::tableOptNum(L, 1, "internal"); + auto cm = Internal::tableOptNum(L, 1, "client"); + if (!im || !cm) + return Internal::configError(L, "hl.window.fullscreen_state: 'internal' and 'client' are required"); + + lua_pushnumber(L, (int)*im); + lua_pushnumber(L, (int)*cm); + lua_pushnumber(L, action); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_fullscreenState, 4); + return 1; +} + +static int hlWindowPseudo(lua_State* L) { + const auto action = Internal::tableToggleAction(L, 1); + + lua_pushnumber(L, (int)action); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_pseudoWindow, 2); + return 1; +} + +static int hlWindowMove(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.window.move: expected a table, e.g. { direction = \"left\" }"); + + auto dirStr = Internal::tableOptStr(L, 1, "direction"); + if (dirStr) { + auto dir = Internal::parseDirectionStr(*dirStr); + if (dir == Math::DIRECTION_DEFAULT) + return Internal::configError(L, "hl.window.move: invalid direction \"{}\" (expected left/right/up/down)", *dirStr); + + auto groupAware = Internal::tableOptBool(L, 1, "group_aware"); + if (groupAware && *groupAware) { + lua_pushnumber(L, (int)dir); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_moveWindowOrGroup, 2); + return 1; + } + + lua_pushnumber(L, (int)dir); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_moveInDirection, 2); + return 1; + } + + auto x = Internal::tableOptNum(L, 1, "x"); + auto y = Internal::tableOptNum(L, 1, "y"); + if (x && y) { + bool relative = Internal::tableOptBool(L, 1, "relative").value_or(false); + lua_pushnumber(L, *x); + lua_pushnumber(L, *y); + lua_pushboolean(L, relative); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_move, 4); + return 1; + } + + auto ws = Internal::tableOptWorkspaceSelector(L, 1, "workspace", "hl.window.move"); + if (ws) { + auto follow = Internal::tableOptBool(L, 1, "follow"); + bool silent = follow.has_value() && !*follow; + lua_pushstring(L, ws->c_str()); + lua_pushboolean(L, silent); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_moveToWorkspace, 3); + return 1; + } + + auto mon = Internal::tableOptMonitorSelector(L, 1, "monitor", "hl.window.move"); + if (mon) { + auto follow = Internal::tableOptBool(L, 1, "follow"); + bool silent = follow.has_value() && !*follow; + lua_pushstring(L, mon->c_str()); + lua_pushboolean(L, silent); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_moveToMonitor, 3); + return 1; + } + + auto intoGroup = Internal::tableOptStr(L, 1, "into_group"); + if (intoGroup) { + auto dir = Internal::parseDirectionStr(*intoGroup); + if (dir == Math::DIRECTION_DEFAULT) + return Internal::configError(L, "hl.window.move: invalid into_group direction \"{}\"", *intoGroup); + lua_pushnumber(L, (int)dir); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_moveIntoGroup, 2); + return 1; + } + + auto intoOrCreateGroup = Internal::tableOptStr(L, 1, "into_or_create_group"); + if (intoOrCreateGroup) { + auto dir = Internal::parseDirectionStr(*intoOrCreateGroup); + if (dir == Math::DIRECTION_DEFAULT) + return Internal::configError(L, "hl.window.move: invalid into_or_create_group direction \"{}\"", *intoOrCreateGroup); + lua_pushnumber(L, (int)dir); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_moveIntoOrCreateGroup, 2); + return 1; + } + + auto outOfGroup = Internal::tableOptStr(L, 1, "out_of_group"); + if (outOfGroup) { + auto dir = Internal::parseDirectionStr(*outOfGroup); + lua_pushnumber(L, (int)dir); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_moveOutOfGroup, 2); + return 1; + } + + auto outOfGroupBool = Internal::tableOptBool(L, 1, "out_of_group"); + if (outOfGroupBool && *outOfGroupBool) { + lua_pushnumber(L, (int)Math::DIRECTION_DEFAULT); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_moveOutOfGroup, 2); + return 1; + } + + return Internal::configError(L, "hl.window.move: unrecognized arguments. Expected one of: direction, x+y(+relative), workspace, into_group, out_of_group"); +} + +static int hlWindowSwap(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.window.swap: expected a table, e.g. { direction = \"left\" }"); + + auto dirStr = Internal::tableOptStr(L, 1, "direction"); + if (dirStr) { + auto dir = Internal::parseDirectionStr(*dirStr); + if (dir == Math::DIRECTION_DEFAULT) + return Internal::configError(L, "hl.window.swap: invalid direction \"{}\" (expected left/right/up/down)", *dirStr); + lua_pushnumber(L, (int)dir); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_swapInDirection, 2); + return 1; + } + + auto target = Internal::tableOptWindowSelector(L, 1, "target", "hl.window.swap"); + if (!target) + target = Internal::tableOptWindowSelector(L, 1, "with", "hl.window.swap"); + if (!target) + target = Internal::tableOptWindowSelector(L, 1, "other", "hl.window.swap"); + + if (target) { + Internal::pushWindowUpval(L, 1); + lua_pushstring(L, target->c_str()); + lua_pushcclosure(L, dsp_swapWithWindow, 2); + return 1; + } + + auto next = Internal::tableOptBool(L, 1, "next"); + if (next && *next) { + lua_pushboolean(L, true); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_swapNext, 2); + return 1; + } + + auto prev = Internal::tableOptBool(L, 1, "prev"); + if (prev && *prev) { + lua_pushboolean(L, false); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_swapNext, 2); + return 1; + } + + return Internal::configError(L, "hl.window.swap: unrecognized arguments. Expected one of: direction, target/with/other, next, prev"); +} + +static int hlWindowCenter(lua_State* L) { + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_center, 1); + return 1; +} + +static int hlWindowCycleNext(lua_State* L) { + bool next = true; + int tiled = -1; + int floating = -1; + if (lua_istable(L, 1)) { + auto n = Internal::tableOptBool(L, 1, "next"); + if (n) + next = *n; + auto t = Internal::tableOptBool(L, 1, "tiled"); + if (t) + tiled = *t ? 1 : 0; + auto f = Internal::tableOptBool(L, 1, "floating"); + if (f) + floating = *f ? 1 : 0; + } + lua_pushboolean(L, next); + lua_pushnumber(L, tiled); + lua_pushnumber(L, floating); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_cycleNext, 4); + return 1; +} + +static int hlWindowTag(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.window.tag: expected a table { tag, window? }"); + + const auto tag = Internal::requireTableFieldStr(L, 1, "tag", "hl.window.tag"); + lua_pushstring(L, tag.c_str()); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_tagWindow, 2); + return 1; +} + +static int hlWindowToggleSwallow(lua_State* L) { + lua_pushcclosure(L, dsp_toggleSwallow, 0); + return 1; +} + +static int hlWindowResizeExact(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.window.resize: expected a table { x, y, relative?, window? }"); + auto x = Internal::tableOptNum(L, 1, "x"); + auto y = Internal::tableOptNum(L, 1, "y"); + bool relative = Internal::tableOptBool(L, 1, "relative").value_or(false); + if (!x || !y) + return Internal::configError(L, "hl.window.resize: 'x' and 'y' are required"); + lua_pushnumber(L, *x); + lua_pushnumber(L, *y); + lua_pushboolean(L, relative); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_resize, 4); + return 1; +} + +static int hlWindowPin(lua_State* L) { + const auto action = Internal::tableToggleAction(L, 1); + + lua_pushnumber(L, (int)action); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_pinWindow, 2); + return 1; +} + +static int hlWindowBringToTop(lua_State* L) { + lua_pushcclosure(L, dsp_bringToTop, 0); + return 1; +} + +static int hlWindowAlterZOrder(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.window.alter_zorder: expected a table { mode, window? }"); + + const auto mode = Internal::requireTableFieldStr(L, 1, "mode", "hl.window.alter_zorder"); + lua_pushstring(L, mode.c_str()); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_alterZOrder, 2); + return 1; +} + +static int hlWindowSetProp(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.window.set_prop: expected a table { prop, value, window? }"); + + const auto prop = Internal::requireTableFieldStr(L, 1, "prop", "hl.window.set_prop"); + const auto value = Internal::requireTableFieldStr(L, 1, "value", "hl.window.set_prop"); + lua_pushstring(L, prop.c_str()); + lua_pushstring(L, value.c_str()); + Internal::pushWindowUpval(L, 1); + lua_pushcclosure(L, dsp_setProp, 3); + return 1; +} + +static int hlWindowDenyFromGroup(lua_State* L) { + const auto action = Internal::tableToggleAction(L, 1); + + lua_pushnumber(L, (int)action); + lua_pushcclosure(L, dsp_denyFromGroup, 1); + return 1; +} + +static int hlWindowDrag(lua_State* L) { + lua_pushcclosure(L, dsp_mouseDrag, 0); + return 1; +} + +static int hlWindowResize(lua_State* L) { + if (lua_gettop(L) == 0 || lua_isnil(L, 1)) { + lua_pushcclosure(L, dsp_mouseResize, 0); + return 1; + } + + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.window.resize: expected no args, or a table { x, y, relative?, window? }"); + + return hlWindowResizeExact(L); +} + +static int dsp_moveFocus(lua_State* L) { + Internal::checkResult(L, CA::moveFocus(sc<Math::eDirection>((int)lua_tonumber(L, lua_upvalueindex(1))))); + return 0; +} + +static int dsp_focusMonitor(lua_State* L) { + const auto PMONITOR = g_pCompositor->getMonitorFromString(lua_tostring(L, lua_upvalueindex(1))); + if (!PMONITOR) + return Internal::configError(L, "hl.focus.monitor: monitor not found"); + Internal::checkResult(L, CA::focusMonitor(PMONITOR)); + return 0; +} + +static int dsp_focusWindowBySelector(lua_State* L) { + const auto PWINDOW = g_pCompositor->getWindowByRegex(lua_tostring(L, lua_upvalueindex(1))); + if (!PWINDOW) + return Internal::configError(L, "hl.focus: window not found"); + Internal::checkResult(L, CA::focus(PWINDOW)); + return 0; +} + +static int dsp_focusUrgentOrLast(lua_State* L) { + Internal::checkResult(L, CA::focusUrgentOrLast()); + return 0; +} + +static int dsp_focusCurrentOrLast(lua_State* L) { + Internal::checkResult(L, CA::focusCurrentOrLast()); + return 0; +} + +static int dsp_changeWorkspace(lua_State* L) { + Internal::checkResult(L, CA::changeWorkspace(std::string(lua_tostring(L, lua_upvalueindex(1))))); + return 0; +} + +static int dsp_focusWorkspaceOnCurrentMonitor(lua_State* L) { + auto ws = Internal::resolveWorkspaceStr(lua_tostring(L, lua_upvalueindex(1))); + if (!ws) + return Internal::configError(L, "Invalid workspace"); + Internal::checkResult(L, CA::changeWorkspaceOnCurrentMonitor(ws)); + return 0; +} + +static int hlFocus(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.focus: expected a table, e.g. { direction = \"left\" }"); + + auto dirStr = Internal::tableOptStr(L, 1, "direction"); + if (dirStr) { + auto dir = Internal::parseDirectionStr(*dirStr); + if (dir == Math::DIRECTION_DEFAULT) + return Internal::configError(L, "hl.focus: invalid direction \"{}\" (expected left/right/up/down)", *dirStr); + lua_pushnumber(L, (int)dir); + lua_pushcclosure(L, dsp_moveFocus, 1); + return 1; + } + + auto monStr = Internal::tableOptMonitorSelector(L, 1, "monitor", "hl.focus"); + if (monStr) { + lua_pushstring(L, monStr->c_str()); + lua_pushcclosure(L, dsp_focusMonitor, 1); + return 1; + } + + auto wsStr = Internal::tableOptWorkspaceSelector(L, 1, "workspace", "hl.focus"); + if (wsStr) { + auto onCurrentMon = Internal::tableOptBool(L, 1, "on_current_monitor"); + + lua_pushstring(L, wsStr->c_str()); + + if (onCurrentMon.value_or(false)) + lua_pushcclosure(L, dsp_focusWorkspaceOnCurrentMonitor, 1); + else + lua_pushcclosure(L, dsp_changeWorkspace, 1); + + return 1; + } + + auto winStr = Internal::tableOptWindowSelector(L, 1, "window", "hl.focus"); + if (winStr) { + lua_pushstring(L, winStr->c_str()); + lua_pushcclosure(L, dsp_focusWindowBySelector, 1); + return 1; + } + + auto urgent = Internal::tableOptBool(L, 1, "urgent_or_last"); + if (urgent && *urgent) { + lua_pushcclosure(L, dsp_focusUrgentOrLast, 0); + return 1; + } + + auto last = Internal::tableOptBool(L, 1, "last"); + if (last && *last) { + lua_pushcclosure(L, dsp_focusCurrentOrLast, 0); + return 1; + } + + return Internal::configError(L, "hl.focus: unrecognized arguments. Expected one of: direction, monitor, window, urgent_or_last, last"); +} + +static int dsp_toggleSpecial(lua_State* L) { + std::string name = lua_isnil(L, lua_upvalueindex(1)) ? "" : lua_tostring(L, lua_upvalueindex(1)); + const auto& [workspaceID, workspaceName, isAutoID] = getWorkspaceIDNameFromString("special:" + name); + if (workspaceID == WORKSPACE_INVALID || !g_pCompositor->isWorkspaceSpecial(workspaceID)) + return Internal::configError(L, "Invalid special workspace"); + + auto ws = g_pCompositor->getWorkspaceByID(workspaceID); + if (!ws) { + const auto PMONITOR = Desktop::focusState()->monitor(); + if (PMONITOR) + ws = g_pCompositor->createNewWorkspace(workspaceID, PMONITOR->m_id, workspaceName); + } + if (!ws) + return Internal::configError(L, "Could not resolve special workspace"); + + Internal::checkResult(L, CA::toggleSpecial(ws)); + return 0; +} + +static int dsp_renameWorkspace(lua_State* L) { + const auto PWS = g_pCompositor->getWorkspaceByString(lua_tostring(L, lua_upvalueindex(1))); + if (!PWS) + return Internal::configError(L, "hl.workspace.rename: no such workspace"); + std::string name = lua_isnil(L, lua_upvalueindex(2)) ? "" : lua_tostring(L, lua_upvalueindex(2)); + Internal::checkResult(L, CA::renameWorkspace(PWS, name)); + return 0; +} + +static int dsp_moveWorkspaceToMonitor(lua_State* L) { + const auto WORKSPACEID = getWorkspaceIDNameFromString(lua_tostring(L, lua_upvalueindex(1))).id; + if (WORKSPACEID == WORKSPACE_INVALID) + return Internal::configError(L, "Invalid workspace"); + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID); + if (!PWORKSPACE) + return Internal::configError(L, "Workspace not found"); + const auto PMONITOR = g_pCompositor->getMonitorFromString(lua_tostring(L, lua_upvalueindex(2))); + if (!PMONITOR) + return Internal::configError(L, "Monitor not found"); + Internal::checkResult(L, CA::moveToMonitor(PWORKSPACE, PMONITOR)); + return 0; +} + +static int dsp_moveCurrentWorkspaceToMonitor(lua_State* L) { + const auto PMONITOR = g_pCompositor->getMonitorFromString(lua_tostring(L, lua_upvalueindex(1))); + if (!PMONITOR) + return Internal::configError(L, "Monitor not found"); + const auto PCURRENTWORKSPACE = Desktop::focusState()->monitor()->m_activeWorkspace; + if (!PCURRENTWORKSPACE) + return Internal::configError(L, "Invalid workspace"); + Internal::checkResult(L, CA::moveToMonitor(PCURRENTWORKSPACE, PMONITOR)); + return 0; +} + +static int dsp_swapActiveWorkspaces(lua_State* L) { + const auto PMON1 = g_pCompositor->getMonitorFromString(lua_tostring(L, lua_upvalueindex(1))); + const auto PMON2 = g_pCompositor->getMonitorFromString(lua_tostring(L, lua_upvalueindex(2))); + if (!PMON1 || !PMON2) + return Internal::configError(L, "Monitor not found"); + Internal::checkResult(L, CA::swapActiveWorkspaces(PMON1, PMON2)); + return 0; +} + +static int hlWorkspaceToggleSpecial(lua_State* L) { + lua_pushstring(L, lua_tostring(L, 1)); + lua_pushcclosure(L, dsp_toggleSpecial, 1); + return 1; +} + +static int hlWorkspaceRename(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.workspace.rename: expected a table { id, name? }"); + + const auto id = Internal::requireTableFieldWorkspaceSelector(L, 1, "id", "hl.workspace.rename"); + auto name = Internal::tableOptStr(L, 1, "name"); + + lua_pushstring(L, id.c_str()); + if (name) + lua_pushstring(L, name->c_str()); + else + lua_pushnil(L); + lua_pushcclosure(L, dsp_renameWorkspace, 2); + return 1; +} + +static int hlWorkspaceMove(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.workspace.move: expected a table, e.g. { monitor = \"DP-1\" }"); + + const auto mon = Internal::requireTableFieldMonitorSelector(L, 1, "monitor", "hl.workspace.move"); + + auto id = Internal::tableOptWorkspaceSelector(L, 1, "id", "hl.workspace.move"); + if (id) { + lua_pushstring(L, id->c_str()); + lua_pushstring(L, mon.c_str()); + lua_pushcclosure(L, dsp_moveWorkspaceToMonitor, 2); + return 1; + } + + lua_pushstring(L, mon.c_str()); + lua_pushcclosure(L, dsp_moveCurrentWorkspaceToMonitor, 1); + return 1; +} + +static int hlWorkspaceSwapMonitors(lua_State* L) { + if (!lua_istable(L, 1)) + return Internal::configError(L, "hl.workspace.swap_monitors: expected a table { monitor1, monitor2 }"); + + const auto m1 = Internal::requireTableFieldMonitorSelector(L, 1, "monitor1", "hl.workspace.swap_monitors"); + const auto m2 = Internal::requireTableFieldMonitorSelector(L, 1, "monitor2", "hl.workspace.swap_monitors"); + lua_pushstring(L, m1.c_str()); + lua_pushstring(L, m2.c_str()); + lua_pushcclosure(L, dsp_swapActiveWorkspaces, 2); + return 1; +} + +void Internal::registerDispatcherBindings(lua_State* L) { + lua_newtable(L); + + { + lua_newtable(L); + Internal::setFn(L, "move_to_corner", hlCursorMoveToCorner); + Internal::setFn(L, "move", hlCursorMove); + lua_setfield(L, -2, "cursor"); + + lua_newtable(L); + Internal::setFn(L, "toggle", hlGroupToggle); + Internal::setFn(L, "next", hlGroupNext); + Internal::setFn(L, "prev", hlGroupPrev); + Internal::setFn(L, "active", hlGroupActive); + Internal::setFn(L, "move_window", hlGroupMoveWindow); + Internal::setFn(L, "lock", hlGroupLock); + Internal::setFn(L, "lock_active", hlGroupLockActive); + lua_setfield(L, -2, "group"); + + lua_newtable(L); + Internal::setFn(L, "close", hlWindowClose); + Internal::setFn(L, "kill", hlWindowKill); + Internal::setFn(L, "signal", hlWindowSignal); + Internal::setFn(L, "float", hlWindowFloat); + Internal::setFn(L, "fullscreen", hlWindowFullscreen); + Internal::setFn(L, "fullscreen_state", hlWindowFullscreenState); + Internal::setFn(L, "pseudo", hlWindowPseudo); + Internal::setFn(L, "move", hlWindowMove); + Internal::setFn(L, "swap", hlWindowSwap); + Internal::setFn(L, "center", hlWindowCenter); + Internal::setFn(L, "cycle_next", hlWindowCycleNext); + Internal::setFn(L, "tag", hlWindowTag); + Internal::setFn(L, "toggle_swallow", hlWindowToggleSwallow); + Internal::setFn(L, "pin", hlWindowPin); + Internal::setFn(L, "bring_to_top", hlWindowBringToTop); + Internal::setFn(L, "alter_zorder", hlWindowAlterZOrder); + Internal::setFn(L, "set_prop", hlWindowSetProp); + Internal::setFn(L, "deny_from_group", hlWindowDenyFromGroup); + Internal::setFn(L, "drag", hlWindowDrag); + Internal::setFn(L, "resize", hlWindowResize); + lua_setfield(L, -2, "window"); + + lua_newtable(L); + Internal::setFn(L, "rename", hlWorkspaceRename); + Internal::setFn(L, "move", hlWorkspaceMove); + Internal::setFn(L, "swap_monitors", hlWorkspaceSwapMonitors); + Internal::setFn(L, "toggle_special", hlWorkspaceToggleSpecial); + lua_setfield(L, -2, "workspace"); + + Internal::setFn(L, "exec_cmd", hlExecCmd); + Internal::setFn(L, "exec_raw", hlExecRaw); + Internal::setFn(L, "exit", hlExit); + Internal::setFn(L, "submap", hlSubmap); + Internal::setFn(L, "pass", hlPass); + Internal::setFn(L, "send_shortcut", hlSendShortcut); + Internal::setFn(L, "send_key_state", hlSendKeyState); + Internal::setFn(L, "layout", hlLayout); + Internal::setFn(L, "dpms", hlDpms); + Internal::setFn(L, "event", hlEvent); + Internal::setFn(L, "global", hlGlobal); + Internal::setFn(L, "force_renderer_reload", hlForceRendererReload); + Internal::setFn(L, "force_idle", hlForceIdle); + Internal::setFn(L, "focus", hlFocus); + } + + lua_setfield(L, -2, "dsp"); +} |
