aboutsummaryrefslogtreecommitdiff
path: root/adapters/fparkan-platform-winit/src/lib.rs
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-06-23 22:56:40 +0300
committerValentin Popov <valentin@popov.link>2026-06-23 22:56:40 +0300
commit4d19728c392c6566358ad78f30bba769f8e723cf (patch)
tree04b67eb48f476d7189231dfdbb1f38e8edbc0c56 /adapters/fparkan-platform-winit/src/lib.rs
parent54f07ee3be4c9aad41181ed46b50d273c10767bd (diff)
downloadfparkan-4d19728c392c6566358ad78f30bba769f8e723cf.tar.xz
fparkan-4d19728c392c6566358ad78f30bba769f8e723cf.zip
feat: create native smoke window handles
Diffstat (limited to 'adapters/fparkan-platform-winit/src/lib.rs')
-rw-r--r--adapters/fparkan-platform-winit/src/lib.rs144
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);