mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-04-12 10:48:39 +03:00
Merge 696d3b23a4c9c93f4423178832fdd58088862a99 into 66636195f18d21bd65f8e7ced461f6b6770be189
This commit is contained in:
@ -543,7 +543,7 @@ pub fn init(
|
||||
.shell_integration = config.@"shell-integration",
|
||||
.shell_integration_features = config.@"shell-integration-features",
|
||||
.working_directory = config.@"working-directory",
|
||||
.resources_dir = global_state.resources_dir,
|
||||
.resources_dir = global_state.resources_dir.host(),
|
||||
.term = config.term,
|
||||
|
||||
// Get the cgroup if we're on linux and have the decl. I'd love
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
pub const App = @import("gtk/App.zig");
|
||||
pub const Surface = @import("gtk/Surface.zig");
|
||||
pub const resourcesDir = @import("gtk/flatpak.zig").resourcesDir;
|
||||
|
||||
test {
|
||||
@import("std").testing.refAllDecls(@This());
|
||||
|
29
src/apprt/gtk/flatpak.zig
Normal file
29
src/apprt/gtk/flatpak.zig
Normal file
@ -0,0 +1,29 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const build_config = @import("../../build_config.zig");
|
||||
const internal_os = @import("../../os/main.zig");
|
||||
const glib = @import("glib");
|
||||
|
||||
pub fn resourcesDir(alloc: Allocator) !internal_os.ResourcesDir {
|
||||
if (comptime build_config.flatpak) {
|
||||
// Only consult Flatpak runtime data for host case.
|
||||
if (internal_os.isFlatpak()) {
|
||||
var result: internal_os.ResourcesDir = .{
|
||||
.app_path = try alloc.dupe(u8, "/app/share/ghostty"),
|
||||
};
|
||||
errdefer alloc.free(result.app_path.?);
|
||||
|
||||
const keyfile = glib.KeyFile.new();
|
||||
defer keyfile.unref();
|
||||
|
||||
if (keyfile.loadFromFile("/.flatpak-info", .{}, null) == 0) return result;
|
||||
const app_dir = std.mem.span(keyfile.getString("Instance", "app-path", null)) orelse return result;
|
||||
defer glib.free(app_dir.ptr);
|
||||
|
||||
result.host_path = try std.fs.path.join(alloc, &[_][]const u8{ app_dir, "share", "ghostty" });
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return try internal_os.resourcesDir(alloc);
|
||||
}
|
@ -109,7 +109,8 @@ pub fn run(gpa_alloc: std.mem.Allocator) !u8 {
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
|
||||
if (global_state.resources_dir == null)
|
||||
const resources_dir = global_state.resources_dir.app();
|
||||
if (resources_dir == null)
|
||||
try stderr.print("Could not find the Ghostty resources directory. Please ensure " ++
|
||||
"that Ghostty is installed correctly.\n", .{});
|
||||
|
||||
|
@ -56,7 +56,7 @@ pub const Location = enum {
|
||||
},
|
||||
|
||||
.resources => try std.fs.path.join(arena_alloc, &.{
|
||||
global_state.resources_dir orelse return null,
|
||||
global_state.resources_dir.app() orelse return null,
|
||||
"themes",
|
||||
}),
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ const harfbuzz = @import("harfbuzz");
|
||||
const oni = @import("oniguruma");
|
||||
const crash = @import("crash/main.zig");
|
||||
const renderer = @import("renderer.zig");
|
||||
const apprt = @import("apprt.zig");
|
||||
|
||||
/// We export the xev backend we want to use so that the rest of
|
||||
/// Ghostty can import this once and have access to the proper
|
||||
@ -35,7 +36,7 @@ pub const GlobalState = struct {
|
||||
|
||||
/// The app resources directory, equivalent to zig-out/share when we build
|
||||
/// from source. This is null if we can't detect it.
|
||||
resources_dir: ?[]const u8,
|
||||
resources_dir: internal_os.ResourcesDir,
|
||||
|
||||
/// Where logging should go
|
||||
pub const Logging = union(enum) {
|
||||
@ -62,7 +63,7 @@ pub const GlobalState = struct {
|
||||
.action = null,
|
||||
.logging = .{ .stderr = {} },
|
||||
.rlimits = .{},
|
||||
.resources_dir = null,
|
||||
.resources_dir = .{},
|
||||
};
|
||||
errdefer self.deinit();
|
||||
|
||||
@ -170,11 +171,14 @@ pub const GlobalState = struct {
|
||||
|
||||
// Find our resources directory once for the app so every launch
|
||||
// hereafter can use this cached value.
|
||||
self.resources_dir = try internal_os.resourcesDir(self.alloc);
|
||||
errdefer if (self.resources_dir) |dir| self.alloc.free(dir);
|
||||
self.resources_dir = rd: {
|
||||
if (@hasDecl(apprt.runtime, "resourcesDir")) break :rd try apprt.runtime.resourcesDir(self.alloc);
|
||||
break :rd try internal_os.resourcesDir(self.alloc);
|
||||
};
|
||||
errdefer self.resources_dir.deinit(self.alloc);
|
||||
|
||||
// Setup i18n
|
||||
if (self.resources_dir) |v| internal_os.i18n.init(v) catch |err| {
|
||||
if (self.resources_dir.app()) |v| internal_os.i18n.init(v) catch |err| {
|
||||
std.log.warn("failed to init i18n, translations will not be available err={}", .{err});
|
||||
};
|
||||
}
|
||||
@ -182,7 +186,7 @@ pub const GlobalState = struct {
|
||||
/// Cleans up the global state. This doesn't _need_ to be called but
|
||||
/// doing so in dev modes will check for memory leaks.
|
||||
pub fn deinit(self: *GlobalState) void {
|
||||
if (self.resources_dir) |dir| self.alloc.free(dir);
|
||||
self.resources_dir.deinit(self.alloc);
|
||||
|
||||
// Flush our crash logs
|
||||
crash.deinit();
|
||||
|
@ -51,6 +51,7 @@ pub const open = openpkg.open;
|
||||
pub const OpenType = openpkg.Type;
|
||||
pub const pipe = pipepkg.pipe;
|
||||
pub const resourcesDir = resourcesdir.resourcesDir;
|
||||
pub const ResourcesDir = resourcesdir.ResourcesDir;
|
||||
pub const ShellEscapeWriter = shell.ShellEscapeWriter;
|
||||
|
||||
test {
|
||||
|
@ -2,13 +2,41 @@ const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub const ResourcesDir = struct {
|
||||
app_path: ?[]const u8 = null,
|
||||
host_path: ?[]const u8 = null,
|
||||
|
||||
/// Free resources held. Requires the same allocator as when resourcesDir()
|
||||
/// is called.
|
||||
pub fn deinit(self: *ResourcesDir, alloc: std.mem.Allocator) void {
|
||||
if (self.app_path) |p| alloc.free(p);
|
||||
if (self.host_path) |p| alloc.free(p);
|
||||
}
|
||||
|
||||
/// Get the directory to the bundled resources directory accessible
|
||||
/// by the application.
|
||||
pub fn app(self: *ResourcesDir) ?[]const u8 {
|
||||
return self.app_path;
|
||||
}
|
||||
|
||||
/// Get the directory to the bundled resources directory accessible
|
||||
/// by the host environment (i.e. for sandboxed applications). The
|
||||
/// returned directory might not be accessible from the application
|
||||
/// itself.
|
||||
///
|
||||
/// In non-sandboxed environment, this should be the same as app().
|
||||
pub fn host(self: *ResourcesDir) ?[]const u8 {
|
||||
return self.host_path orelse self.app_path;
|
||||
}
|
||||
};
|
||||
|
||||
/// Gets the directory to the bundled resources directory, if it
|
||||
/// exists (not all platforms or packages have it). The output is
|
||||
/// owned by the caller.
|
||||
///
|
||||
/// This is highly Ghostty-specific and can likely be generalized at
|
||||
/// some point but we can cross that bridge if we ever need to.
|
||||
pub fn resourcesDir(alloc: std.mem.Allocator) !?[]const u8 {
|
||||
pub fn resourcesDir(alloc: std.mem.Allocator) !ResourcesDir {
|
||||
// Use the GHOSTTY_RESOURCES_DIR environment variable in release builds.
|
||||
//
|
||||
// In debug builds we try using terminfo detection first instead, since
|
||||
@ -20,7 +48,7 @@ pub fn resourcesDir(alloc: std.mem.Allocator) !?[]const u8 {
|
||||
// freed, do not try to use internal_os.getenv or posix getenv.
|
||||
if (comptime builtin.mode != .Debug) {
|
||||
if (std.process.getEnvVarOwned(alloc, "GHOSTTY_RESOURCES_DIR")) |dir| {
|
||||
if (dir.len > 0) return dir;
|
||||
if (dir.len > 0) return .{ .app_path = dir };
|
||||
} else |err| switch (err) {
|
||||
error.EnvironmentVariableNotFound => {},
|
||||
else => return err,
|
||||
@ -37,7 +65,7 @@ pub fn resourcesDir(alloc: std.mem.Allocator) !?[]const u8 {
|
||||
|
||||
// Get the path to our running binary
|
||||
var exe_buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||
var exe: []const u8 = std.fs.selfExePath(&exe_buf) catch return null;
|
||||
var exe: []const u8 = std.fs.selfExePath(&exe_buf) catch return .{};
|
||||
|
||||
// We have an exe path! Climb the tree looking for the terminfo
|
||||
// bundle as we expect it.
|
||||
@ -49,7 +77,7 @@ pub fn resourcesDir(alloc: std.mem.Allocator) !?[]const u8 {
|
||||
if (comptime builtin.target.os.tag.isDarwin()) {
|
||||
inline for (sentinels) |sentinel| {
|
||||
if (try maybeDir(&dir_buf, dir, "Contents/Resources", sentinel)) |v| {
|
||||
return try std.fs.path.join(alloc, &.{ v, "ghostty" });
|
||||
return .{ .app_path = try std.fs.path.join(alloc, &.{ v, "ghostty" }) };
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -59,7 +87,7 @@ pub fn resourcesDir(alloc: std.mem.Allocator) !?[]const u8 {
|
||||
// Ghostty to be in an app bundle.
|
||||
inline for (sentinels) |sentinel| {
|
||||
if (try maybeDir(&dir_buf, dir, "share", sentinel)) |v| {
|
||||
return try std.fs.path.join(alloc, &.{ v, "ghostty" });
|
||||
return .{ .app_path = try std.fs.path.join(alloc, &.{ v, "ghostty" }) };
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -68,14 +96,14 @@ pub fn resourcesDir(alloc: std.mem.Allocator) !?[]const u8 {
|
||||
// fallback and use the provided resources dir.
|
||||
if (comptime builtin.mode == .Debug) {
|
||||
if (std.process.getEnvVarOwned(alloc, "GHOSTTY_RESOURCES_DIR")) |dir| {
|
||||
if (dir.len > 0) return dir;
|
||||
if (dir.len > 0) return .{ .app_path = dir };
|
||||
} else |err| switch (err) {
|
||||
error.EnvironmentVariableNotFound => {},
|
||||
else => return err,
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return .{};
|
||||
}
|
||||
|
||||
/// Little helper to check if the "base/sub/suffix" directory exists and
|
||||
|
Reference in New Issue
Block a user