xwayland: Keep source/Xvisit alive for longer

SeatInterface emits dragEnded when the drag is dropped. The target may want
to interact with the data source after the drop happened, for example only
fetching data after the drop and not during the drag.
(Note that the Wayland protocol has the same
Xvisits are now not deleted prematurely but only when they are really finished.
(Note that the Wayland protocol has the same distinction between dropped and
finished so it maps nicely).
For storing  previous visits the same code pattern as in the rest of the XWayland
DND code is used.
The SelectionSource is reset when the next Drag/Drop operation involving a X window
is started (see startDrag and doHandleXfixesNotify) or when the Wayland source is
about to be deleted.

BUG:450460
FIXED-in:5.25.0
This commit is contained in:
David Redondo 2022-05-17 09:18:02 +02:00 committed by David Edmundson
parent f6f4a296f2
commit 20a94d7157
3 changed files with 24 additions and 8 deletions

View file

@ -152,6 +152,11 @@ void Dnd::startDrag()
m_currentDrag = new WlToXDrag();
auto source = new WlSource(this);
source->setDataSourceIface(dragSource);
connect(dragSource, &KWaylandServer::AbstractDataSource::aboutToBeDestroyed, this, [this, source] {
if (source == wlSource()) {
setWlSource(nullptr);
}
});
setWlSource(source);
ownSelection(true);
}
@ -160,13 +165,9 @@ void Dnd::endDrag()
{
Q_ASSERT(m_currentDrag);
if (qobject_cast<WlToXDrag *>(m_currentDrag)) {
delete m_currentDrag;
setWlSource(nullptr);
} else {
connect(m_currentDrag, &Drag::finish, this, &Dnd::clearOldDrag);
m_oldDrags << m_currentDrag;
}
connect(m_currentDrag, &Drag::finish, this, &Dnd::clearOldDrag);
m_oldDrags << m_currentDrag;
m_currentDrag = nullptr;
}

View file

@ -34,6 +34,12 @@ void XwlDropHandler::drop()
bool XwlDropHandler::handleClientMessage(xcb_client_message_event_t *event)
{
for (auto visit : m_previousVisits) {
if (visit->handleClientMessage(event)) {
return true;
}
}
if (m_xvisit && m_xvisit->handleClientMessage(event)) {
return true;
}
@ -52,7 +58,15 @@ void XwlDropHandler::updateDragTarget(KWaylandServer::SurfaceInterface *surface,
// leave current target
if (m_xvisit) {
m_xvisit->leave();
delete m_xvisit;
if (!m_xvisit->finished()) {
connect(m_xvisit, &Xvisit::finish, this, [this](Xvisit *visit) {
m_previousVisits.removeOne(visit);
delete visit;
});
m_previousVisits.push_back(m_xvisit);
} else {
delete m_xvisit;
}
m_xvisit = nullptr;
}
if (client) {

View file

@ -34,6 +34,7 @@ public:
private:
void drop() override;
Xvisit *m_xvisit = nullptr;
QVector<Xvisit *> m_previousVisits;
};
}
}