diff --git a/src/apprt/gtk-ng/class/surface.zig b/src/apprt/gtk-ng/class/surface.zig index 93afaf776..962b01b18 100644 --- a/src/apprt/gtk-ng/class/surface.zig +++ b/src/apprt/gtk-ng/class/surface.zig @@ -274,6 +274,8 @@ pub const Surface = extern struct { /// /// The surface view handles the audio bell feature but none of the /// others so it is up to the embedding widget to react to this. + /// + /// Bell ringing will also emit the win.ring-bell action. pub const bell = struct { pub const name = "bell"; pub const connect = impl.connect; @@ -546,12 +548,16 @@ pub const Surface = extern struct { // Enable our bell ringing state self.setBellRinging(true); + // Emit our direct signal for anyone who cares signals.bell.impl.emit( self, null, .{}, null, ); + + // Activate a window action if it exists + _ = self.as(gtk.Widget).activateAction("win.ring-bell", null); } pub fn toggleFullscreen(self: *Self) void { diff --git a/src/apprt/gtk-ng/class/window.zig b/src/apprt/gtk-ng/class/window.zig index 447fb0a40..a480ed217 100644 --- a/src/apprt/gtk-ng/class/window.zig +++ b/src/apprt/gtk-ng/class/window.zig @@ -336,6 +336,7 @@ pub const Window = extern struct { .{ "close-tab", actionCloseTab, null }, .{ "new-tab", actionNewTab, null }, .{ "new-window", actionNewWindow, null }, + .{ "ring-bell", actionRingBell, null }, .{ "split-right", actionSplitRight, null }, .{ "split-left", actionSplitLeft, null }, .{ "split-up", actionSplitUp, null }, @@ -1317,6 +1318,10 @@ pub const Window = extern struct { // Setup our binding group. This ensures things like the title // are synced from the active tab. priv.tab_bindings.setSource(child.as(gobject.Object)); + + // If the tab was previously marked as needing attention + // (e.g. due to a bell character), we now unmark that + page.setNeedsAttention(@intFromBool(false)); } fn tabViewPageAttached( @@ -1729,6 +1734,30 @@ pub const Window = extern struct { self.performBindingAction(.clear_screen); } + fn actionRingBell( + _: *gio.SimpleAction, + _: ?*glib.Variant, + self: *Window, + ) callconv(.c) void { + const priv = self.private(); + const config = if (priv.config) |v| v.get() else return; + + if (config.@"bell-features".system) system: { + const native = self.as(gtk.Native).getSurface() orelse { + log.warn("unable to get native surface from window", .{}); + break :system; + }; + native.beep(); + } + + if (config.@"bell-features".attention) { + // Request user attention + self.winproto().setUrgent(true) catch |err| { + log.warn("failed to request user attention={}", .{err}); + }; + } + } + /// Toggle the command palette. /// /// TODO: accept the surface that toggled the command palette as a parameter