Lean runs main on a helper thread, which Cocoa rejects for video init;
export LEAN_MAIN_USE_THREAD=0 from the justfile on macOS. Wait for the
camera permission event before reading the camera format, since SDL
grants access asynchronously.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The opaque Pixels type wrapped a void* pointing into an SDL_Surface's
pixel buffer, but nothing tied the Pixels lifetime to the surface. If
the GC collected the surface first, the Pixels pointer would dangle,
causing use-after-free.
Replace with two safe alternatives:
- updateTexture now takes a ByteArray (Lean-owned, GC-managed buffer)
plus pitch, matching how Haskell's sdl2 uses ByteString and Rust's
rust-sdl2 uses &[u8]. This is faithful to SDL_UpdateTexture's general
void* interface but requires copying pixels into a ByteArray first.
- updateTextureFromSurface is a new zero-copy convenience that takes an
SDLSurface directly. The C side extracts both pixels and pitch from
the surface internally. Because the surface is borrowed (@&) for the
call's duration, the GC cannot collect it mid-use. This is not
strictly faithful to SDL_UpdateTexture's C API, but is the common
case and avoids an unnecessary memcpy.
Also removes: Pixels type, Pixels.nonemptyType, sdl_pixels_external_class,
sdl_Surface_get_pixels, and the pixels_external_class registration in
sdl_init.
WebcamApp.lean is updated to use updateTextureFromSurface.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a Lean extern parameter lacks @&, Lean increments the refcount
before the call and expects the C callee to lean_dec it. If the C side
declares b_lean_obj_arg (borrowed) and never decrements, the refcount
stays elevated and the object is never freed.
Add @& (borrow annotation) to parameters where C only reads the value:
- createWindow/createWindowAndRenderer: title String was owned but C
only calls lean_string_cstr (borrowed read). Leaked the string.
- renderTextureRect: sourceRect and destRect SDLFRect were owned but C
only reads scalar fields via lean_ctor_get_float. These are typically
constructed fresh each frame, so this leaked two rect objects per
frame (~48 bytes each at 60fps = ~5.6 KB/s).
- setRelativeMouseMode: window SDLWindow was owned but C only reads the
external data pointer. Leaked the window's refcount.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>