diff --git a/src/main/commands.ts b/src/main/commands.ts index 4a89f301..68341d3b 100644 --- a/src/main/commands.ts +++ b/src/main/commands.ts @@ -1393,6 +1393,12 @@ async function discoverAndBuildCommands(): Promise { keywords: ['window', 'management', 'maximize', 'fill', 'fullscreen'], category: 'system', }, + { + id: 'system-window-management-fill-stage', + title: 'Window: Maximize (Stage Manager)', + keywords: ['window', 'management', 'maximize', 'fill', 'stage manager', 'stage', 'strip', 'respect'], + category: 'system', + }, { id: 'system-window-management-maximize-width', title: 'Window: Maximize Width', diff --git a/src/main/main.ts b/src/main/main.ts index cf510437..31b24cab 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -3307,6 +3307,7 @@ const WINDOW_MANAGEMENT_PRESET_COMMAND_IDS = new Set([ 'system-window-management-center', 'system-window-management-center-80', 'system-window-management-fill', + 'system-window-management-fill-stage', 'system-window-management-maximize-width', 'system-window-management-maximize-height', 'system-window-management-top-left', @@ -3372,6 +3373,7 @@ const WINDOW_MANAGEMENT_LAYOUT_COMMAND_IDS = new Set([ 'system-window-management-center', 'system-window-management-center-80', 'system-window-management-fill', + 'system-window-management-fill-stage', 'system-window-management-maximize-width', 'system-window-management-maximize-height', 'system-window-management-top-left', @@ -3939,6 +3941,18 @@ function computeWindowManagementLayoutBounds( width: area.width, height: area.height, }; + case 'system-window-management-fill-stage': { + // Maximize while leaving the Stage Manager strip visible: reuse Almost + // Maximize's left inset, extend top/right/bottom to the work-area edges. + const inset = Math.round((area.width - Math.round(area.width * 0.9)) / 2); + const x = area.x + inset; + return { + x, + y: area.y, + width: Math.max(1, areaRight - x), + height: area.height, + }; + } case 'system-window-management-maximize-width': { // Span the full work-area width, keep the current vertical position/height. if (!windowBounds) return null; diff --git a/src/native/window-adjust.swift b/src/native/window-adjust.swift index 2bc48a9a..0b454a8c 100644 --- a/src/native/window-adjust.swift +++ b/src/native/window-adjust.swift @@ -10,6 +10,7 @@ private enum AdjustAction: String { case center = "center" case center80 = "center-80" case fill = "fill" + case fillStage = "fill-stage" case maximizeWidth = "maximize-width" case maximizeHeight = "maximize-height" case topLeft = "top-left" @@ -569,6 +570,18 @@ private func adjustedFrame(_ base: WindowFrame, action: AdjustAction, forcedArea height: max(minHeight, round(area.height)) ) } + case .fillStage: + if let area { + // Maximize while leaving the Stage Manager strip visible: reuse Almost + // Maximize's left inset, extend top/right/bottom to the work-area edges. + let inset = round((area.width - round(area.width * 0.9)) / 2) + next = WindowFrame( + x: area.origin.x + inset, + y: area.origin.y, + width: max(minWidth, round(area.width - inset)), + height: max(minHeight, round(area.height)) + ) + } case .maximizeWidth: if let area { // Span the full work-area width, keep the current vertical position/height. diff --git a/src/renderer/src/WindowManagerPanel.tsx b/src/renderer/src/WindowManagerPanel.tsx index 7dad8fa4..b2049491 100644 --- a/src/renderer/src/WindowManagerPanel.tsx +++ b/src/renderer/src/WindowManagerPanel.tsx @@ -49,6 +49,7 @@ type PresetId = | 'center' | 'center-80' | 'fill' + | 'fill-stage' | 'maximize-width' | 'maximize-height' | 'auto-organize' @@ -91,6 +92,7 @@ export const WINDOW_MANAGEMENT_PRESET_COMMANDS: WindowManagementPresetCommand[] { commandId: 'system-window-management-center', presetId: 'center' }, { commandId: 'system-window-management-center-80', presetId: 'center-80' }, { commandId: 'system-window-management-fill', presetId: 'fill' }, + { commandId: 'system-window-management-fill-stage', presetId: 'fill-stage' }, { commandId: 'system-window-management-maximize-width', presetId: 'maximize-width' }, { commandId: 'system-window-management-maximize-height', presetId: 'maximize-height' }, { commandId: 'system-window-management-top-left', presetId: 'top-left' }, @@ -147,6 +149,7 @@ const PRESETS: Array<{ id: PresetId; label: string; subtitle: string }> = [ { id: 'center', label: 'Center', subtitle: 'Current window' }, { id: 'center-80', label: 'Almost Maximize', subtitle: 'Current window' }, { id: 'fill', label: 'Maximize', subtitle: 'Current window' }, + { id: 'fill-stage', label: 'Maximize (Stage Manager)', subtitle: 'Current window' }, { id: 'maximize-width', label: 'Maximize Width', subtitle: 'Current window' }, { id: 'maximize-height', label: 'Maximize Height', subtitle: 'Current window' }, { id: 'top-left', label: 'Top Left', subtitle: 'Current window' }, @@ -309,6 +312,9 @@ function renderPresetIcon(id: PresetId): JSX.Element { case 'fill': cells.push({ x: 1, y: 1, w: 18, h: 12 }); break; + case 'fill-stage': + cells.push({ x: 1, y: 3, w: 2, h: 8 }, { x: 4, y: 1, w: 15, h: 12 }); + break; case 'maximize-width': cells.push({ x: 1, y: 4, w: 18, h: 6 }); break; @@ -1032,6 +1038,13 @@ function getPresetRegion(presetId: PresetId, area: ScreenArea): Rect | null { if (presetId === 'fill') { return { x: area.left, y: area.top, width: area.width, height: area.height }; } + if (presetId === 'fill-stage') { + // Maximize while leaving the Stage Manager strip visible: reuse Almost + // Maximize's left inset (native path uses 90% width), extend the rest. + const inset = Math.round((area.width - Math.round(area.width * 0.9)) / 2); + const x = area.left + inset; + return { x, y: area.top, width: Math.max(1, area.left + area.width - x), height: area.height }; + } if (presetId === 'center') { const width = Math.max(1, Math.round(area.width * 0.6)); const height = Math.max(1, Math.round(area.height * 0.6)); diff --git a/src/renderer/src/utils/command-helpers.tsx b/src/renderer/src/utils/command-helpers.tsx index dfa5bcbc..5c2f0224 100644 --- a/src/renderer/src/utils/command-helpers.tsx +++ b/src/renderer/src/utils/command-helpers.tsx @@ -546,6 +546,7 @@ type WindowManagementGlyphId = | 'center' | 'center-80' | 'fill' + | 'fill-stage' | 'maximize-width' | 'maximize-height' | 'top-left' @@ -597,6 +598,7 @@ const WINDOW_MANAGEMENT_GLYPH_SUFFIXES = new Set([ 'center', 'center-80', 'fill', + 'fill-stage', 'maximize-width', 'maximize-height', 'top-left', @@ -780,6 +782,9 @@ function renderWindowManagementGlyph(glyphId: WindowManagementGlyphId): JSX.Elem case 'fill': cells.push({ x: 1, y: 1, w: 18, h: 12 }); break; + case 'fill-stage': + cells.push({ x: 1, y: 3, w: 2, h: 8 }, { x: 4, y: 1, w: 15, h: 12 }); + break; case 'maximize-width': cells.push({ x: 1, y: 4, w: 18, h: 6 }); break;