From ff02ed1b3458f88e3d3eb31d59027e374aba2ecd Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Wed, 13 Aug 2025 19:28:11 -0500 Subject: [PATCH] core: add 64 bit unique ID to every core surface - Expose that ID as the environment variable GHOSTTY_SURFACE_ID to processes running in Ghostty surfaces. - Add a function to the core app to search for surfaces by ID. - ID is randomly generated, it has no other meaning other than as a unique identifier for the surface. The ID also cannot be zero as that is used to indicate a null ID in some situations. --- src/App.zig | 10 ++++++++++ src/Surface.zig | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/App.zig b/src/App.zig index 33c8318db..5446f4bf2 100644 --- a/src/App.zig +++ b/src/App.zig @@ -524,6 +524,16 @@ fn hasSurface(self: *const App, surface: *const Surface) bool { return false; } +/// Search for a surface by a 64 bit unique ID. +pub fn findSurfaceByID(self: *const App, id: u64) ?*Surface { + for (self.surfaces.items) |v| { + const surface: *Surface = v.core(); + if (surface.id == id) return surface; + } + + return null; +} + fn hasRtSurface(self: *const App, surface: *apprt.Surface) bool { for (self.surfaces.items) |v| { if (v == surface) return true; diff --git a/src/Surface.zig b/src/Surface.zig index c8055cfee..61e7bd6e0 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -54,6 +54,13 @@ pub const min_window_height_cells: u32 = 4; /// given time. `activate_key_table` calls after this are ignored. const max_active_key_tables = 8; +/// Unique ID used to identify this surface for IPC purposes. It is +/// exposed to the commands running in surfaces as the environment variable +/// GHOSTTY_SURFACE_ID. It must not be zero as zero is used to incicate a null +/// value when communicating an ID over DBus as DBus does not allow null/maybe +/// values. +id: u64, + /// Allocator alloc: Allocator, @@ -579,6 +586,13 @@ pub fn init( errdefer io_thread.deinit(); self.* = .{ + .id = id: { + while (true) { + const candidate = std.crypto.random.int(u64); + if (candidate == 0) continue; + break :id candidate; + } + }, .alloc = alloc, .app = app, .rt_app = rt_app, @@ -632,6 +646,12 @@ pub fn init( // don't leak GHOSTTY_LOG to any subprocesses env.remove("GHOSTTY_LOG"); + var buf: [18]u8 = undefined; + try env.put( + "GHOSTTY_SURFACE_ID", + std.fmt.bufPrint(&buf, "0x{x:0>16}", .{self.id}) catch unreachable, + ); + // Initialize our IO backend var io_exec = try termio.Exec.init(alloc, .{ .command = command,