diff options
| author | Valentin Popov <valentin@popov.link> | 2026-06-23 22:56:40 +0300 |
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2026-06-23 22:56:40 +0300 |
| commit | 4d19728c392c6566358ad78f30bba769f8e723cf (patch) | |
| tree | 04b67eb48f476d7189231dfdbb1f38e8edbc0c56 /adapters/fparkan-platform-winit | |
| parent | 54f07ee3be4c9aad41181ed46b50d273c10767bd (diff) | |
| download | fparkan-4d19728c392c6566358ad78f30bba769f8e723cf.tar.xz fparkan-4d19728c392c6566358ad78f30bba769f8e723cf.zip | |
feat: create native smoke window handles
Diffstat (limited to 'adapters/fparkan-platform-winit')
| -rw-r--r-- | adapters/fparkan-platform-winit/src/lib.rs | 144 |
1 files changed, 142 insertions, 2 deletions
diff --git a/adapters/fparkan-platform-winit/src/lib.rs b/adapters/fparkan-platform-winit/src/lib.rs index d8efa3e..30c5497 100644 --- a/adapters/fparkan-platform-winit/src/lib.rs +++ b/adapters/fparkan-platform-winit/src/lib.rs @@ -28,9 +28,12 @@ use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use std::collections::VecDeque; use std::sync::atomic::{AtomicU64, Ordering}; use std::time::{SystemTime, UNIX_EPOCH}; +use winit::application::ApplicationHandler; +use winit::dpi::PhysicalSize as WinitPhysicalSize; use winit::event::{Event, MouseButton, WindowEvent}; +use winit::event_loop::{ActiveEventLoop, EventLoop}; use winit::platform::scancode::PhysicalKeyExtScancode; -use winit::window::Window; +use winit::window::{Window, WindowId}; static NEXT_WINDOW_HANDLE_ID: AtomicU64 = AtomicU64::new(1); const DEFAULT_SMOKE_WIDTH: u32 = 1280; @@ -184,8 +187,115 @@ impl WinitWindowPlan { } } +/// Native smoke window creation result. +#[derive(Clone, Copy, Debug)] +pub struct WinitSmokeWindowProbe { + /// Validated creation plan. + pub plan: WinitWindowPlan, + /// Captured window descriptor. + pub window: WinitWindow, +} + +impl WinitSmokeWindowProbe { + /// Returns raw native handles captured from the native window. + #[must_use] + pub fn native_handles(&self) -> Option<NativeWindowHandles> { + self.window.native_handles() + } +} + +/// Creates a native smoke window, captures raw handles, then exits the event loop. +/// +/// # Errors +/// +/// Returns [`PlatformError`] when the plan is invalid, the event loop/window +/// cannot be created, or raw native handles are unavailable. +pub fn probe_smoke_window() -> Result<WinitSmokeWindowProbe, PlatformError> { + let plan = WinitWindowPlan::smoke().validate()?; + let event_loop = EventLoop::new().map_err(|err| PlatformError::Backend { + context: "winit event loop", + message: err.to_string(), + })?; + let mut app = SmokeWindowApp::new(plan); + event_loop + .run_app(&mut app) + .map_err(|err| PlatformError::Backend { + context: "winit event loop", + message: err.to_string(), + })?; + app.into_probe() +} + +struct SmokeWindowApp { + plan: WinitWindowPlan, + window: Option<WinitWindow>, + error: Option<String>, +} + +impl SmokeWindowApp { + const fn new(plan: WinitWindowPlan) -> Self { + Self { + plan, + window: None, + error: None, + } + } + + fn into_probe(self) -> Result<WinitSmokeWindowProbe, PlatformError> { + if let Some(message) = self.error { + return Err(PlatformError::Backend { + context: "winit smoke window", + message, + }); + } + let window = self.window.ok_or_else(|| PlatformError::Backend { + context: "winit smoke window", + message: "event loop exited before creating a window".to_string(), + })?; + if self.plan.requires_native_handles && window.native_handles().is_none() { + return Err(PlatformError::Backend { + context: "winit smoke window", + message: "native window/display handles are unavailable".to_string(), + }); + } + Ok(WinitSmokeWindowProbe { + plan: self.plan, + window, + }) + } +} + +impl ApplicationHandler for SmokeWindowApp { + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + if self.window.is_some() || self.error.is_some() { + event_loop.exit(); + return; + } + let attributes = Window::default_attributes() + .with_title("FParkan Vulkan smoke") + .with_inner_size(WinitPhysicalSize::new(self.plan.width, self.plan.height)); + match event_loop.create_window(attributes) { + Ok(window) => { + self.window = Some(WinitWindow::from_window(&window)); + } + Err(err) => { + self.error = Some(err.to_string()); + } + } + event_loop.exit(); + } + + fn window_event( + &mut self, + _event_loop: &ActiveEventLoop, + _window_id: WindowId, + _event: WindowEvent, + ) { + } +} + /// Minimal window view over a `winit` window. -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub struct WinitWindow { handle: WindowHandle, width: u32, @@ -344,6 +454,36 @@ mod tests { } #[test] + fn smoke_window_app_requires_created_native_window() { + let app = SmokeWindowApp::new(WinitWindowPlan::smoke()); + + assert!(matches!( + app.into_probe(), + Err(PlatformError::Backend { + context: "winit smoke window", + .. + }) + )); + } + + #[test] + fn smoke_window_app_rejects_synthetic_window_without_native_handles() { + let mut app = SmokeWindowApp::new(WinitWindowPlan::smoke()); + app.window = Some(WinitWindow::synthetic( + DEFAULT_SMOKE_WIDTH, + DEFAULT_SMOKE_HEIGHT, + )); + + assert!(matches!( + app.into_probe(), + Err(PlatformError::Backend { + context: "winit smoke window", + .. + }) + )); + } + + #[test] fn window_events_push_expected_platform_events() { let mut source = WinitEventSource::new(); let size = winit::dpi::PhysicalSize::new(1024u32, 768u32); |
