From e545ba11a7779695df676e673a1870f13526c549 Mon Sep 17 00:00:00 2001 From: Simon Schneegans Date: Thu, 13 Jan 2022 15:39:28 +0100 Subject: [PATCH 1/5] :memo: Add tutorial --- docs/how-to-create-new-effects.md | 447 ++++++++++++++++++++++++++++++ 1 file changed, 447 insertions(+) create mode 100644 docs/how-to-create-new-effects.md diff --git a/docs/how-to-create-new-effects.md b/docs/how-to-create-new-effects.md new file mode 100644 index 0000000..ec16f02 --- /dev/null +++ b/docs/how-to-create-new-effects.md @@ -0,0 +1,447 @@ +# 🔥 Creating a new Effect for Burn-My-Windows + +The extension is very modular and with a bit of creativity and GLSL knowledge, you can easily create your own effects. +If you are happy with your results, please open a pull request so that we can include your effect in the next version of Burn-My-Windows! + +### Before you Start + +First you should [fork the repository](https://github.com/Schneegans/Burn-My-Windows/fork) and clone it to your PC. +Afterwards, use a terminal in the directory of the cloned repository to install the extension. + +```bash +make install +``` + +_:information_source: Whenever you changed something in the source code, you will have to call this command and restart GNOME Shell with Alt + F2, r + Enter. +Or logout / login if you are on Wayland to see the changes._ + +### Debugging + +Debugging GNOME Shell extensions is a bit difficult. +Most of the time, you will print messages to a log in order to understand what is going on. +To make this a bit more convenient, Burn-My-Windows includes the method `utils.debug("Hello World")`. +With this, each line will be prefixed with the extension's name, which will make spotting log messages more easy. You can use the following command to watch the log output; it will highlight all messages from Burn-My-Windows: + +```bash +journalctl -f -o cat | grep -E 'burn-my-windows|' +``` + +## Adding a new Effect + +For the sake of this tutorial, we will create a **"Simple Fade"** effect. +Of course, you can replace any occurrence of this name and its nick `simple-fade` with your custom effect name. + +Three simple steps are required to create a new effect. +You will have to ... + +1. add a preferences key for enabling the effect, +2. create one additional effects class, and finally +3. register the new effect in two places. + +### 1. Expanding the Schema + +For enabling the new effect, the boolean settings key `simple-fade-close-effect` is required. +In this example, we also add an integer valued settings key for storing the animation time of the new effect and a floating point value for storing another property of the effect - we will use them later in the tutorial. +Just copy the XML code below to the file [`schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml`](schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml). +Just remember to replace `simple-fade` with your custom name! + +```xml + + + + + + false + Simple Fade Close Effect + Use the Simple Fade effect for window closing. + + + + 1500 + Simple Fade Animation Time + The time the Simple Fade effect takes. + + + + 0.1 + Simple Fade Width + Width of the fading effect. + +``` + +### 2. Creating the Effect Class + +You will have to create a new file called `src/SimpleFadeEffect.js` and paste the following code to it. +Please study this code carefully, all of it is explained with inline comments. + +
+ Expand this to show the code. + +```javascript +////////////////////////////////////////////////////////////////////////////////////////// +// ) ( // +// ( /( ( ( ) ( ( ( ( )\ ) ( ( // +// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // +// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // +// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // +// | '_ \ || | '_| ' \)) | ' \()| || | \ 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 ... // +// <- Please add a description of your effect here -> // +////////////////////////////////////////////////////////////////////////////////////////// + +// The shader class for this effect is registered further down in this file. +let Shader = null; + +// The effect class is completely static. It can be used to get some metadata (like the +// effect's name or supported GNOME Shell versions), to initialize the respective page of +// the settings dialog, as well as to create the actual shader for the effect. +var SimpleFadeEffect = class SimpleFadeEffect { + + // ---------------------------------------------------------------------------- metadata + + // The effect is available on all GNOME Shell versions supported by this extension. + static getMinShellVersion() { + return [3, 36]; + } + + // This will be called in various places where a unique identifier for this effect is + // required. It should match the prefix of the settings keys which store whether the + // effect is enabled currently (e.g. the '*-close-effect'). + static getNick() { + return 'simple-fade'; + } + + // This will be shown in the sidebar of the preferences dialog as well as in the + // drop-down menus where the user can choose the effect. + static getLabel() { + return 'Simple Fade Effect'; + } + + // -------------------------------------------------------------------- API for prefs.js + + // This is called by the preferences dialog. It loads the settings page for this effect, + // binds all properties to the settings and appends the page to the main stack of the + // preferences dialog. + static initPreferences(dialog) { + // Empty for now... Code is added here later in the tutorial! + } + + // ---------------------------------------------------------------- API for extension.js + + // This is called from extension.js whenever a window is closed with this effect. + static createShader(settings) { + return new Shader(settings); + } + + // This is also called from extension.js. It is used to tweak the ongoing transitions of + // the actor - usually windows are faded to transparency and scaled down slightly by + // GNOME Shell. Here, we modify this behavior as well as the transition duration. + static tweakTransitions(actor, settings) { + const animationTime = settings.get_int('simple-fade-animation-time'); + + const tweakTransition = (property, value) => { + const transition = actor.get_transition(property); + if (transition) { + transition.set_to(value); + transition.set_duration(animationTime); + } + }; + + // We re-target these transitions so that the window is neither scaled nor faded. + tweakTransition('opacity', 255); + tweakTransition('scale-x', 1); + tweakTransition('scale-y', 1); + } +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// The shader class for this effect will only be registered in GNOME Shell's process // +// (not in the preferences process). It's done this way as Clutter may not be installed // +// on the system and therefore the preferences would crash. // +////////////////////////////////////////////////////////////////////////////////////////// + +if (utils.isInShellProcess()) { + + const Clutter = imports.gi.Clutter; + const shaderSnippets = Me.imports.src.shaderSnippets; + + Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect { + _init(settings) { + super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); + + this.set_shader_source(` + + // The code below injects some standard uniforms which will be updated during the + // animation. This includes: + // uTexture: Contains the texture of the window. + // uProgress: A value which transitions from 0 to 1 during the entire animation. + // uTime: A steadily increasing value in seconds. + // uSizeX: The horizontal size of uTexture in pixels. + // uSizeY: The vertical size of uTexture in pixels. + ${shaderSnippets.standardUniforms()} + + // The width of the fading effect is directly loaded from the settings. + const float FADE_WIDTH = ${settings.get_double('simple-fade-width')}; + + void main() { + + // Get the color from the window texture. + vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st); + + // Radial distance from window edge to the window's center. + float dist = length(cogl_tex_coord_in[0].st - 0.5) * 2.0 / sqrt(2.0); + + // This gradually dissolves from [1..0] from the outside to the center. + float mask = (1.0 - uProgress * (1.0 + FADE_WIDTH) - dist + FADE_WIDTH) / FADE_WIDTH; + + // Make the mask smoother. + mask = smoothstep(0, 1, mask); + + // Set the final output color. This uses premultiplied alpha. + cogl_color_out = windowColor * mask; + } + `); + }; + }); +} +``` + +
+ +### 3. Registering the new Effect + +You will have to register the new effect in two files. +Both, [`extension.js`](extension.js) and [`prefs.js`](prefs.js) define an array in the beginning where you have to add an import to your new effect. +Like this: + +```javascript +const ALL_EFFECTS = [ + ... + Me.imports.src.SimpleFadeEffect.SimpleFadeEffect, + ... +]; +``` + + + +### Testing your Effect + +Now you can call `make install` and restart GNOME Shell with Alt + F2, r + Enter. +Or logout / login if you are on Wayland. +You can open the extension's preferences and choose the new effect! +However, there are no configuration options yet. +It is also not possible to adjust the animation time setting. + +```bash +gnome-extensions prefs burn-my-windows@schneegans.github.com +``` + +## Adding a Preferences Page + +For this, we will create a `simpleFadePage.ui` file and load this in the `initPreferences()` method of your new effect class. +We will be able to adjust two properties: The animation duration and the width of the fading gradient. + +Just save the code below to a file called `resources/ui/common/simpleFadePage.ui` and replace any occurrence of `simple-fade` with your effect's nick name! + +
+ Expand this to show the code. + +```xml + + + + + 5000 + 100 + 10 + 100 + + + + 1 + 0 + 0.01 + 0.1 + + + + vertical + 60 + 60 + 60 + 60 + + + + + + none + 1 + + + + + 0 + + + + + Animation Time [ms] + 0 + start + center + 1 + + + + + end + center + 1 + 0 + left + 300 + simple-fade-animation-time + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + + + + 0 + + + + + Fade Width + 0 + start + center + 1 + + + + + end + center + 1 + 2 + left + 300 + simple-fade-width + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + + + + + + + + + +``` + +
+ +### Loading the Preferences Page + +In order to load the above `*.ui` file, add the following code to your effect's `initPreferences()` method. + +```javascript +static initPreferences(dialog) { + + // Add the settings page to the builder. + dialog.getBuilder().add_from_resource(`/ui/common/simpleFadePage.ui`); + + // These connect the settings to the UI elements. Have a look at prefs.js + // on how to bind other types of UI elements. + dialog.bindAdjustment('simple-fade-animation-time'); + dialog.bindAdjustment('simple-fade-width'); + + // Finally, append the settings page to the main stack. + const stack = dialog.getBuilder().get_object('main-stack'); + stack.add_titled( + dialog.getBuilder().get_object(SimpleFadeEffect.getNick() + '-prefs'), + SimpleFadeEffect.getNick(), SimpleFadeEffect.getLabel()); + } +``` + +Once this is in place, you can kill the extension-preferences process and re-open the settings. +It is not required to reload GNOME Shell for developing the preferences dialog! +Here's a handy one-liner to do this: + +```bash +make install && pkill -f '.Extensions' && sleep 2 ; gnome-extensions prefs burn-my-windows@schneegans.github.com +``` + +### Supporting GTK3 and GTK4 + +The above UI file has been designed to support both, GTK3 and GTK4. +Usually, that is not possible as properties have been changed between the versions. +Most of the time, if your effect should support GNOME Shell 3.3x _and_ GNOME Shell 40+, you will have to provide two `*.ui` files. + +You can then load the respective files in your `initPreferences()` with such a line: + +```javascript +dialog.getBuilder().add_from_resource(`/ui/${utils.getGTKString()}/simpleFadePage.ui`); +``` + +## Summing Up + +That's it! +If you have any questions, feel free to [ask them on the discussions board](https://github.com/Schneegans/Burn-My-Windows/discussions). +If you are happy with your effect, submit a pull request, and it may get included in the next version! \ No newline at end of file From 3cf99ec2bbb61ec81eefab4145e14994a9713084 Mon Sep 17 00:00:00 2001 From: Simon Schneegans Date: Thu, 13 Jan 2022 15:39:41 +0100 Subject: [PATCH 2/5] :memo: Link to tutorial --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d4dd313..53fb32a 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Effect | Preview **Matrix**
Turn your windows into a shower of green letters! The color is actually configurable.

