Phase 9, MA1: crates/ghostty-macos (AppKit via objc2; empty stub on non-Apple targets) ports the foundation of Ghostty 1.3.1's Swift macOS app (ghostty/macos): main, AppDelegate (+Ghostty) with lifecycle, dock menu, open-file, notifications, shortcut sync and quit/reopen paths; MainMenu.xib as generated menu tables built into NSMenus; the Ghostty.App/Config/Surface wrappers driving libghostty in-process via ghostty-lib; the generic helpers; scripts/macos-bundle.sh to assemble Ghostty.app (dry-run on Linux). Feature areas are stubbed for MA2-MA5. Design and type mapping: docs/rewrite/notes/macos-app-design.md (App Intents is a Swift-only framework and cannot be ported). Compile-checked only (no macOS here): just check-macos passes for aarch64/x86_64-apple-darwin with -D warnings; 125 platform-independent tests run on Linux. Test Plan: - just check-macos - cargo test -p ghostty-macos
46 lines
3.8 KiB
Markdown
46 lines
3.8 KiB
Markdown
# macOS app, MA1: foundation
|
|
|
|
Design and work split: `macos-app-design.md`. Crate `crates/ghostty-macos` (lib `ghostty_macos`, bin `ghostty-macos-app`;
|
|
empty stub off Apple). Compile-checked only (`just check-macos`, aarch64 + x86_64, clippy `-D warnings`, lib + tests + bin);
|
|
never run on a Mac. Platform independent logic is unit-tested on Linux (125+ tests).
|
|
|
|
## Ported (Swift -> Rust)
|
|
|
|
* `App/macOS/main.swift` -> `app/entry.rs`; `AppDelegate.swift` -> `app/app_delegate.rs` (all delegate methods, lifecycle,
|
|
dock menu, open-file with execute confirmation, quit confirmation incl. shutdown/restart AppleEvent check, SIGUSR2 reload,
|
|
local key monitor, bell/dock badge, user notifications via objc2-user-notifications, appearance KVO, config-change handling,
|
|
menu shortcut sync + `performGhosttyBindingMenuKeyEquivalent`, float-on-top, set-as-default-terminal, `validateMenuItem`,
|
|
toggle visibility); `AppDelegate+Ghostty.swift` -> `app/app_delegate_ghostty.rs`.
|
|
* `MainMenu.xib` -> `app/menu_spec/` (tables generated by `scripts/gen-macos-menu-spec.py`, plus `Outlet`, `SYNCED_SHORTCUTS`,
|
|
`MENU_IMAGES`, `MenuShortcutKey`, dock menu; tested) and `app/main_menu.rs` (builds the NSMenus, system menus, NSFontManager).
|
|
* `Ghostty.App/Config/ConfigTypes/Command/Action/Error/Event/Shell/Surface`, `GhosttyPackage`, `NSEvent+Extension`, top of
|
|
`Ghostty.Input`, `SurfaceConfiguration`, a model-only `SurfaceView` -> `ghostty/*` (by forks F1-F3 of MA1; see design doc).
|
|
* `Helpers/*` generic ones -> `helpers/*`; unportable SwiftUI-only helpers listed in the design doc.
|
|
* `scripts/macos-bundle.sh` (Ghostty.app assembly, dry-run off macOS), `scripts/gen-macos-capi-consts.py`,
|
|
`scripts/gen-macos-menu-spec.py`, `scripts/macos-crosscheck.sh` now includes `ghostty-macos` (+ its bin).
|
|
* Stubs with the surface `AppDelegate`/`Ghostty.App` use (owners replace them): `features/terminal` (MA3), `quick_terminal::controller`,
|
|
`settings`, `about`, `secure_input`, `global_keybinds`, `services`, `custom_app_icon` (MA4), `update` (MA5).
|
|
|
|
## Deviations
|
|
|
|
* Menu outlets: the xib's `menuSelectionForSearch` outlet does not exist in Swift (and "Jump to Selection" is unconnected), so
|
|
those two items never get a config shortcut -- kept as upstream (module docs of `menu_spec`).
|
|
* `NSApplicationMain` + nib -> explicit NSApplication/delegate/menu setup in `entry::run` (no `NSMainNibFile`).
|
|
* `application(_:willEncode/didDecodeRestorableState:)`: quick terminal state not encoded yet (TODO(MA4)).
|
|
* `updateAppIcon`: AppIcon persistence is MA4's; only the distributed `iconDidChange` notification is posted.
|
|
* Fork-reported deviations: `Ghostty.Config.backgroundColor` falls back to a fixed light gray (Swift: dynamic
|
|
`windowBackgroundColor`); `window_fullscreen*` getters return raw strings until MA3 (typed `FullscreenMode`);
|
|
`open_config` passes the byte length of the URL (Swift `String.count` truncates non-ASCII paths); desktop notifications hop to the
|
|
main queue before touching the view; `CodableBridge` archives are not byte-compatible with Swift's; `ExpiringTarget` drop only
|
|
invalidates the timer; MIME->UTI lookups use CoreServices C functions; tab-add error is `ObjCException{name,reason}`;
|
|
`PasteboardHandle` is an identity `usize`; user-visible duration format "1 hr, 2 min, 3 sec" matches Foundation en_US
|
|
abbreviated style but the `.hide` fractional rounding is unverified off macOS.
|
|
|
|
## Known gaps / TODO(integration)
|
|
|
|
* Nothing here has run on a Mac; objc2 method signatures were only type-checked.
|
|
* `TODO(MA2)` in `ghostty/surface_view.rs`/`surface.rs`, `TODO(MA3)` terminal stubs and `fullscreen::set_is_tab_bar_hook`,
|
|
`TODO(MA4)` feature stubs, `TODO(MA5)` update.
|
|
* `SurfaceView::set_password_input` does not yet drive `SecureInput` (MA4).
|
|
* The bundle script does not embed Sparkle/the DockTilePlugin (MA5/MA4); no `.lproj` localizations exist in the Swift tree either.
|