diff options
Diffstat (limited to 'src/gui/platform/unix/dbusmenu')
-rw-r--r-- | src/gui/platform/unix/dbusmenu/dbusmenu.pri | 15 | ||||
-rw-r--r-- | src/gui/platform/unix/dbusmenu/qdbusmenuadaptor.cpp | 163 | ||||
-rw-r--r-- | src/gui/platform/unix/dbusmenu/qdbusmenuadaptor_p.h | 182 | ||||
-rw-r--r-- | src/gui/platform/unix/dbusmenu/qdbusmenubar.cpp | 179 | ||||
-rw-r--r-- | src/gui/platform/unix/dbusmenu/qdbusmenubar_p.h | 92 | ||||
-rw-r--r-- | src/gui/platform/unix/dbusmenu/qdbusmenuconnection.cpp | 147 | ||||
-rw-r--r-- | src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h | 101 | ||||
-rw-r--r-- | src/gui/platform/unix/dbusmenu/qdbusmenuregistrarproxy.cpp | 64 | ||||
-rw-r--r-- | src/gui/platform/unix/dbusmenu/qdbusmenuregistrarproxy_p.h | 119 | ||||
-rw-r--r-- | src/gui/platform/unix/dbusmenu/qdbusmenutypes.cpp | 303 | ||||
-rw-r--r-- | src/gui/platform/unix/dbusmenu/qdbusmenutypes_p.h | 155 | ||||
-rw-r--r-- | src/gui/platform/unix/dbusmenu/qdbusplatformmenu.cpp | 308 | ||||
-rw-r--r-- | src/gui/platform/unix/dbusmenu/qdbusplatformmenu_p.h | 191 |
13 files changed, 2019 insertions, 0 deletions
diff --git a/src/gui/platform/unix/dbusmenu/dbusmenu.pri b/src/gui/platform/unix/dbusmenu/dbusmenu.pri new file mode 100644 index 0000000000..c328f23144 --- /dev/null +++ b/src/gui/platform/unix/dbusmenu/dbusmenu.pri @@ -0,0 +1,15 @@ +HEADERS += \ + platform/unix/dbusmenu/qdbusmenuadaptor_p.h \ + platform/unix/dbusmenu/qdbusmenutypes_p.h \ + platform/unix/dbusmenu/qdbusmenuconnection_p.h \ + platform/unix/dbusmenu/qdbusmenubar_p.h \ + platform/unix/dbusmenu/qdbusmenuregistrarproxy_p.h \ + platform/unix/dbusmenu/qdbusplatformmenu_p.h + +SOURCES += \ + platform/unix/dbusmenu/qdbusmenuadaptor.cpp \ + platform/unix/dbusmenu/qdbusmenutypes.cpp \ + platform/unix/dbusmenu/qdbusmenuconnection.cpp \ + platform/unix/dbusmenu/qdbusmenubar.cpp \ + platform/unix/dbusmenu/qdbusmenuregistrarproxy.cpp \ + platform/unix/dbusmenu/qdbusplatformmenu.cpp diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenuadaptor.cpp b/src/gui/platform/unix/dbusmenu/qdbusmenuadaptor.cpp new file mode 100644 index 0000000000..eabb4b4122 --- /dev/null +++ b/src/gui/platform/unix/dbusmenu/qdbusmenuadaptor.cpp @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + This file was originally created by qdbusxml2cpp version 0.8 + Command line was: + qdbusxml2cpp -a dbusmenu ../../3rdparty/dbus-ifaces/dbus-menu.xml + + However it is maintained manually. +*/ + +#include "qdbusmenuadaptor_p.h" +#include "qdbusplatformmenu_p.h" +#include <QtCore/QMetaObject> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> + +QT_BEGIN_NAMESPACE + +QDBusMenuAdaptor::QDBusMenuAdaptor(QDBusPlatformMenu *topLevelMenu) + : QDBusAbstractAdaptor(topLevelMenu) + , m_topLevelMenu(topLevelMenu) +{ + setAutoRelaySignals(true); +} + +QDBusMenuAdaptor::~QDBusMenuAdaptor() +{ +} + +QString QDBusMenuAdaptor::status() const +{ + qCDebug(qLcMenu); + return QLatin1String("normal"); +} + +QString QDBusMenuAdaptor::textDirection() const +{ + return QLocale().textDirection() == Qt::RightToLeft ? QLatin1String("rtl") : QLatin1String("ltr"); +} + +uint QDBusMenuAdaptor::version() const +{ + return 4; +} + +bool QDBusMenuAdaptor::AboutToShow(int id) +{ + qCDebug(qLcMenu) << id; + if (id == 0) { + emit m_topLevelMenu->aboutToShow(); + } else { + QDBusPlatformMenuItem *item = QDBusPlatformMenuItem::byId(id); + if (item) { + const QDBusPlatformMenu *menu = static_cast<const QDBusPlatformMenu *>(item->menu()); + if (menu) + emit const_cast<QDBusPlatformMenu *>(menu)->aboutToShow(); + } + } + return false; // updateNeeded (we don't know that, so false) +} + +QList<int> QDBusMenuAdaptor::AboutToShowGroup(const QList<int> &ids, QList<int> &idErrors) +{ + qCDebug(qLcMenu) << ids; + Q_UNUSED(idErrors) + idErrors.clear(); + for (int id : ids) + AboutToShow(id); + return QList<int>(); // updatesNeeded +} + +void QDBusMenuAdaptor::Event(int id, const QString &eventId, const QDBusVariant &data, uint timestamp) +{ + Q_UNUSED(data) + Q_UNUSED(timestamp) + QDBusPlatformMenuItem *item = QDBusPlatformMenuItem::byId(id); + qCDebug(qLcMenu) << id << (item ? item->text() : QLatin1String("")) << eventId; + if (item && eventId == QLatin1String("clicked")) + item->trigger(); + if (item && eventId == QLatin1String("hovered")) + emit item->hovered(); + if (eventId == QLatin1String("closed")) { + // There is no explicit AboutToHide method, so map closed event to aboutToHide method + const QDBusPlatformMenu *menu = nullptr; + if (item) + menu = static_cast<const QDBusPlatformMenu *>(item->menu()); + else if (id == 0) + menu = m_topLevelMenu; + if (menu) + emit const_cast<QDBusPlatformMenu *>(menu)->aboutToHide(); + } +} + +QList<int> QDBusMenuAdaptor::EventGroup(const QDBusMenuEventList &events) +{ + for (const QDBusMenuEvent &ev : events) + Event(ev.m_id, ev.m_eventId, ev.m_data, ev.m_timestamp); + return QList<int>(); // idErrors +} + +QDBusMenuItemList QDBusMenuAdaptor::GetGroupProperties(const QList<int> &ids, const QStringList &propertyNames) +{ + qCDebug(qLcMenu) << ids << propertyNames << "=>" << QDBusMenuItem::items(ids, propertyNames); + return QDBusMenuItem::items(ids, propertyNames); +} + +uint QDBusMenuAdaptor::GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, QDBusMenuLayoutItem &layout) +{ + uint ret = layout.populate(parentId, recursionDepth, propertyNames, m_topLevelMenu); + qCDebug(qLcMenu) << parentId << "depth" << recursionDepth << propertyNames << layout.m_id << layout.m_properties << "revision" << ret << layout; + return ret; +} + +QDBusVariant QDBusMenuAdaptor::GetProperty(int id, const QString &name) +{ + qCDebug(qLcMenu) << id << name; + // handle method call com.canonical.dbusmenu.GetProperty + QDBusVariant value; + return value; +} + +QT_END_NAMESPACE diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenuadaptor_p.h b/src/gui/platform/unix/dbusmenu/qdbusmenuadaptor_p.h new file mode 100644 index 0000000000..6612f019a7 --- /dev/null +++ b/src/gui/platform/unix/dbusmenu/qdbusmenuadaptor_p.h @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtDBus module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + This file was originally created by qdbusxml2cpp version 0.8 + Command line was: + qdbusxml2cpp -a dbusmenu ../../3rdparty/dbus-ifaces/dbus-menu.xml + + However it is maintained manually. + + It is also not part of the public API. This header file may change from + version to version without notice, or even be removed. +*/ + +#ifndef DBUSMENUADAPTOR_H +#define DBUSMENUADAPTOR_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QObject> +#include <QtDBus/QtDBus> +#include "qdbusmenutypes_p.h" + +QT_BEGIN_NAMESPACE + +/* + * Adaptor class for interface com.canonical.dbusmenu + */ +class QDBusMenuAdaptor: public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "com.canonical.dbusmenu") + Q_CLASSINFO("D-Bus Introspection", "" +" <interface name=\"com.canonical.dbusmenu\">\n" +" <property access=\"read\" type=\"u\" name=\"Version\">\n" +" </property>\n" +" <property access=\"read\" type=\"s\" name=\"TextDirection\">\n" +" </property>\n" +" <property access=\"read\" type=\"s\" name=\"Status\">\n" +" </property>\n" +" <property access=\"read\" type=\"as\" name=\"IconThemePath\">\n" +" </property>\n" +" <method name=\"GetLayout\">\n" +" <annotation value=\"QDBusMenuLayoutItem\" name=\"org.qtproject.QtDBus.QtTypeName.Out1\"/>\n" +" <arg direction=\"in\" type=\"i\" name=\"parentId\"/>\n" +" <arg direction=\"in\" type=\"i\" name=\"recursionDepth\"/>\n" +" <arg direction=\"in\" type=\"as\" name=\"propertyNames\"/>\n" +" <arg direction=\"out\" type=\"u\" name=\"revision\"/>\n" +" <arg direction=\"out\" type=\"(ia{sv}av)\" name=\"layout\"/>\n" +" </method>\n" +" <method name=\"GetGroupProperties\">\n" +" <annotation value=\"QList<int>\" name=\"org.qtproject.QtDBus.QtTypeName.In0\"/>\n" +" <annotation value=\"QDBusMenuItemList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n" +" <arg direction=\"in\" type=\"ai\" name=\"ids\"/>\n" +" <arg direction=\"in\" type=\"as\" name=\"propertyNames\"/>\n" +" <arg direction=\"out\" type=\"a(ia{sv})\" name=\"properties\"/>\n" +" </method>\n" +" <method name=\"GetProperty\">\n" +" <arg direction=\"in\" type=\"i\" name=\"id\"/>\n" +" <arg direction=\"in\" type=\"s\" name=\"name\"/>\n" +" <arg direction=\"out\" type=\"v\" name=\"value\"/>\n" +" </method>\n" +" <method name=\"Event\">\n" +" <arg direction=\"in\" type=\"i\" name=\"id\"/>\n" +" <arg direction=\"in\" type=\"s\" name=\"eventId\"/>\n" +" <arg direction=\"in\" type=\"v\" name=\"data\"/>\n" +" <arg direction=\"in\" type=\"u\" name=\"timestamp\"/>\n" +" </method>\n" +" <method name=\"EventGroup\">\n" +" <annotation value=\"QList<QDBusMenuEvent>\" name=\"org.qtproject.QtDBus.QtTypeName.In0\"/>\n" +" <annotation value=\"QList<int>\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n" +" <arg direction=\"in\" type=\"a(isvu)\" name=\"events\"/>\n" +" <arg direction=\"out\" type=\"ai\" name=\"idErrors\"/>\n" +" </method>\n" +" <method name=\"AboutToShow\">\n" +" <arg direction=\"in\" type=\"i\" name=\"id\"/>\n" +" <arg direction=\"out\" type=\"b\" name=\"needUpdate\"/>\n" +" </method>\n" +" <method name=\"AboutToShowGroup\">\n" +" <annotation value=\"QList<int>\" name=\"org.qtproject.QtDBus.QtTypeName.In0\"/>\n" +" <annotation value=\"QList<int>\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n" +" <annotation value=\"QList<int>\" name=\"org.qtproject.QtDBus.QtTypeName.Out1\"/>\n" +" <arg direction=\"in\" type=\"ai\" name=\"ids\"/>\n" +" <arg direction=\"out\" type=\"ai\" name=\"updatesNeeded\"/>\n" +" <arg direction=\"out\" type=\"ai\" name=\"idErrors\"/>\n" +" </method>\n" +" <signal name=\"ItemsPropertiesUpdated\">\n" +" <annotation value=\"QDBusMenuItemList\" name=\"org.qtproject.QtDBus.QtTypeName.In0\"/>\n" +" <annotation value=\"QDBusMenuItemKeysList\" name=\"org.qtproject.QtDBus.QtTypeName.In1\"/>\n" +" <arg direction=\"out\" type=\"a(ia{sv})\" name=\"updatedProps\"/>\n" +" <arg direction=\"out\" type=\"a(ias)\" name=\"removedProps\"/>\n" +" </signal>\n" +" <signal name=\"LayoutUpdated\">\n" +" <arg direction=\"out\" type=\"u\" name=\"revision\"/>\n" +" <arg direction=\"out\" type=\"i\" name=\"parent\"/>\n" +" </signal>\n" +" <signal name=\"ItemActivationRequested\">\n" +" <arg direction=\"out\" type=\"i\" name=\"id\"/>\n" +" <arg direction=\"out\" type=\"u\" name=\"timestamp\"/>\n" +" </signal>\n" +" </interface>\n" + "") +public: + QDBusMenuAdaptor(QDBusPlatformMenu *topLevelMenu); + virtual ~QDBusMenuAdaptor(); + +public: // PROPERTIES + Q_PROPERTY(QString Status READ status) + QString status() const; + + Q_PROPERTY(QString TextDirection READ textDirection) + QString textDirection() const; + + Q_PROPERTY(uint Version READ version) + uint version() const; + +public Q_SLOTS: // METHODS + bool AboutToShow(int id); + QList<int> AboutToShowGroup(const QList<int> &ids, QList<int> &idErrors); + void Event(int id, const QString &eventId, const QDBusVariant &data, uint timestamp); + QList<int> EventGroup(const QDBusMenuEventList &events); + QDBusMenuItemList GetGroupProperties(const QList<int> &ids, const QStringList &propertyNames); + uint GetLayout(int parentId, int recursionDepth, const QStringList &propertyNames, QDBusMenuLayoutItem &layout); + QDBusVariant GetProperty(int id, const QString &name); + +Q_SIGNALS: // SIGNALS + void ItemActivationRequested(int id, uint timestamp); + void ItemsPropertiesUpdated(const QDBusMenuItemList &updatedProps, const QDBusMenuItemKeysList &removedProps); + void LayoutUpdated(uint revision, int parent); + +private: + QDBusPlatformMenu *m_topLevelMenu; +}; + +QT_END_NAMESPACE + +#endif // DBUSMENUADAPTOR_H diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenubar.cpp b/src/gui/platform/unix/dbusmenu/qdbusmenubar.cpp new file mode 100644 index 0000000000..b13c875854 --- /dev/null +++ b/src/gui/platform/unix/dbusmenu/qdbusmenubar.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Dmitry Shachnev <mitya57@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdbusmenubar_p.h" +#include "qdbusmenuregistrarproxy_p.h" + +QT_BEGIN_NAMESPACE + +/* note: do not change these to QStringLiteral; + we are unloaded before QtDBus is done using the strings. + */ +#define REGISTRAR_SERVICE QLatin1String("com.canonical.AppMenu.Registrar") +#define REGISTRAR_PATH QLatin1String("/com/canonical/AppMenu/Registrar") + +QDBusMenuBar::QDBusMenuBar() + : QPlatformMenuBar() + , m_menu(new QDBusPlatformMenu()) + , m_menuAdaptor(new QDBusMenuAdaptor(m_menu)) + , m_windowId(0) +{ + QDBusMenuItem::registerDBusTypes(); + connect(m_menu, &QDBusPlatformMenu::propertiesUpdated, + m_menuAdaptor, &QDBusMenuAdaptor::ItemsPropertiesUpdated); + connect(m_menu, &QDBusPlatformMenu::updated, + m_menuAdaptor, &QDBusMenuAdaptor::LayoutUpdated); + connect(m_menu, &QDBusPlatformMenu::popupRequested, + m_menuAdaptor, &QDBusMenuAdaptor::ItemActivationRequested); +} + +QDBusMenuBar::~QDBusMenuBar() +{ + unregisterMenuBar(); + delete m_menuAdaptor; + delete m_menu; + qDeleteAll(m_menuItems); +} + +QDBusPlatformMenuItem *QDBusMenuBar::menuItemForMenu(QPlatformMenu *menu) +{ + if (!menu) + return nullptr; + quintptr tag = menu->tag(); + const auto it = m_menuItems.constFind(tag); + if (it != m_menuItems.cend()) { + return *it; + } else { + QDBusPlatformMenuItem *item = new QDBusPlatformMenuItem; + updateMenuItem(item, menu); + m_menuItems.insert(tag, item); + return item; + } +} + +void QDBusMenuBar::updateMenuItem(QDBusPlatformMenuItem *item, QPlatformMenu *menu) +{ + const QDBusPlatformMenu *ourMenu = qobject_cast<const QDBusPlatformMenu *>(menu); + item->setText(ourMenu->text()); + item->setIcon(ourMenu->icon()); + item->setEnabled(ourMenu->isEnabled()); + item->setVisible(ourMenu->isVisible()); + item->setMenu(menu); +} + +void QDBusMenuBar::insertMenu(QPlatformMenu *menu, QPlatformMenu *before) +{ + QDBusPlatformMenuItem *menuItem = menuItemForMenu(menu); + QDBusPlatformMenuItem *beforeItem = menuItemForMenu(before); + m_menu->insertMenuItem(menuItem, beforeItem); + m_menu->emitUpdated(); +} + +void QDBusMenuBar::removeMenu(QPlatformMenu *menu) +{ + QDBusPlatformMenuItem *menuItem = menuItemForMenu(menu); + m_menu->removeMenuItem(menuItem); + m_menu->emitUpdated(); +} + +void QDBusMenuBar::syncMenu(QPlatformMenu *menu) +{ + QDBusPlatformMenuItem *menuItem = menuItemForMenu(menu); + updateMenuItem(menuItem, menu); +} + +void QDBusMenuBar::handleReparent(QWindow *newParentWindow) +{ + if (newParentWindow) { + unregisterMenuBar(); + m_windowId = newParentWindow->winId(); + registerMenuBar(); + } +} + +QPlatformMenu *QDBusMenuBar::menuForTag(quintptr tag) const +{ + QDBusPlatformMenuItem *menuItem = m_menuItems.value(tag); + if (menuItem) + return const_cast<QPlatformMenu *>(menuItem->menu()); + return nullptr; +} + +QPlatformMenu *QDBusMenuBar::createMenu() const +{ + return new QDBusPlatformMenu; +} + +void QDBusMenuBar::registerMenuBar() +{ + static uint menuBarId = 0; + + QDBusConnection connection = QDBusConnection::sessionBus(); + m_objectPath = QStringLiteral("/MenuBar/%1").arg(++menuBarId); + if (!connection.registerObject(m_objectPath, m_menu)) + return; + + QDBusMenuRegistrarInterface registrar(REGISTRAR_SERVICE, REGISTRAR_PATH, connection, this); + QDBusPendingReply<> r = registrar.RegisterWindow(m_windowId, 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); + } +} + +void QDBusMenuBar::unregisterMenuBar() +{ + QDBusConnection connection = QDBusConnection::sessionBus(); + + if (m_windowId) { + QDBusMenuRegistrarInterface registrar(REGISTRAR_SERVICE, REGISTRAR_PATH, connection, this); + QDBusPendingReply<> r = registrar.UnregisterWindow(m_windowId); + r.waitForFinished(); + if (r.isError()) + qWarning("Failed to unregister window menu, reason: %s (\"%s\")", + qUtf8Printable(r.error().name()), qUtf8Printable(r.error().message())); + } + + 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 new file mode 100644 index 0000000000..364e7da4b6 --- /dev/null +++ b/src/gui/platform/unix/dbusmenu/qdbusmenubar_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Dmitry Shachnev <mitya57@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDBUSMENUBAR_P_H +#define QDBUSMENUBAR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qdbusplatformmenu_p.h> +#include <private/qdbusmenuadaptor_p.h> +#include <QtCore/QHash> +#include <QtCore/QString> +#include <QtGui/QWindow> + +QT_BEGIN_NAMESPACE + +class QDBusMenuBar : public QPlatformMenuBar +{ + Q_OBJECT + +public: + QDBusMenuBar(); + virtual ~QDBusMenuBar(); + + void insertMenu(QPlatformMenu *menu, QPlatformMenu *before) override; + void removeMenu(QPlatformMenu *menu) override; + void syncMenu(QPlatformMenu *menu) override; + void handleReparent(QWindow *newParentWindow) override; + QPlatformMenu *menuForTag(quintptr tag) const override; + QPlatformMenu *createMenu() const override; + +private: + QDBusPlatformMenu *m_menu; + QDBusMenuAdaptor *m_menuAdaptor; + QHash<quintptr, QDBusPlatformMenuItem *> m_menuItems; + uint m_windowId; + QString m_objectPath; + + QDBusPlatformMenuItem *menuItemForMenu(QPlatformMenu *menu); + static void updateMenuItem(QDBusPlatformMenuItem *item, QPlatformMenu *menu); + void registerMenuBar(); + void unregisterMenuBar(); +}; + +QT_END_NAMESPACE + +#endif // QDBUSMENUBAR_P_H diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenuconnection.cpp b/src/gui/platform/unix/dbusmenu/qdbusmenuconnection.cpp new file mode 100644 index 0000000000..429460f9e8 --- /dev/null +++ b/src/gui/platform/unix/dbusmenu/qdbusmenuconnection.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/qtgui-config.h> + +#ifndef QT_NO_SYSTEMTRAYICON +#include "../dbustray/qdbustrayicon_p.h" +#endif +#include "qdbusmenuconnection_p.h" +#include "qdbusmenuadaptor_p.h" +#include "qdbusplatformmenu_p.h" + +#include <QtDBus/QDBusMessage> +#include <QtDBus/QDBusServiceWatcher> +#include <QtDBus/QDBusConnectionInterface> +#include <qdebug.h> +#include <qcoreapplication.h> + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(qLcMenu) + +const QString StatusNotifierWatcherService = QLatin1String("org.kde.StatusNotifierWatcher"); +const QString StatusNotifierWatcherPath = QLatin1String("/StatusNotifierWatcher"); +const QString StatusNotifierItemPath = QLatin1String("/StatusNotifierItem"); +const QString MenuBarPath = QLatin1String("/MenuBar"); + +/*! + \class QDBusMenuConnection + \internal + A D-Bus connection which is used for both menu and tray icon services. + Connects to the session bus and registers with the respective watcher services. +*/ +QDBusMenuConnection::QDBusMenuConnection(QObject *parent, const QString &serviceName) + : QObject(parent) + , m_connection(serviceName.isNull() ? QDBusConnection::sessionBus() + : QDBusConnection::connectToBus(QDBusConnection::SessionBus, serviceName)) + , m_dbusWatcher(new QDBusServiceWatcher(StatusNotifierWatcherService, m_connection, QDBusServiceWatcher::WatchForRegistration, this)) + , m_statusNotifierHostRegistered(false) +{ +#ifndef QT_NO_SYSTEMTRAYICON + QDBusInterface systrayHost(StatusNotifierWatcherService, StatusNotifierWatcherPath, StatusNotifierWatcherService, m_connection); + if (systrayHost.isValid() && systrayHost.property("IsStatusNotifierHostRegistered").toBool()) + m_statusNotifierHostRegistered = true; + else + qCDebug(qLcMenu) << "StatusNotifierHost is not registered"; +#endif +} + +void QDBusMenuConnection::dbusError(const QDBusError &error) +{ + qWarning() << "QDBusTrayIcon encountered a D-Bus error:" << error; +} + +#ifndef QT_NO_SYSTEMTRAYICON +bool QDBusMenuConnection::registerTrayIconMenu(QDBusTrayIcon *item) +{ + bool success = connection().registerObject(MenuBarPath, item->menu()); + if (!success) // success == false is normal, because the object may be already registered + qCDebug(qLcMenu) << "failed to register" << item->instanceId() << MenuBarPath; + return success; +} + +void QDBusMenuConnection::unregisterTrayIconMenu(QDBusTrayIcon *item) +{ + if (item->menu()) + connection().unregisterObject(MenuBarPath); +} + +bool QDBusMenuConnection::registerTrayIcon(QDBusTrayIcon *item) +{ + bool success = connection().registerService(item->instanceId()); + if (!success) { + qWarning() << "failed to register service" << item->instanceId(); + return false; + } + + success = connection().registerObject(StatusNotifierItemPath, item); + if (!success) { + unregisterTrayIcon(item); + qWarning() << "failed to register" << item->instanceId() << StatusNotifierItemPath; + return false; + } + + if (item->menu()) + registerTrayIconMenu(item); + + return registerTrayIconWithWatcher(item); +} + +bool QDBusMenuConnection::registerTrayIconWithWatcher(QDBusTrayIcon *item) +{ + QDBusMessage registerMethod = QDBusMessage::createMethodCall( + StatusNotifierWatcherService, StatusNotifierWatcherPath, StatusNotifierWatcherService, + QLatin1String("RegisterStatusNotifierItem")); + registerMethod.setArguments(QVariantList() << item->instanceId()); + return m_connection.callWithCallback(registerMethod, this, SIGNAL(trayIconRegistered()), SLOT(dbusError(QDBusError))); +} + +bool QDBusMenuConnection::unregisterTrayIcon(QDBusTrayIcon *item) +{ + unregisterTrayIconMenu(item); + connection().unregisterObject(StatusNotifierItemPath); + bool success = connection().unregisterService(item->instanceId()); + if (!success) + qWarning() << "failed to unregister service" << item->instanceId(); + return success; +} +#endif // QT_NO_SYSTEMTRAYICON + +QT_END_NAMESPACE diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h b/src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h new file mode 100644 index 0000000000..bbdaad1e89 --- /dev/null +++ b/src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DBUSCONNECTION_H +#define DBUSCONNECTION_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QString> +#include <QtDBus/QDBusConnection> +#include <QtDBus/QDBusVariant> + +#include <QtGui/qtgui-config.h> +Q_MOC_INCLUDE(<QtDBus/QDBusError>) + +QT_BEGIN_NAMESPACE + +class QDBusServiceWatcher; +#ifndef QT_NO_SYSTEMTRAYICON +class QDBusTrayIcon; +#endif // QT_NO_SYSTEMTRAYICON + +class QDBusMenuConnection : public QObject +{ + Q_OBJECT + +public: + QDBusMenuConnection(QObject *parent = nullptr, const QString &serviceName = QString()); + QDBusConnection connection() const { return m_connection; } + QDBusServiceWatcher *dbusWatcher() const { return m_dbusWatcher; } + bool isStatusNotifierHostRegistered() const { return m_statusNotifierHostRegistered; } +#ifndef QT_NO_SYSTEMTRAYICON + bool registerTrayIconMenu(QDBusTrayIcon *item); + void unregisterTrayIconMenu(QDBusTrayIcon *item); + bool registerTrayIcon(QDBusTrayIcon *item); + bool registerTrayIconWithWatcher(QDBusTrayIcon *item); + bool unregisterTrayIcon(QDBusTrayIcon *item); +#endif // QT_NO_SYSTEMTRAYICON + +Q_SIGNALS: +#ifndef QT_NO_SYSTEMTRAYICON + void trayIconRegistered(); +#endif // QT_NO_SYSTEMTRAYICON + +private Q_SLOTS: + void dbusError(const QDBusError &error); + +private: + QDBusConnection m_connection; + QDBusServiceWatcher *m_dbusWatcher; + bool m_statusNotifierHostRegistered; +}; + +QT_END_NAMESPACE + +#endif // DBUSCONNECTION_H diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenuregistrarproxy.cpp b/src/gui/platform/unix/dbusmenu/qdbusmenuregistrarproxy.cpp new file mode 100644 index 0000000000..c59b5a675e --- /dev/null +++ b/src/gui/platform/unix/dbusmenu/qdbusmenuregistrarproxy.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Dmitry Shachnev <mitya57@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + * This file was originally created by qdbusxml2cpp version 0.8 + * Command line was: qdbusxml2cpp -p qdbusmenuregistrarproxy ../../3rdparty/dbus-ifaces/com.canonical.AppMenu.Registrar.xml + * + * However it is maintained manually. + */ + +#include "qdbusmenuregistrarproxy_p.h" + +QT_BEGIN_NAMESPACE + +/* + * Implementation of interface class QDBusMenuRegistrarInterface + */ + +QDBusMenuRegistrarInterface::QDBusMenuRegistrarInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +QDBusMenuRegistrarInterface::~QDBusMenuRegistrarInterface() +{ +} + +QT_END_NAMESPACE diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenuregistrarproxy_p.h b/src/gui/platform/unix/dbusmenu/qdbusmenuregistrarproxy_p.h new file mode 100644 index 0000000000..cffc080f87 --- /dev/null +++ b/src/gui/platform/unix/dbusmenu/qdbusmenuregistrarproxy_p.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Dmitry Shachnev <mitya57@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + * This file was originally created by qdbusxml2cpp version 0.8 + * Command line was: qdbusxml2cpp -p qdbusmenuregistrarproxy ../../3rdparty/dbus-ifaces/com.canonical.AppMenu.Registrar.xml + * + * However it is maintained manually. + */ + +#ifndef QDBUSMENUREGISTRARPROXY_P_H +#define QDBUSMENUREGISTRARPROXY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QObject> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QVariant> +#include <QtDBus/QDBusAbstractInterface> +#include <QtDBus/QDBusConnection> +#include <QtDBus/QDBusReply> + +QT_BEGIN_NAMESPACE + +/* + * Proxy class for interface com.canonical.AppMenu.Registrar + */ +class QDBusMenuRegistrarInterface : public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { + return "com.canonical.AppMenu.Registrar"; + } + +public: + explicit QDBusMenuRegistrarInterface(const QString &service, + const QString &path, + const QDBusConnection &connection, + QObject *parent = nullptr); + + ~QDBusMenuRegistrarInterface(); + +public Q_SLOTS: // METHODS + QDBusPendingReply<QString, QDBusObjectPath> GetMenuForWindow(uint windowId) + { + return asyncCall(QStringLiteral("GetMenuForWindow"), windowId); + } + QDBusReply<QString> GetMenuForWindow(uint windowId, QDBusObjectPath &menuObjectPath) + { + QDBusMessage reply = call(QDBus::Block, QStringLiteral("GetMenuForWindow"), windowId); + QList<QVariant> arguments = reply.arguments(); + if (reply.type() == QDBusMessage::ReplyMessage && arguments.count() == 2) + menuObjectPath = qdbus_cast<QDBusObjectPath>(arguments.at(1)); + return reply; + } + + QDBusPendingReply<> RegisterWindow(uint windowId, const QDBusObjectPath &menuObjectPath) + { + return asyncCall(QStringLiteral("RegisterWindow"), windowId, menuObjectPath); + } + + QDBusPendingReply<> UnregisterWindow(uint windowId) + { + return asyncCall(QStringLiteral("UnregisterWindow"), windowId); + } +}; + +QT_END_NAMESPACE + +#endif // QDBUSMENUREGISTRARPROXY_P_H diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenutypes.cpp b/src/gui/platform/unix/dbusmenu/qdbusmenutypes.cpp new file mode 100644 index 0000000000..6fadea5d28 --- /dev/null +++ b/src/gui/platform/unix/dbusmenu/qdbusmenutypes.cpp @@ -0,0 +1,303 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdbusmenutypes_p.h" + +#include <QDBusConnection> +#include <QDBusMetaType> +#include <QImage> +#include <QIcon> +#include <QImage> +#include <QPixmap> +#include <QDebug> +#include <QtEndian> +#include <QBuffer> +#if QT_CONFIG(shortcut) +# include <private/qkeysequence_p.h> +#endif +#include <qpa/qplatformmenu.h> +#include "qdbusplatformmenu_p.h" + +QT_BEGIN_NAMESPACE + +const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuItem &item) +{ + arg.beginStructure(); + arg << item.m_id << item.m_properties; + arg.endStructure(); + return arg; +} + +const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuItem &item) +{ + arg.beginStructure(); + arg >> item.m_id >> item.m_properties; + arg.endStructure(); + return arg; +} + +const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuItemKeys &keys) +{ + arg.beginStructure(); + arg << keys.id << keys.properties; + arg.endStructure(); + return arg; +} + +const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuItemKeys &keys) +{ + arg.beginStructure(); + arg >> keys.id >> keys.properties; + arg.endStructure(); + return arg; +} + +uint QDBusMenuLayoutItem::populate(int id, int depth, const QStringList &propertyNames, const QDBusPlatformMenu *topLevelMenu) +{ + qCDebug(qLcMenu) << id << "depth" << depth << propertyNames; + m_id = id; + if (id == 0) { + m_properties.insert(QLatin1String("children-display"), QLatin1String("submenu")); + if (topLevelMenu) + populate(topLevelMenu, depth, propertyNames); + return 1; // revision + } + + QDBusPlatformMenuItem *item = QDBusPlatformMenuItem::byId(id); + if (item) { + const QDBusPlatformMenu *menu = static_cast<const QDBusPlatformMenu *>(item->menu()); + + if (menu) { + if (depth != 0) + populate(menu, depth, propertyNames); + return menu->revision(); + } + } + + return 1; // revision +} + +void QDBusMenuLayoutItem::populate(const QDBusPlatformMenu *menu, int depth, const QStringList &propertyNames) +{ + const auto items = menu->items(); + for (QDBusPlatformMenuItem *item : items) { + QDBusMenuLayoutItem child; + child.populate(item, depth - 1, propertyNames); + m_children << child; + } +} + +void QDBusMenuLayoutItem::populate(const QDBusPlatformMenuItem *item, int depth, const QStringList &propertyNames) +{ + m_id = item->dbusID(); + QDBusMenuItem proxy(item); + m_properties = proxy.m_properties; + + const QDBusPlatformMenu *menu = static_cast<const QDBusPlatformMenu *>(item->menu()); + if (depth != 0 && menu) + populate(menu, depth, propertyNames); +} + +const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuLayoutItem &item) +{ + arg.beginStructure(); + arg << item.m_id << item.m_properties; + arg.beginArray(qMetaTypeId<QDBusVariant>()); + for (const QDBusMenuLayoutItem &child : item.m_children) + arg << QDBusVariant(QVariant::fromValue<QDBusMenuLayoutItem>(child)); + arg.endArray(); + arg.endStructure(); + return arg; +} + +const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuLayoutItem &item) +{ + arg.beginStructure(); + arg >> item.m_id >> item.m_properties; + arg.beginArray(); + while (!arg.atEnd()) { + QDBusVariant dbusVariant; + arg >> dbusVariant; + QDBusArgument childArgument = qvariant_cast<QDBusArgument>(dbusVariant.variant()); + + QDBusMenuLayoutItem child; + childArgument >> child; + item.m_children.append(child); + } + arg.endArray(); + arg.endStructure(); + return arg; +} + +void QDBusMenuItem::registerDBusTypes() +{ + qDBusRegisterMetaType<QDBusMenuItem>(); + qDBusRegisterMetaType<QDBusMenuItemList>(); + qDBusRegisterMetaType<QDBusMenuItemKeys>(); + qDBusRegisterMetaType<QDBusMenuItemKeysList>(); + qDBusRegisterMetaType<QDBusMenuLayoutItem>(); + qDBusRegisterMetaType<QDBusMenuLayoutItemList>(); + qDBusRegisterMetaType<QDBusMenuEvent>(); + qDBusRegisterMetaType<QDBusMenuEventList>(); + qDBusRegisterMetaType<QDBusMenuShortcut>(); +} + +QDBusMenuItem::QDBusMenuItem(const QDBusPlatformMenuItem *item) + : m_id(item->dbusID()) +{ + if (item->isSeparator()) { + m_properties.insert(QLatin1String("type"), QLatin1String("separator")); + } else { + m_properties.insert(QLatin1String("label"), convertMnemonic(item->text())); + if (item->menu()) + m_properties.insert(QLatin1String("children-display"), QLatin1String("submenu")); + m_properties.insert(QLatin1String("enabled"), item->isEnabled()); + if (item->isCheckable()) { + QString toggleType = item->hasExclusiveGroup() ? QLatin1String("radio") : QLatin1String("checkmark"); + m_properties.insert(QLatin1String("toggle-type"), toggleType); + m_properties.insert(QLatin1String("toggle-state"), item->isChecked() ? 1 : 0); + } +#ifndef QT_NO_SHORTCUT + const QKeySequence &scut = item->shortcut(); + if (!scut.isEmpty()) { + QDBusMenuShortcut shortcut = convertKeySequence(scut); + m_properties.insert(QLatin1String("shortcut"), QVariant::fromValue(shortcut)); + } +#endif + const QIcon &icon = item->icon(); + if (!icon.name().isEmpty()) { + m_properties.insert(QLatin1String("icon-name"), icon.name()); + } else if (!icon.isNull()) { + QBuffer buf; + icon.pixmap(16).save(&buf, "PNG"); + m_properties.insert(QLatin1String("icon-data"), buf.data()); + } + } + m_properties.insert(QLatin1String("visible"), item->isVisible()); +} + +QDBusMenuItemList QDBusMenuItem::items(const QList<int> &ids, const QStringList &propertyNames) +{ + Q_UNUSED(propertyNames) + QDBusMenuItemList ret; + const QList<const QDBusPlatformMenuItem *> items = QDBusPlatformMenuItem::byIds(ids); + ret.reserve(items.size()); + for (const QDBusPlatformMenuItem *item : items) + ret << QDBusMenuItem(item); + return ret; +} + +QString QDBusMenuItem::convertMnemonic(const QString &label) +{ + // convert only the first occurrence of ampersand which is not at the end + // dbusmenu uses underscore instead of ampersand + int idx = label.indexOf(QLatin1Char('&')); + if (idx < 0 || idx == label.length() - 1) + return label; + QString ret(label); + ret[idx] = QLatin1Char('_'); + return ret; +} + +#ifndef QT_NO_SHORTCUT +QDBusMenuShortcut QDBusMenuItem::convertKeySequence(const QKeySequence &sequence) +{ + QDBusMenuShortcut shortcut; + for (int i = 0; i < sequence.count(); ++i) { + QStringList tokens; + int key = sequence[i]; + if (key & Qt::MetaModifier) + tokens << QStringLiteral("Super"); + if (key & Qt::ControlModifier) + tokens << QStringLiteral("Control"); + if (key & Qt::AltModifier) + tokens << QStringLiteral("Alt"); + if (key & Qt::ShiftModifier) + tokens << QStringLiteral("Shift"); + if (key & Qt::KeypadModifier) + tokens << QStringLiteral("Num"); + + QString keyName = QKeySequencePrivate::keyName(key, QKeySequence::PortableText); + if (keyName == QLatin1String("+")) + tokens << QStringLiteral("plus"); + else if (keyName == QLatin1String("-")) + tokens << QStringLiteral("minus"); + else + tokens << keyName; + shortcut << tokens; + } + return shortcut; +} +#endif + +const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuEvent &ev) +{ + arg.beginStructure(); + arg << ev.m_id << ev.m_eventId << ev.m_data << ev.m_timestamp; + arg.endStructure(); + return arg; +} + +const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuEvent &ev) +{ + arg.beginStructure(); + arg >> ev.m_id >> ev.m_eventId >> ev.m_data >> ev.m_timestamp; + arg.endStructure(); + return arg; +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const QDBusMenuItem &item) +{ + QDebugStateSaver saver(d); + d.nospace(); + d << "QDBusMenuItem(id=" << item.m_id << ", properties=" << item.m_properties << ')'; + return d; +} + +QDebug operator<<(QDebug d, const QDBusMenuLayoutItem &item) +{ + QDebugStateSaver saver(d); + d.nospace(); + d << "QDBusMenuLayoutItem(id=" << item.m_id << ", properties=" << item.m_properties << ", " << item.m_children.count() << " children)"; + return d; +} +#endif + +QT_END_NAMESPACE diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenutypes_p.h b/src/gui/platform/unix/dbusmenu/qdbusmenutypes_p.h new file mode 100644 index 0000000000..fd6727d3be --- /dev/null +++ b/src/gui/platform/unix/dbusmenu/qdbusmenutypes_p.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDBUSMENUTYPES_H +#define QDBUSMENUTYPES_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QObject> +#include <QString> +#include <QDBusArgument> +#include <QDBusConnection> +#include <QDBusObjectPath> +#include <QPixmap> + +QT_BEGIN_NAMESPACE + +class QDBusPlatformMenu; +class QDBusPlatformMenuItem; +class QDBusMenuItem; +typedef QVector<QDBusMenuItem> QDBusMenuItemList; +typedef QVector<QStringList> QDBusMenuShortcut; + +class QDBusMenuItem +{ +public: + QDBusMenuItem() { } + QDBusMenuItem(const QDBusPlatformMenuItem *item); + + static QDBusMenuItemList items(const QList<int> &ids, const QStringList &propertyNames); + static QString convertMnemonic(const QString &label); +#ifndef QT_NO_SHORTCUT + static QDBusMenuShortcut convertKeySequence(const QKeySequence &sequence); +#endif + static void registerDBusTypes(); + + int m_id; + QVariantMap m_properties; +}; +Q_DECLARE_TYPEINFO(QDBusMenuItem, Q_MOVABLE_TYPE); + +const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuItem &item); +const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuItem &item); + +class QDBusMenuItemKeys +{ +public: + + int id; + QStringList properties; +}; +Q_DECLARE_TYPEINFO(QDBusMenuItemKeys, Q_MOVABLE_TYPE); + +const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuItemKeys &keys); +const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuItemKeys &keys); + +typedef QVector<QDBusMenuItemKeys> QDBusMenuItemKeysList; + +class QDBusMenuLayoutItem +{ +public: + uint populate(int id, int depth, const QStringList &propertyNames, const QDBusPlatformMenu *topLevelMenu); + void populate(const QDBusPlatformMenu *menu, int depth, const QStringList &propertyNames); + void populate(const QDBusPlatformMenuItem *item, int depth, const QStringList &propertyNames); + + int m_id; + QVariantMap m_properties; + QVector<QDBusMenuLayoutItem> m_children; +}; +Q_DECLARE_TYPEINFO(QDBusMenuLayoutItem, Q_MOVABLE_TYPE); + +const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuLayoutItem &); +const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuLayoutItem &item); + +typedef QVector<QDBusMenuLayoutItem> QDBusMenuLayoutItemList; + +class QDBusMenuEvent +{ +public: + int m_id; + QString m_eventId; + QDBusVariant m_data; + uint m_timestamp; +}; +Q_DECLARE_TYPEINFO(QDBusMenuEvent, Q_MOVABLE_TYPE); // QDBusVariant is movable, even though it cannot + // be marked as such until Qt 6. + +const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuEvent &ev); +const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuEvent &ev); + +typedef QVector<QDBusMenuEvent> QDBusMenuEventList; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const QDBusMenuItem &item); +QDebug operator<<(QDebug d, const QDBusMenuLayoutItem &item); +#endif + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QDBusMenuItem) +Q_DECLARE_METATYPE(QDBusMenuItemList) +Q_DECLARE_METATYPE(QDBusMenuItemKeys) +Q_DECLARE_METATYPE(QDBusMenuItemKeysList) +Q_DECLARE_METATYPE(QDBusMenuLayoutItem) +Q_DECLARE_METATYPE(QDBusMenuLayoutItemList) +Q_DECLARE_METATYPE(QDBusMenuEvent) +Q_DECLARE_METATYPE(QDBusMenuEventList) +Q_DECLARE_METATYPE(QDBusMenuShortcut) + +#endif diff --git a/src/gui/platform/unix/dbusmenu/qdbusplatformmenu.cpp b/src/gui/platform/unix/dbusmenu/qdbusplatformmenu.cpp new file mode 100644 index 0000000000..fc1b37f2f2 --- /dev/null +++ b/src/gui/platform/unix/dbusmenu/qdbusplatformmenu.cpp @@ -0,0 +1,308 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdbusplatformmenu_p.h" + +#include <QDateTime> +#include <QDebug> +#include <QWindow> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(qLcMenu, "qt.qpa.menu") + +static int nextDBusID = 1; +QHash<int, QDBusPlatformMenuItem *> menuItemsByID; + +QDBusPlatformMenuItem::QDBusPlatformMenuItem() + : m_subMenu(nullptr) + , m_role(NoRole) + , m_isEnabled(true) + , m_isVisible(true) + , m_isSeparator(false) + , m_isCheckable(false) + , m_isChecked(false) + , m_hasExclusiveGroup(false) + , m_dbusID(nextDBusID++) +{ + menuItemsByID.insert(m_dbusID, this); +} + +QDBusPlatformMenuItem::~QDBusPlatformMenuItem() +{ + menuItemsByID.remove(m_dbusID); + if (m_subMenu) + static_cast<QDBusPlatformMenu *>(m_subMenu)->setContainingMenuItem(nullptr); +} + +void QDBusPlatformMenuItem::setText(const QString &text) +{ + qCDebug(qLcMenu) << m_dbusID << text; + m_text = text; +} + +void QDBusPlatformMenuItem::setIcon(const QIcon &icon) +{ + m_icon = icon; +} + +/*! + Set a submenu under this menu item. +*/ +void QDBusPlatformMenuItem::setMenu(QPlatformMenu *menu) +{ + if (m_subMenu) + static_cast<QDBusPlatformMenu *>(m_subMenu)->setContainingMenuItem(nullptr); + m_subMenu = menu; + if (menu) + static_cast<QDBusPlatformMenu *>(menu)->setContainingMenuItem(this); +} + +void QDBusPlatformMenuItem::setEnabled(bool enabled) +{ + m_isEnabled = enabled; +} + +void QDBusPlatformMenuItem::setVisible(bool isVisible) +{ + m_isVisible = isVisible; +} + +void QDBusPlatformMenuItem::setIsSeparator(bool isSeparator) +{ + m_isSeparator = isSeparator; +} + +void QDBusPlatformMenuItem::setRole(QPlatformMenuItem::MenuRole role) +{ + m_role = role; +} + +void QDBusPlatformMenuItem::setCheckable(bool checkable) +{ + m_isCheckable = checkable; +} + +void QDBusPlatformMenuItem::setChecked(bool isChecked) +{ + m_isChecked = isChecked; +} + +void QDBusPlatformMenuItem::setHasExclusiveGroup(bool hasExclusiveGroup) +{ + m_hasExclusiveGroup = hasExclusiveGroup; +} + +#ifndef QT_NO_SHORTCUT +void QDBusPlatformMenuItem::setShortcut(const QKeySequence &shortcut) +{ + m_shortcut = shortcut; +} +#endif + +void QDBusPlatformMenuItem::trigger() +{ + emit activated(); +} + +QDBusPlatformMenuItem *QDBusPlatformMenuItem::byId(int id) +{ + // We need to check contains because otherwise QHash would insert + // a default-constructed nullptr value into menuItemsByID + if (menuItemsByID.contains(id)) + return menuItemsByID[id]; + return nullptr; +} + +QList<const QDBusPlatformMenuItem *> QDBusPlatformMenuItem::byIds(const QList<int> &ids) +{ + QList<const QDBusPlatformMenuItem *> ret; + for (int id : ids) { + if (menuItemsByID.contains(id)) + ret << menuItemsByID[id]; + } + return ret; +} + + +QDBusPlatformMenu::QDBusPlatformMenu() + : m_isEnabled(true) + , m_isVisible(true) + , m_revision(1) + , m_containingMenuItem(nullptr) +{ +} + +QDBusPlatformMenu::~QDBusPlatformMenu() +{ + if (m_containingMenuItem) + m_containingMenuItem->setMenu(nullptr); +} + +void QDBusPlatformMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) +{ + QDBusPlatformMenuItem *item = static_cast<QDBusPlatformMenuItem *>(menuItem); + QDBusPlatformMenuItem *beforeItem = static_cast<QDBusPlatformMenuItem *>(before); + int idx = m_items.indexOf(beforeItem); + qCDebug(qLcMenu) << item->dbusID() << item->text(); + if (idx < 0) + m_items.append(item); + else + m_items.insert(idx, item); + m_itemsByTag.insert(item->tag(), item); + if (item->menu()) + syncSubMenu(static_cast<const QDBusPlatformMenu *>(item->menu())); + emitUpdated(); +} + +void QDBusPlatformMenu::removeMenuItem(QPlatformMenuItem *menuItem) +{ + QDBusPlatformMenuItem *item = static_cast<QDBusPlatformMenuItem *>(menuItem); + m_items.removeAll(item); + m_itemsByTag.remove(menuItem->tag()); + if (item->menu()) { + // disconnect from the signals we connected to in syncSubMenu() + const QDBusPlatformMenu *menu = static_cast<const QDBusPlatformMenu *>(item->menu()); + disconnect(menu, &QDBusPlatformMenu::propertiesUpdated, + this, &QDBusPlatformMenu::propertiesUpdated); + disconnect(menu, &QDBusPlatformMenu::updated, + this, &QDBusPlatformMenu::updated); + disconnect(menu, &QDBusPlatformMenu::popupRequested, + this, &QDBusPlatformMenu::popupRequested); + } + emitUpdated(); +} + +void QDBusPlatformMenu::syncSubMenu(const QDBusPlatformMenu *menu) +{ + // The adaptor is only connected to the propertiesUpdated signal of the top-level + // menu, so the submenus should transfer their signals to their parents. + connect(menu, &QDBusPlatformMenu::propertiesUpdated, + this, &QDBusPlatformMenu::propertiesUpdated, Qt::UniqueConnection); + connect(menu, &QDBusPlatformMenu::updated, + this, &QDBusPlatformMenu::updated, Qt::UniqueConnection); + connect(menu, &QDBusPlatformMenu::popupRequested, + this, &QDBusPlatformMenu::popupRequested, Qt::UniqueConnection); +} + +void QDBusPlatformMenu::syncMenuItem(QPlatformMenuItem *menuItem) +{ + QDBusPlatformMenuItem *item = static_cast<QDBusPlatformMenuItem *>(menuItem); + // if a submenu was added to this item, we need to connect to its signals + if (item->menu()) + syncSubMenu(static_cast<const QDBusPlatformMenu *>(item->menu())); + // TODO keep around copies of the QDBusMenuLayoutItems so they can be updated? + // or eliminate them by putting dbus streaming operators in this class instead? + // or somehow tell the dbusmenu client that something has changed, so it will ask for properties again + QDBusMenuItemList updated; + QDBusMenuItemKeysList removed; + updated << QDBusMenuItem(item); + qCDebug(qLcMenu) << updated; + emit propertiesUpdated(updated, removed); +} + +void QDBusPlatformMenu::emitUpdated() +{ + if (m_containingMenuItem) + emit updated(++m_revision, m_containingMenuItem->dbusID()); + else + emit updated(++m_revision, 0); +} + +void QDBusPlatformMenu::setText(const QString &text) +{ + m_text = text; +} + +void QDBusPlatformMenu::setIcon(const QIcon &icon) +{ + m_icon = icon; +} + +void QDBusPlatformMenu::setEnabled(bool enabled) +{ + m_isEnabled = enabled; +} + +void QDBusPlatformMenu::setVisible(bool isVisible) +{ + m_isVisible = isVisible; +} + +void QDBusPlatformMenu::setContainingMenuItem(QDBusPlatformMenuItem *item) +{ + m_containingMenuItem = item; +} + +void QDBusPlatformMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item) +{ + Q_UNUSED(parentWindow); + Q_UNUSED(targetRect); + Q_UNUSED(item); + setVisible(true); + emit popupRequested(m_containingMenuItem->dbusID(), QDateTime::currentMSecsSinceEpoch()); +} + +QPlatformMenuItem *QDBusPlatformMenu::menuItemAt(int position) const +{ + return m_items.value(position); +} + +QPlatformMenuItem *QDBusPlatformMenu::menuItemForTag(quintptr tag) const +{ + return m_itemsByTag[tag]; +} + +const QList<QDBusPlatformMenuItem *> QDBusPlatformMenu::items() const +{ + return m_items; +} + +QPlatformMenuItem *QDBusPlatformMenu::createMenuItem() const +{ + QDBusPlatformMenuItem *ret = new QDBusPlatformMenuItem(); + return ret; +} + +QPlatformMenu *QDBusPlatformMenu::createSubMenu() const +{ + return new QDBusPlatformMenu; +} + +QT_END_NAMESPACE diff --git a/src/gui/platform/unix/dbusmenu/qdbusplatformmenu_p.h b/src/gui/platform/unix/dbusmenu/qdbusplatformmenu_p.h new file mode 100644 index 0000000000..aa0f303416 --- /dev/null +++ b/src/gui/platform/unix/dbusmenu/qdbusplatformmenu_p.h @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDBUSPLATFORMMENU_H +#define QDBUSPLATFORMMENU_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// +// +// W A R N I N G +// ------------- +// +// This file is part of the DBus menu support and is not meant to be used +// in applications. Usage of this API may make your code +// source and binary incompatible with future versions of Qt. +// + +#include <qpa/qplatformmenu.h> +#include <QLoggingCategory> +#include "qdbusmenutypes_p.h" + +QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(qLcMenu) + +class QDBusPlatformMenu; + +class QDBusPlatformMenuItem : public QPlatformMenuItem +{ + Q_OBJECT + +public: + QDBusPlatformMenuItem(); + ~QDBusPlatformMenuItem(); + + const QString text() const { return m_text; } + void setText(const QString &text) override; + QIcon icon() const { return m_icon; } + void setIcon(const QIcon &icon) override; + const QPlatformMenu *menu() const { return m_subMenu; } + void setMenu(QPlatformMenu *menu) override; + bool isEnabled() const { return m_isEnabled; } + void setEnabled(bool enabled) override; + bool isVisible() const { return m_isVisible; } + void setVisible(bool isVisible) override; + bool isSeparator() const { return m_isSeparator; } + void setIsSeparator(bool isSeparator) override; + void setFont(const QFont &font) override { Q_UNUSED(font); } + void setRole(MenuRole role) override; + bool isCheckable() const { return m_isCheckable; } + void setCheckable(bool checkable) override; + bool isChecked() const { return m_isChecked; } + void setChecked(bool isChecked) override; + bool hasExclusiveGroup() const { return m_hasExclusiveGroup; } + void setHasExclusiveGroup(bool hasExclusiveGroup) override; +#if QT_CONFIG(shortcut) + QKeySequence shortcut() const { return m_shortcut; } + void setShortcut(const QKeySequence& shortcut) override; +#endif + void setIconSize(int size) override { Q_UNUSED(size); } + void setNativeContents(WId item) override { Q_UNUSED(item); } + + int dbusID() const { return m_dbusID; } + + void trigger(); + + static QDBusPlatformMenuItem *byId(int id); + static QList<const QDBusPlatformMenuItem *> byIds(const QList<int> &ids); + +private: + QString m_text; + QIcon m_icon; + QPlatformMenu *m_subMenu; + MenuRole m_role : 4; + bool m_isEnabled : 1; + bool m_isVisible : 1; + bool m_isSeparator : 1; + bool m_isCheckable : 1; + bool m_isChecked : 1; + bool m_hasExclusiveGroup : 1; + short /*unused*/ : 6; + short m_dbusID : 16; +#if QT_CONFIG(shortcut) + QKeySequence m_shortcut; +#endif +}; + +class QDBusPlatformMenu : public QPlatformMenu +{ + Q_OBJECT + +public: + QDBusPlatformMenu(); + ~QDBusPlatformMenu(); + void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) override; + void removeMenuItem(QPlatformMenuItem *menuItem) override; + void syncSubMenu(const QDBusPlatformMenu *menu); + void syncMenuItem(QPlatformMenuItem *menuItem) override; + void syncSeparatorsCollapsible(bool enable) override { Q_UNUSED(enable); } + + const QString text() const { return m_text; } + void setText(const QString &text) override; + QIcon icon() const { return m_icon; } + void setIcon(const QIcon &icon) override; + bool isEnabled() const override { return m_isEnabled; } + void setEnabled(bool enabled) override; + bool isVisible() const { return m_isVisible; } + void setVisible(bool visible) override; + void setMinimumWidth(int width) override { Q_UNUSED(width); } + void setFont(const QFont &font) override { Q_UNUSED(font); } + void setMenuType(MenuType type) override { Q_UNUSED(type); } + void setContainingMenuItem(QDBusPlatformMenuItem *item); + + void showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item) override; + + void dismiss() override { } // Closes this and all its related menu popups + + QPlatformMenuItem *menuItemAt(int position) const override; + QPlatformMenuItem *menuItemForTag(quintptr tag) const override; + const QList<QDBusPlatformMenuItem *> items() const; + + QPlatformMenuItem *createMenuItem() const override; + QPlatformMenu *createSubMenu() const override; + + uint revision() const { return m_revision; } + + void emitUpdated(); + +signals: + void updated(uint revision, int dbusId); + void propertiesUpdated(QDBusMenuItemList updatedProps, QDBusMenuItemKeysList removedProps); + void popupRequested(int id, uint timestamp); + +private: + QString m_text; + QIcon m_icon; + bool m_isEnabled; + bool m_isVisible; + uint m_revision; + QHash<quintptr, QDBusPlatformMenuItem *> m_itemsByTag; + QList<QDBusPlatformMenuItem *> m_items; + QDBusPlatformMenuItem *m_containingMenuItem; +}; + +QT_END_NAMESPACE + +#endif + |