freya_winit/
renderer.rs

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