From 277b848ad8df1e8d038e33707548a45d63a601db Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 18 Jul 2022 18:37:41 +0200 Subject: Remove `window::Mode` and introduce `Settings::visible` Additionally, only show the window once one frame has been rendered to avoid blank flashes on Windows. --- glutin/src/application.rs | 25 +++++++++++++++++++------ src/application.rs | 21 --------------------- src/window.rs | 2 -- src/window/mode.rs | 12 ------------ src/window/settings.rs | 5 +++++ winit/src/application.rs | 37 ++++++++++++++++++++----------------- winit/src/application/state.rs | 19 +------------------ winit/src/conversion.rs | 25 +------------------------ winit/src/lib.rs | 2 -- winit/src/mode.rs | 12 ------------ winit/src/settings.rs | 13 ++++++------- 11 files changed, 52 insertions(+), 121 deletions(-) delete mode 100644 src/window/mode.rs delete mode 100644 winit/src/mode.rs diff --git a/glutin/src/application.rs b/glutin/src/application.rs index 24f315fb..054cf839 100644 --- a/glutin/src/application.rs +++ b/glutin/src/application.rs @@ -54,13 +54,17 @@ where runtime.enter(|| A::new(flags)) }; + let should_be_visible = settings.window.visible; + let context = { - let builder = settings.window.into_builder( - &application.title(), - application.mode(), - event_loop.primary_monitor(), - settings.id, - ); + let builder = settings + .window + .into_builder( + &application.title(), + event_loop.primary_monitor(), + settings.id, + ) + .with_visible(false); log::info!("Window builder: {:#?}", builder); @@ -135,6 +139,7 @@ where receiver, context, init_command, + should_be_visible, settings.exit_on_close_request, )); @@ -187,6 +192,7 @@ async fn run_instance( mut receiver: mpsc::UnboundedReceiver>, mut context: glutin::ContextWrapper, init_command: Command, + should_be_visible: bool, exit_on_close_request: bool, ) where A: Application + 'static, @@ -200,6 +206,7 @@ async fn run_instance( let mut clipboard = Clipboard::connect(context.window()); let mut cache = user_interface::Cache::default(); let mut state = application::State::new(&application, context.window()); + let mut visible = false; let mut viewport_version = state.viewport_version(); application::run_command( @@ -399,6 +406,12 @@ async fn run_instance( debug.render_finished(); + if !visible && should_be_visible { + context.window().set_visible(true); + + visible = true; + } + // TODO: Handle animations! // Maybe we can use `ControlFlow::WaitUntil` for this. } diff --git a/src/application.rs b/src/application.rs index 58d4a577..23ce034e 100644 --- a/src/application.rs +++ b/src/application.rs @@ -1,5 +1,4 @@ //! Build interactive cross-platform applications. -use crate::window; use crate::{Command, Element, Executor, Settings, Subscription}; pub use iced_native::application::{Appearance, StyleSheet}; @@ -169,18 +168,6 @@ pub trait Application: Sized { Subscription::none() } - /// Returns the current [`Application`] mode. - /// - /// The runtime will automatically transition your application if a new mode - /// is returned. - /// - /// Currently, the mode only has an effect in native platforms. - /// - /// By default, an application will run in windowed mode. - fn mode(&self) -> window::Mode { - window::Mode::Windowed - } - /// Returns the scale factor of the [`Application`]. /// /// It can be used to dynamically control the size of the UI at runtime @@ -277,14 +264,6 @@ where self.0.style() } - fn mode(&self) -> iced_winit::Mode { - match self.0.mode() { - window::Mode::Windowed => iced_winit::Mode::Windowed, - window::Mode::Fullscreen => iced_winit::Mode::Fullscreen, - window::Mode::Hidden => iced_winit::Mode::Hidden, - } - } - fn subscription(&self) -> Subscription { self.0.subscription() } diff --git a/src/window.rs b/src/window.rs index 71158816..eb5e17a6 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,12 +1,10 @@ //! Configure the window of your application in native platforms. -mod mode; mod position; mod settings; pub mod icon; pub use icon::Icon; -pub use mode::Mode; pub use position::Position; pub use settings::Settings; diff --git a/src/window/mode.rs b/src/window/mode.rs deleted file mode 100644 index fdce8e23..00000000 --- a/src/window/mode.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// The mode of a window-based application. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Mode { - /// The application appears in its own window. - Windowed, - - /// The application takes the whole screen of its current monitor. - Fullscreen, - - /// The application is hidden - Hidden, -} diff --git a/src/window/settings.rs b/src/window/settings.rs index 8e32f4fb..24d0f4f9 100644 --- a/src/window/settings.rs +++ b/src/window/settings.rs @@ -15,6 +15,9 @@ pub struct Settings { /// The maximum size of the window. pub max_size: Option<(u32, u32)>, + /// Whether the window should be visible or not. + pub visible: bool, + /// Whether the window should be resizable or not. pub resizable: bool, @@ -38,6 +41,7 @@ impl Default for Settings { position: Position::default(), min_size: None, max_size: None, + visible: true, resizable: true, decorations: true, transparent: false, @@ -54,6 +58,7 @@ impl From for iced_winit::settings::Window { position: iced_winit::Position::from(settings.position), min_size: settings.min_size, max_size: settings.max_size, + visible: settings.visible, resizable: settings.resizable, decorations: settings.decorations, transparent: settings.transparent, diff --git a/winit/src/application.rs b/winit/src/application.rs index 3a5c3dac..23364209 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -9,7 +9,7 @@ use crate::mouse; use crate::renderer; use crate::widget::operation; use crate::{ - Command, Debug, Error, Executor, Mode, Proxy, Runtime, Settings, Size, + Command, Debug, Error, Executor, Proxy, Runtime, Settings, Size, Subscription, }; @@ -81,16 +81,6 @@ where Subscription::none() } - /// Returns the current [`Application`] mode. - /// - /// The runtime will automatically transition your application if a new mode - /// is returned. - /// - /// By default, an application will run in windowed mode. - fn mode(&self) -> Mode { - Mode::Windowed - } - /// Returns the scale factor of the [`Application`]. /// /// It can be used to dynamically control the size of the UI at runtime @@ -147,12 +137,15 @@ where runtime.enter(|| A::new(flags)) }; - let builder = settings.window.into_builder( - &application.title(), - application.mode(), - event_loop.primary_monitor(), - settings.id, - ); + let should_be_visible = settings.window.visible; + let builder = settings + .window + .into_builder( + &application.title(), + event_loop.primary_monitor(), + settings.id, + ) + .with_visible(false); log::info!("Window builder: {:#?}", builder); @@ -189,6 +182,7 @@ where receiver, init_command, window, + should_be_visible, settings.exit_on_close_request, )); @@ -239,6 +233,7 @@ async fn run_instance( mut receiver: mpsc::UnboundedReceiver>, init_command: Command, window: winit::window::Window, + should_be_visible: bool, exit_on_close_request: bool, ) where A: Application + 'static, @@ -252,6 +247,7 @@ async fn run_instance( let mut clipboard = Clipboard::connect(&window); let mut cache = user_interface::Cache::default(); let mut surface = compositor.create_surface(&window); + let mut visible = false; let mut state = State::new(&application, &window); let mut viewport_version = state.viewport_version(); @@ -383,6 +379,7 @@ async fn run_instance( event::MacOS::ReceivedUrl(url), )) => { use iced_native::event; + events.push(iced_native::Event::PlatformSpecific( event::PlatformSpecific::MacOS(event::MacOS::ReceivedUrl( url, @@ -450,6 +447,12 @@ async fn run_instance( Ok(()) => { debug.render_finished(); + if !visible && should_be_visible { + window.set_visible(true); + + visible = true; + } + // TODO: Handle animations! // Maybe we can use `ControlFlow::WaitUntil` for this. } diff --git a/winit/src/application/state.rs b/winit/src/application/state.rs index 6b843919..5e953cb5 100644 --- a/winit/src/application/state.rs +++ b/winit/src/application/state.rs @@ -1,6 +1,6 @@ use crate::application::{self, StyleSheet as _}; use crate::conversion; -use crate::{Application, Color, Debug, Mode, Point, Size, Viewport}; +use crate::{Application, Color, Debug, Point, Size, Viewport}; use std::marker::PhantomData; use winit::event::{Touch, WindowEvent}; @@ -13,7 +13,6 @@ where ::Theme: application::StyleSheet, { title: String, - mode: Mode, scale_factor: f64, viewport: Viewport, viewport_version: usize, @@ -31,7 +30,6 @@ where /// Creates a new [`State`] for the provided [`Application`] and window. pub fn new(application: &A, window: &Window) -> Self { let title = application.title(); - let mode = application.mode(); let scale_factor = application.scale_factor(); let theme = application.theme(); let appearance = theme.appearance(application.style()); @@ -47,7 +45,6 @@ where Self { title, - mode, scale_factor, viewport, viewport_version: 0, @@ -193,20 +190,6 @@ where self.title = new_title; } - // Update window mode - let new_mode = application.mode(); - - if self.mode != new_mode { - window.set_fullscreen(conversion::fullscreen( - window.current_monitor(), - new_mode, - )); - - window.set_visible(conversion::visible(new_mode)); - - self.mode = new_mode; - } - // Update scale factor let new_scale_factor = application.scale_factor(); diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index 74f6f7a0..05c9746e 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -6,7 +6,7 @@ use crate::keyboard; use crate::mouse; use crate::touch; use crate::window; -use crate::{Event, Mode, Point, Position}; +use crate::{Event, Point, Position}; /// Converts a winit window event into an iced event. pub fn window_event( @@ -182,29 +182,6 @@ pub fn position( } } -/// Converts a [`Mode`] to a [`winit`] fullscreen mode. -/// -/// [`winit`]: https://github.com/rust-windowing/winit -pub fn fullscreen( - monitor: Option, - mode: Mode, -) -> Option { - match mode { - Mode::Windowed | Mode::Hidden => None, - Mode::Fullscreen => { - Some(winit::window::Fullscreen::Borderless(monitor)) - } - } -} - -/// Converts a [`Mode`] to a visibility flag. -pub fn visible(mode: Mode) -> bool { - match mode { - Mode::Windowed | Mode::Fullscreen => true, - Mode::Hidden => false, - } -} - /// Converts a `MouseCursor` from [`iced_native`] to a [`winit`] cursor icon. /// /// [`winit`]: https://github.com/rust-windowing/winit diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 3bde0f2b..e32cc9af 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -45,14 +45,12 @@ pub mod window; pub mod system; mod error; -mod mode; mod position; mod proxy; pub use application::Application; pub use clipboard::Clipboard; pub use error::Error; -pub use mode::Mode; pub use position::Position; pub use proxy::Proxy; pub use settings::Settings; diff --git a/winit/src/mode.rs b/winit/src/mode.rs deleted file mode 100644 index fdce8e23..00000000 --- a/winit/src/mode.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// The mode of a window-based application. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Mode { - /// The application appears in its own window. - Windowed, - - /// The application takes the whole screen of its current monitor. - Fullscreen, - - /// The application is hidden - Hidden, -} diff --git a/winit/src/settings.rs b/winit/src/settings.rs index 213ef47f..7175b9ed 100644 --- a/winit/src/settings.rs +++ b/winit/src/settings.rs @@ -14,7 +14,7 @@ mod platform; pub use platform::PlatformSpecific; use crate::conversion; -use crate::{Mode, Position}; +use crate::Position; use winit::monitor::MonitorHandle; use winit::window::WindowBuilder; @@ -65,6 +65,9 @@ pub struct Window { /// The maximum size of the window. pub max_size: Option<(u32, u32)>, + /// Whether the window should be visible or not. + pub visible: bool, + /// Whether the window should be resizable or not. pub resizable: bool, @@ -89,7 +92,6 @@ impl Window { pub fn into_builder( self, title: &str, - mode: Mode, primary_monitor: Option, _id: Option, ) -> WindowBuilder { @@ -104,8 +106,7 @@ impl Window { .with_decorations(self.decorations) .with_transparent(self.transparent) .with_window_icon(self.icon) - .with_always_on_top(self.always_on_top) - .with_visible(conversion::visible(mode)); + .with_always_on_top(self.always_on_top); if let Some(position) = conversion::position( primary_monitor.as_ref(), @@ -166,9 +167,6 @@ impl Window { ); } - window_builder = window_builder - .with_fullscreen(conversion::fullscreen(primary_monitor, mode)); - window_builder } } @@ -180,6 +178,7 @@ impl Default for Window { position: Position::default(), min_size: None, max_size: None, + visible: true, resizable: true, decorations: true, transparent: false, -- cgit From 11f5527d7645619f49b030e30485f24ac637efbd Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 18 Aug 2022 14:39:15 +0200 Subject: Implement `SetMode` and `FetchMode` window actions --- native/src/command/action.rs | 4 ++-- native/src/window.rs | 2 ++ native/src/window/action.rs | 47 ++++++++++++++++++++++++++++++++++++++++++-- native/src/window/mode.rs | 12 +++++++++++ winit/src/application.rs | 14 +++++++++++++ winit/src/conversion.rs | 33 +++++++++++++++++++++++++++++++ winit/src/window.rs | 16 ++++++++++++++- 7 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 native/src/window/mode.rs diff --git a/native/src/command/action.rs b/native/src/command/action.rs index 3fb02899..a6954f8f 100644 --- a/native/src/command/action.rs +++ b/native/src/command/action.rs @@ -20,7 +20,7 @@ pub enum Action { Clipboard(clipboard::Action), /// Run a window action. - Window(window::Action), + Window(window::Action), /// Run a system action. System(system::Action), @@ -46,7 +46,7 @@ impl Action { match self { Self::Future(future) => Action::Future(Box::pin(future.map(f))), Self::Clipboard(action) => Action::Clipboard(action.map(f)), - Self::Window(window) => Action::Window(window), + Self::Window(window) => Action::Window(window.map(f)), Self::System(system) => Action::System(system.map(f)), Self::Widget(widget) => Action::Widget(widget.map(f)), } diff --git a/native/src/window.rs b/native/src/window.rs index 62487fb9..f910b8f2 100644 --- a/native/src/window.rs +++ b/native/src/window.rs @@ -1,6 +1,8 @@ //! Build window-based GUI applications. mod action; mod event; +mod mode; pub use action::Action; pub use event::Event; +pub use mode::Mode; diff --git a/native/src/window/action.rs b/native/src/window/action.rs index 01294e83..d891c6ac 100644 --- a/native/src/window/action.rs +++ b/native/src/window/action.rs @@ -1,6 +1,10 @@ +use crate::window::Mode; + +use iced_futures::MaybeSend; +use std::fmt; + /// An operation to be performed on some window. -#[derive(Debug)] -pub enum Action { +pub enum Action { /// Resize the window. Resize { /// The new logical width of the window @@ -15,4 +19,43 @@ pub enum Action { /// The new logical y location of the window y: i32, }, + /// Set the [`Mode`] of the window. + SetMode(Mode), + /// Fetch the current [`Mode`] of the window. + FetchMode(Box T + 'static>), +} + +impl Action { + /// Maps the output of a window [`Action`] using the provided closure. + pub fn map( + self, + f: impl Fn(T) -> A + 'static + MaybeSend + Sync, + ) -> Action + where + T: 'static, + { + match self { + Self::Resize { width, height } => Action::Resize { width, height }, + Self::Move { x, y } => Action::Move { x, y }, + Self::SetMode(mode) => Action::SetMode(mode), + Self::FetchMode(o) => Action::FetchMode(Box::new(move |s| f(o(s)))), + } + } +} + +impl fmt::Debug for Action { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Resize { width, height } => write!( + f, + "Action::Resize {{ widget: {}, height: {} }}", + width, height + ), + Self::Move { x, y } => { + write!(f, "Action::Move {{ x: {}, y: {} }}", x, y) + } + Self::SetMode(mode) => write!(f, "Action::SetMode({:?})", mode), + Self::FetchMode(_) => write!(f, "Action::FetchMode"), + } + } } diff --git a/native/src/window/mode.rs b/native/src/window/mode.rs new file mode 100644 index 00000000..fdce8e23 --- /dev/null +++ b/native/src/window/mode.rs @@ -0,0 +1,12 @@ +/// The mode of a window-based application. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Mode { + /// The application appears in its own window. + Windowed, + + /// The application takes the whole screen of its current monitor. + Fullscreen, + + /// The application is hidden + Hidden, +} diff --git a/winit/src/application.rs b/winit/src/application.rs index 23364209..ecec6043 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -640,6 +640,20 @@ pub fn run_command( y, }); } + window::Action::SetMode(mode) => { + window.set_visible(conversion::visible(mode)); + window.set_fullscreen(conversion::fullscreen( + window.primary_monitor(), + mode, + )); + } + window::Action::FetchMode(tag) => { + let mode = conversion::mode(window.fullscreen()); + + proxy + .send_event(tag(mode)) + .expect("Send message to event loop"); + } }, command::Action::System(action) => match action { system::Action::QueryInformation(_tag) => { diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index 05c9746e..ba5b0002 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -182,6 +182,39 @@ pub fn position( } } +/// Converts a [`window::Mode`] to a [`winit`] fullscreen mode. +/// +/// [`winit`]: https://github.com/rust-windowing/winit +pub fn fullscreen( + monitor: Option, + mode: window::Mode, +) -> Option { + match mode { + window::Mode::Windowed | window::Mode::Hidden => None, + window::Mode::Fullscreen => { + Some(winit::window::Fullscreen::Borderless(monitor)) + } + } +} + +/// Converts a [`window::Mode`] to a visibility flag. +pub fn visible(mode: window::Mode) -> bool { + match mode { + window::Mode::Windowed | window::Mode::Fullscreen => true, + window::Mode::Hidden => false, + } +} + +/// Converts a [`winit`] fullscreen mode to a [`window::Mode`]. +/// +/// [`winit`]: https://github.com/rust-windowing/winit +pub fn mode(mode: Option) -> window::Mode { + match mode { + None => window::Mode::Windowed, + Some(_) => window::Mode::Fullscreen, + } +} + /// Converts a `MouseCursor` from [`iced_native`] to a [`winit`] cursor icon. /// /// [`winit`]: https://github.com/rust-windowing/winit diff --git a/winit/src/window.rs b/winit/src/window.rs index f3207e68..265139f7 100644 --- a/winit/src/window.rs +++ b/winit/src/window.rs @@ -2,7 +2,7 @@ use crate::command::{self, Command}; use iced_native::window; -pub use window::Event; +pub use window::{Event, Mode}; /// Resizes the window to the given logical dimensions. pub fn resize(width: u32, height: u32) -> Command { @@ -16,3 +16,17 @@ pub fn resize(width: u32, height: u32) -> Command { pub fn move_to(x: i32, y: i32) -> Command { Command::single(command::Action::Window(window::Action::Move { x, y })) } + +/// Sets the [`Mode`] of the window. +pub fn set_mode(mode: Mode) -> Command { + Command::single(command::Action::Window(window::Action::SetMode(mode))) +} + +/// Fetches the current [`Mode`] of the window. +pub fn fetch_mode( + f: impl FnOnce(Mode) -> Message + 'static, +) -> Command { + Command::single(command::Action::Window(window::Action::FetchMode( + Box::new(f), + ))) +} -- cgit