diff --git a/CMakeLists.txt b/CMakeLists.txt index aa34efb90..23d2b085b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,6 +275,7 @@ protocolNew("unstable/pointer-gestures/pointer-gestures-unstable-v1.xml" "pointe protocolNew("unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml" "keyboard-shortcuts-inhibit-unstable-v1" false) protocolNew("unstable/text-input/text-input-unstable-v3.xml" "text-input-unstable-v3" false) protocolNew("unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" "pointer-constraints-unstable-v1" false) +protocolNew("staging/xdg-activation/xdg-activation-v1.xml" "xdg-activation-v1" false) # tools add_subdirectory(hyprctl) diff --git a/protocols/meson.build b/protocols/meson.build index 8f7e897fe..6e7ae666f 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -52,6 +52,7 @@ new_protocols = [ [wl_protocol_dir, 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml'], [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v3.xml'], [wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'], + [wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'], ] wl_protos_src = [] diff --git a/src/Compositor.cpp b/src/Compositor.cpp index d33c73d61..d1b41e1da 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -265,8 +265,6 @@ void CCompositor::initServer() { m_sWLRIMEMgr = wlr_input_method_manager_v2_create(m_sWLDisplay); - m_sWLRActivation = wlr_xdg_activation_v1_create(m_sWLDisplay); - m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLEventLoop); m_sWLRSessionLockMgr = wlr_session_lock_manager_v1_create(m_sWLDisplay); @@ -318,7 +316,6 @@ void CCompositor::initAllSignals() { addWLSignal(&m_sWLRVKeyboardMgr->events.new_virtual_keyboard, &Events::listen_newVirtualKeyboard, m_sWLRVKeyboardMgr, "VKeyboardMgr"); addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer"); addWLSignal(&m_sWLRIMEMgr->events.input_method, &Events::listen_newIME, m_sWLRIMEMgr, "IMEMgr"); - addWLSignal(&m_sWLRActivation->events.request_activate, &Events::listen_activateXDG, m_sWLRActivation, "ActivationV1"); addWLSignal(&m_sWLRSessionLockMgr->events.new_lock, &Events::listen_newSessionLock, m_sWLRSessionLockMgr, "SessionLockMgr"); if (m_sWRLDRMLeaseMgr) @@ -363,7 +360,6 @@ void CCompositor::removeAllSignals() { removeWLSignal(&Events::listen_newVirtualKeyboard); removeWLSignal(&Events::listen_RendererDestroy); removeWLSignal(&Events::listen_newIME); - removeWLSignal(&Events::listen_activateXDG); removeWLSignal(&Events::listen_newSessionLock); if (m_sWRLDRMLeaseMgr) diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 931be9f3b..bfb347af2 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -51,7 +51,6 @@ class CCompositor { 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; @@ -67,7 +66,6 @@ class CCompositor { wlr_tablet_manager_v2* m_sWLRTabletManager; wlr_xdg_foreign_registry* m_sWLRForeignRegistry; wlr_input_method_manager_v2* m_sWLRIMEMgr; - wlr_xdg_activation_v1* m_sWLRActivation; wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; wlr_backend* m_sWLRHeadlessBackend; wlr_session_lock_manager_v1* m_sWLRSessionLockMgr; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index bf40f9086..3b6a15c3b 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1272,7 +1272,7 @@ void CWindow::activate() { m_bIsUrgent = true; - if (!*PFOCUSONACTIVATE || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY)) + if (!*PFOCUSONACTIVATE || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE)) return; if (m_bIsFloating) diff --git a/src/events/Events.hpp b/src/events/Events.hpp index b5109284f..63eab66d3 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -24,7 +24,6 @@ namespace Events { // Surface XDG (window) LISTENER(newXDGToplevel); - LISTENER(activateXDG); // Window events DYNLISTENFUNC(commitWindow); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 53539eee1..eb8514b44 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -1015,22 +1015,6 @@ void Events::listener_fullscreenWindow(void* owner, void* data) { Debug::log(LOG, "{} fullscreen to {}", PWINDOW, PWINDOW->m_bIsFullscreen); } -void Events::listener_activateXDG(wl_listener* listener, void* data) { - const auto E = (wlr_xdg_activation_v1_request_activate_event*)data; - - Debug::log(LOG, "Activate request for surface at {:x}", (uintptr_t)E->surface); - - if (!wlr_xdg_surface_try_from_wlr_surface(E->surface)) - return; - - const auto PWINDOW = g_pCompositor->getWindowFromSurface(E->surface); - - if (!PWINDOW || PWINDOW == g_pCompositor->m_pLastWindow.lock() || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE)) - return; - - PWINDOW->activate(); -} - void Events::listener_activateX11(void* owner, void* data) { PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); diff --git a/src/includes.hpp b/src/includes.hpp index 1428351b6..cdb38bd79 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -63,7 +63,6 @@ extern "C" { #include #include #include -#include #include #include #include diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 9531e6d00..b00e111e7 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -16,6 +16,7 @@ #include "../protocols/TextInputV3.hpp" #include "../protocols/PointerConstraints.hpp" #include "../protocols/OutputPower.hpp" +#include "../protocols/XDGActivation.hpp" #include "tearing-control-v1.hpp" #include "fractional-scale-v1.hpp" @@ -33,6 +34,7 @@ #include "text-input-unstable-v3.hpp" #include "pointer-constraints-unstable-v1.hpp" #include "wlr-output-power-management-unstable-v1.hpp" +#include "xdg-activation-v1.hpp" CProtocolManager::CProtocolManager() { @@ -52,6 +54,7 @@ CProtocolManager::CProtocolManager() { PROTO::textInputV3 = std::make_unique(&zwp_text_input_manager_v3_interface, 1, "TextInputV3"); PROTO::constraints = std::make_unique(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints"); PROTO::outputPower = std::make_unique(&zwlr_output_power_manager_v1_interface, 1, "OutputPower"); + PROTO::activation = std::make_unique(&xdg_activation_v1_interface, 1, "XDGActivation"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/protocols/XDGActivation.cpp b/src/protocols/XDGActivation.cpp new file mode 100644 index 000000000..6e2e32fb1 --- /dev/null +++ b/src/protocols/XDGActivation.cpp @@ -0,0 +1,103 @@ +#include "XDGActivation.hpp" +#include "../managers/TokenManager.hpp" +#include "../Compositor.hpp" +#include + +#define LOGM PROTO::activation->protoLog + +CXDGActivationToken::CXDGActivationToken(SP resource_) : resource(resource_) { + if (!resource_->resource()) + return; + + resource->setDestroy([this](CXdgActivationTokenV1* r) { PROTO::activation->destroyToken(this); }); + resource->setOnDestroy([this](CXdgActivationTokenV1* r) { PROTO::activation->destroyToken(this); }); + + resource->setSetSerial([this](CXdgActivationTokenV1* r, uint32_t serial_, wl_resource* seat) { serial = serial_; }); + + resource->setSetAppId([this](CXdgActivationTokenV1* r, const char* appid) { appID = appid; }); + + resource->setCommit([this](CXdgActivationTokenV1* r) { + // TODO: should we send a protocol error of already_used here + // if it was used? the protocol spec doesn't say _when_ it should be sent... + if (committed) { + LOGM(WARN, "possible protocol error, two commits from one token. Ignoring."); + return; + } + + committed = true; + // send done with a new token + token = g_pTokenManager->registerNewToken({}, std::chrono::months{12}); + + LOGM(LOG, "assigned new xdg-activation token {}", token); + + resource->sendDone(token.c_str()); + }); +} + +CXDGActivationToken::~CXDGActivationToken() { + if (committed) + g_pTokenManager->removeToken(g_pTokenManager->getToken(token)); +} + +bool CXDGActivationToken::good() { + return resource->resource(); +} + +CXDGActivationProtocol::CXDGActivationProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CXDGActivationProtocol::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](CXdgActivationV1* p) { this->onManagerResourceDestroy(p->resource()); }); + + RESOURCE->setDestroy([this](CXdgActivationV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); + RESOURCE->setGetActivationToken([this](CXdgActivationV1* pMgr, uint32_t id) { this->onGetToken(pMgr, id); }); + RESOURCE->setActivate([this](CXdgActivationV1* pMgr, const char* token, wl_resource* surface) { + const auto TOKEN = std::find_if(m_vTokens.begin(), m_vTokens.end(), [token](const auto& t) { return t->committed && t->token == token; }); + + if (TOKEN == m_vTokens.end()) { + LOGM(WARN, "activate event for non-existent token {}??", token); + return; + } + + auto xdgToken = TOKEN->get(); + + if (xdgToken->used) { + LOGM(WARN, "activate event for already used token {}, ignoring", token); + return; + } + + xdgToken->used = true; + + wlr_surface* surf = wlr_surface_from_resource(surface); + const auto PWINDOW = g_pCompositor->getWindowFromSurface(surf); + + if (!PWINDOW) { + LOGM(WARN, "activate event for non-window or gone surface with token {}, ignoring", token); + return; + } + + PWINDOW->activate(); + }); +} + +void CXDGActivationProtocol::onManagerResourceDestroy(wl_resource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; }); +} + +void CXDGActivationProtocol::destroyToken(CXDGActivationToken* token) { + std::erase_if(m_vTokens, [&](const auto& other) { return other.get() == token; }); +} + +void CXDGActivationProtocol::onGetToken(CXdgActivationV1* pMgr, uint32_t id) { + const auto CLIENT = wl_resource_get_client(pMgr->resource()); + const auto RESOURCE = + m_vTokens.emplace_back(std::make_unique(std::make_shared(CLIENT, wl_resource_get_version(pMgr->resource()), id))).get(); + + if (!RESOURCE->good()) { + wl_resource_post_no_memory(pMgr->resource()); + m_vTokens.pop_back(); + return; + } +} \ No newline at end of file diff --git a/src/protocols/XDGActivation.hpp b/src/protocols/XDGActivation.hpp new file mode 100644 index 000000000..626c6e78b --- /dev/null +++ b/src/protocols/XDGActivation.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "xdg-activation-v1.hpp" + +class CXDGActivationToken { + public: + CXDGActivationToken(SP resource_); + ~CXDGActivationToken(); + + bool good(); + + private: + SP resource; + + uint32_t serial = 0; + std::string appID = ""; + bool committed = false; + bool used = false; + + std::string token = ""; + + friend class CXDGActivationProtocol; +}; + +class CXDGActivationProtocol : public IWaylandProtocol { + public: + CXDGActivationProtocol(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); + + private: + void onManagerResourceDestroy(wl_resource* res); + void destroyToken(CXDGActivationToken* pointer); + void onGetToken(CXdgActivationV1* pMgr, uint32_t id); + + // + std::vector> m_vManagers; + std::vector> m_vTokens; + + friend class CXDGActivationToken; +}; + +namespace PROTO { + inline UP activation; +};