move config loading into apprt to prep for reloading

This commit is contained in:
Mitchell Hashimoto
2023-03-13 21:44:45 -07:00
parent 8cb9ee5d59
commit 3e1f975551
6 changed files with 76 additions and 22 deletions

View File

@ -30,11 +30,6 @@ alloc: Allocator,
/// The list of surfaces that are currently active.
surfaces: SurfaceList,
// The configuration for the app. This may change (app runtimes are notified
// via the callback), but the change will only ever happen during tick()
// so app runtimes can ensure there are no data races in reading this.
config: *const Config,
/// The mailbox that can be used to send this thread messages. Note
/// this is a blocking queue so if it is full you will get errors (or block).
mailbox: Mailbox.Queue,
@ -47,17 +42,15 @@ quit: bool,
/// "startup" logic.
pub fn create(
alloc: Allocator,
config: *const Config,
) !*App {
// If we have DevMode on, store the config so we can show it
if (DevMode.enabled) DevMode.instance.config = config;
//if (DevMode.enabled) DevMode.instance.config = config;
var app = try alloc.create(App);
errdefer alloc.destroy(app);
app.* = .{
.alloc = alloc,
.surfaces = .{},
.config = config,
.mailbox = .{},
.quit = false,
};
@ -99,6 +92,21 @@ pub fn tick(self: *App, rt_app: *apprt.App) !bool {
return self.quit or self.surfaces.items.len == 0;
}
/// Update the configuration associated with the app. This can only be
/// called from the main thread.
///
/// The caller owns the config memory. The prior config must not be freed
/// until this function returns successfully.
pub fn updateConfig(self: *App, config: *const Config) !void {
// Update our config
self.config = config;
// Go through and update all of the surface configurations.
for (self.surfaces.items) |surface| {
try surface.handleMessage(.{ .change_config = config });
}
}
/// Add an initialized surface. This is really only for the runtime
/// implementations to call and should NOT be called by general app users.
/// The surface must be from the pool.
@ -125,6 +133,7 @@ fn drainMailbox(self: *App, rt_app: *apprt.App) !void {
while (self.mailbox.pop()) |message| {
log.debug("mailbox message={s}", .{@tagName(message)});
switch (message) {
.reload_config => try self.reloadConfig(rt_app),
.new_window => |msg| try self.newWindow(rt_app, msg),
.close => |surface| try self.closeSurface(rt_app, surface),
.quit => try self.setQuit(),
@ -134,6 +143,12 @@ fn drainMailbox(self: *App, rt_app: *apprt.App) !void {
}
}
fn reloadConfig(self: *App, rt_app: *apprt.App) !void {
_ = rt_app;
_ = self;
//try rt_app.reloadConfig();
}
fn closeSurface(self: *App, rt_app: *apprt.App, surface: *Surface) !void {
if (!self.hasSurface(surface)) return;
rt_app.closeSurface(surface.rt_surface);
@ -195,6 +210,10 @@ fn hasSurface(self: *App, surface: *Surface) bool {
/// The message types that can be sent to the app thread.
pub const Message = union(enum) {
/// Reload the configuration for the entire app and propagate it to
/// all the active surfaces.
reload_config: void,
/// Create a new terminal window.
new_window: NewWindow,

View File

@ -528,6 +528,8 @@ pub fn close(self: *Surface) void {
/// surface.
pub fn handleMessage(self: *Surface, msg: Message) !void {
switch (msg) {
.change_config => |config| try self.changeConfig(config),
.set_title => |*v| {
// The ptrCast just gets sliceTo to return the proper type.
// We know that our title should end in 0.
@ -553,6 +555,24 @@ pub fn handleMessage(self: *Surface, msg: Message) !void {
}
}
/// Update our configuration at runtime.
fn changeConfig(self: *Surface, config: *const configpkg.Config) !void {
// Update our new derived config immediately
const derived = DerivedConfig.init(self.alloc, config) catch |err| {
// If the derivation fails then we just log and return. We don't
// hard fail in this case because we don't want to error the surface
// when config fails we just want to keep using the old config.
log.err("error updating configuration err={}", .{err});
return;
};
self.config.deinit();
self.config = derived;
// Update our derived configurations for the renderer and termio,
// then send them a message to update.
// TODO
}
/// Returns the x/y coordinate of where the IME (Input Method Editor)
/// keyboard should be rendered.
pub fn imePoint(self: *const Surface) apprt.IMEPos {

View File

@ -19,6 +19,7 @@ const Renderer = renderer.Renderer;
const apprt = @import("../apprt.zig");
const CoreApp = @import("../App.zig");
const CoreSurface = @import("../Surface.zig");
const Config = @import("../config.zig").Config;
// Get native API access on certain platforms so we can do more customization.
const glfwNative = glfw.Native(.{
@ -29,6 +30,7 @@ const log = std.log.scoped(.glfw);
pub const App = struct {
app: *CoreApp,
config: Config,
/// Mac-specific state.
darwin: if (Darwin.enabled) Darwin else void,
@ -53,14 +55,19 @@ pub const App = struct {
var darwin = if (Darwin.enabled) try Darwin.init() else {};
errdefer if (Darwin.enabled) darwin.deinit();
// Load our configuration
var config = try Config.load(core_app.alloc);
errdefer config.deinit();
return .{
.app = core_app,
.config = config,
.darwin = darwin,
};
}
pub fn terminate(self: App) void {
_ = self;
pub fn terminate(self: *App) void {
self.config.deinit();
glfw.terminate();
}
@ -139,7 +146,7 @@ pub const App = struct {
errdefer surface.deinit();
// If we have a parent, inherit some properties
if (self.app.config.@"window-inherit-font-size") {
if (self.config.@"window-inherit-font-size") {
if (parent_) |parent| {
surface.core_surface.setFontSize(parent.font_size);
}
@ -313,7 +320,7 @@ pub const Surface = struct {
// Initialize our surface now that we have the stable pointer.
try self.core_surface.init(
app.app.alloc,
app.app.config,
&app.config,
.{ .rt_app = app, .mailbox = &app.app.mailbox },
self,
);

View File

@ -9,6 +9,7 @@ const apprt = @import("../apprt.zig");
const input = @import("../input.zig");
const CoreApp = @import("../App.zig");
const CoreSurface = @import("../Surface.zig");
const Config = @import("../config.zig").Config;
pub const c = @cImport({
@cInclude("gtk/gtk.h");
@ -37,6 +38,7 @@ pub const App = struct {
};
core_app: *CoreApp,
config: Config,
app: *c.GtkApplication,
ctx: *c.GMainContext,
@ -53,6 +55,10 @@ pub const App = struct {
// rid of this dep.
if (!glfw.init(.{})) return error.GlfwInitFailed;
// Load our configuration
var config = try Config.load(core_app.alloc);
errdefer config.deinit();
// Create our GTK Application which encapsulates our process.
const app = @ptrCast(?*c.GtkApplication, c.gtk_application_new(
null,
@ -108,6 +114,7 @@ pub const App = struct {
return .{
.core_app = core_app,
.app = app,
.config = config,
.ctx = ctx,
.cursor_default = cursor_default,
.cursor_ibeam = cursor_ibeam,
@ -116,7 +123,7 @@ pub const App = struct {
// Terminate the application. The application will not be restarted after
// this so all global state can be cleaned up.
pub fn terminate(self: App) void {
pub fn terminate(self: *App) void {
c.g_settings_sync();
while (c.g_main_context_iteration(self.ctx, 0) != 0) {}
c.g_main_context_release(self.ctx);
@ -125,6 +132,8 @@ pub const App = struct {
c.g_object_unref(self.cursor_ibeam);
c.g_object_unref(self.cursor_default);
self.config.deinit();
glfw.terminate();
}
@ -575,7 +584,7 @@ pub const Surface = struct {
// Initialize our surface now that we have the stable pointer.
try self.core_surface.init(
self.app.core_app.alloc,
self.app.core_app.config,
&self.app.config,
.{ .rt_app = self.app, .mailbox = &self.app.core_app.mailbox },
self,
);

View File

@ -2,6 +2,7 @@ const App = @import("../App.zig");
const Surface = @import("../Surface.zig");
const renderer = @import("../renderer.zig");
const termio = @import("../termio.zig");
const Config = @import("../config.zig").Config;
/// The message types that can be sent to a single surface.
pub const Message = union(enum) {
@ -24,6 +25,11 @@ pub const Message = union(enum) {
/// Write the clipboard contents.
clipboard_write: WriteReq,
/// Change the configuration to the given configuration. The pointer is
/// not valid after receiving this message so any config must be used
/// and derived immediately.
change_config: *const Config,
/// Close the surface. This will only close the current surface that
/// receives this, not the full application.
close: void,

View File

@ -14,8 +14,6 @@ const xdg = @import("xdg.zig");
const apprt = @import("apprt.zig");
const App = @import("App.zig");
const cli_args = @import("cli_args.zig");
const Config = @import("config.zig").Config;
const Ghostty = @import("main_c.zig").Ghostty;
/// Global process state. This is initialized in main() for exe artifacts
@ -29,13 +27,8 @@ pub fn main() !void {
defer state.deinit();
const alloc = state.alloc;
// Try reading our config
var config = try Config.load(alloc);
defer config.deinit();
//std.log.debug("config={}", .{config});
// Create our app state
var app = try App.create(alloc, &config);
var app = try App.create(alloc);
defer app.destroy();
// Create our runtime app