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}