From 38abd653774aa0b3c5cdfd9a8b78619605230726 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 28 Nov 2014 09:20:19 +0100 Subject: QSystemTrayIcon uses D-Bus StatusNotifier on Linux when possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implementing org.kde.StatusNotifier DBus interface http://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/ as well as org.canonical.dbusmenu for the limited purpose of showing the tray icon's context menu. If a desktop environment (such as KDE or Unity) has a StatusNotifierWatcher listening, then tray icon information is sent to be displayed by the tray implementation instead of being rendered directly in an XEmbed window. This is necessary because some modern tray implementations no longer provide XEmbed "hosting". [ChangeLog][QPA][Xcb] QSystemTrayIcon uses StatusNotifier D-Bus protocol when the desktop environment supports it Task-number: QTBUG-31762 Done-with: Marco Martin Change-Id: I3b1f744d621eefc7e9c61d1469460ebfcc77fc54 Reviewed-by: Jørgen Lind Reviewed-by: Dmitry Shachnev --- src/platformsupport/dbusmenu/qdbusplatformmenu.cpp | 249 +++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 src/platformsupport/dbusmenu/qdbusplatformmenu.cpp (limited to 'src/platformsupport/dbusmenu/qdbusplatformmenu.cpp') 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 +#include + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(qLcMenu, "qt.qpa.menu") + +static int nextDBusID = 1; +QHash menusByID; +QHash menuItemsByID; + +QDBusPlatformMenuItem::QDBusPlatformMenuItem(quintptr tag) + : m_tag(tag ? tag : reinterpret_cast(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(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 QDBusPlatformMenuItem::byIds(const QList &ids) +{ + QList 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(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(menuItem); + QDBusPlatformMenuItem *beforeItem = static_cast(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(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(menuItem)); + qCDebug(qLcMenu) << updated; + emit propertiesUpdated(updated, removed); +} + +QDBusPlatformMenu *QDBusPlatformMenu::byId(int id) +{ + return menusByID[id]; +} + +QList 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 QDBusPlatformMenu::items() const +{ + return m_items; +} + +QPlatformMenuItem *QDBusPlatformMenu::createMenuItem() const +{ + QDBusPlatformMenuItem *ret = new QDBusPlatformMenuItem(); + ret->setMenu(const_cast(this)); + return ret; +} + +QT_END_NAMESPACE -- cgit v1.2.3