Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e980df23f | |||
| 296dc33ae4 | |||
| 7a6203a77b | |||
| 095c242fcf | |||
| c2c695ff45 | |||
| 1f1b60c975 | |||
| 0d453ab86b | |||
| f7516518e0 | |||
| 9c821d3e7b | |||
| 468daecbe9 | |||
| 982336be7c | |||
| 44bcbda690 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
.cache/
|
||||
build/
|
||||
.vscode/
|
||||
.vscode/
|
||||
result
|
||||
|
||||
@@ -1,17 +1,69 @@
|
||||
cmake_minimum_required(VERSION 3.10.0)
|
||||
project(hyprland-toggle-tiling VERSION 0.1.0 LANGUAGES C CXX)
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(hyprland-toggle-tiling
|
||||
VERSION 1.4.2
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
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
|
||||
src/main.cpp
|
||||
src/HyprlandService.cpp
|
||||
src/Workspace.cpp
|
||||
src/ShellService.cpp
|
||||
src/FileService.cpp
|
||||
src/WindowRule.cpp
|
||||
src/Client.cpp)
|
||||
target_link_libraries(htt PRIVATE nlohmann_json::nlohmann_json)
|
||||
target_include_directories(htt PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
src/main.cpp
|
||||
src/HyprlandService.cpp
|
||||
src/Workspace.cpp
|
||||
src/ShellService.cpp
|
||||
src/FileService.cpp
|
||||
src/WindowRule.cpp
|
||||
src/Client.cpp
|
||||
)
|
||||
|
||||
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}
|
||||
)
|
||||
|
||||
81
README.md
81
README.md
@@ -29,6 +29,8 @@ 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.
|
||||
- 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.
|
||||
- Lightweight and easy to integrate with your Hyprland setup.
|
||||
|
||||
@@ -40,9 +42,37 @@ 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)
|
||||
|
||||
### 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
|
||||
|
||||
You can also [download the release binary.](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling/releases/tag/1.1.0)
|
||||
You can also [download the release binary.](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling/releases)
|
||||
|
||||
or go nuts and...
|
||||
|
||||
@@ -75,8 +105,21 @@ or go nuts and...
|
||||
|
||||
# Usage
|
||||
```shell
|
||||
./htt <config-file-path>
|
||||
./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:
|
||||
|
||||
```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:
|
||||

