mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-21 05:51:45 +08:00
feat(core): add external data and destructor feature (#9112)
Signed-off-by: chenwen@espressif.com <chenwen@espressif.com>
This commit is contained in:
@@ -832,6 +832,23 @@ menu "LVGL configuration"
|
||||
bool "Enable the multi-touch gesture recognition feature"
|
||||
depends on LV_USE_FLOAT
|
||||
default n
|
||||
|
||||
config LV_USE_EXT_DATA
|
||||
bool "External data and destructor"
|
||||
default n
|
||||
help
|
||||
Enable this option to activate external data and destructor functionality,
|
||||
which assists in resource cleanup when objects are freed by either LVGL core
|
||||
or applications. Currently supported features include:
|
||||
- event
|
||||
- object
|
||||
- observer
|
||||
- anim
|
||||
- timer
|
||||
- group
|
||||
- display
|
||||
- indev (input device)
|
||||
- theme
|
||||
endmenu
|
||||
endmenu
|
||||
|
||||
|
||||
@@ -1400,6 +1400,9 @@
|
||||
#define LV_QNX_BUF_COUNT 1 /**< 1 or 2 */
|
||||
#endif
|
||||
|
||||
/** Enable or disable for external data and destructor function */
|
||||
#define LV_USE_EXT_DATA 0
|
||||
|
||||
/*=====================
|
||||
* BUILD OPTIONS
|
||||
*======================*/
|
||||
|
||||
@@ -67,6 +67,10 @@ lv_group_t * lv_group_create(void)
|
||||
group->refocus_policy = LV_GROUP_REFOCUS_POLICY_PREV;
|
||||
group->wrap = 1;
|
||||
group->user_data = NULL;
|
||||
#if LV_USE_EXT_DATA
|
||||
group->ext_data.free_cb = NULL;
|
||||
group->ext_data.data = NULL;
|
||||
#endif
|
||||
|
||||
return group;
|
||||
}
|
||||
@@ -100,6 +104,12 @@ void lv_group_delete(lv_group_t * group)
|
||||
|
||||
lv_ll_clear(&(group->obj_ll));
|
||||
lv_ll_remove(group_ll_p, group);
|
||||
#if LV_USE_EXT_DATA
|
||||
if(group->ext_data.free_cb) {
|
||||
group->ext_data.free_cb(group->ext_data.data);
|
||||
group->ext_data.data = NULL;
|
||||
}
|
||||
#endif
|
||||
lv_free(group);
|
||||
}
|
||||
|
||||
@@ -410,6 +420,20 @@ lv_group_t * lv_group_by_index(uint32_t index)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
void lv_group_set_external_data(lv_group_t * group, void * data, void (* free_cb)(void * data))
|
||||
{
|
||||
if(!group) {
|
||||
LV_LOG_WARN("Can't attach external user data and destructor callback to a NULL group");
|
||||
return;
|
||||
}
|
||||
|
||||
group->ext_data.data = data;
|
||||
group->ext_data.free_cb = free_cb;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
@@ -237,6 +237,22 @@ uint32_t lv_group_get_count(void);
|
||||
*/
|
||||
lv_group_t * lv_group_by_index(uint32_t index);
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
/**
|
||||
* @brief Attaches external user data and destructor callback to a group
|
||||
*
|
||||
* Associates custom user data with an LVGL group and specifies a destructor function
|
||||
* that will be automatically invoked when the group is deleted to properly clean up
|
||||
* the associated resources.
|
||||
*
|
||||
* @param group Pointer to a group
|
||||
* @param data User-defined data pointer to associate with a group
|
||||
* @param free_cb Callback function for cleaning up ext_data when group is deleted.
|
||||
* Receives ext_data as parameter. NULL means no cleanup required.
|
||||
*/
|
||||
void lv_group_set_external_data(lv_group_t * group, void * data, void (* free_cb)(void * data));
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
@@ -16,6 +16,10 @@ extern "C" {
|
||||
|
||||
#include "lv_group.h"
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
#include "../lvgl_private.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
@@ -29,6 +33,9 @@ extern "C" {
|
||||
* They are NOT for laying out objects on a screen (try layouts for that).
|
||||
*/
|
||||
struct _lv_group_t {
|
||||
#if LV_USE_EXT_DATA
|
||||
lv_ext_data_t ext_data;
|
||||
#endif
|
||||
lv_ll_t obj_ll; /**< Linked list to store the objects in the group*/
|
||||
lv_obj_t ** obj_focus; /**< The object in focus*/
|
||||
|
||||
|
||||
@@ -135,6 +135,13 @@ void lv_obj_class_init_obj(lv_obj_t * obj)
|
||||
|
||||
void lv_obj_destruct(lv_obj_t * obj)
|
||||
{
|
||||
#if LV_USE_EXT_DATA
|
||||
if(obj->ext_data.free_cb) {
|
||||
obj->ext_data.free_cb(obj->ext_data.data);
|
||||
obj->ext_data.data = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(obj->class_p->destructor_cb) obj->class_p->destructor_cb(obj->class_p, obj);
|
||||
|
||||
if(obj->class_p->base_class) {
|
||||
@@ -170,6 +177,19 @@ bool lv_obj_is_group_def(lv_obj_t * obj)
|
||||
return class_p->group_def == LV_OBJ_CLASS_GROUP_DEF_TRUE;
|
||||
}
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
void lv_obj_set_external_data(lv_obj_t * obj, void * data, void (* free_cb)(void * data))
|
||||
{
|
||||
if(!obj) {
|
||||
LV_LOG_WARN("Can't attach external user data and destructor callback to a NULL object");
|
||||
return;
|
||||
}
|
||||
|
||||
obj->ext_data.data = data;
|
||||
obj->ext_data.free_cb = free_cb;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@@ -177,6 +197,12 @@ bool lv_obj_is_group_def(lv_obj_t * obj)
|
||||
static void lv_obj_construct(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(class_p->name);
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
obj->ext_data.free_cb = NULL;
|
||||
obj->ext_data.data = NULL;
|
||||
#endif
|
||||
|
||||
if(obj->class_p->base_class) {
|
||||
const lv_obj_class_t * original_class_p = obj->class_p;
|
||||
|
||||
|
||||
@@ -61,6 +61,23 @@ bool lv_obj_is_editable(lv_obj_t * obj);
|
||||
|
||||
bool lv_obj_is_group_def(lv_obj_t * obj);
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
/**
|
||||
* @brief Associates an array of external data pointers with an LVGL object
|
||||
*
|
||||
* Associates custom user data with an LVGL object and specifies a destructor function
|
||||
* that will be automatically invoked when the object is deleted to properly clean up
|
||||
* the associated resources.
|
||||
*
|
||||
* @param obj Target LVGL object
|
||||
* @param data User-defined data pointer to associate with a object
|
||||
* @param free_cb Cleanup function called for each non-NULL data pointer during
|
||||
* object deletion. Receives single data pointer as parameter.
|
||||
* NULL means no automatic cleanup.
|
||||
*/
|
||||
void lv_obj_set_external_data(lv_obj_t * obj, void * data, void (* free_cb)(void * data));
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
@@ -16,6 +16,10 @@ extern "C" {
|
||||
|
||||
#include "lv_obj.h"
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
#include "../lvgl_private.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
@@ -53,6 +57,9 @@ struct _lv_obj_spec_attr_t {
|
||||
};
|
||||
|
||||
struct _lv_obj_t {
|
||||
#if LV_USE_EXT_DATA
|
||||
lv_ext_data_t ext_data;
|
||||
#endif
|
||||
const lv_obj_class_t * class_p;
|
||||
lv_obj_t * parent;
|
||||
lv_obj_spec_attr_t * spec_attr;
|
||||
|
||||
@@ -91,6 +91,19 @@ static void subject_set_string_free_user_data_event_cb(lv_event_t * e);
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
void lv_subject_set_external_data(lv_subject_t * subject, void * data, void (* free_cb)(void * data))
|
||||
{
|
||||
if(!subject) {
|
||||
LV_LOG_WARN("Can't attach external user data and destructor callback to a NULL subject");
|
||||
return;
|
||||
}
|
||||
|
||||
subject->ext_data.data = data;
|
||||
subject->ext_data.free_cb = free_cb;
|
||||
}
|
||||
#endif
|
||||
|
||||
void lv_subject_init_int(lv_subject_t * subject, int32_t value)
|
||||
{
|
||||
lv_memzero(subject, sizeof(lv_subject_t));
|
||||
@@ -498,6 +511,13 @@ void lv_observer_remove(lv_observer_t * observer)
|
||||
|
||||
observer->subject->notify_restart_query = 1;
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
if(observer->subject->ext_data.free_cb) {
|
||||
observer->subject->ext_data.free_cb(observer->subject->ext_data.data);
|
||||
observer->subject->ext_data.data = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
lv_ll_remove(&(observer->subject->subs_ll), observer);
|
||||
|
||||
if(observer->auto_free_user_data) {
|
||||
|
||||
@@ -16,6 +16,10 @@ extern "C" {
|
||||
|
||||
#include "lv_obj.h"
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
#include "../lvgl_private.h"
|
||||
#endif
|
||||
|
||||
#if LV_USE_OBSERVER
|
||||
|
||||
/*********************
|
||||
@@ -56,6 +60,9 @@ typedef union {
|
||||
* The Subject (an observable value)
|
||||
*/
|
||||
struct _lv_subject_t {
|
||||
#if LV_USE_EXT_DATA
|
||||
lv_ext_data_t ext_data;
|
||||
#endif
|
||||
lv_ll_t subs_ll; /**< Subscribers */
|
||||
lv_subject_value_t value; /**< Current value */
|
||||
lv_subject_value_t prev_value; /**< Previous value */
|
||||
@@ -79,6 +86,27 @@ typedef void (*lv_observer_cb_t)(lv_observer_t * observer, lv_subject_t * subjec
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
/**
|
||||
* @brief Attaches external user data to an integer Subject with lifecycle management
|
||||
*
|
||||
* Associates arbitrary user-defined data with an LVGL observer and registers a destructor
|
||||
* callback that will be automatically invoked when the observer is deleted. This enables:
|
||||
* - Safe resource cleanup through the destructor mechanism
|
||||
* - Contextual data storage for observer callbacks
|
||||
* - Proper memory management for observer-related resources
|
||||
*
|
||||
* @param subject pointer to Subject
|
||||
* @param data User-defined data pointer to associate
|
||||
* @param free_cb Cleanup function called when:
|
||||
* - Observer is explicitly deleted
|
||||
* - Observed object is deleted
|
||||
* - New data replaces current association
|
||||
* NULL indicates no cleanup required
|
||||
*/
|
||||
void lv_subject_set_external_data(lv_subject_t * subject, void * data, void (* free_cb)(void * data));
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize an integer-type Subject.
|
||||
* @param subject pointer to Subject
|
||||
|
||||
@@ -76,7 +76,10 @@ lv_display_t * lv_display_create(int32_t hor_res, int32_t ver_res)
|
||||
disp->antialiasing = LV_COLOR_DEPTH > 8 ? 1 : 0;
|
||||
disp->dpi = LV_DPI_DEF;
|
||||
disp->color_format = LV_COLOR_FORMAT_NATIVE;
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
disp->ext_data.free_cb = NULL;
|
||||
disp->ext_data.data = NULL;
|
||||
#endif
|
||||
|
||||
#if defined(LV_DRAW_SW_DRAW_UNIT_CNT) && (LV_DRAW_SW_DRAW_UNIT_CNT != 0)
|
||||
disp->tile_cnt = LV_DRAW_SW_DRAW_UNIT_CNT;
|
||||
@@ -227,6 +230,13 @@ void lv_display_delete(lv_display_t * disp)
|
||||
if(disp->layer_deinit) disp->layer_deinit(disp, disp->layer_head);
|
||||
lv_free(disp->layer_head);
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
if(disp->ext_data.free_cb) {
|
||||
disp->ext_data.free_cb(disp->ext_data.data);
|
||||
disp->ext_data.data = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
lv_free(disp);
|
||||
|
||||
if(was_default) lv_display_set_default(lv_ll_get_head(disp_ll_p));
|
||||
@@ -1273,6 +1283,19 @@ int32_t lv_display_dpx(const lv_display_t * disp, int32_t n)
|
||||
return LV_DPX_CALC(lv_display_get_dpi(disp), n);
|
||||
}
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
void lv_display_set_external_data(lv_display_t * disp, void * data, void (* free_cb)(void * data))
|
||||
{
|
||||
if(!disp) {
|
||||
LV_LOG_WARN("Can't attach external user data and destructor callback to a NULL display");
|
||||
return;
|
||||
}
|
||||
|
||||
disp->ext_data.data = data;
|
||||
disp->ext_data.free_cb = free_cb;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
@@ -732,6 +732,22 @@ int32_t lv_dpx(int32_t n);
|
||||
*/
|
||||
int32_t lv_display_dpx(const lv_display_t * disp, int32_t n);
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
/**
|
||||
* @brief Attaches external user data and destructor callback to a display
|
||||
*
|
||||
* Associates custom user data with an LVGL display and specifies a destructor function
|
||||
* that will be automatically invoked when the display is deleted to properly clean up
|
||||
* the associated resources.
|
||||
*
|
||||
* @param disp Pointer to a display
|
||||
* @param data User-defined data pointer to associate with the display
|
||||
* @param free_cb Callback function for cleaning up data when display is deleted.
|
||||
* Receives data as parameter. NULL means no cleanup required.
|
||||
*/
|
||||
void lv_display_set_external_data(lv_display_t * disp, void * data, void (* free_cb)(void * data));
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
@@ -22,6 +22,10 @@ extern "C" {
|
||||
#include "../debugging/sysmon/lv_sysmon_private.h"
|
||||
#endif
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
#include "../lvgl_private.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
@@ -34,7 +38,9 @@ extern "C" {
|
||||
**********************/
|
||||
|
||||
struct _lv_display_t {
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
lv_ext_data_t ext_data;
|
||||
#endif
|
||||
/*---------------------
|
||||
* Resolution
|
||||
*--------------------*/
|
||||
|
||||
@@ -142,6 +142,10 @@ lv_indev_t * lv_indev_create(void)
|
||||
indev->gesture_min_velocity = LV_INDEV_DEF_GESTURE_MIN_VELOCITY;
|
||||
indev->rotary_sensitivity = LV_INDEV_DEF_ROTARY_SENSITIVITY;
|
||||
indev->key_remap_cb = NULL;
|
||||
#if LV_USE_EXT_DATA
|
||||
indev->ext_data.free_cb = NULL;
|
||||
indev->ext_data.data = NULL;
|
||||
#endif
|
||||
|
||||
#if LV_USE_GESTURE_RECOGNITION
|
||||
lv_indev_gesture_init(indev);
|
||||
@@ -163,6 +167,14 @@ void lv_indev_delete(lv_indev_t * indev)
|
||||
|
||||
/*Remove the input device from the list*/
|
||||
lv_ll_remove(indev_ll_head, indev);
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
if(indev->ext_data.free_cb) {
|
||||
indev->ext_data.free_cb(indev->ext_data.data);
|
||||
indev->ext_data.data = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*Free the memory of the input device*/
|
||||
lv_free(indev);
|
||||
}
|
||||
@@ -685,6 +697,19 @@ void lv_indev_set_key_remap_cb(lv_indev_t * indev, lv_indev_key_remap_cb_t remap
|
||||
indev->key_remap_cb = remap_cb;
|
||||
}
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
void lv_indev_set_external_data(lv_indev_t * indev, void * data, void (* free_cb)(void * data))
|
||||
{
|
||||
if(!indev) {
|
||||
LV_LOG_WARN("Can't attach external user data and free_cb callback to a NULL indev");
|
||||
return;
|
||||
}
|
||||
|
||||
indev->ext_data.data = data;
|
||||
indev->ext_data.free_cb = free_cb;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
@@ -452,6 +452,22 @@ lv_result_t lv_indev_send_event(lv_indev_t * indev, lv_event_code_t code, void *
|
||||
*/
|
||||
void lv_indev_set_key_remap_cb(lv_indev_t * indev, lv_indev_key_remap_cb_t remap_cb);
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
/**
|
||||
* @brief Attaches external user data and destructor callback to an indev
|
||||
*
|
||||
* Associates custom user data with an LVGL indev and specifies a destructor function
|
||||
* that will be automatically invoked when the indev is deleted to properly clean up
|
||||
* the associated resources.
|
||||
*
|
||||
* @param indev Pointer to an indev
|
||||
* @param data User-defined data pointer to associate with the indev
|
||||
* @param free_cb Callback function for cleaning up ext_data when indev is deleted.
|
||||
* Receives ext_data as parameter. NULL means no cleanup required.
|
||||
*/
|
||||
void lv_indev_set_external_data(lv_indev_t * indev, void * data, void (* free_cb)(void * data));
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
@@ -18,6 +18,10 @@ extern "C" {
|
||||
#include "lv_indev_scroll.h"
|
||||
#include "lv_indev_gesture.h"
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
#include "../lvgl_private.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
@@ -28,6 +32,9 @@ extern "C" {
|
||||
**********************/
|
||||
|
||||
struct _lv_indev_t {
|
||||
#if LV_USE_EXT_DATA
|
||||
lv_ext_data_t ext_data;
|
||||
#endif
|
||||
/** Input device type*/
|
||||
lv_indev_type_t type;
|
||||
|
||||
|
||||
@@ -4503,6 +4503,15 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** Enable or disable for external data and destructor function */
|
||||
#ifndef LV_USE_EXT_DATA
|
||||
#ifdef CONFIG_LV_USE_EXT_DATA
|
||||
#define LV_USE_EXT_DATA CONFIG_LV_USE_EXT_DATA
|
||||
#else
|
||||
#define LV_USE_EXT_DATA 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*=====================
|
||||
* BUILD OPTIONS
|
||||
*======================*/
|
||||
|
||||
@@ -23,6 +23,13 @@ extern "C" {
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
typedef struct {
|
||||
void * data;
|
||||
void (* free_cb)(void * data);
|
||||
} lv_ext_data_t;
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
@@ -114,6 +114,10 @@ void lv_anim_init(lv_anim_t * a)
|
||||
a->repeat_cnt = 1;
|
||||
a->path_cb = lv_anim_path_linear;
|
||||
a->early_apply = 1;
|
||||
#if LV_USE_EXT_DATA
|
||||
a->ext_data.free_cb = NULL;
|
||||
a->ext_data.data = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
lv_anim_t * lv_anim_start(const lv_anim_t * a)
|
||||
@@ -555,6 +559,19 @@ void lv_anim_resume(lv_anim_t * a)
|
||||
a->run_round = state.anim_run_round;
|
||||
}
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
void lv_anim_set_external_data(lv_anim_t * anim, void * data, void (* free_cb)(void * data))
|
||||
{
|
||||
if(!a) {
|
||||
LV_LOG_WARN("Can't attach external user data and destructor callback to a NULL animation");
|
||||
return;
|
||||
}
|
||||
|
||||
anim->ext_data.data = data;
|
||||
anim->ext_data.free_cb = free_cb;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@@ -680,6 +697,12 @@ static void anim_completed_handler(lv_anim_t * a)
|
||||
/*Call the callback function at the end*/
|
||||
if(a->completed_cb != NULL) a->completed_cb(a);
|
||||
if(a->deleted_cb != NULL) a->deleted_cb(a);
|
||||
#if LV_USE_EXT_DATA
|
||||
if(a->ext_data.free_cb) {
|
||||
a->ext_data.free_cb(a->ext_data.data);
|
||||
a->ext_data.data = NULL;
|
||||
}
|
||||
#endif
|
||||
lv_free(a);
|
||||
}
|
||||
/*If the animation is not deleted then restart it*/
|
||||
@@ -797,6 +820,12 @@ static bool remove_concurrent_anims(const lv_anim_t * a_current)
|
||||
/*|| (a->custom_exec_cb && a->custom_exec_cb == a_current->custom_exec_cb)*/)) {
|
||||
lv_ll_remove(anim_ll_p, a);
|
||||
if(a->deleted_cb != NULL) a->deleted_cb(a);
|
||||
#if LV_USE_EXT_DATA
|
||||
if(a->ext_data.free_cb) {
|
||||
a->ext_data.free_cb(a->ext_data.data);
|
||||
a->ext_data.data = NULL;
|
||||
}
|
||||
#endif
|
||||
lv_free(a);
|
||||
/*Read by `anim_timer`. It need to know if a delete occurred in the linked list*/
|
||||
anim_mark_list_change();
|
||||
@@ -818,5 +847,11 @@ static void remove_anim(void * a)
|
||||
lv_anim_t * anim = a;
|
||||
lv_ll_remove(anim_ll_p, a);
|
||||
if(anim->deleted_cb != NULL) anim->deleted_cb(anim);
|
||||
#if LV_USE_EXT_DATA
|
||||
if(anim->ext_data.free_cb) {
|
||||
anim->ext_data.free_cb(anim->ext_data.data);
|
||||
anim->ext_data.data = NULL;
|
||||
}
|
||||
#endif
|
||||
lv_free(a);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ extern "C" {
|
||||
#include "lv_timer.h"
|
||||
#include "lv_ll.h"
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
#include "../lvgl_private.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
@@ -122,6 +126,9 @@ typedef struct {
|
||||
|
||||
/** Describes an animation*/
|
||||
struct _lv_anim_t {
|
||||
#if LV_USE_EXT_DATA
|
||||
lv_ext_data_t ext_data;
|
||||
#endif
|
||||
void * var; /**< Variable (Widget or other user-provided object) to animate */
|
||||
lv_anim_exec_xcb_t exec_cb; /**< Function to execute to animate */
|
||||
lv_anim_custom_exec_cb_t custom_exec_cb; /**< Function to execute to animate,
|
||||
@@ -555,6 +562,25 @@ int32_t lv_anim_path_step(const lv_anim_t * a);
|
||||
*/
|
||||
int32_t lv_anim_path_custom_bezier3(const lv_anim_t * a);
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
/**
|
||||
* @brief Associates external user data with an animation instance
|
||||
*
|
||||
* Attaches arbitrary user-defined data to an LVGL animation object along with an optional
|
||||
* destructor callback that will be automatically invoked when the animation completes
|
||||
* or is deleted, enabling proper resource cleanup.
|
||||
*
|
||||
* @param anim Pointer to the animation object to configure
|
||||
* @param data User-defined data pointer to associate
|
||||
* @param free_cb Cleanup callback that receives ext_data when:
|
||||
* - Animation completes naturally
|
||||
* - Animation is deleted prematurely
|
||||
* - New data replaces current association
|
||||
* NULL indicates no cleanup required
|
||||
*/
|
||||
void lv_anim_set_external_data(lv_anim_t * anim, void * data, void (* free_cb)(void * data));
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
|
||||
+42
-1
@@ -54,6 +54,19 @@ static lv_event_dsc_t ** event_array_at(lv_event_list_t * list, uint32_t index);
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
void lv_event_desc_set_external_data(lv_event_dsc_t * dsc, void * data, void (* free_cb)(void * data))
|
||||
{
|
||||
if(!dsc) {
|
||||
LV_LOG_WARN("Can't attach external user data and destructor callback to a NULL event descriptor");
|
||||
return;
|
||||
}
|
||||
|
||||
dsc->ext_data.data = data;
|
||||
dsc->ext_data.free_cb = free_cb;
|
||||
}
|
||||
#endif
|
||||
|
||||
void lv_event_push(lv_event_t * e)
|
||||
{
|
||||
/*Build a simple linked list from the objects used in the events
|
||||
@@ -118,6 +131,9 @@ lv_result_t lv_event_send(lv_event_list_t * list, lv_event_t * e, bool preproces
|
||||
lv_event_code_t filter = dsc->filter & ~LV_EVENT_PREPROCESS;
|
||||
if(filter == LV_EVENT_ALL || filter == e->code) {
|
||||
e->user_data = dsc->user_data;
|
||||
#if LV_USE_EXT_DATA
|
||||
e->ext_data.data = dsc->ext_data.data;
|
||||
#endif
|
||||
dsc->cb(e);
|
||||
if(e->stop_processing) break;
|
||||
|
||||
@@ -149,6 +165,10 @@ lv_event_dsc_t * lv_event_add(lv_event_list_t * list, lv_event_cb_t cb, lv_event
|
||||
dsc->cb = cb;
|
||||
dsc->filter = filter;
|
||||
dsc->user_data = user_data;
|
||||
#if LV_USE_EXT_DATA
|
||||
dsc->ext_data.free_cb = NULL;
|
||||
dsc->ext_data.data = NULL;
|
||||
#endif
|
||||
|
||||
if(event_array_size(list) == 0) {
|
||||
/*event list hasn't been initialized.*/
|
||||
@@ -168,6 +188,12 @@ bool lv_event_remove_dsc(lv_event_list_t * list, lv_event_dsc_t * dsc)
|
||||
for(uint32_t i = 0; i < size; i++) {
|
||||
lv_event_dsc_t * event = *event_array_at(list, i);
|
||||
if(event == dsc) {
|
||||
#if LV_USE_EXT_DATA
|
||||
if(dsc->ext_data.free_cb) {
|
||||
dsc->ext_data.free_cb(dsc->ext_data.data);
|
||||
dsc->ext_data.data = NULL;
|
||||
}
|
||||
#endif
|
||||
event_mark_deleting(list, event);
|
||||
cleanup_event_list(list);
|
||||
return true;
|
||||
@@ -208,6 +234,12 @@ bool lv_event_remove(lv_event_list_t * list, uint32_t index)
|
||||
LV_ASSERT_NULL(list);
|
||||
lv_event_dsc_t * dsc = lv_event_get_dsc(list, index);
|
||||
if(dsc == NULL) return false;
|
||||
#if LV_USE_EXT_DATA
|
||||
if(dsc->ext_data.free_cb) {
|
||||
dsc->ext_data.free_cb(dsc->ext_data.data);
|
||||
dsc->ext_data.data = NULL;
|
||||
}
|
||||
#endif
|
||||
event_mark_deleting(list, dsc);
|
||||
cleanup_event_list(list);
|
||||
return true;
|
||||
@@ -217,8 +249,17 @@ void lv_event_remove_all(lv_event_list_t * list)
|
||||
{
|
||||
LV_ASSERT_NULL(list);
|
||||
const uint32_t size = event_array_size(list);
|
||||
for(uint32_t i = 0; i < size; i++)
|
||||
for(uint32_t i = 0; i < size; i++) {
|
||||
#if LV_USE_EXT_DATA
|
||||
lv_event_dsc_t * dsc = lv_event_get_dsc(list, i);
|
||||
if(dsc && dsc->ext_data.free_cb) {
|
||||
dsc->ext_data.free_cb(dsc->ext_data.data);
|
||||
dsc->ext_data.data = NULL;
|
||||
}
|
||||
#endif
|
||||
event_mark_deleting(list, *event_array_at(list, i));
|
||||
}
|
||||
|
||||
cleanup_event_list(list);
|
||||
}
|
||||
|
||||
|
||||
@@ -245,6 +245,19 @@ uint32_t lv_event_register_id(void);
|
||||
*/
|
||||
const char * lv_event_code_get_name(lv_event_code_t code);
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
/**
|
||||
* Set external data and its destructor for an event descriptor.
|
||||
* This allows associating custom data with an event callback that will be automatically cleaned up
|
||||
* when the event descriptor is removed or destroyed.
|
||||
* @param dsc pointer to an event descriptor (from lv_obj_add_event_cb)
|
||||
* @param data pointer to the external data to associate with the event descriptor
|
||||
* @param free_cb function pointer to a destructor that will be called to clean up the external data.
|
||||
* The destructor will receive the data pointer as its parameter.
|
||||
*/
|
||||
void lv_event_desc_set_external_data(lv_event_dsc_t * dsc, void * data, void (* free_cb)(void * data));
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
@@ -16,6 +16,10 @@ extern "C" {
|
||||
|
||||
#include "lv_event.h"
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
#include "../lvgl_private.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
@@ -25,6 +29,9 @@ extern "C" {
|
||||
**********************/
|
||||
|
||||
struct _lv_event_dsc_t {
|
||||
#if LV_USE_EXT_DATA
|
||||
lv_ext_data_t ext_data;
|
||||
#endif
|
||||
lv_event_cb_t cb;
|
||||
void * user_data;
|
||||
uint32_t filter;
|
||||
@@ -41,6 +48,9 @@ struct _lv_event_t {
|
||||
uint8_t stop_processing : 1;
|
||||
uint8_t stop_bubbling : 1;
|
||||
uint8_t stop_trickling : 1;
|
||||
#if LV_USE_EXT_DATA
|
||||
lv_ext_data_t ext_data;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -177,6 +177,10 @@ lv_timer_t * lv_timer_create(lv_timer_cb_t timer_xcb, uint32_t period, void * us
|
||||
new_timer->last_run = lv_tick_get();
|
||||
new_timer->user_data = user_data;
|
||||
new_timer->auto_delete = true;
|
||||
#if LV_USE_EXT_DATA
|
||||
new_timer->ext_data.free_cb = NULL;
|
||||
new_timer->ext_data.data = NULL;
|
||||
#endif
|
||||
|
||||
state.timer_created = true;
|
||||
|
||||
@@ -196,6 +200,13 @@ void lv_timer_delete(lv_timer_t * timer)
|
||||
lv_ll_remove(timer_ll_p, timer);
|
||||
state.timer_deleted = true;
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
if(timer->ext_data.free_cb) {
|
||||
timer->ext_data.free_cb(timer->ext_data.data);
|
||||
timer->ext_data.data = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
lv_free(timer);
|
||||
}
|
||||
|
||||
@@ -301,6 +312,19 @@ bool lv_timer_get_paused(lv_timer_t * timer)
|
||||
return timer->paused;
|
||||
}
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
void lv_timer_set_external_data(lv_timer_t * timer, void * data, void (* free_cb)(void * data))
|
||||
{
|
||||
if(!timer) {
|
||||
LV_LOG_WARN("Can't attach external user data and destructor callback to a NULL timer");
|
||||
return;
|
||||
}
|
||||
|
||||
timer->ext_data.data = data;
|
||||
timer->ext_data.free_cb = free_cb;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
@@ -196,6 +196,22 @@ void * lv_timer_get_user_data(lv_timer_t * timer);
|
||||
*/
|
||||
bool lv_timer_get_paused(lv_timer_t * timer);
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
/**
|
||||
* @brief Attaches external user data and destructor callback to a timer object
|
||||
*
|
||||
* Associates custom user data with an LVGL timer and specifies a destructor function
|
||||
* that will be automatically invoked when the timer is deleted to properly clean up
|
||||
* the associated resources.
|
||||
*
|
||||
* @param timer Pointer to the timer object
|
||||
* @param data User-defined data pointer to associate with the timer
|
||||
* @param destructor Callback function for cleaning up ext_data when timer is deleted.
|
||||
* Receives ext_data as parameter. NULL means no cleanup required.
|
||||
*/
|
||||
void lv_timer_set_external_data(lv_timer_t * timer, void * data, void (* free_cb)(void * data));
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
@@ -16,6 +16,10 @@ extern "C" {
|
||||
|
||||
#include "lv_timer.h"
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
#include "../lvgl_private.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
@@ -28,6 +32,9 @@ extern "C" {
|
||||
* Descriptor of a lv_timer
|
||||
*/
|
||||
struct _lv_timer_t {
|
||||
#if LV_USE_EXT_DATA
|
||||
lv_ext_data_t ext_data;
|
||||
#endif
|
||||
uint32_t period; /**< How often the timer should run */
|
||||
uint32_t last_run; /**< Last time the timer ran */
|
||||
lv_timer_cb_t timer_cb; /**< Timer function */
|
||||
|
||||
@@ -667,6 +667,10 @@ lv_theme_t * lv_theme_default_init(lv_display_t * disp, lv_color_t color_primary
|
||||
theme->base.font_large = font;
|
||||
theme->base.apply_cb = theme_apply;
|
||||
theme->base.flags = dark ? MODE_DARK : 0;
|
||||
#if LV_USE_EXT_DATA
|
||||
theme->base.ext_data.free_cb = NULL;
|
||||
theme->base.ext_data.data = NULL;
|
||||
#endif
|
||||
|
||||
style_init(theme);
|
||||
|
||||
@@ -711,6 +715,12 @@ void lv_theme_default_deinit(void)
|
||||
lv_style_reset(theme_styles + i);
|
||||
}
|
||||
}
|
||||
#if LV_USE_EXT_DATA
|
||||
if(theme->base.ext_data.free_cb) {
|
||||
theme->base.ext_data.free_cb(theme->base.ext_data.data);
|
||||
theme->base.ext_data.data = NULL;
|
||||
}
|
||||
#endif
|
||||
lv_free(theme_def);
|
||||
theme_def = NULL;
|
||||
}
|
||||
|
||||
@@ -113,6 +113,19 @@ lv_color_t lv_theme_get_color_secondary(lv_obj_t * obj)
|
||||
return th ? th->color_secondary : lv_palette_main(LV_PALETTE_BLUE);
|
||||
}
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
void lv_theme_set_external_data(lv_theme_t * theme, void * data, void (* free_cb)(void * data))
|
||||
{
|
||||
if(!theme) {
|
||||
LV_LOG_WARN("Can't attach external user data and destructor callback to a NULL theme");
|
||||
return;
|
||||
}
|
||||
|
||||
theme->ext_data.data = data;
|
||||
theme->ext_data.free_cb = free_cb;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
@@ -113,6 +113,22 @@ lv_color_t lv_theme_get_color_secondary(lv_obj_t * obj);
|
||||
*/
|
||||
void lv_theme_delete(lv_theme_t * theme);
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
/**
|
||||
* @brief Attaches external user data and destructor callback to the theme
|
||||
*
|
||||
* Associates custom user data with an LVGL theme and specifies a destructor function
|
||||
* that will be automatically invoked when the theme is deleted to properly clean up
|
||||
* the associated resources.
|
||||
*
|
||||
* @param theme Pointer to theme which callback should be set
|
||||
* @param data User-defined data pointer to associate with the theme
|
||||
* @param free_cb Callback function for cleaning up ext_data when theme is deleted.
|
||||
* Receives ext_data as parameter. NULL means no cleanup required.
|
||||
*/
|
||||
void lv_theme_set_external_data(lv_theme_t * theme, void * data, void (* free_cb)(void * data));
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
@@ -16,6 +16,10 @@ extern "C" {
|
||||
|
||||
#include "lv_theme.h"
|
||||
|
||||
#if LV_USE_EXT_DATA
|
||||
#include "../lvgl_private.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
@@ -25,6 +29,9 @@ extern "C" {
|
||||
**********************/
|
||||
|
||||
struct _lv_theme_t {
|
||||
#if LV_USE_EXT_DATA
|
||||
lv_ext_data_t ext_data;
|
||||
#endif
|
||||
lv_theme_apply_cb_t apply_cb;
|
||||
lv_theme_t * parent; /**< Apply the current theme's style on top of this theme. */
|
||||
void * user_data;
|
||||
|
||||
@@ -198,6 +198,10 @@ lv_theme_t * lv_theme_mono_init(lv_display_t * disp, bool dark_bg, const lv_font
|
||||
theme->base.font_normal = LV_FONT_DEFAULT;
|
||||
theme->base.font_large = LV_FONT_DEFAULT;
|
||||
theme->base.apply_cb = theme_apply;
|
||||
#if LV_USE_EXT_DATA
|
||||
theme->base.ext_data.free_cb = NULL;
|
||||
theme->base.ext_data.data = NULL;
|
||||
#endif
|
||||
|
||||
style_init(theme, dark_bg, font);
|
||||
|
||||
@@ -237,6 +241,12 @@ void lv_theme_mono_deinit(void)
|
||||
lv_style_reset(theme_styles + i);
|
||||
}
|
||||
}
|
||||
#if LV_USE_EXT_DATA
|
||||
if(theme->base.ext_data.free_cb) {
|
||||
theme->base.ext_data.free_cb(theme->base.ext_data.data);
|
||||
theme->base.ext_data.data = NULL;
|
||||
}
|
||||
#endif
|
||||
lv_free(theme_def);
|
||||
theme_def = NULL;
|
||||
}
|
||||
|
||||
@@ -159,6 +159,10 @@ lv_theme_t * lv_theme_simple_init(lv_display_t * disp)
|
||||
theme->base.font_normal = LV_FONT_DEFAULT;
|
||||
theme->base.font_large = LV_FONT_DEFAULT;
|
||||
theme->base.apply_cb = theme_apply;
|
||||
#if LV_USE_EXT_DATA
|
||||
theme->base.ext_data.free_cb = NULL;
|
||||
theme->base.ext_data.data = NULL;
|
||||
#endif
|
||||
|
||||
style_init(theme);
|
||||
|
||||
@@ -198,6 +202,12 @@ void lv_theme_simple_deinit(void)
|
||||
lv_style_reset(theme_styles + i);
|
||||
}
|
||||
}
|
||||
#if LV_USE_EXT_DATA
|
||||
if(theme->base.ext_data.free_cb) {
|
||||
theme->base.ext_data.free_cb(theme->base.ext_data.data);
|
||||
theme->base.ext_data.data = NULL;
|
||||
}
|
||||
#endif
|
||||
lv_free(theme_def);
|
||||
theme_def = NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user