Merge pull request #594 from mitchellh/gtk-prev-tab

apprt/gtk: ctrl+page-up/down for prev/next tab, does not consume input if no tabs
This commit is contained in:
Mitchell Hashimoto
2023-09-29 22:22:57 -07:00
committed by GitHub
5 changed files with 58 additions and 12 deletions

View File

@ -927,15 +927,16 @@ pub fn keyCallback(
// We only execute the binding on press/repeat but we still consume // We only execute the binding on press/repeat but we still consume
// the key on release so that we don't send any release events. // the key on release so that we don't send any release events.
log.debug("key event consumed by binding action={}", .{binding_action}); log.debug("key event binding consumed={} action={}", .{ consumed, binding_action });
if (event.action == .press or event.action == .repeat) { const performed = if (event.action == .press or event.action == .repeat)
try self.performBindingAction(binding_action); try self.performBindingAction(binding_action)
} else
false;
// If we consume this event, then we are done. If we don't consume // If we consume this event, then we are done. If we don't consume
// it, we processed the action but we still want to process our // it, we processed the action but we still want to process our
// encodings, too. // encodings, too.
if (consumed) return true; if (consumed and performed) return true;
} }
// If this input event has text, then we hide the mouse if configured. // If this input event has text, then we hide the mouse if configured.
@ -1902,7 +1903,15 @@ fn showMouse(self: *Surface) void {
/// Perform a binding action. A binding is a keybinding. This function /// Perform a binding action. A binding is a keybinding. This function
/// must be called from the GUI thread. /// must be called from the GUI thread.
pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !void { ///
/// This function returns true if the binding action was performed. This
/// may return false if the binding action is not supported or if the
/// binding action would do nothing (i.e. previous tab with no tabs).
///
/// NOTE: At the time of writing this comment, only previous/next tab
/// will ever return false. We can expand this in the future if it becomes
/// useful. We did previous/next tab so we could implement #498.
pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool {
switch (action) { switch (action) {
.unbind => unreachable, .unbind => unreachable,
.ignore => {}, .ignore => {},
@ -1971,13 +1980,13 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !void
self.config.clipboard_trim_trailing_spaces, self.config.clipboard_trim_trailing_spaces,
) catch |err| { ) catch |err| {
log.err("error reading selection string err={}", .{err}); log.err("error reading selection string err={}", .{err});
return; return true;
}; };
defer self.alloc.free(buf); defer self.alloc.free(buf);
self.rt_surface.setClipboardString(buf, .standard) catch |err| { self.rt_surface.setClipboardString(buf, .standard) catch |err| {
log.err("error setting clipboard string err={}", .{err}); log.err("error setting clipboard string err={}", .{err});
return; return true;
}; };
} }
}, },
@ -2116,12 +2125,26 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !void
}, },
.previous_tab => { .previous_tab => {
if (@hasDecl(apprt.Surface, "hasTabs")) {
if (!self.rt_surface.hasTabs()) {
log.debug("surface has no tabs, ignoring previous_tab binding", .{});
return false;
}
}
if (@hasDecl(apprt.Surface, "gotoPreviousTab")) { if (@hasDecl(apprt.Surface, "gotoPreviousTab")) {
self.rt_surface.gotoPreviousTab(); self.rt_surface.gotoPreviousTab();
} else log.warn("runtime doesn't implement gotoPreviousTab", .{}); } else log.warn("runtime doesn't implement gotoPreviousTab", .{});
}, },
.next_tab => { .next_tab => {
if (@hasDecl(apprt.Surface, "hasTabs")) {
if (!self.rt_surface.hasTabs()) {
log.debug("surface has no tabs, ignoring next_tab binding", .{});
return false;
}
}
if (@hasDecl(apprt.Surface, "gotoNextTab")) { if (@hasDecl(apprt.Surface, "gotoNextTab")) {
self.rt_surface.gotoNextTab(); self.rt_surface.gotoNextTab();
} else log.warn("runtime doesn't implement gotoNextTab", .{}); } else log.warn("runtime doesn't implement gotoNextTab", .{});
@ -2163,6 +2186,8 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !void
.quit => try self.app.setQuit(), .quit => try self.app.setQuit(),
} }
return true;
} }
/// Call this to complete a clipboard request sent to apprt. This should /// Call this to complete a clipboard request sent to apprt. This should

View File

@ -987,7 +987,7 @@ pub const CAPI = struct {
return false; return false;
}; };
ptr.core_surface.performBindingAction(action) catch |err| { _ = ptr.core_surface.performBindingAction(action) catch |err| {
log.err("error performing binding action action={} err={}", .{ action, err }); log.err("error performing binding action action={} err={}", .{ action, err });
return false; return false;
}; };

