mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-09-05 19:08:17 +00:00
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.
This commit is contained in:
@@ -112,6 +112,9 @@ class AppDelegate: NSObject,
|
||||
/// The observer for the app appearance.
|
||||
private var appearanceObserver: NSKeyValueObservation? = nil
|
||||
|
||||
/// Signals
|
||||
private var signals: [DispatchSourceSignal] = []
|
||||
|
||||
/// The custom app icon image that is currently in use.
|
||||
@Published private(set) var appIcon: NSImage? = nil {
|
||||
didSet {
|
||||
@@ -249,6 +252,9 @@ class AppDelegate: NSObject,
|
||||
|
||||
// Setup our menu
|
||||
setupMenuImages()
|
||||
|
||||
// Setup signal handlers
|
||||
setupSignals()
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(_ notification: Notification) {
|
||||
@@ -406,6 +412,34 @@ class AppDelegate: NSObject,
|
||||
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.
|
||||
private func setupMenuImages() {
|
||||
// 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
|
||||
// loop so we have to do the same things the run function does:
|
||||
// https://github.com/GNOME/glib/blob/a8e8b742e7926e33eb635a8edceac74cf239d6ed/gio/gapplication.c#L2533
|
||||
@@ -1508,6 +1515,22 @@ pub fn quitNow(self: *App) void {
|
||||
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
|
||||
/// also when a secondary instance launches and requests a new window.
|
||||
fn gtkActivate(_: *adw.Application, core_app: *CoreApp) callconv(.c) void {
|
||||
|
Reference in New Issue
Block a user