fix: UI scale not applied on Windows; reset to 100% ignored on all platforms#2432
Conversation
…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>
There was a problem hiding this comment.
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>
|
Good call — swapped to |
|
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) |
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): 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>
…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>
Summary
main.cppwas reading the settings file from~/.config/AetherSDR/beforeQApplicationexists, butAppSettingson Windows writes to%APPDATA%/AetherSDR/viaQStandardPaths::ConfigLocation. The file was never found, soQT_SCALE_FACTORwas never set — UI Scale did nothing on Windows. Fixed by adding aQ_OS_WINbranch that reads from%APPDATA%.QT_SCALE_FACTORfrom the parent's environment. The old guardpct != 100skipped theqputenvcall, so the inherited value persisted. Fixed by always writingQT_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
🤖 Generated with Claude Code