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