luv

Workshop wiki

cocoa.lisp

hal/sdl/cocoa.lisp

system luv · 19 definitions · on GitHub

Cocoa application lifecycle for SDL canvases hosted by a durable Lisp.

in-package#:luv
cffi:defcfun
"objc_getClass"%objc-get-class
:pointer
name:string
cffi:defcfun
"sel_registerName"%objc-selector
:pointer
name:string
cffi:defcfun
"objc_msgSend"%objc-send-object
:pointer
receiver:pointer
selector:pointer
cffi:defcfun
"objc_msgSend"%objc-send-boolean
:bool
receiver:pointer
selector:pointer
cffi:defcfun
"objc_msgSend"%objc-send-void
:void
receiver:pointer
selector:pointer
cffi:defcfun
"objc_msgSend"%objc-send-void-boolean
:void
receiver:pointer
selector:pointer
argument:bool
cffi:defcfun
"objc_msgSend"%objc-send-policy
:bool
receiver:pointer
selector:pointer
policy:long
defvar*cocoa-sdl-canvas-host*nil"The canvas currently owning SDL's process-global Cocoa event loop."
defvar*cocoa-sdl-canvas-host-lock*
sb-thread:make-mutex:name"luv Cocoa SDL canvas host"
defmethodclaim-sdl-canvas-host
sb-thread:with-mutex
when
error'canvas-error:canvascanvas:operation:open:reason:cocoa-host-busy:details
formatnil"~S already owns SDL's Cocoa event loop"*cocoa-sdl-canvas-host*
canvas
defuncocoa-application
%objc-send-object
%objc-get-class"NSApplication"
%objc-selector"sharedApplication"
defunset-cocoa-activation-policy
applicationpolicy
unless
%objc-send-policyapplication
%objc-selector"setActivationPolicy:"
policy
error"Cocoa refused application activation policy ~D."policy
defmethodprepare-sdl-canvas-host
call-next-method

SDL normally turns a command-line process into a permanent foreground Cocoa app. This Lisp is a durable REPL host, so we manage that policy around the actual lifetime of its windows instead.

unless
sdl3:set-hint"SDL_MAC_BACKGROUND_APP""1"
error"SDL Cocoa background-app hint failed: ~A"
sdl3:get-error
defmethodactivate-sdl-canvas-host:after

There is no cooperating foreground application to yield activation when a Slynk worker opens a window. This is an explicit user request, so use the same forceful activation that SDL uses for command-line Cocoa apps. A process transitioning out of background-only policy needs a few Cocoa event turns before Launch Services will honor activation, so pump briefly instead of leaving a regular-but-background window in another Stage.

when
let
looprepeat20until
%objc-send-booleanapplication
%objc-selector"isActive"
do
%objc-send-void-booleanapplication
%objc-selector"activateIgnoringOtherApps:"
t
sdl3:pump-events
sleep0.01

The primary method already requested this before activation; repeat it now that the application can actually make the window key.

sdl3:raise-window
sdl-canvas-windowcanvas
defmethoddeactivate-sdl-canvas-host
declare
ignorecanvas
let
%objc-send-voidapplication
%objc-selector"deactivate"