1#[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
59pub trait Program
71where
72 Self: Sized,
73 Self::Theme: DefaultStyle,
74{
75 type Message: std::fmt::Debug + Send;
77
78 type Theme;
80
81 type Executor: Executor;
88
89 type Renderer: core::Renderer + core::text::Renderer;
91
92 type Flags;
94
95 fn new(flags: Self::Flags) -> (Self, Task<Self::Message>);
104
105 fn title(&self, window: window::Id) -> String;
110
111 fn update(&mut self, message: Self::Message) -> Task<Self::Message>;
120
121 fn view(
125 &self,
126 window: window::Id,
127 ) -> Element<'_, Self::Message, Self::Theme, Self::Renderer>;
128
129 fn theme(&self, window: window::Id) -> Self::Theme;
131
132 fn style(&self, theme: &Self::Theme) -> Appearance {
134 theme.default_style()
135 }
136
137 fn subscription(&self) -> Subscription<Self::Message> {
147 Subscription::none()
148 }
149
150 #[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
169pub 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 #[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 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 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 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 pix.swap(0, 2);
1015 }
1016 if let Some(surface) =
1018 platform_specific_handler.create_surface()
1019 {
1020 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 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 #[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 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 compositor::SurfaceError::OutOfMemory => {
1421 panic!("{:?}", error);
1422 }
1423 compositor::SurfaceError::NoDamage => {
1424 debug.render_finished();
1425
1426 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 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 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 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 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 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 }
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 }
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 }
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 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
1971pub(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 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
2414pub 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
2464pub 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}