diff --git a/extension.js b/extension.js index 845fa01..1fcc4d2 100644 --- a/extension.js +++ b/extension.js @@ -213,42 +213,33 @@ class Extension { // of the actor. However, if we are in the overview, we have to enlarge the clone of // the window as well. Workspace.prototype._addWindowClone = function(...params) { - const result = extensionThis._origAddWindowClone.apply(this, params); + const clone = extensionThis._origAddWindowClone.apply(this, params); // The parameters of this method changed a bit through the versions... - let realWindow, clone; + let realWindow, container; if (utils.shellVersionIs(3, 36)) { - clone = result[0]; - realWindow = clone.realWindow; + container = clone[0]; + realWindow = container.realWindow; } else if (utils.shellVersionIs(3, 38)) { - clone = result._windowContainer; + container = clone._windowContainer; realWindow = params[0].get_compositor_private(); } else { - clone = result.window_container; + container = clone.window_container; realWindow = params[0].get_compositor_private(); } - // Syncing the real window's scale with the scale of its clone only works on GNOME - // Shell 3.38+. So effects cannot scale windows in the overview of GNOME 3.36... - if (utils.shellVersionIsAtLeast(3, 38)) { - const xID = realWindow.connect('notify::scale-x', () => { - if (realWindow.scale_x > 0 && clone.allocation.get_size()[0] > 0) { - clone.scale_x = realWindow.scale_x; - } - }); + // Store the overview clone as temporary members of the real window actor. When we + // set up the effect, we will check for the existence of these and enlarge the clone + // as needed. + realWindow._bmwOverviewClone = clone; + realWindow._bmwOverviewCloneContainer = container; - const yID = realWindow.connect('notify::scale-y', () => { - if (realWindow.scale_y > 0 && clone.allocation.get_size()[1] > 0) { - clone.scale_y = realWindow.scale_y; - } - }); - - clone.connect('destroy', () => { - realWindow.disconnect(xID); - realWindow.disconnect(yID); - }); - } + // Remove the temporary members again once the clone is deleted. + container.connect('destroy', () => { + delete realWindow._bmwOverviewClone; + delete realWindow._bmwOverviewCloneContainer; + }); // This is actually needed for the window-close animation on GNOME Shell 3.36. // On GNOME 3.36, the window clone's 'destroy' handler only calls _removeWindowClone @@ -257,10 +248,10 @@ class Extension { // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/gnome-3-36/js/ui/workspace.js#L1877 // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/workspace.js#L1363 if (utils.shellVersionIs(3, 36)) { - clone.connect('destroy', () => this._doRemoveWindow(clone.metaWindow)); + container.connect('destroy', () => this._doRemoveWindow(container.metaWindow)); } - return result; + return clone; }; // Usually, windows are faded in after the overview is completely hidden. We enable @@ -559,12 +550,48 @@ class Extension { actor.scale_x = actorScale.x; actor.scale_y = actorScale.y; + // If we are in the overview, we have to enlarge the window's clone as well. We also + // disable the clone's overlay (e.g. its icon, name, and close button) during the + // animation. + if (actor._bmwOverviewClone) { + actor._bmwOverviewClone.overlayEnabled = false; + actor._bmwOverviewCloneContainer.scale_x = actorScale.x; + actor._bmwOverviewCloneContainer.scale_y = actorScale.y; + } + // Now add a cool shader to our window actor! const shader = effect.shaderFactory.getShader(); - - // Assign the effect to the window actor! actor.add_effect_with_name('burn-my-windows-effect', shader); + // At the end of the animation, we restore the scale of the overview clone (if any) + // and call the methods which would have been called by the original ease() calls at + // the end of the standard fade-in animation. + const endID = shader.connect('end-animation', () => { + shader.disconnect(endID); + + if (actor._bmwOverviewClone) { + actor._bmwOverviewClone.overlayEnabled = true; + actor._bmwOverviewCloneContainer.scale_x = 1.0; + actor._bmwOverviewCloneContainer.scale_y = 1.0; + } + + // Once the animation is done or interrupted, we call the methods which should have + // been called by the original ease() methods. + // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1487 + // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1558. + if (forOpening) { + Main.wm._mapWindowDone(global.window_manager, actor); + } else { + Main.wm._destroyWindowDone(global.window_manager, actor); + } + + // Finally remove the shader and mark it being re-usable for future animations. + actor.remove_effect(shader); + shader.returnToFactory(); + }); + + + // To make things deterministic during testing, we set the effect duration to 5 // seconds. const duration = diff --git a/src/Shader.js b/src/Shader.js index 6b9937b..2803259 100644 --- a/src/Shader.js +++ b/src/Shader.js @@ -37,12 +37,14 @@ const utils = Me.imports.src.utils; // hard-coded use of straight alpha (as opposed to premultiplied). This makes the // // shaders a bit more complicated than required. // // // -// The Shader fires two signals: // +// The Shader fires three signals: // // * begin-animation: This is called each time a new animation is started. It can // // be used to set uniform values which do not change during the // // animation. // // * update-animation: This is called at each frame during the animation. It can be // // used to set uniforms which change during the animation. // +// * end-animation: This is called when the animation is stopped. This can be // +// used to clean up any resources. ////////////////////////////////////////////////////////////////////////////////////////// var Shader = GObject.registerClass( @@ -112,9 +114,8 @@ var Shader = GObject.registerClass( this._timeline.start(); // Reset progress value. - this._progress = 0; - this._testMode = testMode; - this._forOpening = forOpening; + this._progress = 0; + this._testMode = testMode; // This is not necessarily symmetric, but I haven't figured out a way to // get the actual values... @@ -138,8 +139,7 @@ var Shader = GObject.registerClass( this.queue_repaint(); } - // This will stop any running animation and emit the end-animation signal. This can be - // used to clean up any resources required during the animation. + // This will stop any running animation and emit the end-animation signal. endAnimation() { // This will call endAnimation() again, so we can return for now. if (this._timeline.is_playing()) { @@ -147,23 +147,6 @@ var Shader = GObject.registerClass( return; } - // Remove the effect. - const actor = this.get_actor(); - actor.remove_effect(this); - - // Once the animation is done or interrupted, we call the methods which should have - // been called by the original ease() methods. - // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1487 - // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1558. - if (this._forOpening) { - Main.wm._mapWindowDone(global.window_manager, actor); - } else { - Main.wm._destroyWindowDone(global.window_manager, actor); - } - - // Mark this shader of being re-usable. - this.returnToFactory(); - this.emit('end-animation'); }