mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
apprt/gtk-ng: reload config
This commit is contained in:
@ -508,6 +508,8 @@ pub const Application = extern struct {
|
||||
|
||||
.progress_report => return Action.progressReport(target, value),
|
||||
|
||||
.reload_config => try Action.reloadConfig(self, target, value),
|
||||
|
||||
.render => Action.render(target),
|
||||
|
||||
.ring_bell => Action.ringBell(target),
|
||||
@ -530,7 +532,6 @@ pub const Application = extern struct {
|
||||
.equalize_splits,
|
||||
.goto_split,
|
||||
.open_config,
|
||||
.reload_config,
|
||||
.inspector,
|
||||
.desktop_notification,
|
||||
.present_terminal,
|
||||
@ -573,29 +574,6 @@ pub const Application = extern struct {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Reload the configuration for the application and propagate it
|
||||
/// across the entire application and all terminals.
|
||||
pub fn reloadConfig(self: *Self) !void {
|
||||
const alloc = self.allocator();
|
||||
|
||||
// Read our new config. We can always deinit this because
|
||||
// we'll clone and store it if libghostty accepts it and
|
||||
// emits a `config_change` action.
|
||||
var config = try CoreConfig.load(alloc);
|
||||
defer config.deinit();
|
||||
|
||||
// Notify the app that we've updated.
|
||||
const priv = self.private();
|
||||
try priv.core_app.updateConfig(priv.rt_app, &config);
|
||||
}
|
||||
|
||||
/// Returns the configuration for this application.
|
||||
///
|
||||
/// The reference count is increased.
|
||||
pub fn getConfig(self: *Self) *Config {
|
||||
return self.private().config.ref();
|
||||
}
|
||||
|
||||
/// Returns the core app associated with this application. This is
|
||||
/// not a reference-counted type so you should not store this.
|
||||
pub fn core(self: *Self) *CoreApp {
|
||||
@ -662,6 +640,31 @@ pub const Application = extern struct {
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Properties
|
||||
|
||||
/// Returns the configuration for this application.
|
||||
///
|
||||
/// The reference count is increased.
|
||||
pub fn getConfig(self: *Self) *Config {
|
||||
return self.private().config.ref();
|
||||
}
|
||||
|
||||
/// Set the configuration for this application. The reference count
|
||||
/// is increased on the new configuration and the old one is
|
||||
/// unreferenced.
|
||||
///
|
||||
/// If the config has errors this may show the config errors dialog.
|
||||
fn setConfig(self: *Self, config: *Config) void {
|
||||
const priv = self.private();
|
||||
priv.config.unref();
|
||||
priv.config = config.ref();
|
||||
self.as(gobject.Object).notifyByPspec(properties.config.impl.param_spec);
|
||||
|
||||
// Show our errors if we have any
|
||||
self.showConfigErrorsDialog();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Libghostty Callbacks
|
||||
|
||||
@ -794,9 +797,10 @@ pub const Application = extern struct {
|
||||
// For action names:
|
||||
// https://docs.gtk.org/gio/type_func.Action.name_is_valid.html
|
||||
const actions = .{
|
||||
.{ "quit", actionQuit, null },
|
||||
.{ "new-window", actionNewWindow, null },
|
||||
.{ "new-window-command", actionNewWindow, as_variant_type },
|
||||
.{ "quit", actionQuit, null },
|
||||
.{ "reload-config", actionReloadConfig, null },
|
||||
};
|
||||
|
||||
const action_map = self.as(gio.ActionMap);
|
||||
@ -961,7 +965,12 @@ pub const Application = extern struct {
|
||||
const priv = self.private();
|
||||
priv.config_errors_dialog.set(null);
|
||||
|
||||
self.reloadConfig() catch |err| {
|
||||
// Reload our config as if the app reloaded.
|
||||
Action.reloadConfig(
|
||||
self,
|
||||
.app,
|
||||
.{},
|
||||
) catch |err| {
|
||||
// If we fail to reload the configuration, then we want the
|
||||
// user to know it. For now we log but we should show another
|
||||
// GUI.
|
||||
@ -1016,6 +1025,17 @@ pub const Application = extern struct {
|
||||
dialog.present(null);
|
||||
}
|
||||
|
||||
fn actionReloadConfig(
|
||||
_: *gio.SimpleAction,
|
||||
_: ?*glib.Variant,
|
||||
self: *Self,
|
||||
) callconv(.c) void {
|
||||
const priv = self.private();
|
||||
priv.core_app.performAction(self.rt(), .reload_config) catch |err| {
|
||||
log.warn("error reloading config err={}", .{err});
|
||||
};
|
||||
}
|
||||
|
||||
fn actionQuit(
|
||||
_: *gio.SimpleAction,
|
||||
_: ?*glib.Variant,
|
||||
@ -1138,21 +1158,11 @@ const Action = struct {
|
||||
// Wrap our config in a GObject. This will clone it.
|
||||
const alloc = self.allocator();
|
||||
const config_obj: *Config = try .new(alloc, new_config);
|
||||
errdefer config_obj.unref();
|
||||
defer config_obj.unref();
|
||||
|
||||
switch (target) {
|
||||
// TODO: when we implement surfaces in gtk-ng
|
||||
.surface => @panic("TODO"),
|
||||
|
||||
.app => {
|
||||
// Set it on our private
|
||||
const priv = self.private();
|
||||
priv.config.unref();
|
||||
priv.config = config_obj;
|
||||
|
||||
// Show our errors if we have any
|
||||
self.showConfigErrorsDialog();
|
||||
},
|
||||
.surface => |core| core.rt_surface.surface.setConfig(config_obj),
|
||||
.app => self.setConfig(config_obj),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1219,6 +1229,19 @@ const Action = struct {
|
||||
parent: ?*CoreSurface,
|
||||
) !void {
|
||||
const win = Window.new(self, parent);
|
||||
|
||||
// Setup a binding so that whenever our config changes so does the
|
||||
// window. There's never a time when the window config should be out
|
||||
// of sync with the application config.
|
||||
_ = gobject.Object.bindProperty(
|
||||
self.as(gobject.Object),
|
||||
"config",
|
||||
win.as(gobject.Object),
|
||||
"config",
|
||||
.{},
|
||||
);
|
||||
|
||||
// Show the window
|
||||
gtk.Window.present(win.as(gtk.Window));
|
||||
}
|
||||
|
||||
@ -1263,6 +1286,47 @@ const Action = struct {
|
||||
};
|
||||
}
|
||||
|
||||
/// Reload the configuration for the application and propagate it
|
||||
/// across the entire application and all terminals.
|
||||
pub fn reloadConfig(
|
||||
self: *Application,
|
||||
target: apprt.Target,
|
||||
opts: apprt.action.ReloadConfig,
|
||||
) !void {
|
||||
// Tell systemd that reloading has started.
|
||||
systemd.notify.reloading();
|
||||
|
||||
// When we exit this function tell systemd that reloading has finished.
|
||||
defer systemd.notify.ready();
|
||||
|
||||
// Get our config object.
|
||||
const config: *Config = config: {
|
||||
// Soft-reloading applies conditional logic to the existing loaded
|
||||
// config so we return that as-is (but take a reference).
|
||||
if (opts.soft) {
|
||||
break :config self.private().config.ref();
|
||||
}
|
||||
|
||||
// Hard reload, load a new config completely.
|
||||
const alloc = self.allocator();
|
||||
var config = try CoreConfig.load(alloc);
|
||||
defer config.deinit();
|
||||
break :config try .new(alloc, &config);
|
||||
};
|
||||
defer config.unref();
|
||||
|
||||
// Update the proper target. This will trigger a `confige_change`
|
||||
// apprt action which will propagate the config properly to our
|
||||
// property system.
|
||||
switch (target) {
|
||||
.app => try self.core().updateConfig(
|
||||
self.rt(),
|
||||
config.get(),
|
||||
),
|
||||
.surface => |core| try core.updateConfig(config.get()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(target: apprt.Target) void {
|
||||
switch (target) {
|
||||
.app => {},
|
||||
|
@ -1193,6 +1193,14 @@ pub const Surface = extern struct {
|
||||
return self.private().pwd;
|
||||
}
|
||||
|
||||
/// Change the configuration for this surface.
|
||||
pub fn setConfig(self: *Self, config: *Config) void {
|
||||
const priv = self.private();
|
||||
if (priv.config) |c| c.unref();
|
||||
priv.config = config.ref();
|
||||
self.as(gobject.Object).notifyByPspec(properties.config.impl.param_spec);
|
||||
}
|
||||
|
||||
fn propConfig(
|
||||
self: *Self,
|
||||
_: *gobject.ParamSpec,
|
||||
|
Reference in New Issue
Block a user