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