Merge pull request #2456 from iced-rs/window-id-in-event-subscriptions

Introduce `window::Id` to `Event` subscriptions
This commit is contained in:
Héctor Ramón 2024-06-11 20:22:44 +02:00 committed by GitHub
commit e6d0b3bda5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 225 additions and 198 deletions

View file

@ -19,31 +19,10 @@ pub enum Event {
Mouse(mouse::Event), Mouse(mouse::Event),
/// A window event /// A window event
Window(window::Id, window::Event), Window(window::Event),
/// A touch event /// A touch event
Touch(touch::Event), Touch(touch::Event),
/// A platform specific event
PlatformSpecific(PlatformSpecific),
}
/// A platform specific event
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PlatformSpecific {
/// A MacOS specific event
MacOS(MacOS),
}
/// Describes an event specific to MacOS
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MacOS {
/// Triggered when the app receives an URL from the system
///
/// _**Note:** For this event to be triggered, the executable needs to be properly [bundled]!_
///
/// [bundled]: https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW19
ReceivedUrl(String),
} }
/// The status of an [`Event`] after being processed. /// The status of an [`Event`] after being processed.

View file

@ -37,9 +37,8 @@ impl Events {
Command::none() Command::none()
} }
Message::EventOccurred(event) => { Message::EventOccurred(event) => {
if let Event::Window(id, window::Event::CloseRequested) = event if let Event::Window(window::Event::CloseRequested) = event {
{ window::close(window::Id::MAIN)
window::close(id)
} else { } else {
Command::none() Command::none()
} }

View file

@ -9,7 +9,6 @@ use iced_wgpu::{wgpu, Engine, Renderer};
use iced_winit::conversion; use iced_winit::conversion;
use iced_winit::core::mouse; use iced_winit::core::mouse;
use iced_winit::core::renderer; use iced_winit::core::renderer;
use iced_winit::core::window;
use iced_winit::core::{Color, Font, Pixels, Size, Theme}; use iced_winit::core::{Color, Font, Pixels, Size, Theme};
use iced_winit::futures; use iced_winit::futures;
use iced_winit::runtime::program; use iced_winit::runtime::program;
@ -317,7 +316,6 @@ pub fn main() -> Result<(), winit::error::EventLoopError> {
// Map window event to iced event // Map window event to iced event
if let Some(event) = iced_winit::conversion::window_event( if let Some(event) = iced_winit::conversion::window_event(
window::Id::MAIN,
event, event,
window.scale_factor(), window.scale_factor(),
*modifiers, *modifiers,

View file

@ -275,7 +275,7 @@ where
) -> event::Status { ) -> event::Status {
let state = tree.state.downcast_mut::<State>(); let state = tree.state.downcast_mut::<State>();
if let Event::Window(_, window::Event::RedrawRequested(now)) = event { if let Event::Window(window::Event::RedrawRequested(now)) = event {
state.animation = state.animation.timed_transition( state.animation = state.animation.timed_transition(
self.cycle_duration, self.cycle_duration,
self.rotation_duration, self.rotation_duration,

View file

@ -189,7 +189,7 @@ where
) -> event::Status { ) -> event::Status {
let state = tree.state.downcast_mut::<State>(); let state = tree.state.downcast_mut::<State>();
if let Event::Window(_, window::Event::RedrawRequested(now)) = event { if let Event::Window(window::Event::RedrawRequested(now)) = event {
*state = state.timed_transition(self.cycle_duration, now); *state = state.timed_transition(self.cycle_duration, now);
shell.request_redraw(RedrawRequest::NextFrame); shell.request_redraw(RedrawRequest::NextFrame);

View file

@ -145,16 +145,18 @@ impl multi_window::Application for Example {
} }
fn subscription(&self) -> Subscription<Self::Message> { fn subscription(&self) -> Subscription<Self::Message> {
event::listen_with(|event, _| { event::listen_with(|event, _, window| {
if let iced::Event::Window(id, window_event) = event { if let iced::Event::Window(window_event) = event {
match window_event { match window_event {
window::Event::CloseRequested => { window::Event::CloseRequested => {
Some(Message::CloseWindow(id)) Some(Message::CloseWindow(window))
} }
window::Event::Opened { position, .. } => { window::Event::Opened { position, .. } => {
Some(Message::WindowOpened(id, position)) Some(Message::WindowOpened(window, position))
}
window::Event::Closed => {
Some(Message::WindowClosed(window))
} }
window::Event::Closed => Some(Message::WindowClosed(id)),
_ => None, _ => None,
} }
} else { } else {

View file

@ -499,9 +499,7 @@ mod toast {
clipboard: &mut dyn Clipboard, clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>, shell: &mut Shell<'_, Message>,
) -> event::Status { ) -> event::Status {
if let Event::Window(_, window::Event::RedrawRequested(now)) = if let Event::Window(window::Event::RedrawRequested(now)) = &event {
&event
{
let mut next_redraw: Option<window::RedrawRequest> = None; let mut next_redraw: Option<window::RedrawRequest> = None;
self.instants.iter_mut().enumerate().for_each( self.instants.iter_mut().enumerate().for_each(

View file

@ -1,4 +1,4 @@
use iced::event::{self, Event}; use iced::event;
use iced::widget::{center, text}; use iced::widget::{center, text};
use iced::{Element, Subscription}; use iced::{Element, Subscription};
@ -15,27 +15,20 @@ struct App {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum Message { enum Message {
EventOccurred(Event), UrlReceived(String),
} }
impl App { impl App {
fn update(&mut self, message: Message) { fn update(&mut self, message: Message) {
match message { match message {
Message::EventOccurred(event) => { Message::UrlReceived(url) => {
if let Event::PlatformSpecific( self.url = Some(url);
event::PlatformSpecific::MacOS(event::MacOS::ReceivedUrl(
url,
)),
) = event
{
self.url = Some(url);
}
} }
} }
} }
fn subscription(&self) -> Subscription<Message> { fn subscription(&self) -> Subscription<Message> {
event::listen().map(Message::EventOccurred) event::listen_url().map(Message::UrlReceived)
} }
fn view(&self) -> Element<Message> { fn view(&self) -> Element<Message> {

View file

@ -145,11 +145,11 @@ impl Example {
} }
fn subscription(&self) -> Subscription<Message> { fn subscription(&self) -> Subscription<Message> {
event::listen_with(|event, _| match event { event::listen_with(|event, _status, _window| match event {
Event::Mouse(mouse::Event::CursorMoved { position }) => { Event::Mouse(mouse::Event::CursorMoved { position }) => {
Some(Message::MouseMoved(position)) Some(Message::MouseMoved(position))
} }
Event::Window(_, window::Event::Resized { .. }) => { Event::Window(window::Event::Resized { .. }) => {
Some(Message::WindowResized) Some(Message::WindowResized)
} }
_ => None, _ => None,

View file

@ -9,7 +9,7 @@ use crate::MaybeSend;
/// This subscription will notify your application of any [`Event`] that was /// This subscription will notify your application of any [`Event`] that was
/// not captured by any widget. /// not captured by any widget.
pub fn listen() -> Subscription<Event> { pub fn listen() -> Subscription<Event> {
listen_with(|event, status| match status { listen_with(|event, status, _window| match status {
event::Status::Ignored => Some(event), event::Status::Ignored => Some(event),
event::Status::Captured => None, event::Status::Captured => None,
}) })
@ -24,7 +24,7 @@ pub fn listen() -> Subscription<Event> {
/// - Returns `None`, the [`Event`] will be discarded. /// - Returns `None`, the [`Event`] will be discarded.
/// - Returns `Some` message, the `Message` will be produced. /// - Returns `Some` message, the `Message` will be produced.
pub fn listen_with<Message>( pub fn listen_with<Message>(
f: fn(Event, event::Status) -> Option<Message>, f: fn(Event, event::Status, window::Id) -> Option<Message>,
) -> Subscription<Message> ) -> Subscription<Message>
where where
Message: 'static + MaybeSend, Message: 'static + MaybeSend,
@ -32,13 +32,18 @@ where
#[derive(Hash)] #[derive(Hash)]
struct EventsWith; struct EventsWith;
subscription::filter_map( subscription::filter_map((EventsWith, f), move |event| match event {
(EventsWith, f), subscription::Event::Interaction {
move |event, status| match event { event: Event::Window(window::Event::RedrawRequested(_)),
Event::Window(_, window::Event::RedrawRequested(_)) => None, ..
_ => f(event, status), }
}, | subscription::Event::PlatformSpecific(_) => None,
) subscription::Event::Interaction {
window,
event,
status,
} => f(event, status, window),
})
} }
/// Creates a [`Subscription`] that produces a message for every runtime event, /// Creates a [`Subscription`] that produces a message for every runtime event,
@ -47,7 +52,7 @@ where
/// **Warning:** This [`Subscription`], if unfiltered, may produce messages in /// **Warning:** This [`Subscription`], if unfiltered, may produce messages in
/// an infinite loop. /// an infinite loop.
pub fn listen_raw<Message>( pub fn listen_raw<Message>(
f: fn(Event, event::Status) -> Option<Message>, f: fn(Event, event::Status, window::Id) -> Option<Message>,
) -> Subscription<Message> ) -> Subscription<Message>
where where
Message: 'static + MaybeSend, Message: 'static + MaybeSend,
@ -55,5 +60,32 @@ where
#[derive(Hash)] #[derive(Hash)]
struct RawEvents; struct RawEvents;
subscription::filter_map((RawEvents, f), f) subscription::filter_map((RawEvents, f), move |event| match event {
subscription::Event::Interaction {
window,
event,
status,
} => f(event, status, window),
subscription::Event::PlatformSpecific(_) => None,
})
}
/// Creates a [`Subscription`] that notifies of custom application URL
/// received from the system.
///
/// _**Note:** Currently, it only triggers on macOS and the executable needs to be properly [bundled]!_
///
/// [bundled]: https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW19
pub fn listen_url() -> Subscription<String> {
#[derive(Hash)]
struct ListenUrl;
subscription::filter_map(ListenUrl, move |event| match event {
subscription::Event::PlatformSpecific(
subscription::PlatformSpecific::MacOS(
subscription::MacOS::ReceivedUrl(url),
),
) => Some(url),
_ => None,
})
} }

View file

@ -1,5 +1,6 @@
//! Listen to keyboard events. //! Listen to keyboard events.
use crate::core; use crate::core;
use crate::core::event;
use crate::core::keyboard::{Event, Key, Modifiers}; use crate::core::keyboard::{Event, Key, Modifiers};
use crate::subscription::{self, Subscription}; use crate::subscription::{self, Subscription};
use crate::MaybeSend; use crate::MaybeSend;
@ -18,16 +19,14 @@ where
#[derive(Hash)] #[derive(Hash)]
struct OnKeyPress; struct OnKeyPress;
subscription::filter_map((OnKeyPress, f), move |event, status| { subscription::filter_map((OnKeyPress, f), move |event| match event {
match (event, status) { subscription::Event::Interaction {
( event:
core::Event::Keyboard(Event::KeyPressed { core::Event::Keyboard(Event::KeyPressed { key, modifiers, .. }),
key, modifiers, .. status: event::Status::Ignored,
}), ..
core::event::Status::Ignored, } => f(key, modifiers),
) => f(key, modifiers), _ => None,
_ => None,
}
}) })
} }
@ -45,17 +44,13 @@ where
#[derive(Hash)] #[derive(Hash)]
struct OnKeyRelease; struct OnKeyRelease;
subscription::filter_map((OnKeyRelease, f), move |event, status| { subscription::filter_map((OnKeyRelease, f), move |event| match event {
match (event, status) { subscription::Event::Interaction {
( event:
core::Event::Keyboard(Event::KeyReleased { core::Event::Keyboard(Event::KeyReleased { key, modifiers, .. }),
key, status: event::Status::Ignored,
modifiers, ..
.. } => f(key, modifiers),
}), _ => None,
core::event::Status::Ignored,
) => f(key, modifiers),
_ => None,
}
}) })
} }

View file

@ -1,5 +1,4 @@
//! Run commands and keep track of subscriptions. //! Run commands and keep track of subscriptions.
use crate::core::event::{self, Event};
use crate::subscription; use crate::subscription;
use crate::{BoxFuture, BoxStream, Executor, MaybeSend}; use crate::{BoxFuture, BoxStream, Executor, MaybeSend};
@ -127,7 +126,7 @@ where
/// See [`Tracker::broadcast`] to learn more. /// See [`Tracker::broadcast`] to learn more.
/// ///
/// [`Tracker::broadcast`]: subscription::Tracker::broadcast /// [`Tracker::broadcast`]: subscription::Tracker::broadcast
pub fn broadcast(&mut self, event: Event, status: event::Status) { pub fn broadcast(&mut self, event: subscription::Event) {
self.subscriptions.broadcast(event, status); self.subscriptions.broadcast(event);
} }
} }

View file

@ -3,7 +3,8 @@ mod tracker;
pub use tracker::Tracker; pub use tracker::Tracker;
use crate::core::event::{self, Event}; use crate::core::event;
use crate::core::window;
use crate::futures::{Future, Stream}; use crate::futures::{Future, Stream};
use crate::{BoxStream, MaybeSend}; use crate::{BoxStream, MaybeSend};
@ -12,10 +13,48 @@ use futures::never::Never;
use std::any::TypeId; use std::any::TypeId;
use std::hash::Hash; use std::hash::Hash;
/// A subscription event.
#[derive(Debug, Clone, PartialEq)]
pub enum Event {
/// A user interacted with a user interface in a window.
Interaction {
/// The window holding the interface of the interaction.
window: window::Id,
/// The [`Event`] describing the interaction.
///
/// [`Event`]: event::Event
event: event::Event,
/// The [`event::Status`] of the interaction.
status: event::Status,
},
/// A platform specific event.
PlatformSpecific(PlatformSpecific),
}
/// A platform specific event
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PlatformSpecific {
/// A MacOS specific event
MacOS(MacOS),
}
/// Describes an event specific to MacOS
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MacOS {
/// Triggered when the app receives an URL from the system
///
/// _**Note:** For this event to be triggered, the executable needs to be properly [bundled]!_
///
/// [bundled]: https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW19
ReceivedUrl(String),
}
/// A stream of runtime events. /// A stream of runtime events.
/// ///
/// It is the input of a [`Subscription`]. /// It is the input of a [`Subscription`].
pub type EventStream = BoxStream<(Event, event::Status)>; pub type EventStream = BoxStream<Event>;
/// The hasher used for identifying subscriptions. /// The hasher used for identifying subscriptions.
pub type Hasher = rustc_hash::FxHasher; pub type Hasher = rustc_hash::FxHasher;
@ -289,7 +328,7 @@ where
pub(crate) fn filter_map<I, F, Message>(id: I, f: F) -> Subscription<Message> pub(crate) fn filter_map<I, F, Message>(id: I, f: F) -> Subscription<Message>
where where
I: Hash + 'static, I: Hash + 'static,
F: Fn(Event, event::Status) -> Option<Message> + MaybeSend + 'static, F: Fn(Event) -> Option<Message> + MaybeSend + 'static,
Message: 'static + MaybeSend, Message: 'static + MaybeSend,
{ {
Subscription::from_recipe(Runner { Subscription::from_recipe(Runner {
@ -298,9 +337,7 @@ where
use futures::future; use futures::future;
use futures::stream::StreamExt; use futures::stream::StreamExt;
events.filter_map(move |(event, status)| { events.filter_map(move |event| future::ready(f(event)))
future::ready(f(event, status))
})
}, },
}) })
} }

View file

@ -1,5 +1,4 @@
use crate::core::event::{self, Event}; use crate::subscription::{Event, Hasher, Recipe};
use crate::subscription::{Hasher, Recipe};
use crate::{BoxFuture, MaybeSend}; use crate::{BoxFuture, MaybeSend};
use futures::channel::mpsc; use futures::channel::mpsc;
@ -23,7 +22,7 @@ pub struct Tracker {
#[derive(Debug)] #[derive(Debug)]
pub struct Execution { pub struct Execution {
_cancel: futures::channel::oneshot::Sender<()>, _cancel: futures::channel::oneshot::Sender<()>,
listener: Option<futures::channel::mpsc::Sender<(Event, event::Status)>>, listener: Option<futures::channel::mpsc::Sender<Event>>,
} }
impl Tracker { impl Tracker {
@ -139,12 +138,12 @@ impl Tracker {
/// currently open. /// currently open.
/// ///
/// [`Recipe::stream`]: crate::subscription::Recipe::stream /// [`Recipe::stream`]: crate::subscription::Recipe::stream
pub fn broadcast(&mut self, event: Event, status: event::Status) { pub fn broadcast(&mut self, event: Event) {
self.subscriptions self.subscriptions
.values_mut() .values_mut()
.filter_map(|connection| connection.listener.as_mut()) .filter_map(|connection| connection.listener.as_mut())
.for_each(|listener| { .for_each(|listener| {
if let Err(error) = listener.try_send((event.clone(), status)) { if let Err(error) = listener.try_send(event.clone()) {
log::warn!( log::warn!(
"Error sending event to subscription: {error:?}" "Error sending event to subscription: {error:?}"
); );

View file

@ -28,8 +28,8 @@ use raw_window_handle::WindowHandle;
/// In any case, this [`Subscription`] is useful to smoothly draw application-driven /// In any case, this [`Subscription`] is useful to smoothly draw application-driven
/// animations without missing any frames. /// animations without missing any frames.
pub fn frames() -> Subscription<Instant> { pub fn frames() -> Subscription<Instant> {
event::listen_raw(|event, _status| match event { event::listen_raw(|event, _status, _window| match event {
crate::core::Event::Window(_, Event::RedrawRequested(at)) => Some(at), crate::core::Event::Window(Event::RedrawRequested(at)) => Some(at),
_ => None, _ => None,
}) })
} }

View file

@ -236,8 +236,10 @@ pub mod font {
pub mod event { pub mod event {
//! Handle events of a user interface. //! Handle events of a user interface.
pub use crate::core::event::{Event, MacOS, PlatformSpecific, Status}; pub use crate::core::event::{Event, Status};
pub use iced_futures::event::{listen, listen_raw, listen_with}; pub use iced_futures::event::{
listen, listen_raw, listen_url, listen_with,
};
} }
pub mod keyboard { pub mod keyboard {

View file

@ -188,9 +188,6 @@ impl Pipeline {
layer: &'a Layer, layer: &'a Layer,
range: Range<usize>, range: Range<usize>,
) { ) {
#[cfg(feature = "tracing")]
let _ = tracing::info_span!("Wgpu::Quad::Gradient", "DRAW").entered();
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
{ {
render_pass.set_pipeline(&self.pipeline); render_pass.set_pipeline(&self.pipeline);

View file

@ -144,9 +144,6 @@ impl Pipeline {
layer: &'a Layer, layer: &'a Layer,
range: Range<usize>, range: Range<usize>,
) { ) {
#[cfg(feature = "tracing")]
let _ = tracing::info_span!("Wgpu::Quad::Solid", "DRAW").entered();
render_pass.set_pipeline(&self.pipeline); render_pass.set_pipeline(&self.pipeline);
render_pass.set_bind_group(0, constants, &[]); render_pass.set_bind_group(0, constants, &[]);
render_pass.set_vertex_buffer(0, layer.instances.slice(..)); render_pass.set_vertex_buffer(0, layer.instances.slice(..));

View file

@ -172,7 +172,7 @@ where
core::Event::Keyboard(keyboard_event) => { core::Event::Keyboard(keyboard_event) => {
Some(Event::Keyboard(keyboard_event)) Some(Event::Keyboard(keyboard_event))
} }
_ => None, core::Event::Window(_) => None,
}; };
if let Some(canvas_event) = canvas_event { if let Some(canvas_event) = canvas_event {

View file

@ -1,3 +1,4 @@
#![allow(dead_code)]
use crate::core::overlay; use crate::core::overlay;
use crate::core::Element; use crate::core::Element;

View file

@ -107,10 +107,10 @@ where
Some(Event::Keyboard(keyboard_event)) Some(Event::Keyboard(keyboard_event))
} }
core::Event::Touch(touch_event) => Some(Event::Touch(touch_event)), core::Event::Touch(touch_event) => Some(Event::Touch(touch_event)),
core::Event::Window(_, window::Event::RedrawRequested(instant)) => { core::Event::Window(window::Event::RedrawRequested(instant)) => {
Some(Event::RedrawRequested(instant)) Some(Event::RedrawRequested(instant))
} }
_ => None, core::Event::Window(_) => None,
}; };
if let Some(custom_shader_event) = custom_shader_event { if let Some(custom_shader_event) = custom_shader_event {

View file

@ -1003,14 +1003,14 @@ where
state.keyboard_modifiers = modifiers; state.keyboard_modifiers = modifiers;
} }
Event::Window(_, window::Event::Unfocused) => { Event::Window(window::Event::Unfocused) => {
let state = state::<Renderer>(tree); let state = state::<Renderer>(tree);
if let Some(focus) = &mut state.is_focused { if let Some(focus) = &mut state.is_focused {
focus.is_window_focused = false; focus.is_window_focused = false;
} }
} }
Event::Window(_, window::Event::Focused) => { Event::Window(window::Event::Focused) => {
let state = state::<Renderer>(tree); let state = state::<Renderer>(tree);
if let Some(focus) = &mut state.is_focused { if let Some(focus) = &mut state.is_focused {
@ -1020,7 +1020,7 @@ where
shell.request_redraw(window::RedrawRequest::NextFrame); shell.request_redraw(window::RedrawRequest::NextFrame);
} }
} }
Event::Window(_, window::Event::RedrawRequested(now)) => { Event::Window(window::Event::RedrawRequested(now)) => {
let state = state::<Renderer>(tree); let state = state::<Renderer>(tree);
if let Some(focus) = &mut state.is_focused { if let Some(focus) = &mut state.is_focused {

View file

@ -12,7 +12,8 @@ use crate::core::widget::operation;
use crate::core::window; use crate::core::window;
use crate::core::{Color, Event, Point, Size, Theme}; use crate::core::{Color, Event, Point, Size, Theme};
use crate::futures::futures; use crate::futures::futures;
use crate::futures::{Executor, Runtime, Subscription}; use crate::futures::subscription::{self, Subscription};
use crate::futures::{Executor, Runtime};
use crate::graphics; use crate::graphics;
use crate::graphics::compositor::{self, Compositor}; use crate::graphics::compositor::{self, Compositor};
use crate::runtime::clipboard; use crate::runtime::clipboard;
@ -574,12 +575,10 @@ async fn run_instance<A, E, C>(
event::Event::PlatformSpecific(event::PlatformSpecific::MacOS( event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(
event::MacOS::ReceivedUrl(url), event::MacOS::ReceivedUrl(url),
)) => { )) => {
use crate::core::event; runtime.broadcast(subscription::Event::PlatformSpecific(
subscription::PlatformSpecific::MacOS(
events.push(Event::PlatformSpecific( subscription::MacOS::ReceivedUrl(url),
event::PlatformSpecific::MacOS(event::MacOS::ReceivedUrl( ),
url,
)),
)); ));
} }
event::Event::UserEvent(message) => { event::Event::UserEvent(message) => {
@ -623,7 +622,6 @@ async fn run_instance<A, E, C>(
// Then, we can use the `interface_state` here to decide if a redraw // Then, we can use the `interface_state` here to decide if a redraw
// is needed right away, or simply wait until a specific time. // is needed right away, or simply wait until a specific time.
let redraw_event = Event::Window( let redraw_event = Event::Window(
window::Id::MAIN,
window::Event::RedrawRequested(Instant::now()), window::Event::RedrawRequested(Instant::now()),
); );
@ -651,7 +649,11 @@ async fn run_instance<A, E, C>(
_ => ControlFlow::Wait, _ => ControlFlow::Wait,
}); });
runtime.broadcast(redraw_event, core::event::Status::Ignored); runtime.broadcast(subscription::Event::Interaction {
window: window::Id::MAIN,
event: redraw_event,
status: core::event::Status::Ignored,
});
debug.draw_started(); debug.draw_started();
let new_mouse_interaction = user_interface.draw( let new_mouse_interaction = user_interface.draw(
@ -714,7 +716,6 @@ async fn run_instance<A, E, C>(
state.update(&window, &window_event, &mut debug); state.update(&window, &window_event, &mut debug);
if let Some(event) = conversion::window_event( if let Some(event) = conversion::window_event(
window::Id::MAIN,
window_event, window_event,
state.scale_factor(), state.scale_factor(),
state.modifiers(), state.modifiers(),
@ -742,7 +743,11 @@ async fn run_instance<A, E, C>(
for (event, status) in for (event, status) in
events.drain(..).zip(statuses.into_iter()) events.drain(..).zip(statuses.into_iter())
{ {
runtime.broadcast(event, status); runtime.broadcast(subscription::Event::Interaction {
window: window::Id::MAIN,
event,
status,
});
} }
if !messages.is_empty() if !messages.is_empty()

View file

@ -126,7 +126,6 @@ pub fn window_attributes(
/// Converts a winit window event into an iced event. /// Converts a winit window event into an iced event.
pub fn window_event( pub fn window_event(
id: window::Id,
event: winit::event::WindowEvent, event: winit::event::WindowEvent,
scale_factor: f64, scale_factor: f64,
modifiers: winit::keyboard::ModifiersState, modifiers: winit::keyboard::ModifiersState,
@ -137,16 +136,13 @@ pub fn window_event(
WindowEvent::Resized(new_size) => { WindowEvent::Resized(new_size) => {
let logical_size = new_size.to_logical(scale_factor); let logical_size = new_size.to_logical(scale_factor);
Some(Event::Window( Some(Event::Window(window::Event::Resized {
id, width: logical_size.width,
window::Event::Resized { height: logical_size.height,
width: logical_size.width, }))
height: logical_size.height,
},
))
} }
WindowEvent::CloseRequested => { WindowEvent::CloseRequested => {
Some(Event::Window(id, window::Event::CloseRequested)) Some(Event::Window(window::Event::CloseRequested))
} }
WindowEvent::CursorMoved { position, .. } => { WindowEvent::CursorMoved { position, .. } => {
let position = position.to_logical::<f64>(scale_factor); let position = position.to_logical::<f64>(scale_factor);
@ -264,22 +260,19 @@ pub fn window_event(
self::modifiers(new_modifiers.state()), self::modifiers(new_modifiers.state()),
))) )))
} }
WindowEvent::Focused(focused) => Some(Event::Window( WindowEvent::Focused(focused) => Some(Event::Window(if focused {
id, window::Event::Focused
if focused { } else {
window::Event::Focused window::Event::Unfocused
} else { })),
window::Event::Unfocused
},
)),
WindowEvent::HoveredFile(path) => { WindowEvent::HoveredFile(path) => {
Some(Event::Window(id, window::Event::FileHovered(path.clone()))) Some(Event::Window(window::Event::FileHovered(path.clone())))
} }
WindowEvent::DroppedFile(path) => { WindowEvent::DroppedFile(path) => {
Some(Event::Window(id, window::Event::FileDropped(path.clone()))) Some(Event::Window(window::Event::FileDropped(path.clone())))
} }
WindowEvent::HoveredFileCancelled => { WindowEvent::HoveredFileCancelled => {
Some(Event::Window(id, window::Event::FilesHoveredLeft)) Some(Event::Window(window::Event::FilesHoveredLeft))
} }
WindowEvent::Touch(touch) => { WindowEvent::Touch(touch) => {
Some(Event::Touch(touch_event(touch, scale_factor))) Some(Event::Touch(touch_event(touch, scale_factor)))
@ -288,7 +281,7 @@ pub fn window_event(
let winit::dpi::LogicalPosition { x, y } = let winit::dpi::LogicalPosition { x, y } =
position.to_logical(scale_factor); position.to_logical(scale_factor);
Some(Event::Window(id, window::Event::Moved { x, y })) Some(Event::Window(window::Event::Moved { x, y }))
} }
_ => None, _ => None,
} }

View file

@ -16,7 +16,8 @@ use crate::futures::futures::channel::oneshot;
use crate::futures::futures::executor; use crate::futures::futures::executor;
use crate::futures::futures::task; use crate::futures::futures::task;
use crate::futures::futures::{Future, StreamExt}; use crate::futures::futures::{Future, StreamExt};
use crate::futures::{Executor, Runtime, Subscription}; use crate::futures::subscription::{self, Subscription};
use crate::futures::{Executor, Runtime};
use crate::graphics; use crate::graphics;
use crate::graphics::{compositor, Compositor}; use crate::graphics::{compositor, Compositor};
use crate::multi_window::window_manager::WindowManager; use crate::multi_window::window_manager::WindowManager;
@ -491,14 +492,11 @@ async fn run_instance<A, E, C>(
let mut clipboard = Clipboard::connect(&main_window.raw); let mut clipboard = Clipboard::connect(&main_window.raw);
let mut events = { let mut events = {
vec![( vec![(
Some(window::Id::MAIN), window::Id::MAIN,
core::Event::Window( core::Event::Window(window::Event::Opened {
window::Id::MAIN, position: main_window.position(),
window::Event::Opened { size: main_window.size(),
position: main_window.position(), }),
size: main_window.size(),
},
),
)] )]
}; };
@ -564,14 +562,11 @@ async fn run_instance<A, E, C>(
let _ = ui_caches.insert(id, user_interface::Cache::default()); let _ = ui_caches.insert(id, user_interface::Cache::default());
events.push(( events.push((
Some(id), id,
core::Event::Window( core::Event::Window(window::Event::Opened {
id, position: window.position(),
window::Event::Opened { size: window.size(),
position: window.position(), }),
size: window.size(),
},
),
)); ));
} }
Event::EventLoopAwakened(event) => { Event::EventLoopAwakened(event) => {
@ -591,16 +586,13 @@ async fn run_instance<A, E, C>(
event::MacOS::ReceivedUrl(url), event::MacOS::ReceivedUrl(url),
), ),
) => { ) => {
use crate::core::event; runtime.broadcast(
subscription::Event::PlatformSpecific(
events.push(( subscription::PlatformSpecific::MacOS(
None, subscription::MacOS::ReceivedUrl(url),
event::Event::PlatformSpecific(
event::PlatformSpecific::MacOS(
event::MacOS::ReceivedUrl(url),
), ),
), ),
)); );
} }
event::Event::UserEvent(message) => { event::Event::UserEvent(message) => {
messages.push(message); messages.push(message);
@ -623,7 +615,6 @@ async fn run_instance<A, E, C>(
// Then, we can use the `interface_state` here to decide if a redraw // Then, we can use the `interface_state` here to decide if a redraw
// is needed right away, or simply wait until a specific time. // is needed right away, or simply wait until a specific time.
let redraw_event = core::Event::Window( let redraw_event = core::Event::Window(
id,
window::Event::RedrawRequested(Instant::now()), window::Event::RedrawRequested(Instant::now()),
); );
@ -662,10 +653,11 @@ async fn run_instance<A, E, C>(
window.mouse_interaction = new_mouse_interaction; window.mouse_interaction = new_mouse_interaction;
} }
runtime.broadcast( runtime.broadcast(subscription::Event::Interaction {
redraw_event.clone(), window: id,
core::event::Status::Ignored, event: redraw_event,
); status: core::event::Status::Ignored,
});
let _ = control_sender.start_send(Control::ChangeFlow( let _ = control_sender.start_send(Control::ChangeFlow(
match ui_state { match ui_state {
@ -801,8 +793,8 @@ async fn run_instance<A, E, C>(
let _ = ui_caches.remove(&id); let _ = ui_caches.remove(&id);
events.push(( events.push((
None, id,
core::Event::Window(id, window::Event::Closed), core::Event::Window(window::Event::Closed),
)); ));
if window_manager.is_empty() { if window_manager.is_empty() {
@ -816,12 +808,11 @@ async fn run_instance<A, E, C>(
); );
if let Some(event) = conversion::window_event( if let Some(event) = conversion::window_event(
id,
window_event, window_event,
window.state.scale_factor(), window.state.scale_factor(),
window.state.modifiers(), window.state.modifiers(),
) { ) {
events.push((Some(id), event)); events.push((id, event));
} }
} }
} }
@ -837,8 +828,7 @@ async fn run_instance<A, E, C>(
let mut window_events = vec![]; let mut window_events = vec![];
events.retain(|(window_id, event)| { events.retain(|(window_id, event)| {
if *window_id == Some(id) || window_id.is_none() if *window_id == id {
{
window_events.push(event.clone()); window_events.push(event.clone());
false false
} else { } else {
@ -874,10 +864,26 @@ async fn run_instance<A, E, C>(
.into_iter() .into_iter()
.zip(statuses.into_iter()) .zip(statuses.into_iter())
{ {
runtime.broadcast(event, status); runtime.broadcast(
subscription::Event::Interaction {
window: id,
event,
status,
},
);
} }
} }
for (id, event) in events.drain(..) {
runtime.broadcast(
subscription::Event::Interaction {
window: id,
event,
status: core::event::Status::Ignored,
},
);
}
debug.event_processing_finished(); debug.event_processing_finished();
// TODO mw application update returns which window IDs to update // TODO mw application update returns which window IDs to update
@ -1272,25 +1278,20 @@ fn run_command<A, C, E>(
std::mem::take(ui_caches), std::mem::take(ui_caches),
); );
'operate: while let Some(mut operation) = while let Some(mut operation) = current_operation.take() {
current_operation.take()
{
for (id, ui) in uis.iter_mut() { for (id, ui) in uis.iter_mut() {
if let Some(window) = window_manager.get_mut(*id) { if let Some(window) = window_manager.get_mut(*id) {
ui.operate(&window.renderer, operation.as_mut()); ui.operate(&window.renderer, operation.as_mut());
}
}
match operation.finish() { match operation.finish() {
operation::Outcome::None => {} operation::Outcome::None => {}
operation::Outcome::Some(message) => { operation::Outcome::Some(message) => {
proxy.send(message); proxy.send(message);
}
// operation completed, don't need to try to operate on rest of UIs operation::Outcome::Chain(next) => {
break 'operate; current_operation = Some(next);
}
operation::Outcome::Chain(next) => {
current_operation = Some(next);
}
}
} }
} }
} }