From d8bfd812c3383e24196588f5d3e1de4719fcac02 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 19 May 2015 12:36:55 +0200 Subject: D-Bus system tray icon: submenus can be created after context menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QMenuPrivate::init() calls QPlatformTheme::createPlatformMenu() to create a platform menu, but on Linux, that returns null for now. QSystemTrayIcon::setContextMenu() results in recursive calls to QSystemTrayIconPrivate::addPlatformMenu() which then calls QDBusTrayIcon::createMenu() for the context menu and each submenu. However if a submenu is added afterwards, a corresponding platform menu is not immediately created. Now copyActionToPlatformItem() will detect and create the missing platform submenu, by calling a new method: DBusPlatformMenu::createSubMenu(). This is because there is no way of knowing that it's a tray-specific context menu (which is so far the only case in which we use DBusPlatformMenu). So, QPlatformMenu::createSubMenu() needs to exist as a new QPA interface for this use case. Task-number: QTBUG-45803 Change-Id: Ib319e873082196515ea0580d70d069099cf2c175 Reviewed-by: Jørgen Lind --- src/gui/kernel/qplatformmenu.cpp | 5 +++++ src/gui/kernel/qplatformmenu.h | 1 + src/platformsupport/dbusmenu/qdbusplatformmenu.cpp | 9 ++++++++- src/platformsupport/dbusmenu/qdbusplatformmenu_p.h | 4 +++- src/widgets/widgets/qmenu.cpp | 12 +++++++----- 5 files changed, 24 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/gui/kernel/qplatformmenu.cpp b/src/gui/kernel/qplatformmenu.cpp index cb311b8d13..da65381931 100644 --- a/src/gui/kernel/qplatformmenu.cpp +++ b/src/gui/kernel/qplatformmenu.cpp @@ -44,4 +44,9 @@ QPlatformMenuItem *QPlatformMenu::createMenuItem() const return QGuiApplicationPrivate::platformTheme()->createPlatformMenuItem(); } +QPlatformMenu *QPlatformMenu::createSubMenu() const +{ + return QGuiApplicationPrivate::platformTheme()->createPlatformMenu(); +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformmenu.h b/src/gui/kernel/qplatformmenu.h index baa1e460d7..1022d0ed4a 100644 --- a/src/gui/kernel/qplatformmenu.h +++ b/src/gui/kernel/qplatformmenu.h @@ -123,6 +123,7 @@ public: virtual QPlatformMenuItem *menuItemForTag(quintptr tag) const = 0; virtual QPlatformMenuItem *createMenuItem() const; + virtual QPlatformMenu *createSubMenu() const; Q_SIGNALS: void aboutToShow(); void aboutToHide(); diff --git a/src/platformsupport/dbusmenu/qdbusplatformmenu.cpp b/src/platformsupport/dbusmenu/qdbusplatformmenu.cpp index 93c822cefb..a64e107e71 100644 --- a/src/platformsupport/dbusmenu/qdbusplatformmenu.cpp +++ b/src/platformsupport/dbusmenu/qdbusplatformmenu.cpp @@ -75,6 +75,9 @@ void QDBusPlatformMenuItem::setIcon(const QIcon &icon) m_icon = icon; } +/*! + Set a submenu under this menu item. +*/ void QDBusPlatformMenuItem::setMenu(QPlatformMenu *menu) { m_subMenu = static_cast(menu); @@ -242,8 +245,12 @@ const QList QDBusPlatformMenu::items() const QPlatformMenuItem *QDBusPlatformMenu::createMenuItem() const { QDBusPlatformMenuItem *ret = new QDBusPlatformMenuItem(); - ret->setMenu(const_cast(this)); return ret; } +QPlatformMenu *QDBusPlatformMenu::createSubMenu() const +{ + return new QDBusPlatformMenu; +} + QT_END_NAMESPACE diff --git a/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h b/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h index 2519533e32..16bb4f195c 100644 --- a/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h +++ b/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h @@ -124,7 +124,7 @@ public: quintptr tag()const Q_DECL_OVERRIDE { return m_tag; } void setTag(quintptr tag) Q_DECL_OVERRIDE; - const QString text() { return m_text; } + const QString text() const { 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; @@ -150,6 +150,7 @@ public: const QList items() const; QPlatformMenuItem *createMenuItem() const Q_DECL_OVERRIDE; + QPlatformMenu *createSubMenu() const Q_DECL_OVERRIDE; bool operator==(const QDBusPlatformMenu& other) { return m_tag == other.m_tag; } @@ -175,6 +176,7 @@ private: uint m_revision; QHash m_itemsByTag; QList m_items; + QDBusPlatformMenuItem *m_containingMenuItem; static QList m_topLevelMenus; }; diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 1749f9d8c7..2f0dcc49d1 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -183,7 +183,7 @@ void QMenuPrivate::setPlatformMenu(QPlatformMenu *menu) } // forward declare function -static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem* item); +static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item, QPlatformMenu *itemsMenu); void QMenuPrivate::syncPlatformMenu() { @@ -200,7 +200,7 @@ void QMenuPrivate::syncPlatformMenu() menuItem->setTag(reinterpret_cast(action)); QObject::connect(menuItem, SIGNAL(activated()), action, SLOT(trigger()), Qt::QueuedConnection); QObject::connect(menuItem, SIGNAL(hovered()), action, SIGNAL(hovered()), Qt::QueuedConnection); - copyActionToPlatformItem(action, menuItem); + copyActionToPlatformItem(action, menuItem, platformMenu.data()); platformMenu->insertMenuItem(menuItem, beforeItem); beforeItem = menuItem; } @@ -3105,7 +3105,7 @@ QMenu::timerEvent(QTimerEvent *e) } } -static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem* item) +static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item, QPlatformMenu *itemsMenu) { item->setText(action->text()); item->setIsSeparator(action->isSeparator()); @@ -3131,6 +3131,8 @@ static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem* i item->setEnabled(action->isEnabled()); if (action->menu()) { + if (!action->menu()->platformMenu()) + action->menu()->setPlatformMenu(itemsMenu->createSubMenu()); item->setMenu(action->menu()->platformMenu()); } else { item->setMenu(0); @@ -3185,7 +3187,7 @@ void QMenu::actionEvent(QActionEvent *e) menuItem->setTag(reinterpret_cast(e->action())); QObject::connect(menuItem, SIGNAL(activated()), e->action(), SLOT(trigger())); QObject::connect(menuItem, SIGNAL(hovered()), e->action(), SIGNAL(hovered())); - copyActionToPlatformItem(e->action(), menuItem); + copyActionToPlatformItem(e->action(), menuItem, d->platformMenu); QPlatformMenuItem* beforeItem = d->platformMenu->menuItemForTag(reinterpret_cast(e->before())); d->platformMenu->insertMenuItem(menuItem, beforeItem); } else if (e->type() == QEvent::ActionRemoved) { @@ -3195,7 +3197,7 @@ void QMenu::actionEvent(QActionEvent *e) } else if (e->type() == QEvent::ActionChanged) { QPlatformMenuItem *menuItem = d->platformMenu->menuItemForTag(reinterpret_cast(e->action())); if (menuItem) { - copyActionToPlatformItem(e->action(), menuItem); + copyActionToPlatformItem(e->action(), menuItem, d->platformMenu); d->platformMenu->syncMenuItem(menuItem); } } -- cgit v1.2.3