Skip to main content

vizia_winit/
application.rs

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