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 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 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}