diff --git a/examples/child_window.rs b/examples/child_window.rs index 7b5914133d..9feb814066 100644 --- a/examples/child_window.rs +++ b/examples/child_window.rs @@ -8,7 +8,7 @@ fn main() -> Result<(), impl std::error::Error> { use winit::event::{ElementState, KeyEvent, WindowEvent}; use winit::event_loop::{ActiveEventLoop, EventLoop}; use winit::raw_window_handle::HasRawWindowHandle; - use winit::window::{Window, WindowId}; + use winit::window::{Window, WindowAttributes, WindowId}; #[path = "util/fill.rs"] mod fill; @@ -16,12 +16,12 @@ fn main() -> Result<(), impl std::error::Error> { #[derive(Default)] struct Application { parent_window_id: Option, - windows: HashMap, + windows: HashMap>, } impl ApplicationHandler for Application { fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { - let attributes = Window::default_attributes() + let attributes = WindowAttributes::default() .with_title("parent window") .with_position(Position::Logical(LogicalPosition::new(0.0, 0.0))) .with_inner_size(LogicalSize::new(640.0f32, 480.0f32)); @@ -57,14 +57,14 @@ fn main() -> Result<(), impl std::error::Error> { .. } => { let parent_window = self.windows.get(&self.parent_window_id.unwrap()).unwrap(); - let child_window = spawn_child_window(parent_window, event_loop); + let child_window = spawn_child_window(parent_window.as_ref(), event_loop); let child_id = child_window.id(); println!("Child window created with id: {child_id:?}"); self.windows.insert(child_id, child_window); }, WindowEvent::RedrawRequested => { if let Some(window) = self.windows.get(&window_id) { - fill::fill_window(window); + fill::fill_window(window.as_ref()); } }, _ => (), @@ -72,9 +72,12 @@ fn main() -> Result<(), impl std::error::Error> { } } - fn spawn_child_window(parent: &Window, event_loop: &dyn ActiveEventLoop) -> Window { + fn spawn_child_window( + parent: &dyn Window, + event_loop: &dyn ActiveEventLoop, + ) -> Box { let parent = parent.raw_window_handle().unwrap(); - let mut window_attributes = Window::default_attributes() + let mut window_attributes = WindowAttributes::default() .with_title("child window") .with_inner_size(LogicalSize::new(200.0f32, 200.0f32)) .with_position(Position::Logical(LogicalPosition::new(0.0, 0.0))) diff --git a/examples/control_flow.rs b/examples/control_flow.rs index 7b35d1c2dc..47a518c181 100644 --- a/examples/control_flow.rs +++ b/examples/control_flow.rs @@ -11,7 +11,7 @@ use winit::application::ApplicationHandler; use winit::event::{ElementState, KeyEvent, StartCause, WindowEvent}; use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop}; use winit::keyboard::{Key, NamedKey}; -use winit::window::{Window, WindowId}; +use winit::window::{Window, WindowAttributes, WindowId}; #[path = "util/fill.rs"] mod fill; @@ -52,7 +52,7 @@ struct ControlFlowDemo { request_redraw: bool, wait_cancelled: bool, close_requested: bool, - window: Option, + window: Option>, } impl ApplicationHandler for ControlFlowDemo { @@ -66,7 +66,7 @@ impl ApplicationHandler for ControlFlowDemo { } fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { - let window_attributes = Window::default_attributes().with_title( + let window_attributes = WindowAttributes::default().with_title( "Press 1, 2, 3 to change control flow mode. Press R to toggle redraw requests.", ); self.window = Some(event_loop.create_window(window_attributes).unwrap()); @@ -114,7 +114,7 @@ impl ApplicationHandler for ControlFlowDemo { WindowEvent::RedrawRequested => { let window = self.window.as_ref().unwrap(); window.pre_present_notify(); - fill::fill_window(window); + fill::fill_window(window.as_ref()); }, _ => (), } diff --git a/examples/pump_events.rs b/examples/pump_events.rs index 1c307b63dd..3ec8abe38b 100644 --- a/examples/pump_events.rs +++ b/examples/pump_events.rs @@ -11,19 +11,19 @@ fn main() -> std::process::ExitCode { use winit::event::WindowEvent; use winit::event_loop::{ActiveEventLoop, EventLoop}; use winit::platform::pump_events::{EventLoopExtPumpEvents, PumpStatus}; - use winit::window::{Window, WindowId}; + use winit::window::{Window, WindowAttributes, WindowId}; #[path = "util/fill.rs"] mod fill; #[derive(Default)] struct PumpDemo { - window: Option, + window: Option>, } impl ApplicationHandler for PumpDemo { fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { - let window_attributes = Window::default_attributes().with_title("A fantastic window!"); + let window_attributes = WindowAttributes::default().with_title("A fantastic window!"); self.window = Some(event_loop.create_window(window_attributes).unwrap()); } @@ -43,7 +43,7 @@ fn main() -> std::process::ExitCode { match event { WindowEvent::CloseRequested => event_loop.exit(), WindowEvent::RedrawRequested => { - fill::fill_window(window); + fill::fill_window(window.as_ref()); window.request_redraw(); }, _ => (), diff --git a/examples/run_on_demand.rs b/examples/run_on_demand.rs index 10f220a386..ee856e82b3 100644 --- a/examples/run_on_demand.rs +++ b/examples/run_on_demand.rs @@ -9,7 +9,7 @@ fn main() -> Result<(), Box> { use winit::event::WindowEvent; use winit::event_loop::{ActiveEventLoop, EventLoop}; use winit::platform::run_on_demand::EventLoopExtRunOnDemand; - use winit::window::{Window, WindowId}; + use winit::window::{Window, WindowAttributes, WindowId}; #[path = "util/fill.rs"] mod fill; @@ -18,7 +18,7 @@ fn main() -> Result<(), Box> { struct App { idx: usize, window_id: Option, - window: Option, + window: Option>, } impl ApplicationHandler for App { @@ -29,7 +29,7 @@ fn main() -> Result<(), Box> { } fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { - let window_attributes = Window::default_attributes() + let window_attributes = WindowAttributes::default() .with_title("Fantastic window number one!") .with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0)); let window = event_loop.create_window(window_attributes).unwrap(); @@ -65,11 +65,11 @@ fn main() -> Result<(), Box> { CloseRequested", self.idx ); - fill::cleanup_window(window); + fill::cleanup_window(window.as_ref()); self.window = None; }, WindowEvent::RedrawRequested => { - fill::fill_window(window); + fill::fill_window(window.as_ref()); }, _ => (), } diff --git a/examples/util/fill.rs b/examples/util/fill.rs index de04a8e77f..d953c040e0 100644 --- a/examples/util/fill.rs +++ b/examples/util/fill.rs @@ -34,18 +34,20 @@ mod platform { /// The graphics context used to draw to a window. struct GraphicsContext { /// The global softbuffer context. - context: RefCell>, + context: RefCell>, /// The hash map of window IDs to surfaces. - surfaces: HashMap>, + surfaces: HashMap>, } impl GraphicsContext { - fn new(w: &Window) -> Self { + fn new(w: &dyn Window) -> Self { Self { context: RefCell::new( - Context::new(unsafe { mem::transmute::<&'_ Window, &'static Window>(w) }) - .expect("Failed to create a softbuffer context"), + Context::new(unsafe { + mem::transmute::<&'_ dyn Window, &'static dyn Window>(w) + }) + .expect("Failed to create a softbuffer context"), ), surfaces: HashMap::new(), } @@ -53,22 +55,22 @@ mod platform { fn create_surface( &mut self, - window: &Window, - ) -> &mut Surface<&'static Window, &'static Window> { + window: &dyn Window, + ) -> &mut Surface<&'static dyn Window, &'static dyn Window> { self.surfaces.entry(window.id()).or_insert_with(|| { Surface::new(&self.context.borrow(), unsafe { - mem::transmute::<&'_ Window, &'static Window>(window) + mem::transmute::<&'_ dyn Window, &'static dyn Window>(window) }) .expect("Failed to create a softbuffer surface") }) } - fn destroy_surface(&mut self, window: &Window) { + fn destroy_surface(&mut self, window: &dyn Window) { self.surfaces.remove(&window.id()); } } - pub fn fill_window(window: &Window) { + pub fn fill_window(window: &dyn Window) { GC.with(|gc| { let size = window.inner_size(); let (Some(width), Some(height)) = @@ -94,7 +96,7 @@ mod platform { } #[allow(dead_code)] - pub fn cleanup_window(window: &Window) { + pub fn cleanup_window(window: &dyn Window) { GC.with(|gc| { let mut gc = gc.borrow_mut(); if let Some(context) = gc.as_mut() { @@ -106,12 +108,12 @@ mod platform { #[cfg(not(all(feature = "rwh_06", not(any(target_os = "android", target_os = "ios")))))] mod platform { - pub fn fill_window(_window: &winit::window::Window) { + pub fn fill_window(_window: &dyn winit::window::Window) { // No-op on mobile platforms. } #[allow(dead_code)] - pub fn cleanup_window(_window: &winit::window::Window) { + pub fn cleanup_window(_window: &dyn winit::window::Window) { // No-op on mobile platforms. } } diff --git a/examples/window.rs b/examples/window.rs index 61bd51bd72..c546fb5d06 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -31,7 +31,7 @@ use winit::platform::startup_notify::{ use winit::platform::web::{ActiveEventLoopExtWeb, CustomCursorExtWeb, WindowAttributesExtWeb}; use winit::window::{ Cursor, CursorGrabMode, CustomCursor, CustomCursorSource, Fullscreen, Icon, ResizeDirection, - Theme, Window, WindowId, + Theme, Window, WindowAttributes, WindowId, }; #[path = "util/tracing.rs"] @@ -135,7 +135,7 @@ impl Application { // TODO read-out activation token. #[allow(unused_mut)] - let mut window_attributes = Window::default_attributes() + let mut window_attributes = WindowAttributes::default() .with_title("Winit window") .with_transparent(true) .with_window_icon(Some(self.icon.clone())); @@ -560,9 +560,9 @@ struct WindowState { /// /// NOTE: This surface must be dropped before the `Window`. #[cfg(not(any(android_platform, ios_platform)))] - surface: Surface, Arc>, + surface: Surface, Arc>, /// The actual winit Window. - window: Arc, + window: Arc, /// The window theme we're drawing with. theme: Theme, /// Cursor position over the window. @@ -590,8 +590,8 @@ struct WindowState { } impl WindowState { - fn new(app: &Application, window: Window) -> Result> { - let window = Arc::new(window); + fn new(app: &Application, window: Box) -> Result> { + let window: Arc = Arc::from(window); // SAFETY: the surface is dropped before the `window` which provided it with handle, thus // it doesn't outlive it. @@ -601,7 +601,7 @@ impl WindowState { let theme = window.theme().unwrap_or(Theme::Dark); info!("Theme: {theme:?}"); let named_idx = 0; - window.set_cursor(CURSORS[named_idx]); + window.set_cursor(CURSORS[named_idx].into()); // Allow IME out of the box. let ime = true; @@ -636,7 +636,7 @@ impl WindowState { self.ime = !self.ime; self.window.set_ime_allowed(self.ime); if let Some(position) = self.ime.then_some(self.cursor_position).flatten() { - self.window.set_ime_cursor_area(position, PhysicalSize::new(20, 20)); + self.window.set_ime_cursor_area(position.into(), PhysicalSize::new(20, 20).into()); } } @@ -647,7 +647,7 @@ impl WindowState { pub fn cursor_moved(&mut self, position: PhysicalPosition) { self.cursor_position = Some(position); if self.ime { - self.window.set_ime_cursor_area(position, PhysicalSize::new(20, 20)); + self.window.set_ime_cursor_area(position.into(), PhysicalSize::new(20, 20).into()); } } @@ -683,7 +683,7 @@ impl WindowState { fn toggle_resize_increments(&mut self) { let new_increments = match self.window.resize_increments() { Some(_) => None, - None => Some(LogicalSize::new(25.0, 25.0)), + None => Some(LogicalSize::new(25.0, 25.0).into()), }; info!("Had increments: {}", new_increments.is_none()); self.window.set_resize_increments(new_increments); @@ -733,7 +733,7 @@ impl WindowState { mem::swap(&mut inner_size.width, &mut inner_size.height); info!("Requesting resize from {old_inner_size:?} to {inner_size:?}"); - if let Some(new_inner_size) = self.window.request_inner_size(inner_size) { + if let Some(new_inner_size) = self.window.request_inner_size(inner_size.into()) { if old_inner_size == new_inner_size { info!("Inner size change got ignored"); } else { @@ -766,7 +766,7 @@ impl WindowState { ) -> Result<(), Box> { let cursor = event_loop.create_custom_cursor(url_custom_cursor())?; - self.window.set_cursor(cursor); + self.window.set_cursor(cursor.into()); Ok(()) } @@ -788,7 +788,7 @@ impl WindowState { let cursor = CustomCursor::from_animation(Duration::from_secs(3), cursors).unwrap(); let cursor = event_loop.create_custom_cursor(cursor)?; - self.window.set_cursor(cursor); + self.window.set_cursor(cursor.into()); Ok(()) } @@ -817,7 +817,7 @@ impl WindowState { /// Show window menu. fn show_menu(&self) { if let Some(position) = self.cursor_position { - self.window.show_window_menu(position); + self.window.show_window_menu(position.into()); } } diff --git a/examples/x11_embed.rs b/examples/x11_embed.rs index c13075a645..9f52741016 100644 --- a/examples/x11_embed.rs +++ b/examples/x11_embed.rs @@ -7,19 +7,19 @@ fn main() -> Result<(), Box> { use winit::event::WindowEvent; use winit::event_loop::{ActiveEventLoop, EventLoop}; use winit::platform::x11::WindowAttributesExtX11; - use winit::window::{Window, WindowId}; + use winit::window::{Window, WindowAttributes, WindowId}; #[path = "util/fill.rs"] mod fill; pub struct XEmbedDemo { parent_window_id: u32, - window: Option, + window: Option>, } impl ApplicationHandler for XEmbedDemo { fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { - let window_attributes = Window::default_attributes() + let window_attributes = WindowAttributes::default() .with_title("An embedded window!") .with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0)) .with_embed_parent_window(self.parent_window_id); @@ -38,7 +38,7 @@ fn main() -> Result<(), Box> { WindowEvent::CloseRequested => event_loop.exit(), WindowEvent::RedrawRequested => { window.pre_present_notify(); - fill::fill_window(window); + fill::fill_window(window.as_ref()); }, _ => (), } diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 18f9e89351..e8b7b1c21e 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -67,6 +67,8 @@ changelog entry. ### Changed - Change `ActiveEventLoop` to be a trait. +- Change `Window` to be a trait. +- `ActiveEventLoop::create_window` now returns `Box`. - `ApplicationHandler` now uses `dyn ActiveEventLoop`. - On Web, let events wake up event loop immediately when using `ControlFlow::Poll`. - Bump MSRV from `1.70` to `1.73`. diff --git a/src/cursor.rs b/src/cursor.rs index 0a98016216..d9130b8268 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -50,7 +50,7 @@ impl From for Cursor { /// ```no_run /// # use winit::event_loop::ActiveEventLoop; /// # use winit::window::Window; -/// # fn scope(event_loop: &dyn ActiveEventLoop, window: &Window) { +/// # fn scope(event_loop: &dyn ActiveEventLoop, window: &dyn Window) { /// use winit::window::CustomCursor; /// /// let w = 10; @@ -67,7 +67,7 @@ impl From for Cursor { /// }; /// /// if let Ok(custom_cursor) = event_loop.create_custom_cursor(source) { -/// window.set_cursor(custom_cursor.clone()); +/// window.set_cursor(custom_cursor.clone().into()); /// } /// # } /// ``` diff --git a/src/event_loop.rs b/src/event_loop.rs index 7340f1a666..d631e0d847 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -321,7 +321,10 @@ pub trait ActiveEventLoop: AsAny { /// /// - **Web:** The window is created but not inserted into the Web page automatically. Please /// see the Web platform module for more information. - fn create_window(&self, window_attributes: WindowAttributes) -> Result; + fn create_window( + &self, + window_attributes: WindowAttributes, + ) -> Result, OsError>; /// Create custom cursor. /// diff --git a/src/lib.rs b/src/lib.rs index 6d8f084b09..f747c13928 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,16 +44,16 @@ //! use winit::application::ApplicationHandler; //! use winit::event::WindowEvent; //! use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop}; -//! use winit::window::{Window, WindowId}; +//! use winit::window::{Window, WindowId, WindowAttributes}; //! //! #[derive(Default)] //! struct App { -//! window: Option, +//! window: Option>, //! } //! //! impl ApplicationHandler for App { //! fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { -//! self.window = Some(event_loop.create_window(Window::default_attributes()).unwrap()); +//! self.window = Some(event_loop.create_window(WindowAttributes::default()).unwrap()); //! } //! //! fn window_event(&mut self, event_loop: &dyn ActiveEventLoop, id: WindowId, event: WindowEvent) { diff --git a/src/platform/android.rs b/src/platform/android.rs index 1f7383e953..67e04954ed 100644 --- a/src/platform/android.rs +++ b/src/platform/android.rs @@ -99,13 +99,15 @@ pub trait WindowExtAndroid { fn config(&self) -> ConfigurationRef; } -impl WindowExtAndroid for Window { +impl WindowExtAndroid for dyn Window + '_ { fn content_rect(&self) -> Rect { - self.window.content_rect() + let window = self.as_any().downcast_ref::().unwrap(); + window.content_rect() } fn config(&self) -> ConfigurationRef { - self.window.config() + let window = self.as_any().downcast_ref::().unwrap(); + window.config() } } diff --git a/src/platform/ios.rs b/src/platform/ios.rs index 89a9d65561..9b55b0c4b2 100644 --- a/src/platform/ios.rs +++ b/src/platform/ios.rs @@ -209,42 +209,49 @@ pub trait WindowExtIOS { fn recognize_rotation_gesture(&self, should_recognize: bool); } -impl WindowExtIOS for Window { +impl WindowExtIOS for dyn Window + '_ { #[inline] fn set_scale_factor(&self, scale_factor: f64) { - self.window.maybe_queue_on_main(move |w| w.set_scale_factor(scale_factor)) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(move |w| w.set_scale_factor(scale_factor)); } #[inline] fn set_valid_orientations(&self, valid_orientations: ValidOrientations) { - self.window.maybe_queue_on_main(move |w| w.set_valid_orientations(valid_orientations)) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(move |w| w.set_valid_orientations(valid_orientations)); } #[inline] fn set_prefers_home_indicator_hidden(&self, hidden: bool) { - self.window.maybe_queue_on_main(move |w| w.set_prefers_home_indicator_hidden(hidden)) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(move |w| w.set_prefers_home_indicator_hidden(hidden)); } #[inline] fn set_preferred_screen_edges_deferring_system_gestures(&self, edges: ScreenEdge) { - self.window.maybe_queue_on_main(move |w| { + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(move |w| { w.set_preferred_screen_edges_deferring_system_gestures(edges) - }) + }); } #[inline] fn set_prefers_status_bar_hidden(&self, hidden: bool) { - self.window.maybe_queue_on_main(move |w| w.set_prefers_status_bar_hidden(hidden)) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(move |w| w.set_prefers_status_bar_hidden(hidden)); } #[inline] fn set_preferred_status_bar_style(&self, status_bar_style: StatusBarStyle) { - self.window.maybe_queue_on_main(move |w| w.set_preferred_status_bar_style(status_bar_style)) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(move |w| w.set_preferred_status_bar_style(status_bar_style)) } #[inline] fn recognize_pinch_gesture(&self, should_recognize: bool) { - self.window.maybe_queue_on_main(move |w| w.recognize_pinch_gesture(should_recognize)); + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(move |w| w.recognize_pinch_gesture(should_recognize)); } #[inline] @@ -254,7 +261,8 @@ impl WindowExtIOS for Window { minimum_number_of_touches: u8, maximum_number_of_touches: u8, ) { - self.window.maybe_queue_on_main(move |w| { + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(move |w| { w.recognize_pan_gesture( should_recognize, minimum_number_of_touches, @@ -265,12 +273,14 @@ impl WindowExtIOS for Window { #[inline] fn recognize_doubletap_gesture(&self, should_recognize: bool) { - self.window.maybe_queue_on_main(move |w| w.recognize_doubletap_gesture(should_recognize)); + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(move |w| w.recognize_doubletap_gesture(should_recognize)); } #[inline] fn recognize_rotation_gesture(&self, should_recognize: bool) { - self.window.maybe_queue_on_main(move |w| w.recognize_rotation_gesture(should_recognize)); + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(move |w| w.recognize_rotation_gesture(should_recognize)); } } diff --git a/src/platform/macos.rs b/src/platform/macos.rs index 44bc8b8b33..6121dbf0c6 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -152,75 +152,89 @@ pub trait WindowExtMacOS { fn option_as_alt(&self) -> OptionAsAlt; } -impl WindowExtMacOS for Window { +impl WindowExtMacOS for dyn Window + '_ { #[inline] fn simple_fullscreen(&self) -> bool { - self.window.maybe_wait_on_main(|w| w.simple_fullscreen()) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(|w| w.simple_fullscreen()) } #[inline] fn set_simple_fullscreen(&self, fullscreen: bool) -> bool { - self.window.maybe_wait_on_main(move |w| w.set_simple_fullscreen(fullscreen)) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(move |w| w.set_simple_fullscreen(fullscreen)) } #[inline] fn has_shadow(&self) -> bool { - self.window.maybe_wait_on_main(|w| w.has_shadow()) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(|w| w.has_shadow()) } #[inline] fn set_has_shadow(&self, has_shadow: bool) { - self.window.maybe_queue_on_main(move |w| w.set_has_shadow(has_shadow)) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(move |w| w.set_has_shadow(has_shadow)); } #[inline] fn set_tabbing_identifier(&self, identifier: &str) { - self.window.maybe_wait_on_main(|w| w.set_tabbing_identifier(identifier)) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(|w| w.set_tabbing_identifier(identifier)) } #[inline] fn tabbing_identifier(&self) -> String { - self.window.maybe_wait_on_main(|w| w.tabbing_identifier()) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(|w| w.tabbing_identifier()) } #[inline] fn select_next_tab(&self) { - self.window.maybe_queue_on_main(|w| w.select_next_tab()) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(|w| w.select_next_tab()); } #[inline] fn select_previous_tab(&self) { - self.window.maybe_queue_on_main(|w| w.select_previous_tab()) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(|w| w.select_previous_tab()); } #[inline] fn select_tab_at_index(&self, index: usize) { - self.window.maybe_queue_on_main(move |w| w.select_tab_at_index(index)) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(move |w| w.select_tab_at_index(index)); } #[inline] fn num_tabs(&self) -> usize { - self.window.maybe_wait_on_main(|w| w.num_tabs()) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(|w| w.num_tabs()) } #[inline] fn is_document_edited(&self) -> bool { - self.window.maybe_wait_on_main(|w| w.is_document_edited()) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(|w| w.is_document_edited()) } #[inline] fn set_document_edited(&self, edited: bool) { - self.window.maybe_queue_on_main(move |w| w.set_document_edited(edited)) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(move |w| w.set_document_edited(edited)); } #[inline] fn set_option_as_alt(&self, option_as_alt: OptionAsAlt) { - self.window.maybe_queue_on_main(move |w| w.set_option_as_alt(option_as_alt)) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(move |w| w.set_option_as_alt(option_as_alt)); } #[inline] fn option_as_alt(&self) -> OptionAsAlt { - self.window.maybe_wait_on_main(|w| w.option_as_alt()) + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(|w| w.option_as_alt()) } } diff --git a/src/platform/startup_notify.rs b/src/platform/startup_notify.rs index 7698eba5cd..c09aa6629b 100644 --- a/src/platform/startup_notify.rs +++ b/src/platform/startup_notify.rs @@ -72,9 +72,22 @@ impl EventLoopExtStartupNotify for dyn ActiveEventLoop + '_ { } } -impl WindowExtStartupNotify for Window { +impl WindowExtStartupNotify for dyn Window + '_ { fn request_activation_token(&self) -> Result { - self.window.request_activation_token() + #[cfg(wayland_platform)] + if let Some(window) = self.as_any().downcast_ref::() + { + return window.request_activation_token(); + } + + #[cfg(x11_platform)] + if let Some(window) = + self.as_any().downcast_ref::() + { + return window.request_activation_token(); + } + + Err(NotSupportedError::new()) } } diff --git a/src/platform/wayland.rs b/src/platform/wayland.rs index 95a9980c5d..84af00388b 100644 --- a/src/platform/wayland.rs +++ b/src/platform/wayland.rs @@ -16,7 +16,7 @@ use crate::event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder}; use crate::monitor::MonitorHandle; pub use crate::window::Theme; -use crate::window::{Window, WindowAttributes}; +use crate::window::{Window as CoreWindow, WindowAttributes}; /// Additional methods on [`ActiveEventLoop`] that are specific to Wayland. pub trait ActiveEventLoopExtWayland { @@ -71,9 +71,11 @@ impl EventLoopBuilderExtWayland for EventLoopBuilder { } /// Additional methods on [`Window`] that are specific to Wayland. +/// +/// [`Window`]: crate::window::Window pub trait WindowExtWayland {} -impl WindowExtWayland for Window {} +impl WindowExtWayland for dyn CoreWindow + '_ {} /// Additional methods on [`WindowAttributes`] that are specific to Wayland. pub trait WindowAttributesExtWayland { diff --git a/src/platform/web.rs b/src/platform/web.rs index fc70d8b4aa..a2c5c2651e 100644 --- a/src/platform/web.rs +++ b/src/platform/web.rs @@ -82,7 +82,7 @@ pub trait WindowExtWeb { /// Returns [`true`] if calling `event.preventDefault()` is enabled. /// - /// See [`Window::set_prevent_default()`] for more details. + /// See [`WindowExtWeb::set_prevent_default()`] for more details. fn prevent_default(&self) -> bool; /// Sets whether `event.preventDefault()` should be called on events on the @@ -104,22 +104,34 @@ pub trait WindowExtWeb { fn is_cursor_lock_raw(&self) -> bool; } -impl WindowExtWeb for Window { +impl WindowExtWeb for dyn Window + '_ { #[inline] fn canvas(&self) -> Option> { - self.window.canvas() + self.as_any() + .downcast_ref::() + .expect("non Web window on Web") + .canvas() } fn prevent_default(&self) -> bool { - self.window.prevent_default() + self.as_any() + .downcast_ref::() + .expect("non Web window on Web") + .prevent_default() } fn set_prevent_default(&self, prevent_default: bool) { - self.window.set_prevent_default(prevent_default) + self.as_any() + .downcast_ref::() + .expect("non Web window on Web") + .set_prevent_default(prevent_default) } fn is_cursor_lock_raw(&self) -> bool { - self.window.is_cursor_lock_raw() + self.as_any() + .downcast_ref::() + .expect("non Web window on Web") + .is_cursor_lock_raw() } } @@ -136,7 +148,7 @@ pub trait WindowAttributesExtWeb { /// Sets whether `event.preventDefault()` should be called on events on the /// canvas that have side effects. /// - /// See [`Window::set_prevent_default()`] for more details. + /// See [`WindowExtWeb::set_prevent_default()`] for more details. /// /// Enabled by default. fn with_prevent_default(self, prevent_default: bool) -> Self; diff --git a/src/platform/windows.rs b/src/platform/windows.rs index b6315b9b2e..39939267e1 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -4,6 +4,7 @@ //! tested regularly. use std::borrow::Borrow; use std::ffi::c_void; +use std::ops::Deref; use std::path::Path; #[cfg(feature = "serde")] @@ -115,50 +116,25 @@ pub enum CornerPreference { /// /// See [`WindowBorrowExtWindows::any_thread`] for more information. #[derive(Clone, Debug)] -pub struct AnyThread(W); +pub struct AnyThread(W); -impl> AnyThread { +impl AnyThread { /// Get a reference to the inner window. #[inline] - pub fn get_ref(&self) -> &Window { - self.0.borrow() - } - - /// Get a reference to the inner object. - #[inline] - pub fn inner(&self) -> &W { + pub fn get_ref(&self) -> &dyn Window { &self.0 } - - /// Unwrap and get the inner window. - #[inline] - pub fn into_inner(self) -> W { - self.0 - } -} - -impl> AsRef for AnyThread { - fn as_ref(&self) -> &Window { - self.get_ref() - } -} - -impl> Borrow for AnyThread { - fn borrow(&self) -> &Window { - self.get_ref() - } } -impl> std::ops::Deref for AnyThread { - type Target = Window; - +impl Deref for AnyThread { + type Target = W; fn deref(&self) -> &Self::Target { - self.get_ref() + &self.0 } } #[cfg(feature = "rwh_06")] -impl> rwh_06::HasWindowHandle for AnyThread { +impl rwh_06::HasWindowHandle for AnyThread { fn window_handle(&self) -> Result, rwh_06::HandleError> { // SAFETY: The top level user has asserted this is only used safely. unsafe { self.get_ref().window_handle_any_thread() } @@ -341,7 +317,7 @@ pub trait WindowExtWindows { /// /// ```no_run /// # use winit::window::Window; - /// # fn scope(window: Window) { + /// # fn scope(window: Box) { /// use std::thread; /// /// use winit::platform::windows::WindowExtWindows; @@ -365,35 +341,41 @@ pub trait WindowExtWindows { ) -> Result, rwh_06::HandleError>; } -impl WindowExtWindows for Window { +impl WindowExtWindows for dyn Window + '_ { #[inline] fn set_enable(&self, enabled: bool) { - self.window.set_enable(enabled) + let window = self.as_any().downcast_ref::().unwrap(); + window.set_enable(enabled) } #[inline] fn set_taskbar_icon(&self, taskbar_icon: Option) { - self.window.set_taskbar_icon(taskbar_icon) + let window = self.as_any().downcast_ref::().unwrap(); + window.set_taskbar_icon(taskbar_icon) } #[inline] fn set_skip_taskbar(&self, skip: bool) { - self.window.set_skip_taskbar(skip) + let window = self.as_any().downcast_ref::().unwrap(); + window.set_skip_taskbar(skip) } #[inline] fn set_undecorated_shadow(&self, shadow: bool) { - self.window.set_undecorated_shadow(shadow) + let window = self.as_any().downcast_ref::().unwrap(); + window.set_undecorated_shadow(shadow) } #[inline] fn set_system_backdrop(&self, backdrop_type: BackdropType) { - self.window.set_system_backdrop(backdrop_type) + let window = self.as_any().downcast_ref::().unwrap(); + window.set_system_backdrop(backdrop_type) } #[inline] fn set_border_color(&self, color: Option) { - self.window.set_border_color(color.unwrap_or(Color::NONE)) + let window = self.as_any().downcast_ref::().unwrap(); + window.set_border_color(color.unwrap_or(Color::NONE)) } #[inline] @@ -401,25 +383,29 @@ impl WindowExtWindows for Window { // The windows docs don't mention NONE as a valid options but it works in practice and is // useful to circumvent the Windows option "Show accent color on title bars and // window borders" - self.window.set_title_background_color(color.unwrap_or(Color::NONE)) + let window = self.as_any().downcast_ref::().unwrap(); + window.set_title_background_color(color.unwrap_or(Color::NONE)) } #[inline] fn set_title_text_color(&self, color: Color) { - self.window.set_title_text_color(color) + let window = self.as_any().downcast_ref::().unwrap(); + window.set_title_text_color(color) } #[inline] fn set_corner_preference(&self, preference: CornerPreference) { - self.window.set_corner_preference(preference) + let window = self.as_any().downcast_ref::().unwrap(); + window.set_corner_preference(preference) } #[cfg(feature = "rwh_06")] unsafe fn window_handle_any_thread( &self, ) -> Result, rwh_06::HandleError> { + let window = self.as_any().downcast_ref::().unwrap(); unsafe { - let handle = self.window.rwh_06_no_thread_check()?; + let handle = window.rwh_06_no_thread_check()?; // SAFETY: The handle is valid in this context. Ok(rwh_06::WindowHandle::borrow_raw(handle)) @@ -430,7 +416,7 @@ impl WindowExtWindows for Window { /// Additional methods for anything that dereference to [`Window`]. /// /// [`Window`]: crate::window::Window -pub trait WindowBorrowExtWindows: Borrow + Sized { +pub trait WindowBorrowExtWindows: Borrow + Sized { /// Create an object that allows accessing the inner window handle in a thread-unsafe way. /// /// It is possible to call [`window_handle_any_thread`] to get around Windows's thread @@ -457,12 +443,15 @@ pub trait WindowBorrowExtWindows: Borrow + Sized { doc = "[`HasWindowHandle`]: #only-available-with-rwh_06", doc = "[`window_handle_any_thread`]: #only-available-with-rwh_06" )] - unsafe fn any_thread(self) -> AnyThread { + unsafe fn any_thread(self) -> AnyThread + where + Self: Window, + { AnyThread(self) } } -impl + Sized> WindowBorrowExtWindows for W {} +impl + Sized> WindowBorrowExtWindows for W {} /// Additional methods on `WindowAttributes` that are specific to Windows. #[allow(rustdoc::broken_intra_doc_links)] diff --git a/src/platform/x11.rs b/src/platform/x11.rs index 72d052f0f3..589c4753ba 100644 --- a/src/platform/x11.rs +++ b/src/platform/x11.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::dpi::Size; use crate::event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder}; use crate::monitor::MonitorHandle; -use crate::window::{Window, WindowAttributes}; +use crate::window::{Window as CoreWindow, WindowAttributes}; /// X window type. Maps directly to /// [`_NET_WM_WINDOW_TYPE`](https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html). @@ -138,9 +138,11 @@ impl EventLoopBuilderExtX11 for EventLoopBuilder { } /// Additional methods on [`Window`] that are specific to X11. +/// +/// [`Window`]: crate::window::Window pub trait WindowExtX11 {} -impl WindowExtX11 for Window {} +impl WindowExtX11 for dyn CoreWindow {} /// Additional methods on [`WindowAttributes`] that are specific to X11. pub trait WindowAttributesExtX11 { @@ -169,13 +171,13 @@ pub trait WindowAttributesExtX11 { /// /// ``` /// # use winit::dpi::{LogicalSize, PhysicalSize}; - /// # use winit::window::Window; + /// # use winit::window::{Window, WindowAttributes}; /// # use winit::platform::x11::WindowAttributesExtX11; /// // Specify the size in logical dimensions like this: - /// Window::default_attributes().with_base_size(LogicalSize::new(400.0, 200.0)); + /// WindowAttributes::default().with_base_size(LogicalSize::new(400.0, 200.0)); /// /// // Or specify the size in physical dimensions like this: - /// Window::default_attributes().with_base_size(PhysicalSize::new(400, 200)); + /// WindowAttributes::default().with_base_size(PhysicalSize::new(400, 200)); /// ``` fn with_base_size>(self, base_size: S) -> Self; @@ -184,12 +186,12 @@ pub trait WindowAttributesExtX11 { /// # Example /// /// ```no_run - /// use winit::window::Window; + /// use winit::window::{Window, WindowAttributes}; /// use winit::event_loop::ActiveEventLoop; /// use winit::platform::x11::{XWindow, WindowAttributesExtX11}; /// # fn create_window(event_loop: &dyn ActiveEventLoop) -> Result<(), Box> { /// let parent_window_id = std::env::args().nth(1).unwrap().parse::()?; - /// let window_attributes = Window::default_attributes().with_embed_parent_window(parent_window_id); + /// let window_attributes = WindowAttributes::default().with_embed_parent_window(parent_window_id); /// let window = event_loop.create_window(window_attributes)?; /// # Ok(()) } /// ``` diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index b3425ea339..88fa45bba7 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -22,10 +22,9 @@ use crate::event_loop::{ }; use crate::monitor::MonitorHandle as RootMonitorHandle; use crate::platform::pump_events::PumpStatus; -use crate::platform_impl::Fullscreen; use crate::window::{ - self, CursorGrabMode, CustomCursor, CustomCursorSource, ImePurpose, ResizeDirection, Theme, - Window as RootWindow, WindowAttributes, WindowButtons, WindowLevel, + self, CursorGrabMode, CustomCursor, CustomCursorSource, Fullscreen, ImePurpose, + ResizeDirection, Theme, Window as CoreWindow, WindowAttributes, WindowButtons, WindowLevel, }; mod keycodes; @@ -593,9 +592,8 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_window( &self, window_attributes: WindowAttributes, - ) -> Result { - let window = Window::new(self, window_attributes)?; - Ok(RootWindow { window }) + ) -> Result, error::OsError> { + Ok(Box::new(Window::new(self, window_attributes)?)) } fn create_custom_cursor( @@ -723,218 +721,233 @@ impl Window { Ok(Self { app: el.app.clone(), redraw_requester: el.redraw_requester.clone() }) } - pub(crate) fn maybe_queue_on_main(&self, f: impl FnOnce(&Self) + Send + 'static) { - f(self) + pub fn config(&self) -> ConfigurationRef { + self.app.config() } - pub(crate) fn maybe_wait_on_main(&self, f: impl FnOnce(&Self) -> R + Send) -> R { - f(self) + pub fn content_rect(&self) -> Rect { + self.app.content_rect() } - pub fn id(&self) -> WindowId { - WindowId + #[cfg(feature = "rwh_06")] + // Allow the usage of HasRawWindowHandle inside this function + #[allow(deprecated)] + fn raw_window_handle_rwh_06(&self) -> Result { + use rwh_06::HasRawWindowHandle; + + if let Some(native_window) = self.app.native_window().as_ref() { + native_window.raw_window_handle() + } else { + tracing::error!( + "Cannot get the native window, it's null and will always be null before \ + Event::Resumed and after Event::Suspended. Make sure you only call this function \ + between those events." + ); + Err(rwh_06::HandleError::Unavailable) + } } - pub fn primary_monitor(&self) -> Option { - None + #[cfg(feature = "rwh_06")] + fn raw_display_handle_rwh_06(&self) -> Result { + Ok(rwh_06::RawDisplayHandle::Android(rwh_06::AndroidDisplayHandle::new())) + } +} + +#[cfg(feature = "rwh_06")] +impl rwh_06::HasDisplayHandle for Window { + fn display_handle(&self) -> Result, rwh_06::HandleError> { + let raw = self.raw_display_handle_rwh_06()?; + unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) } + } +} + +#[cfg(feature = "rwh_06")] +impl rwh_06::HasWindowHandle for Window { + fn window_handle(&self) -> Result, rwh_06::HandleError> { + let raw = self.raw_window_handle_rwh_06()?; + unsafe { Ok(rwh_06::WindowHandle::borrow_raw(raw)) } } +} - pub fn available_monitors(&self) -> Option { +impl CoreWindow for Window { + fn id(&self) -> window::WindowId { + window::WindowId(WindowId) + } + + fn primary_monitor(&self) -> Option { None } - pub fn current_monitor(&self) -> Option { + fn available_monitors(&self) -> Box> { + Box::new(std::iter::empty()) + } + + fn current_monitor(&self) -> Option { None } - pub fn scale_factor(&self) -> f64 { + fn scale_factor(&self) -> f64 { scale_factor(&self.app) } - pub fn request_redraw(&self) { + fn request_redraw(&self) { self.redraw_requester.request_redraw() } - pub fn pre_present_notify(&self) {} + fn pre_present_notify(&self) {} - pub fn inner_position(&self) -> Result, error::NotSupportedError> { + fn inner_position(&self) -> Result, error::NotSupportedError> { Err(error::NotSupportedError::new()) } - pub fn outer_position(&self) -> Result, error::NotSupportedError> { + fn outer_position(&self) -> Result, error::NotSupportedError> { Err(error::NotSupportedError::new()) } - pub fn set_outer_position(&self, _position: Position) { + fn set_outer_position(&self, _position: Position) { // no effect } - pub fn inner_size(&self) -> PhysicalSize { + fn inner_size(&self) -> PhysicalSize { self.outer_size() } - pub fn request_inner_size(&self, _size: Size) -> Option> { + fn request_inner_size(&self, _size: Size) -> Option> { Some(self.inner_size()) } - pub fn outer_size(&self) -> PhysicalSize { + fn outer_size(&self) -> PhysicalSize { screen_size(&self.app) } - pub fn set_min_inner_size(&self, _: Option) {} + fn set_min_inner_size(&self, _: Option) {} - pub fn set_max_inner_size(&self, _: Option) {} + fn set_max_inner_size(&self, _: Option) {} - pub fn resize_increments(&self) -> Option> { + fn resize_increments(&self) -> Option> { None } - pub fn set_resize_increments(&self, _increments: Option) {} + fn set_resize_increments(&self, _increments: Option) {} - pub fn set_title(&self, _title: &str) {} + fn set_title(&self, _title: &str) {} - pub fn set_transparent(&self, _transparent: bool) {} + fn set_transparent(&self, _transparent: bool) {} - pub fn set_blur(&self, _blur: bool) {} + fn set_blur(&self, _blur: bool) {} - pub fn set_visible(&self, _visibility: bool) {} + fn set_visible(&self, _visibility: bool) {} - pub fn is_visible(&self) -> Option { + fn is_visible(&self) -> Option { None } - pub fn set_resizable(&self, _resizeable: bool) {} + fn set_resizable(&self, _resizeable: bool) {} - pub fn is_resizable(&self) -> bool { + fn is_resizable(&self) -> bool { false } - pub fn set_enabled_buttons(&self, _buttons: WindowButtons) {} + fn set_enabled_buttons(&self, _buttons: WindowButtons) {} - pub fn enabled_buttons(&self) -> WindowButtons { + fn enabled_buttons(&self) -> WindowButtons { WindowButtons::all() } - pub fn set_minimized(&self, _minimized: bool) {} + fn set_minimized(&self, _minimized: bool) {} - pub fn is_minimized(&self) -> Option { + fn is_minimized(&self) -> Option { None } - pub fn set_maximized(&self, _maximized: bool) {} + fn set_maximized(&self, _maximized: bool) {} - pub fn is_maximized(&self) -> bool { + fn is_maximized(&self) -> bool { false } - pub fn set_fullscreen(&self, _monitor: Option) { + fn set_fullscreen(&self, _monitor: Option) { warn!("Cannot set fullscreen on Android"); } - pub fn fullscreen(&self) -> Option { + fn fullscreen(&self) -> Option { None } - pub fn set_decorations(&self, _decorations: bool) {} + fn set_decorations(&self, _decorations: bool) {} - pub fn is_decorated(&self) -> bool { + fn is_decorated(&self) -> bool { true } - pub fn set_window_level(&self, _level: WindowLevel) {} + fn set_window_level(&self, _level: WindowLevel) {} - pub fn set_window_icon(&self, _window_icon: Option) {} + fn set_window_icon(&self, _window_icon: Option) {} - pub fn set_ime_cursor_area(&self, _position: Position, _size: Size) {} + fn set_ime_cursor_area(&self, _position: Position, _size: Size) {} - pub fn set_ime_allowed(&self, _allowed: bool) {} + fn set_ime_allowed(&self, _allowed: bool) {} - pub fn set_ime_purpose(&self, _purpose: ImePurpose) {} + fn set_ime_purpose(&self, _purpose: ImePurpose) {} - pub fn focus_window(&self) {} + fn focus_window(&self) {} - pub fn request_user_attention(&self, _request_type: Option) {} + fn request_user_attention(&self, _request_type: Option) {} - pub fn set_cursor(&self, _: Cursor) {} + fn set_cursor(&self, _: Cursor) {} - pub fn set_cursor_position(&self, _: Position) -> Result<(), error::ExternalError> { + fn set_cursor_position(&self, _: Position) -> Result<(), error::ExternalError> { Err(error::ExternalError::NotSupported(error::NotSupportedError::new())) } - pub fn set_cursor_grab(&self, _: CursorGrabMode) -> Result<(), error::ExternalError> { + fn set_cursor_grab(&self, _: CursorGrabMode) -> Result<(), error::ExternalError> { Err(error::ExternalError::NotSupported(error::NotSupportedError::new())) } - pub fn set_cursor_visible(&self, _: bool) {} + fn set_cursor_visible(&self, _: bool) {} - pub fn drag_window(&self) -> Result<(), error::ExternalError> { + fn drag_window(&self) -> Result<(), error::ExternalError> { Err(error::ExternalError::NotSupported(error::NotSupportedError::new())) } - pub fn drag_resize_window( - &self, - _direction: ResizeDirection, - ) -> Result<(), error::ExternalError> { + fn drag_resize_window(&self, _direction: ResizeDirection) -> Result<(), error::ExternalError> { Err(error::ExternalError::NotSupported(error::NotSupportedError::new())) } #[inline] - pub fn show_window_menu(&self, _position: Position) {} + fn show_window_menu(&self, _position: Position) {} - pub fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), error::ExternalError> { + fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), error::ExternalError> { Err(error::ExternalError::NotSupported(error::NotSupportedError::new())) } - #[cfg(feature = "rwh_06")] - // Allow the usage of HasRawWindowHandle inside this function - #[allow(deprecated)] - pub fn raw_window_handle_rwh_06(&self) -> Result { - use rwh_06::HasRawWindowHandle; - - if let Some(native_window) = self.app.native_window().as_ref() { - native_window.raw_window_handle() - } else { - tracing::error!( - "Cannot get the native window, it's null and will always be null before \ - Event::Resumed and after Event::Suspended. Make sure you only call this function \ - between those events." - ); - Err(rwh_06::HandleError::Unavailable) - } - } + fn set_theme(&self, _theme: Option) {} - #[cfg(feature = "rwh_06")] - pub fn raw_display_handle_rwh_06( - &self, - ) -> Result { - Ok(rwh_06::RawDisplayHandle::Android(rwh_06::AndroidDisplayHandle::new())) + fn theme(&self) -> Option { + None } - pub fn config(&self) -> ConfigurationRef { - self.app.config() - } + fn set_content_protected(&self, _protected: bool) {} - pub fn content_rect(&self) -> Rect { - self.app.content_rect() + fn has_focus(&self) -> bool { + HAS_FOCUS.load(Ordering::Relaxed) } - pub fn set_theme(&self, _theme: Option) {} - - pub fn theme(&self) -> Option { - None + fn title(&self) -> String { + String::new() } - pub fn set_content_protected(&self, _protected: bool) {} + fn reset_dead_keys(&self) {} - pub fn has_focus(&self) -> bool { - HAS_FOCUS.load(Ordering::Relaxed) + #[cfg(feature = "rwh_06")] + fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle { + self } - pub fn title(&self) -> String { - String::new() + #[cfg(feature = "rwh_06")] + fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle { + self } - - pub fn reset_dead_keys(&self) {} } #[derive(Default, Clone, Debug)] diff --git a/src/platform_impl/apple/appkit/event_loop.rs b/src/platform_impl/apple/appkit/event_loop.rs index e31c2cdf28..4f51a4bad3 100644 --- a/src/platform_impl/apple/appkit/event_loop.rs +++ b/src/platform_impl/apple/appkit/event_loop.rs @@ -38,9 +38,7 @@ use crate::monitor::MonitorHandle as RootMonitorHandle; use crate::platform::macos::ActivationPolicy; use crate::platform::pump_events::PumpStatus; use crate::platform_impl::Window; -use crate::window::{ - CustomCursor as RootCustomCursor, CustomCursorSource, Theme, Window as RootWindow, -}; +use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource, Theme}; #[derive(Default)] pub struct PanicInfo { @@ -105,9 +103,8 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_window( &self, window_attributes: crate::window::WindowAttributes, - ) -> Result { - let window = Window::new(self, window_attributes)?; - Ok(RootWindow { window }) + ) -> Result, crate::error::OsError> { + Ok(Box::new(Window::new(self, window_attributes)?)) } fn create_custom_cursor( diff --git a/src/platform_impl/apple/appkit/window.rs b/src/platform_impl/apple/appkit/window.rs index 06013051e0..c4f49ae7fd 100644 --- a/src/platform_impl/apple/appkit/window.rs +++ b/src/platform_impl/apple/appkit/window.rs @@ -1,5 +1,6 @@ #![allow(clippy::unnecessary_cast)] +use dpi::{Position, Size}; use objc2::rc::{autoreleasepool, Retained}; use objc2::{declare_class, mutability, ClassType, DeclaredClass}; use objc2_app_kit::{NSResponder, NSWindow}; @@ -8,7 +9,11 @@ use objc2_foundation::{MainThreadBound, MainThreadMarker, NSObject}; use super::event_loop::ActiveEventLoop; use super::window_delegate::WindowDelegate; use crate::error::OsError as RootOsError; -use crate::window::WindowAttributes; +use crate::monitor::MonitorHandle as CoreMonitorHandle; +use crate::window::{ + Cursor, Fullscreen, Icon, ImePurpose, Theme, UserAttentionType, Window as CoreWindow, + WindowAttributes, WindowButtons, WindowLevel, +}; pub(crate) struct Window { window: MainThreadBound>, @@ -16,12 +21,6 @@ pub(crate) struct Window { delegate: MainThreadBound>, } -impl Drop for Window { - fn drop(&mut self) { - self.window.get_on_main(|window| autoreleasepool(|_| window.close())) - } -} - impl Window { pub(crate) fn new( window_target: &ActiveEventLoop, @@ -36,11 +35,6 @@ impl Window { }) } - pub(crate) fn maybe_queue_on_main(&self, f: impl FnOnce(&WindowDelegate) + Send + 'static) { - // For now, don't actually do queuing, since it may be less predictable - self.maybe_wait_on_main(f) - } - pub(crate) fn maybe_wait_on_main( &self, f: impl FnOnce(&WindowDelegate) -> R + Send, @@ -69,6 +63,283 @@ impl Window { } } +impl Drop for Window { + fn drop(&mut self) { + // Restore the video mode. + if matches!(self.fullscreen(), Some(Fullscreen::Exclusive(_))) { + self.set_fullscreen(None); + } + + self.window.get_on_main(|window| autoreleasepool(|_| window.close())) + } +} + +#[cfg(feature = "rwh_06")] +impl rwh_06::HasDisplayHandle for Window { + fn display_handle(&self) -> Result, rwh_06::HandleError> { + let raw = self.raw_display_handle_rwh_06()?; + unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) } + } +} + +#[cfg(feature = "rwh_06")] +impl rwh_06::HasWindowHandle for Window { + fn window_handle(&self) -> Result, rwh_06::HandleError> { + let raw = self.raw_window_handle_rwh_06()?; + unsafe { Ok(rwh_06::WindowHandle::borrow_raw(raw)) } + } +} + +impl CoreWindow for Window { + fn id(&self) -> crate::window::WindowId { + self.maybe_wait_on_main(|delegate| crate::window::WindowId(delegate.id())) + } + + fn scale_factor(&self) -> f64 { + self.maybe_wait_on_main(|delegate| delegate.scale_factor()) + } + + fn request_redraw(&self) { + self.maybe_wait_on_main(|delegate| delegate.request_redraw()); + } + + fn pre_present_notify(&self) { + self.maybe_wait_on_main(|delegate| delegate.pre_present_notify()); + } + + fn reset_dead_keys(&self) { + self.maybe_wait_on_main(|delegate| delegate.reset_dead_keys()); + } + + fn inner_position( + &self, + ) -> Result, crate::error::NotSupportedError> { + self.maybe_wait_on_main(|delegate| delegate.inner_position()) + } + + fn outer_position( + &self, + ) -> Result, crate::error::NotSupportedError> { + self.maybe_wait_on_main(|delegate| delegate.outer_position()) + } + + fn set_outer_position(&self, position: Position) { + self.maybe_wait_on_main(|delegate| delegate.set_outer_position(position)); + } + + fn inner_size(&self) -> dpi::PhysicalSize { + self.maybe_wait_on_main(|delegate| delegate.inner_size()) + } + + fn request_inner_size(&self, size: Size) -> Option> { + self.maybe_wait_on_main(|delegate| delegate.request_inner_size(size)) + } + + fn outer_size(&self) -> dpi::PhysicalSize { + self.maybe_wait_on_main(|delegate| delegate.outer_size()) + } + + fn set_min_inner_size(&self, min_size: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_min_inner_size(min_size)) + } + + fn set_max_inner_size(&self, max_size: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_max_inner_size(max_size)); + } + + fn resize_increments(&self) -> Option> { + self.maybe_wait_on_main(|delegate| delegate.resize_increments()) + } + + fn set_resize_increments(&self, increments: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_resize_increments(increments)); + } + + fn set_title(&self, title: &str) { + self.maybe_wait_on_main(|delegate| delegate.set_title(title)); + } + + fn set_transparent(&self, transparent: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_transparent(transparent)); + } + + fn set_blur(&self, blur: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_blur(blur)); + } + + fn set_visible(&self, visible: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_visible(visible)); + } + + fn is_visible(&self) -> Option { + self.maybe_wait_on_main(|delegate| delegate.is_visible()) + } + + fn set_resizable(&self, resizable: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_resizable(resizable)) + } + + fn is_resizable(&self) -> bool { + self.maybe_wait_on_main(|delegate| delegate.is_resizable()) + } + + fn set_enabled_buttons(&self, buttons: WindowButtons) { + self.maybe_wait_on_main(|delegate| delegate.set_enabled_buttons(buttons)) + } + + fn enabled_buttons(&self) -> WindowButtons { + self.maybe_wait_on_main(|delegate| delegate.enabled_buttons()) + } + + fn set_minimized(&self, minimized: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_minimized(minimized)); + } + + fn is_minimized(&self) -> Option { + self.maybe_wait_on_main(|delegate| delegate.is_minimized()) + } + + fn set_maximized(&self, maximized: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_maximized(maximized)); + } + + fn is_maximized(&self) -> bool { + self.maybe_wait_on_main(|delegate| delegate.is_maximized()) + } + + fn set_fullscreen(&self, fullscreen: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_fullscreen(fullscreen.map(Into::into))) + } + + fn fullscreen(&self) -> Option { + self.maybe_wait_on_main(|delegate| delegate.fullscreen().map(Into::into)) + } + + fn set_decorations(&self, decorations: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_decorations(decorations)); + } + + fn is_decorated(&self) -> bool { + self.maybe_wait_on_main(|delegate| delegate.is_decorated()) + } + + fn set_window_level(&self, level: WindowLevel) { + self.maybe_wait_on_main(|delegate| delegate.set_window_level(level)); + } + + fn set_window_icon(&self, window_icon: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_window_icon(window_icon)); + } + + fn set_ime_cursor_area(&self, position: Position, size: Size) { + self.maybe_wait_on_main(|delegate| delegate.set_ime_cursor_area(position, size)); + } + + fn set_ime_allowed(&self, allowed: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_ime_allowed(allowed)); + } + + fn set_ime_purpose(&self, purpose: ImePurpose) { + self.maybe_wait_on_main(|delegate| delegate.set_ime_purpose(purpose)); + } + + fn focus_window(&self) { + self.maybe_wait_on_main(|delegate| delegate.focus_window()); + } + + fn has_focus(&self) -> bool { + self.maybe_wait_on_main(|delegate| delegate.has_focus()) + } + + fn request_user_attention(&self, request_type: Option) { + self.maybe_wait_on_main(|delegate| delegate.request_user_attention(request_type)); + } + + fn set_theme(&self, theme: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_theme(theme)); + } + + fn theme(&self) -> Option { + self.maybe_wait_on_main(|delegate| delegate.theme()) + } + + fn set_content_protected(&self, protected: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_content_protected(protected)); + } + + fn title(&self) -> String { + self.maybe_wait_on_main(|delegate| delegate.title()) + } + + fn set_cursor(&self, cursor: Cursor) { + self.maybe_wait_on_main(|delegate| delegate.set_cursor(cursor)); + } + + fn set_cursor_position(&self, position: Position) -> Result<(), crate::error::ExternalError> { + self.maybe_wait_on_main(|delegate| delegate.set_cursor_position(position)) + } + + fn set_cursor_grab( + &self, + mode: crate::window::CursorGrabMode, + ) -> Result<(), crate::error::ExternalError> { + self.maybe_wait_on_main(|delegate| delegate.set_cursor_grab(mode)) + } + + fn set_cursor_visible(&self, visible: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_cursor_visible(visible)) + } + + fn drag_window(&self) -> Result<(), crate::error::ExternalError> { + self.maybe_wait_on_main(|delegate| delegate.drag_window()) + } + + fn drag_resize_window( + &self, + direction: crate::window::ResizeDirection, + ) -> Result<(), crate::error::ExternalError> { + self.maybe_wait_on_main(|delegate| delegate.drag_resize_window(direction)) + } + + fn show_window_menu(&self, position: Position) { + self.maybe_wait_on_main(|delegate| delegate.show_window_menu(position)) + } + + fn set_cursor_hittest(&self, hittest: bool) -> Result<(), crate::error::ExternalError> { + self.maybe_wait_on_main(|delegate| delegate.set_cursor_hittest(hittest)) + } + + fn current_monitor(&self) -> Option { + self.maybe_wait_on_main(|delegate| { + delegate.current_monitor().map(|inner| CoreMonitorHandle { inner }) + }) + } + + fn available_monitors(&self) -> Box> { + self.maybe_wait_on_main(|delegate| { + Box::new( + delegate.available_monitors().into_iter().map(|inner| CoreMonitorHandle { inner }), + ) + }) + } + + fn primary_monitor(&self) -> Option { + self.maybe_wait_on_main(|delegate| { + delegate.primary_monitor().map(|inner| CoreMonitorHandle { inner }) + }) + } + + #[cfg(feature = "rwh_06")] + fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle { + self + } + + #[cfg(feature = "rwh_06")] + fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle { + self + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct WindowId(pub usize); diff --git a/src/platform_impl/apple/uikit/event_loop.rs b/src/platform_impl/apple/uikit/event_loop.rs index 82599c6189..2146262ba5 100644 --- a/src/platform_impl/apple/uikit/event_loop.rs +++ b/src/platform_impl/apple/uikit/event_loop.rs @@ -33,7 +33,7 @@ use crate::event_loop::{ }; use crate::monitor::MonitorHandle as RootMonitorHandle; use crate::platform_impl::Window; -use crate::window::{CustomCursor, CustomCursorSource, Theme, Window as RootWindow}; +use crate::window::{CustomCursor, CustomCursorSource, Theme, Window as CoreWindow}; #[derive(Debug)] pub(crate) struct ActiveEventLoop { @@ -49,9 +49,8 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_window( &self, window_attributes: crate::window::WindowAttributes, - ) -> Result { - let window = Window::new(self, window_attributes)?; - Ok(RootWindow { window }) + ) -> Result, OsError> { + Ok(Box::new(Window::new(self, window_attributes)?)) } fn create_custom_cursor( diff --git a/src/platform_impl/apple/uikit/window.rs b/src/platform_impl/apple/uikit/window.rs index 104535cd6d..3cae4dbf9e 100644 --- a/src/platform_impl/apple/uikit/window.rs +++ b/src/platform_impl/apple/uikit/window.rs @@ -23,10 +23,11 @@ use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, P use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError}; use crate::event::{Event, WindowEvent}; use crate::icon::Icon; +use crate::monitor::MonitorHandle as CoreMonitorHandle; use crate::platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations}; use crate::window::{ - CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes, - WindowButtons, WindowId as RootWindowId, WindowLevel, + CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as CoreWindow, + WindowAttributes, WindowButtons, WindowId as CoreWindowId, WindowLevel, }; declare_class!( @@ -49,7 +50,7 @@ declare_class!( app_state::handle_nonuser_event( mtm, EventWrapper::StaticEvent(Event::WindowEvent { - window_id: RootWindowId(self.id()), + window_id: CoreWindowId(self.id()), event: WindowEvent::Focused(true), }), ); @@ -62,7 +63,7 @@ declare_class!( app_state::handle_nonuser_event( mtm, EventWrapper::StaticEvent(Event::WindowEvent { - window_id: RootWindowId(self.id()), + window_id: CoreWindowId(self.id()), event: WindowEvent::Focused(false), }), ); @@ -522,7 +523,7 @@ impl Window { width: screen_frame.size.width as f64, height: screen_frame.size.height as f64, }; - let window_id = RootWindowId(window.id()); + let window_id = CoreWindowId(window.id()); app_state::handle_nonuser_events( mtm, std::iter::once(EventWrapper::ScaleFactorChanged(app_state::ScaleFactorChanged { @@ -543,11 +544,6 @@ impl Window { Ok(Window { inner: MainThreadBound::new(inner, mtm) }) } - pub(crate) fn maybe_queue_on_main(&self, f: impl FnOnce(&Inner) + Send + 'static) { - // For now, don't actually do queuing, since it may be less predictable - self.maybe_wait_on_main(f) - } - pub(crate) fn maybe_wait_on_main(&self, f: impl FnOnce(&Inner) -> R + Send) -> R { self.inner.get_on_main(|inner| f(inner)) } @@ -573,6 +569,272 @@ impl Window { } } +#[cfg(feature = "rwh_06")] +impl rwh_06::HasDisplayHandle for Window { + fn display_handle(&self) -> Result, rwh_06::HandleError> { + let raw = self.raw_display_handle_rwh_06()?; + unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) } + } +} + +#[cfg(feature = "rwh_06")] +impl rwh_06::HasWindowHandle for Window { + fn window_handle(&self) -> Result, rwh_06::HandleError> { + let raw = self.raw_window_handle_rwh_06()?; + unsafe { Ok(rwh_06::WindowHandle::borrow_raw(raw)) } + } +} + +impl CoreWindow for Window { + fn id(&self) -> crate::window::WindowId { + self.maybe_wait_on_main(|delegate| crate::window::WindowId(delegate.id())) + } + + fn scale_factor(&self) -> f64 { + self.maybe_wait_on_main(|delegate| delegate.scale_factor()) + } + + fn request_redraw(&self) { + self.maybe_wait_on_main(|delegate| delegate.request_redraw()); + } + + fn pre_present_notify(&self) { + self.maybe_wait_on_main(|delegate| delegate.pre_present_notify()); + } + + fn reset_dead_keys(&self) { + self.maybe_wait_on_main(|delegate| delegate.reset_dead_keys()); + } + + fn inner_position( + &self, + ) -> Result, crate::error::NotSupportedError> { + self.maybe_wait_on_main(|delegate| delegate.inner_position()) + } + + fn outer_position( + &self, + ) -> Result, crate::error::NotSupportedError> { + self.maybe_wait_on_main(|delegate| delegate.outer_position()) + } + + fn set_outer_position(&self, position: Position) { + self.maybe_wait_on_main(|delegate| delegate.set_outer_position(position)); + } + + fn inner_size(&self) -> dpi::PhysicalSize { + self.maybe_wait_on_main(|delegate| delegate.inner_size()) + } + + fn request_inner_size(&self, size: Size) -> Option> { + self.maybe_wait_on_main(|delegate| delegate.request_inner_size(size)) + } + + fn outer_size(&self) -> dpi::PhysicalSize { + self.maybe_wait_on_main(|delegate| delegate.outer_size()) + } + + fn set_min_inner_size(&self, min_size: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_min_inner_size(min_size)) + } + + fn set_max_inner_size(&self, max_size: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_max_inner_size(max_size)); + } + + fn resize_increments(&self) -> Option> { + self.maybe_wait_on_main(|delegate| delegate.resize_increments()) + } + + fn set_resize_increments(&self, increments: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_resize_increments(increments)); + } + + fn set_title(&self, title: &str) { + self.maybe_wait_on_main(|delegate| delegate.set_title(title)); + } + + fn set_transparent(&self, transparent: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_transparent(transparent)); + } + + fn set_blur(&self, blur: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_blur(blur)); + } + + fn set_visible(&self, visible: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_visible(visible)); + } + + fn is_visible(&self) -> Option { + self.maybe_wait_on_main(|delegate| delegate.is_visible()) + } + + fn set_resizable(&self, resizable: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_resizable(resizable)) + } + + fn is_resizable(&self) -> bool { + self.maybe_wait_on_main(|delegate| delegate.is_resizable()) + } + + fn set_enabled_buttons(&self, buttons: WindowButtons) { + self.maybe_wait_on_main(|delegate| delegate.set_enabled_buttons(buttons)) + } + + fn enabled_buttons(&self) -> WindowButtons { + self.maybe_wait_on_main(|delegate| delegate.enabled_buttons()) + } + + fn set_minimized(&self, minimized: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_minimized(minimized)); + } + + fn is_minimized(&self) -> Option { + self.maybe_wait_on_main(|delegate| delegate.is_minimized()) + } + + fn set_maximized(&self, maximized: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_maximized(maximized)); + } + + fn is_maximized(&self) -> bool { + self.maybe_wait_on_main(|delegate| delegate.is_maximized()) + } + + fn set_fullscreen(&self, fullscreen: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_fullscreen(fullscreen.map(Into::into))) + } + + fn fullscreen(&self) -> Option { + self.maybe_wait_on_main(|delegate| delegate.fullscreen().map(Into::into)) + } + + fn set_decorations(&self, decorations: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_decorations(decorations)); + } + + fn is_decorated(&self) -> bool { + self.maybe_wait_on_main(|delegate| delegate.is_decorated()) + } + + fn set_window_level(&self, level: WindowLevel) { + self.maybe_wait_on_main(|delegate| delegate.set_window_level(level)); + } + + fn set_window_icon(&self, window_icon: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_window_icon(window_icon)); + } + + fn set_ime_cursor_area(&self, position: Position, size: Size) { + self.maybe_wait_on_main(|delegate| delegate.set_ime_cursor_area(position, size)); + } + + fn set_ime_allowed(&self, allowed: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_ime_allowed(allowed)); + } + + fn set_ime_purpose(&self, purpose: ImePurpose) { + self.maybe_wait_on_main(|delegate| delegate.set_ime_purpose(purpose)); + } + + fn focus_window(&self) { + self.maybe_wait_on_main(|delegate| delegate.focus_window()); + } + + fn has_focus(&self) -> bool { + self.maybe_wait_on_main(|delegate| delegate.has_focus()) + } + + fn request_user_attention(&self, request_type: Option) { + self.maybe_wait_on_main(|delegate| delegate.request_user_attention(request_type)); + } + + fn set_theme(&self, theme: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_theme(theme)); + } + + fn theme(&self) -> Option { + self.maybe_wait_on_main(|delegate| delegate.theme()) + } + + fn set_content_protected(&self, protected: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_content_protected(protected)); + } + + fn title(&self) -> String { + self.maybe_wait_on_main(|delegate| delegate.title()) + } + + fn set_cursor(&self, cursor: Cursor) { + self.maybe_wait_on_main(|delegate| delegate.set_cursor(cursor)); + } + + fn set_cursor_position(&self, position: Position) -> Result<(), crate::error::ExternalError> { + self.maybe_wait_on_main(|delegate| delegate.set_cursor_position(position)) + } + + fn set_cursor_grab( + &self, + mode: crate::window::CursorGrabMode, + ) -> Result<(), crate::error::ExternalError> { + self.maybe_wait_on_main(|delegate| delegate.set_cursor_grab(mode)) + } + + fn set_cursor_visible(&self, visible: bool) { + self.maybe_wait_on_main(|delegate| delegate.set_cursor_visible(visible)) + } + + fn drag_window(&self) -> Result<(), crate::error::ExternalError> { + self.maybe_wait_on_main(|delegate| delegate.drag_window()) + } + + fn drag_resize_window( + &self, + direction: crate::window::ResizeDirection, + ) -> Result<(), crate::error::ExternalError> { + self.maybe_wait_on_main(|delegate| delegate.drag_resize_window(direction)) + } + + fn show_window_menu(&self, position: Position) { + self.maybe_wait_on_main(|delegate| delegate.show_window_menu(position)) + } + + fn set_cursor_hittest(&self, hittest: bool) -> Result<(), crate::error::ExternalError> { + self.maybe_wait_on_main(|delegate| delegate.set_cursor_hittest(hittest)) + } + + fn current_monitor(&self) -> Option { + self.maybe_wait_on_main(|delegate| { + delegate.current_monitor().map(|inner| CoreMonitorHandle { inner }) + }) + } + + fn available_monitors(&self) -> Box> { + self.maybe_wait_on_main(|delegate| { + Box::new( + delegate.available_monitors().into_iter().map(|inner| CoreMonitorHandle { inner }), + ) + }) + } + + fn primary_monitor(&self) -> Option { + self.maybe_wait_on_main(|delegate| { + delegate.primary_monitor().map(|inner| CoreMonitorHandle { inner }) + }) + } + + #[cfg(feature = "rwh_06")] + fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle { + self + } + + #[cfg(feature = "rwh_06")] + fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle { + self + } +} + // WindowExtIOS impl Inner { pub fn set_scale_factor(&self, scale_factor: f64) { diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 919261976d..0935d6e1ef 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -3,7 +3,6 @@ #[cfg(all(not(x11_platform), not(wayland_platform)))] compile_error!("Please select a feature to build for unix: `x11`, `wayland`"); -use std::collections::VecDeque; use std::num::{NonZeroU16, NonZeroU32}; use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; use std::sync::Arc; @@ -19,22 +18,19 @@ pub(crate) use self::common::xkb::{physicalkey_to_scancode, scancode_to_physical use self::x11::{X11Error, XConnection, XError, XNotSupported}; use crate::application::ApplicationHandler; pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource; -use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; -use crate::error::{EventLoopError, ExternalError, NotSupportedError}; -use crate::event_loop::{ActiveEventLoop, AsyncRequestSerial}; -use crate::icon::Icon; +#[cfg(x11_platform)] +use crate::dpi::Size; +use crate::dpi::{PhysicalPosition, PhysicalSize}; +use crate::error::EventLoopError; +use crate::event_loop::ActiveEventLoop; pub(crate) use crate::icon::RgbaIcon as PlatformIcon; use crate::keyboard::Key; use crate::platform::pump_events::PumpStatus; #[cfg(x11_platform)] use crate::platform::x11::{WindowType as XWindowType, XlibErrorHook}; -pub(crate) use crate::platform_impl::Fullscreen; #[cfg(x11_platform)] use crate::utils::Lazy; -use crate::window::{ - ActivationToken, Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, - WindowButtons, WindowLevel, -}; +use crate::window::ActivationToken; pub(crate) mod common; #[cfg(wayland_platform)] @@ -137,13 +133,6 @@ impl fmt::Display for OsError { } } -pub(crate) enum Window { - #[cfg(x11_platform)] - X(x11::Window), - #[cfg(wayland_platform)] - Wayland(wayland::Window), -} - #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct WindowId(u64); @@ -297,316 +286,6 @@ impl VideoModeHandle { } } -impl Window { - pub(crate) fn maybe_queue_on_main(&self, f: impl FnOnce(&Self) + Send + 'static) { - f(self) - } - - pub(crate) fn maybe_wait_on_main(&self, f: impl FnOnce(&Self) -> R + Send) -> R { - f(self) - } - - #[inline] - pub fn id(&self) -> WindowId { - x11_or_wayland!(match self; Window(w) => w.id()) - } - - #[inline] - pub fn set_title(&self, title: &str) { - x11_or_wayland!(match self; Window(w) => w.set_title(title)); - } - - #[inline] - pub fn set_transparent(&self, transparent: bool) { - x11_or_wayland!(match self; Window(w) => w.set_transparent(transparent)); - } - - #[inline] - pub fn set_blur(&self, blur: bool) { - x11_or_wayland!(match self; Window(w) => w.set_blur(blur)); - } - - #[inline] - pub fn set_visible(&self, visible: bool) { - x11_or_wayland!(match self; Window(w) => w.set_visible(visible)) - } - - #[inline] - pub fn is_visible(&self) -> Option { - x11_or_wayland!(match self; Window(w) => w.is_visible()) - } - - #[inline] - pub fn outer_position(&self) -> Result, NotSupportedError> { - x11_or_wayland!(match self; Window(w) => w.outer_position()) - } - - #[inline] - pub fn inner_position(&self) -> Result, NotSupportedError> { - x11_or_wayland!(match self; Window(w) => w.inner_position()) - } - - #[inline] - pub fn set_outer_position(&self, position: Position) { - x11_or_wayland!(match self; Window(w) => w.set_outer_position(position)) - } - - #[inline] - pub fn inner_size(&self) -> PhysicalSize { - x11_or_wayland!(match self; Window(w) => w.inner_size()) - } - - #[inline] - pub fn outer_size(&self) -> PhysicalSize { - x11_or_wayland!(match self; Window(w) => w.outer_size()) - } - - #[inline] - pub fn request_inner_size(&self, size: Size) -> Option> { - x11_or_wayland!(match self; Window(w) => w.request_inner_size(size)) - } - - #[inline] - pub(crate) fn request_activation_token(&self) -> Result { - x11_or_wayland!(match self; Window(w) => w.request_activation_token()) - } - - #[inline] - pub fn set_min_inner_size(&self, dimensions: Option) { - x11_or_wayland!(match self; Window(w) => w.set_min_inner_size(dimensions)) - } - - #[inline] - pub fn set_max_inner_size(&self, dimensions: Option) { - x11_or_wayland!(match self; Window(w) => w.set_max_inner_size(dimensions)) - } - - #[inline] - pub fn resize_increments(&self) -> Option> { - x11_or_wayland!(match self; Window(w) => w.resize_increments()) - } - - #[inline] - pub fn set_resize_increments(&self, increments: Option) { - x11_or_wayland!(match self; Window(w) => w.set_resize_increments(increments)) - } - - #[inline] - pub fn set_resizable(&self, resizable: bool) { - x11_or_wayland!(match self; Window(w) => w.set_resizable(resizable)) - } - - #[inline] - pub fn is_resizable(&self) -> bool { - x11_or_wayland!(match self; Window(w) => w.is_resizable()) - } - - #[inline] - pub fn set_enabled_buttons(&self, buttons: WindowButtons) { - x11_or_wayland!(match self; Window(w) => w.set_enabled_buttons(buttons)) - } - - #[inline] - pub fn enabled_buttons(&self) -> WindowButtons { - x11_or_wayland!(match self; Window(w) => w.enabled_buttons()) - } - - #[inline] - pub fn set_cursor(&self, cursor: Cursor) { - x11_or_wayland!(match self; Window(w) => w.set_cursor(cursor)) - } - - #[inline] - pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { - x11_or_wayland!(match self; Window(window) => window.set_cursor_grab(mode)) - } - - #[inline] - pub fn set_cursor_visible(&self, visible: bool) { - x11_or_wayland!(match self; Window(window) => window.set_cursor_visible(visible)) - } - - #[inline] - pub fn drag_window(&self) -> Result<(), ExternalError> { - x11_or_wayland!(match self; Window(window) => window.drag_window()) - } - - #[inline] - pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { - x11_or_wayland!(match self; Window(window) => window.drag_resize_window(direction)) - } - - #[inline] - pub fn show_window_menu(&self, position: Position) { - x11_or_wayland!(match self; Window(w) => w.show_window_menu(position)) - } - - #[inline] - pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> { - x11_or_wayland!(match self; Window(w) => w.set_cursor_hittest(hittest)) - } - - #[inline] - pub fn scale_factor(&self) -> f64 { - x11_or_wayland!(match self; Window(w) => w.scale_factor()) - } - - #[inline] - pub fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> { - x11_or_wayland!(match self; Window(w) => w.set_cursor_position(position)) - } - - #[inline] - pub fn set_maximized(&self, maximized: bool) { - x11_or_wayland!(match self; Window(w) => w.set_maximized(maximized)) - } - - #[inline] - pub fn is_maximized(&self) -> bool { - x11_or_wayland!(match self; Window(w) => w.is_maximized()) - } - - #[inline] - pub fn set_minimized(&self, minimized: bool) { - x11_or_wayland!(match self; Window(w) => w.set_minimized(minimized)) - } - - #[inline] - pub fn is_minimized(&self) -> Option { - x11_or_wayland!(match self; Window(w) => w.is_minimized()) - } - - #[inline] - pub(crate) fn fullscreen(&self) -> Option { - x11_or_wayland!(match self; Window(w) => w.fullscreen()) - } - - #[inline] - pub(crate) fn set_fullscreen(&self, monitor: Option) { - x11_or_wayland!(match self; Window(w) => w.set_fullscreen(monitor)) - } - - #[inline] - pub fn set_decorations(&self, decorations: bool) { - x11_or_wayland!(match self; Window(w) => w.set_decorations(decorations)) - } - - #[inline] - pub fn is_decorated(&self) -> bool { - x11_or_wayland!(match self; Window(w) => w.is_decorated()) - } - - #[inline] - pub fn set_window_level(&self, level: WindowLevel) { - x11_or_wayland!(match self; Window(w) => w.set_window_level(level)) - } - - #[inline] - pub fn set_window_icon(&self, window_icon: Option) { - x11_or_wayland!(match self; Window(w) => w.set_window_icon(window_icon.map(|icon| icon.inner))) - } - - #[inline] - pub fn set_ime_cursor_area(&self, position: Position, size: Size) { - x11_or_wayland!(match self; Window(w) => w.set_ime_cursor_area(position, size)) - } - - #[inline] - pub fn reset_dead_keys(&self) { - common::xkb::reset_dead_keys() - } - - #[inline] - pub fn set_ime_allowed(&self, allowed: bool) { - x11_or_wayland!(match self; Window(w) => w.set_ime_allowed(allowed)) - } - - #[inline] - pub fn set_ime_purpose(&self, purpose: ImePurpose) { - x11_or_wayland!(match self; Window(w) => w.set_ime_purpose(purpose)) - } - - #[inline] - pub fn focus_window(&self) { - x11_or_wayland!(match self; Window(w) => w.focus_window()) - } - - pub fn request_user_attention(&self, request_type: Option) { - x11_or_wayland!(match self; Window(w) => w.request_user_attention(request_type)) - } - - #[inline] - pub fn request_redraw(&self) { - x11_or_wayland!(match self; Window(w) => w.request_redraw()) - } - - #[inline] - pub fn pre_present_notify(&self) { - x11_or_wayland!(match self; Window(w) => w.pre_present_notify()) - } - - #[inline] - pub fn current_monitor(&self) -> Option { - Some(x11_or_wayland!(match self; Window(w) => w.current_monitor()?; as MonitorHandle)) - } - - #[inline] - pub fn available_monitors(&self) -> VecDeque { - match self { - #[cfg(x11_platform)] - Window::X(ref window) => { - window.available_monitors().into_iter().map(MonitorHandle::X).collect() - }, - #[cfg(wayland_platform)] - Window::Wayland(ref window) => { - window.available_monitors().into_iter().map(MonitorHandle::Wayland).collect() - }, - } - } - - #[inline] - pub fn primary_monitor(&self) -> Option { - Some(x11_or_wayland!(match self; Window(w) => w.primary_monitor()?; as MonitorHandle)) - } - - #[cfg(feature = "rwh_06")] - #[inline] - pub fn raw_window_handle_rwh_06(&self) -> Result { - x11_or_wayland!(match self; Window(window) => window.raw_window_handle_rwh_06()) - } - - #[cfg(feature = "rwh_06")] - #[inline] - pub fn raw_display_handle_rwh_06( - &self, - ) -> Result { - x11_or_wayland!(match self; Window(window) => window.raw_display_handle_rwh_06()) - } - - #[inline] - pub fn set_theme(&self, theme: Option) { - x11_or_wayland!(match self; Window(window) => window.set_theme(theme)) - } - - #[inline] - pub fn theme(&self) -> Option { - x11_or_wayland!(match self; Window(window) => window.theme()) - } - - pub fn set_content_protected(&self, protected: bool) { - x11_or_wayland!(match self; Window(window) => window.set_content_protected(protected)) - } - - #[inline] - pub fn has_focus(&self) -> bool { - x11_or_wayland!(match self; Window(window) => window.has_focus()) - } - - pub fn title(&self) -> String { - x11_or_wayland!(match self; Window(window) => window.title()) - } -} - #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct KeyEventExtra { pub text_with_all_modifiers: Option, diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index 36b56e8258..4dc6747293 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -628,10 +628,9 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_window( &self, window_attributes: crate::window::WindowAttributes, - ) -> Result { + ) -> Result, RootOsError> { let window = crate::platform_impl::wayland::Window::new(self, window_attributes)?; - let window = crate::platform_impl::Window::Wayland(window); - Ok(crate::window::Window { window }) + Ok(Box::new(window)) } fn available_monitors(&self) -> Box> { diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index f4c3180938..1fb97c87f0 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -21,12 +21,12 @@ use crate::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError}; use crate::event::{Ime, WindowEvent}; use crate::event_loop::AsyncRequestSerial; -use crate::platform_impl::{ - Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformIcon, -}; +use crate::monitor::MonitorHandle as CoreMonitorHandle; +use crate::platform_impl::{Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError}; use crate::window::{ - Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, - WindowAttributes, WindowButtons, WindowLevel, + Cursor, CursorGrabMode, Fullscreen as CoreFullscreen, ImePurpose, ResizeDirection, Theme, + UserAttentionType, Window as CoreWindow, WindowAttributes, WindowButtons, + WindowId as CoreWindowId, WindowLevel, }; pub(crate) mod state; @@ -223,51 +223,65 @@ impl Window { } impl Window { - #[inline] - pub fn id(&self) -> WindowId { - self.window_id - } + pub fn request_activation_token(&self) -> Result { + let xdg_activation = match self.xdg_activation.as_ref() { + Some(xdg_activation) => xdg_activation, + None => return Err(NotSupportedError::new()), + }; - #[inline] - pub fn set_title(&self, title: impl ToString) { - let new_title = title.to_string(); - self.window_state.lock().unwrap().set_title(new_title); - } + let serial = AsyncRequestSerial::get(); - #[inline] - pub fn set_visible(&self, _visible: bool) { - // Not possible on Wayland. + let data = XdgActivationTokenData::Obtain((self.window_id, serial)); + let xdg_activation_token = xdg_activation.get_activation_token(&self.queue_handle, data); + xdg_activation_token.set_surface(self.surface()); + xdg_activation_token.commit(); + + Ok(serial) } #[inline] - pub fn is_visible(&self) -> Option { - None + pub fn surface(&self) -> &WlSurface { + self.window.wl_surface() } +} - #[inline] - pub fn outer_position(&self) -> Result, NotSupportedError> { - Err(NotSupportedError::new()) +impl Drop for Window { + fn drop(&mut self) { + self.window_requests.closed.store(true, Ordering::Relaxed); + self.event_loop_awakener.ping(); } +} - #[inline] - pub fn inner_position(&self) -> Result, NotSupportedError> { - Err(NotSupportedError::new()) +#[cfg(feature = "rwh_06")] +impl rwh_06::HasWindowHandle for Window { + fn window_handle(&self) -> Result, rwh_06::HandleError> { + let raw = rwh_06::WaylandWindowHandle::new({ + let ptr = self.window.wl_surface().id().as_ptr(); + std::ptr::NonNull::new(ptr as *mut _).expect("wl_surface will never be null") + }); + + unsafe { Ok(rwh_06::WindowHandle::borrow_raw(raw.into())) } } +} - #[inline] - pub fn set_outer_position(&self, _: Position) { - // Not possible on Wayland. +#[cfg(feature = "rwh_06")] +impl rwh_06::HasDisplayHandle for Window { + fn display_handle(&self) -> Result, rwh_06::HandleError> { + let raw = rwh_06::WaylandDisplayHandle::new({ + let ptr = self.display.id().as_ptr(); + std::ptr::NonNull::new(ptr as *mut _).expect("wl_proxy should never be null") + }); + + unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw.into())) } } +} - #[inline] - pub fn inner_size(&self) -> PhysicalSize { - let window_state = self.window_state.lock().unwrap(); - let scale_factor = window_state.scale_factor(); - super::logical_to_physical_rounded(window_state.inner_size(), scale_factor) +impl CoreWindow for Window { + fn id(&self) -> CoreWindowId { + CoreWindowId(self.window_id) } - #[inline] - pub fn request_redraw(&self) { + fn request_redraw(&self) { // NOTE: try to not wake up the loop when the event was already scheduled and not yet // processed by the loop, because if at this point the value was `true` it could only // mean that the loop still haven't dispatched the value to the client and will do @@ -283,28 +297,50 @@ impl Window { } #[inline] - pub fn pre_present_notify(&self) { + fn title(&self) -> String { + self.window_state.lock().unwrap().title().to_owned() + } + + fn pre_present_notify(&self) { self.window_state.lock().unwrap().request_frame_callback(); } - #[inline] - pub fn outer_size(&self) -> PhysicalSize { + fn reset_dead_keys(&self) { + crate::platform_impl::common::xkb::reset_dead_keys() + } + + fn inner_position(&self) -> Result, NotSupportedError> { + Err(NotSupportedError::new()) + } + + fn outer_position(&self) -> Result, NotSupportedError> { + Err(NotSupportedError::new()) + } + + fn set_outer_position(&self, _position: Position) { + // Not possible. + } + + fn inner_size(&self) -> PhysicalSize { let window_state = self.window_state.lock().unwrap(); let scale_factor = window_state.scale_factor(); - super::logical_to_physical_rounded(window_state.outer_size(), scale_factor) + super::logical_to_physical_rounded(window_state.inner_size(), scale_factor) } - #[inline] - pub fn request_inner_size(&self, size: Size) -> Option> { + fn request_inner_size(&self, size: Size) -> Option> { let mut window_state = self.window_state.lock().unwrap(); let new_size = window_state.request_inner_size(size); self.request_redraw(); Some(new_size) } - /// Set the minimum inner size for the window. - #[inline] - pub fn set_min_inner_size(&self, min_size: Option) { + fn outer_size(&self) -> PhysicalSize { + let window_state = self.window_state.lock().unwrap(); + let scale_factor = window_state.scale_factor(); + super::logical_to_physical_rounded(window_state.outer_size(), scale_factor) + } + + fn set_min_inner_size(&self, min_size: Option) { let scale_factor = self.scale_factor(); let min_size = min_size.map(|size| size.to_logical(scale_factor)); self.window_state.lock().unwrap().set_min_inner_size(min_size); @@ -314,7 +350,7 @@ impl Window { /// Set the maximum inner size for the window. #[inline] - pub fn set_max_inner_size(&self, max_size: Option) { + fn set_max_inner_size(&self, max_size: Option) { let scale_factor = self.scale_factor(); let max_size = max_size.map(|size| size.to_logical(scale_factor)); self.window_state.lock().unwrap().set_max_inner_size(max_size); @@ -322,96 +358,53 @@ impl Window { self.request_redraw(); } - #[inline] - pub fn resize_increments(&self) -> Option> { + fn resize_increments(&self) -> Option> { None } - #[inline] - pub fn set_resize_increments(&self, _increments: Option) { + fn set_resize_increments(&self, _increments: Option) { warn!("`set_resize_increments` is not implemented for Wayland"); } - #[inline] - pub fn set_transparent(&self, transparent: bool) { - self.window_state.lock().unwrap().set_transparent(transparent); - } - - #[inline] - pub fn has_focus(&self) -> bool { - self.window_state.lock().unwrap().has_focus() + fn set_title(&self, title: &str) { + let new_title = title.to_string(); + self.window_state.lock().unwrap().set_title(new_title); } #[inline] - pub fn is_minimized(&self) -> Option { - // XXX clients don't know whether they are minimized or not. - None + fn set_transparent(&self, transparent: bool) { + self.window_state.lock().unwrap().set_transparent(transparent); } - #[inline] - pub fn show_window_menu(&self, position: Position) { - let scale_factor = self.scale_factor(); - let position = position.to_logical(scale_factor); - self.window_state.lock().unwrap().show_window_menu(position); + fn set_visible(&self, _visible: bool) { + // Not possible on Wayland. } - #[inline] - pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { - self.window_state.lock().unwrap().drag_resize_window(direction) + fn is_visible(&self) -> Option { + None } - #[inline] - pub fn set_resizable(&self, resizable: bool) { + fn set_resizable(&self, resizable: bool) { if self.window_state.lock().unwrap().set_resizable(resizable) { // NOTE: Requires commit to be applied. self.request_redraw(); } } - #[inline] - pub fn is_resizable(&self) -> bool { + fn is_resizable(&self) -> bool { self.window_state.lock().unwrap().resizable() } - #[inline] - pub fn set_enabled_buttons(&self, _buttons: WindowButtons) { + fn set_enabled_buttons(&self, _buttons: WindowButtons) { // TODO(kchibisov) v5 of the xdg_shell allows that. } - #[inline] - pub fn enabled_buttons(&self) -> WindowButtons { + fn enabled_buttons(&self) -> WindowButtons { // TODO(kchibisov) v5 of the xdg_shell allows that. WindowButtons::all() } - #[inline] - pub fn scale_factor(&self) -> f64 { - self.window_state.lock().unwrap().scale_factor() - } - - #[inline] - pub fn set_blur(&self, blur: bool) { - self.window_state.lock().unwrap().set_blur(blur); - } - - #[inline] - pub fn set_decorations(&self, decorate: bool) { - self.window_state.lock().unwrap().set_decorate(decorate) - } - - #[inline] - pub fn is_decorated(&self) -> bool { - self.window_state.lock().unwrap().is_decorated() - } - - #[inline] - pub fn set_window_level(&self, _level: WindowLevel) {} - - #[inline] - pub(crate) fn set_window_icon(&self, _window_icon: Option) {} - - #[inline] - pub fn set_minimized(&self, minimized: bool) { + fn set_minimized(&self, minimized: bool) { // You can't unminimize the window on Wayland. if !minimized { warn!("Unminimizing is ignored on Wayland."); @@ -421,8 +414,20 @@ impl Window { self.window.set_minimized(); } - #[inline] - pub fn is_maximized(&self) -> bool { + fn is_minimized(&self) -> Option { + // XXX clients don't know whether they are minimized or not. + None + } + + fn set_maximized(&self, maximized: bool) { + if maximized { + self.window.set_maximized() + } else { + self.window.unset_maximized() + } + } + + fn is_maximized(&self) -> bool { self.window_state .lock() .unwrap() @@ -432,17 +437,26 @@ impl Window { .unwrap_or_default() } - #[inline] - pub fn set_maximized(&self, maximized: bool) { - if maximized { - self.window.set_maximized() - } else { - self.window.unset_maximized() + fn set_fullscreen(&self, fullscreen: Option) { + match fullscreen { + Some(CoreFullscreen::Exclusive(_)) => { + warn!("`Fullscreen::Exclusive` is ignored on Wayland"); + }, + #[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))] + Some(CoreFullscreen::Borderless(monitor)) => { + let output = monitor.and_then(|monitor| match monitor.inner { + PlatformMonitorHandle::Wayland(monitor) => Some(monitor.proxy), + #[cfg(x11_platform)] + PlatformMonitorHandle::X(_) => None, + }); + + self.window.set_fullscreen(output.as_ref()) + }, + None => self.window.unset_fullscreen(), } } - #[inline] - pub(crate) fn fullscreen(&self) -> Option { + fn fullscreen(&self) -> Option { let is_fullscreen = self .window_state .lock() @@ -453,49 +467,71 @@ impl Window { .unwrap_or_default(); if is_fullscreen { - let current_monitor = self.current_monitor().map(PlatformMonitorHandle::Wayland); - Some(Fullscreen::Borderless(current_monitor)) + let current_monitor = self.current_monitor(); + Some(CoreFullscreen::Borderless(current_monitor)) } else { None } } #[inline] - pub(crate) fn set_fullscreen(&self, fullscreen: Option) { - match fullscreen { - Some(Fullscreen::Exclusive(_)) => { - warn!("`Fullscreen::Exclusive` is ignored on Wayland"); - }, - #[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))] - Some(Fullscreen::Borderless(monitor)) => { - let output = monitor.and_then(|monitor| match monitor { - PlatformMonitorHandle::Wayland(monitor) => Some(monitor.proxy), - #[cfg(x11_platform)] - PlatformMonitorHandle::X(_) => None, - }); + fn scale_factor(&self) -> f64 { + self.window_state.lock().unwrap().scale_factor() + } - self.window.set_fullscreen(output.as_ref()) - }, - None => self.window.unset_fullscreen(), + #[inline] + fn set_blur(&self, blur: bool) { + self.window_state.lock().unwrap().set_blur(blur); + } + + #[inline] + fn set_decorations(&self, decorate: bool) { + self.window_state.lock().unwrap().set_decorate(decorate) + } + + #[inline] + fn is_decorated(&self) -> bool { + self.window_state.lock().unwrap().is_decorated() + } + + fn set_window_level(&self, _level: WindowLevel) {} + + fn set_window_icon(&self, _window_icon: Option) {} + + #[inline] + fn set_ime_cursor_area(&self, position: Position, size: Size) { + let window_state = self.window_state.lock().unwrap(); + if window_state.ime_allowed() { + let scale_factor = window_state.scale_factor(); + let position = position.to_logical(scale_factor); + let size = size.to_logical(scale_factor); + window_state.set_ime_cursor_area(position, size); } } #[inline] - pub fn set_cursor(&self, cursor: Cursor) { - let window_state = &mut self.window_state.lock().unwrap(); + fn set_ime_allowed(&self, allowed: bool) { + let mut window_state = self.window_state.lock().unwrap(); - match cursor { - Cursor::Icon(icon) => window_state.set_cursor(icon), - Cursor::Custom(cursor) => window_state.set_custom_cursor(cursor), + if window_state.ime_allowed() != allowed && window_state.set_ime_allowed(allowed) { + let event = WindowEvent::Ime(if allowed { Ime::Enabled } else { Ime::Disabled }); + self.window_events_sink.lock().unwrap().push_window_event(event, self.window_id); + self.event_loop_awakener.ping(); } } #[inline] - pub fn set_cursor_visible(&self, visible: bool) { - self.window_state.lock().unwrap().set_cursor_visible(visible); + fn set_ime_purpose(&self, purpose: ImePurpose) { + self.window_state.lock().unwrap().set_ime_purpose(purpose); + } + + fn focus_window(&self) {} + + fn has_focus(&self) -> bool { + self.window_state.lock().unwrap().has_focus() } - pub fn request_user_attention(&self, request_type: Option) { + fn request_user_attention(&self, request_type: Option) { let xdg_activation = match self.xdg_activation.as_ref() { Some(xdg_activation) => xdg_activation, None => { @@ -521,29 +557,26 @@ impl Window { xdg_activation_token.commit(); } - pub fn request_activation_token(&self) -> Result { - let xdg_activation = match self.xdg_activation.as_ref() { - Some(xdg_activation) => xdg_activation, - None => return Err(NotSupportedError::new()), - }; + fn set_theme(&self, theme: Option) { + self.window_state.lock().unwrap().set_theme(theme) + } - let serial = AsyncRequestSerial::get(); + fn theme(&self) -> Option { + self.window_state.lock().unwrap().theme() + } - let data = XdgActivationTokenData::Obtain((self.window_id, serial)); - let xdg_activation_token = xdg_activation.get_activation_token(&self.queue_handle, data); - xdg_activation_token.set_surface(self.surface()); - xdg_activation_token.commit(); + fn set_content_protected(&self, _protected: bool) {} - Ok(serial) - } + fn set_cursor(&self, cursor: Cursor) { + let window_state = &mut self.window_state.lock().unwrap(); - #[inline] - pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { - self.window_state.lock().unwrap().set_cursor_grab(mode) + match cursor { + Cursor::Icon(icon) => window_state.set_cursor(icon), + Cursor::Custom(cursor) => window_state.set_custom_cursor(cursor), + } } - #[inline] - pub fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> { + fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> { let scale_factor = self.scale_factor(); let position = position.to_logical(scale_factor); self.window_state @@ -554,13 +587,29 @@ impl Window { .map(|_| self.request_redraw()) } - #[inline] - pub fn drag_window(&self) -> Result<(), ExternalError> { + fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { + self.window_state.lock().unwrap().set_cursor_grab(mode) + } + + fn set_cursor_visible(&self, visible: bool) { + self.window_state.lock().unwrap().set_cursor_visible(visible); + } + + fn drag_window(&self) -> Result<(), ExternalError> { self.window_state.lock().unwrap().drag_window() } - #[inline] - pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> { + fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { + self.window_state.lock().unwrap().drag_resize_window(direction) + } + + fn show_window_menu(&self, position: Position) { + let scale_factor = self.scale_factor(); + let position = position.to_logical(scale_factor); + self.window_state.lock().unwrap().show_window_menu(position); + } + + fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> { let surface = self.window.wl_surface(); if hittest { @@ -576,102 +625,42 @@ impl Window { } } - #[inline] - pub fn set_ime_cursor_area(&self, position: Position, size: Size) { - let window_state = self.window_state.lock().unwrap(); - if window_state.ime_allowed() { - let scale_factor = window_state.scale_factor(); - let position = position.to_logical(scale_factor); - let size = size.to_logical(scale_factor); - window_state.set_ime_cursor_area(position, size); - } - } - - #[inline] - pub fn set_ime_allowed(&self, allowed: bool) { - let mut window_state = self.window_state.lock().unwrap(); - - if window_state.ime_allowed() != allowed && window_state.set_ime_allowed(allowed) { - let event = WindowEvent::Ime(if allowed { Ime::Enabled } else { Ime::Disabled }); - self.window_events_sink.lock().unwrap().push_window_event(event, self.window_id); - self.event_loop_awakener.ping(); - } - } - - #[inline] - pub fn set_ime_purpose(&self, purpose: ImePurpose) { - self.window_state.lock().unwrap().set_ime_purpose(purpose); - } - - #[inline] - pub fn focus_window(&self) {} - - #[inline] - pub fn surface(&self) -> &WlSurface { - self.window.wl_surface() - } - - #[inline] - pub fn current_monitor(&self) -> Option { + fn current_monitor(&self) -> Option { let data = self.window.wl_surface().data::()?; - data.outputs().next().map(MonitorHandle::new) - } - - #[inline] - pub fn available_monitors(&self) -> Vec { - self.monitors.lock().unwrap().clone() - } - - #[inline] - pub fn primary_monitor(&self) -> Option { - // XXX there's no such concept on Wayland. + data.outputs() + .next() + .map(MonitorHandle::new) + .map(crate::platform_impl::MonitorHandle::Wayland) + .map(|inner| CoreMonitorHandle { inner }) + } + + fn available_monitors(&self) -> Box> { + Box::new( + self.monitors + .lock() + .unwrap() + .clone() + .into_iter() + .map(crate::platform_impl::MonitorHandle::Wayland) + .map(|inner| CoreMonitorHandle { inner }), + ) + } + + fn primary_monitor(&self) -> Option { + // NOTE: There's no such concept on Wayland. None } + /// Get the raw-window-handle v0.6 display handle. #[cfg(feature = "rwh_06")] - #[inline] - pub fn raw_window_handle_rwh_06(&self) -> Result { - Ok(rwh_06::WaylandWindowHandle::new({ - let ptr = self.window.wl_surface().id().as_ptr(); - std::ptr::NonNull::new(ptr as *mut _).expect("wl_surface will never be null") - }) - .into()) + fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle { + self } + /// Get the raw-window-handle v0.6 window handle. #[cfg(feature = "rwh_06")] - #[inline] - pub fn raw_display_handle_rwh_06( - &self, - ) -> Result { - Ok(rwh_06::WaylandDisplayHandle::new({ - let ptr = self.display.id().as_ptr(); - std::ptr::NonNull::new(ptr as *mut _).expect("wl_proxy should never be null") - }) - .into()) - } - - #[inline] - pub fn set_theme(&self, theme: Option) { - self.window_state.lock().unwrap().set_theme(theme) - } - - #[inline] - pub fn theme(&self) -> Option { - self.window_state.lock().unwrap().theme() - } - - pub fn set_content_protected(&self, _protected: bool) {} - - #[inline] - pub fn title(&self) -> String { - self.window_state.lock().unwrap().title().to_owned() - } -} - -impl Drop for Window { - fn drop(&mut self) { - self.window_requests.closed.store(true, Ordering::Relaxed); - self.event_loop_awakener.ping(); + fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle { + self } } diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index bab0bec427..b156d7d437 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -18,8 +18,7 @@ use tracing::warn; use x11rb::connection::RequestConnection; use x11rb::errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError}; use x11rb::protocol::xinput::{self, ConnectionExt as _}; -use x11rb::protocol::xkb; -use x11rb::protocol::xproto::{self, ConnectionExt as _}; +use x11rb::protocol::{xkb, xproto}; use x11rb::x11_utils::X11Error as LogicalError; use x11rb::xcb_ffi::ReplyOrIdError; @@ -33,9 +32,11 @@ use crate::event_loop::{ use crate::platform::pump_events::PumpStatus; use crate::platform_impl::common::xkb::Context; use crate::platform_impl::platform::{min_timeout, WindowId}; +use crate::platform_impl::x11::window::Window; use crate::platform_impl::{OsError, OwnedDisplayHandle, PlatformCustomCursor}; use crate::window::{ - CustomCursor as RootCustomCursor, CustomCursorSource, Theme, WindowAttributes, + CustomCursor as RootCustomCursor, CustomCursorSource, Theme, Window as CoreWindow, + WindowAttributes, }; mod activation; @@ -46,7 +47,7 @@ pub mod ffi; mod ime; mod monitor; mod util; -mod window; +pub(crate) mod window; mod xdisplay; mod xsettings; @@ -687,10 +688,8 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_window( &self, window_attributes: WindowAttributes, - ) -> Result { - let window = crate::platform_impl::x11::Window::new(self, window_attributes)?; - let window = crate::platform_impl::Window::X(window); - Ok(crate::window::Window { window }) + ) -> Result, RootOsError> { + Ok(Box::new(Window::new(self, window_attributes)?)) } fn create_custom_cursor( @@ -827,39 +826,6 @@ impl FingerId { } } -pub(crate) struct Window(Arc); - -impl Deref for Window { - type Target = UnownedWindow; - - #[inline] - fn deref(&self) -> &UnownedWindow { - &self.0 - } -} - -impl Window { - pub(crate) fn new( - event_loop: &ActiveEventLoop, - attribs: WindowAttributes, - ) -> Result { - let window = Arc::new(UnownedWindow::new(event_loop, attribs)?); - event_loop.windows.borrow_mut().insert(window.id(), Arc::downgrade(&window)); - Ok(Window(window)) - } -} - -impl Drop for Window { - fn drop(&mut self) { - let window = self.deref(); - let xconn = &window.xconn; - - if let Ok(c) = xconn.xcb_connection().destroy_window(window.id().0 as xproto::Window) { - c.ignore_error(); - } - } -} - #[derive(Clone)] pub struct EventLoopProxy { ping: Ping, diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index f001600fa2..8ace7dd0fa 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -1,6 +1,7 @@ use std::ffi::CString; use std::mem::replace; use std::num::NonZeroU32; +use std::ops::Deref; use std::os::raw::*; use std::path::Path; use std::sync::{Arc, Mutex, MutexGuard}; @@ -30,14 +31,312 @@ use crate::platform_impl::x11::{ xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender, X11Error, }; use crate::platform_impl::{ - Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformCustomCursor, + common, Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformCustomCursor, PlatformIcon, VideoModeHandle as PlatformVideoModeHandle, }; use crate::window::{ - CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes, - WindowButtons, WindowLevel, + CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as CoreWindow, + WindowAttributes, WindowButtons, WindowLevel, }; +pub(crate) struct Window(Arc); + +impl Deref for Window { + type Target = UnownedWindow; + + #[inline] + fn deref(&self) -> &UnownedWindow { + &self.0 + } +} + +impl Window { + pub(crate) fn new( + event_loop: &ActiveEventLoop, + attribs: WindowAttributes, + ) -> Result { + let window = Arc::new(UnownedWindow::new(event_loop, attribs)?); + event_loop.windows.borrow_mut().insert(window.id(), Arc::downgrade(&window)); + Ok(Window(window)) + } +} + +impl CoreWindow for Window { + fn id(&self) -> crate::window::WindowId { + crate::window::WindowId(self.0.id()) + } + + fn scale_factor(&self) -> f64 { + self.0.scale_factor() + } + + fn request_redraw(&self) { + self.0.request_redraw() + } + + fn pre_present_notify(&self) { + self.0.pre_present_notify() + } + + fn reset_dead_keys(&self) { + common::xkb::reset_dead_keys(); + } + + fn inner_position(&self) -> Result, NotSupportedError> { + self.0.inner_position() + } + + fn outer_position(&self) -> Result, NotSupportedError> { + self.0.outer_position() + } + + fn set_outer_position(&self, position: Position) { + self.0.set_outer_position(position) + } + + fn inner_size(&self) -> PhysicalSize { + self.0.inner_size() + } + + fn request_inner_size(&self, size: Size) -> Option> { + self.0.request_inner_size(size) + } + + fn outer_size(&self) -> PhysicalSize { + self.0.outer_size() + } + + fn set_min_inner_size(&self, min_size: Option) { + self.0.set_min_inner_size(min_size) + } + + fn set_max_inner_size(&self, max_size: Option) { + self.0.set_max_inner_size(max_size) + } + + fn resize_increments(&self) -> Option> { + self.0.resize_increments() + } + + fn set_resize_increments(&self, increments: Option) { + self.0.set_resize_increments(increments) + } + + fn set_title(&self, title: &str) { + self.0.set_title(title); + } + + fn set_transparent(&self, transparent: bool) { + self.0.set_transparent(transparent); + } + + fn set_blur(&self, blur: bool) { + self.0.set_blur(blur); + } + + fn set_visible(&self, visible: bool) { + self.0.set_visible(visible); + } + + fn is_visible(&self) -> Option { + self.0.is_visible() + } + + fn set_resizable(&self, resizable: bool) { + self.0.set_resizable(resizable); + } + + fn is_resizable(&self) -> bool { + self.0.is_resizable() + } + + fn set_enabled_buttons(&self, buttons: WindowButtons) { + self.0.set_enabled_buttons(buttons) + } + + fn enabled_buttons(&self) -> WindowButtons { + self.0.enabled_buttons() + } + + fn set_minimized(&self, minimized: bool) { + self.0.set_minimized(minimized) + } + + fn is_minimized(&self) -> Option { + self.0.is_minimized() + } + + fn set_maximized(&self, maximized: bool) { + self.0.set_maximized(maximized) + } + + fn is_maximized(&self) -> bool { + self.0.is_maximized() + } + + fn set_fullscreen(&self, fullscreen: Option) { + self.0.set_fullscreen(fullscreen.map(Into::into)) + } + + fn fullscreen(&self) -> Option { + self.0.fullscreen().map(Into::into) + } + + fn set_decorations(&self, decorations: bool) { + self.0.set_decorations(decorations); + } + + fn is_decorated(&self) -> bool { + self.0.is_decorated() + } + + fn set_window_level(&self, level: WindowLevel) { + self.0.set_window_level(level); + } + + fn set_window_icon(&self, window_icon: Option) { + self.0.set_window_icon(window_icon.map(|inner| inner.inner)) + } + + fn set_ime_cursor_area(&self, position: Position, size: Size) { + self.0.set_ime_cursor_area(position, size); + } + + fn set_ime_allowed(&self, allowed: bool) { + self.0.set_ime_allowed(allowed); + } + + fn set_ime_purpose(&self, purpose: ImePurpose) { + self.0.set_ime_purpose(purpose); + } + + fn focus_window(&self) { + self.0.focus_window(); + } + + fn has_focus(&self) -> bool { + self.0.has_focus() + } + + fn request_user_attention(&self, request_type: Option) { + self.0.request_user_attention(request_type); + } + + fn set_theme(&self, theme: Option) { + self.0.set_theme(theme); + } + + fn theme(&self) -> Option { + self.0.theme() + } + + fn set_content_protected(&self, protected: bool) { + self.0.set_content_protected(protected); + } + + fn title(&self) -> String { + self.0.title() + } + + fn set_cursor(&self, cursor: Cursor) { + self.0.set_cursor(cursor); + } + + fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> { + self.0.set_cursor_position(position) + } + + fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { + self.0.set_cursor_grab(mode) + } + + fn set_cursor_visible(&self, visible: bool) { + self.0.set_cursor_visible(visible); + } + + fn drag_window(&self) -> Result<(), ExternalError> { + self.0.drag_window() + } + + fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { + self.0.drag_resize_window(direction) + } + + fn show_window_menu(&self, position: Position) { + self.0.show_window_menu(position); + } + + fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> { + self.0.set_cursor_hittest(hittest) + } + + fn current_monitor(&self) -> Option { + self.0 + .current_monitor() + .map(crate::platform_impl::MonitorHandle::X) + .map(|inner| crate::monitor::MonitorHandle { inner }) + } + + fn available_monitors(&self) -> Box> { + Box::new( + self.0 + .available_monitors() + .into_iter() + .map(crate::platform_impl::MonitorHandle::X) + .map(|inner| crate::monitor::MonitorHandle { inner }), + ) + } + + fn primary_monitor(&self) -> Option { + self.0 + .primary_monitor() + .map(crate::platform_impl::MonitorHandle::X) + .map(|inner| crate::monitor::MonitorHandle { inner }) + } + + #[cfg(feature = "rwh_06")] + fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle { + self + } + + #[cfg(feature = "rwh_06")] + fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle { + self + } +} + +#[cfg(feature = "rwh_06")] +impl rwh_06::HasDisplayHandle for Window { + fn display_handle(&self) -> Result, rwh_06::HandleError> { + let raw = self.0.raw_display_handle_rwh_06()?; + unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) } + } +} + +#[cfg(feature = "rwh_06")] +impl rwh_06::HasWindowHandle for Window { + fn window_handle(&self) -> Result, rwh_06::HandleError> { + let raw = self.0.raw_window_handle_rwh_06()?; + unsafe { Ok(rwh_06::WindowHandle::borrow_raw(raw)) } + } +} + +impl Drop for Window { + fn drop(&mut self) { + let window = &self.0; + let xconn = &window.xconn; + + // Restore the video mode on drop. + if let Some(Fullscreen::Exclusive(_)) = window.fullscreen() { + window.set_fullscreen(None); + } + + if let Ok(c) = xconn.xcb_connection().destroy_window(window.id().0 as xproto::Window) { + c.ignore_error(); + } + } +} + #[derive(Debug)] pub struct SharedState { pub cursor_pos: Option<(f64, f64)>, diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index d0c77fcccc..7c6f43e67a 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -23,8 +23,10 @@ use crate::keyboard::{ Key, KeyCode, KeyLocation, ModifiersKeys, ModifiersState, NamedKey, NativeKey, NativeKeyCode, PhysicalKey, }; +use crate::platform_impl::Window; use crate::window::{ - CustomCursor as RootCustomCursor, CustomCursorSource, Theme, WindowId as RootWindowId, + CustomCursor as RootCustomCursor, CustomCursorSource, Theme, Window as CoreWindow, + WindowId as RootWindowId, }; fn convert_scancode(scancode: u8) -> (PhysicalKey, Option) { @@ -729,9 +731,8 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_window( &self, window_attributes: crate::window::WindowAttributes, - ) -> Result { - let window = crate::platform_impl::Window::new(self, window_attributes)?; - Ok(crate::window::Window { window }) + ) -> Result, crate::error::OsError> { + Ok(Box::new(Window::new(self, window_attributes)?)) } fn create_custom_cursor( diff --git a/src/platform_impl/orbital/window.rs b/src/platform_impl/orbital/window.rs index 3172c6cf87..3530281dea 100644 --- a/src/platform_impl/orbital/window.rs +++ b/src/platform_impl/orbital/window.rs @@ -6,9 +6,9 @@ use super::{ }; use crate::cursor::Cursor; use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; -use crate::platform_impl::Fullscreen; -use crate::window::ImePurpose; -use crate::{error, window}; +use crate::error; +use crate::monitor::MonitorHandle as CoreMonitorHandle; +use crate::window::{self, Fullscreen, ImePurpose, Window as CoreWindow, WindowId as CoreWindowId}; // These values match the values uses in the `window_new` function in orbital: // https://gitlab.redox-os.org/redox-os/orbital/-/blob/master/src/scheme.rs @@ -125,14 +125,6 @@ impl Window { }) } - pub(crate) fn maybe_queue_on_main(&self, f: impl FnOnce(&Self) + Send + 'static) { - f(self) - } - - pub(crate) fn maybe_wait_on_main(&self, f: impl FnOnce(&Self) -> R + Send) -> R { - f(self) - } - fn get_flag(&self, flag: char) -> Result { let mut buf: [u8; 4096] = [0; 4096]; let path = self @@ -150,36 +142,51 @@ impl Window { Ok(()) } + #[cfg(feature = "rwh_06")] #[inline] - pub fn id(&self) -> WindowId { - WindowId { fd: self.window_socket.fd as u64 } + fn raw_window_handle_rwh_06(&self) -> Result { + let handle = rwh_06::OrbitalWindowHandle::new({ + let window = self.window_socket.fd as *mut _; + std::ptr::NonNull::new(window).expect("orbital fd should never be null") + }); + Ok(rwh_06::RawWindowHandle::Orbital(handle)) } + #[cfg(feature = "rwh_06")] #[inline] - pub fn primary_monitor(&self) -> Option { - Some(MonitorHandle) + fn raw_display_handle_rwh_06(&self) -> Result { + Ok(rwh_06::RawDisplayHandle::Orbital(rwh_06::OrbitalDisplayHandle::new())) + } +} + +impl CoreWindow for Window { + fn id(&self) -> CoreWindowId { + CoreWindowId(WindowId { fd: self.window_socket.fd as u64 }) + } + + #[inline] + fn primary_monitor(&self) -> Option { + Some(CoreMonitorHandle { inner: MonitorHandle }) } #[inline] - pub fn available_monitors(&self) -> VecDeque { - let mut v = VecDeque::with_capacity(1); - v.push_back(MonitorHandle); - v + fn available_monitors(&self) -> Box> { + Box::new(vec![CoreMonitorHandle { inner: MonitorHandle }].into_iter()) } #[inline] - pub fn current_monitor(&self) -> Option { - Some(MonitorHandle) + fn current_monitor(&self) -> Option { + Some(CoreMonitorHandle { inner: MonitorHandle }) } #[inline] - pub fn scale_factor(&self) -> f64 { + fn scale_factor(&self) -> f64 { MonitorHandle.scale_factor() } #[inline] - pub fn request_redraw(&self) { - let window_id = self.id(); + fn request_redraw(&self) { + let window_id = self.id().0; let mut redraws = self.redraws.lock().unwrap(); if !redraws.contains(&window_id) { redraws.push_back(window_id); @@ -189,15 +196,15 @@ impl Window { } #[inline] - pub fn pre_present_notify(&self) {} + fn pre_present_notify(&self) {} #[inline] - pub fn reset_dead_keys(&self) { + fn reset_dead_keys(&self) { // TODO? } #[inline] - pub fn inner_position(&self) -> Result, error::NotSupportedError> { + fn inner_position(&self) -> Result, error::NotSupportedError> { let mut buf: [u8; 4096] = [0; 4096]; let path = self.window_socket.fpath(&mut buf).expect("failed to read properties"); let properties = WindowProperties::new(path); @@ -205,20 +212,20 @@ impl Window { } #[inline] - pub fn outer_position(&self) -> Result, error::NotSupportedError> { + fn outer_position(&self) -> Result, error::NotSupportedError> { // TODO: adjust for window decorations self.inner_position() } #[inline] - pub fn set_outer_position(&self, position: Position) { + fn set_outer_position(&self, position: Position) { // TODO: adjust for window decorations let (x, y): (i32, i32) = position.to_physical::(self.scale_factor()).into(); self.window_socket.write(format!("P,{x},{y}").as_bytes()).expect("failed to set position"); } #[inline] - pub fn inner_size(&self) -> PhysicalSize { + fn inner_size(&self) -> PhysicalSize { let mut buf: [u8; 4096] = [0; 4096]; let path = self.window_socket.fpath(&mut buf).expect("failed to read properties"); let properties = WindowProperties::new(path); @@ -226,26 +233,26 @@ impl Window { } #[inline] - pub fn request_inner_size(&self, size: Size) -> Option> { + fn request_inner_size(&self, size: Size) -> Option> { let (w, h): (u32, u32) = size.to_physical::(self.scale_factor()).into(); self.window_socket.write(format!("S,{w},{h}").as_bytes()).expect("failed to set size"); None } #[inline] - pub fn outer_size(&self) -> PhysicalSize { + fn outer_size(&self) -> PhysicalSize { // TODO: adjust for window decorations self.inner_size() } #[inline] - pub fn set_min_inner_size(&self, _: Option) {} + fn set_min_inner_size(&self, _: Option) {} #[inline] - pub fn set_max_inner_size(&self, _: Option) {} + fn set_max_inner_size(&self, _: Option) {} #[inline] - pub fn title(&self) -> String { + fn title(&self) -> String { let mut buf: [u8; 4096] = [0; 4096]; let path = self.window_socket.fpath(&mut buf).expect("failed to read properties"); let properties = WindowProperties::new(path); @@ -253,84 +260,82 @@ impl Window { } #[inline] - pub fn set_title(&self, title: &str) { + fn set_title(&self, title: &str) { self.window_socket.write(format!("T,{title}").as_bytes()).expect("failed to set title"); } #[inline] - pub fn set_transparent(&self, transparent: bool) { + fn set_transparent(&self, transparent: bool) { let _ = self.set_flag(ORBITAL_FLAG_TRANSPARENT, transparent); } #[inline] - pub fn set_blur(&self, _blur: bool) {} + fn set_blur(&self, _blur: bool) {} #[inline] - pub fn set_visible(&self, visible: bool) { + fn set_visible(&self, visible: bool) { let _ = self.set_flag(ORBITAL_FLAG_HIDDEN, !visible); } #[inline] - pub fn is_visible(&self) -> Option { + fn is_visible(&self) -> Option { Some(!self.get_flag(ORBITAL_FLAG_HIDDEN).unwrap_or(false)) } #[inline] - pub fn resize_increments(&self) -> Option> { + fn resize_increments(&self) -> Option> { None } #[inline] - pub fn set_resize_increments(&self, _increments: Option) {} + fn set_resize_increments(&self, _increments: Option) {} #[inline] - pub fn set_resizable(&self, resizeable: bool) { + fn set_resizable(&self, resizeable: bool) { let _ = self.set_flag(ORBITAL_FLAG_RESIZABLE, resizeable); } #[inline] - pub fn is_resizable(&self) -> bool { + fn is_resizable(&self) -> bool { self.get_flag(ORBITAL_FLAG_RESIZABLE).unwrap_or(false) } #[inline] - pub fn set_minimized(&self, _minimized: bool) {} + fn set_minimized(&self, _minimized: bool) {} #[inline] - pub fn is_minimized(&self) -> Option { + fn is_minimized(&self) -> Option { None } #[inline] - pub fn set_maximized(&self, maximized: bool) { + fn set_maximized(&self, maximized: bool) { let _ = self.set_flag(ORBITAL_FLAG_MAXIMIZED, maximized); } #[inline] - pub fn is_maximized(&self) -> bool { + fn is_maximized(&self) -> bool { self.get_flag(ORBITAL_FLAG_MAXIMIZED).unwrap_or(false) } - #[inline] - pub(crate) fn set_fullscreen(&self, _monitor: Option) {} + fn set_fullscreen(&self, _monitor: Option) {} - #[inline] - pub(crate) fn fullscreen(&self) -> Option { + fn fullscreen(&self) -> Option { None } #[inline] - pub fn set_decorations(&self, decorations: bool) { + fn set_decorations(&self, decorations: bool) { let _ = self.set_flag(ORBITAL_FLAG_BORDERLESS, !decorations); } #[inline] - pub fn is_decorated(&self) -> bool { + fn is_decorated(&self) -> bool { !self.get_flag(ORBITAL_FLAG_BORDERLESS).unwrap_or(false) } #[inline] - pub fn set_window_level(&self, level: window::WindowLevel) { + fn set_window_level(&self, level: window::WindowLevel) { match level { window::WindowLevel::AlwaysOnBottom => { let _ = self.set_flag(ORBITAL_FLAG_BACK, true); @@ -346,36 +351,33 @@ impl Window { } #[inline] - pub fn set_window_icon(&self, _window_icon: Option) {} + fn set_window_icon(&self, _window_icon: Option) {} #[inline] - pub fn set_ime_cursor_area(&self, _position: Position, _size: Size) {} + fn set_ime_cursor_area(&self, _position: Position, _size: Size) {} #[inline] - pub fn set_ime_allowed(&self, _allowed: bool) {} + fn set_ime_allowed(&self, _allowed: bool) {} #[inline] - pub fn set_ime_purpose(&self, _purpose: ImePurpose) {} + fn set_ime_purpose(&self, _purpose: ImePurpose) {} #[inline] - pub fn focus_window(&self) {} + fn focus_window(&self) {} #[inline] - pub fn request_user_attention(&self, _request_type: Option) {} + fn request_user_attention(&self, _request_type: Option) {} #[inline] - pub fn set_cursor(&self, _: Cursor) {} + fn set_cursor(&self, _: Cursor) {} #[inline] - pub fn set_cursor_position(&self, _: Position) -> Result<(), error::ExternalError> { + fn set_cursor_position(&self, _: Position) -> Result<(), error::ExternalError> { Err(error::ExternalError::NotSupported(error::NotSupportedError::new())) } #[inline] - pub fn set_cursor_grab( - &self, - mode: window::CursorGrabMode, - ) -> Result<(), error::ExternalError> { + fn set_cursor_grab(&self, mode: window::CursorGrabMode) -> Result<(), error::ExternalError> { let (grab, relative) = match mode { window::CursorGrabMode::None => (false, false), window::CursorGrabMode::Confined => (true, false), @@ -391,12 +393,12 @@ impl Window { } #[inline] - pub fn set_cursor_visible(&self, visible: bool) { + fn set_cursor_visible(&self, visible: bool) { let _ = self.window_socket.write(format!("M,C,{}", if visible { 1 } else { 0 }).as_bytes()); } #[inline] - pub fn drag_window(&self) -> Result<(), error::ExternalError> { + fn drag_window(&self) -> Result<(), error::ExternalError> { self.window_socket .write(b"D") .map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?; @@ -404,7 +406,7 @@ impl Window { } #[inline] - pub fn drag_resize_window( + fn drag_resize_window( &self, direction: window::ResizeDirection, ) -> Result<(), error::ExternalError> { @@ -425,60 +427,68 @@ impl Window { } #[inline] - pub fn show_window_menu(&self, _position: Position) {} + fn show_window_menu(&self, _position: Position) {} #[inline] - pub fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), error::ExternalError> { + fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), error::ExternalError> { Err(error::ExternalError::NotSupported(error::NotSupportedError::new())) } - #[cfg(feature = "rwh_06")] #[inline] - pub fn raw_window_handle_rwh_06(&self) -> Result { - let handle = rwh_06::OrbitalWindowHandle::new({ - let window = self.window_socket.fd as *mut _; - std::ptr::NonNull::new(window).expect("orbital fd should never be null") - }); - Ok(rwh_06::RawWindowHandle::Orbital(handle)) - } - - #[cfg(feature = "rwh_06")] - #[inline] - pub fn raw_display_handle_rwh_06( - &self, - ) -> Result { - Ok(rwh_06::RawDisplayHandle::Orbital(rwh_06::OrbitalDisplayHandle::new())) - } - - #[inline] - pub fn set_enabled_buttons(&self, _buttons: window::WindowButtons) {} + fn set_enabled_buttons(&self, _buttons: window::WindowButtons) {} #[inline] - pub fn enabled_buttons(&self) -> window::WindowButtons { + fn enabled_buttons(&self) -> window::WindowButtons { window::WindowButtons::all() } #[inline] - pub fn theme(&self) -> Option { + fn theme(&self) -> Option { None } #[inline] - pub fn has_focus(&self) -> bool { + fn has_focus(&self) -> bool { false } #[inline] - pub fn set_theme(&self, _theme: Option) {} + fn set_theme(&self, _theme: Option) {} - pub fn set_content_protected(&self, _protected: bool) {} + fn set_content_protected(&self, _protected: bool) {} + + #[cfg(feature = "rwh_06")] + fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle { + self + } + + #[cfg(feature = "rwh_06")] + fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle { + self + } +} + +#[cfg(feature = "rwh_06")] +impl rwh_06::HasWindowHandle for Window { + fn window_handle(&self) -> Result, rwh_06::HandleError> { + let raw = self.raw_window_handle_rwh_06()?; + unsafe { Ok(rwh_06::WindowHandle::borrow_raw(raw)) } + } +} + +#[cfg(feature = "rwh_06")] +impl rwh_06::HasDisplayHandle for Window { + fn display_handle(&self) -> Result, rwh_06::HandleError> { + let raw = self.raw_display_handle_rwh_06()?; + unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) } + } } impl Drop for Window { fn drop(&mut self) { { let mut destroys = self.destroys.lock().unwrap(); - destroys.push_back(self.id()); + destroys.push_back(self.id().0); } self.wake_socket.wake().unwrap(); diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 878ab03e31..3239f201df 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -27,8 +27,7 @@ use crate::platform_impl::platform::cursor::CustomCursor; use crate::platform_impl::platform::r#async::Waker; use crate::platform_impl::Window; use crate::window::{ - CustomCursor as RootCustomCursor, CustomCursorSource, Theme, Window as RootWindow, - WindowId as RootWindowId, + CustomCursor as RootCustomCursor, CustomCursorSource, Theme, WindowId as RootWindowId, }; #[derive(Default)] @@ -632,9 +631,9 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_window( &self, window_attributes: crate::window::WindowAttributes, - ) -> Result { + ) -> Result, crate::error::OsError> { let window = Window::new(self, window_attributes)?; - Ok(RootWindow { window }) + Ok(Box::new(window)) } fn create_custom_cursor( diff --git a/src/platform_impl/web/mod.rs b/src/platform_impl/web/mod.rs index d6a8dd77d1..d429dd07a9 100644 --- a/src/platform_impl/web/mod.rs +++ b/src/platform_impl/web/mod.rs @@ -51,4 +51,3 @@ pub(crate) use self::monitor::{ use self::web_sys as backend; pub use self::window::{PlatformSpecificWindowAttributes, Window, WindowId}; pub(crate) use crate::icon::NoIcon as PlatformIcon; -pub(crate) use crate::platform_impl::Fullscreen; diff --git a/src/platform_impl/web/monitor.rs b/src/platform_impl/web/monitor.rs index 8f11507f96..644a8749c3 100644 --- a/src/platform_impl/web/monitor.rs +++ b/src/platform_impl/web/monitor.rs @@ -29,6 +29,7 @@ use super::main_thread::MainThreadMarker; use super::r#async::{Dispatcher, Notified, Notifier}; use super::web_sys::{Engine, EventListenerHandle}; use crate::dpi::{PhysicalPosition, PhysicalSize}; +use crate::monitor::MonitorHandle as RootMonitorHandle; use crate::platform::web::{ MonitorPermissionError, Orientation, OrientationData, OrientationLock, OrientationLockError, }; @@ -188,6 +189,12 @@ impl PartialOrd for MonitorHandle { } } +impl From for RootMonitorHandle { + fn from(inner: MonitorHandle) -> Self { + RootMonitorHandle { inner } + } +} + #[derive(Debug)] pub enum OrientationLockFuture { Future(Notified>), diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index 77931aa5b8..c3827291d2 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -5,15 +5,17 @@ use std::sync::Arc; use web_sys::HtmlCanvasElement; use super::main_thread::{MainThreadMarker, MainThreadSafe}; -use super::monitor::{MonitorHandle, MonitorHandler}; +use super::monitor::MonitorHandler; use super::r#async::Dispatcher; -use super::{backend, lock, ActiveEventLoop, Fullscreen}; +use super::{backend, lock, ActiveEventLoop}; use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{ExternalError, NotSupportedError, OsError as RootOE}; use crate::icon::Icon; +use crate::monitor::MonitorHandle as RootMonitorHandle; use crate::window::{ - Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, - WindowAttributes, WindowButtons, WindowId as RootWI, WindowLevel, + Cursor, CursorGrabMode, Fullscreen as RootFullscreen, ImePurpose, ResizeDirection, Theme, + UserAttentionType, Window as RootWindow, WindowAttributes, WindowButtons, WindowId as RootWI, + WindowLevel, }; pub struct Window { @@ -65,14 +67,6 @@ impl Window { Ok(Window { inner: dispatcher }) } - pub(crate) fn maybe_queue_on_main(&self, f: impl FnOnce(&Inner) + Send + 'static) { - self.inner.dispatch(f) - } - - pub(crate) fn maybe_wait_on_main(&self, f: impl FnOnce(&Inner) -> R + Send) -> R { - self.inner.queue(f) - } - pub fn canvas(&self) -> Option> { MainThreadMarker::new() .map(|main_thread| Ref::map(self.inner.value(main_thread), |inner| inner.canvas.raw())) @@ -91,333 +85,337 @@ impl Window { lock::is_cursor_lock_raw(inner.canvas.navigator(), inner.canvas.document()) }) } - - #[cfg(feature = "rwh_06")] - #[inline] - pub fn raw_window_handle_rwh_06(&self) -> Result { - MainThreadMarker::new() - .map(|main_thread| { - let inner = self.inner.value(main_thread); - // SAFETY: This will only work if the reference to `HtmlCanvasElement` stays valid. - let canvas: &wasm_bindgen::JsValue = inner.canvas.raw(); - let window_handle = - rwh_06::WebCanvasWindowHandle::new(std::ptr::NonNull::from(canvas).cast()); - rwh_06::RawWindowHandle::WebCanvas(window_handle) - }) - .ok_or(rwh_06::HandleError::Unavailable) - } - - #[cfg(feature = "rwh_06")] - #[inline] - pub(crate) fn raw_display_handle_rwh_06( - &self, - ) -> Result { - Ok(rwh_06::RawDisplayHandle::Web(rwh_06::WebDisplayHandle::new())) - } } -impl Inner { - pub fn set_title(&self, title: &str) { - self.canvas.set_attribute("alt", title) +impl RootWindow for Window { + fn id(&self) -> RootWI { + RootWI(self.inner.queue(|inner| inner.id)) } - pub fn set_transparent(&self, _transparent: bool) {} - - pub fn set_blur(&self, _blur: bool) {} - - pub fn set_visible(&self, _visible: bool) { - // Intentionally a no-op + fn scale_factor(&self) -> f64 { + self.inner.queue(Inner::scale_factor) } - #[inline] - pub fn is_visible(&self) -> Option { - None + fn request_redraw(&self) { + self.inner.dispatch(|inner| inner.canvas.request_animation_frame()) } - pub fn request_redraw(&self) { - self.canvas.request_animation_frame(); - } + fn pre_present_notify(&self) {} - pub fn pre_present_notify(&self) {} - - pub fn outer_position(&self) -> Result, NotSupportedError> { - Ok(self.canvas.position().to_physical(self.scale_factor())) + fn reset_dead_keys(&self) { + // Not supported } - pub fn inner_position(&self) -> Result, NotSupportedError> { + fn inner_position(&self) -> Result, NotSupportedError> { // Note: the canvas element has no window decorations, so this is equal to `outer_position`. self.outer_position() } - pub fn set_outer_position(&self, position: Position) { - let position = position.to_logical::(self.scale_factor()); - - backend::set_canvas_position( - self.canvas.document(), - self.canvas.raw(), - self.canvas.style(), - position, - ) + fn outer_position(&self) -> Result, NotSupportedError> { + self.inner.queue(|inner| Ok(inner.canvas.position().to_physical(inner.scale_factor()))) } - #[inline] - pub fn inner_size(&self) -> PhysicalSize { - self.canvas.inner_size() + fn set_outer_position(&self, position: Position) { + self.inner.dispatch(move |inner| { + let position = position.to_logical::(inner.scale_factor()); + backend::set_canvas_position( + inner.canvas.document(), + inner.canvas.raw(), + inner.canvas.style(), + position, + ) + }) } - #[inline] - pub fn outer_size(&self) -> PhysicalSize { - // Note: the canvas element has no window decorations, so this is equal to `inner_size`. - self.inner_size() + fn inner_size(&self) -> PhysicalSize { + self.inner.queue(|inner| inner.canvas.inner_size()) } - #[inline] - pub fn request_inner_size(&self, size: Size) -> Option> { - let size = size.to_logical(self.scale_factor()); - backend::set_canvas_size( - self.canvas.document(), - self.canvas.raw(), - self.canvas.style(), - size, - ); - None + fn request_inner_size(&self, size: Size) -> Option> { + self.inner.queue(|inner| { + let size = size.to_logical(self.scale_factor()); + backend::set_canvas_size( + inner.canvas.document(), + inner.canvas.raw(), + inner.canvas.style(), + size, + ); + None + }) } - #[inline] - pub fn set_min_inner_size(&self, dimensions: Option) { - let dimensions = dimensions.map(|dimensions| dimensions.to_logical(self.scale_factor())); - backend::set_canvas_min_size( - self.canvas.document(), - self.canvas.raw(), - self.canvas.style(), - dimensions, - ) + fn outer_size(&self) -> PhysicalSize { + // Note: the canvas element has no window decorations, so this is equal to `inner_size`. + self.inner_size() } - #[inline] - pub fn set_max_inner_size(&self, dimensions: Option) { - let dimensions = dimensions.map(|dimensions| dimensions.to_logical(self.scale_factor())); - backend::set_canvas_max_size( - self.canvas.document(), - self.canvas.raw(), - self.canvas.style(), - dimensions, - ) + fn set_min_inner_size(&self, min_size: Option) { + self.inner.dispatch(move |inner| { + let dimensions = min_size.map(|min_size| min_size.to_logical(inner.scale_factor())); + backend::set_canvas_min_size( + inner.canvas.document(), + inner.canvas.raw(), + inner.canvas.style(), + dimensions, + ) + }) } - #[inline] - pub fn resize_increments(&self) -> Option> { - None + fn set_max_inner_size(&self, max_size: Option) { + self.inner.dispatch(move |inner| { + let dimensions = max_size.map(|dimensions| dimensions.to_logical(inner.scale_factor())); + backend::set_canvas_max_size( + inner.canvas.document(), + inner.canvas.raw(), + inner.canvas.style(), + dimensions, + ) + }) } - #[inline] - pub fn set_resize_increments(&self, _increments: Option) { - // Intentionally a no-op: users can't resize canvas elements + fn resize_increments(&self) -> Option> { + None } - #[inline] - pub fn set_resizable(&self, _resizable: bool) { + fn set_resize_increments(&self, _: Option) { // Intentionally a no-op: users can't resize canvas elements } - pub fn is_resizable(&self) -> bool { - true + fn set_title(&self, title: &str) { + self.inner.queue(|inner| inner.canvas.set_attribute("alt", title)) } - #[inline] - pub fn set_enabled_buttons(&self, _buttons: WindowButtons) {} + fn set_transparent(&self, _: bool) {} - #[inline] - pub fn enabled_buttons(&self) -> WindowButtons { - WindowButtons::all() - } - - #[inline] - pub fn scale_factor(&self) -> f64 { - super::backend::scale_factor(&self.window) - } + fn set_blur(&self, _: bool) {} - #[inline] - pub fn set_cursor(&self, cursor: Cursor) { - self.canvas.cursor.set_cursor(cursor) - } - - #[inline] - pub fn set_cursor_position(&self, _position: Position) -> Result<(), ExternalError> { - Err(ExternalError::NotSupported(NotSupportedError::new())) - } - - #[inline] - pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { - match mode { - CursorGrabMode::None => self.canvas.document().exit_pointer_lock(), - CursorGrabMode::Locked => lock::request_pointer_lock( - self.canvas.navigator(), - self.canvas.document(), - self.canvas.raw(), - ), - CursorGrabMode::Confined => { - return Err(ExternalError::NotSupported(NotSupportedError::new())) - }, - } - - Ok(()) + fn set_visible(&self, _: bool) { + // Intentionally a no-op } - #[inline] - pub fn set_cursor_visible(&self, visible: bool) { - self.canvas.cursor.set_cursor_visible(visible) + fn is_visible(&self) -> Option { + None } - #[inline] - pub fn drag_window(&self) -> Result<(), ExternalError> { - Err(ExternalError::NotSupported(NotSupportedError::new())) + fn set_resizable(&self, _: bool) { + // Intentionally a no-op: users can't resize canvas elements } - #[inline] - pub fn drag_resize_window(&self, _direction: ResizeDirection) -> Result<(), ExternalError> { - Err(ExternalError::NotSupported(NotSupportedError::new())) + fn is_resizable(&self) -> bool { + true } - #[inline] - pub fn show_window_menu(&self, _position: Position) {} + fn set_enabled_buttons(&self, _: WindowButtons) {} - #[inline] - pub fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), ExternalError> { - Err(ExternalError::NotSupported(NotSupportedError::new())) + fn enabled_buttons(&self) -> WindowButtons { + WindowButtons::all() } - #[inline] - pub fn set_minimized(&self, _minimized: bool) { + fn set_minimized(&self, _: bool) { // Intentionally a no-op, as canvases cannot be 'minimized' } - #[inline] - pub fn is_minimized(&self) -> Option { + fn is_minimized(&self) -> Option { // Canvas cannot be 'minimized' Some(false) } - #[inline] - pub fn set_maximized(&self, _maximized: bool) { + fn set_maximized(&self, _: bool) { // Intentionally a no-op, as canvases cannot be 'maximized' } - #[inline] - pub fn is_maximized(&self) -> bool { + fn is_maximized(&self) -> bool { // Canvas cannot be 'maximized' false } - #[inline] - pub(crate) fn fullscreen(&self) -> Option { - if self.canvas.is_fullscreen() { - Some(Fullscreen::Borderless(Some(self.monitor.current_monitor()))) - } else { - None - } + fn set_fullscreen(&self, fullscreen: Option) { + self.inner.dispatch(move |inner| { + if let Some(fullscreen) = fullscreen { + inner.canvas.request_fullscreen(fullscreen.into()); + } else { + inner.canvas.exit_fullscreen() + } + }) } - #[inline] - pub(crate) fn set_fullscreen(&self, fullscreen: Option) { - if let Some(fullscreen) = fullscreen { - self.canvas.request_fullscreen(fullscreen); - } else { - self.canvas.exit_fullscreen() - } + fn fullscreen(&self) -> Option { + self.inner.queue(|inner| { + if inner.canvas.is_fullscreen() { + Some(RootFullscreen::Borderless(None)) + } else { + None + } + }) } - #[inline] - pub fn set_decorations(&self, _decorations: bool) { + fn set_decorations(&self, _: bool) { // Intentionally a no-op, no canvas decorations } - pub fn is_decorated(&self) -> bool { + fn is_decorated(&self) -> bool { true } - #[inline] - pub fn set_window_level(&self, _level: WindowLevel) { + fn set_window_level(&self, _: WindowLevel) { // Intentionally a no-op, no window ordering } - #[inline] - pub fn set_window_icon(&self, _window_icon: Option) { + fn set_window_icon(&self, _: Option) { // Currently an intentional no-op } - #[inline] - pub fn set_ime_cursor_area(&self, _position: Position, _size: Size) { + fn set_ime_cursor_area(&self, _: Position, _: Size) { // Currently not implemented } - #[inline] - pub fn set_ime_allowed(&self, _allowed: bool) { + fn set_ime_allowed(&self, _: bool) { // Currently not implemented } - #[inline] - pub fn set_ime_purpose(&self, _purpose: ImePurpose) { + fn set_ime_purpose(&self, _: ImePurpose) { // Currently not implemented } - #[inline] - pub fn focus_window(&self) { - let _ = self.canvas.raw().focus(); + fn focus_window(&self) { + self.inner.dispatch(|inner| { + let _ = inner.canvas.raw().focus(); + }) } - #[inline] - pub fn request_user_attention(&self, _request_type: Option) { - // Currently an intentional no-op + fn has_focus(&self) -> bool { + self.inner.queue(|inner| inner.canvas.has_focus.get()) } - #[inline] - pub fn current_monitor(&self) -> Option { - Some(self.monitor.current_monitor()) + fn request_user_attention(&self, _: Option) { + // Currently an intentional no-op } - #[inline] - pub fn available_monitors(&self) -> Vec { - self.monitor.available_monitors() + fn set_theme(&self, _: Option) {} + + fn theme(&self) -> Option { + self.inner.queue(|inner| { + backend::is_dark_mode(&inner.window).map(|is_dark_mode| { + if is_dark_mode { + Theme::Dark + } else { + Theme::Light + } + }) + }) } - #[inline] - pub fn primary_monitor(&self) -> Option { - self.monitor.primary_monitor() + fn set_content_protected(&self, _: bool) {} + + fn title(&self) -> String { + String::new() } - #[inline] - pub fn id(&self) -> WindowId { - self.id + fn set_cursor(&self, cursor: Cursor) { + self.inner.dispatch(move |inner| inner.canvas.cursor.set_cursor(cursor)) } - #[inline] - pub fn set_theme(&self, _theme: Option) {} + fn set_cursor_position(&self, _: Position) -> Result<(), ExternalError> { + Err(ExternalError::NotSupported(NotSupportedError::new())) + } - #[inline] - pub fn theme(&self) -> Option { - backend::is_dark_mode(&self.window).map(|is_dark_mode| { - if is_dark_mode { - Theme::Dark - } else { - Theme::Light + fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { + self.inner.queue(|inner| { + match mode { + CursorGrabMode::None => inner.canvas.document().exit_pointer_lock(), + CursorGrabMode::Locked => lock::request_pointer_lock( + inner.canvas.navigator(), + inner.canvas.document(), + inner.canvas.raw(), + ), + CursorGrabMode::Confined => { + return Err(ExternalError::NotSupported(NotSupportedError::new())) + }, } + + Ok(()) }) } - pub fn set_content_protected(&self, _protected: bool) {} + fn set_cursor_visible(&self, visible: bool) { + self.inner.dispatch(move |inner| inner.canvas.cursor.set_cursor_visible(visible)) + } - #[inline] - pub fn has_focus(&self) -> bool { - self.canvas.has_focus.get() + fn drag_window(&self) -> Result<(), ExternalError> { + Err(ExternalError::NotSupported(NotSupportedError::new())) } - pub fn title(&self) -> String { - String::new() + fn drag_resize_window(&self, _: ResizeDirection) -> Result<(), ExternalError> { + Err(ExternalError::NotSupported(NotSupportedError::new())) } - pub fn reset_dead_keys(&self) { - // Not supported + fn show_window_menu(&self, _: Position) {} + + fn set_cursor_hittest(&self, _: bool) -> Result<(), ExternalError> { + Err(ExternalError::NotSupported(NotSupportedError::new())) + } + + fn current_monitor(&self) -> Option { + Some(self.inner.queue(|inner| inner.monitor.current_monitor()).into()) + } + + fn available_monitors(&self) -> Box> { + Box::new( + self.inner + .queue(|inner| inner.monitor.available_monitors()) + .into_iter() + .map(RootMonitorHandle::from), + ) + } + + fn primary_monitor(&self) -> Option { + self.inner.queue(|inner| inner.monitor.primary_monitor()).map(RootMonitorHandle::from) + } + + #[cfg(feature = "rwh_06")] + fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle { + self + } + + #[cfg(feature = "rwh_06")] + fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle { + self + } +} + +#[cfg(feature = "rwh_06")] +impl rwh_06::HasWindowHandle for Window { + fn window_handle(&self) -> Result, rwh_06::HandleError> { + MainThreadMarker::new() + .map(|main_thread| { + let inner = self.inner.value(main_thread); + // SAFETY: This will only work if the reference to `HtmlCanvasElement` stays valid. + let canvas: &wasm_bindgen::JsValue = inner.canvas.raw(); + let window_handle = + rwh_06::WebCanvasWindowHandle::new(std::ptr::NonNull::from(canvas).cast()); + // SAFETY: The pointer won't be invalidated as long as `Window` lives, which the + // lifetime is bound to. + unsafe { + rwh_06::WindowHandle::borrow_raw(rwh_06::RawWindowHandle::WebCanvas( + window_handle, + )) + } + }) + .ok_or(rwh_06::HandleError::Unavailable) + } +} + +#[cfg(feature = "rwh_06")] +impl rwh_06::HasDisplayHandle for Window { + fn display_handle(&self) -> Result, rwh_06::HandleError> { + Ok(rwh_06::DisplayHandle::web()) + } +} + +impl Inner { + #[inline] + pub fn scale_factor(&self) -> f64 { + super::backend::scale_factor(&self.window) } } diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 5a4cadc464..a4e3ef35b9 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -86,8 +86,8 @@ use crate::platform_impl::platform::{ use crate::platform_impl::Window; use crate::utils::Lazy; use crate::window::{ - CustomCursor as RootCustomCursor, CustomCursorSource, Theme, Window as RootWindow, - WindowAttributes, WindowId as RootWindowId, + CustomCursor as RootCustomCursor, CustomCursorSource, Theme, Window as CoreWindow, + WindowAttributes, WindowId as CoreWindowId, }; pub(crate) struct WindowData { @@ -518,9 +518,11 @@ impl RootActiveEventLoop for ActiveEventLoop { RootEventLoopProxy { event_loop_proxy } } - fn create_window(&self, window_attributes: WindowAttributes) -> Result { - let window = Window::new(self, window_attributes)?; - Ok(RootWindow { window }) + fn create_window( + &self, + window_attributes: WindowAttributes, + ) -> Result, OsError> { + Ok(Box::new(Window::new(self, window_attributes)?)) } fn create_custom_cursor( @@ -918,7 +920,7 @@ fn update_modifiers(window: HWND, userdata: &WindowData) { drop(window_state); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: ModifiersChanged(modifiers.into()), }); } @@ -930,7 +932,7 @@ unsafe fn gain_active_focus(window: HWND, userdata: &WindowData) { update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: Focused(true), }); } @@ -940,12 +942,12 @@ unsafe fn lose_active_focus(window: HWND, userdata: &WindowData) { userdata.window_state_lock().modifiers_state = ModifiersState::empty(); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: ModifiersChanged(ModifiersState::empty().into()), }); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: Focused(false), }); } @@ -1043,7 +1045,7 @@ unsafe fn public_window_callback_inner( userdata.key_event_builder.process_message(window, msg, wparam, lparam, &mut result); for event in events { userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: KeyboardInput { device_id: DEVICE_ID, event: event.event, @@ -1128,7 +1130,7 @@ unsafe fn public_window_callback_inner( WM_CLOSE => { use crate::event::WindowEvent::CloseRequested; userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: CloseRequested, }); result = ProcResult::Value(0); @@ -1138,7 +1140,7 @@ unsafe fn public_window_callback_inner( use crate::event::WindowEvent::Destroyed; unsafe { RevokeDragDrop(window) }; userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: Destroyed, }); result = ProcResult::Value(0); @@ -1159,7 +1161,7 @@ unsafe fn public_window_callback_inner( // and request a normal redraw with `RedrawWindow`. if !userdata.event_loop_runner.should_buffer() { userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: WindowEvent::RedrawRequested, }); } @@ -1262,7 +1264,7 @@ unsafe fn public_window_callback_inner( let physical_position = unsafe { PhysicalPosition::new((*windowpos).x, (*windowpos).y) }; userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: Moved(physical_position), }); } @@ -1278,7 +1280,7 @@ unsafe fn public_window_callback_inner( let physical_size = PhysicalSize::new(w, h); let event = Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: Resized(physical_size), }; @@ -1393,7 +1395,7 @@ unsafe fn public_window_callback_inner( userdata.window_state_lock().ime_state = ImeState::Enabled; userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: WindowEvent::Ime(Ime::Enabled), }); } @@ -1413,7 +1415,7 @@ unsafe fn public_window_callback_inner( if lparam == 0 { userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: WindowEvent::Ime(Ime::Preedit(String::new(), None)), }); } @@ -1425,11 +1427,11 @@ unsafe fn public_window_callback_inner( userdata.window_state_lock().ime_state = ImeState::Enabled; userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: WindowEvent::Ime(Ime::Preedit(String::new(), None)), }); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: WindowEvent::Ime(Ime::Commit(text)), }); } @@ -1444,7 +1446,7 @@ unsafe fn public_window_callback_inner( let cursor_range = first.map(|f| (f, last.unwrap_or(f))); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: WindowEvent::Ime(Ime::Preedit(text, cursor_range)), }); } @@ -1467,11 +1469,11 @@ unsafe fn public_window_callback_inner( let ime_context = unsafe { ImeContext::current(window) }; if let Some(text) = unsafe { ime_context.get_composed_text() } { userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: WindowEvent::Ime(Ime::Preedit(String::new(), None)), }); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: WindowEvent::Ime(Ime::Commit(text)), }); } @@ -1480,7 +1482,7 @@ unsafe fn public_window_callback_inner( userdata.window_state_lock().ime_state = ImeState::Disabled; userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: WindowEvent::Ime(Ime::Disabled), }); } @@ -1538,7 +1540,7 @@ unsafe fn public_window_callback_inner( drop(w); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: CursorEntered { device_id: DEVICE_ID }, }); @@ -1559,7 +1561,7 @@ unsafe fn public_window_callback_inner( drop(w); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: CursorLeft { device_id: DEVICE_ID }, }); }, @@ -1578,7 +1580,7 @@ unsafe fn public_window_callback_inner( update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: CursorMoved { device_id: DEVICE_ID, position }, }); } @@ -1594,7 +1596,7 @@ unsafe fn public_window_callback_inner( } userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: CursorLeft { device_id: DEVICE_ID }, }); @@ -1610,7 +1612,7 @@ unsafe fn public_window_callback_inner( update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: WindowEvent::MouseWheel { device_id: DEVICE_ID, delta: LineDelta(0.0, value), @@ -1630,7 +1632,7 @@ unsafe fn public_window_callback_inner( update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: WindowEvent::MouseWheel { device_id: DEVICE_ID, delta: LineDelta(value, 0.0), @@ -1665,7 +1667,7 @@ unsafe fn public_window_callback_inner( update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Left }, }); result = ProcResult::Value(0); @@ -1681,7 +1683,7 @@ unsafe fn public_window_callback_inner( update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Released, button: Left }, }); result = ProcResult::Value(0); @@ -1697,7 +1699,7 @@ unsafe fn public_window_callback_inner( update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Right }, }); result = ProcResult::Value(0); @@ -1713,7 +1715,7 @@ unsafe fn public_window_callback_inner( update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Released, button: Right }, }); result = ProcResult::Value(0); @@ -1729,7 +1731,7 @@ unsafe fn public_window_callback_inner( update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Middle }, }); result = ProcResult::Value(0); @@ -1745,7 +1747,7 @@ unsafe fn public_window_callback_inner( update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Released, button: Middle }, }); result = ProcResult::Value(0); @@ -1762,7 +1764,7 @@ unsafe fn public_window_callback_inner( update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Pressed, @@ -1787,7 +1789,7 @@ unsafe fn public_window_callback_inner( update_modifiers(window, userdata); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: MouseInput { device_id: DEVICE_ID, state: Released, @@ -1836,7 +1838,7 @@ unsafe fn public_window_callback_inner( let y = location.y as f64 + (input.y % 100) as f64 / 100f64; let location = PhysicalPosition::new(x, y); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: WindowEvent::Touch(Touch { phase: if util::has_flag(input.dwFlags, TOUCHEVENTF_DOWN) { TouchPhase::Started @@ -1984,7 +1986,7 @@ unsafe fn public_window_callback_inner( let y = location.y as f64 + y.fract(); let location = PhysicalPosition::new(x, y); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: WindowEvent::Touch(Touch { phase: if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_DOWN) { TouchPhase::Started @@ -2167,7 +2169,7 @@ unsafe fn public_window_callback_inner( let new_inner_size = Arc::new(Mutex::new(new_physical_inner_size)); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: ScaleFactorChanged { scale_factor: new_scale_factor, inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&new_inner_size)), @@ -2319,7 +2321,7 @@ unsafe fn public_window_callback_inner( window_state.current_theme = new_theme; drop(window_state); userdata.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), + window_id: CoreWindowId(WindowId(window)), event: ThemeChanged(new_theme), }); } diff --git a/src/platform_impl/windows/monitor.rs b/src/platform_impl/windows/monitor.rs index c6ab740da5..d98d54f71b 100644 --- a/src/platform_impl/windows/monitor.rs +++ b/src/platform_impl/windows/monitor.rs @@ -16,7 +16,6 @@ use crate::dpi::{PhysicalPosition, PhysicalSize}; use crate::monitor::VideoModeHandle as RootVideoModeHandle; use crate::platform_impl::platform::dpi::{dpi_to_scale_factor, get_monitor_dpi}; use crate::platform_impl::platform::util::has_flag; -use crate::platform_impl::platform::window::Window; #[derive(Clone)] pub struct VideoModeHandle { @@ -136,17 +135,6 @@ pub fn current_monitor(hwnd: HWND) -> MonitorHandle { MonitorHandle::new(hmonitor) } -impl Window { - pub fn available_monitors(&self) -> VecDeque { - available_monitors() - } - - pub fn primary_monitor(&self) -> Option { - let monitor = primary_monitor(); - Some(monitor) - } -} - pub(crate) fn get_monitor_info(hmonitor: HMONITOR) -> Result { let mut monitor_info: MONITORINFOEXW = unsafe { mem::zeroed() }; monitor_info.monitorInfo.cbSize = mem::size_of::() as u32; diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index afd399607f..3b4e7439fe 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -49,6 +49,7 @@ use crate::cursor::Cursor; use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError}; use crate::icon::Icon; +use crate::monitor::MonitorHandle as CoreMonitorHandle; use crate::platform::windows::{BackdropType, Color, CornerPreference}; use crate::platform_impl::platform::dark_mode::try_theme; use crate::platform_impl::platform::definitions::{ @@ -62,14 +63,14 @@ use crate::platform_impl::platform::event_loop::{self, ActiveEventLoop, DESTROY_ use crate::platform_impl::platform::icon::{self, IconType}; use crate::platform_impl::platform::ime::ImeContext; use crate::platform_impl::platform::keyboard::KeyEventBuilder; -use crate::platform_impl::platform::monitor::{self, MonitorHandle}; use crate::platform_impl::platform::window_state::{ CursorFlags, SavedWindow, WindowFlags, WindowState, }; -use crate::platform_impl::platform::{util, Fullscreen, SelectedCursor, WindowId}; +use crate::platform_impl::platform::{monitor, util, Fullscreen, SelectedCursor, WindowId}; use crate::window::{ - CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes, - WindowButtons, WindowLevel, + CursorGrabMode, Fullscreen as CoreFullscreen, ImePurpose, ResizeDirection, Theme, + UserAttentionType, Window as CoreWindow, WindowAttributes, WindowButtons, + WindowId as CoreWindowId, WindowLevel, }; /// The Win32 implementation of the main `Window` object. @@ -96,28 +97,283 @@ impl Window { unsafe { init(w_attr, event_loop) } } - pub(crate) fn maybe_queue_on_main(&self, f: impl FnOnce(&Self) + Send + 'static) { - // TODO: Use `thread_executor` here - f(self) + fn window_state_lock(&self) -> MutexGuard<'_, WindowState> { + self.window_state.lock().unwrap() } - pub(crate) fn maybe_wait_on_main(&self, f: impl FnOnce(&Self) -> R + Send) -> R { - // TODO: Use `thread_executor` here - f(self) + /// Returns the `hwnd` of this window. + pub fn hwnd(&self) -> HWND { + self.window } - fn window_state_lock(&self) -> MutexGuard<'_, WindowState> { - self.window_state.lock().unwrap() + #[cfg(feature = "rwh_06")] + pub unsafe fn rwh_06_no_thread_check( + &self, + ) -> Result { + let mut window_handle = rwh_06::Win32WindowHandle::new(unsafe { + // SAFETY: Handle will never be zero. + std::num::NonZeroIsize::new_unchecked(self.window) + }); + let hinstance = unsafe { super::get_window_long(self.hwnd(), GWLP_HINSTANCE) }; + window_handle.hinstance = std::num::NonZeroIsize::new(hinstance); + Ok(rwh_06::RawWindowHandle::Win32(window_handle)) + } + + #[cfg(feature = "rwh_06")] + pub fn raw_window_handle_rwh_06(&self) -> Result { + // TODO: Write a test once integration framework is ready to ensure that it holds. + // If we aren't in the GUI thread, we can't return the window. + if !self.thread_executor.in_event_loop_thread() { + tracing::error!("tried to access window handle outside of the main thread"); + return Err(rwh_06::HandleError::Unavailable); + } + + // SAFETY: We are on the correct thread. + unsafe { self.rwh_06_no_thread_check() } + } + + #[cfg(feature = "rwh_06")] + pub fn raw_display_handle_rwh_06( + &self, + ) -> Result { + Ok(rwh_06::RawDisplayHandle::Windows(rwh_06::WindowsDisplayHandle::new())) + } + + pub fn set_enable(&self, enabled: bool) { + unsafe { EnableWindow(self.hwnd(), enabled.into()) }; + } + + pub fn set_skip_taskbar(&self, skip: bool) { + self.window_state_lock().skip_taskbar = skip; + unsafe { set_skip_taskbar(self.hwnd(), skip) }; + } + + pub fn set_undecorated_shadow(&self, shadow: bool) { + let window = self.window; + let window_state = Arc::clone(&self.window_state); + + self.thread_executor.execute_in_thread(move || { + let _ = &window; + WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| { + f.set(WindowFlags::MARKER_UNDECORATED_SHADOW, shadow) + }); + }); + } + + pub fn set_system_backdrop(&self, backdrop_type: BackdropType) { + unsafe { + DwmSetWindowAttribute( + self.hwnd(), + DWMWA_SYSTEMBACKDROP_TYPE as u32, + &(backdrop_type as i32) as *const _ as _, + mem::size_of::() as _, + ); + } + } + + pub fn set_taskbar_icon(&self, taskbar_icon: Option) { + if let Some(ref taskbar_icon) = taskbar_icon { + taskbar_icon.inner.set_for_window(self.hwnd(), IconType::Big); + } else { + icon::unset_for_window(self.hwnd(), IconType::Big); + } + self.window_state_lock().taskbar_icon = taskbar_icon; + } + + unsafe fn handle_os_dragging(&self, wparam: WPARAM) { + let window = self.window; + let window_state = self.window_state.clone(); + + self.thread_executor.execute_in_thread(move || { + { + let mut guard = window_state.lock().unwrap(); + if !guard.dragging { + guard.dragging = true; + } else { + return; + } + } + + let points = { + let mut pos = unsafe { mem::zeroed() }; + unsafe { GetCursorPos(&mut pos) }; + pos + }; + let points = POINTS { x: points.x as i16, y: points.y as i16 }; + + // ReleaseCapture needs to execute on the main thread + unsafe { ReleaseCapture() }; + + unsafe { + PostMessageW(window, WM_NCLBUTTONDOWN, wparam, &points as *const _ as LPARAM) + }; + }); + } + + unsafe fn handle_showing_window_menu(&self, position: Position) { + unsafe { + let point = { + let mut point = POINT { x: 0, y: 0 }; + let scale_factor = self.scale_factor(); + let (x, y) = position.to_physical::(scale_factor).into(); + point.x = x; + point.y = y; + if ClientToScreen(self.hwnd(), &mut point) == false.into() { + warn!( + "Can't convert client-area coordinates to screen coordinates when showing \ + window menu." + ); + return; + } + point + }; + + // get the current system menu + let h_menu = GetSystemMenu(self.hwnd(), 0); + if h_menu == 0 { + warn!("The corresponding window doesn't have a system menu"); + // This situation should not be treated as an error so just return without showing + // menu. + return; + } + + fn enable(b: bool) -> MENU_ITEM_STATE { + if b { + MFS_ENABLED + } else { + MFS_DISABLED + } + } + + // Change the menu items according to the current window status. + + let restore_btn = enable(self.is_maximized() && self.is_resizable()); + let size_btn = enable(!self.is_maximized() && self.is_resizable()); + let maximize_btn = enable(!self.is_maximized() && self.is_resizable()); + + EnableMenuItem(h_menu, SC_RESTORE, MF_BYCOMMAND | restore_btn); + EnableMenuItem(h_menu, SC_MOVE, MF_BYCOMMAND | enable(!self.is_maximized())); + EnableMenuItem(h_menu, SC_SIZE, MF_BYCOMMAND | size_btn); + EnableMenuItem(h_menu, SC_MINIMIZE, MF_BYCOMMAND | MFS_ENABLED); + EnableMenuItem(h_menu, SC_MAXIMIZE, MF_BYCOMMAND | maximize_btn); + EnableMenuItem(h_menu, SC_CLOSE, MF_BYCOMMAND | MFS_ENABLED); + + // Set the default menu item. + SetMenuDefaultItem(h_menu, SC_CLOSE, 0); + + // Popup the system menu at the position. + let result = TrackPopupMenu( + h_menu, + TPM_RETURNCMD | TPM_LEFTALIGN, /* for now im using LTR, but we have to use user + * layout direction */ + point.x, + point.y, + 0, + self.hwnd(), + std::ptr::null_mut(), + ); + + if result == 0 { + // User canceled the menu, no need to continue. + return; + } + + // Send the command that the user select to the corresponding window. + if PostMessageW(self.hwnd(), WM_SYSCOMMAND, result as _, 0) == 0 { + warn!("Can't post the system menu message to the window."); + } + } + } + + #[inline] + pub fn set_border_color(&self, color: Color) { + unsafe { + DwmSetWindowAttribute( + self.hwnd(), + DWMWA_BORDER_COLOR as u32, + &color as *const _ as _, + mem::size_of::() as _, + ); + } + } + + #[inline] + pub fn set_title_background_color(&self, color: Color) { + unsafe { + DwmSetWindowAttribute( + self.hwnd(), + DWMWA_CAPTION_COLOR as u32, + &color as *const _ as _, + mem::size_of::() as _, + ); + } + } + + #[inline] + pub fn set_title_text_color(&self, color: Color) { + unsafe { + DwmSetWindowAttribute( + self.hwnd(), + DWMWA_TEXT_COLOR as u32, + &color as *const _ as _, + mem::size_of::() as _, + ); + } + } + + #[inline] + pub fn set_corner_preference(&self, preference: CornerPreference) { + unsafe { + DwmSetWindowAttribute( + self.hwnd(), + DWMWA_WINDOW_CORNER_PREFERENCE as u32, + &(preference as DWM_WINDOW_CORNER_PREFERENCE) as *const _ as _, + mem::size_of::() as _, + ); + } + } +} + +impl Drop for Window { + fn drop(&mut self) { + // Restore fullscreen video mode on exit. + if matches!(self.fullscreen(), Some(CoreFullscreen::Exclusive(_))) { + self.set_fullscreen(None); + } + + unsafe { + // The window must be destroyed from the same thread that created it, so we send a + // custom message to be handled by our callback to do the actual work. + PostMessageW(self.hwnd(), DESTROY_MSG_ID.get(), 0, 0); + } + } +} + +#[cfg(feature = "rwh_06")] +impl rwh_06::HasDisplayHandle for Window { + fn display_handle(&self) -> Result, rwh_06::HandleError> { + let raw = self.raw_display_handle_rwh_06()?; + unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) } } +} - pub fn set_title(&self, text: &str) { +#[cfg(feature = "rwh_06")] +impl rwh_06::HasWindowHandle for Window { + fn window_handle(&self) -> Result, rwh_06::HandleError> { + let raw = self.raw_window_handle_rwh_06()?; + unsafe { Ok(rwh_06::WindowHandle::borrow_raw(raw)) } + } +} + +impl CoreWindow for Window { + fn set_title(&self, text: &str) { let wide_text = util::encode_wide(text); unsafe { SetWindowTextW(self.hwnd(), wide_text.as_ptr()); } } - pub fn set_transparent(&self, transparent: bool) { + fn set_transparent(&self, transparent: bool) { let window = self.window; let window_state = Arc::clone(&self.window_state); self.thread_executor.execute_in_thread(move || { @@ -128,10 +384,9 @@ impl Window { }); } - pub fn set_blur(&self, _blur: bool) {} + fn set_blur(&self, _blur: bool) {} - #[inline] - pub fn set_visible(&self, visible: bool) { + fn set_visible(&self, visible: bool) { let window = self.window; let window_state = Arc::clone(&self.window_state); self.thread_executor.execute_in_thread(move || { @@ -142,13 +397,11 @@ impl Window { }); } - #[inline] - pub fn is_visible(&self) -> Option { + fn is_visible(&self) -> Option { Some(unsafe { IsWindowVisible(self.window) == 1 }) } - #[inline] - pub fn request_redraw(&self) { + fn request_redraw(&self) { // NOTE: mark that we requested a redraw to handle requests during `WM_PAINT` handling. self.window_state.lock().unwrap().redraw_requested = true; unsafe { @@ -156,11 +409,9 @@ impl Window { } } - #[inline] - pub fn pre_present_notify(&self) {} + fn pre_present_notify(&self) {} - #[inline] - pub fn outer_position(&self) -> Result, NotSupportedError> { + fn outer_position(&self) -> Result, NotSupportedError> { util::WindowArea::Outer .get_rect(self.hwnd()) .map(|rect| Ok(PhysicalPosition::new(rect.left, rect.top))) @@ -170,8 +421,7 @@ impl Window { ) } - #[inline] - pub fn inner_position(&self) -> Result, NotSupportedError> { + fn inner_position(&self) -> Result, NotSupportedError> { let mut position: POINT = unsafe { mem::zeroed() }; if unsafe { ClientToScreen(self.hwnd(), &mut position) } == false.into() { panic!( @@ -182,8 +432,7 @@ impl Window { Ok(PhysicalPosition::new(position.x, position.y)) } - #[inline] - pub fn set_outer_position(&self, position: Position) { + fn set_outer_position(&self, position: Position) { let (x, y): (i32, i32) = position.to_physical::(self.scale_factor()).into(); let window_state = Arc::clone(&self.window_state); @@ -209,8 +458,7 @@ impl Window { } } - #[inline] - pub fn inner_size(&self) -> PhysicalSize { + fn inner_size(&self) -> PhysicalSize { let mut rect: RECT = unsafe { mem::zeroed() }; if unsafe { GetClientRect(self.hwnd(), &mut rect) } == false.into() { panic!( @@ -221,8 +469,7 @@ impl Window { PhysicalSize::new((rect.right - rect.left) as u32, (rect.bottom - rect.top) as u32) } - #[inline] - pub fn outer_size(&self) -> PhysicalSize { + fn outer_size(&self) -> PhysicalSize { util::WindowArea::Outer .get_rect(self.hwnd()) .map(|rect| { @@ -231,8 +478,7 @@ impl Window { .unwrap() } - #[inline] - pub fn request_inner_size(&self, size: Size) -> Option> { + fn request_inner_size(&self, size: Size) -> Option> { let scale_factor = self.scale_factor(); let physical_size = size.to_physical::(scale_factor); @@ -253,36 +499,31 @@ impl Window { None } - #[inline] - pub fn set_min_inner_size(&self, size: Option) { + fn set_min_inner_size(&self, size: Option) { self.window_state_lock().min_size = size; // Make windows re-check the window size bounds. let size = self.inner_size(); - self.request_inner_size(size.into()); + let _ = self.request_inner_size(size.into()); } - #[inline] - pub fn set_max_inner_size(&self, size: Option) { + fn set_max_inner_size(&self, size: Option) { self.window_state_lock().max_size = size; // Make windows re-check the window size bounds. let size = self.inner_size(); - self.request_inner_size(size.into()); + let _ = self.request_inner_size(size.into()); } - #[inline] - pub fn resize_increments(&self) -> Option> { + fn resize_increments(&self) -> Option> { let w = self.window_state_lock(); let scale_factor = w.scale_factor; w.resize_increments.map(|size| size.to_physical(scale_factor)) } - #[inline] - pub fn set_resize_increments(&self, increments: Option) { + fn set_resize_increments(&self, increments: Option) { self.window_state_lock().resize_increments = increments; } - #[inline] - pub fn set_resizable(&self, resizable: bool) { + fn set_resizable(&self, resizable: bool) { let window = self.window; let window_state = Arc::clone(&self.window_state); @@ -294,14 +535,12 @@ impl Window { }); } - #[inline] - pub fn is_resizable(&self) -> bool { + fn is_resizable(&self) -> bool { let window_state = self.window_state_lock(); window_state.window_flags.contains(WindowFlags::RESIZABLE) } - #[inline] - pub fn set_enabled_buttons(&self, buttons: WindowButtons) { + fn set_enabled_buttons(&self, buttons: WindowButtons) { let window = self.window; let window_state = Arc::clone(&self.window_state); @@ -315,65 +554,22 @@ impl Window { }); } - pub fn enabled_buttons(&self) -> WindowButtons { + fn enabled_buttons(&self) -> WindowButtons { let mut buttons = WindowButtons::empty(); let window_state = self.window_state_lock(); if window_state.window_flags.contains(WindowFlags::MINIMIZABLE) { buttons |= WindowButtons::MINIMIZE; } if window_state.window_flags.contains(WindowFlags::MAXIMIZABLE) { - buttons |= WindowButtons::MAXIMIZE; - } - if window_state.window_flags.contains(WindowFlags::CLOSABLE) { - buttons |= WindowButtons::CLOSE; - } - buttons - } - - /// Returns the `hwnd` of this window. - #[inline] - pub fn hwnd(&self) -> HWND { - self.window - } - - #[cfg(feature = "rwh_06")] - #[inline] - pub unsafe fn rwh_06_no_thread_check( - &self, - ) -> Result { - let mut window_handle = rwh_06::Win32WindowHandle::new(unsafe { - // SAFETY: Handle will never be zero. - std::num::NonZeroIsize::new_unchecked(self.window) - }); - let hinstance = unsafe { super::get_window_long(self.hwnd(), GWLP_HINSTANCE) }; - window_handle.hinstance = std::num::NonZeroIsize::new(hinstance); - Ok(rwh_06::RawWindowHandle::Win32(window_handle)) - } - - #[cfg(feature = "rwh_06")] - #[inline] - pub fn raw_window_handle_rwh_06(&self) -> Result { - // TODO: Write a test once integration framework is ready to ensure that it holds. - // If we aren't in the GUI thread, we can't return the window. - if !self.thread_executor.in_event_loop_thread() { - tracing::error!("tried to access window handle outside of the main thread"); - return Err(rwh_06::HandleError::Unavailable); + buttons |= WindowButtons::MAXIMIZE; } - - // SAFETY: We are on the correct thread. - unsafe { self.rwh_06_no_thread_check() } - } - - #[cfg(feature = "rwh_06")] - #[inline] - pub fn raw_display_handle_rwh_06( - &self, - ) -> Result { - Ok(rwh_06::RawDisplayHandle::Windows(rwh_06::WindowsDisplayHandle::new())) + if window_state.window_flags.contains(WindowFlags::CLOSABLE) { + buttons |= WindowButtons::CLOSE; + } + buttons } - #[inline] - pub fn set_cursor(&self, cursor: Cursor) { + fn set_cursor(&self, cursor: Cursor) { match cursor { Cursor::Icon(icon) => { self.window_state_lock().mouse.selected_cursor = SelectedCursor::Named(icon); @@ -392,8 +588,7 @@ impl Window { } } - #[inline] - pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { + fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { let confine = match mode { CursorGrabMode::None => false, CursorGrabMode::Confined => true, @@ -419,8 +614,7 @@ impl Window { rx.recv().unwrap() } - #[inline] - pub fn set_cursor_visible(&self, visible: bool) { + fn set_cursor_visible(&self, visible: bool) { let window = self.window; let window_state = Arc::clone(&self.window_state); let (tx, rx) = channel(); @@ -438,13 +632,11 @@ impl Window { rx.recv().unwrap().ok(); } - #[inline] - pub fn scale_factor(&self) -> f64 { + fn scale_factor(&self) -> f64 { self.window_state_lock().scale_factor } - #[inline] - pub fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> { + fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> { let scale_factor = self.scale_factor(); let (x, y) = position.to_physical::(scale_factor).into(); @@ -460,38 +652,7 @@ impl Window { Ok(()) } - unsafe fn handle_os_dragging(&self, wparam: WPARAM) { - let window = self.window; - let window_state = self.window_state.clone(); - - self.thread_executor.execute_in_thread(move || { - { - let mut guard = window_state.lock().unwrap(); - if !guard.dragging { - guard.dragging = true; - } else { - return; - } - } - - let points = { - let mut pos = unsafe { mem::zeroed() }; - unsafe { GetCursorPos(&mut pos) }; - pos - }; - let points = POINTS { x: points.x as i16, y: points.y as i16 }; - - // ReleaseCapture needs to execute on the main thread - unsafe { ReleaseCapture() }; - - unsafe { - PostMessageW(window, WM_NCLBUTTONDOWN, wparam, &points as *const _ as LPARAM) - }; - }); - } - - #[inline] - pub fn drag_window(&self) -> Result<(), ExternalError> { + fn drag_window(&self) -> Result<(), ExternalError> { unsafe { self.handle_os_dragging(HTCAPTION as WPARAM); } @@ -499,8 +660,7 @@ impl Window { Ok(()) } - #[inline] - pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { + fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { unsafe { self.handle_os_dragging(match direction { ResizeDirection::East => HTRIGHT, @@ -517,90 +677,13 @@ impl Window { Ok(()) } - unsafe fn handle_showing_window_menu(&self, position: Position) { - unsafe { - let point = { - let mut point = POINT { x: 0, y: 0 }; - let scale_factor = self.scale_factor(); - let (x, y) = position.to_physical::(scale_factor).into(); - point.x = x; - point.y = y; - if ClientToScreen(self.hwnd(), &mut point) == false.into() { - warn!( - "Can't convert client-area coordinates to screen coordinates when showing \ - window menu." - ); - return; - } - point - }; - - // get the current system menu - let h_menu = GetSystemMenu(self.hwnd(), 0); - if h_menu == 0 { - warn!("The corresponding window doesn't have a system menu"); - // This situation should not be treated as an error so just return without showing - // menu. - return; - } - - fn enable(b: bool) -> MENU_ITEM_STATE { - if b { - MFS_ENABLED - } else { - MFS_DISABLED - } - } - - // Change the menu items according to the current window status. - - let restore_btn = enable(self.is_maximized() && self.is_resizable()); - let size_btn = enable(!self.is_maximized() && self.is_resizable()); - let maximize_btn = enable(!self.is_maximized() && self.is_resizable()); - - EnableMenuItem(h_menu, SC_RESTORE, MF_BYCOMMAND | restore_btn); - EnableMenuItem(h_menu, SC_MOVE, MF_BYCOMMAND | enable(!self.is_maximized())); - EnableMenuItem(h_menu, SC_SIZE, MF_BYCOMMAND | size_btn); - EnableMenuItem(h_menu, SC_MINIMIZE, MF_BYCOMMAND | MFS_ENABLED); - EnableMenuItem(h_menu, SC_MAXIMIZE, MF_BYCOMMAND | maximize_btn); - EnableMenuItem(h_menu, SC_CLOSE, MF_BYCOMMAND | MFS_ENABLED); - - // Set the default menu item. - SetMenuDefaultItem(h_menu, SC_CLOSE, 0); - - // Popup the system menu at the position. - let result = TrackPopupMenu( - h_menu, - TPM_RETURNCMD | TPM_LEFTALIGN, /* for now im using LTR, but we have to use user - * layout direction */ - point.x, - point.y, - 0, - self.hwnd(), - std::ptr::null_mut(), - ); - - if result == 0 { - // User canceled the menu, no need to continue. - return; - } - - // Send the command that the user select to the corresponding window. - if PostMessageW(self.hwnd(), WM_SYSCOMMAND, result as _, 0) == 0 { - warn!("Can't post the system menu message to the window."); - } - } - } - - #[inline] - pub fn show_window_menu(&self, position: Position) { + fn show_window_menu(&self, position: Position) { unsafe { self.handle_showing_window_menu(position); } } - #[inline] - pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> { + fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> { let window = self.window; let window_state = Arc::clone(&self.window_state); self.thread_executor.execute_in_thread(move || { @@ -612,13 +695,11 @@ impl Window { Ok(()) } - #[inline] - pub fn id(&self) -> WindowId { - WindowId(self.hwnd()) + fn id(&self) -> CoreWindowId { + CoreWindowId(WindowId(self.hwnd())) } - #[inline] - pub fn set_minimized(&self, minimized: bool) { + fn set_minimized(&self, minimized: bool) { let window = self.window; let window_state = Arc::clone(&self.window_state); @@ -635,13 +716,11 @@ impl Window { }); } - #[inline] - pub fn is_minimized(&self) -> Option { + fn is_minimized(&self) -> Option { Some(util::is_minimized(self.hwnd())) } - #[inline] - pub fn set_maximized(&self, maximized: bool) { + fn set_maximized(&self, maximized: bool) { let window = self.window; let window_state = Arc::clone(&self.window_state); @@ -653,20 +732,18 @@ impl Window { }); } - #[inline] - pub fn is_maximized(&self) -> bool { + fn is_maximized(&self) -> bool { let window_state = self.window_state_lock(); window_state.window_flags.contains(WindowFlags::MAXIMIZED) } - #[inline] - pub fn fullscreen(&self) -> Option { + fn fullscreen(&self) -> Option { let window_state = self.window_state_lock(); - window_state.fullscreen.clone() + window_state.fullscreen.clone().map(Into::into) } - #[inline] - pub fn set_fullscreen(&self, fullscreen: Option) { + fn set_fullscreen(&self, fullscreen: Option) { + let fullscreen = fullscreen.map(Into::into); let window = self.window; let window_state = Arc::clone(&self.window_state); @@ -816,8 +893,7 @@ impl Window { }); } - #[inline] - pub fn set_decorations(&self, decorations: bool) { + fn set_decorations(&self, decorations: bool) { let window = self.window; let window_state = Arc::clone(&self.window_state); @@ -829,14 +905,12 @@ impl Window { }); } - #[inline] - pub fn is_decorated(&self) -> bool { + fn is_decorated(&self) -> bool { let window_state = self.window_state_lock(); window_state.window_flags.contains(WindowFlags::MARKER_DECORATIONS) } - #[inline] - pub fn set_window_level(&self, level: WindowLevel) { + fn set_window_level(&self, level: WindowLevel) { let window = self.window; let window_state = Arc::clone(&self.window_state); @@ -849,38 +923,28 @@ impl Window { }); } - #[inline] - pub fn current_monitor(&self) -> Option { - Some(monitor::current_monitor(self.hwnd())) + fn current_monitor(&self) -> Option { + Some(CoreMonitorHandle { inner: monitor::current_monitor(self.hwnd()) }) } - #[inline] - pub fn set_window_icon(&self, window_icon: Option) { - if let Some(ref window_icon) = window_icon { - window_icon.inner.set_for_window(self.hwnd(), IconType::Small); - } else { - icon::unset_for_window(self.hwnd(), IconType::Small); - } - self.window_state_lock().window_icon = window_icon; + fn available_monitors(&self) -> Box> { + Box::new(monitor::available_monitors().into_iter().map(|inner| CoreMonitorHandle { inner })) } - #[inline] - pub fn set_enable(&self, enabled: bool) { - unsafe { EnableWindow(self.hwnd(), enabled.into()) }; + fn primary_monitor(&self) -> Option { + Some(CoreMonitorHandle { inner: monitor::primary_monitor() }) } - #[inline] - pub fn set_taskbar_icon(&self, taskbar_icon: Option) { - if let Some(ref taskbar_icon) = taskbar_icon { - taskbar_icon.inner.set_for_window(self.hwnd(), IconType::Big); + fn set_window_icon(&self, window_icon: Option) { + if let Some(ref window_icon) = window_icon { + window_icon.inner.set_for_window(self.hwnd(), IconType::Small); } else { - icon::unset_for_window(self.hwnd(), IconType::Big); + icon::unset_for_window(self.hwnd(), IconType::Small); } - self.window_state_lock().taskbar_icon = taskbar_icon; + self.window_state_lock().window_icon = window_icon; } - #[inline] - pub fn set_ime_cursor_area(&self, spot: Position, size: Size) { + fn set_ime_cursor_area(&self, spot: Position, size: Size) { let window = self.window; let state = self.window_state.clone(); self.thread_executor.execute_in_thread(move || unsafe { @@ -889,8 +953,7 @@ impl Window { }); } - #[inline] - pub fn set_ime_allowed(&self, allowed: bool) { + fn set_ime_allowed(&self, allowed: bool) { let window = self.window; let state = self.window_state.clone(); self.thread_executor.execute_in_thread(move || unsafe { @@ -899,11 +962,9 @@ impl Window { }) } - #[inline] - pub fn set_ime_purpose(&self, _purpose: ImePurpose) {} + fn set_ime_purpose(&self, _purpose: ImePurpose) {} - #[inline] - pub fn request_user_attention(&self, request_type: Option) { + fn request_user_attention(&self, request_type: Option) { let window = self.window; let active_window_handle = unsafe { GetActiveWindow() }; if window == active_window_handle { @@ -929,23 +990,20 @@ impl Window { }); } - #[inline] - pub fn set_theme(&self, theme: Option) { + fn set_theme(&self, theme: Option) { try_theme(self.window, theme); } - #[inline] - pub fn theme(&self) -> Option { + fn theme(&self) -> Option { Some(self.window_state_lock().current_theme) } - #[inline] - pub fn has_focus(&self) -> bool { + fn has_focus(&self) -> bool { let window_state = self.window_state.lock().unwrap(); window_state.has_active_focus() } - pub fn title(&self) -> String { + fn title(&self) -> String { let len = unsafe { GetWindowTextLengthW(self.window) } + 1; let mut buf = vec![0; len as usize]; unsafe { GetWindowTextW(self.window, buf.as_mut_ptr(), len) }; @@ -953,38 +1011,7 @@ impl Window { } #[inline] - pub fn set_skip_taskbar(&self, skip: bool) { - self.window_state_lock().skip_taskbar = skip; - unsafe { set_skip_taskbar(self.hwnd(), skip) }; - } - - #[inline] - pub fn set_undecorated_shadow(&self, shadow: bool) { - let window = self.window; - let window_state = Arc::clone(&self.window_state); - - self.thread_executor.execute_in_thread(move || { - let _ = &window; - WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| { - f.set(WindowFlags::MARKER_UNDECORATED_SHADOW, shadow) - }); - }); - } - - #[inline] - pub fn set_system_backdrop(&self, backdrop_type: BackdropType) { - unsafe { - DwmSetWindowAttribute( - self.hwnd(), - DWMWA_SYSTEMBACKDROP_TYPE as u32, - &(backdrop_type as i32) as *const _ as _, - mem::size_of::() as _, - ); - } - } - - #[inline] - pub fn focus_window(&self) { + fn focus_window(&self) { let window_flags = self.window_state_lock().window_flags(); let is_visible = window_flags.contains(WindowFlags::VISIBLE); @@ -997,7 +1024,7 @@ impl Window { } #[inline] - pub fn set_content_protected(&self, protected: bool) { + fn set_content_protected(&self, protected: bool) { unsafe { SetWindowDisplayAffinity( self.hwnd(), @@ -1007,7 +1034,7 @@ impl Window { } #[inline] - pub fn reset_dead_keys(&self) { + fn reset_dead_keys(&self) { // `ToUnicode` consumes the dead-key by default, so we are constructing a fake (but valid) // key input which we can call `ToUnicode` with. unsafe { @@ -1026,63 +1053,14 @@ impl Window { } } - #[inline] - pub fn set_border_color(&self, color: Color) { - unsafe { - DwmSetWindowAttribute( - self.hwnd(), - DWMWA_BORDER_COLOR as u32, - &color as *const _ as _, - mem::size_of::() as _, - ); - } - } - - #[inline] - pub fn set_title_background_color(&self, color: Color) { - unsafe { - DwmSetWindowAttribute( - self.hwnd(), - DWMWA_CAPTION_COLOR as u32, - &color as *const _ as _, - mem::size_of::() as _, - ); - } - } - - #[inline] - pub fn set_title_text_color(&self, color: Color) { - unsafe { - DwmSetWindowAttribute( - self.hwnd(), - DWMWA_TEXT_COLOR as u32, - &color as *const _ as _, - mem::size_of::() as _, - ); - } - } - - #[inline] - pub fn set_corner_preference(&self, preference: CornerPreference) { - unsafe { - DwmSetWindowAttribute( - self.hwnd(), - DWMWA_WINDOW_CORNER_PREFERENCE as u32, - &(preference as DWM_WINDOW_CORNER_PREFERENCE) as *const _ as _, - mem::size_of::() as _, - ); - } + #[cfg(feature = "rwh_06")] + fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle { + self } -} -impl Drop for Window { - #[inline] - fn drop(&mut self) { - unsafe { - // The window must be destroyed from the same thread that created it, so we send a - // custom message to be handled by our callback to do the actual work. - PostMessageW(self.hwnd(), DESTROY_MSG_ID.get(), 0, 0); - } + #[cfg(feature = "rwh_06")] + fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle { + self } } @@ -1237,7 +1215,7 @@ impl<'a> InitData<'a> { .unwrap_or_else(|| PhysicalSize::new(f64::MAX, f64::MAX).into()); let min_size = attributes.min_inner_size.unwrap_or_else(|| PhysicalSize::new(0, 0).into()); let clamped_size = Size::clamp(size, min_size, max_size, win.scale_factor()); - win.request_inner_size(clamped_size); + let _ = win.request_inner_size(clamped_size); // let margins = MARGINS { // cxLeftWidth: 1, diff --git a/src/window.rs b/src/window.rs index 8eae3991c5..639f956172 100644 --- a/src/window.rs +++ b/src/window.rs @@ -12,65 +12,7 @@ use crate::error::{ExternalError, NotSupportedError}; pub use crate::icon::{BadIcon, Icon}; use crate::monitor::{MonitorHandle, VideoModeHandle}; use crate::platform_impl::{self, PlatformSpecificWindowAttributes}; - -/// Represents a window. -/// -/// The window is closed when dropped. -/// -/// ## Threading -/// -/// This is `Send + Sync`, meaning that it can be freely used from other -/// threads. -/// -/// However, some platforms (macOS, Web and iOS) only allow user interface -/// interactions on the main thread, so on those platforms, if you use the -/// window from a thread other than the main, the code is scheduled to run on -/// the main thread, and your thread may be blocked until that completes. -/// -/// ## Platform-specific -/// -/// **Web:** The [`Window`], which is represented by a `HTMLElementCanvas`, can -/// not be closed by dropping the [`Window`]. -pub struct Window { - pub(crate) window: platform_impl::Window, -} - -impl fmt::Debug for Window { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Window").finish_non_exhaustive() - } -} - -impl Drop for Window { - /// This will close the [`Window`]. - /// - /// See [`Window`] for more details. - fn drop(&mut self) { - self.window.maybe_wait_on_main(|w| { - // If the window is in exclusive fullscreen, we must restore the desktop - // video mode (generally this would be done on application exit, but - // closing the window doesn't necessarily always mean application exit, - // such as when there are multiple windows) - if let Some(Fullscreen::Exclusive(_)) = w.fullscreen().map(|f| f.into()) { - w.set_fullscreen(None); - } - }) - } -} - -impl PartialEq for Window { - fn eq(&self, other: &Self) -> bool { - self.id().eq(&other.id()) - } -} - -impl Eq for Window {} - -impl std::hash::Hash for Window { - fn hash(&self, state: &mut H) { - self.id().hash(state); - } -} +use crate::utils::AsAny; /// Identifier of a window. Unique for each window. /// @@ -485,22 +427,27 @@ impl WindowAttributes { } } -/// Base Window functions. -impl Window { - /// Create a new [`WindowAttributes`] which allows modifying the window's attributes before - /// creation. - #[inline] - pub fn default_attributes() -> WindowAttributes { - WindowAttributes::default() - } - +/// Represents a window. +/// +/// The window is closed when dropped. +/// +/// ## Threading +/// +/// This is `Send + Sync`, meaning that it can be freely used from other +/// threads. +/// +/// However, some platforms (macOS, Web and iOS) only allow user interface +/// interactions on the main thread, so on those platforms, if you use the +/// window from a thread other than the main, the code is scheduled to run on +/// the main thread, and your thread may be blocked until that completes. +/// +/// ## Platform-specific +/// +/// **Web:** The [`Window`], which is represented by a `HTMLElementCanvas`, can +/// not be closed by dropping the [`Window`]. +pub trait Window: AsAny + Send + Sync { /// Returns an identifier unique to the window. - #[inline] - pub fn id(&self) -> WindowId { - let _span = tracing::debug_span!("winit::Window::id",).entered(); - - self.window.maybe_wait_on_main(|w| WindowId(w.id())) - } + fn id(&self) -> WindowId; /// Returns the scale factor that can be used to map logical pixels to physical pixels, and /// vice versa. @@ -563,12 +510,7 @@ impl Window { /// [android_1]: https://developer.android.com/training/multiscreen/screendensities /// [web_1]: https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio /// [`contentScaleFactor`]: https://developer.apple.com/documentation/uikit/uiview/1622657-contentscalefactor?language=objc - #[inline] - pub fn scale_factor(&self) -> f64 { - let _span = tracing::debug_span!("winit::Window::scale_factor",).entered(); - - self.window.maybe_wait_on_main(|w| w.scale_factor()) - } + fn scale_factor(&self) -> f64; /// Queues a [`WindowEvent::RedrawRequested`] event to be emitted that aligns with the windowing /// system drawing loop. @@ -596,12 +538,7 @@ impl Window { /// `requestAnimationFrame`. /// /// [`WindowEvent::RedrawRequested`]: crate::event::WindowEvent::RedrawRequested - #[inline] - pub fn request_redraw(&self) { - let _span = tracing::debug_span!("winit::Window::request_redraw",).entered(); - - self.window.maybe_queue_on_main(|w| w.request_redraw()) - } + fn request_redraw(&self); /// Notify the windowing system before presenting to the window. /// @@ -618,7 +555,7 @@ impl Window { /// ```no_run /// # use winit::window::Window; /// # fn swap_buffers() {} - /// # fn scope(window: &Window) { + /// # fn scope(window: &dyn Window) { /// // Do the actual drawing with OpenGL. /// /// // Notify winit that we're about to submit buffer to the windowing system. @@ -635,12 +572,7 @@ impl Window { /// - **Wayland:** Schedules a frame callback to throttle [`WindowEvent::RedrawRequested`]. /// /// [`WindowEvent::RedrawRequested`]: crate::event::WindowEvent::RedrawRequested - #[inline] - pub fn pre_present_notify(&self) { - let _span = tracing::debug_span!("winit::Window::pre_present_notify",).entered(); - - self.window.maybe_queue_on_main(|w| w.pre_present_notify()); - } + fn pre_present_notify(&self); /// Reset the dead key state of the keyboard. /// @@ -654,15 +586,8 @@ impl Window { // Developers' Note: If this cannot be implemented on every desktop platform // at least, then this function should be provided through a platform specific // extension trait - pub fn reset_dead_keys(&self) { - let _span = tracing::debug_span!("winit::Window::reset_dead_keys",).entered(); + fn reset_dead_keys(&self); - self.window.maybe_queue_on_main(|w| w.reset_dead_keys()) - } -} - -/// Position and size functions. -impl Window { /// Returns the position of the top-left hand corner of the window's client area relative to the /// top-left hand corner of the desktop. /// @@ -677,12 +602,7 @@ impl Window { /// - **Android / Wayland:** Always returns [`NotSupportedError`]. /// /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc - #[inline] - pub fn inner_position(&self) -> Result, NotSupportedError> { - let _span = tracing::debug_span!("winit::Window::inner_position",).entered(); - - self.window.maybe_wait_on_main(|w| w.inner_position()) - } + fn inner_position(&self) -> Result, NotSupportedError>; /// Returns the position of the top-left hand corner of the window relative to the /// top-left hand corner of the desktop. @@ -700,12 +620,7 @@ impl Window { /// system. /// - **Web:** Returns the top-left coordinates relative to the viewport. /// - **Android / Wayland:** Always returns [`NotSupportedError`]. - #[inline] - pub fn outer_position(&self) -> Result, NotSupportedError> { - let _span = tracing::debug_span!("winit::Window::outer_position",).entered(); - - self.window.maybe_wait_on_main(|w| w.outer_position()) - } + fn outer_position(&self) -> Result, NotSupportedError>; /// Modifies the position of the window. /// @@ -715,12 +630,12 @@ impl Window { /// ```no_run /// # use winit::dpi::{LogicalPosition, PhysicalPosition}; /// # use winit::window::Window; - /// # fn scope(window: &Window) { + /// # fn scope(window: &dyn Window) { /// // Specify the position in logical dimensions like this: - /// window.set_outer_position(LogicalPosition::new(400.0, 200.0)); + /// window.set_outer_position(LogicalPosition::new(400.0, 200.0).into()); /// /// // Or specify the position in physical dimensions like this: - /// window.set_outer_position(PhysicalPosition::new(400, 200)); + /// window.set_outer_position(PhysicalPosition::new(400, 200).into()); /// # } /// ``` /// @@ -733,17 +648,7 @@ impl Window { /// - **Android / Wayland:** Unsupported. /// /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform - #[inline] - pub fn set_outer_position>(&self, position: P) { - let position = position.into(); - let _span = tracing::debug_span!( - "winit::Window::set_outer_position", - position = ?position - ) - .entered(); - - self.window.maybe_queue_on_main(move |w| w.set_outer_position(position)) - } + fn set_outer_position(&self, position: Position); /// Returns the physical size of the window's client area. /// @@ -757,12 +662,7 @@ impl Window { /// /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform - #[inline] - pub fn inner_size(&self) -> PhysicalSize { - let _span = tracing::debug_span!("winit::Window::inner_size",).entered(); - - self.window.maybe_wait_on_main(|w| w.inner_size()) - } + fn inner_size(&self) -> PhysicalSize; /// Request the new size for the window. /// @@ -783,12 +683,12 @@ impl Window { /// ```no_run /// # use winit::dpi::{LogicalSize, PhysicalSize}; /// # use winit::window::Window; - /// # fn scope(window: &Window) { + /// # fn scope(window: &dyn Window) { /// // Specify the size in logical dimensions like this: - /// let _ = window.request_inner_size(LogicalSize::new(400.0, 200.0)); + /// let _ = window.request_inner_size(LogicalSize::new(400.0, 200.0).into()); /// /// // Or specify the size in physical dimensions like this: - /// let _ = window.request_inner_size(PhysicalSize::new(400, 200)); + /// let _ = window.request_inner_size(PhysicalSize::new(400, 200).into()); /// # } /// ``` /// @@ -798,17 +698,8 @@ impl Window { /// /// [`WindowEvent::Resized`]: crate::event::WindowEvent::Resized /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform - #[inline] #[must_use] - pub fn request_inner_size>(&self, size: S) -> Option> { - let size = size.into(); - let _span = tracing::debug_span!( - "winit::Window::request_inner_size", - size = ?size - ) - .entered(); - self.window.maybe_wait_on_main(|w| w.request_inner_size(size)) - } + fn request_inner_size(&self, size: Size) -> Option>; /// Returns the physical size of the entire window. /// @@ -820,78 +711,52 @@ impl Window { /// - **iOS:** Returns the [`PhysicalSize`] of the window in screen space coordinates. /// - **Web:** Returns the size of the canvas element. _Note: this returns the same value as /// [`Window::inner_size`]._ - #[inline] - pub fn outer_size(&self) -> PhysicalSize { - let _span = tracing::debug_span!("winit::Window::outer_size",).entered(); - self.window.maybe_wait_on_main(|w| w.outer_size()) - } + fn outer_size(&self) -> PhysicalSize; /// Sets a minimum dimension size for the window. /// /// ```no_run /// # use winit::dpi::{LogicalSize, PhysicalSize}; /// # use winit::window::Window; - /// # fn scope(window: &Window) { + /// # fn scope(window: &dyn Window) { /// // Specify the size in logical dimensions like this: - /// window.set_min_inner_size(Some(LogicalSize::new(400.0, 200.0))); + /// window.set_min_inner_size(Some(LogicalSize::new(400.0, 200.0).into())); /// /// // Or specify the size in physical dimensions like this: - /// window.set_min_inner_size(Some(PhysicalSize::new(400, 200))); + /// window.set_min_inner_size(Some(PhysicalSize::new(400, 200).into())); /// # } /// ``` /// /// ## Platform-specific /// /// - **iOS / Android / Orbital:** Unsupported. - #[inline] - pub fn set_min_inner_size>(&self, min_size: Option) { - let min_size = min_size.map(|s| s.into()); - let _span = tracing::debug_span!( - "winit::Window::set_min_inner_size", - min_size = ?min_size - ) - .entered(); - self.window.maybe_queue_on_main(move |w| w.set_min_inner_size(min_size)) - } + fn set_min_inner_size(&self, min_size: Option); /// Sets a maximum dimension size for the window. /// /// ```no_run /// # use winit::dpi::{LogicalSize, PhysicalSize}; /// # use winit::window::Window; - /// # fn scope(window: &Window) { + /// # fn scope(window: &dyn Window) { /// // Specify the size in logical dimensions like this: - /// window.set_max_inner_size(Some(LogicalSize::new(400.0, 200.0))); + /// window.set_max_inner_size(Some(LogicalSize::new(400.0, 200.0).into())); /// /// // Or specify the size in physical dimensions like this: - /// window.set_max_inner_size(Some(PhysicalSize::new(400, 200))); + /// window.set_max_inner_size(Some(PhysicalSize::new(400, 200).into())); /// # } /// ``` /// /// ## Platform-specific /// /// - **iOS / Android / Orbital:** Unsupported. - #[inline] - pub fn set_max_inner_size>(&self, max_size: Option) { - let max_size = max_size.map(|s| s.into()); - let _span = tracing::debug_span!( - "winit::Window::max_size", - max_size = ?max_size - ) - .entered(); - self.window.maybe_queue_on_main(move |w| w.set_max_inner_size(max_size)) - } + fn set_max_inner_size(&self, max_size: Option); /// Returns window resize increments if any were set. /// /// ## Platform-specific /// /// - **iOS / Android / Web / Wayland / Orbital:** Always returns [`None`]. - #[inline] - pub fn resize_increments(&self) -> Option> { - let _span = tracing::debug_span!("winit::Window::resize_increments",).entered(); - self.window.maybe_wait_on_main(|w| w.resize_increments()) - } + fn resize_increments(&self) -> Option>; /// Sets window resize increments. /// @@ -904,30 +769,14 @@ impl Window { /// numbers. /// - **Wayland:** Not implemented. /// - **iOS / Android / Web / Orbital:** Unsupported. - #[inline] - pub fn set_resize_increments>(&self, increments: Option) { - let increments = increments.map(Into::into); - let _span = tracing::debug_span!( - "winit::Window::set_resize_increments", - increments = ?increments - ) - .entered(); - self.window.maybe_queue_on_main(move |w| w.set_resize_increments(increments)) - } -} + fn set_resize_increments(&self, increments: Option); -/// Misc. attribute functions. -impl Window { /// Modifies the title of the window. /// /// ## Platform-specific /// /// - **iOS / Android:** Unsupported. - #[inline] - pub fn set_title(&self, title: &str) { - let _span = tracing::debug_span!("winit::Window::set_title", title).entered(); - self.window.maybe_wait_on_main(|w| w.set_title(title)) - } + fn set_title(&self, title: &str); /// Change the window transparency state. /// @@ -944,11 +793,7 @@ impl Window { /// - **Web / iOS / Android:** Unsupported. /// - **X11:** Can only be set while building the window, with /// [`WindowAttributes::with_transparent`]. - #[inline] - pub fn set_transparent(&self, transparent: bool) { - let _span = tracing::debug_span!("winit::Window::set_transparent", transparent).entered(); - self.window.maybe_queue_on_main(move |w| w.set_transparent(transparent)) - } + fn set_transparent(&self, transparent: bool); /// Change the window blur state. /// @@ -958,11 +803,7 @@ impl Window { /// /// - **Android / iOS / X11 / Web / Windows:** Unsupported. /// - **Wayland:** Only works with org_kde_kwin_blur_manager protocol. - #[inline] - pub fn set_blur(&self, blur: bool) { - let _span = tracing::debug_span!("winit::Window::set_blur", blur).entered(); - self.window.maybe_queue_on_main(move |w| w.set_blur(blur)) - } + fn set_blur(&self, blur: bool); /// Modifies the window's visibility. /// @@ -971,11 +812,7 @@ impl Window { /// ## Platform-specific /// /// - **Android / Wayland / Web:** Unsupported. - #[inline] - pub fn set_visible(&self, visible: bool) { - let _span = tracing::debug_span!("winit::Window::set_visible", visible).entered(); - self.window.maybe_queue_on_main(move |w| w.set_visible(visible)) - } + fn set_visible(&self, visible: bool); /// Gets the window's current visibility state. /// @@ -986,11 +823,7 @@ impl Window { /// /// - **X11:** Not implemented. /// - **Wayland / iOS / Android / Web:** Unsupported. - #[inline] - pub fn is_visible(&self) -> Option { - let _span = tracing::debug_span!("winit::Window::is_visible",).entered(); - self.window.maybe_wait_on_main(|w| w.is_visible()) - } + fn is_visible(&self) -> Option; /// Sets whether the window is resizable or not. /// @@ -1007,11 +840,7 @@ impl Window { /// - **iOS / Android / Web:** Unsupported. /// /// [`WindowEvent::Resized`]: crate::event::WindowEvent::Resized - #[inline] - pub fn set_resizable(&self, resizable: bool) { - let _span = tracing::debug_span!("winit::Window::set_resizable", resizable).entered(); - self.window.maybe_queue_on_main(move |w| w.set_resizable(resizable)) - } + fn set_resizable(&self, resizable: bool); /// Gets the window's current resizable state. /// @@ -1019,11 +848,7 @@ impl Window { /// /// - **X11:** Not implemented. /// - **iOS / Android / Web:** Unsupported. - #[inline] - pub fn is_resizable(&self) -> bool { - let _span = tracing::debug_span!("winit::Window::is_resizable",).entered(); - self.window.maybe_wait_on_main(|w| w.is_resizable()) - } + fn is_resizable(&self) -> bool; /// Sets the enabled window buttons. /// @@ -1031,14 +856,7 @@ impl Window { /// /// - **Wayland / X11 / Orbital:** Not implemented. /// - **Web / iOS / Android:** Unsupported. - pub fn set_enabled_buttons(&self, buttons: WindowButtons) { - let _span = tracing::debug_span!( - "winit::Window::set_enabled_buttons", - buttons = ?buttons - ) - .entered(); - self.window.maybe_queue_on_main(move |w| w.set_enabled_buttons(buttons)) - } + fn set_enabled_buttons(&self, buttons: WindowButtons); /// Gets the enabled window buttons. /// @@ -1046,10 +864,7 @@ impl Window { /// /// - **Wayland / X11 / Orbital:** Not implemented. Always returns [`WindowButtons::all`]. /// - **Web / iOS / Android:** Unsupported. Always returns [`WindowButtons::all`]. - pub fn enabled_buttons(&self) -> WindowButtons { - let _span = tracing::debug_span!("winit::Window::enabled_buttons",).entered(); - self.window.maybe_wait_on_main(|w| w.enabled_buttons()) - } + fn enabled_buttons(&self) -> WindowButtons; /// Sets the window to minimized or back /// @@ -1057,11 +872,7 @@ impl Window { /// /// - **iOS / Android / Web / Orbital:** Unsupported. /// - **Wayland:** Un-minimize is unsupported. - #[inline] - pub fn set_minimized(&self, minimized: bool) { - let _span = tracing::debug_span!("winit::Window::set_minimized", minimized).entered(); - self.window.maybe_queue_on_main(move |w| w.set_minimized(minimized)) - } + fn set_minimized(&self, minimized: bool); /// Gets the window's current minimized state. /// @@ -1075,33 +886,21 @@ impl Window { /// /// - **Wayland**: always `None`. /// - **iOS / Android / Web / Orbital:** Unsupported. - #[inline] - pub fn is_minimized(&self) -> Option { - let _span = tracing::debug_span!("winit::Window::is_minimized",).entered(); - self.window.maybe_wait_on_main(|w| w.is_minimized()) - } + fn is_minimized(&self) -> Option; /// Sets the window to maximized or back. /// /// ## Platform-specific /// /// - **iOS / Android / Web:** Unsupported. - #[inline] - pub fn set_maximized(&self, maximized: bool) { - let _span = tracing::debug_span!("winit::Window::set_maximized", maximized).entered(); - self.window.maybe_queue_on_main(move |w| w.set_maximized(maximized)) - } + fn set_maximized(&self, maximized: bool); /// Gets the window's current maximized state. /// /// ## Platform-specific /// /// - **iOS / Android / Web:** Unsupported. - #[inline] - pub fn is_maximized(&self) -> bool { - let _span = tracing::debug_span!("winit::Window::is_maximized",).entered(); - self.window.maybe_wait_on_main(|w| w.is_maximized()) - } + fn is_maximized(&self) -> bool; /// Sets the window to fullscreen or back. /// @@ -1130,15 +929,7 @@ impl Window { /// or calling without a [transient activation] does nothing. /// /// [transient activation]: https://developer.mozilla.org/en-US/docs/Glossary/Transient_activation - #[inline] - pub fn set_fullscreen(&self, fullscreen: Option) { - let _span = tracing::debug_span!( - "winit::Window::set_fullscreen", - fullscreen = ?fullscreen - ) - .entered(); - self.window.maybe_queue_on_main(move |w| w.set_fullscreen(fullscreen.map(|f| f.into()))) - } + fn set_fullscreen(&self, fullscreen: Option); /// Gets the window's current fullscreen state. /// @@ -1146,12 +937,8 @@ impl Window { /// /// - **Android / Orbital:** Will always return `None`. /// - **Wayland:** Can return `Borderless(None)` when there are no monitors. - /// - **Web:** Can only return `None` or `Borderless`. - #[inline] - pub fn fullscreen(&self) -> Option { - let _span = tracing::debug_span!("winit::Window::fullscreen",).entered(); - self.window.maybe_wait_on_main(|w| w.fullscreen().map(|f| f.into())) - } + /// - **Web:** Can only return `None` or `Borderless(None)`. + fn fullscreen(&self) -> Option; /// Turn window decorations on or off. /// @@ -1162,11 +949,7 @@ impl Window { /// ## Platform-specific /// /// - **iOS / Android / Web:** No effect. - #[inline] - pub fn set_decorations(&self, decorations: bool) { - let _span = tracing::debug_span!("winit::Window::set_decorations", decorations).entered(); - self.window.maybe_queue_on_main(move |w| w.set_decorations(decorations)) - } + fn set_decorations(&self, decorations: bool); /// Gets the window's current decorations state. /// @@ -1176,25 +959,14 @@ impl Window { /// ## Platform-specific /// /// - **iOS / Android / Web:** Always returns `true`. - #[inline] - pub fn is_decorated(&self) -> bool { - let _span = tracing::debug_span!("winit::Window::is_decorated",).entered(); - self.window.maybe_wait_on_main(|w| w.is_decorated()) - } + fn is_decorated(&self) -> bool; /// Change the window level. /// /// This is just a hint to the OS, and the system could ignore it. /// /// See [`WindowLevel`] for details. - pub fn set_window_level(&self, level: WindowLevel) { - let _span = tracing::debug_span!( - "winit::Window::set_window_level", - level = ?level - ) - .entered(); - self.window.maybe_queue_on_main(move |w| w.set_window_level(level)) - } + fn set_window_level(&self, level: WindowLevel); /// Sets the window icon. /// @@ -1210,11 +982,7 @@ impl Window { /// /// - **X11:** Has no universal guidelines for icon sizes, so you're at the whims of the WM. /// That said, it's usually in the same ballpark as on Windows. - #[inline] - pub fn set_window_icon(&self, window_icon: Option) { - let _span = tracing::debug_span!("winit::Window::set_window_icon",).entered(); - self.window.maybe_queue_on_main(move |w| w.set_window_icon(window_icon)) - } + fn set_window_icon(&self, window_icon: Option); /// Set the IME cursor editing area, where the `position` is the top left corner of that area /// and `size` is the size of this area starting from the position. An example of such area @@ -1234,12 +1002,18 @@ impl Window { /// ```no_run /// # use winit::dpi::{LogicalPosition, PhysicalPosition, LogicalSize, PhysicalSize}; /// # use winit::window::Window; - /// # fn scope(window: &Window) { + /// # fn scope(window: &dyn Window) { /// // Specify the position in logical dimensions like this: - /// window.set_ime_cursor_area(LogicalPosition::new(400.0, 200.0), LogicalSize::new(100, 100)); + /// window.set_ime_cursor_area( + /// LogicalPosition::new(400.0, 200.0).into(), + /// LogicalSize::new(100, 100).into(), + /// ); /// /// // Or specify the position in physical dimensions like this: - /// window.set_ime_cursor_area(PhysicalPosition::new(400, 200), PhysicalSize::new(100, 100)); + /// window.set_ime_cursor_area( + /// PhysicalPosition::new(400, 200).into(), + /// PhysicalSize::new(100, 100).into(), + /// ); /// # } /// ``` /// @@ -1250,18 +1024,7 @@ impl Window { /// /// [chinese]: https://support.apple.com/guide/chinese-input-method/use-the-candidate-window-cim12992/104/mac/12.0 /// [japanese]: https://support.apple.com/guide/japanese-input-method/use-the-candidate-window-jpim10262/6.3/mac/12.0 - #[inline] - pub fn set_ime_cursor_area, S: Into>(&self, position: P, size: S) { - let position = position.into(); - let size = size.into(); - let _span = tracing::debug_span!( - "winit::Window::set_ime_cursor_area", - position = ?position, - size = ?size, - ) - .entered(); - self.window.maybe_queue_on_main(move |w| w.set_ime_cursor_area(position, size)) - } + fn set_ime_cursor_area(&self, position: Position, size: Size); /// Sets whether the window should get IME events /// @@ -1285,26 +1048,14 @@ impl Window { /// /// [`Ime`]: crate::event::WindowEvent::Ime /// [`KeyboardInput`]: crate::event::WindowEvent::KeyboardInput - #[inline] - pub fn set_ime_allowed(&self, allowed: bool) { - let _span = tracing::debug_span!("winit::Window::set_ime_allowed", allowed).entered(); - self.window.maybe_queue_on_main(move |w| w.set_ime_allowed(allowed)) - } + fn set_ime_allowed(&self, allowed: bool); /// Sets the IME purpose for the window using [`ImePurpose`]. /// /// ## Platform-specific /// /// - **iOS / Android / Web / Windows / X11 / macOS / Orbital:** Unsupported. - #[inline] - pub fn set_ime_purpose(&self, purpose: ImePurpose) { - let _span = tracing::debug_span!( - "winit::Window::set_ime_purpose", - purpose = ?purpose - ) - .entered(); - self.window.maybe_queue_on_main(move |w| w.set_ime_purpose(purpose)) - } + fn set_ime_purpose(&self, purpose: ImePurpose); /// Brings the window to the front and sets input focus. Has no effect if the window is /// already in focus, minimized, or not visible. @@ -1316,22 +1067,14 @@ impl Window { /// ## Platform-specific /// /// - **iOS / Android / Wayland / Orbital:** Unsupported. - #[inline] - pub fn focus_window(&self) { - let _span = tracing::debug_span!("winit::Window::focus_window",).entered(); - self.window.maybe_queue_on_main(|w| w.focus_window()) - } + fn focus_window(&self); /// Gets whether the window has keyboard focus. /// /// This queries the same state information as [`WindowEvent::Focused`]. /// /// [`WindowEvent::Focused`]: crate::event::WindowEvent::Focused - #[inline] - pub fn has_focus(&self) -> bool { - let _span = tracing::debug_span!("winit::Window::has_focus",).entered(); - self.window.maybe_wait_on_main(|w| w.has_focus()) - } + fn has_focus(&self) -> bool; /// Requests user attention to the window, this has no effect if the application /// is already focused. How requesting for user attention manifests is platform dependent, @@ -1346,15 +1089,7 @@ impl Window { /// - **macOS:** `None` has no effect. /// - **X11:** Requests for user attention must be manually cleared. /// - **Wayland:** Requires `xdg_activation_v1` protocol, `None` has no effect. - #[inline] - pub fn request_user_attention(&self, request_type: Option) { - let _span = tracing::debug_span!( - "winit::Window::request_user_attention", - request_type = ?request_type - ) - .entered(); - self.window.maybe_queue_on_main(move |w| w.request_user_attention(request_type)) - } + fn request_user_attention(&self, request_type: Option); /// Set or override the window theme. /// @@ -1367,15 +1102,7 @@ impl Window { /// - **X11:** Sets `_GTK_THEME_VARIANT` hint to `dark` or `light` and if `None` is used, it /// will default to [`Theme::Dark`]. /// - **iOS / Android / Web / Orbital:** Unsupported. - #[inline] - pub fn set_theme(&self, theme: Option) { - let _span = tracing::debug_span!( - "winit::Window::set_theme", - theme = ?theme - ) - .entered(); - self.window.maybe_queue_on_main(move |w| w.set_theme(theme)) - } + fn set_theme(&self, theme: Option); /// Returns the current window theme. /// @@ -1385,11 +1112,7 @@ impl Window { /// /// - **iOS / Android / x11 / Orbital:** Unsupported. /// - **Wayland:** Only returns theme overrides. - #[inline] - pub fn theme(&self) -> Option { - let _span = tracing::debug_span!("winit::Window::theme",).entered(); - self.window.maybe_wait_on_main(|w| w.theme()) - } + fn theme(&self) -> Option; /// Prevents the window contents from being captured by other apps. /// @@ -1400,26 +1123,15 @@ impl Window { /// - **iOS / Android / x11 / Wayland / Web / Orbital:** Unsupported. /// /// [`NSWindowSharingNone`]: https://developer.apple.com/documentation/appkit/nswindowsharingtype/nswindowsharingnone - pub fn set_content_protected(&self, protected: bool) { - let _span = - tracing::debug_span!("winit::Window::set_content_protected", protected).entered(); - self.window.maybe_queue_on_main(move |w| w.set_content_protected(protected)) - } + fn set_content_protected(&self, protected: bool); /// Gets the current title of the window. /// /// ## Platform-specific /// /// - **iOS / Android / x11 / Wayland / Web:** Unsupported. Always returns an empty string. - #[inline] - pub fn title(&self) -> String { - let _span = tracing::debug_span!("winit::Window::title",).entered(); - self.window.maybe_wait_on_main(|w| w.title()) - } -} + fn title(&self) -> String; -/// Cursor functions. -impl Window { /// Modifies the cursor icon of the window. /// /// ## Platform-specific @@ -1427,24 +1139,19 @@ impl Window { /// - **iOS / Android / Orbital:** Unsupported. /// - **Web:** Custom cursors have to be loaded and decoded first, until then the previous /// cursor is shown. - #[inline] - pub fn set_cursor(&self, cursor: impl Into) { - let cursor = cursor.into(); - let _span = tracing::debug_span!("winit::Window::set_cursor",).entered(); - self.window.maybe_queue_on_main(move |w| w.set_cursor(cursor)) - } + fn set_cursor(&self, cursor: Cursor); /// Changes the position of the cursor in window coordinates. /// /// ```no_run /// # use winit::dpi::{LogicalPosition, PhysicalPosition}; /// # use winit::window::Window; - /// # fn scope(window: &Window) { + /// # fn scope(window: &dyn Window) { /// // Specify the position in logical dimensions like this: - /// window.set_cursor_position(LogicalPosition::new(400.0, 200.0)); + /// window.set_cursor_position(LogicalPosition::new(400.0, 200.0).into()); /// /// // Or specify the position in physical dimensions like this: - /// window.set_cursor_position(PhysicalPosition::new(400, 200)); + /// window.set_cursor_position(PhysicalPosition::new(400, 200).into()); /// # } /// ``` /// @@ -1452,16 +1159,7 @@ impl Window { /// /// - **Wayland**: Cursor must be in [`CursorGrabMode::Locked`]. /// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`]. - #[inline] - pub fn set_cursor_position>(&self, position: P) -> Result<(), ExternalError> { - let position = position.into(); - let _span = tracing::debug_span!( - "winit::Window::set_cursor_position", - position = ?position - ) - .entered(); - self.window.maybe_wait_on_main(|w| w.set_cursor_position(position)) - } + fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError>; /// Set grabbing [mode][CursorGrabMode] on the cursor preventing it from leaving the window. /// @@ -1471,22 +1169,14 @@ impl Window { /// /// ```no_run /// # use winit::window::{CursorGrabMode, Window}; - /// # fn scope(window: &Window) { + /// # fn scope(window: &dyn Window) { /// window /// .set_cursor_grab(CursorGrabMode::Confined) /// .or_else(|_e| window.set_cursor_grab(CursorGrabMode::Locked)) /// .unwrap(); /// # } /// ``` - #[inline] - pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { - let _span = tracing::debug_span!( - "winit::Window::set_cursor_grab", - mode = ?mode - ) - .entered(); - self.window.maybe_wait_on_main(|w| w.set_cursor_grab(mode)) - } + fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError>; /// Modifies the cursor's visibility. /// @@ -1500,11 +1190,7 @@ impl Window { /// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor /// is outside of the window. /// - **iOS / Android:** Unsupported. - #[inline] - pub fn set_cursor_visible(&self, visible: bool) { - let _span = tracing::debug_span!("winit::Window::set_cursor_visible", visible).entered(); - self.window.maybe_queue_on_main(move |w| w.set_cursor_visible(visible)) - } + fn set_cursor_visible(&self, visible: bool); /// Moves the window with the left mouse button until the button is released. /// @@ -1517,11 +1203,7 @@ impl Window { /// - **Wayland:** Requires the cursor to be inside the window to be dragged. /// - **macOS:** May prevent the button release event to be triggered. /// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`]. - #[inline] - pub fn drag_window(&self) -> Result<(), ExternalError> { - let _span = tracing::debug_span!("winit::Window::drag_window",).entered(); - self.window.maybe_wait_on_main(|w| w.drag_window()) - } + fn drag_window(&self) -> Result<(), ExternalError>; /// Resizes the window with the left mouse button until the button is released. /// @@ -1532,15 +1214,7 @@ impl Window { /// /// - **macOS:** Always returns an [`ExternalError::NotSupported`] /// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`]. - #[inline] - pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { - let _span = tracing::debug_span!( - "winit::Window::drag_resize_window", - direction = ?direction - ) - .entered(); - self.window.maybe_wait_on_main(|w| w.drag_resize_window(direction)) - } + fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError>; /// Show [window menu] at a specified position . /// @@ -1551,15 +1225,7 @@ impl Window { /// **Android / iOS / macOS / Orbital / Wayland / Web / X11:** Unsupported. /// /// [window menu]: https://en.wikipedia.org/wiki/Common_menus_in_Microsoft_Windows#System_menu - pub fn show_window_menu(&self, position: impl Into) { - let position = position.into(); - let _span = tracing::debug_span!( - "winit::Window::show_window_menu", - position = ?position - ) - .entered(); - self.window.maybe_queue_on_main(move |w| w.show_window_menu(position)) - } + fn show_window_menu(&self, position: Position); /// Modifies whether the window catches cursor events. /// @@ -1570,23 +1236,12 @@ impl Window { /// ## Platform-specific /// /// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`]. - #[inline] - pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> { - let _span = tracing::debug_span!("winit::Window::set_cursor_hittest", hittest).entered(); - self.window.maybe_wait_on_main(|w| w.set_cursor_hittest(hittest)) - } -} + fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError>; -/// Monitor info functions. -impl Window { /// Returns the monitor on which the window currently resides. /// /// Returns `None` if current monitor can't be detected. - #[inline] - pub fn current_monitor(&self) -> Option { - let _span = tracing::debug_span!("winit::Window::current_monitor",).entered(); - self.window.maybe_wait_on_main(|w| w.current_monitor().map(|inner| MonitorHandle { inner })) - } + fn current_monitor(&self) -> Option; /// Returns the list of all the monitors available on the system. /// @@ -1605,13 +1260,7 @@ impl Window { /// #[rustfmt::skip] /// [`ActiveEventLoop::available_monitors`]: crate::event_loop::ActiveEventLoop::available_monitors - #[inline] - pub fn available_monitors(&self) -> impl Iterator { - let _span = tracing::debug_span!("winit::Window::available_monitors",).entered(); - self.window.maybe_wait_on_main(|w| { - w.available_monitors().into_iter().map(|inner| MonitorHandle { inner }) - }) - } + fn available_monitors(&self) -> Box>; /// Returns the primary monitor of the system. /// @@ -1631,32 +1280,50 @@ impl Window { /// #[rustfmt::skip] /// [`ActiveEventLoop::primary_monitor`]: crate::event_loop::ActiveEventLoop::primary_monitor - #[inline] - pub fn primary_monitor(&self) -> Option { - let _span = tracing::debug_span!("winit::Window::primary_monitor",).entered(); - self.window.maybe_wait_on_main(|w| w.primary_monitor().map(|inner| MonitorHandle { inner })) + fn primary_monitor(&self) -> Option; + + /// Get the raw-window-handle v0.6 display handle. + #[cfg(feature = "rwh_06")] + fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle; + + /// Get the raw-window-handle v0.6 window handle. + #[cfg(feature = "rwh_06")] + 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() } } -#[cfg(feature = "rwh_06")] -impl rwh_06::HasWindowHandle for Window { - fn window_handle(&self) -> Result, rwh_06::HandleError> { - let raw = self.window.raw_window_handle_rwh_06()?; +impl PartialEq for dyn Window + '_ { + fn eq(&self, other: &dyn Window) -> bool { + self.id().eq(&other.id()) + } +} + +impl Eq for dyn Window + '_ {} - // SAFETY: The window handle will never be deallocated while the window is alive, - // and the main thread safety requirements are upheld internally by each platform. - Ok(unsafe { rwh_06::WindowHandle::borrow_raw(raw) }) +impl std::hash::Hash for dyn Window + '_ { + fn hash(&self, state: &mut H) { + self.id().hash(state); } } #[cfg(feature = "rwh_06")] -impl rwh_06::HasDisplayHandle for Window { +impl rwh_06::HasDisplayHandle for dyn Window + '_ { fn display_handle(&self) -> Result, rwh_06::HandleError> { - let raw = self.window.raw_display_handle_rwh_06()?; + self.rwh_06_display_handle().display_handle() + } +} - // SAFETY: The window handle will never be deallocated while the window is alive, - // and the main thread safety requirements are upheld internally by each platform. - Ok(unsafe { rwh_06::DisplayHandle::borrow_raw(raw) }) +#[cfg(feature = "rwh_06")] +impl rwh_06::HasWindowHandle for dyn Window + '_ { + fn window_handle(&self) -> Result, rwh_06::HandleError> { + self.rwh_06_window_handle().window_handle() } } diff --git a/tests/send_objects.rs b/tests/send_objects.rs index 0d6cfb2dc0..9bc4db8eb6 100644 --- a/tests/send_objects.rs +++ b/tests/send_objects.rs @@ -1,5 +1,5 @@ #[allow(dead_code)] -fn needs_send() {} +fn needs_send() {} #[test] fn event_loop_proxy_send() { @@ -8,7 +8,7 @@ fn event_loop_proxy_send() { #[test] fn window_send() { - needs_send::(); + needs_send::(); } #[test] diff --git a/tests/sync_object.rs b/tests/sync_object.rs index 47a78f42a5..dd65e2384c 100644 --- a/tests/sync_object.rs +++ b/tests/sync_object.rs @@ -1,5 +1,5 @@ #[allow(dead_code)] -fn needs_sync() {} +fn needs_sync() {} #[test] fn event_loop_proxy_send() { @@ -8,7 +8,7 @@ fn event_loop_proxy_send() { #[test] fn window_sync() { - needs_sync::(); + needs_sync::(); } #[test]