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.runner.run_in(|| 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                            if result.needs_accessibility {
442                                app.accessibility_tasks_for_next_render |=
443                                    AccessibilityTask::ProcessUpdate { mode: None };
444                                app.window.request_redraw();
445                            }
446                            self.plugins.send(
447                                PluginEvent::FinishedUpdatingTree {
448                                    window: &app.window,
449                                    tree: &app.tree,
450                                },
451                                PluginHandle::new(&self.proxy),
452                            );
453                            #[cfg(debug_assertions)]
454                            {
455                                tracing::info!("Updated app tree.");
456                                tracing::info!("{:#?}", app.tree);
457                                tracing::info!("{:#?}", app.runner);
458                            }
459                        }
460                        NativeWindowEventAction::Accessibility(
461                            accesskit_winit::WindowEvent::AccessibilityDeactivated,
462                        ) => {
463                            self.screen_reader.set(false);
464                        }
465                        NativeWindowEventAction::Accessibility(
466                            accesskit_winit::WindowEvent::ActionRequested(_),
467                        ) => {}
468                        NativeWindowEventAction::Accessibility(
469                            accesskit_winit::WindowEvent::InitialTreeRequested,
470                        ) => {
471                            app.accessibility_tasks_for_next_render = AccessibilityTask::Init;
472                            app.window.request_redraw();
473                            self.screen_reader.set(true);
474                        }
475                        NativeWindowEventAction::User(user_event) => match user_event {
476                            UserEvent::RequestRedraw => {
477                                app.window.request_redraw();
478                            }
479                            UserEvent::FocusAccessibilityNode(strategy) => {
480                                let task = match strategy {
481                                    AccessibilityFocusStrategy::Backward(_)
482                                    | AccessibilityFocusStrategy::Forward(_) => {
483                                        AccessibilityTask::ProcessUpdate {
484                                            mode: Some(NavigationMode::Keyboard),
485                                        }
486                                    }
487                                    _ => AccessibilityTask::ProcessUpdate { mode: None },
488                                };
489                                app.tree.accessibility_diff.request_focus(strategy);
490                                app.accessibility_tasks_for_next_render = task;
491                                app.window.request_redraw();
492                            }
493                            UserEvent::SetCursorIcon(cursor_icon) => {
494                                app.window.set_cursor(cursor_icon);
495                            }
496                            UserEvent::Erased(data) => {
497                                let action = data
498                                    .0
499                                    .downcast::<NativeWindowErasedEventAction>()
500                                    .expect("Expected NativeWindowErasedEventAction");
501                                match *action {
502                                    NativeWindowErasedEventAction::LaunchWindow {
503                                        window_config,
504                                        ack,
505                                    } => {
506                                        let app_window = AppWindow::new(
507                                            window_config,
508                                            active_event_loop,
509                                            &self.proxy,
510                                            &mut self.plugins,
511                                            &self.font_collection,
512                                            &self.font_manager,
513                                            &self.fallback_fonts,
514                                            self.screen_reader.clone(),
515                                        );
516
517                                        let window_id = app_window.window.id();
518
519                                        let _ = self.proxy.send_event(NativeEvent::Window(
520                                            NativeWindowEvent {
521                                                window_id,
522                                                action: NativeWindowEventAction::PollRunner,
523                                            },
524                                        ));
525
526                                        self.windows.insert(window_id, app_window);
527                                        let _ = ack.send(window_id);
528                                    }
529                                    NativeWindowErasedEventAction::CloseWindow(window_id) => {
530                                        // Its fine to ignore if the window doesnt exist anymore
531                                        let _ = self.windows.remove(&window_id);
532                                        let has_windows = !self.windows.is_empty();
533
534                                        let has_tray = {
535                                            #[cfg(feature = "tray")]
536                                            {
537                                                self.tray.1.is_some()
538                                            }
539                                            #[cfg(not(feature = "tray"))]
540                                            {
541                                                false
542                                            }
543                                        };
544
545                                        // Only exit when there is no window and no tray
546                                        if !has_windows && !has_tray {
547                                            active_event_loop.exit();
548                                        }
549                                    }
550                                    NativeWindowErasedEventAction::WithWindow {
551                                        window_id,
552                                        callback,
553                                    } => {
554                                        if let Some(window_id) = window_id {
555                                            if let Some(app) = self.windows.get_mut(&window_id) {
556                                                (callback.0)(&mut app.window)
557                                            }
558                                        } else {
559                                            (callback.0)(&mut app.window)
560                                        }
561                                    }
562                                }
563                            }
564                        },
565                        NativeWindowEventAction::PlatformEvent(platform_event) => {
566                            let mut events_measurer_adapter = EventsMeasurerAdapter {
567                                tree: &mut app.tree,
568                                scale_factor: app.window.scale_factor(),
569                            };
570                            let processed_events = events_measurer_adapter.run(
571                                &mut vec![platform_event],
572                                &mut app.nodes_state,
573                                app.accessibility.focused_node_id(),
574                            );
575                            app.events_sender
576                                .unbounded_send(EventsChunk::Processed(processed_events))
577                                .unwrap();
578                        }
579                    }
580                }
581            }
582        }
583    }
584
585    fn window_event(
586        &mut self,
587        event_loop: &winit::event_loop::ActiveEventLoop,
588        window_id: winit::window::WindowId,
589        event: winit::event::WindowEvent,
590    ) {
591        if let Some(app) = &mut self.windows.get_mut(&window_id) {
592            app.accessibility_adapter.process_event(&app.window, &event);
593            match event {
594                WindowEvent::ThemeChanged(theme) => {
595                    app.platform.preferred_theme.set(match theme {
596                        Theme::Light => PreferredTheme::Light,
597                        Theme::Dark => PreferredTheme::Dark,
598                    });
599                }
600                WindowEvent::ScaleFactorChanged { .. } => {
601                    app.window.request_redraw();
602                    app.process_layout_on_next_render = true;
603                    app.tree.layout.reset();
604                }
605                WindowEvent::CloseRequested => {
606                    let mut on_close_hook = self
607                        .windows
608                        .get_mut(&window_id)
609                        .and_then(|app| app.on_close.take());
610
611                    let decision = if let Some(ref mut on_close) = on_close_hook {
612                        let renderer_context = RendererContext {
613                            fallback_fonts: &mut self.fallback_fonts,
614                            active_event_loop: event_loop,
615                            windows: &mut self.windows,
616                            proxy: &mut self.proxy,
617                            plugins: &mut self.plugins,
618                            screen_reader: &mut self.screen_reader,
619                            font_manager: &mut self.font_manager,
620                            font_collection: &mut self.font_collection,
621                        };
622                        on_close(renderer_context, window_id)
623                    } else {
624                        CloseDecision::Close
625                    };
626
627                    if matches!(decision, CloseDecision::KeepOpen)
628                        && let Some(app) = self.windows.get_mut(&window_id)
629                    {
630                        app.on_close = on_close_hook;
631                    }
632
633                    if matches!(decision, CloseDecision::Close) {
634                        self.windows.remove(&window_id);
635                        let has_windows = !self.windows.is_empty();
636
637                        let has_tray = {
638                            #[cfg(feature = "tray")]
639                            {
640                                self.tray.1.is_some()
641                            }
642                            #[cfg(not(feature = "tray"))]
643                            {
644                                false
645                            }
646                        };
647
648                        // Only exit when there is no windows and no tray
649                        if !has_windows && !has_tray {
650                            event_loop.exit();
651                        }
652                    }
653                }
654                WindowEvent::ModifiersChanged(modifiers) => {
655                    app.modifiers_state = modifiers.state();
656                }
657                WindowEvent::Focused(is_focused) => {
658                    app.just_focused = is_focused;
659                }
660                WindowEvent::RedrawRequested => {
661                    hotpath::measure_block!("RedrawRequested", {
662                        if app.process_layout_on_next_render {
663                            self.plugins.send(
664                                PluginEvent::StartedMeasuringLayout {
665                                    window: &app.window,
666                                    tree: &app.tree,
667                                },
668                                PluginHandle::new(&self.proxy),
669                            );
670                            let size: Size2D = (
671                                app.window.inner_size().width as f32,
672                                app.window.inner_size().height as f32,
673                            )
674                                .into();
675
676                            app.tree.measure_layout(
677                                size,
678                                &self.font_collection,
679                                &self.font_manager,
680                                &app.events_sender,
681                                app.window.scale_factor(),
682                                &self.fallback_fonts,
683                            );
684                            app.platform.root_size.set_if_modified(size);
685                            app.process_layout_on_next_render = false;
686                            self.plugins.send(
687                                PluginEvent::FinishedMeasuringLayout {
688                                    window: &app.window,
689                                    tree: &app.tree,
690                                },
691                                PluginHandle::new(&self.proxy),
692                            );
693                        }
694
695                        app.driver.present(
696                            app.window.inner_size().cast(),
697                            &app.window,
698                            |surface| {
699                                self.plugins.send(
700                                    PluginEvent::BeforeRender {
701                                        window: &app.window,
702                                        canvas: surface.canvas(),
703                                        font_collection: &self.font_collection,
704                                        tree: &app.tree,
705                                    },
706                                    PluginHandle::new(&self.proxy),
707                                );
708
709                                let render_pipeline = RenderPipeline {
710                                    font_collection: &mut self.font_collection,
711                                    font_manager: &self.font_manager,
712                                    tree: &app.tree,
713                                    canvas: surface.canvas(),
714                                    scale_factor: app.window.scale_factor(),
715                                    background: app.background,
716                                };
717
718                                render_pipeline.render();
719
720                                self.plugins.send(
721                                    PluginEvent::AfterRender {
722                                        window: &app.window,
723                                        canvas: surface.canvas(),
724                                        font_collection: &self.font_collection,
725                                        tree: &app.tree,
726                                        animation_clock: &app.animation_clock,
727                                    },
728                                    PluginHandle::new(&self.proxy),
729                                );
730                                self.plugins.send(
731                                    PluginEvent::BeforePresenting {
732                                        window: &app.window,
733                                        font_collection: &self.font_collection,
734                                        tree: &app.tree,
735                                    },
736                                    PluginHandle::new(&self.proxy),
737                                );
738                            },
739                        );
740                        self.plugins.send(
741                            PluginEvent::AfterPresenting {
742                                window: &app.window,
743                                font_collection: &self.font_collection,
744                                tree: &app.tree,
745                            },
746                            PluginHandle::new(&self.proxy),
747                        );
748
749                        self.plugins.send(
750                            PluginEvent::BeforeAccessibility {
751                                window: &app.window,
752                                font_collection: &self.font_collection,
753                                tree: &app.tree,
754                            },
755                            PluginHandle::new(&self.proxy),
756                        );
757
758                        match app.accessibility_tasks_for_next_render.take() {
759                            AccessibilityTask::ProcessUpdate { mode } => {
760                                let update = app
761                                    .accessibility
762                                    .process_updates(&mut app.tree, &app.events_sender);
763                                app.platform
764                                    .focused_accessibility_id
765                                    .set_if_modified(update.focus);
766                                let node_id = app.accessibility.focused_node_id().unwrap();
767                                let layout_node = app.tree.layout.get(&node_id).unwrap();
768                                app.platform.focused_accessibility_node.set_if_modified(
769                                    AccessibilityTree::create_node(node_id, layout_node, &app.tree),
770                                );
771                                if let Some(mode) = mode {
772                                    app.platform.navigation_mode.set(mode);
773                                }
774
775                                let area = layout_node.visible_area();
776                                app.window.set_ime_cursor_area(
777                                    LogicalPosition::new(area.min_x(), area.min_y()),
778                                    LogicalSize::new(area.width(), area.height()),
779                                );
780
781                                app.accessibility_adapter.update_if_active(|| update);
782                            }
783                            AccessibilityTask::Init => {
784                                let update = app.accessibility.init(&mut app.tree);
785                                app.platform
786                                    .focused_accessibility_id
787                                    .set_if_modified(update.focus);
788                                let node_id = app.accessibility.focused_node_id().unwrap();
789                                let layout_node = app.tree.layout.get(&node_id).unwrap();
790                                app.platform.focused_accessibility_node.set_if_modified(
791                                    AccessibilityTree::create_node(node_id, layout_node, &app.tree),
792                                );
793
794                                let area = layout_node.visible_area();
795                                app.window.set_ime_cursor_area(
796                                    LogicalPosition::new(area.min_x(), area.min_y()),
797                                    LogicalSize::new(area.width(), area.height()),
798                                );
799
800                                app.accessibility_adapter.update_if_active(|| update);
801                            }
802                            AccessibilityTask::None => {}
803                        }
804
805                        self.plugins.send(
806                            PluginEvent::AfterAccessibility {
807                                window: &app.window,
808                                font_collection: &self.font_collection,
809                                tree: &app.tree,
810                            },
811                            PluginHandle::new(&self.proxy),
812                        );
813
814                        if app.ticker_sender.receiver_count() > 0 {
815                            app.ticker_sender.broadcast_blocking(()).unwrap();
816                        }
817
818                        self.plugins.send(
819                            PluginEvent::AfterRedraw {
820                                window: &app.window,
821                                font_collection: &self.font_collection,
822                                tree: &app.tree,
823                            },
824                            PluginHandle::new(&self.proxy),
825                        );
826                    });
827                }
828                WindowEvent::Resized(size) => {
829                    app.driver.resize(size);
830
831                    app.window.request_redraw();
832
833                    app.process_layout_on_next_render = true;
834                    app.tree.layout.clear_dirty();
835                    app.tree.layout.invalidate(NodeId::ROOT);
836                }
837
838                WindowEvent::MouseInput { state, button, .. } => {
839                    app.just_focused = false;
840                    app.mouse_state = state;
841                    app.platform
842                        .navigation_mode
843                        .set(NavigationMode::NotKeyboard);
844
845                    let name = if state == ElementState::Pressed {
846                        MouseEventName::MouseDown
847                    } else {
848                        MouseEventName::MouseUp
849                    };
850                    let platform_event = PlatformEvent::Mouse {
851                        name,
852                        cursor: (app.position.x, app.position.y).into(),
853                        button: Some(map_winit_mouse_button(button)),
854                    };
855                    let mut events_measurer_adapter = EventsMeasurerAdapter {
856                        tree: &mut app.tree,
857                        scale_factor: app.window.scale_factor(),
858                    };
859                    let processed_events = events_measurer_adapter.run(
860                        &mut vec![platform_event],
861                        &mut app.nodes_state,
862                        app.accessibility.focused_node_id(),
863                    );
864                    app.events_sender
865                        .unbounded_send(EventsChunk::Processed(processed_events))
866                        .unwrap();
867                }
868
869                WindowEvent::KeyboardInput { event, .. } => {
870                    // Workaround for winit sending a Tab event when alt-tabbing
871                    if app.just_focused {
872                        app.just_focused = false;
873                        return;
874                    }
875
876                    let name = match event.state {
877                        ElementState::Pressed => KeyboardEventName::KeyDown,
878                        ElementState::Released => KeyboardEventName::KeyUp,
879                    };
880                    let platform_event = PlatformEvent::Keyboard {
881                        name,
882                        key: winit_mappings::map_winit_key(&event.logical_key),
883                        code: winit_mappings::map_winit_physical_key(&event.physical_key),
884                        modifiers: winit_mappings::map_winit_modifiers(app.modifiers_state),
885                    };
886                    let mut events_measurer_adapter = EventsMeasurerAdapter {
887                        tree: &mut app.tree,
888                        scale_factor: app.window.scale_factor(),
889                    };
890                    let processed_events = events_measurer_adapter.run(
891                        &mut vec![platform_event],
892                        &mut app.nodes_state,
893                        app.accessibility.focused_node_id(),
894                    );
895                    app.events_sender
896                        .unbounded_send(EventsChunk::Processed(processed_events))
897                        .unwrap();
898                }
899
900                WindowEvent::MouseWheel { delta, phase, .. } => {
901                    const WHEEL_SPEED_MODIFIER: f64 = 53.0;
902                    const TOUCHPAD_SPEED_MODIFIER: f64 = 2.0;
903
904                    if TouchPhase::Moved == phase {
905                        let scroll_data = {
906                            match delta {
907                                MouseScrollDelta::LineDelta(x, y) => (
908                                    (x as f64 * WHEEL_SPEED_MODIFIER),
909                                    (y as f64 * WHEEL_SPEED_MODIFIER),
910                                ),
911                                MouseScrollDelta::PixelDelta(pos) => (
912                                    (pos.x * TOUCHPAD_SPEED_MODIFIER),
913                                    (pos.y * TOUCHPAD_SPEED_MODIFIER),
914                                ),
915                            }
916                        };
917
918                        let platform_event = PlatformEvent::Wheel {
919                            name: WheelEventName::Wheel,
920                            scroll: scroll_data.into(),
921                            cursor: app.position,
922                            source: WheelSource::Device,
923                        };
924                        let mut events_measurer_adapter = EventsMeasurerAdapter {
925                            tree: &mut app.tree,
926                            scale_factor: app.window.scale_factor(),
927                        };
928                        let processed_events = events_measurer_adapter.run(
929                            &mut vec![platform_event],
930                            &mut app.nodes_state,
931                            app.accessibility.focused_node_id(),
932                        );
933                        app.events_sender
934                            .unbounded_send(EventsChunk::Processed(processed_events))
935                            .unwrap();
936                    }
937                }
938
939                WindowEvent::CursorLeft { .. } => {
940                    if app.mouse_state == ElementState::Released {
941                        app.position = CursorPoint::from((-1., -1.));
942                        let platform_event = PlatformEvent::Mouse {
943                            name: MouseEventName::MouseMove,
944                            cursor: app.position,
945                            button: None,
946                        };
947                        let mut events_measurer_adapter = EventsMeasurerAdapter {
948                            tree: &mut app.tree,
949                            scale_factor: app.window.scale_factor(),
950                        };
951                        let processed_events = events_measurer_adapter.run(
952                            &mut vec![platform_event],
953                            &mut app.nodes_state,
954                            app.accessibility.focused_node_id(),
955                        );
956                        app.events_sender
957                            .unbounded_send(EventsChunk::Processed(processed_events))
958                            .unwrap();
959                    }
960                }
961                WindowEvent::CursorMoved { position, .. } => {
962                    app.just_focused = false;
963                    app.position = CursorPoint::from((position.x, position.y));
964
965                    let mut platform_event = vec![PlatformEvent::Mouse {
966                        name: MouseEventName::MouseMove,
967                        cursor: app.position,
968                        button: None,
969                    }];
970
971                    for dropped_file_path in app.dropped_file_paths.drain(..) {
972                        platform_event.push(PlatformEvent::File {
973                            name: FileEventName::FileDrop,
974                            file_path: Some(dropped_file_path),
975                            cursor: app.position,
976                        });
977                    }
978
979                    let mut events_measurer_adapter = EventsMeasurerAdapter {
980                        tree: &mut app.tree,
981                        scale_factor: app.window.scale_factor(),
982                    };
983                    let processed_events = events_measurer_adapter.run(
984                        &mut platform_event,
985                        &mut app.nodes_state,
986                        app.accessibility.focused_node_id(),
987                    );
988                    app.events_sender
989                        .unbounded_send(EventsChunk::Processed(processed_events))
990                        .unwrap();
991                }
992
993                WindowEvent::Touch(Touch {
994                    location,
995                    phase,
996                    id,
997                    force,
998                    ..
999                }) => {
1000                    app.position = CursorPoint::from((location.x, location.y));
1001
1002                    let name = match phase {
1003                        TouchPhase::Cancelled => TouchEventName::TouchCancel,
1004                        TouchPhase::Ended => TouchEventName::TouchEnd,
1005                        TouchPhase::Moved => TouchEventName::TouchMove,
1006                        TouchPhase::Started => TouchEventName::TouchStart,
1007                    };
1008
1009                    let platform_event = PlatformEvent::Touch {
1010                        name,
1011                        location: app.position,
1012                        finger_id: id,
1013                        phase: map_winit_touch_phase(phase),
1014                        force: force.map(map_winit_touch_force),
1015                    };
1016                    let mut events_measurer_adapter = EventsMeasurerAdapter {
1017                        tree: &mut app.tree,
1018                        scale_factor: app.window.scale_factor(),
1019                    };
1020                    let processed_events = events_measurer_adapter.run(
1021                        &mut vec![platform_event],
1022                        &mut app.nodes_state,
1023                        app.accessibility.focused_node_id(),
1024                    );
1025                    app.events_sender
1026                        .unbounded_send(EventsChunk::Processed(processed_events))
1027                        .unwrap();
1028                    app.position = CursorPoint::from((location.x, location.y));
1029                }
1030                WindowEvent::Ime(Ime::Preedit(text, pos)) => {
1031                    let platform_event = PlatformEvent::ImePreedit {
1032                        name: ImeEventName::Preedit,
1033                        text,
1034                        cursor: pos,
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::DroppedFile(file_path) => {
1050                    app.dropped_file_paths.push(file_path);
1051                }
1052                WindowEvent::HoveredFile(file_path) => {
1053                    let platform_event = PlatformEvent::File {
1054                        name: FileEventName::FileHover,
1055                        file_path: Some(file_path),
1056                        cursor: app.position,
1057                    };
1058                    let mut events_measurer_adapter = EventsMeasurerAdapter {
1059                        tree: &mut app.tree,
1060                        scale_factor: app.window.scale_factor(),
1061                    };
1062                    let processed_events = events_measurer_adapter.run(
1063                        &mut vec![platform_event],
1064                        &mut app.nodes_state,
1065                        app.accessibility.focused_node_id(),
1066                    );
1067                    app.events_sender
1068                        .unbounded_send(EventsChunk::Processed(processed_events))
1069                        .unwrap();
1070                }
1071                WindowEvent::HoveredFileCancelled => {
1072                    let platform_event = PlatformEvent::File {
1073                        name: FileEventName::FileHoverCancelled,
1074                        file_path: None,
1075                        cursor: app.position,
1076                    };
1077                    let mut events_measurer_adapter = EventsMeasurerAdapter {
1078                        tree: &mut app.tree,
1079                        scale_factor: app.window.scale_factor(),
1080                    };
1081                    let processed_events = events_measurer_adapter.run(
1082                        &mut vec![platform_event],
1083                        &mut app.nodes_state,
1084                        app.accessibility.focused_node_id(),
1085                    );
1086                    app.events_sender
1087                        .unbounded_send(EventsChunk::Processed(processed_events))
1088                        .unwrap();
1089                }
1090                _ => {}
1091            }
1092        }
1093    }
1094}