Hello,
this is a proposal for a new extension to McCLIM consisting of two parts:
A general macro to produce application starter functions for McCLIM applications
Most Clim application have a starter functions that just makes the application frame and afterwards runs its toplevel:
(defun start () (run-frame-top-level (make-application-frame 'my-foo)))
So far, so simple. But now we want a shortcut to start the toplevel in a newly created process, so we have:
(defun start (&key (new-process nil)) (flet ((run () (run-frame-top-level (make-application-frame 'my-foo)))) (if new-process (clim-sys:make-process #'run :name "foo tool") (run))))
What else? Perhaps a default window width and height? A keyword parameter for the process name? . . .
It has started with the first version, then someone has written the second one, that was copied by others. Further extended... Well, it has become quite convenient, and so you can find mutations of the code in the Clim Listener, Clouseau (the inspector), the Clim Launcher, Climacs, and probably others. For a strange reason all of the authors never created a simple macro for it but have copied the code literally and changed it appropriately. How unlispy! So I changed this, by making one as part of the LED Cube Modeller[1].
It basically creates the code of the second example. You can also specify a default width and height for the application frame, as well as the default process name. Then there is also the option :COMPLAIN-ABOUT-EXISTING-PROCESS; set it to T when defining the starter (the default is nil) and the generated starter function will, previously to do anything else, search for an existing process and ask what it should do about it (I wanted this behaviour for the Cube Modeller's toolbox window). In addition to this you can also specify the frame manager if you want to try out the pixie/clx-look.
The new macro can be used as a drop-in replacement for e.g. the existing climacs-gui:climacs:
(climi::define-application-starter climacs :function-name climacs :default-width 900 :default-height 400)
For the Clim Launcher it is:
(climi::define-application-starter launcher :function-name start :default-process-name "CLIM Launcher" :announce-to-clim-launcher nil)
For the Clim Listener it could be:
(climi::define-application-starter listener :function-name run-listener :default-width 760 :default-height 550)
but there is a tiny problem with this right now that can be fixed with a small change to the Listener (more on this in a seperate mail).
And finally to illustrate :COMPLAIN-ABOUT-EXISTING-PROCESS:
(climi::define-application-starter toolbox :function-name start-toolbox :default-process-name "cube-modeller toolbox" :complain-about-existing-process t)
For further review the expanded version of the Climacs example is attached to this mail.
Still simple, but nice nevertheless as this is a quite general application starter macro, and you all know the advantage of using a macro instead of duplicating code.
Clim Launcher
Together with the Launcher by Dwight Holman there is an additional benefit: The macro can announce the created starter to it. So that if you use it to define the function that fires up your GUI it will automatically displayed in the Clim Launcher.
As this is quite nice, I seperated my modefied version of the Clim Launcher from Clim Desktop and merged it with the DEFINE-APPLICATION-STARTER code. I propose to commit this as a new extension to the McCLIM repository itself. It's not really much code (172 lines altogether), and the barrier to use the macro should be as low as possible.
If you don't want the generated function to be announced to the Launcher you can specify :ANNOUNCE-TO-CLIM-LAUNCHER as nil. The Launcher itself should not be listed for example. Or you want to use the function only internally and have your application started via another function. In this case you can announce this function manually via (add-application "Beirc" #'beirc:beirc), for example. (This is also possible if you don't want to use the macro at all, of course.)
Current status
The current version is work in progress. (What else?) The Clim Launcher still depends on :clim-listener, :beirc, and :closure. If we agree to merge this code with McCLIM these dependencies should be removed, and the Listener, Beirc, Climacs, etc. should instead depend on :clim-launcher (and use DEFINE-APPLICATION-STARTER or CLIM-LAUNCHER:ADD-APPLICATION). The dependency to :climacs is already removed, you might want to evaluate the above example in the package denoted by "CLIMACS-GUI" and be impressed by the fact that a "button" will automatically manifest itself in the next turn of the Launcher's command loop.
Now a direct question: The macro DEFINE-APPLICATION-STARTER currently resides in the file clim-utilities.lisp together with the two functions FIND-PROCESS-WITH-NAME and DESTROY-PROCESS-WITH-NAME that it needs. These will be created in the package "CLIM-INTERNALS", which is not very nice, but on the other hand: The two functions are generally useful to interact with the threads that McCLIM provides in a portable way. (Perhaps we want them to be exported by the package "CLIM-SYS"?) And in order to use DEFINE-APPLICATION-STARTER it would be more nice to just use it as if it were part of the CLIM specification. But do we want it in the package "CLIM"? It is not part of the specification... Or should it just be in and exported by "CLIM-LAUCNHER", and everybody should :USE that package? What do you think? I'm indecisive..
Source code and a screen shot
The current version of the source codeis attached to this mail. It is also in my public flux directory http://matroid.org/flux/ as clim-launcher-20060124-01.tar.bzip2 (or newer). The extracted archive is here: http://matroid.org/flux/clim-launcher/
Here is a recent screenshot of some clim applications, including Closure, Beirc, the Listener and the Launcher, Climacs, and the LED Cube Modeller (including the File Selector):
http://matroid.org/flux/CLIM-Desktop-20060124-1.png (780 kB)
Entertainment
The first name of the macro hasn't been very nice: MAKE-RUN-GUI-DEFUN. So there has been a discussion[2] about it in #lisp. Proposals have been: DEFINE-APPLICATION-ENTRY, DEFINE-APPLICATION, DEFINE-APPLICATION-ENTRY-POINT, DEFINE-APPLICATION-ENTRY-FUNCTION, DEFINE-APPLICATION-STARTER-FUNCTION, EFINE-APPLICATION-STARTER, DEFINE-CLICKY-CLICK-THING, EFINE-APPLICATION-FIRESTARTER, DEFINE-APPLICATION-IGNITION, EFINE-DO-IT-TO-IT-FUNCTION, DEFINE-GUI-FIRE-UP-THINGIE, DEFINE-HEY-HO-LETS-GO, DEFINE-APPLICATION-INVOKER, DEFINE-APPLICATOR, DEFINE-APPLICATION-ANTI-TERMINATOR, DEFINE-APPLICATION-RUNNER, DEFINE-APPLICATION-INITIATOR, IVE-ME-AN-INITIATIR-FOR-MY-MIGHTY-GUI, AND DEFINE-APPLICATION-TOPLEVEL.
Well, although I really like DEFINE-CLICKY-CLICK-THING and DEFINE-HEY-HO-LETS-GO, I hope you are okay with DEFINE-APPLICATION-STARTER. (Or is DEFINE-APPLICATION-RUNNER really better? :) )
Comments and thoughts are welcome, of course. Bye, Max
Links: 1) http://blog.matroid.org/display/25 2) IRC context for the bored: http://meme.b9.com/cview.html?utime=3346791413&channel=lisp&start=33...
PS: So many words for such a simple thing.. Hrm..