From f045cf306c4e581c38ead972ae9e0242e6fca2cd Mon Sep 17 00:00:00 2001 From: Kai Uwe Broulik Date: Mon, 23 May 2022 16:58:31 +0200 Subject: [PATCH] [System Tray] Emit pressed signal on compact representation in popup, too Some actions, such as middle click to mute, trigger only on press. Some applets also need a pressed-click because of some legacy autoclose on focus change bug. Unfortunately, QML does not disambiguate the "pressed" property and "pressed(mouse)" signal with argument, so this has to be done awkwardly through QMetaObject on C++ side. BUG: 426646 BUG: 452893 FIXED-IN: 5.25.0 --- .../contents/ui/items/PlasmoidItem.qml | 9 ++++++- applets/systemtray/systemtray.cpp | 25 +++++++++++++++++++ applets/systemtray/systemtray.h | 8 ++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/applets/systemtray/package/contents/ui/items/PlasmoidItem.qml b/applets/systemtray/package/contents/ui/items/PlasmoidItem.qml index e56cfdb65..9dc2b45de 100644 --- a/applets/systemtray/package/contents/ui/items/PlasmoidItem.qml +++ b/applets/systemtray/package/contents/ui/items/PlasmoidItem.qml @@ -40,7 +40,7 @@ AbstractItem { //forward click event to the applet var appletItem = applet.compactRepresentationItem ? applet.compactRepresentationItem : applet.fullRepresentationItem const mouseArea = findMouseArea(appletItem) - if (mouseArea) { + if (mouseArea && mouse.button !== Qt.RightButton) { mouseArea.clicked(mouse) } else if (mouse.button === Qt.LeftButton) {//falback plasmoidContainer.activated(null) @@ -51,6 +51,13 @@ AbstractItem { // SNI has few problems, for example legacy applications that still use XEmbed require mouse to be released. if (mouse.button === Qt.RightButton) { plasmoidContainer.contextMenu(mouse); + } else { + const appletItem = applet.compactRepresentationItem ? applet.compactRepresentationItem : applet.fullRepresentationItem + const mouseArea = findMouseArea(appletItem) + if (mouseArea) { + // HACK QML only sees the "mouseArea.pressed" property, not the signal. + Plasmoid.nativeInterface.emitPressed(mouseArea, mouse); + } } } onContextMenu: if (applet) { diff --git a/applets/systemtray/systemtray.cpp b/applets/systemtray/systemtray.cpp index cb6eeda3c..28e1b1970 100644 --- a/applets/systemtray/systemtray.cpp +++ b/applets/systemtray/systemtray.cpp @@ -13,6 +13,8 @@ #include "systemtraysettings.h" #include +#include +#include #include #include #include @@ -244,6 +246,29 @@ bool SystemTray::isSystemTrayApplet(const QString &appletId) return false; } +void SystemTray::emitPressed(QQuickItem *mouseArea, QObject *mouseEvent) +{ + if (!mouseArea || !mouseEvent) { + return; + } + + // QQuickMouseEvent is also private, so we cannot use QMetaObject::invokeMethod with Q_ARG + const QMetaObject *mo = mouseArea->metaObject(); + + const int pressedIdx = mo->indexOfSignal("pressed(QQuickMouseEvent*)"); + if (pressedIdx < 0) { + qCWarning(SYSTEM_TRAY) << "Failed to find onPressed signal on" << mouseArea; + return; + } + + QMetaMethod pressedMethod = mo->method(pressedIdx); + + if (!pressedMethod.invoke(mouseArea, Q_ARG(QObject *, mouseEvent))) { + qCWarning(SYSTEM_TRAY) << "Failed to invoke onPressed signal on" << mouseArea << "with" << mouseEvent; + return; + } +} + SystemTrayModel *SystemTray::systemTrayModel() { if (!m_systemTrayModel) { diff --git a/applets/systemtray/systemtray.h b/applets/systemtray/systemtray.h index 34c503fe3..413d45f12 100644 --- a/applets/systemtray/systemtray.h +++ b/applets/systemtray/systemtray.h @@ -66,6 +66,14 @@ public: */ Q_INVOKABLE bool isSystemTrayApplet(const QString &appletId); + /** + * @brief Emits the "onPressed(mouse)" signal of a MouseArea + * + * This is needed because calling mouseArea.pressed from QML + * only sees the "pressed" property, not the signal + */ + Q_INVOKABLE void emitPressed(QQuickItem *mouseArea, QObject /*QQuickMouseEvent*/ *mouseEvent); + /** * Needed to preserve keyboard navigation */