File indexing completed on 2024-11-10 04:57:26
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 "dataoffer.h" 0008 #include "datadevice.h" 0009 #include "datasource.h" 0010 0011 // Qt 0012 #include <QPointer> 0013 #include <QStringList> 0014 // Wayland 0015 #include <qwayland-server-wayland.h> 0016 // system 0017 #include <unistd.h> 0018 0019 namespace KWin 0020 { 0021 class DataOfferInterfacePrivate : public QtWaylandServer::wl_data_offer 0022 { 0023 public: 0024 DataOfferInterfacePrivate(AbstractDataSource *source, DataOfferInterface *q, wl_resource *resource); 0025 DataOfferInterface *q; 0026 QPointer<AbstractDataSource> source; 0027 0028 std::optional<DataDeviceManagerInterface::DnDActions> supportedDnDActions = std::nullopt; 0029 std::optional<DataDeviceManagerInterface::DnDAction> preferredDnDAction = std::nullopt; 0030 0031 protected: 0032 void data_offer_destroy_resource(Resource *resource) override; 0033 void data_offer_accept(Resource *resource, uint32_t serial, const QString &mime_type) override; 0034 void data_offer_receive(Resource *resource, const QString &mime_type, int32_t fd) override; 0035 void data_offer_destroy(Resource *resource) override; 0036 void data_offer_finish(Resource *resource) override; 0037 void data_offer_set_actions(Resource *resource, uint32_t dnd_actions, uint32_t preferred_action) override; 0038 }; 0039 0040 DataOfferInterfacePrivate::DataOfferInterfacePrivate(AbstractDataSource *_source, DataOfferInterface *_q, wl_resource *resource) 0041 : QtWaylandServer::wl_data_offer(resource) 0042 , q(_q) 0043 , source(_source) 0044 { 0045 // defaults are set to sensible values for < version 3 interfaces 0046 if (wl_resource_get_version(resource) < WL_DATA_OFFER_ACTION_SINCE_VERSION) { 0047 supportedDnDActions = DataDeviceManagerInterface::DnDAction::Copy | DataDeviceManagerInterface::DnDAction::Move; 0048 preferredDnDAction = DataDeviceManagerInterface::DnDAction::Copy; 0049 } 0050 } 0051 0052 void DataOfferInterfacePrivate::data_offer_accept(Resource *resource, uint32_t serial, const QString &mime_type) 0053 { 0054 if (!source) { 0055 return; 0056 } 0057 source->accept(mime_type); 0058 } 0059 0060 void DataOfferInterfacePrivate::data_offer_receive(Resource *resource, const QString &mime_type, int32_t fd) 0061 { 0062 if (!source) { 0063 close(fd); 0064 return; 0065 } 0066 source->requestData(mime_type, fd); 0067 } 0068 0069 void DataOfferInterfacePrivate::data_offer_destroy(QtWaylandServer::wl_data_offer::Resource *resource) 0070 { 0071 wl_resource_destroy(resource->handle); 0072 } 0073 0074 void DataOfferInterfacePrivate::data_offer_finish(Resource *resource) 0075 { 0076 if (!source) { 0077 return; 0078 } 0079 source->dndFinished(); 0080 // TODO: It is a client error to perform other requests than wl_data_offer.destroy after this one 0081 } 0082 0083 void DataOfferInterfacePrivate::data_offer_set_actions(Resource *resource, uint32_t dnd_actions, uint32_t preferred_action) 0084 { 0085 // TODO: check it's drag and drop, otherwise send error 0086 // verify that the no other actions are sent 0087 if (dnd_actions 0088 & ~(QtWaylandServer::wl_data_device_manager::dnd_action_copy | QtWaylandServer::wl_data_device_manager::dnd_action_move 0089 | QtWaylandServer::wl_data_device_manager::dnd_action_ask)) { 0090 wl_resource_post_error(resource->handle, error_invalid_action_mask, "Invalid action mask"); 0091 return; 0092 } 0093 0094 if (preferred_action != QtWaylandServer::wl_data_device_manager::dnd_action_copy 0095 && preferred_action != QtWaylandServer::wl_data_device_manager::dnd_action_move 0096 && preferred_action != QtWaylandServer::wl_data_device_manager::dnd_action_ask 0097 && preferred_action != QtWaylandServer::wl_data_device_manager::dnd_action_none) { 0098 wl_resource_post_error(resource->handle, error_invalid_action, "Invalid preferred action"); 0099 return; 0100 } 0101 0102 DataDeviceManagerInterface::DnDActions supportedActions; 0103 if (dnd_actions & QtWaylandServer::wl_data_device_manager::dnd_action_copy) { 0104 supportedActions |= DataDeviceManagerInterface::DnDAction::Copy; 0105 } 0106 if (dnd_actions & QtWaylandServer::wl_data_device_manager::dnd_action_move) { 0107 supportedActions |= DataDeviceManagerInterface::DnDAction::Move; 0108 } 0109 if (dnd_actions & QtWaylandServer::wl_data_device_manager::dnd_action_ask) { 0110 supportedActions |= DataDeviceManagerInterface::DnDAction::Ask; 0111 } 0112 0113 DataDeviceManagerInterface::DnDAction preferredAction = DataDeviceManagerInterface::DnDAction::None; 0114 if (preferred_action == QtWaylandServer::wl_data_device_manager::dnd_action_copy) { 0115 preferredAction = DataDeviceManagerInterface::DnDAction::Copy; 0116 } else if (preferred_action == QtWaylandServer::wl_data_device_manager::dnd_action_move) { 0117 preferredAction = DataDeviceManagerInterface::DnDAction::Move; 0118 } else if (preferred_action == QtWaylandServer::wl_data_device_manager::dnd_action_ask) { 0119 preferredAction = DataDeviceManagerInterface::DnDAction::Ask; 0120 } 0121 0122 if (supportedDnDActions != supportedActions || preferredDnDAction != preferredAction) { 0123 supportedDnDActions = supportedActions; 0124 preferredDnDAction = preferredAction; 0125 Q_EMIT q->dragAndDropActionsChanged(); 0126 } 0127 } 0128 0129 void DataOfferInterface::sendSourceActions() 0130 { 0131 if (!d->source) { 0132 return; 0133 } 0134 if (d->resource()->version() < WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) { 0135 return; 0136 } 0137 uint32_t wlActions = QtWaylandServer::wl_data_device_manager::dnd_action_none; 0138 const auto actions = d->source->supportedDragAndDropActions(); 0139 if (actions.testFlag(DataDeviceManagerInterface::DnDAction::Copy)) { 0140 wlActions |= QtWaylandServer::wl_data_device_manager::dnd_action_copy; 0141 } 0142 if (actions.testFlag(DataDeviceManagerInterface::DnDAction::Move)) { 0143 wlActions |= QtWaylandServer::wl_data_device_manager::dnd_action_move; 0144 } 0145 if (actions.testFlag(DataDeviceManagerInterface::DnDAction::Ask)) { 0146 wlActions |= QtWaylandServer::wl_data_device_manager::dnd_action_ask; 0147 } 0148 d->send_source_actions(wlActions); 0149 } 0150 0151 void DataOfferInterfacePrivate::data_offer_destroy_resource(QtWaylandServer::wl_data_offer::Resource *resource) 0152 { 0153 delete q; 0154 } 0155 0156 DataOfferInterface::DataOfferInterface(AbstractDataSource *source, wl_resource *resource) 0157 : QObject(nullptr) 0158 , d(new DataOfferInterfacePrivate(source, this, resource)) 0159 { 0160 Q_ASSERT(source); 0161 connect(source, &DataSourceInterface::mimeTypeOffered, this, [this](const QString &mimeType) { 0162 d->send_offer(mimeType); 0163 }); 0164 } 0165 0166 DataOfferInterface::~DataOfferInterface() = default; 0167 0168 void DataOfferInterface::sendAllOffers() 0169 { 0170 for (const QString &mimeType : d->source->mimeTypes()) { 0171 d->send_offer(mimeType); 0172 } 0173 } 0174 0175 wl_resource *DataOfferInterface::resource() const 0176 { 0177 return d->resource()->handle; 0178 } 0179 0180 std::optional<DataDeviceManagerInterface::DnDActions> DataOfferInterface::supportedDragAndDropActions() const 0181 { 0182 return d->supportedDnDActions; 0183 } 0184 0185 std::optional<DataDeviceManagerInterface::DnDAction> DataOfferInterface::preferredDragAndDropAction() const 0186 { 0187 return d->preferredDnDAction; 0188 } 0189 0190 void DataOfferInterface::dndAction(DataDeviceManagerInterface::DnDAction action) 0191 { 0192 if (d->resource()->version() < WL_DATA_OFFER_ACTION_SINCE_VERSION) { 0193 return; 0194 } 0195 uint32_t wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_none; 0196 if (action == DataDeviceManagerInterface::DnDAction::Copy) { 0197 wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_copy; 0198 } else if (action == DataDeviceManagerInterface::DnDAction::Move) { 0199 wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_move; 0200 } else if (action == DataDeviceManagerInterface::DnDAction::Ask) { 0201 wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_ask; 0202 } 0203 d->send_action(wlAction); 0204 } 0205 } 0206 0207 #include "moc_dataoffer.cpp"