mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-07-25 18:21:56 +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:
@@ -3,7 +3,7 @@
|
||||
//! getting user input (mouse/keyboard), etc.
|
||||
//!
|
||||
//! This enables compile-time interfaces to be built to swap out the underlying
|
||||
//! application runtime. For example: glfw, pure macOS Cocoa, GTK+, browser, etc.
|
||||
//! application runtime. For example: pure macOS Cocoa, GTK+, browser, etc.
|
||||
//!
|
||||
//! The goal is to have different implementations share as much of the core
|
||||
//! logic as possible, and to only reach out to platform-specific implementation
|
||||
@@ -15,7 +15,6 @@ const build_config = @import("build_config.zig");
|
||||
const structs = @import("apprt/structs.zig");
|
||||
|
||||
pub const action = @import("apprt/action.zig");
|
||||
pub const glfw = @import("apprt/glfw.zig");
|
||||
pub const gtk = @import("apprt/gtk.zig");
|
||||
pub const none = @import("apprt/none.zig");
|
||||
pub const browser = @import("apprt/browser.zig");
|
||||
@@ -42,7 +41,6 @@ pub const SurfaceSize = structs.SurfaceSize;
|
||||
pub const runtime = switch (build_config.artifact) {
|
||||
.exe => switch (build_config.app_runtime) {
|
||||
.none => none,
|
||||
.glfw => glfw,
|
||||
.gtk => gtk,
|
||||
},
|
||||
.lib => embedded,
|
||||
@@ -53,18 +51,12 @@ pub const App = runtime.App;
|
||||
pub const Surface = runtime.Surface;
|
||||
|
||||
/// Runtime is the runtime to use for Ghostty. All runtimes do not provide
|
||||
/// equivalent feature sets. For example, GTK offers tabbing and more features
|
||||
/// that glfw does not provide. However, glfw may require many less
|
||||
/// dependencies.
|
||||
/// equivalent feature sets.
|
||||
pub const Runtime = enum {
|
||||
/// Will not produce an executable at all when `zig build` is called.
|
||||
/// This is only useful if you're only interested in the lib only (macOS).
|
||||
none,
|
||||
|
||||
/// Glfw-backed. Very simple. Glfw is statically linked. Tabbing and
|
||||
/// other rich windowing features are not supported.
|
||||
glfw,
|
||||
|
||||
/// GTK-backed. Rich windowed application. GTK is dynamically linked.
|
||||
gtk,
|
||||
|
||||
@@ -72,12 +64,8 @@ pub const Runtime = enum {
|
||||
// The Linux default is GTK because it is full featured.
|
||||
if (target.os.tag == .linux) return .gtk;
|
||||
|
||||
// Windows we currently only support glfw
|
||||
if (target.os.tag == .windows) return .glfw;
|
||||
|
||||
// Otherwise, we do NONE so we don't create an exe. The GLFW
|
||||
// build is opt-in because it is missing so many features compared
|
||||
// to the other builds that are impossible due to the GLFW interface.
|
||||
// Otherwise, we do NONE so we don't create an exe and we
|
||||
// create libghostty.
|
||||
return .none;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -236,7 +236,7 @@ pub const App = struct {
|
||||
var surface = try self.core_app.alloc.create(Surface);
|
||||
errdefer self.core_app.alloc.destroy(surface);
|
||||
|
||||
// Create the surface -- because windows are surfaces for glfw.
|
||||
// Create the surface
|
||||
try surface.init(self, opts);
|
||||
errdefer surface.deinit();
|
||||
|
||||
|
||||
1266
src/apprt/glfw.zig
1266
src/apprt/glfw.zig
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@ const apprt = @import("../apprt.zig");
|
||||
const font = @import("../font/main.zig");
|
||||
const rendererpkg = @import("../renderer.zig");
|
||||
const Command = @import("../Command.zig");
|
||||
const XCFramework = @import("GhosttyXCFramework.zig");
|
||||
const WasmTarget = @import("../os/wasm/target.zig").Target;
|
||||
|
||||
const gtk = @import("gtk.zig");
|
||||
@@ -24,6 +25,7 @@ const app_version: std.SemanticVersion = .{ .major = 1, .minor = 1, .patch = 4 }
|
||||
/// Standard build configuration options.
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
target: std.Build.ResolvedTarget,
|
||||
xcframework_target: XCFramework.Target = .universal,
|
||||
wasm_target: WasmTarget,
|
||||
|
||||
/// Comptime interfaces
|
||||
@@ -48,14 +50,15 @@ patch_rpath: ?[]const u8 = null,
|
||||
|
||||
/// Artifacts
|
||||
flatpak: bool = false,
|
||||
emit_test_exe: bool = false,
|
||||
emit_bench: bool = false,
|
||||
emit_helpgen: bool = false,
|
||||
emit_docs: bool = false,
|
||||
emit_webdata: bool = false,
|
||||
emit_xcframework: bool = false,
|
||||
emit_helpgen: bool = false,
|
||||
emit_macos_app: bool = false,
|
||||
emit_terminfo: bool = false,
|
||||
emit_termcap: bool = false,
|
||||
emit_test_exe: bool = false,
|
||||
emit_xcframework: bool = false,
|
||||
emit_webdata: bool = false,
|
||||
|
||||
/// Environmental properties
|
||||
env: std.process.EnvMap,
|
||||
@@ -109,6 +112,14 @@ pub fn init(b: *std.Build) !Config {
|
||||
.env = env,
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Target-specific properties
|
||||
config.xcframework_target = b.option(
|
||||
XCFramework.Target,
|
||||
"xcframework-target",
|
||||
"The target for the xcframework.",
|
||||
) orelse .universal;
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Comptime Interfaces
|
||||
config.font_backend = b.option(
|
||||
@@ -340,6 +351,12 @@ pub fn init(b: *std.Build) !Config {
|
||||
!config.emit_test_exe and
|
||||
!config.emit_helpgen);
|
||||
|
||||
config.emit_macos_app = b.option(
|
||||
bool,
|
||||
"emit-macos-app",
|
||||
"Build and install the macOS app bundle.",
|
||||
) orelse config.emit_xcframework;
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// System Packages
|
||||
|
||||
@@ -378,11 +395,6 @@ pub fn init(b: *std.Build) !Config {
|
||||
"glslang",
|
||||
"spirv-cross",
|
||||
"simdutf",
|
||||
|
||||
// This is default false because it is used for testing
|
||||
// primarily and not official packaging. The packaging
|
||||
// guide advises against building the GLFW backend.
|
||||
"glfw3",
|
||||
}) |dep| {
|
||||
_ = b.systemIntegrationOption(dep, .{ .default = false });
|
||||
}
|
||||
|
||||
@@ -93,5 +93,32 @@ pub fn init(
|
||||
|
||||
pub fn install(self: *const GhosttyDocs) void {
|
||||
const b = self.steps[0].owner;
|
||||
for (self.steps) |step| b.getInstallStep().dependOn(step);
|
||||
self.addStepDependencies(b.getInstallStep());
|
||||
}
|
||||
|
||||
pub fn addStepDependencies(
|
||||
self: *const GhosttyDocs,
|
||||
other_step: *std.Build.Step,
|
||||
) void {
|
||||
for (self.steps) |step| other_step.dependOn(step);
|
||||
}
|
||||
|
||||
/// Installs some dummy files to satisfy the folder structure of docs
|
||||
/// without actually generating any documentation. This is useful
|
||||
/// when the `emit-docs` option is not set to true, but we still
|
||||
/// need the rough directory structure to exist, such as for the macOS
|
||||
/// app.
|
||||
pub fn installDummy(self: *const GhosttyDocs, step: *std.Build.Step) void {
|
||||
_ = self;
|
||||
|
||||
const b = step.owner;
|
||||
var wf = b.addWriteFiles();
|
||||
const path = "share/man/.placeholder";
|
||||
step.dependOn(&b.addInstallFile(
|
||||
wf.add(
|
||||
path,
|
||||
"emit-docs not true so no man pages",
|
||||
),
|
||||
path,
|
||||
).step);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,14 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyI18n {
|
||||
}
|
||||
|
||||
pub fn install(self: *const GhosttyI18n) void {
|
||||
for (self.steps) |step| self.owner.getInstallStep().dependOn(step);
|
||||
self.addStepDependencies(self.owner.getInstallStep());
|
||||
}
|
||||
|
||||
pub fn addStepDependencies(
|
||||
self: *const GhosttyI18n,
|
||||
other_step: *std.Build.Step,
|
||||
) void {
|
||||
for (self.steps) |step| other_step.dependOn(step);
|
||||
}
|
||||
|
||||
fn createUpdateStep(b: *std.Build) !*std.Build.Step {
|
||||
|
||||
@@ -397,5 +397,12 @@ fn addLinuxAppResources(
|
||||
|
||||
pub fn install(self: *const GhosttyResources) void {
|
||||
const b = self.steps[0].owner;
|
||||
for (self.steps) |step| b.getInstallStep().dependOn(step);
|
||||
self.addStepDependencies(b.getInstallStep());
|
||||
}
|
||||
|
||||
pub fn addStepDependencies(
|
||||
self: *const GhosttyResources,
|
||||
other_step: *std.Build.Step,
|
||||
) void {
|
||||
for (self.steps) |step| other_step.dependOn(step);
|
||||
}
|
||||
|
||||
@@ -7,11 +7,23 @@ const GhosttyLib = @import("GhosttyLib.zig");
|
||||
const XCFrameworkStep = @import("XCFrameworkStep.zig");
|
||||
|
||||
xcframework: *XCFrameworkStep,
|
||||
macos: GhosttyLib,
|
||||
target: Target,
|
||||
|
||||
pub fn init(b: *std.Build, deps: *const SharedDeps) !GhosttyXCFramework {
|
||||
// Create our universal macOS static library.
|
||||
const macos = try GhosttyLib.initMacOSUniversal(b, deps);
|
||||
pub const Target = enum { native, universal };
|
||||
|
||||
pub fn init(
|
||||
b: *std.Build,
|
||||
deps: *const SharedDeps,
|
||||
target: Target,
|
||||
) !GhosttyXCFramework {
|
||||
// Universal macOS build
|
||||
const macos_universal = try GhosttyLib.initMacOSUniversal(b, deps);
|
||||
|
||||
// Native macOS build
|
||||
const macos_native = try GhosttyLib.initStatic(b, &try deps.retarget(
|
||||
b,
|
||||
Config.genericMacOSTarget(b, null),
|
||||
));
|
||||
|
||||
// iOS
|
||||
const ios = try GhosttyLib.initStatic(b, &try deps.retarget(
|
||||
@@ -47,29 +59,43 @@ pub fn init(b: *std.Build, deps: *const SharedDeps) !GhosttyXCFramework {
|
||||
const xcframework = XCFrameworkStep.create(b, .{
|
||||
.name = "GhosttyKit",
|
||||
.out_path = "macos/GhosttyKit.xcframework",
|
||||
.libraries = &.{
|
||||
.{
|
||||
.library = macos.output,
|
||||
.headers = b.path("include"),
|
||||
.libraries = switch (target) {
|
||||
.universal => &.{
|
||||
.{
|
||||
.library = macos_universal.output,
|
||||
.headers = b.path("include"),
|
||||
},
|
||||
.{
|
||||
.library = ios.output,
|
||||
.headers = b.path("include"),
|
||||
},
|
||||
.{
|
||||
.library = ios_sim.output,
|
||||
.headers = b.path("include"),
|
||||
},
|
||||
},
|
||||
.{
|
||||
.library = ios.output,
|
||||
|
||||
.native => &.{.{
|
||||
.library = macos_native.output,
|
||||
.headers = b.path("include"),
|
||||
},
|
||||
.{
|
||||
.library = ios_sim.output,
|
||||
.headers = b.path("include"),
|
||||
},
|
||||
}},
|
||||
},
|
||||
});
|
||||
|
||||
return .{
|
||||
.xcframework = xcframework,
|
||||
.macos = macos,
|
||||
.target = target,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn install(self: *const GhosttyXCFramework) void {
|
||||
const b = self.xcframework.step.owner;
|
||||
b.getInstallStep().dependOn(self.xcframework.step);
|
||||
self.addStepDependencies(b.getInstallStep());
|
||||
}
|
||||
|
||||
pub fn addStepDependencies(
|
||||
self: *const GhosttyXCFramework,
|
||||
other_step: *std.Build.Step,
|
||||
) void {
|
||||
other_step.dependOn(self.xcframework.step);
|
||||
}
|
||||
|
||||
149
src/build/GhosttyXcodebuild.zig
Normal file
149
src/build/GhosttyXcodebuild.zig
Normal file
@@ -0,0 +1,149 @@
|
||||
const Ghostty = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const RunStep = std.Build.Step.Run;
|
||||
const Config = @import("Config.zig");
|
||||
const Docs = @import("GhosttyDocs.zig");
|
||||
const I18n = @import("GhosttyI18n.zig");
|
||||
const Resources = @import("GhosttyResources.zig");
|
||||
const XCFramework = @import("GhosttyXCFramework.zig");
|
||||
|
||||
build: *std.Build.Step.Run,
|
||||
open: *std.Build.Step.Run,
|
||||
copy: *std.Build.Step.Run,
|
||||
|
||||
pub const Deps = struct {
|
||||
xcframework: *const XCFramework,
|
||||
docs: *const Docs,
|
||||
i18n: *const I18n,
|
||||
resources: *const Resources,
|
||||
};
|
||||
|
||||
pub fn init(
|
||||
b: *std.Build,
|
||||
config: *const Config,
|
||||
deps: Deps,
|
||||
) !Ghostty {
|
||||
const xc_config = switch (config.optimize) {
|
||||
.Debug => "Debug",
|
||||
.ReleaseSafe,
|
||||
.ReleaseSmall,
|
||||
.ReleaseFast,
|
||||
=> "Release",
|
||||
};
|
||||
|
||||
const app_path = b.fmt("macos/build/{s}/Ghostty.app", .{xc_config});
|
||||
|
||||
// Our step to build the Ghostty macOS app.
|
||||
const build = build: {
|
||||
// External environment variables can mess up xcodebuild, so
|
||||
// we create a new empty environment.
|
||||
const env_map = try b.allocator.create(std.process.EnvMap);
|
||||
env_map.* = .init(b.allocator);
|
||||
|
||||
const build = RunStep.create(b, "xcodebuild");
|
||||
build.has_side_effects = true;
|
||||
build.cwd = b.path("macos");
|
||||
build.env_map = env_map;
|
||||
build.addArgs(&.{
|
||||
"xcodebuild",
|
||||
"-target",
|
||||
"Ghostty",
|
||||
"-configuration",
|
||||
xc_config,
|
||||
});
|
||||
|
||||
switch (deps.xcframework.target) {
|
||||
// Universal is our default target, so we don't have to
|
||||
// add anything.
|
||||
.universal => {},
|
||||
|
||||
// Native we need to override the architecture in the Xcode
|
||||
// project with the -arch flag.
|
||||
.native => build.addArgs(&.{
|
||||
"-arch",
|
||||
switch (builtin.cpu.arch) {
|
||||
.aarch64 => "arm64",
|
||||
.x86_64 => "x86_64",
|
||||
else => @panic("unsupported macOS arch"),
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
// We need the xcframework
|
||||
deps.xcframework.addStepDependencies(&build.step);
|
||||
|
||||
// We also need all these resources because the xcode project
|
||||
// references them via symlinks.
|
||||
deps.resources.addStepDependencies(&build.step);
|
||||
deps.i18n.addStepDependencies(&build.step);
|
||||
deps.docs.installDummy(&build.step);
|
||||
|
||||
// Expect success
|
||||
build.expectExitCode(0);
|
||||
|
||||
break :build build;
|
||||
};
|
||||
|
||||
// Our step to open the resulting Ghostty app.
|
||||
const open = open: {
|
||||
const open = RunStep.create(b, "run Ghostty app");
|
||||
open.has_side_effects = true;
|
||||
open.cwd = b.path("");
|
||||
open.addArgs(&.{b.fmt(
|
||||
"{s}/Contents/MacOS/ghostty",
|
||||
.{app_path},
|
||||
)});
|
||||
|
||||
// Open depends on the app
|
||||
open.step.dependOn(&build.step);
|
||||
|
||||
// This overrides our default behavior and forces logs to show
|
||||
// up on stderr (in addition to the centralized macOS log).
|
||||
open.setEnvironmentVariable("GHOSTTY_LOG", "1");
|
||||
|
||||
// This is hack so that we can activate the app and bring it to
|
||||
// the front forcibly even though we're executing directly
|
||||
// via the binary and not launch services.
|
||||
open.setEnvironmentVariable("GHOSTTY_MAC_ACTIVATE", "1");
|
||||
|
||||
if (b.args) |args| {
|
||||
open.addArgs(args);
|
||||
} else {
|
||||
// This tricks the app into thinking it's running from the
|
||||
// app bundle so we don't execute our CLI mode.
|
||||
open.setEnvironmentVariable("GHOSTTY_MAC_APP", "1");
|
||||
}
|
||||
|
||||
break :open open;
|
||||
};
|
||||
|
||||
// Our step to copy the app bundle to the install path.
|
||||
// We have to use `cp -R` because there are symlinks in the
|
||||
// bundle.
|
||||
const copy = copy: {
|
||||
const step = RunStep.create(b, "copy app bundle");
|
||||
step.addArgs(&.{ "cp", "-R" });
|
||||
step.addFileArg(b.path(app_path));
|
||||
step.addArg(b.fmt("{s}", .{b.install_path}));
|
||||
step.step.dependOn(&build.step);
|
||||
break :copy step;
|
||||
};
|
||||
|
||||
return .{
|
||||
.build = build,
|
||||
.open = open,
|
||||
.copy = copy,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn install(self: *const Ghostty) void {
|
||||
const b = self.copy.step.owner;
|
||||
b.getInstallStep().dependOn(&self.copy.step);
|
||||
}
|
||||
|
||||
pub fn installXcframework(self: *const Ghostty) void {
|
||||
const b = self.build.step.owner;
|
||||
b.getInstallStep().dependOn(&self.build.step);
|
||||
}
|
||||
@@ -515,17 +515,6 @@ pub fn add(
|
||||
|
||||
switch (self.config.app_runtime) {
|
||||
.none => {},
|
||||
|
||||
.glfw => if (b.lazyDependency("glfw", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
})) |glfw_dep| {
|
||||
step.root_module.addImport(
|
||||
"glfw",
|
||||
glfw_dep.module("glfw"),
|
||||
);
|
||||
},
|
||||
|
||||
.gtk => try self.addGTK(step),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,9 @@ pub fn create(b: *std.Build, opts: Options) *XCFrameworkStep {
|
||||
}
|
||||
run.addArg("-output");
|
||||
run.addArg(opts.out_path);
|
||||
run.expectExitCode(0);
|
||||
_ = run.captureStdOut();
|
||||
_ = run.captureStdErr();
|
||||
break :run run;
|
||||
};
|
||||
run_create.step.dependOn(&run_delete.step);
|
||||
|
||||
@@ -15,6 +15,7 @@ pub const GhosttyFrameData = @import("GhosttyFrameData.zig");
|
||||
pub const GhosttyLib = @import("GhosttyLib.zig");
|
||||
pub const GhosttyResources = @import("GhosttyResources.zig");
|
||||
pub const GhosttyI18n = @import("GhosttyI18n.zig");
|
||||
pub const GhosttyXcodebuild = @import("GhosttyXcodebuild.zig");
|
||||
pub const GhosttyXCFramework = @import("GhosttyXCFramework.zig");
|
||||
pub const GhosttyWebdata = @import("GhosttyWebdata.zig");
|
||||
pub const HelpStrings = @import("HelpStrings.zig");
|
||||
|
||||
@@ -1582,9 +1582,9 @@ keybind: Keybinds = .{},
|
||||
/// the visible screen area. This means that if the menu bar is visible, the
|
||||
/// window will be placed below the menu bar.
|
||||
///
|
||||
/// Note: this is only supported on macOS and Linux GLFW builds. The GTK
|
||||
/// runtime does not support setting the window position, as windows are
|
||||
/// only allowed position themselves in X11 and not Wayland.
|
||||
/// Note: this is only supported on macOS. The GTK runtime does not support
|
||||
/// setting the window position, as windows are only allowed position
|
||||
/// themselves in X11 and not Wayland.
|
||||
@"window-position-x": ?i16 = null,
|
||||
@"window-position-y": ?i16 = null,
|
||||
|
||||
@@ -2504,8 +2504,6 @@ keybind: Keybinds = .{},
|
||||
///
|
||||
/// The values `left` or `right` enable this for the left or right *Option*
|
||||
/// key, respectively.
|
||||
///
|
||||
/// This does not work with GLFW builds.
|
||||
@"macos-option-as-alt": ?OptionAsAlt = null,
|
||||
|
||||
/// Whether to enable the macOS window shadow. The default value is true.
|
||||
|
||||
@@ -7,7 +7,6 @@ const Allocator = std.mem.Allocator;
|
||||
const posix = std.posix;
|
||||
const build_config = @import("build_config.zig");
|
||||
const options = @import("build_options");
|
||||
const glfw = @import("glfw");
|
||||
const glslang = @import("glslang");
|
||||
const macos = @import("macos");
|
||||
const oni = @import("oniguruma");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -15,11 +15,6 @@ const posix = std.posix;
|
||||
|
||||
const log = std.log.scoped(.io_handler);
|
||||
|
||||
/// True if we should disable the kitty keyboard protocol. We have to
|
||||
/// disable this on GLFW because GLFW input events don't support the
|
||||
/// correct granularity of events.
|
||||
const disable_kitty_keyboard_protocol = apprt.runtime == apprt.glfw;
|
||||
|
||||
/// This is used as the handler for the terminal.Stream type. This is
|
||||
/// stateful and is expected to live for the entire lifetime of the terminal.
|
||||
/// It is NOT VALID to stop a stream handler, create a new one, and use that
|
||||
@@ -913,8 +908,6 @@ pub const StreamHandler = struct {
|
||||
}
|
||||
|
||||
pub fn queryKittyKeyboard(self: *StreamHandler) !void {
|
||||
if (comptime disable_kitty_keyboard_protocol) return;
|
||||
|
||||
log.debug("querying kitty keyboard mode", .{});
|
||||
var data: termio.Message.WriteReq.Small.Array = undefined;
|
||||
const resp = try std.fmt.bufPrint(&data, "\x1b[?{}u", .{
|
||||
@@ -933,15 +926,11 @@ pub const StreamHandler = struct {
|
||||
self: *StreamHandler,
|
||||
flags: terminal.kitty.KeyFlags,
|
||||
) !void {
|
||||
if (comptime disable_kitty_keyboard_protocol) return;
|
||||
|
||||
log.debug("pushing kitty keyboard mode: {}", .{flags});
|
||||
self.terminal.screen.kitty_keyboard.push(flags);
|
||||
}
|
||||
|
||||
pub fn popKittyKeyboard(self: *StreamHandler, n: u16) !void {
|
||||
if (comptime disable_kitty_keyboard_protocol) return;
|
||||
|
||||
log.debug("popping kitty keyboard mode n={}", .{n});
|
||||
self.terminal.screen.kitty_keyboard.pop(@intCast(n));
|
||||
}
|
||||
@@ -951,8 +940,6 @@ pub const StreamHandler = struct {
|
||||
mode: terminal.kitty.KeySetMode,
|
||||
flags: terminal.kitty.KeyFlags,
|
||||
) !void {
|
||||
if (comptime disable_kitty_keyboard_protocol) return;
|
||||
|
||||
log.debug("setting kitty keyboard mode: {} {}", .{ mode, flags });
|
||||
self.terminal.screen.kitty_keyboard.set(mode, flags);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user