Skip to content
This repository was archived by the owner on Jul 9, 2026. It is now read-only.

Latest commit

 

History

History
110 lines (85 loc) · 6.8 KB

File metadata and controls

110 lines (85 loc) · 6.8 KB

Preview Mode — Feasibility Report

What Preview Mode Would Mean

A mode where selecting an app in the switcher shows thumbnails of that app's individual windows (similar to Windows Alt+Tab or macOS's own Cmd+` / Dock Exposé), allowing the user to pick a specific window instead of just activating the app.

New macOS APIs Required

API Purpose Where Complexity
CGWindowListCopyWindowInfo Enumerate all windows, filter by PID platform/macos.rs Medium
CGWindowListCreateImage Capture a window to an image (CGImage → PNG bytes) platform/macos.rs High
CGWindowListCreateDescriptionFromArray Get window titles, bounds, level platform/macos.rs Medium
AXUIElement (Accessibility API) Bring a specific sub-window to front (not just the app) platform/macos.rs High
NSRunningApplication + AXUIElementCreateApplication Bridge PID → AX element for window-level focus platform/macos.rs Medium

These are from Core Graphics (objc2-core-graphics) and Application Services (objc2-application-services) — both already in the dependency tree.

Architecture Changes

New Data Structures & Messages

AppState:
  ├─ mode: AppMode
  │   └─ NEW: Preview
  ├─ selected_app_windows: Vec<WindowInfo>
  └─ window_thumbnails: HashMap<WindowId, ImageHandle>

New Messages:
  PreviewMode(id)
  WindowSelected(id, window_idx)
  WindowThumbnailsReady(id, thumbs)
  CycleWindow(id, direction)

New macOS Functions (platform/macos.rs)

  • windows_of_app(pid) -> Vec<WindowInfo> — enumerates windows for a given PID via CGWindowListCopyWindowInfo
  • capture_thumbnail(WindowId, size) -> Vec<u8> — captures a downscaled PNG of a specific window
  • focus_window(WindowId) — brings a specific window to front using AXUIElement

Files That Need Changes

File Change
app/app.rs AppMode::Preview variant; preview_windows: Vec<WindowInfo>; thumbnails: HashMap<WindowId, ImageHandle>
app/update.rs Handle PreviewMode toggle, WindowSelected, thumbnail capture commands, CycleWindow
app/view.rs Render thumbnail strip/grid when in preview mode (stacked overlay below the app row)
app/subs.rs Add hotkey binding for preview mode (Ctrl+P or assignable)
platform/macos.rs New functions: enumerate_windows(pid), capture_window_thumbnail(window_id), focus_window(window_id)
main.rs Possibly larger window dimensions for preview mode
config.rs Maybe enable_preview: bool setting

Effort Estimate

Component Effort Risk
Mode plumbing (enum variant, hotkey, toggle) 1–2 hrs Low
Window enumeration (CGWindowListCopyWindowInfo → PID filter) 2–4 hrs Medium
Thumbnail capture (CGImage → PNG → Iced Handle, async) 4–8 hrs High — performance, memory, caching strategy
Thumbnail UI (rendering stacked overlay in view.rs) 3–5 hrs Medium
Window-level focusing (AXUIElement to bring specific window front) 3–6 hrs High — macOS AX quirks, permission requirements
Edge cases (minimized windows, fullscreen apps, windows off-screen) 2–4 hrs Medium
Total 15–30 hrs

Key Design Decisions

  1. Async capture: Window screenshots block the GPU. Must be done on a background thread with a completion message back to the Iced loop (similar to how app_loader uses channels in subs.rs).

  2. Thumbnail caching: Don't recapture every frame. Cache thumbnails per window-ID, invalidate on window focus change or a timer.

  3. Window info gathering: CGWindowListCopyWindowInfo is fast — call it on mode entry. Returns window IDs, titles, bounds — enough to build the window list.

  4. Layout approach: When in preview mode and an app is selected, replace or augment the normal grid with a horizontal strip of window thumbnails below the app row. User presses Tab/arrows to cycle, Enter to select.

  5. Minimized windows: CGWindowListCreateImage can capture minimized windows (pass .optionOnScreenOnly = false), but they render as empty. Use AXUIElement to request a preview instead, or simply note them with a "Minimized" label.

Prerequisites

  • The app already requests Accessibility API permission (onboarding flow in accessibility.rs). Window-level focusing requires this.
  • Screen Recording permission may be needed for CGWindowListCreateImage on macOS 10.15+ (Catalina+), since capturing another app's window content is treated as a privacy-sensitive operation. This would need to be added to the permissions onboarding.

Recommended Phasing

Phase Scope Est.
1 — Window list Enumerate windows per app, show titles in the switcher UI, focus a specific window (no thumbnails) 8–12 hrs
2 — Thumbnails Async thumbnail capture, caching, inline rendering in the UI 6–10 hrs
3 — Polish Animations, edge cases, minimized/fullscreen windows, permissions flow 4–8 hrs