gtk/wayland: replace KDE blur with ext-background-effect-v1
The venerable KDE blur protocol has been replaced with the compositor- agnostic ext-background-effect-v1 protocol, to be implemented by Niri and others. The new protocol is much easier to use overall, though we do need to calculate the blur region manually like X11.pull/10727/head
parent
d9070dbee2
commit
9e2e99c55f
|
|
@ -91,8 +91,8 @@
|
|||
.lazy = true,
|
||||
},
|
||||
.wayland_protocols = .{
|
||||
.url = "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz",
|
||||
.hash = "N-V-__8AAKw-DAAaV8bOAAGqA0-oD7o-HNIlPFYKRXSPT03S",
|
||||
.url = "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz",
|
||||
.hash = "N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA",
|
||||
.lazy = true,
|
||||
},
|
||||
.plasma_wayland_protocols = .{
|
||||
|
|
|
|||
|
|
@ -139,6 +139,11 @@
|
|||
"url": "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz",
|
||||
"hash": "sha256-XO3K3egbdeYPI+XoO13SuOtO+5+Peb16NH0UiusFMPg="
|
||||
},
|
||||
"N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA": {
|
||||
"name": "wayland_protocols",
|
||||
"url": "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz",
|
||||
"hash": "sha256-3S3xSrX0EDgleq7cxLX7msDuAY8/D5SvkJcCjmDTMiM="
|
||||
},
|
||||
"N-V-__8AAAzZywE3s51XfsLbP9eyEw57ae9swYB9aGB6fCMs": {
|
||||
"name": "wuffs",
|
||||
"url": "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz",
|
||||
|
|
|
|||
|
|
@ -306,6 +306,14 @@ in
|
|||
hash = "sha256-XO3K3egbdeYPI+XoO13SuOtO+5+Peb16NH0UiusFMPg=";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA";
|
||||
path = fetchZigArtifact {
|
||||
name = "wayland_protocols";
|
||||
url = "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz";
|
||||
hash = "sha256-3S3xSrX0EDgleq7cxLX7msDuAY8/D5SvkJcCjmDTMiM=";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "N-V-__8AAAzZywE3s51XfsLbP9eyEw57ae9swYB9aGB6fCMs";
|
||||
path = fetchZigArtifact {
|
||||
|
|
|
|||
|
|
@ -34,3 +34,4 @@ https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e
|
|||
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
|
||||
https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz
|
||||
https://github.com/ocornut/imgui/archive/refs/tags/v1.92.5-docking.tar.gz
|
||||
https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz
|
||||
|
|
|
|||
|
|
@ -167,6 +167,12 @@
|
|||
"dest": "vendor/p/N-V-__8AAKw-DAAaV8bOAAGqA0-oD7o-HNIlPFYKRXSPT03S",
|
||||
"sha256": "5cedcadde81b75e60f23e5e83b5dd2b8eb4efb9f8f79bd7a347d148aeb0530f8"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz",
|
||||
"dest": "vendor/p/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA",
|
||||
"sha256": "dd2df14ab5f41038257aaedcc4b5fb9ac0ee018f3f0f94af9097028e60d33223"
|
||||
},
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz",
|
||||
|
|
|
|||
|
|
@ -1071,21 +1071,6 @@ pub const Window = extern struct {
|
|||
self.syncAppearance();
|
||||
}
|
||||
|
||||
fn propGdkSurfaceHeight(
|
||||
_: *gdk.Surface,
|
||||
_: *gobject.ParamSpec,
|
||||
self: *Self,
|
||||
) callconv(.c) void {
|
||||
// X11 needs to fix blurring on resize, but winproto implementations
|
||||
// could do anything.
|
||||
self.private().winproto.resizeEvent() catch |err| {
|
||||
log.warn(
|
||||
"winproto resize event failed error={}",
|
||||
.{err},
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
fn propIsActive(
|
||||
_: *gtk.Window,
|
||||
_: *gobject.ParamSpec,
|
||||
|
|
@ -1111,7 +1096,7 @@ pub const Window = extern struct {
|
|||
};
|
||||
}
|
||||
|
||||
fn propGdkSurfaceWidth(
|
||||
fn propGdkSurfaceDims(
|
||||
_: *gdk.Surface,
|
||||
_: *gobject.ParamSpec,
|
||||
self: *Self,
|
||||
|
|
@ -1282,14 +1267,14 @@ pub const Window = extern struct {
|
|||
_ = gobject.Object.signals.notify.connect(
|
||||
gdk_surface,
|
||||
*Self,
|
||||
propGdkSurfaceWidth,
|
||||
propGdkSurfaceDims,
|
||||
self,
|
||||
.{ .detail = "width" },
|
||||
);
|
||||
_ = gobject.Object.signals.notify.connect(
|
||||
gdk_surface,
|
||||
*Self,
|
||||
propGdkSurfaceHeight,
|
||||
propGdkSurfaceDims,
|
||||
self,
|
||||
.{ .detail = "height" },
|
||||
);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ const layer_shell = @import("gtk4-layer-shell");
|
|||
|
||||
const wayland = @import("wayland");
|
||||
const wl = wayland.client.wl;
|
||||
const ext = wayland.client.ext;
|
||||
const kde = wayland.client.kde;
|
||||
const org = wayland.client.org;
|
||||
const xdg = wayland.client.xdg;
|
||||
|
|
@ -96,8 +97,8 @@ pub const Window = struct {
|
|||
/// The context from the app where we can load our Wayland interfaces.
|
||||
globals: *Globals,
|
||||
|
||||
/// A token that, when present, indicates that the window is blurred.
|
||||
blur_token: ?*org.KdeKwinBlur = null,
|
||||
/// Object that controls background effects like background blur.
|
||||
bg_effect: ?*ext.BackgroundEffectSurfaceV1 = null,
|
||||
|
||||
/// Object that controls the decoration mode (client/server/auto)
|
||||
/// of the window.
|
||||
|
|
@ -148,6 +149,20 @@ pub const Window = struct {
|
|||
break :deco deco;
|
||||
};
|
||||
|
||||
const bg_effect: ?*ext.BackgroundEffectSurfaceV1 = bg: {
|
||||
const mgr = app.globals.get(.ext_background_effect) orelse
|
||||
break :bg null;
|
||||
|
||||
const bg_effect: *ext.BackgroundEffectSurfaceV1 = mgr.getBackgroundEffect(
|
||||
wl_surface,
|
||||
) catch |err| {
|
||||
log.warn("could not create background effect object={}", .{err});
|
||||
break :bg null;
|
||||
};
|
||||
|
||||
break :bg bg_effect;
|
||||
};
|
||||
|
||||
if (apprt_window.isQuickTerminal()) {
|
||||
_ = gdk.Surface.signals.enter_monitor.connect(
|
||||
gdk_surface,
|
||||
|
|
@ -163,17 +178,22 @@ pub const Window = struct {
|
|||
.surface = wl_surface,
|
||||
.globals = app.globals,
|
||||
.decoration = deco,
|
||||
.bg_effect = bg_effect,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Window, alloc: Allocator) void {
|
||||
_ = alloc;
|
||||
if (self.blur_token) |blur| blur.release();
|
||||
if (self.bg_effect) |bg| bg.destroy();
|
||||
if (self.decoration) |deco| deco.release();
|
||||
if (self.slide) |slide| slide.release();
|
||||
}
|
||||
|
||||
pub fn resizeEvent(_: *Window) !void {}
|
||||
pub fn resizeEvent(self: *Window) !void {
|
||||
self.syncBlur() catch |err| {
|
||||
log.err("failed to sync blur={}", .{err});
|
||||
};
|
||||
}
|
||||
|
||||
pub fn syncAppearance(self: *Window) !void {
|
||||
self.syncBlur() catch |err| {
|
||||
|
|
@ -224,28 +244,53 @@ pub const Window = struct {
|
|||
|
||||
/// Update the blur state of the window.
|
||||
fn syncBlur(self: *Window) !void {
|
||||
const manager = self.globals.get(.kde_blur_manager) orelse return;
|
||||
const compositor = self.globals.get(.compositor) orelse return;
|
||||
const bg = self.bg_effect orelse return;
|
||||
if (!self.globals.state.bg_effect_capabilities.blur) return;
|
||||
|
||||
const config = if (self.apprt_window.getConfig()) |v|
|
||||
v.get()
|
||||
else
|
||||
return;
|
||||
const blur = config.@"background-blur";
|
||||
|
||||
if (self.blur_token) |tok| {
|
||||
// Only release token when transitioning from blurred -> not blurred
|
||||
if (!blur.enabled()) {
|
||||
manager.unset(self.surface);
|
||||
tok.release();
|
||||
self.blur_token = null;
|
||||
}
|
||||
} else {
|
||||
// Only acquire token when transitioning from not blurred -> blurred
|
||||
if (blur.enabled()) {
|
||||
const tok = try manager.create(self.surface);
|
||||
tok.commit();
|
||||
self.blur_token = tok;
|
||||
}
|
||||
}
|
||||
const region = region: {
|
||||
if (!blur.enabled()) break :region null;
|
||||
|
||||
// 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.
|
||||
|
||||
const native = self.apprt_window.as(gtk.Native);
|
||||
const surface = native.getSurface() orelse break :region null;
|
||||
const region = try compositor.createRegion();
|
||||
|
||||
var x: f64 = 0;
|
||||
var y: f64 = 0;
|
||||
native.getSurfaceTransform(&x, &y);
|
||||
// Slightly inset the blur region
|
||||
x += 1;
|
||||
y += 1;
|
||||
|
||||
var width: f64 = @floatFromInt(surface.getWidth());
|
||||
var height: f64 = @floatFromInt(surface.getHeight());
|
||||
width -= x * 2;
|
||||
height -= y * 2;
|
||||
if (width <= 0 or height <= 0) break :region null;
|
||||
|
||||
// FIXME: Add rounded corners
|
||||
region.add(
|
||||
@intFromFloat(x),
|
||||
@intFromFloat(y),
|
||||
@intFromFloat(width),
|
||||
@intFromFloat(height),
|
||||
);
|
||||
break :region region;
|
||||
};
|
||||
errdefer if (region) |r| r.destroy();
|
||||
|
||||
bg.setBlurRegion(region);
|
||||
}
|
||||
|
||||
fn syncDecoration(self: *Window) !void {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ const Allocator = std.mem.Allocator;
|
|||
|
||||
const wayland = @import("wayland");
|
||||
const wl = wayland.client.wl;
|
||||
const ext = wayland.client.ext;
|
||||
const kde = wayland.client.kde;
|
||||
const org = wayland.client.org;
|
||||
const xdg = wayland.client.xdg;
|
||||
|
|
@ -26,7 +27,8 @@ const Binding = struct {
|
|||
};
|
||||
|
||||
pub const Tag = enum {
|
||||
kde_blur_manager,
|
||||
compositor,
|
||||
ext_background_effect,
|
||||
kde_decoration_manager,
|
||||
kde_slide_manager,
|
||||
kde_output_order,
|
||||
|
|
@ -34,7 +36,8 @@ pub const Tag = enum {
|
|||
|
||||
fn Type(comptime self: Tag) type {
|
||||
return switch (self) {
|
||||
.kde_blur_manager => org.KdeKwinBlurManager,
|
||||
.compositor => wl.Compositor,
|
||||
.ext_background_effect => ext.BackgroundEffectManagerV1,
|
||||
.kde_decoration_manager => org.KdeKwinServerDecorationManager,
|
||||
.kde_slide_manager => org.KdeKwinSlideManager,
|
||||
.kde_output_order => kde.OutputOrderV1,
|
||||
|
|
@ -56,6 +59,8 @@ pub const State = struct {
|
|||
|
||||
default_deco_mode: ?org.KdeKwinServerDecorationManager.Mode = null,
|
||||
|
||||
bg_effect_capabilities: ext.BackgroundEffectManagerV1.Capability = .{},
|
||||
|
||||
/// Reset cached state derived from kde_output_order_v1.
|
||||
fn resetOutputOrder(self: *State, alloc: Allocator) void {
|
||||
if (self.primary_output_name) |name| alloc.free(name);
|
||||
|
|
@ -102,6 +107,11 @@ fn onGlobalAttached(self: *Globals, comptime tag: Tag) void {
|
|||
// keeps listener setup and object lifetime in one
|
||||
// place and also supports globals that appear later.
|
||||
switch (tag) {
|
||||
.ext_background_effect => {
|
||||
const v = self.get(tag) orelse return;
|
||||
v.setListener(*Globals, bgEffectListener, self);
|
||||
self.needs_roundtrip = true;
|
||||
},
|
||||
.kde_decoration_manager => {
|
||||
const v = self.get(tag) orelse return;
|
||||
v.setListener(*Globals, decoManagerListener, self);
|
||||
|
|
@ -179,6 +189,18 @@ fn registryListener(
|
|||
}
|
||||
}
|
||||
|
||||
fn bgEffectListener(
|
||||
_: *ext.BackgroundEffectManagerV1,
|
||||
event: ext.BackgroundEffectManagerV1.Event,
|
||||
self: *Globals,
|
||||
) void {
|
||||
switch (event) {
|
||||
.capabilities => |cap| {
|
||||
self.state.bg_effect_capabilities = cap.flags;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn decoManagerListener(
|
||||
_: *org.KdeKwinServerDecorationManager,
|
||||
event: org.KdeKwinServerDecorationManager.Event,
|
||||
|
|
|
|||
|
|
@ -626,9 +626,6 @@ fn addGtkNg(
|
|||
.wayland_protocols = wayland_protocols_dep.path(""),
|
||||
});
|
||||
|
||||
scanner.addCustomProtocol(
|
||||
plasma_wayland_protocols_dep.path("src/protocols/blur.xml"),
|
||||
);
|
||||
// FIXME: replace with `zxdg_decoration_v1` once GTK merges https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/6398
|
||||
scanner.addCustomProtocol(
|
||||
plasma_wayland_protocols_dep.path("src/protocols/server-decoration.xml"),
|
||||
|
|
@ -640,13 +637,14 @@ fn addGtkNg(
|
|||
plasma_wayland_protocols_dep.path("src/protocols/kde-output-order-v1.xml"),
|
||||
);
|
||||
scanner.addSystemProtocol("staging/xdg-activation/xdg-activation-v1.xml");
|
||||
scanner.addSystemProtocol("staging/ext-background-effect/ext-background-effect-v1.xml");
|
||||
|
||||
scanner.generate("wl_compositor", 1);
|
||||
scanner.generate("org_kde_kwin_blur_manager", 1);
|
||||
scanner.generate("org_kde_kwin_server_decoration_manager", 1);
|
||||
scanner.generate("org_kde_kwin_slide_manager", 1);
|
||||
scanner.generate("kde_output_order_v1", 1);
|
||||
scanner.generate("xdg_activation_v1", 1);
|
||||
scanner.generate("ext_background_effect_manager_v1", 1);
|
||||
|
||||
step.root_module.addImport("wayland", b.createModule(.{
|
||||
.root_source_file = scanner.result,
|
||||
|
|
|
|||
Loading…
Reference in New Issue