This commit is contained in:
vaxerski 2023-09-02 19:36:57 +02:00
parent ee577b571c
commit f8a847109e
5 changed files with 320 additions and 3 deletions

View file

@ -203,6 +203,10 @@ void CPortalManager::onGlobal(void* data, struct wl_registry* registry, uint32_t
if (INTERFACE == zwlr_screencopy_manager_v1_interface.name && m_sPipewire.loop) if (INTERFACE == zwlr_screencopy_manager_v1_interface.name && m_sPipewire.loop)
m_sPortals.screencopy = std::make_unique<CScreencopyPortal>((zwlr_screencopy_manager_v1*)wl_registry_bind(registry, name, &zwlr_screencopy_manager_v1_interface, version)); m_sPortals.screencopy = std::make_unique<CScreencopyPortal>((zwlr_screencopy_manager_v1*)wl_registry_bind(registry, name, &zwlr_screencopy_manager_v1_interface, version));
if (INTERFACE == hyprland_global_shortcuts_manager_v1_interface.name)
m_sPortals.globalShortcuts = std::make_unique<CGlobalShortcutsPortal>(
(hyprland_global_shortcuts_manager_v1*)wl_registry_bind(registry, name, &hyprland_global_shortcuts_manager_v1_interface, version));
else if (INTERFACE == hyprland_toplevel_export_manager_v1_interface.name) else if (INTERFACE == hyprland_toplevel_export_manager_v1_interface.name)
m_sWaylandConnection.hyprlandToplevelMgr = wl_registry_bind(registry, name, &hyprland_toplevel_export_manager_v1_interface, version); m_sWaylandConnection.hyprlandToplevelMgr = wl_registry_bind(registry, name, &hyprland_toplevel_export_manager_v1_interface, version);

View file

@ -5,6 +5,7 @@
#include <wayland-client.h> #include <wayland-client.h>
#include "../portals/Screencopy.hpp" #include "../portals/Screencopy.hpp"
#include "../portals/GlobalShortcuts.hpp"
#include "../helpers/Timer.hpp" #include "../helpers/Timer.hpp"
#include "../shared/ToplevelManager.hpp" #include "../shared/ToplevelManager.hpp"
#include <gbm.h> #include <gbm.h>
@ -42,6 +43,7 @@ class CPortalManager {
struct { struct {
std::unique_ptr<CScreencopyPortal> screencopy; std::unique_ptr<CScreencopyPortal> screencopy;
std::unique_ptr<CGlobalShortcutsPortal> globalShortcuts;
} m_sPortals; } m_sPortals;
struct { struct {

View file

@ -0,0 +1,265 @@
#include "GlobalShortcuts.hpp"
#include "../core/PortalManager.hpp"
#include "../helpers/Log.hpp"
// wayland
static void handleActivated(void* data, hyprland_global_shortcut_v1* hyprland_global_shortcut_v1, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) {
const auto PKEYBIND = (SKeybind*)data;
g_pPortalManager->m_sPortals.globalShortcuts->onActivated(PKEYBIND, ((uint64_t)tv_sec_hi << 32) | (uint64_t)(tv_sec_lo));
}
static void handleDeactivated(void* data, hyprland_global_shortcut_v1* hyprland_global_shortcut_v1, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) {
const auto PKEYBIND = (SKeybind*)data;
g_pPortalManager->m_sPortals.globalShortcuts->onDeactivated(PKEYBIND, ((uint64_t)tv_sec_hi << 32) | (uint64_t)(tv_sec_lo));
}
static const hyprland_global_shortcut_v1_listener shortcutListener = {
.pressed = handleActivated,
.released = handleDeactivated,
};
//
static void onCloseRequest(sdbus::MethodCall& call, CGlobalShortcutsPortal::SSession* sess) {
Debug::log(TRACE, "[globalshortcuts] Close Request {}", (void*)sess);
if (!sess || !sess->request)
return;
auto r = call.createReply();
r.send();
sess->request.release();
}
static void onCloseSession(sdbus::MethodCall& call, CGlobalShortcutsPortal::SSession* sess) {
Debug::log(TRACE, "[globalshortcuts] Close Session {}", (void*)sess);
if (!sess || !sess->session)
return;
auto r = call.createReply();
r.send();
sess->session.release();
}
CGlobalShortcutsPortal::SSession* CGlobalShortcutsPortal::getSession(sdbus::ObjectPath& path) {
for (auto& s : m_vSessions) {
if (s->sessionHandle == path)
return s.get();
}
return nullptr;
}
void CGlobalShortcutsPortal::onCreateSession(sdbus::MethodCall& call) {
sdbus::ObjectPath requestHandle, sessionHandle;
call >> requestHandle;
call >> sessionHandle;
std::string appID;
call >> appID;
Debug::log(LOG, "[globalshortcuts] New session:");
Debug::log(LOG, "[globalshortcuts] | {}", requestHandle.c_str());
Debug::log(LOG, "[globalshortcuts] | {}", sessionHandle.c_str());
Debug::log(LOG, "[globalshortcuts] | appid: {}", appID);
const auto PSESSION = m_vSessions.emplace_back(std::make_unique<SSession>(appID, requestHandle, sessionHandle)).get();
// create objects
PSESSION->request = sdbus::createObject(*g_pPortalManager->getConnection(), requestHandle);
PSESSION->session = sdbus::createObject(*g_pPortalManager->getConnection(), sessionHandle);
PSESSION->request->registerMethod("org.freedesktop.impl.portal.Request", "Close", "", "", [PSESSION](sdbus::MethodCall c) { onCloseRequest(c, PSESSION); });
PSESSION->session->registerMethod("org.freedesktop.impl.portal.Session", "Close", "", "", [PSESSION](sdbus::MethodCall c) { onCloseSession(c, PSESSION); });
PSESSION->request->finishRegistration();
PSESSION->session->finishRegistration();
std::unordered_map<std::string, sdbus::Variant> opts;
call >> opts;
for (auto& [k, v] : opts) {
if (k == "shortcuts") {
PSESSION->registered = true;
std::vector<sdbus::Struct<std::string, std::unordered_map<std::string, sdbus::Variant>>> shortcuts;
shortcuts = v.get<std::vector<sdbus::Struct<std::string, std::unordered_map<std::string, sdbus::Variant>>>>();
for (auto& s : shortcuts) {
const auto PSHORTCUT = PSESSION->keybinds.emplace_back(std::make_unique<SKeybind>()).get();
PSHORTCUT->id = s.get<0>();
std::unordered_map<std::string, sdbus::Variant> data = s.get<1>();
for (auto& [k, v] : data) {
if (k == "description") {
PSHORTCUT->description = v.get<std::string>();
} else {
Debug::log(LOG, "[globalshortcuts] unknown shortcut data type {}", k);
}
}
PSHORTCUT->shortcut =
hyprland_global_shortcuts_manager_v1_register_shortcut(m_sState.manager, PSHORTCUT->id.c_str(), PSESSION->appid.c_str(), PSHORTCUT->description.c_str(), "");
hyprland_global_shortcut_v1_add_listener(PSHORTCUT->shortcut, &shortcutListener, PSHORTCUT);
PSHORTCUT->session = PSESSION;
}
Debug::log(LOG, "[globalshortcuts] registered {} shortcuts", shortcuts.size());
}
}
auto reply = call.createReply();
reply << (uint32_t)0;
reply << std::unordered_map<std::string, sdbus::Variant>{};
reply.send();
}
void CGlobalShortcutsPortal::onBindShortcuts(sdbus::MethodCall& call) {
sdbus::ObjectPath sessionHandle, requestHandle;
call >> requestHandle;
call >> sessionHandle;
Debug::log(LOG, "[globalshortcuts] Bind keys:");
Debug::log(LOG, "[globalshortcuts] | {}", sessionHandle.c_str());
std::vector<sdbus::Struct<std::string, std::unordered_map<std::string, sdbus::Variant>>> shortcuts;
std::vector<sdbus::Struct<std::string, std::unordered_map<std::string, sdbus::Variant>>> shortcutsToReturn;
call >> shortcuts;
const auto PSESSION = getSession(sessionHandle);
if (!PSESSION) {
Debug::log(ERR, "[globalshortcuts] No session?");
return;
}
PSESSION->registered = true;
for (auto& s : shortcuts) {
const auto PSHORTCUT = PSESSION->keybinds.emplace_back(std::make_unique<SKeybind>()).get();
PSHORTCUT->id = s.get<0>();
std::unordered_map<std::string, sdbus::Variant> data = s.get<1>();
for (auto& [k, v] : data) {
if (k == "description") {
PSHORTCUT->description = v.get<std::string>();
} else {
Debug::log(LOG, "[globalshortcuts] unknown shortcut data type {}", k);
}
}
PSHORTCUT->shortcut =
hyprland_global_shortcuts_manager_v1_register_shortcut(m_sState.manager, PSHORTCUT->id.c_str(), PSESSION->appid.c_str(), PSHORTCUT->description.c_str(), "");
hyprland_global_shortcut_v1_add_listener(PSHORTCUT->shortcut, &shortcutListener, PSHORTCUT);
PSHORTCUT->session = PSESSION;
std::unordered_map<std::string, sdbus::Variant> shortcutData;
shortcutData["description"] = PSHORTCUT->description;
shortcutData["trigger_description"] = "";
shortcutsToReturn.push_back({PSHORTCUT->id, shortcutData});
}
Debug::log(LOG, "[globalshortcuts] registered {} shortcuts", shortcuts.size());
auto reply = call.createReply();
std::unordered_map<std::string, sdbus::Variant> data;
data["shortcuts"] = shortcutsToReturn;
reply << (uint32_t)0;
reply << data;
reply.send();
}
void CGlobalShortcutsPortal::onListShortcuts(sdbus::MethodCall& call) {
sdbus::ObjectPath sessionHandle, requestHandle;
call >> requestHandle;
call >> sessionHandle;
Debug::log(LOG, "[globalshortcuts] List keys:");
Debug::log(LOG, "[globalshortcuts] | {}", sessionHandle.c_str());
const auto PSESSION = getSession(sessionHandle);
if (!PSESSION) {
Debug::log(ERR, "[globalshortcuts] No session?");
return;
}
std::vector<sdbus::Struct<std::string, std::unordered_map<std::string, sdbus::Variant>>> shortcuts;
for (auto& s : PSESSION->keybinds) {
std::unordered_map<std::string, sdbus::Variant> opts;
opts["description"] = s->description;
opts["trigger_description"] = "";
shortcuts.push_back({s->id, opts});
}
auto reply = call.createReply();
std::unordered_map<std::string, sdbus::Variant> data;
data["shortcuts"] = shortcuts;
reply << (uint32_t)0;
reply << data;
reply.send();
}
CGlobalShortcutsPortal::CGlobalShortcutsPortal(hyprland_global_shortcuts_manager_v1* mgr) {
m_sState.manager = mgr;
m_pObject = sdbus::createObject(*g_pPortalManager->getConnection(), OBJECT_PATH);
m_pObject->registerMethod(INTERFACE_NAME, "CreateSession", "oosa{sv}", "ua{sv}", [&](sdbus::MethodCall c) { onCreateSession(c); });
m_pObject->registerMethod(INTERFACE_NAME, "BindShortcuts", "ooa(sa{sv})sa{sv}", "ua{sv}", [&](sdbus::MethodCall c) { onBindShortcuts(c); });
m_pObject->registerMethod(INTERFACE_NAME, "ListShortcuts", "oo", "ua{sv}", [&](sdbus::MethodCall c) { onListShortcuts(c); });
m_pObject->registerSignal(INTERFACE_NAME, "Activated", "osta{sv}");
m_pObject->registerSignal(INTERFACE_NAME, "Deactivated", "osta{sv}");
m_pObject->registerSignal(INTERFACE_NAME, "ShortcutsChanged", "oa(sa{sv})");
m_pObject->finishRegistration();
Debug::log(LOG, "[globalshortcuts] registered");
}
void CGlobalShortcutsPortal::onActivated(SKeybind* pKeybind, uint64_t time) {
const auto PSESSION = (CGlobalShortcutsPortal::SSession*)pKeybind->session;
Debug::log(TRACE, "[gs] Session {} called activated on {}", (void*)PSESSION, pKeybind->id);
auto signal = m_pObject->createSignal(INTERFACE_NAME, "Activated");
signal << PSESSION->sessionHandle;
signal << pKeybind->id;
signal << time;
signal << std::unordered_map<std::string, sdbus::Variant>{};
m_pObject->emitSignal(signal);
}
void CGlobalShortcutsPortal::onDeactivated(SKeybind* pKeybind, uint64_t time) {
const auto PSESSION = (CGlobalShortcutsPortal::SSession*)pKeybind->session;
Debug::log(TRACE, "[gs] Session {} called deactivated on {}", (void*)PSESSION, pKeybind->id);
auto signal = m_pObject->createSignal(INTERFACE_NAME, "Deactivated");
signal << PSESSION->sessionHandle;
signal << pKeybind->id;
signal << time;
signal << std::unordered_map<std::string, sdbus::Variant>{};
m_pObject->emitSignal(signal);
}

View file

@ -0,0 +1,46 @@
#pragma once
#include <sdbus-c++/sdbus-c++.h>
#include <protocols/hyprland-global-shortcuts-v1-protocol.h>
struct SKeybind {
std::string id, description, preferredTrigger;
hyprland_global_shortcut_v1* shortcut = nullptr;
void* session = nullptr;
};
class CGlobalShortcutsPortal {
public:
CGlobalShortcutsPortal(hyprland_global_shortcuts_manager_v1* mgr);
void onCreateSession(sdbus::MethodCall& call);
void onBindShortcuts(sdbus::MethodCall& call);
void onListShortcuts(sdbus::MethodCall& call);
void onActivated(SKeybind* pKeybind, uint64_t time);
void onDeactivated(SKeybind* pKeybind, uint64_t time);
struct SSession {
std::string appid;
sdbus::ObjectPath requestHandle, sessionHandle;
std::unique_ptr<sdbus::IObject> request, session;
bool registered = false;
std::vector<std::unique_ptr<SKeybind>> keybinds;
};
std::vector<std::unique_ptr<SSession>> m_vSessions;
private:
struct {
hyprland_global_shortcuts_manager_v1* manager;
} m_sState;
std::unique_ptr<sdbus::IObject> m_pObject;
SSession* getSession(sdbus::ObjectPath& path);
const std::string INTERFACE_NAME = "org.freedesktop.impl.portal.GlobalShortcuts";
const std::string OBJECT_PATH = "/org/freedesktop/portal/desktop";
};

View file

@ -280,7 +280,7 @@ static const hyprland_toplevel_export_frame_v1_listener hyprlandFrameListener =
// --------------------------------------------------------- // // --------------------------------------------------------- //
void onCloseRequest(sdbus::MethodCall& call, CScreencopyPortal::SSession* sess) { static void onCloseRequest(sdbus::MethodCall& call, CScreencopyPortal::SSession* sess) {
Debug::log(TRACE, "[screencopy] Close Request {}", (void*)sess); Debug::log(TRACE, "[screencopy] Close Request {}", (void*)sess);
if (!sess || !sess->request) if (!sess || !sess->request)
@ -292,7 +292,7 @@ void onCloseRequest(sdbus::MethodCall& call, CScreencopyPortal::SSession* sess)
sess->request.release(); sess->request.release();
} }
void onCloseSession(sdbus::MethodCall& call, CScreencopyPortal::SSession* sess) { static void onCloseSession(sdbus::MethodCall& call, CScreencopyPortal::SSession* sess) {
Debug::log(TRACE, "[screencopy] Close Session {}", (void*)sess); Debug::log(TRACE, "[screencopy] Close Session {}", (void*)sess);
if (!sess || !sess->session) if (!sess || !sess->session)