[plasma/kwin] src/wayland: Support more than one wl_data_device
Vlad Zahorodnii <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit e07d87d69916defcdc78ee2cb559ff9363ab2b5f by Vlad Zahorodnii, on behalf of Martin Stransky.
Committed on 10/08/2026 at 10:38.
Pushed by vladz into branch 'master'.
Support more than one wl_data_device
KWin uses only first data_device and ignores any other.
This patch allows to create and use more wl_data_devices per wl_seat.
BUG: 521494
M +37 -22 src/wayland/seat.cpp
M +1 -1 src/wayland/seat_p.h
https://invent.kde.org/plasma/kwin/-/commit/e07d87d69916defcdc78ee2cb559ff9363ab2b5f
diff --git a/src/wayland/seat.cpp b/src/wayland/seat.cpp
index 095ca86c24e..549627cd73e 100644
--- a/src/wayland/seat.cpp
+++ b/src/wayland/seat.cpp
@@ -163,6 +163,7 @@ void SeatInterfacePrivate::registerDataDevice(DataDeviceInterface *dataDevice)
auto dataDeviceCleanup = [this, dataDevice] {
dataDevices.removeOne(dataDevice);
globalDataDevice.selections.removeOne(dataDevice);
+ drag.targets.removeOne(dataDevice);
};
QObject::connect(dataDevice, &QObject::destroyed, q, dataDeviceCleanup);
QObject::connect(dataDevice, &DataDeviceInterface::selectionChanged, q, [this](DataSourceInterface *source, quint32 serial) {
@@ -195,13 +196,16 @@ void SeatInterface::endDrag()
QObject::disconnect(d->drag.dragSourceDestroyConnection);
- AbstractDropHandler *dragTargetDevice = d->drag.target.data();
+ const auto dragTargets = d->drag.targets;
AbstractDataSource *dragSource = d->drag.source;
+ const bool hasTarget = !dragTargets.isEmpty();
if (dragSource) {
- if (dragTargetDevice && dragSource->isAccepted() && dragSource->selectedDndAction() != DnDAction::None) {
+ if (hasTarget && dragSource->isAccepted() && dragSource->selectedDndAction() != DnDAction::None) {
Q_EMIT dragDropped();
- dragTargetDevice->drop();
+ for (const auto &target : dragTargets) {
+ target->drop();
+ }
dragSource->dropPerformed();
} else {
dragSource->dropPerformed();
@@ -209,8 +213,8 @@ void SeatInterface::endDrag()
}
}
- if (dragTargetDevice) {
- dragTargetDevice->updateDragTarget(nullptr, QPointF(), 0);
+ for (const auto &target : dragTargets) {
+ target->updateDragTarget(nullptr, QPointF(), 0);
}
d->drag = {};
@@ -227,9 +231,8 @@ void SeatInterface::cancelDrag()
if (d->drag.source) {
d->drag.source->dndCancelled();
}
- if (d->drag.target) {
- d->drag.target->updateDragTarget(nullptr, QPointF(), 0);
- d->drag.target = nullptr;
+ for (const auto &target : std::as_const(d->drag.targets)) {
+ target->updateDragTarget(nullptr, QPointF(), 0);
}
d->drag = {};
Q_EMIT dragEnded();
@@ -472,22 +475,30 @@ void SeatInterface::setDragTarget(AbstractDropHandler *dropTarget,
return;
}
const quint32 serial = d->display->nextSerial();
- if (d->drag.target) {
- d->drag.target->updateDragTarget(nullptr, QPointF(), serial);
+ for (const auto &target : std::as_const(d->drag.targets)) {
+ target->updateDragTarget(nullptr, QPointF(), serial);
}
+ d->drag.targets.clear();
- // TODO: technically we can have multiple data devices
- // and we should send the drag to all of them, but that seems overly complicated
- // in practice so far the only case for multiple data devices is for clipboard overriding
- d->drag.target = dropTarget;
+ if (surface) {
+ const auto dataDevices = d->dataDevicesForSurface(surface);
+ for (auto device : dataDevices) {
+ d->drag.targets.append(device);
+ }
+ if (d->drag.targets.isEmpty() && dropTarget) {
+ d->drag.targets.append(dropTarget);
+ }
+ }
- if (d->drag.target) {
+ if (!d->drag.targets.isEmpty()) {
d->drag.surface = surface;
d->drag.transformation = inputTransformation;
if (d->dragInhibitsPointer(d->globalPointer.focus.surface)) {
notifyPointerLeave();
}
- d->drag.target->updateDragTarget(surface, globalPosition, serial);
+ for (const auto &target : std::as_const(d->drag.targets)) {
+ target->updateDragTarget(surface, globalPosition, serial);
+ }
} else {
d->drag.surface = nullptr;
}
@@ -501,8 +512,8 @@ QPointF SeatInterface::dragPosition() const
void SeatInterface::notifyDragMotion(const QPointF &position)
{
d->drag.position = position;
- if (d->drag.target) {
- d->drag.target->motion(position);
+ for (const auto &target : std::as_const(d->drag.targets)) {
+ target->motion(position);
}
Q_EMIT dragMoved(position);
}
@@ -1293,14 +1304,18 @@ bool SeatInterfacePrivate::startDrag(Drag::Mode mode, AbstractDataSource *dragSo
}
drag.dragIcon = dragIcon;
- if (!dataDevicesForSurface(originSurface).isEmpty()) {
- drag.target = dataDevicesForSurface(originSurface)[0];
+ const auto devices = dataDevicesForSurface(originSurface);
+ for (auto device : devices) {
+ drag.targets.append(device);
}
- if (drag.target) {
+ if (!drag.targets.isEmpty()) {
if (dragInhibitsPointer(originSurface)) {
q->notifyPointerLeave();
}
- drag.target->updateDragTarget(originSurface, drag.position, display->nextSerial());
+ const quint32 serial = display->nextSerial();
+ for (const auto &target : std::as_const(drag.targets)) {
+ target->updateDragTarget(originSurface, drag.position, serial);
+ }
}
Q_EMIT q->dragStarted();
return true;
diff --git a/src/wayland/seat_p.h b/src/wayland/seat_p.h
index ae664f31f13..6c4ee1bee58 100644
--- a/src/wayland/seat_p.h
+++ b/src/wayland/seat_p.h
@@ -135,7 +135,7 @@ public:
Mode mode = Mode::None;
AbstractDataSource *source = nullptr;
QPointer<SurfaceInterface> surface;
- QPointer<AbstractDropHandler> target;
+ QList<AbstractDropHandler *> targets;
QPointer<DragAndDropIcon> dragIcon;
QPointF position;
QMatrix4x4 transformation;