diff options
24 files changed, 2330 insertions, 23 deletions
diff --git a/src/3rdparty/dbus-ifaces/org.kde.StatusNotifierItem.xml b/src/3rdparty/dbus-ifaces/org.kde.StatusNotifierItem.xml new file mode 100644 index 0000000000..aeeb42fa87 --- /dev/null +++ b/src/3rdparty/dbus-ifaces/org.kde.StatusNotifierItem.xml @@ -0,0 +1,96 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node> + <interface name="org.kde.StatusNotifierItem"> + + <property name="Category" type="s" access="read"/> + <property name="Id" type="s" access="read"/> + <property name="Title" type="s" access="read"/> + <property name="Status" type="s" access="read"/> + <property name="WindowId" type="i" access="read"/> + + <!-- An additional path to add to the theme search path to find the icons specified above. --> + <property name="IconThemePath" type="s" access="read"/> + <property name="Menu" type="o" access="read"/> + <property name="ItemIsMenu" type="b" access="read"/> + + + <!-- main icon --> + <!-- names are preferred over pixmaps --> + <property name="IconName" type="s" access="read"/> + + <!--struct containing width, height and image data--> + <property name="IconPixmap" type="(iiay)" access="read"> + <annotation name="org.qtproject.QtDBus.QtTypeName" value="QXdgDBusImageVector"/> + </property> + + <property name="OverlayIconName" type="s" access="read"/> + + <property name="OverlayIconPixmap" type="(iiay)" access="read"> + <annotation name="org.qtproject.QtDBus.QtTypeName" value="QXdgDBusImageVector"/> + </property> + + + <!-- Requesting attention icon --> + <property name="AttentionIconName" type="s" access="read"/> + + <!--same definition as image--> + <property name="AttentionIconPixmap" type="(iiay)" access="read"> + <annotation name="org.qtproject.QtDBus.QtTypeName" value="QXdgDBusImageVector"/> + </property> + + <property name="AttentionMovieName" type="s" access="read"/> + + + + <!-- tooltip data --> + + <!--(iiay) is an image--> + <property name="ToolTip" type="(s(iiay)ss)" access="read"> + <annotation name="org.qtproject.QtDBus.QtTypeName" value="QXdgDBusToolTipStruct"/> + </property> + + + <!-- interaction: the systemtray wants the application to do something --> + <method name="ContextMenu"> + <!-- we're passing the coordinates of the icon, so the app knows where to put the popup window --> + <arg name="x" type="i" direction="in"/> + <arg name="y" type="i" direction="in"/> + </method> + + <method name="Activate"> + <arg name="x" type="i" direction="in"/> + <arg name="y" type="i" direction="in"/> + </method> + + <method name="SecondaryActivate"> + <arg name="x" type="i" direction="in"/> + <arg name="y" type="i" direction="in"/> + </method> + + <method name="Scroll"> + <arg name="delta" type="i" direction="in"/> + <arg name="orientation" type="s" direction="in"/> + </method> + + <!-- Signals: the client wants to change something in the status--> + <signal name="NewTitle"> + </signal> + + <signal name="NewIcon"> + </signal> + + <signal name="NewAttentionIcon"> + </signal> + + <signal name="NewOverlayIcon"> + </signal> + + <signal name="NewToolTip"> + </signal> + + <signal name="NewStatus"> + <arg name="status" type="s"/> + </signal> + + </interface> +</node> diff --git a/src/platformsupport/dbusmenu/dbusmenu.pri b/src/platformsupport/dbusmenu/dbusmenu.pri new file mode 100644 index 0000000000..9ca1f13897 --- /dev/null +++ b/src/platformsupport/dbusmenu/dbusmenu.pri @@ -0,0 +1,15 @@ +QT_FOR_PRIVATE += dbus + +INCLUDEPATH += $$PWD $$PWD/../../gui/kernel + +HEADERS += \ + $$PWD/qdbusmenuadaptor_p.h \ + $$PWD/qdbusmenutypes_p.h \ + $$PWD/qdbusmenuconnection_p.h \ + $$PWD/qdbusplatformmenu_p.h \ + +SOURCES += \ + $$PWD/qdbusmenuadaptor.cpp \ + $$PWD/qdbusmenutypes.cpp \ + $$PWD/qdbusmenuconnection.cpp \ + $$PWD/qdbusplatformmenu.cpp \ diff --git a/src/platformsupport/dbusmenu/qdbusmenuadaptor.cpp b/src/platformsupport/dbusmenu/qdbusmenuadaptor.cpp new file mode 100644 index 0000000000..07a75f8172 --- /dev/null +++ b/src/platformsupport/dbusmenu/qdbusmenuadaptor.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $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(QObject *parent) + : QDBusAbstractAdaptor(parent) +{ + 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; + return false; +} + +QList<int> QDBusMenuAdaptor::AboutToShowGroup(const QList<int> &ids, QList<int> &idErrors) +{ + qCDebug(qLcMenu) << ids; + Q_UNUSED(idErrors) + idErrors.clear(); + 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; + // Events occur on both menus and menuitems, but we only care if it's an item being clicked. + if (item && eventId == QLatin1String("clicked")) + item->trigger(); +} + +void QDBusMenuAdaptor::EventGroup(const QDBusMenuEventList &events) +{ + Q_FOREACH (const QDBusMenuEvent &ev, events) + Event(ev.m_id, ev.m_eventId, ev.m_data, ev.m_timestamp); +} + +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); + 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/platformsupport/dbusmenu/qdbusmenuadaptor_p.h b/src/platformsupport/dbusmenu/qdbusmenuadaptor_p.h new file mode 100644 index 0000000000..7a5f7b74eb --- /dev/null +++ b/src/platformsupport/dbusmenu/qdbusmenuadaptor_p.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtDBus module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $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 + +#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(QObject *parent); + 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); + void 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); +}; + +QT_END_NAMESPACE + +#endif // DBUSMENUADAPTOR_H diff --git a/src/platformsupport/dbusmenu/qdbusmenuconnection.cpp b/src/platformsupport/dbusmenu/qdbusmenuconnection.cpp new file mode 100644 index 0000000000..83ba6054fc --- /dev/null +++ b/src/platformsupport/dbusmenu/qdbusmenuconnection.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_NO_SYSTEMTRAYICON +#include "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) + : QObject(parent) + , m_connection(QDBusConnection::sessionBus()) + , m_dbusWatcher(new QDBusServiceWatcher(StatusNotifierWatcherService, m_connection, QDBusServiceWatcher::WatchForRegistration, this)) + , m_watcherRegistered(false) +{ +#ifndef QT_NO_SYSTEMTRAYICON + // Start monitoring if any known tray-related services are registered. + if (m_connection.interface()->isServiceRegistered(StatusNotifierWatcherService)) + m_watcherRegistered = true; + else + qCDebug(qLcMenu) << "failed to find service" << StatusNotifierWatcherService; +#endif +} + +void QDBusMenuConnection::dbusError(const QDBusError &error) +{ + qWarning() << "QDBusTrayIcon encountered a D-Bus error:" << error; +} + +#ifndef QT_NO_SYSTEMTRAYICON +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()) { + success = connection().registerObject(MenuBarPath, item->menu()); + if (!success) { + unregisterTrayIcon(item); + qWarning() << "failed to register" << item->instanceId() << MenuBarPath; + return false; + } + } + + QDBusMessage registerMethod = QDBusMessage::createMethodCall( + StatusNotifierWatcherService, StatusNotifierWatcherPath, StatusNotifierWatcherService, + QLatin1String("RegisterStatusNotifierItem")); + registerMethod.setArguments(QVariantList() << item->instanceId()); + success = m_connection.callWithCallback(registerMethod, this, SIGNAL(trayIconRegistered()), SLOT(dbusError(QDBusError))); + + return success; +} + +bool QDBusMenuConnection::unregisterTrayIcon(QDBusTrayIcon *item) +{ + connection().unregisterObject(MenuBarPath); + 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/platformsupport/dbusmenu/qdbusmenuconnection_p.h b/src/platformsupport/dbusmenu/qdbusmenuconnection_p.h new file mode 100644 index 0000000000..361ac81add --- /dev/null +++ b/src/platformsupport/dbusmenu/qdbusmenuconnection_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $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> + +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 = 0); + QDBusConnection connection() const { return m_connection; } + bool isWatcherRegistered() const { return m_watcherRegistered; } +#ifndef QT_NO_SYSTEMTRAYICON + bool registerTrayIcon(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_watcherRegistered; +}; + +QT_END_NAMESPACE + +#endif // DBUSCONNECTION_H diff --git a/src/platformsupport/dbusmenu/qdbusmenutypes.cpp b/src/platformsupport/dbusmenu/qdbusmenutypes.cpp new file mode 100644 index 0000000000..c398e1aa56 --- /dev/null +++ b/src/platformsupport/dbusmenu/qdbusmenutypes.cpp @@ -0,0 +1,257 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $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> +#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) +{ + qCDebug(qLcMenu) << id << "depth" << depth << propertyNames; + m_id = id; + if (id == 0) { + m_properties.insert(QLatin1String("children-display"), QLatin1String("submenu")); + Q_FOREACH (const QDBusPlatformMenu *menu, QDBusPlatformMenu::topLevelMenus()) { + if (menu) + Q_FOREACH (const QDBusPlatformMenuItem *item, menu->items()) { + QDBusMenuLayoutItem child; + child.populate(item, depth - 1, propertyNames); + m_children << child; + } + } + } else { + // TODO insert menu properties (name-value pairs) + } + QDBusPlatformMenu *menu = QDBusPlatformMenu::byId(id); + if (depth != 0 && menu) { + Q_FOREACH (QDBusPlatformMenuItem *item, menu->items()) { + QDBusMenuLayoutItem child; + child.populate(item, depth - 1, propertyNames); + m_children << child; + } + } + if (menu) + return menu->revision(); + return 1; +} + +void QDBusMenuLayoutItem::populate(const QDBusPlatformMenuItem *item, int depth, const QStringList &propertyNames) +{ + Q_UNUSED(depth) + Q_UNUSED(propertyNames) + m_id = item->dbusID(); + QDBusMenuItem proxy(item); + m_properties = proxy.m_properties; + // TODO populate m_children +} + +const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuLayoutItem &item) +{ + arg.beginStructure(); + arg << item.m_id << item.m_properties; + arg.beginArray(qMetaTypeId<QDBusVariant>()); + foreach (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 = dbusVariant.variant().value<QDBusArgument>(); + + 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>(); +} + +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()) { + // dbusmenu supports "radio" too, but QPlatformMenuItem doesn't seem to + // (QAction would have an exclusive actionGroup) + m_properties.insert(QLatin1String("toggle-type"), QLatin1String("checkmark")); + m_properties.insert(QLatin1String("toggle-state"), item->isChecked() ? 1 : 0); + } + /* TODO support shortcuts + const QKeySequence &scut = item->shortcut(); + if (!scut.isEmpty()) { + QDBusMenuShortcut shortcut(scut); + properties.insert(QLatin1String("shortcut"), QVariant::fromValue(shortcut)); + } + */ + 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()); + } + } + if (!item->isVisible()) + m_properties.insert(QLatin1String("visible"), false); +} + +QDBusMenuItemList QDBusMenuItem::items(const QList<int> &ids, const QStringList &propertyNames) +{ + Q_UNUSED(propertyNames) + QDBusMenuItemList ret; + QList<const QDBusPlatformMenuItem *> items = QDBusPlatformMenuItem::byIds(ids); + Q_FOREACH (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; +} + +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/platformsupport/dbusmenu/qdbusmenutypes_p.h b/src/platformsupport/dbusmenu/qdbusmenutypes_p.h new file mode 100644 index 0000000000..c445c958fb --- /dev/null +++ b/src/platformsupport/dbusmenu/qdbusmenutypes_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDBUSMENUTYPES_H +#define QDBUSMENUTYPES_H + +#include <QObject> +#include <QString> +#include <QDBusArgument> +#include <QDBusConnection> +#include <QDBusObjectPath> +#include <QPixmap> + +QT_BEGIN_NAMESPACE + +class QDBusPlatformMenu; +class QDBusPlatformMenuItem; +class QDBusMenuItem; +typedef QList<QDBusMenuItem> QDBusMenuItemList; + +class QDBusMenuItem +{ +public: + QDBusMenuItem() { } + QDBusMenuItem(const QDBusPlatformMenuItem *item); + + static QDBusMenuItemList items(const QList<int> &ids, const QStringList &propertyNames); + static QString convertMnemonic(const QString &label); + static void registerDBusTypes(); + + int m_id; + QVariantMap m_properties; +}; + +const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuItem &item); +const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuItem &item); + +class QDBusMenuItemKeys +{ +public: + + int id; + QStringList properties; +}; + +const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuItemKeys &keys); +const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuItemKeys &keys); + +typedef QList<QDBusMenuItemKeys> QDBusMenuItemKeysList; + +class QDBusMenuLayoutItem +{ +public: + uint populate(int id, int depth, const QStringList &propertyNames); + void populate(const QDBusPlatformMenuItem *item, int depth, const QStringList &propertyNames); + + int m_id; + QVariantMap m_properties; + QList<QDBusMenuLayoutItem> m_children; +}; + +const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuLayoutItem &); +const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuLayoutItem &item); + +typedef QList<QDBusMenuLayoutItem> QDBusMenuLayoutItemList; + +class QDBusMenuEvent +{ +public: + int m_id; + QString m_eventId; + QDBusVariant m_data; + uint m_timestamp; +}; + +const QDBusArgument &operator<<(QDBusArgument &arg, const QDBusMenuEvent &ev); +const QDBusArgument &operator>>(const QDBusArgument &arg, QDBusMenuEvent &ev); + +typedef QList<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) + +#endif diff --git a/src/platformsupport/dbusmenu/qdbusplatformmenu.cpp b/src/platformsupport/dbusmenu/qdbusplatformmenu.cpp new file mode 100644 index 0000000000..02321dcc89 --- /dev/null +++ b/src/platformsupport/dbusmenu/qdbusplatformmenu.cpp @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdbusplatformmenu_p.h" + +#include <QDebug> +#include <QWindow> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(qLcMenu, "qt.qpa.menu") + +static int nextDBusID = 1; +QHash<int, QDBusPlatformMenu *> menusByID; +QHash<int, QDBusPlatformMenuItem *> menuItemsByID; + +QDBusPlatformMenuItem::QDBusPlatformMenuItem(quintptr tag) + : m_tag(tag ? tag : reinterpret_cast<quintptr>(this)) // QMenu will overwrite this later + , m_subMenu(Q_NULLPTR) + , m_role(NoRole) + , m_isEnabled(false) + , m_isVisible(true) + , m_isSeparator(false) + , m_isCheckable(false) + , m_isChecked(false) + , m_dbusID(nextDBusID++) +{ + menuItemsByID.insert(m_dbusID, this); +} + +void QDBusPlatformMenuItem::setTag(quintptr tag) +{ + m_tag = tag; +} + +void QDBusPlatformMenuItem::setText(const QString &text) +{ + qCDebug(qLcMenu) << m_dbusID << text; + m_text = text; +} + +void QDBusPlatformMenuItem::setIcon(const QIcon &icon) +{ + m_icon = icon; +} + +void QDBusPlatformMenuItem::setMenu(QPlatformMenu *menu) +{ + m_subMenu = static_cast<QDBusPlatformMenu *>(menu); +} + +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::setShortcut(const QKeySequence &shortcut) +{ + m_shortcut = shortcut; +} + +void QDBusPlatformMenuItem::trigger() +{ + emit activated(); +} + +QDBusPlatformMenuItem *QDBusPlatformMenuItem::byId(int id) +{ + return menuItemsByID[id]; +} + +QList<const QDBusPlatformMenuItem *> QDBusPlatformMenuItem::byIds(const QList<int> &ids) +{ + QList<const QDBusPlatformMenuItem *> ret; + Q_FOREACH (int id, ids) { + if (menuItemsByID.contains(id)) + ret << menuItemsByID[id]; + } + return ret; +} + + +QDBusPlatformMenu::QDBusPlatformMenu(quintptr tag) + : m_tag(tag ? tag : reinterpret_cast<quintptr>(this)) + , m_isEnabled(false) + , m_isVisible(true) + , m_isSeparator(false) + , m_dbusID(nextDBusID++) + , m_revision(0) +{ + menusByID.insert(m_dbusID, this); +} + +QDBusPlatformMenu::~QDBusPlatformMenu() +{ + menusByID.remove(m_dbusID); +} + +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); +} + +void QDBusPlatformMenu::removeMenuItem(QPlatformMenuItem *menuItem) +{ + m_items.removeAll(static_cast<QDBusPlatformMenuItem *>(menuItem)); + m_itemsByTag.remove(menuItem->tag()); +} + +void QDBusPlatformMenu::syncMenuItem(QPlatformMenuItem *menuItem) +{ + // 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 + emitUpdated(); + QDBusMenuItemList updated; + QDBusMenuItemKeysList removed; + updated << QDBusMenuItem(static_cast<QDBusPlatformMenuItem *>(menuItem)); + qCDebug(qLcMenu) << updated; + emit propertiesUpdated(updated, removed); +} + +QDBusPlatformMenu *QDBusPlatformMenu::byId(int id) +{ + return menusByID[id]; +} + +QList<QDBusPlatformMenu *> QDBusPlatformMenu::topLevelMenus() +{ + // TODO just the top-level menus, not all menus + return menusByID.values(); +} + +void QDBusPlatformMenu::emitUpdated() +{ + emit updated(++m_revision, m_dbusID); +} + +void QDBusPlatformMenu::setTag(quintptr tag) +{ + m_tag = tag; +} + +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; +} + +QPlatformMenuItem *QDBusPlatformMenu::menuItemAt(int position) const +{ + return m_items.at(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(); + ret->setMenu(const_cast<QDBusPlatformMenu *>(this)); + return ret; +} + +QT_END_NAMESPACE diff --git a/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h b/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h new file mode 100644 index 0000000000..98c7a564cc --- /dev/null +++ b/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDBUSPLATFORMMENU_H +#define QDBUSPLATFORMMENU_H +// +// 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 Q_GUI_EXPORT QDBusPlatformMenuItem : public QPlatformMenuItem +{ + Q_OBJECT + +public: + QDBusPlatformMenuItem(quintptr tag = 0LL); + + quintptr tag()const Q_DECL_OVERRIDE { return m_tag; } + void setTag(quintptr tag) Q_DECL_OVERRIDE; + + const QString text() const { return m_text; } + void setText(const QString &text) Q_DECL_OVERRIDE; + QIcon icon() const { return m_icon; } + void setIcon(const QIcon &icon) Q_DECL_OVERRIDE; + const QPlatformMenu *menu() const { return m_subMenu; } + void setMenu(QPlatformMenu *menu) Q_DECL_OVERRIDE; + bool isEnabled() const { return m_isEnabled; } + void setEnabled(bool enabled) Q_DECL_OVERRIDE; + bool isVisible() const { return m_isVisible; } + void setVisible(bool isVisible) Q_DECL_OVERRIDE; + bool isSeparator() const { return m_isSeparator; } + void setIsSeparator(bool isSeparator) Q_DECL_OVERRIDE; + void setFont(const QFont &font) Q_DECL_OVERRIDE { Q_UNUSED(font); } + void setRole(MenuRole role) Q_DECL_OVERRIDE; + bool isCheckable() const { return m_isCheckable; } + void setCheckable(bool checkable) Q_DECL_OVERRIDE; + bool isChecked() const { return m_isChecked; } + void setChecked(bool isChecked) Q_DECL_OVERRIDE; + QKeySequence shortcut() const { return m_shortcut; } + void setShortcut(const QKeySequence& shortcut) Q_DECL_OVERRIDE; + void setIconSize(int size) Q_DECL_OVERRIDE { Q_UNUSED(size); } + void setNativeContents(WId item) Q_DECL_OVERRIDE { Q_UNUSED(item); } + + int dbusID() const { return m_dbusID; } + + void trigger(); + + bool operator==(const QDBusPlatformMenuItem& other) { return m_tag == other.m_tag; } + + static QDBusPlatformMenuItem *byId(int id); + static QList<const QDBusPlatformMenuItem *> byIds(const QList<int> &ids); + +private: + quintptr m_tag; + 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; + int m_dbusID : 16; + int m_reserved : 7; + QKeySequence m_shortcut; +}; + +class Q_GUI_EXPORT QDBusPlatformMenu : public QPlatformMenu +{ + Q_OBJECT + +public: + QDBusPlatformMenu(quintptr tag = 0LL); + ~QDBusPlatformMenu(); + void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) Q_DECL_OVERRIDE; + void removeMenuItem(QPlatformMenuItem *menuItem) Q_DECL_OVERRIDE; + void syncMenuItem(QPlatformMenuItem *menuItem) Q_DECL_OVERRIDE; + void syncSeparatorsCollapsible(bool enable) Q_DECL_OVERRIDE { Q_UNUSED(enable); } + + quintptr tag()const Q_DECL_OVERRIDE { return m_tag; } + void setTag(quintptr tag) Q_DECL_OVERRIDE; + + const QString text() { return m_text; } + void setText(const QString &text) Q_DECL_OVERRIDE; + void setIcon(const QIcon &icon) Q_DECL_OVERRIDE; + void setEnabled(bool enabled) Q_DECL_OVERRIDE; + void setVisible(bool visible) Q_DECL_OVERRIDE; + void setMinimumWidth(int width) Q_DECL_OVERRIDE { Q_UNUSED(width); } + void setFont(const QFont &font) Q_DECL_OVERRIDE { Q_UNUSED(font); } + void setMenuType(MenuType type) Q_DECL_OVERRIDE { Q_UNUSED(type); } + + void showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item) Q_DECL_OVERRIDE + { + Q_UNUSED(parentWindow); + Q_UNUSED(targetRect); + Q_UNUSED(item); + setVisible(true); + } + + void dismiss() Q_DECL_OVERRIDE { } // Closes this and all its related menu popups + + QPlatformMenuItem *menuItemAt(int position) const Q_DECL_OVERRIDE; + QPlatformMenuItem *menuItemForTag(quintptr tag) const Q_DECL_OVERRIDE; + const QList<QDBusPlatformMenuItem *> items() const; + + QPlatformMenuItem *createMenuItem() const Q_DECL_OVERRIDE; + + bool operator==(const QDBusPlatformMenu& other) { return m_tag == other.m_tag; } + + static QDBusPlatformMenu* byId(int id); + static QList<QDBusPlatformMenu *> topLevelMenus(); + + uint revision() { return m_revision; } + + void emitUpdated(); + +signals: + void updated(uint revision, int dbusId); + void propertiesUpdated(QDBusMenuItemList updatedProps, QDBusMenuItemKeysList removedProps); + +private: + quintptr m_tag; + QString m_text; + QIcon m_icon; + bool m_isEnabled; + bool m_isVisible; + bool m_isSeparator; + int m_dbusID; + uint m_revision; + QHash<quintptr, QDBusPlatformMenuItem *> m_itemsByTag; + QList<QDBusPlatformMenuItem *> m_items; +}; + +QT_END_NAMESPACE + +#endif + diff --git a/src/platformsupport/dbustray/dbustray.pri b/src/platformsupport/dbustray/dbustray.pri new file mode 100644 index 0000000000..ca1ff8e434 --- /dev/null +++ b/src/platformsupport/dbustray/dbustray.pri @@ -0,0 +1,13 @@ +QT_FOR_PRIVATE += dbus + +INCLUDEPATH += $$PWD $$PWD/../../gui/kernel + +HEADERS += \ + $$PWD/qdbustrayicon_p.h \ + $$PWD/qdbustraytypes_p.h \ + $$PWD/qstatusnotifieritemadaptor_p.h \ + +SOURCES += \ + $$PWD/qdbustrayicon.cpp \ + $$PWD/qdbustraytypes.cpp \ + $$PWD/qstatusnotifieritemadaptor.cpp \ diff --git a/src/platformsupport/dbustray/qdbustrayicon.cpp b/src/platformsupport/dbustray/qdbustrayicon.cpp new file mode 100644 index 0000000000..1c21da849c --- /dev/null +++ b/src/platformsupport/dbustray/qdbustrayicon.cpp @@ -0,0 +1,260 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_NO_SYSTEMTRAYICON + +#include "qdbustrayicon_p.h" +#include "qdbusmenuconnection_p.h" +#include "qstatusnotifieritemadaptor_p.h" +#include "qdbusmenuadaptor_p.h" +#include "dbusmenu/qdbusplatformmenu_p.h" + +#include <qplatformmenu.h> +#include <qstring.h> +#include <qdebug.h> +#include <qrect.h> +#include <qloggingcategory.h> +#include <qplatformintegration.h> +#include <qplatformservices.h> +#include <private/qguiapplication_p.h> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(qLcTray, "qt.qpa.tray") + +static const QString KDEItemFormat = QStringLiteral("org.kde.StatusNotifierItem-%1-%2"); +static const QString TempFileTemplate = QDir::tempPath() + QStringLiteral("/qt-trayicon-XXXXXX.png"); +static int instanceCount = 0; + +/*! + \class QDBusTrayIcon + \internal +*/ + +QDBusTrayIcon::QDBusTrayIcon() + : m_dbusConnection(Q_NULLPTR) + , m_adaptor(new QStatusNotifierItemAdaptor(this)) + , m_menuAdaptor(Q_NULLPTR) + , m_menu(Q_NULLPTR) + , m_instanceId(KDEItemFormat.arg(QCoreApplication::applicationPid()).arg(++instanceCount)) + , m_category(QStringLiteral("ApplicationStatus")) + , m_defaultStatus(QStringLiteral("Active")) // be visible all the time. QSystemTrayIcon has no API to control this. + , m_status(m_defaultStatus) + , m_tempIcon(Q_NULLPTR) + , m_tempAttentionIcon(Q_NULLPTR) +{ + qCDebug(qLcTray); + if (instanceCount == 1) { + QDBusMenuItem::registerDBusTypes(); + qDBusRegisterMetaType<QXdgDBusImageStruct>(); + qDBusRegisterMetaType<QXdgDBusImageVector>(); + qDBusRegisterMetaType<QXdgDBusToolTipStruct>(); + } + connect(this, SIGNAL(statusChanged(QString)), m_adaptor, SIGNAL(NewStatus(QString))); + connect(this, SIGNAL(tooltipChanged()), m_adaptor, SIGNAL(NewToolTip())); + connect(this, SIGNAL(iconChanged()), m_adaptor, SIGNAL(NewIcon())); + connect(this, SIGNAL(attention()), m_adaptor, SIGNAL(NewAttentionIcon())); + connect(this, SIGNAL(attention()), m_adaptor, SIGNAL(NewTitle())); + connect(&m_attentionTimer, SIGNAL(timeout()), this, SLOT(attentionTimerExpired())); + m_attentionTimer.setSingleShot(true); +} + +QDBusTrayIcon::~QDBusTrayIcon() +{ +} + +void QDBusTrayIcon::init() +{ + qCDebug(qLcTray) << "registering" << m_instanceId; + dBusConnection()->registerTrayIcon(this); +} + +void QDBusTrayIcon::cleanup() +{ + qCDebug(qLcTray) << "unregistering" << m_instanceId; + dBusConnection()->unregisterTrayIcon(this); + delete m_dbusConnection; + m_dbusConnection = Q_NULLPTR; +} + +void QDBusTrayIcon::activate(int x, int y) +{ + qCDebug(qLcTray) << x << y; + setStatus(QStringLiteral("Active")); +} + +void QDBusTrayIcon::attentionTimerExpired() +{ + m_messageTitle = QString(); + m_message = QString(); + m_attentionIcon = QIcon(); + emit attention(); + emit tooltipChanged(); + setStatus(m_defaultStatus); +} + +void QDBusTrayIcon::setStatus(const QString &status) +{ + qCDebug(qLcTray) << status; + if (m_status == status) + return; + m_status = status; + emit statusChanged(m_status); +} + +QTemporaryFile *QDBusTrayIcon::tempIcon(const QIcon &icon) +{ + // Hack for Unity, which doesn't handle icons sent across D-Bus: + // save the icon to a temp file and set the icon name to that filename. + static bool necessary = (QGuiApplicationPrivate::platformIntegration()->services()->desktopEnvironment().split(':').contains("UNITY")); + if (!necessary) + return Q_NULLPTR; + QTemporaryFile *ret = new QTemporaryFile(TempFileTemplate, this); + QSize tempSize; + Q_FOREACH (const QSize &size, icon.availableSizes()) + if (size.width() > tempSize.width()) + tempSize = size; + ret->open(); + icon.pixmap(tempSize).save(ret); + ret->close(); + return ret; +} + +QDBusMenuConnection * QDBusTrayIcon::dBusConnection() +{ + if (!m_dbusConnection) + m_dbusConnection = new QDBusMenuConnection(this); + return m_dbusConnection; +} + +void QDBusTrayIcon::updateIcon(const QIcon &icon) +{ + m_iconName = icon.name(); + m_icon = icon; + if (m_iconName.isEmpty()) { + if (m_tempIcon) + delete m_tempIcon; + m_tempIcon = tempIcon(icon); + if (m_tempIcon) + m_iconName = m_tempIcon->fileName(); + } + qCDebug(qLcTray) << m_iconName << icon.availableSizes(); + emit iconChanged(); +} + +void QDBusTrayIcon::updateToolTip(const QString &tooltip) +{ + qCDebug(qLcTray) << tooltip; + m_tooltip = tooltip; + emit tooltipChanged(); +} + +QPlatformMenu *QDBusTrayIcon::createMenu() const +{ + qCDebug(qLcTray); + if (!m_menu) + const_cast<QDBusTrayIcon *>(this)->m_menu = new QDBusPlatformMenu(); + return m_menu; +} + +void QDBusTrayIcon::updateMenu(QPlatformMenu * menu) +{ + qCDebug(qLcTray) << menu; + if (!m_menu) + m_menu = qobject_cast<QDBusPlatformMenu *>(menu); + if (!m_menuAdaptor) { + m_menuAdaptor = new QDBusMenuAdaptor(m_menu); + // TODO connect(m_menu, , m_menuAdaptor, SIGNAL(ItemActivationRequested(int,uint))); + connect(m_menu, SIGNAL(propertiesUpdated(QDBusMenuItemList,QDBusMenuItemKeysList)), + m_menuAdaptor, SIGNAL(ItemsPropertiesUpdated(QDBusMenuItemList,QDBusMenuItemKeysList))); + connect(m_menu, SIGNAL(updated(uint,int)), + m_menuAdaptor, SIGNAL(LayoutUpdated(uint,int))); + } + m_menu->emitUpdated(); +} + +void QDBusTrayIcon::contextMenu(int x, int y) +{ + qCDebug(qLcTray) << x << y; +} + +void QDBusTrayIcon::showMessage(const QString &title, const QString &msg, const QIcon &icon, + QPlatformSystemTrayIcon::MessageIcon iconType, int msecs) +{ + m_messageTitle = title; + m_message = msg; + m_attentionIcon = icon; + switch (iconType) { + case Information: + m_attentionIconName = QStringLiteral("dialog-information"); + break; + case Warning: + m_attentionIconName = QStringLiteral("dialog-warning"); + break; + case Critical: + m_attentionIconName = QStringLiteral("dialog-error"); + break; + default: + m_attentionIconName.clear(); + break; + } + if (m_attentionIconName.isEmpty()) { + if (m_tempAttentionIcon) + delete m_tempAttentionIcon; + m_tempAttentionIcon = tempIcon(icon); + if (m_tempAttentionIcon) + m_attentionIconName = m_tempAttentionIcon->fileName(); + } + qCDebug(qLcTray) << title << msg << + QPlatformSystemTrayIcon::metaObject()->enumerator( + QPlatformSystemTrayIcon::staticMetaObject.indexOfEnumerator("MessageIcon")).valueToKey(iconType) + << m_attentionIconName << msecs; + setStatus(QStringLiteral("NeedsAttention")); + m_attentionTimer.start(msecs); + emit tooltipChanged(); + emit attention(); +} + +bool QDBusTrayIcon::isSystemTrayAvailable() const +{ + QDBusMenuConnection * conn = const_cast<QDBusTrayIcon *>(this)->dBusConnection(); + + // If the KDE watcher service is registered, we must be on a desktop + // where a StatusNotifier-conforming system tray exists. + qCDebug(qLcTray) << conn->isWatcherRegistered(); + return conn->isWatcherRegistered(); +} + +QT_END_NAMESPACE +#endif //QT_NO_SYSTEMTRAYICON + diff --git a/src/platformsupport/dbustray/qdbustrayicon_p.h b/src/platformsupport/dbustray/qdbustrayicon_p.h new file mode 100644 index 0000000000..1b5f262ef1 --- /dev/null +++ b/src/platformsupport/dbustray/qdbustrayicon_p.h @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QDBUSTRAYICON_H +#define QDBUSTRAYICON_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. +// + +#ifndef QT_NO_SYSTEMTRAYICON + +#include <QIcon> +#include <QTemporaryFile> +#include <QTimer> +#include "QtGui/qpa/qplatformsystemtrayicon.h" +#include "private/qdbusmenuconnection_p.h" + +QT_BEGIN_NAMESPACE + +class QStatusNotifierItemAdaptor; +class QDBusMenuAdaptor; +class QDBusPlatformMenu; + +class QDBusTrayIcon: public QPlatformSystemTrayIcon +{ + Q_OBJECT + Q_PROPERTY(QString category READ category NOTIFY categoryChanged) + Q_PROPERTY(QString status READ status NOTIFY statusChanged) + Q_PROPERTY(QString tooltip READ tooltip NOTIFY tooltipChanged) + Q_PROPERTY(QString iconName READ iconName NOTIFY iconChanged) + Q_PROPERTY(QIcon icon READ icon NOTIFY iconChanged) + Q_PROPERTY(bool isRequestingAttention READ isRequestingAttention NOTIFY attention) + Q_PROPERTY(QString attentionTitle READ attentionTitle NOTIFY attention) + Q_PROPERTY(QString attentionMessage READ attentionMessage NOTIFY attention) + Q_PROPERTY(QString attentionIconName READ attentionIconName NOTIFY attention) + Q_PROPERTY(QIcon attentionIcon READ attentionIcon NOTIFY attention) + Q_PROPERTY(QDBusPlatformMenu *menu READ menu NOTIFY menuChanged) + +public: + QDBusTrayIcon(); + + virtual ~QDBusTrayIcon(); + + QDBusMenuConnection * dBusConnection(); + + void init() Q_DECL_OVERRIDE; + void cleanup() Q_DECL_OVERRIDE; + void updateIcon(const QIcon &icon) Q_DECL_OVERRIDE; + void updateToolTip(const QString &tooltip) Q_DECL_OVERRIDE; + void updateMenu(QPlatformMenu *menu) Q_DECL_OVERRIDE; + QPlatformMenu *createMenu() const Q_DECL_OVERRIDE; + void showMessage(const QString &title, const QString &msg, + const QIcon &icon, MessageIcon iconType, int msecs) Q_DECL_OVERRIDE; + + bool isSystemTrayAvailable() const Q_DECL_OVERRIDE; + bool supportsMessages() const Q_DECL_OVERRIDE { return true; } + QRect geometry() const Q_DECL_OVERRIDE { return QRect(); } + + QString category() const { return m_category; } + QString status() const { return m_status; } + QString tooltip() const { return m_tooltip; } + + QString iconName() const { return m_iconName; } + const QIcon & icon() const { return m_icon; } + + bool isRequestingAttention() const { return m_attentionTimer.isActive(); } + QString attentionTitle() const { return m_messageTitle; } + QString attentionMessage() const { return m_message; } + QString attentionIconName() const { return m_attentionIconName; } + const QIcon & attentionIcon() const { return m_attentionIcon; } + + QString instanceId() const { return m_instanceId; } + + QDBusPlatformMenu *menu() { return m_menu; } + +public Q_SLOTS: + void activate(int x, int y); + void contextMenu(int x, int y); + +signals: + void categoryChanged(); + void statusChanged(QString arg); + void tooltipChanged(); + void iconChanged(); + void attention(); + void menuChanged(); + +private Q_SLOTS: + void attentionTimerExpired(); + +private: + void setStatus(const QString &status); + QTemporaryFile *tempIcon(const QIcon &icon); + +private: + QDBusMenuConnection* m_dbusConnection; + QStatusNotifierItemAdaptor *m_adaptor; + QDBusMenuAdaptor *m_menuAdaptor; + QDBusPlatformMenu *m_menu; + QString m_instanceId; + QString m_category; + QString m_defaultStatus; + QString m_status; + QString m_tooltip; + QString m_messageTitle; + QString m_message; + QIcon m_icon; + QTemporaryFile *m_tempIcon; + QString m_iconName; + QIcon m_attentionIcon; + QTemporaryFile *m_tempAttentionIcon; + QString m_attentionIconName; + QTimer m_attentionTimer; + bool m_isRequestingAttention; + bool m_hasMenu; +}; + +QT_END_NAMESPACE +#endif // QT_NO_SYSTEMTRAYICON + +#endif // QDBUSTRAYICON_H diff --git a/src/platformsupport/dbustray/qdbustraytypes.cpp b/src/platformsupport/dbustray/qdbustraytypes.cpp index 0ca6669508..5100f8ee2c 100644 --- a/src/platformsupport/dbustray/qdbustraytypes.cpp +++ b/src/platformsupport/dbustray/qdbustraytypes.cpp @@ -32,20 +32,47 @@ ** ****************************************************************************/ +#ifndef QT_NO_SYSTEMTRAYICON + #include "qdbustraytypes_p.h" #include <QDBusConnection> +#include <QDBusMetaType> #include <QImage> #include <QIcon> #include <QImage> #include <QPixmap> #include <QDebug> #include <QtEndian> +#include <qpa/qplatformmenu.h> +#include "qdbusplatformmenu_p.h" + +QT_BEGIN_NAMESPACE + +static const int IconSizeLimit = 32; +static const int IconNormalSmallSize = 22; QXdgDBusImageVector iconToQXdgDBusImageVector(const QIcon &icon) { QXdgDBusImageVector ret; - foreach (QSize size, icon.availableSizes()) { + QList<QSize> sizes = icon.availableSizes(); + + // Omit any size larger than 32 px, to save D-Bus bandwidth; + // and ensure that 22px or smaller exists, because it's a common size. + bool hasSmallIcon = false; + QList<QSize> toRemove; + Q_FOREACH (const QSize &size, sizes) { + if (size.width() <= IconNormalSmallSize) + hasSmallIcon = true; + else if (size.width() > IconSizeLimit) + toRemove << size; + } + Q_FOREACH (const QSize &size, toRemove) + sizes.removeOne(size); + if (!hasSmallIcon) + sizes.append(QSize(IconNormalSmallSize, IconNormalSmallSize)); + + foreach (QSize size, sizes) { QXdgDBusImageStruct kim; kim.width = size.width(); kim.height = size.height(); @@ -155,9 +182,5 @@ const QDBusArgument &operator>>(const QDBusArgument &argument, QXdgDBusToolTipSt return argument; } -void registerDBusTrayTypes() -{ - qDBusRegisterMetaType<QXdgDBusImageStruct>(); - qDBusRegisterMetaType<QXdgDBusImageVector>(); - qDBusRegisterMetaType<QXdgDBusToolTipStruct>(); -} +QT_END_NAMESPACE +#endif // QT_NO_SYSTEMTRAYICON diff --git a/src/platformsupport/dbustray/qdbustraytypes_p.h b/src/platformsupport/dbustray/qdbustraytypes_p.h index 5b275e0d33..2e1421eccd 100644 --- a/src/platformsupport/dbustray/qdbustraytypes_p.h +++ b/src/platformsupport/dbustray/qdbustraytypes_p.h @@ -35,6 +35,8 @@ #ifndef QDBUSTRAYTYPES_P_H #define QDBUSTRAYTYPES_P_H +#ifndef QT_NO_SYSTEMTRAYICON + #include <QObject> #include <QString> #include <QDBusArgument> @@ -42,6 +44,8 @@ #include <QDBusObjectPath> #include <QPixmap> +QT_BEGIN_NAMESPACE + // Custom message type to send icons across D-Bus struct QXdgDBusImageStruct { @@ -66,16 +70,17 @@ struct QXdgDBusToolTipStruct const QDBusArgument &operator<<(QDBusArgument &argument, const QXdgDBusImageStruct &icon); const QDBusArgument &operator>>(const QDBusArgument &argument, QXdgDBusImageStruct &icon); -Q_DECLARE_METATYPE(QXdgDBusImageStruct) - const QDBusArgument &operator<<(QDBusArgument &argument, const QXdgDBusImageVector &iconVector); const QDBusArgument &operator>>(const QDBusArgument &argument, QXdgDBusImageVector &iconVector); -Q_DECLARE_METATYPE(QXdgDBusImageVector) - const QDBusArgument &operator<<(QDBusArgument &argument, const QXdgDBusToolTipStruct &toolTip); const QDBusArgument &operator>>(const QDBusArgument &argument, QXdgDBusToolTipStruct &toolTip); +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QXdgDBusImageStruct) +Q_DECLARE_METATYPE(QXdgDBusImageVector) Q_DECLARE_METATYPE(QXdgDBusToolTipStruct) +#endif // QT_NO_SYSTEMTRAYICON #endif // QDBUSTRAYTYPES_P_H diff --git a/src/platformsupport/dbustray/qstatusnotifieritemadaptor.cpp b/src/platformsupport/dbustray/qstatusnotifieritemadaptor.cpp new file mode 100644 index 0000000000..8afcaa70d5 --- /dev/null +++ b/src/platformsupport/dbustray/qstatusnotifieritemadaptor.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + This file was originally created by qdbusxml2cpp version 0.8 + Command line was: + qdbusxml2cpp -a statusnotifieritem ../../3rdparty/dbus-ifaces/org.kde.StatusNotifierItem.xml + + However it is maintained manually, because this adapter needs to do + significant interface adaptation, and can do it more efficiently using the + QDBusTrayIcon API directly rather than via QObject::property() and + QMetaObject::invokeMethod(). +*/ + +#ifndef QT_NO_SYSTEMTRAYICON + +#include "qstatusnotifieritemadaptor_p.h" +#include "qdbustrayicon_p.h" + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(qLcMenu) + +QStatusNotifierItemAdaptor::QStatusNotifierItemAdaptor(QDBusTrayIcon *parent) + : QDBusAbstractAdaptor(parent), m_trayIcon(parent) +{ + setAutoRelaySignals(true); +} + +QStatusNotifierItemAdaptor::~QStatusNotifierItemAdaptor() +{ +} + +QString QStatusNotifierItemAdaptor::attentionIconName() const +{ + return m_trayIcon->attentionIconName(); +} + +QXdgDBusImageVector QStatusNotifierItemAdaptor::attentionIconPixmap() const +{ + return iconToQXdgDBusImageVector(m_trayIcon->attentionIcon()); +} + +QString QStatusNotifierItemAdaptor::attentionMovieName() const +{ + return QString(); +} + +QString QStatusNotifierItemAdaptor::category() const +{ + return m_trayIcon->category(); +} + +QString QStatusNotifierItemAdaptor::iconName() const +{ + return m_trayIcon->iconName(); +} + +QXdgDBusImageVector QStatusNotifierItemAdaptor::iconPixmap() const +{ + return iconToQXdgDBusImageVector(m_trayIcon->icon()); +} + +QString QStatusNotifierItemAdaptor::id() const +{ + // from the API docs: "a name that should be unique for this application and + // consistent between sessions, such as the application name itself" + return QCoreApplication::applicationName(); +} + +bool QStatusNotifierItemAdaptor::itemIsMenu() const +{ + // From KDE docs: if this is true, the item only supports the context menu, + // so the visualization should prefer sending ContextMenu() instead of Activate(). + // But QSystemTrayIcon doesn't have such a setting: it will emit activated() + // and the application is free to use it or ignore it; we don't know whether it will. + return false; +} + +QDBusObjectPath QStatusNotifierItemAdaptor::menu() const +{ + return QDBusObjectPath(m_trayIcon->menu() ? "/MenuBar" : "/NO_DBUSMENU"); +} + +QString QStatusNotifierItemAdaptor::overlayIconName() const +{ + return QString(); +} + +QXdgDBusImageVector QStatusNotifierItemAdaptor::overlayIconPixmap() const +{ + QXdgDBusImageVector ret; // empty vector + return ret; +} + +QString QStatusNotifierItemAdaptor::status() const +{ + return m_trayIcon->status(); +} + +QString QStatusNotifierItemAdaptor::title() const +{ + // Shown e.g. when the icon is hidden, in the popup showing all hidden items. + // Since QSystemTrayIcon doesn't have this property, the application name + // is the best information we have available. + return QCoreApplication::applicationName(); +} + +QXdgDBusToolTipStruct QStatusNotifierItemAdaptor::toolTip() const +{ + QXdgDBusToolTipStruct ret; + if (m_trayIcon->isRequestingAttention()) { + ret.title = m_trayIcon->attentionTitle(); + ret.subTitle = m_trayIcon->attentionMessage(); + ret.icon = m_trayIcon->attentionIconName(); + } else { + ret.title = m_trayIcon->tooltip(); + } + return ret; +} + +void QStatusNotifierItemAdaptor::Activate(int x, int y) +{ + m_trayIcon->activate(x, y); +} + +void QStatusNotifierItemAdaptor::ContextMenu(int x, int y) +{ + m_trayIcon->contextMenu(x, y); +} + +void QStatusNotifierItemAdaptor::Scroll(int, const QString &) +{ + // unsupported +} + +void QStatusNotifierItemAdaptor::SecondaryActivate(int, int) +{ + // unsupported +} + +QT_END_NAMESPACE + +#endif // QT_NO_SYSTEMTRAYICON diff --git a/src/platformsupport/dbustray/qstatusnotifieritemadaptor_p.h b/src/platformsupport/dbustray/qstatusnotifieritemadaptor_p.h new file mode 100644 index 0000000000..fe5da100b2 --- /dev/null +++ b/src/platformsupport/dbustray/qstatusnotifieritemadaptor_p.h @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + This file was originally created by qdbusxml2cpp version 0.8 + Command line was: + qdbusxml2cpp -a statusnotifieritem ../../3rdparty/dbus-ifaces/org.kde.StatusNotifierItem.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 QSTATUSNOTIFIERITEMADAPTER_P_H +#define QSTATUSNOTIFIERITEMADAPTER_P_H + +#ifndef QT_NO_SYSTEMTRAYICON + +#include <QtCore/QObject> +#include <QtDBus/QtDBus> + +#include "qdbustraytypes_p.h" + +QT_BEGIN_NAMESPACE +class QDBusTrayIcon; + +/* + Adaptor class for interface org.kde.StatusNotifierItem + see http://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/ + (also http://www.notmart.org/misc/statusnotifieritem/) +*/ +class QStatusNotifierItemAdaptor: public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.StatusNotifierItem") + Q_CLASSINFO("D-Bus Introspection", "" +" <interface name=\"org.kde.StatusNotifierItem\">\n" +" <property access=\"read\" type=\"s\" name=\"Category\"/>\n" +" <property access=\"read\" type=\"s\" name=\"Id\"/>\n" +" <property access=\"read\" type=\"s\" name=\"Title\"/>\n" +" <property access=\"read\" type=\"s\" name=\"Status\"/>\n" +" <property access=\"read\" type=\"i\" name=\"WindowId\"/>\n" +" <property access=\"read\" type=\"s\" name=\"IconThemePath\"/>\n" +" <property access=\"read\" type=\"o\" name=\"Menu\"/>\n" +" <property access=\"read\" type=\"b\" name=\"ItemIsMenu\"/>\n" +" <property access=\"read\" type=\"s\" name=\"IconName\"/>\n" +" <property access=\"read\" type=\"(iiay)\" name=\"IconPixmap\">\n" +" <annotation value=\"QXdgDBusImageVector\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n" +" </property>\n" +" <property access=\"read\" type=\"s\" name=\"OverlayIconName\"/>\n" +" <property access=\"read\" type=\"(iiay)\" name=\"OverlayIconPixmap\">\n" +" <annotation value=\"QXdgDBusImageVector\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n" +" </property>\n" +" <property access=\"read\" type=\"s\" name=\"AttentionIconName\"/>\n" +" <property access=\"read\" type=\"(iiay)\" name=\"AttentionIconPixmap\">\n" +" <annotation value=\"QXdgDBusImageVector\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n" +" </property>\n" +" <property access=\"read\" type=\"s\" name=\"AttentionMovieName\"/>\n" +" <property access=\"read\" type=\"(s(iiay)ss)\" name=\"ToolTip\">\n" +" <annotation value=\"QXdgDBusToolTipStruct\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n" +" </property>\n" +" <method name=\"ContextMenu\">\n" +" <arg direction=\"in\" type=\"i\" name=\"x\"/>\n" +" <arg direction=\"in\" type=\"i\" name=\"y\"/>\n" +" </method>\n" +" <method name=\"Activate\">\n" +" <arg direction=\"in\" type=\"i\" name=\"x\"/>\n" +" <arg direction=\"in\" type=\"i\" name=\"y\"/>\n" +" </method>\n" +" <method name=\"SecondaryActivate\">\n" +" <arg direction=\"in\" type=\"i\" name=\"x\"/>\n" +" <arg direction=\"in\" type=\"i\" name=\"y\"/>\n" +" </method>\n" +" <method name=\"Scroll\">\n" +" <arg direction=\"in\" type=\"i\" name=\"delta\"/>\n" +" <arg direction=\"in\" type=\"s\" name=\"orientation\"/>\n" +" </method>\n" +" <signal name=\"NewTitle\"/>\n" +" <signal name=\"NewIcon\"/>\n" +" <signal name=\"NewAttentionIcon\"/>\n" +" <signal name=\"NewOverlayIcon\"/>\n" +" <signal name=\"NewToolTip\"/>\n" +" <signal name=\"NewStatus\">\n" +" <arg type=\"s\" name=\"status\"/>\n" +" </signal>\n" +" </interface>\n" + "") +public: + QStatusNotifierItemAdaptor(QDBusTrayIcon *parent); + virtual ~QStatusNotifierItemAdaptor(); + +public: // PROPERTIES + Q_PROPERTY(QString AttentionIconName READ attentionIconName) + QString attentionIconName() const; + + Q_PROPERTY(QXdgDBusImageVector AttentionIconPixmap READ attentionIconPixmap) + QXdgDBusImageVector attentionIconPixmap() const; + + Q_PROPERTY(QString AttentionMovieName READ attentionMovieName) + QString attentionMovieName() const; + + Q_PROPERTY(QString Category READ category) + QString category() const; + + Q_PROPERTY(QString IconName READ iconName) + QString iconName() const; + + Q_PROPERTY(QXdgDBusImageVector IconPixmap READ iconPixmap) + QXdgDBusImageVector iconPixmap() const; + + Q_PROPERTY(QString Id READ id) + QString id() const; + + Q_PROPERTY(bool ItemIsMenu READ itemIsMenu) + bool itemIsMenu() const; + + Q_PROPERTY(QDBusObjectPath Menu READ menu) + QDBusObjectPath menu() const; + + Q_PROPERTY(QString OverlayIconName READ overlayIconName) + QString overlayIconName() const; + + Q_PROPERTY(QXdgDBusImageVector OverlayIconPixmap READ overlayIconPixmap) + QXdgDBusImageVector overlayIconPixmap() const; + + Q_PROPERTY(QString Status READ status) + QString status() const; + + Q_PROPERTY(QString Title READ title) + QString title() const; + + Q_PROPERTY(QXdgDBusToolTipStruct ToolTip READ toolTip) + QXdgDBusToolTipStruct toolTip() const; + +public Q_SLOTS: // METHODS + void Activate(int x, int y); + void ContextMenu(int x, int y); + void Scroll(int delta, const QString &orientation); + void SecondaryActivate(int x, int y); +Q_SIGNALS: // SIGNALS + void NewAttentionIcon(); + void NewIcon(); + void NewOverlayIcon(); + void NewStatus(const QString &status); + void NewTitle(); + void NewToolTip(); + +private: + QDBusTrayIcon *m_trayIcon; +}; + +QT_END_NAMESPACE +#endif // QT_NO_SYSTEMTRAYICON +#endif // QSTATUSNOTIFIERITEMADAPTER_P_H diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index 39cbd9d181..34e2ed3c9b 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -22,5 +22,9 @@ include(accessibility/accessibility.pri) include(linuxaccessibility/linuxaccessibility.pri) include(clipboard/clipboard.pri) include(platformcompositor/platformcompositor.pri) +contains(QT_CONFIG, dbus) { + include(dbusmenu/dbusmenu.pri) + include(dbustray/dbustray.pri) +} load(qt_module) diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp index 1060ff283b..9fa1f19f3c 100644 --- a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -51,6 +51,10 @@ #include <qpa/qplatformintegration.h> #include <qpa/qplatformservices.h> #include <qpa/qplatformdialoghelper.h> +#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON) +#include "QtPlatformSupport/private/qdbustrayicon_p.h" +#include "QtPlatformSupport/private/qdbusplatformmenu_p.h" +#endif #include <algorithm> @@ -85,6 +89,20 @@ const char *QGenericUnixTheme::name = "generic"; static const char defaultSystemFontNameC[] = "Sans Serif"; enum { defaultSystemFontSize = 9 }; +#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON) +static bool isDBusTrayAvailable() { + static bool dbusTrayAvailable = false; + static bool dbusTrayAvailableKnown = false; + if (!dbusTrayAvailableKnown) { + QDBusMenuConnection conn; + if (conn.isWatcherRegistered()) + dbusTrayAvailable = true; + dbusTrayAvailableKnown = true; + } + return dbusTrayAvailable; +} +#endif + class QGenericUnixThemePrivate : public QPlatformThemePrivate { public: @@ -509,6 +527,15 @@ QPlatformTheme *QKdeTheme::createKdeTheme() return new QKdeTheme(kdeDirs, kdeVersion); } +#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON) +QPlatformSystemTrayIcon *QKdeTheme::createPlatformSystemTrayIcon() const +{ + if (isDBusTrayAvailable()) + return new QDBusTrayIcon(); + return Q_NULLPTR; +} +#endif + #endif // QT_NO_SETTINGS /*! @@ -595,6 +622,15 @@ QString QGnomeTheme::gtkFontName() const return QStringLiteral("%1 %2").arg(QLatin1String(defaultSystemFontNameC)).arg(defaultSystemFontSize); } +#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON) +QPlatformSystemTrayIcon *QGnomeTheme::createPlatformSystemTrayIcon() const +{ + if (isDBusTrayAvailable()) + return new QDBusTrayIcon(); + return Q_NULLPTR; +} +#endif + QString QGnomeTheme::standardButtonText(int button) const { switch (button) { diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h b/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h index 2a689c6872..d0f7702793 100644 --- a/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -98,6 +98,9 @@ public: virtual const QPalette *palette(Palette type = SystemPalette) const Q_DECL_OVERRIDE; virtual const QFont *font(Font type) const Q_DECL_OVERRIDE; +#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON) + QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const Q_DECL_OVERRIDE; +#endif static const char *name; }; @@ -115,6 +118,9 @@ public: QString standardButtonText(int button) const Q_DECL_OVERRIDE; virtual QString gtkFontName() const; +#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON) + QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const Q_DECL_OVERRIDE; +#endif static const char *name; }; diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 05035a5b1e..8974ab549f 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -47,6 +47,7 @@ #include <QtGui/qscreen.h> #include <QtPlatformHeaders/qxcbwindowfunctions.h> +#include "QtPlatformSupport/private/qdbusmenuconnection_p.h" #ifdef XCB_USE_XLIB # include <X11/Xlib.h> @@ -82,8 +83,8 @@ static int resourceType(const QByteArray &key) QXcbNativeInterface::QXcbNativeInterface() : m_genericEventFilterType(QByteArrayLiteral("xcb_generic_event_t")), m_sysTraySelectionAtom(XCB_ATOM_NONE), - m_systrayVisualId(XCB_NONE) - + m_systrayVisualId(XCB_NONE), + m_dbusTrayConnection(Q_NULLPTR) { } diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index 1db2d1cf83..df3efb037c 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -47,6 +47,7 @@ class QWidget; class QXcbScreen; class QXcbConnection; class QXcbNativeInterfaceHandler; +class QDBusMenuConnection; class Q_XCB_EXPORT QXcbNativeInterface : public QPlatformNativeInterface { @@ -121,6 +122,7 @@ private: xcb_atom_t m_sysTraySelectionAtom; xcb_visualid_t m_systrayVisualId; + QDBusMenuConnection *m_dbusTrayConnection; static QXcbScreen *qPlatformScreenForWindow(QWindow *window); diff --git a/src/widgets/util/qsystemtrayicon.cpp b/src/widgets/util/qsystemtrayicon.cpp index 30ef7e82e5..f322b083fc 100644 --- a/src/widgets/util/qsystemtrayicon.cpp +++ b/src/widgets/util/qsystemtrayicon.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtWidgets module of the Qt Toolkit. @@ -69,8 +69,12 @@ QT_BEGIN_NAMESPACE \list \li All supported versions of Windows. - \li All window managers for X11 that implement the \l{freedesktop.org} system - tray specification, including recent versions of KDE and GNOME. + \li All window managers and independent tray implementations for X11 that implement the + \l{http://standards.freedesktop.org/systemtray-spec/systemtray-spec-0.2.html freedesktop.org} + XEmbed system tray specification. + \li All X11 desktop environments that implement the D-Bus + \l{http://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/ StatusNotifierItem} + specification, including recent versions of KDE and Unity. \li All supported versions of Mac OS X. Note that the Growl notification system must be installed for QSystemTrayIcon::showMessage() to display messages on Mac OS X prior to 10.8 (Mountain Lion). diff --git a/src/widgets/util/qsystemtrayicon_x11.cpp b/src/widgets/util/qsystemtrayicon_x11.cpp index ba80734876..13562ee27a 100644 --- a/src/widgets/util/qsystemtrayicon_x11.cpp +++ b/src/widgets/util/qsystemtrayicon_x11.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtWidgets module of the Qt Toolkit. @@ -344,8 +344,8 @@ void QSystemTrayIconPrivate::updateToolTip_sys() bool QSystemTrayIconPrivate::isSystemTrayAvailable_sys() { QScopedPointer<QPlatformSystemTrayIcon> sys(QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon()); - if (sys) - return sys->isSystemTrayAvailable(); + if (sys && sys->isSystemTrayAvailable()) + return true; // no QPlatformSystemTrayIcon so fall back to default xcb platform behavior const QString platform = QGuiApplication::platformName(); |