Skip to content

Instantly share code, notes, and snippets.

@jolby
Last active December 7, 2022 05:54
Show Gist options
  • Save jolby/e1cfb217a411603ed1ee446d9d483a6c to your computer and use it in GitHub Desktop.
Save jolby/e1cfb217a411603ed1ee446d9d483a6c to your computer and use it in GitHub Desktop.
Chat GPT McCLIM/SDL2 inner loop sketch
Me: We have a project using common lisp, in particular the McCLIM common lisp user interface
-------------
ChatGPT: McCLIM is a Common Lisp library for building user interfaces. It is based on the CLIM specification, which is a standard for building user interfaces in Lisp.
Some key features of McCLIM include:
Support for multiple display devices, including text-based and graphical displays
A rich set of widgets for building user interfaces, such as buttons, menus, and text fields
Support for internationalization and localization of user interfaces
Extensive documentation and examples to help users get started with building their own user interfaces
Using McCLIM, developers can build user interfaces that are highly customizable and tailored to their specific needs. It is a popular choice for building user interfaces in Common Lisp projects.
-------------
Me: We would like to create a backend interface for McCLIM. We will be using the SDL2 library and OpenGL for creating native windows and drawing. Write the inner loop handing SDL2 events using separate queues for input events and drawing commands.
-------------
ChatGPT: The inner loop for handling SDL2 events and drawing commands with McCLIM would look something like this:
(defun main-loop ()
(let ((input-event-queue (make-queue))
(drawing-command-queue (make-queue)))
(loop
(when (sdl2:sdl-poll-event event)
(case (sdl2:event-type event)
(sdl2:event-type-quit
(return))
(sdl2:event-type-keydown
(enqueue input-event-queue event))
(sdl2:event-type-mousebuttondown
(enqueue input-event-queue event))
(sdl2:event-type-mousemotion
(enqueue input-event-queue event))))
(when (not (queue-empty-p drawing-command-queue))
(let ((command (dequeue drawing-command-queue)))
(execute-drawing-command command)))
(when (not (queue-empty-p input-event-queue))
(let ((event (dequeue input-event-queue)))
(handle-input-event event)))
(sdl2:sdl-gl-swap-window))))
------------------
Me: Change the case statement to dispatch events using CLOS.
------------------
ChatGPT: We can use the Common Lisp Object System (CLOS) to dispatch events in the main loop by defining a generic function for handling events and creating methods for each type of event.
Here is an example of how this could be done:
(defgeneric handle-event (event))
(defmethod handle-event ((event sdl2:quit-event))
(return))
(defmethod handle-event ((event sdl2:keydown-event))
(enqueue input-event-queue event))
(defmethod handle-event ((event sdl2:mousebuttondown-event))
(enqueue input-event-queue event))
(defmethod handle-event ((event sdl2:mousemotion-event))
(enqueue input-event-queue event))
(defun main-loop ()
(let ((input-event-queue (make-queue))
(drawing-command-queue (make-queue)))
(loop
(when (sdl2:sdl-poll-event event)
(handle-event event))
(when (not (queue-empty-p drawing-command-queue))
(let ((command (dequeue drawing-command-queue)))
(execute-drawing-command command)))
(when (not (queue-empty-p input-event-queue))
(let ((event (dequeue input-event-queue)))
(handle-input-event event)))
(sdl2:sdl-gl-swap-window))))
In this updated version of the main loop, we define a handle-event generic function and create methods for each of the supported event types. When an event is received, the handle-event function is called and the appropriate method is called based on the type of the event.
This allows us to easily add or remove event handling methods without changing the main loop itself. It also makes the code more readable and maintainable.
-------------------
Me: Now protect the inner loop with restarts. We want restart handlers for application error conditions.
-------------------
ChatGPT: We can protect the main loop with restarts to provide more control over how application errors are handled. Here is an example of how this could be done:
(defun main-loop ()
(handler-case
(let ((input-event-queue (make-queue))
(drawing-command-queue (make-queue)))
(loop
(when (sdl2:sdl-poll-event event)
(handle-event event))
(when (not (queue-empty-p drawing-command-queue))
(let ((command (dequeue drawing-command-queue)))
(execute-drawing-command command)))
(when (not (queue-empty-p input-event-queue))
(let ((event (dequeue input-event-queue)))
(handle-input-event event)))
(sdl2:sdl-gl-swap-window)))
(error (condition)
(restart-case condition
(continue ()
(format t "An error occurred, but the application will continue.")
(continue))
(abort ()
(format t "An error occurred, the application will abort.")
(abort))
(retry ()
(format t "An error occurred, retrying the operation.")
(retry))))))
In this updated version of the main loop, we wrap the entire loop body in a handler-case form. This allows us to define a restart-case form that provides restart handlers for different error conditions.
In this example, we have defined three restart handlers: continue, abort, and retry. The continue restart simply continues execution of the main loop, the abort restart exits the application, and the retry restart repeats the current iteration of the main loop.
If an error occurs during execution of the main loop, the restart-case form is invoked and the user can choose which restart handler to use. This provides more control over how application errors are handled, and can help prevent the application from crashing or entering an unstable state.
-----------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment