diff --git a/examples/sdl.rs b/examples/sdl.rs index 1c14f1a6..35233d13 100644 --- a/examples/sdl.rs +++ b/examples/sdl.rs @@ -19,25 +19,23 @@ fn main() -> LvResult<()> { const HOR_RES: u32 = 240; const VER_RES: u32 = 240; + let mut screen_style = Style::default(); + screen_style.set_bg_color(Color::from_rgb((0, 0, 0))); + let buffer = DrawBuffer::<{ (HOR_RES * VER_RES) as usize }>::default(); - let display = lv_drv_disp_sdl!(buffer, HOR_RES, VER_RES)?; + let (display, mut screen) = lv_drv_disp_sdl!(buffer, HOR_RES, VER_RES)?; let _input = lv_drv_input_pointer_sdl!(display)?; - // Create screen and widgets - let mut screen = display.get_scr_act()?; - - let mut screen_style = Style::default(); - screen_style.set_bg_color(Color::from_rgb((0, 0, 0))); screen.add_style(Part::Main, &mut screen_style); // Create the button let mut button = Btn::create(&mut screen)?; button.set_align(Align::LeftMid, 30, 0); button.set_size(180, 80); - let mut btn_lbl = Label::create(&mut button)?; + let mut btn_lbl = Label::create(&button)?; btn_lbl.set_text(CString::new("Click me!").unwrap().as_c_str())?; let mut btn_state = false; - button.on_event(|_btn, event| { + button.on_event(|btn, event| { println!("Button received event: {:?}", event); if let lvgl::Event::Clicked = event { if btn_state { @@ -49,6 +47,7 @@ fn main() -> LvResult<()> { } btn_state = !btn_state; } + btn })?; loop { diff --git a/lvgl-codegen/src/lib.rs b/lvgl-codegen/src/lib.rs index ca97a8c6..dea403fa 100644 --- a/lvgl-codegen/src/lib.rs +++ b/lvgl-codegen/src/lib.rs @@ -107,7 +107,7 @@ impl Rusty for LvFunc { if new_name.as_str().eq("create") { return Ok(quote! { - pub fn create(parent: &mut impl crate::NativeObject) -> crate::LvResult { + pub fn create(parent: &'a impl crate::NativeObject) -> crate::LvResult { unsafe { let ptr = lvgl_sys::#original_func_name( parent.raw().as_mut(), @@ -121,10 +121,10 @@ impl Rusty for LvFunc { } } - pub fn new() -> crate::LvResult { - let mut parent = crate::display::get_scr_act()?; - Self::create(&mut parent) - } + //pub fn new() -> crate::LvResult { + // let mut parent = crate::display::get_scr_act()?; + // Self::create(&mut parent) + //} }); } @@ -646,7 +646,7 @@ mod test { define_object!(Arc); impl<'a> Arc<'a> { - pub fn create(parent: &mut impl crate::NativeObject) -> crate::LvResult { + pub fn create(parent: &'a impl crate::NativeObject) -> crate::LvResult { unsafe { let ptr = lvgl_sys::lv_arc_create( parent.raw().as_mut(), @@ -660,10 +660,10 @@ mod test { } } - pub fn new() -> crate::LvResult { - let mut parent = crate::display::get_scr_act()?; - Self::create(&mut parent) - } + //pub fn new() -> crate::LvResult { + // let mut parent = crate::display::get_scr_act()?; + // Self::create(&mut parent) + //} } }; diff --git a/lvgl-sys/Cargo.toml b/lvgl-sys/Cargo.toml index b42c74be..63fbb4f6 100644 --- a/lvgl-sys/Cargo.toml +++ b/lvgl-sys/Cargo.toml @@ -35,3 +35,4 @@ bindgen = "0.65.1" use-vendored-config = [] drivers = [] rust_timer = [] +no_compile = [] diff --git a/lvgl-sys/build.rs b/lvgl-sys/build.rs index fbf0ac53..cbd63bf2 100644 --- a/lvgl-sys/build.rs +++ b/lvgl-sys/build.rs @@ -154,6 +154,7 @@ fn main() { #[cfg(feature = "drivers")] cfg.includes(incl_extra.split(',')); + //#[cfg(not(feature = "no_compile"))] cfg.compile("lvgl"); let mut cc_args = vec![ diff --git a/lvgl/Cargo.toml b/lvgl/Cargo.toml index 15069d1c..b9848357 100644 --- a/lvgl/Cargo.toml +++ b/lvgl/Cargo.toml @@ -21,7 +21,7 @@ paste = "1.0.12" ctor = "0.2.2" [features] -default = ["embedded_graphics", "drivers"] +default = ["embedded_graphics", "drivers", "lvgl-sys/no_compile"] # Enable the embedded_graphics crate as a backend for graphics and input # devices. This is the 'legacy' method (supported in LVGL 0.5.2 and below) and diff --git a/lvgl/src/display.rs b/lvgl/src/display.rs index 8284d944..3d2153ee 100644 --- a/lvgl/src/display.rs +++ b/lvgl/src/display.rs @@ -1,11 +1,12 @@ use crate::functions::CoreError; -use crate::Screen; -use crate::{disp_drv_register, disp_get_default, get_str_act, NativeObject}; +use crate::{disp_drv_register, NativeObject}; use crate::{Box, Color}; +use crate::{Screen, Widget}; use core::convert::TryInto; #[cfg(feature = "nightly")] use core::error::Error; use core::fmt; +use core::marker::PhantomData; use core::mem::{ManuallyDrop, MaybeUninit}; use core::pin::Pin; use core::ptr::NonNull; @@ -39,17 +40,22 @@ impl Error for DisplayError {} type Result = result::Result; /// An LVGL-registered display. Equivalent to an `lv_disp_t`. -pub struct Display { - pub(crate) disp: NonNull, +pub struct Display<'a> { + disp: NonNull, drop: Option, + _screens: PhantomData<&'a Screen<'a>>, } -impl<'a> Display { +impl<'a> Display<'a> { pub(crate) fn from_raw( disp: NonNull, drop: Option, ) -> Self { - Self { disp, drop } + Self { + disp, + drop, + _screens: PhantomData, + } } /// Registers a given `DrawBuffer` with an associated update function to @@ -59,21 +65,42 @@ impl<'a> Display { hor_res: u32, ver_res: u32, display_update: F, - ) -> Result + ) -> Result<(Self, Screen<'a>)> where F: FnMut(&DisplayRefresh) + 'a, { - let mut display_diver = DisplayDriver::new(draw_buffer, display_update)?; - let disp_p = &mut display_diver.disp_drv; + let mut display_driver = DisplayDriver::new(draw_buffer, display_update)?; + let disp_p = &mut display_driver.disp_drv; disp_p.hor_res = hor_res.try_into().unwrap_or(240); disp_p.ver_res = ver_res.try_into().unwrap_or(240); - Ok(disp_drv_register(&mut display_diver, None)?) + let disp = disp_drv_register::( + unsafe { &mut *(&mut display_driver as *mut _ as *mut _) }, + None, + )?; + let scr = unsafe { + Screen::from_raw( + NonNull::new(lvgl_sys::lv_disp_get_scr_act(disp.disp.as_ptr())) + .ok_or(DisplayError::FailedToRegister)?, + ) + .ok_or(DisplayError::FailedToRegister)? + }; + Ok((disp, scr)) //display_diver.disp_drv.leak(); } /// Returns the current active screen. - pub fn get_scr_act(&'a self) -> Result> { - Ok(get_str_act(Some(self))?.try_into()?) + /// + /// # Safety + /// + /// This function should only be called if the resulting `Screen` was not + /// previously instantiated (i.e. the display was registered with + /// `register_raw()`) or the resulting screen is never in conflict with the + /// other screen which holds the same underlying value. + pub unsafe fn get_scr_act(&'a self) -> Option> { + unsafe { + let ret = lvgl_sys::lv_disp_get_scr_act(&self as *const _ as *mut _); + Screen::from_raw(NonNull::new(ret)?) + } } /// Sets a `Screen` as currently active. @@ -82,6 +109,65 @@ impl<'a> Display { unsafe { lvgl_sys::lv_disp_load_scr(scr_ptr) } } + pub fn is_scr_act(&'a self, screen: &Screen) -> bool { + unsafe { + let act = self.get_scr_act().map(|s| { + s.raw().as_ptr() as usize + }).unwrap_or(0); + let given = screen.raw().as_ptr() as usize; + act == given + } + } + + /// Same as `register_raw`, but also returns the original screen. Intended + /// for use within display-initializing macros. + /// + /// # Safety + /// + /// See `register_raw()`. + pub unsafe fn register_raw_macro(draw_buffer: DrawBuffer, + hor_res: u32, + ver_res: u32, + flush_cb: Option< + unsafe extern "C" fn( + *mut lvgl_sys::lv_disp_drv_t, + *const lvgl_sys::lv_area_t, + *mut lvgl_sys::lv_color_t, + ), + >, + rounder_cb: Option< + unsafe extern "C" fn(*mut lvgl_sys::lv_disp_drv_t, *mut lvgl_sys::lv_area_t), + >, + set_px_cb: Option< + unsafe extern "C" fn( + *mut lvgl_sys::lv_disp_drv_t, + *mut u8, + lvgl_sys::lv_coord_t, + lvgl_sys::lv_coord_t, + lvgl_sys::lv_coord_t, + lvgl_sys::lv_color_t, + lvgl_sys::lv_opa_t, + ), + >, + clear_cb: Option, + monitor_cb: Option, + wait_cb: Option, + clean_dcache_cb: Option, + drv_update_cb: Option, + render_start_cb: Option, + drop: Option, + ) -> Result<(Self, Screen<'a>)> { + let disp = unsafe { + Display::register_raw(draw_buffer, hor_res, ver_res, flush_cb, rounder_cb, set_px_cb, clear_cb, monitor_cb, wait_cb, clean_dcache_cb, drv_update_cb, render_start_cb, drop)? + }; + let scr = Screen::from_raw( + NonNull::new(lvgl_sys::lv_disp_get_scr_act(disp.disp.as_ptr())) + .ok_or(DisplayError::FailedToRegister)?, + ) + .ok_or(DisplayError::FailedToRegister)?; + Ok((disp, scr)) + } + /// Registers a display from raw functions and values. /// /// # Safety @@ -137,17 +223,20 @@ impl<'a> Display { let disp_p = &mut display_driver.disp_drv; disp_p.hor_res = hor_res.try_into().unwrap_or(240); disp_p.ver_res = ver_res.try_into().unwrap_or(240); - Ok(disp_drv_register(&mut display_driver, drop)?) + Ok(disp_drv_register::( + unsafe { &mut *(&mut display_driver as *mut _ as *mut _) }, + drop, + )?) } } -impl Default for Display { - fn default() -> Self { - disp_get_default().expect("LVGL must be INITIALIZED") - } -} +//impl Default for Display<'_> { +// fn default() -> Self { +// disp_get_default().expect("LVGL must be INITIALIZED") +// } +//} -impl Drop for Display { +impl Drop for Display<'_> { fn drop(&mut self) { if let Some(drop) = self.drop { unsafe { drop() } @@ -155,11 +244,6 @@ impl Drop for Display { } } -/// Gets the active screen of the default display. -pub(crate) fn get_scr_act() -> Result> { - Ok(get_str_act(None)?.try_into()?) -} - /// A buffer of size `N` representing `N` pixels. `N` can be smaller than the /// entire number of pixels on the screen, in which case the screen will be /// drawn to multiple times per frame. @@ -388,28 +472,13 @@ mod tests { use crate::tests; #[test] - fn get_scr_act_return_display() { - tests::initialize_test(true); - let _screen = get_str_act(None).expect("We can get the active screen"); - } - - #[test] - fn get_default_display() { - tests::initialize_test(true); - let display = Display::default(); - let _screen_direct = display - .get_scr_act() - .expect("Return screen directly from the display instance"); - let _screen_default = get_scr_act().expect("Return screen from the default display"); - } - - #[test] - fn register_display_directly() -> Result<()> { - crate::tests::initialize_test(true); - let display = Display::default(); - let _screen = display - .get_scr_act() - .expect("Return screen directly from the display instance"); - Ok(()) + fn register_display_and_screen() { + tests::initialize_test(); + const REFRESH_BUFFER_SIZE: usize = 240 * 240 / 10; + let buffer = DrawBuffer::::default(); + let (_display, _screen) = Display::register(buffer, 240, 240, |_| {}).unwrap(); + //let _screen_direct = display + // .get_scr_act() + // .expect("Return screen directly from the display instance"); } } diff --git a/lvgl/src/drivers/lv_drv_display.rs b/lvgl/src/drivers/lv_drv_display.rs index b8803c6d..cc1e1e08 100644 --- a/lvgl/src/drivers/lv_drv_display.rs +++ b/lvgl/src/drivers/lv_drv_display.rs @@ -3,7 +3,7 @@ macro_rules! lv_drv_disp_fbdev { ($draw_buffer:ident, $hor_res:ident, $ver_res:ident) => { unsafe { lvgl_sys::fbdev_init(); - $crate::Display::register_raw( + $crate::Display::register_raw_macro( $draw_buffer, $hor_res, $ver_res, @@ -27,7 +27,7 @@ macro_rules! lv_drv_disp_drm { ($draw_buffer:ident, $hor_res:ident, $ver_res:ident) => { unsafe { lvgl_sys::drm_init(); - $crate::Display::register_raw( + $crate::Display::register_raw_macro( $draw_buffer, $hor_res, $ver_res, @@ -51,7 +51,7 @@ macro_rules! lv_drv_disp_gtk { ($draw_buffer:ident, $hor_res:ident, $ver_res:ident) => { unsafe { lvgl_sys::gtkdrv_init(); - $crate::Display::register_raw( + $crate::Display::register_raw_macro( $draw_buffer, $hor_res, $ver_res, @@ -75,7 +75,7 @@ macro_rules! lv_drv_disp_sdl { ($draw_buffer:ident, $hor_res:ident, $ver_res:ident) => { unsafe { lvgl_sys::sdl_init(); - $crate::Display::register_raw( + $crate::Display::register_raw_macro( $draw_buffer, $hor_res, $ver_res, @@ -102,7 +102,7 @@ macro_rules! lv_drv_disp_gc9a01 { 0 => (), c = panic!("GC9A01_init() returned error code {c}") }; - $crate::Display::register_raw( + $crate::Display::register_raw_macro( $draw_buffer, $hor_res, $ver_res, @@ -126,7 +126,7 @@ macro_rules! lv_drv_disp_ili9341 { ($draw_buffer:ident, $hor_res:ident, $ver_res:ident) => { unsafe { lvgl_sys::ili9341_init(); - $crate::Display::register_raw( + $crate::Display::register_raw_macro( $draw_buffer, $hor_res, $ver_res, @@ -150,7 +150,7 @@ macro_rules! lv_drv_disp_r61581 { ($draw_buffer:ident, $hor_res:ident, $ver_res:ident) => { unsafe { lvgl_sys::r61581_init(); - $crate::Display::register_raw( + $crate::Display::register_raw_macro( $draw_buffer, $hor_res, $ver_res, @@ -174,7 +174,7 @@ macro_rules! lv_drv_disp_sharp_mip { ($draw_buffer:ident, $hor_res:ident, $ver_res:ident) => { unsafe { lvgl_sys::sharp_mip_init(); - $crate::Display::register_raw( + $crate::Display::register_raw_macro( $draw_buffer, $hor_res, $ver_res, @@ -198,7 +198,7 @@ macro_rules! lv_drv_disp_ssd1963 { ($draw_buffer:ident, $hor_res:ident, $ver_res:ident) => { unsafe { lvgl_sys::ssd1963_init(); - $crate::Display::register_raw( + $crate::Display::register_raw_macro( $draw_buffer, $hor_res, $ver_res, @@ -222,7 +222,7 @@ macro_rules! lv_drv_disp_st7565 { ($draw_buffer:ident, $hor_res:ident, $ver_res:ident) => { unsafe { lvgl_sys::st7565_init(); - $crate::Display::register_raw( + $crate::Display::register_raw_macro( $draw_buffer, $hor_res, $ver_res, @@ -246,7 +246,7 @@ macro_rules! lv_drv_disp_uc1610 { ($draw_buffer:ident, $hor_res:ident, $ver_res:ident) => { unsafe { lvgl_sys::uc1610_init(); - $crate::Display::register_raw( + $crate::Display::register_raw_macro( $draw_buffer, $hor_res, $ver_res, @@ -274,7 +274,7 @@ mod tests { fn gtk_test() { const HOR_RES: u32 = 240; const VER_RES: u32 = 240; - tests::initialize_test(false); + tests::initialize_test(); let buffer = DrawBuffer::<{ (HOR_RES * VER_RES) as usize }>::default(); let _disp = lv_drv_disp_sdl!(buffer, HOR_RES, VER_RES).unwrap(); } diff --git a/lvgl/src/drivers/lv_drv_input.rs b/lvgl/src/drivers/lv_drv_input.rs index f3fd41c4..eaa606e0 100644 --- a/lvgl/src/drivers/lv_drv_input.rs +++ b/lvgl/src/drivers/lv_drv_input.rs @@ -88,8 +88,10 @@ mod tests { #[test] fn gtk_test() { - tests::initialize_test(true); - let disp = Display::default(); + tests::initialize_test(); + const REFRESH_BUFFER_SIZE: usize = 240 * 240 / 10; + let buffer = DrawBuffer::::default(); + let (disp, _) = Display::register(buffer, 240, 240, |_| {}).unwrap(); let _input = lv_drv_input_pointer_sdl!(disp); } } diff --git a/lvgl/src/functions.rs b/lvgl/src/functions.rs index ca19e2c2..0b8e68a6 100644 --- a/lvgl/src/functions.rs +++ b/lvgl/src/functions.rs @@ -1,6 +1,6 @@ use crate::display::{Display, DisplayDriver}; use crate::input_device::InputDriver; -use crate::{Event, LvError, LvResult, Obj, Widget}; +use crate::{Event, LvError, LvResult, Widget}; use core::ptr::NonNull; #[cfg(not(feature = "rust_timer"))] use core::time::Duration; @@ -30,26 +30,13 @@ pub(crate) fn disp_drv_register( )) } -pub(crate) fn disp_get_default() -> Result { - let disp_ptr = unsafe { lvgl_sys::lv_disp_get_default() }; - Ok(Display::from_raw( - NonNull::new(disp_ptr).ok_or(CoreError::OperationFailed)?, - None, - )) -} - -pub(crate) fn get_str_act(disp: Option<&Display>) -> Result { - let scr_ptr = unsafe { - lvgl_sys::lv_disp_get_scr_act( - disp.map(|d| d.disp.as_ptr()) - .unwrap_or(ptr::null_mut() as *mut lvgl_sys::lv_disp_t), - ) - }; - match unsafe { Obj::from_raw(NonNull::new(scr_ptr).ok_or(CoreError::ResourceNotAvailable)?) } { - Some(o) => Ok(o), - None => Err(CoreError::OperationFailed), - } -} +//pub(crate) fn disp_get_default() -> Result { +// let disp_ptr = unsafe { lvgl_sys::lv_disp_get_default() }; +// Ok(Display::from_raw( +// NonNull::new(disp_ptr).ok_or(CoreError::OperationFailed)?, +// None, +// )) +//} /// Runs an LVGL tick lasting a given `core::time::Duration`. This function /// should be called periodically. diff --git a/lvgl/src/input_device/encoder.rs b/lvgl/src/input_device/encoder.rs index 97700f14..87e3c70f 100644 --- a/lvgl/src/input_device/encoder.rs +++ b/lvgl/src/input_device/encoder.rs @@ -173,7 +173,7 @@ unsafe extern "C" fn feedback(_indev_drv: *mut lvgl_sys::lv_indev_drv_t, _code: #[cfg(test)] mod test { use super::*; - use crate::Display; + use crate::{Display, DrawBuffer}; use core::marker::PhantomData; use embedded_graphics::draw_target::DrawTarget; use embedded_graphics::geometry::Size; @@ -214,8 +214,10 @@ mod test { #[test] fn encoder_input_device() { - crate::tests::initialize_test(true); - let display = Display::default(); + crate::tests::initialize_test(); + const REFRESH_BUFFER_SIZE: usize = 240 * 240 / 10; + let buffer = DrawBuffer::::default(); + let (display, _) = Display::register(buffer, 240, 240, |_| {}).unwrap(); fn read_encoder_device() -> BufferStatus { EncoderInputData::Press.pressed().once() diff --git a/lvgl/src/input_device/pointer.rs b/lvgl/src/input_device/pointer.rs index 97905ea3..e68154f4 100644 --- a/lvgl/src/input_device/pointer.rs +++ b/lvgl/src/input_device/pointer.rs @@ -178,7 +178,7 @@ unsafe extern "C" fn feedback(_indev_drv: *mut lvgl_sys::lv_indev_drv_t, _code: #[cfg(test)] mod test { use super::*; - use crate::Display; + use crate::{Display, DrawBuffer}; use core::marker::PhantomData; use embedded_graphics::draw_target::DrawTarget; use embedded_graphics::geometry::Size; @@ -219,8 +219,10 @@ mod test { #[test] fn pointer_input_device() { - crate::tests::initialize_test(true); - let display = Display::default(); + crate::tests::initialize_test(); + const REFRESH_BUFFER_SIZE: usize = 240 * 240 / 10; + let buffer = DrawBuffer::::default(); + let (display, _) = Display::register(buffer, 240, 240, |_| {}).unwrap(); fn read_touchpad_device() -> BufferStatus { PointerInputData::Touch(Point::new(120, 23)) diff --git a/lvgl/src/lib.rs b/lvgl/src/lib.rs index 8a0638fe..3b8cf15c 100644 --- a/lvgl/src/lib.rs +++ b/lvgl/src/lib.rs @@ -114,15 +114,8 @@ fn once_init() { #[cfg(test)] pub(crate) mod tests { - use crate::display::{Display, DrawBuffer}; - - pub(crate) fn initialize_test(buf: bool) { + pub(crate) fn initialize_test() { unsafe { crate::deinit() }; crate::init(); - if buf { - const REFRESH_BUFFER_SIZE: usize = 240 * 240 / 10; - let buffer = DrawBuffer::::default(); - let _ = Display::register(buffer, 240, 240, |_| {}).unwrap(); - } } } diff --git a/lvgl/src/lv_core/group.rs b/lvgl/src/lv_core/group.rs index 53053def..aa672830 100644 --- a/lvgl/src/lv_core/group.rs +++ b/lvgl/src/lv_core/group.rs @@ -26,7 +26,7 @@ impl Group { } /// Adds an object to the group. - pub fn add_obj(&mut self, obj: &impl NativeObject) -> LvResult<()> { + pub fn add_obj(&mut self, obj: &mut impl NativeObject) -> LvResult<()> { unsafe { lvgl_sys::lv_group_add_obj(self.raw()?.as_mut(), obj.raw().as_mut()) } Ok(()) } @@ -64,12 +64,11 @@ mod test { fn group_test() { const HOR_RES: u32 = 240; const VER_RES: u32 = 240; - crate::tests::initialize_test(false); + crate::tests::initialize_test(); let buffer = DrawBuffer::<{ (HOR_RES * VER_RES) as usize }>::default(); - let display = Display::register(buffer, HOR_RES, VER_RES, |_| {}).unwrap(); - let mut screen = display.get_scr_act().unwrap(); + let (_display, mut screen) = Display::register(buffer, HOR_RES, VER_RES, |_| {}).unwrap(); let mut group = Group::default(); - let btn = Btn::create(&mut screen).unwrap(); - group.add_obj(&btn).unwrap(); + let mut btn = Btn::create(&mut screen).unwrap(); + group.add_obj(&mut btn).unwrap(); } } diff --git a/lvgl/src/lv_core/obj.rs b/lvgl/src/lv_core/obj.rs index 433ca537..5f013ec5 100644 --- a/lvgl/src/lv_core/obj.rs +++ b/lvgl/src/lv_core/obj.rs @@ -7,8 +7,10 @@ use crate::lv_core::style::Style; use crate::{Align, LvError, LvResult}; +use core::cell::UnsafeCell; use core::fmt::{self, Debug}; use core::marker::PhantomData; +use core::mem::transmute; use core::ptr::{self, NonNull}; /// Represents a native LVGL object. @@ -22,11 +24,17 @@ pub trait NativeObject { /// This is the parent object of all widget types. It stores the native LVGL /// raw pointer. pub struct Obj<'a> { - // We use a raw pointer here because we do not control this memory address, - // it is controlled by LVGL's global state. - raw: NonNull, - // This is to ensure safety for children memory; it has no runtime impact - dependents: PhantomData<&'a isize>, + // We do not control this memory address, it is controlled by LVGL's + // global state. + raw: NonNull>, + // This is to ensure parent doesn't get dropped; it has no runtime impact + parent: PhantomData<&'a Obj<'a>>, +} + +impl Drop for Obj<'_> { + fn drop(&mut self) { + unsafe { lvgl_sys::lv_obj_del_async(self.raw().as_mut()) } + } } impl Debug for Obj<'_> { @@ -40,14 +48,15 @@ impl Debug for Obj<'_> { // We need to manually impl methods on Obj since widget codegen is defined in // terms of Obj impl<'a> Obj<'a> { - pub fn create(parent: &'a mut impl NativeObject) -> LvResult { + pub fn create(parent: &'a impl NativeObject) -> LvResult { unsafe { let ptr = lvgl_sys::lv_obj_create(parent.raw().as_mut()); - if let Some(nn_ptr) = ptr::NonNull::new(ptr) { + if let Some(nn_ptr) = NonNull::new(ptr) { //(*ptr).user_data = Box::new(UserDataObj::empty()).into_raw() as *mut _; Ok(Self { - raw: nn_ptr, - dependents: PhantomData::<&'a _>, + // Gross, but fast. UnsafeCell has the same layout as T + raw: transmute(nn_ptr), + parent: PhantomData::<&'a _>, }) } else { Err(LvError::InvalidReference) @@ -55,16 +64,16 @@ impl<'a> Obj<'a> { } } - pub fn new() -> crate::LvResult { - let mut parent = crate::display::get_scr_act()?; - Self::create(unsafe { &mut *(&mut parent as *mut _) }) - } + //pub fn new() -> crate::LvResult { + // let mut parent = crate::display::get_scr_act()?; + // Self::create(unsafe { &mut *(&mut parent as *mut _) }) + //} pub fn blank() -> LvResult { match NonNull::new(unsafe { lvgl_sys::lv_obj_create(ptr::null_mut()) }) { Some(raw) => Ok(Self { - raw, - dependents: PhantomData, + raw: unsafe { transmute(raw) }, + parent: PhantomData::<&'a _>, }), None => Err(LvError::LvOOMemory), } @@ -72,8 +81,8 @@ impl<'a> Obj<'a> { } impl NativeObject for Obj<'_> { - fn raw(&self) -> ptr::NonNull { - self.raw + fn raw(&self) -> NonNull { + unsafe { NonNull::new_unchecked((*(self.raw.as_ptr())).get()) } } } @@ -89,10 +98,10 @@ pub trait Widget<'a>: NativeObject + Sized + 'a { /// If the pointer is derived from a Rust-instantiated `obj` such as via /// calling `.raw()`, only the `obj` that survives longest may be dropped /// and the caller is responsible for ensuring data races do not occur. - unsafe fn from_raw(raw_pointer: ptr::NonNull) -> Option; + unsafe fn from_raw(raw_pointer: NonNull) -> Option; /// Adds a `Style` to a given widget. - fn add_style(&mut self, part: Self::Part, style: &'a mut Style) { + fn add_style(&self, part: Self::Part, style: &'a mut Style) { unsafe { lvgl_sys::lv_obj_add_style( self.raw().as_mut(), @@ -157,8 +166,8 @@ impl<'a> Widget<'a> for Obj<'a> { unsafe fn from_raw(raw: NonNull) -> Option { Some(Self { - raw, - dependents: PhantomData, + raw: transmute(raw), + parent: PhantomData::<&'a _>, }) } } @@ -183,9 +192,9 @@ macro_rules! define_object { } impl<'a> $item<'a> { - pub fn on_event(&mut self, f: F) -> $crate::LvResult<()> + pub fn on_event(&self, f: F) -> $crate::LvResult<()> where - F: FnMut(Self, $crate::support::Event<>::SpecialEvent>), + F: FnMut(Self, $crate::support::Event<>::SpecialEvent>) -> Self, { use $crate::NativeObject; unsafe { diff --git a/lvgl/src/lv_core/screen.rs b/lvgl/src/lv_core/screen.rs index ef87065b..4fdd6ff0 100644 --- a/lvgl/src/lv_core/screen.rs +++ b/lvgl/src/lv_core/screen.rs @@ -69,10 +69,9 @@ mod test { fn screen_test() { const HOR_RES: u32 = 240; const VER_RES: u32 = 240; - crate::tests::initialize_test(false); + crate::tests::initialize_test(); let buffer = DrawBuffer::<{ (HOR_RES * VER_RES) as usize }>::default(); - let display = Display::register(buffer, HOR_RES, VER_RES, |_| {}).unwrap(); - let mut screen_old = display.get_scr_act().unwrap(); + let (display, mut screen_old) = Display::register(buffer, HOR_RES, VER_RES, |_| {}).unwrap(); let mut screen_new = Screen::blank().unwrap(); display.set_scr_act(&mut screen_new); display.set_scr_act(&mut screen_old); diff --git a/lvgl/src/mem.rs b/lvgl/src/mem.rs index 176185b6..e724d4a1 100644 --- a/lvgl/src/mem.rs +++ b/lvgl/src/mem.rs @@ -127,7 +127,7 @@ mod test { #[test] fn place_value_in_lv_mem() { - tests::initialize_test(false); + tests::initialize_test(); let v = Box::new(5); drop(v); @@ -137,7 +137,7 @@ mod test { #[test] fn place_complex_value_in_lv_mem() { - tests::initialize_test(false); + tests::initialize_test(); #[repr(C)] #[derive(Debug)] @@ -189,7 +189,7 @@ mod test { #[test] fn clone_object_in_lv_mem() { - crate::tests::initialize_test(false); + crate::tests::initialize_test(); let v1 = Box::new(5); let v2 = v1.clone(); diff --git a/lvgl/src/misc/anim.rs b/lvgl/src/misc/anim.rs index 206e9a93..33807e76 100644 --- a/lvgl/src/misc/anim.rs +++ b/lvgl/src/misc/anim.rs @@ -127,13 +127,15 @@ where mod test { use super::*; use crate::widgets::Btn; - use crate::Display; + use crate::{Display, DrawBuffer}; #[test] fn anim_test() { - crate::tests::initialize_test(true); - let display = Display::default(); - let mut screen = display.get_scr_act().unwrap(); + crate::tests::initialize_test(); + const REFRESH_BUFFER_SIZE: usize = 240 * 240 / 10; + let buffer = DrawBuffer::::default(); + let (_display, mut screen) = Display::register(buffer, 240, 240, |_| {}).unwrap(); + //let mut screen = display.get_scr_act().unwrap(); let mut btn = Btn::create(&mut screen).unwrap(); let mut anim = Animation::new(&mut btn, Duration::from_millis(10), 0, 100, |_, _| {}).unwrap(); diff --git a/lvgl/src/support.rs b/lvgl/src/support.rs index a85cba6a..2dc3a8d4 100644 --- a/lvgl/src/support.rs +++ b/lvgl/src/support.rs @@ -5,6 +5,7 @@ use core::convert::{TryFrom, TryInto}; use core::error::Error; use core::fmt; use core::ptr::NonNull; +use core::mem::ManuallyDrop; #[cfg(feature = "embedded_graphics")] use embedded_graphics::pixelcolor::{Rgb565, Rgb888}; @@ -280,7 +281,7 @@ pub enum PointerEvent { pub(crate) unsafe extern "C" fn event_callback<'a, T, F>(event: *mut lvgl_sys::lv_event_t) where T: Widget<'a> + Sized, - F: FnMut(T, Event<>::SpecialEvent>), + F: FnMut(T, Event<>::SpecialEvent>) -> T, { let code = (*event).code; let obj = (*event).target; @@ -290,8 +291,8 @@ where let object = T::from_raw(obj_ptr).unwrap(); // get the pointer from the Rust callback closure FnMut provided by users let user_closure = &mut *((*obj).user_data as *mut F); - // call user callback closure - user_closure(object, code); + // call user callback closure and do *not* drop the widget + let _never_drop = ManuallyDrop::new(user_closure(object, code)); } } } diff --git a/lvgl/src/widgets/label.rs b/lvgl/src/widgets/label.rs index 691ffb8d..5689ad62 100644 --- a/lvgl/src/widgets/label.rs +++ b/lvgl/src/widgets/label.rs @@ -1,37 +1,7 @@ use crate::widgets::Label; use crate::{LabelLongMode, NativeObject}; -#[cfg(feature = "alloc")] -mod alloc_imp { - use crate::widgets::Label; - //use crate::LvError; - use cstr_core::CString; - //use core::convert::TryFrom; - - impl> From for Label<'_> { - fn from(text: S) -> Self { - // text.try_into().unwrap() - let text_cstr = CString::new(text.as_ref()).unwrap(); - let mut label = Label::new().unwrap(); - label.set_text(text_cstr.as_c_str()).unwrap(); - label - } - } - - // Issue link: https://github.com/rust-lang/rust/issues/50133 - // - // impl> TryFrom for Label { - // type Error = LvError; - // fn try_from(text: S) -> Result { - // let text_cstr = CString::new(text.as_ref())?; - // let mut label = Label::new()?; - // label.set_text(text_cstr.as_c_str())?; - // Ok(label) - // } - // } -} - -impl Label<'_> { +impl<'a> Label<'a> { pub fn set_long_mode(&mut self, long_mode: LabelLongMode) { unsafe { lvgl_sys::lv_label_set_long_mode(self.raw().as_mut(), long_mode.into()); @@ -41,4 +11,14 @@ impl Label<'_> { pub fn get_long_mode(&self) -> u8 { unsafe { lvgl_sys::lv_label_get_long_mode(self.raw().as_ref()) } } + + #[cfg(feature = "alloc")] + pub fn from_str>(text: S, parent: &'a mut impl NativeObject) -> Self { + use cstr_core::CString; + // text.try_into().unwrap() + let text_cstr = CString::new(text.as_ref()).unwrap(); + let mut label = Label::create(parent).unwrap(); + label.set_text(text_cstr.as_c_str()).unwrap(); + label + } }