Three fixes:
1. **Flickering (every-other-frame)**: Swapchain slots were dropped
immediately after page_flip, setting acquired=false so the next
acquire() could return the same GBM BO currently being scanned out
by the CRTC. Added current_slot field to EventLoopData that holds
the submitted slot until the next frame replaces it, preventing
buffer reuse during scanout.
2. **Missing keyboard_key action**: The DRM codepath was missing the
'keyboard_key' custom action handler that nested.rs has. Added it
with evdev→XKB keycode conversion and keyboard.input() dispatch.
3. **Maximize alignment**: DRM maximize was clamping to size hints and
centering horizontally, while nested.rs uses full output width.
Aligned to match nested.rs behavior.
4. **z_order sorting**: Electron window rendering now sorts by z_order
to match nested.rs's chain+sort approach.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two critical bugs causing a black/off screen:
1. [[root]] window configs were spawned as Electron processes but never
added to config.windows. The render loop, window_mapped state, and
respawn logic all iterate config.windows — so root windows were
invisible. Fix: merge root entries (with fullscreen geometry and low
z_order) into config.windows before WoState::new(), so all subsystems
see them uniformly.
2. When the display manager (Ly) leaves the CRTC in a state Smithay
considers 'already committed' (matching mode/connectors),
commit_pending() returns false and only page_flip() is used.
page_flip without a prior modeset can 'succeed' but produce no
visible output because the CRTC was never properly activated with
a framebuffer. Fix: force a full modeset commit (ALLOW_MODESET) on
the very first frame (total_flips==0) regardless of commit_pending.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Three bugs addressed:
1. SO_RCVTIMEO(5s) on the IPC socket was never cleared after the HELLO
handshake. When the web page becomes static (no paint events for >5s),
the blocking read_exact in recv_message times out, the IPC reader thread
exits, and the socket is closed — causing ECONNRESET on the Electron
side and permanently stalling frame delivery. Fix: clear SO_RCVTIMEO
to zero (infinite) immediately after successful HELLO exchange.
2. If a VBlank event is lost or delayed (e.g. during DRM master transitions),
vblank_pending stays true and all subsequent render_frame calls bail out
permanently. Fix: if vblank_pending has been stuck for >500ms, force-clear
it with a warning so rendering can resume.
making it impossible to diagnose the black screen from logs. Fix: add
INFO-level logging for first render, first page flip, first texture
import, swapchain exhaustion on first frame, and vblank recovery events.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Three root causes prevented Electron frames from reaching the compositor:
1. --disable-gpu killed Chromium's rendering pipeline, preventing the
'paint' event from firing in offscreen mode. Replaced with
--use-gl=swiftshader so Chromium can composite internally while the
native wo_dmabuf module handles GPU buffer allocation separately.
2. DISPLAY=:0 with no X server caused Electron to fail silently on
pure Wayland sessions (Ly/logind). Replaced with
--ozone-platform=headless which lets Chromium's OSR pipeline work
without any display server connection.
3. WO_DRM_RENDER_NODE was never set, so the native wo_dmabuf.node
module always defaulted to /dev/dri/renderD128 regardless of which
GPU the compositor actually opened. Now resolved via sysfs
(card1 -> renderD128, card2 -> renderD129, etc.) and passed through
to Electron.
Also: retry EACCES/EPERM as transient during DRM device open (logind
session activation can lag behind libseat's is_active() flag on Ly).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>