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
858 debug.startup_finished();
859 loop {
860 let event = if let Ok(event) = event_receiver.try_next() {
862 event
863 } else {
864 event_receiver.next().await
865 };
866
867 let Some(event) = event else {
868 break;
869 };
870 let mut rebuild_a11y_tree = false;
871
872 match event {
873 Event::StartDnd => {
874 let queued = clipboard.get_queued();
875 for crate::clipboard::StartDnd {
876 internal,
877 source_surface,
878 icon_surface,
879 content,
880 actions,
881 } in queued
882 {
883 let Some(window_id) = source_surface.and_then(|source| {
884 match source {
885 core::clipboard::DndSource::Surface(s) => Some(s),
886 core::clipboard::DndSource::Widget(w) => {
887 user_interfaces.iter_mut().find_map(
889 |(ui_id, ui)| {
890 let Some(ui_renderer) = window_manager
891 .get_mut(ui_id.clone())
892 .map(|w| &w.renderer)
893 else {
894 return None;
895 };
896
897 let operation: Box<dyn Operation<()>> =
898 Box::new(operation::map(
899 Box::new(search_id::search_id(
900 w.clone(),
901 )),
902 |_| {},
903 ));
904 let mut current_operation =
905 Some(operation);
906
907 while let Some(mut operation) =
908 current_operation.take()
909 {
910 ui.operate(
911 ui_renderer,
912 operation.as_mut(),
913 );
914
915 match operation.finish() {
916 operation::Outcome::None => {}
917 operation::Outcome::Some(
918 (),
919 ) => {
920 return Some(ui_id.clone());
921 }
922 operation::Outcome::Chain(
923 next,
924 ) => {
925 current_operation =
926 Some(next);
927 }
928 }
929 }
930 None
931 },
932 )
933 }
934 }
935 }) else {
936 eprintln!("No source surface");
937 continue;
938 };
939
940 let Some(window) = window_manager.get_mut(window_id) else {
941 eprintln!("No window");
942 continue;
943 };
944
945 let state = &window.state;
946 let mut dnd_buffer = None;
947 let icon_surface = icon_surface.map(|i| {
948 let mut icon_surface =
949 i.downcast::<P::Theme, P::Renderer>();
950
951 let mut renderer = compositor.create_renderer();
952
953 let lim = core::layout::Limits::new(
954 Size::new(1., 1.),
955 Size::new(
956 state.viewport().physical_width() as f32,
957 state.viewport().physical_height() as f32,
958 ),
959 );
960
961 let mut tree = core::widget::Tree {
962 id: icon_surface.element.as_widget().id(),
963 tag: icon_surface.element.as_widget().tag(),
964 state: icon_surface.state,
965 children: icon_surface
966 .element
967 .as_widget()
968 .children(),
969 };
970
971 let size = icon_surface
972 .element
973 .as_widget()
974 .layout(&mut tree, &renderer, &lim);
975 icon_surface.element.as_widget_mut().diff(&mut tree);
976
977 let size = lim.resolve(
978 Length::Shrink,
979 Length::Shrink,
980 size.size(),
981 );
982 let viewport = Viewport::with_logical_size(
983 size,
984 state.viewport().scale_factor(),
985 );
986
987 let mut ui = UserInterface::build(
988 icon_surface.element,
989 size,
990 user_interface::Cache::default(),
991 &mut renderer,
992 );
993 _ = ui.draw(
994 &mut renderer,
995 state.theme(),
996 &renderer::Style {
997 icon_color: state.icon_color(),
998 text_color: state.text_color(),
999 scale_factor: state.scale_factor(),
1000 },
1001 Default::default(),
1002 );
1003 let mut bytes = compositor.screenshot(
1004 &mut renderer,
1005 &viewport,
1006 core::Color::TRANSPARENT,
1007 &debug.overlay(),
1008 );
1009 for pix in bytes.chunks_exact_mut(4) {
1010 pix.swap(0, 2);
1012 }
1013 if let Some(surface) =
1015 platform_specific_handler.create_surface()
1016 {
1017 let id = window::Id::unique();
1019 platform_specific_handler
1020 .update_subsurfaces(id, &surface);
1021 let surface = Arc::new(surface);
1022 dnd_surface = Some(surface.clone());
1023 dnd_buffer = Some((
1024 viewport.physical_size(),
1025 state.scale_factor(),
1026 bytes,
1027 icon_surface.offset,
1028 ));
1029 Icon::Surface(dnd::DndSurface(surface))
1030 } else {
1031 platform_specific_handler.clear_subsurface_list();
1032 Icon::Buffer {
1033 data: Arc::new(bytes),
1034 width: viewport.physical_width(),
1035 height: viewport.physical_height(),
1036 transparent: true,
1037 }
1038 }
1039 });
1040
1041 clipboard.start_dnd_winit(
1042 internal,
1043 DndSurface(Arc::new(Box::new(window.raw.clone()))),
1044 icon_surface,
1045 content,
1046 actions,
1047 );
1048
1049 if let (Some(surface), Some((size, scale, bytes, offset))) =
1051 (dnd_surface.as_ref(), dnd_buffer)
1052 {
1053 platform_specific_handler.update_surface_shm(
1054 &surface,
1055 size.width,
1056 size.height,
1057 scale,
1058 &bytes,
1059 offset,
1060 );
1061 }
1062 }
1063 }
1064 Event::WindowCreated {
1065 id,
1066 window,
1067 exit_on_close_request,
1068 make_visible,
1069 on_open,
1070 resize_border,
1071 } => {
1072 let window = window_manager.insert(
1073 id,
1074 window,
1075 &program,
1076 &mut compositor,
1077 exit_on_close_request,
1078 resize_border,
1079 );
1080 #[cfg(feature = "wayland")]
1081 platform_specific_handler.send_wayland(
1082 platform_specific::Action::TrackWindow(
1083 window.raw.clone(),
1084 id,
1085 ),
1086 );
1087 #[cfg(feature = "a11y")]
1088 {
1089 use crate::a11y::*;
1090 use iced_accessibility::accesskit::{
1091 ActivationHandler, NodeBuilder, NodeId, Role, Tree,
1092 TreeUpdate,
1093 };
1094 use iced_accessibility::accesskit_winit::Adapter;
1095
1096 let node_id = core::id::window_node_id();
1097
1098 let activation_handler = WinitActivationHandler {
1099 proxy: control_sender.clone(),
1100 title: window.state.title.clone(),
1101 };
1102
1103 let action_handler = WinitActionHandler {
1104 id,
1105 proxy: control_sender.clone(),
1106 };
1107
1108 let deactivation_handler = WinitDeactivationHandler {
1109 proxy: control_sender.clone(),
1110 };
1111 _ = adapters.insert(
1112 id,
1113 (
1114 node_id,
1115 Adapter::with_direct_handlers(
1116 window.raw.as_ref(),
1117 activation_handler,
1118 action_handler,
1119 deactivation_handler,
1120 ),
1121 ),
1122 );
1123 }
1124
1125 let logical_size = window.state.logical_size();
1126
1127 let _ = user_interfaces.insert(
1128 id,
1129 build_user_interface(
1130 &program,
1131 user_interface::Cache::default(),
1132 &mut window.renderer,
1133 logical_size,
1134 &mut debug,
1135 id,
1136 window.raw.clone(),
1137 window.prev_dnd_destination_rectangles_count,
1138 &mut clipboard,
1139 ),
1140 );
1141 let _ = ui_caches.insert(id, user_interface::Cache::default());
1142
1143 if make_visible {
1144 window.raw.set_visible(true);
1145 }
1146
1147 events.push((
1148 Some(id),
1149 core::Event::Window(window::Event::Opened {
1150 position: window.position(),
1151 size: window.size(),
1152 }),
1153 ));
1154
1155 if clipboard.window_id().is_none() {
1156 clipboard = Clipboard::connect(
1157 window.raw.clone(),
1158 crate::clipboard::ControlSender {
1159 sender: control_sender.clone(),
1160 proxy: proxy.raw.clone(),
1161 },
1162 );
1163 }
1164
1165 let _ = on_open.send(id);
1166 is_window_opening = false;
1167 }
1168 Event::UserEvent(action) => {
1169 rebuild_a11y_tree = true;
1170 let exited = run_action(
1171 action,
1172 &program,
1173 &mut compositor,
1174 &mut events,
1175 &mut messages,
1176 &mut clipboard,
1177 &mut control_sender,
1178 &mut debug,
1179 &mut user_interfaces,
1180 &mut window_manager,
1181 &mut ui_caches,
1182 &mut is_window_opening,
1183 &mut platform_specific_handler,
1184 );
1185 if exited {
1186 runtime.track(None.into_iter());
1187 }
1188 actions += 1;
1189 }
1190 Event::NewEvents(
1191 event::StartCause::Init
1192 | event::StartCause::ResumeTimeReached { .. },
1193 ) => {
1194 if window_manager.ids().next().is_none() {
1195 _ = control_sender
1196 .start_send(Control::ChangeFlow(ControlFlow::Wait));
1197 }
1198 for (_id, window) in window_manager.iter_mut() {
1199 window.request_redraw();
1200 }
1201 }
1202 Event::Winit(window_id, event) => {
1203 #[cfg(feature = "a11y")]
1204 {
1205 if let Some((id, window)) =
1206 window_manager.get_mut_alias(window_id)
1207 {
1208 if let Some(Some((_, adapter))) =
1209 a11y_enabled.then(|| adapters.get_mut(&id))
1210 {
1211 adapter.process_event(window.raw.as_ref(), &event);
1212 };
1213 }
1214 }
1215 match event {
1216 event::WindowEvent::RedrawRequested => {
1217 let Some((id, window)) =
1218 window_manager.get_mut_alias(window_id)
1219 else {
1220 continue;
1221 };
1222
1223 window.redraw_requested = false;
1224
1225 let redraw_event = core::Event::Window(
1231 window::Event::RedrawRequested(Instant::now()),
1232 );
1233
1234 let cursor = window.state.cursor();
1235
1236 let ui = user_interfaces
1237 .get_mut(&id)
1238 .expect("Get user interface");
1239
1240 let (ui_state, _) = ui.update(
1241 &[redraw_event.clone()],
1242 cursor,
1243 &mut window.renderer,
1244 &mut clipboard,
1245 &mut messages,
1246 );
1247
1248 debug.draw_started();
1249 let new_mouse_interaction = ui.draw(
1250 &mut window.renderer,
1251 window.state.theme(),
1252 &renderer::Style {
1253 icon_color: window.state.icon_color(),
1254 text_color: window.state.text_color(),
1255 scale_factor: window.state.scale_factor(),
1256 },
1257 cursor,
1258 );
1259 platform_specific_handler.update_subsurfaces(
1260 id,
1261 window.raw.rwh_06_window_handle(),
1262 );
1263 debug.draw_finished();
1264
1265 if new_mouse_interaction != window.mouse_interaction {
1266 if let Some(interaction) =
1267 conversion::mouse_interaction(
1268 new_mouse_interaction,
1269 )
1270 {
1271 if matches!(
1272 window.mouse_interaction,
1273 mouse::Interaction::Hide
1274 ) {
1275 window.raw.set_cursor_visible(true);
1276 }
1277 window.raw.set_cursor(interaction.into())
1278 } else {
1279 window.raw.set_cursor_visible(false);
1280 }
1281
1282 window.mouse_interaction = new_mouse_interaction;
1283 }
1284
1285 runtime.broadcast(subscription::Event::Interaction {
1286 window: id,
1287 event: redraw_event,
1288 status: core::event::Status::Ignored,
1289 });
1290
1291 if control_sender
1292 .start_send(Control::ChangeFlow(match ui_state {
1293 user_interface::State::Updated {
1294 redraw_request: Some(redraw_request),
1295 } => match redraw_request {
1296 window::RedrawRequest::NextFrame => {
1297 window.request_redraw();
1298
1299 ControlFlow::Wait
1300 }
1301 window::RedrawRequest::At(at) => {
1302 ControlFlow::WaitUntil(at)
1303 }
1304 },
1305 _ => ControlFlow::Wait,
1306 }))
1307 .is_err()
1308 {
1309 panic!("send error");
1310 }
1311
1312 let physical_size = window.state.physical_size();
1313 if physical_size.width == 0 || physical_size.height == 0
1314 {
1315 continue;
1316 }
1317 if window.viewport_version
1318 != window.state.viewport_version()
1319 {
1320 let logical_size = window.state.logical_size();
1321 debug.layout_started();
1322 let mut ui = user_interfaces
1323 .remove(&id)
1324 .expect("Remove user interface")
1325 .relayout(logical_size, &mut window.renderer);
1326
1327 let _ = user_interfaces.insert(id, ui);
1328 debug.layout_finished();
1329
1330 debug.draw_started();
1331 let new_mouse_interaction = user_interfaces
1332 .get_mut(&id)
1333 .expect("Get user interface")
1334 .draw(
1335 &mut window.renderer,
1336 window.state.theme(),
1337 &renderer::Style {
1338 icon_color: window.state.icon_color(),
1339 text_color: window.state.text_color(),
1340 scale_factor: window
1341 .state
1342 .scale_factor(),
1343 },
1344 window.state.cursor(),
1345 );
1346 platform_specific_handler.update_subsurfaces(
1347 id,
1348 window.raw.rwh_06_window_handle(),
1349 );
1350 debug.draw_finished();
1351
1352 if new_mouse_interaction != window.mouse_interaction
1353 {
1354 if let Some(interaction) =
1355 conversion::mouse_interaction(
1356 new_mouse_interaction,
1357 )
1358 {
1359 if matches!(
1360 window.mouse_interaction,
1361 mouse::Interaction::Hide
1362 ) {
1363 window.raw.set_cursor_visible(true);
1364 }
1365 window.raw.set_cursor(interaction.into())
1366 } else {
1367 window.raw.set_cursor_visible(false);
1368 }
1369
1370 window.mouse_interaction =
1371 new_mouse_interaction;
1372 }
1373 compositor.configure_surface(
1374 &mut window.surface,
1375 physical_size.width,
1376 physical_size.height,
1377 );
1378
1379 window.viewport_version =
1380 window.state.viewport_version();
1381 }
1382
1383 window.raw.pre_present_notify();
1384 debug.render_started();
1385 match compositor.present(
1386 &mut window.renderer,
1387 &mut window.surface,
1388 window.state.viewport(),
1389 window.state.background_color(),
1390 &debug.overlay(),
1391 ) {
1392 Ok(()) => {
1393 debug.render_finished();
1394 }
1395 Err(error) => {
1396 match error {
1397 compositor::SurfaceError::OutOfMemory => {
1399 panic!("{:?}", error);
1400 }
1401 compositor::SurfaceError::NoDamage => {
1402 debug.render_finished();
1403
1404 let _ = control_sender.start_send(
1406 Control::ChangeFlow(
1407 ControlFlow::WaitUntil(
1408 Instant::now().checked_add(
1409 Duration::from_millis(100),
1410 ).unwrap_or(Instant::now()),
1411 ),
1412 ),
1413 );
1414 }
1415 _ => {
1416 debug.render_finished();
1417 log::error!(
1418 "Error {error:?} when \
1419 presenting surface."
1420 );
1421
1422 for (_id, window) in
1424 window_manager.iter_mut()
1425 {
1426 window.request_redraw();
1427 }
1428 }
1429 }
1430 }
1431 }
1432 }
1433 window_event => {
1434 if !is_daemon
1435 && matches!(
1436 window_event,
1437 winit::event::WindowEvent::Destroyed
1438 )
1439 && !is_window_opening
1440 && window_manager.is_empty()
1441 {
1442 runtime.track(None.into_iter());
1443 control_sender
1444 .start_send(Control::Exit)
1445 .expect("Send control action");
1446
1447 continue;
1448 }
1449
1450 let Some((id, window)) =
1451 window_manager.get_mut_alias(window_id)
1452 else {
1453 continue;
1454 };
1455
1456 if let Some(func) =
1458 window.drag_resize_window_func.as_mut()
1459 {
1460 if func(window.raw.as_ref(), &window_event) {
1461 continue;
1462 }
1463 }
1464
1465 if matches!(
1466 window_event,
1467 winit::event::WindowEvent::CloseRequested
1468 ) && window.exit_on_close_request
1469 {
1470 _ = run_action(
1471 Action::Window(runtime::window::Action::Close(
1472 id,
1473 )),
1474 &program,
1475 &mut compositor,
1476 &mut events,
1477 &mut messages,
1478 &mut clipboard,
1479 &mut control_sender,
1480 &mut debug,
1481 &mut user_interfaces,
1482 &mut window_manager,
1483 &mut ui_caches,
1484 &mut is_window_opening,
1485 &mut platform_specific_handler,
1486 );
1487 } else {
1488 window.state.update(
1489 window.raw.as_ref(),
1490 &window_event,
1491 &mut debug,
1492 );
1493 if let Some(event) = conversion::window_event(
1494 window_event,
1495 window.state.scale_factor(),
1496 window.state.modifiers(),
1497 ) {
1498 events.push((Some(id), event));
1499 }
1500 }
1501 }
1502 _ => {}
1503 }
1504 }
1505 Event::AboutToWait => {
1506 let skip = events.is_empty() && messages.is_empty();
1507 if skip
1508 && window_manager.iter_mut().all(|(_, w)| !w.resize_enabled)
1509 {
1510 _ = control_sender
1511 .start_send(Control::ChangeFlow(ControlFlow::Wait));
1512 continue;
1513 }
1514
1515 debug.event_processing_started();
1516 let mut uis_stale = false;
1517 let mut resized = false;
1518 for (id, window) in window_manager.iter_mut() {
1519 if skip && !window.resize_enabled {
1520 _ = control_sender
1521 .start_send(Control::ChangeFlow(ControlFlow::Wait));
1522 continue;
1523 }
1524 let mut window_events = vec![];
1525
1526 events.retain(|(window_id, event)| {
1527 if *window_id == Some(id) {
1528 window_events.push(event.clone());
1529 false
1530 } else {
1531 true
1532 }
1533 });
1534 let no_window_events = window_events.is_empty();
1535 #[cfg(feature = "wayland")]
1536 window_events.push(core::Event::PlatformSpecific(
1537 core::event::PlatformSpecific::Wayland(
1538 core::event::wayland::Event::RequestResize,
1539 ),
1540 ));
1541 let (ui_state, statuses) = user_interfaces
1542 .get_mut(&id)
1543 .expect("Get user interface")
1544 .update(
1545 &window_events,
1546 window.state.cursor(),
1547 &mut window.renderer,
1548 &mut clipboard,
1549 &mut messages,
1550 );
1551
1552 let mut needs_redraw =
1553 !no_window_events || !messages.is_empty();
1554
1555 if let Some(requested_size) =
1556 clipboard.requested_logical_size.lock().unwrap().take()
1557 {
1558 let requested_physical_size: PhysicalSize<u32> =
1559 winit::dpi::PhysicalSize::from_logical(
1560 requested_size.cast::<u32>(),
1561 window.state.scale_factor(),
1562 );
1563
1564 let physical_size = window.state.physical_size();
1565 if requested_physical_size.width != physical_size.width
1566 || requested_physical_size.height
1567 != physical_size.height
1568 {
1569 window.resize_enabled = true;
1572 resized = true;
1573 needs_redraw = true;
1574 let s = winit::dpi::Size::Logical(
1575 requested_size.cast(),
1576 );
1577 _ = window.raw.request_surface_size(s);
1578 window.raw.set_min_surface_size(Some(s));
1579 window.raw.set_max_surface_size(Some(s));
1580 window.state.synchronize(
1581 &program,
1582 id,
1583 window.raw.as_ref(),
1584 );
1585 }
1586 }
1587 if needs_redraw {
1588 window.request_redraw();
1589 } else {
1590 _ = control_sender
1591 .start_send(Control::ChangeFlow(ControlFlow::Wait));
1592 continue;
1593 }
1594
1595 if !uis_stale {
1596 uis_stale =
1597 matches!(ui_state, user_interface::State::Outdated);
1598 }
1599
1600 for (event, status) in
1601 window_events.into_iter().zip(statuses.into_iter())
1602 {
1603 runtime.broadcast(subscription::Event::Interaction {
1604 window: id,
1605 event,
1606 status,
1607 });
1608 }
1609 }
1610
1611 if !resized && skip {
1612 _ = control_sender
1613 .start_send(Control::ChangeFlow(ControlFlow::Wait));
1614 continue;
1615 }
1616
1617 for (id, event) in events.drain(..) {
1618 if id.is_none()
1619 && matches!(
1620 event,
1621 core::Event::Keyboard(_)
1622 | core::Event::Touch(_)
1623 | core::Event::Mouse(_)
1624 )
1625 {
1626 _ = control_sender
1627 .start_send(Control::ChangeFlow(ControlFlow::Wait));
1628 continue;
1629 }
1630 runtime.broadcast(subscription::Event::Interaction {
1631 window: id.unwrap_or(window::Id::NONE),
1632 event,
1633 status: core::event::Status::Ignored,
1634 });
1635 }
1636
1637 debug.event_processing_finished();
1638
1639 if !messages.is_empty() || uis_stale {
1640 let cached_interfaces: FxHashMap<
1641 window::Id,
1642 user_interface::Cache,
1643 > = ManuallyDrop::into_inner(user_interfaces)
1644 .drain()
1645 .map(|(id, ui)| (id, ui.into_cache()))
1646 .collect();
1647
1648 update(
1649 &mut program,
1650 &mut runtime,
1651 &mut debug,
1652 &mut messages,
1653 );
1654
1655 for (id, window) in window_manager.iter_mut() {
1656 window.state.synchronize(
1657 &program,
1658 id,
1659 window.raw.as_ref(),
1660 );
1661
1662 window.request_redraw();
1663 }
1664 rebuild_a11y_tree = true;
1665
1666 user_interfaces = ManuallyDrop::new(build_user_interfaces(
1667 &program,
1668 &mut debug,
1669 &mut window_manager,
1670 cached_interfaces,
1671 &mut clipboard,
1672 ));
1673
1674 if actions > 0 {
1675 proxy.free_slots(actions);
1676 actions = 0;
1677 }
1678 }
1679
1680 debug.draw_started();
1681
1682 for (id, window) in window_manager.iter_mut() {
1683 let redraw_event = core::Event::Window(
1689 window::Event::RedrawRequested(Instant::now()),
1690 );
1691
1692 let cursor = window.state.cursor();
1693
1694 let ui = user_interfaces
1695 .get_mut(&id)
1696 .expect("Get user interface");
1697
1698 let (ui_state, _) = ui.update(
1699 &[redraw_event.clone()],
1700 cursor,
1701 &mut window.renderer,
1702 &mut clipboard,
1703 &mut messages,
1704 );
1705
1706 let new_mouse_interaction = {
1707 let state = &window.state;
1708
1709 ui.draw(
1710 &mut window.renderer,
1711 state.theme(),
1712 &renderer::Style {
1713 icon_color: state.icon_color(),
1714 text_color: state.text_color(),
1715 scale_factor: state.scale_factor(),
1716 },
1717 cursor,
1718 )
1719 };
1720 platform_specific_handler.clear_subsurface_list();
1721
1722 if new_mouse_interaction != window.mouse_interaction {
1723 if let Some(interaction) =
1724 conversion::mouse_interaction(new_mouse_interaction)
1725 {
1726 if matches!(
1727 window.mouse_interaction,
1728 mouse::Interaction::Hide
1729 ) {
1730 window.raw.set_cursor_visible(true);
1731 }
1732 window.raw.set_cursor(interaction.into())
1733 } else {
1734 window.raw.set_cursor_visible(false);
1735 }
1736
1737 window.mouse_interaction = new_mouse_interaction;
1738 }
1739
1740 window.request_redraw();
1743 runtime.broadcast(subscription::Event::Interaction {
1744 window: id,
1745 event: redraw_event,
1746 status: core::event::Status::Ignored,
1747 });
1748
1749 let _ = control_sender.start_send(Control::ChangeFlow(
1750 match ui_state {
1751 user_interface::State::Updated {
1752 redraw_request: Some(redraw_request),
1753 } => match redraw_request {
1754 window::RedrawRequest::NextFrame => {
1755 window.request_redraw();
1756
1757 ControlFlow::Wait
1758 }
1759 window::RedrawRequest::At(at) => {
1760 ControlFlow::WaitUntil(at)
1761 }
1762 },
1763 _ => ControlFlow::Wait,
1764 },
1765 ));
1766 }
1767
1768 debug.draw_finished();
1769 }
1770
1771 Event::Dnd(e) => {
1772 match &e {
1773 dnd::DndEvent::Offer(_, dnd::OfferEvent::Leave) => {
1774 events.push((cur_dnd_surface, core::Event::Dnd(e)));
1775 }
1779 dnd::DndEvent::Offer(
1780 _,
1781 dnd::OfferEvent::Enter { surface, .. },
1782 ) => {
1783 let window_handle = surface.0.window_handle().ok();
1784 let window_id = window_manager.iter_mut().find_map(
1785 |(id, window)| {
1786 if window
1787 .raw
1788 .window_handle()
1789 .ok()
1790 .zip(window_handle)
1791 .map(|(a, b)| a == b)
1792 .unwrap_or_default()
1793 {
1794 Some(id)
1795 } else {
1796 None
1797 }
1798 },
1799 );
1800 cur_dnd_surface = window_id;
1801 events.push((cur_dnd_surface, core::Event::Dnd(e)));
1802 }
1803 dnd::DndEvent::Offer(..) => {
1804 events.push((cur_dnd_surface, core::Event::Dnd(e)));
1805 }
1806 dnd::DndEvent::Source(evt) => {
1807 match evt {
1808 dnd::SourceEvent::Finished
1809 | dnd::SourceEvent::Cancelled => {
1810 dnd_surface = None;
1811 }
1812 _ => {}
1813 }
1814 for w in window_manager.ids() {
1815 events.push((Some(w), core::Event::Dnd(e.clone())));
1816 }
1817 }
1818 };
1819 }
1820 #[cfg(feature = "a11y")]
1821 Event::Accessibility(id, e) => {
1822 rebuild_a11y_tree = true;
1823 match e.action {
1824 iced_accessibility::accesskit::Action::Focus => {
1825 }
1827 _ => {}
1828 }
1829 events.push((Some(id), conversion::a11y(e)));
1830 }
1831 #[cfg(feature = "a11y")]
1832 Event::AccessibilityEnabled(enabled) => {
1833 a11y_enabled = enabled;
1834 }
1835 Event::PlatformSpecific(e) => {
1836 crate::platform_specific::handle_event(
1837 e,
1838 &mut events,
1839 &mut platform_specific_handler,
1840 &program,
1841 &mut compositor,
1842 &mut window_manager,
1843 &mut debug,
1844 &mut user_interfaces,
1845 &mut clipboard,
1846 #[cfg(feature = "a11y")]
1847 &mut adapters,
1848 );
1849 }
1850 _ => {
1851 }
1853 }
1854 #[cfg(feature = "a11y")]
1855 {
1856 use iced_accessibility::{
1857 accesskit::{NodeBuilder, NodeId, Role, Tree, TreeUpdate},
1858 A11yId, A11yNode, A11yTree,
1859 };
1860 if !a11y_enabled || !rebuild_a11y_tree {
1861 continue;
1862 }
1863
1864 for id in window_manager.ids() {
1865 let Some((a11y_id, adapter)) = adapters.get_mut(&id) else {
1866 continue;
1867 };
1868 let Some(window) = window_manager.get(id) else {
1869 continue;
1870 };
1871 let interface =
1872 user_interfaces.get_mut(&id).expect("Get user interface");
1873
1874 let child_tree = interface.a11y_nodes(window.state.cursor());
1876 let mut root = NodeBuilder::new(Role::Window);
1877 root.set_name(window.state.title.to_string());
1878 let window_tree = A11yTree::node_with_child_tree(
1879 A11yNode::new(root, *a11y_id),
1880 child_tree,
1881 );
1882 let tree = Tree::new(NodeId(*a11y_id));
1883
1884 let focus = Arc::new(std::sync::Mutex::new(None));
1885 let focus_clone = focus.clone();
1886 let operation: Box<dyn Operation<()>> =
1887 Box::new(operation::map(
1888 Box::new(operation::focusable::find_focused()),
1889 move |id| {
1890 let mut guard = focus.lock().unwrap();
1891 _ = guard.replace(id);
1892 },
1893 ));
1894 let mut current_operation = Some(operation);
1895
1896 while let Some(mut operation) = current_operation.take() {
1897 interface.operate(&window.renderer, operation.as_mut());
1898
1899 match operation.finish() {
1900 operation::Outcome::None => {}
1901 operation::Outcome::Some(()) => {
1902 break;
1903 }
1904 operation::Outcome::Chain(next) => {
1905 current_operation = Some(next);
1906 }
1907 }
1908 }
1909 let mut guard = focus_clone.lock().unwrap();
1910 let focus = guard
1911 .take()
1912 .map(|id| A11yId::Widget(id))
1913 .filter(|f_id| window_tree.contains(f_id));
1914 tracing::debug!(
1915 "tree root: {:?}\nchildren: {:?}\nfocus: {:?}\n",
1916 window_tree
1917 .root()
1918 .iter()
1919 .map(|n| (n.node(), n.id()))
1920 .collect::<Vec<_>>(),
1921 window_tree
1922 .children()
1923 .iter()
1924 .map(|n| (n.node(), n.id()))
1925 .collect::<Vec<_>>(),
1926 &focus,
1927 );
1928 let focus =
1929 focus.map(|id| id.into()).unwrap_or_else(|| tree.root);
1930 adapter.update_if_active(|| TreeUpdate {
1931 nodes: window_tree.into(),
1932 tree: Some(tree),
1933 focus,
1934 });
1935 }
1936 }
1937 }
1938
1939 let _ = ManuallyDrop::into_inner(user_interfaces);
1940}
1941
1942pub(crate) fn build_user_interface<'a, P: Program>(
1944 program: &'a P,
1945 cache: user_interface::Cache,
1946 renderer: &mut P::Renderer,
1947 size: Size,
1948 debug: &mut Debug,
1949 id: window::Id,
1950 raw: Arc<dyn winit::window::Window>,
1951 prev_dnd_destination_rectangles_count: usize,
1952 clipboard: &mut Clipboard,
1953) -> UserInterface<'a, P::Message, P::Theme, P::Renderer>
1954where
1955 P::Theme: DefaultStyle,
1956{
1957 debug.view_started();
1958 let view = program.view(id);
1959 debug.view_finished();
1960
1961 debug.layout_started();
1962 let user_interface = UserInterface::build(view, size, cache, renderer);
1963 debug.layout_finished();
1964
1965 let dnd_rectangles = user_interface
1966 .dnd_rectangles(prev_dnd_destination_rectangles_count, renderer);
1967 let new_dnd_rectangles_count = dnd_rectangles.as_ref().len();
1968 if new_dnd_rectangles_count > 0 || prev_dnd_destination_rectangles_count > 0
1969 {
1970 clipboard.register_dnd_destination(
1971 DndSurface(Arc::new(Box::new(raw.clone()))),
1972 dnd_rectangles.into_rectangles(),
1973 );
1974 }
1975
1976 user_interface
1977}
1978
1979fn update<P: Program, E: Executor>(
1980 program: &mut P,
1981 runtime: &mut Runtime<E, Proxy<P::Message>, Action<P::Message>>,
1982 debug: &mut Debug,
1983 messages: &mut Vec<P::Message>,
1984) where
1985 P::Theme: DefaultStyle,
1986{
1987 for message in messages.drain(..) {
1988 debug.log_message(&message);
1989 debug.update_started();
1990
1991 let task = runtime.enter(|| program.update(message));
1992 debug.update_finished();
1993
1994 if let Some(stream) = runtime::task::into_stream(task) {
1995 runtime.run(stream);
1996 }
1997 }
1998
1999 let subscription = runtime.enter(|| program.subscription());
2000 runtime.track(subscription::into_recipes(subscription.map(Action::Output)));
2001}
2002
2003fn run_action<P, C>(
2004 action: Action<P::Message>,
2005 program: &P,
2006 compositor: &mut C,
2007 events: &mut Vec<(Option<window::Id>, core::Event)>,
2008 messages: &mut Vec<P::Message>,
2009 clipboard: &mut Clipboard,
2010 control_sender: &mut mpsc::UnboundedSender<Control>,
2011 debug: &mut Debug,
2012 interfaces: &mut FxHashMap<
2013 window::Id,
2014 UserInterface<'_, P::Message, P::Theme, P::Renderer>,
2015 >,
2016 window_manager: &mut WindowManager<P, C>,
2017 ui_caches: &mut FxHashMap<window::Id, user_interface::Cache>,
2018 is_window_opening: &mut bool,
2019 platform_specific: &mut crate::platform_specific::PlatformSpecific,
2020) -> bool
2021where
2022 P: Program,
2023 C: Compositor<Renderer = P::Renderer> + 'static,
2024 P::Theme: DefaultStyle,
2025{
2026 use crate::runtime::clipboard;
2027 use crate::runtime::system;
2028 use crate::runtime::window;
2029
2030 match action {
2031 Action::Output(message) => {
2032 messages.push(message);
2033 }
2034 Action::Clipboard(action) => match action {
2035 clipboard::Action::Read { target, channel } => {
2036 let _ = channel.send(clipboard.read(target));
2037 }
2038 clipboard::Action::Write { target, contents } => {
2039 clipboard.write(target, contents);
2040 }
2041 clipboard::Action::WriteData(contents, kind) => {
2042 clipboard.write_data(kind, ClipboardStoreData(contents))
2043 }
2044 clipboard::Action::ReadData(allowed, tx, kind) => {
2045 let contents = clipboard.read_data(kind, allowed);
2046 _ = tx.send(contents);
2047 }
2048 },
2049 Action::Window(action) => match action {
2050 window::Action::Open(id, settings, channel) => {
2051 let monitor = window_manager.last_monitor();
2052
2053 control_sender
2054 .start_send(Control::CreateWindow {
2055 id,
2056 settings,
2057 title: program.title(id),
2058 monitor,
2059 on_open: channel,
2060 })
2061 .expect("Send control action");
2062
2063 *is_window_opening = true;
2064 }
2065 window::Action::Close(id) => {
2066 let _ = ui_caches.remove(&id);
2067 let _ = interfaces.remove(&id);
2068 #[cfg(feature = "wayland")]
2069 platform_specific
2070 .send_wayland(platform_specific::Action::RemoveWindow(id));
2071
2072 if let Some(window) = window_manager.remove(id) {
2073 clipboard.register_dnd_destination(
2074 DndSurface(Arc::new(Box::new(window.raw.clone()))),
2075 Vec::new(),
2076 );
2077 let proxy = clipboard.proxy();
2078 if clipboard.window_id() == Some(window.raw.id()) {
2079 *clipboard = window_manager
2080 .first()
2081 .map(|window| window.raw.clone())
2082 .zip(proxy)
2083 .map(|(w, proxy)| {
2084 Clipboard::connect(
2085 w,
2086 crate::clipboard::ControlSender {
2087 sender: control_sender.clone(),
2088 proxy,
2089 },
2090 )
2091 })
2092 .unwrap_or_else(Clipboard::unconnected);
2093 }
2094
2095 events.push((
2096 Some(id),
2097 core::Event::Window(core::window::Event::Closed),
2098 ));
2099 }
2100 }
2101 window::Action::GetOldest(channel) => {
2102 let id =
2103 window_manager.iter_mut().next().map(|(id, _window)| id);
2104
2105 let _ = channel.send(id);
2106 }
2107 window::Action::GetLatest(channel) => {
2108 let id =
2109 window_manager.iter_mut().last().map(|(id, _window)| id);
2110
2111 let _ = channel.send(id);
2112 }
2113 window::Action::Drag(id) => {
2114 if let Some(window) = window_manager.get_mut(id) {
2115 let _ = window.raw.drag_window();
2116 }
2117 }
2118 window::Action::Resize(id, size) => {
2119 if let Some(window) = window_manager.get_mut(id) {
2120 let _ = window.raw.request_surface_size(
2121 winit::dpi::LogicalSize {
2122 width: size.width,
2123 height: size.height,
2124 }
2125 .into(),
2126 );
2127 }
2128 }
2129 window::Action::GetSize(id, channel) => {
2130 if let Some(window) = window_manager.get_mut(id) {
2131 let size = window
2132 .raw
2133 .surface_size()
2134 .to_logical(window.raw.scale_factor());
2135
2136 let _ = channel.send(Size::new(size.width, size.height));
2137 }
2138 }
2139 window::Action::GetMaximized(id, channel) => {
2140 if let Some(window) = window_manager.get_mut(id) {
2141 let _ = channel.send(window.raw.is_maximized());
2142 }
2143 }
2144 window::Action::Maximize(id, maximized) => {
2145 if let Some(window) = window_manager.get_mut(id) {
2146 window.raw.set_maximized(maximized);
2147 }
2148 }
2149 window::Action::GetMinimized(id, channel) => {
2150 if let Some(window) = window_manager.get_mut(id) {
2151 let _ = channel.send(window.raw.is_minimized());
2152 }
2153 }
2154 window::Action::Minimize(id, minimized) => {
2155 if let Some(window) = window_manager.get_mut(id) {
2156 window.raw.set_minimized(minimized);
2157 }
2158 }
2159 window::Action::GetPosition(id, channel) => {
2160 if let Some(window) = window_manager.get(id) {
2161 let position = window
2162 .raw
2163 .inner_position()
2164 .map(|position| {
2165 let position = position
2166 .to_logical::<f32>(window.raw.scale_factor());
2167
2168 Point::new(position.x, position.y)
2169 })
2170 .ok();
2171
2172 let _ = channel.send(position);
2173 }
2174 }
2175 window::Action::GetScaleFactor(id, channel) => {
2176 if let Some(window) = window_manager.get_mut(id) {
2177 let scale_factor = window.raw.scale_factor();
2178
2179 let _ = channel.send(scale_factor as f32);
2180 }
2181 }
2182 window::Action::Move(id, position) => {
2183 if let Some(window) = window_manager.get_mut(id) {
2184 window.raw.set_outer_position(
2185 winit::dpi::LogicalPosition {
2186 x: position.x,
2187 y: position.y,
2188 }
2189 .into(),
2190 );
2191 }
2192 }
2193 window::Action::ChangeMode(id, mode) => {
2194 if let Some(window) = window_manager.get_mut(id) {
2195 window.raw.set_visible(conversion::visible(mode));
2196 window.raw.set_fullscreen(conversion::fullscreen(
2197 window.raw.current_monitor(),
2198 mode,
2199 ));
2200 }
2201 }
2202 window::Action::ChangeIcon(id, icon) => {
2203 if let Some(window) = window_manager.get_mut(id) {
2204 window.raw.set_window_icon(conversion::icon(icon));
2205 }
2206 }
2207 window::Action::GetMode(id, channel) => {
2208 if let Some(window) = window_manager.get_mut(id) {
2209 let mode = if window.raw.is_visible().unwrap_or(true) {
2210 conversion::mode(window.raw.fullscreen())
2211 } else {
2212 core::window::Mode::Hidden
2213 };
2214
2215 let _ = channel.send(mode);
2216 }
2217 }
2218 window::Action::ToggleMaximize(id) => {
2219 if let Some(window) = window_manager.get_mut(id) {
2220 window.raw.set_maximized(!window.raw.is_maximized());
2221 }
2222 }
2223 window::Action::ToggleDecorations(id) => {
2224 if let Some(window) = window_manager.get_mut(id) {
2225 window.raw.set_decorations(!window.raw.is_decorated());
2226 }
2227 }
2228 window::Action::RequestUserAttention(id, attention_type) => {
2229 if let Some(window) = window_manager.get_mut(id) {
2230 window.raw.request_user_attention(
2231 attention_type.map(conversion::user_attention),
2232 );
2233 }
2234 }
2235 window::Action::GainFocus(id) => {
2236 if let Some(window) = window_manager.get_mut(id) {
2237 window.raw.focus_window();
2238 }
2239 }
2240 window::Action::ChangeLevel(id, level) => {
2241 if let Some(window) = window_manager.get_mut(id) {
2242 window
2243 .raw
2244 .set_window_level(conversion::window_level(level));
2245 }
2246 }
2247 window::Action::ShowSystemMenu(id) => {
2248 if let Some(window) = window_manager.get_mut(id) {
2249 if let mouse::Cursor::Available(point) =
2250 window.state.cursor()
2251 {
2252 window.raw.show_window_menu(
2253 winit::dpi::LogicalPosition {
2254 x: point.x,
2255 y: point.y,
2256 }
2257 .into(),
2258 );
2259 }
2260 }
2261 }
2262 window::Action::GetRawId(id, channel) => {
2263 if let Some(window) = window_manager.get_mut(id) {
2264 let _ = channel.send(window.raw.id().into());
2265 }
2266 }
2267 window::Action::RunWithHandle(id, f) => {
2268 use window::raw_window_handle::HasWindowHandle;
2269
2270 if let Some(handle) = window_manager
2271 .get_mut(id)
2272 .and_then(|window| window.raw.window_handle().ok())
2273 {
2274 f(handle);
2275 }
2276 }
2277 window::Action::Screenshot(id, channel) => {
2278 if let Some(window) = window_manager.get_mut(id) {
2279 let bytes = compositor.screenshot(
2280 &mut window.renderer,
2281 window.state.viewport(),
2282 window.state.background_color(),
2283 &debug.overlay(),
2284 );
2285
2286 let _ = channel.send(window::Screenshot::new(
2287 bytes,
2288 window.state.physical_size(),
2289 window.state.viewport().scale_factor(),
2290 ));
2291 }
2292 }
2293 window::Action::EnableMousePassthrough(id) => {
2294 if let Some(window) = window_manager.get_mut(id) {
2295 let _ = window.raw.set_cursor_hittest(false);
2296 }
2297 }
2298 window::Action::DisableMousePassthrough(id) => {
2299 if let Some(window) = window_manager.get_mut(id) {
2300 let _ = window.raw.set_cursor_hittest(true);
2301 }
2302 }
2303 window::Action::EnableBlur(id) => {
2304 if let Some(window) = window_manager.get_mut(id) {
2305 window.raw.set_blur(true);
2306 }
2307 }
2308 window::Action::DisableBlur(id) => {
2309 if let Some(window) = window_manager.get_mut(id) {
2310 window.raw.set_blur(false);
2311 }
2312 }
2313 },
2314 Action::System(action) => match action {
2315 system::Action::QueryInformation(_channel) => {
2316 #[cfg(feature = "system")]
2317 {
2318 let graphics_info = compositor.fetch_information();
2319
2320 let _ = std::thread::spawn(move || {
2321 let information =
2322 crate::system::information(graphics_info);
2323
2324 let _ = _channel.send(information);
2325 });
2326 }
2327 }
2328 },
2329 Action::Widget(operation) => {
2330 let mut current_operation = Some(operation);
2331
2332 while let Some(mut operation) = current_operation.take() {
2333 for (id, ui) in interfaces.iter_mut() {
2334 if let Some(window) = window_manager.get_mut(*id) {
2335 ui.operate(&window.renderer, operation.as_mut());
2336 }
2337 }
2338
2339 match operation.finish() {
2340 operation::Outcome::None => {}
2341 operation::Outcome::Some(()) => {}
2342 operation::Outcome::Chain(next) => {
2343 current_operation = Some(next);
2344 }
2345 }
2346 }
2347 }
2348 Action::LoadFont { bytes, channel } => {
2349 compositor.load_font(bytes.clone());
2351
2352 let _ = channel.send(Ok(()));
2353 }
2354 Action::Exit => {
2355 control_sender
2356 .start_send(Control::Exit)
2357 .expect("Send control action");
2358 return true;
2359 }
2360 Action::Dnd(a) => match a {
2361 iced_runtime::dnd::DndAction::RegisterDndDestination {
2362 surface,
2363 rectangles,
2364 } => {
2365 clipboard.register_dnd_destination(surface, rectangles);
2366 }
2367 iced_runtime::dnd::DndAction::EndDnd => {
2368 clipboard.end_dnd();
2369 }
2370 iced_runtime::dnd::DndAction::PeekDnd(m, channel) => {
2371 let data = clipboard.peek_dnd(m);
2372 _ = channel.send(data);
2373 }
2374 iced_runtime::dnd::DndAction::SetAction(a) => {
2375 clipboard.set_action(a);
2376 }
2377 },
2378 Action::PlatformSpecific(a) => {
2379 platform_specific.send_action(a);
2380 }
2381 }
2382 false
2383}
2384
2385pub fn build_user_interfaces<'a, P: Program, C>(
2387 program: &'a P,
2388 debug: &mut Debug,
2389 window_manager: &mut WindowManager<P, C>,
2390 mut cached_user_interfaces: FxHashMap<window::Id, user_interface::Cache>,
2391 clipboard: &mut Clipboard,
2392) -> FxHashMap<window::Id, UserInterface<'a, P::Message, P::Theme, P::Renderer>>
2393where
2394 C: Compositor<Renderer = P::Renderer>,
2395 P::Theme: DefaultStyle,
2396{
2397 cached_user_interfaces
2398 .drain()
2399 .filter_map(|(id, cache)| {
2400 let window = window_manager.get_mut(id)?;
2401 let interface = build_user_interface(
2402 program,
2403 cache,
2404 &mut window.renderer,
2405 window.state.logical_size(),
2406 debug,
2407 id,
2408 window.raw.clone(),
2409 window.prev_dnd_destination_rectangles_count,
2410 clipboard,
2411 );
2412
2413 let dnd_rectangles = interface.dnd_rectangles(
2414 window.prev_dnd_destination_rectangles_count,
2415 &window.renderer,
2416 );
2417 let new_dnd_rectangles_count = dnd_rectangles.as_ref().len();
2418 if new_dnd_rectangles_count > 0
2419 || window.prev_dnd_destination_rectangles_count > 0
2420 {
2421 clipboard.register_dnd_destination(
2422 DndSurface(Arc::new(Box::new(window.raw.clone()))),
2423 dnd_rectangles.into_rectangles(),
2424 );
2425 }
2426
2427 window.prev_dnd_destination_rectangles_count =
2428 new_dnd_rectangles_count;
2429
2430 Some((id, interface))
2431 })
2432 .collect()
2433}
2434
2435pub fn user_force_quit(
2438 event: &winit::event::WindowEvent,
2439 _modifiers: winit::keyboard::ModifiersState,
2440) -> bool {
2441 match event {
2442 #[cfg(target_os = "macos")]
2443 winit::event::WindowEvent::KeyboardInput {
2444 event:
2445 winit::event::KeyEvent {
2446 logical_key: winit::keyboard::Key::Character(c),
2447 state: winit::event::ElementState::Pressed,
2448 ..
2449 },
2450 ..
2451 } if c == "q" && _modifiers.super_key() => true,
2452 _ => false,
2453 }
2454}