summaryrefslogtreecommitdiff
path: root/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components
diff options
context:
space:
mode:
authorAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
committerAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
commit70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 (patch)
treeab1123d4067c1b086dd6faa7ee4ea643236b565a /raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components
parent5d94c0a7d44a2255b81815a52a7056a94a39842d (diff)
downloadRaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.tar.gz
RaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.zip
Replaced file structures for themes in the correct format
Diffstat (limited to 'raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components')
-rw-r--r--raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/appfolders.js265
-rw-r--r--raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/applications.js614
-rw-r--r--raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/coverflow_alt_tab.js91
-rw-r--r--raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/dash_to_dock.js421
-rw-r--r--raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/lockscreen.js89
-rw-r--r--raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/overview.js226
-rw-r--r--raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/panel.js577
-rw-r--r--raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/screenshot.js110
-rw-r--r--raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/window_list.js148
9 files changed, 2541 insertions, 0 deletions
diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/appfolders.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/appfolders.js
new file mode 100644
index 0000000..8824777
--- /dev/null
+++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/appfolders.js
@@ -0,0 +1,265 @@
+import Shell from 'gi://Shell';
+import Clutter from 'gi://Clutter';
+import Cogl from 'gi://Cogl';
+import * as Main from 'resource:///org/gnome/shell/ui/main.js';
+import { adjustAnimationTime } from 'resource:///org/gnome/shell/misc/animationUtils.js';
+
+import { PaintSignals } from '../conveniences/paint_signals.js';
+// TODO drop Tweener in favour of Clutter's `ease` (will need to extend the blur effect for it)
+const Tweener = imports.tweener.tweener;
+
+// TODO: Drop GNOME 46 backwards compatibility
+const transparent = Clutter.Color ?
+ Clutter.Color.from_pixel(0x00000000) :
+ new Cogl.Color({
+ red: 0,
+ green: 0,
+ blue: 0,
+ alpha: 0
+ });
+const FOLDER_DIALOG_ANIMATION_TIME = 200;
+
+const DIALOGS_STYLES = [
+ "appfolder-dialogs-transparent",
+ "appfolder-dialogs-light",
+ "appfolder-dialogs-dark"
+];
+
+let original_zoomAndFadeIn = null;
+let original_zoomAndFadeOut = null;
+let sigma;
+let brightness;
+
+let _zoomAndFadeIn = function () {
+ let [sourceX, sourceY] =
+ this._source.get_transformed_position();
+ let [dialogX, dialogY] =
+ this.child.get_transformed_position();
+
+ this.child.set({
+ translation_x: sourceX - dialogX,
+ translation_y: sourceY - dialogY,
+ scale_x: this._source.width / this.child.width,
+ scale_y: this._source.height / this.child.height,
+ opacity: 0,
+ });
+
+ this.set_background_color(transparent);
+
+ let blur_effect = this.get_effect("appfolder-blur");
+
+ blur_effect.radius = 0;
+ blur_effect.brightness = 1.0;
+ Tweener.addTween(blur_effect,
+ {
+ radius: sigma * 2,
+ brightness: brightness,
+ time: adjustAnimationTime(FOLDER_DIALOG_ANIMATION_TIME / 1000),
+ transition: 'easeOutQuad'
+ }
+ );
+
+ this.child.ease({
+ translation_x: 0,
+ translation_y: 0,
+ scale_x: 1,
+ scale_y: 1,
+ opacity: 255,
+ duration: FOLDER_DIALOG_ANIMATION_TIME,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ });
+
+ this._needsZoomAndFade = false;
+
+ if (this._sourceMappedId === 0) {
+ this._sourceMappedId = this._source.connect(
+ 'notify::mapped', this._zoomAndFadeOut.bind(this));
+ }
+};
+
+let _zoomAndFadeOut = function () {
+ if (!this._isOpen)
+ return;
+
+ if (!this._source.mapped) {
+ this.hide();
+ return;
+ }
+
+ let [sourceX, sourceY] =
+ this._source.get_transformed_position();
+ let [dialogX, dialogY] =
+ this.child.get_transformed_position();
+
+ this.set_background_color(transparent);
+
+ let blur_effect = this.get_effect("appfolder-blur");
+ Tweener.addTween(blur_effect,
+ {
+ radius: 0,
+ brightness: 1.0,
+ time: adjustAnimationTime(FOLDER_DIALOG_ANIMATION_TIME / 1000),
+ transition: 'easeInQuad'
+ }
+ );
+
+ this.child.ease({
+ translation_x: sourceX - dialogX,
+ translation_y: sourceY - dialogY,
+ scale_x: this._source.width / this.child.width,
+ scale_y: this._source.height / this.child.height,
+ opacity: 0,
+ duration: FOLDER_DIALOG_ANIMATION_TIME,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ onComplete: () => {
+ this.child.set({
+ translation_x: 0,
+ translation_y: 0,
+ scale_x: 1,
+ scale_y: 1,
+ opacity: 255,
+ });
+ this.hide();
+
+ this._popdownCallbacks.forEach(func => func());
+ this._popdownCallbacks = [];
+ },
+ });
+
+ this._needsZoomAndFade = false;
+};
+
+
+export const AppFoldersBlur = class AppFoldersBlur {
+ // we do not use the effects manager and dummy pipelines here because we
+ // really want to manage our sigma value ourself during the transition
+ constructor(connections, settings, _) {
+ this.connections = connections;
+ this.paint_signals = new PaintSignals(connections);
+ this.settings = settings;
+ }
+
+ enable() {
+ this._log("blurring appfolders");
+
+ brightness = this.settings.appfolder.BRIGHTNESS;
+ sigma = this.settings.appfolder.SIGMA;
+
+ let appDisplay = Main.overview._overview.controls._appDisplay;
+
+ if (appDisplay._folderIcons.length > 0) {
+ this.blur_appfolders();
+ }
+
+ this.connections.connect(
+ appDisplay, 'view-loaded', _ => this.blur_appfolders()
+ );
+ }
+
+ blur_appfolders() {
+ let appDisplay = Main.overview._overview.controls._appDisplay;
+
+ if (this.settings.HACKS_LEVEL === 1)
+ this._log("appfolders hack level 1");
+
+ appDisplay._folderIcons.forEach(icon => {
+ icon._ensureFolderDialog();
+
+ if (original_zoomAndFadeIn == null) {
+ original_zoomAndFadeIn = icon._dialog._zoomAndFadeIn;
+ }
+ if (original_zoomAndFadeOut == null) {
+ original_zoomAndFadeOut = icon._dialog._zoomAndFadeOut;
+ }
+
+ let blur_effect = new Shell.BlurEffect({
+ name: "appfolder-blur",
+ radius: sigma * 2,
+ brightness: brightness,
+ mode: Shell.BlurMode.BACKGROUND
+ });
+
+ icon._dialog.remove_effect_by_name("appfolder-blur");
+ icon._dialog.add_effect(blur_effect);
+
+ DIALOGS_STYLES.forEach(
+ style => icon._dialog._viewBox.remove_style_class_name(style)
+ );
+
+ if (this.settings.appfolder.STYLE_DIALOGS > 0)
+ icon._dialog._viewBox.add_style_class_name(
+ DIALOGS_STYLES[this.settings.appfolder.STYLE_DIALOGS - 1]
+ );
+
+ // finally override the builtin functions
+ icon._dialog._zoomAndFadeIn = _zoomAndFadeIn;
+ icon._dialog._zoomAndFadeOut = _zoomAndFadeOut;
+
+
+ // HACK
+ //
+ //`Shell.BlurEffect` does not repaint when shadows are under it. [1]
+ //
+ // This does not entirely fix this bug (shadows caused by windows
+ // still cause artifacts), but it prevents the shadows of the panel
+ // buttons to cause artifacts on the panel itself
+ //
+ // [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857
+
+ if (this.settings.HACKS_LEVEL === 1) {
+ this.paint_signals.disconnect_all_for_actor(icon._dialog);
+ this.paint_signals.connect(icon._dialog, blur_effect);
+ } else {
+ this.paint_signals.disconnect_all();
+ }
+ });
+ };
+
+ set_sigma(s) {
+ sigma = s;
+ if (this.settings.appfolder.BLUR)
+ this.blur_appfolders();
+ }
+
+ set_brightness(b) {
+ brightness = b;
+ if (this.settings.appfolder.BLUR)
+ this.blur_appfolders();
+ }
+
+ disable() {
+ this._log("removing blur from appfolders");
+
+ let appDisplay = Main.overview._overview.controls._appDisplay;
+
+ if (original_zoomAndFadeIn != null) {
+ appDisplay._folderIcons.forEach(icon => {
+ if (icon._dialog)
+ icon._dialog._zoomAndFadeIn = original_zoomAndFadeIn;
+ });
+ }
+
+ if (original_zoomAndFadeOut != null) {
+ appDisplay._folderIcons.forEach(icon => {
+ if (icon._dialog)
+ icon._dialog._zoomAndFadeOut = original_zoomAndFadeOut;
+ });
+ }
+
+ appDisplay._folderIcons.forEach(icon => {
+ if (icon._dialog) {
+ icon._dialog.remove_effect_by_name("appfolder-blur");
+ DIALOGS_STYLES.forEach(
+ s => icon._dialog._viewBox.remove_style_class_name(s)
+ );
+ }
+ });
+
+ this.connections.disconnect_all();
+ }
+
+ _log(str) {
+ if (this.settings.DEBUG)
+ console.log(`[Blur my Shell > appfolders] ${str}`);
+ }
+}; \ No newline at end of file
diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/applications.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/applications.js
new file mode 100644
index 0000000..e783046
--- /dev/null
+++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/applications.js
@@ -0,0 +1,614 @@
+import Meta from 'gi://Meta';
+import Gio from 'gi://Gio';
+import * as Main from 'resource:///org/gnome/shell/ui/main.js';
+import * as Config from 'resource:///org/gnome/shell/misc/config.js';
+
+import { ApplicationsService } from '../dbus/services.js';
+import { PaintSignals } from '../conveniences/paint_signals.js';
+import { DummyPipeline } from '../conveniences/dummy_pipeline.js';
+import { Pipeline } from '../conveniences/pipeline.js';
+
+
+/// Converts a wildcard pattern to a RegExp object.
+/// Supports * (matches any sequence) and ? (matches any single character).
+/// Matching is case-insensitive.
+///
+/// @param {string} pattern - The wildcard pattern (e.g., "Firefox*", "*Code*")
+/// @returns {RegExp} The compiled regex pattern
+function wildcardToRegex(pattern) {
+ // Escape special regex characters except * and ?
+ const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&');
+ // Convert wildcards: * -> .*, ? -> .
+ const regex = '^' + escaped.replace(/\*/g, '.*').replace(/\?/g, '.') + '$';
+ return new RegExp(regex, 'i');
+}
+
+
+/// Compiles an array of wildcard patterns into RegExp objects.
+/// Caches the results to avoid recompilation on every check.
+///
+/// @param {string[]} patterns - Array of wildcard patterns
+/// @param {Map} cache - Cache map storing pattern -> regex mappings
+/// @returns {RegExp[]} Array of compiled regex patterns
+function compilePatterns(patterns, cache) {
+ return patterns.map(pattern => {
+ if (cache.has(pattern)) {
+ return cache.get(pattern);
+ }
+ const regex = wildcardToRegex(pattern);
+ cache.set(pattern, regex);
+ return regex;
+ });
+}
+
+
+/// Tests if a value matches any of the compiled patterns.
+///
+/// @param {string} value - The value to test (e.g., wm_class)
+/// @param {RegExp[]} patterns - Array of compiled regex patterns
+/// @returns {boolean} True if value matches any pattern
+function matchesAnyPattern(value, patterns) {
+ if (!value || patterns.length === 0) {
+ return false;
+ }
+ return patterns.some(pattern => pattern.test(value));
+}
+
+export const ApplicationsBlur = class ApplicationsBlur {
+ constructor(connections, settings, effects_manager) {
+ this.connections = connections;
+ this.settings = settings;
+ this.effects_manager = effects_manager;
+ this.paint_signals = new PaintSignals(connections);
+
+ // stores every blurred meta window
+ this.meta_window_map = new Map();
+
+ // cache for compiled patterns to avoid recompilation
+ this._whitelist_pattern_cache = new Map();
+ this._blacklist_pattern_cache = new Map();
+ this._compiled_whitelist = [];
+ this._compiled_blacklist = [];
+
+ // compile initial patterns
+ this._update_patterns();
+ }
+
+ /// Updates the compiled whitelist and blacklist patterns from settings.
+ /// Called during initialization and when whitelist/blacklist settings change.
+ _update_patterns() {
+ const whitelist = this.settings.applications.WHITELIST || [];
+ const blacklist = this.settings.applications.BLACKLIST || [];
+
+ this._compiled_whitelist = compilePatterns(whitelist, this._whitelist_pattern_cache);
+ this._compiled_blacklist = compilePatterns(blacklist, this._blacklist_pattern_cache);
+
+ this._log(`Patterns updated - whitelist: ${whitelist.length}, blacklist: ${blacklist.length}`);
+ }
+
+ enable() {
+ this._log("blurring applications...");
+
+ // export dbus service for preferences
+ this.service = new ApplicationsService;
+ this.service.export();
+
+ this.mutter_gsettings = new Gio.Settings({ schema: 'org.gnome.mutter' });
+
+ // blur already existing windows
+ this.update_all_windows();
+
+ // blur every new window
+ this.connections.connect(
+ global.display,
+ 'window-created',
+ (_meta_display, meta_window) => {
+ this._log("window created");
+
+ if (meta_window)
+ this.track_new(meta_window);
+ }
+ );
+
+ // update window blur when focus is changed
+ this.focused_window_pid = null;
+ this.init_dynamic_opacity();
+ this.connections.connect(
+ global.display,
+ 'focus-window',
+ (_meta_display, meta_window, _p0) => {
+ if (meta_window && meta_window.bms_pid != this.focused_window_pid)
+ this.set_focus_for_window(meta_window);
+ else if (!meta_window)
+ this.set_focus_for_window(null);
+ }
+ );
+
+ this.connect_to_overview();
+ }
+
+ /// Initializes the dynamic opacity for windows, without touching to the connections.
+ /// This is used both when enabling the component, and when changing the dynamic-opacity pref.
+ init_dynamic_opacity() {
+ if (this.settings.applications.DYNAMIC_OPACITY) {
+ // make the currently focused window solid
+ if (global.display.focus_window)
+ this.set_focus_for_window(global.display.focus_window);
+ } else {
+ // remove old focused window if the pref was changed
+ if (this.focused_window_pid)
+ this.set_focus_for_window(null);
+ }
+ }
+
+ /// Connect to the overview being opened/closed to force the blur being
+ /// shown on every window of the workspaces viewer.
+ connect_to_overview() {
+ this.connections.disconnect_all_for(Main.overview);
+
+ if (this.settings.applications.BLUR_ON_OVERVIEW) {
+ // when the overview is opened, show every window actors (which
+ // allows the blur to be shown too)
+ this.connections.connect(
+ Main.overview, 'showing',
+ _ => this.meta_window_map.forEach((meta_window, _pid) => {
+ let window_actor = meta_window.get_compositor_private();
+ window_actor?.show();
+ })
+ );
+
+ // when the overview is closed, hide every actor that is not on the
+ // current workspace (to mimic the original behaviour)
+ this.connections.connect(
+ Main.overview, 'hidden',
+ _ => {
+ this.meta_window_map.forEach((meta_window, _pid) => {
+ let window_actor = meta_window.get_compositor_private();
+
+ if (
+ (!meta_window.get_workspace().active) || meta_window.minimized
+ )
+ window_actor.hide();
+ });
+ }
+ );
+ }
+ }
+
+ /// Iterate through all existing windows and add blur as needed.
+ update_all_windows() {
+ // Recompile patterns in case whitelist/blacklist changed
+ this._update_patterns();
+
+ // remove all previously blurred windows, in the case where the
+ // whitelist was changed
+ this.meta_window_map.forEach(((_meta_window, pid) => {
+ this.remove_blur(pid);
+ }));
+
+ for (
+ let i = 0;
+ i < global.workspace_manager.get_n_workspaces();
+ ++i
+ ) {
+ let workspace = global.workspace_manager.get_workspace_by_index(i);
+ let windows = workspace.list_windows();
+
+ windows.forEach(meta_window => this.track_new(meta_window));
+ }
+ }
+
+ /// Adds the needed signals to every new tracked window, and adds blur if
+ /// needed.
+ /// Accepts only untracked meta windows (i.e no `bms_pid` set)
+ track_new(meta_window) {
+ // create a pid that will follow the window during its whole life
+ const pid = ("" + Math.random()).slice(2, 16);
+ meta_window.bms_pid = pid;
+
+ this._log(`new window tracked, pid: ${pid}`);
+
+ // register the blurred window
+ this.meta_window_map.set(pid, meta_window);
+
+ // update the blur when wm-class is changed
+ this.connections.connect(
+ meta_window, 'notify::wm-class',
+ _ => this.check_blur(meta_window)
+ );
+
+ // update the clip, position, and/or size when the window changes
+ this.connections.connect(
+ meta_window, 'size-changed',
+ _ => this.update_size(pid)
+ );
+ if (this.settings.applications.STATIC_BLUR) {
+ this.connections.connect(
+ meta_window, 'position-changed',
+ _ => this.update_size(pid)
+ );
+ }
+
+ // remove the blur when the window is unmanaged
+ this.connections.connect(
+ meta_window, 'unmanaging',
+ _ => this.untrack_meta_window(pid)
+ );
+
+ this.check_blur(meta_window);
+
+ if (this.settings.applications.STATIC_BLUR && meta_window.get_client_type() === Meta.WindowClientType.X11) {
+ const window_actor = meta_window.get_compositor_private();
+ window_actor.connect('child-added', _ => {
+ if (!meta_window.blur_actor) {
+ this._warn("can't move blur actor to back, it doesn't exist");
+ return;
+ }
+
+ window_actor.set_child_below_sibling(meta_window.blur_actor, null);
+ });
+ }
+ }
+
+ /// Updates the size of the blur actor associated to a meta window from its pid.
+ /// Accepts only tracked meta window (i.e `bms_pid` set), be it blurred or not.
+ update_size(pid) {
+ if (this.meta_window_map.has(pid)) {
+ const meta_window = this.meta_window_map.get(pid);
+ const blur_actor = meta_window.blur_actor;
+ if (blur_actor) {
+ if (this.settings.applications.STATIC_BLUR) {
+ const bg_manager = meta_window.bg_manager;
+ const bg_actor_monitor_index = bg_manager.backgroundActor.monitor;
+ const window_monitor_index = meta_window.get_monitor();
+ const monitor = Main.layoutManager.monitors[window_monitor_index];
+
+ if (bg_actor_monitor_index !== window_monitor_index) {
+ this._log(`application (pid ${pid}) switching to monitor: ${window_monitor_index}`);
+
+ // Recreate the BackgroundActor on the right monitor. This is necessary to make sure differently
+ // sized monitors have the correct scaled image of the wallpaper.
+ bg_manager._monitorIndex = window_monitor_index;
+ bg_manager._updateBackgroundActor();
+
+ // Also to fix differently sized monitor issues.
+ blur_actor.width = monitor.width;
+ blur_actor.height = monitor.height;
+ }
+
+ const frame = meta_window.get_frame_rect();
+ const buffer = meta_window.get_buffer_rect();
+ blur_actor.x = monitor.x - buffer.x;
+ blur_actor.y = monitor.y - buffer.y;
+
+ // set_clip(x-offset, y-offset, width, height)
+ blur_actor.set_clip(frame.x - monitor.x, frame.y - monitor.y, frame.width, frame.height);
+ } else {
+ const allocation = this.compute_allocation(meta_window);
+ blur_actor.x = allocation.x;
+ blur_actor.y = allocation.y;
+ blur_actor.width = allocation.width;
+ blur_actor.height = allocation.height;
+ }
+ }
+ } else
+ // the pid was visibly not removed
+ this.untrack_meta_window(pid);
+ }
+
+ /// Checks if the given actor needs to be blurred.
+ /// Accepts only tracked meta window, be it blurred or not.
+ ///
+ /// In order to be blurred, a window either:
+ /// - is whitelisted in the user preferences if not enable-all
+ /// - is not blacklisted if enable-all
+ ///
+ /// Whitelist and blacklist support wildcard patterns:
+ /// - * matches any sequence of characters
+ /// - ? matches any single character
+ /// - Matching is case-insensitive
+ check_blur(meta_window) {
+ const window_wm_class = meta_window.get_wm_class();
+ const enable_all = this.settings.applications.ENABLE_ALL;
+ if (window_wm_class)
+ this._log(`pid ${meta_window.bms_pid} associated to wm class name ${window_wm_class}`);
+
+
+ // if we are in blacklist mode and the window is not blacklisted
+ // or if we are in whitelist mode and the window is whitelisted
+ if (
+ window_wm_class !== ""
+ && ((enable_all && !matchesAnyPattern(window_wm_class, this._compiled_blacklist))
+ || (!enable_all && matchesAnyPattern(window_wm_class, this._compiled_whitelist))
+ )
+ && [
+ Meta.FrameType.NORMAL,
+ Meta.FrameType.DIALOG,
+ Meta.FrameType.MODAL_DIALOG
+ ].includes(meta_window.get_frame_type())
+ ) {
+ // only blur the window if it is not already done
+ if (!meta_window.blur_actor)
+ this.create_blur_effect(meta_window);
+ }
+
+ // remove blur it is not explicitly whitelisted or un-blacklisted
+ else if (meta_window.blur_actor)
+ this.remove_blur(meta_window.bms_pid);
+ }
+
+ /// Add the blur effect to the window.
+ /// Accepts only tracked meta window that is NOT already blurred.
+ create_blur_effect(meta_window) {
+ const pid = meta_window.bms_pid;
+ const window_actor = meta_window.get_compositor_private();
+
+ let blur_actor;
+
+ if (this.settings.applications.STATIC_BLUR) {
+ const pipeline = new Pipeline(this.effects_manager, global.blur_my_shell._pipelines_manager, this.settings.applications.PIPELINE);
+ const bg_managers = [];
+ blur_actor = pipeline.create_background_with_effects(
+ meta_window.get_monitor(), bg_managers, window_actor,
+ 'bms-application-blurred-widget'
+ );
+
+ if (bg_managers.length > 0) meta_window.bg_manager = bg_managers[0];
+ else // I've never seen this happen, but just in case
+ this._warn(`no bg_manager on blur creation for pid ${pid}`);
+ } else {
+ const pipeline = new DummyPipeline(this.effects_manager, this.settings.applications);
+ [blur_actor, meta_window.bg_manager] = pipeline.create_background_with_effect(
+ window_actor, 'bms-application-blurred-widget'
+ );
+
+ // if hacks are selected, force to repaint the window
+ if (this.settings.HACKS_LEVEL === 1) {
+ this._log("hack level 1");
+
+ this.paint_signals.disconnect_all_for_actor(blur_actor);
+ this.paint_signals.connect(blur_actor, pipeline.effect);
+ } else {
+ this.paint_signals.disconnect_all_for_actor(blur_actor);
+ }
+ }
+
+ meta_window.blur_actor = blur_actor;
+
+ // make sure window is blurred in overview
+ if (this.settings.applications.BLUR_ON_OVERVIEW)
+ this.enforce_window_visibility_on_overview_for(window_actor);
+
+ // update the size
+ this.update_size(pid);
+
+ // set the window actor's opacity
+ this.set_window_opacity(window_actor, this.settings.applications.OPACITY);
+
+ // now set up the signals, for the window actor only: they are disconnected
+ // in `remove_blur`, whereas the signals for the meta window are disconnected
+ // only when the whole component is disabled
+
+ // update the window opacity when it changes, else we don't control it fully
+ this.connections.connect(
+ window_actor, 'notify::opacity',
+ _ => {
+ if (this.focused_window_pid != pid)
+ this.set_window_opacity(window_actor, this.settings.applications.OPACITY);
+ }
+ );
+
+ // hide the blur if window becomes invisible
+ if (!window_actor.visible)
+ blur_actor.hide();
+
+ this.connections.connect(
+ window_actor,
+ 'notify::visible',
+ window_actor => {
+ if (window_actor.visible)
+ meta_window.blur_actor.show();
+ else
+ meta_window.blur_actor.hide();
+ }
+ );
+ }
+
+ /// With `focus=true`, tells us we are focused on said window (which can be null if
+ /// we are not focused anymore). It automatically removes the ancient focus.
+ /// With `focus=false`, just remove the focus from said window (which can still be null).
+ set_focus_for_window(meta_window, focus = true) {
+ let blur_actor = null;
+ let window_actor = null;
+ let new_pid = null;
+ if (meta_window) {
+ blur_actor = meta_window.blur_actor;
+ window_actor = meta_window.get_compositor_private();
+ new_pid = meta_window.bms_pid;
+ }
+
+ if (focus) {
+ // remove old focused window if any
+ if (this.focused_window_pid) {
+ const old_focused_window = this.meta_window_map.get(this.focused_window_pid);
+ if (old_focused_window)
+ this.set_focus_for_window(old_focused_window, false);
+ }
+ // set new focused window pid
+ this.focused_window_pid = new_pid;
+ // if we have blur, hide it and make the window opaque
+ if (this.settings.applications.DYNAMIC_OPACITY && blur_actor) {
+ blur_actor.hide();
+ this.set_window_opacity(window_actor, 255);
+ }
+ }
+ // if we remove the focus and have blur, show it and make the window transparent
+ else if (blur_actor) {
+ blur_actor.show();
+ this.set_window_opacity(window_actor, this.settings.applications.OPACITY);
+ }
+ }
+
+ /// Makes sure that, when the overview is visible, the window actor will
+ /// stay visible no matter what.
+ /// We can instead hide the last child of the window actor, which will
+ /// improve performances without hiding the blur effect.
+ enforce_window_visibility_on_overview_for(window_actor) {
+ this.connections.connect(window_actor, 'notify::visible',
+ _ => {
+ if (this.settings.applications.BLUR_ON_OVERVIEW) {
+ if (
+ !window_actor.visible
+ && Main.overview.visible
+ ) {
+ window_actor.show();
+ window_actor.get_last_child().hide();
+ } else if (
+ window_actor.visible
+ )
+ window_actor.get_last_child().show();
+ }
+ }
+ );
+ }
+
+ /// Set the opacity of the window actor that sits on top of the blur effect.
+ set_window_opacity(window_actor, opacity) {
+ window_actor?.get_children().forEach(child => {
+ if (child.name !== "blur-actor" && child.opacity != opacity)
+ child.opacity = opacity;
+ });
+ }
+
+ /// Update the opacity of all window actors.
+ set_opacity() {
+ let opacity = this.settings.applications.OPACITY;
+
+ this.meta_window_map.forEach(((meta_window, pid) => {
+ if (pid != this.focused_window_pid && meta_window.blur_actor) {
+ let window_actor = meta_window.get_compositor_private();
+ this.set_window_opacity(window_actor, opacity);
+ }
+ }));
+ }
+
+ /// Find the system's window scaling.
+ /// If `scale-monitor-framebuffer` experimental feature if on, we don't need to manage scaling.
+ /// Else, on wayland, we need to divide by the scale to get the correct result.
+ compute_scale(meta_window) {
+ // TODO: Drop GNOME <50 compatibility
+ const gnome_shell_major_version = parseInt(Config.PACKAGE_VERSION.split('.')[0]);
+ const scale_monitor_framebuffer =
+ gnome_shell_major_version >= 50 ||
+ this.mutter_gsettings
+ .get_strv('experimental-features')
+ .includes('scale-monitor-framebuffer');
+ const is_wayland = gnome_shell_major_version >= 50 ||
+ (typeof Meta.is_wayland_compositor === 'function'
+ ? Meta.is_wayland_compositor()
+ : global.display?.is_wayland_compositor?.() ?? true);
+ const monitor_index = meta_window.get_monitor();
+ // check if the window is using wayland, or xwayland/xorg for rendering
+ return !scale_monitor_framebuffer && is_wayland && meta_window.get_client_type() == 0
+ ? Main.layoutManager.monitors[monitor_index].geometry_scale
+ : 1;
+ }
+
+ /// Compute the size and position for a blur actor.
+ /// Coordinates are relative to window buffer's corner.
+ compute_allocation(meta_window) {
+ const scale = this.compute_scale(meta_window);
+
+ let frame = meta_window.get_frame_rect();
+ let buffer = meta_window.get_buffer_rect();
+
+ return {
+ x: (frame.x - buffer.x) / scale,
+ y: (frame.y - buffer.y) / scale,
+ width: frame.width / scale,
+ height: frame.height / scale
+ };
+ }
+
+ change_blur_type() {
+ this._log("resetting...");
+
+ this.disable();
+ setTimeout(_ => this.enable(), 1);
+ }
+
+ change_pipeline() {
+ this.update_all_windows();
+ }
+
+ /// Removes the blur actor to make a blurred window become normal again.
+ /// It however does not untrack the meta window itself.
+ /// Accepts a pid corresponding (or not) to a blurred (or not) meta window.
+ remove_blur(pid) {
+ this._log(`removing blur for pid ${pid}`);
+
+ let meta_window = this.meta_window_map.get(pid);
+ if (meta_window) {
+ let window_actor = meta_window.get_compositor_private();
+ let blur_actor = meta_window.blur_actor;
+ let bg_manager = meta_window.bg_manager;
+
+ if (blur_actor && window_actor) {
+ // reset the opacity
+ this.set_window_opacity(window_actor, 255);
+
+ // remove the blurred actor
+ window_actor.remove_child(blur_actor);
+ bg_manager._bms_pipeline.destroy();
+ bg_manager.destroy();
+ blur_actor.destroy();
+
+ // kinda untrack the blurred actor, as its presence is how we know
+ // whether we are blurred or not
+ delete meta_window.blur_actor;
+ delete meta_window.bg_manager;
+
+ // disconnect the signals of the window actor
+ this.paint_signals.disconnect_all_for_actor(blur_actor);
+ this.connections.disconnect_all_for(window_actor);
+ }
+ }
+ }
+
+ /// Kinda the same as `remove_blur`, but better: it also untracks the window.
+ /// This needs to be called when the component is being disabled, else it
+ /// would cause havoc by having untracked windows during normal operations,
+ /// which is not the point at all!
+ /// Accepts a pid corresponding (or not) to a blurred (or not) meta window.
+ untrack_meta_window(pid) {
+ this.remove_blur(pid);
+ let meta_window = this.meta_window_map.get(pid);
+ if (meta_window) {
+ this.connections.disconnect_all_for(meta_window);
+ this.meta_window_map.delete(pid);
+ }
+ }
+
+ disable() {
+ this._log("removing blur from applications...");
+
+ this.service?.unexport();
+ delete this.mutter_gsettings;
+
+ this.meta_window_map.forEach((_meta_window, pid) => {
+ this.untrack_meta_window(pid);
+ });
+
+ this.connections.disconnect_all();
+ this.paint_signals.disconnect_all();
+ }
+
+ _log(str) {
+ if (this.settings.DEBUG)
+ console.log(`[Blur my Shell > applications] ${str}`);
+ }
+
+ _warn(str) {
+ console.warn(`[Blur my Shell > applications] ${str}`);
+ }
+};
diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/coverflow_alt_tab.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/coverflow_alt_tab.js
new file mode 100644
index 0000000..4e6062a
--- /dev/null
+++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/coverflow_alt_tab.js
@@ -0,0 +1,91 @@
+import * as Main from "resource:///org/gnome/shell/ui/main.js";
+
+import { PaintSignals } from "../conveniences/paint_signals.js";
+import { Pipeline } from "../conveniences/pipeline.js";
+
+export const CoverflowAltTabBlur = class CoverflowAltTabBlur {
+ constructor(connections, settings, effects_manager) {
+ this.connections = connections;
+ this.settings = settings;
+ this.paint_signals = new PaintSignals(connections);
+ this.effects_manager = effects_manager;
+ this.background_actors = [];
+ this.background_managers = [];
+ }
+
+ enable() {
+ this._log("blurring coverflow alt-tab");
+
+ this.update_backgrounds();
+
+ this.connections.connect(
+ Main.layoutManager.uiGroup,
+ "child-added",
+ (_, child) => this.try_blur(child)
+ );
+
+ this.connections.connect(Main.layoutManager, "monitors-changed", (_) => {
+ this.update_backgrounds();
+ });
+ }
+
+ update_backgrounds() {
+ this.remove_background_actors();
+
+ Main.layoutManager.uiGroup
+ .get_children()
+ .forEach((child) => this.try_blur(child));
+ }
+
+ try_blur(actor) {
+ if (
+ actor.constructor.name !== "Meta_BackgroundGroup" ||
+ actor.get_name() !== "coverflow-alt-tab-background-group"
+ ) {
+ return;
+ }
+
+ this._log("found coverflow alt-tab to blur");
+
+ for (let i = 0; i < Main.layoutManager.monitors.length; i++) {
+ const pipeline = new Pipeline(
+ this.effects_manager,
+ global.blur_my_shell._pipelines_manager,
+ this.settings.coverflow_alt_tab.PIPELINE
+ );
+
+ const background_actor = pipeline.create_background_with_effects(
+ i,
+ this.background_managers,
+ actor,
+ "bms-coverflow-alt-tab-blurred-widget"
+ );
+
+ this.background_actors.push(background_actor);
+ }
+ }
+
+ remove_background_actors() {
+ this.background_actors.forEach((actor) => actor.destroy());
+ this.background_actors = [];
+
+ this.background_managers.forEach((background_manager) => {
+ background_manager._bms_pipeline.destroy();
+ background_manager.destroy();
+ });
+ this.background_managers = [];
+ }
+
+ disable() {
+ this._log("removing blur from coverflow alt-tab");
+
+ this.remove_background_actors();
+ this.connections.disconnect_all();
+ }
+
+ _log(str) {
+ if (this.settings.DEBUG) {
+ console.log(`[Blur my Shell > coverflow alt-tab] ${str}`);
+ }
+ }
+};
diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/dash_to_dock.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/dash_to_dock.js
new file mode 100644
index 0000000..4ff212c
--- /dev/null
+++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/dash_to_dock.js
@@ -0,0 +1,421 @@
+import Meta from 'gi://Meta';
+import * as Main from 'resource:///org/gnome/shell/ui/main.js';
+import * as Signals from 'resource:///org/gnome/shell/misc/signals.js';
+
+import { PaintSignals } from '../conveniences/paint_signals.js';
+
+import { Pipeline } from '../conveniences/pipeline.js';
+import { DummyPipeline } from '../conveniences/dummy_pipeline.js';
+
+const DASH_STYLES = [
+ "transparent-dash",
+ "light-dash",
+ "dark-dash"
+];
+
+
+/// This type of object is created for every dash found, and talks to the main
+/// DashBlur thanks to signals.
+///
+/// This allows to dynamically track the created dashes for each screen.
+class DashInfos {
+ constructor(
+ dash_blur, dash, dash_container, dash_background,
+ background, background_group, bg_manager
+ ) {
+ // the parent DashBlur object, to communicate
+ this.dash_blur = dash_blur;
+ this.dash = dash;
+ this.dash_container = dash_container;
+ this.dash_background = dash_background;
+ this.background = background;
+ this.background_group = background_group;
+ this.bg_manager = bg_manager;
+ this.settings = dash_blur.settings;
+ this.old_style = this.dash._background.style;
+
+ this.dash_destroy_id = dash.connect('destroy', () => this.remove_dash_blur(false));
+ this.dash_blur_connections_ids = [];
+ this.dash_blur_connections_ids.push(
+ this.dash_blur.connect('remove-dashes', () => this.remove_dash_blur()),
+ this.dash_blur.connect('override-style', () => this.override_style()),
+ this.dash_blur.connect('remove-style', () => this.remove_style()),
+ this.dash_blur.connect('show', () => this.background_group.show()),
+ this.dash_blur.connect('hide', () => this.background_group.hide()),
+ this.dash_blur.connect('update-size', () => this.update_size()),
+ this.dash_blur.connect('change-blur-type', () => this.change_blur_type()),
+ this.dash_blur.connect('update-pipeline', () => this.update_pipeline())
+ );
+ }
+
+ // IMPORTANT: do never call this in a mutable `this.dash_blur.forEach`
+ remove_dash_blur(dash_not_already_destroyed = true) {
+ // remove the style and destroy the effects
+ this.remove_style();
+ this.destroy_dash(dash_not_already_destroyed);
+
+ // remove the dash infos from their list
+ const dash_infos_index = this.dash_blur.dashes.indexOf(this);
+ if (dash_infos_index >= 0)
+ this.dash_blur.dashes.splice(dash_infos_index, 1);
+
+ // disconnect everything
+ this.dash_blur_connections_ids.forEach(id => { if (id) this.dash_blur.disconnect(id); });
+ this.dash_blur_connections_ids = [];
+ if (this.dash_destroy_id)
+ this.dash.disconnect(this.dash_destroy_id);
+ this.dash_destroy_id = null;
+ }
+
+ override_style() {
+ this.remove_style();
+
+ this.dash.set_style_class_name(
+ DASH_STYLES[this.settings.dash_to_dock.STYLE_DASH_TO_DOCK]
+ );
+ }
+
+ remove_style() {
+ this.dash._background.style = this.old_style;
+
+ DASH_STYLES.forEach(
+ style => this.dash.remove_style_class_name(style)
+ );
+ }
+
+ destroy_dash(dash_not_already_destroyed = true) {
+ if (!dash_not_already_destroyed)
+ this.bg_manager.backgroundActor = null;
+
+ this.paint_signals?.disconnect_all();
+ this.dash.get_parent().remove_child(this.background_group);
+ this.bg_manager._bms_pipeline.destroy();
+ this.bg_manager.destroy();
+ this.background_group.destroy();
+ }
+
+ change_blur_type() {
+ this.destroy_dash();
+
+ let [
+ background, background_group, bg_manager, paint_signals
+ ] = this.dash_blur.add_blur(this.dash);
+
+ this.background = background;
+ this.background_group = background_group;
+ this.bg_manager = bg_manager;
+ this.paint_signals = paint_signals;
+
+ this.dash.get_parent().insert_child_at_index(this.background_group, 0);
+
+ this.update_size();
+ }
+
+ update_pipeline() {
+ this.bg_manager._bms_pipeline.change_pipeline_to(
+ this.settings.dash_to_dock.PIPELINE
+ );
+ }
+
+ update_size() {
+ if (this.dash_blur.is_static) {
+ let [x, y] = this.get_dash_position(this.dash_container, this.dash_background);
+
+ this.background.x = -x;
+ this.background.y = -y;
+
+ if (this.dash_container.get_style_class_name().includes("top"))
+ this.background.set_clip(
+ x,
+ y + this.dash.y + this.dash_background.y,
+ this.dash_background.width,
+ this.dash_background.height
+ );
+ else if (this.dash_container.get_style_class_name().includes("bottom"))
+ this.background.set_clip(
+ x,
+ y + this.dash.y + this.dash_background.y,
+ this.dash_background.width,
+ this.dash_background.height
+ );
+ else if (this.dash_container.get_style_class_name().includes("left"))
+ this.background.set_clip(
+ x + this.dash.x + this.dash_background.x,
+ y + this.dash.y + this.dash_background.y,
+ this.dash_background.width,
+ this.dash_background.height
+ );
+ else if (this.dash_container.get_style_class_name().includes("right"))
+ this.background.set_clip(
+ x + this.dash.x + this.dash_background.x,
+ y + this.dash.y + this.dash_background.y,
+ this.dash_background.width,
+ this.dash_background.height
+ );
+ } else {
+ this.background.width = this.dash_background.width;
+ this.background.height = this.dash_background.height;
+
+ this.background.x = this.dash_background.x;
+ this.background.y = this.dash_background.y + this.dash.y;
+ }
+ }
+
+ get_dash_position(dash_container, dash_background) {
+ var x, y;
+
+ let monitor = Main.layoutManager.findMonitorForActor(dash_container);
+ let dash_box = dash_container._slider.get_child();
+
+ if (dash_container.get_style_class_name().includes("top")) {
+ x = (monitor.width - dash_background.width) / 2;
+ y = dash_box.y;
+ } else if (dash_container.get_style_class_name().includes("bottom")) {
+ x = (monitor.width - dash_background.width) / 2;
+ y = monitor.height - dash_container.height;
+ } else if (dash_container.get_style_class_name().includes("left")) {
+ x = dash_box.x;
+ y = dash_container.y + (dash_container.height - dash_background.height) / 2 - dash_background.y;
+ } else if (dash_container.get_style_class_name().includes("right")) {
+ x = monitor.width - dash_container.width;
+ y = dash_container.y + (dash_container.height - dash_background.height) / 2 - dash_background.y;
+ }
+
+ return [x, y];
+ }
+
+ _log(str) {
+ if (this.settings.DEBUG)
+ console.log(`[Blur my Shell > dash] ${str}`);
+ }
+
+ _warn(str) {
+ console.warn(`[Blur my Shell > dash] ${str}`);
+ }
+}
+
+export const DashBlur = class DashBlur extends Signals.EventEmitter {
+ constructor(connections, settings, _) {
+ super();
+ this.dashes = [];
+ this.connections = connections;
+ this.settings = settings;
+ this.paint_signals = new PaintSignals(connections);
+ this.is_static = this.settings.dash_to_dock.STATIC_BLUR;
+ this.enabled = false;
+ }
+
+ enable() {
+ this.connections.connect(Main.uiGroup, 'child-added', (_, actor) => {
+ if (
+ (actor.get_name() === "dashtodockContainer") &&
+ (actor.constructor.name === 'DashToDock')
+ )
+ this.try_blur(actor);
+ });
+
+ this.blur_existing_dashes();
+ this.connect_to_overview();
+
+ this.update_size();
+
+ this.enabled = true;
+ }
+
+ // Finds all existing dashes on every monitor, and call `try_blur` on them
+ // We cannot only blur `Main.overview.dash`, as there could be several
+ blur_existing_dashes() {
+ this._log("searching for dash");
+
+ // blur every dash found, filtered by name
+ Main.uiGroup.get_children().filter((child) => {
+ return (child.get_name() === "dashtodockContainer") &&
+ (child.constructor.name === 'DashToDock');
+ }).forEach(dash_container => this.try_blur(dash_container));
+ }
+
+ // Tries to blur the dash contained in the given actor
+ try_blur(dash_container) {
+ let dash_box = dash_container._slider.get_child();
+
+ // verify that we did not already blur that dash
+ if (!dash_box.get_children().some(child =>
+ child.get_name() === "bms-dash-backgroundgroup"
+ )) {
+ this._log("dash to dock found, blurring it");
+
+ // finally blur the dash
+ let dash = dash_box.get_children().find(child => {
+ return child.get_name() === 'dash';
+ });
+
+ this.dashes.push(this.blur_dash_from(dash, dash_container));
+ }
+ }
+
+ // Blurs the dash and returns a `DashInfos` containing its information
+ blur_dash_from(dash, dash_container) {
+ let [background, background_group, bg_manager, paint_signals] = this.add_blur(dash);
+
+ // insert the background group to the right element
+ dash.get_parent().insert_child_at_index(background_group, 0);
+
+ // updates size and position on change
+ this.connections.connect(
+ dash,
+ ['notify::width', 'notify::height'],
+ _ => this.update_size()
+ );
+ this.connections.connect(
+ dash_container,
+ ['notify::width', 'notify::height', 'notify::y', 'notify::x'],
+ _ => this.update_size()
+ );
+
+ const dash_background = dash.get_children().find(child => {
+ return child.get_style_class_name() === 'dash-background';
+ });
+
+ // create infos
+ let infos = new DashInfos(
+ this,
+ dash,
+ dash_container,
+ dash_background,
+ background,
+ background_group,
+ bg_manager,
+ paint_signals
+ );
+
+ this.update_size();
+ this.update_background();
+
+ // returns infos
+ return infos;
+ }
+
+ add_blur(dash) {
+ const monitor = Main.layoutManager.findMonitorForActor(dash);
+ if (!monitor)
+ return;
+
+ const background_group = new Meta.BackgroundGroup({
+ name: 'bms-dash-backgroundgroup', width: 0, height: 0
+ });
+
+ let background, bg_manager, paint_signals;
+ let static_blur = this.settings.dash_to_dock.STATIC_BLUR;
+ if (static_blur) {
+ let bg_manager_list = [];
+ const pipeline = new Pipeline(
+ global.blur_my_shell._effects_manager,
+ global.blur_my_shell._pipelines_manager,
+ this.settings.dash_to_dock.PIPELINE
+ );
+ background = pipeline.create_background_with_effects(
+ monitor.index, bg_manager_list,
+ background_group, 'bms-dash-blurred-widget'
+ );
+ bg_manager = bg_manager_list[0];
+ }
+ else {
+ const pipeline = new DummyPipeline(
+ global.blur_my_shell._effects_manager,
+ this.settings.dash_to_dock
+ );
+ [background, bg_manager] = pipeline.create_background_with_effect(
+ background_group, 'bms-dash-blurred-widget'
+ );
+
+ paint_signals = new PaintSignals(this.connections);
+
+ // HACK
+ //
+ //`Shell.BlurEffect` does not repaint when shadows are under it. [1]
+ //
+ // This does not entirely fix this bug (shadows caused by windows
+ // still cause artifacts), but it prevents the shadows of the dash
+ // buttons to cause artifacts on the dash itself
+ //
+ // [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857
+
+ if (this.settings.HACKS_LEVEL === 1) {
+ this._log("hack level 1");
+
+ paint_signals.disconnect_all();
+ paint_signals.connect(background, pipeline.effect);
+ } else {
+ paint_signals.disconnect_all();
+ }
+ }
+
+ return [background, background_group, bg_manager, paint_signals];
+ }
+
+ change_blur_type() {
+ this.is_static = this.settings.dash_to_dock.STATIC_BLUR;
+ this.emit('change-blur-type');
+
+ this.update_background();
+ }
+
+ /// Connect when overview if opened/closed to hide/show the blur accordingly
+ connect_to_overview() {
+ this.connections.disconnect_all_for(Main.overview);
+
+ if (this.settings.dash_to_dock.UNBLUR_IN_OVERVIEW) {
+ this.connections.connect(
+ Main.overview, 'showing', _ => this.hide()
+ );
+ this.connections.connect(
+ Main.overview, 'hidden', _ => this.show()
+ );
+ }
+ };
+
+ /// Updates the background to either remove it or not, according to the
+ /// user preferences.
+ update_background() {
+ this._log("updating background");
+ if (this.settings.dash_to_dock.OVERRIDE_BACKGROUND)
+ this.emit('override-style');
+ else
+ this.emit('remove-style');
+ }
+
+ update_pipeline() {
+ this.emit('update-pipeline');
+ }
+
+ update_size() {
+ this.emit('update-size');
+ }
+
+ show() {
+ this.emit('show');
+ }
+ hide() {
+ this.emit('hide');
+ }
+
+ disable() {
+ this._log("removing blur from dashes");
+
+ this.emit('remove-dashes');
+
+ this.dashes = [];
+ this.connections.disconnect_all();
+
+ this.enabled = false;
+ }
+
+ _log(str) {
+ if (this.settings.DEBUG)
+ console.log(`[Blur my Shell > dash manager] ${str}`);
+ }
+
+ _warn(str) {
+ console.warn(`[Blur my Shell > dash manager] ${str}`);
+ }
+}; \ No newline at end of file
diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/lockscreen.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/lockscreen.js
new file mode 100644
index 0000000..7755ba9
--- /dev/null
+++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/lockscreen.js
@@ -0,0 +1,89 @@
+import * as Main from 'resource:///org/gnome/shell/ui/main.js';
+import { UnlockDialog } from 'resource:///org/gnome/shell/ui/unlockDialog.js';
+
+import { Pipeline } from '../conveniences/pipeline.js';
+
+const original_createBackground =
+ UnlockDialog.prototype._createBackground;
+const original_updateBackgroundEffects =
+ UnlockDialog.prototype._updateBackgroundEffects;
+const original_updateBackgrounds =
+ UnlockDialog.prototype._updateBackgrounds;
+
+
+export const LockscreenBlur = class LockscreenBlur {
+ constructor(connections, settings, effects_manager) {
+ this.connections = connections;
+ this.settings = settings;
+ this.effects_manager = effects_manager;
+ this.enabled = false;
+ }
+
+ enable() {
+ this._log("blurring lockscreen");
+
+ this.update_lockscreen();
+
+ this.enabled = true;
+ }
+
+ update_lockscreen() {
+ UnlockDialog.prototype._createBackground =
+ this._createBackground;
+ UnlockDialog.prototype._updateBackgroundEffects =
+ this._updateBackgroundEffects;
+ UnlockDialog.prototype._updateBackgrounds =
+ this._updateBackgrounds;
+ }
+
+ _createBackground(monitor_index) {
+ let pipeline = new Pipeline(
+ global.blur_my_shell._effects_manager, global.blur_my_shell._pipelines_manager,
+ global.blur_my_shell._settings.lockscreen.PIPELINE
+ );
+
+ pipeline.create_background_with_effects(
+ monitor_index,
+ this._bgManagers,
+ this._backgroundGroup,
+ "screen-shield-background"
+ );
+ }
+
+ _updateBackgroundEffects() {
+ this._updateBackgrounds();
+ }
+
+ _updateBackgrounds() {
+ for (let i = 0; i < this._bgManagers.length; i++) {
+ this._bgManagers[i]._bms_pipeline.destroy();
+ this._bgManagers[i].destroy();
+ }
+
+ this._bgManagers = [];
+ this._backgroundGroup.destroy_all_children();
+
+ for (let i = 0; i < Main.layoutManager.monitors.length; i++)
+ this._createBackground(i);
+ }
+
+ disable() {
+ this._log("removing blur from lockscreen");
+
+ UnlockDialog.prototype._createBackground =
+ original_createBackground;
+ UnlockDialog.prototype._updateBackgroundEffects =
+ original_updateBackgroundEffects;
+ UnlockDialog.prototype._updateBackgrounds =
+ original_updateBackgrounds;
+
+ this.connections.disconnect_all();
+
+ this.enabled = false;
+ }
+
+ _log(str) {
+ if (this.settings.DEBUG)
+ console.log(`[Blur my Shell > lockscreen] ${str}`);
+ }
+};
diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/overview.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/overview.js
new file mode 100644
index 0000000..50a625e
--- /dev/null
+++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/overview.js
@@ -0,0 +1,226 @@
+import Meta from 'gi://Meta';
+import * as Main from 'resource:///org/gnome/shell/ui/main.js';
+
+import { WorkspaceAnimationController } from 'resource:///org/gnome/shell/ui/workspaceAnimation.js';
+const wac_proto = WorkspaceAnimationController.prototype;
+
+import { Pipeline } from '../conveniences/pipeline.js';
+
+const OVERVIEW_COMPONENTS_STYLE = [
+ "overview-components-light",
+ "overview-components-dark",
+ "overview-components-transparent"
+];
+
+
+export const OverviewBlur = class OverviewBlur {
+ constructor(connections, settings, effects_manager) {
+ this.connections = connections;
+ this.settings = settings;
+ this.effects_manager = effects_manager;
+ this.overview_background_managers = [];
+ this.overview_background_group = new Meta.BackgroundGroup(
+ { name: 'bms-overview-backgroundgroup' }
+ );
+ this.animation_background_managers = [];
+ this.animation_background_group = new Meta.BackgroundGroup(
+ { name: 'bms-animation-backgroundgroup' }
+ );
+ this.enabled = false;
+ this.proto_patched = false;
+ }
+
+ enable() {
+ this._log("blurring overview");
+
+ // add css class name for workspace-switch background
+ Main.uiGroup.add_style_class_name("blurred-overview");
+
+ // add css class name to make components semi-transparent if wanted
+ this.update_components_classname();
+
+ // update backgrounds when the component is enabled
+ this.update_backgrounds();
+
+ // connect to monitors change
+ this.connections.connect(Main.layoutManager, 'monitors-changed',
+ _ => this.update_backgrounds()
+ );
+
+ // part for the workspace animation switch
+
+ // make sure not to do this part if the functions were patched prior, as
+ // the functions would call themselves and cause infinite recursion
+ if (!this.proto_patched) {
+ // store original workspace switching methods for restoring them on
+ // disable()
+ this._original_PrepareSwitch = wac_proto._prepareWorkspaceSwitch;
+ this._original_FinishSwitch = wac_proto._finishWorkspaceSwitch;
+
+ const w_m = global.workspace_manager;
+ const outer_this = this;
+
+ // create a blurred background actor for each monitor during a
+ // workspace switch
+ wac_proto._prepareWorkspaceSwitch = function (...params) {
+ outer_this._log("prepare workspace switch");
+ outer_this._original_PrepareSwitch.apply(this, params);
+
+ // this permits to show the blur behind windows that are on
+ // workspaces on the left and right
+ if (
+ outer_this.settings.applications.BLUR
+ ) {
+ let ws_index = w_m.get_active_workspace_index();
+ [ws_index - 1, ws_index + 1].forEach(
+ i => w_m.get_workspace_by_index(i)?.list_windows().forEach(
+ window => window.get_compositor_private().show()
+ )
+ );
+ }
+
+ Main.uiGroup.insert_child_above(
+ outer_this.animation_background_group,
+ global.window_group
+ );
+
+ outer_this.animation_background_managers.forEach(bg_manager => {
+ if (bg_manager._bms_pipeline.actor)
+ if (
+ Meta.prefs_get_workspaces_only_on_primary() &&
+ bg_manager._monitorIndex !== Main.layoutManager.primaryMonitor.index
+ )
+ bg_manager._bms_pipeline.actor.visible = false;
+ else
+ bg_manager._bms_pipeline.actor.visible = true;
+ });
+ };
+
+ // remove the workspace-switch actors when the switch is done
+ wac_proto._finishWorkspaceSwitch = function (...params) {
+ outer_this._log("finish workspace switch");
+ outer_this._original_FinishSwitch.apply(this, params);
+
+ // this hides windows that are not on the current workspace
+ if (
+ outer_this.settings.applications.BLUR
+ )
+ for (let i = 0; i < w_m.get_n_workspaces(); i++) {
+ if (i != w_m.get_active_workspace_index())
+ w_m.get_workspace_by_index(i)?.list_windows().forEach(
+ window => window.get_compositor_private().hide()
+ );
+ }
+
+ Main.uiGroup.remove_child(outer_this.animation_background_group);
+ };
+
+ this.proto_patched = true;
+ }
+
+ this.enabled = true;
+ }
+
+ update_backgrounds() {
+ // remove every old background
+ this.remove_background_actors();
+ // create new backgrounds for the overview and the animation
+ for (let i = 0; i < Main.layoutManager.monitors.length; i++) {
+ const pipeline_overview = new Pipeline(
+ this.effects_manager,
+ global.blur_my_shell._pipelines_manager,
+ this.settings.overview.PIPELINE
+ );
+ pipeline_overview.create_background_with_effects(
+ i, this.overview_background_managers,
+ this.overview_background_group, 'bms-overview-blurred-widget'
+ );
+
+ const pipeline_animation = new Pipeline(
+ this.effects_manager,
+ global.blur_my_shell._pipelines_manager,
+ this.settings.overview.PIPELINE
+ );
+ pipeline_animation.create_background_with_effects(
+ i, this.animation_background_managers,
+ this.animation_background_group, 'bms-animation-blurred-widget'
+ );
+ }
+ // add the container widget for the overview only to the overview group
+ Main.layoutManager.overviewGroup.insert_child_at_index(this.overview_background_group, 0);
+ // make sure it stays below
+ this.connections.connect(Main.layoutManager.overviewGroup, "child-added", (_, child) => {
+ if (child !== this.overview_background_group) {
+ if (this.overview_background_group.get_parent())
+ Main.layoutManager.overviewGroup.remove_child(this.overview_background_group);
+ Main.layoutManager.overviewGroup.insert_child_at_index(this.overview_background_group, 0);
+ }
+ });
+ }
+
+ /// Updates the classname to style overview components with semi-transparent
+ /// backgrounds.
+ update_components_classname() {
+ OVERVIEW_COMPONENTS_STYLE.forEach(
+ style => Main.uiGroup.remove_style_class_name(style)
+ );
+
+ if (this.settings.overview.STYLE_COMPONENTS > 0)
+ Main.uiGroup.add_style_class_name(
+ OVERVIEW_COMPONENTS_STYLE[this.settings.overview.STYLE_COMPONENTS - 1]
+ );
+ }
+
+ remove_background_actors() {
+ this.overview_background_group.remove_all_children();
+ this.animation_background_group.remove_all_children();
+
+ this.connections.disconnect_all_for(Main.layoutManager.overviewGroup);
+ if (this.overview_background_group.get_parent())
+ Main.layoutManager.overviewGroup.remove_child(this.overview_background_group);
+
+ this.overview_background_managers.forEach(background_manager => {
+ background_manager._bms_pipeline.destroy();
+ background_manager.destroy();
+ });
+ this.animation_background_managers.forEach(background_manager => {
+ background_manager._bms_pipeline.destroy();
+ background_manager.destroy();
+ });
+ this.overview_background_managers = [];
+ this.animation_background_managers = [];
+ }
+
+ disable() {
+ this._log("removing blur from overview");
+
+ this.remove_background_actors();
+ Main.uiGroup.remove_style_class_name("blurred-overview");
+ OVERVIEW_COMPONENTS_STYLE.forEach(
+ style => Main.uiGroup.remove_style_class_name(style)
+ );
+
+ this.connections.disconnect_all();
+ this.enabled = false;
+ }
+
+ restore_patched_proto() {
+ if (this.proto_patched) {
+ if (this._original_PrepareSwitch)
+ wac_proto._prepareWorkspaceSwitch = this._original_PrepareSwitch;
+ if (this._original_FinishSwitch)
+ wac_proto._finishWorkspaceSwitch = this._original_FinishSwitch;
+
+ this.proto_patched = false;
+ }
+ }
+
+ _log(str) {
+ if (this.settings.DEBUG)
+ console.log(`[Blur my Shell > overview] ${str}`);
+ }
+
+ _warn(str) {
+ console.warn(`[Blur my Shell > overview] ${str}`);
+ }
+};
diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/panel.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/panel.js
new file mode 100644
index 0000000..6c084cf
--- /dev/null
+++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/panel.js
@@ -0,0 +1,577 @@
+import St from 'gi://St';
+import GLib from 'gi://GLib';
+import Meta from 'gi://Meta';
+import * as Main from 'resource:///org/gnome/shell/ui/main.js';
+
+import { PaintSignals } from '../conveniences/paint_signals.js';
+
+import { Pipeline } from '../conveniences/pipeline.js';
+import { DummyPipeline } from '../conveniences/dummy_pipeline.js';
+
+const DASH_TO_PANEL_UUID = 'dash-to-panel@jderose9.github.com';
+const PANEL_STYLES = [
+ "transparent-panel",
+ "light-panel",
+ "dark-panel",
+ "contrasted-panel"
+];
+
+// global listener, so we don't miss the panel destruction event
+let isMainPanelAlive = true;
+Main.panel.connect('destroy', () => isMainPanelAlive = false);
+
+export const PanelBlur = class PanelBlur {
+ constructor(connections, settings, effects_manager) {
+ this.connections = connections;
+ this.window_signal_ids = new Map();
+ this.settings = settings;
+ this.effects_manager = effects_manager;
+ this.actors_list = [];
+ this.enabled = false;
+ }
+
+ enable() {
+ if (this.enabled) {
+ this._log("blur already enabled");
+ return;
+ }
+
+ this._log("blurring top panel");
+
+ // check for panels when Dash to Panel is activated
+ this.connections.connect(
+ Main.extensionManager,
+ 'extension-state-changed',
+ (_, extension) => {
+ if (extension.uuid === DASH_TO_PANEL_UUID
+ && extension.state === 1
+ ) {
+ this.connections.connect(
+ global.dashToPanel,
+ 'panels-created',
+ _ => this.blur_dtp_panels()
+ );
+
+ this.blur_existing_panels();
+ }
+ }
+ );
+
+ this.blur_existing_panels();
+
+ // connect to overview being opened/closed, and dynamically show or not
+ // the blur when a window is near a panel
+ this.connect_to_windows_and_overview();
+
+ // connect to workareas change
+ this.connections.connect(global.display, 'workareas-changed',
+ _ => this.reset()
+ );
+
+ this.enabled = true;
+ }
+
+ reset() {
+ if (!this.enabled) {
+ this._log("reset called but blur is not enabled");
+ return;
+ }
+
+ this._log("resetting...");
+
+ this.disable();
+ setTimeout(_ => this.enable(), 1);
+ }
+
+ /// Check for already existing panels and blur them if they are not already
+ blur_existing_panels() {
+ // check if dash-to-panel is present
+ if (global.dashToPanel) {
+ // blur already existing ones
+ if (global.dashToPanel.panels)
+ this.blur_dtp_panels();
+
+ // blur main panel if requested in settings
+ if (this.settings.dash_to_panel.BLUR_ORIGINAL_PANEL && isMainPanelAlive)
+ this.maybe_blur_panel(Main.panel);
+ } else {
+ // if no dash-to-panel, blur the main and only panel
+ this.maybe_blur_panel(Main.panel);
+ }
+ }
+
+ blur_dtp_panels() {
+ // Defer the blurring to the next idle cycle.
+ // This is crucial to ensure the panel actors have been allocated their
+ // final size and position by the compositor, avoiding race conditions
+ // during extension startup.
+ GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
+ if (!global.dashToPanel?.panels) {
+ return GLib.SOURCE_REMOVE;
+ }
+
+ this._log("Blurring Dash to Panel panels after idle.");
+
+ // blur every panel, except Main.panel (this is handled in blur_existing_panels() method above)
+ global.dashToPanel.panels.forEach(p => {
+ if (p.panel != Main.panel)
+ this.maybe_blur_panel(p.panel);
+ });
+
+ return GLib.SOURCE_REMOVE;
+ });
+ };
+
+ /// Blur a panel only if it is not already blurred (contained in the list)
+ maybe_blur_panel(panel) {
+ // check if the panel is contained in the list
+ let actors = this.actors_list.find(
+ actors => actors.widgets.panel == panel
+ );
+
+ if (!actors)
+ // if the actors is not blurred, blur it
+ this.blur_panel(panel);
+ }
+
+ /// Blur a panel
+ blur_panel(panel) {
+ let panel_box = panel.get_parent();
+ let is_dtp_panel = false;
+ if (!panel_box.name) {
+ is_dtp_panel = true;
+ panel_box = panel_box.get_parent();
+ }
+
+ let monitor = Main.layoutManager.findMonitorForActor(panel);
+ if (!monitor)
+ return;
+
+ let background_group = new Meta.BackgroundGroup(
+ { name: 'bms-panel-backgroundgroup', width: 0, height: 0 }
+ );
+
+ let background, bg_manager;
+ let static_blur = this.settings.panel.STATIC_BLUR;
+ if (static_blur) {
+ let bg_manager_list = [];
+ const pipeline = new Pipeline(
+ this.effects_manager,
+ global.blur_my_shell._pipelines_manager,
+ this.settings.panel.PIPELINE
+ );
+ background = pipeline.create_background_with_effects(
+ monitor.index, bg_manager_list,
+ background_group, 'bms-panel-blurred-widget'
+ );
+ bg_manager = bg_manager_list[0];
+ }
+ else {
+ const pipeline = new DummyPipeline(this.effects_manager, this.settings.panel);
+ [background, bg_manager] = pipeline.create_background_with_effect(
+ background_group, 'bms-panel-blurred-widget'
+ );
+
+ let paint_signals = new PaintSignals(this.connections);
+
+ // HACK
+ //
+ //`Shell.BlurEffect` does not repaint when shadows are under it. [1]
+ //
+ // This does not entirely fix this bug (shadows caused by windows
+ // still cause artifacts), but it prevents the shadows of the panel
+ // buttons to cause artifacts on the panel itself
+ //
+ // [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857
+
+ {
+ if (this.settings.HACKS_LEVEL === 1) {
+ this._log("panel hack level 1");
+
+ paint_signals.disconnect_all();
+ paint_signals.connect(background, pipeline.effect);
+ } else {
+ paint_signals.disconnect_all();
+ }
+ }
+ }
+
+ // insert the background group to the panel box
+ panel_box.insert_child_at_index(background_group, 0);
+
+ // the object that is used to remembering each elements that is linked to the blur effect
+ let actors = {
+ widgets: { panel, panel_box, background, background_group },
+ static_blur,
+ monitor,
+ bg_manager,
+ is_dtp_panel
+ };
+ this.actors_list.push(actors);
+
+ // update the size of the actor
+ this.update_size(actors);
+
+ // connect to panel, panel_box and its parent position or size change
+ // this should fire update_size every time one of its params change
+ this.connections.connect(
+ panel,
+ 'notify::position',
+ _ => this.update_size(actors)
+ );
+ this.connections.connect(
+ panel_box,
+ ['notify::size', 'notify::position'],
+ _ => this.update_size(actors)
+ );
+ this.connections.connect(
+ panel_box.get_parent(),
+ 'notify::position',
+ _ => this.update_size(actors)
+ );
+
+ // connect to the panel getting destroyed
+ this.connections.connect(
+ panel,
+ 'destroy',
+ _ => this.destroy_blur(actors, true)
+ );
+ }
+
+ update_size(actors) {
+ let panel = actors.widgets.panel;
+ let panel_box = actors.widgets.panel_box;
+ let background = actors.widgets.background;
+ let [width, height] = panel_box.get_size();
+
+ // if static blur, need to clip the background
+ if (actors.static_blur) {
+ let monitor = Main.layoutManager.findMonitorForActor(panel);
+ if (!monitor)
+ return;
+
+ // an alternative to panel.get_transformed_position, because it
+ // sometimes yields NaN (probably when the actor is not fully
+ // positionned yet)
+ let [p_x, p_y] = panel_box.get_position();
+ let [p_p_x, p_p_y] = panel_box.get_parent().get_position();
+ let x = p_x + p_p_x - monitor.x + (width - panel.width) / 2;
+ let y = p_y + p_p_y - monitor.y + (height - panel.height) / 2;
+
+ background.set_clip(x, y, panel.width, panel.height);
+ background.x = (width - panel.width) / 2 - x;
+ background.y = .5 + (height - panel.height) / 2 - y;
+ } else {
+ background.x = panel.x;
+ background.y = panel.y;
+ background.width = panel.width;
+ background.height = panel.height;
+ }
+
+ // update the monitor panel is on
+ actors.monitor = Main.layoutManager.findMonitorForActor(panel);
+ }
+
+ /// Connect when overview if opened/closed to hide/show the blur accordingly
+ ///
+ /// If HIDETOPBAR is set, we need just to hide the blur when showing appgrid
+ /// (so no shadow is cropped)
+ connect_to_overview() {
+ // may be called when panel blur is disabled, if hidetopbar
+ // compatibility is toggled on/off
+ // if this is the case, do nothing as only the panel blur interfers with
+ // hidetopbar
+ if (
+ this.settings.panel.BLUR &&
+ this.settings.panel.UNBLUR_IN_OVERVIEW
+ ) {
+ if (!this.settings.hidetopbar.COMPATIBILITY) {
+ this.connections.connect(
+ Main.overview, 'showing', _ => this.hide()
+ );
+ this.connections.connect(
+ Main.overview, 'hidden', _ => this.show()
+ );
+ } else {
+ let appDisplay = Main.overview._overview._controls._appDisplay;
+
+ this.connections.connect(
+ appDisplay, 'show', _ => this.hide()
+ );
+ this.connections.connect(
+ appDisplay, 'hide', _ => this.show()
+ );
+ this.connections.connect(
+ Main.overview, 'hidden', _ => this.show()
+ );
+ }
+
+ }
+ }
+
+ /// Connect to windows disable transparency when a window is too close
+ connect_to_windows() {
+ if (
+ this.settings.panel.OVERRIDE_BACKGROUND_DYNAMICALLY
+ ) {
+ // connect to overview opening/closing
+ this.connections.connect(Main.overview, ['showing', 'hiding'],
+ _ => this.update_visibility()
+ );
+
+ // connect to session mode update
+ this.connections.connect(Main.sessionMode, 'updated',
+ _ => this.update_visibility()
+ );
+
+ // manage already-existing windows
+ for (const meta_window_actor of global.get_window_actors()) {
+ this.on_window_actor_added(
+ meta_window_actor.get_parent(), meta_window_actor
+ );
+ }
+
+ // manage windows at their creation/removal
+ this.connections.connect(global.window_group, 'child-added',
+ this.on_window_actor_added.bind(this)
+ );
+ this.connections.connect(global.window_group, 'child-removed',
+ this.on_window_actor_removed.bind(this)
+ );
+
+ // connect to a workspace change
+ this.connections.connect(global.window_manager, 'switch-workspace',
+ _ => this.update_visibility()
+ );
+
+ // perform early update
+ this.update_visibility();
+ } else {
+ // reset transparency for every panels
+ this.actors_list.forEach(
+ actors => this.set_should_override_panel(actors, true)
+ );
+ }
+ }
+
+ /// An helper to connect to both the windows and overview signals.
+ /// This is the only function that should be directly called, to prevent
+ /// inconsistencies with signals not being disconnected.
+ connect_to_windows_and_overview() {
+ this.disconnect_from_windows_and_overview();
+ this.connect_to_overview();
+ this.connect_to_windows();
+ }
+
+ /// Disconnect all the connections created by connect_to_windows
+ disconnect_from_windows_and_overview() {
+ // disconnect the connections to actors
+ for (const actor of [
+ Main.overview, Main.sessionMode,
+ global.window_group, global.window_manager,
+ Main.overview._overview._controls._appDisplay
+ ]) {
+ this.connections.disconnect_all_for(actor);
+ }
+
+ // disconnect the connections from windows
+ for (const [actor, ids] of this.window_signal_ids) {
+ for (const id of ids) {
+ actor.disconnect(id);
+ }
+ }
+ this.window_signal_ids = new Map();
+ }
+
+ /// Update the css classname of the panel for light theme
+ update_light_text_classname(disable = false) {
+ if (!isMainPanelAlive) {
+ this._log("cannot update light text classname, Main.panel is not alive");
+ return;
+ }
+
+ if (this.settings.panel.FORCE_LIGHT_TEXT && !disable)
+ Main.panel.add_style_class_name("panel-light-text");
+ else
+ Main.panel.remove_style_class_name("panel-light-text");
+ }
+
+ /// Callback when a new window is added
+ on_window_actor_added(container, meta_window_actor) {
+ this.window_signal_ids.set(meta_window_actor, [
+ meta_window_actor.connect('notify::allocation',
+ _ => this.update_visibility()
+ ),
+ meta_window_actor.connect('notify::visible',
+ _ => this.update_visibility()
+ )
+ ]);
+ this.update_visibility();
+ }
+
+ /// Callback when a window is removed
+ on_window_actor_removed(container, meta_window_actor) {
+ for (const signalId of this.window_signal_ids.get(meta_window_actor)) {
+ meta_window_actor.disconnect(signalId);
+ }
+ this.window_signal_ids.delete(meta_window_actor);
+ this.update_visibility();
+ }
+
+ /// Update the visibility of the blur effect
+ update_visibility() {
+ if (
+ isMainPanelAlive && Main.panel.has_style_pseudo_class('overview')
+ || !Main.sessionMode.hasWindows
+ ) {
+ this.actors_list.forEach(
+ actors => this.set_should_override_panel(actors, true)
+ );
+ return;
+ }
+
+ if (!Main.layoutManager.primaryMonitor)
+ return;
+
+ // get all the windows in the active workspace that are visible
+ const workspace = global.workspace_manager.get_active_workspace();
+ const windows = workspace.list_windows().filter(meta_window =>
+ meta_window.showing_on_its_workspace()
+ && !meta_window.is_hidden()
+ && meta_window.get_window_type() !== Meta.WindowType.DESKTOP
+ // exclude Desktop Icons NG
+ && meta_window.get_gtk_application_id() !== "com.rastersoft.ding"
+ && meta_window.get_gtk_application_id() !== "com.desktop.ding"
+ );
+
+ // check if at least one window is near enough to each panel and act
+ // accordingly
+ const scale = St.ThemeContext.get_for_stage(global.stage).scale_factor;
+ this.actors_list
+ // do not apply for dtp panels, as it would only cause bugs and it
+ // can be done from its preferences anyway
+ .filter(actors => !actors.is_dtp_panel)
+ .forEach(actors => {
+ let panel = actors.widgets.panel;
+ let panel_top = panel.get_transformed_position()[1];
+ let panel_bottom = panel_top + panel.get_height();
+
+ // check if at least a window is near enough the panel
+ let window_overlap_panel = false;
+ windows.forEach(meta_window => {
+ let window_monitor_i = meta_window.get_monitor();
+ let same_monitor = actors.monitor.index == window_monitor_i;
+
+ let window_vertical_pos = meta_window.get_frame_rect().y;
+ let window_vertical_bottom = window_vertical_pos + meta_window.get_frame_rect().height;
+
+ // if so, and if in the same monitor, then it overlaps
+ if (same_monitor
+ &&
+ // check if panel is on top
+ ((panel_top === 0 && window_vertical_pos < panel_bottom + 5 * scale) ||
+ // check if panel is at the bottom
+ (panel_top > 0 && window_vertical_bottom > panel_top - 5 * scale))
+ )
+ window_overlap_panel = true;
+ });
+
+ // if no window overlaps, then the panel is transparent
+ this.set_should_override_panel(
+ actors, !window_overlap_panel
+ );
+ });
+ }
+
+ /// Choose wether or not the panel background should be overriden, in
+ /// respect to its argument and the `override-background` setting.
+ set_should_override_panel(actors, should_override) {
+ let panel = actors.widgets.panel;
+
+ PANEL_STYLES.forEach(style => panel.remove_style_class_name(style));
+
+ if (
+ this.settings.panel.OVERRIDE_BACKGROUND
+ &&
+ should_override
+ ) {
+ panel.add_style_class_name(
+ PANEL_STYLES[this.settings.panel.STYLE_PANEL]
+ );
+ }
+
+ // update the classname if the panel to have or have not light text
+ this.update_light_text_classname(!should_override);
+ }
+
+ update_pipeline() {
+ this.actors_list.forEach(actors =>
+ actors.bg_manager._bms_pipeline.change_pipeline_to(
+ this.settings.panel.PIPELINE
+ )
+ );
+ }
+
+ show() {
+ this.actors_list.forEach(actors => {
+ actors.widgets.background.show();
+ });
+ }
+
+ hide() {
+ this.actors_list.forEach(actors => {
+ actors.widgets.background.hide();
+ });
+ }
+
+ // IMPORTANT: do never call this in a mutable `this.actors_list.forEach`
+ destroy_blur(actors, panel_already_destroyed) {
+ this.set_should_override_panel(actors, false);
+
+ actors.bg_manager._bms_pipeline.destroy();
+
+ if (panel_already_destroyed)
+ actors.bg_manager.backgroundActor = null;
+ actors.bg_manager.destroy();
+
+ if (!panel_already_destroyed) {
+ actors.widgets.panel_box.remove_child(actors.widgets.background_group);
+ actors.widgets.background_group.destroy_all_children();
+ actors.widgets.background_group.destroy();
+ }
+
+ let index = this.actors_list.indexOf(actors);
+ if (index >= 0)
+ this.actors_list.splice(index, 1);
+ }
+
+ disable() {
+ if (!this.enabled) {
+ this._log("blur already removed");
+ return;
+ }
+
+ this._log("removing blur from top panel");
+
+ this.disconnect_from_windows_and_overview();
+
+ this.update_light_text_classname(true);
+
+ const immutable_actors_list = [...this.actors_list];
+ immutable_actors_list.forEach(actors => this.destroy_blur(actors, false));
+ this.actors_list = [];
+
+ this.connections.disconnect_all();
+
+ this.enabled = false;
+ }
+
+ _log(str) {
+ if (this.settings.DEBUG)
+ console.log(`[Blur my Shell > panel] ${str}`);
+ }
+
+ _warn(str) {
+ console.warn(`[Blur my Shell > panel] ${str}`);
+ }
+};
diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/screenshot.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/screenshot.js
new file mode 100644
index 0000000..dcf05eb
--- /dev/null
+++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/screenshot.js
@@ -0,0 +1,110 @@
+import * as Main from 'resource:///org/gnome/shell/ui/main.js';
+
+import { Pipeline } from '../conveniences/pipeline.js';
+
+export const ScreenshotBlur = class ScreenshotBlur {
+ constructor(connections, settings, effects_manager) {
+ this.connections = connections;
+ this.settings = settings;
+ this.screenshot_background_managers = [];
+ this.effects_manager = effects_manager;
+ }
+
+ enable() {
+ this._log("blurring screenshot's window selector");
+
+ // connect to monitors change
+ this.connections.connect(Main.layoutManager, 'monitors-changed',
+ _ => this.update_backgrounds()
+ );
+
+ // update backgrounds when the component is enabled
+ this.update_backgrounds();
+ }
+
+ update_backgrounds() {
+ // remove every old background
+ this.remove_background_actors();
+ // create new backgrounds for the screenshot window selector
+ for (let i = 0; i < Main.screenshotUI._windowSelectors.length; i++) {
+ const window_selector = Main.screenshotUI._windowSelectors[i];
+ const pipeline = new Pipeline(
+ this.effects_manager,
+ global.blur_my_shell._pipelines_manager,
+ this.settings.screenshot.PIPELINE
+ );
+ pipeline.create_background_with_effects(
+ window_selector._monitorIndex, this.screenshot_background_managers,
+ window_selector, 'bms-screenshot-blurred-widget', false
+ );
+
+ // prevent old `BackgroundActor` from being accessed, which creates a whole bug of logs
+ this.connections.connect(window_selector.get_parent(), 'destroy', _ => {
+ this.screenshot_background_managers.forEach(background_manager => {
+ if (background_manager.backgroundActor) {
+ let widget = background_manager.backgroundActor.get_parent();
+ let parent = widget?.get_parent();
+
+ if (parent == window_selector) {
+ background_manager._bms_pipeline.destroy();
+ parent.remove_child(widget);
+ }
+ }
+ background_manager.destroy();
+ });
+
+ window_selector.get_children().forEach(child => {
+ if (child.get_name() == 'bms-screenshot-blurred-widget')
+ window_selector.remove_child(child);
+ });
+
+ let index = this.screenshot_background_managers.indexOf(window_selector);
+ this.screenshot_background_managers.splice(index, 1);
+ });
+ }
+ }
+
+ update_pipeline() {
+ this.screenshot_background_managers.forEach(background_manager =>
+ background_manager._bms_pipeline.change_pipeline_to(
+ this.settings.screenshot.PIPELINE
+ )
+ );
+ }
+
+ remove_background_actors() {
+ this.screenshot_background_managers.forEach(background_manager => {
+ background_manager._bms_pipeline.destroy();
+ if (background_manager.backgroundActor) {
+ let widget = background_manager.backgroundActor.get_parent();
+ widget?.get_parent()?.remove_child(widget);
+ }
+ background_manager.destroy();
+ });
+
+ Main.screenshotUI._windowSelectors.forEach(window_selector =>
+ window_selector.get_children().forEach(child => {
+ if (child.get_name() == 'bms-screenshot-blurred-widget')
+ window_selector.remove_child(child);
+ })
+ );
+
+ this.screenshot_background_managers = [];
+ }
+
+ disable() {
+ this._log("removing blur from screenshot's window selector");
+
+ this.remove_background_actors();
+ this.connections.disconnect_all();
+ }
+
+ _log(str) {
+ if (this.settings.DEBUG)
+ console.log(`[Blur my Shell > screenshot] ${str}`);
+ }
+
+ _warn(str) {
+ console.warn(`[Blur my Shell > screenshot] ${str}`);
+ }
+};
diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/window_list.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/window_list.js
new file mode 100644
index 0000000..6ab0644
--- /dev/null
+++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/window_list.js
@@ -0,0 +1,148 @@
+import * as Main from 'resource:///org/gnome/shell/ui/main.js';
+
+import { PaintSignals } from '../conveniences/paint_signals.js';
+import { DummyPipeline } from '../conveniences/dummy_pipeline.js';
+
+
+export const WindowListBlur = class WindowListBlur {
+ constructor(connections, settings, effects_manager) {
+ this.connections = connections;
+ this.settings = settings;
+ this.paint_signals = new PaintSignals(connections);
+ this.effects_manager = effects_manager;
+ this.pipelines = [];
+ }
+
+ enable() {
+ this._log("blurring window list");
+
+ // blur if window-list is found
+ Main.layoutManager.uiGroup.get_children().forEach(
+ child => this.try_blur(child)
+ );
+
+ // listen to new actors in `Main.layoutManager.uiGroup` and blur it if
+ // if is window-list
+ this.connections.connect(
+ Main.layoutManager.uiGroup,
+ 'child-added',
+ (_, child) => this.try_blur(child)
+ );
+
+ // connect to overview
+ this.connections.connect(Main.overview, 'showing', _ => {
+ this.hide();
+ });
+ this.connections.connect(Main.overview, 'hidden', _ => {
+ this.show();
+ });
+ }
+
+ try_blur(actor) {
+ if (
+ actor.constructor.name === "WindowList" &&
+ actor.style !== "background:transparent;"
+ ) {
+ this._log("found window list to blur");
+
+ const pipeline = new DummyPipeline(
+ this.effects_manager, this.settings.window_list
+ );
+ pipeline.attach_effect_to_actor(actor);
+ this.pipelines.push(pipeline);
+
+ actor.set_style("background:transparent;");
+
+ actor._windowList.get_children().forEach(
+ window => this.style_window_button(window)
+ );
+
+ this.connections.connect(
+ actor._windowList,
+ 'child-added',
+ (_, window) => this.style_window_button(window)
+ );
+
+ this.connections.connect(
+ actor,
+ 'destroy',
+ _ => this.destroy_blur(pipeline, true)
+ );
+
+
+ // HACK
+ //
+ //`Shell.BlurEffect` does not repaint when shadows are under it. [1]
+ //
+ // This does not entirely fix this bug (shadows caused by windows
+ // still cause artifacts), but it prevents the shadows of the panel
+ // buttons to cause artifacts on the panel itself
+ //
+ // [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857
+
+ if (this.settings.HACKS_LEVEL === 1) {
+ this._log("window list hack level 1");
+
+ this.paint_signals.disconnect_all_for_actor(actor);
+ this.paint_signals.connect(actor, pipeline.effect);
+ } else {
+ this.paint_signals.disconnect_all_for_actor(actor);
+ }
+ }
+ }
+
+ style_window_button(window) {
+ window.get_child_at_index(0).set_style(
+ "box-shadow:none; background-color:rgba(0,0,0,0.2); border-radius:5px;"
+ );
+ }
+
+ // IMPORTANT: do never call this in a mutable `this.pipelines.forEach`
+ destroy_blur(pipeline, actor_destroyed = false) {
+ if (!actor_destroyed) {
+ this.remove_style(pipeline.actor);
+ this.paint_signals.disconnect_all_for_actor(pipeline.actor);
+ }
+
+ pipeline.destroy();
+
+ let index = this.pipelines.indexOf(pipeline);
+ if (index >= 0)
+ this.pipelines.splice(pipeline, 1);
+ }
+
+ remove_style(actor) {
+ if (
+ actor.constructor.name === "WindowList" &&
+ actor.style === "background:transparent;"
+ ) {
+ actor.style = null;
+ actor._windowList.get_children().forEach(
+ child => child.get_child_at_index(0).set_style(null)
+ );
+ }
+ }
+
+ hide() {
+ this.pipelines.forEach(pipeline => pipeline.effect?.set_enabled(false));
+ }
+
+ show() {
+ this.pipelines.forEach(pipeline => pipeline.effect?.set_enabled(true));
+ }
+
+ disable() {
+ this._log("removing blur from window list");
+
+ const immutable_pipelines_list = [...this.pipelines];
+ immutable_pipelines_list.forEach(pipeline => this.destroy_blur(pipeline));
+
+ this.pipelines = [];
+ this.connections.disconnect_all();
+ }
+
+ _log(str) {
+ if (this.settings.DEBUG)
+ console.log(`[Blur my Shell > window list] ${str}`);
+ }
+}; \ No newline at end of file