feat(GTK): show menu in context menu if titlebar is disabled (#4864)

This PR addresses https://github.com/ghostty-org/ghostty/issues/4732.

While @tristan957 suggested alternative approaches, this implementation
provides a straightforward way to make the menu accessible when the
window decoration is disabled. It follows patterns seen in other GTK
apps for handling submenus, though not strictly in the context menu
format truth be told.

If there’s a better way to approach this or further refinements needed,
I’m happy to discuss and iterate. This has been a minor issue I’ve
encountered personally, and I’d like to help improve the experience for
others as well.

Small video of how it looks:


https://github.com/user-attachments/assets/59548fef-f11c-421f-b05b-be81eab6ce06
This commit is contained in:
Mitchell Hashimoto
2025-01-09 07:28:42 -08:00
committed by GitHub
2 changed files with 29 additions and 13 deletions

View File

@ -831,12 +831,12 @@ fn setSizeLimit(
switch (target) {
.app => {},
.surface => |v| try v.rt_surface.setSizeLimits(.{
.width = value.min_width,
.height = value.min_height,
}, if (value.max_width > 0) .{
.width = value.max_width,
.height = value.max_height,
} else null),
.width = value.min_width,
.height = value.min_height,
}, if (value.max_width > 0) .{
.width = value.max_width,
.height = value.max_height,
} else null),
}
}
@ -1766,12 +1766,10 @@ fn initActions(self: *App) void {
}
}
/// This sets the self.menu property to the application menu that can be
/// shared by all application windows.
fn initMenu(self: *App) void {
const menu = c.g_menu_new();
errdefer c.g_object_unref(menu);
/// Initializes and populates the provided GMenu with sections and actions.
/// This function is used to set up the application's menu structure, either for
/// the main menu button or as a context menu when window decorations are disabled.
fn initMenuContent(menu: *c.GMenu) void {
{
const section = c.g_menu_new();
defer c.g_object_unref(section);
@ -1793,7 +1791,14 @@ fn initMenu(self: *App) void {
c.g_menu_append(section, "Reload Configuration", "app.reload-config");
c.g_menu_append(section, "About Ghostty", "win.about");
}
}
/// This sets the self.menu property to the application menu that can be
/// shared by all application windows.
fn initMenu(self: *App) void {
const menu = c.g_menu_new();
errdefer c.g_object_unref(menu);
initMenuContent(@ptrCast(menu));
self.menu = menu;
}
@ -1825,6 +1830,17 @@ fn initContextMenu(self: *App) void {
c.g_menu_append(section, "Terminal Inspector", "win.toggle_inspector");
}
if (!self.config.@"window-decoration") {
const section = c.g_menu_new();
defer c.g_object_unref(section);
const submenu = c.g_menu_new();
defer c.g_object_unref(submenu);
initMenuContent(@ptrCast(submenu));
c.g_menu_append_submenu(section, "Menu", @ptrCast(@alignCast(submenu)));
c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section)));
}
self.context_menu = menu;
}

View File

@ -270,7 +270,7 @@ pub fn init(self: *Window, app: *App) !void {
}
self.context_menu = c.gtk_popover_menu_new_from_model(@ptrCast(@alignCast(self.app.context_menu)));
c.gtk_widget_set_parent(self.context_menu, window);
c.gtk_widget_set_parent(self.context_menu, box);
c.gtk_popover_set_has_arrow(@ptrCast(@alignCast(self.context_menu)), 0);
c.gtk_widget_set_halign(self.context_menu, c.GTK_ALIGN_START);