@@ -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
85109export 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 ( ) ;
0 commit comments