diff --git a/kwin/incinerate/onAnimationBegin.js b/kwin/incinerate/onAnimationBegin.js index 12be257..18f72bc 100644 --- a/kwin/incinerate/onAnimationBegin.js +++ b/kwin/incinerate/onAnimationBegin.js @@ -1,4 +1,9 @@ // This part is automatically included in the effect's source during the build process. // The code below is called whenever a window is closed or opened. -effect.setUniform(this.shader, 'uSeed', [Math.random(), Math.random()]); +let seed = [Math.random(), Math.random()]; +let startPos = seed[0] > seed[1] ? [seed[0], Math.floor(seed[1] + 0.5)] : + [Math.floor(seed[0] + 0.5), seed[1]]; + +effect.setUniform(this.shader, 'uSeed', seed); +effect.setUniform(this.shader, 'uStartPos', startPos); \ No newline at end of file diff --git a/resources/shaders/incinerate.frag b/resources/shaders/incinerate.frag index c33da41..61558b9 100644 --- a/resources/shaders/incinerate.frag +++ b/resources/shaders/incinerate.frag @@ -17,6 +17,7 @@ uniform vec2 uSeed; uniform vec3 uColor; uniform float uScale; uniform float uTurbulence; +uniform vec2 uStartPos; // This maps a given value in [0..1] to a color from the rgba color ramp // [transparent black ... semi-transparent uColor ... opaque white]. @@ -75,11 +76,8 @@ void main() { // Now we compute a 2D gradient in [0..1] which covers the entire window. The dark // regions will be burned first, the bright regions in the end. We mix a radial gradient - // with some noise. The center of the radial gradient is positioned somewhere at the - // window boundary. - vec2 center = uSeed.x > uSeed.y ? vec2(uSeed.x, floor(uSeed.y + 0.5)) - : vec2(floor(uSeed.x + 0.5), uSeed.y); - float circle = length(iTexCoord - center); + // with some noise. The center of the radial gradient is positioned at uStartPos. + float circle = length(iTexCoord - uStartPos); vec2 uv = iTexCoord / uScale * uSize / 1.5; float smokeNoise = diff --git a/resources/ui/gtk3/Incinerate.ui b/resources/ui/gtk3/Incinerate.ui index 808eba4..816b0f9 100644 --- a/resources/ui/gtk3/Incinerate.ui +++ b/resources/ui/gtk3/Incinerate.ui @@ -181,6 +181,68 @@ + + + 10 + 10 + 10 + 10 + 0 + + + + + vertical + 3 + + + Start at Pointer + 0 + start + center + 1 + + + + + If disabled, a random location will be chosen. + 0 + start + center + 1 + + + + + + + + end + center + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + 10 diff --git a/resources/ui/gtk4/Incinerate.ui b/resources/ui/gtk4/Incinerate.ui index 958cd5e..71e5521 100644 --- a/resources/ui/gtk4/Incinerate.ui +++ b/resources/ui/gtk4/Incinerate.ui @@ -152,6 +152,59 @@ + + + 0 + + + + + vertical + 3 + + + Start at Pointer + 0 + start + center + 1 + + + + + If disabled, a random location will be chosen. + 0 + start + center + 1 + + + + + + + + end + center + + + + + edit-clear-symbolic + Reset to Default Value + + + + + + + + 0 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 50f69e0..ee26406 100644 --- a/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml +++ b/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml @@ -371,6 +371,12 @@ The color of the effect. + + true + Incinerate Use Pointer + Use the pointer location for the incinerate effect. + + diff --git a/src/Incinerate.js b/src/Incinerate.js index dd3e777..0277929 100644 --- a/src/Incinerate.js +++ b/src/Incinerate.js @@ -47,22 +47,65 @@ var Incinerate = class { shader._uColor = shader.get_uniform_location('uColor'); shader._uScale = shader.get_uniform_location('uScale'); shader._uTurbulence = shader.get_uniform_location('uTurbulence'); + shader._uStartPos = shader.get_uniform_location('uStartPos'); // Write all uniform values at the start of each animation. - shader.connect('begin-animation', (shader, settings) => { - const c = Clutter.Color.from_string(settings.get_string('incinerate-color'))[1]; - + shader.connect('begin-animation', (shader, settings, forOpening, actor) => { // If we are currently performing integration test, the animation uses a fixed // seed. const testMode = settings.get_boolean('test-mode'); + let seed = [testMode ? 0 : Math.random(), testMode ? 0 : Math.random()]; + + // If this option is set, we use the mouse pointer position. Because the actor + // position may change after the begin-animation signal is called, we set the + // uStartPos uniform during the update callback. + if (settings.get_boolean('incinerate-use-pointer')) { + this._startPointerPos = global.get_pointer(); + this._actor = actor; + + } else { + // Else, a random position along the window boundary is used as start position + // for the incinerate effect. + let startPos = seed[0] > seed[1] ? [seed[0], Math.floor(seed[1] + 0.5)] : + [Math.floor(seed[0] + 0.5), seed[1]]; + + shader.set_uniform_float(shader._uStartPos, 2, startPos); + + this._startPointerPos = null; + } + + const c = Clutter.Color.from_string(settings.get_string('incinerate-color'))[1]; // clang-format off - shader.set_uniform_float(shader._uSeed, 2, [testMode ? 0 : Math.random(), testMode ? 0 : Math.random()]); - shader.set_uniform_float(shader._uColor, 3, [c.red / 255, c.green / 255, c.blue / 255]); - shader.set_uniform_float(shader._uScale, 1, [settings.get_double('incinerate-scale')]); + shader.set_uniform_float(shader._uSeed, 2, seed); + shader.set_uniform_float(shader._uColor, 3, [c.red / 255, c.green / 255, c.blue / 255]); + shader.set_uniform_float(shader._uScale, 1, [settings.get_double('incinerate-scale')]); shader.set_uniform_float(shader._uTurbulence, 1, [settings.get_double('incinerate-turbulence')]); // clang-format on }); + + // If the mouse pointer position is used as start position, we set the uStartPos + // uniform during the update callback as the actor position may not be set up + // properly before the begin animation callback. + shader.connect('update-animation', (shader) => { + if (this._startPointerPos) { + const [x, y] = this._startPointerPos; + const [ok, localX, localY] = this._actor.transform_stage_point(x, y); + + if (ok) { + let startPos = [ + Math.max(0.0, Math.min(1.0, localX / this._actor.width)), + Math.max(0.0, Math.min(1.0, localY / this._actor.height)) + ]; + shader.set_uniform_float(shader._uStartPos, 2, startPos); + } + } + }); + + // Make sure to drop the reference to the actor. + shader.connect('end-animation', (shader) => { + shader._actor = null; + }); }); } @@ -100,6 +143,7 @@ var Incinerate = class { dialog.bindAdjustment('incinerate-animation-time'); dialog.bindAdjustment('incinerate-scale'); dialog.bindAdjustment('incinerate-turbulence'); + dialog.bindSwitch('incinerate-use-pointer'); dialog.bindColorButton('incinerate-color'); // Finally, return the new settings page.