Skip to content

Commit 2d26095

Browse files
committed
fix: prevent the same event from refreshing the effect many times
1 parent 81b6685 commit 2d26095

2 files changed

Lines changed: 76 additions & 35 deletions

File tree

src/manager/event_handlers.ts

Lines changed: 75 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,45 @@ import {
3030
windowScaleFactor,
3131
} from './utils.js';
3232

33-
export async function onAddEffect(actor: RoundedWindowActor) {
34-
logDebug(`Adding effect to ${actor?.metaWindow.title}`);
33+
/**
34+
* Per-actor queue lock to run event handlers one after another and avoid
35+
* needlessly refreshing the effect a lot of times.
36+
*/
37+
function withActorLock(
38+
actor: RoundedWindowActor,
39+
fn: () => Promise<void>,
40+
): Promise<void> {
41+
const prev: Promise<void> | undefined = actor.rwcLock;
42+
const next = prev ? prev.then(fn, fn) : fn();
43+
actor.rwcLock = next;
44+
return next;
45+
}
3546

36-
const win = actor.metaWindow;
47+
export function onAddEffect(actor: RoundedWindowActor) {
48+
return withActorLock(actor, async () => {
49+
logDebug(`Adding effect to ${actor?.metaWindow.title}`);
50+
const win = actor.metaWindow;
3751

38-
// Skip windows that already have the effect to prevent a memory leak
39-
const shouldHaveEffect = await shouldEnableEffect(win);
40-
const effect = getRoundedCornersEffect(actor);
41-
const hasEffect = effect && actor.rwcCustomData;
52+
// Skip windows that already have the effect to prevent a memory leak
53+
const shouldHaveEffect = await shouldEnableEffect(win);
54+
const effect = getRoundedCornersEffect(actor);
55+
const hasEffect = effect && actor.rwcCustomData;
4256

43-
if (!shouldHaveEffect || hasEffect) {
44-
logDebug(`Skipping ${win.title}`);
45-
return;
46-
}
57+
if (!shouldHaveEffect || hasEffect) {
58+
logDebug(`Skipping ${win.title}`);
59+
return;
60+
}
4761

62+
createEffect(actor);
63+
});
64+
}
65+
66+
/**
67+
* Create the effect on an actor.
68+
*
69+
* @param actor - The window actor to create the effect on.
70+
*/
71+
function createEffect(actor: RoundedWindowActor) {
4872
unwrapActor(actor)?.add_effect_with_name(
4973
ROUNDED_CORNERS_EFFECT,
5074
new RoundedCornersEffect(),
@@ -79,7 +103,7 @@ export async function onAddEffect(actor: RoundedWindowActor) {
79103
};
80104

81105
// Make sure the effect is applied correctly.
82-
refreshRoundedCorners(actor);
106+
updateEffect(actor);
83107
}
84108

85109
export function onRemoveEffect(actor: RoundedWindowActor) {
@@ -227,40 +251,57 @@ function refreshShadow(actor: RoundedWindowActor) {
227251
*
228252
* @param actor - The window actor to refresh the rounded corners settings for.
229253
*/
230-
async function refreshRoundedCorners(actor: RoundedWindowActor) {
231-
const win = actor.metaWindow;
254+
function refreshRoundedCorners(actor: RoundedWindowActor) {
255+
return withActorLock(actor, async () => {
256+
const win = actor.metaWindow;
232257

233-
const shouldHaveEffect = await shouldEnableEffect(win);
258+
const shouldHaveEffect = await shouldEnableEffect(win);
234259

235-
const windowInfo = (actor as RoundedWindowActor).rwcCustomData;
236-
const effect = getRoundedCornersEffect(actor);
260+
const windowInfo = (actor as RoundedWindowActor).rwcCustomData;
261+
const effect = getRoundedCornersEffect(actor);
237262

238-
const hasEffect = effect && windowInfo;
263+
const hasEffect = effect && windowInfo;
239264

240-
// onAddEffect already skips windows that shouldn't have rounded corners.
241-
// This if statement is just for code readability to match the check for
242-
// onRemoveEffect below.
243-
if (!hasEffect && shouldHaveEffect) {
244-
onAddEffect(actor);
265+
// onAddEffect already skips windows that shouldn't have rounded corners.
266+
// This if statement is just for code readability to match the check for
267+
// onRemoveEffect below.
268+
if (!hasEffect && shouldHaveEffect) {
269+
createEffect(actor);
245270

246-
// onAddEffect calls refreshRoundedCorners at the end, so return here to
247-
// avoid running it twice.
248-
return;
249-
}
271+
// createEffect already calls updateEffect at the end,
272+
// so return here to avoid running the update twice.
273+
return;
274+
}
250275

251-
if (hasEffect && !shouldHaveEffect) {
252-
onRemoveEffect(actor);
253-
return;
254-
}
276+
if (hasEffect && !shouldHaveEffect) {
277+
onRemoveEffect(actor);
278+
return;
279+
}
280+
281+
// Don'd do anything when the window doesn't have the effect and shouldn't have it.
282+
if (!hasEffect) return;
283+
284+
updateEffect(actor);
285+
});
286+
}
255287

256-
// Don'd do anything when the window doesn't have the effect and shouldn't have it.
257-
if (!hasEffect) return;
288+
/**
289+
* Update effect uniforms and constraints for a window.
290+
*
291+
* @param actor - The window actor to update the effect for.
292+
*/
293+
function updateEffect(actor: RoundedWindowActor) {
294+
const win = actor.metaWindow;
295+
const windowInfo = actor.rwcCustomData;
296+
if (!windowInfo) return;
297+
298+
const effect = getRoundedCornersEffect(actor);
299+
if (!effect) return;
258300

259301
if (!effect.enabled) {
260302
effect.enabled = true;
261303
}
262304

263-
// When window size is changed, update uniforms for corner rounding shader.
264305
const cfg = getRoundedCornersCfg(win);
265306
const windowContentOffset = computeWindowContentsOffset(win);
266307
effect.updateUniforms(
@@ -269,7 +310,6 @@ async function refreshRoundedCorners(actor: RoundedWindowActor) {
269310
computeBounds(actor, windowContentOffset),
270311
);
271312

272-
// Update BindConstraint for the shadow
273313
const shadow = windowInfo.shadow;
274314
const offsets = computeShadowActorOffset(actor, windowContentOffset);
275315
const constraints = shadow.get_constraints();

src/utils/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export type RoundedWindowActor = Meta.WindowActor & {
5656
unminimizedTimeoutId: number;
5757
propertyBindings: GObject.Binding[];
5858
};
59+
rwcLock?: Promise<void>;
5960
};
6061

6162
/**

0 commit comments

Comments
 (0)