1use alloc::{
2 string::{String, ToString},
3 vec,
4 vec::Vec,
5};
6use synchronization::blocking_mutex::raw::CriticalSectionRawMutex;
7use synchronization::mutex::{Mutex, MutexGuard};
8use synchronization::{once_lock::OnceLock, rwlock::RwLock};
9
10use core::{future::Future, mem::forget};
11
12use core::time::Duration;
13use file_system::Device;
14
15use super::lvgl;
16
17use super::Point;
18
19use crate::Color;
20use crate::Display;
21use crate::Input;
22use crate::InputKind;
23use crate::window::Window;
24use crate::{Error, Result, ScreenReadData};
25
26static MANAGER_INSTANCE: OnceLock<Manager> = OnceLock::new();
27
28pub async fn initialize(
29 screen_device: Device,
30 input_device: Device,
31 input_device_type: InputKind,
32 buffer_size: usize,
33 double_buffered: bool,
34) -> &'static Manager {
35 let manager = Manager::new(
36 time::get_instance(),
37 screen_device,
38 input_device,
39 input_device_type,
40 buffer_size,
41 double_buffered,
42 )
43 .expect("Failed to create manager instance");
44
45 MANAGER_INSTANCE.get_or_init(|| manager)
46}
47
48pub fn get_instance() -> &'static Manager {
49 MANAGER_INSTANCE
50 .try_get()
51 .expect("Graphics manager not initialized")
52}
53
54struct Inner {
55 _inputs: Vec<Input>,
56 _displays: Vec<Display>,
57 window_parent: *mut lvgl::lv_obj_t,
58}
59
60pub struct Manager {
61 inner: RwLock<CriticalSectionRawMutex, Inner>,
62 global_lock: Mutex<CriticalSectionRawMutex, ()>,
63}
64
65impl Drop for Manager {
66 fn drop(&mut self) {
67 unsafe {
68 lvgl::lv_deinit();
69 }
70 }
71}
72
73extern "C" fn binding_tick_callback_function() -> u32 {
74 time::get_instance()
75 .get_current_time()
76 .unwrap_or_default()
77 .as_millis() as u32
78}
79
80unsafe impl Send for Manager {}
81
82unsafe impl Sync for Manager {}
83
84impl Manager {
85 fn new(
86 _: &time::Manager,
87 screen_device: Device,
88 input_device: Device,
89 input_device_type: InputKind,
90 buffer_size: usize,
91 double_buffered: bool,
92 ) -> Result<Self> {
93 unsafe {
94 lvgl::lv_init();
95
96 if !lvgl::lv_is_initialized() {
97 panic!("Failed to initialize lvgl");
98 }
99
100 lvgl::lv_tick_set_cb(Some(binding_tick_callback_function));
101 }
102
103 let (display, input) = Self::create_display(
104 screen_device,
105 buffer_size,
106 input_device,
107 input_device_type,
108 double_buffered,
109 )?;
110
111 let screen = display.get_object();
112
113 unsafe {
114 let group = lvgl::lv_group_create();
115 lvgl::lv_group_set_default(group);
116 }
117
118 Ok(Self {
119 inner: RwLock::new(Inner {
120 _inputs: vec![input],
121 _displays: vec![display],
122
123 window_parent: screen,
124 }),
125 global_lock: Mutex::new(()),
126 })
127 }
128
129 pub async fn r#loop<F>(&self, sleep: impl Fn(Duration) -> F + Send + 'static) -> Result<()>
130 where
131 F: Future<Output = ()> + Send + 'static,
132 {
133 loop {
134 let time_until_next = unsafe {
135 let _lock = self.global_lock.lock().await;
136 lvgl::lv_timer_handler()
137 };
138
139 sleep(Duration::from_millis(time_until_next as u64)).await;
140 }
141 }
142
143 pub async fn set_window_parent(&self, window_parent: *mut lvgl::lv_obj_t) -> Result<()> {
144 self.inner.write().await.window_parent = window_parent;
145
146 Ok(())
147 }
148
149 pub async fn create_window(&self) -> Result<Window> {
150 let parent_object = self.inner.write().await.window_parent;
151
152 let window = unsafe { Window::new(parent_object)? };
153
154 Ok(window)
155 }
156
157 pub async fn add_input_device(
158 &self,
159
160 input_device: Device,
161 input_type: InputKind,
162 ) -> Result<()> {
163 let input = Input::new(input_device, input_type)?;
164
165 self.inner.write().await._inputs.push(input);
166
167 Ok(())
168 }
169
170 fn create_display(
171 screen_device: Device,
172 buffer_size: usize,
173 input_device: Device,
174 input_device_type: InputKind,
175 double_buffered: bool,
176 ) -> Result<(Display, Input)> {
177 let mut screen_read_data = ScreenReadData::default();
178
179 screen_device
180 .read(screen_read_data.as_mut())
181 .map_err(|_| Error::FailedToGetResolution)?;
182
183 let resolution: Point = screen_read_data.get_resolution();
184
185 let display = Display::new(screen_device, resolution, buffer_size, double_buffered)?;
186
187 let input = Input::new(input_device, input_device_type)?;
188
189 Ok((display, input))
190 }
191
192 pub async fn get_window_count(&self) -> Result<usize> {
193 let window_parent = self.inner.read().await.window_parent;
194 unsafe { Ok(lvgl::lv_obj_get_child_count(window_parent) as usize) }
195 }
196
197 pub async fn get_window_icon(&self, index: usize) -> Result<(String, Color)> {
198 let window_parent = self.inner.read().await.window_parent;
199
200 let window = unsafe {
201 let child = lvgl::lv_obj_get_child(window_parent, index as i32);
202
203 Window::from_raw(child)
204 };
205
206 let icon = window.get_icon();
207
208 let icon = (icon.0.to_string(), icon.1);
209
210 forget(window);
211
212 Ok(icon)
213 }
214
215 pub async fn get_window_identifier(&self, index: usize) -> Result<usize> {
216 let window_parent = self.inner.read().await.window_parent;
217
218 let window = unsafe { lvgl::lv_obj_get_child(window_parent, index as i32) as usize };
219
220 Ok(window)
221 }
222
223 pub async fn maximize_window(&self, identifier: usize) -> Result<()> {
224 let window_count = self.get_window_count().await?;
225
226 let window_parent = self.inner.read().await.window_parent;
227
228 let found = (0..window_count).find(|index| unsafe {
229 let child = lvgl::lv_obj_get_child(window_parent, *index as i32);
230
231 child == identifier as *mut lvgl::lv_obj_t
232 });
233
234 if found.is_some() {
235 unsafe {
236 lvgl::lv_obj_move_foreground(identifier as *mut lvgl::lv_obj_t);
237 }
238
239 Ok(())
240 } else {
241 Err(Error::InvalidWindowIdentifier)
242 }
243 }
244
245 pub async fn lock_function<T>(&self, function: impl FnOnce() -> Result<T>) -> Result<T> {
246 let _lock = self.global_lock.lock().await;
247
248 function()
249 }
250
251 pub async fn lock(&self) -> MutexGuard<'_, CriticalSectionRawMutex, ()> {
252 self.global_lock.lock().await
253 }
254
255 pub fn get_current_screen(&self) -> Result<*mut lvgl::lv_obj_t> {
256 Ok(unsafe { lvgl::lv_screen_active() })
257 }
258}