74 lines
2.5 KiB
Zig
74 lines
2.5 KiB
Zig
//! Playpen: a terminal with vertical tabs, web panes and saved layouts, built
|
|
//! on libghostty-vt.
|
|
//!
|
|
//! libghostty-vt supplies the terminal emulator core (escape sequence
|
|
//! parsing, screen and scrollback state, key/mouse encoding). Everything
|
|
//! else — process management, rendering, and the GTK4 UI — lives here.
|
|
|
|
const std = @import("std");
|
|
const adw = @import("adw");
|
|
const gdk = @import("gdk");
|
|
const gio = @import("gio");
|
|
const gtk = @import("gtk");
|
|
|
|
const Window = @import("Window.zig");
|
|
|
|
/// libghostty-vt logs unimplemented sequences at debug level, which is very
|
|
/// chatty against a real shell. Keep the app's own warnings and errors.
|
|
pub const std_options: std.Options = .{
|
|
.log_level = .info,
|
|
};
|
|
|
|
const css = @embedFile("style.css");
|
|
|
|
var gpa: std.heap.DebugAllocator(.{}) = .init;
|
|
|
|
pub fn main() u8 {
|
|
defer _ = gpa.deinit();
|
|
|
|
// Non-unique so every launch is its own process. The default GApplication
|
|
// behavior hands off to an already-running instance over D-Bus, which for
|
|
// a terminal means a second launch silently does nothing visible here and
|
|
// opens a window in whatever session owns the first one.
|
|
const app = adw.Application.new("dev.greyson.playpen", .{ .non_unique = true });
|
|
defer app.unref();
|
|
|
|
_ = gio.Application.signals.activate.connect(app, ?*anyopaque, &onActivate, null, .{});
|
|
|
|
const status = gio.Application.run(app.as(gio.Application), 0, null);
|
|
return @intCast(status);
|
|
}
|
|
|
|
fn onActivate(app: *adw.Application, _: ?*anyopaque) callconv(.c) void {
|
|
forceDark();
|
|
loadCss();
|
|
|
|
const window = Window.create(gpa.allocator(), app) catch |err| {
|
|
std.log.err("failed to create window: {s}", .{@errorName(err)});
|
|
return;
|
|
};
|
|
window.present();
|
|
}
|
|
|
|
/// The window's own chrome is dark by hand in `style.css`, but stock widgets —
|
|
/// popovers, dialogs, text entries — follow the desktop's colour scheme and
|
|
/// would come up light against it. Layouts brought the first real dialogs into
|
|
/// the app, which is where that mismatch became visible.
|
|
fn forceDark() void {
|
|
const manager = adw.StyleManager.getDefault();
|
|
manager.setColorScheme(.force_dark);
|
|
}
|
|
|
|
fn loadCss() void {
|
|
const display = gdk.Display.getDefault() orelse return;
|
|
const provider = gtk.CssProvider.new();
|
|
defer provider.unref();
|
|
|
|
provider.loadFromString(css);
|
|
gtk.StyleContext.addProviderForDisplay(
|
|
display,
|
|
provider.as(gtk.StyleProvider),
|
|
gtk.STYLE_PROVIDER_PRIORITY_APPLICATION,
|
|
);
|
|
}
|