Remove window::Mode and introduce Settings::visible

Additionally, only show the window once one frame has been rendered to avoid blank flashes on Windows.
This commit is contained in:
Héctor Ramón Jiménez 2022-07-18 18:37:41 +02:00
parent 07cbed1064
commit 277b848ad8
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
11 changed files with 52 additions and 121 deletions

View file

@ -54,13 +54,17 @@ where
runtime.enter(|| A::new(flags)) runtime.enter(|| A::new(flags))
}; };
let should_be_visible = settings.window.visible;
let context = { let context = {
let builder = settings.window.into_builder( let builder = settings
&application.title(), .window
application.mode(), .into_builder(
event_loop.primary_monitor(), &application.title(),
settings.id, event_loop.primary_monitor(),
); settings.id,
)
.with_visible(false);
log::info!("Window builder: {:#?}", builder); log::info!("Window builder: {:#?}", builder);
@ -135,6 +139,7 @@ where
receiver, receiver,
context, context,
init_command, init_command,
should_be_visible,
settings.exit_on_close_request, settings.exit_on_close_request,
)); ));
@ -187,6 +192,7 @@ async fn run_instance<A, E, C>(
mut receiver: mpsc::UnboundedReceiver<glutin::event::Event<'_, A::Message>>, mut receiver: mpsc::UnboundedReceiver<glutin::event::Event<'_, A::Message>>,
mut context: glutin::ContextWrapper<glutin::PossiblyCurrent, Window>, mut context: glutin::ContextWrapper<glutin::PossiblyCurrent, Window>,
init_command: Command<A::Message>, init_command: Command<A::Message>,
should_be_visible: bool,
exit_on_close_request: bool, exit_on_close_request: bool,
) where ) where
A: Application + 'static, A: Application + 'static,
@ -200,6 +206,7 @@ async fn run_instance<A, E, C>(
let mut clipboard = Clipboard::connect(context.window()); let mut clipboard = Clipboard::connect(context.window());
let mut cache = user_interface::Cache::default(); let mut cache = user_interface::Cache::default();
let mut state = application::State::new(&application, context.window()); let mut state = application::State::new(&application, context.window());
let mut visible = false;
let mut viewport_version = state.viewport_version(); let mut viewport_version = state.viewport_version();
application::run_command( application::run_command(
@ -399,6 +406,12 @@ async fn run_instance<A, E, C>(
debug.render_finished(); debug.render_finished();
if !visible && should_be_visible {
context.window().set_visible(true);
visible = true;
}
// TODO: Handle animations! // TODO: Handle animations!
// Maybe we can use `ControlFlow::WaitUntil` for this. // Maybe we can use `ControlFlow::WaitUntil` for this.
} }

View file

@ -1,5 +1,4 @@
//! Build interactive cross-platform applications. //! Build interactive cross-platform applications.
use crate::window;
use crate::{Command, Element, Executor, Settings, Subscription}; use crate::{Command, Element, Executor, Settings, Subscription};
pub use iced_native::application::{Appearance, StyleSheet}; pub use iced_native::application::{Appearance, StyleSheet};
@ -169,18 +168,6 @@ pub trait Application: Sized {
Subscription::none() 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`]. /// Returns the scale factor of the [`Application`].
/// ///
/// It can be used to dynamically control the size of the UI at runtime /// It can be used to dynamically control the size of the UI at runtime
@ -277,14 +264,6 @@ where
self.0.style() 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::Message> { fn subscription(&self) -> Subscription<Self::Message> {
self.0.subscription() self.0.subscription()
} }

View file

@ -1,12 +1,10 @@
//! Configure the window of your application in native platforms. //! Configure the window of your application in native platforms.
mod mode;
mod position; mod position;
mod settings; mod settings;
pub mod icon; pub mod icon;
pub use icon::Icon; pub use icon::Icon;
pub use mode::Mode;
pub use position::Position; pub use position::Position;
pub use settings::Settings; pub use settings::Settings;

View file

@ -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,
}

View file

@ -15,6 +15,9 @@ pub struct Settings {
/// The maximum size of the window. /// The maximum size of the window.
pub max_size: Option<(u32, u32)>, 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. /// Whether the window should be resizable or not.
pub resizable: bool, pub resizable: bool,
@ -38,6 +41,7 @@ impl Default for Settings {
position: Position::default(), position: Position::default(),
min_size: None, min_size: None,
max_size: None, max_size: None,
visible: true,
resizable: true, resizable: true,
decorations: true, decorations: true,
transparent: false, transparent: false,
@ -54,6 +58,7 @@ impl From<Settings> for iced_winit::settings::Window {
position: iced_winit::Position::from(settings.position), position: iced_winit::Position::from(settings.position),
min_size: settings.min_size, min_size: settings.min_size,
max_size: settings.max_size, max_size: settings.max_size,
visible: settings.visible,
resizable: settings.resizable, resizable: settings.resizable,
decorations: settings.decorations, decorations: settings.decorations,
transparent: settings.transparent, transparent: settings.transparent,

View file

@ -9,7 +9,7 @@ use crate::mouse;
use crate::renderer; use crate::renderer;
use crate::widget::operation; use crate::widget::operation;
use crate::{ use crate::{
Command, Debug, Error, Executor, Mode, Proxy, Runtime, Settings, Size, Command, Debug, Error, Executor, Proxy, Runtime, Settings, Size,
Subscription, Subscription,
}; };
@ -81,16 +81,6 @@ where
Subscription::none() 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`]. /// Returns the scale factor of the [`Application`].
/// ///
/// It can be used to dynamically control the size of the UI at runtime /// It can be used to dynamically control the size of the UI at runtime
@ -147,12 +137,15 @@ where
runtime.enter(|| A::new(flags)) runtime.enter(|| A::new(flags))
}; };
let builder = settings.window.into_builder( let should_be_visible = settings.window.visible;
&application.title(), let builder = settings
application.mode(), .window
event_loop.primary_monitor(), .into_builder(
settings.id, &application.title(),
); event_loop.primary_monitor(),
settings.id,
)
.with_visible(false);
log::info!("Window builder: {:#?}", builder); log::info!("Window builder: {:#?}", builder);
@ -189,6 +182,7 @@ where
receiver, receiver,
init_command, init_command,
window, window,
should_be_visible,
settings.exit_on_close_request, settings.exit_on_close_request,
)); ));
@ -239,6 +233,7 @@ async fn run_instance<A, E, C>(
mut receiver: mpsc::UnboundedReceiver<winit::event::Event<'_, A::Message>>, mut receiver: mpsc::UnboundedReceiver<winit::event::Event<'_, A::Message>>,
init_command: Command<A::Message>, init_command: Command<A::Message>,
window: winit::window::Window, window: winit::window::Window,
should_be_visible: bool,
exit_on_close_request: bool, exit_on_close_request: bool,
) where ) where
A: Application + 'static, A: Application + 'static,
@ -252,6 +247,7 @@ async fn run_instance<A, E, C>(
let mut clipboard = Clipboard::connect(&window); let mut clipboard = Clipboard::connect(&window);
let mut cache = user_interface::Cache::default(); let mut cache = user_interface::Cache::default();
let mut surface = compositor.create_surface(&window); let mut surface = compositor.create_surface(&window);
let mut visible = false;
let mut state = State::new(&application, &window); let mut state = State::new(&application, &window);
let mut viewport_version = state.viewport_version(); let mut viewport_version = state.viewport_version();
@ -383,6 +379,7 @@ async fn run_instance<A, E, C>(
event::MacOS::ReceivedUrl(url), event::MacOS::ReceivedUrl(url),
)) => { )) => {
use iced_native::event; use iced_native::event;
events.push(iced_native::Event::PlatformSpecific( events.push(iced_native::Event::PlatformSpecific(
event::PlatformSpecific::MacOS(event::MacOS::ReceivedUrl( event::PlatformSpecific::MacOS(event::MacOS::ReceivedUrl(
url, url,
@ -450,6 +447,12 @@ async fn run_instance<A, E, C>(
Ok(()) => { Ok(()) => {
debug.render_finished(); debug.render_finished();
if !visible && should_be_visible {
window.set_visible(true);
visible = true;
}
// TODO: Handle animations! // TODO: Handle animations!
// Maybe we can use `ControlFlow::WaitUntil` for this. // Maybe we can use `ControlFlow::WaitUntil` for this.
} }

View file

@ -1,6 +1,6 @@
use crate::application::{self, StyleSheet as _}; use crate::application::{self, StyleSheet as _};
use crate::conversion; 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 std::marker::PhantomData;
use winit::event::{Touch, WindowEvent}; use winit::event::{Touch, WindowEvent};
@ -13,7 +13,6 @@ where
<A::Renderer as crate::Renderer>::Theme: application::StyleSheet, <A::Renderer as crate::Renderer>::Theme: application::StyleSheet,
{ {
title: String, title: String,
mode: Mode,
scale_factor: f64, scale_factor: f64,
viewport: Viewport, viewport: Viewport,
viewport_version: usize, viewport_version: usize,
@ -31,7 +30,6 @@ where
/// Creates a new [`State`] for the provided [`Application`] and window. /// Creates a new [`State`] for the provided [`Application`] and window.
pub fn new(application: &A, window: &Window) -> Self { pub fn new(application: &A, window: &Window) -> Self {
let title = application.title(); let title = application.title();
let mode = application.mode();
let scale_factor = application.scale_factor(); let scale_factor = application.scale_factor();
let theme = application.theme(); let theme = application.theme();
let appearance = theme.appearance(application.style()); let appearance = theme.appearance(application.style());
@ -47,7 +45,6 @@ where
Self { Self {
title, title,
mode,
scale_factor, scale_factor,
viewport, viewport,
viewport_version: 0, viewport_version: 0,
@ -193,20 +190,6 @@ where
self.title = new_title; 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 // Update scale factor
let new_scale_factor = application.scale_factor(); let new_scale_factor = application.scale_factor();

View file

@ -6,7 +6,7 @@ use crate::keyboard;
use crate::mouse; use crate::mouse;
use crate::touch; use crate::touch;
use crate::window; use crate::window;
use crate::{Event, Mode, Point, Position}; use crate::{Event, Point, Position};
/// Converts a winit window event into an iced event. /// Converts a winit window event into an iced event.
pub fn window_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<winit::monitor::MonitorHandle>,
mode: Mode,
) -> Option<winit::window::Fullscreen> {
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. /// Converts a `MouseCursor` from [`iced_native`] to a [`winit`] cursor icon.
/// ///
/// [`winit`]: https://github.com/rust-windowing/winit /// [`winit`]: https://github.com/rust-windowing/winit

View file

@ -45,14 +45,12 @@ pub mod window;
pub mod system; pub mod system;
mod error; mod error;
mod mode;
mod position; mod position;
mod proxy; mod proxy;
pub use application::Application; pub use application::Application;
pub use clipboard::Clipboard; pub use clipboard::Clipboard;
pub use error::Error; pub use error::Error;
pub use mode::Mode;
pub use position::Position; pub use position::Position;
pub use proxy::Proxy; pub use proxy::Proxy;
pub use settings::Settings; pub use settings::Settings;

View file

@ -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,
}

View file

@ -14,7 +14,7 @@ mod platform;
pub use platform::PlatformSpecific; pub use platform::PlatformSpecific;
use crate::conversion; use crate::conversion;
use crate::{Mode, Position}; use crate::Position;
use winit::monitor::MonitorHandle; use winit::monitor::MonitorHandle;
use winit::window::WindowBuilder; use winit::window::WindowBuilder;
@ -65,6 +65,9 @@ pub struct Window {
/// The maximum size of the window. /// The maximum size of the window.
pub max_size: Option<(u32, u32)>, 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. /// Whether the window should be resizable or not.
pub resizable: bool, pub resizable: bool,
@ -89,7 +92,6 @@ impl Window {
pub fn into_builder( pub fn into_builder(
self, self,
title: &str, title: &str,
mode: Mode,
primary_monitor: Option<MonitorHandle>, primary_monitor: Option<MonitorHandle>,
_id: Option<String>, _id: Option<String>,
) -> WindowBuilder { ) -> WindowBuilder {
@ -104,8 +106,7 @@ impl Window {
.with_decorations(self.decorations) .with_decorations(self.decorations)
.with_transparent(self.transparent) .with_transparent(self.transparent)
.with_window_icon(self.icon) .with_window_icon(self.icon)
.with_always_on_top(self.always_on_top) .with_always_on_top(self.always_on_top);
.with_visible(conversion::visible(mode));
if let Some(position) = conversion::position( if let Some(position) = conversion::position(
primary_monitor.as_ref(), primary_monitor.as_ref(),
@ -166,9 +167,6 @@ impl Window {
); );
} }
window_builder = window_builder
.with_fullscreen(conversion::fullscreen(primary_monitor, mode));
window_builder window_builder
} }
} }
@ -180,6 +178,7 @@ impl Default for Window {
position: Position::default(), position: Position::default(),
min_size: None, min_size: None,
max_size: None, max_size: None,
visible: true,
resizable: true, resizable: true,
decorations: true, decorations: true,
transparent: false, transparent: false,