mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-07-28 19:46:35 +00:00
Nuke GLFW, make zig build run on macOS build the Xcode project (#7815)
This PR does two things. 1. Build system improvements to make developing on macOS more enjoyable 2. Delete the GLFW apprt ## Build System Improvements (macOS) On macOS, there are a few major improvements: * `zig build` now produces a full macOS app bundle and copies it into `zig-out` * `zig build run` now builds the macOS app and runs it, streaming logs directly into the terminal * `-Demit-macos-app` can control whether app bundle is created * `-Dxcframework-target` can be set to one of `native` or `universal` to control whether the xcframework uses only your target machines arch or creates a universal one with macOS and iOS. This defaults to `native` for the `run` command and `universal` for all others. * The general flow of the `build.zig` file was improved to be more declarative ## Nuke GLFW > This deletes the GLFW apprt from the Ghostty codebase. > > The GLFW apprt was the original apprt used by Ghostty (well, before > Ghostty even had the concept of an "apprt" -- it was all just a single > application then). It let me iterate on the core terminal features, > rendering, etc. without bothering about the UI. It was a good way to get > started. But it has long since outlived its usefulness. > > We've had a stable GTK apprt for Linux (and Windows via WSL) and a > native macOS app via libghostty for awhile now. The GLFW apprt only > remained within the tree for a few reasons: > > 1. Primarily, it provided a faster feedback loop on macOS because > building the macOS app historically required us to hop out of the > zig build system and into Xcode, which is slow and cumbersome. > > 2. It was a convenient way to narrow whether a bug was in the > core Ghostty codebase or in the apprt itself. If a bug was in both > the glfw and macOS app then it was likely in the core. > > 3. It provided us a way on macOS to test OpenGL. > > All of these reasons are no longer valid. Respectively: > > 1. Our Zig build scripts now execute the `xcodebuild` CLI directly and > can open the resulting app, stream logs, etc. This is the same > experience we have on Linux. (Xcode has always been a dependency of > building on macOS in general, so this is not cumbersome.) > > 2. We have a healthy group of maintainers, many of which have access > to both macOS and Linux, so we can quickly narrow down bugs > regardless of the apprt. > > 3. Our OpenGL renderer hasn't been compatible with macOS for some time > now, so this is no longer a useful feature. > > At this point, the GLFW apprt is just a burden. It adds complexity > across the board, and some people try to run Ghostty with it in the real > world and get confused when it doesn't work (it's always been lacking in > features and buggy compared to the other apprts). > > So, it's time to say goodbye. Its bittersweet because it is a big part > of Ghostty's history, but we've grown up now and it's time to move on. > Thank you, goodbye. > > (NOTE: If you are a user of the GLFW apprt, then please fork the project > prior to this commit or start a new project based on it. We've warned > against using it for a very, very long time now.)
This commit is contained in:
@@ -5,7 +5,6 @@ const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const builtin = @import("builtin");
|
||||
const glfw = @import("glfw");
|
||||
const objc = @import("objc");
|
||||
const macos = @import("macos");
|
||||
const graphics = macos.graphics;
|
||||
@@ -38,11 +37,6 @@ pub const swap_chain_count = 3;
|
||||
|
||||
const log = std.log.scoped(.metal);
|
||||
|
||||
// Get native API access on certain platforms so we can do more customization.
|
||||
const glfwNative = glfw.Native(.{
|
||||
.cocoa = builtin.os.tag == .macos,
|
||||
});
|
||||
|
||||
layer: IOSurfaceLayer,
|
||||
|
||||
/// MTLDevice
|
||||
@@ -87,27 +81,6 @@ pub fn init(alloc: Allocator, opts: rendererpkg.Options) !Metal {
|
||||
|
||||
// Get the metadata about our underlying view that we'll be rendering to.
|
||||
const info: ViewInfo = switch (apprt.runtime) {
|
||||
apprt.glfw => info: {
|
||||
// Everything in glfw is window-oriented so we grab the backing
|
||||
// window, then derive everything from that.
|
||||
const nswindow = objc.Object.fromId(glfwNative.getCocoaWindow(
|
||||
opts.rt_surface.window,
|
||||
).?);
|
||||
|
||||
const contentView = objc.Object.fromId(
|
||||
nswindow.getProperty(?*anyopaque, "contentView").?,
|
||||
);
|
||||
const scaleFactor = nswindow.getProperty(
|
||||
graphics.c.CGFloat,
|
||||
"backingScaleFactor",
|
||||
);
|
||||
|
||||
break :info .{
|
||||
.view = contentView,
|
||||
.scaleFactor = scaleFactor,
|
||||
};
|
||||
},
|
||||
|
||||
apprt.embedded => .{
|
||||
.scaleFactor = @floatCast(opts.rt_surface.content_scale.x),
|
||||
.view = switch (opts.rt_surface.platform) {
|
||||
|
||||
@@ -5,7 +5,6 @@ const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const builtin = @import("builtin");
|
||||
const glfw = @import("glfw");
|
||||
const gl = @import("opengl");
|
||||
const shadertoy = @import("shadertoy.zig");
|
||||
const apprt = @import("../apprt.zig");
|
||||
@@ -60,18 +59,6 @@ pub fn deinit(self: *OpenGL) void {
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
/// Returns the hints that we want for this
|
||||
pub fn glfwWindowHints(config: *const configpkg.Config) glfw.Window.Hints {
|
||||
_ = config;
|
||||
return .{
|
||||
.context_version_major = MIN_VERSION_MAJOR,
|
||||
.context_version_minor = MIN_VERSION_MINOR,
|
||||
.opengl_profile = .opengl_core_profile,
|
||||
.opengl_forward_compat = true,
|
||||
.transparent_framebuffer = true,
|
||||
};
|
||||
}
|
||||
|
||||
/// 32-bit windows cross-compilation breaks with `.c` for some reason, so...
|
||||
const gl_debug_proc_callconv =
|
||||
@typeInfo(
|
||||
@@ -172,8 +159,7 @@ fn prepareContext(getProcAddress: anytype) !void {
|
||||
|
||||
/// This is called early right after surface creation.
|
||||
pub fn surfaceInit(surface: *apprt.Surface) !void {
|
||||
// Treat this like a thread entry
|
||||
const self: OpenGL = undefined;
|
||||
_ = surface;
|
||||
|
||||
switch (apprt.runtime) {
|
||||
else => @compileError("unsupported app runtime for OpenGL"),
|
||||
@@ -181,8 +167,6 @@ pub fn surfaceInit(surface: *apprt.Surface) !void {
|
||||
// GTK uses global OpenGL context so we load from null.
|
||||
apprt.gtk => try prepareContext(null),
|
||||
|
||||
apprt.glfw => try self.threadEnter(surface),
|
||||
|
||||
apprt.embedded => {
|
||||
// TODO(mitchellh): this does nothing today to allow libghostty
|
||||
// to compile for OpenGL targets but libghostty is strictly
|
||||
@@ -205,17 +189,12 @@ pub fn surfaceInit(surface: *apprt.Surface) !void {
|
||||
pub fn finalizeSurfaceInit(self: *const OpenGL, surface: *apprt.Surface) !void {
|
||||
_ = self;
|
||||
_ = surface;
|
||||
|
||||
// For GLFW, we grabbed the OpenGL context in surfaceInit and
|
||||
// we need to release it before we start the renderer thread.
|
||||
if (apprt.runtime == apprt.glfw) {
|
||||
glfw.makeContextCurrent(null);
|
||||
}
|
||||
}
|
||||
|
||||
/// Callback called by renderer.Thread when it begins.
|
||||
pub fn threadEnter(self: *const OpenGL, surface: *apprt.Surface) !void {
|
||||
_ = self;
|
||||
_ = surface;
|
||||
|
||||
switch (apprt.runtime) {
|
||||
else => @compileError("unsupported app runtime for OpenGL"),
|
||||
@@ -227,21 +206,6 @@ pub fn threadEnter(self: *const OpenGL, surface: *apprt.Surface) !void {
|
||||
// on the main thread. As such, we don't do anything here.
|
||||
},
|
||||
|
||||
apprt.glfw => {
|
||||
// We need to make the OpenGL context current. OpenGL requires
|
||||
// that a single thread own the a single OpenGL context (if any).
|
||||
// This ensures that the context switches over to our thread.
|
||||
// Important: the prior thread MUST have detached the context
|
||||
// prior to calling this entrypoint.
|
||||
glfw.makeContextCurrent(surface.window);
|
||||
errdefer glfw.makeContextCurrent(null);
|
||||
glfw.swapInterval(1);
|
||||
|
||||
// Load OpenGL bindings. This API is context-aware so this sets
|
||||
// a threadlocal context for these pointers.
|
||||
try prepareContext(&glfw.getProcAddress);
|
||||
},
|
||||
|
||||
apprt.embedded => {
|
||||
// TODO(mitchellh): this does nothing today to allow libghostty
|
||||
// to compile for OpenGL targets but libghostty is strictly
|
||||
@@ -262,11 +226,6 @@ pub fn threadExit(self: *const OpenGL) void {
|
||||
// be sharing the global bindings with other windows.
|
||||
},
|
||||
|
||||
apprt.glfw => {
|
||||
gl.glad.unload();
|
||||
glfw.makeContextCurrent(null);
|
||||
},
|
||||
|
||||
apprt.embedded => {
|
||||
// TODO: see threadEnter
|
||||
},
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const glfw = @import("glfw");
|
||||
const xev = @import("xev");
|
||||
const wuffs = @import("wuffs");
|
||||
const apprt = @import("../apprt.zig");
|
||||
@@ -606,20 +605,6 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
||||
}
|
||||
};
|
||||
|
||||
/// Returns the hints that we want for this window.
|
||||
pub fn glfwWindowHints(config: *const configpkg.Config) glfw.Window.Hints {
|
||||
// If our graphics API provides hints, use them,
|
||||
// otherwise fall back to generic hints.
|
||||
if (@hasDecl(GraphicsAPI, "glfwWindowHints")) {
|
||||
return GraphicsAPI.glfwWindowHints(config);
|
||||
}
|
||||
|
||||
return .{
|
||||
.client_api = .no_api,
|
||||
.transparent_framebuffer = config.@"background-opacity" < 1,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn init(alloc: Allocator, options: renderer.Options) !Self {
|
||||
// Initialize our graphics API wrapper, this will prepare the
|
||||
// surface provided by the apprt and set up any API-specific
|
||||
|
||||
Reference in New Issue
Block a user