📝 Add comments

This commit is contained in:
Simon Schneegans
2022-01-21 20:46:36 +01:00
parent 3985697573
commit c7001de666
2 changed files with 67 additions and 31 deletions
+8 -2
View File
@@ -85,20 +85,26 @@ class Extension {
// the WorkspacesView.
const extensionThis = this;
// Do not attempt to close windows twice. Due to the animation in the overview, the
// close button can be clicked twice which normally would lead to a crash.
// This class is only available in GNOME Shell 3.38+.
if (WindowPreview) {
this._origDeleteAll = WindowPreview.prototype._deleteAll;
// The _deleteAll is called when the user clicks the X in the overview.
WindowPreview.prototype._deleteAll = function() {
// Do not attempt to close windows twice. Due to the animation in the overview,
// the close button can be clicked twice which normally would lead to a crash.
if (!this._closeRequested) {
// 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.
this.metaWindow.connect('unmanaged', () => {
const transitionConfig = extensionThis._effect.getCloseTransition(
this.window_container, extensionThis._settings);
extensionThis._tweakTransitions(this.window_container, transitionConfig);
});
// Call the original method.
extensionThis._origDeleteAll.apply(this);
// This is required, else WindowPreview's _restack() which is called by the
+59 -29
View File
@@ -20,9 +20,10 @@ const Me = imports.misc.extensionUtils.getCurrentExtension();
const utils = Me.imports.src.utils;
//////////////////////////////////////////////////////////////////////////////////////////
// T... //
// 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. //
// This effect shatters the window into pieces. For an explanation how this works, look //
// further down in this file into the documentation of the Shader class. 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. //
//////////////////////////////////////////////////////////////////////////////////////////
// The shader class for this effect is registered further down in this file.
@@ -88,7 +89,7 @@ var BrokenGlass = class BrokenGlass {
// This is also called from extension.js. It is used to tweak the ongoing transition of
// the actor - usually windows are faded to transparency and scaled down slightly by
// GNOME Shell. For this effect, windows are set to twice their original size, so that
// we have some space to draw the dust. 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) {
return {
'opacity': {to: 255, mode: 1},
@@ -110,21 +111,32 @@ if (utils.isInShellProcess()) {
const {Clutter, GdkPixbuf, Cogl} = imports.gi;
const shaderSnippets = Me.imports.src.shaderSnippets;
// This shader creates a complex-looking effect with rather simple means. Here is how it
// works: The window is drawn five times on top of each other (see the SHARD_LAYERS
// constant in the GLSL code). Each layer only draws some of the shards, all layers
// combined make up the entire window. The layers are then scaled, rotated, and moved
// independently from each other - this creates the impression that all shards are
// moving independently. In reality, there are only five groups of shards! Which shard
// belongs to which layer is defined by the green channel of the texture
// 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.
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
_init(actor, settings) {
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
// Load the claw 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,
// this texture is also re-created each time. This could be improved in the future!
const dustData = GdkPixbuf.Pixbuf.new_from_resource('/img/shards.png');
this._dustTexture = new Clutter.Image();
this._dustTexture.set_data(
dustData.get_pixels(), Cogl.PixelFormat.RGB_888, dustData.width,
dustData.height, dustData.rowstride);
const shardData = GdkPixbuf.Pixbuf.new_from_resource('/img/shards.png');
this._shardTexture = new Clutter.Image();
this._shardTexture.set_data(
shardData.get_pixels(), Cogl.PixelFormat.RGB_888, shardData.width,
shardData.height, shardData.rowstride);
// Usually, the shards fly away from the center of the window.
let epicenterX = 0.5;
let epicenterY = 0.5;
// However, if this option is set, we use the mouse pointer position.
if (settings.get_boolean('broken-glass-use-pointer')) {
const [x, y] = global.get_pointer();
const [ok, localX, localY] = actor.transform_stage_point(x, y);
@@ -137,48 +149,61 @@ if (utils.isInShellProcess()) {
// Inject some common shader snippets.
${shaderSnippets.standardUniforms()}
uniform sampler2D uDustTexture;
uniform sampler2D uShardTexture;
const vec2 SEED = vec2(${Math.random()}, ${Math.random()});
const float SHARD_SCALE = ${settings.get_double('broken-glass-scale')};
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 CANVAS_SCALE = 2.0;
const float ACTOR_SCALE = 2.0;
const float PADDING = ACTOR_SCALE / 2.0 - 0.5;
const vec2 EPICENTER = vec2(${epicenterX}, ${epicenterY});
void main() {
cogl_color_out = vec4(0, 0, 0, 0);
// Draw the individual shard layers.
for (float i=0; i<SHARD_LAYERS; ++i) {
vec2 epicenter = vec2(${epicenterX}, ${epicenterY});
float padding = CANVAS_SCALE / 2.0 - 0.5;
// To enable drawing shards outside of the window bounds, the actor was scaled
// by ACTOR_SCALE. Here we scale and move the texture coordinates so that the
// window gets drawn at the correct position again.
vec2 coords = cogl_tex_coord_in[0].st * ACTOR_SCALE - PADDING;
vec2 coords = cogl_tex_coord_in[0].st * CANVAS_SCALE;
coords -= padding;
coords -= epicenter;
// Scale and rotate around our epicenter.
coords -= EPICENTER;
// Scale each layer a bit differently.
coords /= mix(1.0, 1.0 + BLOW_FORCE*(i+2)/SHARD_LAYERS, uProgress);
// Rotate each layer a bit differently.
float rotation = (mod(i, 2.0)-0.5)*0.2*uProgress;
coords = vec2(coords.x * cos(rotation) - coords.y * sin(rotation),
coords.x * sin(rotation) + coords.y * cos(rotation));
// Move down each layer a bit.
float gravity = GRAVITY*0.1*(i+1)*uProgress*uProgress;
coords += vec2(0, gravity);
coords += epicenter;
vec2 dustCoords = (coords + SEED) * vec2(uSizeX, uSizeY) / SHARD_SCALE / 512.0;
vec2 dustMap = texture2D(uDustTexture, dustCoords).rg;
// Restore correct position.
coords += EPICENTER;
// Retrieve information from the shard texture for our layer.
vec2 shardCoords = (coords + SEED) * vec2(uSizeX, uSizeY) / SHARD_SCALE / 500.0;
vec2 shardMap = texture2D(uShardTexture, shardCoords).rg;
float dustGroup = floor(dustMap.g * SHARD_LAYERS * 0.999);
// The green channel contains a random value in [0..1] for each shard. We
// discretize this into SHARD_LAYERS bins and check if our layer falls into
// the bin of the current shard.
float shardGroup = floor(shardMap.g * SHARD_LAYERS * 0.999);
if (dustGroup == i) {
if (shardGroup == i) {
vec4 windowColor = texture2D(uTexture, coords);
float dissolve = (dustMap.x - pow(uProgress+0.1, 2)) > 0 ? 1: 0;
// Dissolve the shard by using distance information from the red channel.
float dissolve = (shardMap.x - pow(uProgress+0.1, 2)) > 0 ? 1: 0;
cogl_color_out = mix(cogl_color_out, windowColor, dissolve);
}
}
@@ -186,17 +211,22 @@ if (utils.isInShellProcess()) {
`);
};
// This is overridden to bind the dust texture for drawing. Sadly, this seems to be
// This is overridden to bind the shard 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();
// Use linear filtering for the window texture.
pipeline.set_layer_filters(
0, Cogl.PipelineFilter.LINEAR, Cogl.PipelineFilter.LINEAR);
pipeline.set_layer_texture(1, this._dustTexture.get_texture());
// Bind the shard texture.
pipeline.set_layer_texture(1, this._shardTexture.get_texture());
pipeline.set_layer_wrap_mode(1, Cogl.PipelineWrapMode.REPEAT);
this.set_uniform_value('uDustTexture', 1);
this.set_uniform_value('uShardTexture', 1);
super.vfunc_paint_target(node, paint_context);
}
});