Skip to content

fix: survive explorer.exe restarts (tray icon no longer disappears)#36

Open
amorel wants to merge 1 commit into
CodeZeno:mainfrom
amorel:taskbar-restart-fix
Open

fix: survive explorer.exe restarts (tray icon no longer disappears)#36
amorel wants to merge 1 commit into
CodeZeno:mainfrom
amorel:taskbar-restart-fix

Conversation

@amorel

@amorel amorel commented Jun 17, 2026

Copy link
Copy Markdown

Fixes #35 (and the symptom reported in #34).

Problem

When explorer.exe restarts, it destroys the taskbar, which destroys our embedded child window outright (IsWindow returns false) and leaves the UI thread parked in GetMessageW with no window to recreate in place. The tray icon and widget vanish until the app is manually relaunched. Full root-cause analysis in #35.

Fix

A dedicated watchdog thread (independent of the now-dead message loop) polls the Shell_TrayWnd handle and, when it changes, relaunches the widget as a fresh process that re-embeds into the new taskbar.

  • The relaunched child is flagged via an environment variable (CCUM_RELAUNCH) so it waits on the single-instance mutex until the previous instance exits — no double instance, no race.
  • A throttle (CCUM_LAST_RELAUNCH_UNIX + backoff) prevents a relaunch storm if Explorer is crash-looping.
  • Env-var based, so no public CLI surface is added; no new dependencies.

In-process recovery isn't viable because the window is genuinely destroyed and can't be recreated from another thread; a clean relaunch is the robust path. Happy to switch to in-process recreation if you'd prefer that direction.

Testing

  • Restarted Explorer repeatedly while the widget was running; verified each time that the process relaunches (new PID) and the new window is correctly re-embedded (IsWindow == true, GetParent == the new Shell_TrayWnd).
  • cargo build --release, cargo clippy (no new warnings from this change), cargo fmt --check (no changes to the touched code).

Single commit, scoped to src/window.rs.

When explorer.exe restarts it destroys the taskbar, which destroys our embedded child window outright (IsWindow returns false) and leaves the UI thread parked in GetMessage with no window to recreate in place. The tray icon and widget vanish until the app is manually relaunched (see issue CodeZeno#34).

A dedicated watchdog thread (independent of the now-dead message loop) polls the Shell_TrayWnd handle and, when it changes, relaunches the widget as a fresh process that re-embeds into the new taskbar. The relaunched child is flagged via an environment variable so it waits on the single-instance mutex until the previous instance exits, and a throttle backs off if explorer is crash-looping.
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.

Tray icon / widget disappears after Explorer (taskbar) restarts - root cause + fix

1 participant