To interface Cairo with Quartz, I've needed the ability to send Objective-C messages to Objective-C objects managed by the VM. Floating around is a prototype project done by the fine fellows at Heeg called ObjCConnect. It was a little more ambituous in scope for what I needed and has accrued some dust sitting on the shelf. But it served as a great harvesting target, which allowed me to create a very minimal interface to the Objective-C runtime.
For the uninitiated, Objective-C programs run with a special library called the "Objective-C Runtime" linked into them. This engine is like a minimal Smalltalk VM. It handles class registration, method dispatch, and program object reflection/introspection.
I published my first cut in the Open Repository as "ObjectiveCRuntime."
It supports really two basic APIs: fetching class objects and sending messages to objects (class or instance). It also shows how to do an ExternalInterface object as a class interface, rather than as an instance interface. What's really neat to me, is that once you have this, you have a wealth of possibilities at your finger tips. Consider this fragment:
| window nsWindow |
window := ApplicationWindow allInstances detect: [:each | each model isKindOf: VisualLauncher].
nsWindow := window windowHandle
The first line finds the window of the launcher. The second line gets the windowHandle, which is very conveniently a pointer to the NSWindow object behind our launcher. That integer value is perfectly passable as an "id" (whcih is the generic type for Object in Objective-C). Once we have that, we can send messages to it. The messages you can send it are
documented right here. The cool thing is... we can send all of those messages now! We don't have to go declare an interface for each one of those functions like we normally would for a conventional C library using DLLCConnect. The message:
ObjectiveCRuntime object: nsWindow perform: 'center'
happily puts our launcher in the middle of the screen. And:
ObjectiveCRuntime object: nsWindow perform: 'setShowsResizeIndicator' with: 1
happily puts the little resize grip in the lower right of the window. And if we want to get a little more involved, we can do:
ObjectiveCRuntime
object: nsWindow
perform: 'setTitle:'
with:
(ObjectiveCRuntime
object: (ObjectiveCRuntime classNamed: 'NSString')
perform: 'stringWithUTF8String:'
with: 'Smalltalk, meet Objective-C' copyToHeap datum)
Tada! I find it truly totally cool how easy it is to bind Objective-C to another language, versus something like C++. Truly, Less is More.