QT on OS X, how to detect clicking the app Dock Icon

后端 未结 4 699
傲寒
傲寒 2020-12-10 08:06

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?

4条回答
  •  渐次进展
    2020-12-10 08:37

    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 
    #include 
    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.

提交回复
热议问题