refactored window storage;
new helper window events (Destroyed, Created); clippy + fmt;
This commit is contained in:
parent
633f405f3f
commit
d53ccc857d
56 changed files with 1508 additions and 1819 deletions
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
170
winit/src/multi_window/windows.rs
Normal file
170
winit/src/multi_window/windows.rs
Normal file
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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),
|
||||
/// 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();
|
||||
|
||||
/// The position of the window.
|
||||
pub position: Position,
|
||||
let (width, height) = settings.size;
|
||||
|
||||
/// The minimum size of the window.
|
||||
pub min_size: Option<(u32, u32)>,
|
||||
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);
|
||||
|
||||
/// 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()
|
||||
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();
|
||||
if let Some((width, height)) = settings.min_size {
|
||||
window_builder = window_builder
|
||||
.with_min_inner_size(winit::dpi::LogicalSize { width, height });
|
||||
}
|
||||
|
||||
let (width, height) = self.size;
|
||||
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(target_os = "windows")]
|
||||
{
|
||||
use winit::platform::windows::WindowBuilderExtWindows;
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
window_builder = window_builder
|
||||
.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(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 });
|
||||
}
|
||||
|
||||
if let Some((width, height)) = self.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(target_os = "windows")]
|
||||
{
|
||||
use winit::platform::windows::WindowBuilderExtWindows;
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
window_builder = window_builder
|
||||
.with_parent_window(self.platform_specific.parent);
|
||||
}
|
||||
window_builder = window_builder
|
||||
.with_drag_and_drop(self.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,
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
/// The platform specific window settings of an application.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub struct PlatformSpecific;
|
||||
|
|
@ -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>,
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue