apprt/gtk-ng: action accelerators, clean up explicit error sets

pull/8146/head
Mitchell Hashimoto 2025-08-04 12:31:51 -07:00
parent 84cb4ce31a
commit 55c68d809d
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
3 changed files with 85 additions and 6 deletions

View File

@ -15,6 +15,7 @@ const apprt = @import("../../../apprt.zig");
const cgroup = @import("../cgroup.zig");
const CoreApp = @import("../../../App.zig");
const configpkg = @import("../../../config.zig");
const input = @import("../../../input.zig");
const internal_os = @import("../../../os/main.zig");
const systemd = @import("../../../os/systemd.zig");
const terminal = @import("../../../terminal/main.zig");
@ -24,6 +25,7 @@ const CoreConfig = configpkg.Config;
const CoreSurface = @import("../../../Surface.zig");
const ext = @import("../ext.zig");
const key = @import("../key.zig");
const adw_version = @import("../adw_version.zig");
const gtk_version = @import("../gtk_version.zig");
const winprotopkg = @import("../winproto.zig");
@ -861,6 +863,61 @@ pub const Application = extern struct {
}
}
fn syncActionAccelerators(self: *Self) void {
self.syncActionAccelerator("app.quit", .{ .quit = {} });
self.syncActionAccelerator("app.open-config", .{ .open_config = {} });
self.syncActionAccelerator("app.reload-config", .{ .reload_config = {} });
self.syncActionAccelerator("win.toggle-inspector", .{ .inspector = .toggle });
self.syncActionAccelerator("app.show-gtk-inspector", .show_gtk_inspector);
self.syncActionAccelerator("win.toggle-command-palette", .toggle_command_palette);
self.syncActionAccelerator("win.close", .{ .close_window = {} });
self.syncActionAccelerator("win.new-window", .{ .new_window = {} });
self.syncActionAccelerator("win.new-tab", .{ .new_tab = {} });
self.syncActionAccelerator("win.close-tab", .{ .close_tab = {} });
self.syncActionAccelerator("win.split-right", .{ .new_split = .right });
self.syncActionAccelerator("win.split-down", .{ .new_split = .down });
self.syncActionAccelerator("win.split-left", .{ .new_split = .left });
self.syncActionAccelerator("win.split-up", .{ .new_split = .up });
self.syncActionAccelerator("win.copy", .{ .copy_to_clipboard = {} });
self.syncActionAccelerator("win.paste", .{ .paste_from_clipboard = {} });
self.syncActionAccelerator("win.reset", .{ .reset = {} });
self.syncActionAccelerator("win.clear", .{ .clear_screen = {} });
self.syncActionAccelerator("win.prompt-title", .{ .prompt_surface_title = {} });
}
fn syncActionAccelerator(
self: *Self,
gtk_action: [:0]const u8,
action: input.Binding.Action,
) void {
const gtk_app = self.as(gtk.Application);
// Reset it initially
const zero = [_:null]?[*:0]const u8{};
gtk_app.setAccelsForAction(gtk_action, &zero);
const config = self.private().config.get();
const trigger = config.keybind.set.getTrigger(action) orelse return;
var buf: [1024]u8 = undefined;
const accel = if (key.accelFromTrigger(
&buf,
trigger,
)) |accel_|
accel_ orelse return
else |err| switch (err) {
// This should really never, never happen. Its not critical enough
// to actually crash, but this is a bug somewhere. An accelerator
// for a trigger can't possibly be more than 1024 bytes.
error.NoSpaceLeft => {
log.warn("accelerator somehow longer than 1024 bytes: {}", .{trigger});
return;
},
};
const accels = [_:null]?[*:0]const u8{accel};
gtk_app.setAccelsForAction(gtk_action, &accels);
}
//---------------------------------------------------------------
// Properties
@ -891,6 +948,9 @@ pub const Application = extern struct {
_: *gobject.ParamSpec,
self: *Self,
) callconv(.c) void {
// Sync our accelerators for menu items.
self.syncActionAccelerators();
// Load our runtime and custom CSS. If this fails then our window is
// just stuck with the old CSS but we don't want to fail the entire
// config change operation.

View File

@ -152,7 +152,7 @@ pub const GlobalShortcuts = extern struct {
}
}
fn refresh(self: *Self) !void {
fn refresh(self: *Self) Allocator.Error!void {
// Always close our previous state first.
self.close();
@ -173,7 +173,7 @@ pub const GlobalShortcuts = extern struct {
errdefer priv.map = .{};
// Update map
var trigger_buf: [256]u8 = undefined;
var trigger_buf: [1024]u8 = undefined;
var it = config.keybind.set.bindings.iterator();
while (it.next()) |entry| {
const leaf = switch (entry.value_ptr.*) {
@ -183,10 +183,23 @@ pub const GlobalShortcuts = extern struct {
};
if (!leaf.flags.global) continue;
const trigger = try key.xdgShortcutFromTrigger(
const trigger = if (key.xdgShortcutFromTrigger(
&trigger_buf,
entry.key_ptr.*,
) orelse continue;
)) |shortcut_|
shortcut_ orelse continue
else |err| switch (err) {
// If there isn't space to translate the trigger, then our
// buffer might be too small (but 1024 is insane!). In any case
// we don't want to stop registering globals.
error.NoSpaceLeft => {
log.warn(
"buffer too small to translate trigger, ignoring={}",
.{entry.key_ptr.*},
);
continue;
},
};
try priv.map.put(
alloc,

View File

@ -9,7 +9,10 @@ const input = @import("../../input.zig");
const winproto = @import("winproto.zig");
/// Returns a GTK accelerator string from a trigger.
pub fn accelFromTrigger(buf: []u8, trigger: input.Binding.Trigger) !?[:0]const u8 {
pub fn accelFromTrigger(
buf: []u8,
trigger: input.Binding.Trigger,
) error{NoSpaceLeft}!?[:0]const u8 {
var buf_stream = std.io.fixedBufferStream(buf);
const writer = buf_stream.writer();
@ -30,7 +33,10 @@ pub fn accelFromTrigger(buf: []u8, trigger: input.Binding.Trigger) !?[:0]const u
/// Returns a XDG-compliant shortcuts string from a trigger.
/// Spec: https://specifications.freedesktop.org/shortcuts-spec/latest/
pub fn xdgShortcutFromTrigger(buf: []u8, trigger: input.Binding.Trigger) !?[:0]const u8 {
pub fn xdgShortcutFromTrigger(
buf: []u8,
trigger: input.Binding.Trigger,
) error{NoSpaceLeft}!?[:0]const u8 {
var buf_stream = std.io.fixedBufferStream(buf);
const writer = buf_stream.writer();