summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/dbus-ifaces/org.kde.StatusNotifierItem.xml96
-rw-r--r--src/platformsupport/dbusmenu/dbusmenu.pri15
-rw-r--r--src/platformsupport/dbusmenu/qdbusmenuadaptor.cpp132
-rw-r--r--src/platformsupport/dbusmenu/qdbusmenuadaptor_p.h162
-rw-r--r--src/platformsupport/dbusmenu/qdbusmenuconnection.cpp127
-rw-r--r--src/platformsupport/dbusmenu/qdbusmenuconnection_p.h88
-rw-r--r--src/platformsupport/dbusmenu/qdbusmenutypes.cpp257
-rw-r--r--src/platformsupport/dbusmenu/qdbusmenutypes_p.h127
-rw-r--r--src/platformsupport/dbusmenu/qdbusplatformmenu.cpp249
-rw-r--r--src/platformsupport/dbusmenu/qdbusplatformmenu_p.h181
-rw-r--r--src/platformsupport/dbustray/dbustray.pri13
-rw-r--r--src/platformsupport/dbustray/qdbustrayicon.cpp260
-rw-r--r--src/platformsupport/dbustray/qdbustrayicon_p.h160
-rw-r--r--src/platformsupport/dbustray/qdbustraytypes.cpp37
-rw-r--r--src/platformsupport/dbustray/qdbustraytypes_p.h13
-rw-r--r--src/platformsupport/dbustray/qstatusnotifieritemadaptor.cpp174
-rw-r--r--src/platformsupport/dbustray/qstatusnotifieritemadaptor_p.h185
-rw-r--r--src/platformsupport/platformsupport.pro4
-rw-r--r--src/platformsupport/themes/genericunix/qgenericunixthemes.cpp38
-rw-r--r--src/platformsupport/themes/genericunix/qgenericunixthemes_p.h8
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.cpp7
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.h4
-rw-r--r--src/widgets/util/qsystemtrayicon.cpp10
-rw-r--r--src/widgets/util/qsystemtrayicon_x11.cpp6
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&lt;int&gt;\" 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&lt;QDBusMenuEvent&gt;\" name=\"org.qtproject.QtDBus.QtTypeName.In0\"/>\n"
+" <annotation value=\"QList&lt;int&gt;\" 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&lt;int&gt;\" name=\"org.qtproject.QtDBus.QtTypeName.In0\"/>\n"
+" <annotation value=\"QList&lt;int&gt;\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+" <annotation value=\"QList&lt;int&gt;\" 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();