diff --git a/src/apprt/gtk-ng/class/surface.zig b/src/apprt/gtk-ng/class/surface.zig index 631b93e42..701497d17 100644 --- a/src/apprt/gtk-ng/class/surface.zig +++ b/src/apprt/gtk-ng/class/surface.zig @@ -523,6 +523,22 @@ pub const Surface = extern struct { priv.gl_area.queueRender(); } + /// Callback used to determine whether border should be shown around the + /// surface. + fn closureShouldBorderBeShown( + _: *Self, + config_: ?*Config, + bell_ringing_: c_int, + ) callconv(.c) c_int { + const config = if (config_) |v| v.get() else { + log.warn("config unavailable for computing whether border should be shown , likely bug", .{}); + return @intFromBool(false); + }; + + const bell_ringing = bell_ringing_ != 0; + return @intFromBool(config.@"bell-features".border and bell_ringing); + } + pub fn toggleFullscreen(self: *Self) void { signals.@"toggle-fullscreen".impl.emit( self, @@ -2478,6 +2494,7 @@ pub const Surface = extern struct { class.bindTemplateCallback("notify_mouse_hidden", &propMouseHidden); class.bindTemplateCallback("notify_mouse_shape", &propMouseShape); class.bindTemplateCallback("notify_bell_ringing", &propBellRinging); + class.bindTemplateCallback("should_border_be_shown", &closureShouldBorderBeShown); // Properties gobject.ext.registerProperties(class, &.{ diff --git a/src/apprt/gtk-ng/css/style.css b/src/apprt/gtk-ng/css/style.css index a1a425f66..5901d1d7e 100644 --- a/src/apprt/gtk-ng/css/style.css +++ b/src/apprt/gtk-ng/css/style.css @@ -102,6 +102,12 @@ label.resize-overlay { /* background-color: color-mix(in srgb, var(--error-bg-color), transparent); */ } +.surface .bell-overlay { + border-color: color-mix(in srgb, var(--accent-color), transparent 50%); + border-width: 3px; + border-style: solid; +} + /* * Command Palette */ diff --git a/src/apprt/gtk-ng/ui/1.2/surface.blp b/src/apprt/gtk-ng/ui/1.2/surface.blp index 49aae0a04..b558fc322 100644 --- a/src/apprt/gtk-ng/ui/1.2/surface.blp +++ b/src/apprt/gtk-ng/ui/1.2/surface.blp @@ -54,6 +54,27 @@ template $GhosttySurface: Adw.Bin { valign: start; } + [overlay] + // The "border" bell feature is implemented here as an overlay rather than + // just adding a border to the GLArea or other widget for two reasons. + // First, adding a border to an existing widget causes a resize of the + // widget which undesirable side effects. Second, we can make it reactive + // here in the blueprint with relatively little code. + Revealer { + reveal-child: bind $should_border_be_shown(template.config, template.bell-ringing) as ; + transition-type: crossfade; + transition-duration: 500; + + Box bell_overlay { + styles [ + "bell-overlay", + ] + + halign: fill; + valign: fill; + } + } + [overlay] $GhosttySurfaceChildExited child_exited_overlay { visible: bind template.child-exited; diff --git a/src/config/Config.zig b/src/config/Config.zig index 2cf5a3e17..2f6643c7d 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -2433,7 +2433,12 @@ keybind: Keybinds = .{}, /// Prepend a bell emoji (🔔) to the title of the alerted surface until the /// terminal is re-focused or interacted with (such as on keyboard input). /// -/// Only implemented on macOS. +/// * `border` +/// +/// Display a border around the alerted surface until the terminal is +/// re-focused or interacted with (such as on keyboard input). +/// +/// GTK only. /// /// Example: `audio`, `no-audio`, `system`, `no-system` /// @@ -6988,6 +6993,7 @@ pub const BellFeatures = packed struct { audio: bool = false, attention: bool = true, title: bool = true, + border: bool = false, }; /// See mouse-shift-capture