mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
gtk(wayland): add support for background blur on KDE Plasma
This commit is contained in:

committed by
Mitchell Hashimoto

parent
31439f311d
commit
9184395cba
@ -1479,7 +1479,14 @@ fn addDeps(
|
|||||||
|
|
||||||
const wayland = b.createModule(.{ .root_source_file = scanner.result });
|
const wayland = b.createModule(.{ .root_source_file = scanner.result });
|
||||||
|
|
||||||
|
const plasma_wayland_protocols = b.dependency("plasma_wayland_protocols", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
scanner.addCustomProtocol(plasma_wayland_protocols.path("src/protocols/blur.xml"));
|
||||||
|
|
||||||
scanner.generate("wl_compositor", 1);
|
scanner.generate("wl_compositor", 1);
|
||||||
|
scanner.generate("org_kde_kwin_blur_manager", 1);
|
||||||
|
|
||||||
step.root_module.addImport("wayland", wayland);
|
step.root_module.addImport("wayland", wayland);
|
||||||
step.linkSystemLibrary2("wayland-client", dynamic_link_opts);
|
step.linkSystemLibrary2("wayland-client", dynamic_link_opts);
|
||||||
|
@ -847,9 +847,11 @@ fn configChange(
|
|||||||
new_config: *const Config,
|
new_config: *const Config,
|
||||||
) void {
|
) void {
|
||||||
switch (target) {
|
switch (target) {
|
||||||
// We don't do anything for surface config change events. There
|
.surface => |surface| {
|
||||||
// is nothing to sync with regards to a surface today.
|
if (surface.rt_surface.container.window()) |window| window.syncAppearance(new_config) catch |err| {
|
||||||
.surface => {},
|
log.warn("error syncing appearance changes to window err={}", .{err});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
.app => {
|
.app => {
|
||||||
// We clone (to take ownership) and update our configuration.
|
// We clone (to take ownership) and update our configuration.
|
||||||
|
@ -392,6 +392,17 @@ pub fn init(self: *Window, app: *App) !void {
|
|||||||
c.gtk_widget_show(window);
|
c.gtk_widget_show(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates appearance based on config settings. Will be called once upon window
|
||||||
|
/// realization, and every time the config is reloaded.
|
||||||
|
///
|
||||||
|
/// TODO: Many of the initial style settings in `create` could possibly be made
|
||||||
|
/// reactive by moving them here.
|
||||||
|
pub fn syncAppearance(self: *Window, config: *const configpkg.Config) !void {
|
||||||
|
if (self.wayland) |*wl| {
|
||||||
|
try wl.setBlur(config.@"background-blur-radius" > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets up the GTK actions for the window scope. Actions are how GTK handles
|
/// Sets up the GTK actions for the window scope. Actions are how GTK handles
|
||||||
/// menus and such. The menu is defined in App.zig but the action is defined
|
/// menus and such. The menu is defined in App.zig but the action is defined
|
||||||
/// here. The string name binds them.
|
/// here. The string name binds them.
|
||||||
@ -565,6 +576,10 @@ fn gtkRealize(v: *c.GtkWindow, ud: ?*anyopaque) callconv(.C) bool {
|
|||||||
self.wayland = wayland.SurfaceState.init(v, wl);
|
self.wayland = wayland.SurfaceState.init(v, wl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.syncAppearance(&self.app.config) catch |err| {
|
||||||
|
log.err("failed to initialize appearance={}", .{err});
|
||||||
|
};
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ const std = @import("std");
|
|||||||
const c = @import("c.zig").c;
|
const c = @import("c.zig").c;
|
||||||
const wayland = @import("wayland");
|
const wayland = @import("wayland");
|
||||||
const wl = wayland.client.wl;
|
const wl = wayland.client.wl;
|
||||||
|
const org = wayland.client.org;
|
||||||
const build_options = @import("build_options");
|
const build_options = @import("build_options");
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk_wayland);
|
const log = std.log.scoped(.gtk_wayland);
|
||||||
@ -9,6 +10,7 @@ const log = std.log.scoped(.gtk_wayland);
|
|||||||
/// Wayland state that contains application-wide Wayland objects (e.g. wl_display).
|
/// Wayland state that contains application-wide Wayland objects (e.g. wl_display).
|
||||||
pub const AppState = struct {
|
pub const AppState = struct {
|
||||||
display: *wl.Display,
|
display: *wl.Display,
|
||||||
|
blur_manager: ?*org.KdeKwinBlurManager = null,
|
||||||
|
|
||||||
pub fn init(display: ?*c.GdkDisplay) ?AppState {
|
pub fn init(display: ?*c.GdkDisplay) ?AppState {
|
||||||
if (comptime !build_options.wayland) return null;
|
if (comptime !build_options.wayland) return null;
|
||||||
@ -45,6 +47,9 @@ pub const SurfaceState = struct {
|
|||||||
app_state: *AppState,
|
app_state: *AppState,
|
||||||
surface: *wl.Surface,
|
surface: *wl.Surface,
|
||||||
|
|
||||||
|
/// A token that, when present, indicates that the window is blurred.
|
||||||
|
blur_token: ?*org.KdeKwinBlur = null,
|
||||||
|
|
||||||
pub fn init(window: *c.GtkWindow, app_state: *AppState) ?SurfaceState {
|
pub fn init(window: *c.GtkWindow, app_state: *AppState) ?SurfaceState {
|
||||||
if (comptime !build_options.wayland) return null;
|
if (comptime !build_options.wayland) return null;
|
||||||
|
|
||||||
@ -66,6 +71,32 @@ pub const SurfaceState = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *SurfaceState) void {
|
pub fn deinit(self: *SurfaceState) void {
|
||||||
|
if (self.blur_token) |blur| blur.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setBlur(self: *SurfaceState, blurred: bool) !void {
|
||||||
|
log.debug("setting blur={}", .{blurred});
|
||||||
|
|
||||||
|
const mgr = self.app_state.blur_manager orelse {
|
||||||
|
log.warn("can't set blur: org_kde_kwin_blur_manager protocol unavailable", .{});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (self.blur_token) |blur| {
|
||||||
|
// Only release token when transitioning from blurred -> not blurred
|
||||||
|
if (!blurred) {
|
||||||
|
mgr.unset(self.surface);
|
||||||
|
blur.release();
|
||||||
|
self.blur_token = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Only acquire token when transitioning from not blurred -> blurred
|
||||||
|
if (blurred) {
|
||||||
|
const blur_token = try mgr.create(self.surface);
|
||||||
|
blur_token.commit();
|
||||||
|
self.blur_token = blur_token;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,6 +104,10 @@ fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, state: *Ap
|
|||||||
switch (event) {
|
switch (event) {
|
||||||
.global => |global| {
|
.global => |global| {
|
||||||
log.debug("got global interface={s}", .{global.interface});
|
log.debug("got global interface={s}", .{global.interface});
|
||||||
|
if (bindInterface(org.KdeKwinBlurManager, registry, global, 1)) |iface| {
|
||||||
|
state.blur_manager = iface;
|
||||||
|
return;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.global_remove => {},
|
.global_remove => {},
|
||||||
}
|
}
|
||||||
|
@ -583,11 +583,27 @@ palette: Palette = .{},
|
|||||||
@"background-opacity": f64 = 1.0,
|
@"background-opacity": f64 = 1.0,
|
||||||
|
|
||||||
/// A positive value enables blurring of the background when background-opacity
|
/// A positive value enables blurring of the background when background-opacity
|
||||||
/// is less than 1. The value is the blur radius to apply. A value of 20
|
/// is less than 1.
|
||||||
|
///
|
||||||
|
/// On macOS, the value is the blur radius to apply. A value of 20
|
||||||
/// is reasonable for a good looking blur. Higher values will cause strange
|
/// is reasonable for a good looking blur. Higher values will cause strange
|
||||||
/// rendering issues as well as performance issues.
|
/// rendering issues as well as performance issues.
|
||||||
///
|
///
|
||||||
/// This is only supported on macOS.
|
/// On KDE Plasma under Wayland, the exact value is _ignored_ — the reason is
|
||||||
|
/// that KWin, the window compositor powering Plasma, only has one global blur
|
||||||
|
/// setting and does not allow applications to have individual blur settings.
|
||||||
|
///
|
||||||
|
/// To configure KWin's global blur setting, open System Settings and go to
|
||||||
|
/// "Apps & Windows" > "Window Management" > "Desktop Effects" and select the
|
||||||
|
/// "Blur" plugin. If disabled, enable it by ticking the checkbox to the left.
|
||||||
|
/// Then click on the "Configure" button and there will be two sliders that
|
||||||
|
/// allow you to set background blur and noise strengths for all apps,
|
||||||
|
/// including Ghostty.
|
||||||
|
///
|
||||||
|
/// All other Linux desktop environments are as of now unsupported. Users may
|
||||||
|
/// need to set environment-specific settings and/or install third-party plugins
|
||||||
|
/// in order to support background blur, as there isn't a unified interface for
|
||||||
|
/// doing so.
|
||||||
@"background-blur-radius": u8 = 0,
|
@"background-blur-radius": u8 = 0,
|
||||||
|
|
||||||
/// The opacity level (opposite of transparency) of an unfocused split.
|
/// The opacity level (opposite of transparency) of an unfocused split.
|
||||||
|
Reference in New Issue
Block a user