File indexing completed on 2024-04-28 03:54:16

0001 /*
0002     SPDX-FileCopyrightText: 2020 David Edmundson <davidedmundson@kde.org>
0003     SPDX-FileCopyrightText: 2021 Méven Car <meven.car@enioka.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "waylandclipboard_p.h"
0009 
0010 #include <QBuffer>
0011 #include <QFile>
0012 #include <QGuiApplication>
0013 #include <QImageReader>
0014 #include <QImageWriter>
0015 #include <QMimeData>
0016 #include <QPointer>
0017 #include <QWaylandClientExtension>
0018 #include <QWindow>
0019 #include <QtWaylandClientVersion>
0020 #include <qpa/qplatformnativeinterface.h>
0021 
0022 #include <errno.h>
0023 #include <poll.h>
0024 #include <signal.h>
0025 #include <string.h>
0026 #include <unistd.h>
0027 
0028 #include "qwayland-wayland.h"
0029 #include "qwayland-wlr-data-control-unstable-v1.h"
0030 
0031 static inline QString applicationQtXImageLiteral()
0032 {
0033     return QStringLiteral("application/x-qt-image");
0034 }
0035 
0036 // copied from https://code.woboq.org/qt5/qtbase/src/gui/kernel/qinternalmimedata.cpp.html
0037 static QString utf8Text()
0038 {
0039     return QStringLiteral("text/plain;charset=utf-8");
0040 }
0041 
0042 static QStringList imageMimeFormats(const QList<QByteArray> &imageFormats)
0043 {
0044     QStringList formats;
0045     formats.reserve(imageFormats.size());
0046     for (const auto &format : imageFormats)
0047         formats.append(QLatin1String("image/") + QLatin1String(format.toLower()));
0048     // put png at the front because it is best
0049     int pngIndex = formats.indexOf(QLatin1String("image/png"));
0050     if (pngIndex != -1 && pngIndex != 0)
0051         formats.move(pngIndex, 0);
0052     return formats;
0053 }
0054 
0055 static inline QStringList imageReadMimeFormats()
0056 {
0057     return imageMimeFormats(QImageReader::supportedImageFormats());
0058 }
0059 
0060 static inline QStringList imageWriteMimeFormats()
0061 {
0062     return imageMimeFormats(QImageWriter::supportedImageFormats());
0063 }
0064 // end copied
0065 
0066 class DataControlDeviceManager : public QWaylandClientExtensionTemplate<DataControlDeviceManager>, public QtWayland::zwlr_data_control_manager_v1
0067 {
0068     Q_OBJECT
0069 public:
0070     DataControlDeviceManager()
0071         : QWaylandClientExtensionTemplate<DataControlDeviceManager>(2)
0072     {
0073     }
0074 
0075     void instantiate()
0076     {
0077         initialize();
0078     }
0079 
0080     ~DataControlDeviceManager()
0081     {
0082         if (isInitialized()) {
0083             destroy();
0084         }
0085     }
0086 };
0087 
0088 class DataControlOffer : public QMimeData, public QtWayland::zwlr_data_control_offer_v1
0089 {
0090     Q_OBJECT
0091 public:
0092     DataControlOffer(struct ::zwlr_data_control_offer_v1 *id)
0093         : QtWayland::zwlr_data_control_offer_v1(id)
0094     {
0095     }
0096 
0097     ~DataControlOffer()
0098     {
0099         destroy();
0100     }
0101 
0102     QStringList formats() const override
0103     {
0104         return m_receivedFormats;
0105     }
0106 
0107     bool containsImageData() const
0108     {
0109         if (m_receivedFormats.contains(applicationQtXImageLiteral())) {
0110             return true;
0111         }
0112         const auto formats = imageReadMimeFormats();
0113         for (const auto &receivedFormat : m_receivedFormats) {
0114             if (formats.contains(receivedFormat)) {
0115                 return true;
0116             }
0117         }
0118         return false;
0119     }
0120 
0121     bool hasFormat(const QString &mimeType) const override
0122     {
0123         if (mimeType == QStringLiteral("text/plain") && m_receivedFormats.contains(utf8Text())) {
0124             return true;
0125         }
0126         if (m_receivedFormats.contains(mimeType)) {
0127             return true;
0128         }
0129 
0130         // If we have image data
0131         if (containsImageData()) {
0132             // is the requested output mimeType supported ?
0133             const QStringList imageFormats = imageWriteMimeFormats();
0134             for (const QString &imageFormat : imageFormats) {
0135                 if (imageFormat == mimeType) {
0136                     return true;
0137                 }
0138             }
0139             if (mimeType == applicationQtXImageLiteral()) {
0140                 return true;
0141             }
0142         }
0143 
0144         return false;
0145     }
0146 
0147 protected:
0148     void zwlr_data_control_offer_v1_offer(const QString &mime_type) override
0149     {
0150         m_receivedFormats << mime_type;
0151     }
0152 
0153     QVariant retrieveData(const QString &mimeType, QMetaType type) const override;
0154 
0155 private:
0156     /** reads data from a file descriptor with a timeout of 1 second
0157      *  true if data is read successfully
0158      */
0159     static bool readData(int fd, QByteArray &data);
0160     QStringList m_receivedFormats;
0161 };
0162 
0163 QVariant DataControlOffer::retrieveData(const QString &mimeType, QMetaType type) const
0164 {
0165     Q_UNUSED(type);
0166 
0167     QString mime;
0168     if (!m_receivedFormats.contains(mimeType)) {
0169         if (mimeType == QStringLiteral("text/plain") && m_receivedFormats.contains(utf8Text())) {
0170             mime = utf8Text();
0171         } else if (mimeType == applicationQtXImageLiteral()) {
0172             const auto writeFormats = imageWriteMimeFormats();
0173             for (const auto &receivedFormat : m_receivedFormats) {
0174                 if (writeFormats.contains(receivedFormat)) {
0175                     mime = receivedFormat;
0176                     break;
0177                 }
0178             }
0179             if (mime.isEmpty()) {
0180                 // default exchange format
0181                 mime = QStringLiteral("image/png");
0182             }
0183         }
0184 
0185         if (mime.isEmpty()) {
0186             return QVariant();
0187         }
0188     } else {
0189         mime = mimeType;
0190     }
0191 
0192     int pipeFds[2];
0193     if (pipe(pipeFds) != 0) {
0194         return QVariant();
0195     }
0196 
0197     auto t = const_cast<DataControlOffer *>(this);
0198     t->receive(mime, pipeFds[1]);
0199 
0200     close(pipeFds[1]);
0201 
0202     /*
0203      * Ideally we need to introduce a non-blocking QMimeData object
0204      * Or a non-blocking constructor to QMimeData with the mimetypes that are relevant
0205      *
0206      * However this isn't actually any worse than X.
0207      */
0208 
0209     QPlatformNativeInterface *native = qGuiApp->platformNativeInterface();
0210     auto display = static_cast<struct ::wl_display *>(native->nativeResourceForIntegration("wl_display"));
0211     wl_display_flush(display);
0212 
0213     QFile readPipe;
0214     if (readPipe.open(pipeFds[0], QIODevice::ReadOnly)) {
0215         QByteArray data;
0216         if (readData(pipeFds[0], data)) {
0217             close(pipeFds[0]);
0218 
0219             if (mimeType == applicationQtXImageLiteral()) {
0220                 QImage img = QImage::fromData(data, mime.mid(mime.indexOf(QLatin1Char('/')) + 1).toLatin1().toUpper().data());
0221                 if (!img.isNull()) {
0222                     return img;
0223                 }
0224             }
0225             return data;
0226         }
0227         close(pipeFds[0]);
0228     }
0229     return QVariant();
0230 }
0231 
0232 bool DataControlOffer::readData(int fd, QByteArray &data)
0233 {
0234     pollfd pfds[1];
0235     pfds[0].fd = fd;
0236     pfds[0].events = POLLIN;
0237 
0238     while (true) {
0239         const int ready = poll(pfds, 1, 1000);
0240         if (ready < 0) {
0241             if (errno != EINTR) {
0242                 qWarning("DataControlOffer: poll() failed: %s", strerror(errno));
0243                 return false;
0244             }
0245         } else if (ready == 0) {
0246             qWarning("DataControlOffer: timeout reading from pipe");
0247             return false;
0248         } else {
0249             char buf[4096];
0250             int n = read(fd, buf, sizeof buf);
0251 
0252             if (n < 0) {
0253                 qWarning("DataControlOffer: read() failed: %s", strerror(errno));
0254                 return false;
0255             } else if (n == 0) {
0256                 return true;
0257             } else if (n > 0) {
0258                 data.append(buf, n);
0259             }
0260         }
0261     }
0262 }
0263 
0264 class DataControlSource : public QObject, public QtWayland::zwlr_data_control_source_v1
0265 {
0266     Q_OBJECT
0267 public:
0268     DataControlSource(struct ::zwlr_data_control_source_v1 *id, QMimeData *mimeData);
0269     DataControlSource() = default;
0270     ~DataControlSource()
0271     {
0272         destroy();
0273     }
0274 
0275     QMimeData *mimeData()
0276     {
0277         return m_mimeData.get();
0278     }
0279     std::unique_ptr<QMimeData> releaseMimeData()
0280     {
0281         return std::move(m_mimeData);
0282     }
0283 
0284 Q_SIGNALS:
0285     void cancelled();
0286 
0287 protected:
0288     void zwlr_data_control_source_v1_send(const QString &mime_type, int32_t fd) override;
0289     void zwlr_data_control_source_v1_cancelled() override;
0290 
0291 private:
0292     std::unique_ptr<QMimeData> m_mimeData;
0293 };
0294 
0295 DataControlSource::DataControlSource(struct ::zwlr_data_control_source_v1 *id, QMimeData *mimeData)
0296     : QtWayland::zwlr_data_control_source_v1(id)
0297     , m_mimeData(mimeData)
0298 {
0299     const auto formats = mimeData->formats();
0300     for (const QString &format : formats) {
0301         offer(format);
0302     }
0303     if (mimeData->hasText()) {
0304         // ensure GTK applications get this mimetype to avoid them discarding the offer
0305         offer(QStringLiteral("text/plain;charset=utf-8"));
0306     }
0307 
0308     if (mimeData->hasImage()) {
0309         const QStringList imageFormats = imageWriteMimeFormats();
0310         for (const QString &imageFormat : imageFormats) {
0311             if (!formats.contains(imageFormat)) {
0312                 offer(imageFormat);
0313             }
0314         }
0315     }
0316 }
0317 
0318 void DataControlSource::zwlr_data_control_source_v1_send(const QString &mime_type, int32_t fd)
0319 {
0320     QString send_mime_type = mime_type;
0321     if (send_mime_type == QStringLiteral("text/plain;charset=utf-8")) {
0322         // if we get a request on the fallback mime, send the data from the original mime type
0323         send_mime_type = QStringLiteral("text/plain");
0324     }
0325 
0326     QByteArray ba;
0327     if (m_mimeData->hasImage()) {
0328         // adapted from QInternalMimeData::renderDataHelper
0329         if (mime_type == applicationQtXImageLiteral()) {
0330             QImage image = qvariant_cast<QImage>(m_mimeData->imageData());
0331             QBuffer buf(&ba);
0332             buf.open(QBuffer::WriteOnly);
0333             // would there not be PNG ??
0334             image.save(&buf, "PNG");
0335 
0336         } else if (mime_type.startsWith(QLatin1String("image/"))) {
0337             QImage image = qvariant_cast<QImage>(m_mimeData->imageData());
0338             QBuffer buf(&ba);
0339             buf.open(QBuffer::WriteOnly);
0340             image.save(&buf, mime_type.mid(mime_type.indexOf(QLatin1Char('/')) + 1).toLatin1().toUpper().data());
0341         }
0342         // end adapted
0343     } else {
0344         ba = m_mimeData->data(send_mime_type);
0345     }
0346 
0347     // Create a sigpipe handler that does nothing, or clients may be forced to terminate
0348     // if the pipe is closed in the other end.
0349     struct sigaction action, oldAction;
0350     action.sa_handler = SIG_IGN;
0351     sigemptyset(&action.sa_mask);
0352     action.sa_flags = 0;
0353     sigaction(SIGPIPE, &action, &oldAction);
0354     write(fd, ba.constData(), ba.size());
0355     sigaction(SIGPIPE, &oldAction, nullptr);
0356     close(fd);
0357 }
0358 
0359 void DataControlSource::zwlr_data_control_source_v1_cancelled()
0360 {
0361     Q_EMIT cancelled();
0362 }
0363 
0364 class DataControlDevice : public QObject, public QtWayland::zwlr_data_control_device_v1
0365 {
0366     Q_OBJECT
0367 public:
0368     DataControlDevice(struct ::zwlr_data_control_device_v1 *id)
0369         : QtWayland::zwlr_data_control_device_v1(id)
0370     {
0371     }
0372 
0373     ~DataControlDevice()
0374     {
0375         destroy();
0376     }
0377 
0378     void setSelection(std::unique_ptr<DataControlSource> selection);
0379     QMimeData *receivedSelection()
0380     {
0381         return m_receivedSelection.get();
0382     }
0383     QMimeData *selection()
0384     {
0385         return m_selection ? m_selection->mimeData() : nullptr;
0386     }
0387 
0388     void setPrimarySelection(std::unique_ptr<DataControlSource> selection);
0389     QMimeData *receivedPrimarySelection()
0390     {
0391         return m_receivedPrimarySelection.get();
0392     }
0393     QMimeData *primarySelection()
0394     {
0395         return m_primarySelection ? m_primarySelection->mimeData() : nullptr;
0396     }
0397 
0398 Q_SIGNALS:
0399     void receivedSelectionChanged();
0400     void selectionChanged();
0401 
0402     void receivedPrimarySelectionChanged();
0403     void primarySelectionChanged();
0404 
0405 protected:
0406     void zwlr_data_control_device_v1_data_offer(struct ::zwlr_data_control_offer_v1 *id) override
0407     {
0408         // this will become memory managed when we retrieve the selection event
0409         // a compositor calling data_offer without doing that would be a bug
0410         new DataControlOffer(id);
0411     }
0412 
0413     void zwlr_data_control_device_v1_selection(struct ::zwlr_data_control_offer_v1 *id) override
0414     {
0415         if (!id) {
0416             m_receivedSelection.reset();
0417         } else {
0418             auto derivated = QtWayland::zwlr_data_control_offer_v1::fromObject(id);
0419             auto offer = dynamic_cast<DataControlOffer *>(derivated); // dynamic because of the dual inheritance
0420             m_receivedSelection.reset(offer);
0421         }
0422         Q_EMIT receivedSelectionChanged();
0423     }
0424 
0425     void zwlr_data_control_device_v1_primary_selection(struct ::zwlr_data_control_offer_v1 *id) override
0426     {
0427         if (!id) {
0428             m_receivedPrimarySelection.reset();
0429         } else {
0430             auto derivated = QtWayland::zwlr_data_control_offer_v1::fromObject(id);
0431             auto offer = dynamic_cast<DataControlOffer *>(derivated); // dynamic because of the dual inheritance
0432             m_receivedPrimarySelection.reset(offer);
0433         }
0434         Q_EMIT receivedPrimarySelectionChanged();
0435     }
0436 
0437 private:
0438     std::unique_ptr<DataControlSource> m_selection; // selection set locally
0439     std::unique_ptr<DataControlOffer> m_receivedSelection; // latest selection set from externally to here
0440 
0441     std::unique_ptr<DataControlSource> m_primarySelection; // selection set locally
0442     std::unique_ptr<DataControlOffer> m_receivedPrimarySelection; // latest selection set from externally to here
0443     friend WaylandClipboard;
0444 };
0445 
0446 void DataControlDevice::setSelection(std::unique_ptr<DataControlSource> selection)
0447 {
0448     m_selection = std::move(selection);
0449     connect(m_selection.get(), &DataControlSource::cancelled, this, [this]() {
0450         m_selection.reset();
0451     });
0452     set_selection(m_selection->object());
0453     Q_EMIT selectionChanged();
0454 }
0455 
0456 void DataControlDevice::setPrimarySelection(std::unique_ptr<DataControlSource> selection)
0457 {
0458     m_primarySelection = std::move(selection);
0459     connect(m_primarySelection.get(), &DataControlSource::cancelled, this, [this]() {
0460         m_primarySelection.reset();
0461     });
0462 
0463     if (zwlr_data_control_device_v1_get_version(object()) >= ZWLR_DATA_CONTROL_DEVICE_V1_SET_PRIMARY_SELECTION_SINCE_VERSION) {
0464         set_primary_selection(m_primarySelection->object());
0465         Q_EMIT primarySelectionChanged();
0466     }
0467 }
0468 class Keyboard;
0469 // We are binding to Seat/Keyboard manually because we want to react to gaining focus but inside Qt the events are Qt and arrive to late
0470 class KeyboardFocusWatcher : public QWaylandClientExtensionTemplate<KeyboardFocusWatcher>, public QtWayland::wl_seat
0471 {
0472     Q_OBJECT
0473 public:
0474     KeyboardFocusWatcher()
0475         : QWaylandClientExtensionTemplate(5)
0476     {
0477         initialize();
0478         auto native = qGuiApp->platformNativeInterface();
0479         auto display = static_cast<struct ::wl_display *>(native->nativeResourceForIntegration("wl_display"));
0480         // so we get capabilities
0481         wl_display_roundtrip(display);
0482     }
0483     ~KeyboardFocusWatcher() override
0484     {
0485         if (isActive()) {
0486             release();
0487         }
0488     }
0489     void seat_capabilities(uint32_t capabilities) override
0490     {
0491         const bool hasKeyboard = capabilities & capability_keyboard;
0492         if (hasKeyboard && !m_keyboard) {
0493             m_keyboard = std::make_unique<Keyboard>(get_keyboard(), *this);
0494         } else if (!hasKeyboard && m_keyboard) {
0495             m_keyboard.reset();
0496         }
0497     }
0498     bool hasFocus() const
0499     {
0500         return m_focus;
0501     }
0502 Q_SIGNALS:
0503     void keyboardEntered();
0504 
0505 private:
0506     friend Keyboard;
0507     bool m_focus = false;
0508     std::unique_ptr<Keyboard> m_keyboard;
0509 };
0510 
0511 class Keyboard : public QtWayland::wl_keyboard
0512 {
0513 public:
0514     Keyboard(::wl_keyboard *keyboard, KeyboardFocusWatcher &seat)
0515         : wl_keyboard(keyboard)
0516         , m_seat(seat)
0517     {
0518     }
0519     ~Keyboard()
0520     {
0521         release();
0522     }
0523 
0524 private:
0525     void keyboard_enter([[maybe_unused]] uint32_t serial, [[maybe_unused]] wl_surface *surface, [[maybe_unused]] wl_array *keys) override
0526     {
0527         m_seat.m_focus = true;
0528         Q_EMIT m_seat.keyboardEntered();
0529     }
0530     void keyboard_leave([[maybe_unused]] uint32_t serial, [[maybe_unused]] wl_surface *surface) override
0531     {
0532         m_seat.m_focus = false;
0533     }
0534     KeyboardFocusWatcher &m_seat;
0535 };
0536 
0537 WaylandClipboard::WaylandClipboard(QObject *parent)
0538     : KSystemClipboard(parent)
0539     , m_keyboardFocusWatcher(new KeyboardFocusWatcher)
0540     , m_manager(new DataControlDeviceManager)
0541 {
0542     connect(m_manager.get(), &DataControlDeviceManager::activeChanged, this, [this]() {
0543         if (m_manager->isActive()) {
0544             QPlatformNativeInterface *native = qApp->platformNativeInterface();
0545             if (!native) {
0546                 return;
0547             }
0548             auto seat = static_cast<struct ::wl_seat *>(native->nativeResourceForIntegration("wl_seat"));
0549             if (!seat) {
0550                 return;
0551             }
0552             m_device.reset(new DataControlDevice(m_manager->get_data_device(seat)));
0553 
0554             connect(m_device.get(), &DataControlDevice::receivedSelectionChanged, this, [this]() {
0555                 // When our source is still valid, so the offer is for setting it or we emit changed when it is cancelled
0556                 if (!m_device->selection()) {
0557                     Q_EMIT changed(QClipboard::Clipboard);
0558                 }
0559             });
0560             connect(m_device.get(), &DataControlDevice::selectionChanged, this, [this]() {
0561                 Q_EMIT changed(QClipboard::Clipboard);
0562             });
0563 
0564             connect(m_device.get(), &DataControlDevice::receivedPrimarySelectionChanged, this, [this]() {
0565                 // When our source is still valid, so the offer is for setting it or we emit changed when it is cancelled
0566                 if (!m_device->primarySelection()) {
0567                     Q_EMIT changed(QClipboard::Selection);
0568                 }
0569             });
0570             connect(m_device.get(), &DataControlDevice::primarySelectionChanged, this, [this]() {
0571                 Q_EMIT changed(QClipboard::Selection);
0572             });
0573 
0574         } else {
0575             m_device.reset();
0576         }
0577     });
0578 
0579     m_manager->instantiate();
0580 }
0581 
0582 WaylandClipboard::~WaylandClipboard() = default;
0583 
0584 bool WaylandClipboard::isValid()
0585 {
0586     return m_manager && m_manager->isInitialized();
0587 }
0588 
0589 void WaylandClipboard::setMimeData(QMimeData *mime, QClipboard::Mode mode)
0590 {
0591     if (!m_device) {
0592         return;
0593     }
0594 
0595     // roundtrip to have accurate focus state when losing focus but setting mime data before processing wayland events.
0596     auto native = qGuiApp->platformNativeInterface();
0597     auto display = static_cast<struct ::wl_display *>(native->nativeResourceForIntegration("wl_display"));
0598     wl_display_roundtrip(display);
0599 
0600     // If the application is focused, use the normal mechanism so a future paste will not deadlock itselfs
0601     if (m_keyboardFocusWatcher->hasFocus()) {
0602         QGuiApplication::clipboard()->setMimeData(mime, mode);
0603         return;
0604     }
0605     // If not, set the clipboard once the app receives focus to avoid the deadlock
0606     connect(m_keyboardFocusWatcher.get(), &KeyboardFocusWatcher::keyboardEntered, this, &WaylandClipboard::gainedFocus, Qt::UniqueConnection);
0607     auto source = std::make_unique<DataControlSource>(m_manager->create_data_source(), mime);
0608     if (mode == QClipboard::Clipboard) {
0609         m_device->setSelection(std::move(source));
0610     } else if (mode == QClipboard::Selection) {
0611         m_device->setPrimarySelection(std::move(source));
0612     }
0613 }
0614 
0615 void WaylandClipboard::gainedFocus()
0616 {
0617     disconnect(m_keyboardFocusWatcher.get(), &KeyboardFocusWatcher::keyboardEntered, this, nullptr);
0618     // QClipboard takes ownership of the QMimeData so we need to transfer and unset our selections
0619     if (auto &selection = m_device->m_selection) {
0620         std::unique_ptr<QMimeData> data = selection->releaseMimeData();
0621         WaylandClipboard::clear(QClipboard::Clipboard);
0622         QGuiApplication::clipboard()->setMimeData(data.release(), QClipboard::Clipboard);
0623     }
0624     if (auto &primarySelection = m_device->m_primarySelection) {
0625         std::unique_ptr<QMimeData> data = primarySelection->releaseMimeData();
0626         WaylandClipboard::clear(QClipboard::Selection);
0627         QGuiApplication::clipboard()->setMimeData(data.release(), QClipboard::Selection);
0628     }
0629 }
0630 
0631 void WaylandClipboard::clear(QClipboard::Mode mode)
0632 {
0633     if (!m_device) {
0634         return;
0635     }
0636     if (mode == QClipboard::Clipboard) {
0637         m_device->set_selection(nullptr);
0638         m_device->m_selection.reset();
0639     } else if (mode == QClipboard::Selection) {
0640         if (zwlr_data_control_device_v1_get_version(m_device->object()) >= ZWLR_DATA_CONTROL_DEVICE_V1_SET_PRIMARY_SELECTION_SINCE_VERSION) {
0641             m_device->set_primary_selection(nullptr);
0642             m_device->m_primarySelection.reset();
0643         }
0644     }
0645 }
0646 
0647 const QMimeData *WaylandClipboard::mimeData(QClipboard::Mode mode) const
0648 {
0649     if (!m_device) {
0650         return nullptr;
0651     }
0652 
0653     // return our locally set selection if it's not cancelled to avoid copying data to ourselves
0654     if (mode == QClipboard::Clipboard) {
0655         if (m_device->selection()) {
0656             return m_device->selection();
0657         }
0658         // This application owns the clipboard via the regular data_device, use it so we don't block ourselves
0659         if (QGuiApplication::clipboard()->ownsClipboard()) {
0660             return QGuiApplication::clipboard()->mimeData(mode);
0661         }
0662         return m_device->receivedSelection();
0663     } else if (mode == QClipboard::Selection) {
0664         if (m_device->primarySelection()) {
0665             return m_device->primarySelection();
0666         }
0667         // This application owns the primary selection via the regular primary_selection_device, use it so we don't block ourselves
0668         if (QGuiApplication::clipboard()->ownsSelection()) {
0669             return QGuiApplication::clipboard()->mimeData(mode);
0670         }
0671         return m_device->receivedPrimarySelection();
0672     }
0673     return nullptr;
0674 }
0675 
0676 #include "waylandclipboard.moc"