Monday, August 11, 2008

Qt4 Mac Dock Icon Click

When you click the "close button" of an application's window, on Mac OS X the window will be hidden but the application continue running. When you click on the Dock Icon, the application's window will be showed. This is the default behaviour for Mac Apps but Qt Apps doesn't the same. So, how we could implement this behaviour?
#ifndef _APPLICATION_H_
#define _APPLICATION_H_

// Qt4 Headers
include <QApplication>
include <QWidget>

// Carbon Headers
#ifdef Q_WS_MAC
#include <Carbon/Carbon.h>
#endif

class Application : public QApplication {
Q_OBJECT

public:
Application (int& argc, char **argv);

QWidget *mainWindow (void) const;

private:
QWidget *m_mainWindow;

#ifdef Q_WS_MAC
AEEventHandlerUPP m_appleEventProcessorUPP;
#endif
};

#endif // !_APPLICATION_H_

Here, we've implemented an Application class that Inherits from QApplication. This class contains a reference to the App's Main Window.
#ifdef Q_WS_MAC
static OSStatus appleEventProcessor(const AppleEvent *ae,
AppleEvent *event,
long handlerRefCon)
{
Application *app = (Application *) handlerRefCon;

OSType aeID = typeWildCard;
OSType aeClass = typeWildCard;

AEGetAttributePtr(ae, keyEventClassAttr, typeType, 0,
&aeClass, sizeof(aeClass), 0);
AEGetAttributePtr(ae, keyEventIDAttr, typeType, 0,
&aeID, sizeof(aeID), 0);

if (aeClass == kCoreEventClass) {
if (aeID == kAEReopenApplication) {
app->mainWindow()->show();
}
return noErr;
}

return eventNotHandledErr;
}
#endif

Application::Application (int& argc, char **argv)
: QApplication(argc, argv)
{
// Don't Quit the App on Window Close
setQuitOnLastWindowClosed(false);

// Initialize Main Window
m_mainWindow = new QLabel("Test Main Window");

#ifdef Q_WS_MAC
// Install Reopen Application Event (Dock Clicked)
m_appleEventProcessorUPP = AEEventHandlerUPP(appleEventProcessor);
AEInstallEventHandler(kCoreEventClass, kAEReopenApplication,
m_appleEventProcessorUPP, (long) this, true);
#endif
}

QWidget *Application::mainWindow (void) const {
return(m_mainWindow);
}

Thats all folks! Run the app, Click on close button and then click on the dock icon to see the result.

10 comments:

  1. It's incredible, this is typically which I was looking for (thanks Google ;o)) and this post is from yesterday !!!

    How lucky I am ;o)

    Thanks for this nice article ;o)

    ReplyDelete
  2. This is not working. Is there some particular includes to put in the cpp file or something particular to put in the .pro file ?

    With which SDK this is intended to work ? I'm compiling with an OS X 10.4.11, the XCode 2.5 and the SDK 10.4u.

    I use macx-g++ as the spec to compile on console with make.

    I have errors like that on the console :

    /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/CoreServices.framework/Frameworks/OSServices.framework/Headers/OpenTransportProviders.h:108: error: expected identifier before numeric constant
    /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/CoreServices.framework/Frameworks/OSServices.framework/Headers/OpenTransportProviders.h:108: error: expected `}' before numeric constant
    /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/CoreServices.framework/Frameworks/OSServices.framework/Headers/OpenTransportProviders.h:108: error: expected unqualified-id before numeric constant
    /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/CoreServices.framework/Frameworks/OSServices.framework/Headers/OpenTransportProviders.h:575: error: expected declaration before '}' token
    /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/CoreServices.framework/Frameworks/OSServices.framework/Headers/OpenTransportProviders.h:108: error: expected identifier before numeric constant
    /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/CoreServices.framework/Frameworks/OSServices.framework/Headers/OpenTransportProviders.h:108: error: expected `}' before numeric constant
    /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/CoreServices.framework/Frameworks/OSServices.framework/Headers/OpenTransportProviders.h:108: error: expected unqualified-id before numeric constant
    /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/CoreServices.framework/Frameworks/OSServices.framework/Headers/OpenTransportProviders.h:575: error: expected declaration before '}' token

    ReplyDelete
  3. Hi again,

    've just tried at home your sample code and it works with Leopard ! Fantastic ! Thanks a lot.

    I will see later in the morning if I manage to get it working in my real project, with the same environment I told you about in my previous comment.

    I think i've done mistakes when integrating your code even if the error messages seems to be related to the OS X SDK.

    ReplyDelete
  4. Your raw sample works like a charm on Tiger with the 104.4u SDK and by compiling as an universal binray.

    But this is still a problem with my real app. I've commented all the useful code and it still failed only by including the header

    I think there is a problem with the order of the compilation of the files or perhaps this is related to a two-level inheritance (I have a SingleApplication class inheriting from QApplication then a MyApplication class inheriting from SingleApplication).

    ReplyDelete
  5. Ok, I've got it !!!

    I have a conflict between gSOAP and the Mac OS X SDK.

    I was including the gsoap binding proxy before Carbon.h

    #include "SOAP/soapserviceBindingProxy.h"

    // Carbon Headers
    #ifdef Q_WS_MAC
    #include
    #endif


    If I include the manager binding proxy after the Carbon.h include, it compiles but with a lot of warning on symbols redefinition like

    TCP_NODELAY
    TCP_KEEPALIVE
    TCP_MAXSEG
    ...

    I don't know if this symbol redefinition could lead to problems but my app compile and seems to run fine.

    ReplyDelete
  6. Thank you very much for this piece of useful code!
    Great.

    ReplyDelete
  7. Hi,

    Jusr for information, with the new release of Qt 4.6.0, the code is not working without adding

    macx:LIBS += -framework Carbon

    in the .pro file.

    I wonder if it is is nice to include Carbon now that Qt fully use Cocoa.

    It would be nice to be able to do the same in Cocoa, by mixing C++ Qt code with Cocoa objective-c one... If you or someone knows, it is the time to share ;o)

    ReplyDelete
  8. Great! It worked like a charm! My application will be forever grateful :D

    ReplyDelete
  9. This comment has been removed by the author.

    ReplyDelete
  10. appleEventProcessor is not emiting :(

    QT 4.7

    ReplyDelete