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 std::{error::Error, fmt::Display, sync::Arc};
12use vizia_input::ImeState;
13
14// #[cfg(feature = "accesskit")]
15// use accesskit::{Action, NodeBuilder, NodeId, TreeUpdate};
16// #[cfg(feature = "accesskit")]
17// use accesskit_winit;
18// use std::cell::RefCell;
19use vizia_core::context::EventProxy;
20use vizia_core::prelude::*;
21use vizia_core::{backend::*, events::EventManager};
22use winit::{
23    application::ApplicationHandler,
24    dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize},
25    error::EventLoopError,
26    event::ElementState,
27    event_loop::{ActiveEventLoop, ControlFlow, EventLoop, EventLoopProxy},
28    keyboard::{NativeKeyCode, PhysicalKey},
29    window::{CursorIcon, CustomCursor, WindowAttributes, WindowId, WindowLevel},
30};
31
32// #[cfg(all(
33//     feature = "clipboard",
34//     feature = "wayland",
35//     any(
36//         target_os = "linux",
37//         target_os = "dragonfly",
38//         target_os = "freebsd",
39//         target_os = "netbsd",
40//         target_os = "openbsd"
41//     )
42// ))]
43// use raw_window_handle::{HasRawDisplayHandle, RawDisplayHandle};
44use vizia_window::{Anchor, AnchorTarget, WindowPosition};
45
46#[derive(Debug)]
47pub enum UserEvent {
48    Event(Event),
49    #[cfg(feature = "accesskit")]
50    AccessKitEvent(accesskit_winit::Event),
51}
52
53#[cfg(feature = "accesskit")]
54impl From<accesskit_winit::Event> for UserEvent {
55    fn from(action_request_event: accesskit_winit::Event) -> Self {
56        UserEvent::AccessKitEvent(action_request_event)
57    }
58}
59
60impl From<vizia_core::events::Event> for UserEvent {
61    fn from(event: vizia_core::events::Event) -> Self {
62        UserEvent::Event(event)
63    }
64}
65
66type IdleCallback = Option<Box<dyn Fn(&mut Context)>>;
67
68#[derive(Debug)]
69pub enum ApplicationError {
70    EventLoopError(EventLoopError),
71    LogError,
72}
73
74impl Display for ApplicationError {
75    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76        match self {
77            ApplicationError::EventLoopError(ele) => write!(f, "{}", ele),
78            ApplicationError::LogError => write!(f, "log error"),
79        }
80    }
81}
82
83impl std::error::Error for ApplicationError {}
84
85///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.
86///
87/// # Example
88/// ```no_run
89/// # use vizia_core::prelude::*;
90/// # use vizia_winit::application::Application;
91/// Application::new(|cx|{
92///    // Content goes here
93/// })
94/// .run();
95///```
96/// Calling `run()` on the `Application` causes the program to enter the event loop and for the main window to display.
97pub struct Application {
98    cx: BackendContext,
99    event_manager: EventManager,
100    pub(crate) event_loop: Option<EventLoop<UserEvent>>,
101    on_idle: IdleCallback,
102    window_description: WindowDescription,
103    control_flow: ControlFlow,
104    event_loop_proxy: EventLoopProxy<UserEvent>,
105    windows: HashMap<WindowId, WinState>,
106    window_ids: HashMap<Entity, WindowId>,
107    #[cfg(feature = "accesskit")]
108    accesskit_adapter: Option<accesskit_winit::Adapter>,
109    #[cfg(feature = "accesskit")]
110    adapter_initialized: bool,
111}
112
113pub struct WinitEventProxy(EventLoopProxy<UserEvent>);
114
115impl EventProxy for WinitEventProxy {
116    fn send(&self, event: Event) -> Result<(), ()> {
117        self.0.send_event(UserEvent::Event(event)).map_err(|_| ())
118    }
119
120    fn make_clone(&self) -> Box<dyn EventProxy> {
121        Box::new(WinitEventProxy(self.0.clone()))
122    }
123}
124
125impl Application {
126    pub fn new<F>(content: F) -> Self
127    where
128        F: 'static + FnOnce(&mut Context),
129    {
130        let context = Context::new();
131
132        let event_loop =
133            EventLoop::<UserEvent>::with_user_event().build().expect("Failed to create event loop");
134
135        let mut cx = BackendContext::new(context);
136        let event_proxy_obj = event_loop.create_proxy();
137        cx.set_event_proxy(Box::new(WinitEventProxy(event_proxy_obj)));
138
139        cx.renegotiate_language();
140        cx.0.remove_user_themes();
141        (content)(cx.context());
142
143        let proxy = event_loop.create_proxy();
144
145        Self {
146            cx,
147            event_manager: EventManager::new(),
148            event_loop: Some(event_loop),
149            on_idle: None,
150            window_description: WindowDescription::new(),
151            control_flow: ControlFlow::Wait,
152            event_loop_proxy: proxy,
153            windows: HashMap::new(),
154            window_ids: HashMap::new(),
155            #[cfg(feature = "accesskit")]
156            accesskit_adapter: None,
157            #[cfg(feature = "accesskit")]
158            adapter_initialized: false,
159        }
160    }
161
162    fn create_window(
163        &mut self,
164        event_loop: &ActiveEventLoop,
165        window_entity: Entity,
166        window_description: &WindowDescription,
167        #[allow(unused_variables)] owner: Option<Arc<winit::window::Window>>,
168    ) -> Result<Arc<winit::window::Window>, Box<dyn Error>> {
169        #[allow(unused_mut)]
170        let mut window_attributes = apply_window_description(window_description);
171
172        let window_state = WinState::new(event_loop, window_entity, window_attributes, owner)?;
173        let window = window_state.window.clone();
174
175        if let Some(position) = window_description.position {
176            window.set_outer_position(LogicalPosition::new(position.x, position.y));
177        } else {
178            let (anchor, mut parent_anchor) =
179                match (window_description.anchor, window_description.parent_anchor) {
180                    (Some(a), None) => (Some(a), Some(a)),
181                    (None, Some(b)) => (Some(b.opposite()), Some(b)),
182                    t => t,
183                };
184
185            if let Some(anchor) = anchor {
186                let (y, x) = match anchor {
187                    Anchor::TopLeft => (0.0, 0.0),
188                    Anchor::TopCenter => (0.0, 0.5),
189                    Anchor::TopRight => (0.0, 1.0),
190                    Anchor::Left => (0.5, 0.0),
191                    Anchor::Center => (0.5, 0.5),
192                    Anchor::Right => (0.5, 1.0),
193                    Anchor::BottomLeft => (1.0, 0.0),
194                    Anchor::BottomCenter => (1.0, 0.5),
195                    Anchor::BottomRight => (1.0, 1.0),
196                };
197
198                let window_size = window.inner_size();
199
200                let anchor_target = window_description.anchor_target.unwrap_or_default();
201                let parent = match anchor_target {
202                    AnchorTarget::Monitor => window
203                        .current_monitor()
204                        .map(|monitor| (PhysicalPosition::default(), monitor.size())),
205                    AnchorTarget::Window => self
206                        .cx
207                        .0
208                        .tree
209                        .get_parent_window(window_entity)
210                        .and_then(|parent_window| self.window_ids.get(&parent_window))
211                        .and_then(|id| self.windows.get(id))
212                        .map(|win_state| {
213                            (
214                                win_state.window.outer_position().unwrap(),
215                                win_state.window.inner_size(),
216                            )
217                        }),
218                    AnchorTarget::Mouse => self
219                        .cx
220                        .0
221                        .tree
222                        .get_parent_window(window_entity)
223                        .and_then(|parent_window| self.window_ids.get(&parent_window))
224                        .and_then(|id| self.windows.get(id))
225                        .map(|win_state| {
226                            let pos = win_state.window.outer_position().unwrap();
227                            (
228                                PhysicalPosition::new(
229                                    pos.x + self.cx.0.mouse.cursor_x as i32,
230                                    pos.y + self.cx.0.mouse.cursor_y as i32,
231                                ),
232                                PhysicalSize::new(0, 0),
233                            )
234                        }),
235                };
236
237                if let Some((parent_position, parent_size)) = parent {
238                    if anchor_target != AnchorTarget::Window {
239                        parent_anchor = Some(anchor);
240                    }
241
242                    let (py, px) = match parent_anchor.unwrap_or_default() {
243                        Anchor::TopLeft => (0.0, 0.0),
244                        Anchor::TopCenter => (0.0, 0.5),
245                        Anchor::TopRight => (0.0, 1.0),
246                        Anchor::Left => (0.5, 0.0),
247                        Anchor::Center => (0.5, 0.5),
248                        Anchor::Right => (0.5, 1.0),
249                        Anchor::BottomLeft => (1.0, 0.0),
250                        Anchor::BottomCenter => (1.0, 0.5),
251                        Anchor::BottomRight => (1.0, 1.0),
252                    };
253
254                    let x = (((parent_size.width as f32 * px) as i32
255                        - (window_size.width as f32 * x) as i32)
256                        as f32) as i32;
257                    let y = (((parent_size.height as f32 * py) as i32
258                        - (window_size.height as f32 * y) as i32)
259                        as f32) as i32;
260
261                    let offset = window_description.offset.unwrap_or_default();
262                    let offset: PhysicalPosition<i32> = PhysicalPosition::from_logical(
263                        LogicalPosition::new(offset.x, offset.y),
264                        window.scale_factor(),
265                    );
266
267                    window.set_outer_position(PhysicalPosition::new(
268                        parent_position.x + x as i32 + offset.x,
269                        parent_position.y + y as i32 + offset.y,
270                    ));
271                }
272            }
273        }
274
275        let window_id = window_state.window.id();
276        self.windows.insert(window_id, window_state);
277        self.window_ids.insert(window_entity, window_id);
278        Ok(window)
279    }
280
281    /// Sets the default built-in theming to be ignored.
282    pub fn ignore_default_theme(mut self) -> Self {
283        self.cx.context().ignore_default_theme = true;
284        self
285    }
286
287    pub fn should_poll(mut self) -> Self {
288        self.control_flow = ControlFlow::Poll;
289
290        self
291    }
292
293    /// Takes a closure which will be called at the end of every loop of the application.
294    ///
295    /// The callback provides a place to run 'idle' processing and happens at the end of each loop but before drawing.
296    /// If the callback pushes events into the queue in state then the event loop will re-run. Care must be taken not to
297    /// push events into the queue every time the callback runs unless this is intended.
298    ///
299    /// # Example
300    ///
301    /// ```no_run
302    /// # use vizia_core::prelude::*;
303    /// # use vizia_winit::application::Application;
304    /// #
305    /// Application::new(|cx| {
306    ///     // Build application here
307    /// })
308    /// .on_idle(|cx| {
309    ///     // Code here runs at the end of every event loop after OS and vizia events have been handled
310    /// })
311    /// .run();
312    /// ```
313    pub fn on_idle<F: 'static + Fn(&mut Context)>(mut self, callback: F) -> Self {
314        self.on_idle = Some(Box::new(callback));
315
316        self
317    }
318
319    /// Returns a `ContextProxy` which can be used to send events from another thread.
320    pub fn get_proxy(&self) -> ContextProxy {
321        self.cx.0.get_proxy()
322    }
323
324    pub fn run(mut self) -> Result<(), ApplicationError> {
325        self.event_loop.take().unwrap().run_app(&mut self).map_err(ApplicationError::EventLoopError)
326    }
327}
328
329impl ApplicationHandler<UserEvent> for Application {
330    fn user_event(&mut self, _event_loop: &ActiveEventLoop, user_event: UserEvent) {
331        match user_event {
332            UserEvent::Event(event) => {
333                self.cx.send_event(event);
334            }
335
336            #[cfg(feature = "accesskit")]
337            UserEvent::AccessKitEvent(access_event) => {
338                match access_event.window_event {
339                    accesskit_winit::WindowEvent::InitialTreeRequested => {
340                        let tree_update = self.cx.init_accessibility_tree();
341                        if let Some(adapter) = &mut self.accesskit_adapter {
342                            adapter.update_if_active(|| {
343                                self.adapter_initialized = true;
344                                tree_update
345                            });
346                        }
347                    }
348                    accesskit_winit::WindowEvent::ActionRequested(action_request) => {
349                        let node_id = action_request.target;
350
351                        if action_request.action != Action::ScrollIntoView {
352                            let entity = Entity::new(node_id.0, 0);
353
354                            // Handle focus action from screen reader
355                            if action_request.action == Action::Focus {
356                                self.cx.0.with_current(entity, |cx| {
357                                    cx.focus();
358                                });
359                            }
360
361                            self.cx.send_event(
362                                Event::new(WindowEvent::ActionRequest(action_request))
363                                    .direct(entity),
364                            );
365                        }
366                    }
367                    accesskit_winit::WindowEvent::AccessibilityDeactivated => todo!(),
368                }
369            }
370        }
371    }
372
373    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
374        if self.windows.is_empty() {
375            // Create the main window
376            let main_window: Arc<winit::window::Window> = self
377                .create_window(event_loop, Entity::root(), &self.window_description.clone(), None)
378                .expect("failed to create initial window");
379            let custom_cursors = Arc::new(load_default_cursors(event_loop));
380            self.cx.add_main_window(
381                Entity::root(),
382                &self.window_description,
383                main_window.scale_factor() as f32,
384            );
385            self.cx.add_window(Window {
386                window: Some(main_window.clone()),
387                on_close: None,
388                on_create: None,
389                should_close: false,
390                custom_cursors: custom_cursors.clone(),
391            });
392
393            self.cx.0.windows.insert(
394                Entity::root(),
395                WindowState {
396                    window_description: self.window_description.clone(),
397                    ..Default::default()
398                },
399            );
400
401            #[cfg(feature = "accesskit")]
402            {
403                self.accesskit_adapter = Some(Adapter::with_event_loop_proxy(
404                    event_loop,
405                    &main_window,
406                    self.event_loop_proxy.clone(),
407                ));
408            }
409
410            main_window.set_visible(self.window_description.visible);
411
412            // set current system theme if available
413            if let Some(theme) = main_window.theme() {
414                let theme = match theme {
415                    winit::window::Theme::Light => ThemeMode::LightMode,
416                    winit::window::Theme::Dark => ThemeMode::DarkMode,
417                };
418                self.cx.emit_origin(WindowEvent::ThemeChanged(theme));
419            }
420
421            self.cx.0.remove_user_themes();
422
423            // Create any subwindows
424            for (window_entity, window_state) in self.cx.0.windows.clone().into_iter() {
425                if window_entity == Entity::root() {
426                    continue;
427                }
428                let owner = window_state.owner.and_then(|entity| {
429                    self.window_ids
430                        .get(&entity)
431                        .and_then(|id| self.windows.get(id).map(|ws| ws.window.clone()))
432                });
433
434                let window = self
435                    .create_window(
436                        event_loop,
437                        window_entity,
438                        &window_state.window_description,
439                        owner,
440                    )
441                    .expect("Failed to create window");
442
443                self.cx.add_main_window(
444                    window_entity,
445                    &window_state.window_description,
446                    window.scale_factor() as f32,
447                );
448
449                self.cx.0.with_current(window_entity, |cx| {
450                    if let Some(content) = &window_state.content {
451                        (content)(cx)
452                    }
453                });
454                self.cx.mutate_window(window_entity, |cx, win: &mut Window| {
455                    win.window = Some(window.clone());
456                    win.custom_cursors = custom_cursors.clone();
457                    if let Some(callback) = &win.on_create {
458                        (callback)(&mut EventContext::new_with_current(
459                            cx.context(),
460                            window_entity,
461                        ));
462                    }
463                });
464                self.cx.needs_refresh(window_entity);
465            }
466        }
467    }
468
469    fn window_event(
470        &mut self,
471        _event_loop: &ActiveEventLoop,
472        window_id: WindowId,
473        event: winit::event::WindowEvent,
474    ) {
475        let window = match self.windows.get_mut(&window_id) {
476            Some(window) => window,
477            None => return,
478        };
479
480        match event {
481            winit::event::WindowEvent::Resized(size) => {
482                window.resize(size);
483                self.cx.set_window_size(window.entity, size.width as f32, size.height as f32);
484                self.cx.needs_refresh(window.entity);
485                window.window().request_redraw();
486
487                #[cfg(target_os = "windows")]
488                {
489                    self.event_manager.flush_events(self.cx.context(), |_| {});
490
491                    self.cx.process_style_updates();
492
493                    if self.cx.process_animations() {
494                        window.window().request_redraw();
495                    }
496
497                    self.cx.process_visual_updates();
498
499                    // #[cfg(feature = "accesskit")]
500
501                    // self.cx.process_tree_updates(|tree_updates| {
502                    //     for update in tree_updates.iter_mut() {
503                    //         self.accesskit_adapter
504                    //             .unwrap()
505                    //             .update_if_active(|| update.take().unwrap());
506                    //     }
507                    // });
508
509                    // for update in self.cx.0.tree_updates.iter_mut() {
510                    //     self.accesskit_adapter
511                    //         .as_mut()
512                    //         .unwrap()
513                    //         .update_if_active(|| update.take().unwrap());
514                    // }
515
516                    // self.cx.0.tree_updates.clear();
517
518                    window.window().request_redraw();
519                }
520            }
521
522            winit::event::WindowEvent::Moved(position) => {
523                let window_entity = window.entity;
524                self.cx.emit_window_event(
525                    window_entity,
526                    WindowEvent::WindowMoved(WindowPosition { x: position.x, y: position.y }),
527                );
528
529                #[cfg(target_os = "windows")]
530                {
531                    self.event_manager.flush_events(self.cx.context(), |_| {});
532
533                    self.cx.process_style_updates();
534
535                    if self.cx.process_animations() {
536                        window.window().request_redraw();
537                    }
538
539                    self.cx.process_visual_updates();
540
541                    // #[cfg(feature = "accesskit")]
542
543                    // self.cx.process_tree_updates(|tree_updates| {
544                    //     for update in tree_updates.iter_mut() {
545                    //         self.accesskit_adapter
546                    //             .unwrap()
547                    //             .update_if_active(|| update.take().unwrap());
548                    //     }
549                    // });
550
551                    // for update in self.cx.0.tree_updates.iter_mut() {
552                    //     self.accesskit_adapter
553                    //         .as_mut()
554                    //         .unwrap()
555                    //         .update_if_active(|| update.take().unwrap());
556                    // }
557
558                    // self.cx.0.tree_updates.clear();
559
560                    window.window().request_redraw();
561                }
562            }
563
564            winit::event::WindowEvent::CloseRequested | winit::event::WindowEvent::Destroyed => {
565                let window_entity = window.entity;
566                self.cx.emit_window_event(window_entity, WindowEvent::WindowClose);
567            }
568            winit::event::WindowEvent::DroppedFile(path) => {
569                self.cx.emit_window_event(window.entity, WindowEvent::Drop(DropData::File(path)));
570            }
571
572            winit::event::WindowEvent::HoveredFile(_) => {}
573            winit::event::WindowEvent::HoveredFileCancelled => {}
574            winit::event::WindowEvent::Focused(is_focused) => {
575                self.cx.emit_window_event(window.entity, WindowEvent::WindowFocused(is_focused));
576
577                self.cx.0.window_has_focus = is_focused;
578                // #[cfg(feature = "accesskit")]
579                // accesskit.update_if_active(|| TreeUpdate {
580                //     nodes: vec![],
581                //     tree: None,
582                //     focus: is_focused.then_some(self.cx.focused().accesskit_id()).unwrap_or(NodeId(0)),
583                // });
584            }
585            winit::event::WindowEvent::KeyboardInput { device_id: _, event, is_synthetic: _ } => {
586                let code = match event.physical_key {
587                    PhysicalKey::Code(code) => winit_key_code_to_code(code),
588                    PhysicalKey::Unidentified(native) => match native {
589                        NativeKeyCode::Windows(_scancode) => return,
590                        _ => return,
591                    },
592                };
593
594                let key = match event.logical_key {
595                    winit::keyboard::Key::Named(named_key) => winit_key_to_key(named_key),
596                    _ => None,
597                };
598
599                if let winit::keyboard::Key::Character(character) = event.logical_key {
600                    if event.state == ElementState::Pressed {
601                        self.cx.emit_window_event(
602                            window.entity,
603                            WindowEvent::CharInput(character.as_str().chars().next().unwrap()),
604                        );
605                    }
606                }
607
608                let event = match event.state {
609                    winit::event::ElementState::Pressed => WindowEvent::KeyDown(code, key),
610                    winit::event::ElementState::Released => WindowEvent::KeyUp(code, key),
611                };
612
613                self.cx.emit_window_event(window.entity, event);
614                window.window().request_redraw();
615            }
616            winit::event::WindowEvent::ModifiersChanged(modifiers) => {
617                self.cx.modifiers().set(Modifiers::SHIFT, modifiers.state().shift_key());
618
619                self.cx.modifiers().set(Modifiers::ALT, modifiers.state().alt_key());
620
621                self.cx.modifiers().set(Modifiers::CTRL, modifiers.state().control_key());
622
623                self.cx.modifiers().set(Modifiers::SUPER, modifiers.state().super_key());
624
625                window.window().request_redraw();
626            }
627            winit::event::WindowEvent::Ime(ime) => match ime {
628                winit::event::Ime::Enabled => {
629                    self.cx.0.set_ime_state(ImeState::StartComposition);
630                    self.cx.emit_window_event(window.entity, WindowEvent::ImeActivate(true));
631                }
632                winit::event::Ime::Preedit(text, cursor) => {
633                    self.cx.0.set_ime_state(ImeState::Composing {
634                        preedit: Some(text.clone()),
635                        cursor_pos: cursor,
636                    });
637                    self.cx.emit_window_event(window.entity, WindowEvent::ImePreedit(text, cursor));
638                }
639                winit::event::Ime::Commit(text) => {
640                    self.cx.0.set_ime_state(ImeState::EndComposition);
641                    self.cx.emit_window_event(window.entity, WindowEvent::ImeCommit(text));
642                }
643                winit::event::Ime::Disabled => {
644                    self.cx.0.set_ime_state(ImeState::Inactive);
645                    self.cx.emit_window_event(window.entity, WindowEvent::ImeActivate(false));
646                }
647            },
648            winit::event::WindowEvent::CursorMoved { device_id: _, position } => {
649                self.cx.emit_window_event(
650                    window.entity,
651                    WindowEvent::MouseMove(position.x as f32, position.y as f32),
652                );
653                window.window().request_redraw();
654            }
655            winit::event::WindowEvent::CursorEntered { device_id: _ } => {
656                self.cx.emit_window_event(window.entity, WindowEvent::MouseEnter);
657                window.window().request_redraw();
658            }
659            winit::event::WindowEvent::CursorLeft { device_id: _ } => {
660                self.cx.emit_window_event(window.entity, WindowEvent::MouseLeave);
661                window.window().request_redraw();
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                window.window().request_redraw();
678            }
679            winit::event::WindowEvent::MouseInput { device_id: _, state, button } => {
680                let button = match button {
681                    winit::event::MouseButton::Left => MouseButton::Left,
682                    winit::event::MouseButton::Right => MouseButton::Right,
683                    winit::event::MouseButton::Middle => MouseButton::Middle,
684                    winit::event::MouseButton::Other(val) => MouseButton::Other(val),
685                    winit::event::MouseButton::Back => MouseButton::Back,
686                    winit::event::MouseButton::Forward => MouseButton::Forward,
687                };
688
689                let event = match state {
690                    winit::event::ElementState::Pressed => WindowEvent::MouseDown(button),
691                    winit::event::ElementState::Released => WindowEvent::MouseUp(button),
692                };
693
694                self.cx.emit_window_event(window.entity, event);
695                window.window().request_redraw();
696            }
697
698            winit::event::WindowEvent::ScaleFactorChanged {
699                scale_factor,
700                inner_size_writer: _,
701            } => {
702                self.cx.set_scale_factor(scale_factor);
703                self.cx.needs_refresh(window.entity);
704            }
705            winit::event::WindowEvent::ThemeChanged(theme) => {
706                let theme = match theme {
707                    winit::window::Theme::Light => ThemeMode::LightMode,
708                    winit::window::Theme::Dark => ThemeMode::DarkMode,
709                };
710                self.cx.emit_window_event(window.entity, WindowEvent::ThemeChanged(theme));
711            }
712            winit::event::WindowEvent::Occluded(_) => {}
713            winit::event::WindowEvent::RedrawRequested => {
714                for window in self.windows.values_mut() {
715                    window.make_current();
716                    //self.cx.needs_refresh(window.entity);
717                    if self.cx.draw(window.entity, &mut window.surface, &mut window.dirty_surface) {
718                        window.swap_buffers();
719                    }
720
721                    // Un-cloak
722                    #[cfg(target_os = "windows")]
723                    if window.is_initially_cloaked {
724                        window.is_initially_cloaked = false;
725                        set_cloak(window.window(), false);
726                    }
727                }
728            }
729
730            _ => {}
731        }
732    }
733
734    fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
735        if self.windows.is_empty() {
736            event_loop.exit();
737            return;
738        }
739
740        event_loop.set_control_flow(self.control_flow);
741
742        self.event_manager.flush_events(self.cx.context(), |_| {});
743
744        self.cx.process_style_updates();
745
746        if self.cx.process_animations() {
747            for window in self.windows.values() {
748                window.window().request_redraw();
749            }
750        }
751
752        self.cx.process_visual_updates();
753
754        #[cfg(feature = "accesskit")]
755        {
756            self.cx.process_tree_updates();
757
758            if self.adapter_initialized {
759                for update in self.cx.0.tree_updates.iter_mut() {
760                    self.accesskit_adapter
761                        .as_mut()
762                        .unwrap()
763                        .update_if_active(|| update.take().unwrap());
764                }
765            }
766
767            self.cx.0.tree_updates.clear();
768        }
769
770        if let Some(idle_callback) = &self.on_idle {
771            self.cx.set_current(Entity::root());
772            (idle_callback)(self.cx.context());
773        }
774
775        if self.cx.has_queued_events() {
776            self.event_loop_proxy
777                .send_event(UserEvent::Event(Event::new(())))
778                .expect("Failed to send event");
779        }
780
781        if self.cx.0.windows.iter().any(|(_, window_state)| !window_state.redraw_list.is_empty()) {
782            for window in self.windows.values() {
783                window.window().request_redraw();
784            }
785        }
786
787        if self.control_flow != ControlFlow::Poll {
788            if let Some(timer_time) = self.cx.get_next_timer_time() {
789                event_loop.set_control_flow(ControlFlow::WaitUntil(timer_time));
790            } else {
791                event_loop.set_control_flow(ControlFlow::Wait);
792            }
793        }
794
795        let window_entities = self
796            .cx
797            .0
798            .windows
799            .iter()
800            .filter_map(|(entity, state)| state.should_close.then_some(*entity))
801            .collect::<Vec<_>>();
802
803        for window_entity in window_entities {
804            self.cx.0.remove(window_entity);
805        }
806
807        // Sync window state with context
808        self.windows.retain(|_, win| self.cx.0.windows.contains_key(&win.entity));
809        self.window_ids.retain(|e, _| self.cx.0.windows.contains_key(e));
810
811        if self.windows.len() != self.cx.0.windows.len() {
812            for (window_entity, window_state) in self.cx.0.windows.clone().iter() {
813                if !self.window_ids.contains_key(window_entity) {
814                    let owner = window_state.owner.and_then(|entity| {
815                        self.window_ids
816                            .get(&entity)
817                            .and_then(|id| self.windows.get(id).map(|ws| ws.window.clone()))
818                    });
819
820                    let window = self
821                        .create_window(
822                            event_loop,
823                            *window_entity,
824                            &window_state.window_description,
825                            owner,
826                        )
827                        .expect("Failed to create window");
828
829                    self.cx.add_main_window(
830                        *window_entity,
831                        &window_state.window_description,
832                        window.scale_factor() as f32,
833                    );
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}