mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-08-17 23:55:04 +00:00
Fix for resuming windows when lvgl was stopped and started again
This commit is contained in:
parent
9487441b97
commit
a9340ae345
@ -210,12 +210,45 @@ error_t window_manager_start(void) {
|
|||||||
return ERROR_RESOURCE;
|
return ERROR_RESOURCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A previous stop() (see its comment) may have left window records behind for an app that's
|
||||||
|
// still running (as opposed to a real full shutdown, where every app has already removed its
|
||||||
|
// own window before this runs, leaving the list empty). Rebuild the topmost one now, exactly
|
||||||
|
// like window_manager_remove()'s resurface path does when a buried window becomes topmost -
|
||||||
|
// otherwise that app's task just sits blocked in its own event loop forever with no window
|
||||||
|
// and no way to know it needs to rebuild one.
|
||||||
|
WindowCreateWidgetsFn top_create_widgets = nullptr;
|
||||||
|
void* top_user_data = nullptr;
|
||||||
|
WindowId top_id = 0;
|
||||||
|
bool has_top = false;
|
||||||
|
|
||||||
mutex_lock(&s.mutex);
|
mutex_lock(&s.mutex);
|
||||||
s.real_root_widget = real_widget;
|
s.real_root_widget = real_widget;
|
||||||
s.content_root_widget = content_widget;
|
s.content_root_widget = content_widget;
|
||||||
s.started = true;
|
s.started = true;
|
||||||
|
if (!s.windows.empty()) {
|
||||||
|
top_create_widgets = s.windows.back().create_widgets;
|
||||||
|
top_user_data = s.windows.back().user_data;
|
||||||
|
top_id = s.windows.back().id;
|
||||||
|
has_top = true;
|
||||||
|
}
|
||||||
mutex_unlock(&s.mutex);
|
mutex_unlock(&s.mutex);
|
||||||
|
|
||||||
|
if (has_top) {
|
||||||
|
lv_obj_t* new_widget = build_window_widget(content_widget, top_create_widgets, top_user_data);
|
||||||
|
|
||||||
|
mutex_lock(&s.mutex);
|
||||||
|
bool still_topmost = !s.windows.empty() && s.windows.back().id == top_id;
|
||||||
|
if (still_topmost) {
|
||||||
|
s.top_widget = new_widget;
|
||||||
|
new_widget = nullptr; // consumed
|
||||||
|
}
|
||||||
|
mutex_unlock(&s.mutex);
|
||||||
|
|
||||||
|
// Something else changed the window stack while we were building (e.g. a concurrent
|
||||||
|
// remove()) - discard what we just made.
|
||||||
|
delete_widget(new_widget);
|
||||||
|
}
|
||||||
|
|
||||||
mutex_unlock(&s.lifecycle_mutex);
|
mutex_unlock(&s.lifecycle_mutex);
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
@ -234,8 +267,8 @@ error_t window_manager_stop(void) {
|
|||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
lv_obj_t* widget = s.real_root_widget;
|
lv_obj_t* widget = s.real_root_widget;
|
||||||
// Claim every window's waiter before clearing - normally at most the topmost window's is
|
// Claim every window's waiter before tearing down - normally at most the topmost window's
|
||||||
// ever set, but every window is being torn down here, so every one is checked.
|
// is ever set, but every window's widget is being torn down here, so every one is checked.
|
||||||
std::vector<WindowWaitSignal*> waiters;
|
std::vector<WindowWaitSignal*> waiters;
|
||||||
for (auto& window : s.windows) {
|
for (auto& window : s.windows) {
|
||||||
if (auto* signal = claim_waiter_locked(window); signal != nullptr) {
|
if (auto* signal = claim_waiter_locked(window); signal != nullptr) {
|
||||||
@ -245,7 +278,15 @@ error_t window_manager_stop(void) {
|
|||||||
s.real_root_widget = nullptr;
|
s.real_root_widget = nullptr;
|
||||||
s.content_root_widget = nullptr;
|
s.content_root_widget = nullptr;
|
||||||
s.top_widget = nullptr;
|
s.top_widget = nullptr;
|
||||||
s.windows.clear();
|
// Deliberately NOT s.windows.clear(): this only tears down the LVGL widget tree, not the
|
||||||
|
// window records themselves. A real full shutdown (every app already removed its own window
|
||||||
|
// via window_manager_remove() before this runs) leaves the list empty anyway, so this is a
|
||||||
|
// no-op there. But a caller can also stop()/start() this module on its own, temporarily,
|
||||||
|
// while apps keep running underneath (e.g. an app borrowing the display/touch hardware
|
||||||
|
// directly) - those apps' tasks are still alive, blocked in their own event loops, with no
|
||||||
|
// way to know they need to call window_manager_create() again. Keeping the records lets
|
||||||
|
// window_manager_start() rebuild the topmost one automatically instead of leaving that app
|
||||||
|
// stuck with no window forever.
|
||||||
s.started = false;
|
s.started = false;
|
||||||
mutex_unlock(&s.mutex);
|
mutex_unlock(&s.mutex);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user