diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenubar.cpp b/src/gui/platform/unix/dbusmenu/qdbusmenubar.cpp index 2c006366cb4..862b60f12d0 100644 --- a/src/gui/platform/unix/dbusmenu/qdbusmenubar.cpp +++ b/src/gui/platform/unix/dbusmenu/qdbusmenubar.cpp @@ -4,6 +4,10 @@ #include "qdbusmenubar_p.h" #include "qdbusmenuregistrarproxy_p.h" +#include +#include +#include + QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; @@ -18,7 +22,6 @@ QDBusMenuBar::QDBusMenuBar() : QPlatformMenuBar() , m_menu(new QDBusPlatformMenu()) , m_menuAdaptor(new QDBusMenuAdaptor(m_menu)) - , m_windowId(0) { QDBusMenuItem::registerDBusTypes(); connect(m_menu, &QDBusPlatformMenu::propertiesUpdated, @@ -88,7 +91,7 @@ void QDBusMenuBar::handleReparent(QWindow *newParentWindow) { if (newParentWindow) { unregisterMenuBar(); - m_windowId = newParentWindow->winId(); + m_window = newParentWindow; registerMenuBar(); } } @@ -116,30 +119,39 @@ void QDBusMenuBar::registerMenuBar() return; QDBusMenuRegistrarInterface registrar(REGISTRAR_SERVICE, REGISTRAR_PATH, connection, this); - QDBusPendingReply<> r = registrar.RegisterWindow(m_windowId, QDBusObjectPath(m_objectPath)); + QDBusPendingReply<> r = registrar.RegisterWindow(m_window->winId(), QDBusObjectPath(m_objectPath)); r.waitForFinished(); if (r.isError()) { qWarning("Failed to register window menu, reason: %s (\"%s\")", qUtf8Printable(r.error().name()), qUtf8Printable(r.error().message())); connection.unregisterObject(m_objectPath); + return; } + const auto unixServices = dynamic_cast( + QGuiApplicationPrivate::platformIntegration()->services()); + unixServices->registerDBusMenuForWindow(m_window, connection.baseService(), m_objectPath); } void QDBusMenuBar::unregisterMenuBar() { QDBusConnection connection = QDBusConnection::sessionBus(); - if (m_windowId) { + if (m_window) { QDBusMenuRegistrarInterface registrar(REGISTRAR_SERVICE, REGISTRAR_PATH, connection, this); - QDBusPendingReply<> r = registrar.UnregisterWindow(m_windowId); + QDBusPendingReply<> r = registrar.UnregisterWindow(m_window->winId()); r.waitForFinished(); if (r.isError()) qWarning("Failed to unregister window menu, reason: %s (\"%s\")", qUtf8Printable(r.error().name()), qUtf8Printable(r.error().message())); + + const auto unixServices = dynamic_cast( + QGuiApplicationPrivate::platformIntegration()->services()); + unixServices->unregisterDBusMenuForWindow(m_window); } - if (!m_objectPath.isEmpty()) + if (!m_objectPath.isEmpty()) { connection.unregisterObject(m_objectPath); + } } QT_END_NAMESPACE diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenubar_p.h b/src/gui/platform/unix/dbusmenu/qdbusmenubar_p.h index 3028df7215d..24c63802aa1 100644 --- a/src/gui/platform/unix/dbusmenu/qdbusmenubar_p.h +++ b/src/gui/platform/unix/dbusmenu/qdbusmenubar_p.h @@ -42,7 +42,7 @@ private: QDBusPlatformMenu *m_menu; QDBusMenuAdaptor *m_menuAdaptor; QHash m_menuItems; - uint m_windowId; + QPointer m_window; QString m_objectPath; QDBusPlatformMenuItem *menuItemForMenu(QPlatformMenu *menu); diff --git a/src/gui/platform/unix/qgenericunixservices.cpp b/src/gui/platform/unix/qgenericunixservices.cpp index 3aa071b8b26..32487b16511 100644 --- a/src/gui/platform/unix/qgenericunixservices.cpp +++ b/src/gui/platform/unix/qgenericunixservices.cpp @@ -577,6 +577,20 @@ QString QGenericUnixServices::portalWindowIdentifier(QWindow *window) return QString(); } + +void QGenericUnixServices::registerDBusMenuForWindow(QWindow *window, const QString &service, const QString &path) +{ + Q_UNUSED(window); + Q_UNUSED(service); + Q_UNUSED(path); +} + +void QGenericUnixServices::unregisterDBusMenuForWindow(QWindow *window) +{ + Q_UNUSED(window); +} + + bool QGenericUnixServices::hasCapability(Capability capability) const { switch (capability) { diff --git a/src/gui/platform/unix/qgenericunixservices_p.h b/src/gui/platform/unix/qgenericunixservices_p.h index 8bb49527793..9e34f090229 100644 --- a/src/gui/platform/unix/qgenericunixservices_p.h +++ b/src/gui/platform/unix/qgenericunixservices_p.h @@ -39,6 +39,9 @@ public: void setApplicationBadge(qint64 number); virtual QString portalWindowIdentifier(QWindow *window); + virtual void registerDBusMenuForWindow(QWindow *window, const QString &service, const QString &path); + virtual void unregisterDBusMenuForWindow(QWindow *window); + private: QString m_webBrowser; QString m_documentLauncher; diff --git a/src/plugins/platforms/xcb/qxcbatom.cpp b/src/plugins/platforms/xcb/qxcbatom.cpp index dd5596653cd..d31773a34db 100644 --- a/src/plugins/platforms/xcb/qxcbatom.cpp +++ b/src/plugins/platforms/xcb/qxcbatom.cpp @@ -204,6 +204,8 @@ static const char *xcb_atomnames = { "EDID_DATA\0" "XFree86_DDC_EDID1_RAWDATA\0" "_ICC_PROFILE\0" + "_KDE_NET_WM_APPMENU_SERVICE_NAME\0" + "_KDE_NET_WM_APPMENU_OBJECT_PATH\0" // \0\0 terminates loop. }; diff --git a/src/plugins/platforms/xcb/qxcbatom.h b/src/plugins/platforms/xcb/qxcbatom.h index bc677eaf3e3..7dd52f122c7 100644 --- a/src/plugins/platforms/xcb/qxcbatom.h +++ b/src/plugins/platforms/xcb/qxcbatom.h @@ -211,6 +211,10 @@ public: Atom_ICC_PROFILE, + // AppMenu + Atom_KDE_NET_WM_APPMENU_SERVICE_NAME, + Atom_KDE_NET_WM_APPMENU_OBJECT_PATH, + NAtoms }; diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 4dafae31e31..fc5a7e55c50 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -93,10 +93,12 @@ static bool runningUnderDebugger() #endif } -class QXcbUnixServices : public QGenericUnixServices +class QXcbUnixServices : public QGenericUnixServices, public QXcbObject { public: QString portalWindowIdentifier(QWindow *window) override; + void registerDBusMenuForWindow(QWindow *window, const QString &service, const QString &path) override; + void unregisterDBusMenuForWindow(QWindow *window) override; }; @@ -173,6 +175,7 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char m_connection = nullptr; return; } + m_services->setConnection(m_connection); m_fontDatabase.reset(new QGenericUnixFontDatabase()); @@ -601,4 +604,30 @@ QString QXcbUnixServices::portalWindowIdentifier(QWindow *window) return "x11:"_L1 + QString::number(window->winId(), 16); } +void QXcbUnixServices::registerDBusMenuForWindow(QWindow *window, const QString &service, const QString &path) +{ + const QByteArray serviceValue = service.toLatin1(); + const QByteArray pathValue = path.toLatin1(); + + xcb_change_property(xcb_connection(), + XCB_PROP_MODE_REPLACE, window->winId(), + atom(QXcbAtom::Atom_KDE_NET_WM_APPMENU_SERVICE_NAME), + XCB_ATOM_STRING, 8, + serviceValue.length(), + serviceValue.constData()); + + xcb_change_property(xcb_connection(), + XCB_PROP_MODE_REPLACE, window->winId(), + atom(QXcbAtom::Atom_KDE_NET_WM_APPMENU_OBJECT_PATH), + XCB_ATOM_STRING, 8, + pathValue.length(), + pathValue.constData()); +} + +void QXcbUnixServices::unregisterDBusMenuForWindow(QWindow *window) +{ + xcb_delete_property(xcb_connection(), window->winId(), atom(QXcbAtom::Atom_KDE_NET_WM_APPMENU_SERVICE_NAME)); + xcb_delete_property(xcb_connection(), window->winId(), atom(QXcbAtom::Atom_KDE_NET_WM_APPMENU_OBJECT_PATH)); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index a1e0c3f3e1b..a5323496f75 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -18,6 +18,7 @@ QT_BEGIN_NAMESPACE class QXcbConnection; class QAbstractEventDispatcher; class QXcbNativeInterface; +class QXcbUnixServices; class Q_XCB_EXPORT QXcbIntegration : public QPlatformIntegration #ifndef QT_NO_OPENGL @@ -115,7 +116,7 @@ private: mutable QScopedPointer m_accessibility; #endif - QScopedPointer m_services; + QScopedPointer m_services; mutable QByteArray m_wmClass; const char *m_instanceName;