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