Merge branch 'main' of github.com:Schneegans/Burn-My-Windows

This commit is contained in:
Simon Schneegans
2023-04-06 20:17:58 +02:00
168 changed files with 203 additions and 229 deletions
+2
View File
@@ -116,6 +116,8 @@ jobs:
- '35' - '35'
- '36' - '36'
- '37' - '37'
- '38'
- 'rawhide'
session: session:
- 'gnome-xsession' - 'gnome-xsession'
- 'gnome-wayland-nested' - 'gnome-wayland-nested'
+2 -2
View File
@@ -48,7 +48,7 @@ pot: $(JS_FILES) $(UI_FILES)
# This runs several tests in containerized versions of GNOME Shell. # This runs several tests in containerized versions of GNOME Shell.
test: test:
@ for version in 32 33 34 35 36 37 ; do \ @ for version in 32 33 34 35 36 37 38 "rawhide" ; do \
for session in "gnome-xsession" "gnome-wayland-nested" ; do \ for session in "gnome-xsession" "gnome-wayland-nested" ; do \
echo ; \ echo ; \
echo "Running Tests on Fedora $$version ($$session)." ; \ echo "Running Tests on Fedora $$version ($$session)." ; \
@@ -59,7 +59,7 @@ test:
# This re-generates all reference images required by the tests. # This re-generates all reference images required by the tests.
references: references:
@ for version in 32 33 34 35 36 37 ; do \ @ for version in 32 33 34 35 36 37 38 "rawhide" ; do \
for session in "gnome-xsession" "gnome-wayland-nested" ; do \ for session in "gnome-xsession" "gnome-wayland-nested" ; do \
echo ; \ echo ; \
echo "Generating References for Fedora $$version ($$session)." ; \ echo "Generating References for Fedora $$version ($$session)." ; \
+156 -223
View File
@@ -133,90 +133,113 @@ class Extension {
} }
// We will monkey-patch these methods. Let's store the original ones. // We will monkey-patch these methods. Let's store the original ones.
this._origShouldAnimateActor = WindowManager.prototype._shouldAnimateActor;
this._origWaitForOverviewToHide = WindowManager.prototype._waitForOverviewToHide;
this._origAddWindowClone = Workspace.prototype._addWindowClone; this._origAddWindowClone = Workspace.prototype._addWindowClone;
this._origWindowRemoved = Workspace.prototype._windowRemoved; this._origWindowRemoved = Workspace.prototype._windowRemoved;
this._origDoRemoveWindow = Workspace.prototype._doRemoveWindow; this._origDoRemoveWindow = Workspace.prototype._doRemoveWindow;
this._origShouldAnimateActor = WindowManager.prototype._shouldAnimateActor;
this._origWaitForOverviewToHide = WindowManager.prototype._waitForOverviewToHide;
this._origDestroyWindowDone = WindowManager.prototype._destroyWindowDone;
// ------------------------------------------------ patching the window-open animation // ------------------------------- patching the window animations outside the overview
// Here we add an effect to the window-open animation. This is done whenever a new // If a window is created, the transitions are set up in the async _mapWindow() of the
// window is created. Usually, there is no real window animation for opening windows
// in the overview - only the window's clone is animated - but thanks to the hacks
// below, we can show the real animations in the overview.
// If a window is created the transitions are set up in the async _mapWindow of the
// WindowManager: // WindowManager:
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1478 // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1487
// AFAIK, overriding this method is not possible as it's called by a signal to // AFAIK, overriding this method is not possible as it's called by a signal to which
// which it is bound via the bind() method. To tweak the async transition // it is bound via the bind() method. To tweak the async transition anyways, we
// anyways, we override the actors ease() method once - the next time it will be // override the actors ease() method once. We do this in _shouldAnimateActor() which
// called by the _mapWindow(), we will intercept it! // is called right before the ease() in _mapWindow:
this._windowCreatedConnection = // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1472
global.display.connect('window-created', (d, metaWin) => {
let actor = metaWin.get_compositor_private();
const orig = actor.ease; // The same trick is done for the window-close animation. This is set up in a similar
actor.ease = function(...params) { // fashion in the WindowManager's _destroyWindow():
orig.apply(actor, params); // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1558.
actor.ease = orig; // Here is _shouldAnimateActor() also called right before. So we use it again to
// monkey-patch the window actor's ease() once.
// There are cases where the ease() is called prior to mapping the actor. If // We override WindowManager._shouldAnimateActor() also for another purpose: Usually,
// the actor is not yet mapped, we defer the effect creation. // it returns false when we are in the overview. This prevents the window animations
if (actor.mapped) { // there. To enable animations in the overview, we check inside the method whether it
extensionThis._setupEffect(actor, true); // was called by either _mapWindow or _destroyWindow. If so, we return true. Let's see
} else { // if this breaks stuff left and right...
const connectionID = actor.connect('notify::mapped', () => { // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1120
extensionThis._setupEffect(actor, true); WindowManager.prototype._shouldAnimateActor = function(actor, types) {
actor.disconnect(connectionID); const caller = (new Error()).stack.split('\n')[1];
}); const forClosing = caller.includes('_destroyWindow@');
} const forOpening = caller.includes('_mapWindow@');
};
// This is also called in other cases, for instance when minimizing windows. We are
// only interested in window opening and window closing for now.
if (forClosing || forOpening) {
// If there is an applicable effect profile, we intercept the ease() method to
// setup our own effect.
const chosenEffect = extensionThis._chooseEffect(actor, forOpening);
if (chosenEffect) {
// Store the original ease() method of the actor.
const orig = actor.ease;
// Now intercept the next call to actor.ease().
actor.ease = function(...params) {
// Quickly restore the original behavior. Nobody noticed, I guess :D
actor.ease = orig;
// And then create the effect!
extensionThis._setupEffect(actor, forOpening, chosenEffect.effect,
chosenEffect.profile);
};
return true;
}
}
return extensionThis._origShouldAnimateActor.apply(this, [actor, types]);
};
// Make sure to remove any effects if requested by the window manager.
this._killEffectsSignal =
global.window_manager.connect('kill-window-effects', (wm, actor) => {
const shader = actor.get_effect('burn-my-windows-effect');
if (shader) {
shader.endAnimation();
}
}); });
// --------------------------------------------- fix window animations in the overview
// Some of the effects require that the window's actor is enlarged to provide a bigger // Some of the effects require that the window's actor is enlarged to provide a bigger
// canvas to draw the effects. Outside the overview we can simply increase the scale // canvas to draw the effects. Outside the overview we can simply increase the scale
// of the actor. However, if we are in the overview, we have to enlarge the clone of // of the actor. However, if we are in the overview, we have to enlarge the clone of
// the window as well. // the window as well.
Workspace.prototype._addWindowClone = function(...params) { 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... // The parameters of this method changed a bit through the versions...
let realWindow, clone; let realWindow, container;
if (utils.shellVersionIs(3, 36)) { if (utils.shellVersionIs(3, 36)) {
clone = result[0]; container = clone[0];
realWindow = clone.realWindow; realWindow = container.realWindow;
} else if (utils.shellVersionIs(3, 38)) { } else if (utils.shellVersionIs(3, 38)) {
clone = result._windowContainer; container = clone._windowContainer;
realWindow = params[0].get_compositor_private(); realWindow = params[0].get_compositor_private();
} else { } else {
clone = result.window_container; container = clone.window_container;
realWindow = params[0].get_compositor_private(); realWindow = params[0].get_compositor_private();
} }
// Syncing the real window's scale with the scale of its clone only works on GNOME // Store the overview clone as temporary members of the real window actor. When we
// Shell 3.38+. So effects cannot scale windows in the overview of GNOME 3.36... // set up the effect, we will check for the existence of these and enlarge the clone
if (utils.shellVersionIsAtLeast(3, 38)) { // as needed.
const xID = realWindow.connect('notify::scale-x', () => { realWindow._bmwOverviewClone = clone;
if (realWindow.scale_x > 0 && clone.allocation.get_size()[0] > 0) { realWindow._bmwOverviewCloneContainer = container;
clone.scale_x = realWindow.scale_x;
}
});
const yID = realWindow.connect('notify::scale-y', () => { // Remove the temporary members again once the clone is deleted.
if (realWindow.scale_y > 0 && clone.allocation.get_size()[1] > 0) { container.connect('destroy', () => {
clone.scale_y = realWindow.scale_y; delete realWindow._bmwOverviewClone;
} delete realWindow._bmwOverviewCloneContainer;
}); });
clone.connect('destroy', () => {
realWindow.disconnect(xID);
realWindow.disconnect(yID);
});
}
// This is actually needed for the window-close animation on GNOME Shell 3.36. // 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 // On GNOME 3.36, the window clone's 'destroy' handler only calls _removeWindowClone
@@ -225,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/gnome-3-36/js/ui/workspace.js#L1877
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/workspace.js#L1363 // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/workspace.js#L1363
if (utils.shellVersionIs(3, 36)) { 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 // Usually, windows are faded in after the overview is completely hidden. We enable
@@ -237,61 +260,11 @@ class Extension {
return Promise.resolve(); return Promise.resolve();
}; };
// Here comes the ULTRA-HACK: The method below is called (amongst others) by the
// _destroyWindow and _mapWindow methods of the WindowManager. Usually, it returns
// false when we are in the overview. This prevents the window animations. As we
// cannot monkey-patch the _destroyWindow or _mapWindow methods themselves, we check
// inside the method below whether it was called by either of those. If so, we return
// true. Let's see if this breaks stuff left and right...
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1124
WindowManager.prototype._shouldAnimateActor = function(...params) {
const caller = (new Error()).stack.split('\n')[1];
if (caller.includes('_destroyWindow@') || caller.includes('_mapWindow@')) {
return true;
}
return extensionThis._origShouldAnimateActor.apply(this, params);
};
// ----------------------------------------------- patching the window-close animation
// The signal handler below and the following patch are all which is required outside
// of the overview. All other hacks further below are just required to defer the
// window-hiding in the overview until the effect is finished.
// The close animation is set up in WindowManager's _destroyWindow:
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1554
// As we cannot monkey-patch the _destroyWindow itself, we connect to the 'destroy'
// signal of the window manager and tweak the animation to our needs.
this._destroyConnection = global.window_manager.connect('destroy', (wm, actor) => {
this._setupEffect(actor, false);
});
// Once the window-close animation is is finished, the window manager's
// _destroyWindowDone is called. We use this to free the effect so that it can be
// re-used in future.
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1564
WindowManager.prototype._destroyWindowDone = function(shellwm, actor) {
if (this._destroying.has(actor)) {
const shader = actor.get_effect('burn-my-windows-effect');
if (shader) {
actor.remove_effect(shader);
shader.endAnimation();
shader.returnToFactory();
}
}
// Call the original method.
extensionThis._origDestroyWindowDone.apply(this, [shellwm, actor]);
};
// These three method overrides are mega-hacky! Usually, windows are not faded when // These three method overrides are mega-hacky! Usually, windows are not faded when
// closed from the overview (why?). With these overrides we make sure that they are // closed from the overview (why?). With these overrides we make sure that they are
// actually faded out. To do this, _windowRemoved and _doRemoveWindow now check // actually faded out. To do this, _windowRemoved and _doRemoveWindow now check
// whether there is a transition ongoing (via extensionThis._shouldDestroy). If that's // whether there is a transition ongoing (via extensionThis._shouldDestroy). If that's
// the case, these methods do nothing. Are the actors removed in the end? I hope so. // the case, these methods do nothing.
// The _destroyWindow of the WindowManager sets the transitions up and should take
// care of removing the actors at the end of the transitions.
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/workspace.js#L1258 // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/workspace.js#L1258
Workspace.prototype._windowRemoved = function(ws, metaWin) { Workspace.prototype._windowRemoved = function(ws, metaWin) {
if (extensionThis._shouldDestroy(this, metaWin)) { if (extensionThis._shouldDestroy(this, metaWin)) {
@@ -369,16 +342,14 @@ class Extension {
// Disable the window-picking D-Bus API. // Disable the window-picking D-Bus API.
this._windowPicker.unexport(); this._windowPicker.unexport();
// Restore the original window-open and window-close animations. global.window_manager.disconnect(this._killEffectsSignal);
global.window_manager.disconnect(this._destroyConnection);
global.display.disconnect(this._windowCreatedConnection);
// Restore the original window-open and window-close animations.
Workspace.prototype._addWindowClone = this._origAddWindowClone; Workspace.prototype._addWindowClone = this._origAddWindowClone;
Workspace.prototype._windowRemoved = this._origWindowRemoved; Workspace.prototype._windowRemoved = this._origWindowRemoved;
Workspace.prototype._doRemoveWindow = this._origDoRemoveWindow; Workspace.prototype._doRemoveWindow = this._origDoRemoveWindow;
WindowManager.prototype._shouldAnimateActor = this._origShouldAnimateActor; WindowManager.prototype._shouldAnimateActor = this._origShouldAnimateActor;
WindowManager.prototype._waitForOverviewToHide = this._origWaitForOverviewToHide; WindowManager.prototype._waitForOverviewToHide = this._origWaitForOverviewToHide;
WindowManager.prototype._destroyWindowDone = this._origDestroyWindowDone;
if (WindowPreview) { if (WindowPreview) {
WindowPreview.prototype._deleteAll = this._origDeleteAll; WindowPreview.prototype._deleteAll = this._origDeleteAll;
@@ -427,11 +398,10 @@ class Extension {
this._profiles.sort((a, b) => b.priority - a.priority); this._profiles.sort((a, b) => b.priority - a.priority);
} }
// This method adds one of the configured effects to the given actor. First, a profile // This method selects an effect profile matching the current circumstances. Then a
// matching the current circumstances is chosen. Then a random effect from its enabled // random effect from its enabled effects will be selected. It returns null if no
// effects will be selected. This will also tweak the transitions of the given actor // profile is currently applicable.
// (e.g. scale it up if required). _chooseEffect(actor, forOpening) {
_setupEffect(actor, forOpening) {
// For now, we only add effects to normal windows and dialog windows. // For now, we only add effects to normal windows and dialog windows.
const isNormalWindow = actor.meta_window.window_type == Meta.WindowType.NORMAL; const isNormalWindow = actor.meta_window.window_type == Meta.WindowType.NORMAL;
@@ -440,17 +410,7 @@ class Extension {
actor.meta_window.window_type == Meta.WindowType.DIALOG; actor.meta_window.window_type == Meta.WindowType.DIALOG;
if (!isNormalWindow && !isDialogWindow) { if (!isNormalWindow && !isDialogWindow) {
return; return null;
}
// There is the weird case where an animation is already ongoing. This happens when a
// window is closed which has been created before the session was started (e.g. when
// GNOME Shell has been restarted in the meantime).
const oldShader = actor.get_effect('burn-my-windows-effect');
if (oldShader) {
actor.remove_effect(oldShader);
oldShader.endAnimation();
oldShader.returnToFactory();
} }
// ----------------------------------------------- choose a profile and then an effect // ----------------------------------------------- choose a profile and then an effect
@@ -556,11 +516,23 @@ class Extension {
// If nothing was enabled, we have to do nothing :) // If nothing was enabled, we have to do nothing :)
if (!effect || !profile) { if (!effect || !profile) {
return; return null;
} }
return {effect: effect, profile: profile};
}
// ----------------------------------------------------------- tweak actor transitions // This method adds the given effect using the settings from the given profile to the
// given actor.
_setupEffect(actor, forOpening, effect, profile) {
// There is the weird case where an animation is already ongoing. This happens when a
// window is closed which has been created before the session was started (e.g. when
// GNOME Shell has been restarted in the meantime).
const oldShader = actor.get_effect('burn-my-windows-effect');
if (oldShader) {
oldShader.endAnimation();
}
// If we are currently performing integration test, all animations are set to a fixed // If we are currently performing integration test, all animations are set to a fixed
// duration and show a fixed frame from the middle of the animation. // duration and show a fixed frame from the middle of the animation.
@@ -572,97 +544,60 @@ class Extension {
// actorScale. // actorScale.
const actorScale = effect.getActorScale(profile.settings, forOpening, actor); const actorScale = effect.getActorScale(profile.settings, forOpening, actor);
// All scaling is relative to the window's center.
actor.set_pivot_point(0.5, 0.5);
actor.opacity = 255;
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 && utils.shellVersionIsAtLeast(3, 38)) {
actor._bmwOverviewClone.overlayEnabled = false;
actor._bmwOverviewCloneContainer.set_pivot_point(0.5, 0.5);
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();
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 && utils.shellVersionIsAtLeast(3, 38)) {
actor._bmwOverviewClone.overlayEnabled = true;
actor._bmwOverviewCloneContainer.scale_x = 1.0;
actor._bmwOverviewCloneContainer.scale_y = 1.0;
}
// Remove the shader and mark it being re-usable for future animations.
actor.remove_effect(shader);
shader.returnToFactory();
// Finally, 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);
}
});
// To make things deterministic during testing, we set the effect duration to 5 // To make things deterministic during testing, we set the effect duration to 5
// seconds. // seconds.
const duration = const duration =
testMode ? 5000 : profile.settings.get_int(effect.getNick() + '-animation-time'); testMode ? 5000 : profile.settings.get_int(effect.getNick() + '-animation-time');
// All animations are relative to the window's center. // Finally start the animation!
actor.set_pivot_point(0.5, 0.5); shader.beginAnimation(profile.settings, forOpening, testMode, duration, actor);
// We tweak the opacity and scale of the actor. If there is no ongoing transition for
// a property, a new one is set up.
const config = {'opacity': 255, 'scale-x': actorScale.x, 'scale-y': actorScale.y};
for (const property in config) {
let transition = actor.get_transition(property);
// If there is currently no ongoing transition, we create a new one. Clutter does
// not like to create transitions with the same start and end value - however, we
// need at least one transition for our progress value in the shader. So we trick
// Clutter by creating an arbitrary transition first and then modifying the start
// and end values according to our config object.
if (!transition) {
actor.set_property(property, 0);
actor.save_easing_state();
actor.set_easing_duration(1000);
actor.set_property(property, 1);
actor.restore_easing_state();
// Now there should be a transition!
transition = actor.get_transition(property);
}
// Tweak the transition according to the config object. For some reason, there are
// rare cases, where no transition is set up. This happens from time to time...
if (transition) {
transition.set_duration(duration);
transition.set_to(config[property]);
transition.set_from(config[property]);
transition.set_progress_mode(Clutter.AnimationMode.LINEAR);
}
}
// Once the transitions are finished, we restore the original actor size.
if (forOpening) {
const connectionID = actor.connect('transitions-completed', () => {
actor.scale_x = 1.0;
actor.scale_y = 1.0;
actor.disconnect(connectionID);
});
}
// -------------------------------------------------------------------- add the shader
// Now add a cool shader to our window actor!
const shader = effect.shaderFactory.getShader();
// There should always be an opacity transition going on...
const transition = actor.get_transition('opacity');
if (!transition) {
utils.debug('Cannot setup shader without opacity transition.')
return;
}
// Assign the effect to the window actor!
actor.add_effect_with_name('burn-my-windows-effect', shader);
// Set one-time uniforms.
shader.beginAnimation(profile.settings, forOpening, testMode, duration * 0.001,
actor);
// Set other uniforms each frame.
transition.connect('new-frame', (t) => {
if (testMode) {
shader.updateAnimation(0.5);
} else {
shader.updateAnimation(t.get_progress());
}
});
// Remove the effect if the animation finished or was interrupted.
if (forOpening) {
transition.connect('stopped', () => {
const oldShader = actor.get_effect('burn-my-windows-effect');
if (oldShader) {
actor.remove_effect(oldShader);
oldShader.endAnimation();
oldShader.returnToFactory();
}
});
}
} }
// This is required to enable window-close animations in the overview. See the comment // This is required to enable window-close animations in the overview. See the comment
@@ -676,11 +611,9 @@ class Extension {
// This was called "realWindow" in GNOME 3.36. // This was called "realWindow" in GNOME 3.36.
const propertyName = utils.shellVersionIs(3, 36) ? 'realWindow' : '_windowActor'; const propertyName = utils.shellVersionIs(3, 36) ? 'realWindow' : '_windowActor';
const actor = workspace._windows[index][propertyName]; const actor = workspace._windows[index][propertyName];
if (!actor.get_transition('scale-y')) { const shader = actor.get_effect('burn-my-windows-effect');
return true;
}
return false; return shader == null;
} }
} }
+43 -4
View File
@@ -17,6 +17,7 @@
const {Gio, Shell, GObject, Clutter} = imports.gi; const {Gio, Shell, GObject, Clutter} = imports.gi;
const ByteArray = imports.byteArray; const ByteArray = imports.byteArray;
const Main = imports.ui.main;
const ExtensionUtils = imports.misc.extensionUtils; const ExtensionUtils = imports.misc.extensionUtils;
const Me = imports.misc.extensionUtils.getCurrentExtension(); const Me = imports.misc.extensionUtils.getCurrentExtension();
const utils = Me.imports.src.utils; const utils = Me.imports.src.utils;
@@ -36,12 +37,14 @@ const utils = Me.imports.src.utils;
// hard-coded use of straight alpha (as opposed to premultiplied). This makes the // // hard-coded use of straight alpha (as opposed to premultiplied). This makes the //
// shaders a bit more complicated than required. // // 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 // // * 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 // // be used to set uniform values which do not change during the //
// animation. // // animation. //
// * update-animation: This is called at each frame during the animation. It can be // // * update-animation: This is called at each frame during the animation. It can be //
// used to set uniforms which change during the animation. // // 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( var Shader = GObject.registerClass(
@@ -77,13 +80,42 @@ var Shader = GObject.registerClass(
this._uDuration = this.get_uniform_location('uDuration'); this._uDuration = this.get_uniform_location('uDuration');
this._uSize = this.get_uniform_location('uSize'); this._uSize = this.get_uniform_location('uSize');
this._uPadding = this.get_uniform_location('uPadding'); this._uPadding = this.get_uniform_location('uPadding');
// Create a timeline to drive the animation.
this._timeline = new Clutter.Timeline();
// Call updateAnimation() once a frame.
this._timeline.connect('new-frame', (t) => {
if (this._testMode) {
this.updateAnimation(0.5);
} else {
this.updateAnimation(t.get_progress());
}
});
// Clean up if the animation finished or was interrupted.
this._timeline.connect('stopped', (t, finished) => {
this.endAnimation();
});
} }
// This is called once each time the shader is used. // This is called once each time the shader is used.
beginAnimation(settings, forOpening, testMode, duration, actor) { beginAnimation(settings, forOpening, testMode, duration, actor) {
if (this._timeline.is_playing()) {
this._timeline.stop();
}
// On GNOME 3.36 this method was not yet available.
if (this._timeline.set_actor) {
this._timeline.set_actor(actor);
}
this._timeline.set_duration(duration);
this._timeline.start();
// Reset progress value. // Reset progress value.
this._progress = 0; this._progress = 0;
this._testMode = testMode;
// This is not necessarily symmetric, but I haven't figured out a way to // This is not necessarily symmetric, but I haven't figured out a way to
// get the actual values... // get the actual values...
@@ -91,7 +123,7 @@ var Shader = GObject.registerClass(
this.set_uniform_float(this._uPadding, 1, [padding]); this.set_uniform_float(this._uPadding, 1, [padding]);
this.set_uniform_float(this._uForOpening, 1, [forOpening]); this.set_uniform_float(this._uForOpening, 1, [forOpening]);
this.set_uniform_float(this._uDuration, 1, [duration]); this.set_uniform_float(this._uDuration, 1, [duration * 0.001]);
this.set_uniform_float(this._uSize, 2, [actor.width, actor.height]); this.set_uniform_float(this._uSize, 2, [actor.width, actor.height]);
this.emit('begin-animation', settings, forOpening, testMode, actor); this.emit('begin-animation', settings, forOpening, testMode, actor);
@@ -103,11 +135,18 @@ var Shader = GObject.registerClass(
// in vfunc_paint_target. We do not emit it here, as the pipeline which may be used // in vfunc_paint_target. We do not emit it here, as the pipeline which may be used
// by handlers must not have been created yet. // by handlers must not have been created yet.
this._progress = progress; this._progress = progress;
this.queue_repaint();
} }
// This will just emit the end-animation signal. It can be used to clean up any // This will stop any running animation and emit the end-animation signal.
// resources required during the animation.
endAnimation() { endAnimation() {
// This will call endAnimation() again, so we can return for now.
if (this._timeline.is_playing()) {
this._timeline.stop();
return;
}
this.emit('end-animation'); this.emit('end-animation');
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 643 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 643 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Some files were not shown because too many files have changed in this diff Show More