-
-
Notifications
You must be signed in to change notification settings - Fork 118
fix(gui): reopen the Aetherial strip after minimize — Principle XI. #5366
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
ten9876
merged 3 commits into
aethersdr:main
from
crypticpy:pr/5365-aetherial-strip-minimize-lockout
Sep 10, 2026
Merged
Changes from 2 commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| #include "gui/WindowShowState.h" | ||
|
|
||
| #include <QWidget> | ||
|
|
||
| namespace AetherSDR { | ||
|
|
||
| bool windowIsShowing(const QWidget* w) | ||
| { | ||
| return w && w->isVisible() && !w->isMinimized(); | ||
| } | ||
|
|
||
| void showAndRaiseWindow(QWidget* w) | ||
| { | ||
| if (!w) | ||
| return; | ||
|
ten9876 marked this conversation as resolved.
Outdated
ten9876 marked this conversation as resolved.
Outdated
|
||
| // Clear ONLY the minimized bit. showNormal() would also clear Maximized | ||
| // and FullScreen, so a strip that was maximized, then minimized, would come | ||
| // back at normal size (#3918). On a hidden widget this is a pending state | ||
| // that show() applies; on a visible one it takes effect immediately and | ||
| // show() is a no-op. | ||
| w->setWindowState(w->windowState() & ~Qt::WindowMinimized); | ||
| w->show(); | ||
| w->raise(); | ||
| w->activateWindow(); | ||
| } | ||
|
|
||
| } // namespace AetherSDR | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| #pragma once | ||
|
|
||
| class QWidget; | ||
|
|
||
| namespace AetherSDR { | ||
|
|
||
| // Window show-state helpers for press-to-open / press-again-to-close buttons. | ||
| // | ||
| // QWidget::isVisible() stays TRUE for a minimized window, and QWidget::show() | ||
| // on a minimized window restores it to its saved state — which is minimized. | ||
| // A toggle written as `if (w->isVisible()) w->hide(); else w->show();` is | ||
| // therefore unrecoverable once the window is minimized: the first press hides | ||
| // it, and the second press "shows" it straight back into the taskbar/Dock. | ||
| // Both behaviours are pinned by window_show_state_test. | ||
|
|
||
| // True when w is actually on screen for the user — visible AND not minimized. | ||
| [[nodiscard]] bool windowIsShowing(const QWidget* w); | ||
|
|
||
| // Bring w to the front, un-minimizing it first if needed. Only the Minimized | ||
| // bit is cleared, so a Maximized or FullScreen window keeps that state — both | ||
| // when it is merely raised and when it is restored from the taskbar/Dock | ||
| // (#3918). showNormal() would drop it in either case. | ||
| void showAndRaiseWindow(QWidget* w); | ||
|
|
||
| } // namespace AetherSDR |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| // Regression test for the Aetherial Audio Channel Strip toggle, which could | ||
| // not reopen the window once it had been minimized. | ||
| // | ||
| // Two Qt behaviours combine into the bug, and both are pinned here against a | ||
| // REAL QWidget rather than asserted from memory: | ||
| // | ||
| // 1. QWidget::isVisible() stays TRUE while a window is minimized. A toggle | ||
| // written `if (w->isVisible()) w->hide(); else w->show();` therefore | ||
| // treats a minimized window as "showing" and hides it. | ||
| // 2. QWidget::show() on a minimized window restores its SAVED state, which | ||
| // is still minimized — so the follow-up press does not recover it either. | ||
| // | ||
| // windowIsShowing() fixes (1) and showAndRaiseWindow() fixes (2), while the | ||
| // isMinimized() guard inside it keeps a maximized window maximized (#3918). | ||
|
ten9876 marked this conversation as resolved.
Outdated
|
||
| // | ||
| // Runs on the offscreen platform, where both behaviours reproduce. | ||
|
|
||
| #include "gui/WindowShowState.h" | ||
|
|
||
| #include <QApplication> | ||
| #include <QWidget> | ||
|
|
||
| #include <cstdio> | ||
|
|
||
| using AetherSDR::showAndRaiseWindow; | ||
| using AetherSDR::windowIsShowing; | ||
|
|
||
| namespace { | ||
|
|
||
| int g_failures = 0; | ||
|
|
||
| void report(const char* name, bool ok) | ||
| { | ||
| std::printf("%s %s\n", ok ? "[ OK ]" : "[FAIL]", name); | ||
| if (!ok) { | ||
| ++g_failures; | ||
| } | ||
| } | ||
|
|
||
| // The toggle exactly as MainWindow::toggleAetherialStrip() runs it. | ||
| void toggle(QWidget* w) | ||
| { | ||
| if (windowIsShowing(w)) | ||
| w->hide(); | ||
| else | ||
| showAndRaiseWindow(w); | ||
| } | ||
|
|
||
| } // namespace | ||
|
|
||
| int main(int argc, char** argv) | ||
| { | ||
| QApplication app(argc, argv); | ||
|
|
||
| // --- Case 1: null is never "showing", and raising it must not crash. | ||
| report("windowIsShowing(nullptr) is false", !windowIsShowing(nullptr)); | ||
| showAndRaiseWindow(nullptr); | ||
| report("showAndRaiseWindow(nullptr) is a no-op", true); | ||
|
|
||
| QWidget w; | ||
| w.resize(320, 240); | ||
|
|
||
| // --- Case 2: a hidden window is not showing; the toggle opens it. | ||
| report("hidden window is not showing", !windowIsShowing(&w)); | ||
| toggle(&w); | ||
| app.processEvents(); | ||
| report("toggle opens a hidden window", windowIsShowing(&w)); | ||
|
|
||
| // --- Case 3: the toggle closes an ordinary open window. | ||
| toggle(&w); | ||
| app.processEvents(); | ||
| report("toggle hides a showing window", !w.isVisible()); | ||
|
|
||
| // --- Case 4: THE BUG. Qt reports a minimized window as visible, so the | ||
| // old bare isVisible() check would take the hide() branch here. | ||
| w.show(); | ||
| app.processEvents(); | ||
| w.showMinimized(); | ||
| app.processEvents(); | ||
| report("Qt: minimized window still reports isVisible()", w.isVisible()); | ||
| report("Qt: minimized window reports isMinimized()", w.isMinimized()); | ||
| report("windowIsShowing() treats minimized as not showing", | ||
| !windowIsShowing(&w)); | ||
|
|
||
| // --- Case 5: why the second press never recovered it either — show() on a | ||
| // minimized window leaves it minimized. | ||
| w.show(); | ||
| app.processEvents(); | ||
| report("Qt: show() does not un-minimize", w.isMinimized()); | ||
|
|
||
| // --- Case 6: the toggle restores a minimized window in ONE press. | ||
| toggle(&w); | ||
| app.processEvents(); | ||
| report("toggle restores a minimized window", windowIsShowing(&w)); | ||
| report("restored window is no longer minimized", !w.isMinimized()); | ||
|
|
||
| // --- Case 7: the isMinimized() guard — raising a maximized window must | ||
| // not drop it out of maximized state (#3918). | ||
| w.showMaximized(); | ||
| app.processEvents(); | ||
| if (w.isMaximized()) { | ||
|
ten9876 marked this conversation as resolved.
|
||
| showAndRaiseWindow(&w); | ||
| app.processEvents(); | ||
| report("showAndRaiseWindow keeps a maximized window maximized", | ||
| w.isMaximized()); | ||
|
|
||
| // --- Case 8: the reopen path itself must not drop maximize. This is | ||
| // what showNormal() got wrong: it clears Minimized AND Maximized, so a | ||
| // maximized strip that was minimized came back at normal size. | ||
| w.showMinimized(); | ||
| app.processEvents(); | ||
| report("Qt: minimizing keeps the Maximized bit alongside Minimized", | ||
| w.isMinimized() && (w.windowState() & Qt::WindowMaximized)); | ||
| toggle(&w); | ||
| app.processEvents(); | ||
| report("toggle restores a minimized-from-maximized window", | ||
| windowIsShowing(&w)); | ||
| report("restored window is still maximized", w.isMaximized()); | ||
| } else { | ||
| // Some platforms decline to maximize; the guard is still pinned by | ||
| // case 6, so skip rather than fail on a platform quirk. | ||
| std::printf("[SKIP] maximized state unavailable on this platform\n"); | ||
|
ten9876 marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| if (g_failures == 0) { | ||
| std::printf("All window show-state tests passed.\n"); | ||
| } | ||
| return g_failures == 0 ? 0 : 1; | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.