As I have said before, it is a bit of a misrepresentation of the common lisp interface manager spec to just draw an ellipse, though that is certainly very easy to do. Here is a very minimal application example though. We are of course using JackDanielâs McCLIM implementation of the spec. In a gist, we are going to make a GUI application with a button that issues a command that adds a random ellipse, somewhat similar to my cl-series-pure-lisp one but using common lisp interface manager drawing equipment in a CLIM application-frame
instead. Key features are the common lisp object system class integration and simply added interactive button, and threadsafe execute-frame-command
.
As a quick note about historical context, while McCLIM hails originally from Strandh in 1996, the clim spec was and is the modern progeny of lispâs/lisp machinesâ dynamic-windows from the 80s.
Well, honestly inside emacs in this case, but it could have been outside of emacs. Starting lisp in a way emacs needs to explicitly separately connect to. I guess you recognize this from over here. And then slime-connect
ing to the running common lisp image, that has McCLIM in it and started a swank server i.e. for emacs to connect to.
(eepitch-shell)
ecl
(require "asdf")
(asdf:load-system :mcclim)
(asdf:system-source-directory :swank)
(merge-pathnames #p"*.*" *)
(directory *)
(merge-pathnames #p"start-swank.lisp" **)
(load *)
(slime-connect "localhost" 4005)
(setq eepitch-buffer-name "*slime-repl ECL*")
(in-package :clim-user)
(print '(I can see this is working))
(defclass ellipses-mixin () ((ellipses :initform '() :accessor ellipses)))
application-frame
child of that class(define-application-frame ellipses-frame
(standard-application-frame ellipses-mixin) ()
(:pane :application :display-function 'draw-ellipses))
(defmethod draw-ellipses ((obj ellipses-frame) pane)
(loop :for ellipse :in (ellipses obj) :do
(apply 'draw-ellipse* pane ellipse)))
(The clim idiom is to :incremental-redraw t .. updating-output
but that is its own kettle of fish. This is fine indicatively for now.)
(define-ellipses-frame-command
(com-add-random-ellipse :menu t :name t)
()
(let ((frame *application-frame*)
(ellipse (list (1+ (random #o200)) ; cx
(1+ (random #o200)) ; cy
(1+ (random #o200)) ; rdx1
(1+ (random #o200)) ; rdx2
(1+ (random #o200)) ; rdy1
(1+ (random #o200)) ; rdy2
)))
(push ellipse (ellipses frame))))
(make-application-frame 'ellipses-frame)
(defparameter *ellipse-frame* *)
(execute-frame-command *ellipse-frame* '(com-add-random-ellipse))
There is no special reason to do this except to see execute-frame-command
. Note that anything that goes through execute-frame-command
is threadsafe by McCLIM - super handy.
(run-frame-top-level *ellipse-frame*)
M-x sli-disc
) in emacs and go back to the image on its ownAnd reopen the frame from the âexternalâ lisp image
(eepitch-shell)
(in-package :clim-user)
(run-frame-top-level *ellipse-frame*)
Our ellipse and functionality introduced inside emacs is still there!
See you on the Mastodon to talk about this example too everyone. If you need a push to get started especially. NOT SALTY AT ALL ABOUT MY EXPERIENCE REPORT ON MIXINS AND CLIM PRESENTATIONS BEING BETTER-LUCK-NEXT-YEARâD BY ONE REVIEWER AT ELS2025 (thank-you for your notes).
screwlisp proposes kittens