[gnome] Update extensions

This commit is contained in:
2024-10-31 10:19:02 -04:00
parent 851ec4a772
commit 6d1e6d1132
238 changed files with 8705 additions and 4185 deletions

View File

@ -1,11 +1,22 @@
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 '../effects/paint_signals.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;
const transparent = Clutter.Color.from_pixel(0x00000000);
// 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 = [
@ -43,7 +54,7 @@ let _zoomAndFadeIn = function () {
{
radius: sigma * 2,
brightness: brightness,
time: FOLDER_DIALOG_ANIMATION_TIME / 1000,
time: adjustAnimationTime(FOLDER_DIALOG_ANIMATION_TIME / 1000),
transition: 'easeOutQuad'
}
);
@ -87,7 +98,7 @@ let _zoomAndFadeOut = function () {
{
radius: 0,
brightness: 1.0,
time: FOLDER_DIALOG_ANIMATION_TIME / 1000,
time: adjustAnimationTime(FOLDER_DIALOG_ANIMATION_TIME / 1000),
transition: 'easeInQuad'
}
);
@ -120,6 +131,8 @@ let _zoomAndFadeOut = function () {
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);
@ -129,12 +142,8 @@ export const AppFoldersBlur = class AppFoldersBlur {
enable() {
this._log("blurring appfolders");
brightness = this.settings.appfolder.CUSTOMIZE
? this.settings.appfolder.BRIGHTNESS
: this.settings.BRIGHTNESS;
sigma = this.settings.appfolder.CUSTOMIZE
? this.settings.appfolder.SIGMA
: this.settings.SIGMA;
brightness = this.settings.appfolder.BRIGHTNESS;
sigma = this.settings.appfolder.SIGMA;
let appDisplay = Main.overview._overview.controls._appDisplay;
@ -143,15 +152,15 @@ export const AppFoldersBlur = class AppFoldersBlur {
}
this.connections.connect(
appDisplay, 'view-loaded', this.blur_appfolders.bind(this)
appDisplay, 'view-loaded', _ => this.blur_appfolders()
);
}
blur_appfolders() {
let appDisplay = Main.overview._overview.controls._appDisplay;
if (this.settings.HACKS_LEVEL === 1 || this.settings.HACKS_LEVEL === 2)
this._log(`appfolders hack level ${this.settings.HACKS_LEVEL}`);
if (this.settings.HACKS_LEVEL === 1)
this._log("appfolders hack level 1");
appDisplay._folderIcons.forEach(icon => {
icon._ensureFolderDialog();
@ -197,7 +206,7 @@ export const AppFoldersBlur = class AppFoldersBlur {
//
// [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857
if (this.settings.HACKS_LEVEL === 1 || this.settings.HACKS_LEVEL === 2) {
if (this.settings.HACKS_LEVEL === 1) {
this.paint_signals.disconnect_all_for_actor(icon._dialog);
this.paint_signals.connect(icon._dialog, blur_effect);
} else {
@ -218,11 +227,6 @@ export const AppFoldersBlur = class AppFoldersBlur {
this.blur_appfolders();
}
// not implemented for dynamic blur
set_color(c) { }
set_noise_amount(n) { }
set_noise_lightness(l) { }
disable() {
this._log("removing blur from appfolders");

View File

@ -1,24 +1,20 @@
import Shell from 'gi://Shell';
import Clutter from 'gi://Clutter';
import Meta from 'gi://Meta';
import Gio from 'gi://Gio';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import { PaintSignals } from '../effects/paint_signals.js';
import { ApplicationsService } from '../dbus/services.js';
import { PaintSignals } from '../conveniences/paint_signals.js';
import { DummyPipeline } from '../conveniences/dummy_pipeline.js';
export const ApplicationsBlur = class ApplicationsBlur {
constructor(connections, settings, _) {
constructor(connections, settings, effects_manager) {
this.connections = connections;
this.settings = settings;
this.effects_manager = effects_manager;
this.paint_signals = new PaintSignals(connections);
this.mutter_gsettings = new Gio.Settings({ schema: 'org.gnome.mutter' });
// stores every blurred window
this.window_map = new Map();
// stores every blur actor
this.blur_actor_map = new Map();
// stores every blurred meta window
this.meta_window_map = new Map();
}
enable() {
@ -28,6 +24,8 @@ export const ApplicationsBlur = class ApplicationsBlur {
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();
@ -38,16 +36,42 @@ export const ApplicationsBlur = class ApplicationsBlur {
(_meta_display, meta_window) => {
this._log("window created");
if (meta_window) {
let window_actor = meta_window.get_compositor_private();
this.track_new(window_actor, meta_window);
}
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() {
@ -58,9 +82,9 @@ export const ApplicationsBlur = class ApplicationsBlur {
// allows the blur to be shown too)
this.connections.connect(
Main.overview, 'showing',
_ => this.window_map.forEach((meta_window, _pid) => {
_ => this.meta_window_map.forEach((meta_window, _pid) => {
let window_actor = meta_window.get_compositor_private();
window_actor.show();
window_actor?.show();
})
);
@ -69,7 +93,7 @@ export const ApplicationsBlur = class ApplicationsBlur {
this.connections.connect(
Main.overview, 'hidden',
_ => {
this.window_map.forEach((meta_window, _pid) => {
this.meta_window_map.forEach((meta_window, _pid) => {
let window_actor = meta_window.get_compositor_private();
if (
@ -86,7 +110,7 @@ export const ApplicationsBlur = class ApplicationsBlur {
update_all_windows() {
// remove all previously blurred windows, in the case where the
// whitelist was changed
this.window_map.forEach(((_meta_window, pid) => {
this.meta_window_map.forEach(((_meta_window, pid) => {
this.remove_blur(pid);
}));
@ -98,82 +122,81 @@ export const ApplicationsBlur = class ApplicationsBlur {
let workspace = global.workspace_manager.get_workspace_by_index(i);
let windows = workspace.list_windows();
windows.forEach(meta_window => {
let window_actor = meta_window.get_compositor_private();
// disconnect previous signals
this.connections.disconnect_all_for(window_actor);
this.track_new(window_actor, meta_window);
});
windows.forEach(meta_window => this.track_new(meta_window));
}
}
/// Adds the needed signals to every new tracked window, and adds blur if
/// needed.
track_new(window_actor, meta_window) {
let pid = ("" + Math.random()).slice(2, 16);
/// 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;
window_actor['blur_provider_pid'] = pid;
meta_window['blur_provider_pid'] = pid;
this._log(`new window tracked, pid: ${pid}`);
// remove the blur when the window is destroyed
this.connections.connect(window_actor, 'destroy', window_actor => {
let pid = window_actor.blur_provider_pid;
if (this.blur_actor_map.has(pid)) {
this.remove_blur(pid);
}
this.window_map.delete(pid);
});
// register the blurred window
this.meta_window_map.set(pid, meta_window);
// update the blur when mutter-hint or wm-class is changed
for (const prop of ['mutter-hints', 'wm-class']) {
this.connections.connect(
meta_window,
`notify::${prop}`,
_ => {
let pid = meta_window.blur_provider_pid;
this._log(`${prop} changed for pid ${pid}`);
let window_actor = meta_window.get_compositor_private();
this.check_blur(pid, window_actor, 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 position and size when the window size changes
this.connections.connect(meta_window, 'size-changed', () => {
if (this.blur_actor_map.has(pid)) {
let allocation = this.compute_allocation(meta_window);
let blur_actor = this.blur_actor_map.get(pid);
this.connections.connect(
meta_window, 'size-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);
}
/// 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) {
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;
}
});
this.check_blur(pid, window_actor, meta_window);
} 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
/// - has a correct mutter hint, set to `blur-provider=sigma_value`
check_blur(pid, window_actor, meta_window) {
let mutter_hint = meta_window.get_mutter_hints();
let window_wm_class = meta_window.get_wm_class();
check_blur(meta_window) {
const window_wm_class = meta_window.get_wm_class();
const enable_all = this.settings.applications.ENABLE_ALL;
const whitelist = this.settings.applications.WHITELIST;
const blacklist = this.settings.applications.BLACKLIST;
if (window_wm_class)
this._log(`pid ${meta_window.bms_pid} associated to wm class name ${window_wm_class}`);
let enable_all = this.settings.applications.ENABLE_ALL;
let whitelist = this.settings.applications.WHITELIST;
let blacklist = this.settings.applications.BLACKLIST;
this._log(`checking blur for ${pid}`);
// either the window is included in whitelist
if (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 && !blacklist.includes(window_wm_class))
|| (!enable_all && whitelist.includes(window_wm_class))
)
@ -183,209 +206,114 @@ export const ApplicationsBlur = class ApplicationsBlur {
Meta.FrameType.MODAL_DIALOG
].includes(meta_window.get_frame_type())
) {
this._log(`application ${pid} listed, blurring it`);
// get blur effect parameters
let brightness, sigma;
if (this.settings.applications.CUSTOMIZE) {
brightness = this.settings.applications.BRIGHTNESS;
sigma = this.settings.applications.SIGMA;
} else {
brightness = this.settings.BRIGHTNESS;
sigma = this.settings.SIGMA;
}
this.update_blur(pid, window_actor, meta_window, brightness, sigma);
// only blur the window if it is not already done
if (!meta_window.blur_actor)
this.create_blur_effect(meta_window);
}
// or blur is asked by window itself
else if (
mutter_hint != null &&
mutter_hint.includes("blur-provider")
) {
this._log(`application ${pid} has hint ${mutter_hint}, parsing`);
// get blur effect parameters
let [brightness, sigma] = this.parse_xprop(mutter_hint);
this.update_blur(pid, window_actor, meta_window, brightness, sigma);
}
// remove blur if the mutter hint is no longer valid, and the window
// is not explicitly whitelisted or un-blacklisted
else if (this.blur_actor_map.has(pid)) {
this.remove_blur(pid);
}
}
/// When given the xprop property, returns the brightness and sigma values
/// matching. If one of the two values is invalid, or missing, then it uses
/// default values.
///
/// An xprop property is valid if it is in one of the following formats:
///
/// blur-provider=sigma:60,brightness:0.9
/// blur-provider=s:10,brightness:0.492
/// blur-provider=b:1.0,s:16
///
/// Brightness is a floating-point between 0.0 and 1.0 included.
/// Sigma is an integer between 0 and 999 included.
///
/// If sigma is set to 0, then the blur is removed.
/// Setting "default" instead of the two values will make the
/// extension use its default value.
///
/// Note that no space can be inserted.
///
parse_xprop(property) {
// set brightness and sigma to default values
let brightness, sigma;
if (this.settings.applications.CUSTOMIZE) {
brightness = this.settings.applications.BRIGHTNESS;
sigma = this.settings.applications.SIGMA;
} else {
brightness = this.settings.BRIGHTNESS;
sigma = this.settings.SIGMA;
}
// get the argument of the property
let arg = property.match("blur-provider=(.*)");
this._log(`argument = ${arg}`);
// if argument is valid, parse it
if (arg != null) {
// verify if there is only one value: in this case, this is sigma
let maybe_sigma = parseInt(arg[1]);
if (
!isNaN(maybe_sigma) &&
maybe_sigma >= 0 &&
maybe_sigma <= 999
) {
sigma = maybe_sigma;
} else {
// perform pattern matching
let res_b = arg[1].match("(brightness|b):(default|0?1?\.[0-9]*)");
let res_s = arg[1].match("(sigma|s):(default|\\d{1,3})");
// if values are valid and not default, change them to the xprop one
if (
res_b != null && res_b[2] !== 'default'
) {
brightness = parseFloat(res_b[2]);
}
if (
res_s != null && res_s[2] !== 'default'
) {
sigma = parseInt(res_s[2]);
}
}
}
this._log(`brightness = ${brightness}, sigma = ${sigma}`);
return [brightness, sigma];
}
/// Updates the blur on a window which needs to be blurred.
update_blur(pid, window_actor, meta_window, brightness, sigma) {
// the window is already blurred, update its blur effect
if (this.blur_actor_map.has(pid)) {
// window is already blurred, but sigma is null: remove the blur
if (sigma === 0) {
this.remove_blur(pid);
}
// window is already blurred and sigma is non-null: update it
else {
this.update_blur_effect(
this.blur_actor_map.get(pid),
brightness,
sigma
);
}
}
// the window is not blurred, and sigma is a non-null value: blur it
else if (sigma !== 0) {
// window is not blurred, blur it
this.create_blur_effect(
pid,
window_actor,
meta_window,
brightness,
sigma
);
}
// 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.
create_blur_effect(pid, window_actor, meta_window, brightness, sigma) {
let blur_effect = new Shell.BlurEffect({
radius: sigma * 2,
brightness: brightness,
mode: Shell.BlurMode.BACKGROUND
});
/// 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 = this.create_blur_actor(
meta_window,
window_actor,
blur_effect
const pipeline = new DummyPipeline(this.effects_manager, this.settings.applications);
let [blur_actor, bg_manager] = pipeline.create_background_with_effect(
window_actor, 'bms-application-blurred-widget'
);
meta_window.blur_actor = blur_actor;
meta_window.bg_manager = bg_manager;
// if hacks are selected, force to repaint the window
if (this.settings.HACKS_LEVEL === 1 || this.settings.HACKS_LEVEL === 2) {
this._log("applications hack level 1 or 2");
if (this.settings.HACKS_LEVEL === 1) {
this._log("hack level 1");
this.paint_signals.disconnect_all();
this.paint_signals.connect(blur_actor, blur_effect);
this.paint_signals.disconnect_all_for_actor(blur_actor);
this.paint_signals.connect(blur_actor, pipeline.effect);
} else {
this.paint_signals.disconnect_all();
this.paint_signals.disconnect_all_for_actor(blur_actor);
}
// insert the blurred widget
window_actor.insert_child_at_index(blur_actor, 0);
// 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',
_ => this.set_window_opacity(window_actor, this.settings.applications.OPACITY)
window_actor, 'notify::opacity',
_ => {
if (this.focused_window_pid != pid)
this.set_window_opacity(window_actor, this.settings.applications.OPACITY);
}
);
// register the blur actor/effect
blur_actor['blur_provider_pid'] = pid;
this.blur_actor_map.set(pid, blur_actor);
this.window_map.set(pid, meta_window);
// hide the blur if window is invisible
if (!window_actor.visible) {
blur_actor.hide();
}
// hide the blur if window becomes invisible
if (!window_actor.visible)
blur_actor.hide();
this.connections.connect(
window_actor,
'notify::visible',
window_actor => {
let pid = window_actor.blur_provider_pid;
if (window_actor.visible) {
this.blur_actor_map.get(pid).show();
} else {
this.blur_actor_map.get(pid).hide();
}
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
@ -412,12 +340,24 @@ export const ApplicationsBlur = class ApplicationsBlur {
/// 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 => {
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);
}
}));
}
/// Compute the size and position for a blur actor.
/// 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.
@ -442,107 +382,68 @@ export const ApplicationsBlur = class ApplicationsBlur {
};
}
/// Returns a new already blurred widget, configured to follow the size and
/// position of its target window.
create_blur_actor(meta_window, window_actor, blur_effect) {
// compute the size and position
let allocation = this.compute_allocation(meta_window);
// create the actor
let blur_actor = new Clutter.Actor({
x: allocation.x,
y: allocation.y,
width: allocation.width,
height: allocation.height
});
// add the effect
blur_actor.add_effect_with_name('blur-effect', blur_effect);
return blur_actor;
}
/// Updates the blur effect by overwriting its sigma and brightness values.
update_blur_effect(blur_actor, brightness, sigma) {
let effect = blur_actor.get_effect('blur-effect');
effect.radius = sigma * 2;
effect.brightness = brightness;
}
/// Removes the blur actor from the shell and unregister it.
/// 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.window_map.get(pid);
// disconnect needed signals and untrack window
let meta_window = this.meta_window_map.get(pid);
if (meta_window) {
this.window_map.delete(pid);
let window_actor = meta_window.get_compositor_private();
let blur_actor = meta_window.blur_actor;
let bg_manager = meta_window.bg_manager;
let blur_actor = this.blur_actor_map.get(pid);
if (blur_actor) {
this.blur_actor_map.delete(pid);
if (blur_actor && window_actor) {
// reset the opacity
this.set_window_opacity(window_actor, 255);
if (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();
// remove the blurred actor
window_actor.remove_child(blur_actor);
// 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 about overview animation etc
this.connections.disconnect_all_for(window_actor);
}
// 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.blur_actor_map.forEach(((_blur_actor, pid) => {
this.remove_blur(pid);
}));
this.meta_window_map.forEach((_meta_window, pid) => {
this.untrack_meta_window(pid);
});
this.connections.disconnect_all();
this.paint_signals.disconnect_all();
}
/// Update the opacity of all window actors.
set_opacity() {
let opacity = this.settings.applications.OPACITY;
this.window_map.forEach(((meta_window, _pid) => {
let window_actor = meta_window.get_compositor_private();
this.set_window_opacity(window_actor, opacity);
}));
}
/// Updates each blur effect to use new sigma value
// FIXME set_sigma and set_brightness are called when the extension is
// loaded and when sigma is changed, and do not respect the per-app
// xprop behaviour
set_sigma(s) {
this.blur_actor_map.forEach((actor, _) => {
actor.get_effect('blur-effect').set_sigma(s);
});
}
/// Updates each blur effect to use new brightness value
set_brightness(b) {
this.blur_actor_map.forEach((actor, _) => {
actor.get_effect('blur-effect').set_brightness(b);
});
}
// not implemented for dynamic blur
set_color(c) { }
set_noise_amount(n) { }
set_noise_lightness(l) { }
_log(str) {
if (this.settings.DEBUG)
console.log(`[Blur my Shell > applications] ${str}`);

View File

@ -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}`);
}
}
};

View File

@ -1,12 +1,11 @@
import St from 'gi://St';
import Shell from 'gi://Shell';
import Meta from 'gi://Meta';
import Mtk from 'gi://Mtk';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const Signals = imports.signals;
import * as Signals from 'resource:///org/gnome/shell/misc/signals.js';
import { PaintSignals } from '../effects/paint_signals.js';
import { BlurEffect } from '../effects/blur_effect.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",
@ -15,150 +14,65 @@ const DASH_STYLES = [
];
// An helper function to find the monitor in which an actor is situated,
/// there might be a pre-existing function in GLib already
function find_monitor_for(actor) {
let extents = actor.get_transformed_extents();
let rect = new Mtk.Rectangle({
x: extents.get_x(),
y: extents.get_y(),
width: extents.get_width(),
height: extents.get_height(),
});
let index = global.display.get_monitor_index_for_rect(rect);
return Main.layoutManager.monitors[index];
}
/// 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_parent, effect) {
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_container = dash_container;
// the blurred dash
this.dash = dash;
this.dash_container = dash_container;
this.dash_background = dash_background;
this.background_parent = background_parent;
this.background = background;
this.effect = effect;
this.background_group = background_group;
this.bg_manager = bg_manager;
this.settings = dash_blur.settings;
this.old_style = this.dash._background.style;
dash_blur.connections.connect(dash_blur, 'remove-dashes', () => {
this._log("removing blur from dash");
this.dash.get_parent().remove_child(this.background_parent);
this.remove_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())
);
}
dash_blur.connections.connect(dash_blur, 'update-sigma', () => {
if (this.dash_blur.is_static) {
this.dash_blur.update_size();
}
this.effect.radius = 2 * this.dash_blur.sigma * this.effect.scale;
});
// 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);
dash_blur.connections.connect(dash_blur, 'update-brightness', () => {
this.effect.brightness = this.dash_blur.brightness;
});
// 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);
dash_blur.connections.connect(dash_blur, 'update-corner-radius', () => {
if (this.dash_blur.is_static) {
let monitor = find_monitor_for(this.dash);
let corner_radius = this.dash_blur.corner_radius * monitor.geometry_scale;
this.effect.corner_radius = Math.min(
corner_radius, this.effect.width / 2, this.effect.height / 2
);
}
});
// 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;
}
dash_blur.connections.connect(dash_blur, 'override-background', () => {
this.remove_style();
override_style() {
this.remove_style();
this.dash.set_style_class_name(
DASH_STYLES[this.settings.dash_to_dock.STYLE_DASH_TO_DOCK]
);
});
dash_blur.connections.connect(dash_blur, 'reset-background', () => this.remove_style());
dash_blur.connections.connect(dash_blur, 'show', () => {
if (this.dash_blur.is_static)
this.background_parent.show();
else
this.effect.radius = this.dash_blur.sigma * 2 * this.effect.scale;
});
dash_blur.connections.connect(dash_blur, 'hide', () => {
if (this.dash_blur.is_static)
this.background_parent.hide();
else
this.effect.radius = 0;
});
dash_blur.connections.connect(dash_blur, 'update-wallpaper', () => {
if (this.dash_blur.is_static) {
let bg = Main.layoutManager._backgroundGroup.get_child_at_index(
Main.layoutManager.monitors.length
- find_monitor_for(this.dash).index - 1
);
if (bg && bg.get_content()) {
this.background.content.set({
background: bg.get_content().background
});
this._log('wallpaper updated');
} else {
this._warn("could not get background for dash-to-dock");
}
}
});
dash_blur.connections.connect(dash_blur, '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;
this.effect.width = this.dash_background.width;
this.effect.height = this.dash_background.height;
this.dash_blur.set_corner_radius(this.dash_blur.corner_radius);
if (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 (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 (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 (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;
}
});
dash_blur.connections.connect(dash_blur, 'change-blur-type', () => {
this.background_parent.remove_child(this.background);
if (this.effect.chained_effect)
this.effect.get_actor()?.remove_effect(this.effect.chained_effect);
this.effect.get_actor()?.remove_effect(this.effect);
let [background, effect] = this.dash_blur.add_blur(this.dash, this.dash_background, this.dash_container);
this.background = background;
this.effect = effect;
this.background_parent.add_child(this.background);
});
this.dash.set_style_class_name(
DASH_STYLES[this.settings.dash_to_dock.STYLE_DASH_TO_DOCK]
);
}
remove_style() {
@ -169,10 +83,88 @@ class DashInfos {
);
}
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 = find_monitor_for(dash_container);
let monitor = Main.layoutManager.findMonitorForActor(dash_container);
let dash_box = dash_container._slider.get_child();
if (dash_container.get_style_class_name().includes("top")) {
@ -202,19 +194,13 @@ class DashInfos {
}
}
export const DashBlur = class DashBlur {
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.sigma = this.settings.dash_to_dock.CUSTOMIZE
? this.settings.dash_to_dock.SIGMA
: this.settings.SIGMA;
this.brightness = this.settings.dash_to_dock.CUSTOMIZE
? this.settings.dash_to_dock.BRIGHTNESS
: this.settings.BRIGHTNESS;
this.corner_radius = this.settings.dash_to_dock.CORNER_RADIUS;
this.is_static = this.settings.dash_to_dock.STATIC_BLUR;
this.enabled = false;
}
@ -231,7 +217,6 @@ export const DashBlur = class DashBlur {
this.blur_existing_dashes();
this.connect_to_overview();
this.update_wallpaper();
this.update_size();
this.enabled = true;
@ -246,7 +231,7 @@ export const DashBlur = class DashBlur {
Main.uiGroup.get_children().filter((child) => {
return (child.get_name() === "dashtodockContainer") &&
(child.constructor.name === 'DashToDock');
}).forEach(this.try_blur.bind(this));
}).forEach(dash_container => this.try_blur(dash_container));
}
// Tries to blur the dash contained in the given actor
@ -254,9 +239,9 @@ export const DashBlur = class DashBlur {
let dash_box = dash_container._slider.get_child();
// verify that we did not already blur that dash
if (!dash_box.get_children().some((child) => {
return child.get_name() === "dash-blurred-background-parent";
})) {
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
@ -270,48 +255,26 @@ export const DashBlur = class DashBlur {
// Blurs the dash and returns a `DashInfos` containing its information
blur_dash_from(dash, dash_container) {
// dash background parent, not visible
let background_parent = new St.Widget({
name: 'dash-blurred-background-parent',
style_class: 'dash-blurred-background-parent',
width: 0,
height: 0
});
let [background, background_group, bg_manager, paint_signals] = this.add_blur(dash);
// finally blur the dash
let dash_background = dash.get_children().find(child => {
return child.get_style_class_name() === 'dash-background';
});
let [background, effect] = this.add_blur(dash, dash_background, dash_container);
this.update_wallpaper();
this.update_size();
// 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', _ => {
this.update_size();
});
this.connections.connect(dash, 'notify::height', _ => {
this.update_size();
});
this.connections.connect(dash_container, 'notify::width', _ => {
this.update_size();
});
this.connections.connect(dash_container, 'notify::height', _ => {
this.update_size();
});
this.connections.connect(dash_container, 'notify::y', _ => {
this.update_wallpaper();
this.update_size();
});
this.connections.connect(dash_container, 'notify::x', _ => {
this.update_wallpaper();
this.update_size();
});
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()
);
background_parent.add_child(background);
dash.get_parent().insert_child_at_index(background_parent, 0);
const dash_background = dash.get_children().find(child => {
return child.get_style_class_name() === 'dash-background';
});
// create infos
let infos = new DashInfos(
@ -320,137 +283,81 @@ export const DashBlur = class DashBlur {
dash_container,
dash_background,
background,
background_parent,
effect
background_group,
bg_manager,
paint_signals
);
// update the background
this.update_size();
this.update_background();
// returns infos
return infos;
}
add_blur(dash, dash_background, dash_container) {
let monitor = find_monitor_for(dash);
add_blur(dash) {
const monitor = Main.layoutManager.findMonitorForActor(dash);
if (!monitor)
return;
// dash background widget
let background = this.is_static
? new Meta.BackgroundActor({
meta_display: global.display,
monitor: monitor.index,
})
: new St.Widget({
name: 'dash-blurred-background',
style_class: 'dash-blurred-background',
x: dash_background.x,
y: dash_background.y + dash.y,
width: dash_background.width,
height: dash_background.height,
});
const background_group = new Meta.BackgroundGroup({
name: 'bms-dash-backgroundgroup', width: 0, height: 0
});
// the effect to be applied
let effect;
if (this.is_static) {
let corner_radius = this.corner_radius * monitor.geometry_scale;
corner_radius = Math.min(corner_radius, dash_background.width / 2, dash_background.height / 2);
effect = new BlurEffect({
radius: 2 * this.sigma * monitor.geometry_scale,
brightness: this.brightness,
width: dash_background.width,
height: dash_background.height,
corner_radius: corner_radius
});
// connect to every background change (even without changing image)
// FIXME this signal is fired very often, so we should find another one
// fired only when necessary (but that still catches all cases)
this.connections.connect(
Main.layoutManager._backgroundGroup,
'notify',
_ => this.update_wallpaper()
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
);
} else {
effect = new Shell.BlurEffect({
brightness: this.brightness,
radius: this.sigma * 2 * monitor.geometry_scale,
mode: Shell.BlurMode.BACKGROUND
});
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 panel
// buttons to cause artifacts on the panel itself
// 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("dash hack level 1");
this.paint_signals.disconnect_all();
this._log("hack level 1");
let rp = () => {
effect.queue_repaint();
};
dash._box.get_children().forEach((icon) => {
try {
let zone = icon.get_child_at_index(0);
this.connections.connect(zone, [
'enter-event', 'leave-event', 'button-press-event'
], rp);
} catch (e) {
this._warn(`${e}, continuing`);
}
});
this.connections.connect(dash._box, 'actor-added', (_, actor) => {
try {
let zone = actor.get_child_at_index(0);
this.connections.connect(zone, [
'enter-event', 'leave-event', 'button-press-event'
], rp);
} catch (e) {
this._warn(`${e}, continuing`);
}
});
let show_apps = dash._showAppsIcon;
this.connections.connect(show_apps, [
'enter-event', 'leave-event', 'button-press-event'
], rp);
this.connections.connect(dash, 'leave-event', rp);
} else if (this.settings.HACKS_LEVEL === 2) {
this._log("dash hack level 2");
this.paint_signals.connect(background, effect);
paint_signals.disconnect_all();
paint_signals.connect(background, pipeline.effect);
} else {
this.paint_signals.disconnect_all();
paint_signals.disconnect_all();
}
}
// store the scale in the effect in order to retrieve it in set_sigma
effect.scale = monitor.geometry_scale;
background.add_effect(effect);
return [background, effect];
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', true);
this.emit('change-blur-type');
this.update_wallpaper();
this.update_background();
this.update_size();
}
/// Connect when overview if opened/closed to hide/show the blur accordingly
@ -459,10 +366,10 @@ export const DashBlur = class DashBlur {
if (this.settings.dash_to_dock.UNBLUR_IN_OVERVIEW) {
this.connections.connect(
Main.overview, 'showing', this.hide.bind(this)
Main.overview, 'showing', _ => this.hide()
);
this.connections.connect(
Main.overview, 'hidden', this.show.bind(this)
Main.overview, 'hidden', _ => this.show()
);
}
};
@ -470,45 +377,32 @@ export const DashBlur = class DashBlur {
/// 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-background', true);
this.emit('override-style');
else
this.emit('reset-background', true);
this.emit('remove-style');
}
update_wallpaper() {
if (this.is_static)
this.emit('update-wallpaper', true);
update_pipeline() {
this.emit('update-pipeline');
}
update_size() {
this.emit('update-size', true);
this.emit('update-size');
}
set_sigma(sigma) {
this.sigma = sigma;
this.emit('update-sigma', true);
show() {
this.emit('show');
}
set_brightness(brightness) {
this.brightness = brightness;
this.emit('update-brightness', true);
hide() {
this.emit('hide');
}
set_corner_radius(radius) {
this.corner_radius = radius;
this.emit('update-corner-radius', true);
}
// not implemented for dynamic blur
set_color(c) { }
set_noise_amount(n) { }
set_noise_lightness(l) { }
disable() {
this._log("removing blur from dashes");
this.emit('remove-dashes', true);
this.emit('remove-dashes');
this.dashes = [];
this.connections.disconnect_all();
@ -516,13 +410,6 @@ export const DashBlur = class DashBlur {
this.enabled = false;
}
show() {
this.emit('show', true);
}
hide() {
this.emit('hide', true);
}
_log(str) {
if (this.settings.DEBUG)
console.log(`[Blur my Shell > dash manager] ${str}`);
@ -531,6 +418,4 @@ export const DashBlur = class DashBlur {
_warn(str) {
console.warn(`[Blur my Shell > dash manager] ${str}`);
}
};
Signals.addSignalMethods(DashBlur.prototype);
};

View File

@ -1,19 +1,14 @@
import St from 'gi://St';
import Shell from 'gi://Shell';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as Background from 'resource:///org/gnome/shell/ui/background.js';
import { UnlockDialog } from 'resource:///org/gnome/shell/ui/unlockDialog.js';
let sigma;
let brightness;
let color;
let noise;
let lightness;
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 {
@ -27,22 +22,6 @@ export const LockscreenBlur = class LockscreenBlur {
enable() {
this._log("blurring lockscreen");
brightness = this.settings.lockscreen.CUSTOMIZE
? this.settings.lockscreen.BRIGHTNESS
: this.settings.BRIGHTNESS;
sigma = this.settings.lockscreen.CUSTOMIZE
? this.settings.lockscreen.SIGMA
: this.settings.SIGMA;
color = this.settings.lockscreen.CUSTOMIZE
? this.settings.lockscreen.COLOR
: this.settings.COLOR;
noise = this.settings.lockscreen.CUSTOMIZE
? this.settings.lockscreen.NOISE_AMOUNT
: this.settings.NOISE_AMOUNT;
lightness = this.settings.lockscreen.CUSTOMIZE
? this.settings.lockscreen.NOISE_LIGHTNESS
: this.settings.NOISE_LIGHTNESS;
this.update_lockscreen();
this.enabled = true;
@ -53,103 +32,39 @@ export const LockscreenBlur = class LockscreenBlur {
this._createBackground;
UnlockDialog.prototype._updateBackgroundEffects =
this._updateBackgroundEffects;
UnlockDialog.prototype._updateBackgrounds =
this._updateBackgrounds;
}
_createBackground(monitorIndex) {
let monitor = Main.layoutManager.monitors[monitorIndex];
let widget = new St.Widget({
style_class: "screen-shield-background",
x: monitor.x,
y: monitor.y,
width: monitor.width,
height: monitor.height,
});
_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
);
let blur_effect = new Shell.BlurEffect({
name: 'blur',
radius: sigma * 2,
brightness: brightness
});
// store the scale in the effect in order to retrieve later
blur_effect.scale = monitor.geometry_scale;
let color_effect = global.blur_my_shell._lockscreen_blur.effects_manager.new_color_effect({
name: 'color',
color: color
}, this.settings);
let noise_effect = global.blur_my_shell._lockscreen_blur.effects_manager.new_noise_effect({
name: 'noise',
noise: noise,
lightness: lightness
}, this.settings);
widget.add_effect(color_effect);
widget.add_effect(noise_effect);
widget.add_effect(blur_effect);
let bgManager = new Background.BackgroundManager({
container: widget,
monitorIndex,
controlPosition: false,
});
this._bgManagers.push(bgManager);
this._backgroundGroup.add_child(widget);
pipeline.create_background_with_effects(
monitor_index,
this._bgManagers,
this._backgroundGroup,
"screen-shield-background"
);
}
_updateBackgroundEffects() {
for (const widget of this._backgroundGroup) {
const color_effect = widget.get_effect('color');
const noise_effect = widget.get_effect('noise');
const blur_effect = widget.get_effect('blur');
this._updateBackgrounds();
}
if (color_effect)
color_effect.set({
color: color
});
if (noise_effect) {
noise_effect.set({
noise: noise,
lightness: lightness,
});
}
if (blur_effect) {
blur_effect.set({
brightness: brightness,
radius: sigma * 2 * blur_effect.scale,
});
}
_updateBackgrounds() {
for (let i = 0; i < this._bgManagers.length; i++) {
this._bgManagers[i]._bms_pipeline.destroy();
this._bgManagers[i].destroy();
}
}
set_sigma(s) {
sigma = s;
this.update_lockscreen();
}
this._bgManagers = [];
this._backgroundGroup.destroy_all_children();
set_brightness(b) {
brightness = b;
this.update_lockscreen();
}
set_color(c) {
color = c;
this.update_lockscreen();
}
set_noise_amount(n) {
noise = n;
this.update_lockscreen();
}
set_noise_lightness(l) {
lightness = l;
this.update_lockscreen();
for (let i = 0; i < Main.layoutManager.monitors.length; i++)
this._createBackground(i);
}
disable() {
@ -159,6 +74,8 @@ export const LockscreenBlur = class LockscreenBlur {
original_createBackground;
UnlockDialog.prototype._updateBackgroundEffects =
original_updateBackgroundEffects;
UnlockDialog.prototype._updateBackgrounds =
original_updateBackgrounds;
this.connections.disconnect_all();

View File

@ -1,10 +1,11 @@
import Shell from 'gi://Shell';
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",
@ -15,40 +16,23 @@ const OVERVIEW_COMPONENTS_STYLE = [
export const OverviewBlur = class OverviewBlur {
constructor(connections, settings, effects_manager) {
this.connections = connections;
this.effects = [];
this.settings = settings;
this.effects_manager = effects_manager;
this._workspace_switch_bg_actors = [];
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");
// connect to every background change (even without changing image)
// FIXME this signal is fired very often, so we should find another one
// fired only when necessary (but that still catches all cases)
this.connections.connect(
Main.layoutManager._backgroundGroup,
'notify',
_ => {
this._log("updated background");
this.update_backgrounds();
}
);
// connect to monitors change
this.connections.connect(
Main.layoutManager,
'monitors-changed',
_ => {
if (Main.screenShield && !Main.screenShield.locked) {
this._log("changed monitors");
this.update_backgrounds();
}
}
);
// add css class name for workspace-switch background
Main.uiGroup.add_style_class_name("blurred-overview");
@ -58,12 +42,16 @@ export const OverviewBlur = class OverviewBlur {
// 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 extension was enabled prior, as
// 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.enabled) {
if (!this.proto_patched) {
// store original workspace switching methods for restoring them on
// disable()
this._original_PrepareSwitch = wac_proto._prepareWorkspaceSwitch;
@ -91,25 +79,20 @@ export const OverviewBlur = class OverviewBlur {
);
}
Main.layoutManager.monitors.forEach(monitor => {
if (
!(
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() &&
(monitor !== Main.layoutManager.primaryMonitor)
bg_manager._monitorIndex !== Main.layoutManager.primaryMonitor.index
)
) {
const bg_actor = outer_this.create_background_actor(
monitor, true
);
Main.uiGroup.insert_child_above(
bg_actor,
global.window_group
);
// store the actors so that we can delete them later
outer_this._workspace_switch_bg_actors.push(bg_actor);
}
bg_manager._bms_pipeline.actor.visible = false;
else
bg_manager._bms_pipeline.actor.visible = true;
});
};
@ -129,15 +112,10 @@ export const OverviewBlur = class OverviewBlur {
);
}
outer_this.effects = outer_this.effects.filter(
effects_group => !effects_group.is_transition
);
outer_this._workspace_switch_bg_actors.forEach(actor => {
actor.destroy();
});
outer_this._workspace_switch_bg_actors = [];
Main.uiGroup.remove_child(outer_this.animation_background_group);
};
this.proto_patched = true;
}
this.enabled = true;
@ -146,78 +124,30 @@ export const OverviewBlur = class OverviewBlur {
update_backgrounds() {
// remove every old background
this.remove_background_actors();
// add new backgrounds
Main.layoutManager.monitors.forEach(monitor => {
const bg_actor = this.create_background_actor(monitor, false);
Main.layoutManager.overviewGroup.insert_child_at_index(
bg_actor,
monitor.index
// 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'
);
});
}
create_background_actor(monitor, is_transition) {
let bg_actor = new Meta.BackgroundActor({
name: "blur-my-shell_background_actor",
meta_display: global.display,
monitor: monitor.index
});
let background_group = Main.layoutManager._backgroundGroup
.get_children()
.filter((child) => child instanceof Meta.BackgroundActor);
let background =
background_group[
Main.layoutManager.monitors.length - monitor.index - 1
];
if (!background) {
this._warn("could not get background for overview");
return bg_actor;
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'
);
}
bg_actor.content.set({
background: background.get_content().background
});
let blur_effect = new Shell.BlurEffect({
brightness: this.settings.overview.CUSTOMIZE
? this.settings.overview.BRIGHTNESS
: this.settings.BRIGHTNESS,
radius: (this.settings.overview.CUSTOMIZE
? this.settings.overview.SIGMA
: this.settings.SIGMA) * 2 * monitor.geometry_scale,
mode: Shell.BlurMode.ACTOR
});
// store the scale in the effect in order to retrieve it in set_sigma
blur_effect.scale = monitor.geometry_scale;
let color_effect = this.effects_manager.new_color_effect({
color: this.settings.overview.CUSTOMIZE
? this.settings.overview.COLOR
: this.settings.COLOR
}, this.settings);
let noise_effect = this.effects_manager.new_noise_effect({
noise: this.settings.overview.CUSTOMIZE
? this.settings.overview.NOISE_AMOUNT
: this.settings.NOISE_AMOUNT,
lightness: this.settings.overview.CUSTOMIZE
? this.settings.overview.NOISE_LIGHTNESS
: this.settings.NOISE_LIGHTNESS
}, this.settings);
bg_actor.add_effect(color_effect);
bg_actor.add_effect(noise_effect);
bg_actor.add_effect(blur_effect);
this.effects.push({ blur_effect, color_effect, noise_effect, is_transition });
bg_actor.set_x(monitor.x);
bg_actor.set_y(monitor.y);
return bg_actor;
// add the container widget for the overview only to the overview group
Main.layoutManager.overviewGroup.insert_child_at_index(this.overview_background_group, 0);
}
/// Updates the classname to style overview components with semi-transparent
@ -233,71 +163,43 @@ export const OverviewBlur = class OverviewBlur {
);
}
set_sigma(s) {
this.effects.forEach(effect => {
effect.blur_effect.radius = s * 2 * effect.blur_effect.scale;
});
}
set_brightness(b) {
this.effects.forEach(effect => {
effect.blur_effect.brightness = b;
});
}
set_color(c) {
this.effects.forEach(effect => {
effect.color_effect.color = c;
});
}
set_noise_amount(n) {
this.effects.forEach(effect => {
effect.noise_effect.noise = n;
});
}
set_noise_lightness(l) {
this.effects.forEach(effect => {
effect.noise_effect.lightness = l;
});
}
remove_background_actors() {
Main.layoutManager.overviewGroup.get_children().forEach(child => {
if (child instanceof Meta.BackgroundActor
&& child.get_name() == "blur-my-shell_background_actor"
) {
child.get_effects().forEach(effect => {
this.effects_manager.remove(effect);
});
Main.layoutManager.overviewGroup.remove_child(child);
child.destroy();
}
this.overview_background_group.remove_all_children();
this.animation_background_group.remove_all_children();
this.overview_background_managers.forEach(background_manager => {
background_manager._bms_pipeline.destroy();
background_manager.destroy();
});
this.effects = [];
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)
);
// make sure to absolutely not do this if the component was not enabled
// prior, as this would cause infinite recursion
if (this.enabled) {
// restore original behavior
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.connections.disconnect_all();
this.enabled = false;
this.proto_patched = false;
}
}
_log(str) {

View File

@ -1,10 +1,11 @@
import St from 'gi://St';
import Shell from 'gi://Shell';
import Meta from 'gi://Meta';
import Mtk from 'gi://Mtk';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import { PaintSignals } from '../effects/paint_signals.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 = [
@ -56,26 +57,9 @@ export const PanelBlur = class PanelBlur {
// update the classname if the panel to have or have not light text
this.update_light_text_classname();
// connect to every background change (even without changing image)
// FIXME this signal is fired very often, so we should find another one
// fired only when necessary (but that still catches all cases)
this.connections.connect(
Main.layoutManager._backgroundGroup,
'notify',
_ => this.actors_list.forEach(actors =>
this.update_wallpaper(actors)
)
);
// connect to monitors change
this.connections.connect(
Main.layoutManager,
'monitors-changed',
_ => {
if (Main.screenShield && !Main.screenShield.locked) {
this.reset();
}
}
// connect to workareas change
this.connections.connect(global.display, 'workareas-changed',
_ => this.reset()
);
this.enabled = true;
@ -131,9 +115,6 @@ export const PanelBlur = class PanelBlur {
if (!actors)
// if the actors is not blurred, blur it
this.blur_panel(panel);
else
// if it is blurred, update the blur anyway
this.change_blur_type(actors);
}
/// Blur a panel
@ -145,71 +126,74 @@ export const PanelBlur = class PanelBlur {
panel_box = panel_box.get_parent();
}
let monitor = this.find_monitor_for(panel);
let monitor = Main.layoutManager.findMonitorForActor(panel);
if (!monitor)
return;
let background_parent = new St.Widget({
name: 'topbar-blurred-background-parent',
x: 0, y: 0, width: 0, height: 0
});
let background_group = new Meta.BackgroundGroup(
{ name: 'bms-panel-backgroundgroup', width: 0, height: 0 }
);
let background = this.settings.panel.STATIC_BLUR
? new Meta.BackgroundActor({
meta_display: global.display,
monitor: monitor.index
})
: new St.Widget;
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'
);
background_parent.add_child(background);
let paint_signals = new PaintSignals(this.connections);
// insert background parent
panel_box.insert_child_at_index(background_parent, 0);
// 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
let blur = new Shell.BlurEffect({
brightness: this.settings.panel.CUSTOMIZE
? this.settings.panel.BRIGHTNESS
: this.settings.BRIGHTNESS,
radius: (this.settings.panel.CUSTOMIZE
? this.settings.panel.SIGMA
: this.settings.SIGMA) * 2 * monitor.geometry_scale,
mode: this.settings.panel.STATIC_BLUR
? Shell.BlurMode.ACTOR
: Shell.BlurMode.BACKGROUND
});
{
if (this.settings.HACKS_LEVEL === 1) {
this._log("panel hack level 1");
// store the scale in the effect in order to retrieve it in set_sigma
blur.scale = monitor.geometry_scale;
paint_signals.disconnect_all();
paint_signals.connect(background, pipeline.effect);
} else {
paint_signals.disconnect_all();
}
}
}
let color = this.effects_manager.new_color_effect({
color: this.settings.panel.CUSTOMIZE
? this.settings.panel.COLOR
: this.settings.COLOR
}, this.settings);
let noise = this.effects_manager.new_noise_effect({
noise: this.settings.panel.CUSTOMIZE
? this.settings.panel.NOISE_AMOUNT
: this.settings.NOISE_AMOUNT,
lightness: this.settings.panel.CUSTOMIZE
? this.settings.panel.NOISE_LIGHTNESS
: this.settings.NOISE_LIGHTNESS
}, this.settings);
let paint_signals = new PaintSignals(this.connections);
// 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_parent },
effects: { blur, color, noise },
paint_signals,
widgets: { panel, panel_box, background, background_group },
static_blur,
monitor,
bg_manager,
is_dtp_panel
};
this.actors_list.push(actors);
// perform updates
this.change_blur_type(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
@ -228,157 +212,47 @@ export const PanelBlur = class PanelBlur {
'notify::position',
_ => this.update_size(actors)
);
}
update_all_blur_type() {
this.actors_list.forEach(actors => this.change_blur_type(actors));
}
change_blur_type(actors) {
let is_static = this.settings.panel.STATIC_BLUR;
// reset widgets to right state
actors.widgets.background_parent.remove_child(actors.widgets.background);
this.effects_manager.remove(actors.effects.blur);
this.effects_manager.remove(actors.effects.color);
this.effects_manager.remove(actors.effects.noise);
// create new background actor
actors.widgets.background = is_static
? new Meta.BackgroundActor({
meta_display: global.display,
monitor: this.find_monitor_for(actors.widgets.panel).index
})
: new St.Widget;
// change blur mode
actors.effects.blur.set_mode(is_static ? 0 : 1);
// disable other effects if the blur is dynamic, as they makes it opaque
actors.effects.color._static = is_static;
actors.effects.noise._static = is_static;
actors.effects.color.update_enabled();
actors.effects.noise.update_enabled();
// add the effects in order
actors.widgets.background.add_effect(actors.effects.color);
actors.widgets.background.add_effect(actors.effects.noise);
actors.widgets.background.add_effect(actors.effects.blur);
// add the background actor behing the panel
actors.widgets.background_parent.add_child(actors.widgets.background);
// perform updates
this.update_wallpaper(actors);
this.update_size(actors);
// 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 (!is_static) {
if (this.settings.HACKS_LEVEL === 1) {
this._log("panel hack level 1");
actors.paint_signals.disconnect_all();
let rp = () => { actors.effects.blur.queue_repaint(); };
this.connections.connect(actors.widgets.panel, [
'enter-event', 'leave-event', 'button-press-event'
], rp);
actors.widgets.panel.get_children().forEach(child => {
this.connections.connect(child, [
'enter-event', 'leave-event', 'button-press-event'
], rp);
});
} else if (this.settings.HACKS_LEVEL === 2) {
this._log("panel hack level 2");
actors.paint_signals.disconnect_all();
actors.paint_signals.connect(
actors.widgets.background, actors.effects.blur
);
} else {
actors.paint_signals.disconnect_all();
}
}
}
update_wallpaper(actors) {
// if static blur, get right wallpaper and update blur with it
if (this.settings.panel.STATIC_BLUR) {
let bg = Main.layoutManager._backgroundGroup.get_child_at_index(
Main.layoutManager.monitors.length
- this.find_monitor_for(actors.widgets.panel).index - 1
);
if (bg && bg.get_content())
actors.widgets.background.content.set({
background: bg.get_content().background
});
else
this._warn("could not get background for panel");
}
// 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 monitor = this.find_monitor_for(panel);
if (!monitor)
return;
let [width, height] = panel_box.get_size();
background.width = width;
background.height = height;
// if static blur, need to clip the background
if (this.settings.panel.STATIC_BLUR) {
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;
let y = p_y + p_p_y - monitor.y;
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, width, height);
background.x = -x;
background.y = -y;
// fixes a bug where the blur is washed away when changing the sigma
this.invalidate_blur(actors);
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 = this.find_monitor_for(panel);
}
/// An helper function to find the monitor in which an actor is situated,
/// there might be a pre-existing function in GLib already
find_monitor_for(actor) {
let extents = actor.get_transformed_extents();
let rect = new Mtk.Rectangle({
x: extents.get_x(),
y: extents.get_y(),
width: extents.get_width(),
height: extents.get_height(),
});
let index = global.display.get_monitor_index_for_rect(rect);
return Main.layoutManager.monitors[index];
actors.monitor = Main.layoutManager.findMonitorForActor(panel);
}
/// Connect when overview if opened/closed to hide/show the blur accordingly
@ -396,22 +270,22 @@ export const PanelBlur = class PanelBlur {
) {
if (!this.settings.hidetopbar.COMPATIBILITY) {
this.connections.connect(
Main.overview, 'showing', this.hide.bind(this)
Main.overview, 'showing', _ => this.hide()
);
this.connections.connect(
Main.overview, 'hidden', this.show.bind(this)
Main.overview, 'hidden', _ => this.show()
);
} else {
let appDisplay = Main.overview._overview._controls._appDisplay;
this.connections.connect(
appDisplay, 'show', this.hide.bind(this)
appDisplay, 'show', _ => this.hide()
);
this.connections.connect(
appDisplay, 'hide', this.show.bind(this)
appDisplay, 'hide', _ => this.show()
);
this.connections.connect(
Main.overview, 'hidden', this.show.bind(this)
Main.overview, 'hidden', _ => this.show()
);
}
@ -425,12 +299,12 @@ export const PanelBlur = class PanelBlur {
) {
// connect to overview opening/closing
this.connections.connect(Main.overview, ['showing', 'hiding'],
this.update_visibility.bind(this)
_ => this.update_visibility()
);
// connect to session mode update
this.connections.connect(Main.sessionMode, 'updated',
this.update_visibility.bind(this)
_ => this.update_visibility()
);
// manage already-existing windows
@ -450,7 +324,7 @@ export const PanelBlur = class PanelBlur {
// connect to a workspace change
this.connections.connect(global.window_manager, 'switch-workspace',
this.update_visibility.bind(this)
_ => this.update_visibility()
);
// perform early update
@ -600,75 +474,45 @@ export const PanelBlur = class PanelBlur {
);
}
/// Fixes a bug where the blur is washed away when changing the sigma, or
/// enabling/disabling other effects.
invalidate_blur(actors) {
if (this.settings.panel.STATIC_BLUR && actors.widgets.background)
actors.widgets.background.get_content()?.invalidate();
}
invalidate_all_blur() {
this.actors_list.forEach(actors => this.invalidate_blur(actors));
}
set_sigma(s) {
this.actors_list.forEach(actors => {
actors.effects.blur.radius = s * 2 * actors.effects.blur.scale;
this.invalidate_blur(actors);
});
}
set_brightness(b) {
this.actors_list.forEach(actors => {
actors.effects.blur.brightness = b;
});
}
set_color(c) {
this.actors_list.forEach(actors => {
actors.effects.color.color = c;
});
}
set_noise_amount(n) {
this.actors_list.forEach(actors => {
actors.effects.noise.noise = n;
});
}
set_noise_lightness(l) {
this.actors_list.forEach(actors => {
actors.effects.noise.lightness = l;
});
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_parent.show();
actors.widgets.background.show();
});
}
hide() {
this.actors_list.forEach(actors => {
actors.widgets.background_parent.hide();
actors.widgets.background.hide();
});
}
// destroy every blurred background left, necessary after sleep
destroy_blur_effects() {
Main.panel?.get_parent()?.get_children().forEach(
child => {
if (child.name === 'topbar-blurred-background-parent') {
child.get_children().forEach(meta_background_actor => {
meta_background_actor.get_effects().forEach(effect => {
this.effects_manager.remove(effect);
});
});
child.destroy_all_children();
child.destroy();
}
}
);
// 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() {
@ -678,21 +522,8 @@ export const PanelBlur = class PanelBlur {
this.update_light_text_classname(true);
this.actors_list.forEach(actors => {
this.set_should_override_panel(actors, false);
this.effects_manager.remove(actors.effects.noise);
this.effects_manager.remove(actors.effects.color);
this.effects_manager.remove(actors.effects.blur);
try {
actors.widgets.panel_box.remove_child(
actors.widgets.background_parent
);
} catch (e) { }
actors.widgets.background_parent?.destroy();
});
this.destroy_blur_effects();
const immutable_actors_list = [...this.actors_list];
immutable_actors_list.forEach(actors => this.destroy_blur(actors, false));
this.actors_list = [];
this.connections.disconnect_all();

View File

@ -1,41 +1,21 @@
import Shell from 'gi://Shell';
import Meta from 'gi://Meta';
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.effects = [];
this.settings = settings;
this.screenshot_background_managers = [];
this.effects_manager = effects_manager;
}
enable() {
this._log("blurring screenshot's window selector");
// connect to every background change (even without changing image)
// FIXME this signal is fired very often, so we should find another one
// fired only when necessary (but that still catches all cases)
this.connections.connect(
Main.layoutManager._backgroundGroup,
'notify',
_ => {
this._log("updated background for screenshot's window selector");
this.update_backgrounds();
}
);
// connect to monitors change
this.connections.connect(
Main.layoutManager,
'monitors-changed',
_ => {
if (Main.screenShield && !Main.screenShield.locked) {
this._log("changed monitors for screenshot's window selector");
this.update_backgrounds();
}
}
this.connections.connect(Main.layoutManager, 'monitors-changed',
_ => this.update_backgrounds()
);
// update backgrounds when the component is enabled
@ -44,121 +24,78 @@ export const ScreenshotBlur = class ScreenshotBlur {
update_backgrounds() {
// remove every old background
this.remove();
// add new backgrounds
this.remove_background_actors();
// create new backgrounds for the screenshot window selector
for (let i = 0; i < Main.screenshotUI._windowSelectors.length; i++) {
const actor = Main.screenshotUI._windowSelectors[i];
const monitor = Main.layoutManager.monitors[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
);
if (!monitor)
continue;
// 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();
const bg_actor = this.create_background_actor(monitor);
actor.insert_child_at_index(bg_actor, 0);
actor._blur_actor = bg_actor;
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);
});
}
}
create_background_actor(monitor) {
let bg_actor = new Meta.BackgroundActor({
meta_display: global.display,
monitor: monitor.index
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();
});
let background = Main.layoutManager._backgroundGroup.get_child_at_index(
Main.layoutManager.monitors.length - monitor.index - 1
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);
})
);
if (!background) {
this._warn("could not get background for screenshot's window selector");
return bg_actor;
}
bg_actor.content.set({
background: background.get_content().background
});
let blur_effect = new Shell.BlurEffect({
brightness: this.settings.screenshot.CUSTOMIZE
? this.settings.screenshot.BRIGHTNESS
: this.settings.BRIGHTNESS,
radius: (this.settings.screenshot.CUSTOMIZE
? this.settings.screenshot.SIGMA
: this.settings.SIGMA) * 2 * monitor.geometry_scale,
mode: Shell.BlurMode.ACTOR
});
// store the scale in the effect in order to retrieve it in set_sigma
blur_effect.scale = monitor.geometry_scale;
let color_effect = this.effects_manager.new_color_effect({
color: this.settings.screenshot.CUSTOMIZE
? this.settings.screenshot.COLOR
: this.settings.COLOR
}, this.settings);
let noise_effect = this.effects_manager.new_noise_effect({
noise: this.settings.screenshot.CUSTOMIZE
? this.settings.screenshot.NOISE_AMOUNT
: this.settings.NOISE_AMOUNT,
lightness: this.settings.screenshot.CUSTOMIZE
? this.settings.screenshot.NOISE_LIGHTNESS
: this.settings.NOISE_LIGHTNESS
}, this.settings);
bg_actor.add_effect(color_effect);
bg_actor.add_effect(noise_effect);
bg_actor.add_effect(blur_effect);
this.effects.push({ blur_effect, color_effect, noise_effect });
return bg_actor;
}
set_sigma(s) {
this.effects.forEach(effect => {
effect.blur_effect.radius = s * 2 * effect.blur_effect;
});
}
set_brightness(b) {
this.effects.forEach(effect => {
effect.blur_effect.brightness = b;
});
}
set_color(c) {
this.effects.forEach(effect => {
effect.color_effect.color = c;
});
}
set_noise_amount(n) {
this.effects.forEach(effect => {
effect.noise_effect.noise = n;
});
}
set_noise_lightness(l) {
this.effects.forEach(effect => {
effect.noise_effect.lightness = l;
});
}
remove() {
Main.screenshotUI._windowSelectors.forEach(actor => {
if (actor._blur_actor) {
actor.remove_child(actor._blur_actor);
actor._blur_actor.destroy();
delete actor._blur_actor;
}
});
this.effects = [];
this.screenshot_background_managers = [];
}
disable() {
this._log("removing blur from screenshot's window selector");
this.remove();
this.remove_background_actors();
this.connections.disconnect_all();
}

View File

@ -1,15 +1,16 @@
import Shell from 'gi://Shell';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import { PaintSignals } from '../effects/paint_signals.js';
import { PaintSignals } from '../conveniences/paint_signals.js';
import { DummyPipeline } from '../conveniences/dummy_pipeline.js';
export const WindowListBlur = class WindowListBlur {
constructor(connections, settings, _) {
constructor(connections, settings, effects_manager) {
this.connections = connections;
this.settings = settings;
this.paint_signals = new PaintSignals(connections);
this.effects = [];
this.effects_manager = effects_manager;
this.pipelines = [];
}
enable() {
@ -37,36 +38,35 @@ export const WindowListBlur = class WindowListBlur {
});
}
try_blur(child) {
try_blur(actor) {
if (
child.constructor.name === "WindowList" &&
child.style !== "background:transparent;"
actor.constructor.name === "WindowList" &&
actor.style !== "background:transparent;"
) {
this._log("found window list to blur");
let blur_effect = new Shell.BlurEffect({
name: 'window-list-blur',
radius: (this.settings.window_list.CUSTOMIZE
? this.settings.window_list.SIGMA
: this.settings.SIGMA) * 2,
brightness: this.settings.window_list.CUSTOMIZE
? this.settings.window_list.BRIGHTNESS
: this.settings.BRIGHTNESS,
mode: Shell.BlurMode.BACKGROUND
});
const pipeline = new DummyPipeline(
this.effects_manager, this.settings.window_list
);
pipeline.attach_effect_to_actor(actor);
this.pipelines.push(pipeline);
child.set_style("background:transparent;");
child.add_effect(blur_effect);
this.effects.push({ blur_effect });
actor.set_style("background:transparent;");
child._windowList.get_children().forEach(
window => this.blur_window_button(window)
actor._windowList.get_children().forEach(
window => this.style_window_button(window)
);
this.connections.connect(
child._windowList,
actor._windowList,
'child-added',
(_, window) => this.blur_window_button(window)
(_, window) => this.style_window_button(window)
);
this.connections.connect(
actor,
'destroy',
_ => this.destroy_blur(pipeline, true)
);
@ -83,75 +83,61 @@ export const WindowListBlur = class WindowListBlur {
if (this.settings.HACKS_LEVEL === 1) {
this._log("window list hack level 1");
this.paint_signals.connect(child, blur_effect);
} else if (this.settings.HACKS_LEVEL === 2) {
this._log("window list hack level 2");
this.paint_signals.connect(child, blur_effect);
this.paint_signals.disconnect_all_for_actor(actor);
this.paint_signals.connect(actor, pipeline.effect);
} else {
this.paint_signals.disconnect_all();
this.paint_signals.disconnect_all_for_actor(actor);
}
}
}
blur_window_button(window) {
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;"
);
}
try_remove_blur(child) {
if (
child.constructor.name === "WindowList" &&
child.style === "background:transparent;"
) {
child.style = null;
child.remove_effect_by_name('window-list-blur');
// 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);
}
child._windowList.get_children().forEach(
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)
);
}
}
set_sigma(s) {
this.effects.forEach(effect => {
effect.blur_effect.radius = s * 2;
});
}
set_brightness(b) {
this.effects.forEach(effect => {
effect.blur_effect.brightness = b;
});
}
// not implemented for dynamic blur
set_color(c) { }
set_noise_amount(n) { }
set_noise_lightness(l) { }
hide() {
this.set_sigma(0);
this.pipelines.forEach(pipeline => pipeline.effect?.set_enabled(false));
}
show() {
this.set_sigma(
this.settings.window_list.CUSTOMIZE
? this.settings.window_list.SIGMA
: this.settings.SIGMA
);
this.pipelines.forEach(pipeline => pipeline.effect?.set_enabled(true));
}
disable() {
this._log("removing blur from window list");
Main.layoutManager.uiGroup.get_children().forEach(
child => this.try_remove_blur(child)
);
const immutable_pipelines_list = [...this.pipelines];
immutable_pipelines_list.forEach(pipeline => this.destroy_blur(pipeline));
this.effects = [];
this.pipelines = [];
this.connections.disconnect_all();
}