Skip to content

Add crash-safe recovery for Fly Away offscreen windows #69

@shanselman

Description

@shanselman

Problem

Fly Away mode physically moves user windows offscreen. Normal PeekDesktop shutdown restores them because DesktopPeek.Stop() calls restore while peeking, but a hard crash, Task Manager end task, process kill, power loss, or OS termination can leave windows offscreen with the restore snapshot lost in memory.

That can put users in a nasty recovery state: their apps still exist, but their windows may be outside the visible virtual desktop with no obvious way back.

Goal

Make Fly Away crash-safe by persisting enough restore state before moving windows offscreen, then doing a best-effort recovery on the next PeekDesktop startup if the previous run died before restoring.

Proposed design

  1. Persist a Fly Away recovery snapshot before moving windows

    • When entering Fly Away, after capturing windows and before FlyAwayAll() moves them, write a recovery file under PeekDesktop app data, e.g. %LOCALAPPDATA%\PeekDesktop\flyaway-recovery.json.
    • Store only data needed to restore: HWND value, process ID, original WINDOWPLACEMENT, original bounds, timestamp, and app/version metadata.
    • Avoid storing window titles or other user content for privacy.
    • Write atomically: serialize to a temp file, flush, then replace/move into place.
  2. Clear the snapshot only after successful restore

    • On normal Fly Away restore, delete the recovery file after the restore attempt completes.
    • If no windows were moved, do not leave a recovery file behind.
    • If restore partially succeeds, still log skipped/destroyed handles and clear the file so startup does not repeatedly replay stale data.
  3. Recover on startup

    • During startup, before installing hooks or entering a new peek session, check for a recovery file.
    • If present, load it and attempt best-effort restore for surviving HWNDs.
    • Validate each entry before restoring:
      • IsWindow(hwnd) is true.
      • Optional: process ID still matches the saved process ID.
      • Window appears offscreen or outside current monitor work areas, so we avoid yanking intentionally moved windows.
    • Use the saved placement/bounds to restore windows.
    • Log recovered/skipped counts and delete the recovery file after the attempt.
  4. Graceful-exit safety belt

    • Keep the existing graceful Stop() restore behavior.
    • Optionally wire ProcessExit / unhandled exception best-effort restore, but do not depend on it. The persisted snapshot is the real protection because it survives hard termination.
  5. Test plan

    • Add harness tests for recovery snapshot serialization/deserialization and stale/invalid-handle skipping.
    • Add a manual validation checklist:
      1. Enable Fly Away.
      2. Trigger peek so windows move offscreen.
      3. Kill PeekDesktop.exe from Task Manager or Stop-Process -Id <pid> -Force.
      4. Restart PeekDesktop.
      5. Verify surviving windows return to their original positions.
      6. Verify the recovery file is deleted after recovery.
      7. Verify normal Fly Away restore still deletes the file and does not run recovery on next startup.

Acceptance criteria

  • Fly Away writes a recovery snapshot before moving windows offscreen.
  • Normal restore removes the snapshot.
  • Startup detects and replays a leftover snapshot.
  • Invalid/destroyed handles are skipped safely and logged.
  • No private window titles/content are persisted.
  • Manual kill/crash scenario no longer leaves users stranded with offscreen windows.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions