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