QtMacアプリを開いています。アプリのアイコンをクリックしています
アプリでこれに関する通知を受け取る方法はありますか?
非推奨の警告(OS X 10.5以降)とタイプエラーのため、正しくコンパイルするための元の回答を取得できませんでした。いくつかの型名を変更してコンパイルしましたが、それでもコードは機能しませんでした。
新しいバージョンのQt(4.8.7+、5.xを含む;私は5.4.1を使用)は、追加したいメソッドを実装し、class_addMethod
メソッドがすでに存在する場合は失敗することがわかりました。このQTBUGを参照してください。
注:上記のバグレポートには、わずかに異なる解決策が含まれています(問題を自分で修正した後で見つけました)。
私にとって有効な解決策の1つは、メソッドが存在するかどうかを確認することです。もしそうなら、私たちはそれを交換します。そうでない場合は、単に追加します。
このコードは古いバージョンのQtでテストしていませんが、OPロジックを使用しているため、機能するはずです。
これが私のコードです。OPの場合と同様に、すべてのコードはQApplicationサブクラスの.cppファイルにあります。
#ifdef Q_OS_MAC
#include <objc/objc.h>
#include <objc/message.h>
void setupDockClickHandler();
bool dockClickHandler(id self,SEL _cmd,...);
#endif
私のQApplicationサブクラスコンストラクターには
#ifdef Q_OS_MAC
setupDockClickHandler();
#endif
そして最後に、同じファイルのどこか(私の場合は下部):
#ifdef Q_OS_MAC
void setupDockClickHandler() {
Class cls = objc_getClass("NSApplication");
objc_object *appInst = objc_msgSend((objc_object*)cls, sel_registerName("sharedApplication"));
if(appInst != NULL) {
objc_object* delegate = objc_msgSend(appInst, sel_registerName("delegate"));
Class delClass = (Class)objc_msgSend(delegate, sel_registerName("class"));
SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
if (class_getInstanceMethod(delClass, shouldHandle)) {
if (class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"))
qDebug() << "Registered dock click handler (replaced original method)";
else
qWarning() << "Failed to replace method for dock click handler";
}
else {
if (class_addMethod(delClass, shouldHandle, (IMP)dockClickHandler,"B@:"))
qDebug() << "Registered dock click handler";
else
qWarning() << "Failed to register dock click handler";
}
}
}
bool dockClickHandler(id self,SEL _cmd,...) {
Q_UNUSED(self)
Q_UNUSED(_cmd)
// Do something fun here!
qDebug() << "Dock icon clicked!";
// Return NO (false) to suppress the default OS X actions
return false;
}
#endif
また、applicationShouldHandleReopen:hasVisibleWindows:メソッドに関するAppleのドキュメントも参照してください。
これをコンパイルするには、いくつかの追加のフレームワークとリンクする必要もあります。
qmakeを使用して、.proファイルに次を追加しました。
LIBS += -framework CoreFoundation -framework Carbon -lobjc
もちろん、これらのフラグは、手動でコンパイルする場合、c++またはclang++コマンドラインに追加する必要があるものとまったく同じです。
それが必要なすべてであるはずです。
それはクレイジーですが、私はそれを手に入れました、そしてObjective-Cコーディングなしで:
QApplicationを派生させました。派生クラスの*.cpp部分に、次のように記述します。
#ifdef Q_OS_MAC
#include <objc/objc.h>
#include <objc/message.h>
bool dockClickHandler(id self,SEL _cmd,...)
{
Q_UNUSED(self)
Q_UNUSED(_cmd)
((MyApplictionClass*)qApp)->onClickOnDock();
return true;
}
#endif
派生アプリケーションクラスコンストラクターに次のように配置します。
#ifdef Q_OS_MAC
objc_object* cls = objc_getClass("NSApplication");
SEL sharedApplication = sel_registerName("sharedApplication");
objc_object* appInst = objc_msgSend(cls,sharedApplication);
if(appInst != NULL)
{
objc_object* delegate = objc_msgSend(appInst, sel_registerName("delegate"));
objc_object* delClass = objc_msgSend(delegate, sel_registerName("class"));
const char* tst = class_getName(delClass->isa);
bool test = class_addMethod((objc_class*)delClass, sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:"), (IMP)dockClickHandler,"B@:");
if (!test)
{
// failed to register handler...
}
}
#endif
この単純なメソッドをアプリケーションクラスに追加しました(回答の上部にあるハンドラーから参照されていることに注意してください)
void MyApplictionClass::onClickOnDock()
{
// do something...
}
チャームのように機能します。
QEvent :: ApplicationActivateの問題は、アクティベーションごとに発行されることです。たとえば、ApplicationSwitcherでアプリに切り替えた場合でも同様です。ネイティブの動作では、cmd + tabで切り替えているときではなく、Dockアイコンをクリックしたときにのみアプリが表示されます。
ただし、少なくともQt5.9.1で機能するハックがあります。Dockアイコンをクリックすると、2つの連続したQEvent :: ApplicationStateChangeEventイベントが生成されますが、cmd+tabは1つだけです。したがって、このコードはDockクリック信号を非常に正確に出力します。Appクラスは、QApplicationから継承されたアプリケーションクラスであり、それ自体のイベントフィルターでもあります。
bool App::eventFilter(QObject* watched, QEvent* event)
{
#ifdef Q_OS_MACOS
if (watched == this && event->type() == QEvent::ApplicationStateChange) {
auto ev = static_cast<QApplicationStateChangeEvent*>(event);
if (_prevAppState == Qt::ApplicationActive
&& ev->applicationState() == Qt::ApplicationActive) {
emit clickedOnDock();
}
_prevAppState = ev->applicationState();
}
#endif // Q_OS_MACOS
return QApplication::eventFilter(watched, event);
}
Qt5.4.0以降、ドックのクリックに関連するQEventを処理できます:QEvent::ApplicationActivate。