File indexing completed on 2024-12-22 05:09:19

0001 /*
0002     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 #include "dataoffer.h"
0007 #include "datadevice.h"
0008 #include "wayland_pointer_p.h"
0009 // Qt
0010 #include <QMimeDatabase>
0011 #include <QMimeType>
0012 // Wayland
0013 #include <wayland-client-protocol.h>
0014 
0015 namespace KWayland
0016 {
0017 namespace Client
0018 {
0019 class Q_DECL_HIDDEN DataOffer::Private
0020 {
0021 public:
0022     Private(wl_data_offer *offer, DataOffer *q);
0023     WaylandPointer<wl_data_offer, wl_data_offer_destroy> dataOffer;
0024     QList<QMimeType> mimeTypes;
0025     DataDeviceManager::DnDActions sourceActions = DataDeviceManager::DnDAction::None;
0026     DataDeviceManager::DnDAction selectedAction = DataDeviceManager::DnDAction::None;
0027 
0028 private:
0029     void offer(const QString &mimeType);
0030     void setAction(DataDeviceManager::DnDAction action);
0031     static void offerCallback(void *data, wl_data_offer *dataOffer, const char *mimeType);
0032     static void sourceActionsCallback(void *data, wl_data_offer *wl_data_offer, uint32_t source_actions);
0033     static void actionCallback(void *data, wl_data_offer *wl_data_offer, uint32_t dnd_action);
0034     DataOffer *q;
0035 
0036     static const struct wl_data_offer_listener s_listener;
0037 };
0038 
0039 #ifndef K_DOXYGEN
0040 const struct wl_data_offer_listener DataOffer::Private::s_listener = {offerCallback, sourceActionsCallback, actionCallback};
0041 #endif
0042 
0043 DataOffer::Private::Private(wl_data_offer *offer, DataOffer *q)
0044     : q(q)
0045 {
0046     dataOffer.setup(offer);
0047     wl_data_offer_add_listener(offer, &s_listener, this);
0048 }
0049 
0050 void DataOffer::Private::offerCallback(void *data, wl_data_offer *dataOffer, const char *mimeType)
0051 {
0052     auto d = reinterpret_cast<Private *>(data);
0053     Q_ASSERT(d->dataOffer == dataOffer);
0054     d->offer(QString::fromUtf8(mimeType));
0055 }
0056 
0057 void DataOffer::Private::offer(const QString &mimeType)
0058 {
0059     QMimeDatabase db;
0060     const auto &m = db.mimeTypeForName(mimeType);
0061     if (m.isValid()) {
0062         mimeTypes << m;
0063         Q_EMIT q->mimeTypeOffered(m.name());
0064     }
0065 }
0066 
0067 void DataOffer::Private::sourceActionsCallback(void *data, wl_data_offer *wl_data_offer, uint32_t source_actions)
0068 {
0069     Q_UNUSED(wl_data_offer)
0070     DataDeviceManager::DnDActions actions;
0071     if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) {
0072         actions |= DataDeviceManager::DnDAction::Copy;
0073     }
0074     if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) {
0075         actions |= DataDeviceManager::DnDAction::Move;
0076     }
0077     if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) {
0078         actions |= DataDeviceManager::DnDAction::Ask;
0079     }
0080     auto d = reinterpret_cast<Private *>(data);
0081     if (d->sourceActions != actions) {
0082         d->sourceActions = actions;
0083         Q_EMIT d->q->sourceDragAndDropActionsChanged();
0084     }
0085 }
0086 
0087 void DataOffer::Private::actionCallback(void *data, wl_data_offer *wl_data_offer, uint32_t dnd_action)
0088 {
0089     Q_UNUSED(wl_data_offer)
0090     auto d = reinterpret_cast<Private *>(data);
0091     switch (dnd_action) {
0092     case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY:
0093         d->setAction(DataDeviceManager::DnDAction::Copy);
0094         break;
0095     case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE:
0096         d->setAction(DataDeviceManager::DnDAction::Move);
0097         break;
0098     case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
0099         d->setAction(DataDeviceManager::DnDAction::Ask);
0100         break;
0101     case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
0102         d->setAction(DataDeviceManager::DnDAction::None);
0103         break;
0104     default:
0105         Q_UNREACHABLE();
0106     }
0107 }
0108 
0109 void DataOffer::Private::setAction(DataDeviceManager::DnDAction action)
0110 {
0111     if (action == selectedAction) {
0112         return;
0113     }
0114     selectedAction = action;
0115     Q_EMIT q->selectedDragAndDropActionChanged();
0116 }
0117 
0118 DataOffer::DataOffer(DataDevice *parent, wl_data_offer *dataOffer)
0119     : QObject(parent)
0120     , d(new Private(dataOffer, this))
0121 {
0122 }
0123 
0124 DataOffer::~DataOffer()
0125 {
0126     release();
0127 }
0128 
0129 void DataOffer::release()
0130 {
0131     d->dataOffer.release();
0132 }
0133 
0134 void DataOffer::destroy()
0135 {
0136     d->dataOffer.destroy();
0137 }
0138 
0139 bool DataOffer::isValid() const
0140 {
0141     return d->dataOffer.isValid();
0142 }
0143 
0144 QList<QMimeType> DataOffer::offeredMimeTypes() const
0145 {
0146     return d->mimeTypes;
0147 }
0148 
0149 void DataOffer::accept(const QMimeType &mimeType, quint32 serial)
0150 {
0151     accept(mimeType.name(), serial);
0152 }
0153 
0154 void DataOffer::accept(const QString &mimeType, quint32 serial)
0155 {
0156     wl_data_offer_accept(d->dataOffer, serial, mimeType.toUtf8().constData());
0157 }
0158 
0159 void DataOffer::receive(const QMimeType &mimeType, qint32 fd)
0160 {
0161     receive(mimeType.name(), fd);
0162 }
0163 
0164 void DataOffer::receive(const QString &mimeType, qint32 fd)
0165 {
0166     Q_ASSERT(isValid());
0167     wl_data_offer_receive(d->dataOffer, mimeType.toUtf8().constData(), fd);
0168 }
0169 
0170 DataOffer::operator wl_data_offer *()
0171 {
0172     return d->dataOffer;
0173 }
0174 
0175 DataOffer::operator wl_data_offer *() const
0176 {
0177     return d->dataOffer;
0178 }
0179 
0180 void DataOffer::dragAndDropFinished()
0181 {
0182     Q_ASSERT(isValid());
0183     if (wl_proxy_get_version(d->dataOffer) < WL_DATA_OFFER_FINISH_SINCE_VERSION) {
0184         return;
0185     }
0186     wl_data_offer_finish(d->dataOffer);
0187 }
0188 
0189 DataDeviceManager::DnDActions DataOffer::sourceDragAndDropActions() const
0190 {
0191     return d->sourceActions;
0192 }
0193 
0194 void DataOffer::setDragAndDropActions(DataDeviceManager::DnDActions supported, DataDeviceManager::DnDAction preferred)
0195 {
0196     if (wl_proxy_get_version(d->dataOffer) < WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION) {
0197         return;
0198     }
0199     auto toWayland = [](DataDeviceManager::DnDAction action) {
0200         switch (action) {
0201         case DataDeviceManager::DnDAction::Copy:
0202             return WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
0203         case DataDeviceManager::DnDAction::Move:
0204             return WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
0205         case DataDeviceManager::DnDAction::Ask:
0206             return WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
0207         case DataDeviceManager::DnDAction::None:
0208             return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
0209         default:
0210             Q_UNREACHABLE();
0211         }
0212     };
0213     uint32_t wlSupported = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
0214     if (supported.testFlag(DataDeviceManager::DnDAction::Copy)) {
0215         wlSupported |= toWayland(DataDeviceManager::DnDAction::Copy);
0216     }
0217     if (supported.testFlag(DataDeviceManager::DnDAction::Move)) {
0218         wlSupported |= toWayland(DataDeviceManager::DnDAction::Move);
0219     }
0220     if (supported.testFlag(DataDeviceManager::DnDAction::Ask)) {
0221         wlSupported |= toWayland(DataDeviceManager::DnDAction::Ask);
0222     }
0223     wl_data_offer_set_actions(d->dataOffer, wlSupported, toWayland(preferred));
0224 }
0225 
0226 DataDeviceManager::DnDAction DataOffer::selectedDragAndDropAction() const
0227 {
0228     return d->selectedAction;
0229 }
0230 
0231 }
0232 }
0233 
0234 #include "moc_dataoffer.cpp"