feat(macos): port Ghostty's macOS code paths (Metal, CoreText, Darwin)
Ports the macOS-specific Zig code behind cfg(target_os = "macos"): - renderer: a GraphicsApi trait with generic::Renderer<G>; Metal backend (all renderer/metal/* files, shaders.metal verbatim, runtime library compile, IOSurface layer, CVDisplayLink), shadertoy -> MSL via naga; OpenGL remains the backend elsewhere. - font: CoreText face, shaper and discovery with build.rs backend selection (coretext default; coretext-freetype / coretext-harfbuzz / coretext-noshape features), no fontconfig/freetype/harfbuzz on Apple. - input: KeymapDarwin via UCKeyTranslate, option-as-alt, mac keycodes. - os: macos, mach, cf_release_thread, NSProcessInfo args and macOS branches; config: macOS defaults, keybinds, Application Support paths. - termio/core: login(1) wrapping, openpty/execvpe, Darwin child exit handling, os_log logging. Compile-checked for aarch64/x86_64-apple-darwin (clippy -D warnings clean) using the cross setup in docs/rewrite/notes/macos-M1.md; cannot run here. The embedded runtime/C API (embedded.zig) is the next step. Also includes the cross-platform integration edits shared by the crash, verification, Windows and macOS work (Cargo target-gating, thread crash-context hooks, apprt-gtk surface/IME refactor, termio/os cfg gates), a cfg fix so ghostty-config builds on wasm32, and an allow for the intentional recursion in the crash overflow test. Test Plan: - cargo test --workspace (3224 passed) - cargo clippy --workspace --all-targets -- -D warnings - cargo check --target aarch64-apple-darwin -p ghostty-renderer (with the documented cross env)
This commit is contained in:
1 parent
3c8fae1089
commit
452b782149
124 files changed
+14936
-1242
No files matched your search
@@ -3,6 +3,23 @@
|
||||
/// On Linux GTK, this returns true if the program was launched using the
|
||||
/// desktop file. This also includes when `gtk-launch` is used because I
|
||||
/// can't find a way to distinguish the two scenarios.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn launched_from_desktop() -> bool {
|
||||
// macOS apps launched from finder or `open` always have the init
|
||||
// process as their parent.
|
||||
macos_launched_from_desktop(false, std::env::var_os(MAC_LAUNCH_SOURCE_ENV), || {
|
||||
rustix::process::getppid().map_or(0, rustix::process::Pid::as_raw_pid)
|
||||
})
|
||||
}
|
||||
|
||||
/// iPhone/iPad is always launched from the "desktop".
|
||||
#[cfg(target_os = "ios")]
|
||||
pub fn launched_from_desktop() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// See the other variants.
|
||||
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
|
||||
pub fn launched_from_desktop() -> bool {
|
||||
// On Linux and BSD, GTK sets GIO_LAUNCHED_DESKTOP_FILE and
|
||||
// GIO_LAUNCHED_DESKTOP_FILE_PID. We only check the latter to see if
|
||||
@@ -14,14 +31,49 @@ pub fn launched_from_desktop() -> bool {
|
||||
return false;
|
||||
};
|
||||
|
||||
let pid = rustix::process::getpid().as_raw_nonzero().get();
|
||||
let Ok(gio_pid) = gio_pid_str.to_string_lossy().parse::<i32>() else {
|
||||
// (`std::process::id` is `getpid` / `GetCurrentProcessId`.)
|
||||
let pid = std::process::id();
|
||||
let Ok(gio_pid) = gio_pid_str.to_string_lossy().parse::<u32>() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
gio_pid == pid
|
||||
}
|
||||
|
||||
/// Environment variable set by the macOS app to tell libghostty how it was
|
||||
/// launched ("app", "cli" or "zig_run").
|
||||
pub const MAC_LAUNCH_SOURCE_ENV: &str = "GHOSTTY_MAC_LAUNCH_SOURCE";
|
||||
|
||||
/// `launched_from_desktop` on macOS. `artifact_is_lib` mirrors
|
||||
/// `build_config.artifact == .lib`: when embedded as a library, the app
|
||||
/// bundle may tell us via [`MAC_LAUNCH_SOURCE_ENV`] that it launched us even
|
||||
/// though our parent isn't `launchd`.
|
||||
#[cfg_attr(not(any(target_os = "macos", test)), allow(dead_code))]
|
||||
fn macos_launched_from_desktop(
|
||||
artifact_is_lib: bool,
|
||||
source: Option<std::ffi::OsString>,
|
||||
getppid: impl FnOnce() -> i32,
|
||||
) -> bool {
|
||||
if artifact_is_lib && let Some(source) = source {
|
||||
// Source can be "app", "cli", or "zig_run". We assume its the
|
||||
// desktop only if its "app".
|
||||
if source == "app" {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
getppid() == 1
|
||||
}
|
||||
|
||||
/// The libghostty variant of [`launched_from_desktop`] on macOS (honours the
|
||||
/// `GHOSTTY_MAC_LAUNCH_SOURCE` environment variable).
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn launched_from_desktop_lib() -> bool {
|
||||
macos_launched_from_desktop(true, std::env::var_os(MAC_LAUNCH_SOURCE_ENV), || {
|
||||
rustix::process::getppid().map_or(0, rustix::process::Pid::as_raw_pid)
|
||||
})
|
||||
}
|
||||
|
||||
/// The list of desktop environments that we detect. New Linux desktop
|
||||
/// environments should only be added to this list if there's a specific reason
|
||||
/// to differentiate between `gnome` and `other`.
|
||||
@@ -37,6 +89,13 @@ pub enum DesktopEnvironment {
|
||||
/// on Linux and BSD to enable or disable certain features but there may be more uses in
|
||||
/// the future.
|
||||
pub fn desktop_environment() -> DesktopEnvironment {
|
||||
if cfg!(windows) {
|
||||
return DesktopEnvironment::Windows;
|
||||
}
|
||||
if cfg!(target_os = "macos") {
|
||||
return DesktopEnvironment::Macos;
|
||||
}
|
||||
|
||||
// Use $XDG_SESSION_DESKTOP to determine what DE we are using on Linux
|
||||
// https://www.freedesktop.org/software/systemd/man/latest/pam_systemd.html#desktop=
|
||||
if let Some(sd) = std::env::var_os("XDG_SESSION_DESKTOP") {
|
||||
@@ -69,6 +128,8 @@ pub fn desktop_environment() -> DesktopEnvironment {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[cfg(unix)]
|
||||
#[allow(dead_code)]
|
||||
fn de(session: Option<&str>, current: Option<&str>) -> DesktopEnvironment {
|
||||
temp_env::with_vars(
|
||||
[
|
||||
@@ -79,6 +140,8 @@ mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
#[test]
|
||||
fn desktop_environment_detection() {
|
||||
use DesktopEnvironment::{Gnome, Other};
|
||||
@@ -93,6 +156,24 @@ mod tests {
|
||||
assert_eq!(de(Some("foobar"), Some("GNOME")), Gnome);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn macos_launch_detection() {
|
||||
use std::ffi::OsString;
|
||||
// Parent is launchd.
|
||||
assert!(macos_launched_from_desktop(false, None, || 1));
|
||||
assert!(!macos_launched_from_desktop(false, None, || 4242));
|
||||
// The env var only counts for the lib artifact and only for "app".
|
||||
let app = Some(OsString::from("app"));
|
||||
assert!(macos_launched_from_desktop(true, app.clone(), || 4242));
|
||||
assert!(!macos_launched_from_desktop(false, app, || 4242));
|
||||
assert!(!macos_launched_from_desktop(
|
||||
true,
|
||||
Some(OsString::from("cli")),
|
||||
|| 4242
|
||||
));
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
#[test]
|
||||
fn launched_from_desktop_pid_match() {
|
||||
let pid = std::process::id().to_string();
|
||||
|
||||
Reference in new issue
Block a user