fix(ui): tapping the accent popup after its text box closed crashed (#574)
The accent popup keeps a pointer to the text box it edits, and about 25 separate paths close the popup by hand. A path that deleted the text box without closing it (e.g. a form closing after its send) left the popup on screen pointing at freed memory; tapping an accent letter then ran lv_textarea_del_char on it. That is the beta_85 T-Deck crash in #574 (loopTask LoadProhibited at 0x3, accentBoxCellCb -> lv_textarea_del_char), matched against the release image. Tie the popup to its text box with an LV_EVENT_DELETE hook that clears the pointer and hides the popup (hide only: in a layer clean the popup may be deleted in the same pass). The cell handler also checks the text box is still valid, and accentBoxHide no longer deletes a popup that something else already removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
edf465ab19
commit
b408487dec
1 file changed
+17
-1
+17
-1
@@ -8091,7 +8091,8 @@ static const AccentSet* accentSetFor(char c) {
|
||||
return nullptr;
|
||||
}
|
||||
static void accentBoxHide() {
|
||||
if (s_accbox) { lv_obj_del(s_accbox); s_accbox = nullptr; }
|
||||
// is_valid: a screen/layer clean can delete the box without passing through here.
|
||||
if (s_accbox) { if (lv_obj_is_valid(s_accbox)) lv_obj_del(s_accbox); s_accbox = nullptr; }
|
||||
s_accbox_ta = nullptr;
|
||||
#if defined(TLORA_PAGER) || defined(HAS_M9_KEYBOARD)
|
||||
s_accentnav_active = false;
|
||||
@@ -8117,10 +8118,23 @@ static void accentNavConfirm() {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// The box outlives its text field whenever the field is deleted by a path that
|
||||
// doesn't call accentBoxHide() (a form closing after its send, a panel rebuild).
|
||||
// Tapping a cell then edited freed memory: the beta_85 T-Deck crash in #574
|
||||
// (loopTask LoadProhibited, accentBoxCellCb -> lv_textarea_del_char). Tie the box
|
||||
// to the field instead: when the field goes, drop the pointer and hide the box.
|
||||
// Only hide here, never delete: when a whole layer is being cleaned the box may be
|
||||
// deleted in the same pass, and a second delete would be its own crash.
|
||||
static void accentBoxTaDeleteCb(lv_event_t* e) {
|
||||
if (lv_event_get_target(e) != s_accbox_ta) return;
|
||||
s_accbox_ta = nullptr;
|
||||
if (s_accbox && lv_obj_is_valid(s_accbox)) lv_obj_add_flag(s_accbox, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
static void accentBoxCellCb(lv_event_t* e) {
|
||||
if (lv_event_get_code(e) != LV_EVENT_CLICKED) return;
|
||||
const char* variant = static_cast<const char*>(lv_event_get_user_data(e));
|
||||
lv_obj_t* ta = s_accbox_ta;
|
||||
if (ta && !lv_obj_is_valid(ta)) ta = nullptr; // belt and braces for the hook above
|
||||
if (ta && variant) {
|
||||
lv_textarea_del_char(ta); // remove the just-typed base letter
|
||||
lv_textarea_add_text(ta, variant); // insert the chosen accent
|
||||
@@ -8139,6 +8153,8 @@ static void accentBoxMaybeShow() {
|
||||
const AccentSet* set = accentSetFor(last[0]);
|
||||
if (!set) return;
|
||||
s_accbox_ta = ta;
|
||||
lv_obj_remove_event_cb(ta, accentBoxTaDeleteCb); // at most one hook per field
|
||||
lv_obj_add_event_cb(ta, accentBoxTaDeleteCb, LV_EVENT_DELETE, nullptr);
|
||||
#if defined(TLORA_PAGER) || defined(HAS_M9_KEYBOARD)
|
||||
s_accentnav_active = false; // fresh box -> Fn+Space (re-)arms nav mode
|
||||
s_accentnav_idx = 0;
|
||||
|
||||
Reference in new issue
Block a user