wayland: Fix drag-and-drop issues in Firefox

At the moment, the data offer initializes supported and preferred action
to "none". But if the target doesn't accept anything the source
provides, the compositor may still need to send action events with "none"

This change makes data offer and data source provide dnd actions wrapped
in std::optional in order to indicate if they have been set explicitly.
This commit is contained in:
Vlad Zahorodnii 2022-05-17 22:57:13 +03:00
parent 20a94d7157
commit 1ee00bc6f9
3 changed files with 28 additions and 21 deletions

View file

@ -212,6 +212,25 @@ void DataDeviceInterface::drop()
d->drag.surface = nullptr;
}
static DataDeviceManagerInterface::DnDAction chooseDndAction(AbstractDataSource *source, DataOfferInterface *offer)
{
if (offer->preferredDragAndDropAction().has_value()) {
if (source->supportedDragAndDropActions().testFlag(*offer->preferredDragAndDropAction())) {
return *offer->preferredDragAndDropAction();
}
}
if (offer->supportedDragAndDropActions().has_value()) {
for (const auto &action : {DataDeviceManagerInterface::DnDAction::Copy, DataDeviceManagerInterface::DnDAction::Move, DataDeviceManagerInterface::DnDAction::Ask}) {
if (source->supportedDragAndDropActions().testFlag(action) && offer->supportedDragAndDropActions()->testFlag(action)) {
return action;
}
}
}
return DataDeviceManagerInterface::DnDAction::None;
}
void DataDeviceInterface::updateDragTarget(SurfaceInterface *surface, quint32 serial)
{
if (d->drag.surface) {
@ -291,21 +310,7 @@ void DataDeviceInterface::updateDragTarget(SurfaceInterface *surface, quint32 se
if (offer) {
offer->sendSourceActions();
auto matchOffers = [dragSource, offer] {
DataDeviceManagerInterface::DnDAction action{DataDeviceManagerInterface::DnDAction::None};
if (dragSource->supportedDragAndDropActions().testFlag(offer->preferredDragAndDropAction())) {
action = offer->preferredDragAndDropAction();
} else {
if (dragSource->supportedDragAndDropActions().testFlag(DataDeviceManagerInterface::DnDAction::Copy)
&& offer->supportedDragAndDropActions().testFlag(DataDeviceManagerInterface::DnDAction::Copy)) {
action = DataDeviceManagerInterface::DnDAction::Copy;
} else if (dragSource->supportedDragAndDropActions().testFlag(DataDeviceManagerInterface::DnDAction::Move)
&& offer->supportedDragAndDropActions().testFlag(DataDeviceManagerInterface::DnDAction::Move)) {
action = DataDeviceManagerInterface::DnDAction::Move;
} else if (dragSource->supportedDragAndDropActions().testFlag(DataDeviceManagerInterface::DnDAction::Ask)
&& offer->supportedDragAndDropActions().testFlag(DataDeviceManagerInterface::DnDAction::Ask)) {
action = DataDeviceManagerInterface::DnDAction::Ask;
}
}
const DataDeviceManagerInterface::DnDAction action = chooseDndAction(dragSource, offer);
offer->dndAction(action);
dragSource->dndAction(action);
};

View file

@ -25,8 +25,8 @@ public:
DataOfferInterface *q;
QPointer<AbstractDataSource> source;
DataDeviceManagerInterface::DnDActions supportedDnDActions = DataDeviceManagerInterface::DnDAction::None;
DataDeviceManagerInterface::DnDAction preferredDnDAction = DataDeviceManagerInterface::DnDAction::None;
std::optional<DataDeviceManagerInterface::DnDActions> supportedDnDActions = std::nullopt;
std::optional<DataDeviceManagerInterface::DnDAction> preferredDnDAction = std::nullopt;
protected:
void data_offer_destroy_resource(Resource *resource) override;
@ -182,12 +182,12 @@ wl_resource *DataOfferInterface::resource() const
return d->resource()->handle;
}
DataDeviceManagerInterface::DnDActions DataOfferInterface::supportedDragAndDropActions() const
std::optional<DataDeviceManagerInterface::DnDActions> DataOfferInterface::supportedDragAndDropActions() const
{
return d->supportedDnDActions;
}
DataDeviceManagerInterface::DnDAction DataOfferInterface::preferredDragAndDropAction() const
std::optional<DataDeviceManagerInterface::DnDAction> DataOfferInterface::preferredDragAndDropAction() const
{
return d->preferredDnDAction;
}

View file

@ -12,6 +12,8 @@
#include "datadevicemanager_interface.h"
#include <optional>
namespace KWaylandServer
{
class DataDeviceInterface;
@ -35,12 +37,12 @@ public:
/**
* @returns The Drag and Drop actions supported by this DataOfferInterface.
*/
DataDeviceManagerInterface::DnDActions supportedDragAndDropActions() const;
std::optional<DataDeviceManagerInterface::DnDActions> supportedDragAndDropActions() const;
/**
* @returns The preferred Drag and Drop action of this DataOfferInterface.
*/
DataDeviceManagerInterface::DnDAction preferredDragAndDropAction() const;
std::optional<DataDeviceManagerInterface::DnDAction> preferredDragAndDropAction() const;
/**
* This event indicates the @p action selected by the compositor after matching the