From 9f7a96b997d90c4c188f3837e02859a25a05611e Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sat, 14 Dec 2024 16:19:56 +0100 Subject: core/data: Use pointer focus for DnD operations (#8707) fixes #7737 --- src/managers/SeatManager.cpp | 15 ++++++++++---- src/managers/SeatManager.hpp | 3 +++ src/managers/input/InputManager.cpp | 5 +++-- src/protocols/core/DataDevice.cpp | 39 ++++++++++++++++++++++++------------- src/protocols/core/DataDevice.hpp | 2 ++ 5 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 08923dd7..b169faeb 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -14,8 +14,7 @@ CSeatManager::CSeatManager() { listeners.newSeatResource = PROTO::seat->events.newSeatResource.registerListener([this](std::any res) { onNewSeatResource(std::any_cast>(res)); }); } -CSeatManager::SSeatResourceContainer::SSeatResourceContainer(SP res) { - resource = res; +CSeatManager::SSeatResourceContainer::SSeatResourceContainer(SP res) : resource(res) { listeners.destroy = res->events.destroy.registerListener( [this](std::any data) { std::erase_if(g_pSeatManager->seatResources, [this](const auto& e) { return e->resource.expired() || e->resource == resource; }); }); } @@ -192,8 +191,12 @@ void CSeatManager::setPointerFocus(SP surf, const Vector2D& if (state.pointerFocus == surf) return; - if (PROTO::data->dndActive() && surf) { - Debug::log(LOG, "[seatmgr] Refusing pointer focus during an active dnd"); + if (PROTO::data->dndActive()) { + if (state.dndPointerFocus == surf) + return; + Debug::log(LOG, "[seatmgr] Refusing pointer focus during an active dnd, but setting dndPointerFocus"); + state.dndPointerFocus = surf; + events.dndPointerFocusChange.emit(); return; } @@ -221,6 +224,7 @@ void CSeatManager::setPointerFocus(SP surf, const Vector2D& auto lastPointerFocusResource = state.pointerFocusResource; + state.dndPointerFocus.reset(); state.pointerFocusResource.reset(); state.pointerFocus = surf; @@ -230,6 +234,8 @@ void CSeatManager::setPointerFocus(SP surf, const Vector2D& return; } + state.dndPointerFocus = surf; + auto client = surf->client(); for (auto const& r : seatResources | std::views::reverse) { if (r->resource->client() != client) @@ -252,6 +258,7 @@ void CSeatManager::setPointerFocus(SP surf, const Vector2D& listeners.pointerSurfaceDestroy = surf->events.destroy.registerListener([this](std::any d) { setPointerFocus(nullptr, {}); }); events.pointerFocusChange.emit(); + events.dndPointerFocusChange.emit(); } void CSeatManager::sendPointerMotion(uint32_t timeMs, const Vector2D& local) { diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index e50f123f..ccfe5e76 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -95,6 +95,8 @@ class CSeatManager { WP touchFocus; WP touchFocusResource; + + WP dndPointerFocus; } state; struct SSetCursorEvent { @@ -105,6 +107,7 @@ class CSeatManager { struct { CSignal keyboardFocusChange; CSignal pointerFocusChange; + CSignal dndPointerFocusChange; CSignal touchFocusChange; CSignal setCursor; // SSetCursorEvent CSignal setSelection; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index d1eb7c4c..fdaa6bfa 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -374,8 +374,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (g_pPointerManager->softwareLockedFor(PMONITOR->self.lock()) > 0 && !skipFrameSchedule) g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.lock(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_MOVE); - // grabs - if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(foundSurface)) { + // FIXME: This will be disabled during DnD operations because we do not exactly follow the spec + // xdg-popup grabs should be keyboard-only, while they are absolute in our case... + if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(foundSurface) && !PROTO::data->dndActive()) { if (m_bHardInput || refocus) { g_pSeatManager->setGrab(nullptr); return; // setGrab will refocus diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index f51a3249..d23e3415 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -2,6 +2,7 @@ #include #include "../../managers/SeatManager.hpp" #include "../../managers/PointerManager.hpp" +#include "../../managers/eventLoop/EventLoopManager.hpp" #include "../../Compositor.hpp" #include "Seat.hpp" #include "Compositor.hpp" @@ -342,7 +343,10 @@ bool CWLDataDeviceManagerResource::good() { } CWLDataDeviceProtocol::CWLDataDeviceProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { - ; + g_pEventLoopManager->doLater([this]() { + listeners.onKeyboardFocusChange = g_pSeatManager->events.keyboardFocusChange.registerListener([this](std::any d) { onKeyboardFocus(); }); + listeners.onDndPointerFocusChange = g_pSeatManager->events.dndPointerFocusChange.registerListener([this](std::any d) { onDndPointerFocus(); }); + }); } void CWLDataDeviceProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { @@ -355,10 +359,6 @@ void CWLDataDeviceProtocol::bindManager(wl_client* client, void* data, uint32_t } LOGM(LOG, "New datamgr resource bound at {:x}", (uintptr_t)RESOURCE.get()); - - // we need to do it here because protocols come before seatMgr - if (!listeners.onKeyboardFocusChange) - listeners.onKeyboardFocusChange = g_pSeatManager->events.keyboardFocusChange.registerListener([this](std::any d) { this->onKeyboardFocus(); }); } void CWLDataDeviceProtocol::destroyResource(CWLDataDeviceManagerResource* seat) { @@ -461,10 +461,21 @@ void CWLDataDeviceProtocol::updateSelection() { void CWLDataDeviceProtocol::onKeyboardFocus() { for (auto const& o : m_vOffers) { + if (o->source && o->source->hasDnd()) + continue; o->dead = true; } updateSelection(); +} + +void CWLDataDeviceProtocol::onDndPointerFocus() { + for (auto const& o : m_vOffers) { + if (o->source && !o->source->hasDnd()) + continue; + o->dead = true; + } + updateDrag(); } @@ -515,8 +526,8 @@ void CWLDataDeviceProtocol::initiateDrag(WP currentSource dnd.mouseMove = g_pHookSystem->hookDynamic("mouseMove", [this](void* self, SCallbackInfo& info, std::any e) { auto V = std::any_cast(e); - if (dnd.focusedDevice && g_pSeatManager->state.keyboardFocus) { - auto surf = CWLSurface::fromResource(g_pSeatManager->state.keyboardFocus.lock()); + if (dnd.focusedDevice && g_pSeatManager->state.dndPointerFocus) { + auto surf = CWLSurface::fromResource(g_pSeatManager->state.dndPointerFocus.lock()); if (!surf) return; @@ -536,8 +547,8 @@ void CWLDataDeviceProtocol::initiateDrag(WP currentSource dnd.touchMove = g_pHookSystem->hookDynamic("touchMove", [this](void* self, SCallbackInfo& info, std::any e) { auto E = std::any_cast(e); - if (dnd.focusedDevice && g_pSeatManager->state.keyboardFocus) { - auto surf = CWLSurface::fromResource(g_pSeatManager->state.keyboardFocus.lock()); + if (dnd.focusedDevice && g_pSeatManager->state.dndPointerFocus) { + auto surf = CWLSurface::fromResource(g_pSeatManager->state.dndPointerFocus.lock()); if (!surf) return; @@ -555,7 +566,9 @@ void CWLDataDeviceProtocol::initiateDrag(WP currentSource // unfocus the pointer from the surface, this is part of """standard""" wayland procedure and gtk will freak out if this isn't happening. // BTW, the spec does NOT require this explicitly... // Fuck you gtk. + const auto LASTDNDFOCUS = g_pSeatManager->state.dndPointerFocus; g_pSeatManager->setPointerFocus(nullptr, {}); + g_pSeatManager->state.dndPointerFocus = LASTDNDFOCUS; // make a new offer, etc updateDrag(); @@ -568,10 +581,10 @@ void CWLDataDeviceProtocol::updateDrag() { if (dnd.focusedDevice) dnd.focusedDevice->sendLeave(); - if (!g_pSeatManager->state.keyboardFocusResource) + if (!g_pSeatManager->state.dndPointerFocus) return; - dnd.focusedDevice = dataDeviceForClient(g_pSeatManager->state.keyboardFocusResource->client()); + dnd.focusedDevice = dataDeviceForClient(g_pSeatManager->state.dndPointerFocus->client()); if (!dnd.focusedDevice) return; @@ -590,8 +603,8 @@ void CWLDataDeviceProtocol::updateDrag() { dnd.focusedDevice->sendDataOffer(OFFER); OFFER->sendData(); - dnd.focusedDevice->sendEnter(wl_display_next_serial(g_pCompositor->m_sWLDisplay), g_pSeatManager->state.keyboardFocus.lock(), - g_pSeatManager->state.keyboardFocus->current.size / 2.F, OFFER); + dnd.focusedDevice->sendEnter(wl_display_next_serial(g_pCompositor->m_sWLDisplay), g_pSeatManager->state.dndPointerFocus.lock(), + g_pSeatManager->state.dndPointerFocus->current.size / 2.F, OFFER); } void CWLDataDeviceProtocol::resetDndState() { diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index 81ca1b11..bf22b511 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -155,6 +155,7 @@ class CWLDataDeviceProtocol : public IWaylandProtocol { void sendSelectionToDevice(SP dev, SP sel); void updateSelection(); void onKeyboardFocus(); + void onDndPointerFocus(); struct { WP focusedDevice; @@ -191,6 +192,7 @@ class CWLDataDeviceProtocol : public IWaylandProtocol { struct { CHyprSignalListener onKeyboardFocusChange; + CHyprSignalListener onDndPointerFocusChange; } listeners; }; -- cgit v1.2.3