1use super::lvgl;
2use crate::{Color, Error, EventKind, Key, Result, event::Event};
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 discard_events_for_target(&mut self, target: *mut lvgl::lv_obj_t) {
182 self.event_queue.retain(|event| event.target != target);
183 }
184
185 pub fn clear_event_targets_for(&mut self, target: *mut lvgl::lv_obj_t) {
189 for event in &mut self.event_queue {
190 if event.target == target {
191 event.target = ptr::null_mut();
192 }
193 }
194 }
195
196 pub fn as_object(&self) -> &lvgl::lv_obj_t {
197 &self.object
198 }
199
200 pub fn as_object_mutable(&mut self) -> &mut lvgl::lv_obj_t {
201 &mut self.object
202 }
203
204 pub fn get_icon(&self) -> (&str, Color) {
205 let icon_string = str::from_utf8(&self.icon_text)
206 .unwrap_or("??")
207 .trim_matches(char::from(0));
208
209 (icon_string, self.icon_color)
210 }
211
212 pub fn set_icon(&mut self, icon_string: &str, icon_color: Color) {
213 let mut iterator = icon_string.chars();
214
215 if let Some(character) = iterator.next() {
216 self.icon_text[0] = character as u8;
217 }
218
219 if let Some(character) = iterator.next() {
220 self.icon_text[1] = character as u8;
221 }
222
223 self.icon_color = icon_color;
224 }
225
226 pub fn wake_up(&mut self) {
227 self.waker.wake();
228 }
229
230 pub fn register_waker(&mut self, waker: &core::task::Waker) {
231 self.waker.register(waker);
232 }
233
234 pub unsafe fn from_raw(window: *mut lvgl::lv_obj_t) -> Option<NonNull<Self>> {
245 if window.is_null() {
246 return None;
247 }
248
249 let class = unsafe { lvgl::lv_obj_get_class(window) };
250
251 if class != get_window_class() {
252 return None;
253 }
254
255 NonNull::new(window as *mut Self)
256 }
257
258 pub fn delete(&mut self) {
259 unsafe {
260 lvgl::lv_obj_delete(&mut self.object);
261 }
262 }
263}
264
265impl AsRef<lvgl::lv_obj_t> for Window {
266 #[inline]
267 fn as_ref(&self) -> &lvgl::lv_obj_t {
268 &self.object
269 }
270}
271
272impl AsMut<lvgl::lv_obj_t> for Window {
273 #[inline]
274 fn as_mut(&mut self) -> &mut lvgl::lv_obj_t {
275 &mut self.object
276 }
277}
278
279impl Deref for Window {
280 type Target = lvgl::lv_obj_t;
281
282 #[inline]
283 fn deref(&self) -> &Self::Target {
284 &self.object
285 }
286}
287
288impl DerefMut for Window {
289 #[inline]
290 fn deref_mut(&mut self) -> &mut Self::Target {
291 &mut self.object
292 }
293}
294
295pub struct OwnedWindow(NonNull<Window>);
297
298impl OwnedWindow {
299 pub fn new(window: NonNull<Window>) -> Self {
300 Self(window)
301 }
302}
303
304impl From<OwnedWindow> for NonNull<Window> {
305 fn from(val: OwnedWindow) -> Self {
306 let this = ManuallyDrop::new(val);
307 this.0
308 }
309}
310
311impl Drop for OwnedWindow {
312 fn drop(&mut self) {
313 crate::ffi_manager()
314 .lock_function_sync(|| {
315 unsafe {
316 self.0.as_mut().delete();
317 }
318 Ok(())
319 })
320 .expect("Failed to delete window");
321 }
322}
323
324impl Deref for OwnedWindow {
325 type Target = Window;
326
327 #[inline]
328 fn deref(&self) -> &Self::Target {
329 unsafe { self.0.as_ref() }
330 }
331}
332
333impl DerefMut for OwnedWindow {
334 #[inline]
335 fn deref_mut(&mut self) -> &mut Self::Target {
336 unsafe { self.0.as_mut() }
337 }
338}