SUMMARY Application closes when deleting QSystemTrayIcon in Linux Plasma 6 STEPS TO REPRODUCE 1. Create and show QSystemTrayIcon instance 2. delete QSystemTrayIcon instance (e.g. when disabled in app settings) OBSERVED RESULT app closes itself EXPECTED RESULT app continue working w/o system tray icon SOFTWARE/OS VERSIONS KDE Plasma Version: 6.0.2 Qt Version: 6.6.2 ADDITIONAL INFORMATION App works as expected when run w/o KDEPlasmaPlatformTheme6.so loaded. Ref.: https://github.com/qbittorrent/qBittorrent/issues/20604
This has the same root cause as https://bugs.kde.org/show_bug.cgi?id=483757 The system tray implementation uses QEventLoopLocker internally, which triggers this behavior. Because of a behavior change in Qt6 the application needs to set QCoreApplication::setQuitLockEnabled(false)
>Because of a behavior change in Qt6 the application needs to set QCoreApplication::setQuitLockEnabled(false) Could you please specify in more detail what exactly has been changed in Qt? Is QEventLoopLocker intended to quit the application if there are open windows?
I think I figured it out. Previously, `QCoreApplication::setQuitLockEnabled(false)` was implicitly set by `QGuiApplication::setQuitOnLastWindowClosed(false)`. I wonder if this was mentioned somewhere in the documentation? I didn't find it. Anyway, I don't think it's a good idea to use something like `QEventLoopLocker` at "platform theme" level.
This issue affects Telegram Desktop and qBittorrent: when disabling tray icon in settings app instantly closes. And when the icon is disabled its impossible to use file dialogs: app abruptly closes when selecting any file or closing file dialog. Below there is my MRE. Without setQuitOnLastWindowClosed(false) line all woks fine. But when you uncomment it and try to open file dialog (with disabled icon) app closes. But if you start with setQuitOnLastWindowClosed(false) and trayIcon->show() enabled the dialog works fine. main.cpp: ``` #include <QApplication> #include <QMessageBox> #include "Window.hpp" int main(int argc, char *argv[]) { const auto app = QApplication(argc, argv); /* QApplication::setQuitOnLastWindowClosed(false); */ Window window; window.show(); return app.exec(); } ``` Window.hpp: ``` #pragma once #include <QApplication> #include <QCheckBox> #include <QDialog> #include <QFileDialog> #include <QPushButton> #include <QStyle> #include <QSystemTrayIcon> #include <QVBoxLayout> class Window : public QDialog { Q_OBJECT QCheckBox *showIconCheckBox; QSystemTrayIcon *trayIcon; QPushButton *button; public: Window() { showIconCheckBox = new QCheckBox("Show icon"); button = new QPushButton("Show dialog"); connect(button, &QAbstractButton::clicked, this, [] { const auto fname = QFileDialog::getOpenFileName(); qInfo() << fname; }); const auto mainLayout = new QVBoxLayout; mainLayout->addWidget(showIconCheckBox); mainLayout->addWidget(button); setLayout(mainLayout); trayIcon = new QSystemTrayIcon(this); trayIcon->setIcon( QApplication::style()->standardIcon(QStyle::SP_TabCloseButton)); /* trayIcon->show(); */ showIconCheckBox->setChecked(trayIcon->isVisible()); connect(showIconCheckBox, &QAbstractButton::toggled, trayIcon, &QSystemTrayIcon::setVisible); } }; ``` meson.build: ``` project( 'test-tray-icon', 'cpp', default_options: ['cpp_std=c++20']) qt6_mod = import('qt6') qt6_dep = dependency('qt6', modules: ['Core','Gui', 'Widgets']) processed = qt6_mod.preprocess( moc_headers : 'Window.hpp', ) executable('a', ['main.cpp', processed], dependencies: qt6_dep) ``` Alternative CMakeLists.txt: ``` cmake_minimum_required(VERSION 3.16) project(test-tray-icon LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets) qt_standard_project_setup() qt_add_executable(a main.cpp Window.hpp) target_link_libraries(a PRIVATE Qt6::Core Qt6::Gui Qt6::Widgets) ```
// Ensure that closing the last KMainWindow doesn't exit the application // if a system tray icon is still present. QEventLoopLocker eventLoopLocker; One could argue it's not on the implementation to make sure apps dont quit when windows are closed. I couldn't find Qt documentation tthat QSystemTrayIcon would do that automatically either if that is required nor does KStatusNotifierItem. However changing that behavior seems like a behavior change as well...
But given that there was a Qt6 behavior change that causes problems I would be in favour of removing this. It's the apps job to not close and the correct thing is probably quitOnLastWindowClosed anyways.
I believe that the "platform theme" should be considered exactly as an extension of the Qt implementation. Therefore, it is completely unacceptable for it to make Qt's behavior so incorrect and unpredictable. The application should base its logic only on the Qt interface. And it is certainly not declared by its interface that the application can terminate when some dialog or system tray icon is closed.
I totally agree: whether a kde dialog or a plain qt dialog is used should only change its look & feel, but not its behavior (especially if it is just a QFileDialog in code). I commented here https://bugs.kde.org/show_bug.cgi?id=483439#c14 and it was already mentioned here https://bugs.kde.org/show_bug.cgi?id=471941. But nothing happened.
This is fixed with https://codereview.qt-project.org/c/qt/qtbase/+/556573