From d7ec5fe7828145113bfef50ed4cc56e1a0f11820 Mon Sep 17 00:00:00 2001 From: Adrien Prokopowicz <6529475+prokopyl@users.noreply.github.com> Date: Wed, 22 Jul 2026 10:02:22 +0200 Subject: [PATCH 1/4] wip --- examples/open_parented/src/main.rs | 10 ++--- examples/open_window/src/main.rs | 6 +-- examples/plugin_clack/src/gui.rs | 6 +-- examples/render_femtovg/src/main.rs | 6 +-- examples/render_wgpu/src/main.rs | 5 ++- src/host.rs | 6 +-- src/window.rs | 68 ++++++++++++++--------------- 7 files changed, 53 insertions(+), 54 deletions(-) diff --git a/examples/open_parented/src/main.rs b/examples/open_parented/src/main.rs index 000d7b60..c7ab4292 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, WindowOpenOptions, + 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 { @@ -25,7 +25,7 @@ impl ParentWindowHandler { .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 }) } @@ -130,7 +130,7 @@ impl WindowHandler for ChildWindowHandler { fn main() -> Result<(), baseview::Error> { let window_open_options = WindowOpenOptions::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..c0456bf1 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, + WindowOpenOptions, WindowSize, }; #[derive(Debug, Clone)] @@ -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..4efe85b0 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, WindowOpenOptions, 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<'_> { @@ -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..a8d69d5d 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, + WindowOpenOptions, WindowSize, }; use femtovg::renderer::OpenGl; use femtovg::{Canvas, Color}; @@ -123,7 +123,7 @@ fn main() -> Result<(), baseview::Error> { .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..02e33e4f 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, WindowOpenOptions, + WindowSize, }; use log::LevelFilter; @@ -214,7 +215,7 @@ fn main() -> Result<(), baseview::Error> { .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..a5fcf3be 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 @@ -50,7 +50,7 @@ pub trait HostCallbacks: 'static { /// /// 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 +/// [`WindowHandle`](crate::Window) 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). pub struct Host { #[cfg(target_os = "linux")] diff --git a/src/window.rs b/src/window.rs index 6311d590..56ab859d 100644 --- a/src/window.rs +++ b/src/window.rs @@ -5,16 +5,34 @@ use crate::*; use dpi::{LogicalSize, PhysicalSize, Pixel, Size}; use std::marker::PhantomData; -pub struct WindowHandle { - window_handle: platform::WindowHandle, +pub struct Window { + inner: platform::WindowHandle, // so that WindowHandle is !Send on all platforms phantom: PhantomData<*mut ()>, } -impl WindowHandle { +impl Window { #[inline] - fn new(window_handle: platform::WindowHandle) -> Self { - Self { window_handle, phantom: PhantomData } + pub fn create( + builder: WindowOpenOptions, + handler: impl FnOnce(WindowContext) -> Result + Send + 'static, + ) -> Result { + Self::create_with_host(builder, handler, None) + } + + pub fn create_with_host( + builder: WindowOpenOptions, + handler: impl FnOnce(WindowContext) -> Result + Send + 'static, + host: impl Into>, + ) -> Result { + Ok(Self { + inner: platform::WindowHandle::create_window( + builder, + 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,14 +40,14 @@ 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`]. @@ -37,7 +55,7 @@ impl WindowHandle { /// The `size` can be provided in either physical or logical pixels. #[inline] pub fn resize(&self, size: Size) -> Result<(), Error> { - self.window_handle.resize(size)?; + self.inner.resize(size)?; Ok(()) } @@ -57,7 +75,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 +86,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 +96,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 +110,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 +118,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 +135,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 From 8f12e90cb39c1ca4ea66434176dc435a4f263269 Mon Sep 17 00:00:00 2001 From: Adrien Prokopowicz <6529475+prokopyl@users.noreply.github.com> Date: Wed, 22 Jul 2026 12:28:49 +0200 Subject: [PATCH 2/4] docs --- README.md | 13 ++---------- src/host.rs | 14 +++++++------ src/window.rs | 58 +++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 64 insertions(+), 21 deletions(-) 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/src/host.rs b/src/host.rs index a5fcf3be..f35bf623 100644 --- a/src/host.rs +++ b/src/host.rs @@ -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::Window) 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/window.rs b/src/window.rs index 56ab859d..0b70fc83 100644 --- a/src/window.rs +++ b/src/window.rs @@ -5,6 +5,38 @@ use crate::*; use dpi::{LogicalSize, PhysicalSize, Pixel, Size}; use std::marker::PhantomData; +/// 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 @@ -12,22 +44,38 @@ pub struct Window { } impl Window { + /// Creates a new window, using the given [`WindowOpenOptions`] 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] pub fn create( - builder: WindowOpenOptions, + options: WindowOpenOptions, handler: impl FnOnce(WindowContext) -> Result + Send + 'static, ) -> Result { - Self::create_with_host(builder, handler, None) + Self::create_with_host(options, handler, None) } + /// Creates a new window, using the given [`WindowOpenOptions`] 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( - builder: WindowOpenOptions, + options: WindowOpenOptions, handler: impl FnOnce(WindowContext) -> Result + Send + 'static, host: impl Into>, ) -> Result { Ok(Self { inner: platform::WindowHandle::create_window( - builder, + options, WindowHandlerBuilder::new(handler), host.into().unwrap_or_else(Host::default), )?, @@ -53,6 +101,8 @@ impl Window { /// 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.inner.resize(size)?; From 484a766d23a74fd4485643f6d4624aa1e37c2214 Mon Sep 17 00:00:00 2001 From: Adrien Prokopowicz <6529475+prokopyl@users.noreply.github.com> Date: Wed, 22 Jul 2026 15:14:49 +0200 Subject: [PATCH 3/4] wip --- examples/open_parented/src/main.rs | 6 +++--- examples/open_window/src/main.rs | 4 ++-- examples/plugin_clack/src/gui.rs | 4 ++-- examples/render_femtovg/src/main.rs | 4 ++-- examples/render_wgpu/src/main.rs | 7 +++---- src/platform/macos/view.rs | 4 ++-- src/platform/macos/window.rs | 9 ++++----- src/platform/win/window.rs | 6 ++---- src/platform/x11/window_shared.rs | 4 ++-- src/platform/x11/window_thread.rs | 6 +++--- src/window.rs | 8 ++++---- src/window_open_options.rs | 16 +++++++++------- 12 files changed, 38 insertions(+), 40 deletions(-) diff --git a/examples/open_parented/src/main.rs b/examples/open_parented/src/main.rs index c7ab4292..dac0c1da 100644 --- a/examples/open_parented/src/main.rs +++ b/examples/open_parented/src/main.rs @@ -1,6 +1,6 @@ use baseview::dpi::LogicalSize; use baseview::{ - Event, EventStatus, HandlerError, Window, WindowContext, WindowHandler, WindowOpenOptions, + Event, EventStatus, HandlerError, Window, WindowContext, WindowHandler, WindowSettings, WindowSize, }; use std::cell::{Cell, RefCell}; @@ -20,7 +20,7 @@ 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"); @@ -128,7 +128,7 @@ 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)); Window::create(window_open_options, ParentWindowHandler::new)?.run_until_closed()?; diff --git a/examples/open_window/src/main.rs b/examples/open_window/src/main.rs index c0456bf1..83b299b1 100644 --- a/examples/open_window/src/main.rs +++ b/examples/open_window/src/main.rs @@ -9,7 +9,7 @@ use baseview::copy_to_clipboard; use baseview::dpi::{LogicalSize, PhysicalPosition}; use baseview::{ Event, EventStatus, HandlerError, MouseEvent, Window, WindowContext, WindowHandler, - WindowOpenOptions, WindowSize, + 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); diff --git a/examples/plugin_clack/src/gui.rs b/examples/plugin_clack/src/gui.rs index 4efe85b0..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, Window, WindowOpenOptions, WindowSize}; +use baseview::{HandlerError, Window, WindowSettings, WindowSize}; use clack_extensions::gui::{ AspectRatioStrategy, GuiApiType, GuiConfiguration, GuiResizeHints, GuiSize, HostGui, PluginGuiImpl, Window as ClapWindow, @@ -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()); diff --git a/examples/render_femtovg/src/main.rs b/examples/render_femtovg/src/main.rs index a8d69d5d..db2503d6 100644 --- a/examples/render_femtovg/src/main.rs +++ b/examples/render_femtovg/src/main.rs @@ -2,7 +2,7 @@ use baseview::dpi::{LogicalSize, PhysicalPosition}; use baseview::gl::{GlConfig, GlContext}; use baseview::{ Event, EventStatus, HandlerError, MouseEvent, Window, WindowContext, WindowHandler, - WindowOpenOptions, WindowSize, + WindowSettings, WindowSize, }; use femtovg::renderer::OpenGl; use femtovg::{Canvas, Color}; @@ -118,7 +118,7 @@ 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() }); diff --git a/examples/render_wgpu/src/main.rs b/examples/render_wgpu/src/main.rs index 02e33e4f..f72944d5 100644 --- a/examples/render_wgpu/src/main.rs +++ b/examples/render_wgpu/src/main.rs @@ -1,6 +1,6 @@ use baseview::dpi::{LogicalSize, PhysicalSize}; use baseview::{ - Event, EventStatus, HandlerError, Window, WindowContext, WindowHandler, WindowOpenOptions, + Event, EventStatus, HandlerError, Window, WindowContext, WindowHandler, WindowSettings, WindowSize, }; @@ -211,9 +211,8 @@ 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)); Window::create(window_open_options, |c| pollster::block_on(WgpuExample::new(c)))? .run_until_closed()?; 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 0b70fc83..e635ab3b 100644 --- a/src/window.rs +++ b/src/window.rs @@ -44,7 +44,7 @@ pub struct Window { } impl Window { - /// Creates a new window, using the given [`WindowOpenOptions`] and a builder closure to + /// 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. @@ -52,13 +52,13 @@ impl Window { /// (unless you use [`run_until_closed`](Self::run_until_closed), which does it automatically) #[inline] pub fn create( - options: WindowOpenOptions, + options: WindowSettings, handler: impl FnOnce(WindowContext) -> Result + Send + 'static, ) -> Result { Self::create_with_host(options, handler, None) } - /// Creates a new window, using the given [`WindowOpenOptions`] and a builder closure to + /// 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). /// @@ -69,7 +69,7 @@ impl Window { /// Calling this function with [`None`] for the `host` value is equivalent to calling /// [`create`](Self::create). pub fn create_with_host( - options: WindowOpenOptions, + options: WindowSettings, handler: impl FnOnce(WindowContext) -> Result + Send + 'static, host: impl Into>, ) -> Result { diff --git a/src/window_open_options.rs b/src/window_open_options.rs index c5bca625..1b788205 100644 --- a/src/window_open_options.rs +++ b/src/window_open_options.rs @@ -4,14 +4,18 @@ 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 { +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 +26,7 @@ pub struct WindowOpenOptions { pub gl_config: Option, } -impl WindowOpenOptions { +impl WindowSettings { #[inline] pub fn new() -> Self { Self::default() @@ -44,9 +48,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 +60,7 @@ impl WindowOpenOptions { } } -impl Default for WindowOpenOptions { +impl Default for WindowSettings { fn default() -> Self { Self { title: String::from("baseview window"), From 28a7744b799a54b61550e7be153e9dad3f274bfa Mon Sep 17 00:00:00 2001 From: Adrien Prokopowicz <6529475+prokopyl@users.noreply.github.com> Date: Wed, 22 Jul 2026 15:19:08 +0200 Subject: [PATCH 4/4] wip --- src/window_open_options.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/window_open_options.rs b/src/window_open_options.rs index 1b788205..7cca66b6 100644 --- a/src/window_open_options.rs +++ b/src/window_open_options.rs @@ -6,6 +6,7 @@ use raw_window_handle::HasWindowHandle; /// Settings used when creating a new window #[derive(Debug, Clone, PartialEq)] +#[non_exhaustive] pub struct WindowSettings { /// The window title pub title: String,