From d7185d71c6c5b51749cbd4e92b3730c60ee259f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 12 May 2020 12:22:52 +0200 Subject: [PATCH 1/4] windowManager: Clean up starting of size-change animations a bit We can do without having two calls to shellwm.completed_size_change() in there, so use an early return for all cases. https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1251 --- js/ui/windowManager.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js index 3dacca2eca..e05c02305a 100644 --- a/js/ui/windowManager.js +++ b/js/ui/windowManager.js @@ -1278,13 +1278,13 @@ var WindowManager = class { } _sizeChangeWindow(shellwm, actor, whichChange, oldFrameRect, _oldBufferRect) { - let types = [Meta.WindowType.NORMAL]; - if (!this._shouldAnimateActor(actor, types)) { - shellwm.completed_size_change(actor); - return; - } + const types = [Meta.WindowType.NORMAL]; + const shouldAnimate = + this._shouldAnimateActor(actor, types) && + oldFrameRect.width > 0 && + oldFrameRect.height > 0; - if (oldFrameRect.width > 0 && oldFrameRect.height > 0) + if (shouldAnimate) this._prepareAnimationInfo(shellwm, actor, oldFrameRect, whichChange); else shellwm.completed_size_change(actor); -- GitLab From 8078d78c30f9fde233d54c665bcd5c0fa80ea963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 12 May 2020 13:51:27 +0200 Subject: [PATCH 2/4] windowManager: Also clear animationInfo when size-changed wasn't emitted It might be that we receive a "kill-window-effects" signal between the emission of the "size-change" and the "size-changed" signal. In this case we already have the animationInfo attached to the window actor, so we should also remove it. https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1251 --- js/ui/windowManager.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js index e05c02305a..61d4f96f14 100644 --- a/js/ui/windowManager.js +++ b/js/ui/windowManager.js @@ -1385,8 +1385,10 @@ var WindowManager = class { this._clearAnimationInfo(actor); } - if (this._resizePending.delete(actor)) + if (this._resizePending.delete(actor)) { + this._clearAnimationInfo(actor); this._shellwm.completed_size_change(actor); + } } _hasAttachedDialogs(window, ignoreWindow) { -- GitLab From 4a6f550acb3f3c0672cd72f64e0639d9db2f3c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 12 May 2020 13:50:05 +0200 Subject: [PATCH 3/4] windowManager: Use new mutter API to freeze window actors ourself We're currently using the hack of telling mutter that our effect is completed (even though it isn't) in order to unfreeze updates of the window actor. This causes a bug with detecting the wl_outputs a window is visible on, because the MetaWindowActor emits its "effects-completed" signal too early, making Mutter update the wl_outputs while we're doing the animation. Now since meta_wayland_actor_surface_is_on_logical_monitor() uses the transformed position and size of the MetaSurfaceActor and is being called right after we setup the animation (but before it actually starts, that happens at the next paint cycle) it will use a "very wrong" rectangle: The transformation has been set to move the actor back to its old position, and while we did already unfreeze updates and called clutter_actor_set_position() in meta_window_actor_sync_actor_geometry(), the actual allocation is not updated yet; this makes clutter_actor_get_transformed_position() return a position including in the new transformation, but not including the new allocation, and the rectangle ends up being moved to the next monitor or completely out of the stage. To fix this issue properly, we need to decouple unfreezing actor updates from emitting the "effects-completed" signal, which is now possible with the new meta_window_actor_freeze() and meta_window_actor_thaw() APIs. So use those new methods to freeze and thaw actor updates ourselves and make sure to call shellwm.completed_size_change() only after the animation has finished. Mutter MR: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1250 Fixes https://gitlab.gnome.org/GNOME/mutter/-/issues/513 https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1251 --- js/ui/windowManager.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js index 61d4f96f14..97601eee47 100644 --- a/js/ui/windowManager.js +++ b/js/ui/windowManager.js @@ -1299,6 +1299,8 @@ var WindowManager = class { actorClone.set_position(oldFrameRect.x, oldFrameRect.y); actorClone.set_size(oldFrameRect.width, oldFrameRect.height); + actor.freeze(); + if (this._clearAnimationInfo(actor)) this._shellwm.completed_size_change(actor); @@ -1307,9 +1309,12 @@ var WindowManager = class { }); this._resizePending.add(actor); - actor.__animationInfo = { clone: actorClone, - oldRect: oldFrameRect, - destroyId }; + actor.__animationInfo = { + clone: actorClone, + oldRect: oldFrameRect, + frozen: true, + destroyId, + }; } _sizeChangedWindow(shellwm, actor) { @@ -1362,13 +1367,17 @@ var WindowManager = class { // Now unfreeze actor updates, to get it to the new size. // It's important that we don't wait until the animation is completed to // do this, otherwise our scale will be applied to the old texture size. - shellwm.completed_size_change(actor); + actor.thaw(); + actor.__animationInfo.frozen = false; } _clearAnimationInfo(actor) { if (actor.__animationInfo) { actor.__animationInfo.clone.destroy(); actor.disconnect(actor.__animationInfo.destroyId); + if (actor.__animationInfo.frozen) + actor.thaw(); + delete actor.__animationInfo; return true; } @@ -1383,6 +1392,7 @@ var WindowManager = class { actor.translation_x = 0; actor.translation_y = 0; this._clearAnimationInfo(actor); + this._shellwm.completed_size_change(actor); } if (this._resizePending.delete(actor)) { -- GitLab From c23ad83c593880c09efcc733cf1ff6dd9453d187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Tue, 12 May 2020 12:28:03 +0200 Subject: [PATCH 4/4] windowManager: Warn when removing old animationInfo Now that we properly notify mutter about when a size-change animation has ended, it should never happen that a new size-change animation is started without the last one being cancelled (ie. 'kill-window-effects' being emitted). This means there should also never be an old animationInfo attached to a window actor, so warn in case we still find one when starting the animation. https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1251 --- js/ui/windowManager.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js index 97601eee47..1ea5daff70 100644 --- a/js/ui/windowManager.js +++ b/js/ui/windowManager.js @@ -1301,8 +1301,10 @@ var WindowManager = class { actor.freeze(); - if (this._clearAnimationInfo(actor)) + if (this._clearAnimationInfo(actor)) { + log('Old animationInfo removed from actor %s'.format(actor)); this._shellwm.completed_size_change(actor); + } let destroyId = actor.connect('destroy', () => { this._clearAnimationInfo(actor); -- GitLab