# Tutorial: Updating a Classic application to modern Carbon

## 3. Carbon Events

One of the most important and difficult taks in a Carbon porting job is switching from the "classic" Event Manager WaitNextEvent() driven event loop to the modern Carbon Event Manager RunApplicationEventLoop() driven event loop. This step does just that. Special effort was take to reap the benefits of all the hard work put into step 1 so that as much code is reused as possible. In fact the Classic code is left in on this step to illustrate just how much code can be reused.

The application Carbon Event handler is registered in the Open Application Apple Event handler.

    static pascal OSErr openApplicationAEHandler(const AppleEvent *appleEvent, AppleEvent *reply,
                                                    long refcon)
    {
        OSErr error;
        DescType returnedType;
        Size actualSize;

        error = AEGetAttributePtr(appleEvent, keyMissedKeywordAttr, typeWildCard, &returnedType,
                                    NULL, 0, &actualSize);
        if (error == noErr)
            error = errAEParamMissed;
        else if (error == errAEDescNotFound)
        {
            EventTypeSpec applicationEvents[] = {
                                                    {kEventClassCommand, kEventCommandProcess}
                                                };

    #if TARGET_API_MAC_CARBON
            gAppEventHandler = NewEventHandlerUPP(appEventHandler);
            InstallApplicationEventHandler(gAppEventHandler, GetEventTypeCount(applicationEvents),
                                            applicationEvents, NULL, NULL);
    #endif
            error = noErr;
        }

        return error;
    }

The application event handler simply passes on menu commands to the menu command handler which is unchanged from step 2.

    static pascal OSStatus appEventHandler(EventHandlerCallRef nextHandler, EventRef event,
                                            void *junk)
    {
    #pragma unused (nextHandler, junk)

        OSStatus result = eventNotHandledErr;
        UInt32 eventClass, eventKind;
        HICommand command;

        eventClass = GetEventClass(event);
        eventKind = GetEventKind(event);

        switch (eventClass)
        {
            case kEventClassCommand:
                switch (eventKind)
                {
                    case kEventCommandProcess:
                        GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL,
                                            sizeof(HICommand), NULL, &command);

                        if (command.commandID != kHICommandQuit)    // let the Quit Application
                        {                        // Apple Event handler take care of Quit commands
                            MenuCommand commandID;

                            if (command.commandID != 0)
                                commandID = command.commandID;

                            HandleMenuChoice(commandID);

                            result = noErr;
                        }
                        break;
                }
                break;
        }

        return result;
    }

See PrefsWindow.c in the 3_Carbon_Events folder to see the window event handler that was added for the window in this step. The dialog's event handler is now split into a window event handler to handle clicks in the window's controls (see PrefsDialog.c), and a control event handler to handle key presses in the list box. Because key presses can potentially close the dialog (if the user presses return, escape, etc.), the dialog's window is retained before the standard handler is called.

    static pascal OSStatus listBoxControlEventHandler(EventHandlerCallRef nextHandler,
                                                        EventRef event, void *prefsDialog)
    {
        OSStatus result = eventNotHandledErr;
        UInt32 eventClass, eventKind;
        DialogRef dialog;
        WindowRef dialogWindow;

        eventClass = GetEventClass(event);
        eventKind = GetEventKind(event);

        switch (eventClass)
        {
            case kEventClassTextInput:
                switch (eventKind)
                {
                    case kEventTextInputUnicodeForKeyEvent:
                        dialog = (DialogRef)prefsDialog;
                        dialogWindow = GetDialogWindow(dialog);
                        RetainWindow(dialogWindow);        // hold onto the dialog's window

                        result = CallNextEventHandler(nextHandler, event);
                        if (result == noErr)    // we don't need to postprocess if nothing happened
                        {
                            ItemCount retainCount;

                            retainCount = GetWindowRetainCount(dialogWindow);
                            if (retainCount > 1)        // if we're the last one holding the window
                                handleDialogItemHit(dialog, iIconList);        // then there's no
                        }            // need to postprocess anything because it's about to go away

                        ReleaseWindow(dialogWindow);
                        break;
                }
                break;
        }

        return result;
    }

Next Page

Previous Page

Return to Main Page