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