gtk: use native blur on GTK 4.23.3+ (#13586)

Finally, what was previously thought impossible, is now possible.
The blur region itself is far more accurate than what we can conjure up
on our own, and in a much more finetuned and detailed way too.
Thank you, GTK devs!

Closes #13581
This commit is contained in:
Mitchell Hashimoto
2026-08-03 20:55:14 -07:00
committed by GitHub
2 changed files with 61 additions and 0 deletions

View File

@@ -37,6 +37,7 @@ const InspectorWindow = @import("inspector_window.zig").InspectorWindow;
const i18n = @import("../../../os/i18n.zig");
const media = @import("../media.zig");
const global = @import("../../../global.zig");
const gtk_version = @import("../gtk_version.zig");
const log = std.log.scoped(.gtk_ghostty_surface);
@@ -1991,6 +1992,58 @@ pub const Surface = extern struct {
);
}
fn snapshot(self: *Self, snap: *gtk.Snapshot) callconv(.c) void {
const priv = self.private();
const blur = blur: {
// Native GTK blur is only available since GTK 4.23.3
if (gtk_version.runtimeUntil(4, 23, 3)) break :blur null;
const config = priv.config orelse break :blur null;
break :blur switch (config.get().@"background-blur") {
.radius => |v| @as(f32, v),
.true, .@"macos-glass-regular", .@"macos-glass-clear" => 20.0,
.false => null,
};
};
if (blur) |b| blur: {
// pushCopy and appendPaste are only supported since 4.22.
// These two functions are crucial for the blur function
// and it cannot be implemented otherwise, so if you compile
// Ghostty on an older GTK version, you won't get blur.
// Sorry.
if (comptime !gtk_version.atLeast(4, 22, 0)) break :blur;
const width = self.as(gtk.Widget).getWidth();
const height = self.as(gtk.Widget).getHeight();
// Push the current render state (background)
// to be appended below
snap.pushCopy();
defer snap.pop();
// Apply blur to the copied background
snap.pushBlur(b);
defer snap.pop();
snap.appendPaste(&.{
.f_origin = .{ .f_x = 0, .f_y = 0 },
.f_size = .{
.f_width = @floatFromInt(width),
.f_height = @floatFromInt(height),
},
}, 0);
}
// Draw the children normally
gtk.Widget.virtual_methods.snapshot.call(
Class.parent,
self.as(Parent),
snap,
);
}
//---------------------------------------------------------------
// Properties
@@ -3737,6 +3790,7 @@ pub const Surface = extern struct {
// Virtual methods
gobject.Object.virtual_methods.dispose.implement(class, &dispose);
gobject.Object.virtual_methods.finalize.implement(class, &finalize);
gtk.Widget.virtual_methods.snapshot.implement(class, &snapshot);
}
pub const as = C.Class.as;

View File

@@ -22,6 +22,7 @@ const input = @import("../../../input.zig");
const ApprtWindow = @import("../class/window.zig").Window;
const GlobalShortcuts = @import("../class/global_shortcuts.zig").GlobalShortcuts;
const BlurRegion = @import("BlurRegion.zig");
const gtk_version = @import("../gtk_version.zig");
const log = std.log.scoped(.winproto_wayland);
@@ -174,6 +175,12 @@ pub const Window = struct {
};
const bg_effect: ?*ext.BackgroundEffectSurfaceV1 = bg: {
if (gtk_version.runtimeAtLeast(4, 23, 3)) {
// GTK 4.23.3 added an official way to do background blur,
// so we don't need to do anything on our own.
break :bg null;
}
const mgr = app.globals.get(.ext_background_effect) orelse
break :bg null;