Skip to content

Commit

Permalink
Merge pull request #41 from levnikmyskin/dev
Browse files Browse the repository at this point in the history
Hyprland 0.41.0
  • Loading branch information
levnikmyskin authored Jun 12, 2024
2 parents 8ca5fb7 + 0de606b commit fa70776
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 56 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ compile_flags.txt
compile_commands.json
.cache
result/
.idea
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Virtual desktops for Hyprland ![hyprico](.github/hyprland.ico)
`virtual-desktops` is a plugin for the [Hyprland](https://github.com/hyprwm/Hyprland) compositor. `virtual-desktops` manages multiple screens workspaces as if they were a single virtual desktop.

This plugin **only supports official releases of Hyprland** (e.g., v0.39.x, v0.40.x).
If you are on `hyprland-git`, please try compiling this plugin from the [dev branch](https://github.com/levnikmyskin/hyprland-virtual-desktops/tree/dev).
There is **NO GUARANTEE** that the plugin will compile succesfully on the latest Hyprland commit, but we try our best to keep it updated. Also, always check the [PR section](https://github.com/levnikmyskin/hyprland-virtual-desktops/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc),
as there might be a draft PR for the next Hyprland release, where you can check the status of development.
## WARNING
You are on the `dev` branch. This branch unconsistently gather updates and fixes to follow `hyprland-git`. By unconsistently, I mean that there is NO GUARANTEE that this branch will work with `hyprland-git` at any given time.
This plugin **DOES NOT** support `hyprland-git`, please refrain from opening issues if virtual-desktop does not compile with the latest commit on hyprland. Feel free to contribute to this branch via PRs though.


Feel free to join our [matrix room](https://matrix.to/#/#hypr-virtual-desktops:matrix.org)!

>>>>>>> main
## Table of contents
- [Virtual desktops for Hyprland ](#virtual-desktops-for-hyprland-)
Expand Down Expand Up @@ -121,6 +121,7 @@ Since version 2.2, this plugin exposes a couple of `hyprctl` commands. That is,
| Command | description | args | example|
|------------|-------------|------|--------|
| printdesk (vdesk)| Prints to Hyprland log the specified vdesk or the currently active vdesk* (if no argument is given) | optional vdesk, see [above](#hyprctl-dispatchers) | `hyprctl printdesk` or `hyprctl printdesk 2` or `hyprctl printdesk coding`|
| printstate | Prints state of all vdesks | `none` | `hyprctl printstate` |
| printlayout | print to Hyprland logs the current layout | `none` | `hyprctl printlayout` |


Expand Down
32 changes: 17 additions & 15 deletions include/VirtualDesk.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
#include "globals.hpp"
#include "utils.hpp"
#include <hyprland/src/Compositor.hpp>
#include <hyprland/src/helpers/memory/SharedPtr.hpp>

typedef std::unordered_map<int, int> WorkspaceMap;
// map with CMonitor* -> hyprland workspace id
typedef std::unordered_map<const CMonitor*, int> Layout;
typedef std::string MonitorName;

Expand All @@ -25,21 +27,21 @@ typedef std::string MonitorName;
class VirtualDesk {
public:
VirtualDesk(int id = 1, std::string name = "1");
int id;
std::string name;
std::vector<Layout> layouts;

const Layout& activeLayout(const RememberLayoutConf&, const CMonitor* exclude = nullptr);
Layout& searchActiveLayout(const RememberLayoutConf&, const CMonitor* exclude = nullptr);
std::unordered_set<std::string> setFromMonitors(const std::vector<std::shared_ptr<CMonitor>>&);
void changeWorkspaceOnMonitor(int, CMonitor*);
void invalidateActiveLayout();
void resetLayout();
CMonitor* deleteInvalidMonitor(const CMonitor*);
void deleteInvalidMonitorsOnActiveLayout();
void deleteInvalidMonitorOnAllLayouts(const CMonitor*);
static std::shared_ptr<CMonitor> firstAvailableMonitor(const std::vector<std::shared_ptr<CMonitor>>&);
bool isWorkspaceOnActiveLayout(int workspaceId);
int id;
std::string name;
std::vector<Layout> layouts;

const Layout& activeLayout(const RememberLayoutConf&, const CMonitor* exclude = nullptr);
Layout& searchActiveLayout(const RememberLayoutConf&, const CMonitor* exclude = nullptr);
std::unordered_set<std::string> setFromMonitors(const std::vector<CSharedPointer<CMonitor>>&);
void changeWorkspaceOnMonitor(int, CMonitor*);
void invalidateActiveLayout();
void resetLayout();
CMonitor* deleteInvalidMonitor(const CMonitor*);
void deleteInvalidMonitorsOnActiveLayout();
void deleteInvalidMonitorOnAllLayouts(const CMonitor*);
static CSharedPointer<CMonitor> firstAvailableMonitor(const std::vector<CSharedPointer<CMonitor>>&);
bool isWorkspaceOnActiveLayout(int workspaceId);

private:
int m_activeLayout_idx;
Expand Down
22 changes: 12 additions & 10 deletions include/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <hyprland/src/debug/Log.hpp>
#include "globals.hpp"
#include <hyprland/src/config/ConfigManager.hpp>
#include <hyprland/src/helpers/memory/SharedPtr.hpp>
#include <string>
#include <hyprland/src/Compositor.hpp>

Expand Down Expand Up @@ -36,6 +37,7 @@ const std::string BACKCYCLE_DISPATCH_STR = "backcyclevdesks";

const std::string RESET_VDESK_DISPATCH_STR = "vdeskreset";
const std::string PRINTDESK_DISPATCH_STR = "printdesk";
const std::string PRINTSTATE_DISPATCH_STR = "printstate";
const std::string PRINTLAYOUT_DISPATCH_STR = "printlayout";

const std::string REMEMBER_NONE = "none";
Expand All @@ -48,17 +50,17 @@ enum RememberLayoutConf {
monitors = 2
};

RememberLayoutConf layoutConfFromInt(const int64_t);
RememberLayoutConf layoutConfFromString(const std::string& conf);
void printLog(std::string s, LogLevel level = INFO);
RememberLayoutConf layoutConfFromInt(const int64_t);
RememberLayoutConf layoutConfFromString(const std::string& conf);
void printLog(std::string s, LogLevel level = INFO);

std::string parseMoveDispatch(std::string& arg);
bool extractBool(std::string& arg);
std::vector<std::shared_ptr<CMonitor>> currentlyEnabledMonitors(const CMonitor* exclude = nullptr);
std::string parseMoveDispatch(std::string& arg);
bool extractBool(std::string& arg);
std::vector<CSharedPointer<CMonitor>> currentlyEnabledMonitors(const CMonitor* exclude = nullptr);

std::string ltrim(const std::string& s);
std::string rtrim(const std::string& s);
std::string trim(const std::string& s);
std::string ltrim(const std::string& s);
std::string rtrim(const std::string& s);
std::string trim(const std::string& s);

bool isVerbose();
bool isVerbose();
#endif
8 changes: 4 additions & 4 deletions src/VirtualDesk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ void VirtualDesk::deleteInvalidMonitorsOnActiveLayout() {
}
}

std::shared_ptr<CMonitor> VirtualDesk::firstAvailableMonitor(const std::vector<std::shared_ptr<CMonitor>>& enabledMonitors) {
int n = INT_MAX;
std::shared_ptr<CMonitor> newMonitor;
CSharedPointer<CMonitor> VirtualDesk::firstAvailableMonitor(const std::vector<CSharedPointer<CMonitor>>& enabledMonitors) {
int n = INT_MAX;
CSharedPointer<CMonitor> newMonitor;
for (auto mon : currentlyEnabledMonitors()) {
auto n_on_mon = g_pCompositor->getWindowsOnWorkspace(mon->activeWorkspaceID());
if (n_on_mon < n) {
Expand Down Expand Up @@ -160,7 +160,7 @@ void VirtualDesk::checkAndAdaptLayout(Layout* layout, const CMonitor* exclude) {
}
}

std::unordered_set<std::string> VirtualDesk::setFromMonitors(const std::vector<std::shared_ptr<CMonitor>>& monitors) {
std::unordered_set<std::string> VirtualDesk::setFromMonitors(const std::vector<CSharedPointer<CMonitor>>& monitors) {
std::unordered_set<std::string> set;
std::transform(monitors.begin(), monitors.end(), std::inserter(set, set.begin()), [](auto mon) { return monitorDesc(mon.get()); });
return set;
Expand Down
10 changes: 5 additions & 5 deletions src/VirtualDeskManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ int VirtualDeskManager::moveToDesk(std::string& arg, int vdeskId) {
if (isVerbose())
printLog("creating new vdesk with id " + std::to_string(vdeskId));

auto vdesk = getOrCreateVdesk(vdeskId);
auto vdesk = getOrCreateVdesk(vdeskId);

PHLWINDOW window = g_pCompositor->getWindowByRegex(arg);
if (!window) {
Expand Down Expand Up @@ -178,7 +178,7 @@ void VirtualDeskManager::cycleWorkspaces() {
return;

auto n_monitors = g_pCompositor->m_vMonitors.size();
CMonitor* currentMonitor = g_pCompositor->m_pLastMonitor;
CMonitor* currentMonitor = g_pCompositor->m_pLastMonitor.get();

// TODO: implement for more than two monitors as well.
// This probably requires to compute monitors position
Expand Down Expand Up @@ -281,15 +281,15 @@ void VirtualDeskManager::invalidateAllLayouts() {
}

CMonitor* VirtualDeskManager::getCurrentMonitor() {
CMonitor* currentMonitor = g_pCompositor->m_pLastMonitor;
CMonitor* currentMonitor = g_pCompositor->m_pLastMonitor.get();
// This can happen when we receive the "on disconnect" signal
// let's just take first monitor we can find
if (currentMonitor && (!currentMonitor->m_bEnabled || !currentMonitor->output)) {
for (std::shared_ptr<CMonitor> mon : g_pCompositor->m_vMonitors) {
for (auto mon : g_pCompositor->m_vMonitors) {
if (mon->m_bEnabled && mon->output)
return mon.get();
}
return nullptr;
}
return currentMonitor;
}
}
91 changes: 77 additions & 14 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <hyprland/src/desktop/Workspace.hpp>
#include <hyprland/src/debug/Log.hpp>
#include <hyprland/src/events/Events.hpp>
#include <hyprland/src/helpers/memory/SharedPtr.hpp>

#include "globals.hpp"
#include "VirtualDeskManager.hpp"
Expand All @@ -14,21 +15,21 @@
#include <any>
#include <vector>

static std::shared_ptr<HOOK_CALLBACK_FN> onWorkspaceChangeHook = nullptr;
static std::shared_ptr<HOOK_CALLBACK_FN> onWindowOpenHook = nullptr;
static std::shared_ptr<HOOK_CALLBACK_FN> onConfigReloadedHook = nullptr;
static CSharedPointer<HOOK_CALLBACK_FN> onWorkspaceChangeHook = nullptr;
static CSharedPointer<HOOK_CALLBACK_FN> onWindowOpenHook = nullptr;
static CSharedPointer<HOOK_CALLBACK_FN> onConfigReloadedHook = nullptr;

inline CFunctionHook* g_pMonitorConnectHook = nullptr;
inline CFunctionHook* g_pMonitorDisconnectHook = nullptr;
typedef void (*origMonitorConnect)(void*, bool);
typedef void (*origMonitorDisconnect)(void*, bool);
inline CFunctionHook* g_pMonitorConnectHook = nullptr;
inline CFunctionHook* g_pMonitorDisconnectHook = nullptr;
typedef void (*origMonitorConnect)(void*, bool);
typedef void (*origMonitorDisconnect)(void*, bool);

std::unique_ptr<VirtualDeskManager> manager = std::make_unique<VirtualDeskManager>();
std::vector<StickyApps::SStickyRule> stickyRules;
bool notifiedInit = false;
bool monitorLayoutChanging = false;
std::unique_ptr<VirtualDeskManager> manager = std::make_unique<VirtualDeskManager>();
std::vector<StickyApps::SStickyRule> stickyRules;
bool notifiedInit = false;
bool monitorLayoutChanging = false;

void parseNamesConf(std::string& conf) {
void parseNamesConf(std::string& conf) {
size_t pos;
size_t delim;
std::string rule;
Expand Down Expand Up @@ -173,6 +174,60 @@ std::string printVDeskDispatch(eHyprCtlOutputFormat format, std::string arg) {
return "";
}

std::string printStateDispatch(eHyprCtlOutputFormat format, std::string arg) {
std::string out;
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
out += "Virtual desks\n";
int index = 0;
for(auto const& [vdeskId, desk] : manager->vdesksMap) {
unsigned int windows = 0;
std::string workspaces;
bool first = true;
for(auto const& [monitor, workspaceId] : desk->activeLayout(manager->conf)) {
windows += g_pCompositor->getWindowsOnWorkspace(workspaceId);
if(!first) workspaces += ", ";
else first = false;
workspaces += std::format("{}", workspaceId);
}
out += std::format(
"- {}: {}\n Focused: {}\n Populated: {}\n Workspaces: {}\n Windows: {}\n",
desk->name,
desk->id,
manager->activeVdesk().get() == desk.get(),
windows > 0,
workspaces,
windows
);
if(index++ < manager->vdesksMap.size() - 1) out += "\n";
}
} else if(format == eHyprCtlOutputFormat::FORMAT_JSON) {
std::string vdesks;
int index = 0;
for(auto const& [vdeskId, desk] : manager->vdesksMap) {
unsigned int windows = 0;
std::string workspaces;
bool first = true;
for(auto const& [monitor, workspaceId] : desk->activeLayout(manager->conf)) {
windows += g_pCompositor->getWindowsOnWorkspace(workspaceId);
if(!first) workspaces += ", ";
else first = false;
workspaces += std::format("{}", workspaceId);
}
vdesks += std::format(R"#({{
"id": {},
"name": "{}",
"focused": {},
"populated": {},
"workspaces": [{}],
"windows": {}
}})#", vdeskId, desk->name, manager->activeVdesk().get() == desk.get(), windows > 0, workspaces, windows);
if(index++ < manager->vdesksMap.size() - 1) vdesks += ",";
}
out += std::format(R"#([{}])#", vdesks);
}
return out;
}

std::string printLayoutDispatch(eHyprCtlOutputFormat format, std::string arg) {
auto activeDesk = manager->activeVdesk();
auto layout = activeDesk->activeLayout(manager->conf);
Expand Down Expand Up @@ -233,7 +288,7 @@ void onWorkspaceChange(void*, SCallbackInfo&, std::any val) {

void onWindowOpen(void*, SCallbackInfo&, std::any val) {
PHLWINDOW window = std::any_cast<PHLWINDOW>(val);
int vdesk = StickyApps::matchRuleOnWindow(stickyRules, manager, window);
int vdesk = StickyApps::matchRuleOnWindow(stickyRules, manager, window);
if (vdesk > 0)
manager->changeActiveDesk(vdesk, true);
}
Expand Down Expand Up @@ -292,13 +347,21 @@ void registerHyprctlCommands() {
if (!ptr)
printLog(std::format("Failed to register hyprctl command: {}", PRINTLAYOUT_DISPATCH_STR));

// Register printstate
cmd.name = PRINTSTATE_DISPATCH_STR;
cmd.fn = printStateDispatch;
cmd.exact = true;
ptr = HyprlandAPI::registerHyprCtlCommand(PHANDLE, cmd);
if (!ptr)
printLog(std::format("Failed to register hyprctl command: {}", PRINTSTATE_DISPATCH_STR));

// Register printdesk
cmd.name = PRINTDESK_DISPATCH_STR;
cmd.fn = printVDeskDispatch;
cmd.exact = false;
ptr = HyprlandAPI::registerHyprCtlCommand(PHANDLE, cmd);
if (!ptr)
printLog(std::format("Failed to register hyprctl command: {}", VDESK_DISPATCH_STR));
printLog(std::format("Failed to register hyprctl command: {}", PRINTDESK_DISPATCH_STR));
}

// Do NOT change this function.
Expand Down
4 changes: 2 additions & 2 deletions src/sticky_apps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ int StickyApps::matchRuleOnWindow(const std::vector<SStickyRule>& rules, std::un

const std::string StickyApps::extractProperty(const SStickyRule& rule, PHLWINDOW window) {
if (rule.property == TITLE) {
return g_pXWaylandManager->getTitle(window);
return window->m_szTitle;
} else if (rule.property == INITIAL_TITLE) {
return window->m_szInitialTitle;
} else if (rule.property == CLASS) {
return g_pXWaylandManager->getAppIDClass(window);
return window->m_szClass;
} else if (rule.property == INITIAL_CLASS) {
return window->m_szInitialClass;
}
Expand Down
4 changes: 2 additions & 2 deletions src/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ bool isVerbose() {
return **PVERBOSELOGS;
}

std::vector<std::shared_ptr<CMonitor>> currentlyEnabledMonitors(const CMonitor* exclude) {
std::vector<std::shared_ptr<CMonitor>> monitors;
std::vector<CSharedPointer<CMonitor>> currentlyEnabledMonitors(const CMonitor* exclude) {
std::vector<CSharedPointer<CMonitor>> monitors;
std::copy_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), std::back_inserter(monitors), [&](auto mon) {
if (g_pCompositor->m_pUnsafeOutput && g_pCompositor->m_pUnsafeOutput->szName == mon->szName)
return false;
Expand Down

0 comments on commit fa70776

Please sign in to comment.