CmdPal: Multi-monitor support for dock#46054
Conversation
Refactor settings and app state persistence from data models into service classes, improving separation of concerns and testability. Changes: - Add PersistenceService: shared generic JSON load/save with merge semantics, replacing duplicated logic in SettingsModel and AppStateModel - Add SettingsService: owns settings lifecycle, file I/O, migrations, and the SettingsChanged event (previously on SettingsModel itself) - Add AppStateService: owns app state lifecycle and StateChanged event (previously on AppStateModel itself) - Add CmdPalLogger: ILogger adapter over ManagedCommon.Logger, replacing scattered Debug.WriteLine calls with structured logging - Extract JsonSerializationContext into its own file - Update all consumers to inject services instead of raw models - Fix missing SettingsChanged unsubscription in AppearanceSettingsViewModel.Dispose() - Fix SearchBar caching stale settings by subscribing to SettingsChanged Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Added orchestration logs for Morpheus, Trinity, Oracle (2026-03-10T15:43Z) - Created session log for multi-monitor settings UI feature work - Merged 4 inbox decisions into decisions.md (D-004 through D-007) - Deleted inbox files after merge - Updated cross-agent awareness in morpheus/trinity/oracle history.md files Session Summary: ✅ DockMonitorConfigViewModel with SideOverrideIndex binding (0–4 index mapping) ✅ SettingsViewModel IMonitorService injection + RefreshMonitorConfigs() ✅ Monitors UI section with ItemsRepeater showing per-monitor controls ✅ 8 localization strings for monitor configuration ✅ 27 unit tests for multi-monitor dock logic (all passing) ✅ Fixed pre-existing build warnings (CS0169, SA1512) ✅ AOT discipline applied (no LINQ, partial keywords verified) All ViewModels and UI projects build clean. Tests execute cleanly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix three bugs in multi-monitor dock support: 1. DockWindowManager: Pass config.Side (nullable) instead of config.ResolveSide() so EffectiveSide follows global setting dynamically when no per-monitor override is configured. 2. DockWindow constructor: Destroy and recreate AppBar after _targetMonitor and _sideOverride are set, since the base constructor positions the AppBar on the primary monitor before these fields are available. 3. UpdateSettingsOnUiThread: Use EffectiveSide instead of _settings.Side for edge comparison so it matches what UpdateWindowPosition actually uses. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Defer dock initialization from ShellPage constructor to Loaded event to ensure WinUI framework is fully materialized (Bug 1: startup) - Subscribe DockWindowManager to SettingsService.SettingsChanged so SyncDocksToSettings runs when per-monitor configs or side changes (Bug 3: monitor toggle, Bug 4: position change) - Add MonitorConfigReconciler to handle unstable GDI DeviceIds across reboots by falling back to IsPrimary matching and pruning orphans (Bug 2: persistence) - Add IsPrimary field to DockMonitorConfig for stable matching key - Add 6 unit tests for MonitorConfigReconciler - Include remaining multi-monitor settings UI (DockSettingsPage, DockMonitorConfigViewModel, MonitorService, IMonitorService) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add _closed guard to DockWindow.UpdateSettingsOnUiThread to prevent accessing SystemBackdrop after the WinUI window has been torn down. Race: DockWindowManager closes the window via HideDocks, then the already-enqueued UpdateSettingsOnUiThread runs on disposed state. - Refresh _sideOverride from MonitorConfigs in SettingsChangedHandler so EffectiveSide returns the current per-monitor side, not the stale construction-time snapshot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Create ExitDockEditModeMessage and broadcast from button click handlers so Save/Discard closes the teaching tip on ALL dock windows, not just the local one - Broadcast from click handlers only (not from ExitEditMode/ DiscardEditMode) to prevent reentrancy infinite loop Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
.squad/agents/morpheus/history.md
Outdated
| ## Session Work (2026-03-10T15:43Z) | ||
|
|
||
| **Task:** Build DockMonitorConfigViewModel + update SettingsViewModel | ||
| **Outcome:** Created full ViewModel with SideOverrideIndex binding (0–4 index mapping to nullable DockSide for "inherit" semantics). Updated SettingsViewModel with IMonitorService injection and RefreshMonitorConfigs(). Both projects build clean. Fixed pre-existing CS0169/SA1512 build warnings that were blocking Oracle's tests. |
Check failure
Code scanning / check-spelling
Forbidden Pattern
.squad/agents/oracle/history.md
Outdated
| - Test project: `Tests/Microsoft.CmdPal.UI.ViewModels.UnitTests` — MSTest + Moq, references ViewModels project | ||
| - Added `DockMultiMonitorTests.cs` with 27 tests covering `ScreenRect`, `MonitorInfo`, `DockMonitorConfig.ResolveSide`, `DockSettings` defaults, effective-config fallback logic, and `DockBandSettings` resolve pattern | ||
| - `DockWindowManager` is not directly unit-testable (creates `DockWindow` UI objects); tested the pure data logic it depends on instead | ||
| - Pre-existing build errors in ViewModels project (`CS0169` in SettingsViewModel, `SA1512` in DockMonitorConfigViewModel) block full test build — not caused by test code |
Check failure
Code scanning / check-spelling
Forbidden Pattern
.squad/agents/oracle/history.md
Outdated
| ## Session Work (2026-03-10T15:43Z) | ||
|
|
||
| **Task:** Write unit tests for multi-monitor dock types | ||
| **Outcome:** Created DockMultiMonitorTests.cs with 27 tests covering ScreenRect, MonitorInfo, DockMonitorConfig.ResolveSide, DockSettings defaults, and DockBandSettings. Tests compile clean. Identified and reported pre-existing CS0169/SA1512 build errors; Morpheus fixed these. All 27 tests pass. |
Check failure
Code scanning / check-spelling
Forbidden Pattern
.squad/commit-message.txt
Outdated
| ✅ Monitors UI section with ItemsRepeater showing per-monitor controls | ||
| ✅ 8 localization strings for monitor configuration | ||
| ✅ 27 unit tests for multi-monitor dock logic (all passing) | ||
| ✅ Fixed pre-existing build warnings (CS0169, SA1512) |
Check failure
Code scanning / check-spelling
Forbidden Pattern
.squad/decisions.md
Outdated
| - **Decision:** | ||
| 1. **Project boundary:** We ONLY work on projects listed in `src/modules/cmdpal/CommandPalette.slnf`. No other PowerToys modules may be touched. | ||
| 2. **No commits to main:** Never commit directly to the `main` branch. All work must be on a feature branch. | ||
| 3. **Branch naming:** `dev/mjolley/{branch-title-here}` — lowercase, hyphen-separated title describing the work. |
Check failure
Code scanning / check-spelling
Unrecognized Spelling
.squad/decisions.md
Outdated
| ### D-003: Base branch is dev/mjolley/persistence | ||
| - **Date:** 2026-03-10 | ||
| - **By:** Neo (directive from project owner) | ||
| - **Decision:** All multi-monitor dock work branches from `dev/mjolley/persistence`, NOT `main`. This branch has settings/app-state/personalization persistence changes we depend on. Feature branches for this work: `dev/mjolley/{feature-name}` created from this base. |
Check failure
Code scanning / check-spelling
Unrecognized Spelling
.squad/decisions.md
Outdated
| - **Date:** 2026-03-10 | ||
| - **By:** Neo (directive from project owner) | ||
| - **Decision:** All multi-monitor dock work branches from `dev/mjolley/persistence`, NOT `main`. This branch has settings/app-state/personalization persistence changes we depend on. Feature branches for this work: `dev/mjolley/{feature-name}` created from this base. | ||
| - **Enforcement:** Before creating a feature branch, confirm current branch is `dev/mjolley/persistence`. |
Check failure
Code scanning / check-spelling
Unrecognized Spelling
.squad/decisions.md
Outdated
| 3. **Any new list/collection type used in persisted settings must be explicitly registered in `JsonSerializationContext`.** | ||
| - **Enforcement:** All agents working on CmdPal must check for LINQ usage and missing `partial` keywords before marking work as done. | ||
|
|
||
| ### D-006: ViewModels project had pre-existing build errors (RESOLVED) |
Check failure
Code scanning / check-spelling
Forbidden Pattern
.squad/routing.md
Outdated
| 3. When a `squad:{member}` label is applied, that member picks up the issue in their next session. | ||
| 4. When `squad:copilot` is applied and auto-assign is enabled, `@copilot` is assigned on the issue and picks it up autonomously. | ||
| 5. Members can reassign by removing their label and adding another member's label. | ||
| 6. The `squad` label is the "inbox" — untriaged issues waiting for Lead review. |
Check failure
Code scanning / check-spelling
Unrecognized Spelling
|
|
||
| ### Code Style | ||
|
|
||
| <!-- Example: Linting, formatting, naming conventions --> |
Check failure
Code scanning / check-spelling
Unrecognized Spelling
Add per-monitor band customization so each monitor dock can show different pinned commands. Monitors inherit global bands by default and can be individually customized via the settings UI. Changes: - DockMonitorConfig: add IsCustomized, StartBands/CenterBands/EndBands, ForkFromGlobal(), and Resolve*Bands() helpers - DockViewModel: convert from singleton to per-monitor instances with GetActiveBandLists() routing and EnsureMonitorForked() auto-fork - DockWindowManager: create per-monitor DockViewModels, pass to windows - DockWindow: accept DockViewModel as constructor parameter - App.xaml.cs: remove singleton DockViewModel DI registration - Settings UI: add Customize bands toggle per monitor with band toggles - MonitorBandSettingsViewModel: per-monitor band pin/unpin ViewModel - JsonSerializationContext: register DockBandSettings list type - 14 unit tests covering band resolution, fork independence, reconciler Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
106f771 to
d5cedfd
Compare
- Move band initialization from DockViewModel constructor to DockWindowManager after window.Show() via InitializeBands(), avoiding ExecutionEngineException in AOT - Remove per-monitor band list from settings UI — users manage bands through dock edit mode instead - Keep Customize Bands toggle (label left, toggle right) to fork/unfork per-monitor band config from global - Clean up unused BandItems, PopulateBandItems, GetAvailableBands, MonitorCustomizeBands_Toggled, and 3 RESW strings Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
d5cedfd to
67c1afd
Compare
|
/azp run |
|
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command. |
Adding multi-monitor support for dock. Users can enable dock on any monitor and determine where on each monitor it should display, or have them default to the overall position.
Closes: #45836