Commit Graph

5 Commits

Author SHA1 Message Date
fullex
e666470794 refactor(sub-window): rename DetachedWindowManager to SubWindowService
Unify the "window detached from main" concept under the SubWindow name,
pairing it with MainWindow. Rename the service class, WindowType enum
value, HTML entry, renderer directory, React components, logger contexts,
and window-manager docs accordingly.

Scope of rename (noun-only):
- DetachedWindowManager -> SubWindowService
- DetachedWindowState -> SubWindowState
- WindowType.DetachedTab -> WindowType.SubWindow (value 'subWindow')
- detachedWindow.html / detachedWindow/ -> subWindow.html / subWindow/
- DetachedAppShell -> SubWindowAppShell
- DetachedTabApp -> SubWindowApp
- DETACHED_DEFAULT_WIDTH/HEIGHT -> SUB_WINDOW_DEFAULT_WIDTH/HEIGHT
- Logger contexts / sources and all "detached window" prose

Preserved (interaction-specific, not window-type nouns):
- IPC channels Tab_Detach / Tab_Attach / Tab_MoveWindow / Tab_TryAttach /
  Tab_DragEnd and their 'tab:*' literals - these describe the drag-tab
  interaction, not the SubWindow concept
- Component prop isDetached and useTabDrag.detachedCreated state
- The DevTools "detached" and Node spawn "detached" unrelated usages
2026-04-21 19:32:47 -07:00
fullex
f533e9259f refactor(window-manager): group behavior runtime setters under wm.behavior
Move runtime overrides (setHideOnBlur / setAlwaysOnTop /
setMacShowInDockByType) off the flat WindowManager API onto a
`wm.behavior` sub-namespace backed by a new BehaviorController class
in behavior.ts. The controller owns the hideOnBlur override map and
the per-type macShowInDock override map; WindowManager keeps only the
Dock commit-state flag and the visibility predicate.

Surfacing the three-layer declarative split (windowOptions / behavior
/ quirks) at the API level lets consumers tell at a glance which
layer a runtime setter belongs to, and gives future behavior setters
a natural home without inflating the flat WindowManager namespace.
`setTitleBarOverlay` and `setInitData` stay on the flat namespace
since they do not target the behavior layer.

Hard-cut migration: 5 production call sites (SelectionService,
MainWindowService) and the window / MainWindowService test suites
updated in place; no deprecation alias kept. Documentation across
the window-manager reference set rewritten to the new API shape.

Drive-by: add missing `setIsPinned` dep to HomeWindow.tsx
`baseFooterProps` useMemo to silence a pre-existing
react-hooks/exhaustive-deps warning surfaced while verifying lint.
2026-04-19 08:10:52 -07:00
fullex
bafed0d0e1 refactor(window-manager): migrate main window & fix macOS Dock semantics
- Rename WindowService -> MainWindowService (git mv, preserves blame/log)
- Register WindowType.Main in windowRegistry (singleton, showMode: manual);
  MainWindowService drives construction via wm.open and retains business
  logic only: IPC handlers, tray-aware close, crash recovery, show/toggle
- 50 call sites renamed (@DependsOn, application.get keys, imports)

WM Dock visibility refactored from visibility-based to existence-based:
- updateDockVisibility predicate drops isVisible/isMinimized check — a
  hidden main window must not remove the Dock icon (Cmd+W semantics)
- Add wm.setMacShowInDockByType(type, value) for tray-mode transitions;
  keyed by type so services can suppress Dock before the first instance
  exists (tray-on-launch path)
- Reduce triggers to window creation, destruction, and type-override
  changes; show/hide/minimize/restore no longer affect Dock state
- dockShouldBeVisible initializes true to match Electron's default

MainWindowService uses setMacShowInDockByType for tray-on-launch, close-
to-tray, and reopen-from-tray paths, replacing manual app.dock?.hide()
calls that raced against WM.

Docs updated across window-manager/{README, overview, platform,
api-reference, migration-guide}. New MainWindowService unit test covers
the close matrix (isQuitting, win/linux tray on/off, mac default, mac
tray on_close, fullscreen edge, Dock override assertions) and crash
recovery (first reload vs second-within-60s forceExit).
2026-04-19 06:52:03 -07:00
fullex
62d39d41f7 refactor(window-manager): split metadata into windowOptions/behavior/quirks
WindowTypeMetadata now declares per-type config across three orthogonal
layers, chosen by what goes wrong if misconfigured:

  - windowOptions: BrowserWindow constructor parameters (Electron-native).
  - behavior: cross-platform declarative WM behavior that the constructor
    cannot express — hideOnBlur, alwaysOnTop level/relativeLevel,
    visibleOnAllWorkspaces options, macShowInDock.
  - quirks: OS-specific monkey-patches around hide/show/close.

`macReapplyAlwaysOnTop` is now a pure boolean — the level it re-applies
reads from `behavior.alwaysOnTop`, eliminating the previous mixing of
hack flag and semantic value.

