From b4c5b7615591bbf757d12c174811ed89524e3bc9 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sat, 3 May 2025 18:24:44 +0900 Subject: [PATCH] winit-core: move window Create `WindowAttributes` for respective platform specific window attributes in `winit` due to move of `WindowAttributes`. --- examples/application.rs | 114 ++++++--- examples/window.rs | 5 +- examples/x11_embed.rs | 10 +- src/changelog/unreleased.md | 5 +- src/event_loop.rs | 3 +- src/lib.rs | 5 +- src/platform/android.rs | 7 +- src/platform/ios.rs | 86 +++---- src/platform/macos.rs | 226 ++++++++++-------- src/platform/startup_notify.rs | 14 +- src/platform/wayland.rs | 37 ++- src/platform/web.rs | 78 ++++-- src/platform/windows.rs | 209 ++++++++-------- src/platform/x11.rs | 129 +++++----- src/platform_impl/android/mod.rs | 6 +- src/platform_impl/apple/appkit/cursor.rs | 3 +- src/platform_impl/apple/appkit/event_loop.rs | 3 +- src/platform_impl/apple/appkit/mod.rs | 1 - src/platform_impl/apple/appkit/window.rs | 6 +- .../apple/appkit/window_delegate.rs | 91 +++---- src/platform_impl/apple/uikit/event_loop.rs | 3 +- src/platform_impl/apple/uikit/mod.rs | 2 +- src/platform_impl/apple/uikit/view.rs | 5 +- .../apple/uikit/view_controller.rs | 24 +- src/platform_impl/apple/uikit/window.rs | 24 +- .../linux/wayland/event_loop/mod.rs | 3 +- .../linux/wayland/seat/text_input/mod.rs | 2 +- src/platform_impl/linux/wayland/window/mod.rs | 45 ++-- .../linux/wayland/window/state.rs | 28 +-- src/platform_impl/linux/x11/mod.rs | 6 +- src/platform_impl/linux/x11/util/cursor.rs | 3 +- src/platform_impl/linux/x11/window.rs | 90 +++---- src/platform_impl/linux/x11/xdisplay.rs | 2 +- src/platform_impl/orbital/event_loop.rs | 10 +- .../web/event_loop/window_target.rs | 3 +- src/platform_impl/web/mod.rs | 10 +- src/platform_impl/web/web_sys/canvas.rs | 19 +- src/platform_impl/web/window.rs | 47 +--- src/platform_impl/windows/event_loop.rs | 10 +- src/platform_impl/windows/mod.rs | 46 +--- src/platform_impl/windows/util.rs | 2 +- src/platform_impl/windows/window.rs | 53 ++-- tests/send_objects.rs | 4 +- tests/serde_objects.rs | 2 +- tests/sync_object.rs | 4 +- winit-core/src/cursor.rs | 3 +- winit-core/src/lib.rs | 1 + {src => winit-core/src}/window.rs | 162 ++++++++----- 48 files changed, 843 insertions(+), 808 deletions(-) rename {src => winit-core/src}/window.rs (95%) diff --git a/examples/application.rs b/examples/application.rs index 931c8366..aee0dc09 100644 --- a/examples/application.rs +++ b/examples/application.rs @@ -16,29 +16,27 @@ use rwh_06::{DisplayHandle, HasDisplayHandle}; #[cfg(not(android_platform))] use softbuffer::{Context, Surface}; use winit::application::ApplicationHandler; +use winit::cursor::{Cursor, CustomCursor, CustomCursorSource}; use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize}; use winit::error::RequestError; use winit::event::{DeviceEvent, DeviceId, Ime, MouseButton, MouseScrollDelta, WindowEvent}; use winit::event_loop::{ActiveEventLoop, EventLoop}; -use winit::icon::RgbaIcon; +use winit::icon::{Icon, RgbaIcon}; use winit::keyboard::{Key, ModifiersState}; use winit::monitor::Fullscreen; #[cfg(macos_platform)] use winit::platform::macos::{ - ApplicationHandlerExtMacOS, OptionAsAlt, WindowAttributesExtMacOS, WindowExtMacOS, + ApplicationHandlerExtMacOS, OptionAsAlt, WindowAttributesMacOS, WindowExtMacOS, }; #[cfg(any(x11_platform, wayland_platform))] -use winit::platform::startup_notify::{ - self, EventLoopExtStartupNotify, WindowAttributesExtStartupNotify, WindowExtStartupNotify, -}; +use winit::platform::startup_notify::{self, EventLoopExtStartupNotify, WindowExtStartupNotify}; +#[cfg(wayland_platform)] +use winit::platform::wayland::{ActiveEventLoopExtWayland, WindowAttributesWayland}; #[cfg(web_platform)] -use winit::platform::web::{ActiveEventLoopExtWeb, WindowAttributesExtWeb}; +use winit::platform::web::{ActiveEventLoopExtWeb, WindowAttributesWeb}; #[cfg(x11_platform)] -use winit::platform::x11::WindowAttributesExtX11; -use winit::window::{ - Cursor, CursorGrabMode, CustomCursor, CustomCursorSource, Icon, ResizeDirection, Theme, Window, - WindowAttributes, WindowId, -}; +use winit::platform::x11::{ActiveEventLoopExtX11, WindowAttributesX11}; +use winit::window::{CursorGrabMode, ResizeDirection, Theme, Window, WindowAttributes, WindowId}; #[path = "util/tracing.rs"] mod tracing; @@ -149,43 +147,29 @@ impl Application { .with_transparent(true) .with_window_icon(Some(self.icon.clone())); - #[cfg(any(x11_platform, wayland_platform))] - if let Some(token) = event_loop.read_token_from_env() { - startup_notify::reset_activation_token_env(); - info!("Using token {:?} to activate a window", token); - window_attributes = window_attributes.with_activation_token(token); + #[cfg(x11_platform)] + if event_loop.is_x11() { + window_attributes = window_attributes + .with_platform_attributes(Box::new(window_attributes_x11(event_loop)?)); } - #[cfg(x11_platform)] - match std::env::var("X11_VISUAL_ID") { - Ok(visual_id_str) => { - info!("Using X11 visual id {visual_id_str}"); - let visual_id = visual_id_str.parse()?; - window_attributes = window_attributes.with_x11_visual(visual_id); - }, - Err(_) => info!("Set the X11_VISUAL_ID env variable to request specific X11 visual"), - } - - #[cfg(x11_platform)] - match std::env::var("X11_SCREEN_ID") { - Ok(screen_id_str) => { - info!("Placing the window on X11 screen {screen_id_str}"); - let screen_id = screen_id_str.parse()?; - window_attributes = window_attributes.with_x11_screen(screen_id); - }, - Err(_) => info!( - "Set the X11_SCREEN_ID env variable to place the window on non-default screen" - ), + #[cfg(wayland_platform)] + if event_loop.is_wayland() { + window_attributes = window_attributes + .with_platform_attributes(Box::new(window_attributes_wayland(event_loop))); } #[cfg(macos_platform)] if let Some(tab_id) = _tab_id { - window_attributes = window_attributes.with_tabbing_identifier(&tab_id); + let window_attributes_macos = + Box::new(WindowAttributesMacOS::default().with_tabbing_identifier(&tab_id)); + window_attributes = window_attributes.with_platform_attributes(window_attributes_macos); } #[cfg(web_platform)] { - window_attributes = window_attributes.with_append(true); + window_attributes = + window_attributes.with_platform_attributes(Box::new(window_attributes_web())); } let window = event_loop.create_window(window_attributes)?; @@ -1198,6 +1182,60 @@ fn mouse_button_to_string(button: MouseButton) -> &'static str { } } +#[cfg(web_platform)] +fn window_attributes_web() -> WindowAttributesWeb { + WindowAttributesWeb::default().with_append(true) +} + +#[cfg(wayland_platform)] +fn window_attributes_wayland(event_loop: &dyn ActiveEventLoop) -> WindowAttributesWayland { + let mut window_attributes = WindowAttributesWayland::default(); + + if let Some(token) = event_loop.read_token_from_env() { + startup_notify::reset_activation_token_env(); + info!("Using token {:?} to activate a window", token); + window_attributes = window_attributes.with_activation_token(token); + } + + window_attributes +} + +#[cfg(x11_platform)] +fn window_attributes_x11( + event_loop: &dyn ActiveEventLoop, +) -> Result> { + let mut window_attributes = WindowAttributesX11::default(); + + #[cfg(any(x11_platform, wayland_platform))] + if let Some(token) = event_loop.read_token_from_env() { + startup_notify::reset_activation_token_env(); + info!("Using token {:?} to activate a window", token); + window_attributes = window_attributes.with_activation_token(token); + } + + match std::env::var("X11_VISUAL_ID") { + Ok(visual_id_str) => { + info!("Using X11 visual id {visual_id_str}"); + let visual_id = visual_id_str.parse()?; + window_attributes = window_attributes.with_x11_visual(visual_id); + }, + Err(_) => info!("Set the X11_VISUAL_ID env variable to request specific X11 visual"), + } + + match std::env::var("X11_SCREEN_ID") { + Ok(screen_id_str) => { + info!("Placing the window on X11 screen {screen_id_str}"); + let screen_id = screen_id_str.parse()?; + window_attributes = window_attributes.with_x11_screen(screen_id); + }, + Err(_) => { + info!("Set the X11_SCREEN_ID env variable to place the window on non-default screen") + }, + } + + Ok(window_attributes) +} + /// Cursor list to cycle through. const CURSORS: &[CursorIcon] = &[ CursorIcon::Default, diff --git a/examples/window.rs b/examples/window.rs index b6077270..76c60c39 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -6,7 +6,7 @@ use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::{ActiveEventLoop, EventLoop}; #[cfg(web_platform)] -use winit::platform::web::WindowAttributesExtWeb; +use winit::platform::web::WindowAttributesWeb; use winit::window::{Window, WindowAttributes, WindowId}; #[path = "util/fill.rs"] @@ -24,7 +24,8 @@ impl ApplicationHandler for App { #[cfg(not(web_platform))] let window_attributes = WindowAttributes::default(); #[cfg(web_platform)] - let window_attributes = WindowAttributes::default().with_append(true); + let window_attributes = WindowAttributes::default() + .with_platform_attributes(Box::new(WindowAttributesWeb::default().with_append(true))); self.window = match event_loop.create_window(window_attributes) { Ok(window) => Some(window), Err(err) => { diff --git a/examples/x11_embed.rs b/examples/x11_embed.rs index e600a5d0..c047f71e 100644 --- a/examples/x11_embed.rs +++ b/examples/x11_embed.rs @@ -6,7 +6,7 @@ fn main() -> Result<(), Box> { use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::{ActiveEventLoop, EventLoop}; - use winit::platform::x11::WindowAttributesExtX11; + use winit::platform::x11::WindowAttributesX11; use winit::window::{Window, WindowAttributes, WindowId}; #[path = "util/fill.rs"] @@ -20,10 +20,12 @@ fn main() -> Result<(), Box> { impl ApplicationHandler for XEmbedDemo { fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { - let window_attributes = WindowAttributes::default() + let mut window_attributes = WindowAttributes::default() .with_title("An embedded window!") - .with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0)) - .with_embed_parent_window(self.parent_window_id); + .with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0)); + let x11_attrs = + WindowAttributesX11::default().with_embed_parent_window(self.parent_window_id); + window_attributes = window_attributes.with_platform_attributes(Box::new(x11_attrs)); self.window = Some(event_loop.create_window(window_attributes).unwrap()); } diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 210e1b0b..2198bb7f 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -61,7 +61,7 @@ changelog entry. - Add `MonitorHandle::current_video_mode()`. - Add `ApplicationHandlerExtMacOS` trait, and a `macos_handler` method to `ApplicationHandler` which returns a `dyn ApplicationHandlerExtMacOS` which allows for macOS specific extensions to winit. - Add a `standard_key_binding` method to the `ApplicationHandlerExtMacOS` trait. This allows handling of standard keybindings such as "go to end of line" on macOS. -- On macOS, add `WindowExtMacOS::set_unified_titlebar` and `WindowAttributesExtMacOS::with_unified_titlebar` +- On macOS, add `WindowExtMacOS::set_unified_titlebar` and `WindowAttributesMacOS::with_unified_titlebar` to use a larger style of titlebar. - Add `WindowId::into_raw()` and `from_raw()`. - Add `PointerKind`, `PointerSource`, `ButtonSource`, `FingerId`, `primary` and `position` to all @@ -79,6 +79,8 @@ changelog entry. - Add `icon` module that exposes winit's icon API. - `VideoMode::new` to create a `VideoMode`. - `keyboard::ModifiersKey` to track which modifier is exactly pressed. +- `ActivationToken::as_raw` to get a ref to raw token. +- Each platform now has corresponding `WindowAttributes` struct instead of trait extension. ### Changed @@ -235,6 +237,7 @@ changelog entry. the `Drop` impl on the application handler. - Remove `NamedKey::Space`, match on `Key::Character(" ")` instead. - Remove `PartialEq` impl for `WindowAttributes`. +- `WindowAttributesExt*` platform extensions; use `WindowAttributes*` instead. ### Fixed diff --git a/src/event_loop.rs b/src/event_loop.rs index 2b426cf2..d093f86d 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -18,11 +18,12 @@ use rwh_06::{DisplayHandle, HandleError, HasDisplayHandle}; pub use winit_core::event_loop::*; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor, CustomCursorSource}; use crate::error::{EventLoopError, RequestError}; use crate::monitor::MonitorHandle; use crate::platform_impl; use crate::utils::{impl_dyn_casting, AsAny}; -use crate::window::{CustomCursor, CustomCursorSource, Theme, Window, WindowAttributes}; +use crate::window::{Theme, Window, WindowAttributes}; /// Provides a way to retrieve events from the system and from the windows that were registered to /// the events loop. diff --git a/src/lib.rs b/src/lib.rs index 4f3fd440..940a1a4f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -299,14 +299,13 @@ pub use rwh_06 as raw_window_handle; pub mod application; #[cfg(any(doc, doctest, test))] pub mod changelog; -use winit_core::cursor; +pub use winit_core::cursor; pub mod event; pub mod event_loop; -pub use winit_core::{error, icon, keyboard, monitor}; +pub use winit_core::{error, icon, keyboard, monitor, window}; #[macro_use] mod os_error; mod platform_impl; use winit_core::as_any as utils; -pub mod window; pub mod platform; diff --git a/src/platform/android.rs b/src/platform/android.rs index 086711ac..d2250ed3 100644 --- a/src/platform/android.rs +++ b/src/platform/android.rs @@ -72,7 +72,7 @@ use self::activity::{AndroidApp, ConfigurationRef, Rect}; use crate::event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder}; -use crate::window::{Window, WindowAttributes}; +use crate::window::Window; /// Additional methods on [`EventLoop`] that are specific to Android. pub trait EventLoopExtAndroid { @@ -118,11 +118,6 @@ impl ActiveEventLoopExtAndroid for dyn ActiveEventLoop + '_ { } } -/// Additional methods on [`WindowAttributes`] that are specific to Android. -pub trait WindowAttributesExtAndroid {} - -impl WindowAttributesExtAndroid for WindowAttributes {} - pub trait EventLoopBuilderExtAndroid { /// Associates the [`AndroidApp`] that was passed to `android_main()` with the event loop /// diff --git a/src/platform/ios.rs b/src/platform/ios.rs index 5cbf8589..f9345e17 100644 --- a/src/platform/ios.rs +++ b/src/platform/ios.rs @@ -103,10 +103,11 @@ use std::os::raw::c_void; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use winit_core::window::PlatformWindowAttributes; use crate::monitor::{MonitorHandle, VideoMode}; use crate::platform_impl::MonitorHandle as IosMonitorHandle; -use crate::window::{Window, WindowAttributes}; +use crate::window::Window; /// Additional methods on [`Window`] that are specific to iOS. pub trait WindowExtIOS { @@ -283,8 +284,18 @@ impl WindowExtIOS for dyn Window + '_ { } } +#[derive(Clone, Debug, Default, PartialEq)] +pub struct WindowAttributesIos { + pub(crate) scale_factor: Option, + pub(crate) valid_orientations: ValidOrientations, + pub(crate) prefers_home_indicator_hidden: bool, + pub(crate) prefers_status_bar_hidden: bool, + pub(crate) preferred_status_bar_style: StatusBarStyle, + pub(crate) preferred_screen_edges_deferring_system_gestures: ScreenEdge, +} + /// Additional methods on [`WindowAttributes`] that are specific to iOS. -pub trait WindowAttributesExtIOS { +impl WindowAttributesIos { /// Sets the [`contentScaleFactor`] of the underlying [`UIWindow`] to `scale_factor`. /// /// The default value is device dependent, and it's recommended GLES or Metal applications set @@ -293,7 +304,10 @@ pub trait WindowAttributesExtIOS { /// [`UIWindow`]: https://developer.apple.com/documentation/uikit/uiwindow?language=objc /// [`contentScaleFactor`]: https://developer.apple.com/documentation/uikit/uiview/1622657-contentscalefactor?language=objc /// [`MonitorHandleProvider::scale_factor()`]: crate::monitor::MonitorHandleProvider::scale_factor() - fn with_scale_factor(self, scale_factor: f64) -> Self; + pub fn with_scale_factor(mut self, scale_factor: f64) -> Self { + self.scale_factor = Some(scale_factor); + self + } /// Sets the valid orientations for the [`Window`]. /// @@ -301,7 +315,10 @@ pub trait WindowAttributesExtIOS { /// /// This sets the initial value returned by /// [`-[UIViewController supportedInterfaceOrientations]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621435-supportedinterfaceorientations?language=objc). - fn with_valid_orientations(self, valid_orientations: ValidOrientations) -> Self; + pub fn with_valid_orientations(mut self, valid_orientations: ValidOrientations) -> Self { + self.valid_orientations = valid_orientations; + self + } /// Sets whether the [`Window`] prefers the home indicator hidden. /// @@ -311,7 +328,10 @@ pub trait WindowAttributesExtIOS { /// [`-[UIViewController prefersHomeIndicatorAutoHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887510-prefershomeindicatorautohidden?language=objc). /// /// This only has an effect on iOS 11.0+. - fn with_prefers_home_indicator_hidden(self, hidden: bool) -> Self; + pub fn with_prefers_home_indicator_hidden(mut self, hidden: bool) -> Self { + self.prefers_home_indicator_hidden = hidden; + self + } /// Sets the screen edges for which the system gestures will take a lower priority than the /// application's touch handling. @@ -320,7 +340,13 @@ pub trait WindowAttributesExtIOS { /// [`-[UIViewController preferredScreenEdgesDeferringSystemGestures]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887512-preferredscreenedgesdeferringsys?language=objc). /// /// This only has an effect on iOS 11.0+. - fn with_preferred_screen_edges_deferring_system_gestures(self, edges: ScreenEdge) -> Self; + pub fn with_preferred_screen_edges_deferring_system_gestures( + mut self, + edges: ScreenEdge, + ) -> Self { + self.preferred_screen_edges_deferring_system_gestures = edges; + self + } /// Sets whether the [`Window`] prefers the status bar hidden. /// @@ -328,7 +354,10 @@ pub trait WindowAttributesExtIOS { /// /// This sets the initial value returned by /// [`-[UIViewController prefersStatusBarHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621440-prefersstatusbarhidden?language=objc). - fn with_prefers_status_bar_hidden(self, hidden: bool) -> Self; + pub fn with_prefers_status_bar_hidden(mut self, hidden: bool) -> Self { + self.prefers_status_bar_hidden = hidden; + self + } /// Sets the style of the [`Window`]'s status bar. /// @@ -336,44 +365,15 @@ pub trait WindowAttributesExtIOS { /// /// This sets the initial value returned by /// [`-[UIViewController preferredStatusBarStyle]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621416-preferredstatusbarstyle?language=objc), - fn with_preferred_status_bar_style(self, status_bar_style: StatusBarStyle) -> Self; + pub fn with_preferred_status_bar_style(mut self, status_bar_style: StatusBarStyle) -> Self { + self.preferred_status_bar_style = status_bar_style; + self + } } -impl WindowAttributesExtIOS for WindowAttributes { - #[inline] - fn with_scale_factor(mut self, scale_factor: f64) -> Self { - self.platform_specific.scale_factor = Some(scale_factor); - self - } - - #[inline] - fn with_valid_orientations(mut self, valid_orientations: ValidOrientations) -> Self { - self.platform_specific.valid_orientations = valid_orientations; - self - } - - #[inline] - fn with_prefers_home_indicator_hidden(mut self, hidden: bool) -> Self { - self.platform_specific.prefers_home_indicator_hidden = hidden; - self - } - - #[inline] - fn with_preferred_screen_edges_deferring_system_gestures(mut self, edges: ScreenEdge) -> Self { - self.platform_specific.preferred_screen_edges_deferring_system_gestures = edges; - self - } - - #[inline] - fn with_prefers_status_bar_hidden(mut self, hidden: bool) -> Self { - self.platform_specific.prefers_status_bar_hidden = hidden; - self - } - - #[inline] - fn with_preferred_status_bar_style(mut self, status_bar_style: StatusBarStyle) -> Self { - self.platform_specific.preferred_status_bar_style = status_bar_style; - self +impl PlatformWindowAttributes for WindowAttributesIos { + fn box_clone(&self) -> Box { + Box::from(self.clone()) } } diff --git a/src/platform/macos.rs b/src/platform/macos.rs index a417406e..d5e2262c 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -69,12 +69,13 @@ use std::os::raw::c_void; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use winit_core::window::PlatformWindowAttributes; use crate::application::ApplicationHandler; use crate::event_loop::{ActiveEventLoop, EventLoopBuilder}; use crate::monitor::MonitorHandle; use crate::platform_impl::MonitorHandle as MacOsMonitorHandle; -use crate::window::{Window, WindowAttributes, WindowId}; +use crate::window::{Window, WindowId}; /// Additional methods on [`Window`] that are specific to MacOS. pub trait WindowExtMacOS { @@ -292,7 +293,7 @@ pub enum ActivationPolicy { Prohibited, } -/// Additional methods on [`WindowAttributes`] that are specific to MacOS. +/// [`WindowAttributes`] that are specific to MacOS. /// /// **Note:** Properties dealing with the titlebar will be overwritten by the /// [`WindowAttributes::with_decorations`] method: @@ -301,127 +302,156 @@ pub enum ActivationPolicy { /// - `with_titlebar_hidden` /// - `with_titlebar_buttons_hidden` /// - `with_fullsize_content_view` -pub trait WindowAttributesExtMacOS { +#[derive(Clone, Debug, PartialEq)] +pub struct WindowAttributesMacOS { + pub(crate) movable_by_window_background: bool, + pub(crate) titlebar_transparent: bool, + pub(crate) title_hidden: bool, + pub(crate) titlebar_hidden: bool, + pub(crate) titlebar_buttons_hidden: bool, + pub(crate) fullsize_content_view: bool, + pub(crate) disallow_hidpi: bool, + pub(crate) has_shadow: bool, + pub(crate) accepts_first_mouse: bool, + pub(crate) tabbing_identifier: Option, + pub(crate) option_as_alt: OptionAsAlt, + pub(crate) borderless_game: bool, + pub(crate) unified_titlebar: bool, + pub(crate) panel: bool, +} + +impl WindowAttributesMacOS { /// Enables click-and-drag behavior for the entire window, not just the titlebar. - fn with_movable_by_window_background(self, movable_by_window_background: bool) -> Self; + #[inline] + pub fn with_movable_by_window_background(mut self, movable_by_window_background: bool) -> Self { + self.movable_by_window_background = movable_by_window_background; + self + } + /// Makes the titlebar transparent and allows the content to appear behind it. - fn with_titlebar_transparent(self, titlebar_transparent: bool) -> Self; - /// Hides the window title. - fn with_title_hidden(self, title_hidden: bool) -> Self; + #[inline] + pub fn with_titlebar_transparent(mut self, titlebar_transparent: bool) -> Self { + self.titlebar_transparent = titlebar_transparent; + self + } + /// Hides the window titlebar. - fn with_titlebar_hidden(self, titlebar_hidden: bool) -> Self; + #[inline] + pub fn with_titlebar_hidden(mut self, titlebar_hidden: bool) -> Self { + self.titlebar_hidden = titlebar_hidden; + self + } + /// Hides the window titlebar buttons. - fn with_titlebar_buttons_hidden(self, titlebar_buttons_hidden: bool) -> Self; + #[inline] + pub fn with_titlebar_buttons_hidden(mut self, titlebar_buttons_hidden: bool) -> Self { + self.titlebar_buttons_hidden = titlebar_buttons_hidden; + self + } + + /// Hides the window title. + #[inline] + pub fn with_title_hidden(mut self, title_hidden: bool) -> Self { + self.title_hidden = title_hidden; + self + } + /// Makes the window content appear behind the titlebar. - fn with_fullsize_content_view(self, fullsize_content_view: bool) -> Self; - fn with_disallow_hidpi(self, disallow_hidpi: bool) -> Self; - fn with_has_shadow(self, has_shadow: bool) -> Self; + #[inline] + pub fn with_fullsize_content_view(mut self, fullsize_content_view: bool) -> Self { + self.fullsize_content_view = fullsize_content_view; + self + } + + #[inline] + pub fn with_disallow_hidpi(mut self, disallow_hidpi: bool) -> Self { + self.disallow_hidpi = disallow_hidpi; + self + } + + #[inline] + pub fn with_has_shadow(mut self, has_shadow: bool) -> Self { + self.has_shadow = has_shadow; + self + } + /// Window accepts click-through mouse events. - fn with_accepts_first_mouse(self, accepts_first_mouse: bool) -> Self; + #[inline] + pub fn with_accepts_first_mouse(mut self, accepts_first_mouse: bool) -> Self { + self.accepts_first_mouse = accepts_first_mouse; + self + } + /// Defines the window tabbing identifier. /// /// - fn with_tabbing_identifier(self, identifier: &str) -> Self; + #[inline] + pub fn with_tabbing_identifier(mut self, tabbing_identifier: &str) -> Self { + self.tabbing_identifier.replace(tabbing_identifier.to_string()); + self + } + /// Set how the Option keys are interpreted. /// /// See [`WindowExtMacOS::set_option_as_alt`] for details on what this means if set. - fn with_option_as_alt(self, option_as_alt: OptionAsAlt) -> Self; + #[inline] + pub fn with_option_as_alt(mut self, option_as_alt: OptionAsAlt) -> Self { + self.option_as_alt = option_as_alt; + self + } + /// See [`WindowExtMacOS::set_borderless_game`] for details on what this means if set. - fn with_borderless_game(self, borderless_game: bool) -> Self; + #[inline] + pub fn with_borderless_game(mut self, borderless_game: bool) -> Self { + self.borderless_game = borderless_game; + self + } + /// See [`WindowExtMacOS::set_unified_titlebar`] for details on what this means if set. - fn with_unified_titlebar(self, unified_titlebar: bool) -> Self; + #[inline] + pub fn with_unified_titlebar(mut self, unified_titlebar: bool) -> Self { + self.unified_titlebar = unified_titlebar; + self + } + /// Use [`NSPanel`] window with [`NonactivatingPanel`] window style mask instead of /// [`NSWindow`]. /// /// [`NSWindow`]: https://developer.apple.com/documentation/appkit/NSWindow?language=objc /// [`NSPanel`]: https://developer.apple.com/documentation/appkit/NSPanel?language=objc /// [`NonactivatingPanel`]: https://developer.apple.com/documentation/appkit/nswindow/stylemask-swift.struct/nonactivatingpanel?language=objc - fn with_panel(self, panel: bool) -> Self; + #[inline] + pub fn with_panel(mut self, panel: bool) -> Self { + self.panel = panel; + self + } } -impl WindowAttributesExtMacOS for WindowAttributes { +impl Default for WindowAttributesMacOS { #[inline] - fn with_movable_by_window_background(mut self, movable_by_window_background: bool) -> Self { - self.platform_specific.movable_by_window_background = movable_by_window_background; - self + fn default() -> Self { + Self { + movable_by_window_background: false, + titlebar_transparent: false, + title_hidden: false, + titlebar_hidden: false, + titlebar_buttons_hidden: false, + fullsize_content_view: false, + disallow_hidpi: false, + has_shadow: true, + accepts_first_mouse: true, + tabbing_identifier: None, + option_as_alt: Default::default(), + borderless_game: false, + unified_titlebar: false, + panel: false, + } } +} - #[inline] - fn with_titlebar_transparent(mut self, titlebar_transparent: bool) -> Self { - self.platform_specific.titlebar_transparent = titlebar_transparent; - self - } - - #[inline] - fn with_titlebar_hidden(mut self, titlebar_hidden: bool) -> Self { - self.platform_specific.titlebar_hidden = titlebar_hidden; - self - } - - #[inline] - fn with_titlebar_buttons_hidden(mut self, titlebar_buttons_hidden: bool) -> Self { - self.platform_specific.titlebar_buttons_hidden = titlebar_buttons_hidden; - self - } - - #[inline] - fn with_title_hidden(mut self, title_hidden: bool) -> Self { - self.platform_specific.title_hidden = title_hidden; - self - } - - #[inline] - fn with_fullsize_content_view(mut self, fullsize_content_view: bool) -> Self { - self.platform_specific.fullsize_content_view = fullsize_content_view; - self - } - - #[inline] - fn with_disallow_hidpi(mut self, disallow_hidpi: bool) -> Self { - self.platform_specific.disallow_hidpi = disallow_hidpi; - self - } - - #[inline] - fn with_has_shadow(mut self, has_shadow: bool) -> Self { - self.platform_specific.has_shadow = has_shadow; - self - } - - #[inline] - fn with_accepts_first_mouse(mut self, accepts_first_mouse: bool) -> Self { - self.platform_specific.accepts_first_mouse = accepts_first_mouse; - self - } - - #[inline] - fn with_tabbing_identifier(mut self, tabbing_identifier: &str) -> Self { - self.platform_specific.tabbing_identifier.replace(tabbing_identifier.to_string()); - self - } - - #[inline] - fn with_option_as_alt(mut self, option_as_alt: OptionAsAlt) -> Self { - self.platform_specific.option_as_alt = option_as_alt; - self - } - - #[inline] - fn with_borderless_game(mut self, borderless_game: bool) -> Self { - self.platform_specific.borderless_game = borderless_game; - self - } - - #[inline] - fn with_unified_titlebar(mut self, unified_titlebar: bool) -> Self { - self.platform_specific.unified_titlebar = unified_titlebar; - self - } - - #[inline] - fn with_panel(mut self, panel: bool) -> Self { - self.platform_specific.panel = panel; - self +impl PlatformWindowAttributes for WindowAttributesMacOS { + fn box_clone(&self) -> Box { + Box::from(self.clone()) } } diff --git a/src/platform/startup_notify.rs b/src/platform/startup_notify.rs index 2364bf4d..80a3279f 100644 --- a/src/platform/startup_notify.rs +++ b/src/platform/startup_notify.rs @@ -27,7 +27,7 @@ use crate::error::{NotSupportedError, RequestError}; use crate::event_loop::{ActiveEventLoop, AsyncRequestSerial}; #[cfg(wayland_platform)] use crate::platform::wayland::ActiveEventLoopExtWayland; -use crate::window::{ActivationToken, Window, WindowAttributes}; +use crate::window::{ActivationToken, Window}; /// The variable which is used mostly on X11. const X11_VAR: &str = "DESKTOP_STARTUP_ID"; @@ -88,13 +88,6 @@ impl WindowExtStartupNotify for dyn Window + '_ { } } -impl WindowAttributesExtStartupNotify for WindowAttributes { - fn with_activation_token(mut self, token: ActivationToken) -> Self { - self.platform_specific.activation_token = Some(token); - self - } -} - /// Remove the activation environment variables from the current process. /// /// This is wise to do before running child processes, @@ -108,6 +101,7 @@ pub fn reset_activation_token_env() { /// /// This could be used before running daemon processes. pub fn set_activation_token_env(token: ActivationToken) { - env::set_var(X11_VAR, &token.token); - env::set_var(WAYLAND_VAR, token.token); + let token = token.into_raw(); + env::set_var(X11_VAR, &token); + env::set_var(WAYLAND_VAR, token); } diff --git a/src/platform/wayland.rs b/src/platform/wayland.rs index b26e5cd2..119358c9 100644 --- a/src/platform/wayland.rs +++ b/src/platform/wayland.rs @@ -13,14 +13,15 @@ //! * `wayland-csd-adwaita` (default). //! * `wayland-csd-adwaita-crossfont`. //! * `wayland-csd-adwaita-notitle`. - use std::ffi::c_void; use std::ptr::NonNull; +use winit_core::window::PlatformWindowAttributes; + use crate::event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder}; use crate::platform_impl::wayland::Window; -pub use crate::window::Theme; -use crate::window::{Window as CoreWindow, WindowAttributes}; +use crate::platform_impl::ApplicationName; +use crate::window::{ActivationToken, Window as CoreWindow}; /// Additional methods on [`ActiveEventLoop`] that are specific to Wayland. pub trait ActiveEventLoopExtWayland { @@ -89,8 +90,14 @@ impl WindowExtWayland for dyn CoreWindow + '_ { } } -/// Additional methods on [`WindowAttributes`] that are specific to Wayland. -pub trait WindowAttributesExtWayland { +/// Window attributes methods specific to Wayland. +#[derive(Debug, Default, Clone)] +pub struct WindowAttributesWayland { + pub(crate) name: Option, + pub(crate) activation_token: Option, +} + +impl WindowAttributesWayland { /// Build window with the given name. /// /// The `general` name sets an application ID, which should match the `.desktop` @@ -98,14 +105,22 @@ pub trait WindowAttributesExtWayland { /// /// For details about application ID conventions, see the /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id) - fn with_name(self, general: impl Into, instance: impl Into) -> Self; -} - -impl WindowAttributesExtWayland for WindowAttributes { #[inline] - fn with_name(mut self, general: impl Into, instance: impl Into) -> Self { - self.platform_specific.name = + pub fn with_name(mut self, general: impl Into, instance: impl Into) -> Self { + self.name = Some(crate::platform_impl::ApplicationName::new(general.into(), instance.into())); self } + + #[inline] + pub fn with_activation_token(mut self, token: ActivationToken) -> Self { + self.activation_token = Some(token); + self + } +} + +impl PlatformWindowAttributes for WindowAttributesWayland { + fn box_clone(&self) -> Box { + Box::from(self.clone()) + } } diff --git a/src/platform/web.rs b/src/platform/web.rs index db738730..c25f98c4 100644 --- a/src/platform/web.rs +++ b/src/platform/web.rs @@ -53,13 +53,15 @@ use std::task::{Context, Poll}; use serde::{Deserialize, Serialize}; #[cfg(web_platform)] use web_sys::HtmlCanvasElement; +use winit_core::window::PlatformWindowAttributes; use crate::application::ApplicationHandler; -use crate::cursor::CustomCursorSource; +use crate::cursor::{CustomCursor, CustomCursorSource}; use crate::error::NotSupportedError; use crate::event_loop::{ActiveEventLoop, EventLoop}; use crate::monitor::MonitorHandleProvider; -use crate::platform_impl::MonitorHandle as WebMonitorHandle; +use crate::platform_impl::main_thread::{MainThreadMarker, MainThreadSafe}; +use crate::platform_impl::{web_sys as backend, MonitorHandle as WebMonitorHandle}; #[cfg(web_platform)] use crate::platform_impl::{ CustomCursorFuture as PlatformCustomCursorFuture, @@ -67,7 +69,7 @@ use crate::platform_impl::{ MonitorPermissionFuture as PlatformMonitorPermissionFuture, OrientationLockFuture as PlatformOrientationLockFuture, }; -use crate::window::{CustomCursor, Window, WindowAttributes}; +use crate::window::Window; #[cfg(not(web_platform))] #[doc(hidden)] @@ -127,7 +129,15 @@ impl WindowExtWeb for dyn Window + '_ { } } -pub trait WindowAttributesExtWeb { +#[derive(Clone, Debug)] +pub struct WindowAttributesWeb { + pub(crate) canvas: Option>>, + pub(crate) prevent_default: bool, + pub(crate) focusable: bool, + pub(crate) append: bool, +} + +impl WindowAttributesWeb { /// Pass an [`HtmlCanvasElement`] to be used for this [`Window`]. If [`None`], /// [`WindowAttributes::default()`] will create one. /// @@ -135,7 +145,18 @@ pub trait WindowAttributesExtWeb { /// /// [`None`] by default. #[cfg_attr(not(web_platform), doc = "", doc = "[`HtmlCanvasElement`]: #only-available-on-wasm")] - fn with_canvas(self, canvas: Option) -> Self; + pub fn with_canvas(mut self, canvas: Option) -> Self { + match canvas { + Some(canvas) => { + let main_thread = MainThreadMarker::new() + .expect("received a `HtmlCanvasElement` outside the window context"); + self.canvas = Some(Arc::new(MainThreadSafe::new(main_thread, canvas))); + }, + None => self.canvas = None, + } + + self + } /// Sets whether `event.preventDefault()` should be called on events on the /// canvas that have side effects. @@ -143,39 +164,50 @@ pub trait WindowAttributesExtWeb { /// See [`WindowExtWeb::set_prevent_default()`] for more details. /// /// Enabled by default. - fn with_prevent_default(self, prevent_default: bool) -> Self; + pub fn with_prevent_default(mut self, prevent_default: bool) -> Self { + self.prevent_default = prevent_default; + self + } /// Whether the canvas should be focusable using the tab key. This is necessary to capture /// canvas keyboard events. /// /// Enabled by default. - fn with_focusable(self, focusable: bool) -> Self; + pub fn with_focusable(mut self, focusable: bool) -> Self { + self.focusable = focusable; + self + } /// On window creation, append the canvas element to the Web page if it isn't already. /// /// Disabled by default. - fn with_append(self, append: bool) -> Self; + pub fn with_append(mut self, append: bool) -> Self { + self.append = append; + self + } } -impl WindowAttributesExtWeb for WindowAttributes { - fn with_canvas(mut self, canvas: Option) -> Self { - self.platform_specific.set_canvas(canvas); - self +impl PlatformWindowAttributes for WindowAttributesWeb { + fn box_clone(&self) -> Box { + Box::from(self.clone()) } +} - fn with_prevent_default(mut self, prevent_default: bool) -> Self { - self.platform_specific.prevent_default = prevent_default; - self +impl PartialEq for WindowAttributesWeb { + fn eq(&self, other: &Self) -> bool { + (match (&self.canvas, &other.canvas) { + (Some(this), Some(other)) => Arc::ptr_eq(this, other), + (None, None) => true, + _ => false, + }) && self.prevent_default.eq(&other.prevent_default) + && self.focusable.eq(&other.focusable) + && self.append.eq(&other.append) } +} - fn with_focusable(mut self, focusable: bool) -> Self { - self.platform_specific.focusable = focusable; - self - } - - fn with_append(mut self, append: bool) -> Self { - self.platform_specific.append = append; - self +impl Default for WindowAttributesWeb { + fn default() -> Self { + Self { canvas: None, prevent_default: true, focusable: true, append: false } } } diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 02a7df2b..015029ff 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -12,13 +12,14 @@ use std::sync::Arc; use serde::{Deserialize, Serialize}; #[cfg(windows_platform)] use windows_sys::Win32::Foundation::HANDLE; +use winit_core::window::PlatformWindowAttributes; use crate::dpi::PhysicalSize; use crate::event::DeviceId; use crate::event_loop::EventLoopBuilder; -use crate::icon::BadIcon; +use crate::icon::{BadIcon, Icon}; use crate::platform_impl::RaiiIcon; -use crate::window::{Icon, Window, WindowAttributes}; +use crate::window::Window; /// Window Handle type used by Win32 API pub type HWND = *mut c_void; @@ -446,9 +447,49 @@ pub trait WindowBorrowExtWindows: Borrow + Sized { impl + Sized> WindowBorrowExtWindows for W {} -/// Additional methods on `WindowAttributes` that are specific to Windows. -#[allow(rustdoc::broken_intra_doc_links)] -pub trait WindowAttributesExtWindows { +#[derive(Clone, Debug)] +pub struct WindowAttributesWindows { + pub(crate) owner: Option, + pub(crate) menu: Option, + pub(crate) taskbar_icon: Option, + pub(crate) no_redirection_bitmap: bool, + pub(crate) drag_and_drop: bool, + pub(crate) skip_taskbar: bool, + pub(crate) class_name: String, + pub(crate) decoration_shadow: bool, + pub(crate) backdrop_type: BackdropType, + pub(crate) clip_children: bool, + pub(crate) border_color: Option, + pub(crate) title_background_color: Option, + pub(crate) title_text_color: Option, + pub(crate) corner_preference: Option, +} + +impl Default for WindowAttributesWindows { + fn default() -> Self { + Self { + owner: None, + menu: None, + taskbar_icon: None, + no_redirection_bitmap: false, + drag_and_drop: true, + skip_taskbar: false, + class_name: "Window Class".to_string(), + decoration_shadow: false, + backdrop_type: BackdropType::default(), + clip_children: true, + border_color: None, + title_background_color: None, + title_text_color: None, + corner_preference: None, + } + } +} + +unsafe impl Send for WindowAttributesWindows {} +unsafe impl Sync for WindowAttributesWindows {} + +impl WindowAttributesWindows { /// Set an owner to the window to be created. Can be used to create a dialog box, for example. /// This only works when [`WindowAttributes::with_parent_window`] isn't called or set to `None`. /// Can be used in combination with @@ -461,7 +502,10 @@ pub trait WindowAttributesExtWindows { /// - An owned window is hidden when its owner is minimized. /// /// For more information, see - fn with_owner_window(self, parent: HWND) -> Self; + pub fn with_owner_window(mut self, parent: HWND) -> Self { + self.owner = Some(parent); + self + } /// Sets a menu on the window to be created. /// @@ -477,13 +521,22 @@ pub trait WindowAttributesExtWindows { doc = "[`CreateMenu`]: windows_sys::Win32::UI::WindowsAndMessaging::CreateMenu" )] #[cfg_attr(not(windows_platform), doc = "[`CreateMenu`]: #only-available-on-windows")] - fn with_menu(self, menu: HMENU) -> Self; + pub fn with_menu(mut self, menu: HMENU) -> Self { + self.menu = Some(menu); + self + } /// This sets `ICON_BIG`. A good ceiling here is 256x256. - fn with_taskbar_icon(self, taskbar_icon: Option) -> Self; + pub fn with_taskbar_icon(mut self, taskbar_icon: Option) -> Self { + self.taskbar_icon = taskbar_icon; + self + } /// This sets `WS_EX_NOREDIRECTIONBITMAP`. - fn with_no_redirection_bitmap(self, flag: bool) -> Self; + pub fn with_no_redirection_bitmap(mut self, flag: bool) -> Self { + self.no_redirection_bitmap = flag; + self + } /// Enables or disables drag and drop support (enabled by default). Will interfere with other /// crates that use multi-threaded COM API (`CoInitializeEx` with `COINIT_MULTITHREADED` @@ -491,132 +544,82 @@ pub trait WindowAttributesExtWindows { /// attempt to initialize COM API regardless of this option. Currently only fullscreen mode /// does that, but there may be more in the future. If you need COM API with /// `COINIT_MULTITHREADED` you must initialize it before calling any winit functions. See for more information. - fn with_drag_and_drop(self, flag: bool) -> Self; + pub fn with_drag_and_drop(mut self, flag: bool) -> Self { + self.drag_and_drop = flag; + self + } /// Whether show or hide the window icon in the taskbar. - fn with_skip_taskbar(self, skip: bool) -> Self; + pub fn with_skip_taskbar(mut self, skip: bool) -> Self { + self.skip_taskbar = skip; + self + } /// Customize the window class name. - fn with_class_name>(self, class_name: S) -> Self; + pub fn with_class_name>(mut self, class_name: S) -> Self { + self.class_name = class_name.into(); + self + } /// Shows or hides the background drop shadow for undecorated windows. /// /// The shadow is hidden by default. /// Enabling the shadow causes a thin 1px line to appear on the top of the window. - fn with_undecorated_shadow(self, shadow: bool) -> Self; + pub fn with_undecorated_shadow(mut self, shadow: bool) -> Self { + self.decoration_shadow = shadow; + self + } /// Sets system-drawn backdrop type. /// /// Requires Windows 11 build 22523+. - fn with_system_backdrop(self, backdrop_type: BackdropType) -> Self; + pub fn with_system_backdrop(mut self, backdrop_type: BackdropType) -> Self { + self.backdrop_type = backdrop_type; + self + } /// This sets or removes `WS_CLIPCHILDREN` style. - fn with_clip_children(self, flag: bool) -> Self; + pub fn with_clip_children(mut self, flag: bool) -> Self { + self.clip_children = flag; + self + } /// Sets the color of the window border. /// /// Supported starting with Windows 11 Build 22000. - fn with_border_color(self, color: Option) -> Self; + pub fn with_border_color(mut self, color: Option) -> Self { + self.border_color = Some(color.unwrap_or(Color::NONE)); + self + } /// Sets the background color of the title bar. /// /// Supported starting with Windows 11 Build 22000. - fn with_title_background_color(self, color: Option) -> Self; + pub fn with_title_background_color(mut self, color: Option) -> Self { + self.title_background_color = Some(color.unwrap_or(Color::NONE)); + self + } /// Sets the color of the window title. /// /// Supported starting with Windows 11 Build 22000. - fn with_title_text_color(self, color: Color) -> Self; + pub fn with_title_text_color(mut self, color: Color) -> Self { + self.title_text_color = Some(color); + self + } /// Sets the preferred style of the window corners. /// /// Supported starting with Windows 11 Build 22000. - fn with_corner_preference(self, corners: CornerPreference) -> Self; + pub fn with_corner_preference(mut self, corners: CornerPreference) -> Self { + self.corner_preference = Some(corners); + self + } } -impl WindowAttributesExtWindows for WindowAttributes { - #[inline] - fn with_owner_window(mut self, parent: HWND) -> Self { - self.platform_specific.owner = Some(parent); - self - } - - #[inline] - fn with_menu(mut self, menu: HMENU) -> Self { - self.platform_specific.menu = Some(menu); - self - } - - #[inline] - fn with_taskbar_icon(mut self, taskbar_icon: Option) -> Self { - self.platform_specific.taskbar_icon = taskbar_icon; - self - } - - #[inline] - fn with_no_redirection_bitmap(mut self, flag: bool) -> Self { - self.platform_specific.no_redirection_bitmap = flag; - self - } - - #[inline] - fn with_drag_and_drop(mut self, flag: bool) -> Self { - self.platform_specific.drag_and_drop = flag; - self - } - - #[inline] - fn with_skip_taskbar(mut self, skip: bool) -> Self { - self.platform_specific.skip_taskbar = skip; - self - } - - #[inline] - fn with_class_name>(mut self, class_name: S) -> Self { - self.platform_specific.class_name = class_name.into(); - self - } - - #[inline] - fn with_undecorated_shadow(mut self, shadow: bool) -> Self { - self.platform_specific.decoration_shadow = shadow; - self - } - - #[inline] - fn with_system_backdrop(mut self, backdrop_type: BackdropType) -> Self { - self.platform_specific.backdrop_type = backdrop_type; - self - } - - #[inline] - fn with_clip_children(mut self, flag: bool) -> Self { - self.platform_specific.clip_children = flag; - self - } - - #[inline] - fn with_border_color(mut self, color: Option) -> Self { - self.platform_specific.border_color = Some(color.unwrap_or(Color::NONE)); - self - } - - #[inline] - fn with_title_background_color(mut self, color: Option) -> Self { - self.platform_specific.title_background_color = Some(color.unwrap_or(Color::NONE)); - self - } - - #[inline] - fn with_title_text_color(mut self, color: Color) -> Self { - self.platform_specific.title_text_color = Some(color); - self - } - - #[inline] - fn with_corner_preference(mut self, corners: CornerPreference) -> Self { - self.platform_specific.corner_preference = Some(corners); - self +impl PlatformWindowAttributes for WindowAttributesWindows { + fn box_clone(&self) -> Box { + Box::from(self.clone()) } } @@ -733,7 +736,7 @@ impl WinIcon { /// /// ```rust,no_run /// # use winit::platform::windows::WinIcon; - /// # use winit::window::Icon; + /// # use winit::icon::Icon; /// assert!(WinIcon::from_resource_name("0", None).is_ok()); /// assert!(WinIcon::from_resource(0, None).is_err()); /// ``` diff --git a/src/platform/x11.rs b/src/platform/x11.rs index 4443b3a0..3d106fae 100644 --- a/src/platform/x11.rs +++ b/src/platform/x11.rs @@ -1,10 +1,11 @@ //! # X11 #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use winit_core::window::{ActivationToken, PlatformWindowAttributes, Window as CoreWindow}; use crate::dpi::Size; use crate::event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder}; -use crate::window::{Window as CoreWindow, WindowAttributes}; +use crate::platform_impl::ApplicationName; /// X window type. Maps directly to /// [`_NET_WM_WINDOW_TYPE`](https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html). @@ -141,12 +142,46 @@ pub trait WindowExtX11 {} impl WindowExtX11 for dyn CoreWindow {} -/// Additional methods on [`WindowAttributes`] that are specific to X11. -pub trait WindowAttributesExtX11 { - /// Create this window with a specific X11 visual. - fn with_x11_visual(self, visual_id: XVisualID) -> Self; +#[derive(Clone, Debug)] +pub struct WindowAttributesX11 { + pub(crate) name: Option, + pub(crate) activation_token: Option, + pub(crate) visual_id: Option, + pub(crate) screen_id: Option, + pub(crate) base_size: Option, + pub(crate) override_redirect: bool, + pub(crate) x11_window_types: Vec, - fn with_x11_screen(self, screen_id: i32) -> Self; + /// The parent window to embed this window into. + pub(crate) embed_window: Option, +} + +impl Default for WindowAttributesX11 { + fn default() -> Self { + Self { + name: None, + activation_token: None, + visual_id: None, + screen_id: None, + base_size: None, + override_redirect: false, + x11_window_types: vec![WindowType::Normal], + embed_window: None, + } + } +} + +impl WindowAttributesX11 { + /// Create this window with a specific X11 visual. + pub fn with_x11_visual(mut self, visual_id: XVisualID) -> Self { + self.visual_id = Some(visual_id); + self + } + + pub fn with_x11_screen(mut self, screen_id: i32) -> Self { + self.screen_id = Some(screen_id); + self + } /// Build window with the given `general` and `instance` names. /// @@ -156,27 +191,40 @@ pub trait WindowAttributesExtX11 { /// /// For details about application ID conventions, see the /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id) - fn with_name(self, general: impl Into, instance: impl Into) -> Self; + pub fn with_name(mut self, general: impl Into, instance: impl Into) -> Self { + self.name = + Some(crate::platform_impl::ApplicationName::new(general.into(), instance.into())); + self + } /// Build window with override-redirect flag; defaults to false. - fn with_override_redirect(self, override_redirect: bool) -> Self; + pub fn with_override_redirect(mut self, override_redirect: bool) -> Self { + self.override_redirect = override_redirect; + self + } /// Build window with `_NET_WM_WINDOW_TYPE` hints; defaults to `Normal`. - fn with_x11_window_type(self, x11_window_type: Vec) -> Self; + pub fn with_x11_window_type(mut self, x11_window_types: Vec) -> Self { + self.x11_window_types = x11_window_types; + self + } /// Build window with base size hint. /// /// ``` /// # use winit::dpi::{LogicalSize, PhysicalSize}; /// # use winit::window::{Window, WindowAttributes}; - /// # use winit::platform::x11::WindowAttributesExtX11; + /// # use winit::platform::x11::WindowAttributesX11; /// // Specify the size in logical dimensions like this: - /// WindowAttributes::default().with_base_size(LogicalSize::new(400.0, 200.0)); + /// WindowAttributesX11::default().with_base_size(LogicalSize::new(400.0, 200.0)); /// /// // Or specify the size in physical dimensions like this: - /// WindowAttributes::default().with_base_size(PhysicalSize::new(400, 200)); + /// WindowAttributesX11::default().with_base_size(PhysicalSize::new(400, 200)); /// ``` - fn with_base_size>(self, base_size: S) -> Self; + pub fn with_base_size>(mut self, base_size: S) -> Self { + self.base_size = Some(base_size.into()); + self + } /// Embed this window into another parent window. /// @@ -185,57 +233,28 @@ pub trait WindowAttributesExtX11 { /// ```no_run /// use winit::window::{Window, WindowAttributes}; /// use winit::event_loop::ActiveEventLoop; - /// use winit::platform::x11::{XWindow, WindowAttributesExtX11}; + /// use winit::platform::x11::{XWindow, WindowAttributesX11}; /// # fn create_window(event_loop: &dyn ActiveEventLoop) -> Result<(), Box> { /// let parent_window_id = std::env::args().nth(1).unwrap().parse::()?; - /// let window_attributes = WindowAttributes::default().with_embed_parent_window(parent_window_id); + /// let window_x11_attributes = WindowAttributesX11::default().with_embed_parent_window(parent_window_id); + /// let window_attributes = WindowAttributes::default().with_platform_attributes(Box::new(window_x11_attributes)); /// let window = event_loop.create_window(window_attributes)?; /// # Ok(()) } /// ``` - fn with_embed_parent_window(self, parent_window_id: XWindow) -> Self; -} - -impl WindowAttributesExtX11 for WindowAttributes { - #[inline] - fn with_x11_visual(mut self, visual_id: XVisualID) -> Self { - self.platform_specific.x11.visual_id = Some(visual_id); + pub fn with_embed_parent_window(mut self, parent_window_id: XWindow) -> Self { + self.embed_window = Some(parent_window_id); self } #[inline] - fn with_x11_screen(mut self, screen_id: i32) -> Self { - self.platform_specific.x11.screen_id = Some(screen_id); - self - } - - #[inline] - fn with_name(mut self, general: impl Into, instance: impl Into) -> Self { - self.platform_specific.name = - Some(crate::platform_impl::ApplicationName::new(general.into(), instance.into())); - self - } - - #[inline] - fn with_override_redirect(mut self, override_redirect: bool) -> Self { - self.platform_specific.x11.override_redirect = override_redirect; - self - } - - #[inline] - fn with_x11_window_type(mut self, x11_window_types: Vec) -> Self { - self.platform_specific.x11.x11_window_types = x11_window_types; - self - } - - #[inline] - fn with_base_size>(mut self, base_size: S) -> Self { - self.platform_specific.x11.base_size = Some(base_size.into()); - self - } - - #[inline] - fn with_embed_parent_window(mut self, parent_window_id: XWindow) -> Self { - self.platform_specific.x11.embed_window = Some(parent_window_id); + pub fn with_activation_token(mut self, token: ActivationToken) -> Self { + self.activation_token = Some(token); self } } + +impl PlatformWindowAttributes for WindowAttributesX11 { + fn box_clone(&self) -> Box { + Box::from(self.clone()) + } +} diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index c768e3bb..ab3c6f36 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -11,7 +11,7 @@ use android_activity::{ use tracing::{debug, trace, warn}; use crate::application::ApplicationHandler; -use crate::cursor::Cursor; +use crate::cursor::{Cursor, CustomCursor, CustomCursorSource}; use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{EventLoopError, NotSupportedError, RequestError}; use crate::event::{self, DeviceId, FingerId, Force, StartCause, SurfaceSizeWriter}; @@ -23,8 +23,8 @@ use crate::event_loop::{ use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle}; use crate::platform::pump_events::PumpStatus; use crate::window::{ - self, CursorGrabMode, CustomCursor, CustomCursorSource, ImePurpose, ResizeDirection, Theme, - Window as CoreWindow, WindowAttributes, WindowButtons, WindowId, WindowLevel, + self, CursorGrabMode, ImePurpose, ResizeDirection, Theme, Window as CoreWindow, + WindowAttributes, WindowButtons, WindowId, WindowLevel, }; mod keycodes; diff --git a/src/platform_impl/apple/appkit/cursor.rs b/src/platform_impl/apple/appkit/cursor.rs index 45036a26..80903d50 100644 --- a/src/platform_impl/apple/appkit/cursor.rs +++ b/src/platform_impl/apple/appkit/cursor.rs @@ -10,9 +10,8 @@ use objc2_foundation::{ ns_string, NSData, NSDictionary, NSNumber, NSObject, NSPoint, NSSize, NSString, }; -use crate::cursor::{CursorImage, CustomCursorProvider, CustomCursorSource}; +use crate::cursor::{CursorIcon, CursorImage, CustomCursorProvider, CustomCursorSource}; use crate::error::{NotSupportedError, RequestError}; -use crate::window::CursorIcon; #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct CustomCursor(pub(crate) Retained); diff --git a/src/platform_impl/apple/appkit/event_loop.rs b/src/platform_impl/apple/appkit/event_loop.rs index 849e40a0..b81319a2 100644 --- a/src/platform_impl/apple/appkit/event_loop.rs +++ b/src/platform_impl/apple/appkit/event_loop.rs @@ -24,6 +24,7 @@ use super::event::dummy_event; use super::monitor; use super::observer::setup_control_flow_observers; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor as CoreCustomCursor, CustomCursorSource}; use crate::error::{EventLoopError, RequestError}; use crate::event_loop::{ ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, @@ -33,7 +34,7 @@ use crate::monitor::MonitorHandle as CoreMonitorHandle; use crate::platform::macos::ActivationPolicy; use crate::platform::pump_events::PumpStatus; use crate::platform_impl::Window; -use crate::window::{CustomCursor as CoreCustomCursor, CustomCursorSource, Theme}; +use crate::window::Theme; #[derive(Default)] pub struct PanicInfo { diff --git a/src/platform_impl/apple/appkit/mod.rs b/src/platform_impl/apple/appkit/mod.rs index ef2e597f..c9fc98b8 100644 --- a/src/platform_impl/apple/appkit/mod.rs +++ b/src/platform_impl/apple/appkit/mod.rs @@ -20,4 +20,3 @@ pub(crate) use self::event_loop::{ }; pub(crate) use self::monitor::MonitorHandle; pub(crate) use self::window::Window; -pub(crate) use self::window_delegate::PlatformSpecificWindowAttributes; diff --git a/src/platform_impl/apple/appkit/window.rs b/src/platform_impl/apple/appkit/window.rs index 5e66bd40..1e21177f 100644 --- a/src/platform_impl/apple/appkit/window.rs +++ b/src/platform_impl/apple/appkit/window.rs @@ -11,11 +11,13 @@ use objc2_foundation::NSObject; use super::event_loop::ActiveEventLoop; use super::window_delegate::WindowDelegate; +use crate::cursor::Cursor; use crate::error::RequestError; +use crate::icon::Icon; use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle}; use crate::window::{ - Cursor, Icon, ImePurpose, Theme, UserAttentionType, Window as CoreWindow, WindowAttributes, - WindowButtons, WindowId, WindowLevel, + ImePurpose, Theme, UserAttentionType, Window as CoreWindow, WindowAttributes, WindowButtons, + WindowId, WindowLevel, }; #[derive(Debug)] diff --git a/src/platform_impl/apple/appkit/window_delegate.rs b/src/platform_impl/apple/appkit/window_delegate.rs index 62555bc9..826c3d4d 100644 --- a/src/platform_impl/apple/appkit/window_delegate.rs +++ b/src/platform_impl/apple/appkit/window_delegate.rs @@ -45,59 +45,21 @@ use super::util::cgerr; use super::view::WinitView; use super::window::{window_id, WinitPanel, WinitWindow}; use super::{ffi, MonitorHandle}; +use crate::cursor::Cursor; use crate::dpi::{ LogicalInsets, LogicalPosition, LogicalSize, PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size, }; use crate::error::{NotSupportedError, RequestError}; use crate::event::{SurfaceSizeWriter, WindowEvent}; +use crate::icon::Icon; use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle, MonitorHandleProvider}; -use crate::platform::macos::{OptionAsAlt, WindowExtMacOS}; +use crate::platform::macos::{OptionAsAlt, WindowAttributesMacOS, WindowExtMacOS}; use crate::window::{ - Cursor, CursorGrabMode, Icon, ImePurpose, ResizeDirection, Theme, UserAttentionType, - WindowAttributes, WindowButtons, WindowId, WindowLevel, + CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes, + WindowButtons, WindowId, WindowLevel, }; -#[derive(Clone, Debug, PartialEq)] -pub struct PlatformSpecificWindowAttributes { - pub movable_by_window_background: bool, - pub titlebar_transparent: bool, - pub title_hidden: bool, - pub titlebar_hidden: bool, - pub titlebar_buttons_hidden: bool, - pub fullsize_content_view: bool, - pub disallow_hidpi: bool, - pub has_shadow: bool, - pub accepts_first_mouse: bool, - pub tabbing_identifier: Option, - pub option_as_alt: OptionAsAlt, - pub borderless_game: bool, - pub unified_titlebar: bool, - pub panel: bool, -} - -impl Default for PlatformSpecificWindowAttributes { - #[inline] - fn default() -> Self { - Self { - movable_by_window_background: false, - titlebar_transparent: false, - title_hidden: false, - titlebar_hidden: false, - titlebar_buttons_hidden: false, - fullsize_content_view: false, - disallow_hidpi: false, - has_shadow: true, - accepts_first_mouse: true, - tabbing_identifier: None, - option_as_alt: Default::default(), - borderless_game: false, - unified_titlebar: false, - panel: false, - } - } -} - #[derive(Debug)] pub(crate) struct State { /// Strong reference to the global application state. @@ -552,6 +514,7 @@ impl Drop for WindowDelegate { fn new_window( app_state: &Rc, attrs: &WindowAttributes, + macos_attrs: &WindowAttributesMacOS, mtm: MainThreadMarker, ) -> Option> { autoreleasepool(|_| { @@ -592,9 +555,7 @@ fn new_window( }, }; - let mut masks = if (!attrs.decorations && screen.is_none()) - || attrs.platform_specific.titlebar_hidden - { + let mut masks = if (!attrs.decorations && screen.is_none()) || macos_attrs.titlebar_hidden { // Resizable without a titlebar or borders // if decorations is set to false, ignore pl_attrs // @@ -622,7 +583,7 @@ fn new_window( masks &= !NSWindowStyleMask::Closable; } - if attrs.platform_specific.fullsize_content_view { + if macos_attrs.fullsize_content_view { // NOTE: If we decide to add an option to change this at runtime, we must emit a // `SurfaceResized` event to let applications know that the safe area changed. // @@ -637,7 +598,7 @@ fn new_window( // confusing issues with the window not being properly activated. // // Winit ensures this by not allowing access to `ActiveEventLoop` before handling events. - let window: Retained = if attrs.platform_specific.panel { + let window: Retained = if macos_attrs.panel { masks |= NSWindowStyleMask::NonactivatingPanel; let window: Option> = unsafe { @@ -673,7 +634,7 @@ fn new_window( window.setTitle(&NSString::from_str(&attrs.title)); window.setAcceptsMouseMovedEvents(true); - if let Some(identifier) = &attrs.platform_specific.tabbing_identifier { + if let Some(identifier) = &macos_attrs.tabbing_identifier { window.setTabbingIdentifier(&NSString::from_str(identifier)); window.setTabbingMode(NSWindowTabbingMode::Preferred); } @@ -682,13 +643,13 @@ fn new_window( window.setSharingType(NSWindowSharingType::None); } - if attrs.platform_specific.titlebar_transparent { + if macos_attrs.titlebar_transparent { window.setTitlebarAppearsTransparent(true); } - if attrs.platform_specific.title_hidden { + if macos_attrs.title_hidden { window.setTitleVisibility(NSWindowTitleVisibility::Hidden); } - if attrs.platform_specific.titlebar_buttons_hidden { + if macos_attrs.titlebar_buttons_hidden { for titlebar_button in &[ #[allow(deprecated)] NSWindowFullScreenButton, @@ -701,10 +662,10 @@ fn new_window( } } } - if attrs.platform_specific.movable_by_window_background { + if macos_attrs.movable_by_window_background { window.setMovableByWindowBackground(true); } - if attrs.platform_specific.unified_titlebar { + if macos_attrs.unified_titlebar { unsafe { // The toolbar style is ignored if there is no toolbar, so it is // necessary to add one. @@ -719,7 +680,7 @@ fn new_window( } } - if !attrs.platform_specific.has_shadow { + if !macos_attrs.has_shadow { window.setHasShadow(false); } if attrs.position.is_none() { @@ -728,8 +689,8 @@ fn new_window( let view = WinitView::new( app_state, - attrs.platform_specific.accepts_first_mouse, - attrs.platform_specific.option_as_alt, + macos_attrs.accepts_first_mouse, + macos_attrs.option_as_alt, mtm, ); @@ -737,7 +698,7 @@ fn new_window( // macos 10.14 and `true` after 10.15, we should set it to `YES` or `NO` to avoid // always the default system value in favour of the user's code #[allow(deprecated)] - view.setWantsBestResolutionOpenGLSurface(!attrs.platform_specific.disallow_hidpi); + view.setWantsBestResolutionOpenGLSurface(!macos_attrs.disallow_hidpi); // On Mojave, views automatically become layer-backed shortly after being added to // a window. Changing the layer-backedness of a view breaks the association between @@ -785,13 +746,19 @@ fn new_window( impl WindowDelegate { pub(super) fn new( app_state: &Rc, - attrs: WindowAttributes, + mut attrs: WindowAttributes, mtm: MainThreadMarker, ) -> Result, RequestError> { - let window = new_window(app_state, &attrs, mtm) + let macos_attrs = attrs + .platform + .take() + .and_then(|attrs| attrs.cast::().ok()) + .unwrap_or_default(); + + let window = new_window(app_state, &attrs, &macos_attrs, mtm) .ok_or_else(|| os_error!("couldn't create `NSWindow`"))?; - match attrs.parent_window.map(|handle| handle.0) { + match attrs.parent_window() { Some(rwh_06::RawWindowHandle::AppKit(handle)) => { // SAFETY: Caller ensures the pointer is valid or NULL // Unwrap is fine, since the pointer comes from `NonNull`. @@ -843,7 +810,7 @@ impl WindowDelegate { standard_frame: Cell::new(None), is_simple_fullscreen: Cell::new(false), saved_style: Cell::new(None), - is_borderless_game: Cell::new(attrs.platform_specific.borderless_game), + is_borderless_game: Cell::new(macos_attrs.borderless_game), }); let delegate: Retained = unsafe { msg_send![super(delegate), init] }; diff --git a/src/platform_impl/apple/uikit/event_loop.rs b/src/platform_impl/apple/uikit/event_loop.rs index c9f4009a..a0819923 100644 --- a/src/platform_impl/apple/uikit/event_loop.rs +++ b/src/platform_impl/apple/uikit/event_loop.rs @@ -21,6 +21,7 @@ use super::super::notification_center::create_observer; use super::app_state::{send_occluded_event_for_all_windows, AppState}; use super::{app_state, monitor, MonitorHandle}; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor, CustomCursorSource}; use crate::error::{EventLoopError, NotSupportedError, RequestError}; use crate::event_loop::{ ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, @@ -28,7 +29,7 @@ use crate::event_loop::{ }; use crate::monitor::MonitorHandle as CoreMonitorHandle; use crate::platform_impl::Window; -use crate::window::{CustomCursor, CustomCursorSource, Theme, Window as CoreWindow}; +use crate::window::{Theme, Window as CoreWindow}; #[derive(Debug)] pub(crate) struct ActiveEventLoop { diff --git a/src/platform_impl/apple/uikit/mod.rs b/src/platform_impl/apple/uikit/mod.rs index 6a7c088c..764cf8e6 100644 --- a/src/platform_impl/apple/uikit/mod.rs +++ b/src/platform_impl/apple/uikit/mod.rs @@ -13,7 +13,7 @@ pub(crate) use self::event_loop::{ ActiveEventLoop, EventLoop, PlatformSpecificEventLoopAttributes, }; pub(crate) use self::monitor::MonitorHandle; -pub(crate) use self::window::{PlatformSpecificWindowAttributes, Window}; +pub(crate) use self::window::Window; #[derive(Debug)] pub enum OsError {} diff --git a/src/platform_impl/apple/uikit/view.rs b/src/platform_impl/apple/uikit/view.rs index af733a60..5123fd61 100644 --- a/src/platform_impl/apple/uikit/view.rs +++ b/src/platform_impl/apple/uikit/view.rs @@ -22,7 +22,6 @@ use crate::event::{ WindowEvent, }; use crate::keyboard::{Key, KeyCode, KeyLocation, NamedKey, NativeKeyCode, PhysicalKey}; -use crate::window::WindowAttributes; pub struct WinitViewState { pinch_gesture_recognizer: RefCell>>, @@ -337,7 +336,7 @@ define_class!( impl WinitView { pub(crate) fn new( mtm: MainThreadMarker, - window_attributes: &WindowAttributes, + scale_factor: Option, frame: CGRect, ) -> Retained { let this = mtm.alloc().set_ivars(WinitViewState { @@ -357,7 +356,7 @@ impl WinitView { this.setMultipleTouchEnabled(true); - if let Some(scale_factor) = window_attributes.platform_specific.scale_factor { + if let Some(scale_factor) = scale_factor { this.setContentScaleFactor(scale_factor as _); } diff --git a/src/platform_impl/apple/uikit/view_controller.rs b/src/platform_impl/apple/uikit/view_controller.rs index f860838b..e3a3ddaa 100644 --- a/src/platform_impl/apple/uikit/view_controller.rs +++ b/src/platform_impl/apple/uikit/view_controller.rs @@ -8,8 +8,7 @@ use objc2_ui_kit::{ UIUserInterfaceIdiom, UIView, UIViewController, }; -use crate::platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations}; -use crate::window::WindowAttributes; +use crate::platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations, WindowAttributesIos}; pub struct ViewControllerState { prefers_status_bar_hidden: Cell, @@ -129,7 +128,7 @@ impl WinitViewController { pub(crate) fn new( mtm: MainThreadMarker, - window_attributes: &WindowAttributes, + ios_attributes: &WindowAttributesIos, view: &UIView, ) -> Retained { // These are set properly below, we just to set them to something in the meantime. @@ -142,25 +141,16 @@ impl WinitViewController { }); let this: Retained = unsafe { msg_send![super(this), init] }; - this.set_prefers_status_bar_hidden( - window_attributes.platform_specific.prefers_status_bar_hidden, - ); + this.set_prefers_status_bar_hidden(ios_attributes.prefers_status_bar_hidden); - this.set_preferred_status_bar_style( - window_attributes.platform_specific.preferred_status_bar_style, - ); + this.set_preferred_status_bar_style(ios_attributes.preferred_status_bar_style); - this.set_supported_interface_orientations( - mtm, - window_attributes.platform_specific.valid_orientations, - ); + this.set_supported_interface_orientations(mtm, ios_attributes.valid_orientations); - this.set_prefers_home_indicator_auto_hidden( - window_attributes.platform_specific.prefers_home_indicator_hidden, - ); + this.set_prefers_home_indicator_auto_hidden(ios_attributes.prefers_home_indicator_hidden); this.set_preferred_screen_edges_deferring_system_gestures( - window_attributes.platform_specific.preferred_screen_edges_deferring_system_gestures, + ios_attributes.preferred_screen_edges_deferring_system_gestures, ); this.setView(Some(view)); diff --git a/src/platform_impl/apple/uikit/window.rs b/src/platform_impl/apple/uikit/window.rs index a959f1b7..a6c56b81 100644 --- a/src/platform_impl/apple/uikit/window.rs +++ b/src/platform_impl/apple/uikit/window.rs @@ -27,7 +27,7 @@ use crate::error::{NotSupportedError, RequestError}; use crate::event::WindowEvent; use crate::icon::Icon; use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle}; -use crate::platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations}; +use crate::platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations, WindowAttributesIos}; use crate::window::{ CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as CoreWindow, WindowAttributes, WindowButtons, WindowId, WindowLevel, @@ -473,7 +473,7 @@ pub struct Window { impl Window { pub(crate) fn new( event_loop: &ActiveEventLoop, - window_attributes: WindowAttributes, + mut window_attributes: WindowAttributes, ) -> Result { let mtm = event_loop.mtm; @@ -484,6 +484,12 @@ impl Window { warn!("`WindowAttributes::max_surface_size` is ignored on iOS"); } + let ios_attributes = window_attributes + .platform + .take() + .and_then(|attrs| attrs.cast::().ok()) + .unwrap_or_default(); + // TODO: transparency, visible #[allow(deprecated)] @@ -512,12 +518,12 @@ impl Window { None => screen_bounds, }; - let view = WinitView::new(mtm, &window_attributes, frame); + let view = WinitView::new(mtm, ios_attributes.scale_factor, frame); let gl_or_metal_backed = view.isKindOfClass(class!(CAMetalLayer)) || view.isKindOfClass(class!(CAEAGLLayer)); - let view_controller = WinitViewController::new(mtm, &window_attributes, &view); + let view_controller = WinitViewController::new(mtm, &ios_attributes, &view); let window = WinitUIWindow::new(mtm, &window_attributes, frame, &view_controller); window.makeKeyAndVisible(); @@ -885,13 +891,3 @@ impl Inner { self.window.convertRect_fromCoordinateSpace(rect, &screen_space) } } - -#[derive(Clone, Debug, Default, PartialEq)] -pub struct PlatformSpecificWindowAttributes { - pub scale_factor: Option, - pub valid_orientations: ValidOrientations, - pub prefers_home_indicator_hidden: bool, - pub prefers_status_bar_hidden: bool, - pub preferred_status_bar_style: StatusBarStyle, - pub preferred_screen_edges_deferring_system_gestures: ScreenEdge, -} diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index d66349df..57d109b5 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -18,6 +18,7 @@ use sctk::reexports::client::{globals, Connection, QueueHandle}; use tracing::warn; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor as CoreCustomCursor, CustomCursorSource}; use crate::dpi::LogicalSize; use crate::error::{EventLoopError, NotSupportedError, OsError, RequestError}; use crate::event::{DeviceEvent, StartCause, SurfaceSizeWriter, WindowEvent}; @@ -29,7 +30,7 @@ use crate::monitor::MonitorHandle as CoreMonitorHandle; use crate::platform::pump_events::PumpStatus; use crate::platform_impl::platform::min_timeout; use crate::platform_impl::wayland::types::cursor::WaylandCustomCursor; -use crate::window::{CustomCursor as CoreCustomCursor, CustomCursorSource, Theme}; +use crate::window::Theme; mod proxy; pub mod sink; diff --git a/src/platform_impl/linux/wayland/seat/text_input/mod.rs b/src/platform_impl/linux/wayland/seat/text_input/mod.rs index 140f7dfc..2bce758e 100644 --- a/src/platform_impl/linux/wayland/seat/text_input/mod.rs +++ b/src/platform_impl/linux/wayland/seat/text_input/mod.rs @@ -163,9 +163,9 @@ pub trait ZwpTextInputV3Ext { impl ZwpTextInputV3Ext for ZwpTextInputV3 { fn set_content_type_by_purpose(&self, purpose: ImePurpose) { let (hint, purpose) = match purpose { - ImePurpose::Normal => (ContentHint::None, ContentPurpose::Normal), ImePurpose::Password => (ContentHint::SensitiveData, ContentPurpose::Password), ImePurpose::Terminal => (ContentHint::None, ContentPurpose::Terminal), + _ => (ContentHint::None, ContentPurpose::Normal), }; self.set_content_type(hint, purpose); } diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index 66e3d25a..773116af 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -19,15 +19,17 @@ use super::output::MonitorHandle; use super::state::WinitState; use super::types::xdg_activation::XdgActivationTokenData; use super::ActiveEventLoop; +use crate::cursor::Cursor; use crate::dpi::{LogicalSize, PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{NotSupportedError, RequestError}; use crate::event::{Ime, WindowEvent}; use crate::event_loop::AsyncRequestSerial; use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle}; +use crate::platform::wayland::WindowAttributesWayland; use crate::platform_impl::wayland::output; use crate::window::{ - Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, - Window as CoreWindow, WindowAttributes, WindowButtons, WindowId, WindowLevel, + CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as CoreWindow, + WindowAttributes, WindowButtons, WindowId, WindowLevel, }; pub(crate) mod state; @@ -78,7 +80,7 @@ pub struct Window { impl Window { pub(crate) fn new( event_loop_window_target: &ActiveEventLoop, - attributes: WindowAttributes, + mut attributes: WindowAttributes, ) -> Result { let queue_handle = event_loop_window_target.queue_handle.clone(); let mut state = event_loop_window_target.state.borrow_mut(); @@ -121,8 +123,15 @@ impl Window { // Set the decorations hint. window_state.set_decorate(attributes.decorations); + let (app_name, activation_token) = + match attributes.platform.take().and_then(|p| p.cast::().ok()) + { + Some(attrs) => (attrs.name, attrs.activation_token), + None => (None, None), + }; + // Set the app_id. - if let Some(name) = attributes.platform_specific.name.map(|name| name.general) { + if let Some(name) = app_name.map(|name| name.general) { window.set_app_id(name); } @@ -162,10 +171,8 @@ impl Window { } // Activate the window when the token is passed. - if let (Some(xdg_activation), Some(token)) = - (xdg_activation.as_ref(), attributes.platform_specific.activation_token) - { - xdg_activation.activate(token.token, &surface); + if let (Some(xdg_activation), Some(token)) = (xdg_activation.as_ref(), activation_token) { + xdg_activation.activate(token.into_raw(), &surface); } // XXX Do initial commit. @@ -497,7 +504,7 @@ impl CoreWindow for Window { fn set_window_level(&self, _level: WindowLevel) {} - fn set_window_icon(&self, _window_icon: Option) {} + fn set_window_icon(&self, _window_icon: Option) {} #[inline] fn set_ime_cursor_area(&self, position: Position, size: Size) { @@ -678,23 +685,3 @@ impl WindowRequests { self.redraw_requested.swap(false, Ordering::Relaxed) } } - -impl TryFrom<&str> for Theme { - type Error = (); - - /// ``` - /// use winit::window::Theme; - /// - /// assert_eq!("dark".try_into(), Ok(Theme::Dark)); - /// assert_eq!("lIghT".try_into(), Ok(Theme::Light)); - /// ``` - fn try_from(theme: &str) -> Result { - if theme.eq_ignore_ascii_case("dark") { - Ok(Self::Dark) - } else if theme.eq_ignore_ascii_case("light") { - Ok(Self::Light) - } else { - Err(()) - } - } -} diff --git a/src/platform_impl/linux/wayland/window/state.rs b/src/platform_impl/linux/wayland/window/state.rs index 337b2af1..b4939cff 100644 --- a/src/platform_impl/linux/wayland/window/state.rs +++ b/src/platform_impl/linux/wayland/window/state.rs @@ -28,7 +28,7 @@ use sctk::subcompositor::SubcompositorState; use tracing::{info, warn}; use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur; -use crate::cursor::CustomCursor as CoreCustomCursor; +use crate::cursor::{CursorIcon, CustomCursor as CoreCustomCursor}; use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Size}; use crate::error::{NotSupportedError, RequestError}; use crate::platform_impl::wayland::event_loop::OwnedDisplayHandle; @@ -41,7 +41,7 @@ use crate::platform_impl::wayland::types::cursor::{ CustomCursor, SelectedCursor, WaylandCustomCursor, }; use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager; -use crate::window::{CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme, WindowId}; +use crate::window::{CursorGrabMode, ImePurpose, ResizeDirection, Theme, WindowId}; #[cfg(feature = "sctk-adwaita")] pub type WinitFrame = sctk_adwaita::AdwaitaFrame; @@ -398,7 +398,7 @@ impl WindowState { self.apply_on_pointer(|_, data| { let serial = data.latest_button_serial(); let seat = data.seat(); - xdg_toplevel.resize(seat, serial, direction.into()); + xdg_toplevel.resize(seat, serial, resize_direction_to_xdg(direction)); }); Ok(()) @@ -1148,18 +1148,16 @@ pub enum FrameCallbackState { Received, } -impl From for XdgResizeEdge { - fn from(value: ResizeDirection) -> Self { - match value { - ResizeDirection::North => XdgResizeEdge::Top, - ResizeDirection::West => XdgResizeEdge::Left, - ResizeDirection::NorthWest => XdgResizeEdge::TopLeft, - ResizeDirection::NorthEast => XdgResizeEdge::TopRight, - ResizeDirection::East => XdgResizeEdge::Right, - ResizeDirection::SouthWest => XdgResizeEdge::BottomLeft, - ResizeDirection::SouthEast => XdgResizeEdge::BottomRight, - ResizeDirection::South => XdgResizeEdge::Bottom, - } +fn resize_direction_to_xdg(direction: ResizeDirection) -> XdgResizeEdge { + match direction { + ResizeDirection::North => XdgResizeEdge::Top, + ResizeDirection::West => XdgResizeEdge::Left, + ResizeDirection::NorthWest => XdgResizeEdge::TopLeft, + ResizeDirection::NorthEast => XdgResizeEdge::TopRight, + ResizeDirection::East => XdgResizeEdge::Right, + ResizeDirection::SouthWest => XdgResizeEdge::BottomLeft, + ResizeDirection::SouthEast => XdgResizeEdge::BottomRight, + ResizeDirection::South => XdgResizeEdge::Bottom, } } diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 1a5ac780..3a86326d 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -23,6 +23,7 @@ use x11rb::x11_utils::X11Error as LogicalError; use x11rb::xcb_ffi::ReplyOrIdError; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor as CoreCustomCursor, CustomCursorSource}; use crate::error::{EventLoopError, RequestError}; use crate::event::{DeviceId, StartCause, WindowEvent}; use crate::event_loop::{ @@ -36,10 +37,7 @@ use crate::platform::x11::XlibErrorHook; use crate::platform_impl::common::xkb::Context; use crate::platform_impl::platform::min_timeout; use crate::platform_impl::x11::window::Window; -use crate::window::{ - CustomCursor as CoreCustomCursor, CustomCursorSource, Theme, Window as CoreWindow, - WindowAttributes, WindowId, -}; +use crate::window::{Theme, Window as CoreWindow, WindowAttributes, WindowId}; mod activation; mod atoms; diff --git a/src/platform_impl/linux/x11/util/cursor.rs b/src/platform_impl/linux/x11/util/cursor.rs index c7bf497a..a76b6f91 100644 --- a/src/platform_impl/linux/x11/util/cursor.rs +++ b/src/platform_impl/linux/x11/util/cursor.rs @@ -9,9 +9,8 @@ use x11rb::protocol::xproto; use super::super::ActiveEventLoop; use super::*; -use crate::cursor::{CustomCursorProvider, CustomCursorSource}; +use crate::cursor::{CursorIcon, CustomCursorProvider, CustomCursorSource}; use crate::error::{NotSupportedError, RequestError}; -use crate::window::CursorIcon; impl XConnection { pub fn set_cursor_icon( diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index 8c88f01a..af2422c4 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -32,7 +32,7 @@ use crate::icon::RgbaIcon; use crate::monitor::{ Fullscreen, MonitorHandle as CoreMonitorHandle, MonitorHandleProvider, VideoMode, }; -use crate::platform::x11::WindowType; +use crate::platform::x11::{WindowAttributesX11, WindowType}; use crate::platform_impl::common; use crate::platform_impl::x11::atoms::*; use crate::platform_impl::x11::util::rgba_to_cardinals; @@ -204,7 +204,7 @@ impl CoreWindow for Window { self.0.set_window_level(level); } - fn set_window_icon(&self, window_icon: Option) { + fn set_window_icon(&self, window_icon: Option) { let icon = match window_icon.as_ref() { Some(icon) => icon.cast_ref::(), None => None, @@ -443,12 +443,18 @@ impl UnownedWindow { #[allow(clippy::unnecessary_cast)] pub(crate) fn new( event_loop: &ActiveEventLoop, - window_attrs: WindowAttributes, + mut window_attrs: WindowAttributes, ) -> Result { let xconn = &event_loop.xconn; let atoms = xconn.atoms(); - let screen_id = match window_attrs.platform_specific.x11.screen_id { + let x11_attributes = window_attrs + .platform + .take() + .and_then(|attrs| attrs.cast::().ok()) + .unwrap_or_default(); + + let screen_id = match x11_attributes.screen_id { Some(id) => id, None => xconn.default_screen_index() as c_int, }; @@ -461,7 +467,7 @@ impl UnownedWindow { )? }; - let root = match window_attrs.parent_window.as_ref().map(|handle| handle.0) { + let root = match window_attrs.parent_window() { Some(rwh_06::RawWindowHandle::Xlib(handle)) => handle.window as xproto::Window, Some(rwh_06::RawWindowHandle::Xcb(handle)) => handle.window.get(), Some(raw) => unreachable!("Invalid raw window handle {raw:?} on X11"), @@ -528,33 +534,32 @@ impl UnownedWindow { .flat_map(|depth| depth.visuals.iter().map(move |visual| (visual, depth.depth))); // creating - let (visualtype, depth, require_colormap) = - match window_attrs.platform_specific.x11.visual_id { - Some(vi) => { - // Find this specific visual. - let (visualtype, depth) = all_visuals - .find(|(visual, _)| visual.visual_id == vi) - .ok_or_else(|| os_error!(X11Error::NoSuchVisual(vi)))?; + let (visualtype, depth, require_colormap) = match x11_attributes.visual_id { + Some(vi) => { + // Find this specific visual. + let (visualtype, depth) = all_visuals + .find(|(visual, _)| visual.visual_id == vi) + .ok_or_else(|| os_error!(X11Error::NoSuchVisual(vi)))?; - (Some(visualtype), depth, true) - }, - None if window_attrs.transparent => { - // Find a suitable visual, true color with 32 bits of depth. - all_visuals - .find_map(|(visual, depth)| { - (depth == 32 && visual.class == xproto::VisualClass::TRUE_COLOR) - .then_some((Some(visual), depth, true)) - }) - .unwrap_or_else(|| { - debug!( - "Could not set transparency, because XMatchVisualInfo returned \ - zero for the required parameters" - ); - (None as _, x11rb::COPY_FROM_PARENT as _, false) - }) - }, - _ => (None, x11rb::COPY_FROM_PARENT as _, false), - }; + (Some(visualtype), depth, true) + }, + None if window_attrs.transparent => { + // Find a suitable visual, true color with 32 bits of depth. + all_visuals + .find_map(|(visual, depth)| { + (depth == 32 && visual.class == xproto::VisualClass::TRUE_COLOR) + .then_some((Some(visual), depth, true)) + }) + .unwrap_or_else(|| { + debug!( + "Could not set transparency, because XMatchVisualInfo returned zero \ + for the required parameters" + ); + (None as _, x11rb::COPY_FROM_PARENT as _, false) + }) + }, + _ => (None, x11rb::COPY_FROM_PARENT as _, false), + }; let mut visual = visualtype.map_or(x11rb::COPY_FROM_PARENT, |v| v.visual_id); let window_attributes = { @@ -574,12 +579,12 @@ impl UnownedWindow { aux = aux.event_mask(event_mask).border_pixel(0); - if window_attrs.platform_specific.x11.override_redirect { + if x11_attributes.override_redirect { aux = aux.override_redirect(true as u32); } // Add a colormap if needed. - let colormap_visual = match window_attrs.platform_specific.x11.visual_id { + let colormap_visual = match x11_attributes.visual_id { Some(vi) => Some(vi), None if require_colormap => Some(visual), _ => None, @@ -602,7 +607,7 @@ impl UnownedWindow { }; // Figure out the window's parent. - let parent = window_attrs.platform_specific.x11.embed_window.unwrap_or(root); + let parent = x11_attributes.embed_window.unwrap_or(root); // finally creating the window let xwindow = { @@ -665,7 +670,7 @@ impl UnownedWindow { } // Embed the window if needed. - if window_attrs.platform_specific.x11.embed_window.is_some() { + if x11_attributes.embed_window.is_some() { window.embed_window()?; } @@ -686,7 +691,7 @@ impl UnownedWindow { // WM_CLASS must be set *before* mapping the window, as per ICCCM! { - let (instance, class) = if let Some(name) = window_attrs.platform_specific.name { + let (instance, class) = if let Some(name) = x11_attributes.name { (name.instance, name.general) } else { let class = env::args_os() @@ -717,8 +722,7 @@ impl UnownedWindow { flusher.ignore_error() } - leap!(window.set_window_types(window_attrs.platform_specific.x11.x11_window_types)) - .ignore_error(); + leap!(window.set_window_types(x11_attributes.x11_window_types)).ignore_error(); // Set size hints. let mut min_surface_size = @@ -739,7 +743,7 @@ impl UnownedWindow { shared_state.min_surface_size = min_surface_size.map(Into::into); shared_state.max_surface_size = max_surface_size.map(Into::into); shared_state.surface_resize_increments = window_attrs.surface_resize_increments; - shared_state.base_size = window_attrs.platform_specific.x11.base_size; + shared_state.base_size = x11_attributes.base_size; let normal_hints = WmSizeHints { position: position.map(|PhysicalPosition { x, y }| { @@ -755,9 +759,7 @@ impl UnownedWindow { size_increment: window_attrs .surface_resize_increments .map(|size| cast_size_to_hint(size, scale_factor)), - base_size: window_attrs - .platform_specific - .x11 + base_size: x11_attributes .base_size .map(|size| cast_size_to_hint(size, scale_factor)), aspect: None, @@ -884,8 +886,8 @@ impl UnownedWindow { window.set_cursor(window_attrs.cursor); // Remove the startup notification if we have one. - if let Some(startup) = window_attrs.platform_specific.activation_token.as_ref() { - leap!(xconn.remove_activation_token(xwindow, &startup.token)); + if let Some(startup) = x11_attributes.activation_token.as_ref() { + leap!(xconn.remove_activation_token(xwindow, startup.as_raw())); } // We never want to give the user a broken window, since by then, it's too late to handle. diff --git a/src/platform_impl/linux/x11/xdisplay.rs b/src/platform_impl/linux/x11/xdisplay.rs index f14e5beb..bd9ddce4 100644 --- a/src/platform_impl/linux/x11/xdisplay.rs +++ b/src/platform_impl/linux/x11/xdisplay.rs @@ -16,7 +16,7 @@ use x11rb::xcb_ffi::XCBConnection; use super::atoms::Atoms; use super::ffi; use super::monitor::MonitorHandle; -use crate::window::CursorIcon; +use crate::cursor::CursorIcon; /// A connection to an X server. pub struct XConnection { diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index 4e7c9a43..4318061c 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -13,6 +13,7 @@ use smol_str::SmolStr; use super::{PlatformSpecificEventLoopAttributes, RedoxSocket, TimeSocket, WindowProperties}; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor, CustomCursorSource}; use crate::error::{EventLoopError, NotSupportedError, RequestError}; use crate::event::{self, Ime, Modifiers, StartCause}; use crate::event_loop::{ @@ -25,9 +26,7 @@ use crate::keyboard::{ PhysicalKey, }; use crate::platform_impl::Window; -use crate::window::{ - CustomCursor as RootCustomCursor, CustomCursorSource, Theme, Window as CoreWindow, WindowId, -}; +use crate::window::{Theme, Window as CoreWindow, WindowId}; fn convert_scancode(scancode: u8) -> (PhysicalKey, Option) { // Key constants from https://docs.rs/orbclient/latest/orbclient/event/index.html @@ -699,10 +698,7 @@ impl RootActiveEventLoop for ActiveEventLoop { Ok(Box::new(Window::new(self, window_attributes)?)) } - fn create_custom_cursor( - &self, - _: CustomCursorSource, - ) -> Result { + fn create_custom_cursor(&self, _: CustomCursorSource) -> Result { Err(NotSupportedError::new("create_custom_cursor is not supported").into()) } diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 098dac30..7952f91d 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -11,6 +11,7 @@ use super::super::monitor::MonitorPermissionFuture; use super::runner::Event; use super::{backend, runner}; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor as CoreCustomCursor, CustomCursorSource}; use crate::error::{NotSupportedError, RequestError}; use crate::event::{ElementState, KeyEvent, TouchPhase, WindowEvent}; use crate::event_loop::{ @@ -23,7 +24,7 @@ use crate::platform::web::{CustomCursorFuture, PollStrategy, WaitUntilStrategy}; use crate::platform_impl::platform::cursor::CustomCursor; use crate::platform_impl::web::event_loop::proxy::EventLoopProxy; use crate::platform_impl::Window; -use crate::window::{CustomCursor as CoreCustomCursor, CustomCursorSource, Theme, WindowId}; +use crate::window::{Theme, WindowId}; #[derive(Default, Debug)] struct ModifiersShared(Rc>); diff --git a/src/platform_impl/web/mod.rs b/src/platform_impl/web/mod.rs index 38161534..7c98b106 100644 --- a/src/platform_impl/web/mod.rs +++ b/src/platform_impl/web/mod.rs @@ -24,13 +24,13 @@ mod r#async; mod cursor; mod error; mod event; -mod event_loop; +pub(crate) mod event_loop; mod keyboard; mod lock; -mod main_thread; +pub(crate) mod main_thread; mod monitor; -mod web_sys; -mod window; +pub(crate) mod web_sys; +pub(crate) mod window; pub(crate) use cursor::CustomCursorFuture; @@ -41,4 +41,4 @@ pub(crate) use self::monitor::{ HasMonitorPermissionFuture, MonitorHandle, MonitorPermissionFuture, OrientationLockFuture, }; use self::web_sys as backend; -pub use self::window::{PlatformSpecificWindowAttributes, Window}; +pub use self::window::Window; diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index c4ea043a..76cf8d4a 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -28,6 +28,7 @@ use crate::event::{ }; use crate::keyboard::{Key, KeyLocation, ModifiersState, PhysicalKey}; use crate::monitor::Fullscreen; +use crate::platform::web::WindowAttributesWeb; use crate::window::{WindowAttributes, WindowId}; #[allow(dead_code)] @@ -84,9 +85,15 @@ impl Canvas { window: web_sys::Window, navigator: Navigator, document: Document, - attr: WindowAttributes, + mut attr: WindowAttributes, ) -> Result { - let canvas = match attr.platform_specific.canvas.map(Arc::try_unwrap) { + let web_attributes = attr + .platform + .take() + .and_then(|attrs| attrs.cast::().ok()) + .unwrap_or_default(); + + let canvas = match web_attributes.canvas.map(Arc::try_unwrap) { Some(Ok(canvas)) => canvas.into_inner(main_thread), Some(Err(canvas)) => canvas.get(main_thread).clone(), None => document @@ -95,7 +102,7 @@ impl Canvas { .unchecked_into(), }; - if attr.platform_specific.append && !document.contains(Some(&canvas)) { + if web_attributes.append && !document.contains(Some(&canvas)) { document .body() .expect("Failed to get body from document") @@ -108,7 +115,7 @@ impl Canvas { // sequential keyboard navigation, but its order is defined by the // document's source order. // https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex - if attr.platform_specific.focusable { + if web_attributes.focusable { canvas .set_attribute("tabindex", "0") .map_err(|_| os_error!("Failed to set a tabindex"))?; @@ -161,7 +168,7 @@ impl Canvas { common, id, has_focus: Rc::new(Cell::new(false)), - prevent_default: Rc::new(Cell::new(attr.platform_specific.prevent_default)), + prevent_default: Rc::new(Cell::new(web_attributes.prevent_default)), is_intersecting: Cell::new(None), cursor, handlers: RefCell::new(Handlers { @@ -517,7 +524,7 @@ impl Canvas { self.set_old_size(new_size); runner.send_event(runner::Event::WindowEvent { window_id: self.id, - event: crate::event::WindowEvent::SurfaceResized(new_size), + event: WindowEvent::SurfaceResized(new_size), }) } } diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index 4a31c2d1..de0bd7ba 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -1,22 +1,22 @@ use std::cell::Ref; use std::fmt; use std::rc::Rc; -use std::sync::Arc; use dpi::{LogicalPosition, LogicalSize}; use web_sys::HtmlCanvasElement; -use super::main_thread::{MainThreadMarker, MainThreadSafe}; +use super::main_thread::MainThreadMarker; use super::monitor::MonitorHandler; use super::r#async::Dispatcher; use super::{backend, lock, ActiveEventLoop}; +use crate::cursor::Cursor; use crate::dpi::{LogicalInsets, PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{NotSupportedError, RequestError}; use crate::icon::Icon; use crate::monitor::{Fullscreen, MonitorHandle as CoremMonitorHandle}; use crate::window::{ - Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, - Window as RootWindow, WindowAttributes, WindowButtons, WindowId, WindowLevel, + CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as RootWindow, + WindowAttributes, WindowButtons, WindowId, WindowLevel, }; pub struct Window { @@ -462,42 +462,3 @@ impl Drop for Inner { } } } -#[derive(Clone, Debug)] -pub struct PlatformSpecificWindowAttributes { - pub(crate) canvas: Option>>, - pub(crate) prevent_default: bool, - pub(crate) focusable: bool, - pub(crate) append: bool, -} - -impl PartialEq for PlatformSpecificWindowAttributes { - fn eq(&self, other: &Self) -> bool { - (match (&self.canvas, &other.canvas) { - (Some(this), Some(other)) => Arc::ptr_eq(this, other), - (None, None) => true, - _ => false, - }) && self.prevent_default.eq(&other.prevent_default) - && self.focusable.eq(&other.focusable) - && self.append.eq(&other.append) - } -} - -impl PlatformSpecificWindowAttributes { - pub(crate) fn set_canvas(&mut self, canvas: Option) { - let Some(canvas) = canvas else { - self.canvas = None; - return; - }; - - let main_thread = MainThreadMarker::new() - .expect("received a `HtmlCanvasElement` outside the window context"); - - self.canvas = Some(Arc::new(MainThreadSafe::new(main_thread, canvas))); - } -} - -impl Default for PlatformSpecificWindowAttributes { - fn default() -> Self { - Self { canvas: None, prevent_default: true, focusable: true, append: false } - } -} diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 0762599d..b466a3a9 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -63,6 +63,7 @@ pub(super) use self::runner::{Event, EventLoopRunner}; use super::window::set_skip_taskbar; use super::SelectedCursor; use crate::application::ApplicationHandler; +use crate::cursor::{CustomCursor, CustomCursorSource}; use crate::dpi::{PhysicalPosition, PhysicalSize}; use crate::error::{EventLoopError, NotSupportedError, RequestError}; use crate::event::{ @@ -91,10 +92,7 @@ use crate::platform_impl::platform::window_state::{ }; use crate::platform_impl::platform::{raw_input, util, wrap_device_id}; use crate::platform_impl::Window; -use crate::window::{ - CustomCursor as CoreCustomCursor, CustomCursorSource, Theme, Window as CoreWindow, - WindowAttributes, WindowId, -}; +use crate::window::{Theme, Window as CoreWindow, WindowAttributes, WindowId}; pub(crate) struct WindowData { pub window_state: Arc>, @@ -420,7 +418,7 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_custom_cursor( &self, source: CustomCursorSource, - ) -> Result { + ) -> Result { let cursor = match source { CustomCursorSource::Image(cursor) => cursor, CustomCursorSource::Animation { .. } | CustomCursorSource::Url { .. } => { @@ -428,7 +426,7 @@ impl RootActiveEventLoop for ActiveEventLoop { }, }; - Ok(CoreCustomCursor(Arc::new(WinCursor::new(&cursor)?))) + Ok(CustomCursor(Arc::new(WinCursor::new(&cursor)?))) } fn available_monitors(&self) -> Box> { diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index ab007776..152b1fec 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -1,5 +1,5 @@ use windows_sys::Win32::Foundation::HWND; -use windows_sys::Win32::UI::WindowsAndMessaging::{HMENU, WINDOW_LONG_PTR_INDEX}; +use windows_sys::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX; pub(crate) use self::event_loop::{EventLoop, PlatformSpecificEventLoopAttributes}; pub(crate) use self::icon::{RaiiIcon, SelectedCursor}; @@ -7,50 +7,6 @@ pub(crate) use self::keyboard::{physicalkey_to_scancode, scancode_to_physicalkey pub(crate) use self::monitor::MonitorHandle; pub(crate) use self::window::Window; use crate::event::DeviceId; -use crate::icon::Icon; -use crate::platform::windows::{BackdropType, Color, CornerPreference}; - -#[derive(Clone, Debug)] -pub struct PlatformSpecificWindowAttributes { - pub owner: Option, - pub menu: Option, - pub taskbar_icon: Option, - pub no_redirection_bitmap: bool, - pub drag_and_drop: bool, - pub skip_taskbar: bool, - pub class_name: String, - pub decoration_shadow: bool, - pub backdrop_type: BackdropType, - pub clip_children: bool, - pub border_color: Option, - pub title_background_color: Option, - pub title_text_color: Option, - pub corner_preference: Option, -} - -impl Default for PlatformSpecificWindowAttributes { - fn default() -> Self { - Self { - owner: None, - menu: None, - taskbar_icon: None, - no_redirection_bitmap: false, - drag_and_drop: true, - skip_taskbar: false, - class_name: "Window Class".to_string(), - decoration_shadow: false, - backdrop_type: BackdropType::default(), - clip_children: true, - border_color: None, - title_background_color: None, - title_text_color: None, - corner_preference: None, - } - } -} - -unsafe impl Send for PlatformSpecificWindowAttributes {} -unsafe impl Sync for PlatformSpecificWindowAttributes {} fn wrap_device_id(id: u32) -> DeviceId { DeviceId::from_raw(id as i64) diff --git a/src/platform_impl/windows/util.rs b/src/platform_impl/windows/util.rs index 2bef7915..162c40a6 100644 --- a/src/platform_impl/windows/util.rs +++ b/src/platform_impl/windows/util.rs @@ -24,7 +24,7 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{ WINDOWPLACEMENT, }; -use crate::window::CursorIcon; +use crate::cursor::CursorIcon; pub fn encode_wide(string: impl AsRef) -> Vec { string.as_ref().encode_wide().chain(once(0)).collect() diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index d715a715..0c9f1a2d 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -55,7 +55,9 @@ use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size} use crate::error::RequestError; use crate::icon::{Icon, RgbaIcon}; use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle, MonitorHandleProvider}; -use crate::platform::windows::{BackdropType, Color, CornerPreference, WinIcon}; +use crate::platform::windows::{ + BackdropType, Color, CornerPreference, WinIcon, WindowAttributesWindows, +}; use crate::platform_impl::platform::dark_mode::try_theme; use crate::platform_impl::platform::definitions::{ CLSID_TaskbarList, IID_ITaskbarList, IID_ITaskbarList2, ITaskbarList, ITaskbarList2, @@ -1137,6 +1139,7 @@ pub(super) struct InitData<'a> { // inputs pub runner: &'a Rc, pub attributes: WindowAttributes, + pub win_attributes: Box, pub window_flags: WindowFlags, // outputs pub window: Option, @@ -1186,7 +1189,7 @@ impl InitData<'_> { } unsafe fn create_window_data(&self, win: &Window) -> event_loop::WindowData { - let file_drop_handler = if self.attributes.platform_specific.drag_and_drop { + let file_drop_handler = if self.win_attributes.drag_and_drop { let ole_init_result = unsafe { OleInitialize(ptr::null_mut()) }; // It is ok if the initialize result is `S_FALSE` because it might happen that // multiple windows are created on the same thread. @@ -1250,7 +1253,7 @@ impl InitData<'_> { let win = self.window.as_mut().expect("failed window creation"); // making the window transparent - if self.attributes.transparent && !self.attributes.platform_specific.no_redirection_bitmap { + if self.attributes.transparent && !self.win_attributes.no_redirection_bitmap { // Empty region for the blur effect, so the window is fully transparent let region = unsafe { CreateRectRgn(0, 0, -1, -1) }; @@ -1267,9 +1270,9 @@ impl InitData<'_> { unsafe { DeleteObject(region) }; } - win.set_skip_taskbar(self.attributes.platform_specific.skip_taskbar); + win.set_skip_taskbar(self.win_attributes.skip_taskbar); win.set_window_icon(self.attributes.window_icon.clone()); - win.set_taskbar_icon(self.attributes.platform_specific.taskbar_icon.clone()); + win.set_taskbar_icon(self.win_attributes.taskbar_icon.clone()); let attributes = self.attributes.clone(); @@ -1306,43 +1309,45 @@ impl InitData<'_> { win.set_outer_position(position); } - win.set_system_backdrop(self.attributes.platform_specific.backdrop_type); + win.set_system_backdrop(self.win_attributes.backdrop_type); - if let Some(color) = self.attributes.platform_specific.border_color { + if let Some(color) = self.win_attributes.border_color { win.set_border_color(color); } - if let Some(color) = self.attributes.platform_specific.title_background_color { + if let Some(color) = self.win_attributes.title_background_color { win.set_title_background_color(color); } - if let Some(color) = self.attributes.platform_specific.title_text_color { + if let Some(color) = self.win_attributes.title_text_color { win.set_title_text_color(color); } - if let Some(corner) = self.attributes.platform_specific.corner_preference { + if let Some(corner) = self.win_attributes.corner_preference { win.set_corner_preference(corner); } } } unsafe fn init( - attributes: WindowAttributes, + mut attributes: WindowAttributes, runner: &Rc, ) -> Result { let title = util::encode_wide(&attributes.title); - let class_name = util::encode_wide(&attributes.platform_specific.class_name); + let win_attributes = attributes + .platform + .take() + .and_then(|attrs| attrs.cast::().ok()) + .unwrap_or_default(); + + let class_name = util::encode_wide(&win_attributes.class_name); unsafe { register_window_class(&class_name) }; let mut window_flags = WindowFlags::empty(); window_flags.set(WindowFlags::MARKER_DECORATIONS, attributes.decorations); - window_flags.set( - WindowFlags::MARKER_UNDECORATED_SHADOW, - attributes.platform_specific.decoration_shadow, - ); + window_flags.set(WindowFlags::MARKER_UNDECORATED_SHADOW, win_attributes.decoration_shadow); window_flags .set(WindowFlags::ALWAYS_ON_TOP, attributes.window_level == WindowLevel::AlwaysOnTop); window_flags .set(WindowFlags::ALWAYS_ON_BOTTOM, attributes.window_level == WindowLevel::AlwaysOnBottom); - window_flags - .set(WindowFlags::NO_BACK_BUFFER, attributes.platform_specific.no_redirection_bitmap); + window_flags.set(WindowFlags::NO_BACK_BUFFER, win_attributes.no_redirection_bitmap); window_flags.set(WindowFlags::MARKER_ACTIVATE, attributes.active); window_flags.set(WindowFlags::TRANSPARENT, attributes.transparent); // WindowFlags::VISIBLE and MAXIMIZED are set down below after the window has been configured. @@ -1350,9 +1355,9 @@ unsafe fn init( // Will be changed later using `window.set_enabled_buttons` but we need to set a default here // so the diffing later can work. window_flags.set(WindowFlags::CLOSABLE, true); - window_flags.set(WindowFlags::CLIP_CHILDREN, attributes.platform_specific.clip_children); + window_flags.set(WindowFlags::CLIP_CHILDREN, win_attributes.clip_children); - let mut fallback_parent = || match attributes.platform_specific.owner { + let mut fallback_parent = || match win_attributes.owner { Some(parent) => { window_flags.set(WindowFlags::POPUP, true); Some(parent) @@ -1363,10 +1368,10 @@ unsafe fn init( }, }; - let parent = match attributes.parent_window.as_ref().map(|handle| handle.0) { + let parent = match attributes.parent_window() { Some(rwh_06::RawWindowHandle::Win32(handle)) => { window_flags.set(WindowFlags::CHILD, true); - if attributes.platform_specific.menu.is_some() { + if win_attributes.menu.is_some() { warn!("Setting a menu on a child window is unsupported"); } Some(handle.hwnd.get() as HWND) @@ -1375,10 +1380,10 @@ unsafe fn init( None => fallback_parent(), }; - let menu = attributes.platform_specific.menu; + let menu = win_attributes.menu; let fullscreen = attributes.fullscreen.clone(); let maximized = attributes.maximized; - let mut initdata = InitData { runner, attributes, window_flags, window: None }; + let mut initdata = InitData { runner, attributes, win_attributes, window_flags, window: None }; let (style, ex_style) = window_flags.to_window_styles(); let handle = unsafe { diff --git a/tests/send_objects.rs b/tests/send_objects.rs index 9bc4db8e..48bfa3b9 100644 --- a/tests/send_objects.rs +++ b/tests/send_objects.rs @@ -25,6 +25,6 @@ fn ids_send() { #[test] fn custom_cursor_send() { - needs_send::(); - needs_send::(); + needs_send::(); + needs_send::(); } diff --git a/tests/serde_objects.rs b/tests/serde_objects.rs index c427373f..18e796cd 100644 --- a/tests/serde_objects.rs +++ b/tests/serde_objects.rs @@ -1,10 +1,10 @@ #![cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use winit::cursor::CursorIcon; use winit::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}; use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase}; use winit::keyboard::{Key, KeyCode, KeyLocation, ModifiersState, NamedKey, PhysicalKey}; -use winit::window::CursorIcon; #[allow(dead_code)] fn needs_serde>() {} diff --git a/tests/sync_object.rs b/tests/sync_object.rs index dd65e238..1c156c01 100644 --- a/tests/sync_object.rs +++ b/tests/sync_object.rs @@ -18,6 +18,6 @@ fn window_builder_sync() { #[test] fn custom_cursor_sync() { - needs_sync::(); - needs_sync::(); + needs_sync::(); + needs_sync::(); } diff --git a/winit-core/src/cursor.rs b/winit-core/src/cursor.rs index 54728d95..47028ec8 100644 --- a/winit-core/src/cursor.rs +++ b/winit-core/src/cursor.rs @@ -5,7 +5,8 @@ use std::ops::Deref; use std::sync::Arc; use std::time::Duration; -use cursor_icon::CursorIcon; +#[doc(inline)] +pub use cursor_icon::CursorIcon; use crate::as_any::{impl_dyn_casting, AsAny}; diff --git a/winit-core/src/lib.rs b/winit-core/src/lib.rs index df29046f..82e47d98 100644 --- a/winit-core/src/lib.rs +++ b/winit-core/src/lib.rs @@ -7,3 +7,4 @@ pub mod event_loop; pub mod icon; pub mod keyboard; pub mod monitor; +pub mod window; diff --git a/src/window.rs b/winit-core/src/window.rs similarity index 95% rename from src/window.rs rename to winit-core/src/window.rs index dde0167f..c148ee4b 100644 --- a/src/window.rs +++ b/winit-core/src/window.rs @@ -1,18 +1,16 @@ -//! The [`Window`] struct and associated types. +//! The [`Window`] trait and associated types. use std::fmt; -#[doc(inline)] -pub use cursor_icon::{CursorIcon, ParseError as CursorIconParseError}; +use cursor_icon::CursorIcon; +use dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -pub use crate::cursor::{BadImage, Cursor, CustomCursor, CustomCursorSource, MAX_CURSOR_SIZE}; -use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size}; +use crate::as_any::AsAny; +use crate::cursor::Cursor; use crate::error::RequestError; -pub use crate::icon::{BadIcon, Icon}; +use crate::icon::Icon; use crate::monitor::{Fullscreen, MonitorHandle}; -use crate::platform_impl::PlatformSpecificWindowAttributes; -use crate::utils::{impl_dyn_casting, AsAny}; /// Identifier of a window. Unique for each window. /// @@ -46,7 +44,8 @@ impl fmt::Debug for WindowId { } /// Attributes used when creating a window. -#[derive(Debug, Clone)] +#[derive(Debug)] +#[non_exhaustive] pub struct WindowAttributes { pub surface_size: Option, pub min_surface_size: Option, @@ -69,53 +68,9 @@ pub struct WindowAttributes { pub cursor: Cursor, pub(crate) parent_window: Option, pub fullscreen: Option, - // Platform-specific configuration. - #[allow(dead_code)] - pub(crate) platform_specific: PlatformSpecificWindowAttributes, + pub platform: Option>, } -impl Default for WindowAttributes { - #[inline] - fn default() -> WindowAttributes { - WindowAttributes { - surface_size: None, - min_surface_size: None, - max_surface_size: None, - surface_resize_increments: None, - position: None, - resizable: true, - enabled_buttons: WindowButtons::all(), - title: "winit window".to_owned(), - maximized: false, - fullscreen: None, - visible: true, - transparent: false, - blur: false, - decorations: true, - window_level: Default::default(), - window_icon: None, - preferred_theme: None, - content_protected: false, - cursor: Cursor::default(), - parent_window: None, - active: true, - platform_specific: Default::default(), - } - } -} - -/// Wrapper for [`rwh_06::RawWindowHandle`] for [`WindowAttributes::parent_window`]. -/// -/// # Safety -/// -/// The user has to account for that when using [`WindowAttributes::with_parent_window()`], -/// which is `unsafe`. -#[derive(Debug, Clone, PartialEq)] -pub(crate) struct SendSyncRawWindowHandle(pub(crate) rwh_06::RawWindowHandle); - -unsafe impl Send for SendSyncRawWindowHandle {} -unsafe impl Sync for SendSyncRawWindowHandle {} - impl WindowAttributes { /// Get the parent window stored on the attributes. pub fn parent_window(&self) -> Option<&rwh_06::RawWindowHandle> { @@ -411,8 +366,94 @@ impl WindowAttributes { self.parent_window = parent_window.map(SendSyncRawWindowHandle); self } + + /// Set the platform specific opaque attribute object. + /// + /// The interpretation will depend on the underlying backend that will be used. + #[inline] + pub fn with_platform_attributes(mut self, platform: Box) -> Self { + self.platform = Some(platform); + self + } } +impl Clone for WindowAttributes { + fn clone(&self) -> Self { + Self { + surface_size: self.surface_size, + min_surface_size: self.min_surface_size, + max_surface_size: self.max_surface_size, + surface_resize_increments: self.surface_resize_increments, + position: self.position, + resizable: self.resizable, + enabled_buttons: self.enabled_buttons, + title: self.title.clone(), + maximized: self.maximized, + visible: self.visible, + transparent: self.transparent, + blur: self.blur, + decorations: self.decorations, + window_icon: self.window_icon.clone(), + preferred_theme: self.preferred_theme, + content_protected: self.content_protected, + window_level: self.window_level, + active: self.active, + cursor: self.cursor.clone(), + parent_window: self.parent_window.clone(), + fullscreen: self.fullscreen.clone(), + platform: self.platform.as_ref().map(|platform| platform.box_clone()), + } + } +} + +impl Default for WindowAttributes { + #[inline] + fn default() -> WindowAttributes { + WindowAttributes { + enabled_buttons: WindowButtons::all(), + title: String::from("winit window"), + decorations: true, + resizable: true, + visible: true, + active: true, + surface_resize_increments: Default::default(), + content_protected: Default::default(), + min_surface_size: Default::default(), + max_surface_size: Default::default(), + preferred_theme: Default::default(), + parent_window: Default::default(), + surface_size: Default::default(), + window_level: Default::default(), + window_icon: Default::default(), + transparent: Default::default(), + fullscreen: Default::default(), + maximized: Default::default(), + position: Default::default(), + platform: Default::default(), + cursor: Cursor::default(), + blur: Default::default(), + } + } +} + +/// Wrapper for [`rwh_06::RawWindowHandle`] for [`WindowAttributes::parent_window`]. +/// +/// # Safety +/// +/// The user has to account for that when using [`WindowAttributes::with_parent_window()`], +/// which is `unsafe`. +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct SendSyncRawWindowHandle(pub(crate) rwh_06::RawWindowHandle); + +unsafe impl Send for SendSyncRawWindowHandle {} +unsafe impl Sync for SendSyncRawWindowHandle {} + +pub trait PlatformWindowAttributes: AsAny + std::fmt::Debug + Send + Sync { + fn box_clone(&self) -> Box; +} + +impl_dyn_casting!(PlatformWindowAttributes); + /// Represents a window. /// /// The window is closed when dropped. @@ -1333,14 +1374,6 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug { fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle; } -impl dyn Window + '_ { - /// Create a new [`WindowAttributes`] which allows modifying the window's attributes before - /// creation. - pub fn default_attributes() -> WindowAttributes { - WindowAttributes::default() - } -} - impl_dyn_casting!(Window); impl PartialEq for dyn Window + '_ { @@ -1560,4 +1593,9 @@ impl ActivationToken { pub fn into_raw(self) -> String { self.token } + + /// Get a reference to a raw token. + pub fn as_raw(&self) -> &str { + &self.token + } }