Skip to content

ui/sdl2: add Pebble watch-frame window decorations - #1

Merged
gmarull merged 1 commit into
coredevices:pebble-10.1from
teslabs:qemu-deco
May 8, 2026
Merged

ui/sdl2: add Pebble watch-frame window decorations#1
gmarull merged 1 commit into
coredevices:pebble-10.1from
teslabs:qemu-deco

Conversation

@gmarull

@gmarull gmarull commented May 8, 2026

Copy link
Copy Markdown
Member

Wrap the SDL2 display in a borderless, shaped window that renders a watch-frame PNG around the guest framebuffer. The frame area drags the window via SDL_SetWindowHitTest; configured button hot-zones synthesize back/up/select/down key events; a small close icon at the top-right shuts the VM down.

Selection is via -display sdl,decoration=. Built-in presets ship under pc-bios/pebble-decorations/:

  • pt2-sb, pt2-br : Pebble Time 2 (200x228 framebuffer)
  • pr2-bk20, pr2-gd14 : Pebble Round 2 (260x260 round, inscribed-circle shape mask so framebuffer corners stay clipped)
  • p2d-bk, p2d-wh : Pebble Flint (144x168)

The framebuffer renders at native pixel size; the PNG is scaled per axis so its inner screen rect lines up with the framebuffer. PNG alpha is binarized at load time and at shape-mask build time so the watch silhouette has crisp edges with no halo on a black-cleared canvas.

Also fix an upstream-style bug exposed by the shaped window: PIXMAN x8r8g8b8 / x8b8g8r8 / r8g8b8x8 surfaces were being mapped to SDL ARGB/ ABGR/RGBA8888, so the don't-care byte was interpreted as alpha. With sdl2-compat treating rendered alpha as window transparency, every black framebuffer pixel became invisible. Map the X-byte formats to the matching SDL XRGB/XBGR/RGBX8888 instead.

@gmarull
gmarull requested a review from jplexer May 8, 2026 13:05
@gmarull
gmarull force-pushed the qemu-deco branch 2 times, most recently from 0cfb24b to 656aae4 Compare May 8, 2026 13:52
Wrap the SDL2 display in a borderless, shaped window that renders a
watch-frame PNG around the guest framebuffer. The frame area drags the
window via SDL_SetWindowHitTest; configured button hot-zones synthesize
back/up/select/down key events; a small close icon at the top-right
shuts the VM down.

Selection is via -display sdl,decoration=<name>. Built-in presets ship
under pc-bios/pebble-decorations/:

  - pt2-sb, pt2-br : Pebble Time 2 (200x228 framebuffer)
  - pr2-bk20, pr2-gd14 : Pebble Round 2 (260x260 round, inscribed-circle
    shape mask so framebuffer corners stay clipped)
  - p2d-bk, p2d-wh : Pebble Flint (144x168)

The framebuffer renders at native pixel size; the PNG is scaled per
axis so its inner screen rect lines up with the framebuffer. PNG alpha
is binarized at load time and at shape-mask build time so the watch
silhouette has crisp edges with no halo on a black-cleared canvas.

Two transparency paths, one per host:

  - Linux/X11: SDL_CreateShapedWindow + binary alpha mask clip the
    silhouette at the WM level, the existing path.
  - macOS: libsdl.org SDL 2.32 doesn't honor SDL_WINDOW_TRANSPARENT
    (an SDL3-only flag) and its NSWindow setup leaves the contentView
    opaque even with NSWindow.opaque=NO. ui/sdl2-cocoa.m replaces
    contentView with a custom NSView that paints a per-frame CGImage
    via drawRect: through NSGraphicsContext (the only path that
    preserves per-pixel alpha on this combination). SDL's original
    SDLView is re-hosted as a fullsize subview with alphaValue=0 so
    NSResponder hooks (mouse, keyboard, SDL_SetWindowHitTest) keep
    firing without painting over our view. The frame is composited in
    software by sdl2_decoration_compose() since no SDL renderer exists
    on this path.

Also fix an upstream-style bug exposed by the shaped window: PIXMAN
x8r8g8b8 / x8b8g8r8 / r8g8b8x8 surfaces were being mapped to SDL ARGB/
ABGR/RGBA8888, so the don't-care byte was interpreted as alpha. With
sdl2-compat treating rendered alpha as window transparency, every black
framebuffer pixel became invisible. Map the X-byte formats to the
matching SDL XRGB/XBGR/RGBX8888 instead.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>
@gmarull
gmarull merged commit 7c04655 into coredevices:pebble-10.1 May 8, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant