diff --git a/docs/src/main-modules/display/display_events_list.txt b/docs/src/main-modules/display/display_events_list.txt index 24df74bb8a..0f802ee078 100644 --- a/docs/src/main-modules/display/display_events_list.txt +++ b/docs/src/main-modules/display/display_events_list.txt @@ -30,3 +30,7 @@ Call returns immediately if `disp->flushing == 0`. - :cpp:enumerator:`LV_EVENT_FLUSH_WAIT_FINISH`: Sent when the call to `wait_for_flushing()` is about to return, regardless whether any actual waiting occurred. +- :cpp:enumerator:`LV_EVENT_SCREEN_UNLOAD_START`: Sent when a screen starts to be unloaded on this display +- :cpp:enumerator:`LV_EVENT_SCREEN_LOAD_START`: Sent when a screen starts to be loaded on this display +- :cpp:enumerator:`LV_EVENT_SCREEN_LOADED`: Sent when a screen finishes being loaded on this display +- :cpp:enumerator:`LV_EVENT_SCREEN_UNLOADED`: Sent when a screen finishes being unloaded on this display diff --git a/src/display/lv_display.c b/src/display/lv_display.c index e18bd59879..63555da779 100644 --- a/src/display/lv_display.c +++ b/src/display/lv_display.c @@ -32,13 +32,25 @@ /********************** * TYPEDEFS **********************/ +typedef enum { + LV_LOAD_SCREEN_RESULT_OK, + LV_LOAD_SCREEN_RESULT_OLD_SCREEN_DELETED, + LV_LOAD_SCREEN_RESULT_NEW_SCREEN_DELETED, + LV_LOAD_SCREEN_RESULT_BOTH_SCREENS_DELETED, + LV_LOAD_SCREEN_RESULT_DISPLAY_DELETED, +} lv_load_screen_result_t; /********************** * STATIC PROTOTYPES **********************/ + +static bool old_screen_deleted(lv_load_screen_result_t res); +static bool new_screen_deleted(lv_load_screen_result_t res); + static lv_obj_tree_walk_res_t invalidate_layout_cb(lv_obj_t * obj, void * user_data); static void update_resolution(lv_display_t * disp); -static bool load_new_screen(lv_obj_t * scr); +static void screen_event_delete_cb(lv_event_t * e); +static lv_load_screen_result_t load_new_screen(lv_obj_t * scr); static void scr_load_anim_start(lv_anim_t * a); static void opa_scale_anim(void * obj, int32_t v); static void set_x_anim(void * obj, int32_t v); @@ -772,10 +784,16 @@ void lv_screen_load_anim(lv_obj_t * new_scr, lv_screen_load_anim_t anim_type, ui d->prev_scr = d->act_scr; act_scr = d->scr_to_load; /*Active screen changed.*/ - - if(load_new_screen(d->scr_to_load)) { + lv_load_screen_result_t res = load_new_screen(d->scr_to_load); + if(res == LV_LOAD_SCREEN_RESULT_DISPLAY_DELETED) { + return; + } + if(old_screen_deleted(res)) { d->prev_scr = NULL; } + if(new_screen_deleted(res)) { + return; + } } d->scr_to_load = new_scr; @@ -800,8 +818,14 @@ void lv_screen_load_anim(lv_obj_t * new_scr, lv_screen_load_anim_t anim_type, ui /*Shortcut for immediate load*/ if(time == 0 && delay == 0) { - bool old_screen_deleted = load_new_screen(new_scr); - if(!old_screen_deleted && auto_del && act_scr) { + lv_load_screen_result_t res = load_new_screen(new_scr); + if(res == LV_LOAD_SCREEN_RESULT_DISPLAY_DELETED) { + return; + } + if(new_screen_deleted(res)) { + d->act_scr = NULL; + } + if(!old_screen_deleted(res) && auto_del && act_scr) { lv_obj_delete(act_scr); } return; @@ -1327,6 +1351,15 @@ void lv_display_set_external_data(lv_display_t * disp, void * data, void (* free * STATIC FUNCTIONS **********************/ +static bool old_screen_deleted(lv_load_screen_result_t res) +{ + return res == LV_LOAD_SCREEN_RESULT_BOTH_SCREENS_DELETED || res == LV_LOAD_SCREEN_RESULT_OLD_SCREEN_DELETED; +} +static bool new_screen_deleted(lv_load_screen_result_t res) +{ + return res == LV_LOAD_SCREEN_RESULT_BOTH_SCREENS_DELETED || res == LV_LOAD_SCREEN_RESULT_NEW_SCREEN_DELETED; +} + static void update_resolution(lv_display_t * disp) { int32_t hor_res = lv_display_get_horizontal_resolution(disp); @@ -1370,8 +1403,29 @@ static lv_obj_tree_walk_res_t invalidate_layout_cb(lv_obj_t * obj, void * user_d return LV_OBJ_TREE_WALK_NEXT; } -/* Returns true if the old screen was deleted while loading the new screen*/ -static bool load_new_screen(lv_obj_t * scr) +static void screen_event_delete_cb(lv_event_t * e) +{ + lv_obj_t ** screen_var = lv_event_get_user_data(e); + *screen_var = NULL; +} + +/** + * Load a new screen and report the result. + * + * @param scr the screen object to load; must not be NULL + * @return a value of ::lv_load_screen_result_t indicating the outcome: + * - LV_LOAD_SCREEN_RESULT_OK: the new screen was loaded successfully; + * both the old and new screens remain valid. + * - LV_LOAD_SCREEN_RESULT_OLD_SCREEN_DELETED: the old screen was + * deleted while loading the new screen, but the new screen remains valid. + * - LV_LOAD_SCREEN_RESULT_NEW_SCREEN_DELETED: the new screen was + * deleted during loading/unloading events; the old screen remains valid. + * - LV_LOAD_SCREEN_RESULT_BOTH_SCREENS_DELETED: both the old and new + * screens were deleted during the operation. + * - LV_LOAD_SCREEN_RESULT_DISPLAY_DELETED: the display was deleted + * while processing screen load/unload events. + */ +static lv_load_screen_result_t load_new_screen(lv_obj_t * scr) { /*scr must not be NULL, but d->act_scr might be*/ LV_ASSERT_NULL(scr); @@ -1381,27 +1435,60 @@ static bool load_new_screen(lv_obj_t * scr) LV_ASSERT_NULL(d); lv_obj_t * old_scr = d->act_scr; - bool old_screen_deleted = false; + /* Attach an event delete cb to the screen so we know if the screen is deleted during an event*/ if(old_scr) { - if(lv_obj_send_event(old_scr, LV_EVENT_SCREEN_UNLOAD_START, NULL) == LV_RESULT_INVALID) { - old_screen_deleted = true; + lv_obj_add_event_cb(old_scr, screen_event_delete_cb, LV_EVENT_DELETE, &old_scr); + } + lv_obj_add_event_cb(scr, screen_event_delete_cb, LV_EVENT_DELETE, &scr); + + if(old_scr) { + if(lv_display_send_event(d, LV_EVENT_SCREEN_UNLOAD_START, old_scr) == LV_RESULT_INVALID) { + return LV_LOAD_SCREEN_RESULT_DISPLAY_DELETED; + } + if(old_scr && lv_obj_send_event(old_scr, LV_EVENT_SCREEN_UNLOAD_START, NULL) == LV_RESULT_INVALID) { old_scr = NULL; } } - lv_obj_send_event(scr, LV_EVENT_SCREEN_LOAD_START, NULL); + + if(lv_display_send_event(d, LV_EVENT_SCREEN_LOAD_START, scr) == LV_RESULT_INVALID) { + return LV_LOAD_SCREEN_RESULT_DISPLAY_DELETED; + } + + if(scr && lv_obj_send_event(scr, LV_EVENT_SCREEN_LOAD_START, NULL) == LV_RESULT_INVALID) { + scr = NULL; + } d->act_scr = scr; d->scr_to_load = NULL; - lv_obj_send_event(scr, LV_EVENT_SCREEN_LOADED, NULL); + if(scr && lv_display_send_event(d, LV_EVENT_SCREEN_LOADED, scr) == LV_RESULT_INVALID) { + return LV_LOAD_SCREEN_RESULT_DISPLAY_DELETED; + } + + if(scr && lv_obj_send_event(scr, LV_EVENT_SCREEN_LOADED, NULL) == LV_RESULT_INVALID) { + d->act_scr = NULL; + scr = NULL; + } + if(old_scr) { - if(lv_obj_send_event(old_scr, LV_EVENT_SCREEN_UNLOADED, NULL) == LV_RESULT_INVALID) { - old_screen_deleted = true; + if(lv_display_send_event(d, LV_EVENT_SCREEN_UNLOADED, old_scr) == LV_RESULT_INVALID) { + return LV_LOAD_SCREEN_RESULT_DISPLAY_DELETED; + } + if(old_scr && lv_obj_send_event(old_scr, LV_EVENT_SCREEN_UNLOADED, NULL) == LV_RESULT_INVALID) { + old_scr = NULL; } } - lv_obj_invalidate(scr); - return old_screen_deleted; + if(scr) { + lv_obj_invalidate(scr); + lv_obj_remove_event_cb(scr, screen_event_delete_cb); + } + + if(!old_scr) { + return scr ? LV_LOAD_SCREEN_RESULT_OLD_SCREEN_DELETED : LV_LOAD_SCREEN_RESULT_BOTH_SCREENS_DELETED; + } + lv_obj_remove_event_cb(old_scr, screen_event_delete_cb); + return scr ? LV_LOAD_SCREEN_RESULT_OK : LV_LOAD_SCREEN_RESULT_NEW_SCREEN_DELETED; } static void scr_load_anim_start(lv_anim_t * a) diff --git a/tests/src/test_cases/test_screen_load.c b/tests/src/test_cases/test_screen_load.c index cde5f18049..531475bf11 100644 --- a/tests/src/test_cases/test_screen_load.c +++ b/tests/src/test_cases/test_screen_load.c @@ -132,9 +132,361 @@ void test_screen_load_with_delete_event(void) TEST_ASSERT_EQUAL(lv_obj_is_valid(screen_with_anim_4), true); } +static size_t display_screen_load_start = 0; +static size_t display_screen_loaded = 0; +static size_t display_screen_unload_start = 0; +static size_t display_screen_unloaded = 0; +static void count_display_screen_load_events_cb(lv_event_t * e) +{ + lv_obj_t * screen = lv_event_get_param(e); + TEST_ASSERT_NOT_NULL(screen); + + lv_display_t * screen_display = lv_obj_get_display(screen); + TEST_ASSERT_NOT_NULL(screen_display); + TEST_ASSERT_EQUAL(screen_display, lv_event_get_target(e)); + + switch(lv_event_get_code(e)) { + case LV_EVENT_SCREEN_UNLOADED: + display_screen_unloaded++; + break; + case LV_EVENT_SCREEN_UNLOAD_START: + display_screen_unload_start++; + break; + case LV_EVENT_SCREEN_LOADED: + display_screen_loaded++; + break; + case LV_EVENT_SCREEN_LOAD_START: + display_screen_load_start++; + break; + default: + break; + } +} + +void test_display_receives_screen_load_events(void) +{ + display_screen_load_start = 0; + display_screen_loaded = 0; + display_screen_unload_start = 0; + display_screen_unloaded = 0; + + lv_display_t * display = lv_display_create(100, 100); + lv_display_set_default(display); + + lv_obj_t * screen1 = lv_obj_create(NULL); + + lv_display_add_event_cb(display, count_display_screen_load_events_cb, LV_EVENT_SCREEN_UNLOAD_START, NULL); + lv_display_add_event_cb(display, count_display_screen_load_events_cb, LV_EVENT_SCREEN_UNLOADED, NULL); + lv_display_add_event_cb(display, count_display_screen_load_events_cb, LV_EVENT_SCREEN_LOAD_START, NULL); + lv_display_add_event_cb(display, count_display_screen_load_events_cb, LV_EVENT_SCREEN_LOADED, NULL); + + lv_screen_load(screen1); + TEST_ASSERT_EQUAL(1, display_screen_unloaded); + TEST_ASSERT_EQUAL(1, display_screen_unload_start); + TEST_ASSERT_EQUAL(1, display_screen_loaded); + TEST_ASSERT_EQUAL(1, display_screen_load_start); + + /* Loading the same screen doesn't do anything*/ + lv_screen_load(screen1); + TEST_ASSERT_EQUAL(1, display_screen_unloaded); + TEST_ASSERT_EQUAL(1, display_screen_unload_start); + TEST_ASSERT_EQUAL(1, display_screen_loaded); + TEST_ASSERT_EQUAL(1, display_screen_load_start); + + lv_display_delete(display); +} + +static size_t screen_event_count = 0; +static void screen_event_cb(lv_event_t * e) +{ + LV_UNUSED(e); + screen_event_count++; +} + +static size_t display_event_count = 0; +/* This event handler deletes the display during screen load events*/ +static void display_event_delete_cb(lv_event_t * e) +{ + lv_obj_t * screen = lv_event_get_param(e); + TEST_ASSERT_NOT_NULL(screen); + + lv_display_t * screen_display = lv_obj_get_display(screen); + TEST_ASSERT_NOT_NULL(screen_display); + lv_display_t * event_display = lv_event_get_target(e); + TEST_ASSERT_NOT_NULL(event_display); + + /* Screen display and event display should match*/ + TEST_ASSERT_EQUAL(screen_display, event_display); + lv_display_delete(event_display); + display_event_count++; +} + + + +void test_display_delete_when_screen_is_loaded(void) +{ + /* Check that LVGL correctly handles deleting the display during screen load events*/ + { + lv_display_t * display = lv_display_create(100, 100); + lv_display_set_default(display); + lv_obj_t * screen = lv_obj_create(NULL); + lv_display_add_event_cb(display, display_event_delete_cb, LV_EVENT_SCREEN_UNLOAD_START, NULL); + + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOAD_START, NULL); + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOADED, NULL); + + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOAD_START, NULL); + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOADED, NULL); + lv_screen_load(screen); + + /* The display screen event was called only once*/ + TEST_ASSERT_EQUAL(display_event_count, 1); + /* No unload event for previous screen as the display was deleted + * No load event for new screen as the display was deleted */ + TEST_ASSERT_EQUAL(screen_event_count, 0); + + display_event_count = screen_event_count = 0; + } + + { + lv_display_t * display = lv_display_create(100, 100); + lv_display_set_default(display); + lv_obj_t * screen = lv_obj_create(NULL); + lv_display_add_event_cb(display, display_event_delete_cb, LV_EVENT_SCREEN_LOAD_START, NULL); + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOAD_START, NULL); + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOADED, NULL); + + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOAD_START, NULL); + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOADED, NULL); + lv_screen_load(screen); + + /* The display screen event was called only once*/ + TEST_ASSERT_EQUAL(display_event_count, 1); + /* We should've gotten an unload start event from previous screen before the display got deleted + * No load event for new screen as the display was deleted */ + TEST_ASSERT_EQUAL(screen_event_count, 1); + + display_event_count = screen_event_count = 0; + } + + { + lv_display_t * display = lv_display_create(100, 100); + lv_display_set_default(display); + lv_obj_t * screen = lv_obj_create(NULL); + lv_display_add_event_cb(display, display_event_delete_cb, LV_EVENT_SCREEN_LOADED, NULL); + + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOAD_START, NULL); + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOADED, NULL); + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOAD_START, NULL); + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOADED, NULL); + lv_screen_load(screen); + + /* The display screen event was called only once*/ + TEST_ASSERT_EQUAL(display_event_count, 1); + /* We should've gotten an unload start event from previous screen before the display got deleted + * We should've gotten an load_start event for new screen before the display was deleted */ + TEST_ASSERT_EQUAL(screen_event_count, 2); + + display_event_count = screen_event_count = 0; + } + { + lv_display_t * display = lv_display_create(100, 100); + lv_display_set_default(display); + lv_obj_t * screen = lv_obj_create(NULL); + lv_display_add_event_cb(display, display_event_delete_cb, LV_EVENT_SCREEN_UNLOADED, NULL); + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOAD_START, NULL); + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOADED, NULL); + + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOAD_START, NULL); + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOADED, NULL); + lv_screen_load(screen); + + /* The display screen event was called only once*/ + TEST_ASSERT_EQUAL(display_event_count, 1); + /* We should've gotten an unload start event from previous screen before the display got deleted + * We should've gotten an load_start and loaded events for new screen before the display was deleted */ + TEST_ASSERT_EQUAL(screen_event_count, 3); + display_event_count = screen_event_count = 0; + } +} + +static size_t screen_delete_event_count = 0; +/* This event handler deletes the target object during screen load events*/ +static void screen_delete_event_cb(lv_event_t * e) +{ + lv_obj_delete(lv_event_get_target_obj(e)); + screen_delete_event_count++; +} + +void test_new_screen_delete_when_screen_is_loaded(void) +{ + /* Check that LVGL correctly handles when the new screen is deleted during screen load events*/ + { + lv_obj_t * screen = lv_obj_create(NULL); + lv_obj_add_event_cb(screen, screen_delete_event_cb, LV_EVENT_SCREEN_LOAD_START, NULL); + lv_screen_load(screen); + + /* New screen deleted during screen load*/ + TEST_ASSERT_EQUAL(screen_delete_event_count, 1); + TEST_ASSERT_NULL(lv_display_get_screen_active(lv_display_get_default())); + screen_delete_event_count = 0; + } + + { + lv_obj_t * screen = lv_obj_create(NULL); + lv_obj_add_event_cb(screen, screen_delete_event_cb, LV_EVENT_SCREEN_LOADED, NULL); + lv_screen_load(screen); + + /* New screen deleted during screen load*/ + TEST_ASSERT_EQUAL(screen_delete_event_count, 1); + TEST_ASSERT_NULL(lv_display_get_screen_active(lv_display_get_default())); + screen_delete_event_count = 0; + } +} +void test_old_screen_delete_when_screen_is_loaded(void) +{ + /* Check that LVGL correctly handles when the old screen is deleted during screen load events*/ + lv_obj_t * default_screen = lv_obj_create(NULL); + lv_screen_load(default_screen); + { + lv_obj_t * screen = lv_obj_create(NULL); + lv_obj_add_event_cb(lv_screen_active(), screen_delete_event_cb, LV_EVENT_SCREEN_UNLOAD_START, NULL); + lv_screen_load(screen); + + /* Old screen deleted during screen load*/ + TEST_ASSERT_EQUAL(screen_delete_event_count, 1); + TEST_ASSERT_EQUAL(screen, lv_display_get_screen_active(lv_display_get_default())); + screen_delete_event_count = 0; + } + { + lv_obj_t * screen = lv_obj_create(NULL); + lv_obj_add_event_cb(lv_screen_active(), screen_delete_event_cb, LV_EVENT_SCREEN_UNLOADED, NULL); + lv_screen_load(screen); + + /* Old screen deleted during screen load*/ + TEST_ASSERT_EQUAL(screen_delete_event_count, 1); + TEST_ASSERT_EQUAL(screen, lv_display_get_screen_active(lv_display_get_default())); + screen_delete_event_count = 0; + } + lv_obj_t * active_screen = lv_screen_active(); + TEST_ASSERT_NOT_NULL(active_screen); + lv_obj_delete(active_screen); +} + +static size_t display_screen_delete_screen_event_count = 0; +/* Deletes the display passed as a param on a display screen load event*/ +static void display_delete_screen_event_cb(lv_event_t * e) +{ + lv_obj_t * screen = lv_event_get_param(e); + TEST_ASSERT_NOT_NULL(screen); + lv_obj_delete(screen); + display_screen_delete_screen_event_count++; +} + +void test_screen_is_deleted_when_loaded_in_display_event(void) +{ + /* Check that LVGL correctly handles deleting the screens during display screen load events*/ + { + lv_display_t * display = lv_display_create(100, 100); + lv_display_set_default(display); + lv_obj_t * screen = lv_obj_create(NULL); + lv_display_add_event_cb(display, display_delete_screen_event_cb, LV_EVENT_SCREEN_UNLOAD_START, NULL); + + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOAD_START, NULL); + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOADED, NULL); + + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOAD_START, NULL); + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOADED, NULL); + lv_screen_load(screen); + + /* The display screen event was called only once*/ + TEST_ASSERT_EQUAL(display_screen_delete_screen_event_count, 1); + /* No unload events are sent to the previous screen as the old screen was deleted during the display event + * Both load events for new screen are sent */ + TEST_ASSERT_EQUAL(screen_event_count, 2); + + TEST_ASSERT_EQUAL(screen, lv_screen_active()); + + display_screen_delete_screen_event_count = screen_event_count = 0; + lv_display_delete(display); + } + + { + lv_display_t * display = lv_display_create(100, 100); + lv_display_set_default(display); + lv_obj_t * screen = lv_obj_create(NULL); + lv_display_add_event_cb(display, display_delete_screen_event_cb, LV_EVENT_SCREEN_LOAD_START, NULL); + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOAD_START, NULL); + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOADED, NULL); + + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOAD_START, NULL); + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOADED, NULL); + lv_screen_load(screen); + + /* The display screen event was called only once*/ + TEST_ASSERT_EQUAL(display_screen_delete_screen_event_count, 1); + /* Both unload events are sent to the previous screen + * No load event for new screen as the screen was deleted during the display event */ + TEST_ASSERT_EQUAL(screen_event_count, 2); + + TEST_ASSERT_NULL(lv_screen_active()); + + display_screen_delete_screen_event_count = screen_event_count = 0; + lv_display_delete(display); + } + + { + lv_display_t * display = lv_display_create(100, 100); + lv_display_set_default(display); + lv_obj_t * screen = lv_obj_create(NULL); + lv_display_add_event_cb(display, display_delete_screen_event_cb, LV_EVENT_SCREEN_LOADED, NULL); + + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOAD_START, NULL); + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOADED, NULL); + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOAD_START, NULL); + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOADED, NULL); + lv_screen_load(screen); + + /* The display screen event was called only once*/ + TEST_ASSERT_EQUAL(display_screen_delete_screen_event_count, 1); + /* Both unload events are sent to the previous screen + * loaded event is not sent to the new screen as the screen was deleted during the display event */ + TEST_ASSERT_EQUAL(screen_event_count, 3); + + TEST_ASSERT_NULL(lv_screen_active()); + + display_screen_delete_screen_event_count = screen_event_count = 0; + lv_display_delete(display); + } + { + lv_display_t * display = lv_display_create(100, 100); + lv_display_set_default(display); + lv_obj_t * screen = lv_obj_create(NULL); + lv_display_add_event_cb(display, display_delete_screen_event_cb, LV_EVENT_SCREEN_UNLOADED, NULL); + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOAD_START, NULL); + lv_obj_add_event_cb(lv_screen_active(), screen_event_cb, LV_EVENT_SCREEN_UNLOADED, NULL); + + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOAD_START, NULL); + lv_obj_add_event_cb(screen, screen_event_cb, LV_EVENT_SCREEN_LOADED, NULL); + lv_screen_load(screen); + + /* The display screen event was called only once*/ + TEST_ASSERT_EQUAL(display_screen_delete_screen_event_count, 1); + /* unloaded event is not sent to the previous screen as the screen is deleted during display event + * Both load events for new screen are sent */ + TEST_ASSERT_EQUAL(screen_event_count, 3); + + TEST_ASSERT_EQUAL(screen, lv_screen_active()); + + display_screen_delete_screen_event_count = screen_event_count = 0; + lv_display_delete(display); + } + +} + static void unloaded_event_cb(lv_event_t * e) { - lv_free(lv_event_get_target_obj(e)); + lv_obj_delete(lv_event_get_target_obj(e)); } static lv_obj_t * screen_create(void) @@ -145,7 +497,6 @@ static lv_obj_t * screen_create(void) void test_screen_mix_event_and_manual_creation(void) { - lv_obj_delete(lv_screen_active()); size_t free_mem = lv_test_get_free_mem(); lv_obj_t * screen = lv_obj_create(NULL); @@ -158,7 +509,6 @@ void test_screen_mix_event_and_manual_creation(void) /* Manually loading a screen with auto delete set to `true` should not lead to a double free */ lv_screen_load_anim(screen, LV_SCREEN_LOAD_ANIM_NONE, 0, 0, true); - lv_obj_delete(lv_screen_active()); TEST_ASSERT_MEM_LEAK_LESS_THAN(free_mem, 32);