Skip to content

Latest commit

 

History

History
54 lines (43 loc) · 4.53 KB

File metadata and controls

54 lines (43 loc) · 4.53 KB

Architecture

Boundary

ScreenCloneManager.exe has two modes: a visible Spectre.Console CLI and a hidden per-user controller. launch.ps1 is only the desktop context-menu entry; lifecycle and OBS logic remain in C#.

DesktopBackground context menu
  -> pwsh 7 launch.ps1
  -> visible CLI
       -> current-user Named Pipe
       -> single controller (per-user mutex)
            -> one authenticated WebSocket v5 connection to 127.0.0.1
            -> existing or tool-started OBS process
            -> exact source UUID + current monitor index
            -> exact recorded projector HWND per stable display identity
            -> WM_DISPLAYCHANGE + configurable low-frequency reconciliation (5 s default)

Sources of truth and invariants

  • Windows display identity: QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS) plus DisplayConfigGetDeviceInfo. Only read APIs are imported. No topology setter exists in the codebase.
  • Source identity: OBS sourceUuid; source name is fallback/display text only.
  • Projector ownership: windows newly observed after a single OpenSourceProjector request, restricted to the selected OBS PID and matched by fullscreen geometry/class/title. Stop sends WM_CLOSE only to recorded handles after revalidating PID.
  • Tool-started OBS lifecycle: only when no OBS is running, remove stale OBS 32 run_* crash sentinels, start minimized without --minimize-to-tray, wait for the normal OBS/WebSocket/source path, open and track native full-screen projectors, then hide the tool-owned editor window. Existing user-started OBS windows are untouched.
  • Session intent: desiredTargets is updated before windows are closed. The reconciliation planner therefore reopens accidental closes but not intentional stop/change operations.
  • OBS ownership: an existing OBS process is never closed. A tool-started OBS is normally closed only when no standard OBS output is active and it has not been adopted through an output or baseline change.
  • User OBS baseline: the controller never sends set-current Program/Preview/Profile/Scene Collection requests. clone screen contains one reference to the verified internal-display input; before creating the scene, adding that reference, or removing duplicate internal-display scene items, the active Scene Collection JSON is backed up and the result is read back.
  • Security: the pipe server uses PipeOptions.CurrentUserOnly; mutex/pipe names are derived from the current SID; websocket secrets use DPAPI CurrentUser.

Modules

  • Display/: DisplayConfig enumeration, topology inference, stable identity and OBS monitor mapping.
  • Obs/: one small WebSocket v5 client, typed requests, OBS configuration backup/initialization, process policy, clone-scene policy.
  • Windows/: PID-scoped window enumeration, HWND tracking, exact close, topmost and mouse pass-through.
  • Controller/: IPC framing, singleton host, session state, and hot-plug/accidental-close reconciliation. Terminal session loss exits quietly.
  • Cli/: immediate target selector, one-second live status menu while open, settings, and human-readable environment checks.
  • Configuration/ and Infrastructure/: atomic config, DPAPI secret, bounded JSONL logs.

Reconciliation sequence

  1. A hidden top-level tool HWND receives WM_DISPLAYCHANGE and requests immediate reconciliation; a configurable 5-second-default timer is a low-frequency safety net.
  2. Saved device path is matched first, then EDID manufacturer/product/connector, then stable key.
  3. Each online display is remapped to the current OBS monitor list. Friendly name is weighted strongly because OBS/QScreen may use logical DPI coordinates while DisplayConfig exposes physical coordinates.
  4. A missing expected projector is opened once and its new HWND is recorded. Existing live tracked HWNDs are retained.
  5. One target offline affects only that target. If all desired targets are offline, the desired session is terminated and cannot auto-resume after controller exit.

Failure containment

  • Per-target projector errors are stored without closing successful targets.
  • OBS readiness code 207 is retried only for GetVersion within a fixed deadline. Other request failures propagate.
  • Output status code 604 means the feature is not configured and is normalized to inactive; it is not treated as connection failure.
  • Config corruption is backed up and reset. Log write failure is retained in diagnostics and does not throw into the active projector loop. Tool logs older than three days are deleted by a delayed best-effort task on interactive startup.
  • No forced OBS process termination is used.