File indexing completed on 2024-05-19 16:35:17

0001 /*
0002     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0003     SPDX-FileCopyrightText: 2020 David Edmundson <davidedmundson@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 #include "datasource_interface.h"
0008 #include "clientconnection.h"
0009 #include "datadevicemanager_interface.h"
0010 #include "utils.h"
0011 // Qt
0012 #include <QStringList>
0013 // Wayland
0014 #include <qwayland-server-wayland.h>
0015 // system
0016 #include <unistd.h>
0017 
0018 namespace KWaylandServer
0019 {
0020 class DataSourceInterfacePrivate : public QtWaylandServer::wl_data_source
0021 {
0022 public:
0023     DataSourceInterfacePrivate(DataSourceInterface *_q, ::wl_resource *resource);
0024 
0025     DataSourceInterface *q;
0026     QStringList mimeTypes;
0027     DataDeviceManagerInterface::DnDActions supportedDnDActions = DataDeviceManagerInterface::DnDAction::None;
0028     DataDeviceManagerInterface::DnDAction selectedDndAction = DataDeviceManagerInterface::DnDAction::None;
0029     bool isAccepted = false;
0030 
0031 protected:
0032     void data_source_destroy_resource(Resource *resource) override;
0033     void data_source_offer(Resource *resource, const QString &mime_type) override;
0034     void data_source_destroy(Resource *resource) override;
0035     void data_source_set_actions(Resource *resource, uint32_t dnd_actions) override;
0036 
0037 private:
0038     void offer(const QString &mimeType);
0039 };
0040 
0041 DataSourceInterfacePrivate::DataSourceInterfacePrivate(DataSourceInterface *_q, ::wl_resource *resource)
0042     : QtWaylandServer::wl_data_source(resource)
0043     , q(_q)
0044 {
0045 }
0046 
0047 void DataSourceInterfacePrivate::data_source_destroy_resource(Resource *resource)
0048 {
0049     Q_EMIT q->aboutToBeDestroyed();
0050     delete q;
0051 }
0052 
0053 void DataSourceInterfacePrivate::data_source_offer(QtWaylandServer::wl_data_source::Resource *resource, const QString &mime_type)
0054 {
0055     mimeTypes << mime_type;
0056     Q_EMIT q->mimeTypeOffered(mime_type);
0057 }
0058 
0059 void DataSourceInterfacePrivate::data_source_destroy(QtWaylandServer::wl_data_source::Resource *resource)
0060 {
0061     wl_resource_destroy(resource->handle);
0062 }
0063 
0064 void DataSourceInterfacePrivate::offer(const QString &mimeType)
0065 {
0066     mimeTypes << mimeType;
0067     Q_EMIT q->mimeTypeOffered(mimeType);
0068 }
0069 
0070 void DataSourceInterfacePrivate::data_source_set_actions(Resource *resource, uint32_t dnd_actions)
0071 {
0072     // verify that the no other actions are sent
0073     if (dnd_actions
0074         & ~(QtWaylandServer::wl_data_device_manager::dnd_action_copy | QtWaylandServer::wl_data_device_manager::dnd_action_move
0075             | QtWaylandServer::wl_data_device_manager::dnd_action_ask)) {
0076         wl_resource_post_error(resource->handle, error_invalid_action_mask, "Invalid action mask");
0077         return;
0078     }
0079     DataDeviceManagerInterface::DnDActions supportedActions;
0080     if (dnd_actions & QtWaylandServer::wl_data_device_manager::dnd_action_copy) {
0081         supportedActions |= DataDeviceManagerInterface::DnDAction::Copy;
0082     }
0083     if (dnd_actions & QtWaylandServer::wl_data_device_manager::dnd_action_move) {
0084         supportedActions |= DataDeviceManagerInterface::DnDAction::Move;
0085     }
0086     if (dnd_actions & QtWaylandServer::wl_data_device_manager::dnd_action_ask) {
0087         supportedActions |= DataDeviceManagerInterface::DnDAction::Ask;
0088     }
0089     if (supportedDnDActions != supportedActions) {
0090         supportedDnDActions = supportedActions;
0091         Q_EMIT q->supportedDragAndDropActionsChanged();
0092     }
0093 }
0094 
0095 DataSourceInterface::DataSourceInterface(wl_resource *resource)
0096     : d(new DataSourceInterfacePrivate(this, resource))
0097 {
0098     if (d->resource()->version() < WL_DATA_SOURCE_ACTION_SINCE_VERSION) {
0099         d->supportedDnDActions = DataDeviceManagerInterface::DnDAction::Copy;
0100     }
0101 }
0102 
0103 DataSourceInterface::~DataSourceInterface() = default;
0104 
0105 void DataSourceInterface::accept(const QString &mimeType)
0106 {
0107     d->send_target(mimeType);
0108     d->isAccepted = !mimeType.isNull();
0109 }
0110 
0111 void DataSourceInterface::requestData(const QString &mimeType, qint32 fd)
0112 {
0113     d->send_send(mimeType, int32_t(fd));
0114     close(fd);
0115 }
0116 
0117 void DataSourceInterface::cancel()
0118 {
0119     d->send_cancelled();
0120 }
0121 
0122 QStringList DataSourceInterface::mimeTypes() const
0123 {
0124     return d->mimeTypes;
0125 }
0126 
0127 DataSourceInterface *DataSourceInterface::get(wl_resource *native)
0128 {
0129     if (auto sourcePrivate = resource_cast<DataSourceInterfacePrivate *>(native)) {
0130         return sourcePrivate->q;
0131     }
0132     return nullptr;
0133 }
0134 
0135 DataDeviceManagerInterface::DnDActions DataSourceInterface::supportedDragAndDropActions() const
0136 {
0137     return d->supportedDnDActions;
0138 }
0139 
0140 DataDeviceManagerInterface::DnDAction DataSourceInterface::selectedDndAction() const
0141 {
0142     return d->selectedDndAction;
0143 }
0144 
0145 void DataSourceInterface::dropPerformed()
0146 {
0147     if (d->resource()->version() < WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) {
0148         return;
0149     }
0150     d->send_dnd_drop_performed();
0151 }
0152 
0153 void DataSourceInterface::dndFinished()
0154 {
0155     if (d->resource()->version() < WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
0156         return;
0157     }
0158     d->send_dnd_finished();
0159 }
0160 
0161 void DataSourceInterface::dndAction(DataDeviceManagerInterface::DnDAction action)
0162 {
0163     d->selectedDndAction = action;
0164 
0165     if (d->resource()->version() < WL_DATA_SOURCE_ACTION_SINCE_VERSION) {
0166         return;
0167     }
0168     uint32_t wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_none;
0169     if (action == DataDeviceManagerInterface::DnDAction::Copy) {
0170         wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_copy;
0171     } else if (action == DataDeviceManagerInterface::DnDAction::Move) {
0172         wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_move;
0173     } else if (action == DataDeviceManagerInterface::DnDAction::Ask) {
0174         wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_ask;
0175     }
0176     d->send_action(wlAction);
0177 }
0178 
0179 void DataSourceInterface::dndCancelled()
0180 {
0181     // for v3 or less, cancel should not be called after a failed drag operation
0182     if (wl_resource_get_version(resource()) < 3) {
0183         return;
0184     }
0185     d->send_cancelled();
0186 }
0187 
0188 wl_resource *DataSourceInterface::resource() const
0189 {
0190     return d->resource()->handle;
0191 }
0192 
0193 wl_client *DataSourceInterface::client() const
0194 {
0195     return d->resource()->client();
0196 }
0197 
0198 bool DataSourceInterface::isAccepted() const
0199 {
0200     return d->isAccepted;
0201 }
0202 
0203 void DataSourceInterface::setAccepted(bool accepted)
0204 {
0205     d->isAccepted = accepted;
0206 }
0207 
0208 }