diff --git a/src/main_wayland.cpp b/src/main_wayland.cpp index f108b5f2a3..e462c1e4b5 100644 --- a/src/main_wayland.cpp +++ b/src/main_wayland.cpp @@ -202,7 +202,7 @@ void ApplicationWayland::refreshSettings(const KConfigGroup &group, const QByteA } if (group.name() == "Wayland" && names.contains("EnablePrimarySelection")) { - waylandServer()->setEnablePrimarySelection(group.readEntry("EnablePrimarySelection", true)); + waylandServer()->seat()->setPrimarySelectionEnabled(group.readEntry("EnablePrimarySelection", true)); } } diff --git a/src/wayland/autotests/server/test_datacontrol_interface.cpp b/src/wayland/autotests/server/test_datacontrol_interface.cpp index e2a1850157..1bd77a5370 100644 --- a/src/wayland/autotests/server/test_datacontrol_interface.cpp +++ b/src/wayland/autotests/server/test_datacontrol_interface.cpp @@ -122,11 +122,16 @@ public: Q_UNUSED(mimeType); Q_UNUSED(fd); }; - void cancel() override{}; + void cancel() override + { + Q_EMIT cancelled(); + }; QStringList mimeTypes() const override { return {"text/test1", "text/test2"}; } +Q_SIGNALS: + void cancelled(); }; // The test itself @@ -143,6 +148,7 @@ private Q_SLOTS: void testCopyFromControl(); void testCopyFromControlPrimarySelection(); void testKlipperCase(); + void testPrimarySelectionDisabled(); private: KWayland::Client::ConnectionThread *m_connection; @@ -298,6 +304,32 @@ void DataControlInterfaceTest::testCopyToControlPrimarySelection() QCOMPARE(offer->receivedOffers()[1], "text/test2"); } +void DataControlInterfaceTest::testPrimarySelectionDisabled() +{ + // we set a dummy data source on the seat using abstract client directly + // then confirm we receive the offer despite not having a surface + + // disable primary selection + m_seat->setPrimarySelectionEnabled(false); + + std::unique_ptr dataControlDevice(new DataControlDevice); + dataControlDevice->init(m_dataControlDeviceManager->get_data_device(*m_clientSeat)); + + QSignalSpy newOfferSpy(dataControlDevice.get(), &DataControlDevice::dataControlOffer); + QSignalSpy selectionSpy(dataControlDevice.get(), &DataControlDevice::primary_selection); + + std::unique_ptr testSelection(new TestDataSource); + QSignalSpy cancelSpy(testSelection.get(), &TestDataSource::cancelled); + + m_seat->setPrimarySelection(testSelection.get()); + + // selection will be sent after we've been sent a new offer object and the mimes have been sent to that object + cancelSpy.wait(); + + QCOMPARE(newOfferSpy.count(), 0); + QCOMPARE(cancelSpy.count(), 1); +} + void DataControlInterfaceTest::testCopyFromControl() { // we create a data device and set a selection diff --git a/src/wayland/seat_interface.cpp b/src/wayland/seat_interface.cpp index 9cb5fbbf5c..8d7d43ebdd 100644 --- a/src/wayland/seat_interface.cpp +++ b/src/wayland/seat_interface.cpp @@ -1316,6 +1316,14 @@ AbstractDataSource *SeatInterface::primarySelection() const return d->currentPrimarySelection; } +void SeatInterface::setPrimarySelectionEnabled(bool enabled) +{ + if (enabled != d->primarySelectionEnabled) { + setPrimarySelection(nullptr); + d->primarySelectionEnabled = enabled; + } +} + void SeatInterface::setPrimarySelection(AbstractDataSource *selection) { if (d->currentPrimarySelection == selection) { @@ -1326,6 +1334,13 @@ void SeatInterface::setPrimarySelection(AbstractDataSource *selection) disconnect(d->currentPrimarySelection, nullptr, this, nullptr); } + if (!d->primarySelectionEnabled) { + if (selection) { + selection->cancel(); + } + return; + } + if (selection) { auto cleanup = [this]() { setPrimarySelection(nullptr); diff --git a/src/wayland/seat_interface.h b/src/wayland/seat_interface.h index 954f61e4b6..57d8e245cd 100644 --- a/src/wayland/seat_interface.h +++ b/src/wayland/seat_interface.h @@ -170,6 +170,8 @@ public: void setTimestamp(quint32 time); quint32 timestamp() const; + void setPrimarySelectionEnabled(bool enabled); + /** * @name Drag'n'Drop related methods */ diff --git a/src/wayland/seat_interface_p.h b/src/wayland/seat_interface_p.h index ff9457657c..de2712d09a 100644 --- a/src/wayland/seat_interface_p.h +++ b/src/wayland/seat_interface_p.h @@ -67,6 +67,7 @@ public: // the last thing copied into the clipboard content AbstractDataSource *currentSelection = nullptr; AbstractDataSource *currentPrimarySelection = nullptr; + bool primarySelectionEnabled = true; // Pointer related members struct Pointer diff --git a/src/wayland_server.cpp b/src/wayland_server.cpp index c469599976..2c54a81dfc 100644 --- a/src/wayland_server.cpp +++ b/src/wayland_server.cpp @@ -306,16 +306,6 @@ void WaylandServer::handleOutputDisabled(Output *output) } } -void WaylandServer::setEnablePrimarySelection(bool enable) -{ - if (!enable && m_primarySelectionDeviceManager != nullptr) { - delete m_primarySelectionDeviceManager; - m_primarySelectionDeviceManager = nullptr; - } else if (enable && m_primarySelectionDeviceManager == nullptr) { - m_primarySelectionDeviceManager = new PrimarySelectionDeviceManagerV1Interface(m_display, m_display); - } -} - bool WaylandServer::start() { return m_display->start(); @@ -396,7 +386,8 @@ bool WaylandServer::init(InitializationFlags flags) new DataControlDeviceManagerV1Interface(m_display, m_display); const auto kwinConfig = kwinApp()->config(); - setEnablePrimarySelection(kwinConfig->group("Wayland").readEntry("EnablePrimarySelection", true)); + m_seat->setPrimarySelectionEnabled(kwinConfig->group("Wayland").readEntry("EnablePrimarySelection", true)); + new PrimarySelectionDeviceManagerV1Interface(m_display, m_display); m_idle = new IdleInterface(m_display, m_display); auto idleInhibition = new IdleInhibition(m_idle); diff --git a/src/wayland_server.h b/src/wayland_server.h index d9440112b8..d35867e32d 100644 --- a/src/wayland_server.h +++ b/src/wayland_server.h @@ -48,7 +48,6 @@ class LinuxDmaBufV1ClientBuffer; class TabletManagerV2Interface; class KeyboardShortcutsInhibitManagerV1Interface; class XdgDecorationManagerV1Interface; -class PrimarySelectionDeviceManagerV1Interface; class XWaylandKeyboardGrabManagerV1Interface; } @@ -221,7 +220,6 @@ public: { m_linuxDmabufBuffers.remove(buffer); } - void setEnablePrimarySelection(bool enable); /** * Returns the first socket name that can be used to connect to this server. @@ -289,7 +287,6 @@ private: KWaylandServer::XdgForeignV2Interface *m_XdgForeign = nullptr; KWaylandServer::PrimaryOutputV1Interface *m_primary = nullptr; XdgActivationV1Integration *m_xdgActivationIntegration = nullptr; - KWaylandServer::PrimarySelectionDeviceManagerV1Interface *m_primarySelectionDeviceManager = nullptr; KWaylandServer::XWaylandKeyboardGrabManagerV1Interface *m_xWaylandKeyboardGrabManager = nullptr; QList m_windows; InitializationFlags m_initFlags;