Send a cancelled() event if the dnd data source is not accepted

Currently, Firefox will stuck in "dnd" mode if you try to drag any of
its tabs. The main reason for that is that kwin doesn't send the
wl_data_source.cancelled event if the pointer button has been released
and there is no target surface or if the data source hasn't been
accepted by anyone.

CCBUG: 427528
This commit is contained in:
Vlad Zahorodnii 2020-10-28 13:58:25 +02:00
parent decfb64ada
commit f6e98a34b2
4 changed files with 36 additions and 6 deletions

View file

@ -247,6 +247,9 @@ void DataDeviceInterface::updateDragTarget(SurfaceInterface *surface, quint32 se
return;
}
auto *source = d->seat->dragSource()->dragSource();
if (source) {
source->setAccepted(false);
}
DataOfferInterface *offer = d->createDataOffer(source);
d->drag.surface = surface;
if (d->seat->isDragPointer()) {

View file

@ -26,6 +26,7 @@ public:
DataSourceInterface *q;
QStringList mimeTypes;
DataDeviceManagerInterface::DnDActions supportedDnDActions = DataDeviceManagerInterface::DnDAction::None;
bool isAccepted = false;
protected:
void data_source_destroy_resource(Resource *resource) override;
@ -107,6 +108,7 @@ DataSourceInterface::~DataSourceInterface() = default;
void DataSourceInterface::accept(const QString &mimeType)
{
d->send_target(mimeType);
d->isAccepted = !mimeType.isNull();
}
void DataSourceInterface::requestData(const QString &mimeType, qint32 fd)
@ -181,4 +183,14 @@ wl_client *DataSourceInterface::client() const
return d->resource()->client();
}
bool DataSourceInterface::isAccepted() const
{
return d->isAccepted;
}
void DataSourceInterface::setAccepted(bool accepted)
{
d->isAccepted = accepted;
}
}

View file

@ -49,6 +49,9 @@ public:
wl_client *client() const override;
bool isAccepted() const;
void setAccepted(bool accepted);
private:
friend class DataDeviceManagerInterfacePrivate;
explicit DataSourceInterface(DataDeviceManagerInterface *parent, wl_resource *parentResource);

View file

@ -396,16 +396,28 @@ void SeatInterface::Private::registerPrimarySelectionDevice(PrimarySelectionDevi
void SeatInterface::Private::endDrag(quint32 serial)
{
auto target = drag.target;
QObject::disconnect(drag.destroyConnection);
QObject::disconnect(drag.dragSourceDestroyConnection);
if (drag.source && drag.source->dragSource()) {
drag.source->dragSource()->dropPerformed();
DataDeviceInterface *dragTarget = drag.target;
DataSourceInterface *dragSource = drag.source ? drag.source->dragSource() : nullptr;
if (dragSource) {
// TODO: Also check the current drag-and-drop action.
if (dragTarget && dragSource->isAccepted()) {
dragTarget->drop();
dragSource->dropPerformed();
} else {
if (wl_resource_get_version(dragSource->resource()) >=
WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
dragSource->cancel();
}
}
}
if (target) {
target->drop();
target->updateDragTarget(nullptr, serial);
if (dragTarget) {
dragTarget->updateDragTarget(nullptr, serial);
}
drag = Drag();
emit q->dragSurfaceChanged();
emit q->dragEnded();