diff --git a/README.md b/README.md index 7bbc254..c6c38fe 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ - [It's just workspaces, really](#its-just-workspaces-really) - [Hyprctl dispatchers](#hyprctl-dispatchers) - [Mix with Hyprland native workspaces](#mix-with-hyprland-native-workspaces) + - [Hyprctl commands](#hyprctl-commands) - [Hyprland keywords](#hyprland-keywords) - [Syntax](#syntax) - [Examples](#examples) @@ -60,7 +61,6 @@ This plugin exposes a few hyprctl dispatchers: |------------|-------------|------|--------| | vdesk [vdesk] | Changes to virtual desktop `vdesk` | see below | `vdesk 3` or `vdesk coding`| | lastdesk | Changes to last visited virtual desktop | `none` | `lastdesk`| -| printdesk (vdesk)| Prints to Hyprland log the specified vdesk or the currently active vdesk* (if no argument is given) | optional vdesk, see below | `printdesk` or `printdesk 2` or `printdesk coding`| | movetodesk vdesk(, window) | Moves the active/selected window to the specified `vdesk` | `vdesk`, optional window, see below | `movetodesk 2` or `movetodesk 2,title:kitty` | | movetodesksilent vdesk(, window) | same as `movetodesk`, but doesn't switch to desk | same as above | same as above | | movetolastdesk (window) | Moves the active/selected window to the last visited `vdesk` | optional window | `movetolastdesk` or `movetolastdesk title:kitty` | @@ -74,9 +74,7 @@ This plugin exposes a few hyprctl dispatchers: | nextdesk | go to next vdesk. Creates it if it doesn't exist | `none` | `nextdesk` | | backcyclevdesks | backward cycle between currently existing vdesks. Goes back to vdesk with max id when at vdesk 1 | `none` | `backcyclevdesks` | | cyclevdesks | cycle between currently existing vdesks. Goes back to vdesk 1 if next vdesk does not exist | `none` | `cyclevdesks` | -| printlayout | print to Hyprland logs the current layout | `none` | `printlayout` | -\*`printdesk` currently prints to the active Hyprland session log, thus probably not really useful. > BREAKING v2.1.0: `prevdesk` dispatcher was renamed to `lastdesk`. `prevdesk` has a new functionality: it goes to the previous desk. If you were using `prevdesk`, please update your config. @@ -106,6 +104,16 @@ to the same vdesk given the same number of monitors, unless you focus (e.g. with The vdesk a workspace will end up to is easily computed by doing `ceil(workspace_id / n_monitors)`. You know where I'm going with this one...you can easily script it. +### Hyprctl commands +Since version 2.2, this plugin exposes a couple of `hyprctl` commands. That is, you can use them by calling `hyprctl {command} {args}`. +**NOTICE**: some of these used to be dispatchers. + +| Command | description | args | example| +|------------|-------------|------|--------| +| printdesk (vdesk)| Prints to Hyprland log the specified vdesk or the currently active vdesk* (if no argument is given) | optional vdesk, see [above](#hyprctl-dispatchers) | `hyprctl printdesk` or `hyprctl printdesk 2` or `hyprctl printdesk coding`| +| printlayout | print to Hyprland logs the current layout | `none` | `hyprctl printlayout` | + + ### Hyprland keywords Since version 2.2, this plugin exposes one keyword: `stickyrule`. A sticky rule is composed of a window identifier and a vdesk identifier. diff --git a/include/utils.hpp b/include/utils.hpp index 9e9fa71..29f9b3d 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -28,14 +28,15 @@ const std::string MOVETOLASTDESKSILENT_DISPATCH_STR = "movetolastdesksilent"; const std::string MOVETOPREVDESKSILENT_DISPATCH_STR = "movetoprevdesksilent"; const std::string MOVETONEXTDESKSILENT_DISPATCH_STR = "movetonextdesksilent"; +const std::string LASTDESK_DISPATCH_STR = "lastdesk"; +const std::string PREVDESK_DISPATCH_STR = "prevdesk"; +const std::string NEXTDESK_DISPATCH_STR = "nextdesk"; +const std::string CYCLEVDESK_DISPATCH_STR = "cyclevdesks"; +const std::string BACKCYCLE_DISPATCH_STR = "backcyclevdesks"; + const std::string RESET_VDESK_DISPATCH_STR = "vdeskreset"; -const std::string LASTDESK_DISPATCH_STR = "lastdesk"; -const std::string PREVDESK_DISPATCH_STR = "prevdesk"; -const std::string NEXTDESK_DISPATCH_STR = "nextdesk"; const std::string PRINTDESK_DISPATCH_STR = "printdesk"; const std::string PRINTLAYOUT_DISPATCH_STR = "printlayout"; -const std::string CYCLEVDESK_DISPATCH_STR = "cyclevdesks"; -const std::string BACKCYCLE_DISPATCH_STR = "backcyclevdesks"; const std::string REMEMBER_NONE = "none"; const std::string REMEMBER_SIZE = "size"; diff --git a/src/main.cpp b/src/main.cpp index 2441fa2..a677bfe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -132,47 +132,78 @@ void moveToNextDeskSilentDispatch(std::string arg) { manager->moveToDesk(arg, manager->nextDeskId(cycle)); } -void printVdesk(int vdeskId) { - printLog("VDesk " + std::to_string(vdeskId) + ": " + manager->vdeskNamesMap[vdeskId]); -} +std::string printVDeskDispatch(eHyprCtlOutputFormat format, std::string arg) { + static auto* const PVDESKNAMESCONF = (Hyprlang::STRING const*)(HyprlandAPI::getConfigValue(PHANDLE, VIRTUALDESK_NAMES_CONF))->getDataStaticPtr(); -void printVdesk(std::string name) { - for (auto const& [key, val] : manager->vdeskNamesMap) { - if (val == name) { - printLog("Vdesk " + std::to_string(key) + ": " + val); - return; - } - } -} + auto vdeskNamesConf = std::string{*PVDESKNAMESCONF}; + parseNamesConf(vdeskNamesConf); -void printVDeskDispatch(std::string arg) { - std::string vdesknamesConf = std::any_cast(HyprlandAPI::getConfigValue(PHANDLE, VIRTUALDESK_NAMES_CONF)); + arg.erase(0, PRINTDESK_DISPATCH_STR.length()); + printLog(std::format("Got {}", arg)); - parseNamesConf(vdesknamesConf); - - if (arg.length() == 0) { - printVdesk(manager->activeVdesk()->id); - } else + int vdeskId; + std::string vdeskName; + if (arg.length() > 0) { + arg = arg.erase(0, 1); // delete whitespace + printLog(std::format("Got {}", arg)); try { // maybe id - printVdesk(std::stoi(arg)); + vdeskId = std::stoi(arg); + vdeskName = manager->vdeskNamesMap.at(vdeskId); } catch (std::exception const& ex) { // by name then - printVdesk(arg); + vdeskId = manager->getDeskIdFromName(arg, false); + if (vdeskId < 0) + vdeskName = "not found"; + else + vdeskName = manager->vdeskNamesMap[vdeskId]; } + } else { + vdeskId = manager->activeVdesk()->id; + vdeskName = manager->activeVdesk()->name; + } + + if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { + return std::format("Virtual desk {}: {}", vdeskId, vdeskName); + + } else if (format == eHyprCtlOutputFormat::FORMAT_JSON) { + return std::format(R"#({{ + "virtualdesk": {{ + "id": {}, + "name": "{}" + }} + }})#", + vdeskId, vdeskName); + } + return ""; } -void printLayoutDispatch(std::string arg) { - auto activeDesk = manager->activeVdesk(); - auto layout = activeDesk->activeLayout(manager->conf); - std::ostringstream out; - out << "Active desk: " << activeDesk->name; - out << "\nActive layout size " << layout.size(); - out << "; Monitors:\n"; - for (auto const& [desc, wid] : layout) { - out << desc << "; Workspace " << wid << "\n"; +std::string printLayoutDispatch(eHyprCtlOutputFormat format, std::string arg) { + auto activeDesk = manager->activeVdesk(); + auto layout = activeDesk->activeLayout(manager->conf); + std::string out; + if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { + out += std::format("Active desk: {}\nActive layout size: {};\nMonitors:", activeDesk->name, layout.size()); + for (auto const& [mon, wid] : layout) { + out += std::format("\n\t{}; Workspace {}", escapeJSONStrings(mon->szName), wid); + } + } else if (format == eHyprCtlOutputFormat::FORMAT_JSON) { + out += std::format(R"#({{ + "activeDesk": "{}", + "activeLayoutSize": {}, + "monitors": [ + )#", + activeDesk->name, layout.size()); + for (auto const& [mon, wid] : layout) { + out += std::format(R"#({{ + "monitorId": {}, + "workspace": {} + }})#", + mon->ID, wid); + } + out += "]\n}"; } - printLog(out.str()); + return out; } void resetVDeskDispatch(std::string arg) { @@ -253,6 +284,26 @@ void onConfigReloaded(void*, SCallbackInfo&, std::any val) { manager->loadLayoutConf(); } +void registerHyprctlCommands() { + SHyprCtlCommand cmd; + + // Register printlayout + cmd.name = PRINTLAYOUT_DISPATCH_STR; + cmd.fn = printLayoutDispatch; + cmd.exact = true; + auto ptr = HyprlandAPI::registerHyprCtlCommand(PHANDLE, cmd); + if (!ptr) + printLog(std::format("Failed to register hyprctl command: {}", PRINTLAYOUT_DISPATCH_STR)); + + // Register printdesk + cmd.name = PRINTDESK_DISPATCH_STR; + cmd.fn = printVDeskDispatch; + cmd.exact = false; + ptr = HyprlandAPI::registerHyprCtlCommand(PHANDLE, cmd); + if (!ptr) + printLog(std::format("Failed to register hyprctl command: {}", VDESK_DISPATCH_STR)); +} + // Do NOT change this function. APICALL EXPORT std::string PLUGIN_API_VERSION() { return HYPRLAND_API_VERSION; @@ -279,8 +330,6 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { HyprlandAPI::addDispatcher(PHANDLE, MOVETONEXTDESKSILENT_DISPATCH_STR, moveToNextDeskSilentDispatch); HyprlandAPI::addDispatcher(PHANDLE, RESET_VDESK_DISPATCH_STR, resetVDeskDispatch); - HyprlandAPI::addDispatcher(PHANDLE, PRINTDESK_DISPATCH_STR, printVDeskDispatch); - HyprlandAPI::addDispatcher(PHANDLE, PRINTLAYOUT_DISPATCH_STR, printLayoutDispatch); // Configs HyprlandAPI::addConfigValue(PHANDLE, VIRTUALDESK_NAMES_CONF, Hyprlang::STRING{"unset"}); @@ -298,6 +347,7 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { onMonitorDisconnectHook = HyprlandAPI::registerCallbackDynamic(PHANDLE, "monitorRemoved", onMonitorDisconnect); onMonitorAddedHook = HyprlandAPI::registerCallbackDynamic(PHANDLE, "monitorAdded", onMonitorAdded); onRenderHook = HyprlandAPI::registerCallbackDynamic(PHANDLE, "preRender", onRender); + registerHyprctlCommands(); // Initialize first vdesk HyprlandAPI::reloadConfig();