aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/os/macos.zig
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-04-04 19:22:04 +0300
committerCan Celik <ogulcancelik@gmail.com>2026-04-05 01:23:06 +0300
commit41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch)
tree3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/os/macos.zig
parent55c138263e190a1e79d4b997bfb9397306c0ec1f (diff)
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/src/os/macos.zig')
-rw-r--r--vendor/libghostty-vt/src/os/macos.zig177
1 files changed, 177 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/os/macos.zig b/vendor/libghostty-vt/src/os/macos.zig
new file mode 100644
index 00000000..fcd1c3e5
--- /dev/null
+++ b/vendor/libghostty-vt/src/os/macos.zig
@@ -0,0 +1,177 @@
+const std = @import("std");
+const builtin = @import("builtin");
+const build_config = @import("../build_config.zig");
+const assert = @import("../quirks.zig").inlineAssert;
+const objc = @import("objc");
+const Allocator = std.mem.Allocator;
+
+/// Verifies that the running macOS system version is at least the given version.
+pub fn isAtLeastVersion(major: i64, minor: i64, patch: i64) bool {
+ comptime assert(builtin.target.os.tag.isDarwin());
+
+ const NSProcessInfo = objc.getClass("NSProcessInfo").?;
+ const info = NSProcessInfo.msgSend(objc.Object, objc.sel("processInfo"), .{});
+ return info.msgSend(bool, objc.sel("isOperatingSystemAtLeastVersion:"), .{
+ NSOperatingSystemVersion{ .major = major, .minor = minor, .patch = patch },
+ });
+}
+
+pub const AppSupportDirError = Allocator.Error || error{AppleAPIFailed};
+
+/// Return the path to the application support directory for Ghostty
+/// with the given sub path joined. This allocates the result using the
+/// given allocator.
+pub fn appSupportDir(
+ alloc: Allocator,
+ sub_path: []const u8,
+) AppSupportDirError![]const u8 {
+ return try commonDir(
+ alloc,
+ .NSApplicationSupportDirectory,
+ &.{ build_config.bundle_id, sub_path },
+ );
+}
+
+pub const CacheDirError = Allocator.Error || error{AppleAPIFailed};
+
+/// Return the path to the system cache directory with the given sub path joined.
+/// This allocates the result using the given allocator.
+pub fn cacheDir(
+ alloc: Allocator,
+ sub_path: []const u8,
+) CacheDirError![]const u8 {
+ return try commonDir(
+ alloc,
+ .NSCachesDirectory,
+ &.{ build_config.bundle_id, sub_path },
+ );
+}
+
+pub const SetQosClassError = error{
+ // The thread can't have its QoS class changed usually because
+ // a different pthread API was called that makes it an invalid
+ // target.
+ ThreadIncompatible,
+};
+
+/// Set the QoS class of the running thread.
+///
+/// https://developer.apple.com/documentation/apple-silicon/tuning-your-code-s-performance-for-apple-silicon?preferredLanguage=occ
+pub fn setQosClass(class: QosClass) !void {
+ return switch (std.posix.errno(pthread_set_qos_class_self_np(
+ class,
+ 0,
+ ))) {
+ .SUCCESS => {},
+ .PERM => error.ThreadIncompatible,
+
+ // EPERM is the only known error that can happen based on
+ // the man pages for pthread_set_qos_class_self_np. I haven't
+ // checked the XNU source code to see if there are other
+ // possible errors.
+ else => @panic("unexpected pthread_set_qos_class_self_np error"),
+ };
+}
+
+/// https://developer.apple.com/library/archive/documentation/Performance/Conceptual/power_efficiency_guidelines_osx/PrioritizeWorkAtTheTaskLevel.html#//apple_ref/doc/uid/TP40013929-CH35-SW1
+pub const QosClass = enum(c_uint) {
+ user_interactive = 0x21,
+ user_initiated = 0x19,
+ default = 0x15,
+ utility = 0x11,
+ background = 0x09,
+ unspecified = 0x00,
+};
+
+extern "c" fn pthread_set_qos_class_self_np(
+ qos_class: QosClass,
+ relative_priority: c_int,
+) c_int;
+
+pub extern "c" fn pthread_setname_np(
+ name: [*:0]const u8,
+) void;
+
+pub const NSOperatingSystemVersion = extern struct {
+ major: i64,
+ minor: i64,
+ patch: i64,
+};
+
+pub const NSSearchPathDirectory = enum(c_ulong) {
+ NSCachesDirectory = 13,
+ NSApplicationSupportDirectory = 14,
+};
+
+pub const NSSearchPathDomainMask = enum(c_ulong) {
+ NSUserDomainMask = 1,
+};
+
+fn commonDir(
+ alloc: Allocator,
+ directory: NSSearchPathDirectory,
+ sub_paths: []const []const u8,
+) (error{AppleAPIFailed} || Allocator.Error)![]const u8 {
+ comptime assert(builtin.target.os.tag.isDarwin());
+
+ const NSFileManager = objc.getClass("NSFileManager").?;
+ const manager = NSFileManager.msgSend(
+ objc.Object,
+ objc.sel("defaultManager"),
+ .{},
+ );
+
+ const url = manager.msgSend(
+ objc.Object,
+ objc.sel("URLForDirectory:inDomain:appropriateForURL:create:error:"),
+ .{
+ directory,
+ NSSearchPathDomainMask.NSUserDomainMask,
+ @as(?*anyopaque, null),
+ true,
+ @as(?*anyopaque, null),
+ },
+ );
+
+ if (url.value == null) return error.AppleAPIFailed;
+
+ const path = url.getProperty(objc.Object, "path");
+ const c_str = path.getProperty(?[*:0]const u8, "UTF8String") orelse
+ return error.AppleAPIFailed;
+ const base_dir = std.mem.sliceTo(c_str, 0);
+
+ // Create a new array with base_dir as the first element
+ var paths = try alloc.alloc([]const u8, sub_paths.len + 1);
+ paths[0] = base_dir;
+ @memcpy(paths[1..], sub_paths);
+ defer alloc.free(paths);
+
+ return try std.fs.path.join(alloc, paths);
+}
+
+test "cacheDir paths" {
+ if (!builtin.target.os.tag.isDarwin()) return;
+
+ const testing = std.testing;
+ const alloc = testing.allocator;
+
+ // Test base path
+ {
+ const cache_path = try cacheDir(alloc, "");
+ defer alloc.free(cache_path);
+ try testing.expect(std.mem.indexOf(u8, cache_path, "Caches") != null);
+ try testing.expect(std.mem.indexOf(u8, cache_path, build_config.bundle_id) != null);
+ }
+
+ // Test with subdir
+ {
+ const cache_path = try cacheDir(alloc, "test");
+ defer alloc.free(cache_path);
+ try testing.expect(std.mem.indexOf(u8, cache_path, "Caches") != null);
+ try testing.expect(std.mem.indexOf(u8, cache_path, build_config.bundle_id) != null);
+
+ const bundle_path = try std.fmt.allocPrint(alloc, "{s}/test", .{build_config.bundle_id});
+ defer alloc.free(bundle_path);
+ try testing.expect(std.mem.indexOf(u8, cache_path, bundle_path) != null);
+ }
+}