diff --git a/Makefile b/Makefile index 7d49900..6dc34d4 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ burn-my-windows@schneegans.github.com.zip: schemas/gschemas.compiled resources/b @echo "Packing zip file..." @rm --force burn-my-windows@schneegans.github.com.zip - @zip -r burn-my-windows@schneegans.github.com.zip -- *.js src/*/*.js resources/burn-my-windows.gresource schemas/gschemas.compiled metadata.json LICENSE + @zip -r burn-my-windows@schneegans.github.com.zip -- *.js src/*.js resources/burn-my-windows.gresource schemas/gschemas.compiled metadata.json LICENSE @#Check if the zip size is too big to be uploaded @if [[ "$$(stat -c %s burn-my-windows@schneegans.github.com.zip)" -gt 4096000 ]]; then \ diff --git a/extension.js b/extension.js index 1ec8db1..e831235 100644 --- a/extension.js +++ b/extension.js @@ -21,11 +21,15 @@ const WINDOW_REPOSITIONING_DELAY = imports.ui.workspace.WINDOW_REPOSITIONING_DEL const ExtensionUtils = imports.misc.extensionUtils; const Me = imports.misc.extensionUtils.getCurrentExtension(); -const utils = Me.imports.src.common.utils; -const FireShader = Me.imports.src.extension.FireShader.FireShader; -const MatrixShader = Me.imports.src.extension.MatrixShader.MatrixShader; -const TVEffectShader = Me.imports.src.extension.TVEffectShader.TVEffectShader; -const TRexShader = Me.imports.src.extension.TRexShader.TRexShader; +const utils = Me.imports.src.utils; +const FireEffect = Me.imports.src.FireEffect.FireEffect; + +const EFFECT_TYPES = [ + Me.imports.src.FireEffect.FireEffect, + Me.imports.src.MatrixEffect.MatrixEffect, + Me.imports.src.TRexEffect.TRexEffect, + Me.imports.src.TVEffect.TVEffect, +]; ////////////////////////////////////////////////////////////////////////////////////////// // This extensions modifies the window-close animation to look like the window was set // @@ -150,21 +154,21 @@ class Extension { let shader = null; // Add a cool shader to our window actor! - const mode = this._settings.get_enum('close-animation'); - if (mode == 1) { - shader = new FireShader(this._settings); - } else if (mode == 2) { - shader = new MatrixShader(this._settings); - } else if (mode == 3) { - shader = new TVEffectShader(this._settings); - tweakTransition('scale-y', 0.5); - } else if (mode == 4) { - shader = new TRexShader(this._settings); + // const mode = this._settings.get_enum('close-animation'); + // if (mode == 1) { + shader = FireEffect.createShader(this._settings); + // } else if (mode == 2) { + // shader = new MatrixShader(this._settings); + // } else if (mode == 3) { + // shader = new TVEffectShader(this._settings); + // tweakTransition('scale-y', 0.5); + // } else if (mode == 4) { + // shader = new TRexShader(this._settings); - const warp = 0.5 * this._settings.get_double('claw-scratch-warp'); - tweakTransition('scale-x', 1.0 + warp); - tweakTransition('scale-y', 1.0 + warp); - } + // const warp = 0.5 * this._settings.get_double('claw-scratch-warp'); + // tweakTransition('scale-x', 1.0 + warp); + // tweakTransition('scale-y', 1.0 + warp); + // } if (shader) { actor.add_effect(shader); diff --git a/prefs.js b/prefs.js index 7b28134..d1f201e 100644 --- a/prefs.js +++ b/prefs.js @@ -17,20 +17,20 @@ const {Gio, Gtk, Gdk} = imports.gi; const ExtensionUtils = imports.misc.extensionUtils; const Me = imports.misc.extensionUtils.getCurrentExtension(); -const utils = Me.imports.src.common.utils; +const utils = Me.imports.src.utils; -const FirePage = Me.imports.src.prefs.FirePage.FirePage; -const MatrixPage = Me.imports.src.prefs.MatrixPage.MatrixPage; -const TVEffectPage = Me.imports.src.prefs.TVEffectPage.TVEffectPage; -const TRexPage = Me.imports.src.prefs.TRexPage.TRexPage; +const EFFECT_TYPES = [ + Me.imports.src.FireEffect.FireEffect, + Me.imports.src.MatrixEffect.MatrixEffect, + Me.imports.src.TRexEffect.TRexEffect, + Me.imports.src.TVEffect.TVEffect, +]; ////////////////////////////////////////////////////////////////////////////////////////// // For now, the preferences dialog of this extension is very simple. In the future, if // // we might consider to improve its layout... // ////////////////////////////////////////////////////////////////////////////////////////// -const EFFECT_TYPES = [FirePage, MatrixPage, TVEffectPage, TRexPage]; - var PreferencesDialog = class PreferencesDialog { // ------------------------------------------------------------ constructor / destructor diff --git a/src/FireEffect.js b/src/FireEffect.js new file mode 100644 index 0000000..3a2a0ce --- /dev/null +++ b/src/FireEffect.js @@ -0,0 +1,306 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// ) ( // +// ( /( ( ( ) ( ( ( ( )\ ) ( ( // +// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // +// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // +// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // +// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< // +// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ // +// |__/ // +// Copyright (c) 2021 Simon Schneegans // +// Released under the GPLv3 or later. See LICENSE file for details. // +////////////////////////////////////////////////////////////////////////////////////////// + +'use strict'; + +const {Gio, GObject} = imports.gi; + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const utils = Me.imports.src.utils; + +////////////////////////////////////////////////////////////////////////////////////////// +// This effect is a homage to the good old Compiz days. However, it is implemented // +// quite differently. While Compiz used a particle system, this effect uses a noise // +// shader. The noise is moved vertically over time and mapped to a configurable color // +// gradient. It is faded to transparency towards the edges of the window. In addition, // +// there are a couple of moving gradients which fade-in or fade-out the fire effect. // +////////////////////////////////////////////////////////////////////////////////////////// + +let FireShader = null; + +if (utils.isInShellProcess()) { + + const Clutter = imports.gi.Clutter; + const shaderSnippets = Me.imports.src.shaderSnippets; + + FireShader = GObject.registerClass({Properties: {}, Signals: {}}, + class FireShader extends Clutter.ShaderEffect { + _init(settings) { + super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); + + // Load the gradient values from the settings. We directly inject the values in the + // GLSL code below. The shader is compiled once for each window-closing anyways. In + // the future, we may want to prevent this frequent recompilations of shaders, + // though. + const gradient = []; + for (let i = 1; i <= 5; i++) { + const color = + Clutter.Color.from_string(settings.get_string('fire-color-' + i))[1]; + gradient.push(`vec4(${color.red / 255}, ${color.green / 255}, ${ + color.blue / 255}, ${color.alpha / 255})`); + } + + this.set_shader_source(` + + // Inject some common shader snippets. + ${shaderSnippets.standardUniforms()} + ${shaderSnippets.noise()} + + // These may be configurable in the future. + const float EDGE_FADE = 90; + const float FADE_WIDTH = 0.1; + const float HIDE_TIME = 0.4; + const vec2 FIRE_SCALE = vec2(400, 600) * ${settings.get_double('flame-scale')}; + const float FIRE_SPEED = ${settings.get_double('flame-movement-speed')}; + + // This maps the input value from [0..1] to a color from the gradient. + vec4 getFireColor(float v) { + const float steps[5] = float[](0.0, 0.2, 0.35, 0.5, 0.8); + const vec4 colors[5] = vec4[]( + ${gradient[0]}, + ${gradient[1]}, + ${gradient[2]}, + ${gradient[3]}, + ${gradient[4]} + ); + + if (v < steps[0]) { + return colors[0]; + } + + for (int i=0; i<4; ++i) { + if (v <= steps[i+1]) { + return mix(colors[i], colors[i+1], vec4(v - steps[i])/(steps[i+1]-steps[i])); + } + } + + return colors[4]; + } + + // This method requires the uniforms from standardUniforms() to be available. + // It returns two values: The first is an alpha value which can be used for the window + // texture. This gradually dissolves the window from top to bottom. The second can be used + // to mask any effect, it will be most opaque where the window is currently fading and + // gradually dissolve to zero over time. + // hideTime: A value in [0..1]. It determines the percentage of the animation which + // is spent for hiding the window. 1-hideTime will be spent thereafter for + // dissolving the effect mask. + // fadeWidth: The relative size of the window-hiding gradient in [0..1]. + // edgeFadeWidth: The pixel width of the effect fading range at the edges of the window. + vec2 effectMask(float hideTime, float fadeWidth, float edgeFadeWidth) { + float burnProgress = clamp(uProgress/hideTime, 0, 1); + float afterBurnProgress = clamp((uProgress-hideTime)/(1-hideTime), 0, 1); + + // Gradient from top to bottom. + float t = cogl_tex_coord_in[0].t * (1 - fadeWidth); + + // Visible part of the window. Gradually dissolves towards the bottom. + float windowMask = 1 - clamp((burnProgress - t) / fadeWidth, 0, 1); + + // Gradient from top burning window. + float effectMask = clamp(t*(1-windowMask)/burnProgress, 0, 1); + + // Fade-out when the window burned down. + if (uProgress > hideTime) { + float fade = sqrt(1-afterBurnProgress*afterBurnProgress); + effectMask *= mix(1, 1-t, afterBurnProgress) * fade; + } + + // Fade at window borders. + vec2 pos = cogl_tex_coord_in[0].st * vec2(uSizeX, uSizeY); + effectMask *= smoothstep(0, 1, clamp(pos.x / edgeFadeWidth, 0, 1)); + effectMask *= smoothstep(0, 1, clamp(pos.y / edgeFadeWidth, 0, 1)); + effectMask *= smoothstep(0, 1, clamp((uSizeX - pos.x) / edgeFadeWidth, 0, 1)); + effectMask *= smoothstep(0, 1, clamp((uSizeY - pos.y) / edgeFadeWidth, 0, 1)); + + return vec2(windowMask, effectMask); + } + + void main() { + + // Get a noise value which moves vertically in time. + vec2 uv = cogl_tex_coord_in[0].st * vec2(uSizeX, uSizeY) / FIRE_SCALE; + uv.y += uTime * FIRE_SPEED; + + #if ${settings.get_boolean('flame-3d-noise') ? 1 : 0} + float noise = noise3D(vec3(uv*7.5, uTime*FIRE_SPEED*3.0), 5); + #else + float noise = noise2D(uv * 7.5, 5); + #endif + + // Modulate noise by effect mask. + vec2 effectMask = effectMask(HIDE_TIME, FADE_WIDTH, EDGE_FADE); + noise *= effectMask.y; + + // Map noise value to color. + vec4 fire = getFireColor(noise); + fire.rgb *= fire.a; + + // Get the window texture and fade it according to the effect mask. + cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st) * effectMask.x; + + // Add the fire to the window. + cogl_color_out += fire; + + // These are pretty useful for understanding how this works. + // cogl_color_out = vec4(vec3(noise), 1); + // cogl_color_out = vec4(vec3(effectMask.x), 1); + // cogl_color_out = vec4(vec3(effectMask.y), 1); + } + `); + }; + }); +} + +var FireEffect = class FireEffect { + + // ---------------------------------------------------------------------- static methods + + static getMinShellVersion() { + return [3, 36]; + } + + static getSettingsPrefix() { + return 'fire'; + } + + static getLabel() { + return 'Fire'; + } + + static initPreferences(dialog) { + + dialog.getBuilder().add_from_resource( + `/ui/${utils.isGTK4() ? 'gtk4' : 'gtk3'}/firePage.ui`); + + // Bind all properties. + dialog.bindAdjustment('fire-animation-time'); + dialog.bindAdjustment('flame-movement-speed'); + dialog.bindAdjustment('flame-scale'); + dialog.bindSwitch('flame-3d-noise'); + dialog.bindColorButton('fire-color-1'); + dialog.bindColorButton('fire-color-2'); + dialog.bindColorButton('fire-color-3'); + dialog.bindColorButton('fire-color-4'); + dialog.bindColorButton('fire-color-5'); + + // The fire-gradient-reset button needs to be bound explicitly. + dialog.getBuilder().get_object('reset-fire-colors').connect('clicked', () => { + dialog.getSettings().reset('fire-color-1'); + dialog.getSettings().reset('fire-color-2'); + dialog.getSettings().reset('fire-color-3'); + dialog.getSettings().reset('fire-color-4'); + dialog.getSettings().reset('fire-color-5'); + }); + + // Initialize the fire-preset dropdown. + FireEffect._createFirePresets(dialog); + + const stack = dialog.getBuilder().get_object('main-stack'); + stack.add_titled(dialog.getBuilder().get_object('fire-prefs'), 'fire', 'Fire'); + } + + static createShader(settings) { + return new FireShader(settings); + } + + // ----------------------------------------------------------------------- private stuff + + // This populates the preset dropdown menu for the fire options. + static _createFirePresets(dialog) { + dialog.getBuilder().get_object('settings-widget').connect('realize', (widget) => { + const presets = [ + { + name: 'Default Fire', + scale: 1.0, + speed: 0.5, + color1: 'rgba(76, 51, 25, 0.0)', + color2: 'rgba(180, 55, 30, 0.7)', + color3: 'rgba(255, 76, 38, 0.9)', + color4: 'rgba(255, 166, 25, 1)', + color5: 'rgba(255, 255, 255, 1)' + }, + { + name: 'Hell Fire', + scale: 1.5, + speed: 0.2, + color1: 'rgba(0,0,0,0)', + color2: 'rgba(103,7,80,0.5)', + color3: 'rgba(150,0,24,0.9)', + color4: 'rgb(255,200,0)', + color5: 'rgba(255, 255, 255, 1)' + }, + { + name: 'Dark and Smutty', + scale: 1.0, + speed: 0.5, + color1: 'rgba(0,0,0,0)', + color2: 'rgba(36,3,0,0.5)', + color3: 'rgba(150,0,24,0.9)', + color4: 'rgb(255,177,21)', + color5: 'rgb(255,238,166)' + }, + { + name: 'Cold Breeze', + scale: 1.5, + speed: -0.1, + color1: 'rgba(0,110,255,0)', + color2: 'rgba(30,111,180,0.24)', + color3: 'rgba(38,181,255,0.54)', + color4: 'rgba(34,162,255,0.84)', + color5: 'rgb(97,189,255)' + }, + { + name: 'Santa is Coming', + scale: 0.4, + speed: -0.5, + color1: 'rgba(0,110,255,0)', + color2: 'rgba(208,233,255,0.24)', + color3: 'rgba(207,235,255,0.84)', + color4: 'rgb(208,243,255)', + color5: 'rgb(255,255,255)' + } + ]; + + const menu = Gio.Menu.new(); + const group = Gio.SimpleActionGroup.new(); + const groupName = 'presets'; + + // Add all presets. + presets.forEach((preset, i) => { + const actionName = 'fire' + i; + menu.append(preset.name, groupName + '.' + actionName); + let action = Gio.SimpleAction.new(actionName, null); + + // Load the preset on activation. + action.connect('activate', () => { + dialog.getSettings().set_double('flame-movement-speed', preset.speed); + dialog.getSettings().set_double('flame-scale', preset.scale); + dialog.getSettings().set_string('fire-color-1', preset.color1); + dialog.getSettings().set_string('fire-color-2', preset.color2); + dialog.getSettings().set_string('fire-color-3', preset.color3); + dialog.getSettings().set_string('fire-color-4', preset.color4); + dialog.getSettings().set_string('fire-color-5', preset.color5); + }); + + group.add_action(action); + }); + + dialog.getBuilder().get_object('fire-preset-button').set_menu_model(menu); + + const root = utils.isGTK4() ? widget.get_root() : widget.get_toplevel(); + root.insert_action_group(groupName, group); + }); + } +} \ No newline at end of file diff --git a/src/MatrixEffect.js b/src/MatrixEffect.js new file mode 100644 index 0000000..56a9235 --- /dev/null +++ b/src/MatrixEffect.js @@ -0,0 +1,193 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// ) ( // +// ( /( ( ( ) ( ( ( ( )\ ) ( ( // +// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // +// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // +// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // +// | '_ \ || | '_| ' \)) | ' \()| || | \ 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 ExtensionUtils = imports.misc.extensionUtils; +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const utils = Me.imports.src.utils; + +////////////////////////////////////////////////////////////////////////////////////////// +// The MatrixShader multiplies a grid of random letters with some gradients which are // +// moving from top to bottom. The speed of the moving gradients is chosen randomly. // +// Also, there is a random delay making the gradients not drop all at the same time. // +// This effect is not available on GNOME 3.3x, due to the limitation described in the // +// documentation of vfunc_paint_target further down in this file. // +////////////////////////////////////////////////////////////////////////////////////////// + + +let MatrixShader = null; + +if (utils.isInShellProcess()) { + + const {Clutter, GdkPixbuf, Cogl} = imports.gi; + const shaderSnippets = Me.imports.src.shaderSnippets; + + + MatrixShader = GObject.registerClass({Properties: {}, Signals: {}}, + class MatrixShader extends Clutter.ShaderEffect { + _init(settings) { + super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); + + // Load the font texture. As the shader is re-created for each window animation, + // this texture is also re-created each time. This could be improved in the future! + const fontData = GdkPixbuf.Pixbuf.new_from_resource('/img/matrixFont.png'); + this._fontTexture = new Clutter.Image(); + this._fontTexture.set_data( + fontData.get_pixels(), + fontData.has_alpha ? Cogl.PixelFormat.RGBA_8888 : Cogl.PixelFormat.RGB_888, + fontData.width, fontData.height, fontData.rowstride); + + const trailColor = + Clutter.Color.from_string(settings.get_string('matrix-trail-color'))[1]; + const tipColor = + Clutter.Color.from_string(settings.get_string('matrix-tip-color'))[1]; + + // The technique for this effect was inspired by + // https://www.shadertoy.com/view/ldccW4, however the implementation is quite + // different as the letters drop only once and there is no need for a noise texture. + this.set_shader_source(` + +// Inject some common shader snippets. +${shaderSnippets.standardUniforms()} +${shaderSnippets.noise()} + +uniform sampler2D uFontTexture; + +// These may be configurable in the future. +const float EDGE_FADE = 30; +const float FADE_WIDTH = 150; +const float TRAIL_LENGTH = 0.2; +const float FINAL_FADE_START_TIME = 0.8; +const float LETTER_TILES = 16.0; +const float LETTER_SIZE = ${settings.get_int('matrix-scale')}; +const float LETTER_FLICKER_SPEED = 2.0; +const float RANDOMNESS = ${settings.get_double('matrix-randomness')}; + +// This returns a flickering grid of random letters. +float getText(vec2 fragCoord) { +vec2 pixelCoords = fragCoord * vec2(uSizeX, uSizeY); +vec2 uv = mod(pixelCoords.xy, LETTER_SIZE)/LETTER_SIZE; +vec2 block = pixelCoords/LETTER_SIZE - uv; + +// Choose random letter. +uv += floor(hash2D(floor(hash2D(block)*vec2(12.9898,78.233) + LETTER_FLICKER_SPEED*uTime + 42.254))*LETTER_TILES); + +return texture2D(uFontTexture, uv/LETTER_TILES).r; +} + +// This returns two values: The first are gradients for the "raindrops" which move +// from top to bottom. This is used for fading the letters. The second value is set +// to one below each drop and to zero above it. This second value is used for fading +// the window texture. +vec2 getRain(vec2 fragCoord) { +vec2 coords = fragCoord * vec2(uSizeX, uSizeY); +coords.x -= mod(coords.x, LETTER_SIZE); + +float delay = fract(sin(coords.x)*78.233) * mix(0.0, 1.0, RANDOMNESS); +float speed = fract(cos(coords.x)*12.989) * mix(0.0, 0.3, RANDOMNESS) + 1.5; + +float distToDrop = (uProgress*2-delay)*speed - fragCoord.y; +float rainAlpha = distToDrop >= 0 ? exp(-distToDrop/TRAIL_LENGTH) : 0; +float windowAlpha = 1 - clamp(uSizeY*distToDrop, 0, FADE_WIDTH) / FADE_WIDTH; +return vec2(rainAlpha, windowAlpha); +} + +void main() { + +// Get a cool matrix effect. See comments for those methods above. +vec2 rain = getRain(cogl_tex_coord_in[0].st); +float text = getText(cogl_tex_coord_in[0].st); + +// Get the window texture and fade it according to the effect mask. +cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st) * rain.y; + +// This is used to fade out the remaining trails in the end. +float finalFade = 1-clamp((uProgress-FINAL_FADE_START_TIME)/ +(1-FINAL_FADE_START_TIME), 0, 1); +float rainAlpha = finalFade * rain.x; + +// Fade at window borders. +vec2 pos = cogl_tex_coord_in[0].st * vec2(uSizeX, uSizeY); +rainAlpha *= clamp(pos.x / EDGE_FADE, 0, 1); +rainAlpha *= clamp(pos.y / EDGE_FADE, 0, 1); +rainAlpha *= clamp((uSizeX - pos.x) / EDGE_FADE, 0, 1); +rainAlpha *= clamp((uSizeY - pos.y) / EDGE_FADE, 0, 1); + +// Add the matrix effect to the window. +vec3 trailColor = vec3(${trailColor.red / 255}, +${trailColor.green / 255}, +${trailColor.blue / 255}); +vec3 tipColor = vec3(${tipColor.red / 255}, +${tipColor.green / 255}, +${tipColor.blue / 255}); +cogl_color_out.rgb += mix(trailColor, tipColor, min(1, pow(rainAlpha+0.1, 4))) * rainAlpha * text; + +// These are pretty useful for understanding how this works. +// cogl_color_out = vec4(vec3(text), 1); +// cogl_color_out = vec4(vec3(rain.x), 1); +// cogl_color_out = vec4(vec3(rain.y), 1); +} +`); + }; + + // This is overridden to bind the font texture for drawing. Sadly, this seems to be + // impossible under GNOME 3.3x as this.get_pipeline() is not available. It was called + // get_target() back then but this is not wrapped in GJS. + // https://gitlab.gnome.org/GNOME/mutter/-/blob/gnome-3-36/clutter/clutter/clutter-offscreen-effect.c#L598 + vfunc_paint_target(node, paint_context) { + const pipeline = this.get_pipeline(); + pipeline.set_layer_texture(1, this._fontTexture.get_texture()); + this.set_uniform_value('uFontTexture', 1); + super.vfunc_paint_target(node, paint_context); + } + }); +} + +var MatrixEffect = class MatrixEffect { + + // ---------------------------------------------------------------------- static methods + + static getMinShellVersion() { + return [40, 0]; + } + + static getSettingsPrefix() { + return 'matrix'; + } + + static getLabel() { + return 'Matrix'; + } + + static initPreferences(dialog) { + + dialog.getBuilder().add_from_resource('/ui/gtk4/matrixPage.ui'); + + // Bind all properties. + dialog.bindAdjustment('matrix-animation-time'); + dialog.bindAdjustment('matrix-scale'); + dialog.bindAdjustment('matrix-randomness'); + dialog.bindColorButton('matrix-trail-color'); + dialog.bindColorButton('matrix-tip-color'); + + const stack = dialog.getBuilder().get_object('main-stack'); + stack.add_titled(dialog.getBuilder().get_object('matrix-prefs'), 'matrix', 'Matrix'); + } + + static createShader(settings) { + return new MatrixShader(settings); + } +} \ No newline at end of file diff --git a/src/TRexEffect.js b/src/TRexEffect.js new file mode 100644 index 0000000..e302ac3 --- /dev/null +++ b/src/TRexEffect.js @@ -0,0 +1,204 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// ) ( // +// ( /( ( ( ) ( ( ( ( )\ ) ( ( // +// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // +// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // +// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // +// | '_ \ || | '_| ' \)) | ' \()| || | \ 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 ExtensionUtils = imports.misc.extensionUtils; +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const utils = Me.imports.src.utils; + +////////////////////////////////////////////////////////////////////////////////////////// +// This effect tears your windows apart with a series of violent scratches! // +// This effect is not available on GNOME 3.3x, due to the limitation described in the // +// documentation of vfunc_paint_target further down in this file. // +////////////////////////////////////////////////////////////////////////////////////////// + +let TRexShader = null; + +if (utils.isInShellProcess()) { + + const {Clutter, GdkPixbuf, Cogl} = imports.gi; + const shaderSnippets = Me.imports.src.shaderSnippets; + + + TRexShader = GObject.registerClass({Properties: {}, Signals: {}}, + class TRexShader extends Clutter.ShaderEffect { + _init(settings) { + super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); + + // Load the claw texture. As the shader is re-created for each window animation, + // this texture is also re-created each time. This could be improved in the future! + // See assets/README.md for how this texture was created. + const clawData = GdkPixbuf.Pixbuf.new_from_resource('/img/claws.png'); + this._clawTexture = new Clutter.Image(); + this._clawTexture.set_data( + clawData.get_pixels(), Cogl.PixelFormat.RGB_888, clawData.width, + clawData.height, clawData.rowstride); + + const color = + Clutter.Color.from_string(settings.get_string('claw-scratch-color'))[1]; + + this.set_shader_source(` + +// Inject some common shader snippets. +${shaderSnippets.standardUniforms()} +${shaderSnippets.noise()} + +// See assets/README.md for how this texture was created. +uniform sampler2D uClawTexture; + +const vec2 SEED = vec2(${Math.random()}, ${Math.random()}); +const float CLAW_SIZE = ${settings.get_double('claw-scratch-scale')}; +const float NUM_CLAWS = ${settings.get_int('claw-scratch-count')}; +const float WARP_INTENSITY = 1.0 + ${settings.get_double('claw-scratch-warp')}; +const float FLASH_INTENSITY = 0.1; +const float MAX_SPAWN_TIME = 0.5; // Scratches will only start in the first half of the animation. +const float FF_TIME = 0.5; // Relative time for the final fade to transparency. + +// This method generates a grid of randomly rotated, slightly shifted and scaled +// UV squares. It returns the texture coords of the UV square at the given actor +// coordinates. If these do not fall into one of the UV grids, the coordinates of +// the closest UV grid will be clamped and returned. +vec2 getClawUV(vec2 texCoords, float gridScale, vec2 seed) { + +// Shift coordinates by a random offset and make sure the have a 1:1 aspect ratio. +vec2 coords = texCoords + hash2D(seed); +coords *= uSizeX < uSizeY ? vec2(1.0, 1.0 * uSizeY / uSizeX) : vec2(1.0 * uSizeX / uSizeY, 1.0); + +// Apply global scale. +coords *= gridScale; + +// Get grid cell coordinates in [0..1]. +vec2 cellUV = mod(coords, vec2(1)); + +// This is unique for each cell. +vec2 cellID = coords-cellUV + vec2(362.456); + +// Add random rotation, scale and offset to each grid cell. +float scale = mix(0.8, 1.0, hash(cellID*seed*134.451)); +float offsetX = mix(0.0, 1.0 - scale, hash(cellID*seed*54.4129)); +float offsetY = mix(0.0, 1.0 - scale, hash(cellID*seed*25.3089)); +float rotation = mix(0.0, 2.0 * 3.141, hash(cellID*seed*2.99837)); + +cellUV -= vec2(offsetX, offsetY); +cellUV /= scale; + +cellUV -= 0.5; +cellUV = vec2(cellUV.x * cos(rotation) - cellUV.y * sin(rotation), +cellUV.x * sin(rotation) + cellUV.y * cos(rotation)); +cellUV += 0.5; + +// Clamp resulting coordinates. +return clamp(cellUV, vec2(0), vec2(1)); +} + +void main() { + +// Warp the texture coordinates to create a blow-up effect. +vec2 coords = cogl_tex_coord_in[0].st * 2.0 - 1.0; +float dist = length(coords); +coords = (coords/dist * pow(dist, WARP_INTENSITY)) * 0.5 + 0.5; +coords = mix(cogl_tex_coord_in[0].st, coords, uProgress); + +// 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 +// add a value to make the scratch appear later. +float scratchMap = 1.0; +for (int i=0; i uProgress ? 1 : 0); + +// Add colorful flashes. +float flashIntensity = 1.0 / FLASH_INTENSITY * (scratchMap - uProgress) + 1; +if (flashIntensity < 0 || flashIntensity >= 1) { +flashIntensity = 0; +} + +vec3 flashColor = vec3(${color.red / 255}, +${color.green / 255}, +${color.blue / 255}) * ${color.alpha / 255}; + +cogl_color_out.rgb += flashIntensity * mix(flashColor, vec3(0), uProgress); + +// Fade out the remaining shards. +float fade = smoothstep(0, 1, 1 - clamp((uProgress - 1.0 + FF_TIME)/FF_TIME, 0, 1)); +cogl_color_out *= fade; + +// These are pretty useful for understanding how this works. +// cogl_color_out = vec4(vec3(flashIntensity), 1); +// cogl_color_out = vec4(vec3(scratchMap), 1); +} +`); + }; + + // This is overridden to bind the claw texture for drawing. Sadly, this seems to be + // impossible under GNOME 3.3x as this.get_pipeline() is not available. It was called + // get_target() back then but this is not wrapped in GJS. + // https://gitlab.gnome.org/GNOME/mutter/-/blob/gnome-3-36/clutter/clutter/clutter-offscreen-effect.c#L598 + vfunc_paint_target(node, paint_context) { + const pipeline = this.get_pipeline(); + pipeline.set_layer_texture(1, this._clawTexture.get_texture()); + this.set_uniform_value('uClawTexture', 1); + super.vfunc_paint_target(node, paint_context); + } + }); +} + +var TRexEffect = class TRexEffect { + + // ---------------------------------------------------------------------- static methods + + static getMinShellVersion() { + return [40, 0]; + } + + static getSettingsPrefix() { + return 'trex'; + } + + static getLabel() { + return 'T-Rex Attack'; + } + + static initPreferences(dialog) { + + dialog.getBuilder().add_from_resource('/ui/gtk4/trexPage.ui'); + + // Bind all properties. + dialog.bindAdjustment('trex-animation-time'); + dialog.bindColorButton('claw-scratch-color'); + dialog.bindAdjustment('claw-scratch-scale'); + dialog.bindAdjustment('claw-scratch-count'); + dialog.bindAdjustment('claw-scratch-warp'); + + const stack = dialog.getBuilder().get_object('main-stack'); + stack.add_titled( + dialog.getBuilder().get_object('trex-prefs'), 'trex', 'T-Rex Attack'); + } + + static createShader(settings) { + return new TRexShader(settings); + } +} \ No newline at end of file diff --git a/src/TVEffect.js b/src/TVEffect.js new file mode 100644 index 0000000..1d9d3f5 --- /dev/null +++ b/src/TVEffect.js @@ -0,0 +1,133 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// ) ( // +// ( /( ( ( ) ( ( ( ( )\ ) ( ( // +// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // +// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // +// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // +// | '_ \ || | '_| ' \)) | ' \()| || | \ 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 ExtensionUtils = imports.misc.extensionUtils; +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const utils = Me.imports.src.utils; + +////////////////////////////////////////////////////////////////////////////////////////// +// The TVEffectShader hides the actor by making it first transparent from top and // +// bottom towards the middle and then hiding the resulting line from left and right // +// towards the center. // +////////////////////////////////////////////////////////////////////////////////////////// + + +let TVEffectShader = null; + +if (utils.isInShellProcess()) { + + const Clutter = imports.gi.Clutter; + const shaderSnippets = Me.imports.src.shaderSnippets; + + TVEffectShader = GObject.registerClass( + {Properties: {}, Signals: {}}, class TVEffectShader extends Clutter.ShaderEffect { + _init(settings) { + super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); + + const color = + Clutter.Color.from_string(settings.get_string('tv-effect-color'))[1]; + + this.set_shader_source(` + + // Inject some common shader snippets. + ${shaderSnippets.standardUniforms()} + + const float BLUR_WIDTH = 0.01; // Width of the gradients. + const float TB_TIME = 0.7; // Relative time for the top/bottom animation. + const float LR_TIME = 0.4; // Relative time for the left/right animation. + const float LR_DELAY = 0.6; // Delay after which the left/right animation starts. + const float FF_TIME = 0.2; // Relative time for the final fade to transparency. + + void main() { + + // All of these are in [0..1] during the different stages of the animation. + // tb refers to the top-bottom animation. + // lr refers to the left-right animation. + // ff refers to the final fade animation. + float tbProgress = smoothstep(0, 1, clamp(uProgress/TB_TIME, 0, 1)); + float lrProgress = smoothstep(0, 1, clamp((uProgress - LR_DELAY)/LR_TIME, 0, 1)); + float ffProgress = smoothstep(0, 1, clamp((uProgress - 1.0 + FF_TIME)/FF_TIME, 0, 1)); + + // This is a top-center-bottom gradient in [0..1..0] + float tb = cogl_tex_coord_in[0].t * 2; + tb = tb < 1 ? tb : 2 - tb; + + // This is a left-center-right gradient in [0..1..0] + float lr = cogl_tex_coord_in[0].s * 2; + lr = lr < 1 ? lr : 2 - lr; + + // Combine the progress values with the gradients to create the alpha masks. + float tbMask = 1 - smoothstep(0, 1, clamp((tbProgress - tb) / BLUR_WIDTH, 0, 1)); + float lrMask = 1 - smoothstep(0, 1, clamp((lrProgress - lr) / BLUR_WIDTH, 0, 1)); + float ffMask = 1 - smoothstep(0, 1, ffProgress); + + // Assemble the final alpha value. + float mask = tbMask * lrMask * ffMask; + + vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st); + vec4 effectColor = vec4(${color.red / 255}, + ${color.green / 255}, + ${color.blue / 255}, 1.0) * windowColor.a; + + windowColor.rgb = mix(windowColor.rgb, effectColor.rgb, smoothstep(0, 1, uProgress)); + + cogl_color_out = windowColor * mask; + + // These are pretty useful for understanding how this works. + // cogl_color_out = vec4(vec3(tbMask), 1); + // cogl_color_out = vec4(vec3(lrMask), 1); + // cogl_color_out = vec4(vec3(ffMask), 1); + // cogl_color_out = vec4(vec3(mask), 1); + } + `); + }; + }); +} + +var TVEffect = class TVEffect { + + // ---------------------------------------------------------------------- static methods + + static getMinShellVersion() { + return [3, 36]; + } + + static getSettingsPrefix() { + return 'tv'; + } + + static getLabel() { + return 'TV Effect'; + } + + static initPreferences(dialog) { + + dialog.getBuilder().add_from_resource( + `/ui/${utils.isGTK4() ? 'gtk4' : 'gtk3'}/tvPage.ui`); + + // Bind all properties. + dialog.bindAdjustment('tv-animation-time'); + dialog.bindColorButton('tv-effect-color'); + + const stack = dialog.getBuilder().get_object('main-stack'); + stack.add_titled(dialog.getBuilder().get_object('tv-prefs'), 'tv', 'TV Effect'); + } + + static createShader(settings) { + return new TVEffectShader(settings); + } +} \ No newline at end of file diff --git a/src/extension/FireShader.js b/src/extension/FireShader.js deleted file mode 100644 index 07644c4..0000000 --- a/src/extension/FireShader.js +++ /dev/null @@ -1,156 +0,0 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// ) ( // -// ( /( ( ( ) ( ( ( ( )\ ) ( ( // -// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // -// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // -// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // -// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< // -// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ // -// |__/ // -// Copyright (c) 2021 Simon Schneegans // -// Released under the GPLv3 or later. See LICENSE file for details. // -////////////////////////////////////////////////////////////////////////////////////////// - -'use strict'; - -const {Clutter, GObject} = imports.gi; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const shaderSnippets = Me.imports.src.extension.shaderSnippets; - -////////////////////////////////////////////////////////////////////////////////////////// -// This effect is a homage to the good old Compiz days. However, it is implemented // -// quite differently. While Compiz used a particle system, this effect uses a noise // -// shader. The noise is moved vertically over time and mapped to a configurable color // -// gradient. It is faded to transparency towards the edges of the window. In addition, // -// there are a couple of moving gradients which fade-in or fade-out the fire effect. // -////////////////////////////////////////////////////////////////////////////////////////// - -var FireShader = GObject.registerClass({Properties: {}, Signals: {}}, - class FireShader extends Clutter.ShaderEffect { - _init(settings) { - super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); - - // Load the gradient values from the settings. We directly inject the values in the - // GLSL code below. The shader is compiled once for each window-closing anyways. In - // the future, we may want to prevent this frequent recompilations of shaders, - // though. - const gradient = []; - for (let i = 1; i <= 5; i++) { - const color = Clutter.Color.from_string(settings.get_string('fire-color-' + i))[1]; - gradient.push(`vec4(${color.red / 255}, ${color.green / 255}, ${ - color.blue / 255}, ${color.alpha / 255})`); - } - - this.set_shader_source(` - - // Inject some common shader snippets. - ${shaderSnippets.standardUniforms()} - ${shaderSnippets.noise()} - - // These may be configurable in the future. - const float EDGE_FADE = 90; - const float FADE_WIDTH = 0.1; - const float HIDE_TIME = 0.4; - const vec2 FIRE_SCALE = vec2(400, 600) * ${settings.get_double('flame-scale')}; - const float FIRE_SPEED = ${settings.get_double('flame-movement-speed')}; - - // This maps the input value from [0..1] to a color from the gradient. - vec4 getFireColor(float v) { - const float steps[5] = float[](0.0, 0.2, 0.35, 0.5, 0.8); - const vec4 colors[5] = vec4[]( - ${gradient[0]}, - ${gradient[1]}, - ${gradient[2]}, - ${gradient[3]}, - ${gradient[4]} - ); - - if (v < steps[0]) { - return colors[0]; - } - - for (int i=0; i<4; ++i) { - if (v <= steps[i+1]) { - return mix(colors[i], colors[i+1], vec4(v - - steps[i])/(steps[i+1]-steps[i])); - } - } - - return colors[4]; - } - - // This method requires the uniforms from standardUniforms() to be available. - // It returns two values: The first is an alpha value which can be used for the window - // texture. This gradually dissolves the window from top to bottom. The second can be used - // to mask any effect, it will be most opaque where the window is currently fading and - // gradually dissolve to zero over time. - // hideTime: A value in [0..1]. It determines the percentage of the animation which - // is spent for hiding the window. 1-hideTime will be spent thereafter for - // dissolving the effect mask. - // fadeWidth: The relative size of the window-hiding gradient in [0..1]. - // edgeFadeWidth: The pixel width of the effect fading range at the edges of the window. - vec2 effectMask(float hideTime, float fadeWidth, float edgeFadeWidth) { - float burnProgress = clamp(uProgress/hideTime, 0, 1); - float afterBurnProgress = clamp((uProgress-hideTime)/(1-hideTime), 0, 1); - - // Gradient from top to bottom. - float t = cogl_tex_coord_in[0].t * (1 - fadeWidth); - - // Visible part of the window. Gradually dissolves towards the bottom. - float windowMask = 1 - clamp((burnProgress - t) / fadeWidth, 0, 1); - - // Gradient from top burning window. - float effectMask = clamp(t*(1-windowMask)/burnProgress, 0, 1); - - // Fade-out when the window burned down. - if (uProgress > hideTime) { - float fade = sqrt(1-afterBurnProgress*afterBurnProgress); - effectMask *= mix(1, 1-t, afterBurnProgress) * fade; - } - - // Fade at window borders. - vec2 pos = cogl_tex_coord_in[0].st * vec2(uSizeX, uSizeY); - effectMask *= smoothstep(0, 1, clamp(pos.x / edgeFadeWidth, 0, 1)); - effectMask *= smoothstep(0, 1, clamp(pos.y / edgeFadeWidth, 0, 1)); - effectMask *= smoothstep(0, 1, clamp((uSizeX - pos.x) / edgeFadeWidth, 0, 1)); - effectMask *= smoothstep(0, 1, clamp((uSizeY - pos.y) / edgeFadeWidth, 0, 1)); - - return vec2(windowMask, effectMask); - } - - void main() { - - // Get a noise value which moves vertically in time. - vec2 uv = cogl_tex_coord_in[0].st * vec2(uSizeX, uSizeY) / FIRE_SCALE; - uv.y += uTime * FIRE_SPEED; - - #if ${settings.get_boolean('flame-3d-noise') ? 1 : 0} - float noise = noise3D(vec3(uv*7.5, uTime*FIRE_SPEED*3.0), 5); - #else - float noise = noise2D(uv * 7.5, 5); - #endif - - // Modulate noise by effect mask. - vec2 effectMask = effectMask(HIDE_TIME, FADE_WIDTH, EDGE_FADE); - noise *= effectMask.y; - - // Map noise value to color. - vec4 fire = getFireColor(noise); - fire.rgb *= fire.a; - - // Get the window texture and fade it according to the effect mask. - cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st) * effectMask.x; - - // Add the fire to the window. - cogl_color_out += fire; - - // These are pretty useful for understanding how this works. - // cogl_color_out = vec4(vec3(noise), 1); - // cogl_color_out = vec4(vec3(effectMask.x), 1); - // cogl_color_out = vec4(vec3(effectMask.y), 1); - } - `); - }; -}); \ No newline at end of file diff --git a/src/extension/MatrixShader.js b/src/extension/MatrixShader.js deleted file mode 100644 index fe0ad38..0000000 --- a/src/extension/MatrixShader.js +++ /dev/null @@ -1,147 +0,0 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// ) ( // -// ( /( ( ( ) ( ( ( ( )\ ) ( ( // -// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // -// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // -// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // -// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< // -// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ // -// |__/ // -// Copyright (c) 2021 Simon Schneegans // -// Released under the GPLv3 or later. See LICENSE file for details. // -////////////////////////////////////////////////////////////////////////////////////////// - -'use strict'; - -const {Clutter, GObject, GdkPixbuf, Cogl} = imports.gi; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const shaderSnippets = Me.imports.src.extension.shaderSnippets; - -////////////////////////////////////////////////////////////////////////////////////////// -// The MatrixShader multiplies a grid of random letters with some gradients which are // -// moving from top to bottom. The speed of the moving gradients is chosen randomly. // -// Also, there is a random delay making the gradients not drop all at the same time. // -// This effect is not available on GNOME 3.3x, due to the limitation described in the // -// documentation of vfunc_paint_target further down in this file. // -////////////////////////////////////////////////////////////////////////////////////////// - -var MatrixShader = GObject.registerClass({Properties: {}, Signals: {}}, - class MatrixShader extends Clutter.ShaderEffect { - _init(settings) { - super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); - - // Load the font texture. As the shader is re-created for each window animation, this - // texture is also re-created each time. This could be improved in the future! - const fontData = GdkPixbuf.Pixbuf.new_from_resource('/img/matrixFont.png'); - this._fontTexture = new Clutter.Image(); - this._fontTexture.set_data( - fontData.get_pixels(), - fontData.has_alpha ? Cogl.PixelFormat.RGBA_8888 : Cogl.PixelFormat.RGB_888, - fontData.width, fontData.height, fontData.rowstride); - - const trailColor = - Clutter.Color.from_string(settings.get_string('matrix-trail-color'))[1]; - const tipColor = - Clutter.Color.from_string(settings.get_string('matrix-tip-color'))[1]; - - // The technique for this effect was inspired by - // https://www.shadertoy.com/view/ldccW4, however the implementation is quite - // different as the letters drop only once and there is no need for a noise texture. - this.set_shader_source(` - - // Inject some common shader snippets. - ${shaderSnippets.standardUniforms()} - ${shaderSnippets.noise()} - - uniform sampler2D uFontTexture; - - // These may be configurable in the future. - const float EDGE_FADE = 30; - const float FADE_WIDTH = 150; - const float TRAIL_LENGTH = 0.2; - const float FINAL_FADE_START_TIME = 0.8; - const float LETTER_TILES = 16.0; - const float LETTER_SIZE = ${settings.get_int('matrix-scale')}; - const float LETTER_FLICKER_SPEED = 2.0; - const float RANDOMNESS = ${settings.get_double('matrix-randomness')}; - - // This returns a flickering grid of random letters. - float getText(vec2 fragCoord) { - vec2 pixelCoords = fragCoord * vec2(uSizeX, uSizeY); - vec2 uv = mod(pixelCoords.xy, LETTER_SIZE)/LETTER_SIZE; - vec2 block = pixelCoords/LETTER_SIZE - uv; - - // Choose random letter. - uv += floor(hash2D(floor(hash2D(block)*vec2(12.9898,78.233) + LETTER_FLICKER_SPEED*uTime + 42.254))*LETTER_TILES); - - return texture2D(uFontTexture, uv/LETTER_TILES).r; - } - - // This returns two values: The first are gradients for the "raindrops" which move - // from top to bottom. This is used for fading the letters. The second value is set - // to one below each drop and to zero above it. This second value is used for fading - // the window texture. - vec2 getRain(vec2 fragCoord) { - vec2 coords = fragCoord * vec2(uSizeX, uSizeY); - coords.x -= mod(coords.x, LETTER_SIZE); - - float delay = fract(sin(coords.x)*78.233) * mix(0.0, 1.0, RANDOMNESS); - float speed = fract(cos(coords.x)*12.989) * mix(0.0, 0.3, RANDOMNESS) + 1.5; - - float distToDrop = (uProgress*2-delay)*speed - fragCoord.y; - float rainAlpha = distToDrop >= 0 ? exp(-distToDrop/TRAIL_LENGTH) : 0; - float windowAlpha = 1 - clamp(uSizeY*distToDrop, 0, FADE_WIDTH) / FADE_WIDTH; - return vec2(rainAlpha, windowAlpha); - } - - void main() { - - // Get a cool matrix effect. See comments for those methods above. - vec2 rain = getRain(cogl_tex_coord_in[0].st); - float text = getText(cogl_tex_coord_in[0].st); - - // Get the window texture and fade it according to the effect mask. - cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st) * rain.y; - - // This is used to fade out the remaining trails in the end. - float finalFade = 1-clamp((uProgress-FINAL_FADE_START_TIME)/ - (1-FINAL_FADE_START_TIME), 0, 1); - float rainAlpha = finalFade * rain.x; - - // Fade at window borders. - vec2 pos = cogl_tex_coord_in[0].st * vec2(uSizeX, uSizeY); - rainAlpha *= clamp(pos.x / EDGE_FADE, 0, 1); - rainAlpha *= clamp(pos.y / EDGE_FADE, 0, 1); - rainAlpha *= clamp((uSizeX - pos.x) / EDGE_FADE, 0, 1); - rainAlpha *= clamp((uSizeY - pos.y) / EDGE_FADE, 0, 1); - - // Add the matrix effect to the window. - vec3 trailColor = vec3(${trailColor.red / 255}, - ${trailColor.green / 255}, - ${trailColor.blue / 255}); - vec3 tipColor = vec3(${tipColor.red / 255}, - ${tipColor.green / 255}, - ${tipColor.blue / 255}); - cogl_color_out.rgb += mix(trailColor, tipColor, min(1, pow(rainAlpha+0.1, 4))) * rainAlpha * text; - - // These are pretty useful for understanding how this works. - // cogl_color_out = vec4(vec3(text), 1); - // cogl_color_out = vec4(vec3(rain.x), 1); - // cogl_color_out = vec4(vec3(rain.y), 1); - } - `); - }; - - // This is overridden to bind the font texture for drawing. Sadly, this seems to be - // impossible under GNOME 3.3x as this.get_pipeline() is not available. It was called - // get_target() back then but this is not wrapped in GJS. - // https://gitlab.gnome.org/GNOME/mutter/-/blob/gnome-3-36/clutter/clutter/clutter-offscreen-effect.c#L598 - vfunc_paint_target(node, paint_context) { - const pipeline = this.get_pipeline(); - pipeline.set_layer_texture(1, this._fontTexture.get_texture()); - this.set_uniform_value('uFontTexture', 1); - super.vfunc_paint_target(node, paint_context); - } -}); \ No newline at end of file diff --git a/src/extension/TRexShader.js b/src/extension/TRexShader.js deleted file mode 100644 index 14f4f5d..0000000 --- a/src/extension/TRexShader.js +++ /dev/null @@ -1,157 +0,0 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// ) ( // -// ( /( ( ( ) ( ( ( ( )\ ) ( ( // -// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // -// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // -// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // -// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< // -// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ // -// |__/ // -// Copyright (c) 2021 Simon Schneegans // -// Released under the GPLv3 or later. See LICENSE file for details. // -////////////////////////////////////////////////////////////////////////////////////////// - -'use strict'; - -const {Clutter, GObject, GdkPixbuf, Cogl} = imports.gi; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const shaderSnippets = Me.imports.src.extension.shaderSnippets; - -////////////////////////////////////////////////////////////////////////////////////////// -// This effect tears your windows apart with a series of violent scratches! // -// This effect is not available on GNOME 3.3x, due to the limitation described in the // -// documentation of vfunc_paint_target further down in this file. // -////////////////////////////////////////////////////////////////////////////////////////// - -var TRexShader = GObject.registerClass({Properties: {}, Signals: {}}, - class TRexShader extends Clutter.ShaderEffect { - _init(settings) { - super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); - - // Load the claw texture. As the shader is re-created for each window animation, this - // texture is also re-created each time. This could be improved in the future! - // See assets/README.md for how this texture was created. - const clawData = GdkPixbuf.Pixbuf.new_from_resource('/img/claws.png'); - this._clawTexture = new Clutter.Image(); - this._clawTexture.set_data( - clawData.get_pixels(), Cogl.PixelFormat.RGB_888, clawData.width, clawData.height, - clawData.rowstride); - - const color = Clutter.Color.from_string(settings.get_string('claw-scratch-color'))[1]; - - this.set_shader_source(` - - // Inject some common shader snippets. - ${shaderSnippets.standardUniforms()} - ${shaderSnippets.noise()} - - // See assets/README.md for how this texture was created. - uniform sampler2D uClawTexture; - - const vec2 SEED = vec2(${Math.random()}, ${Math.random()}); - const float CLAW_SIZE = ${settings.get_double('claw-scratch-scale')}; - const float NUM_CLAWS = ${settings.get_int('claw-scratch-count')}; - const float WARP_INTENSITY = 1.0 + ${settings.get_double('claw-scratch-warp')}; - const float FLASH_INTENSITY = 0.1; - const float MAX_SPAWN_TIME = 0.5; // Scratches will only start in the first half of the animation. - const float FF_TIME = 0.5; // Relative time for the final fade to transparency. - - // This method generates a grid of randomly rotated, slightly shifted and scaled - // UV squares. It returns the texture coords of the UV square at the given actor - // coordinates. If these do not fall into one of the UV grids, the coordinates of - // the closest UV grid will be clamped and returned. - vec2 getClawUV(vec2 texCoords, float gridScale, vec2 seed) { - - // Shift coordinates by a random offset and make sure the have a 1:1 aspect ratio. - vec2 coords = texCoords + hash2D(seed); - coords *= uSizeX < uSizeY ? vec2(1.0, 1.0 * uSizeY / uSizeX) : vec2(1.0 * uSizeX / uSizeY, 1.0); - - // Apply global scale. - coords *= gridScale; - - // Get grid cell coordinates in [0..1]. - vec2 cellUV = mod(coords, vec2(1)); - - // This is unique for each cell. - vec2 cellID = coords-cellUV + vec2(362.456); - - // Add random rotation, scale and offset to each grid cell. - float scale = mix(0.8, 1.0, hash(cellID*seed*134.451)); - float offsetX = mix(0.0, 1.0 - scale, hash(cellID*seed*54.4129)); - float offsetY = mix(0.0, 1.0 - scale, hash(cellID*seed*25.3089)); - float rotation = mix(0.0, 2.0 * 3.141, hash(cellID*seed*2.99837)); - - cellUV -= vec2(offsetX, offsetY); - cellUV /= scale; - - cellUV -= 0.5; - cellUV = vec2(cellUV.x * cos(rotation) - cellUV.y * sin(rotation), - cellUV.x * sin(rotation) + cellUV.y * cos(rotation)); - cellUV += 0.5; - - // Clamp resulting coordinates. - return clamp(cellUV, vec2(0), vec2(1)); - } - - void main() { - - // Warp the texture coordinates to create a blow-up effect. - vec2 coords = cogl_tex_coord_in[0].st * 2.0 - 1.0; - float dist = length(coords); - coords = (coords/dist * pow(dist, WARP_INTENSITY)) * 0.5 + 0.5; - coords = mix(cogl_tex_coord_in[0].st, coords, uProgress); - - // 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 - // add a value to make the scratch appear later. - float scratchMap = 1.0; - for (int i=0; i uProgress ? 1 : 0); - - // Add colorful flashes. - float flashIntensity = 1.0 / FLASH_INTENSITY * (scratchMap - uProgress) + 1; - if (flashIntensity < 0 || flashIntensity >= 1) { - flashIntensity = 0; - } - - vec3 flashColor = vec3(${color.red / 255}, - ${color.green / 255}, - ${color.blue / 255}) * ${color.alpha / 255}; - - cogl_color_out.rgb += flashIntensity * mix(flashColor, vec3(0), uProgress); - - // Fade out the remaining shards. - float fade = smoothstep(0, 1, 1 - clamp((uProgress - 1.0 + FF_TIME)/FF_TIME, 0, 1)); - cogl_color_out *= fade; - - // These are pretty useful for understanding how this works. - // cogl_color_out = vec4(vec3(flashIntensity), 1); - // cogl_color_out = vec4(vec3(scratchMap), 1); - } - `); - }; - - // This is overridden to bind the claw texture for drawing. Sadly, this seems to be - // impossible under GNOME 3.3x as this.get_pipeline() is not available. It was called - // get_target() back then but this is not wrapped in GJS. - // https://gitlab.gnome.org/GNOME/mutter/-/blob/gnome-3-36/clutter/clutter/clutter-offscreen-effect.c#L598 - vfunc_paint_target(node, paint_context) { - const pipeline = this.get_pipeline(); - pipeline.set_layer_texture(1, this._clawTexture.get_texture()); - this.set_uniform_value('uClawTexture', 1); - super.vfunc_paint_target(node, paint_context); - } -}); \ No newline at end of file diff --git a/src/extension/TVEffectShader.js b/src/extension/TVEffectShader.js deleted file mode 100644 index f60db07..0000000 --- a/src/extension/TVEffectShader.js +++ /dev/null @@ -1,90 +0,0 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// ) ( // -// ( /( ( ( ) ( ( ( ( )\ ) ( ( // -// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // -// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // -// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // -// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< // -// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ // -// |__/ // -// Copyright (c) 2021 Simon Schneegans // -// Released under the GPLv3 or later. See LICENSE file for details. // -////////////////////////////////////////////////////////////////////////////////////////// - -'use strict'; - -const {Clutter, GObject} = imports.gi; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const shaderSnippets = Me.imports.src.extension.shaderSnippets; - -////////////////////////////////////////////////////////////////////////////////////////// -// The TVEffectShader hides the actor by making it first transparent from top and // -// bottom towards the middle and then hiding the resulting line from left and right // -// towards the center. // -////////////////////////////////////////////////////////////////////////////////////////// - -var TVEffectShader = GObject.registerClass( - {Properties: {}, Signals: {}}, class TVEffectShader extends Clutter.ShaderEffect { - _init(settings) { - super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); - - const color = - Clutter.Color.from_string(settings.get_string('tv-effect-color'))[1]; - - this.set_shader_source(` - - // Inject some common shader snippets. - ${shaderSnippets.standardUniforms()} - - const float BLUR_WIDTH = 0.01; // Width of the gradients. - const float TB_TIME = 0.7; // Relative time for the top/bottom animation. - const float LR_TIME = 0.4; // Relative time for the left/right animation. - const float LR_DELAY = 0.6; // Delay after which the left/right animation starts. - const float FF_TIME = 0.2; // Relative time for the final fade to transparency. - - void main() { - - // All of these are in [0..1] during the different stages of the animation. - // tb refers to the top-bottom animation. - // lr refers to the left-right animation. - // ff refers to the final fade animation. - float tbProgress = smoothstep(0, 1, clamp(uProgress/TB_TIME, 0, 1)); - float lrProgress = smoothstep(0, 1, clamp((uProgress - LR_DELAY)/LR_TIME, 0, 1)); - float ffProgress = smoothstep(0, 1, clamp((uProgress - 1.0 + FF_TIME)/FF_TIME, 0, 1)); - - // This is a top-center-bottom gradient in [0..1..0] - float tb = cogl_tex_coord_in[0].t * 2; - tb = tb < 1 ? tb : 2 - tb; - - // This is a left-center-right gradient in [0..1..0] - float lr = cogl_tex_coord_in[0].s * 2; - lr = lr < 1 ? lr : 2 - lr; - - // Combine the progress values with the gradients to create the alpha masks. - float tbMask = 1 - smoothstep(0, 1, clamp((tbProgress - tb) / BLUR_WIDTH, 0, 1)); - float lrMask = 1 - smoothstep(0, 1, clamp((lrProgress - lr) / BLUR_WIDTH, 0, 1)); - float ffMask = 1 - smoothstep(0, 1, ffProgress); - - // Assemble the final alpha value. - float mask = tbMask * lrMask * ffMask; - - vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st); - vec4 effectColor = vec4(${color.red / 255}, - ${color.green / 255}, - ${color.blue / 255}, 1.0) * windowColor.a; - - windowColor.rgb = mix(windowColor.rgb, effectColor.rgb, smoothstep(0, 1, uProgress)); - - cogl_color_out = windowColor * mask; - - // These are pretty useful for understanding how this works. - // cogl_color_out = vec4(vec3(tbMask), 1); - // cogl_color_out = vec4(vec3(lrMask), 1); - // cogl_color_out = vec4(vec3(ffMask), 1); - // cogl_color_out = vec4(vec3(mask), 1); - } - `); - }; - }); \ No newline at end of file diff --git a/src/prefs/FirePage.js b/src/prefs/FirePage.js deleted file mode 100644 index fc8fe64..0000000 --- a/src/prefs/FirePage.js +++ /dev/null @@ -1,161 +0,0 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// ) ( // -// ( /( ( ( ) ( ( ( ( )\ ) ( ( // -// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // -// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // -// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // -// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< // -// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ // -// |__/ // -// Copyright (c) 2021 Simon Schneegans // -// Released under the GPLv3 or later. See LICENSE file for details. // -////////////////////////////////////////////////////////////////////////////////////////// - -'use strict'; - -const {Gio} = imports.gi; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const utils = Me.imports.src.common.utils; - -////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// - -var FirePage = class FirePage { - - // ---------------------------------------------------------------------- static methods - - static getMinShellVersion() { - return [3, 36]; - } - - static getSettingsPrefix() { - return 'fire'; - } - - static getLabel() { - return 'Fire'; - } - - static initPreferences(dialog) { - - dialog.getBuilder().add_from_resource( - `/ui/${utils.isGTK4() ? 'gtk4' : 'gtk3'}/firePage.ui`); - - // Bind all properties. - dialog.bindAdjustment('fire-animation-time'); - dialog.bindAdjustment('flame-movement-speed'); - dialog.bindAdjustment('flame-scale'); - dialog.bindSwitch('flame-3d-noise'); - dialog.bindColorButton('fire-color-1'); - dialog.bindColorButton('fire-color-2'); - dialog.bindColorButton('fire-color-3'); - dialog.bindColorButton('fire-color-4'); - dialog.bindColorButton('fire-color-5'); - - // The fire-gradient-reset button needs to be bound explicitly. - dialog.getBuilder().get_object('reset-fire-colors').connect('clicked', () => { - dialog.getSettings().reset('fire-color-1'); - dialog.getSettings().reset('fire-color-2'); - dialog.getSettings().reset('fire-color-3'); - dialog.getSettings().reset('fire-color-4'); - dialog.getSettings().reset('fire-color-5'); - }); - - // Initialize the fire-preset dropdown. - FirePage._createFirePresets(dialog); - - const stack = dialog.getBuilder().get_object('main-stack'); - stack.add_titled(dialog.getBuilder().get_object('fire-prefs'), 'fire', 'Fire'); - } - - // ----------------------------------------------------------------------- private stuff - - // This populates the preset dropdown menu for the fire options. - static _createFirePresets(dialog) { - dialog.getBuilder().get_object('settings-widget').connect('realize', (widget) => { - const presets = [ - { - name: 'Default Fire', - scale: 1.0, - speed: 0.5, - color1: 'rgba(76, 51, 25, 0.0)', - color2: 'rgba(180, 55, 30, 0.7)', - color3: 'rgba(255, 76, 38, 0.9)', - color4: 'rgba(255, 166, 25, 1)', - color5: 'rgba(255, 255, 255, 1)' - }, - { - name: 'Hell Fire', - scale: 1.5, - speed: 0.2, - color1: 'rgba(0,0,0,0)', - color2: 'rgba(103,7,80,0.5)', - color3: 'rgba(150,0,24,0.9)', - color4: 'rgb(255,200,0)', - color5: 'rgba(255, 255, 255, 1)' - }, - { - name: 'Dark and Smutty', - scale: 1.0, - speed: 0.5, - color1: 'rgba(0,0,0,0)', - color2: 'rgba(36,3,0,0.5)', - color3: 'rgba(150,0,24,0.9)', - color4: 'rgb(255,177,21)', - color5: 'rgb(255,238,166)' - }, - { - name: 'Cold Breeze', - scale: 1.5, - speed: -0.1, - color1: 'rgba(0,110,255,0)', - color2: 'rgba(30,111,180,0.24)', - color3: 'rgba(38,181,255,0.54)', - color4: 'rgba(34,162,255,0.84)', - color5: 'rgb(97,189,255)' - }, - { - name: 'Santa is Coming', - scale: 0.4, - speed: -0.5, - color1: 'rgba(0,110,255,0)', - color2: 'rgba(208,233,255,0.24)', - color3: 'rgba(207,235,255,0.84)', - color4: 'rgb(208,243,255)', - color5: 'rgb(255,255,255)' - } - ]; - - const menu = Gio.Menu.new(); - const group = Gio.SimpleActionGroup.new(); - const groupName = 'presets'; - - // Add all presets. - presets.forEach((preset, i) => { - const actionName = 'fire' + i; - menu.append(preset.name, groupName + '.' + actionName); - let action = Gio.SimpleAction.new(actionName, null); - - // Load the preset on activation. - action.connect('activate', () => { - dialog.getSettings().set_double('flame-movement-speed', preset.speed); - dialog.getSettings().set_double('flame-scale', preset.scale); - dialog.getSettings().set_string('fire-color-1', preset.color1); - dialog.getSettings().set_string('fire-color-2', preset.color2); - dialog.getSettings().set_string('fire-color-3', preset.color3); - dialog.getSettings().set_string('fire-color-4', preset.color4); - dialog.getSettings().set_string('fire-color-5', preset.color5); - }); - - group.add_action(action); - }); - - dialog.getBuilder().get_object('fire-preset-button').set_menu_model(menu); - - const root = utils.isGTK4() ? widget.get_root() : widget.get_toplevel(); - root.insert_action_group(groupName, group); - }); - } -} \ No newline at end of file diff --git a/src/prefs/MatrixPage.js b/src/prefs/MatrixPage.js deleted file mode 100644 index d4eb561..0000000 --- a/src/prefs/MatrixPage.js +++ /dev/null @@ -1,53 +0,0 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// ) ( // -// ( /( ( ( ) ( ( ( ( )\ ) ( ( // -// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // -// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // -// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // -// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< // -// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ // -// |__/ // -// Copyright (c) 2021 Simon Schneegans // -// Released under the GPLv3 or later. See LICENSE file for details. // -////////////////////////////////////////////////////////////////////////////////////////// - -'use strict'; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const utils = Me.imports.src.common.utils; - -////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// - -var MatrixPage = class MatrixPage { - - // ---------------------------------------------------------------------- static methods - - static getMinShellVersion() { - return [40, 0]; - } - - static getSettingsPrefix() { - return 'matrix'; - } - - static getLabel() { - return 'Matrix'; - } - - static initPreferences(dialog) { - - dialog.getBuilder().add_from_resource('/ui/gtk4/matrixPage.ui'); - - // Bind all properties. - dialog.bindAdjustment('matrix-animation-time'); - dialog.bindAdjustment('matrix-scale'); - dialog.bindAdjustment('matrix-randomness'); - dialog.bindColorButton('matrix-trail-color'); - dialog.bindColorButton('matrix-tip-color'); - - const stack = dialog.getBuilder().get_object('main-stack'); - stack.add_titled(dialog.getBuilder().get_object('matrix-prefs'), 'matrix', 'Matrix'); - } -} \ No newline at end of file diff --git a/src/prefs/TRexPage.js b/src/prefs/TRexPage.js deleted file mode 100644 index 709cff9..0000000 --- a/src/prefs/TRexPage.js +++ /dev/null @@ -1,54 +0,0 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// ) ( // -// ( /( ( ( ) ( ( ( ( )\ ) ( ( // -// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // -// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // -// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // -// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< // -// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ // -// |__/ // -// Copyright (c) 2021 Simon Schneegans // -// Released under the GPLv3 or later. See LICENSE file for details. // -////////////////////////////////////////////////////////////////////////////////////////// - -'use strict'; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const utils = Me.imports.src.common.utils; - -////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// - -var TRexPage = class TRexPage { - - // ---------------------------------------------------------------------- static methods - - static getMinShellVersion() { - return [40, 0]; - } - - static getSettingsPrefix() { - return 'trex'; - } - - static getLabel() { - return 'T-Rex Attack'; - } - - static initPreferences(dialog) { - - dialog.getBuilder().add_from_resource('/ui/gtk4/trexPage.ui'); - - // Bind all properties. - dialog.bindAdjustment('trex-animation-time'); - dialog.bindColorButton('claw-scratch-color'); - dialog.bindAdjustment('claw-scratch-scale'); - dialog.bindAdjustment('claw-scratch-count'); - dialog.bindAdjustment('claw-scratch-warp'); - - const stack = dialog.getBuilder().get_object('main-stack'); - stack.add_titled( - dialog.getBuilder().get_object('trex-prefs'), 'trex', 'T-Rex Attack'); - } -} \ No newline at end of file diff --git a/src/prefs/TVEffectPage.js b/src/prefs/TVEffectPage.js deleted file mode 100644 index 59973f6..0000000 --- a/src/prefs/TVEffectPage.js +++ /dev/null @@ -1,51 +0,0 @@ -////////////////////////////////////////////////////////////////////////////////////////// -// ) ( // -// ( /( ( ( ) ( ( ( ( )\ ) ( ( // -// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // -// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // -// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // -// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< // -// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ // -// |__/ // -// Copyright (c) 2021 Simon Schneegans // -// Released under the GPLv3 or later. See LICENSE file for details. // -////////////////////////////////////////////////////////////////////////////////////////// - -'use strict'; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const utils = Me.imports.src.common.utils; - -////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////// - -var TVEffectPage = class TVEffectPage { - - // ---------------------------------------------------------------------- static methods - - static getMinShellVersion() { - return [3, 36]; - } - - static getSettingsPrefix() { - return 'tv'; - } - - static getLabel() { - return 'TV Effect'; - } - - static initPreferences(dialog) { - - dialog.getBuilder().add_from_resource( - `/ui/${utils.isGTK4() ? 'gtk4' : 'gtk3'}/tvPage.ui`); - - // Bind all properties. - dialog.bindAdjustment('tv-animation-time'); - dialog.bindColorButton('tv-effect-color'); - - const stack = dialog.getBuilder().get_object('main-stack'); - stack.add_titled(dialog.getBuilder().get_object('tv-prefs'), 'tv', 'TV Effect'); - } -} \ No newline at end of file diff --git a/src/extension/shaderSnippets.js b/src/shaderSnippets.js similarity index 100% rename from src/extension/shaderSnippets.js rename to src/shaderSnippets.js diff --git a/src/common/utils.js b/src/utils.js similarity index 97% rename from src/common/utils.js rename to src/utils.js index 61827a8..ffcb71b 100644 --- a/src/common/utils.js +++ b/src/utils.js @@ -46,6 +46,10 @@ function isGTK4() { return Gtk.get_major_version() == 4; } +function isInShellProcess() { + return window.global && global.stage; +} + function shellVersionIs(major, minor) { return GS_MAJOR == major && GS_MINOR == minor; }