use std::io;
use super::placement::WindowPlacement;
pub(super) use crate::frame::validate_frame_dimensions;
pub use crate::frame::{MAX_FRAME_DIMENSION, MAX_FRAME_PIXELS};
pub const MAX_WINDOW_EVENTS: usize = 1_024;
pub const MAX_TITLE_UNITS: usize = 256;
pub const MAX_PUMP_MESSAGES: usize = 1_024;
pub const MAX_WAIT_MILLISECONDS: u32 = 30_000;
pub const MAX_COMPOSITION_UNITS: usize = 4_096;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WindowVisibility {
Hidden,
Visible,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WindowConfig {
title: Vec<u16>,
width: u32,
height: u32,
visibility: WindowVisibility,
placement: Option<WindowPlacement>,
}
impl WindowConfig {
pub fn new(title: impl AsRef<str>, width: u32, height: u32) -> io::Result<Self> {
Self::with_visibility(title, width, height, WindowVisibility::Visible)
}
pub fn with_visibility(
title: impl AsRef<str>,
width: u32,
height: u32,
visibility: WindowVisibility,
) -> io::Result<Self> {
let title = title.as_ref();
if title.is_empty() || title.contains('\0') {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"window title must be non-empty and NUL-free",
));
}
let units = title.encode_utf16().count();
if units > MAX_TITLE_UNITS {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"window title exceeds the bounded UTF-16 limit",
));
}
validate_frame_dimensions(width, height)?;
let mut encoded = Vec::new();
encoded
.try_reserve_exact(units + 1)
.map_err(|_| allocation_error())?;
encoded.extend(title.encode_utf16());
encoded.push(0);
Ok(Self {
title: encoded,
width,
height,
visibility,
placement: None,
})
}
#[must_use]
pub const fn width(&self) -> u32 {
self.width
}
#[must_use]
pub const fn height(&self) -> u32 {
self.height
}
#[must_use]
pub fn title(&self) -> String {
String::from_utf16_lossy(&self.title[..self.title.len().saturating_sub(1)])
}
pub(super) fn title_utf16(&self) -> &[u16] {
&self.title
}
#[must_use]
pub const fn visibility(&self) -> WindowVisibility {
self.visibility
}
#[must_use]
pub const fn with_placement(mut self, placement: WindowPlacement) -> Self {
self.placement = Some(placement);
self
}
#[must_use]
pub const fn placement(&self) -> Option<WindowPlacement> {
self.placement
}
}
pub(super) fn coordinate_error() -> io::Error {
io::Error::new(
io::ErrorKind::InvalidInput,
"window dimensions exceed Win32 coordinate range",
)
}
pub(super) fn allocation_error() -> io::Error {
io::Error::new(
io::ErrorKind::OutOfMemory,
"native window storage reservation failed",
)
}
pub(super) fn windows_error(error: windows::core::Error) -> io::Error {
io::Error::from_raw_os_error(error.code().0)
}