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: Send + 'static>(&self, f: F) -> futures_channel::oneshot::Receiver<T>
174    where
175        F: FnOnce(&mut RendererContext) -> T + Send + '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) + Send + '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#[derive(Debug)]
239pub enum NativeEvent {
240    Window(NativeWindowEvent),
241    #[cfg(feature = "tray")]
242    Tray(NativeTrayEvent),
243    Generic(NativeGenericEvent),
244}
245
246impl From<accesskit_winit::Event> for NativeEvent {
247    fn from(event: accesskit_winit::Event) -> Self {
248        NativeEvent::Window(NativeWindowEvent {
249            window_id: event.window_id,
250            action: NativeWindowEventAction::Accessibility(event.window_event),
251        })
252    }
253}
254
255impl ApplicationHandler<NativeEvent> for WinitRenderer {
256    fn resumed(&mut self, active_event_loop: &winit::event_loop::ActiveEventLoop) {
257        if !self.resumed {
258            #[cfg(feature = "tray")]
259            {
260                #[cfg(not(target_os = "linux"))]
261                if let Some(tray_icon) = self.tray.0.take() {
262                    self.tray_icon = Some((tray_icon)());
263                }
264
265                #[cfg(target_os = "macos")]
266                {
267                    use objc2_core_foundation::CFRunLoop;
268
269                    let rl = CFRunLoop::main().expect("Failed to run CFRunLoop");
270                    CFRunLoop::wake_up(&rl);
271                }
272            }
273
274            for window_config in self.windows_configs.drain(..) {
275                let app_window = AppWindow::new(
276                    window_config,
277                    active_event_loop,
278                    &self.proxy,
279                    &mut self.plugins,
280                    &self.font_collection,
281                    &self.font_manager,
282                    &self.fallback_fonts,
283                    self.screen_reader.clone(),
284                );
285
286                self.proxy
287                    .send_event(NativeEvent::Window(NativeWindowEvent {
288                        window_id: app_window.window.id(),
289                        action: NativeWindowEventAction::PollRunner,
290                    }))
291                    .ok();
292
293                self.windows.insert(app_window.window.id(), app_window);
294            }
295            self.resumed = true;
296
297            let _ = self
298                .proxy
299                .send_event(NativeEvent::Generic(NativeGenericEvent::PollFutures));
300        }
301    }
302
303    fn user_event(
304        &mut self,
305        active_event_loop: &winit::event_loop::ActiveEventLoop,
306        event: NativeEvent,
307    ) {
308        match event {
309            NativeEvent::Generic(NativeGenericEvent::RendererCallback(cb)) => {
310                let mut renderer_context = RendererContext {
311                    fallback_fonts: &mut self.fallback_fonts,
312                    active_event_loop,
313                    windows: &mut self.windows,
314                    proxy: &mut self.proxy,
315                    plugins: &mut self.plugins,
316                    screen_reader: &mut self.screen_reader,
317                    font_manager: &mut self.font_manager,
318                    font_collection: &mut self.font_collection,
319                };
320                (cb)(&mut renderer_context);
321            }
322            NativeEvent::Generic(NativeGenericEvent::PollFutures) => {
323                let mut cx = std::task::Context::from_waker(&self.waker);
324                self.futures
325                    .retain_mut(|fut| fut.poll(&mut cx).is_pending());
326            }
327            #[cfg(feature = "tray")]
328            NativeEvent::Tray(NativeTrayEvent { action }) => {
329                let renderer_context = RendererContext {
330                    fallback_fonts: &mut self.fallback_fonts,
331                    active_event_loop,
332                    windows: &mut self.windows,
333                    proxy: &mut self.proxy,
334                    plugins: &mut self.plugins,
335                    screen_reader: &mut self.screen_reader,
336                    font_manager: &mut self.font_manager,
337                    font_collection: &mut self.font_collection,
338                };
339                match action {
340                    NativeTrayEventAction::TrayEvent(icon_event) => {
341                        use crate::tray::TrayEvent;
342                        if let Some(tray_handler) = &mut self.tray.1 {
343                            (tray_handler)(TrayEvent::Icon(icon_event), renderer_context)
344                        }
345                    }
346                    NativeTrayEventAction::MenuEvent(menu_event) => {
347                        use crate::tray::TrayEvent;
348                        if let Some(tray_handler) = &mut self.tray.1 {
349                            (tray_handler)(TrayEvent::Menu(menu_event), renderer_context)
350                        }
351                    }
352                    NativeTrayEventAction::LaunchWindow(data) => {
353                        let window_config = data
354                            .0
355                            .downcast::<WindowConfig>()
356                            .expect("Expected WindowConfig");
357                        let app_window = AppWindow::new(
358                            *window_config,
359                            active_event_loop,
360                            &self.proxy,
361                            &mut self.plugins,
362                            &self.font_collection,
363                            &self.font_manager,
364                            &self.fallback_fonts,
365                            self.screen_reader.clone(),
366                        );
367
368                        self.proxy
369                            .send_event(NativeEvent::Window(NativeWindowEvent {
370                                window_id: app_window.window.id(),
371                                action: NativeWindowEventAction::PollRunner,
372                            }))
373                            .ok();
374
375                        self.windows.insert(app_window.window.id(), app_window);
376                    }
377                }
378            }
379            NativeEvent::Window(NativeWindowEvent { action, window_id }) => {
380                if let Some(app) = &mut self.windows.get_mut(&window_id) {
381                    match action {
382                        NativeWindowEventAction::PollRunner => {
383                            let mut cx = std::task::Context::from_waker(&app.waker);
384
385                            {
386                                let fut = std::pin::pin!(async {
387                                    select! {
388                                        events_chunk = app.events_receiver.next() => {
389                                            match events_chunk {
390                                                Some(EventsChunk::Processed(processed_events)) => {
391                                                    let events_executor_adapter = EventsExecutorAdapter {
392                                                        runner: &mut app.runner,
393                                                    };
394                                                    events_executor_adapter.run(&mut app.nodes_state, processed_events);
395                                                }
396                                                Some(EventsChunk::Batch(events)) => {
397                                                    for event in events {
398                                                        app.runner.handle_event(event.node_id, event.name, event.data, event.bubbles);
399                                                    }
400                                                }
401                                                _ => {}
402                                            }
403
404                                        },
405                                         _ = app.runner.handle_events().fuse() => {},
406                                    }
407                                });
408
409                                match fut.poll(&mut cx) {
410                                    std::task::Poll::Ready(_) => {
411                                        self.proxy
412                                            .send_event(NativeEvent::Window(NativeWindowEvent {
413                                                window_id: app.window.id(),
414                                                action: NativeWindowEventAction::PollRunner,
415                                            }))
416                                            .ok();
417                                    }
418                                    std::task::Poll::Pending => {}
419                                }
420                            }
421
422                            self.plugins.send(
423                                PluginEvent::StartedUpdatingTree {
424                                    window: &app.window,
425                                    tree: &app.tree,
426                                },
427                                PluginHandle::new(&self.proxy),
428                            );
429                            let mutations = app.runner.sync_and_update();
430                            let result = app.tree.apply_mutations(mutations);
431                            if result.needs_render {
432                                app.process_layout_on_next_render = true;
433                                app.window.request_redraw();
434                            }
435                            self.plugins.send(
436                                PluginEvent::FinishedUpdatingTree {
437                                    window: &app.window,
438                                    tree: &app.tree,
439                                },
440                                PluginHandle::new(&self.proxy),
441                            );
442                            #[cfg(debug_assertions)]
443                            {
444                                tracing::info!("Updated app tree.");
445                                tracing::info!("{:#?}", app.tree);
446                                tracing::info!("{:#?}", app.runner);
447                            }
448                        }
449                        NativeWindowEventAction::Accessibility(
450                            accesskit_winit::WindowEvent::AccessibilityDeactivated,
451                        ) => {
452                            self.screen_reader.set(false);
453                        }
454                        NativeWindowEventAction::Accessibility(
455                            accesskit_winit::WindowEvent::ActionRequested(_),
456                        ) => {}
457                        NativeWindowEventAction::Accessibility(
458                            accesskit_winit::WindowEvent::InitialTreeRequested,
459                        ) => {
460                            app.accessibility_tasks_for_next_render = AccessibilityTask::Init;
461                            app.window.request_redraw();
462                            self.screen_reader.set(true);
463                        }
464                        NativeWindowEventAction::User(user_event) => match user_event {
465                            UserEvent::RequestRedraw => {
466                                app.window.request_redraw();
467                            }
468                            UserEvent::FocusAccessibilityNode(strategy) => {
469                                let task = match strategy {
470                                    AccessibilityFocusStrategy::Backward(_)
471                                    | AccessibilityFocusStrategy::Forward(_) => {
472                                        AccessibilityTask::ProcessUpdate {
473                                            mode: Some(NavigationMode::Keyboard),
474                                        }
475                                    }
476                                    _ => AccessibilityTask::ProcessUpdate { mode: None },
477                                };
478                                app.tree.accessibility_diff.request_focus(strategy);
479                                app.accessibility_tasks_for_next_render = task;
480                                app.window.request_redraw();
481                            }
482                            UserEvent::SetCursorIcon(cursor_icon) => {
483                                app.window.set_cursor(cursor_icon);
484                            }
485                            UserEvent::Erased(data) => {
486                                let action = data
487                                    .0
488                                    .downcast::<NativeWindowErasedEventAction>()
489                                    .expect("Expected NativeWindowErasedEventAction");
490                                match *action {
491                                    NativeWindowErasedEventAction::LaunchWindow {
492                                        window_config,
493                                        ack,
494                                    } => {
495                                        let app_window = AppWindow::new(
496                                            window_config,
497                                            active_event_loop,
498                                            &self.proxy,
499                                            &mut self.plugins,
500                                            &self.font_collection,
501                                            &self.font_manager,
502                                            &self.fallback_fonts,
503                                            self.screen_reader.clone(),
504                                        );
505
506                                        let window_id = app_window.window.id();
507
508                                        let _ = self.proxy.send_event(NativeEvent::Window(
509                                            NativeWindowEvent {
510                                                window_id,
511                                                action: NativeWindowEventAction::PollRunner,
512                                            },
513                                        ));
514
515                                        self.windows.insert(window_id, app_window);
516                                        let _ = ack.send(window_id);
517                                    }
518                                    NativeWindowErasedEventAction::CloseWindow(window_id) => {
519                                        // Its fine to ignore if the window doesnt exist anymore
520                                        let _ = self.windows.remove(&window_id);
521                                        let has_windows = !self.windows.is_empty();
522
523                                        let has_tray = {
524                                            #[cfg(feature = "tray")]
525                                            {
526                                                self.tray.1.is_some()
527                                            }
528                                            #[cfg(not(feature = "tray"))]
529                                            {
530                                                false
531                                            }
532                                        };
533
534                                        // Only exit when there is no window and no tray
535                                        if !has_windows && !has_tray {
536                                            active_event_loop.exit();
537                                        }
538                                    }
539                                    NativeWindowErasedEventAction::WithWindow {
540                                        window_id,
541                                        callback,
542                                    } => {
543                                        if let Some(window_id) = window_id {
544                                            if let Some(app) = self.windows.get_mut(&window_id) {
545                                                (callback.0)(&mut app.window)
546                                            }
547                                        } else {
548                                            (callback.0)(&mut app.window)
549                                        }
550                                    }
551                                }
552                            }
553                        },
554                        NativeWindowEventAction::PlatformEvent(platform_event) => {
555                            let mut events_measurer_adapter = EventsMeasurerAdapter {
556                                tree: &mut app.tree,
557                                scale_factor: app.window.scale_factor(),
558                            };
559                            let processed_events = events_measurer_adapter.run(
560                                &mut vec![platform_event],
561                                &mut app.nodes_state,
562                                app.accessibility.focused_node_id(),
563                            );
564                            app.events_sender
565                                .unbounded_send(EventsChunk::Processed(processed_events))
566                                .unwrap();
567                        }
568                    }
569                }
570            }
571        }
572    }
573
574    fn window_event(
575        &mut self,
576        event_loop: &winit::event_loop::ActiveEventLoop,
577        window_id: winit::window::WindowId,
578        event: winit::event::WindowEvent,
579    ) {
580        if let Some(app) = &mut self.windows.get_mut(&window_id) {
581            app.accessibility_adapter.process_event(&app.window, &event);
582            match event {
583                WindowEvent::ThemeChanged(theme) => {
584                    app.platform.preferred_theme.set(match theme {
585                        Theme::Light => PreferredTheme::Light,
586                        Theme::Dark => PreferredTheme::Dark,
587                    });
588                }
589                WindowEvent::ScaleFactorChanged { .. } => {
590                    app.window.request_redraw();
591                    app.process_layout_on_next_render = true;
592                    app.tree.layout.reset();
593                }
594                WindowEvent::CloseRequested => {
595                    let mut on_close_hook = self
596                        .windows
597                        .get_mut(&window_id)
598                        .and_then(|app| app.on_close.take());
599
600                    let decision = if let Some(ref mut on_close) = on_close_hook {
601                        let renderer_context = RendererContext {
602                            fallback_fonts: &mut self.fallback_fonts,
603                            active_event_loop: event_loop,
604                            windows: &mut self.windows,
605                            proxy: &mut self.proxy,
606                            plugins: &mut self.plugins,
607                            screen_reader: &mut self.screen_reader,
608                            font_manager: &mut self.font_manager,
609                            font_collection: &mut self.font_collection,
610                        };
611                        on_close(renderer_context, window_id)
612                    } else {
613                        CloseDecision::Close
614                    };
615
616                    if matches!(decision, CloseDecision::KeepOpen)
617                        && let Some(app) = self.windows.get_mut(&window_id)
618                    {
619                        app.on_close = on_close_hook;
620                    }
621
622                    if matches!(decision, CloseDecision::Close) {
623                        self.windows.remove(&window_id);
624                        let has_windows = !self.windows.is_empty();
625
626                        let has_tray = {
627                            #[cfg(feature = "tray")]
628                            {
629                                self.tray.1.is_some()
630                            }
631                            #[cfg(not(feature = "tray"))]
632                            {
633                                false
634                            }
635                        };
636
637                        // Only exit when there is no windows and no tray
638                        if !has_windows && !has_tray {
639                            event_loop.exit();
640                        }
641                    }
642                }
643                WindowEvent::ModifiersChanged(modifiers) => {
644                    app.modifiers_state = modifiers.state();
645                }
646                WindowEvent::RedrawRequested => {
647                    hotpath::measure_block!("RedrawRequested", {
648                        if app.process_layout_on_next_render {
649                            self.plugins.send(
650                                PluginEvent::StartedMeasuringLayout {
651                                    window: &app.window,
652                                    tree: &app.tree,
653                                },
654                                PluginHandle::new(&self.proxy),
655                            );
656                            let size: Size2D = (
657                                app.window.inner_size().width as f32,
658                                app.window.inner_size().height as f32,
659                            )
660                                .into();
661
662                            app.tree.measure_layout(
663                                size,
664                                &self.font_collection,
665                                &self.font_manager,
666                                &app.events_sender,
667                                app.window.scale_factor(),
668                                &self.fallback_fonts,
669                            );
670                            app.platform.root_size.set_if_modified(size);
671                            app.process_layout_on_next_render = false;
672                            self.plugins.send(
673                                PluginEvent::FinishedMeasuringLayout {
674                                    window: &app.window,
675                                    tree: &app.tree,
676                                },
677                                PluginHandle::new(&self.proxy),
678                            );
679                        }
680
681                        app.driver.present(
682                            app.window.inner_size().cast(),
683                            &app.window,
684                            |surface| {
685                                self.plugins.send(
686                                    PluginEvent::BeforeRender {
687                                        window: &app.window,
688                                        canvas: surface.canvas(),
689                                        font_collection: &self.font_collection,
690                                        tree: &app.tree,
691                                    },
692                                    PluginHandle::new(&self.proxy),
693                                );
694
695                                let render_pipeline = RenderPipeline {
696                                    font_collection: &mut self.font_collection,
697                                    font_manager: &self.font_manager,
698                                    tree: &app.tree,
699                                    canvas: surface.canvas(),
700                                    scale_factor: app.window.scale_factor(),
701                                    background: app.background,
702                                };
703
704                                render_pipeline.render();
705
706                                self.plugins.send(
707                                    PluginEvent::AfterRender {
708                                        window: &app.window,
709                                        canvas: surface.canvas(),
710                                        font_collection: &self.font_collection,
711                                        tree: &app.tree,
712                                        animation_clock: &app.animation_clock,
713                                    },
714                                    PluginHandle::new(&self.proxy),
715                                );
716                                self.plugins.send(
717                                    PluginEvent::BeforePresenting {
718                                        window: &app.window,
719                                        font_collection: &self.font_collection,
720                                        tree: &app.tree,
721                                    },
722                                    PluginHandle::new(&self.proxy),
723                                );
724                            },
725                        );
726                        self.plugins.send(
727                            PluginEvent::AfterPresenting {
728                                window: &app.window,
729                                font_collection: &self.font_collection,
730                                tree: &app.tree,
731                            },
732                            PluginHandle::new(&self.proxy),
733                        );
734
735                        self.plugins.send(
736                            PluginEvent::BeforeAccessibility {
737                                window: &app.window,
738                                font_collection: &self.font_collection,
739                                tree: &app.tree,
740                            },
741                            PluginHandle::new(&self.proxy),
742                        );
743
744                        match app.accessibility_tasks_for_next_render.take() {
745                            AccessibilityTask::ProcessUpdate { mode } => {
746                                let update = app
747                                    .accessibility
748                                    .process_updates(&mut app.tree, &app.events_sender);
749                                app.platform
750                                    .focused_accessibility_id
751                                    .set_if_modified(update.focus);
752                                let node_id = app.accessibility.focused_node_id().unwrap();
753                                let layout_node = app.tree.layout.get(&node_id).unwrap();
754                                app.platform.focused_accessibility_node.set_if_modified(
755                                    AccessibilityTree::create_node(node_id, layout_node, &app.tree),
756                                );
757                                if let Some(mode) = mode {
758                                    app.platform.navigation_mode.set(mode);
759                                }
760
761                                let area = layout_node.visible_area();
762                                app.window.set_ime_cursor_area(
763                                    LogicalPosition::new(area.min_x(), area.min_y()),
764                                    LogicalSize::new(area.width(), area.height()),
765                                );
766
767                                app.accessibility_adapter.update_if_active(|| update);
768                            }
769                            AccessibilityTask::Init => {
770                                let update = app.accessibility.init(&mut app.tree);
771                                app.platform
772                                    .focused_accessibility_id
773                                    .set_if_modified(update.focus);
774                                let node_id = app.accessibility.focused_node_id().unwrap();
775                                let layout_node = app.tree.layout.get(&node_id).unwrap();
776                                app.platform.focused_accessibility_node.set_if_modified(
777                                    AccessibilityTree::create_node(node_id, layout_node, &app.tree),
778                                );
779
780                                let area = layout_node.visible_area();
781                                app.window.set_ime_cursor_area(
782                                    LogicalPosition::new(area.min_x(), area.min_y()),
783                                    LogicalSize::new(area.width(), area.height()),
784                                );
785
786                                app.accessibility_adapter.update_if_active(|| update);
787                            }
788                            AccessibilityTask::None => {}
789                        }
790
791                        self.plugins.send(
792                            PluginEvent::AfterAccessibility {
793                                window: &app.window,
794                                font_collection: &self.font_collection,
795                                tree: &app.tree,
796                            },
797                            PluginHandle::new(&self.proxy),
798                        );
799
800                        if app.ticker_sender.receiver_count() > 0 {
801                            app.ticker_sender.broadcast_blocking(()).unwrap();
802                        }
803
804                        self.plugins.send(
805                            PluginEvent::AfterRedraw {
806                                window: &app.window,
807                                font_collection: &self.font_collection,
808                                tree: &app.tree,
809                            },
810                            PluginHandle::new(&self.proxy),
811                        );
812                    });
813                }
814                WindowEvent::Resized(size) => {
815                    app.driver.resize(size);
816
817                    app.window.request_redraw();
818
819                    app.process_layout_on_next_render = true;
820                    app.tree.layout.clear_dirty();
821                    app.tree.layout.invalidate(NodeId::ROOT);
822                }
823
824                WindowEvent::MouseInput { state, button, .. } => {
825                    app.mouse_state = state;
826                    app.platform
827                        .navigation_mode
828                        .set(NavigationMode::NotKeyboard);
829
830                    let name = if state == ElementState::Pressed {
831                        MouseEventName::MouseDown
832                    } else {
833                        MouseEventName::MouseUp
834                    };
835                    let platform_event = PlatformEvent::Mouse {
836                        name,
837                        cursor: (app.position.x, app.position.y).into(),
838                        button: Some(map_winit_mouse_button(button)),
839                    };
840                    let mut events_measurer_adapter = EventsMeasurerAdapter {
841                        tree: &mut app.tree,
842                        scale_factor: app.window.scale_factor(),
843                    };
844                    let processed_events = events_measurer_adapter.run(
845                        &mut vec![platform_event],
846                        &mut app.nodes_state,
847                        app.accessibility.focused_node_id(),
848                    );
849                    app.events_sender
850                        .unbounded_send(EventsChunk::Processed(processed_events))
851                        .unwrap();
852                }
853
854                WindowEvent::KeyboardInput { event, .. } => {
855                    let name = match event.state {
856                        ElementState::Pressed => KeyboardEventName::KeyDown,
857                        ElementState::Released => KeyboardEventName::KeyUp,
858                    };
859                    let platform_event = PlatformEvent::Keyboard {
860                        name,
861                        key: winit_mappings::map_winit_key(&event.logical_key),
862                        code: winit_mappings::map_winit_physical_key(&event.physical_key),
863                        modifiers: winit_mappings::map_winit_modifiers(app.modifiers_state),
864                    };
865                    let mut events_measurer_adapter = EventsMeasurerAdapter {
866                        tree: &mut app.tree,
867                        scale_factor: app.window.scale_factor(),
868                    };
869                    let processed_events = events_measurer_adapter.run(
870                        &mut vec![platform_event],
871                        &mut app.nodes_state,
872                        app.accessibility.focused_node_id(),
873                    );
874                    app.events_sender
875                        .unbounded_send(EventsChunk::Processed(processed_events))
876                        .unwrap();
877                }
878
879                WindowEvent::MouseWheel { delta, phase, .. } => {
880                    const WHEEL_SPEED_MODIFIER: f64 = 53.0;
881                    const TOUCHPAD_SPEED_MODIFIER: f64 = 2.0;
882
883                    if TouchPhase::Moved == phase {
884                        let scroll_data = {
885                            match delta {
886                                MouseScrollDelta::LineDelta(x, y) => (
887                                    (x as f64 * WHEEL_SPEED_MODIFIER),
888                                    (y as f64 * WHEEL_SPEED_MODIFIER),
889                                ),
890                                MouseScrollDelta::PixelDelta(pos) => (
891                                    (pos.x * TOUCHPAD_SPEED_MODIFIER),
892                                    (pos.y * TOUCHPAD_SPEED_MODIFIER),
893                                ),
894                            }
895                        };
896
897                        let platform_event = PlatformEvent::Wheel {
898                            name: WheelEventName::Wheel,
899                            scroll: scroll_data.into(),
900                            cursor: app.position,
901                            source: WheelSource::Device,
902                        };
903                        let mut events_measurer_adapter = EventsMeasurerAdapter {
904                            tree: &mut app.tree,
905                            scale_factor: app.window.scale_factor(),
906                        };
907                        let processed_events = events_measurer_adapter.run(
908                            &mut vec![platform_event],
909                            &mut app.nodes_state,
910                            app.accessibility.focused_node_id(),
911                        );
912                        app.events_sender
913                            .unbounded_send(EventsChunk::Processed(processed_events))
914                            .unwrap();
915                    }
916                }
917
918                WindowEvent::CursorLeft { .. } => {
919                    if app.mouse_state == ElementState::Released {
920                        app.position = CursorPoint::from((-1., -1.));
921                        let platform_event = PlatformEvent::Mouse {
922                            name: MouseEventName::MouseMove,
923                            cursor: app.position,
924                            button: None,
925                        };
926                        let mut events_measurer_adapter = EventsMeasurerAdapter {
927                            tree: &mut app.tree,
928                            scale_factor: app.window.scale_factor(),
929                        };
930                        let processed_events = events_measurer_adapter.run(
931                            &mut vec![platform_event],
932                            &mut app.nodes_state,
933                            app.accessibility.focused_node_id(),
934                        );
935                        app.events_sender
936                            .unbounded_send(EventsChunk::Processed(processed_events))
937                            .unwrap();
938                    }
939                }
940                WindowEvent::CursorMoved { position, .. } => {
941                    app.position = CursorPoint::from((position.x, position.y));
942
943                    let mut platform_event = vec![PlatformEvent::Mouse {
944                        name: MouseEventName::MouseMove,
945                        cursor: app.position,
946                        button: None,
947                    }];
948
949                    for dropped_file_path in app.dropped_file_paths.drain(..) {
950                        platform_event.push(PlatformEvent::File {
951                            name: FileEventName::FileDrop,
952                            file_path: Some(dropped_file_path),
953                            cursor: app.position,
954                        });
955                    }
956
957                    let mut events_measurer_adapter = EventsMeasurerAdapter {
958                        tree: &mut app.tree,
959                        scale_factor: app.window.scale_factor(),
960                    };
961                    let processed_events = events_measurer_adapter.run(
962                        &mut platform_event,
963                        &mut app.nodes_state,
964                        app.accessibility.focused_node_id(),
965                    );
966                    app.events_sender
967                        .unbounded_send(EventsChunk::Processed(processed_events))
968                        .unwrap();
969                }
970
971                WindowEvent::Touch(Touch {
972                    location,
973                    phase,
974                    id,
975                    force,
976                    ..
977                }) => {
978                    app.position = CursorPoint::from((location.x, location.y));
979
980                    let name = match phase {
981                        TouchPhase::Cancelled => TouchEventName::TouchCancel,
982                        TouchPhase::Ended => TouchEventName::TouchEnd,
983                        TouchPhase::Moved => TouchEventName::TouchMove,
984                        TouchPhase::Started => TouchEventName::TouchStart,
985                    };
986
987                    let platform_event = PlatformEvent::Touch {
988                        name,
989                        location: app.position,
990                        finger_id: id,
991                        phase: map_winit_touch_phase(phase),
992                        force: force.map(map_winit_touch_force),
993                    };
994                    let mut events_measurer_adapter = EventsMeasurerAdapter {
995                        tree: &mut app.tree,
996                        scale_factor: app.window.scale_factor(),
997                    };
998                    let processed_events = events_measurer_adapter.run(
999                        &mut vec![platform_event],
1000                        &mut app.nodes_state,
1001                        app.accessibility.focused_node_id(),
1002                    );
1003                    app.events_sender
1004                        .unbounded_send(EventsChunk::Processed(processed_events))
1005                        .unwrap();
1006                    app.position = CursorPoint::from((location.x, location.y));
1007                }
1008                WindowEvent::Ime(Ime::Preedit(text, pos)) => {
1009                    let platform_event = PlatformEvent::ImePreedit {
1010                        name: ImeEventName::Preedit,
1011                        text,
1012                        cursor: pos,
1013                    };
1014                    let mut events_measurer_adapter = EventsMeasurerAdapter {
1015                        tree: &mut app.tree,
1016                        scale_factor: app.window.scale_factor(),
1017                    };
1018                    let processed_events = events_measurer_adapter.run(
1019                        &mut vec![platform_event],
1020                        &mut app.nodes_state,
1021                        app.accessibility.focused_node_id(),
1022                    );
1023                    app.events_sender
1024                        .unbounded_send(EventsChunk::Processed(processed_events))
1025                        .unwrap();
1026                }
1027                WindowEvent::DroppedFile(file_path) => {
1028                    app.dropped_file_paths.push(file_path);
1029                }
1030                WindowEvent::HoveredFile(file_path) => {
1031                    let platform_event = PlatformEvent::File {
1032                        name: FileEventName::FileHover,
1033                        file_path: Some(file_path),
1034                        cursor: app.position,
1035                    };
1036                    let mut events_measurer_adapter = EventsMeasurerAdapter {
1037                        tree: &mut app.tree,
1038                        scale_factor: app.window.scale_factor(),
1039                    };
1040                    let processed_events = events_measurer_adapter.run(
1041                        &mut vec![platform_event],
1042                        &mut app.nodes_state,
1043                        app.accessibility.focused_node_id(),
1044                    );
1045                    app.events_sender
1046                        .unbounded_send(EventsChunk::Processed(processed_events))
1047                        .unwrap();
1048                }
1049                WindowEvent::HoveredFileCancelled => {
1050                    let platform_event = PlatformEvent::File {
1051                        name: FileEventName::FileHoverCancelled,
1052                        file_path: None,
1053                        cursor: app.position,
1054                    };
1055                    let mut events_measurer_adapter = EventsMeasurerAdapter {
1056                        tree: &mut app.tree,
1057                        scale_factor: app.window.scale_factor(),
1058                    };
1059                    let processed_events = events_measurer_adapter.run(
1060                        &mut vec![platform_event],
1061                        &mut app.nodes_state,
1062                        app.accessibility.focused_node_id(),
1063                    );
1064                    app.events_sender
1065                        .unbounded_send(EventsChunk::Processed(processed_events))
1066                        .unwrap();
1067                }
1068                _ => {}
1069            }
1070        }
1071    }
1072}