mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-13 09:39:33 +01:00
UI: Handle a caller finishing itself from dialogFinished()
That set dialogFinished_ to the caller, which processFinishDialog() then deleted while it was still in the stack, leaking the popup. Take the pointer out first and loop. Nothing does this now (MemStickScreen and DevMenuScreen work around it), but it's easy to do by accident. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a7229ce1c8
commit
24d8955531
1 file changed
+28
-25
+28
-25
@@ -414,34 +414,37 @@ Screen *ScreenManager::dialogParent(const Screen *dialog) const {
|
||||
}
|
||||
|
||||
void ScreenManager::processFinishDialog() {
|
||||
if (dialogFinished_) {
|
||||
{
|
||||
// Another dialog may have been pushed before the render, so search for it.
|
||||
Screen *caller = dialogParent(dialogFinished_);
|
||||
bool erased = false;
|
||||
for (size_t i = 0; i < stack_.size(); ++i) {
|
||||
if (stack_[i].screen == dialogFinished_) {
|
||||
stack_[i].screen->focusChanged(ScreenFocusChange::FOCUS_LOST_TOP);
|
||||
stack_.erase(stack_.begin() + i);
|
||||
erased = true;
|
||||
}
|
||||
}
|
||||
// The caller's dialogFinished() can finish the caller too, which sets dialogFinished_ again. So take it
|
||||
// out first (or we'd delete the caller while it's still in the stack) and loop to process the new one.
|
||||
while (dialogFinished_) {
|
||||
const Screen *finished = dialogFinished_;
|
||||
const DialogResult result = dialogResult_;
|
||||
dialogFinished_ = nullptr;
|
||||
|
||||
if (erased && !stack_.empty()) {
|
||||
stack_.back().screen->focusChanged(ScreenFocusChange::FOCUS_BECAME_TOP);
|
||||
}
|
||||
|
||||
if (!caller) {
|
||||
ERROR_LOG(Log::UI, "ERROR: no top screen when finishing dialog");
|
||||
} else if (caller != topScreen()) {
|
||||
// The caller may get confused if we call dialogFinished() now.
|
||||
WARN_LOG(Log::UI, "Skipping non-top dialog when finishing dialog.");
|
||||
} else {
|
||||
caller->dialogFinished(dialogFinished_, dialogResult_);
|
||||
// Another dialog may have been pushed before the render, so search for it.
|
||||
Screen *caller = dialogParent(finished);
|
||||
bool erased = false;
|
||||
for (size_t i = 0; i < stack_.size(); ++i) {
|
||||
if (stack_[i].screen == finished) {
|
||||
stack_[i].screen->focusChanged(ScreenFocusChange::FOCUS_LOST_TOP);
|
||||
stack_.erase(stack_.begin() + i);
|
||||
erased = true;
|
||||
}
|
||||
}
|
||||
delete dialogFinished_;
|
||||
dialogFinished_ = nullptr;
|
||||
|
||||
if (erased && !stack_.empty()) {
|
||||
stack_.back().screen->focusChanged(ScreenFocusChange::FOCUS_BECAME_TOP);
|
||||
}
|
||||
|
||||
if (!caller) {
|
||||
ERROR_LOG(Log::UI, "ERROR: no top screen when finishing dialog");
|
||||
} else if (caller != topScreen()) {
|
||||
// The caller may get confused if we call dialogFinished() now.
|
||||
WARN_LOG(Log::UI, "Skipping non-top dialog when finishing dialog.");
|
||||
} else {
|
||||
caller->dialogFinished(finished, result);
|
||||
}
|
||||
delete finished;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user