Skip to content

Commit 3a7d33f

Browse files
committed
feat: add compositor-level background blur via ext-background-effect-v1
- Add protocol XML + VAPI + scanner rules for ext-background-effect-v1 - Add BackgroundEffectHelper for registry binding, effect lifecycle, and rounded-rectangle region math - Add "background-blur" config key (bool, default false) - Wire blur into ControlCenter and NotificationWindow size allocations - Add get_blur_bounds() / get_blur_radius() helpers to Notification
1 parent 1043ef9 commit 3a7d33f

14 files changed

Lines changed: 847 additions & 14 deletions

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,31 @@ The main config file is located in `/etc/xdg/swaync/config.json`. Copy it over
301301
to your `.config/swaync/` folder to customize without needing root access.
302302
See `swaync(5)` man page for more information
303303
304+
### Background Blur
305+
306+
SwayNotificationCenter can blur the background behind the control center and
307+
notification popups using the `ext-background-effect-v1` Wayland protocol.
308+
This requires compositor support (e.g. niri, KDE Plasma 6.3+).
309+
310+
To enable it, set `"background-blur": true` in your `config.json` and make sure
311+
the CSS backgrounds have some transparency so the blur is visible. For example:
312+
313+
```css
314+
.control-center {
315+
background: rgba(30, 30, 30, 0.5);
316+
}
317+
.floating-notifications .notification {
318+
background: rgba(28, 28, 30, 0.45);
319+
}
320+
```
321+
322+
The blur region shape derives its `border-radius` automatically by reading the
323+
`--border-radius` CSS variable. If your custom style overrides the border radius
324+
via a variable (e.g. `--border-radius: 14px`), the blur corners will match. If
325+
you set `border-radius` directly on a class without an accompanying
326+
`--border-radius` variable, the blur region will be rectangular (no rounding).
327+
No separate configuration is needed for corner rounding.
328+
304329
To reload the config, you'll need to run `swaync-client --reload-config`
305330

