🔨 Initial attempt on window-opening animation
This commit is contained in:
@@ -150,12 +150,19 @@ var SimpleFade = class SimpleFade {
|
|||||||
return new Shader(settings);
|
return new Shader(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
// This is also called from extension.js. It is used to tweak a window's open / close
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
|
||||||
// GNOME Shell. For each property, you can set a "from", "to", and a "mode". For this
|
// forOpening is set to true if this is called for a window-open transition, for a
|
||||||
// effect, windows should neither be scaled nor faded.
|
// window-close transition it is set to false. The modes can be set to any value from
|
||||||
static getCloseTransition(actor, settings) {
|
// here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
|
||||||
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 1.0}};
|
// determines how the uProgress uniform value will progress in the shader.
|
||||||
|
// For this effect, windows should neither be scaled nor faded.
|
||||||
|
static tweakTransition(actor, settings, forOpening) {
|
||||||
|
return {
|
||||||
|
'opacity': {from: 255, to: 255, mode: 4},
|
||||||
|
'scale-x': {from: 1.0, to: 1.0, mode: 4},
|
||||||
|
'scale-y': {from: 1.0, to: 1.0, mode: 4}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+223
-169
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
const {Clutter, Gio, Meta} = imports.gi;
|
const {Clutter, Gio, Meta} = imports.gi;
|
||||||
|
|
||||||
|
const Main = imports.ui.main;
|
||||||
const Workspace = imports.ui.workspace.Workspace;
|
const Workspace = imports.ui.workspace.Workspace;
|
||||||
const WindowManager = imports.ui.windowManager.WindowManager;
|
const WindowManager = imports.ui.windowManager.WindowManager;
|
||||||
|
|
||||||
@@ -43,13 +44,12 @@ const ALL_EFFECTS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// This extensions modifies the window-close animation to look like the window was set //
|
// This extensions modifies the window-close and window-open animations with all kinds //
|
||||||
// on fire. There are also a few other effects available. All of them are implemented //
|
// of effects. The effects are implemented using GLSL shaders which are applied to the //
|
||||||
// using GLSL shaders which are applied to the window's Clutter.Actor. The extension is //
|
// window's Clutter.Actor. The extension is actually very simple, much of the //
|
||||||
// actually very simple, most of the complexity comes from the fact that GNOME Shell //
|
// complexity comes from the fact that GNOME Shell usually does not show an animation //
|
||||||
// usually does not show an animation when a window is closed in the overview. Several //
|
// when a window is closed in the overview. Several methods need to be monkey-patched //
|
||||||
// methods need to be monkey-patched to get this working. For more details, read the //
|
// to get this working. For more details, read the other comments in this file... //
|
||||||
// other comments in this file... //
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class Extension {
|
class Extension {
|
||||||
@@ -68,30 +68,82 @@ class Extension {
|
|||||||
this._settings = ExtensionUtils.getSettings();
|
this._settings = ExtensionUtils.getSettings();
|
||||||
|
|
||||||
// This will store an item of ALL_EFFECTS which was used the last time a window was
|
// This will store an item of ALL_EFFECTS which was used the last time a window was
|
||||||
// closed.
|
// opened / closed.
|
||||||
this._effect = 0;
|
this._currentEffect = 0;
|
||||||
|
|
||||||
// We will monkey-patch these three methods. Let's store the original ones.
|
// We will use extensionThis to refer to the extension inside the patched methods.
|
||||||
|
const extensionThis = this;
|
||||||
|
|
||||||
|
// We will monkey-patch these methods. Let's store the original ones.
|
||||||
|
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._origAddWindowClone = Workspace.prototype._addWindowClone;
|
|
||||||
this._origShouldAnimateActor = WindowManager.prototype._shouldAnimateActor;
|
this._origShouldAnimateActor = WindowManager.prototype._shouldAnimateActor;
|
||||||
|
|
||||||
// We will also override these animation times.
|
// We will also override these animation times.
|
||||||
this._origWindowTime = imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME;
|
this._origWindowTime = imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME;
|
||||||
this._origDialogTime = imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME;
|
this._origDialogTime = imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME;
|
||||||
|
|
||||||
// Reset the dialog destroy time if the corresponding setting gets disabled.
|
Workspace.prototype._addWindowClone = function(...params) {
|
||||||
this._settings.connect('changed::destroy-dialogs', () => {
|
const result = extensionThis._origAddWindowClone.apply(this, params);
|
||||||
if (!this._settings.get_boolean('destroy-dialogs')) {
|
|
||||||
imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME =
|
const clone = utils.shellVersionIs(3, 36) ? result[0] : result;
|
||||||
this._origDialogTime;
|
const window = params[0].get_compositor_private();
|
||||||
}
|
|
||||||
});
|
const xID = window.connect('notify::scale-x', () => {
|
||||||
|
if (window.scale_x > 0) {
|
||||||
|
clone.window_container.scale_x = window.scale_x;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const yID = window.connect('notify::scale-y', () => {
|
||||||
|
if (window.scale_y > 0) {
|
||||||
|
clone.window_container.scale_y = window.scale_y;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
clone.window_container.connect('destroy', () => {
|
||||||
|
window.disconnect(xID);
|
||||||
|
window.disconnect(yID);
|
||||||
|
});
|
||||||
|
|
||||||
|
// On GNOME 3.36, the window clone's 'destroy' handler only calls _removeWindowClone
|
||||||
|
// but not _doRemoveWindow. The latter is required to trigger the repositioning of
|
||||||
|
// the overview window layout. Therefore we call this method in addition.
|
||||||
|
// 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#L1415
|
||||||
|
if (utils.shellVersionIs(3, 36)) {
|
||||||
|
clone.connect('destroy', () => this._doRemoveWindow(clone.metaWindow));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
this._windowCreatedConnection =
|
||||||
|
global.display.connect('window-created', (d, metaWin) => {
|
||||||
|
let actor = metaWin.get_compositor_private();
|
||||||
|
|
||||||
|
if (Main.overview.visible && !Main.overview.closing) {
|
||||||
|
utils.debug('window-created: setup effect on show');
|
||||||
|
const id = actor.connect('show', () => {
|
||||||
|
extensionThis._setupEffect(actor, true);
|
||||||
|
actor.disconnect(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
utils.debug('window-created: setup effect on ease');
|
||||||
|
const orig = actor.ease;
|
||||||
|
actor.ease = function(...params) {
|
||||||
|
orig.apply(actor, params);
|
||||||
|
actor.ease = orig;
|
||||||
|
|
||||||
|
extensionThis._setupEffect(actor, true);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// We will use extensionThis to refer to the extension inside the patched methods of
|
|
||||||
// the WorkspacesView.
|
|
||||||
const extensionThis = this;
|
|
||||||
|
|
||||||
// This class is only available in GNOME Shell 3.38+. So no transition tweaking in
|
// This class is only available in GNOME Shell 3.38+. So no transition tweaking in
|
||||||
// GNOME Shell 3.36, but this is not used by any effect available there anyways for
|
// GNOME Shell 3.36, but this is not used by any effect available there anyways for
|
||||||
@@ -111,26 +163,15 @@ class Extension {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// When a window is removed from the overview, we need adjust the transitions of the
|
|
||||||
// window clone according to the chosen effect. We do this in the 'unmanaged' signal
|
|
||||||
// of the WindowPreview's Meta.Window. This is not ideal, as it does not work for
|
|
||||||
// dialogs which close themselves... Maybe there's a better way?
|
|
||||||
WindowPreview.prototype._init = function(...params) {
|
WindowPreview.prototype._init = function(...params) {
|
||||||
// Call the original method.
|
// Call the original method.
|
||||||
extensionThis._origInit.apply(this, params);
|
extensionThis._origInit.apply(this, params);
|
||||||
|
|
||||||
// When the user clicks the X in the overview, the window is not deleted
|
|
||||||
// immediately. However, as soon as the window is really deleted, we need to
|
|
||||||
// adjust the transition of its clone.
|
|
||||||
const connectionID = this.metaWindow.connect('unmanaged', () => {
|
const connectionID = this.metaWindow.connect('unmanaged', () => {
|
||||||
if (this.window_container) {
|
if (this.window_container) {
|
||||||
// Hide the window's icon, name, and close button.
|
// Hide the window's icon, name, and close button.
|
||||||
this.overlayEnabled = false;
|
this.overlayEnabled = false;
|
||||||
this._icon.visible = false;
|
this._icon.visible = false;
|
||||||
|
|
||||||
const transitionConfig = extensionThis._effect.getCloseTransition(
|
|
||||||
this.window_container, extensionThis._settings);
|
|
||||||
extensionThis._tweakTransitions(this.window_container, transitionConfig);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -151,19 +192,6 @@ class Extension {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// On GNOME 3.36, the window clone's 'destroy' handler only calls _removeWindowClone
|
|
||||||
// but not _doRemoveWindow. The latter is required to trigger the repositioning of the
|
|
||||||
// overview window layout. Therefore we call this method in addition.
|
|
||||||
// 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#L1415
|
|
||||||
if (utils.shellVersionIs(3, 36)) {
|
|
||||||
Workspace.prototype._addWindowClone = function(...params) {
|
|
||||||
const [clone, overlay] = extensionThis._origAddWindowClone.apply(this, params);
|
|
||||||
clone.connect('destroy', () => this._doRemoveWindow(clone.metaWindow));
|
|
||||||
return [clone, overlay];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// These three method overrides are mega-hacky! They are only required to make the
|
// These three method overrides are mega-hacky! They are only required to make the
|
||||||
// fire animation work in the overview. Usually, windows are not faded when closed
|
// fire animation work in the overview. Usually, windows are not faded when closed
|
||||||
// from the overview (why?). With these overrides we make sure that they are actually
|
// from the overview (why?). With these overrides we make sure that they are actually
|
||||||
@@ -205,92 +233,7 @@ class Extension {
|
|||||||
// As we cannot monkey-patch the _destroyWindow itself, we connect to the 'destroy'
|
// 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.
|
// signal of the window manager and tweak the animation to our needs.
|
||||||
this._destroyConnection = global.window_manager.connect('destroy', (wm, actor) => {
|
this._destroyConnection = global.window_manager.connect('destroy', (wm, actor) => {
|
||||||
// The _destroyWindow method of WindowManager, which was called right before this
|
this._setupEffect(actor, false);
|
||||||
// one, set up the window close animation. This usually fades-out the window and
|
|
||||||
// scales it a bit down. If no transition is in progress, something unexpected
|
|
||||||
// happened. We rather try not to burn the window!
|
|
||||||
const transition = actor.get_transition('scale-y');
|
|
||||||
if (!transition) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We do nothing if a dialog got closed and we should not burn them.
|
|
||||||
const shouldDestroyDialogs = this._settings.get_boolean('destroy-dialogs');
|
|
||||||
const isDialogWindow =
|
|
||||||
actor.meta_window.window_type == Meta.WindowType.MODAL_DIALOG ||
|
|
||||||
actor.meta_window.window_type == Meta.WindowType.DIALOG;
|
|
||||||
|
|
||||||
// If an effect is to be previewed, we have to affect dialogs es well. This is
|
|
||||||
// because the preview window is a dialog window...
|
|
||||||
const previewNick = this._settings.get_string('close-preview-effect');
|
|
||||||
|
|
||||||
if (isDialogWindow && !shouldDestroyDialogs && previewNick == '') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we have to choose an effect.
|
|
||||||
this._effect = null;
|
|
||||||
|
|
||||||
// First we check if an effect is to be previewed.
|
|
||||||
if (previewNick != '') {
|
|
||||||
this._effect = ALL_EFFECTS.find(Effect => {
|
|
||||||
return Effect.getNick() == previewNick;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Only preview the effect once.
|
|
||||||
this._settings.set_string('close-preview-effect', '');
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// Else we choose a random effect from all enabled effects. Therefore, we first
|
|
||||||
// create a list of all currently enabled effects.
|
|
||||||
const enabled = ALL_EFFECTS.filter(Effect => {
|
|
||||||
return this._settings.get_boolean(`${Effect.getNick()}-close-effect`);
|
|
||||||
});
|
|
||||||
|
|
||||||
// And then choose a random effect.
|
|
||||||
if (enabled.length > 0) {
|
|
||||||
this._effect = enabled[Math.floor(Math.random() * enabled.length)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If nothing was enabled, we have to do nothing :)
|
|
||||||
if (this._effect == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The effect usually will choose to override the present transitions on the actor.
|
|
||||||
const transitionConfig = this._effect.getCloseTransition(actor, this._settings);
|
|
||||||
this._tweakTransitions(actor, transitionConfig);
|
|
||||||
|
|
||||||
// Add a cool shader to our window actor!
|
|
||||||
const shader = this._effect.createShader(actor, this._settings);
|
|
||||||
|
|
||||||
if (shader) {
|
|
||||||
actor.add_effect(shader);
|
|
||||||
|
|
||||||
// Update uniforms at each frame.
|
|
||||||
transition.connect('new-frame', (t) => {
|
|
||||||
shader.set_uniform_value('uProgress', t.get_progress());
|
|
||||||
shader.set_uniform_value('uTime', 0.001 * t.get_elapsed_time());
|
|
||||||
shader.set_uniform_value('uSizeX', actor.width);
|
|
||||||
shader.set_uniform_value('uSizeY', actor.height);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// The code below is not necessary for Burn-My-Windows to function. However, there
|
|
||||||
// are some extensions such as "Show Application View When Workspace Empty"
|
|
||||||
// https://extensions.gnome.org/extension/2036/show-application-view-when-workspace-empty/
|
|
||||||
// which do something *after* a window was closed. As the window-close animation
|
|
||||||
// duration depends on the used effect, this may vary each time a window is closed.
|
|
||||||
// We set the currently used time here, so that others can get an idea how long this
|
|
||||||
// will take...
|
|
||||||
const duration = transition.get_duration();
|
|
||||||
if (isDialogWindow && shouldDestroyDialogs) {
|
|
||||||
imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME = duration;
|
|
||||||
} else {
|
|
||||||
imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME = duration;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,12 +244,13 @@ class Extension {
|
|||||||
// Unregister our resources.
|
// Unregister our resources.
|
||||||
Gio.resources_unregister(this._resources);
|
Gio.resources_unregister(this._resources);
|
||||||
|
|
||||||
// Restore the original behavior.
|
// Restore the original window-open and window-close animations.
|
||||||
global.window_manager.disconnect(this._destroyConnection);
|
global.window_manager.disconnect(this._destroyConnection);
|
||||||
|
global.display.disconnect(this._windowCreatedConnection);
|
||||||
|
|
||||||
|
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;
|
||||||
Workspace.prototype._addWindowClone = this._origAddWindowClone;
|
|
||||||
WindowManager.prototype._shouldAnimateActor = this._origShouldAnimateActor;
|
WindowManager.prototype._shouldAnimateActor = this._origShouldAnimateActor;
|
||||||
|
|
||||||
imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME = this._origWindowTime;
|
imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME = this._origWindowTime;
|
||||||
@@ -323,6 +267,152 @@ class Extension {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- private stuff
|
// ----------------------------------------------------------------------- private stuff
|
||||||
|
|
||||||
|
_setupEffect(actor, forOpening) {
|
||||||
|
const isNormalWindow = actor.meta_window.window_type == Meta.WindowType.NORMAL;
|
||||||
|
const isDialogWindow =
|
||||||
|
actor.meta_window.window_type == Meta.WindowType.MODAL_DIALOG ||
|
||||||
|
actor.meta_window.window_type == Meta.WindowType.DIALOG;
|
||||||
|
|
||||||
|
if (!isNormalWindow && !isDialogWindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We do nothing if a dialog got closed and we should not burn them.
|
||||||
|
const shouldDestroyDialogs = this._settings.get_boolean('destroy-dialogs');
|
||||||
|
|
||||||
|
// If an effect is to be previewed, we have to affect dialogs es well. This is
|
||||||
|
// because the preview window is a dialog window...
|
||||||
|
const action = forOpening ? 'open' : 'close';
|
||||||
|
const previewNick = this._settings.get_string(action + '-preview-effect');
|
||||||
|
|
||||||
|
if (isDialogWindow && !shouldDestroyDialogs && previewNick == '') {
|
||||||
|
this._fixAnimationTimes(isDialogWindow, forOpening, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------ choose an effect
|
||||||
|
|
||||||
|
this._currentEffect = null;
|
||||||
|
|
||||||
|
if (previewNick != '') {
|
||||||
|
this._currentEffect = ALL_EFFECTS.find(Effect => {
|
||||||
|
return Effect.getNick() == previewNick;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Only preview the effect once.
|
||||||
|
this._settings.set_string(action + '-preview-effect', '');
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Else we choose a random effect from all enabled effects. Therefore, we first
|
||||||
|
// create a list of all currently enabled effects.
|
||||||
|
const enabled = ALL_EFFECTS.filter(Effect => {
|
||||||
|
return this._settings.get_boolean(`${Effect.getNick()}-${action}-effect`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// And then choose a random effect.
|
||||||
|
if (enabled.length > 0) {
|
||||||
|
this._currentEffect = enabled[Math.floor(Math.random() * enabled.length)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If nothing was enabled, we have to do nothing :)
|
||||||
|
if (this._currentEffect == null) {
|
||||||
|
this._fixAnimationTimes(isDialogWindow, forOpening, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------- tweak actor transitions
|
||||||
|
|
||||||
|
// This is used to tweak the ongoing transitions of a window actor. This is either the
|
||||||
|
// actual actor of the Meta.Window or a clone in the overview. Usually windows are
|
||||||
|
// faded in / out scaled up / down slightly by GNOME Shell. Here, we allow
|
||||||
|
// modifications to this behavior by the effects. The given config object is created
|
||||||
|
// by the effect's tweakTransition() method.
|
||||||
|
const config = this._currentEffect.tweakTransition(actor, this._settings, forOpening);
|
||||||
|
const duration =
|
||||||
|
this._settings.get_int(this._currentEffect.getNick() + '-animation-time');
|
||||||
|
|
||||||
|
actor.set_pivot_point(0.5, 0.5);
|
||||||
|
|
||||||
|
for (const property in config) {
|
||||||
|
const from = config[property].from;
|
||||||
|
const to = config[property].to;
|
||||||
|
const mode = config[property].mode;
|
||||||
|
|
||||||
|
let transition = actor.get_transition(property);
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
transition = actor.get_transition(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!transition) {
|
||||||
|
this._fixAnimationTimes(isDialogWindow, forOpening, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
transition.set_duration(duration);
|
||||||
|
transition.set_to(to);
|
||||||
|
transition.set_from(from);
|
||||||
|
transition.set_progress_mode(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
const transition = actor.get_transition('scale-y');
|
||||||
|
transition.connect('completed', () => {
|
||||||
|
actor.scale_x = 1.0;
|
||||||
|
actor.scale_y = 1.0;
|
||||||
|
});
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------- add the shader
|
||||||
|
|
||||||
|
// Add a cool shader to our window actor!
|
||||||
|
const shader = this._currentEffect.createShader(actor, this._settings, forOpening);
|
||||||
|
|
||||||
|
if (shader) {
|
||||||
|
actor.remove_effect_by_name(`burn-my-windows-effect`);
|
||||||
|
actor.add_effect_with_name(`burn-my-windows-effect`, shader);
|
||||||
|
|
||||||
|
// Update uniforms at each frame.
|
||||||
|
transition.connect('new-frame', (t) => {
|
||||||
|
shader.set_uniform_value('uProgress', t.get_progress());
|
||||||
|
shader.set_uniform_value('uTime', 0.001 * t.get_elapsed_time());
|
||||||
|
shader.set_uniform_value('uSizeX', actor.width);
|
||||||
|
shader.set_uniform_value('uSizeY', actor.height);
|
||||||
|
});
|
||||||
|
|
||||||
|
transition.connect('completed', () => {
|
||||||
|
actor.remove_effect_by_name(`burn-my-windows-effect`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this._fixAnimationTimes(isDialogWindow, forOpening, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The code below is not necessary for Burn-My-Windows to function. However, there
|
||||||
|
// are some extensions such as "Show Application View When Workspace Empty"
|
||||||
|
// https://extensions.gnome.org/extension/2036/show-application-view-when-workspace-empty/
|
||||||
|
// which do something *after* a window was closed. As the window-close animation
|
||||||
|
// duration depends on the used effect, this may vary each time a window is
|
||||||
|
// closed. We set the currently used time here, so that others can get an idea how
|
||||||
|
// long this will take...
|
||||||
|
_fixAnimationTimes(isDialogWindow, forOpening, duration) {
|
||||||
|
if (!forOpening) {
|
||||||
|
if (isDialogWindow) {
|
||||||
|
imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME =
|
||||||
|
duration != null ? duration : this._origDialogTime;
|
||||||
|
} else {
|
||||||
|
imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME =
|
||||||
|
duration != null ? duration : this._origWindowTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
// for Workspace.prototype._windowRemoved above for an explanation.
|
// for Workspace.prototype._windowRemoved above for an explanation.
|
||||||
_shouldDestroy(workspace, metaWindow) {
|
_shouldDestroy(workspace, metaWindow) {
|
||||||
@@ -340,42 +430,6 @@ class Extension {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is used to tweak the ongoing transitions of a window actor. This is either the
|
|
||||||
// actual actor of the Meta.Window or a clone in the overview. Usually windows are faded
|
|
||||||
// to transparency and scaled down slightly by GNOME Shell. Here, we allow modifications
|
|
||||||
// to this behavior by the effects.
|
|
||||||
_tweakTransitions(actor, config) {
|
|
||||||
const duration = this._settings.get_int(this._effect.getNick() + '-animation-time');
|
|
||||||
|
|
||||||
for (const property in config) {
|
|
||||||
const from = config[property].from;
|
|
||||||
const to = config[property].to;
|
|
||||||
const mode = config[property].mode;
|
|
||||||
|
|
||||||
const transition = actor.get_transition(property);
|
|
||||||
|
|
||||||
if (transition) {
|
|
||||||
transition.set_duration(duration);
|
|
||||||
|
|
||||||
if (to != undefined) transition.set_to(to);
|
|
||||||
if (from != undefined) transition.set_from(from);
|
|
||||||
if (mode != undefined) transition.set_progress_mode(mode);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (from != undefined) actor[property] = from;
|
|
||||||
|
|
||||||
if (to != undefined) {
|
|
||||||
actor.save_easing_state();
|
|
||||||
actor.set_easing_duration(duration)
|
|
||||||
if (mode != undefined) actor.set_easing_mode(mode);
|
|
||||||
actor[property] = to;
|
|
||||||
actor.restore_easing_state();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is called once when the extension is loaded, not enabled.
|
// This function is called once when the extension is loaded, not enabled.
|
||||||
|
|||||||
+20
-13
@@ -79,17 +79,21 @@ var BrokenGlass = class BrokenGlass {
|
|||||||
// ---------------------------------------------------------------- API for extension.js
|
// ---------------------------------------------------------------- API for extension.js
|
||||||
|
|
||||||
// This is called from extension.js whenever a window is closed with this effect.
|
// This is called from extension.js whenever a window is closed with this effect.
|
||||||
static createShader(actor, settings) {
|
static createShader(actor, settings, forOpening) {
|
||||||
return new Shader(actor, settings);
|
return new Shader(actor, settings, forOpening);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
// This is also called from extension.js. It is used to tweak a window's open / close
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
|
||||||
// GNOME Shell. For this effect, windows are set to twice their original size, so that
|
// forOpening is set to true if this is called for a window-open transition, for a
|
||||||
|
// window-close transition it is set to false. The modes can be set to any value from
|
||||||
|
// here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
|
||||||
|
// determines how the uProgress uniform value will progress in the shader.
|
||||||
|
// For this effect, windows are set to twice their original size, so that
|
||||||
// we have some space to draw the shards. We also set the animation mode to "Linear".
|
// we have some space to draw the shards. We also set the animation mode to "Linear".
|
||||||
static getCloseTransition(actor, settings) {
|
static tweakTransition(actor, settings, forOpening) {
|
||||||
return {
|
return {
|
||||||
'opacity': {to: 255, mode: 1},
|
'opacity': {from: 255, to: 255, mode: 1},
|
||||||
'scale-x': {from: 2.0, to: 2.0, mode: 1},
|
'scale-x': {from: 2.0, to: 2.0, mode: 1},
|
||||||
'scale-y': {from: 2.0, to: 2.0, mode: 1}
|
'scale-y': {from: 2.0, to: 2.0, mode: 1}
|
||||||
};
|
};
|
||||||
@@ -118,7 +122,7 @@ if (utils.isInShellProcess()) {
|
|||||||
// resources/img/shards.png. The red channel of the texture contains the distance to the
|
// resources/img/shards.png. The red channel of the texture contains the distance to the
|
||||||
// shard edges. This information is used to fade out the shards.
|
// shard edges. This information is used to fade out the shards.
|
||||||
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
||||||
_init(actor, settings) {
|
_init(actor, settings, forOpening) {
|
||||||
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
||||||
|
|
||||||
// Load the shards texture. As the shader is re-created for each window animation,
|
// Load the shards texture. As the shader is re-created for each window animation,
|
||||||
@@ -151,16 +155,19 @@ if (utils.isInShellProcess()) {
|
|||||||
const vec2 SEED = vec2(${Math.random()}, ${Math.random()});
|
const vec2 SEED = vec2(${Math.random()}, ${Math.random()});
|
||||||
const float SHARD_SCALE = ${settings.get_double('broken-glass-scale')};
|
const float SHARD_SCALE = ${settings.get_double('broken-glass-scale')};
|
||||||
const float SHARD_LAYERS = 5;
|
const float SHARD_LAYERS = 5;
|
||||||
const float GRAVITY = ${settings.get_double('broken-glass-gravity')};
|
|
||||||
const float BLOW_FORCE = ${settings.get_double('broken-glass-blow-force')};
|
const float BLOW_FORCE = ${settings.get_double('broken-glass-blow-force')};
|
||||||
const float ACTOR_SCALE = 2.0;
|
const float ACTOR_SCALE = 2.0;
|
||||||
const float PADDING = ACTOR_SCALE / 2.0 - 0.5;
|
const float PADDING = ACTOR_SCALE / 2.0 - 0.5;
|
||||||
const vec2 EPICENTER = vec2(${epicenterX}, ${epicenterY});
|
const vec2 EPICENTER = vec2(${epicenterX}, ${epicenterY});
|
||||||
|
const float GRAVITY = ${forOpening ? '-1.0' : '1.0'} *
|
||||||
|
${settings.get_double('broken-glass-gravity')};
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
|
||||||
cogl_color_out = vec4(0, 0, 0, 0);
|
cogl_color_out = vec4(0, 0, 0, 0);
|
||||||
|
|
||||||
|
float progress = ${forOpening ? '1.0-uProgress' : 'uProgress'};
|
||||||
|
|
||||||
// Draw the individual shard layers.
|
// Draw the individual shard layers.
|
||||||
for (float i=0; i<SHARD_LAYERS; ++i) {
|
for (float i=0; i<SHARD_LAYERS; ++i) {
|
||||||
|
|
||||||
@@ -173,15 +180,15 @@ if (utils.isInShellProcess()) {
|
|||||||
coords -= EPICENTER;
|
coords -= EPICENTER;
|
||||||
|
|
||||||
// Scale each layer a bit differently.
|
// Scale each layer a bit differently.
|
||||||
coords /= mix(1.0, 1.0 + BLOW_FORCE*(i+2)/SHARD_LAYERS, uProgress);
|
coords /= mix(1.0, 1.0 + BLOW_FORCE*(i+2)/SHARD_LAYERS, progress);
|
||||||
|
|
||||||
// Rotate each layer a bit differently.
|
// Rotate each layer a bit differently.
|
||||||
float rotation = (mod(i, 2.0)-0.5)*0.2*uProgress;
|
float rotation = (mod(i, 2.0)-0.5)*0.2*progress;
|
||||||
coords = vec2(coords.x * cos(rotation) - coords.y * sin(rotation),
|
coords = vec2(coords.x * cos(rotation) - coords.y * sin(rotation),
|
||||||
coords.x * sin(rotation) + coords.y * cos(rotation));
|
coords.x * sin(rotation) + coords.y * cos(rotation));
|
||||||
|
|
||||||
// Move down each layer a bit.
|
// Move down each layer a bit.
|
||||||
float gravity = GRAVITY*0.1*(i+1)*uProgress*uProgress;
|
float gravity = GRAVITY*0.1*(i+1)*progress*progress;
|
||||||
coords += vec2(0, gravity);
|
coords += vec2(0, gravity);
|
||||||
|
|
||||||
// Restore correct position.
|
// Restore correct position.
|
||||||
@@ -200,7 +207,7 @@ if (utils.isInShellProcess()) {
|
|||||||
vec4 windowColor = texture2D(uTexture, coords);
|
vec4 windowColor = texture2D(uTexture, coords);
|
||||||
|
|
||||||
// Dissolve the shard by using distance information from the red channel.
|
// Dissolve the shard by using distance information from the red channel.
|
||||||
float dissolve = (shardMap.x - pow(uProgress+0.1, 2)) > 0 ? 1: 0;
|
float dissolve = (shardMap.x - pow(progress+0.1, 2)) > 0 ? 1: 0;
|
||||||
cogl_color_out = mix(cogl_color_out, windowColor, dissolve);
|
cogl_color_out = mix(cogl_color_out, windowColor, dissolve);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-8
@@ -74,15 +74,23 @@ var EnergizeA = class EnergizeA {
|
|||||||
// ---------------------------------------------------------------- API for extension.js
|
// ---------------------------------------------------------------- API for extension.js
|
||||||
|
|
||||||
// This is called from extension.js whenever a window is closed with this effect.
|
// This is called from extension.js whenever a window is closed with this effect.
|
||||||
static createShader(actor, settings) {
|
static createShader(actor, settings, forOpening) {
|
||||||
return new Shader(settings);
|
return new Shader(settings, forOpening);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
// This is also called from extension.js. It is used to tweak a window's open / close
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
|
||||||
// GNOME Shell. For this effect, windows should neither be scaled nor faded.
|
// forOpening is set to true if this is called for a window-open transition, for a
|
||||||
static getCloseTransition(actor, settings) {
|
// window-close transition it is set to false. The modes can be set to any value from
|
||||||
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 1.0}};
|
// here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
|
||||||
|
// determines how the uProgress uniform value will progress in the shader.
|
||||||
|
// For this effect, windows should neither be scaled nor faded.
|
||||||
|
static tweakTransition(actor, settings, forOpening) {
|
||||||
|
return {
|
||||||
|
'opacity': {from: 255, to: 255, mode: 3},
|
||||||
|
'scale-x': {from: 1.0, to: 1.0, mode: 3},
|
||||||
|
'scale-y': {from: 1.0, to: 1.0, mode: 3}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +107,7 @@ if (utils.isInShellProcess()) {
|
|||||||
const shaderSnippets = Me.imports.src.shaderSnippets;
|
const shaderSnippets = Me.imports.src.shaderSnippets;
|
||||||
|
|
||||||
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
||||||
_init(settings) {
|
_init(settings, forOpening) {
|
||||||
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
||||||
|
|
||||||
const color = Clutter.Color.from_string(settings.get_string('energize-a-color'))[1];
|
const color = Clutter.Color.from_string(settings.get_string('energize-a-color'))[1];
|
||||||
@@ -144,6 +152,10 @@ if (utils.isInShellProcess()) {
|
|||||||
// Compute fading window opacity.
|
// Compute fading window opacity.
|
||||||
float windowMask = pow(1.0 - fadeOutProgress, 2.0);
|
float windowMask = pow(1.0 - fadeOutProgress, 2.0);
|
||||||
|
|
||||||
|
#if ${forOpening ? '1' : '0'}
|
||||||
|
windowMask = 1.0 - windowMask;
|
||||||
|
#endif
|
||||||
|
|
||||||
return vec2(atomMask, windowMask);
|
return vec2(atomMask, windowMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-8
@@ -74,15 +74,23 @@ var EnergizeB = class EnergizeB {
|
|||||||
// ---------------------------------------------------------------- API for extension.js
|
// ---------------------------------------------------------------- API for extension.js
|
||||||
|
|
||||||
// This is called from extension.js whenever a window is closed with this effect.
|
// This is called from extension.js whenever a window is closed with this effect.
|
||||||
static createShader(actor, settings) {
|
static createShader(actor, settings, forOpening) {
|
||||||
return new Shader(settings);
|
return new Shader(settings, forOpening);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
// This is also called from extension.js. It is used to tweak a window's open / close
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
|
||||||
// GNOME Shell. For this effect, windows should neither be scaled nor faded.
|
// forOpening is set to true if this is called for a window-open transition, for a
|
||||||
static getCloseTransition(actor, settings) {
|
// window-close transition it is set to false. The modes can be set to any value from
|
||||||
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 1.0}};
|
// here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
|
||||||
|
// determines how the uProgress uniform value will progress in the shader.
|
||||||
|
// For this effect, windows should neither be scaled nor faded.
|
||||||
|
static tweakTransition(actor, settings, forOpening) {
|
||||||
|
return {
|
||||||
|
'opacity': {from: 255, to: 255, mode: 3},
|
||||||
|
'scale-x': {from: 1.0, to: 1.0, mode: 3},
|
||||||
|
'scale-y': {from: 1.0, to: 1.0, mode: 3}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +107,7 @@ if (utils.isInShellProcess()) {
|
|||||||
const shaderSnippets = Me.imports.src.shaderSnippets;
|
const shaderSnippets = Me.imports.src.shaderSnippets;
|
||||||
|
|
||||||
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
||||||
_init(settings) {
|
_init(settings, forOpening) {
|
||||||
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
||||||
|
|
||||||
const color = Clutter.Color.from_string(settings.get_string('energize-b-color'))[1];
|
const color = Clutter.Color.from_string(settings.get_string('energize-b-color'))[1];
|
||||||
@@ -162,6 +170,10 @@ if (utils.isInShellProcess()) {
|
|||||||
// Compute fading window opacity.
|
// Compute fading window opacity.
|
||||||
float windowMask = pow(1.0 - fadeProgress, 2.0);
|
float windowMask = pow(1.0 - fadeProgress, 2.0);
|
||||||
|
|
||||||
|
#if ${forOpening ? '1' : '0'}
|
||||||
|
windowMask = 1.0 - windowMask;
|
||||||
|
#endif
|
||||||
|
|
||||||
return vec4(showerMask, streakMask, atomMask, windowMask);
|
return vec4(showerMask, streakMask, atomMask, windowMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+22
-10
@@ -96,15 +96,23 @@ var Fire = class Fire {
|
|||||||
// ---------------------------------------------------------------- API for extension.js
|
// ---------------------------------------------------------------- API for extension.js
|
||||||
|
|
||||||
// This is called from extension.js whenever a window is closed with this effect.
|
// This is called from extension.js whenever a window is closed with this effect.
|
||||||
static createShader(actor, settings) {
|
static createShader(actor, settings, forOpening) {
|
||||||
return new Shader(settings);
|
return new Shader(settings, forOpening);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
// This is also called from extension.js. It is used to tweak a window's open / close
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
|
||||||
// GNOME Shell. For this effect, windows should neither be scaled nor faded.
|
// forOpening is set to true if this is called for a window-open transition, for a
|
||||||
static getCloseTransition(actor, settings) {
|
// window-close transition it is set to false. The modes can be set to any value from
|
||||||
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 1.0}};
|
// here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
|
||||||
|
// determines how the uProgress uniform value will progress in the shader.
|
||||||
|
// For this effect, windows should neither be scaled nor faded.
|
||||||
|
static tweakTransition(actor, settings, forOpening) {
|
||||||
|
return {
|
||||||
|
'opacity': {from: 255, to: 255, mode: 3},
|
||||||
|
'scale-x': {from: 1.0, to: 1.0, mode: 3},
|
||||||
|
'scale-y': {from: 1.0, to: 1.0, mode: 3}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- private stuff
|
// ----------------------------------------------------------------------- private stuff
|
||||||
@@ -210,7 +218,7 @@ if (utils.isInShellProcess()) {
|
|||||||
const shaderSnippets = Me.imports.src.shaderSnippets;
|
const shaderSnippets = Me.imports.src.shaderSnippets;
|
||||||
|
|
||||||
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
||||||
_init(settings) {
|
_init(settings, forOpening) {
|
||||||
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
||||||
|
|
||||||
// Load the gradient values from the settings. We directly inject the values in the
|
// Load the gradient values from the settings. We directly inject the values in the
|
||||||
@@ -233,7 +241,7 @@ if (utils.isInShellProcess()) {
|
|||||||
${shaderSnippets.edgeMask()}
|
${shaderSnippets.edgeMask()}
|
||||||
|
|
||||||
// These may be configurable in the future.
|
// These may be configurable in the future.
|
||||||
const float EDGE_FADE = 90;
|
const float EDGE_FADE = 70;
|
||||||
const float FADE_WIDTH = 0.1;
|
const float FADE_WIDTH = 0.1;
|
||||||
const float HIDE_TIME = 0.4;
|
const float HIDE_TIME = 0.4;
|
||||||
const vec2 FIRE_SCALE = vec2(400, 600) * ${settings.get_double('flame-scale')};
|
const vec2 FIRE_SCALE = vec2(400, 600) * ${settings.get_double('flame-scale')};
|
||||||
@@ -295,6 +303,10 @@ if (utils.isInShellProcess()) {
|
|||||||
// Fade at window borders.
|
// Fade at window borders.
|
||||||
effectMask *= getAbsoluteEdgeMask(edgeFadeWidth);
|
effectMask *= getAbsoluteEdgeMask(edgeFadeWidth);
|
||||||
|
|
||||||
|
#if ${forOpening ? '1' : '0'}
|
||||||
|
windowMask = 1.0 - windowMask;
|
||||||
|
#endif
|
||||||
|
|
||||||
return vec2(windowMask, effectMask);
|
return vec2(windowMask, effectMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +334,7 @@ if (utils.isInShellProcess()) {
|
|||||||
cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st) * effectMask.x;
|
cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st) * effectMask.x;
|
||||||
|
|
||||||
// Add the fire to the window.
|
// Add the fire to the window.
|
||||||
cogl_color_out += fire;
|
cogl_color_out = mix(cogl_color_out, fire, fire.a);
|
||||||
|
|
||||||
// These are pretty useful for understanding how this works.
|
// These are pretty useful for understanding how this works.
|
||||||
// cogl_color_out = vec4(vec3(noise), 1);
|
// cogl_color_out = vec4(vec3(noise), 1);
|
||||||
|
|||||||
+19
-10
@@ -81,19 +81,24 @@ var Matrix = class Matrix {
|
|||||||
// ---------------------------------------------------------------- API for extension.js
|
// ---------------------------------------------------------------- API for extension.js
|
||||||
|
|
||||||
// This is called from extension.js whenever a window is closed with this effect.
|
// This is called from extension.js whenever a window is closed with this effect.
|
||||||
static createShader(actor, settings) {
|
static createShader(actor, settings, forOpening) {
|
||||||
return new Shader(settings);
|
return new Shader(settings, forOpening);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
// This is also called from extension.js. It is used to tweak a window's open / close
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
|
||||||
// GNOME Shell. For this effect, windows should neither be scaled nor faded.
|
// forOpening is set to true if this is called for a window-open transition, for a
|
||||||
static getCloseTransition(actor, settings) {
|
// window-close transition it is set to false. The modes can be set to any value from
|
||||||
|
// here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
|
||||||
|
// determines how the uProgress uniform value will progress in the shader.
|
||||||
|
// For this effect, windows should not be faded but scaled vertically to allow for some
|
||||||
|
// overshooting.
|
||||||
|
static tweakTransition(actor, settings, forOpening) {
|
||||||
const yScale = 1.0 + settings.get_double('matrix-overshoot');
|
const yScale = 1.0 + settings.get_double('matrix-overshoot');
|
||||||
return {
|
return {
|
||||||
'opacity': {to: 255},
|
'opacity': {from: 255, to: 255, mode: 1},
|
||||||
'scale-x': {to: 1.0},
|
'scale-x': {from: 1.0, to: 1.0, mode: 1},
|
||||||
'scale-y': {from: yScale, to: yScale}
|
'scale-y': {from: yScale, to: yScale, mode: 1}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,7 +116,7 @@ if (utils.isInShellProcess()) {
|
|||||||
const shaderSnippets = Me.imports.src.shaderSnippets;
|
const shaderSnippets = Me.imports.src.shaderSnippets;
|
||||||
|
|
||||||
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
||||||
_init(settings) {
|
_init(settings, forOpening) {
|
||||||
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
||||||
|
|
||||||
// Load the font texture. As the shader is re-created for each window animation,
|
// Load the font texture. As the shader is re-created for each window animation,
|
||||||
@@ -187,6 +192,10 @@ if (utils.isInShellProcess()) {
|
|||||||
rainAlpha *= smoothstep(0, 1, clamp(cogl_tex_coord_in[0].y / shorten, 0, 1));
|
rainAlpha *= smoothstep(0, 1, clamp(cogl_tex_coord_in[0].y / shorten, 0, 1));
|
||||||
rainAlpha *= smoothstep(0, 1, clamp((1.0 - cogl_tex_coord_in[0].y) / shorten, 0, 1));
|
rainAlpha *= smoothstep(0, 1, clamp((1.0 - cogl_tex_coord_in[0].y) / shorten, 0, 1));
|
||||||
|
|
||||||
|
#if ${forOpening ? '1' : '0'}
|
||||||
|
windowAlpha = 1.0 - windowAlpha;
|
||||||
|
#endif
|
||||||
|
|
||||||
return vec2(rainAlpha, windowAlpha);
|
return vec2(rainAlpha, windowAlpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+23
-18
@@ -78,20 +78,23 @@ var TRexAttack = class TRexAttack {
|
|||||||
// ---------------------------------------------------------------- API for extension.js
|
// ---------------------------------------------------------------- API for extension.js
|
||||||
|
|
||||||
// This is called from extension.js whenever a window is closed with this effect.
|
// This is called from extension.js whenever a window is closed with this effect.
|
||||||
static createShader(actor, settings) {
|
static createShader(actor, settings, forOpening) {
|
||||||
return new Shader(settings);
|
return new Shader(settings, forOpening);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
// This is also called from extension.js. It is used to tweak a window's open / close
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
|
||||||
// GNOME Shell. For this effect, we slightly increase the window's scale as part of the
|
// forOpening is set to true if this is called for a window-open transition, for a
|
||||||
// warp effect.
|
// window-close transition it is set to false. The modes can be set to any value from
|
||||||
static getCloseTransition(actor, settings) {
|
// here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
|
||||||
const warp = 0.5 * settings.get_double('claw-scratch-warp');
|
// determines how the uProgress uniform value will progress in the shader.
|
||||||
|
// For this effect, we slightly increase the window's scale as part of the warp effect.
|
||||||
|
static tweakTransition(actor, settings, forOpening) {
|
||||||
|
const warp = 1.0 + 0.5 * settings.get_double('claw-scratch-warp');
|
||||||
return {
|
return {
|
||||||
'opacity': {to: 255},
|
'opacity': {from: 255, to: 255, mode: 3},
|
||||||
'scale-x': {to: 1.0 + warp},
|
'scale-x': {from: forOpening ? warp : 1.0, to: forOpening ? 1.0 : warp, mode: 3},
|
||||||
'scale-y': {to: 1.0 + warp}
|
'scale-y': {from: forOpening ? warp : 1.0, to: forOpening ? 1.0 : warp, mode: 3}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,7 +112,7 @@ if (utils.isInShellProcess()) {
|
|||||||
const shaderSnippets = Me.imports.src.shaderSnippets;
|
const shaderSnippets = Me.imports.src.shaderSnippets;
|
||||||
|
|
||||||
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
||||||
_init(settings) {
|
_init(settings, forOpening) {
|
||||||
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
||||||
|
|
||||||
// Load the claw texture. As the shader is re-created for each window animation,
|
// Load the claw texture. As the shader is re-created for each window animation,
|
||||||
@@ -180,11 +183,13 @@ if (utils.isInShellProcess()) {
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
|
||||||
|
float progress = ${forOpening ? '1.0-uProgress' : 'uProgress'};
|
||||||
|
|
||||||
// Warp the texture coordinates to create a blow-up effect.
|
// Warp the texture coordinates to create a blow-up effect.
|
||||||
vec2 coords = cogl_tex_coord_in[0].st * 2.0 - 1.0;
|
vec2 coords = cogl_tex_coord_in[0].st * 2.0 - 1.0;
|
||||||
float dist = length(coords);
|
float dist = length(coords);
|
||||||
coords = (coords/dist * pow(dist, WARP_INTENSITY)) * 0.5 + 0.5;
|
coords = (coords/dist * pow(dist, WARP_INTENSITY)) * 0.5 + 0.5;
|
||||||
coords = mix(cogl_tex_coord_in[0].st, coords, uProgress);
|
coords = mix(cogl_tex_coord_in[0].st, coords, progress);
|
||||||
|
|
||||||
// Accumulate several random scratches. The color in the scratch map refers to the
|
// Accumulate several random scratches. The color in the scratch map refers to the
|
||||||
// relative time when the respective part will become invisible. Therefore we can
|
// relative time when the respective part will become invisible. Therefore we can
|
||||||
@@ -198,11 +203,11 @@ if (utils.isInShellProcess()) {
|
|||||||
|
|
||||||
// Get the window texture. We shift the texture lookup by the local derivative of
|
// Get the window texture. We shift the texture lookup by the local derivative of
|
||||||
// the claw texture in order to mimic some folding distortion.
|
// the claw texture in order to mimic some folding distortion.
|
||||||
vec2 offset = vec2(dFdx(scratchMap), dFdy(scratchMap)) * uProgress * 0.5;
|
vec2 offset = vec2(dFdx(scratchMap), dFdy(scratchMap)) * progress * 0.5;
|
||||||
cogl_color_out = texture2D(uTexture, coords + offset);
|
cogl_color_out = texture2D(uTexture, coords + offset);
|
||||||
|
|
||||||
// Add colorful flashes.
|
// Add colorful flashes.
|
||||||
float flashIntensity = 1.0 / FLASH_INTENSITY * (scratchMap - uProgress) + 1;
|
float flashIntensity = 1.0 / FLASH_INTENSITY * (scratchMap - progress) + 1;
|
||||||
if (flashIntensity < 0 || flashIntensity >= 1) {
|
if (flashIntensity < 0 || flashIntensity >= 1) {
|
||||||
flashIntensity = 0;
|
flashIntensity = 0;
|
||||||
}
|
}
|
||||||
@@ -211,16 +216,16 @@ if (utils.isInShellProcess()) {
|
|||||||
flashIntensity *= cogl_color_out.a;
|
flashIntensity *= cogl_color_out.a;
|
||||||
|
|
||||||
// Hide scratched out parts.
|
// Hide scratched out parts.
|
||||||
cogl_color_out *= (scratchMap > uProgress ? 1 : 0);
|
cogl_color_out *= (scratchMap > progress ? 1 : 0);
|
||||||
|
|
||||||
vec3 flashColor = vec3(${color.red / 255},
|
vec3 flashColor = vec3(${color.red / 255},
|
||||||
${color.green / 255},
|
${color.green / 255},
|
||||||
${color.blue / 255}) * ${color.alpha / 255};
|
${color.blue / 255}) * ${color.alpha / 255};
|
||||||
|
|
||||||
cogl_color_out.rgb += flashIntensity * mix(flashColor, vec3(0), uProgress);
|
cogl_color_out.rgb += flashIntensity * mix(flashColor, vec3(0), progress);
|
||||||
|
|
||||||
// Fade out the remaining shards.
|
// Fade out the remaining shards.
|
||||||
float fade = smoothstep(0, 1, 1 - clamp((uProgress - 1.0 + FF_TIME)/FF_TIME, 0, 1));
|
float fade = smoothstep(0, 1, 1 - clamp((progress - 1.0 + FF_TIME)/FF_TIME, 0, 1));
|
||||||
cogl_color_out *= fade;
|
cogl_color_out *= fade;
|
||||||
|
|
||||||
// These are pretty useful for understanding how this works.
|
// These are pretty useful for understanding how this works.
|
||||||
|
|||||||
+22
-12
@@ -75,15 +75,23 @@ var TVEffect = class TVEffect {
|
|||||||
// ---------------------------------------------------------------- API for extension.js
|
// ---------------------------------------------------------------- API for extension.js
|
||||||
|
|
||||||
// This is called from extension.js whenever a window is closed with this effect.
|
// This is called from extension.js whenever a window is closed with this effect.
|
||||||
static createShader(actor, settings) {
|
static createShader(actor, settings, forOpening) {
|
||||||
return new Shader(settings);
|
return new Shader(settings, forOpening);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
// This is also called from extension.js. It is used to tweak a window's open / close
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
|
||||||
// GNOME Shell. For this effect, windows are scaled down vertically.
|
// forOpening is set to true if this is called for a window-open transition, for a
|
||||||
static getCloseTransition(actor, settings) {
|
// window-close transition it is set to false. The modes can be set to any value from
|
||||||
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 0.5}};
|
// here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
|
||||||
|
// determines how the uProgress uniform value will progress in the shader.
|
||||||
|
// For this effect, windows are scaled down vertically.
|
||||||
|
static tweakTransition(actor, settings, forOpening) {
|
||||||
|
return {
|
||||||
|
'opacity': {from: 255, to: 255, mode: 3},
|
||||||
|
'scale-x': {from: 1.0, to: 1.0, mode: 3},
|
||||||
|
'scale-y': {from: forOpening ? 0.5 : 1.0, to: forOpening ? 1.0 : 0.5, mode: 3}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +108,7 @@ if (utils.isInShellProcess()) {
|
|||||||
const shaderSnippets = Me.imports.src.shaderSnippets;
|
const shaderSnippets = Me.imports.src.shaderSnippets;
|
||||||
|
|
||||||
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
||||||
_init(settings) {
|
_init(settings, forOpening) {
|
||||||
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
||||||
|
|
||||||
const color = Clutter.Color.from_string(settings.get_string('tv-effect-color'))[1];
|
const color = Clutter.Color.from_string(settings.get_string('tv-effect-color'))[1];
|
||||||
@@ -118,13 +126,15 @@ if (utils.isInShellProcess()) {
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
|
||||||
|
float progress = ${forOpening ? '1.0-uProgress' : 'uProgress'};
|
||||||
|
|
||||||
// All of these are in [0..1] during the different stages of the animation.
|
// All of these are in [0..1] during the different stages of the animation.
|
||||||
// tb refers to the top-bottom animation.
|
// tb refers to the top-bottom animation.
|
||||||
// lr refers to the left-right animation.
|
// lr refers to the left-right animation.
|
||||||
// ff refers to the final fade animation.
|
// ff refers to the final fade animation.
|
||||||
float tbProgress = smoothstep(0, 1, clamp(uProgress/TB_TIME, 0, 1));
|
float tbProgress = smoothstep(0, 1, clamp(progress/TB_TIME, 0, 1));
|
||||||
float lrProgress = smoothstep(0, 1, clamp((uProgress - LR_DELAY)/LR_TIME, 0, 1));
|
float lrProgress = smoothstep(0, 1, clamp((progress - LR_DELAY)/LR_TIME, 0, 1));
|
||||||
float ffProgress = smoothstep(0, 1, clamp((uProgress - 1.0 + FF_TIME)/FF_TIME, 0, 1));
|
float ffProgress = smoothstep(0, 1, clamp((progress - 1.0 + FF_TIME)/FF_TIME, 0, 1));
|
||||||
|
|
||||||
// This is a top-center-bottom gradient in [0..1..0]
|
// This is a top-center-bottom gradient in [0..1..0]
|
||||||
float tb = cogl_tex_coord_in[0].t * 2;
|
float tb = cogl_tex_coord_in[0].t * 2;
|
||||||
@@ -147,7 +157,7 @@ if (utils.isInShellProcess()) {
|
|||||||
${color.green / 255},
|
${color.green / 255},
|
||||||
${color.blue / 255}, 1.0) * windowColor.a;
|
${color.blue / 255}, 1.0) * windowColor.a;
|
||||||
|
|
||||||
windowColor.rgb = mix(windowColor.rgb, effectColor.rgb, smoothstep(0, 1, uProgress));
|
windowColor.rgb = mix(windowColor.rgb, effectColor.rgb, smoothstep(0, 1, progress));
|
||||||
|
|
||||||
cogl_color_out = windowColor * mask;
|
cogl_color_out = windowColor * mask;
|
||||||
|
|
||||||
|
|||||||
+23
-13
@@ -75,15 +75,23 @@ var Wisps = class Wisps {
|
|||||||
// ---------------------------------------------------------------- API for extension.js
|
// ---------------------------------------------------------------- API for extension.js
|
||||||
|
|
||||||
// This is called from extension.js whenever a window is closed with this effect.
|
// This is called from extension.js whenever a window is closed with this effect.
|
||||||
static createShader(actor, settings) {
|
static createShader(actor, settings, forOpening) {
|
||||||
return new Shader(settings);
|
return new Shader(settings, forOpening);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
// This is also called from extension.js. It is used to tweak a window's open / close
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
|
||||||
// GNOME Shell. For this effect, windows should be scaled down slightly but not faded.
|
// forOpening is set to true if this is called for a window-open transition, for a
|
||||||
static getCloseTransition(actor, settings) {
|
// window-close transition it is set to false. The modes can be set to any value from
|
||||||
return {'opacity': {to: 255}, 'scale-x': {to: 0.9}, 'scale-y': {to: 0.9}};
|
// here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
|
||||||
|
// determines how the uProgress uniform value will progress in the shader.
|
||||||
|
// For this effect, windows should be scaled down slightly but not faded.
|
||||||
|
static tweakTransition(actor, settings, forOpening) {
|
||||||
|
return {
|
||||||
|
'opacity': {from: 255, to: 255, mode: 3},
|
||||||
|
'scale-x': {from: forOpening ? 0.9 : 1.0, to: forOpening ? 1.0 : 0.9, mode: 3},
|
||||||
|
'scale-y': {from: forOpening ? 0.9 : 1.0, to: forOpening ? 1.0 : 0.9, mode: 3}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +108,7 @@ if (utils.isInShellProcess()) {
|
|||||||
const shaderSnippets = Me.imports.src.shaderSnippets;
|
const shaderSnippets = Me.imports.src.shaderSnippets;
|
||||||
|
|
||||||
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
|
||||||
_init(settings) {
|
_init(settings, forOpening) {
|
||||||
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
||||||
|
|
||||||
const color = Clutter.Color.from_string(settings.get_string('wisps-color'))[1];
|
const color = Clutter.Color.from_string(settings.get_string('wisps-color'))[1];
|
||||||
@@ -160,6 +168,8 @@ if (utils.isInShellProcess()) {
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
|
||||||
|
float progress = ${forOpening ? '1.0-uProgress' : 'uProgress'};
|
||||||
|
|
||||||
// Get the color of the window.
|
// Get the color of the window.
|
||||||
vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st);
|
vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st);
|
||||||
vec4 effectColor = vec4(${color.red / 255},
|
vec4 effectColor = vec4(${color.red / 255},
|
||||||
@@ -167,7 +177,7 @@ if (utils.isInShellProcess()) {
|
|||||||
${color.blue / 255}, 1.0) * windowColor.a;
|
${color.blue / 255}, 1.0) * windowColor.a;
|
||||||
|
|
||||||
// Compute several layers of moving wisps.
|
// Compute several layers of moving wisps.
|
||||||
vec2 uv = (cogl_tex_coord_in[0].st-0.5) / mix(1.0, 0.5, uProgress) + 0.5;
|
vec2 uv = (cogl_tex_coord_in[0].st-0.5) / mix(1.0, 0.5, progress) + 0.5;
|
||||||
uv /= ${settings.get_double('wisps-scale')};
|
uv /= ${settings.get_double('wisps-scale')};
|
||||||
float wisps = 0;
|
float wisps = 0;
|
||||||
for (int i=0; i<WISPS_LAYERS; ++i) {
|
for (int i=0; i<WISPS_LAYERS; ++i) {
|
||||||
@@ -175,12 +185,12 @@ if (utils.isInShellProcess()) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute shrinking edge mask.
|
// Compute shrinking edge mask.
|
||||||
float mask = getRelativeEdgeMask(mix(0.01, 0.5, uProgress));
|
float mask = getRelativeEdgeMask(mix(0.01, 0.5, progress));
|
||||||
|
|
||||||
// Compute three different progress values.
|
// Compute three different progress values.
|
||||||
float wispsIn = smoothstep(0, 1, clamp(uProgress/WISPS_IN_TIME, 0, 1));
|
float wispsIn = smoothstep(0, 1, clamp(progress/WISPS_IN_TIME, 0, 1));
|
||||||
float wispsOut = smoothstep(0, 1, clamp((uProgress - WISPS_IN_TIME)/(1.0 - WISPS_IN_TIME), 0, 1));
|
float wispsOut = smoothstep(0, 1, clamp((progress - WISPS_IN_TIME)/(1.0 - WISPS_IN_TIME), 0, 1));
|
||||||
float windowOut = smoothstep(0, 1, clamp(uProgress/WINDOW_OUT_TIME, 0, 1));
|
float windowOut = smoothstep(0, 1, clamp(progress/WINDOW_OUT_TIME, 0, 1));
|
||||||
|
|
||||||
// Use a noise function to dissolve the window.
|
// Use a noise function to dissolve the window.
|
||||||
float noise = smoothstep(1.0, 0.0, abs(2.0 * simplex2DFractal(uv * vec2(uSizeX, uSizeY) / 250) - 1.0));
|
float noise = smoothstep(1.0, 0.0, abs(2.0 * simplex2DFractal(uv * vec2(uSizeX, uSizeY) / 250) - 1.0));
|
||||||
|
|||||||
Reference in New Issue
Block a user