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