GTK: start search accepts selection contents (#10262)

Fixes: #10196

If user invokes `search_selection` the contents of that string are no
longer ignored.

I'm not very familar with how apprt actions are sent to macos to ensure
the defer free will work there, but it is required for GTK otherwise we
are leaking the memory

I'm also open to making the string optional instead of checking against
`""` thats just how the current `start_search` action was sending its
needle (which I assume is better for macos?)

The text is also highlighted currently due to `grabFocus` always
selecting the search contents, not sure how the macos part works but
that could easily be changed to change the contents after focus was
grabbed

https://github.com/ghostty-org/ghostty/blob/main/src/apprt/gtk/class/search_overlay.zig#L233-L241
This commit is contained in:
Mitchell Hashimoto
2026-01-11 07:23:29 -08:00
committed by GitHub
4 changed files with 17 additions and 5 deletions

View File

@@ -5221,6 +5221,7 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
.search_selection => {
const selection = try self.selectionString(self.alloc) orelse return false;
defer self.alloc.free(selection);
return try self.rt_app.performAction(
.{ .surface = self },
.start_search,

View File

@@ -734,7 +734,7 @@ pub const Application = extern struct {
.show_on_screen_keyboard => return Action.showOnScreenKeyboard(target),
.command_finished => return Action.commandFinished(target, value),
.start_search => Action.startSearch(target),
.start_search => Action.startSearch(target, value),
.end_search => Action.endSearch(target),
.search_total => Action.searchTotal(target, value),
.search_selected => Action.searchSelected(target, value),
@@ -2439,17 +2439,17 @@ const Action = struct {
}
}
pub fn startSearch(target: apprt.Target) void {
pub fn startSearch(target: apprt.Target, value: apprt.action.StartSearch) void {
switch (target) {
.app => {},
.surface => |v| v.rt_surface.surface.setSearchActive(true),
.surface => |v| v.rt_surface.surface.setSearchActive(true, value.needle),
}
}
pub fn endSearch(target: apprt.Target) void {
switch (target) {
.app => {},
.surface => |v| v.rt_surface.surface.setSearchActive(false),
.surface => |v| v.rt_surface.surface.setSearchActive(false, ""),
}
}

View File

@@ -250,6 +250,13 @@ pub const SearchOverlay = extern struct {
priv.active = active;
}
// Set contents of search
pub fn setSearchContents(self: *Self, content: [:0]const u8) void {
const priv = self.private();
priv.search_entry.as(gtk.Editable).setText(content);
signals.@"search-changed".impl.emit(self, null, .{content}, null);
}
/// Set the total number of search matches.
pub fn setSearchTotal(self: *Self, total: ?usize) void {
const priv = self.private();

View File

@@ -2091,7 +2091,7 @@ pub const Surface = extern struct {
self.as(gobject.Object).notifyByPspec(properties.@"error".impl.param_spec);
}
pub fn setSearchActive(self: *Self, active: bool) void {
pub fn setSearchActive(self: *Self, active: bool, needle: [:0]const u8) void {
const priv = self.private();
var value = gobject.ext.Value.newFrom(active);
defer value.unset();
@@ -2101,6 +2101,10 @@ pub const Surface = extern struct {
&value,
);
if (!std.mem.eql(u8, needle, "")) {
priv.search_overlay.setSearchContents(needle);
}
if (active) {
priv.search_overlay.grabFocus();
}