feat: create native smoke window handles

This commit is contained in:
2026-06-23 23:56:40 +04:00
parent 54f07ee3be
commit 4d19728c39
7 changed files with 230 additions and 43 deletions
+142 -2
View File
@@ -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,
@@ -343,6 +453,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();