diff --git a/CMakeLists.txt b/CMakeLists.txt index d11ec813..8e420570 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -273,6 +273,7 @@ protocolNew("unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" "xdg-decora protocolNew("staging/alpha-modifier/alpha-modifier-v1.xml" "alpha-modifier-v1" false) protocolNew("staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml" "ext-foreign-toplevel-list-v1" false) protocolNew("unstable/pointer-gestures/pointer-gestures-unstable-v1.xml" "pointer-gestures-unstable-v1" false) +protocolNew("unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml" "keyboard-shortcuts-inhibit-unstable-v1" false) # tools add_subdirectory(hyprctl) diff --git a/protocols/meson.build b/protocols/meson.build index 0006f401..de6bbcce 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -50,6 +50,7 @@ new_protocols = [ [wl_protocol_dir, 'staging/alpha-modifier/alpha-modifier-v1.xml'], [wl_protocol_dir, 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml'], [wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'], + [wl_protocol_dir, 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml'], ] wl_protos_src = [] diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 37b0e400..fb67ecee 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -211,8 +211,6 @@ void CCompositor::initServer() { m_sWLROutputMgr = wlr_output_manager_v1_create(m_sWLDisplay); - m_sWLRKbShInhibitMgr = wlr_keyboard_shortcuts_inhibit_v1_create(m_sWLDisplay); - m_sWLRPointerConstraints = wlr_pointer_constraints_v1_create(m_sWLDisplay); m_sWLRVKeyboardMgr = wlr_virtual_keyboard_manager_v1_create(m_sWLDisplay); @@ -294,7 +292,6 @@ void CCompositor::initAllSignals() { addWLSignal(&m_sWLRTextInputMgr->events.text_input, &Events::listen_newTextInput, m_sWLRTextInputMgr, "TextInputMgr"); addWLSignal(&m_sWLRActivation->events.request_activate, &Events::listen_activateXDG, m_sWLRActivation, "ActivationV1"); addWLSignal(&m_sWLRSessionLockMgr->events.new_lock, &Events::listen_newSessionLock, m_sWLRSessionLockMgr, "SessionLockMgr"); - addWLSignal(&m_sWLRKbShInhibitMgr->events.new_inhibitor, &Events::listen_newShortcutInhibitor, m_sWLRKbShInhibitMgr, "ShortcutInhibitMgr"); if (m_sWRLDRMLeaseMgr) addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM"); @@ -343,7 +340,6 @@ void CCompositor::removeAllSignals() { removeWLSignal(&Events::listen_newTextInput); removeWLSignal(&Events::listen_activateXDG); removeWLSignal(&Events::listen_newSessionLock); - removeWLSignal(&Events::listen_newShortcutInhibitor); if (m_sWRLDRMLeaseMgr) removeWLSignal(&Events::listen_leaseRequest); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 7d1b3b35..a2c8abba 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -40,41 +40,40 @@ class CCompositor { ~CCompositor(); // ------------------ WLR BASICS ------------------ // - wl_display* m_sWLDisplay; - wl_event_loop* m_sWLEventLoop; - wlr_backend* m_sWLRBackend; - wlr_session* m_sWLRSession; - wlr_renderer* m_sWLRRenderer; - wlr_allocator* m_sWLRAllocator; - wlr_compositor* m_sWLRCompositor; - wlr_subcompositor* m_sWLRSubCompositor; - wlr_data_device_manager* m_sWLRDataDevMgr; - wlr_drm* m_sWRLDRM; - wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; - wlr_xdg_activation_v1* m_sWLRXDGActivation; - wlr_output_layout* m_sWLROutputLayout; - wlr_idle_notifier_v1* m_sWLRIdleNotifier; - wlr_layer_shell_v1* m_sWLRLayerShell; - wlr_xdg_shell* m_sWLRXDGShell; - wlr_cursor* m_sWLRCursor; - wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr; - wlr_output_manager_v1* m_sWLROutputMgr; - wlr_presentation* m_sWLRPresentation; - wlr_keyboard_shortcuts_inhibit_manager_v1* m_sWLRKbShInhibitMgr; - wlr_egl* m_sWLREGL; - int m_iDRMFD; - wlr_pointer_constraints_v1* m_sWLRPointerConstraints; - wlr_server_decoration_manager* m_sWLRServerDecoMgr; - wlr_virtual_pointer_manager_v1* m_sWLRVirtPtrMgr; - wlr_tablet_manager_v2* m_sWLRTabletManager; - wlr_xdg_foreign_registry* m_sWLRForeignRegistry; - wlr_output_power_manager_v1* m_sWLROutputPowerMgr; - wlr_input_method_manager_v2* m_sWLRIMEMgr; - wlr_text_input_manager_v3* m_sWLRTextInputMgr; - wlr_xdg_activation_v1* m_sWLRActivation; - wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; - wlr_backend* m_sWLRHeadlessBackend; - wlr_session_lock_manager_v1* m_sWLRSessionLockMgr; + wl_display* m_sWLDisplay; + wl_event_loop* m_sWLEventLoop; + wlr_backend* m_sWLRBackend; + wlr_session* m_sWLRSession; + wlr_renderer* m_sWLRRenderer; + wlr_allocator* m_sWLRAllocator; + wlr_compositor* m_sWLRCompositor; + wlr_subcompositor* m_sWLRSubCompositor; + wlr_data_device_manager* m_sWLRDataDevMgr; + wlr_drm* m_sWRLDRM; + wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; + wlr_xdg_activation_v1* m_sWLRXDGActivation; + wlr_output_layout* m_sWLROutputLayout; + wlr_idle_notifier_v1* m_sWLRIdleNotifier; + wlr_layer_shell_v1* m_sWLRLayerShell; + wlr_xdg_shell* m_sWLRXDGShell; + wlr_cursor* m_sWLRCursor; + wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr; + wlr_output_manager_v1* m_sWLROutputMgr; + wlr_presentation* m_sWLRPresentation; + wlr_egl* m_sWLREGL; + int m_iDRMFD; + wlr_pointer_constraints_v1* m_sWLRPointerConstraints; + wlr_server_decoration_manager* m_sWLRServerDecoMgr; + wlr_virtual_pointer_manager_v1* m_sWLRVirtPtrMgr; + wlr_tablet_manager_v2* m_sWLRTabletManager; + wlr_xdg_foreign_registry* m_sWLRForeignRegistry; + wlr_output_power_manager_v1* m_sWLROutputPowerMgr; + wlr_input_method_manager_v2* m_sWLRIMEMgr; + wlr_text_input_manager_v3* m_sWLRTextInputMgr; + wlr_xdg_activation_v1* m_sWLRActivation; + wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; + wlr_backend* m_sWLRHeadlessBackend; + wlr_session_lock_manager_v1* m_sWLRSessionLockMgr; // ------------------------------------------------- // std::string m_szWLDisplaySocket = ""; diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 3a03f3d0..a49eb92e 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -132,7 +132,4 @@ namespace Events { // Session Lock LISTENER(newSessionLock); - - // Shortcut inhibitor - LISTENER(newShortcutInhibitor); }; diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp index 6381937c..bd65adcd 100644 --- a/src/events/Misc.cpp +++ b/src/events/Misc.cpp @@ -221,20 +221,3 @@ void Events::listener_newSessionLock(wl_listener* listener, void* data) { g_pSessionLockManager->onNewSessionLock((wlr_session_lock_v1*)data); } - -void Events::listener_newShortcutInhibitor(wl_listener* listener, void* data) { - const auto INHIBITOR = (wlr_keyboard_shortcuts_inhibitor_v1*)data; - - const auto PINH = &g_pKeybindManager->m_lShortcutInhibitors.emplace_back(); - PINH->hyprListener_destroy.initCallback( - &INHIBITOR->events.destroy, - [](void* owner, void* data) { - const auto OWNER = (SShortcutInhibitor*)owner; - g_pKeybindManager->m_lShortcutInhibitors.remove(*OWNER); - }, - PINH, "ShortcutInhibitor"); - - PINH->pWlrInhibitor = INHIBITOR; - - Debug::log(LOG, "New shortcut inhibitor for surface {:x}", (uintptr_t)INHIBITOR->surface); -} diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index d6e24d53..3ea6e71e 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -316,13 +316,3 @@ struct SSwitchDevice { return pWlrDevice == other.pWlrDevice; } }; - -struct SShortcutInhibitor { - wlr_keyboard_shortcuts_inhibitor_v1* pWlrInhibitor = nullptr; - - DYNLISTENER(destroy); - - bool operator==(const SShortcutInhibitor& other) const { - return pWlrInhibitor == other.pWlrInhibitor; - } -}; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index ad863274..402c567f 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -4,6 +4,7 @@ #include "helpers/VarList.hpp" #include "../config/ConfigValue.hpp" #include "TokenManager.hpp" +#include "../protocols/ShortcutsInhibit.hpp" #include #include @@ -539,13 +540,9 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi static auto PDISABLEINHIBIT = CConfigValue("binds:disable_keybind_grabbing"); - if (!*PDISABLEINHIBIT && !m_lShortcutInhibitors.empty()) { - for (auto& i : m_lShortcutInhibitors) { - if (i.pWlrInhibitor->surface == g_pCompositor->m_pLastFocus) { - Debug::log(LOG, "Keybind handling is disabled due to an inhibitor for surface {:x}", (uintptr_t)i.pWlrInhibitor->surface); - return false; - } - } + if (!*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited()) { + Debug::log(LOG, "Keybind handling is disabled due to an inhibitor"); + return false; } for (auto& k : m_lKeybinds) { diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 450960f5..b0587b7f 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -81,7 +81,6 @@ class CKeybindManager { bool m_bGroupsLocked = false; std::list m_lKeybinds; - std::list m_lShortcutInhibitors; private: std::deque m_dPressedKeys; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 8605e8bd..a10032a0 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -12,6 +12,7 @@ #include "../protocols/ForeignToplevel.hpp" #include "../protocols/PointerGestures.hpp" #include "../protocols/ForeignToplevelWlr.hpp" +#include "../protocols/ShortcutsInhibit.hpp" #include "tearing-control-v1.hpp" #include "fractional-scale-v1.hpp" @@ -25,6 +26,7 @@ #include "ext-foreign-toplevel-list-v1.hpp" #include "pointer-gestures-unstable-v1.hpp" #include "wlr-foreign-toplevel-management-unstable-v1.hpp" +#include "keyboard-shortcuts-inhibit-unstable-v1.hpp" CProtocolManager::CProtocolManager() { @@ -40,6 +42,7 @@ CProtocolManager::CProtocolManager() { PROTO::foreignToplevel = std::make_unique(&ext_foreign_toplevel_list_v1_interface, 1, "ForeignToplevel"); PROTO::pointerGestures = std::make_unique(&zwp_pointer_gestures_v1_interface, 3, "PointerGestures"); PROTO::foreignToplevelWlr = std::make_unique(&zwlr_foreign_toplevel_manager_v1_interface, 3, "ForeignToplevelWlr"); + PROTO::shortcutsInhibit = std::make_unique(&zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1, "ShortcutsInhibit"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/protocols/ShortcutsInhibit.cpp b/src/protocols/ShortcutsInhibit.cpp new file mode 100644 index 00000000..30bc4dc2 --- /dev/null +++ b/src/protocols/ShortcutsInhibit.cpp @@ -0,0 +1,85 @@ +#include "ShortcutsInhibit.hpp" +#include +#include "../Compositor.hpp" + +#define LOGM PROTO::shortcutsInhibit->protoLog + +CKeyboardShortcutsInhibitor::CKeyboardShortcutsInhibitor(SP resource_, wlr_surface* surf) : resource(resource_), pSurface(surf) { + if (!resource->resource()) + return; + + resource->setDestroy([this](CZwpKeyboardShortcutsInhibitorV1* pMgr) { PROTO::shortcutsInhibit->destroyInhibitor(this); }); + resource->setOnDestroy([this](CZwpKeyboardShortcutsInhibitorV1* pMgr) { PROTO::shortcutsInhibit->destroyInhibitor(this); }); + + // I don't really care about following the spec here that much, + // let's make the app believe it's always active + resource->sendActive(); +} + +wlr_surface* CKeyboardShortcutsInhibitor::surface() { + return pSurface; +} + +bool CKeyboardShortcutsInhibitor::good() { + return resource->resource(); +} + +CKeyboardShortcutsInhibitProtocol::CKeyboardShortcutsInhibitProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CKeyboardShortcutsInhibitProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + RESOURCE->setOnDestroy([this](CZwpKeyboardShortcutsInhibitManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); + + RESOURCE->setDestroy([this](CZwpKeyboardShortcutsInhibitManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); + RESOURCE->setInhibitShortcuts( + [this](CZwpKeyboardShortcutsInhibitManagerV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* seat) { this->onInhibit(pMgr, id, surface, seat); }); +} + +void CKeyboardShortcutsInhibitProtocol::onManagerResourceDestroy(wl_resource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; }); +} + +void CKeyboardShortcutsInhibitProtocol::destroyInhibitor(CKeyboardShortcutsInhibitor* inhibitor) { + std::erase_if(m_vInhibitors, [&](const auto& other) { return other.get() == inhibitor; }); +} + +void CKeyboardShortcutsInhibitProtocol::onInhibit(CZwpKeyboardShortcutsInhibitManagerV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* seat) { + wlr_surface* surf = wlr_surface_from_resource(surface); + const auto CLIENT = wl_resource_get_client(pMgr->resource()); + + for (auto& in : m_vInhibitors) { + if (in->surface() != surf) + continue; + + wl_resource_post_error(pMgr->resource(), ZWP_KEYBOARD_SHORTCUTS_INHIBIT_MANAGER_V1_ERROR_ALREADY_INHIBITED, "Already inhibited for surface resource"); + return; + } + + const auto RESOURCE = m_vInhibitors + .emplace_back(std::make_unique( + std::make_shared(CLIENT, wl_resource_get_version(pMgr->resource()), id), surf)) + .get(); + + if (!RESOURCE->good()) { + wl_resource_post_no_memory(pMgr->resource()); + m_vInhibitors.pop_back(); + LOGM(ERR, "Failed to create an inhibitor resource"); + return; + } +} + +bool CKeyboardShortcutsInhibitProtocol::isInhibited() { + if (!g_pCompositor->m_pLastFocus) + return false; + + for (auto& in : m_vInhibitors) { + if (in->surface() != g_pCompositor->m_pLastFocus) + continue; + + return true; + } + + return false; +} diff --git a/src/protocols/ShortcutsInhibit.hpp b/src/protocols/ShortcutsInhibit.hpp new file mode 100644 index 00000000..4e06938f --- /dev/null +++ b/src/protocols/ShortcutsInhibit.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "keyboard-shortcuts-inhibit-unstable-v1.hpp" + +class CKeyboardShortcutsInhibitor { + public: + CKeyboardShortcutsInhibitor(SP resource_, wlr_surface* surf); + + // read-only pointer, may be invalid + wlr_surface* surface(); + bool good(); + + private: + SP resource; + wlr_surface* pSurface = nullptr; +}; + +class CKeyboardShortcutsInhibitProtocol : public IWaylandProtocol { + public: + CKeyboardShortcutsInhibitProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + bool isInhibited(); + + private: + void onManagerResourceDestroy(wl_resource* res); + void destroyInhibitor(CKeyboardShortcutsInhibitor* pointer); + void onInhibit(CZwpKeyboardShortcutsInhibitManagerV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* seat); + + // + std::vector> m_vManagers; + std::vector> m_vInhibitors; + + friend class CKeyboardShortcutsInhibitor; +}; + +namespace PROTO { + inline UP shortcutsInhibit; +}; \ No newline at end of file