From 0754544e27284ffe76304f9c7bdeb8b099cfd8cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 12 Oct 2026 14:32:38 +0200 Subject: [PATCH] UI: Don't recreate a screen's views while a popup is on top of it Popups are transparent, so the screen under one still renders, and render() ran DoRecreateViews(). A RecreateViews() on that screen (a resize or rotation on DisplayLayoutScreen or TouchControlLayoutScreen, MainScreen on RECENT_FILES_CHANGED from the recent-files thread, the achievements login finishing) then deleted the choice that opened the popup. Closing the popup wrote through it and called its handlers. Leave the old views in place until the screen is back on top, where update() recreates them. Co-Authored-By: Claude Opus 5.5 --- Common/UI/ScreenManager.cpp | 9 +++++++++ Common/UI/ScreenManager.h | 2 ++ Common/UI/UIScreen.cpp | 6 +++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Common/UI/ScreenManager.cpp b/Common/UI/ScreenManager.cpp index 7f63bb7a91..3987a7594d 100644 --- a/Common/UI/ScreenManager.cpp +++ b/Common/UI/ScreenManager.cpp @@ -393,6 +393,15 @@ void ScreenManager::finishDialog(Screen *dialog, DialogResult result) { dialogResult_ = result; } +bool ScreenManager::HasScreenAbove(const Screen *screen) const { + for (size_t i = 0; i + 1 < stack_.size(); ++i) { + if (stack_[i].screen == screen) { + return true; + } + } + return false; +} + Screen *ScreenManager::dialogParent(const Screen *dialog) const { for (size_t i = 1; i < stack_.size(); ++i) { if (stack_[i].screen == dialog) { diff --git a/Common/UI/ScreenManager.h b/Common/UI/ScreenManager.h index bd02dce94b..e815c834c1 100644 --- a/Common/UI/ScreenManager.h +++ b/Common/UI/ScreenManager.h @@ -64,6 +64,8 @@ public: // Pops the dialog away. void finishDialog(Screen *dialog, DialogResult result = DR_OK); Screen *dialogParent(const Screen *dialog) const; + // True if the screen is in the stack, with something (like a popup) on top of it. + bool HasScreenAbove(const Screen *screen) const; void sendMessage(UIMessage message, const char *value); diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index d29d2dead9..bf77236647 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -128,7 +128,11 @@ Bounds UIScreen::GetLayoutBounds(UIContext &dc) const { } ScreenRenderFlags UIScreen::render(ScreenRenderMode mode) { - DoRecreateViews(); + // A screen rendered under a popup must keep its views: the popup's callbacks point into them (the choice + // that opened it, the value it writes to). update() recreates them once the screen is on top again. + if (!root_ || !screenManager()->HasScreenAbove(this)) { + DoRecreateViews(); + } UIContext &uiContext = *screenManager()->getUIContext(); if (root_) {