diff --git a/README.md b/README.md index 0b5b326a..8c03f144 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,11 @@ A low-level windowing system geared towards making audio plugin UIs. -`baseview` abstracts the platform-specific windowing APIs (winapi, cocoa, xcb) into a platform-independent API, but otherwise gets out of your way so you can write plugin UIs. +`baseview` abstracts the platform-specific windowing APIs (winapi, cocoa, xcb) into a platform-independent API, but +otherwise gets out of your way so you can write plugin UIs. Interested in learning more about the project? Join us on [discord](https://discord.gg/b3hjnGw), channel `#baseview`. -## Prerequisites - -### Linux - -Install dependencies, e.g.: - -```sh -sudo apt-get install libx11-dev libxcb1-dev libx11-xcb-dev libgl1-mesa-dev -``` - ## Contributing Contributions are very much welcomed! As long as they comply to the policy and licensing requirements diff --git a/examples/open_parented/src/main.rs b/examples/open_parented/src/main.rs index 000d7b60..dac0c1da 100644 --- a/examples/open_parented/src/main.rs +++ b/examples/open_parented/src/main.rs @@ -1,7 +1,7 @@ use baseview::dpi::LogicalSize; use baseview::{ - Event, EventStatus, HandlerError, WindowContext, WindowHandle, WindowHandler, - WindowOpenOptions, WindowSize, + Event, EventStatus, HandlerError, Window, WindowContext, WindowHandler, WindowSettings, + WindowSize, }; use std::cell::{Cell, RefCell}; use std::num::NonZeroU32; @@ -10,7 +10,7 @@ struct ParentWindowHandler { surface: RefCell>, damaged: Cell, - child_window: WindowHandle, + child_window: Window, } impl ParentWindowHandler { @@ -20,12 +20,12 @@ impl ParentWindowHandler { let size = window.size().physical; surface.resize(size.width.try_into()?, size.height.try_into()?)?; - let window_open_options = WindowOpenOptions::new() + let window_open_options = WindowSettings::new() .with_size(LogicalSize::new(256, 256)) .with_parent(&window) .with_title("baseview child"); - let child_window = baseview::create_window(window_open_options, ChildWindowHandler::new)?; + let child_window = Window::create(window_open_options, ChildWindowHandler::new)?; Ok(Self { surface: surface.into(), damaged: true.into(), child_window }) } @@ -128,9 +128,9 @@ impl WindowHandler for ChildWindowHandler { } fn main() -> Result<(), baseview::Error> { - let window_open_options = WindowOpenOptions::new().with_size(LogicalSize::new(512.0, 512.0)); + let window_open_options = WindowSettings::new().with_size(LogicalSize::new(512.0, 512.0)); - baseview::create_window(window_open_options, ParentWindowHandler::new)?.run_until_closed()?; + Window::create(window_open_options, ParentWindowHandler::new)?.run_until_closed()?; Ok(()) } diff --git a/examples/open_window/src/main.rs b/examples/open_window/src/main.rs index 93f1bfd6..83b299b1 100644 --- a/examples/open_window/src/main.rs +++ b/examples/open_window/src/main.rs @@ -8,8 +8,8 @@ use rtrb::{Consumer, RingBuffer}; use baseview::copy_to_clipboard; use baseview::dpi::{LogicalSize, PhysicalPosition}; use baseview::{ - Event, EventStatus, HandlerError, MouseEvent, WindowContext, WindowHandler, WindowOpenOptions, - WindowSize, + Event, EventStatus, HandlerError, MouseEvent, Window, WindowContext, WindowHandler, + WindowSettings, WindowSize, }; #[derive(Debug, Clone)] @@ -140,7 +140,7 @@ impl WindowHandler for OpenWindowExample { } fn main() -> Result<(), baseview::Error> { - let window_open_options = WindowOpenOptions::new().with_size(LogicalSize::new(512.0, 512.0)); + let window_open_options = WindowSettings::new().with_size(LogicalSize::new(512.0, 512.0)); let (mut tx, rx) = RingBuffer::new(128); @@ -152,7 +152,7 @@ fn main() -> Result<(), baseview::Error> { } }); - baseview::create_window(window_open_options, |window| { + Window::create(window_open_options, |window| { let ctx = softbuffer::Context::new(window.clone())?; let mut surface = softbuffer::Surface::new(&ctx, window.clone())?; let size = window.size().physical; diff --git a/examples/plugin_clack/src/gui.rs b/examples/plugin_clack/src/gui.rs index bace4d76..4fcfac6a 100644 --- a/examples/plugin_clack/src/gui.rs +++ b/examples/plugin_clack/src/gui.rs @@ -3,7 +3,7 @@ use crate::ExamplePluginMainThread; use baseview::dpi::*; use baseview::gl::GlConfig; use baseview::host::{Host, HostCallbacks, HostMainThreadCaller}; -use baseview::{HandlerError, WindowHandle, WindowOpenOptions, WindowSize}; +use baseview::{HandlerError, Window, WindowSettings, WindowSize}; use clack_extensions::gui::{ AspectRatioStrategy, GuiApiType, GuiConfiguration, GuiResizeHints, GuiSize, HostGui, PluginGuiImpl, Window as ClapWindow, @@ -14,7 +14,7 @@ use clack_plugin::prelude::{HostMainThreadHandle, HostSharedHandle}; use raw_window_handle::HasRawWindowHandle; pub struct ExamplePluginGui { - pub handle: WindowHandle, + pub handle: Window, } impl PluginGuiImpl for ExamplePluginMainThread<'_> { @@ -31,7 +31,7 @@ impl PluginGuiImpl for ExamplePluginMainThread<'_> { } fn create(&mut self, _configuration: GuiConfiguration) -> Result<(), PluginError> { - let options = WindowOpenOptions::new() + let options = WindowSettings::new() .with_size(PhysicalSize::new(400, 200)) .with_gl_config(GlConfig::default()); @@ -45,7 +45,7 @@ impl PluginGuiImpl for ExamplePluginMainThread<'_> { }); } - let window = baseview::create_window_with_host(options, OpenWindowExample::new, host)?; + let window = Window::create_with_host(options, OpenWindowExample::new, host)?; self.gui = Some(ExamplePluginGui { handle: window }); Ok(()) diff --git a/examples/render_femtovg/src/main.rs b/examples/render_femtovg/src/main.rs index f1f34d4e..db2503d6 100644 --- a/examples/render_femtovg/src/main.rs +++ b/examples/render_femtovg/src/main.rs @@ -1,8 +1,8 @@ use baseview::dpi::{LogicalSize, PhysicalPosition}; use baseview::gl::{GlConfig, GlContext}; use baseview::{ - Event, EventStatus, HandlerError, MouseEvent, WindowContext, WindowHandler, WindowOpenOptions, - WindowSize, + Event, EventStatus, HandlerError, MouseEvent, Window, WindowContext, WindowHandler, + WindowSettings, WindowSize, }; use femtovg::renderer::OpenGl; use femtovg::{Canvas, Color}; @@ -118,12 +118,12 @@ impl WindowHandler for FemtovgExample { fn main() -> Result<(), baseview::Error> { tracing_subscriber::fmt::init(); - let window_open_options = WindowOpenOptions::new() + let window_open_options = WindowSettings::new() .with_title("Femtovg on Baseview") .with_size(LogicalSize::new(512, 512)) .with_gl_config(GlConfig { alpha_bits: 8, ..GlConfig::default() }); - baseview::create_window(window_open_options, FemtovgExample::new)?.run_until_closed()?; + Window::create(window_open_options, FemtovgExample::new)?.run_until_closed()?; Ok(()) } diff --git a/examples/render_wgpu/src/main.rs b/examples/render_wgpu/src/main.rs index 5203a2ee..f72944d5 100644 --- a/examples/render_wgpu/src/main.rs +++ b/examples/render_wgpu/src/main.rs @@ -1,6 +1,7 @@ use baseview::dpi::{LogicalSize, PhysicalSize}; use baseview::{ - Event, EventStatus, HandlerError, WindowContext, WindowHandler, WindowOpenOptions, WindowSize, + Event, EventStatus, HandlerError, Window, WindowContext, WindowHandler, WindowSettings, + WindowSize, }; use log::LevelFilter; @@ -210,11 +211,10 @@ impl WindowHandler for WgpuExample { fn main() -> Result<(), baseview::Error> { env_logger::builder().filter_level(LevelFilter::Debug).init(); - let window_open_options = WindowOpenOptions::new() - .with_title("WGPU on Baseview") - .with_size(LogicalSize::new(512, 512)); + let window_open_options = + WindowSettings::new().with_title("WGPU on Baseview").with_size(LogicalSize::new(512, 512)); - baseview::create_window(window_open_options, |c| pollster::block_on(WgpuExample::new(c)))? + Window::create(window_open_options, |c| pollster::block_on(WgpuExample::new(c)))? .run_until_closed()?; Ok(()) diff --git a/src/host.rs b/src/host.rs index 11cbd37c..f35bf623 100644 --- a/src/host.rs +++ b/src/host.rs @@ -3,7 +3,7 @@ use std::cell::RefCell; /// A special handler for the Window thread to wake up and call methods on the main thread. /// -/// [`WindowHandle::host_main_thread_callback`](crate::WindowHandle::host_main_thread_callback) +/// [`WindowHandle::host_main_thread_callback`](crate::Window::host_main_thread_callback) /// should be called as a response to this. /// /// # Platform compatibility notes @@ -12,7 +12,7 @@ use std::cell::RefCell; pub trait HostMainThreadCaller: Send + 'static { /// Schedules a callback on the main thread. /// - /// [`WindowHandle::host_main_thread_callback`](crate::WindowHandle::host_main_thread_callback) + /// [`WindowHandle::host_main_thread_callback`](crate::Window::host_main_thread_callback) /// should be called as a response to this. /// /// # Platform compatibility notes @@ -48,10 +48,12 @@ pub trait HostCallbacks: 'static { /// /// This type and its methods are always safe to use. /// -/// It also brings the additional safety guarantee that all handlers given to this types will be -/// destroyed alongside with the window, guaranteeing callbacks cannot be fired after the -/// [`WindowHandle`](crate::WindowHandle) is dropped. (or after this [`Host`] object is dropped, if -/// it never made it to a [`create_window_with_host`](crate::create_window_with_host) call). +/// It also brings the additional safety guarantee that all handlers given to this type will be +/// destroyed alongside with the window. +/// +/// This guarantees callbacks cannot be fired after the [`Window`](crate::Window) is dropped. +/// (or after this [`Host`] object is dropped, if it never made it to a +/// [`Window::create_with_host`](crate::Window::create_with_host) call). pub struct Host { #[cfg(target_os = "linux")] pub(crate) main_thread: Option>, @@ -67,8 +69,8 @@ impl Default for Host { impl Host { /// Creates a new, empty host with no callbacks. /// - /// Calling [`create_window_with_host`](crate::create_window_with_host) with this is equivalent - /// to just calling [`create_window`](crate::create_window). + /// Calling [`Window::create_with_host`](crate::Window::create_with_host) with this is equivalent + /// to just calling [`Window::create`](crate::Window::create). #[inline] pub fn new() -> Self { Self { diff --git a/src/platform/macos/view.rs b/src/platform/macos/view.rs index c8f2491a..4c66d122 100644 --- a/src/platform/macos/view.rs +++ b/src/platform/macos/view.rs @@ -10,7 +10,7 @@ use crate::wrappers::appkit::*; use crate::MouseEvent::{ButtonPressed, ButtonReleased}; use crate::{ DropData, DropEffect, Event, EventStatus, MouseButton, MouseEvent, ScrollDelta, WindowEvent, - WindowHandler, WindowOpenOptions, WindowSize, + WindowHandler, WindowSettings, WindowSize, }; use dpi::{LogicalPosition, LogicalSize, Size}; use objc2::__framework_prelude::Retained; @@ -79,7 +79,7 @@ pub(crate) struct BaseviewView { impl BaseviewView { pub fn new( - _options: WindowOpenOptions, builder: WindowHandlerBuilder, parenting: ViewParentingType, + _options: WindowSettings, builder: WindowHandlerBuilder, parenting: ViewParentingType, host: Host, final_size: LogicalSize, mtm: MainThreadMarker, ) -> Result<(Retained>, Rc)> { let view_rect = diff --git a/src/platform/macos/window.rs b/src/platform/macos/window.rs index 85e9eb9b..b309c007 100644 --- a/src/platform/macos/window.rs +++ b/src/platform/macos/window.rs @@ -32,7 +32,7 @@ impl Drop for WindowHandle { impl WindowHandle { pub fn create_window( - mut options: WindowOpenOptions, handler: WindowHandlerBuilder, host: Host, + mut options: WindowSettings, handler: WindowHandlerBuilder, host: Host, ) -> Result { autoreleasepool(|_| { let Some(mtm) = MainThreadMarker::new() else { @@ -57,7 +57,7 @@ impl WindowHandle { } pub fn create_window_parented( - builder: WindowOpenOptions, handler: WindowHandlerBuilder, host: Host, + builder: WindowSettings, handler: WindowHandlerBuilder, host: Host, parent_view: Retained, mtm: MainThreadMarker, ) -> Result { let parenting = @@ -74,8 +74,7 @@ impl WindowHandle { } pub fn create_window_standalone( - builder: WindowOpenOptions, handler: WindowHandlerBuilder, host: Host, - mtm: MainThreadMarker, + builder: WindowSettings, handler: WindowHandlerBuilder, host: Host, mtm: MainThreadMarker, ) -> Result { let window = create_window_with_options(&builder, mtm); @@ -158,7 +157,7 @@ impl WindowHandle { } fn create_window_with_options( - options: &WindowOpenOptions, mtm: MainThreadMarker, + options: &WindowSettings, mtm: MainThreadMarker, ) -> Retained { let initial_size = options.size.to_logical(1.0); let window = create_window(initial_size, mtm); diff --git a/src/platform/win/window.rs b/src/platform/win/window.rs index f5030e10..41eddbcc 100644 --- a/src/platform/win/window.rs +++ b/src/platform/win/window.rs @@ -32,9 +32,7 @@ use crate::wrappers::win32::{ ole_initialize, run_thread_message_loop_until, Dpi, DpiAwarenessContext, ExtendedUser32, Rect, WindowStyle, }; -use crate::{ - Event, MouseButton, MouseEvent, ScrollDelta, WindowEvent, WindowOpenOptions, WindowSize, -}; +use crate::{Event, MouseButton, MouseEvent, ScrollDelta, WindowEvent, WindowSettings, WindowSize}; #[allow(non_snake_case)] fn HIWORD(wparam: WPARAM) -> u16 { @@ -560,7 +558,7 @@ unsafe fn wnd_proc_inner( impl WindowHandle { pub fn create_window( - options: WindowOpenOptions, build: WindowHandlerBuilder, host: Host, + options: WindowSettings, build: WindowHandlerBuilder, host: Host, ) -> Result { let extended_user_32 = ExtendedUser32::load()?; let title = HSTRING::from(options.title); diff --git a/src/platform/x11/window_shared.rs b/src/platform/x11/window_shared.rs index 8a2487dc..877dd2d9 100644 --- a/src/platform/x11/window_shared.rs +++ b/src/platform/x11/window_shared.rs @@ -3,7 +3,7 @@ use crate::platform::x11::visual_info::WindowVisualConfig; use crate::platform::x11::window_thread::WindowThreadShared; use crate::platform::x11::xcb_window::XcbWindow; use crate::platform::*; -use crate::{warn, MouseCursor, WindowHandler, WindowOpenOptions, WindowSize}; +use crate::{warn, MouseCursor, WindowHandler, WindowSettings, WindowSize}; use calloop::LoopSignal; use dpi::{PhysicalSize, Size}; use raw_window_handle::{DisplayHandle, XlibWindowHandle}; @@ -66,7 +66,7 @@ pub(crate) struct WindowInner { impl WindowInner { pub(crate) fn create( - options: WindowOpenOptions, ev_loop: &calloop::EventLoop<'static, EventLoop>, + options: WindowSettings, ev_loop: &calloop::EventLoop<'static, EventLoop>, shared: Arc, ) -> Result> { // Connect to the X server diff --git a/src/platform/x11/window_thread.rs b/src/platform/x11/window_thread.rs index 1f4c7ae5..e066ad8b 100644 --- a/src/platform/x11/window_thread.rs +++ b/src/platform/x11/window_thread.rs @@ -4,7 +4,7 @@ use crate::host::{Host, HostCallbacks}; use crate::platform::x11::event_loop::{EventLoop, MainThreadCaller}; use crate::platform::x11::window_shared::WindowInner; use crate::warn; -use crate::{WindowContext, WindowOpenOptions, WindowSize}; +use crate::{WindowContext, WindowSettings, WindowSize}; use calloop::LoopSignal; use dpi::{PhysicalSize, Size}; use std::cell::Cell; @@ -94,7 +94,7 @@ pub struct WindowThreadHandle { impl WindowThreadHandle { pub fn create_window( - options: WindowOpenOptions, handler: WindowHandlerBuilder, host: Host, + options: WindowSettings, handler: WindowHandlerBuilder, host: Host, ) -> Result { let (tx, rx) = result_channel(); let shared = Arc::new(WindowThreadShared::new()); @@ -263,7 +263,7 @@ impl Display for RequestFailed { impl WindowThread { pub fn create( - options: WindowOpenOptions, handler: WindowHandlerBuilder, shared: Arc, + options: WindowSettings, handler: WindowHandlerBuilder, shared: Arc, receiver: calloop::channel::Channel, sender: mpsc::Sender, main_thread_caller: Option, diff --git a/src/window.rs b/src/window.rs index 6311d590..e635ab3b 100644 --- a/src/window.rs +++ b/src/window.rs @@ -5,16 +5,82 @@ use crate::*; use dpi::{LogicalSize, PhysicalSize, Pixel, Size}; use std::marker::PhantomData; -pub struct WindowHandle { - window_handle: platform::WindowHandle, +/// A handle to a Window created by baseview. +/// +/// Unlike some other windowing libraries like `winit`, baseview [`Window`]s manage their own +/// lifecycle. +/// +/// All of its events and internal operations (such as rendering) are handled in a separate +/// [`WindowHandler`] type, which is owned by the window itself. +/// +/// Dropping this [`Window`] handle will always destroy the window, and drop its associated +/// [`WindowHandler`] and [`Host`] types. +/// +/// # Window lifecycle and ownership +/// +/// Owning this [`Window`] does not mean you fully own the window itself, per se. +/// While you control when the window is [`create`d](Self::create), you do not have the sole control +/// over when it is destroyed. +/// +/// The lifetime of this [`Window`] handle is going to be the longest possible lifetime for the +/// underlying platform window, but it can be destroyed earlier than this. +/// +/// This is because while dropping this handle will always destroy the window, it can be destroyed +/// from other factors, such as: +/// +/// * The [`WindowHandler`] decided to close the window itself, e.g. by calling [`WindowContext::request_close`] from the user clicking an internal "close" button; +/// * The [`WindowContext`] encountered a fatal error (e.g. during rendering) or panicked, +/// and cannot operate anymore. +/// * The underlying platform closed or destroyed the window directly. +/// * The connection to the display server (on e.g. X11) was lost. +/// +/// This type makes enables to handle those cases safely: most methods will either return errors or +/// become no-ops. You can use the [`Window::is_open`] method to know if the window has been closed. +/// +pub struct Window { + inner: platform::WindowHandle, // so that WindowHandle is !Send on all platforms phantom: PhantomData<*mut ()>, } -impl WindowHandle { +impl Window { + /// Creates a new window, using the given [`WindowSettings`] and a builder closure to + /// create the associated [`WindowHandler`]. + /// + /// This function creates the window but does not open or show it. + /// You must use the [`show`](Self::show) method to actually open it. + /// (unless you use [`run_until_closed`](Self::run_until_closed), which does it automatically) #[inline] - fn new(window_handle: platform::WindowHandle) -> Self { - Self { window_handle, phantom: PhantomData } + pub fn create( + options: WindowSettings, + handler: impl FnOnce(WindowContext) -> Result + Send + 'static, + ) -> Result { + Self::create_with_host(options, handler, None) + } + + /// Creates a new window, using the given [`WindowSettings`] and a builder closure to + /// create the associated [`WindowHandler`], as well as an optional [`Host`] containing callbacks + /// to a potential system that is hosting the window (e.g. in a plug-in setting). + /// + /// This function creates the window but does not open or show it. + /// You must use the [`show`](Self::show) method to actually open it. + /// (unless you use [`run_until_closed`](Self::run_until_closed), which does it automatically) + /// + /// Calling this function with [`None`] for the `host` value is equivalent to calling + /// [`create`](Self::create). + pub fn create_with_host( + options: WindowSettings, + handler: impl FnOnce(WindowContext) -> Result + Send + 'static, + host: impl Into>, + ) -> Result { + Ok(Self { + inner: platform::WindowHandle::create_window( + options, + WindowHandlerBuilder::new(handler), + host.into().unwrap_or_else(Host::default), + )?, + phantom: PhantomData, + }) } /// Blocks the thread and runs an event loop until the window is closed. @@ -22,22 +88,24 @@ impl WindowHandle { /// The window is shown automatically if it wasn't already. #[inline] pub fn run_until_closed(self) -> Result<(), Error> { - self.window_handle.run_until_closed()?; + self.inner.run_until_closed()?; Ok(()) } /// The current size of the window. #[inline] pub fn size(&self) -> WindowSize { - self.window_handle.size() + self.inner.size() } /// Resizes the window to the given [`Size`]. /// /// The `size` can be provided in either physical or logical pixels. + /// + /// Using this method does *not* trigger the [`HostCallbacks::request_resize`](host::HostCallbacks) callback. #[inline] pub fn resize(&self, size: Size) -> Result<(), Error> { - self.window_handle.resize(size)?; + self.inner.resize(size)?; Ok(()) } @@ -57,7 +125,7 @@ impl WindowHandle { /// On macOS, this function is always a no-op. #[inline] pub fn suggest_fallback_scale_factor(&self, scale_factor: f64) -> Result<(), Error> { - self.window_handle.suggest_scale_factor(scale_factor)?; + self.inner.suggest_scale_factor(scale_factor)?; Ok(()) } @@ -68,7 +136,7 @@ impl WindowHandle { /// It is guaranteed that no other objects (e.g. the parent window) are used by this window after /// this call. /// - /// Calling this method is more explicit, but otherwise identical to just dropping this [`WindowHandle`]. + /// Calling this method is more explicit, but otherwise identical to just dropping this [`Window`]. #[inline] pub fn close(self) { drop(self) @@ -78,7 +146,7 @@ impl WindowHandle { /// if the window was closed/dropped. #[inline] pub fn is_open(&self) -> bool { - self.window_handle.is_open() + self.inner.is_open() } /// Performs the work the window thread had scheduled for the main thread. @@ -92,7 +160,7 @@ impl WindowHandle { /// On Windows and macOS, this is always a no-op. #[inline] pub fn host_main_thread_callback(&mut self) { - self.window_handle.handle_main_thread_callback() + self.inner.handle_main_thread_callback() } /// Reparents this window using the given `parent`. @@ -100,14 +168,14 @@ impl WindowHandle { /// If the window was a floating window, it will become parented. #[inline] pub fn set_parent(&self, parent: impl Into) -> Result<(), Error> { - self.window_handle.set_parent(parent.into().inner)?; + self.inner.set_parent(parent.into().inner)?; Ok(()) } /// Shows the window to the screen. #[inline] pub fn show(&self) -> Result<(), Error> { - self.window_handle.show()?; + self.inner.show()?; Ok(()) } @@ -117,31 +185,11 @@ impl WindowHandle { /// paused and the user will not be able to see or interact with it. #[inline] pub fn hide(&self) -> Result<(), Error> { - self.window_handle.hide()?; + self.inner.hide()?; Ok(()) } } -#[inline] -pub fn create_window( - builder: WindowOpenOptions, - handler: impl FnOnce(WindowContext) -> Result + Send + 'static, -) -> Result { - create_window_with_host(builder, handler, None) -} - -pub fn create_window_with_host( - builder: WindowOpenOptions, - handler: impl FnOnce(WindowContext) -> Result + Send + 'static, - host: impl Into>, -) -> Result { - Ok(WindowHandle::new(platform::WindowHandle::create_window( - builder, - WindowHandlerBuilder::new(handler), - host.into().unwrap_or_else(Host::default), - )?)) -} - /// A window's size, which can be read in either logical or physical pixels. /// /// Methods that produce this type in baseview guarantee that either the physical or the logical diff --git a/src/window_open_options.rs b/src/window_open_options.rs index c5bca625..7cca66b6 100644 --- a/src/window_open_options.rs +++ b/src/window_open_options.rs @@ -4,14 +4,19 @@ use crate::platform; use dpi::{LogicalSize, Size}; use raw_window_handle::HasWindowHandle; -/// The options for opening a new window +/// Settings used when creating a new window #[derive(Debug, Clone, PartialEq)] -pub struct WindowOpenOptions { +#[non_exhaustive] +pub struct WindowSettings { + /// The window title pub title: String, /// The size of the window, either in physical or logical coordinates pub size: Size, + /// If the window is to be embedded in a parent window, the handle to that window. + /// + /// If `None`, the window will be standalone. pub parent: Option, /// If provided, then an OpenGL context will be created for this window. You'll be able to @@ -22,7 +27,7 @@ pub struct WindowOpenOptions { pub gl_config: Option, } -impl WindowOpenOptions { +impl WindowSettings { #[inline] pub fn new() -> Self { Self::default() @@ -44,9 +49,7 @@ impl WindowOpenOptions { pub fn with_parent<'a, P: HasWindowHandle + 'a>( mut self, parent: impl Into>, ) -> Self { - let Some(parent) = parent.into() else { return self }; - - self.parent = Some(ParentWindowHandle::from_window(parent)); + self.parent = parent.into().map(ParentWindowHandle::from_window); self } @@ -58,7 +61,7 @@ impl WindowOpenOptions { } } -impl Default for WindowOpenOptions { +impl Default for WindowSettings { fn default() -> Self { Self { title: String::from("baseview window"),