apprt/gtk-ng: hook up quit timer

This commit is contained in:
Mitchell Hashimoto
2025-07-21 08:26:38 -07:00
parent 805c8601a9
commit 3e83364937

View File

@ -110,6 +110,15 @@ pub const Application = extern struct {
/// only be set by the main loop thread. /// only be set by the main loop thread.
running: bool = false, running: bool = false,
/// The timer used to quit the application after the last window is
/// closed. Even if there is no quit delay set, this is the state
/// used to determine to close the app.
quit_timer: union(enum) {
off,
active: c_uint,
expired,
} = .off,
/// If non-null, we're currently showing a config errors dialog. /// If non-null, we're currently showing a config errors dialog.
/// This is a WeakRef because the dialog can close on its own /// This is a WeakRef because the dialog can close on its own
/// outside of our own lifecycle and that's okay. /// outside of our own lifecycle and that's okay.
@ -309,6 +318,9 @@ pub const Application = extern struct {
// The final cleanup that is always required at the end of running. // The final cleanup that is always required at the end of running.
defer { defer {
// Ensure our timer source is removed
self.stopQuitTimer();
// Sync any remaining settings // Sync any remaining settings
gio.Settings.sync(); gio.Settings.sync();
@ -378,7 +390,7 @@ pub const Application = extern struct {
if (!config.@"quit-after-last-window-closed") break :q false; if (!config.@"quit-after-last-window-closed") break :q false;
// If the quit timer has expired, quit. // If the quit timer has expired, quit.
// if (self.quit_timer == .expired) break :q true; if (priv.quit_timer == .expired) break :q true;
// There's no quit timer running, or it hasn't expired, don't quit. // There's no quit timer running, or it hasn't expired, don't quit.
break :q false; break :q false;
@ -525,6 +537,51 @@ pub const Application = extern struct {
return &self.private().winproto; return &self.private().winproto;
} }
/// This will get called when there are no more open surfaces.
fn startQuitTimer(self: *Self) void {
const priv = self.private();
const config = priv.config.get();
// Cancel any previous timer.
self.stopQuitTimer();
// This is a no-op unless we are configured to quit after last window is closed.
if (!config.@"quit-after-last-window-closed") return;
// If a delay is configured, set a timeout function to quit after the delay.
if (config.@"quit-after-last-window-closed-delay") |v| {
priv.quit_timer = .{
.active = glib.timeoutAdd(
v.asMilliseconds(),
handleQuitTimerExpired,
self,
),
};
} else {
// If no delay is configured, treat it as expired.
priv.quit_timer = .expired;
}
}
/// This will get called when a new surface gets opened.
fn stopQuitTimer(self: *Self) void {
const priv = self.private();
switch (priv.quit_timer) {
.off => {},
.expired => priv.quit_timer = .off,
.active => |source| {
if (glib.Source.remove(source) == 0) {
log.warn(
"unable to remove quit timer source={d}",
.{source},
);
}
priv.quit_timer = .off;
},
}
}
//--------------------------------------------------------------- //---------------------------------------------------------------
// Libghostty Callbacks // Libghostty Callbacks
@ -744,6 +801,13 @@ pub const Application = extern struct {
//--------------------------------------------------------------- //---------------------------------------------------------------
// Signal Handlers // Signal Handlers
fn handleQuitTimerExpired(ud: ?*anyopaque) callconv(.c) c_int {
const self: *Self = @ptrCast(@alignCast(ud));
const priv = self.private();
priv.quit_timer = .expired;
return 0;
}
fn handleStyleManagerDark( fn handleStyleManagerDark(
style: *adw.StyleManager, style: *adw.StyleManager,
_: *gobject.ParamSpec, _: *gobject.ParamSpec,
@ -967,14 +1031,9 @@ const Action = struct {
self: *Application, self: *Application,
mode: apprt.action.QuitTimer, mode: apprt.action.QuitTimer,
) !void { ) !void {
// TODO: An actual quit timer implementation. For now, we immediately
// quit on no windows regardless of the config.
switch (mode) { switch (mode) {
.start => { .start => self.startQuitTimer(),
self.private().running = false; .stop => self.stopQuitTimer(),
},
.stop => {},
} }
} }