Feature: moving a window to another workspace changes its windowing mode to respect the new workspace's one
This commit is contained in:
39
README.md
39
README.md
@@ -30,6 +30,7 @@ Check out [the demo](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-til
|
|||||||
Switch to floating mode again and newly opened windows will be in floating mode.
|
Switch to floating mode again and newly opened windows will be in floating mode.
|
||||||
- Floating/tiling window rules are isolated between workspaces. You can set one workspace to be floating, and all the rest to tiling for example.
|
- Floating/tiling window rules are isolated between workspaces. You can set one workspace to be floating, and all the rest to tiling for example.
|
||||||
- Returns applied rule for the current workspace. Useful for scripting.
|
- Returns applied rule for the current workspace. Useful for scripting.
|
||||||
|
- Moving a window from a tiling workspace to a floating one changes the float state of the window to respect the new workspace.
|
||||||
- Useful for workflows that require both tiling and floating window management.
|
- Useful for workflows that require both tiling and floating window management.
|
||||||
- Lightweight and easy to integrate with your Hyprland setup.
|
- Lightweight and easy to integrate with your Hyprland setup.
|
||||||
|
|
||||||
@@ -76,7 +77,7 @@ or go nuts and...
|
|||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
```shell
|
```shell
|
||||||
./htt <config-file-path> (-q)
|
./htt <config-file-path> (flags)
|
||||||
```
|
```
|
||||||
- `-q`: Print the rule applied on the current workspace to STDOUT, but don't change anything. If there isn't an active rule for the current workspace, it returns a tiling rule. The returned string is a valid Hyprland window rule configuration line, like so:
|
- `-q`: Print the rule applied on the current workspace to STDOUT, but don't change anything. If there isn't an active rule for the current workspace, it returns a tiling rule. The returned string is a valid Hyprland window rule configuration line, like so:
|
||||||
|
|
||||||
@@ -89,6 +90,8 @@ windowrule = tile on, match:workspace 2
|
|||||||
Potential applications for this are mainly scripts, like my waybar module here:
|
Potential applications for this are mainly scripts, like my waybar module here:
|
||||||

|

|
||||||
|
|
||||||
|
- `-m [integer]`: Move currently active window to specified workspace. Upon moving, the window will adapt to the windowing mode of the new workspace. Doesn't work with `-q`. See  for details.
|
||||||
|
|
||||||
- If the specified configuration file does not exist, it will be created.
|
- If the specified configuration file does not exist, it will be created.
|
||||||
- If the configuration contains existing rules, this should still work, but your existing configuration will probably get a bit messy, syntax-wise. I advise against it.
|
- If the configuration contains existing rules, this should still work, but your existing configuration will probably get a bit messy, syntax-wise. I advise against it.
|
||||||
|
|
||||||
@@ -104,5 +107,37 @@ Potential applications for this are mainly scripts, like my waybar module here:
|
|||||||
bind = $mod + t, exec, /path/to/htt <config-file-path>
|
bind = $mod + t, exec, /path/to/htt <config-file-path>
|
||||||
```
|
```
|
||||||
|
|
||||||
Or not. Do whatever you want.
|
3. If you want windows to respect workspaces' rules after moving them to another workspace (see  for details), you might want to tell HTT to move your windows instead of telling Hyprland.
|
||||||
|
On the default configuration, this would mean changing this:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bind = $mainMod SHIFT, 1, movetoworkspace, 1
|
||||||
|
bind = $mainMod SHIFT, 2, movetoworkspace, 2
|
||||||
|
bind = $mainMod SHIFT, 3, movetoworkspace, 3
|
||||||
|
bind = $mainMod SHIFT, 4, movetoworkspace, 4
|
||||||
|
bind = $mainMod SHIFT, 5, movetoworkspace, 5
|
||||||
|
bind = $mainMod SHIFT, 6, movetoworkspace, 6
|
||||||
|
bind = $mainMod SHIFT, 7, movetoworkspace, 7
|
||||||
|
bind = $mainMod SHIFT, 8, movetoworkspace, 8
|
||||||
|
bind = $mainMod SHIFT, 9, movetoworkspace, 9
|
||||||
|
bind = $mainMod SHIFT, 0, movetoworkspace, 10
|
||||||
|
```
|
||||||
|
|
||||||
|
to this:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bind = $mainMod SHIFT, 1, exec, htt [your htt config file] -m 1
|
||||||
|
bind = $mainMod SHIFT, 2, exec, htt [your htt config file] -m 2
|
||||||
|
bind = $mainMod SHIFT, 3, exec, htt [your htt config file] -m 3
|
||||||
|
bind = $mainMod SHIFT, 4, exec, htt [your htt config file] -m 4
|
||||||
|
bind = $mainMod SHIFT, 5, exec, htt [your htt config file] -m 5
|
||||||
|
bind = $mainMod SHIFT, 6, exec, htt [your htt config file] -m 6
|
||||||
|
bind = $mainMod SHIFT, 7, exec, htt [your htt config file] -m 7
|
||||||
|
bind = $mainMod SHIFT, 8, exec, htt [your htt config file] -m 8
|
||||||
|
bind = $mainMod SHIFT, 9, exec, htt [your htt config file] -m 9
|
||||||
|
bind = $mainMod SHIFT, 0, exec, htt [your htt config file] -m 10
|
||||||
|
```
|
||||||
|
|
||||||
|
... in your configuration.
|
||||||
|
Otherwise, just use `exec, htt [your htt config file] -m [workspace ID]` wherever you used `movetoworkspace [workspace ID]` before.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
#include "../include/HyprlandService.h"
|
#include "../include/HyprlandService.h"
|
||||||
#include "../include/ShellService.h"
|
#include "../include/ShellService.h"
|
||||||
#include "../include/Macros.h"
|
#include "../include/Macros.h"
|
||||||
@@ -22,11 +24,35 @@ std::string HyprlandService::getConfigFilePath() {
|
|||||||
return configFilePath;
|
return configFilePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::list<Workspace> HyprlandService::getWorkspaces() {
|
||||||
|
json j = json::parse(ShellService::exec(HYPRCTL_BINARY " workspaces -j"));
|
||||||
|
return j.get<std::list<Workspace>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Workspace> HyprlandService::getWorkspace(int id) {
|
||||||
|
std::list<Workspace> workspaces = getWorkspaces();
|
||||||
|
|
||||||
|
for (auto it = workspaces.begin(); it != workspaces.end(); ) {
|
||||||
|
if (it->id == id) {
|
||||||
|
return *it;
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
Workspace HyprlandService::getCurrentWorkspace() {
|
Workspace HyprlandService::getCurrentWorkspace() {
|
||||||
json j = json::parse(ShellService::exec(HYPRCTL_BINARY " activeworkspace -j"));
|
json j = json::parse(ShellService::exec(HYPRCTL_BINARY " activeworkspace -j"));
|
||||||
return j.get<Workspace>();
|
return j.get<Workspace>();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Client HyprlandService::getActiveClient() {
|
||||||
|
json j = json::parse(ShellService::exec(HYPRCTL_BINARY " activewindow -j"));
|
||||||
|
return j.get<Client>();
|
||||||
|
}
|
||||||
|
|
||||||
std::list<Client> HyprlandService::getClients() {
|
std::list<Client> HyprlandService::getClients() {
|
||||||
json j = json::parse(ShellService::exec(HYPRCTL_BINARY " clients -j"));
|
json j = json::parse(ShellService::exec(HYPRCTL_BINARY " clients -j"));
|
||||||
return j.get<std::list<Client>>();
|
return j.get<std::list<Client>>();
|
||||||
@@ -57,18 +83,14 @@ std::list<WindowRule> HyprlandService::getWindowRules() {
|
|||||||
return rules;
|
return rules;
|
||||||
};
|
};
|
||||||
|
|
||||||
void HyprlandService::setClientFloating(Client& c) {
|
void HyprlandService::setClientFloating(Client c) {
|
||||||
ShellService::exec(HYPRCTL_BINARY " dispatch setfloating address:" + c.address);
|
ShellService::exec(HYPRCTL_BINARY " dispatch setfloating address:" + c.address);
|
||||||
};
|
};
|
||||||
|
|
||||||
void HyprlandService::setClientTiled(Client& c) {
|
void HyprlandService::setClientTiled(Client c) {
|
||||||
ShellService::exec(HYPRCTL_BINARY " dispatch settiled address:" + c.address);
|
ShellService::exec(HYPRCTL_BINARY " dispatch settiled address:" + c.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HyprlandService::toggleClientFloating(Client& c) {
|
|
||||||
ShellService::exec(HYPRCTL_BINARY " dispatch togglefloating address:" + c.address);
|
|
||||||
};
|
|
||||||
|
|
||||||
//on = true -> creates a window rule to ENABLE floating mode for currently active workspace
|
//on = true -> creates a window rule to ENABLE floating mode for currently active workspace
|
||||||
//on = false -> creates a window rule to DISABLE floating mode for currently active workspace
|
//on = false -> creates a window rule to DISABLE floating mode for currently active workspace
|
||||||
void HyprlandService::setFloatingRule(bool on) {
|
void HyprlandService::setFloatingRule(bool on) {
|
||||||
@@ -122,18 +144,20 @@ void HyprlandService::removeRule(WindowRule rule) {
|
|||||||
//else: rule not found, do nothing
|
//else: rule not found, do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HyprlandService::isFloatingRulePresent() {
|
bool HyprlandService::isFloatingRulePresent(int workspaceId) {
|
||||||
//Checks if there's a valid window rule in place that enables floating mode for the currently active workspace
|
|
||||||
std::list<WindowRule> rules = getWindowRules();
|
std::list<WindowRule> rules = getWindowRules();
|
||||||
int id = getCurrentWorkspace().id;
|
|
||||||
|
|
||||||
for (auto& rule : rules) {
|
for (auto& rule : rules) {
|
||||||
if (rule.workspaceID == id && rule.tile == false) {
|
if (rule.workspaceID == workspaceId && rule.tile == false) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HyprlandService::isFloatingRulePresent(Workspace workspace) {
|
||||||
|
return isFloatingRulePresent(workspace.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
WindowRule HyprlandService::getActiveWorkspaceRule() {
|
WindowRule HyprlandService::getActiveWorkspaceRule() {
|
||||||
@@ -149,3 +173,27 @@ WindowRule HyprlandService::getActiveWorkspaceRule() {
|
|||||||
//If no rule is found, return a default rule (tiled)
|
//If no rule is found, return a default rule (tiled)
|
||||||
return WindowRule {.tile = true, .workspaceID = id};
|
return WindowRule {.tile = true, .workspaceID = id};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void HyprlandService::moveToWorkspace(int workspaceId) {
|
||||||
|
if (isFloatingRulePresent(workspaceId)) {
|
||||||
|
setClientFloating(getActiveClient());
|
||||||
|
} else {
|
||||||
|
setClientTiled(getActiveClient());
|
||||||
|
}
|
||||||
|
|
||||||
|
ShellService::exec(HYPRCTL_BINARY " dispatch movetoworkspace " + std::to_string(workspaceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HyprlandService::toggleFloating() {
|
||||||
|
if (isFloatingRulePresent(getCurrentWorkspace())) {
|
||||||
|
for (auto& c : getClientsOnActiveWorkspace()) {
|
||||||
|
setClientTiled(c);
|
||||||
|
}
|
||||||
|
setFloatingRule(false);
|
||||||
|
} else {
|
||||||
|
for (auto& c : getClientsOnActiveWorkspace()) {
|
||||||
|
setClientFloating(c);
|
||||||
|
}
|
||||||
|
setFloatingRule(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
48
src/main.cpp
48
src/main.cpp
@@ -1,37 +1,37 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
#include "../include/HyprlandService.h"
|
#include "../include/HyprlandService.h"
|
||||||
|
|
||||||
void help(char* execPath) {
|
void help(char* execPath) {
|
||||||
std::cerr << "Usage: " << execPath << " <config_file_path> (-q)\n\n";
|
std::cerr << "Usage: " << execPath << " <config_file_path> (flags)\n\n";
|
||||||
std::cerr << "-q:\tQuery current windowing mode, don't change anything.\n\tReturns Hyprland window rule active on current workspace.\n\tIf no rule is active, returns a default tiled rule.\n";
|
std::cerr << "Flags:\n\n";
|
||||||
|
std::cerr << "-q:\t\tQuery current windowing mode, don't change anything.\n\t\tReturns Hyprland window rule active on current workspace.\n\t\tIf no rule is active, returns a default tiled rule.\n\n";
|
||||||
|
std::cerr << "-m [integer]:\tMove currently active window to specified workspace.\n\t\tUpon moving, the window will adapt to the windowing mode of the new workspace.\n\t\tDoesn't work with -q.\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
if (argc < 2) {
|
if (argc >= 2) {
|
||||||
|
HyprlandService::setConfigFilePath(argv[1]);
|
||||||
|
|
||||||
|
if (argc == 2) {
|
||||||
|
HyprlandService::toggleFloating();
|
||||||
|
}
|
||||||
|
else if (argc == 3 && argv[2] == std::string("-q")) {
|
||||||
|
std::cout << HyprlandService::getActiveWorkspaceRule().toString() << std::endl;
|
||||||
|
} else if (argc == 4 && argv[2] == std::string("-m")) {
|
||||||
|
int workspace = 0;
|
||||||
|
try {
|
||||||
|
HyprlandService::moveToWorkspace(std::stoi(argv[3]));
|
||||||
|
} catch (std::invalid_argument) {
|
||||||
|
help(argv[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
help(argv[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
help(argv[0]);
|
help(argv[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
HyprlandService::setConfigFilePath(argv[1]);
|
|
||||||
|
|
||||||
if (argc == 3 && argv[2] == std::string("-q")) {
|
|
||||||
WindowRule rule = HyprlandService::getActiveWorkspaceRule();
|
|
||||||
std::cout << rule.toString() << std::endl;
|
|
||||||
}
|
|
||||||
else if (argc == 2) {
|
|
||||||
if (HyprlandService::isFloatingRulePresent()) {
|
|
||||||
for (auto& c : HyprlandService::getClientsOnActiveWorkspace()) {
|
|
||||||
HyprlandService::setClientTiled(c);
|
|
||||||
}
|
|
||||||
HyprlandService::setFloatingRule(false);
|
|
||||||
} else {
|
|
||||||
for (auto& c : HyprlandService::getClientsOnActiveWorkspace()) {
|
|
||||||
HyprlandService::setClientFloating(c);
|
|
||||||
}
|
|
||||||
HyprlandService::setFloatingRule(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else (help(argv[0]));
|
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user