reload configuration on SIGUSR2
This is done at the apprt-level for a couple reasons.
(1) For libghostty, we don't have a way to know what the embedding
application is doing, so its risky to create signal handlers that
might overwrite the application's signal handlers.
(2) It's extremely messy to deal with signals and multi-threading.
Apprts have framework access that handles this for us.
For GTK, we use g_unix_signal_add.
For macOS, we use `DispatchSource.makeSignalSource`. This is an awkward
API but made for this purpose.
pull/7759/head
parent
5c4a30d85f
commit
2fa4fc8902
|
|
@ -112,6 +112,9 @@ class AppDelegate: NSObject,
|
||||||
/// The observer for the app appearance.
|
/// The observer for the app appearance.
|
||||||
private var appearanceObserver: NSKeyValueObservation? = nil
|
private var appearanceObserver: NSKeyValueObservation? = nil
|
||||||
|
|
||||||
|
/// Signals
|
||||||
|
private var signals: [DispatchSourceSignal] = []
|
||||||
|
|
||||||
/// The custom app icon image that is currently in use.
|
/// The custom app icon image that is currently in use.
|
||||||
@Published private(set) var appIcon: NSImage? = nil {
|
@Published private(set) var appIcon: NSImage? = nil {
|
||||||
didSet {
|
didSet {
|
||||||
|
|
@ -249,6 +252,9 @@ class AppDelegate: NSObject,
|
||||||
|
|
||||||
// Setup our menu
|
// Setup our menu
|
||||||
setupMenuImages()
|
setupMenuImages()
|
||||||
|
|
||||||
|
// Setup signal handlers
|
||||||
|
setupSignals()
|
||||||
}
|
}
|
||||||
|
|
||||||
func applicationDidBecomeActive(_ notification: Notification) {
|
func applicationDidBecomeActive(_ notification: Notification) {
|
||||||
|
|
@ -406,6 +412,34 @@ class AppDelegate: NSObject,
|
||||||
return dockMenu
|
return dockMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Setup signal handlers
|
||||||
|
private func setupSignals() {
|
||||||
|
// Register a signal handler for config reloading. It appears that all
|
||||||
|
// of this is required. I've commented each line because its a bit unclear.
|
||||||
|
// Warning: signal handlers don't work when run via Xcode. They have to be
|
||||||
|
// run on a real app bundle.
|
||||||
|
|
||||||
|
// We need to ignore signals we register with makeSignalSource or they
|
||||||
|
// don't seem to handle.
|
||||||
|
signal(SIGUSR2, SIG_IGN)
|
||||||
|
|
||||||
|
// Make the signal source and register our event handle. We keep a weak
|
||||||
|
// ref to ourself so we don't create a retain cycle.
|
||||||
|
let sigusr2 = DispatchSource.makeSignalSource(signal: SIGUSR2, queue: .main)
|
||||||
|
sigusr2.setEventHandler { [weak self] in
|
||||||
|
guard let self else { return }
|
||||||
|
Ghostty.logger.info("reloading configuration in response to SIGUSR2")
|
||||||
|
self.ghostty.reloadConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
// The signal source starts unactivated, so we have to resume it once
|
||||||
|
// we setup the event handler.
|
||||||
|
sigusr2.resume()
|
||||||
|
|
||||||
|
// We need to keep a strong reference to it so it isn't disabled.
|
||||||
|
signals.append(sigusr2)
|
||||||
|
}
|
||||||
|
|
||||||
/// Setup all the images for our menu items.
|
/// Setup all the images for our menu items.
|
||||||
private func setupMenuImages() {
|
private func setupMenuImages() {
|
||||||
// Note: This COULD Be done all in the xib file, but I find it easier to
|
// Note: This COULD Be done all in the xib file, but I find it easier to
|
||||||
|
|
|
||||||
|
|
@ -373,6 +373,13 @@ pub fn init(self: *App, core_app: *CoreApp, opts: Options) !void {
|
||||||
.{},
|
.{},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Setup a listener for SIGUSR2 to reload the configuration.
|
||||||
|
_ = glib.unixSignalAdd(
|
||||||
|
std.posix.SIG.USR2,
|
||||||
|
sigusr2,
|
||||||
|
self,
|
||||||
|
);
|
||||||
|
|
||||||
// We don't use g_application_run, we want to manually control the
|
// 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:
|
// loop so we have to do the same things the run function does:
|
||||||
// https://github.com/GNOME/glib/blob/a8e8b742e7926e33eb635a8edceac74cf239d6ed/gio/gapplication.c#L2533
|
// https://github.com/GNOME/glib/blob/a8e8b742e7926e33eb635a8edceac74cf239d6ed/gio/gapplication.c#L2533
|
||||||
|
|
@ -1508,6 +1515,22 @@ pub fn quitNow(self: *App) void {
|
||||||
self.running = false;
|
self.running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SIGUSR2 signal handler via g_unix_signal_add
|
||||||
|
fn sigusr2(ud: ?*anyopaque) callconv(.c) c_int {
|
||||||
|
const self: *App = @ptrCast(@alignCast(ud orelse
|
||||||
|
return @intFromBool(glib.SOURCE_CONTINUE)));
|
||||||
|
|
||||||
|
log.info("received SIGUSR2, reloading configuration", .{});
|
||||||
|
self.reloadConfig(.app, .{ .soft = false }) catch |err| {
|
||||||
|
log.err(
|
||||||
|
"error reloading configuration for SIGUSR2: {}",
|
||||||
|
.{err},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return @intFromBool(glib.SOURCE_CONTINUE);
|
||||||
|
}
|
||||||
|
|
||||||
/// This is called by the `activate` signal. This is sent on program startup and
|
/// This is called by the `activate` signal. This is sent on program startup and
|
||||||
/// also when a secondary instance launches and requests a new window.
|
/// also when a secondary instance launches and requests a new window.
|
||||||
fn gtkActivate(_: *adw.Application, core_app: *CoreApp) callconv(.c) void {
|
fn gtkActivate(_: *adw.Application, core_app: *CoreApp) callconv(.c) void {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue