Skip to content

fix: recover widgets lost during monitor connect/disconnect on macOS#277

Open
lohrm-spf wants to merge 1 commit intoglzr-io:mainfrom
michidk:fix/monitor-change-widget-recovery
Open

fix: recover widgets lost during monitor connect/disconnect on macOS#277
lohrm-spf wants to merge 1 commit intoglzr-io:mainfrom
michidk:fix/monitor-change-widget-recovery

Conversation

@lohrm-spf
Copy link
Copy Markdown

Summary

Fixes a bug where Zebar's bar silently disappears when connecting/disconnecting external monitors on macOS while the process and tray icon remain alive.

Problem

During macOS display reconfiguration, Tauri's available_monitors() can transiently return an empty or partial list. The existing code path:

  1. relaunch_all removes all widget states from the HashMap before attempting recreation
  2. widget_coordinates returns an empty Vec when no monitors match → the creation loop runs zero iterations → returns Ok(())
  3. Widget state is permanently lost — no error logged, no recovery attempted
  4. Additionally, ? operator in the per-widget relaunch loop bails on the first failure, skipping all remaining widgets whose states were already deleted

Result: process alive (tray icon visible), zero widget windows, empty error log.

Fix

Three layered defenses:

  • Skip empty monitor broadcasts (monitor_state.rs): When available_monitors() returns an empty list during display transition, skip the update to prevent premature relaunches with zero monitors
  • Per-widget error resilience (widget_factory.rs): Collect errors instead of bailing on first failure, so one widget's error doesn't prevent siblings from relaunching. Also adds warn! when no monitors match a widget's selection
  • Startup recovery with backoff (main.rs): After a monitor change relaunch, if widget_states is empty but startup configs exist, retry startup() with exponential backoff (500ms/1000ms/1500ms)

Test plan

  • Confirm bar disappears on monitor disconnect (before fix)
  • Verify bar recovers after monitor disconnect/reconnect (after fix)
  • Verify normal startup and manual widget open/close still work
  • Verify multi-monitor setup creates widgets on all monitors

During macOS display reconfiguration, available_monitors() can
transiently return an empty list. This caused relaunch_all to
destroy all widget state and recreate zero windows — silently
leaving the process running with no visible bar.

Three fixes:

- Skip broadcasting empty monitor lists in the poll loop to
  prevent premature relaunches during display transitions
- Collect per-widget relaunch errors instead of bailing on first
  failure, so one widget's error doesn't kill siblings
- Add a safety net in the monitor change handler that detects
  empty widget state after relaunch and retries startup with
  exponential backoff (500/1000/1500ms)

Also adds warn-level logging for empty monitor lists and empty
widget coordinates so this class of failure is no longer silent.
@github-project-automation github-project-automation bot moved this to 📬 Needs triage in zebar Mar 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 📬 Needs triage

Development

Successfully merging this pull request may close these issues.

2 participants