mirror of
https://github.com/Trensa-Organization/split-monitor-workspaces.git
synced 2025-03-15 19:23:39 +01:00
Initial commit
This commit is contained in:
commit
e3f4e050ce
6 changed files with 228 additions and 0 deletions
14
.clang-format
Normal file
14
.clang-format
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
BreakBeforeBraces: Stroustrup
|
||||||
|
TabWidth: 4
|
||||||
|
IndentWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
IndentCaseLabels: true
|
||||||
|
ColumnLimit: 200
|
||||||
|
PointerAlignment: Left
|
||||||
|
AllowShortBlocksOnASingleLine: Empty
|
||||||
|
AllowShortEnumsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*.so
|
||||||
|
compile_flags.txt
|
28
Makefile
Normal file
28
Makefile
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# compile with HYPRLAND_HEADERS=<path_to_hl> make all
|
||||||
|
# make sure that the path above is to the root hl repo directory, NOT src/
|
||||||
|
# and that you have ran `make protocols` in the hl dir.
|
||||||
|
|
||||||
|
PLUGIN_NAME=split-monitor-workspaces
|
||||||
|
|
||||||
|
SOURCE_FILES=$(wildcard src/*.cpp)
|
||||||
|
|
||||||
|
.PHONY: clean clangd
|
||||||
|
|
||||||
|
all: check_env $(PLUGIN_NAME).so
|
||||||
|
|
||||||
|
install: all
|
||||||
|
cp $(PLUGIN_NAME).so ${HOME}/.local/share/hyprload/plugins/bin
|
||||||
|
|
||||||
|
check_env:
|
||||||
|
ifndef HYPRLAND_HEADERS
|
||||||
|
$(error HYPRLAND_HEADERS is undefined! Please set it to the path to the root of the configured Hyprland repo)
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(PLUGIN_NAME).so: $(SOURCE_FILES) $(INCLUDE_FILES)
|
||||||
|
g++ -shared -fPIC --no-gnu-unique $(SOURCE_FILES) -o $(PLUGIN_NAME).so -g -I "/usr/include/pixman-1" -I "/usr/include/libdrm" -I "${HYPRLAND_HEADERS}" -Iinclude -std=c++23
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm ./examplePlugin.so
|
||||||
|
|
||||||
|
clangd:
|
||||||
|
printf "%b" "-I/usr/include/pixman-1\n-I/usr/include/libdrm\n-I${HYPRLAND_HEADERS}\n-Iinclude\n-std=c++2b" > compile_flags.txt
|
43
README.md
Normal file
43
README.md
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
# split-monitor-workspaces
|
||||||
|
A small plugin to provide `awesome`/`dwm`-like behavior with workspaces: split them between monitors and provide independent numbering
|
||||||
|
|
||||||
|
# Installing
|
||||||
|
Since Hyprland plugins don't have ABI guarantees, you *should* download the Hyprland source and compile it if you plan to use plugins.
|
||||||
|
This ensures the compiler version is the same between the Hyprland build you're running, and the plugins you are using.
|
||||||
|
|
||||||
|
The guide on compiling and installing Hyprland manually is on the [wiki](http://wiki.hyprland.org/Getting-Started/Installation/#manual-manual-build)
|
||||||
|
|
||||||
|
## Using [hyprload](https://github.com/Duckonaut/hyprload)
|
||||||
|
1. Export the `HYPRLAND_HEADERS` variable to point to the root directory of the Hyprland repo
|
||||||
|
- `export HYPRLAND_HEADERS="$HOME/repos/Hyprland"`
|
||||||
|
2. Install
|
||||||
|
- `make install`
|
||||||
|
|
||||||
|
## Manual installation
|
||||||
|
1. Export the `HYPRLAND_HEADERS` variable to point to the root directory of the Hyprland repo
|
||||||
|
- `export HYPRLAND_HEADERS="$HOME/repos/Hyprland"`
|
||||||
|
2. Compile
|
||||||
|
- `make all`
|
||||||
|
3. Add this line to the bottom of your hyprland config
|
||||||
|
- `exec-once=hyprctl plugin load <ABSOLUTE PATH TO split-monitor-workspaces.so>`
|
||||||
|
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
The plugin provides drop-in replacements for workspace-related commands
|
||||||
|
| Normal | Replacement |
|
||||||
|
|-----------------------|-------------------------------|
|
||||||
|
| workspace | split-workspace |
|
||||||
|
| movetoworkspace | split-movetoworkspace |
|
||||||
|
| movetoworkspacesilent | split-movetoworkspacesilent |
|
||||||
|
|
||||||
|
It also provides the following config values
|
||||||
|
| Name | Type | Default | Description |
|
||||||
|
|-------------------------------------------|-----------|-----------|-----------------------------------------------|
|
||||||
|
| `plugin:split-monitor-workspaces:count` | int | 10 | How many workspaces to bind to the monitor |
|
||||||
|
|
||||||
|
Keep in mind that if you're using, for example, the `wlr/workspaces` widgets in [waybar](https://github.com/Alexays/Waybar), this will require a change to your config. You should set `all-outputs` to `false`, and adjust the icon mapping.
|
||||||
|
|
||||||
|
If your workspace-per-monitor count is 10, the first monitor will have workspaces 1-10, the second 11-20 and so on. They will be accessed via numbers 1-10 while your mouse is on a given monitor.
|
||||||
|
|
||||||
|
# Special thanks
|
||||||
|
- [hyprsome](https://github.com/sopa0/hyprsome): An earlier project of similar nature
|
5
include/globals.hpp
Normal file
5
include/globals.hpp
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <src/plugins/PluginAPI.hpp>
|
||||||
|
|
||||||
|
inline HANDLE PHANDLE = nullptr;
|
136
src/main.cpp
Normal file
136
src/main.cpp
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
#define WLR_USE_UNSTABLE
|
||||||
|
#include "src/helpers/Color.hpp"
|
||||||
|
#include "src/managers/KeybindManager.hpp"
|
||||||
|
|
||||||
|
#include "globals.hpp"
|
||||||
|
|
||||||
|
#include <src/Compositor.hpp>
|
||||||
|
#include <src/config/ConfigManager.hpp>
|
||||||
|
#include <src/helpers/Workspace.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
|
#include <thread>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
const std::string s_workspaceCount = "plugin:split-monitor-workspaces:count";
|
||||||
|
const CColor s_pluginColor = {0x61 / 255.0f, 0xAF / 255.0f, 0xEF / 255.0f, 1.0f};
|
||||||
|
|
||||||
|
std::map<uint64_t, std::vector<std::string>> g_vMonitorWorkspaceMap;
|
||||||
|
|
||||||
|
static HOOK_CALLBACK_FN* e_monitorAddedHandle = nullptr;
|
||||||
|
static HOOK_CALLBACK_FN* e_monitorRemovedHandle = nullptr;
|
||||||
|
|
||||||
|
const std::string& getWorkspaceFromMonitor(CMonitor* monitor, const std::string& workspace)
|
||||||
|
{
|
||||||
|
int workspaceIndex = std::stoi(workspace);
|
||||||
|
if (workspaceIndex - 1 < 0) {
|
||||||
|
return workspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workspaceIndex - 1 >= g_vMonitorWorkspaceMap[monitor->ID].size()) {
|
||||||
|
return workspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_vMonitorWorkspaceMap[monitor->ID][workspaceIndex - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void monitorWorkspace(std::string workspace)
|
||||||
|
{
|
||||||
|
CMonitor* monitor = g_pCompositor->getMonitorFromCursor();
|
||||||
|
int workspaceCount = HyprlandAPI::getConfigValue(PHANDLE, s_workspaceCount)->intValue;
|
||||||
|
|
||||||
|
HyprlandAPI::invokeHyprctlCommand("dispatch", "workspace " + getWorkspaceFromMonitor(monitor, workspace));
|
||||||
|
}
|
||||||
|
|
||||||
|
void monitorMoveToWorkspace(std::string workspace)
|
||||||
|
{
|
||||||
|
CMonitor* monitor = g_pCompositor->getMonitorFromCursor();
|
||||||
|
int workspaceCount = HyprlandAPI::getConfigValue(PHANDLE, s_workspaceCount)->intValue;
|
||||||
|
|
||||||
|
HyprlandAPI::invokeHyprctlCommand("dispatch", "movetoworkspace " + getWorkspaceFromMonitor(monitor, workspace));
|
||||||
|
}
|
||||||
|
|
||||||
|
void monitorMoveToWorkspaceSilent(std::string workspace)
|
||||||
|
{
|
||||||
|
CMonitor* monitor = g_pCompositor->getMonitorFromCursor();
|
||||||
|
int workspaceCount = HyprlandAPI::getConfigValue(PHANDLE, s_workspaceCount)->intValue;
|
||||||
|
|
||||||
|
HyprlandAPI::invokeHyprctlCommand("dispatch", "movetoworkspacesilent " + getWorkspaceFromMonitor(monitor, workspace));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mapWorkspacesToMonitors()
|
||||||
|
{
|
||||||
|
g_vMonitorWorkspaceMap.clear();
|
||||||
|
|
||||||
|
int workspaceIndex = 1;
|
||||||
|
|
||||||
|
for (auto& monitor : g_pCompositor->m_vMonitors) {
|
||||||
|
int workspaceCount = g_pConfigManager->getConfigValuePtrSafe(s_workspaceCount)->intValue;
|
||||||
|
std::string logMessage =
|
||||||
|
"[split-monitor-workspaces] Mapping workspaces " + std::to_string(workspaceIndex) + "-" + std::to_string(workspaceIndex + workspaceCount - 1) + " to monitor " + monitor->szName;
|
||||||
|
|
||||||
|
HyprlandAPI::addNotification(PHANDLE, logMessage, s_pluginColor, 5000);
|
||||||
|
|
||||||
|
for (int i = workspaceIndex; i < workspaceIndex + workspaceCount; i++) {
|
||||||
|
std::string workspaceName = std::to_string(i);
|
||||||
|
g_vMonitorWorkspaceMap[monitor->ID].push_back(workspaceName);
|
||||||
|
HyprlandAPI::invokeHyprctlCommand("keyword", "wsbind " + workspaceName + "," + monitor->szName);
|
||||||
|
CWorkspace* workspace = g_pCompositor->getWorkspaceByName(workspaceName);
|
||||||
|
|
||||||
|
if (workspace != nullptr) {
|
||||||
|
g_pCompositor->moveWorkspaceToMonitor(workspace, monitor.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
workspaceIndex += workspaceCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void refreshMapping(void*, std::any value)
|
||||||
|
{
|
||||||
|
mapWorkspacesToMonitors();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do NOT change this function.
|
||||||
|
APICALL EXPORT std::string PLUGIN_API_VERSION()
|
||||||
|
{
|
||||||
|
return HYPRLAND_API_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle)
|
||||||
|
{
|
||||||
|
PHANDLE = handle;
|
||||||
|
|
||||||
|
HyprlandAPI::addConfigValue(PHANDLE, s_workspaceCount, SConfigValue{.intValue = 10});
|
||||||
|
|
||||||
|
HyprlandAPI::addDispatcher(PHANDLE, "split-workspace", monitorWorkspace);
|
||||||
|
HyprlandAPI::addDispatcher(PHANDLE, "split-movetoworkspace", monitorMoveToWorkspace);
|
||||||
|
HyprlandAPI::addDispatcher(PHANDLE, "split-movetoworkspacesilent", monitorMoveToWorkspaceSilent);
|
||||||
|
|
||||||
|
HyprlandAPI::reloadConfig();
|
||||||
|
|
||||||
|
mapWorkspacesToMonitors();
|
||||||
|
|
||||||
|
HyprlandAPI::addNotification(PHANDLE, "[split-monitor-workspaces] Initialized successfully!", s_pluginColor, 5000);
|
||||||
|
|
||||||
|
e_monitorAddedHandle = HyprlandAPI::registerCallbackDynamic(PHANDLE, "monitorAdded", refreshMapping);
|
||||||
|
e_monitorRemovedHandle = HyprlandAPI::registerCallbackDynamic(PHANDLE, "monitorRemoved", refreshMapping);
|
||||||
|
|
||||||
|
return {"split-monitor-workspaces", "Split monitor workspace namespaces", "Duckonaut", "1.0"};
|
||||||
|
}
|
||||||
|
|
||||||
|
APICALL EXPORT void PLUGIN_EXIT()
|
||||||
|
{
|
||||||
|
HyprlandAPI::removeDispatcher(PHANDLE, "split-workspace");
|
||||||
|
HyprlandAPI::removeDispatcher(PHANDLE, "split-movetoworkspace");
|
||||||
|
HyprlandAPI::removeDispatcher(PHANDLE, "split-movetoworkspacesilent");
|
||||||
|
|
||||||
|
HyprlandAPI::unregisterCallback(PHANDLE, e_monitorAddedHandle);
|
||||||
|
HyprlandAPI::unregisterCallback(PHANDLE, e_monitorRemovedHandle);
|
||||||
|
|
||||||
|
HyprlandAPI::addNotification(PHANDLE, "[split-monitor-workspaces] Unloaded successfully!", s_pluginColor, 5000);
|
||||||
|
|
||||||
|
g_vMonitorWorkspaceMap.clear();
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue