8 Commits
v1.4 ... master

21 changed files with 366 additions and 123 deletions

3
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.cache/ .cache/
build/ build/
.vscode/ .vscode/
result

View File

@@ -1,17 +1,69 @@
cmake_minimum_required(VERSION 3.10.0) cmake_minimum_required(VERSION 3.16)
project(hyprland-toggle-tiling VERSION 1.4.0 LANGUAGES C CXX)
project(hyprland-toggle-tiling
VERSION 1.4.2
LANGUAGES CXX
)
include(GNUInstallDirs)
include(FetchContent) include(FetchContent)
FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz)
FetchContent_MakeAvailable(json) # --------------------------------------------------
# Dependency handling
# --------------------------------------------------
option(USE_SYSTEM_JSON
"Use system-installed nlohmann_json instead of fetching"
OFF
)
if(USE_SYSTEM_JSON)
find_package(nlohmann_json CONFIG REQUIRED)
else()
# Try system package first silently
find_package(nlohmann_json CONFIG QUIET)
if(NOT nlohmann_json_FOUND)
message(STATUS "nlohmann_json not found, fetching from GitHub")
FetchContent_Declare(
nlohmann_json
URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz
)
FetchContent_MakeAvailable(nlohmann_json)
else()
message(STATUS "Using system nlohmann_json")
endif()
endif()
# --------------------------------------------------
# Executable
# --------------------------------------------------
add_executable(htt add_executable(htt
src/main.cpp src/main.cpp
src/HyprlandService.cpp src/HyprlandService.cpp
src/Workspace.cpp src/Workspace.cpp
src/ShellService.cpp src/ShellService.cpp
src/FileService.cpp src/FileService.cpp
src/WindowRule.cpp src/WindowRule.cpp
src/Client.cpp) src/Client.cpp
target_link_libraries(htt PRIVATE nlohmann_json::nlohmann_json) )
target_include_directories(htt PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_features(htt PRIVATE cxx_std_17)
target_link_libraries(htt
PRIVATE
nlohmann_json::nlohmann_json
)
target_include_directories(htt PRIVATE ${PROJECT_SOURCE_DIR}/src)
# --------------------------------------------------
# Install
# --------------------------------------------------
install(TARGETS htt
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

View File

@@ -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.
@@ -41,6 +42,34 @@ You have a few options of obtainting the program.
You may install this program [from the AUR.](https://aur.archlinux.org/packages/hyprland-toggle-tiling-git) You may install this program [from the AUR.](https://aur.archlinux.org/packages/hyprland-toggle-tiling-git)
### Nix Flake (for Nix users)
This project provides a Nix flake for reproducible builds and easy installation.
#### Build the package
```shell
nix build git+ssh://gitea@typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling.git
```
The binary will be at `./result/bin/htt`.
#### Add to Home Manager
1. Add the flake as an input:
```shell
inputs.htt.url = "git+ssh://gitea@typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling.git";
```
2. Then include it in your configuration:
```shell
home.packages = [
inputs.htt.packages.${pkgs.system}.default
];
```
### Download the release ### Download the release
You can also [download the release binary.](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling/releases) You can also [download the release binary.](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling/releases)
@@ -76,7 +105,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 +118,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:
![wayland module showcase](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling/raw/branch/master/assets/waybar_module.gif) ![wayland module showcase](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling/raw/branch/master/assets/waybar_module.gif)
- `-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 ![the 1.4 changelog](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling/releases/tag/v1.4) 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 +135,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 ![the 1.4 changelog](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling/releases/tag/v1.4) 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.

37
default.nix Normal file
View File

@@ -0,0 +1,37 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.stdenv.mkDerivation rec {
pname = "hyprland-toggle-tiling";
version = "1.4.2";
src = pkgs.fetchFromGitHub {
owner = "TypoMustakes";
repo = "hyprland-toggle-tiling";
rev = "v${version}";
sha256 = "sha256-5mI5WiPjSU+/MgvTPNvE6Ck/WBnidaFwW9/xeL7MMWE=";
};
nativeBuildInputs = [
pkgs.cmake
pkgs.pkg-config
];
buildInputs = [
pkgs.hyprland
pkgs.nlohmann_json
];
cmakeFlags = [
"-DUSE_SYSTEM_JSON=ON"
];
cmakeBuildType = "Release";
meta = with pkgs.lib; {
description = "Toggle tiling and floating modes in Hyprland globally.";
homepage = "https://github.com/TypoMustakes/hyprland-toggle-tiling";
license = licenses.gpl3Only;
platforms = platforms.linux;
mainProgram = "htt";
};
}

27
flake.lock generated Normal file
View File

@@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1775710090,
"narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "4c1018dae018162ec878d42fec712642d214fdfa",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

20
flake.nix Normal file
View File

@@ -0,0 +1,20 @@
{
description = "hyprland-toggle-tiling";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in
{
packages.${system}.default = pkgs.callPackage ./default.nix {};
apps.${system}.default = {
type = "app";
program = "${self.packages.${system}.default}/bin/htt";
};
};
}

View File

@@ -23,7 +23,6 @@ class Client {
std::array<int, 2> size; std::array<int, 2> size;
WorkspaceSignature workspace; WorkspaceSignature workspace;
bool floating; bool floating;
bool pseudo;
int monitor; int monitor;
std::string className; std::string className;
std::string title; std::string title;
@@ -34,6 +33,7 @@ class Client {
bool pinned; bool pinned;
int fullscreen; int fullscreen;
int fullscreenClient; int fullscreenClient;
bool overFullscreen;
std::string swallowing; std::string swallowing;
int focusHistory; int focusHistory;
bool inhibitingIdle; bool inhibitingIdle;

View File

@@ -2,9 +2,9 @@
#define HYPRLAND_SERVICE_H #define HYPRLAND_SERVICE_H
#include <list> #include <list>
#include "Workspace.h" #include "Workspace.hpp"
#include "Client.h" #include "Client.hpp"
#include "WindowRule.h" #include "WindowRule.hpp"
class HyprlandService { class HyprlandService {
private: private:

View File

@@ -1,9 +0,0 @@
#ifndef MACROS_H
#define MACROS_H
#define HYPRCTL_BINARY "/usr/bin/hyprctl"
#define NULL_PATH "/dev/null"
#define ECHO_PATH "/usr/bin/echo"
#define CAT_PATH "/usr/bin/cat"
#endif

9
include/Macros.hpp Normal file
View File

@@ -0,0 +1,9 @@
#ifndef MACROS_H
#define MACROS_H
#define HYPRCTL_BINARY "hyprctl"
#define NULL_PATH "/dev/null"
#define ECHO_PATH "echo"
#define CAT_PATH "cat"
#endif

View File

@@ -1,4 +1,4 @@
#include "../include/Client.h" #include "../include/Client.hpp"
void from_json(const json& j, WorkspaceSignature& ws) { void from_json(const json& j, WorkspaceSignature& ws) {
j.at("id").get_to(ws.id); j.at("id").get_to(ws.id);
@@ -12,7 +12,6 @@ void from_json(const json& j, Client& client) {
j.at("size").get_to(client.size); j.at("size").get_to(client.size);
j.at("workspace").get_to(client.workspace); j.at("workspace").get_to(client.workspace);
j.at("floating").get_to(client.floating); j.at("floating").get_to(client.floating);
j.at("pseudo").get_to(client.pseudo);
j.at("monitor").get_to(client.monitor); j.at("monitor").get_to(client.monitor);
j.at("class").get_to(client.className); // Maps "class" JSON field to className j.at("class").get_to(client.className); // Maps "class" JSON field to className
j.at("title").get_to(client.title); j.at("title").get_to(client.title);
@@ -23,6 +22,7 @@ void from_json(const json& j, Client& client) {
j.at("pinned").get_to(client.pinned); j.at("pinned").get_to(client.pinned);
j.at("fullscreen").get_to(client.fullscreen); j.at("fullscreen").get_to(client.fullscreen);
j.at("fullscreenClient").get_to(client.fullscreenClient); j.at("fullscreenClient").get_to(client.fullscreenClient);
j.at("overFullscreen").get_to(client.overFullscreen);
j.at("swallowing").get_to(client.swallowing); j.at("swallowing").get_to(client.swallowing);
j.at("focusHistoryID").get_to(client.focusHistory); j.at("focusHistoryID").get_to(client.focusHistory);
j.at("inhibitingIdle").get_to(client.inhibitingIdle); j.at("inhibitingIdle").get_to(client.inhibitingIdle);

View File

@@ -1,8 +1,8 @@
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
#include "../include/FileService.h" #include "../include/FileService.hpp"
#include "../include/Macros.h" #include "../include/Macros.hpp"
#include "../include/ShellService.h" #include "../include/ShellService.hpp"
bool FileService::doesNonEmptyFileExist(std::string path) { bool FileService::doesNonEmptyFileExist(std::string path) {
std::ifstream file(path); std::ifstream file(path);
@@ -60,4 +60,4 @@ std::vector<std::string> FileService::readLines(std::string path) {
lines.push_back(line); lines.push_back(line);
} }
return lines; return lines;
}; };

View File

@@ -1,15 +1,17 @@
#include "../include/HyprlandService.hpp"
#include "../include/FileService.hpp"
#include "../include/Macros.hpp"
#include "../include/ShellService.hpp"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "../include/HyprlandService.h" #include <optional>
#include "../include/ShellService.h" #include <string>
#include "../include/Macros.h"
#include "../include/FileService.h"
using json = nlohmann::json; using json = nlohmann::json;
std::string HyprlandService::configFilePath; std::string HyprlandService::configFilePath;
void HyprlandService::setConfigFilePath(std::string path) { void HyprlandService::setConfigFilePath(std::string path) {
//Look for substring "~/". If found, expand it // Look for substring "~/". If found, expand it
const std::string tilde = "~/"; const std::string tilde = "~/";
size_t pos = path.find(tilde); size_t pos = path.find(tilde);
if (pos != std::string::npos) { if (pos != std::string::npos) {
@@ -18,15 +20,38 @@ void HyprlandService::setConfigFilePath(std::string path) {
configFilePath = path; configFilePath = path;
}; };
std::string HyprlandService::getConfigFilePath() { 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>>();
@@ -36,7 +61,7 @@ std::list<Client> HyprlandService::getClientsOnActiveWorkspace() {
std::list<Client> clients = getClients(); std::list<Client> clients = getClients();
int activeWorkspaceID = getCurrentWorkspace().id; int activeWorkspaceID = getCurrentWorkspace().id;
for (auto it = clients.begin(); it != clients.end(); ) { for (auto it = clients.begin(); it != clients.end();) {
if (it->workspace.id != activeWorkspaceID) { if (it->workspace.id != activeWorkspaceID) {
it = clients.erase(it); it = clients.erase(it);
} else { } else {
@@ -50,47 +75,42 @@ std::list<Client> HyprlandService::getClientsOnActiveWorkspace() {
std::list<WindowRule> HyprlandService::getWindowRules() { std::list<WindowRule> HyprlandService::getWindowRules() {
std::list<WindowRule> rules; std::list<WindowRule> rules;
for (auto& line : FileService::readLines(getConfigFilePath())) { for (auto &line : FileService::readLines(getConfigFilePath())) {
rules.push_back(WindowRule::parse(line)); rules.push_back(WindowRule::parse(line));
} }
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) { // on = true -> creates a window rule to ENABLE floating mode for currently
ShellService::exec(HYPRCTL_BINARY " dispatch togglefloating address:" + c.address); // active workspace on = false -> creates a window rule to DISABLE 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
void HyprlandService::setFloatingRule(bool on) { void HyprlandService::setFloatingRule(bool on) {
WindowRule rule {.tile = !on, .workspaceID = getCurrentWorkspace().id}; WindowRule rule{.tile = !on, .workspaceID = getCurrentWorkspace().id};
auto conflictingRule = findConflictingRule(rule); auto conflictingRule = findConflictingRule(rule);
if (conflictingRule.has_value()) { if (conflictingRule.has_value()) {
removeRule(conflictingRule.value()); removeRule(conflictingRule.value());
} }
FileService::appendToFile( FileService::appendToFile(getConfigFilePath(), rule.toString());
getConfigFilePath(),
rule.toString()
);
}; };
std::optional<WindowRule> HyprlandService::findConflictingRule(WindowRule subject) { std::optional<WindowRule>
HyprlandService::findConflictingRule(WindowRule subject) {
std::list<WindowRule> rules = getWindowRules(); std::list<WindowRule> rules = getWindowRules();
int id = getCurrentWorkspace().id; int id = getCurrentWorkspace().id;
for (auto& rule : rules) { for (auto &rule : rules) {
if (rule.tile == !subject.tile && rule.workspaceID == subject.workspaceID) if (rule.tile == !subject.tile && rule.workspaceID == subject.workspaceID) {
{
return rule; return rule;
} }
} }
@@ -103,9 +123,8 @@ void HyprlandService::removeRule(WindowRule rule) {
int index = 0; int index = 0;
int foundIndex = -1; int foundIndex = -1;
for (auto& it : rules) { for (auto &it : rules) {
if (it.toString() == rule.toString()) if (it.toString() == rule.toString()) {
{
foundIndex = index; foundIndex = index;
break; break;
} }
@@ -113,39 +132,63 @@ void HyprlandService::removeRule(WindowRule rule) {
} }
if (foundIndex != -1) { if (foundIndex != -1) {
FileService::deleteNthLine( FileService::deleteNthLine(getConfigFilePath(), foundIndex);
getConfigFilePath(),
foundIndex
);
} }
//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() {
std::list<WindowRule> rules = getWindowRules(); std::list<WindowRule> rules = getWindowRules();
int id = getCurrentWorkspace().id; int id = getCurrentWorkspace().id;
for (auto& rule : rules) { for (auto &rule : rules) {
if (rule.workspaceID == id) { if (rule.workspaceID == id) {
return rule; return rule;
} }
} }
//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);
}
}

View File

@@ -1,42 +1,43 @@
#include "../include/ShellService.h" #include "../include/ShellService.hpp"
#include <pwd.h> #include <pwd.h>
#include <unistd.h> #include <unistd.h>
std::string ShellService::exec(const std::string& command) { std::string ShellService::exec(const std::string &command) {
char buffer[128]; char buffer[128];
std::string result = ""; std::string result = "";
FILE* pipe = popen(command.c_str(), "r"); FILE *pipe = popen(command.c_str(), "r");
if (!pipe) { if (!pipe) {
return "popen failed"; return "popen failed";
} }
while (fgets(buffer, sizeof(buffer), pipe) != NULL) { while (fgets(buffer, sizeof(buffer), pipe) != NULL) {
result += buffer; result += buffer;
} }
int status = pclose(pipe); int status = pclose(pipe);
if (status == -1) { if (status == -1) {
return "Error closing pipe"; return "Error closing pipe";
} }
return result; return result;
}; };
std::string ShellService::getHomePath() std::string ShellService::getHomePath() {
{ char *home = getenv("HOME");
char* home = getenv("HOME");
if (home && *home) { if (home && *home) {
return std::string(home); return std::string(home) + std::string("/");
} }
// Fallback: try to get home directory from passwd if HOME is not set // Fallback: try to get home directory from passwd if HOME is not set
// This assumes that the 'htt' process is ran with the user as the process owner. Should it be run with systemd or some other wonky method, it will behave unexpectedly // This assumes that the 'htt' process is ran with the user as the process
struct passwd* pw = getpwuid(getuid()); // owner. Should it be run with systemd or some other wonky method, it will
// behave unexpectedly
struct passwd *pw = getpwuid(getuid());
if (pw && pw->pw_dir) { if (pw && pw->pw_dir) {
return std::string(pw->pw_dir); return std::string(pw->pw_dir);
} }
// As a last resort, exit // As a last resort, exit
exit(1); exit(1);
} }

View File

@@ -1,5 +1,5 @@
#include <algorithm> #include <algorithm>
#include "../include/WindowRule.h" #include "../include/WindowRule.hpp"
std::string WindowRule::toString() { std::string WindowRule::toString() {
std::string mode = this->tile ? "tile on" : "float on"; std::string mode = this->tile ? "tile on" : "float on";

View File

@@ -1,4 +1,4 @@
#include "../include/Workspace.h" #include "../include/Workspace.hpp"
void from_json(const nlohmann::json &j, Workspace &w) { void from_json(const nlohmann::json &j, Workspace &w) {
j.at("id").get_to(w.id); j.at("id").get_to(w.id);

View File

@@ -1,37 +1,36 @@
#include <iostream> #include <iostream>
#include "../include/HyprlandService.h" #include <stdexcept>
#include "../include/HyprlandService.hpp"
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")) {
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);
} }