mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
Command/Pty work better with Flatpak but not 100% yet
This commit is contained in:
2
dist/linux/app.desktop
vendored
2
dist/linux/app.desktop
vendored
@ -2,7 +2,7 @@
|
|||||||
Name=Ghostty
|
Name=Ghostty
|
||||||
Type=Application
|
Type=Application
|
||||||
Comment=A terminal emulator
|
Comment=A terminal emulator
|
||||||
Exec=/usr/bin/ghostty
|
Exec=/app/bin/ghostty
|
||||||
Icon=com.mitchellh.ghostty
|
Icon=com.mitchellh.ghostty
|
||||||
Keywords=terminal;tty;pty;
|
Keywords=terminal;tty;pty;
|
||||||
StartupNotify=true
|
StartupNotify=true
|
||||||
|
@ -24,6 +24,7 @@ const Command = @This();
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const TempDir = @import("TempDir.zig");
|
const TempDir = @import("TempDir.zig");
|
||||||
|
const internal_os = @import("os/main.zig");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const os = std.os;
|
const os = std.os;
|
||||||
const debug = std.debug;
|
const debug = std.debug;
|
||||||
|
15
src/Pty.zig
15
src/Pty.zig
@ -104,12 +104,15 @@ pub fn childPreExec(self: Pty) !void {
|
|||||||
if (setsid() < 0) return error.ProcessGroupFailed;
|
if (setsid() < 0) return error.ProcessGroupFailed;
|
||||||
|
|
||||||
// Set controlling terminal
|
// Set controlling terminal
|
||||||
switch (std.os.system.getErrno(c.ioctl(self.slave, TIOCSCTTY, @as(c_ulong, 0)))) {
|
// TODO: maybe
|
||||||
.SUCCESS => {},
|
if (!@import("os/main.zig").isFlatpak()) {
|
||||||
else => |err| {
|
switch (std.os.system.getErrno(c.ioctl(self.slave, TIOCSCTTY, @as(c_ulong, 0)))) {
|
||||||
log.err("error setting controlling terminal errno={}", .{err});
|
.SUCCESS => {},
|
||||||
return error.SetControllingTerminalFailed;
|
else => |err| {
|
||||||
},
|
log.err("error setting controlling terminal errno={}", .{err});
|
||||||
|
return error.SetControllingTerminalFailed;
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can close master/slave pair now
|
// Can close master/slave pair now
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
//! system.
|
//! system.
|
||||||
|
|
||||||
pub usingnamespace @import("file.zig");
|
pub usingnamespace @import("file.zig");
|
||||||
|
pub usingnamespace @import("flatpak.zig");
|
||||||
pub usingnamespace @import("locale.zig");
|
pub usingnamespace @import("locale.zig");
|
||||||
pub usingnamespace @import("macos_version.zig");
|
pub usingnamespace @import("macos_version.zig");
|
||||||
pub usingnamespace @import("mouse.zig");
|
pub usingnamespace @import("mouse.zig");
|
||||||
|
@ -6,6 +6,7 @@ const builtin = @import("builtin");
|
|||||||
const build_config = @import("../build_config.zig");
|
const build_config = @import("../build_config.zig");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
const EnvMap = std.process.EnvMap;
|
||||||
const termio = @import("../termio.zig");
|
const termio = @import("../termio.zig");
|
||||||
const Command = @import("../Command.zig");
|
const Command = @import("../Command.zig");
|
||||||
const Pty = @import("../Pty.zig");
|
const Pty = @import("../Pty.zig");
|
||||||
@ -17,6 +18,7 @@ const tracy = @import("tracy");
|
|||||||
const trace = tracy.trace;
|
const trace = tracy.trace;
|
||||||
const apprt = @import("../apprt.zig");
|
const apprt = @import("../apprt.zig");
|
||||||
const fastmem = @import("../fastmem.zig");
|
const fastmem = @import("../fastmem.zig");
|
||||||
|
const internal_os = @import("../os/main.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.io_exec);
|
const log = std.log.scoped(.io_exec);
|
||||||
|
|
||||||
@ -90,7 +92,7 @@ pub fn init(alloc: Allocator, opts: termio.Options) !Exec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Exec) void {
|
pub fn deinit(self: *Exec) void {
|
||||||
self.subprocess.deinit(self.alloc);
|
self.subprocess.deinit();
|
||||||
|
|
||||||
// Clean up our other members
|
// Clean up our other members
|
||||||
self.terminal.deinit(self.alloc);
|
self.terminal.deinit(self.alloc);
|
||||||
@ -139,6 +141,7 @@ pub fn threadEnter(self: *Exec, thread: *termio.Thread) !ThreadData {
|
|||||||
|
|
||||||
// Store our data so our callbacks can access it
|
// Store our data so our callbacks can access it
|
||||||
self.data = ev_data_ptr;
|
self.data = ev_data_ptr;
|
||||||
|
errdefer self.data = null;
|
||||||
|
|
||||||
// Start our reader thread
|
// Start our reader thread
|
||||||
const read_thread = try std.Thread.spawn(
|
const read_thread = try std.Thread.spawn(
|
||||||
@ -319,10 +322,11 @@ fn ttyWrite(
|
|||||||
|
|
||||||
/// Subprocess manages the lifecycle of the shell subprocess.
|
/// Subprocess manages the lifecycle of the shell subprocess.
|
||||||
const Subprocess = struct {
|
const Subprocess = struct {
|
||||||
|
arena: std.heap.ArenaAllocator,
|
||||||
cwd: ?[]const u8,
|
cwd: ?[]const u8,
|
||||||
env: std.process.EnvMap,
|
env: EnvMap,
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
argv0_override: ?[]const u8,
|
args: [][]const u8,
|
||||||
grid_size: renderer.GridSize,
|
grid_size: renderer.GridSize,
|
||||||
screen_size: renderer.ScreenSize,
|
screen_size: renderer.ScreenSize,
|
||||||
pty: ?Pty = null,
|
pty: ?Pty = null,
|
||||||
@ -330,11 +334,16 @@ const Subprocess = struct {
|
|||||||
|
|
||||||
/// Initialize the subprocess. This will NOT start it, this only sets
|
/// Initialize the subprocess. This will NOT start it, this only sets
|
||||||
/// up the internal state necessary to start it later.
|
/// up the internal state necessary to start it later.
|
||||||
pub fn init(alloc: Allocator, opts: termio.Options) !Subprocess {
|
pub fn init(gpa: Allocator, opts: termio.Options) !Subprocess {
|
||||||
|
// We have a lot of maybe-allocations that all share the same lifetime
|
||||||
|
// so use an arena so we don't end up in an accounting nightmare.
|
||||||
|
var arena = std.heap.ArenaAllocator.init(gpa);
|
||||||
|
errdefer arena.deinit();
|
||||||
|
const alloc = arena.allocator();
|
||||||
|
|
||||||
// Determine the path to the binary we're executing
|
// Determine the path to the binary we're executing
|
||||||
const path = (try Command.expandPath(alloc, opts.config.command orelse "sh")) orelse
|
const path = (try Command.expandPath(alloc, opts.config.command orelse "sh")) orelse
|
||||||
return error.CommandNotFound;
|
return error.CommandNotFound;
|
||||||
errdefer alloc.free(path);
|
|
||||||
|
|
||||||
// On macOS, we launch the program as a login shell. This is a Mac-specific
|
// On macOS, we launch the program as a login shell. This is a Mac-specific
|
||||||
// behavior (see other terminals). Terminals in general should NOT be
|
// behavior (see other terminals). Terminals in general should NOT be
|
||||||
@ -354,10 +363,12 @@ const Subprocess = struct {
|
|||||||
std.mem.copy(u8, argv0_buf[1..], argv0);
|
std.mem.copy(u8, argv0_buf[1..], argv0);
|
||||||
break :argv0 argv0_buf;
|
break :argv0 argv0_buf;
|
||||||
} else null;
|
} else null;
|
||||||
errdefer if (argv0_override) |buf| alloc.free(buf);
|
|
||||||
|
|
||||||
// Set our env vars
|
// Set our env vars
|
||||||
var env = try std.process.getEnvMap(alloc);
|
var env = if (internal_os.isFlatpak())
|
||||||
|
EnvMap.init(alloc)
|
||||||
|
else
|
||||||
|
try std.process.getEnvMap(alloc);
|
||||||
errdefer env.deinit();
|
errdefer env.deinit();
|
||||||
try env.put("TERM", "xterm-256color");
|
try env.put("TERM", "xterm-256color");
|
||||||
try env.put("COLORTERM", "truecolor");
|
try env.put("COLORTERM", "truecolor");
|
||||||
@ -377,22 +388,47 @@ const Subprocess = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we're NOT in a flatpak (usually!), then we just exec the
|
||||||
|
// process directly. If we are in a flatpak, we use flatpak-spawn
|
||||||
|
// to escape the sandbox.
|
||||||
|
const args = if (!internal_os.isFlatpak()) &[_][]const u8{
|
||||||
|
argv0_override orelse path,
|
||||||
|
} else args: {
|
||||||
|
var args = try std.ArrayList([]const u8).initCapacity(alloc, 8);
|
||||||
|
defer args.deinit();
|
||||||
|
|
||||||
|
try args.append("/usr/bin/flatpak-spawn");
|
||||||
|
try args.append("--host");
|
||||||
|
try args.append("--watch-bus");
|
||||||
|
var env_it = env.iterator();
|
||||||
|
while (env_it.next()) |pair| {
|
||||||
|
try args.append(try std.fmt.allocPrint(
|
||||||
|
alloc,
|
||||||
|
"--env={s}={s}",
|
||||||
|
.{ pair.key_ptr.*, pair.value_ptr.* },
|
||||||
|
));
|
||||||
|
}
|
||||||
|
try args.append(path);
|
||||||
|
|
||||||
|
break :args try args.toOwnedSlice();
|
||||||
|
};
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
|
.arena = arena,
|
||||||
.env = env,
|
.env = env,
|
||||||
.cwd = opts.config.@"working-directory",
|
.cwd = opts.config.@"working-directory",
|
||||||
.path = path,
|
.path = if (internal_os.isFlatpak()) "/usr/bin/flatpak-spawn" else path,
|
||||||
.argv0_override = argv0_override,
|
.args = args,
|
||||||
.grid_size = opts.grid_size,
|
.grid_size = opts.grid_size,
|
||||||
.screen_size = opts.screen_size,
|
.screen_size = opts.screen_size,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clean up the subprocess. This will stop the subprocess if it is started.
|
/// Clean up the subprocess. This will stop the subprocess if it is started.
|
||||||
pub fn deinit(self: *Subprocess, alloc: Allocator) void {
|
pub fn deinit(self: *Subprocess) void {
|
||||||
self.stop();
|
self.stop();
|
||||||
self.env.deinit();
|
self.env.deinit();
|
||||||
alloc.free(self.path);
|
self.arena.deinit();
|
||||||
if (self.argv0_override) |v| alloc.free(v);
|
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,12 +450,15 @@ const Subprocess = struct {
|
|||||||
self.pty = null;
|
self.pty = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const args = &[_][]const u8{self.argv0_override orelse self.path};
|
log.debug("starting command path={s} args={s}", .{
|
||||||
|
self.path,
|
||||||
|
self.args,
|
||||||
|
});
|
||||||
|
|
||||||
// Build our subcommand
|
// Build our subcommand
|
||||||
var cmd: Command = .{
|
var cmd: Command = .{
|
||||||
.path = self.path,
|
.path = self.path,
|
||||||
.args = args,
|
.args = self.args,
|
||||||
.env = &self.env,
|
.env = &self.env,
|
||||||
.cwd = self.cwd,
|
.cwd = self.cwd,
|
||||||
.stdin = .{ .handle = pty.slave },
|
.stdin = .{ .handle = pty.slave },
|
||||||
|
Reference in New Issue
Block a user