Skip to main content

vizia_winit/
application.rs

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