Skip to content

Commit

Permalink
fix(dnd): prevent input block after dnd
Browse files Browse the repository at this point in the history
  • Loading branch information
nnyyxxxx committed Feb 14, 2025
1 parent 40adb3d commit bab7e67
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 34 deletions.
38 changes: 22 additions & 16 deletions src/protocols/core/DataDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "../../managers/HookSystemManager.hpp"
#include "../../helpers/Monitor.hpp"
#include "../../render/Renderer.hpp"
#include "../../xwayland/Dnd.hpp"
using namespace Hyprutils::OS;

CWLDataOfferResource::CWLDataOfferResource(SP<CWlDataOffer> resource_, SP<IDataSource> source_) : source(source_), resource(resource_) {
Expand Down Expand Up @@ -689,14 +690,24 @@ void CWLDataDeviceProtocol::updateDrag() {
g_pSeatManager->state.dndPointerFocus->current.size / 2.F, offer);
}

void CWLDataDeviceProtocol::resetDndState() {
void CWLDataDeviceProtocol::cleanupDndState(bool resetDevice, bool resetSource, bool simulateInput) {
dnd.dndSurface.reset();
dnd.dndSurfaceCommit.reset();
dnd.dndSurfaceDestroy.reset();
dnd.mouseButton.reset();
dnd.mouseMove.reset();
dnd.touchUp.reset();
dnd.touchMove.reset();

if (resetDevice)
dnd.focusedDevice.reset();
if (resetSource)
dnd.currentSource.reset();

if (simulateInput) {
g_pInputManager->simulateMouseMovement();
g_pSeatManager->resendEnterEvents();
}
}

void CWLDataDeviceProtocol::dropDrag() {
Expand All @@ -714,11 +725,11 @@ void CWLDataDeviceProtocol::dropDrag() {
dnd.focusedDevice->sendDrop();
dnd.focusedDevice->sendLeave();

resetDndState();

if (dnd.overriddenCursor)
g_pInputManager->unsetCursorImage();
dnd.overriddenCursor = false;

cleanupDndState(true, true, true);
}

bool CWLDataDeviceProtocol::wasDragSuccessful() {
Expand All @@ -729,7 +740,7 @@ bool CWLDataDeviceProtocol::wasDragSuccessful() {
if (o->dead || !o->source || !o->source->hasDnd())
continue;

if (o->recvd || o->accepted)
if (o->source->hasDnd() && (o->recvd || o->accepted))
return true;
}

Expand All @@ -739,9 +750,6 @@ bool CWLDataDeviceProtocol::wasDragSuccessful() {
if (o->dead || !o->source || !o->source->hasDnd())
continue;

if (o->source != dnd.currentSource)
continue;

return true;
}
}
Expand All @@ -751,8 +759,6 @@ bool CWLDataDeviceProtocol::wasDragSuccessful() {
}

void CWLDataDeviceProtocol::completeDrag() {
resetDndState();

if (!dnd.focusedDevice && !dnd.currentSource)
return;

Expand All @@ -761,15 +767,11 @@ void CWLDataDeviceProtocol::completeDrag() {
dnd.currentSource->sendDndFinished();
}

dnd.focusedDevice.reset();
dnd.currentSource.reset();

g_pInputManager->simulateMouseMovement();
g_pSeatManager->resendEnterEvents();
cleanupDndState(true, true, true);
}

void CWLDataDeviceProtocol::abortDrag() {
resetDndState();
cleanupDndState(false, false, false);

if (dnd.overriddenCursor)
g_pInputManager->unsetCursorImage();
Expand All @@ -778,8 +780,12 @@ void CWLDataDeviceProtocol::abortDrag() {
if (!dnd.focusedDevice && !dnd.currentSource)
return;

if (dnd.focusedDevice)
if (dnd.focusedDevice) {
if (auto x11Device = dnd.focusedDevice->getX11(); x11Device)
x11Device->forceCleanupDnd();
dnd.focusedDevice->sendLeave();
}

if (dnd.currentSource)
dnd.currentSource->cancelled();

Expand Down
2 changes: 1 addition & 1 deletion src/protocols/core/DataDevice.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ class CWLDataDeviceProtocol : public IWaylandProtocol {
void updateDrag();
void dropDrag();
void completeDrag();
void resetDndState();
void cleanupDndState(bool resetDevice, bool resetSource, bool simulateInput);
bool wasDragSuccessful();

//
Expand Down
66 changes: 49 additions & 17 deletions src/xwayland/Dnd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,6 @@ void CX11DataDevice::sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, con
return;
}

xcb_set_selection_owner(g_pXWayland->pWM->connection, g_pXWayland->pWM->dndSelection.window, HYPRATOMS["XdndSelection"], XCB_TIME_CURRENT_TIME);

xcb_client_message_data_t data = {0};
data.data32[0] = g_pXWayland->pWM->dndSelection.window;
data.data32[1] = XDND_VERSION << 24;

// let the client know it needs to check for DND_TYPE_LIST
data.data32[1] |= 1;

std::vector<xcb_atom_t> targets;
// reserve to avoid reallocations
targets.reserve(SOURCE->mimes().size());
Expand All @@ -87,6 +78,14 @@ void CX11DataDevice::sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, con
xcb_change_property(g_pXWayland->pWM->connection, XCB_PROP_MODE_REPLACE, g_pXWayland->pWM->dndSelection.window, HYPRATOMS["XdndTypeList"], XCB_ATOM_ATOM, 32, targets.size(),
targets.data());

xcb_set_selection_owner(g_pXWayland->pWM->connection, g_pXWayland->pWM->dndSelection.window, HYPRATOMS["XdndSelection"], XCB_TIME_CURRENT_TIME);
xcb_flush(g_pXWayland->pWM->connection);

xcb_client_message_data_t data = {0};
data.data32[0] = g_pXWayland->pWM->dndSelection.window;
data.data32[1] = XDND_VERSION << 24;
data.data32[1] |= 1;

g_pXWayland->pWM->sendDndEvent(surf, HYPRATOMS["XdndEnter"], data);

lastSurface = XSURF;
Expand All @@ -103,6 +102,13 @@ void CX11DataDevice::sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, con
#endif
}

void CX11DataDevice::cleanupState() {
lastSurface.reset();
lastOffer.reset();
lastSurfaceCoords = {};
lastTime = 0;
}

void CX11DataDevice::sendLeave() {
#ifndef NO_XWAYLAND
if (!lastSurface)
Expand All @@ -113,10 +119,7 @@ void CX11DataDevice::sendLeave() {

g_pXWayland->pWM->sendDndEvent(lastSurface->surface.lock(), HYPRATOMS["XdndLeave"], data);

lastSurface.reset();
lastOffer.reset();

xcb_set_selection_owner(g_pXWayland->pWM->connection, g_pXWayland->pWM->dndSelection.window, XCB_ATOM_NONE, XCB_TIME_CURRENT_TIME);
cleanupState();
#endif
}

Expand All @@ -140,17 +143,26 @@ void CX11DataDevice::sendMotion(uint32_t timeMs, const Vector2D& local) {

void CX11DataDevice::sendDrop() {
#ifndef NO_XWAYLAND
if (!lastSurface || !lastOffer)
if (!lastSurface || !lastOffer) {
Debug::log(ERR, "CX11DataDevice::sendDrop: No surface or offer");
return;
}

// we don't have timeMs here, just send last time + 1
xcb_client_message_data_t data = {0};
data.data32[0] = g_pXWayland->pWM->dndSelection.window;
data.data32[2] = lastTime + 1;
data.data32[2] = lastTime;

g_pXWayland->pWM->sendDndEvent(lastSurface->surface.lock(), HYPRATOMS["XdndDrop"], data);

sendLeave();
auto source = lastOffer->getSource();
if (source) {
source->sendDndDropPerformed();
}

cleanupState();

g_pInputManager->simulateMouseMovement();
g_pSeatManager->resendEnterEvents();
#endif
}

Expand Down Expand Up @@ -217,3 +229,23 @@ void CX11DataSource::sendDndDropPerformed() {
void CX11DataSource::sendDndAction(wl_data_device_manager_dnd_action a) {
;
}

void CX11DataDevice::forceCleanupDnd() {
#ifndef NO_XWAYLAND
if (lastOffer) {
auto source = lastOffer->getSource();
if (source) {
source->cancelled();
source->sendDndFinished();
}
}

xcb_set_selection_owner(g_pXWayland->pWM->connection, XCB_ATOM_NONE, HYPRATOMS["XdndSelection"], XCB_TIME_CURRENT_TIME);
xcb_flush(g_pXWayland->pWM->connection);

cleanupState();

g_pSeatManager->setPointerFocus(nullptr, {});
g_pInputManager->simulateMouseMovement();
#endif
}
4 changes: 4 additions & 0 deletions src/xwayland/Dnd.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once

#include "../protocols/types/DataDevice.hpp"
#include "../managers/SeatManager.hpp"
#include "../managers/input/InputManager.hpp"
#include <wayland-server-protocol.h>
#include <hyprutils/os/FileDescriptor.hpp>

Expand Down Expand Up @@ -72,10 +74,12 @@ class CX11DataDevice : public IDataDevice {
virtual void sendDrop();
virtual void sendSelection(SP<IDataOffer> offer);
virtual eDataSourceType type();
void forceCleanupDnd();

WP<CX11DataDevice> self;

private:
void cleanupState();
WP<CXWaylandSurface> lastSurface;
WP<IDataOffer> lastOffer;
Vector2D lastSurfaceCoords;
Expand Down

0 comments on commit bab7e67

Please sign in to comment.