mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 00:06:09 +03:00
apprt/gtk: enable single instance mode
This commit is contained in:
@ -31,11 +31,7 @@ const log = std.log.scoped(.gtk);
|
|||||||
/// application frameworks also have this restriction so it simplifies
|
/// application frameworks also have this restriction so it simplifies
|
||||||
/// the assumptions.
|
/// the assumptions.
|
||||||
pub const App = struct {
|
pub const App = struct {
|
||||||
pub const Options = struct {
|
pub const Options = struct {};
|
||||||
/// GTK app ID. This is currently unused but should remain populated
|
|
||||||
/// for the future.
|
|
||||||
id: [:0]const u8 = "com.mitchellh.ghostty",
|
|
||||||
};
|
|
||||||
|
|
||||||
core_app: *CoreApp,
|
core_app: *CoreApp,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -62,9 +58,14 @@ pub const App = struct {
|
|||||||
var config = try Config.load(core_app.alloc);
|
var config = try Config.load(core_app.alloc);
|
||||||
errdefer config.deinit();
|
errdefer config.deinit();
|
||||||
|
|
||||||
|
// Our uniqueness ID is based on whether we're in a debug mode or not.
|
||||||
|
// In debug mode we want to be separate so we can develop Ghostty in
|
||||||
|
// Ghostty.
|
||||||
|
const uniqueness_id = "com.mitchellh.ghostty" ++ if (builtin.mode == .Debug) "-debug" else "";
|
||||||
|
|
||||||
// Create our GTK Application which encapsulates our process.
|
// Create our GTK Application which encapsulates our process.
|
||||||
const app = @as(?*c.GtkApplication, @ptrCast(c.gtk_application_new(
|
const app = @as(?*c.GtkApplication, @ptrCast(c.gtk_application_new(
|
||||||
null,
|
uniqueness_id,
|
||||||
|
|
||||||
// GTK >= 2.74
|
// GTK >= 2.74
|
||||||
if (@hasDecl(c, "G_APPLICATION_DEFAULT_FLAGS"))
|
if (@hasDecl(c, "G_APPLICATION_DEFAULT_FLAGS"))
|
||||||
@ -77,7 +78,7 @@ pub const App = struct {
|
|||||||
app,
|
app,
|
||||||
"activate",
|
"activate",
|
||||||
c.G_CALLBACK(&activate),
|
c.G_CALLBACK(&activate),
|
||||||
null,
|
core_app,
|
||||||
null,
|
null,
|
||||||
G_CONNECT_DEFAULT,
|
G_CONNECT_DEFAULT,
|
||||||
);
|
);
|
||||||
@ -121,12 +122,19 @@ pub const App = struct {
|
|||||||
.ctx = ctx,
|
.ctx = ctx,
|
||||||
.cursor_default = cursor_default,
|
.cursor_default = cursor_default,
|
||||||
.cursor_ibeam = cursor_ibeam,
|
.cursor_ibeam = cursor_ibeam,
|
||||||
|
|
||||||
|
// If we are NOT the primary instance, then we never want to run.
|
||||||
|
// This means that another instance of the GTK app is running and
|
||||||
|
// our "activate" call above will open a window.
|
||||||
|
.running = c.g_application_get_is_remote(gapp) == 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Terminate the application. The application will not be restarted after
|
// Terminate the application. The application will not be restarted after
|
||||||
// this so all global state can be cleaned up.
|
// this so all global state can be cleaned up.
|
||||||
pub fn terminate(self: *App) void {
|
pub fn terminate(self: *App) void {
|
||||||
|
c.g_signal_emit(self.app, c.g_signal_lookup("shutdown", c.g_application_get_type()), 0);
|
||||||
|
|
||||||
c.g_settings_sync();
|
c.g_settings_sync();
|
||||||
while (c.g_main_context_iteration(self.ctx, 0) != 0) {}
|
while (c.g_main_context_iteration(self.ctx, 0) != 0) {}
|
||||||
c.g_main_context_release(self.ctx);
|
c.g_main_context_release(self.ctx);
|
||||||
@ -183,6 +191,9 @@ pub const App = struct {
|
|||||||
_ = parent_;
|
_ = parent_;
|
||||||
const alloc = self.core_app.alloc;
|
const alloc = self.core_app.alloc;
|
||||||
|
|
||||||
|
// If we're trying to quit, then do not open any new windows.
|
||||||
|
if (!self.running) return;
|
||||||
|
|
||||||
// Allocate a fixed pointer for our window. We try to minimize
|
// Allocate a fixed pointer for our window. We try to minimize
|
||||||
// allocations but windows and other GUI requirements are so minimal
|
// allocations but windows and other GUI requirements are so minimal
|
||||||
// compared to the steady-state terminal operation so we use heap
|
// compared to the steady-state terminal operation so we use heap
|
||||||
@ -261,15 +272,18 @@ pub const App = struct {
|
|||||||
}.callback, null);
|
}.callback, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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 activate(app: *c.GtkApplication, ud: ?*anyopaque) callconv(.C) void {
|
fn activate(app: *c.GtkApplication, ud: ?*anyopaque) callconv(.C) void {
|
||||||
_ = app;
|
_ = app;
|
||||||
_ = ud;
|
|
||||||
|
|
||||||
// We purposely don't do anything on activation right now. We have
|
const core_app: *CoreApp = @ptrCast(@alignCast(ud orelse return));
|
||||||
// this callback because if we don't then GTK emits a warning to
|
|
||||||
// stderr that we don't want. We emit a debug log just so that we know
|
// Queue a new window
|
||||||
// we reached this point.
|
_ = core_app.mailbox.push(.{
|
||||||
log.debug("application activated", .{});
|
.new_window = .{},
|
||||||
|
}, .{ .instant = {} });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,9 +34,6 @@ pub fn main() !void {
|
|||||||
var app_runtime = try apprt.App.init(app, .{});
|
var app_runtime = try apprt.App.init(app, .{});
|
||||||
defer app_runtime.terminate();
|
defer app_runtime.terminate();
|
||||||
|
|
||||||
// Create an initial window
|
|
||||||
try app_runtime.newWindow(null);
|
|
||||||
|
|
||||||
// Run the GUI event loop
|
// Run the GUI event loop
|
||||||
try app_runtime.run();
|
try app_runtime.run();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user