From 338772ca404e35ee54d98ba6c8c8f5b9224b6d0f Mon Sep 17 00:00:00 2001 From: David Redondo Date: Mon, 7 Mar 2022 14:25:36 +0100 Subject: [PATCH] Open Klipper under mouse also on wayland On Wayland if Plasma had no focus when the shortcut was invoked - the menu window is created as toplevel because it has no parent and there is no current focusWindow - the application can't know the currrent cursor position We use a newly introduced request on plasma_surface to open under the cursor. As it can only be called before mapping a buffer to a surface, the menu is hidden before being shown again. BUG:436249 FIXED-IN:5.25 --- klipper/CMakeLists.txt | 1 + klipper/klipper.cpp | 35 ++++++++++++++++++++++++++++++++++- klipper/klipper.h | 11 +++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/klipper/CMakeLists.txt b/klipper/CMakeLists.txt index 0370354ba..825533db2 100644 --- a/klipper/CMakeLists.txt +++ b/klipper/CMakeLists.txt @@ -47,6 +47,7 @@ target_link_libraries(libklipper_common_static KF5::WindowSystem KF5::WidgetsAddons KF5::XmlGui + KF5::WaylandClient ${ZLIB_LIBRARY}) if (X11_FOUND) target_link_libraries(libklipper_common_static XCB::XCB) diff --git a/klipper/klipper.cpp b/klipper/klipper.cpp index 3b11c6ecc..c91e1d134 100644 --- a/klipper/klipper.cpp +++ b/klipper/klipper.cpp @@ -27,6 +27,10 @@ #include #include #include +#include +#include +#include +#include #include #include "configdialog.h" @@ -113,6 +117,7 @@ Klipper::Klipper(QObject *parent, const KSharedConfigPtr &config, KlipperMode mo , m_config(config) , m_pendingContentsCheck(false) , m_mode(mode) + , m_plasmashell(nullptr) { if (m_mode == KlipperMode::Standalone) { setenv("KSNI_NO_DBUSMENU", "1", 1); @@ -249,6 +254,18 @@ Klipper::Klipper(QObject *parent, const KSharedConfigPtr &config, KlipperMode mo m_notification->setHint(QStringLiteral("desktop-entry"), QStringLiteral("org.kde.klipper")); } }); + + if (KWindowSystem::isPlatformWayland()) { + auto registry = new KWayland::Client::Registry(this); + auto connection = KWayland::Client::ConnectionThread::fromApplication(qGuiApp); + connect(registry, &KWayland::Client::Registry::plasmaShellAnnounced, this, [registry, this](quint32 name, quint32 version) { + if (!m_plasmashell) { + m_plasmashell = registry->createPlasmaShell(name, version); + } + }); + registry->create(connection); + registry->setup(); + } } Klipper::~Klipper() @@ -384,10 +401,26 @@ void Klipper::saveSettings() const void Klipper::showPopupMenu(QMenu *menu) { Q_ASSERT(menu != nullptr); - + if (m_plasmashell) { + menu->hide(); + menu->windowHandle()->installEventFilter(this); + } menu->popup(QCursor::pos()); } +bool Klipper::eventFilter(QObject *filtered, QEvent *event) +{ + const bool ret = QObject::eventFilter(filtered, event); + auto menuWindow = qobject_cast(filtered); + if (menuWindow && event->type() == QEvent::Expose && menuWindow->isVisible()) { + auto surface = KWayland::Client::Surface::fromWindow(menuWindow); + auto plasmaSurface = m_plasmashell->createSurface(surface, menuWindow); + plasmaSurface->openUnderCursor(); + menuWindow->removeEventFilter(this); + } + return ret; +} + bool Klipper::loadHistory() { static const char failed_load_warning[] = "Failed to load history resource. Clipboard history cannot be read."; diff --git a/klipper/klipper.h b/klipper/klipper.h index 81ffa13fb..306c55538 100644 --- a/klipper/klipper.h +++ b/klipper/klipper.h @@ -31,6 +31,14 @@ class HistoryItem; class KNotification; class KSystemClipboard; +namespace KWayland +{ +namespace Client +{ +class PlasmaShell; +} +} + enum class KlipperMode { Standalone, DataEngine, @@ -65,6 +73,8 @@ public: Klipper(QObject *parent, const KSharedConfigPtr &config, KlipperMode mode = KlipperMode::Standalone); ~Klipper() override; + bool eventFilter(QObject *object, QEvent *event) override; + /** * Get clipboard history (the "document") */ @@ -223,4 +233,5 @@ private: KlipperMode m_mode; QTimer *m_saveFileTimer = nullptr; QPointer m_notification; + KWayland::Client::PlasmaShell *m_plasmashell; };