mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
apprt/gtk: use tagged union for quit timer
This commit is contained in:
@ -135,6 +135,9 @@ pub fn updateConfig(self: *App, config: *const Config) !void {
|
|||||||
pub fn addSurface(self: *App, rt_surface: *apprt.Surface) !void {
|
pub fn addSurface(self: *App, rt_surface: *apprt.Surface) !void {
|
||||||
try self.surfaces.append(self.alloc, rt_surface);
|
try self.surfaces.append(self.alloc, rt_surface);
|
||||||
|
|
||||||
|
// Since we have non-zero surfaces, we can cancel the quit timer.
|
||||||
|
// It is up to the apprt if there is a quit timer at all and if it
|
||||||
|
// should be canceled.
|
||||||
if (@hasDecl(apprt.App, "cancelQuitTimer")) rt_surface.app.cancelQuitTimer();
|
if (@hasDecl(apprt.App, "cancelQuitTimer")) rt_surface.app.cancelQuitTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +164,10 @@ pub fn deleteSurface(self: *App, rt_surface: *apprt.Surface) void {
|
|||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (@hasDecl(apprt.App, "startQuitTimer") and self.surfaces.items.len == 0) rt_surface.app.startQuitTimer();
|
// If we have no surfaces, we can start the quit timer. It is up to the
|
||||||
|
// apprt to determine if this is necessary.
|
||||||
|
if (@hasDecl(apprt.App, "startQuitTimer") and
|
||||||
|
self.surfaces.items.len == 0) rt_surface.app.startQuitTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The last focused surface. This is only valid while on the main thread
|
/// The last focused surface. This is only valid while on the main thread
|
||||||
|
@ -76,11 +76,12 @@ transient_cgroup_base: ?[]const u8 = null,
|
|||||||
/// CSS Provider for any styles based on ghostty configuration values
|
/// CSS Provider for any styles based on ghostty configuration values
|
||||||
css_provider: *c.GtkCssProvider,
|
css_provider: *c.GtkCssProvider,
|
||||||
|
|
||||||
/// GLib source for tracking quit timer.
|
/// The timer used to quit the application after the last window is closed.
|
||||||
quit_timer_source: ?c.guint = null,
|
quit_timer: union(enum) {
|
||||||
|
off: void,
|
||||||
/// If there is a quit timer, has it expired?
|
active: c.guint,
|
||||||
quit_timer_expired: bool = false,
|
expired: void,
|
||||||
|
} = .{ .off = {} },
|
||||||
|
|
||||||
pub fn init(core_app: *CoreApp, opts: Options) !App {
|
pub fn init(core_app: *CoreApp, opts: Options) !App {
|
||||||
_ = opts;
|
_ = opts;
|
||||||
@ -491,6 +492,7 @@ pub fn run(self: *App) !void {
|
|||||||
// Tick the terminal app and see if we should quit.
|
// Tick the terminal app and see if we should quit.
|
||||||
const should_quit = try self.core_app.tick(self);
|
const should_quit = try self.core_app.tick(self);
|
||||||
|
|
||||||
|
// Check if we must quit based on the current state.
|
||||||
const must_quit = q: {
|
const must_quit = q: {
|
||||||
// If we've been told by GTK that we should quit, do so regardless
|
// If we've been told by GTK that we should quit, do so regardless
|
||||||
// of any other setting.
|
// of any other setting.
|
||||||
@ -499,10 +501,8 @@ pub fn run(self: *App) !void {
|
|||||||
// If we are configured to always stay running, don't quit.
|
// If we are configured to always stay running, don't quit.
|
||||||
if (!self.config.@"quit-after-last-window-closed") break :q false;
|
if (!self.config.@"quit-after-last-window-closed") break :q false;
|
||||||
|
|
||||||
if (self.quit_timer_source) |_| {
|
// If the quit timer has expired, quit.
|
||||||
// if the quit timer has expired, quit.
|
if (self.quit_timer == .expired) break :q true;
|
||||||
if (self.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;
|
||||||
@ -516,34 +516,41 @@ pub fn run(self: *App) !void {
|
|||||||
// cancelled if a new surface is opened before the timer expires.
|
// cancelled if a new surface is opened before the timer expires.
|
||||||
pub fn gtkQuitTimerExpired(ud: ?*anyopaque) callconv(.C) c.gboolean {
|
pub fn gtkQuitTimerExpired(ud: ?*anyopaque) callconv(.C) c.gboolean {
|
||||||
const self: *App = @ptrCast(@alignCast(ud));
|
const self: *App = @ptrCast(@alignCast(ud));
|
||||||
self.quit_timer_expired = true;
|
self.quit_timer = .{ .expired = {} };
|
||||||
return c.FALSE;
|
return c.FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This will get called when there are no more open surfaces.
|
/// This will get called when there are no more open surfaces.
|
||||||
pub fn startQuitTimer(self: *App) void {
|
pub fn startQuitTimer(self: *App) void {
|
||||||
// Cancel any previous timeout.
|
// Cancel any previous timer.
|
||||||
self.cancelQuitTimer();
|
self.cancelQuitTimer();
|
||||||
|
|
||||||
// This is a no-op unless we are configured to quit after last window is closed.
|
// This is a no-op unless we are configured to quit after last window is closed.
|
||||||
if (!self.config.@"quit-after-last-window-closed") return;
|
if (!self.config.@"quit-after-last-window-closed") return;
|
||||||
|
|
||||||
// If a delay is configured, set a timeout function to quit after the delay.
|
// If a delay is configured, set a timeout function to quit after the delay.
|
||||||
if (self.config.@"quit-after-last-window-closed-delay") |duration| {
|
if (self.config.@"quit-after-last-window-closed-delay") |v| {
|
||||||
const t: c.guint = if (duration.duration > (std.math.maxInt(c.guint) * std.time.ns_per_ms))
|
const ms: u64 = std.math.divTrunc(
|
||||||
std.math.maxInt(c.guint)
|
u64,
|
||||||
else
|
v.duration,
|
||||||
@intCast(duration.duration / std.time.ns_per_ms);
|
std.time.ns_per_ms,
|
||||||
self.quit_timer_source = c.g_timeout_add(t, gtkQuitTimerExpired, self);
|
) catch std.math.maxInt(c.guint);
|
||||||
|
const t = std.math.cast(c.guint, ms) orelse std.math.maxInt(c.guint);
|
||||||
|
self.quit_timer = .{ .active = c.g_timeout_add(t, gtkQuitTimerExpired, self) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This will get called when a new surface gets opened.
|
/// This will get called when a new surface gets opened.
|
||||||
pub fn cancelQuitTimer(self: *App) void {
|
pub fn cancelQuitTimer(self: *App) void {
|
||||||
if (self.quit_timer_source) |source| {
|
switch (self.quit_timer) {
|
||||||
if (c.g_source_remove(source) == c.FALSE)
|
.off => {},
|
||||||
log.warn("unable to remove quit timer {d}", .{source});
|
.expired => self.quit_timer = .{ .off = {} },
|
||||||
self.quit_timer_source = null;
|
.active => |source| {
|
||||||
|
if (c.g_source_remove(source) == c.FALSE) {
|
||||||
|
log.warn("unable to remove quit timer source={d}", .{source});
|
||||||
|
}
|
||||||
|
self.quit_timer = .{ .off = {} };
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user