aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorVaxry <[email protected]>2024-12-14 16:19:56 +0100
committerGitHub <[email protected]>2024-12-14 16:19:56 +0100
commit9f7a96b997d90c4c188f3837e02859a25a05611e (patch)
treeea3fde67a04a5c9adbf2011b05c2056892ad2b1e
parent3cba4ba44e7ba3cc8bb67ac71bc61245b5aca347 (diff)
downloadHyprland-9f7a96b997d90c4c188f3837e02859a25a05611e.tar.gz
Hyprland-9f7a96b997d90c4c188f3837e02859a25a05611e.zip
core/data: Use pointer focus for DnD operations (#8707)
fixes #7737
-rw-r--r--src/managers/SeatManager.cpp15
-rw-r--r--src/managers/SeatManager.hpp3
-rw-r--r--src/managers/input/InputManager.cpp5
-rw-r--r--src/protocols/core/DataDevice.cpp39
-rw-r--r--src/protocols/core/DataDevice.hpp2
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<SP<CWLSeatResource>>(res)); });
}
-CSeatManager::SSeatResourceContainer::SSeatResourceContainer(SP<CWLSeatResource> res) {
- resource = res;
+CSeatManager::SSeatResourceContainer::SSeatResourceContainer(SP<CWLSeatResource> 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<CWLSurfaceResource> 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<CWLSurfaceResource> surf, const Vector2D&
auto lastPointerFocusResource = state.pointerFocusResource;
+ state.dndPointerFocus.reset();
state.pointerFocusResource.reset();
state.pointerFocus = surf;
@@ -230,6 +234,8 @@ void CSeatManager::setPointerFocus(SP<CWLSurfaceResource> 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<CWLSurfaceResource> 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<CWLSurfaceResource> touchFocus;
WP<CWLSeatResource> touchFocusResource;
+
+ WP<CWLSurfaceResource> 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 <algorithm>
#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<CWLDataSourceResource> currentSource
dnd.mouseMove = g_pHookSystem->hookDynamic("mouseMove", [this](void* self, SCallbackInfo& info, std::any e) {
auto V = std::any_cast<const Vector2D>(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<CWLDataSourceResource> currentSource
dnd.touchMove = g_pHookSystem->hookDynamic("touchMove", [this](void* self, SCallbackInfo& info, std::any e) {
auto E = std::any_cast<ITouch::SMotionEvent>(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<CWLDataSourceResource> 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<CWLDataDeviceResource> dev, SP<IDataSource> sel);
void updateSelection();
void onKeyboardFocus();
+ void onDndPointerFocus();
struct {
WP<CWLDataDeviceResource> focusedDevice;
@@ -191,6 +192,7 @@ class CWLDataDeviceProtocol : public IWaylandProtocol {
struct {
CHyprSignalListener onKeyboardFocusChange;
+ CHyprSignalListener onDndPointerFocusChange;
} listeners;
};