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