diff --git a/src/Surface.zig b/src/Surface.zig index 5396c2068..b00219b6f 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -545,9 +545,7 @@ pub fn init( }; } - if (config.title) |title| { - try self.rt_surface.setTitle(title); - } + if (config.title) |title| try rt_surface.setTitle(title); } pub fn deinit(self: *Surface) void { @@ -668,9 +666,11 @@ pub fn handleMessage(self: *Surface, msg: Message) !void { .set_title => |*v| { // We ignore the message in case the title was set via config. - if (self.config.title) |_| { + 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); diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig index a23d8ed22..84582484e 100644 --- a/src/apprt/gtk/App.zig +++ b/src/apprt/gtk/App.zig @@ -107,31 +107,14 @@ pub fn init(core_app: *CoreApp, opts: Options) !App { const default_id = "com.mitchellh.ghostty"; const app_id: [:0]const u8 = app_id: { if (config.class) |class| { - break :app_id if (builtin.mode == .Debug) "com.mitchellh.ghostty-debug" else isValidGtkId(class) catch |err| switch (err) { - error.InvalidChar => { - log.warn("Invalid char found in class. Setting app id to default value", .{}); - break :app_id default_id; - }, - error.InvalidLength => { - log.warn("Class name value doesn't have valid length (> 0 or 255 <=). Setting app id to default value", .{}); - break :app_id default_id; - }, - error.NoDotInId => { - log.warn("Class name has no dot char. Setting app id to default value", .{}); - break :app_id default_id; - }, - error.StartWithDot => { - log.warn("Class name start with dot. Setting app id to default value", .{}); - break :app_id default_id; - }, - error.EndsWithDot => { - log.warn("Class name ends with dot. Setting app id to default value", .{}); - break :app_id default_id; - }, - }; - } else { - break :app_id if (builtin.mode == .Debug) "com.mitchellh.ghostty-debug" else default_id; + if (isValidAppId(class)) { + break :app_id class; + } else { + log.warn("invalid 'class' in config, ignoring", .{}); + } } + + break :app_id if (builtin.mode == .Debug) "com.mitchellh.ghostty-debug" else default_id; }; // Create our GTK Application which encapsulates our process. @@ -516,53 +499,31 @@ fn initMenu(self: *App) void { self.menu = menu; } -fn isValidGtkId(app_id: [:0]const u8) ![:0]const u8 { - var position: u8 = 0; +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; - - if (app_id.len > 255 or app_id.len == 0) - return error.InvalidLength; - - if (app_id[position] == '.') - return error.StartWithDot; - - if (app_id[app_id.len - 1] == '.') - return error.EndsWithDot; - - while (true) { - const char = app_id[position]; - + for (app_id) |char| { switch (char) { - 'a'...'z', 'A'...'Z', '0'...'9', '_', '-' => { - position += 1; - continue; - }, - '.' => { - hasDot = true; - position += 1; - continue; - }, - 0 => { - if (position != app_id.len) return error.InvalidChar; - break; - }, - else => return error.InvalidChar, + 'a'...'z', 'A'...'Z', '0'...'9', '_', '-' => {}, + '.' => hasDot = true, + 0 => return false, } } + if (!hasDot) return false; - if (!hasDot) return error.NoDotInId; - - return app_id; + return true; } -test "ValidGtkClassName" { - try testing.expectEqualStrings("foo.bar", try isValidGtkId("foo.bar")); - try testing.expectEqualStrings("foo.bar.baz", try isValidGtkId("foo.bar.baz")); - - try testing.expectError(error.NoDotInId, isValidGtkId("foo")); - try testing.expectError(error.InvalidChar, isValidGtkId("foo.bar?")); - try testing.expectError(error.EndsWithDot, isValidGtkId("foo.")); - try testing.expectError(error.StartWithDot, isValidGtkId(".foo")); - try testing.expectError(error.InvalidLength, isValidGtkId("")); - try testing.expectError(error.InvalidLength, isValidGtkId("foo" ** 86)); +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)); } diff --git a/src/apprt/gtk/Window.zig b/src/apprt/gtk/Window.zig index 28f3c9f6d..9a36f826f 100644 --- a/src/apprt/gtk/Window.zig +++ b/src/apprt/gtk/Window.zig @@ -123,12 +123,8 @@ pub fn init(self: *Window, app: *App) !void { } c.gtk_box_append(@ptrCast(box), notebook_widget); - if (app.config.fullscreen) { - c.gtk_window_fullscreen(self.window); - - // We disable this because we just want to start the first window in fullscreen. - app.config.fullscreen = false; - } + // 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(>kCloseRequest), self, null, c.G_CONNECT_DEFAULT); diff --git a/src/config/Config.zig b/src/config/Config.zig index 8e9b720fe..54f3d6c3f 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -278,23 +278,26 @@ command: ?[]const u8 = null, /// indicate that it is a login shell, depending on the OS). @"command-arg": RepeatableString = .{}, -/// The setting to tell Ghostty to start in fullscreen mode. -/// By default with will start windowed. -/// New windows created when this is set to true will not start in fullscreen. +/// 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. fullscreen: bool = false, -/// The setting that will change the application class value. -/// This is usefull if you want to have multiple instances of Ghostty -/// running with separate classes making it possible to have unique behavior for each of them. -/// This is currently only supported on Gtk builds. -/// The class name must follow the GTK requirements defined here: https://docs.gtk.org/gio/type_func.Application.id_is_valid.html -class: ?[:0]const u8 = null, - -/// The setting that will tell Ghostty which title to display. -/// By default Ghostty will output the current directory or what application is running as the title, -/// but with this setting it will force Ghostty to output that title independent of what is happening in the terminal. +/// 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"