diff --git a/README.md b/README.md index b66f2e0..25ea8e7 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,8 @@ This extension is not only more useless than the cube, but it is also much more | **Doom**
Melt your windows. Inspired by the legendary screen transitions of the original Doom. | | | **Energize A**
Beam your windows away! | | | **Energize B**
Using different transporter technology results in an alternative visual effect. | | -| **Fire**
The classic effect inspired by Compiz. However, this is implemented using a GLSL shader and not with a particle system like in the old days. | | +| **Fire**
The classic effect inspired by Compiz. However, this is implemented using a GLSL shader and not with a particle system like in the old days. | | +| **Focus**
Focus Dude, Focus | | | **Glide**
This very simple effect fades the window to transparency with subtle 3D effects. | | | **Glitch**
This effect applies some intentional graphics issues to your windows. | | | **Hexagon**
With glowing lines and hexagon-shaped tiles, this effect looks very sci-fi. | | @@ -70,6 +71,8 @@ Below is a table which summarizes the current availability for all effects. Energize A ✅ ✅ ✅ ✅ Energize B ✅ ✅ ✅ ✅ Fire ✅ ✅ ✅ ✅ +Focus ✅ ✅ ✅ ✅ + Glide ✅ ✅ ✅ ✅ Glitch ✅ ✅ ✅ ✅ Hexagon ✅ ✅ ✅ ✅ @@ -190,6 +193,7 @@ Here are links to all effects which are currently available in the KDE store: | [Energize A](https://store.kde.org/p/1884310) | [Energize A](https://store.kde.org/p/2133829) | | [Energize B](https://store.kde.org/p/1884311) | [Energize B](https://store.kde.org/p/2133828) | | [Fire](https://store.kde.org/p/1884307) | [Fire](https://store.kde.org/p/2133822) | +| [Focus - coming soon,maybe] | [Focus - coming soon,maybe] | | [Glide](https://store.kde.org/p/1935778) | [Glide](https://store.kde.org/p/2133839) | | [Glitch](https://store.kde.org/p/1972813) | [Glitch](https://store.kde.org/p/2133844) | | [Hexagon](https://store.kde.org/p/1884309) | [Hexagon](https://store.kde.org/p/2133836) | diff --git a/docs/pics/focus.gif b/docs/pics/focus.gif new file mode 100644 index 0000000..d678618 Binary files /dev/null and b/docs/pics/focus.gif differ diff --git a/extension.js b/extension.js index 2cd97c2..cdc3ef6 100644 --- a/extension.js +++ b/extension.js @@ -28,6 +28,7 @@ import Doom from './src/effects/Doom.js'; import EnergizeA from './src/effects/EnergizeA.js'; import EnergizeB from './src/effects/EnergizeB.js'; import Fire from './src/effects/Fire.js'; +import Focus from './src/effects/Focus.js'; import Glide from './src/effects/Glide.js'; import Glitch from './src/effects/Glitch.js'; import Hexagon from './src/effects/Hexagon.js'; @@ -44,6 +45,7 @@ import TVEffect from './src/effects/TVEffect.js'; import TVGlitch from './src/effects/TVGlitch.js'; import Wisps from './src/effects/Wisps.js'; + import * as Main from 'resource:///org/gnome/shell/ui/main.js'; import {Workspace} from 'resource:///org/gnome/shell/ui/workspace.js'; import {WindowPreview} from 'resource:///org/gnome/shell/ui/windowPreview.js'; @@ -69,26 +71,13 @@ export default class BurnMyWindows extends Extension { // New effects must be registered here and in prefs.js. this._ALL_EFFECTS = [ - new Apparition(), - new BrokenGlass(), - new Doom(), - new EnergizeA(), - new EnergizeB(), - new Fire(), - new Glide(), - new Glitch(), - new Hexagon(), - new Incinerate(), - new Matrix(), - new PaintBrush(), - new Pixelate(), - new PixelWheel(), - new PixelWipe(), - new Portal(), - new SnapOfDisintegration(), - new TRexAttack(), - new TVEffect(), - new TVGlitch(), + new Apparition(), new BrokenGlass(), new Doom(), + new EnergizeA(), new EnergizeB(), new Fire(), + new Focus(), new Glide(), new Glitch(), + new Hexagon(), new Incinerate(), new Matrix(), + new PaintBrush(), new Pixelate(), new PixelWheel(), + new PixelWipe(), new Portal(), new SnapOfDisintegration(), + new TRexAttack(), new TVEffect(), new TVGlitch(), new Wisps(), ]; diff --git a/prefs.js b/prefs.js index 419ac84..3882c9b 100644 --- a/prefs.js +++ b/prefs.js @@ -29,6 +29,7 @@ import Doom from './src/effects/Doom.js'; import EnergizeA from './src/effects/EnergizeA.js'; import EnergizeB from './src/effects/EnergizeB.js'; import Fire from './src/effects/Fire.js'; +import Focus from './src/effects/Focus.js'; import Glide from './src/effects/Glide.js'; import Glitch from './src/effects/Glitch.js'; import Hexagon from './src/effects/Hexagon.js'; @@ -45,6 +46,7 @@ import TVEffect from './src/effects/TVEffect.js'; import TVGlitch from './src/effects/TVGlitch.js'; import Wisps from './src/effects/Wisps.js'; + import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; // Currently, the extension supports only one set of UI files. In the past, there were @@ -69,29 +71,13 @@ export default class BurnMyWindowsPreferences extends ExtensionPreferences { // New effects must be registered here and in extension.js. this._ALL_EFFECTS = [ - Apparition, - BrokenGlass, - Doom, - EnergizeA, - EnergizeB, - Fire, - Glide, - Glitch, - Hexagon, - Incinerate, - Matrix, - PaintBrush, - Pixelate, - PixelWheel, - PixelWipe, - Portal, - SnapOfDisintegration, - TRexAttack, - TVEffect, - TVGlitch, - Wisps, + Apparition, BrokenGlass, Doom, EnergizeA, EnergizeB, Fire, + Focus, Glide, Glitch, Hexagon, Incinerate, Matrix, + PaintBrush, Pixelate, PixelWheel, PixelWipe, Portal, SnapOfDisintegration, + TRexAttack, TVEffect, TVGlitch, Wisps, ]; + // Load all of our resources. this._resources = Gio.Resource.load(this.path + '/resources/burn-my-windows.gresource'); @@ -105,6 +91,7 @@ export default class BurnMyWindowsPreferences extends ExtensionPreferences { this._builder.add_from_resource(`/ui/common/menus.ui`); this._builder.add_from_resource(`/ui/${getUIDir()}/prefs.ui`); + // Store a reference to the general settings object. this._settings = this.getSettings(); @@ -134,6 +121,7 @@ export default class BurnMyWindowsPreferences extends ExtensionPreferences { // Maybe the service is masked... } + let powerProfileRow = this._builder.get_object('profile-power-profile'); powerProfileRow.set_visible(hasPowerProfiles); @@ -173,6 +161,7 @@ export default class BurnMyWindowsPreferences extends ExtensionPreferences { } }); + // This is our top-level widget which we will return later. this._widget = this._builder.get_object('general-prefs'); @@ -274,6 +263,7 @@ export default class BurnMyWindowsPreferences extends ExtensionPreferences { } }); + // 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) => { diff --git a/resources/shaders/focus.frag b/resources/shaders/focus.frag new file mode 100644 index 0000000..5082499 --- /dev/null +++ b/resources/shaders/focus.frag @@ -0,0 +1,86 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// ) ( // +// ( /( ( ( ) ( ( ( ( )\ ) ( ( // +// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // +// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // +// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // +// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< // +// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ // +// |__/ // +////////////////////////////////////////////////////////////////////////////////////////// + +// SPDX-FileCopyrightText: Justin Garza JGarza9788@gmail.com +// SPDX-License-Identifier: GPL-3.0-or-later + +// The content from common.glsl is automatically prepended to each shader effect. This +// provides the standard input: + +// vec2 iTexCoord: Texture coordinates for retrieving the window input color. +// bool uIsFullscreen: True if the window is maximized or in fullscreen mode. +// bool uForOpening: True if a window-open animation is ongoing, false otherwise. +// float uProgress: A value which transitions from 0 to 1 during the animation. +// float uDuration: The duration of the current animation in seconds. +// vec2 uSize: The size of uTexture in pixels. +// float uPadding: The empty area around the actual window (e.g. where the shadow +// is drawn). For now, this will only be set on GNOME. + +// Furthermore, there are two global methods for reading the window input color and +// setting the shader output color. Both methods assume straight alpha: + +// vec4 getInputColor(vec2 coords) +// void setOutputColor(vec4 outColor) + + +// Ease-in-out cubic for alpha +float easeInOutCubic(float x) { + return x < 0.5 ? 4.0 * x * x * x : 1.0 - pow(-2.0 * x + 2.0, 3.0) / 2.0; +} + +// Ease-in-out sine for blur +float easeInOutSine(float x) { + return -(cos(3.14159265 * x) - 1.0) / 2.0; +} + +// A simple blur function +vec4 blur(vec2 uv, float radius, float samples) { + vec4 color = vec4(0.0); + + const float tau = 6.28318530718; + const float directions = 15.0; + + for (float d = 0.0; d < tau; d += tau / directions) { + for (float s = 0.0; s < 1.0; s += 1.0 / samples) { + vec2 offset = vec2(cos(d), sin(d)) * radius * (1.0 - s) / uSize; + color += getInputColor(uv + offset); + } + } + + return color / samples / directions; +} + + +// The width of the fading effect is loaded from the settings. +uniform float uBlurAmount; +uniform float uBlurQuality; + +void main() { + + float progl = uForOpening ? uProgress : 1.0 - uProgress; + + float easedProgressBlur = easeInOutSine(progl); // Blur easing + float easedProgressAlpha = easeInOutCubic(progl); // Alpha easing + + // Control blur amount using easedProgressBlur + float blurAmount = mix(uBlurAmount, 0.0, easedProgressBlur); + + // Apply blur + vec4 texColor = blur( iTexCoord.st, blurAmount, uBlurQuality); + + // Control alpha using easedProgressAlpha + float alpha = easedProgressAlpha; + + // Set final color with alpha transition + texColor.a *= alpha; + + setOutputColor(texColor); +} \ No newline at end of file diff --git a/resources/ui/adw/focus.ui b/resources/ui/adw/focus.ui new file mode 100644 index 0000000..15965f4 --- /dev/null +++ b/resources/ui/adw/focus.ui @@ -0,0 +1,114 @@ + + + + + + + + 5000 + 100 + 10 + 100 + + + + 100 + 0 + 1 + 10 + + + + 20 + 1 + 1 + 5 + + + + + + + Animation Time [ms] + + + center + 1 + 0 + left + 300 + focus-animation-time + + + + + edit-clear-symbolic + center + Reset to Default Value + + + + + + + + + Blur Amount + + + center + 1 + 2 + left + 300 + focus-blur-amount + + + + + edit-clear-symbolic + center + Reset to Default Value + + + + + + + + + Blur Quality + + + center + 1 + 2 + left + 300 + focus-blur-quality + + + + + edit-clear-symbolic + center + Reset to Default Value + + + + + + + + + + diff --git a/schemas/org.gnome.shell.extensions.burn-my-windows-profile.gschema.xml b/schemas/org.gnome.shell.extensions.burn-my-windows-profile.gschema.xml index d9ae300..41b793d 100644 --- a/schemas/org.gnome.shell.extensions.burn-my-windows-profile.gschema.xml +++ b/schemas/org.gnome.shell.extensions.burn-my-windows-profile.gschema.xml @@ -821,6 +821,35 @@ SPDX-License-Identifier: CC0-1.0 The color of the dust. + + + + + + + false + Focus Enable Effect + Use the Focus effect. + + + + 500 + Focus Animation Time + The time the Focus effect takes. + + + + 50 + Focus Blur Amount + The Blur Amount before Focusing. + + + + 5 + Focus Blur Quality + The Quality of the Blur (Setting this too high may increase GPU load and affect performance) + + \ No newline at end of file diff --git a/src/effects/Focus.js b/src/effects/Focus.js new file mode 100644 index 0000000..7e18fd8 --- /dev/null +++ b/src/effects/Focus.js @@ -0,0 +1,99 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// ) ( // +// ( /( ( ( ) ( ( ( ( )\ ) ( ( // +// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // +// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // +// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // +// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< // +// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ // +// |__/ // +////////////////////////////////////////////////////////////////////////////////////////// + +// SPDX-FileCopyrightText: Justin Garza JGarza9788@gmail.com +// SPDX-License-Identifier: GPL-3.0-or-later + +'use strict'; + +import * as utils from '../utils.js'; + +// We import the ShaderFactory only in the Shell process as it is not required in the +// preferences process. The preferences process does not create any shader instances, it +// only uses the static metadata of the effect. +const ShaderFactory = await utils.importInShellOnly('./ShaderFactory.js'); + +const _ = await utils.importGettext(); + +////////////////////////////////////////////////////////////////////////////////////////// +// This effect uses a blur effect to allow the window to focus in and out of view. // +////////////////////////////////////////////////////////////////////////////////////////// + +// The effect class 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. +export default class Effect { + // The constructor creates a ShaderFactory which will be used by extension.js to create + // shader instances for this effect. The shaders will be automagically created using the + // GLSL file in resources/shaders/.glsl. The callback will be called for each + // newly created shader instance. + constructor() { + this.shaderFactory = new ShaderFactory(Effect.getNick(), (shader) => { + // Store uniform locations of newly created shaders. + shader._uBlurAmount = shader.get_uniform_location('uBlurAmount'); + shader._uBlurQuality = shader.get_uniform_location('uBlurQuality'); + + // Write all uniform values at the start of each animation. + shader.connect('begin-animation', (shader, settings) => { + shader.set_uniform_float(shader._uBlurAmount, 1, [ + settings.get_int('focus-blur-amount'), + ]); + + shader.set_uniform_float(shader._uBlurQuality, 1, [ + settings.get_int('focus-blur-quality'), + ]); + }); + }); + } + + // ---------------------------------------------------------------------------- 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. '*-enable-effect'), and its animation time + // (e.g. '*-animation-time'). Also, the shader file and the settings UI files should be + // named likes this. + static getNick() { + return 'focus'; + } + + // 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 _('Focus'); + } + + // -------------------------------------------------------------------- API for prefs.js + + // This is called by the preferences dialog whenever a new effect profile is loaded. It + // binds all user interface elements to the respective settings keys of the profile. + static bindPreferences(dialog) { + // These connect the settings to the UI elements. Have a look at prefs.js + // on how to bind other types of UI elements. + dialog.bindAdjustment('focus-animation-time'); + dialog.bindAdjustment('focus-blur-amount'); + dialog.bindAdjustment('focus-blur-quality'); + } + + // ---------------------------------------------------------------- API for extension.js + + // The getActorScale() is called from extension.js to adjust the actor's size during the + // animation. This is useful if the effect requires drawing something beyond the usual + // bounds of the actor. This only works for GNOME 3.38+. + static getActorScale(settings, forOpening, actor) { + return {x: 1.0, y: 1.0}; + } +}