mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
add app runtime option, add gtk backend
This commit is contained in:
43
build.zig
43
build.zig
@ -3,6 +3,7 @@ const builtin = @import("builtin");
|
|||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const Builder = std.build.Builder;
|
const Builder = std.build.Builder;
|
||||||
const LibExeObjStep = std.build.LibExeObjStep;
|
const LibExeObjStep = std.build.LibExeObjStep;
|
||||||
|
const apprt = @import("src/apprt.zig");
|
||||||
const glfw = @import("vendor/mach/libs/glfw/build.zig");
|
const glfw = @import("vendor/mach/libs/glfw/build.zig");
|
||||||
const fontconfig = @import("pkg/fontconfig/build.zig");
|
const fontconfig = @import("pkg/fontconfig/build.zig");
|
||||||
const freetype = @import("pkg/freetype/build.zig");
|
const freetype = @import("pkg/freetype/build.zig");
|
||||||
@ -45,6 +46,7 @@ comptime {
|
|||||||
var tracy: bool = false;
|
var tracy: bool = false;
|
||||||
var enable_coretext: bool = false;
|
var enable_coretext: bool = false;
|
||||||
var enable_fontconfig: bool = false;
|
var enable_fontconfig: bool = false;
|
||||||
|
var app_runtime: apprt.Runtime = .none;
|
||||||
|
|
||||||
pub fn build(b: *std.build.Builder) !void {
|
pub fn build(b: *std.build.Builder) !void {
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
@ -77,6 +79,12 @@ pub fn build(b: *std.build.Builder) !void {
|
|||||||
"Enable fontconfig for font discovery (default true on Linux)",
|
"Enable fontconfig for font discovery (default true on Linux)",
|
||||||
) orelse target.isLinux();
|
) orelse target.isLinux();
|
||||||
|
|
||||||
|
app_runtime = b.option(
|
||||||
|
apprt.Runtime,
|
||||||
|
"app-runtime",
|
||||||
|
"The app runtime to use. Not all values supported on all platforms.",
|
||||||
|
) orelse apprt.Runtime.default(target);
|
||||||
|
|
||||||
const static = b.option(
|
const static = b.option(
|
||||||
bool,
|
bool,
|
||||||
"static",
|
"static",
|
||||||
@ -111,6 +119,7 @@ pub fn build(b: *std.build.Builder) !void {
|
|||||||
exe_options.addOption(bool, "tracy_enabled", tracy);
|
exe_options.addOption(bool, "tracy_enabled", tracy);
|
||||||
exe_options.addOption(bool, "coretext", enable_coretext);
|
exe_options.addOption(bool, "coretext", enable_coretext);
|
||||||
exe_options.addOption(bool, "fontconfig", enable_fontconfig);
|
exe_options.addOption(bool, "fontconfig", enable_fontconfig);
|
||||||
|
exe_options.addOption(apprt.Runtime, "app_runtime", app_runtime);
|
||||||
|
|
||||||
// Exe
|
// Exe
|
||||||
{
|
{
|
||||||
@ -120,7 +129,7 @@ pub fn build(b: *std.build.Builder) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exe.addOptions("build_options", exe_options);
|
exe.addOptions("build_options", exe_options);
|
||||||
exe.install();
|
if (app_runtime != .none) exe.install();
|
||||||
|
|
||||||
// Add the shared dependencies
|
// Add the shared dependencies
|
||||||
_ = try addDeps(b, exe, static);
|
_ = try addDeps(b, exe, static);
|
||||||
@ -134,7 +143,7 @@ pub fn build(b: *std.build.Builder) !void {
|
|||||||
b.installFile("dist/macos/Ghostty.icns", "Ghostty.app/Contents/Resources/Ghostty.icns");
|
b.installFile("dist/macos/Ghostty.icns", "Ghostty.app/Contents/Resources/Ghostty.icns");
|
||||||
}
|
}
|
||||||
|
|
||||||
// On Mac we can build the app.
|
// On Mac we can build the embedding library.
|
||||||
if (builtin.target.isDarwin()) {
|
if (builtin.target.isDarwin()) {
|
||||||
const static_lib_aarch64 = lib: {
|
const static_lib_aarch64 = lib: {
|
||||||
const lib = b.addStaticLibrary(.{
|
const lib = b.addStaticLibrary(.{
|
||||||
@ -539,22 +548,30 @@ fn addDeps(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!lib) {
|
if (!lib) {
|
||||||
step.addModule("glfw", glfw.module(b));
|
|
||||||
|
|
||||||
// We always statically compile glad
|
// We always statically compile glad
|
||||||
step.addIncludePath("vendor/glad/include/");
|
step.addIncludePath("vendor/glad/include/");
|
||||||
step.addCSourceFile("vendor/glad/src/gl.c", &.{});
|
step.addCSourceFile("vendor/glad/src/gl.c", &.{});
|
||||||
|
|
||||||
// Glfw
|
switch (app_runtime) {
|
||||||
const glfw_opts: glfw.Options = .{
|
.none => {},
|
||||||
.metal = step.target.isDarwin(),
|
|
||||||
.opengl = false,
|
|
||||||
};
|
|
||||||
try glfw.link(b, step, glfw_opts);
|
|
||||||
|
|
||||||
// Imgui
|
.glfw => {
|
||||||
const imgui_step = try imgui.link(b, step, imgui_opts);
|
step.addModule("glfw", glfw.module(b));
|
||||||
try glfw.link(b, imgui_step, glfw_opts);
|
const glfw_opts: glfw.Options = .{
|
||||||
|
.metal = step.target.isDarwin(),
|
||||||
|
.opengl = false,
|
||||||
|
};
|
||||||
|
try glfw.link(b, step, glfw_opts);
|
||||||
|
|
||||||
|
// Must also link to imgui
|
||||||
|
const imgui_step = try imgui.link(b, step, imgui_opts);
|
||||||
|
try glfw.link(b, imgui_step, glfw_opts);
|
||||||
|
},
|
||||||
|
|
||||||
|
.gtk => {
|
||||||
|
step.linkSystemLibrary("gtk4");
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_libs;
|
return static_libs;
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
, expat
|
, expat
|
||||||
, fontconfig
|
, fontconfig
|
||||||
, freetype
|
, freetype
|
||||||
|
, gtk4
|
||||||
, harfbuzz
|
, harfbuzz
|
||||||
, libpng
|
, libpng
|
||||||
, libGL
|
, libGL
|
||||||
@ -53,6 +54,8 @@ let
|
|||||||
libXcursor
|
libXcursor
|
||||||
libXi
|
libXi
|
||||||
libXrandr
|
libXrandr
|
||||||
|
|
||||||
|
gtk4
|
||||||
];
|
];
|
||||||
in mkShell rec {
|
in mkShell rec {
|
||||||
name = "ghostty";
|
name = "ghostty";
|
||||||
@ -102,6 +105,9 @@ in mkShell rec {
|
|||||||
libXi
|
libXi
|
||||||
libXinerama
|
libXinerama
|
||||||
libXrandr
|
libXrandr
|
||||||
|
|
||||||
|
# Only needed for GTK builds
|
||||||
|
gtk4
|
||||||
];
|
];
|
||||||
|
|
||||||
# This should be set onto the rpath of the ghostty binary if you want
|
# This should be set onto the rpath of the ghostty binary if you want
|
||||||
|
@ -8,21 +8,49 @@
|
|||||||
//! The goal is to have different implementations share as much of the core
|
//! 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
|
//! logic as possible, and to only reach out to platform-specific implementation
|
||||||
//! code when absolutely necessary.
|
//! code when absolutely necessary.
|
||||||
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const build_config = @import("build_config.zig");
|
const build_config = @import("build_config.zig");
|
||||||
|
|
||||||
pub usingnamespace @import("apprt/structs.zig");
|
pub usingnamespace @import("apprt/structs.zig");
|
||||||
pub const glfw = @import("apprt/glfw.zig");
|
pub const glfw = @import("apprt/glfw.zig");
|
||||||
|
pub const gtk = @import("apprt/gtk.zig");
|
||||||
pub const browser = @import("apprt/browser.zig");
|
pub const browser = @import("apprt/browser.zig");
|
||||||
pub const embedded = @import("apprt/embedded.zig");
|
pub const embedded = @import("apprt/embedded.zig");
|
||||||
pub const Window = @import("apprt/Window.zig");
|
pub const Window = @import("apprt/Window.zig");
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
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,
|
||||||
|
|
||||||
|
pub fn default(target: std.zig.CrossTarget) Runtime {
|
||||||
|
_ = target;
|
||||||
|
return .glfw;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// The implementation to use for the app runtime. This is comptime chosen
|
/// The implementation to use for the app runtime. This is comptime chosen
|
||||||
/// so that every build has exactly one application runtime implementation.
|
/// so that every build has exactly one application runtime implementation.
|
||||||
/// Note: it is very rare to use Runtime directly; most usage will use
|
/// Note: it is very rare to use Runtime directly; most usage will use
|
||||||
/// Window or something.
|
/// Window or something.
|
||||||
pub const runtime = switch (build_config.artifact) {
|
pub const runtime = switch (build_config.artifact) {
|
||||||
.exe => glfw,
|
.exe => switch (build_config.app_runtime) {
|
||||||
|
.none => @compileError("exe with no runtime not allowed"),
|
||||||
|
.glfw => glfw,
|
||||||
|
.gtk => gtk,
|
||||||
|
},
|
||||||
.lib => embedded,
|
.lib => embedded,
|
||||||
.wasm_module => browser,
|
.wasm_module => browser,
|
||||||
};
|
};
|
||||||
|
45
src/apprt/gtk.zig
Normal file
45
src/apprt/gtk.zig
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
//! Application runtime that uses GTK4.
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
pub const c = @cImport({
|
||||||
|
@cInclude("gtk/gtk.h");
|
||||||
|
});
|
||||||
|
|
||||||
|
const log = std.log.scoped(.gtk);
|
||||||
|
|
||||||
|
pub const App = struct {
|
||||||
|
pub const Options = struct {
|
||||||
|
/// GTK app ID
|
||||||
|
id: [:0]const u8 = "com.mitchellh.ghostty",
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(opts: Options) !App {
|
||||||
|
const app = c.gtk_application_new(opts.id.ptr, c.G_APPLICATION_DEFAULT_FLAGS);
|
||||||
|
errdefer c.g_object_unref(app);
|
||||||
|
return .{};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn terminate(self: App) void {
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wakeup(self: App) !void {
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wait(self: App) !void {
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Window = struct {
|
||||||
|
pub const Options = struct {};
|
||||||
|
|
||||||
|
pub fn deinit(self: *Window) void {
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
};
|
@ -4,15 +4,19 @@
|
|||||||
//! to shim logic and values into them later.
|
//! to shim logic and values into them later.
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
const options = @import("build_options");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
/// The artifact we're producing. This can be used to determine if we're
|
/// The artifact we're producing. This can be used to determine if we're
|
||||||
/// building a standalone exe, an embedded lib, etc.
|
/// building a standalone exe, an embedded lib, etc.
|
||||||
pub const artifact = Artifact.detect();
|
pub const artifact = Artifact.detect();
|
||||||
|
|
||||||
|
/// The runtime to back exe artifacts with.
|
||||||
|
pub const app_runtime = options.app_runtime;
|
||||||
|
|
||||||
/// Whether our devmode UI is enabled or not. This requires imgui to be
|
/// Whether our devmode UI is enabled or not. This requires imgui to be
|
||||||
/// compiled.
|
/// compiled.
|
||||||
pub const devmode_enabled = artifact == .exe;
|
pub const devmode_enabled = artifact == .exe and app_runtime == .glfw;
|
||||||
|
|
||||||
pub const Artifact = enum {
|
pub const Artifact = enum {
|
||||||
/// Standalone executable
|
/// Standalone executable
|
||||||
|
12
src/main.zig
12
src/main.zig
@ -1,5 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
const build_config = @import("build_config.zig");
|
||||||
const options = @import("build_options");
|
const options = @import("build_options");
|
||||||
const glfw = @import("glfw");
|
const glfw = @import("glfw");
|
||||||
const macos = @import("macos");
|
const macos = @import("macos");
|
||||||
@ -88,12 +89,19 @@ pub fn main() !void {
|
|||||||
try config.finalize();
|
try config.finalize();
|
||||||
std.log.debug("config={}", .{config});
|
std.log.debug("config={}", .{config});
|
||||||
|
|
||||||
// We want to log all our errors
|
switch (build_config.app_runtime) {
|
||||||
glfw.setErrorCallback(glfwErrorCallback);
|
.none => {},
|
||||||
|
.glfw => {
|
||||||
|
// We want to log all our errors
|
||||||
|
glfw.setErrorCallback(glfwErrorCallback);
|
||||||
|
},
|
||||||
|
.gtk => {},
|
||||||
|
}
|
||||||
|
|
||||||
// Run our app with a single initial window to start.
|
// Run our app with a single initial window to start.
|
||||||
var app = try App.create(alloc, .{}, &config);
|
var app = try App.create(alloc, .{}, &config);
|
||||||
defer app.destroy();
|
defer app.destroy();
|
||||||
|
if (build_config.app_runtime == .gtk) return;
|
||||||
_ = try app.newWindow(.{});
|
_ = try app.newWindow(.{});
|
||||||
try app.run();
|
try app.run();
|
||||||
}
|
}
|
||||||
|
@ -420,6 +420,7 @@ pub fn deinitDevMode(self: *const OpenGL) void {
|
|||||||
/// Callback called by renderer.Thread when it begins.
|
/// Callback called by renderer.Thread when it begins.
|
||||||
pub fn threadEnter(self: *const OpenGL, win: apprt.runtime.Window) !void {
|
pub fn threadEnter(self: *const OpenGL, win: apprt.runtime.Window) !void {
|
||||||
_ = self;
|
_ = self;
|
||||||
|
if (apprt.runtime == apprt.gtk) @panic("TODO");
|
||||||
|
|
||||||
// We need to make the OpenGL context current. OpenGL requires
|
// We need to make the OpenGL context current. OpenGL requires
|
||||||
// that a single thread own the a single OpenGL context (if any). This
|
// that a single thread own the a single OpenGL context (if any). This
|
||||||
@ -1066,7 +1067,8 @@ pub fn setScreenSize(self: *OpenGL, dim: renderer.ScreenSize) !void {
|
|||||||
// Apply our padding
|
// Apply our padding
|
||||||
const padding = self.padding.explicit.add(if (self.padding.balance)
|
const padding = self.padding.explicit.add(if (self.padding.balance)
|
||||||
renderer.Padding.balanced(dim, grid_size, self.cell_size)
|
renderer.Padding.balanced(dim, grid_size, self.cell_size)
|
||||||
else .{});
|
else
|
||||||
|
.{});
|
||||||
const padded_dim = dim.subPadding(padding);
|
const padded_dim = dim.subPadding(padding);
|
||||||
|
|
||||||
log.debug("screen size padded={} screen={} grid={} cell={} padding={}", .{
|
log.debug("screen size padded={} screen={} grid={} cell={} padding={}", .{
|
||||||
|
Reference in New Issue
Block a user