From 094f8effa3d5504692e6e89462eb2bb2ede1e7ec Mon Sep 17 00:00:00 2001 From: Raiden1411 <67233402+Raiden1411@users.noreply.github.com> Date: Mon, 6 Nov 2023 10:19:09 +0000 Subject: [PATCH] fix: begin implementation of suggested changes --- src/Surface.zig | 21 +++++----- src/apprt/gtk/App.zig | 82 +++++++++++++++++++++++++++++++++++++++- src/apprt/gtk/Window.zig | 4 ++ 3 files changed, 93 insertions(+), 14 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index 24810d933..a450051c0 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -546,10 +546,8 @@ pub fn init( }; } - if (config.fullscreen) { - if (@hasDecl(apprt.Surface, "toggleFullscreen")) { - rt_surface.toggleFullscreen(config.@"macos-non-native-fullscreen"); - } else log.warn("runtime doesn't implement toggleFullscreen", .{}); + if (config.title) |title| { + try self.rt_surface.setTitle(title); } } @@ -670,16 +668,15 @@ 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) |_| { + return; + } // The ptrCast just gets sliceTo to return the proper type. // We know that our title should end in 0. - if (self.config.title) |title| { - log.debug("setting title \"{s}\"", .{title}); - try self.rt_surface.setTitle(title); - } else { - const slice = std.mem.sliceTo(@as([*:0]const u8, @ptrCast(v)), 0); - log.debug("changing title \"{s}\"", .{slice}); - try self.rt_surface.setTitle(slice); - } + const slice = std.mem.sliceTo(@as([*:0]const u8, @ptrCast(v)), 0); + log.debug("changing title \"{s}\"", .{slice}); + try self.rt_surface.setTitle(slice); }, .set_mouse_shape => |shape| { diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig index cbda211ab..7c830aef9 100644 --- a/src/apprt/gtk/App.zig +++ b/src/apprt/gtk/App.zig @@ -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,10 +104,36 @@ 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 default_id = "com.mitchellh.ghostty"; const app_id: [:0]const u8 = app_id: { - var id = config.class orelse "com.mitchellh.ghostty"; - break :app_id if (builtin.mode == .Debug) "com.mitchellh.ghostty-debug" else 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 is over 255 chars in length. 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; + } }; + // Create our GTK Application which encapsulates our process. log.debug("creating GTK application id={s} single-instance={}", .{ app_id, @@ -488,3 +515,54 @@ fn initMenu(self: *App) void { self.menu = menu; } + +fn isValidGtkId(app_id: [:0]const u8) ![:0]const u8 { + var position: u8 = 0; + 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]; + + 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, + } + } + + if (!hasDot) return error.NoDotInId; + + return app_id; +} + +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)); +} diff --git a/src/apprt/gtk/Window.zig b/src/apprt/gtk/Window.zig index 1103806c3..b4a4327c9 100644 --- a/src/apprt/gtk/Window.zig +++ b/src/apprt/gtk/Window.zig @@ -123,6 +123,10 @@ 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); + } + // All of our events _ = c.g_signal_connect_data(window, "close-request", c.G_CALLBACK(>kCloseRequest), self, null, c.G_CONNECT_DEFAULT); _ = c.g_signal_connect_data(window, "destroy", c.G_CALLBACK(>kDestroy), self, null, c.G_CONNECT_DEFAULT);