Commit bc1c8514 authored by Konrad Materka's avatar Konrad Materka
Browse files

[KDEPlatformSystemTrayIcon] Recreate deleted menu

Summary:
Recreate internal menu when needed.
It is possible that internal representation of system tray menu is
deleted. This can happen when QSystemTrayIcon is hidden.

BUG: 365105

Test Plan: Unit tests included

Reviewers: apol, davidedmundson, #plasma, #frameworks, broulik, nicolasfella

Reviewed By: apol

Subscribers: plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D24843
parent 655fdfb6
......@@ -31,6 +31,9 @@ macro(FRAMEWORKINTEGRATION_TESTS _testname)
target_link_libraries(${_testname} Qt5::GuiPrivate Qt5::Test Qt5::DBus Qt5::X11Extras Qt5::QuickControls2 ${QT5PLATFORMSUPPORT_LIBS} KF5::ConfigWidgets KF5::ConfigCore KF5::IconThemes KF5::KIOFileWidgets KF5::I18n KF5::Notifications KF5::WindowSystem KF5::WaylandClient XCB::XCB)
endmacro()
set(dbus_interface)
qt5_add_dbus_interface(dbus_interface ../src/platformtheme/org.kde.StatusNotifierWatcher.xml statusnotifierwatcher_interface)
set(platformThemeSRCS
../src/platformtheme/qdbusmenubar.cpp # fork of Qt's qdbusmenubar with some added setters for our convenience
../src/platformtheme/kdeplatformtheme.cpp
......@@ -43,10 +46,9 @@ set(platformThemeSRCS
../src/platformtheme/kfiletreeview.cpp
../src/platformtheme/kwaylandintegration.cpp
../src/platformtheme/x11integration.cpp
${dbus_interface}
)
qt5_add_dbus_interface(platformThemeSRCS ../src/platformtheme/org.kde.StatusNotifierWatcher.xml statusnotifierwatcher_interface)
frameworkintegration_tests(
kdeplatformtheme_unittest
${platformThemeSRCS}
......@@ -65,6 +67,12 @@ frameworkintegration_tests(
ksni_unittest
)
frameworkintegration_tests(
kdeplatformsystemtrayicon_unittest
../src/platformtheme/kdeplatformsystemtrayicon.cpp
${dbus_interface}
)
frameworkintegration_tests(
kdirselectdialog_unittest
../src/platformtheme/kdeplatformfiledialogbase.cpp
......
/* This file is part of the KDE libraries
* Copyright 2019 Konrad Materka <materka@gmail.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License or ( at
* your option ) version 3 or, at the discretion of KDE e.V. ( which shall
* act as a proxy as in section 14 of the GPLv3 ), any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <QMenu>
#include <QSignalSpy>
#include <QTest>
#include "../src/platformtheme/kdeplatformsystemtrayicon.h"
class KDEPlatformSystemTrayIcon_UnitTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
// test for BUG 365105
void testMenuRecreate();
void testAddActionAfterMenuRecreate();
};
void KDEPlatformSystemTrayIcon_UnitTest::testMenuRecreate()
{
QMenu *trayIconMenu = new QMenu();
trayIconMenu->addAction("testAction");
KDEPlatformSystemTrayIcon *kpsti = new KDEPlatformSystemTrayIcon();
// simulates first QSystemTrayIcon::show()
kpsti->init();
SystemTrayMenu *ourMenu = qobject_cast<SystemTrayMenu*>(kpsti->createMenu());
trayIconMenu->setPlatformMenu(ourMenu);
kpsti->updateMenu(trayIconMenu->platformMenu());
QMenu *firstMenu = ourMenu->menu();
QSignalSpy menuDestroyedSpy(firstMenu, SIGNAL(destroyed()));
QCOMPARE(firstMenu->actions().size(), 1);
QCOMPARE(firstMenu->actions().first()->text(), "testAction");
// simulates QSystemTrayIcon::hide()
kpsti->cleanup();
// simulates second QSystemTrayIcon::show()
kpsti->init();
kpsti->updateMenu(trayIconMenu->platformMenu());
QMenu *recreatedMenu = ourMenu->menu();
QVERIFY(firstMenu != recreatedMenu);
QCOMPARE(recreatedMenu->actions().size(), 1);
QCOMPARE(recreatedMenu->actions().first()->text(), "testAction");
QCOMPARE(menuDestroyedSpy.count(), 1);
}
void KDEPlatformSystemTrayIcon_UnitTest::testAddActionAfterMenuRecreate()
{
QMenu *trayIconMenu = new QMenu();
trayIconMenu->addAction("testAction1");
KDEPlatformSystemTrayIcon *kpsti = new KDEPlatformSystemTrayIcon();
// simulates first QSystemTrayIcon::show()
kpsti->init();
SystemTrayMenu *ourMenu = qobject_cast<SystemTrayMenu*>(kpsti->createMenu());
trayIconMenu->setPlatformMenu(ourMenu);
kpsti->updateMenu(trayIconMenu->platformMenu());
QMenu *firstMenu = ourMenu->menu();
QSignalSpy menuDestroyedSpy(firstMenu, SIGNAL(destroyed()));
QCOMPARE(firstMenu->actions().size(), 1);
QCOMPARE(firstMenu->actions().first()->text(), "testAction1");
// simulates QSystemTrayIcon::hide()
kpsti->cleanup();
// add action, internal menu is destroyed
trayIconMenu->addAction("testAction2");
// simulates second QSystemTrayIcon::show()
kpsti->init();
kpsti->updateMenu(trayIconMenu->platformMenu());
QMenu *recreatedMenu = ourMenu->menu();
QVERIFY(firstMenu != recreatedMenu);
QCOMPARE(recreatedMenu->actions().size(), 2);
QCOMPARE(recreatedMenu->actions().first()->text(), "testAction1");
QCOMPARE(recreatedMenu->actions().last()->text(), "testAction2");
QCOMPARE(menuDestroyedSpy.count(), 1);
}
QTEST_MAIN(KDEPlatformSystemTrayIcon_UnitTest)
#include "kdeplatformsystemtrayicon_unittest.moc"
......@@ -29,11 +29,11 @@
SystemTrayMenu::SystemTrayMenu()
: QPlatformMenu()
, m_enabled(true)
, m_visible(true)
, m_separatorsCollapsible(true)
, m_tag(0)
, m_menu(new QMenu())
{
connect(m_menu.data(), &QMenu::aboutToShow, this, &QPlatformMenu::aboutToShow);
connect(m_menu.data(), &QMenu::aboutToHide, this, &QPlatformMenu::aboutToHide);
}
SystemTrayMenu::~SystemTrayMenu()
......@@ -109,18 +109,18 @@ void SystemTrayMenu::removeMenuItem(QPlatformMenuItem *menuItem)
void SystemTrayMenu::setEnabled(bool enabled)
{
if (!m_menu) {
return;
m_enabled = enabled;
if (m_menu) {
m_menu->setEnabled(enabled);
}
m_menu->setEnabled(enabled);
}
void SystemTrayMenu::setIcon(const QIcon &icon)
{
if (!m_menu) {
return;
m_icon = icon;
if (m_menu) {
m_menu->setIcon(icon);
}
m_menu->setIcon(icon);
}
void SystemTrayMenu::setTag(quintptr tag)
......@@ -130,18 +130,18 @@ void SystemTrayMenu::setTag(quintptr tag)
void SystemTrayMenu::setText(const QString &text)
{
if (!m_menu) {
return;
m_text = text;
if (m_menu) {
m_menu->setTitle(text);
}
m_menu->setTitle(text);
}
void SystemTrayMenu::setVisible(bool visible)
{
if (!m_menu) {
return;
m_visible = visible;
if (m_menu) {
m_menu->setVisible(visible);
}
m_menu->setVisible(visible);
}
void SystemTrayMenu::syncMenuItem(QPlatformMenuItem *menuItem)
......@@ -152,10 +152,10 @@ void SystemTrayMenu::syncMenuItem(QPlatformMenuItem *menuItem)
void SystemTrayMenu::syncSeparatorsCollapsible(bool enable)
{
if (!m_menu) {
return;
m_separatorsCollapsible = enable;
if (m_menu) {
m_menu->setSeparatorsCollapsible(enable);
}
m_menu->setSeparatorsCollapsible(enable);
}
quintptr SystemTrayMenu::tag() const
......@@ -163,9 +163,28 @@ quintptr SystemTrayMenu::tag() const
return m_tag;
}
QMenu *SystemTrayMenu::menu() const
QMenu *SystemTrayMenu::menu()
{
return m_menu.data();
if (!m_menu) {
createMenu();
}
return m_menu;
}
void SystemTrayMenu::createMenu()
{
m_menu = new QMenu();
connect(m_menu, &QMenu::aboutToShow, this, &QPlatformMenu::aboutToShow);
connect(m_menu, &QMenu::aboutToHide, this, &QPlatformMenu::aboutToHide);
m_menu->setEnabled(m_enabled);
m_menu->setIcon(m_icon);
m_menu->setTitle(m_text);
m_menu->setVisible(m_visible);
m_menu->setSeparatorsCollapsible(m_separatorsCollapsible);
for (auto item : m_items) {
m_menu->addAction(item->action());
}
}
SystemTrayMenuItem::SystemTrayMenuItem()
......@@ -245,7 +264,7 @@ void SystemTrayMenuItem::setVisible(bool isVisible)
void SystemTrayMenuItem::setIconSize(int size)
{
Q_UNUSED(size);
Q_UNUSED(size)
}
void SystemTrayMenuItem::setHasExclusiveGroup(bool hasExclusiveGroup)
......
......@@ -49,9 +49,16 @@ public:
QPlatformMenuItem *createMenuItem() const override;
QPlatformMenu *createSubMenu() const override;
QMenu *menu() const;
QMenu *menu();
private:
void createMenu();
QString m_text;
QIcon m_icon;
bool m_enabled;
bool m_visible;
bool m_separatorsCollapsible;
quintptr m_tag;
QPointer<QMenu> m_menu;
QList<SystemTrayMenuItem*> m_items;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment