184 lines
5.3 KiB
Diff
184 lines
5.3 KiB
Diff
|
From 711c5bb43f2823766d5189dc8d567c8f4cec253c Mon Sep 17 00:00:00 2001
|
||
|
From: David Edmundson <kde@davidedmundson.co.uk>
|
||
|
Date: Wed, 15 May 2024 22:08:26 +0100
|
||
|
Subject: [PATCH] wayland: send dndFinished to source if target fails to do so
|
||
|
|
||
|
After receiving a drop a client should call data_offer.finish
|
||
|
to tell the source it's done using the drop.
|
||
|
|
||
|
A client could delete an offer after drop before calling finish.
|
||
|
|
||
|
This can happen with misbehaving/buggy or malicious Wayland clients.
|
||
|
A real case was found in the wild with Chromium, as described in the
|
||
|
linked bug.
|
||
|
|
||
|
In this situation we should let the source know the dnd is finished
|
||
|
as there are no other transfers than can take place.
|
||
|
|
||
|
We don't want to universally send this in all data offer destructors
|
||
|
only, offers that are deleted post drop so the flag on the source is
|
||
|
exposed.
|
||
|
|
||
|
BUG: 482142
|
||
|
---
|
||
|
src/wayland/abstract_data_source.h | 24 ++++++++++++++++++++++--
|
||
|
src/wayland/dataoffer.cpp | 9 ++++++++-
|
||
|
src/wayland/datasource.cpp | 15 +++------------
|
||
|
src/wayland/datasource.h | 3 ---
|
||
|
4 files changed, 33 insertions(+), 18 deletions(-)
|
||
|
|
||
|
diff --git a/src/wayland/abstract_data_source.h b/src/wayland/abstract_data_source.h
|
||
|
index d5213d8f8a0..af5f9005bdb 100644
|
||
|
--- a/src/wayland/abstract_data_source.h
|
||
|
+++ b/src/wayland/abstract_data_source.h
|
||
|
@@ -56,11 +56,16 @@ public:
|
||
|
/**
|
||
|
* The user performed the drop action during a drag and drop operation.
|
||
|
*/
|
||
|
- virtual void dropPerformed(){};
|
||
|
+ virtual void dropPerformed()
|
||
|
+ {
|
||
|
+ m_dndDropped = true;
|
||
|
+ }
|
||
|
/**
|
||
|
* The drop destination finished interoperating with this data source.
|
||
|
*/
|
||
|
- virtual void dndFinished(){};
|
||
|
+ virtual void dndFinished()
|
||
|
+ {
|
||
|
+ }
|
||
|
/**
|
||
|
* This event indicates the @p action selected by the compositor after matching the
|
||
|
* source/destination side actions. Only one action (or none) will be offered here.
|
||
|
@@ -69,11 +74,22 @@ public:
|
||
|
{
|
||
|
};
|
||
|
|
||
|
+ bool isDndCancelled() const
|
||
|
+ {
|
||
|
+ return m_dndCancelled;
|
||
|
+ }
|
||
|
+
|
||
|
+ bool isDropPerformed() const
|
||
|
+ {
|
||
|
+ return m_dndDropped;
|
||
|
+ }
|
||
|
+
|
||
|
/**
|
||
|
* Called when a user stops clicking but it is not accepted by a client.
|
||
|
*/
|
||
|
virtual void dndCancelled()
|
||
|
{
|
||
|
+ m_dndCancelled = true;
|
||
|
}
|
||
|
|
||
|
virtual wl_client *client() const
|
||
|
@@ -89,6 +105,10 @@ Q_SIGNALS:
|
||
|
|
||
|
protected:
|
||
|
explicit AbstractDataSource(QObject *parent = nullptr);
|
||
|
+
|
||
|
+private:
|
||
|
+ bool m_dndCancelled = false;
|
||
|
+ bool m_dndDropped = false;
|
||
|
};
|
||
|
|
||
|
}
|
||
|
diff --git a/src/wayland/dataoffer.cpp b/src/wayland/dataoffer.cpp
|
||
|
index 91f5f552b93..79d8f32034f 100644
|
||
|
--- a/src/wayland/dataoffer.cpp
|
||
|
+++ b/src/wayland/dataoffer.cpp
|
||
|
@@ -77,6 +77,7 @@ void DataOfferInterfacePrivate::data_offer_finish(Resource *resource)
|
||
|
return;
|
||
|
}
|
||
|
source->dndFinished();
|
||
|
+ source.clear();
|
||
|
// TODO: It is a client error to perform other requests than wl_data_offer.destroy after this one
|
||
|
}
|
||
|
|
||
|
@@ -163,7 +164,13 @@ DataOfferInterface::DataOfferInterface(AbstractDataSource *source, wl_resource *
|
||
|
});
|
||
|
}
|
||
|
|
||
|
-DataOfferInterface::~DataOfferInterface() = default;
|
||
|
+DataOfferInterface::~DataOfferInterface()
|
||
|
+{
|
||
|
+ if (d->source && d->source->isDropPerformed()) {
|
||
|
+ d->source->dndFinished();
|
||
|
+ d->source.clear();
|
||
|
+ }
|
||
|
+}
|
||
|
|
||
|
void DataOfferInterface::sendAllOffers()
|
||
|
{
|
||
|
diff --git a/src/wayland/datasource.cpp b/src/wayland/datasource.cpp
|
||
|
index 418a160e01e..1713c135c37 100644
|
||
|
--- a/src/wayland/datasource.cpp
|
||
|
+++ b/src/wayland/datasource.cpp
|
||
|
@@ -129,7 +129,7 @@ DataDeviceManagerInterface::DnDAction DataSourceInterface::selectedDndAction() c
|
||
|
|
||
|
void DataSourceInterface::dropPerformed()
|
||
|
{
|
||
|
- d->dropPerformed = true;
|
||
|
+ AbstractDataSource::dropPerformed();
|
||
|
if (d->resource()->version() < WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) {
|
||
|
return;
|
||
|
}
|
||
|
@@ -138,17 +138,13 @@ void DataSourceInterface::dropPerformed()
|
||
|
|
||
|
void DataSourceInterface::dndFinished()
|
||
|
{
|
||
|
+ AbstractDataSource::dndFinished();
|
||
|
if (d->resource()->version() < WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
|
||
|
return;
|
||
|
}
|
||
|
d->send_dnd_finished();
|
||
|
}
|
||
|
|
||
|
-bool DataSourceInterface::isDropPerformed() const
|
||
|
-{
|
||
|
- return d->dropPerformed;
|
||
|
-}
|
||
|
-
|
||
|
void DataSourceInterface::dndAction(DataDeviceManagerInterface::DnDAction action)
|
||
|
{
|
||
|
d->selectedDndAction = action;
|
||
|
@@ -169,7 +165,7 @@ void DataSourceInterface::dndAction(DataDeviceManagerInterface::DnDAction action
|
||
|
|
||
|
void DataSourceInterface::dndCancelled()
|
||
|
{
|
||
|
- d->isCanceled = true;
|
||
|
+ AbstractDataSource::dndCancelled();
|
||
|
// for v3 or less, cancel should not be called after a failed drag operation
|
||
|
if (wl_resource_get_version(resource()) < 3) {
|
||
|
return;
|
||
|
@@ -177,11 +173,6 @@ void DataSourceInterface::dndCancelled()
|
||
|
d->send_cancelled();
|
||
|
}
|
||
|
|
||
|
-bool DataSourceInterface::isDndCancelled() const
|
||
|
-{
|
||
|
- return d->isCanceled;
|
||
|
-}
|
||
|
-
|
||
|
wl_resource *DataSourceInterface::resource() const
|
||
|
{
|
||
|
return d->resource()->handle;
|
||
|
diff --git a/src/wayland/datasource.h b/src/wayland/datasource.h
|
||
|
index dc39556ed62..e19d3cf4cd0 100644
|
||
|
--- a/src/wayland/datasource.h
|
||
|
+++ b/src/wayland/datasource.h
|
||
|
@@ -43,9 +43,6 @@ public:
|
||
|
void dndAction(DataDeviceManagerInterface::DnDAction action) override;
|
||
|
void dndCancelled() override;
|
||
|
|
||
|
- bool isDndCancelled() const;
|
||
|
- bool isDropPerformed() const;
|
||
|
-
|
||
|
wl_resource *resource() const;
|
||
|
|
||
|
wl_client *client() const override;
|
||
|
--
|
||
|
GitLab
|
||
|
|