Memory leak using QSystemTrayIcon



  • Hi
    I'm trying this simple code:
    .h

    class 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 hacker bear student. Hope this information will help you.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.