Skip to content

Commit

Permalink
Merge pull request #65 from levnikmyskin/feat/listen_to_new_monitor_e…
Browse files Browse the repository at this point in the history
…vents

Listen to new pre/post monitor connection/disconnection events
  • Loading branch information
levnikmyskin authored Nov 21, 2024
2 parents 85957e2 + bc038f2 commit 863acc3
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 46 deletions.
2 changes: 1 addition & 1 deletion include/VirtualDeskManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class VirtualDeskManager {
int m_activeDeskKey = 1;
bool confLoaded = false;
void cycleWorkspaces();
CSharedPointer<CMonitor> getCurrentMonitor();
std::shared_ptr<VirtualDesk> getOrCreateVdesk(int vdeskId);
CSharedPointer<CMonitor> getFocusedMonitor();
};
#endif
8 changes: 4 additions & 4 deletions src/VirtualDeskManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ void VirtualDeskManager::applyCurrentVDesk() {
}
if (isVerbose())
printLog("applying vdesk" + activeVdesk()->name);
auto currentMonitor = getCurrentMonitor();
auto currentMonitor = getFocusedMonitor();
auto layout = activeVdesk()->activeLayout(conf);
PHLWORKSPACE focusedWorkspace = nullptr;
for (const auto& [lmon, workspaceId] : layout) {
Expand Down Expand Up @@ -177,7 +177,7 @@ void VirtualDeskManager::cycleWorkspaces() {
if (!**PCYCLEWORKSPACES)
return;

auto n_monitors = g_pCompositor->m_vMonitors.size();
auto n_monitors = g_pCompositor->m_vMonitors.size();
CSharedPointer<CMonitor> currentMonitor = g_pCompositor->m_pLastMonitor.lock();

// TODO: implement for more than two monitors as well.
Expand Down Expand Up @@ -280,7 +280,7 @@ void VirtualDeskManager::invalidateAllLayouts() {
}
}

CSharedPointer<CMonitor> VirtualDeskManager::getCurrentMonitor() {
CSharedPointer<CMonitor> VirtualDeskManager::getFocusedMonitor() {
CWeakPointer<CMonitor> currentMonitor = g_pCompositor->m_pLastMonitor;
// This can happen when we receive the "on disconnect" signal
// let's just take first monitor we can find
Expand All @@ -292,4 +292,4 @@ CSharedPointer<CMonitor> VirtualDeskManager::getCurrentMonitor() {
return nullptr;
}
return currentMonitor.lock();
}
}
97 changes: 56 additions & 41 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,20 @@

using namespace Hyprutils::Memory;

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);

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) {
static CSharedPointer<HOOK_CALLBACK_FN> onWorkspaceChangeHook = nullptr;
static CSharedPointer<HOOK_CALLBACK_FN> onWindowOpenHook = nullptr;
static CSharedPointer<HOOK_CALLBACK_FN> onConfigReloadedHook = nullptr;
static CSharedPointer<HOOK_CALLBACK_FN> onPreMonitorAddedHook = nullptr;
static CSharedPointer<HOOK_CALLBACK_FN> onMonitorAddedHook = nullptr;
static CSharedPointer<HOOK_CALLBACK_FN> onPreMonitorRemovedHook = nullptr;
static CSharedPointer<HOOK_CALLBACK_FN> onMonitorRemovedHook = nullptr;

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) {
size_t pos;
size_t delim;
std::string rule;
Expand Down Expand Up @@ -275,50 +274,71 @@ void resetVDeskDispatch(std::string arg) {
void onWorkspaceChange(void*, SCallbackInfo&, std::any val) {
if (monitorLayoutChanging)
return;
auto workspace = std::any_cast<PHLWORKSPACE>(val);
WORKSPACEID workspaceID = std::any_cast<PHLWORKSPACE>(val)->m_iID;
auto workspace = std::any_cast<PHLWORKSPACE>(val);
WORKSPACEID workspaceID = std::any_cast<PHLWORKSPACE>(val)->m_iID;

auto monitor = workspace->m_pMonitor.lock();
auto monitor = workspace->m_pMonitor.lock();
if (!monitor || !monitor->m_bEnabled)
return;

manager->activeVdesk()->changeWorkspaceOnMonitor(workspaceID, monitor);
if (isVerbose())
printLog("workspace changed: workspace id " + std::to_string(workspaceID) + "; on monitor " + std::to_string(monitor->ID));
if (isVerbose()) {
auto vdesk = manager->activeVdesk();
printLog("workspace changed on vdesk " + std::to_string(vdesk->id) + ": workspace id " + std::to_string(workspaceID) + "; on monitor " + std::to_string(monitor->ID));
}
}

void onWindowOpen(void*, SCallbackInfo&, std::any val) {
auto 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);
}

void hookMonitorDisconnect(void* thisptr, bool destroy) {
void onPreMonitorRemoved(void*, SCallbackInfo&, std::any val) {
CSharedPointer<CMonitor> monitor = std::any_cast<CSharedPointer<CMonitor>>(val);
if (monitor->szName == std::string("HEADLESS-1")) {
return;
}
if (isVerbose())
printLog("Monitor PRE disconnect called with disabled monitor " + monitor->szName);
monitorLayoutChanging = true;
(*(origMonitorDisconnect)g_pMonitorDisconnectHook->m_pOriginal)(thisptr, destroy);
monitorLayoutChanging = false;
}

CSharedPointer<CMonitor> monitor = CSharedPointer(static_cast<CMonitor*>(thisptr));
void onMonitorRemoved(void*, SCallbackInfo&, std::any val) {
CSharedPointer<CMonitor> monitor = std::any_cast<CSharedPointer<CMonitor>>(val);
if (monitor->szName == std::string("HEADLESS-1")) {
return;
}
if (isVerbose())
printLog("Monitor disconnect called with disabled monitor " + monitor->szName);
if (!currentlyEnabledMonitors(monitor).empty()) {
monitorLayoutChanging = false;
manager->invalidateAllLayouts();
manager->deleteInvalidMonitorsOnAllVdesks(monitor);
manager->applyCurrentVDesk();
StickyApps::matchRules(stickyRules, manager);
}
}

void hookMonitorConnect(void* thisptr, bool noRule) {
void onPreMonitorAdded(void*, SCallbackInfo&, std::any val) {
CSharedPointer<CMonitor> monitor = std::any_cast<CSharedPointer<CMonitor>>(val);
if (monitor->szName == std::string("HEADLESS-1")) {
return;
}
if (isVerbose())
printLog("Monitor PRE connect called with monitor " + monitor->szName);
monitorLayoutChanging = true;
(*(origMonitorConnect)g_pMonitorConnectHook->m_pOriginal)(thisptr, noRule);
monitorLayoutChanging = false;
}

CSharedPointer<CMonitor> monitor = CSharedPointer(static_cast<CMonitor*>(thisptr));
void onMonitorAdded(void*, SCallbackInfo&, std::any val) {
CSharedPointer<CMonitor> monitor = std::any_cast<CSharedPointer<CMonitor>>(val);
if (monitor->szName == std::string("HEADLESS-1")) {
return;
}
if (isVerbose())
printLog("Monitor connect called with monitor " + monitor->szName);
monitorLayoutChanging = false;
manager->invalidateAllLayouts();
manager->deleteInvalidMonitorsOnAllVdesks();
manager->applyCurrentVDesk();
Expand Down Expand Up @@ -402,18 +422,13 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
// Keywords
HyprlandAPI::addConfigKeyword(PHANDLE, STICKY_RULES_KEYW, parseStickyRule, Hyprlang::SHandlerOptions{});

onWorkspaceChangeHook = HyprlandAPI::registerCallbackDynamic(PHANDLE, "workspace", onWorkspaceChange);
onWindowOpenHook = HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", onWindowOpen);
onConfigReloadedHook = HyprlandAPI::registerCallbackDynamic(PHANDLE, "configReloaded", onConfigReloaded);

// Function hooks
static const auto METHODS_CONNECT = HyprlandAPI::findFunctionsByName(PHANDLE, "onConnect");
g_pMonitorConnectHook = HyprlandAPI::createFunctionHook(handle, METHODS_CONNECT[0].address, (void*)&hookMonitorConnect);
g_pMonitorConnectHook->hook();

static const auto METHODS_DISCONNECT = HyprlandAPI::findFunctionsByName(PHANDLE, "onDisconnect");
g_pMonitorDisconnectHook = HyprlandAPI::createFunctionHook(handle, METHODS_DISCONNECT[0].address, (void*)&hookMonitorDisconnect);
g_pMonitorDisconnectHook->hook();
onWorkspaceChangeHook = HyprlandAPI::registerCallbackDynamic(PHANDLE, "workspace", onWorkspaceChange);
onWindowOpenHook = HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", onWindowOpen);
onConfigReloadedHook = HyprlandAPI::registerCallbackDynamic(PHANDLE, "configReloaded", onConfigReloaded);
onPreMonitorAddedHook = HyprlandAPI::registerCallbackDynamic(PHANDLE, "preMonitorAdded", onPreMonitorAdded);
onPreMonitorRemovedHook = HyprlandAPI::registerCallbackDynamic(PHANDLE, "preMonitorRemoved", onPreMonitorRemoved);
onMonitorAddedHook = HyprlandAPI::registerCallbackDynamic(PHANDLE, "monitorAdded", onMonitorAdded);
onMonitorRemovedHook = HyprlandAPI::registerCallbackDynamic(PHANDLE, "monitorRemoved", onMonitorRemoved);

registerHyprctlCommands();

Expand Down

0 comments on commit 863acc3

Please sign in to comment.