[0.8.0] - 2026-06-30
Added
- Windows apps are now grouped on the Linux menu by their Start Menu folder (#581, thanks @Milliw). The Start Menu subfolder each app lives in (e.g.
Microsoft Office\Tools) is mirrored into nested sub-groups under the "winpodx" menu folder, just like Windows shows them. Renders on KDE Plasma, XFCE, Cinnamon, MATE and LXQt (the freedesktop.menumechanism); on GNOME the apps still appear but ungrouped (its overview is a flat grid). Top-level apps and apps with no folder stay directly under "winpodx". - Your
[pod] keyboardsetting now drives the FreeRDP session keyboard layout (#660, thanks @lsvab). The locale you pick for the Windows install (e.g.keyboard = "hu-HU") is now mapped to the matching Windows layout and passed to FreeRDP as/kbd:layout:0x…, so a non-US keyboard works in the RemoteApp window without hand-writingrdp.extra_flags. The defaulten-USis left untouched (FreeRDP keeps auto-detecting your host XKB layout, so users who never changed the setting aren't forced onto US), an explicit/kbdinrdp.extra_flagsalways wins, and an unmapped locale falls back to auto-detect. (Passing/kbdmanually viardp.extra_flagswas already unblocked in 0.7.4.)
Changed
- App discovery now surfaces only the apps your Windows Start Menu actually shows, by default (#581, thanks @Milliw). Previously every registered executable was scanned (registry App Paths, Chocolatey/Scoop shims, every UWP package) and dumped into the Linux menu, flooding it with uninstallers, helpers, and background processes. Discovery now defaults to Start-Menu-only: Start Menu shortcuts, Start-Menu-visible UWP apps (intersected with
Get-StartApps), and the OS essentials (File Explorer / Calculator / Settings). Turn the old behaviour back on withwinpodx config set desktop.full_app_scan trueor the Settings → "Discover all installed apps (not just Start Menu apps)" checkbox — useful for portable apps that have no Start Menu entry. Takes effect on the nextwinpodx app refresh. - Bundled rdprrap bumped 0.1.3 → 0.3.0. rdprrap (the multi-session RDP wrapper that lets each RemoteApp window get its own session) now derives its
termsrv.dllpatch sites dynamically — it disassembles each target function at runtime and encodes the patch bytes, instead of relying on hardcoded struct offsets / register choices / byte templates. This keeps multi-session working across Windows build-to-buildtermsrv.dllstruct-layout shifts. OEM version 27 → 28, so existing installs pick it up on the nextwinpodx guest sync/apply-fixes.
Fixed
- The GUI no longer crashes (SIGSEGV) from a layout-recursion when app names are long/CJK or the app list is empty (#553, thanks @hermitguo). Word-wrap
QLabels inside the resizable app-list scroll area (the empty-state panel, the launcher tiles) had a wrap width that tracked the viewport, so their height fed back into their width and re-enteredQBoxLayout::setGeometry→heightForWidthwithout bound on Qt 6.11 — a hard segfault on startup (empty list) or right after adding a CJK-named app. Those labels now have a constant (fixed) wrap width, breaking the feedback loop. - The Debloat / maintenance task window now closes itself when the operation finishes (#550, thanks @ismikes). The progress
BusyDialogwas closed withQTimer.singleShot(0, dlg.finish)from inside the worker — but a barethreading.Threadhas no Qt event loop, so that timer never fired and the window hung open until dismissed by hand (the v0.7.2 change only fixed when the worker starts, not the close).BusyDialog.finish()is now signal-based, so a cross-thread close queuesaccept()onto the GUI thread and the window closes on completion (Debloat, Grow Disk, Sync Guest, Apply Fixes). - "Refresh Apps" in the GUI no longer crashes (SIGSEGV) on completion. The discovery worker (a parentless, Python-owned
QObject) had two delete paths — its owndeleteLateron the worker thread and the Python ref-drop on the main thread. Qt6 emitsQThread.finishedbefore flushing the worker'sdeleteLater, so the cleanup slot dropped the last Python ref while that delete was still in flight, double-freeing the worker across threads (QObject::~QObjectsegfault). Now there is exactly one delete path (the ref-drop, afterthread.wait()confirms the worker thread is dead), the start guard also bails on a live thread ref (so a fast re-click can't drop a still-finishing worker), and the window joins in-flight worker threads on close. - The GUI no longer crashes (SIGABRT) when a background worker reads the display scale.
QGuiApplication.screens()is GUI-thread-only, but it was reachable from worker threads (the Info panel'sgather_info, etc.), which spammedQObject::setParent: ... different threadwarnings and could abort the whole app with__cxa_pure_virtualduring the worker's thread teardown — surfacing as the GUI dying on a refresh. The Qt scale probe now short-circuits toNoneoff the main thread and falls back to the subprocess/env detection. winpodx app refreshnow removes apps that are no longer discovered, not just adds new ones (#581). A refresh used to only ever add entries; discovered apps that vanished — an app uninstalled inside Windows, or everything dropped by the new Start-Menu-only default — lingered in the Linux menu until manually deleted. Refresh now prunes the stale discovered profiles (and their launchers) so the menu actually migrates to the current set. Manually-added apps (~/.local/share/winpodx/apps/) are never touched, and a failed/empty scan never wipes the menu.--win-isonow actually installs from your ISO instead of downloading Windows anyway (#647, thanks @ismikes). The local ISO was staged into<storage>/custom.isoafterwinpodx setuphad already runcompose up— so the container had booted and dockur had started its Microsoft download before the file existed (dockur looks forcustom.isothe moment it boots). The staging now happens insidewinpodx setup, after the storage path is resolved but before the container is (re)created, so dockur finds the ISO and installs from it. Also exposed aswinpodx setup --win-iso <path>.- The reverse-open listener now self-heals on app launch instead of staying dead until the next
pod start. Awinpodx pod stop/ tray Quit stops the listener (stop_listener()); while the pod kept running, nothing re-spawned the watcher, so "Open with → a Linux app" from Windows silently did nothing.ensure_ready(everywinpodx app run/ GUI launch) now idempotently ensures the listener is up whenreverse_openis enabled. Surfaced during the v0.7.4 smoke.
Contributors
Thanks to everyone who reported issues fixed in this release: @Milliw (#581), @lsvab (#660), @ismikes (#647, #550), @hermitguo (#553), and @liveifsh (#659).