|
||||
|
||||
- `-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 configuration contains existing rules, this should still work, but your existing configuration will probably get a bit messy, syntax-wise. I advise against it.
|
||||
|
||||
@@ -92,5 +135,37 @@ or go nuts and...
|
||||
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.
|
||||
|
||||
|
||||
BIN
assets/waybar_module.gif
Normal file
BIN
assets/waybar_module.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
37
default.nix
Normal file
37
default.nix
Normal 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
27
flake.lock
generated
Normal 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
20
flake.nix
Normal 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";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -23,7 +23,6 @@ class Client {
|
||||
std::array<int, 2> size;
|
||||
WorkspaceSignature workspace;
|
||||
bool floating;
|
||||
bool pseudo;
|
||||
int monitor;
|
||||
std::string className;
|
||||
std::string title;
|
||||
@@ -34,6 +33,7 @@ class Client {
|
||||
bool pinned;
|
||||
int fullscreen;
|
||||
int fullscreenClient;
|
||||
bool overFullscreen;
|
||||
std::string swallowing;
|
||||
int focusHistory;
|
||||
bool inhibitingIdle;
|
||||
@@ -2,26 +2,36 @@
|
||||
#define HYPRLAND_SERVICE_H
|
||||
|
||||
#include <list>
|
||||
#include "Workspace.h"
|
||||
#include "Client.h"
|
||||
#include "WindowRule.h"
|
||||
#include "Workspace.hpp"
|
||||
#include "Client.hpp"
|
||||
#include "WindowRule.hpp"
|
||||
|
||||
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
|
||||
@@ -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
9
include/Macros.hpp
Normal 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
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../include/Client.h"
|
||||
#include "../include/Client.hpp"
|
||||
|
||||
void from_json(const json& j, WorkspaceSignature& ws) {
|
||||
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("workspace").get_to(client.workspace);
|
||||
j.at("floating").get_to(client.floating);
|
||||
j.at("pseudo").get_to(client.pseudo);
|
||||
j.at("monitor").get_to(client.monitor);
|
||||
j.at("class").get_to(client.className); // Maps "class" JSON field to className
|
||||
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("fullscreen").get_to(client.fullscreen);
|
||||
j.at("fullscreenClient").get_to(client.fullscreenClient);
|
||||
j.at("overFullscreen").get_to(client.overFullscreen);
|
||||
j.at("swallowing").get_to(client.swallowing);
|
||||
j.at("focusHistoryID").get_to(client.focusHistory);
|
||||
j.at("inhibitingIdle").get_to(client.inhibitingIdle);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include "../include/FileService.h"
|
||||
#include "../include/Macros.h"
|
||||
#include "../include/ShellService.h"
|
||||
#include "../include/FileService.hpp"
|
||||
#include "../include/Macros.hpp"
|
||||
#include "../include/ShellService.hpp"
|
||||
|
||||
bool FileService::doesNonEmptyFileExist(std::string path) {
|
||||
std::ifstream file(path);
|
||||
@@ -60,4 +60,4 @@ std::vector<std::string> FileService::readLines(std::string path) {
|
||||
lines.push_back(line);
|
||||
}
|
||||
return lines;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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 "../include/HyprlandService.h"
|
||||
#include "../include/ShellService.h"
|
||||
#include "../include/Macros.h"
|
||||
#include "../include/FileService.h"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
std::string HyprlandService::configFilePath;
|
||||
|
||||
void HyprlandService::setConfigFilePath(std::string path) {
|
||||
//Look for substring "~/". If found, expand it
|
||||
// Look for substring "~/". If found, expand it
|
||||
const std::string tilde = "~/";
|
||||
size_t pos = path.find(tilde);
|
||||
if (pos != std::string::npos) {
|
||||
@@ -18,15 +20,38 @@ void HyprlandService::setConfigFilePath(std::string path) {
|
||||
configFilePath = path;
|
||||
};
|
||||
|
||||
std::string HyprlandService::getConfigFilePath() {
|
||||
return configFilePath;
|
||||
};
|
||||
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"));
|
||||
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>>();
|
||||
@@ -36,7 +61,7 @@ std::list<Client> HyprlandService::getClientsOnActiveWorkspace() {
|
||||
std::list<Client> clients = getClients();
|
||||
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) {
|
||||
it = clients.erase(it);
|
||||
} else {
|
||||
@@ -50,47 +75,42 @@ std::list<Client> HyprlandService::getClientsOnActiveWorkspace() {
|
||||
std::list<WindowRule> HyprlandService::getWindowRules() {
|
||||
std::list<WindowRule> rules;
|
||||
|
||||
for (auto& line : FileService::readLines(getConfigFilePath())) {
|
||||
for (auto &line : FileService::readLines(getConfigFilePath())) {
|
||||
rules.push_back(WindowRule::parse(line));
|
||||
}
|
||||
|
||||
return rules;
|
||||
};
|
||||
|
||||
void HyprlandService::setClientFloating(Client& c) {
|
||||
ShellService::exec(HYPRCTL_BINARY " dispatch setfloating address:" + c.address);
|
||||
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
|
||||
// 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) {
|
||||
WindowRule rule {.tile = !on, .workspaceID = getCurrentWorkspace().id};
|
||||
WindowRule rule{.tile = !on, .workspaceID = getCurrentWorkspace().id};
|
||||
auto conflictingRule = findConflictingRule(rule);
|
||||
if (conflictingRule.has_value()) {
|
||||
removeRule(conflictingRule.value());
|
||||
}
|
||||
|
||||
FileService::appendToFile(
|
||||
getConfigFilePath(),
|
||||
rule.toString()
|
||||
);
|
||||
FileService::appendToFile(getConfigFilePath(), rule.toString());
|
||||
};
|
||||
|
||||
std::optional<WindowRule> HyprlandService::findConflictingRule(WindowRule subject) {
|
||||
std::optional<WindowRule>
|
||||
HyprlandService::findConflictingRule(WindowRule subject) {
|
||||
std::list<WindowRule> rules = getWindowRules();
|
||||
int id = getCurrentWorkspace().id;
|
||||
|
||||
for (auto& rule : rules) {
|
||||
if (rule.tile == !subject.tile && rule.workspaceID == subject.workspaceID)
|
||||
{
|
||||
for (auto &rule : rules) {
|
||||
if (rule.tile == !subject.tile && rule.workspaceID == subject.workspaceID) {
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
@@ -103,9 +123,8 @@ void HyprlandService::removeRule(WindowRule rule) {
|
||||
int index = 0;
|
||||
int foundIndex = -1;
|
||||
|
||||
for (auto& it : rules) {
|
||||
if (it.toString() == rule.toString())
|
||||
{
|
||||
for (auto &it : rules) {
|
||||
if (it.toString() == rule.toString()) {
|
||||
foundIndex = index;
|
||||
break;
|
||||
}
|
||||
@@ -113,25 +132,63 @@ void HyprlandService::removeRule(WindowRule rule) {
|
||||
}
|
||||
|
||||
if (foundIndex != -1) {
|
||||
FileService::deleteNthLine(
|
||||
getConfigFilePath(),
|
||||
foundIndex
|
||||
);
|
||||
FileService::deleteNthLine(getConfigFilePath(), foundIndex);
|
||||
}
|
||||
|
||||
//else: rule not found, do nothing
|
||||
// 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) {
|
||||
for (auto &rule : rules) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,43 @@
|
||||
#include "../include/ShellService.h"
|
||||
#include "../include/ShellService.hpp"
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
std::string ShellService::exec(const std::string& command) {
|
||||
std::string ShellService::exec(const std::string &command) {
|
||||
char buffer[128];
|
||||
std::string result = "";
|
||||
|
||||
FILE* pipe = popen(command.c_str(), "r");
|
||||
FILE *pipe = popen(command.c_str(), "r");
|
||||
if (!pipe) {
|
||||
return "popen failed";
|
||||
return "popen failed";
|
||||
}
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), pipe) != NULL) {
|
||||
result += buffer;
|
||||
result += buffer;
|
||||
}
|
||||
|
||||
int status = pclose(pipe);
|
||||
if (status == -1) {
|
||||
return "Error closing pipe";
|
||||
return "Error closing pipe";
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
std::string ShellService::getHomePath()
|
||||
{
|
||||
char* home = getenv("HOME");
|
||||
std::string ShellService::getHomePath() {
|
||||
char *home = getenv("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
|
||||
// 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
|
||||
struct passwd* pw = getpwuid(getuid());
|
||||
// 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
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
if (pw && pw->pw_dir) {
|
||||
return std::string(pw->pw_dir);
|
||||
return std::string(pw->pw_dir);
|
||||
}
|
||||
|
||||
// As a last resort, exit
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <algorithm>
|
||||
#include "../include/WindowRule.h"
|
||||
#include "../include/WindowRule.hpp"
|
||||
|
||||
std::string WindowRule::toString() {
|
||||
std::string mode = this->tile ? "tile on" : "float on";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../include/Workspace.h"
|
||||
#include "../include/Workspace.hpp"
|
||||
|
||||
void from_json(const nlohmann::json &j, Workspace &w) {
|
||||
j.at("id").get_to(w.id);
|
||||
|
||||
45
src/main.cpp
45
src/main.cpp
@@ -1,23 +1,36 @@
|
||||
#include <iostream>
|
||||
#include "../include/HyprlandService.h"
|
||||
#include <stdexcept>
|
||||
#include "../include/HyprlandService.hpp"
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
HyprlandService::setConfigFilePath(argv[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);
|
||||
}
|
||||
HyprlandService::setFloatingRule(false);
|
||||
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 {
|
||||
for (auto& c : HyprlandService::getClientsOnActiveWorkspace()) {
|
||||
HyprlandService::setClientFloating(c);
|
||||
}
|
||||
HyprlandService::setFloatingRule(true);
|
||||
help(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user