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