--- layout: ../Site.layout.js --- # Just draw an ellipse! Screwlisp's Common Lisp Interface Manager McCLIM intro - - «.intro» (to "intro") - - «.starting clim outside emacs» (to "starting clim outside emacs") - - «.lisp class w ellipses list» (to "lisp class w ellipses list") - - «.clim child of ellipses-mixin» (to "clim child of ellipses-mixin") - - «.display-function» (to "display-function") - - «.command random ellipse» (to "command random ellipse") - - «.make ellipses frame» (to "make ellipses frame") - - «.add one ellipse manually» (to "add one ellipse manually") - - «.open the app» (to "open the app") - - «.now disconnect emacs from lisp» (to "now disconnect emacs from lisp") ## Intro - - «intro» (to ".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](https://turtleware.eu)'s [McCLIM](https://codeberg.org/McCLIM/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](/programming/cl-series-ellipse-sampling) 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](https://metamodular.com/) 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 - - «starting clim outside emacs» (to ".starting clim outside 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](/momentary/eev-clim-kitten). 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)) ``` ## Common Lisp class with a list of ellipses - - «lisp class w ellipses list» (to ".lisp class w ellipses list") ``` (defclass ellipses-mixin () ((ellipses :initform '() :accessor ellipses))) ``` ## CLIM `application-frame` child of that class - - «clim child of ellipses-mixin» (to ".clim child of ellipses-mixin") ``` (define-application-frame ellipses-frame (standard-application-frame ellipses-mixin) () (:pane :application :display-function 'draw-ellipses)) ``` ## Display-function - - «display-function» (to ".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 - - «command random ellipse» (to ".command 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 ellipses frame» (to ".make ellipses frame") ``` (make-application-frame 'ellipses-frame) (defparameter *ellipse-frame* *) ``` ## Add one ellipse manually - - «add one ellipse manually» (to ".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! - - «open the app» (to ".open the 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 - - «now disconnect emacs from lisp» (to ".now disconnect emacs from lisp") 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](https://gamerplus.org/@screwlisp/114594982268789432) 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).