iced_winit/
program.rs

1//! Create interactive, native cross-platform applications for WGPU.
2#[path = "application/drag_resize.rs"]
3mod drag_resize;
4mod state;
5pub(crate) mod window_manager;
6
7use iced_futures::core::window::Id;
8pub use runtime::{default, Appearance, DefaultStyle};
9use window_manager::ViewFn;
10use winit::dpi::PhysicalSize;
11use winit::event::WindowEvent;
12use winit::event_loop::OwnedDisplayHandle;
13#[cfg(feature = "wayland")]
14use winit::platform::wayland::WindowExtWayland;
15
16use crate::conversion;
17use crate::core;
18use crate::core::mouse;
19use crate::core::renderer;
20use crate::core::time::Instant;
21use crate::core::widget::operation;
22use crate::core::widget::Operation;
23use crate::core::window;
24use crate::core::Clipboard as CoreClipboard;
25use crate::core::Length;
26use crate::core::{Element, Point, Size};
27use crate::futures::futures::channel::mpsc;
28use crate::futures::futures::channel::oneshot;
29use crate::futures::futures::task;
30use crate::futures::futures::{Future, StreamExt};
31use crate::futures::subscription::{self, Subscription};
32use crate::futures::{Executor, Runtime};
33use crate::graphics;
34use crate::graphics::{compositor, Compositor};
35use crate::platform_specific;
36use crate::runtime::user_interface::{self, UserInterface};
37use crate::runtime::Debug;
38use crate::runtime::{self, Action, Task};
39use crate::{Clipboard, Error, Proxy, Settings};
40use dnd::DndSurface;
41use dnd::Icon;
42use iced_futures::core::widget::operation::search_id;
43use iced_graphics::Viewport;
44pub use state::State;
45use window_clipboard::mime::ClipboardStoreData;
46use winit::raw_window_handle::HasWindowHandle;
47
48pub(crate) use window_manager::WindowManager;
49
50use rustc_hash::FxHashMap;
51use std::any::Any;
52use std::borrow::Cow;
53use std::collections::HashMap;
54use std::mem::ManuallyDrop;
55use std::sync::Arc;
56use std::sync::Mutex;
57use std::time::Duration;
58
59/// An interactive, native, cross-platform, multi-windowed application.
60///
61/// This trait is the main entrypoint of multi-window Iced. Once implemented, you can run
62/// your GUI application by simply calling [`run`]. It will run in
63/// its own window.
64///
65/// A [`Program`] can execute asynchronous actions by returning a
66/// [`Task`] in some of its methods.
67///
68/// When using a [`Program`] with the `debug` feature enabled, a debug view
69/// can be toggled by pressing `F12`.
70pub trait Program
71where
72    Self: Sized,
73    Self::Theme: DefaultStyle,
74{
75    /// The type of __messages__ your [`Program`] will produce.
76    type Message: std::fmt::Debug + Send;
77
78    /// The theme used to draw the [`Program`].
79    type Theme;
80
81    /// The [`Executor`] that will run commands and subscriptions.
82    ///
83    /// The [default executor] can be a good starting point!
84    ///
85    /// [`Executor`]: Self::Executor
86    /// [default executor]: crate::futures::backend::default::Executor
87    type Executor: Executor;
88
89    /// The graphics backend to use to draw the [`Program`].
90    type Renderer: core::Renderer + core::text::Renderer;
91
92    /// The data needed to initialize your [`Program`].
93    type Flags;
94
95    /// Initializes the [`Program`] with the flags provided to
96    /// [`run`] as part of the [`Settings`].
97    ///
98    /// Here is where you should return the initial state of your app.
99    ///
100    /// Additionally, you can return a [`Task`] if you need to perform some
101    /// async action in the background on startup. This is useful if you want to
102    /// load state from a file, perform an initial HTTP request, etc.
103    fn new(flags: Self::Flags) -> (Self, Task<Self::Message>);
104
105    /// Returns the current title of the [`Program`].
106    ///
107    /// This title can be dynamic! The runtime will automatically update the
108    /// title of your application when necessary.
109    fn title(&self, window: window::Id) -> String;
110
111    /// Handles a __message__ and updates the state of the [`Program`].
112    ///
113    /// This is where you define your __update logic__. All the __messages__,
114    /// produced by either user interactions or commands, will be handled by
115    /// this method.
116    ///
117    /// Any [`Task`] returned will be executed immediately in the background by the
118    /// runtime.
119    fn update(&mut self, message: Self::Message) -> Task<Self::Message>;
120
121    /// Returns the widgets to display in the [`Program`] for the `window`.
122    ///
123    /// These widgets can produce __messages__ based on user interaction.
124    fn view(
125        &self,
126        window: window::Id,
127    ) -> Element<'_, Self::Message, Self::Theme, Self::Renderer>;
128
129    /// Returns the current `Theme` of the [`Program`].
130    fn theme(&self, window: window::Id) -> Self::Theme;
131
132    /// Returns the `Style` variation of the `Theme`.
133    fn style(&self, theme: &Self::Theme) -> Appearance {
134        theme.default_style()
135    }
136
137    /// Returns the event `Subscription` for the current state of the
138    /// application.
139    ///
140    /// The messages produced by the `Subscription` will be handled by
141    /// [`update`](#tymethod.update).
142    ///
143    /// A `Subscription` will be kept alive as long as you keep returning it!
144    ///
145    /// By default, it returns an empty subscription.
146    fn subscription(&self) -> Subscription<Self::Message> {
147        Subscription::none()
148    }
149
150    /// Returns the scale factor of the window of the [`Program`].
151    ///
152    /// It can be used to dynamically control the size of the UI at runtime
153    /// (i.e. zooming).
154    ///
155    /// For instance, a scale factor of `2.0` will make widgets twice as big,
156    /// while a scale factor of `0.5` will shrink them to half their size.
157    ///
158    /// By default, it returns `1.0`.
159    #[allow(unused_variables)]
160    fn scale_factor(&self, window: window::Id) -> f64 {
161        1.0
162    }
163
164    fn with_program<T>(&self, f: impl Fn(&Self) -> T) -> T {
165        f(self)
166    }
167}
168
169/// Runs a [`Program`] with an executor, compositor, and the provided
170/// settings.
171pub fn run<P, C>(
172    settings: Settings,
173    graphics_settings: graphics::Settings,
174    window_settings: Option<window::Settings>,
175    flags: P::Flags,
176) -> Result<(), Error>
177where
178    P: Program + 'static,
179    C: Compositor<Renderer = P::Renderer> + 'static,
180    P::Theme: DefaultStyle,
181{
182    use winit::event_loop::EventLoop;
183
184    let mut debug = Debug::new();
185    debug.startup_started();
186
187    let event_loop = EventLoop::new().expect("Create event loop");
188    #[cfg(feature = "wayland")]
189    let is_wayland =
190        winit::platform::wayland::EventLoopExtWayland::is_wayland(&event_loop);
191    #[cfg(not(feature = "wayland"))]
192    let is_wayland = false;
193
194    let (event_sender, event_receiver) = mpsc::unbounded();
195    let (proxy, worker): (Proxy<<P as Program>::Message>, _) =
196        Proxy::new(event_loop.create_proxy(), event_sender.clone());
197
198    let mut runtime = {
199        let executor =
200            P::Executor::new().map_err(Error::ExecutorCreationFailed)?;
201        executor.spawn(worker);
202
203        Runtime::new(executor, proxy.clone())
204    };
205
206    let (program, task) = runtime.enter(|| P::new(flags));
207    let is_daemon = window_settings.is_none() || settings.is_daemon;
208
209    let task = if let Some(window_settings) = window_settings {
210        let mut task = Some(task);
211
212        let open = iced_runtime::task::oneshot(|channel| {
213            iced_runtime::Action::Window(iced_runtime::window::Action::Open(
214                iced_runtime::core::window::Id::RESERVED,
215                window_settings,
216                channel,
217            ))
218        });
219
220        open.then(move |_| task.take().unwrap_or(Task::none()))
221    } else {
222        task
223    };
224
225    if let Some(stream) = runtime::task::into_stream(task) {
226        runtime.run(stream);
227    }
228
229    runtime.track(subscription::into_recipes(
230        runtime.enter(|| program.subscription().map(Action::Output)),
231    ));
232
233    let (boot_sender, boot_receiver) = oneshot::channel();
234    let (control_sender, control_receiver) = mpsc::unbounded();
235
236    let instance = Box::pin(run_instance::<P, C>(
237        program,
238        runtime,
239        proxy.clone(),
240        debug,
241        boot_receiver,
242        event_receiver,
243        control_sender.clone(),
244        event_loop.owned_display_handle(),
245        is_daemon,
246    ));
247
248    let context = task::Context::from_waker(task::noop_waker_ref());
249
250    struct Runner<Message: 'static, F, C> {
251        instance: std::pin::Pin<Box<F>>,
252        context: task::Context<'static>,
253        id: Option<String>,
254        boot: Option<BootConfig<C>>,
255        sender: mpsc::UnboundedSender<Event<Message>>,
256        receiver: mpsc::UnboundedReceiver<Control>,
257        error: Option<Error>,
258        proxy: Proxy<Message>,
259
260        #[cfg(target_arch = "wasm32")]
261        is_booted: std::rc::Rc<std::cell::RefCell<bool>>,
262        #[cfg(target_arch = "wasm32")]
263        canvas: Option<web_sys::HtmlCanvasElement>,
264    }
265
266    struct BootConfig<C> {
267        sender: oneshot::Sender<Boot<C>>,
268        fonts: Vec<Cow<'static, [u8]>>,
269        graphics_settings: graphics::Settings,
270        control_sender: mpsc::UnboundedSender<Control>,
271        is_wayland: bool,
272    }
273
274    let runner = Runner {
275        instance,
276        context,
277        id: settings.id,
278        boot: Some(BootConfig {
279            sender: boot_sender,
280            fonts: settings.fonts,
281            graphics_settings,
282            control_sender,
283            is_wayland,
284        }),
285        sender: event_sender,
286        receiver: control_receiver,
287        error: None,
288        proxy: proxy.clone(),
289
290        #[cfg(target_arch = "wasm32")]
291        is_booted: std::rc::Rc::new(std::cell::RefCell::new(false)),
292        #[cfg(target_arch = "wasm32")]
293        canvas: None,
294    };
295
296    impl<Message, F, C> winit::application::ApplicationHandler
297        for Runner<Message, F, C>
298    where
299        Message: std::fmt::Debug,
300        F: Future<Output = ()>,
301        C: Compositor + 'static,
302    {
303        fn proxy_wake_up(
304            &mut self,
305            event_loop: &dyn winit::event_loop::ActiveEventLoop,
306        ) {
307            self.process_event(event_loop, None);
308        }
309
310        fn new_events(
311            &mut self,
312            event_loop: &dyn winit::event_loop::ActiveEventLoop,
313            cause: winit::event::StartCause,
314        ) {
315            if self.boot.is_some() {
316                return;
317            }
318            self.process_event(event_loop, Some(Event::NewEvents(cause)));
319        }
320
321        fn window_event(
322            &mut self,
323            event_loop: &dyn winit::event_loop::ActiveEventLoop,
324            window_id: winit::window::WindowId,
325            event: winit::event::WindowEvent,
326        ) {
327            #[cfg(target_os = "windows")]
328            let is_move_or_resize = matches!(
329                event,
330                winit::event::WindowEvent::SurfaceResized(_)
331                    | winit::event::WindowEvent::Moved(_)
332            );
333
334            #[cfg(feature = "wayland")]
335            {
336                if matches!(event, WindowEvent::RedrawRequested) {
337                    for id in
338                        crate::subsurface_widget::subsurface_ids(window_id)
339                    {
340                        _ = self.sender.start_send(Event::Winit(
341                            id,
342                            WindowEvent::RedrawRequested,
343                        ));
344                    }
345                } else if matches!(event, WindowEvent::RedrawRequested) {
346                    for id in
347                        crate::subsurface_widget::subsurface_ids(window_id)
348                    {
349                        _ = self.sender.start_send(Event::Winit(
350                            id,
351                            WindowEvent::CloseRequested,
352                        ));
353                    }
354                }
355            }
356
357            self.process_event(
358                event_loop,
359                Some(Event::Winit(window_id, event)),
360            );
361
362            // TODO: Remove when unnecessary
363            // On Windows, we emulate an `AboutToWait` event after every `Resized` event
364            // since the event loop does not resume during resize interaction.
365            // More details: https://github.com/rust-windowing/winit/issues/3272
366            #[cfg(target_os = "windows")]
367            {
368                if is_move_or_resize {
369                    self.process_event(event_loop, Some(Event::AboutToWait));
370                }
371            }
372        }
373
374        fn about_to_wait(
375            &mut self,
376            event_loop: &dyn winit::event_loop::ActiveEventLoop,
377        ) {
378            self.process_event(event_loop, Some(Event::AboutToWait));
379        }
380
381        fn can_create_surfaces(
382            &mut self,
383            event_loop: &dyn winit::event_loop::ActiveEventLoop,
384        ) {
385            // create initial window
386            let Some(BootConfig {
387                sender,
388                fonts,
389                graphics_settings,
390                control_sender,
391                is_wayland,
392            }) = self.boot.take()
393            else {
394                return;
395            };
396
397            let window: Arc<dyn winit::window::Window> = match event_loop
398                .create_window(
399                    winit::window::WindowAttributes::default()
400                        .with_visible(false),
401                ) {
402                Ok(window) => Arc::from(window),
403                Err(error) => {
404                    self.error = Some(Error::WindowCreationFailed(error));
405                    event_loop.exit();
406                    return;
407                }
408            };
409
410            #[cfg(target_arch = "wasm32")]
411            {
412                use winit::platform::web::WindowExtWebSys;
413                self.canvas = window.canvas();
414            }
415
416            let proxy = self.proxy.raw.clone();
417            let finish_boot = async move {
418                let mut compositor =
419                    C::new(graphics_settings, window.clone()).await?;
420
421                for font in fonts {
422                    compositor.load_font(font);
423                }
424
425                sender
426                    .send(Boot {
427                        compositor,
428                        is_wayland,
429                        clipboard: Clipboard::connect(
430                            window,
431                            crate::clipboard::ControlSender {
432                                sender: control_sender,
433                                proxy,
434                            },
435                        ),
436                    })
437                    .ok()
438                    .expect("Send boot event");
439
440                Ok::<_, graphics::Error>(())
441            };
442
443            #[cfg(not(target_arch = "wasm32"))]
444            if let Err(error) =
445                crate::futures::futures::executor::block_on(finish_boot)
446            {
447                self.error = Some(Error::GraphicsCreationFailed(error));
448                event_loop.exit();
449            }
450
451            #[cfg(target_arch = "wasm32")]
452            {
453                let is_booted = self.is_booted.clone();
454
455                wasm_bindgen_futures::spawn_local(async move {
456                    finish_boot.await.expect("Finish boot!");
457
458                    *is_booted.borrow_mut() = true;
459                });
460
461                event_loop
462                    .set_control_flow(winit::event_loop::ControlFlow::Poll);
463            }
464        }
465    }
466
467    impl<Message, F, C> Runner<Message, F, C>
468    where
469        F: Future<Output = ()>,
470        C: Compositor,
471    {
472        fn process_event(
473            &mut self,
474            event_loop: &dyn winit::event_loop::ActiveEventLoop,
475            event: Option<Event<Message>>,
476        ) {
477            if event_loop.exiting() {
478                return;
479            }
480
481            if let Some(event) = event {
482                self.sender.start_send(event).expect("Send event");
483            }
484
485            loop {
486                let poll = self.instance.as_mut().poll(&mut self.context);
487
488                match poll {
489                    task::Poll::Pending => match self.receiver.try_next() {
490                        Ok(Some(control)) => match control {
491                            Control::ChangeFlow(flow) => {
492                                use winit::event_loop::ControlFlow;
493
494                                match (event_loop.control_flow(), flow) {
495                                    (
496                                        ControlFlow::WaitUntil(current),
497                                        ControlFlow::WaitUntil(new),
498                                    ) if new < current => {}
499                                    (
500                                        ControlFlow::WaitUntil(target),
501                                        ControlFlow::Wait,
502                                    ) if target > Instant::now() => {}
503                                    _ => {
504                                        event_loop.set_control_flow(flow);
505                                    }
506                                }
507                            }
508                            Control::CreateWindow {
509                                id,
510                                settings,
511                                title,
512                                monitor,
513                                on_open,
514                            } => {
515                                let exit_on_close_request =
516                                    settings.exit_on_close_request;
517                                let resize_border = settings.resize_border;
518
519                                let visible = settings.visible;
520
521                                #[cfg(target_arch = "wasm32")]
522                                let target =
523                                    settings.platform_specific.target.clone();
524
525                                let window_attributes =
526                                    conversion::window_attributes(
527                                        settings,
528                                        &title,
529                                        monitor
530                                            .or(event_loop.primary_monitor()),
531                                        self.id.clone(),
532                                    )
533                                    .with_visible(false);
534
535                                #[cfg(target_arch = "wasm32")]
536                                let window_attributes = {
537                                    use winit::platform::web::WindowAttributesExtWebSys;
538                                    window_attributes
539                                        .with_canvas(self.canvas.take())
540                                };
541
542                                log::info!("Window attributes for id `{id:#?}`: {window_attributes:#?}");
543
544                                let window = Arc::from(
545                                    event_loop
546                                        .create_window(window_attributes)
547                                        .expect("Create window"),
548                                );
549
550                                #[cfg(target_arch = "wasm32")]
551                                {
552                                    use winit::platform::web::WindowExtWebSys;
553
554                                    let canvas = window
555                                        .canvas()
556                                        .expect("Get window canvas");
557
558                                    let _ = canvas.set_attribute(
559                                        "style",
560                                        "display: block; width: 100%; height: 100%",
561                                    );
562
563                                    let window = web_sys::window().unwrap();
564                                    let document = window.document().unwrap();
565                                    let body = document.body().unwrap();
566
567                                    let target = target.and_then(|target| {
568                                        body.query_selector(&format!(
569                                            "#{target}"
570                                        ))
571                                        .ok()
572                                        .unwrap_or(None)
573                                    });
574
575                                    match target {
576                                        Some(node) => {
577                                            let _ = node
578                                                .replace_with_with_node_1(
579                                                    &canvas,
580                                                )
581                                                .expect(&format!(
582                                                    "Could not replace #{}",
583                                                    node.id()
584                                                ));
585                                        }
586                                        None => {
587                                            let _ = body
588                                                .append_child(&canvas)
589                                                .expect(
590                                                "Append canvas to HTML body",
591                                            );
592                                        }
593                                    };
594                                }
595
596                                self.process_event(
597                                    event_loop,
598                                    Some(Event::WindowCreated {
599                                        id,
600                                        window,
601                                        exit_on_close_request,
602                                        make_visible: visible,
603                                        on_open,
604                                        resize_border,
605                                    }),
606                                );
607                            }
608                            Control::Exit => {
609                                event_loop.exit();
610                            }
611                            Control::Dnd(e) => {
612                                self.sender.start_send(Event::Dnd(e)).unwrap();
613                            }
614                            #[cfg(feature = "a11y")]
615                            Control::Accessibility(id, event) => {
616                                self.process_event(
617                                    event_loop,
618                                    Some(Event::Accessibility(id, event)),
619                                );
620                            }
621                            #[cfg(feature = "a11y")]
622                            Control::AccessibilityEnabled(event) => {
623                                self.process_event(
624                                    event_loop,
625                                    Some(Event::AccessibilityEnabled(event)),
626                                );
627                            }
628                            Control::PlatformSpecific(e) => {
629                                self.sender
630                                    .start_send(Event::PlatformSpecific(e))
631                                    .unwrap();
632                            }
633                            Control::AboutToWait => {
634                                self.sender
635                                    .start_send(Event::AboutToWait)
636                                    .expect("Send event");
637                            }
638                            Control::Winit(id, e) => {
639                                #[cfg(feature = "wayland")]
640                                {
641                                    if matches!(e, WindowEvent::RedrawRequested)
642                                    {
643                                        for id in crate::subsurface_widget::subsurface_ids(id) {
644                                            _ = self.sender
645                                                .start_send(Event::Winit(
646                                                id,
647                                                WindowEvent::RedrawRequested,
648                                            ));
649                                        }
650                                    } else if matches!(
651                                        e,
652                                        WindowEvent::RedrawRequested
653                                    ) {
654                                        for id in crate::subsurface_widget::subsurface_ids(id) {
655                                            _ = self.sender
656                                                .start_send(Event::Winit(
657                                                id,
658                                                WindowEvent::CloseRequested,
659                                            ));
660                                        }
661                                    }
662                                }
663                                self.sender
664                                    .start_send(Event::Winit(id, e))
665                                    .expect("Send event");
666                            }
667                            Control::StartDnd => {
668                                self.sender
669                                    .start_send(Event::StartDnd)
670                                    .expect("Send event");
671                            }
672                        },
673                        _ => {
674                            break;
675                        }
676                    },
677                    task::Poll::Ready(_) => {
678                        event_loop.exit();
679                        break;
680                    }
681                };
682            }
683        }
684    }
685
686    #[cfg(not(target_arch = "wasm32"))]
687    {
688        let mut runner = runner;
689        let _ = event_loop.run_app(&mut runner);
690
691        runner.error.map(Err).unwrap_or(Ok(()))
692    }
693
694    #[cfg(target_arch = "wasm32")]
695    {
696        use winit::platform::web::EventLoopExtWebSys;
697        let _ = event_loop.spawn_app(runner);
698
699        Ok(())
700    }
701}
702
703struct Boot<C> {
704    compositor: C,
705    is_wayland: bool,
706    clipboard: Clipboard,
707}
708
709pub(crate) enum Event<Message: 'static> {
710    WindowCreated {
711        id: window::Id,
712        window: Arc<dyn winit::window::Window>,
713        exit_on_close_request: bool,
714        make_visible: bool,
715        on_open: oneshot::Sender<window::Id>,
716        resize_border: u32,
717    },
718    Dnd(dnd::DndEvent<dnd::DndSurface>),
719    #[cfg(feature = "a11y")]
720    Accessibility(window::Id, iced_accessibility::accesskit::ActionRequest),
721    #[cfg(feature = "a11y")]
722    AccessibilityEnabled(bool),
723    Winit(winit::window::WindowId, winit::event::WindowEvent),
724    AboutToWait,
725    UserEvent(Action<Message>),
726    NewEvents(winit::event::StartCause),
727    PlatformSpecific(crate::platform_specific::Event),
728    StartDnd,
729}
730
731pub(crate) enum Control {
732    ChangeFlow(winit::event_loop::ControlFlow),
733    Exit,
734    CreateWindow {
735        id: window::Id,
736        settings: window::Settings,
737        title: String,
738        monitor: Option<winit::monitor::MonitorHandle>,
739        on_open: oneshot::Sender<window::Id>,
740    },
741    Dnd(dnd::DndEvent<dnd::DndSurface>),
742    #[cfg(feature = "a11y")]
743    Accessibility(window::Id, iced_accessibility::accesskit::ActionRequest),
744    #[cfg(feature = "a11y")]
745    AccessibilityEnabled(bool),
746    PlatformSpecific(crate::platform_specific::Event),
747    AboutToWait,
748    Winit(winit::window::WindowId, winit::event::WindowEvent),
749    StartDnd,
750}
751
752async fn run_instance<'a, P, C>(
753    mut program: P,
754    mut runtime: Runtime<P::Executor, Proxy<P::Message>, Action<P::Message>>,
755    mut proxy: Proxy<P::Message>,
756    mut debug: Debug,
757    boot: oneshot::Receiver<Boot<C>>,
758    mut event_receiver: mpsc::UnboundedReceiver<Event<P::Message>>,
759    mut control_sender: mpsc::UnboundedSender<Control>,
760    display_handle: OwnedDisplayHandle,
761    is_daemon: bool,
762) where
763    P: Program + 'static,
764    C: Compositor<Renderer = P::Renderer> + 'static,
765    P::Theme: DefaultStyle,
766{
767    use winit::event;
768    use winit::event_loop::ControlFlow;
769
770    let Boot {
771        mut compositor,
772        is_wayland,
773        mut clipboard,
774    } = boot.await.expect("Receive boot");
775
776    let mut platform_specific_handler =
777        crate::platform_specific::PlatformSpecific::default();
778    #[cfg(all(feature = "wayland", target_os = "linux"))]
779    if is_wayland {
780        platform_specific_handler = platform_specific_handler.with_wayland(
781            control_sender.clone(),
782            proxy.raw.clone(),
783            display_handle,
784        );
785    }
786
787    let mut window_manager = WindowManager::new();
788    let mut is_window_opening = !is_daemon;
789
790    let mut events = Vec::new();
791    let mut messages = Vec::new();
792    let mut actions = 0;
793
794    #[cfg(feature = "a11y")]
795    let (mut adapters, mut a11y_enabled) = if let Some((main_id, title, raw)) =
796        window_manager.ids().next().and_then(|id| {
797            window_manager
798                .get(id)
799                .map(|w| (id, w.state.title.clone(), w.raw.clone()))
800        }) {
801        let node_id = core::id::window_node_id();
802        use crate::a11y::*;
803        use iced_accessibility::accesskit::{
804            ActivationHandler, NodeBuilder, NodeId, Role, Tree, TreeUpdate,
805        };
806        use iced_accessibility::accesskit_winit::Adapter;
807
808        let activation_handler = WinitActivationHandler {
809            proxy: control_sender.clone(),
810            title: title.clone(),
811        };
812
813        let action_handler = WinitActionHandler {
814            id: main_id,
815            proxy: control_sender.clone(),
816        };
817
818        let deactivation_handler = WinitDeactivationHandler {
819            proxy: control_sender.clone(),
820        };
821        (
822            HashMap::from([(
823                main_id,
824                (
825                    node_id,
826                    Adapter::with_direct_handlers(
827                        raw.as_ref(),
828                        activation_handler,
829                        action_handler,
830                        deactivation_handler,
831                    ),
832                ),
833            )]),
834            false,
835        )
836    } else {
837        (Default::default(), false)
838    };
839
840    let mut ui_caches = FxHashMap::default();
841    let mut user_interfaces: ManuallyDrop<
842        HashMap<
843            window::Id,
844            UserInterface<
845                '_,
846                <P as Program>::Message,
847                <P as Program>::Theme,
848                <P as Program>::Renderer,
849            >,
850            rustc_hash::FxBuildHasher,
851        >,
852    > = ManuallyDrop::new(FxHashMap::default());
853
854    let mut cur_dnd_surface: Option<window::Id> = None;
855
856    let mut dnd_surface: Option<
857        Arc<Box<dyn HasWindowHandle + Send + Sync + 'static>>,
858    > = None;
859    let mut dnd_surface_id: Option<window::Id> = None;
860
861    debug.startup_finished();
862    loop {
863        // Empty the queue if possible
864        let event = if let Ok(event) = event_receiver.try_next() {
865            event
866        } else {
867            event_receiver.next().await
868        };
869
870        let Some(event) = event else {
871            break;
872        };
873        let mut rebuild_a11y_tree = false;
874
875        match event {
876            Event::StartDnd => {
877                let queued = clipboard.get_queued();
878                for crate::clipboard::StartDnd {
879                    internal,
880                    source_surface,
881                    icon_surface,
882                    content,
883                    actions,
884                } in queued
885                {
886                    let Some(window_id) = source_surface.and_then(|source| {
887                        match source {
888                            core::clipboard::DndSource::Surface(s) => Some(s),
889                            core::clipboard::DndSource::Widget(w) => {
890                                // search windows for widget with operation
891                                user_interfaces.iter_mut().find_map(
892                                    |(ui_id, ui)| {
893                                        let Some(ui_renderer) = window_manager
894                                            .get_mut(ui_id.clone())
895                                            .map(|w| &w.renderer)
896                                        else {
897                                            return None;
898                                        };
899
900                                        let operation: Box<dyn Operation<()>> =
901                                            Box::new(operation::map(
902                                                Box::new(search_id::search_id(
903                                                    w.clone(),
904                                                )),
905                                                |_| {},
906                                            ));
907                                        let mut current_operation =
908                                            Some(operation);
909
910                                        while let Some(mut operation) =
911                                            current_operation.take()
912                                        {
913                                            ui.operate(
914                                                ui_renderer,
915                                                operation.as_mut(),
916                                            );
917
918                                            match operation.finish() {
919                                                operation::Outcome::None => {}
920                                                operation::Outcome::Some(
921                                                    (),
922                                                ) => {
923                                                    return Some(ui_id.clone());
924                                                }
925                                                operation::Outcome::Chain(
926                                                    next,
927                                                ) => {
928                                                    current_operation =
929                                                        Some(next);
930                                                }
931                                            }
932                                        }
933                                        None
934                                    },
935                                )
936                            }
937                        }
938                    }) else {
939                        eprintln!("No source surface");
940                        continue;
941                    };
942
943                    let Some(window) = window_manager.get_mut(window_id) else {
944                        eprintln!("No window");
945                        continue;
946                    };
947
948                    let state = &window.state;
949                    let mut dnd_buffer = None;
950                    let icon_surface = icon_surface.map(|i| {
951                        let mut icon_surface =
952                            i.downcast::<P::Theme, P::Renderer>();
953
954                        let mut renderer = compositor.create_renderer();
955
956                        let lim = core::layout::Limits::new(
957                            Size::new(1., 1.),
958                            Size::new(
959                                state.viewport().physical_width() as f32,
960                                state.viewport().physical_height() as f32,
961                            ),
962                        );
963
964                        let mut tree = core::widget::Tree {
965                            id: icon_surface.element.as_widget().id(),
966                            tag: icon_surface.element.as_widget().tag(),
967                            state: icon_surface.state,
968                            children: icon_surface
969                                .element
970                                .as_widget()
971                                .children(),
972                        };
973
974                        let size = icon_surface
975                            .element
976                            .as_widget()
977                            .layout(&mut tree, &renderer, &lim);
978                        icon_surface.element.as_widget_mut().diff(&mut tree);
979
980                        let size = lim.resolve(
981                            Length::Shrink,
982                            Length::Shrink,
983                            size.size(),
984                        );
985                        let viewport = Viewport::with_logical_size(
986                            size,
987                            state.viewport().scale_factor(),
988                        );
989
990                        let mut ui = UserInterface::build(
991                            icon_surface.element,
992                            size,
993                            user_interface::Cache::default(),
994                            &mut renderer,
995                        );
996                        _ = ui.draw(
997                            &mut renderer,
998                            state.theme(),
999                            &renderer::Style {
1000                                icon_color: state.icon_color(),
1001                                text_color: state.text_color(),
1002                                scale_factor: state.scale_factor(),
1003                            },
1004                            Default::default(),
1005                        );
1006                        let mut bytes = compositor.screenshot(
1007                            &mut renderer,
1008                            &viewport,
1009                            core::Color::TRANSPARENT,
1010                            &debug.overlay(),
1011                        );
1012                        for pix in bytes.chunks_exact_mut(4) {
1013                            // rgba -> argb little endian
1014                            pix.swap(0, 2);
1015                        }
1016                        // update subsurfaces
1017                        if let Some(surface) =
1018                            platform_specific_handler.create_surface()
1019                        {
1020                            // TODO Remove id
1021                            let id = window::Id::unique();
1022                            platform_specific_handler
1023                                .update_subsurfaces(id, &surface);
1024                            let surface = Arc::new(surface);
1025                            dnd_surface = Some(surface.clone());
1026                            dnd_surface_id = Some(id);
1027                            dnd_buffer = Some((
1028                                viewport.physical_size(),
1029                                state.scale_factor(),
1030                                bytes,
1031                                icon_surface.offset,
1032                            ));
1033                            Icon::Surface(dnd::DndSurface(surface))
1034                        } else {
1035                            platform_specific_handler.clear_subsurface_list();
1036                            Icon::Buffer {
1037                                data: Arc::new(bytes),
1038                                width: viewport.physical_width(),
1039                                height: viewport.physical_height(),
1040                                transparent: true,
1041                            }
1042                        }
1043                    });
1044
1045                    clipboard.start_dnd_winit(
1046                        internal,
1047                        DndSurface(Arc::new(Box::new(window.raw.clone()))),
1048                        icon_surface,
1049                        content,
1050                        actions,
1051                    );
1052
1053                    // This needs to be after `wl_data_device::start_drag` for the offset to have an effect
1054                    if let (Some(surface), Some((size, scale, bytes, offset))) =
1055                        (dnd_surface.as_ref(), dnd_buffer)
1056                    {
1057                        platform_specific_handler.update_surface_shm(
1058                            &surface,
1059                            size.width,
1060                            size.height,
1061                            scale,
1062                            &bytes,
1063                            offset,
1064                        );
1065                    }
1066                }
1067            }
1068            Event::WindowCreated {
1069                id,
1070                window,
1071                exit_on_close_request,
1072                make_visible,
1073                on_open,
1074                resize_border,
1075            } => {
1076                let window = window_manager.insert(
1077                    id,
1078                    window,
1079                    &program,
1080                    &mut compositor,
1081                    exit_on_close_request,
1082                    resize_border,
1083                );
1084                #[cfg(feature = "wayland")]
1085                platform_specific_handler.send_wayland(
1086                    platform_specific::Action::TrackWindow(
1087                        window.raw.clone(),
1088                        id,
1089                    ),
1090                );
1091                #[cfg(feature = "a11y")]
1092                {
1093                    use crate::a11y::*;
1094                    use iced_accessibility::accesskit::{
1095                        ActivationHandler, NodeBuilder, NodeId, Role, Tree,
1096                        TreeUpdate,
1097                    };
1098                    use iced_accessibility::accesskit_winit::Adapter;
1099
1100                    let node_id = core::id::window_node_id();
1101
1102                    let activation_handler = WinitActivationHandler {
1103                        proxy: control_sender.clone(),
1104                        title: window.state.title.clone(),
1105                    };
1106
1107                    let action_handler = WinitActionHandler {
1108                        id,
1109                        proxy: control_sender.clone(),
1110                    };
1111
1112                    let deactivation_handler = WinitDeactivationHandler {
1113                        proxy: control_sender.clone(),
1114                    };
1115                    _ = adapters.insert(
1116                        id,
1117                        (
1118                            node_id,
1119                            Adapter::with_direct_handlers(
1120                                window.raw.as_ref(),
1121                                activation_handler,
1122                                action_handler,
1123                                deactivation_handler,
1124                            ),
1125                        ),
1126                    );
1127                }
1128
1129                let logical_size = window.state.logical_size();
1130
1131                let _ = user_interfaces.insert(
1132                    id,
1133                    build_user_interface(
1134                        &program,
1135                        user_interface::Cache::default(),
1136                        &mut window.renderer,
1137                        logical_size,
1138                        &mut debug,
1139                        id,
1140                        window.raw.clone(),
1141                        window.prev_dnd_destination_rectangles_count,
1142                        &mut clipboard,
1143                    ),
1144                );
1145                let _ = ui_caches.insert(id, user_interface::Cache::default());
1146
1147                if make_visible {
1148                    window.raw.set_visible(true);
1149                }
1150
1151                events.push((
1152                    Some(id),
1153                    core::Event::Window(window::Event::Opened {
1154                        position: window.position(),
1155                        size: window.size(),
1156                    }),
1157                ));
1158
1159                if clipboard.window_id().is_none() {
1160                    clipboard = Clipboard::connect(
1161                        window.raw.clone(),
1162                        crate::clipboard::ControlSender {
1163                            sender: control_sender.clone(),
1164                            proxy: proxy.raw.clone(),
1165                        },
1166                    );
1167                }
1168
1169                let _ = on_open.send(id);
1170                is_window_opening = false;
1171            }
1172            Event::UserEvent(action) => {
1173                rebuild_a11y_tree = true;
1174                let exited = run_action(
1175                    action,
1176                    &program,
1177                    &mut compositor,
1178                    &mut events,
1179                    &mut messages,
1180                    &mut clipboard,
1181                    &mut control_sender,
1182                    &mut debug,
1183                    &mut user_interfaces,
1184                    &mut window_manager,
1185                    &mut ui_caches,
1186                    &mut is_window_opening,
1187                    &mut platform_specific_handler,
1188                );
1189                if exited {
1190                    runtime.track(None.into_iter());
1191                }
1192                actions += 1;
1193            }
1194            Event::NewEvents(
1195                event::StartCause::Init
1196                | event::StartCause::ResumeTimeReached { .. },
1197            ) => {
1198                if window_manager.ids().next().is_none() {
1199                    _ = control_sender
1200                        .start_send(Control::ChangeFlow(ControlFlow::Wait));
1201                }
1202                for (_id, window) in window_manager.iter_mut() {
1203                    window.request_redraw();
1204                }
1205            }
1206            Event::Winit(window_id, event) => {
1207                #[cfg(feature = "a11y")]
1208                {
1209                    if let Some((id, window)) =
1210                        window_manager.get_mut_alias(window_id)
1211                    {
1212                        if let Some(Some((_, adapter))) =
1213                            a11y_enabled.then(|| adapters.get_mut(&id))
1214                        {
1215                            adapter.process_event(window.raw.as_ref(), &event);
1216                        };
1217                    }
1218                }
1219                match event {
1220                    event::WindowEvent::RedrawRequested => {
1221                        let Some((id, window)) =
1222                            window_manager.get_mut_alias(window_id)
1223                        else {
1224                            continue;
1225                        };
1226
1227                        // XX must force update to corner radius before the surface is committed.
1228                        #[cfg(feature = "wayland")]
1229                        if window.viewport_version
1230                            != window.state.viewport_version()
1231                            || window.size() != window.state.logical_size()
1232                        {
1233                            platform_specific_handler.send_wayland(
1234                                platform_specific::Action::ResizeWindow(id),
1235                            );
1236                            window.redraw_requested = true;
1237                            control_sender
1238                                .start_send(Control::Winit(
1239                                    window.raw.id(),
1240                                    WindowEvent::RedrawRequested,
1241                                ))
1242                                .expect("Send redraw event");
1243                        }
1244
1245                        window.redraw_requested = false;
1246
1247                        // TODO: Avoid redrawing all the time by forcing widgets to
1248                        // request redraws on state changes
1249                        //
1250                        // Then, we can use the `interface_state` here to decide if a redraw
1251                        // is needed right away, or simply wait until a specific time.
1252                        let redraw_event = core::Event::Window(
1253                            window::Event::RedrawRequested(Instant::now()),
1254                        );
1255
1256                        let cursor = window.state.cursor();
1257
1258                        let ui = user_interfaces
1259                            .get_mut(&id)
1260                            .expect("Get user interface");
1261
1262                        let (ui_state, _) = ui.update(
1263                            &[redraw_event.clone()],
1264                            cursor,
1265                            &mut window.renderer,
1266                            &mut clipboard,
1267                            &mut messages,
1268                        );
1269
1270                        debug.draw_started();
1271                        let new_mouse_interaction = ui.draw(
1272                            &mut window.renderer,
1273                            window.state.theme(),
1274                            &renderer::Style {
1275                                icon_color: window.state.icon_color(),
1276                                text_color: window.state.text_color(),
1277                                scale_factor: window.state.scale_factor(),
1278                            },
1279                            cursor,
1280                        );
1281                        platform_specific_handler.update_subsurfaces(
1282                            id,
1283                            window.raw.rwh_06_window_handle(),
1284                        );
1285                        debug.draw_finished();
1286
1287                        if new_mouse_interaction != window.mouse_interaction {
1288                            if let Some(interaction) =
1289                                conversion::mouse_interaction(
1290                                    new_mouse_interaction,
1291                                )
1292                            {
1293                                if matches!(
1294                                    window.mouse_interaction,
1295                                    mouse::Interaction::Hide
1296                                ) {
1297                                    window.raw.set_cursor_visible(true);
1298                                }
1299                                window.raw.set_cursor(interaction.into())
1300                            } else {
1301                                window.raw.set_cursor_visible(false);
1302                            }
1303
1304                            window.mouse_interaction = new_mouse_interaction;
1305                        }
1306
1307                        runtime.broadcast(subscription::Event::Interaction {
1308                            window: id,
1309                            event: redraw_event,
1310                            status: core::event::Status::Ignored,
1311                        });
1312
1313                        if control_sender
1314                            .start_send(Control::ChangeFlow(match ui_state {
1315                                user_interface::State::Updated {
1316                                    redraw_request: Some(redraw_request),
1317                                } => match redraw_request {
1318                                    window::RedrawRequest::NextFrame => {
1319                                        window.request_redraw();
1320
1321                                        ControlFlow::Wait
1322                                    }
1323                                    window::RedrawRequest::At(at) => {
1324                                        ControlFlow::WaitUntil(at)
1325                                    }
1326                                },
1327                                _ => ControlFlow::Wait,
1328                            }))
1329                            .is_err()
1330                        {
1331                            panic!("send error");
1332                        }
1333
1334                        let physical_size = window.state.physical_size();
1335                        if physical_size.width == 0 || physical_size.height == 0
1336                        {
1337                            continue;
1338                        }
1339                        if window.viewport_version
1340                            != window.state.viewport_version()
1341                        {
1342                            let logical_size = window.state.logical_size();
1343                            debug.layout_started();
1344                            let mut ui = user_interfaces
1345                                .remove(&id)
1346                                .expect("Remove user interface")
1347                                .relayout(logical_size, &mut window.renderer);
1348
1349                            let _ = user_interfaces.insert(id, ui);
1350                            debug.layout_finished();
1351
1352                            debug.draw_started();
1353                            let new_mouse_interaction = user_interfaces
1354                                .get_mut(&id)
1355                                .expect("Get user interface")
1356                                .draw(
1357                                    &mut window.renderer,
1358                                    window.state.theme(),
1359                                    &renderer::Style {
1360                                        icon_color: window.state.icon_color(),
1361                                        text_color: window.state.text_color(),
1362                                        scale_factor: window
1363                                            .state
1364                                            .scale_factor(),
1365                                    },
1366                                    window.state.cursor(),
1367                                );
1368                            platform_specific_handler.update_subsurfaces(
1369                                id,
1370                                window.raw.rwh_06_window_handle(),
1371                            );
1372                            debug.draw_finished();
1373
1374                            if new_mouse_interaction != window.mouse_interaction
1375                            {
1376                                if let Some(interaction) =
1377                                    conversion::mouse_interaction(
1378                                        new_mouse_interaction,
1379                                    )
1380                                {
1381                                    if matches!(
1382                                        window.mouse_interaction,
1383                                        mouse::Interaction::Hide
1384                                    ) {
1385                                        window.raw.set_cursor_visible(true);
1386                                    }
1387                                    window.raw.set_cursor(interaction.into())
1388                                } else {
1389                                    window.raw.set_cursor_visible(false);
1390                                }
1391
1392                                window.mouse_interaction =
1393                                    new_mouse_interaction;
1394                            }
1395                            compositor.configure_surface(
1396                                &mut window.surface,
1397                                physical_size.width,
1398                                physical_size.height,
1399                            );
1400
1401                            window.viewport_version =
1402                                window.state.viewport_version();
1403                        }
1404
1405                        window.raw.pre_present_notify();
1406                        debug.render_started();
1407                        match compositor.present(
1408                            &mut window.renderer,
1409                            &mut window.surface,
1410                            window.state.viewport(),
1411                            window.state.background_color(),
1412                            &debug.overlay(),
1413                        ) {
1414                            Ok(()) => {
1415                                debug.render_finished();
1416                            }
1417                            Err(error) => {
1418                                match error {
1419                                    // This is an unrecoverable error.
1420                                    compositor::SurfaceError::OutOfMemory => {
1421                                        panic!("{:?}", error);
1422                                    }
1423                                    compositor::SurfaceError::NoDamage => {
1424                                        debug.render_finished();
1425
1426                                        // TODO Ideally there would be a way to know if some widget wants to animate?
1427                                        let _ = control_sender.start_send(
1428                                        Control::ChangeFlow(
1429                                                ControlFlow::WaitUntil(
1430                                                    Instant::now().checked_add(
1431                                                        Duration::from_millis(100),
1432                                                    ).unwrap_or(Instant::now()),
1433                                                ),
1434                                            ),
1435                                        );
1436                                    }
1437                                    _ => {
1438                                        debug.render_finished();
1439                                        log::error!(
1440                                            "Error {error:?} when \
1441                                        presenting surface."
1442                                        );
1443
1444                                        // Try rendering all windows again next frame.
1445                                        for (_id, window) in
1446                                            window_manager.iter_mut()
1447                                        {
1448                                            window.request_redraw();
1449                                        }
1450                                    }
1451                                }
1452                            }
1453                        }
1454                    }
1455                    window_event => {
1456                        if !is_daemon
1457                            && matches!(
1458                                window_event,
1459                                winit::event::WindowEvent::Destroyed
1460                            )
1461                            && !is_window_opening
1462                            && window_manager.is_empty()
1463                        {
1464                            runtime.track(None.into_iter());
1465                            control_sender
1466                                .start_send(Control::Exit)
1467                                .expect("Send control action");
1468
1469                            continue;
1470                        }
1471
1472                        let Some((id, window)) =
1473                            window_manager.get_mut_alias(window_id)
1474                        else {
1475                            continue;
1476                        };
1477
1478                        // Initiates a drag resize window state when found.
1479                        if let Some(func) =
1480                            window.drag_resize_window_func.as_mut()
1481                        {
1482                            if func(window.raw.as_ref(), &window_event) {
1483                                continue;
1484                            }
1485                        }
1486
1487                        if matches!(
1488                            window_event,
1489                            winit::event::WindowEvent::CloseRequested
1490                        ) && window.exit_on_close_request
1491                        {
1492                            _ = run_action(
1493                                Action::Window(runtime::window::Action::Close(
1494                                    id,
1495                                )),
1496                                &program,
1497                                &mut compositor,
1498                                &mut events,
1499                                &mut messages,
1500                                &mut clipboard,
1501                                &mut control_sender,
1502                                &mut debug,
1503                                &mut user_interfaces,
1504                                &mut window_manager,
1505                                &mut ui_caches,
1506                                &mut is_window_opening,
1507                                &mut platform_specific_handler,
1508                            );
1509                        } else {
1510                            window.state.update(
1511                                window.raw.as_ref(),
1512                                &window_event,
1513                                &mut debug,
1514                            );
1515                            if let Some(event) = conversion::window_event(
1516                                window_event,
1517                                window.state.scale_factor(),
1518                                window.state.modifiers(),
1519                                window.raw.as_ref(),
1520                            ) {
1521                                events.push((Some(id), event));
1522                            }
1523                        }
1524                    }
1525                    _ => {}
1526                }
1527            }
1528            Event::AboutToWait => {
1529                let skip = events.is_empty() && messages.is_empty();
1530                if skip
1531                    && window_manager.iter_mut().all(|(_, w)| !w.resize_enabled)
1532                {
1533                    _ = control_sender
1534                        .start_send(Control::ChangeFlow(ControlFlow::Wait));
1535                    continue;
1536                }
1537
1538                debug.event_processing_started();
1539                let mut uis_stale = false;
1540                let mut resized = false;
1541                for (id, window) in window_manager.iter_mut() {
1542                    if skip && !window.resize_enabled {
1543                        _ = control_sender
1544                            .start_send(Control::ChangeFlow(ControlFlow::Wait));
1545                        continue;
1546                    }
1547                    let mut window_events = vec![];
1548
1549                    events.retain(|(window_id, event)| {
1550                        if *window_id == Some(id) {
1551                            window_events.push(event.clone());
1552                            false
1553                        } else {
1554                            true
1555                        }
1556                    });
1557                    let no_window_events = window_events.is_empty();
1558                    #[cfg(feature = "wayland")]
1559                    window_events.push(core::Event::PlatformSpecific(
1560                        core::event::PlatformSpecific::Wayland(
1561                            core::event::wayland::Event::RequestResize,
1562                        ),
1563                    ));
1564                    let (ui_state, statuses) = user_interfaces
1565                        .get_mut(&id)
1566                        .expect("Get user interface")
1567                        .update(
1568                            &window_events,
1569                            window.state.cursor(),
1570                            &mut window.renderer,
1571                            &mut clipboard,
1572                            &mut messages,
1573                        );
1574
1575                    let mut needs_redraw =
1576                        !no_window_events || !messages.is_empty();
1577
1578                    if let Some(requested_size) =
1579                        clipboard.requested_logical_size.lock().unwrap().take()
1580                    {
1581                        let requested_physical_size: PhysicalSize<u32> =
1582                            winit::dpi::PhysicalSize::from_logical(
1583                                requested_size.cast::<u32>(),
1584                                window.state.scale_factor(),
1585                            );
1586
1587                        let physical_size = window.state.physical_size();
1588                        if requested_physical_size.width != physical_size.width
1589                            || requested_physical_size.height
1590                                != physical_size.height
1591                        {
1592                            // FIXME what to do when we are stuck in a configure event/resize request loop
1593                            // We don't have control over how winit handles this.
1594                            window.resize_enabled = true;
1595                            resized = true;
1596                            needs_redraw = true;
1597                            let s = winit::dpi::Size::Logical(
1598                                requested_size.cast(),
1599                            );
1600                            _ = window.raw.request_surface_size(s);
1601                            window.raw.set_min_surface_size(Some(s));
1602                            window.raw.set_max_surface_size(Some(s));
1603                            window.state.synchronize(
1604                                &program,
1605                                id,
1606                                window.raw.as_ref(),
1607                            );
1608                        }
1609                    }
1610                    if needs_redraw {
1611                        window.request_redraw();
1612                    } else {
1613                        _ = control_sender
1614                            .start_send(Control::ChangeFlow(ControlFlow::Wait));
1615                        continue;
1616                    }
1617
1618                    if !uis_stale {
1619                        uis_stale =
1620                            matches!(ui_state, user_interface::State::Outdated);
1621                    }
1622
1623                    for (event, status) in
1624                        window_events.into_iter().zip(statuses.into_iter())
1625                    {
1626                        runtime.broadcast(subscription::Event::Interaction {
1627                            window: id,
1628                            event,
1629                            status,
1630                        });
1631                    }
1632                }
1633
1634                if !resized && skip {
1635                    _ = control_sender
1636                        .start_send(Control::ChangeFlow(ControlFlow::Wait));
1637                    continue;
1638                }
1639
1640                for (id, event) in events.drain(..) {
1641                    if id.is_none()
1642                        && matches!(
1643                            event,
1644                            core::Event::Keyboard(_)
1645                                | core::Event::Touch(_)
1646                                | core::Event::Mouse(_)
1647                        )
1648                    {
1649                        _ = control_sender
1650                            .start_send(Control::ChangeFlow(ControlFlow::Wait));
1651                        continue;
1652                    }
1653                    runtime.broadcast(subscription::Event::Interaction {
1654                        window: id.unwrap_or(window::Id::NONE),
1655                        event,
1656                        status: core::event::Status::Ignored,
1657                    });
1658                }
1659
1660                debug.event_processing_finished();
1661
1662                if !messages.is_empty() || uis_stale {
1663                    let cached_interfaces: FxHashMap<
1664                        window::Id,
1665                        user_interface::Cache,
1666                    > = ManuallyDrop::into_inner(user_interfaces)
1667                        .drain()
1668                        .map(|(id, ui)| (id, ui.into_cache()))
1669                        .collect();
1670
1671                    update(
1672                        &mut program,
1673                        &mut runtime,
1674                        &mut debug,
1675                        &mut messages,
1676                    );
1677
1678                    for (id, window) in window_manager.iter_mut() {
1679                        window.state.synchronize(
1680                            &program,
1681                            id,
1682                            window.raw.as_ref(),
1683                        );
1684
1685                        window.request_redraw();
1686                    }
1687                    rebuild_a11y_tree = true;
1688
1689                    user_interfaces = ManuallyDrop::new(build_user_interfaces(
1690                        &program,
1691                        &mut debug,
1692                        &mut window_manager,
1693                        cached_interfaces,
1694                        &mut clipboard,
1695                    ));
1696
1697                    if actions > 0 {
1698                        proxy.free_slots(actions);
1699                        actions = 0;
1700                    }
1701
1702                    platform_specific_handler.retain_subsurfaces(|id| {
1703                        window_manager.get(id).is_some()
1704                            || dnd_surface_id == Some(id)
1705                    });
1706                }
1707
1708                debug.draw_started();
1709
1710                for (id, window) in window_manager.iter_mut() {
1711                    // TODO: Avoid redrawing all the time by forcing widgets to
1712                    //  request redraws on state changes
1713                    //
1714                    // Then, we can use the `interface_state` here to decide if a redraw
1715                    // is needed right away, or simply wait until a specific time.
1716                    let redraw_event = core::Event::Window(
1717                        window::Event::RedrawRequested(Instant::now()),
1718                    );
1719
1720                    let cursor = window.state.cursor();
1721
1722                    let ui = user_interfaces
1723                        .get_mut(&id)
1724                        .expect("Get user interface");
1725
1726                    let (ui_state, _) = ui.update(
1727                        &[redraw_event.clone()],
1728                        cursor,
1729                        &mut window.renderer,
1730                        &mut clipboard,
1731                        &mut messages,
1732                    );
1733
1734                    let new_mouse_interaction = {
1735                        let state = &window.state;
1736
1737                        ui.draw(
1738                            &mut window.renderer,
1739                            state.theme(),
1740                            &renderer::Style {
1741                                icon_color: state.icon_color(),
1742                                text_color: state.text_color(),
1743                                scale_factor: state.scale_factor(),
1744                            },
1745                            cursor,
1746                        )
1747                    };
1748                    platform_specific_handler.clear_subsurface_list();
1749
1750                    if new_mouse_interaction != window.mouse_interaction {
1751                        if let Some(interaction) =
1752                            conversion::mouse_interaction(new_mouse_interaction)
1753                        {
1754                            if matches!(
1755                                window.mouse_interaction,
1756                                mouse::Interaction::Hide
1757                            ) {
1758                                window.raw.set_cursor_visible(true);
1759                            }
1760                            window.raw.set_cursor(interaction.into())
1761                        } else {
1762                            window.raw.set_cursor_visible(false);
1763                        }
1764
1765                        window.mouse_interaction = new_mouse_interaction;
1766                    }
1767
1768                    // TODO once widgets can request to be redrawn, we can avoid always requesting a
1769                    // redraw
1770                    window.request_redraw();
1771                    runtime.broadcast(subscription::Event::Interaction {
1772                        window: id,
1773                        event: redraw_event,
1774                        status: core::event::Status::Ignored,
1775                    });
1776
1777                    let _ = control_sender.start_send(Control::ChangeFlow(
1778                        match ui_state {
1779                            user_interface::State::Updated {
1780                                redraw_request: Some(redraw_request),
1781                            } => match redraw_request {
1782                                window::RedrawRequest::NextFrame => {
1783                                    window.request_redraw();
1784
1785                                    ControlFlow::Wait
1786                                }
1787                                window::RedrawRequest::At(at) => {
1788                                    ControlFlow::WaitUntil(at)
1789                                }
1790                            },
1791                            _ => ControlFlow::Wait,
1792                        },
1793                    ));
1794                }
1795
1796                debug.draw_finished();
1797            }
1798
1799            Event::Dnd(e) => {
1800                match &e {
1801                    dnd::DndEvent::Offer(_, dnd::OfferEvent::Leave) => {
1802                        events.push((cur_dnd_surface, core::Event::Dnd(e)));
1803                        // XXX can't clear the dnd surface on leave because
1804                        // the data event comes after
1805                        // cur_dnd_surface = None;
1806                    }
1807                    dnd::DndEvent::Offer(
1808                        _,
1809                        dnd::OfferEvent::Enter { surface, .. },
1810                    ) => {
1811                        let window_handle = surface.0.window_handle().ok();
1812                        let window_id = window_manager.iter_mut().find_map(
1813                            |(id, window)| {
1814                                if window
1815                                    .raw
1816                                    .window_handle()
1817                                    .ok()
1818                                    .zip(window_handle)
1819                                    .map(|(a, b)| a == b)
1820                                    .unwrap_or_default()
1821                                {
1822                                    Some(id)
1823                                } else {
1824                                    None
1825                                }
1826                            },
1827                        );
1828                        cur_dnd_surface = window_id;
1829                        events.push((cur_dnd_surface, core::Event::Dnd(e)));
1830                    }
1831                    dnd::DndEvent::Offer(..) => {
1832                        events.push((cur_dnd_surface, core::Event::Dnd(e)));
1833                    }
1834                    dnd::DndEvent::Source(evt) => {
1835                        match evt {
1836                            dnd::SourceEvent::Finished
1837                            | dnd::SourceEvent::Cancelled => {
1838                                dnd_surface = None;
1839                                dnd_surface_id = None;
1840                            }
1841                            _ => {}
1842                        }
1843                        for w in window_manager.ids() {
1844                            events.push((Some(w), core::Event::Dnd(e.clone())));
1845                        }
1846                    }
1847                };
1848            }
1849            #[cfg(feature = "a11y")]
1850            Event::Accessibility(id, e) => {
1851                rebuild_a11y_tree = true;
1852                match e.action {
1853                    iced_accessibility::accesskit::Action::Focus => {
1854                        // TODO send a command for this
1855                    }
1856                    _ => {}
1857                }
1858                events.push((Some(id), conversion::a11y(e)));
1859            }
1860            #[cfg(feature = "a11y")]
1861            Event::AccessibilityEnabled(enabled) => {
1862                a11y_enabled = enabled;
1863            }
1864            Event::PlatformSpecific(e) => {
1865                crate::platform_specific::handle_event(
1866                    e,
1867                    &mut events,
1868                    &mut platform_specific_handler,
1869                    &program,
1870                    &mut compositor,
1871                    &mut window_manager,
1872                    &mut debug,
1873                    &mut user_interfaces,
1874                    &mut clipboard,
1875                    #[cfg(feature = "a11y")]
1876                    &mut adapters,
1877                );
1878            }
1879            _ => {
1880                // log ignored events?
1881            }
1882        }
1883        #[cfg(feature = "a11y")]
1884        {
1885            use iced_accessibility::{
1886                accesskit::{NodeBuilder, NodeId, Role, Tree, TreeUpdate},
1887                A11yId, A11yNode, A11yTree,
1888            };
1889            if !a11y_enabled || !rebuild_a11y_tree {
1890                continue;
1891            }
1892
1893            for id in window_manager.ids() {
1894                let Some((a11y_id, adapter)) = adapters.get_mut(&id) else {
1895                    continue;
1896                };
1897                let Some(window) = window_manager.get(id) else {
1898                    continue;
1899                };
1900                let interface =
1901                    user_interfaces.get_mut(&id).expect("Get user interface");
1902
1903                // TODO cleanup duplication
1904                let child_tree = interface.a11y_nodes(window.state.cursor());
1905                let mut root = NodeBuilder::new(Role::Window);
1906                root.set_name(window.state.title.to_string());
1907                let window_tree = A11yTree::node_with_child_tree(
1908                    A11yNode::new(root, *a11y_id),
1909                    child_tree,
1910                );
1911                let tree = Tree::new(NodeId(*a11y_id));
1912
1913                let focus = Arc::new(std::sync::Mutex::new(None));
1914                let focus_clone = focus.clone();
1915                let operation: Box<dyn Operation<()>> =
1916                    Box::new(operation::map(
1917                        Box::new(operation::focusable::find_focused()),
1918                        move |id| {
1919                            let mut guard = focus.lock().unwrap();
1920                            _ = guard.replace(id);
1921                        },
1922                    ));
1923                let mut current_operation = Some(operation);
1924
1925                while let Some(mut operation) = current_operation.take() {
1926                    interface.operate(&window.renderer, operation.as_mut());
1927
1928                    match operation.finish() {
1929                        operation::Outcome::None => {}
1930                        operation::Outcome::Some(()) => {
1931                            break;
1932                        }
1933                        operation::Outcome::Chain(next) => {
1934                            current_operation = Some(next);
1935                        }
1936                    }
1937                }
1938                let mut guard = focus_clone.lock().unwrap();
1939                let focus = guard
1940                    .take()
1941                    .map(|id| A11yId::Widget(id))
1942                    .filter(|f_id| window_tree.contains(f_id));
1943                tracing::debug!(
1944                    "tree root: {:?}\nchildren: {:?}\nfocus: {:?}\n",
1945                    window_tree
1946                        .root()
1947                        .iter()
1948                        .map(|n| (n.node(), n.id()))
1949                        .collect::<Vec<_>>(),
1950                    window_tree
1951                        .children()
1952                        .iter()
1953                        .map(|n| (n.node(), n.id()))
1954                        .collect::<Vec<_>>(),
1955                    &focus,
1956                );
1957                let focus =
1958                    focus.map(|id| id.into()).unwrap_or_else(|| tree.root);
1959                adapter.update_if_active(|| TreeUpdate {
1960                    nodes: window_tree.into(),
1961                    tree: Some(tree),
1962                    focus,
1963                });
1964            }
1965        }
1966    }
1967
1968    let _ = ManuallyDrop::into_inner(user_interfaces);
1969}
1970
1971/// Builds a window's [`UserInterface`] for the [`Program`].
1972pub(crate) fn build_user_interface<'a, P: Program>(
1973    program: &'a P,
1974    cache: user_interface::Cache,
1975    renderer: &mut P::Renderer,
1976    size: Size,
1977    debug: &mut Debug,
1978    id: window::Id,
1979    raw: Arc<dyn winit::window::Window>,
1980    prev_dnd_destination_rectangles_count: usize,
1981    clipboard: &mut Clipboard,
1982) -> UserInterface<'a, P::Message, P::Theme, P::Renderer>
1983where
1984    P::Theme: DefaultStyle,
1985{
1986    debug.view_started();
1987    let view = program.view(id);
1988    debug.view_finished();
1989
1990    debug.layout_started();
1991    let user_interface = UserInterface::build(view, size, cache, renderer);
1992    debug.layout_finished();
1993
1994    let dnd_rectangles = user_interface
1995        .dnd_rectangles(prev_dnd_destination_rectangles_count, renderer);
1996    let new_dnd_rectangles_count = dnd_rectangles.as_ref().len();
1997    if new_dnd_rectangles_count > 0 || prev_dnd_destination_rectangles_count > 0
1998    {
1999        clipboard.register_dnd_destination(
2000            DndSurface(Arc::new(Box::new(raw.clone()))),
2001            dnd_rectangles.into_rectangles(),
2002        );
2003    }
2004
2005    user_interface
2006}
2007
2008fn update<P: Program, E: Executor>(
2009    program: &mut P,
2010    runtime: &mut Runtime<E, Proxy<P::Message>, Action<P::Message>>,
2011    debug: &mut Debug,
2012    messages: &mut Vec<P::Message>,
2013) where
2014    P::Theme: DefaultStyle,
2015{
2016    for message in messages.drain(..) {
2017        debug.log_message(&message);
2018        debug.update_started();
2019
2020        let task = runtime.enter(|| program.update(message));
2021        debug.update_finished();
2022
2023        if let Some(stream) = runtime::task::into_stream(task) {
2024            runtime.run(stream);
2025        }
2026    }
2027
2028    let subscription = runtime.enter(|| program.subscription());
2029    runtime.track(subscription::into_recipes(subscription.map(Action::Output)));
2030}
2031
2032fn run_action<P, C>(
2033    action: Action<P::Message>,
2034    program: &P,
2035    compositor: &mut C,
2036    events: &mut Vec<(Option<window::Id>, core::Event)>,
2037    messages: &mut Vec<P::Message>,
2038    clipboard: &mut Clipboard,
2039    control_sender: &mut mpsc::UnboundedSender<Control>,
2040    debug: &mut Debug,
2041    interfaces: &mut FxHashMap<
2042        window::Id,
2043        UserInterface<'_, P::Message, P::Theme, P::Renderer>,
2044    >,
2045    window_manager: &mut WindowManager<P, C>,
2046    ui_caches: &mut FxHashMap<window::Id, user_interface::Cache>,
2047    is_window_opening: &mut bool,
2048    platform_specific: &mut crate::platform_specific::PlatformSpecific,
2049) -> bool
2050where
2051    P: Program,
2052    C: Compositor<Renderer = P::Renderer> + 'static,
2053    P::Theme: DefaultStyle,
2054{
2055    use crate::runtime::clipboard;
2056    use crate::runtime::system;
2057    use crate::runtime::window;
2058
2059    match action {
2060        Action::Output(message) => {
2061            messages.push(message);
2062        }
2063        Action::Clipboard(action) => match action {
2064            clipboard::Action::Read { target, channel } => {
2065                let _ = channel.send(clipboard.read(target));
2066            }
2067            clipboard::Action::Write { target, contents } => {
2068                clipboard.write(target, contents);
2069            }
2070            clipboard::Action::WriteData(contents, kind) => {
2071                clipboard.write_data(kind, ClipboardStoreData(contents))
2072            }
2073            clipboard::Action::ReadData(allowed, tx, kind) => {
2074                let contents = clipboard.read_data(kind, allowed);
2075                _ = tx.send(contents);
2076            }
2077        },
2078        Action::Window(action) => match action {
2079            window::Action::Open(id, settings, channel) => {
2080                let monitor = window_manager.last_monitor();
2081
2082                control_sender
2083                    .start_send(Control::CreateWindow {
2084                        id,
2085                        settings,
2086                        title: program.title(id),
2087                        monitor,
2088                        on_open: channel,
2089                    })
2090                    .expect("Send control action");
2091
2092                *is_window_opening = true;
2093            }
2094            window::Action::Close(id) => {
2095                let _ = ui_caches.remove(&id);
2096                let _ = interfaces.remove(&id);
2097                #[cfg(feature = "wayland")]
2098                platform_specific
2099                    .send_wayland(platform_specific::Action::RemoveWindow(id));
2100
2101                if let Some(window) = window_manager.remove(id) {
2102                    clipboard.register_dnd_destination(
2103                        DndSurface(Arc::new(Box::new(window.raw.clone()))),
2104                        Vec::new(),
2105                    );
2106                    let proxy = clipboard.proxy();
2107                    if clipboard.window_id() == Some(window.raw.id()) {
2108                        *clipboard = window_manager
2109                            .first()
2110                            .map(|window| window.raw.clone())
2111                            .zip(proxy)
2112                            .map(|(w, proxy)| {
2113                                Clipboard::connect(
2114                                    w,
2115                                    crate::clipboard::ControlSender {
2116                                        sender: control_sender.clone(),
2117                                        proxy,
2118                                    },
2119                                )
2120                            })
2121                            .unwrap_or_else(Clipboard::unconnected);
2122                    }
2123
2124                    events.push((
2125                        Some(id),
2126                        core::Event::Window(core::window::Event::Closed),
2127                    ));
2128                }
2129            }
2130            window::Action::GetOldest(channel) => {
2131                let id =
2132                    window_manager.iter_mut().next().map(|(id, _window)| id);
2133
2134                let _ = channel.send(id);
2135            }
2136            window::Action::GetLatest(channel) => {
2137                let id =
2138                    window_manager.iter_mut().last().map(|(id, _window)| id);
2139
2140                let _ = channel.send(id);
2141            }
2142            window::Action::Drag(id) => {
2143                if let Some(window) = window_manager.get_mut(id) {
2144                    let _ = window.raw.drag_window();
2145                }
2146            }
2147            window::Action::Resize(id, size) => {
2148                if let Some(window) = window_manager.get_mut(id) {
2149                    let _ = window.raw.request_surface_size(
2150                        winit::dpi::LogicalSize {
2151                            width: size.width,
2152                            height: size.height,
2153                        }
2154                        .into(),
2155                    );
2156                }
2157            }
2158            window::Action::GetSize(id, channel) => {
2159                if let Some(window) = window_manager.get_mut(id) {
2160                    let size = window
2161                        .raw
2162                        .surface_size()
2163                        .to_logical(window.raw.scale_factor());
2164
2165                    let _ = channel.send(Size::new(size.width, size.height));
2166                }
2167            }
2168            window::Action::GetMaximized(id, channel) => {
2169                if let Some(window) = window_manager.get_mut(id) {
2170                    let _ = channel.send(window.raw.is_maximized());
2171                }
2172            }
2173            window::Action::Maximize(id, maximized) => {
2174                if let Some(window) = window_manager.get_mut(id) {
2175                    window.raw.set_maximized(maximized);
2176                }
2177            }
2178            window::Action::GetMinimized(id, channel) => {
2179                if let Some(window) = window_manager.get_mut(id) {
2180                    let _ = channel.send(window.raw.is_minimized());
2181                }
2182            }
2183            window::Action::Minimize(id, minimized) => {
2184                if let Some(window) = window_manager.get_mut(id) {
2185                    window.raw.set_minimized(minimized);
2186                }
2187            }
2188            window::Action::GetPosition(id, channel) => {
2189                if let Some(window) = window_manager.get(id) {
2190                    let position = window
2191                        .raw
2192                        .inner_position()
2193                        .map(|position| {
2194                            let position = position
2195                                .to_logical::<f32>(window.raw.scale_factor());
2196
2197                            Point::new(position.x, position.y)
2198                        })
2199                        .ok();
2200
2201                    let _ = channel.send(position);
2202                }
2203            }
2204            window::Action::GetScaleFactor(id, channel) => {
2205                if let Some(window) = window_manager.get_mut(id) {
2206                    let scale_factor = window.raw.scale_factor();
2207
2208                    let _ = channel.send(scale_factor as f32);
2209                }
2210            }
2211            window::Action::Move(id, position) => {
2212                if let Some(window) = window_manager.get_mut(id) {
2213                    window.raw.set_outer_position(
2214                        winit::dpi::LogicalPosition {
2215                            x: position.x,
2216                            y: position.y,
2217                        }
2218                        .into(),
2219                    );
2220                }
2221            }
2222            window::Action::ChangeMode(id, mode) => {
2223                if let Some(window) = window_manager.get_mut(id) {
2224                    window.raw.set_visible(conversion::visible(mode));
2225                    window.raw.set_fullscreen(conversion::fullscreen(
2226                        window.raw.current_monitor(),
2227                        mode,
2228                    ));
2229                }
2230            }
2231            window::Action::ChangeIcon(id, icon) => {
2232                if let Some(window) = window_manager.get_mut(id) {
2233                    window.raw.set_window_icon(conversion::icon(icon));
2234                }
2235            }
2236            window::Action::GetMode(id, channel) => {
2237                if let Some(window) = window_manager.get_mut(id) {
2238                    let mode = if window.raw.is_visible().unwrap_or(true) {
2239                        conversion::mode(window.raw.fullscreen())
2240                    } else {
2241                        core::window::Mode::Hidden
2242                    };
2243
2244                    let _ = channel.send(mode);
2245                }
2246            }
2247            window::Action::ToggleMaximize(id) => {
2248                if let Some(window) = window_manager.get_mut(id) {
2249                    window.raw.set_maximized(!window.raw.is_maximized());
2250                }
2251            }
2252            window::Action::ToggleDecorations(id) => {
2253                if let Some(window) = window_manager.get_mut(id) {
2254                    window.raw.set_decorations(!window.raw.is_decorated());
2255                }
2256            }
2257            window::Action::RequestUserAttention(id, attention_type) => {
2258                if let Some(window) = window_manager.get_mut(id) {
2259                    window.raw.request_user_attention(
2260                        attention_type.map(conversion::user_attention),
2261                    );
2262                }
2263            }
2264            window::Action::GainFocus(id) => {
2265                if let Some(window) = window_manager.get_mut(id) {
2266                    window.raw.focus_window();
2267                }
2268            }
2269            window::Action::ChangeLevel(id, level) => {
2270                if let Some(window) = window_manager.get_mut(id) {
2271                    window
2272                        .raw
2273                        .set_window_level(conversion::window_level(level));
2274                }
2275            }
2276            window::Action::ShowSystemMenu(id) => {
2277                if let Some(window) = window_manager.get_mut(id) {
2278                    if let mouse::Cursor::Available(point) =
2279                        window.state.cursor()
2280                    {
2281                        window.raw.show_window_menu(
2282                            winit::dpi::LogicalPosition {
2283                                x: point.x,
2284                                y: point.y,
2285                            }
2286                            .into(),
2287                        );
2288                    }
2289                }
2290            }
2291            window::Action::GetRawId(id, channel) => {
2292                if let Some(window) = window_manager.get_mut(id) {
2293                    let _ = channel.send(window.raw.id().into());
2294                }
2295            }
2296            window::Action::RunWithHandle(id, f) => {
2297                use window::raw_window_handle::HasWindowHandle;
2298
2299                if let Some(handle) = window_manager
2300                    .get_mut(id)
2301                    .and_then(|window| window.raw.window_handle().ok())
2302                {
2303                    f(handle);
2304                }
2305            }
2306            window::Action::Screenshot(id, channel) => {
2307                if let Some(window) = window_manager.get_mut(id) {
2308                    let bytes = compositor.screenshot(
2309                        &mut window.renderer,
2310                        window.state.viewport(),
2311                        window.state.background_color(),
2312                        &debug.overlay(),
2313                    );
2314
2315                    let _ = channel.send(window::Screenshot::new(
2316                        bytes,
2317                        window.state.physical_size(),
2318                        window.state.viewport().scale_factor(),
2319                    ));
2320                }
2321            }
2322            window::Action::EnableMousePassthrough(id) => {
2323                if let Some(window) = window_manager.get_mut(id) {
2324                    let _ = window.raw.set_cursor_hittest(false);
2325                }
2326            }
2327            window::Action::DisableMousePassthrough(id) => {
2328                if let Some(window) = window_manager.get_mut(id) {
2329                    let _ = window.raw.set_cursor_hittest(true);
2330                }
2331            }
2332            window::Action::EnableBlur(id) => {
2333                if let Some(window) = window_manager.get_mut(id) {
2334                    window.raw.set_blur(true);
2335                }
2336            }
2337            window::Action::DisableBlur(id) => {
2338                if let Some(window) = window_manager.get_mut(id) {
2339                    window.raw.set_blur(false);
2340                }
2341            }
2342        },
2343        Action::System(action) => match action {
2344            system::Action::QueryInformation(_channel) => {
2345                #[cfg(feature = "system")]
2346                {
2347                    let graphics_info = compositor.fetch_information();
2348
2349                    let _ = std::thread::spawn(move || {
2350                        let information =
2351                            crate::system::information(graphics_info);
2352
2353                        let _ = _channel.send(information);
2354                    });
2355                }
2356            }
2357        },
2358        Action::Widget(operation) => {
2359            let mut current_operation = Some(operation);
2360
2361            while let Some(mut operation) = current_operation.take() {
2362                for (id, ui) in interfaces.iter_mut() {
2363                    if let Some(window) = window_manager.get_mut(*id) {
2364                        ui.operate(&window.renderer, operation.as_mut());
2365                    }
2366                }
2367
2368                match operation.finish() {
2369                    operation::Outcome::None => {}
2370                    operation::Outcome::Some(()) => {}
2371                    operation::Outcome::Chain(next) => {
2372                        current_operation = Some(next);
2373                    }
2374                }
2375            }
2376        }
2377        Action::LoadFont { bytes, channel } => {
2378            // TODO: Error handling (?)
2379            compositor.load_font(bytes.clone());
2380
2381            let _ = channel.send(Ok(()));
2382        }
2383        Action::Exit => {
2384            control_sender
2385                .start_send(Control::Exit)
2386                .expect("Send control action");
2387            return true;
2388        }
2389        Action::Dnd(a) => match a {
2390            iced_runtime::dnd::DndAction::RegisterDndDestination {
2391                surface,
2392                rectangles,
2393            } => {
2394                clipboard.register_dnd_destination(surface, rectangles);
2395            }
2396            iced_runtime::dnd::DndAction::EndDnd => {
2397                clipboard.end_dnd();
2398            }
2399            iced_runtime::dnd::DndAction::PeekDnd(m, channel) => {
2400                let data = clipboard.peek_dnd(m);
2401                _ = channel.send(data);
2402            }
2403            iced_runtime::dnd::DndAction::SetAction(a) => {
2404                clipboard.set_action(a);
2405            }
2406        },
2407        Action::PlatformSpecific(a) => {
2408            platform_specific.send_action(a);
2409        }
2410    }
2411    false
2412}
2413
2414/// Build the user interface for every window.
2415pub fn build_user_interfaces<'a, P: Program, C>(
2416    program: &'a P,
2417    debug: &mut Debug,
2418    window_manager: &mut WindowManager<P, C>,
2419    mut cached_user_interfaces: FxHashMap<window::Id, user_interface::Cache>,
2420    clipboard: &mut Clipboard,
2421) -> FxHashMap<window::Id, UserInterface<'a, P::Message, P::Theme, P::Renderer>>
2422where
2423    C: Compositor<Renderer = P::Renderer>,
2424    P::Theme: DefaultStyle,
2425{
2426    cached_user_interfaces
2427        .drain()
2428        .filter_map(|(id, cache)| {
2429            let window = window_manager.get_mut(id)?;
2430            let interface = build_user_interface(
2431                program,
2432                cache,
2433                &mut window.renderer,
2434                window.state.logical_size(),
2435                debug,
2436                id,
2437                window.raw.clone(),
2438                window.prev_dnd_destination_rectangles_count,
2439                clipboard,
2440            );
2441
2442            let dnd_rectangles = interface.dnd_rectangles(
2443                window.prev_dnd_destination_rectangles_count,
2444                &window.renderer,
2445            );
2446            let new_dnd_rectangles_count = dnd_rectangles.as_ref().len();
2447            if new_dnd_rectangles_count > 0
2448                || window.prev_dnd_destination_rectangles_count > 0
2449            {
2450                clipboard.register_dnd_destination(
2451                    DndSurface(Arc::new(Box::new(window.raw.clone()))),
2452                    dnd_rectangles.into_rectangles(),
2453                );
2454            }
2455
2456            window.prev_dnd_destination_rectangles_count =
2457                new_dnd_rectangles_count;
2458
2459            Some((id, interface))
2460        })
2461        .collect()
2462}
2463
2464/// Returns true if the provided event should cause a [`Program`] to
2465/// exit.
2466pub fn user_force_quit(
2467    event: &winit::event::WindowEvent,
2468    _modifiers: winit::keyboard::ModifiersState,
2469) -> bool {
2470    match event {
2471        #[cfg(target_os = "macos")]
2472        winit::event::WindowEvent::KeyboardInput {
2473            event:
2474                winit::event::KeyEvent {
2475                    logical_key: winit::keyboard::Key::Character(c),
2476                    state: winit::event::ElementState::Pressed,
2477                    ..
2478                },
2479            ..
2480        } if c == "q" && _modifiers.super_key() => true,
2481        _ => false,
2482    }
2483}