306331
The main CSS style file is located in `/etc/xdg/swaync/style.css`. Copy it over
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
wayland-client
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
namespace Ext.BackgroundEffect {
2+
[CCode (cheader_filename = "ext-background-effect-v1-client-protocol.h", cname = "struct ext_background_effect_manager_v1", cprefix = "ext_background_effect_manager_v1_")]
3+
public class Manager : Wl.Proxy {
4+
[CCode (cheader_filename = "ext-background-effect-v1-client-protocol.h", cname = "ext_background_effect_manager_v1_interface")]
5+
public static Wl.Interface iface;
6+
public void set_user_data (void * user_data);
7+
public void * get_user_data ();
8+
public uint32 get_version ();
9+
10+
public void destroy ();
11+
public int add_listener (ManagerListener listener, void * data);
12+
public Surface * get_background_effect (Wl.Surface surface);
13+
}
14+
15+
[CCode (cheader_filename = "ext-background-effect-v1-client-protocol.h", cname = "enum ext_background_effect_manager_v1_error", cprefix = "EXT_BACKGROUND_EFFECT_MANAGER_V1_ERROR_", has_type_id = false)]
16+
public enum ManagerError {
17+
BACKGROUND_EFFECT_EXISTS = 0,
18+
}
19+
20+
[CCode (cheader_filename = "ext-background-effect-v1-client-protocol.h", cname = "enum ext_background_effect_manager_v1_capability", cprefix = "EXT_BACKGROUND_EFFECT_MANAGER_V1_CAPABILITY_", has_type_id = false)]
21+
[Flags]
22+
public enum Capability {
23+
BLUR = 1,
24+
}
25+
26+
[CCode (cheader_filename = "ext-background-effect-v1-client-protocol.h", cname = "struct ext_background_effect_manager_v1_listener", has_type_id = false)]
27+
public struct ManagerListener {
28+
public ManagerListenerCapabilities capabilities;
29+
}
30+
31+
[CCode (has_target = false, has_typedef = false)]
32+
public delegate void ManagerListenerCapabilities (void * data, Manager manager, uint32 flags);
33+
34+
[CCode (cheader_filename = "ext-background-effect-v1-client-protocol.h", cname = "struct ext_background_effect_surface_v1", cprefix = "ext_background_effect_surface_v1_")]
35+
public class Surface : Wl.Proxy {
36+
[CCode (cheader_filename = "ext-background-effect-v1-client-protocol.h", cname = "ext_background_effect_surface_v1_interface")]
37+
public static Wl.Interface iface;
38+
public void set_user_data (void * user_data);
39+
public void * get_user_data ();
40+
public uint32 get_version ();
41+
42+
public void destroy ();
43+
public void set_blur_region (Wl.Region ? region);
44+
}
45+
46+
[CCode (cheader_filename = "ext-background-effect-v1-client-protocol.h", cname = "enum ext_background_effect_surface_v1_error", cprefix = "EXT_BACKGROUND_EFFECT_SURFACE_V1_ERROR_", has_type_id = false)]
47+
public enum SurfaceError {
48+
SURFACE_DESTROYED = 0,
49+
}
50+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<protocol name="ext_background_effect_v1">
3+
<copyright>
4+
Copyright (C) 2015 Martin Gräßlin
5+
Copyright (C) 2015 Marco Martin
6+
Copyright (C) 2020 Vlad Zahorodnii
7+
Copyright (C) 2024 Xaver Hugl
8+
9+
Permission is hereby granted, free of charge, to any person obtaining a
10+
copy of this software and associated documentation files (the "Software"),
11+
to deal in the Software without restriction, including without limitation
12+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
13+
and/or sell copies of the Software, and to permit persons to whom the
14+
Software is furnished to do so, subject to the following conditions:
15+
16+
The above copyright notice and this permission notice (including the next
17+
paragraph) shall be included in all copies or substantial portions of the
18+
Software.
19+
20+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23+
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26+
DEALINGS IN THE SOFTWARE.
27+
</copyright>
28+
29+
<description summary="background effect protocol">
30+
This protocol provides a way to improve visuals of translucent surfaces
31+
by applying effects like blur to the background behind them.
32+
33+
The capabilities are send when the global is bound, and every time they
34+
change. Note that when the capability goes away, the corresponding effect
35+
is no longer applied by the compositor, even if it was set before.
36+
37+
Warning! The protocol described in this file is currently in the testing
38+
phase. Backward compatible changes may be added together with the
39+
corresponding interface version bump. Backward incompatible changes can
40+
only be done by creating a new major version of the extension.
41+
</description>
42+
43+
<interface name="ext_background_effect_manager_v1" version="1">
44+
<description summary="background effect factory">
45+
This protocol provides a way to improve visuals of translucent surfaces
46+
by applying effects like blur to the background behind them.
47+
</description>
48+
49+
<enum name="error">
50+
<entry name="background_effect_exists" value="0"
51+
summary="the surface already has a background effect object"/>
52+
</enum>
53+
54+
<enum name="capability" bitfield="true">
55+
<description summary="compositor capabilities">
56+
These flags indicate which background effect features the compositor
57+
supports.
58+
</description>
59+
<entry name="blur" value="1" summary="the compositor supports applying blur"/>
60+
</enum>
61+
62+
<event name="capabilities">
63+
<description summary="capabilities of the compositor">
64+
Advertises the capabilities of the compositor.
65+
</description>
66+
<arg name="flags" type="uint" enum="capability"
67+
summary="capabilities of the compositor"/>
68+
</event>
69+
70+
<request name="destroy" type="destructor">
71+
<description summary="destroy the background effect manager">
72+
Informs the server that the client will no longer be using this
73+
protocol object. Existing objects created by this object are not
74+
affected.
75+
</description>
76+
</request>
77+
78+
<request name="get_background_effect">
79+
<description summary="get a background effects object">
80+
Instantiate an interface extension for the given wl_surface to add
81+
effects like blur for the background behind it.
82+
83+
If the given wl_surface already has a ext_background_effect_surface_v1
84+
object associated, the background_effect_exists protocol error will be
85+
raised.
86+
</description>
87+
<arg name="id" type="new_id" interface="ext_background_effect_surface_v1"
88+
summary="the new ext_background_effect_surface_v1 object"/>
89+
<arg name="surface" type="object" interface="wl_surface"
90+
summary="the surface"/>
91+
</request>
92+
</interface>
93+
94+
<interface name="ext_background_effect_surface_v1" version="1">
95+
<description summary="background effects for a surface">
96+
The background effect object provides a way to specify a region behind a
97+
surface that should have background effects like blur applied.
98+
99+
If the wl_surface associated with the ext_background_effect_surface_v1
100+
object has been destroyed, this object becomes inert.
101+
</description>
102+
103+
<enum name="error">
104+
<entry name="surface_destroyed" value="0"
105+
summary="the associated surface has been destroyed"/>
106+
</enum>
107+
108+
<request name="destroy" type="destructor">
109+
<description summary="release the blur object">
110+
Informs the server that the client will no longer be using this
111+
protocol object. The effect regions will be removed on the next
112+
commit.
113+
</description>
114+
</request>
115+
116+
<request name="set_blur_region">
117+
<description summary="set blur region">
118+
This request sets the region of the surface that will have its
119+
background blurred.
120+
121+
The blur region is specified in the surface-local coordinates, and
122+
clipped by the compositor to the surface size.
123+
124+
The initial value for the blur region is empty. Setting the pending
125+
blur region has copy semantics, and the wl_region object can be
126+
destroyed immediately. A NULL wl_region removes the effect.
127+
128+
The blur region is double-buffered state, and will be applied on the
129+
next wl_surface.commit.
130+
131+
The blur algorithm is subject to compositor policies.
132+
133+
If the associated surface has been destroyed, the surface_destroyed
134+
error will be raised.
135+
</description>
136+
<arg name="region" type="object" interface="wl_region"
137+
summary="blur region of the surface" allow-null="true"/>
138+
</request>
139+
</interface>
140+
</protocol>

protocols/meson.build

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,51 @@
11
dep_scanner = dependency('wayland-scanner', native: true)
22
prog_scanner = find_program(dep_scanner.get_variable(pkgconfig: 'wayland_scanner'))
33

4-
protocol_file = files(
5-
'xdg-activation-v1.xml',
6-
)
4+
output_type = 'private-code'
5+
if dep_scanner.version().version_compare('< 1.14.91')
6+
output_type = 'code'
7+
endif
78

89
protocol_sources = []
10+
11+
# xdg-activation-v1
12+
xdg_activation_file = files('xdg-activation-v1.xml')
13+
914
protocol_sources += custom_target(
1015
'xdg-activation-v1-client-protocol.h',
1116
command: [prog_scanner, 'client-header', '@INPUT@', '@OUTPUT@'],
12-
input: protocol_file,
17+
input: xdg_activation_file,
1318
output: 'xdg-activation-v1-client-protocol.h',
1419
)
1520

16-
output_type = 'private-code'
17-
if dep_scanner.version().version_compare('< 1.14.91')
18-
output_type = 'code'
19-
endif
2021
protocol_sources += custom_target(
2122
'xdg-activation-protocol.c',
2223
command: [prog_scanner, output_type, '@INPUT@', '@OUTPUT@'],
23-
input: protocol_file,
24+
input: xdg_activation_file,
2425
output: 'xdg-activation-protocol.c',
2526
)
2627

28+
# ext-background-effect-v1
29+
background_effect_file = files('ext-background-effect-v1.xml')
30+
31+
protocol_sources += custom_target(
32+
'ext-background-effect-v1-client-protocol.h',
33+
command: [prog_scanner, 'client-header', '@INPUT@', '@OUTPUT@'],
34+
input: background_effect_file,
35+
output: 'ext-background-effect-v1-client-protocol.h',
36+
)
37+
38+
protocol_sources += custom_target(
39+
'ext-background-effect-protocol.c',
40+
command: [prog_scanner, output_type, '@INPUT@', '@OUTPUT@'],
41+
input: background_effect_file,
42+
output: 'ext-background-effect-protocol.c',
43+
)
44+
2745
protocol_dep += declare_dependency(
2846
dependencies: [
2947
vala.find_library('xdg-activation-v1', dirs: meson.current_source_dir()),
48+
vala.find_library('ext-background-effect-v1', dirs: meson.current_source_dir()),
3049
dependency('wayland-client'),
3150
],
3251
include_directories: include_directories('.'),

0 commit comments

Comments
 (0)