From 3b9b5346b830554aa7470ccf1202a7f3be72d1b4 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Tue, 30 Jul 2024 16:33:56 -0500 Subject: [PATCH] protocols: Move globalshortcuts impl (#7102) * move global shortcuts to hyprwayland-scanner * remove wayland-scanner from deps * fix the thing --- CMakeLists.txt | 31 +----- protocols/meson.build | 28 +----- src/debug/HyprCtl.cpp | 3 +- src/managers/KeybindManager.cpp | 5 +- src/managers/ProtocolManager.cpp | 7 +- src/managers/ProtocolManager.hpp | 4 - src/protocols/GlobalShortcuts.cpp | 153 +++++++++--------------------- src/protocols/GlobalShortcuts.hpp | 65 ++++++------- 8 files changed, 84 insertions(+), 212 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 550f1dc5..3616da24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,8 +49,6 @@ endif() find_package(PkgConfig REQUIRED) -pkg_get_variable(WaylandScanner wayland-scanner wayland_scanner) -message(STATUS "Found WaylandScanner at ${WaylandScanner}") pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir) @@ -232,30 +230,6 @@ target_link_libraries(Hyprland rt PkgConfig::deps) # used by `make installheaders`, to ensure the headers are generated add_custom_target(generate-protocol-headers) -function(protocol protoPath protoName external) - if(external) - set(path ${CMAKE_SOURCE_DIR}/${protoPath}) - else() - set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) - endif() - - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h - COMMAND ${WaylandScanner} server-header ${path} - protocols/${protoName}-protocol.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c - COMMAND ${WaylandScanner} private-code ${path} - protocols/${protoName}-protocol.c - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - target_sources( - Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h - ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c) - target_sources(generate-protocol-headers - PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h) -endfunction() - function(protocolnew protoPath protoName external) if(external) set(path ${CMAKE_SOURCE_DIR}/${protoPath}) @@ -288,10 +262,7 @@ endfunction() target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads libudis86 uuid) -protocol( - "subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" - "hyprland-global-shortcuts-v1" true) - +protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-global-shortcuts-v1" true) protocolnew("unstable/text-input" "text-input-unstable-v1" false) protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-toplevel-export-v1" true) protocolnew("protocols" "wlr-screencopy-unstable-v1" true) diff --git a/protocols/meson.build b/protocols/meson.build index 4fd40859..5b807914 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -12,21 +12,12 @@ hyprland_protos = dependency('hyprland-protocols', wl_protocol_dir = wayland_protos.get_variable('pkgdatadir') hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir') -wayland_scanner_dep = dependency('wayland-scanner', native: true) -wayland_scanner = find_program( - wayland_scanner_dep.get_variable('wayland_scanner'), - native: true, -) hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.8', native: true) hyprwayland_scanner = find_program( hyprwayland_scanner_dep.get_variable('hyprwayland_scanner'), native: true, ) -protocols = [ - [hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'] -] - new_protocols = [ ['wlr-gamma-control-unstable-v1.xml'], ['wlr-foreign-toplevel-management-unstable-v1.xml'], @@ -40,6 +31,7 @@ new_protocols = [ ['wayland-drm.xml'], ['wlr-data-control-unstable-v1.xml'], ['wlr-screencopy-unstable-v1.xml'], + [hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'], [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], @@ -73,24 +65,6 @@ new_protocols = [ wl_protos_src = [] wl_protos_headers = [] -foreach p : protocols - xml = join_paths(p) - wl_protos_src += custom_target( - xml.underscorify() + '_server_c', - input: xml, - output: '@BASENAME@-protocol.c', - command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], - ) - wl_protos_headers += custom_target( - xml.underscorify() + '_server_h', - input: xml, - install: true, - install_dir: join_paths(get_option('includedir'), 'hyprland/protocols'), - output: '@BASENAME@-protocol.h', - command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'], - ) -endforeach - new_wl_protos = [] foreach p : new_protocols xml = join_paths(p) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index b81cfeff..d89d1772 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -32,6 +32,7 @@ using namespace Hyprutils::String; #include "../devices/IKeyboard.hpp" #include "../devices/ITouch.hpp" #include "../devices/Tablet.hpp" +#include "../protocols/GlobalShortcuts.hpp" #include "debug/RollingLogFollow.hpp" #include "config/ConfigManager.hpp" #include "helpers/MiscFunctions.hpp" @@ -776,7 +777,7 @@ std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string request) std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) { std::string ret = ""; - const auto SHORTCUTS = g_pProtocolManager->m_pGlobalShortcutsProtocolManager->getAllShortcuts(); + const auto SHORTCUTS = PROTO::globalShortcuts->getAllShortcuts(); if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { for (auto& sh : SHORTCUTS) ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 038f6401..2b99ce97 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -3,6 +3,7 @@ #include "../managers/SeatManager.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/ShortcutsInhibit.hpp" +#include "../protocols/GlobalShortcuts.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "../devices/IKeyboard.hpp" #include "KeybindManager.hpp" @@ -2664,10 +2665,10 @@ void CKeybindManager::global(std::string args) { if (NAME.empty()) return; - if (!g_pProtocolManager->m_pGlobalShortcutsProtocolManager->globalShortcutExists(APPID, NAME)) + if (!PROTO::globalShortcuts->isTaken(APPID, NAME)) return; - g_pProtocolManager->m_pGlobalShortcutsProtocolManager->sendGlobalShortcutEvent(APPID, NAME, g_pKeybindManager->m_iPassPressed); + PROTO::globalShortcuts->sendGlobalShortcutEvent(APPID, NAME, g_pKeybindManager->m_iPassPressed); } void CKeybindManager::moveGroupWindow(std::string args) { diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index d052e045..635e6223 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -42,6 +42,7 @@ #include "../protocols/Screencopy.hpp" #include "../protocols/ToplevelExport.hpp" #include "../protocols/TextInputV1.hpp" +#include "../protocols/GlobalShortcuts.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -148,6 +149,7 @@ CProtocolManager::CProtocolManager() { PROTO::xwaylandShell = std::make_unique(&xwayland_shell_v1_interface, 1, "XWaylandShell"); PROTO::screencopy = std::make_unique(&zwlr_screencopy_manager_v1_interface, 3, "Screencopy"); PROTO::toplevelExport = std::make_unique(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); + PROTO::globalShortcuts = std::make_unique(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) @@ -164,10 +166,6 @@ CProtocolManager::CProtocolManager() { PROTO::linuxDma = std::make_unique(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF"); } else Debug::log(WARN, "ProtocolManager: Not binding linux-dmabuf and MesaDRM: DMABUF not available"); - - // Old protocol implementations. - // TODO: rewrite them to use hyprwayland-scanner. - m_pGlobalShortcutsProtocolManager = std::make_unique(); } CProtocolManager::~CProtocolManager() { @@ -220,6 +218,7 @@ CProtocolManager::~CProtocolManager() { PROTO::xwaylandShell.reset(); PROTO::screencopy.reset(); PROTO::toplevelExport.reset(); + PROTO::globalShortcuts.reset(); PROTO::lease.reset(); PROTO::sync.reset(); diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp index 044a4d9b..1b6d31b6 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -1,7 +1,6 @@ #pragma once #include "../defines.hpp" -#include "../protocols/GlobalShortcuts.hpp" #include "../helpers/Monitor.hpp" #include "../helpers/memory/Memory.hpp" #include "../helpers/signal/Signal.hpp" @@ -12,9 +11,6 @@ class CProtocolManager { CProtocolManager(); ~CProtocolManager(); - // TODO: rewrite to use the new protocol framework - std::unique_ptr m_pGlobalShortcutsProtocolManager; - private: std::unordered_map m_mModeChangeListeners; diff --git a/src/protocols/GlobalShortcuts.cpp b/src/protocols/GlobalShortcuts.cpp index 7eb84be6..860004c9 100644 --- a/src/protocols/GlobalShortcuts.cpp +++ b/src/protocols/GlobalShortcuts.cpp @@ -1,120 +1,61 @@ #include "GlobalShortcuts.hpp" #include "../Compositor.hpp" -#define GLOBAL_SHORTCUTS_VERSION 1 +#define LOGM PROTO::globalShortcuts->protoLog -static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) { - g_pProtocolManager->m_pGlobalShortcutsProtocolManager->bindManager(client, data, version, id); -} - -static void handleDisplayDestroy(struct wl_listener* listener, void* data) { - CGlobalShortcutsProtocolManagerDestroyWrapper* wrap = wl_container_of(listener, wrap, listener); - CGlobalShortcutsProtocolManager* proto = wrap->parent; - proto->displayDestroy(); -} - -void CGlobalShortcutsProtocolManager::displayDestroy() { - wl_list_remove(&m_liDisplayDestroy.listener.link); - wl_list_init(&m_liDisplayDestroy.listener.link); - wl_global_destroy(m_pGlobal); -} - -CGlobalShortcutsProtocolManager::~CGlobalShortcutsProtocolManager() { - displayDestroy(); -} - -CGlobalShortcutsProtocolManager::CGlobalShortcutsProtocolManager() { - m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, &hyprland_global_shortcuts_manager_v1_interface, GLOBAL_SHORTCUTS_VERSION, this, bindManagerInt); - - if (!m_pGlobal) { - Debug::log(ERR, "GlobalShortcutsManager could not start!"); +CShortcutClient::CShortcutClient(SP resource_) : resource(resource_) { + if (!good()) return; - } - wl_list_init(&m_liDisplayDestroy.listener.link); - m_liDisplayDestroy.listener.notify = handleDisplayDestroy; - m_liDisplayDestroy.parent = this; - wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy.listener); + resource->setOnDestroy([this](CHyprlandGlobalShortcutsManagerV1* pMgr) { PROTO::globalShortcuts->destroyResource(this); }); + resource->setDestroy([this](CHyprlandGlobalShortcutsManagerV1* pMgr) { PROTO::globalShortcuts->destroyResource(this); }); - Debug::log(LOG, "GlobalShortcutsManager started successfully!"); -} - -static void handleRegisterShortcut(wl_client* client, wl_resource* resource, uint32_t shortcut, const char* id, const char* app_id, const char* description, - const char* trigger_description) { - g_pProtocolManager->m_pGlobalShortcutsProtocolManager->registerShortcut(client, resource, shortcut, id, app_id, description, trigger_description); -} - -static void handleDestroy(wl_client* client, wl_resource* resource) { - wl_resource_destroy(resource); -} - -static const struct hyprland_global_shortcuts_manager_v1_interface globalShortcutsManagerImpl = { - .register_shortcut = handleRegisterShortcut, - .destroy = handleDestroy, -}; - -static const struct hyprland_global_shortcut_v1_interface shortcutImpl = { - .destroy = handleDestroy, -}; - -void CGlobalShortcutsProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) { - const auto RESOURCE = wl_resource_create(client, &hyprland_global_shortcuts_manager_v1_interface, version, id); - wl_resource_set_implementation(RESOURCE, &globalShortcutsManagerImpl, this, nullptr); - - Debug::log(LOG, "GlobalShortcutsManager bound successfully!"); - - m_vClients.emplace_back(std::make_unique(client)); -} - -SShortcutClient* CGlobalShortcutsProtocolManager::clientFromWlClient(wl_client* client) { - for (auto& c : m_vClients) { - if (c->client == client) { - return c.get(); + resource->setRegisterShortcut([this](CHyprlandGlobalShortcutsManagerV1* pMgr, uint32_t shortcut, const char* id, const char* app_id, const char* description, + const char* trigger_description) { + if (PROTO::globalShortcuts->isTaken(id, app_id)) { + resource->error(HYPRLAND_GLOBAL_SHORTCUTS_MANAGER_V1_ERROR_ALREADY_TAKEN, "Combination is taken"); + return; } - } - return nullptr; -} + const auto PSHORTCUT = shortcuts.emplace_back(makeShared(makeShared(resource->client(), resource->version(), shortcut))); + PSHORTCUT->id = id; + PSHORTCUT->description = description; + PSHORTCUT->appid = app_id; + PSHORTCUT->shortcut = shortcut; -static void onShortcutDestroy(wl_resource* pResource) { - g_pProtocolManager->m_pGlobalShortcutsProtocolManager->destroyShortcut(pResource); -} - -void CGlobalShortcutsProtocolManager::registerShortcut(wl_client* client, wl_resource* resource, uint32_t shortcut, const char* id, const char* app_id, const char* description, - const char* trigger_description) { - const auto PCLIENT = clientFromWlClient(client); - - if (!PCLIENT) { - Debug::log(ERR, "Error at global shortcuts: no client in register?"); - return; - } - - for (auto& c : m_vClients) { - for (auto& sh : c->shortcuts) { - if (sh->appid == app_id && sh->id == id) { - wl_resource_post_error(resource, HYPRLAND_GLOBAL_SHORTCUTS_MANAGER_V1_ERROR_ALREADY_TAKEN, "Combination is taken"); - return; - } + if (!PSHORTCUT->resource->resource()) { + PSHORTCUT->resource->noMemory(); + shortcuts.pop_back(); + return; } - } - const auto PSHORTCUT = PCLIENT->shortcuts.emplace_back(std::make_unique()).get(); - PSHORTCUT->id = id; - PSHORTCUT->description = description; - PSHORTCUT->appid = app_id; - PSHORTCUT->shortcut = shortcut; + PSHORTCUT->resource->setDestroy([this](CHyprlandGlobalShortcutV1* pMgr) { std::erase_if(shortcuts, [&](const auto& other) { return other->resource.get() == pMgr; }); }); + }); +} - PSHORTCUT->resource = wl_resource_create(client, &hyprland_global_shortcut_v1_interface, 1, shortcut); - if (!PSHORTCUT->resource) { +bool CShortcutClient::good() { + return resource->resource(); +} + +CGlobalShortcutsProtocol::CGlobalShortcutsProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CGlobalShortcutsProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESROUCE = m_vClients.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESROUCE->good()) { wl_client_post_no_memory(client); - std::erase_if(PCLIENT->shortcuts, [&](const auto& other) { return other.get() == PSHORTCUT; }); + m_vClients.pop_back(); return; } - - wl_resource_set_implementation(PSHORTCUT->resource, &shortcutImpl, this, &onShortcutDestroy); } -bool CGlobalShortcutsProtocolManager::globalShortcutExists(std::string appid, std::string trigger) { +void CGlobalShortcutsProtocol::destroyResource(CShortcutClient* client) { + std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; }); +} + +bool CGlobalShortcutsProtocol::isTaken(std::string appid, std::string trigger) { for (auto& c : m_vClients) { for (auto& sh : c->shortcuts) { if (sh->appid == appid && sh->id == trigger) { @@ -126,7 +67,7 @@ bool CGlobalShortcutsProtocolManager::globalShortcutExists(std::string appid, st return false; } -void CGlobalShortcutsProtocolManager::sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed) { +void CGlobalShortcutsProtocol::sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed) { for (auto& c : m_vClients) { for (auto& sh : c->shortcuts) { if (sh->appid == appid && sh->id == trigger) { @@ -135,15 +76,15 @@ void CGlobalShortcutsProtocolManager::sendGlobalShortcutEvent(std::string appid, uint32_t tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0; uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF; if (pressed) - hyprland_global_shortcut_v1_send_pressed(sh->resource, tvSecHi, tvSecLo, now.tv_nsec); + sh->resource->sendPressed(tvSecHi, tvSecLo, now.tv_nsec); else - hyprland_global_shortcut_v1_send_released(sh->resource, tvSecHi, tvSecLo, now.tv_nsec); + sh->resource->sendReleased(tvSecHi, tvSecLo, now.tv_nsec); } } } } -std::vector CGlobalShortcutsProtocolManager::getAllShortcuts() { +std::vector CGlobalShortcutsProtocol::getAllShortcuts() { std::vector copy; for (auto& c : m_vClients) { for (auto& sh : c->shortcuts) { @@ -153,9 +94,3 @@ std::vector CGlobalShortcutsProtocolManager::getAllShortcuts() { return copy; } - -void CGlobalShortcutsProtocolManager::destroyShortcut(wl_resource* resource) { - for (auto& c : m_vClients) { - std::erase_if(c->shortcuts, [&](const auto& other) { return other->resource == resource; }); - } -} diff --git a/src/protocols/GlobalShortcuts.hpp b/src/protocols/GlobalShortcuts.hpp index 7e512021..14f6ee0b 100644 --- a/src/protocols/GlobalShortcuts.hpp +++ b/src/protocols/GlobalShortcuts.hpp @@ -1,48 +1,43 @@ #pragma once #include "../defines.hpp" -#include "hyprland-global-shortcuts-v1-protocol.h" +#include "hyprland-global-shortcuts-v1.hpp" +#include "../protocols/WaylandProtocol.hpp" #include struct SShortcut { - wl_resource* resource; - std::string id, description, appid; - uint32_t shortcut = 0; + SP resource; + std::string id, description, appid; + uint32_t shortcut = 0; }; -struct SShortcutClient { - wl_client* client = nullptr; - std::vector> shortcuts; -}; - -class CGlobalShortcutsProtocolManager; -struct CGlobalShortcutsProtocolManagerDestroyWrapper { - wl_listener listener; - CGlobalShortcutsProtocolManager* parent = nullptr; -}; - -class CGlobalShortcutsProtocolManager { +class CShortcutClient { public: - CGlobalShortcutsProtocolManager(); - ~CGlobalShortcutsProtocolManager(); + CShortcutClient(SP resource); - void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); - void displayDestroy(); - - void registerShortcut(wl_client* client, wl_resource* resource, uint32_t shortcut, const char* id, const char* app_id, const char* description, - const char* trigger_description); - void destroyShortcut(wl_resource* resource); - - bool globalShortcutExists(std::string appid, std::string trigger); - void sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed); - - std::vector getAllShortcuts(); - - CGlobalShortcutsProtocolManagerDestroyWrapper m_liDisplayDestroy; + bool good(); private: - std::vector> m_vClients; + SP resource; + std::vector> shortcuts; - SShortcutClient* clientFromWlClient(wl_client* client); - - wl_global* m_pGlobal = nullptr; + friend class CGlobalShortcutsProtocol; +}; + +class CGlobalShortcutsProtocol : IWaylandProtocol { + public: + CGlobalShortcutsProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); + void destroyResource(CShortcutClient* client); + + void sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed); + bool isTaken(std::string id, std::string app_id); + std::vector getAllShortcuts(); + + private: + std::vector> m_vClients; +}; + +namespace PROTO { + inline UP globalShortcuts; };