1use super::lvgl;
2use crate::{Color, Error, EventKind, Key, Result, event::Event, synchronous_lock};
3use alloc::collections::VecDeque;
4use core::{
5 mem::ManuallyDrop,
6 ops::{Deref, DerefMut},
7 ptr::{self, NonNull},
8 str,
9};
10use synchronization::{once_lock::OnceLock, waitqueue::AtomicWaker};
11
12const WINDOW_QUEUE_DEFAULT_CAPACITY: usize = 10;
13
14#[repr(transparent)]
15pub struct ClassWrapper(lvgl::lv_obj_class_t);
16
17unsafe impl Send for ClassWrapper {}
18unsafe impl Sync for ClassWrapper {}
19
20static WINDOW_CLASS: OnceLock<ClassWrapper> = OnceLock::new();
21
22pub fn get_window_class() -> &'static lvgl::lv_obj_class_t {
23 let class_ref = WINDOW_CLASS.get_or_init(|| {
24 let mut cls = lvgl::lv_obj_class_t {
25 base_class: unsafe { &lvgl::lv_obj_class },
26 constructor_cb: Some(window_constructor),
27 destructor_cb: Some(window_destructor),
28 event_cb: Some(window_event_callback),
29 width_def: unsafe { lvgl::lv_pct(100) },
30 height_def: unsafe { lvgl::lv_pct(100) },
31 name: c"window".as_ptr(),
32 ..Default::default()
33 };
34
35 cls.set_instance_size(size_of::<Window>() as _);
36 cls.set_group_def(lvgl::lv_obj_class_group_def_t_LV_OBJ_CLASS_GROUP_DEF_INHERIT as _);
37 cls.set_theme_inheritable(
38 lvgl::lv_obj_class_theme_inheritable_t_LV_OBJ_CLASS_THEME_INHERITABLE_TRUE as _,
39 );
40 cls.set_editable(lvgl::lv_obj_class_editable_t_LV_OBJ_CLASS_EDITABLE_INHERIT as _);
41
42 ClassWrapper(cls)
43 });
44
45 &class_ref.0
46}
47
48#[repr(C)]
49pub struct Window {
50 object: lvgl::lv_obj_t,
51 event_queue: VecDeque<Event>,
52 icon_text: [u8; 2],
53 icon_color: Color,
54 waker: AtomicWaker,
55}
56
57unsafe extern "C" fn window_constructor(
58 _class_p: *const lvgl::lv_obj_class_t,
59 object: *mut lvgl::lv_obj_t,
60) {
61 unsafe {
62 let window = object as *mut Window;
63
64 ptr::write(
65 &mut (*window).event_queue,
66 VecDeque::with_capacity(WINDOW_QUEUE_DEFAULT_CAPACITY),
67 );
68 ptr::write(&mut (*window).icon_text, *b"Wi");
69 ptr::write(&mut (*window).icon_color, Color::BLACK);
70 ptr::write(&mut (*window).waker, AtomicWaker::new());
71
72 lvgl::lv_obj_add_flag(
73 &mut (*window).object,
74 lvgl::lv_obj_flag_t_LV_OBJ_FLAG_EVENT_BUBBLE,
75 );
76 lvgl::lv_obj_set_style_border_width(&mut (*window).object, 0, lvgl::LV_STATE_DEFAULT);
77 lvgl::lv_obj_set_style_radius(&mut (*window).object, 0, lvgl::LV_STATE_DEFAULT);
78 }
79}
80
81unsafe extern "C" fn window_destructor(
82 _class_p: *const lvgl::lv_obj_class_t,
83 obj: *mut lvgl::lv_obj_t,
84) {
85 unsafe {
86 let window = obj as *mut Window;
87 core::ptr::drop_in_place(window);
89 }
90}
91
92unsafe extern "C" fn window_event_callback(
93 _class_p: *const lvgl::lv_obj_class_t,
94 event: *mut lvgl::lv_event_t,
95) {
96 unsafe {
97 let res = lvgl::lv_obj_event_base(get_window_class(), event);
98
99 if res != lvgl::lv_result_t_LV_RESULT_OK {
100 return; }
102
103 let code = lvgl::lv_event_get_code(event);
104
105 let window = lvgl::lv_event_get_current_target(event) as *mut Window;
106 let target = lvgl::lv_event_get_target(event) as *mut lvgl::lv_obj_t;
107
108 let (code, key) = match code {
109 lvgl::lv_event_code_t_LV_EVENT_CHILD_CREATED => {
110 lvgl::lv_obj_add_flag(target, lvgl::lv_obj_flag_t_LV_OBJ_FLAG_EVENT_BUBBLE);
111 (code, None)
112 }
113 lvgl::lv_event_code_t_LV_EVENT_KEY => {
114 let key = lvgl::lv_indev_get_key(lvgl::lv_indev_active());
115 let key = Key::from(key);
116 (code, Some(key))
117 }
118 lvgl::lv_event_code_t_LV_EVENT_DRAW_MAIN
119 | lvgl::lv_event_code_t_LV_EVENT_DRAW_MAIN_BEGIN
120 | lvgl::lv_event_code_t_LV_EVENT_DRAW_MAIN_END
121 | lvgl::lv_event_code_t_LV_EVENT_DRAW_POST
122 | lvgl::lv_event_code_t_LV_EVENT_DRAW_POST_BEGIN
123 | lvgl::lv_event_code_t_LV_EVENT_GET_SELF_SIZE
124 | lvgl::lv_event_code_t_LV_EVENT_COVER_CHECK
125 | lvgl::lv_event_code_t_LV_EVENT_LAYOUT_CHANGED => {
126 return;
127 }
129 _ => (code, None),
130 };
131
132 (*window)
133 .event_queue
134 .push_back(Event::new(EventKind::from_lvgl_code(code), target, key));
135 (*window).waker.wake();
136 }
137}
138
139impl Window {
140 pub unsafe fn new(parent: *mut lvgl::lv_obj_t) -> Result<NonNull<Self>> {
155 let obj = unsafe { lvgl::lv_obj_class_create_obj(get_window_class(), parent) };
156
157 unsafe {
158 lvgl::lv_obj_class_init_obj(obj);
159 }
160
161 match NonNull::new(obj as *mut Self) {
162 Some(window) => Ok(window),
163 None => Err(Error::FailedToCreateObject),
164 }
165 }
166
167 pub fn get_identifier(&self) -> usize {
168 self as *const Self as usize
169 }
170
171 pub fn peek_event(&self) -> Option<Event> {
172 self.event_queue.front().cloned()
173 }
174
175 pub fn pop_event(&mut self) -> Option<Event> {
176 self.event_queue.pop_front()
177 }
178
179 pub fn as_object(&self) -> &lvgl::lv_obj_t {
180 &self.object
181 }
182
183 pub fn as_object_mutable(&mut self) -> &mut lvgl::lv_obj_t {
184 &mut self.object
185 }
186
187 pub fn get_icon(&self) -> (&str, Color) {
188 let icon_string = str::from_utf8(&self.icon_text)
189 .unwrap_or("??")
190 .trim_matches(char::from(0));
191
192 (icon_string, self.icon_color)
193 }
194
195 pub fn set_icon(&mut self, icon_string: &str, icon_color: Color) {
196 let mut iterator = icon_string.chars();
197
198 if let Some(character) = iterator.next() {
199 self.icon_text[0] = character as u8;
200 }
201
202 if let Some(character) = iterator.next() {
203 self.icon_text[1] = character as u8;
204 }
205
206 self.icon_color = icon_color;
207 }
208
209 pub fn wake_up(&mut self) {
210 self.waker.wake();
211 }
212
213 pub fn register_waker(&mut self, waker: &core::task::Waker) {
214 self.waker.register(waker);
215 }
216
217 pub unsafe fn from_raw(window: *mut lvgl::lv_obj_t) -> Option<NonNull<Self>> {
228 if !unsafe { lvgl::lv_obj_is_valid(window) } {
229 return None;
230 }
231
232 let class = unsafe { lvgl::lv_obj_get_class(window) };
233
234 if class != get_window_class() {
235 return None;
236 }
237
238 NonNull::new(window as *mut Self)
239 }
240
241 pub fn delete(&mut self) {
242 unsafe {
243 lvgl::lv_obj_delete(&mut self.object);
244 }
245 }
246}
247
248impl AsRef<lvgl::lv_obj_t> for Window {
249 #[inline]
250 fn as_ref(&self) -> &lvgl::lv_obj_t {
251 &self.object
252 }
253}
254
255impl AsMut<lvgl::lv_obj_t> for Window {
256 #[inline]
257 fn as_mut(&mut self) -> &mut lvgl::lv_obj_t {
258 &mut self.object
259 }
260}
261
262impl Deref for Window {
263 type Target = lvgl::lv_obj_t;
264
265 #[inline]
266 fn deref(&self) -> &Self::Target {
267 &self.object
268 }
269}
270
271impl DerefMut for Window {
272 #[inline]
273 fn deref_mut(&mut self) -> &mut Self::Target {
274 &mut self.object
275 }
276}
277
278pub struct OwnedWindow(NonNull<Window>);
280
281impl OwnedWindow {
282 pub fn new(window: NonNull<Window>) -> Self {
283 Self(window)
284 }
285}
286
287impl From<NonNull<Window>> for OwnedWindow {
288 fn from(window: NonNull<Window>) -> Self {
289 Self::new(window)
290 }
291}
292
293impl From<OwnedWindow> for NonNull<Window> {
294 fn from(val: OwnedWindow) -> Self {
295 let this = ManuallyDrop::new(val);
296 this.0
297 }
298}
299
300impl Drop for OwnedWindow {
301 fn drop(&mut self) {
302 synchronous_lock!({
303 unsafe {
304 self.0.as_mut().delete();
305 }
306 });
307 }
308}
309
310impl Deref for OwnedWindow {
311 type Target = Window;
312
313 #[inline]
314 fn deref(&self) -> &Self::Target {
315 unsafe { self.0.as_ref() }
316 }
317}
318
319impl DerefMut for OwnedWindow {
320 #[inline]
321 fn deref_mut(&mut self) -> &mut Self::Target {
322 unsafe { self.0.as_mut() }
323 }
324}