mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
move config loading into apprt to prep for reloading
This commit is contained in:
35
src/App.zig
35
src/App.zig
@ -30,11 +30,6 @@ alloc: Allocator,
|
|||||||
/// The list of surfaces that are currently active.
|
/// The list of surfaces that are currently active.
|
||||||
surfaces: SurfaceList,
|
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
|
/// 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).
|
/// this is a blocking queue so if it is full you will get errors (or block).
|
||||||
mailbox: Mailbox.Queue,
|
mailbox: Mailbox.Queue,
|
||||||
@ -47,17 +42,15 @@ quit: bool,
|
|||||||
/// "startup" logic.
|
/// "startup" logic.
|
||||||
pub fn create(
|
pub fn create(
|
||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
config: *const Config,
|
|
||||||
) !*App {
|
) !*App {
|
||||||
// If we have DevMode on, store the config so we can show it
|
// 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);
|
var app = try alloc.create(App);
|
||||||
errdefer alloc.destroy(app);
|
errdefer alloc.destroy(app);
|
||||||
app.* = .{
|
app.* = .{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
.surfaces = .{},
|
.surfaces = .{},
|
||||||
.config = config,
|
|
||||||
.mailbox = .{},
|
.mailbox = .{},
|
||||||
.quit = false,
|
.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;
|
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
|
/// Add an initialized surface. This is really only for the runtime
|
||||||
/// implementations to call and should NOT be called by general app users.
|
/// implementations to call and should NOT be called by general app users.
|
||||||
/// The surface must be from the pool.
|
/// 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| {
|
while (self.mailbox.pop()) |message| {
|
||||||
log.debug("mailbox message={s}", .{@tagName(message)});
|
log.debug("mailbox message={s}", .{@tagName(message)});
|
||||||
switch (message) {
|
switch (message) {
|
||||||
|
.reload_config => try self.reloadConfig(rt_app),
|
||||||
.new_window => |msg| try self.newWindow(rt_app, msg),
|
.new_window => |msg| try self.newWindow(rt_app, msg),
|
||||||
.close => |surface| try self.closeSurface(rt_app, surface),
|
.close => |surface| try self.closeSurface(rt_app, surface),
|
||||||
.quit => try self.setQuit(),
|
.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 {
|
fn closeSurface(self: *App, rt_app: *apprt.App, surface: *Surface) !void {
|
||||||
if (!self.hasSurface(surface)) return;
|
if (!self.hasSurface(surface)) return;
|
||||||
rt_app.closeSurface(surface.rt_surface);
|
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.
|
/// The message types that can be sent to the app thread.
|
||||||
pub const Message = union(enum) {
|
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.
|
/// Create a new terminal window.
|
||||||
new_window: NewWindow,
|
new_window: NewWindow,
|
||||||
|
|
||||||
|
@ -528,6 +528,8 @@ pub fn close(self: *Surface) void {
|
|||||||
/// surface.
|
/// surface.
|
||||||
pub fn handleMessage(self: *Surface, msg: Message) !void {
|
pub fn handleMessage(self: *Surface, msg: Message) !void {
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
|
.change_config => |config| try self.changeConfig(config),
|
||||||
|
|
||||||
.set_title => |*v| {
|
.set_title => |*v| {
|
||||||
// The ptrCast just gets sliceTo to return the proper type.
|
// The ptrCast just gets sliceTo to return the proper type.
|
||||||
// We know that our title should end in 0.
|
// 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)
|
/// Returns the x/y coordinate of where the IME (Input Method Editor)
|
||||||
/// keyboard should be rendered.
|
/// keyboard should be rendered.
|
||||||
pub fn imePoint(self: *const Surface) apprt.IMEPos {
|
pub fn imePoint(self: *const Surface) apprt.IMEPos {
|
||||||
|
@ -19,6 +19,7 @@ const Renderer = renderer.Renderer;
|
|||||||
const apprt = @import("../apprt.zig");
|
const apprt = @import("../apprt.zig");
|
||||||
const CoreApp = @import("../App.zig");
|
const CoreApp = @import("../App.zig");
|
||||||
const CoreSurface = @import("../Surface.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.
|
// Get native API access on certain platforms so we can do more customization.
|
||||||
const glfwNative = glfw.Native(.{
|
const glfwNative = glfw.Native(.{
|
||||||
@ -29,6 +30,7 @@ const log = std.log.scoped(.glfw);
|
|||||||
|
|
||||||
pub const App = struct {
|
pub const App = struct {
|
||||||
app: *CoreApp,
|
app: *CoreApp,
|
||||||
|
config: Config,
|
||||||
|
|
||||||
/// Mac-specific state.
|
/// Mac-specific state.
|
||||||
darwin: if (Darwin.enabled) Darwin else void,
|
darwin: if (Darwin.enabled) Darwin else void,
|
||||||
@ -53,14 +55,19 @@ pub const App = struct {
|
|||||||
var darwin = if (Darwin.enabled) try Darwin.init() else {};
|
var darwin = if (Darwin.enabled) try Darwin.init() else {};
|
||||||
errdefer if (Darwin.enabled) darwin.deinit();
|
errdefer if (Darwin.enabled) darwin.deinit();
|
||||||
|
|
||||||
|
// Load our configuration
|
||||||
|
var config = try Config.load(core_app.alloc);
|
||||||
|
errdefer config.deinit();
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.app = core_app,
|
.app = core_app,
|
||||||
|
.config = config,
|
||||||
.darwin = darwin,
|
.darwin = darwin,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn terminate(self: App) void {
|
pub fn terminate(self: *App) void {
|
||||||
_ = self;
|
self.config.deinit();
|
||||||
glfw.terminate();
|
glfw.terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +146,7 @@ pub const App = struct {
|
|||||||
errdefer surface.deinit();
|
errdefer surface.deinit();
|
||||||
|
|
||||||
// If we have a parent, inherit some properties
|
// 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| {
|
if (parent_) |parent| {
|
||||||
surface.core_surface.setFontSize(parent.font_size);
|
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.
|
// Initialize our surface now that we have the stable pointer.
|
||||||
try self.core_surface.init(
|
try self.core_surface.init(
|
||||||
app.app.alloc,
|
app.app.alloc,
|
||||||
app.app.config,
|
&app.config,
|
||||||
.{ .rt_app = app, .mailbox = &app.app.mailbox },
|
.{ .rt_app = app, .mailbox = &app.app.mailbox },
|
||||||
self,
|
self,
|
||||||
);
|
);
|
||||||
|
@ -9,6 +9,7 @@ const apprt = @import("../apprt.zig");
|
|||||||
const input = @import("../input.zig");
|
const input = @import("../input.zig");
|
||||||
const CoreApp = @import("../App.zig");
|
const CoreApp = @import("../App.zig");
|
||||||
const CoreSurface = @import("../Surface.zig");
|
const CoreSurface = @import("../Surface.zig");
|
||||||
|
const Config = @import("../config.zig").Config;
|
||||||
|
|
||||||
pub const c = @cImport({
|
pub const c = @cImport({
|
||||||
@cInclude("gtk/gtk.h");
|
@cInclude("gtk/gtk.h");
|
||||||
@ -37,6 +38,7 @@ pub const App = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
core_app: *CoreApp,
|
core_app: *CoreApp,
|
||||||
|
config: Config,
|
||||||
|
|
||||||
app: *c.GtkApplication,
|
app: *c.GtkApplication,
|
||||||
ctx: *c.GMainContext,
|
ctx: *c.GMainContext,
|
||||||
@ -53,6 +55,10 @@ pub const App = struct {
|
|||||||
// rid of this dep.
|
// rid of this dep.
|
||||||
if (!glfw.init(.{})) return error.GlfwInitFailed;
|
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.
|
// Create our GTK Application which encapsulates our process.
|
||||||
const app = @ptrCast(?*c.GtkApplication, c.gtk_application_new(
|
const app = @ptrCast(?*c.GtkApplication, c.gtk_application_new(
|
||||||
null,
|
null,
|
||||||
@ -108,6 +114,7 @@ pub const App = struct {
|
|||||||
return .{
|
return .{
|
||||||
.core_app = core_app,
|
.core_app = core_app,
|
||||||
.app = app,
|
.app = app,
|
||||||
|
.config = config,
|
||||||
.ctx = ctx,
|
.ctx = ctx,
|
||||||
.cursor_default = cursor_default,
|
.cursor_default = cursor_default,
|
||||||
.cursor_ibeam = cursor_ibeam,
|
.cursor_ibeam = cursor_ibeam,
|
||||||
@ -116,7 +123,7 @@ pub const App = struct {
|
|||||||
|
|
||||||
// Terminate the application. The application will not be restarted after
|
// Terminate the application. The application will not be restarted after
|
||||||
// this so all global state can be cleaned up.
|
// 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();
|
c.g_settings_sync();
|
||||||
while (c.g_main_context_iteration(self.ctx, 0) != 0) {}
|
while (c.g_main_context_iteration(self.ctx, 0) != 0) {}
|
||||||
c.g_main_context_release(self.ctx);
|
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_ibeam);
|
||||||
c.g_object_unref(self.cursor_default);
|
c.g_object_unref(self.cursor_default);
|
||||||
|
|
||||||
|
self.config.deinit();
|
||||||
|
|
||||||
glfw.terminate();
|
glfw.terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,7 +584,7 @@ pub const Surface = struct {
|
|||||||
// Initialize our surface now that we have the stable pointer.
|
// Initialize our surface now that we have the stable pointer.
|
||||||
try self.core_surface.init(
|
try self.core_surface.init(
|
||||||
self.app.core_app.alloc,
|
self.app.core_app.alloc,
|
||||||
self.app.core_app.config,
|
&self.app.config,
|
||||||
.{ .rt_app = self.app, .mailbox = &self.app.core_app.mailbox },
|
.{ .rt_app = self.app, .mailbox = &self.app.core_app.mailbox },
|
||||||
self,
|
self,
|
||||||
);
|
);
|
||||||
|
@ -2,6 +2,7 @@ const App = @import("../App.zig");
|
|||||||
const Surface = @import("../Surface.zig");
|
const Surface = @import("../Surface.zig");
|
||||||
const renderer = @import("../renderer.zig");
|
const renderer = @import("../renderer.zig");
|
||||||
const termio = @import("../termio.zig");
|
const termio = @import("../termio.zig");
|
||||||
|
const Config = @import("../config.zig").Config;
|
||||||
|
|
||||||
/// The message types that can be sent to a single surface.
|
/// The message types that can be sent to a single surface.
|
||||||
pub const Message = union(enum) {
|
pub const Message = union(enum) {
|
||||||
@ -24,6 +25,11 @@ pub const Message = union(enum) {
|
|||||||
/// Write the clipboard contents.
|
/// Write the clipboard contents.
|
||||||
clipboard_write: WriteReq,
|
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
|
/// Close the surface. This will only close the current surface that
|
||||||
/// receives this, not the full application.
|
/// receives this, not the full application.
|
||||||
close: void,
|
close: void,
|
||||||
|
@ -14,8 +14,6 @@ const xdg = @import("xdg.zig");
|
|||||||
const apprt = @import("apprt.zig");
|
const apprt = @import("apprt.zig");
|
||||||
|
|
||||||
const App = @import("App.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;
|
const Ghostty = @import("main_c.zig").Ghostty;
|
||||||
|
|
||||||
/// Global process state. This is initialized in main() for exe artifacts
|
/// Global process state. This is initialized in main() for exe artifacts
|
||||||
@ -29,13 +27,8 @@ pub fn main() !void {
|
|||||||
defer state.deinit();
|
defer state.deinit();
|
||||||
const alloc = state.alloc;
|
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
|
// Create our app state
|
||||||
var app = try App.create(alloc, &config);
|
var app = try App.create(alloc);
|
||||||
defer app.destroy();
|
defer app.destroy();
|
||||||
|
|
||||||
// Create our runtime app
|
// Create our runtime app
|
||||||
|
Reference in New Issue
Block a user