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..
Generally, I think your idea is very cool. A standardized way to start applications (apart from `run-frame-toplevel') would be highly useful. I do, however, have a request:
Max-Gerd Retzlaff m.retzlaff@gmx.net writes:
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.
This functionality should not be wired to a specific launcher program. Instead, McCLIM should maintain an *application-entry-points* alist that maps application names to functions. Thereby, any CLIM-application will be able to retrieve a list of the programs available. This would also open for the possibility of creating alternative launcher programs.
Hi,
I have not much time to write right now but there is a new version and I want to inform you about it so that you do not spend thought on things that are already changed.
I've had a discussion with Timothy Moore in #lisp. His idea has been:
<moore33> mgr: I mean that launch-application could be a generic function that does what the code generated by your macro does, with all the flexibility that implies. Not that I care very much, but these days I tend to think about protocols before I think about macros.
(The discussion is logged, here is a direct link: http://meme.b9.com/cview.html?channel=lisp&utime=3347129927#utime_reques... )
Afterwards I have rewritten the stuff in clim-utilities.lisp; please, have a look at the file in the attached archive or at: http://matroid.org/flux/clim-launcher/clim-utilities.lisp
(The archive i is also in my public flux directory http://matroid.org/flux/ as clim-launcher-20060125-01.tar.bzip2 (or newer).)
Now there is the generic function LAUNCH-APPLICATION, the most generic method of it consists basically of the code the previous version of the DEFINE-APPLICATION-STARTER macro has generated, only more general.
You can know just execute (climi::launch-application 'climacs-gui:climacs :new-process t) to start Climacs, without the need to define a custom starter function. In this case you have to announce your application manually with something like: (clim-launcher:add-application "Climacs" ;; (See [1].) (lambda () (climacs-gui::climacs :new-process t)))
To create a custum starter function nevertheless, DEFINE-APPLICATION-STARTER does still exist, although it has been changed to use LAUNCH-APPLICATION. (It will still announce the application by default, of course.)
Using a generic method has the huge benefit that the starter can now be modified for each application frame. Think of Beirc, which wants to make a separate thread for the IRC connection on its start-up.
Another example is Clouseau that needs an object to inspect as an argument. We can now modify LAUNCH-APPLICATION and put the argument :object into the (also new) ARGUMENTS-FOR-APPLICATION-FRAME-CREATION argument for the generic LAUNCH-APPLICATION method:
-- zipp --
;;; Clouseau example (in-package :clouseau)
(climi::define-application-starter inspector :function-name inspector)
(in-package :climi)
(defmethod launch-application :around ((application-frame-name (eql 'clouseau::inspector)) &rest rest &key arguments-for-application-frame-creation &allow-other-keys) "This method will put the :OBJECT argument into :ARGUMENTS-FOR-APPLICATION-FRAME-CREATION" (let ((object (getf rest :object))) (when object (setf (getf arguments-for-application-frame-creation :obj) object ;; ensure that its in the list: (getf rest :arguments-for-application-frame-creation) arguments-for-application-frame-creation))) ;; call the real thing (apply #'call-next-method application-frame-name rest))
-- zapp --
We can now start Clouseau with (climi::launch-application 'clouseau:inspector :new-process t :object 'dudel) or via the custom generated function (clouseau:inspector :object 'tada :new-process t)
Comments are welcome. Bye, Max
1) The name ADD-APPLICATION should be renamed as well. I like ANNOUNCE-APPLICATION, but how will DELETE-APPLICATION then be called? Perhaps we should take REGISTER-APPLICATION and DEREGISTER-APPLICATION, although I prefer "announce"..
Hello
On Tue, Jan 24, 2006 at 04:03:00PM +0100, Troels Henriksen wrote:
Generally, I think your idea is very cool. A standardized way to start applications (apart from `run-frame-toplevel') would be highly useful.
Thank you.
I do, however, have a request:
Max-Gerd Retzlaff m.retzlaff@gmx.net writes:
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.
This functionality should not be wired to a specific launcher program. Instead, McCLIM should maintain an *application-entry-points* alist that maps application names to functions. Thereby, any CLIM-application will be able to retrieve a list of the programs available. This would also open for the possibility of creating alternative launcher programs.
This is perfectly possible. Think of CLIM-LAUNCHER as just what you want + a simplistic standard GUI. The list of applications ist called clim-launcher::*applications* (though it is not an association list right now but a list of application objects (this is part of what Dwight has written)), and the interface function to add and delete applications are currently named ADD-APPLICATION and DELETE-APPLICATION (see the footnote in my other, just sent mail about the names).
I've just seperated both parts: The "backend" has right now got 39 lines of code, and the current GUI consists of 45 lines. To separate the parts is a good idea, and I have just done that in my private directory. Though I would like to have this very simple GUI interface included directly into McCLIM.
This doesn't mean that there cannot be another shiny, flashing "launch bar" that is available via a separate package.
Bye, Max
I'm trying to get a bit familiar with clim. I wonder about the user interface. The usual way in "normal" applications to get extra user inpt is via Dialog boxes. Now as I understand this is not the clim way it seems you use a interactor pane for it. I just wonder if I have overlooked something which may allow a more "dialog" oriented way..
Thanks Friedrich
Friedrich Dominicus frido@q-software-solutions.de wrote:
I'm trying to get a bit familiar with clim. I wonder about the user interface. The usual way in "normal" applications to get extra user inpt is via Dialog boxes. Now as I understand this is not the clim way it seems you use a interactor pane for it. I just wonder if I have overlooked something which may allow a more "dialog" oriented way..
Just wrap your accept calls in
(accepting-values (stream :own-window t) ...)
Then a dialog window will pop up.
Oh, well it's that simply. Thanks I'll try it.
Regards Friedrich