freya_winit/
extensions.rs

1use freya_core::{
2    prelude::{
3        Platform,
4        UserEvent,
5    },
6    user_event::SingleThreadErasedEvent,
7};
8use winit::window::{
9    Window,
10    WindowId,
11};
12
13use crate::{
14    config::WindowConfig,
15    renderer::{
16        NativeWindowErasedEventAction,
17        WithWindowCallback,
18    },
19};
20
21pub trait WinitPlatformExt {
22    /// Launch a new window with the given configuration.
23    ///
24    /// Returns the [`WindowId`] of the newly created window once it has been created.
25    ///
26    /// # Example
27    ///
28    /// ```rust,no_run
29    /// use freya::prelude::*;
30    ///
31    /// async fn open_new_window() {
32    ///     let window_id = Platform::get()
33    ///         .launch_window(WindowConfig::new(my_app).with_title("New Window"))
34    ///         .await;
35    /// }
36    /// # fn my_app() -> impl IntoElement { rect() }
37    /// ```
38    fn launch_window(&self, window_config: WindowConfig) -> impl Future<Output = WindowId>;
39
40    /// Close an existing window by its [`WindowId`].
41    ///
42    /// # Example
43    ///
44    /// ```rust,no_run
45    /// use freya::{
46    ///     prelude::*,
47    ///     winit::window::WindowId,
48    /// };
49    ///
50    /// fn close_window(window_id: WindowId) {
51    ///     Platform::get().close_window(window_id);
52    /// }
53    /// ```
54    fn close_window(&self, window_id: WindowId);
55
56    /// Focus a window by its [`WindowId`].
57    ///
58    /// If `window_id` is `None`, the current window will be focused.
59    ///
60    /// # Example
61    ///
62    /// ```rust,no_run
63    /// use freya::{
64    ///     prelude::*,
65    ///     winit::window::WindowId,
66    /// };
67    ///
68    /// fn focus_specific_window(window_id: WindowId) {
69    ///     Platform::get().focus_window(Some(window_id));
70    /// }
71    ///
72    /// fn focus_current_window() {
73    ///     Platform::get().focus_window(None);
74    /// }
75    /// ```
76    fn focus_window(&self, window_id: Option<WindowId>);
77
78    /// Execute a callback with mutable access to a [`Window`].
79    ///
80    /// If `window_id` is `None`, the callback will be executed on the current window.
81    /// This allows direct manipulation of the underlying winit [`Window`] for advanced use cases.
82    ///
83    /// # Example
84    ///
85    /// ```rust,no_run
86    /// use freya::{
87    ///     prelude::*,
88    ///     winit::window::WindowId,
89    /// };
90    ///
91    /// fn set_window_title(window_id: Option<WindowId>, title: &'static str) {
92    ///     Platform::get().with_window(window_id, move |window| {
93    ///         window.set_title(title);
94    ///     });
95    /// }
96    ///
97    /// fn minimize_current_window() {
98    ///     Platform::get().with_window(None, |window| {
99    ///         window.set_minimized(true);
100    ///     });
101    /// }
102    /// ```
103    fn with_window(
104        &self,
105        window_id: Option<WindowId>,
106        callback: impl FnOnce(&mut Window) + 'static,
107    );
108}
109
110impl WinitPlatformExt for Platform {
111    async fn launch_window(&self, window_config: WindowConfig) -> WindowId {
112        let (tx, rx) = futures_channel::oneshot::channel();
113        self.send(UserEvent::Erased(SingleThreadErasedEvent(Box::new(
114            NativeWindowErasedEventAction::LaunchWindow {
115                window_config,
116                ack: tx,
117            },
118        ))));
119        rx.await.expect("Failed to create Window")
120    }
121
122    fn close_window(&self, window_id: WindowId) {
123        self.send(UserEvent::Erased(SingleThreadErasedEvent(Box::new(
124            NativeWindowErasedEventAction::CloseWindow(window_id),
125        ))));
126    }
127
128    fn focus_window(&self, window_id: Option<WindowId>) {
129        self.send(UserEvent::Erased(SingleThreadErasedEvent(Box::new(
130            NativeWindowErasedEventAction::WithWindow {
131                window_id,
132                callback: WithWindowCallback(Box::new(|window| window.focus_window())),
133            },
134        ))));
135    }
136
137    fn with_window(
138        &self,
139        window_id: Option<WindowId>,
140        callback: impl FnOnce(&mut Window) + 'static,
141    ) {
142        self.send(UserEvent::Erased(SingleThreadErasedEvent(Box::new(
143            NativeWindowErasedEventAction::WithWindow {
144                window_id,
145                callback: WithWindowCallback(Box::new(callback)),
146            },
147        ))));
148    }
149}