Skip to main content

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