[gnome] Fix extension locations

This commit is contained in:
2024-01-23 15:31:15 -05:00
parent 2f029aee37
commit 5ac7107501
331 changed files with 2 additions and 0 deletions

View File

@ -0,0 +1,261 @@
import Shell from 'gi://Shell';
import Clutter from 'gi://Clutter';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import { PaintSignals } from '../effects/paint_signals.js';
const Tweener = imports.tweener.tweener;
const transparent = Clutter.Color.from_pixel(0x00000000);
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.sigma = 0;
blur_effect.brightness = 1.0;
Tweener.addTween(blur_effect,
{
sigma: sigma,
brightness: brightness,
time: 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,
{
sigma: 0,
brightness: 1.0,
time: 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 {
constructor(connections, settings, _) {
this.connections = connections;
this.paint_signals = new PaintSignals(connections);
this.settings = settings;
}
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;
let appDisplay = Main.overview._overview.controls._appDisplay;
if (appDisplay._folderIcons.length > 0) {
this.blur_appfolders();
}
this.connections.connect(
appDisplay, 'view-loaded', this.blur_appfolders.bind(this)
);
}
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}`);
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",
sigma: sigma,
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.settings.HACKS_LEVEL === 2) {
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();
}
// not implemented for dynamic blur
set_color(c) { }
set_noise_amount(n) { }
set_noise_lightness(l) { }
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}`);
}
};

View File

@ -0,0 +1,548 @@
import Shell from 'gi://Shell';
import Clutter from 'gi://Clutter';
import Meta from 'gi://Meta';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import { PaintSignals } from '../effects/paint_signals.js';
import { ApplicationsService } from '../dbus/services.js';
export const ApplicationsBlur = class ApplicationsBlur {
constructor(connections, settings, _) {
this.connections = connections;
this.settings = settings;
this.paint_signals = new PaintSignals(connections);
// stores every blurred window
this.window_map = new Map();
// stores every blur actor
this.blur_actor_map = new Map();
}
enable() {
this._log("blurring applications...");
// export dbus service for preferences
this.service = new ApplicationsService;
this.service.export();
// 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) {
let window_actor = meta_window.get_compositor_private();
this.track_new(window_actor, meta_window);
}
}
);
this.connect_to_overview();
}
/// 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.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',
_ => {
let active_workspace =
global.workspace_manager.get_active_workspace();
this.window_map.forEach((meta_window, _pid) => {
let window_actor = meta_window.get_compositor_private();
if (
meta_window.get_workspace() !== active_workspace
)
window_actor.hide();
});
}
);
}
}
/// Iterate through all existing windows and add blur as needed.
update_all_windows() {
// remove all previously blurred windows, in the case where the
// whitelist was changed
this.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 => {
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);
});
}
}
/// 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);
window_actor['blur_provider_pid'] = pid;
meta_window['blur_provider_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);
});
// 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 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);
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);
}
/// Checks if the given actor needs to be blurred.
///
/// 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();
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 !== ""
&& ((enable_all && !blacklist.includes(window_wm_class))
|| (!enable_all && whitelist.includes(window_wm_class))
)
&& [
Meta.FrameType.NORMAL,
Meta.FrameType.DIALOG,
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);
}
// 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
);
}
}
/// Add the blur effect to the window.
create_blur_effect(pid, window_actor, meta_window, brightness, sigma) {
let blur_effect = new Shell.BlurEffect({
sigma: sigma,
brightness: brightness,
mode: Shell.BlurMode.BACKGROUND
});
let blur_actor = this.create_blur_actor(
meta_window,
window_actor,
blur_effect
);
// 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");
this.paint_signals.disconnect_all();
this.paint_signals.connect(blur_actor, blur_effect);
} else {
this.paint_signals.disconnect_all();
}
// 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);
// set the window actor's opacity
this.set_window_opacity(window_actor, this.settings.applications.OPACITY);
this.connections.connect(
window_actor,
'notify::opacity',
_ => 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
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();
}
}
);
}
/// 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;
});
}
/// Compute the size and position for a blur actor.
/// On wayland, it seems like we need to divide by the scale to get the
/// correct result.
compute_allocation(meta_window) {
const is_wayland = Meta.is_wayland_compositor();
const monitor_index = meta_window.get_monitor();
// check if the window is using wayland, or xwayland/xorg for rendering
const scale = is_wayland && meta_window.get_client_type() == 0
? Main.layoutManager.monitors[monitor_index].geometry_scale
: 1;
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
};
}
/// 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.sigma = sigma;
effect.brightness = brightness;
}
/// Removes the blur actor from the shell and unregister it.
remove_blur(pid) {
this._log(`removing blur for pid ${pid}`);
let meta_window = this.window_map.get(pid);
// disconnect needed signals and untrack window
if (meta_window) {
this.window_map.delete(pid);
let window_actor = meta_window.get_compositor_private();
let blur_actor = this.blur_actor_map.get(pid);
if (blur_actor) {
this.blur_actor_map.delete(pid);
if (window_actor) {
// reset the opacity
this.set_window_opacity(window_actor, 255);
// remove the blurred actor
window_actor.remove_child(blur_actor);
// disconnect the signals about overview animation etc
this.connections.disconnect_all_for(window_actor);
}
}
}
}
disable() {
this._log("removing blur from applications...");
this.service?.unexport();
this.blur_actor_map.forEach(((_blur_actor, pid) => {
this.remove_blur(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,322 @@
import St from 'gi://St';
import Shell from 'gi://Shell';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const Signals = imports.signals;
import { PaintSignals } from '../effects/paint_signals.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, background_parent, effect, settings) {
// the parent DashBlur object, to communicate
this.dash_blur = dash_blur;
// the blurred dash
this.dash = dash;
this.background_parent = background_parent;
this.effect = effect;
this.settings = 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.dash._background.style = this.old_style;
DASH_STYLES.forEach(
style => this.dash.remove_style_class_name(style)
);
});
dash_blur.connections.connect(dash_blur, 'update-sigma', () => {
this.effect.sigma = this.dash_blur.sigma;
});
dash_blur.connections.connect(dash_blur, 'update-brightness', () => {
this.effect.brightness = this.dash_blur.brightness;
});
dash_blur.connections.connect(dash_blur, 'override-background', () => {
this.dash._background.style = null;
DASH_STYLES.forEach(
style => this.dash.remove_style_class_name(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.dash._background.style = this.old_style;
DASH_STYLES.forEach(
style => this.dash.remove_style_class_name(style)
);
});
dash_blur.connections.connect(dash_blur, 'show', () => {
this.effect.sigma = this.dash_blur.sigma;
});
dash_blur.connections.connect(dash_blur, 'hide', () => {
this.effect.sigma = 0;
});
}
_log(str) {
if (this.settings.DEBUG)
console.log(`[Blur my Shell > dash] ${str}`);
}
}
export const DashBlur = class DashBlur {
constructor(connections, settings, _) {
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.enabled = false;
}
enable() {
this.connections.connect(Main.uiGroup, 'actor-added', (_, actor) => {
if (
(actor.get_name() === "dashtodockContainer") &&
(actor.constructor.name === 'DashToDock')
)
this.try_blur(actor);
});
this.blur_existing_dashes();
this.connect_to_overview();
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(this.try_blur.bind(this));
}
// 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) => {
return child.get_name() === "dash-blurred-background-parent";
})) {
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) {
// the effect to be applied
let effect = new Shell.BlurEffect({
brightness: this.brightness,
sigma: this.sigma,
mode: Shell.BlurMode.BACKGROUND
});
// 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
});
// dash background widget
let background = new St.Widget({
name: 'dash-blurred-background',
style_class: 'dash-blurred-background',
x: 0,
y: dash_container._slider.y,
width: dash.width,
height: dash.height,
});
// updates size and position on change
this.connections.connect(dash_container._slider, 'notify::y', _ => {
background.y = dash_container._slider.y;
});
this.connections.connect(dash, 'notify::width', _ => {
background.width = dash.width;
});
this.connections.connect(dash, 'notify::height', _ => {
background.height = dash.height;
});
// add the widget to the dash
background.add_effect(effect);
background_parent.add_child(background);
dash.get_parent().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
if (this.settings.HACKS_LEVEL === 1) {
this._log("dash hack level 1");
this.paint_signals.disconnect_all();
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);
} else {
this.paint_signals.disconnect_all();
}
// create infos
let infos = new DashInfos(
this, dash, background_parent, effect, this.settings
);
// update the background
this.update_background();
// returns infos
return infos;
}
/// 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.bind(this)
);
this.connections.connect(
Main.overview, 'hidden', this.show.bind(this)
);
}
};
/// Updates the background to either remove it or not, according to the
/// user preferences.
update_background() {
if (this.settings.dash_to_dock.OVERRIDE_BACKGROUND)
this.emit('override-background', true);
else
this.emit('reset-background', true);
}
set_sigma(sigma) {
this.sigma = sigma;
this.emit('update-sigma', true);
}
set_brightness(brightness) {
this.brightness = brightness;
this.emit('update-brightness', 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.dashes = [];
this.connections.disconnect_all();
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}`);
}
_warn(str) {
console.warn(`[Blur my Shell > dash manager] ${str}`);
}
};
Signals.addSignalMethods(DashBlur.prototype);

View File

@ -0,0 +1,167 @@
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;
const original_createBackground =
UnlockDialog.prototype._createBackground;
const original_updateBackgroundEffects =
UnlockDialog.prototype._updateBackgroundEffects;
export const LockscreenBlur = class LockscreenBlur {
constructor(connections, settings, effects_manager) {
this.connections = connections;
this.settings = settings;
this.effects_manager = effects_manager;
}
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();
}
update_lockscreen() {
UnlockDialog.prototype._createBackground =
this._createBackground;
UnlockDialog.prototype._updateBackgroundEffects =
this._updateBackgroundEffects;
}
_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,
});
let blur_effect = new Shell.BlurEffect({
name: 'blur',
sigma: sigma,
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);
}
_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');
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,
sigma: sigma * blur_effect.scale,
});
}
}
}
set_sigma(s) {
sigma = s;
this.update_lockscreen();
}
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();
}
disable() {
this._log("removing blur from lockscreen");
UnlockDialog.prototype._createBackground =
original_createBackground;
UnlockDialog.prototype._updateBackgroundEffects =
original_updateBackgroundEffects;
this.connections.disconnect_all();
}
_log(str) {
if (this.settings.DEBUG)
console.log(`[Blur my Shell > lockscreen] ${str}`);
}
};

View File

@ -0,0 +1,309 @@
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;
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.effects = [];
this.settings = settings;
this.effects_manager = effects_manager;
this._workspace_switch_bg_actors = [];
this.enabled = 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");
// 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();
// part for the workspace animation switch
// make sure not to do this part if the extension was enabled prior, as
// the functions would call themselves and cause infinite recursion
if (!this.enabled) {
// 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.layoutManager.monitors.forEach(monitor => {
if (
!(
Meta.prefs_get_workspaces_only_on_primary() &&
(monitor !== Main.layoutManager.primaryMonitor)
)
) {
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);
}
});
};
// 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()
);
}
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 = [];
};
}
this.enabled = true;
}
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_background_actor(monitor, is_transition) {
let bg_actor = new Meta.BackgroundActor({
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;
}
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,
sigma: this.settings.overview.CUSTOMIZE
? this.settings.overview.SIGMA
: this.settings.SIGMA
* 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;
}
/// 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]
);
}
set_sigma(s) {
this.effects.forEach(effect => {
effect.blur_effect.sigma = s * 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(actor => {
if (actor.constructor.name === 'Meta_BackgroundActor') {
actor.get_effects().forEach(effect => {
this.effects_manager.remove(effect);
});
Main.layoutManager.overviewGroup.remove_child(actor);
actor.destroy();
}
});
this.effects = [];
}
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
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;
}
_log(str) {
if (this.settings.DEBUG)
console.log(`[Blur my Shell > overview] ${str}`);
}
_warn(str) {
console.warn(`[Blur my Shell > overview] ${str}`);
}
};

View File

@ -0,0 +1,695 @@
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';
const DASH_TO_PANEL_UUID = 'dash-to-panel@jderose9.github.com';
const PANEL_STYLES = [
"transparent-panel",
"light-panel",
"dark-panel",
"contrasted-panel"
];
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() {
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 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();
}
}
);
this.enabled = true;
}
reset() {
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();
} else {
// if no dash-to-panel, blur the main and only panel
this.maybe_blur_panel(Main.panel);
}
}
blur_dtp_panels() {
// FIXME when Dash to Panel changes its size, it seems it creates new
// panels; but I can't get to delete old widgets
// blur every panel found
global.dashToPanel.panels.forEach(p => {
this.maybe_blur_panel(p.panel);
});
// if main panel is not included in the previous panels, blur it
if (
!global.dashToPanel.panels
.map(p => p.panel)
.includes(Main.panel)
&&
this.settings.dash_to_panel.BLUR_ORIGINAL_PANEL
)
this.maybe_blur_panel(Main.panel);
};
/// 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);
else
// if it is blurred, update the blur anyway
this.change_blur_type(actors);
}
/// 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 = this.find_monitor_for(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 = this.settings.panel.STATIC_BLUR
? new Meta.BackgroundActor({
meta_display: global.display,
monitor: monitor.index
})
: new St.Widget;
background_parent.add_child(background);
// insert background parent
panel_box.insert_child_at_index(background_parent, 0);
let blur = new Shell.BlurEffect({
brightness: this.settings.panel.CUSTOMIZE
? this.settings.panel.BRIGHTNESS
: this.settings.BRIGHTNESS,
sigma: this.settings.panel.CUSTOMIZE
? this.settings.panel.SIGMA
: this.settings.SIGMA
* monitor.geometry_scale,
mode: this.settings.panel.STATIC_BLUR
? Shell.BlurMode.ACTOR
: Shell.BlurMode.BACKGROUND
});
// store the scale in the effect in order to retrieve it in set_sigma
blur.scale = monitor.geometry_scale;
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);
let actors = {
widgets: { panel, panel_box, background, background_parent },
effects: { blur, color, noise },
paint_signals,
monitor,
is_dtp_panel
};
this.actors_list.push(actors);
// perform updates
this.change_blur_type(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)
);
}
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)
actors.widgets.background.content.set({
background: bg.get_content().background
});
else
this._warn("could not get background for panel");
}
}
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) {
// 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;
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);
} else {
background.x = panel.x;
background.y = panel.y;
}
// 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];
}
/// 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.bind(this)
);
this.connections.connect(
Main.overview, 'hidden', this.show.bind(this)
);
} else {
let appDisplay = Main.overview._overview._controls._appDisplay;
this.connections.connect(
appDisplay, 'show', this.hide.bind(this)
);
this.connections.connect(
appDisplay, 'hide', this.show.bind(this)
);
}
}
}
/// 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.bind(this)
);
// connect to session mode update
this.connections.connect(Main.sessionMode, 'updated',
this.update_visibility.bind(this)
);
// 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, 'actor-added',
this.on_window_actor_added.bind(this)
);
this.connections.connect(global.window_group, 'actor-removed',
this.on_window_actor_removed.bind(this)
);
// connect to a workspace change
this.connections.connect(global.window_manager, 'switch-workspace',
this.update_visibility.bind(this)
);
// 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();
}
/// 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 (
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"
);
// 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;
// if so, and if in the same monitor, then it overlaps
if (same_monitor
&&
window_vertical_pos < panel_bottom + 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]
);
}
/// 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.sigma = s * 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;
});
}
show() {
this.actors_list.forEach(actors => {
actors.widgets.background_parent.show();
});
}
hide() {
this.actors_list.forEach(actors => {
actors.widgets.background_parent.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();
}
}
);
}
disable() {
this._log("removing blur from top panel");
this.disconnect_from_windows_and_overview();
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();
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}`);
}
};

View File

