init gtk app

This commit is contained in:
Mitchell Hashimoto
2023-02-21 08:20:13 -08:00
parent 48c9c65915
commit f268f3955e
5 changed files with 110 additions and 15 deletions

View File

@ -22,6 +22,7 @@
, expat , expat
, fontconfig , fontconfig
, freetype , freetype
, glib
, gtk4 , gtk4
, harfbuzz , harfbuzz
, libpng , libpng
@ -56,6 +57,7 @@ let
libXrandr libXrandr
gtk4 gtk4
glib
]; ];
in mkShell rec { in mkShell rec {
name = "ghostty"; name = "ghostty";
@ -108,6 +110,7 @@ in mkShell rec {
# Only needed for GTK builds # Only needed for GTK builds
gtk4 gtk4
glib
]; ];
# 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

View File

@ -125,10 +125,11 @@ pub fn destroy(self: *App) void {
self.windows.deinit(self.alloc); self.windows.deinit(self.alloc);
if (Darwin.enabled) self.darwin.deinit(); if (Darwin.enabled) self.darwin.deinit();
self.mailbox.destroy(self.alloc); self.mailbox.destroy(self.alloc);
self.alloc.destroy(self);
// Close our windowing runtime // Close our windowing runtime
self.runtime.terminate(); self.runtime.terminate();
self.alloc.destroy(self);
} }
/// Wake up the app event loop. This should be called after any messages /// Wake up the app event loop. This should be called after any messages
@ -164,7 +165,7 @@ pub fn tick(self: *App) !void {
i += 1; i += 1;
} }
// Drain our mailbox only if we're not quitting. // // Drain our mailbox only if we're not quitting.
if (!self.quit) try self.drainMailbox(); if (!self.quit) try self.drainMailbox();
} }

View File

@ -4,6 +4,9 @@ const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const assert = std.debug.assert; const assert = std.debug.assert;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const apprt = @import("../apprt.zig");
const CoreApp = @import("../App.zig");
const CoreWindow = @import("../Window.zig");
pub const c = @cImport({ pub const c = @cImport({
@cInclude("gtk/gtk.h"); @cInclude("gtk/gtk.h");
@ -17,29 +20,111 @@ pub const App = struct {
id: [:0]const u8 = "com.mitchellh.ghostty", id: [:0]const u8 = "com.mitchellh.ghostty",
}; };
app: *c.GtkApplication,
ctx: *c.GMainContext,
pub fn init(opts: Options) !App { pub fn init(opts: Options) !App {
const app = c.gtk_application_new(opts.id.ptr, c.G_APPLICATION_DEFAULT_FLAGS); const app = @ptrCast(?*c.GtkApplication, c.gtk_application_new(
opts.id.ptr,
c.G_APPLICATION_DEFAULT_FLAGS,
)) orelse return error.GtkInitFailed;
errdefer c.g_object_unref(app); errdefer c.g_object_unref(app);
return .{};
// We don't use g_application_run, we want to manually control the
// loop so we have to do the same things the run function does:
// https://github.com/GNOME/glib/blob/a8e8b742e7926e33eb635a8edceac74cf239d6ed/gio/gapplication.c#L2533
const ctx = c.g_main_context_default() orelse return error.GtkContextFailed;
if (c.g_main_context_acquire(ctx) == 0) return error.GtkContextAcquireFailed;
errdefer c.g_main_context_release(ctx);
const gapp = @ptrCast(*c.GApplication, app);
var err_: ?*c.GError = null;
if (c.g_application_register(
gapp,
null,
@ptrCast([*c][*c]c.GError, &err_),
) == 0) {
if (err_) |err| {
log.warn("error registering application: {s}", .{err.message});
c.g_error_free(err);
}
return error.GtkApplicationRegisterFailed;
}
c.g_application_activate(gapp);
return .{ .app = app, .ctx = ctx };
} }
pub fn terminate(self: App) void { pub fn terminate(self: App) void {
_ = self; c.g_settings_sync();
while (c.g_main_context_iteration(self.ctx, 0) != 0) {}
c.g_main_context_release(self.ctx);
c.g_object_unref(self.app);
} }
pub fn wakeup(self: App) !void { pub fn wakeup(self: App) !void {
_ = self; _ = self;
c.g_main_context_wakeup(null);
} }
pub fn wait(self: App) !void { pub fn wait(self: App) !void {
_ = self; _ = c.g_main_context_iteration(self.ctx, 1);
} }
}; };
pub const Window = struct { pub const Window = struct {
pub const Options = struct {}; pub const Options = struct {};
pub fn init(app: *const CoreApp, core_win: *CoreWindow, opts: Options) !Window {
_ = app;
_ = core_win;
_ = opts;
return .{};
}
pub fn deinit(self: *Window) void { pub fn deinit(self: *Window) void {
_ = self; _ = self;
} }
pub fn setShouldClose(self: *Window) void {
_ = self;
}
pub fn shouldClose(self: *const Window) bool {
_ = self;
return false;
}
pub fn getContentScale(self: *const Window) !apprt.ContentScale {
_ = self;
return .{ .x = 1, .y = 1 };
}
pub fn getSize(self: *const Window) !apprt.WindowSize {
_ = self;
return .{ .width = 800, .height = 600 };
}
pub fn setSizeLimits(self: *Window, min: apprt.WindowSize, max_: ?apprt.WindowSize) !void {
_ = self;
_ = min;
_ = max_;
}
pub fn setTitle(self: *Window, slice: [:0]const u8) !void {
_ = self;
_ = slice;
}
pub fn getClipboardString(self: *const Window) ![:0]const u8 {
_ = self;
return "";
}
pub fn setClipboardString(self: *const Window, val: [:0]const u8) !void {
_ = self;
_ = val;
}
}; };

View File

@ -101,9 +101,9 @@ pub fn main() !void {
// 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();
try app.run();
if (build_config.app_runtime == .gtk) return; if (build_config.app_runtime == .gtk) return;
_ = try app.newWindow(.{}); _ = try app.newWindow(.{});
try app.run();
} }
// Required by tracy/tracy.zig to enable/disable tracy support. // Required by tracy/tracy.zig to enable/disable tracy support.

