mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00

This makes it so `zig build run` can take arguments such as `--config-default-files=false` or any other configuration. Previously, it only accepted commands such as `+version`. Incidentally, this also makes it so that the app in general can now take configuration arguments via the CLI if it is launched as a new instance via `open`. For example: open -n Ghostty.app --args --config-default-files=false This previously didn't work. This is kind of cool. To make this work, the libghostty C API was modified so that initialization requires the CLI args, and there is a new C API to try to execute an action if it was set.
161 lines
6.4 KiB
Zig
161 lines
6.4 KiB
Zig
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
const build_config = @import("../build_config.zig");
|
|
const posix = std.posix;
|
|
|
|
const c = @cImport({
|
|
@cInclude("unistd.h");
|
|
});
|
|
|
|
/// Returns true if the program was launched from a desktop environment.
|
|
///
|
|
/// On macOS, this returns true if the program was launched from Finder.
|
|
///
|
|
/// 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.
|
|
///
|
|
/// For other platforms and app runtimes, this returns false.
|
|
pub fn launchedFromDesktop() bool {
|
|
return switch (builtin.os.tag) {
|
|
// macOS apps launched from finder or `open` always have the init
|
|
// process as their parent.
|
|
.macos => macos: {
|
|
// This special case is so that if we launch the app via the
|
|
// app bundle (i.e. via open) then we still treat it as if it
|
|
// was launched from the desktop.
|
|
if (build_config.artifact == .lib) lib: {
|
|
const env = "GHOSTTY_MAC_LAUNCH_SOURCE";
|
|
const source = posix.getenv(env) orelse break :lib;
|
|
|
|
// Source can be "app", "cli", or "zig_run". We assume
|
|
// its the desktop only if its "app". We may want to do
|
|
// "zig_run" but at the moment there's no reason.
|
|
if (std.mem.eql(u8, source, "app")) break :macos true;
|
|
}
|
|
|
|
break :macos c.getppid() == 1;
|
|
},
|
|
|
|
// On Linux and BSD, GTK sets GIO_LAUNCHED_DESKTOP_FILE and
|
|
// GIO_LAUNCHED_DESKTOP_FILE_PID. We only check the latter to see if
|
|
// we match the PID and assume that if we do, we were launched from
|
|
// the desktop file. Pid comparing catches the scenario where
|
|
// another terminal was launched from a desktop file and then launches
|
|
// Ghostty and Ghostty inherits the env.
|
|
.linux, .freebsd => ul: {
|
|
const gio_pid_str = posix.getenv("GIO_LAUNCHED_DESKTOP_FILE_PID") orelse
|
|
break :ul false;
|
|
|
|
const pid = c.getpid();
|
|
const gio_pid = std.fmt.parseInt(
|
|
@TypeOf(pid),
|
|
gio_pid_str,
|
|
10,
|
|
) catch break :ul false;
|
|
|
|
break :ul gio_pid == pid;
|
|
},
|
|
|
|
// TODO: This should have some logic to detect this. Perhaps std.builtin.subsystem
|
|
.windows => false,
|
|
|
|
// iPhone/iPad is always launched from the "desktop"
|
|
.ios => true,
|
|
|
|
else => @compileError("unsupported platform"),
|
|
};
|
|
}
|
|
|
|
/// 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`.
|
|
pub const DesktopEnvironment = enum {
|
|
gnome,
|
|
macos,
|
|
other,
|
|
windows,
|
|
};
|
|
|
|
/// Detect what desktop environment we are running under. This is mainly used
|
|
/// on Linux and BSD to enable or disable certain features but there may be more uses in
|
|
/// the future.
|
|
pub fn desktopEnvironment() DesktopEnvironment {
|
|
return switch (comptime builtin.os.tag) {
|
|
.macos => .macos,
|
|
.windows => .windows,
|
|
.linux, .freebsd => de: {
|
|
if (@inComptime()) @compileError("Checking for the desktop environment on Linux/BSD must be done at runtime.");
|
|
|
|
// 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 (posix.getenv("XDG_SESSION_DESKTOP")) |sd| {
|
|
if (std.ascii.eqlIgnoreCase("gnome", sd)) break :de .gnome;
|
|
if (std.ascii.eqlIgnoreCase("gnome-xorg", sd)) break :de .gnome;
|
|
}
|
|
|
|
// If $XDG_SESSION_DESKTOP is not set, or doesn't match any known
|
|
// DE, check $XDG_CURRENT_DESKTOP. $XDG_CURRENT_DESKTOP is a
|
|
// colon-separated list of up to three desktop names, although we
|
|
// only look at the first.
|
|
// https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html
|
|
if (posix.getenv("XDG_CURRENT_DESKTOP")) |cd| {
|
|
var cd_it = std.mem.splitScalar(u8, cd, ':');
|
|
const cd_first = cd_it.first();
|
|
if (std.ascii.eqlIgnoreCase(cd_first, "gnome")) break :de .gnome;
|
|
}
|
|
|
|
break :de .other;
|
|
},
|
|
else => .other,
|
|
};
|
|
}
|
|
|
|
test "desktop environment" {
|
|
const testing = std.testing;
|
|
|
|
switch (builtin.os.tag) {
|
|
.macos => try testing.expectEqual(.macos, desktopEnvironment()),
|
|
.windows => try testing.expectEqual(.windows, desktopEnvironment()),
|
|
.linux, .freebsd => {
|
|
const getenv = std.posix.getenv;
|
|
const setenv = @import("env.zig").setenv;
|
|
const unsetenv = @import("env.zig").unsetenv;
|
|
|
|
const xdg_current_desktop = getenv("XDG_CURRENT_DESKTOP");
|
|
defer if (xdg_current_desktop) |v| {
|
|
_ = setenv("XDG_CURRENT_DESKTOP", v);
|
|
} else {
|
|
_ = unsetenv("XDG_CURRENT_DESKTOP");
|
|
};
|
|
_ = unsetenv("XDG_CURRENT_DESKTOP");
|
|
|
|
const xdg_session_desktop = getenv("XDG_SESSION_DESKTOP");
|
|
defer if (xdg_session_desktop) |v| {
|
|
_ = setenv("XDG_SESSION_DESKTOP", v);
|
|
} else {
|
|
_ = unsetenv("XDG_SESSION_DESKTOP");
|
|
};
|
|
_ = unsetenv("XDG_SESSION_DESKTOP");
|
|
|
|
_ = setenv("XDG_SESSION_DESKTOP", "gnome");
|
|
try testing.expectEqual(.gnome, desktopEnvironment());
|
|
_ = setenv("XDG_SESSION_DESKTOP", "gnome-xorg");
|
|
try testing.expectEqual(.gnome, desktopEnvironment());
|
|
_ = setenv("XDG_SESSION_DESKTOP", "foobar");
|
|
try testing.expectEqual(.other, desktopEnvironment());
|
|
|
|
_ = unsetenv("XDG_SESSION_DESKTOP");
|
|
try testing.expectEqual(.other, desktopEnvironment());
|
|
|
|
_ = setenv("XDG_CURRENT_DESKTOP", "GNOME");
|
|
try testing.expectEqual(.gnome, desktopEnvironment());
|
|
_ = setenv("XDG_CURRENT_DESKTOP", "FOOBAR");
|
|
try testing.expectEqual(.other, desktopEnvironment());
|
|
_ = unsetenv("XDG_CURRENT_DESKTOP");
|
|
try testing.expectEqual(.other, desktopEnvironment());
|
|
},
|
|
else => try testing.expectEqual(.other, DesktopEnvironment()),
|
|
}
|
|
}
|