I have an open Qt Mac app. I am clicking the app Icon
Is there a way to get a notification for this in the app?
I couldn't get the original answer to compile properly due to deprecation warnings (post-OS X 10.5) and type errors; I changed a few type names and got it to compile, but the code still didn't work.
It turns out that newer versions of Qt (4.8.7+, including 5.x; I use 5.4.1) implement the method we want to add, and class_addMethod
fails if the method already exists. See this QTBUG.
Note: the above bug report contains a slightly different solution (I found it after fixing the issue myself).
One solution, that works for me, is to check if the method exists. If it does, we replace it. If not, we simply add it.
I have not tested this code on older Qt versions, but it uses OPs logic, so it should work.
Here's my code. As in OPs case, all code is in the .cpp file of a QApplication subclass.
#ifdef Q_OS_MAC
#include <objc/objc.h>
#include <objc/message.h>
void setupDockClickHandler();
bool dockClickHandler(id self,SEL _cmd,...);
#endif
My QApplication subclass constructor contains
#ifdef Q_OS_MAC
setupDockClickHandler();
#endif
And finally, somewhere in the same file (at the bottom, in my case):
#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
Also see the Apple documentation on the applicationShouldHandleReopen:hasVisibleWindows: method.
In order for this to compile, you also need to link with some extra frameworks.
Using qmake, I added the following to my .pro file:
LIBS += -framework CoreFoundation -framework Carbon -lobjc
Those flags are of course exactly what you should add to the c++ or clang++ command line, if you compile manually.
That should be everything that's required.
It's crazy, but i got it, and without any Objective-C coding:
I derived QApplication. In the *.cpp portion of my derived class i put:
#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
in my derived application class constructor I put:
#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
Added this simple method to my application class (note it's referred to from the handler at the top of my answer)
void MyApplictionClass::onClickOnDock()
{
// do something...
}
Works like charm.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With