diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig index a33f1ce51..39a2ec62f 100644 --- a/src/apprt/gtk/App.zig +++ b/src/apprt/gtk/App.zig @@ -398,8 +398,22 @@ fn initActions(self: *App) void { fn initMenu(self: *App) void { const menu = c.g_menu_new(); errdefer c.g_object_unref(menu); - c.g_menu_append(menu, "Close", "win.close"); - c.g_menu_append(menu, "Quit", "app.quit"); + + { + const section = c.g_menu_new(); + defer c.g_object_unref(section); + c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section))); + c.g_menu_append(section, "New Window", "win.new_window"); + c.g_menu_append(section, "New Tab", "win.new_tab"); + } + + { + const section = c.g_menu_new(); + defer c.g_object_unref(section); + c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section))); + c.g_menu_append(section, "Close Window", "win.close"); + c.g_menu_append(section, "Quit Ghostty", "app.quit"); + } // { // const section = c.g_menu_new(); diff --git a/src/apprt/gtk/Window.zig b/src/apprt/gtk/Window.zig index cf6e109c5..20b5510fb 100644 --- a/src/apprt/gtk/Window.zig +++ b/src/apprt/gtk/Window.zig @@ -159,11 +159,25 @@ pub fn init(self: *Window, app: *App) !void { /// menus and such. The menu is defined in App.zig but the action is defined /// here. The string name binds them. fn initActions(self: *Window) void { - const action_close = c.g_simple_action_new("close", null); - defer c.g_object_unref(action_close); - _ = c.g_signal_connect_data(action_close, "activate", c.G_CALLBACK(>kActionClose), self, null, c.G_CONNECT_DEFAULT); + const actions = .{ + .{ "close", >kActionClose }, + .{ "new_window", >kActionNewWindow }, + .{ "new_tab", >kActionNewTab }, + }; - c.g_action_map_add_action(@ptrCast(self.window), @ptrCast(action_close)); + inline for (actions) |entry| { + const action = c.g_simple_action_new(entry[0], null); + defer c.g_object_unref(action); + _ = c.g_signal_connect_data( + action, + "activate", + c.G_CALLBACK(entry[1]), + self, + null, + c.G_CONNECT_DEFAULT, + ); + c.g_action_map_add_action(@ptrCast(self.window), @ptrCast(action)); + } } pub fn deinit(self: *Window) void { @@ -492,6 +506,32 @@ fn gtkActionClose( }; } +fn gtkActionNewWindow( + _: *c.GSimpleAction, + _: *c.GVariant, + ud: ?*anyopaque, +) callconv(.C) void { + const self: *Window = @ptrCast(@alignCast(ud orelse return)); + const surface = self.app.core_app.focusedSurface() orelse return; + surface.performBindingAction(.{ .new_window = {} }) catch |err| { + log.warn("error performing binding action error={}", .{err}); + return; + }; +} + +fn gtkActionNewTab( + _: *c.GSimpleAction, + _: *c.GVariant, + ud: ?*anyopaque, +) callconv(.C) void { + const self: *Window = @ptrCast(@alignCast(ud orelse return)); + const surface = self.app.core_app.focusedSurface() orelse return; + surface.performBindingAction(.{ .new_tab = {} }) catch |err| { + log.warn("error performing binding action error={}", .{err}); + return; + }; +} + fn userdataSelf(ud: *anyopaque) *Window { return @ptrCast(@alignCast(ud)); }