KengoSawa2の技術的ななにか

IT屋さんのようなKengoSawa2がなんかそれっぽい事を書いていくblogです

Mac OS X QSystemTrayIconのactivated()を受けたスロット延長でhide()するとクラッシュする件

環境:Mac OS X + Qt 5.3.2 QSystemTrayIconでQSystemTrayIconのactivated()シグナルを受けたスロットの延長でQSystemTrayIcon::hide()するとクラッシュする件。

なんっどやっても内部クラッシュするのでなんでだー!!ってなってたけど、Qt内部のバグによるもので、回避策を打たないと100%クラッシュします。例を挙げて解説します。

QSystemTrayIconをクリックしたら対象のアイコンを隠したい時があったので、以下のようにコードを書きました。まず

QSystemTrayIcon *systray = new QSystemTrayIcon(this);

connect(systray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
            this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));

 こんな感じで普通にconnectします。で、スロットの方では以下のように

void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason){
    switch (reason) {

    case QSystemTrayIcon::Trigger:
    case QSystemTrayIcon::DoubleClick:
    case QSystemTrayIcon::MiddleClick:
         systray->hide();
         break;
    default:
         break;
    }

まあ、至って普通に見えますね。が、これを動作させると大体以下のような感じで落ちます。

Crashed Thread:  0  Dispatch queue: com.apple.main-thread

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: EXC_I386_GPFLT

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libqcocoa.dylib               	0x0000000103f47787 -[QNSStatusItem triggerSelector:button:] + 71
1   libqcocoa.dylib               	0x0000000103f472a5 -[QNSImageView mousePressed:button:] + 405
2   com.apple.AppKit              	0x00007fff90b4150e -[NSWindow sendEvent:] + 6853
3   com.apple.AppKit              	0x00007fff90f2b29e -[NSStatusBarWindow sendEvent:] + 67
4   com.apple.AppKit              	0x00007fff90b3d644 -[NSApplication sendEvent:] + 5761
5   libqcocoa.dylib               	0x0000000103f22b0e -[QNSApplication sendEvent:] + 78
6   com.apple.AppKit              	0x00007fff90a5321a -[NSApplication run] + 636
7   libqcocoa.dylib               	0x0000000103f1f1d4 QCocoaEventDispatcher::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 2420
8   QtCore                        	0x000000010096bacd QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 381
9   QtCore                        	0x000000010096f007 QCoreApplication::exec() + 359
10  TEDT.RapidCopy                	0x0000000100005bcc main + 236
11  TEDT.RapidCopy                	0x00000001000057c4 start + 52

解決法は以下のようにすればokです。

void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason){
    switch (reason) {

    case QSystemTrayIcon::Trigger:
    case QSystemTrayIcon::DoubleClick:
    case QSystemTrayIcon::MiddleClick:
         //Mac OS XのQtバグ回避
         QMetaObject::invokeMethod(systray, "hide", Qt::QueuedConnection);
         break;
    default:
         break;
    }
}

この現象はmacosxのバグとのことで、Qt4.xからずっと対処されていない問題のようです。

Qtをお使いの方ならご存知、何でも答えてくれるVokerさんが答えてくれています。

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

で、ちょっとつらいのがこの問題、Qt4.xのドキュメントには補足されてます。
QSystemTrayIcon Class Reference | Documentation | Qt Project

が、Qt5では補足が引き継がれていません。。
QSystemTrayIcon Class | QtWidgets 5.3 | Documentation | Qt Project

Qt5の補足にコピペで書いておいてあげないとと思ったのですが、投稿の仕方がわからず(´・ω・`)
誰か投稿の仕方教えてください。。

落ち方をぐぐってこの記事にたどり着く人が出たらいいなあと思ってます。
めっちゃわからずにはまったよー(´;ω;`)

2014/11/24訂正:
日本qtユーザー会の
Tasuku Suzuki (@task_jp) | Twitterさんからqtのバグであること、
またバグ回避方法のオススメについて教えて頂いたので、記事内容を訂正しました。
ありがとうございます(._.)
qtbugレポートへのリンクは以下の通りです。
https://bugreports.qt-project.org/browse/QTBUG-6328