diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -31,6 +31,9 @@ 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 @@ ../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 @@ ksni_unittest ) +frameworkintegration_tests( + kdeplatformsystemtrayicon_unittest + ../src/platformtheme/kdeplatformsystemtrayicon.cpp + ${dbus_interface} +) + frameworkintegration_tests( kdirselectdialog_unittest ../src/platformtheme/kdeplatformfiledialogbase.cpp diff --git a/autotests/kdeplatformsystemtrayicon_unittest.cpp b/autotests/kdeplatformsystemtrayicon_unittest.cpp new file mode 100644 --- /dev/null +++ b/autotests/kdeplatformsystemtrayicon_unittest.cpp @@ -0,0 +1,106 @@ +/* This file is part of the KDE libraries + * Copyright 2019 Konrad Materka + * + * 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 +#include +#include + +#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(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(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" diff --git a/src/platformtheme/kdeplatformsystemtrayicon.h b/src/platformtheme/kdeplatformsystemtrayicon.h --- a/src/platformtheme/kdeplatformsystemtrayicon.h +++ b/src/platformtheme/kdeplatformsystemtrayicon.h @@ -49,9 +49,16 @@ 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 m_menu; QList m_items; diff --git a/src/platformtheme/kdeplatformsystemtrayicon.cpp b/src/platformtheme/kdeplatformsystemtrayicon.cpp --- a/src/platformtheme/kdeplatformsystemtrayicon.cpp +++ b/src/platformtheme/kdeplatformsystemtrayicon.cpp @@ -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::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::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,20 +152,39 @@ 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 { 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::setIconSize(int size) { - Q_UNUSED(size); + Q_UNUSED(size) } void SystemTrayMenuItem::setHasExclusiveGroup(bool hasExclusiveGroup)