mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
gtk(x11): set WINDOWID
env var for subprocesses
`WINDOWID` is the conventional environment variable for scripts that want to know the X11 window ID of the terminal, so that it may call tools like `xprop` or `xdotool`. We already know the window ID for window protocol handling, so we might as well throw this in for convenience.
This commit is contained in:

committed by
Mitchell Hashimoto

parent
f8b547f92e
commit
56ea6c406c
@ -519,9 +519,17 @@ pub fn init(
|
|||||||
// This separate block ({}) is important because our errdefers must
|
// This separate block ({}) is important because our errdefers must
|
||||||
// be scoped here to be valid.
|
// be scoped here to be valid.
|
||||||
{
|
{
|
||||||
|
var env_ = rt_surface.defaultTermioEnv() catch |err| env: {
|
||||||
|
// If an error occurs, we don't want to block surface startup.
|
||||||
|
log.warn("error getting env map for surface err={}", .{err});
|
||||||
|
break :env null;
|
||||||
|
};
|
||||||
|
errdefer if (env_) |*env| env.deinit();
|
||||||
|
|
||||||
// Initialize our IO backend
|
// Initialize our IO backend
|
||||||
var io_exec = try termio.Exec.init(alloc, .{
|
var io_exec = try termio.Exec.init(alloc, .{
|
||||||
.command = command,
|
.command = command,
|
||||||
|
.env = env_,
|
||||||
.shell_integration = config.@"shell-integration",
|
.shell_integration = config.@"shell-integration",
|
||||||
.shell_integration_features = config.@"shell-integration-features",
|
.shell_integration_features = config.@"shell-integration-features",
|
||||||
.working_directory = config.@"working-directory",
|
.working_directory = config.@"working-directory",
|
||||||
|
@ -12,6 +12,7 @@ const objc = @import("objc");
|
|||||||
const apprt = @import("../apprt.zig");
|
const apprt = @import("../apprt.zig");
|
||||||
const font = @import("../font/main.zig");
|
const font = @import("../font/main.zig");
|
||||||
const input = @import("../input.zig");
|
const input = @import("../input.zig");
|
||||||
|
const internal_os = @import("../os/main.zig");
|
||||||
const renderer = @import("../renderer.zig");
|
const renderer = @import("../renderer.zig");
|
||||||
const terminal = @import("../terminal/main.zig");
|
const terminal = @import("../terminal/main.zig");
|
||||||
const CoreApp = @import("../App.zig");
|
const CoreApp = @import("../App.zig");
|
||||||
@ -1026,6 +1027,30 @@ pub const Surface = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn defaultTermioEnv(self: *const Surface) !?std.process.EnvMap {
|
||||||
|
const alloc = self.app.core_app.alloc;
|
||||||
|
var env = try internal_os.getEnvMap(alloc);
|
||||||
|
errdefer env.deinit();
|
||||||
|
|
||||||
|
if (comptime builtin.target.isDarwin()) {
|
||||||
|
if (env.get("__XCODE_BUILT_PRODUCTS_DIR_PATHS") != null) {
|
||||||
|
env.remove("__XCODE_BUILT_PRODUCTS_DIR_PATHS");
|
||||||
|
env.remove("__XPC_DYLD_LIBRARY_PATH");
|
||||||
|
env.remove("DYLD_FRAMEWORK_PATH");
|
||||||
|
env.remove("DYLD_INSERT_LIBRARIES");
|
||||||
|
env.remove("DYLD_LIBRARY_PATH");
|
||||||
|
env.remove("LD_LIBRARY_PATH");
|
||||||
|
env.remove("SECURITYSESSIONID");
|
||||||
|
env.remove("XPC_SERVICE_NAME");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove this so that running `ghostty` within Ghostty works.
|
||||||
|
env.remove("GHOSTTY_MAC_APP");
|
||||||
|
}
|
||||||
|
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
/// The cursor position from the host directly is in screen coordinates but
|
/// The cursor position from the host directly is in screen coordinates but
|
||||||
/// all our interface works in pixels.
|
/// all our interface works in pixels.
|
||||||
fn cursorPosToPixels(self: *const Surface, pos: apprt.CursorPos) !apprt.CursorPos {
|
fn cursorPosToPixels(self: *const Surface, pos: apprt.CursorPos) !apprt.CursorPos {
|
||||||
|
@ -874,6 +874,11 @@ pub const Surface = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn defaultTermioEnv(self: *Surface) !?std.process.EnvMap {
|
||||||
|
_ = self;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
fn sizeCallback(window: glfw.Window, width: i32, height: i32) void {
|
fn sizeCallback(window: glfw.Window, width: i32, height: i32) void {
|
||||||
_ = width;
|
_ = width;
|
||||||
_ = height;
|
_ = height;
|
||||||
|
@ -2252,6 +2252,25 @@ fn doPaste(self: *Surface, data: [:0]const u8) void {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn defaultTermioEnv(self: *Surface) !?std.process.EnvMap {
|
||||||
|
const alloc = self.app.core_app.alloc;
|
||||||
|
var env = try internal_os.getEnvMap(alloc);
|
||||||
|
errdefer env.deinit();
|
||||||
|
|
||||||
|
// Don't leak these GTK environment variables to child processes.
|
||||||
|
env.remove("GDK_DEBUG");
|
||||||
|
env.remove("GDK_DISABLE");
|
||||||
|
env.remove("GSK_RENDERER");
|
||||||
|
|
||||||
|
if (self.container.window()) |window| {
|
||||||
|
// On some window protocols we might want to add specific
|
||||||
|
// environment variables to subprocesses, such as WINDOWID on X11.
|
||||||
|
try window.winproto.addSubprocessEnv(&env);
|
||||||
|
}
|
||||||
|
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
/// Check a GValue to see what's type its wrapping. This is equivalent to GTK's
|
/// Check a GValue to see what's type its wrapping. This is equivalent to GTK's
|
||||||
/// `G_VALUE_HOLDS` macro but Zig's C translator does not like it.
|
/// `G_VALUE_HOLDS` macro but Zig's C translator does not like it.
|
||||||
fn g_value_holds(value_: ?*c.GValue, g_type: c.GType) bool {
|
fn g_value_holds(value_: ?*c.GValue, g_type: c.GType) bool {
|
||||||
|
@ -131,4 +131,10 @@ pub const Window = union(Protocol) {
|
|||||||
inline else => |v| v.clientSideDecorationEnabled(),
|
inline else => |v| v.clientSideDecorationEnabled(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn addSubprocessEnv(self: *Window, env: *std.process.EnvMap) !void {
|
||||||
|
switch (self.*) {
|
||||||
|
inline else => |*v| try v.addSubprocessEnv(env),
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -61,4 +61,6 @@ pub const Window = struct {
|
|||||||
_ = self;
|
_ = self;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn addSubprocessEnv(_: *Window, _: *std.process.EnvMap) !void {}
|
||||||
};
|
};
|
||||||
|
@ -262,6 +262,11 @@ pub const Window = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn addSubprocessEnv(self: *Window, env: *std.process.EnvMap) !void {
|
||||||
|
_ = self;
|
||||||
|
_ = env;
|
||||||
|
}
|
||||||
|
|
||||||
/// Update the blur state of the window.
|
/// Update the blur state of the window.
|
||||||
fn syncBlur(self: *Window) !void {
|
fn syncBlur(self: *Window) !void {
|
||||||
const manager = self.app_context.kde_blur_manager orelse return;
|
const manager = self.app_context.kde_blur_manager orelse return;
|
||||||
|
@ -314,6 +314,13 @@ pub const Window = struct {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn addSubprocessEnv(self: *Window, env: *std.process.EnvMap) !void {
|
||||||
|
var buf: [64]u8 = undefined;
|
||||||
|
const window_id = try std.fmt.bufPrint(&buf, "{}", .{self.window});
|
||||||
|
|
||||||
|
try env.put("WINDOWID", window_id);
|
||||||
|
}
|
||||||
|
|
||||||
fn getWindowProperty(
|
fn getWindowProperty(
|
||||||
self: *Window,
|
self: *Window,
|
||||||
comptime T: type,
|
comptime T: type,
|
||||||
|
@ -2,9 +2,18 @@ const std = @import("std");
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const posix = std.posix;
|
const posix = std.posix;
|
||||||
|
const isFlatpak = @import("flatpak.zig").isFlatpak;
|
||||||
|
|
||||||
pub const Error = Allocator.Error;
|
pub const Error = Allocator.Error;
|
||||||
|
|
||||||
|
/// Get the environment map.
|
||||||
|
pub fn getEnvMap(alloc: Allocator) !std.process.EnvMap {
|
||||||
|
return if (isFlatpak())
|
||||||
|
std.process.EnvMap.init(alloc)
|
||||||
|
else
|
||||||
|
try std.process.getEnvMap(alloc);
|
||||||
|
}
|
||||||
|
|
||||||
/// Append a value to an environment variable such as PATH.
|
/// Append a value to an environment variable such as PATH.
|
||||||
/// The returned value is always allocated so it must be freed.
|
/// The returned value is always allocated so it must be freed.
|
||||||
pub fn appendEnv(
|
pub fn appendEnv(
|
||||||
|
@ -26,6 +26,7 @@ pub const shell = @import("shell.zig");
|
|||||||
// Functions and types
|
// Functions and types
|
||||||
pub const CFReleaseThread = @import("cf_release_thread.zig");
|
pub const CFReleaseThread = @import("cf_release_thread.zig");
|
||||||
pub const TempDir = @import("TempDir.zig");
|
pub const TempDir = @import("TempDir.zig");
|
||||||
|
pub const getEnvMap = env.getEnvMap;
|
||||||
pub const appendEnv = env.appendEnv;
|
pub const appendEnv = env.appendEnv;
|
||||||
pub const appendEnvAlways = env.appendEnvAlways;
|
pub const appendEnvAlways = env.appendEnvAlways;
|
||||||
pub const prependEnv = env.prependEnv;
|
pub const prependEnv = env.prependEnv;
|
||||||
|
@ -682,6 +682,7 @@ pub const ThreadData = struct {
|
|||||||
|
|
||||||
pub const Config = struct {
|
pub const Config = struct {
|
||||||
command: ?[]const u8 = null,
|
command: ?[]const u8 = null,
|
||||||
|
env: ?EnvMap = null,
|
||||||
shell_integration: configpkg.Config.ShellIntegration = .detect,
|
shell_integration: configpkg.Config.ShellIntegration = .detect,
|
||||||
shell_integration_features: configpkg.Config.ShellIntegrationFeatures = .{},
|
shell_integration_features: configpkg.Config.ShellIntegrationFeatures = .{},
|
||||||
working_directory: ?[]const u8 = null,
|
working_directory: ?[]const u8 = null,
|
||||||
@ -721,18 +722,9 @@ const Subprocess = struct {
|
|||||||
errdefer arena.deinit();
|
errdefer arena.deinit();
|
||||||
const alloc = arena.allocator();
|
const alloc = arena.allocator();
|
||||||
|
|
||||||
// Set our env vars. For Flatpak builds running in Flatpak we don't
|
// Get our env. If a default env isn't provided by the caller
|
||||||
// inherit our environment because the login shell on the host side
|
// then we get it ourselves.
|
||||||
// will get it.
|
var env = cfg.env orelse try internal_os.getEnvMap(alloc);
|
||||||
var env = env: {
|
|
||||||
if (comptime build_config.flatpak) {
|
|
||||||
if (internal_os.isFlatpak()) {
|
|
||||||
break :env std.process.EnvMap.init(alloc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break :env try std.process.getEnvMap(alloc);
|
|
||||||
};
|
|
||||||
errdefer env.deinit();
|
errdefer env.deinit();
|
||||||
|
|
||||||
// If we have a resources dir then set our env var
|
// If we have a resources dir then set our env var
|
||||||
@ -847,35 +839,11 @@ const Subprocess = struct {
|
|||||||
try env.put("TERM_PROGRAM", "ghostty");
|
try env.put("TERM_PROGRAM", "ghostty");
|
||||||
try env.put("TERM_PROGRAM_VERSION", build_config.version_string);
|
try env.put("TERM_PROGRAM_VERSION", build_config.version_string);
|
||||||
|
|
||||||
// When embedding in macOS and running via XCode, XCode injects
|
|
||||||
// a bunch of things that break our shell process. We remove those.
|
|
||||||
if (comptime builtin.target.isDarwin() and build_config.artifact == .lib) {
|
|
||||||
if (env.get("__XCODE_BUILT_PRODUCTS_DIR_PATHS") != null) {
|
|
||||||
env.remove("__XCODE_BUILT_PRODUCTS_DIR_PATHS");
|
|
||||||
env.remove("__XPC_DYLD_LIBRARY_PATH");
|
|
||||||
env.remove("DYLD_FRAMEWORK_PATH");
|
|
||||||
env.remove("DYLD_INSERT_LIBRARIES");
|
|
||||||
env.remove("DYLD_LIBRARY_PATH");
|
|
||||||
env.remove("LD_LIBRARY_PATH");
|
|
||||||
env.remove("SECURITYSESSIONID");
|
|
||||||
env.remove("XPC_SERVICE_NAME");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove this so that running `ghostty` within Ghostty works.
|
|
||||||
env.remove("GHOSTTY_MAC_APP");
|
|
||||||
}
|
|
||||||
|
|
||||||
// VTE_VERSION is set by gnome-terminal and other VTE-based terminals.
|
// VTE_VERSION is set by gnome-terminal and other VTE-based terminals.
|
||||||
// We don't want our child processes to think we're running under VTE.
|
// We don't want our child processes to think we're running under VTE.
|
||||||
|
// This is not apprt-specific, so we do it here.
|
||||||
env.remove("VTE_VERSION");
|
env.remove("VTE_VERSION");
|
||||||
|
|
||||||
// Don't leak these GTK environment variables to child processes.
|
|
||||||
if (comptime build_config.app_runtime == .gtk) {
|
|
||||||
env.remove("GDK_DEBUG");
|
|
||||||
env.remove("GDK_DISABLE");
|
|
||||||
env.remove("GSK_RENDERER");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup our shell integration, if we can.
|
// Setup our shell integration, if we can.
|
||||||
const integrated_shell: ?shell_integration.Shell, const shell_command: []const u8 = shell: {
|
const integrated_shell: ?shell_integration.Shell, const shell_command: []const u8 = shell: {
|
||||||
const default_shell_command = cfg.command orelse switch (builtin.os.tag) {
|
const default_shell_command = cfg.command orelse switch (builtin.os.tag) {
|
||||||
|
Reference in New Issue
Block a user