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/docs/changelog.md b/docs/changelog.md
index 274b15e..cc601cd 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -1,5 +1,21 @@
# Changelog of the Burn-My-Windows Extension
+## [Burn My Window 8](https://github.com/schneegans/Burn-My-Windows/releases/tag/v8)
+
+**Release Date:** TBD
+
+#### New Features
+
+* **Random effects!** You can now select a set of effects of which one will be chosen randomly whenever you close a window.
+* Each effect has its own "Animation Time" setting now. The global animation time has been replaced by those, so **you may have to adjust the sliders to match your previous settings**.
+
+#### Other Enhancements
+
+* The source code has received a **major refactoring**. This will make the addition of new effects much easier in the future.
+* The **layout of the settings dialog** has been reworked to make it easier to expand it in the future.
+* The lower limit of the **animation time of the TV Effect** has been reduced.
+
+
## [Burn My Window 7](https://github.com/schneegans/Burn-My-Windows/releases/tag/v7)
**Release Date:** 2022-01-03
diff --git a/extension.js b/extension.js
index c920725..172755c 100644
--- a/extension.js
+++ b/extension.js
@@ -15,20 +15,22 @@
const {Clutter, Gio, Meta} = imports.gi;
-const Config = imports.misc.config;
-const [GS_MAJOR, GS_MINOR] = Config.PACKAGE_VERSION.split('.');
-
const Workspace = imports.ui.workspace.Workspace;
const WindowManager = imports.ui.windowManager.WindowManager;
const WINDOW_REPOSITIONING_DELAY = imports.ui.workspace.WINDOW_REPOSITIONING_DELAY;
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;
+
+// New effects must be registered here and in prefs.js.
+const ALL_EFFECTS = [
+ 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 //
@@ -61,25 +63,6 @@ class Extension {
this._origAddWindowClone = Workspace.prototype._addWindowClone;
this._origShouldAnimateActor = WindowManager.prototype._shouldAnimateActor;
- // We may also override these animation times.
- this._origWindowTime = imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME;
- this._origDialogTime = imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME;
-
- // Update animation times if the respective settings are changed.
- const loadAnimationTimes = () => {
- imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME =
- this._settings.get_int('destroy-animation-time');
-
- imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME =
- this._settings.get_boolean('destroy-dialogs') ?
- this._settings.get_int('destroy-animation-time') :
- this._origDialogTime;
- };
-
- this._settings.connect('changed::destroy-animation-time', loadAnimationTimes);
- this._settings.connect('changed::destroy-dialogs', loadAnimationTimes);
- loadAnimationTimes();
-
// We will use extensionThis to refer to the extension inside the patched methods of
// the WorkspacesView.
const extensionThis = this;
@@ -89,7 +72,7 @@ class Extension {
// overview window layout. Therefore we call this method in addition.
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/gnome-3-36/js/ui/workspace.js#L1877
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/workspace.js#L1415
- if (GS_MAJOR == 3 && GS_MINOR == 36) {
+ if (utils.shellVersionIs(3, 36)) {
Workspace.prototype._addWindowClone = function(...params) {
const [clone, overlay] = extensionThis._origAddWindowClone.apply(this, params);
clone.connect('destroy', () => this._doRemoveWindow(clone.metaWindow));
@@ -154,38 +137,24 @@ class Extension {
return;
}
- // If there's a transition in progress, we re-target these transitions so that the
- // window is neither scaled nor faded.
- const tweakTransition = (property, value) => {
- const transition = actor.get_transition(property);
- if (transition) {
- transition.set_to(value);
- transition.set_progress_mode(Clutter.AnimationMode.EASE_OUT_QUAD);
- }
- };
+ // Create a list of all currently enabled effects.
+ const enabledEffects = ALL_EFFECTS.filter(Effect => {
+ return this._settings.get_boolean(`${Effect.getNick()}-close-effect`);
+ });
- tweakTransition('opacity', 255);
- tweakTransition('scale-x', 1);
- tweakTransition('scale-y', 1);
+ // Nothing is enabled...
+ if (enabledEffects.length == 0) {
+ return;
+ }
- let shader = null;
+ // Choose a random effect.
+ const Effect = enabledEffects[Math.floor(Math.random() * enabledEffects.length)];
+
+ // The effect usually will choose to override the present transitions on the actor.
+ Effect.tweakTransitions(actor, this._settings);
// 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 warp = 0.5 * this._settings.get_double('claw-scratch-warp');
- tweakTransition('scale-x', 1.0 + warp);
- tweakTransition('scale-y', 1.0 + warp);
- }
+ const shader = Effect.createShader(this._settings);
if (shader) {
actor.add_effect(shader);
@@ -216,9 +185,6 @@ class Extension {
Workspace.prototype._addWindowClone = this._origAddWindowClone;
WindowManager.prototype._shouldAnimateActor = this._origShouldAnimateActor;
- imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME = this._origWindowTime;
- imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME = this._origDialogTime;
-
this._settings = null;
}
@@ -233,8 +199,8 @@ class Extension {
}
// This was called "realWindow" in GNOME 3.36.
- const GS_336 = GS_MAJOR == 3 && GS_MINOR == 36;
- const actor = workspace._windows[index][GS_336 ? 'realWindow' : '_windowActor'];
+ const propertyName = utils.shellVersionIs(3, 36) ? 'realWindow' : '_windowActor';
+ const actor = workspace._windows[index][propertyName];
if (!actor.get_transition('scale-y')) {
return true;
}
diff --git a/prefs.js b/prefs.js
index 9dc4ae4..4d67e1f 100644
--- a/prefs.js
+++ b/prefs.js
@@ -17,14 +17,24 @@ 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;
+
+// New effects must be registered here and in extension.js.
+const ALL_EFFECTS = [
+ 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... //
+// The preferences dialog is organized in pages, each of which is loaded from a //
+// separate ui file. There's one page with general options, all other paged are loaded //
+// from the respective effects. //
//////////////////////////////////////////////////////////////////////////////////////////
var PreferencesDialog = class PreferencesDialog {
+
// ------------------------------------------------------------ constructor / destructor
constructor() {
@@ -32,81 +42,88 @@ var PreferencesDialog = class PreferencesDialog {
this._resources = Gio.Resource.load(Me.path + '/resources/burn-my-windows.gresource');
Gio.resources_register(this._resources);
- // Load the user interface file.
+ // Store a reference to the settings object.
+ this._settings = ExtensionUtils.getSettings();
+
+ // Load the general user interface files.
this._builder = new Gtk.Builder();
- this._builder.add_from_resource(`/ui/${utils.isGTK4() ? 'gtk4' : 'gtk3'}.ui`);
+ this._builder.add_from_resource(`/ui/common/main-menu.ui`);
+ this._builder.add_from_resource(`/ui/${utils.getGTKString()}/prefs.ui`);
+ this._builder.add_from_resource(`/ui/${utils.getGTKString()}/generalPage.ui`);
+
+ // Bind general options properties.
+ this.bindSwitch('destroy-dialogs');
+
+ // Add the General Options page to the main stack.
+ const stack = this._builder.get_object('main-stack');
+ stack.add_titled(
+ this._builder.get_object('general-prefs'), 'general', 'General Options');
+
+ // Add all other effect pages.
+ ALL_EFFECTS.forEach(Effect => {
+ const [minMajor, minMinor] = Effect.getMinShellVersion();
+ if (utils.shellVersionIsAtLeast(minMajor, minMinor)) {
+ Effect.initPreferences(this);
+ }
+ });
// This is our top-level widget which we will return later.
this._widget = this._builder.get_object('settings-widget');
- // Store a reference to the settings object.
- this._settings = ExtensionUtils.getSettings();
-
- // Bind all properties.
- this._bindCombobox('close-animation');
- this._bindAdjustment('destroy-animation-time');
- this._bindSwitch('destroy-dialogs');
- this._bindAdjustment('flame-movement-speed');
- this._bindAdjustment('flame-scale');
- this._bindSwitch('flame-3d-noise');
- this._bindColorButton('fire-color-1');
- this._bindColorButton('fire-color-2');
- this._bindColorButton('fire-color-3');
- this._bindColorButton('fire-color-4');
- this._bindColorButton('fire-color-5');
- this._bindAdjustment('matrix-scale');
- this._bindAdjustment('matrix-randomness');
- this._bindColorButton('matrix-trail-color');
- this._bindColorButton('matrix-tip-color');
- this._bindColorButton('tv-effect-color');
- this._bindColorButton('claw-scratch-color');
- this._bindAdjustment('claw-scratch-scale');
- this._bindAdjustment('claw-scratch-count');
- this._bindAdjustment('claw-scratch-warp');
-
- // The fire-gradient-reset button needs to be bound explicitly.
- this._builder.get_object('reset-fire-colors').connect('clicked', () => {
- this._settings.reset('fire-color-1');
- this._settings.reset('fire-color-2');
- this._settings.reset('fire-color-3');
- this._settings.reset('fire-color-4');
- this._settings.reset('fire-color-5');
- });
-
- // Initialize the fire-preset dropdown.
- this._createFirePresets();
-
- // Add a menu to the title bar of the preferences dialog.
+ // Some things can only be done once the widget is shown as we do not have access to
+ // the toplevel widget before.
this._widget.connect('realize', (widget) => {
const window = utils.isGTK4() ? widget.get_root() : widget.get_toplevel();
// Show the version number in the title bar.
window.set_title(`Burn-My-Windows ${Me.metadata.version}`);
- // Add the menu.
- const menu = this._builder.get_object('menu-button');
- window.get_titlebar().pack_end(menu);
+ // Add the main menu to the title bar.
+ {
+ // Add the menu button to the title bar.
+ const menu = this._builder.get_object('menu-button');
+ window.get_titlebar().pack_end(menu);
- // Populate the actions.
- const group = Gio.SimpleActionGroup.new();
+ // Populate the menu with actions.
+ const group = Gio.SimpleActionGroup.new();
+ window.insert_action_group('prefs', group);
- const addAction = (name, uri) => {
- const action = Gio.SimpleAction.new(name, null);
- action.connect('activate', () => Gtk.show_uri(null, uri, Gdk.CURRENT_TIME));
- group.add_action(action);
- };
+ const addAction = (name, uri) => {
+ const action = Gio.SimpleAction.new(name, null);
+ action.connect('activate', () => Gtk.show_uri(null, uri, Gdk.CURRENT_TIME));
+ group.add_action(action);
+ };
- addAction('homepage', 'https://github.com/Schneegans/Burn-My-Windows');
- addAction(
- 'changelog',
- 'https://github.com/Schneegans/Burn-My-Windows/blob/main/docs/changelog.md');
- addAction('bugs', 'https://github.com/Schneegans/Burn-My-Windows/issues');
- addAction(
- 'donate-paypal',
- 'https://www.paypal.com/donate/?hosted_button_id=3F7UFL8KLVPXE');
- addAction('donate-github', 'https://github.com/sponsors/Schneegans');
+ // clang-format off
+ addAction('homepage', 'https://github.com/Schneegans/Burn-My-Windows');
+ addAction('changelog', 'https://github.com/Schneegans/Burn-My-Windows/blob/main/docs/changelog.md');
+ addAction('bugs', 'https://github.com/Schneegans/Burn-My-Windows/issues');
+ addAction('donate-paypal', 'https://www.paypal.com/donate/?hosted_button_id=3F7UFL8KLVPXE');
+ addAction('donate-github', 'https://github.com/sponsors/Schneegans');
+ // clang-format on
+ }
- window.insert_action_group('prefs', group);
+ // Populate the close-effects drop-down menu.
+ {
+ const menu = this._builder.get_object('close-effect-menu');
+ const group = Gio.SimpleActionGroup.new();
+ window.insert_action_group('close-effects', group);
+
+ ALL_EFFECTS.forEach(Effect => {
+ const [minMajor, minMinor] = Effect.getMinShellVersion();
+ if (utils.shellVersionIsAtLeast(minMajor, minMinor)) {
+ const nick = Effect.getNick();
+ const label = Effect.getLabel();
+ const actionName = nick + '-close-effect';
+ const fullName = 'close-effects.' + actionName;
+
+ const action = this._settings.create_action(actionName);
+ group.add_action(action);
+
+ menu.append_item(Gio.MenuItem.new(label, fullName));
+ }
+ });
+ }
});
// As we do not have something like a destructor, we just listen for the destroy
@@ -124,35 +141,44 @@ var PreferencesDialog = class PreferencesDialog {
// -------------------------------------------------------------------- public interface
+ // Returns the internally used Gtk.Builder. Effects can use this to modify the UI of the
+ // preferences dialog.
+ getBuilder() {
+ return this._builder;
+ }
+
+ // Returns a Gio.Settings object for this extension.
+ getSettings() {
+ return this._settings;
+ }
+
// Returns the widget used for the settings of this extension.
getWidget() {
return this._widget;
}
- // ----------------------------------------------------------------------- private stuff
-
// Connects a Gtk.ComboBox (or anything else which has an 'active-id' property) to a
// settings key. It also binds the corresponding reset button.
- _bindCombobox(settingsKey) {
+ bindCombobox(settingsKey) {
this._bind(settingsKey, 'active-id');
}
// Connects a Gtk.Adjustment (or anything else which has a 'value' property) to a
// settings key. It also binds the corresponding reset button.
- _bindAdjustment(settingsKey) {
+ bindAdjustment(settingsKey) {
this._bind(settingsKey, 'value');
}
// Connects a Gtk.Switch (or anything else which has an 'active' property) to a settings
// key. It also binds the corresponding reset button.
- _bindSwitch(settingsKey) {
+ bindSwitch(settingsKey) {
this._bind(settingsKey, 'active');
}
// Colors are stored as strings like 'rgb(1, 0.5, 0)'. As Gio.Settings.bind_with_mapping
// is not available yet, we need to do the color conversion manually. It also binds the
// corresponding reset button.
- _bindColorButton(settingsKey) {
+ bindColorButton(settingsKey) {
const button = this._builder.get_object(settingsKey);
@@ -179,17 +205,7 @@ var PreferencesDialog = class PreferencesDialog {
this._bindResetButton(settingsKey);
}
- // Connects any widget's property to a settings key. The widget must have the same ID as
- // the settings key. It also binds the corresponding reset button.
- _bind(settingsKey, property) {
- const object = this._builder.get_object(settingsKey);
-
- if (object) {
- this._settings.bind(settingsKey, object, property, Gio.SettingsBindFlags.DEFAULT);
- }
-
- this._bindResetButton(settingsKey);
- }
+ // ----------------------------------------------------------------------- private stuff
// Searches for a reset button for the given settings key and make it reset the settings
// key when clicked.
@@ -202,91 +218,16 @@ var PreferencesDialog = class PreferencesDialog {
}
}
- // This populates the preset dropdown menu for the fire options.
- _createFirePresets() {
- this._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)'
- }
- ];
+ // Connects any widget's property to a settings key. The widget must have the same ID as
+ // the settings key. It also binds the corresponding reset button.
+ _bind(settingsKey, property) {
+ const object = this._builder.get_object(settingsKey);
- const menu = Gio.Menu.new();
- const group = Gio.SimpleActionGroup.new();
- const groupName = 'presets';
+ if (object) {
+ this._settings.bind(settingsKey, object, property, Gio.SettingsBindFlags.DEFAULT);
+ }
- // 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', () => {
- this._settings.set_double('flame-movement-speed', preset.speed);
- this._settings.set_double('flame-scale', preset.scale);
- this._settings.set_string('fire-color-1', preset.color1);
- this._settings.set_string('fire-color-2', preset.color2);
- this._settings.set_string('fire-color-3', preset.color3);
- this._settings.set_string('fire-color-4', preset.color4);
- this._settings.set_string('fire-color-5', preset.color5);
- });
-
- group.add_action(action);
- });
-
- this._builder.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);
- });
+ this._bindResetButton(settingsKey);
}
}
diff --git a/resources/ui/common/main-menu.ui b/resources/ui/common/main-menu.ui
new file mode 100644
index 0000000..4ba062b
--- /dev/null
+++ b/resources/ui/common/main-menu.ui
@@ -0,0 +1,32 @@
+
+
+
+
\ No newline at end of file
diff --git a/resources/ui/gtk3.ui b/resources/ui/gtk3.ui
deleted file mode 100644
index a99b1c7..0000000
--- a/resources/ui/gtk3.ui
+++ /dev/null
@@ -1,651 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
- 10000
- 500
- 10
- 100
-
-
-
- 3
- 0.1
- 0.01
- 0.1
-
-
-
- 2.0
- -2.0
- 0.01
- 0.1
-
-
-
- 50
- 5
- 1
- 5
-
-
-
- 1
- 0
- 0.01
- 0.1
-
-
-
- never
- 200
- 0
- 1
-
-
-
-
- vertical
- 60
- 60
- 30
- 30
-
-
-
- 30
- 10
- General Options
- 0
-
-
-
-
-
-
-
-
-
- none
-
-
-
- 10
- 10
- 10
- 10
- 0
-
-
- 8
-
-
- Close Window Animation
- 0
- start
- center
- 1
-
-
-
-
- center
- animation-mode-list
- 1
- fire
-
-
-
- 0
-
-
-
-
-
-
-
-
- edit-clear-symbolic
- 1
-
-
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 10
- 10
- 10
- 10
- 0
-
-
- 8
-
-
- Animation Time [ms]
- 0
- start
- center
- 1
-
-
-
-
- end
- center
- 1
- 0
- left
- 300
- destroy-animation-time
-
-
-
-
-
-
- edit-clear-symbolic
- 1
-
-
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 10
- 10
- 10
- 10
- 0
-
-
- 8
-
-
- Also Burn Dialogs
- 0
- start
- center
- 1
-
-
-
-
- end
- center
-
-
-
-
-
-
- edit-clear-symbolic
- 1
-
-
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 30
- 10
-
-
- Fire Animation Options
- 0
- 1
-
-
-
-
-
- none
-
-
- 8
-
-
- Choose a Preset
-
-
-
-
- pan-down-symbolic
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
- none
-
-
-
-
- 10
- 10
- 10
- 10
- 0
-
-
- 8
-
-
- Scale
- 0
- start
- center
- 1
-
-
-
-
- end
- center
- 1
- 2
- left
- 300
- flame-scale
-
-
-
-
-
-
- edit-clear-symbolic
- 1
-
-
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 10
- 10
- 10
- 10
- 0
-
-
- 8
-
-
- Speed
- 0
- start
- center
- 1
-
-
-
-
- end
- center
- 1
- 2
- left
- 300
- flame-movement-speed
-
-
-
-
-
-
- edit-clear-symbolic
- 1
-
-
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 10
- 10
- 10
- 10
- 0
- 0
-
-
- 8
-
-
- vertical
- 3
-
-
- 3D Noise
- 0
- start
- center
- 1
-
-
-
-
- Creates a more dynamic fire but requires more GPU power.
- 0
- start
- center
- 1
-
-
-
-
-
-
-
- end
- center
-
-
-
-
-
-
- edit-clear-symbolic
- 1
-
-
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 10
- 10
- 10
- 10
- 0
-
-
-
- 8
-
-
- Gradient
- 0
- start
- center
- 1
-
-
-
-
- 1
- 1
-
-
-
-
- 1
- 1
-
-
-
-
- 1
- 1
-
-
-
-
- 1
- 1
-
-
-
-
- 1
- 1
-
-
-
-
-
-
- edit-clear-symbolic
- 1
-
-
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 30
- 10
-
-
- TV Effect Options
- 0
- 1
-
-
-
-
-
-
-
-
-
-
- none
-
-
-
-
- 10
- 10
- 10
- 10
- 0
-
-
- 8
-
-
- Color
- 0
- start
- center
- 1
-
-
-
-
- 1
- 1
-
-
-
-
-
-
- edit-clear-symbolic
- 1
-
-
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/resources/ui/gtk3/firePage.ui b/resources/ui/gtk3/firePage.ui
new file mode 100644
index 0000000..688285c
--- /dev/null
+++ b/resources/ui/gtk3/firePage.ui
@@ -0,0 +1,379 @@
+
+
+
+
+ 10000
+ 500
+ 10
+ 100
+
+
+
+ 3
+ 0.1
+ 0.01
+ 0.1
+
+
+
+ 2.0
+ -2.0
+ 0.01
+ 0.1
+
+
+
+ vertical
+ 60
+ 60
+ 60
+ 60
+
+
+
+ 20
+
+
+ none
+
+
+
+
+ 10
+ 10
+ 10
+ 10
+ 0
+
+
+
+
+ Presets
+ 0
+ start
+ center
+ 1
+
+
+
+
+
+
+ 8
+
+
+ Choose a Preset
+
+
+
+
+ pan-down-symbolic
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ none
+
+
+
+
+ 10
+ 10
+ 10
+ 10
+ 0
+
+
+ 8
+
+
+ Animation Time [ms]
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 0
+ left
+ 300
+ fire-animation-time
+
+
+
+
+
+
+ edit-clear-symbolic
+ 1
+
+
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 10
+ 10
+ 10
+ 10
+ 0
+
+
+
+
+ Scale
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 2
+ left
+ 300
+ flame-scale
+
+
+
+
+
+
+ edit-clear-symbolic
+ 1
+
+
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 10
+ 10
+ 10
+ 10
+ 0
+
+
+
+
+ Speed
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 2
+ left
+ 300
+ flame-movement-speed
+
+
+
+
+
+
+ edit-clear-symbolic
+ 1
+
+
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 10
+ 10
+ 10
+ 10
+ 0
+
+
+
+
+ vertical
+ 3
+
+
+ 3D Noise
+ 0
+ start
+ center
+ 1
+
+
+
+
+ Creates a more dynamic fire but requires more GPU power.
+ 0
+ start
+ center
+ 1
+
+
+
+
+
+
+
+ end
+ center
+
+
+
+
+
+
+ edit-clear-symbolic
+ 1
+
+
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 10
+ 10
+ 10
+ 10
+ 0
+
+
+ 8
+
+
+ Gradient
+ 0
+ start
+ center
+ 1
+
+
+
+
+ 1
+ 1
+
+
+
+
+ 1
+ 1
+
+
+
+
+ 1
+ 1
+
+
+
+
+ 1
+ 1
+
+
+
+
+ 1
+ 1
+
+
+
+
+
+
+ edit-clear-symbolic
+ 1
+
+
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/ui/gtk3/generalPage.ui b/resources/ui/gtk3/generalPage.ui
new file mode 100644
index 0000000..9c952b8
--- /dev/null
+++ b/resources/ui/gtk3/generalPage.ui
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+ vertical
+ 60
+ 60
+ 30
+ 30
+
+
+
+
+
+ none
+
+
+
+ 10
+ 10
+ 10
+ 10
+ 0
+
+
+ 8
+
+
+ vertical
+ 3
+
+
+ Close Window Animation
+ 0
+ start
+ center
+ 1
+
+
+
+
+ If multiple are selected, one is chosen randomly.
+ 0
+ start
+ center
+ 1
+
+
+
+
+
+
+
+ Choose Effects
+ close-effect-menu
+
+
+
+
+
+
+
+
+
+ 10
+ 10
+ 10
+ 10
+ 0
+
+
+ 8
+
+
+ Also Burn Dialogs
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+
+
+
+
+
+
+ edit-clear-symbolic
+ 1
+
+
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/ui/gtk3/prefs.ui b/resources/ui/gtk3/prefs.ui
new file mode 100644
index 0000000..5b79db1
--- /dev/null
+++ b/resources/ui/gtk3/prefs.ui
@@ -0,0 +1,35 @@
+
+
+
+
+
+ main-menu
+ 1
+
+
+ open-menu-symbolic
+ 1
+ 1
+
+
+
+
+
+
+
+ main-stack
+
+
+
+
+ slide-up-down
+ 1
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/ui/gtk3/tvPage.ui b/resources/ui/gtk3/tvPage.ui
new file mode 100644
index 0000000..b992120
--- /dev/null
+++ b/resources/ui/gtk3/tvPage.ui
@@ -0,0 +1,127 @@
+
+
+
+
+ 5000
+ 100
+ 10
+ 100
+
+
+
+ vertical
+ 60
+ 60
+ 60
+ 60
+
+
+
+
+
+ none
+
+
+
+
+ 10
+ 10
+ 10
+ 10
+ 0
+
+
+ 8
+
+
+ Animation Time [ms]
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 0
+ left
+ 300
+ tv-animation-time
+
+
+
+
+
+
+ edit-clear-symbolic
+ 1
+
+
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 10
+ 10
+ 10
+ 10
+ 0
+
+
+
+
+ Color
+ 0
+ start
+ center
+ 1
+
+
+
+
+ 0
+ 1
+
+
+
+
+
+
+ edit-clear-symbolic
+ 1
+
+
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/ui/gtk4.ui b/resources/ui/gtk4.ui
deleted file mode 100644
index 20b4805..0000000
--- a/resources/ui/gtk4.ui
+++ /dev/null
@@ -1,948 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
Fire
-
fire
-
-
-
Matrix
-
matrix
-
-
-
TV Effect
-
tv
-
-
-
T-Rex Attack
-
trex
-
-
-
-
-
-
-
- main-menu
- open-menu-symbolic
-
-
-
- never
- 200
- 0
- 1
-
-
- 1
-
-
- vertical
- 60
- 60
- 30
- 30
-
-
-
- 30
- 10
- General Options
- 0
-
-
-
-
-
-
-
-
-
- none
- 1
-
-
-
-
-
- 0
-
-
-
-
- Close Window Animation
- 0
- start
- center
- 1
-
-
-
-
- center
- animation-mode-list
- 1
- fire
-
-
-
- 0
-
-
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
- Animation Time [ms]
- 0
- start
- center
- 1
-
-
-
-
- end
- center
- 1
- 0
- left
- 300
-
-
- 10000
- 500
- 10
- 100
-
-
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
- Also Burn Dialogs
- 0
- start
- center
- 1
-
-
-
-
- end
- center
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 30
- 10
-
-
- Fire Animation Options
- 0
- 1
-
-
-
-
-
- Choose a Preset
- 0
-
-
-
-
-
-
-
-
-
- none
- 1
-
-
-
-
- 0
-
-
-
-
- Scale
- 0
- start
- center
- 1
-
-
-
-
- end
- center
- 1
- 2
- left
- 300
-
-
- 3
- 0.1
- 0.01
- 0.1
-
-
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
- Speed
- 0
- start
- center
- 1
-
-
-
-
- end
- center
- 1
- 2
- left
- 300
-
-
- 2.0
- -2.0
- 0.01
- 0.1
-
-
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
- vertical
- 3
-
-
- 3D Noise
- 0
- start
- center
- 1
-
-
-
-
- Creates a more dynamic fire but requires more GPU power.
- 0
- start
- center
- 1
-
-
-
-
-
-
-
- end
- center
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
- Gradient
- 0
- start
- center
- 1
-
-
-
-
- 1
- 1
-
-
-
-
- 1
- 1
-
-
-
-
- 1
- 1
-
-
-
-
- 1
- 1
-
-
-
-
- 1
- 1
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 30
- 10
-
-
- Matrix Animation Options
- 0
- 1
-
-
-
-
-
-
-
-
-
-
- none
- 1
-
-
-
-
- 0
-
-
-
-
- Scale
- 0
- start
- center
- 1
-
-
-
-
- end
- center
- 1
- 0
- left
- 300
-
-
- 50
- 5
- 1
- 5
-
-
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
- Randomness
- 0
- start
- center
- 1
-
-
-
-
- end
- center
- 1
- 2
- left
- 300
-
-
- 1.0
- 0.0
- 0.01
- 0.1
-
-
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
- Trail Color
- 0
- start
- center
- 1
-
-
-
-
- 0
- 1
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
- Tip Color
- 0
- start
- center
- 1
-
-
-
-
- 0
- 1
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 30
- 10
-
-
- T-Rex Attack Options
- 0
- 1
-
-
-
-
-
-
-
-
-
-
- none
- 1
-
-
-
-
- 0
-
-
-
-
- Claw Scratch Scale
- 0
- start
- center
- 1
-
-
-
-
- end
- center
- 1
- 1
- left
- 300
-
-
- 10
- 0.1
- 0.1
- 1
-
-
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
- Claw Scratch Count
- 0
- start
- center
- 1
-
-
-
-
- end
- center
- 1
- 0
- left
- 300
-
-
- 50
- 1
- 1
- 10
-
-
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
- Warp Effect
- 0
- start
- center
- 1
-
-
-
-
- end
- center
- 1
- 2
- left
- 300
-
-
- 1
- 0
- 0.01
- 0.1
-
-
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
- Flash Color
- 0
- start
- center
- 1
-
-
-
-
- 1
- 1
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 30
- 10
-
-
- TV Effect Options
- 0
- 1
-
-
-
-
-
-
-
-
-
-
- none
- 1
-
-
-
-
- 0
-
-
-
-
- Color
- 0
- start
- center
- 1
-
-
-
-
- 0
- 1
-
-
-
-
- edit-clear-symbolic
- Reset to Default Value
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/resources/ui/gtk4/firePage.ui b/resources/ui/gtk4/firePage.ui
new file mode 100644
index 0000000..346b2ee
--- /dev/null
+++ b/resources/ui/gtk4/firePage.ui
@@ -0,0 +1,315 @@
+
+
+
+
+ vertical
+ 60
+ 60
+ 60
+ 60
+
+
+
+ 20
+
+
+ none
+ 1
+
+
+
+
+ 0
+
+
+
+
+ Presets
+ 0
+ start
+ center
+ 1
+
+
+
+
+ Choose a Preset
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ none
+ 1
+
+
+
+
+ 0
+
+
+
+
+ Animation Time [ms]
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 0
+ left
+ 300
+
+
+ 10000
+ 500
+ 10
+ 100
+
+
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ Scale
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 2
+ left
+ 300
+
+
+ 3
+ 0.1
+ 0.01
+ 0.1
+
+
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ Speed
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 2
+ left
+ 300
+
+
+ 2.0
+ -2.0
+ 0.01
+ 0.1
+
+
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ vertical
+ 3
+
+
+ 3D Noise
+ 0
+ start
+ center
+ 1
+
+
+
+
+ Creates a more dynamic fire but requires more GPU power.
+ 0
+ start
+ center
+ 1
+
+
+
+
+
+
+
+ end
+ center
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ Gradient
+ 0
+ start
+ center
+ 1
+
+
+
+
+ 1
+ 1
+
+
+
+
+ 1
+ 1
+
+
+
+
+ 1
+ 1
+
+
+
+
+ 1
+ 1
+
+
+
+
+ 1
+ 1
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/ui/gtk4/generalPage.ui b/resources/ui/gtk4/generalPage.ui
new file mode 100644
index 0000000..193c826
--- /dev/null
+++ b/resources/ui/gtk4/generalPage.ui
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+ vertical
+ 60
+ 60
+ 60
+ 60
+
+
+
+
+
+ none
+ 1
+
+
+
+
+
+ 0
+
+
+
+
+ vertical
+ 3
+
+
+ Close Window Animation
+ 0
+ start
+ center
+ 1
+
+
+
+
+ If multiple are selected, one is chosen randomly.
+ 0
+ start
+ center
+ 1
+
+
+
+
+
+
+
+ Choose Effects
+ close-effect-menu
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ Also Burn Dialogs
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/ui/gtk4/matrixPage.ui b/resources/ui/gtk4/matrixPage.ui
new file mode 100644
index 0000000..7f5a570
--- /dev/null
+++ b/resources/ui/gtk4/matrixPage.ui
@@ -0,0 +1,234 @@
+
+
+
+
+ vertical
+ 60
+ 60
+ 60
+ 60
+
+
+
+
+
+ none
+ 1
+
+
+
+
+ 0
+
+
+
+
+ Animation Time [ms]
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 0
+ left
+ 300
+
+
+ 10000
+ 500
+ 10
+ 100
+
+
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ Scale
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 0
+ left
+ 300
+
+
+ 50
+ 5
+ 1
+ 5
+
+
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ Randomness
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 2
+ left
+ 300
+
+
+ 1.0
+ 0.0
+ 0.01
+ 0.1
+
+
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ Trail Color
+ 0
+ start
+ center
+ 1
+
+
+
+
+ 0
+ 1
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ Tip Color
+ 0
+ start
+ center
+ 1
+
+
+
+
+ 0
+ 1
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/ui/gtk4/prefs.ui b/resources/ui/gtk4/prefs.ui
new file mode 100644
index 0000000..92a5f39
--- /dev/null
+++ b/resources/ui/gtk4/prefs.ui
@@ -0,0 +1,27 @@
+
+
+
+
+
+ main-menu
+ open-menu-symbolic
+
+
+
+
+
+ main-stack
+
+
+
+
+ slide-up-down
+ 1
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/ui/gtk4/trexPage.ui b/resources/ui/gtk4/trexPage.ui
new file mode 100644
index 0000000..2bfe567
--- /dev/null
+++ b/resources/ui/gtk4/trexPage.ui
@@ -0,0 +1,246 @@
+
+
+
+
+ vertical
+ 60
+ 60
+ 60
+ 60
+
+
+
+
+
+ none
+ 1
+
+
+
+
+ 0
+
+
+
+
+ Animation Time [ms]
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 0
+ left
+ 300
+
+
+ 10000
+ 500
+ 10
+ 100
+
+
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ Claw Scratch Scale
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 1
+ left
+ 300
+
+
+ 10
+ 0.1
+ 0.1
+ 1
+
+
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ Claw Scratch Count
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 0
+ left
+ 300
+
+
+ 50
+ 1
+ 1
+ 10
+
+
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ Warp Effect
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 2
+ left
+ 300
+
+
+ 1
+ 0
+ 0.01
+ 0.1
+
+
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ Flash Color
+ 0
+ start
+ center
+ 1
+
+
+
+
+ 1
+ 1
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/ui/gtk4/tvPage.ui b/resources/ui/gtk4/tvPage.ui
new file mode 100644
index 0000000..c64ecef
--- /dev/null
+++ b/resources/ui/gtk4/tvPage.ui
@@ -0,0 +1,109 @@
+
+
+
+
+ vertical
+ 60
+ 60
+ 60
+ 60
+
+
+
+
+
+ none
+ 1
+
+
+
+
+ 0
+
+
+
+
+ Animation Time [ms]
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 0
+ left
+ 300
+
+
+ 5000
+ 100
+ 10
+ 100
+
+
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ Color
+ 0
+ start
+ center
+ 1
+
+
+
+
+ 0
+ 1
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
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 d19bbf3..be346ba 100644
--- a/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml
+++ b/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml
@@ -1,27 +1,11 @@
-
-
-
-
-
-
-
-
- "fire"
- Close Animation
- The animation used for window closing.
-
-
-
-
- 1500
- Destroy Animation Time
- The time it takes to burn the windows.
-
+
+
+
false
@@ -29,22 +13,38 @@
Set to true to burn dialogs as well.
+
+
+
+
+
+ true
+ Fire Close Effect
+ Use the fire effect for window closing.
+
+
+
+ 1500
+ Fire Animation Time
+ The time the fire effect takes.
+
+
0.5
- Flame Movement Speed
- The speed at which the flames move.
+ Fire Movement Speed
+ The speed at which the fire moves.1.0
- Flame Scale
- The size of the flames.
+ Fire Scale
+ The size of the fire.false
- Flame 3D Noise
- Use a 3D noise for the flames.
+ Fire 3D Noise
+ Use a 3D noise for the fire.
@@ -77,6 +77,21 @@
The fifth color of the fire gradient.
+
+
+
+
+
+ false
+ Matrix Close Effect
+ Use the matrix effect for window closing.
+
+
+
+ 2000
+ Matrix Animation Time
+ The time the matrix effect takes.
+ 20
@@ -102,6 +117,21 @@
The color matrix trails.
+
+
+
+
+
+ false
+ TV Close Effect
+ Use the tv effect for window closing.
+
+
+
+ 400
+ TV Animation Time
+ The time the tv effect takes.
+ "rgb(255, 255, 255)"
@@ -109,6 +139,21 @@
The color of the TV effect.
+
+
+
+
+
+ false
+ T-Rex Close Effect
+ Use the trex effect for window closing.
+
+
+
+ 1500
+ T-Rex Animation Time
+ The time the trex effect takes.
+ "rgb(170, 0, 0)"
@@ -134,7 +179,6 @@
Number of claw scratches drawn on top of each other.
-
\ No newline at end of file
diff --git a/src/FireEffect.js b/src/FireEffect.js
new file mode 100644
index 0000000..e0c5458
--- /dev/null
+++ b/src/FireEffect.js
@@ -0,0 +1,355 @@
+//////////////////////////////////////////////////////////////////////////////////////////
+// ) ( //
+// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
+// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
+// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
+// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
+// | '_ \ || | '_| ' \)) | ' \()| || | \ 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. //
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// The shader class for this effect is registered further down in this file.
+let FireShader = 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 FireEffect = class FireEffect {
+
+ // ---------------------------------------------------------------------------- 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 'fire';
+ }
+
+ // 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 'Fire';
+ }
+
+ // -------------------------------------------------------------------- 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) {
+
+ // Add the settings page to the builder.
+ dialog.getBuilder().add_from_resource(`/ui/${utils.getGTKString()}/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);
+
+ // Finally, append the settings page to the main stack.
+ const stack = dialog.getBuilder().get_object('main-stack');
+ stack.add_titled(
+ dialog.getBuilder().get_object('fire-prefs'), FireEffect.getNick(),
+ FireEffect.getLabel());
+ }
+
+ // ---------------------------------------------------------------- API for extension.js
+
+ // This is called from extension.js whenever a window is closed with this effect.
+ static createShader(settings) {
+ return new FireShader(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('fire-animation-time');
+
+ const tweakTransition = (property, value) => {
+ const transition = actor.get_transition(property);
+ if (transition) {
+ transition.set_to(value);
+ transition.set_duration(animationTime);
+ }
+ };
+
+ // If there's a transition in progress, 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);
+ }
+
+ // ----------------------------------------------------------------------- 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);
+ });
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// 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;
+
+ 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/MatrixEffect.js b/src/MatrixEffect.js
new file mode 100644
index 0000000..bd23bd2
--- /dev/null
+++ b/src/MatrixEffect.js
@@ -0,0 +1,244 @@
+//////////////////////////////////////////////////////////////////////////////////////////
+// ) ( //
+// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
+// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
+// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
+// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
+// | '_ \ || | '_| ' \)) | ' \()| || | \ 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. //
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// The shader class for this effect is registered further down in this file.
+let MatrixShader = 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 MatrixEffect = class MatrixEffect {
+
+ // ---------------------------------------------------------------------------- metadata
+
+ // This effect is only available on GNOME Shell 40+.
+ static getMinShellVersion() {
+ return [40, 0];
+ }
+
+ // 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 'matrix';
+ }
+
+ // 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 'Matrix';
+ }
+
+ // -------------------------------------------------------------------- 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) {
+
+ // Add the settings page to the builder.
+ 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');
+
+ // Finally, append the settings page to the main stack.
+ const stack = dialog.getBuilder().get_object('main-stack');
+ stack.add_titled(
+ dialog.getBuilder().get_object('matrix-prefs'), MatrixEffect.getNick(),
+ MatrixEffect.getLabel());
+ }
+
+ // ---------------------------------------------------------------- API for extension.js
+
+ // This is called from extension.js whenever a window is closed with this effect.
+ static createShader(settings) {
+ return new MatrixShader(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('matrix-animation-time');
+
+ const tweakTransition = (property, value) => {
+ const transition = actor.get_transition(property);
+ if (transition) {
+ transition.set_to(value);
+ transition.set_duration(animationTime);
+ }
+ };
+
+ // If there's a transition in progress, 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, 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);
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/TRexEffect.js b/src/TRexEffect.js
new file mode 100644
index 0000000..9850601
--- /dev/null
+++ b/src/TRexEffect.js
@@ -0,0 +1,254 @@
+//////////////////////////////////////////////////////////////////////////////////////////
+// ) ( //
+// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
+// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
+// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
+// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
+// | '_ \ || | '_| ' \)) | ' \()| || | \ 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. //
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// The shader class for this effect is registered further down in this file.
+let TRexShader = 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 TRexEffect = class TRexEffect {
+
+ // ---------------------------------------------------------------------------- metadata
+
+ // This effect is only available on GNOME Shell 40+.
+ static getMinShellVersion() {
+ return [40, 0];
+ }
+
+ // 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 'trex';
+ }
+
+ // 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 'T-Rex Attack';
+ }
+
+ // -------------------------------------------------------------------- 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) {
+
+ // Add the settings page to the builder.
+ 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');
+
+ // Finally, append the settings page to the main stack.
+ const stack = dialog.getBuilder().get_object('main-stack');
+ stack.add_titled(
+ dialog.getBuilder().get_object('trex-prefs'), TRexEffect.getNick(),
+ TRexEffect.getLabel());
+ }
+
+ // ---------------------------------------------------------------- API for extension.js
+
+ // This is called from extension.js whenever a window is closed with this effect.
+ static createShader(settings) {
+ return new TRexShader(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('trex-animation-time');
+
+ const tweakTransition = (property, value) => {
+ const transition = actor.get_transition(property);
+ if (transition) {
+ transition.set_to(value);
+ transition.set_duration(animationTime);
+ }
+ };
+
+ // For this effect, we slightly increase the window's scale as part of the warp
+ // effect.
+ const warp = 0.5 * settings.get_double('claw-scratch-warp');
+ tweakTransition('opacity', 255);
+ tweakTransition('scale-x', 1.0 + warp);
+ tweakTransition('scale-y', 1.0 + warp);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// 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, 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);
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/TVEffect.js b/src/TVEffect.js
new file mode 100644
index 0000000..b38f523
--- /dev/null
+++ b/src/TVEffect.js
@@ -0,0 +1,179 @@
+//////////////////////////////////////////////////////////////////////////////////////////
+// ) ( //
+// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
+// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
+// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
+// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
+// | '_ \ || | '_| ' \)) | ' \()| || | \ 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 TVShader 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. //
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// The shader class for this effect is registered further down in this file.
+let TVShader = 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 TVEffect = class TVEffect {
+
+ // ---------------------------------------------------------------------------- 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 'tv';
+ }
+
+ // 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 'TV 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) {
+
+ // Add the settings page to the builder.
+ dialog.getBuilder().add_from_resource(`/ui/${utils.getGTKString()}/tvPage.ui`);
+
+ // Bind all properties.
+ dialog.bindAdjustment('tv-animation-time');
+ dialog.bindColorButton('tv-effect-color');
+
+ // Finally, append the settings page to the main stack.
+ const stack = dialog.getBuilder().get_object('main-stack');
+ stack.add_titled(
+ dialog.getBuilder().get_object('tv-prefs'), TVEffect.getNick(),
+ TVEffect.getLabel());
+ }
+
+ // ---------------------------------------------------------------- API for extension.js
+
+ // This is called from extension.js whenever a window is closed with this effect.
+ static createShader(settings) {
+ return new TVShader(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('tv-animation-time');
+
+ const tweakTransition = (property, value) => {
+ const transition = actor.get_transition(property);
+ if (transition) {
+ transition.set_to(value);
+ transition.set_duration(animationTime);
+ }
+ };
+
+ // For this effect, we scale the window only vertically.
+ tweakTransition('opacity', 255);
+ tweakTransition('scale-x', 1);
+ tweakTransition('scale-y', 0.5);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// 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;
+
+ TVShader = GObject.registerClass({Properties: {}, Signals: {}},
+ class TVShader 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/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/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 71%
rename from src/common/utils.js
rename to src/utils.js
index 1dead0a..e230444 100644
--- a/src/common/utils.js
+++ b/src/utils.js
@@ -15,6 +15,9 @@
const {Gtk} = imports.gi;
+const Config = imports.misc.config;
+const [GS_MAJOR, GS_MINOR] = Config.PACKAGE_VERSION.split('.');
+
const ExtensionUtils = imports.misc.extensionUtils;
const Me = imports.misc.extensionUtils.getCurrentExtension();
@@ -42,3 +45,34 @@ function debug(message) {
function isGTK4() {
return Gtk.get_major_version() == 4;
}
+
+// This method returns 'gtk3' or 'gtk4' depending on the currently used gtk version.
+function getGTKString() {
+ return isGTK4() ? 'gtk4' : 'gtk3';
+}
+
+// This method returns true if called in GNOME Shell's process, false if called in the
+// preferences process.
+function isInShellProcess() {
+ return window.global && global.stage;
+}
+
+// This method returns true if the current GNOME Shell version matches the given
+// arguments.
+function shellVersionIs(major, minor) {
+ return GS_MAJOR == major && GS_MINOR == minor;
+}
+
+// This method returns true if the current GNOME Shell version is at least as high as the
+// given arguments.
+function shellVersionIsAtLeast(major, minor) {
+ if (GS_MAJOR > major) {
+ return true;
+ }
+
+ if (GS_MAJOR == major) {
+ return GS_MINOR >= minor;
+ }
+
+ return false;
+}
\ No newline at end of file