Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package kf6-kguiaddons for openSUSE:Factory checked in at 2026-01-12 10:11:36 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kf6-kguiaddons (Old) and /work/SRC/openSUSE:Factory/.kf6-kguiaddons.new.1928 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kf6-kguiaddons" Mon Jan 12 10:11:36 2026 rev:23 rq:1326426 version:6.22.0 Changes: -------- --- /work/SRC/openSUSE:Factory/kf6-kguiaddons/kf6-kguiaddons.changes 2025-12-16 15:56:06.574492305 +0100 +++ /work/SRC/openSUSE:Factory/.kf6-kguiaddons.new.1928/kf6-kguiaddons.changes 2026-01-12 10:15:40.283555489 +0100 @@ -1,0 +2,16 @@ +Sun Jan 4 14:47:11 UTC 2026 - Christophe Marin <[email protected]> + +- Update to 6.22.0 + * New feature release + * For more details please see: + * https://kde.org/announcements/frameworks/6/6.22.0 +- Changes since 6.21.0: + * Update dependency version to 6.22.0 + * ksystemclipboard: Use WaylandClipboard also on wayland-egl + * ksystemclipboard: Dispatch read events in another thread (kde#480448) + * Remove focus hacks as preparation for clipoard thread + * Add manual test for ksystemclipboard + * Deprecate KColorSchemeWatcher + * Update version to 6.22.0 + +------------------------------------------------------------------- Old: ---- kguiaddons-6.21.0.tar.xz kguiaddons-6.21.0.tar.xz.sig New: ---- kguiaddons-6.22.0.tar.xz kguiaddons-6.22.0.tar.xz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kf6-kguiaddons.spec ++++++ --- /var/tmp/diff_new_pack.e3tDTN/_old 2026-01-12 10:15:42.043627765 +0100 +++ /var/tmp/diff_new_pack.e3tDTN/_new 2026-01-12 10:15:42.047627929 +0100 @@ -32,11 +32,11 @@ %define mypython_sitearch %{expand:%%%{mypython}_sitearch} %endif -# Full KF6 version (e.g. 6.21.0) +# Full KF6 version (e.g. 6.22.0) %{!?_kf6_version: %global _kf6_version %{version}} %bcond_without released Name: kf6-kguiaddons -Version: 6.21.0 +Version: 6.22.0 Release: 0 Summary: Utilities for graphical user interfaces License: LGPL-2.1-or-later ++++++ kguiaddons-6.21.0.tar.xz -> kguiaddons-6.22.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-6.21.0/CMakeLists.txt new/kguiaddons-6.22.0/CMakeLists.txt --- old/kguiaddons-6.21.0/CMakeLists.txt 2025-12-05 14:21:33.000000000 +0100 +++ new/kguiaddons-6.22.0/CMakeLists.txt 2026-01-02 18:41:55.000000000 +0100 @@ -1,10 +1,10 @@ cmake_minimum_required(VERSION 3.16) -set(KF_VERSION "6.21.0") # handled by release scripts +set(KF_VERSION "6.22.0") # handled by release scripts project(KGuiAddons VERSION ${KF_VERSION}) include(FeatureSummary) -find_package(ECM 6.21.0 NO_MODULE) +find_package(ECM 6.22.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) @@ -103,7 +103,7 @@ SOVERSION 6) ecm_set_disabled_deprecation_versions( - QT 6.10 + QT 6.11 ) add_subdirectory(src) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-6.21.0/src/CMakeLists.txt new/kguiaddons-6.22.0/src/CMakeLists.txt --- old/kguiaddons-6.21.0/src/CMakeLists.txt 2025-12-05 14:21:33.000000000 +0100 +++ new/kguiaddons-6.22.0/src/CMakeLists.txt 2026-01-02 18:41:55.000000000 +0100 @@ -121,7 +121,7 @@ VERSION ${KF_VERSION} USE_VERSION_HEADER DEPRECATED_BASE_VERSION 0 - DEPRECATION_VERSIONS 6.3 6.12 + DEPRECATION_VERSIONS 6.3 6.12 6.22 ) set(kguiaddons_INCLUDES diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-6.21.0/src/colors/kcolorschemewatcher.cpp new/kguiaddons-6.22.0/src/colors/kcolorschemewatcher.cpp --- old/kguiaddons-6.21.0/src/colors/kcolorschemewatcher.cpp 2025-12-05 14:21:33.000000000 +0100 +++ new/kguiaddons-6.22.0/src/colors/kcolorschemewatcher.cpp 2026-01-02 18:41:55.000000000 +0100 @@ -6,6 +6,8 @@ #include "kcolorschemewatcher.h" +#if KGUIADDONS_BUILD_DEPRECATED_SINCE(6, 22) + #include "kcolorschemewatcher_qt.h" #include "kcolorschemewatcherbackend.h" @@ -63,3 +65,5 @@ } #include "moc_kcolorschemewatcher.cpp" + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-6.21.0/src/colors/kcolorschemewatcher.h new/kguiaddons-6.22.0/src/colors/kcolorschemewatcher.h --- old/kguiaddons-6.21.0/src/colors/kcolorschemewatcher.h 2025-12-05 14:21:33.000000000 +0100 +++ new/kguiaddons-6.22.0/src/colors/kcolorschemewatcher.h 2026-01-02 18:41:55.000000000 +0100 @@ -15,11 +15,15 @@ class KColorSchemeWatcherPrivate; +#if KGUIADDONS_ENABLE_DEPRECATED_SINCE(6, 22) + /*! * \class KColorSchemeWatcher * \inmodule KGuiAddons * \brief Information about system-wide color preferences. * \since 5.100 + * \deprecated[6.22] + * Use QStyleHints and QAccessibilityHints instead */ class KGUIADDONS_EXPORT KColorSchemeWatcher : public QObject { @@ -49,6 +53,7 @@ /*! * */ + KGUIADDONS_DEPRECATED_VERSION(6, 22, "Use Qt API instead") KColorSchemeWatcher(QObject *parent = nullptr); ~KColorSchemeWatcher() override; @@ -68,3 +73,5 @@ }; #endif + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-6.21.0/src/systemclipboard/ksystemclipboard.cpp new/kguiaddons-6.22.0/src/systemclipboard/ksystemclipboard.cpp --- old/kguiaddons-6.21.0/src/systemclipboard/ksystemclipboard.cpp 2025-12-05 14:21:33.000000000 +0100 +++ new/kguiaddons-6.22.0/src/systemclipboard/ksystemclipboard.cpp 2026-01-02 18:41:55.000000000 +0100 @@ -24,7 +24,7 @@ #ifdef WITH_WAYLAND static bool s_waylandChecked = false; - if (!systemClipboard && qGuiApp->platformName() == QLatin1String("wayland") && !s_waylandChecked) { + if (!systemClipboard && qGuiApp->platformName().startsWith(QLatin1String("wayland")) && !s_waylandChecked) { s_waylandChecked = true; if (auto waylandClipboard = WaylandClipboard::create(qApp)) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-6.21.0/src/systemclipboard/waylandclipboard.cpp new/kguiaddons-6.22.0/src/systemclipboard/waylandclipboard.cpp --- old/kguiaddons-6.21.0/src/systemclipboard/waylandclipboard.cpp 2025-12-05 14:21:33.000000000 +0100 +++ new/kguiaddons-6.22.0/src/systemclipboard/waylandclipboard.cpp 2026-01-02 18:41:55.000000000 +0100 @@ -1,7 +1,6 @@ /* SPDX-FileCopyrightText: 2020 David Edmundson <[email protected]> SPDX-FileCopyrightText: 2021 Méven Car <[email protected]> - SPDX-License-Identifier: LGPL-2.0-or-later */ @@ -13,7 +12,10 @@ #include <QImageReader> #include <QImageWriter> #include <QMimeData> +#include <QMutex> #include <QPointer> +#include <QThread> +#include <QTimer> #include <QWaylandClientExtension> #include <QWindow> #include <QtWaylandClientVersion> @@ -28,6 +30,14 @@ #include "qwayland-wayland.h" #include "qwayland-ext-data-control-v1.h" +/** + * Wayland clipboard wraps ext_data_control an additional is used as we need to avoid + * deadlocks if an application tries to read the normal clipboard whilst it owns the data control. + * + * To solve this all ext_data_control classes live on another thread which dispatches events on a separate + * queue. A recursive mutex allows the main thread to read mimedata and no wayland events which change the mimedata process until this is complete. + */ + static inline QString applicationQtXImageLiteral() { return QStringLiteral("application/x-qt-image"); @@ -298,10 +308,6 @@ { return m_mimeData.get(); } - std::unique_ptr<QMimeData> releaseMimeData() - { - return std::move(m_mimeData); - } Q_SIGNALS: void cancelled(); @@ -445,6 +451,7 @@ void ext_data_control_device_v1_selection(struct ::ext_data_control_offer_v1 *id) override { + QMutexLocker locker(&m_selectionLock); if (!id) { m_receivedSelection.reset(); } else { @@ -457,6 +464,7 @@ void ext_data_control_device_v1_primary_selection(struct ::ext_data_control_offer_v1 *id) override { + QMutexLocker locker(&m_primarySelectionLock); if (!id) { m_receivedPrimarySelection.reset(); } else { @@ -468,9 +476,11 @@ } private: + QRecursiveMutex m_selectionLock; std::unique_ptr<DataControlSource> m_selection; // selection set locally std::unique_ptr<DataControlOffer> m_receivedSelection; // latest selection set from externally to here + QRecursiveMutex m_primarySelectionLock; std::unique_ptr<DataControlSource> m_primarySelection; // selection set locally std::unique_ptr<DataControlOffer> m_receivedPrimarySelection; // latest selection set from externally to here friend WaylandClipboard; @@ -478,106 +488,92 @@ void DataControlDevice::setSelection(std::unique_ptr<DataControlSource> selection) { - set_selection(selection->object()); + { + QMutexLocker locker(&m_selectionLock); + set_selection(selection->object()); - // Note the previous selection is destroyed after the set_selection request. - m_selection = std::move(selection); - connect(m_selection.get(), &DataControlSource::cancelled, this, [this]() { - m_selection.reset(); - }); + // Note the previous selection is destroyed after the set_selection request. + m_selection = std::move(selection); + connect(m_selection.get(), &DataControlSource::cancelled, this, [this]() { + m_selection.reset(); + }); + } Q_EMIT selectionChanged(); } void DataControlDevice::setPrimarySelection(std::unique_ptr<DataControlSource> selection) { - set_primary_selection(selection->object()); + { + QMutexLocker locker(&m_primarySelectionLock); + set_primary_selection(selection->object()); - // Note the previous selection is destroyed after the set_primary_selection request. - m_primarySelection = std::move(selection); - connect(m_primarySelection.get(), &DataControlSource::cancelled, this, [this]() { - m_primarySelection.reset(); - }); + // Note the previous selection is destroyed after the set_primary_selection request. + m_primarySelection = std::move(selection); + connect(m_primarySelection.get(), &DataControlSource::cancelled, this, [this]() { + m_primarySelection.reset(); + }); + } Q_EMIT primarySelectionChanged(); } -class Keyboard; -// 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 -class KeyboardFocusWatcher : public QWaylandClientExtensionTemplate<KeyboardFocusWatcher>, public QtWayland::wl_seat + +class ClipboardThread : public QThread { - Q_OBJECT public: - KeyboardFocusWatcher() - : QWaylandClientExtensionTemplate(5) - { - initialize(); - auto waylandApp = qGuiApp->nativeInterface<QNativeInterface::QWaylandApplication>(); - auto display = waylandApp->display(); - // so we get capabilities - wl_display_roundtrip(display); - } - ~KeyboardFocusWatcher() override + ClipboardThread(wl_display *display) + : m_display(display) { - if (isActive()) { - release(); - } + m_queue = wl_display_create_queue_with_name(m_display, "ksystemclipboard queue"); } - void seat_capabilities(uint32_t capabilities) override + + ~ClipboardThread() { - const bool hasKeyboard = capabilities & capability_keyboard; - if (hasKeyboard && !m_keyboard) { - m_keyboard = std::make_unique<Keyboard>(get_keyboard(), *this); - } else if (!hasKeyboard && m_keyboard) { - m_keyboard.reset(); + if (m_callback) { + wl_callback_destroy(m_callback); } + wl_event_queue_destroy(m_queue); } - bool hasFocus() const - { - return m_focus; - } -Q_SIGNALS: - void keyboardEntered(); - -private: - friend Keyboard; - bool m_focus = false; - std::unique_ptr<Keyboard> m_keyboard; -}; -class Keyboard : public QtWayland::wl_keyboard -{ -public: - Keyboard(::wl_keyboard *keyboard, KeyboardFocusWatcher &seat) - : wl_keyboard(keyboard) - , m_seat(seat) + void syncQueue() { - } - ~Keyboard() - { - release(); + // wl_display_dispatch_queue will block until it gets an event, as KSystemClipboard + // has the lifespan of the QApplication and the QPA is still alive + // we need something to explicitly wake up the event queue up before the main thread + // blocks waiting for this thread. + auto wrapped_display = wl_proxy_create_wrapper(m_display); + wl_proxy_set_queue(static_cast<wl_proxy *>(wrapped_display), m_queue); + m_callback = wl_display_sync(static_cast<struct wl_display *>(wrapped_display)); + wl_display_flush(m_display); + wl_proxy_wrapper_destroy(wrapped_display); } -private: - void keyboard_enter([[maybe_unused]] uint32_t serial, [[maybe_unused]] wl_surface *surface, [[maybe_unused]] wl_array *keys) override + void run() override { - m_seat.m_focus = true; - Q_EMIT m_seat.keyboardEntered(); - } - void keyboard_leave([[maybe_unused]] uint32_t serial, [[maybe_unused]] wl_surface *surface) override - { - m_seat.m_focus = false; + int ret = 0; + while (ret >= 0 && !qGuiApp->closingDown()) { + ret = wl_display_dispatch_queue(m_display, m_queue); + } } - KeyboardFocusWatcher &m_seat; + wl_callback *m_callback = nullptr; + wl_event_queue *m_queue = nullptr; + wl_display *m_display = nullptr; }; WaylandClipboard::WaylandClipboard(QObject *parent) : KSystemClipboard(parent) - , m_keyboardFocusWatcher(new KeyboardFocusWatcher) , m_manager(new DataControlDeviceManager) { + auto waylandApp = qGuiApp->nativeInterface<QNativeInterface::QWaylandApplication>(); + if (!waylandApp) { + return; + } + connect(m_manager.get(), &DataControlDeviceManager::activeChanged, this, [this]() { if (m_manager->isActive()) { auto waylandApp = qGuiApp->nativeInterface<QNativeInterface::QWaylandApplication>(); + m_thread = std::make_unique<ClipboardThread>(waylandApp->display()); + if (!waylandApp) { return; } @@ -586,7 +582,9 @@ if (!seat) { return; } + wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(m_manager->object()), m_thread->m_queue); m_device.reset(new DataControlDevice(m_manager->get_data_device(seat))); + m_device->moveToThread(m_thread.get()); connect(m_device.get(), &DataControlDevice::receivedSelectionChanged, this, [this]() { // When our source is still valid, so the offer is for setting it or we emit changed when it is cancelled @@ -607,16 +605,25 @@ connect(m_device.get(), &DataControlDevice::primarySelectionChanged, this, [this]() { Q_EMIT changed(QClipboard::Selection); }); + m_thread->start(); } else { m_device.reset(); + m_thread->wait(); + m_thread.reset(); } }); m_manager->instantiate(); } -WaylandClipboard::~WaylandClipboard() = default; +WaylandClipboard::~WaylandClipboard() +{ + if (m_thread->isRunning()) { + m_thread->syncQueue(); + m_thread->wait(); + } +} WaylandClipboard *WaylandClipboard::create(QObject *parent) { @@ -639,23 +646,8 @@ return; } - // roundtrip to have accurate focus state when losing focus but setting mime data before processing wayland events. - auto waylandApp = qGuiApp->nativeInterface<QNativeInterface::QWaylandApplication>(); - auto display = waylandApp->display(); - wl_display_roundtrip(display); - - // If the application is focused, use the normal mechanism so a future paste will not deadlock itselfs - if (m_keyboardFocusWatcher->hasFocus()) { - QGuiApplication::clipboard()->setMimeData(mime, mode); - // if we short-circuit the ext_data_device, when we receive the data - // we cannot identify ourselves as the owner - // because of that we act like it's a synchronous action to not confuse klipper. - wl_display_roundtrip(display); - return; - } - // If not, set the clipboard once the app receives focus to avoid the deadlock - connect(m_keyboardFocusWatcher.get(), &KeyboardFocusWatcher::keyboardEntered, this, &WaylandClipboard::gainedFocus, Qt::UniqueConnection); auto source = std::make_unique<DataControlSource>(m_manager->create_data_source(), mime); + source->moveToThread(m_thread.get()); if (mode == QClipboard::Clipboard) { m_device->setSelection(std::move(source)); } else if (mode == QClipboard::Selection) { @@ -663,31 +655,18 @@ } } -void WaylandClipboard::gainedFocus() -{ - disconnect(m_keyboardFocusWatcher.get(), &KeyboardFocusWatcher::keyboardEntered, this, nullptr); - // QClipboard takes ownership of the QMimeData so we need to transfer and unset our selections - if (auto &selection = m_device->m_selection) { - std::unique_ptr<QMimeData> data = selection->releaseMimeData(); - selection.reset(); - QGuiApplication::clipboard()->setMimeData(data.release(), QClipboard::Clipboard); - } - if (auto &primarySelection = m_device->m_primarySelection) { - std::unique_ptr<QMimeData> data = primarySelection->releaseMimeData(); - primarySelection.reset(); - QGuiApplication::clipboard()->setMimeData(data.release(), QClipboard::Selection); - } -} - void WaylandClipboard::clear(QClipboard::Mode mode) { if (!m_device) { return; } + if (mode == QClipboard::Clipboard) { + QMutexLocker locker(&m_device->m_selectionLock); m_device->set_selection(nullptr); m_device->m_selection.reset(); } else if (mode == QClipboard::Selection) { + QMutexLocker locker(&m_device->m_primarySelectionLock); m_device->set_primary_selection(nullptr); m_device->m_primarySelection.reset(); } @@ -699,24 +678,42 @@ return nullptr; } + // WaylandClipboard owns the mimedata, but the caller can read it until the next event loop runs. + auto lockWithUnlockLater = [this](QRecursiveMutex &mutex) { + mutex.lock(); + QTimer::singleShot(0, this, [&mutex, guard = QPointer<DataControlDevice>(m_device.get())] { + if (!guard) { + return; + } + mutex.unlock(); + }); + }; + // return our locally set selection if it's not cancelled to avoid copying data to ourselves if (mode == QClipboard::Clipboard) { + QMutexLocker lock(&m_device->m_selectionLock); if (m_device->selection()) { return m_device->selection(); } + // This application owns the clipboard via the regular data_device, use it so we don't block ourselves if (QGuiApplication::clipboard()->ownsClipboard()) { return QGuiApplication::clipboard()->mimeData(mode); } + lockWithUnlockLater(m_device->m_selectionLock); return m_device->receivedSelection(); } else if (mode == QClipboard::Selection) { + QMutexLocker lock(&m_device->m_primarySelectionLock); if (m_device->primarySelection()) { return m_device->primarySelection(); } + // This application owns the primary selection via the regular primary_selection_device, use it so we don't block ourselves if (QGuiApplication::clipboard()->ownsSelection()) { return QGuiApplication::clipboard()->mimeData(mode); } + + lockWithUnlockLater(m_device->m_primarySelectionLock); return m_device->receivedPrimarySelection(); } return nullptr; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-6.21.0/src/systemclipboard/waylandclipboard_p.h new/kguiaddons-6.22.0/src/systemclipboard/waylandclipboard_p.h --- old/kguiaddons-6.21.0/src/systemclipboard/waylandclipboard_p.h 2025-12-05 14:21:33.000000000 +0100 +++ new/kguiaddons-6.22.0/src/systemclipboard/waylandclipboard_p.h 2026-01-02 18:41:55.000000000 +0100 @@ -13,10 +13,11 @@ class DataControlDevice; class DataControlDeviceManager; -class KeyboardFocusWatcher; +class ClipboardThread; class WaylandClipboard : public KSystemClipboard { + Q_OBJECT public: ~WaylandClipboard(); static WaylandClipboard *create(QObject *parent); @@ -28,8 +29,7 @@ private: WaylandClipboard(QObject *parent); - void gainedFocus(); - std::unique_ptr<KeyboardFocusWatcher> m_keyboardFocusWatcher; + std::unique_ptr<ClipboardThread> m_thread; std::unique_ptr<DataControlDeviceManager> m_manager; std::unique_ptr<DataControlDevice> m_device; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-6.21.0/tests/CMakeLists.txt new/kguiaddons-6.22.0/tests/CMakeLists.txt --- old/kguiaddons-6.21.0/tests/CMakeLists.txt 2025-12-05 14:21:33.000000000 +0100 +++ new/kguiaddons-6.22.0/tests/CMakeLists.txt 2026-01-02 18:41:55.000000000 +0100 @@ -20,4 +20,5 @@ kcursorsavergui_test kcolorschemewatchertest kcountryflagemojiiconenginedemo + clipboardtest ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kguiaddons-6.21.0/tests/clipboardtest.cpp new/kguiaddons-6.22.0/tests/clipboardtest.cpp --- old/kguiaddons-6.21.0/tests/clipboardtest.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/kguiaddons-6.22.0/tests/clipboardtest.cpp 2026-01-02 18:41:55.000000000 +0100 @@ -0,0 +1,116 @@ +/* + SPDX-FileCopyrightText: 2025 David Edmundson <[email protected]> + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include <KSystemClipboard> +#include <QApplication> +#include <QClipboard> +#include <QFormLayout> +#include <QGroupBox> +#include <QHBoxLayout> +#include <QLabel> +#include <QLineEdit> +#include <QMimeData> +#include <QPushButton> +#include <QTableView> +#include <QTextEdit> +#include <QVBoxLayout> +#include <QWidget> + +// This tests KSystemClipboard +// it also shows the Qt Clipboard so that we can confirm nothing deadlocks +// copying between the two + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + QWidget window; + window.setWindowTitle(QStringLiteral("Clipboard Test")); + + auto *rootLayout = new QHBoxLayout(&window); + + // regular clipboard + { + auto clipboard = QApplication::clipboard(); + auto *group = new QGroupBox(QStringLiteral("Normal Clipboard"), &window); + rootLayout->addWidget(group); + + auto *groupLayout = new QVBoxLayout(group); + + auto *clipboardView = new QTextEdit(&window); + clipboardView->setEnabled(false); + + clipboardView->setMinimumHeight(200); + QObject::connect(clipboard, &QClipboard::changed, clipboardView, [clipboardView, clipboard](QClipboard::Mode mode) { + if (mode != QClipboard::Clipboard) { + return; + } + clipboardView->setText(clipboard->text()); + }); + clipboardView->setText(clipboard->text()); + + groupLayout->addWidget(clipboardView); + + auto *textEdit = new QTextEdit(group); + textEdit->setPlaceholderText(QStringLiteral("Enter clipboard content here…")); + textEdit->setMinimumHeight(120); + groupLayout->addWidget(textEdit); + + auto *btnRow = new QHBoxLayout(); + btnRow->addStretch(); + auto *submitBtn = new QPushButton(QStringLiteral("Submit"), group); + btnRow->addWidget(submitBtn); + groupLayout->addLayout(btnRow); + + QObject::connect(submitBtn, &QPushButton::clicked, &window, [textEdit, clipboard]() { + auto mimeData = new QMimeData; + mimeData->setText(textEdit->toPlainText()); + clipboard->setMimeData(mimeData, QClipboard::Clipboard); + }); + } + // system clipboard + { + auto clipboard = KSystemClipboard::instance(); + auto *group = new QGroupBox(QStringLiteral("System Clipboard"), &window); + rootLayout->addWidget(group); + + auto *groupLayout = new QVBoxLayout(group); + + auto *clipboardView = new QTextEdit(&window); + clipboardView->setEnabled(false); + + clipboardView->setMinimumHeight(200); + QObject::connect(clipboard, &KSystemClipboard::changed, clipboardView, [clipboardView, clipboard](QClipboard::Mode mode) { + if (mode != QClipboard::Clipboard) { + return; + } + clipboardView->setText(clipboard->text(mode)); + }); + clipboardView->setText(clipboard->text(QClipboard::Clipboard)); + + groupLayout->addWidget(clipboardView); + + auto *textEdit = new QTextEdit(group); + textEdit->setPlaceholderText(QStringLiteral("Enter clipboard content here…")); + textEdit->setMinimumHeight(120); + groupLayout->addWidget(textEdit); + + auto *btnRow = new QHBoxLayout(); + btnRow->addStretch(); + auto *submitBtn = new QPushButton(QStringLiteral("Submit"), group); + btnRow->addWidget(submitBtn); + groupLayout->addLayout(btnRow); + + QObject::connect(submitBtn, &QPushButton::clicked, &window, [textEdit, clipboard]() { + auto mimeData = new QMimeData; + mimeData->setText(textEdit->toPlainText()); + clipboard->setMimeData(mimeData, QClipboard::Clipboard); + }); + } + + window.resize(600, 500); + window.show(); + return app.exec(); +}