View File

@ -288,6 +288,10 @@ pub fn newTab(self: *Surface) !void {
try self.window.newTab(&self.core_surface); try self.window.newTab(&self.core_surface);
} }
pub fn hasTabs(self: *const Surface) bool {
return self.window.hasTabs();
}
pub fn gotoPreviousTab(self: *Surface) void { pub fn gotoPreviousTab(self: *Surface) void {
self.window.gotoPreviousTab(self); self.window.gotoPreviousTab(self);
} }

View File

@ -290,6 +290,11 @@ pub fn closeSurface(self: *Window, surface: *Surface) void {
self.closeTab(page); self.closeTab(page);
} }
/// Returns true if this window has any tabs.
pub fn hasTabs(self: *const Window) bool {
return c.gtk_notebook_get_n_pages(self.notebook) > 1;
}
/// Go to the previous tab for a surface. /// Go to the previous tab for a surface.
pub fn gotoPreviousTab(self: *Window, surface: *Surface) void { pub fn gotoPreviousTab(self: *Window, surface: *Surface) void {
const page = c.gtk_notebook_get_page(self.notebook, @ptrCast(surface.gl_area)) orelse return; const page = c.gtk_notebook_get_page(self.notebook, @ptrCast(surface.gl_area)) orelse return;
@ -526,7 +531,7 @@ fn gtkActionClose(
) callconv(.C) void { ) callconv(.C) void {
const self: *Window = @ptrCast(@alignCast(ud orelse return)); const self: *Window = @ptrCast(@alignCast(ud orelse return));
const surface = self.actionSurface() orelse return; const surface = self.actionSurface() orelse return;
surface.performBindingAction(.{ .close_surface = {} }) catch |err| { _ = surface.performBindingAction(.{ .close_surface = {} }) catch |err| {
log.warn("error performing binding action error={}", .{err}); log.warn("error performing binding action error={}", .{err});
return; return;
}; };
@ -539,7 +544,7 @@ fn gtkActionNewWindow(
) callconv(.C) void { ) callconv(.C) void {
const self: *Window = @ptrCast(@alignCast(ud orelse return)); const self: *Window = @ptrCast(@alignCast(ud orelse return));
const surface = self.actionSurface() orelse return; const surface = self.actionSurface() orelse return;
surface.performBindingAction(.{ .new_window = {} }) catch |err| { _ = surface.performBindingAction(.{ .new_window = {} }) catch |err| {
log.warn("error performing binding action error={}", .{err}); log.warn("error performing binding action error={}", .{err});
return; return;
}; };
@ -552,7 +557,7 @@ fn gtkActionNewTab(
) callconv(.C) void { ) callconv(.C) void {
const self: *Window = @ptrCast(@alignCast(ud orelse return)); const self: *Window = @ptrCast(@alignCast(ud orelse return));
const surface = self.actionSurface() orelse return; const surface = self.actionSurface() orelse return;
surface.performBindingAction(.{ .new_tab = {} }) catch |err| { _ = surface.performBindingAction(.{ .new_tab = {} }) catch |err| {
log.warn("error performing binding action error={}", .{err}); log.warn("error performing binding action error={}", .{err});
return; return;
}; };

View File

@ -561,6 +561,16 @@ pub fn default(alloc_gpa: Allocator) Allocator.Error!Config {
.{ .key = .right, .mods = .{ .ctrl = true, .shift = true } }, .{ .key = .right, .mods = .{ .ctrl = true, .shift = true } },
.{ .next_tab = {} }, .{ .next_tab = {} },
); );
try result.keybind.set.put(
alloc,
.{ .key = .page_up, .mods = .{ .ctrl = true } },
.{ .previous_tab = {} },
);
try result.keybind.set.put(
alloc,
.{ .key = .page_down, .mods = .{ .ctrl = true } },
.{ .next_tab = {} },
);
try result.keybind.set.put( try result.keybind.set.put(
alloc, alloc,
.{ .key = .o, .mods = .{ .ctrl = true, .shift = true } }, .{ .key = .o, .mods = .{ .ctrl = true, .shift = true } },
@ -1537,6 +1547,8 @@ pub const Keybinds = struct {
return .{ return .{
.set = .{ .set = .{
.bindings = try self.set.bindings.clone(alloc), .bindings = try self.set.bindings.clone(alloc),
.reverse = try self.set.reverse.clone(alloc),
.unconsumed = try self.set.unconsumed.clone(alloc),
}, },
}; };
} }