From 5ec182df699041699f514d164a161c299fde5d19 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Tue, 13 Nov 2018 15:40:14 +0100 Subject: Client: Implement primary-selection-unstable-v1 [ChangeLog][QPA plugin] Added support for middle mouse pasting through the primary-selection-unstable-v1 protocol. Fixes: QTBUG-66008 Change-Id: I7c8fb9aa2c856f5b6794aeab1ee75d80cad05dcd Reviewed-by: Paul Olav Tvete --- src/client/client.pro | 6 ++ src/client/configure.json | 5 + src/client/qwaylandclipboard.cpp | 71 +++++++++---- src/client/qwaylanddataoffer.cpp | 15 ++- src/client/qwaylanddataoffer_p.h | 24 +++-- src/client/qwaylanddisplay.cpp | 10 +- src/client/qwaylanddisplay_p.h | 9 ++ src/client/qwaylandinputdevice.cpp | 25 +++++ src/client/qwaylandinputdevice_p.h | 19 +++- src/client/qwaylandprimaryselectionv1.cpp | 162 ++++++++++++++++++++++++++++++ src/client/qwaylandprimaryselectionv1_p.h | 148 +++++++++++++++++++++++++++ 11 files changed, 461 insertions(+), 33 deletions(-) create mode 100644 src/client/qwaylandprimaryselectionv1.cpp create mode 100644 src/client/qwaylandprimaryselectionv1_p.h (limited to 'src/client') diff --git a/src/client/client.pro b/src/client/client.pro index ff9e845f1..4f4c58328 100644 --- a/src/client/client.pro +++ b/src/client/client.pro @@ -31,6 +31,7 @@ WAYLANDCLIENTSOURCES += \ ../extensions/touch-extension.xml \ ../extensions/qt-key-unstable-v1.xml \ ../extensions/qt-windowmanager.xml \ + ../3rdparty/protocol/wp-primary-selection-unstable-v1.xml \ ../3rdparty/protocol/text-input-unstable-v2.xml \ ../3rdparty/protocol/xdg-output-unstable-v1.xml \ ../3rdparty/protocol/wayland.xml @@ -118,6 +119,11 @@ qtConfig(wayland-datadevice) { qwaylanddatasource.cpp } +qtConfig(wayland-client-primary-selection) { + HEADERS += qwaylandprimaryselectionv1_p.h + SOURCES += qwaylandprimaryselectionv1.cpp +} + qtConfig(draganddrop) { HEADERS += \ qwaylanddnd_p.h diff --git a/src/client/configure.json b/src/client/configure.json index 2ec87eb49..403a2edcf 100644 --- a/src/client/configure.json +++ b/src/client/configure.json @@ -93,6 +93,11 @@ "condition": "features.draganddrop || features.clipboard", "output": [ "privateFeature" ] }, + "wayland-client-primary-selection": { + "label": "primary-selection clipboard", + "condition": "features.clipboard", + "output": [ "privateFeature" ] + }, "wayland-client-fullscreen-shell-v1": { "label": "fullscreen-shell-v1", "condition": "features.wayland-client", diff --git a/src/client/qwaylandclipboard.cpp b/src/client/qwaylandclipboard.cpp index 60820da92..369c6ec07 100644 --- a/src/client/qwaylandclipboard.cpp +++ b/src/client/qwaylandclipboard.cpp @@ -43,6 +43,9 @@ #include "qwaylanddataoffer_p.h" #include "qwaylanddatasource_p.h" #include "qwaylanddatadevice_p.h" +#if QT_CONFIG(wayland_client_primary_selection) +#include "qwaylandprimaryselectionv1_p.h" +#endif QT_BEGIN_NAMESPACE @@ -59,44 +62,74 @@ QWaylandClipboard::~QWaylandClipboard() QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode) { - if (mode != QClipboard::Clipboard) + auto *seat = mDisplay->currentInputDevice(); + if (!seat) return &m_emptyData; - QWaylandInputDevice *inputDevice = mDisplay->currentInputDevice(); - if (!inputDevice || !inputDevice->dataDevice()) + switch (mode) { + case QClipboard::Clipboard: + if (auto *dataDevice = seat->dataDevice()) { + if (auto *source = dataDevice->selectionSource()) + return source->mimeData(); + if (auto *offer = dataDevice->selectionOffer()) + return offer->mimeData(); + } + return &m_emptyData; + case QClipboard::Selection: +#if QT_CONFIG(wayland_client_primary_selection) + if (auto *selectionDevice = seat->primarySelectionDevice()) { + if (auto *source = selectionDevice->selectionSource()) + return source->mimeData(); + if (auto *offer = selectionDevice->selectionOffer()) + return offer->mimeData(); + } +#endif + return &m_emptyData; + default: return &m_emptyData; - - QWaylandDataSource *source = inputDevice->dataDevice()->selectionSource(); - if (source) { - return source->mimeData(); } - - if (inputDevice->dataDevice()->selectionOffer()) - return inputDevice->dataDevice()->selectionOffer()->mimeData(); - - return &m_emptyData; } void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) { - if (mode != QClipboard::Clipboard) - return; - - QWaylandInputDevice *inputDevice = mDisplay->currentInputDevice(); - if (!inputDevice || !inputDevice->dataDevice()) + auto *seat = mDisplay->currentInputDevice(); + if (!seat) return; static const QString plain = QStringLiteral("text/plain"); static const QString utf8 = QStringLiteral("text/plain;charset=utf-8"); + if (data && data->hasFormat(plain) && !data->hasFormat(utf8)) data->setData(utf8, data->data(plain)); - inputDevice->dataDevice()->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(), data) : nullptr); - emitChanged(mode); + switch (mode) { + case QClipboard::Clipboard: + if (auto *dataDevice = seat->dataDevice()) { + dataDevice->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(), data) : nullptr); + emitChanged(mode); + } + break; + case QClipboard::Selection: +#if QT_CONFIG(wayland_client_primary_selection) + if (auto *selectionDevice = seat->primarySelectionDevice()) { + selectionDevice->setSelectionSource(data ? new QWaylandPrimarySelectionSourceV1(mDisplay->primarySelectionManager(), data) : nullptr); + emitChanged(mode); + } +#endif + break; + default: + break; + } } bool QWaylandClipboard::supportsMode(QClipboard::Mode mode) const { +#if QT_CONFIG(wayland_client_primary_selection) + if (mode == QClipboard::Selection) { + auto *seat = mDisplay->currentInputDevice(); + return seat && seat->primarySelectionDevice(); + } +#endif return mode == QClipboard::Clipboard; } diff --git a/src/client/qwaylanddataoffer.cpp b/src/client/qwaylanddataoffer.cpp index 0c732c020..e31e1220f 100644 --- a/src/client/qwaylanddataoffer.cpp +++ b/src/client/qwaylanddataoffer.cpp @@ -58,7 +58,8 @@ static QString utf8Text() QWaylandDataOffer::QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer) : QtWayland::wl_data_offer(offer) - , m_mimeData(new QWaylandMimeData(this, display)) + , m_display(display) + , m_mimeData(new QWaylandMimeData(this)) { } @@ -81,14 +82,19 @@ QMimeData *QWaylandDataOffer::mimeData() return m_mimeData.data(); } +void QWaylandDataOffer::startReceiving(const QString &mimeType, int fd) +{ + receive(mimeType, fd); + wl_display_flush(m_display->wl_display()); +} + void QWaylandDataOffer::data_offer_offer(const QString &mime_type) { m_mimeData->appendFormat(mime_type); } -QWaylandMimeData::QWaylandMimeData(QWaylandDataOffer *dataOffer, QWaylandDisplay *display) +QWaylandMimeData::QWaylandMimeData(QWaylandAbstractDataOffer *dataOffer) : m_dataOffer(dataOffer) - , m_display(display) { } @@ -140,8 +146,7 @@ QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::T return QVariant(); } - m_dataOffer->receive(mime, pipefd[1]); - wl_display_flush(m_display->wl_display()); + m_dataOffer->startReceiving(mime, pipefd[1]); close(pipefd[1]); diff --git a/src/client/qwaylanddataoffer_p.h b/src/client/qwaylanddataoffer_p.h index 5412400a5..9cf1483ca 100644 --- a/src/client/qwaylanddataoffer_p.h +++ b/src/client/qwaylanddataoffer_p.h @@ -65,27 +65,40 @@ namespace QtWaylandClient { class QWaylandDisplay; class QWaylandMimeData; -class Q_WAYLAND_CLIENT_EXPORT QWaylandDataOffer : public QtWayland::wl_data_offer +class QWaylandAbstractDataOffer +{ +public: + virtual void startReceiving(const QString &mimeType, int fd) = 0; + virtual QMimeData *mimeData() = 0; + + virtual ~QWaylandAbstractDataOffer() = default; +}; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandDataOffer + : public QtWayland::wl_data_offer // needs to be the first because we do static casts from the user pointer to the wrapper + , public QWaylandAbstractDataOffer { public: explicit QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer); ~QWaylandDataOffer() override; + QMimeData *mimeData() override; QString firstFormat() const; - QMimeData *mimeData(); + void startReceiving(const QString &mimeType, int fd) override; protected: void data_offer_offer(const QString &mime_type) override; private: + QWaylandDisplay *m_display = nullptr; QScopedPointer m_mimeData; }; class QWaylandMimeData : public QInternalMimeData { public: - explicit QWaylandMimeData(QWaylandDataOffer *dataOffer, QWaylandDisplay *display); + explicit QWaylandMimeData(QWaylandAbstractDataOffer *dataOffer); ~QWaylandMimeData() override; void appendFormat(const QString &mimeType); @@ -98,13 +111,12 @@ protected: private: int readData(int fd, QByteArray &data) const; - mutable QWaylandDataOffer *m_dataOffer = nullptr; - QWaylandDisplay *m_display = nullptr; + QWaylandAbstractDataOffer *m_dataOffer = nullptr; mutable QStringList m_types; mutable QHash m_data; }; -} +} // namespace QtWaylandClient QT_END_NAMESPACE #endif diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp index 7c32b6bf5..1febca9b1 100644 --- a/src/client/qwaylanddisplay.cpp +++ b/src/client/qwaylanddisplay.cpp @@ -52,7 +52,10 @@ #if QT_CONFIG(wayland_datadevice) #include "qwaylanddatadevicemanager_p.h" #include "qwaylanddatadevice_p.h" -#endif +#endif // QT_CONFIG(wayland_datadevice) +#if QT_CONFIG(wayland_client_primary_selection) +#include "qwaylandprimaryselectionv1_p.h" +#endif // QT_CONFIG(wayland_client_primary_selection) #if QT_CONFIG(cursor) #include #endif @@ -69,6 +72,7 @@ #include "qwaylandqtkey_p.h" #include +#include #include @@ -318,6 +322,10 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin mTouchExtension.reset(new QWaylandTouchExtension(this, id)); } else if (interface == QStringLiteral("zqt_key_v1")) { mQtKeyExtension.reset(new QWaylandQtKeyExtension(this, id)); +#if QT_CONFIG(wayland_client_primary_selection) + } else if (interface == QStringLiteral("zwp_primary_selection_device_manager_v1")) { + mPrimarySelectionManager.reset(new QWaylandPrimarySelectionDeviceManagerV1(this, id, 1)); +#endif } else if (interface == QStringLiteral("zwp_text_input_manager_v2") && !mClientSideInputContextRequested) { mTextInputManager.reset(new QtWayland::zwp_text_input_manager_v2(registry, id, 1)); for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices)) diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h index 2c7ed3231..67df545f6 100644 --- a/src/client/qwaylanddisplay_p.h +++ b/src/client/qwaylanddisplay_p.h @@ -93,6 +93,9 @@ class QWaylandScreen; class QWaylandClientBufferIntegration; class QWaylandWindowManagerIntegration; class QWaylandDataDeviceManager; +#if QT_CONFIG(wayland_client_primary_selection) +class QWaylandPrimarySelectionDeviceManagerV1; +#endif class QWaylandTouchExtension; class QWaylandQtKeyExtension; class QWaylandWindow; @@ -149,6 +152,9 @@ public: QWaylandInputDevice *currentInputDevice() const { return defaultInputDevice(); } #if QT_CONFIG(wayland_datadevice) QWaylandDataDeviceManager *dndSelectionHandler() const { return mDndSelectionHandler.data(); } +#endif +#if QT_CONFIG(wayland_client_primary_selection) + QWaylandPrimarySelectionDeviceManagerV1 *primarySelectionManager() const { return mPrimarySelectionManager.data(); } #endif QtWayland::qt_surface_extension *windowExtension() const { return mWindowExtension.data(); } QWaylandTouchExtension *touchExtension() const { return mTouchExtension.data(); } @@ -238,6 +244,9 @@ private: QScopedPointer mTouchExtension; QScopedPointer mQtKeyExtension; QScopedPointer mWindowManagerIntegration; +#if QT_CONFIG(wayland_client_primary_selection) + QScopedPointer mPrimarySelectionManager; +#endif QScopedPointer mTextInputManager; QScopedPointer mHardwareIntegration; QScopedPointer mXdgOutputManager; diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index f0fd99563..8a580898d 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -47,6 +47,9 @@ #include "qwaylanddatadevice_p.h" #include "qwaylanddatadevicemanager_p.h" #endif +#if QT_CONFIG(wayland_client_primary_selection) +#include "qwaylandprimaryselectionv1_p.h" +#endif #include "qwaylandtouch_p.h" #include "qwaylandscreen_p.h" #include "qwaylandcursor_p.h" @@ -363,6 +366,12 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version, } #endif +#if QT_CONFIG(wayland_client_primary_selection) + // TODO: Could probably decouple this more if there was a signal for new seat added + if (auto *psm = mQDisplay->primarySelectionManager()) + setPrimarySelectionDevice(psm->createDevice(this)); +#endif + if (mQDisplay->textInputManager()) mTextInput.reset(new QWaylandTextInput(mQDisplay, mQDisplay->textInputManager()->get_text_input(wl_seat()))); @@ -446,6 +455,18 @@ QWaylandDataDevice *QWaylandInputDevice::dataDevice() const } #endif +#if QT_CONFIG(wayland_client_primary_selection) +void QWaylandInputDevice::setPrimarySelectionDevice(QWaylandPrimarySelectionDeviceV1 *primarySelectionDevice) +{ + mPrimarySelectionDevice.reset(primarySelectionDevice); +} + +QWaylandPrimarySelectionDeviceV1 *QWaylandInputDevice::primarySelectionDevice() const +{ + return mPrimarySelectionDevice.data(); +} +#endif + void QWaylandInputDevice::setTextInput(QWaylandTextInput *textInput) { mTextInput.reset(textInput); @@ -1189,6 +1210,10 @@ void QWaylandInputDevice::Keyboard::handleFocusLost() #if QT_CONFIG(clipboard) if (auto *dataDevice = mParent->dataDevice()) dataDevice->invalidateSelectionOffer(); +#endif +#if QT_CONFIG(wayland_client_primary_selection) + if (auto *device = mParent->primarySelectionDevice()) + device->invalidateSelectionOffer(); #endif mParent->mQDisplay->handleKeyboardFocusChanged(mParent); mRepeatTimer.stop(); diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h index f44f1ab1f..06ba5d566 100644 --- a/src/client/qwaylandinputdevice_p.h +++ b/src/client/qwaylandinputdevice_p.h @@ -78,11 +78,17 @@ struct wl_cursor_image; QT_BEGIN_NAMESPACE +namespace QtWayland { +class zwp_primary_selection_device_v1; +} //namespace QtWayland + namespace QtWaylandClient { -class QWaylandWindow; -class QWaylandDisplay; class QWaylandDataDevice; +class QWaylandDisplay; +#if QT_CONFIG(wayland_client_primary_selection) +class QWaylandPrimarySelectionDeviceV1; +#endif class QWaylandTextInput; #if QT_CONFIG(cursor) class QWaylandCursorTheme; @@ -116,6 +122,11 @@ public: QWaylandDataDevice *dataDevice() const; #endif +#if QT_CONFIG(wayland_client_primary_selection) + void setPrimarySelectionDevice(QWaylandPrimarySelectionDeviceV1 *primarySelectionDevice); + QWaylandPrimarySelectionDeviceV1 *primarySelectionDevice() const; +#endif + void setTextInput(QWaylandTextInput *textInput); QWaylandTextInput *textInput() const; @@ -159,6 +170,10 @@ private: QWaylandDataDevice *mDataDevice = nullptr; #endif +#if QT_CONFIG(wayland_client_primary_selection) + QScopedPointer mPrimarySelectionDevice; +#endif + Keyboard *mKeyboard = nullptr; Pointer *mPointer = nullptr; Touch *mTouch = nullptr; diff --git a/src/client/qwaylandprimaryselectionv1.cpp b/src/client/qwaylandprimaryselectionv1.cpp new file mode 100644 index 000000000..3ddf6dac3 --- /dev/null +++ b/src/client/qwaylandprimaryselectionv1.cpp @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylandprimaryselectionv1_p.h" +#include "qwaylandinputdevice_p.h" +#include "qwaylanddisplay_p.h" +#include "qwaylandmimehelper_p.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +QWaylandPrimarySelectionDeviceManagerV1::QWaylandPrimarySelectionDeviceManagerV1(QWaylandDisplay *display, uint id, uint version) + : zwp_primary_selection_device_manager_v1(display->wl_registry(), id, qMin(version, uint(1))) + , m_display(display) +{ + // Create devices for all seats. + // This only works if we get the global before all devices + const auto seats = m_display->inputDevices(); + for (auto *seat : seats) + seat->setPrimarySelectionDevice(createDevice(seat)); +} + +QWaylandPrimarySelectionDeviceV1 *QWaylandPrimarySelectionDeviceManagerV1::createDevice(QWaylandInputDevice *seat) +{ + return new QWaylandPrimarySelectionDeviceV1(this, seat); +} + +QWaylandPrimarySelectionOfferV1::QWaylandPrimarySelectionOfferV1(QWaylandDisplay *display, ::zwp_primary_selection_offer_v1 *offer) + : zwp_primary_selection_offer_v1(offer) + , m_display(display) + , m_mimeData(new QWaylandMimeData(this)) +{} + +void QWaylandPrimarySelectionOfferV1::startReceiving(const QString &mimeType, int fd) +{ + receive(mimeType, fd); + wl_display_flush(m_display->wl_display()); +} + +void QWaylandPrimarySelectionOfferV1::zwp_primary_selection_offer_v1_offer(const QString &mime_type) +{ + m_mimeData->appendFormat(mime_type); +} + +QWaylandPrimarySelectionDeviceV1::QWaylandPrimarySelectionDeviceV1( + QWaylandPrimarySelectionDeviceManagerV1 *manager, QWaylandInputDevice *seat) + : QtWayland::zwp_primary_selection_device_v1(manager->get_device(seat->wl_seat())) + , m_display(manager->display()) + , m_seat(seat) +{ +} + +QWaylandPrimarySelectionDeviceV1::~QWaylandPrimarySelectionDeviceV1() +{ + destroy(); +} + +void QWaylandPrimarySelectionDeviceV1::setSelectionSource(QWaylandPrimarySelectionSourceV1 *source) +{ + if (source) { + connect(source, &QWaylandPrimarySelectionSourceV1::cancelled, this, [this]() { + m_selectionSource.reset(); + QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Selection); + }); + } + set_selection(source ? source->object() : nullptr, m_seat->serial()); + m_selectionSource.reset(source); +} + +void QWaylandPrimarySelectionDeviceV1::zwp_primary_selection_device_v1_data_offer(zwp_primary_selection_offer_v1 *offer) +{ + new QWaylandPrimarySelectionOfferV1(m_display, offer); +} + +void QWaylandPrimarySelectionDeviceV1::zwp_primary_selection_device_v1_selection(zwp_primary_selection_offer_v1 *id) +{ + + if (id) + m_selectionOffer.reset(static_cast(zwp_primary_selection_offer_v1_get_user_data(id))); + else + m_selectionOffer.reset(); + + QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Selection); +} + +QWaylandPrimarySelectionSourceV1::QWaylandPrimarySelectionSourceV1(QWaylandPrimarySelectionDeviceManagerV1 *manager, QMimeData *mimeData) + : QtWayland::zwp_primary_selection_source_v1(manager->create_source()) + , m_mimeData(mimeData) +{ + if (!mimeData) + return; + for (auto &format : mimeData->formats()) + offer(format); +} + +QWaylandPrimarySelectionSourceV1::~QWaylandPrimarySelectionSourceV1() +{ + destroy(); +} + +void QWaylandPrimarySelectionSourceV1::zwp_primary_selection_source_v1_send(const QString &mime_type, int32_t fd) +{ + QByteArray content = QWaylandMimeHelper::getByteArray(m_mimeData, mime_type); + if (!content.isEmpty()) { + // Create a sigpipe handler that does nothing, or clients may be forced to terminate + // if the pipe is closed in the other end. + struct sigaction action, oldAction; + action.sa_handler = SIG_IGN; + sigemptyset (&action.sa_mask); + action.sa_flags = 0; + + sigaction(SIGPIPE, &action, &oldAction); + write(fd, content.constData(), size_t(content.size())); + sigaction(SIGPIPE, &oldAction, nullptr); + } + close(fd); +} + +} // namespace QtWaylandClient + +QT_END_NAMESPACE diff --git a/src/client/qwaylandprimaryselectionv1_p.h b/src/client/qwaylandprimaryselectionv1_p.h new file mode 100644 index 000000000..b165c51b8 --- /dev/null +++ b/src/client/qwaylandprimaryselectionv1_p.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDPRIMARYSELECTIONV1_P_H +#define QWAYLANDPRIMARYSELECTIONV1_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include +#include + +#include + +QT_REQUIRE_CONFIG(wayland_client_primary_selection); + +QT_BEGIN_NAMESPACE + +class QMimeData; + +namespace QtWaylandClient { + +class QWaylandInputDevice; +class QWaylandPrimarySelectionDeviceV1; + +class QWaylandPrimarySelectionDeviceManagerV1 : public QtWayland::zwp_primary_selection_device_manager_v1 +{ +public: + explicit QWaylandPrimarySelectionDeviceManagerV1(QWaylandDisplay *display, uint id, uint version); + QWaylandPrimarySelectionDeviceV1 *createDevice(QWaylandInputDevice *seat); + QWaylandDisplay *display() const { return m_display; } + +private: + QWaylandDisplay *m_display = nullptr; +}; + +class QWaylandPrimarySelectionOfferV1 : public QtWayland::zwp_primary_selection_offer_v1, public QWaylandAbstractDataOffer +{ +public: + explicit QWaylandPrimarySelectionOfferV1(QWaylandDisplay *display, ::zwp_primary_selection_offer_v1 *offer); + ~QWaylandPrimarySelectionOfferV1() override { destroy(); } + void startReceiving(const QString &mimeType, int fd) override; + QMimeData *mimeData() override { return m_mimeData.data(); } + +protected: + void zwp_primary_selection_offer_v1_offer(const QString &mime_type) override; + +private: + QWaylandDisplay *m_display = nullptr; + QScopedPointer m_mimeData; +}; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandPrimarySelectionSourceV1 : public QObject, public QtWayland::zwp_primary_selection_source_v1 +{ + Q_OBJECT +public: + explicit QWaylandPrimarySelectionSourceV1(QWaylandPrimarySelectionDeviceManagerV1 *manager, QMimeData *mimeData); + ~QWaylandPrimarySelectionSourceV1() override; + + QMimeData *mimeData() const { return m_mimeData; } + +signals: + void cancelled(); + +protected: + void zwp_primary_selection_source_v1_send(const QString &mime_type, int32_t fd) override; + void zwp_primary_selection_source_v1_cancelled() override { emit cancelled(); } + +private: + QWaylandDisplay *m_display = nullptr; + QMimeData *m_mimeData = nullptr; +}; + +class QWaylandPrimarySelectionDeviceV1 : public QObject, public QtWayland::zwp_primary_selection_device_v1 +{ + Q_OBJECT + QWaylandPrimarySelectionDeviceV1(QWaylandPrimarySelectionDeviceManagerV1 *manager, QWaylandInputDevice *seat); + +public: + ~QWaylandPrimarySelectionDeviceV1() override; + QWaylandPrimarySelectionOfferV1 *selectionOffer() const { return m_selectionOffer.data(); } + void invalidateSelectionOffer() { m_selectionOffer.reset(); } + QWaylandPrimarySelectionSourceV1 *selectionSource() const { return m_selectionSource.data(); } + void setSelectionSource(QWaylandPrimarySelectionSourceV1 *source); + +protected: + void zwp_primary_selection_device_v1_data_offer(struct ::zwp_primary_selection_offer_v1 *offer) override; + void zwp_primary_selection_device_v1_selection(struct ::zwp_primary_selection_offer_v1 *id) override; + +private: + QWaylandDisplay *m_display = nullptr; + QWaylandInputDevice *m_seat = nullptr; + QScopedPointer m_selectionOffer; + QScopedPointer m_selectionSource; + friend class QWaylandPrimarySelectionDeviceManagerV1; +}; + +} // namespace QtWaylandClient + +QT_END_NAMESPACE + +#endif // QWAYLANDPRIMARYSELECTIONV1_P_H -- cgit v1.2.3