_Only available in GNOME Shell 40+_ | **T-Rex Attack**
Destroy your windows with a series of violent slashes!

_Only available in GNOME Shell 40+_ | **TV-Effect**
This is a very simple effect to demonstrate that this extension could also be used in a more professional environment. | +**Your Effect!**
The extension is very modular and with a bit of creativity and GLSL knowledge, you can easily create your own effects. | [A tutorial for creating custom effects is available here.](docs/how-to-create-new-effects.md) ## 💞 These People _love_ this Extension From adacc616a03f87ab37494651a5acffcae89fd73a Mon Sep 17 00:00:00 2001 From: Simon Schneegans Date: Thu, 13 Jan 2022 16:04:42 +0100 Subject: [PATCH 3/5] :memo: Use separate GTK3 example code --- docs/how-to-create-new-effects.md | 186 +++++++++++++++++++++++++----- 1 file changed, 156 insertions(+), 30 deletions(-) diff --git a/docs/how-to-create-new-effects.md b/docs/how-to-create-new-effects.md index ec16f02..6769387 100644 --- a/docs/how-to-create-new-effects.md +++ b/docs/how-to-create-new-effects.md @@ -254,13 +254,161 @@ gnome-extensions prefs burn-my-windows@schneegans.github.com ## Adding a Preferences Page -For this, we will create a `simpleFadePage.ui` file and load this in the `initPreferences()` method of your new effect class. -We will be able to adjust two properties: The animation duration and the width of the fading gradient. +If your effect should support GNOME Shell 3.3x _and_ GNOME Shell 40+, you will have to provide two `*.ui` files. +This is because starting with GNOME Shell 40, the preference dialog uses GTK4, before it used to use GTK3. +We will load the relevant file in the `initPreferences()` method of your new effect class. +There are two sliders in this example: The animation duration and the width of the fading gradient. -Just save the code below to a file called `resources/ui/common/simpleFadePage.ui` and replace any occurrence of `simple-fade` with your effect's nick name! +Just save the code below to `resources/ui/gtk3/simpleFadePage.ui` and `resources/ui/gtk4/simpleFadePage.ui` respectively. +Remember to replace any occurrence of `simple-fade` with your effect's nick-name!
- Expand this to show the code. + Expand this to show the GTK3 code. + +```xml + + + + + 5000 + 100 + 10 + 100 + + + + 1 + 0 + 0.01 + 0.1 + + + + vertical + 60 + 60 + 60 + 60 + + + + + + none + + + + + 10 + 10 + 10 + 10 + 0 + + + + + Animation Time [ms] + 0 + start + center + 1 + + + + + end + center + 1 + 0 + left + 300 + simple-fade-animation-time + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + + + + 10 + 10 + 10 + 10 + 0 + + + + + Fade Width + 0 + start + center + 1 + + + + + end + center + 1 + 2 + left + 300 + simple-fade-width + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + + + + + + + + + +``` + +
+ +
+ Expand this to show the GTK4 code. ```xml @@ -324,12 +472,7 @@ Just save the code below to a file called `resources/ui/common/simpleFadePage.ui - - - edit-clear-symbolic - 1 - - + edit-clear-symbolic Reset to Default Value