4 Commits
v1.3 ... v1.4

6 changed files with 132 additions and 34 deletions

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.10.0)
project(hyprland-toggle-tiling VERSION 0.1.0 LANGUAGES C CXX)
project(hyprland-toggle-tiling VERSION 1.4.0 LANGUAGES C CXX)
include(FetchContent)
FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz)

View File

@@ -29,6 +29,7 @@ Check out [the demo](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-til
Let's say you switched to tiling mode. From that point on, new windows will open in tiling mode as well.
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.
- Returns applied rule for the current workspace. Useful for scripting.
- Useful for workflows that require both tiling and floating window management.
- Lightweight and easy to integrate with your Hyprland setup.
@@ -75,8 +76,19 @@ or go nuts and...
# Usage
```shell
./htt <config-file-path>
./htt <config-file-path> (-q)
```
- `-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:
```shell
# (On workspace 2...)
$ ./htt ~/.cache/htt/rules -q
windowrule = tile on, match:workspace 2
```
Potential applications for this are mainly scripts, like my waybar module here:
![wayland module showcase](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling/raw/branch/master/assets/waybar_module.gif)
- 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.

BIN
assets/waybar_module.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

@@ -9,19 +9,29 @@
class HyprlandService {
private:
static std::string configFilePath;
public:
static void setConfigFilePath(std::string);
static std::string getConfigFilePath();
static std::list<Workspace> getWorkspaces();
static std::optional<Workspace> getWorkspace(int);
static Workspace getCurrentWorkspace();
static std::list<Client> getClients();
static std::list<Client> getClientsOnActiveWorkspace();
static Client getActiveClient();
static bool isFloatingRulePresent(int);
static bool isFloatingRulePresent(Workspace);
static std::list<WindowRule> getWindowRules();
static std::optional<WindowRule> findConflictingRule(WindowRule);
static void setFloatingRule(bool);
static void removeRule(WindowRule);
static void setClientFloating(Client&);
static void setClientTiled(Client&);
static void toggleClientFloating(Client&);
static bool isFloatingRulePresent();
static void setClientFloating(Client);
static void setClientTiled(Client);
public:
static void toggleFloating();
static void moveToWorkspace(int);
static void setConfigFilePath(std::string);
static WindowRule getActiveWorkspaceRule();
};
#endif

View File

@@ -1,4 +1,6 @@
#include <nlohmann/json.hpp>
#include <optional>
#include <string>
#include "../include/HyprlandService.h"
#include "../include/ShellService.h"
#include "../include/Macros.h"
@@ -22,11 +24,35 @@ std::string HyprlandService::getConfigFilePath() {
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() {
json j = json::parse(ShellService::exec(HYPRCTL_BINARY " activeworkspace -j"));
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() {
json j = json::parse(ShellService::exec(HYPRCTL_BINARY " clients -j"));
return j.get<std::list<Client>>();
@@ -57,18 +83,14 @@ std::list<WindowRule> HyprlandService::getWindowRules() {
return rules;
};
void HyprlandService::setClientFloating(Client& c) {
void HyprlandService::setClientFloating(Client c) {
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);
}
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 = false -> creates a window rule to DISABLE floating mode for currently active workspace
void HyprlandService::setFloatingRule(bool on) {
@@ -122,16 +144,56 @@ void HyprlandService::removeRule(WindowRule rule) {
//else: rule not found, do nothing
}
bool HyprlandService::isFloatingRulePresent() {
//Checks if there's a valid window rule in place that enables floating mode for the currently active workspace
bool HyprlandService::isFloatingRulePresent(int workspaceId) {
std::list<WindowRule> rules = getWindowRules();
int id = getCurrentWorkspace().id;
for (auto& rule : rules) {
if (rule.workspaceID == id && rule.tile == false) {
if (rule.workspaceID == workspaceId && rule.tile == false) {
return true;
}
}
return false;
}
bool HyprlandService::isFloatingRulePresent(Workspace workspace) {
return isFloatingRulePresent(workspace.id);
};
WindowRule HyprlandService::getActiveWorkspaceRule() {
std::list<WindowRule> rules = getWindowRules();
int id = getCurrentWorkspace().id;
for (auto& rule : rules) {
if (rule.workspaceID == id) {
return rule;
}
}
//If no rule is found, return a default rule (tiled)
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);
}
}

View File

@@ -1,23 +1,37 @@
#include <iostream>
#include <stdexcept>
#include "../include/HyprlandService.h"
int main(int argc, char** argv){
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <config_file_path>\n";
void help(char* execPath) {
std::cerr << "Usage: " << execPath << " <config_file_path> (flags)\n\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);
}
int main(int argc, char** argv) {
if (argc >= 2) {
HyprlandService::setConfigFilePath(argv[1]);
if (HyprlandService::isFloatingRulePresent()) {
for (auto& c : HyprlandService::getClientsOnActiveWorkspace()) {
HyprlandService::setClientTiled(c);
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]);
}
HyprlandService::setFloatingRule(false);
} else {
for (auto& c : HyprlandService::getClientsOnActiveWorkspace()) {
HyprlandService::setClientFloating(c);
help(argv[0]);
}
HyprlandService::setFloatingRule(true);
} else {
help(argv[0]);
}
exit(0);
}