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>
This commit is contained in:
Copilot
2026-03-26 12:53:06 +08:00
committed by GitHub
parent 358819bf2e
commit d9f0ef13aa

View File

@ -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<LvglGif>(image->image_dsc());