fix(sweep): flush leaked ImGui popup so scroll survives the full UI sweep

The send-confirm surface renders via RenderSendConfirmPopup, which calls
ImGui::OpenPopup() every frame — but BeginOverlayDialog is a plain window,
so that popup is never consumed by a BeginPopup and is normally cleared
only when a mouse click triggers ImGui's click-to-dismiss. The headless
sweep never clicks and tears the surface down by just clearing its flag,
so the orphaned popup lingered on OpenPopupStack past the end of the sweep.

A stuck popup makes IsPopupOpen(AnyPopup) permanently true, which disables
the smooth-scroll wheel capture in draw_helpers::ApplySmoothScroll — so
after a sweep the mouse wheel stopped scrolling Settings / Explorer /
Console (the tabs that use ApplySmoothScroll; native-scroll tabs were
unaffected).

Flush any lingering popup (ClosePopupToLevel) right after each surface's
teardown, so it can't bleed into the next capture or survive the sweep.
Confirmed via instrumentation: only 'popup-send-confirm' leaked (stack=1,
once per skin); now flushed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-09 20:03:56 -05:00
parent 5db7941fbc
commit 8846a96e3d

View File

@@ -22,6 +22,9 @@
#include "util/platform.h" #include "util/platform.h"
#include "wallet/wallet_capabilities.h" #include "wallet/wallet_capabilities.h"
#include "imgui.h"
#include "imgui_internal.h" // ClosePopupToLevel / OpenPopupStack — flush stuck popups after teardown
#include <sodium.h> #include <sodium.h>
#include <cmath> #include <cmath>
@@ -465,6 +468,15 @@ void App::onScreenshotCaptured()
{ const SweepTarget& t = sweep_targets_[sweep_target_idx_]; if (t.teardown) t.teardown(*this); } { const SweepTarget& t = sweep_targets_[sweep_target_idx_]; if (t.teardown) t.teardown(*this); }
// Some surfaces leave an ImGui popup open (e.g. the send-confirm dialog calls OpenPopup but is
// torn down by just clearing its flag). The headless sweep never clicks, so ImGui's normal
// click-to-dismiss cleanup never runs and the popup lingers on the stack — which keeps
// IsPopupOpen(AnyPopup) true forever and disables the smooth-scroll wheel capture on
// Settings/Explorer/Console (draw_helpers::ApplySmoothScroll). Flush any lingering popup here so
// it can't bleed into the next surface's capture or survive past the sweep.
if (ImGuiContext* g = ImGui::GetCurrentContext(); g && g->OpenPopupStack.Size > 0)
ImGui::ClosePopupToLevel(0, false);
if (++sweep_target_idx_ >= static_cast<int>(sweep_targets_.size())) { if (++sweep_target_idx_ >= static_cast<int>(sweep_targets_.size())) {
sweep_target_idx_ = 0; sweep_target_idx_ = 0;
if (++sweep_skin_idx_ >= static_cast<int>(sweep_skins_.size())) { if (++sweep_skin_idx_ >= static_cast<int>(sweep_skins_.size())) {