diff --git a/CHANGELOG.md b/CHANGELOG.md index d775335f..19f6170f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ Programa is a fork of [cmux](https://github.com/manaflow-ai/cmux); for history p - The `programa codex install-hooks` and `uninstall-hooks` legacy aliases. Use `programa codex install-integration` and `uninstall-integration`. ### Fixed +- The Window menu's Fill, Center, Move & Resize, Full Screen Tile and Move to Display items, and their shortcuts, work again. The main window had been marked not movable, which makes macOS disable all of them. - The notifications popover now opens in minimal mode, the default layout. Show Notifications (⌘I), the sidebar bell and the menu bar icon's Show Notifications did nothing there. - Port chips in the sidebar now show up again for terminals restored after relaunching Programa. The restored terminals kept their running shell, but port scanning never learned about them. - A window closed with the red button no longer comes back on the next launch. Since 0.5.0 a closed window was kept alive for Dock reopen and then saved and restored like a visible one, so every restart opened an extra window of stale workspaces. Closed windows now stay closed across a relaunch and their shells are ended at startup. diff --git a/Sources/AppDelegate.swift b/Sources/AppDelegate.swift index 5dd94b64..e17a6f3c 100644 --- a/Sources/AppDelegate.swift +++ b/Sources/AppDelegate.swift @@ -4741,8 +4741,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate, @preconcurrency UNUser window.title = "" window.titleVisibility = .hidden window.titlebarAppearsTransparent = true + // Keep the window movable: AppKit validates Window > Fill / Center / + // Move & Resize / Move to Display (and their shortcuts) against + // `isMovable`. Native titlebar drag stays off because + // MainWindowHostingView returns false from `mouseDownCanMoveWindow`; + // explicit drag surfaces use `performDrag` instead. window.isMovableByWindowBackground = false - window.isMovable = false let restoredFrame = resolvedWindowFrame(from: sessionWindowSnapshot) if let restoredFrame { window.setFrame(restoredFrame, display: false) @@ -7975,16 +7979,14 @@ final class AppDelegate: NSObject, NSApplicationDelegate, @preconcurrency UNUser if !window.titlebarAppearsTransparent { window.titlebarAppearsTransparent = true } - // Keep window immovable; the sidebar's WindowDragHandleView handles - // drag-to-move via performDrag with temporary movable override. - // isMovableByWindowBackground=true breaks tab reordering, and - // isMovable=true blocks clicks on sidebar buttons in minimal mode. + // isMovableByWindowBackground=true breaks sidebar tab reordering, so + // drag-to-move goes through WindowDragHandleView's performDrag. The + // window itself stays movable (see createMainWindow) so the Window menu + // tiling items validate; MainWindowHostingView's mouseDownCanMoveWindow + // override keeps clicks on sidebar buttons from becoming native drags. if window.isMovableByWindowBackground { window.isMovableByWindowBackground = false } - if window.isMovable { - window.isMovable = false - } if !window.styleMask.contains(.fullSizeContentView) { window.styleMask.insert(.fullSizeContentView) } diff --git a/Sources/MainWindowHostingView.swift b/Sources/MainWindowHostingView.swift index e05b1f99..e7ea4eaf 100644 --- a/Sources/MainWindowHostingView.swift +++ b/Sources/MainWindowHostingView.swift @@ -19,6 +19,12 @@ final class MainWindowHostingView: NSHostingView, MainWi override var safeAreaRect: NSRect { bounds } override var safeAreaLayoutGuide: NSLayoutGuide { zeroSafeAreaLayoutGuide } + /// The window stays `isMovable` so AppKit enables the Window menu tiling + /// items, but SwiftUI content under the transparent titlebar must not turn + /// a click into a native window drag (sidebar buttons in minimal mode). + /// Explicit drag surfaces call `performDrag` themselves. + override var mouseDownCanMoveWindow: Bool { false } + required init(rootView: Content) { super.init(rootView: rootView) // Tell SwiftUI to ignore safe areas outright, rather than relying only on