Bump to v3.1.1: tray tooltip 'starting up' could get stuck after first launch
Bug: if v3.1 installed via auto-update on a profile with StartMinimised on, the tray icon's hover tooltip got stuck at the initial "RemSound - starting up" string. The snapshot tick was running and SetTooltip was being called every second with the live state, but Windows shell kept showing the original cached text on hover. The fix-by-workaround was a hide-then-re-show cycle which forced the shell to rebuild the icon registration with the latest NotifyIcon.Text. Root cause: NotifyIcon.Text values set BEFORE the icon's first NIM_ADD (i.e. while Visible=false) become the shell's "initial" tooltip when the icon eventually appears. Subsequent NIM_MODIFY calls from text changes DO propagate, but the shell tends to keep showing the original text on hover - presumably a tooltip-cache eviction quirk. In the resume-after-update-with-StartMinimised flow, the window briefly shows then BeginInvokes a Minimize that flips Visible=true before the snapshot timer has had a chance to fire, so the shell registers with the stale "starting up" string. Fix: drop the hard-coded "starting up" initial text from the controller ctor entirely. The controller now takes a Func<string> buildTooltip callback from MainForm and calls it in Minimize() right before flipping Visible=true, so the shell's NIM_ADD sees current live state instead of a stale string. The 1 Hz snapshot tick keeps working for ongoing live updates while the icon is visible. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
752c12b579
commit
aa099eb555
@@ -20,6 +20,33 @@ internal sealed class AboutDialog : Form
|
||||
/// updates" path.</summary>
|
||||
private const string ReleaseNotes =
|
||||
"""
|
||||
RemSound v3.1.1
|
||||
|
||||
Hot-fix for a small but annoying bug with the system
|
||||
tray tooltip after v3.1 first installed itself.
|
||||
|
||||
What was happening: if the v3.1 auto-update fired
|
||||
while RemSound was set to start minimised to the tray,
|
||||
the tray icon's hover text could get stuck saying
|
||||
"RemSound — starting up" indefinitely, instead of
|
||||
switching to the live "X peers, sending, receiving"
|
||||
summary after a second or so. Showing the main window
|
||||
and then minimising it again was the workaround.
|
||||
|
||||
What was actually going wrong: Windows registers a
|
||||
tray icon's tooltip with the shell at the moment the
|
||||
icon becomes visible. RemSound was setting an initial
|
||||
"starting up" string at construction time, and the
|
||||
shell tended to keep showing that on hover even after
|
||||
the live state had been computed and pushed through.
|
||||
The workaround (hide then re-show the icon) cleared
|
||||
the shell's cache. The fix is to compute the right
|
||||
live tooltip text once, just before the icon becomes
|
||||
visible for the first time, so the shell registers
|
||||
the icon with correct text from the start.
|
||||
|
||||
Everything else in v3.1 is unchanged.
|
||||
|
||||
RemSound v3.1
|
||||
|
||||
Two big rounds of work on audio cues and the system
|
||||
|
||||
@@ -622,6 +622,10 @@ public sealed class MainForm : Form
|
||||
// every time the submenu opens, so newly-loaded profiles appear immediately.
|
||||
getRecentProfilePaths: () => AppConfig.Load().RecentProfiles,
|
||||
switchToProfile: path => SwitchToRecentProfile(path),
|
||||
// Tooltip builder — called once just before the tray icon first becomes visible
|
||||
// (in Minimize) so the shell's NIM_ADD sees the current live state instead of a
|
||||
// stale "starting up" string. Subsequent updates ride on the 1 Hz snapshot tick.
|
||||
buildTooltip: BuildTrayTooltip,
|
||||
exit: Close);
|
||||
|
||||
recordingController = new RecordingController(
|
||||
|
||||
@@ -37,6 +37,7 @@ internal sealed class MainFormTrayController : IDisposable
|
||||
private readonly Action toggleReceiving;
|
||||
private readonly Func<IReadOnlyList<string>> getRecentProfilePaths;
|
||||
private readonly Action<string> switchToProfile;
|
||||
private readonly Func<string> buildTooltip;
|
||||
private readonly Action exit;
|
||||
|
||||
private readonly ToolStripMenuItem sendingItem;
|
||||
@@ -51,6 +52,7 @@ internal sealed class MainFormTrayController : IDisposable
|
||||
Action toggleReceiving,
|
||||
Func<IReadOnlyList<string>> getRecentProfilePaths,
|
||||
Action<string> switchToProfile,
|
||||
Func<string> buildTooltip,
|
||||
Action exit)
|
||||
{
|
||||
this.owner = owner;
|
||||
@@ -60,16 +62,20 @@ internal sealed class MainFormTrayController : IDisposable
|
||||
this.toggleReceiving = toggleReceiving;
|
||||
this.getRecentProfilePaths = getRecentProfilePaths;
|
||||
this.switchToProfile = switchToProfile;
|
||||
this.buildTooltip = buildTooltip;
|
||||
this.exit = exit;
|
||||
|
||||
// Initial tooltip text — deliberately NOT just "RemSound" because some screen
|
||||
// readers (NVDA in particular) read tray icons as "<process name>, <tooltip>",
|
||||
// which with a single-word "RemSound" tooltip on a "RemSound" process renders as
|
||||
// "RemSound RemSound" until the first snapshot tick (~1s after launch) overwrites
|
||||
// it. Picking a sensible startup-state string avoids the duplicate read entirely;
|
||||
// the snapshot tick refreshes this with live peer / send / receive info from then
|
||||
// on.
|
||||
trayIcon.Text = "RemSound — starting up";
|
||||
// We deliberately don't bake any "starting up" / "running" string into the icon
|
||||
// here. The tooltip is computed fresh from buildTooltip() at the moment the icon
|
||||
// first becomes visible (in Minimize) and refreshed every second from MainForm's
|
||||
// snapshot tick after that. The reason: Windows' shell caches the tooltip text
|
||||
// it sees at NIM_ADD time and is reluctant to refresh hover text for the same
|
||||
// icon ID. Setting an "initial" string here meant that on a slow / minimised-at-
|
||||
// launch flow (e.g. the resume-after-update path with StartMinimised on), the
|
||||
// shell registered the icon with the stale string and kept showing it until the
|
||||
// user hid + re-showed the icon. By computing the right text once, just before
|
||||
// we set Visible = true for the first time, the shell sees the live state from
|
||||
// NIM_ADD onward.
|
||||
trayIcon.Icon = SystemIcons.Application;
|
||||
trayIcon.Visible = false;
|
||||
trayIcon.DoubleClick += (_, _) => Restore();
|
||||
@@ -182,6 +188,13 @@ internal sealed class MainFormTrayController : IDisposable
|
||||
public void Minimize()
|
||||
{
|
||||
owner.Hide();
|
||||
// Refresh the tooltip BEFORE showing the icon so the shell's NIM_ADD call carries
|
||||
// the current live state (peer count, send / receive routing, recording timer),
|
||||
// not a stale "starting up" string set earlier. The shell tends to cache hover
|
||||
// text from NIM_ADD time and is slow to update on subsequent NIM_MODIFY calls —
|
||||
// computing the right text now means the first hover already reads correctly.
|
||||
try { SetTooltip(buildTooltip()); }
|
||||
catch { /* harmless — fall through to the snapshot-tick refresh */ }
|
||||
trayIcon.Visible = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
tag_name on the latest GitHub release; bump it on every public release. The
|
||||
AssemblyVersion / FileVersion default to this value, and Assembly.GetName().Version
|
||||
is what the About dialog and the updater both read. -->
|
||||
<Version>3.1.0</Version>
|
||||
<Version>3.1.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user