@ -0,0 +1,173 @@
import Shell from 'gi://Shell';
import Meta from 'gi://Meta';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
export const ScreenshotBlur = class ScreenshotBlur {
constructor(connections, settings, effects_manager) {
this.connections = connections;
this.effects = [];
this.settings = settings;
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();
}
}
);
// update backgrounds when the component is enabled
this.update_backgrounds();
}
update_backgrounds() {
// remove every old background
this.remove();
// add new backgrounds
for (let i = 0; i < Main.screenshotUI._windowSelectors.length; i++) {
const actor = Main.screenshotUI._windowSelectors[i];
const monitor = Main.layoutManager.monitors[i];
if (!monitor)
continue;
const bg_actor = this.create_background_actor(monitor);
actor.insert_child_at_index(bg_actor, 0);
actor._blur_actor = bg_actor;
}
}
create_background_actor(monitor) {
let bg_actor = new Meta.BackgroundActor({
meta_display: global.display,
monitor: monitor.index
});
let background = Main.layoutManager._backgroundGroup.get_child_at_index(
Main.layoutManager.monitors.length - monitor.index - 1
);
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,
sigma: this.settings.screenshot.CUSTOMIZE
? this.settings.screenshot.SIGMA
: this.settings.SIGMA
* 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.sigma = s * 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();
}
});
this.effects = [];
}
disable() {
this._log("removing blur from screenshot's window selector");
this.remove();
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}`);
}
};

View File

@ -0,0 +1,162 @@
import Shell from 'gi://Shell';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import { PaintSignals } from '../effects/paint_signals.js';
export const WindowListBlur = class WindowListBlur {
constructor(connections, settings, _) {
this.connections = connections;
this.settings = settings;
this.paint_signals = new PaintSignals(connections);
this.effects = [];
}
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,
'actor-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(child) {
if (
child.constructor.name === "WindowList" &&
child.style !== "background:transparent;"
) {
this._log("found window list to blur");
let blur_effect = new Shell.BlurEffect({
name: 'window-list-blur',
sigma: this.settings.window_list.CUSTOMIZE
? this.settings.window_list.SIGMA
: this.settings.SIGMA,
brightness: this.settings.window_list.CUSTOMIZE
? this.settings.window_list.BRIGHTNESS
: this.settings.BRIGHTNESS,
mode: Shell.BlurMode.BACKGROUND
});
child.set_style("background:transparent;");
child.add_effect(blur_effect);
this.effects.push({ blur_effect });
child._windowList.get_children().forEach(
window => this.blur_window_button(window)
);
this.connections.connect(
child._windowList,
'actor-added',
(_, window) => this.blur_window_button(window)
);
// 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.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);
} else {
this.paint_signals.disconnect_all();
}
}
}
blur_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');
child._windowList.get_children().forEach(
child => child.get_child_at_index(0).set_style(null)
);
}
}
set_sigma(s) {
this.effects.forEach(effect => {
effect.blur_effect.sigma = s;
});
}
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);
}
show() {
this.set_sigma(
this.settings.window_list.CUSTOMIZE
? this.settings.window_list.SIGMA
: this.settings.SIGMA
);
}
disable() {
this._log("removing blur from window list");
Main.layoutManager.uiGroup.get_children().forEach(
child => this.try_remove_blur(child)
);
this.effects = [];
this.connections.disconnect_all();
}
_log(str) {
if (this.settings.DEBUG)
console.log(`[Blur my Shell > window list] ${str}`);
}
};

View File

@ -0,0 +1,101 @@
import GObject from 'gi://GObject';
/// An object to easily manage signals.
export const Connections = class Connections {
constructor() {
this.buffer = [];
}
/// Adds a connection.
///
/// Takes as arguments:
/// - an actor, which fires the signal
/// - signal(s) (string or array of strings), which are watched for
/// - a callback, which is called when the signal is fired
connect(actor, signals, handler) {
if (signals instanceof Array) {
signals.forEach(signal => {
let id = actor.connect(signal, handler);
this.process_connection(actor, id);
});
} else {
let id = actor.connect(signals, handler);
this.process_connection(actor, id);
}
}
/// Process the given actor and id.
///
/// This makes sure that the signal is disconnected when the actor is
/// destroyed, and that the signal can be managed through other Connections
/// methods.
process_connection(actor, id) {
let infos = {
actor: actor,
id: id
};
// remove the signal when the actor is destroyed
if (
actor.connect &&
(
!(actor instanceof GObject.Object) ||
GObject.signal_lookup('destroy', actor)
)
) {
let destroy_id = actor.connect('destroy', () => {
actor.disconnect(id);
actor.disconnect(destroy_id);
let index = this.buffer.indexOf(infos);
if (index >= 0) {
this.buffer.splice(index, 1);
}
});
}
this.buffer.push(infos);
}
/// Disconnects every connection found for an actor.
disconnect_all_for(actor) {
// get every connection stored for the actor
let actor_connections = this.buffer.filter(
infos => infos.actor === actor
);
// remove each of them
actor_connections.forEach((connection) => {
// disconnect
try {
connection.actor.disconnect(connection.id);
} catch (e) {
this._warn(`error removing connection: ${e}; continuing`);
}
// remove from buffer
let index = this.buffer.indexOf(connection);
this.buffer.splice(index, 1);
});
}
/// Disconnect every connection for each actor.
disconnect_all() {
this.buffer.forEach((connection) => {
// disconnect
try {
connection.actor.disconnect(connection.id);
} catch (e) {
this._warn(`error removing connection: ${e}; continuing`);
}
});
// reset buffer
this.buffer = [];
}
_warn(str) {
console.warn(`[Blur my Shell > connections] ${str}`);
}
};

View File

@ -0,0 +1,89 @@
import { ColorEffect } from '../effects/color_effect.js';
import { NoiseEffect } from '../effects/noise_effect.js';
/// An object to manage effects (by not destroying them all the time)
export const EffectsManager = class EffectsManager {
constructor(connections) {
this.connections = connections;
this.used = [];
this.color_effects = [];
this.noise_effects = [];
}
connect_to_destroy(effect) {
effect.old_actor = effect.get_actor();
if (effect.old_actor)
effect.old_actor_id = effect.old_actor.connect('destroy', _ => {
this.remove(effect);
});
this.connections.connect(effect, 'notify::actor', _ => {
let actor = effect.get_actor();
if (effect.old_actor && actor != effect.old_actor)
effect.old_actor.disconnect(effect.old_actor_id);
if (actor) {
effect.old_actor_id = actor.connect('destroy', _ => {
this.remove(effect);
});
}
});
}
new_color_effect(params, settings) {
let effect;
if (this.color_effects.length > 0) {
effect = this.color_effects.splice(0, 1)[0];
effect.set(params);
} else
effect = new ColorEffect(params, settings);
this.used.push(effect);
this.connect_to_destroy(effect);
return effect;
}
new_noise_effect(params, settings) {
let effect;
if (this.noise_effects.length > 0) {
effect = this.noise_effects.splice(0, 1)[0];
effect.set(params);
} else
effect = new NoiseEffect(params, settings);
this.used.push(effect);
this.connect_to_destroy(effect);
return effect;
}
remove(effect) {
effect.get_actor()?.remove_effect(effect);
if (effect.old_actor)
effect.old_actor.disconnect(effect.old_actor_id);
delete effect.old_actor;
delete effect.old_actor_id;
let index = this.used.indexOf(effect);
if (index >= 0) {
this.used.splice(index, 1);
if (effect instanceof ColorEffect)
this.color_effects.push(effect);
else if (effect instanceof NoiseEffect)
this.noise_effects.push(effect);
}
}
destroy_all() {
this.used.forEach(effect => { this.remove(effect); });
[
this.used,
this.color_effects,
this.noise_effects
].forEach(array => {
array.splice(0, array.length);
});
}
};

View File

@ -0,0 +1,131 @@
import { Type } from './settings.js';
// This lists the preferences keys
export const Keys = [
{
component: "general", schemas: [
{ type: Type.I, name: "sigma" },
{ type: Type.D, name: "brightness" },
{ type: Type.C, name: "color" },
{ type: Type.D, name: "noise-amount" },
{ type: Type.D, name: "noise-lightness" },
{ type: Type.B, name: "color-and-noise" },
{ type: Type.I, name: "hacks-level" },
{ type: Type.B, name: "debug" },
]
},
{
component: "overview", schemas: [
{ type: Type.B, name: "blur" },
{ type: Type.B, name: "customize" },
{ type: Type.I, name: "sigma" },
{ type: Type.D, name: "brightness" },
{ type: Type.C, name: "color" },
{ type: Type.D, name: "noise-amount" },
{ type: Type.D, name: "noise-lightness" },
{ type: Type.I, name: "style-components" },
]
},
{
component: "appfolder", schemas: [
{ type: Type.B, name: "blur" },
{ type: Type.B, name: "customize" },
{ type: Type.I, name: "sigma" },
{ type: Type.D, name: "brightness" },
{ type: Type.C, name: "color" },
{ type: Type.D, name: "noise-amount" },
{ type: Type.D, name: "noise-lightness" },
{ type: Type.I, name: "style-dialogs" },
]
},
{
component: "panel", schemas: [
{ type: Type.B, name: "blur" },
{ type: Type.B, name: "customize" },
{ type: Type.I, name: "sigma" },
{ type: Type.D, name: "brightness" },
{ type: Type.C, name: "color" },
{ type: Type.D, name: "noise-amount" },
{ type: Type.D, name: "noise-lightness" },
{ type: Type.B, name: "static-blur" },
{ type: Type.B, name: "unblur-in-overview" },
{ type: Type.B, name: "override-background" },
{ type: Type.I, name: "style-panel" },
{ type: Type.B, name: "override-background-dynamically" },
]
},
{
component: "dash-to-dock", schemas: [
{ type: Type.B, name: "blur" },
{ type: Type.B, name: "customize" },
{ type: Type.I, name: "sigma" },
{ type: Type.D, name: "brightness" },
{ type: Type.C, name: "color" },
{ type: Type.D, name: "noise-amount" },
{ type: Type.D, name: "noise-lightness" },
{ type: Type.B, name: "static-blur" },
{ type: Type.B, name: "unblur-in-overview" },
{ type: Type.B, name: "override-background" },
{ type: Type.I, name: "style-dash-to-dock" },
]
},
{
component: "applications", schemas: [
{ type: Type.B, name: "blur" },
{ type: Type.B, name: "customize" },
{ type: Type.I, name: "sigma" },
{ type: Type.D, name: "brightness" },
{ type: Type.C, name: "color" },
{ type: Type.D, name: "noise-amount" },
{ type: Type.D, name: "noise-lightness" },
{ type: Type.I, name: "opacity" },
{ type: Type.B, name: "blur-on-overview" },
{ type: Type.B, name: "enable-all" },
{ type: Type.AS, name: "whitelist" },
{ type: Type.AS, name: "blacklist" },
]
},
{
component: "lockscreen", schemas: [
{ type: Type.B, name: "blur" },
{ type: Type.B, name: "customize" },
{ type: Type.I, name: "sigma" },
{ type: Type.D, name: "brightness" },
{ type: Type.C, name: "color" },
{ type: Type.D, name: "noise-amount" },
{ type: Type.D, name: "noise-lightness" },
]
},
{
component: "window-list", schemas: [
{ type: Type.B, name: "blur" },
{ type: Type.B, name: "customize" },
{ type: Type.I, name: "sigma" },
{ type: Type.D, name: "brightness" },
{ type: Type.C, name: "color" },
{ type: Type.D, name: "noise-amount" },
{ type: Type.D, name: "noise-lightness" },
]
},
{
component: "screenshot", schemas: [
{ type: Type.B, name: "blur" },
{ type: Type.B, name: "customize" },
{ type: Type.I, name: "sigma" },
{ type: Type.D, name: "brightness" },
{ type: Type.C, name: "color" },
{ type: Type.D, name: "noise-amount" },
{ type: Type.D, name: "noise-lightness" },
]
},
{
component: "hidetopbar", schemas: [
{ type: Type.B, name: "compatibility" },
]
},
{
component: "dash-to-panel", schemas: [
{ type: Type.B, name: "blur-original-panel" },
]
},
];

View File

@ -0,0 +1,182 @@
import GLib from 'gi://GLib';
const Signals = imports.signals;
/// An enum non-extensively describing the type of gsettings key.
export const Type = {
B: 'Boolean',
I: 'Integer',
D: 'Double',
S: 'String',
C: 'Color',
AS: 'StringArray'
};
/// An object to get and manage the gsettings preferences.
///
/// Should be initialized with an array of keys, for example:
///
/// let settings = new Settings([
/// { type: Type.I, name: "panel-corner-radius" },
/// { type: Type.B, name: "debug" }
/// ]);
///
/// Each {type, name} object represents a gsettings key, which must be created
/// in the gschemas.xml file of the extension.
export const Settings = class Settings {
constructor(keys, settings) {
this.settings = settings;
this.keys = keys;
this.keys.forEach(bundle => {
let component = this;
let component_settings = settings;
if (bundle.component !== "general") {
let bundle_component = bundle.component.replaceAll('-', '_');
this[bundle_component] = {
settings: this.settings.get_child(bundle.component)
};
component = this[bundle_component];
component_settings = settings.get_child(bundle.component);
}
bundle.schemas.forEach(key => {
let property_name = this.get_property_name(key.name);
switch (key.type) {
case Type.B:
Object.defineProperty(component, property_name, {
get() {
return component_settings.get_boolean(key.name);
},
set(v) {
component_settings.set_boolean(key.name, v);
}
});
break;
case Type.I:
Object.defineProperty(component, property_name, {
get() {
return component_settings.get_int(key.name);
},
set(v) {
component_settings.set_int(key.name, v);
}
});
break;
case Type.D:
Object.defineProperty(component, property_name, {
get() {
return component_settings.get_double(key.name);
},
set(v) {
component_settings.set_double(key.name, v);
}
});
break;
case Type.S:
Object.defineProperty(component, property_name, {
get() {
return component_settings.get_string(key.name);
},
set(v) {
component_settings.set_string(key.name, v);
}
});
break;
case Type.C:
Object.defineProperty(component, property_name, {
// returns the array [red, blue, green, alpha] with
// values between 0 and 1
get() {
let val = component_settings.get_value(key.name);
return val.deep_unpack();
},
// takes an array [red, blue, green, alpha] with
// values between 0 and 1
set(v) {
let val = new GLib.Variant("(dddd)", v);
component_settings.set_value(key.name, val);
}
});
break;
case Type.AS:
Object.defineProperty(component, property_name, {
get() {
let val = component_settings.get_value(key.name);
return val.deep_unpack();
},
set(v) {
let val = new GLib.Variant("as", v);
component_settings.set_value(key.name, val);
}
});
break;
}
component[property_name + '_reset'] = function () {
return component_settings.reset(key.name);
};
component[property_name + '_changed'] = function (cb) {
return component_settings.connect('changed::' + key.name, cb);
};
component[property_name + '_disconnect'] = function () {
return component_settings.disconnect.apply(
component_settings, arguments
);
};
});
});
};
/// Reset the preferences.
reset() {
this.keys.forEach(bundle => {
let component = this;
if (bundle.component !== "general") {
let bundle_component = bundle.component.replaceAll('-', '_');
component = this[bundle_component];
}
bundle.schemas.forEach(key => {
let property_name = this.get_property_name(key.name);
component[property_name + '_reset']();
});
});
this.emit('reset', true);
}
/// From the gschema name, returns the name of the associated property on
/// the Settings object.
get_property_name(name) {
return name.replaceAll('-', '_').toUpperCase();
}
/// Remove all connections managed by the Settings object, i.e. created with
/// `settings.PROPERTY_changed(callback)`.
disconnect_all_settings() {
this.keys.forEach(bundle => {
let component = this;
if (bundle.component !== "general") {
let bundle_component = bundle.component.replaceAll('-', '_');
component = this[bundle_component];
}
bundle.schemas.forEach(key => {
let property_name = this.get_property_name(key.name);
component[property_name + '_disconnect']();
});
});
}
};
Signals.addSignalMethods(Settings.prototype);

View File

@ -0,0 +1,58 @@
import Gio from 'gi://Gio';
const bus_name = 'org.gnome.Shell';
const iface_name = 'dev.aunetx.BlurMyShell';
const obj_path = '/dev/aunetx/BlurMyShell';
/// Call pick() from the DBus service, it will open the Inspector from
/// gnome-shell to pick an actor on stage.
export function pick() {
Gio.DBus.session.call(
bus_name,
obj_path,
iface_name,
'pick',
null,
null,
Gio.DBusCallFlags.NO_AUTO_START,
-1,
null,
null
);
}
/// Connect to DBus 'picking' signal, which will be emitted when the inspector
/// is picking a window.
export function on_picking(cb) {
const id = Gio.DBus.session.signal_subscribe(
bus_name,
iface_name,
'picking',
obj_path,
null,
Gio.DBusSignalFlags.NONE,
_ => {
cb();
Gio.DBus.session.signal_unsubscribe(id);
}
);
}
/// Connect to DBus 'picked' signal, which will be emitted when a window is
/// picked.
export function on_picked(cb) {
const id = Gio.DBus.session.signal_subscribe(
bus_name,
iface_name,
'picked',
obj_path,
null,
Gio.DBusSignalFlags.NONE,
(conn, sender, obj_path, iface, signal, params) => {
const val = params.get_child_value(0);
cb(val.get_string()[0]);
Gio.DBus.session.signal_unsubscribe(id);
}
);
}

View File

@ -0,0 +1,12 @@
<node>
<interface name="dev.aunetx.BlurMyShell">
<!-- This method is called in preferences to pick a window -->
<method name="pick" />
<!-- When window is picking, send a signal to preferences -->
<signal name="picking"></signal>
<!-- If window is picked, send a signal to preferences -->
<signal name="picked">
<arg name="window" type="s" />
</signal>
</interface>
</node>

View File

@ -0,0 +1,90 @@
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as LookingGlass from 'resource:///org/gnome/shell/ui/lookingGlass.js';
export const ApplicationsService = class ApplicationsService {
constructor() {
let decoder = new TextDecoder();
let path = GLib.filename_from_uri(GLib.uri_resolve_relative(
import.meta.url, 'iface.xml', GLib.UriFlags.NONE)
)[0];
let [, buffer] = GLib.file_get_contents(path);
let iface = decoder.decode(buffer);
GLib.free(buffer);
this.DBusImpl = Gio.DBusExportedObject.wrapJSObject(iface, this);
}
/// Pick Window for Preferences Page, exported to DBus client.
pick() {
// emit `picking` signal to know we are listening
const send_picking_signal = _ =>
this.DBusImpl.emit_signal(
'picking',
null
);
// emit `picked` signal to send wm_class
const send_picked_signal = wm_class =>
this.DBusImpl.emit_signal(
'picked',
new GLib.Variant('(s)', [wm_class])
);
// notify the preferences that we are listening
send_picking_signal();
// A very interesting way to pick a window:
// 1. Open LookingGlass to mask all event handles of window
// 2. Use inspector to pick window, thats is also lookingGlass do
// 3. Close LookingGlass when done
// It will restore event handles of window
// open then hide LookingGlass
const looking_class = Main.createLookingGlass();
looking_class.open();
looking_class.hide();
// inspect window now
const inspector = new LookingGlass.Inspector(Main.createLookingGlass());
inspector.connect('target', (me, target, x, y) => {
// remove border effect when window is picked.
const effect_name = 'lookingGlass_RedBorderEffect';
target
.get_effects()
.filter(e => e.toString().includes(effect_name))
.forEach(e => target.remove_effect(e));
// get wm_class_instance property of window, then pass it to DBus
// client
const type_str = target.toString();
let actor = target;
if (type_str.includes('MetaSurfaceActor'))
actor = target.get_parent();
if (!actor.toString().includes('WindowActor'))
return send_picked_signal('window-not-found');
send_picked_signal(
actor.meta_window.get_wm_class() ?? 'window-not-found'
);
});
// close LookingGlass when we're done
inspector.connect('closed', _ => looking_class.close());
}
export() {
this.DBusImpl.export(
Gio.DBus.session,
'/dev/aunetx/BlurMyShell'
);
};
unexport() {
this.DBusImpl.unexport();
}
};

View File

@ -0,0 +1,13 @@
uniform sampler2D tex;
uniform float red;
uniform float green;
uniform float blue;
uniform float blend;
void main() {
vec4 c = texture2D(tex, cogl_tex_coord_in[0].st);
vec3 pix_color = c.xyz;
vec3 color = vec3(red, green, blue);
cogl_color_out = vec4(mix(pix_color, color, blend), 1.);
}

View File

@ -0,0 +1,181 @@
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Clutter from 'gi://Clutter';
import Shell from 'gi://Shell';
const SHADER_PATH = GLib.filename_from_uri(GLib.uri_resolve_relative(import.meta.url, 'color_effect.glsl', GLib.UriFlags.NONE))[0];
const get_shader_source = _ => {
try {
return Shell.get_file_contents_utf8_sync(SHADER_PATH);
} catch (e) {
console.warn(`[Blur my Shell] error loading shader from ${SHADER_PATH}: ${e}`);
return null;
}
};
/// New Clutter Shader Effect that simply mixes a color in, the class applies
/// the GLSL shader programmed into vfunc_get_static_shader_source and applies
/// it to an Actor.
///
/// Clutter Shader Source Code:
/// https://github.com/GNOME/clutter/blob/master/clutter/clutter-shader-effect.c
///
/// GJS Doc:
/// https://gjs-docs.gnome.org/clutter10~10_api/clutter.shadereffect
export const ColorEffect = new GObject.registerClass({
GTypeName: "ColorEffect",
Properties: {
'red': GObject.ParamSpec.double(
`red`,
`Red`,
`Red value in shader`,
GObject.ParamFlags.READWRITE,
0.0, 1.0,
0.4,
),
'green': GObject.ParamSpec.double(
`green`,
`Green`,
`Green value in shader`,
GObject.ParamFlags.READWRITE,
0.0, 1.0,
0.4,
),
'blue': GObject.ParamSpec.double(
`blue`,
`Blue`,
`Blue value in shader`,
GObject.ParamFlags.READWRITE,
0.0, 1.0,
0.4,
),
'blend': GObject.ParamSpec.double(
`blend`,
`Blend`,
`Amount of blending between the colors`,
GObject.ParamFlags.READWRITE,
0.0, 1.0,
0.4,
),
}
}, class ColorShader extends Clutter.ShaderEffect {
constructor(params, settings) {
// initialize without color as a parameter
let _color = params.color;
delete params.color;
super(params);
this._red = null;
this._green = null;
this._blue = null;
this._blend = null;
this._static = true;
this._settings = settings;
// set shader source
this._source = get_shader_source();
if (this._source)
this.set_shader_source(this._source);
// set shader color
if (_color)
this.color = _color;
this.update_enabled();
}
get red() {
return this._red;
}
set red(value) {
if (this._red !== value) {
this._red = value;
this.set_uniform_value('red', parseFloat(this._red - 1e-6));
}
}
get green() {
return this._green;
}
set green(value) {
if (this._green !== value) {
this._green = value;
this.set_uniform_value('green', parseFloat(this._green - 1e-6));
}
}
get blue() {
return this._blue;
}
set blue(value) {
if (this._blue !== value) {
this._blue = value;
this.set_uniform_value('blue', parseFloat(this._blue - 1e-6));
}
}
get blend() {
return this._blend;
}
set blend(value) {
if (this._blend !== value) {
this._blend = value;
this.set_uniform_value('blend', parseFloat(this._blend - 1e-6));
}
this.update_enabled();
}
set color(rgba) {
let [r, g, b, a] = rgba;
this.red = r;
this.green = g;
this.blue = b;
this.blend = a;
}
get color() {
return [this.red, this.green, this.blue, this.blend];
}
/// False set function, only cares about the color. Too hard to change.
set(params) {
this.color = params.color;
}
update_enabled() {
// don't anything if this._settings is undefined (when calling super)
if (this._settings === undefined)
return;
this.set_enabled(
this.blend > 0 &&
this._settings.COLOR_AND_NOISE &&
this._static
);
}
vfunc_paint_target(paint_node = null, paint_context = null) {
this.set_uniform_value("tex", 0);
if (paint_node && paint_context)
super.vfunc_paint_target(paint_node, paint_context);
else if (paint_node)
super.vfunc_paint_target(paint_node);
else
super.vfunc_paint_target();
}
});

View File

@ -0,0 +1,20 @@
uniform sampler2D tex;
uniform float noise;
uniform float lightness;
float PHI = 1.61803398874989484820459;
float SEED = 24;
float noise_gen(in vec2 xy) {
float r = fract(tan(distance(xy * PHI, xy) * SEED) * xy.x);
r = r != r ? 0.0 : r;
return r;
}
void main() {
vec4 c = texture2D(tex, cogl_tex_coord_in[0].st);
vec3 pix_color = c.xyz;
float blend = noise * (1. - noise_gen(gl_FragCoord.xy));
cogl_color_out = vec4(mix(pix_color, lightness * pix_color, blend), 1.);
}

View File

@ -0,0 +1,109 @@
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Clutter from 'gi://Clutter';
import Shell from 'gi://Shell';
const SHADER_PATH = GLib.filename_from_uri(GLib.uri_resolve_relative(import.meta.url, 'noise_effect.glsl', GLib.UriFlags.NONE))[0];
const get_shader_source = _ => {
try {
return Shell.get_file_contents_utf8_sync(SHADER_PATH);
} catch (e) {
console.warn(`[Blur my Shell] error loading shader from ${SHADER_PATH}: ${e}`);
return null;
}
};
export const NoiseEffect = new GObject.registerClass({
GTypeName: "NoiseEffect",
Properties: {
'noise': GObject.ParamSpec.double(
`noise`,
`Noise`,
`Amount of noise integrated with the image`,
GObject.ParamFlags.READWRITE,
0.0, 1.0,
0.4,
),
'lightness': GObject.ParamSpec.double(
`lightness`,
`Lightness`,
`Lightness of the grey used for the noise`,
GObject.ParamFlags.READWRITE,
0.0, 2.0,
0.4,
),
}
}, class NoiseShader extends Clutter.ShaderEffect {
constructor(params, settings) {
super(params);
this._noise = null;
this._lightness = null;
this._static = true;
this._settings = settings;
if (params.noise)
this.noise = params.noise;
if (params.lightness)
this.lightness = params.lightness;
// set shader source
this._source = get_shader_source();
if (this._source)
this.set_shader_source(this._source);
this.update_enabled();
}
get noise() {
return this._noise;
}
set noise(value) {
if (this._noise !== value) {
this._noise = value;
this.set_uniform_value('noise', parseFloat(this._noise - 1e-6));
}
this.update_enabled();
}
get lightness() {
return this._lightness;
}
set lightness(value) {
if (this._lightness !== value) {
this._lightness = value;
this.set_uniform_value('lightness', parseFloat(this._lightness - 1e-6));
}
}
update_enabled() {
// don't anything if this._settings is undefined (when calling super)
if (this._settings === undefined)
return;
this.set_enabled(
this.noise > 0 &&
this._settings.COLOR_AND_NOISE &&
this._static
);
}
vfunc_paint_target(paint_node = null, paint_context = null) {
this.set_uniform_value("tex", 0);
if (paint_node && paint_context)
super.vfunc_paint_target(paint_node, paint_context);
else if (paint_node)
super.vfunc_paint_target(paint_node);
else
super.vfunc_paint_target();
}
});

View File

@ -0,0 +1,89 @@
import GObject from 'gi://GObject';
import Clutter from 'gi://Clutter';
export const PaintSignals = class PaintSignals {
constructor(connections) {
this.buffer = [];
this.connections = connections;
}
connect(actor, blur_effect) {
let paint_effect = new EmitPaintSignal();
let infos = {
actor: actor,
paint_effect: paint_effect
};
let counter = 0;
actor.add_effect(paint_effect);
this.connections.connect(paint_effect, 'update-blur', () => {
try {
// checking if blur_effect.queue_repaint() has been recently called
if (counter === 0) {
counter = 2;
blur_effect.queue_repaint();
}
else counter--;
} catch (e) { }
});
// remove the actor from buffer when it is destroyed
if (
actor.connect &&
(
!(actor instanceof GObject.Object) ||
GObject.signal_lookup('destroy', actor)
)
)
this.connections.connect(actor, 'destroy', () => {
this.buffer.forEach(infos => {
if (infos.actor === actor) {
// remove from buffer
let index = this.buffer.indexOf(infos);
this.buffer.splice(index, 1);
}
});
});
this.buffer.push(infos);
}
disconnect_all_for_actor(actor) {
this.buffer.forEach(infos => {
if (infos.actor === actor) {
this.connections.disconnect_all_for(infos.paint_effect);
infos.actor.remove_effect(infos.paint_effect);
// remove from buffer
let index = this.buffer.indexOf(infos);
this.buffer.splice(index, 1);
}
});
}
disconnect_all() {
this.buffer.forEach(infos => {
this.connections.disconnect_all_for(infos.paint_effect);
infos.actor.remove_effect(infos.paint_effect);
});
this.buffer = [];
}
};
export const EmitPaintSignal = GObject.registerClass({
GTypeName: 'EmitPaintSignal',
Signals: {
'update-blur': {
param_types: []
},
}
},
class EmitPaintSignal extends Clutter.Effect {
vfunc_paint(node, paint_context, paint_flags) {
this.emit("update-blur");
super.vfunc_paint(node, paint_context, paint_flags);
}
}
);

View File

@ -0,0 +1,641 @@
import Meta from 'gi://Meta';
import Clutter from 'gi://Clutter';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js';
import { EffectsManager } from './conveniences/effects_manager.js';
import { Connections } from './conveniences/connections.js';
import { Settings } from './conveniences/settings.js';
import { Keys } from './conveniences/keys.js';
import { PanelBlur } from './components/panel.js';
import { OverviewBlur } from './components/overview.js';
import { DashBlur } from './components/dash_to_dock.js';
import { LockscreenBlur } from './components/lockscreen.js';
import { AppFoldersBlur } from './components/appfolders.js';
import { WindowListBlur } from './components/window_list.js';
import { ApplicationsBlur } from './components/applications.js';
import { ScreenshotBlur } from './components/screenshot.js';
// This lists the components that need to be connected in order to either use
// general sigma/brightness or their own.
const INDEPENDENT_COMPONENTS = [
"overview", "appfolder", "panel", "dash_to_dock", "applications",
"lockscreen", "window_list", "screenshot"
];
/// The main extension class, created when the GNOME Shell is loaded.
export default class BlurMyShell extends Extension {
/// Enables the extension
enable() {
// add the extension to global to make it accessible to other extensions
// create it first as it is very useful when debugging crashes
global.blur_my_shell = this;
// create a Settings instance, to manage extension's preferences
// it needs to be loaded before logging, as it checks for DEBUG
this._settings = new Settings(Keys, this.getSettings());
this._log("enabling extension...");
// create main extension Connections instance
this._connection = new Connections;
// store it in a global array
this._connections = [this._connection];
// create a global effects manager (to prevent RAM bleeding)
this._effects_manager = new EffectsManager(this._connection);
// create an instance of each component, with its associated Connections
let init = _ => {
// create a Connections instance, to manage signals
let connection = new Connections;
// store it to keeps track of them globally
this._connections.push(connection);
return [connection, this._settings, this._effects_manager];
};
this._panel_blur = new PanelBlur(...init());
this._dash_to_dock_blur = new DashBlur(...init());
this._overview_blur = new OverviewBlur(...init());
this._lockscreen_blur = new LockscreenBlur(...init());
this._appfolder_blur = new AppFoldersBlur(...init());
this._window_list_blur = new WindowListBlur(...init());
this._applications_blur = new ApplicationsBlur(...init());
this._screenshot_blur = new ScreenshotBlur(...init());
// maybe disable clipped redraw
this._update_clipped_redraws();
// connect each component to preferences change
this._connect_to_settings();
// enable every component
// if the shell is still starting up, wait for it to be entirely loaded;
// this should prevent bugs like #136 and #137
if (Main.layoutManager._startingUp) {
this._connection.connect(
Main.layoutManager,
'startup-complete',
this._enable_components.bind(this)
);
} else {
this._enable_components();
}
// try to enable the components as soon as possible anyway, this way the
// overview may load before the user sees it
try {
if (this._settings.overview.BLUR && !this._overview_blur.enabled)
this._overview_blur.enable();
} catch (e) {
this._log("Could not enable overview blur directly");
this._log(e);
}
try {
if (this._settings.dash_to_dock.BLUR
&& !this._dash_to_dock_blur.enabled)
this._dash_to_dock_blur.enable();
} catch (e) {
this._log("Could not enable dash-to-dock blur directly");
this._log(e);
}
try {
if (this._settings.panel.BLUR && !this._panel_blur.enabled)
this._panel_blur.enable();
} catch (e) {
this._log("Could not enable panel blur directly");
this._log(e);
}
}
/// Disables the extension
disable() {
this._log("disabling extension...");
// disable every component
this._panel_blur.disable();
this._dash_to_dock_blur.disable();
this._overview_blur.disable();
this._lockscreen_blur.disable();
this._appfolder_blur.disable();
this._window_list_blur.disable();
this._applications_blur.disable();
this._screenshot_blur.disable();
// untrack them
this._panel_blur = null;
this._dash_to_dock_blur = null;
this._overview_blur = null;
this._lockscreen_blur = null;
this._appfolder_blur = null;
this._window_list_blur = null;
this._applications_blur = null;
// make sure no settings change can re-enable them
this._settings.disconnect_all_settings();
// force disconnecting every signal, even if component crashed
this._connections.forEach((connections) => {
connections.disconnect_all();
});
this._connections = [];
// remove the clipped redraws flag
this._reenable_clipped_redraws();
// remove the extension from GJS's global
delete global.blur_my_shell;
this._log("extension disabled.");
this._settings = null;
}
/// Restart the extension.
_restart() {
this._log("restarting...");
this.disable();
this.enable();
this._log("restarted.");
}
/// Add or remove the clutter debug flag to disable clipped redraws.
/// This will entirely fix the blur effect, but should not be used except if
/// the user really needs it, as clipped redraws are a huge performance
/// boost for the compositor.
_update_clipped_redraws() {
if (this._settings.HACKS_LEVEL === 3)
this._disable_clipped_redraws();
else
this._reenable_clipped_redraws();
}
/// Add the Clutter debug flag.
_disable_clipped_redraws() {
Meta.add_clutter_debug_flags(
null, Clutter.DrawDebugFlag.DISABLE_CLIPPED_REDRAWS, null
);
}
/// Remove the Clutter debug flag.
_reenable_clipped_redraws() {
Meta.remove_clutter_debug_flags(
null, Clutter.DrawDebugFlag.DISABLE_CLIPPED_REDRAWS, null
);
}
/// Enables every component needed, should be called when the shell is
/// entirely loaded as the `enable` methods interact with it.
_enable_components() {
// enable each component if needed, and if it is not already enabled
if (this._settings.panel.BLUR && !this._panel_blur.enabled)
this._panel_blur.enable();
if (this._settings.dash_to_dock.BLUR && !this._dash_to_dock_blur.enabled)
this._dash_to_dock_blur.enable();
if (this._settings.overview.BLUR && !this._overview_blur.enabled)
this._overview_blur.enable();
if (this._settings.lockscreen.BLUR)
this._lockscreen_blur.enable();
if (this._settings.appfolder.BLUR)
this._appfolder_blur.enable();
if (this._settings.applications.BLUR)
this._applications_blur.enable();
if (this._settings.window_list.BLUR)
this._window_list_blur.enable();
if (this._settings.screenshot.BLUR)
this._screenshot_blur.enable();
this._log("all components enabled.");
}
/// Updates needed things in each component when a preference changed
_connect_to_settings() {
// global blur values changed, update everybody
this._settings.SIGMA_changed(() => {
this._update_sigma();
});
this._settings.BRIGHTNESS_changed(() => {
this._update_brightness();
});
this._settings.COLOR_changed(() => {
this._update_color();
});
this._settings.NOISE_AMOUNT_changed(() => {
this._update_noise_amount();
});
this._settings.NOISE_LIGHTNESS_changed(() => {
this._update_noise_lightness();
});
this._settings.COLOR_AND_NOISE_changed(() => {
// both updating noise amount and color calls `update_enabled` on
// each color and noise effects
this._update_noise_amount();
this._update_color();
});
// restart the extension when hacks level is changed, easier than
// restarting individual components and should not happen often either
this._settings.HACKS_LEVEL_changed(_ => this._restart());
// connect each component to use the proper sigma/brightness/color
INDEPENDENT_COMPONENTS.forEach(component => {
this._connect_to_individual_settings(component);
});
// other component's preferences changed
// ---------- OVERVIEW ----------
// toggled on/off
this._settings.overview.BLUR_changed(() => {
if (this._settings.overview.BLUR) {
this._overview_blur.enable();
} else {
this._overview_blur.disable();
}
});
// overview components style changed
this._settings.overview.STYLE_COMPONENTS_changed(() => {
if (this._settings.overview.BLUR) {
this._overview_blur.update_components_classname();
}
});
// ---------- APPFOLDER ----------
// toggled on/off
this._settings.appfolder.BLUR_changed(() => {
if (this._settings.appfolder.BLUR) {
this._appfolder_blur.enable();
} else {
this._appfolder_blur.disable();
}
});
// appfolder dialogs style changed
this._settings.appfolder.STYLE_DIALOGS_changed(() => {
if (this._settings.appfolder.BLUR)
this._appfolder_blur.blur_appfolders();
});
// ---------- PANEL ----------
// toggled on/off
this._settings.panel.BLUR_changed(() => {
if (this._settings.panel.BLUR) {
this._panel_blur.enable();
} else {
this._panel_blur.disable();
}
});
this._settings.COLOR_AND_NOISE_changed(() => {
// permits making sure that the blur is not washed out when disabling
// the other effects
if (this._settings.panel.BLUR)
this._panel_blur.invalidate_all_blur();
});
// static blur toggled on/off
this._settings.panel.STATIC_BLUR_changed(() => {
if (this._settings.panel.BLUR)
this._panel_blur.update_all_blur_type();
});
// panel blur's overview connection toggled on/off
this._settings.panel.UNBLUR_IN_OVERVIEW_changed(() => {
this._panel_blur.connect_to_windows_and_overview();
});
// panel override background toggled on/off
this._settings.panel.OVERRIDE_BACKGROUND_changed(() => {
if (this._settings.panel.BLUR)
this._panel_blur.connect_to_windows_and_overview();
});
// panel style changed
this._settings.panel.STYLE_PANEL_changed(() => {
if (this._settings.panel.BLUR)
this._panel_blur.connect_to_windows_and_overview();
});
// panel background's dynamic overriding toggled on/off
this._settings.panel.OVERRIDE_BACKGROUND_DYNAMICALLY_changed(() => {
if (this._settings.panel.BLUR)
this._panel_blur.connect_to_windows_and_overview();
});
// ---------- DASH TO DOCK ----------
// toggled on/off
this._settings.dash_to_dock.BLUR_changed(() => {
if (this._settings.dash_to_dock.BLUR) {
this._dash_to_dock_blur.enable();
} else {
this._dash_to_dock_blur.disable();
}
});
// TODO implement static blur for dash
// static blur toggled on/off
this._settings.dash_to_dock.STATIC_BLUR_changed(() => {
//if (this._settings.dash_to_dock.BLUR)
// this._dash_to_dock_blur.change_blur_type();
});
// dash-to-dock override background toggled on/off
this._settings.dash_to_dock.OVERRIDE_BACKGROUND_changed(() => {
if (this._settings.dash_to_dock.BLUR)
this._dash_to_dock_blur.update_background();
});
// dash-to-dock style changed
this._settings.dash_to_dock.STYLE_DASH_TO_DOCK_changed(() => {
if (this._settings.dash_to_dock.BLUR)
this._dash_to_dock_blur.update_background();
});
// dash-to-dock blur's overview connection toggled on/off
this._settings.dash_to_dock.UNBLUR_IN_OVERVIEW_changed(() => {
if (this._settings.dash_to_dock.BLUR)
this._dash_to_dock_blur.connect_to_overview();
});
// ---------- APPLICATIONS ----------
// toggled on/off
this._settings.applications.BLUR_changed(() => {
if (this._settings.applications.BLUR) {
this._applications_blur.enable();
} else {
this._applications_blur.disable();
}
});
// application opacity changed
this._settings.applications.OPACITY_changed(_ => {
if (this._settings.applications.BLUR)
this._applications_blur.set_opacity(
this._settings.applications.OPACITY
);
});
// application blur-on-overview changed
this._settings.applications.BLUR_ON_OVERVIEW_changed(_ => {
if (this._settings.applications.BLUR)
this._applications_blur.connect_to_overview();
});
// application enable-all changed
this._settings.applications.ENABLE_ALL_changed(_ => {
if (this._settings.applications.BLUR)
this._applications_blur.update_all_windows();
});
// application whitelist changed
this._settings.applications.WHITELIST_changed(_ => {
if (
this._settings.applications.BLUR
&& !this._settings.applications.ENABLE_ALL
)
this._applications_blur.update_all_windows();
});
// application blacklist changed
this._settings.applications.BLACKLIST_changed(_ => {
if (
this._settings.applications.BLUR
&& this._settings.applications.ENABLE_ALL
)
this._applications_blur.update_all_windows();
});
// ---------- LOCKSCREEN ----------
// toggled on/off
this._settings.lockscreen.BLUR_changed(() => {
if (this._settings.lockscreen.BLUR) {
this._lockscreen_blur.enable();
} else {
this._lockscreen_blur.disable();
}
});
// ---------- WINDOW LIST ----------
// toggled on/off
this._settings.window_list.BLUR_changed(() => {
if (this._settings.window_list.BLUR) {
this._window_list_blur.enable();
} else {
this._window_list_blur.disable();
}
});
// ---------- HIDETOPBAR ----------
// toggled on/off
this._settings.hidetopbar.COMPATIBILITY_changed(() => {
// no need to verify if it is enabled or not, it is done anyway
this._panel_blur.connect_to_windows_and_overview();
});
// ---------- DASH TO PANEL ----------
// toggled on/off
this._settings.dash_to_panel.BLUR_ORIGINAL_PANEL_changed(() => {
if (this._settings.panel.BLUR)
this._panel_blur.reset();
});
// ---------- SCREENSHOT ----------
// toggled on/off
this._settings.screenshot.BLUR_changed(() => {
if (this._settings.screenshot.BLUR) {
this._screenshot_blur.enable();
} else {
this._screenshot_blur.disable();
}
});
}
/// Select the component by its name and connect it to its preferences
/// changes for general values, sigma and brightness.
///
/// Doing this in such a way is less accessible but prevents a lot of
/// boilerplate and headaches.
_connect_to_individual_settings(name) {
// get component and preferences needed
let component = this['_' + name + '_blur'];
let component_settings = this._settings[name];
// general values switch is toggled
component_settings.CUSTOMIZE_changed(() => {
if (component_settings.CUSTOMIZE) {
component.set_sigma(component_settings.SIGMA);
component.set_brightness(component_settings.BRIGHTNESS);
component.set_color(component_settings.COLOR);
component.set_noise_amount(component_settings.NOISE_AMOUNT);
component.set_noise_lightness(component_settings.NOISE_LIGHTNESS);
}
else {
component.set_sigma(this._settings.SIGMA);
component.set_brightness(this._settings.BRIGHTNESS);
component.set_color(this._settings.COLOR);
component.set_noise_amount(this._settings.NOISE_AMOUNT);
component.set_noise_lightness(this._settings.NOISE_LIGHTNESS);
}
});
// sigma is changed
component_settings.SIGMA_changed(() => {
if (component_settings.CUSTOMIZE)
component.set_sigma(component_settings.SIGMA);
else
component.set_sigma(this._settings.SIGMA);
});
// brightness is changed
component_settings.BRIGHTNESS_changed(() => {
if (component_settings.CUSTOMIZE)
component.set_brightness(component_settings.BRIGHTNESS);
else
component.set_brightness(this._settings.BRIGHTNESS);
});
// color is changed
component_settings.COLOR_changed(() => {
if (component_settings.CUSTOMIZE)
component.set_color(component_settings.COLOR);
else
component.set_color(this._settings.COLOR);
});
// noise amount is changed
component_settings.NOISE_AMOUNT_changed(() => {
if (component_settings.CUSTOMIZE)
component.set_noise_amount(component_settings.NOISE_AMOUNT);
else
component.set_noise_amount(this._settings.NOISE_AMOUNT);
});
// noise lightness is changed
component_settings.NOISE_LIGHTNESS_changed(() => {
if (component_settings.CUSTOMIZE)
component.set_noise_lightness(component_settings.NOISE_LIGHTNESS);
else
component.set_noise_lightness(this._settings.NOISE_LIGHTNESS);
});
}
/// Update each component's sigma value
_update_sigma() {
INDEPENDENT_COMPONENTS.forEach(name => {
// get component and preferences needed
let component = this['_' + name + '_blur'];
let component_settings = this._settings[name];
// update sigma accordingly
if (component_settings.CUSTOMIZE) {
component.set_sigma(component_settings.SIGMA);
}
else {
component.set_sigma(this._settings.SIGMA);
}
});
}
/// Update each component's brightness value
_update_brightness() {
INDEPENDENT_COMPONENTS.forEach(name => {
// get component and preferences needed
let component = this['_' + name + '_blur'];
let component_settings = this._settings[name];
// update brightness accordingly
if (component_settings.CUSTOMIZE)
component.set_brightness(component_settings.BRIGHTNESS);
else
component.set_brightness(this._settings.BRIGHTNESS);
});
}
/// Update each component's color value
_update_color() {
INDEPENDENT_COMPONENTS.forEach(name => {
// get component and preferences needed
let component = this['_' + name + '_blur'];
let component_settings = this._settings[name];
// update color accordingly
if (component_settings.CUSTOMIZE)
component.set_color(component_settings.COLOR);
else
component.set_color(this._settings.COLOR);
});
}
/// Update each component's noise amount value
_update_noise_amount() {
INDEPENDENT_COMPONENTS.forEach(name => {
// get component and preferences needed
let component = this['_' + name + '_blur'];
let component_settings = this._settings[name];
// update color accordingly
if (component_settings.CUSTOMIZE)
component.set_noise_amount(component_settings.NOISE_AMOUNT);
else
component.set_noise_amount(this._settings.NOISE_AMOUNT);
});
}
/// Update each component's noise lightness value
_update_noise_lightness() {
INDEPENDENT_COMPONENTS.forEach(name => {
// get component and preferences needed
let component = this['_' + name + '_blur'];
let component_settings = this._settings[name];
// update color accordingly
if (component_settings.CUSTOMIZE)
component.set_noise_lightness(component_settings.NOISE_LIGHTNESS);
else
component.set_noise_lightness(this._settings.NOISE_LIGHTNESS);
});
}
_log(str) {
if (this._settings.DEBUG)
console.log(`[Blur my Shell > extension] ${str}`);
}
}

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="7" width="11" height="1" fill="#363636"/>
<rect transform="rotate(90)" x="2" y="-8" width="11" height="1" fill="#363636"/>
</svg>

After

Width:  |  Height:  |  Size: 249 B

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="16"
height="16"
version="1.1"
viewBox="0 0 16 16"
id="svg7"
sodipodi:docname="applications.svg"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview9"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="44.6875"
inkscape:cx="5.5944056"
inkscape:cy="8"
inkscape:window-width="1500"
inkscape:window-height="963"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg7" />
<defs
id="defs3">
<style
id="current-color-scheme"
type="text/css">.ColorScheme-Text { color:#363636; }</style>
</defs>
<path
d="M 2,1 C 0.892,1 0,1.892 0,3 v 9 c 0,1.108 0.892,2 2,2 h 12 c 1.108,0 2,-0.892 2,-2 V 3 C 16,1.892 15.108,1 14,1 Z m 0,1 h 12 c 0.554,0 1,0.446 1,1 H 1 C 1,2.446 1.446,2 2,2 Z M 1,3 h 14 v 9 c 0,0.554 -0.446,1 -1,1 H 2 C 1.446,13 1,12.554 1,12 Z"
style="fill:currentColor"
class="ColorScheme-Text"
id="path5"
sodipodi:nodetypes="sssssssssssccsccssssc" />
<g
id="g68"
transform="translate(0.3993007,0.15314685)">
<path
d="M 9.5,4 C 9.223,4 9,4.223 9,4.5 v 2 A 0.499,0.499 0 0 0 9.5,7 h 2 C 11.777,7 12,6.777 12,6.5 v -2 C 12,4.223 11.777,4 11.5,4 Z M 10,5 h 1 v 1 h -1 z"
fill="#363636"
id="path2" />
<path
d="M 4,6 C 3.446,6 3,6.446 3,7 v 3 c 0,0.554 0.446,1 1,1 h 3 c 0.554,0 1,-0.446 1,-1 V 7 C 8,6.446 7.554,6 7,6 Z m 0,1 h 3 v 3 H 4 Z"
fill="#363636"
id="path8" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="16"
height="16"
version="1.1"
viewBox="0 0 16 16"
id="svg7"
sodipodi:docname="panel.svg"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview9"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="44.6875"
inkscape:cx="5.5944056"
inkscape:cy="8"
inkscape:window-width="1500"
inkscape:window-height="963"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg7" />
<defs
id="defs3">
<style
id="current-color-scheme"
type="text/css">.ColorScheme-Text { color:#363636; }</style>
</defs>
<path
d="M 2,1 C 0.892,1 0,1.892 0,3 v 9 c 0,1.108 0.892,2 2,2 h 12 c 1.108,0 2,-0.892 2,-2 V 3 C 16,1.892 15.108,1 14,1 Z m 0,1 h 12 c 0.554,0 1,0.446 1,1 H 1 C 1,2.446 1.446,2 2,2 Z M 1,4 h 14 v 8 c 0,0.554 -0.446,1 -1,1 H 2 C 1.446,13 1,12.554 1,12 Z"
style="fill:currentColor"
class="ColorScheme-Text"
id="path5"
sodipodi:nodetypes="sssssssssssccsccssssc" />
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="16"
height="16"
version="1.1"
viewBox="0 0 16 16"
id="svg7"
sodipodi:docname="top-panel.svg"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview9"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="44.6875"
inkscape:cx="5.5944056"
inkscape:cy="8"
inkscape:window-width="1500"
inkscape:window-height="963"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg7" />
<defs
id="defs3">
<style
id="current-color-scheme"
type="text/css">.ColorScheme-Text { color:#363636; }</style>
</defs>
<path
d="M 2,1 C 0.892,1 0,1.892 0,3 v 9 c 0,1.108 0.892,2 2,2 h 12 c 1.108,0 2,-0.892 2,-2 V 3 C 16,1.892 15.108,1 14,1 Z m 0,1 h 12 c 0.554,0 1,0.446 1,1 H 1 C 1,2.446 1.446,2 2,2 Z M 1,3 h 14 v 9 c 0,0.554 -0.446,1 -1,1 H 2 C 1.446,13 1,12.554 1,12 Z m 3,7 c -0.554,0 -1,0.446 -1,1 0,0.554 0.446,1 1,1 h 8 c 0.554,0 1,-0.446 1,-1 0,-0.554 -0.446,-1 -1,-1 z"
style="fill:currentColor"
class="ColorScheme-Text"
id="path5"
sodipodi:nodetypes="sssssssssssccsccsssscsssssss" />
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="16"
height="16"
enable-background="new"
version="1.1"
id="svg16"
sodipodi:docname="general-symbolic.svg"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs20" />
<sodipodi:namedview
id="namedview18"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="24.174578"
inkscape:cx="13.98163"
inkscape:cy="8.3765683"
inkscape:window-width="1500"
inkscape:window-height="963"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g14" />
<g
fill="#363636"
id="g14"
transform="rotate(90,7.75,8.25)">
<path
d="m 2.9500144,1 c -0.277,0 -0.5,0.223 -0.5,0.5 v 6.5547 a 2.5,2.5 0 0 1 0.5,-0.054688 2.5,2.5 0 0 1 0.5,0.050781 v -6.5508 c 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 0.5,11.945 a 2.5,2.5 0 0 1 -0.5,0.05469 2.5,2.5 0 0 1 -0.5,-0.05078 v 1.5508 c 0,0.277 0.223,0.5 0.5,0.5 0.277,0 0.5,-0.223 0.5,-0.5 v -1.5547 z"
id="path2" />
<path
d="M 7.5,1 C 7.223,1 7,1.223 7,1.5 V 3.0547 A 2.5,2.5 0 0 1 7.5,3.000012 2.5,2.5 0 0 1 8,3.050793 v -1.5508 c 0,-0.277 -0.223,-0.5 -0.5,-0.5 z M 8,7.9453 A 2.5,2.5 0 0 1 7.5,7.999988 2.5,2.5 0 0 1 7,7.949207 v 6.5508 c 0,0.277 0.223,0.5 0.5,0.5 0.277,0 0.5,-0.223 0.5,-0.5 v -6.5547 z"
id="path4" />
<path
d="m 12.049986,1.0001482 c -0.277,0 -0.5,0.223 -0.5,0.5 v 6.5547 a 2.5,2.5 0 0 1 0.5,-0.054688 2.5,2.5 0 0 1 0.5,0.050781 v -6.5508 c 0,-0.277 -0.223,-0.5 -0.5,-0.5 z m 0.5,11.9450008 a 2.5,2.5 0 0 1 -0.5,0.05469 2.5,2.5 0 0 1 -0.5,-0.05078 v 1.5508 c 0,0.276999 0.223,0.5 0.5,0.5 0.277,0 0.5,-0.223001 0.5,-0.5 v -1.5547 z"
id="path6" />
<circle
cx="2.9500144"
cy="10.5"
id="circle8"
r="1.5" />
<circle
cx="7.5"
cy="5.5"
r="1.5"
id="circle10" />
<circle
cx="12.049986"
cy="10.500149"
id="circle12"
r="1.5" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="16"
height="16"
version="1.1"
viewBox="0 0 16 16"
id="svg7"
sodipodi:docname="heart-filled-symbolic.svg"
inkscape:version="1.2 (dc2aedaf03, 2022-05-15)"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview9"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="31.598834"
inkscape:cx="4.6046002"
inkscape:cy="6.2344072"
inkscape:window-width="1920"
inkscape:window-height="1043"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg7"
inkscape:showpageshadow="0"
inkscape:deskcolor="#d1d1d1" /><defs
id="defs3"><style
id="current-color-scheme"
type="text/css">.ColorScheme-Text { color:#363636; }</style></defs><path
d="M 11.846993,1.3381264 C 10.739505,1.3069919 9.6587026,1.7072882 8.8403186,2.4589575 L 7.981904,3.2284167 7.1190425,2.4589575 C 5.9848678,1.4359762 4.3836806,1.1023952 2.9337159,1.5827525 1.4793039,2.0586601 0.3940558,3.2773422 0.08716067,4.7762309 -0.21973329,6.2751198 0.29620488,7.8229343 1.4392744,8.8370195 L 7.981904,14.663563 14.520086,8.8370195 C 15.854409,7.685054 16.343662,5.8303457 15.75211,4.171338 15.160562,2.5123304 13.608299,1.3870507 11.846993,1.3381264 Z m 0,0"
fill="#222222"
id="path866"
style="stroke-width:1.13863" /></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" enable-background="new"><defs><filter id="a" color-interpolation-filters="sRGB"><feBlend mode="darken" in2="BackgroundImage"/></filter></defs><g transform="matrix(0 -1 -1 0 -413 -83.997)" color="#000" fill="#dedede"><rect y="-418" x="-92.997" width="2" style="marker:none" ry="1" rx="1" height="2" overflow="visible" enable-background="new"/><rect y="-422" x="-92.997" width="2" style="marker:none" ry="1" rx="1" height="2" overflow="visible" enable-background="new"/><rect y="-426" x="-92.997" width="2" style="marker:none" ry="1" rx="1" height="2" overflow="visible" enable-background="new"/></g></svg>

After

Width:  |  Height:  |  Size: 667 B

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="16"
height="16"
version="1.1"
viewBox="0 0 16 16"
id="svg7"
sodipodi:docname="overview.svg"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview9"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="44.6875"
inkscape:cx="5.5944056"
inkscape:cy="8"
inkscape:window-width="1500"
inkscape:window-height="963"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g68"
inkscape:snap-bbox="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true" />
<defs
id="defs3">
<style
id="current-color-scheme"
type="text/css">.ColorScheme-Text { color:#363636; }</style>
</defs>
<path
d="M 2,1 C 0.892,1 0,1.892 0,3 v 9 c 0,1.108 0.892,2 2,2 h 12 c 1.108,0 2,-0.892 2,-2 V 3 C 16,1.892 15.108,1 14,1 Z m 0,1 h 12 c 0.554,0 1,0.446 1,1 H 1 C 1,2.446 1.446,2 2,2 Z M 1,3 h 14 v 9 c 0,0.554 -0.446,1 -1,1 H 2 C 1.446,13 1,12.554 1,12 Z"
style="fill:currentColor"
class="ColorScheme-Text"
id="path5"
sodipodi:nodetypes="sssssssssssccsccssssc" />
<g
id="g68"
transform="translate(0.3993007,0.15314685)">
<path
d="m 3.1756095,3.5602457 c -0.8440582,0 -1,0.446 -1,1 v 5.5732153 c 0,0.677136 0.446,1 1,1 H 12.02579 c 0.554,0 0.999999,-0.446 0.999999,-1 V 4.5602457 c 0,-0.554 -0.445999,-1 -0.999999,-1 z m 0,1 H 12.02579 V 10.133461 H 3.1756095 Z"
fill="#363636"
id="path8"
sodipodi:nodetypes="sssssssssccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="m4.4647 3.9648c-0.12775 0-0.2555 0.048567-0.35339 0.14649-0.19578 0.19586-0.19578 0.51116 0 0.70703l3.1816 3.1816-3.1816 3.1816c-0.19578 0.19586-0.19578 0.51116 0 0.70703 0.19578 0.19586 0.51118 0.19586 0.70704 0l3.1816-3.1816 3.1816 3.1816c0.19578 0.19586 0.51114 0.19586 0.70704 0 0.19578-0.19586 0.19578-0.51116 0-0.70703l-3.1816-3.1816 3.1816-3.1816c0.19578-0.19586 0.19578-0.51116 0-0.70703-0.19578-0.19586-0.51118-0.19586-0.70704 0l-3.1816 3.1816-3.1816-3.1816c-0.09789-0.097928-0.22564-0.14649-0.35339-0.14649z" fill="#363636" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.9149" style="paint-order:stroke fill markers"/>
</svg>

After

Width:  |  Height:  |  Size: 740 B

View File

@ -0,0 +1,7 @@
<svg width="16" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
<g fill="#363636">
<path d="m8 3a6 6 0 0 0-6 6 6 6 0 0 0 6 6 6 6 0 0 0 6-6h-1a5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5z"/>
<path d="m8.1719 0.67188-0.70703 0.70703 2.1211 2.1211-2.1211 2.1211 0.70703 0.70703 2.8281-2.8281-0.70703-0.70703z"/>
<rect x="8" y="3" width="2" height="1"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 406 B

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 2.953125 1.074219 l 2.417969 13.210937 l 3.238281 -2.398437 l 2.054687 2.648437 c 1.03125 1.433594 3.148438 -0.210937 2.011719 -1.5625 l -2.015625 -2.59375 l 2.984375 -2.175781 z m 0 0" fill="#222222"/></svg>

After

Width:  |  Height:  |  Size: 346 B

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 2.953125 1.074219 l 2.417969 13.210937 l 3.238281 -2.398437 l 2.054687 2.648437 c 1.03125 1.433594 3.148438 -0.210937 2.011719 -1.5625 l -2.015625 -2.59375 l 2.984375 -2.175781 z m 0 0" fill="#222222"/></svg>

After

Width:  |  Height:  |  Size: 346 B

View File

@ -0,0 +1,20 @@
{
"_generated": "Generated by SweetTooth, do not edit",
"description": "Adds a blur look to different parts of the GNOME Shell, including the top panel, dash and overview.\n\nYou can support my work by sponsoring me on:\n- github: https://github.com/sponsors/aunetx\n- ko-fi: https://ko-fi.com/aunetx\n\nNote: if the extension shows an error after updating, please make sure to restart your session to see if it persists. This is due to a bug in gnome shell, which I can't fix by myself.",
"donations": {
"github": "aunetx",
"kofi": "aunetx"
},
"gettext-domain": "blur-my-shell",
"name": "Blur my Shell",
"original-authors": [
"me@aunetx.dev"
],
"settings-schema": "org.gnome.shell.extensions.blur-my-shell",
"shell-version": [
"45"
],
"url": "https://github.com/aunetx/gnome-shell-extension-blur-my-shell",
"uuid": "blur-my-shell@aunetx",
"version": 54
}

View File

@ -0,0 +1,174 @@
import Adw from 'gi://Adw';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Gio from 'gi://Gio';
import { WindowRow } from './window_row.js';
const make_array = prefs_group => {
let list_box = prefs_group
.get_first_child()
.get_last_child()
.get_first_child();
let elements = [];
let i = 0;
let element = list_box.get_row_at_index(i);
while (element) {
elements.push(element);
i++;
element = list_box.get_row_at_index(i);
}
return elements;
};
export const Applications = GObject.registerClass({
GTypeName: 'Applications',
Template: GLib.uri_resolve_relative(import.meta.url, '../ui/applications.ui', GLib.UriFlags.NONE),
InternalChildren: [
'blur',
'customize',
'opacity',
'blur_on_overview',
'enable_all',
'whitelist',
'add_window_whitelist',
'blacklist',
'add_window_blacklist'
],
}, class Applications extends Adw.PreferencesPage {
constructor(preferences, preferences_window) {
super({});
this._preferences_window = preferences_window;
this.preferences = preferences;
this.preferences.applications.settings.bind(
'blur', this._blur, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.applications.settings.bind(
'opacity', this._opacity, 'value',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.applications.settings.bind(
'blur-on-overview', this._blur_on_overview, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.applications.settings.bind(
'enable-all', this._enable_all, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this._customize.connect_to(this.preferences, this.preferences.applications, false);
// connect 'enable all' button to whitelist/blacklist visibility
this._enable_all.bind_property(
'active', this._whitelist, 'visible',
GObject.BindingFlags.INVERT_BOOLEAN
);
this._enable_all.bind_property(
'active', this._blacklist, 'visible',
GObject.BindingFlags.DEFAULT
);
// make sure that blacklist / whitelist is correctly hidden
if (this._enable_all.active)
this._whitelist.visible = false;
this._blacklist.visible = !this._whitelist.visible;
// listen to app row addition
this._add_window_whitelist.connect('clicked',
_ => this.add_to_whitelist()
);
this._add_window_blacklist.connect('clicked',
_ => this.add_to_blacklist()
);
// add initial applications
this.add_widgets_from_lists();
this.preferences.connect('reset', _ => {
this.remove_all_widgets();
this.add_widgets_from_lists();
});
}
// A way to retriew the whitelist widgets.
get _whitelist_elements() {
return make_array(this._whitelist);
}
// A way to retriew the blacklist widgets.
get _blacklist_elements() {
return make_array(this._blacklist);
}
add_widgets_from_lists() {
this.preferences.applications.WHITELIST.forEach(
app_name => this.add_to_whitelist(app_name)
);
this.preferences.applications.BLACKLIST.forEach(
app_name => this.add_to_blacklist(app_name)
);
}
close_all_expanded_rows() {
this._whitelist_elements.forEach(
element => element.set_expanded(false)
);
this._blacklist_elements.forEach(
element => element.set_expanded(false)
);
}
remove_all_widgets() {
this._whitelist_elements.forEach(
element => this._whitelist.remove(element)
);
this._blacklist_elements.forEach(
element => this._blacklist.remove(element)
);
}
add_to_whitelist(app_name = null) {
let window_row = new WindowRow('whitelist', this, app_name);
this._whitelist.add(window_row);
}
add_to_blacklist(app_name = null) {
let window_row = new WindowRow('blacklist', this, app_name);
this._blacklist.add(window_row);
}
update_whitelist_titles() {
let titles = this._whitelist_elements
.map(element => element._window_class.buffer.text)
.filter(title => title != "");
this.preferences.applications.WHITELIST = titles;
}
update_blacklist_titles() {
let titles = this._blacklist_elements
.map(element => element._window_class.buffer.text)
.filter(title => title != "");
this.preferences.applications.BLACKLIST = titles;
}
remove_from_whitelist(widget) {
this._whitelist.remove(widget);
this.update_whitelist_titles();
}
remove_from_blacklist(widget) {
this._blacklist.remove(widget);
this.update_blacklist_titles();
}
});

View File

@ -0,0 +1,163 @@
import Adw from 'gi://Adw';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Gio from 'gi://Gio';
import Gtk from 'gi://Gtk';
/// Given a component (described by its preferences node), a gschema key and
/// a Gtk.ColorButton, binds everything transparently.
let bind_color = function (component, key, widget) {
let property_name = key.replaceAll('-', '_').toUpperCase();
let parse_color = _ => {
let [r, g, b, a] = component[property_name];
let w = widget.rgba;
w.red = r;
w.green = g;
w.blue = b;
w.alpha = a;
widget.rgba = w;
};
component.settings.connect('changed::' + key, parse_color);
widget.connect('color-set', _ => {
let c = widget.rgba;
component[property_name] = [c.red, c.green, c.blue, c.alpha];
});
parse_color();
};
export const CustomizeRow = GObject.registerClass({
GTypeName: 'CustomizeRow',
Template: GLib.uri_resolve_relative(import.meta.url, '../ui/customize-row.ui', GLib.UriFlags.NONE),
InternalChildren: [
'sigma',
'brightness',
'color',
'color_row',
'noise_amount',
'noise_amount_row',
'noise_lightness',
'noise_lightness_row',
'noise_color_notice'
],
}, class CustomizeRow extends Adw.ExpanderRow {
/// Makes the required connections between the widgets and the preferences.
///
/// This function may be bound to another object than CustomizeRow, if we
/// are using it for the General page; some things will then change (no
/// expansion row, and no notice)
///
/// The color_and_noise parameter is either a boolean (true by default) or
/// a widget; and permits selecting weather or not we want to show the color
/// and noise buttons to the user. If it is a widget, it means we need to
/// dynamically update their visibility, according to the widget's state.
connect_to(settings, component_settings, color_and_noise = true) {
let s = component_settings.settings;
// is not fired if in General page
if (this instanceof CustomizeRow)
// bind the customize button
s.bind(
'customize', this, 'enable-expansion',
Gio.SettingsBindFlags.DEFAULT
);
// bind sigma and brightness
s.bind(
'sigma', this._sigma, 'value',
Gio.SettingsBindFlags.DEFAULT
);
s.bind(
'brightness', this._brightness, 'value',
Gio.SettingsBindFlags.DEFAULT
);
// bind the color button
bind_color(component_settings, 'color', this._color);
// bind noise sliders
s.bind(
'noise-amount', this._noise_amount, 'value',
Gio.SettingsBindFlags.DEFAULT
);
s.bind(
'noise-lightness', this._noise_lightness, 'value',
Gio.SettingsBindFlags.DEFAULT
);
// color_and_noise is either a boolean or a widget, if true, or it is a
// widget, this will appropriately show the required preferences about
// setting the color and noise
if (color_and_noise) {
// if we gave the static_blur widget, we are dealing with the panel,
// and binding it to enable/disable the required components when
// switching between static and dynamic blur
if (color_and_noise instanceof Gtk.Switch) {
// bind its state to dynamically toggle the notice and rows
color_and_noise.bind_property(
'active', this._color_row, 'visible',
GObject.BindingFlags.SYNC_CREATE
);
color_and_noise.bind_property(
'active', this._noise_amount_row, 'visible',
GObject.BindingFlags.SYNC_CREATE
);
color_and_noise.bind_property(
'active', this._noise_lightness_row, 'visible',
GObject.BindingFlags.SYNC_CREATE
);
color_and_noise.bind_property(
'active', this._noise_color_notice, 'visible',
GObject.BindingFlags.INVERT_BOOLEAN
);
// only way to get the correct state when first opening the
// window...
setTimeout(_ => {
let is_visible = color_and_noise.active;
this._color_row.visible = is_visible;
this._noise_amount_row.visible = is_visible;
this._noise_lightness_row.visible = is_visible;
this._noise_color_notice.visible = !is_visible;
}, 10);
}
// if in General page, there is no notice at all
if (this instanceof CustomizeRow) {
// disable the notice
this._noise_color_notice.visible = false;
}
} else {
// enable the notice and disable color and noise preferences
this._color_row.visible = false;
this._noise_amount_row.visible = false;
this._noise_lightness_row.visible = false;
this._noise_color_notice.visible = true;
}
// now we bind the color-and-noise preference to the sensitivity of the
// associated widgets, this will grey them out if the user choose not to
// have color and noise enabled
// note: I would love to bind to the visibility instead, but this part
// is already dirty enough, it would look like I obfuscate my code
// intentionally... (I am not)
settings.settings.bind(
'color-and-noise',
this._color_row, 'sensitive',
Gio.SettingsBindFlags.DEFAULT
);
settings.settings.bind(
'color-and-noise',
this._noise_amount_row, 'sensitive',
Gio.SettingsBindFlags.DEFAULT
);
settings.settings.bind(
'color-and-noise',
this._noise_lightness_row, 'sensitive',
Gio.SettingsBindFlags.DEFAULT
);
};
});

View File

@ -0,0 +1,43 @@
import Adw from 'gi://Adw';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Gio from 'gi://Gio';
export const Dash = GObject.registerClass({
GTypeName: 'Dash',
Template: GLib.uri_resolve_relative(import.meta.url, '../ui/dash.ui', GLib.UriFlags.NONE),
InternalChildren: [
'blur',
'customize',
'override_background',
'style_dash_to_dock',
'unblur_in_overview'
],
}, class Dash extends Adw.PreferencesPage {
constructor(preferences) {
super({});
this.preferences = preferences;
this.preferences.dash_to_dock.settings.bind(
'blur', this._blur, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.dash_to_dock.settings.bind(
'override-background',
this._override_background, 'enable-expansion',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.dash_to_dock.settings.bind(
'style-dash-to-dock', this._style_dash_to_dock, 'selected',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.dash_to_dock.settings.bind(
'unblur-in-overview', this._unblur_in_overview, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this._customize.connect_to(this.preferences, this.preferences.dash_to_dock, false);
}
});

View File

@ -0,0 +1,49 @@
import Adw from 'gi://Adw';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Gio from 'gi://Gio';
import { CustomizeRow } from './customize_row.js';
export const General = GObject.registerClass({
GTypeName: 'General',
Template: GLib.uri_resolve_relative(import.meta.url, '../ui/general.ui', GLib.UriFlags.NONE),
InternalChildren: [
'sigma',
'brightness',
'color',
'color_row',
'noise_amount',
'noise_amount_row',
'noise_lightness',
'noise_lightness_row',
'color_and_noise',
'hack_level',
'debug',
'reset'
],
}, class General extends Adw.PreferencesPage {
constructor(preferences) {
super({});
this.preferences = preferences;
CustomizeRow.prototype.connect_to.call(this, preferences, preferences);
this.preferences.settings.bind(
'color-and-noise', this._color_and_noise, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.settings.bind(
'hacks-level', this._hack_level, 'selected',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.settings.bind(
'debug', this._debug, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this._reset.connect('clicked', _ => this.preferences.reset());
}
});

View File

@ -0,0 +1,67 @@
import Gdk from 'gi://Gdk';
import Gtk from 'gi://Gtk';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
export function addMenu(window) {
const builder = new Gtk.Builder();
// add a dummy page and remove it immediately, to access headerbar
builder.add_from_file(GLib.filename_from_uri(GLib.uri_resolve_relative(import.meta.url, '../ui/menu.ui', GLib.UriFlags.NONE))[0]);
let menu_util = builder.get_object('menu_util');
window.add(menu_util);
try {
addMenuToHeader(window, builder);
} catch (error) {
// could not add menu... not so bad
}
window.remove(menu_util);
}
function addMenuToHeader(window, builder) {
// a little hack to get to the headerbar
const page = builder.get_object('menu_util');
const pages_stack = page.get_parent(); // AdwViewStack
const content_stack = pages_stack.get_parent().get_parent(); // GtkStack
const preferences = content_stack.get_parent(); // GtkBox
const headerbar = preferences.get_first_child(); // AdwHeaderBar
headerbar.pack_start(builder.get_object('info_menu'));
// setup menu actions
const actionGroup = new Gio.SimpleActionGroup();
window.insert_action_group('prefs', actionGroup);
// a list of actions with their associated link
const actions = [
{
name: 'open-bug-report',
link: 'https://github.com/aunetx/blur-my-shell/issues'
},
{
name: 'open-readme',
link: 'https://github.com/aunetx/blur-my-shell'
},
{
name: 'open-license',
link: 'https://github.com/aunetx/blur-my-shell/blob/master/LICENSE'
},
{
name: 'donate-github',
link: 'https://github.com/sponsors/aunetx'
},
{
name: 'donate-kofi',
link: 'https://ko-fi.com/aunetx'
},
];
actions.forEach(action => {
let act = new Gio.SimpleAction({ name: action.name });
act.connect(
'activate',
_ => Gtk.show_uri(window, action.link, Gdk.CURRENT_TIME)
);
actionGroup.add_action(act);
});
}

View File

@ -0,0 +1,49 @@
import Adw from 'gi://Adw';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Gio from 'gi://Gio';
export const Other = GObject.registerClass({
GTypeName: 'Other',
Template: GLib.uri_resolve_relative(import.meta.url, '../ui/other.ui', GLib.UriFlags.NONE),
InternalChildren: [
'lockscreen_blur',
'lockscreen_customize',
'screenshot_blur',
'screenshot_customize',
'window_list_blur',
'window_list_customize',
],
}, class Overview extends Adw.PreferencesPage {
constructor(preferences) {
super({});
this.preferences = preferences;
this.preferences.lockscreen.settings.bind(
'blur', this._lockscreen_blur, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this._lockscreen_customize.connect_to(this.preferences, this.preferences.lockscreen);
this.preferences.screenshot.settings.bind(
'blur', this._screenshot_blur, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this._screenshot_customize.connect_to(this.preferences, this.preferences.screenshot);
this.preferences.window_list.settings.bind(
'blur', this._window_list_blur, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this._window_list_customize.connect_to(
this.preferences, this.preferences.window_list, false
);
}
});

View File

@ -0,0 +1,47 @@
import Adw from 'gi://Adw';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Gio from 'gi://Gio';
export const Overview = GObject.registerClass({
GTypeName: 'Overview',
Template: GLib.uri_resolve_relative(import.meta.url, '../ui/overview.ui', GLib.UriFlags.NONE),
InternalChildren: [
'overview_blur',
'overview_customize',
'overview_style_components',
'appfolder_blur',
'appfolder_customize',
'appfolder_style_dialogs'
],
}, class Overview extends Adw.PreferencesPage {
constructor(preferences) {
super({});
this.preferences = preferences;
this.preferences.overview.settings.bind(
'blur', this._overview_blur, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.overview.settings.bind(
'style-components', this._overview_style_components, 'selected',
Gio.SettingsBindFlags.DEFAULT
);
this._overview_customize.connect_to(this.preferences, this.preferences.overview);
this.preferences.appfolder.settings.bind(
'blur', this._appfolder_blur, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.appfolder.settings.bind(
'style-dialogs', this._appfolder_style_dialogs, 'selected',
Gio.SettingsBindFlags.DEFAULT
);
this._appfolder_customize.connect_to(this.preferences, this.preferences.appfolder, false);
}
});

View File

@ -0,0 +1,65 @@
import Adw from 'gi://Adw';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Gio from 'gi://Gio';
export const Panel = GObject.registerClass({
GTypeName: 'Panel',
Template: GLib.uri_resolve_relative(import.meta.url, '../ui/panel.ui', GLib.UriFlags.NONE),
InternalChildren: [
'blur',
'customize',
'static_blur',
'unblur_in_overview',
'override_background',
'style_panel',
'override_background_dynamically',
'hidetopbar_compatibility',
'dtp_blur_original_panel'
],
}, class Panel extends Adw.PreferencesPage {
constructor(preferences) {
super({});
this.preferences = preferences;
this.preferences.panel.settings.bind(
'blur', this._blur, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.panel.settings.bind(
'static-blur', this._static_blur, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.panel.settings.bind(
'unblur-in-overview', this._unblur_in_overview, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.panel.settings.bind(
'override-background',
this._override_background, 'enable-expansion',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.panel.settings.bind(
'style-panel', this._style_panel, 'selected',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.panel.settings.bind(
'override-background-dynamically',
this._override_background_dynamically, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this._customize.connect_to(this.preferences, this.preferences.panel, this._static_blur);
this.preferences.hidetopbar.settings.bind(
'compatibility', this._hidetopbar_compatibility, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this.preferences.dash_to_panel.settings.bind(
'blur-original-panel', this._dtp_blur_original_panel, 'active',
Gio.SettingsBindFlags.DEFAULT
);
}
});

View File

@ -0,0 +1,109 @@
import Adw from 'gi://Adw';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Gio from 'gi://Gio';
import Gtk from 'gi://Gtk';
import { pick, on_picking, on_picked } from '../dbus/client.js';
export const WindowRow = GObject.registerClass({
GTypeName: 'WindowRow',
Template: GLib.uri_resolve_relative(import.meta.url, '../ui/window-row.ui', GLib.UriFlags.NONE),
InternalChildren: [
'window_picker',
'window_class',
'picking_failure_toast'
],
}, class WindowRow extends Adw.ExpanderRow {
constructor(list, app_page, app_name) {
super({});
this._list = list;
this._app_page = app_page;
// add a 'remove' button before the text
let action_row = this.child.get_first_child().get_first_child();
let remove_button = new Gtk.Button({
'icon-name': 'remove-window-symbolic',
'width-request': 38,
'height-request': 38,
'margin-top': 6,
'margin-bottom': 6,
});
remove_button.add_css_class('circular');
remove_button.add_css_class('flat');
action_row.add_prefix(remove_button);
// connect the button to the whitelist / blacklist removal
remove_button.connect('clicked', _ => this._remove_row());
// bind row title to text buffer
this._window_class.buffer.bind_property(
'text', this, 'title',
Gio.SettingsBindFlags.BIDIRECTIONNAL
);
// set application name if it exists, or open the revealer and pick one
if (app_name)
this._window_class.buffer.text = app_name;
else {
app_page.close_all_expanded_rows();
this.set_expanded(true);
this._do_pick_window(true);
}
// pick a window when the picker button is clicked
this._window_picker.connect('clicked', _ => this._do_pick_window());
// update list on text buffer change
this._window_class.connect('changed',
_ => this._update_rows_titles()
);
}
_remove_row() {
this._app_page["remove_from_" + this._list](this);
}
_update_rows_titles() {
this._app_page["update_" + this._list + "_titles"](this);
}
_do_pick_window(remove_if_failed = false) {
// a mechanism to know if the extension is listening correcly
let has_responded = false;
let should_take_answer = true;
setTimeout(_ => {
if (!has_responded) {
// show toast about failure
this._app_page._preferences_window.add_toast(
this._picking_failure_toast
);
// prevent title from changing with later picks
should_take_answer = false;
// remove row if asked
if (remove_if_failed)
this._remove_row();
}
}, 15);
on_picking(_ =>
has_responded = true
);
on_picked(wm_class => {
if (should_take_answer) {
if (wm_class == 'window-not-found') {
console.warn("Can't pick window from here");
return;
}
this._window_class.buffer.text = wm_class;
}
});
pick();
}
});

View File

@ -0,0 +1,41 @@
import Gdk from 'gi://Gdk';
import Gtk from 'gi://Gtk';
import { ExtensionPreferences } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
import { Settings } from './conveniences/settings.js';
import { Keys } from './conveniences/keys.js';
import { addMenu } from './preferences/menu.js';
import { General } from './preferences/general.js';
import { Panel } from './preferences/panel.js';
import { Overview } from './preferences/overview.js';
import { Dash } from './preferences/dash.js';
import { Applications } from './preferences/applications.js';
import { Other } from './preferences/other.js';
export default class BlurMyShellPreferences extends ExtensionPreferences {
constructor(metadata) {
super(metadata);
// load the icon theme
let iconPath = this.dir.get_child("icons").get_path();
let iconTheme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default());
iconTheme.add_search_path(iconPath);
}
fillPreferencesWindow(window) {
addMenu(window);
const preferences = new Settings(Keys, this.getSettings());
window.add(new General(preferences));
window.add(new Panel(preferences));
window.add(new Overview(preferences));
window.add(new Dash(preferences));
window.add(new Applications(preferences, window));
window.add(new Other(preferences));
window.search_enabled = true;
}
}

View File

@ -0,0 +1,467 @@
<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
<!-- GENERAL -->
<schema id="org.gnome.shell.extensions.blur-my-shell" path="/org/gnome/shell/extensions/blur-my-shell/">
<!-- SIGMA -->
<key type="i" name="sigma">
<default>30</default>
<summary>Global sigma (gaussian blur radius) to use</summary>
</key>
<!-- BRIGHTNESS -->
<key type="d" name="brightness">
<default>0.6</default>
<summary>Global brightness to use</summary>
</key>
<!-- COLOR -->
<key type="(dddd)" name="color">
<default>(0.,0.,0.,0.)</default>
<summary>Color to mix with the blur effect</summary>
</key>
<!-- NOISE AMOUNT -->
<key type="d" name="noise-amount">
<default>0.</default>
<summary>Amount of noise to add to the blur effect</summary>
</key>
<!-- NOISE LIGHTNESS -->
<key type="d" name="noise-lightness">
<default>0.</default>
<summary>Lightness of the noise added to the blur effect</summary>
</key>
<!-- COLOR AND NOISE -->
<key type="b" name="color-and-noise">
<default>true</default>
<summary>Boolean, controls wether or not the color and noise effects are in use globally</summary>
</key>
<!-- HACKS LEVEL -->
<key type="i" name="hacks-level">
<default>1</default>
<summary>Level of hacks to use (from 0 to 3, 3 disabling clipped redraws entirely)</summary>
</key>
<!-- DEBUG -->
<key type="b" name="debug">
<default>false</default>
<summary>Boolean, set to true to activate debug mode (more verbose journalctl logs)</summary>
</key>
<child name='overview' schema='org.gnome.shell.extensions.blur-my-shell.overview'></child>
<child name='appfolder' schema='org.gnome.shell.extensions.blur-my-shell.appfolder'></child>
<child name='panel' schema='org.gnome.shell.extensions.blur-my-shell.panel'></child>
<child name='dash-to-dock' schema='org.gnome.shell.extensions.blur-my-shell.dash-to-dock'></child>
<child name='applications' schema='org.gnome.shell.extensions.blur-my-shell.applications'></child>
<child name='screenshot' schema='org.gnome.shell.extensions.blur-my-shell.screenshot'></child>
<child name='lockscreen' schema='org.gnome.shell.extensions.blur-my-shell.lockscreen'></child>
<child name='window-list' schema='org.gnome.shell.extensions.blur-my-shell.window-list'></child>
<child name='hidetopbar' schema='org.gnome.shell.extensions.blur-my-shell.hidetopbar'></child>
<child name='dash-to-panel' schema='org.gnome.shell.extensions.blur-my-shell.dash-to-panel'></child>
</schema>
<!-- OVERVIEW -->
<schema id="org.gnome.shell.extensions.blur-my-shell.overview" path="/org/gnome/shell/extensions/blur-my-shell/overview/">
<!-- BLUR -->
<key type="b" name="blur">
<default>true</default>
<summary>Boolean, whether to blur activate the blur for this component or not</summary>
</key>
<!-- CUSTOMIZE -->
<key type="b" name="customize">
<default>false</default>
<summary>Boolean, whether to customize the blur effect sigma/brightness or use general values</summary>
</key>
<!-- SIGMA -->
<key type="i" name="sigma">
<default>30</default>
<summary>Sigma (gaussian blur radius) to use for the blur effect</summary>
</key>
<!-- BRIGHTNESS -->
<key type="d" name="brightness">
<default>0.6</default>
<summary>Brightness to use for the blur effect</summary>
</key>
<!-- COLOR -->
<key type="(dddd)" name="color">
<default>(0.,0.,0.,0.)</default>
<summary>Color to mix with the blur effect</summary>
</key>
<!-- NOISE AMOUNT -->
<key type="d" name="noise-amount">
<default>0.</default>
<summary>Amount of noise to add to the blur effect</summary>
</key>
<!-- NOISE LIGHTNESS -->
<key type="d" name="noise-lightness">
<default>0.</default>
<summary>Lightness of the noise added to the blur effect</summary>
</key>
<!-- STYLE COMPONENTS -->
<key type="i" name="style-components">
<default>1</default>
<summary>Enum to select the style of the components in overview (0 not styled, 1 light, 2 dark, 3 transparent)</summary>
</key>
</schema>
<!-- APPFOLDER -->
<schema id="org.gnome.shell.extensions.blur-my-shell.appfolder" path="/org/gnome/shell/extensions/blur-my-shell/appfolder/">
<!-- BLUR -->
<key type="b" name="blur">
<default>true</default>
<summary>Boolean, whether to blur activate the blur for this component or not</summary>
</key>
<!-- CUSTOMIZE -->
<key type="b" name="customize">
<default>false</default>
<summary>Boolean, whether to customize the blur effect sigma/brightness or use general values</summary>
</key>
<!-- SIGMA -->
<key type="i" name="sigma">
<default>30</default>
<summary>Sigma (gaussian blur radius) to use for the blur effect</summary>
</key>
<!-- BRIGHTNESS -->
<key type="d" name="brightness">
<default>0.6</default>
<summary>Brightness to use for the blur effect</summary>
</key>
<!-- COLOR -->
<key type="(dddd)" name="color">
<default>(0.,0.,0.,0.)</default>
<summary>Color to mix with the blur effect</summary>
</key>
<!-- NOISE AMOUNT -->
<key type="d" name="noise-amount">
<default>0.</default>
<summary>Amount of noise to add to the blur effect</summary>
</key>
<!-- NOISE LIGHTNESS -->
<key type="d" name="noise-lightness">
<default>0.</default>
<summary>Lightness of the noise added to the blur effect</summary>
</key>
<!-- STYLE DIALOGS -->
<key type="i" name="style-dialogs">
<default>1</default>
<summary>Enum to select the style of the appfolder dialogs (0 not styled, 1 transparent, 2 light, 3 dark)</summary>
</key>
</schema>
<!-- PANEL -->
<schema id="org.gnome.shell.extensions.blur-my-shell.panel" path="/org/gnome/shell/extensions/blur-my-shell/panel/">
<!-- BLUR -->
<key type="b" name="blur">
<default>true</default>
<summary>Boolean, whether to blur activate the blur for this component or not</summary>
</key>
<!-- CUSTOMIZE -->
<key type="b" name="customize">
<default>false</default>
<summary>Boolean, whether to customize the blur effect sigma/brightness or use general values</summary>
</key>
<!-- SIGMA -->
<key type="i" name="sigma">
<default>30</default>
<summary>Sigma (gaussian blur radius) to use for the blur effect</summary>
</key>
<!-- BRIGHTNESS -->
<key type="d" name="brightness">
<default>0.6</default>
<summary>Brightness to use for the blur effect</summary>
</key>
<!-- COLOR -->
<key type="(dddd)" name="color">
<default>(0.,0.,0.,0.)</default>
<summary>Color to mix with the blur effect</summary>
</key>
<!-- NOISE AMOUNT -->
<key type="d" name="noise-amount">
<default>0.</default>
<summary>Amount of noise to add to the blur effect</summary>
</key>
<!-- NOISE LIGHTNESS -->
<key type="d" name="noise-lightness">
<default>0.</default>
<summary>Lightness of the noise added to the blur effect</summary>
</key>
<!-- STATIC BLUR -->
<key type="b" name="static-blur">
<default>true</default>
<summary>Boolean, whether to use a static or dynamic blur for this component</summary>
</key>
<!-- UNBLUR IN OVERVIEW -->
<key type="b" name="unblur-in-overview">
<default>true</default>
<summary>Boolean, whether to disable blur from this component when opening the overview or not</summary>
</key>
<!-- OVERRIDE BACKGROUND -->
<key type="b" name="override-background">
<default>true</default>
<summary>Boolean, whether to override the background or not</summary>
</key>
<!-- STYLE PANEL -->
<key type="i" name="style-panel">
<default>0</default>
<summary>Enum to select the style of the panel (0 transparent, 1 light, 2 dark, 3 contrasted)</summary>
</key>
<!-- UNBLUR DYNAMICALLY -->
<key type="b" name="override-background-dynamically">
<default>false</default>
<summary>Boolean, whether to disable blur from this component when a window is close to the panel</summary>
</key>
</schema>
<!-- DASH TO DOCK -->
<schema id="org.gnome.shell.extensions.blur-my-shell.dash-to-dock" path="/org/gnome/shell/extensions/blur-my-shell/dash-to-dock/">
<!-- BLUR -->
<key type="b" name="blur">
<default>false</default>
<summary>Boolean, whether to blur activate the blur for this component or not</summary>
</key>
<!-- CUSTOMIZE -->
<key type="b" name="customize">
<default>false</default>
<summary>Boolean, whether to customize the blur effect sigma/brightness or use general values</summary>
</key>
<!-- SIGMA -->
<key type="i" name="sigma">
<default>30</default>
<summary>Sigma (gaussian blur radius) to use for the blur effect</summary>
</key>
<!-- BRIGHTNESS -->
<key type="d" name="brightness">
<default>0.6</default>
<summary>Brightness to use for the blur effect</summary>
</key>
<!-- COLOR -->
<key type="(dddd)" name="color">
<default>(0.,0.,0.,0.)</default>
<summary>Color to mix with the blur effect</summary>
</key>
<!-- NOISE AMOUNT -->
<key type="d" name="noise-amount">
<default>0.</default>
<summary>Amount of noise to add to the blur effect</summary>
</key>
<!-- NOISE LIGHTNESS -->
<key type="d" name="noise-lightness">
<default>0.</default>
<summary>Lightness of the noise added to the blur effect</summary>
</key>
<!-- STATIC BLUR -->
<key type="b" name="static-blur">
<default>true</default>
<summary>Boolean, whether to use static or dynamic blur for this component</summary>
</key>
<!-- OVERRIDE BACKGROUND -->
<key type="b" name="override-background">
<default>true</default>
<summary>Boolean, whether to override the background or not</summary>
</key>
<!-- STYLE DASH TO DOCK -->
<key type="i" name="style-dash-to-dock">
<default>1</default>
<summary>Enum to select the style of dash to dock (0 transparent, 1 light, 2 dark)</summary>
</key>
<!-- UNBLUR IN OVERVIEW -->
<key type="b" name="unblur-in-overview">
<default>false</default>
<summary>Boolean, whether to disable blur from this component when opening the overview or not</summary>
</key>
</schema>
<!-- APPLICATIONS -->
<schema id="org.gnome.shell.extensions.blur-my-shell.applications" path="/org/gnome/shell/extensions/blur-my-shell/applications/">
<!-- BLUR -->
<key type="b" name="blur">
<default>true</default>
<summary>Boolean, whether to blur activate the blur for this component or not</summary>
</key>
<!-- CUSTOMIZE -->
<key type="b" name="customize">
<default>true</default>
<summary>Boolean, whether to customize the blur effect sigma/brightness or use general values</summary>
</key>
<!-- SIGMA -->
<key type="i" name="sigma">
<default>30</default>
<summary>Sigma (gaussian blur radius) to use for the blur effect</summary>
</key>
<!-- BRIGHTNESS -->
<key type="d" name="brightness">
<default>1.</default>
<summary>Brightness to use for the blur effect</summary>
</key>
<!-- COLOR -->
<key type="(dddd)" name="color">
<default>(0.,0.,0.,0.)</default>
<summary>Color to mix with the blur effect</summary>
</key>
<!-- NOISE AMOUNT -->
<key type="d" name="noise-amount">
<default>0.</default>
<summary>Amount of noise to add to the blur effect</summary>
</key>
<!-- NOISE LIGHTNESS -->
<key type="d" name="noise-lightness">
<default>0.</default>
<summary>Lightness of the noise added to the blur effect</summary>
</key>
<!-- OPACITY -->
<key type="i" name="opacity">
<default>230</default>
<summary>Opacity of the window actor on top of the blur effect</summary>
</key>
<!-- BLUR ON OVERVIEW -->
<key type="b" name="blur-on-overview">
<default>false</default>
<summary>Wether or not to blur applications on the overview</summary>
</key>
<!-- ENABLE ALL -->
<key type="b" name="enable-all">
<default>false</default>
<summary>Wether or not to blur all applications by default</summary>
</key>
<!-- WHITELIST -->
<key type="as" name="whitelist">
<default>[]</default>
<summary>List of applications to blur</summary>
</key>
<!-- BLACKLIST -->
<key type="as" name="blacklist">
<default>["Plank"]</default>
<summary>List of applications not to blur</summary>
</key>
</schema>
<!-- SCREENSHOT -->
<schema id="org.gnome.shell.extensions.blur-my-shell.screenshot" path="/org/gnome/shell/extensions/blur-my-shell/screenshot/">
<!-- BLUR -->
<key type="b" name="blur">
<default>true</default>
<summary>Boolean, whether to blur activate the blur for this component or not</summary>
</key>
<!-- CUSTOMIZE -->
<key type="b" name="customize">
<default>false</default>
<summary>Boolean, whether to customize the blur effect sigma/brightness or use general values</summary>
</key>
<!-- SIGMA -->
<key type="i" name="sigma">
<default>30</default>
<summary>Sigma (gaussian blur radius) to use for the blur effect</summary>
</key>
<!-- BRIGHTNESS -->
<key type="d" name="brightness">
<default>0.6</default>
<summary>Brightness to use for the blur effect</summary>
</key>
<!-- COLOR -->
<key type="(dddd)" name="color">
<default>(0.,0.,0.,0.)</default>
<summary>Color to mix with the blur effect</summary>
</key>
<!-- NOISE AMOUNT -->
<key type="d" name="noise-amount">
<default>0.</default>
<summary>Amount of noise to add to the blur effect</summary>
</key>
<!-- NOISE LIGHTNESS -->
<key type="d" name="noise-lightness">
<default>0.</default>
<summary>Lightness of the noise added to the blur effect</summary>
</key>
</schema>
<!-- LOCKSCREEN -->
<schema id="org.gnome.shell.extensions.blur-my-shell.lockscreen" path="/org/gnome/shell/extensions/blur-my-shell/lockscreen/">
<!-- BLUR -->
<key type="b" name="blur">
<default>true</default>
<summary>Boolean, whether to blur activate the blur for this component or not</summary>
</key>
<!-- CUSTOMIZE -->
<key type="b" name="customize">
<default>false</default>
<summary>Boolean, whether to customize the blur effect sigma/brightness or use general values</summary>
</key>
<!-- SIGMA -->
<key type="i" name="sigma">
<default>30</default>
<summary>Sigma (gaussian blur radius) to use for the blur effect</summary>
</key>
<!-- BRIGHTNESS -->
<key type="d" name="brightness">
<default>0.6</default>
<summary>Brightness to use for the blur effect</summary>
</key>
<!-- COLOR -->
<key type="(dddd)" name="color">
<default>(0.,0.,0.,0.)</default>
<summary>Color to mix with the blur effect</summary>
</key>
<!-- NOISE AMOUNT -->
<key type="d" name="noise-amount">
<default>0.</default>
<summary>Amount of noise to add to the blur effect</summary>
</key>
<!-- NOISE LIGHTNESS -->
<key type="d" name="noise-lightness">
<default>0.</default>
<summary>Lightness of the noise added to the blur effect</summary>
</key>
</schema>
<!-- WINDOW LIST -->
<schema id="org.gnome.shell.extensions.blur-my-shell.window-list" path="/org/gnome/shell/extensions/blur-my-shell/window-list/">
<!-- BLUR -->
<key type="b" name="blur">
<default>true</default>
<summary>Boolean, whether to blur activate the blur for this component or not</summary>
</key>
<!-- CUSTOMIZE -->
<key type="b" name="customize">
<default>false</default>
<summary>Boolean, whether to customize the blur effect sigma/brightness or use general values</summary>
</key>
<!-- SIGMA -->
<key type="i" name="sigma">
<default>30</default>
<summary>Sigma (gaussian blur radius) to use for the blur effect</summary>
</key>
<!-- BRIGHTNESS -->
<key type="d" name="brightness">
<default>0.6</default>
<summary>Brightness to use for the blur effect</summary>
</key>
<!-- COLOR -->
<key type="(dddd)" name="color">
<default>(0.,0.,0.,0.)</default>
<summary>Color to mix with the blur effect</summary>
</key>
<!-- NOISE AMOUNT -->
<key type="d" name="noise-amount">
<default>0.</default>
<summary>Amount of noise to add to the blur effect</summary>
</key>
<!-- NOISE LIGHTNESS -->
<key type="d" name="noise-lightness">
<default>0.</default>
<summary>Lightness of the noise added to the blur effect</summary>
</key>
</schema>
<!-- HIDETOPBAR -->
<schema id="org.gnome.shell.extensions.blur-my-shell.hidetopbar" path="/org/gnome/shell/extensions/blur-my-shell/hidetopbar/">
<!-- COMPATIBILITY -->
<key type="b" name="compatibility">
<default>false</default>
<summary>Boolean, whether to try compatibility with hidetopbar@mathieu.bidon.ca or not</summary>
</key>
</schema>
<!-- DASH TO PANEL -->
<schema id="org.gnome.shell.extensions.blur-my-shell.dash-to-panel" path="/org/gnome/shell/extensions/blur-my-shell/dash-to-panel/">
<!-- COMPATIBILITY -->
<key type="b" name="blur-original-panel">
<default>true</default>
<summary>Boolean, whether to blur the original panel (if option selected) with Dash to Panel</summary>
</key>
</schema>
</schemalist>

View File

@ -0,0 +1,334 @@
/*** PANEL ***/
/*
* `.transparent-panel`
*/
#panel.transparent-panel {
background: transparent;
transition-duration: 500ms;
}
/*
* `.dark-panel`
*/
#panel.dark-panel {
background-color: rgba(100, 100, 100, 0.35);
box-shadow: none;
transition-duration: 500ms;
}
/*
* `.light-panel`
*/
#panel.light-panel {
background-color: rgba(200, 200, 200, 0.2);
box-shadow: none;
transition-duration: 500ms;
}
/*
* `.contrasted-panel`
*/
#panel.contrasted-panel {
background-color: transparent;
box-shadow: none;
transition-duration: 500ms;
}
.contrasted-panel .panel-button,
.contrasted-panel .clock,
.contrasted-panel .clock-display StIcon {
color: #ffffff;
border-radius: 14px;
border: 3px solid transparent;
background-color: rgba(0, 0, 0, 0.8);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.03);
}
.contrasted-panel .clock-display StIcon {
padding: 8px;
margin: 0;
}
.contrasted-panel .panel-button:hover,
.contrasted-panel .panel-button:hover .clock {
color: #ffffff;
background-color: rgba(0, 0, 0, 0.8);
}
.contrasted-panel .clock-display {
background-color: transparent !important;
box-shadow: none !important;
border: none !important;
}
.contrasted-panel .clock {
margin: 0 !important;
}
/*** DASH ***/
/*
* `.transparent-dash`
*/
.transparent-dash .dash-background {
background-color: transparent !important;
}
/*
* `.light-dash`
*/
.light-dash .dash-background {
background-color: rgba(200, 200, 200, 0.2) !important;
}
/*
* `.dark-dash`
*/
.dark-dash .dash-background {
background-color: rgba(100, 100, 100, 0.35) !important;
}
/*** OVERVIEW ***/
/*
* Add transparency to the workspace animation (between workspaces)
*/
.blurred-overview .workspace-animation {
background-color: transparent !important;
}
/*
* `.overview-components-transparent`
*/
.overview-components-transparent .workspace-thumbnail {
background-color: rgba(0, 0, 0, 0);
border: 1px solid rgba(100, 100, 100, 0.35);
}
.overview-components-transparent .search-entry {
color: white;
background-color: rgba(0, 0, 0, 0);
border-color: transparent;
box-shadow: none;
}
.overview-components-transparent .search-entry .search-entry-icon {
color: rgba(255, 255, 255, 0.65);
}
.overview-components-transparent .search-section-content {
border: none;
box-shadow: none;
}
.overview-components-transparent .search-section-content,
.overview-components-transparent .app-folder .overview-icon {
background-color: rgba(0, 0, 0, 0);
}
/* prevents the extension from interfering with Just Perfection */
.overview-components-transparent.just-perfection .search-section-content {
background-color: transparent;
}
.overview-components-transparent .app-folder .overview-icon {
border-color: transparent;
}
.overview-components-transparent .app-folder:hover .overview-icon,
.overview-components-transparent .app-folder:focus .overview-icon {
background-color: rgba(230, 230, 230, 0.08);
}
.overview-components-transparent .app-folder:active .overview-icon,
.overview-components-transparent .app-folder:focus:hover .overview-icon,
.overview-components-transparent .app-folder:drop .overview-icon {
background-color: rgba(230, 230, 230, 0.12);
}
.overview-components-transparent .app-folder:focus:active .overview-icon {
background-color: rgba(230, 230, 230, 0.15);
}
/* this shouldn't apply to Dash to Dock */
.overview-components-transparent StBoxLayout>StWidget>#dash>.dash-background {
background-color: rgba(0, 0, 0, 0);
}
/*
* `.overview-components-light`
*/
.overview-components-light .workspace-thumbnail {
background-color: rgba(200, 200, 200, 0.2);
}
.overview-components-light .search-entry {
color: white;
background-color: rgba(200, 200, 200, 0.2);
border-color: transparent;
box-shadow: none;
}
.overview-components-light .search-entry .search-entry-icon {
color: rgba(255, 255, 255, 0.65);
}
.overview-components-light .search-section-content {
border: none;
box-shadow: none;
}
.overview-components-light .search-section-content,
.overview-components-light .app-folder .overview-icon {
background-color: rgba(200, 200, 200, 0.2);
}
/* prevents the extension from interfering with Just Perfection */
.overview-components-light.just-perfection .search-section-content {
background-color: transparent;
}
.overview-components-light .app-folder .overview-icon {
border-color: transparent;
}
.overview-components-light .app-folder:hover .overview-icon,
.overview-components-light .app-folder:focus .overview-icon {
background-color: rgba(230, 230, 230, 0.2);
}
.overview-components-light .app-folder:active .overview-icon,
.overview-components-light .app-folder:focus:hover .overview-icon,
.overview-components-light .app-folder:drop .overview-icon {
background-color: rgba(230, 230, 230, 0.25);
}
.overview-components-light .app-folder:focus:active .overview-icon {
background-color: rgba(230, 230, 230, 0.3);
}
/* this shouldn't apply to Dash to Dock */
.overview-components-light StBoxLayout>StWidget>#dash>.dash-background {
background-color: rgba(200, 200, 200, 0.2);
}
/*
* `.overview-components-dark`
*/
.overview-components-dark .workspace-thumbnail {
background-color: rgba(100, 100, 100, 0.35);
}
.overview-components-dark .search-entry {
color: white;
background-color: rgba(100, 100, 100, 0.35);
border-color: transparent;
box-shadow: none;
}
.overview-components-dark .search-entry .search-entry-icon {
color: rgba(255, 255, 255, 0.65);
}
.overview-components-dark .search-section-content {
border: none;
box-shadow: none;
}
.overview-components-dark .search-section-content,
.overview-components-dark .app-folder .overview-icon {
background-color: rgba(100, 100, 100, 0.35);
}
/* prevents the extension from interfering with Just Perfection */
.overview-components-dark.just-perfection .search-section-content {
background-color: transparent;
}
.overview-components-dark .app-folder .overview-icon {
border-color: transparent;
}
.overview-components-dark .app-folder:hover .overview-icon,
.overview-components-dark .app-folder:focus .overview-icon {
background-color: rgba(120, 120, 120, 0.35);
}
.overview-components-dark .app-folder:active .overview-icon,
.overview-components-dark .app-folder:focus:hover .overview-icon,
.overview-components-dark .app-folder:drop .overview-icon {
background-color: rgba(120, 120, 120, 0.4);
}
.overview-components-dark .app-folder:focus:active .overview-icon {
background-color: rgba(120, 120, 120, 0.45);
}
/* this shouldn't apply to Dash to Dock */
.overview-components-dark StBoxLayout>StWidget>#dash>.dash-background {
background-color: rgba(100, 100, 100, 0.35);
}
/*** APPFOLDER DIALOG ***/
/*
* `.appfolder-dialogs-transparent`
*/
.appfolder-dialogs-transparent {
background-color: rgba(0, 0, 0, 0);
border: none;
box-shadow: none;
}
.appfolder-dialogs-transparent .folder-name-entry {
color: white;
background-color: rgba(0, 0, 0, 0);
border: 0;
box-shadow: none;
}
/*
* `.appfolder-dialogs-light`
*/
.appfolder-dialogs-light {
background-color: rgba(200, 200, 200, 0.2);
border: none;
box-shadow: none;
}
.appfolder-dialogs-light .folder-name-entry {
color: white;
background-color: rgba(200, 200, 200, 0.2);
border: 0;
box-shadow: none;
}
/*
* `.appfolder-dialogs-dark`
*/
.appfolder-dialogs-dark {
background-color: rgba(100, 100, 100, 0.35);
border: none;
box-shadow: none;
}
.appfolder-dialogs-dark .folder-name-entry {
color: white;
background-color: rgba(100, 100, 100, 0.35);
border: 0;
box-shadow: none;
}

View File

@ -0,0 +1,163 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="blur-my-shell@aunetx">
<template class="Applications" parent="AdwPreferencesPage">
<property name="name">applications</property>
<property name="title" translatable="yes">Applications</property>
<property name="icon-name">applications-symbolic</property>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Applications blur (beta)</property>
<property name="description" translatable="yes">Adds blur to the applications. This is still beta functionality.
To get the best results possible, make sure to choose the option “No artifact” in the “General → Hack level” preference.
</property>
<property name="header-suffix">
<object class="GtkSwitch" id="blur">
<property name="valign">center</property>
</object>
</property>
<child>
<object class="CustomizeRow" id="customize">
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Opacity</property>
<property name="subtitle" translatable="yes">The opacity of the window on top of the blur effect, a higher value will be more legible.</property>
<property name="activatable-widget">opacity</property>
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
<child>
<object class="GtkScale" id="opacity_scale">
<property name="valign">center</property>
<property name="hexpand">true</property>
<property name="width-request">200px</property>
<property name="draw-value">true</property>
<property name="value-pos">right</property>
<property name="orientation">horizontal</property>
<property name="digits">0</property>
<property name="adjustment">opacity</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Blur on overview</property>
<property name="subtitle" translatable="yes">Forces the blur to be properly shown on all workspaces on overview.
This may cause some latency or performance issues.</property>
<property name="activatable-widget">blur_on_overview</property>
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
<child>
<object class="GtkSwitch" id="blur_on_overview">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Enable all by default</property>
<property name="subtitle" translatable="yes">Adds blur behind all windows by default.
Not recommended because of performance and stability issues.</property>
<property name="activatable-widget">enable_all</property>
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
<child>
<object class="GtkSwitch" id="enable_all">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup" id="whitelist">
<property name="title" translatable="yes">Whitelist</property>
<property name="description" translatable="yes">A list of windows to blur.</property>
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
<property name="header-suffix">
<object class="GtkButton" id="add_window_whitelist">
<property name="halign">start</property>
<property name="valign">center</property>
<child>
<object class="GtkBox">
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<child>
<object class="GtkImage">
<property name="margin-end">6</property>
<property name="icon-name">add-window-symbolic</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Add Window</property>
</object>
</child>
</object>
</child>
<style>
<class name="circular" />
<class name="suggested-action" />
</style>
</object>
</property>
<!-- WINDOW ROW WIDGETS GO HERE -->
</object>
</child>
<child>
<object class="AdwPreferencesGroup" id="blacklist">
<property name="title" translatable="yes">Blacklist</property>
<property name="description" translatable="yes">A list of windows not to blur.</property>
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
<property name="header-suffix">
<object class="GtkButton" id="add_window_blacklist">
<property name="halign">start</property>
<property name="valign">center</property>
<child>
<object class="GtkBox">
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<child>
<object class="GtkImage">
<property name="margin-end">6</property>
<property name="icon-name">list-add-symbolic</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Add Window</property>
</object>
</child>
</object>
</child>
<style>
<class name="circular" />
<class name="suggested-action" />
</style>
</object>
</property>
<!-- WINDOW ROW WIDGETS GO HERE -->
</object>
</child>
</template>
<object class="GtkAdjustment" id="opacity">
<property name="lower">25</property>
<property name="upper">255</property>
<property name="step-increment">1</property>
</object>
</interface>

View File

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="blur-my-shell@aunetx">
<template class="CustomizeRow" parent="AdwExpanderRow">
<property name="title" translatable="yes">Customize properties</property>
<property name="subtitle" translatable="yes">Uses customized blur properties, instead of the ones set in the General page.</property>
<property name="show-enable-switch">true</property>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Sigma</property>
<property name="subtitle" translatable="yes">The intensity of the blur.</property>
<property name="activatable-widget">sigma_scale</property>
<child>
<object class="GtkScale" id="sigma_scale">
<property name="valign">center</property>
<property name="hexpand">true</property>
<property name="width-request">200px</property>
<property name="draw-value">true</property>
<property name="value-pos">right</property>
<property name="orientation">horizontal</property>
<property name="digits">0</property>
<property name="adjustment">sigma</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Brightness</property>
<property name="subtitle" translatable="yes">The brightness of the blur effect, a high value might make the text harder to read.</property>
<property name="activatable-widget">brightness_scale</property>
<child>
<object class="GtkScale" id="brightness_scale">
<property name="valign">center</property>
<property name="hexpand">true</property>
<property name="width-request">200px</property>
<property name="draw-value">true</property>
<property name="value-pos">right</property>
<property name="orientation">horizontal</property>
<property name="digits">2</property>
<property name="adjustment">brightness</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="color_row">
<property name="title" translatable="yes">Color</property>
<property name="subtitle" translatable="yes">Changes the color of the blur. The opacity of the color controls how much it is blended into the blur effect.</property>
<property name="activatable-widget">color</property>
<child>
<object class="GtkColorButton" id="color">
<property name="valign">center</property>
<property name="hexpand">false</property>
<property name="width-request">70px</property>
<property name="height-request">45px</property>
<property name="show-editor">true</property>
<property name="use-alpha">true</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="noise_amount_row">
<property name="title" translatable="yes">Noise amount</property>
<property name="subtitle" translatable="yes">The amount of noise to add to the blur effect, useful on low-contrast screens or for aesthetic purpose.</property>
<property name="activatable-widget">noise_amount_scale</property>
<child>
<object class="GtkScale" id="noise_amount_scale">
<property name="valign">center</property>
<property name="hexpand">true</property>
<property name="width-request">200px</property>
<property name="draw-value">true</property>
<property name="value-pos">right</property>
<property name="orientation">horizontal</property>
<property name="digits">2</property>
<property name="adjustment">noise_amount</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="noise_lightness_row">
<property name="title" translatable="yes">Noise lightness</property>
<property name="subtitle" translatable="yes">The lightness of the noise added to the blur effect.</property>
<property name="activatable-widget">noise_lightness_scale</property>
<child>
<object class="GtkScale" id="noise_lightness_scale">
<property name="valign">center</property>
<property name="hexpand">true</property>
<property name="width-request">200px</property>
<property name="draw-value">true</property>
<property name="value-pos">right</property>
<property name="orientation">horizontal</property>
<property name="digits">2</property>
<property name="adjustment">noise_lightness</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="noise_color_notice">
<property name="title" translatable="yes">Notice</property>
<property name="subtitle" translatable="yes">Noise and color can't be activated on dynamically blurred components, such as this one.</property>
</object>
</child>
</template>
<object class="GtkAdjustment" id="sigma">
<property name="lower">0</property>
<property name="upper">200</property>
<property name="step-increment">1</property>
</object>
<object class="GtkAdjustment" id="brightness">
<property name="lower">0.0</property>
<property name="upper">1.0</property>
<property name="step-increment">0.01</property>
</object>
<object class="GtkAdjustment" id="noise_amount">
<property name="lower">0.0</property>
<property name="upper">1.0</property>
<property name="step-increment">0.01</property>
</object>
<object class="GtkAdjustment" id="noise_lightness">
<property name="lower">0.0</property>
<property name="upper">2.0</property>
<property name="step-increment">0.01</property>
</object>
</interface>

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="blur-my-shell@aunetx">
<template class="Dash" parent="AdwPreferencesPage">
<property name="name">dash</property>
<property name="title" translatable="yes">Dash</property>
<property name="icon-name">dash-symbolic</property>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Dash to Dock blur</property>
<property name="description" translatable="yes">Blur the background of the Dash to Dock extension, if it is used.</property>
<property name="header-suffix">
<object class="GtkSwitch" id="blur">
<property name="valign">center</property>
</object>
</property>
<child>
<object class="CustomizeRow" id="customize">
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
</object>
</child>
<child>
<object class="AdwExpanderRow" id="override_background">
<property name="title" translatable="yes">Override background</property>
<property name="subtitle" translatable="yes">Makes the background either transparent or semi-transparent, disable this to use Dash to Dock preferences instead.</property>
<property name="show-enable-switch">true</property>
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Background style</property>
<property name="subtitle" translatable="yes">The transparent/semi-transparent style for the dock background.</property>
<property name="activatable-widget">style_dash_to_dock</property>
<child>
<object class="GtkDropDown" id="style_dash_to_dock">
<property name="valign">center</property>
<property name="model">style_dash_to_dock_model</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Disable in overview</property>
<property name="subtitle" translatable="yes">Disables the blur from Dash to Dock when entering the overview.</property>
<property name="activatable-widget">unblur_in_overview</property>
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
<child>
<object class="GtkSwitch" id="unblur_in_overview">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
<object class="GtkStringList" id="style_dash_to_dock_model">
<items>
<item translatable="yes">Transparent</item>
<item translatable="yes">Light</item>
<item translatable="yes">Dark</item>
</items>
</object>
</interface>

View File

@ -0,0 +1,234 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="blur-my-shell@aunetx">
<template class="General" parent="AdwPreferencesPage">
<property name="name">general</property>
<property name="title" translatable="yes">General</property>
<property name="icon-name">general-symbolic</property>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Blur preferences</property>
<property name="description" translatable="yes">Global blur preferences, used by all components by default.</property>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Sigma</property>
<property name="subtitle" translatable="yes">The intensity of the blur.</property>
<property name="activatable-widget">sigma_scale</property>
<child>
<object class="GtkScale" id="sigma_scale">
<property name="valign">center</property>
<property name="hexpand">true</property>
<property name="width-request">200px</property>
<property name="draw-value">true</property>
<property name="value-pos">right</property>
<property name="orientation">horizontal</property>
<property name="digits">0</property>
<property name="adjustment">sigma</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Brightness</property>
<property name="subtitle" translatable="yes">The brightness of the blur effect, a high value might make the text harder to read.</property>
<property name="activatable-widget">brightness_scale</property>
<child>
<object class="GtkScale" id="brightness_scale">
<property name="valign">center</property>
<property name="hexpand">true</property>
<property name="width-request">200px</property>
<property name="draw-value">true</property>
<property name="value-pos">right</property>
<property name="orientation">horizontal</property>
<property name="digits">2</property>
<property name="adjustment">brightness</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="color_row">
<property name="title" translatable="yes">Color</property>
<property name="subtitle" translatable="yes">Changes the color of the blur. The opacity of the color controls how much it is blended into the blur effect.</property>
<property name="activatable-widget">color</property>
<child>
<object class="GtkColorButton" id="color">
<property name="valign">center</property>
<property name="hexpand">false</property>
<property name="width-request">70px</property>
<property name="height-request">45px</property>
<property name="show-editor">true</property>
<property name="use-alpha">true</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="noise_amount_row">
<property name="title" translatable="yes">Noise amount</property>
<property name="subtitle" translatable="yes">The amount of noise to add to the blur effect, useful on low-contrast screens or for aesthetic purpose.</property>
<property name="activatable-widget">noise_amount_scale</property>
<child>
<object class="GtkScale" id="noise_amount_scale">
<property name="valign">center</property>
<property name="hexpand">true</property>
<property name="width-request">200px</property>
<property name="draw-value">true</property>
<property name="value-pos">right</property>
<property name="orientation">horizontal</property>
<property name="digits">2</property>
<property name="adjustment">noise_amount</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="noise_lightness_row">
<property name="title" translatable="yes">Noise lightness</property>
<property name="subtitle" translatable="yes">The lightness of the noise added to the blur effect.</property>
<property name="activatable-widget">noise_lightness_scale</property>
<child>
<object class="GtkScale" id="noise_lightness_scale">
<property name="valign">center</property>
<property name="hexpand">true</property>
<property name="width-request">200px</property>
<property name="draw-value">true</property>
<property name="value-pos">right</property>
<property name="orientation">horizontal</property>
<property name="digits">2</property>
<property name="adjustment">noise_lightness</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Performance</property>
<property name="description" translatable="yes">Various options to tweak the performance.</property>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Color and noise effects</property>
<property name="subtitle" translatable="yes">Globally disables noise and color effects which may improve performance on low-end systems.</property>
<property name="activatable-widget">color_and_noise</property>
<child>
<object class="GtkSwitch" id="color_and_noise">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Hack level</property>
<property name="subtitle" translatable="yes">Changes the behaviour of the dynamic blur effect.
The default value is highly recommended unless you use application blur, in which case “No artifact” is better.
This option will entirely disable clipped redraws in GNOME shell, and may impact performance significantly but will completely fix the blur effect.</property>
<property name="activatable-widget">hack_level</property>
<child>
<object class="GtkDropDown" id="hack_level">
<property name="valign">center</property>
<property name="model">hack_level_model</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Debug</property>
<property name="subtitle" translatable="yes">Makes the extension verbose in logs, activate when you need to report an issue.</property>
<property name="activatable-widget">debug</property>
<child>
<object class="GtkSwitch" id="debug">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Reset preferences</property>
<property name="description" translatable="yes">Resets preferences of Blur my Shell irreversibly.</property>
<property name="header-suffix">
<object class="GtkButton" id="reset">
<property name="halign">start</property>
<property name="valign">center</property>
<child>
<object class="GtkBox">
<property name="margin-start">20</property>
<property name="margin-end">20</property>
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
<child>
<object class="GtkImage">
<property name="margin-end">6</property>
<property name="icon-name">reset-symbolic</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Reset</property>
</object>
</child>
</object>
</child>
<style>
<class name="circular" />
<class name="destructive-action" />
</style>
</object>
</property>
</object>
</child>
</template>
<object class="GtkAdjustment" id="sigma">
<property name="lower">0</property>
<property name="upper">200</property>
<property name="step-increment">1</property>
</object>
<object class="GtkAdjustment" id="brightness">
<property name="lower">0.0</property>
<property name="upper">1.0</property>
<property name="step-increment">0.01</property>
</object>
<object class="GtkAdjustment" id="noise_amount">
<property name="lower">0.0</property>
<property name="upper">1.0</property>
<property name="step-increment">0.01</property>
</object>
<object class="GtkAdjustment" id="noise_lightness">
<property name="lower">0.0</property>
<property name="upper">2.0</property>
<property name="step-increment">0.01</property>
</object>
<object class="GtkStringList" id="hack_level_model">
<items>
<item translatable="yes">High performances</item>
<item translatable="yes">Default</item>
<item translatable="yes">High quality</item>
<item translatable="yes">No artifact</item>
</items>
</object>
</interface>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="blur-my-shell@aunetx">
<menu id="info_menu_model">
<section>
<item>
<attribute name="label" translatable="yes">Project page</attribute>
<attribute name="action">prefs.open-readme</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Report a Bug</attribute>
<attribute name="action">prefs.open-bug-report</attribute>
</item>
<item>
<attribute name="label" translatable="yes">License</attribute>
<attribute name="action">prefs.open-license</attribute>
</item>
<submenu>
<attribute name="label" translatable="yes">Donate</attribute>
<item>
<attribute name="label">GitHub</attribute>
<attribute name="action">prefs.donate-github</attribute>
</item>
<item>
<attribute name="label">Ko-fi</attribute>
<attribute name="action">prefs.donate-kofi</attribute>
</item>
</submenu>
</section>
</menu>
<object class="GtkMenuButton" id="info_menu">
<property name="menu-model">info_menu_model</property>
<property name="icon-name">heart-filled-symbolic</property>
</object>
<object class="AdwPreferencesPage" id="menu_util"></object>
</interface>

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="blur-my-shell@aunetx">
<template class="Other" parent="AdwPreferencesPage">
<property name="name">other</property>
<property name="title" translatable="yes">Other</property>
<property name="icon-name">other-symbolic</property>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Lockscreen blur</property>
<property name="description" translatable="yes">Change the blur of the lockscreen to use this extension's preferences.</property>
<property name="header-suffix">
<object class="GtkSwitch" id="lockscreen_blur">
<property name="valign">center</property>
</object>
</property>
<child>
<object class="CustomizeRow" id="lockscreen_customize">
<property name="sensitive" bind-source="lockscreen_blur" bind-property="state" bind-flags="sync-create" />
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Screenshot blur</property>
<property name="description" translatable="yes">Add blur to the background of the window selector in the screenshot UI.</property>
<property name="header-suffix">
<object class="GtkSwitch" id="screenshot_blur">
<property name="valign">center</property>
</object>
</property>
<child>
<object class="CustomizeRow" id="screenshot_customize">
<property name="sensitive" bind-source="screenshot_blur" bind-property="state" bind-flags="sync-create" />
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Window list extension blur</property>
<property name="description" translatable="yes">Make the window-list extension blurred, if it is used.</property>
<property name="header-suffix">
<object class="GtkSwitch" id="window_list_blur">
<property name="valign">center</property>
</object>
</property>
<child>
<object class="CustomizeRow" id="window_list_customize">
<property name="sensitive" bind-source="window_list_blur" bind-property="state" bind-flags="sync-create" />
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="blur-my-shell@aunetx">
<template class="Overview" parent="AdwPreferencesPage">
<property name="name">overview</property>
<property name="title" translatable="yes">Overview</property>
<property name="icon-name">overview-symbolic</property>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Background blur</property>
<property name="description" translatable="yes">Add blur to the overview background, using the wallpaper picture.</property>
<property name="header-suffix">
<object class="GtkSwitch" id="overview_blur">
<property name="valign">center</property>
</object>
</property>
<child>
<object class="CustomizeRow" id="overview_customize">
<property name="sensitive" bind-source="overview_blur" bind-property="state" bind-flags="sync-create" />
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Overview components style</property>
<property name="subtitle" translatable="yes">The semi-transparent style for the dash, search entry/results, and application folders.</property>
<property name="sensitive" bind-source="overview_blur" bind-property="state" bind-flags="sync-create" />
<property name="activatable-widget">overview_style_components</property>
<child>
<object class="GtkDropDown" id="overview_style_components">
<property name="valign">center</property>
<property name="model">overview_style_components_model</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Application folder blur</property>
<property name="description" translatable="yes">Makes the background of application folder dialogs blurred.</property>
<property name="header-suffix">
<object class="GtkSwitch" id="appfolder_blur">
<property name="valign">center</property>
</object>
</property>
<child>
<object class="CustomizeRow" id="appfolder_customize">
<property name="sensitive" bind-source="appfolder_blur" bind-property="state" bind-flags="sync-create" />
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Application folder dialogs style</property>
<property name="subtitle" translatable="yes">The semi-transparent style for the application folder dialogs.</property>
<property name="sensitive" bind-source="appfolder_blur" bind-property="state" bind-flags="sync-create" />
<property name="activatable-widget">appfolder_style_dialogs</property>
<child>
<object class="GtkDropDown" id="appfolder_style_dialogs">
<property name="valign">center</property>
<property name="model">appfolder_style_dialogs_model</property>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
<object class="GtkStringList" id="overview_style_components_model">
<items>
<item translatable="yes">Do not style</item>
<item translatable="yes">Light</item>
<item translatable="yes">Dark</item>
<item translatable="yes">Transparent</item>
</items>
</object>
<object class="GtkStringList" id="appfolder_style_dialogs_model">
<items>
<item translatable="yes">Do not style</item>
<item translatable="yes">Transparent</item>
<item translatable="yes">Light</item>
<item translatable="yes">Dark</item>
</items>
</object>
</interface>

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="blur-my-shell@aunetx">
<template class="Panel" parent="AdwPreferencesPage">
<property name="name">panel</property>
<property name="title" translatable="yes">Panel</property>
<property name="icon-name">bottom-panel-symbolic</property>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Panel blur</property>
<property name="description" translatable="yes">Blur the top panel using the background image.</property>
<property name="header-suffix">
<object class="GtkSwitch" id="blur">
<property name="valign">center</property>
</object>
</property>
<child>
<object class="CustomizeRow" id="customize">
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Static blur</property>
<property name="subtitle" translatable="yes">Uses a static blurred image, more performant and stable.</property>
<property name="activatable-widget">static_blur</property>
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
<child>
<object class="GtkSwitch" id="static_blur">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Disable in overview</property>
<property name="subtitle" translatable="yes">Disables the blur from the panel when entering the overview.</property>
<property name="activatable-widget">unblur_in_overview</property>
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
<child>
<object class="GtkSwitch" id="unblur_in_overview">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwExpanderRow" id="override_background">
<property name="title" translatable="yes">Override background</property>
<property name="subtitle" translatable="yes">Override the background of the panel to use a transparent or semi-transparent one.
Recommended unless you want to customize your GNOME theme.</property>
<property name="show-enable-switch">true</property>
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Background style</property>
<property name="subtitle" translatable="yes">The transparent/semi-transparent style for the panel background.</property>
<property name="activatable-widget">style_panel</property>
<child>
<object class="GtkDropDown" id="style_panel">
<property name="valign">center</property>
<property name="model">style_panel_model</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Disable when a window is near</property>
<property name="subtitle" translatable="yes">Disables the transparency of the panel when a window is near it.</property>
<property name="activatable-widget">override_background_dynamically</property>
<child>
<object class="GtkSwitch" id="override_background_dynamically">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Compatibility</property>
<property name="description" translatable="yes">Various options to provide compatibility with other extensions.</property>
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Hidetopbar extension</property>
<property name="subtitle" translatable="yes">Does not disable the blur in overview, best used with static blur.</property>
<property name="activatable-widget">hidetopbar_compatibility</property>
<property name="sensitive" bind-source="unblur_in_overview" bind-property="state" bind-flags="sync-create" />
<child>
<object class="GtkSwitch" id="hidetopbar_compatibility">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Blur original panel with Dash to Panel</property>
<property name="subtitle" translatable="yes">Enables the blurring of the original panel with Dash to Panel, if selected in the extension's options.</property>
<property name="activatable-widget">dtp_blur_original_panel</property>
<child>
<object class="GtkSwitch" id="dtp_blur_original_panel">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
<object class="GtkStringList" id="style_panel_model">
<items>
<item translatable="yes">Transparent</item>
<item translatable="yes">Light</item>
<item translatable="yes">Dark</item>
<item translatable="yes">Contrasted</item>
</items>
</object>
</interface>

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="blur-my-shell@aunetx">
<template class="WindowRow" parent="AdwExpanderRow">
<property name="title" translatable="yes">Window Name</property>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Select window</property>
<property name="subtitle" translatable="yes">Pick a window or select it by its classname.</property>
<child>
<object class="GtkBox" id="window_selector">
<property name="valign">center</property>
<property name="hexpand">true</property>
<property name="width-request">175px</property>
<style>
<class name="linked" />
</style>
<child>
<object class="GtkButton" id="window_picker">
<property name="valign">center</property>
<property name="hexpand">true</property>
<property name="icon-name">select-window-symbolic</property>
</object>
</child>
<child>
<object class="GtkEntry" id="window_class">
<property name="valign">center</property>
<property name="hexpand">true</property>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
<object class="AdwToast" id="picking_failure_toast">
<property name="title">Could not pick window, make sure that the extension is enabled.</property>
</object>
</interface>