graphics/
manager.rs

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}