[Openmcl-devel] Questions about Cocoa app development]

mikel evins mevins at mac.com
Sun Jan 27 12:00:53 PST 2008

On Jan 26, 2008, at 1:50 AM, Didier Verna wrote:

>       Hi Mikel,
> thank you for the detailed answer.
> mikel evins <mevins at mac.com> wrote:
>> As for interacting with your application, well, you can build a
>> Listener into it. Feel free to send suggestions for how you'd like it
>> to work.
>  At a first glance, having a window -> listenener menu option
> implemented directly by build-application (optionally with an option  
> to
> turn it off) would be nice.
> Also, I have done a few tests and noticed that if you create a simple
> nib file without a window (just a MainMenu), you do get the listener  
> in
> your app. Only when you add a window does the listener go away. How's
> that implemented ?

Unintentionally. :-)

By default, an NSApplication instance sends  
applicationOpenUntitledFile: to its delegate, which causes a new  
window to be created. If your nib doesn't have a window that is  
defined as the key target, that message is being handled by Clozure  
CL's classes, which respond by opening a Listener if one is not  
already open.

If you want your window to be opened instead, create one in your main  

If you want no window to open at launch, implement an application  
delegate and define its applicationShouldOpenUntitledFile: method to  
return NO.

>>> 2/ How do you execute specific Lisp code when the application  
>>> starts,
>>> both before and after the GUI is setup ?
>> One Cocoa-flavored way to do it is to create an application delegate
>> and implement the methods applicationWillFinishLaunching: and
>> applicationDidFinishLaunching:. You can implement these in Lisp and
>> have them evaluate arbitrary Lisp forms. Apple documentation of these
>> and other delegate methods is here:
>  OK, I've done a test with a menu-only nib file, but I can't get this
> to work. Here's my code (trivial, really):
> (defvar *test* nil)
> (defclass app-delegate (ns:ns-object)
>  ()
>  (:metaclass ns:+ns-object))
> (objc:defmethod (#/test: :void)
>    ((self app-delegate) sender)
>  (declare (ignore sender))
>  (setf *test* 0)
>  (format t "Test~%"))
> (objc:defmethod (#/applicationWillFinishLaunching: :void)
>    ((self app-delegate) notification)
>  (declare (ignore notification))
>  (setf *test* 1)
>  (format t "Will finish launching~%"))
> (objc:defmethod (#/applicationDidFinishLaunching: :void)
>    ((self app-delegate) notification)
>  (declare (ignore notification))
>  (setf *test* 2)
>  (format t "Did finish launching~%"))
> I've made connections to the app-delegate in the nib file (the  
> delegate
> field of the Application itself, and the test action from the Help  
> menu
> option). However, only the help button seems to work. Am I doing
> something wrong ?

No, we are.

BUILD-APPLICATION saves an image that uses Clozure CL's application  
classes and its Cocoa startup code. The code for START-COCOA- 
APPLICATION in cocoa-ide/cocoa-window.lisp sets the application  
delegate for you. Unfortunately, if you use BUILD-APPLICATION to build  
your app, there's no handy way to tell START-COCOA-APPLICATION you  
want to use a particular delegate class. This is a bug, and I have  
filed a bug report. I'll fix it when I can.

In the meantime, try these as workarounds:


First, define this method in your source file:

(defmethod application-init-file ((app cocoa-application))

For "home:init-file" substitute any suitable pathname.

Then, put the lisp forms you want evaluated in the file at that path.


Put the forms you want evaluated in a definition like this:

(defmethod initialize-instance ::after ((app cocoa-application) &rest  
initargs &key &allow-other-keys)
   [your code goes here])

You can always try redefining START-COCOA-APPLICATION as well, though  
that's probably not for the faint of heart.


More information about the Openmcl-devel mailing list