pebble_skip/user_interface/window/
mod.rs

1use super::window_stack;
2use crate::{graphics::graphics_types::Color8, Box, Handle, SpecialDrop};
3use core::{
4	marker::PhantomData,
5	mem::ManuallyDrop,
6	ops::{Deref, DerefMut},
7};
8use debugless_unwrap::DebuglessUnwrapNone as _;
9#[allow(clippy::wildcard_imports)]
10use pebble_sys::{
11	standard_c::memory::void,
12	user_interface::window::{Window as sysWindow, WindowHandlers as sysWindowHandlers, *},
13};
14use unsafe_unwrap::UnsafeUnwrap;
15
16pub mod number_window;
17
18#[repr(transparent)] // Needed for WindowRef and WindowRefMut to work.
19pub struct Window<T: ?Sized>(pub(crate) Handle<'static, sysWindow>, PhantomData<T>);
20
21#[repr(transparent)]
22pub struct WindowRef<'a>(Handle<'a, sysWindow>);
23
24#[repr(transparent)]
25pub struct WindowRefMut<'a>(Handle<'a, sysWindow>);
26
27pub struct WindowHandlers<L: FnMut() -> T, A: FnMut(&mut T), D: FnMut(&mut T), U: FnMut(T), T> {
28	pub load: L,
29	pub appear: A,
30	pub disappear: D,
31	pub unload: U,
32}
33
34trait WindowHandlersTrait<T> {
35	fn load(&mut self) -> T;
36	fn appear(&mut self, data: &mut T);
37	fn disappear(&mut self, data: &mut T);
38	fn unload(&mut self, data: T);
39}
40
41impl<L: FnMut() -> T, A: FnMut(&mut T), D: FnMut(&mut T), U: FnMut(T), T> WindowHandlersTrait<T>
42	for WindowHandlers<L, A, D, U, T>
43{
44	fn load(&mut self) -> T {
45		(self.load)()
46	}
47
48	fn appear(&mut self, data: &mut T) {
49		(self.appear)(data)
50	}
51
52	fn disappear(&mut self, data: &mut T) {
53		(self.disappear)(data)
54	}
55
56	fn unload(&mut self, data: T) {
57		(self.unload)(data)
58	}
59}
60
61struct WindowData<'a, T> {
62	user_data: Option<T>,
63	window_handlers: Box<'a, dyn 'a + WindowHandlersTrait<T>>,
64}
65
66pub struct WindowCreationError<L: FnMut() -> T, A: FnMut(&mut T), D: FnMut(&mut T), U: FnMut(T), T>
67{
68	pub window_handlers: WindowHandlers<L, A, D, U, T>,
69}
70
71impl<T> Window<T> {
72	/// Creates a new [`Window<T>`] instance with the specified [window handlers].
73	///
74	/// [`Window<T>`]: #
75	/// [window handlers]: ./struct.WindowHandlers.html
76	///
77	/// # Errors
78	///
79	/// This function errors if associated data can't be allocated on the heap or if the window can't be created for another reason.
80	pub fn new<
81		'a,
82		L: 'a + FnMut() -> T,
83		A: 'a + FnMut(&mut T),
84		D: 'a + FnMut(&mut T),
85		U: 'a + FnMut(T),
86	>(
87		window_handlers: WindowHandlers<L, A, D, U, T>,
88	) -> Result<Self, WindowCreationError<L, A, D, U, T>>
89	where
90		T: 'a,
91	{
92		#![allow(clippy::items_after_statements)]
93
94		let window_data = Box::new(WindowData {
95			user_data: None,
96			window_handlers: Box::new(window_handlers)
97				.map_err(|window_handlers| WindowCreationError { window_handlers })?,
98		})
99		.map_err(|window_data| WindowCreationError::<_, _, _, _, T> {
100			window_handlers: Box::into_inner(unsafe {
101				Box::downcast_unchecked(window_data.window_handlers)
102			}),
103		})?;
104		let raw_window = match unsafe { window_create() } {
105			Some(raw_window) => raw_window,
106			None => {
107				return Err(WindowCreationError {
108					window_handlers: Box::into_inner(unsafe {
109						Box::downcast_unchecked(Box::into_inner(window_data).window_handlers)
110					}),
111				});
112			}
113		};
114
115		extern "C" fn raw_load<T>(raw_window: &mut sysWindow) {
116			let window_data = unsafe {
117				window_get_user_data(raw_window)
118					.cast::<WindowData<T>>()
119					.as_mut()
120					.unsafe_unwrap()
121			};
122			window_data
123				.user_data
124				.replace(window_data.window_handlers.load())
125				.debugless_unwrap_none();
126		}
127		extern "C" fn raw_appear<T>(raw_window: &mut sysWindow) {
128			let window_data = unsafe {
129				window_get_user_data(raw_window)
130					.cast::<WindowData<T>>()
131					.as_mut()
132					.unsafe_unwrap()
133			};
134			window_data
135				.window_handlers
136				.appear(unsafe { window_data.user_data.as_mut().unsafe_unwrap() });
137		}
138		extern "C" fn raw_disappear<T>(raw_window: &mut sysWindow) {
139			let window_data = unsafe {
140				window_get_user_data(raw_window)
141					.cast::<WindowData<T>>()
142					.as_mut()
143					.unsafe_unwrap()
144			};
145			window_data
146				.window_handlers
147				.disappear(unsafe { window_data.user_data.as_mut().unsafe_unwrap() });
148		}
149		extern "C" fn raw_unload<T>(raw_window: &mut sysWindow) {
150			let window_data = unsafe {
151				window_get_user_data(raw_window)
152					.cast::<WindowData<T>>()
153					.as_mut()
154					.unsafe_unwrap()
155			};
156			window_data
157				.window_handlers
158				.unload(unsafe { window_data.user_data.take().unsafe_unwrap() });
159		}
160
161		unsafe {
162			//SAFETY: window_data is only retrieved and destroyed in the destructor, *after* destroying the window.
163			window_set_user_data(raw_window, {
164				let mem: &mut void = Box::leak(window_data).into();
165				mem
166			});
167			window_set_window_handlers(
168				raw_window,
169				sysWindowHandlers {
170					load: Some(raw_load::<T>),
171					appear: Some(raw_appear::<T>),
172					disappear: Some(raw_disappear::<T>),
173					unload: Some(raw_unload::<T>),
174				},
175			)
176		}
177		Ok(Self(Handle::new(raw_window), PhantomData))
178	}
179
180	/// Assembles a new instance of [`Window<T>`] from the given raw window handle.
181	///
182	/// [`Window<T>`]: #
183	///
184	/// # Safety
185	///
186	/// This function is only safe if `raw_window` is a raw window handle that was previously [`.leak()`]ed from the same [`Window<T>`] variant and no other [`Window<T>`] instance has been created from it since.
187	///
188	/// [`.leak()`]: #method.leak
189	/// [`Window<T>`]: #
190	pub unsafe fn from_raw(raw_window: &'static mut sysWindow) -> Self {
191		Self(Handle::new(raw_window), PhantomData)
192	}
193
194	/// Leaks the current [`Window<T>`] instance into a raw Pebble window handle.
195	///
196	/// Note that [`Window<T>`] has associated heap instances beyond the raw window, so only destroying that would still leak memory.
197	///
198	/// [`Window<T>`]: #
199	#[must_use = "Not reassembling the `Window<T>` later causes a memory leak."]
200	pub fn leak(self) -> &'static mut sysWindow
201	where
202		T: 'static,
203	{
204		unsafe { ManuallyDrop::new(self).0.duplicate().unwrap() }
205	}
206}
207
208impl<T: ?Sized> Window<T> {
209	#[allow(clippy::must_use_candidate)] // side effects
210	pub fn hide(&self, animated: bool) -> bool {
211		window_stack::remove(self, animated)
212	}
213
214	#[must_use]
215	pub fn is_loaded(&self) -> bool {
216		// I assume the interior mutation could cause issues with background workers here,
217		// but [`Window`] won't be Send or Sync, so this shouldn't be terrible.
218		unsafe { window_is_loaded(self.0.as_mut_unchecked()) }
219	}
220
221	/// Pushes this window onto the window navidation stack, as topmost window of the app.
222	///
223	/// # Arguments
224	///
225	/// `animated`: Whether to animate the push using a sliding animation.
226	pub fn show(&self, animated: bool) {
227		window_stack::push(self, animated)
228	}
229
230	pub fn set_background_color(&self, background_color: Color8) {
231		unsafe { window_set_background_color(self.0.as_mut_unchecked(), background_color) }
232	}
233}
234
235impl<T: ?Sized> Drop for Window<T> {
236	fn drop(&mut self) {
237		self.special_drop()
238	}
239}
240
241impl<T: ?Sized> SpecialDrop for Window<T> {
242	default fn special_drop(&mut self) {
243		panic!("Dropping unsized `Window<T>`s is illegal")
244	}
245}
246
247impl<T: Sized> SpecialDrop for Window<T> {
248	fn special_drop(&mut self) {
249		unsafe {
250			//SAFETY: window_data is created and leaked in the only accessible constructor.
251			//SAFETY: self.0 isn't accessed after this.
252			let window_data = window_get_user_data(&*self.0).cast();
253			window_destroy(self.0.duplicate().unwrap());
254			Box::<WindowData<T>>::from_raw(&mut *window_data);
255		}
256	}
257}
258
259impl<'a> Deref for WindowRef<'a> {
260	type Target = Window<void>;
261
262	fn deref(&self) -> &Self::Target {
263		//SAFETY: Same memory layout, no access to data.
264		unsafe { &*(self as *const _ as *const Window<void>) }
265	}
266}
267
268impl<'a> Deref for WindowRefMut<'a> {
269	type Target = Window<void>;
270
271	fn deref(&self) -> &Self::Target {
272		//SAFETY: Same memory layout, no access to data.
273		unsafe { &*(self as *const _ as *const Window<void>) }
274	}
275}
276
277impl<'a> DerefMut for WindowRefMut<'a> {
278	fn deref_mut(&mut self) -> &mut Self::Target {
279		//SAFETY: Same memory layout, no access to data.
280		unsafe { &mut *(self as *mut _ as *mut Window<void>) }
281	}
282}