Skip to content

Fix: keep float bar above the taskbar (stop it disappearing on taskbar click)#88

Open
Gosuj wants to merge 1 commit into
Finesssee:mainfrom
Gosuj:fix/floatbar-keep-above-taskbar
Open

Fix: keep float bar above the taskbar (stop it disappearing on taskbar click)#88
Gosuj wants to merge 1 commit into
Finesssee:mainfrom
Gosuj:fix/floatbar-keep-above-taskbar

Conversation

@Gosuj

@Gosuj Gosuj commented Jun 16, 2026

Copy link
Copy Markdown

Problem

When the Float Bar overlaps the Windows taskbar/tray area (its normal position), it disappears whenever the user clicks the taskbar, and reappears only after interacting elsewhere.

Root cause

The float bar window is created with always_on_top(true), which sets HWND_TOPMOST once at creation. The Windows taskbar (Shell_TrayWnd) is also a top-most window. When the user clicks the taskbar, the shell raises Shell_TrayWnd to the front of the top-most band — above the float bar, which visually overlaps it — so the bar gets occluded ("disappears").

Confirmed by inspection:

  • floatbar::handle_window_event only persists geometry on move/resize/close — there is no blur/hide handler, so nothing in app code is deliberately hiding the bar.
  • always_on_top is never re-asserted after creation.

Fix

Re-assert HWND_TOPMOST on a short (150 ms) interval while the float bar window exists, via SetWindowPos with SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE (z-order only — focus, position and size untouched, preserving the existing WS_EX_NOACTIVATE / click-through behaviour).

  • Guarded by an AtomicBool so only one task runs at a time.
  • The task exits and clears the guard once the window is gone, so a later show() restarts it.
  • Mirrors the existing auto_refresh task pattern (tauri::async_runtime::spawn + tokio::time::sleep).
  • No-op on non-Windows platforms.

Single file changed: apps/desktop-tauri/src-tauri/src/floatbar/window.rs.

Verification status

⚠️ Not locally built/verified. I diagnosed this from source and wrote the fix, but I don't have the Rust/MSVC toolchain set up on this machine, so I have not run cargo build/clippy/fmt or runtime-tested it. The change is small and self-contained and follows the existing Win32 helper + async-task patterns in this file; please let CI / your local build be the gate. Happy to adjust the interval, switch to an event-driven SetWinEventHook(EVENT_SYSTEM_FOREGROUND) approach, or address review feedback.

The detached float bar is created with `always_on_top(true)`, which sets
`HWND_TOPMOST` exactly once. The Windows taskbar (`Shell_TrayWnd`) is itself a
top-most window, so when the user clicks it the shell raises it above other
top-most windows — including the float bar, which visually overlaps the
taskbar/tray area. The bar then appears to "disappear" on every taskbar click.

Re-assert `HWND_TOPMOST` on a short (150ms) interval while the float bar window
exists, using `SetWindowPos` with `SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE` so
focus, position, and size are untouched. The task is guarded by an `AtomicBool`
so only one runs at a time and it exits (clearing the guard) once the window is
gone, so a later `show()` restarts it. No-op on non-Windows platforms.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Finesssee

Copy link
Copy Markdown
Owner

This needs another pass before merge.

The current fix adds a hidden 150ms polling loop guarded by a process-global AtomicBool, which makes the floatbar z-order lifecycle harder to reason about and introduces a restart race: if the old worker observes the window as gone, a new show() can return early while the guard is still true, then the old worker clears the guard and exits, leaving the newly shown floatbar without any keep-on-top worker.

Can you restructure this instead of continuously polling? Ideally this should live behind a Windows-only floatbar z-order controller that owns its lifecycle explicitly, with a generation/cancellation token or an event-driven repair path that reacts when the shell/taskbar actually invalidates the z-order. If polling is truly unavoidable, please make it an explicit owned lifecycle object rather than a global boolean loop hidden inside show().

@Finesssee

Copy link
Copy Markdown
Owner

No update since the requested changes above, so this is still not merge-ready. Please push the restructuring/fix within the next day; otherwise I’ll close this PR as stale/unresolved and we can reopen or start a fresh PR when the implementation is ready.

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.

2 participants