cli/gtk: clarify +new-window documentation and improve instance discovery

- Add a `GHOSTTY_CLASS` environment variables to any command executed by
  Ghostty to make discovering the correct application ID easier.

- Add a flag to force the relelase application ID.

- Ensure that CLI flags to `+new-window` are mutually exclusive.

- Fix documentation about D-Bus activation requirements.
This commit is contained in:
Jeffrey C. Ollie
2025-07-10 12:11:01 -05:00
parent 7845399c00
commit 340d190bf0
2 changed files with 57 additions and 11 deletions

View File

@ -2358,6 +2358,13 @@ pub fn defaultTermioEnv(self: *Surface) !std.process.EnvMap {
try window.winproto.addSubprocessEnv(&env); try window.winproto.addSubprocessEnv(&env);
} }
class: {
const gio_app = self.app.app.as(gio.Application);
const class = std.mem.span(gio_app.getApplicationId() orelse break :class);
try env.put("GHOSTTY_CLASS", class);
}
return env; return env;
} }

View File

@ -14,8 +14,10 @@ pub const Options = struct {
/// This is set by the CLI parser for deinit. /// This is set by the CLI parser for deinit.
_arena: ?ArenaAllocator = null, _arena: ?ArenaAllocator = null,
/// If `true`, open up a new window in a release instance of Ghostty.
release: bool = false,
/// If `true`, open up a new window in a debug instance of Ghostty. /// If `true`, open up a new window in a debug instance of Ghostty.
/// Otherwise open up a new window in a release instance of Ghostty.
debug: bool = false, debug: bool = false,
/// If set, open up a new window in a custom instance of Ghostty. Takes /// If set, open up a new window in a custom instance of Ghostty. Takes
@ -41,25 +43,41 @@ pub const Options = struct {
/// The `new-window` will use native platform IPC to open up a new window in a /// The `new-window` will use native platform IPC to open up a new window in a
/// running instance of Ghostty. /// running instance of Ghostty.
/// ///
/// On GTK, if D-Bus activation is properly configured, Ghostty does not need /// On GTK, D-Bus activation must be properly configured. Ghostty does not need
/// to be running for this to open a new window, making it suitable for binding /// to be running for this to open a new window, making it suitable for binding
/// to keys in your window manager (if other methods of configuring global /// to keys in your window manager (if other methods for configuring global
/// shortcuts are unavailable). See the Ghostty website for information on /// shortcuts are unavailable). D-Bus will handle launching a new instance
/// properly configuring D-Bus activation. /// of Ghostty if it is not already running. See the Ghostty website for
/// information on properly configuring D-Bus activation.
/// ///
/// If Ghostty is already running, D-Bus activation is unnecessary and this /// GTK uses an application ID to identify instances of applications. If
/// command should cause the running instance to open a new window. /// Ghostty is compiled with debug optimizations, the application ID will
/// be `com.mitchellh.ghostty-debug`. If Ghostty is compiled with release
/// optimizations, the application ID will be `com.mitchellh.ghostty`.
///
/// The `class` configuration entry can be used to set up a custom application
/// ID. The class name must follow the requirements defined [in the GTK
/// documentation](https://docs.gtk.org/gio/type_func.Application.id_is_valid.html)
/// or it will be ignored and Ghostty will use the default application ID as
/// defined above.
///
/// The `new-window` command will try and find the application ID of the running
/// Ghostty instance in the `GHOSTTY_CLASS` environment variable. If this
/// environment variable is not set, and any of the command line flags defined
/// below are not set, a release instance of Ghostty will be opened.
/// ///
/// Only supported on GTK. /// Only supported on GTK.
/// ///
/// Flags: /// Flags:
/// ///
/// * `--debug`: If `true`, open up a new window in a debug instance of /// * `--release`: If `true`, force opening up a new window in a release instance of
/// Ghostty. Otherwise open up a new window in a release instance of
/// Ghostty. /// Ghostty.
/// ///
/// * `--class`: If set, open up a new window in a custom instance of Ghostty. /// * `--debug`: If `true`, force opening up a new window in a debug instance of
/// This takes precedence over the `--debug` flag. /// Ghostty.
///
/// * `--class=<class>`: If set, open up a new window in a custom instance of Ghostty. The
/// class must be a valid GTK application ID.
/// ///
/// Available since: 1.2.0 /// Available since: 1.2.0
pub fn run(alloc: Allocator) !u8 { pub fn run(alloc: Allocator) !u8 {
@ -102,6 +120,16 @@ fn runArgs(alloc_gpa: Allocator, argsIter: anytype) !u8 {
if (exit) return 1; if (exit) return 1;
} }
var count: usize = 0;
if (opts.release) count += 1;
if (opts.debug) count += 1;
if (opts.class) |_| count += 1;
if (count > 1) {
try stderr.print("The --release, --debug, and --class flags are mutually exclusive, only one may be specified at a time.\n", .{});
return 1;
}
var arena = ArenaAllocator.init(alloc_gpa); var arena = ArenaAllocator.init(alloc_gpa);
defer arena.deinit(); defer arena.deinit();
const alloc = arena.allocator(); const alloc = arena.allocator();
@ -123,9 +151,20 @@ fn runArgs(alloc_gpa: Allocator, argsIter: anytype) !u8 {
break :result .{ class, object_path }; break :result .{ class, object_path };
} }
if (opts.release) {
break :result .{ "com.mitchellh.ghostty", "/com/mitchellh/ghostty" };
}
if (opts.debug) { if (opts.debug) {
break :result .{ "com.mitchellh.ghostty-debug", "/com/mitchellh/ghostty_debug" }; break :result .{ "com.mitchellh.ghostty-debug", "/com/mitchellh/ghostty_debug" };
} }
if (std.posix.getenv("GHOSTTY_CLASS")) |class| {
const object_path = try std.fmt.allocPrintZ(alloc, "/{s}", .{class});
std.mem.replaceScalar(u8, object_path, '.', '/');
std.mem.replaceScalar(u8, object_path, '-', '_');
break :result .{ class, object_path };
}
break :result .{ "com.mitchellh.ghostty", "/com/mitchellh/ghostty" }; break :result .{ "com.mitchellh.ghostty", "/com/mitchellh/ghostty" };
}; };