Skip to content

fix: UI scale not applied on Windows; reset to 100% ignored on all platforms#2432

Merged
ten9876 merged 2 commits into
aethersdr:mainfrom
chibondking:fix/ui-scale-win-env
May 7, 2026
Merged

fix: UI scale not applied on Windows; reset to 100% ignored on all platforms#2432
ten9876 merged 2 commits into
aethersdr:mainfrom
chibondking:fix/ui-scale-win-env

Conversation

@chibondking

Copy link
Copy Markdown
Collaborator

Summary

  • Windows (broken entirely): main.cpp was reading the settings file from ~/.config/AetherSDR/ before QApplication exists, but AppSettings on Windows writes to %APPDATA%/AetherSDR/ via QStandardPaths::ConfigLocation. The file was never found, so QT_SCALE_FACTOR was never set — UI Scale did nothing on Windows. Fixed by adding a Q_OS_WIN branch that reads from %APPDATA%.
  • All platforms (reset to 100% silently ignored): When restarting after resetting scale to 100%, the child process inherits QT_SCALE_FACTOR from the parent's environment. The old guard pct != 100 skipped the qputenv call, so the inherited value persisted. Fixed by always writing QT_SCALE_FACTOR (including "1.00") to guarantee the inherited value is overridden.

Out of scope

macOS Retina compounding (QT_SCALE_FACTOR × devicePixelRatio) is a known follow-on issue — at non-100% scales on Retina Macs the factor doubles up. Tracked separately.

Test plan

  • Windows: set UI Scale to 125%, restart — window should be visibly larger; reset to 100%, restart — should return to normal size
  • Linux: change scale, restart — confirm scale applies; reset to 100% from a scaled session, restart — confirm it returns to 1x
  • macOS: basic smoke — scale changes should apply (Retina compounding is a known separate issue, not a regression)

🤖 Generated with Claude Code

…atforms

Two bugs in the pre-QApplication QT_SCALE_FACTOR setup:

1. Windows path mismatch: main.cpp was reading from ~/.config/AetherSDR/
   but AppSettings (via QStandardPaths::ConfigLocation) writes to %APPDATA%/
   AetherSDR/ on Windows. The settings file was never found, so QT_SCALE_FACTOR
   was never set — UI Scale did nothing on Windows. Fix adds a Q_OS_WIN branch
   that reads from %APPDATA% to match.

2. Inherited env not overridden at 100%: when a user restarted after resetting
   scale to 100%, the child process inherited QT_SCALE_FACTOR from the parent.
   The old guard (pct != 100) skipped the qputenv call, so the inherited value
   silently persisted. Fix always writes QT_SCALE_FACTOR (including "1.00") to
   guarantee the inherited value is overridden.

macOS Retina compounding (QT_SCALE_FACTOR × devicePixelRatio) is a separate
issue, tracked for follow-on investigation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@aethersdr-agent aethersdr-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @chibondking — clean, focused fix and a particularly clear writeup of both bugs.

The Windows path matches what AppSettings::AppSettings() actually produces: QStandardPaths::ConfigLocation resolves to %APPDATA% on Windows (no org/app appended at this level), then +/AetherSDR + /AetherSDR.settings gives the same path you read here. The reset-to-100% logic is also right — restart inherits the parent's QT_SCALE_FACTOR, so unconditionally writing it (even at 1.00) is the correct guarantee.

One concern worth addressing before merge:

QString::fromLocal8Bit(qgetenv("APPDATA")) will mangle the path for Windows users whose profile directory contains non-ASCII characters (Cyrillic, CJK, accented Latin, etc.) — fairly common for international users. Qt has a wide-char-safe equivalent that returns QString directly:

QString settingsPath = QDir::fromNativeSeparators(qEnvironmentVariable("APPDATA"))
                       + "/AetherSDR/AetherSDR.settings";

Same result on ASCII-only paths, correct on Unicode paths, and a bit shorter. Worth swapping in to avoid a "scale only broken for users with é in their username" follow-up.

Otherwise this looks good — happy to see the macOS Retina compounding tracked as a separate item rather than scope-crept in.

QString::fromLocal8Bit(qgetenv("APPDATA")) mangles paths containing
non-ASCII characters (Cyrillic, CJK, accented Latin), breaking UI Scale
for international users whose profile directories contain such chars.

qEnvironmentVariable() returns QString directly via the Win32 wide-char
API, handling all Unicode paths correctly.

Addresses review feedback on aethersdr#2432.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@chibondking

Copy link
Copy Markdown
Collaborator Author

Good call — swapped to qEnvironmentVariable("APPDATA") in 65aef71. Same result on ASCII paths, handles Cyrillic/CJK/accented Latin correctly.

