freya_winit/
renderer.rs

1use std::{
2    borrow::Cow,
3    fmt,
4    pin::Pin,
5    task::Waker,
6};
7
8use accesskit_winit::WindowEvent as AccessibilityWindowEvent;
9use freya_core::integration::*;
10use freya_engine::prelude::{
11    FontCollection,
12    FontMgr,
13};
14use futures_lite::future::FutureExt as _;
15use futures_util::{
16    FutureExt as _,
17    StreamExt,
18    select,
19};
20use ragnarok::{
21    EventsExecutorRunner,
22    EventsMeasurerRunner,
23};
24use rustc_hash::FxHashMap;
25use torin::prelude::{
26    CursorPoint,
27    Size2D,
28};
29#[cfg(all(feature = "tray", not(target_os = "linux")))]
30use tray_icon::TrayIcon;
31use winit::{
32    application::ApplicationHandler,
33    dpi::{
34        LogicalPosition,
35        LogicalSize,
36    },
37    event::{
38        ElementState,
39        Ime,
40        MouseScrollDelta,
41        Touch,
42        TouchPhase,
43        WindowEvent,
44    },
45    event_loop::{
46        ActiveEventLoop,
47        EventLoopProxy,
48    },
49    window::{
50        Theme,
51        Window,
52        WindowId,
53    },
54};
55
56use crate::{
57    accessibility::AccessibilityTask,
58    config::{
59        CloseDecision,
60        WindowConfig,
61    },
62    plugins::{
63        PluginEvent,
64        PluginHandle,
65        PluginsManager,
66    },
67    window::AppWindow,
68    winit_mappings::{
69        self,
70        map_winit_mouse_button,
71        map_winit_touch_force,
72        map_winit_touch_phase,
73    },
74};
75
76pub struct WinitRenderer {
77    pub windows_configs: Vec<WindowConfig>,
78    #[cfg(feature = "tray")]
79    pub(crate) tray: (
80        Option<crate::config::TrayIconGetter>,
81        Option<crate::config::TrayHandler>,
82    ),
83    #[cfg(all(feature = "tray", not(target_os = "linux")))]
84    pub(crate) tray_icon: Option<TrayIcon>,
85    pub resumed: bool,
86    pub windows: FxHashMap<WindowId, AppWindow>,
87    pub proxy: EventLoopProxy<NativeEvent>,
88    pub plugins: PluginsManager,
89    pub fallback_fonts: Vec<Cow<'static, str>>,
90    pub screen_reader: ScreenReader,
91    pub font_manager: FontMgr,
92    pub font_collection: FontCollection,
93    pub futures: Vec<Pin<Box<dyn std::future::Future<Output = ()>>>>,
94    pub waker: Waker,
95}
96
97pub struct RendererContext<'a> {
98    pub windows: &'a mut FxHashMap<WindowId, AppWindow>,
99    pub proxy: &'a mut EventLoopProxy<NativeEvent>,
100    pub plugins: &'a mut PluginsManager,
101    pub fallback_fonts: &'a mut Vec<Cow<'static, str>>,
102    pub screen_reader: &'a mut ScreenReader,
103    pub font_manager: &'a mut FontMgr,
104    pub font_collection: &'a mut FontCollection,
105    pub(crate) active_event_loop: &'a ActiveEventLoop,
106}
107
108impl RendererContext<'_> {
109    pub fn launch_window(&mut self, window_config: WindowConfig) -> WindowId {
110        let app_window = AppWindow::new(
111            window_config,
112            self.active_event_loop,
113            self.proxy,
114            self.plugins,
115            self.font_collection,
116            self.font_manager,
117            self.fallback_fonts,
118            self.screen_reader.clone(),
119        );
120
121        let window_id = app_window.window.id();
122
123        self.proxy
124            .send_event(NativeEvent::Window(NativeWindowEvent {
125                window_id,
126                action: NativeWindowEventAction::PollRunner,
127            }))
128            .ok();
129
130        self.windows.insert(window_id, app_window);
131
132        window_id
133    }
134
135    pub fn windows(&self) -> &FxHashMap<WindowId, AppWindow> {
136        self.windows
137    }
138
139    pub fn windows_mut(&mut self) -> &mut FxHashMap<WindowId, AppWindow> {
140        self.windows
141    }
142
143    pub fn exit(&mut self) {
144        self.active_event_loop.exit();
145    }
146}
147
148#[derive(Debug)]
149pub enum NativeWindowEventAction {
150    PollRunner,
151
152    Accessibility(AccessibilityWindowEvent),
153
154    PlatformEvent(PlatformEvent),
155
156    User(UserEvent),
157}
158
159pub struct WithWindowCallback(pub(crate) Box<dyn FnOnce(&mut Window)>);
160
161impl fmt::Debug for WithWindowCallback {
162    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163        f.write_str("WithWindowCallback")
164    }
165}
166
167/// Proxy wrapper provided to launch tasks so they can post callbacks executed inside the renderer.
168#[derive(Clone)]
169pub struct LaunchProxy(pub EventLoopProxy<NativeEvent>);
170
171impl LaunchProxy {
172    /// Send a callback to the renderer to get access to [RendererContext].
173    pub fn with<F, T: 'static>(&self, f: F) -> futures_channel::oneshot::Receiver<T>
174    where
175        F: FnOnce(&mut RendererContext) -> T + 'static,
176    {
177        let (tx, rx) = futures_channel::oneshot::channel::<T>();
178        let cb = Box::new(move |ctx: &mut RendererContext| {
179            let res = (f)(ctx);
180            let _ = tx.send(res);
181        });
182        let _ = self
183            .0
184            .send_event(NativeEvent::Generic(NativeGenericEvent::RendererCallback(
185                cb,
186            )));
187        rx
188    }
189}
190
191#[derive(Debug)]
192pub enum NativeWindowErasedEventAction {
193    LaunchWindow {
194        window_config: WindowConfig,
195        ack: futures_channel::oneshot::Sender<WindowId>,
196    },
197    CloseWindow(WindowId),
198    WithWindow {
199        window_id: Option<WindowId>,
200        callback: WithWindowCallback,
201    },
202}
203
204#[derive(Debug)]
205pub struct NativeWindowEvent {
206    pub window_id: WindowId,
207    pub action: NativeWindowEventAction,
208}
209
210#[cfg(feature = "tray")]
211#[derive(Debug)]
212pub enum NativeTrayEventAction {
213    TrayEvent(tray_icon::TrayIconEvent),
214    MenuEvent(tray_icon::menu::MenuEvent),
215    LaunchWindow(SingleThreadErasedEvent),
216}
217
218#[cfg(feature = "tray")]
219#[derive(Debug)]
220pub struct NativeTrayEvent {
221    pub action: NativeTrayEventAction,
222}
223
224pub enum NativeGenericEvent {
225    PollFutures,
226    RendererCallback(Box<dyn FnOnce(&mut RendererContext) + 'static>),
227}
228
229impl fmt::Debug for NativeGenericEvent {
230    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231        match self {
232            NativeGenericEvent::PollFutures => f.write_str("PollFutures"),
233            NativeGenericEvent::RendererCallback(_) => f.write_str("RendererCallback"),
234        }
235    }
236}
237
238/// # Safety
239/// The values are never sent, received or accessed by other threads other than the main thread.
240/// This is needed to send `Rc<T>` and other non-Send and non-Sync values.
241unsafe impl Send for NativeGenericEvent {}
242unsafe impl Sync for NativeGenericEvent {}
243
244#[derive(Debug)]
245pub enum NativeEvent {
246    Window(NativeWindowEvent),
247    #[cfg(feature = "tray")]
248    Tray(NativeTrayEvent),
249    Generic(NativeGenericEvent),
250}
251
252impl From<accesskit_winit::Event> for NativeEvent {
253    fn from(event: accesskit_winit::Event) -> Self {
254        NativeEvent::Window(NativeWindowEvent {
255            window_id: event.window_id,
256            action: NativeWindowEventAction::Accessibility(event.window_event),
257        })
258    }
259}
260
261impl ApplicationHandler<NativeEvent> for WinitRenderer {
262    fn resumed(&mut self, active_event_loop: &winit::event_loop::ActiveEventLoop) {
263        if !self.resumed {
264            #[cfg(feature = "tray")]
265            {
266                #[cfg(not(target_os = "linux"))]
267                if let Some(tray_icon) = self.tray.0.take() {
268                    self.tray_icon = Some((tray_icon)());
269                }
270
271                #[cfg(target_os = "macos")]
272                {
273                    use objc2_core_foundation::CFRunLoop;
274
275                    let rl = CFRunLoop::main().expect("Failed to run CFRunLoop");
276                    CFRunLoop::wake_up(&rl);
277                }
278            }
279
280            for window_config in self.windows_configs.drain(..) {
281                let app_window = AppWindow::new(
282                    window_config,
283                    active_event_loop,
284                    &self.proxy,
285                    &mut self.plugins,
286                    &self.font_collection,
287                    &self.font_manager,
288                    &self.fallback_fonts,
289                    self.screen_reader.clone(),
290                );
291
292                self.proxy
293                    .send_event(NativeEvent::Window(NativeWindowEvent {
294                        window_id: app_window.window.id(),
295                        action: NativeWindowEventAction::PollRunner,
296                    }))
297                    .ok();
298
299                self.windows.insert(app_window.window.id(), app_window);
300            }
301            self.resumed = true;
302
303            let _ = self
304                .proxy
305                .send_event(NativeEvent::Generic(NativeGenericEvent::PollFutures));
306        }
307    }
308
309    fn user_event(
310        &mut self,
311        active_event_loop: &winit::event_loop::ActiveEventLoop,
312        event: NativeEvent,
313    ) {
314        match event {
315            NativeEvent::Generic(NativeGenericEvent::RendererCallback(cb)) => {
316                let mut renderer_context = RendererContext {
317                    fallback_fonts: &mut self.fallback_fonts,
318                    active_event_loop,
319                    windows: &mut self.windows,
320                    proxy: &mut self.proxy,
321                    plugins: &mut self.plugins,
322                    screen_reader: &mut self.screen_reader,
323                    font_manager: &mut self.font_manager,
324                    font_collection: &mut self.font_collection,
325                };
326                (cb)(&mut renderer_context);
327            }
328            NativeEvent::Generic(NativeGenericEvent::PollFutures) => {
329                let mut cx = std::task::Context::from_waker(&self.waker);
330                self.futures
331                    .retain_mut(|fut| fut.poll(&mut cx).is_pending());
332            }
333            #[cfg(feature = "tray")]
334            NativeEvent::Tray(NativeTrayEvent { action }) => {
335                let renderer_context = RendererContext {
336                    fallback_fonts: &mut self.fallback_fonts,
337                    active_event_loop,
338                    windows: &mut self.windows,
339                    proxy: &mut self.proxy,
340                    plugins: &mut self.plugins,
341                    screen_reader: &mut self.screen_reader,
342                    font_manager: &mut self.font_manager,
343                    font_collection: &mut self.font_collection,
344                };
345                match action {
346                    NativeTrayEventAction::TrayEvent(icon_event) => {
347                        use crate::tray::TrayEvent;
348                        if let Some(tray_handler) = &mut self.tray.1 {
349                            (tray_handler)(TrayEvent::Icon(icon_event), renderer_context)
350                        }
351                    }
352                    NativeTrayEventAction::MenuEvent(menu_event) => {
353                        use crate::tray::TrayEvent;
354                        if let Some(tray_handler) = &mut self.tray.1 {
355                            (tray_handler)(TrayEvent::Menu(menu_event), renderer_context)
356                        }
357                    }
358                    NativeTrayEventAction::LaunchWindow(data) => {
359                        let window_config = data
360                            .0
361                            .downcast::<WindowConfig>()
362                            .expect("Expected WindowConfig");
363                        let app_window = AppWindow::new(
364                            *window_config,
365                            active_event_loop,
366                            &self.proxy,
367                            &mut self.plugins,
368                            &self.font_collection,
369                            &self.font_manager,
370                            &self.fallback_fonts,
371                            self.screen_reader.clone(),
372                        );
373
374                        self.proxy
375                            .send_event(NativeEvent::Window(NativeWindowEvent {
376                                window_id: app_window.window.id(),
377                                action: NativeWindowEventAction::PollRunner,
378                            }))
379                            .ok();
380
381                        self.windows.insert(app_window.window.id(), app_window);
382                    }
383                }
384            }
385            NativeEvent::Window(NativeWindowEvent { action, window_id }) => {
386                if let Some(app) = &mut self.windows.get_mut(&window_id) {
387                    match action {
388                        NativeWindowEventAction::PollRunner => {
389                            let mut cx = std::task::Context::from_waker(&app.waker);
390
391                            {
392                                let fut = std::pin::pin!(async {
393                                    select! {
394                                        events_chunk = app.events_receiver.next() => {
395                                            match events_chunk {
396                                                Some(EventsChunk::Processed(processed_events)) => {
397                                                    let events_executor_adapter = EventsExecutorAdapter {
398                                                        runner: &mut app.runner,
399                                                    };
400                                                    events_executor_adapter.run(&mut app.nodes_state, processed_events);
401                                                }
402                                                Some(EventsChunk::Batch(events)) => {
403                                                    for event in events {
404                                                        app.runner.handle_event(event.node_id, event.name, event.data, event.bubbles);
405                                                    }
406                                                }
407                                                _ => {}
408                                            }
409
410                                        },
411                                         _ = app.runner.handle_events().fuse() => {},
412                                    }
413                                });
414
415                                match fut.poll(&mut cx) {
416                                    std::task::Poll::Ready(_) => {
417                                        self.proxy
418                                            .send_event(NativeEvent::Window(NativeWindowEvent {
419                                                window_id: app.window.id(),
420                                                action: NativeWindowEventAction::PollRunner,
421                                            }))
422                                            .ok();
423                                    }
424                                    std::task::Poll::Pending => {}
425                                }
426                            }
427
428                            self.plugins.send(
429                                PluginEvent::StartedUpdatingTree {
430                                    window: &app.window,
431                                    tree: &app.tree,
432                                },
433                                PluginHandle::new(&self.proxy),
434                            );
435                            let mutations = app.runner.sync_and_update();
436                            let result = app.tree.apply_mutations(mutations);
437                            if result.needs_render {
438                                app.process_layout_on_next_render = true;
439                                app.window.request_redraw();
440                            }
441                            self.plugins.send(
442                                PluginEvent::FinishedUpdatingTree {
443                                    window: &app.window,
444                                    tree: &app.tree,
445                                },
446                                PluginHandle::new(&self.proxy),
447                            );
448                            #[cfg(debug_assertions)]
449                            {
450                                tracing::info!("Updated app tree.");
451                                tracing::info!("{:#?}", app.tree);
452                                tracing::info!("{:#?}", app.runner);
453                            }
454                        }
455                        NativeWindowEventAction::Accessibility(
456                            accesskit_winit::WindowEvent::AccessibilityDeactivated,
457                        ) => {
458                            self.screen_reader.set(false);
459                        }
460                        NativeWindowEventAction::Accessibility(
461                            accesskit_winit::WindowEvent::ActionRequested(_),
462                        ) => {}
463                        NativeWindowEventAction::Accessibility(
464                            accesskit_winit::WindowEvent::InitialTreeRequested,
465                        ) => {
466                            app.accessibility_tasks_for_next_render = AccessibilityTask::Init;
467                            app.window.request_redraw();
468                            self.screen_reader.set(true);
469                        }
470                        NativeWindowEventAction::User(user_event) => match user_event {
471                            UserEvent::RequestRedraw => {
472                                app.window.request_redraw();
473                            }
474                            UserEvent::FocusAccessibilityNode(strategy) => {
475                                let task = match strategy {
476                                    AccessibilityFocusStrategy::Backward(_)
477                                    | AccessibilityFocusStrategy::Forward(_) => {
478                                        AccessibilityTask::ProcessUpdate {
479                                            mode: Some(NavigationMode::Keyboard),
480                                        }
481                                    }
482                                    _ => AccessibilityTask::ProcessUpdate { mode: None },
483                                };
484                                app.tree.accessibility_diff.request_focus(strategy);
485                                app.accessibility_tasks_for_next_render = task;
486                                app.window.request_redraw();
487                            }
488                            UserEvent::SetCursorIcon(cursor_icon) => {
489                                app.window.set_cursor(cursor_icon);
490                            }
491                            UserEvent::Erased(data) => {
492                                let action = data
493                                    .0
494                                    .downcast::<NativeWindowErasedEventAction>()
495                                    .expect("Expected NativeWindowErasedEventAction");
496                                match *action {
497                                    NativeWindowErasedEventAction::LaunchWindow {
498                                        window_config,
499                                        ack,
500                                    } => {
501                                        let app_window = AppWindow::new(
502                                            window_config,
503                                            active_event_loop,
504                                            &self.proxy,
505                                            &mut self.plugins,
506                                            &self.font_collection,
507                                            &self.font_manager,
508                                            &self.fallback_fonts,
509                                            self.screen_reader.clone(),
510                                        );
511
512                                        let window_id = app_window.window.id();
513
514                                        let _ = self.proxy.send_event(NativeEvent::Window(
515                                            NativeWindowEvent {
516                                                window_id,
517                                                action: NativeWindowEventAction::PollRunner,
518                                            },
519                                        ));
520
521                                        self.windows.insert(window_id, app_window);
522                                        let _ = ack.send(window_id);
523                                    }
524                                    NativeWindowErasedEventAction::CloseWindow(window_id) => {
525                                        // Its fine to ignore if the window doesnt exist anymore
526                                        let _ = self.windows.remove(&window_id);
527                                        let has_windows = !self.windows.is_empty();
528
529                                        let has_tray = {
530                                            #[cfg(feature = "tray")]
531                                            {
532                                                self.tray.1.is_some()
533                                            }
534                                            #[cfg(not(feature = "tray"))]
535                                            {
536                                                false
537                                            }
538                                        };
539
540                                        // Only exit when there is no window and no tray
541                                        if !has_windows && !has_tray {
542                                            active_event_loop.exit();
543                                        }
544                                    }
545                                    NativeWindowErasedEventAction::WithWindow {
546                                        window_id,
547                                        callback,
548                                    } => {
549                                        if let Some(window_id) = window_id {
550                                            if let Some(app) = self.windows.get_mut(&window_id) {
551                                                (callback.0)(&mut app.window)
552                                            }
553                                        } else {
554                                            (callback.0)(&mut app.window)
555                                        }
556                                    }
557                                }
558                            }
559                        },
560                        NativeWindowEventAction::PlatformEvent(platform_event) => {
561                            let mut events_measurer_adapter = EventsMeasurerAdapter {
562                                tree: &mut app.tree,
563                                scale_factor: app.window.scale_factor(),
564                            };
565                            let processed_events = events_measurer_adapter.run(
566                                &mut vec![platform_event],
567                                &mut app.nodes_state,
568                                app.accessibility.focused_node_id(),
569                            );
570                            app.events_sender
571                                .unbounded_send(EventsChunk::Processed(processed_events))
572                                .unwrap();
573                        }
574                    }
575                }
576            }
577        }
578    }
579
580    fn window_event(
581        &mut self,
582        event_loop: &winit::event_loop::ActiveEventLoop,
583        window_id: winit::window::WindowId,
584        event: winit::event::WindowEvent,
585    ) {
586        if let Some(app) = &mut self.windows.get_mut(&window_id) {
587            app.accessibility_adapter.process_event(&app.window, &event);
588            match event {
589                WindowEvent::ThemeChanged(theme) => {
590                    app.platform.preferred_theme.set(match theme {
591                        Theme::Light => PreferredTheme::Light,
592                        Theme::Dark => PreferredTheme::Dark,
593                    });
594                }
595                WindowEvent::ScaleFactorChanged { .. } => {
596                    app.window.request_redraw();
597                    app.process_layout_on_next_render = true;
598                    app.tree.layout.reset();
599                }
600                WindowEvent::CloseRequested => {
601                    let mut on_close_hook = self
602                        .windows
603                        .get_mut(&window_id)
604                        .and_then(|app| app.on_close.take());
605
606                    let decision = if let Some(ref mut on_close) = on_close_hook {
607                        let renderer_context = RendererContext {
608                            fallback_fonts: &mut self.fallback_fonts,
609                            active_event_loop: event_loop,
610                            windows: &mut self.windows,
611                            proxy: &mut self.proxy,
612                            plugins: &mut self.plugins,
613                            screen_reader: &mut self.screen_reader,
614                            font_manager: &mut self.font_manager,
615                            font_collection: &mut self.font_collection,
616                        };
617                        on_close(renderer_context, window_id)
618                    } else {
619                        CloseDecision::Close
620                    };
621
622                    if matches!(decision, CloseDecision::KeepOpen)
623                        && let Some(app) = self.windows.get_mut(&window_id)
624                    {
625                        app.on_close = on_close_hook;
626                    }
627
628                    if matches!(decision, CloseDecision::Close) {
629                        self.windows.remove(&window_id);
630                        let has_windows = !self.windows.is_empty();
631
632                        let has_tray = {
633                            #[cfg(feature = "tray")]
634                            {
635                                self.tray.1.is_some()
636                            }
637                            #[cfg(not(feature = "tray"))]
638                            {
639                                false
640                            }
641                        };
642
643                        // Only exit when there is no windows and no tray
644                        if !has_windows && !has_tray {
645                            event_loop.exit();
646                        }
647                    }
648                }
649                WindowEvent::ModifiersChanged(modifiers) => {
650                    app.modifiers_state = modifiers.state();
651                }
652                WindowEvent::RedrawRequested => {
653                    hotpath::measure_block!("RedrawRequested", {
654                        if app.process_layout_on_next_render {
655                            self.plugins.send(
656                                PluginEvent::StartedMeasuringLayout {
657                                    window: &app.window,
658                                    tree: &app.tree,
659                                },
660                                PluginHandle::new(&self.proxy),
661                            );
662                            let size: Size2D = (
663                                app.window.inner_size().width as f32,
664                                app.window.inner_size().height as f32,
665                            )
666                                .into();
667
668                            app.tree.measure_layout(
669                                size,
670                                &self.font_collection,
671                                &self.font_manager,
672                                &app.events_sender,
673                                app.window.scale_factor(),
674                                &self.fallback_fonts,
675                            );
676                            app.platform.root_size.set_if_modified(size);
677                            app.process_layout_on_next_render = false;
678                            self.plugins.send(
679                                PluginEvent::FinishedMeasuringLayout {
680                                    window: &app.window,
681                                    tree: &app.tree,
682                                },
683                                PluginHandle::new(&self.proxy),
684                            );
685                        }
686
687                        app.driver.present(
688                            app.window.inner_size().cast(),
689                            &app.window,
690                            |surface| {
691                                self.plugins.send(
692                                    PluginEvent::BeforeRender {
693                                        window: &app.window,
694                                        canvas: surface.canvas(),
695                                        font_collection: &self.font_collection,
696                                        tree: &app.tree,
697                                    },
698                                    PluginHandle::new(&self.proxy),
699                                );
700
701                                let render_pipeline = RenderPipeline {
702                                    font_collection: &mut self.font_collection,
703                                    font_manager: &self.font_manager,
704                                    tree: &app.tree,
705                                    canvas: surface.canvas(),
706                                    scale_factor: app.window.scale_factor(),
707                                    background: app.background,
708                                };
709
710                                render_pipeline.render();
711
712                                self.plugins.send(
713                                    PluginEvent::AfterRender {
714                                        window: &app.window,
715                                        canvas: surface.canvas(),
716                                        font_collection: &self.font_collection,
717                                        tree: &app.tree,
718                                        animation_clock: &app.animation_clock,
719                                    },
720                                    PluginHandle::new(&self.proxy),
721                                );
722                                self.plugins.send(
723                                    PluginEvent::BeforePresenting {
724                                        window: &app.window,
725                                        font_collection: &self.font_collection,
726                                        tree: &app.tree,
727                                    },
728                                    PluginHandle::new(&self.proxy),
729                                );
730                            },
731                        );
732                        self.plugins.send(
733                            PluginEvent::AfterPresenting {
734                                window: &app.window,
735                                font_collection: &self.font_collection,
736                                tree: &app.tree,
737                            },
738                            PluginHandle::new(&self.proxy),
739                        );
740
741                        self.plugins.send(
742                            PluginEvent::BeforeAccessibility {
743                                window: &app.window,
744                                font_collection: &self.font_collection,
745                                tree: &app.tree,
746                            },
747                            PluginHandle::new(&self.proxy),
748                        );
749
750                        match app.accessibility_tasks_for_next_render.take() {
751                            AccessibilityTask::ProcessUpdate { mode } => {
752                                let update = app
753                                    .accessibility
754                                    .process_updates(&mut app.tree, &app.events_sender);
755                                app.platform
756                                    .focused_accessibility_id
757                                    .set_if_modified(update.focus);
758                                let node_id = app.accessibility.focused_node_id().unwrap();
759                                let layout_node = app.tree.layout.get(&node_id).unwrap();
760                                app.platform.focused_accessibility_node.set_if_modified(
761                                    AccessibilityTree::create_node(node_id, layout_node, &app.tree),
762                                );
763                                if let Some(mode) = mode {
764                                    app.platform.navigation_mode.set(mode);
765                                }
766
767                                let area = layout_node.visible_area();
768                                app.window.set_ime_cursor_area(
769                                    LogicalPosition::new(area.min_x(), area.min_y()),
770                                    LogicalSize::new(area.width(), area.height()),
771                                );
772
773                                app.accessibility_adapter.update_if_active(|| update);
774                            }
775                            AccessibilityTask::Init => {
776                                let update = app.accessibility.init(&mut app.tree);
777                                app.platform
778                                    .focused_accessibility_id
779                                    .set_if_modified(update.focus);
780                                let node_id = app.accessibility.focused_node_id().unwrap();
781                                let layout_node = app.tree.layout.get(&node_id).unwrap();
782                                app.platform.focused_accessibility_node.set_if_modified(
783                                    AccessibilityTree::create_node(node_id, layout_node, &app.tree),
784                                );
785
786                                let area = layout_node.visible_area();
787                                app.window.set_ime_cursor_area(
788                                    LogicalPosition::new(area.min_x(), area.min_y()),
789                                    LogicalSize::new(area.width(), area.height()),
790                                );
791
792                                app.accessibility_adapter.update_if_active(|| update);
793                            }
794                            AccessibilityTask::None => {}
795                        }
796
797                        self.plugins.send(
798                            PluginEvent::AfterAccessibility {
799                                window: &app.window,
800                                font_collection: &self.font_collection,
801                                tree: &app.tree,
802                            },
803                            PluginHandle::new(&self.proxy),
804                        );
805
806                        if app.ticker_sender.receiver_count() > 0 {
807                            app.ticker_sender.broadcast_blocking(()).unwrap();
808                        }
809
810                        self.plugins.send(
811                            PluginEvent::AfterRedraw {
812                                window: &app.window,
813                                font_collection: &self.font_collection,
814                                tree: &app.tree,
815                            },
816                            PluginHandle::new(&self.proxy),
817                        );
818                    });
819                }
820                WindowEvent::Resized(size) => {
821                    app.driver.resize(size);
822
823                    app.window.request_redraw();
824
825                    app.process_layout_on_next_render = true;
826                    app.tree.layout.clear_dirty();
827                    app.tree.layout.invalidate(NodeId::ROOT);
828                }
829
830                WindowEvent::MouseInput { state, button, .. } => {
831                    app.mouse_state = state;
832                    app.platform
833                        .navigation_mode
834                        .set(NavigationMode::NotKeyboard);
835
836                    let name = if state == ElementState::Pressed {
837                        MouseEventName::MouseDown
838                    } else {
839                        MouseEventName::MouseUp
840                    };
841                    let platform_event = PlatformEvent::Mouse {
842                        name,
843                        cursor: (app.position.x, app.position.y).into(),
844                        button: Some(map_winit_mouse_button(button)),
845                    };
846                    let mut events_measurer_adapter = EventsMeasurerAdapter {
847                        tree: &mut app.tree,
848                        scale_factor: app.window.scale_factor(),
849                    };
850                    let processed_events = events_measurer_adapter.run(
851                        &mut vec![platform_event],
852                        &mut app.nodes_state,
853                        app.accessibility.focused_node_id(),
854                    );
855                    app.events_sender
856                        .unbounded_send(EventsChunk::Processed(processed_events))
857                        .unwrap();
858                }
859
860                WindowEvent::KeyboardInput { event, .. } => {
861                    let name = match event.state {
862                        ElementState::Pressed => KeyboardEventName::KeyDown,
863                        ElementState::Released => KeyboardEventName::KeyUp,
864                    };
865                    let platform_event = PlatformEvent::Keyboard {
866                        name,
867                        key: winit_mappings::map_winit_key(&event.logical_key),
868                        code: winit_mappings::map_winit_physical_key(&event.physical_key),
869                        modifiers: winit_mappings::map_winit_modifiers(app.modifiers_state),
870                    };
871                    let mut events_measurer_adapter = EventsMeasurerAdapter {
872                        tree: &mut app.tree,
873                        scale_factor: app.window.scale_factor(),
874                    };
875                    let processed_events = events_measurer_adapter.run(
876                        &mut vec![platform_event],
877                        &mut app.nodes_state,
878                        app.accessibility.focused_node_id(),
879                    );
880                    app.events_sender
881                        .unbounded_send(EventsChunk::Processed(processed_events))
882                        .unwrap();
883                }
884
885                WindowEvent::MouseWheel { delta, phase, .. } => {
886                    const WHEEL_SPEED_MODIFIER: f64 = 53.0;
887                    const TOUCHPAD_SPEED_MODIFIER: f64 = 2.0;
888
889                    if TouchPhase::Moved == phase {
890                        let scroll_data = {
891                            match delta {
892                                MouseScrollDelta::LineDelta(x, y) => (
893                                    (x as f64 * WHEEL_SPEED_MODIFIER),
894                                    (y as f64 * WHEEL_SPEED_MODIFIER),
895                                ),
896                                MouseScrollDelta::PixelDelta(pos) => (
897                                    (pos.x * TOUCHPAD_SPEED_MODIFIER),
898                                    (pos.y * TOUCHPAD_SPEED_MODIFIER),
899                                ),
900                            }
901                        };
902
903                        let platform_event = PlatformEvent::Wheel {
904                            name: WheelEventName::Wheel,
905                            scroll: scroll_data.into(),
906                            cursor: app.position,
907                            source: WheelSource::Device,
908                        };
909                        let mut events_measurer_adapter = EventsMeasurerAdapter {
910                            tree: &mut app.tree,
911                            scale_factor: app.window.scale_factor(),
912                        };
913                        let processed_events = events_measurer_adapter.run(
914                            &mut vec![platform_event],
915                            &mut app.nodes_state,
916                            app.accessibility.focused_node_id(),
917                        );
918                        app.events_sender
919                            .unbounded_send(EventsChunk::Processed(processed_events))
920                            .unwrap();
921                    }
922                }
923
924                WindowEvent::CursorLeft { .. } => {
925                    if app.mouse_state == ElementState::Released {
926                        app.position = CursorPoint::from((-1., -1.));
927                        let platform_event = PlatformEvent::Mouse {
928                            name: MouseEventName::MouseMove,
929                            cursor: app.position,
930                            button: None,
931                        };
932                        let mut events_measurer_adapter = EventsMeasurerAdapter {
933                            tree: &mut app.tree,
934                            scale_factor: app.window.scale_factor(),
935                        };
936                        let processed_events = events_measurer_adapter.run(
937                            &mut vec![platform_event],
938                            &mut app.nodes_state,
939                            app.accessibility.focused_node_id(),
940                        );
941                        app.events_sender
942                            .unbounded_send(EventsChunk::Processed(processed_events))
943                            .unwrap();
944                    }
945                }
946                WindowEvent::CursorMoved { position, .. } => {
947                    app.position = CursorPoint::from((position.x, position.y));
948
949                    let mut platform_event = vec![PlatformEvent::Mouse {
950                        name: MouseEventName::MouseMove,
951                        cursor: app.position,
952                        button: None,
953                    }];
954
955                    for dropped_file_path in app.dropped_file_paths.drain(..) {
956                        platform_event.push(PlatformEvent::File {
957                            name: FileEventName::FileDrop,
958                            file_path: Some(dropped_file_path),
959                            cursor: app.position,
960                        });
961                    }
962
963                    let mut events_measurer_adapter = EventsMeasurerAdapter {
964                        tree: &mut app.tree,
965                        scale_factor: app.window.scale_factor(),
966                    };
967                    let processed_events = events_measurer_adapter.run(
968                        &mut platform_event,
969                        &mut app.nodes_state,
970                        app.accessibility.focused_node_id(),
971                    );
972                    app.events_sender
973                        .unbounded_send(EventsChunk::Processed(processed_events))
974                        .unwrap();
975                }
976
977                WindowEvent::Touch(Touch {
978                    location,
979                    phase,
980                    id,
981                    force,
982                    ..
983                }) => {
984                    app.position = CursorPoint::from((location.x, location.y));
985
986                    let name = match phase {
987                        TouchPhase::Cancelled => TouchEventName::TouchCancel,
988                        TouchPhase::Ended => TouchEventName::TouchEnd,
989                        TouchPhase::Moved => TouchEventName::TouchMove,
990                        TouchPhase::Started => TouchEventName::TouchStart,
991                    };
992
993                    let platform_event = PlatformEvent::Touch {
994                        name,
995                        location: app.position,
996                        finger_id: id,
997                        phase: map_winit_touch_phase(phase),
998                        force: force.map(map_winit_touch_force),
999                    };
1000                    let mut events_measurer_adapter = EventsMeasurerAdapter {
1001                        tree: &mut app.tree,
1002                        scale_factor: app.window.scale_factor(),
1003                    };
1004                    let processed_events = events_measurer_adapter.run(
1005                        &mut vec![platform_event],
1006                        &mut app.nodes_state,
1007                        app.accessibility.focused_node_id(),
1008                    );
1009                    app.events_sender
1010                        .unbounded_send(EventsChunk::Processed(processed_events))
1011                        .unwrap();
1012                    app.position = CursorPoint::from((location.x, location.y));
1013                }
1014                WindowEvent::Ime(Ime::Preedit(text, pos)) => {
1015                    let platform_event = PlatformEvent::ImePreedit {
1016                        name: ImeEventName::Preedit,
1017                        text,
1018                        cursor: pos,
1019                    };
1020                    let mut events_measurer_adapter = EventsMeasurerAdapter {
1021                        tree: &mut app.tree,
1022                        scale_factor: app.window.scale_factor(),
1023                    };
1024                    let processed_events = events_measurer_adapter.run(
1025                        &mut vec![platform_event],
1026                        &mut app.nodes_state,
1027                        app.accessibility.focused_node_id(),
1028                    );
1029                    app.events_sender
1030                        .unbounded_send(EventsChunk::Processed(processed_events))
1031                        .unwrap();
1032                }
1033                WindowEvent::DroppedFile(file_path) => {
1034                    app.dropped_file_paths.push(file_path);
1035                }
1036                WindowEvent::HoveredFile(file_path) => {
1037                    let platform_event = PlatformEvent::File {
1038                        name: FileEventName::FileHover,
1039                        file_path: Some(file_path),
1040                        cursor: app.position,
1041                    };
1042                    let mut events_measurer_adapter = EventsMeasurerAdapter {
1043                        tree: &mut app.tree,
1044                        scale_factor: app.window.scale_factor(),
1045                    };
1046                    let processed_events = events_measurer_adapter.run(
1047                        &mut vec![platform_event],
1048                        &mut app.nodes_state,
1049                        app.accessibility.focused_node_id(),
1050                    );
1051                    app.events_sender
1052                        .unbounded_send(EventsChunk::Processed(processed_events))
1053                        .unwrap();
1054                }
1055                WindowEvent::HoveredFileCancelled => {
1056                    let platform_event = PlatformEvent::File {
1057                        name: FileEventName::FileHoverCancelled,
1058                        file_path: None,
1059                        cursor: app.position,
1060                    };
1061                    let mut events_measurer_adapter = EventsMeasurerAdapter {
1062                        tree: &mut app.tree,
1063                        scale_factor: app.window.scale_factor(),
1064                    };
1065                    let processed_events = events_measurer_adapter.run(
1066                        &mut vec![platform_event],
1067                        &mut app.nodes_state,
1068                        app.accessibility.focused_node_id(),
1069                    );
1070                    app.events_sender
1071                        .unbounded_send(EventsChunk::Processed(processed_events))
1072                        .unwrap();
1073                }
1074                _ => {}
1075            }
1076        }
1077    }
1078}