summaryrefslogtreecommitdiff
path: root/raveos-gnome-theme/theme-data/extensions/installed/burn-my-windows@schneegans.github.com/src/Shader.js
diff options
context:
space:
mode:
authorNippy <nippy@rp1.hu>2026-06-01 18:57:29 +0200
committerNippy <nippy@rp1.hu>2026-06-01 18:57:29 +0200
commit2e5a7d93476c0819b5a23f5740e4c843eaedc73a (patch)
tree84279c63b84126eb8f6d9d94a42c44aabbe22336 /raveos-gnome-theme/theme-data/extensions/installed/burn-my-windows@schneegans.github.com/src/Shader.js
parente1f0fac166056bb106284be4a3fec0c558525927 (diff)
downloadRaveOS-PKGBUILD-2e5a7d93476c0819b5a23f5740e4c843eaedc73a.tar.gz
RaveOS-PKGBUILD-2e5a7d93476c0819b5a23f5740e4c843eaedc73a.zip
Raveos gnome update
Diffstat (limited to 'raveos-gnome-theme/theme-data/extensions/installed/burn-my-windows@schneegans.github.com/src/Shader.js')
-rw-r--r--raveos-gnome-theme/theme-data/extensions/installed/burn-my-windows@schneegans.github.com/src/Shader.js231
1 files changed, 231 insertions, 0 deletions
diff --git a/raveos-gnome-theme/theme-data/extensions/installed/burn-my-windows@schneegans.github.com/src/Shader.js b/raveos-gnome-theme/theme-data/extensions/installed/burn-my-windows@schneegans.github.com/src/Shader.js
new file mode 100644
index 0000000..b7a6377
--- /dev/null
+++ b/raveos-gnome-theme/theme-data/extensions/installed/burn-my-windows@schneegans.github.com/src/Shader.js
@@ -0,0 +1,231 @@
+//////////////////////////////////////////////////////////////////////////////////////////
+// ) ( //
+// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
+// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
+// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
+// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
+// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< //
+// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ //
+// |__/ //
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// SPDX-FileCopyrightText: Simon Schneegans <code@simonschneegans.de>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+'use strict';
+
+import Gio from 'gi://Gio';
+import Shell from 'gi://Shell';
+import Cogl from 'gi://Cogl';
+import GObject from 'gi://GObject';
+import Clutter from 'gi://Clutter';
+import Meta from 'gi://Meta';
+
+import * as utils from './utils.js';
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// This is the base class for all shaders of Burn-My-Windows. It automagically loads //
+// the shader's source code from the resource file resources/shaders/<nick>.glsl and //
+// ensures that some standard uniforms are always updated. //
+// Using Shell.GLSLEffect as a base class has some benefits and some drawbacks. The //
+// main benefit when compared to Clutter.ShaderEffect is that setting uniforms of types //
+// vec2, vec3 or vec4 is supported via the API (with Clutter.ShaderEffect the GJS //
+// binding does not work properly). However, there are two drawbacks: On the one hand, //
+// the shader source code is cached statically - this means if we want to have a //
+// different shader, we have to derive a new class. Therefore, each effect has to //
+// derive its own class from the class below. This is encapsulated in the //
+// ShaderFactory, however it is some really awkward code. The other drawback is the //
+// hard-coded use of straight alpha (as opposed to premultiplied). This makes the //
+// shaders a bit more complicated than required. //
+// //
+// The Shader fires three signals: //
+// * begin-animation: This is called each time a new animation is started. It can //
+// be used to set uniform values which do not change during the //
+// animation. //
+// * update-animation: This is called at each frame during the animation. It can be //
+// used to set uniforms which change during the animation. //
+// * end-animation: This is called when the animation is stopped. This can be //
+// used to clean up any resources.
+//////////////////////////////////////////////////////////////////////////////////////////
+
+export var Shader = GObject.registerClass({
+ Signals: {
+ 'begin-animation': {
+ param_types: [
+ Gio.Settings.$gtype, GObject.TYPE_BOOLEAN, GObject.TYPE_BOOLEAN,
+ Clutter.Actor.$gtype
+ ]
+ },
+ 'update-animation': {param_types: [GObject.TYPE_DOUBLE]},
+ 'end-animation': {}
+ }
+},
+
+ class Shader extends Shell.GLSLEffect {
+ // --------------------------------------------
+ // The constructor automagically loads the shader's source code (in
+ // vfunc_build_pipeline()) from the resource file resources/shaders/<nick>.glsl
+ // resolving any #includes in this file.
+ _init(nick) {
+ this._nick = nick;
+
+ // This will call vfunc_build_pipeline().
+ super._init();
+
+ // These will be updated during the animation.
+ this._progress = 0;
+ this._time = 0;
+
+ // Store standard uniform locations.
+ this._uForOpening = this.get_uniform_location('uForOpening');
+ this._uIsFullscreen = this.get_uniform_location('uIsFullscreen');
+ this._uProgress = this.get_uniform_location('uProgress');
+ this._uDuration = this.get_uniform_location('uDuration');
+ this._uSize = this.get_uniform_location('uSize');
+ this._uPadding = this.get_uniform_location('uPadding');
+
+ // Create a timeline to drive the animation.
+ this._timeline = new Clutter.Timeline();
+
+ // Call updateAnimation() once a frame.
+ this._timeline.connect('new-frame', (t) => {
+ if (this._testMode) {
+ this.updateAnimation(0.5);
+ } else {
+ this.updateAnimation(t.get_progress());
+ }
+ });
+
+ // Clean up if the animation finished or was interrupted.
+ this._timeline.connect('stopped', (t, finished) => {
+ this.endAnimation();
+ });
+ }
+
+ // This is called once each time the shader is used.
+ beginAnimation(settings, forOpening, testMode, duration, actor) {
+ if (this._timeline.is_playing()) {
+ this._timeline.stop();
+ }
+
+ // On GNOME 3.36 this method was not yet available.
+ if (this._timeline.set_actor) {
+ this._timeline.set_actor(actor);
+ }
+
+ this._timeline.set_duration(duration);
+ this._timeline.start();
+
+ // Make sure that no fullscreen window is drawn over our animations. Since GNOME 48
+ // this is a "global" method.
+ if (Meta.disable_unredirect_for_display) {
+ Meta.disable_unredirect_for_display(global.display);
+ } else {
+ global.compositor.disable_unredirect();
+ }
+
+ global.begin_work();
+
+ // Reset progress value.
+ this._progress = 0;
+ this._testMode = testMode;
+
+ // This is not necessarily symmetric, but I haven't figured out a way to
+ // get the actual values...
+ const padding = (actor.width - actor.meta_window.get_frame_rect().width) / 2;
+ let isFullscreen = actor.meta_window.fullscreen;
+
+ // is_maximized has been added in GNOME 49.
+ if (actor.meta_window.is_maximized) {
+ isFullscreen |= actor.meta_window.is_maximized();
+ } else {
+ isFullscreen |= actor.meta_window.get_maximized() === Meta.MaximizeFlags.BOTH;
+ }
+
+ this.set_uniform_float(this._uPadding, 1, [padding]);
+ this.set_uniform_float(this._uForOpening, 1, [forOpening]);
+ this.set_uniform_float(this._uIsFullscreen, 1, [isFullscreen]);
+ this.set_uniform_float(this._uDuration, 1, [duration * 0.001]);
+ this.set_uniform_float(this._uSize, 2, [actor.width, actor.height]);
+
+ this.emit('begin-animation', settings, forOpening, testMode, actor);
+ }
+
+ // This is called at each frame during the animation.
+ updateAnimation(progress) {
+ // Store the current progress value. The corresponding signal is emitted each frame
+ // in vfunc_paint_target. We do not emit it here, as the pipeline which may be used
+ // by handlers must not have been created yet.
+ this._progress = progress;
+
+ this.queue_repaint();
+ }
+
+ // This will stop any running animation and emit the end-animation signal.
+ endAnimation() {
+ // This will call endAnimation() again, so we can return for now.
+ if (this._timeline.is_playing()) {
+ this._timeline.stop();
+ return;
+ }
+
+ // Restore unredirecting behavior for fullscreen windows. Since GNOME 48 this is a
+ // "global" method.
+ if (Meta.disable_unredirect_for_display) {
+ Meta.enable_unredirect_for_display(global.display);
+ } else {
+ global.compositor.enable_unredirect();
+ }
+ global.end_work();
+
+ this.emit('end-animation');
+ }
+
+ // This is called by the constructor. This means, it's only called when the
+ // effect is used for the first time.
+ vfunc_build_pipeline() {
+ // Shell.GLSLEffect requires the declarations and the main source code as separate
+ // strings. As it's more convenient to store the in one GLSL file, we use a regex
+ // here to split the source code in two parts.
+ const code = this._loadShaderResource(`/shaders/${this._nick}.frag`);
+
+ // Match anything between the curly brackets of "void main() {...}".
+ const regex = RegExp('void main *\\(\\) *\\{([\\S\\s]+)\\}');
+ const match = regex.exec(code);
+
+ const declarations = code.substr(0, match.index);
+ const main = match[1];
+
+ this.add_glsl_snippet(
+ Cogl.SnippetHook ? Cogl.SnippetHook.FRAGMENT : Shell.SnippetHook.FRAGMENT,
+ declarations, main, true);
+ }
+
+ // We use this vfunc to trigger the update as it allows calling this.get_pipeline() in
+ // the handler. This could still be null if called from the updateAnimation() above.
+ vfunc_paint_target(...params) {
+ this.emit('update-animation', this._progress);
+
+ // Starting with GNOME 44.2, the alpha channel is not written to by default. We need
+ // to undo this. It is a pity that we have to do this here, as it is not really
+ // required to be done each frame. But it's the only place where we can do it.
+ // https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2650
+ this.get_pipeline().set_blend(
+ 'RGBA = ADD (SRC_COLOR * (SRC_COLOR[A]), DST_COLOR * (1-SRC_COLOR[A]))');
+
+ this.set_uniform_float(this._uProgress, 1, [this._progress]);
+ super.vfunc_paint_target(...params);
+ }
+
+ // --------------------------------------------------------------------- private stuff
+
+ // This loads a GLSL file from the extension's resources to a JavaScript string. The
+ // code from "common.glsl" is prepended automatically.
+ _loadShaderResource(path) {
+ let common = utils.getStringResource('/shaders/common.glsl');
+ let code = utils.getStringResource(path);
+
+ // Add a trailing newline. Else the GLSL compiler complains...
+ return common + '\n' + code + '\n';
+ }
+});