View File

@ -444,6 +444,7 @@ pub fn threadEnter(self: *const OpenGL, win: apprt.runtime.Window) !void {
/// Callback called by renderer.Thread when it exits. /// Callback called by renderer.Thread when it exits.
pub fn threadExit(self: *const OpenGL) void { pub fn threadExit(self: *const OpenGL) void {
_ = self; _ = self;
if (apprt.runtime == apprt.gtk) @panic("TODO");
gl.glad.unload(); gl.glad.unload();
glfw.makeContextCurrent(null); glfw.makeContextCurrent(null);
@ -569,6 +570,7 @@ pub fn render(
// Build our devmode draw data // Build our devmode draw data
const devmode_data = devmode_data: { const devmode_data = devmode_data: {
if (DevMode.enabled) {
if (state.devmode) |dm| { if (state.devmode) |dm| {
if (dm.visible) { if (dm.visible) {
imgui.ImplOpenGL3.newFrame(); imgui.ImplOpenGL3.newFrame();
@ -577,6 +579,7 @@ pub fn render(
break :devmode_data try dm.render(); break :devmode_data try dm.render();
} }
} }
}
break :devmode_data null; break :devmode_data null;
}; };
@ -639,11 +642,14 @@ pub fn render(
try self.draw(); try self.draw();
// If we have devmode, then render that // If we have devmode, then render that
if (DevMode.enabled) {
if (critical.devmode_data) |data| { if (critical.devmode_data) |data| {
imgui.ImplOpenGL3.renderDrawData(data); imgui.ImplOpenGL3.renderDrawData(data);
} }
}
// Swap our window buffers // Swap our window buffers
if (apprt.runtime == apprt.gtk) @panic("TODO");
win.window.swapBuffers(); win.window.swapBuffers();
} }