apprt/gtk-ng: tab attention for bell

This commit is contained in:
Mitchell Hashimoto
2025-08-13 08:55:24 -07:00
parent 156278e6c1
commit f9896c8ef7
2 changed files with 73 additions and 1 deletions

View File

@@ -275,7 +275,8 @@ pub const Surface = extern struct {
/// The surface view handles the audio bell feature but none of the /// 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. /// others so it is up to the embedding widget to react to this.
/// ///
/// Bell ringing will also emit the win.ring-bell action. /// Bell ringing will also emit the tab.ring-bell and win.ring-bell
/// actions.
pub const bell = struct { pub const bell = struct {
pub const name = "bell"; pub const name = "bell";
pub const connect = impl.connect; pub const connect = impl.connect;
@@ -557,6 +558,7 @@ pub const Surface = extern struct {
); );
// Activate a window action if it exists // Activate a window action if it exists
_ = self.as(gtk.Widget).activateAction("tab.ring-bell", null);
_ = self.as(gtk.Widget).activateAction("win.ring-bell", null); _ = self.as(gtk.Widget).activateAction("win.ring-bell", null);
} }

View File

@@ -11,6 +11,7 @@ const i18n = @import("../../../os/main.zig").i18n;
const apprt = @import("../../../apprt.zig"); const apprt = @import("../../../apprt.zig");
const input = @import("../../../input.zig"); const input = @import("../../../input.zig");
const CoreSurface = @import("../../../Surface.zig"); const CoreSurface = @import("../../../Surface.zig");
const ext = @import("../ext.zig");
const gtk_version = @import("../gtk_version.zig"); const gtk_version = @import("../gtk_version.zig");
const adw_version = @import("../adw_version.zig"); const adw_version = @import("../adw_version.zig");
const gresource = @import("../build/gresource.zig"); const gresource = @import("../build/gresource.zig");
@@ -175,6 +176,9 @@ pub const Tab = extern struct {
fn init(self: *Self, _: *Class) callconv(.c) void { fn init(self: *Self, _: *Class) callconv(.c) void {
gtk.Widget.initTemplate(self.as(gtk.Widget)); gtk.Widget.initTemplate(self.as(gtk.Widget));
// Init our actions
self.initActions();
// If our configuration is null then we get the configuration // If our configuration is null then we get the configuration
// from the application. // from the application.
const priv = self.private(); const priv = self.private();
@@ -194,6 +198,46 @@ pub const Tab = extern struct {
}; };
} }
/// Setup our action map.
fn initActions(self: *Self) void {
// The set of actions. Each action has (in order):
// [0] The action name
// [1] The callback function
// [2] The glib.VariantType of the parameter
//
// For action names:
// https://docs.gtk.org/gio/type_func.Action.name_is_valid.html
const actions = .{
.{ "ring-bell", actionRingBell, null },
};
// We need to collect our actions into a group since we're just
// a plain widget that doesn't implement ActionGroup directly.
const group = gio.SimpleActionGroup.new();
errdefer group.unref();
const map = group.as(gio.ActionMap);
inline for (actions) |entry| {
const action = gio.SimpleAction.new(
entry[0],
entry[2],
);
defer action.unref();
_ = gio.SimpleAction.signals.activate.connect(
action,
*Self,
entry[1],
self,
.{},
);
map.addAction(action.as(gio.Action));
}
self.as(gtk.Widget).insertActionGroup(
"tab",
group.as(gio.ActionGroup),
);
}
//--------------------------------------------------------------- //---------------------------------------------------------------
// Properties // Properties
@@ -223,6 +267,15 @@ pub const Tab = extern struct {
return core_surface.needsConfirmQuit(); return core_surface.needsConfirmQuit();
} }
/// Get the tab page holding this tab, if any.
fn getTabPage(self: *Self) ?*adw.TabPage {
const tab_view = ext.getAncestor(
adw.TabView,
self.as(gtk.Widget),
) orelse return null;
return tab_view.getPage(self.as(gtk.Widget));
}
//--------------------------------------------------------------- //---------------------------------------------------------------
// Virtual methods // Virtual methods
@@ -291,6 +344,23 @@ pub const Tab = extern struct {
self.as(gobject.Object).notifyByPspec(properties.@"active-surface".impl.param_spec); self.as(gobject.Object).notifyByPspec(properties.@"active-surface".impl.param_spec);
} }
fn actionRingBell(
_: *gio.SimpleAction,
_: ?*glib.Variant,
self: *Self,
) callconv(.c) void {
// Future note: I actually don't like this logic living here at all.
// I think a better approach will be for the ring bell action to
// specify its sending surface and then do all this in the window.
// If the page is selected already we don't mark it as needing
// attention. We only want to mark unfocused pages. This will then
// clear when the page is selected.
const page = self.getTabPage() orelse return;
if (page.getSelected() != 0) return;
page.setNeedsAttention(@intFromBool(true));
}
fn closureComputedTitle( fn closureComputedTitle(
_: *Self, _: *Self,
config_: ?*Config, config_: ?*Config,