Merge pull request #816 from Raiden1411/feat/options

feat: add support for `--fullscreen`, `--title` and `--class` values
This commit is contained in:
Mitchell Hashimoto
2023-11-06 08:55:33 -08:00
committed by GitHub
6 changed files with 92 additions and 4 deletions

View File

@ -67,6 +67,11 @@ class TerminalManager {
Self.lastCascadePoint = window.cascadeTopLeft(from: Self.lastCascadePoint)
}
if (ghostty.windowFullscreen) {
// NOTE: this doesn't properly handle non-native fullscreen yet
c.window?.toggleFullScreen(nil)
}
c.showWindow(self)
}

View File

@ -105,6 +105,15 @@ extension Ghostty {
_ = ghostty_config_get(config, &v, key, UInt(key.count))
return v
}
/// Whether to open new windows in fullscreen.
var windowFullscreen: Bool {
guard let config = self.config else { return true }
var v = false
let key = "fullscreen"
_ = ghostty_config_get(config, &v, key, UInt(key.count))
return v
}
/// The background opacity.
var backgroundOpacity: Double {

View File

@ -155,6 +155,7 @@ const DerivedConfig = struct {
window_padding_x: u32,
window_padding_y: u32,
window_padding_balance: bool,
title: ?[:0]const u8,
pub fn init(alloc_gpa: Allocator, config: *const configpkg.Config) !DerivedConfig {
var arena = ArenaAllocator.init(alloc_gpa);
@ -180,6 +181,7 @@ const DerivedConfig = struct {
.window_padding_x = config.@"window-padding-x",
.window_padding_y = config.@"window-padding-y",
.window_padding_balance = config.@"window-padding-balance",
.title = config.title,
// Assignments happen sequentially so we have to do this last
// so that the memory is captured from allocs above.
@ -544,6 +546,8 @@ pub fn init(
log.warn("unable to set initial window size: {s}", .{err});
};
}
if (config.title) |title| try rt_surface.setTitle(title);
}
pub fn deinit(self: *Surface) void {
@ -663,6 +667,12 @@ pub fn handleMessage(self: *Surface, msg: Message) !void {
.change_config => |config| try self.changeConfig(config),
.set_title => |*v| {
// We ignore the message in case the title was set via config.
if (self.config.title != null) {
log.debug("ignoring title change request since static title is set via config", .{});
return;
}
// The ptrCast just gets sliceTo to return the proper type.
// We know that our title should end in 0.
const slice = std.mem.sliceTo(@as([*:0]const u8, @ptrCast(v)), 0);

View File

@ -28,6 +28,7 @@ const UnsafePasteWindow = @import("UnsafePasteWindow.zig");
const c = @import("c.zig");
const inspector = @import("inspector.zig");
const key = @import("key.zig");
const testing = std.testing;
const log = std.log.scoped(.gtk);
@ -103,9 +104,17 @@ pub fn init(core_app: *CoreApp, opts: Options) !App {
// Our app ID determines uniqueness and maps to our desktop file.
// We append "-debug" to the ID if we're in debug mode so that we
// can develop Ghostty in Ghostty.
const app_id: [:0]const u8 = comptime app_id: {
var id = "com.mitchellh.ghostty";
break :app_id if (builtin.mode == .Debug) id ++ "-debug" else id;
const app_id: [:0]const u8 = app_id: {
if (config.class) |class| {
if (isValidAppId(class)) {
break :app_id class;
} else {
log.warn("invalid 'class' in config, ignoring", .{});
}
}
const default_id = "com.mitchellh.ghostty";
break :app_id if (builtin.mode == .Debug) default_id ++ "-debug" else default_id;
};
// Create our GTK Application which encapsulates our process.
@ -159,7 +168,6 @@ pub fn init(core_app: *CoreApp, opts: Options) !App {
.config = config,
.ctx = ctx,
.cursor_none = cursor_none,
// 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.
@ -490,3 +498,32 @@ fn initMenu(self: *App) void {
self.menu = menu;
}
fn isValidAppId(app_id: [:0]const u8) bool {
if (app_id.len > 255 or app_id.len == 0) return false;
if (app_id[0] == '.') return false;
if (app_id[app_id.len - 1] == '.') return false;
var hasDot = false;
for (app_id) |char| {
switch (char) {
'a'...'z', 'A'...'Z', '0'...'9', '_', '-' => {},
'.' => hasDot = true,
else => return false,
}
}
if (!hasDot) return false;
return true;
}
test "isValidAppId" {
try testing.expect(isValidAppId("foo.bar"));
try testing.expect(isValidAppId("foo.bar.baz"));
try testing.expect(!isValidAppId("foo"));
try testing.expect(!isValidAppId("foo.bar?"));
try testing.expect(!isValidAppId("foo."));
try testing.expect(!isValidAppId(".foo"));
try testing.expect(!isValidAppId(""));
try testing.expect(!isValidAppId("foo" ** 86));
}

View File

@ -123,6 +123,9 @@ pub fn init(self: *Window, app: *App) !void {
}
c.gtk_box_append(@ptrCast(box), notebook_widget);
// If we are in fullscreen mode, new windows start fullscreen.
if (app.config.fullscreen) c.gtk_window_fullscreen(self.window);
// All of our events
_ = c.g_signal_connect_data(window, "close-request", c.G_CALLBACK(&gtkCloseRequest), self, null, c.G_CONNECT_DEFAULT);
_ = c.g_signal_connect_data(window, "destroy", c.G_CALLBACK(&gtkDestroy), self, null, c.G_CONNECT_DEFAULT);

View File

@ -278,6 +278,30 @@ command: ?[]const u8 = null,
/// indicate that it is a login shell, depending on the OS).
@"command-arg": RepeatableString = .{},
/// Start new windows in fullscreen. This setting applies to new
/// windows and does not apply to tabs, splits, etc. However, this
/// setting will apply to all new windows, not just the first one.
///
/// On macOS, this always creates the window in native fullscreen.
/// Non-native fullscreen is not currently supported with this
/// setting.
fullscreen: bool = false,
/// The title Ghostty will use for the window. This will force the title
/// of the window to be this title at all times and Ghostty will ignore any
/// set title escape sequences programs (such as Neovim) may send.
title: ?[:0]const u8 = null,
/// The setting that will change the application class value. This value is
/// often used with Linux window managers to change behavior (such as
/// floating vs tiled). If you don't know what this is, don't set it.
///
/// The class name must follow the GTK requirements defined here:
/// https://docs.gtk.org/gio/type_func.Application.id_is_valid.html
///
/// This only affects GTK builds.
class: ?[:0]const u8 = null,
/// The directory to change to after starting the command.
///
/// This setting is secondary to the "window-inherit-working-directory"