Unsolved Memory leak using QSystemTrayIcon
-
Hi
I'm trying this simple code:
.hclass MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); };
.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { if(QSystemTrayIcon::isSystemTrayAvailable()) { QSystemTrayIcon* trayIcon = new QSystemTrayIcon(this); trayIcon->setIcon(this->windowIcon()); QMenu* contextMenu = new QMenu(this); contextMenu->addAction("Quit", this, SLOT(close())); trayIcon->setContextMenu(contextMenu); trayIcon->show(); } }
main.cpp
int main(int argc, char *argv[]) { QApplication app(argc, argv); QIcon appIcon(":/icons/app.svg"); app.setWindowIcon(appIcon); MainWindow w; w.show(); return app.exec(); }
Analyzing by valgrind form within Qt Creator, I get:
4 bytes in 1 blocks are indirectly lost in loss record 33 of 6,632
4 bytes in 1 blocks are indirectly lost in loss record 34 of 6,632
64 bytes in 1 blocks are still reachable in loss record 4,289 of 6,632
522 (64 direct, 458 indirect) bytes in 1 blocks are definitely lost in loss record 6,396 of 6,632(pointing to the line
trayIcon->setContextMenu(contextMenu);
)
If I comment out the line with setContextMenu() call, there are no leaks shown.What am i doing wrong?
-
It seems the reason is not of QSystemTrayIcon, but of creating actions method. Rewrote .cpp for better look:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QAction* quitAction = new QAction(tr("&Quit"), this); connect(quitAction, &QAction::triggered, qApp, &QApplication::quit); QMenu* contextMenu = new QMenu("Menu", this); contextMenu->addAction(quitAction); QSystemTrayIcon* trayIcon = new QSystemTrayIcon(this); trayIcon->setIcon(this->windowIcon()); trayIcon->setContextMenu(contextMenu); trayIcon->show(); }
In that case valgrind shows no memory leaks. But if I write
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QMenu* contextMenu = new QMenu("Menu", this); contextMenu->addAction("Quit", qApp, &QApplication::quit); QSystemTrayIcon* trayIcon = new QSystemTrayIcon(this); trayIcon->setIcon(this->windowIcon()); trayIcon->setContextMenu(contextMenu); trayIcon->show(); }
valgrind shows same leaks again.
In that (second) case, doesn't QAction instance destroyed when QMenu does? -
The same leak is reported if QMenu instance created before QAction, like in this code:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QMenu* contextMenu = new QMenu("Menu", this); QAction* quitAction = new QAction(tr("&Quit"), this); connect(quitAction, &QAction::triggered, qApp, &QApplication::quit); contextMenu->addAction(quitAction); QSystemTrayIcon* trayIcon = new QSystemTrayIcon(this); trayIcon->setIcon(this->windowIcon()); trayIcon->setContextMenu(contextMenu); trayIcon->show(); }
I just can not understand, is it a bug, or my incompetence, or ...
-
i have the same problem but dont have a solution)
Upd:
Hello again, i found solution. You need to call setContextMenu() BEFORE any addAction(), so your code from last example must look like:MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QMenu* contextMenu = new QMenu("Menu", this); QSystemTrayIcon* trayIcon = new QSystemTrayIcon(this); trayIcon->setIcon(this->windowIcon()); trayIcon->setContextMenu(contextMenu); // <--- QAction* quitAction = new QAction(tr("&Quit"), this); connect(quitAction, &QAction::triggered, qApp, &QApplication::quit); contextMenu->addAction(quitAction); // <--- trayIcon->show(); }
Why did it happens?
I'm looked into source code of QSystemTrayIcon (qtbase/src/widgets/util/qsystemtrayicon.cpp) and see this:void QSystemTrayIcon::setContextMenu(QMenu *menu) { Q_D(QSystemTrayIcon); d->menu = menu; d->updateMenu_sys(); }
And i think d->updateMenu_sys() is a problem. If QMenu have actions when you call setContextMenu you get copies without ownership (or you lost ownership from existing actions). And that leads to memory leak.
P.S. sorry for my poor english, i'm just a russian
hackerbearstudent. Hope this information will help you.