QSystemTrayIcon hide() crash on mac while I use QTimer to change the icon of QSystemTrayIcon



  • I want the systemTrayIcon to change the icon every 500ms , so I use QTimer and in timeout() signal's slot function , I change the icon of
    systemTrayIcon like this

    @
    void MainWidget::flashing()
    {
    fIndex++;
    if(fIndex == fMaxFlashingNumber){ //fMaxFlashingNumber is 20
    fSystemTrayTimer->stop(); //fSystemTrayTimer is QTimer
    fSystemTrayIcon->setIcon(fIcon); //fIcon is defined before
    }else {
    if(fIndex %2 ==0){
    fSystemTrayIcon->setIcon(fIcon);
    }else {
    fSystemTrayIcon->setIcon(QIcon("images/butterfly.png"));
    }
    }
    }
    @

    when the systemTrayIcon is triggered , I want to hide the systemTrayIcon , I call

    @
    fSystemTrayTimer->stop() ;
    fSystemTrayIcon->hide();
    @

    it will crash on mac , it works well on windows , I don't know why . If I don't use QTimer , it won't crash .
    and also another problem , when I call

    @fSystemTrayIcon->setIcon(QIcon()); @

    to set the icon empty , it will
    showing nothing on windows, while it still show the original icon on mac , why it can't work , strange problem .

    [EDIT: code formatting, Volker]



  • here is the crash information:
    Interval Since Last Report: 7802367 sec
    Crashes Since Last Report: 83
    Per-App Interval Since Last Report: 944 sec
    Per-App Crashes Since Last Report: 16
    Anonymous UUID: A2CE6324-1143-4A63-9F98-BB0933D1C757

    Exception Type: EXC_BAD_ACCESS (SIGBUS)
    Exception Codes: KERN_PROTECTION_FAILURE at 0x000000000000002b
    Crashed Thread: 0 Dispatch queue: com.apple.main-thread

    Application Specific Information:
    objc_msgSend() selector name: item

    Thread 0 Crashed: Dispatch queue: com.apple.main-thread
    0 libobjc.A.dylib 0x99596ed7 objc_msgSend + 23
    1 QtGui 0x00b86f16 -[QNSImageView mousePressed:button:] + 198
    2 QtGui 0x00b86531 -[QNSImageView mouseDown:] + 49
    3 com.apple.AppKit 0x92936c68 -[NSWindow sendEvent:] + 5549
    4 com.apple.AppKit 0x92d74169 -[NSStatusBarWindow sendEvent:] + 82
    5 com.apple.AppKit 0x92eaa0ca carbonAppWindowMouseHandler + 261
    6 com.apple.AppKit 0x92eab4a0 carbonAppWindowHandler + 131
    7 com.apple.HIToolbox 0x9727ac2f DispatchEventToHandlers(EventTargetRec*, OpaqueEventRef*, HandlerCallRec*) + 1567
    8 com.apple.HIToolbox 0x97279ef6 SendEventToEventTargetInternal(OpaqueEventRef*, OpaqueEventTargetRef*, HandlerCallRec*) + 411
    9 com.apple.HIToolbox 0x9729c7f3 SendEventToEventTarget + 52
    10 com.apple.HIToolbox 0x972ae34f ToolboxEventDispatcherHandler(OpaqueEventHandlerCallRef*, OpaqueEventRef*, void*) + 1257
    11 com.apple.HIToolbox 0x9727b080 DispatchEventToHandlers(EventTargetRec*, OpaqueEventRef*, HandlerCallRec*) + 2672
    12 com.apple.HIToolbox 0x97279ef6 SendEventToEventTargetInternal(OpaqueEventRef*, OpaqueEventTargetRef*, HandlerCallRec*) + 411
    13 com.apple.HIToolbox 0x9729c7f3 SendEventToEventTarget + 52
    14 QtGui 0x00b3c854 QEventDispatcherMac::processEvents(QFlagsQEventLoop::ProcessEventsFlag) + 596
    15 QtCore 0x009092a1 QEventLoop::processEvents(QFlagsQEventLoop::ProcessEventsFlag) + 65
    16 QtCore 0x009094dd QEventLoop::exec(QFlagsQEventLoop::ProcessEventsFlag) + 189
    17 QtCore 0x0090b80e QCoreApplication::exec() + 174
    18 com.yourcompany.demo 0x00005149 main + 75 (main.cpp:7)
    19 com.yourcompany.demo 0x00004b19 _start + 208
    20 com.yourcompany.demo 0x00004a48 start + 40



  • this is also tested in qtdemo's systray example , see the code I modified with timer
    window.h

    **
    ****************************************************************************/
    @
    #ifndef WINDOW_H
    #define WINDOW_H

    #include <QSystemTrayIcon>
    #include <QDialog>

    QT_BEGIN_NAMESPACE
    class QAction;
    class QCheckBox;
    class QComboBox;
    class QGroupBox;
    class QLabel;
    class QLineEdit;
    class QMenu;
    class QPushButton;
    class QSpinBox;
    class QTextEdit;
    QT_END_NAMESPACE

    //! [0]
    class Window : public QDialog
    {
    Q_OBJECT

    public:
    Window();

    void setVisible(bool visible);
    

    protected:
    void closeEvent(QCloseEvent *event);

    private slots:
    void setIcon(int index);
    void iconActivated(QSystemTrayIcon::ActivationReason reason);
    void showMessage();
    void messageClicked();

    void startFlashing();
    void stopFlashing();
    protected:
    virtual void timerEvent(QTimerEvent *ev);

    private:
    int fTimerID;
    int fIndex;
    private:
    void createIconGroupBox();
    void createMessageGroupBox();
    void createActions();
    void createTrayIcon();

    QGroupBox *iconGroupBox;
    QLabel *iconLabel;
    QComboBox *iconComboBox;
    QCheckBox *showIconCheckBox;
    
    QGroupBox *messageGroupBox;
    QLabel *typeLabel;
    QLabel *durationLabel;
    QLabel *durationWarningLabel;
    QLabel *titleLabel;
    QLabel *bodyLabel;
    QComboBox *typeComboBox;
    QSpinBox *durationSpinBox;
    QLineEdit *titleEdit;
    QTextEdit *bodyEdit;
    QPushButton *showMessageButton;
    
    QAction *minimizeAction;
    QAction *maximizeAction;
    QAction *restoreAction;
    QAction *quitAction;
    
    QSystemTrayIcon *trayIcon;
    QMenu *trayIconMenu;
    

    };
    //! [0]

    #endif
    @



  • window.cpp

    **
    ****************************************************************************/
    @
    #include <QtGui>

    #include "window.h"

    //! [0]
    Window::Window()
    {
    createIconGroupBox();
    createMessageGroupBox();

    iconLabel->setMinimumWidth(durationLabel->sizeHint().width());
    
    createActions();
    createTrayIcon();
    
    connect(showMessageButton, SIGNAL(clicked()), this, SLOT(showMessage()));
    connect(showIconCheckBox, SIGNAL(toggled(bool)),
            trayIcon, SLOT(setVisible(bool)));
    connect(iconComboBox, SIGNAL(currentIndexChanged(int)),
            this, SLOT(setIcon(int)));
    connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked()));
    connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
            this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
    
    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(iconGroupBox);
    mainLayout->addWidget(messageGroupBox);
    setLayout(mainLayout);
    
    iconComboBox->setCurrentIndex(1);
    trayIcon->show();
    
    setWindowTitle(tr("Systray"));
    resize(400, 300);
    

    }
    //! [0]

    //! [1]
    void Window::setVisible(bool visible)
    {
    minimizeAction->setEnabled(visible);
    maximizeAction->setEnabled(!isMaximized());
    restoreAction->setEnabled(isMaximized() || !visible);
    QDialog::setVisible(visible);
    }
    //! [1]

    //! [2]
    void Window::closeEvent(QCloseEvent *event)
    {
    if (trayIcon->isVisible()) {
    QMessageBox::information(this, tr("Systray"),
    tr("The program will keep running in the "
    "system tray. To terminate the program, "
    "choose <b>Quit</b> in the context menu "
    "of the system tray entry."));
    hide();
    event->ignore();
    }
    }
    //! [2]

    void Window::startFlashing()
    {
    trayIcon->show();
    fTimerID = startTimer(500);

    }
    void Window::stopFlashing()
    {
    killTimer(fTimerID);
    trayIcon->hide();
    }
    void Window::timerEvent(QTimerEvent *ev)
    {
    fIndex++;
    if(fIndex%2 ==0){
    trayIcon->setIcon(iconComboBox->itemIcon(0));
    }else
    trayIcon->setIcon(iconComboBox->itemIcon(1));
    }

    //! [3]
    void Window::setIcon(int index)
    {
    QIcon icon = iconComboBox->itemIcon(index);
    trayIcon->setIcon(icon);
    setWindowIcon(icon);

    trayIcon->setToolTip(iconComboBox->itemText(index));
    

    }
    //! [3]

    //! [4]
    void Window::iconActivated(QSystemTrayIcon::ActivationReason reason)
    {
    switch (reason) {
    case QSystemTrayIcon::Trigger:
    stopFlashing();
    break;
    case QSystemTrayIcon::DoubleClick:
    iconComboBox->setCurrentIndex((iconComboBox->currentIndex() + 1)
    % iconComboBox->count());
    break;
    case QSystemTrayIcon::MiddleClick:
    showMessage();
    break;
    default:
    ;
    }
    }
    //! [4]

    //! [5]
    void Window::showMessage()
    {
    QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::MessageIcon(
    typeComboBox->itemData(typeComboBox->currentIndex()).toInt());
    trayIcon->showMessage(titleEdit->text(), bodyEdit->toPlainText(), icon,
    durationSpinBox->value() * 1000);
    //trayIcon->hide();
    startFlashing();
    }
    //! [5]

    @



  • //! [6]
    @
    void Window::messageClicked()
    {
    QMessageBox::information(0, tr("Systray"),
    tr("Sorry, I already gave what help I could.n"
    "Maybe you should try asking a human?"));
    }
    //! [6]

    void Window::createIconGroupBox()
    {
    iconGroupBox = new QGroupBox(tr("Tray Icon"));

    iconLabel = new QLabel("Icon:");
    
    iconComboBox = new QComboBox;
    iconComboBox->addItem(QIcon(":/images/bad.svg"), tr("Bad"));
    iconComboBox->addItem(QIcon(":/images/heart.svg"), tr("Heart"));
    iconComboBox->addItem(QIcon(":/images/trash.svg"), tr("Trash"));
    
    showIconCheckBox = new QCheckBox(tr("Show icon"));
    showIconCheckBox->setChecked(true);
    
    QHBoxLayout *iconLayout = new QHBoxLayout;
    iconLayout->addWidget(iconLabel);
    iconLayout->addWidget(iconComboBox);
    iconLayout->addStretch();
    iconLayout->addWidget(showIconCheckBox);
    iconGroupBox->setLayout(iconLayout);
    

    }

    void Window::createMessageGroupBox()
    {
    messageGroupBox = new QGroupBox(tr("Balloon Message"));

    typeLabel = new QLabel(tr("Type:"));
    
    typeComboBox = new QComboBox;
    typeComboBox->addItem(tr("None"), QSystemTrayIcon::NoIcon);
    typeComboBox->addItem(style()->standardIcon(
            QStyle::SP_MessageBoxInformation), tr("Information"),
            QSystemTrayIcon::Information);
    typeComboBox->addItem(style()->standardIcon(
            QStyle::SP_MessageBoxWarning), tr("Warning"),
            QSystemTrayIcon::Warning);
    typeComboBox->addItem(style()->standardIcon(
            QStyle::SP_MessageBoxCritical), tr("Critical"),
            QSystemTrayIcon::Critical);
    typeComboBox->setCurrentIndex(1);
    
    durationLabel = new QLabel(tr("Duration:"));
    
    durationSpinBox = new QSpinBox;
    durationSpinBox->setRange(5, 60);
    durationSpinBox->setSuffix(" s");
    durationSpinBox->setValue(15);
    
    durationWarningLabel = new QLabel(tr("(some systems might ignore this "
                                         "hint)"));
    durationWarningLabel->setIndent(10);
    
    titleLabel = new QLabel(tr("Title:"));
    
    titleEdit = new QLineEdit(tr("Cannot connect to network"));
    
    bodyLabel = new QLabel(tr("Body:"));
    
    bodyEdit = new QTextEdit;
    bodyEdit->setPlainText(tr("Don't believe me. Honestly, I don't have a "
                              "clue.nClick this balloon for details."));
    
    showMessageButton = new QPushButton(tr("Show Message"));
    showMessageButton->setDefault(true);
    
    QGridLayout *messageLayout = new QGridLayout;
    messageLayout->addWidget(typeLabel, 0, 0);
    messageLayout->addWidget(typeComboBox, 0, 1, 1, 2);
    messageLayout->addWidget(durationLabel, 1, 0);
    messageLayout->addWidget(durationSpinBox, 1, 1);
    messageLayout->addWidget(durationWarningLabel, 1, 2, 1, 3);
    messageLayout->addWidget(titleLabel, 2, 0);
    messageLayout->addWidget(titleEdit, 2, 1, 1, 4);
    messageLayout->addWidget(bodyLabel, 3, 0);
    messageLayout->addWidget(bodyEdit, 3, 1, 2, 4);
    messageLayout->addWidget(showMessageButton, 5, 4);
    messageLayout->setColumnStretch(3, 1);
    messageLayout->setRowStretch(4, 1);
    messageGroupBox->setLayout(messageLayout);
    

    }

    void Window::createActions()
    {
    minimizeAction = new QAction(tr("Mi&nimize"), this);
    connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));

    maximizeAction = new QAction(tr("Ma&ximize"), this);
    connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
    
    restoreAction = new QAction(tr("&Restore"), this);
    connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
    
    quitAction = new QAction(tr("&Quit"), this);
    connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
    

    }

    void Window::createTrayIcon()
    {
    trayIconMenu = new QMenu(this);
    trayIconMenu->addAction(minimizeAction);
    trayIconMenu->addAction(maximizeAction);
    trayIconMenu->addAction(restoreAction);
    trayIconMenu->addSeparator();
    trayIconMenu->addAction(quitAction);

    trayIcon = new QSystemTrayIcon(this);
    trayIcon->setContextMenu(trayIconMenu);
    

    }
    @
    is this a qt bug ? or something I did wrong somewhere



  • Oh god, please format your code with the '@' tag.



  • sorry , I copy it from mac , as I was not familiar with the format of mac textEdit , it is strange Its format is so messy , I will try to format it



  • sorry could you tell me detailedly how to format it ?



  • strange , when I edit it , the format looks well , but why when I post , it is so ugly .


  • Moderators

    [quote author="brucewuu" date="1309868142"]@//! [6]

    void Window::messageClicked()
    {
    QMessageBox::information(0, tr("Systray"),
    tr("Sorry, I already gave what help I could.n"
    "Maybe you should try asking a human?"));
    }

    //! [6]

    void Window::createIconGroupBox()
    {
    iconGroupBox = new QGroupBox(tr("Tray Icon"));

    iconLabel = new QLabel("Icon:");
    
    iconComboBox = new QComboBox;
    iconComboBox->addItem(QIcon(":/images/bad.svg"), tr("Bad"));
    iconComboBox->addItem(QIcon(":/images/heart.svg"), tr("Heart"));
    iconComboBox->addItem(QIcon(":/images/trash.svg"), tr("Trash"));
    
    showIconCheckBox = new QCheckBox(tr("Show icon"));
    showIconCheckBox->setChecked(true);
    
    QHBoxLayout *iconLayout = new QHBoxLayout;
    iconLayout->addWidget(iconLabel);
    iconLayout->addWidget(iconComboBox);
    iconLayout->addStretch();
    iconLayout->addWidget(showIconCheckBox);
    iconGroupBox->setLayout(iconLayout);
    

    }

    void Window::createMessageGroupBox()
    {
    messageGroupBox = new QGroupBox(tr("Balloon Message"));

    typeLabel = new QLabel(tr("Type:"));
    
    typeComboBox = new QComboBox;
    typeComboBox->addItem(tr("None"), QSystemTrayIcon::NoIcon);
    typeComboBox->addItem(style()->standardIcon(
            QStyle::SP_MessageBoxInformation), tr("Information"),
            QSystemTrayIcon::Information);
    typeComboBox->addItem(style()->standardIcon(
            QStyle::SP_MessageBoxWarning), tr("Warning"),
            QSystemTrayIcon::Warning);
    typeComboBox->addItem(style()->standardIcon(
            QStyle::SP_MessageBoxCritical), tr("Critical"),
            QSystemTrayIcon::Critical);
    typeComboBox->setCurrentIndex(1);
    
    durationLabel = new QLabel(tr("Duration:"));
    
    durationSpinBox = new QSpinBox;
    durationSpinBox->setRange(5, 60);
    durationSpinBox->setSuffix(" s");
    durationSpinBox->setValue(15);
    
    durationWarningLabel = new QLabel(tr("(some systems might ignore this "
                                         "hint)"));
    durationWarningLabel->setIndent(10);
    
    titleLabel = new QLabel(tr("Title:"));
    
    titleEdit = new QLineEdit(tr("Cannot connect to network"));
    
    bodyLabel = new QLabel(tr("Body:"));
    
    bodyEdit = new QTextEdit;
    bodyEdit->setPlainText(tr("Don't believe me. Honestly, I don't have a "
                              "clue.nClick this balloon for details."));
    
    showMessageButton = new QPushButton(tr("Show Message"));
    showMessageButton->setDefault(true);
    
    QGridLayout *messageLayout = new QGridLayout;
    messageLayout->addWidget(typeLabel, 0, 0);
    messageLayout->addWidget(typeComboBox, 0, 1, 1, 2);
    messageLayout->addWidget(durationLabel, 1, 0);
    messageLayout->addWidget(durationSpinBox, 1, 1);
    messageLayout->addWidget(durationWarningLabel, 1, 2, 1, 3);
    messageLayout->addWidget(titleLabel, 2, 0);
    messageLayout->addWidget(titleEdit, 2, 1, 1, 4);
    messageLayout->addWidget(bodyLabel, 3, 0);
    messageLayout->addWidget(bodyEdit, 3, 1, 2, 4);
    messageLayout->addWidget(showMessageButton, 5, 4);
    messageLayout->setColumnStretch(3, 1);
    messageLayout->setRowStretch(4, 1);
    messageGroupBox->setLayout(messageLayout);
    

    }

    void Window::createActions()
    {
    minimizeAction = new QAction(tr("Mi&nimize"), this);
    connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));

    maximizeAction = new QAction(tr("Ma&ximize"), this);
    connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
    
    restoreAction = new QAction(tr("&Restore"), this);
    connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
    
    quitAction = new QAction(tr("&Quit"), this);
    connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
    

    }

    void Window::createTrayIcon()
    {
    trayIconMenu = new QMenu(this);
    trayIconMenu->addAction(minimizeAction);
    trayIconMenu->addAction(maximizeAction);
    trayIconMenu->addAction(restoreAction);
    trayIconMenu->addSeparator();
    trayIconMenu->addAction(quitAction);

    trayIcon = new QSystemTrayIcon(this);
    trayIcon->setContextMenu(trayIconMenu);
    

    }
    @
    is this a qt bug ? or something I did wrong somewhere[/quote]


  • Moderators

    If you start and end your code section in your post with an 'at' sign ('@') it will look much nicer. That is what the others are asking for.

    I have just added in the post above these two signs in the begin at the end. And voila it looks much better.

    Sorry, had to do two posts ;-)


  • Moderators

    there is a wiki page explaining how the editor works :
    "Using the editor :":http://developer.qt.nokia.com/wiki/ForumHelp#9bd9c32b79efb1b2d5b039e4d48300a9



  • ok , guys , thanks very much , I have changed them now ~~anyone could give me solution ?thanks



  • It may be caused by some internal objects that are no longer available after you hide the icon. I can reproduce the crash on my Mac box.

    As a workaround you can replace the call to hide with a single shot timer in your slot like this

    @
    fSystemTrayTimer->stop() ;
    //fSystemTrayIcon->hide();
    QTimer::singleShot(0, fSystemTrayIcon, SLOT(hide()));
    @

    This way the call to hide is delivered after you have left the slot.

    EDIT:
    I've added this as a doc not to [[Doc:QSystemTrayIcon]] too.



  • thanks Volker , you are always the best problem solver for me . Great Appreciation ~~~



  • hi Volker , I also meet the same problem as the following link
    http://svn.netlabs.org/qt4/ticket/201
    do you have some solution for that ?thanks ~~



  • I'll have a look into this later.



  • thanks very much , I have read the guide to ask questions , it is very helpful for me , thank you very much , I will do this better ~~



  • I didn't forget you but I was terribly busy the last week and am off for vacation soon, so please be a bit more patient.



  • thanks Volker ~~just have a look when you have time , thanks



  • [quote author="brucewuu" date="1309959197"]hi Volker , I also meet the same problem as the following link
    http://svn.netlabs.org/qt4/ticket/201
    do you have some solution for that ?thanks ~~[/quote]

    That's out of scope for me. I don't know the internal workings for the OS/2 port, sorry.


Log in to reply
 

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