@ten9876 ten9876 merged commit 27bbf0d into aethersdr:main May 7, 2026
5 checks passed
@ten9876

ten9876 commented May 7, 2026

Copy link
Copy Markdown
Collaborator

Claude here — two bugs in one tiny patch, both with clear root causes. The Windows pre-Qt path mismatch (Linux ~/.config vs Windows %APPDATA%) is the kind of bug that's easy to land and hard to spot without the Windows builder catching it — which incidentally is exactly the CI gap I just filed at #2439. The always-set fix on the inherited-env case is a really good catch too; the old != 100 guard was a perfectly reasonable optimisation that turned into a silent footgun on restart. Merged.

73, Jeremy KK7GWY & Claude (AI dev partner)

ten9876 pushed a commit to chibondking/AetherSDR that referenced this pull request May 7, 2026
QProcess::startDetached(applicationFilePath()) launches the raw binary
inside the .app bundle, bypassing Launch Services. On macOS this causes
the relaunched instance to appear as a separate dock entry and lose the
correct activation policy; on notarized or sandboxed builds it can fail
entirely.

Fix adds a Q_OS_MAC branch in applyUiScale() that walks up three path
components from the binary (Foo.app/Contents/MacOS/Foo → Foo.app) and
relaunches via 'open -n <bundle>'. Falls back to direct exec when not
running from a bundle (dev/CI builds).

The previously-noted "Retina DPR compounding" concern was a misdiagnosis:
QT_SCALE_FACTOR operates on Qt's logical pixel layer, which is below the
Retina backing scale factor — there is no compounding visible to the user.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ten9876 pushed a commit that referenced this pull request May 7, 2026
* fix(macos): relaunch via 'open -n' on UI scale restart (#2432)

QProcess::startDetached(applicationFilePath()) launches the raw binary
inside the .app bundle, bypassing Launch Services. On macOS this causes
the relaunched instance to appear as a separate dock entry and lose the
correct activation policy; on notarized or sandboxed builds it can fail
entirely.

Fix adds a Q_OS_MAC branch in applyUiScale() that walks up three path
components from the binary (Foo.app/Contents/MacOS/Foo → Foo.app) and
relaunches via 'open -n <bundle>'. Falls back to direct exec when not
running from a bundle (dev/CI builds).

The previously-noted "Retina DPR compounding" concern was a misdiagnosis:
QT_SCALE_FACTOR operates on Qt's logical pixel layer, which is below the
Retina backing scale factor — there is no compounding visible to the user.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(macos): forward CLI args through 'open --args' on scale restart

'open -n <bundle>' was silently dropping any command-line arguments
passed to the original process. Forward them via 'open --args' to keep
parity with the Linux/Windows direct-exec path.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
ten9876 pushed a commit that referenced this pull request May 7, 2026
…2443)

* fix(windows): read settings from %LOCALAPPDATA%, not %APPDATA%

Qt 6 changed QStandardPaths::ConfigLocation on Windows to map to
%LOCALAPPDATA% (AppData\Local) instead of %APPDATA% (AppData\Roaming)
as it did in Qt 5. The previous fix used APPDATA, so the pre-QApplication
settings read was still finding the wrong directory — QT_SCALE_FACTOR
was never set and UI Scale remained broken on Windows.

Fixes the remaining Windows regression after #2432.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(windows): use GenericConfigLocation for settings path, migrate old triple-nested location

Qt 6's ConfigLocation on Windows resolves to AppConfigLocation
(%LOCALAPPDATA%/OrgName/AppName). AppSettings was appending "/AetherSDR"
on top of that, producing a triple-nested path:
  %LOCALAPPDATA%\AetherSDR\AetherSDR\AetherSDR\AetherSDR.settings

main.cpp read from %LOCALAPPDATA%\AetherSDR\AetherSDR.settings (two
levels up), never found UiScalePercent, and never set QT_SCALE_FACTOR —
so UI scaling had no effect on Windows despite the setting being saved.

Switch AppSettings to GenericConfigLocation (%LOCALAPPDATA% on Windows,
~/.config on Linux/macOS — no org/app suffix), matching the log-dir
path already used in main.cpp. Add a one-time migration that moves the
settings file from the old triple-nested path on first launch so
existing users don't lose their settings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(settings): extend path migration to macOS (same triple-nesting bug)

Qt 6 ConfigLocation on macOS also resolves to AppConfigLocation
(~/Library/Preferences/AetherSDR/AetherSDR), producing the same
triple-nested path as Windows. Widen the #ifdef to cover both platforms
so existing macOS settings are migrated instead of silently abandoned.

Requested in PR review by ten9876.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants