From b6a3e5d941c750c0b7b092852d989bd7657dd1c6 Mon Sep 17 00:00:00 2001 From: Simon Schneegans Date: Fri, 1 Apr 2022 21:10:02 +0200 Subject: [PATCH] :tada: Add Apparition effect --- docs/changelog.md | 1 + extension.js | 1 + prefs.js | 1 + resources/ui/gtk3/Apparition.ui | 304 ++++++++++++++++++ resources/ui/gtk4/Apparition.ui | 255 +++++++++++++++ ...ell.extensions.burn-my-windows.gschema.xml | 46 +++ src/Apparition.js | 171 ++++++++++ 7 files changed, 779 insertions(+) create mode 100644 resources/ui/gtk3/Apparition.ui create mode 100644 resources/ui/gtk4/Apparition.ui create mode 100644 src/Apparition.js diff --git a/docs/changelog.md b/docs/changelog.md index f399758..57cd716 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -6,6 +6,7 @@ #### New Features +* **New Effect: Apparition.** This effect hides the window by violently sucking it into the void of magic. * **New Effect: Snap of Disintegration.** This was requested quite frequently! Dissolve your windows into a cloud of dust. #### Bug Fixes diff --git a/extension.js b/extension.js index 76e366b..dee6049 100644 --- a/extension.js +++ b/extension.js @@ -33,6 +33,7 @@ const utils = Me.imports.src.utils; // New effects must be registered here and in prefs.js. const ALL_EFFECTS = [ + Me.imports.src.Apparition.Apparition, Me.imports.src.BrokenGlass.BrokenGlass, Me.imports.src.EnergizeA.EnergizeA, Me.imports.src.EnergizeB.EnergizeB, diff --git a/prefs.js b/prefs.js index 12b48ff..c225aba 100644 --- a/prefs.js +++ b/prefs.js @@ -32,6 +32,7 @@ const utils = Me.imports.src.utils; // New effects must be registered here and in extension.js. const ALL_EFFECTS = [ + Me.imports.src.Apparition.Apparition, Me.imports.src.BrokenGlass.BrokenGlass, Me.imports.src.EnergizeA.EnergizeA, Me.imports.src.EnergizeB.EnergizeB, diff --git a/resources/ui/gtk3/Apparition.ui b/resources/ui/gtk3/Apparition.ui new file mode 100644 index 0000000..bd4dd2c --- /dev/null +++ b/resources/ui/gtk3/Apparition.ui @@ -0,0 +1,304 @@ + + + + + 2000 + 100 + 10 + 100 + + + + 1 + 0 + 0.01 + 0.1 + + + + 10 + -10 + 0.1 + 1 + + + + 10 + 0 + 0.1 + 1 + + + + 1 + 0 + 0.01 + 0.1 + + + + vertical + + + + + + none + + + + + 10 + 10 + 10 + 10 + 0 + + + 8 + + + Animation Time [ms] + 0 + start + center + 1 + + + + + end + center + 1 + 0 + left + 300 + apparition-animation-time + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + + + + 10 + 10 + 10 + 10 + 0 + + + 8 + + + Randomness + 0 + start + center + 1 + + + + + end + center + 1 + 2 + left + 300 + apparition-randomness + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + + + + 10 + 10 + 10 + 10 + 0 + + + 8 + + + Twirl Intensity + 0 + start + center + 1 + + + + + end + center + 1 + 1 + left + 300 + apparition-twirl-intensity + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + + + + 10 + 10 + 10 + 10 + 0 + + + 8 + + + Shake Intensity + 0 + start + center + 1 + + + + + end + center + 1 + 1 + left + 300 + apparition-shake-intensity + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + + + + 10 + 10 + 10 + 10 + 0 + + + 8 + + + Suction Intensity + 0 + start + center + 1 + + + + + end + center + 1 + 2 + left + 300 + apparition-suction-intensity + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/ui/gtk4/Apparition.ui b/resources/ui/gtk4/Apparition.ui new file mode 100644 index 0000000..cac7c8a --- /dev/null +++ b/resources/ui/gtk4/Apparition.ui @@ -0,0 +1,255 @@ + + + + + vertical + + + + + + none + 1 + + + + + 0 + + + + + Animation Time [ms] + 0 + start + center + 1 + + + + + end + center + 1 + 0 + left + 300 + + + 2000 + 100 + 10 + 100 + + + + + + + edit-clear-symbolic + Reset to Default Value + + + + + + + + + + + 0 + + + + + Randomness + 0 + start + center + 1 + + + + + end + center + 1 + 2 + left + 300 + + + 1 + 0 + 0.01 + 0.1 + + + + + + + edit-clear-symbolic + Reset to Default Value + + + + + + + + + + + 0 + + + + + Twirl Intensity + 0 + start + center + 1 + + + + + end + center + 1 + 1 + left + 300 + + + 10 + -10 + 0.1 + 1 + + + + + + + edit-clear-symbolic + Reset to Default Value + + + + + + + + + + + 0 + + + + + Shake Intensity + 0 + start + center + 1 + + + + + end + center + 1 + 1 + left + 300 + + + 10 + 0 + 0.1 + 1 + + + + + + + edit-clear-symbolic + Reset to Default Value + + + + + + + + + + + 0 + + + + + Suction Intensity + 0 + start + center + 1 + + + + + end + center + 1 + 2 + left + 300 + + + 1 + 0 + 0.01 + 0.1 + + + + + + + edit-clear-symbolic + Reset to Default Value + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml b/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml index d37f07a..8109c2c 100644 --- a/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml +++ b/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml @@ -31,6 +31,52 @@ If set to true, all animations will show only one still frame to allow for continuous integration tests. + + + + + + false + Apparition Open Effect + Use the apparition effect for window openeing. + + + + false + Apparition Close Effect + Use the apparition effect for window closing. + + + + 300 + Apparition Animation Time + The time the apparition effect takes. + + + + 0.7 + Apparition Randomness + The amount of randomness of the apparition effect. + + + + 3.0 + Apparition Twirl Intensity + The amount of twirling of the apparition effect. + + + + 3.0 + Apparition Shake Intensity + The amount of shaking of the apparition effect. + + + + 0.5 + Apparition Suction Intensity + The amount of suction of the apparition effect. + + diff --git a/src/Apparition.js b/src/Apparition.js new file mode 100644 index 0000000..d8291e5 --- /dev/null +++ b/src/Apparition.js @@ -0,0 +1,171 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// ) ( // +// ( /( ( ( ) ( ( ( ( )\ ) ( ( // +// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // +// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // +// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // +// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< // +// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ // +// |__/ // +// Copyright (c) 2021 Simon Schneegans // +// Released under the GPLv3 or later. See LICENSE file for details. // +////////////////////////////////////////////////////////////////////////////////////////// + +'use strict'; + +const GObject = imports.gi.GObject; + +const _ = imports.gettext.domain('burn-my-windows').gettext; + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const utils = Me.imports.src.utils; + +////////////////////////////////////////////////////////////////////////////////////////// +// This effect hides the actor by violently sucking it into the void of magic. // +// towards the middle and then hiding the resulting line from left and right towards // +// the center. // +////////////////////////////////////////////////////////////////////////////////////////// + +// The shader class for this effect is registered further down in this file. +let Shader = null; + +// The effect class is completely static. It can be used to get some metadata (like the +// effect's name or supported GNOME Shell versions), to initialize the respective page of +// the settings dialog, as well as to create the actual shader for the effect. +var Apparition = class Apparition { + + // ---------------------------------------------------------------------------- metadata + + // The effect is available on all GNOME Shell versions supported by this extension. + static getMinShellVersion() { + return [3, 36]; + } + + // This will be called in various places where a unique identifier for this effect is + // required. It should match the prefix of the settings keys which store whether the + // effect is enabled currently (e.g. '*-close-effect'), and its animation time + // (e.g. '*-animation-time'). + static getNick() { + return 'apparition'; + } + + // This will be shown in the sidebar of the preferences dialog as well as in the + // drop-down menus where the user can choose the effect. + static getLabel() { + return _('Apparition'); + } + + // -------------------------------------------------------------------- API for prefs.js + + // This is called by the preferences dialog. It loads the settings page for this effect, + // binds all properties to the settings and appends the page to the main stack of the + // preferences dialog. + static getPreferences(dialog) { + + // Add the settings page to the builder. + dialog.getBuilder().add_from_resource(`/ui/${utils.getGTKString()}/Apparition.ui`); + + // Bind all properties. + dialog.bindAdjustment('apparition-randomness'); + dialog.bindAdjustment('apparition-animation-time'); + dialog.bindAdjustment('apparition-twirl-intensity'); + dialog.bindAdjustment('apparition-shake-intensity'); + dialog.bindAdjustment('apparition-suction-intensity'); + + // Finally, return the new settings page. + return dialog.getBuilder().get_object('apparition-prefs'); + } + + // ---------------------------------------------------------------- API for extension.js + + // This is called from extension.js whenever a window is closed with this effect. + static createShader(actor, settings, forOpening) { + return new Shader(actor, settings, forOpening); + } + + // The tweakTransition() is called from extension.js to tweak a window's open / close + // transitions - usually windows are faded in / out and scaled up / down by GNOME Shell. + // The parameter '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. + // The only required property is 'opacity', even if it transitions from 1.0 to 1.0. The + // current value of the opacity transition is passed as uProgress to the shader. + // Tweaking the actor's scale during the transition only works properly for GNOME 3.38+. + + // For this effect, windows are set to twice their original size, so that we have + // some space to draw the animation. We also set the animation mode to "Linear". + static tweakTransition(actor, settings, forOpening) { + return { + 'opacity': {from: 255, to: 255, mode: 1}, + 'scale-x': {from: 2.0, to: 2.0, mode: 1}, + 'scale-y': {from: 2.0, to: 2.0, mode: 1} + }; + } +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// The shader class for this effect will only be registered in GNOME Shell's process // +// (not in the preferences process). It's done this way as Clutter may not be installed // +// on the system and therefore the preferences would crash. // +////////////////////////////////////////////////////////////////////////////////////////// + +if (utils.isInShellProcess()) { + + const Clutter = imports.gi.Clutter; + const shaderSnippets = Me.imports.src.shaderSnippets; + + Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect { + _init(actor, settings, forOpening) { + super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); + + // If we are currently performing integration test, the animation uses a fixed seed. + const testMode = settings.get_boolean('test-mode'); + + // The math for the whirling is inspired by this post: + // http://www.geeks3d.com/20110428/shader-library-swirl-post-processing-filter-in-glsl + this.set_shader_source(` + + // Inject some common shader snippets. + ${shaderSnippets.standardUniforms()} + + const vec2 SEED = vec2(${testMode ? 0 : Math.random()}, + ${testMode ? 0 : Math.random()}); + const float SHAKE = ${settings.get_double('apparition-shake-intensity')}; + const float TWIRL = ${settings.get_double('apparition-twirl-intensity')}; + const float SUCTION = ${settings.get_double('apparition-suction-intensity')}; + const float RANDOMNESS = ${settings.get_double('apparition-randomness')}; + const float ACTOR_SCALE = 2.0; + const float PADDING = ACTOR_SCALE / 2.0 - 0.5; + + void main() { + + // We simply inverse the progress for opening windows. + float progress = ${forOpening ? '1.0-uProgress' : 'uProgress'}; + + // Choose a random suction center. + vec2 center = SEED * RANDOMNESS + 0.5 * (1.0 - RANDOMNESS); + vec2 coords = cogl_tex_coord_in[0].st * ACTOR_SCALE - PADDING - center; + + // Add some shaking. + coords.x += progress * 0.05 * SHAKE * sin((progress + SEED.x) * (1.0 + SEED.x) * SHAKE); + coords.y += progress * 0.05 * SHAKE * cos((progress + SEED.y) * (1.0 + SEED.y) * SHAKE); + + // "Suck" the texture into the center. + float dist = length(coords) / sqrt(2); + coords += progress * coords / dist * 0.5 * SUCTION; + + // Apply some whirling. + float angle = pow(1.0 - dist, 2.0) * TWIRL * progress; + float s = sin(angle); + float c = cos(angle); + coords = vec2(dot(coords, vec2(c, -s)), dot(coords, vec2(s, c))); + + // Fade out the window texture. + cogl_color_out = texture2D(uTexture, coords + center) * (1.0 - progress); + } + `); + }; + }); +} \ No newline at end of file