diff options
author | 2023-01-05 15:26:28 -0800 | |
---|---|---|
committer | 2023-01-09 11:28:07 -0800 | |
commit | ec41918ec40bddaba81235372f1566da59fd09f2 (patch) | |
tree | fb530943ccf14dfec3820bf65f71a9572fd3d8be | |
parent | 1944e98f82b7efd5b268e04ba5ced065e55a218e (diff) | |
download | iced-ec41918ec40bddaba81235372f1566da59fd09f2.tar.gz iced-ec41918ec40bddaba81235372f1566da59fd09f2.tar.bz2 iced-ec41918ec40bddaba81235372f1566da59fd09f2.zip |
Implemented window title update functionality for multiwindow.
Diffstat (limited to '')
-rw-r--r-- | examples/multi_window/Cargo.toml | 2 | ||||
-rw-r--r-- | examples/multi_window/src/main.rs | 10 | ||||
-rw-r--r-- | glutin/src/application.rs | 33 | ||||
-rw-r--r-- | glutin/src/multi_window.rs | 156 | ||||
-rw-r--r-- | glutin/src/multi_window/state.rs | 14 | ||||
-rw-r--r-- | native/src/window.rs | 4 | ||||
-rw-r--r-- | native/src/window/action.rs | 8 | ||||
-rw-r--r-- | native/src/window/icon.rs | 6 | ||||
-rw-r--r-- | native/src/window/id.rs | 13 | ||||
-rw-r--r-- | src/multi_window/application.rs | 8 | ||||
-rw-r--r-- | winit/src/application.rs | 2 | ||||
-rw-r--r-- | winit/src/multi_window.rs | 190 | ||||
-rw-r--r-- | winit/src/multi_window/state.rs | 14 | ||||
-rw-r--r-- | winit/src/window.rs | 37 |
14 files changed, 262 insertions, 235 deletions
diff --git a/examples/multi_window/Cargo.toml b/examples/multi_window/Cargo.toml index 6de895d7..62198595 100644 --- a/examples/multi_window/Cargo.toml +++ b/examples/multi_window/Cargo.toml @@ -10,4 +10,4 @@ publish = false iced = { path = "../..", features = ["debug", "multi_window"] } env_logger = "0.10.0" iced_native = { path = "../../native" } -iced_lazy = { path = "../../lazy" }
\ No newline at end of file +iced_lazy = { path = "../../lazy" } diff --git a/examples/multi_window/src/main.rs b/examples/multi_window/src/main.rs index 9fe6b481..b9f0514c 100644 --- a/examples/multi_window/src/main.rs +++ b/examples/multi_window/src/main.rs @@ -26,6 +26,7 @@ struct Example { _focused: window::Id, } +#[derive(Debug)] struct Window { title: String, panes: pane_grid::State<Pane>, @@ -80,8 +81,11 @@ impl Application for Example { ) } - fn title(&self) -> String { - String::from("Multi windowed pane grid - Iced") + fn title(&self, window: window::Id) -> String { + self.windows + .get(&window) + .map(|w| w.title.clone()) + .unwrap_or(String::from("New Window")) } fn update(&mut self, message: Message) -> Command<Message> { @@ -262,7 +266,6 @@ impl Application for Example { &window.title, WindowMessage::TitleChanged, ), - button(text("Apply")).style(theme::Button::Primary), button(text("Close")) .on_press(WindowMessage::CloseWindow) .style(theme::Button::Destructive), @@ -389,6 +392,7 @@ impl std::fmt::Display for SelectableWindow { } } +#[derive(Debug)] struct Pane { id: usize, pub axis: pane_grid::Axis, diff --git a/glutin/src/application.rs b/glutin/src/application.rs index 45ff37f0..f43a47b9 100644 --- a/glutin/src/application.rs +++ b/glutin/src/application.rs @@ -245,18 +245,7 @@ where ) })?; - let (width, height) = window.inner_size().into(); - let surface_attributes = - SurfaceAttributesBuilder::<WindowSurface>::new() - .with_srgb(Some(true)) - .build( - window_handle, - NonZeroU32::new(width).unwrap_or(ONE), - NonZeroU32::new(height).unwrap_or(ONE), - ); - - let surface = display - .create_window_surface(configuration.as_ref(), &surface_attributes) + let surface = gl_surface(&display, configuration.as_ref(), &window) .map_err(|error| { Error::GraphicsCreationFailed( iced_graphics::Error::BackendError(format!( @@ -616,3 +605,23 @@ async fn run_instance<A, E, C>( // Manually drop the user interface drop(ManuallyDrop::into_inner(user_interface)); } + +#[allow(unsafe_code)] +/// Creates a new [`glutin::Surface<WindowSurface>`]. +pub fn gl_surface( + display: &Display, + gl_config: &Config, + window: &winit::window::Window, +) -> Result<Surface<WindowSurface>, glutin::error::Error> { + let (width, height) = window.inner_size().into(); + + let surface_attributes = SurfaceAttributesBuilder::<WindowSurface>::new() + .with_srgb(Some(true)) + .build( + window.raw_window_handle(), + NonZeroU32::new(width).unwrap_or(ONE), + NonZeroU32::new(height).unwrap_or(ONE), + ); + + unsafe { display.create_window_surface(gl_config, &surface_attributes) } +} diff --git a/glutin/src/multi_window.rs b/glutin/src/multi_window.rs index 35eeeb36..e79ec77d 100644 --- a/glutin/src/multi_window.rs +++ b/glutin/src/multi_window.rs @@ -12,7 +12,6 @@ use iced_winit::conversion; use iced_winit::futures; use iced_winit::futures::channel::mpsc; use iced_winit::renderer; -use iced_winit::settings; use iced_winit::user_interface; use iced_winit::window; use iced_winit::winit; @@ -26,11 +25,12 @@ use glutin::context::{ NotCurrentGlContextSurfaceAccessor, PossiblyCurrentGlContext, }; use glutin::display::{Display, DisplayApiPreference, GlDisplay}; -use glutin::surface::{ - GlSurface, Surface, SurfaceAttributesBuilder, SwapInterval, WindowSurface, -}; +use glutin::surface::{GlSurface, SwapInterval}; use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; +use crate::application::gl_surface; +use iced_native::window::Action; +use iced_winit::multi_window::Event; use std::collections::HashMap; use std::ffi::CString; use std::mem::ManuallyDrop; @@ -76,7 +76,7 @@ where }; let builder = settings.window.into_builder( - &application.title(), + &application.title(window::Id::MAIN), event_loop.primary_monitor(), settings.id, ); @@ -239,7 +239,14 @@ where ) })?; - let surface = gl_surface(&display, configuration.as_ref(), &window); + let surface = gl_surface(&display, configuration.as_ref(), &window) + .map_err(|error| { + Error::GraphicsCreationFailed( + iced_graphics::Error::BackendError(format!( + "failed to create surface: {error}" + )), + ) + })?; (display, window, configuration.0, surface, context) }; @@ -301,14 +308,13 @@ where event: winit::event::WindowEvent::Resized(*new_inner_size), window_id, }), - winit::event::Event::UserEvent(Event::NewWindow(id, settings)) => { - // TODO(derezzedex) + winit::event::Event::UserEvent(Event::NewWindow { + id, + settings, + title, + }) => { let window = settings - .into_builder( - "fix window title", - event_loop.primary_monitor(), - None, - ) + .into_builder(&title, event_loop.primary_monitor(), None) .build(event_loop) .expect("Failed to build window"); @@ -372,9 +378,11 @@ async fn run_instance<A, E, C>( let mut interfaces = ManuallyDrop::new(HashMap::new()); for (&id, window) in windows.keys().zip(windows.values()) { - let surface = gl_surface(&display, &configuration, &window); - let current_context = context.make_current(&surface).expect("Make current."); - let state = State::new(&application, &window); + let surface = gl_surface(&display, &configuration, &window) + .expect("Create surface."); + let current_context = + context.make_current(&surface).expect("Make current."); + let state = State::new(&application, id, &window); let physical_size = state.physical_size(); surface.resize( @@ -392,7 +400,9 @@ async fn run_instance<A, E, C>( id, ); - context = current_context.make_not_current().expect("Make not current."); + context = current_context + .make_not_current() + .expect("Make not current."); let _ = states.insert(id, state); let _ = surfaces.insert(id, surface); @@ -431,7 +441,7 @@ async fn run_instance<A, E, C>( let (filtered, remaining): (Vec<_>, Vec<_>) = events.iter().cloned().partition( |(window_id, _event): &( - Option<crate::window::Id>, + Option<window::Id>, iced_native::event::Event, )| { *window_id == Some(id) || *window_id == None @@ -503,7 +513,11 @@ async fn run_instance<A, E, C>( ); // Update window - state.synchronize(&application, &windows); + state.synchronize( + &application, + id, + windows.get(&id).expect("No window found with ID."), + ); let should_exit = application.should_exit(); @@ -563,7 +577,7 @@ async fn run_instance<A, E, C>( event::Event::UserEvent(event) => match event { Event::Application(message) => messages.push(message), Event::WindowCreated(id, window) => { - let state = State::new(&application, &window); + let state = State::new(&application, id, &window); let user_interface = multi_window::build_user_interface( &application, user_interface::Cache::default(), @@ -573,26 +587,8 @@ async fn run_instance<A, E, C>( id, ); - let window_handle = window.raw_window_handle(); - let (width, height) = window.inner_size().into(); - let surface_attributes = - SurfaceAttributesBuilder::<WindowSurface>::new() - .with_srgb(Some(true)) - .build( - window_handle, - NonZeroU32::new(width).unwrap_or(ONE), - NonZeroU32::new(height).unwrap_or(ONE), - ); - - #[allow(unsafe_code)] - let surface = unsafe { - display - .create_window_surface( - &configuration, - &surface_attributes, - ) - .expect("failed to create surface") - }; + let surface = gl_surface(&display, &configuration, &window) + .expect("Create surface."); let _ = states.insert(id, state); let _ = interfaces.insert(id, user_interface); @@ -624,7 +620,7 @@ async fn run_instance<A, E, C>( break 'main; } } - Event::NewWindow(_, _) => unreachable!(), + Event::NewWindow { .. } => unreachable!(), }, event::Event::RedrawRequested(id) => { let state = window_ids @@ -687,9 +683,10 @@ async fn run_instance<A, E, C>( NonZeroU32::new(physical_size.height).unwrap_or(ONE), ); - if let Err(error) = - surface.set_swap_interval(¤t_context, SwapInterval::Wait(ONE)) - { + if let Err(_) = surface.set_swap_interval( + ¤t_context, + SwapInterval::Wait(ONE), + ) { log::error!("Could not set swap interval for surface attached to window id: {:?}", id); } @@ -706,9 +703,13 @@ async fn run_instance<A, E, C>( &debug.overlay(), ); - surface.swap_buffers(¤t_context).expect("Swap buffers"); + surface + .swap_buffers(¤t_context) + .expect("Swap buffers"); - context = current_context.make_not_current().expect("Make not current."); + context = current_context + .make_not_current() + .expect("Make not current."); debug.render_finished(); // TODO: Handle animations! // Maybe we can use `ControlFlow::WaitUntil` for this. @@ -751,11 +752,10 @@ async fn run_instance<A, E, C>( )); } } else { - // TODO(derezzedex): log error + log::error!("Window state not found for id: {:?}", window_id); } } else { - // TODO(derezzedex): log error - // println!("{:?}: {:?}", window_id, window_event); + log::error!("Window not found for id: {:?}", window_id); } } _ => {} @@ -766,25 +766,6 @@ async fn run_instance<A, E, C>( // drop(ManuallyDrop::into_inner(user_interface)); } -/// TODO(derezzedex): -// This is the an 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 - Application(Message), - - /// TODO(derezzedex) - // Create a wrapper variant of `window::Event` type instead - // (maybe we should also allow users to listen/react to those internal messages?) - NewWindow(window::Id, settings::Window), - /// TODO(derezzedex) - CloseWindow(window::Id), - /// TODO(derezzedex) - WindowCreated(window::Id, winit::window::Window), -} - /// Updates an [`Application`] by feeding it the provided messages, spawning any /// resulting [`Command`], and tracking its [`Subscription`]. pub fn update<A: Application, E: Executor>( @@ -872,7 +853,11 @@ pub fn run_command<A, E>( command::Action::Window(id, action) => match action { window::Action::Spawn { settings } => { proxy - .send_event(Event::NewWindow(id, settings.into())) + .send_event(Event::NewWindow { + id, + settings: settings.into(), + title: application.title(id), + }) .expect("Send message to event loop"); } window::Action::Close => { @@ -934,6 +919,16 @@ pub fn run_command<A, E>( let window = windows.get(&id).expect("No window found!"); window.set_decorations(!window.is_decorated()); } + Action::RequestUserAttention(attention_type) => { + let window = windows.get(&id).expect("No window found!"); + window.request_user_attention( + attention_type.map(conversion::user_attention), + ); + } + Action::GainFocus => { + let window = windows.get(&id).expect("No window found!"); + window.focus_window(); + } }, command::Action::System(action) => match action { system::Action::QueryInformation(_tag) => { @@ -1031,26 +1026,3 @@ where interfaces } - -#[allow(unsafe_code)] -fn gl_surface( - display: &Display, - gl_config: &Config, - window: &winit::window::Window, -) -> Surface<WindowSurface> { - let (width, height) = window.inner_size().into(); - - let surface_attributes = SurfaceAttributesBuilder::<WindowSurface>::new() - .with_srgb(Some(true)) - .build( - window.raw_window_handle(), - NonZeroU32::new(width).unwrap_or(ONE), - NonZeroU32::new(height).unwrap_or(ONE), - ); - - unsafe { - display - .create_window_surface(gl_config, &surface_attributes) - .expect("failed to create surface") - } -} diff --git a/glutin/src/multi_window/state.rs b/glutin/src/multi_window/state.rs index e7e82876..04ec5083 100644 --- a/glutin/src/multi_window/state.rs +++ b/glutin/src/multi_window/state.rs @@ -8,7 +8,6 @@ use iced_winit::winit; use winit::event::{Touch, WindowEvent}; use winit::window::Window; -use std::collections::HashMap; use std::marker::PhantomData; /// The state of a windowed [`Application`]. @@ -33,8 +32,8 @@ where <A::Renderer as crate::Renderer>::Theme: application::StyleSheet, { /// Creates a new [`State`] for the provided [`Application`] and window. - pub fn new(application: &A, window: &Window) -> Self { - let title = application.title(); + pub fn new(application: &A, window_id: window::Id, window: &Window) -> Self { + let title = application.title(window_id); let scale_factor = application.scale_factor(); let theme = application.theme(); let appearance = theme.appearance(&application.style()); @@ -67,7 +66,7 @@ where &self.viewport } - /// TODO(derezzedex) + /// Returns whether or not the current [`Viewport`] has changed. pub fn viewport_changed(&self) -> bool { self.viewport_changed } @@ -187,12 +186,11 @@ where pub fn synchronize( &mut self, application: &A, - windows: &HashMap<window::Id, Window>, + window_id: window::Id, + window: &Window, ) { - let window = windows.values().next().expect("No window found"); - // Update window title - let new_title = application.title(); + let new_title = application.title(window_id); if self.title != new_title { window.set_title(&new_title); diff --git a/native/src/window.rs b/native/src/window.rs index 1c03fcdf..96a5fe61 100644 --- a/native/src/window.rs +++ b/native/src/window.rs @@ -4,6 +4,8 @@ mod event; mod icon; mod id; mod mode; +mod position; +mod settings; mod user_attention; pub use action::Action; @@ -11,6 +13,6 @@ pub use event::Event; pub use icon::Icon; pub use id::Id; pub use mode::Mode; -pub use user_attention::UserAttention; pub use position::Position; pub use settings::Settings; +pub use user_attention::UserAttention; diff --git a/native/src/window/action.rs b/native/src/window/action.rs index 0587f25c..929663ec 100644 --- a/native/src/window/action.rs +++ b/native/src/window/action.rs @@ -1,4 +1,4 @@ -use crate::window::{self, Mode, UserAttention}; +use crate::window; use iced_futures::MaybeSend; use std::fmt; @@ -13,9 +13,9 @@ pub enum Action<T> { /// There’s no guarantee that this will work unless the left mouse /// button was pressed immediately before this function is called. Drag, - /// TODO(derezzedex) + /// Spawns a new window with the provided [`window::Settings`]. Spawn { - /// TODO(derezzedex) + /// The settings of the [`Window`]. settings: window::Settings, }, /// Resize the window. @@ -62,7 +62,7 @@ pub enum Action<T> { /// - **macOS:** `None` has no effect. /// - **X11:** Requests for user attention must be manually cleared. /// - **Wayland:** Requires `xdg_activation_v1` protocol, `None` has no effect. - RequestUserAttention(Option<UserAttention>), + RequestUserAttention(Option<window::UserAttention>), /// Brings the window to the front and sets input focus. Has no effect if the window is /// already in focus, minimized, or not visible. /// diff --git a/native/src/window/icon.rs b/native/src/window/icon.rs index e89baf03..08a6acfd 100644 --- a/native/src/window/icon.rs +++ b/native/src/window/icon.rs @@ -3,10 +3,10 @@ /// The icon of a window. #[derive(Debug, Clone)] pub struct Icon { - /// TODO(derezzedex) + /// The __rgba__ color data of the window [`Icon`]. pub rgba: Vec<u8>, - /// TODO(derezzedex) + /// The width of the window [`Icon`]. pub width: u32, - /// TODO(derezzedex) + /// The height of the window [`Icon`]. pub height: u32, } diff --git a/native/src/window/id.rs b/native/src/window/id.rs index 5060e162..fa9761f5 100644 --- a/native/src/window/id.rs +++ b/native/src/window/id.rs @@ -1,15 +1,18 @@ use std::collections::hash_map::DefaultHasher; +use std::fmt::{Display, Formatter}; use std::hash::{Hash, Hasher}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -/// TODO(derezzedex) +/// The ID of the window. +/// +/// This is not necessarily the same as the window ID fetched from `winit::window::Window`. pub struct Id(u64); impl Id { /// TODO(derezzedex): maybe change `u64` to an enum `Type::{Single, Multi(u64)}` pub const MAIN: Self = Id(0); - /// TODO(derezzedex) + /// Creates a new unique window ID. pub fn new(id: impl Hash) -> Id { let mut hasher = DefaultHasher::new(); id.hash(&mut hasher); @@ -17,3 +20,9 @@ impl Id { Id(hasher.finish()) } } + +impl Display for Id { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "Id({})", self.0) + } +} diff --git a/src/multi_window/application.rs b/src/multi_window/application.rs index 7d559397..dc1ac5b0 100644 --- a/src/multi_window/application.rs +++ b/src/multi_window/application.rs @@ -44,7 +44,7 @@ pub trait Application: Sized { /// /// This title can be dynamic! The runtime will automatically update the /// title of your application when necessary. - fn title(&self) -> String; + fn title(&self, window: window::Id) -> String; /// Handles a __message__ and updates the state of the [`Application`]. /// @@ -110,7 +110,7 @@ pub trait Application: Sized { false } - /// TODO(derezzedex) + /// Requests that the [`window`] be closed. fn close_requested(&self, window: window::Id) -> Self::Message; /// Runs the [`Application`]. @@ -163,8 +163,8 @@ where (Instance(app), command) } - fn title(&self) -> String { - self.0.title() + fn title(&self, window: window::Id) -> String { + self.0.title(window) } fn update(&mut self, message: Self::Message) -> Command<Self::Message> { diff --git a/winit/src/application.rs b/winit/src/application.rs index 910f3d94..eef6833c 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -675,7 +675,7 @@ pub fn run_command<A, E>( window::Action::Drag => { let _res = window.drag_window(); } - window::Action::Spawn { .. } | window::Action::Close => { + window::Action::Spawn { .. } => { log::info!( "This is only available on `multi_window::Application`" ) diff --git a/winit/src/multi_window.rs b/winit/src/multi_window.rs index 43455148..6a2bdca9 100644 --- a/winit/src/multi_window.rs +++ b/winit/src/multi_window.rs @@ -22,6 +22,7 @@ use iced_native::user_interface::{self, UserInterface}; pub use iced_native::application::{Appearance, StyleSheet}; +use iced_native::window::Action; use std::collections::HashMap; use std::mem::ManuallyDrop; @@ -36,7 +37,14 @@ pub enum Event<Message> { /// TODO(derezzedex) // Create a wrapper variant of `window::Event` type instead // (maybe we should also allow users to listen/react to those internal messages?) - NewWindow(window::Id, settings::Window), + NewWindow { + /// The [window::Id] of the newly spawned [`Window`]. + id: window::Id, + /// The [settings::Window] of the newly spawned [`Window`]. + settings: settings::Window, + /// The title of the newly spawned [`Window`]. + title: String, + }, /// TODO(derezzedex) CloseWindow(window::Id), /// TODO(derezzedex) @@ -95,11 +103,11 @@ 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 the [`Application`]. + /// Returns the current title of the current [`Application`] window. /// /// This title can be dynamic! The runtime will automatically update the /// title of your application when necessary. - fn title(&self) -> String; + fn title(&self, window_id: window::Id) -> String; /// Returns the current [`Theme`] of the [`Application`]. fn theme(&self) -> <Self::Renderer as crate::Renderer>::Theme; @@ -144,7 +152,7 @@ where false } - /// TODO(derezzedex) + /// Requests that the [`window`] be closed. fn close_requested(&self, window: window::Id) -> Self::Message; } @@ -184,7 +192,7 @@ where }; let builder = settings.window.into_builder( - &application.title(), + &application.title(window::Id::MAIN), event_loop.primary_monitor(), settings.id, ); @@ -253,14 +261,13 @@ where event: winit::event::WindowEvent::Resized(*new_inner_size), window_id, }), - winit::event::Event::UserEvent(Event::NewWindow(id, settings)) => { - // TODO(derezzedex) + winit::event::Event::UserEvent(Event::NewWindow { + id, + settings, + title, + }) => { let window = settings - .into_builder( - "fix window title", - event_loop.primary_monitor(), - None, - ) + .into_builder(&title, event_loop.primary_monitor(), None) .build(event_loop) .expect("Failed to build window"); @@ -320,10 +327,7 @@ async fn run_instance<A, E, C>( for (&id, window) in windows.keys().zip(windows.values()) { let mut surface = compositor.create_surface(window); - println!("Creating surface for window: {:?}", window); - - let state = State::new(&application, window); - + let state = State::new(&application, id, window); let physical_size = state.physical_size(); compositor.configure_surface( @@ -457,7 +461,11 @@ async fn run_instance<A, E, C>( ); // Update window - state.synchronize(&application, &windows); + state.synchronize( + &application, + id, + windows.get(&id).expect("No window found with ID."), + ); let should_exit = application.should_exit(); @@ -516,72 +524,85 @@ async fn run_instance<A, E, C>( ), )); } - event::Event::UserEvent(event) => { - match event { - Event::Application(message) => { - messages.push(message); - } - Event::WindowCreated(id, window) => { - let mut surface = compositor.create_surface(&window); - - let state = State::new(&application, &window); + event::Event::UserEvent(event) => match event { + Event::Application(message) => { + messages.push(message); + } + Event::WindowCreated(id, window) => { + let mut surface = compositor.create_surface(&window); - let physical_size = state.physical_size(); + let state = State::new(&application, id, &window); - compositor.configure_surface( - &mut surface, - physical_size.width, - physical_size.height, - ); + let physical_size = state.physical_size(); - let user_interface = build_user_interface( - &application, - user_interface::Cache::default(), - &mut renderer, - state.logical_size(), - &mut debug, - id, - ); + compositor.configure_surface( + &mut surface, + physical_size.width, + physical_size.height, + ); - 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); - } - Event::CloseWindow(id) => { - println!("Closing window {:?}. Total: {}", id, windows.len()); + let user_interface = build_user_interface( + &application, + user_interface::Cache::default(), + &mut renderer, + state.logical_size(), + &mut debug, + 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 _ = 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); + } + 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 + ); + } - if windows.is_empty() { - log::info!("All windows are closed. Terminating program."); - break 'main; - } else { - log::info!("Remaining windows: {:?}", windows.len()); - } + 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::NewWindow { .. } => unreachable!(), + }, event::Event::RedrawRequested(id) => { let state = window_ids .get(&id) @@ -716,11 +737,10 @@ async fn run_instance<A, E, C>( )); } } else { - // TODO(derezzedex): log error + log::error!("No window state found for id: {:?}", window_id); } } else { - // TODO(derezzedex): log error - // println!("{:?}: {:?}", window_id, window_event); + log::error!("No window found with id: {:?}", window_id); } } _ => {} @@ -864,7 +884,11 @@ pub fn run_command<A, E>( command::Action::Window(id, action) => match action { window::Action::Spawn { settings } => { proxy - .send_event(Event::NewWindow(id, settings.into())) + .send_event(Event::NewWindow { + id, + settings: settings.into(), + title: application.title(id), + }) .expect("Send message to event loop"); } window::Action::Close => { @@ -926,6 +950,16 @@ pub fn run_command<A, E>( let window = windows.get(&id).expect("No window found!"); window.set_decorations(!window.is_decorated()); } + window::Action::RequestUserAttention(attention_type) => { + let window = windows.get(&id).expect("No window found!"); + window.request_user_attention( + attention_type.map(conversion::user_attention), + ); + } + Action::GainFocus => { + let window = windows.get(&id).expect("No window found!"); + window.focus_window(); + } }, command::Action::System(action) => match action { system::Action::QueryInformation(_tag) => { diff --git a/winit/src/multi_window/state.rs b/winit/src/multi_window/state.rs index eebdcdf1..7a598b98 100644 --- a/winit/src/multi_window/state.rs +++ b/winit/src/multi_window/state.rs @@ -4,7 +4,6 @@ use crate::multi_window::Application; use crate::window; use crate::{Color, Debug, Point, Size, Viewport}; -use std::collections::HashMap; use std::marker::PhantomData; use winit::event::{Touch, WindowEvent}; use winit::window::Window; @@ -31,8 +30,8 @@ where <A::Renderer as crate::Renderer>::Theme: application::StyleSheet, { /// Creates a new [`State`] for the provided [`Application`] and window. - pub fn new(application: &A, window: &Window) -> Self { - let title = application.title(); + pub fn new(application: &A, window_id: window::Id, window: &Window) -> Self { + let title = application.title(window_id); let scale_factor = application.scale_factor(); let theme = application.theme(); let appearance = theme.appearance(&application.style()); @@ -65,7 +64,7 @@ where &self.viewport } - /// TODO(derezzedex) + /// Returns whether or not the viewport changed. pub fn viewport_changed(&self) -> bool { self.viewport_changed } @@ -184,12 +183,11 @@ where pub fn synchronize( &mut self, application: &A, - windows: &HashMap<window::Id, Window>, + window_id: window::Id, + window: &Window, ) { - let window = windows.values().next().expect("No window found"); - // Update window title - let new_title = application.title(); + let new_title = application.title(window_id); if self.title != new_title { window.set_title(&new_title); diff --git a/winit/src/window.rs b/winit/src/window.rs index fba863ef..5a8ff6df 100644 --- a/winit/src/window.rs +++ b/winit/src/window.rs @@ -2,19 +2,19 @@ use crate::command::{self, Command}; use iced_native::window; -pub use window::{Id, Event, Mode, UserAttention}; +pub use window::{Event, Id, Mode, UserAttention}; -/// Closes the current window and exits the application. -pub fn close<Message>() -> Command<Message> { - Command::single(command::Action::Window(window::Action::Close)) +/// Closes the window. +pub fn close<Message>(id: window::Id) -> Command<Message> { + Command::single(command::Action::Window(id, window::Action::Close)) } /// Begins dragging the window while the left mouse button is held. -pub fn drag<Message>() -> Command<Message> { - Command::single(command::Action::Window(window::Action::Drag)) +pub fn drag<Message>(id: window::Id) -> Command<Message> { + Command::single(command::Action::Window(id, window::Action::Drag)) } -/// TODO(derezzedex) +/// Spawns a new window. pub fn spawn<Message>( id: window::Id, settings: window::Settings, @@ -25,11 +25,6 @@ pub fn spawn<Message>( )) } -/// TODO(derezzedex) -pub fn close<Message>(id: window::Id) -> Command<Message> { - Command::single(command::Action::Window(id, window::Action::Close)) -} - /// Resizes the window to the given logical dimensions. pub fn resize<Message>( id: window::Id, @@ -43,13 +38,19 @@ pub fn resize<Message>( } /// Sets the window to maximized or back. -pub fn maximize<Message>(value: bool) -> Command<Message> { - Command::single(command::Action::Window(window::Action::Maximize(value))) +pub fn maximize<Message>(id: window::Id, value: bool) -> Command<Message> { + Command::single(command::Action::Window( + id, + window::Action::Maximize(value), + )) } /// Set the window to minimized or back. -pub fn minimize<Message>(value: bool) -> Command<Message> { - Command::single(command::Action::Window(window::Action::Minimize(value))) +pub fn minimize<Message>(id: window::Id, value: bool) -> Command<Message> { + Command::single(command::Action::Window( + id, + window::Action::Minimize(value), + )) } /// Moves a window to the given logical coordinates. @@ -63,8 +64,8 @@ pub fn set_mode<Message>(id: window::Id, mode: Mode) -> Command<Message> { } /// Sets the window to maximized or back. -pub fn toggle_maximize<Message>() -> Command<Message> { - Command::single(command::Action::Window(window::Action::ToggleMaximize)) +pub fn toggle_maximize<Message>(id: window::Id) -> Command<Message> { + Command::single(command::Action::Window(id, window::Action::ToggleMaximize)) } /// Fetches the current [`Mode`] of the window. |