diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-04-04 19:22:04 +0300 |
|---|---|---|
| committer | Can Celik <ogulcancelik@gmail.com> | 2026-04-05 01:23:06 +0300 |
| commit | 41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch) | |
| tree | 3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/os/desktop.zig | |
| parent | 55c138263e190a1e79d4b997bfb9397306c0ec1f (diff) | |
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/src/os/desktop.zig')
| -rw-r--r-- | vendor/libghostty-vt/src/os/desktop.zig | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/os/desktop.zig b/vendor/libghostty-vt/src/os/desktop.zig new file mode 100644 index 00000000..93bfb74b --- /dev/null +++ b/vendor/libghostty-vt/src/os/desktop.zig @@ -0,0 +1,160 @@ +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()), + } +} |
