A GUI toolkit for Common Lisp


McCLIM 0.9.9 "Ostara" release

Written by Daniel Kochmański on 2025-03-11 15:00

Table of Contents

  1. Changes
    1. More strict processing of geometry changes, repaints and recording
    2. Dynamic slots for medium state and the current text line
    3. Thread-safe output history and drawing context
    4. Refactored text renderer for performance and alternative text directions
    5. New demos
  2. Future changes
    1. The repaint queue
    2. Input editing streams rewrite
    3. SDL2 backend and keyboard layouts
  3. Closing remarks

Dear All,

After a year of development it is time to make a release. The codename of this version is "Ostara", after the second of the eight annual pagan holidays celebrating the arrival of spring. Ostara was a Germanic goddess representing rebirth and is the equivalent of Easter.

In this release we mainly focus on robustness with numerous bugs fixed and a few features implemented. Most notably McCLIM streams are now thread-safe to write to and to draw on. Here is the list of committers and their number of commits since the last release:

Daniel Kochmański (502), Charlie McMackin (15), Andrea Demichele (2), John Carroll (1), José M. Á. Ronquillo Rivera (1) and Robert Brown (1).

This is not an exhaustive list of contributors, as it does not list people who reported issues, updated the wiki, or performed other non-coding tasks. Thank you! Moreover I'd like to thank people who donate money to my Patreon page, your continuous support means a lot to me.

Changes

For a detailed list of changes, consult the NEWS file or the git log directly. Below is a high-level overview of these changes.

More strict processing of geometry changes, repaints and recording

This is the least visible change because it pertains to how we process updates to states of CLIM stream panes. Previously when the program added new output, the pane was resized immediately, followed by scrolling and repainting. That was clearly suboptimal, especially when there is a lot of changes done in a short period of time. Instead, we now batch these changes and execute them when STREAM-FINISH-OUTPUT is called. That greatly improves performance and saves visual glitches for certain scenarios.

Dynamic slots for medium state and the current text line

To enable concurrent drawing threads, we needed to ensure that there are no races regarding drawing options (like the drawing ink or the text style). To do that, CLIM stream panes have a slot that contains an instance of a class that has dynamic slots (for how this work see my blog post). This allows for drawing and writing text to streams concurrently from multiple threads. For example:

In this demo we have seven concurrent threads:

  • two threads print 1000 lines with prefixes "XXX" and "YYY"
  • four threads drawing dots in different colors
  • one thread monitors the current progress of printing lines

Note that we may also scroll the output while these threads are still running and modifying the sheet. The cursor is not corrupted and the output proceeds without glitches.

Thread-safe output history and drawing context

Modifications to the output record history and writing pixels on a buffer are mutually exclusive operations protected with locks. For forward compatibility, all repaint requests by the program should be issued with DISPATCH-REPAINT. Moreover the user program should not directly use operators that change the output recording state of the stream.

Notice how multiple threads are modifying the sheet geometry and the cursor position. The output record history is a bottleneck because each thread, after drawing, needs to take the lock and update the record. This is suboptimal, but enables us to quickly write throwaway code like this:

(in-package "CLIM-USER")

(defparameter *stream* (open-window-stream :width 800 :height 600))
(defparameter *stop* t)

(defun woosh (id ink)
  (setf *stop* nil)
  (with-drawing-options (*stream* :ink ink)
    (loop while (null *stop*) do
      (updating-output (*stream* :unique-id id :fixed-position t)
        (format *stream* "Time: ~a~%" (get-internal-real-time)))
      (sleep 1/30))))

(bt:make-thread (lambda () (woosh :thread-1 +dark-red+)))
(bt:make-thread (lambda () (woosh :thread-2 +dark-blue+)))

and in my opinion it is great for prototyping, because you can add additional elements while the program is running without invoking arcane protocols.

Refactored text renderer for performance and alternative text directions

The text renderer has been refactored to achieve better performance and exploit optimization opportunities when they are presented. For example a different code path is executed when the text is not translucent.

That said, the most notable change with the text renderer is the ability to change the line and the page directions:

These changes apply to DRAW-TEXT. Line-oriented integration with CLIM streams that allows mixing the text that has different directions is not yet implemented, but we can already mix text and graphics, and the latter will be correctly wrapped along the text when necessary.

Mixing in graphics in a text line

New demos

I wrote new demos that may be started from the system clim-examples:

  • incremental redisplay: demonstrates how to work with output record caches
  • animation with pulse: an animation with a timer synchronizing redisplay
  • concurrent drawing: a demo where we can spin any number of drawing threads
  • concurrent writing: a stress test for concurrent writing lines to a stream
  • concurrent griding: a stress test with concurrent drawing with many records

Future changes

The repaint queue

The thread-safety of CLIM streams is factored out from a branch repaint-queue. This branch works, but it still has various regressions that need to be addressed before merging. The results are very promising and its effect compounds with thread-safety, because drawing locks the output history far less often, while recording is rather cheap.

Input editing streams rewrite

This work is mostly done but it needs more testing and there are a few bugs that need to be addressed before merging. This change involves also better command completions that include a fuzzy completer, and makes text editing much easier. If you want to see the current state of it check out input-editing branch.

SDL2 backend and keyboard layouts

I didn't work on either of these tasks since the last release, but I plan to finish them after merging branches repaint-queue and input-editing. After finishing SDL2 branch and keyboard layouts I want to make the next release.

Closing remarks

McCLIM improves on a daily basis, and this trend continues. I'm very happy that I've been able to make a timely release unlike the last one. Fixing numerous issues further accelerates other improvements. From my subjective perspective the software is much more resilient than a year ago.

You may grab the latest release from here: https://codeberg.org/McCLIM/McCLIM/releases/tag/0.9.9-ostara.

Best regards,
Daniel Kochmański