This page documents the FancyZones Editor, a standalone WPF application that allows users to create, modify, and apply zone layouts. It covers the application startup sequence, the main layout picker window, the zone-editing subsystems for grid and canvas layouts, the layout model hierarchy, and how all data is serialized back to disk.
For how FancyZones stores and loads applied layouts, app zone history, and virtual desktop data at runtime, see Layout and Persistence System. For the FancyZones module itself (window snapping, hooks, and the C++ core), see FancyZones.
The editor is a separate process launched by the FancyZones module. Its source lives under src/modules/fancyzones/editor/FancyZonesEditor/.
Application-level component map:
Sources: src/modules/fancyzones/editor/FancyZonesEditor/App.xaml.cs30-84 src/modules/fancyzones/editor/FancyZonesEditor/Overlay.cs1-50
The App class (App.xaml.cs) is the WPF application entry point. The OnStartup handler performs the following steps in order:
GPOWrapper policy disables FancyZones, the process exits immediately.ThemeManager is instantiated to apply light/dark/high-contrast themes.RunnerHelper.WaitForPowerToysRunner spawns a thread that shuts down the editor if the parent runner process exits.FancyZonesEditorIO.ParseParams() reads EditorParameters JSON to determine monitor layout and the active virtual desktop.ParseLayoutTemplates() โ built-in template settingsParseCustomLayouts() โ user-defined layoutsParseDefaultLayouts() โ per-orientation default assignmentsParseLayoutHotkeys() โ Win+Ctrl+Alt+[0โ9] bindingsParseAppliedLayouts() โ which layout is currently applied to each monitorOverlay.Show() creates the transparent per-monitor windows and opens MainWindow.Sources: src/modules/fancyzones/editor/FancyZonesEditor/App.xaml.cs88-155
All layouts derive from the abstract LayoutModel base class.
Sources: src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs17-419 src/modules/fancyzones/editor/FancyZonesEditor/Models/GridLayoutModel.cs14-260 src/modules/fancyzones/editor/FancyZonesEditor/Models/CanvasLayoutModel.cs12-207
| Value | Name | Model class | Notes |
|---|---|---|---|
| 0 | Blank | CanvasLayoutModel | No zones; represents "No layout" |
| 1 | Focus | CanvasLayoutModel | Single focus zone with surrounding zones |
| 2 | Columns | GridLayoutModel | Equal-width vertical columns |
| 3 | Rows | GridLayoutModel | Equal-height horizontal rows |
| 4 | Grid | GridLayoutModel | Equal-sized grid cells |
| 5 | PriorityGrid | GridLayoutModel | Pre-baked asymmetric grid configurations |
| 6 | Custom | Either | User-created layouts |
Sources: src/modules/fancyzones/editor/FancyZonesEditor/Models/MainWindowSettingsModel.cs46-100
GridLayoutModel stores zone sizes as integer fractions of GridMultiplier (10000). A column occupying 30% of the screen has ColumnPercents[col] = 3000. The CellChildMap[row, col] integer array maps grid cells to zone indices, allowing zones to span multiple cells via shared index values.
PriorityGrid configurations are stored as hard-coded byte arrays in _priorityData for 1โ11 zones.
Sources: src/modules/fancyzones/editor/FancyZonesEditor/Models/GridLayoutModel.cs22-35 src/modules/fancyzones/editor/FancyZonesEditor/Models/GridLayoutModel.cs75-84
MainWindow (MainWindow.xaml / MainWindow.xaml.cs) is the layout picker. It is data-bound to MainWindowSettingsModel.
The window contains:
GridView bound to MonitorViewModel.MonitorInfoForViewModel showing all detected monitors. Clicking a monitor changes Overlay.CurrentDesktop.GridView bound to MainWindowSettingsModel.TemplateModels.GridView bound to MainWindowSettingsModel.CustomModels.NewLayoutButton) at bottom-right.Each layout card renders a LayoutPreview thumbnail and an Edit button.
| Action | Handler | What it does |
|---|---|---|
| Click a layout card | Layout_ItemClick | Calls Select() then Apply() |
| Click Edit (pencil icon) | EditLayout_Click | Opens EditLayoutDialog |
| Click "Edit zones" in dialog | EditZones_Click | Hides main window, calls Overlay.OpenEditor() |
| Click "Duplicate" | DuplicateLayout_Click | Calls model.Clone(), then model.Persist() + SerializeCustomLayouts() |
| Click "Delete" | DeleteLayout_Click | Shows confirmation, calls model.Delete(), re-serializes all data |
| Click "Create new layout" | NewLayoutButton_Click | Opens NewLayoutDialog to choose name and type |
| Window close | OnClosing | Serializes all five data files, then calls App.Current.Shutdown() |
When Apply() is called:
_settings.SetAppliedModel(model) โ marks the model as applied in-memoryApp.Overlay.Monitors[CurrentDesktop].SetLayoutSettings(model) โ writes layout settings to the monitor recordSerializeAppliedLayouts() โ writes applied-layouts.jsonSerializeCustomLayouts() โ writes custom-layouts.jsonSources: src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml.cs302-311
The EditLayoutDialog (ContentDialog) is shown inline inside MainWindow. It exposes:
QuickKey property on LayoutModel maps to Win+Ctrl+Alt+[0โ9]TemplateZoneCountSpacing and ShowSpacing on GridLayoutModelOn Save (EditLayoutDialog_PrimaryButtonClick), all five data files are serialized. On Cancel (EditLayoutDialog_SecondaryButtonClick), Overlay.EndEditing() restores the backup.
Sources: src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml373-457 src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml.cs429-457
Overlay (Overlay.cs) manages the transparent fullscreen windows placed over each monitor, and the editor windows used for zone customization.
| Property | Type | Description |
|---|---|---|
Monitors | List<Monitor> | One entry per physical monitor / virtual desktop pair |
CurrentDesktop | int | Index of the active monitor in Monitors |
WorkArea | Rect | Work area rect of Monitors[CurrentDesktop] |
SpanZonesAcrossMonitors | bool | When true, a single logical monitor covers all screens |
MultiMonitorMode | bool | True when multiple monitors, not spanning |
Show() โ Creates the LayoutPreview control, subscribes to property changes, calls ShowLayout() then OpenMainWindow().OpenEditor(LayoutModel) โ Creates a GridEditor or CanvasEditor control, creates a GridEditorWindow or CanvasEditorWindow, and places the editor control into the current monitor window.StartEditing(LayoutModel) โ Calls _layoutBackup.Backup(model) to snapshot the current state.EndEditing(LayoutModel) โ Restores from backup if a model is provided; otherwise accepts the edits.CloseEditor() โ Closes the editor window and restores LayoutPreview to the monitor window.Sources: src/modules/fancyzones/editor/FancyZonesEditor/Overlay.cs138-260
When the user selects "Edit zones," Overlay.OpenEditor() creates the appropriate editor based on the layout model type.
Files: GridEditor.xaml.cs, GridZone.xaml.cs, GridResizer.xaml, GridData.cs
The GridEditor (UserControl) places a Canvas (Preview) at the exact pixel size of the monitor work area. Each zone is a GridZone element positioned via Canvas.SetLeft/Top. Resizer handles (GridResizer, a Thumb) float between zones.
Zone splitting: Hovering over a GridZone shows a splitter line. Clicking fires the Split event, which calls GridData.Split(zoneIndex, offset, orientation).
Zone merging: Dragging across multiple zones selects them (highlighted in accent color). On mouse-up, a Merge confirmation panel appears. GridData.DoMerge(indices) then collapses the selected zones into one.
Resizer dragging: Resizer_DragDelta accumulates pixel deltas, converts them to GridData multiplier units, and calls GridData.Drag(resizerIndex, delta).
Keyboard navigation:
Tab / Ctrl+Tab โ cycles focus between zones and resizersDelete on focused resizer โ merges adjacent zonesShift+S on focused zone โ splits the zone at its midpointSources: src/modules/fancyzones/editor/FancyZonesEditor/GridEditor.xaml.cs40-480 src/modules/fancyzones/editor/FancyZonesEditor/GridZone.xaml.cs63-280
GridData is the internal model for the grid editor. It converts the GridLayoutModel (rows/cols/percents/cell map) into a flat list of Zone structs and a list of Resizer structs. Zone boundaries are expressed in [0, 10000] coordinates.
| Class | Role |
|---|---|
GridData.Zone | Left, Top, Right, Bottom in multiplier units; Index |
GridData.Resizer | Orientation, PositiveSideIndices, NegativeSideIndices |
MagneticSnap | Converts pixel positions to snapped grid positions |
Sources: src/modules/fancyzones/editor/FancyZonesEditor/GridData.cs78-113
Files: CanvasEditor.xaml.cs, CanvasZone.xaml.cs
The CanvasEditor renders each Int32Rect zone in CanvasLayoutModel.Zones as a CanvasZone control on a Canvas. Zones can overlap.
CanvasEditor.UpdateZoneRects() calls model.ScaleLayout(workAreaWidth, workAreaHeight) to normalize zones to the current work area dimensions, then positions each CanvasZone via Canvas.SetLeft/Top.
CanvasZone supports:
Snapping uses two strategy classes:
SnappyHelperMagnetic โ snaps to edges of other zones and monitor boundaries with a magnetic pull zoneSnappyHelperNonMagnetic โ simple clamping without snappingZones in the CanvasEditorWindow can be added via the + button (OnAddZone), which calls CanvasLayoutModel.AddZone(). Zone count is capped at LayoutDefaultSettings.MaxZones.
Sources: src/modules/fancyzones/editor/FancyZonesEditor/CanvasEditor.xaml.cs22-113 src/modules/fancyzones/editor/FancyZonesEditor/CanvasZone.xaml.cs60-265
Both GridEditorWindow and CanvasEditorWindow inherit from EditorWindow. EditorWindow.OnSave():
EditingLayout.Type = LayoutType.Custom if it was Blank (new custom layout case)EditingLayout.Persist() โ PersistData() โ AddCustomLayout(this)SerializeLayoutTemplates() and SerializeCustomLayouts()EditorWindow.OnCancel() calls Overlay.EndEditing(EditingLayout) which restores the LayoutBackup snapshot, then re-selects the applied model.
Sources: src/modules/fancyzones/editor/FancyZonesEditor/EditorWindow.cs21-56
FancyZonesEditorIO (Utils/FancyZonesEditorIO.cs) handles all reading and writing. It delegates to data wrapper classes from FancyZonesEditorCommon.Data.
| Parse method | Data class | Purpose |
|---|---|---|
ParseParams() | EditorParameters | Monitor geometry, virtual desktop IDs, active monitor |
ParseLayoutTemplates() | LayoutTemplates | Saved zone counts and spacing for template types |
ParseCustomLayouts() | CustomLayouts | User-defined grid and canvas layouts |
ParseDefaultLayouts() | DefaultLayouts | Default layout UUIDs for horizontal/vertical orientations |
ParseLayoutHotkeys() | LayoutHotkeys | Key (0โ9) โ Layout UUID bindings |
ParseAppliedLayouts() | AppliedLayouts | Per-monitor applied layout settings |
| Serialize method | Trigger |
|---|---|
SerializeAppliedLayouts() | Apply layout, save edit dialog, window close |
SerializeCustomLayouts() | Apply, duplicate, delete, save edit dialog, save editor, window close |
SerializeLayoutTemplates() | Save edit dialog, save editor, window close |
SerializeLayoutHotkeys() | Save edit dialog, window close |
SerializeDefaultLayouts() | Set/reset default layout, delete layout, save edit dialog, window close |
Sources: src/modules/fancyzones/editor/FancyZonesEditor/Utils/FancyZonesEditorIO.cs263-460 src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml.cs313-324
SerializeAppliedLayouts() iterates App.Overlay.Monitors and writes each monitor's current LayoutSettings (ZonesetUuid, Type, ShowSpacing, Spacing, ZoneCount, SensitivityRadius) along with its Device identity (monitor name, instance ID, serial number, monitor number, virtual desktop ID). Monitors that were loaded but not shown in the current editor session are preserved in _unusedLayouts and re-emitted verbatim.
Sources: src/modules/fancyzones/editor/FancyZonesEditor/Utils/FancyZonesEditorIO.cs263-319
MainWindowSettingsModel (Models/MainWindowSettingsModel.cs) is the DataContext for MainWindow. It holds:
static TemplateModels โ ObservableCollection<LayoutModel> of the six built-in templates, initialized in the constructor.static CustomModels โ ObservableCollection<LayoutModel> of user-defined layouts.static LayoutHotkeys โ LayoutHotkeysModel mapping keys to layout UUIDs.static DefaultLayouts โ DefaultLayoutsModel tracking the default layout per monitor orientation.SelectedModel / AppliedModel โ currently selected and applied models.IsShiftKeyPressed โ tracks Shift key state for grid editor split direction.Sources: src/modules/fancyzones/editor/FancyZonesEditor/Models/MainWindowSettingsModel.cs18-100
LayoutBackup (LayoutBackup.cs) creates deep copies of a LayoutModel before editing begins (via Backup(model)). On cancel, Restore(model) calls grid.RestoreTo(other) or canvas.RestoreTo(other) to revert all fields, and also restores the hotkey and default layout assignments.
Sources: src/modules/fancyzones/editor/FancyZonesEditor/LayoutBackup.cs12-80
DefaultLayoutsModel (Models/DefaultLayoutsModel.cs) maintains a dictionary keyed by MonitorConfigurationType (Horizontal / Vertical). Set(model, type) assigns a layout as the default for that orientation. Reset() clears the assignment. Changes fire PropertyChanged, which LayoutModel.DefaultLayouts_PropertyChanged listens to in order to update IsHorizontalDefault / IsVerticalDefault on all models.
Sources: src/modules/fancyzones/editor/FancyZonesEditor/Models/DefaultLayoutsModel.cs1-80 src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs161-191
LayoutPreview (LayoutPreview.xaml.cs) is a UserControl used both in the layout cards in MainWindow and as the live preview drawn over each monitor. It subscribes to LayoutModel.PropertyChanged and calls RenderPreview() on each change.
GridLayoutModel: calls RenderSmallScalePreview (thumbnail) or RenderActualScalePreview (full-size overlay using a Viewbox).CanvasLayoutModel: calls RenderCanvasPreview, placing Border rectangles for each zone.Sources: src/modules/fancyzones/editor/FancyZonesEditor/LayoutPreview.xaml.cs94-260
New custom layout flow:
Sources: src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml.cs204-415 src/modules/fancyzones/editor/FancyZonesEditor/EditorWindow.cs21-43 src/modules/fancyzones/editor/FancyZonesEditor/Overlay.cs185-230
The editor supports four themes via ResourceDictionary files:
Themes/Light.xamlThemes/Dark.xamlThemes/HighContrast1.xaml, HighContrast2.xaml, HighContrastBlack.xaml, HighContrastWhite.xamlThe active theme is applied by ThemeManager instantiated in App.OnStartup. Theme brushes like PrimaryBackgroundBrush, GridZoneBackgroundBrush, and SecondaryForegroundBrush are used throughout XAML via DynamicResource bindings.
Sources: src/modules/fancyzones/editor/FancyZonesEditor/App.xaml.cs99 src/modules/fancyzones/editor/FancyZonesEditor/Themes/Dark.xaml1-30
Refresh this wiki
This wiki was recently refreshed. Please wait 4 days to refresh again.