From d9f0ef13aa7501be50fca54db9d175151ba67867 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 12:53:06 +0800 Subject: [PATCH] Fix GIF emoji flickering by merging lock scopes in SetEmotion() (#1880) * Initial plan * Fix GIF emoji flickering by merging lock scopes in SetEmotion() Remove the separate first lock scope that hid emoji_image_ before destroying gif_controller_ (added by PR #1848). Instead, move the gif_controller_ cleanup into each lock scope where new content is set, so destruction and creation happen atomically. This prevents both the original race condition crash AND the visible flickering. Co-authored-by: 78 <4488133+78@users.noreply.github.com> Agent-Logs-Url: https://github.com/78/xiaozhi-esp32/sessions/2dd0ff3a-4556-47a6-8d40-a30e18c01923 --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: 78 <4488133+78@users.noreply.github.com> --- main/display/lcd_display.cc | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/main/display/lcd_display.cc b/main/display/lcd_display.cc index 9d110e0..be236bb 100644 --- a/main/display/lcd_display.cc +++ b/main/display/lcd_display.cc @@ -1075,18 +1075,6 @@ void LcdDisplay::SetEmotion(const char* emotion) { if (!setup_ui_called_) { ESP_LOGW(TAG, "SetEmotion('%s') called before SetupUI() - emotion will not be displayed!", emotion); } - // Stop any running GIF animation - if (gif_controller_) { - DisplayLockGuard lock(this); - gif_controller_->Stop(); - // Hide image before destroying GIF controller to prevent LVGL from - // accessing freed image data during rendering between lock scopes - if (emoji_image_) { - lv_obj_add_flag(emoji_image_, LV_OBJ_FLAG_HIDDEN); - } - gif_controller_.reset(); - } - if (emoji_image_ == nullptr) { if (setup_ui_called_) { ESP_LOGW(TAG, "SetEmotion('%s') failed: emoji_image_ is nullptr (SetupUI() was called but emoji image not created)", emotion); @@ -1100,6 +1088,10 @@ void LcdDisplay::SetEmotion(const char* emotion) { const char* utf8 = font_awesome_get_utf8(emotion); if (utf8 != nullptr && emoji_label_ != nullptr) { DisplayLockGuard lock(this); + if (gif_controller_) { + gif_controller_->Stop(); + gif_controller_.reset(); + } lv_label_set_text(emoji_label_, utf8); lv_obj_add_flag(emoji_image_, LV_OBJ_FLAG_HIDDEN); lv_obj_remove_flag(emoji_label_, LV_OBJ_FLAG_HIDDEN); @@ -1108,6 +1100,12 @@ void LcdDisplay::SetEmotion(const char* emotion) { } DisplayLockGuard lock(this); + // Stop any running GIF animation in the same lock scope as setting new image + // to prevent LVGL from accessing freed image data between operations + if (gif_controller_) { + gif_controller_->Stop(); + gif_controller_.reset(); + } if (image->IsGif()) { // Create new GIF controller gif_controller_ = std::make_unique(image->image_dsc());