Merge pull request #24 from levnikmyskin/feat/hyprctl_commands_stdout

Implement hyprctl commands (closes #16)
This commit is contained in:
Alessio Molinari 2024-03-01 18:04:26 +01:00 committed by GitHub
commit 195c5d0c33
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 99 additions and 40 deletions

View File

@ -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.

View File

@ -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";

View File

@ -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<Hyprlang::STRING>(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();