screwlisp proposes kittens

Just draw an ellipse! Screwlisp’s Common Lisp Interface Manager McCLIM intro

Intro

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.

Start our clim lisp image outside of emacs

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-connecting 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))

Common Lisp class with a list of ellipses

(defclass ellipses-mixin () ((ellipses :initform '() :accessor ellipses)))

CLIM application-frame child of that class

(define-application-frame ellipses-frame
    (standard-application-frame ellipses-mixin) ()
  (:pane :application :display-function 'draw-ellipses))

Display-function

(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.)

A command that adds a slightly random ellipse

(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 one of these frames

(make-application-frame 'ellipses-frame)
(defparameter *ellipse-frame* *)

Add one ellipse manually

(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.

Finally, open that app!

(run-frame-top-level *ellipse-frame*)

Now quit lisp (M-x sli-disc) in emacs and go back to the image on its own

And 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!

Fin.

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