Carbon->Cocoa transition

Cubase 5 is now completely Cocoa based (and with support for Carbon plug-ins). So, what does it mean to port a cross-platform C++ application to Cocoa.
At the time Apple removed the 64 bit HIToolbox API from Mac OS X, we needed to redesign our native platform implementation of our base framework. Before we had more or less a simple macro based differentiation between our supported platforms like this:

void myFunction ()
{
#if MAC
// call some Mac API
#elif WINDOWS
// call some Windows API
#elif BEOS
// call some BeOS API
#endif
}

This doesn’t really work good as we needed to support a different language than C, or C++ namely Objective-C. So we sat down and thought about alternatives. As we already use some kind of COM like interfaces to connect to plug-ins we thought we could adapt this for our platform layer and we did.
We re-factored all our UI platform code so that we use interfaces for windows, views, menus and so on.
It works like this, if we took the pseudo code from above:

class SimpleInterface : public Unknown
{
public:
static SimpleInterface* createSimpleInterface ();
virtual void doMyFunction () = 0;
};

void myFunction ()
{
interface->doMyFunction ();
}

This way we can now build up different implementations for Windows, Mac Carbon, Mac Cocoa and so on.
The Mac Cocoa code would look like this:

class CocoaSimpleInterface : public SimpleInterface
{
public:
void doMyFunction ();
};

void CocoaSimpleInterface::doMyFunction ()
{
// some objective-c code here
}

SimpleInterface* SimpleInterface::createSimpleInterface ()
{
return new CocoaSimpleInterface;
}

We even did implement nearly all interfaces for Carbon too. We needed to as nearly all plug-ins today uses Carbon for their user interfaces. So instead of working with window groups to layer Carbon and Cocoa windows together, we just can create windows based on the plug-ins use of Carbon or Cocoa. This does give us better user experience than other Cocoa hosts which have a hard time to support Carbon based plug-ins.
So this design decision gave us many benefits we could not solved before. Even supporting new platforms will be much easier now.
Now to some things that worked not that easy. And that’s mainly AppKit.
Apple told developers some years now to switch to Cocoa from Carbon, but boy is Cocoa buggy and less customizable than Carbon. To build up simple applications or Mac only applications with Cocoa is straight forward and maybe one of the best native solutions I saw yet, but complex cross-platform applications ?
No. One really amusing example is the menu bar. As you can imagine, we build up the menu bar in code, abstract so that we only need to write code once for all platforms. But do you think you can build a menu bar in Cocoa from code ? No, you cannot, if you try to you get so much weird behavior like double Help menus, non working menu items, etc. So we just have to create a more or less empty menu bar in Interface Builder. And we need to do this for every language we support, not like Carbon where Carbon nicely translates it’s own items.
Another big problem for us, or mainly for our plug-in developers will be that Objective-C does not have the two-level namespace feature known from C++. This basically means that class name clashes can occur. It will be interesting to see what solutions the plug-in developers will come up with, especially those coming from Windows without much knowledge of the Mac API.
So now that Cubase 5 is Cocoa based, what’s next ? Yeah, let’s start to build a 64 bit version. We are now at the same point we were 2 years ago before Apple dropped 64 bit HIToolbox. So nothing really won from a users point of view. Internally it was a good thing to re-factor our UI code and gave us the opportunity to fix some bugs and streamline our native implementations.

6 Comments : 01.16.09