diff --git a/src/core/lv_group.c b/src/core/lv_group.c index a585469e7a..37fe493638 100644 --- a/src/core/lv_group.c +++ b/src/core/lv_group.c @@ -129,10 +129,12 @@ void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj) LV_LOG_TRACE("begin"); + if(!lv_obj_allocate_spec_attr(obj)) { + return; + } + /*Be sure the object is removed from its current group*/ lv_group_remove_obj(obj); - - if(obj->spec_attr == NULL) lv_obj_allocate_spec_attr(obj); obj->spec_attr->group_p = group; lv_obj_t ** next = lv_ll_ins_tail(&group->obj_ll); diff --git a/src/core/lv_obj.c b/src/core/lv_obj.c index 115c7f6844..368454173a 100644 --- a/src/core/lv_obj.c +++ b/src/core/lv_obj.c @@ -411,20 +411,67 @@ lv_group_t * lv_obj_get_group(const lv_obj_t * obj) * OTHER FUNCTIONS *------------------*/ -void lv_obj_allocate_spec_attr(lv_obj_t * obj) +lv_result_t lv_obj_add_child(lv_obj_t * parent, lv_obj_t * child) +{ + LV_ASSERT_OBJ(parent, MY_CLASS); + + uint16_t new_child_cnt = parent->spec_attr->child_cnt + 1; + + lv_obj_t ** children = lv_realloc(parent->spec_attr->children, + new_child_cnt * (sizeof(lv_obj_t *))); + if(!children) { + return LV_RESULT_INVALID; + } + children[new_child_cnt - 1] = child; + + parent->spec_attr->child_cnt = new_child_cnt; + parent->spec_attr->children = children; + return LV_RESULT_OK; +} + +void lv_obj_remove_child(lv_obj_t * parent, lv_obj_t * child) +{ + LV_ASSERT_OBJ(parent, MY_CLASS); + LV_ASSERT_OBJ(child, MY_CLASS); + for(int32_t i = lv_obj_get_index(child); i < (int32_t)parent->spec_attr->child_cnt - 1; i++) { + parent->spec_attr->children[i] = parent->spec_attr->children[i + 1]; + } + + /* No more children*/ + if(parent->spec_attr->child_cnt == 1) { + lv_free(parent->spec_attr->children); + parent->spec_attr->children = NULL; + parent->spec_attr->child_cnt = 0; + return; + } + + parent->spec_attr->child_cnt--; + parent->spec_attr->children = lv_realloc(parent->spec_attr->children, + parent->spec_attr->child_cnt * (sizeof(lv_obj_t *))); + /* Reallocating a smaller size should never fail, so assert it here*/ + LV_ASSERT_MALLOC(parent->spec_attr->children); +} + +lv_obj_spec_attr_t * lv_obj_allocate_spec_attr(lv_obj_t * obj) { LV_ASSERT_OBJ(obj, MY_CLASS); - - if(obj->spec_attr == NULL) { - obj->spec_attr = lv_malloc_zeroed(sizeof(lv_obj_spec_attr_t)); - LV_ASSERT_MALLOC(obj->spec_attr); - if(obj->spec_attr == NULL) return; - - obj->spec_attr->scroll_dir = LV_DIR_ALL; - obj->spec_attr->scrollbar_mode = LV_SCROLLBAR_MODE_AUTO; + if(obj->spec_attr) { + return obj->spec_attr; } + + lv_obj_spec_attr_t * spec_attr = lv_malloc_zeroed(sizeof(lv_obj_spec_attr_t)); + LV_ASSERT_MALLOC(spec_attr); + if(!spec_attr) { + return NULL; + } + + spec_attr->scroll_dir = LV_DIR_ALL; + spec_attr->scrollbar_mode = LV_SCROLLBAR_MODE_AUTO; + obj->spec_attr = spec_attr; + return spec_attr; } + bool lv_obj_check_type(const lv_obj_t * obj, const lv_obj_class_t * class_p) { if(obj == NULL) return false; diff --git a/src/core/lv_obj.h b/src/core/lv_obj.h index d18887e132..00c80630c0 100644 --- a/src/core/lv_obj.h +++ b/src/core/lv_obj.h @@ -313,12 +313,6 @@ void * lv_obj_get_user_data(lv_obj_t * obj); * Other functions *======================*/ -/** - * Allocate special data for an object if not allocated yet. - * @param obj pointer to an object - */ -void lv_obj_allocate_spec_attr(lv_obj_t * obj); - /** * Check the type of obj. * @param obj pointer to an object diff --git a/src/core/lv_obj_class.c b/src/core/lv_obj_class.c index 926edf6bb8..b9168c04df 100644 --- a/src/core/lv_obj_class.c +++ b/src/core/lv_obj_class.c @@ -88,14 +88,15 @@ lv_obj_t * lv_obj_class_create_obj(const lv_obj_class_t * class_p, lv_obj_t * pa else { LV_TRACE_OBJ_CREATE("creating normal object"); LV_ASSERT_OBJ(parent, MY_CLASS); - if(parent->spec_attr == NULL) { - lv_obj_allocate_spec_attr(parent); - } - parent->spec_attr->child_cnt++; - parent->spec_attr->children = lv_realloc(parent->spec_attr->children, - sizeof(lv_obj_t *) * parent->spec_attr->child_cnt); - parent->spec_attr->children[parent->spec_attr->child_cnt - 1] = obj; + if(!lv_obj_allocate_spec_attr(parent)) { + lv_free(obj); + return NULL; + } + if(lv_obj_add_child(parent, obj) != LV_RESULT_OK) { + lv_free(obj); + return NULL; + } } return obj; diff --git a/src/core/lv_obj_draw.c b/src/core/lv_obj_draw.c index 1414e85286..53bdd0ffea 100644 --- a/src/core/lv_obj_draw.c +++ b/src/core/lv_obj_draw.c @@ -411,7 +411,10 @@ void lv_obj_refresh_ext_draw_size(lv_obj_t * obj) /*Allocate spec. attrs. only if the result is not zero. *Zero is the default value if the spec. attr. are not defined.*/ else if(s_new != 0) { - lv_obj_allocate_spec_attr(obj); + if(!lv_obj_allocate_spec_attr(obj)) { + LV_PROFILER_DRAW_END; + return; + } obj->spec_attr->ext_draw_size = s_new; } diff --git a/src/core/lv_obj_event.c b/src/core/lv_obj_event.c index bbb44fbf4f..32dd8a1f0d 100644 --- a/src/core/lv_obj_event.c +++ b/src/core/lv_obj_event.c @@ -102,7 +102,9 @@ lv_result_t lv_obj_event_base(const lv_obj_class_t * class_p, lv_event_t * e) lv_event_dsc_t * lv_obj_add_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb, lv_event_code_t filter, void * user_data) { LV_ASSERT_OBJ(obj, MY_CLASS); - lv_obj_allocate_spec_attr(obj); + if(!lv_obj_allocate_spec_attr(obj)) { + return NULL; + } return lv_event_add(&obj->spec_attr->event_list, event_cb, filter, user_data); } diff --git a/src/core/lv_obj_pos.c b/src/core/lv_obj_pos.c index 4f3847e45d..ce31363122 100644 --- a/src/core/lv_obj_pos.c +++ b/src/core/lv_obj_pos.c @@ -1213,7 +1213,9 @@ void lv_obj_set_ext_click_area(lv_obj_t * obj, int32_t size) { LV_ASSERT_OBJ(obj, MY_CLASS); - lv_obj_allocate_spec_attr(obj); + if(!lv_obj_allocate_spec_attr(obj)) { + return; + } obj->spec_attr->ext_click_pad = size; } @@ -1274,7 +1276,10 @@ void lv_obj_set_transform(lv_obj_t * obj, const lv_matrix_t * matrix) return; } - lv_obj_allocate_spec_attr(obj); + if(!lv_obj_allocate_spec_attr(obj)) { + return; + } + if(!obj->spec_attr->matrix) { obj->spec_attr->matrix = lv_malloc(sizeof(lv_matrix_t)); LV_ASSERT_MALLOC(obj->spec_attr->matrix); diff --git a/src/core/lv_obj_private.h b/src/core/lv_obj_private.h index 70ab09f1b3..e9ddbdbabf 100644 --- a/src/core/lv_obj_private.h +++ b/src/core/lv_obj_private.h @@ -28,7 +28,7 @@ extern "C" { * Special, rarely used attributes. * They are allocated automatically if any elements is set. */ -struct _lv_obj_spec_attr_t { +typedef struct _lv_obj_spec_attr_t { lv_obj_t ** children; /**< Store the pointer of the children in an array.*/ lv_group_t * group_p; #if LV_DRAW_TRANSFORM_USE_MATRIX @@ -50,7 +50,9 @@ struct _lv_obj_spec_attr_t { uint16_t scroll_dir : 4; /**< The allowed scroll direction(s), see `lv_dir_t`*/ uint16_t layer_type : 2; /**< Cache the layer type here. Element of lv_intermediate_layer_type_t */ uint16_t name_static : 1; /**< 1: `name` was not dynamically allocated */ -}; +} lv_obj_spec_attr_t; + + struct _lv_obj_t { #if LV_USE_EXT_DATA @@ -92,6 +94,16 @@ struct _lv_obj_t { * GLOBAL PROTOTYPES **********************/ +/** + * Allocate special data for an object if not allocated yet. + * @param obj pointer to an object + * @return the spec_attr created or NULL if something went wrong + */ +lv_obj_spec_attr_t * lv_obj_allocate_spec_attr(lv_obj_t * obj); + +lv_result_t lv_obj_add_child(lv_obj_t * parent, lv_obj_t * child); +void lv_obj_remove_child(lv_obj_t * parent, lv_obj_t * child); + /********************** * MACROS **********************/ diff --git a/src/core/lv_obj_scroll.c b/src/core/lv_obj_scroll.c index 237c6fb468..e05e734a9e 100644 --- a/src/core/lv_obj_scroll.c +++ b/src/core/lv_obj_scroll.c @@ -63,7 +63,9 @@ void lv_obj_set_scrollbar_mode(lv_obj_t * obj, lv_scrollbar_mode_t mode) { LV_ASSERT_OBJ(obj, MY_CLASS); - lv_obj_allocate_spec_attr(obj); + if(!lv_obj_allocate_spec_attr(obj)) { + return; + } if(obj->spec_attr->scrollbar_mode == mode) return; obj->spec_attr->scrollbar_mode = mode; @@ -72,7 +74,9 @@ void lv_obj_set_scrollbar_mode(lv_obj_t * obj, lv_scrollbar_mode_t mode) void lv_obj_set_scroll_dir(lv_obj_t * obj, lv_dir_t dir) { - lv_obj_allocate_spec_attr(obj); + if(!lv_obj_allocate_spec_attr(obj)) { + return; + } if(dir != obj->spec_attr->scroll_dir) { obj->spec_attr->scroll_dir = dir; @@ -81,13 +85,17 @@ void lv_obj_set_scroll_dir(lv_obj_t * obj, lv_dir_t dir) void lv_obj_set_scroll_snap_x(lv_obj_t * obj, lv_scroll_snap_t align) { - lv_obj_allocate_spec_attr(obj); + if(!lv_obj_allocate_spec_attr(obj)) { + return; + } obj->spec_attr->scroll_snap_x = align; } void lv_obj_set_scroll_snap_y(lv_obj_t * obj, lv_scroll_snap_t align) { - lv_obj_allocate_spec_attr(obj); + if(!lv_obj_allocate_spec_attr(obj)) { + return; + } obj->spec_attr->scroll_snap_y = align; } @@ -418,7 +426,9 @@ lv_result_t lv_obj_scroll_by_raw(lv_obj_t * obj, int32_t x, int32_t y) { if(x == 0 && y == 0) return LV_RESULT_OK; - lv_obj_allocate_spec_attr(obj); + if(!lv_obj_allocate_spec_attr(obj)) { + return LV_RESULT_INVALID; + } obj->spec_attr->scroll.x += x; obj->spec_attr->scroll.y += y; diff --git a/src/core/lv_obj_style.c b/src/core/lv_obj_style.c index bff861bea4..5b1e9d19f1 100644 --- a/src/core/lv_obj_style.c +++ b/src/core/lv_obj_style.c @@ -637,7 +637,9 @@ void lv_obj_update_layer_type(lv_obj_t * obj) lv_layer_type_t layer_type = calculate_layer_type(obj); if(obj->spec_attr) obj->spec_attr->layer_type = layer_type; else if(layer_type != LV_LAYER_TYPE_NONE) { - lv_obj_allocate_spec_attr(obj); + if(!lv_obj_allocate_spec_attr(obj)) { + return; + } obj->spec_attr->layer_type = layer_type; } } diff --git a/src/core/lv_obj_tree.c b/src/core/lv_obj_tree.c index 2dc7a024ff..a35dec99d7 100644 --- a/src/core/lv_obj_tree.c +++ b/src/core/lv_obj_tree.c @@ -163,38 +163,25 @@ void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent) return; } - lv_obj_invalidate(obj); - - lv_obj_allocate_spec_attr(parent); - - lv_obj_t * old_parent = obj->parent; - /*Remove the object from the old parent's child list*/ - int32_t i; - for(i = lv_obj_get_index(obj); i <= (int32_t)lv_obj_get_child_count(old_parent) - 2; i++) { - old_parent->spec_attr->children[i] = old_parent->spec_attr->children[i + 1]; - } - old_parent->spec_attr->child_cnt--; - if(old_parent->spec_attr->child_cnt) { - old_parent->spec_attr->children = lv_realloc(old_parent->spec_attr->children, - old_parent->spec_attr->child_cnt * (sizeof(lv_obj_t *))); - } - else { - lv_free(old_parent->spec_attr->children); - old_parent->spec_attr->children = NULL; + if(!lv_obj_allocate_spec_attr(parent)) { + return; } - /*Add the child to the new parent as the last (newest child)*/ - parent->spec_attr->child_cnt++; - parent->spec_attr->children = lv_realloc(parent->spec_attr->children, - parent->spec_attr->child_cnt * (sizeof(lv_obj_t *))); - parent->spec_attr->children[lv_obj_get_child_count(parent) - 1] = obj; + /*Add the object to the new parents list first*/ + if(lv_obj_add_child(parent, obj) != LV_RESULT_OK) { + LV_LOG_WARN("Failed to attach child to parent"); + return; + } - obj->parent = parent; + /*Remove the object from the old parent's child list + * This should never fail, thus we do only do it after adding it to the new parent's list*/ + lv_obj_remove_child(obj->parent, obj); /*Notify the original parent because one of its children is lost*/ - lv_obj_scrollbar_invalidate(old_parent); - lv_obj_send_event(old_parent, LV_EVENT_CHILD_CHANGED, obj); - lv_obj_send_event(old_parent, LV_EVENT_CHILD_DELETED, NULL); + lv_obj_scrollbar_invalidate(obj->parent); + lv_obj_send_event(obj->parent, LV_EVENT_CHILD_CHANGED, obj); + lv_obj_send_event(obj->parent, LV_EVENT_CHILD_DELETED, NULL); + obj->parent = parent; /*Notify the new parent about the child*/ lv_obj_send_event(parent, LV_EVENT_CHILD_CHANGED, obj); @@ -426,7 +413,9 @@ void lv_obj_set_name(lv_obj_t * obj, const char * name) { LV_ASSERT_OBJ(obj, MY_CLASS); - lv_obj_allocate_spec_attr(obj); + if(!lv_obj_allocate_spec_attr(obj)) { + return; + } if(!obj->spec_attr->name_static && obj->spec_attr->name) lv_free((void *)obj->spec_attr->name); @@ -444,8 +433,9 @@ void lv_obj_set_name_static(lv_obj_t * obj, const char * name) { LV_ASSERT_OBJ(obj, MY_CLASS); - lv_obj_allocate_spec_attr(obj); - + if(!lv_obj_allocate_spec_attr(obj)) { + return; + } if(!obj->spec_attr->name_static && obj->spec_attr->name) lv_free((void *)obj->spec_attr->name); obj->spec_attr->name = name; @@ -740,14 +730,7 @@ static void obj_delete_core(lv_obj_t * obj) } /*Remove the object from the child list of its parent*/ else { - int32_t id = lv_obj_get_index(obj); - uint16_t i; - for(i = id; i < obj->parent->spec_attr->child_cnt - 1; i++) { - obj->parent->spec_attr->children[i] = obj->parent->spec_attr->children[i + 1]; - } - obj->parent->spec_attr->child_cnt--; - obj->parent->spec_attr->children = lv_realloc(obj->parent->spec_attr->children, - obj->parent->spec_attr->child_cnt * sizeof(lv_obj_t *)); + lv_obj_remove_child(obj->parent, obj); } /*Free the object itself*/ diff --git a/src/misc/lv_types.h b/src/misc/lv_types.h index 7895a9c8aa..dcc73f06aa 100644 --- a/src/misc/lv_types.h +++ b/src/misc/lv_types.h @@ -188,8 +188,6 @@ typedef struct _lv_hit_test_info_t lv_hit_test_info_t; typedef struct _lv_cover_check_info_t lv_cover_check_info_t; -typedef struct _lv_obj_spec_attr_t lv_obj_spec_attr_t; - typedef struct _lv_image_t lv_image_t; typedef struct _lv_animimg_t lv_animimg_t;