mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
Implement a prompt that allows the user to set the title
This commit is contained in:

committed by
Jeffrey C. Ollie

parent
3f715c296a
commit
6b75ca40ca
@ -495,6 +495,7 @@ pub fn performAction(
|
||||
.toggle_split_zoom => self.toggleSplitZoom(target),
|
||||
.toggle_window_decorations => self.toggleWindowDecorations(target),
|
||||
.quit_timer => self.quitTimer(value),
|
||||
.prompt_title => try self.promptTitle(target),
|
||||
|
||||
// Unimplemented
|
||||
.close_all_windows,
|
||||
@ -506,7 +507,6 @@ pub fn performAction(
|
||||
.render_inspector,
|
||||
.renderer_health,
|
||||
.color_change,
|
||||
.prompt_title,
|
||||
=> {
|
||||
log.warn("unimplemented action={}", .{action});
|
||||
return false;
|
||||
@ -770,6 +770,15 @@ fn quitTimer(self: *App, mode: apprt.action.QuitTimer) void {
|
||||
}
|
||||
}
|
||||
|
||||
fn promptTitle(_: *App, target: apprt.Target) !void {
|
||||
switch (target) {
|
||||
.app => {},
|
||||
.surface => |v| {
|
||||
try v.rt_surface.promptTitle();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn setTitle(
|
||||
_: *App,
|
||||
target: apprt.Target,
|
||||
@ -1016,6 +1025,7 @@ fn syncActionAccelerators(self: *App) !void {
|
||||
try self.syncActionAccelerator("win.paste", .{ .paste_from_clipboard = {} });
|
||||
try self.syncActionAccelerator("win.reset", .{ .reset = {} });
|
||||
try self.syncActionAccelerator("win.clear", .{ .clear_screen = {} });
|
||||
try self.syncActionAccelerator("win.prompt-title", .{ .prompt_surface_title = {} });
|
||||
}
|
||||
|
||||
fn syncActionAccelerator(
|
||||
@ -1766,6 +1776,97 @@ fn initActions(self: *App) void {
|
||||
}
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
/// 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);
|
||||
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");
|
||||
c.g_menu_append(section, "Close Tab", "win.close_tab");
|
||||
c.g_menu_append(section, "Split Right", "win.split_right");
|
||||
c.g_menu_append(section, "Split Down", "win.split_down");
|
||||
c.g_menu_append(section, "Close Window", "win.close");
|
||||
}
|
||||
|
||||
{
|
||||
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, "Terminal Inspector", "win.toggle_inspector");
|
||||
c.g_menu_append(section, "Open Configuration", "app.open-config");
|
||||
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;
|
||||
}
|
||||
|
||||
fn initContextMenu(self: *App) void {
|
||||
const menu = c.g_menu_new();
|
||||
errdefer c.g_object_unref(menu);
|
||||
|
||||
{
|
||||
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, "Copy", "win.copy");
|
||||
c.g_menu_append(section, "Paste", "win.paste");
|
||||
}
|
||||
|
||||
{
|
||||
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, "Split Right", "win.split_right");
|
||||
c.g_menu_append(section, "Split Down", "win.split_down");
|
||||
}
|
||||
|
||||
{
|
||||
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, "Change Title...", "win.prompt-title");
|
||||
}
|
||||
|
||||
{
|
||||
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, "Reset", "win.reset");
|
||||
c.g_menu_append(section, "Terminal Inspector", "win.toggle_inspector");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
pub fn refreshContextMenu(_: *App, window: ?*c.GtkWindow, has_selection: bool) void {
|
||||
const action: ?*c.GSimpleAction = @ptrCast(c.g_action_map_lookup_action(@ptrCast(window), "copy"));
|
||||
c.g_simple_action_set_enabled(action, if (has_selection) 1 else 0);
|
||||
}
|
||||
|
||||
>>>>>>> a9ae01e38 (Implement a prompt that allows the user to set the title)
|
||||
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;
|
||||
|
@ -987,6 +987,31 @@ pub fn getTitle(self: *Surface) ?[:0]const u8 {
|
||||
return null;
|
||||
}
|
||||
|
||||
const PromptTitleDialogContext = struct {
|
||||
entry: *c.GtkWidget,
|
||||
self: *Surface,
|
||||
};
|
||||
|
||||
pub fn promptTitle(self: *Surface) !void {
|
||||
const window = self.container.window() orelse return;
|
||||
|
||||
const context = try self.app.core_app.alloc.create(PromptTitleDialogContext);
|
||||
context.self = self;
|
||||
|
||||
const dialog = c.gtk_message_dialog_new(window.window, c.GTK_DIALOG_MODAL, c.GTK_MESSAGE_QUESTION, c.GTK_BUTTONS_OK_CANCEL, "Set Tab Title");
|
||||
|
||||
const content_area = c.gtk_message_dialog_get_message_area(@ptrCast(dialog));
|
||||
|
||||
const entry = c.gtk_entry_new();
|
||||
context.entry = entry;
|
||||
c.gtk_box_append(@ptrCast(content_area), entry);
|
||||
c.gtk_widget_show(entry);
|
||||
|
||||
_ = c.g_signal_connect_data(dialog, "response", c.G_CALLBACK(>kPromptTitleResponse), context, null, c.G_CONNECT_DEFAULT);
|
||||
|
||||
c.gtk_widget_show(dialog);
|
||||
}
|
||||
|
||||
/// Set the current working directory of the surface.
|
||||
///
|
||||
/// In addition, update the tab's tooltip text, and if we are the focused child,
|
||||
@ -2273,3 +2298,13 @@ fn g_value_holds(value_: ?*c.GValue, g_type: c.GType) bool {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn gtkPromptTitleResponse(dialog: *c.GtkDialog, response: c.gint, ud: ?*anyopaque) callconv(.C) void {
|
||||
const context: *PromptTitleDialogContext = @ptrCast(@alignCast(ud));
|
||||
if (response == c.GTK_RESPONSE_OK) {
|
||||
const buffer = c.gtk_entry_get_buffer(@ptrCast(context.entry));
|
||||
const title = c.gtk_entry_buffer_get_text(buffer);
|
||||
context.self.setTitle(std.mem.span(title)) catch {};
|
||||
}
|
||||
c.gtk_window_destroy(@ptrCast(dialog));
|
||||
}
|
||||
|
@ -478,6 +478,7 @@ fn initActions(self: *Window) void {
|
||||
.{ "paste", >kActionPaste },
|
||||
.{ "reset", >kActionReset },
|
||||
.{ "clear", >kActionClear },
|
||||
.{ "prompt_title", >kActionPromptTitle },
|
||||
};
|
||||
|
||||
inline for (actions) |entry| {
|
||||
@ -1071,6 +1072,19 @@ fn gtkActionClear(
|
||||
};
|
||||
}
|
||||
|
||||
fn gtkActionPromptTitle(
|
||||
_: *c.GSimpleAction,
|
||||
_: *c.GVariant,
|
||||
ud: ?*anyopaque,
|
||||
) callconv(.C) void {
|
||||
const self: *Window = @ptrCast(@alignCast(ud orelse return));
|
||||
const surface = self.actionSurface() orelse return;
|
||||
_ = surface.performBindingAction(.{ .prompt_surface_title = {} }) catch |err| {
|
||||
log.warn("error performing binding action error={}", .{err});
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the surface to use for an action.
|
||||
pub fn actionSurface(self: *Window) ?*CoreSurface {
|
||||
const tab = self.notebook.currentTab() orelse return null;
|
||||
|
Reference in New Issue
Block a user