Field renames in the registry:

  - defaultConfig → windowOptions
  - show → showMode (also gains 'immediate' | 'manual' string variants
    in place of true/false; 'auto' unchanged)
  - showInDock (top-level) → behavior.macShowInDock
  - preload now accepts a plain filename ('index.js' / 'simplest.js'),
    mirroring htmlPath; empty string disables, omit defaults to
    'index.js'. Removes the variant→file mapping switch.
  - mergeWindowConfig → mergeWindowOptions

Two runtime setters added on WindowManager:

  - setHideOnBlur(id, enabled): runtime override on behavior.hideOnBlur.
    Override map is cleared on destroy and on releaseToPool, so pool
    consumers re-applying after open() see a clean default.
  - setAlwaysOnTop(id, enabled): toggles using level/relativeLevel from
    behavior — registry is the single source of truth.

setVisibleOnAllWorkspaces intentionally has no WM setter: its options
differ per call in real usage (SelectionAction's full-screen show
sequence) and WM has no state to maintain.

Types derived from Electron's signatures so they stay in sync with
@types/electron:

  - AlwaysOnTopLevel = NonNullable<Parameters<BW['setAlwaysOnTop']>[1]>
  - VisibleOnAllWorkspacesOptions imported directly

applyWindowQuirks is split into applyWindowBehavior (new, behavior.ts)
+ applyWindowQuirks. Behavior runs first so monkey-patches wrap any
subsequent show/hide rather than the initial setter calls. Behavior
takes a closure for reading the override map, avoiding a reverse
WindowManager dependency.

Consumer changes:

  - SelectionToolbar: declares behavior.hideOnBlur; mouse-key hook
    lifecycle moves from showToolbarAtPosition/hideToolbar call sites
    to window 'show'/'hide' event listeners, so any hide path (WM-
    driven blur included) triggers cleanup symmetrically.
  - SelectionAction: pinActionWindow routes through wm.setAlwaysOnTop
    via getWindowId. Show-sequence setVisibleOnAllWorkspaces calls
    stay direct (true/false options differ per call). Hardcoded
    'floating' level dropped from the show sequence; Electron's
    default is identical.
  - QuickAssistant: removes the inline setVisibleOnAllWorkspaces and
    setAlwaysOnTop calls (now declared in registry behavior). The
    blur handler stays in the service because hideQuickAssistant() is
    a platform-specific business flow (Windows minimize+setOpacity,
    macOS<26 app.hide()) that a generic window.hide() cannot express.

QuickAssistant pin/blur on macOS NSPanel — separate concern, addressed
in the same change because the diagnosis surfaced during refactor:

  Electron's blur tracker can get stuck after (outside-click → intra-
  panel pin/unpin click → outside-click). Cocoa fires
  windowDidResignKey: for the second outside-click but Electron filters
  it — its tracker thinks the window was already blurred (the intra-
  panel click silently re-keyed the panel without firing
  windowDidBecomeKey:). Upstream marked wontfix (electron/electron#3222).

  Workaround: after un-pinning, poll window.isFocused() at 200ms,
  capped at 30s. isFocused() reads Cocoa state directly, bypassing
  the broken Electron tracker. Triggered only when hasBlurredSinceShow
  is true (the failure precondition), so the common open→pin→unpin
  path runs no timer.

  Renderer side: HomeWindow's pin sync moves from useEffect (deferred
  by one render cycle) to a setter wrapper, so IPC fires synchronously
  inside the click handler — closes a small race where a fast outside
  click could see a stale main flag.

Tests: 15 new specs covering behavior layer (declarative + runtime
override, pool recycle reset, level derivation, initial
setVisibleOnAllWorkspaces application, macReapplyAlwaysOnTop reading
from behavior). Existing fixtures mechanically renamed.

Docs: 6 window-manager docs synchronized; README adds sections on
configuration layers, "WM does not know pin", behavior/quirks API,
when to provide a runtime setter, type derivation convention, and
Electron edge cases.
2026-04-19 01:27:26 -07:00
fullex
d2f629799c docs(window-manager): split README into docs/references/window-manager/
Move the 756-line src/main/core/window/README.md into a dedicated
docs/references/window-manager/ directory organized by concern
(overview, usage, pool mechanics, platform, API reference, migration),
following the docs/references/lifecycle/ pattern. The in-source README
shrinks to a 14-line pointer.

Along the way:

- Reframe onWindowCreated + open()/close() as the canonical consumer
  pattern, and demote create()/destroy() to internal primitives with an
  explicit anti-pattern section for direct-ID attachment at call sites.
- Add a previously-undocumented "Renderer IPC Surface" section covering
  WindowManager_Open/Close/Show/Hide/etc., with target-resolution rules
  (bare sender vs singleton type).
- Make the pool-recycle-does-not-re-fire-onWindowCreated consequence
  explicit in the Event Timing Contract guarantees.
- Update @see links in WindowManager.ts and types.ts to point at the new
  doc locations directly instead of bouncing through the in-source README.
2026-04-18 08:35:17 -07:00