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