From a61e7bb4f406b2dd4991314f8637f26983bf7a7a Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 15 Aug 2024 23:19:57 +0200 Subject: [PATCH 01/12] iOS: Refactor event handling to share code with macOS (#3865) Instead of storing the event handler within the AppState, and extracting it our every time we need it, we now use the same event handling implementation as for macOS that ensures we don't re-entrantly call the event handler, and that we un-register the handler again after we're done using it (`UIApplicationMain` won't return, but may still unwind, so this is very important for panic safety). --- src/platform_impl/apple/appkit/app_state.rs | 4 +- src/platform_impl/apple/appkit/mod.rs | 1 - .../apple/{appkit => }/event_handler.rs | 13 +- src/platform_impl/apple/mod.rs | 1 + src/platform_impl/apple/uikit/app_state.rs | 285 ++++++++---------- src/platform_impl/apple/uikit/event_loop.rs | 56 +--- 6 files changed, 144 insertions(+), 216 deletions(-) rename src/platform_impl/apple/{appkit => }/event_handler.rs (93%) diff --git a/src/platform_impl/apple/appkit/app_state.rs b/src/platform_impl/apple/appkit/app_state.rs index 0bf7e0d57b..f65fb8b4ef 100644 --- a/src/platform_impl/apple/appkit/app_state.rs +++ b/src/platform_impl/apple/appkit/app_state.rs @@ -8,7 +8,7 @@ use std::time::Instant; use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy}; use objc2_foundation::{MainThreadMarker, NSNotification}; -use super::event_handler::EventHandler; +use super::super::event_handler::EventHandler; use super::event_loop::{stop_app_immediately, ActiveEventLoop, PanicInfo}; use super::observer::{EventLoopWaker, RunLoop}; use super::{menu, WindowId}; @@ -291,7 +291,7 @@ impl AppState { callback: impl FnOnce(&mut dyn ApplicationHandler, &ActiveEventLoop), ) { let event_loop = ActiveEventLoop { app_state: Rc::clone(self), mtm: self.mtm }; - self.event_handler.handle(callback, &event_loop); + self.event_handler.handle(|app| callback(app, &event_loop)); } /// dispatch `NewEvents(Init)` + `Resumed` diff --git a/src/platform_impl/apple/appkit/mod.rs b/src/platform_impl/apple/appkit/mod.rs index 607f17e271..f02c26d16a 100644 --- a/src/platform_impl/apple/appkit/mod.rs +++ b/src/platform_impl/apple/appkit/mod.rs @@ -5,7 +5,6 @@ mod app; mod app_state; mod cursor; mod event; -mod event_handler; mod event_loop; mod ffi; mod menu; diff --git a/src/platform_impl/apple/appkit/event_handler.rs b/src/platform_impl/apple/event_handler.rs similarity index 93% rename from src/platform_impl/apple/appkit/event_handler.rs rename to src/platform_impl/apple/event_handler.rs index 9eebdba702..37765d760c 100644 --- a/src/platform_impl/apple/appkit/event_handler.rs +++ b/src/platform_impl/apple/event_handler.rs @@ -2,8 +2,9 @@ use std::cell::RefCell; use std::{fmt, mem}; use crate::application::ApplicationHandler; -use crate::platform_impl::ActiveEventLoop; +/// A helper type for storing a reference to `ApplicationHandler`, allowing interior mutable access +/// to it within the execution of a closure. #[derive(Default)] pub(crate) struct EventHandler { /// This can be in the following states: @@ -100,19 +101,17 @@ impl EventHandler { // soundness. } + #[cfg(target_os = "macos")] pub(crate) fn in_use(&self) -> bool { self.inner.try_borrow().is_err() } + #[cfg(target_os = "macos")] pub(crate) fn ready(&self) -> bool { matches!(self.inner.try_borrow().as_deref(), Ok(Some(_))) } - pub(crate) fn handle( - &self, - callback: impl FnOnce(&mut dyn ApplicationHandler, &ActiveEventLoop), - event_loop: &ActiveEventLoop, - ) { + pub(crate) fn handle(&self, callback: impl FnOnce(&mut dyn ApplicationHandler)) { match self.inner.try_borrow_mut().as_deref_mut() { Ok(Some(user_app)) => { // It is important that we keep the reference borrowed here, @@ -121,7 +120,7 @@ impl EventHandler { // // If the handler unwinds, the `RefMut` will ensure that the // handler is no longer borrowed. - callback(*user_app, event_loop); + callback(*user_app); }, Ok(None) => { // `NSApplication`, our app state and this handler are all diff --git a/src/platform_impl/apple/mod.rs b/src/platform_impl/apple/mod.rs index 705ad1fc22..559492c8b5 100644 --- a/src/platform_impl/apple/mod.rs +++ b/src/platform_impl/apple/mod.rs @@ -2,6 +2,7 @@ #[cfg(target_os = "macos")] mod appkit; +mod event_handler; mod notification_center; #[cfg(not(target_os = "macos"))] mod uikit; diff --git a/src/platform_impl/apple/uikit/app_state.rs b/src/platform_impl/apple/uikit/app_state.rs index 83db6efbb0..3b9201e886 100644 --- a/src/platform_impl/apple/uikit/app_state.rs +++ b/src/platform_impl/apple/uikit/app_state.rs @@ -1,12 +1,12 @@ #![deny(unused_results)] -use std::cell::{RefCell, RefMut}; +use std::cell::{OnceCell, RefCell, RefMut}; use std::collections::HashSet; use std::os::raw::c_void; -use std::sync::atomic::AtomicBool; +use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex, OnceLock}; use std::time::Instant; -use std::{fmt, mem, ptr}; +use std::{mem, ptr}; use core_foundation::base::CFRelease; use core_foundation::date::CFAbsoluteTimeGetCurrent; @@ -23,11 +23,13 @@ use objc2_foundation::{ }; use objc2_ui_kit::{UIApplication, UICoordinateSpace, UIView, UIWindow}; +use super::super::event_handler::EventHandler; use super::window::WinitUIWindow; use super::ActiveEventLoop; +use crate::application::ApplicationHandler; use crate::dpi::PhysicalSize; use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent}; -use crate::event_loop::{ActiveEventLoop as RootActiveEventLoop, ControlFlow}; +use crate::event_loop::ControlFlow; use crate::window::WindowId as RootWindowId; macro_rules! bug { @@ -42,25 +44,45 @@ macro_rules! bug_assert { }; } -pub(crate) struct EventLoopHandler { - #[allow(clippy::type_complexity)] - pub(crate) handler: Box, - pub(crate) event_loop: ActiveEventLoop, -} +/// Get the global event handler for the application. +/// +/// This is stored separately from AppState, since AppState needs to be accessible while the handler +/// is executing. +fn get_handler(mtm: MainThreadMarker) -> &'static EventHandler { + // TODO(madsmtm): Use `MainThreadBound` once that is possible in `static`s. + struct StaticMainThreadBound(T); -impl fmt::Debug for EventLoopHandler { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("EventLoopHandler") - .field("handler", &"...") - .field("event_loop", &self.event_loop) - .finish() + impl StaticMainThreadBound { + const fn get(&self, _mtm: MainThreadMarker) -> &T { + &self.0 + } } + + unsafe impl Send for StaticMainThreadBound {} + unsafe impl Sync for StaticMainThreadBound {} + + // SAFETY: Creating `StaticMainThreadBound` in a `const` context, where there is no concept + // of the main thread. + static GLOBAL: StaticMainThreadBound> = + StaticMainThreadBound(OnceCell::new()); + + GLOBAL.get(mtm).get_or_init(EventHandler::new) } -impl EventLoopHandler { - fn handle_event(&mut self, event: Event) { - (self.handler)(event, &self.event_loop) - } +fn handle_event(mtm: MainThreadMarker, event: Event) { + let event_loop = &ActiveEventLoop { mtm }; + get_handler(mtm).handle(|app| match event { + Event::NewEvents(cause) => app.new_events(event_loop, cause), + Event::WindowEvent { window_id, event } => app.window_event(event_loop, window_id, event), + Event::DeviceEvent { device_id, event } => app.device_event(event_loop, device_id, event), + Event::UserWakeUp => app.proxy_wake_up(event_loop), + Event::Suspended => app.suspended(event_loop), + Event::Resumed => app.resumed(event_loop), + Event::CreateSurfaces => app.can_create_surfaces(event_loop), + Event::AboutToWait => app.about_to_wait(event_loop), + Event::LoopExiting => app.exiting(event_loop), + Event::MemoryWarning => app.memory_warning(event_loop), + }) } #[derive(Debug)] @@ -77,14 +99,8 @@ pub struct ScaleFactorChanged { } enum UserCallbackTransitionResult<'a> { - Success { - handler: EventLoopHandler, - active_control_flow: ControlFlow, - processing_redraws: bool, - }, - ReentrancyPrevented { - queued_events: &'a mut Vec, - }, + Success { active_control_flow: ControlFlow, processing_redraws: bool }, + ReentrancyPrevented { queued_events: &'a mut Vec }, } impl Event { @@ -97,19 +113,12 @@ impl Event { #[derive(Debug)] #[must_use = "dropping `AppStateImpl` without inspecting it is probably a bug"] enum AppStateImpl { - NotLaunched { + Initial { queued_windows: Vec>, queued_events: Vec, queued_gpu_redraws: HashSet>, }, - Launching { - queued_windows: Vec>, - queued_events: Vec, - queued_handler: EventLoopHandler, - queued_gpu_redraws: HashSet>, - }, ProcessingEvents { - handler: EventLoopHandler, queued_gpu_redraws: HashSet>, active_control_flow: ControlFlow, }, @@ -119,16 +128,12 @@ enum AppStateImpl { queued_gpu_redraws: HashSet>, }, ProcessingRedraws { - handler: EventLoopHandler, active_control_flow: ControlFlow, }, Waiting { - waiting_handler: EventLoopHandler, start: Instant, }, - PollFinished { - waiting_handler: EventLoopHandler, - }, + PollFinished, Terminated, } @@ -154,7 +159,7 @@ impl AppState { fn init_guard(guard: &mut RefMut<'static, Option>) { let waker = EventLoopWaker::new(unsafe { CFRunLoopGetMain() }); **guard = Some(AppState { - app_state: Some(AppStateImpl::NotLaunched { + app_state: Some(AppStateImpl::Initial { queued_windows: Vec::new(), queued_events: Vec::new(), queued_gpu_redraws: HashSet::new(), @@ -207,42 +212,23 @@ impl AppState { } fn has_launched(&self) -> bool { - !matches!(self.state(), AppStateImpl::NotLaunched { .. } | AppStateImpl::Launching { .. }) + !matches!(self.state(), AppStateImpl::Initial { .. }) } fn has_terminated(&self) -> bool { matches!(self.state(), AppStateImpl::Terminated) } - fn will_launch_transition(&mut self, queued_handler: EventLoopHandler) { - let (queued_windows, queued_events, queued_gpu_redraws) = match self.take_state() { - AppStateImpl::NotLaunched { queued_windows, queued_events, queued_gpu_redraws } => { - (queued_windows, queued_events, queued_gpu_redraws) - }, - s => bug!("unexpected state {:?}", s), - }; - self.set_state(AppStateImpl::Launching { - queued_windows, - queued_events, - queued_handler, - queued_gpu_redraws, - }); - } - fn did_finish_launching_transition( &mut self, ) -> (Vec>, Vec) { - let (windows, events, handler, queued_gpu_redraws) = match self.take_state() { - AppStateImpl::Launching { - queued_windows, - queued_events, - queued_handler, - queued_gpu_redraws, - } => (queued_windows, queued_events, queued_handler, queued_gpu_redraws), + let (windows, events, queued_gpu_redraws) = match self.take_state() { + AppStateImpl::Initial { queued_windows, queued_events, queued_gpu_redraws } => { + (queued_windows, queued_events, queued_gpu_redraws) + }, s => bug!("unexpected state {:?}", s), }; self.set_state(AppStateImpl::ProcessingEvents { - handler, active_control_flow: self.control_flow, queued_gpu_redraws, }); @@ -256,22 +242,18 @@ impl AppState { return None; } - let (handler, event) = match (self.control_flow, self.take_state()) { - (ControlFlow::Poll, AppStateImpl::PollFinished { waiting_handler }) => { - (waiting_handler, EventWrapper::StaticEvent(Event::NewEvents(StartCause::Poll))) + let event = match (self.control_flow, self.take_state()) { + (ControlFlow::Poll, AppStateImpl::PollFinished) => { + EventWrapper::StaticEvent(Event::NewEvents(StartCause::Poll)) }, - (ControlFlow::Wait, AppStateImpl::Waiting { waiting_handler, start }) => ( - waiting_handler, + (ControlFlow::Wait, AppStateImpl::Waiting { start }) => { EventWrapper::StaticEvent(Event::NewEvents(StartCause::WaitCancelled { start, requested_resume: None, - })), - ), - ( - ControlFlow::WaitUntil(requested_resume), - AppStateImpl::Waiting { waiting_handler, start }, - ) => { - let event = if Instant::now() >= requested_resume { + })) + }, + (ControlFlow::WaitUntil(requested_resume), AppStateImpl::Waiting { start }) => { + if Instant::now() >= requested_resume { EventWrapper::StaticEvent(Event::NewEvents(StartCause::ResumeTimeReached { start, requested_resume, @@ -281,14 +263,12 @@ impl AppState { start, requested_resume: Some(requested_resume), })) - }; - (waiting_handler, event) + } }, s => bug!("`EventHandler` unexpectedly woke up {:?}", s), }; self.set_state(AppStateImpl::ProcessingEvents { - handler, queued_gpu_redraws: Default::default(), active_control_flow: self.control_flow, }); @@ -299,8 +279,7 @@ impl AppState { // If we're not able to process an event due to recursion or `Init` not having been sent out // yet, then queue the events up. match self.state_mut() { - &mut AppStateImpl::Launching { ref mut queued_events, .. } - | &mut AppStateImpl::NotLaunched { ref mut queued_events, .. } + &mut AppStateImpl::Initial { ref mut queued_events, .. } | &mut AppStateImpl::InUserCallback { ref mut queued_events, .. } => { // A lifetime cast: early returns are not currently handled well with NLL, but // polonius handles them well. This transmute is a safe workaround. @@ -324,17 +303,14 @@ impl AppState { }, } - let (handler, queued_gpu_redraws, active_control_flow, processing_redraws) = match self - .take_state() + let (queued_gpu_redraws, active_control_flow, processing_redraws) = match self.take_state() { - AppStateImpl::Launching { .. } - | AppStateImpl::NotLaunched { .. } - | AppStateImpl::InUserCallback { .. } => unreachable!(), - AppStateImpl::ProcessingEvents { handler, queued_gpu_redraws, active_control_flow } => { - (handler, queued_gpu_redraws, active_control_flow, false) + AppStateImpl::Initial { .. } | AppStateImpl::InUserCallback { .. } => unreachable!(), + AppStateImpl::ProcessingEvents { queued_gpu_redraws, active_control_flow } => { + (queued_gpu_redraws, active_control_flow, false) }, - AppStateImpl::ProcessingRedraws { handler, active_control_flow } => { - (handler, Default::default(), active_control_flow, true) + AppStateImpl::ProcessingRedraws { active_control_flow } => { + (Default::default(), active_control_flow, true) }, AppStateImpl::PollFinished { .. } | AppStateImpl::Waiting { .. } @@ -344,17 +320,17 @@ impl AppState { queued_events: Vec::new(), queued_gpu_redraws, }); - UserCallbackTransitionResult::Success { handler, active_control_flow, processing_redraws } + UserCallbackTransitionResult::Success { active_control_flow, processing_redraws } } fn main_events_cleared_transition(&mut self) -> HashSet> { - let (handler, queued_gpu_redraws, active_control_flow) = match self.take_state() { - AppStateImpl::ProcessingEvents { handler, queued_gpu_redraws, active_control_flow } => { - (handler, queued_gpu_redraws, active_control_flow) + let (queued_gpu_redraws, active_control_flow) = match self.take_state() { + AppStateImpl::ProcessingEvents { queued_gpu_redraws, active_control_flow } => { + (queued_gpu_redraws, active_control_flow) }, s => bug!("unexpected state {:?}", s), }; - self.set_state(AppStateImpl::ProcessingRedraws { handler, active_control_flow }); + self.set_state(AppStateImpl::ProcessingRedraws { active_control_flow }); queued_gpu_redraws } @@ -362,10 +338,8 @@ impl AppState { if !self.has_launched() || self.has_terminated() { return; } - let (waiting_handler, old) = match self.take_state() { - AppStateImpl::ProcessingRedraws { handler, active_control_flow } => { - (handler, active_control_flow) - }, + let old = match self.take_state() { + AppStateImpl::ProcessingRedraws { active_control_flow } => active_control_flow, s => bug!("unexpected state {:?}", s), }; @@ -373,35 +347,35 @@ impl AppState { match (old, new) { (ControlFlow::Wait, ControlFlow::Wait) => { let start = Instant::now(); - self.set_state(AppStateImpl::Waiting { waiting_handler, start }); + self.set_state(AppStateImpl::Waiting { start }); }, (ControlFlow::WaitUntil(old_instant), ControlFlow::WaitUntil(new_instant)) if old_instant == new_instant => { let start = Instant::now(); - self.set_state(AppStateImpl::Waiting { waiting_handler, start }); + self.set_state(AppStateImpl::Waiting { start }); }, (_, ControlFlow::Wait) => { let start = Instant::now(); - self.set_state(AppStateImpl::Waiting { waiting_handler, start }); + self.set_state(AppStateImpl::Waiting { start }); self.waker.stop() }, (_, ControlFlow::WaitUntil(new_instant)) => { let start = Instant::now(); - self.set_state(AppStateImpl::Waiting { waiting_handler, start }); + self.set_state(AppStateImpl::Waiting { start }); self.waker.start_at(new_instant) }, // Unlike on macOS, handle Poll to Poll transition here to call the waker (_, ControlFlow::Poll) => { - self.set_state(AppStateImpl::PollFinished { waiting_handler }); + self.set_state(AppStateImpl::PollFinished); self.waker.start() }, } } - fn terminated_transition(&mut self) -> EventLoopHandler { + fn terminated_transition(&mut self) { match self.replace_state(AppStateImpl::Terminated) { - AppStateImpl::ProcessingEvents { handler, .. } => handler, + AppStateImpl::ProcessingEvents { .. } => {}, s => bug!("`LoopExiting` happened while not processing events {:?}", s), } } @@ -422,15 +396,15 @@ impl AppState { pub(crate) fn set_key_window(mtm: MainThreadMarker, window: &Retained) { let mut this = AppState::get_mut(mtm); match this.state_mut() { - &mut AppStateImpl::NotLaunched { ref mut queued_windows, .. } => { + &mut AppStateImpl::Initial { ref mut queued_windows, .. } => { return queued_windows.push(window.clone()) }, &mut AppStateImpl::ProcessingEvents { .. } | &mut AppStateImpl::InUserCallback { .. } | &mut AppStateImpl::ProcessingRedraws { .. } => {}, - s @ &mut AppStateImpl::Launching { .. } - | s @ &mut AppStateImpl::Waiting { .. } - | s @ &mut AppStateImpl::PollFinished { .. } => bug!("unexpected state {:?}", s), + s @ &mut AppStateImpl::Waiting { .. } | s @ &mut AppStateImpl::PollFinished { .. } => { + bug!("unexpected state {:?}", s) + }, &mut AppStateImpl::Terminated => { panic!("Attempt to create a `Window` after the app has terminated") }, @@ -442,8 +416,7 @@ pub(crate) fn set_key_window(mtm: MainThreadMarker, window: &Retained) { let mut this = AppState::get_mut(mtm); match this.state_mut() { - &mut AppStateImpl::NotLaunched { ref mut queued_gpu_redraws, .. } - | &mut AppStateImpl::Launching { ref mut queued_gpu_redraws, .. } + &mut AppStateImpl::Initial { ref mut queued_gpu_redraws, .. } | &mut AppStateImpl::ProcessingEvents { ref mut queued_gpu_redraws, .. } | &mut AppStateImpl::InUserCallback { ref mut queued_gpu_redraws, .. } => { let _ = queued_gpu_redraws.insert(window); @@ -457,14 +430,14 @@ pub(crate) fn queue_gl_or_metal_redraw(mtm: MainThreadMarker, window: Retained mem::take(queued_windows), + AppStateImpl::Initial { queued_windows, .. } => mem::take(queued_windows), s => bug!("unexpected state {:?}", s), }; @@ -537,18 +510,15 @@ pub(crate) fn handle_nonuser_events>( return; } - let (mut handler, active_control_flow, processing_redraws) = - match this.try_user_callback_transition() { - UserCallbackTransitionResult::ReentrancyPrevented { queued_events } => { - queued_events.extend(events); - return; - }, - UserCallbackTransitionResult::Success { - handler, - active_control_flow, - processing_redraws, - } => (handler, active_control_flow, processing_redraws), - }; + let (active_control_flow, processing_redraws) = match this.try_user_callback_transition() { + UserCallbackTransitionResult::ReentrancyPrevented { queued_events } => { + queued_events.extend(events); + return; + }, + UserCallbackTransitionResult::Success { active_control_flow, processing_redraws } => { + (active_control_flow, processing_redraws) + }, + }; drop(this); for wrapper in events { @@ -562,9 +532,9 @@ pub(crate) fn handle_nonuser_events>( event ); } - handler.handle_event(event) + handle_event(mtm, event) }, - EventWrapper::ScaleFactorChanged(event) => handle_hidpi_proxy(&mut handler, event), + EventWrapper::ScaleFactorChanged(event) => handle_hidpi_proxy(mtm, event), } } @@ -588,9 +558,9 @@ pub(crate) fn handle_nonuser_events>( queued_gpu_redraws.is_empty(), "redraw queued while processing redraws" ); - AppStateImpl::ProcessingRedraws { handler, active_control_flow } + AppStateImpl::ProcessingRedraws { active_control_flow } } else { - AppStateImpl::ProcessingEvents { handler, queued_gpu_redraws, active_control_flow } + AppStateImpl::ProcessingEvents { queued_gpu_redraws, active_control_flow } }); break; } @@ -608,9 +578,9 @@ pub(crate) fn handle_nonuser_events>( event ); } - handler.handle_event(event) + handle_event(mtm, event) }, - EventWrapper::ScaleFactorChanged(event) => handle_hidpi_proxy(&mut handler, event), + EventWrapper::ScaleFactorChanged(event) => handle_hidpi_proxy(mtm, event), } } } @@ -618,23 +588,23 @@ pub(crate) fn handle_nonuser_events>( fn handle_user_events(mtm: MainThreadMarker) { let mut this = AppState::get_mut(mtm); - let (mut handler, active_control_flow, processing_redraws) = - match this.try_user_callback_transition() { - UserCallbackTransitionResult::ReentrancyPrevented { .. } => { - bug!("unexpected attempted to process an event") - }, - UserCallbackTransitionResult::Success { - handler, - active_control_flow, - processing_redraws, - } => (handler, active_control_flow, processing_redraws), - }; + let (active_control_flow, processing_redraws) = match this.try_user_callback_transition() { + UserCallbackTransitionResult::ReentrancyPrevented { .. } => { + bug!("unexpected attempted to process an event") + }, + UserCallbackTransitionResult::Success { active_control_flow, processing_redraws } => { + (active_control_flow, processing_redraws) + }, + }; if processing_redraws { bug!("user events attempted to be sent out while `ProcessingRedraws`"); } + let proxy_wake_up = this.proxy_wake_up.clone(); drop(this); - handler.handle_event(Event::UserWakeUp); + if proxy_wake_up.swap(false, Ordering::Relaxed) { + handle_event(mtm, Event::UserWakeUp); + } loop { let mut this = AppState::get_mut(mtm); @@ -651,23 +621,22 @@ fn handle_user_events(mtm: MainThreadMarker) { }, _ => unreachable!(), }; - this.app_state = Some(AppStateImpl::ProcessingEvents { - handler, - queued_gpu_redraws, - active_control_flow, - }); + this.app_state = + Some(AppStateImpl::ProcessingEvents { queued_gpu_redraws, active_control_flow }); break; } drop(this); for wrapper in queued_events { match wrapper { - EventWrapper::StaticEvent(event) => handler.handle_event(event), - EventWrapper::ScaleFactorChanged(event) => handle_hidpi_proxy(&mut handler, event), + EventWrapper::StaticEvent(event) => handle_event(mtm, event), + EventWrapper::ScaleFactorChanged(event) => handle_hidpi_proxy(mtm, event), } } - handler.handle_event(Event::UserWakeUp); + if proxy_wake_up.swap(false, Ordering::Relaxed) { + handle_event(mtm, Event::UserWakeUp); + } } } @@ -749,13 +718,13 @@ pub(crate) fn terminated(application: &UIApplication) { handle_nonuser_events(mtm, events); let mut this = AppState::get_mut(mtm); - let mut handler = this.terminated_transition(); + this.terminated_transition(); drop(this); - handler.handle_event(Event::LoopExiting) + handle_event(mtm, Event::LoopExiting) } -fn handle_hidpi_proxy(handler: &mut EventLoopHandler, event: ScaleFactorChanged) { +fn handle_hidpi_proxy(mtm: MainThreadMarker, event: ScaleFactorChanged) { let ScaleFactorChanged { suggested_size, scale_factor, window } = event; let new_inner_size = Arc::new(Mutex::new(suggested_size)); let event = Event::WindowEvent { @@ -765,7 +734,7 @@ fn handle_hidpi_proxy(handler: &mut EventLoopHandler, event: ScaleFactorChanged) inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&new_inner_size)), }, }; - handler.handle_event(event); + handle_event(mtm, event); let (view, screen_frame) = get_view_and_screen_frame(&window); let physical_size = *new_inner_size.lock().unwrap(); drop(new_inner_size); diff --git a/src/platform_impl/apple/uikit/event_loop.rs b/src/platform_impl/apple/uikit/event_loop.rs index bd52fc4029..82599c6189 100644 --- a/src/platform_impl/apple/uikit/event_loop.rs +++ b/src/platform_impl/apple/uikit/event_loop.rs @@ -22,9 +22,7 @@ use objc2_ui_kit::{ }; use super::super::notification_center::create_observer; -use super::app_state::{ - send_occluded_event_for_all_windows, AppState, EventLoopHandler, EventWrapper, -}; +use super::app_state::{send_occluded_event_for_all_windows, AppState, EventWrapper}; use super::{app_state, monitor, MonitorHandle}; use crate::application::ApplicationHandler; use crate::error::{EventLoopError, ExternalError, NotSupportedError, OsError}; @@ -128,32 +126,6 @@ impl OwnedDisplayHandle { } } -fn map_user_event<'a, A: ApplicationHandler + 'a>( - mut app: A, - proxy_wake_up: Arc, -) -> impl FnMut(Event, &dyn RootActiveEventLoop) + 'a { - move |event, window_target| match event { - Event::NewEvents(cause) => app.new_events(window_target, cause), - Event::WindowEvent { window_id, event } => { - app.window_event(window_target, window_id, event) - }, - Event::DeviceEvent { device_id, event } => { - app.device_event(window_target, device_id, event) - }, - Event::UserWakeUp => { - if proxy_wake_up.swap(false, AtomicOrdering::Relaxed) { - app.proxy_wake_up(window_target); - } - }, - Event::Suspended => app.suspended(window_target), - Event::Resumed => app.resumed(window_target), - Event::CreateSurfaces => app.can_create_surfaces(window_target), - Event::AboutToWait => app.about_to_wait(window_target), - Event::LoopExiting => app.exiting(window_target), - Event::MemoryWarning => app.memory_warning(window_target), - } -} - pub struct EventLoop { mtm: MainThreadMarker, window_target: ActiveEventLoop, @@ -285,7 +257,7 @@ impl EventLoop { }) } - pub fn run_app(self, app: A) -> ! { + pub fn run_app(self, mut app: A) -> ! { let application: Option> = unsafe { msg_send_id![UIApplication::class(), sharedApplication] }; assert!( @@ -295,35 +267,23 @@ impl EventLoop { `EventLoop::run_app` calls `UIApplicationMain` on iOS", ); - let handler = map_user_event(app, AppState::get_mut(self.mtm).proxy_wake_up()); - - let handler = unsafe { - std::mem::transmute::< - Box, - Box, - >(Box::new(handler)) - }; - - let handler = EventLoopHandler { handler, event_loop: self.window_target }; - - app_state::will_launch(self.mtm, handler); - extern "C" { // These functions are in crt_externs.h. fn _NSGetArgc() -> *mut c_int; fn _NSGetArgv() -> *mut *mut *mut c_char; } - unsafe { + app_state::launch(self.mtm, &mut app, || unsafe { UIApplicationMain( *_NSGetArgc(), NonNull::new(*_NSGetArgv()).unwrap(), - // We intentionally override neither the application nor the delegate, to allow the - // user to do so themselves! + // We intentionally override neither the application nor the delegate, to allow + // the user to do so themselves! None, None, - ) - }; + ); + }); + unreachable!() } From 6c4da1919729cdd285f452317d2c9a15b7d0cb0f Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Sun, 18 Aug 2024 23:50:10 +0200 Subject: [PATCH 02/12] macOS/iOS: Remove window activation hacks (#3872) No longer necessary after a8c7109 and facb809. --- src/platform/ios.rs | 9 --- src/platform/macos.rs | 14 ---- src/platform_impl/apple/appkit/app_state.rs | 24 ------- .../apple/appkit/window_delegate.rs | 5 ++ src/platform_impl/apple/uikit/app_state.rs | 71 ++----------------- src/platform_impl/apple/uikit/window.rs | 8 ++- 6 files changed, 18 insertions(+), 113 deletions(-) diff --git a/src/platform/ios.rs b/src/platform/ios.rs index 9716adc880..c4923bdf07 100644 --- a/src/platform/ios.rs +++ b/src/platform/ios.rs @@ -3,15 +3,6 @@ //! Winit has an OS requirement of iOS 8 or higher, and is regularly tested on //! iOS 9.3. //! -//! ## Window initialization -//! -//! iOS's main `UIApplicationMain` does some init work that's required by all -//! UI-related code (see issue [#1705]). It is best to create your windows -//! inside [`ApplicationHandler::resumed`]. -//! -//! [#1705]: https://github.com/rust-windowing/winit/issues/1705 -//! [`ApplicationHandler::resumed`]: crate::application::ApplicationHandler::resumed -//! //! ## Building app //! //! To build ios app you will need rustc built for this targets: diff --git a/src/platform/macos.rs b/src/platform/macos.rs index 88de5cf212..9aeb0940ba 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -3,20 +3,6 @@ //! Winit has an OS requirement of macOS 10.11 or higher (same as Rust //! itself), and is regularly tested on macOS 10.14. //! -//! ## Window initialization -//! -//! A lot of functionality expects the application to be ready before you -//! start doing anything; this includes creating windows, fetching monitors, -//! drawing, and so on, see issues [#2238], [#2051] and [#2087]. -//! -//! If you encounter problems, you should try doing your initialization inside -//! [`ApplicationHandler::resumed`]. -//! -//! [#2238]: https://github.com/rust-windowing/winit/issues/2238 -//! [#2051]: https://github.com/rust-windowing/winit/issues/2051 -//! [#2087]: https://github.com/rust-windowing/winit/issues/2087 -//! [`ApplicationHandler::resumed`]: crate::application::ApplicationHandler::resumed -//! //! ## Custom `NSApplicationDelegate` //! //! Winit usually handles everything related to the lifecycle events of the application. Sometimes, diff --git a/src/platform_impl/apple/appkit/app_state.rs b/src/platform_impl/apple/appkit/app_state.rs index f65fb8b4ef..1b68717378 100644 --- a/src/platform_impl/apple/appkit/app_state.rs +++ b/src/platform_impl/apple/appkit/app_state.rs @@ -115,7 +115,6 @@ impl AppState { // menu bar is initially unresponsive on macOS 10.15. app.setActivationPolicy(self.activation_policy); - window_activation_hack(&app); #[allow(deprecated)] app.activateIgnoringOtherApps(self.activate_ignoring_other_apps); @@ -387,26 +386,3 @@ impl AppState { fn min_timeout(a: Option, b: Option) -> Option { a.map_or(b, |a_timeout| b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout)))) } - -/// A hack to make activation of multiple windows work when creating them before -/// `applicationDidFinishLaunching:` / `Event::Event::NewEvents(StartCause::Init)`. -/// -/// Alternative to this would be the user calling `window.set_visible(true)` in -/// `StartCause::Init`. -/// -/// If this becomes too bothersome to maintain, it can probably be removed -/// without too much damage. -fn window_activation_hack(app: &NSApplication) { - // TODO: Proper ordering of the windows - app.windows().into_iter().for_each(|window| { - // Call `makeKeyAndOrderFront` if it was called on the window in `WinitWindow::new` - // This way we preserve the user's desired initial visibility status - // TODO: Also filter on the type/"level" of the window, and maybe other things? - if window.isVisible() { - tracing::trace!("Activating visible window"); - window.makeKeyAndOrderFront(None); - } else { - tracing::trace!("Skipping activating invisible window"); - } - }) -} diff --git a/src/platform_impl/apple/appkit/window_delegate.rs b/src/platform_impl/apple/appkit/window_delegate.rs index a38cd0af51..6e58171952 100644 --- a/src/platform_impl/apple/appkit/window_delegate.rs +++ b/src/platform_impl/apple/appkit/window_delegate.rs @@ -558,6 +558,11 @@ fn new_window( masks |= NSWindowStyleMask::FullSizeContentView; } + // NOTE: This should only be created after the application has started launching, + // (`applicationWillFinishLaunching:` at the earliest), otherwise you'll run into very + // confusing issues with the window not being properly activated. + // + // Winit ensures this by not allowing access to `ActiveEventLoop` before handling events. let window: Option> = unsafe { msg_send_id![ super(mtm.alloc().set_ivars(())), diff --git a/src/platform_impl/apple/uikit/app_state.rs b/src/platform_impl/apple/uikit/app_state.rs index 3b9201e886..376f30b827 100644 --- a/src/platform_impl/apple/uikit/app_state.rs +++ b/src/platform_impl/apple/uikit/app_state.rs @@ -15,8 +15,7 @@ use core_foundation::runloop::{ CFRunLoopTimerInvalidate, CFRunLoopTimerRef, CFRunLoopTimerSetNextFireDate, }; use objc2::rc::Retained; -use objc2::runtime::AnyObject; -use objc2::{msg_send, sel}; +use objc2::sel; use objc2_foundation::{ CGRect, CGSize, MainThreadMarker, NSInteger, NSObjectProtocol, NSOperatingSystemVersion, NSProcessInfo, @@ -114,7 +113,6 @@ impl Event { #[must_use = "dropping `AppStateImpl` without inspecting it is probably a bug"] enum AppStateImpl { Initial { - queued_windows: Vec>, queued_events: Vec, queued_gpu_redraws: HashSet>, }, @@ -160,7 +158,6 @@ impl AppState { let waker = EventLoopWaker::new(unsafe { CFRunLoopGetMain() }); **guard = Some(AppState { app_state: Some(AppStateImpl::Initial { - queued_windows: Vec::new(), queued_events: Vec::new(), queued_gpu_redraws: HashSet::new(), }), @@ -219,12 +216,10 @@ impl AppState { matches!(self.state(), AppStateImpl::Terminated) } - fn did_finish_launching_transition( - &mut self, - ) -> (Vec>, Vec) { - let (windows, events, queued_gpu_redraws) = match self.take_state() { - AppStateImpl::Initial { queued_windows, queued_events, queued_gpu_redraws } => { - (queued_windows, queued_events, queued_gpu_redraws) + fn did_finish_launching_transition(&mut self) -> Vec { + let (events, queued_gpu_redraws) = match self.take_state() { + AppStateImpl::Initial { queued_events, queued_gpu_redraws } => { + (queued_events, queued_gpu_redraws) }, s => bug!("unexpected state {:?}", s), }; @@ -232,7 +227,7 @@ impl AppState { active_control_flow: self.control_flow, queued_gpu_redraws, }); - (windows, events) + events } fn wakeup_transition(&mut self) -> Option { @@ -393,26 +388,6 @@ impl AppState { } } -pub(crate) fn set_key_window(mtm: MainThreadMarker, window: &Retained) { - let mut this = AppState::get_mut(mtm); - match this.state_mut() { - &mut AppStateImpl::Initial { ref mut queued_windows, .. } => { - return queued_windows.push(window.clone()) - }, - &mut AppStateImpl::ProcessingEvents { .. } - | &mut AppStateImpl::InUserCallback { .. } - | &mut AppStateImpl::ProcessingRedraws { .. } => {}, - s @ &mut AppStateImpl::Waiting { .. } | s @ &mut AppStateImpl::PollFinished { .. } => { - bug!("unexpected state {:?}", s) - }, - &mut AppStateImpl::Terminated => { - panic!("Attempt to create a `Window` after the app has terminated") - }, - } - drop(this); - window.makeKeyAndVisible(); -} - pub(crate) fn queue_gl_or_metal_redraw(mtm: MainThreadMarker, window: Retained) { let mut this = AppState::get_mut(mtm); match this.state_mut() { @@ -436,39 +411,13 @@ pub(crate) fn launch(mtm: MainThreadMarker, app: &mut dyn ApplicationHandler, ru pub fn did_finish_launching(mtm: MainThreadMarker) { let mut this = AppState::get_mut(mtm); - let windows = match this.state_mut() { - AppStateImpl::Initial { queued_windows, .. } => mem::take(queued_windows), - s => bug!("unexpected state {:?}", s), - }; this.waker.start(); // have to drop RefMut because the window setup code below can trigger new events drop(this); - for window in windows { - // Do a little screen dance here to account for windows being created before - // `UIApplicationMain` is called. This fixes visual issues such as being - // offcenter and sized incorrectly. Additionally, to fix orientation issues, we - // gotta reset the `rootViewController`. - // - // relevant iOS log: - // ``` - // [ApplicationLifecycle] Windows were created before application initialization - // completed. This may result in incorrect visual appearance. - // ``` - let screen = window.screen(); - let _: () = unsafe { msg_send![&window, setScreen: ptr::null::()] }; - window.setScreen(&screen); - - let controller = window.rootViewController(); - window.setRootViewController(None); - window.setRootViewController(controller.as_deref()); - - window.makeKeyAndVisible(); - } - - let (windows, events) = AppState::get_mut(mtm).did_finish_launching_transition(); + let events = AppState::get_mut(mtm).did_finish_launching_transition(); let events = [ EventWrapper::StaticEvent(Event::NewEvents(StartCause::Init)), @@ -477,12 +426,6 @@ pub fn did_finish_launching(mtm: MainThreadMarker) { .into_iter() .chain(events); handle_nonuser_events(mtm, events); - - // the above window dance hack, could possibly trigger new windows to be created. - // we can just set those windows up normally, as they were created after didFinishLaunching - for window in windows { - window.makeKeyAndVisible(); - } } // AppState::did_finish_launching handles the special transition `Init` diff --git a/src/platform_impl/apple/uikit/window.rs b/src/platform_impl/apple/uikit/window.rs index d60e79afe5..c96c1a35f6 100644 --- a/src/platform_impl/apple/uikit/window.rs +++ b/src/platform_impl/apple/uikit/window.rs @@ -78,6 +78,11 @@ impl WinitUIWindow { frame: CGRect, view_controller: &UIViewController, ) -> Retained { + // NOTE: This should only be created after the application has started launching, + // (`application:willFinishLaunchingWithOptions:` at the earliest), otherwise you'll run + // into very confusing issues with the window not being properly activated. + // + // Winit ensures this by not allowing access to `ActiveEventLoop` before handling events. let this: Retained = unsafe { msg_send_id![mtm.alloc(), initWithFrame: frame] }; this.setRootViewController(Some(view_controller)); @@ -490,8 +495,7 @@ impl Window { let view_controller = WinitViewController::new(mtm, &window_attributes, &view); let window = WinitUIWindow::new(mtm, &window_attributes, frame, &view_controller); - - app_state::set_key_window(mtm, &window); + window.makeKeyAndVisible(); // Like the Windows and macOS backends, we send a `ScaleFactorChanged` and `Resized` // event on window creation if the DPI factor != 1.0 From 6e008b39e9a598ee67c53d634a2790862d342f5a Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 19 Aug 2024 12:41:29 +0200 Subject: [PATCH 03/12] Improve iOS documentation (#3873) * Update version docs to link to `rustc`'s supported versions * Document how to run Winit on Mac Catalyst * Improve instructions for building iOS applications The old instructions are outdated, and suggested a workaround that is unnecessary. The user-story in the ecosystem is sadly not very clear-cut, so the instructions here are still woefully incomplete. * iOS: Clean up notes on main thread safety These platform-specific notes on `Window` methods were unnecessary, as it's already discussed in the top-level `Window` docs. --- src/platform/ios.rs | 88 ++++++++++++++++++++++++++++++------------- src/platform/macos.rs | 6 ++- src/window.rs | 23 +++++------ 3 files changed, 74 insertions(+), 43 deletions(-) diff --git a/src/platform/ios.rs b/src/platform/ios.rs index c4923bdf07..89a9d65561 100644 --- a/src/platform/ios.rs +++ b/src/platform/ios.rs @@ -1,45 +1,79 @@ //! # iOS / UIKit //! -//! Winit has an OS requirement of iOS 8 or higher, and is regularly tested on -//! iOS 9.3. +//! Winit has [the same iOS version requirements as `rustc`][rustc-ios-version], although it's +//! frequently only tested on newer iOS versions. //! -//! ## Building app +//! [rustc-ios-version]: https://doc.rust-lang.org/rustc/platform-support/apple-ios.html#os-version //! -//! To build ios app you will need rustc built for this targets: +//! ## Running on Mac Catalyst //! -//! - armv7-apple-ios -//! - armv7s-apple-ios -//! - i386-apple-ios -//! - aarch64-apple-ios -//! - x86_64-apple-ios +//! Mac Catalyst allows running applications using UIKit on macOS, which can be very useful for +//! testing. See [`rustc`'s documentation on Mac Catalyst][rustc-mac-catalyst] for details on how to +//! use these targets. To use these with Winit, you'll need to bundle your application before +//! running it, otherwise UIKit will exit with an error. //! -//! Then +//! To run e.g. the `window` example in the Winit repository, you can use [`cargo-bundle`] as +//! follows: //! +//! ```console +//! $ cargo +nightly bundle --format=ios --target=aarch64-apple-ios-macabi --example=window +//! $ ./target/aarch64-apple-ios-macabi/debug/examples/bundle/ios/winit.app/window //! ``` -//! cargo build --target=... -//! ``` -//! The simplest way to integrate your app into xcode environment is to build it -//! as a static library. Wrap your main function and export it. //! -//! ```rust, ignore -//! #[no_mangle] -//! pub extern fn start_winit_app() { -//! start_inner() -//! } +//! [rustc-mac-catalyst]: https://doc.rust-lang.org/rustc/platform-support/apple-ios-macabi.html +//! [`cargo-bundle`]: https://github.com/burtonageo/cargo-bundle //! -//! fn start_inner() { -//! ... -//! } -//! ``` +//! ## Introduction to building an app +//! +//! Building and running your application in the iOS simulator, or on a real device, is a bit more +//! complicated than Mac Catalyst - fundamentally, you must use Xcode, since the binary needs to be +//! bundled, signed, notarized and uploaded to the device (there is [an open source work-in-progress +//! on re-implementing parts of this][apple-platform-rs], but the user-story around it is not yet +//! clear). +//! +//! This means that you're left with effectively two options: Use a tool that manages the Xcode +//! configuration for you, or use Xcode directly. [`cargo-dinghy`] and [`cargo-mobile2`] are notable +//! projects in the ecosystem that attempt the former, and [`cargo-xcode`] is an excellent project +//! that attempts the latter. We will also attempt to describe here how you would go about using +//! Xcode directly: //! -//! Compile project and then drag resulting .a into Xcode project. Add winit.h to xcode. +//! First off, you'll need the correct Rust targets, see [`rustc`'s documentation on iOS][rustc-ios] +//! for details. Nowadays, the correct targets are usually `aarch64-apple-ios-sim` for the +//! simulator, and `aarch64-apple-ios` for the actual device. //! -//! ```ignore -//! void start_winit_app(); +//! Next, create a new Xcode project using the "App" template. The exact configuration does not +//! really matter, as we're going to delete most of it, since it's tailored for Objective-C and/or +//! Swift, and Rust/Winit is neither. Specifically, we need to delete: +//! - Everything relating to storyboards (unless you want to use e.g. a launch screen). This +//! includes the relevant keys in `Info.plist`. +//! - All the generated C header, Objective-C and/or Swift files. +//! +//! Now that we have a fairly clean slate that we can build upon, you can add a "run script" build +//! phase to your Xcode target, which will get invoked instead of the "compile sources" and "link +//! binary" steps. The basic script should look something like: +//! +//! ```sh +//! # Build desired targets based on `ARCHS` environment variable +//! cargo build --target=aarch64-apple-ios --target=armv7s-apple-ios +//! # Merge these with `lipo`, and place the result in "$TARGET_BUILD_DIR/$EXECUTABLE_PATH", which +//! # is understood by Xcode +//! lipo "$TARGET_BUILD_DIR/$EXECUTABLE_PATH" target/aarch64-apple-ios/debug/my_app target/armv7s-apple-ios/debug/my_app //! ``` //! -//! Use start_winit_app inside your xcode's main function. +//! Note that this is very much the overall idea; the script needs to be much more involved to +//! properly deal with different target architectures, invoking `lipo` when needed, incremental +//! rebuild change detection, and so on. `cargo-xcode` has a script [here][cargo-xcode-script] that +//! handles most of this complexity, you might be able to build upon that. +//! +//! Apologies that we're not able to provide you with more than this; work is in-progress on +//! improving the situation, but it's slow-going. //! +//! [apple-platform-rs]: https://github.com/indygreg/apple-platform-rs +//! [`cargo-dinghy`]: https://github.com/sonos/dinghy +//! [`cargo-mobile2`]: https://github.com/tauri-apps/cargo-mobile2 +//! [`cargo-xcode`]: https://crates.io/crates/cargo-xcode +//! [rustc-ios]: https://doc.rust-lang.org/rustc/platform-support/apple-ios.html +//! [cargo-xcode-script]: https://gitlab.com/kornelski/cargo-xcode/-/blob/main/src/xcodebuild.sh //! //! ## App lifecycle and events //! diff --git a/src/platform/macos.rs b/src/platform/macos.rs index 9aeb0940ba..44bc8b8b33 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -1,7 +1,9 @@ //! # macOS / AppKit //! -//! Winit has an OS requirement of macOS 10.11 or higher (same as Rust -//! itself), and is regularly tested on macOS 10.14. +//! Winit has [the same macOS version requirements as `rustc`][rustc-macos-version], and is tested +//! once in a while on as low as macOS 10.14. +//! +//! [rustc-macos-version]: https://doc.rust-lang.org/rustc/platform-support/apple-darwin.html#os-version //! //! ## Custom `NSApplicationDelegate` //! diff --git a/src/window.rs b/src/window.rs index 7dd7807107..35894692ac 100644 --- a/src/window.rs +++ b/src/window.rs @@ -590,7 +590,6 @@ impl Window { /// /// - **Windows** This API uses `RedrawWindow` to request a `WM_PAINT` message and /// `RedrawRequested` is emitted in sync with any `WM_PAINT` messages. - /// - **iOS:** Can only be called on the main thread. /// - **Wayland:** The events are aligned with the frame callbacks when /// [`Window::pre_present_notify`] is used. /// - **Web:** [`WindowEvent::RedrawRequested`] will be aligned with the @@ -671,8 +670,8 @@ impl Window { /// /// ## Platform-specific /// - /// - **iOS:** Can only be called on the main thread. Returns the top left coordinates of the - /// window's [safe area] in the screen space coordinate system. + /// - **iOS:** Returns the top left coordinates of the window's [safe area] in the screen space + /// coordinate system. /// - **Web:** Returns the top-left coordinates relative to the viewport. _Note: this returns /// the same value as [`Window::outer_position`]._ /// - **Android / Wayland:** Always returns [`NotSupportedError`]. @@ -697,8 +696,8 @@ impl Window { /// /// ## Platform-specific /// - /// - **iOS:** Can only be called on the main thread. Returns the top left coordinates of the - /// window in the screen space coordinate system. + /// - **iOS:** Returns the top left coordinates of the window in the screen space coordinate + /// system. /// - **Web:** Returns the top-left coordinates relative to the viewport. /// - **Android / Wayland:** Always returns [`NotSupportedError`]. #[inline] @@ -727,8 +726,8 @@ impl Window { /// /// ## Platform-specific /// - /// - **iOS:** Can only be called on the main thread. Sets the top left coordinates of the - /// window in the screen space coordinate system. + /// - **iOS:** Sets the top left coordinates of the window in the screen space coordinate + /// system. /// - **Web:** Sets the top-left coordinates relative to the viewport. Doesn't account for CSS /// [`transform`]. /// - **Android / Wayland:** Unsupported. @@ -752,8 +751,8 @@ impl Window { /// /// ## Platform-specific /// - /// - **iOS:** Can only be called on the main thread. Returns the `PhysicalSize` of the window's - /// [safe area] in screen space coordinates. + /// - **iOS:** Returns the `PhysicalSize` of the window's [safe area] in screen space + /// coordinates. /// - **Web:** Returns the size of the canvas element. Doesn't account for CSS [`transform`]. /// /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc @@ -818,8 +817,7 @@ impl Window { /// /// ## Platform-specific /// - /// - **iOS:** Can only be called on the main thread. Returns the [`PhysicalSize`] of the window - /// in screen space coordinates. + /// - **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] @@ -973,7 +971,6 @@ impl Window { /// ## Platform-specific /// /// - **Android / Wayland / Web:** Unsupported. - /// - **iOS:** Can only be called on the main thread. #[inline] pub fn set_visible(&self, visible: bool) { let _span = tracing::debug_span!("winit::Window::set_visible", visible).entered(); @@ -1121,7 +1118,6 @@ impl Window { /// separate spaces are not preferred. /// /// The dock and the menu bar are disabled in exclusive fullscreen mode. - /// - **iOS:** Can only be called on the main thread. /// - **Wayland:** Does not support exclusive fullscreen mode and will no-op a request. /// - **Windows:** Screen saver is disabled in fullscreen mode. /// - **Android / Orbital:** Unsupported. @@ -1148,7 +1144,6 @@ impl Window { /// /// ## Platform-specific /// - /// - **iOS:** Can only be called on the main thread. /// - **Android / Orbital:** Will always return `None`. /// - **Wayland:** Can return `Borderless(None)` when there are no monitors. /// - **Web:** Can only return `None` or `Borderless`. From 1e1f0fd7e9a877be1b37a60685bf72dad8bb8d3c Mon Sep 17 00:00:00 2001 From: lucasmerlin Date: Mon, 19 Aug 2024 22:04:29 +0200 Subject: [PATCH 04/12] Basic iOS IME support (#3823) This implements basic iOS IME support (typing, backspace, support for emojis etc but no autocomplete or copy / paste menu). Co-authored-by: Mads Marquart --- Cargo.toml | 2 + src/changelog/unreleased.md | 5 +- src/platform_impl/apple/uikit/view.rs | 102 +++++++++++++++++++++++- src/platform_impl/apple/uikit/window.rs | 18 ++++- src/window.rs | 3 +- 5 files changed, 120 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9bf54e42f0..00568aaa46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -183,6 +183,8 @@ objc2-ui-kit = { version = "0.2.2", features = [ "UIEvent", "UIGeometry", "UIGestureRecognizer", + "UITextInput", + "UITextInputTraits", "UIOrientation", "UIPanGestureRecognizer", "UIPinchGestureRecognizer", diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 5d797b034d..afa776260e 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -47,13 +47,13 @@ changelog entry. `DeviceEvent::MouseMotion` is returning raw data, not OS accelerated, when using `CursorGrabMode::Locked`. - On Web, implement `MonitorHandle` and `VideoModeHandle`. - + Without prompting the user for permission, only the current monitor is returned. But when prompting and being granted permission through `ActiveEventLoop::request_detailed_monitor_permission()`, access to all monitors and their details is available. Handles created with "detailed monitor permissions" can be used in `Window::set_fullscreen()` as well. - + Keep in mind that handles do not auto-upgrade after permissions are granted and have to be re-created to make full use of this feature. - Add `Touch::finger_id` with a new type `FingerId`. @@ -62,6 +62,7 @@ changelog entry. - Implement `Clone`, `Copy`, `Debug`, `Deserialize`, `Eq`, `Hash`, `Ord`, `PartialEq`, `PartialOrd` and `Serialize` on many types. - Add `MonitorHandle::current_video_mode()`. +- Add basic iOS IME support. The soft keyboard can now be shown using `Window::set_ime_allowed`. ### Changed diff --git a/src/platform_impl/apple/uikit/view.rs b/src/platform_impl/apple/uikit/view.rs index d946445eda..0d601bb97c 100644 --- a/src/platform_impl/apple/uikit/view.rs +++ b/src/platform_impl/apple/uikit/view.rs @@ -4,19 +4,23 @@ use std::cell::{Cell, RefCell}; use objc2::rc::Retained; use objc2::runtime::{NSObjectProtocol, ProtocolObject}; use objc2::{declare_class, msg_send, msg_send_id, mutability, sel, ClassType, DeclaredClass}; -use objc2_foundation::{CGFloat, CGPoint, CGRect, MainThreadMarker, NSObject, NSSet}; +use objc2_foundation::{CGFloat, CGPoint, CGRect, MainThreadMarker, NSObject, NSSet, NSString}; use objc2_ui_kit::{ UICoordinateSpace, UIEvent, UIForceTouchCapability, UIGestureRecognizer, - UIGestureRecognizerDelegate, UIGestureRecognizerState, UIPanGestureRecognizer, + UIGestureRecognizerDelegate, UIGestureRecognizerState, UIKeyInput, UIPanGestureRecognizer, UIPinchGestureRecognizer, UIResponder, UIRotationGestureRecognizer, UITapGestureRecognizer, - UITouch, UITouchPhase, UITouchType, UITraitEnvironment, UIView, + UITextInputTraits, UITouch, UITouchPhase, UITouchType, UITraitEnvironment, UIView, }; use super::app_state::{self, EventWrapper}; use super::window::WinitUIWindow; use super::{FingerId, DEVICE_ID}; use crate::dpi::PhysicalPosition; -use crate::event::{Event, FingerId as RootFingerId, Force, Touch, TouchPhase, WindowEvent}; +use crate::event::{ + ElementState, Event, FingerId as RootFingerId, Force, KeyEvent, Touch, TouchPhase, WindowEvent, +}; +use crate::keyboard::{Key, KeyCode, KeyLocation, NamedKey, NativeKeyCode, PhysicalKey}; +use crate::platform_impl::KeyEventExtra; use crate::window::{WindowAttributes, WindowId as RootWindowId}; pub struct WinitViewState { @@ -314,6 +318,11 @@ declare_class!( let mtm = MainThreadMarker::new().unwrap(); app_state::handle_nonuser_event(mtm, gesture_event); } + + #[method(canBecomeFirstResponder)] + fn can_become_first_responder(&self) -> bool { + true + } } unsafe impl NSObjectProtocol for WinitView {} @@ -324,6 +333,26 @@ declare_class!( true } } + + unsafe impl UITextInputTraits for WinitView { + } + + unsafe impl UIKeyInput for WinitView { + #[method(hasText)] + fn has_text(&self) -> bool { + true + } + + #[method(insertText:)] + fn insert_text(&self, text: &NSString) { + self.handle_insert_text(text) + } + + #[method(deleteBackward)] + fn delete_backward(&self) { + self.handle_delete_backward() + } + } ); impl WinitView { @@ -512,4 +541,69 @@ impl WinitView { let mtm = MainThreadMarker::new().unwrap(); app_state::handle_nonuser_events(mtm, touch_events); } + + fn handle_insert_text(&self, text: &NSString) { + let window = self.window().unwrap(); + let window_id = RootWindowId(window.id()); + let mtm = MainThreadMarker::new().unwrap(); + // send individual events for each character + app_state::handle_nonuser_events( + mtm, + text.to_string().chars().flat_map(|c| { + let text = smol_str::SmolStr::from_iter([c]); + // Emit both press and release events + [ElementState::Pressed, ElementState::Released].map(|state| { + EventWrapper::StaticEvent(Event::WindowEvent { + window_id, + event: WindowEvent::KeyboardInput { + event: KeyEvent { + text: if state == ElementState::Pressed { + Some(text.clone()) + } else { + None + }, + state, + location: KeyLocation::Standard, + repeat: false, + logical_key: Key::Character(text.clone()), + physical_key: PhysicalKey::Unidentified( + NativeKeyCode::Unidentified, + ), + platform_specific: KeyEventExtra {}, + }, + is_synthetic: false, + device_id: DEVICE_ID, + }, + }) + }) + }), + ); + } + + fn handle_delete_backward(&self) { + let window = self.window().unwrap(); + let window_id = RootWindowId(window.id()); + let mtm = MainThreadMarker::new().unwrap(); + app_state::handle_nonuser_events( + mtm, + [ElementState::Pressed, ElementState::Released].map(|state| { + EventWrapper::StaticEvent(Event::WindowEvent { + window_id, + event: WindowEvent::KeyboardInput { + device_id: DEVICE_ID, + event: KeyEvent { + state, + logical_key: Key::Named(NamedKey::Backspace), + physical_key: PhysicalKey::Code(KeyCode::Backspace), + platform_specific: KeyEventExtra {}, + repeat: false, + location: KeyLocation::Standard, + text: None, + }, + is_synthetic: false, + }, + }) + }), + ); + } } diff --git a/src/platform_impl/apple/uikit/window.rs b/src/platform_impl/apple/uikit/window.rs index c96c1a35f6..104535cd6d 100644 --- a/src/platform_impl/apple/uikit/window.rs +++ b/src/platform_impl/apple/uikit/window.rs @@ -370,12 +370,24 @@ impl Inner { warn!("`Window::set_ime_cursor_area` is ignored on iOS") } - pub fn set_ime_allowed(&self, _allowed: bool) { - warn!("`Window::set_ime_allowed` is ignored on iOS") + /// Show / hide the keyboard. To show the keyboard, we call `becomeFirstResponder`, + /// requesting focus for the [WinitView]. Since [WinitView] implements + /// [objc2_ui_kit::UIKeyInput], the keyboard will be shown. + /// + pub fn set_ime_allowed(&self, allowed: bool) { + if allowed { + unsafe { + self.view.becomeFirstResponder(); + } + } else { + unsafe { + self.view.resignFirstResponder(); + } + } } pub fn set_ime_purpose(&self, _purpose: ImePurpose) { - warn!("`Window::set_ime_allowed` is ignored on iOS") + warn!("`Window::set_ime_purpose` is ignored on iOS") } pub fn focus_window(&self) { diff --git a/src/window.rs b/src/window.rs index 35894692ac..8eae3991c5 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1279,7 +1279,8 @@ impl Window { /// /// - **macOS:** IME must be enabled to receive text-input where dead-key sequences are /// combined. - /// - **iOS / Android / Web / Orbital:** Unsupported. + /// - **iOS:** This will show / hide the soft keyboard. + /// - **Android / Web / Orbital:** Unsupported. /// - **X11**: Enabling IME will disable dead keys reporting during compose. /// /// [`Ime`]: crate::event::WindowEvent::Ime From 8f4a8efa99eb2e1f7a35c0e3aea57627593639f8 Mon Sep 17 00:00:00 2001 From: John Nunley Date: Wed, 21 Aug 2024 21:14:07 -0700 Subject: [PATCH 05/12] m: Ignore mutex poisoning in X11_BACKEND A panic doesn't really put any of the fields in XConnection into an invalid state, so there is no real reason to panic when poisoning is detected. So just ignore the poison. Closes #3870 Signed-off-by: John Nunley --- src/platform_impl/linux/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 9fbc3e8912..f73157dabd 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -626,7 +626,7 @@ unsafe extern "C" fn x_error_callback( display: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent, ) -> c_int { - let xconn_lock = X11_BACKEND.lock().unwrap(); + let xconn_lock = X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner()); if let Ok(ref xconn) = *xconn_lock { // Call all the hooks. let mut error_handled = false; @@ -748,7 +748,7 @@ impl EventLoop { #[cfg(x11_platform)] fn new_x11_any_thread() -> Result { - let xconn = match X11_BACKEND.lock().unwrap().as_ref() { + let xconn = match X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner()).as_ref() { Ok(xconn) => xconn.clone(), Err(_) => return Err(EventLoopError::NotSupported(NotSupportedError::new())), }; From aee95114db9c90eef6f4d895790552791cf41ab9 Mon Sep 17 00:00:00 2001 From: John Nunley Date: Thu, 22 Aug 2024 19:25:20 -0700 Subject: [PATCH 06/12] m: Replace libxcursor with custom cursor code Another one bites the dust. This replaces the code dependent on libxcursor with equivalent code written using x11rb, featuring its special "cursor" module. cc #3198 Signed-off-by: John Nunley --- Cargo.toml | 1 + src/changelog/unreleased.md | 1 + src/platform_impl/linux/x11/ffi.rs | 1 - src/platform_impl/linux/x11/mod.rs | 6 + src/platform_impl/linux/x11/util/cursor.rs | 234 +++++++++++++-------- src/platform_impl/linux/x11/window.rs | 22 +- src/platform_impl/linux/x11/xdisplay.rs | 35 ++- 7 files changed, 201 insertions(+), 99 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 00568aaa46..ea54b49b27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -257,6 +257,7 @@ wayland-protocols-plasma = { version = "0.3.2", features = ["client"], optional x11-dl = { version = "2.19.1", optional = true } x11rb = { version = "0.13.0", default-features = false, features = [ "allow-unsafe-code", + "cursor", "dl-libxcb", "randr", "resource_manager", diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index afa776260e..18f9e89351 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -102,6 +102,7 @@ changelog entry. application delegate yourself. - On iOS, no longer act as-if the application successfully open all URLs. Override `application:didFinishLaunchingWithOptions:` and provide the desired behaviour yourself. +- On X11, remove our dependency on libXcursor. (#3749) ### Removed diff --git a/src/platform_impl/linux/x11/ffi.rs b/src/platform_impl/linux/x11/ffi.rs index 57bd78e95d..6895f19238 100644 --- a/src/platform_impl/linux/x11/ffi.rs +++ b/src/platform_impl/linux/x11/ffi.rs @@ -1,5 +1,4 @@ pub use x11_dl::error::OpenError; -pub use x11_dl::xcursor::*; pub use x11_dl::xinput2::*; pub use x11_dl::xlib::*; pub use x11_dl::xlib_xcb::*; diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index c2d3041e89..bab0bec427 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -906,6 +906,9 @@ pub enum X11Error { /// Failed to get property. GetProperty(util::GetPropertyError), + + /// Could not find an ARGB32 pict format. + NoArgb32Format, } impl fmt::Display for X11Error { @@ -930,6 +933,9 @@ impl fmt::Display for X11Error { X11Error::XsettingsParse(err) => { write!(f, "Failed to parse xsettings: {:?}", err) }, + X11Error::NoArgb32Format => { + f.write_str("winit only supports X11 displays with ARGB32 picture formats") + }, } } } diff --git a/src/platform_impl/linux/x11/util/cursor.rs b/src/platform_impl/linux/x11/util/cursor.rs index 717217a8eb..36e35ccdb8 100644 --- a/src/platform_impl/linux/x11/util/cursor.rs +++ b/src/platform_impl/linux/x11/util/cursor.rs @@ -1,9 +1,11 @@ -use std::ffi::CString; +use std::collections::hash_map::Entry; use std::hash::{Hash, Hasher}; +use std::iter; use std::sync::Arc; -use std::{iter, slice}; use x11rb::connection::Connection; +use x11rb::protocol::render::{self, ConnectionExt as _}; +use x11rb::protocol::xproto; use super::super::ActiveEventLoop; use super::*; @@ -12,81 +14,148 @@ use crate::platform_impl::{OsError, PlatformCustomCursorSource}; use crate::window::CursorIcon; impl XConnection { - pub fn set_cursor_icon(&self, window: xproto::Window, cursor: Option) { - let cursor = *self - .cursor_cache - .lock() - .unwrap() - .entry(cursor) - .or_insert_with(|| self.get_cursor(cursor)); - - self.update_cursor(window, cursor).expect("Failed to set cursor"); - } + pub fn set_cursor_icon( + &self, + window: xproto::Window, + cursor: Option, + ) -> Result<(), X11Error> { + let cursor = { + let mut cache = self.cursor_cache.lock().unwrap_or_else(|e| e.into_inner()); + + match cache.entry(cursor) { + Entry::Occupied(o) => *o.get(), + Entry::Vacant(v) => *v.insert(self.get_cursor(cursor)?), + } + }; - pub(crate) fn set_custom_cursor(&self, window: xproto::Window, cursor: &CustomCursor) { - self.update_cursor(window, cursor.inner.cursor).expect("Failed to set cursor"); + self.update_cursor(window, cursor) } - fn create_empty_cursor(&self) -> ffi::Cursor { - let data = 0; - let pixmap = unsafe { - let screen = (self.xlib.XDefaultScreen)(self.display); - let window = (self.xlib.XRootWindow)(self.display, screen); - (self.xlib.XCreateBitmapFromData)(self.display, window, &data, 1, 1) - }; - - if pixmap == 0 { - panic!("failed to allocate pixmap for cursor"); - } + pub(crate) fn set_custom_cursor( + &self, + window: xproto::Window, + cursor: &CustomCursor, + ) -> Result<(), X11Error> { + self.update_cursor(window, cursor.inner.cursor) + } - unsafe { - // We don't care about this color, since it only fills bytes - // in the pixmap which are not 0 in the mask. - let mut dummy_color = MaybeUninit::uninit(); - let cursor = (self.xlib.XCreatePixmapCursor)( - self.display, - pixmap, - pixmap, - dummy_color.as_mut_ptr(), - dummy_color.as_mut_ptr(), + /// Create a cursor from an image. + fn create_cursor_from_image( + &self, + width: u16, + height: u16, + hotspot_x: u16, + hotspot_y: u16, + image: &[u8], + ) -> Result { + // Create a pixmap for the default root window. + let root = self.default_root().root; + let pixmap = + xproto::PixmapWrapper::create_pixmap(self.xcb_connection(), 32, root, width, height)?; + + // Create a GC to draw with. + let gc = xproto::GcontextWrapper::create_gc( + self.xcb_connection(), + pixmap.pixmap(), + &Default::default(), + )?; + + // Draw the data into it. + self.xcb_connection() + .put_image( + xproto::ImageFormat::Z_PIXMAP, + pixmap.pixmap(), + gc.gcontext(), + width, + height, + 0, 0, 0, - ); - (self.xlib.XFreePixmap)(self.display, pixmap); + 32, + image, + )? + .ignore_error(); + drop(gc); + + // Create the XRender picture. + let picture = render::PictureWrapper::create_picture( + self.xcb_connection(), + pixmap.pixmap(), + self.find_argb32_format()?, + &Default::default(), + )?; + drop(pixmap); + + // Create the cursor. + let cursor = self.xcb_connection().generate_id()?; + self.xcb_connection() + .render_create_cursor(cursor, picture.picture(), hotspot_x, hotspot_y)? + .check()?; - cursor + Ok(cursor) + } + + /// Find the render format that corresponds to ARGB32. + fn find_argb32_format(&self) -> Result { + macro_rules! direct { + ($format:expr, $shift_name:ident, $mask_name:ident, $shift:expr) => {{ + ($format).direct.$shift_name == $shift && ($format).direct.$mask_name == 0xff + }}; } + + self.render_formats() + .formats + .iter() + .find(|format| { + format.type_ == render::PictType::DIRECT + && format.depth == 32 + && direct!(format, red_shift, red_mask, 16) + && direct!(format, green_shift, green_mask, 8) + && direct!(format, blue_shift, blue_mask, 0) + && direct!(format, alpha_shift, alpha_mask, 24) + }) + .ok_or(X11Error::NoArgb32Format) + .map(|format| format.id) + } + + fn create_empty_cursor(&self) -> Result { + self.create_cursor_from_image(1, 1, 0, 0, &[0, 0, 0, 0]) } - fn get_cursor(&self, cursor: Option) -> ffi::Cursor { + fn get_cursor(&self, cursor: Option) -> Result { let cursor = match cursor { Some(cursor) => cursor, None => return self.create_empty_cursor(), }; - let mut xcursor = 0; + let database = self.database(); + let handle = x11rb::cursor::Handle::new( + self.xcb_connection(), + self.default_screen_index(), + &database, + )? + .reply()?; + + let mut last_error = None; for &name in iter::once(&cursor.name()).chain(cursor.alt_names().iter()) { - let name = CString::new(name).unwrap(); - xcursor = unsafe { - (self.xcursor.XcursorLibraryLoadCursor)( - self.display, - name.as_ptr() as *const c_char, - ) - }; - - if xcursor != 0 { - break; + match handle.load_cursor(self.xcb_connection(), name) { + Ok(cursor) => return Ok(cursor), + Err(err) => last_error = Some(err.into()), } } - xcursor + Err(last_error.unwrap()) } - fn update_cursor(&self, window: xproto::Window, cursor: ffi::Cursor) -> Result<(), X11Error> { + fn update_cursor( + &self, + window: xproto::Window, + cursor: xproto::Cursor, + ) -> Result<(), X11Error> { self.xcb_connection() .change_window_attributes( window, - &xproto::ChangeWindowAttributesAux::new().cursor(cursor as xproto::Cursor), + &xproto::ChangeWindowAttributesAux::new().cursor(cursor), )? .ignore_error(); @@ -123,51 +192,44 @@ impl Eq for CustomCursor {} impl CustomCursor { pub(crate) fn new( event_loop: &ActiveEventLoop, - cursor: PlatformCustomCursorSource, + mut cursor: PlatformCustomCursorSource, ) -> Result { - unsafe { - let ximage = (event_loop.xconn.xcursor.XcursorImageCreate)( - cursor.0.width as i32, - cursor.0.height as i32, - ); - if ximage.is_null() { - return Err(ExternalError::Os(os_error!(OsError::Misc( - "`XcursorImageCreate` failed" - )))); - } - (*ximage).xhot = cursor.0.hotspot_x as u32; - (*ximage).yhot = cursor.0.hotspot_y as u32; - (*ximage).delay = 0; - - let dst = slice::from_raw_parts_mut((*ximage).pixels, cursor.0.rgba.len() / 4); - for (dst, chunk) in dst.iter_mut().zip(cursor.0.rgba.chunks_exact(4)) { - *dst = (chunk[0] as u32) << 16 - | (chunk[1] as u32) << 8 - | (chunk[2] as u32) - | (chunk[3] as u32) << 24; + // Reverse RGBA order to BGRA. + cursor.0.rgba.chunks_mut(4).for_each(|chunk| { + let chunk: &mut [u8; 4] = chunk.try_into().unwrap(); + chunk[0..3].reverse(); + + // Byteswap if we need to. + if event_loop.xconn.needs_endian_swap() { + let value = u32::from_ne_bytes(*chunk).swap_bytes(); + *chunk = value.to_ne_bytes(); } - - let cursor = - (event_loop.xconn.xcursor.XcursorImageLoadCursor)(event_loop.xconn.display, ximage); - (event_loop.xconn.xcursor.XcursorImageDestroy)(ximage); - Ok(Self { - inner: Arc::new(CustomCursorInner { xconn: event_loop.xconn.clone(), cursor }), - }) - } + }); + + let cursor = event_loop + .xconn + .create_cursor_from_image( + cursor.0.width, + cursor.0.height, + cursor.0.hotspot_x, + cursor.0.hotspot_y, + &cursor.0.rgba, + ) + .map_err(|err| ExternalError::Os(os_error!(OsError::XError(err.into()))))?; + + Ok(Self { inner: Arc::new(CustomCursorInner { xconn: event_loop.xconn.clone(), cursor }) }) } } #[derive(Debug)] struct CustomCursorInner { xconn: Arc, - cursor: ffi::Cursor, + cursor: xproto::Cursor, } impl Drop for CustomCursorInner { fn drop(&mut self) { - unsafe { - (self.xconn.xlib.XFreeCursor)(self.xconn.display, self.cursor); - } + self.xconn.xcb_connection().free_cursor(self.cursor).map(|r| r.ignore_error()).ok(); } } diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index 31f06fd5c3..f001600fa2 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -1492,13 +1492,17 @@ impl UnownedWindow { #[allow(clippy::mutex_atomic)] if SelectedCursor::Named(icon) != old_cursor && *self.cursor_visible.lock().unwrap() { - self.xconn.set_cursor_icon(self.xwindow, Some(icon)); + if let Err(err) = self.xconn.set_cursor_icon(self.xwindow, Some(icon)) { + tracing::error!("failed to set cursor icon: {err}"); + } } }, Cursor::Custom(RootCustomCursor { inner: PlatformCustomCursor::X(cursor) }) => { #[allow(clippy::mutex_atomic)] if *self.cursor_visible.lock().unwrap() { - self.xconn.set_custom_cursor(self.xwindow, &cursor); + if let Err(err) = self.xconn.set_custom_cursor(self.xwindow, &cursor) { + tracing::error!("failed to set window icon: {err}"); + } } *self.selected_cursor.lock().unwrap() = SelectedCursor::Custom(cursor); @@ -1599,16 +1603,18 @@ impl UnownedWindow { if visible { Some((*self.selected_cursor.lock().unwrap()).clone()) } else { None }; *visible_lock = visible; drop(visible_lock); - match cursor { + let result = match cursor { Some(SelectedCursor::Custom(cursor)) => { - self.xconn.set_custom_cursor(self.xwindow, &cursor); + self.xconn.set_custom_cursor(self.xwindow, &cursor) }, Some(SelectedCursor::Named(cursor)) => { - self.xconn.set_cursor_icon(self.xwindow, Some(cursor)); - }, - None => { - self.xconn.set_cursor_icon(self.xwindow, None); + self.xconn.set_cursor_icon(self.xwindow, Some(cursor)) }, + None => self.xconn.set_cursor_icon(self.xwindow, None), + }; + + if let Err(err) = result { + tracing::error!("failed to set cursor icon: {err}"); } } diff --git a/src/platform_impl/linux/x11/xdisplay.rs b/src/platform_impl/linux/x11/xdisplay.rs index b1b870f313..9494ce633f 100644 --- a/src/platform_impl/linux/x11/xdisplay.rs +++ b/src/platform_impl/linux/x11/xdisplay.rs @@ -6,6 +6,7 @@ use std::{fmt, ptr}; use x11rb::connection::Connection; use x11rb::protocol::randr::ConnectionExt as _; +use x11rb::protocol::render; use x11rb::protocol::xproto::{self, ConnectionExt}; use x11rb::resource_manager; use x11rb::xcb_ffi::XCBConnection; @@ -18,7 +19,6 @@ use crate::window::CursorIcon; /// A connection to an X server. pub struct XConnection { pub xlib: ffi::Xlib, - pub xcursor: ffi::Xcursor, // TODO(notgull): I'd like to remove this, but apparently Xlib and Xinput2 are tied together // for some reason. @@ -55,8 +55,11 @@ pub struct XConnection { /// Atom for the XSettings screen. xsettings_screen: Option, + /// XRender format information. + render_formats: render::QueryPictFormatsReply, + pub latest_error: Mutex>, - pub cursor_cache: Mutex, ffi::Cursor>>, + pub cursor_cache: Mutex, xproto::Cursor>>, } unsafe impl Send for XConnection {} @@ -69,7 +72,6 @@ impl XConnection { pub fn new(error_handler: XErrorHandler) -> Result { // opening the libraries let xlib = ffi::Xlib::open()?; - let xcursor = ffi::Xcursor::open()?; let xlib_xcb = ffi::Xlib_xcb::open()?; let xinput2 = ffi::XInput2::open()?; @@ -118,15 +120,22 @@ impl XConnection { tracing::warn!("error setting XSETTINGS; Xft options won't reload automatically") } + // Start getting the XRender formats. + let formats_cookie = render::query_pict_formats(&xcb) + .map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?; + // Fetch atoms. let atoms = Atoms::new(&xcb) .map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))? .reply() .map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?; + // Finish getting everything else. + let formats = + formats_cookie.reply().map_err(|e| XNotSupported::XcbConversionError(Arc::new(e)))?; + Ok(XConnection { xlib, - xcursor, xinput2, display, xcb: Some(xcb), @@ -138,6 +147,7 @@ impl XConnection { database: RwLock::new(database), cursor_cache: Default::default(), randr_version: (randr_version.major_version, randr_version.minor_version), + render_formats: formats, xsettings_screen, }) } @@ -257,6 +267,23 @@ impl XConnection { pub fn xsettings_screen(&self) -> Option { self.xsettings_screen } + + /// Get the data containing our rendering formats. + #[inline] + pub fn render_formats(&self) -> &render::QueryPictFormatsReply { + &self.render_formats + } + + /// Do we need to do an endian swap? + #[inline] + pub fn needs_endian_swap(&self) -> bool { + #[cfg(target_endian = "big")] + let endian = xproto::ImageOrder::MSB_FIRST; + #[cfg(not(target_endian = "big"))] + let endian = xproto::ImageOrder::LSB_FIRST; + + self.xcb_connection().setup().image_byte_order != endian + } } impl fmt::Debug for XConnection { From e716adcc0a82a4049e58bee957bcd01a18de088a Mon Sep 17 00:00:00 2001 From: John Nunley Date: Fri, 23 Aug 2024 04:47:40 -0700 Subject: [PATCH 07/12] x11: use more information in X11 "not supported" errors This makes it so, when X11 fails to initialize due to not loading a library, it provides more verbose information on what exactly happened. Fixes #3883. Signed-off-by: John Nunley Co-authored-by: Kirill Chibisov --- src/platform_impl/linux/mod.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index f73157dabd..919261976d 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -116,6 +116,8 @@ pub(crate) static X11_BACKEND: Lazy, XNotSupported pub enum OsError { Misc(&'static str), #[cfg(x11_platform)] + XNotSupported(XNotSupported), + #[cfg(x11_platform)] XError(Arc), #[cfg(wayland_platform)] WaylandError(Arc), @@ -126,6 +128,8 @@ impl fmt::Display for OsError { match *self { OsError::Misc(e) => _f.pad(e), #[cfg(x11_platform)] + OsError::XNotSupported(ref e) => fmt::Display::fmt(e, _f), + #[cfg(x11_platform)] OsError::XError(ref e) => fmt::Display::fmt(e, _f), #[cfg(wayland_platform)] OsError::WaylandError(ref e) => fmt::Display::fmt(e, _f), @@ -750,7 +754,9 @@ impl EventLoop { fn new_x11_any_thread() -> Result { let xconn = match X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner()).as_ref() { Ok(xconn) => xconn.clone(), - Err(_) => return Err(EventLoopError::NotSupported(NotSupportedError::new())), + Err(err) => { + return Err(EventLoopError::Os(os_error!(OsError::XNotSupported(err.clone())))) + }, }; Ok(EventLoop::X(x11::EventLoop::new(xconn))) From 241b7a80bba96c91fa3901729cd5dec66abb9be4 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Fri, 23 Aug 2024 23:40:27 +0300 Subject: [PATCH 08/12] api: convert `Window` to `dyn Window` This should allow us to make future split of backends much easier. The `Box` is a _temporary_ solution, which will be removed with the future updates when we decide on how the Window should be stored. --- examples/child_window.rs | 17 +- examples/control_flow.rs | 8 +- examples/pump_events.rs | 8 +- examples/run_on_demand.rs | 10 +- examples/util/fill.rs | 28 +- examples/window.rs | 28 +- examples/x11_embed.rs | 8 +- src/changelog/unreleased.md | 2 + src/cursor.rs | 4 +- src/event_loop.rs | 5 +- src/lib.rs | 6 +- src/platform/android.rs | 8 +- src/platform/ios.rs | 34 +- src/platform/macos.rs | 44 +- src/platform/startup_notify.rs | 17 +- src/platform/wayland.rs | 6 +- src/platform/web.rs | 26 +- src/platform/windows.rs | 83 +- src/platform/x11.rs | 16 +- src/platform_impl/android/mod.rs | 217 +++--- src/platform_impl/apple/appkit/event_loop.rs | 9 +- src/platform_impl/apple/appkit/window.rs | 295 +++++++- src/platform_impl/apple/uikit/event_loop.rs | 7 +- src/platform_impl/apple/uikit/window.rs | 282 ++++++- src/platform_impl/linux/mod.rs | 333 +------- .../linux/wayland/event_loop/mod.rs | 5 +- src/platform_impl/linux/wayland/window/mod.rs | 485 ++++++------ src/platform_impl/linux/x11/mod.rs | 48 +- src/platform_impl/linux/x11/window.rs | 305 +++++++- src/platform_impl/orbital/event_loop.rs | 9 +- src/platform_impl/orbital/window.rs | 204 ++--- .../web/event_loop/window_target.rs | 7 +- src/platform_impl/web/mod.rs | 1 - src/platform_impl/web/monitor.rs | 7 + src/platform_impl/web/window.rs | 456 ++++++----- src/platform_impl/windows/event_loop.rs | 84 +- src/platform_impl/windows/monitor.rs | 12 - src/platform_impl/windows/window.rs | 716 +++++++++--------- src/window.rs | 603 ++++----------- tests/send_objects.rs | 4 +- tests/sync_object.rs | 4 +- 41 files changed, 2314 insertions(+), 2137 deletions(-) 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] From 9419e4e1a739812ac9019901b658e0bf09bc0e6a Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 2 Sep 2024 04:31:45 +0700 Subject: [PATCH 09/12] Fix spelling of "inner" (#3896) --- src/platform_impl/windows/event_loop/runner.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/platform_impl/windows/event_loop/runner.rs b/src/platform_impl/windows/event_loop/runner.rs index f84dde9b31..6b356fa83b 100644 --- a/src/platform_impl/windows/event_loop/runner.rs +++ b/src/platform_impl/windows/event_loop/runner.rs @@ -372,19 +372,19 @@ impl BufferedEvent { match self { Self::Event(event) => dispatch(event), Self::ScaleFactorChanged(window_id, scale_factor, new_inner_size) => { - let user_new_innner_size = Arc::new(Mutex::new(new_inner_size)); + let user_new_inner_size = Arc::new(Mutex::new(new_inner_size)); dispatch(Event::WindowEvent { window_id, event: WindowEvent::ScaleFactorChanged { scale_factor, inner_size_writer: InnerSizeWriter::new(Arc::downgrade( - &user_new_innner_size, + &user_new_inner_size, )), }, }); - let inner_size = *user_new_innner_size.lock().unwrap(); + let inner_size = *user_new_inner_size.lock().unwrap(); - drop(user_new_innner_size); + drop(user_new_inner_size); if inner_size != new_inner_size { let window_flags = unsafe { From d37c591378156c5b245981da3dc05907279b045b Mon Sep 17 00:00:00 2001 From: Tarek Abdel Sater Date: Wed, 4 Sep 2024 16:44:05 +0400 Subject: [PATCH 10/12] macOS: add option to explicitly hide menu/dock in Borderless (#3882) --- src/changelog/unreleased.md | 2 ++ src/platform/macos.rs | 26 +++++++++++++++++++ .../apple/appkit/window_delegate.rs | 25 +++++++++++++++++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index e8b7b1c21e..399c353ac0 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -63,6 +63,8 @@ changelog entry. and `Serialize` on many types. - Add `MonitorHandle::current_video_mode()`. - Add basic iOS IME support. The soft keyboard can now be shown using `Window::set_ime_allowed`. +- On macOS, add `WindowExtMacOS::set_borderless_game` and `WindowAttributesExtMacOS::with_borderless_game` + to fully disable the menu bar and dock in Borderless Fullscreen as commonly done in games. ### Changed diff --git a/src/platform/macos.rs b/src/platform/macos.rs index 6121dbf0c6..d36d5694e9 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -150,6 +150,12 @@ pub trait WindowExtMacOS { /// Getter for the [`WindowExtMacOS::set_option_as_alt`]. fn option_as_alt(&self) -> OptionAsAlt; + + /// Disable the Menu Bar and Dock in Borderless Fullscreen mode. Useful for games. + fn set_borderless_game(&self, borderless_game: bool); + + /// Getter for the [`WindowExtMacOS::set_borderless_game`]. + fn is_borderless_game(&self) -> bool; } impl WindowExtMacOS for dyn Window + '_ { @@ -236,6 +242,18 @@ impl WindowExtMacOS for dyn Window + '_ { let window = self.as_any().downcast_ref::().unwrap(); window.maybe_wait_on_main(|w| w.option_as_alt()) } + + #[inline] + fn set_borderless_game(&self, borderless_game: bool) { + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(|w| w.set_borderless_game(borderless_game)) + } + + #[inline] + fn is_borderless_game(&self) -> bool { + let window = self.as_any().downcast_ref::().unwrap(); + window.maybe_wait_on_main(|w| w.is_borderless_game()) + } } /// Corresponds to `NSApplicationActivationPolicy`. @@ -287,6 +305,8 @@ pub trait WindowAttributesExtMacOS { /// /// See [`WindowExtMacOS::set_option_as_alt`] for details on what this means if set. fn with_option_as_alt(self, option_as_alt: OptionAsAlt) -> Self; + /// See [`WindowExtMacOS::set_borderless_game`] for details on what this means if set. + fn with_borderless_game(self, borderless_game: bool) -> Self; } impl WindowAttributesExtMacOS for WindowAttributes { @@ -355,6 +375,12 @@ impl WindowAttributesExtMacOS for WindowAttributes { self.platform_specific.option_as_alt = option_as_alt; self } + + #[inline] + fn with_borderless_game(mut self, borderless_game: bool) -> Self { + self.platform_specific.borderless_game = borderless_game; + self + } } pub trait EventLoopBuilderExtMacOS { diff --git a/src/platform_impl/apple/appkit/window_delegate.rs b/src/platform_impl/apple/appkit/window_delegate.rs index 6e58171952..7263b4d295 100644 --- a/src/platform_impl/apple/appkit/window_delegate.rs +++ b/src/platform_impl/apple/appkit/window_delegate.rs @@ -56,6 +56,7 @@ pub struct PlatformSpecificWindowAttributes { pub accepts_first_mouse: bool, pub tabbing_identifier: Option, pub option_as_alt: OptionAsAlt, + pub borderless_game: bool, } impl Default for PlatformSpecificWindowAttributes { @@ -73,6 +74,7 @@ impl Default for PlatformSpecificWindowAttributes { accepts_first_mouse: true, tabbing_identifier: None, option_as_alt: Default::default(), + borderless_game: false, } } } @@ -121,6 +123,7 @@ pub(crate) struct State { standard_frame: Cell>, is_simple_fullscreen: Cell, saved_style: Cell>, + is_borderless_game: Cell, } declare_class!( @@ -731,6 +734,7 @@ impl WindowDelegate { standard_frame: Cell::new(None), is_simple_fullscreen: Cell::new(false), saved_style: Cell::new(None), + is_borderless_game: Cell::new(attrs.platform_specific.borderless_game), }); let delegate: Retained = unsafe { msg_send_id![super(delegate), init] }; @@ -1417,7 +1421,7 @@ impl WindowDelegate { } match (old_fullscreen, fullscreen) { - (None, Some(_)) => { + (None, Some(fullscreen)) => { // `toggleFullScreen` doesn't work if the `StyleMask` is none, so we // set a normal style temporarily. The previous state will be // restored in `WindowDelegate::window_did_exit_fullscreen`. @@ -1427,6 +1431,17 @@ impl WindowDelegate { self.set_style_mask(required); self.ivars().saved_style.set(Some(curr_mask)); } + + // In borderless games, we want to disable the dock and menu bar + // by setting the presentation options. We do this here rather than in + // `window:willUseFullScreenPresentationOptions` because for some reason + // the menu bar remains interactable despite being hidden. + if self.is_borderless_game() && matches!(fullscreen, Fullscreen::Borderless(_)) { + let presentation_options = NSApplicationPresentationOptions::NSApplicationPresentationHideDock + | NSApplicationPresentationOptions::NSApplicationPresentationHideMenuBar; + app.setPresentationOptions(presentation_options); + } + toggle_fullscreen(self.window()); }, (Some(Fullscreen::Borderless(_)), None) => { @@ -1813,6 +1828,14 @@ impl WindowExtMacOS for WindowDelegate { fn option_as_alt(&self) -> OptionAsAlt { self.view().option_as_alt() } + + fn set_borderless_game(&self, borderless_game: bool) { + self.ivars().is_borderless_game.set(borderless_game); + } + + fn is_borderless_game(&self) -> bool { + self.ivars().is_borderless_game.get() + } } const DEFAULT_STANDARD_FRAME: NSRect = From 8db3e0e043198c02be997bb01cfd2ccac49e8053 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 4 Sep 2024 15:04:48 +0200 Subject: [PATCH 11/12] Rename "inner size" to "surface size" (#3889) * Rename `WindowEvent::Resized` to `SurfaceResized` * Rename `InnerSizeWriter` to `SurfaceSizeWriter` * Replace `inner_size` with `surface_size` * Rename `resize_increments` to `surface_resize_increments` --- examples/child_window.rs | 4 +- examples/run_on_demand.rs | 2 +- examples/util/fill.rs | 2 +- examples/window.rs | 32 ++-- examples/x11_embed.rs | 2 +- src/changelog/unreleased.md | 17 ++ src/event.rs | 48 +++--- src/monitor.rs | 4 +- src/platform/web.rs | 6 +- src/platform_impl/android/mod.rs | 24 +-- src/platform_impl/apple/appkit/view.rs | 2 +- src/platform_impl/apple/appkit/window.rs | 24 +-- .../apple/appkit/window_delegate.rs | 62 +++---- src/platform_impl/apple/uikit/app_state.rs | 10 +- src/platform_impl/apple/uikit/view.rs | 4 +- src/platform_impl/apple/uikit/window.rs | 58 +++---- .../linux/wayland/event_loop/mod.rs | 18 +- src/platform_impl/linux/wayland/window/mod.rs | 34 ++-- .../linux/wayland/window/state.rs | 54 +++--- .../linux/x11/event_processor.rs | 39 +++-- src/platform_impl/linux/x11/util/geometry.rs | 4 +- src/platform_impl/linux/x11/window.rs | 155 +++++++++--------- src/platform_impl/orbital/event_loop.rs | 4 +- src/platform_impl/orbital/window.rs | 18 +- .../web/event_loop/window_target.rs | 2 +- src/platform_impl/web/web_sys/canvas.rs | 18 +- src/platform_impl/web/window.rs | 18 +- src/platform_impl/windows/event_loop.rs | 32 ++-- .../windows/event_loop/runner.rs | 22 +-- src/platform_impl/windows/window.rs | 35 ++-- src/platform_impl/windows/window_state.rs | 8 +- src/window.rs | 140 ++++++++-------- 32 files changed, 466 insertions(+), 436 deletions(-) diff --git a/examples/child_window.rs b/examples/child_window.rs index 9feb814066..c16d323766 100644 --- a/examples/child_window.rs +++ b/examples/child_window.rs @@ -24,7 +24,7 @@ fn main() -> Result<(), impl std::error::Error> { 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)); + .with_surface_size(LogicalSize::new(640.0f32, 480.0f32)); let window = event_loop.create_window(attributes).unwrap(); println!("Parent window id: {:?})", window.id()); @@ -79,7 +79,7 @@ fn main() -> Result<(), impl std::error::Error> { let parent = parent.raw_window_handle().unwrap(); let mut window_attributes = WindowAttributes::default() .with_title("child window") - .with_inner_size(LogicalSize::new(200.0f32, 200.0f32)) + .with_surface_size(LogicalSize::new(200.0f32, 200.0f32)) .with_position(Position::Logical(LogicalPosition::new(0.0, 0.0))) .with_visible(true); // `with_parent_window` is unsafe. Parent window must be a valid window. diff --git a/examples/run_on_demand.rs b/examples/run_on_demand.rs index ee856e82b3..e6d105ad5e 100644 --- a/examples/run_on_demand.rs +++ b/examples/run_on_demand.rs @@ -31,7 +31,7 @@ fn main() -> Result<(), Box> { fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { let window_attributes = WindowAttributes::default() .with_title("Fantastic window number one!") - .with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0)); + .with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0)); let window = event_loop.create_window(window_attributes).unwrap(); self.window_id = Some(window.id()); self.window = Some(window); diff --git a/examples/util/fill.rs b/examples/util/fill.rs index d953c040e0..446aa38956 100644 --- a/examples/util/fill.rs +++ b/examples/util/fill.rs @@ -72,7 +72,7 @@ mod platform { pub fn fill_window(window: &dyn Window) { GC.with(|gc| { - let size = window.inner_size(); + let size = window.surface_size(); let (Some(width), Some(height)) = (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) else { diff --git a/examples/window.rs b/examples/window.rs index c546fb5d06..719011c1af 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -389,7 +389,7 @@ impl ApplicationHandler for Application { }; match event { - WindowEvent::Resized(size) => { + WindowEvent::SurfaceResized(size) => { window.resize(size); }, WindowEvent::Focused(focused) => { @@ -607,7 +607,7 @@ impl WindowState { let ime = true; window.set_ime_allowed(ime); - let size = window.inner_size(); + let size = window.surface_size(); let mut state = Self { #[cfg(macos_platform)] option_as_alt: window.option_as_alt(), @@ -681,12 +681,12 @@ impl WindowState { /// Toggle resize increments on a window. fn toggle_resize_increments(&mut self) { - let new_increments = match self.window.resize_increments() { + let new_increments = match self.window.surface_resize_increments() { Some(_) => None, None => Some(LogicalSize::new(25.0, 25.0).into()), }; info!("Had increments: {}", new_increments.is_none()); - self.window.set_resize_increments(new_increments); + self.window.set_surface_resize_increments(new_increments); } /// Toggle fullscreen. @@ -725,22 +725,22 @@ impl WindowState { self.window.set_option_as_alt(self.option_as_alt); } - /// Swap the window dimensions with `request_inner_size`. + /// Swap the window dimensions with `request_surface_size`. fn swap_dimensions(&mut self) { - let old_inner_size = self.window.inner_size(); - let mut inner_size = old_inner_size; + let old_surface_size = self.window.surface_size(); + let mut surface_size = old_surface_size; - mem::swap(&mut inner_size.width, &mut inner_size.height); - info!("Requesting resize from {old_inner_size:?} to {inner_size:?}"); + mem::swap(&mut surface_size.width, &mut surface_size.height); + info!("Requesting resize from {old_surface_size:?} to {surface_size:?}"); - if let Some(new_inner_size) = self.window.request_inner_size(inner_size.into()) { - if old_inner_size == new_inner_size { + if let Some(new_surface_size) = self.window.request_surface_size(surface_size.into()) { + if old_surface_size == new_surface_size { info!("Inner size change got ignored"); } else { - self.resize(new_inner_size); + self.resize(new_surface_size); } } else { - info!("Request inner size is asynchronous"); + info!("Requesting surface size is asynchronous"); } } @@ -793,9 +793,9 @@ impl WindowState { Ok(()) } - /// Resize the window to the new size. + /// Resize the surface to the new size. fn resize(&mut self, size: PhysicalSize) { - info!("Resized to {size:?}"); + info!("Surface resized to {size:?}"); #[cfg(not(any(android_platform, ios_platform)))] { let (width, height) = match (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) @@ -840,7 +840,7 @@ impl WindowState { }, }; - let win_size = self.window.inner_size(); + let win_size = self.window.surface_size(); let border_size = BORDER_SIZE * self.window.scale_factor(); let x_direction = if position.x < border_size { diff --git a/examples/x11_embed.rs b/examples/x11_embed.rs index 9f52741016..1b9a796ff6 100644 --- a/examples/x11_embed.rs +++ b/examples/x11_embed.rs @@ -21,7 +21,7 @@ fn main() -> Result<(), Box> { fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { let window_attributes = WindowAttributes::default() .with_title("An embedded window!") - .with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0)) + .with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0)) .with_embed_parent_window(self.parent_window_id); self.window = Some(event_loop.create_window(window_attributes).unwrap()); diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 399c353ac0..6f55ff7f2c 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -107,6 +107,23 @@ changelog entry. - On iOS, no longer act as-if the application successfully open all URLs. Override `application:didFinishLaunchingWithOptions:` and provide the desired behaviour yourself. - On X11, remove our dependency on libXcursor. (#3749) +- Renamed the following APIs to make it clearer that the sizes apply to the underlying surface: + - `WindowEvent::Resized` to `SurfaceResized`. + - `InnerSizeWriter` to `SurfaceSizeWriter`. + - `WindowAttributes.inner_size` to `surface_size`. + - `WindowAttributes.min_inner_size` to `min_surface_size`. + - `WindowAttributes.max_inner_size` to `max_surface_size`. + - `WindowAttributes.resize_increments` to `surface_resize_increments`. + - `WindowAttributes::with_inner_size` to `with_surface_size`. + - `WindowAttributes::with_min_inner_size` to `with_min_surface_size`. + - `WindowAttributes::with_max_inner_size` to `with_max_surface_size`. + - `WindowAttributes::with_resize_increments` to `with_surface_resize_increments`. + - `Window::inner_size` to `surface_size`. + - `Window::request_inner_size` to `request_surface_size`. + - `Window::set_min_inner_size` to `set_min_surface_size`. + - `Window::set_max_inner_size` to `set_max_surface_size`. + + To migrate, you can probably just replace all instances of `inner_size` with `surface_size` in your codebase. ### Removed diff --git a/src/event.rs b/src/event.rs index ec7fd97569..67ee7a53d2 100644 --- a/src/event.rs +++ b/src/event.rs @@ -148,8 +148,13 @@ pub enum WindowEvent { /// [`request_activation_token`]: crate::platform::startup_notify::WindowExtStartupNotify::request_activation_token ActivationTokenDone { serial: AsyncRequestSerial, token: ActivationToken }, - /// The size of the window has changed. Contains the client area's new dimensions. - Resized(PhysicalSize), + /// The size of the window's surface has changed. + /// + /// Contains the new dimensions of the surface (can also be retrieved with + /// [`Window::surface_size`]). + /// + /// [`Window::surface_size`]: crate::window::Window::surface_size + SurfaceResized(PhysicalSize), /// The position of the window has changed. Contains the window's new position. /// @@ -360,16 +365,16 @@ pub enum WindowEvent { /// * Changing the display's scale factor (e.g. in Control Panel on Windows). /// * Moving the window to a display with a different scale factor. /// - /// To update the window size, use the provided [`InnerSizeWriter`] handle. By default, the + /// To update the window size, use the provided [`SurfaceSizeWriter`] handle. By default, the /// window is resized to the value suggested by the OS, but it can be changed to any value. /// /// For more information about DPI in general, see the [`dpi`] crate. ScaleFactorChanged { scale_factor: f64, - /// Handle to update inner size during scale changes. + /// Handle to update surface size during scale changes. /// - /// See [`InnerSizeWriter`] docs for more details. - inner_size_writer: InnerSizeWriter, + /// See [`SurfaceSizeWriter`] docs for more details. + surface_size_writer: SurfaceSizeWriter, }, /// The system window theme has changed. @@ -995,26 +1000,25 @@ pub enum MouseScrollDelta { PixelDelta(PhysicalPosition), } -/// Handle to synchronously change the size of the window from the -/// [`WindowEvent`]. +/// Handle to synchronously change the size of the window from the [`WindowEvent`]. #[derive(Debug, Clone)] -pub struct InnerSizeWriter { - pub(crate) new_inner_size: Weak>>, +pub struct SurfaceSizeWriter { + pub(crate) new_surface_size: Weak>>, } -impl InnerSizeWriter { +impl SurfaceSizeWriter { #[cfg(not(orbital_platform))] - pub(crate) fn new(new_inner_size: Weak>>) -> Self { - Self { new_inner_size } + pub(crate) fn new(new_surface_size: Weak>>) -> Self { + Self { new_surface_size } } - /// Try to request inner size which will be set synchronously on the window. - pub fn request_inner_size( + /// Try to request surface size which will be set synchronously on the window. + pub fn request_surface_size( &mut self, - new_inner_size: PhysicalSize, + new_surface_size: PhysicalSize, ) -> Result<(), ExternalError> { - if let Some(inner) = self.new_inner_size.upgrade() { - *inner.lock().unwrap() = new_inner_size; + if let Some(inner) = self.new_surface_size.upgrade() { + *inner.lock().unwrap() = new_surface_size; Ok(()) } else { Err(ExternalError::Ignored) @@ -1022,13 +1026,13 @@ impl InnerSizeWriter { } } -impl PartialEq for InnerSizeWriter { +impl PartialEq for SurfaceSizeWriter { fn eq(&self, other: &Self) -> bool { - self.new_inner_size.as_ptr() == other.new_inner_size.as_ptr() + self.new_surface_size.as_ptr() == other.new_surface_size.as_ptr() } } -impl Eq for InnerSizeWriter {} +impl Eq for SurfaceSizeWriter {} #[cfg(test)] mod tests { @@ -1066,7 +1070,7 @@ mod tests { with_window_event(Destroyed); with_window_event(Focused(true)); with_window_event(Moved((0, 0).into())); - with_window_event(Resized((0, 0).into())); + with_window_event(SurfaceResized((0, 0).into())); with_window_event(DroppedFile("x.txt".into())); with_window_event(HoveredFile("x.txt".into())); with_window_event(HoveredFileCancelled); diff --git a/src/monitor.rs b/src/monitor.rs index b774314dda..898f9b2003 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -47,9 +47,9 @@ impl Ord for VideoModeHandle { impl VideoModeHandle { /// Returns the resolution of this video mode. This **must not** be used to create your - /// rendering surface. Use [`Window::inner_size()`] instead. + /// rendering surface. Use [`Window::surface_size()`] instead. /// - /// [`Window::inner_size()`]: crate::window::Window::inner_size + /// [`Window::surface_size()`]: crate::window::Window::surface_size #[inline] pub fn size(&self) -> PhysicalSize { self.video_mode.size() diff --git a/src/platform/web.rs b/src/platform/web.rs index a2c5c2651e..b4c93f0c79 100644 --- a/src/platform/web.rs +++ b/src/platform/web.rs @@ -27,14 +27,14 @@ //! - [`padding`](https://developer.mozilla.org/en-US/docs/Web/CSS/padding) //! //! The following APIs can't take them into account and will therefore provide inaccurate results: -//! - [`WindowEvent::Resized`] and [`Window::(set_)inner_size()`] +//! - [`WindowEvent::SurfaceResized`] and [`Window::(set_)surface_size()`] //! - [`WindowEvent::Occluded`] //! - [`WindowEvent::CursorMoved`], [`WindowEvent::CursorEntered`], [`WindowEvent::CursorLeft`], and //! [`WindowEvent::Touch`]. //! - [`Window::set_outer_position()`] //! -//! [`WindowEvent::Resized`]: crate::event::WindowEvent::Resized -//! [`Window::(set_)inner_size()`]: crate::window::Window::inner_size +//! [`WindowEvent::SurfaceResized`]: crate::event::WindowEvent::SurfaceResized +//! [`Window::(set_)surface_size()`]: crate::window::Window::surface_size //! [`WindowEvent::Occluded`]: crate::event::WindowEvent::Occluded //! [`WindowEvent::CursorMoved`]: crate::event::WindowEvent::CursorMoved //! [`WindowEvent::CursorEntered`]: crate::event::WindowEvent::CursorEntered diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 88fa45bba7..1da2a0130d 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -15,7 +15,7 @@ use crate::application::ApplicationHandler; use crate::cursor::Cursor; use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{self, EventLoopError, ExternalError, NotSupportedError}; -use crate::event::{self, Force, InnerSizeWriter, StartCause}; +use crate::event::{self, Force, StartCause, SurfaceSizeWriter}; use crate::event_loop::{ ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, EventLoopProxy as RootEventLoopProxy, OwnedDisplayHandle as RootOwnedDisplayHandle, @@ -201,11 +201,11 @@ impl EventLoop { let old_scale_factor = scale_factor(&self.android_app); let scale_factor = scale_factor(&self.android_app); if (scale_factor - old_scale_factor).abs() < f64::EPSILON { - let new_inner_size = Arc::new(Mutex::new(screen_size(&self.android_app))); + let new_surface_size = Arc::new(Mutex::new(screen_size(&self.android_app))); let window_id = window::WindowId(WindowId); let event = event::WindowEvent::ScaleFactorChanged { - inner_size_writer: InnerSizeWriter::new(Arc::downgrade( - &new_inner_size, + surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade( + &new_surface_size, )), scale_factor, }; @@ -287,7 +287,7 @@ impl EventLoop { PhysicalSize::new(0, 0) }; let window_id = window::WindowId(WindowId); - let event = event::WindowEvent::Resized(size); + let event = event::WindowEvent::SurfaceResized(size); app.window_event(&self.window_target, window_id, event); } @@ -808,27 +808,27 @@ impl CoreWindow for Window { // no effect } - fn inner_size(&self) -> PhysicalSize { + fn surface_size(&self) -> PhysicalSize { self.outer_size() } - fn request_inner_size(&self, _size: Size) -> Option> { - Some(self.inner_size()) + fn request_surface_size(&self, _size: Size) -> Option> { + Some(self.surface_size()) } fn outer_size(&self) -> PhysicalSize { screen_size(&self.app) } - fn set_min_inner_size(&self, _: Option) {} + fn set_min_surface_size(&self, _: Option) {} - fn set_max_inner_size(&self, _: Option) {} + fn set_max_surface_size(&self, _: Option) {} - fn resize_increments(&self) -> Option> { + fn surface_resize_increments(&self) -> Option> { None } - fn set_resize_increments(&self, _increments: Option) {} + fn set_surface_resize_increments(&self, _increments: Option) {} fn set_title(&self, _title: &str) {} diff --git a/src/platform_impl/apple/appkit/view.rs b/src/platform_impl/apple/appkit/view.rs index 9392a283fc..0ba46a6338 100644 --- a/src/platform_impl/apple/appkit/view.rs +++ b/src/platform_impl/apple/appkit/view.rs @@ -198,7 +198,7 @@ declare_class!( // 2. Even when a window resize does occur on a new tabbed window, it contains the wrong size (includes tab height). let logical_size = LogicalSize::new(rect.size.width as f64, rect.size.height as f64); let size = logical_size.to_physical::(self.scale_factor()); - self.queue_event(WindowEvent::Resized(size)); + self.queue_event(WindowEvent::SurfaceResized(size)); } #[method(drawRect:)] diff --git a/src/platform_impl/apple/appkit/window.rs b/src/platform_impl/apple/appkit/window.rs index c4f49ae7fd..11c241dc45 100644 --- a/src/platform_impl/apple/appkit/window.rs +++ b/src/platform_impl/apple/appkit/window.rs @@ -127,32 +127,32 @@ impl CoreWindow for Window { 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 surface_size(&self) -> dpi::PhysicalSize { + self.maybe_wait_on_main(|delegate| delegate.surface_size()) } - fn request_inner_size(&self, size: Size) -> Option> { - self.maybe_wait_on_main(|delegate| delegate.request_inner_size(size)) + fn request_surface_size(&self, size: Size) -> Option> { + self.maybe_wait_on_main(|delegate| delegate.request_surface_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_min_surface_size(&self, min_size: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_min_surface_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 set_max_surface_size(&self, max_size: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_max_surface_size(max_size)); } - fn resize_increments(&self) -> Option> { - self.maybe_wait_on_main(|delegate| delegate.resize_increments()) + fn surface_resize_increments(&self) -> Option> { + self.maybe_wait_on_main(|delegate| delegate.surface_resize_increments()) } - fn set_resize_increments(&self, increments: Option) { - self.maybe_wait_on_main(|delegate| delegate.set_resize_increments(increments)); + fn set_surface_resize_increments(&self, increments: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_surface_resize_increments(increments)); } fn set_title(&self, title: &str) { diff --git a/src/platform_impl/apple/appkit/window_delegate.rs b/src/platform_impl/apple/appkit/window_delegate.rs index 7263b4d295..52ef4759de 100644 --- a/src/platform_impl/apple/appkit/window_delegate.rs +++ b/src/platform_impl/apple/appkit/window_delegate.rs @@ -36,7 +36,7 @@ use super::window::WinitWindow; use super::{ffi, Fullscreen, MonitorHandle, OsError, WindowId}; use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError}; -use crate::event::{InnerSizeWriter, WindowEvent}; +use crate::event::{SurfaceSizeWriter, WindowEvent}; use crate::platform::macos::{OptionAsAlt, WindowExtMacOS}; use crate::window::{ Cursor, CursorGrabMode, Icon, ImePurpose, ResizeDirection, Theme, UserAttentionType, @@ -95,7 +95,7 @@ pub(crate) struct State { previous_scale_factor: Cell, /// The current resize increments for the window content. - resize_increments: Cell, + surface_resize_increments: Cell, /// Whether the window is showing decorations. decorations: Cell, resizable: Cell, @@ -164,7 +164,7 @@ declare_class!( #[method(windowDidResize:)] fn window_did_resize(&self, _: Option<&AnyObject>) { trace_scope!("windowDidResize:"); - // NOTE: WindowEvent::Resized is reported in frameDidChange. + // NOTE: WindowEvent::SurfaceResized is reported in frameDidChange. self.emit_move_event(); } @@ -172,7 +172,7 @@ declare_class!( fn window_will_start_live_resize(&self, _: Option<&AnyObject>) { trace_scope!("windowWillStartLiveResize:"); - let increments = self.ivars().resize_increments.get(); + let increments = self.ivars().surface_resize_increments.get(); self.set_resize_increments_inner(increments); } @@ -505,7 +505,7 @@ fn new_window( let scale_factor = NSScreen::mainScreen(mtm) .map(|screen| screen.backingScaleFactor() as f64) .unwrap_or(1.0); - let size = match attrs.inner_size { + let size = match attrs.surface_size { Some(size) => { let size = size.to_logical(scale_factor); NSSize::new(size.width, size.height) @@ -703,13 +703,15 @@ impl WindowDelegate { None => (), } - let resize_increments = - match attrs.resize_increments.map(|i| i.to_logical(window.backingScaleFactor() as _)) { - Some(LogicalSize { width, height }) if width >= 1. && height >= 1. => { - NSSize::new(width, height) - }, - _ => NSSize::new(1., 1.), - }; + let surface_resize_increments = match attrs + .surface_resize_increments + .map(|i| i.to_logical(window.backingScaleFactor() as _)) + { + Some(LogicalSize { width, height }) if width >= 1. && height >= 1. => { + NSSize::new(width, height) + }, + _ => NSSize::new(1., 1.), + }; let scale_factor = window.backingScaleFactor() as _; @@ -722,7 +724,7 @@ impl WindowDelegate { window: window.retain(), previous_position: Cell::new(None), previous_scale_factor: Cell::new(scale_factor), - resize_increments: Cell::new(resize_increments), + surface_resize_increments: Cell::new(surface_resize_increments), decorations: Cell::new(attrs.decorations), resizable: Cell::new(attrs.resizable), maximized: Cell::new(attrs.maximized), @@ -763,11 +765,11 @@ impl WindowDelegate { delegate.set_blur(attrs.blur); } - if let Some(dim) = attrs.min_inner_size { - delegate.set_min_inner_size(Some(dim)); + if let Some(dim) = attrs.min_surface_size { + delegate.set_min_surface_size(Some(dim)); } - if let Some(dim) = attrs.max_inner_size { - delegate.set_max_inner_size(Some(dim)); + if let Some(dim) = attrs.max_surface_size { + delegate.set_max_surface_size(Some(dim)); } delegate.set_window_level(attrs.window_level); @@ -830,20 +832,20 @@ impl WindowDelegate { let content_size = LogicalSize::new(content_size.width, content_size.height); let suggested_size = content_size.to_physical(scale_factor); - let new_inner_size = Arc::new(Mutex::new(suggested_size)); + let new_surface_size = Arc::new(Mutex::new(suggested_size)); self.queue_event(WindowEvent::ScaleFactorChanged { scale_factor, - inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&new_inner_size)), + surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(&new_surface_size)), }); - let physical_size = *new_inner_size.lock().unwrap(); - drop(new_inner_size); + let physical_size = *new_surface_size.lock().unwrap(); + drop(new_surface_size); if physical_size != suggested_size { let logical_size = physical_size.to_logical(scale_factor); let size = NSSize::new(logical_size.width, logical_size.height); window.setContentSize(size); } - self.queue_event(WindowEvent::Resized(physical_size)); + self.queue_event(WindowEvent::SurfaceResized(physical_size)); } fn emit_move_event(&self) { @@ -944,7 +946,7 @@ impl WindowDelegate { } #[inline] - pub fn inner_size(&self) -> PhysicalSize { + pub fn surface_size(&self) -> PhysicalSize { let content_rect = self.window().contentRectForFrameRect(self.window().frame()); let logical = LogicalSize::new(content_rect.size.width, content_rect.size.height); logical.to_physical(self.scale_factor()) @@ -958,14 +960,14 @@ impl WindowDelegate { } #[inline] - pub fn request_inner_size(&self, size: Size) -> Option> { + pub fn request_surface_size(&self, size: Size) -> Option> { let scale_factor = self.scale_factor(); let size = size.to_logical(scale_factor); self.window().setContentSize(NSSize::new(size.width, size.height)); None } - pub fn set_min_inner_size(&self, dimensions: Option) { + pub fn set_min_surface_size(&self, dimensions: Option) { let dimensions = dimensions.unwrap_or(Size::Logical(LogicalSize { width: 0.0, height: 0.0 })); let min_size = dimensions.to_logical::(self.scale_factor()); @@ -984,7 +986,7 @@ impl WindowDelegate { self.window().setContentSize(current_size); } - pub fn set_max_inner_size(&self, dimensions: Option) { + pub fn set_max_surface_size(&self, dimensions: Option) { let dimensions = dimensions.unwrap_or(Size::Logical(LogicalSize { width: f32::MAX as f64, height: f32::MAX as f64, @@ -1006,8 +1008,8 @@ impl WindowDelegate { self.window().setContentSize(current_size); } - pub fn resize_increments(&self) -> Option> { - let increments = self.ivars().resize_increments.get(); + pub fn surface_resize_increments(&self) -> Option> { + let increments = self.ivars().surface_resize_increments.get(); let (w, h) = (increments.width, increments.height); if w > 1.0 || h > 1.0 { Some(LogicalSize::new(w, h).to_physical(self.scale_factor())) @@ -1016,9 +1018,9 @@ impl WindowDelegate { } } - pub fn set_resize_increments(&self, increments: Option) { + pub fn set_surface_resize_increments(&self, increments: Option) { // XXX the resize increments are only used during live resizes. - self.ivars().resize_increments.set( + self.ivars().surface_resize_increments.set( increments .map(|increments| { let logical = increments.to_logical::(self.scale_factor()); diff --git a/src/platform_impl/apple/uikit/app_state.rs b/src/platform_impl/apple/uikit/app_state.rs index 376f30b827..ef1a73831d 100644 --- a/src/platform_impl/apple/uikit/app_state.rs +++ b/src/platform_impl/apple/uikit/app_state.rs @@ -27,7 +27,7 @@ use super::window::WinitUIWindow; use super::ActiveEventLoop; use crate::application::ApplicationHandler; use crate::dpi::PhysicalSize; -use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent}; +use crate::event::{Event, StartCause, SurfaceSizeWriter, WindowEvent}; use crate::event_loop::ControlFlow; use crate::window::WindowId as RootWindowId; @@ -669,18 +669,18 @@ pub(crate) fn terminated(application: &UIApplication) { fn handle_hidpi_proxy(mtm: MainThreadMarker, event: ScaleFactorChanged) { let ScaleFactorChanged { suggested_size, scale_factor, window } = event; - let new_inner_size = Arc::new(Mutex::new(suggested_size)); + let new_surface_size = Arc::new(Mutex::new(suggested_size)); let event = Event::WindowEvent { window_id: RootWindowId(window.id()), event: WindowEvent::ScaleFactorChanged { scale_factor, - inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&new_inner_size)), + surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(&new_surface_size)), }, }; handle_event(mtm, event); let (view, screen_frame) = get_view_and_screen_frame(&window); - let physical_size = *new_inner_size.lock().unwrap(); - drop(new_inner_size); + let physical_size = *new_surface_size.lock().unwrap(); + drop(new_surface_size); let logical_size = physical_size.to_logical(scale_factor); let size = CGSize::new(logical_size.width, logical_size.height); let new_frame: CGRect = CGRect::new(screen_frame.origin, size); diff --git a/src/platform_impl/apple/uikit/view.rs b/src/platform_impl/apple/uikit/view.rs index 0d601bb97c..20a185b957 100644 --- a/src/platform_impl/apple/uikit/view.rs +++ b/src/platform_impl/apple/uikit/view.rs @@ -93,7 +93,7 @@ declare_class!( mtm, EventWrapper::StaticEvent(Event::WindowEvent { window_id: RootWindowId(window.id()), - event: WindowEvent::Resized(size), + event: WindowEvent::SurfaceResized(size), }), ); } @@ -144,7 +144,7 @@ declare_class!( .chain(std::iter::once(EventWrapper::StaticEvent( Event::WindowEvent { window_id, - event: WindowEvent::Resized(size.to_physical(scale_factor)), + event: WindowEvent::SurfaceResized(size.to_physical(scale_factor)), }, ))), ); diff --git a/src/platform_impl/apple/uikit/window.rs b/src/platform_impl/apple/uikit/window.rs index 3cae4dbf9e..6e01947813 100644 --- a/src/platform_impl/apple/uikit/window.rs +++ b/src/platform_impl/apple/uikit/window.rs @@ -187,7 +187,7 @@ impl Inner { self.window.setBounds(bounds); } - pub fn inner_size(&self) -> PhysicalSize { + pub fn surface_size(&self) -> PhysicalSize { let scale_factor = self.scale_factor(); let safe_area = self.safe_area_screen_space(); let size = LogicalSize { @@ -207,25 +207,25 @@ impl Inner { size.to_physical(scale_factor) } - pub fn request_inner_size(&self, _size: Size) -> Option> { - Some(self.inner_size()) + pub fn request_surface_size(&self, _size: Size) -> Option> { + Some(self.surface_size()) } - pub fn set_min_inner_size(&self, _dimensions: Option) { - warn!("`Window::set_min_inner_size` is ignored on iOS") + pub fn set_min_surface_size(&self, _dimensions: Option) { + warn!("`Window::set_min_surface_size` is ignored on iOS") } - pub fn set_max_inner_size(&self, _dimensions: Option) { - warn!("`Window::set_max_inner_size` is ignored on iOS") + pub fn set_max_surface_size(&self, _dimensions: Option) { + warn!("`Window::set_max_surface_size` is ignored on iOS") } - pub fn resize_increments(&self) -> Option> { + pub fn surface_resize_increments(&self) -> Option> { None } #[inline] - pub fn set_resize_increments(&self, _increments: Option) { - warn!("`Window::set_resize_increments` is ignored on iOS") + pub fn set_surface_resize_increments(&self, _increments: Option) { + warn!("`Window::set_surface_resize_increments` is ignored on iOS") } pub fn set_resizable(&self, _resizable: bool) { @@ -469,11 +469,11 @@ impl Window { ) -> Result { let mtm = event_loop.mtm; - if window_attributes.min_inner_size.is_some() { - warn!("`WindowAttributes::min_inner_size` is ignored on iOS"); + if window_attributes.min_surface_size.is_some() { + warn!("`WindowAttributes::min_surface_size` is ignored on iOS"); } - if window_attributes.max_inner_size.is_some() { - warn!("`WindowAttributes::max_inner_size` is ignored on iOS"); + if window_attributes.max_surface_size.is_some() { + warn!("`WindowAttributes::max_surface_size` is ignored on iOS"); } // TODO: transparency, visible @@ -489,7 +489,7 @@ impl Window { let screen_bounds = screen.bounds(); - let frame = match window_attributes.inner_size { + let frame = match window_attributes.surface_size { Some(dim) => { let scale_factor = screen.scale(); let size = dim.to_logical::(scale_factor as f64); @@ -510,7 +510,7 @@ impl Window { let window = WinitUIWindow::new(mtm, &window_attributes, frame, &view_controller); window.makeKeyAndVisible(); - // Like the Windows and macOS backends, we send a `ScaleFactorChanged` and `Resized` + // Like the Windows and macOS backends, we send a `ScaleFactorChanged` and `SurfaceResized` // event on window creation if the DPI factor != 1.0 let scale_factor = view.contentScaleFactor(); let scale_factor = scale_factor as f64; @@ -534,7 +534,7 @@ impl Window { .chain(std::iter::once(EventWrapper::StaticEvent( Event::WindowEvent { window_id, - event: WindowEvent::Resized(size.to_physical(scale_factor)), + event: WindowEvent::SurfaceResized(size.to_physical(scale_factor)), }, ))), ); @@ -622,32 +622,32 @@ impl CoreWindow for Window { 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 surface_size(&self) -> dpi::PhysicalSize { + self.maybe_wait_on_main(|delegate| delegate.surface_size()) } - fn request_inner_size(&self, size: Size) -> Option> { - self.maybe_wait_on_main(|delegate| delegate.request_inner_size(size)) + fn request_surface_size(&self, size: Size) -> Option> { + self.maybe_wait_on_main(|delegate| delegate.request_surface_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_min_surface_size(&self, min_size: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_min_surface_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 set_max_surface_size(&self, max_size: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_max_surface_size(max_size)); } - fn resize_increments(&self) -> Option> { - self.maybe_wait_on_main(|delegate| delegate.resize_increments()) + fn surface_resize_increments(&self) -> Option> { + self.maybe_wait_on_main(|delegate| delegate.surface_resize_increments()) } - fn set_resize_increments(&self, increments: Option) { - self.maybe_wait_on_main(|delegate| delegate.set_resize_increments(increments)); + fn set_surface_resize_increments(&self, increments: Option) { + self.maybe_wait_on_main(|delegate| delegate.set_surface_resize_increments(increments)); } fn set_title(&self, title: &str) { diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index 4dc6747293..8ccddf803c 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -16,7 +16,7 @@ use crate::application::ApplicationHandler; use crate::cursor::OnlyCursorImage; use crate::dpi::LogicalSize; use crate::error::{EventLoopError, ExternalError, OsError as RootOsError}; -use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent}; +use crate::event::{Event, StartCause, SurfaceSizeWriter, WindowEvent}; use crate::event_loop::{ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents}; use crate::platform::pump_events::PumpStatus; use crate::platform_impl::platform::min_timeout; @@ -317,24 +317,24 @@ impl EventLoop { let windows = state.windows.get_mut(); let window = windows.get(&window_id).unwrap().lock().unwrap(); let scale_factor = window.scale_factor(); - let size = logical_to_physical_rounded(window.inner_size(), scale_factor); + let size = logical_to_physical_rounded(window.surface_size(), scale_factor); (size, scale_factor) }); // Stash the old window size. let old_physical_size = physical_size; - let new_inner_size = Arc::new(Mutex::new(physical_size)); + let new_surface_size = Arc::new(Mutex::new(physical_size)); let root_window_id = crate::window::WindowId(window_id); let event = WindowEvent::ScaleFactorChanged { scale_factor, - inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&new_inner_size)), + surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(&new_surface_size)), }; app.window_event(&self.active_event_loop, root_window_id, event); - let physical_size = *new_inner_size.lock().unwrap(); - drop(new_inner_size); + let physical_size = *new_surface_size.lock().unwrap(); + drop(new_surface_size); // Resize the window when user altered the size. if old_physical_size != physical_size { @@ -344,7 +344,7 @@ impl EventLoop { let new_logical_size: LogicalSize = physical_size.to_logical(scale_factor); - window.request_inner_size(new_logical_size.into()); + window.request_surface_size(new_logical_size.into()); }); // Make it queue resize. @@ -360,7 +360,7 @@ impl EventLoop { let window = windows.get(&window_id).unwrap().lock().unwrap(); let scale_factor = window.scale_factor(); - let size = logical_to_physical_rounded(window.inner_size(), scale_factor); + let size = logical_to_physical_rounded(window.surface_size(), scale_factor); // Mark the window as needed a redraw. state @@ -375,7 +375,7 @@ impl EventLoop { }); let window_id = crate::window::WindowId(window_id); - let event = WindowEvent::Resized(physical_size); + let event = WindowEvent::SurfaceResized(physical_size); app.window_event(&self.active_event_loop, window_id, event); } diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index 1fb97c87f0..814061dd8f 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -89,7 +89,7 @@ impl Window { state.xdg_activation.as_ref().map(|activation_state| activation_state.global().clone()); let display = event_loop_window_target.connection.display(); - let size: Size = attributes.inner_size.unwrap_or(LogicalSize::new(800., 600.).into()); + let size: Size = attributes.surface_size.unwrap_or(LogicalSize::new(800., 600.).into()); // We prefer server side decorations, however to not have decorations we ask for client // side decorations instead. @@ -129,10 +129,10 @@ impl Window { // Set the min and max sizes. We must set the hints upon creating a window, so // we use the default `1.` scaling... - let min_size = attributes.min_inner_size.map(|size| size.to_logical(1.)); - let max_size = attributes.max_inner_size.map(|size| size.to_logical(1.)); - window_state.set_min_inner_size(min_size); - window_state.set_max_inner_size(max_size); + let min_size = attributes.min_surface_size.map(|size| size.to_logical(1.)); + let max_size = attributes.max_surface_size.map(|size| size.to_logical(1.)); + window_state.set_min_surface_size(min_size); + window_state.set_max_surface_size(max_size); // Non-resizable implies that the min and max sizes are set to the same value. window_state.set_resizable(attributes.resizable); @@ -321,15 +321,15 @@ impl CoreWindow for Window { // Not possible. } - fn inner_size(&self) -> PhysicalSize { + fn surface_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) + super::logical_to_physical_rounded(window_state.surface_size(), scale_factor) } - fn request_inner_size(&self, size: Size) -> Option> { + fn request_surface_size(&self, size: Size) -> Option> { let mut window_state = self.window_state.lock().unwrap(); - let new_size = window_state.request_inner_size(size); + let new_size = window_state.request_surface_size(size); self.request_redraw(); Some(new_size) } @@ -340,30 +340,30 @@ impl CoreWindow for Window { super::logical_to_physical_rounded(window_state.outer_size(), scale_factor) } - fn set_min_inner_size(&self, min_size: Option) { + fn set_min_surface_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); + self.window_state.lock().unwrap().set_min_surface_size(min_size); // NOTE: Requires commit to be applied. self.request_redraw(); } - /// Set the maximum inner size for the window. + /// Set the maximum surface size for the window. #[inline] - fn set_max_inner_size(&self, max_size: Option) { + fn set_max_surface_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); + self.window_state.lock().unwrap().set_max_surface_size(max_size); // NOTE: Requires commit to be applied. self.request_redraw(); } - fn resize_increments(&self) -> Option> { + fn surface_resize_increments(&self) -> Option> { None } - fn set_resize_increments(&self, _increments: Option) { - warn!("`set_resize_increments` is not implemented for Wayland"); + fn set_surface_resize_increments(&self, _increments: Option) { + warn!("`set_surface_resize_increments` is not implemented for Wayland"); } fn set_title(&self, title: &str) { diff --git a/src/platform_impl/linux/wayland/window/state.rs b/src/platform_impl/linux/wayland/window/state.rs index 9afff645a8..79c1766b60 100644 --- a/src/platform_impl/linux/wayland/window/state.rs +++ b/src/platform_impl/linux/wayland/window/state.rs @@ -46,7 +46,7 @@ pub type WinitFrame = sctk_adwaita::AdwaitaFrame; #[cfg(not(feature = "sctk-adwaita"))] pub type WinitFrame = sctk::shell::xdg::fallback_frame::FallbackFrame; -// Minimum window inner size. +// Minimum window surface size. const MIN_WINDOW_SIZE: LogicalSize = LogicalSize::new(2, 1); /// The state of the window which is being updated from the [`WinitState`]. @@ -112,7 +112,7 @@ pub struct WindowState { /// The text inputs observed on the window. text_inputs: Vec, - /// The inner size of the window, as in without client side decorations. + /// The surface size of the window, as in without client side decorations. size: LogicalSize, /// Whether the CSD fail to create, so we don't try to create them on each iteration. @@ -122,8 +122,8 @@ pub struct WindowState { decorate: bool, /// Min size. - min_inner_size: LogicalSize, - max_inner_size: Option>, + min_surface_size: LogicalSize, + max_surface_size: Option>, /// The size of the window when no states were applied to it. The primary use for it /// is to fallback to original window size, before it was maximized, if the compositor @@ -197,8 +197,8 @@ impl WindowState { ime_allowed: false, ime_purpose: ImePurpose::Normal, last_configure: None, - max_inner_size: None, - min_inner_size: MIN_WINDOW_SIZE, + max_surface_size: None, + min_surface_size: MIN_WINDOW_SIZE, pointer_constraints, pointers: Default::default(), queue_handle: queue_handle.clone(), @@ -328,7 +328,7 @@ impl WindowState { // Apply configure bounds only when compositor let the user decide what size to pick. if constrain { - let bounds = self.inner_size_bounds(&configure); + let bounds = self.surface_size_bounds(&configure); new_size.width = bounds.0.map(|bound_w| new_size.width.min(bound_w.get())).unwrap_or(new_size.width); new_size.height = bounds @@ -353,7 +353,7 @@ impl WindowState { // NOTE: Set the configure before doing a resize, since we query it during it. self.last_configure = Some(configure); - if state_change_requires_resize || new_size != self.inner_size() { + if state_change_requires_resize || new_size != self.surface_size() { self.resize(new_size); true } else { @@ -361,8 +361,8 @@ impl WindowState { } } - /// Compute the bounds for the inner size of the surface. - fn inner_size_bounds( + /// Compute the bounds for the surface size of the surface. + fn surface_size_bounds( &self, configure: &WindowConfigure, ) -> (Option, Option) { @@ -507,8 +507,8 @@ impl WindowState { // Restore min/max sizes of the window. self.reload_min_max_hints(); } else { - self.set_min_inner_size(Some(self.size)); - self.set_max_inner_size(Some(self.size)); + self.set_min_surface_size(Some(self.size)); + self.set_max_surface_size(Some(self.size)); } // Reload the state on the frame as well. @@ -533,7 +533,7 @@ impl WindowState { /// Get the size of the window. #[inline] - pub fn inner_size(&self) -> LogicalSize { + pub fn surface_size(&self) -> LogicalSize { self.size } @@ -628,21 +628,21 @@ impl WindowState { } /// Try to resize the window when the user can do so. - pub fn request_inner_size(&mut self, inner_size: Size) -> PhysicalSize { + pub fn request_surface_size(&mut self, surface_size: Size) -> PhysicalSize { if self.last_configure.as_ref().map(Self::is_stateless).unwrap_or(true) { - self.resize(inner_size.to_logical(self.scale_factor())) + self.resize(surface_size.to_logical(self.scale_factor())) } - logical_to_physical_rounded(self.inner_size(), self.scale_factor()) + logical_to_physical_rounded(self.surface_size(), self.scale_factor()) } - /// Resize the window to the new inner size. - fn resize(&mut self, inner_size: LogicalSize) { - self.size = inner_size; + /// Resize the window to the new surface size. + fn resize(&mut self, surface_size: LogicalSize) { + self.size = surface_size; // Update the stateless size. if Some(true) == self.last_configure.as_ref().map(Self::is_stateless) { - self.stateless_size = inner_size; + self.stateless_size = surface_size; } // Update the inner frame. @@ -673,7 +673,7 @@ impl WindowState { // Update the target viewport, this is used if and only if fractional scaling is in use. if let Some(viewport) = self.viewport.as_ref() { - // Set inner size without the borders. + // Set surface size without the borders. viewport.set_destination(self.size.width as _, self.size.height as _); } } @@ -753,7 +753,7 @@ impl WindowState { } /// Set maximum inner window size. - pub fn set_min_inner_size(&mut self, size: Option>) { + pub fn set_min_surface_size(&mut self, size: Option>) { // Ensure that the window has the right minimum size. let mut size = size.unwrap_or(MIN_WINDOW_SIZE); size.width = size.width.max(MIN_WINDOW_SIZE.width); @@ -766,12 +766,12 @@ impl WindowState { .map(|frame| frame.add_borders(size.width, size.height).into()) .unwrap_or(size); - self.min_inner_size = size; + self.min_surface_size = size; self.window.set_min_size(Some(size.into())); } /// Set maximum inner window size. - pub fn set_max_inner_size(&mut self, size: Option>) { + pub fn set_max_surface_size(&mut self, size: Option>) { let size = size.map(|size| { self.frame .as_ref() @@ -779,7 +779,7 @@ impl WindowState { .unwrap_or(size) }); - self.max_inner_size = size; + self.max_surface_size = size; self.window.set_max_size(size.map(Into::into)); } @@ -812,8 +812,8 @@ impl WindowState { /// Reload the hints for minimum and maximum sizes. pub fn reload_min_max_hints(&mut self) { - self.set_min_inner_size(Some(self.min_inner_size)); - self.set_max_inner_size(self.max_inner_size); + self.set_min_surface_size(Some(self.min_surface_size)); + self.set_max_surface_size(self.max_surface_size); } /// Set the grabbing state on the surface. diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 09bb02912c..032c417ae1 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -22,8 +22,8 @@ use xkbcommon_dl::xkb_mod_mask_t; use crate::dpi::{PhysicalPosition, PhysicalSize}; use crate::event::{ - DeviceEvent, ElementState, Event, Ime, InnerSizeWriter, MouseButton, MouseScrollDelta, - RawKeyEvent, Touch, TouchPhase, WindowEvent, + DeviceEvent, ElementState, Event, Ime, MouseButton, MouseScrollDelta, RawKeyEvent, + SurfaceSizeWriter, Touch, TouchPhase, WindowEvent, }; use crate::keyboard::ModifiersState; use crate::platform_impl::common::xkb::{self, XkbState}; @@ -598,19 +598,19 @@ impl EventProcessor { // `XSendEvent` (synthetic `ConfigureNotify`) -> position relative to root // `XConfigureNotify` (real `ConfigureNotify`) -> position relative to parent // https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.5 - // We don't want to send `Moved` when this is false, since then every `Resized` + // We don't want to send `Moved` when this is false, since then every `SurfaceResized` // (whether the window moved or not) is accompanied by an extraneous `Moved` event // that has a position relative to the parent window. let is_synthetic = xev.send_event == xlib::True; // These are both in physical space. - let new_inner_size = (xev.width as u32, xev.height as u32); + let new_surface_size = (xev.width as u32, xev.height as u32); let new_inner_position = (xev.x, xev.y); let (mut resized, moved) = { let mut shared_state_lock = window.shared_state_lock(); - let resized = util::maybe_change(&mut shared_state_lock.size, new_inner_size); + let resized = util::maybe_change(&mut shared_state_lock.size, new_surface_size); let moved = if is_synthetic { util::maybe_change(&mut shared_state_lock.inner_position, new_inner_position) } else { @@ -671,7 +671,7 @@ impl EventProcessor { let last_scale_factor = shared_state_lock.last_monitor.scale_factor; let new_scale_factor = { - let window_rect = util::AaRect::new(new_outer_position, new_inner_size); + let window_rect = util::AaRect::new(new_outer_position, new_surface_size); let monitor = self .target .xconn @@ -695,27 +695,30 @@ impl EventProcessor { &shared_state_lock, ); - let old_inner_size = PhysicalSize::new(width, height); - let new_inner_size = PhysicalSize::new(new_width, new_height); + let old_surface_size = PhysicalSize::new(width, height); + let new_surface_size = PhysicalSize::new(new_width, new_height); // Unlock shared state to prevent deadlock in callback below drop(shared_state_lock); - let inner_size = Arc::new(Mutex::new(new_inner_size)); + let surface_size = Arc::new(Mutex::new(new_surface_size)); callback(&self.target, Event::WindowEvent { window_id, event: WindowEvent::ScaleFactorChanged { scale_factor: new_scale_factor, - inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&inner_size)), + surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(&surface_size)), }, }); - let new_inner_size = *inner_size.lock().unwrap(); - drop(inner_size); + let new_surface_size = *surface_size.lock().unwrap(); + drop(surface_size); - if new_inner_size != old_inner_size { - window.request_inner_size_physical(new_inner_size.width, new_inner_size.height); - window.shared_state_lock().dpi_adjusted = Some(new_inner_size.into()); + if new_surface_size != old_surface_size { + window.request_surface_size_physical( + new_surface_size.width, + new_surface_size.height, + ); + window.shared_state_lock().dpi_adjusted = Some(new_surface_size.into()); // if the DPI factor changed, force a resize event to ensure the logical // size is computed with the right DPI factor resized = true; @@ -736,13 +739,13 @@ impl EventProcessor { // XResizeWindow requests, making Xorg, the winit client, and the WM // consume 100% of CPU. if let Some(adjusted_size) = shared_state_lock.dpi_adjusted { - if new_inner_size == adjusted_size || !util::wm_name_is_one_of(&["Xfwm4"]) { + if new_surface_size == adjusted_size || !util::wm_name_is_one_of(&["Xfwm4"]) { // When this finally happens, the event will not be synthetic. shared_state_lock.dpi_adjusted = None; } else { // Unlock shared state to prevent deadlock in callback below drop(shared_state_lock); - window.request_inner_size_physical(adjusted_size.0, adjusted_size.1); + window.request_surface_size_physical(adjusted_size.0, adjusted_size.1); } } @@ -757,7 +760,7 @@ impl EventProcessor { if resized { callback(&self.target, Event::WindowEvent { window_id, - event: WindowEvent::Resized(new_inner_size.into()), + event: WindowEvent::SurfaceResized(new_surface_size.into()), }); } } diff --git a/src/platform_impl/linux/x11/util/geometry.rs b/src/platform_impl/linux/x11/util/geometry.rs index 63ec564730..70a286b81a 100644 --- a/src/platform_impl/linux/x11/util/geometry.rs +++ b/src/platform_impl/linux/x11/util/geometry.rs @@ -76,7 +76,7 @@ impl FrameExtentsHeuristic { } } - pub fn inner_size_to_outer(&self, width: u32, height: u32) -> (u32, u32) { + pub fn surface_size_to_outer(&self, width: u32, height: u32) -> (u32, u32) { ( width.saturating_add( self.frame_extents.left.saturating_add(self.frame_extents.right) as _ @@ -98,7 +98,7 @@ impl XConnection { self.xcb_connection().translate_coordinates(window, root, 0, 0)?.reply().map_err(Into::into) } - // This is adequate for inner_size + // This is adequate for surface_size pub fn get_geometry( &self, window: xproto::Window, diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index 8ace7dd0fa..c56e5f7080 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -23,7 +23,7 @@ use super::{ use crate::cursor::{Cursor, CustomCursor as RootCustomCursor}; use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError}; -use crate::event::{Event, InnerSizeWriter, WindowEvent}; +use crate::event::{Event, SurfaceSizeWriter, WindowEvent}; use crate::event_loop::AsyncRequestSerial; use crate::platform::x11::WindowType; use crate::platform_impl::x11::atoms::*; @@ -94,32 +94,32 @@ impl CoreWindow for Window { self.0.set_outer_position(position) } - fn inner_size(&self) -> PhysicalSize { - self.0.inner_size() + fn surface_size(&self) -> PhysicalSize { + self.0.surface_size() } - fn request_inner_size(&self, size: Size) -> Option> { - self.0.request_inner_size(size) + fn request_surface_size(&self, size: Size) -> Option> { + self.0.request_surface_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_min_surface_size(&self, min_size: Option) { + self.0.set_min_surface_size(min_size) } - fn set_max_inner_size(&self, max_size: Option) { - self.0.set_max_inner_size(max_size) + fn set_max_surface_size(&self, max_size: Option) { + self.0.set_max_surface_size(max_size) } - fn resize_increments(&self) -> Option> { - self.0.resize_increments() + fn surface_resize_increments(&self) -> Option> { + self.0.surface_resize_increments() } - fn set_resize_increments(&self, increments: Option) { - self.0.set_resize_increments(increments) + fn set_surface_resize_increments(&self, increments: Option) { + self.0.set_surface_resize_increments(increments) } fn set_title(&self, title: &str) { @@ -356,9 +356,9 @@ pub struct SharedState { // Used to restore video mode after exiting fullscreen pub desktop_video_mode: Option<(randr::Crtc, randr::Mode)>, pub frame_extents: Option, - pub min_inner_size: Option, - pub max_inner_size: Option, - pub resize_increments: Option, + pub min_surface_size: Option, + pub max_surface_size: Option, + pub surface_resize_increments: Option, pub base_size: Option, pub visibility: Visibility, pub has_focus: bool, @@ -396,9 +396,9 @@ impl SharedState { restore_position: None, desktop_video_mode: None, frame_extents: None, - min_inner_size: None, - max_inner_size: None, - resize_increments: None, + min_surface_size: None, + max_surface_size: None, + surface_resize_increments: None, base_size: None, has_focus: false, cursor_hittest: None, @@ -479,10 +479,10 @@ impl UnownedWindow { info!("Guessed window scale factor: {}", scale_factor); - let max_inner_size: Option<(u32, u32)> = - window_attrs.max_inner_size.map(|size| size.to_physical::(scale_factor).into()); - let min_inner_size: Option<(u32, u32)> = - window_attrs.min_inner_size.map(|size| size.to_physical::(scale_factor).into()); + let max_surface_size: Option<(u32, u32)> = + window_attrs.max_surface_size.map(|size| size.to_physical::(scale_factor).into()); + let min_surface_size: Option<(u32, u32)> = + window_attrs.min_surface_size.map(|size| size.to_physical::(scale_factor).into()); let position = window_attrs.position.map(|position| position.to_physical::(scale_factor)); @@ -491,16 +491,16 @@ impl UnownedWindow { // x11 only applies constraints when the window is actively resized // by the user, so we have to manually apply the initial constraints let mut dimensions: (u32, u32) = window_attrs - .inner_size + .surface_size .map(|size| size.to_physical::(scale_factor)) .or_else(|| Some((800, 600).into())) .map(Into::into) .unwrap(); - if let Some(max) = max_inner_size { + if let Some(max) = max_surface_size { dimensions.0 = cmp::min(dimensions.0, max.0); dimensions.1 = cmp::min(dimensions.1, max.1); } - if let Some(min) = min_inner_size { + if let Some(min) = min_surface_size { dimensions.0 = cmp::max(dimensions.0, min.0); dimensions.1 = cmp::max(dimensions.1, min.1); } @@ -717,24 +717,24 @@ impl UnownedWindow { .ignore_error(); // Set size hints. - let mut min_inner_size = - window_attrs.min_inner_size.map(|size| size.to_physical::(scale_factor)); - let mut max_inner_size = - window_attrs.max_inner_size.map(|size| size.to_physical::(scale_factor)); + let mut min_surface_size = + window_attrs.min_surface_size.map(|size| size.to_physical::(scale_factor)); + let mut max_surface_size = + window_attrs.max_surface_size.map(|size| size.to_physical::(scale_factor)); if !window_attrs.resizable { if util::wm_name_is_one_of(&["Xfwm4"]) { warn!("To avoid a WM bug, disabling resizing has no effect on Xfwm4"); } else { - max_inner_size = Some(dimensions.into()); - min_inner_size = Some(dimensions.into()); + max_surface_size = Some(dimensions.into()); + min_surface_size = Some(dimensions.into()); } } let shared_state = window.shared_state.get_mut().unwrap(); - shared_state.min_inner_size = min_inner_size.map(Into::into); - shared_state.max_inner_size = max_inner_size.map(Into::into); - shared_state.resize_increments = window_attrs.resize_increments; + shared_state.min_surface_size = min_surface_size.map(Into::into); + shared_state.max_surface_size = max_surface_size.map(Into::into); + shared_state.surface_resize_increments = window_attrs.surface_resize_increments; shared_state.base_size = window_attrs.platform_specific.x11.base_size; let normal_hints = WmSizeHints { @@ -746,10 +746,10 @@ impl UnownedWindow { cast_dimension_to_hint(dimensions.0), cast_dimension_to_hint(dimensions.1), )), - max_size: max_inner_size.map(cast_physical_size_to_hint), - min_size: min_inner_size.map(cast_physical_size_to_hint), + max_size: max_surface_size.map(cast_physical_size_to_hint), + min_size: min_surface_size.map(cast_physical_size_to_hint), size_increment: window_attrs - .resize_increments + .surface_resize_increments .map(|size| cast_size_to_hint(size, scale_factor)), base_size: window_attrs .platform_specific @@ -1210,7 +1210,7 @@ impl UnownedWindow { // Check if the self is on this monitor let monitor = self.shared_state_lock().last_monitor.clone(); if monitor.name == new_monitor.name { - let (width, height) = self.inner_size_physical(); + let (width, height) = self.surface_size_physical(); let (new_width, new_height) = self.adjust_for_dpi( // If we couldn't determine the previous scale // factor (e.g., because all monitors were closed @@ -1224,22 +1224,22 @@ impl UnownedWindow { ); let window_id = crate::window::WindowId(self.id()); - let old_inner_size = PhysicalSize::new(width, height); - let inner_size = Arc::new(Mutex::new(PhysicalSize::new(new_width, new_height))); + let old_surface_size = PhysicalSize::new(width, height); + let surface_size = Arc::new(Mutex::new(PhysicalSize::new(new_width, new_height))); callback(Event::WindowEvent { window_id, event: WindowEvent::ScaleFactorChanged { scale_factor: new_monitor.scale_factor, - inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&inner_size)), + surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(&surface_size)), }, }); - let new_inner_size = *inner_size.lock().unwrap(); - drop(inner_size); + let new_surface_size = *surface_size.lock().unwrap(); + drop(surface_size); - if new_inner_size != old_inner_size { - let (new_width, new_height) = new_inner_size.into(); - self.request_inner_size_physical(new_width, new_height); + if new_surface_size != old_surface_size { + let (new_width, new_height) = new_surface_size.into(); + self.request_surface_size_physical(new_width, new_height); } } } @@ -1559,7 +1559,7 @@ impl UnownedWindow { self.set_position_physical(x, y); } - pub(crate) fn inner_size_physical(&self) -> (u32, u32) { + pub(crate) fn surface_size_physical(&self) -> (u32, u32) { // This should be okay to unwrap since the only error XGetGeometry can return // is BadWindow, and if the window handle is bad we have bigger problems. self.xconn @@ -1569,23 +1569,23 @@ impl UnownedWindow { } #[inline] - pub fn inner_size(&self) -> PhysicalSize { - self.inner_size_physical().into() + pub fn surface_size(&self) -> PhysicalSize { + self.surface_size_physical().into() } #[inline] pub fn outer_size(&self) -> PhysicalSize { let extents = self.shared_state_lock().frame_extents.clone(); if let Some(extents) = extents { - let (width, height) = self.inner_size_physical(); - extents.inner_size_to_outer(width, height).into() + let (width, height) = self.surface_size_physical(); + extents.surface_size_to_outer(width, height).into() } else { self.update_cached_frame_extents(); self.outer_size() } } - pub(crate) fn request_inner_size_physical(&self, width: u32, height: u32) { + pub(crate) fn request_surface_size_physical(&self, width: u32, height: u32) { self.xconn .xcb_connection() .configure_window( @@ -1601,7 +1601,7 @@ impl UnownedWindow { } #[inline] - pub fn request_inner_size(&self, size: Size) -> Option> { + pub fn request_surface_size(&self, size: Size) -> Option> { let scale_factor = self.scale_factor(); let size = size.to_physical::(scale_factor).into(); if !self.shared_state_lock().is_resizable { @@ -1611,7 +1611,7 @@ impl UnownedWindow { }) .expect("Failed to call `XSetWMNormalHints`"); } - self.request_inner_size_physical(size.0 as u32, size.1 as u32); + self.request_surface_size_physical(size.0 as u32, size.1 as u32); None } @@ -1638,7 +1638,7 @@ impl UnownedWindow { Ok(()) } - pub(crate) fn set_min_inner_size_physical(&self, dimensions: Option<(u32, u32)>) { + pub(crate) fn set_min_surface_size_physical(&self, dimensions: Option<(u32, u32)>) { self.update_normal_hints(|normal_hints| { normal_hints.min_size = dimensions.map(|(w, h)| (cast_dimension_to_hint(w), cast_dimension_to_hint(h))) @@ -1647,14 +1647,14 @@ impl UnownedWindow { } #[inline] - pub fn set_min_inner_size(&self, dimensions: Option) { - self.shared_state_lock().min_inner_size = dimensions; + pub fn set_min_surface_size(&self, dimensions: Option) { + self.shared_state_lock().min_surface_size = dimensions; let physical_dimensions = dimensions.map(|dimensions| dimensions.to_physical::(self.scale_factor()).into()); - self.set_min_inner_size_physical(physical_dimensions); + self.set_min_surface_size_physical(physical_dimensions); } - pub(crate) fn set_max_inner_size_physical(&self, dimensions: Option<(u32, u32)>) { + pub(crate) fn set_max_surface_size_physical(&self, dimensions: Option<(u32, u32)>) { self.update_normal_hints(|normal_hints| { normal_hints.max_size = dimensions.map(|(w, h)| (cast_dimension_to_hint(w), cast_dimension_to_hint(h))) @@ -1663,15 +1663,15 @@ impl UnownedWindow { } #[inline] - pub fn set_max_inner_size(&self, dimensions: Option) { - self.shared_state_lock().max_inner_size = dimensions; + pub fn set_max_surface_size(&self, dimensions: Option) { + self.shared_state_lock().max_surface_size = dimensions; let physical_dimensions = dimensions.map(|dimensions| dimensions.to_physical::(self.scale_factor()).into()); - self.set_max_inner_size_physical(physical_dimensions); + self.set_max_surface_size_physical(physical_dimensions); } #[inline] - pub fn resize_increments(&self) -> Option> { + pub fn surface_resize_increments(&self) -> Option> { WmSizeHints::get( self.xconn.xcb_connection(), self.xwindow as xproto::Window, @@ -1685,8 +1685,8 @@ impl UnownedWindow { } #[inline] - pub fn set_resize_increments(&self, increments: Option) { - self.shared_state_lock().resize_increments = increments; + pub fn set_surface_resize_increments(&self, increments: Option) { + self.shared_state_lock().surface_resize_increments = increments; let physical_increments = increments.map(|increments| cast_size_to_hint(increments, self.scale_factor())); self.update_normal_hints(|hints| hints.size_increment = physical_increments) @@ -1704,14 +1704,15 @@ impl UnownedWindow { let scale_factor = new_scale_factor / old_scale_factor; self.update_normal_hints(|normal_hints| { let dpi_adjuster = |size: Size| -> (i32, i32) { cast_size_to_hint(size, scale_factor) }; - let max_size = shared_state.max_inner_size.map(dpi_adjuster); - let min_size = shared_state.min_inner_size.map(dpi_adjuster); - let resize_increments = shared_state.resize_increments.map(dpi_adjuster); + let max_size = shared_state.max_surface_size.map(dpi_adjuster); + let min_size = shared_state.min_surface_size.map(dpi_adjuster); + let surface_resize_increments = + shared_state.surface_resize_increments.map(dpi_adjuster); let base_size = shared_state.base_size.map(dpi_adjuster); normal_hints.max_size = max_size; normal_hints.min_size = min_size; - normal_hints.size_increment = resize_increments; + normal_hints.size_increment = surface_resize_increments; normal_hints.base_size = base_size; }) .expect("Failed to update normal hints"); @@ -1734,9 +1735,9 @@ impl UnownedWindow { let (min_size, max_size) = if resizable { let shared_state_lock = self.shared_state_lock(); - (shared_state_lock.min_inner_size, shared_state_lock.max_inner_size) + (shared_state_lock.min_surface_size, shared_state_lock.max_surface_size) } else { - let window_size = Some(Size::from(self.inner_size())); + let window_size = Some(Size::from(self.surface_size())); (window_size, window_size) }; self.shared_state_lock().is_resizable = resizable; @@ -1745,11 +1746,11 @@ impl UnownedWindow { .expect_then_ignore_error("Failed to call `XSetWMNormalHints`"); let scale_factor = self.scale_factor(); - let min_inner_size = min_size.map(|size| cast_size_to_hint(size, scale_factor)); - let max_inner_size = max_size.map(|size| cast_size_to_hint(size, scale_factor)); + let min_surface_size = min_size.map(|size| cast_size_to_hint(size, scale_factor)); + let max_surface_size = max_size.map(|size| cast_size_to_hint(size, scale_factor)); self.update_normal_hints(|normal_hints| { - normal_hints.min_size = min_inner_size; - normal_hints.max_size = max_inner_size; + normal_hints.min_size = min_surface_size; + normal_hints.max_size = max_surface_size; }) .expect("Failed to call `XSetWMNormalHints`"); } @@ -1946,7 +1947,7 @@ impl UnownedWindow { pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> { let mut rectangles: Vec = Vec::new(); if hittest { - let size = self.inner_size(); + let size = self.surface_size(); rectangles.push(Rectangle { x: 0, y: 0, diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index 7c6f43e67a..11a44f05b6 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -476,7 +476,7 @@ impl EventLoop { app.window_event( window_target, RootWindowId(window_id), - event::WindowEvent::Resized((width, height).into()), + event::WindowEvent::SurfaceResized((width, height).into()), ); // Acknowledge resize after event loop. @@ -523,7 +523,7 @@ impl EventLoop { let window_id = RootWindowId(window_id); // Send resize event on create to indicate first size. - let event = event::WindowEvent::Resized((properties.w, properties.h).into()); + let event = event::WindowEvent::SurfaceResized((properties.w, properties.h).into()); app.window_event(&self.window_target, window_id, event); // Send moved event on create to indicate first position. diff --git a/src/platform_impl/orbital/window.rs b/src/platform_impl/orbital/window.rs index 3530281dea..c23cd88efa 100644 --- a/src/platform_impl/orbital/window.rs +++ b/src/platform_impl/orbital/window.rs @@ -42,13 +42,13 @@ impl Window { (-1, -1) }; - let (w, h): (u32, u32) = if let Some(size) = attrs.inner_size { + let (w, h): (u32, u32) = if let Some(size) = attrs.surface_size { size.to_physical::(scale).into() } else { (1024, 768) }; - // TODO: min/max inner_size + // TODO: min/max surface_size // Async by default. let mut flag_str = ORBITAL_FLAG_ASYNC.to_string(); @@ -225,7 +225,7 @@ impl CoreWindow for Window { } #[inline] - fn inner_size(&self) -> PhysicalSize { + fn surface_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); @@ -233,7 +233,7 @@ impl CoreWindow for Window { } #[inline] - fn request_inner_size(&self, size: Size) -> Option> { + fn request_surface_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 @@ -242,14 +242,14 @@ impl CoreWindow for Window { #[inline] fn outer_size(&self) -> PhysicalSize { // TODO: adjust for window decorations - self.inner_size() + self.surface_size() } #[inline] - fn set_min_inner_size(&self, _: Option) {} + fn set_min_surface_size(&self, _: Option) {} #[inline] - fn set_max_inner_size(&self, _: Option) {} + fn set_max_surface_size(&self, _: Option) {} #[inline] fn title(&self) -> String { @@ -283,12 +283,12 @@ impl CoreWindow for Window { } #[inline] - fn resize_increments(&self) -> Option> { + fn surface_resize_increments(&self) -> Option> { None } #[inline] - fn set_resize_increments(&self, _increments: Option) {} + fn set_surface_resize_increments(&self, _increments: Option) {} #[inline] fn set_resizable(&self, resizeable: bool) { diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 3239f201df..50417b3aef 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -556,7 +556,7 @@ impl ActiveEventLoop { canvas.set_old_size(new_size); runner.send_event(Event::WindowEvent { window_id: RootWindowId(id), - event: WindowEvent::Resized(new_size), + event: WindowEvent::SurfaceResized(new_size), }); canvas.request_animation_frame(); } diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index e7d95d84dc..f5050f4875 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -23,7 +23,7 @@ use super::pointer::PointerHandler; use super::{event, fullscreen, ButtonsState, ResizeScaleHandle}; use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize}; use crate::error::OsError as RootOE; -use crate::event::{Force, InnerSizeWriter, MouseButton, MouseScrollDelta}; +use crate::event::{Force, MouseButton, MouseScrollDelta, SurfaceSizeWriter}; use crate::keyboard::{Key, KeyLocation, ModifiersState, PhysicalKey}; use crate::platform_impl::{Fullscreen, OsError}; use crate::window::{WindowAttributes, WindowId as RootWindowId}; @@ -126,17 +126,17 @@ impl Canvas { current_size: Rc::default(), }; - if let Some(size) = attr.inner_size { + if let Some(size) = attr.surface_size { let size = size.to_logical(super::scale_factor(&common.window)); super::set_canvas_size(&common.document, &common.raw, &common.style, size); } - if let Some(size) = attr.min_inner_size { + if let Some(size) = attr.min_surface_size { let size = size.to_logical(super::scale_factor(&common.window)); super::set_canvas_min_size(&common.document, &common.raw, &common.style, Some(size)); } - if let Some(size) = attr.max_inner_size { + if let Some(size) = attr.max_surface_size { let size = size.to_logical(super::scale_factor(&common.window)); super::set_canvas_max_size(&common.document, &common.raw, &common.style, Some(size)); } @@ -213,7 +213,7 @@ impl Canvas { } #[inline] - pub fn inner_size(&self) -> PhysicalSize { + pub fn surface_size(&self) -> PhysicalSize { self.common.current_size.get() } @@ -504,7 +504,7 @@ impl Canvas { window_id: RootWindowId(self.id), event: crate::event::WindowEvent::ScaleFactorChanged { scale_factor: scale, - inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&new_size)), + surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(&new_size)), }, }); @@ -513,8 +513,8 @@ impl Canvas { }; if current_size != new_size { - // Then we resize the canvas to the new size, a new - // `Resized` event will be sent by the `ResizeObserver`: + // Then we resize the canvas to the new size, a new `SurfaceResized` event will be sent + // by the `ResizeObserver`: let new_size = new_size.to_logical(scale); super::set_canvas_size(self.document(), self.raw(), self.style(), new_size); @@ -530,7 +530,7 @@ impl Canvas { self.set_old_size(new_size); runner.send_event(crate::event::Event::WindowEvent { window_id: RootWindowId(self.id), - event: crate::event::WindowEvent::Resized(new_size), + event: crate::event::WindowEvent::SurfaceResized(new_size), }) } } diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index c3827291d2..239c58e9d5 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -127,11 +127,11 @@ impl RootWindow for Window { }) } - fn inner_size(&self) -> PhysicalSize { - self.inner.queue(|inner| inner.canvas.inner_size()) + fn surface_size(&self) -> PhysicalSize { + self.inner.queue(|inner| inner.canvas.surface_size()) } - fn request_inner_size(&self, size: Size) -> Option> { + fn request_surface_size(&self, size: Size) -> Option> { self.inner.queue(|inner| { let size = size.to_logical(self.scale_factor()); backend::set_canvas_size( @@ -145,11 +145,11 @@ impl RootWindow for Window { } fn outer_size(&self) -> PhysicalSize { - // Note: the canvas element has no window decorations, so this is equal to `inner_size`. - self.inner_size() + // Note: the canvas element has no window decorations, so this is equal to `surface_size`. + self.surface_size() } - fn set_min_inner_size(&self, min_size: Option) { + fn set_min_surface_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( @@ -161,7 +161,7 @@ impl RootWindow for Window { }) } - fn set_max_inner_size(&self, max_size: Option) { + fn set_max_surface_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( @@ -173,11 +173,11 @@ impl RootWindow for Window { }) } - fn resize_increments(&self) -> Option> { + fn surface_resize_increments(&self) -> Option> { None } - fn set_resize_increments(&self, _: Option) { + fn set_surface_resize_increments(&self, _: Option) { // Intentionally a no-op: users can't resize canvas elements } diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index a4e3ef35b9..b63ece77d7 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -58,7 +58,7 @@ use crate::application::ApplicationHandler; use crate::dpi::{PhysicalPosition, PhysicalSize}; use crate::error::{EventLoopError, ExternalError, OsError}; use crate::event::{ - Event, FingerId as RootFingerId, Force, Ime, InnerSizeWriter, RawKeyEvent, Touch, TouchPhase, + Event, FingerId as RootFingerId, Force, Ime, RawKeyEvent, SurfaceSizeWriter, Touch, TouchPhase, WindowEvent, }; use crate::event_loop::{ @@ -1274,14 +1274,14 @@ unsafe fn public_window_callback_inner( }, WM_SIZE => { - use crate::event::WindowEvent::Resized; + use crate::event::WindowEvent::SurfaceResized; let w = super::loword(lparam as u32) as u32; let h = super::hiword(lparam as u32) as u32; let physical_size = PhysicalSize::new(w, h); let event = Event::WindowEvent { window_id: CoreWindowId(WindowId(window)), - event: Resized(physical_size), + event: SurfaceResized(physical_size), }; { @@ -1308,7 +1308,7 @@ unsafe fn public_window_callback_inner( let scale_factor = userdata.window_state_lock().scale_factor; let Some(inc) = userdata .window_state_lock() - .resize_increments + .surface_resize_increments .map(|inc| inc.to_physical(scale_factor)) .filter(|inc| inc.width > 0 && inc.height > 0) else { @@ -2131,7 +2131,7 @@ unsafe fn public_window_callback_inner( // New size as suggested by Windows. let suggested_rect = unsafe { *(lparam as *const RECT) }; - // The window rect provided is the window's outer size, not it's inner size. However, + // The window rect provided is the window's outer size, not it's surface size. However, // win32 doesn't provide an `UnadjustWindowRectEx` function to get the client rect from // the outer rect, so we instead adjust the window rect to get the decoration margins // and remove them from the outer size. @@ -2151,33 +2151,33 @@ unsafe fn public_window_callback_inner( let old_physical_inner_rect = util::WindowArea::Inner .get_rect(window) .expect("failed to query (old) inner window area"); - let old_physical_inner_size = PhysicalSize::new( + let old_physical_surface_size = PhysicalSize::new( (old_physical_inner_rect.right - old_physical_inner_rect.left) as u32, (old_physical_inner_rect.bottom - old_physical_inner_rect.top) as u32, ); // `allow_resize` prevents us from re-applying DPI adjustment to the restored size after // exiting fullscreen (the restored size is already DPI adjusted). - let new_physical_inner_size = match allow_resize { + let new_physical_surface_size = match allow_resize { // We calculate our own size because the default suggested rect doesn't do a great // job of preserving the window's logical size. - true => old_physical_inner_size + true => old_physical_surface_size .to_logical::(old_scale_factor) .to_physical::(new_scale_factor), - false => old_physical_inner_size, + false => old_physical_surface_size, }; - let new_inner_size = Arc::new(Mutex::new(new_physical_inner_size)); + let new_surface_size = Arc::new(Mutex::new(new_physical_surface_size)); userdata.send_event(Event::WindowEvent { window_id: CoreWindowId(WindowId(window)), event: ScaleFactorChanged { scale_factor: new_scale_factor, - inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&new_inner_size)), + surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(&new_surface_size)), }, }); - let new_physical_inner_size = *new_inner_size.lock().unwrap(); - drop(new_inner_size); + let new_physical_surface_size = *new_surface_size.lock().unwrap(); + drop(new_surface_size); let dragging_window: bool; @@ -2186,7 +2186,7 @@ unsafe fn public_window_callback_inner( dragging_window = window_state.window_flags().contains(WindowFlags::MARKER_IN_SIZE_MOVE); // Unset maximized if we're changing the window's size. - if new_physical_inner_size != old_physical_inner_size { + if new_physical_surface_size != old_physical_surface_size { WindowState::set_window_flags(window_state, window, |f| { f.set(WindowFlags::MAXIMIZED, false) }); @@ -2201,8 +2201,8 @@ unsafe fn public_window_callback_inner( let mut conservative_rect = RECT { left: suggested_ul.0, top: suggested_ul.1, - right: suggested_ul.0 + new_physical_inner_size.width as i32, - bottom: suggested_ul.1 + new_physical_inner_size.height as i32, + right: suggested_ul.0 + new_physical_surface_size.width as i32, + bottom: suggested_ul.1 + new_physical_surface_size.height as i32, }; conservative_rect = window_flags diff --git a/src/platform_impl/windows/event_loop/runner.rs b/src/platform_impl/windows/event_loop/runner.rs index 6b356fa83b..d288d6d590 100644 --- a/src/platform_impl/windows/event_loop/runner.rs +++ b/src/platform_impl/windows/event_loop/runner.rs @@ -9,7 +9,7 @@ use windows_sys::Win32::Foundation::HWND; use super::ControlFlow; use crate::dpi::PhysicalSize; -use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent}; +use crate::event::{Event, StartCause, SurfaceSizeWriter, WindowEvent}; use crate::platform_impl::platform::event_loop::{WindowData, GWL_USERDATA}; use crate::platform_impl::platform::get_window_long; use crate::window::WindowId; @@ -357,12 +357,12 @@ impl BufferedEvent { pub fn from_event(event: Event) -> BufferedEvent { match event { Event::WindowEvent { - event: WindowEvent::ScaleFactorChanged { scale_factor, inner_size_writer }, + event: WindowEvent::ScaleFactorChanged { scale_factor, surface_size_writer }, window_id, } => BufferedEvent::ScaleFactorChanged( window_id, scale_factor, - *inner_size_writer.new_inner_size.upgrade().unwrap().lock().unwrap(), + *surface_size_writer.new_surface_size.upgrade().unwrap().lock().unwrap(), ), event => BufferedEvent::Event(event), } @@ -371,29 +371,29 @@ impl BufferedEvent { pub fn dispatch_event(self, dispatch: impl FnOnce(Event)) { match self { Self::Event(event) => dispatch(event), - Self::ScaleFactorChanged(window_id, scale_factor, new_inner_size) => { - let user_new_inner_size = Arc::new(Mutex::new(new_inner_size)); + Self::ScaleFactorChanged(window_id, scale_factor, new_surface_size) => { + let user_new_surface_size = Arc::new(Mutex::new(new_surface_size)); dispatch(Event::WindowEvent { window_id, event: WindowEvent::ScaleFactorChanged { scale_factor, - inner_size_writer: InnerSizeWriter::new(Arc::downgrade( - &user_new_inner_size, + surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade( + &user_new_surface_size, )), }, }); - let inner_size = *user_new_inner_size.lock().unwrap(); + let surface_size = *user_new_surface_size.lock().unwrap(); - drop(user_new_inner_size); + drop(user_new_surface_size); - if inner_size != new_inner_size { + if surface_size != new_surface_size { let window_flags = unsafe { let userdata = get_window_long(window_id.0.into(), GWL_USERDATA) as *mut WindowData; (*userdata).window_state_lock().window_flags }; - window_flags.set_size((window_id.0).0, inner_size); + window_flags.set_size((window_id.0).0, surface_size); } }, } diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 3b4e7439fe..c08cc436ae 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -458,7 +458,7 @@ impl CoreWindow for Window { } } - fn inner_size(&self) -> PhysicalSize { + fn surface_size(&self) -> PhysicalSize { let mut rect: RECT = unsafe { mem::zeroed() }; if unsafe { GetClientRect(self.hwnd(), &mut rect) } == false.into() { panic!( @@ -478,14 +478,14 @@ impl CoreWindow for Window { .unwrap() } - fn request_inner_size(&self, size: Size) -> Option> { + fn request_surface_size(&self, size: Size) -> Option> { let scale_factor = self.scale_factor(); let physical_size = size.to_physical::(scale_factor); let window_flags = self.window_state_lock().window_flags; window_flags.set_size(self.hwnd(), physical_size); - if physical_size != self.inner_size() { + if physical_size != self.surface_size() { let window_state = Arc::clone(&self.window_state); let window = self.window; self.thread_executor.execute_in_thread(move || { @@ -499,28 +499,28 @@ impl CoreWindow for Window { None } - fn set_min_inner_size(&self, size: Option) { + fn set_min_surface_size(&self, size: Option) { self.window_state_lock().min_size = size; // Make windows re-check the window size bounds. - let size = self.inner_size(); - let _ = self.request_inner_size(size.into()); + let size = self.surface_size(); + let _ = self.request_surface_size(size.into()); } - fn set_max_inner_size(&self, size: Option) { + fn set_max_surface_size(&self, size: Option) { self.window_state_lock().max_size = size; // Make windows re-check the window size bounds. - let size = self.inner_size(); - let _ = self.request_inner_size(size.into()); + let size = self.surface_size(); + let _ = self.request_surface_size(size.into()); } - fn resize_increments(&self) -> Option> { + fn surface_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)) + w.surface_resize_increments.map(|size| size.to_physical(scale_factor)) } - fn set_resize_increments(&self, increments: Option) { - self.window_state_lock().resize_increments = increments; + fn set_surface_resize_increments(&self, increments: Option) { + self.window_state_lock().surface_resize_increments = increments; } fn set_resizable(&self, resizable: bool) { @@ -1209,13 +1209,14 @@ impl<'a> InitData<'a> { win.set_enabled_buttons(attributes.enabled_buttons); - let size = attributes.inner_size.unwrap_or_else(|| PhysicalSize::new(800, 600).into()); + let size = attributes.surface_size.unwrap_or_else(|| PhysicalSize::new(800, 600).into()); let max_size = attributes - .max_inner_size + .max_surface_size .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 min_size = + attributes.min_surface_size.unwrap_or_else(|| PhysicalSize::new(0, 0).into()); let clamped_size = Size::clamp(size, min_size, max_size, win.scale_factor()); - let _ = win.request_inner_size(clamped_size); + let _ = win.request_surface_size(clamped_size); // let margins = MARGINS { // cxLeftWidth: 1, diff --git a/src/platform_impl/windows/window_state.rs b/src/platform_impl/windows/window_state.rs index d03ff40709..f84dd2cfdb 100644 --- a/src/platform_impl/windows/window_state.rs +++ b/src/platform_impl/windows/window_state.rs @@ -30,7 +30,7 @@ pub(crate) struct WindowState { pub min_size: Option, pub max_size: Option, - pub resize_increments: Option, + pub surface_resize_increments: Option, pub window_icon: Option, pub taskbar_icon: Option, @@ -151,10 +151,10 @@ impl WindowState { last_position: None, }, - min_size: attributes.min_inner_size, - max_size: attributes.max_inner_size, + min_size: attributes.min_surface_size, + max_size: attributes.max_surface_size, - resize_increments: attributes.resize_increments, + surface_resize_increments: attributes.surface_resize_increments, window_icon: attributes.window_icon.clone(), taskbar_icon: None, diff --git a/src/window.rs b/src/window.rs index 639f956172..6a3dd62539 100644 --- a/src/window.rs +++ b/src/window.rs @@ -57,9 +57,10 @@ impl From for WindowId { /// Attributes used when creating a window. #[derive(Debug, Clone, PartialEq)] pub struct WindowAttributes { - pub inner_size: Option, - pub min_inner_size: Option, - pub max_inner_size: Option, + pub surface_size: Option, + pub min_surface_size: Option, + pub max_surface_size: Option, + pub surface_resize_increments: Option, pub position: Option, pub resizable: bool, pub enabled_buttons: WindowButtons, @@ -71,7 +72,6 @@ pub struct WindowAttributes { pub decorations: bool, pub window_icon: Option, pub preferred_theme: Option, - pub resize_increments: Option, pub content_protected: bool, pub window_level: WindowLevel, pub active: bool, @@ -88,9 +88,10 @@ impl Default for WindowAttributes { #[inline] fn default() -> WindowAttributes { WindowAttributes { - inner_size: None, - min_inner_size: None, - max_inner_size: None, + surface_size: None, + min_surface_size: None, + max_surface_size: None, + surface_resize_increments: None, position: None, resizable: true, enabled_buttons: WindowButtons::all(), @@ -104,7 +105,6 @@ impl Default for WindowAttributes { window_level: Default::default(), window_icon: None, preferred_theme: None, - resize_increments: None, content_protected: false, cursor: Cursor::default(), #[cfg(feature = "rwh_06")] @@ -137,38 +137,51 @@ impl WindowAttributes { self.parent_window.as_ref().map(|handle| &handle.0) } - /// Requests the window to be of specific dimensions. + /// Requests the surface to be of specific dimensions. /// /// If this is not set, some platform-specific dimensions will be used. /// - /// See [`Window::request_inner_size`] for details. + /// See [`Window::request_surface_size`] for details. #[inline] - pub fn with_inner_size>(mut self, size: S) -> Self { - self.inner_size = Some(size.into()); + pub fn with_surface_size>(mut self, size: S) -> Self { + self.surface_size = Some(size.into()); self } - /// Sets the minimum dimensions a window can have. + /// Sets the minimum dimensions the surface can have. /// - /// If this is not set, the window will have no minimum dimensions (aside - /// from reserved). + /// If this is not set, the surface will have no minimum dimensions (aside from reserved). /// - /// See [`Window::set_min_inner_size`] for details. + /// See [`Window::set_min_surface_size`] for details. #[inline] - pub fn with_min_inner_size>(mut self, min_size: S) -> Self { - self.min_inner_size = Some(min_size.into()); + pub fn with_min_surface_size>(mut self, min_size: S) -> Self { + self.min_surface_size = Some(min_size.into()); self } - /// Sets the maximum dimensions a window can have. + /// Sets the maximum dimensions the surface can have. /// - /// If this is not set, the window will have no maximum or will be set to + /// If this is not set, the surface will have no maximum, or the maximum will be restricted to /// the primary monitor's dimensions by the platform. /// - /// See [`Window::set_max_inner_size`] for details. + /// See [`Window::set_max_surface_size`] for details. #[inline] - pub fn with_max_inner_size>(mut self, max_size: S) -> Self { - self.max_inner_size = Some(max_size.into()); + pub fn with_max_surface_size>(mut self, max_size: S) -> Self { + self.max_surface_size = Some(max_size.into()); + self + } + + /// Build window with resize increments hint. + /// + /// The default is `None`. + /// + /// See [`Window::set_surface_resize_increments`] for details. + #[inline] + pub fn with_surface_resize_increments>( + mut self, + surface_resize_increments: S, + ) -> Self { + self.surface_resize_increments = Some(surface_resize_increments.into()); self } @@ -182,7 +195,7 @@ impl WindowAttributes { /// /// - **macOS:** The top left corner position of the window content, the window's "inner" /// position. The window title bar will be placed above it. The window will be positioned such - /// that it fits on screen, maintaining set `inner_size` if any. If you need to precisely + /// that it fits on screen, maintaining set `surface_size` if any. If you need to precisely /// position the top left corner of the whole window you have to use /// [`Window::set_outer_position`] after creating the window. /// - **Windows:** The top left corner position of the window title bar, the window's "outer" @@ -346,17 +359,6 @@ impl WindowAttributes { self } - /// Build window with resize increments hint. - /// - /// The default is `None`. - /// - /// See [`Window::set_resize_increments`] for details. - #[inline] - pub fn with_resize_increments>(mut self, resize_increments: S) -> Self { - self.resize_increments = Some(resize_increments.into()); - self - } - /// Prevents the window contents from being captured by other apps. /// /// The default is `false`. @@ -650,9 +652,9 @@ pub trait Window: AsAny + Send + Sync { /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform fn set_outer_position(&self, position: Position); - /// Returns the physical size of the window's client area. + /// Returns the size of the window's render-able surface. /// - /// The client area is the content of the window, excluding the title bar and borders. + /// This is the dimensions you should pass to things like Wgpu or Glutin when configuring. /// /// ## Platform-specific /// @@ -662,21 +664,21 @@ pub trait Window: AsAny + Send + Sync { /// /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform - fn inner_size(&self) -> PhysicalSize; + fn surface_size(&self) -> PhysicalSize; - /// Request the new size for the window. + /// Request the new size for the surface. /// /// On platforms where the size is entirely controlled by the user the /// applied size will be returned immediately, resize event in such case /// may not be generated. /// - /// On platforms where resizing is disallowed by the windowing system, the current - /// inner size is returned immediately, and the user one is ignored. + /// On platforms where resizing is disallowed by the windowing system, the current surface size + /// is returned immediately, and the user one is ignored. /// /// When `None` is returned, it means that the request went to the display system, - /// and the actual size will be delivered later with the [`WindowEvent::Resized`]. + /// and the actual size will be delivered later with the [`WindowEvent::SurfaceResized`]. /// - /// See [`Window::inner_size`] for more information about the values. + /// See [`Window::surface_size`] for more information about the values. /// /// The request could automatically un-maximize the window if it's maximized. /// @@ -685,10 +687,10 @@ pub trait Window: AsAny + Send + Sync { /// # use winit::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).into()); + /// let _ = window.request_surface_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).into()); + /// let _ = window.request_surface_size(PhysicalSize::new(400, 200).into()); /// # } /// ``` /// @@ -696,72 +698,72 @@ pub trait Window: AsAny + Send + Sync { /// /// - **Web:** Sets the size of the canvas element. Doesn't account for CSS [`transform`]. /// - /// [`WindowEvent::Resized`]: crate::event::WindowEvent::Resized + /// [`WindowEvent::SurfaceResized`]: crate::event::WindowEvent::SurfaceResized /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform #[must_use] - fn request_inner_size(&self, size: Size) -> Option>; + fn request_surface_size(&self, size: Size) -> Option>; - /// Returns the physical size of the entire window. + /// Returns the size of the entire window. /// - /// These dimensions include the title bar and borders. If you don't want that (and you usually - /// don't), use [`Window::inner_size`] instead. + /// These dimensions include window decorations like the title bar and borders. If you don't + /// want that (and you usually don't), use [`Window::surface_size`] instead. /// /// ## Platform-specific /// /// - **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`]._ + /// [`Window::surface_size`]._ fn outer_size(&self) -> PhysicalSize; - /// Sets a minimum dimension size for the window. + /// Sets a minimum dimensions of the window's surface. /// /// ```no_run /// # use winit::dpi::{LogicalSize, PhysicalSize}; /// # use winit::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).into())); + /// window.set_min_surface_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).into())); + /// window.set_min_surface_size(Some(PhysicalSize::new(400, 200).into())); /// # } /// ``` /// /// ## Platform-specific /// /// - **iOS / Android / Orbital:** Unsupported. - fn set_min_inner_size(&self, min_size: Option); + fn set_min_surface_size(&self, min_size: Option); - /// Sets a maximum dimension size for the window. + /// Sets a maximum dimensions of the window's surface. /// /// ```no_run /// # use winit::dpi::{LogicalSize, PhysicalSize}; /// # use winit::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).into())); + /// window.set_max_surface_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).into())); + /// window.set_max_surface_size(Some(PhysicalSize::new(400, 200).into())); /// # } /// ``` /// /// ## Platform-specific /// /// - **iOS / Android / Orbital:** Unsupported. - fn set_max_inner_size(&self, max_size: Option); + fn set_max_surface_size(&self, max_size: Option); - /// Returns window resize increments if any were set. + /// Returns surface resize increments if any were set. /// /// ## Platform-specific /// /// - **iOS / Android / Web / Wayland / Orbital:** Always returns [`None`]. - fn resize_increments(&self) -> Option>; + fn surface_resize_increments(&self) -> Option>; - /// Sets window resize increments. + /// Sets resize increments of the surface. /// - /// This is a niche constraint hint usually employed by terminal emulators - /// and other apps that need "blocky" resizes. + /// This is a niche constraint hint usually employed by terminal emulators and other such apps + /// that need "blocky" resizes. /// /// ## Platform-specific /// @@ -769,7 +771,7 @@ pub trait Window: AsAny + Send + Sync { /// numbers. /// - **Wayland:** Not implemented. /// - **iOS / Android / Web / Orbital:** Unsupported. - fn set_resize_increments(&self, increments: Option); + fn set_surface_resize_increments(&self, increments: Option); /// Modifies the title of the window. /// @@ -828,9 +830,9 @@ pub trait Window: AsAny + Send + Sync { /// Sets whether the window is resizable or not. /// /// Note that making the window unresizable doesn't exempt you from handling - /// [`WindowEvent::Resized`], as that event can still be triggered by DPI scaling, entering - /// fullscreen mode, etc. Also, the window could still be resized by calling - /// [`Window::request_inner_size`]. + /// [`WindowEvent::SurfaceResized`], as that event can still be triggered by DPI scaling, + /// entering fullscreen mode, etc. Also, the window could still be resized by calling + /// [`Window::request_surface_size`]. /// /// ## Platform-specific /// @@ -839,7 +841,7 @@ pub trait Window: AsAny + Send + Sync { /// - **X11:** Due to a bug in XFCE, this has no effect on Xfwm. /// - **iOS / Android / Web:** Unsupported. /// - /// [`WindowEvent::Resized`]: crate::event::WindowEvent::Resized + /// [`WindowEvent::SurfaceResized`]: crate::event::WindowEvent::SurfaceResized fn set_resizable(&self, resizable: bool); /// Gets the window's current resizable state. From b674d20edf4c212d4a98040e4a99013a76287f1e Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Fri, 6 Sep 2024 17:20:11 +0300 Subject: [PATCH 12/12] api: unify error handling Make error infrastructure more backend agnostic and let backends just forward the os errors opaquely. --- examples/window.rs | 4 +- src/error.rs | 202 ++++++++++-------- src/event.rs | 6 +- src/event_loop.rs | 8 +- src/platform/startup_notify.rs | 8 +- src/platform_impl/android/mod.rs | 38 ++-- src/platform_impl/apple/appkit/cursor.rs | 9 +- src/platform_impl/apple/appkit/event_loop.rs | 6 +- src/platform_impl/apple/appkit/mod.rs | 17 -- src/platform_impl/apple/appkit/window.rs | 37 ++-- .../apple/appkit/window_delegate.rs | 46 ++-- src/platform_impl/apple/uikit/event_loop.rs | 8 +- src/platform_impl/apple/uikit/window.rs | 75 +++---- src/platform_impl/linux/mod.rs | 40 +--- .../linux/wayland/event_loop/mod.rs | 59 ++--- src/platform_impl/linux/wayland/mod.rs | 48 +---- src/platform_impl/linux/wayland/state.rs | 10 +- src/platform_impl/linux/wayland/window/mod.rs | 44 ++-- .../linux/wayland/window/state.rs | 27 ++- src/platform_impl/linux/x11/ime/context.rs | 16 +- src/platform_impl/linux/x11/mod.rs | 16 +- src/platform_impl/linux/x11/util/cursor.rs | 8 +- src/platform_impl/linux/x11/window.rs | 125 +++++------ src/platform_impl/orbital/event_loop.rs | 29 +-- src/platform_impl/orbital/mod.rs | 29 +-- src/platform_impl/orbital/window.rs | 50 ++--- .../web/event_loop/window_target.rs | 11 +- src/platform_impl/web/mod.rs | 1 - src/platform_impl/web/web_sys/canvas.rs | 10 +- src/platform_impl/web/window.rs | 37 ++-- src/platform_impl/windows/event_loop.rs | 6 +- src/platform_impl/windows/icon.rs | 14 +- src/platform_impl/windows/mod.rs | 2 - src/platform_impl/windows/window.rs | 31 +-- src/window.rs | 38 ++-- 35 files changed, 496 insertions(+), 619 deletions(-) diff --git a/examples/window.rs b/examples/window.rs index 719011c1af..650b0a7cb2 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -17,7 +17,7 @@ use rwh_06::{DisplayHandle, HasDisplayHandle}; use softbuffer::{Context, Surface}; use winit::application::ApplicationHandler; use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize}; -use winit::error::ExternalError; +use winit::error::RequestError; use winit::event::{DeviceEvent, DeviceId, Ime, MouseButton, MouseScrollDelta, WindowEvent}; use winit::event_loop::{ActiveEventLoop, EventLoop}; use winit::keyboard::{Key, ModifiersState}; @@ -76,7 +76,7 @@ struct Application { receiver: Receiver, sender: Sender, /// Custom cursors assets. - custom_cursors: Result, ExternalError>, + custom_cursors: Result, RequestError>, /// Application icon. icon: Icon, windows: HashMap, diff --git a/src/error.rs b/src/error.rs index 3e9ec8525a..697b37dd15 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,45 +1,40 @@ -use std::{error, fmt}; +use std::error::Error; +use std::fmt::{self, Display}; -use crate::platform_impl; - -// TODO: Rename -/// An error that may be generated when requesting Winit state -#[derive(Debug)] -pub enum ExternalError { - /// The operation is not supported by the backend. - NotSupported(NotSupportedError), - /// The operation was ignored. - Ignored, - /// The OS cannot perform the operation. - Os(OsError), -} - -/// The error type for when the requested operation is not supported by the backend. -#[derive(Clone, Copy, Default, Eq, Hash, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct NotSupportedError { - _marker: (), -} - -/// The error type for when the OS cannot perform the requested operation. -#[derive(Debug)] -pub struct OsError { - line: u32, - file: &'static str, - error: platform_impl::OsError, -} - -/// A general error that may occur while running the Winit event loop +/// A general error that may occur while running or creating +/// the event loop. #[derive(Debug)] +#[non_exhaustive] pub enum EventLoopError { - /// The operation is not supported by the backend. - NotSupported(NotSupportedError), - /// The OS cannot perform the operation. - Os(OsError), /// The event loop can't be re-created. RecreationAttempt, /// Application has exit with an error status. ExitFailure(i32), + /// Got unspecified OS-specific error during the request. + Os(OsError), + /// Creating the event loop with the requested configuration is not supported. + NotSupported(NotSupportedError), +} + +impl fmt::Display for EventLoopError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::RecreationAttempt => write!(f, "EventLoop can't be recreated"), + Self::Os(err) => err.fmt(f), + Self::ExitFailure(status) => write!(f, "Exit Failure: {status}"), + Self::NotSupported(err) => err.fmt(f), + } + } +} + +impl Error for EventLoopError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + if let Self::Os(err) = self { + err.source() + } else { + None + } + } } impl From for EventLoopError { @@ -48,85 +43,108 @@ impl From for EventLoopError { } } -impl NotSupportedError { - #[inline] - #[allow(dead_code)] - pub(crate) fn new() -> NotSupportedError { - NotSupportedError { _marker: () } +impl From for EventLoopError { + fn from(value: NotSupportedError) -> Self { + Self::NotSupported(value) } } -impl OsError { - #[allow(dead_code)] - pub(crate) fn new(line: u32, file: &'static str, error: platform_impl::OsError) -> OsError { - OsError { line, file, error } - } +/// A general error that may occur during a request to the windowing system. +#[derive(Debug)] +#[non_exhaustive] +pub enum RequestError { + /// The request is not supported. + NotSupported(NotSupportedError), + /// The request was ignored by the operating system. + Ignored, + /// Got unspecified OS specific error during the request. + Os(OsError), } -#[allow(unused_macros)] -macro_rules! os_error { - ($error:expr) => {{ - crate::error::OsError::new(line!(), file!(), $error) - }}; +impl Display for RequestError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::NotSupported(err) => err.fmt(f), + Self::Ignored => write!(f, "The request was ignored"), + Self::Os(err) => err.fmt(f), + } + } +} +impl Error for RequestError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + if let Self::Os(err) = self { + err.source() + } else { + None + } + } } -impl fmt::Display for OsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.pad(&format!("os error at {}:{}: {}", self.file, self.line, self.error)) +impl From for RequestError { + fn from(value: NotSupportedError) -> Self { + Self::NotSupported(value) } } -impl fmt::Display for ExternalError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - match self { - ExternalError::NotSupported(e) => e.fmt(f), - ExternalError::Ignored => write!(f, "Operation was ignored"), - ExternalError::Os(e) => e.fmt(f), - } +impl From for RequestError { + fn from(value: OsError) -> Self { + Self::Os(value) } } -impl fmt::Debug for NotSupportedError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.debug_struct("NotSupportedError").finish() +/// The requested operation is not supported. +#[derive(Debug)] +pub struct NotSupportedError { + /// The reason why a certain operation is not supported. + reason: &'static str, +} + +impl NotSupportedError { + pub(crate) fn new(reason: &'static str) -> Self { + Self { reason } } } impl fmt::Display for NotSupportedError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.pad("the requested operation is not supported by Winit") + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Operation is not supported: {}", self.reason) } } +impl Error for NotSupportedError {} -impl fmt::Display for EventLoopError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - match self { - EventLoopError::RecreationAttempt => write!(f, "EventLoop can't be recreated"), - EventLoopError::NotSupported(e) => e.fmt(f), - EventLoopError::Os(e) => e.fmt(f), - EventLoopError::ExitFailure(status) => write!(f, "Exit Failure: {status}"), - } +/// Unclassified error from the OS. +#[derive(Debug)] +pub struct OsError { + line: u32, + file: &'static str, + error: Box, +} + +impl OsError { + #[allow(dead_code)] + pub(crate) fn new( + line: u32, + file: &'static str, + error: impl Into>, + ) -> Self { + Self { line, file, error: error.into() } } } -impl error::Error for OsError {} -impl error::Error for ExternalError {} -impl error::Error for NotSupportedError {} -impl error::Error for EventLoopError {} - -#[cfg(test)] -#[allow(clippy::redundant_clone)] -mod tests { - use super::*; - - // Eat attributes for testing - #[test] - fn ensure_fmt_does_not_panic() { - let _ = format!("{:?}, {}", NotSupportedError::new(), NotSupportedError::new().clone()); - let _ = format!( - "{:?}, {}", - ExternalError::NotSupported(NotSupportedError::new()), - ExternalError::NotSupported(NotSupportedError::new()) - ); +impl Display for OsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad(&format!("os error at {}:{}: {}", self.file, self.line, self.error)) + } +} +impl Error for OsError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + Some(self.error.as_ref()) } } + +#[allow(unused_macros)] +macro_rules! os_error { + ($error:expr) => {{ + crate::error::OsError::new(line!(), file!(), $error) + }}; +} diff --git a/src/event.rs b/src/event.rs index 67ee7a53d2..223992db8f 100644 --- a/src/event.rs +++ b/src/event.rs @@ -46,7 +46,7 @@ use smol_str::SmolStr; use web_time::Instant; use crate::dpi::{PhysicalPosition, PhysicalSize}; -use crate::error::ExternalError; +use crate::error::RequestError; use crate::event_loop::AsyncRequestSerial; use crate::keyboard::{self, ModifiersKeyState, ModifiersKeys, ModifiersState}; use crate::platform_impl; @@ -1016,12 +1016,12 @@ impl SurfaceSizeWriter { pub fn request_surface_size( &mut self, new_surface_size: PhysicalSize, - ) -> Result<(), ExternalError> { + ) -> Result<(), RequestError> { if let Some(inner) = self.new_surface_size.upgrade() { *inner.lock().unwrap() = new_surface_size; Ok(()) } else { - Err(ExternalError::Ignored) + Err(RequestError::Ignored) } } } diff --git a/src/event_loop.rs b/src/event_loop.rs index d631e0d847..edcac345f8 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -20,7 +20,7 @@ use std::time::{Duration, Instant}; use web_time::{Duration, Instant}; use crate::application::ApplicationHandler; -use crate::error::{EventLoopError, ExternalError, OsError}; +use crate::error::{EventLoopError, RequestError}; use crate::monitor::MonitorHandle; use crate::platform_impl; use crate::utils::AsAny; @@ -268,7 +268,7 @@ impl EventLoop { pub fn create_custom_cursor( &self, custom_cursor: CustomCursorSource, - ) -> Result { + ) -> Result { self.event_loop.window_target().create_custom_cursor(custom_cursor) } } @@ -324,7 +324,7 @@ pub trait ActiveEventLoop: AsAny { fn create_window( &self, window_attributes: WindowAttributes, - ) -> Result, OsError>; + ) -> Result, RequestError>; /// Create custom cursor. /// @@ -334,7 +334,7 @@ pub trait ActiveEventLoop: AsAny { fn create_custom_cursor( &self, custom_cursor: CustomCursorSource, - ) -> Result; + ) -> Result; /// Returns the list of all the monitors available on the system. /// diff --git a/src/platform/startup_notify.rs b/src/platform/startup_notify.rs index c09aa6629b..1329ff2689 100644 --- a/src/platform/startup_notify.rs +++ b/src/platform/startup_notify.rs @@ -23,7 +23,7 @@ use std::env; -use crate::error::NotSupportedError; +use crate::error::{NotSupportedError, RequestError}; use crate::event_loop::{ActiveEventLoop, AsyncRequestSerial}; #[cfg(wayland_platform)] use crate::platform::wayland::ActiveEventLoopExtWayland; @@ -46,7 +46,7 @@ pub trait WindowExtStartupNotify { /// Request a new activation token. /// /// The token will be delivered inside - fn request_activation_token(&self) -> Result; + fn request_activation_token(&self) -> Result; } pub trait WindowAttributesExtStartupNotify { @@ -73,7 +73,7 @@ impl EventLoopExtStartupNotify for dyn ActiveEventLoop + '_ { } impl WindowExtStartupNotify for dyn Window + '_ { - fn request_activation_token(&self) -> Result { + fn request_activation_token(&self) -> Result { #[cfg(wayland_platform)] if let Some(window) = self.as_any().downcast_ref::() { @@ -87,7 +87,7 @@ impl WindowExtStartupNotify for dyn Window + '_ { return window.request_activation_token(); } - Err(NotSupportedError::new()) + Err(NotSupportedError::new("startup notify is not supported").into()) } } diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 1da2a0130d..426dd0fb35 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -14,7 +14,7 @@ use tracing::{debug, trace, warn}; use crate::application::ApplicationHandler; use crate::cursor::Cursor; use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; -use crate::error::{self, EventLoopError, ExternalError, NotSupportedError}; +use crate::error::{EventLoopError, NotSupportedError, RequestError}; use crate::event::{self, Force, StartCause, SurfaceSizeWriter}; use crate::event_loop::{ ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, @@ -592,15 +592,15 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_window( &self, window_attributes: WindowAttributes, - ) -> Result, error::OsError> { + ) -> Result, RequestError> { Ok(Box::new(Window::new(self, window_attributes)?)) } fn create_custom_cursor( &self, _source: CustomCursorSource, - ) -> Result { - Err(ExternalError::NotSupported(NotSupportedError::new())) + ) -> Result { + Err(NotSupportedError::new("create_custom_cursor is not supported").into()) } fn available_monitors(&self) -> Box> { @@ -715,7 +715,7 @@ impl Window { pub(crate) fn new( el: &ActiveEventLoop, _window_attrs: window::WindowAttributes, - ) -> Result { + ) -> Result { // FIXME this ignores requested window attributes Ok(Self { app: el.app.clone(), redraw_requester: el.redraw_requester.clone() }) @@ -796,12 +796,12 @@ impl CoreWindow for Window { fn pre_present_notify(&self) {} - fn inner_position(&self) -> Result, error::NotSupportedError> { - Err(error::NotSupportedError::new()) + fn inner_position(&self) -> Result, RequestError> { + Err(NotSupportedError::new("inner_position is not supported").into()) } - fn outer_position(&self) -> Result, error::NotSupportedError> { - Err(error::NotSupportedError::new()) + fn outer_position(&self) -> Result, RequestError> { + Err(NotSupportedError::new("outer_position is not supported").into()) } fn set_outer_position(&self, _position: Position) { @@ -896,29 +896,29 @@ impl CoreWindow for Window { fn set_cursor(&self, _: Cursor) {} - fn set_cursor_position(&self, _: Position) -> Result<(), error::ExternalError> { - Err(error::ExternalError::NotSupported(error::NotSupportedError::new())) + fn set_cursor_position(&self, _: Position) -> Result<(), RequestError> { + Err(NotSupportedError::new("set_cursor_position is not supported").into()) } - fn set_cursor_grab(&self, _: CursorGrabMode) -> Result<(), error::ExternalError> { - Err(error::ExternalError::NotSupported(error::NotSupportedError::new())) + fn set_cursor_grab(&self, _: CursorGrabMode) -> Result<(), RequestError> { + Err(NotSupportedError::new("set_cursor_grab is not supported").into()) } fn set_cursor_visible(&self, _: bool) {} - fn drag_window(&self) -> Result<(), error::ExternalError> { - Err(error::ExternalError::NotSupported(error::NotSupportedError::new())) + fn drag_window(&self) -> Result<(), RequestError> { + Err(NotSupportedError::new("drag_window is not supported").into()) } - fn drag_resize_window(&self, _direction: ResizeDirection) -> Result<(), error::ExternalError> { - Err(error::ExternalError::NotSupported(error::NotSupportedError::new())) + fn drag_resize_window(&self, _direction: ResizeDirection) -> Result<(), RequestError> { + Err(NotSupportedError::new("drag_resize_window").into()) } #[inline] fn show_window_menu(&self, _position: Position) {} - fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), error::ExternalError> { - Err(error::ExternalError::NotSupported(error::NotSupportedError::new())) + fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), RequestError> { + Err(NotSupportedError::new("set_cursor_hittest is not supported").into()) } fn set_theme(&self, _theme: Option) {} diff --git a/src/platform_impl/apple/appkit/cursor.rs b/src/platform_impl/apple/appkit/cursor.rs index fd474f18f4..70a36e1110 100644 --- a/src/platform_impl/apple/appkit/cursor.rs +++ b/src/platform_impl/apple/appkit/cursor.rs @@ -11,9 +11,8 @@ use objc2_foundation::{ NSString, }; -use super::OsError; use crate::cursor::{CursorImage, OnlyCursorImageSource}; -use crate::error::ExternalError; +use crate::error::RequestError; use crate::window::CursorIcon; #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -25,12 +24,12 @@ unsafe impl Send for CustomCursor {} unsafe impl Sync for CustomCursor {} impl CustomCursor { - pub(crate) fn new(cursor: OnlyCursorImageSource) -> Result { + pub(crate) fn new(cursor: OnlyCursorImageSource) -> Result { cursor_from_image(&cursor.0).map(Self) } } -pub(crate) fn cursor_from_image(cursor: &CursorImage) -> Result, ExternalError> { +pub(crate) fn cursor_from_image(cursor: &CursorImage) -> Result, RequestError> { let width = cursor.width; let height = cursor.height; @@ -48,7 +47,7 @@ pub(crate) fn cursor_from_image(cursor: &CursorImage) -> Result Result, crate::error::OsError> { + ) -> Result, RequestError> { Ok(Box::new(Window::new(self, window_attributes)?)) } fn create_custom_cursor( &self, source: CustomCursorSource, - ) -> Result { + ) -> Result { Ok(RootCustomCursor { inner: CustomCursor::new(source.inner)? }) } diff --git a/src/platform_impl/apple/appkit/mod.rs b/src/platform_impl/apple/appkit/mod.rs index f02c26d16a..8724c24938 100644 --- a/src/platform_impl/apple/appkit/mod.rs +++ b/src/platform_impl/apple/appkit/mod.rs @@ -14,8 +14,6 @@ mod view; mod window; mod window_delegate; -use std::fmt; - pub(crate) use self::cursor::CustomCursor as PlatformCustomCursor; pub(crate) use self::event::{physicalkey_to_scancode, scancode_to_physicalkey, KeyEventExtra}; pub(crate) use self::event_loop::{ @@ -50,18 +48,3 @@ impl FingerId { FingerId } } - -#[derive(Debug)] -pub enum OsError { - CGError(core_graphics::base::CGError), - CreationError(&'static str), -} - -impl fmt::Display for OsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - OsError::CGError(e) => f.pad(&format!("CGError {e}")), - OsError::CreationError(e) => f.pad(e), - } - } -} diff --git a/src/platform_impl/apple/appkit/window.rs b/src/platform_impl/apple/appkit/window.rs index 11c241dc45..3a454e0457 100644 --- a/src/platform_impl/apple/appkit/window.rs +++ b/src/platform_impl/apple/appkit/window.rs @@ -8,7 +8,7 @@ use objc2_foundation::{MainThreadBound, MainThreadMarker, NSObject}; use super::event_loop::ActiveEventLoop; use super::window_delegate::WindowDelegate; -use crate::error::OsError as RootOsError; +use crate::error::RequestError; use crate::monitor::MonitorHandle as CoreMonitorHandle; use crate::window::{ Cursor, Fullscreen, Icon, ImePurpose, Theme, UserAttentionType, Window as CoreWindow, @@ -25,7 +25,7 @@ impl Window { pub(crate) fn new( window_target: &ActiveEventLoop, attributes: WindowAttributes, - ) -> Result { + ) -> Result { let mtm = window_target.mtm; let delegate = autoreleasepool(|_| WindowDelegate::new(&window_target.app_state, attributes, mtm))?; @@ -111,16 +111,12 @@ impl CoreWindow for Window { 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 inner_position(&self) -> Result, RequestError> { + Ok(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 outer_position(&self) -> Result, RequestError> { + Ok(self.maybe_wait_on_main(|delegate| delegate.outer_position())) } fn set_outer_position(&self, position: Position) { @@ -275,14 +271,11 @@ impl CoreWindow for Window { self.maybe_wait_on_main(|delegate| delegate.set_cursor(cursor)); } - fn set_cursor_position(&self, position: Position) -> Result<(), crate::error::ExternalError> { + fn set_cursor_position(&self, position: Position) -> Result<(), RequestError> { self.maybe_wait_on_main(|delegate| delegate.set_cursor_position(position)) } - fn set_cursor_grab( - &self, - mode: crate::window::CursorGrabMode, - ) -> Result<(), crate::error::ExternalError> { + fn set_cursor_grab(&self, mode: crate::window::CursorGrabMode) -> Result<(), RequestError> { self.maybe_wait_on_main(|delegate| delegate.set_cursor_grab(mode)) } @@ -290,23 +283,25 @@ impl CoreWindow for Window { 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_window(&self) -> Result<(), RequestError> { + self.maybe_wait_on_main(|delegate| delegate.drag_window()); + Ok(()) } fn drag_resize_window( &self, direction: crate::window::ResizeDirection, - ) -> Result<(), crate::error::ExternalError> { - self.maybe_wait_on_main(|delegate| delegate.drag_resize_window(direction)) + ) -> Result<(), RequestError> { + Ok(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 set_cursor_hittest(&self, hittest: bool) -> Result<(), RequestError> { + self.maybe_wait_on_main(|delegate| delegate.set_cursor_hittest(hittest)); + Ok(()) } fn current_monitor(&self) -> Option { diff --git a/src/platform_impl/apple/appkit/window_delegate.rs b/src/platform_impl/apple/appkit/window_delegate.rs index 52ef4759de..fdad0c515e 100644 --- a/src/platform_impl/apple/appkit/window_delegate.rs +++ b/src/platform_impl/apple/appkit/window_delegate.rs @@ -33,9 +33,9 @@ use super::monitor::{self, flip_window_screen_coordinates, get_display_id}; use super::observer::RunLoop; use super::view::WinitView; use super::window::WinitWindow; -use super::{ffi, Fullscreen, MonitorHandle, OsError, WindowId}; +use super::{ffi, Fullscreen, MonitorHandle, WindowId}; use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}; -use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError}; +use crate::error::{NotSupportedError, RequestError}; use crate::event::{SurfaceSizeWriter, WindowEvent}; use crate::platform::macos::{OptionAsAlt, WindowExtMacOS}; use crate::window::{ @@ -677,9 +677,9 @@ impl WindowDelegate { app_state: &Rc, attrs: WindowAttributes, mtm: MainThreadMarker, - ) -> Result, RootOsError> { + ) -> Result, RequestError> { let window = new_window(app_state, &attrs, mtm) - .ok_or_else(|| os_error!(OsError::CreationError("couldn't create `NSWindow`")))?; + .ok_or_else(|| os_error!("couldn't create `NSWindow`"))?; #[cfg(feature = "rwh_06")] match attrs.parent_window.map(|handle| handle.0) { @@ -688,9 +688,9 @@ impl WindowDelegate { // Unwrap is fine, since the pointer comes from `NonNull`. let parent_view: Retained = unsafe { Retained::retain(handle.ns_view.as_ptr().cast()) }.unwrap(); - let parent = parent_view.window().ok_or_else(|| { - os_error!(OsError::CreationError("parent view should be installed in a window")) - })?; + let parent = parent_view + .window() + .ok_or_else(|| os_error!("parent view should be installed in a window"))?; // SAFETY: We know that there are no parent -> child -> parent cycles since the only // place in `winit` where we allow making a window a child window is @@ -925,15 +925,15 @@ impl WindowDelegate { #[inline] pub fn pre_present_notify(&self) {} - pub fn outer_position(&self) -> Result, NotSupportedError> { + pub fn outer_position(&self) -> PhysicalPosition { let position = flip_window_screen_coordinates(self.window().frame()); - Ok(LogicalPosition::new(position.x, position.y).to_physical(self.scale_factor())) + LogicalPosition::new(position.x, position.y).to_physical(self.scale_factor()) } - pub fn inner_position(&self) -> Result, NotSupportedError> { + pub fn inner_position(&self) -> PhysicalPosition { let content_rect = self.window().contentRectForFrameRect(self.window().frame()); let position = flip_window_screen_coordinates(content_rect); - Ok(LogicalPosition::new(position.x, position.y).to_physical(self.scale_factor())) + LogicalPosition::new(position.x, position.y).to_physical(self.scale_factor()) } pub fn set_outer_position(&self, position: Position) { @@ -1125,18 +1125,18 @@ impl WindowDelegate { } #[inline] - pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { + pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), RequestError> { let associate_mouse_cursor = match mode { CursorGrabMode::Locked => false, CursorGrabMode::None => true, CursorGrabMode::Confined => { - return Err(ExternalError::NotSupported(NotSupportedError::new())) + return Err(NotSupportedError::new("confined cursor is not supported").into()) }, }; // TODO: Do this for real https://stackoverflow.com/a/40922095/5435443 CGDisplay::associate_mouse_and_mouse_cursor_position(associate_mouse_cursor) - .map_err(|status| ExternalError::Os(os_error!(OsError::CGError(status)))) + .map_err(|status| os_error!(format!("CGError {status}")).into()) } #[inline] @@ -1154,8 +1154,8 @@ impl WindowDelegate { } #[inline] - pub fn set_cursor_position(&self, cursor_position: Position) -> Result<(), ExternalError> { - let physical_window_position = self.inner_position().unwrap(); + pub fn set_cursor_position(&self, cursor_position: Position) -> Result<(), RequestError> { + let physical_window_position = self.inner_position(); let scale_factor = self.scale_factor(); let window_position = physical_window_position.to_logical::(scale_factor); let logical_cursor_position = cursor_position.to_logical::(scale_factor); @@ -1164,33 +1164,31 @@ impl WindowDelegate { y: logical_cursor_position.y + window_position.y, }; CGDisplay::warp_mouse_cursor_position(point) - .map_err(|e| ExternalError::Os(os_error!(OsError::CGError(e))))?; + .map_err(|status| os_error!(format!("CGError {status}")))?; CGDisplay::associate_mouse_and_mouse_cursor_position(true) - .map_err(|e| ExternalError::Os(os_error!(OsError::CGError(e))))?; + .map_err(|status| os_error!(format!("CGError {status}")))?; Ok(()) } #[inline] - pub fn drag_window(&self) -> Result<(), ExternalError> { + pub fn drag_window(&self) { let mtm = MainThreadMarker::from(self); let event = NSApplication::sharedApplication(mtm).currentEvent().unwrap(); self.window().performWindowDragWithEvent(&event); - Ok(()) } #[inline] - pub fn drag_resize_window(&self, _direction: ResizeDirection) -> Result<(), ExternalError> { - Err(ExternalError::NotSupported(NotSupportedError::new())) + pub fn drag_resize_window(&self, _direction: ResizeDirection) -> Result<(), NotSupportedError> { + Err(NotSupportedError::new("drag_resize_window is not supported")) } #[inline] pub fn show_window_menu(&self, _position: Position) {} #[inline] - pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> { + pub fn set_cursor_hittest(&self, hittest: bool) { self.window().setIgnoresMouseEvents(!hittest); - Ok(()) } pub(crate) fn is_zoomed(&self) -> bool { diff --git a/src/platform_impl/apple/uikit/event_loop.rs b/src/platform_impl/apple/uikit/event_loop.rs index 2146262ba5..a3b31fde54 100644 --- a/src/platform_impl/apple/uikit/event_loop.rs +++ b/src/platform_impl/apple/uikit/event_loop.rs @@ -25,7 +25,7 @@ use super::super::notification_center::create_observer; use super::app_state::{send_occluded_event_for_all_windows, AppState, EventWrapper}; use super::{app_state, monitor, MonitorHandle}; use crate::application::ApplicationHandler; -use crate::error::{EventLoopError, ExternalError, NotSupportedError, OsError}; +use crate::error::{EventLoopError, NotSupportedError, RequestError}; use crate::event::Event; use crate::event_loop::{ ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, @@ -49,15 +49,15 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_window( &self, window_attributes: crate::window::WindowAttributes, - ) -> Result, OsError> { + ) -> Result, RequestError> { Ok(Box::new(Window::new(self, window_attributes)?)) } fn create_custom_cursor( &self, _source: CustomCursorSource, - ) -> Result { - Err(ExternalError::NotSupported(NotSupportedError::new())) + ) -> Result { + Err(NotSupportedError::new("create_custom_cursor is not supported").into()) } fn available_monitors(&self) -> Box> { diff --git a/src/platform_impl/apple/uikit/window.rs b/src/platform_impl/apple/uikit/window.rs index 6e01947813..b4ca0bc721 100644 --- a/src/platform_impl/apple/uikit/window.rs +++ b/src/platform_impl/apple/uikit/window.rs @@ -20,7 +20,7 @@ use super::view_controller::WinitViewController; use super::{app_state, monitor, ActiveEventLoop, Fullscreen, MonitorHandle}; use crate::cursor::Cursor; use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}; -use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError}; +use crate::error::{NotSupportedError, RequestError}; use crate::event::{Event, WindowEvent}; use crate::icon::Icon; use crate::monitor::MonitorHandle as CoreMonitorHandle; @@ -159,20 +159,20 @@ impl Inner { pub fn pre_present_notify(&self) {} - pub fn inner_position(&self) -> Result, NotSupportedError> { + pub fn inner_position(&self) -> PhysicalPosition { let safe_area = self.safe_area_screen_space(); let position = LogicalPosition { x: safe_area.origin.x as f64, y: safe_area.origin.y as f64 }; let scale_factor = self.scale_factor(); - Ok(position.to_physical(scale_factor)) + position.to_physical(scale_factor) } - pub fn outer_position(&self) -> Result, NotSupportedError> { + pub fn outer_position(&self) -> PhysicalPosition { let screen_frame = self.screen_frame(); let position = LogicalPosition { x: screen_frame.origin.x as f64, y: screen_frame.origin.y as f64 }; let scale_factor = self.scale_factor(); - Ok(position.to_physical(scale_factor)) + position.to_physical(scale_factor) } pub fn set_outer_position(&self, physical_position: Position) { @@ -256,31 +256,31 @@ impl Inner { debug!("`Window::set_cursor` ignored on iOS") } - pub fn set_cursor_position(&self, _position: Position) -> Result<(), ExternalError> { - Err(ExternalError::NotSupported(NotSupportedError::new())) + pub fn set_cursor_position(&self, _position: Position) -> Result<(), NotSupportedError> { + Err(NotSupportedError::new("set_cursor_position is not supported")) } - pub fn set_cursor_grab(&self, _: CursorGrabMode) -> Result<(), ExternalError> { - Err(ExternalError::NotSupported(NotSupportedError::new())) + pub fn set_cursor_grab(&self, _: CursorGrabMode) -> Result<(), NotSupportedError> { + Err(NotSupportedError::new("set_cursor_grab is not supported")) } pub fn set_cursor_visible(&self, _visible: bool) { debug!("`Window::set_cursor_visible` is ignored on iOS") } - pub fn drag_window(&self) -> Result<(), ExternalError> { - Err(ExternalError::NotSupported(NotSupportedError::new())) + pub fn drag_window(&self) -> Result<(), NotSupportedError> { + Err(NotSupportedError::new("drag_window is not supported")) } - pub fn drag_resize_window(&self, _direction: ResizeDirection) -> Result<(), ExternalError> { - Err(ExternalError::NotSupported(NotSupportedError::new())) + pub fn drag_resize_window(&self, _direction: ResizeDirection) -> Result<(), NotSupportedError> { + Err(NotSupportedError::new("drag_resize_window is not supported")) } #[inline] pub fn show_window_menu(&self, _position: Position) {} - pub fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), ExternalError> { - Err(ExternalError::NotSupported(NotSupportedError::new())) + pub fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), NotSupportedError> { + Err(NotSupportedError::new("set_cursor_hittest is not supported")) } pub fn set_minimized(&self, _minimized: bool) { @@ -466,7 +466,7 @@ impl Window { pub(crate) fn new( event_loop: &ActiveEventLoop, window_attributes: WindowAttributes, - ) -> Result { + ) -> Result { let mtm = event_loop.mtm; if window_attributes.min_surface_size.is_some() { @@ -606,31 +606,27 @@ impl CoreWindow for Window { 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 inner_position(&self) -> Result, RequestError> { + Ok(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 outer_position(&self) -> Result, RequestError> { + Ok(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 surface_size(&self) -> dpi::PhysicalSize { + fn surface_size(&self) -> PhysicalSize { self.maybe_wait_on_main(|delegate| delegate.surface_size()) } - fn request_surface_size(&self, size: Size) -> Option> { + fn request_surface_size(&self, size: Size) -> Option> { self.maybe_wait_on_main(|delegate| delegate.request_surface_size(size)) } - fn outer_size(&self) -> dpi::PhysicalSize { + fn outer_size(&self) -> PhysicalSize { self.maybe_wait_on_main(|delegate| delegate.outer_size()) } @@ -642,7 +638,7 @@ impl CoreWindow for Window { self.maybe_wait_on_main(|delegate| delegate.set_max_surface_size(max_size)); } - fn surface_resize_increments(&self) -> Option> { + fn surface_resize_increments(&self) -> Option> { self.maybe_wait_on_main(|delegate| delegate.surface_resize_increments()) } @@ -770,38 +766,35 @@ impl CoreWindow for Window { 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_position(&self, position: Position) -> Result<(), RequestError> { + Ok(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_grab(&self, mode: crate::window::CursorGrabMode) -> Result<(), RequestError> { + Ok(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_window(&self) -> Result<(), RequestError> { + Ok(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)) + ) -> Result<(), RequestError> { + Ok(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 set_cursor_hittest(&self, hittest: bool) -> Result<(), RequestError> { + Ok(self.maybe_wait_on_main(|delegate| delegate.set_cursor_hittest(hittest))?) } fn current_monitor(&self) -> Option { diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 0935d6e1ef..b715e40ac2 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -3,25 +3,24 @@ #[cfg(all(not(x11_platform), not(wayland_platform)))] compile_error!("Please select a feature to build for unix: `x11`, `wayland`"); +use std::env; use std::num::{NonZeroU16, NonZeroU32}; use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; -use std::sync::Arc; use std::time::Duration; -use std::{env, fmt}; #[cfg(x11_platform)] -use std::{ffi::CStr, mem::MaybeUninit, os::raw::*, sync::Mutex}; +use std::{ffi::CStr, mem::MaybeUninit, os::raw::*, sync::Arc, sync::Mutex}; use smol_str::SmolStr; pub(crate) use self::common::xkb::{physicalkey_to_scancode, scancode_to_physicalkey}; #[cfg(x11_platform)] -use self::x11::{X11Error, XConnection, XError, XNotSupported}; +use self::x11::{XConnection, XError, XNotSupported}; use crate::application::ApplicationHandler; pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource; #[cfg(x11_platform)] use crate::dpi::Size; use crate::dpi::{PhysicalPosition, PhysicalSize}; -use crate::error::EventLoopError; +use crate::error::{EventLoopError, NotSupportedError}; use crate::event_loop::ActiveEventLoop; pub(crate) use crate::icon::RgbaIcon as PlatformIcon; use crate::keyboard::Key; @@ -108,31 +107,6 @@ impl Default for PlatformSpecificWindowAttributes { pub(crate) static X11_BACKEND: Lazy, XNotSupported>>> = Lazy::new(|| Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new))); -#[derive(Debug, Clone)] -pub enum OsError { - Misc(&'static str), - #[cfg(x11_platform)] - XNotSupported(XNotSupported), - #[cfg(x11_platform)] - XError(Arc), - #[cfg(wayland_platform)] - WaylandError(Arc), -} - -impl fmt::Display for OsError { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - match *self { - OsError::Misc(e) => _f.pad(e), - #[cfg(x11_platform)] - OsError::XNotSupported(ref e) => fmt::Display::fmt(e, _f), - #[cfg(x11_platform)] - OsError::XError(ref e) => fmt::Display::fmt(e, _f), - #[cfg(wayland_platform)] - OsError::WaylandError(ref e) => fmt::Display::fmt(e, _f), - } - } -} - #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct WindowId(u64); @@ -411,7 +385,7 @@ impl EventLoop { } else { "neither WAYLAND_DISPLAY nor WAYLAND_SOCKET nor DISPLAY is set." }; - return Err(EventLoopError::Os(os_error!(OsError::Misc(msg)))); + return Err(NotSupportedError::new(msg).into()); }, }; @@ -433,9 +407,7 @@ impl EventLoop { fn new_x11_any_thread() -> Result { let xconn = match X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner()).as_ref() { Ok(xconn) => xconn.clone(), - Err(err) => { - return Err(EventLoopError::Os(os_error!(OsError::XNotSupported(err.clone())))) - }, + Err(err) => return Err(os_error!(err.clone()).into()), }; Ok(EventLoop::X(x11::EventLoop::new(xconn))) diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index 8ccddf803c..1ba1667e8c 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -8,19 +8,18 @@ use std::sync::atomic::Ordering; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; -use sctk::reexports::calloop::Error as CalloopError; use sctk::reexports::calloop_wayland_source::WaylandSource; use sctk::reexports::client::{globals, Connection, QueueHandle}; use crate::application::ApplicationHandler; use crate::cursor::OnlyCursorImage; use crate::dpi::LogicalSize; -use crate::error::{EventLoopError, ExternalError, OsError as RootOsError}; +use crate::error::{EventLoopError, OsError, RequestError}; use crate::event::{Event, StartCause, SurfaceSizeWriter, WindowEvent}; use crate::event_loop::{ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents}; use crate::platform::pump_events::PumpStatus; use crate::platform_impl::platform::min_timeout; -use crate::platform_impl::{OsError, PlatformCustomCursor}; +use crate::platform_impl::PlatformCustomCursor; use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource, Theme}; mod proxy; @@ -31,7 +30,7 @@ use sink::EventSink; use super::state::{WindowCompositorUpdate, WinitState}; use super::window::state::FrameCallbackState; -use super::{logical_to_physical_rounded, DeviceId, WaylandError, WindowId}; +use super::{logical_to_physical_rounded, DeviceId, WindowId}; type WaylandDispatcher = calloop::Dispatcher<'static, WaylandSource, WinitState>; @@ -61,27 +60,20 @@ pub struct EventLoop { impl EventLoop { pub fn new() -> Result { - macro_rules! map_err { - ($e:expr, $err:expr) => { - $e.map_err(|error| os_error!($err(error).into())) - }; - } - - let connection = map_err!(Connection::connect_to_env(), WaylandError::Connection)?; + let connection = Connection::connect_to_env().map_err(|err| os_error!(err))?; let (globals, mut event_queue) = - map_err!(globals::registry_queue_init(&connection), WaylandError::Global)?; + globals::registry_queue_init(&connection).map_err(|err| os_error!(err))?; let queue_handle = event_queue.handle(); let event_loop = - map_err!(calloop::EventLoop::::try_new(), WaylandError::Calloop)?; + calloop::EventLoop::::try_new().map_err(|err| os_error!(err))?; - let mut winit_state = WinitState::new(&globals, &queue_handle, event_loop.handle()) - .map_err(|error| os_error!(error))?; + let mut winit_state = WinitState::new(&globals, &queue_handle, event_loop.handle())?; // NOTE: do a roundtrip after binding the globals to prevent potential // races with the server. - map_err!(event_queue.roundtrip(&mut winit_state), WaylandError::Dispatch)?; + event_queue.roundtrip(&mut winit_state).map_err(|err| os_error!(err))?; // Register Wayland source. let wayland_source = WaylandSource::new(connection.clone(), event_queue); @@ -97,37 +89,32 @@ impl EventLoop { result }); - map_err!( - event_loop.handle().register_dispatcher(wayland_dispatcher.clone()), - WaylandError::Calloop - )?; + event_loop + .handle() + .register_dispatcher(wayland_dispatcher.clone()) + .map_err(|err| os_error!(err))?; // Setup the user proxy. let (ping, ping_source) = calloop::ping::make_ping().unwrap(); - let result = event_loop + event_loop .handle() .insert_source(ping_source, move |_, _, winit_state: &mut WinitState| { winit_state.dispatched_events = true; winit_state.proxy_wake_up = true; }) - .map_err(|error| error.error); - map_err!(result, WaylandError::Calloop)?; + .map_err(|err| os_error!(err))?; // An event's loop awakener to wake up for window events from winit's windows. - let (event_loop_awakener, event_loop_awakener_source) = map_err!( - calloop::ping::make_ping() - .map_err(|error| CalloopError::OtherError(Box::new(error).into())), - WaylandError::Calloop - )?; + let (event_loop_awakener, event_loop_awakener_source) = + calloop::ping::make_ping().map_err(|err| os_error!(err))?; - let result = event_loop + event_loop .handle() .insert_source(event_loop_awakener_source, move |_, _, winit_state: &mut WinitState| { // Mark that we have something to dispatch. winit_state.dispatched_events = true; }) - .map_err(|error| error.error); - map_err!(result, WaylandError::Calloop)?; + .map_err(|err| os_error!(err))?; let active_event_loop = ActiveEventLoop { connection: connection.clone(), @@ -517,14 +504,12 @@ impl EventLoop { }) } - fn roundtrip(&mut self) -> Result { + fn roundtrip(&mut self) -> Result { let state = &mut self.active_event_loop.state.get_mut(); let mut wayland_source = self.wayland_dispatcher.as_source_mut(); let event_queue = wayland_source.queue(); - event_queue.roundtrip(state).map_err(|error| { - os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(error)))) - }) + event_queue.roundtrip(state).map_err(|err| os_error!(err)) } fn control_flow(&self) -> ControlFlow { @@ -614,7 +599,7 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_custom_cursor( &self, cursor: CustomCursorSource, - ) -> Result { + ) -> Result { Ok(RootCustomCursor { inner: PlatformCustomCursor::Wayland(OnlyCursorImage(Arc::from(cursor.inner.0))), }) @@ -628,7 +613,7 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_window( &self, window_attributes: crate::window::WindowAttributes, - ) -> Result, RootOsError> { + ) -> Result, RequestError> { let window = crate::platform_impl::wayland::Window::new(self, window_attributes)?; Ok(Box::new(window)) } diff --git a/src/platform_impl/linux/wayland/mod.rs b/src/platform_impl/linux/wayland/mod.rs index 18de24277d..214b4a71d5 100644 --- a/src/platform_impl/linux/wayland/mod.rs +++ b/src/platform_impl/linux/wayland/mod.rs @@ -1,18 +1,14 @@ //! Winit's Wayland backend. -use std::fmt::Display; -use std::sync::Arc; - pub use event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy}; pub use output::{MonitorHandle, VideoModeHandle}; -use sctk::reexports::client::globals::{BindError, GlobalError}; use sctk::reexports::client::protocol::wl_surface::WlSurface; -use sctk::reexports::client::{self, ConnectError, DispatchError, Proxy}; +use sctk::reexports::client::Proxy; pub use window::Window; pub(super) use crate::cursor::OnlyCursorImage as CustomCursor; use crate::dpi::{LogicalSize, PhysicalSize}; -pub use crate::platform_impl::platform::{OsError, WindowId}; +pub use crate::platform_impl::platform::WindowId; mod event_loop; mod output; @@ -21,46 +17,6 @@ mod state; mod types; mod window; -#[derive(Debug)] -pub enum WaylandError { - /// Error connecting to the socket. - Connection(ConnectError), - - /// Error binding the global. - Global(GlobalError), - - // Bind error. - Bind(BindError), - - /// Error during the dispatching the event queue. - Dispatch(DispatchError), - - /// Calloop error. - Calloop(calloop::Error), - - /// Wayland - Wire(client::backend::WaylandError), -} - -impl Display for WaylandError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - WaylandError::Connection(error) => error.fmt(f), - WaylandError::Global(error) => error.fmt(f), - WaylandError::Bind(error) => error.fmt(f), - WaylandError::Dispatch(error) => error.fmt(f), - WaylandError::Calloop(error) => error.fmt(f), - WaylandError::Wire(error) => error.fmt(f), - } - } -} - -impl From for OsError { - fn from(value: WaylandError) -> Self { - Self::WaylandError(Arc::new(value)) - } -} - /// Dummy device id, since Wayland doesn't have device events. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct DeviceId; diff --git a/src/platform_impl/linux/wayland/state.rs b/src/platform_impl/linux/wayland/state.rs index 2b9f9fa8ff..bec0a55d3a 100644 --- a/src/platform_impl/linux/wayland/state.rs +++ b/src/platform_impl/linux/wayland/state.rs @@ -21,6 +21,7 @@ use sctk::shm::slot::SlotPool; use sctk::shm::{Shm, ShmHandler}; use sctk::subcompositor::SubcompositorState; +use crate::error::OsError; use crate::platform_impl::wayland::event_loop::sink::EventSink; use crate::platform_impl::wayland::output::MonitorHandle; use crate::platform_impl::wayland::seat::{ @@ -32,8 +33,7 @@ use crate::platform_impl::wayland::types::wp_fractional_scaling::FractionalScali use crate::platform_impl::wayland::types::wp_viewporter::ViewporterState; use crate::platform_impl::wayland::types::xdg_activation::XdgActivationState; use crate::platform_impl::wayland::window::{WindowRequests, WindowState}; -use crate::platform_impl::wayland::{WaylandError, WindowId}; -use crate::platform_impl::OsError; +use crate::platform_impl::wayland::WindowId; /// Winit's Wayland state. pub struct WinitState { @@ -126,7 +126,7 @@ impl WinitState { ) -> Result { let registry_state = RegistryState::new(globals); let compositor_state = - CompositorState::bind(globals, queue_handle).map_err(WaylandError::Bind)?; + CompositorState::bind(globals, queue_handle).map_err(|err| os_error!(err))?; let subcompositor_state = match SubcompositorState::bind( compositor_state.wl_compositor().clone(), globals, @@ -156,7 +156,7 @@ impl WinitState { (None, None) }; - let shm = Shm::bind(globals, queue_handle).map_err(WaylandError::Bind)?; + let shm = Shm::bind(globals, queue_handle).map_err(|err| os_error!(err))?; let custom_cursor_pool = Arc::new(Mutex::new(SlotPool::new(2, &shm).unwrap())); Ok(Self { @@ -168,7 +168,7 @@ impl WinitState { shm, custom_cursor_pool, - xdg_shell: XdgShell::bind(globals, queue_handle).map_err(WaylandError::Bind)?, + xdg_shell: XdgShell::bind(globals, queue_handle).map_err(|err| os_error!(err))?, xdg_activation: XdgActivationState::bind(globals, queue_handle).ok(), windows: Default::default(), diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index 814061dd8f..42f37a0963 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -16,13 +16,13 @@ use super::event_loop::sink::EventSink; use super::output::MonitorHandle; use super::state::WinitState; use super::types::xdg_activation::XdgActivationTokenData; -use super::{ActiveEventLoop, WaylandError, WindowId}; +use super::{ActiveEventLoop, WindowId}; use crate::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}; -use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError}; +use crate::error::{NotSupportedError, RequestError}; use crate::event::{Ime, WindowEvent}; use crate::event_loop::AsyncRequestSerial; use crate::monitor::MonitorHandle as CoreMonitorHandle; -use crate::platform_impl::{Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError}; +use crate::platform_impl::{Fullscreen, MonitorHandle as PlatformMonitorHandle}; use crate::window::{ Cursor, CursorGrabMode, Fullscreen as CoreFullscreen, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as CoreWindow, WindowAttributes, WindowButtons, @@ -77,7 +77,7 @@ impl Window { pub(crate) fn new( event_loop_window_target: &ActiveEventLoop, attributes: WindowAttributes, - ) -> Result { + ) -> Result { let queue_handle = event_loop_window_target.queue_handle.clone(); let mut state = event_loop_window_target.state.borrow_mut(); @@ -190,15 +190,11 @@ impl Window { let event_queue = wayland_source.queue(); // Do a roundtrip. - event_queue.roundtrip(&mut state).map_err(|error| { - os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(error)))) - })?; + event_queue.roundtrip(&mut state).map_err(|err| os_error!(err))?; // XXX Wait for the initial configure to arrive. while !window_state.lock().unwrap().is_configured() { - event_queue.blocking_dispatch(&mut state).map_err(|error| { - os_error!(OsError::WaylandError(Arc::new(WaylandError::Dispatch(error)))) - })?; + event_queue.blocking_dispatch(&mut state).map_err(|err| os_error!(err))?; } // Wake-up event loop, so it'll send initial redraw requested. @@ -223,10 +219,10 @@ impl Window { } impl Window { - pub fn request_activation_token(&self) -> Result { + 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()), + None => return Err(NotSupportedError::new("xdg_activation_v1 is not available").into()), }; let serial = AsyncRequestSerial::get(); @@ -309,12 +305,14 @@ impl CoreWindow for Window { crate::platform_impl::common::xkb::reset_dead_keys() } - fn inner_position(&self) -> Result, NotSupportedError> { - Err(NotSupportedError::new()) + fn inner_position(&self) -> Result, RequestError> { + Err(NotSupportedError::new("window position information is not available on Wayland") + .into()) } - fn outer_position(&self) -> Result, NotSupportedError> { - Err(NotSupportedError::new()) + fn outer_position(&self) -> Result, RequestError> { + Err(NotSupportedError::new("window position information is not available on Wayland") + .into()) } fn set_outer_position(&self, _position: Position) { @@ -576,7 +574,7 @@ impl CoreWindow for Window { } } - fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> { + fn set_cursor_position(&self, position: Position) -> Result<(), RequestError> { let scale_factor = self.scale_factor(); let position = position.to_logical(scale_factor); self.window_state @@ -587,7 +585,7 @@ impl CoreWindow for Window { .map(|_| self.request_redraw()) } - fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { + fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), RequestError> { self.window_state.lock().unwrap().set_cursor_grab(mode) } @@ -595,11 +593,11 @@ impl CoreWindow for Window { self.window_state.lock().unwrap().set_cursor_visible(visible); } - fn drag_window(&self) -> Result<(), ExternalError> { + fn drag_window(&self) -> Result<(), RequestError> { self.window_state.lock().unwrap().drag_window() } - fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { + fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), RequestError> { self.window_state.lock().unwrap().drag_resize_window(direction) } @@ -609,16 +607,14 @@ impl CoreWindow for Window { self.window_state.lock().unwrap().show_window_menu(position); } - fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> { + fn set_cursor_hittest(&self, hittest: bool) -> Result<(), RequestError> { let surface = self.window.wl_surface(); if hittest { surface.set_input_region(None); Ok(()) } else { - let region = Region::new(&*self.compositor).map_err(|_| { - ExternalError::Os(os_error!(OsError::Misc("failed to set input region."))) - })?; + let region = Region::new(&*self.compositor).map_err(|err| os_error!(err))?; region.add(0, 0, 0, 0); surface.set_input_region(Some(region.wl_region())); Ok(()) diff --git a/src/platform_impl/linux/wayland/window/state.rs b/src/platform_impl/linux/wayland/window/state.rs index 79c1766b60..e21e6e03d5 100644 --- a/src/platform_impl/linux/wayland/window/state.rs +++ b/src/platform_impl/linux/wayland/window/state.rs @@ -30,7 +30,7 @@ use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur; use crate::cursor::CustomCursor as RootCustomCursor; use crate::dpi::{LogicalPosition, LogicalSize, PhysicalSize, Size}; -use crate::error::{ExternalError, NotSupportedError}; +use crate::error::{NotSupportedError, RequestError}; use crate::platform_impl::wayland::logical_to_physical_rounded; use crate::platform_impl::wayland::seat::{ PointerConstraintsState, WinitPointerData, WinitPointerDataExt, ZwpTextInputV3Ext, @@ -388,7 +388,7 @@ impl WindowState { } /// Start interacting drag resize. - pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { + pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), RequestError> { let xdg_toplevel = self.window.xdg_toplevel(); // TODO(kchibisov) handle touch serials. @@ -402,7 +402,7 @@ impl WindowState { } /// Start the window drag. - pub fn drag_window(&self) -> Result<(), ExternalError> { + pub fn drag_window(&self) -> Result<(), RequestError> { let xdg_toplevel = self.window.xdg_toplevel(); // TODO(kchibisov) handle touch serials. self.apply_on_pointer(|_, data| { @@ -799,7 +799,7 @@ impl WindowState { } /// Set the cursor grabbing state on the top-level. - pub fn set_cursor_grab(&mut self, mode: CursorGrabMode) -> Result<(), ExternalError> { + pub fn set_cursor_grab(&mut self, mode: CursorGrabMode) -> Result<(), RequestError> { if self.cursor_grab_mode.user_grab_mode == mode { return Ok(()); } @@ -817,11 +817,15 @@ impl WindowState { } /// Set the grabbing state on the surface. - fn set_cursor_grab_inner(&mut self, mode: CursorGrabMode) -> Result<(), ExternalError> { + fn set_cursor_grab_inner(&mut self, mode: CursorGrabMode) -> Result<(), RequestError> { let pointer_constraints = match self.pointer_constraints.as_ref() { Some(pointer_constraints) => pointer_constraints, None if mode == CursorGrabMode::None => return Ok(()), - None => return Err(ExternalError::NotSupported(NotSupportedError::new())), + None => { + return Err( + NotSupportedError::new("zwp_pointer_constraints is not available").into() + ) + }, }; // Replace the current mode. @@ -865,16 +869,17 @@ impl WindowState { } /// Set the position of the cursor. - pub fn set_cursor_position(&self, position: LogicalPosition) -> Result<(), ExternalError> { + pub fn set_cursor_position(&self, position: LogicalPosition) -> Result<(), RequestError> { if self.pointer_constraints.is_none() { - return Err(ExternalError::NotSupported(NotSupportedError::new())); + return Err(NotSupportedError::new("zwp_pointer_constraints is not available").into()); } // Position can be set only for locked cursor. if self.cursor_grab_mode.current_grab_mode != CursorGrabMode::Locked { - return Err(ExternalError::Os(os_error!(crate::platform_impl::OsError::Misc( - "cursor position can be set only for locked cursor." - )))); + return Err(NotSupportedError::new( + "cursor position could only be changed for locked pointer", + ) + .into()); } self.apply_on_pointer(|_, data| { diff --git a/src/platform_impl/linux/x11/ime/context.rs b/src/platform_impl/linux/x11/ime/context.rs index 2ffaa9a32c..bb1ef64240 100644 --- a/src/platform_impl/linux/x11/ime/context.rs +++ b/src/platform_impl/linux/x11/ime/context.rs @@ -1,7 +1,8 @@ +use std::error::Error; use std::ffi::CStr; use std::os::raw::c_short; use std::sync::Arc; -use std::{mem, ptr}; +use std::{fmt, mem, ptr}; use x11_dl::xlib::{XIMCallback, XIMPreeditCaretCallbackStruct, XIMPreeditDrawCallbackStruct}; @@ -19,6 +20,19 @@ pub enum ImeContextCreationError { Null, } +impl fmt::Display for ImeContextCreationError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ImeContextCreationError::XError(err) => err.fmt(f), + ImeContextCreationError::Null => { + write!(f, "got null pointer from Xlib without exact reason") + }, + } + } +} + +impl Error for ImeContextCreationError {} + /// The callback used by XIM preedit functions. type XIMProcNonnull = unsafe extern "C" fn(ffi::XIM, ffi::XPointer, ffi::XPointer); diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index b156d7d437..cada63f42e 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -23,7 +23,7 @@ use x11rb::x11_utils::X11Error as LogicalError; use x11rb::xcb_ffi::ReplyOrIdError; use crate::application::ApplicationHandler; -use crate::error::{EventLoopError, ExternalError, OsError as RootOsError}; +use crate::error::{EventLoopError, RequestError}; use crate::event::{Event, StartCause, WindowEvent}; use crate::event_loop::{ ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, @@ -33,7 +33,7 @@ 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::platform_impl::{OwnedDisplayHandle, PlatformCustomCursor}; use crate::window::{ CustomCursor as RootCustomCursor, CustomCursorSource, Theme, Window as CoreWindow, WindowAttributes, @@ -399,9 +399,11 @@ impl EventLoop { // `run_on_demand` calls but if they have only just dropped their // windows we need to make sure those last requests are sent to the // X Server. - self.event_processor.target.x_connection().sync_with_server().map_err(|x_err| { - EventLoopError::Os(os_error!(OsError::XError(Arc::new(X11Error::Xlib(x_err))))) - })?; + self.event_processor + .target + .x_connection() + .sync_with_server() + .map_err(|x_err| EventLoopError::Os(os_error!(X11Error::Xlib(x_err))))?; exit } @@ -688,14 +690,14 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_window( &self, window_attributes: WindowAttributes, - ) -> Result, RootOsError> { + ) -> Result, RequestError> { Ok(Box::new(Window::new(self, window_attributes)?)) } fn create_custom_cursor( &self, custom_cursor: CustomCursorSource, - ) -> Result { + ) -> Result { Ok(RootCustomCursor { inner: PlatformCustomCursor::X(CustomCursor::new(self, custom_cursor.inner)?), }) diff --git a/src/platform_impl/linux/x11/util/cursor.rs b/src/platform_impl/linux/x11/util/cursor.rs index 36e35ccdb8..bd4adace6b 100644 --- a/src/platform_impl/linux/x11/util/cursor.rs +++ b/src/platform_impl/linux/x11/util/cursor.rs @@ -9,8 +9,8 @@ use x11rb::protocol::xproto; use super::super::ActiveEventLoop; use super::*; -use crate::error::ExternalError; -use crate::platform_impl::{OsError, PlatformCustomCursorSource}; +use crate::error::RequestError; +use crate::platform_impl::PlatformCustomCursorSource; use crate::window::CursorIcon; impl XConnection { @@ -193,7 +193,7 @@ impl CustomCursor { pub(crate) fn new( event_loop: &ActiveEventLoop, mut cursor: PlatformCustomCursorSource, - ) -> Result { + ) -> Result { // Reverse RGBA order to BGRA. cursor.0.rgba.chunks_mut(4).for_each(|chunk| { let chunk: &mut [u8; 4] = chunk.try_into().unwrap(); @@ -215,7 +215,7 @@ impl CustomCursor { cursor.0.hotspot_y, &cursor.0.rgba, ) - .map_err(|err| ExternalError::Os(os_error!(OsError::XError(err.into()))))?; + .map_err(|err| os_error!(err))?; Ok(Self { inner: Arc::new(CustomCursorInner { xconn: event_loop.xconn.clone(), cursor }) }) } diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index c56e5f7080..ac5a0bc0d9 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -22,7 +22,7 @@ use super::{ }; use crate::cursor::{Cursor, CustomCursor as RootCustomCursor}; use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; -use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError}; +use crate::error::{NotSupportedError, RequestError}; use crate::event::{Event, SurfaceSizeWriter, WindowEvent}; use crate::event_loop::AsyncRequestSerial; use crate::platform::x11::WindowType; @@ -31,8 +31,8 @@ use crate::platform_impl::x11::{ xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender, X11Error, }; use crate::platform_impl::{ - common, Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformCustomCursor, - PlatformIcon, VideoModeHandle as PlatformVideoModeHandle, + common, Fullscreen, MonitorHandle as PlatformMonitorHandle, PlatformCustomCursor, PlatformIcon, + VideoModeHandle as PlatformVideoModeHandle, }; use crate::window::{ CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as CoreWindow, @@ -54,7 +54,7 @@ impl Window { pub(crate) fn new( event_loop: &ActiveEventLoop, attribs: WindowAttributes, - ) -> Result { + ) -> Result { let window = Arc::new(UnownedWindow::new(event_loop, attribs)?); event_loop.windows.borrow_mut().insert(window.id(), Arc::downgrade(&window)); Ok(Window(window)) @@ -82,11 +82,11 @@ impl CoreWindow for Window { common::xkb::reset_dead_keys(); } - fn inner_position(&self) -> Result, NotSupportedError> { + fn inner_position(&self) -> Result, RequestError> { self.0.inner_position() } - fn outer_position(&self) -> Result, NotSupportedError> { + fn outer_position(&self) -> Result, RequestError> { self.0.outer_position() } @@ -242,11 +242,11 @@ impl CoreWindow for Window { self.0.set_cursor(cursor); } - fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> { + fn set_cursor_position(&self, position: Position) -> Result<(), RequestError> { self.0.set_cursor_position(position) } - fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { + fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), RequestError> { self.0.set_cursor_grab(mode) } @@ -254,11 +254,11 @@ impl CoreWindow for Window { self.0.set_cursor_visible(visible); } - fn drag_window(&self) -> Result<(), ExternalError> { + fn drag_window(&self) -> Result<(), RequestError> { self.0.drag_window() } - fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { + fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), RequestError> { self.0.drag_resize_window(direction) } @@ -266,7 +266,7 @@ impl CoreWindow for Window { self.0.show_window_menu(position); } - fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> { + fn set_cursor_hittest(&self, hittest: bool) -> Result<(), RequestError> { self.0.set_cursor_hittest(hittest) } @@ -427,13 +427,9 @@ pub struct UnownedWindow { redraw_sender: WakeSender, activation_sender: WakeSender, } - macro_rules! leap { ($e:expr) => { - match $e { - Ok(x) => x, - Err(err) => return Err(os_error!(OsError::XError(X11Error::from(err).into()))), - } + $e.map_err(|err| os_error!(err))? }; } @@ -442,7 +438,7 @@ impl UnownedWindow { pub(crate) fn new( event_loop: &ActiveEventLoop, window_attrs: WindowAttributes, - ) -> Result { + ) -> Result { let xconn = &event_loop.xconn; let atoms = xconn.atoms(); #[cfg(feature = "rwh_06")] @@ -527,10 +523,9 @@ impl UnownedWindow { match window_attrs.platform_specific.x11.visual_id { Some(vi) => { // Find this specific visual. - let (visualtype, depth) = - all_visuals.find(|(visual, _)| visual.visual_id == vi).ok_or_else( - || os_error!(OsError::XError(X11Error::NoSuchVisual(vi).into())), - )?; + let (visualtype, depth) = all_visuals + .find(|(visual, _)| visual.visual_id == vi) + .ok_or_else(|| os_error!(X11Error::NoSuchVisual(vi)))?; (Some(visualtype), depth, true) }, @@ -828,7 +823,7 @@ impl UnownedWindow { &mut supported_ptr, ); if supported_ptr == ffi::False { - return Err(os_error!(OsError::Misc("`XkbSetDetectableAutoRepeat` failed"))); + return Err(os_error!("`XkbSetDetectableAutoRepeat` failed").into()); } } @@ -848,14 +843,16 @@ impl UnownedWindow { // Try to create input context for the window. if let Some(ime) = event_loop.ime.as_ref() { - let result = ime.borrow_mut().create_context(window.xwindow as ffi::Window, false); - leap!(result); + ime.borrow_mut() + .create_context(window.xwindow as ffi::Window, false) + .map_err(|err| os_error!(err))?; } // These properties must be set after mapping if window_attrs.maximized { leap!(window.set_maximized_inner(window_attrs.maximized)).ignore_error(); } + if window_attrs.fullscreen.is_some() { if let Some(flusher) = leap!(window @@ -888,7 +885,7 @@ impl UnownedWindow { } /// Embed this window into a parent window. - pub(super) fn embed_window(&self) -> Result<(), RootOsError> { + pub(super) fn embed_window(&self) -> Result<(), RequestError> { let atoms = self.xconn.atoms(); leap!(leap!(self.xconn.change_property( self.xwindow, @@ -1500,7 +1497,7 @@ impl UnownedWindow { } #[inline] - pub fn outer_position(&self) -> Result, NotSupportedError> { + pub fn outer_position(&self) -> Result, RequestError> { let extents = self.shared_state_lock().frame_extents.clone(); if let Some(extents) = extents { let (x, y) = self.inner_position_physical(); @@ -1521,7 +1518,7 @@ impl UnownedWindow { } #[inline] - pub fn inner_position(&self) -> Result, NotSupportedError> { + pub fn inner_position(&self) -> Result, RequestError> { Ok(self.inner_position_physical().into()) } @@ -1815,7 +1812,7 @@ impl UnownedWindow { } #[inline] - pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { + pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), RequestError> { let mut grabbed_lock = self.cursor_grabbed_mode.lock().unwrap(); if mode == *grabbed_lock { return Ok(()); @@ -1829,9 +1826,10 @@ impl UnownedWindow { .expect_then_ignore_error("Failed to call `xcb_ungrab_pointer`"); let result = match mode { - CursorGrabMode::None => self.xconn.flush_requests().map_err(|err| { - ExternalError::Os(os_error!(OsError::XError(X11Error::Xlib(err).into()))) - }), + CursorGrabMode::None => self + .xconn + .flush_requests() + .map_err(|err| RequestError::Os(os_error!(X11Error::Xlib(err)))), CursorGrabMode::Confined => { let result = { self.xconn @@ -1878,10 +1876,12 @@ impl UnownedWindow { }, _ => unreachable!(), } - .map_err(|err| ExternalError::Os(os_error!(OsError::Misc(err)))) + .map_err(|err| RequestError::Os(os_error!(err))) }, CursorGrabMode::Locked => { - return Err(ExternalError::NotSupported(NotSupportedError::new())); + return Err( + NotSupportedError::new("locked cursor is not implemented on X11").into() + ); }, }; @@ -1923,28 +1923,23 @@ impl UnownedWindow { self.shared_state_lock().last_monitor.scale_factor } - pub fn set_cursor_position_physical(&self, x: i32, y: i32) -> Result<(), ExternalError> { - { - self.xconn - .xcb_connection() - .warp_pointer(x11rb::NONE, self.xwindow, 0, 0, 0, 0, x as _, y as _) - .map_err(|e| { - ExternalError::Os(os_error!(OsError::XError(X11Error::from(e).into()))) - })?; - self.xconn.flush_requests().map_err(|e| { - ExternalError::Os(os_error!(OsError::XError(X11Error::Xlib(e).into()))) - }) - } + pub fn set_cursor_position_physical(&self, x: i32, y: i32) -> Result<(), RequestError> { + self.xconn + .xcb_connection() + .warp_pointer(x11rb::NONE, self.xwindow, 0, 0, 0, 0, x as _, y as _) + .map_err(|err| os_error!(X11Error::from(err)))?; + self.xconn.flush_requests().map_err(|err| os_error!(X11Error::Xlib(err)))?; + Ok(()) } #[inline] - pub fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> { + pub fn set_cursor_position(&self, position: Position) -> Result<(), RequestError> { let (x, y) = position.to_physical::(self.scale_factor()).into(); self.set_cursor_position_physical(x, y) } #[inline] - pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> { + pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), RequestError> { let mut rectangles: Vec = Vec::new(); if hittest { let size = self.surface_size(); @@ -1956,17 +1951,17 @@ impl UnownedWindow { }) } let region = RegionWrapper::create_region(self.xconn.xcb_connection(), &rectangles) - .map_err(|_e| ExternalError::Ignored)?; + .map_err(|_e| RequestError::Ignored)?; self.xconn .xcb_connection() .xfixes_set_window_shape_region(self.xwindow, SK::INPUT, 0, 0, region.region()) - .map_err(|_e| ExternalError::Ignored)?; + .map_err(|_e| RequestError::Ignored)?; self.shared_state_lock().cursor_hittest = Some(hittest); Ok(()) } /// Moves the window while it is being dragged. - pub fn drag_window(&self) -> Result<(), ExternalError> { + pub fn drag_window(&self) -> Result<(), RequestError> { self.drag_initiate(util::MOVERESIZE_MOVE) } @@ -1974,7 +1969,7 @@ impl UnownedWindow { pub fn show_window_menu(&self, _position: Position) {} /// Resizes the window while it is being dragged. - pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { + pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), RequestError> { self.drag_initiate(match direction { ResizeDirection::East => util::MOVERESIZE_RIGHT, ResizeDirection::North => util::MOVERESIZE_TOP, @@ -1988,13 +1983,13 @@ impl UnownedWindow { } /// Initiates a drag operation while the left mouse button is pressed. - fn drag_initiate(&self, action: isize) -> Result<(), ExternalError> { + fn drag_initiate(&self, action: isize) -> Result<(), RequestError> { let pointer = self .xconn .query_pointer(self.xwindow, util::VIRTUAL_CORE_POINTER) - .map_err(|err| ExternalError::Os(os_error!(OsError::XError(err.into()))))?; + .map_err(|err| os_error!(err))?; - let window = self.inner_position().map_err(ExternalError::NotSupported)?; + let window_position = self.inner_position()?; let atoms = self.xconn.atoms(); let message = atoms[_NET_WM_MOVERESIZE]; @@ -2005,13 +2000,9 @@ impl UnownedWindow { self.xconn .xcb_connection() .ungrab_pointer(x11rb::CURRENT_TIME) - .map_err(|err| { - ExternalError::Os(os_error!(OsError::XError(X11Error::from(err).into()))) - })? + .map_err(|err| os_error!(X11Error::from(err)))? .ignore_error(); - self.xconn.flush_requests().map_err(|err| { - ExternalError::Os(os_error!(OsError::XError(X11Error::Xlib(err).into()))) - })?; + self.xconn.flush_requests().map_err(|err| os_error!(X11Error::Xlib(err)))?; *grabbed_lock = CursorGrabMode::None; // we keep the lock until we are done @@ -2025,18 +2016,18 @@ impl UnownedWindow { | xproto::EventMask::SUBSTRUCTURE_NOTIFY, ), [ - (window.x + xinput_fp1616_to_float(pointer.win_x) as i32) as u32, - (window.y + xinput_fp1616_to_float(pointer.win_y) as i32) as u32, + (window_position.x + xinput_fp1616_to_float(pointer.win_x) as i32) as u32, + (window_position.y + xinput_fp1616_to_float(pointer.win_y) as i32) as u32, action.try_into().unwrap(), 1, // Button 1 1, ], ) - .map_err(|err| ExternalError::Os(os_error!(OsError::XError(err.into()))))?; + .map_err(|err| os_error!(err))?; - self.xconn.flush_requests().map_err(|err| { - ExternalError::Os(os_error!(OsError::XError(X11Error::Xlib(err).into()))) - }) + self.xconn.flush_requests().map_err(|err| os_error!(X11Error::Xlib(err)))?; + + Ok(()) } #[inline] @@ -2135,7 +2126,7 @@ impl UnownedWindow { } #[inline] - pub fn request_activation_token(&self) -> Result { + pub fn request_activation_token(&self) -> Result { let serial = AsyncRequestSerial::get(); self.activation_sender.send((self.id(), serial)); Ok(serial) diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index 11a44f05b6..c40914c906 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -12,11 +12,11 @@ use orbclient::{ use smol_str::SmolStr; use super::{ - DeviceId, KeyEventExtra, MonitorHandle, OsError, PlatformSpecificEventLoopAttributes, - RedoxSocket, TimeSocket, WindowId, WindowProperties, + DeviceId, KeyEventExtra, MonitorHandle, PlatformSpecificEventLoopAttributes, RedoxSocket, + TimeSocket, WindowId, WindowProperties, }; use crate::application::ApplicationHandler; -use crate::error::{EventLoopError, ExternalError, NotSupportedError}; +use crate::error::{EventLoopError, NotSupportedError, RequestError}; use crate::event::{self, Ime, Modifiers, StartCause}; use crate::event_loop::{self, ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents}; use crate::keyboard::{ @@ -284,17 +284,11 @@ impl EventLoop { // events. let (user_events_sender, user_events_receiver) = mpsc::sync_channel(1); - let event_socket = Arc::new( - RedoxSocket::event() - .map_err(OsError::new) - .map_err(|error| EventLoopError::Os(os_error!(error)))?, - ); + let event_socket = + Arc::new(RedoxSocket::event().map_err(|error| os_error!(format!("{error}")))?); - let wake_socket = Arc::new( - TimeSocket::open() - .map_err(OsError::new) - .map_err(|error| EventLoopError::Os(os_error!(error)))?, - ); + let wake_socket = + Arc::new(TimeSocket::open().map_err(|error| os_error!(format!("{error}")))?); event_socket .write(&syscall::Event { @@ -302,8 +296,7 @@ impl EventLoop { flags: syscall::EventFlags::EVENT_READ, data: wake_socket.0.fd, }) - .map_err(OsError::new) - .map_err(|error| EventLoopError::Os(os_error!(error)))?; + .map_err(|error| os_error!(format!("{error}")))?; Ok(Self { windows: Vec::new(), @@ -731,15 +724,15 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_window( &self, window_attributes: crate::window::WindowAttributes, - ) -> Result, crate::error::OsError> { + ) -> Result, RequestError> { Ok(Box::new(Window::new(self, window_attributes)?)) } fn create_custom_cursor( &self, _: CustomCursorSource, - ) -> Result { - Err(ExternalError::NotSupported(NotSupportedError::new())) + ) -> Result { + Err(NotSupportedError::new("create_custom_cursor is not supported").into()) } fn available_monitors(&self) -> Box> { diff --git a/src/platform_impl/orbital/mod.rs b/src/platform_impl/orbital/mod.rs index 4ba0923cc6..f125b6e51d 100644 --- a/src/platform_impl/orbital/mod.rs +++ b/src/platform_impl/orbital/mod.rs @@ -1,9 +1,7 @@ #![cfg(target_os = "redox")] -use std::fmt::{self, Display, Formatter}; use std::num::{NonZeroU16, NonZeroU32}; -use std::str; -use std::sync::Arc; +use std::{fmt, str}; use smol_str::SmolStr; @@ -15,6 +13,11 @@ mod event_loop; pub use self::window::Window; mod window; +pub(crate) use crate::cursor::{ + NoCustomCursor as PlatformCustomCursor, NoCustomCursor as PlatformCustomCursorSource, +}; +pub(crate) use crate::icon::NoIcon as PlatformIcon; + struct RedoxSocket { fd: usize, } @@ -173,26 +176,6 @@ impl<'a> fmt::Display for WindowProperties<'a> { } } -#[derive(Clone, Debug)] -pub struct OsError(Arc); - -impl OsError { - fn new(error: syscall::Error) -> Self { - Self(Arc::new(error)) - } -} - -impl Display for OsError { - fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), fmt::Error> { - self.0.fmt(fmt) - } -} - -pub(crate) use crate::cursor::{ - NoCustomCursor as PlatformCustomCursor, NoCustomCursor as PlatformCustomCursorSource, -}; -pub(crate) use crate::icon::NoIcon as PlatformIcon; - #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct MonitorHandle; diff --git a/src/platform_impl/orbital/window.rs b/src/platform_impl/orbital/window.rs index c23cd88efa..25f011fa11 100644 --- a/src/platform_impl/orbital/window.rs +++ b/src/platform_impl/orbital/window.rs @@ -1,12 +1,10 @@ use std::collections::VecDeque; use std::sync::{Arc, Mutex}; -use super::{ - ActiveEventLoop, MonitorHandle, OsError, RedoxSocket, TimeSocket, WindowId, WindowProperties, -}; +use super::{ActiveEventLoop, MonitorHandle, RedoxSocket, TimeSocket, WindowId, WindowProperties}; use crate::cursor::Cursor; use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; -use crate::error; +use crate::error::{NotSupportedError, RequestError}; use crate::monitor::MonitorHandle as CoreMonitorHandle; use crate::window::{self, Fullscreen, ImePurpose, Window as CoreWindow, WindowId as CoreWindowId}; @@ -32,7 +30,7 @@ impl Window { pub(crate) fn new( el: &ActiveEventLoop, attrs: window::WindowAttributes, - ) -> Result { + ) -> Result { let scale = MonitorHandle.scale_factor(); let (x, y) = if let Some(pos) = attrs.position { @@ -125,20 +123,17 @@ impl Window { }) } - fn get_flag(&self, flag: char) -> Result { + fn get_flag(&self, flag: char) -> Result { let mut buf: [u8; 4096] = [0; 4096]; - let path = self - .window_socket - .fpath(&mut buf) - .map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?; + let path = self.window_socket.fpath(&mut buf).map_err(|err| os_error!(format!("{err}")))?; let properties = WindowProperties::new(path); Ok(properties.flags.contains(flag)) } - fn set_flag(&self, flag: char, value: bool) -> Result<(), error::ExternalError> { + fn set_flag(&self, flag: char, value: bool) -> Result<(), RequestError> { self.window_socket .write(format!("F,{flag},{}", if value { 1 } else { 0 }).as_bytes()) - .map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?; + .map_err(|err| os_error!(format!("{err}")))?; Ok(()) } @@ -204,7 +199,7 @@ impl CoreWindow for Window { } #[inline] - fn inner_position(&self) -> Result, error::NotSupportedError> { + fn inner_position(&self) -> Result, RequestError> { 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); @@ -212,7 +207,7 @@ impl CoreWindow for Window { } #[inline] - fn outer_position(&self) -> Result, error::NotSupportedError> { + fn outer_position(&self) -> Result, RequestError> { // TODO: adjust for window decorations self.inner_position() } @@ -372,12 +367,12 @@ impl CoreWindow for Window { fn set_cursor(&self, _: Cursor) {} #[inline] - fn set_cursor_position(&self, _: Position) -> Result<(), error::ExternalError> { - Err(error::ExternalError::NotSupported(error::NotSupportedError::new())) + fn set_cursor_position(&self, _: Position) -> Result<(), RequestError> { + Err(NotSupportedError::new("set_cursor_position is not supported").into()) } #[inline] - fn set_cursor_grab(&self, mode: window::CursorGrabMode) -> Result<(), error::ExternalError> { + fn set_cursor_grab(&self, mode: window::CursorGrabMode) -> Result<(), RequestError> { let (grab, relative) = match mode { window::CursorGrabMode::None => (false, false), window::CursorGrabMode::Confined => (true, false), @@ -385,10 +380,10 @@ impl CoreWindow for Window { }; self.window_socket .write(format!("M,G,{}", if grab { 1 } else { 0 }).as_bytes()) - .map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?; + .map_err(|err| os_error!(format!("{err}")))?; self.window_socket .write(format!("M,R,{}", if relative { 1 } else { 0 }).as_bytes()) - .map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?; + .map_err(|err| os_error!(format!("{err}")))?; Ok(()) } @@ -398,18 +393,13 @@ impl CoreWindow for Window { } #[inline] - fn drag_window(&self) -> Result<(), error::ExternalError> { - self.window_socket - .write(b"D") - .map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?; + fn drag_window(&self) -> Result<(), RequestError> { + self.window_socket.write(b"D").map_err(|err| os_error!(format!("{err}")))?; Ok(()) } #[inline] - fn drag_resize_window( - &self, - direction: window::ResizeDirection, - ) -> Result<(), error::ExternalError> { + fn drag_resize_window(&self, direction: window::ResizeDirection) -> Result<(), RequestError> { let arg = match direction { window::ResizeDirection::East => "R", window::ResizeDirection::North => "T", @@ -422,7 +412,7 @@ impl CoreWindow for Window { }; self.window_socket .write(format!("D,{}", arg).as_bytes()) - .map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?; + .map_err(|err| os_error!(format!("{err}")))?; Ok(()) } @@ -430,8 +420,8 @@ impl CoreWindow for Window { fn show_window_menu(&self, _position: Position) {} #[inline] - fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), error::ExternalError> { - Err(error::ExternalError::NotSupported(error::NotSupportedError::new())) + fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), RequestError> { + Err(NotSupportedError::new("set_cursor_hittest is not supported").into()) } #[inline] diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 50417b3aef..7b4f63da52 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -11,7 +11,7 @@ use super::event::DeviceId; use super::runner::{EventWrapper, WeakShared}; use super::window::WindowId; use super::{backend, runner, EventLoopProxy}; -use crate::error::{ExternalError, NotSupportedError}; +use crate::error::{NotSupportedError, RequestError}; use crate::event::{ DeviceId as RootDeviceId, ElementState, Event, FingerId as RootFingerId, KeyEvent, Touch, TouchPhase, WindowEvent, @@ -606,7 +606,10 @@ impl ActiveEventLoop { } pub(crate) fn has_multiple_screens(&self) -> Result { - self.runner.monitor().is_extended().ok_or(NotSupportedError::new()) + self.runner + .monitor() + .is_extended() + .ok_or(NotSupportedError::new("has_multiple_screens is not supported")) } pub(crate) fn request_detailed_monitor_permission(&self) -> MonitorPermissionFuture { @@ -631,7 +634,7 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_window( &self, window_attributes: crate::window::WindowAttributes, - ) -> Result, crate::error::OsError> { + ) -> Result, RequestError> { let window = Window::new(self, window_attributes)?; Ok(Box::new(window)) } @@ -639,7 +642,7 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_custom_cursor( &self, source: CustomCursorSource, - ) -> Result { + ) -> Result { Ok(RootCustomCursor { inner: CustomCursor::new(self, source.inner) }) } diff --git a/src/platform_impl/web/mod.rs b/src/platform_impl/web/mod.rs index d429dd07a9..b99dd3cb90 100644 --- a/src/platform_impl/web/mod.rs +++ b/src/platform_impl/web/mod.rs @@ -37,7 +37,6 @@ pub(crate) use cursor::{ CustomCursorSource as PlatformCustomCursorSource, }; -pub use self::error::OsError; pub use self::event::{DeviceId, FingerId}; pub(crate) use self::event_loop::{ ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle, diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index f5050f4875..a1e5096e00 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -22,10 +22,10 @@ use super::media_query_handle::MediaQueryListHandle; use super::pointer::PointerHandler; use super::{event, fullscreen, ButtonsState, ResizeScaleHandle}; use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize}; -use crate::error::OsError as RootOE; +use crate::error::RequestError; use crate::event::{Force, MouseButton, MouseScrollDelta, SurfaceSizeWriter}; use crate::keyboard::{Key, KeyLocation, ModifiersState, PhysicalKey}; -use crate::platform_impl::{Fullscreen, OsError}; +use crate::platform_impl::Fullscreen; use crate::window::{WindowAttributes, WindowId as RootWindowId}; #[allow(dead_code)] @@ -83,13 +83,13 @@ impl Canvas { navigator: Navigator, document: Document, attr: WindowAttributes, - ) -> Result { + ) -> Result { let canvas = match attr.platform_specific.canvas.map(Arc::try_unwrap) { Some(Ok(canvas)) => canvas.into_inner(main_thread), Some(Err(canvas)) => canvas.get(main_thread).clone(), None => document .create_element("canvas") - .map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))? + .map_err(|_| os_error!("Failed to create canvas element"))? .unchecked_into(), }; @@ -109,7 +109,7 @@ impl Canvas { if attr.platform_specific.focusable { canvas .set_attribute("tabindex", "0") - .map_err(|_| os_error!(OsError("Failed to set a tabindex".to_owned())))?; + .map_err(|_| os_error!("Failed to set a tabindex"))?; } let style = Style::new(&window, &canvas); diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index 239c58e9d5..d979310a6e 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -9,7 +9,7 @@ use super::monitor::MonitorHandler; use super::r#async::Dispatcher; use super::{backend, lock, ActiveEventLoop}; use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; -use crate::error::{ExternalError, NotSupportedError, OsError as RootOE}; +use crate::error::{NotSupportedError, RequestError}; use crate::icon::Icon; use crate::monitor::MonitorHandle as RootMonitorHandle; use crate::window::{ @@ -31,7 +31,10 @@ pub struct Inner { } impl Window { - pub(crate) fn new(target: &ActiveEventLoop, attr: WindowAttributes) -> Result { + pub(crate) fn new( + target: &ActiveEventLoop, + attr: WindowAttributes, + ) -> Result { let id = target.generate_id(); let window = target.runner.window(); @@ -106,13 +109,13 @@ impl RootWindow for Window { // Not supported } - fn inner_position(&self) -> Result, NotSupportedError> { + fn inner_position(&self) -> Result, RequestError> { // Note: the canvas element has no window decorations, so this is equal to `outer_position`. self.outer_position() } - fn outer_position(&self) -> Result, NotSupportedError> { - self.inner.queue(|inner| Ok(inner.canvas.position().to_physical(inner.scale_factor()))) + fn outer_position(&self) -> Result, RequestError> { + Ok(self.inner.queue(|inner| inner.canvas.position().to_physical(inner.scale_factor()))) } fn set_outer_position(&self, position: Position) { @@ -315,12 +318,12 @@ impl RootWindow for Window { self.inner.dispatch(move |inner| inner.canvas.cursor.set_cursor(cursor)) } - fn set_cursor_position(&self, _: Position) -> Result<(), ExternalError> { - Err(ExternalError::NotSupported(NotSupportedError::new())) + fn set_cursor_position(&self, _: Position) -> Result<(), RequestError> { + Err(NotSupportedError::new("set_cursor_position is not supported").into()) } - fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { - self.inner.queue(|inner| { + fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), RequestError> { + Ok(self.inner.queue(|inner| { match mode { CursorGrabMode::None => inner.canvas.document().exit_pointer_lock(), CursorGrabMode::Locked => lock::request_pointer_lock( @@ -329,30 +332,30 @@ impl RootWindow for Window { inner.canvas.raw(), ), CursorGrabMode::Confined => { - return Err(ExternalError::NotSupported(NotSupportedError::new())) + return Err(NotSupportedError::new("confined cursor mode is not supported")) }, } Ok(()) - }) + })?) } fn set_cursor_visible(&self, visible: bool) { self.inner.dispatch(move |inner| inner.canvas.cursor.set_cursor_visible(visible)) } - fn drag_window(&self) -> Result<(), ExternalError> { - Err(ExternalError::NotSupported(NotSupportedError::new())) + fn drag_window(&self) -> Result<(), RequestError> { + Err(NotSupportedError::new("drag_window is not supported").into()) } - fn drag_resize_window(&self, _: ResizeDirection) -> Result<(), ExternalError> { - Err(ExternalError::NotSupported(NotSupportedError::new())) + fn drag_resize_window(&self, _: ResizeDirection) -> Result<(), RequestError> { + Err(NotSupportedError::new("drag_resize_window is not supported").into()) } fn show_window_menu(&self, _: Position) {} - fn set_cursor_hittest(&self, _: bool) -> Result<(), ExternalError> { - Err(ExternalError::NotSupported(NotSupportedError::new())) + fn set_cursor_hittest(&self, _: bool) -> Result<(), RequestError> { + Err(NotSupportedError::new("set_cursor_hittest is not supported").into()) } fn current_monitor(&self) -> Option { diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index b63ece77d7..5c7a3e1a49 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -56,7 +56,7 @@ use super::window::set_skip_taskbar; use super::SelectedCursor; use crate::application::ApplicationHandler; use crate::dpi::{PhysicalPosition, PhysicalSize}; -use crate::error::{EventLoopError, ExternalError, OsError}; +use crate::error::{EventLoopError, RequestError}; use crate::event::{ Event, FingerId as RootFingerId, Force, Ime, RawKeyEvent, SurfaceSizeWriter, Touch, TouchPhase, WindowEvent, @@ -521,14 +521,14 @@ impl RootActiveEventLoop for ActiveEventLoop { fn create_window( &self, window_attributes: WindowAttributes, - ) -> Result, OsError> { + ) -> Result, RequestError> { Ok(Box::new(Window::new(self, window_attributes)?)) } fn create_custom_cursor( &self, source: CustomCursorSource, - ) -> Result { + ) -> Result { Ok(RootCustomCursor { inner: WinCursor::new(&source.inner.0)? }) } diff --git a/src/platform_impl/windows/icon.rs b/src/platform_impl/windows/icon.rs index b3e814becc..b5f43a676e 100644 --- a/src/platform_impl/windows/icon.rs +++ b/src/platform_impl/windows/icon.rs @@ -17,7 +17,7 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{ use super::util; use crate::cursor::CursorImage; use crate::dpi::PhysicalSize; -use crate::error::ExternalError; +use crate::error::RequestError; use crate::icon::*; impl Pixel { @@ -179,7 +179,7 @@ impl Default for SelectedCursor { pub struct WinCursor(pub(super) Arc); impl WinCursor { - pub(crate) fn new(image: &CursorImage) -> Result { + pub(crate) fn new(image: &CursorImage) -> Result { let mut bgra = image.rgba.clone(); bgra.chunks_exact_mut(4).for_each(|chunk| chunk.swap(0, 2)); @@ -189,16 +189,16 @@ impl WinCursor { unsafe { let hdc_screen = GetDC(0); if hdc_screen == 0 { - return Err(ExternalError::Os(os_error!(io::Error::last_os_error()))); + return Err(os_error!(io::Error::last_os_error()).into()); } let hbm_color = CreateCompatibleBitmap(hdc_screen, w, h); ReleaseDC(0, hdc_screen); if hbm_color == 0 { - return Err(ExternalError::Os(os_error!(io::Error::last_os_error()))); + return Err(os_error!(io::Error::last_os_error()).into()); } if SetBitmapBits(hbm_color, bgra.len() as u32, bgra.as_ptr() as *const c_void) == 0 { DeleteObject(hbm_color); - return Err(ExternalError::Os(os_error!(io::Error::last_os_error()))); + return Err(os_error!(io::Error::last_os_error()).into()); }; // Mask created according to https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createbitmap#parameters @@ -206,7 +206,7 @@ impl WinCursor { let hbm_mask = CreateBitmap(w, h, 1, 1, mask_bits.as_ptr() as *const _); if hbm_mask == 0 { DeleteObject(hbm_color); - return Err(ExternalError::Os(os_error!(io::Error::last_os_error()))); + return Err(os_error!(io::Error::last_os_error()).into()); } let icon_info = ICONINFO { @@ -221,7 +221,7 @@ impl WinCursor { DeleteObject(hbm_color); DeleteObject(hbm_mask); if handle == 0 { - return Err(ExternalError::Os(os_error!(io::Error::last_os_error()))); + return Err(os_error!(io::Error::last_os_error()).into()); } Ok(Self(Arc::new(RaiiCursor { handle }))) diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 93349f7f14..92079ebbc1 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -103,8 +103,6 @@ fn wrap_device_id(id: u32) -> RootDeviceId { RootDeviceId(DeviceId(id)) } -pub type OsError = std::io::Error; - #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct KeyEventExtra { pub text_with_all_modifiers: Option, diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index c08cc436ae..db0dd9ba7c 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -47,7 +47,7 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{ use crate::cursor::Cursor; use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; -use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError}; +use crate::error::{NotSupportedError, RequestError}; use crate::icon::Icon; use crate::monitor::MonitorHandle as CoreMonitorHandle; use crate::platform::windows::{BackdropType, Color, CornerPreference}; @@ -89,7 +89,7 @@ impl Window { pub(crate) fn new( event_loop: &ActiveEventLoop, w_attr: WindowAttributes, - ) -> Result { + ) -> Result { // We dispatch an `init` function because of code style. // First person to remove the need for cloning here gets a cookie! // @@ -411,7 +411,7 @@ impl CoreWindow for Window { fn pre_present_notify(&self) {} - fn outer_position(&self) -> Result, NotSupportedError> { + fn outer_position(&self) -> Result, RequestError> { util::WindowArea::Outer .get_rect(self.hwnd()) .map(|rect| Ok(PhysicalPosition::new(rect.left, rect.top))) @@ -421,7 +421,7 @@ impl CoreWindow for Window { ) } - fn inner_position(&self) -> Result, NotSupportedError> { + fn inner_position(&self) -> Result, RequestError> { let mut position: POINT = unsafe { mem::zeroed() }; if unsafe { ClientToScreen(self.hwnd(), &mut position) } == false.into() { panic!( @@ -588,12 +588,12 @@ impl CoreWindow for Window { } } - fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> { + fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), RequestError> { let confine = match mode { CursorGrabMode::None => false, CursorGrabMode::Confined => true, CursorGrabMode::Locked => { - return Err(ExternalError::NotSupported(NotSupportedError::new())) + return Err(NotSupportedError::new("locked cursor is not supported").into()) }, }; @@ -608,9 +608,10 @@ impl CoreWindow for Window { .unwrap() .mouse .set_cursor_flags(window, |f| f.set(CursorFlags::GRABBED, confine)) - .map_err(|e| ExternalError::Os(os_error!(e))); + .map_err(|err| os_error!(err).into()); let _ = tx.send(result); }); + rx.recv().unwrap() } @@ -636,23 +637,23 @@ impl CoreWindow for Window { self.window_state_lock().scale_factor } - fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> { + fn set_cursor_position(&self, position: Position) -> Result<(), RequestError> { let scale_factor = self.scale_factor(); let (x, y) = position.to_physical::(scale_factor).into(); let mut point = POINT { x, y }; unsafe { if ClientToScreen(self.hwnd(), &mut point) == false.into() { - return Err(ExternalError::Os(os_error!(io::Error::last_os_error()))); + return Err(os_error!(io::Error::last_os_error()).into()); } if SetCursorPos(point.x, point.y) == false.into() { - return Err(ExternalError::Os(os_error!(io::Error::last_os_error()))); + return Err(os_error!(io::Error::last_os_error()).into()); } } Ok(()) } - fn drag_window(&self) -> Result<(), ExternalError> { + fn drag_window(&self) -> Result<(), RequestError> { unsafe { self.handle_os_dragging(HTCAPTION as WPARAM); } @@ -660,7 +661,7 @@ impl CoreWindow for Window { Ok(()) } - fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { + fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), RequestError> { unsafe { self.handle_os_dragging(match direction { ResizeDirection::East => HTRIGHT, @@ -683,7 +684,7 @@ impl CoreWindow for Window { } } - fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> { + fn set_cursor_hittest(&self, hittest: bool) -> Result<(), RequestError> { let window = self.window; let window_state = Arc::clone(&self.window_state); self.thread_executor.execute_in_thread(move || { @@ -1249,7 +1250,7 @@ impl<'a> InitData<'a> { unsafe fn init( attributes: WindowAttributes, event_loop: &ActiveEventLoop, -) -> Result { +) -> Result { let title = util::encode_wide(&attributes.title); let class_name = util::encode_wide(&attributes.platform_specific.class_name); @@ -1332,7 +1333,7 @@ unsafe fn init( } if handle == 0 { - return Err(os_error!(io::Error::last_os_error())); + return Err(os_error!(io::Error::last_os_error()).into()); } // If the handle is non-null, then window creation must have succeeded, which means diff --git a/src/window.rs b/src/window.rs index 6a3dd62539..1ded68b146 100644 --- a/src/window.rs +++ b/src/window.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; pub use crate::cursor::{BadImage, Cursor, CustomCursor, CustomCursorSource, MAX_CURSOR_SIZE}; use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; -use crate::error::{ExternalError, NotSupportedError}; +use crate::error::RequestError; pub use crate::icon::{BadIcon, Icon}; use crate::monitor::{MonitorHandle, VideoModeHandle}; use crate::platform_impl::{self, PlatformSpecificWindowAttributes}; @@ -601,10 +601,10 @@ pub trait Window: AsAny + Send + Sync { /// coordinate system. /// - **Web:** Returns the top-left coordinates relative to the viewport. _Note: this returns /// the same value as [`Window::outer_position`]._ - /// - **Android / Wayland:** Always returns [`NotSupportedError`]. + /// - **Android / Wayland:** Always returns [`RequestError::NotSupported`]. /// /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc - fn inner_position(&self) -> Result, NotSupportedError>; + fn inner_position(&self) -> Result, RequestError>; /// Returns the position of the top-left hand corner of the window relative to the /// top-left hand corner of the desktop. @@ -621,8 +621,8 @@ pub trait Window: AsAny + Send + Sync { /// - **iOS:** Returns the top left coordinates of the window in the screen space coordinate /// system. /// - **Web:** Returns the top-left coordinates relative to the viewport. - /// - **Android / Wayland:** Always returns [`NotSupportedError`]. - fn outer_position(&self) -> Result, NotSupportedError>; + /// - **Android / Wayland:** Always returns [`RequestError::NotSupported`]. + fn outer_position(&self) -> Result, RequestError>; /// Modifies the position of the window. /// @@ -1160,8 +1160,8 @@ pub trait Window: AsAny + Send + Sync { /// ## Platform-specific /// /// - **Wayland**: Cursor must be in [`CursorGrabMode::Locked`]. - /// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`]. - fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError>; + /// - **iOS / Android / Web / Orbital:** Always returns an [`RequestError::NotSupported`]. + fn set_cursor_position(&self, position: Position) -> Result<(), RequestError>; /// Set grabbing [mode][CursorGrabMode] on the cursor preventing it from leaving the window. /// @@ -1178,7 +1178,7 @@ pub trait Window: AsAny + Send + Sync { /// .unwrap(); /// # } /// ``` - fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError>; + fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), RequestError>; /// Modifies the cursor's visibility. /// @@ -1204,8 +1204,8 @@ pub trait Window: AsAny + Send + Sync { /// - **X11:** Un-grabs the cursor. /// - **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`]. - fn drag_window(&self) -> Result<(), ExternalError>; + /// - **iOS / Android / Web:** Always returns an [`RequestError::NotSupported`]. + fn drag_window(&self) -> Result<(), RequestError>; /// Resizes the window with the left mouse button until the button is released. /// @@ -1214,9 +1214,9 @@ pub trait Window: AsAny + Send + Sync { /// /// ## Platform-specific /// - /// - **macOS:** Always returns an [`ExternalError::NotSupported`] - /// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`]. - fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError>; + /// - **macOS:** Always returns an [`RequestError::NotSupported`] + /// - **iOS / Android / Web:** Always returns an [`RequestError::NotSupported`]. + fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), RequestError>; /// Show [window menu] at a specified position . /// @@ -1237,8 +1237,8 @@ pub trait Window: AsAny + Send + Sync { /// /// ## Platform-specific /// - /// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`]. - fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError>; + /// - **iOS / Android / Web / Orbital:** Always returns an [`RequestError::NotSupported`]. + fn set_cursor_hittest(&self, hittest: bool) -> Result<(), RequestError>; /// Returns the monitor on which the window currently resides. /// @@ -1345,8 +1345,8 @@ pub enum CursorGrabMode { /// /// ## Platform-specific /// - /// - **macOS:** Not implemented. Always returns [`ExternalError::NotSupported`] for now. - /// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`]. + /// - **macOS:** Not implemented. Always returns [`RequestError::NotSupported`] for now. + /// - **iOS / Android / Web:** Always returns an [`RequestError::NotSupported`]. Confined, /// The cursor is locked inside the window area to the certain position. @@ -1356,9 +1356,9 @@ pub enum CursorGrabMode { /// /// ## Platform-specific /// - /// - **X11 / Windows:** Not implemented. Always returns [`ExternalError::NotSupported`] for + /// - **X11 / Windows:** Not implemented. Always returns [`RequestError::NotSupported`] for /// now. - /// - **iOS / Android:** Always returns an [`ExternalError::NotSupported`]. + /// - **iOS / Android:** Always returns an [`RequestError::NotSupported`]. Locked, }