[Openmcl-devel] Setting a toplevel function for build-application

Paul Krueger plkrueger at comcast.net
Tue Sep 17 11:26:18 PDT 2013


I've hesitated to respond to this because the whole subject can be pretty confusing, but I'll make a few comments and then direct anyone interested to look at my contrib code (...ccl/contrib/cocoa-ide/krueger/InterfaceProjects/...) for more information (but make sure you have the latest version).

On Sep 17, 2013, at 11:31 AM, Gary Byers <gb at clozure.com> wrote:

> If the application is a Cocoa application - an instance of the class GUI::COCOA-IDE, which is new since the last time that I was paying attention
> to any of this - its CCL::TOPLEVEL-FUNCTION method creates another thread
> to do the periodic housekeeping stuff, then initializes Cocoa and runs the
> Cocoa event loop.  You might be able to subclass GUI::COCOA-IDE and override
> this method and do this very slightly differently, but there aren't that many
> ways of doing this differently.

I'll second this. In previous incarnations of my Cocoa app development tools I did provide a custom top-level function, but I had some difficulty making it all work well in my most recent code and finally gave that up when I discovered an easier way to do things.

> 
> Cocoa also uses an application class (NSApplication) with a single global
> instance of that class; like many other Cocoa objects, this instance can
> have another NSObject associated with it as the instance's "delegate" object.
> Most interesting events (with a small #\e) in an NSApplication's lifetime
> result in methods being invoked (if they're implemented) on the NSApplication
> object's delegate.

Right. Providing a custom application delegate is a reasonable way to customize a stand-alone Cocoa app. I provide examples and discussion in my contrib. The "CCL Cocoa Developer Tools Tutorial" in my contrib spends a fair amount of time discussing this.

> 
> The CCL IDE uses an instance of the class LispApplicationDelegate as
> the NSApplication's delegate; this class's methods are defined in
> "ccl:cocoa-ide;app-delegate.lisp".   The application delegate is also
> the target for a bunch of menu and other UI items. You might find it easiest to
> subclass this class and override a few of its methods:
> 
> (defclass beeping-application-delegate (gui::lisp-appication-delegate)
>  ()
> (:metaclass ns:+ns-object))
> 
> (objc:defmethod (#/applicationDidFinishLaunching: :void)
>    ((self lisp-application-delegate) notification)
>  (#_NSBeep)
>  (call-next-method notication))

Sure, or define your own application delegate class. Which of those you decide to do probably depends on how much of the regular IDE menu and window functionality you want to include in your stand-alone application.

> 
> If you can figure out how to persuade BUILD-APPLICATION to use
> BEEPING-APPLICATION-DELEGATE as you application's delegate's
> class name, you're only minutes away from having an application
> the beeps when it starts up.  (The thrill may wear off fairly
> quickly.)

The application delegate is actually set at runtime as part of the start-up process that is done by the init-cocoa-ide method, so I wouldn't say that this is something that build-application needs to know. There are a couple of different ways that the application delegate object can be set. If your app uses a main nib file and if that nib file includes the declaration of an app delegate object that is bound to the delegate outlet of the application object, then the process of loading the nib will create an app delegate and link it appropriately. If that doesn't happen, then the init-cocoa-ide method will create an application delegate object for you. The problem of course is that it will create one of the class LispApplicationDelegate.

In my case I wanted to modify this process in a couple of ways. I wanted to make it possible to have a cocoa application that executed a custom application  initialization method rather than loading a main nib file (because I now define all of my windows, menus, etc. procedurally) and I wanted to make it easy to specify a custom app delegate class that was determined at runtime rather than having a fixed default class. I finally determined that the easiest way to make both of those happen was to override the gui::init-cocoa-ide method with a version of my own that is similar to the original, but looks for custom key values in the application's info plist which specify a startup method and an application delegate class and then uses those. If you want to do something similar you can look at the custom-app-init.lisp file in my contrib. Just make sure your version is loaded before saving the application so that on startup your version is invoked.




More information about the Openmcl-devel mailing list