feat(core): add external data and destructor feature (#9112)

Signed-off-by: chenwen@espressif.com <chenwen@espressif.com>
This commit is contained in:
ChenWen
2025-12-21 16:56:33 +08:00
committed by GitHub
parent 947084fc9c
commit dd42852d85
32 changed files with 515 additions and 3 deletions
+17
View File
@@ -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
+3
View File
@@ -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
*======================*/
+24
View File
@@ -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
**********************/
+16
View File
@@ -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
**********************/
+7
View File
@@ -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*/
+26
View File
@@ -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;
+17
View File
@@ -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
**********************/
+7
View File
@@ -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;
+20
View File
@@ -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) {
+28
View File
@@ -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
+24 -1
View File
@@ -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
**********************/
+16
View File
@@ -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
+7 -1
View File
@@ -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
*--------------------*/
+25
View File
@@ -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
**********************/
+16
View File
@@ -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
**********************/
+7
View File
@@ -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;
+9
View File
@@ -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
*======================*/
+7
View File
@@ -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
**********************/
+35
View File
@@ -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);
}
+26
View File
@@ -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
View File
@@ -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);
}
+13
View File
@@ -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
**********************/
+10
View File
@@ -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
};
+24
View File
@@ -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
**********************/
+16
View File
@@ -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
**********************/
+7
View File
@@ -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 */
+10
View File
@@ -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;
}
+13
View File
@@ -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
**********************/
+16
View File
@@ -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
**********************/
+7
View File
@@ -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;
+10
View File
@@ -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;
}
+10
View File
@@ -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;
}