Skip to content

Commit d0ebafe

Browse files
committed
Apply alpha modifier to non-toplevel surfaces
Also made it easier to apply effects to other types of buffers like layer surfaces or popups
1 parent 434246d commit d0ebafe

File tree

1 file changed

+140
-133
lines changed

1 file changed

+140
-133
lines changed

src/comp/output.c

Lines changed: 140 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -131,174 +131,181 @@ struct comp_workspace *comp_output_get_active_ws(struct comp_output *output,
131131
return active_ws;
132132
}
133133

134-
static void output_configure_scene(struct comp_output *output,
135-
struct wlr_scene_node *node,
136-
bool is_in_saved_tree,
137-
struct comp_object *closest_object) {
138-
if (!node->enabled) {
134+
static void
135+
configure_apply_alpha_modifier(struct wlr_scene_surface *scene_surface,
136+
float *opacity) {
137+
if (!scene_surface) {
139138
return;
140139
}
141140

142-
if (node->data) {
143-
closest_object = node->data;
144-
if (closest_object->type == COMP_OBJECT_TYPE_SAVED_OBJECT) {
145-
is_in_saved_tree = true;
141+
const struct wlr_alpha_modifier_surface_v1_state *alpha_modifier_state =
142+
wlr_alpha_modifier_v1_get_surface_state(scene_surface->surface);
143+
if (alpha_modifier_state) {
144+
*opacity *= (float)alpha_modifier_state->multiplier;
145+
}
146+
}
147+
148+
static void configure_apply_toplevel(struct comp_toplevel *toplevel,
149+
struct wlr_scene_buffer *buffer,
150+
struct wlr_scene_surface *scene_surface,
151+
bool is_in_saved_tree) {
152+
bool has_effects = !toplevel->fullscreen;
153+
154+
// HACK: Force an node update after setting all other effects. This
155+
// avoids re-damaging the same region multiple times for each buffer,
156+
// each frame.
157+
bool options_changed = false;
158+
159+
// Stretch the saved toplevel buffer to fit the toplevel state
160+
if (!wl_list_empty(&toplevel->saved_scene_tree->children)) {
161+
int width = toplevel->state.width;
162+
int height = toplevel->state.height;
163+
if (buffer->transform & WL_OUTPUT_TRANSFORM_90) {
164+
width = toplevel->state.height;
165+
height = toplevel->state.width;
146166
}
167+
buffer_change_option(options_changed, buffer->dst_width, width);
168+
buffer_change_option(options_changed, buffer->dst_height, height);
147169
}
148170

149-
switch (node->type) {
150-
default:
151-
break;
152-
case WLR_SCENE_NODE_BUFFER: {
153-
struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
154-
if (!closest_object) {
155-
wlr_log(WLR_DEBUG,
156-
"Tried to apply effects to buffer with unknown data");
157-
break;
171+
//
172+
// Opacity
173+
//
174+
175+
float opacity = has_effects ? toplevel->opacity : 1;
176+
if (toplevel->anim.resize.client->state == ANIMATION_STATE_RUNNING) {
177+
if (is_in_saved_tree) {
178+
opacity *= toplevel->anim.resize.crossfade_opacity;
158179
}
159-
comp_saved_object_try_extract(closest_object);
160-
if (closest_object->type != COMP_OBJECT_TYPE_TOPLEVEL) {
180+
}
181+
if (toplevel->anim.open_close.client->state == ANIMATION_STATE_RUNNING) {
182+
opacity *= toplevel->anim.open_close.fade_opacity;
183+
}
184+
185+
// Don't let alpha modifier adjust the blur alpha/strength
186+
float blur_alpha = ease_out_cubic(opacity);
187+
buffer_change_option(options_changed, buffer->backdrop_blur_alpha,
188+
blur_alpha);
189+
buffer_change_option(options_changed, buffer->backdrop_blur_strength,
190+
opacity);
191+
192+
// Alpha modifier support
193+
configure_apply_alpha_modifier(scene_surface, &opacity);
194+
buffer_change_option(options_changed, buffer->opacity, opacity);
195+
196+
//
197+
// Toplevel only effects
198+
//
199+
200+
bool is_main_surface = false;
201+
if (scene_surface) {
202+
switch (toplevel->type) {
203+
case COMP_TOPLEVEL_TYPE_XDG:;
204+
struct wlr_xdg_surface *xdg_surface =
205+
wlr_xdg_surface_try_from_wlr_surface(scene_surface->surface);
206+
is_main_surface = xdg_surface && xdg_surface->role ==
207+
WLR_XDG_SURFACE_ROLE_TOPLEVEL;
208+
break;
209+
case COMP_TOPLEVEL_TYPE_XWAYLAND:
210+
is_main_surface = wlr_xwayland_surface_try_from_wlr_surface(
211+
scene_surface->surface);
161212
break;
162213
}
214+
}
163215

164-
struct comp_toplevel *toplevel = closest_object->data;
165-
bool has_effects = !toplevel->fullscreen;
166-
167-
// HACK: Force an node update after setting all other effects. This
168-
// avoids re-damaging the same region multiple times for each buffer,
169-
// each frame.
170-
bool options_changed = false;
171-
172-
// Stretch the saved toplevel buffer to fit the toplevel state
173-
if (!wl_list_empty(&toplevel->saved_scene_tree->children)) {
174-
int width = toplevel->state.width;
175-
int height = toplevel->state.height;
176-
if (buffer->transform & WL_OUTPUT_TRANSFORM_90) {
177-
width = toplevel->state.height;
178-
height = toplevel->state.width;
179-
}
180-
buffer_change_option(options_changed, buffer->dst_width, width);
181-
buffer_change_option(options_changed, buffer->dst_height, height);
182-
}
183-
184-
//
185-
// Opacity
186-
//
187-
188-
float opacity = has_effects ? toplevel->opacity : 1;
216+
// Ignore other unknown types
217+
if (is_in_saved_tree || is_main_surface) {
218+
// Blur
219+
bool blur = has_effects;
189220
if (toplevel->anim.resize.client->state == ANIMATION_STATE_RUNNING) {
190221
if (is_in_saved_tree) {
191-
opacity *= toplevel->anim.resize.crossfade_opacity;
222+
blur = false;
192223
}
193224
}
194-
if (toplevel->anim.open_close.client->state ==
195-
ANIMATION_STATE_RUNNING) {
196-
opacity *= toplevel->anim.open_close.fade_opacity;
225+
buffer_change_option(options_changed, buffer->backdrop_blur, blur);
226+
switch (toplevel->tiling_mode) {
227+
case COMP_TILING_MODE_FLOATING:
228+
buffer_change_option(options_changed,
229+
buffer->backdrop_blur_optimized, false);
230+
break;
231+
case COMP_TILING_MODE_TILED:
232+
buffer_change_option(options_changed,
233+
buffer->backdrop_blur_optimized, true);
234+
break;
197235
}
236+
buffer_change_option(options_changed,
237+
buffer->backdrop_blur_ignore_transparent, true);
238+
}
198239

199-
// Don't let alpha modifier adjust the blur alpha/strength
200-
float blur_alpha = ease_out_cubic(opacity);
201-
buffer_change_option(options_changed, buffer->backdrop_blur_alpha,
202-
blur_alpha);
203-
buffer_change_option(options_changed, buffer->backdrop_blur_strength,
204-
opacity);
240+
// Set corners for subsurfaces as well. Fixes Firefox weirdness :/
241+
if (is_main_surface ||
242+
(scene_surface && scene_surface->surface &&
243+
wlr_subsurface_try_from_wlr_surface(scene_surface->surface))) {
244+
// Corners
245+
float corner_radius = has_effects ? toplevel->corner_radius : 0;
246+
buffer_change_option(options_changed, buffer->corner_radius,
247+
corner_radius);
248+
enum corner_location corners =
249+
toplevel->using_csd ? CORNER_LOCATION_ALL : CORNER_LOCATION_BOTTOM;
250+
corners = has_effects ? corners : CORNER_LOCATION_NONE;
251+
buffer_change_option(options_changed, buffer->corners, corners);
252+
}
205253

206-
// Alpha modifier support
207-
struct wlr_scene_surface *surface =
208-
wlr_scene_surface_try_from_buffer(buffer);
209-
if (surface) {
210-
const struct wlr_alpha_modifier_surface_v1_state
211-
*alpha_modifier_state =
212-
wlr_alpha_modifier_v1_get_surface_state(surface->surface);
213-
if (alpha_modifier_state) {
214-
opacity *= (float)alpha_modifier_state->multiplier;
215-
}
216-
}
217-
buffer_change_option(options_changed, buffer->opacity, opacity);
254+
// HACK: Lastly, force update the node if there were changes made
255+
if (options_changed) {
256+
buffer->opacity = -1;
257+
}
258+
wlr_scene_buffer_set_opacity(buffer, opacity);
259+
}
218260

219-
//
220-
// Toplevel only effects
221-
//
261+
static void output_configure_scene(struct comp_output *output,
262+
struct wlr_scene_node *node,
263+
bool is_in_saved_tree,
264+
struct comp_object *closest_object) {
265+
if (!node->enabled) {
266+
return;
267+
}
222268

223-
bool is_main_surface = false;
269+
if (node->data) {
270+
closest_object = node->data;
271+
if (closest_object->type == COMP_OBJECT_TYPE_SAVED_OBJECT) {
272+
is_in_saved_tree = true;
273+
}
274+
}
224275

276+
if (node->type == WLR_SCENE_NODE_BUFFER) {
277+
struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
225278
struct wlr_scene_surface *scene_surface =
226279
wlr_scene_surface_try_from_buffer(buffer);
227-
if (scene_surface) {
228-
switch (toplevel->type) {
229-
case COMP_TOPLEVEL_TYPE_XDG:;
230-
struct wlr_xdg_surface *xdg_surface =
231-
wlr_xdg_surface_try_from_wlr_surface(
232-
scene_surface->surface);
233-
is_main_surface =
234-
xdg_surface &&
235-
xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL;
236-
break;
237-
case COMP_TOPLEVEL_TYPE_XWAYLAND:
238-
is_main_surface =
239-
wlr_xwayland_surface_try_from_wlr_surface(surface->surface);
280+
if (closest_object) {
281+
comp_saved_object_try_extract(closest_object);
282+
switch (closest_object->type) {
283+
case COMP_OBJECT_TYPE_TOPLEVEL:
284+
configure_apply_toplevel(closest_object->data, buffer,
285+
scene_surface, is_in_saved_tree);
286+
return;
287+
case COMP_OBJECT_TYPE_WIDGET:
288+
return;
289+
case COMP_OBJECT_TYPE_LAYER_SURFACE: {
290+
// TODO: Layer effects
240291
break;
241292
}
242-
}
243-
244-
// Ignore other unknown types
245-
if (is_in_saved_tree || is_main_surface) {
246-
// Blur
247-
bool blur = has_effects;
248-
if (toplevel->anim.resize.client->state ==
249-
ANIMATION_STATE_RUNNING) {
250-
if (is_in_saved_tree) {
251-
blur = false;
252-
}
253-
}
254-
buffer_change_option(options_changed, buffer->backdrop_blur, blur);
255-
switch (toplevel->tiling_mode) {
256-
case COMP_TILING_MODE_FLOATING:
257-
buffer_change_option(options_changed,
258-
buffer->backdrop_blur_optimized, false);
259-
break;
260-
case COMP_TILING_MODE_TILED:
261-
buffer_change_option(options_changed,
262-
buffer->backdrop_blur_optimized, true);
293+
default:
263294
break;
264295
}
265-
buffer_change_option(options_changed,
266-
buffer->backdrop_blur_ignore_transparent,
267-
true);
268296
}
269297

270-
// Set corners for subsurfaces as well. Fixes Firefox weirdness :/
271-
if (is_main_surface ||
272-
(surface && surface->surface &&
273-
wlr_subsurface_try_from_wlr_surface(surface->surface))) {
274-
// Corners
275-
float corner_radius = has_effects ? toplevel->corner_radius : 0;
276-
buffer_change_option(options_changed, buffer->corner_radius,
277-
corner_radius);
278-
enum corner_location corners = toplevel->using_csd
279-
? CORNER_LOCATION_ALL
280-
: CORNER_LOCATION_BOTTOM;
281-
corners = has_effects ? corners : CORNER_LOCATION_NONE;
282-
buffer_change_option(options_changed, buffer->corners, corners);
283-
}
284-
285-
// HACK: Lastly, force update the node if there were changes made
286-
if (options_changed) {
287-
buffer->opacity = -1;
288-
}
298+
// Alpha modifier support for other surfaces
299+
float opacity = 1.0;
300+
configure_apply_alpha_modifier(scene_surface, &opacity);
289301
wlr_scene_buffer_set_opacity(buffer, opacity);
290-
291-
break;
292-
}
293-
case WLR_SCENE_NODE_TREE: {
302+
} else if (node->type == WLR_SCENE_NODE_TREE) {
294303
struct wlr_scene_tree *tree = wlr_scene_tree_from_node(node);
295304
struct wlr_scene_node *node;
296305
wl_list_for_each(node, &tree->children, link) {
297306
output_configure_scene(output, node, is_in_saved_tree,
298307
closest_object);
299308
}
300-
break;
301-
}
302309
}
303310
}
304311

0 commit comments

Comments
 (0)