Skip to main content

vizia_winit/
application.rs

1#[cfg(target_os = "windows")]
2use crate::window::set_cloak;
3use crate::{
4    convert::{winit_key_code_to_code, winit_key_to_key},
5    window::{WinState, Window},
6    window_modifiers::WindowModifiers,
7};
8#[cfg(feature = "accesskit")]
9use accesskit_winit::Adapter;
10#[cfg(all(
11    feature = "clipboard",
12    feature = "wayland",
13    any(
14        target_os = "linux",
15        target_os = "dragonfly",
16        target_os = "freebsd",
17        target_os = "netbsd",
18        target_os = "openbsd"
19    )
20))]
21use copypasta::wayland_clipboard::create_clipboards_from_external;
22use hashbrown::HashMap;
23use log::warn;
24use std::{error::Error, fmt::Display, sync::Arc};
25use vizia_input::ImeState;
26
27// #[cfg(feature = "accesskit")]
28// use accesskit::{Action, NodeBuilder, NodeId, TreeUpdate};
29// #[cfg(feature = "accesskit")]
30// use accesskit_winit;
31// use std::cell::RefCell;
32use vizia_core::context::EventProxy;
33use vizia_core::events::ProxyEvent;
34use vizia_core::prelude::*;
35use vizia_core::{backend::*, events::EventManager};
36use vizia_reactive::Runtime;
37use winit::{
38    application::ApplicationHandler,
39    dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize},
40    error::EventLoopError,
41    event::ElementState,
42    event_loop::{ActiveEventLoop, ControlFlow, EventLoop, EventLoopProxy},
43    keyboard::{NativeKeyCode, PhysicalKey},
44    window::{CursorIcon, CustomCursor, WindowAttributes, WindowId, WindowLevel},
45};
46
47#[cfg(all(
48    feature = "clipboard",
49    feature = "wayland",
50    any(
51        target_os = "linux",
52        target_os = "dragonfly",
53        target_os = "freebsd",
54        target_os = "netbsd",
55        target_os = "openbsd"
56    )
57))]
58use winit::raw_window_handle::{HasDisplayHandle, RawDisplayHandle};
59
60// #[cfg(all(
61//     feature = "clipboard",
62//     feature = "wayland",
63//     any(
64//         target_os = "linux",
65//         target_os = "dragonfly",
66//         target_os = "freebsd",
67//         target_os = "netbsd",
68//         target_os = "openbsd"
69//     )
70// ))]
71// use raw_window_handle::{HasRawDisplayHandle, RawDisplayHandle};
72use vizia_window::{Anchor, AnchorTarget, WindowPosition};
73
74#[derive(Debug)]
75pub enum UserEvent {
76    Event(ProxyEvent),
77    #[cfg(feature = "accesskit")]
78    AccessKitEvent(accesskit_winit::Event),
79}
80
81#[cfg(feature = "accesskit")]
82impl From<accesskit_winit::Event> for UserEvent {
83    fn from(action_request_event: accesskit_winit::Event) -> Self {
84        UserEvent::AccessKitEvent(action_request_event)
85    }
86}
87
88type IdleCallback = Option<Box<dyn Fn(&mut Context)>>;
89
90#[derive(Debug)]
91pub enum ApplicationError {
92    EventLoopError(EventLoopError),
93    LogError,
94}
95
96impl Display for ApplicationError {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        match self {
99            ApplicationError::EventLoopError(ele) => write!(f, "{}", ele),
100            ApplicationError::LogError => write!(f, "log error"),
101        }
102    }
103}
104
105impl std::error::Error for ApplicationError {}
106
107///Creating a new application creates a root `Window` and a `Context`. Views declared within the closure passed to `Application::new()` are added to the context and rendered into the root window.
108///
109/// # Example
110/// ```no_run
111/// # use vizia_core::prelude::*;
112/// # use vizia_winit::application::Application;
113/// Application::new(|cx|{
114///    // Content goes here
115/// })
116/// .run();
117///```
118/// Calling `run()` on the `Application` causes the program to enter the event loop and for the main window to display.
119pub struct Application {
120    cx: BackendContext,
121    event_manager: EventManager,
122    pub(crate) event_loop: Option<EventLoop<UserEvent>>,
123    on_idle: IdleCallback,
124    window_description: WindowDescription,
125    control_flow: ControlFlow,
126    event_loop_proxy: EventLoopProxy<UserEvent>,
127    windows: HashMap<WindowId, WinState>,
128    window_ids: HashMap<Entity, WindowId>,
129    #[cfg(feature = "accesskit")]
130    accesskit_adapter: Option<accesskit_winit::Adapter>,
131    #[cfg(feature = "accesskit")]
132    adapter_initialized: bool,
133}
134
135pub struct WinitEventProxy(EventLoopProxy<UserEvent>);
136
137impl EventProxy for WinitEventProxy {
138    fn send(&self, event: ProxyEvent) -> Result<(), ()> {
139        self.0.send_event(UserEvent::Event(event)).map_err(|_| ())
140    }
141
142    fn make_clone(&self) -> Box<dyn EventProxy> {
143        Box::new(WinitEventProxy(self.0.clone()))
144    }
145}
146
147impl Application {
148    pub fn new<F>(content: F) -> Self
149    where
150        F: 'static + FnOnce(&mut Context),
151    {
152        let context = Context::new();
153
154        let event_loop =
155            EventLoop::<UserEvent>::with_user_event().build().expect("Failed to create event loop");
156
157        let mut cx = BackendContext::new(context);
158
159        // Mark the current thread as the UI thread so that rayon workers
160        // correctly enqueue effects via SYNC_RUNTIME instead of the
161        // thread-local RUNTIME (which nobody drains).
162        Runtime::init_on_ui_thread();
163
164        let proxy = event_loop.create_proxy();
165        cx.set_event_proxy(Box::new(WinitEventProxy(proxy.clone())));
166
167        // Ensure we wake the event loop when a SyncSignal is mutated off the UI thread.
168        let waker_proxy = proxy.clone();
169        Runtime::set_sync_effect_waker(move || {
170            let _ = waker_proxy.send_event(UserEvent::Event(ProxyEvent::new(())));
171        });
172
173        cx.renegotiate_language();
174        cx.0.add_built_in_translations();
175        (content)(cx.context());
176
177        Self {
178            cx,
179            event_manager: EventManager::new(),
180            event_loop: Some(event_loop),
181            on_idle: None,
182            window_description: WindowDescription::new(),
183            control_flow: ControlFlow::Wait,
184            event_loop_proxy: proxy,
185            windows: HashMap::new(),
186            window_ids: HashMap::new(),
187            #[cfg(feature = "accesskit")]
188            accesskit_adapter: None,
189            #[cfg(feature = "accesskit")]
190            adapter_initialized: false,
191        }
192    }
193
194    fn create_window(
195        &mut self,
196        event_loop: &ActiveEventLoop,
197        window_entity: Entity,
198        window_description: &WindowDescription,
199        #[allow(unused_variables)] owner: Option<Arc<winit::window::Window>>,
200    ) -> Result<Arc<winit::window::Window>, Box<dyn Error>> {
201        #[allow(unused_mut)]
202        let mut window_attributes = apply_window_description(window_description);
203
204        let window_state = WinState::new(
205            event_loop,
206            window_entity,
207            window_attributes,
208            window_description.skia_resource_cache_limit,
209            owner,
210        )?;
211        let window = window_state.window.clone();
212
213        if let Some(position) = window_description.position {
214            window.set_outer_position(LogicalPosition::new(position.x, position.y));
215        } else {
216            let (anchor, mut parent_anchor) =
217                match (window_description.anchor, window_description.parent_anchor) {
218                    (Some(a), None) => (Some(a), Some(a)),
219                    (None, Some(b)) => (Some(b.opposite()), Some(b)),
220                    t => t,
221                };
222
223            if let Some(anchor) = anchor {
224                let (y, x) = match anchor {
225                    Anchor::TopLeft => (0.0, 0.0),
226                    Anchor::TopCenter => (0.0, 0.5),
227                    Anchor::TopRight => (0.0, 1.0),
228                    Anchor::Left => (0.5, 0.0),
229                    Anchor::Center => (0.5, 0.5),
230                    Anchor::Right => (0.5, 1.0),
231                    Anchor::BottomLeft => (1.0, 0.0),
232                    Anchor::BottomCenter => (1.0, 0.5),
233                    Anchor::BottomRight => (1.0, 1.0),
234                };
235
236                let window_size = window.inner_size();
237
238                let anchor_target = window_description.anchor_target.unwrap_or_default();
239                let parent = match anchor_target {
240                    AnchorTarget::Monitor => window
241                        .current_monitor()
242                        .map(|monitor| (PhysicalPosition::default(), monitor.size())),
243                    AnchorTarget::Window => self
244                        .cx
245                        .0
246                        .tree
247                        .get_parent_window(window_entity)
248                        .and_then(|parent_window| self.window_ids.get(&parent_window))
249                        .and_then(|id| self.windows.get(id))
250                        .and_then(|WinState { window, .. }| {
251                            let position = window
252                                .outer_position()
253                                .inspect_err(|e| warn!("can't get window position: {e:?}"));
254                            Some((position.ok()?, window.inner_size()))
255                        }),
256                    AnchorTarget::Mouse => self
257                        .cx
258                        .0
259                        .tree
260                        .get_parent_window(window_entity)
261                        .and_then(|parent_window| self.window_ids.get(&parent_window))
262                        .and_then(|id| self.windows.get(id))
263                        .and_then(|WinState { window, .. }| {
264                            window
265                                .outer_position()
266                                .inspect_err(|e| warn!("can't get window position: {e:?}"))
267                                .ok()
268                        })
269                        .map(|pos| {
270                            (
271                                PhysicalPosition::new(
272                                    pos.x + self.cx.0.mouse.cursor_x as i32,
273                                    pos.y + self.cx.0.mouse.cursor_y as i32,
274                                ),
275                                PhysicalSize::new(0, 0),
276                            )
277                        }),
278                };
279
280                if let Some((parent_position, parent_size)) = parent {
281                    if anchor_target != AnchorTarget::Window {
282                        parent_anchor = Some(anchor);
283                    }
284
285                    let (py, px) = match parent_anchor.unwrap_or_default() {
286                        Anchor::TopLeft => (0.0, 0.0),
287                        Anchor::TopCenter => (0.0, 0.5),
288                        Anchor::TopRight => (0.0, 1.0),
289                        Anchor::Left => (0.5, 0.0),
290                        Anchor::Center => (0.5, 0.5),
291                        Anchor::Right => (0.5, 1.0),
292                        Anchor::BottomLeft => (1.0, 0.0),
293                        Anchor::BottomCenter => (1.0, 0.5),
294                        Anchor::BottomRight => (1.0, 1.0),
295                    };
296
297                    let x = (((parent_size.width as f32 * px) as i32
298                        - (window_size.width as f32 * x) as i32)
299                        as f32) as i32;
300                    let y = (((parent_size.height as f32 * py) as i32
301                        - (window_size.height as f32 * y) as i32)
302                        as f32) as i32;
303
304                    let offset = window_description.offset.unwrap_or_default();
305                    let offset: PhysicalPosition<i32> = PhysicalPosition::from_logical(
306                        LogicalPosition::new(offset.x, offset.y),
307                        window.scale_factor(),
308                    );
309
310                    window.set_outer_position(PhysicalPosition::new(
311                        parent_position.x + x + offset.x,
312                        parent_position.y + y + offset.y,
313                    ));
314                }
315            }
316        }
317
318        let window_id = window_state.window.id();
319        self.windows.insert(window_id, window_state);
320        self.window_ids.insert(window_entity, window_id);
321
322        #[cfg(all(
323            feature = "clipboard",
324            feature = "wayland",
325            any(
326                target_os = "linux",
327                target_os = "dragonfly",
328                target_os = "freebsd",
329                target_os = "netbsd",
330                target_os = "openbsd"
331            )
332        ))]
333        self.init_wayland_clipboard(window_entity, &window);
334
335        Ok(window)
336    }
337
338    #[cfg(all(
339        feature = "clipboard",
340        feature = "wayland",
341        any(
342            target_os = "linux",
343            target_os = "dragonfly",
344            target_os = "freebsd",
345            target_os = "netbsd",
346            target_os = "openbsd"
347        )
348    ))]
349    fn init_wayland_clipboard(&mut self, window_entity: Entity, window: &winit::window::Window) {
350        let Ok(display_handle) = window.display_handle() else {
351            return;
352        };
353
354        if let RawDisplayHandle::Wayland(handle) = display_handle.as_raw() {
355            // SAFETY: The display handle comes from a live winit window and remains valid for
356            // at least as long as the window/application lifetime where the provider is used.
357            let (_, clipboard) =
358                unsafe { create_clipboards_from_external(handle.display.as_ptr()) };
359            self.cx.set_clipboard_provider(window_entity, Box::new(clipboard));
360        }
361    }
362
363    /// Sets the default built-in theming to be ignored.
364    pub fn ignore_default_theme(mut self) -> Self {
365        self.cx.context().ignore_default_theme = true;
366        self
367    }
368
369    pub fn should_poll(mut self) -> Self {
370        self.control_flow = ControlFlow::Poll;
371
372        self
373    }
374
375    /// Takes a closure which will be called at the end of every loop of the application.
376    ///
377    /// The callback provides a place to run 'idle' processing and happens at the end of each loop but before drawing.
378    /// If the callback pushes events into the queue in state then the event loop will re-run. Care must be taken not to
379    /// push events into the queue every time the callback runs unless this is intended.
380    ///
381    /// # Example
382    ///
383    /// ```no_run
384    /// # use vizia_core::prelude::*;
385    /// # use vizia_winit::application::Application;
386    /// #
387    /// Application::new(|cx| {
388    ///     // Build application here
389    /// })
390    /// .on_idle(|cx| {
391    ///     // Code here runs at the end of every event loop after OS and vizia events have been handled
392    /// })
393    /// .run();
394    /// ```
395    pub fn on_idle<F: 'static + Fn(&mut Context)>(mut self, callback: F) -> Self {
396        self.on_idle = Some(Box::new(callback));
397
398        self
399    }
400
401    /// Returns a `ContextProxy` which can be used to send events from another thread.
402    pub fn get_proxy(&self) -> ContextProxy {
403        self.cx.0.get_proxy()
404    }
405
406    pub fn run(mut self) -> Result<(), ApplicationError> {
407        self.event_loop.take().unwrap().run_app(&mut self).map_err(ApplicationError::EventLoopError)
408    }
409}
410
411impl ApplicationHandler<UserEvent> for Application {
412    fn user_event(&mut self, _event_loop: &ActiveEventLoop, user_event: UserEvent) {
413        match user_event {
414            UserEvent::Event(event) => {
415                self.cx.send_event(event.into_event());
416            }
417
418            #[cfg(feature = "accesskit")]
419            UserEvent::AccessKitEvent(access_event) => {
420                match access_event.window_event {
421                    accesskit_winit::WindowEvent::InitialTreeRequested => {
422                        let tree_update = self.cx.init_accessibility_tree();
423                        if let Some(adapter) = &mut self.accesskit_adapter {
424                            adapter.update_if_active(|| {
425                                self.adapter_initialized = true;
426                                tree_update
427                            });
428                        }
429                    }
430                    accesskit_winit::WindowEvent::ActionRequested(action_request) => {
431                        let node_id = action_request.target_node;
432
433                        if action_request.action != Action::ScrollIntoView {
434                            let entity = Entity::new(node_id.0, 0);
435
436                            // Handle focus action from screen reader
437                            if action_request.action == Action::Focus {
438                                self.cx.0.with_current(entity, |cx| {
439                                    cx.focus();
440                                });
441                            }
442
443                            self.cx.send_event(
444                                Event::new(WindowEvent::ActionRequest(action_request))
445                                    .direct(entity),
446                            );
447                        }
448                    }
449                    accesskit_winit::WindowEvent::AccessibilityDeactivated => todo!(),
450                }
451            }
452        }
453    }
454
455    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
456        if self.windows.is_empty() {
457            // Create the main window
458            let main_window: Arc<winit::window::Window> = self
459                .create_window(event_loop, Entity::root(), &self.window_description.clone(), None)
460                .expect("failed to create initial window");
461
462            let custom_cursors = Arc::new(load_default_cursors(event_loop));
463            self.cx.add_main_window(
464                Entity::root(),
465                &self.window_description,
466                main_window.scale_factor() as f32,
467            );
468            self.cx.add_window(Window {
469                window: Some(main_window.clone()),
470                on_close: None,
471                on_create: None,
472                should_close: false,
473                custom_cursors: custom_cursors.clone(),
474            });
475
476            self.cx.0.windows.insert(
477                Entity::root(),
478                WindowState {
479                    window_description: self.window_description.clone(),
480                    ..Default::default()
481                },
482            );
483
484            #[cfg(feature = "accesskit")]
485            {
486                self.accesskit_adapter = Some(Adapter::with_event_loop_proxy(
487                    event_loop,
488                    &main_window,
489                    self.event_loop_proxy.clone(),
490                ));
491            }
492
493            main_window.set_visible(self.window_description.visible);
494
495            // set current system theme if available
496            if let Some(theme) = main_window.theme() {
497                let theme = match theme {
498                    winit::window::Theme::Light => ThemeMode::LightMode,
499                    winit::window::Theme::Dark => ThemeMode::DarkMode,
500                };
501                self.cx.emit_origin(WindowEvent::ThemeChanged(theme));
502            }
503
504            self.cx.0.add_built_in_styles();
505
506            // Create any subwindows
507            for (window_entity, window_state) in self.cx.0.windows.clone().into_iter() {
508                if window_entity == Entity::root() {
509                    continue;
510                }
511                let owner = window_state.owner.and_then(|entity| {
512                    self.window_ids
513                        .get(&entity)
514                        .and_then(|id| self.windows.get(id).map(|ws| ws.window.clone()))
515                });
516
517                let window = self
518                    .create_window(
519                        event_loop,
520                        window_entity,
521                        &window_state.window_description,
522                        owner,
523                    )
524                    .expect("Failed to create window");
525
526                self.cx.add_main_window(
527                    window_entity,
528                    &window_state.window_description,
529                    window.scale_factor() as f32,
530                );
531
532                window.set_visible(window_state.window_description.visible);
533
534                self.cx.0.with_current(window_entity, |cx| {
535                    if let Some(content) = &window_state.content {
536                        (content)(cx)
537                    }
538                });
539                self.cx.mutate_window(window_entity, |cx, win: &mut Window| {
540                    win.window = Some(window.clone());
541                    win.custom_cursors = custom_cursors.clone();
542                    if let Some(callback) = &win.on_create {
543                        (callback)(&mut EventContext::new_with_current(
544                            cx.context(),
545                            window_entity,
546                        ));
547                    }
548                });
549                self.cx.needs_refresh(window_entity);
550            }
551        }
552    }
553
554    fn window_event(
555        &mut self,
556        _event_loop: &ActiveEventLoop,
557        window_id: WindowId,
558        event: winit::event::WindowEvent,
559    ) {
560        let window = match self.windows.get_mut(&window_id) {
561            Some(window) => window,
562            None => return,
563        };
564
565        match event {
566            winit::event::WindowEvent::Resized(size) => {
567                window.resize(size);
568                self.cx.set_window_size(window.entity, size.width as f32, size.height as f32);
569                self.cx.needs_refresh(window.entity);
570                window.window().request_redraw();
571
572                #[cfg(target_os = "windows")]
573                {
574                    self.event_manager.flush_events(self.cx.context(), |_| {});
575
576                    self.cx.process_style_updates();
577
578                    if self.cx.process_animations() {
579                        window.window().request_redraw();
580                    }
581
582                    self.cx.process_visual_updates();
583
584                    // #[cfg(feature = "accesskit")]
585
586                    // self.cx.process_tree_updates(|tree_updates| {
587                    //     for update in tree_updates.iter_mut() {
588                    //         self.accesskit_adapter
589                    //             .unwrap()
590                    //             .update_if_active(|| update.take().unwrap());
591                    //     }
592                    // });
593
594                    // for update in self.cx.0.tree_updates.iter_mut() {
595                    //     self.accesskit_adapter
596                    //         .as_mut()
597                    //         .unwrap()
598                    //         .update_if_active(|| update.take().unwrap());
599                    // }
600
601                    // self.cx.0.tree_updates.clear();
602
603                    window.window().request_redraw();
604                }
605            }
606
607            winit::event::WindowEvent::Moved(position) => {
608                let window_entity = window.entity;
609                self.cx.emit_window_event(
610                    window_entity,
611                    WindowEvent::WindowMoved(WindowPosition { x: position.x, y: position.y }),
612                );
613
614                #[cfg(target_os = "windows")]
615                {
616                    self.event_manager.flush_events(self.cx.context(), |_| {});
617
618                    self.cx.process_style_updates();
619
620                    if self.cx.process_animations() {
621                        window.window().request_redraw();
622                    }
623
624                    self.cx.process_visual_updates();
625
626                    // #[cfg(feature = "accesskit")]
627
628                    // self.cx.process_tree_updates(|tree_updates| {
629                    //     for update in tree_updates.iter_mut() {
630                    //         self.accesskit_adapter
631                    //             .unwrap()
632                    //             .update_if_active(|| update.take().unwrap());
633                    //     }
634                    // });
635
636                    // for update in self.cx.0.tree_updates.iter_mut() {
637                    //     self.accesskit_adapter
638                    //         .as_mut()
639                    //         .unwrap()
640                    //         .update_if_active(|| update.take().unwrap());
641                    // }
642
643                    // self.cx.0.tree_updates.clear();
644                }
645            }
646
647            winit::event::WindowEvent::CloseRequested | winit::event::WindowEvent::Destroyed => {
648                let window_entity = window.entity;
649                self.cx.emit_window_event(window_entity, WindowEvent::WindowClose);
650            }
651            winit::event::WindowEvent::DroppedFile(path) => {
652                self.cx.emit_window_event(window.entity, WindowEvent::Drop(DropData::File(path)));
653            }
654
655            winit::event::WindowEvent::HoveredFile(_) => {}
656            winit::event::WindowEvent::HoveredFileCancelled => {}
657            winit::event::WindowEvent::Focused(is_focused) => {
658                self.cx.emit_window_event(window.entity, WindowEvent::WindowFocused(is_focused));
659
660                self.cx.0.window_has_focus = is_focused;
661                // #[cfg(feature = "accesskit")]
662                // accesskit.update_if_active(|| TreeUpdate {
663                //     nodes: vec![],
664                //     tree: None,
665                //     focus: is_focused.then_some(self.cx.focused().accesskit_id()).unwrap_or(NodeId(0)),
666                // });
667            }
668            winit::event::WindowEvent::KeyboardInput { device_id: _, event, is_synthetic: _ } => {
669                let code = match event.physical_key {
670                    PhysicalKey::Code(code) => winit_key_code_to_code(code),
671                    PhysicalKey::Unidentified(native) => match native {
672                        NativeKeyCode::Windows(_scancode) => return,
673                        _ => return,
674                    },
675                };
676
677                let key = match &event.logical_key {
678                    winit::keyboard::Key::Named(named_key) => winit_key_to_key(*named_key),
679                    winit::keyboard::Key::Character(character) => {
680                        Some(vizia_input::Key::Character(character.to_string()))
681                    }
682                    winit::keyboard::Key::Unidentified(_) => {
683                        Some(vizia_input::Key::Named(vizia_input::NamedKey::Unidentified))
684                    }
685                    winit::keyboard::Key::Dead(_) => {
686                        Some(vizia_input::Key::Named(vizia_input::NamedKey::Dead))
687                    }
688                };
689
690                if event.state == ElementState::Pressed {
691                    match &event.logical_key {
692                        winit::keyboard::Key::Character(character) => {
693                            if let Some(character) = character.as_str().chars().next() {
694                                self.cx.emit_window_event(
695                                    window.entity,
696                                    WindowEvent::CharInput(character),
697                                );
698                            }
699                        }
700                        // Some platforms report space as a named key instead of character text.
701                        winit::keyboard::Key::Named(winit::keyboard::NamedKey::Space) => {
702                            self.cx.emit_window_event(window.entity, WindowEvent::CharInput(' '));
703                        }
704                        _ => {}
705                    }
706                }
707
708                let event = match event.state {
709                    winit::event::ElementState::Pressed => WindowEvent::KeyDown(code, key),
710                    winit::event::ElementState::Released => WindowEvent::KeyUp(code, key),
711                };
712
713                self.cx.emit_window_event(window.entity, event);
714            }
715            winit::event::WindowEvent::ModifiersChanged(modifiers) => {
716                self.cx.modifiers().set(Modifiers::SHIFT, modifiers.state().shift_key());
717
718                self.cx.modifiers().set(Modifiers::ALT, modifiers.state().alt_key());
719
720                self.cx.modifiers().set(Modifiers::CTRL, modifiers.state().control_key());
721
722                self.cx.modifiers().set(Modifiers::SUPER, modifiers.state().super_key());
723            }
724            winit::event::WindowEvent::Ime(ime) => match ime {
725                winit::event::Ime::Enabled => {
726                    self.cx.0.set_ime_state(ImeState::StartComposition);
727                    self.cx.emit_window_event(window.entity, WindowEvent::ImeActivate(true));
728                }
729                winit::event::Ime::Preedit(text, cursor) => {
730                    self.cx.0.set_ime_state(ImeState::Composing {
731                        preedit: Some(text.clone()),
732                        cursor_pos: cursor,
733                    });
734                    self.cx.emit_window_event(window.entity, WindowEvent::ImePreedit(text, cursor));
735                }
736                winit::event::Ime::Commit(text) => {
737                    self.cx.0.set_ime_state(ImeState::EndComposition);
738                    self.cx.emit_window_event(window.entity, WindowEvent::ImeCommit(text));
739                }
740                winit::event::Ime::Disabled => {
741                    self.cx.0.set_ime_state(ImeState::Inactive);
742                    self.cx.emit_window_event(window.entity, WindowEvent::ImeActivate(false));
743                }
744            },
745            winit::event::WindowEvent::CursorMoved { device_id: _, position } => {
746                self.cx.emit_window_event(
747                    window.entity,
748                    WindowEvent::MouseMove(position.x as f32, position.y as f32),
749                );
750            }
751            winit::event::WindowEvent::CursorEntered { device_id: _ } => {
752                self.cx.emit_window_event(window.entity, WindowEvent::MouseEnter);
753            }
754            winit::event::WindowEvent::CursorLeft { device_id: _ } => {
755                self.cx.emit_window_event(window.entity, WindowEvent::MouseLeave);
756            }
757            winit::event::WindowEvent::MouseWheel { device_id: _, delta, phase: _ } => {
758                let out_event = match delta {
759                    winit::event::MouseScrollDelta::LineDelta(x, y) => {
760                        WindowEvent::MouseScroll(x, y)
761                    }
762                    winit::event::MouseScrollDelta::PixelDelta(pos) => {
763                        WindowEvent::MouseScroll(
764                            pos.x as f32 / 20.0,
765                            pos.y as f32 / 20.0, // this number calibrated for wayland
766                        )
767                    }
768                };
769
770                self.cx.emit_window_event(window.entity, out_event);
771            }
772            winit::event::WindowEvent::MouseInput { device_id: _, state, button } => {
773                let button = match button {
774                    winit::event::MouseButton::Left => MouseButton::Left,
775                    winit::event::MouseButton::Right => MouseButton::Right,
776                    winit::event::MouseButton::Middle => MouseButton::Middle,
777                    winit::event::MouseButton::Other(val) => MouseButton::Other(val),
778                    winit::event::MouseButton::Back => MouseButton::Back,
779                    winit::event::MouseButton::Forward => MouseButton::Forward,
780                };
781
782                let event = match state {
783                    winit::event::ElementState::Pressed => WindowEvent::MouseDown(button),
784                    winit::event::ElementState::Released => WindowEvent::MouseUp(button),
785                };
786
787                self.cx.emit_window_event(window.entity, event);
788            }
789
790            winit::event::WindowEvent::ScaleFactorChanged {
791                scale_factor,
792                inner_size_writer: _,
793            } => {
794                self.cx.set_scale_factor(scale_factor);
795                self.cx.needs_refresh(window.entity);
796            }
797            winit::event::WindowEvent::ThemeChanged(theme) => {
798                let theme = match theme {
799                    winit::window::Theme::Light => ThemeMode::LightMode,
800                    winit::window::Theme::Dark => ThemeMode::DarkMode,
801                };
802                self.cx.emit_window_event(window.entity, WindowEvent::ThemeChanged(theme));
803            }
804            winit::event::WindowEvent::Occluded(_) => {}
805            winit::event::WindowEvent::RedrawRequested => {
806                for window in self.windows.values_mut() {
807                    window.make_current();
808                    //self.cx.needs_refresh(window.entity);
809                    if self.cx.draw(window.entity, &mut window.surface, &mut window.dirty_surface) {
810                        window.swap_buffers();
811                    }
812
813                    // Un-cloak
814                    #[cfg(target_os = "windows")]
815                    if window.is_initially_cloaked {
816                        window.is_initially_cloaked = false;
817                        set_cloak(window.window(), false);
818                    }
819                }
820            }
821
822            _ => {}
823        }
824    }
825
826    fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
827        if self.windows.is_empty() {
828            event_loop.exit();
829            return;
830        }
831
832        event_loop.set_control_flow(self.control_flow);
833
834        Runtime::drain_pending_work();
835
836        self.event_manager.flush_events(self.cx.context(), |_| {});
837
838        self.cx.process_style_updates();
839
840        if self.cx.process_animations() {
841            for window in self.windows.values() {
842                window.window().request_redraw();
843            }
844        }
845
846        self.cx.process_visual_updates();
847
848        #[cfg(feature = "accesskit")]
849        {
850            self.cx.process_tree_updates();
851
852            if self.adapter_initialized {
853                for update in self.cx.0.tree_updates.iter_mut() {
854                    self.accesskit_adapter
855                        .as_mut()
856                        .unwrap()
857                        .update_if_active(|| update.take().unwrap());
858                }
859            }
860
861            self.cx.0.tree_updates.clear();
862        }
863
864        if let Some(idle_callback) = &self.on_idle {
865            self.cx.set_current(Entity::root());
866            (idle_callback)(self.cx.context());
867        }
868
869        if self.cx.has_queued_events() {
870            self.event_loop_proxy
871                .send_event(UserEvent::Event(ProxyEvent::new(())))
872                .expect("Failed to send event");
873        }
874
875        if self.cx.0.windows.iter().any(|(_, window_state)| !window_state.redraw_list.is_empty()) {
876            for window in self.windows.values() {
877                window.window().request_redraw();
878            }
879        }
880
881        if self.control_flow != ControlFlow::Poll {
882            if let Some(timer_time) = self.cx.get_next_timer_time() {
883                event_loop.set_control_flow(ControlFlow::WaitUntil(timer_time));
884            } else {
885                event_loop.set_control_flow(ControlFlow::Wait);
886            }
887        }
888
889        let window_entities = self
890            .cx
891            .0
892            .windows
893            .iter()
894            .filter_map(|(entity, state)| state.should_close.then_some(*entity))
895            .collect::<Vec<_>>();
896
897        for window_entity in window_entities {
898            self.cx.0.remove(window_entity);
899        }
900
901        // Sync window state with context
902        self.windows.retain(|_, win| self.cx.0.windows.contains_key(&win.entity));
903        self.window_ids.retain(|e, _| self.cx.0.windows.contains_key(e));
904
905        if self.windows.len() != self.cx.0.windows.len() {
906            for (window_entity, window_state) in self.cx.0.windows.clone().iter() {
907                if !self.window_ids.contains_key(window_entity) {
908                    let owner = window_state.owner.and_then(|entity| {
909                        self.window_ids
910                            .get(&entity)
911                            .and_then(|id| self.windows.get(id).map(|ws| ws.window.clone()))
912                    });
913
914                    let window = self
915                        .create_window(
916                            event_loop,
917                            *window_entity,
918                            &window_state.window_description,
919                            owner,
920                        )
921                        .expect("Failed to create window");
922
923                    self.cx.add_main_window(
924                        *window_entity,
925                        &window_state.window_description,
926                        window.scale_factor() as f32,
927                    );
928
929                    window.set_visible(window_state.window_description.visible);
930
931                    self.cx.0.with_current(*window_entity, |cx| {
932                        if let Some(content) = &window_state.content {
933                            (content)(cx)
934                        }
935                    });
936
937                    self.cx.mutate_window(*window_entity, |cx, win: &mut Window| {
938                        win.window = Some(window.clone());
939                        if let Some(callback) = &win.on_create {
940                            (callback)(&mut EventContext::new_with_current(
941                                cx.context(),
942                                *window_entity,
943                            ));
944                        }
945                    });
946                }
947            }
948        }
949
950        if self.windows.is_empty() {
951            event_loop.exit();
952        }
953    }
954
955    fn new_events(&mut self, _event_loop: &ActiveEventLoop, _cause: winit::event::StartCause) {
956        self.cx.process_timers();
957        self.cx.emit_scheduled_events();
958    }
959
960    fn exiting(&mut self, _event_loop: &ActiveEventLoop) {
961        Runtime::deinit_on_ui_thread();
962    }
963}
964
965impl WindowModifiers for Application {
966    fn title<T: ToStringLocalized>(mut self, title: impl Res<T> + Clone + 'static) -> Self {
967        self.window_description.title = title.get_value(&self.cx.0).to_string_local(&self.cx.0);
968
969        let getter_for_locale = title.clone();
970
971        title.set_or_bind(&mut self.cx.0, move |cx, val| {
972            let title_str = val.get_value(cx).to_string_local(cx);
973
974            cx.emit(WindowEvent::SetTitle(title_str));
975        });
976
977        let locale = self.cx.0.environment().locale;
978        locale.set_or_bind(&mut self.cx.0, move |cx, _| {
979            let title = getter_for_locale.get_value(cx).to_string_local(cx);
980            cx.emit(WindowEvent::SetTitle(title));
981        });
982
983        self
984    }
985
986    fn inner_size<S: Into<WindowSize>>(mut self, size: impl Res<S>) -> Self {
987        self.window_description.inner_size = size.get_value(&self.cx.0).into();
988
989        size.set_or_bind(&mut self.cx.0, |cx, size| {
990            cx.emit(WindowEvent::SetSize(size.get_value(cx).into()));
991        });
992
993        self
994    }
995
996    fn min_inner_size<S: Into<WindowSize>>(mut self, size: impl Res<Option<S>>) -> Self {
997        self.window_description.min_inner_size = size.get_value(&self.cx.0).map(|s| s.into());
998
999        size.set_or_bind(&mut self.cx.0, |cx, size| {
1000            cx.emit(WindowEvent::SetMinSize(size.get_value(cx).map(|s| s.into())));
1001        });
1002
1003        self
1004    }
1005
1006    fn max_inner_size<S: Into<WindowSize>>(mut self, size: impl Res<Option<S>>) -> Self {
1007        self.window_description.max_inner_size = size.get_value(&self.cx.0).map(|s| s.into());
1008
1009        size.set_or_bind(&mut self.cx.0, |cx, size| {
1010            cx.emit(WindowEvent::SetMaxSize(size.get_value(cx).map(|s| s.into())));
1011        });
1012        self
1013    }
1014
1015    fn position<P: Into<WindowPosition>>(mut self, position: impl Res<P>) -> Self {
1016        self.window_description.position = Some(position.get_value(&self.cx.0).into());
1017
1018        position.set_or_bind(&mut self.cx.0, |cx, size| {
1019            cx.emit(WindowEvent::SetPosition(size.get_value(cx).into()));
1020        });
1021
1022        self
1023    }
1024
1025    fn offset<P: Into<WindowPosition>>(mut self, offset: impl Res<P>) -> Self {
1026        self.window_description.offset = Some(offset.get_value(&self.cx.0).into());
1027
1028        self
1029    }
1030
1031    fn anchor<P: Into<Anchor>>(mut self, anchor: impl Res<P>) -> Self {
1032        self.window_description.anchor = Some(anchor.get_value(&self.cx.0).into());
1033
1034        self
1035    }
1036
1037    fn anchor_target<P: Into<AnchorTarget>>(mut self, anchor_target: impl Res<P>) -> Self {
1038        self.window_description.anchor_target = Some(anchor_target.get_value(&self.cx.0).into());
1039
1040        self
1041    }
1042
1043    fn parent_anchor<P: Into<Anchor>>(mut self, parent_anchor: impl Res<P>) -> Self {
1044        self.window_description.parent_anchor = Some(parent_anchor.get_value(&self.cx.0).into());
1045
1046        self
1047    }
1048
1049    fn resizable(mut self, flag: impl Res<bool>) -> Self {
1050        self.window_description.resizable = flag.get_value(&self.cx.0);
1051
1052        flag.set_or_bind(&mut self.cx.0, |cx, flag| {
1053            cx.emit(WindowEvent::SetResizable(flag.get_value(cx)));
1054        });
1055
1056        self
1057    }
1058
1059    fn minimized(mut self, flag: impl Res<bool>) -> Self {
1060        self.window_description.minimized = flag.get_value(&self.cx.0);
1061
1062        flag.set_or_bind(&mut self.cx.0, |cx, flag| {
1063            cx.emit(WindowEvent::SetMinimized(flag.get_value(cx)));
1064        });
1065        self
1066    }
1067
1068    fn maximized(mut self, flag: impl Res<bool>) -> Self {
1069        self.window_description.maximized = flag.get_value(&self.cx.0);
1070
1071        flag.set_or_bind(&mut self.cx.0, |cx, flag| {
1072            cx.emit(WindowEvent::SetMaximized(flag.get_value(cx)));
1073        });
1074
1075        self
1076    }
1077
1078    fn visible(mut self, flag: impl Res<bool>) -> Self {
1079        self.window_description.visible = flag.get_value(&self.cx.0);
1080
1081        flag.set_or_bind(&mut self.cx.0, |cx, flag| {
1082            cx.emit(WindowEvent::SetVisible(flag.get_value(cx)));
1083        });
1084
1085        self
1086    }
1087
1088    fn transparent(mut self, flag: bool) -> Self {
1089        self.window_description.transparent = flag;
1090
1091        self
1092    }
1093
1094    fn decorations(mut self, flag: bool) -> Self {
1095        self.window_description.decorations = flag;
1096
1097        self
1098    }
1099
1100    fn always_on_top(mut self, flag: bool) -> Self {
1101        self.window_description.always_on_top = flag;
1102        self
1103    }
1104
1105    fn vsync(mut self, flag: bool) -> Self {
1106        self.window_description.vsync = flag;
1107
1108        self
1109    }
1110
1111    fn skia_resource_cache_limit(mut self, limit: usize) -> Self {
1112        self.window_description.skia_resource_cache_limit = limit;
1113
1114        self
1115    }
1116
1117    fn icon(mut self, width: u32, height: u32, image: Vec<u8>) -> Self {
1118        self.window_description.icon = Some(image);
1119        self.window_description.icon_width = width;
1120        self.window_description.icon_height = height;
1121
1122        self
1123    }
1124
1125    fn on_close(self, _callback: impl Fn(&mut EventContext)) -> Self {
1126        self
1127    }
1128
1129    fn on_create(self, _callback: impl Fn(&mut EventContext)) -> Self {
1130        self
1131    }
1132
1133    fn enabled_window_buttons(mut self, window_buttons: WindowButtons) -> Self {
1134        self.window_description.enabled_window_buttons = window_buttons;
1135
1136        self
1137    }
1138}
1139
1140fn apply_window_description(description: &WindowDescription) -> WindowAttributes {
1141    let mut window_attributes = winit::window::Window::default_attributes();
1142
1143    window_attributes = window_attributes.with_title(&description.title).with_inner_size(
1144        LogicalSize::new(description.inner_size.width, description.inner_size.height),
1145    );
1146
1147    if let Some(min_inner_size) = description.min_inner_size {
1148        window_attributes = window_attributes
1149            .with_min_inner_size(LogicalSize::new(min_inner_size.width, min_inner_size.height));
1150    }
1151
1152    if let Some(max_inner_size) = description.max_inner_size {
1153        window_attributes = window_attributes
1154            .with_max_inner_size(LogicalSize::new(max_inner_size.width, max_inner_size.height));
1155    }
1156
1157    if let Some(position) = description.position {
1158        window_attributes =
1159            window_attributes.with_position(LogicalPosition::new(position.x, position.y));
1160    }
1161
1162    window_attributes
1163        .with_resizable(description.resizable)
1164        .with_maximized(description.maximized)
1165        // Accesskit requires that the window start invisible until accesskit is initialized.
1166        .with_visible(false)
1167        .with_window_level(if description.always_on_top {
1168            WindowLevel::AlwaysOnTop
1169        } else {
1170            WindowLevel::Normal
1171        })
1172        .with_transparent(description.transparent)
1173        .with_decorations(description.decorations)
1174        .with_window_icon(description.icon.as_ref().map(|icon| {
1175            winit::window::Icon::from_rgba(
1176                icon.clone(),
1177                description.icon_width,
1178                description.icon_height,
1179            )
1180            .unwrap()
1181        }))
1182        .with_enabled_buttons(
1183            winit::window::WindowButtons::from_bits(description.enabled_window_buttons.bits())
1184                .unwrap(),
1185        )
1186}
1187
1188#[allow(unused_variables)]
1189pub fn load_default_cursors(event_loop: &ActiveEventLoop) -> HashMap<CursorIcon, CustomCursor> {
1190    #[allow(unused_mut)]
1191    let mut custom_cursors = HashMap::new();
1192
1193    #[cfg(target_os = "windows")]
1194    {
1195        let mut load_cursor = |cursor, bytes, x, y| {
1196            custom_cursors.insert(
1197                cursor,
1198                event_loop.create_custom_cursor(
1199                    CustomCursor::from_rgba(bytes, 32, 32, x, y)
1200                        .expect("Failed to create custom cursor"),
1201                ),
1202            );
1203        };
1204
1205        load_cursor(
1206            CursorIcon::Alias, //
1207            include_bytes!("../resources/cursors/windows/aliasb"),
1208            0,
1209            0,
1210        );
1211        load_cursor(
1212            CursorIcon::Cell, //
1213            include_bytes!("../resources/cursors/windows/cell"),
1214            7,
1215            7,
1216        );
1217        load_cursor(
1218            CursorIcon::ColResize,
1219            include_bytes!("../resources/cursors/windows/col_resize"),
1220            10,
1221            8,
1222        );
1223        load_cursor(
1224            CursorIcon::Copy, //
1225            include_bytes!("../resources/cursors/windows/copy"),
1226            0,
1227            0,
1228        );
1229        load_cursor(
1230            CursorIcon::Grab, //
1231            include_bytes!("../resources/cursors/windows/grab"),
1232            6,
1233            0,
1234        );
1235        load_cursor(
1236            CursorIcon::Grabbing, //
1237            include_bytes!("../resources/cursors/windows/grabbing"),
1238            6,
1239            0,
1240        );
1241        load_cursor(
1242            CursorIcon::RowResize, //
1243            include_bytes!("../resources/cursors/windows/row_resize"),
1244            9,
1245            10,
1246        );
1247        load_cursor(
1248            CursorIcon::VerticalText, //
1249            include_bytes!("../resources/cursors/windows/vertical_text"),
1250            9,
1251            3,
1252        );
1253        load_cursor(
1254            CursorIcon::ZoomIn, //
1255            include_bytes!("../resources/cursors/windows/zoom_in"),
1256            6,
1257            6,
1258        );
1259        load_cursor(
1260            CursorIcon::ZoomOut, //
1261            include_bytes!("../resources/cursors/windows/zoom_out"),
1262            6,
1263            6,
1264        );
1265    }
1266
1267    custom_cursors
1268}