mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-06-08 12:54:28 +00:00
gtk/x11: use BlurRegion
This commit is contained in:
@@ -19,6 +19,7 @@ pub const c = @cImport({
|
||||
const input = @import("../../../input.zig");
|
||||
const Config = @import("../../../config.zig").Config;
|
||||
const ApprtWindow = @import("../class/window.zig").Window;
|
||||
const BlurRegion = @import("BlurRegion.zig");
|
||||
|
||||
const log = std.log.scoped(.gtk_x11);
|
||||
|
||||
@@ -169,13 +170,13 @@ pub const Window = struct {
|
||||
app: *App,
|
||||
apprt_window: *ApprtWindow,
|
||||
x11_surface: *gdk_x11.X11Surface,
|
||||
alloc: Allocator,
|
||||
|
||||
blur_region: Region = .{},
|
||||
blur_region: BlurRegion = .empty,
|
||||
|
||||
// Cache last applied values to avoid redundant X11 property updates.
|
||||
// Redundant property updates seem to cause some visual glitches
|
||||
// with some window managers: https://github.com/ghostty-org/ghostty/pull/8075
|
||||
last_applied_blur_region: ?Region = null,
|
||||
last_applied_decoration_hints: ?MotifWMHints = null,
|
||||
|
||||
pub fn init(
|
||||
@@ -183,8 +184,6 @@ pub const Window = struct {
|
||||
app: *App,
|
||||
apprt_window: *ApprtWindow,
|
||||
) !Window {
|
||||
_ = alloc;
|
||||
|
||||
const surface = apprt_window.as(gtk.Native).getSurface() orelse
|
||||
return error.NotX11Surface;
|
||||
|
||||
@@ -195,6 +194,7 @@ pub const Window = struct {
|
||||
|
||||
return .{
|
||||
.app = app,
|
||||
.alloc = alloc,
|
||||
.apprt_window = apprt_window,
|
||||
.x11_surface = x11_surface,
|
||||
};
|
||||
@@ -213,26 +213,6 @@ pub const Window = struct {
|
||||
pub fn syncAppearance(self: *Window) !void {
|
||||
// The user could have toggled between CSDs and SSDs,
|
||||
// therefore we need to recalculate the blur region offset.
|
||||
self.blur_region = blur: {
|
||||
// NOTE(pluiedev): CSDs are a f--king mistake.
|
||||
// Please, GNOME, stop this nonsense of making a window ~30% bigger
|
||||
// internally than how they really are just for your shadows and
|
||||
// rounded corners and all that fluff. Please. I beg of you.
|
||||
var x: f64 = 0;
|
||||
var y: f64 = 0;
|
||||
|
||||
self.apprt_window.as(gtk.Native).getSurfaceTransform(&x, &y);
|
||||
|
||||
// Transform surface coordinates to device coordinates.
|
||||
const scale: f64 = @floatFromInt(self.apprt_window.as(gtk.Widget).getScaleFactor());
|
||||
x *= scale;
|
||||
y *= scale;
|
||||
|
||||
break :blur .{
|
||||
.x = @intFromFloat(x),
|
||||
.y = @intFromFloat(y),
|
||||
};
|
||||
};
|
||||
self.syncBlur() catch |err| {
|
||||
log.err("failed to synchronize blur={}", .{err});
|
||||
};
|
||||
@@ -249,36 +229,29 @@ pub const Window = struct {
|
||||
}
|
||||
|
||||
fn syncBlur(self: *Window) !void {
|
||||
// FIXME: This doesn't currently factor in rounded corners on Adwaita,
|
||||
// which means that the blur region will grow slightly outside of the
|
||||
// window borders. Unfortunately, actually calculating the rounded
|
||||
// region can be quite complex without having access to existing APIs
|
||||
// (cf. https://github.com/cutefishos/fishui/blob/41d4ba194063a3c7fff4675619b57e6ac0504f06/src/platforms/linux/blurhelper/windowblur.cpp#L134)
|
||||
// and I think it's not really noticeable enough to justify the effort.
|
||||
// (Wayland also has this visual artifact anyway...)
|
||||
|
||||
const gtk_widget = self.apprt_window.as(gtk.Widget);
|
||||
const config = if (self.apprt_window.getConfig()) |v| v.get() else return;
|
||||
|
||||
// When blur is disabled, remove the property if it was previously set
|
||||
const blur = config.@"background-blur";
|
||||
if (!blur.enabled()) {
|
||||
if (self.last_applied_blur_region != null) {
|
||||
try self.deleteProperty(self.app.atoms.kde_blur);
|
||||
self.last_applied_blur_region = null;
|
||||
}
|
||||
|
||||
self.blur_region.deinit(self.alloc);
|
||||
self.blur_region = .empty;
|
||||
try self.deleteProperty(self.app.atoms.kde_blur);
|
||||
return;
|
||||
}
|
||||
|
||||
// Transform surface coordinates to device coordinates.
|
||||
const scale = gtk_widget.getScaleFactor();
|
||||
self.blur_region.width = gtk_widget.getWidth() * scale;
|
||||
self.blur_region.height = gtk_widget.getHeight() * scale;
|
||||
var region: BlurRegion = try .calcForWindow(
|
||||
self.alloc,
|
||||
self.apprt_window,
|
||||
self.clientSideDecorationEnabled(),
|
||||
true,
|
||||
);
|
||||
errdefer region.deinit(self.alloc);
|
||||
|
||||
// Only update X11 properties when the blur region actually changes
|
||||
if (self.last_applied_blur_region) |last| {
|
||||
if (std.meta.eql(self.blur_region, last)) return;
|
||||
if (region.eql(self.blur_region)) {
|
||||
region.deinit(self.alloc);
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("set blur={}, window xid={}, region={}", .{
|
||||
@@ -288,14 +261,14 @@ pub const Window = struct {
|
||||
});
|
||||
|
||||
try self.changeProperty(
|
||||
Region,
|
||||
BlurRegion.Slice,
|
||||
self.app.atoms.kde_blur,
|
||||
c.XA_CARDINAL,
|
||||
._32,
|
||||
.{ .mode = .replace },
|
||||
&self.blur_region,
|
||||
self.blur_region.slices.items,
|
||||
);
|
||||
self.last_applied_blur_region = self.blur_region;
|
||||
self.blur_region = region;
|
||||
}
|
||||
|
||||
fn syncDecorations(self: *Window) !void {
|
||||
@@ -335,7 +308,7 @@ pub const Window = struct {
|
||||
self.app.atoms.motif_wm_hints,
|
||||
._32,
|
||||
.{ .mode = .replace },
|
||||
&hints,
|
||||
&.{hints},
|
||||
);
|
||||
self.last_applied_decoration_hints = hints;
|
||||
}
|
||||
@@ -410,9 +383,11 @@ pub const Window = struct {
|
||||
options: struct {
|
||||
mode: PropertyChangeMode,
|
||||
},
|
||||
value: *T,
|
||||
values: []const T,
|
||||
) X11Error!void {
|
||||
const data: format.bufferType() = @ptrCast(value);
|
||||
const data: format.bufferType() = @ptrCast(@constCast(values));
|
||||
// The number of "words" that each element `T` occupies.
|
||||
const words_per_elem = @divExact(@sizeOf(T), @sizeOf(format.elemType()));
|
||||
|
||||
const status = c.XChangeProperty(
|
||||
@ptrCast(@alignCast(self.app.display)),
|
||||
@@ -422,7 +397,7 @@ pub const Window = struct {
|
||||
@intFromEnum(format),
|
||||
@intFromEnum(options.mode),
|
||||
data,
|
||||
@divExact(@sizeOf(T), @sizeOf(format.elemType())),
|
||||
@intCast(words_per_elem * values.len),
|
||||
);
|
||||
|
||||
// For some godforsaken reason Xlib alternates between
|
||||
@@ -498,13 +473,6 @@ const PropertyFormat = enum(c_int) {
|
||||
}
|
||||
};
|
||||
|
||||
const Region = extern struct {
|
||||
x: c_long = 0,
|
||||
y: c_long = 0,
|
||||
width: c_long = 0,
|
||||
height: c_long = 0,
|
||||
};
|
||||
|
||||
// See Xm/MwmUtil.h, packaged with the Motif Window Manager
|
||||
const MotifWMHints = extern struct {
|
||||
flags: packed struct(c_ulong) {
|
||||
|
||||
Reference in New Issue
Block a user