Title: Fix 35 upstream bugs: volume flyout, mixer, media flyout, visualizer, taskbar widget, startup - #1108
Open
frans15-2006 wants to merge 38 commits into
Open
Title: Fix 35 upstream bugs: volume flyout, mixer, media flyout, visualizer, taskbar widget, startup#1108frans15-2006 wants to merge 38 commits into
frans15-2006 wants to merge 38 commits into
Conversation
SongImage ImageBrush used Stretch=UniformToFill inside the fixed 78x78 frame, center-cropping rectangular covers. Use Uniform so the full artwork is always visible (letterboxed). Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Any duplicate launch signals the running instance to open its settings window, so duplicate autostart entries/boot storms surface a window on every login. Gate the signal: when the first instance started <30s ago, the duplicate exits silently. Interactive re-launches keep opening settings. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…exclusive mode) pauseOtherMediaSessionsIfNeeded ran on every media-property change, so thumbnail refreshes/progress updates re-paused the other app even when playback focus never moved. Gate the metadata path on genuine new-track/status boundaries (state transitions still pause via CurrentSession_OnPlaybackStateChanged). Harden PauseOtherSessions fan-out (null session guard + per-session catch; it is fire-and-forget). Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…tion change - Handle WM_DISPLAYCHANGE (was ignored): immediately drop cached tray/XAML handles, poisoned automation lookups and monitor id, then re-resolve the taskbar/position instead of running up to 1.5s stale. WindowProc is now an instance method to reach instance state. - Invalid DPI no longer keeps the stale hit-test region: reset to empty (invisible + click-through) instead of leaving a ghost that eats clicks. - Sanitize region rects (NaN/infinity/overflow/non-positive) to Empty so a garbage rect from transient geometry can never swallow taskbar input. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Process.MainModule throws Access Denied for admin-level processes seen from a non-elevated caller, so sessions fell back to 'Unknown' with no icon. Resolve exe paths via OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION) + QueryFullProcessImageName (granted cross-integrity), then read FileVersionInfo/icons from the file itself: new MediaPlayerData.TryGetProcessPath shared by the mixer icon lookup and the session display-name fallback chain (FileDescription -> exe name -> window title/ProcessName). Process handles now disposed. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…it audio OnDataAvailable assumed 16-bit int or 32-bit float and treated interleaved channels as mono samples: 24-bit streams (typical of spatial/Atmos pipelines) decoded as permanent silence, and 6/8-channel streams fed the FFT at multiples of the real rate. Decode per WaveFormat (8/16/24/32-int, 32-float via Encoding) and downmix each frame to mono, with a non-finite guard. Stereo behavior is equivalent (L/R average vs alternating). Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Explorer recreates the OSD XAML island (new HWND), so the stored hidden handle is dead and ShowFlyout's Zero-gate never re-hides. On TaskbarCreated recovery (post-stabilization), reset the handle and re-hide with retries, gated on VolumeControlEnabled. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…D hunt) - HideVolumeOsd enumerated XAML islands with NULL child-after, which always returns the FIRST match: infinite 100%-CPU spin + hiding the wrong island whenever it missed criteria. Chain properly through islands and their content bridges. - Both flyout auto-hide loops (async void) caught only TaskCanceledException: any other throw was an abnormal exit with no trace. Catch Exception, log, emergency-hide. Per-session poll guarded so one dead session can't break the mixer refresh. - AudioSessionModel: suppress device write-back while syncing from device (same echo guard as master volume). - Breadcrumb logs on volume flyout show/hide for the next crash report. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
… silent guards) - OpenAnimation DIP scaling can race the window's DPI flip on mixed-DPI multi-monitor setups, stranding the flyout off-screen; queue a raw-pixel resting-position correction after the flight (no-op when already exact). Shared by media + volume flyouts. - Normalize out-of-range Position setting to bottom-center instead of flying with a stale storyboard target. - Log ShowMediaFlyout suppressions (null session/disabled/fullscreen) and every show with monitor + raw coords - these paths were silent, leaving empty logs for flyout-never-appears reports. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Alt+Tab/keys dying over time (regression vs v2.10, worse at boot): HookCallback ran ShowMediaFlyout synchronously on the low-level keyboard hook - blocking Dispatcher.Invoke, media COM fetches and animation setup on every key press. Slow hooks stall all keystrokes system-wide and Windows silently drops them. Debounce + queue via Dispatcher.BeginInvoke so the hook returns immediately (volume path already deferred). Dismiss jump-up-then-down: CloseAnimation derived From from GetWindowPlacement (zeros for transient handles) scaled by the selected monitor's DPI (wrong when the flyout lives on another monitor). Now From comes from the window's actual rendered position (PointToScreen + host monitor DPI, placement fallback), To is always recomputed as From +/-20dip (pinned to From when animations are off so stale storyboard values can't teleport the window). Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…ng change UpdateUi set the new single-copy text but left the previous song's forever-loop TranslateTransform running until the async position pass rebuilt marquees. Frames in between rendered the new text at the old offset (empty widget), then snapped back (blink) - worst with loop mode, which doubles the text. - ResetMarquee helper stops the animation, zeroes X and restores single-copy text synchronously on song change and on hide - Refresh cached StringWidth measurements + UpdateMarquees immediately for text changes only (play/pause updates skip it so scrolling never restarts); extracted shared RefreshCachedTextWidths for CalculateSize Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Manifest: - Add desktop/com to IgnorableNamespaces (strict parsers reject unknown unmarked extension namespaces -> 'error in parsing the app package') - Fix Dependencies versions (bogus MaxVersionTested 10.0.0.0, stale 14393 min) to match wapproj 19041/26100 Installer: - Check for .NET 10 Desktop Runtime (x64) in FluentFlyout_Installer.bat; GitHub builds are framework-dependent so a missing runtime installs fine but the app silently never starts (no window, no Task Manager entry) - offer the download instead of failing silently - Document the prerequisite in README.txt and README.md msixbundle section - Drop stale dev-machine AppInstallerUri from wapproj Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…resume Visualizer: - Stop WASAPI cleanly on Suspend and clear cached device ID; on Resume wait 2.5s for audio stack then restart with backoff - Extend restart retries 5x500ms -> 10x800ms plus one delayed 15s follow-up so slow resume without further system events still recovers - Re-arm single-shot silence watchdog while silence is short (was firing once then going blind) and null-guard DataAvailable timer access - Restart on abnormal RecordingStopped (device invalidated underneath us) Volume mixer (same S3 root cause: stale MMDevice, no DefaultDeviceChanged on desktop): - Subscribe to PowerModeChanged.Resume + SessionUnlock/Logon and re-resolve default render device after 2s settle, fixing frozen volume flyout and single-session mixer after sleep Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
The layout pass only updated SongImageBorder.Height when switching between compact (36) and normal (78) layouts, leaving the 78px width from XAML in place. In compact layout the cover box became 78x36, so the album art was rendered stretched/cropped instead of square. Set Width alongside Height and use UniformToFill so non-square source art fills the square box consistently with the taskbar widget and next-up flyout. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…ihugo#973) The mixer enumerated every WASAPI session and added a row for each, so apps that open multiple sessions or multiple processes of the same executable (e.g. Flow Launcher) appeared several times. Deduplicate by process id and by resolved display name while enumerating, matching the native Windows mixer's per-app grouping. 'System sounds' (pid 0) stays a single entry. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…nchihugo#1087) Some apps (notably packaged and elevated ones) report an AudioSessionControl DisplayName that is an unexpanded indirect string resource such as "@%SystemRoot%\System32\foo.dll,-101" or "@{Package?ms-resource:...}". That raw string was used as the mixer row label, showing garbage or an empty name. Treat any '@'-prefixed DisplayName as unresolved so the existing executable-based fallback (FileDescription, then file name) supplies a real app name. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…chihugo#1086, unchihugo#1076) The view model attached the default render endpoint once at construction. If that failed (audio stack not ready at startup) or the cached MMDevice was later invalidated (driver reset, endpoint reconfiguration, DefaultDeviceChanged reporting an id that no longer resolves), every subsequent read threw and was swallowed, so the flyout kept displaying the last known value while the real system volume changed - the frozen number users report. - add EnsureDeviceAttached() to lazily re-resolve the default endpoint - drop the cached device and reattach when a master-volume read fails - fall back to the default endpoint when GetDeviceById returns null - ensure a device before adjusting master volume from the taskbar widget Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…o#1039) With "Automatically hide the taskbar" enabled the taskbar is excluded from the monitor work area, so flyouts anchored 16px from the screen edge sat exactly where the taskbar slides out and were overlapped by it. The native volume OSD reserves that space; we now do the same. Add SHAppBarMessage/APPBARDATA P/Invokes and a GetAutoHideTaskbarInset() helper that returns the auto-hidden taskbar's thickness for the relevant screen edge (0 when auto-hide is off or the taskbar is on another edge), and apply it to every bottom- and top-anchored flyout placement, including GetFinalPosition used to stack the volume flyout above the media flyout. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
pauseOtherMediaSessionsIfNeeded ran for whichever session raised a playback or media-property event. Any background player that reported itself as Playing therefore paused the session the user had just started, which in turn raised an event and paused the first one back. Users experienced this as an undocumented "exclusive audio mode" that ping-pongs between e.g. Spotify and a browser video, with no setting that appeared to control it. Restrict the fan-out to the currently focused/active session and null-guard the playback info lookup, so the feature does what its setting describes: the session you are controlling pauses the rest. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…nchihugo#961) When a song restarts (loop/repeat in YouTube Music) the player briefly republishes empty media properties. That blank snapshot was pushed straight to the taskbar widget, which then displayed just the album art with no title or artist, and it was also stored in the dedupe cache so the following real update could be swallowed. Skip blank metadata while the session is still alive. The next-up flyout additionally compared only against the last shown title, so a looped track - whose title is unchanged - never triggered it again. Treat a republished title as a new song when it is not a thumbnail-only update. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…go#1065, unchihugo#1052) The widget window is reparented into Shell_TrayWnd as a WS_CHILD. When Explorer restarts, that parent HWND is destroyed and recreated; our child window survives with its hit-test region intact - which is why users report the widget and visualizer still respond to clicks while being completely invisible - but it is never composited into the new taskbar again. Merely calling SetParent on the next position tick does not restore rendering. Rebuild the taskbar window once Explorer has stabilized (we already wait for the new Shell_TrayWnd to have geometry there), alongside the existing tray-icon and native-OSD recovery. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…hihugo#1071) The capture watchdog was created in Start() but only ever armed from OnDataAvailable. If StartRecording() succeeded while the underlying stream was dead - the usual outcome of a desktop S3 sleep/wake cycle, where WASAPI accepts the AudioClient but never delivers a buffer - no callback ever arrived, so the watchdog was never started, the "no audio callbacks" recovery path never ran, and the visualizer stayed frozen until the app was restarted manually. Arm the watchdog right after the capture starts, and clean up a partially constructed capture when Start() throws so the next restart attempt can bind the endpoint. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…hugo#983) Locking the PC and letting the monitors sleep tears down and recreates taskbar child windows without necessarily producing a WM_DISPLAYCHANGE for us, so the widget was simply gone after unlocking and only came back by restarting the app. The existing display-environment refresh (which recreates the taskbar window and re-syncs DPI/placement) already handles this case - it just was never triggered. Subscribe to SystemEvents.SessionSwitch (unlock/logon/remote or console connect) and PowerModeChanged (Resume) and route them through the existing debounced ScheduleDisplayEnvironmentRefresh, unsubscribing during cleanup. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Turning off a secondary display or changing the projection mode makes EnumDisplayMonitors return an empty list for a short window. Both MonitorUtil.GetSelectedMonitor and TaskbarWindow.GetSelectedTaskbarHandle then evaluated Math.Clamp(index, 0, -1), which throws ArgumentException because min is greater than max. That exception escaped from flyout placement and from every taskbar position tick, so the widget was left with a stale hit-test region: invisible but still swallowing taskbar clicks, matching the reported "taskbar stops responding until the widget is disabled". Return a default MonitorInfo / the primary Shell_TrayWnd instead; the next tick picks up the real topology once Windows has settled. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…nchihugo#1078) Hiding the Windows volume flyout was attempted lazily, from the first ShowFlyout call, and only once. Two consequences: the native OSD still appeared for the first volume change after login, and if the XAML island wasn't enumerable at that moment (common right after login or an Explorer restart) the handle stayed zero and the native flyout kept showing for the rest of the session with no further attempt. Kick off the existing retrying hide routine once the mixer window is created when the volume flyout feature is enabled. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
VolumeMixerWindow.ShowFlyout is async void, and only its auto-hide loop was wrapped in a try/catch. Everything before it - blur setup, mixer refresh, placement/OpenAnimation, Show, and the CancellationTokenSource swap - ran unguarded, so any exception there (window torn down mid-show by a display refresh, DWM/blur call failing, CTS already disposed) escaped an async void method and terminated the process. Users saw the app vanish right after pressing a volume key, with logs ending mid-session. Wrap the show path, tolerate a disposed CTS in both ShowFlyout and OnClosed, and guard the deferred expand dispatch. Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…inates Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
…anges Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
6 tasks
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Batch fix for 35 open issues across volume flyout/mixer, media flyout, taskbar widget, visualizer, and startup paths. Each commit is scoped to one issue and references its number. No new dependencies were added.
Motivation
Closes #1086, #1075, #1078, #1087, #1084, #1015, #984, #1096, #1085, #1019, #1094, #1071, #1107, #1029, #1083, #973, #961, #1065, #1052, #966, #983, #987, #1039, #1076, #920, #746, #153, #659, #608, #529, #843, #817, #849, #802
Type of Change
What Changed
Volume flyout / mixer
Media flyout / widget
Taskbar widget / visualizer
System integration
Additional Information
Developed via AI-assisted tooling on a Linux sandbox without the .NET Windows workload. Built and manually verified on Windows (net10.0-windows) with
dotnet buildsucceeding at 0 errors. Manually tested: startup behavior, volume flyout, media flyout, mixer names/icons, Alt+Tab, sleep/resume, audio device switching, seekbar, and native OSD suppression — all passing.Checklist