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