# Windowing Backends SimVX ships three Vulkan windowing backends behind a single `WindowBackend` protocol (`simvx.graphics.platform._base`). The default selection order is **SDL3 → GLFW → Qt** (`platform/__init__.py:_BACKENDS`), and the first import that succeeds wins. You can pin one explicitly: ```python from simvx.graphics import App app = App(width=1280, height=720, title="Game", backend="glfw") ``` Each backend implements every method of the `WindowBackend` Protocol; the matrix below describes *behaviour* and *feature coverage*, not protocol completeness. ## Feature matrix Legend: ✓ supported · partial · ✗ not supported. | Capability | SDL3 | GLFW | Qt (PySide6) | |-----------------------------|-------------------|-------------------|-------------------| | Keyboard input | ✓ | ✓ | ✓ | | Mouse buttons + cursor pos | ✓ | ✓ | ✓ | | Mouse scroll wheel | ✓ | ✓ | ✓ (mouse_button) | | Cursor shape | ✓ | ✓ | ✓ | | Gamepad (buttons + axes) | ✓ | ✓ | ✗ | | Touch events | ✓ (`set_touch_callback`) | ✗ | ✗ | | IME / text input (Unicode) | ✓ (always-on; see TODO #181) | ✓ (always-on) | ✓ | | Clipboard read/write | ✗ (use OS shim) | ✗ (use OS shim) | ✗ (use OS shim) | | Drag-and-drop (file paths) | ✗ | ✗ | ✗ | | Native file dialogs | ✗ (use SimVX UI `FileBrowser`) | ✗ (use SimVX UI `FileBrowser`) | ✗ (use SimVX UI `FileBrowser`) | | Multi-window | ✗ (single window) | ✗ (single window) | ✗ (single window) | | Headless / hidden window | ✓ (`visible=False`) | ✓ (`visible=False`) | partial (Qt creates a real window) | | Fullscreen toggle | ✗ | ✓ (`set_fullscreen`) | ✗ | | App lifecycle hooks | ✓ (`set_lifecycle_callback`, mobile) | ✗ | ✗ | | Pause-when-backgrounded | ✓ (`paused`) | ✗ | ✗ | | HiDPI content scale | ✓ | ✓ | ✓ | | Vulkan surface creation | ✓ | ✓ | ✓ | ## When to pick each backend SimVX is backend-agnostic: any windowing library that can hand out a Vulkan surface works. The three implementations shipped today differ only in their input/lifecycle feature set: - **SDL3: default at autoselect time.** Picked first because it is the only backend with multi-touch (mobile, touchscreen kiosks) and full app-lifecycle callbacks. Loaded via `PySDL3`; falls back to GLFW if the binding is missing. - **GLFW: desktop fallback.** Smaller dependency, faster cold start, and the only backend with built-in fullscreen toggle. Use for kiosk-style desktop apps and headless rendering. No touch and no app-lifecycle callbacks. - **Qt (PySide6): embedding into Qt host apps.** Pick this only when the Vulkan surface needs to live inside an existing Qt main loop (third-party tooling). Touch, gamepad, fullscreen toggle, and headless are all missing : `App(visible=False)` will still spawn a window. PySide6 is an optional install (`simvx-graphics[qt]`). ## Headless rendering All three backends support an invisible window via `App(visible=False)` and `App.run_headless(scene, frames=N)`, but only SDL3 and GLFW honour the window-visibility flag fully. Qt creates a real (off-screen-positioned) window because PySide6 cannot create a Vulkan-capable surface without one. For CI and pytest captures use SDL3 or GLFW. ## Gaps tracked in `TODO.md` - Per-focus SDL3 text input toggle (mobile IME flicker): see `## Cross-Platform Preparation`. - Drag-and-drop file path delivery, not yet plumbed on any backend. - Multi-window: out of scope until the multi-threaded renderer entry lands.