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,