summaryrefslogtreecommitdiffstats
path: root/winit/src
diff options
context:
space:
mode:
authorLibravatar Bingus <shankern@protonmail.com>2023-07-12 19:21:05 -0700
committerLibravatar Bingus <shankern@protonmail.com>2023-07-21 13:53:38 -0700
commitd53ccc857da4d4cda769904342aeb5a82a64f146 (patch)
tree7de16b72e0e054d10380586ba5b79a7181478aa7 /winit/src
parent633f405f3f78bc7f82d2b2061491b0e011137451 (diff)
downloadiced-d53ccc857da4d4cda769904342aeb5a82a64f146.tar.gz
iced-d53ccc857da4d4cda769904342aeb5a82a64f146.tar.bz2
iced-d53ccc857da4d4cda769904342aeb5a82a64f146.zip
refactored window storage;
new helper window events (Destroyed, Created); clippy + fmt;
Diffstat (limited to 'winit/src')
-rw-r--r--winit/src/application.rs86
-rw-r--r--winit/src/conversion.rs9
-rw-r--r--winit/src/icon.rs63
-rw-r--r--winit/src/lib.rs8
-rw-r--r--winit/src/multi_window.rs1078
-rw-r--r--winit/src/multi_window/state.rs96
-rw-r--r--winit/src/multi_window/windows.rs170
-rw-r--r--winit/src/profiler.rs101
-rw-r--r--winit/src/settings.rs246
-rw-r--r--winit/src/settings/macos.rs12
-rw-r--r--winit/src/settings/other.rs3
-rw-r--r--winit/src/settings/wasm.rs11
-rw-r--r--winit/src/settings/windows.rs21
-rw-r--r--winit/src/window.rs0
14 files changed, 856 insertions, 1048 deletions
diff --git a/winit/src/application.rs b/winit/src/application.rs
index ab7b2495..5c45bbda 100644
--- a/winit/src/application.rs
+++ b/winit/src/application.rs
@@ -18,6 +18,7 @@ use crate::runtime::clipboard;
use crate::runtime::program::Program;
use crate::runtime::user_interface::{self, UserInterface};
use crate::runtime::{Command, Debug};
+use crate::settings;
use crate::style::application::{Appearance, StyleSheet};
use crate::{Clipboard, Error, Proxy, Settings};
@@ -25,11 +26,6 @@ use futures::channel::mpsc;
use std::mem::ManuallyDrop;
-#[cfg(feature = "trace")]
-pub use crate::Profiler;
-#[cfg(feature = "trace")]
-use tracing::{info_span, instrument::Instrument};
-
/// An interactive, native cross-platform application.
///
/// This trait is the main entrypoint of Iced. Once implemented, you can run
@@ -117,15 +113,9 @@ where
use futures::Future;
use winit::event_loop::EventLoopBuilder;
- #[cfg(feature = "trace")]
- let _guard = Profiler::init();
-
let mut debug = Debug::new();
debug.startup_started();
- #[cfg(feature = "trace")]
- let _ = info_span!("Application", "RUN").entered();
-
let event_loop = EventLoopBuilder::with_user_event().build();
let proxy = event_loop.create_proxy();
@@ -146,14 +136,13 @@ where
let target = settings.window.platform_specific.target.clone();
let should_be_visible = settings.window.visible;
- let builder = settings
- .window
- .into_builder(
- &application.title(),
- event_loop.primary_monitor(),
- settings.id,
- )
- .with_visible(false);
+ let builder = settings::window_builder(
+ settings.window,
+ &application.title(),
+ event_loop.primary_monitor(),
+ settings.id,
+ )
+ .with_visible(false);
log::debug!("Window builder: {:#?}", builder);
@@ -196,28 +185,20 @@ where
let (mut event_sender, event_receiver) = mpsc::unbounded();
let (control_sender, mut control_receiver) = mpsc::unbounded();
- let mut instance = Box::pin({
- let run_instance = run_instance::<A, E, C>(
- application,
- compositor,
- renderer,
- runtime,
- proxy,
- debug,
- event_receiver,
- control_sender,
- init_command,
- window,
- should_be_visible,
- settings.exit_on_close_request,
- );
-
- #[cfg(feature = "trace")]
- let run_instance =
- run_instance.instrument(info_span!("Application", "LOOP"));
-
- run_instance
- });
+ let mut instance = Box::pin(run_instance::<A, E, C>(
+ application,
+ compositor,
+ renderer,
+ runtime,
+ proxy,
+ debug,
+ event_receiver,
+ control_sender,
+ init_command,
+ window,
+ should_be_visible,
+ settings.exit_on_close_request,
+ ));
let mut context = task::Context::from_waker(task::noop_waker_ref());
@@ -480,9 +461,6 @@ async fn run_instance<A, E, C>(
messages.push(message);
}
event::Event::RedrawRequested(_) => {
- #[cfg(feature = "trace")]
- let _ = info_span!("Application", "FRAME").entered();
-
let physical_size = state.physical_size();
if physical_size.width == 0 || physical_size.height == 0 {
@@ -622,24 +600,12 @@ pub fn build_user_interface<'a, A: Application>(
where
<A::Renderer as core::Renderer>::Theme: StyleSheet,
{
- #[cfg(feature = "trace")]
- let view_span = info_span!("Application", "VIEW").entered();
-
debug.view_started();
let view = application.view();
-
- #[cfg(feature = "trace")]
- let _ = view_span.exit();
debug.view_finished();
- #[cfg(feature = "trace")]
- let layout_span = info_span!("Application", "LAYOUT").entered();
-
debug.layout_started();
let user_interface = UserInterface::build(view, size, cache, renderer);
-
- #[cfg(feature = "trace")]
- let _ = layout_span.exit();
debug.layout_finished();
user_interface
@@ -666,16 +632,10 @@ pub fn update<A: Application, C, E: Executor>(
<A::Renderer as core::Renderer>::Theme: StyleSheet,
{
for message in messages.drain(..) {
- #[cfg(feature = "trace")]
- let update_span = info_span!("Application", "UPDATE").entered();
-
debug.log_message(&message);
debug.update_started();
let command = runtime.enter(|| application.update(message));
-
- #[cfg(feature = "trace")]
- let _ = update_span.exit();
debug.update_finished();
run_command(
@@ -750,7 +710,7 @@ pub fn run_command<A, C, E>(
}
window::Action::Spawn { .. } => {
log::info!(
- "Spawning a window is only available with `multi_window::Application`s."
+ "Spawning a window is only available with multi-window applications."
)
}
window::Action::Resize(size) => {
diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index fe0fce19..0625e74b 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -7,7 +7,6 @@ use crate::core::mouse;
use crate::core::touch;
use crate::core::window;
use crate::core::{Event, Point};
-use crate::Position;
/// Converts a winit window event into an iced event.
pub fn window_event(
@@ -169,17 +168,17 @@ pub fn window_level(level: window::Level) -> winit::window::WindowLevel {
pub fn position(
monitor: Option<&winit::monitor::MonitorHandle>,
(width, height): (u32, u32),
- position: Position,
+ position: window::Position,
) -> Option<winit::dpi::Position> {
match position {
- Position::Default => None,
- Position::Specific(x, y) => {
+ window::Position::Default => None,
+ window::Position::Specific(x, y) => {
Some(winit::dpi::Position::Logical(winit::dpi::LogicalPosition {
x: f64::from(x),
y: f64::from(y),
}))
}
- Position::Centered => {
+ window::Position::Centered => {
if let Some(monitor) = monitor {
let start = monitor.position();
diff --git a/winit/src/icon.rs b/winit/src/icon.rs
deleted file mode 100644
index 0fe010ca..00000000
--- a/winit/src/icon.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-//! Attach an icon to the window of your application.
-pub use crate::core::window::icon::*;
-
-use crate::core::window::icon;
-
-use std::io;
-
-#[cfg(feature = "image")]
-use std::path::Path;
-
-/// Creates an icon from an image file.
-///
-/// This will return an error in case the file is missing at run-time. You may prefer [`Self::from_file_data`] instead.
-#[cfg(feature = "image")]
-pub fn from_file<P: AsRef<Path>>(icon_path: P) -> Result<Icon, Error> {
- let icon = image_rs::io::Reader::open(icon_path)?.decode()?.to_rgba8();
-
- Ok(icon::from_rgba(icon.to_vec(), icon.width(), icon.height())?)
-}
-
-/// Creates an icon from the content of an image file.
-///
-/// This content can be included in your application at compile-time, e.g. using the `include_bytes!` macro.
-/// You can pass an explicit file format. Otherwise, the file format will be guessed at runtime.
-#[cfg(feature = "image")]
-pub fn from_file_data(
- data: &[u8],
- explicit_format: Option<image_rs::ImageFormat>,
-) -> Result<Icon, Error> {
- let mut icon = image_rs::io::Reader::new(std::io::Cursor::new(data));
- let icon_with_format = match explicit_format {
- Some(format) => {
- icon.set_format(format);
- icon
- }
- None => icon.with_guessed_format()?,
- };
-
- let pixels = icon_with_format.decode()?.to_rgba8();
-
- Ok(icon::from_rgba(
- pixels.to_vec(),
- pixels.width(),
- pixels.height(),
- )?)
-}
-
-/// An error produced when creating an [`Icon`].
-#[derive(Debug, thiserror::Error)]
-pub enum Error {
- /// The [`Icon`] is not valid.
- #[error("The icon is invalid: {0}")]
- InvalidError(#[from] icon::Error),
-
- /// The underlying OS failed to create the icon.
- #[error("The underlying OS failted to create the window icon: {0}")]
- OsError(#[from] io::Error),
-
- /// The `image` crate reported an error.
- #[cfg(feature = "image")]
- #[error("Unable to create icon from a file: {0}")]
- ImageError(#[from] image_rs::error::ImageError),
-}
diff --git a/winit/src/lib.rs b/winit/src/lib.rs
index dc163430..31002f51 100644
--- a/winit/src/lib.rs
+++ b/winit/src/lib.rs
@@ -51,20 +51,14 @@ pub mod settings;
pub mod system;
mod error;
-mod icon;
mod proxy;
-#[cfg(feature = "trace")]
-mod profiler;
#[cfg(feature = "application")]
pub use application::Application;
-#[cfg(feature = "trace")]
-pub use profiler::Profiler;
pub use clipboard::Clipboard;
pub use error::Error;
-pub use icon::Icon;
pub use proxy::Proxy;
pub use settings::Settings;
+pub use crate::core::window::*;
pub use iced_graphics::Viewport;
-pub use iced_native::window::Position;
diff --git a/winit/src/multi_window.rs b/winit/src/multi_window.rs
index 9b395c1d..e6f440bc 100644
--- a/winit/src/multi_window.rs
+++ b/winit/src/multi_window.rs
@@ -1,58 +1,57 @@
//! Create interactive, native cross-platform applications for WGPU.
mod state;
+mod windows;
pub use state::State;
-use crate::clipboard::{self, Clipboard};
-use crate::conversion;
-use crate::mouse;
-use crate::renderer;
-use crate::settings;
-use crate::widget::operation;
-use crate::window;
-use crate::{
- Command, Debug, Element, Error, Executor, Proxy, Renderer, Runtime,
- Settings, Size, Subscription,
-};
-
-use iced_futures::futures::channel::mpsc;
-use iced_futures::futures::{self, FutureExt};
-use iced_graphics::compositor;
-use iced_native::user_interface::{self, UserInterface};
-
-pub use iced_native::application::{Appearance, StyleSheet};
-
-use std::collections::HashMap;
+use crate::core::widget::operation;
+use crate::core::{self, mouse, renderer, window, Size};
+use crate::futures::futures::channel::mpsc;
+use crate::futures::futures::{task, Future, FutureExt, StreamExt};
+use crate::futures::{Executor, Runtime, Subscription};
+use crate::graphics::{compositor, Compositor};
+use crate::multi_window::windows::Windows;
+use crate::runtime::command::{self, Command};
+use crate::runtime::multi_window::Program;
+use crate::runtime::user_interface::{self, UserInterface};
+use crate::runtime::Debug;
+use crate::settings::window_builder;
+use crate::style::application::StyleSheet;
+use crate::{conversion, settings, Clipboard, Error, Proxy, Settings};
+
+use iced_runtime::user_interface::Cache;
use std::mem::ManuallyDrop;
use std::time::Instant;
-
-#[cfg(feature = "trace")]
-pub use crate::Profiler;
-#[cfg(feature = "trace")]
-use tracing::{info_span, instrument::Instrument};
+use winit::monitor::MonitorHandle;
/// This is a wrapper around the `Application::Message` associate type
/// to allows the `shell` to create internal messages, while still having
/// the current user-specified custom messages.
#[derive(Debug)]
pub enum Event<Message> {
- /// An [`Application`] generated message
+ /// An internal event which contains an [`Application`] generated message.
Application(Message),
- /// A message which spawns a new window.
+ /// An internal event which spawns a new window.
NewWindow {
/// The [window::Id] of the newly spawned [`Window`].
id: window::Id,
/// The [settings::Window] of the newly spawned [`Window`].
- settings: settings::Window,
+ settings: window::Settings,
/// The title of the newly spawned [`Window`].
title: String,
+ /// The monitor on which to spawn the window. If `None`, will use monitor of the last window
+ /// spawned.
+ monitor: Option<MonitorHandle>,
},
- /// Close a window.
+ /// An internal event for closing a window.
CloseWindow(window::Id),
- /// A message for when the window has finished being created.
+ /// An internal event for when the window has finished being created.
WindowCreated(window::Id, winit::window::Window),
}
+#[allow(unsafe_code)]
+unsafe impl<Message> std::marker::Send for Event<Message> {}
+
/// An interactive, native, cross-platform, multi-windowed application.
///
/// This trait is the main entrypoint of multi-window Iced. Once implemented, you can run
@@ -64,37 +63,13 @@ pub enum Event<Message> {
///
/// When using an [`Application`] with the `debug` feature enabled, a debug view
/// can be toggled by pressing `F12`.
-pub trait Application: Sized
+pub trait Application: Program
where
- <Self::Renderer as crate::Renderer>::Theme: StyleSheet,
+ <Self::Renderer as core::Renderer>::Theme: StyleSheet,
{
/// The data needed to initialize your [`Application`].
type Flags;
- /// The graphics backend to use to draw the [`Program`].
- type Renderer: Renderer;
-
- /// The type of __messages__ your [`Program`] will produce.
- type Message: std::fmt::Debug + Send;
-
- /// Handles a __message__ and updates the state of the [`Program`].
- ///
- /// This is where you define your __update logic__. All the __messages__,
- /// produced by either user interactions or commands, will be handled by
- /// this method.
- ///
- /// Any [`Command`] returned will be executed immediately in the
- /// background by shells.
- fn update(&mut self, message: Self::Message) -> Command<Self::Message>;
-
- /// Returns the widgets to display for the `window` in the [`Program`].
- ///
- /// These widgets can produce __messages__ based on user interaction.
- fn view(
- &self,
- window: window::Id,
- ) -> Element<'_, Self::Message, Self::Renderer>;
-
/// Initializes the [`Application`] with the flags provided to
/// [`run`] as part of the [`Settings`].
///
@@ -105,19 +80,22 @@ where
/// load state from a file, perform an initial HTTP request, etc.
fn new(flags: Self::Flags) -> (Self, Command<Self::Message>);
- /// Returns the current title of each window of the [`Application`].
+ /// Returns the current title of the [`Application`].
///
/// This title can be dynamic! The runtime will automatically update the
/// title of your application when necessary.
fn title(&self, window: window::Id) -> String;
- /// Returns the current [`Theme`] of the [`Application`].
- fn theme(&self, window: window::Id) -> <Self::Renderer as crate::Renderer>::Theme;
+ /// Returns the current `Theme` of the [`Application`].
+ fn theme(
+ &self,
+ window: window::Id,
+ ) -> <Self::Renderer as core::Renderer>::Theme;
- /// Returns the [`Style`] variation of the [`Theme`].
+ /// Returns the `Style` variation of the `Theme`.
fn style(
&self,
- ) -> <<Self::Renderer as crate::Renderer>::Theme as StyleSheet>::Style {
+ ) -> <<Self::Renderer as core::Renderer>::Theme as StyleSheet>::Style {
Default::default()
}
@@ -147,17 +125,6 @@ where
fn scale_factor(&self, window: window::Id) -> f64 {
1.0
}
-
- /// Returns whether the [`Application`] should be terminated.
- ///
- /// By default, it returns `false`.
- fn should_exit(&self) -> bool {
- false
- }
-
- /// Returns the `Self::Message` that should be processed when a `window` is requested to
- /// be closed.
- fn close_requested(&self, window: window::Id) -> Self::Message;
}
/// Runs an [`Application`] with an executor, compositor, and the provided
@@ -169,22 +136,14 @@ pub fn run<A, E, C>(
where
A: Application + 'static,
E: Executor + 'static,
- C: iced_graphics::window::Compositor<Renderer = A::Renderer> + 'static,
- <A::Renderer as crate::Renderer>::Theme: StyleSheet,
+ C: Compositor<Renderer = A::Renderer> + 'static,
+ <A::Renderer as core::Renderer>::Theme: StyleSheet,
{
- use futures::task;
- use futures::Future;
use winit::event_loop::EventLoopBuilder;
- #[cfg(feature = "trace")]
- let _guard = Profiler::init();
-
let mut debug = Debug::new();
debug.startup_started();
- #[cfg(feature = "trace")]
- let _ = info_span!("Application", "RUN").entered();
-
let event_loop = EventLoopBuilder::with_user_event().build();
let proxy = event_loop.create_proxy();
@@ -201,68 +160,77 @@ where
runtime.enter(|| A::new(flags))
};
- let builder = settings.window.into_builder(
+ let should_main_be_visible = settings.window.visible;
+ let builder = window_builder(
+ settings.window,
&application.title(window::Id::MAIN),
event_loop.primary_monitor(),
settings.id,
- );
+ )
+ .with_visible(false);
log::info!("Window builder: {:#?}", builder);
- let window = builder
+ let main_window = builder
.build(&event_loop)
.map_err(Error::WindowCreationFailed)?;
- let windows: HashMap<window::Id, winit::window::Window> =
- HashMap::from([(window::Id::MAIN, window)]);
-
- let window = windows.values().next().expect("No window found");
-
#[cfg(target_arch = "wasm32")]
{
use winit::platform::web::WindowExtWebSys;
- let canvas = window.canvas();
+ let canvas = main_window.canvas();
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let body = document.body().unwrap();
- let _ = body
- .append_child(&canvas)
- .expect("Append canvas to HTML body");
+ let target = target.and_then(|target| {
+ body.query_selector(&format!("#{}", target))
+ .ok()
+ .unwrap_or(None)
+ });
+
+ match target {
+ Some(node) => {
+ let _ = node
+ .replace_with_with_node_1(&canvas)
+ .expect(&format!("Could not replace #{}", node.id()));
+ }
+ None => {
+ let _ = body
+ .append_child(&canvas)
+ .expect("Append canvas to HTML body");
+ }
+ };
}
- let (compositor, renderer) = C::new(compositor_settings, Some(&window))?;
+ let (mut compositor, renderer) =
+ C::new(compositor_settings, Some(&main_window))?;
+
+ let windows =
+ Windows::new(&application, &mut compositor, renderer, main_window);
let (mut event_sender, event_receiver) = mpsc::unbounded();
let (control_sender, mut control_receiver) = mpsc::unbounded();
- let mut instance = Box::pin({
- let run_instance = run_instance::<A, E, C>(
- application,
- compositor,
- renderer,
- runtime,
- proxy,
- debug,
- event_receiver,
- control_sender,
- init_command,
- windows,
- settings.exit_on_close_request,
- );
-
- #[cfg(feature = "trace")]
- let run_instance =
- run_instance.instrument(info_span!("Application", "LOOP"));
-
- run_instance
- });
+ let mut instance = Box::pin(run_instance::<A, E, C>(
+ application,
+ compositor,
+ runtime,
+ proxy,
+ debug,
+ event_receiver,
+ control_sender,
+ init_command,
+ windows,
+ should_main_be_visible,
+ settings.exit_on_close_request,
+ ));
let mut context = task::Context::from_waker(task::noop_waker_ref());
- platform::run(event_loop, move |event, event_loop, control_flow| {
+ platform::run(event_loop, move |event, window_target, control_flow| {
use winit::event_loop::ControlFlow;
if let ControlFlow::ExitWithCode(_) = control_flow {
@@ -285,11 +253,12 @@ where
id,
settings,
title,
+ monitor,
}) => {
- let window = settings
- .into_builder(&title, event_loop.primary_monitor(), None)
- .build(event_loop)
- .expect("Failed to build window");
+ let window =
+ settings::window_builder(settings, &title, monitor, None)
+ .build(window_target)
+ .expect("Failed to build window");
Some(winit::event::Event::UserEvent(Event::WindowCreated(
id, window,
@@ -320,7 +289,6 @@ where
async fn run_instance<A, E, C>(
mut application: A,
mut compositor: C,
- mut renderer: A::Renderer,
mut runtime: Runtime<E, Proxy<Event<A::Message>>, Event<A::Message>>,
mut proxy: winit::event_loop::EventLoopProxy<Event<A::Message>>,
mut debug: Debug,
@@ -329,74 +297,65 @@ async fn run_instance<A, E, C>(
>,
mut control_sender: mpsc::UnboundedSender<winit::event_loop::ControlFlow>,
init_command: Command<A::Message>,
- mut windows: HashMap<window::Id, winit::window::Window>,
- _exit_on_close_request: bool,
+ mut windows: Windows<A, C>,
+ should_main_window_be_visible: bool,
+ exit_on_main_closed: bool,
) where
A: Application + 'static,
E: Executor + 'static,
- C: iced_graphics::window::Compositor<Renderer = A::Renderer> + 'static,
- <A::Renderer as crate::Renderer>::Theme: StyleSheet,
+ C: Compositor<Renderer = A::Renderer> + 'static,
+ <A::Renderer as core::Renderer>::Theme: StyleSheet,
{
- use iced_futures::futures::stream::StreamExt;
use winit::event;
use winit::event_loop::ControlFlow;
- let mut clipboard =
- Clipboard::connect(windows.values().next().expect("No window found"));
- let mut caches = HashMap::new();
- let mut window_ids: HashMap<_, _> = windows
- .iter()
- .map(|(&id, window)| (window.id(), id))
- .collect();
-
- let mut states = HashMap::new();
- let mut surfaces = HashMap::new();
- let mut interfaces = ManuallyDrop::new(HashMap::new());
-
- for (&id, window) in windows.keys().zip(windows.values()) {
- let mut surface = compositor.create_surface(window);
- let state = State::new(&application, id, window);
- let physical_size = state.physical_size();
-
- compositor.configure_surface(
- &mut surface,
- physical_size.width,
- physical_size.height,
- );
+ let mut clipboard = Clipboard::connect(windows.main());
- let user_interface = build_user_interface(
- &application,
- user_interface::Cache::default(),
- &mut renderer,
- state.logical_size(),
- &mut debug,
- id,
- );
+ let mut ui_caches = vec![user_interface::Cache::default()];
+ let mut user_interfaces = ManuallyDrop::new(build_user_interfaces(
+ &application,
+ &mut debug,
+ &mut windows,
+ vec![user_interface::Cache::default()],
+ ));
- let _ = states.insert(id, state);
- let _ = surfaces.insert(id, surface);
- let _ = interfaces.insert(id, user_interface);
- let _ = caches.insert(id, user_interface::Cache::default());
+ if should_main_window_be_visible {
+ windows.main().set_visible(true);
}
run_command(
&application,
- &mut caches,
- &states,
- &mut renderer,
+ &mut compositor,
init_command,
&mut runtime,
&mut clipboard,
&mut proxy,
&mut debug,
- &windows,
- || compositor.fetch_information(),
+ &mut windows,
+ &mut ui_caches,
);
- runtime.track(application.subscription().map(Event::Application));
+ runtime.track(
+ application
+ .subscription()
+ .map(Event::Application)
+ .into_recipes(),
+ );
let mut mouse_interaction = mouse::Interaction::default();
- let mut events = Vec::new();
+
+ let mut events =
+ if let Some((position, size)) = logical_bounds_of(windows.main()) {
+ vec![(
+ Some(window::Id::MAIN),
+ core::Event::Window(
+ window::Id::MAIN,
+ window::Event::Created { position, size },
+ ),
+ )]
+ } else {
+ Vec::new()
+ };
let mut messages = Vec::new();
let mut redraw_pending = false;
@@ -413,25 +372,20 @@ async fn run_instance<A, E, C>(
);
}
event::Event::MainEventsCleared => {
- for id in states.keys().copied().collect::<Vec<_>>() {
- // Partition events into only events for this window
- let (filtered, remaining): (Vec<_>, Vec<_>) =
- events.iter().cloned().partition(
- |(window_id, _event): &(
- Option<window::Id>,
- iced_native::event::Event,
- )| {
- *window_id == Some(id) || *window_id == None
- },
- );
-
- // Only retain events which have not been processed for next iteration
- events.retain(|el| remaining.contains(el));
-
- let window_events: Vec<_> = filtered
- .into_iter()
- .map(|(_id, event)| event)
- .collect();
+ debug.event_processing_started();
+ let mut uis_stale = false;
+
+ for (i, id) in windows.ids.iter().enumerate() {
+ let mut window_events = vec![];
+
+ events.retain(|(window_id, event)| {
+ if *window_id == Some(*id) || window_id.is_none() {
+ window_events.push(event.clone());
+ false
+ } else {
+ true
+ }
+ });
if !redraw_pending
&& window_events.is_empty()
@@ -440,144 +394,124 @@ async fn run_instance<A, E, C>(
continue;
}
- // Process winit events for window
- debug.event_processing_started();
- let cursor_position =
- states.get(&id).unwrap().cursor_position();
-
- let (interface_state, statuses) = {
- let user_interface = interfaces.get_mut(&id).unwrap();
- user_interface.update(
- &window_events,
- cursor_position,
- &mut renderer,
- &mut clipboard,
- &mut messages,
- )
- };
+ let (ui_state, statuses) = user_interfaces[i].update(
+ &window_events,
+ windows.states[i].cursor(),
+ &mut windows.renderers[i],
+ &mut clipboard,
+ &mut messages,
+ );
+
+ if !uis_stale {
+ uis_stale =
+ matches!(ui_state, user_interface::State::Outdated);
+ }
- for event in
+ for (event, status) in
window_events.into_iter().zip(statuses.into_iter())
{
- runtime.broadcast(event);
+ runtime.broadcast(event, status);
}
- debug.event_processing_finished();
-
- // Update application with app messages
- // Unless we implement some kind of diffing, we must redraw all windows as we
- // cannot know what changed.
- if !messages.is_empty()
- || matches!(
- interface_state,
- user_interface::State::Outdated,
- )
- {
- let mut cached_interfaces: HashMap<_, _> =
- ManuallyDrop::into_inner(interfaces)
- .drain()
- .map(
- |(id, interface): (
- window::Id,
- UserInterface<'_, _, _>,
- )| {
- (id, interface.into_cache())
- },
- )
- .collect();
-
- // Update application
- update(
- &mut application,
- &mut cached_interfaces,
- &states,
- &mut renderer,
- &mut runtime,
- &mut clipboard,
- &mut proxy,
- &mut debug,
- &mut messages,
- &windows,
- || compositor.fetch_information(),
- );
-
- // synchronize window states with application states.
- for (id, state) in states.iter_mut() {
- state.synchronize(
- &application,
- *id,
- windows
- .get(id)
- .expect("No window found with ID."),
- );
- }
+ }
- interfaces = ManuallyDrop::new(build_user_interfaces(
- &application,
- &mut renderer,
- &mut debug,
- &states,
- cached_interfaces,
- ));
+ debug.event_processing_finished();
+
+ // TODO mw application update returns which window IDs to update
+ if !messages.is_empty() || uis_stale {
+ let mut cached_interfaces: Vec<Cache> =
+ ManuallyDrop::into_inner(user_interfaces)
+ .drain(..)
+ .map(UserInterface::into_cache)
+ .collect();
+
+ // Update application
+ update(
+ &mut application,
+ &mut compositor,
+ &mut runtime,
+ &mut clipboard,
+ &mut proxy,
+ &mut debug,
+ &mut messages,
+ &mut windows,
+ &mut cached_interfaces,
+ );
- if application.should_exit() {
- break 'main;
- }
+ // we must synchronize all window states with application state after an
+ // application update since we don't know what changed
+ for (state, (id, window)) in windows
+ .states
+ .iter_mut()
+ .zip(windows.ids.iter().zip(windows.raw.iter()))
+ {
+ state.synchronize(&application, *id, window);
}
+ // rebuild UIs with the synchronized states
+ user_interfaces = ManuallyDrop::new(build_user_interfaces(
+ &application,
+ &mut debug,
+ &mut windows,
+ cached_interfaces,
+ ));
+ }
+
+ debug.draw_started();
+
+ for (i, id) in windows.ids.iter().enumerate() {
// TODO: Avoid redrawing all the time by forcing widgets to
- // request redraws on state changes
+ // request redraws on state changes
//
// Then, we can use the `interface_state` here to decide if a redraw
// is needed right away, or simply wait until a specific time.
- let redraw_event = iced_native::Event::Window(
- id,
+ let redraw_event = core::Event::Window(
+ *id,
window::Event::RedrawRequested(Instant::now()),
);
- let (interface_state, _) =
- interfaces.get_mut(&id).unwrap().update(
- &[redraw_event.clone()],
- cursor_position,
- &mut renderer,
- &mut clipboard,
- &mut messages,
- );
+ let cursor = windows.states[i].cursor();
+
+ let (ui_state, _) = user_interfaces[i].update(
+ &[redraw_event.clone()],
+ cursor,
+ &mut windows.renderers[i],
+ &mut clipboard,
+ &mut messages,
+ );
- debug.draw_started();
let new_mouse_interaction = {
- let state = states.get(&id).unwrap();
+ let state = &windows.states[i];
- interfaces.get_mut(&id).unwrap().draw(
- &mut renderer,
+ user_interfaces[i].draw(
+ &mut windows.renderers[i],
state.theme(),
&renderer::Style {
text_color: state.text_color(),
},
- state.cursor_position(),
+ cursor,
)
};
- debug.draw_finished();
-
- let window = windows.get(&id).unwrap();
if new_mouse_interaction != mouse_interaction {
- window.set_cursor_icon(conversion::mouse_interaction(
- new_mouse_interaction,
- ));
+ windows.raw[i].set_cursor_icon(
+ conversion::mouse_interaction(
+ new_mouse_interaction,
+ ),
+ );
mouse_interaction = new_mouse_interaction;
}
- for window in windows.values() {
- window.request_redraw();
- }
+ // TODO once widgets can request to be redrawn, we can avoid always requesting a
+ // redraw
+ windows.raw[i].request_redraw();
- runtime.broadcast((
+ runtime.broadcast(
redraw_event.clone(),
- crate::event::Status::Ignored,
- ));
+ core::event::Status::Ignored,
+ );
- let _ = control_sender.start_send(match interface_state {
+ let _ = control_sender.start_send(match ui_state {
user_interface::State::Updated {
redraw_request: Some(redraw_request),
} => match redraw_request {
@@ -590,17 +524,20 @@ async fn run_instance<A, E, C>(
},
_ => ControlFlow::Wait,
});
-
- redraw_pending = false;
}
+
+ redraw_pending = false;
+
+ debug.draw_finished();
}
event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(
event::MacOS::ReceivedUrl(url),
)) => {
- use iced_native::event;
+ use crate::core::event;
+
events.push((
None,
- iced_native::Event::PlatformSpecific(
+ event::Event::PlatformSpecific(
event::PlatformSpecific::MacOS(
event::MacOS::ReceivedUrl(url),
),
@@ -612,91 +549,48 @@ async fn run_instance<A, E, C>(
messages.push(message);
}
Event::WindowCreated(id, window) => {
- let mut surface = compositor.create_surface(&window);
- let state = State::new(&application, id, &window);
- let physical_size = state.physical_size();
+ let bounds = logical_bounds_of(&window);
- compositor.configure_surface(
- &mut surface,
- physical_size.width,
- physical_size.height,
- );
+ let (inner_size, i) =
+ windows.add(&application, &mut compositor, id, window);
- let user_interface = build_user_interface(
+ user_interfaces.push(build_user_interface(
&application,
user_interface::Cache::default(),
- &mut renderer,
- state.logical_size(),
+ &mut windows.renderers[i],
+ inner_size,
&mut debug,
id,
- );
-
- let _ = states.insert(id, state);
- let _ = surfaces.insert(id, surface);
- let _ = interfaces.insert(id, user_interface);
- let _ = window_ids.insert(window.id(), id);
- let _ = windows.insert(id, window);
- let _ = caches.insert(id, user_interface::Cache::default());
+ ));
+ ui_caches.push(user_interface::Cache::default());
+
+ if let Some(bounds) = bounds {
+ events.push((
+ Some(id),
+ core::Event::Window(
+ id,
+ window::Event::Created {
+ position: bounds.0,
+ size: bounds.1,
+ },
+ ),
+ ));
+ }
}
Event::CloseWindow(id) => {
- if let Some(window) = windows.get(&id) {
- if window_ids.remove(&window.id()).is_none() {
- log::error!("Failed to remove window with id {:?} from window_ids.", window.id());
- }
- } else {
- log::error!(
- "Could not find window with id {:?} in windows.",
- id
- );
- }
- if states.remove(&id).is_none() {
- log::error!(
- "Failed to remove window {:?} from states.",
- id
- );
- }
- if interfaces.remove(&id).is_none() {
- log::error!(
- "Failed to remove window {:?} from interfaces.",
- id
- );
- }
- if windows.remove(&id).is_none() {
- log::error!(
- "Failed to remove window {:?} from windows.",
- id
- );
- }
- if surfaces.remove(&id).is_none() {
- log::error!(
- "Failed to remove window {:?} from surfaces.",
- id
- );
- }
+ let i = windows.delete(id);
+ let _ = user_interfaces.remove(i);
+ let _ = ui_caches.remove(i);
if windows.is_empty() {
- log::info!(
- "All windows are closed. Terminating program."
- );
break 'main;
- } else {
- log::info!("Remaining windows: {:?}", windows.len());
}
}
Event::NewWindow { .. } => unreachable!(),
},
event::Event::RedrawRequested(id) => {
- #[cfg(feature = "trace")]
- let _ = info_span!("Application", "FRAME").entered();
-
- let state = window_ids
- .get(&id)
- .and_then(|id| states.get_mut(id))
- .unwrap();
- let surface = window_ids
- .get(&id)
- .and_then(|id| surfaces.get_mut(id))
- .unwrap();
+ let i = windows.index_from_raw(id);
+ let state = &windows.states[i];
let physical_size = state.physical_size();
if physical_size.width == 0 || physical_size.height == 0 {
@@ -704,60 +598,55 @@ async fn run_instance<A, E, C>(
}
debug.render_started();
+ let current_viewport_version = state.viewport_version();
+ let window_viewport_version = windows.viewport_versions[i];
- if state.viewport_changed() {
- let mut user_interface = window_ids
- .get(&id)
- .and_then(|id| interfaces.remove(id))
- .unwrap();
-
+ if window_viewport_version != current_viewport_version {
let logical_size = state.logical_size();
debug.layout_started();
- user_interface =
- user_interface.relayout(logical_size, &mut renderer);
+
+ let renderer = &mut windows.renderers[i];
+ let ui = user_interfaces.remove(i);
+
+ user_interfaces
+ .insert(i, ui.relayout(logical_size, renderer));
+
debug.layout_finished();
debug.draw_started();
- let new_mouse_interaction = {
- let state = &state;
-
- user_interface.draw(
- &mut renderer,
- state.theme(),
- &renderer::Style {
- text_color: state.text_color(),
- },
- state.cursor_position(),
- )
- };
+ let new_mouse_interaction = user_interfaces[i].draw(
+ renderer,
+ state.theme(),
+ &renderer::Style {
+ text_color: state.text_color(),
+ },
+ state.cursor(),
+ );
- let window = window_ids
- .get(&id)
- .and_then(|id| windows.get(id))
- .unwrap();
if new_mouse_interaction != mouse_interaction {
- window.set_cursor_icon(conversion::mouse_interaction(
- new_mouse_interaction,
- ));
+ windows.raw[i].set_cursor_icon(
+ conversion::mouse_interaction(
+ new_mouse_interaction,
+ ),
+ );
mouse_interaction = new_mouse_interaction;
}
debug.draw_finished();
- let _ = interfaces
- .insert(*window_ids.get(&id).unwrap(), user_interface);
-
compositor.configure_surface(
- surface,
+ &mut windows.surfaces[i],
physical_size.width,
physical_size.height,
);
+
+ windows.viewport_versions[i] = current_viewport_version;
}
match compositor.present(
- &mut renderer,
- surface,
+ &mut windows.renderers[i],
+ &mut windows.surfaces[i],
state.viewport(),
state.background_color(),
&debug.overlay(),
@@ -775,10 +664,12 @@ async fn run_instance<A, E, C>(
}
_ => {
debug.render_finished();
- log::error!("Error {error:?} when presenting surface.");
+ log::error!(
+ "Error {error:?} when presenting surface."
+ );
- // Try rendering windows again next frame.
- for window in windows.values() {
+ // Try rendering all windows again next frame.
+ for window in &windows.raw {
window.request_redraw();
}
}
@@ -789,42 +680,58 @@ async fn run_instance<A, E, C>(
event: window_event,
window_id,
} => {
- if let (Some(window), Some(state)) = (
- window_ids.get(&window_id).and_then(|id| windows.get(id)),
- window_ids
- .get(&window_id)
- .and_then(|id| states.get_mut(id)),
- ) {
- if crate::application::requests_exit(&window_event, state.modifiers()) {
- if let Some(id) = window_ids.get(&window_id).cloned() {
- let message = application.close_requested(id);
- messages.push(message);
- }
+ let window_deleted = windows
+ .pending_destroy
+ .iter()
+ .any(|(_, w_id)| window_id == *w_id);
+
+ if matches!(window_event, winit::event::WindowEvent::Destroyed)
+ {
+ // This is the only special case, since in order trigger the Destroyed event the
+ // window reference from winit must be dropped, but we still want to inform the
+ // user that the window was destroyed so they can clean up any specific window
+ // code for this window
+ let id = windows.get_pending_destroy(window_id);
+
+ events.push((
+ None,
+ core::Event::Window(id, window::Event::Destroyed),
+ ));
+ } else if !window_deleted {
+ let i = windows.index_from_raw(window_id);
+ let id = windows.ids[i];
+ let raw = &windows.raw[i];
+ let state = &mut windows.states[i];
+
+ // first check if we need to just break the entire application
+ // e.g. a user does a force quit on MacOS, or if a user has set "exit on main closed"
+ // as an option in window settings and wants to close the main window
+ if requests_exit(
+ i,
+ exit_on_main_closed,
+ &window_event,
+ state.modifiers(),
+ ) {
+ break 'main;
}
- state.update(window, &window_event, &mut debug);
+ state.update(raw, &window_event, &mut debug);
if let Some(event) = conversion::window_event(
- *window_ids.get(&window_id).unwrap(),
+ id,
&window_event,
state.scale_factor(),
state.modifiers(),
) {
- events
- .push((window_ids.get(&window_id).cloned(), event));
+ events.push((Some(id), event));
}
- } else {
- log::error!(
- "Could not find window or state for id: {window_id:?}"
- );
}
}
_ => {}
}
}
- // Manually drop the user interfaces
- drop(ManuallyDrop::into_inner(interfaces));
+ let _ = ManuallyDrop::into_inner(user_interfaces);
}
/// Builds a window's [`UserInterface`] for the [`Application`].
@@ -837,103 +744,79 @@ pub fn build_user_interface<'a, A: Application>(
id: window::Id,
) -> UserInterface<'a, A::Message, A::Renderer>
where
- <A::Renderer as crate::Renderer>::Theme: StyleSheet,
+ <A::Renderer as core::Renderer>::Theme: StyleSheet,
{
- #[cfg(feature = "trace")]
- let view_span = info_span!("Application", "VIEW").entered();
-
debug.view_started();
let view = application.view(id);
-
- #[cfg(feature = "trace")]
- let _ = view_span.exit();
debug.view_finished();
- #[cfg(feature = "trace")]
- let layout_span = info_span!("Application", "LAYOUT").entered();
debug.layout_started();
-
let user_interface = UserInterface::build(view, size, cache, renderer);
-
- #[cfg(feature = "trace")]
- let _ = layout_span.exit();
debug.layout_finished();
user_interface
}
-/// Updates an [`Application`] by feeding it messages, spawning any
+/// Updates a multi-window [`Application`] by feeding it messages, spawning any
/// resulting [`Command`], and tracking its [`Subscription`].
-pub fn update<A: Application, E: Executor>(
+pub fn update<A: Application, C, E: Executor>(
application: &mut A,
- caches: &mut HashMap<window::Id, user_interface::Cache>,
- states: &HashMap<window::Id, State<A>>,
- renderer: &mut A::Renderer,
+ compositor: &mut C,
runtime: &mut Runtime<E, Proxy<Event<A::Message>>, Event<A::Message>>,
clipboard: &mut Clipboard,
proxy: &mut winit::event_loop::EventLoopProxy<Event<A::Message>>,
debug: &mut Debug,
messages: &mut Vec<A::Message>,
- windows: &HashMap<window::Id, winit::window::Window>,
- graphics_info: impl FnOnce() -> compositor::Information + Copy,
+ windows: &mut Windows<A, C>,
+ ui_caches: &mut Vec<user_interface::Cache>,
) where
- A: Application + 'static,
- <A::Renderer as crate::Renderer>::Theme: StyleSheet,
+ C: Compositor<Renderer = A::Renderer> + 'static,
+ <A::Renderer as core::Renderer>::Theme: StyleSheet,
{
for message in messages.drain(..) {
- #[cfg(feature = "trace")]
- let update_span = info_span!("Application", "UPDATE").entered();
-
debug.log_message(&message);
-
debug.update_started();
let command = runtime.enter(|| application.update(message));
-
- #[cfg(feature = "trace")]
- let _ = update_span.exit();
debug.update_finished();
run_command(
application,
- caches,
- states,
- renderer,
+ compositor,
command,
runtime,
clipboard,
proxy,
debug,
windows,
- graphics_info,
+ ui_caches,
);
}
let subscription = application.subscription().map(Event::Application);
- runtime.track(subscription);
+ runtime.track(subscription.into_recipes());
}
/// Runs the actions of a [`Command`].
-pub fn run_command<A, E>(
+pub fn run_command<A, C, E>(
application: &A,
- caches: &mut HashMap<window::Id, user_interface::Cache>,
- states: &HashMap<window::Id, State<A>>,
- renderer: &mut A::Renderer,
+ compositor: &mut C,
command: Command<A::Message>,
runtime: &mut Runtime<E, Proxy<Event<A::Message>>, Event<A::Message>>,
clipboard: &mut Clipboard,
proxy: &mut winit::event_loop::EventLoopProxy<Event<A::Message>>,
debug: &mut Debug,
- windows: &HashMap<window::Id, winit::window::Window>,
- _graphics_info: impl FnOnce() -> compositor::Information + Copy,
+ windows: &mut Windows<A, C>,
+ ui_caches: &mut Vec<user_interface::Cache>,
) where
- A: Application + 'static,
+ A: Application,
E: Executor,
- <A::Renderer as crate::Renderer>::Theme: StyleSheet,
+ C: Compositor<Renderer = A::Renderer> + 'static,
+ <A::Renderer as core::Renderer>::Theme: StyleSheet,
{
- use iced_native::command;
- use iced_native::system;
- use iced_native::window;
+ use crate::runtime::clipboard;
+ use crate::runtime::system;
+ use crate::runtime::window;
for action in command.actions() {
match action {
@@ -954,11 +837,14 @@ pub fn run_command<A, E>(
},
command::Action::Window(id, action) => match action {
window::Action::Spawn { settings } => {
+ let monitor = windows.last_monitor();
+
proxy
.send_event(Event::NewWindow {
id,
- settings: settings.into(),
+ settings,
title: application.title(id),
+ monitor,
})
.expect("Send message to event loop");
}
@@ -968,86 +854,117 @@ pub fn run_command<A, E>(
.expect("Send message to event loop");
}
window::Action::Drag => {
- let window = windows.get(&id).expect("No window found");
- let _res = window.drag_window();
+ let _ = windows.with_raw(id).drag_window();
}
- window::Action::Resize { width, height } => {
- let window = windows.get(&id).expect("No window found");
- window.set_inner_size(winit::dpi::LogicalSize {
- width,
- height,
- });
+ window::Action::Resize(size) => {
+ windows.with_raw(id).set_inner_size(
+ winit::dpi::LogicalSize {
+ width: size.width,
+ height: size.height,
+ },
+ );
+ }
+ window::Action::FetchSize(callback) => {
+ let window = windows.with_raw(id);
+ let size = window.inner_size();
+
+ proxy
+ .send_event(Event::Application(callback(Size::new(
+ size.width,
+ size.height,
+ ))))
+ .expect("Send message to event loop")
+ }
+ window::Action::Maximize(maximized) => {
+ windows.with_raw(id).set_maximized(maximized);
+ }
+ window::Action::Minimize(minimized) => {
+ windows.with_raw(id).set_minimized(minimized);
}
window::Action::Move { x, y } => {
- let window = windows.get(&id).expect("No window found");
- window.set_outer_position(winit::dpi::LogicalPosition {
- x,
- y,
- });
+ windows.with_raw(id).set_outer_position(
+ winit::dpi::LogicalPosition { x, y },
+ );
}
window::Action::ChangeMode(mode) => {
- let window = windows.get(&id).expect("No window found");
+ let window = windows.with_raw(id);
window.set_visible(conversion::visible(mode));
window.set_fullscreen(conversion::fullscreen(
window.current_monitor(),
mode,
));
}
+ window::Action::ChangeIcon(icon) => {
+ windows.with_raw(id).set_window_icon(conversion::icon(icon))
+ }
window::Action::FetchMode(tag) => {
- let window = windows.get(&id).expect("No window found");
+ let window = windows.with_raw(id);
let mode = if window.is_visible().unwrap_or(true) {
conversion::mode(window.fullscreen())
} else {
- window::Mode::Hidden
+ core::window::Mode::Hidden
};
proxy
.send_event(Event::Application(tag(mode)))
- .expect("Send message to event loop");
- }
- window::Action::Maximize(value) => {
- let window = windows.get(&id).expect("No window found!");
- window.set_maximized(value);
- }
- window::Action::Minimize(value) => {
- let window = windows.get(&id).expect("No window found!");
- window.set_minimized(value);
+ .expect("Event loop doesn't exist.");
}
window::Action::ToggleMaximize => {
- let window = windows.get(&id).expect("No window found!");
+ let window = windows.with_raw(id);
window.set_maximized(!window.is_maximized());
}
window::Action::ToggleDecorations => {
- let window = windows.get(&id).expect("No window found!");
+ let window = windows.with_raw(id);
window.set_decorations(!window.is_decorated());
}
window::Action::RequestUserAttention(attention_type) => {
- let window = windows.get(&id).expect("No window found!");
- window.request_user_attention(
+ windows.with_raw(id).request_user_attention(
attention_type.map(conversion::user_attention),
);
}
window::Action::GainFocus => {
- let window = windows.get(&id).expect("No window found!");
- window.focus_window();
+ windows.with_raw(id).focus_window();
}
- window::Action::ChangeAlwaysOnTop(on_top) => {
- let window = windows.get(&id).expect("No window found!");
- window.set_always_on_top(on_top);
+ window::Action::ChangeLevel(level) => {
+ windows
+ .with_raw(id)
+ .set_window_level(conversion::window_level(level));
}
- window::Action::FetchId(tag) => {
- let window = windows.get(&id).expect("No window found!");
+ window::Action::FetchId(tag) => proxy
+ .send_event(Event::Application(tag(windows
+ .with_raw(id)
+ .id()
+ .into())))
+ .expect("Event loop doesn't exist."),
+ window::Action::Screenshot(tag) => {
+ let i = windows.index_from_id(id);
+ let state = &windows.states[i];
+ let surface = &mut windows.surfaces[i];
+ let renderer = &mut windows.renderers[i];
+
+ let bytes = compositor.screenshot(
+ renderer,
+ surface,
+ state.viewport(),
+ state.background_color(),
+ &debug.overlay(),
+ );
proxy
- .send_event(Event::Application(tag(window.id().into())))
- .expect("Send message to event loop.")
+ .send_event(Event::Application(tag(
+ window::Screenshot::new(
+ bytes,
+ state.physical_size(),
+ ),
+ )))
+ .expect("Event loop doesn't exist.")
}
},
command::Action::System(action) => match action {
system::Action::QueryInformation(_tag) => {
#[cfg(feature = "system")]
{
- let graphics_info = _graphics_info();
+ let graphics_info = compositor.fetch_information();
let proxy = proxy.clone();
let _ = std::thread::spawn(move || {
@@ -1058,33 +975,36 @@ pub fn run_command<A, E>(
proxy
.send_event(Event::Application(message))
- .expect("Send message to event loop")
+ .expect("Event loop doesn't exist.")
});
}
}
},
command::Action::Widget(action) => {
- let mut current_caches = std::mem::take(caches);
- let mut current_operation = Some(action.into_operation());
+ let mut current_operation = Some(action);
- let mut user_interfaces = build_user_interfaces(
+ let mut uis = build_user_interfaces(
application,
- renderer,
debug,
- states,
- current_caches,
+ windows,
+ std::mem::take(ui_caches),
);
- while let Some(mut operation) = current_operation.take() {
- for user_interface in user_interfaces.values_mut() {
- user_interface.operate(renderer, operation.as_mut());
+ 'operate: while let Some(mut operation) =
+ current_operation.take()
+ {
+ for (i, ui) in uis.iter_mut().enumerate() {
+ ui.operate(&windows.renderers[i], operation.as_mut());
match operation.finish() {
operation::Outcome::None => {}
operation::Outcome::Some(message) => {
proxy
.send_event(Event::Application(message))
- .expect("Send message to event loop");
+ .expect("Event loop doesn't exist.");
+
+ // operation completed, don't need to try to operate on rest of UIs
+ break 'operate;
}
operation::Outcome::Chain(next) => {
current_operation = Some(next);
@@ -1093,55 +1013,105 @@ pub fn run_command<A, E>(
}
}
- let user_interfaces: HashMap<_, _> = user_interfaces
- .drain()
- .map(|(id, interface)| (id, interface.into_cache()))
- .collect();
+ *ui_caches =
+ uis.drain(..).map(UserInterface::into_cache).collect();
+ }
+ command::Action::LoadFont { bytes, tagger } => {
+ use crate::core::text::Renderer;
+
+ // TODO change this once we change each renderer to having a single backend reference.. :pain:
+ // TODO: Error handling (?)
+ for renderer in &mut windows.renderers {
+ renderer.load_font(bytes.clone());
+ }
- current_caches = user_interfaces;
- *caches = current_caches;
+ proxy
+ .send_event(Event::Application(tagger(Ok(()))))
+ .expect("Send message to event loop");
}
}
}
}
-/// Build the user interfaces for every window.
-pub fn build_user_interfaces<'a, A>(
+/// Build the user interface for every window.
+pub fn build_user_interfaces<'a, A: Application, C: Compositor>(
application: &'a A,
- renderer: &mut A::Renderer,
debug: &mut Debug,
- states: &HashMap<window::Id, State<A>>,
- mut cached_user_interfaces: HashMap<window::Id, user_interface::Cache>,
-) -> HashMap<
- window::Id,
- UserInterface<
- 'a,
- <A as Application>::Message,
- <A as Application>::Renderer,
- >,
->
+ windows: &mut Windows<A, C>,
+ mut cached_user_interfaces: Vec<user_interface::Cache>,
+) -> Vec<UserInterface<'a, A::Message, A::Renderer>>
where
- A: Application + 'static,
- <A::Renderer as crate::Renderer>::Theme: StyleSheet,
+ <A::Renderer as core::Renderer>::Theme: StyleSheet,
+ C: Compositor<Renderer = A::Renderer>,
{
- let mut interfaces = HashMap::new();
-
- for (id, cache) in cached_user_interfaces.drain() {
- let state = &states.get(&id).unwrap();
-
- let user_interface = build_user_interface(
- application,
- cache,
- renderer,
- state.logical_size(),
- debug,
- id,
- );
+ cached_user_interfaces
+ .drain(..)
+ .zip(
+ windows
+ .ids
+ .iter()
+ .zip(windows.states.iter().zip(windows.renderers.iter_mut())),
+ )
+ .fold(vec![], |mut uis, (cache, (id, (state, renderer)))| {
+ uis.push(build_user_interface(
+ application,
+ cache,
+ renderer,
+ state.logical_size(),
+ debug,
+ *id,
+ ));
+
+ uis
+ })
+}
- let _ = interfaces.insert(id, user_interface);
+/// Returns true if the provided event should cause an [`Application`] to
+/// exit.
+pub fn requests_exit(
+ window: usize,
+ exit_on_main_closed: bool,
+ event: &winit::event::WindowEvent<'_>,
+ _modifiers: winit::event::ModifiersState,
+) -> bool {
+ use winit::event::WindowEvent;
+
+ //TODO alt f4..?
+ match event {
+ WindowEvent::CloseRequested => exit_on_main_closed && window == 0,
+ #[cfg(target_os = "macos")]
+ WindowEvent::KeyboardInput {
+ input:
+ winit::event::KeyboardInput {
+ virtual_keycode: Some(winit::event::VirtualKeyCode::Q),
+ state: winit::event::ElementState::Pressed,
+ ..
+ },
+ ..
+ } if _modifiers.logo() => true,
+ _ => false,
}
+}
+
+fn logical_bounds_of(
+ window: &winit::window::Window,
+) -> Option<((i32, i32), Size<u32>)> {
+ let scale = window.scale_factor();
+ let pos = window
+ .inner_position()
+ .map(|pos| {
+ ((pos.x as f64 / scale) as i32, (pos.y as f64 / scale) as i32)
+ })
+ .ok()?;
+ let size = {
+ let size = window.inner_size();
+ Size::new(
+ (size.width as f64 / scale) as u32,
+ (size.height as f64 / scale) as u32,
+ )
+ };
- interfaces
+ Some((pos, size))
}
#[cfg(not(target_arch = "wasm32"))]
diff --git a/winit/src/multi_window/state.rs b/winit/src/multi_window/state.rs
index 54a114ad..f2741c3c 100644
--- a/winit/src/multi_window/state.rs
+++ b/winit/src/multi_window/state.rs
@@ -1,33 +1,50 @@
-use crate::application::{self, StyleSheet as _};
use crate::conversion;
+use crate::core;
+use crate::core::{mouse, window};
+use crate::core::{Color, Size};
+use crate::graphics::Viewport;
use crate::multi_window::Application;
-use crate::window;
-use crate::{Color, Debug, Point, Size, Viewport};
+use crate::style::application;
+use std::fmt::{Debug, Formatter};
-use std::marker::PhantomData;
+use iced_style::application::StyleSheet;
use winit::event::{Touch, WindowEvent};
use winit::window::Window;
/// The state of a multi-windowed [`Application`].
-#[allow(missing_debug_implementations)]
pub struct State<A: Application>
where
- <A::Renderer as crate::Renderer>::Theme: application::StyleSheet,
+ <A::Renderer as core::Renderer>::Theme: application::StyleSheet,
{
title: String,
scale_factor: f64,
viewport: Viewport,
- viewport_changed: bool,
- cursor_position: winit::dpi::PhysicalPosition<f64>,
+ viewport_version: usize,
+ cursor_position: Option<winit::dpi::PhysicalPosition<f64>>,
modifiers: winit::event::ModifiersState,
- theme: <A::Renderer as crate::Renderer>::Theme,
+ theme: <A::Renderer as core::Renderer>::Theme,
appearance: application::Appearance,
- application: PhantomData<A>,
+}
+
+impl<A: Application> Debug for State<A>
+where
+ <A::Renderer as core::Renderer>::Theme: application::StyleSheet,
+{
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("multi_window::State")
+ .field("title", &self.title)
+ .field("scale_factor", &self.scale_factor)
+ .field("viewport", &self.viewport)
+ .field("viewport_version", &self.viewport_version)
+ .field("cursor_position", &self.cursor_position)
+ .field("appearance", &self.appearance)
+ .finish()
+ }
}
impl<A: Application> State<A>
where
- <A::Renderer as crate::Renderer>::Theme: application::StyleSheet,
+ <A::Renderer as core::Renderer>::Theme: application::StyleSheet,
{
/// Creates a new [`State`] for the provided [`Application`]'s `window`.
pub fn new(
@@ -53,13 +70,11 @@ where
title,
scale_factor,
viewport,
- viewport_changed: false,
- // TODO: Encode cursor availability in the type-system
- cursor_position: winit::dpi::PhysicalPosition::new(-1.0, -1.0),
+ viewport_version: 0,
+ cursor_position: None,
modifiers: winit::event::ModifiersState::default(),
theme,
appearance,
- application: PhantomData,
}
}
@@ -68,9 +83,11 @@ where
&self.viewport
}
- /// Returns whether or not the viewport changed.
- pub fn viewport_changed(&self) -> bool {
- self.viewport_changed
+ /// Returns the version of the [`Viewport`] of the [`State`].
+ ///
+ /// The version is incremented every time the [`Viewport`] changes.
+ pub fn viewport_version(&self) -> usize {
+ self.viewport_version
}
/// Returns the physical [`Size`] of the [`Viewport`] of the [`State`].
@@ -89,11 +106,16 @@ where
}
/// Returns the current cursor position of the [`State`].
- pub fn cursor_position(&self) -> Point {
- conversion::cursor_position(
- self.cursor_position,
- self.viewport.scale_factor(),
- )
+ pub fn cursor(&self) -> mouse::Cursor {
+ self.cursor_position
+ .map(|cursor_position| {
+ conversion::cursor_position(
+ cursor_position,
+ self.viewport.scale_factor(),
+ )
+ })
+ .map(mouse::Cursor::Available)
+ .unwrap_or(mouse::Cursor::Unavailable)
}
/// Returns the current keyboard modifiers of the [`State`].
@@ -102,7 +124,7 @@ where
}
/// Returns the current theme of the [`State`].
- pub fn theme(&self) -> &<A::Renderer as crate::Renderer>::Theme {
+ pub fn theme(&self) -> &<A::Renderer as core::Renderer>::Theme {
&self.theme
}
@@ -121,7 +143,7 @@ where
&mut self,
window: &Window,
event: &WindowEvent<'_>,
- _debug: &mut Debug,
+ _debug: &mut crate::runtime::Debug,
) {
match event {
WindowEvent::Resized(new_size) => {
@@ -132,7 +154,7 @@ where
window.scale_factor() * self.scale_factor,
);
- self.viewport_changed = true;
+ self.viewport_version = self.viewport_version.wrapping_add(1);
}
WindowEvent::ScaleFactorChanged {
scale_factor: new_scale_factor,
@@ -146,18 +168,16 @@ where
new_scale_factor * self.scale_factor,
);
- self.viewport_changed = true;
+ self.viewport_version = self.viewport_version.wrapping_add(1);
}
WindowEvent::CursorMoved { position, .. }
| WindowEvent::Touch(Touch {
location: position, ..
}) => {
- self.cursor_position = *position;
+ self.cursor_position = Some(*position);
}
WindowEvent::CursorLeft { .. } => {
- // TODO: Encode cursor availability in the type-system
- self.cursor_position =
- winit::dpi::PhysicalPosition::new(-1.0, -1.0);
+ self.cursor_position = None;
}
WindowEvent::ModifiersChanged(new_modifiers) => {
self.modifiers = *new_modifiers;
@@ -197,16 +217,20 @@ where
self.title = new_title;
}
- // Update scale factor
+ // Update scale factor and size
let new_scale_factor = application.scale_factor(window_id);
+ let new_size = window.inner_size();
+ let current_size = self.viewport.physical_size();
- if self.scale_factor != new_scale_factor {
- let size = window.inner_size();
-
+ if self.scale_factor != new_scale_factor
+ || (current_size.width, current_size.height)
+ != (new_size.width, new_size.height)
+ {
self.viewport = Viewport::with_physical_size(
- Size::new(size.width, size.height),
+ Size::new(new_size.width, new_size.height),
window.scale_factor() * new_scale_factor,
);
+ self.viewport_version = self.viewport_version.wrapping_add(1);
self.scale_factor = new_scale_factor;
}
diff --git a/winit/src/multi_window/windows.rs b/winit/src/multi_window/windows.rs
new file mode 100644
index 00000000..7b63defa
--- /dev/null
+++ b/winit/src/multi_window/windows.rs
@@ -0,0 +1,170 @@
+use crate::core::{window, Size};
+use crate::multi_window::{Application, State};
+use iced_graphics::Compositor;
+use iced_style::application::StyleSheet;
+use std::fmt::{Debug, Formatter};
+use winit::monitor::MonitorHandle;
+
+pub struct Windows<A: Application, C: Compositor>
+where
+ <A::Renderer as crate::core::Renderer>::Theme: StyleSheet,
+ C: Compositor<Renderer = A::Renderer>,
+{
+ pub ids: Vec<window::Id>,
+ pub raw: Vec<winit::window::Window>,
+ pub states: Vec<State<A>>,
+ pub viewport_versions: Vec<usize>,
+ pub surfaces: Vec<C::Surface>,
+ pub renderers: Vec<A::Renderer>,
+ pub pending_destroy: Vec<(window::Id, winit::window::WindowId)>,
+}
+
+impl<A: Application, C: Compositor> Debug for Windows<A, C>
+where
+ <A::Renderer as crate::core::Renderer>::Theme: StyleSheet,
+ C: Compositor<Renderer = A::Renderer>,
+{
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("Windows")
+ .field("ids", &self.ids)
+ .field(
+ "raw",
+ &self
+ .raw
+ .iter()
+ .map(|raw| raw.id())
+ .collect::<Vec<winit::window::WindowId>>(),
+ )
+ .field("states", &self.states)
+ .field("viewport_versions", &self.viewport_versions)
+ .finish()
+ }
+}
+
+impl<A: Application, C: Compositor> Windows<A, C>
+where
+ <A::Renderer as crate::core::Renderer>::Theme: StyleSheet,
+ C: Compositor<Renderer = A::Renderer>,
+{
+ /// Creates a new [`Windows`] with a single `window::Id::MAIN` window.
+ pub fn new(
+ application: &A,
+ compositor: &mut C,
+ renderer: A::Renderer,
+ main: winit::window::Window,
+ ) -> Self {
+ let state = State::new(application, window::Id::MAIN, &main);
+ let viewport_version = state.viewport_version();
+ let physical_size = state.physical_size();
+ let surface = compositor.create_surface(
+ &main,
+ physical_size.width,
+ physical_size.height,
+ );
+
+ Self {
+ ids: vec![window::Id::MAIN],
+ raw: vec![main],
+ states: vec![state],
+ viewport_versions: vec![viewport_version],
+ surfaces: vec![surface],
+ renderers: vec![renderer],
+ pending_destroy: vec![],
+ }
+ }
+
+ /// Adds a new window to [`Windows`]. Returns the size of the newly created window in logical
+ /// pixels & the index of the window within [`Windows`].
+ pub fn add(
+ &mut self,
+ application: &A,
+ compositor: &mut C,
+ id: window::Id,
+ window: winit::window::Window,
+ ) -> (Size, usize) {
+ let state = State::new(application, id, &window);
+ let window_size = state.logical_size();
+ let viewport_version = state.viewport_version();
+ let physical_size = state.physical_size();
+ let surface = compositor.create_surface(
+ &window,
+ physical_size.width,
+ physical_size.height,
+ );
+ let renderer = compositor.renderer();
+
+ self.ids.push(id);
+ self.raw.push(window);
+ self.states.push(state);
+ self.viewport_versions.push(viewport_version);
+ self.surfaces.push(surface);
+ self.renderers.push(renderer);
+
+ (window_size, self.ids.len() - 1)
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.ids.is_empty()
+ }
+
+ pub fn main(&self) -> &winit::window::Window {
+ &self.raw[0]
+ }
+
+ pub fn index_from_raw(&self, id: winit::window::WindowId) -> usize {
+ self.raw
+ .iter()
+ .position(|window| window.id() == id)
+ .expect("No raw window in multi_window::Windows")
+ }
+
+ pub fn index_from_id(&self, id: window::Id) -> usize {
+ self.ids
+ .iter()
+ .position(|window_id| *window_id == id)
+ .expect("No window in multi_window::Windows")
+ }
+
+ pub fn last_monitor(&self) -> Option<MonitorHandle> {
+ self.raw.last().and_then(|w| w.current_monitor())
+ }
+
+ pub fn last(&self) -> usize {
+ self.ids.len() - 1
+ }
+
+ pub fn with_raw(&self, id: window::Id) -> &winit::window::Window {
+ let i = self.index_from_id(id);
+ &self.raw[i]
+ }
+
+ /// Deletes the window with `id` from [`Windows`]. Returns the index that the window had.
+ pub fn delete(&mut self, id: window::Id) -> usize {
+ let i = self.index_from_id(id);
+
+ let id = self.ids.remove(i);
+ let window = self.raw.remove(i);
+ let _ = self.states.remove(i);
+ let _ = self.viewport_versions.remove(i);
+ let _ = self.surfaces.remove(i);
+
+ self.pending_destroy.push((id, window.id()));
+
+ i
+ }
+
+ /// Gets the winit `window` that is pending to be destroyed if it exists.
+ pub fn get_pending_destroy(
+ &mut self,
+ window: winit::window::WindowId,
+ ) -> window::Id {
+ let i = self
+ .pending_destroy
+ .iter()
+ .position(|(_, window_id)| window == *window_id)
+ .unwrap();
+
+ let (id, _) = self.pending_destroy.remove(i);
+ id
+ }
+}
diff --git a/winit/src/profiler.rs b/winit/src/profiler.rs
deleted file mode 100644
index 7031507a..00000000
--- a/winit/src/profiler.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-//! A simple profiler for Iced.
-use std::ffi::OsStr;
-use std::path::Path;
-use std::time::Duration;
-use tracing_subscriber::prelude::*;
-use tracing_subscriber::Registry;
-#[cfg(feature = "chrome-trace")]
-use {
- tracing_chrome::FlushGuard,
- tracing_subscriber::fmt::{format::DefaultFields, FormattedFields},
-};
-
-/// Profiler state. This will likely need to be updated or reworked when adding new tracing backends.
-#[allow(missing_debug_implementations)]
-pub struct Profiler {
- #[cfg(feature = "chrome-trace")]
- /// [`FlushGuard`] must not be dropped until the application scope is dropped for accurate tracing.
- _guard: FlushGuard,
-}
-
-impl Profiler {
- /// Initializes the [`Profiler`].
- pub fn init() -> Self {
- // Registry stores the spans & generates unique span IDs
- let subscriber = Registry::default();
-
- let default_path = Path::new(env!("CARGO_MANIFEST_DIR"));
- let curr_exe = std::env::current_exe()
- .unwrap_or_else(|_| default_path.to_path_buf());
- let out_dir = curr_exe.parent().unwrap_or(default_path).join("traces");
-
- #[cfg(feature = "chrome-trace")]
- let (chrome_layer, guard) = {
- let mut layer = tracing_chrome::ChromeLayerBuilder::new();
-
- // Optional configurable env var: CHROME_TRACE_FILE=/path/to/trace_file/file.json,
- // for uploading to chrome://tracing (old) or ui.perfetto.dev (new).
- if let Ok(path) = std::env::var("CHROME_TRACE_FILE") {
- layer = layer.file(path);
- } else if std::fs::create_dir_all(&out_dir).is_ok() {
- let time = std::time::SystemTime::now()
- .duration_since(std::time::UNIX_EPOCH)
- .unwrap_or(Duration::from_millis(0))
- .as_millis();
-
- let curr_exe_name = curr_exe
- .file_name()
- .unwrap_or_else(|| OsStr::new("trace"))
- .to_str()
- .unwrap_or("trace");
-
- let path =
- out_dir.join(format!("{curr_exe_name}_trace_{time}.json"));
-
- layer = layer.file(path);
- } else {
- layer = layer.file(env!("CARGO_MANIFEST_DIR"))
- }
-
- let (chrome_layer, guard) = layer
- .name_fn(Box::new(|event_or_span| match event_or_span {
- tracing_chrome::EventOrSpan::Event(event) => {
- event.metadata().name().into()
- }
- tracing_chrome::EventOrSpan::Span(span) => {
- if let Some(fields) = span
- .extensions()
- .get::<FormattedFields<DefaultFields>>()
- {
- format!(
- "{}: {}",
- span.metadata().name(),
- fields.fields.as_str()
- )
- } else {
- span.metadata().name().into()
- }
- }
- }))
- .build();
-
- (chrome_layer, guard)
- };
-
- let fmt_layer = tracing_subscriber::fmt::Layer::default();
- let subscriber = subscriber.with(fmt_layer);
-
- #[cfg(feature = "chrome-trace")]
- let subscriber = subscriber.with(chrome_layer);
-
- // create dispatcher which will forward span events to the subscriber
- // this can only be set once or will panic
- tracing::subscriber::set_global_default(subscriber)
- .expect("Tracer could not set the global default subscriber.");
-
- Profiler {
- #[cfg(feature = "chrome-trace")]
- _guard: guard,
- }
- }
-}
diff --git a/winit/src/settings.rs b/winit/src/settings.rs
index 40b3d487..2b846fbd 100644
--- a/winit/src/settings.rs
+++ b/winit/src/settings.rs
@@ -1,35 +1,10 @@
//! Configure your application.
-#[cfg(target_os = "windows")]
-#[path = "settings/windows.rs"]
-mod platform;
-
-#[cfg(target_os = "macos")]
-#[path = "settings/macos.rs"]
-mod platform;
-
-#[cfg(target_arch = "wasm32")]
-#[path = "settings/wasm.rs"]
-mod platform;
-
-#[cfg(not(any(
- target_os = "windows",
- target_os = "macos",
- target_arch = "wasm32"
-)))]
-#[path = "settings/other.rs"]
-mod platform;
-
-pub use platform::PlatformSpecific;
-
use crate::conversion;
-use crate::core::window::{Icon, Level};
-use crate::Position;
+use crate::core::window;
use winit::monitor::MonitorHandle;
use winit::window::WindowBuilder;
-use std::fmt;
-
/// The settings of an application.
#[derive(Debug, Clone, Default)]
pub struct Settings<Flags> {
@@ -40,7 +15,7 @@ pub struct Settings<Flags> {
pub id: Option<String>,
/// The [`Window`] settings.
- pub window: Window,
+ pub window: window::Settings,
/// The data needed to initialize an [`Application`].
///
@@ -50,166 +25,93 @@ pub struct Settings<Flags> {
/// Whether the [`Application`] should exit when the user requests the
/// window to close (e.g. the user presses the close button).
///
+ /// With a [`multi_window::Application`] this will instead be used to determine whether the
+ /// application should exit when the "main"" window is closed, i.e. the first window created on
+ /// app launch.
+ ///
/// [`Application`]: crate::Application
pub exit_on_close_request: bool,
}
-/// The window settings of an application.
-#[derive(Clone)]
-pub struct Window {
- /// The size of the window.
- pub size: (u32, u32),
-
- /// The position of the window.
- pub position: Position,
-
- /// The minimum size of the window.
- pub min_size: Option<(u32, u32)>,
-
- /// 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,
-
- /// Whether the window should have a border, a title bar, etc.
- pub decorations: bool,
-
- /// Whether the window should be transparent.
- pub transparent: bool,
-
- /// The window [`Level`].
- pub level: Level,
-
- /// The window icon, which is also usually used in the taskbar
- pub icon: Option<Icon>,
-
- /// Platform specific settings.
- pub platform_specific: platform::PlatformSpecific,
-}
-
-impl fmt::Debug for Window {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Window")
- .field("size", &self.size)
- .field("position", &self.position)
- .field("min_size", &self.min_size)
- .field("max_size", &self.max_size)
- .field("visible", &self.visible)
- .field("resizable", &self.resizable)
- .field("decorations", &self.decorations)
- .field("transparent", &self.transparent)
- .field("level", &self.level)
- .field("icon", &self.icon.is_some())
- .field("platform_specific", &self.platform_specific)
- .finish()
+/// Converts the window settings into a `WindowBuilder` from `winit`.
+pub fn window_builder(
+ settings: window::Settings,
+ title: &str,
+ monitor: Option<MonitorHandle>,
+ _id: Option<String>,
+) -> WindowBuilder {
+ let mut window_builder = WindowBuilder::new();
+
+ let (width, height) = settings.size;
+
+ window_builder = window_builder
+ .with_title(title)
+ .with_inner_size(winit::dpi::LogicalSize { width, height })
+ .with_resizable(settings.resizable)
+ .with_decorations(settings.decorations)
+ .with_transparent(settings.transparent)
+ .with_window_icon(settings.icon.and_then(conversion::icon))
+ .with_window_level(conversion::window_level(settings.level))
+ .with_visible(settings.visible);
+
+ if let Some(position) =
+ conversion::position(monitor.as_ref(), settings.size, settings.position)
+ {
+ window_builder = window_builder.with_position(position);
}
-}
-
-impl Window {
- /// Converts the window settings into a `WindowBuilder` from `winit`.
- pub fn into_builder(
- self,
- title: &str,
- primary_monitor: Option<MonitorHandle>,
- _id: Option<String>,
- ) -> WindowBuilder {
- let mut window_builder = WindowBuilder::new();
-
- let (width, height) = self.size;
+ if let Some((width, height)) = settings.min_size {
window_builder = window_builder
- .with_title(title)
- .with_inner_size(winit::dpi::LogicalSize { width, height })
- .with_resizable(self.resizable)
- .with_decorations(self.decorations)
- .with_transparent(self.transparent)
- .with_window_icon(self.icon.and_then(conversion::icon))
- .with_window_level(conversion::window_level(self.level))
- .with_visible(self.visible);
-
- if let Some(position) = conversion::position(
- primary_monitor.as_ref(),
- self.size,
- self.position,
- ) {
- window_builder = window_builder.with_position(position);
- }
-
- if let Some((width, height)) = self.min_size {
- window_builder = window_builder
- .with_min_inner_size(winit::dpi::LogicalSize { width, height });
- }
+ .with_min_inner_size(winit::dpi::LogicalSize { width, height });
+ }
- if let Some((width, height)) = self.max_size {
- window_builder = window_builder
- .with_max_inner_size(winit::dpi::LogicalSize { width, height });
- }
+ if let Some((width, height)) = settings.max_size {
+ window_builder = window_builder
+ .with_max_inner_size(winit::dpi::LogicalSize { width, height });
+ }
- #[cfg(any(
- target_os = "linux",
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "netbsd",
- target_os = "openbsd"
- ))]
- {
- // `with_name` is available on both `WindowBuilderExtWayland` and `WindowBuilderExtX11` and they do
- // exactly the same thing. We arbitrarily choose `WindowBuilderExtWayland` here.
- use ::winit::platform::wayland::WindowBuilderExtWayland;
-
- if let Some(id) = _id {
- window_builder = window_builder.with_name(id.clone(), id);
- }
+ #[cfg(any(
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ {
+ // `with_name` is available on both `WindowBuilderExtWayland` and `WindowBuilderExtX11` and they do
+ // exactly the same thing. We arbitrarily choose `WindowBuilderExtWayland` here.
+ use ::winit::platform::wayland::WindowBuilderExtWayland;
+
+ if let Some(id) = _id {
+ window_builder = window_builder.with_name(id.clone(), id);
}
+ }
- #[cfg(target_os = "windows")]
- {
- use winit::platform::windows::WindowBuilderExtWindows;
- #[allow(unsafe_code)]
- unsafe {
- window_builder = window_builder
- .with_parent_window(self.platform_specific.parent);
- }
+ #[cfg(target_os = "windows")]
+ {
+ use winit::platform::windows::WindowBuilderExtWindows;
+ #[allow(unsafe_code)]
+ unsafe {
window_builder = window_builder
- .with_drag_and_drop(self.platform_specific.drag_and_drop);
+ .with_parent_window(settings.platform_specific.parent);
}
+ window_builder = window_builder
+ .with_drag_and_drop(settings.platform_specific.drag_and_drop);
+ }
- #[cfg(target_os = "macos")]
- {
- use winit::platform::macos::WindowBuilderExtMacOS;
-
- window_builder = window_builder
- .with_title_hidden(self.platform_specific.title_hidden)
- .with_titlebar_transparent(
- self.platform_specific.titlebar_transparent,
- )
- .with_fullsize_content_view(
- self.platform_specific.fullsize_content_view,
- );
- }
+ #[cfg(target_os = "macos")]
+ {
+ use winit::platform::macos::WindowBuilderExtMacOS;
- window_builder
+ window_builder = window_builder
+ .with_title_hidden(settings.platform_specific.title_hidden)
+ .with_titlebar_transparent(
+ settings.platform_specific.titlebar_transparent,
+ )
+ .with_fullsize_content_view(
+ settings.platform_specific.fullsize_content_view,
+ );
}
-}
-impl Default for Window {
- fn default() -> Window {
- Window {
- size: (1024, 768),
- position: Position::default(),
- min_size: None,
- max_size: None,
- visible: true,
- resizable: true,
- decorations: true,
- transparent: false,
- level: Level::default(),
- icon: None,
- platform_specific: Default::default(),
- }
- }
+ window_builder
}
diff --git a/winit/src/settings/macos.rs b/winit/src/settings/macos.rs
deleted file mode 100644
index f86e63ad..00000000
--- a/winit/src/settings/macos.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//! Platform specific settings for macOS.
-
-/// The platform specific window settings of an application.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
-pub struct PlatformSpecific {
- /// Hides the window title.
- pub title_hidden: bool,
- /// Makes the titlebar transparent and allows the content to appear behind it.
- pub titlebar_transparent: bool,
- /// Makes the window content appear behind the titlebar.
- pub fullsize_content_view: bool,
-}
diff --git a/winit/src/settings/other.rs b/winit/src/settings/other.rs
deleted file mode 100644
index b1103f62..00000000
--- a/winit/src/settings/other.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-/// The platform specific window settings of an application.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
-pub struct PlatformSpecific;
diff --git a/winit/src/settings/wasm.rs b/winit/src/settings/wasm.rs
deleted file mode 100644
index 8e0f1bbc..00000000
--- a/winit/src/settings/wasm.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//! Platform specific settings for WebAssembly.
-
-/// The platform specific window settings of an application.
-#[derive(Debug, Clone, PartialEq, Eq, Default)]
-pub struct PlatformSpecific {
- /// The identifier of a DOM element that will be replaced with the
- /// application.
- ///
- /// If set to `None`, the application will be appended to the HTML body.
- pub target: Option<String>,
-}
diff --git a/winit/src/settings/windows.rs b/winit/src/settings/windows.rs
deleted file mode 100644
index 45d753bd..00000000
--- a/winit/src/settings/windows.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-//! Platform specific settings for Windows.
-use raw_window_handle::RawWindowHandle;
-
-/// The platform specific window settings of an application.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct PlatformSpecific {
- /// Parent window
- pub parent: Option<RawWindowHandle>,
-
- /// Drag and drop support
- pub drag_and_drop: bool,
-}
-
-impl Default for PlatformSpecific {
- fn default() -> Self {
- Self {
- parent: None,
- drag_and_drop: true,
- }
- }
-}
diff --git a/winit/src/window.rs b/winit/src/window.rs
deleted file mode 100644
index e69de29b..00000000
--- a/winit/src/window.rs
+++ /dev/null