[gnome] Update extensions
@ -1,11 +1,22 @@
|
||||
import Shell from 'gi://Shell';
|
||||
import Clutter from 'gi://Clutter';
|
||||
import Cogl from 'gi://Cogl';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
import { adjustAnimationTime } from 'resource:///org/gnome/shell/misc/animationUtils.js';
|
||||
|
||||
import { PaintSignals } from '../effects/paint_signals.js';
|
||||
import { PaintSignals } from '../conveniences/paint_signals.js';
|
||||
// TODO drop Tweener in favour of Clutter's `ease` (will need to extend the blur effect for it)
|
||||
const Tweener = imports.tweener.tweener;
|
||||
|
||||
const transparent = Clutter.Color.from_pixel(0x00000000);
|
||||
// TODO: Drop GNOME 46 backwards compatibility
|
||||
const transparent = Clutter.Color ?
|
||||
Clutter.Color.from_pixel(0x00000000) :
|
||||
new Cogl.Color({
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0,
|
||||
alpha: 0
|
||||
});
|
||||
const FOLDER_DIALOG_ANIMATION_TIME = 200;
|
||||
|
||||
const DIALOGS_STYLES = [
|
||||
@ -43,7 +54,7 @@ let _zoomAndFadeIn = function () {
|
||||
{
|
||||
radius: sigma * 2,
|
||||
brightness: brightness,
|
||||
time: FOLDER_DIALOG_ANIMATION_TIME / 1000,
|
||||
time: adjustAnimationTime(FOLDER_DIALOG_ANIMATION_TIME / 1000),
|
||||
transition: 'easeOutQuad'
|
||||
}
|
||||
);
|
||||
@ -87,7 +98,7 @@ let _zoomAndFadeOut = function () {
|
||||
{
|
||||
radius: 0,
|
||||
brightness: 1.0,
|
||||
time: FOLDER_DIALOG_ANIMATION_TIME / 1000,
|
||||
time: adjustAnimationTime(FOLDER_DIALOG_ANIMATION_TIME / 1000),
|
||||
transition: 'easeInQuad'
|
||||
}
|
||||
);
|
||||
@ -120,6 +131,8 @@ let _zoomAndFadeOut = function () {
|
||||
|
||||
|
||||
export const AppFoldersBlur = class AppFoldersBlur {
|
||||
// we do not use the effects manager and dummy pipelines here because we
|
||||
// really want to manage our sigma value ourself during the transition
|
||||
constructor(connections, settings, _) {
|
||||
this.connections = connections;
|
||||
this.paint_signals = new PaintSignals(connections);
|
||||
@ -129,12 +142,8 @@ export const AppFoldersBlur = class AppFoldersBlur {
|
||||
enable() {
|
||||
this._log("blurring appfolders");
|
||||
|
||||
brightness = this.settings.appfolder.CUSTOMIZE
|
||||
? this.settings.appfolder.BRIGHTNESS
|
||||
: this.settings.BRIGHTNESS;
|
||||
sigma = this.settings.appfolder.CUSTOMIZE
|
||||
? this.settings.appfolder.SIGMA
|
||||
: this.settings.SIGMA;
|
||||
brightness = this.settings.appfolder.BRIGHTNESS;
|
||||
sigma = this.settings.appfolder.SIGMA;
|
||||
|
||||
let appDisplay = Main.overview._overview.controls._appDisplay;
|
||||
|
||||
@ -143,15 +152,15 @@ export const AppFoldersBlur = class AppFoldersBlur {
|
||||
}
|
||||
|
||||
this.connections.connect(
|
||||
appDisplay, 'view-loaded', this.blur_appfolders.bind(this)
|
||||
appDisplay, 'view-loaded', _ => this.blur_appfolders()
|
||||
);
|
||||
}
|
||||
|
||||
blur_appfolders() {
|
||||
let appDisplay = Main.overview._overview.controls._appDisplay;
|
||||
|
||||
if (this.settings.HACKS_LEVEL === 1 || this.settings.HACKS_LEVEL === 2)
|
||||
this._log(`appfolders hack level ${this.settings.HACKS_LEVEL}`);
|
||||
if (this.settings.HACKS_LEVEL === 1)
|
||||
this._log("appfolders hack level 1");
|
||||
|
||||
appDisplay._folderIcons.forEach(icon => {
|
||||
icon._ensureFolderDialog();
|
||||
@ -197,7 +206,7 @@ export const AppFoldersBlur = class AppFoldersBlur {
|
||||
//
|
||||
// [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857
|
||||
|
||||
if (this.settings.HACKS_LEVEL === 1 || this.settings.HACKS_LEVEL === 2) {
|
||||
if (this.settings.HACKS_LEVEL === 1) {
|
||||
this.paint_signals.disconnect_all_for_actor(icon._dialog);
|
||||
this.paint_signals.connect(icon._dialog, blur_effect);
|
||||
} else {
|
||||
@ -218,11 +227,6 @@ export const AppFoldersBlur = class AppFoldersBlur {
|
||||
this.blur_appfolders();
|
||||
}
|
||||
|
||||
// not implemented for dynamic blur
|
||||
set_color(c) { }
|
||||
set_noise_amount(n) { }
|
||||
set_noise_lightness(l) { }
|
||||
|
||||
disable() {
|
||||
this._log("removing blur from appfolders");
|
||||
|
||||
|
||||
@ -1,24 +1,20 @@
|
||||
import Shell from 'gi://Shell';
|
||||
import Clutter from 'gi://Clutter';
|
||||
import Meta from 'gi://Meta';
|
||||
import Gio from 'gi://Gio';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
|
||||
import { PaintSignals } from '../effects/paint_signals.js';
|
||||
import { ApplicationsService } from '../dbus/services.js';
|
||||
import { PaintSignals } from '../conveniences/paint_signals.js';
|
||||
import { DummyPipeline } from '../conveniences/dummy_pipeline.js';
|
||||
|
||||
export const ApplicationsBlur = class ApplicationsBlur {
|
||||
constructor(connections, settings, _) {
|
||||
constructor(connections, settings, effects_manager) {
|
||||
this.connections = connections;
|
||||
this.settings = settings;
|
||||
this.effects_manager = effects_manager;
|
||||
this.paint_signals = new PaintSignals(connections);
|
||||
|
||||
this.mutter_gsettings = new Gio.Settings({ schema: 'org.gnome.mutter' });
|
||||
|
||||
// stores every blurred window
|
||||
this.window_map = new Map();
|
||||
// stores every blur actor
|
||||
this.blur_actor_map = new Map();
|
||||
// stores every blurred meta window
|
||||
this.meta_window_map = new Map();
|
||||
}
|
||||
|
||||
enable() {
|
||||
@ -28,6 +24,8 @@ export const ApplicationsBlur = class ApplicationsBlur {
|
||||
this.service = new ApplicationsService;
|
||||
this.service.export();
|
||||
|
||||
this.mutter_gsettings = new Gio.Settings({ schema: 'org.gnome.mutter' });
|
||||
|
||||
// blur already existing windows
|
||||
this.update_all_windows();
|
||||
|
||||
@ -38,16 +36,42 @@ export const ApplicationsBlur = class ApplicationsBlur {
|
||||
(_meta_display, meta_window) => {
|
||||
this._log("window created");
|
||||
|
||||
if (meta_window) {
|
||||
let window_actor = meta_window.get_compositor_private();
|
||||
this.track_new(window_actor, meta_window);
|
||||
}
|
||||
if (meta_window)
|
||||
this.track_new(meta_window);
|
||||
}
|
||||
);
|
||||
|
||||
// update window blur when focus is changed
|
||||
this.focused_window_pid = null;
|
||||
this.init_dynamic_opacity();
|
||||
this.connections.connect(
|
||||
global.display,
|
||||
'focus-window',
|
||||
(_meta_display, meta_window, _p0) => {
|
||||
if (meta_window && meta_window.bms_pid != this.focused_window_pid)
|
||||
this.set_focus_for_window(meta_window);
|
||||
else if (!meta_window)
|
||||
this.set_focus_for_window(null);
|
||||
}
|
||||
);
|
||||
|
||||
this.connect_to_overview();
|
||||
}
|
||||
|
||||
/// Initializes the dynamic opacity for windows, without touching to the connections.
|
||||
/// This is used both when enabling the component, and when changing the dynamic-opacity pref.
|
||||
init_dynamic_opacity() {
|
||||
if (this.settings.applications.DYNAMIC_OPACITY) {
|
||||
// make the currently focused window solid
|
||||
if (global.display.focus_window)
|
||||
this.set_focus_for_window(global.display.focus_window);
|
||||
} else {
|
||||
// remove old focused window if the pref was changed
|
||||
if (this.focused_window_pid)
|
||||
this.set_focus_for_window(null);
|
||||
}
|
||||
}
|
||||
|
||||
/// Connect to the overview being opened/closed to force the blur being
|
||||
/// shown on every window of the workspaces viewer.
|
||||
connect_to_overview() {
|
||||
@ -58,9 +82,9 @@ export const ApplicationsBlur = class ApplicationsBlur {
|
||||
// allows the blur to be shown too)
|
||||
this.connections.connect(
|
||||
Main.overview, 'showing',
|
||||
_ => this.window_map.forEach((meta_window, _pid) => {
|
||||
_ => this.meta_window_map.forEach((meta_window, _pid) => {
|
||||
let window_actor = meta_window.get_compositor_private();
|
||||
window_actor.show();
|
||||
window_actor?.show();
|
||||
})
|
||||
);
|
||||
|
||||
@ -69,7 +93,7 @@ export const ApplicationsBlur = class ApplicationsBlur {
|
||||
this.connections.connect(
|
||||
Main.overview, 'hidden',
|
||||
_ => {
|
||||
this.window_map.forEach((meta_window, _pid) => {
|
||||
this.meta_window_map.forEach((meta_window, _pid) => {
|
||||
let window_actor = meta_window.get_compositor_private();
|
||||
|
||||
if (
|
||||
@ -86,7 +110,7 @@ export const ApplicationsBlur = class ApplicationsBlur {
|
||||
update_all_windows() {
|
||||
// remove all previously blurred windows, in the case where the
|
||||
// whitelist was changed
|
||||
this.window_map.forEach(((_meta_window, pid) => {
|
||||
this.meta_window_map.forEach(((_meta_window, pid) => {
|
||||
this.remove_blur(pid);
|
||||
}));
|
||||
|
||||
@ -98,82 +122,81 @@ export const ApplicationsBlur = class ApplicationsBlur {
|
||||
let workspace = global.workspace_manager.get_workspace_by_index(i);
|
||||
let windows = workspace.list_windows();
|
||||
|
||||
windows.forEach(meta_window => {
|
||||
let window_actor = meta_window.get_compositor_private();
|
||||
|
||||
// disconnect previous signals
|
||||
this.connections.disconnect_all_for(window_actor);
|
||||
|
||||
this.track_new(window_actor, meta_window);
|
||||
});
|
||||
windows.forEach(meta_window => this.track_new(meta_window));
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds the needed signals to every new tracked window, and adds blur if
|
||||
/// needed.
|
||||
track_new(window_actor, meta_window) {
|
||||
let pid = ("" + Math.random()).slice(2, 16);
|
||||
/// Accepts only untracked meta windows (i.e no `bms_pid` set)
|
||||
track_new(meta_window) {
|
||||
// create a pid that will follow the window during its whole life
|
||||
const pid = ("" + Math.random()).slice(2, 16);
|
||||
meta_window.bms_pid = pid;
|
||||
|
||||
window_actor['blur_provider_pid'] = pid;
|
||||
meta_window['blur_provider_pid'] = pid;
|
||||
this._log(`new window tracked, pid: ${pid}`);
|
||||
|
||||
// remove the blur when the window is destroyed
|
||||
this.connections.connect(window_actor, 'destroy', window_actor => {
|
||||
let pid = window_actor.blur_provider_pid;
|
||||
if (this.blur_actor_map.has(pid)) {
|
||||
this.remove_blur(pid);
|
||||
}
|
||||
this.window_map.delete(pid);
|
||||
});
|
||||
// register the blurred window
|
||||
this.meta_window_map.set(pid, meta_window);
|
||||
|
||||
// update the blur when mutter-hint or wm-class is changed
|
||||
for (const prop of ['mutter-hints', 'wm-class']) {
|
||||
this.connections.connect(
|
||||
meta_window,
|
||||
`notify::${prop}`,
|
||||
_ => {
|
||||
let pid = meta_window.blur_provider_pid;
|
||||
this._log(`${prop} changed for pid ${pid}`);
|
||||
|
||||
let window_actor = meta_window.get_compositor_private();
|
||||
this.check_blur(pid, window_actor, meta_window);
|
||||
}
|
||||
);
|
||||
}
|
||||
// update the blur when wm-class is changed
|
||||
this.connections.connect(
|
||||
meta_window, 'notify::wm-class',
|
||||
_ => this.check_blur(meta_window)
|
||||
);
|
||||
|
||||
// update the position and size when the window size changes
|
||||
this.connections.connect(meta_window, 'size-changed', () => {
|
||||
if (this.blur_actor_map.has(pid)) {
|
||||
let allocation = this.compute_allocation(meta_window);
|
||||
let blur_actor = this.blur_actor_map.get(pid);
|
||||
this.connections.connect(
|
||||
meta_window, 'size-changed',
|
||||
_ => this.update_size(pid)
|
||||
);
|
||||
|
||||
// remove the blur when the window is unmanaged
|
||||
this.connections.connect(
|
||||
meta_window, 'unmanaging',
|
||||
_ => this.untrack_meta_window(pid)
|
||||
);
|
||||
|
||||
this.check_blur(meta_window);
|
||||
}
|
||||
|
||||
/// Updates the size of the blur actor associated to a meta window from its pid.
|
||||
/// Accepts only tracked meta window (i.e `bms_pid` set), be it blurred or not.
|
||||
update_size(pid) {
|
||||
if (this.meta_window_map.has(pid)) {
|
||||
const meta_window = this.meta_window_map.get(pid);
|
||||
const blur_actor = meta_window.blur_actor;
|
||||
if (blur_actor) {
|
||||
const allocation = this.compute_allocation(meta_window);
|
||||
blur_actor.x = allocation.x;
|
||||
blur_actor.y = allocation.y;
|
||||
blur_actor.width = allocation.width;
|
||||
blur_actor.height = allocation.height;
|
||||
}
|
||||
});
|
||||
|
||||
this.check_blur(pid, window_actor, meta_window);
|
||||
} else
|
||||
// the pid was visibly not removed
|
||||
this.untrack_meta_window(pid);
|
||||
}
|
||||
|
||||
/// Checks if the given actor needs to be blurred.
|
||||
/// Accepts only tracked meta window, be it blurred or not.
|
||||
///
|
||||
/// In order to be blurred, a window either:
|
||||
/// - is whitelisted in the user preferences if not enable-all
|
||||
/// - is not blacklisted if enable-all
|
||||
/// - has a correct mutter hint, set to `blur-provider=sigma_value`
|
||||
check_blur(pid, window_actor, meta_window) {
|
||||
let mutter_hint = meta_window.get_mutter_hints();
|
||||
let window_wm_class = meta_window.get_wm_class();
|
||||
check_blur(meta_window) {
|
||||
const window_wm_class = meta_window.get_wm_class();
|
||||
const enable_all = this.settings.applications.ENABLE_ALL;
|
||||
const whitelist = this.settings.applications.WHITELIST;
|
||||
const blacklist = this.settings.applications.BLACKLIST;
|
||||
if (window_wm_class)
|
||||
this._log(`pid ${meta_window.bms_pid} associated to wm class name ${window_wm_class}`);
|
||||
|
||||
let enable_all = this.settings.applications.ENABLE_ALL;
|
||||
let whitelist = this.settings.applications.WHITELIST;
|
||||
let blacklist = this.settings.applications.BLACKLIST;
|
||||
|
||||
this._log(`checking blur for ${pid}`);
|
||||
|
||||
// either the window is included in whitelist
|
||||
if (window_wm_class !== ""
|
||||
// if we are in blacklist mode and the window is not blacklisted
|
||||
// or if we are in whitelist mode and the window is whitelisted
|
||||
if (
|
||||
window_wm_class !== ""
|
||||
&& ((enable_all && !blacklist.includes(window_wm_class))
|
||||
|| (!enable_all && whitelist.includes(window_wm_class))
|
||||
)
|
||||
@ -183,209 +206,114 @@ export const ApplicationsBlur = class ApplicationsBlur {
|
||||
Meta.FrameType.MODAL_DIALOG
|
||||
].includes(meta_window.get_frame_type())
|
||||
) {
|
||||
this._log(`application ${pid} listed, blurring it`);
|
||||
|
||||
// get blur effect parameters
|
||||
|
||||
let brightness, sigma;
|
||||
|
||||
if (this.settings.applications.CUSTOMIZE) {
|
||||
brightness = this.settings.applications.BRIGHTNESS;
|
||||
sigma = this.settings.applications.SIGMA;
|
||||
} else {
|
||||
brightness = this.settings.BRIGHTNESS;
|
||||
sigma = this.settings.SIGMA;
|
||||
}
|
||||
|
||||
this.update_blur(pid, window_actor, meta_window, brightness, sigma);
|
||||
// only blur the window if it is not already done
|
||||
if (!meta_window.blur_actor)
|
||||
this.create_blur_effect(meta_window);
|
||||
}
|
||||
|
||||
// or blur is asked by window itself
|
||||
else if (
|
||||
mutter_hint != null &&
|
||||
mutter_hint.includes("blur-provider")
|
||||
) {
|
||||
this._log(`application ${pid} has hint ${mutter_hint}, parsing`);
|
||||
|
||||
// get blur effect parameters
|
||||
let [brightness, sigma] = this.parse_xprop(mutter_hint);
|
||||
|
||||
this.update_blur(pid, window_actor, meta_window, brightness, sigma);
|
||||
}
|
||||
|
||||
// remove blur if the mutter hint is no longer valid, and the window
|
||||
// is not explicitly whitelisted or un-blacklisted
|
||||
else if (this.blur_actor_map.has(pid)) {
|
||||
this.remove_blur(pid);
|
||||
}
|
||||
}
|
||||
|
||||
/// When given the xprop property, returns the brightness and sigma values
|
||||
/// matching. If one of the two values is invalid, or missing, then it uses
|
||||
/// default values.
|
||||
///
|
||||
/// An xprop property is valid if it is in one of the following formats:
|
||||
///
|
||||
/// blur-provider=sigma:60,brightness:0.9
|
||||
/// blur-provider=s:10,brightness:0.492
|
||||
/// blur-provider=b:1.0,s:16
|
||||
///
|
||||
/// Brightness is a floating-point between 0.0 and 1.0 included.
|
||||
/// Sigma is an integer between 0 and 999 included.
|
||||
///
|
||||
/// If sigma is set to 0, then the blur is removed.
|
||||
/// Setting "default" instead of the two values will make the
|
||||
/// extension use its default value.
|
||||
///
|
||||
/// Note that no space can be inserted.
|
||||
///
|
||||
parse_xprop(property) {
|
||||
// set brightness and sigma to default values
|
||||
let brightness, sigma;
|
||||
if (this.settings.applications.CUSTOMIZE) {
|
||||
brightness = this.settings.applications.BRIGHTNESS;
|
||||
sigma = this.settings.applications.SIGMA;
|
||||
} else {
|
||||
brightness = this.settings.BRIGHTNESS;
|
||||
sigma = this.settings.SIGMA;
|
||||
}
|
||||
|
||||
// get the argument of the property
|
||||
let arg = property.match("blur-provider=(.*)");
|
||||
this._log(`argument = ${arg}`);
|
||||
|
||||
// if argument is valid, parse it
|
||||
if (arg != null) {
|
||||
// verify if there is only one value: in this case, this is sigma
|
||||
let maybe_sigma = parseInt(arg[1]);
|
||||
|
||||
if (
|
||||
!isNaN(maybe_sigma) &&
|
||||
maybe_sigma >= 0 &&
|
||||
maybe_sigma <= 999
|
||||
) {
|
||||
sigma = maybe_sigma;
|
||||
} else {
|
||||
// perform pattern matching
|
||||
let res_b = arg[1].match("(brightness|b):(default|0?1?\.[0-9]*)");
|
||||
let res_s = arg[1].match("(sigma|s):(default|\\d{1,3})");
|
||||
|
||||
// if values are valid and not default, change them to the xprop one
|
||||
if (
|
||||
res_b != null && res_b[2] !== 'default'
|
||||
) {
|
||||
brightness = parseFloat(res_b[2]);
|
||||
}
|
||||
|
||||
if (
|
||||
res_s != null && res_s[2] !== 'default'
|
||||
) {
|
||||
sigma = parseInt(res_s[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._log(`brightness = ${brightness}, sigma = ${sigma}`);
|
||||
|
||||
return [brightness, sigma];
|
||||
}
|
||||
|
||||
/// Updates the blur on a window which needs to be blurred.
|
||||
update_blur(pid, window_actor, meta_window, brightness, sigma) {
|
||||
// the window is already blurred, update its blur effect
|
||||
if (this.blur_actor_map.has(pid)) {
|
||||
// window is already blurred, but sigma is null: remove the blur
|
||||
if (sigma === 0) {
|
||||
this.remove_blur(pid);
|
||||
}
|
||||
// window is already blurred and sigma is non-null: update it
|
||||
else {
|
||||
this.update_blur_effect(
|
||||
this.blur_actor_map.get(pid),
|
||||
brightness,
|
||||
sigma
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// the window is not blurred, and sigma is a non-null value: blur it
|
||||
else if (sigma !== 0) {
|
||||
// window is not blurred, blur it
|
||||
this.create_blur_effect(
|
||||
pid,
|
||||
window_actor,
|
||||
meta_window,
|
||||
brightness,
|
||||
sigma
|
||||
);
|
||||
}
|
||||
// remove blur it is not explicitly whitelisted or un-blacklisted
|
||||
else if (meta_window.blur_actor)
|
||||
this.remove_blur(meta_window.bms_pid);
|
||||
}
|
||||
|
||||
/// Add the blur effect to the window.
|
||||
create_blur_effect(pid, window_actor, meta_window, brightness, sigma) {
|
||||
let blur_effect = new Shell.BlurEffect({
|
||||
radius: sigma * 2,
|
||||
brightness: brightness,
|
||||
mode: Shell.BlurMode.BACKGROUND
|
||||
});
|
||||
/// Accepts only tracked meta window that is NOT already blurred.
|
||||
create_blur_effect(meta_window) {
|
||||
const pid = meta_window.bms_pid;
|
||||
const window_actor = meta_window.get_compositor_private();
|
||||
|
||||
let blur_actor = this.create_blur_actor(
|
||||
meta_window,
|
||||
window_actor,
|
||||
blur_effect
|
||||
const pipeline = new DummyPipeline(this.effects_manager, this.settings.applications);
|
||||
let [blur_actor, bg_manager] = pipeline.create_background_with_effect(
|
||||
window_actor, 'bms-application-blurred-widget'
|
||||
);
|
||||
|
||||
meta_window.blur_actor = blur_actor;
|
||||
meta_window.bg_manager = bg_manager;
|
||||
|
||||
// if hacks are selected, force to repaint the window
|
||||
if (this.settings.HACKS_LEVEL === 1 || this.settings.HACKS_LEVEL === 2) {
|
||||
this._log("applications hack level 1 or 2");
|
||||
if (this.settings.HACKS_LEVEL === 1) {
|
||||
this._log("hack level 1");
|
||||
|
||||
this.paint_signals.disconnect_all();
|
||||
this.paint_signals.connect(blur_actor, blur_effect);
|
||||
this.paint_signals.disconnect_all_for_actor(blur_actor);
|
||||
this.paint_signals.connect(blur_actor, pipeline.effect);
|
||||
} else {
|
||||
this.paint_signals.disconnect_all();
|
||||
this.paint_signals.disconnect_all_for_actor(blur_actor);
|
||||
}
|
||||
|
||||
// insert the blurred widget
|
||||
window_actor.insert_child_at_index(blur_actor, 0);
|
||||
|
||||
// make sure window is blurred in overview
|
||||
if (this.settings.applications.BLUR_ON_OVERVIEW)
|
||||
this.enforce_window_visibility_on_overview_for(window_actor);
|
||||
|
||||
// update the size
|
||||
this.update_size(pid);
|
||||
|
||||
// set the window actor's opacity
|
||||
this.set_window_opacity(window_actor, this.settings.applications.OPACITY);
|
||||
|
||||
// now set up the signals, for the window actor only: they are disconnected
|
||||
// in `remove_blur`, whereas the signals for the meta window are disconnected
|
||||
// only when the whole component is disabled
|
||||
|
||||
// update the window opacity when it changes, else we don't control it fully
|
||||
this.connections.connect(
|
||||
window_actor,
|
||||
'notify::opacity',
|
||||
_ => this.set_window_opacity(window_actor, this.settings.applications.OPACITY)
|
||||
window_actor, 'notify::opacity',
|
||||
_ => {
|
||||
if (this.focused_window_pid != pid)
|
||||
this.set_window_opacity(window_actor, this.settings.applications.OPACITY);
|
||||
}
|
||||
);
|
||||
|
||||
// register the blur actor/effect
|
||||
blur_actor['blur_provider_pid'] = pid;
|
||||
this.blur_actor_map.set(pid, blur_actor);
|
||||
this.window_map.set(pid, meta_window);
|
||||
|
||||
// hide the blur if window is invisible
|
||||
if (!window_actor.visible) {
|
||||
blur_actor.hide();
|
||||
}
|
||||
|
||||
// hide the blur if window becomes invisible
|
||||
if (!window_actor.visible)
|
||||
blur_actor.hide();
|
||||
|
||||
this.connections.connect(
|
||||
window_actor,
|
||||
'notify::visible',
|
||||
window_actor => {
|
||||
let pid = window_actor.blur_provider_pid;
|
||||
if (window_actor.visible) {
|
||||
this.blur_actor_map.get(pid).show();
|
||||
} else {
|
||||
this.blur_actor_map.get(pid).hide();
|
||||
}
|
||||
if (window_actor.visible)
|
||||
meta_window.blur_actor.show();
|
||||
else
|
||||
meta_window.blur_actor.hide();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// With `focus=true`, tells us we are focused on said window (which can be null if
|
||||
/// we are not focused anymore). It automatically removes the ancient focus.
|
||||
/// With `focus=false`, just remove the focus from said window (which can still be null).
|
||||
set_focus_for_window(meta_window, focus = true) {
|
||||
let blur_actor = null;
|
||||
let window_actor = null;
|
||||
let new_pid = null;
|
||||
if (meta_window) {
|
||||
blur_actor = meta_window.blur_actor;
|
||||
window_actor = meta_window.get_compositor_private();
|
||||
new_pid = meta_window.bms_pid;
|
||||
}
|
||||
|
||||
if (focus) {
|
||||
// remove old focused window if any
|
||||
if (this.focused_window_pid) {
|
||||
const old_focused_window = this.meta_window_map.get(this.focused_window_pid);
|
||||
if (old_focused_window)
|
||||
this.set_focus_for_window(old_focused_window, false);
|
||||
}
|
||||
// set new focused window pid
|
||||
this.focused_window_pid = new_pid;
|
||||
// if we have blur, hide it and make the window opaque
|
||||
if (this.settings.applications.DYNAMIC_OPACITY && blur_actor) {
|
||||
blur_actor.hide();
|
||||
this.set_window_opacity(window_actor, 255);
|
||||
}
|
||||
}
|
||||
// if we remove the focus and have blur, show it and make the window transparent
|
||||
else if (blur_actor) {
|
||||
blur_actor.show();
|
||||
this.set_window_opacity(window_actor, this.settings.applications.OPACITY);
|
||||
}
|
||||
}
|
||||
|
||||
/// Makes sure that, when the overview is visible, the window actor will
|
||||
/// stay visible no matter what.
|
||||
/// We can instead hide the last child of the window actor, which will
|
||||
@ -412,12 +340,24 @@ export const ApplicationsBlur = class ApplicationsBlur {
|
||||
|
||||
/// Set the opacity of the window actor that sits on top of the blur effect.
|
||||
set_window_opacity(window_actor, opacity) {
|
||||
window_actor.get_children().forEach(child => {
|
||||
window_actor?.get_children().forEach(child => {
|
||||
if (child.name !== "blur-actor" && child.opacity != opacity)
|
||||
child.opacity = opacity;
|
||||
});
|
||||
}
|
||||
|
||||
/// Update the opacity of all window actors.
|
||||
set_opacity() {
|
||||
let opacity = this.settings.applications.OPACITY;
|
||||
|
||||
this.meta_window_map.forEach(((meta_window, pid) => {
|
||||
if (pid != this.focused_window_pid && meta_window.blur_actor) {
|
||||
let window_actor = meta_window.get_compositor_private();
|
||||
this.set_window_opacity(window_actor, opacity);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/// Compute the size and position for a blur actor.
|
||||
/// If `scale-monitor-framebuffer` experimental feature if on, we don't need to manage scaling.
|
||||
/// Else, on wayland, we need to divide by the scale to get the correct result.
|
||||
@ -442,107 +382,68 @@ export const ApplicationsBlur = class ApplicationsBlur {
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns a new already blurred widget, configured to follow the size and
|
||||
/// position of its target window.
|
||||
create_blur_actor(meta_window, window_actor, blur_effect) {
|
||||
// compute the size and position
|
||||
let allocation = this.compute_allocation(meta_window);
|
||||
|
||||
// create the actor
|
||||
let blur_actor = new Clutter.Actor({
|
||||
x: allocation.x,
|
||||
y: allocation.y,
|
||||
width: allocation.width,
|
||||
height: allocation.height
|
||||
});
|
||||
|
||||
// add the effect
|
||||
blur_actor.add_effect_with_name('blur-effect', blur_effect);
|
||||
|
||||
return blur_actor;
|
||||
}
|
||||
|
||||
/// Updates the blur effect by overwriting its sigma and brightness values.
|
||||
update_blur_effect(blur_actor, brightness, sigma) {
|
||||
let effect = blur_actor.get_effect('blur-effect');
|
||||
effect.radius = sigma * 2;
|
||||
effect.brightness = brightness;
|
||||
}
|
||||
|
||||
/// Removes the blur actor from the shell and unregister it.
|
||||
/// Removes the blur actor to make a blurred window become normal again.
|
||||
/// It however does not untrack the meta window itself.
|
||||
/// Accepts a pid corresponding (or not) to a blurred (or not) meta window.
|
||||
remove_blur(pid) {
|
||||
this._log(`removing blur for pid ${pid}`);
|
||||
|
||||
let meta_window = this.window_map.get(pid);
|
||||
// disconnect needed signals and untrack window
|
||||
let meta_window = this.meta_window_map.get(pid);
|
||||
if (meta_window) {
|
||||
this.window_map.delete(pid);
|
||||
let window_actor = meta_window.get_compositor_private();
|
||||
let blur_actor = meta_window.blur_actor;
|
||||
let bg_manager = meta_window.bg_manager;
|
||||
|
||||
let blur_actor = this.blur_actor_map.get(pid);
|
||||
if (blur_actor) {
|
||||
this.blur_actor_map.delete(pid);
|
||||
if (blur_actor && window_actor) {
|
||||
// reset the opacity
|
||||
this.set_window_opacity(window_actor, 255);
|
||||
|
||||
if (window_actor) {
|
||||
// reset the opacity
|
||||
this.set_window_opacity(window_actor, 255);
|
||||
// remove the blurred actor
|
||||
window_actor.remove_child(blur_actor);
|
||||
bg_manager._bms_pipeline.destroy();
|
||||
bg_manager.destroy();
|
||||
blur_actor.destroy();
|
||||
|
||||
// remove the blurred actor
|
||||
window_actor.remove_child(blur_actor);
|
||||
// kinda untrack the blurred actor, as its presence is how we know
|
||||
// whether we are blurred or not
|
||||
delete meta_window.blur_actor;
|
||||
delete meta_window.bg_manager;
|
||||
|
||||
// disconnect the signals about overview animation etc
|
||||
this.connections.disconnect_all_for(window_actor);
|
||||
}
|
||||
// disconnect the signals of the window actor
|
||||
this.paint_signals.disconnect_all_for_actor(blur_actor);
|
||||
this.connections.disconnect_all_for(window_actor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Kinda the same as `remove_blur`, but better: it also untracks the window.
|
||||
/// This needs to be called when the component is being disabled, else it
|
||||
/// would cause havoc by having untracked windows during normal operations,
|
||||
/// which is not the point at all!
|
||||
/// Accepts a pid corresponding (or not) to a blurred (or not) meta window.
|
||||
untrack_meta_window(pid) {
|
||||
this.remove_blur(pid);
|
||||
let meta_window = this.meta_window_map.get(pid);
|
||||
if (meta_window) {
|
||||
this.connections.disconnect_all_for(meta_window);
|
||||
this.meta_window_map.delete(pid);
|
||||
}
|
||||
}
|
||||
|
||||
disable() {
|
||||
this._log("removing blur from applications...");
|
||||
|
||||
this.service?.unexport();
|
||||
delete this.mutter_gsettings;
|
||||
|
||||
this.blur_actor_map.forEach(((_blur_actor, pid) => {
|
||||
this.remove_blur(pid);
|
||||
}));
|
||||
this.meta_window_map.forEach((_meta_window, pid) => {
|
||||
this.untrack_meta_window(pid);
|
||||
});
|
||||
|
||||
this.connections.disconnect_all();
|
||||
this.paint_signals.disconnect_all();
|
||||
}
|
||||
|
||||
/// Update the opacity of all window actors.
|
||||
set_opacity() {
|
||||
let opacity = this.settings.applications.OPACITY;
|
||||
|
||||
this.window_map.forEach(((meta_window, _pid) => {
|
||||
let window_actor = meta_window.get_compositor_private();
|
||||
this.set_window_opacity(window_actor, opacity);
|
||||
}));
|
||||
}
|
||||
|
||||
/// Updates each blur effect to use new sigma value
|
||||
// FIXME set_sigma and set_brightness are called when the extension is
|
||||
// loaded and when sigma is changed, and do not respect the per-app
|
||||
// xprop behaviour
|
||||
set_sigma(s) {
|
||||
this.blur_actor_map.forEach((actor, _) => {
|
||||
actor.get_effect('blur-effect').set_sigma(s);
|
||||
});
|
||||
}
|
||||
|
||||
/// Updates each blur effect to use new brightness value
|
||||
set_brightness(b) {
|
||||
this.blur_actor_map.forEach((actor, _) => {
|
||||
actor.get_effect('blur-effect').set_brightness(b);
|
||||
});
|
||||
}
|
||||
|
||||
// not implemented for dynamic blur
|
||||
set_color(c) { }
|
||||
set_noise_amount(n) { }
|
||||
set_noise_lightness(l) { }
|
||||
|
||||
_log(str) {
|
||||
if (this.settings.DEBUG)
|
||||
console.log(`[Blur my Shell > applications] ${str}`);
|
||||
|
||||
@ -0,0 +1,91 @@
|
||||
import * as Main from "resource:///org/gnome/shell/ui/main.js";
|
||||
|
||||
import { PaintSignals } from "../conveniences/paint_signals.js";
|
||||
import { Pipeline } from "../conveniences/pipeline.js";
|
||||
|
||||
export const CoverflowAltTabBlur = class CoverflowAltTabBlur {
|
||||
constructor(connections, settings, effects_manager) {
|
||||
this.connections = connections;
|
||||
this.settings = settings;
|
||||
this.paint_signals = new PaintSignals(connections);
|
||||
this.effects_manager = effects_manager;
|
||||
this.background_actors = [];
|
||||
this.background_managers = [];
|
||||
}
|
||||
|
||||
enable() {
|
||||
this._log("blurring coverflow alt-tab");
|
||||
|
||||
this.update_backgrounds();
|
||||
|
||||
this.connections.connect(
|
||||
Main.layoutManager.uiGroup,
|
||||
"child-added",
|
||||
(_, child) => this.try_blur(child)
|
||||
);
|
||||
|
||||
this.connections.connect(Main.layoutManager, "monitors-changed", (_) => {
|
||||
this.update_backgrounds();
|
||||
});
|
||||
}
|
||||
|
||||
update_backgrounds() {
|
||||
this.remove_background_actors();
|
||||
|
||||
Main.layoutManager.uiGroup
|
||||
.get_children()
|
||||
.forEach((child) => this.try_blur(child));
|
||||
}
|
||||
|
||||
try_blur(actor) {
|
||||
if (
|
||||
actor.constructor.name !== "Meta_BackgroundGroup" ||
|
||||
actor.get_name() !== "coverflow-alt-tab-background-group"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._log("found coverflow alt-tab to blur");
|
||||
|
||||
for (let i = 0; i < Main.layoutManager.monitors.length; i++) {
|
||||
const pipeline = new Pipeline(
|
||||
this.effects_manager,
|
||||
global.blur_my_shell._pipelines_manager,
|
||||
this.settings.coverflow_alt_tab.PIPELINE
|
||||
);
|
||||
|
||||
const background_actor = pipeline.create_background_with_effects(
|
||||
i,
|
||||
this.background_managers,
|
||||
actor,
|
||||
"bms-coverflow-alt-tab-blurred-widget"
|
||||
);
|
||||
|
||||
this.background_actors.push(background_actor);
|
||||
}
|
||||
}
|
||||
|
||||
remove_background_actors() {
|
||||
this.background_actors.forEach((actor) => actor.destroy);
|
||||
this.background_actors = [];
|
||||
|
||||
this.background_managers.forEach((background_manager) => {
|
||||
background_manager._bms_pipeline.destroy();
|
||||
background_manager.destroy();
|
||||
});
|
||||
this.background_managers = [];
|
||||
}
|
||||
|
||||
disable() {
|
||||
this._log("removing blur from coverflow alt-tab");
|
||||
|
||||
this.remove_background_actors();
|
||||
this.connections.disconnect_all();
|
||||
}
|
||||
|
||||
_log(str) {
|
||||
if (this.settings.DEBUG) {
|
||||
console.log(`[Blur my Shell > coverflow alt-tab] ${str}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1,12 +1,11 @@
|
||||
import St from 'gi://St';
|
||||
import Shell from 'gi://Shell';
|
||||
import Meta from 'gi://Meta';
|
||||
import Mtk from 'gi://Mtk';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
const Signals = imports.signals;
|
||||
import * as Signals from 'resource:///org/gnome/shell/misc/signals.js';
|
||||
|
||||
import { PaintSignals } from '../effects/paint_signals.js';
|
||||
import { BlurEffect } from '../effects/blur_effect.js';
|
||||
import { PaintSignals } from '../conveniences/paint_signals.js';
|
||||
|
||||
import { Pipeline } from '../conveniences/pipeline.js';
|
||||
import { DummyPipeline } from '../conveniences/dummy_pipeline.js';
|
||||
|
||||
const DASH_STYLES = [
|
||||
"transparent-dash",
|
||||
@ -15,150 +14,65 @@ const DASH_STYLES = [
|
||||
];
|
||||
|
||||
|
||||
// An helper function to find the monitor in which an actor is situated,
|
||||
/// there might be a pre-existing function in GLib already
|
||||
function find_monitor_for(actor) {
|
||||
let extents = actor.get_transformed_extents();
|
||||
let rect = new Mtk.Rectangle({
|
||||
x: extents.get_x(),
|
||||
y: extents.get_y(),
|
||||
width: extents.get_width(),
|
||||
height: extents.get_height(),
|
||||
});
|
||||
|
||||
let index = global.display.get_monitor_index_for_rect(rect);
|
||||
|
||||
return Main.layoutManager.monitors[index];
|
||||
}
|
||||
|
||||
|
||||
/// This type of object is created for every dash found, and talks to the main
|
||||
/// DashBlur thanks to signals.
|
||||
///
|
||||
/// This allows to dynamically track the created dashes for each screen.
|
||||
class DashInfos {
|
||||
constructor(dash_blur, dash, dash_container, dash_background, background, background_parent, effect) {
|
||||
constructor(
|
||||
dash_blur, dash, dash_container, dash_background,
|
||||
background, background_group, bg_manager
|
||||
) {
|
||||
// the parent DashBlur object, to communicate
|
||||
this.dash_blur = dash_blur;
|
||||
this.dash_container = dash_container;
|
||||
// the blurred dash
|
||||
this.dash = dash;
|
||||
this.dash_container = dash_container;
|
||||
this.dash_background = dash_background;
|
||||
this.background_parent = background_parent;
|
||||
this.background = background;
|
||||
this.effect = effect;
|
||||
this.background_group = background_group;
|
||||
this.bg_manager = bg_manager;
|
||||
this.settings = dash_blur.settings;
|
||||
this.old_style = this.dash._background.style;
|
||||
|
||||
dash_blur.connections.connect(dash_blur, 'remove-dashes', () => {
|
||||
this._log("removing blur from dash");
|
||||
this.dash.get_parent().remove_child(this.background_parent);
|
||||
this.remove_style();
|
||||
});
|
||||
this.dash_destroy_id = dash.connect('destroy', () => this.remove_dash_blur(false));
|
||||
this.dash_blur_connections_ids = [];
|
||||
this.dash_blur_connections_ids.push(
|
||||
this.dash_blur.connect('remove-dashes', () => this.remove_dash_blur()),
|
||||
this.dash_blur.connect('override-style', () => this.override_style()),
|
||||
this.dash_blur.connect('remove-style', () => this.remove_style()),
|
||||
this.dash_blur.connect('show', () => this.background_group.show()),
|
||||
this.dash_blur.connect('hide', () => this.background_group.hide()),
|
||||
this.dash_blur.connect('update-size', () => this.update_size()),
|
||||
this.dash_blur.connect('change-blur-type', () => this.change_blur_type()),
|
||||
this.dash_blur.connect('update-pipeline', () => this.update_pipeline())
|
||||
);
|
||||
}
|
||||
|
||||
dash_blur.connections.connect(dash_blur, 'update-sigma', () => {
|
||||
if (this.dash_blur.is_static) {
|
||||
this.dash_blur.update_size();
|
||||
}
|
||||
this.effect.radius = 2 * this.dash_blur.sigma * this.effect.scale;
|
||||
});
|
||||
// IMPORTANT: do never call this in a mutable `this.dash_blur.forEach`
|
||||
remove_dash_blur(dash_not_already_destroyed = true) {
|
||||
// remove the style and destroy the effects
|
||||
this.remove_style();
|
||||
this.destroy_dash(dash_not_already_destroyed);
|
||||
|
||||
dash_blur.connections.connect(dash_blur, 'update-brightness', () => {
|
||||
this.effect.brightness = this.dash_blur.brightness;
|
||||
});
|
||||
// remove the dash infos from their list
|
||||
const dash_infos_index = this.dash_blur.dashes.indexOf(this);
|
||||
if (dash_infos_index >= 0)
|
||||
this.dash_blur.dashes.splice(dash_infos_index, 1);
|
||||
|
||||
dash_blur.connections.connect(dash_blur, 'update-corner-radius', () => {
|
||||
if (this.dash_blur.is_static) {
|
||||
let monitor = find_monitor_for(this.dash);
|
||||
let corner_radius = this.dash_blur.corner_radius * monitor.geometry_scale;
|
||||
this.effect.corner_radius = Math.min(
|
||||
corner_radius, this.effect.width / 2, this.effect.height / 2
|
||||
);
|
||||
}
|
||||
});
|
||||
// disconnect everything
|
||||
this.dash_blur_connections_ids.forEach(id => { if (id) this.dash_blur.disconnect(id); });
|
||||
this.dash_blur_connections_ids = [];
|
||||
if (this.dash_destroy_id)
|
||||
this.dash.disconnect(this.dash_destroy_id);
|
||||
this.dash_destroy_id = null;
|
||||
}
|
||||
|
||||
dash_blur.connections.connect(dash_blur, 'override-background', () => {
|
||||
this.remove_style();
|
||||
override_style() {
|
||||
this.remove_style();
|
||||
|
||||
this.dash.set_style_class_name(
|
||||
DASH_STYLES[this.settings.dash_to_dock.STYLE_DASH_TO_DOCK]
|
||||
);
|
||||
});
|
||||
|
||||
dash_blur.connections.connect(dash_blur, 'reset-background', () => this.remove_style());
|
||||
|
||||
dash_blur.connections.connect(dash_blur, 'show', () => {
|
||||
if (this.dash_blur.is_static)
|
||||
this.background_parent.show();
|
||||
else
|
||||
this.effect.radius = this.dash_blur.sigma * 2 * this.effect.scale;
|
||||
});
|
||||
|
||||
dash_blur.connections.connect(dash_blur, 'hide', () => {
|
||||
if (this.dash_blur.is_static)
|
||||
this.background_parent.hide();
|
||||
else
|
||||
this.effect.radius = 0;
|
||||
});
|
||||
|
||||
dash_blur.connections.connect(dash_blur, 'update-wallpaper', () => {
|
||||
if (this.dash_blur.is_static) {
|
||||
let bg = Main.layoutManager._backgroundGroup.get_child_at_index(
|
||||
Main.layoutManager.monitors.length
|
||||
- find_monitor_for(this.dash).index - 1
|
||||
);
|
||||
if (bg && bg.get_content()) {
|
||||
this.background.content.set({
|
||||
background: bg.get_content().background
|
||||
});
|
||||
this._log('wallpaper updated');
|
||||
} else {
|
||||
this._warn("could not get background for dash-to-dock");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dash_blur.connections.connect(dash_blur, 'update-size', () => {
|
||||
if (this.dash_blur.is_static) {
|
||||
let [x, y] = this.get_dash_position(this.dash_container, this.dash_background);
|
||||
|
||||
this.background.x = -x;
|
||||
this.background.y = -y;
|
||||
|
||||
this.effect.width = this.dash_background.width;
|
||||
this.effect.height = this.dash_background.height;
|
||||
|
||||
this.dash_blur.set_corner_radius(this.dash_blur.corner_radius);
|
||||
|
||||
if (dash_container.get_style_class_name().includes("top")) {
|
||||
this.background.set_clip(x, y + this.dash.y + this.dash_background.y, this.dash_background.width, this.dash_background.height);
|
||||
} else if (dash_container.get_style_class_name().includes("bottom")) {
|
||||
this.background.set_clip(x, y + this.dash.y + this.dash_background.y, this.dash_background.width, this.dash_background.height);
|
||||
} else if (dash_container.get_style_class_name().includes("left")) {
|
||||
this.background.set_clip(x + this.dash.x + this.dash_background.x, y + this.dash.y + this.dash_background.y, this.dash_background.width, this.dash_background.height);
|
||||
} else if (dash_container.get_style_class_name().includes("right")) {
|
||||
this.background.set_clip(x + this.dash.x + this.dash_background.x, y + this.dash.y + this.dash_background.y, this.dash_background.width, this.dash_background.height);
|
||||
}
|
||||
} else {
|
||||
this.background.width = this.dash_background.width;
|
||||
this.background.height = this.dash_background.height;
|
||||
|
||||
this.background.x = this.dash_background.x;
|
||||
this.background.y = this.dash_background.y + this.dash.y;
|
||||
}
|
||||
});
|
||||
|
||||
dash_blur.connections.connect(dash_blur, 'change-blur-type', () => {
|
||||
this.background_parent.remove_child(this.background);
|
||||
if (this.effect.chained_effect)
|
||||
this.effect.get_actor()?.remove_effect(this.effect.chained_effect);
|
||||
this.effect.get_actor()?.remove_effect(this.effect);
|
||||
|
||||
let [background, effect] = this.dash_blur.add_blur(this.dash, this.dash_background, this.dash_container);
|
||||
this.background = background;
|
||||
this.effect = effect;
|
||||
this.background_parent.add_child(this.background);
|
||||
});
|
||||
this.dash.set_style_class_name(
|
||||
DASH_STYLES[this.settings.dash_to_dock.STYLE_DASH_TO_DOCK]
|
||||
);
|
||||
}
|
||||
|
||||
remove_style() {
|
||||
@ -169,10 +83,88 @@ class DashInfos {
|
||||
);
|
||||
}
|
||||
|
||||
destroy_dash(dash_not_already_destroyed = true) {
|
||||
if (!dash_not_already_destroyed)
|
||||
this.bg_manager.backgroundActor = null;
|
||||
|
||||
this.paint_signals?.disconnect_all();
|
||||
this.dash.get_parent().remove_child(this.background_group);
|
||||
this.bg_manager._bms_pipeline.destroy();
|
||||
this.bg_manager.destroy();
|
||||
this.background_group.destroy();
|
||||
}
|
||||
|
||||
change_blur_type() {
|
||||
this.destroy_dash();
|
||||
|
||||
let [
|
||||
background, background_group, bg_manager, paint_signals
|
||||
] = this.dash_blur.add_blur(this.dash);
|
||||
|
||||
this.background = background;
|
||||
this.background_group = background_group;
|
||||
this.bg_manager = bg_manager;
|
||||
this.paint_signals = paint_signals;
|
||||
|
||||
this.dash.get_parent().insert_child_at_index(this.background_group, 0);
|
||||
|
||||
this.update_size();
|
||||
}
|
||||
|
||||
update_pipeline() {
|
||||
this.bg_manager._bms_pipeline.change_pipeline_to(
|
||||
this.settings.dash_to_dock.PIPELINE
|
||||
);
|
||||
}
|
||||
|
||||
update_size() {
|
||||
if (this.dash_blur.is_static) {
|
||||
let [x, y] = this.get_dash_position(this.dash_container, this.dash_background);
|
||||
|
||||
this.background.x = -x;
|
||||
this.background.y = -y;
|
||||
|
||||
if (this.dash_container.get_style_class_name().includes("top"))
|
||||
this.background.set_clip(
|
||||
x,
|
||||
y + this.dash.y + this.dash_background.y,
|
||||
this.dash_background.width,
|
||||
this.dash_background.height
|
||||
);
|
||||
else if (this.dash_container.get_style_class_name().includes("bottom"))
|
||||
this.background.set_clip(
|
||||
x,
|
||||
y + this.dash.y + this.dash_background.y,
|
||||
this.dash_background.width,
|
||||
this.dash_background.height
|
||||
);
|
||||
else if (this.dash_container.get_style_class_name().includes("left"))
|
||||
this.background.set_clip(
|
||||
x + this.dash.x + this.dash_background.x,
|
||||
y + this.dash.y + this.dash_background.y,
|
||||
this.dash_background.width,
|
||||
this.dash_background.height
|
||||
);
|
||||
else if (this.dash_container.get_style_class_name().includes("right"))
|
||||
this.background.set_clip(
|
||||
x + this.dash.x + this.dash_background.x,
|
||||
y + this.dash.y + this.dash_background.y,
|
||||
this.dash_background.width,
|
||||
this.dash_background.height
|
||||
);
|
||||
} else {
|
||||
this.background.width = this.dash_background.width;
|
||||
this.background.height = this.dash_background.height;
|
||||
|
||||
this.background.x = this.dash_background.x;
|
||||
this.background.y = this.dash_background.y + this.dash.y;
|
||||
}
|
||||
}
|
||||
|
||||
get_dash_position(dash_container, dash_background) {
|
||||
var x, y;
|
||||
|
||||
let monitor = find_monitor_for(dash_container);
|
||||
let monitor = Main.layoutManager.findMonitorForActor(dash_container);
|
||||
let dash_box = dash_container._slider.get_child();
|
||||
|
||||
if (dash_container.get_style_class_name().includes("top")) {
|
||||
@ -202,19 +194,13 @@ class DashInfos {
|
||||
}
|
||||
}
|
||||
|
||||
export const DashBlur = class DashBlur {
|
||||
export const DashBlur = class DashBlur extends Signals.EventEmitter {
|
||||
constructor(connections, settings, _) {
|
||||
super();
|
||||
this.dashes = [];
|
||||
this.connections = connections;
|
||||
this.settings = settings;
|
||||
this.paint_signals = new PaintSignals(connections);
|
||||
this.sigma = this.settings.dash_to_dock.CUSTOMIZE
|
||||
? this.settings.dash_to_dock.SIGMA
|
||||
: this.settings.SIGMA;
|
||||
this.brightness = this.settings.dash_to_dock.CUSTOMIZE
|
||||
? this.settings.dash_to_dock.BRIGHTNESS
|
||||
: this.settings.BRIGHTNESS;
|
||||
this.corner_radius = this.settings.dash_to_dock.CORNER_RADIUS;
|
||||
this.is_static = this.settings.dash_to_dock.STATIC_BLUR;
|
||||
this.enabled = false;
|
||||
}
|
||||
@ -231,7 +217,6 @@ export const DashBlur = class DashBlur {
|
||||
this.blur_existing_dashes();
|
||||
this.connect_to_overview();
|
||||
|
||||
this.update_wallpaper();
|
||||
this.update_size();
|
||||
|
||||
this.enabled = true;
|
||||
@ -246,7 +231,7 @@ export const DashBlur = class DashBlur {
|
||||
Main.uiGroup.get_children().filter((child) => {
|
||||
return (child.get_name() === "dashtodockContainer") &&
|
||||
(child.constructor.name === 'DashToDock');
|
||||
}).forEach(this.try_blur.bind(this));
|
||||
}).forEach(dash_container => this.try_blur(dash_container));
|
||||
}
|
||||
|
||||
// Tries to blur the dash contained in the given actor
|
||||
@ -254,9 +239,9 @@ export const DashBlur = class DashBlur {
|
||||
let dash_box = dash_container._slider.get_child();
|
||||
|
||||
// verify that we did not already blur that dash
|
||||
if (!dash_box.get_children().some((child) => {
|
||||
return child.get_name() === "dash-blurred-background-parent";
|
||||
})) {
|
||||
if (!dash_box.get_children().some(child =>
|
||||
child.get_name() === "bms-dash-backgroundgroup"
|
||||
)) {
|
||||
this._log("dash to dock found, blurring it");
|
||||
|
||||
// finally blur the dash
|
||||
@ -270,48 +255,26 @@ export const DashBlur = class DashBlur {
|
||||
|
||||
// Blurs the dash and returns a `DashInfos` containing its information
|
||||
blur_dash_from(dash, dash_container) {
|
||||
// dash background parent, not visible
|
||||
let background_parent = new St.Widget({
|
||||
name: 'dash-blurred-background-parent',
|
||||
style_class: 'dash-blurred-background-parent',
|
||||
width: 0,
|
||||
height: 0
|
||||
});
|
||||
let [background, background_group, bg_manager, paint_signals] = this.add_blur(dash);
|
||||
|
||||
// finally blur the dash
|
||||
let dash_background = dash.get_children().find(child => {
|
||||
return child.get_style_class_name() === 'dash-background';
|
||||
});
|
||||
|
||||
let [background, effect] = this.add_blur(dash, dash_background, dash_container);
|
||||
|
||||
this.update_wallpaper();
|
||||
this.update_size();
|
||||
// insert the background group to the right element
|
||||
dash.get_parent().insert_child_at_index(background_group, 0);
|
||||
|
||||
// updates size and position on change
|
||||
this.connections.connect(dash, 'notify::width', _ => {
|
||||
this.update_size();
|
||||
});
|
||||
this.connections.connect(dash, 'notify::height', _ => {
|
||||
this.update_size();
|
||||
});
|
||||
this.connections.connect(dash_container, 'notify::width', _ => {
|
||||
this.update_size();
|
||||
});
|
||||
this.connections.connect(dash_container, 'notify::height', _ => {
|
||||
this.update_size();
|
||||
});
|
||||
this.connections.connect(dash_container, 'notify::y', _ => {
|
||||
this.update_wallpaper();
|
||||
this.update_size();
|
||||
});
|
||||
this.connections.connect(dash_container, 'notify::x', _ => {
|
||||
this.update_wallpaper();
|
||||
this.update_size();
|
||||
});
|
||||
this.connections.connect(
|
||||
dash,
|
||||
['notify::width', 'notify::height'],
|
||||
_ => this.update_size()
|
||||
);
|
||||
this.connections.connect(
|
||||
dash_container,
|
||||
['notify::width', 'notify::height', 'notify::y', 'notify::x'],
|
||||
_ => this.update_size()
|
||||
);
|
||||
|
||||
background_parent.add_child(background);
|
||||
dash.get_parent().insert_child_at_index(background_parent, 0);
|
||||
const dash_background = dash.get_children().find(child => {
|
||||
return child.get_style_class_name() === 'dash-background';
|
||||
});
|
||||
|
||||
// create infos
|
||||
let infos = new DashInfos(
|
||||
@ -320,137 +283,81 @@ export const DashBlur = class DashBlur {
|
||||
dash_container,
|
||||
dash_background,
|
||||
background,
|
||||
background_parent,
|
||||
effect
|
||||
background_group,
|
||||
bg_manager,
|
||||
paint_signals
|
||||
);
|
||||
|
||||
// update the background
|
||||
this.update_size();
|
||||
this.update_background();
|
||||
|
||||
// returns infos
|
||||
return infos;
|
||||
}
|
||||
|
||||
add_blur(dash, dash_background, dash_container) {
|
||||
let monitor = find_monitor_for(dash);
|
||||
add_blur(dash) {
|
||||
const monitor = Main.layoutManager.findMonitorForActor(dash);
|
||||
if (!monitor)
|
||||
return;
|
||||
|
||||
// dash background widget
|
||||
let background = this.is_static
|
||||
? new Meta.BackgroundActor({
|
||||
meta_display: global.display,
|
||||
monitor: monitor.index,
|
||||
})
|
||||
: new St.Widget({
|
||||
name: 'dash-blurred-background',
|
||||
style_class: 'dash-blurred-background',
|
||||
x: dash_background.x,
|
||||
y: dash_background.y + dash.y,
|
||||
width: dash_background.width,
|
||||
height: dash_background.height,
|
||||
});
|
||||
const background_group = new Meta.BackgroundGroup({
|
||||
name: 'bms-dash-backgroundgroup', width: 0, height: 0
|
||||
});
|
||||
|
||||
// the effect to be applied
|
||||
let effect;
|
||||
if (this.is_static) {
|
||||
let corner_radius = this.corner_radius * monitor.geometry_scale;
|
||||
corner_radius = Math.min(corner_radius, dash_background.width / 2, dash_background.height / 2);
|
||||
|
||||
effect = new BlurEffect({
|
||||
radius: 2 * this.sigma * monitor.geometry_scale,
|
||||
brightness: this.brightness,
|
||||
width: dash_background.width,
|
||||
height: dash_background.height,
|
||||
corner_radius: corner_radius
|
||||
});
|
||||
|
||||
// connect to every background change (even without changing image)
|
||||
// FIXME this signal is fired very often, so we should find another one
|
||||
// fired only when necessary (but that still catches all cases)
|
||||
this.connections.connect(
|
||||
Main.layoutManager._backgroundGroup,
|
||||
'notify',
|
||||
_ => this.update_wallpaper()
|
||||
let background, bg_manager, paint_signals;
|
||||
let static_blur = this.settings.dash_to_dock.STATIC_BLUR;
|
||||
if (static_blur) {
|
||||
let bg_manager_list = [];
|
||||
const pipeline = new Pipeline(
|
||||
global.blur_my_shell._effects_manager,
|
||||
global.blur_my_shell._pipelines_manager,
|
||||
this.settings.dash_to_dock.PIPELINE
|
||||
);
|
||||
} else {
|
||||
effect = new Shell.BlurEffect({
|
||||
brightness: this.brightness,
|
||||
radius: this.sigma * 2 * monitor.geometry_scale,
|
||||
mode: Shell.BlurMode.BACKGROUND
|
||||
});
|
||||
background = pipeline.create_background_with_effects(
|
||||
monitor.index, bg_manager_list,
|
||||
background_group, 'bms-dash-blurred-widget'
|
||||
);
|
||||
bg_manager = bg_manager_list[0];
|
||||
}
|
||||
else {
|
||||
const pipeline = new DummyPipeline(
|
||||
global.blur_my_shell._effects_manager,
|
||||
this.settings.dash_to_dock
|
||||
);
|
||||
[background, bg_manager] = pipeline.create_background_with_effect(
|
||||
background_group, 'bms-dash-blurred-widget'
|
||||
);
|
||||
|
||||
paint_signals = new PaintSignals(this.connections);
|
||||
|
||||
// HACK
|
||||
//
|
||||
//`Shell.BlurEffect` does not repaint when shadows are under it. [1]
|
||||
//
|
||||
// This does not entirely fix this bug (shadows caused by windows
|
||||
// still cause artifacts), but it prevents the shadows of the panel
|
||||
// buttons to cause artifacts on the panel itself
|
||||
// still cause artifacts), but it prevents the shadows of the dash
|
||||
// buttons to cause artifacts on the dash itself
|
||||
//
|
||||
// [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857
|
||||
|
||||
if (this.settings.HACKS_LEVEL === 1) {
|
||||
this._log("dash hack level 1");
|
||||
this.paint_signals.disconnect_all();
|
||||
this._log("hack level 1");
|
||||
|
||||
let rp = () => {
|
||||
effect.queue_repaint();
|
||||
};
|
||||
|
||||
dash._box.get_children().forEach((icon) => {
|
||||
try {
|
||||
let zone = icon.get_child_at_index(0);
|
||||
|
||||
this.connections.connect(zone, [
|
||||
'enter-event', 'leave-event', 'button-press-event'
|
||||
], rp);
|
||||
} catch (e) {
|
||||
this._warn(`${e}, continuing`);
|
||||
}
|
||||
});
|
||||
|
||||
this.connections.connect(dash._box, 'actor-added', (_, actor) => {
|
||||
try {
|
||||
let zone = actor.get_child_at_index(0);
|
||||
|
||||
this.connections.connect(zone, [
|
||||
'enter-event', 'leave-event', 'button-press-event'
|
||||
], rp);
|
||||
} catch (e) {
|
||||
this._warn(`${e}, continuing`);
|
||||
}
|
||||
});
|
||||
|
||||
let show_apps = dash._showAppsIcon;
|
||||
|
||||
this.connections.connect(show_apps, [
|
||||
'enter-event', 'leave-event', 'button-press-event'
|
||||
], rp);
|
||||
|
||||
this.connections.connect(dash, 'leave-event', rp);
|
||||
} else if (this.settings.HACKS_LEVEL === 2) {
|
||||
this._log("dash hack level 2");
|
||||
|
||||
this.paint_signals.connect(background, effect);
|
||||
paint_signals.disconnect_all();
|
||||
paint_signals.connect(background, pipeline.effect);
|
||||
} else {
|
||||
this.paint_signals.disconnect_all();
|
||||
paint_signals.disconnect_all();
|
||||
}
|
||||
}
|
||||
|
||||
// store the scale in the effect in order to retrieve it in set_sigma
|
||||
effect.scale = monitor.geometry_scale;
|
||||
|
||||
background.add_effect(effect);
|
||||
|
||||
return [background, effect];
|
||||
return [background, background_group, bg_manager, paint_signals];
|
||||
}
|
||||
|
||||
change_blur_type() {
|
||||
this.is_static = this.settings.dash_to_dock.STATIC_BLUR;
|
||||
this.emit('change-blur-type', true);
|
||||
this.emit('change-blur-type');
|
||||
|
||||
this.update_wallpaper();
|
||||
this.update_background();
|
||||
this.update_size();
|
||||
}
|
||||
|
||||
/// Connect when overview if opened/closed to hide/show the blur accordingly
|
||||
@ -459,10 +366,10 @@ export const DashBlur = class DashBlur {
|
||||
|
||||
if (this.settings.dash_to_dock.UNBLUR_IN_OVERVIEW) {
|
||||
this.connections.connect(
|
||||
Main.overview, 'showing', this.hide.bind(this)
|
||||
Main.overview, 'showing', _ => this.hide()
|
||||
);
|
||||
this.connections.connect(
|
||||
Main.overview, 'hidden', this.show.bind(this)
|
||||
Main.overview, 'hidden', _ => this.show()
|
||||
);
|
||||
}
|
||||
};
|
||||
@ -470,45 +377,32 @@ export const DashBlur = class DashBlur {
|
||||
/// Updates the background to either remove it or not, according to the
|
||||
/// user preferences.
|
||||
update_background() {
|
||||
this._log("updating background");
|
||||
if (this.settings.dash_to_dock.OVERRIDE_BACKGROUND)
|
||||
this.emit('override-background', true);
|
||||
this.emit('override-style');
|
||||
else
|
||||
this.emit('reset-background', true);
|
||||
this.emit('remove-style');
|
||||
}
|
||||
|
||||
update_wallpaper() {
|
||||
if (this.is_static)
|
||||
this.emit('update-wallpaper', true);
|
||||
update_pipeline() {
|
||||
this.emit('update-pipeline');
|
||||
}
|
||||
|
||||
update_size() {
|
||||
this.emit('update-size', true);
|
||||
this.emit('update-size');
|
||||
}
|
||||
|
||||
set_sigma(sigma) {
|
||||
this.sigma = sigma;
|
||||
this.emit('update-sigma', true);
|
||||
show() {
|
||||
this.emit('show');
|
||||
}
|
||||
|
||||
set_brightness(brightness) {
|
||||
this.brightness = brightness;
|
||||
this.emit('update-brightness', true);
|
||||
hide() {
|
||||
this.emit('hide');
|
||||
}
|
||||
|
||||
set_corner_radius(radius) {
|
||||
this.corner_radius = radius;
|
||||
this.emit('update-corner-radius', true);
|
||||
}
|
||||
|
||||
// not implemented for dynamic blur
|
||||
set_color(c) { }
|
||||
set_noise_amount(n) { }
|
||||
set_noise_lightness(l) { }
|
||||
|
||||
disable() {
|
||||
this._log("removing blur from dashes");
|
||||
|
||||
this.emit('remove-dashes', true);
|
||||
this.emit('remove-dashes');
|
||||
|
||||
this.dashes = [];
|
||||
this.connections.disconnect_all();
|
||||
@ -516,13 +410,6 @@ export const DashBlur = class DashBlur {
|
||||
this.enabled = false;
|
||||
}
|
||||
|
||||
show() {
|
||||
this.emit('show', true);
|
||||
}
|
||||
hide() {
|
||||
this.emit('hide', true);
|
||||
}
|
||||
|
||||
_log(str) {
|
||||
if (this.settings.DEBUG)
|
||||
console.log(`[Blur my Shell > dash manager] ${str}`);
|
||||
@ -531,6 +418,4 @@ export const DashBlur = class DashBlur {
|
||||
_warn(str) {
|
||||
console.warn(`[Blur my Shell > dash manager] ${str}`);
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(DashBlur.prototype);
|
||||
};
|
||||
@ -1,19 +1,14 @@
|
||||
import St from 'gi://St';
|
||||
import Shell from 'gi://Shell';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
import * as Background from 'resource:///org/gnome/shell/ui/background.js';
|
||||
import { UnlockDialog } from 'resource:///org/gnome/shell/ui/unlockDialog.js';
|
||||
|
||||
let sigma;
|
||||
let brightness;
|
||||
let color;
|
||||
let noise;
|
||||
let lightness;
|
||||
import { Pipeline } from '../conveniences/pipeline.js';
|
||||
|
||||
const original_createBackground =
|
||||
UnlockDialog.prototype._createBackground;
|
||||
const original_updateBackgroundEffects =
|
||||
UnlockDialog.prototype._updateBackgroundEffects;
|
||||
const original_updateBackgrounds =
|
||||
UnlockDialog.prototype._updateBackgrounds;
|
||||
|
||||
|
||||
export const LockscreenBlur = class LockscreenBlur {
|
||||
@ -27,22 +22,6 @@ export const LockscreenBlur = class LockscreenBlur {
|
||||
enable() {
|
||||
this._log("blurring lockscreen");
|
||||
|
||||
brightness = this.settings.lockscreen.CUSTOMIZE
|
||||
? this.settings.lockscreen.BRIGHTNESS
|
||||
: this.settings.BRIGHTNESS;
|
||||
sigma = this.settings.lockscreen.CUSTOMIZE
|
||||
? this.settings.lockscreen.SIGMA
|
||||
: this.settings.SIGMA;
|
||||
color = this.settings.lockscreen.CUSTOMIZE
|
||||
? this.settings.lockscreen.COLOR
|
||||
: this.settings.COLOR;
|
||||
noise = this.settings.lockscreen.CUSTOMIZE
|
||||
? this.settings.lockscreen.NOISE_AMOUNT
|
||||
: this.settings.NOISE_AMOUNT;
|
||||
lightness = this.settings.lockscreen.CUSTOMIZE
|
||||
? this.settings.lockscreen.NOISE_LIGHTNESS
|
||||
: this.settings.NOISE_LIGHTNESS;
|
||||
|
||||
this.update_lockscreen();
|
||||
|
||||
this.enabled = true;
|
||||
@ -53,103 +32,39 @@ export const LockscreenBlur = class LockscreenBlur {
|
||||
this._createBackground;
|
||||
UnlockDialog.prototype._updateBackgroundEffects =
|
||||
this._updateBackgroundEffects;
|
||||
UnlockDialog.prototype._updateBackgrounds =
|
||||
this._updateBackgrounds;
|
||||
}
|
||||
|
||||
_createBackground(monitorIndex) {
|
||||
let monitor = Main.layoutManager.monitors[monitorIndex];
|
||||
let widget = new St.Widget({
|
||||
style_class: "screen-shield-background",
|
||||
x: monitor.x,
|
||||
y: monitor.y,
|
||||
width: monitor.width,
|
||||
height: monitor.height,
|
||||
});
|
||||
_createBackground(monitor_index) {
|
||||
let pipeline = new Pipeline(
|
||||
global.blur_my_shell._effects_manager, global.blur_my_shell._pipelines_manager,
|
||||
global.blur_my_shell._settings.lockscreen.PIPELINE
|
||||
);
|
||||
|
||||
let blur_effect = new Shell.BlurEffect({
|
||||
name: 'blur',
|
||||
radius: sigma * 2,
|
||||
brightness: brightness
|
||||
});
|
||||
|
||||
// store the scale in the effect in order to retrieve later
|
||||
blur_effect.scale = monitor.geometry_scale;
|
||||
|
||||
let color_effect = global.blur_my_shell._lockscreen_blur.effects_manager.new_color_effect({
|
||||
name: 'color',
|
||||
color: color
|
||||
}, this.settings);
|
||||
|
||||
let noise_effect = global.blur_my_shell._lockscreen_blur.effects_manager.new_noise_effect({
|
||||
name: 'noise',
|
||||
noise: noise,
|
||||
lightness: lightness
|
||||
}, this.settings);
|
||||
|
||||
widget.add_effect(color_effect);
|
||||
widget.add_effect(noise_effect);
|
||||
widget.add_effect(blur_effect);
|
||||
|
||||
let bgManager = new Background.BackgroundManager({
|
||||
container: widget,
|
||||
monitorIndex,
|
||||
controlPosition: false,
|
||||
});
|
||||
|
||||
this._bgManagers.push(bgManager);
|
||||
|
||||
this._backgroundGroup.add_child(widget);
|
||||
pipeline.create_background_with_effects(
|
||||
monitor_index,
|
||||
this._bgManagers,
|
||||
this._backgroundGroup,
|
||||
"screen-shield-background"
|
||||
);
|
||||
}
|
||||
|
||||
_updateBackgroundEffects() {
|
||||
for (const widget of this._backgroundGroup) {
|
||||
const color_effect = widget.get_effect('color');
|
||||
const noise_effect = widget.get_effect('noise');
|
||||
const blur_effect = widget.get_effect('blur');
|
||||
this._updateBackgrounds();
|
||||
}
|
||||
|
||||
if (color_effect)
|
||||
color_effect.set({
|
||||
color: color
|
||||
});
|
||||
|
||||
if (noise_effect) {
|
||||
noise_effect.set({
|
||||
noise: noise,
|
||||
lightness: lightness,
|
||||
});
|
||||
}
|
||||
|
||||
if (blur_effect) {
|
||||
blur_effect.set({
|
||||
brightness: brightness,
|
||||
radius: sigma * 2 * blur_effect.scale,
|
||||
});
|
||||
}
|
||||
_updateBackgrounds() {
|
||||
for (let i = 0; i < this._bgManagers.length; i++) {
|
||||
this._bgManagers[i]._bms_pipeline.destroy();
|
||||
this._bgManagers[i].destroy();
|
||||
}
|
||||
}
|
||||
|
||||
set_sigma(s) {
|
||||
sigma = s;
|
||||
this.update_lockscreen();
|
||||
}
|
||||
this._bgManagers = [];
|
||||
this._backgroundGroup.destroy_all_children();
|
||||
|
||||
set_brightness(b) {
|
||||
brightness = b;
|
||||
this.update_lockscreen();
|
||||
}
|
||||
|
||||
set_color(c) {
|
||||
color = c;
|
||||
this.update_lockscreen();
|
||||
}
|
||||
|
||||
set_noise_amount(n) {
|
||||
noise = n;
|
||||
this.update_lockscreen();
|
||||
}
|
||||
|
||||
set_noise_lightness(l) {
|
||||
lightness = l;
|
||||
this.update_lockscreen();
|
||||
for (let i = 0; i < Main.layoutManager.monitors.length; i++)
|
||||
this._createBackground(i);
|
||||
}
|
||||
|
||||
disable() {
|
||||
@ -159,6 +74,8 @@ export const LockscreenBlur = class LockscreenBlur {
|
||||
original_createBackground;
|
||||
UnlockDialog.prototype._updateBackgroundEffects =
|
||||
original_updateBackgroundEffects;
|
||||
UnlockDialog.prototype._updateBackgrounds =
|
||||
original_updateBackgrounds;
|
||||
|
||||
this.connections.disconnect_all();
|
||||
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import Shell from 'gi://Shell';
|
||||
import Meta from 'gi://Meta';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
|
||||
import { WorkspaceAnimationController } from 'resource:///org/gnome/shell/ui/workspaceAnimation.js';
|
||||
const wac_proto = WorkspaceAnimationController.prototype;
|
||||
|
||||
import { Pipeline } from '../conveniences/pipeline.js';
|
||||
|
||||
const OVERVIEW_COMPONENTS_STYLE = [
|
||||
"overview-components-light",
|
||||
"overview-components-dark",
|
||||
@ -15,40 +16,23 @@ const OVERVIEW_COMPONENTS_STYLE = [
|
||||
export const OverviewBlur = class OverviewBlur {
|
||||
constructor(connections, settings, effects_manager) {
|
||||
this.connections = connections;
|
||||
this.effects = [];
|
||||
this.settings = settings;
|
||||
this.effects_manager = effects_manager;
|
||||
this._workspace_switch_bg_actors = [];
|
||||
this.overview_background_managers = [];
|
||||
this.overview_background_group = new Meta.BackgroundGroup(
|
||||
{ name: 'bms-overview-backgroundgroup' }
|
||||
);
|
||||
this.animation_background_managers = [];
|
||||
this.animation_background_group = new Meta.BackgroundGroup(
|
||||
{ name: 'bms-animation-backgroundgroup' }
|
||||
);
|
||||
this.enabled = false;
|
||||
this.proto_patched = false;
|
||||
}
|
||||
|
||||
enable() {
|
||||
this._log("blurring overview");
|
||||
|
||||
// connect to every background change (even without changing image)
|
||||
// FIXME this signal is fired very often, so we should find another one
|
||||
// fired only when necessary (but that still catches all cases)
|
||||
this.connections.connect(
|
||||
Main.layoutManager._backgroundGroup,
|
||||
'notify',
|
||||
_ => {
|
||||
this._log("updated background");
|
||||
this.update_backgrounds();
|
||||
}
|
||||
);
|
||||
|
||||
// connect to monitors change
|
||||
this.connections.connect(
|
||||
Main.layoutManager,
|
||||
'monitors-changed',
|
||||
_ => {
|
||||
if (Main.screenShield && !Main.screenShield.locked) {
|
||||
this._log("changed monitors");
|
||||
this.update_backgrounds();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// add css class name for workspace-switch background
|
||||
Main.uiGroup.add_style_class_name("blurred-overview");
|
||||
|
||||
@ -58,12 +42,16 @@ export const OverviewBlur = class OverviewBlur {
|
||||
// update backgrounds when the component is enabled
|
||||
this.update_backgrounds();
|
||||
|
||||
// connect to monitors change
|
||||
this.connections.connect(Main.layoutManager, 'monitors-changed',
|
||||
_ => this.update_backgrounds()
|
||||
);
|
||||
|
||||
// part for the workspace animation switch
|
||||
|
||||
// make sure not to do this part if the extension was enabled prior, as
|
||||
// make sure not to do this part if the functions were patched prior, as
|
||||
// the functions would call themselves and cause infinite recursion
|
||||
if (!this.enabled) {
|
||||
if (!this.proto_patched) {
|
||||
// store original workspace switching methods for restoring them on
|
||||
// disable()
|
||||
this._original_PrepareSwitch = wac_proto._prepareWorkspaceSwitch;
|
||||
@ -91,25 +79,20 @@ export const OverviewBlur = class OverviewBlur {
|
||||
);
|
||||
}
|
||||
|
||||
Main.layoutManager.monitors.forEach(monitor => {
|
||||
if (
|
||||
!(
|
||||
Main.uiGroup.insert_child_above(
|
||||
outer_this.animation_background_group,
|
||||
global.window_group
|
||||
);
|
||||
|
||||
outer_this.animation_background_managers.forEach(bg_manager => {
|
||||
if (bg_manager._bms_pipeline.actor)
|
||||
if (
|
||||
Meta.prefs_get_workspaces_only_on_primary() &&
|
||||
(monitor !== Main.layoutManager.primaryMonitor)
|
||||
bg_manager._monitorIndex !== Main.layoutManager.primaryMonitor.index
|
||||
)
|
||||
) {
|
||||
const bg_actor = outer_this.create_background_actor(
|
||||
monitor, true
|
||||
);
|
||||
|
||||
Main.uiGroup.insert_child_above(
|
||||
bg_actor,
|
||||
global.window_group
|
||||
);
|
||||
|
||||
// store the actors so that we can delete them later
|
||||
outer_this._workspace_switch_bg_actors.push(bg_actor);
|
||||
}
|
||||
bg_manager._bms_pipeline.actor.visible = false;
|
||||
else
|
||||
bg_manager._bms_pipeline.actor.visible = true;
|
||||
});
|
||||
};
|
||||
|
||||
@ -129,15 +112,10 @@ export const OverviewBlur = class OverviewBlur {
|
||||
);
|
||||
}
|
||||
|
||||
outer_this.effects = outer_this.effects.filter(
|
||||
effects_group => !effects_group.is_transition
|
||||
);
|
||||
|
||||
outer_this._workspace_switch_bg_actors.forEach(actor => {
|
||||
actor.destroy();
|
||||
});
|
||||
outer_this._workspace_switch_bg_actors = [];
|
||||
Main.uiGroup.remove_child(outer_this.animation_background_group);
|
||||
};
|
||||
|
||||
this.proto_patched = true;
|
||||
}
|
||||
|
||||
this.enabled = true;
|
||||
@ -146,78 +124,30 @@ export const OverviewBlur = class OverviewBlur {
|
||||
update_backgrounds() {
|
||||
// remove every old background
|
||||
this.remove_background_actors();
|
||||
|
||||
// add new backgrounds
|
||||
Main.layoutManager.monitors.forEach(monitor => {
|
||||
const bg_actor = this.create_background_actor(monitor, false);
|
||||
|
||||
Main.layoutManager.overviewGroup.insert_child_at_index(
|
||||
bg_actor,
|
||||
monitor.index
|
||||
// create new backgrounds for the overview and the animation
|
||||
for (let i = 0; i < Main.layoutManager.monitors.length; i++) {
|
||||
const pipeline_overview = new Pipeline(
|
||||
this.effects_manager,
|
||||
global.blur_my_shell._pipelines_manager,
|
||||
this.settings.overview.PIPELINE
|
||||
);
|
||||
pipeline_overview.create_background_with_effects(
|
||||
i, this.overview_background_managers,
|
||||
this.overview_background_group, 'bms-overview-blurred-widget'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
create_background_actor(monitor, is_transition) {
|
||||
let bg_actor = new Meta.BackgroundActor({
|
||||
name: "blur-my-shell_background_actor",
|
||||
meta_display: global.display,
|
||||
monitor: monitor.index
|
||||
});
|
||||
let background_group = Main.layoutManager._backgroundGroup
|
||||
.get_children()
|
||||
.filter((child) => child instanceof Meta.BackgroundActor);
|
||||
let background =
|
||||
background_group[
|
||||
Main.layoutManager.monitors.length - monitor.index - 1
|
||||
];
|
||||
|
||||
if (!background) {
|
||||
this._warn("could not get background for overview");
|
||||
return bg_actor;
|
||||
const pipeline_animation = new Pipeline(
|
||||
this.effects_manager,
|
||||
global.blur_my_shell._pipelines_manager,
|
||||
this.settings.overview.PIPELINE
|
||||
);
|
||||
pipeline_animation.create_background_with_effects(
|
||||
i, this.animation_background_managers,
|
||||
this.animation_background_group, 'bms-animation-blurred-widget'
|
||||
);
|
||||
}
|
||||
|
||||
bg_actor.content.set({
|
||||
background: background.get_content().background
|
||||
});
|
||||
|
||||
let blur_effect = new Shell.BlurEffect({
|
||||
brightness: this.settings.overview.CUSTOMIZE
|
||||
? this.settings.overview.BRIGHTNESS
|
||||
: this.settings.BRIGHTNESS,
|
||||
radius: (this.settings.overview.CUSTOMIZE
|
||||
? this.settings.overview.SIGMA
|
||||
: this.settings.SIGMA) * 2 * monitor.geometry_scale,
|
||||
mode: Shell.BlurMode.ACTOR
|
||||
});
|
||||
|
||||
// store the scale in the effect in order to retrieve it in set_sigma
|
||||
blur_effect.scale = monitor.geometry_scale;
|
||||
|
||||
let color_effect = this.effects_manager.new_color_effect({
|
||||
color: this.settings.overview.CUSTOMIZE
|
||||
? this.settings.overview.COLOR
|
||||
: this.settings.COLOR
|
||||
}, this.settings);
|
||||
|
||||
let noise_effect = this.effects_manager.new_noise_effect({
|
||||
noise: this.settings.overview.CUSTOMIZE
|
||||
? this.settings.overview.NOISE_AMOUNT
|
||||
: this.settings.NOISE_AMOUNT,
|
||||
lightness: this.settings.overview.CUSTOMIZE
|
||||
? this.settings.overview.NOISE_LIGHTNESS
|
||||
: this.settings.NOISE_LIGHTNESS
|
||||
}, this.settings);
|
||||
|
||||
bg_actor.add_effect(color_effect);
|
||||
bg_actor.add_effect(noise_effect);
|
||||
bg_actor.add_effect(blur_effect);
|
||||
this.effects.push({ blur_effect, color_effect, noise_effect, is_transition });
|
||||
|
||||
bg_actor.set_x(monitor.x);
|
||||
bg_actor.set_y(monitor.y);
|
||||
|
||||
return bg_actor;
|
||||
// add the container widget for the overview only to the overview group
|
||||
Main.layoutManager.overviewGroup.insert_child_at_index(this.overview_background_group, 0);
|
||||
}
|
||||
|
||||
/// Updates the classname to style overview components with semi-transparent
|
||||
@ -233,71 +163,43 @@ export const OverviewBlur = class OverviewBlur {
|
||||
);
|
||||
}
|
||||
|
||||
set_sigma(s) {
|
||||
this.effects.forEach(effect => {
|
||||
effect.blur_effect.radius = s * 2 * effect.blur_effect.scale;
|
||||
});
|
||||
}
|
||||
|
||||
set_brightness(b) {
|
||||
this.effects.forEach(effect => {
|
||||
effect.blur_effect.brightness = b;
|
||||
});
|
||||
}
|
||||
|
||||
set_color(c) {
|
||||
this.effects.forEach(effect => {
|
||||
effect.color_effect.color = c;
|
||||
});
|
||||
}
|
||||
|
||||
set_noise_amount(n) {
|
||||
this.effects.forEach(effect => {
|
||||
effect.noise_effect.noise = n;
|
||||
});
|
||||
}
|
||||
|
||||
set_noise_lightness(l) {
|
||||
this.effects.forEach(effect => {
|
||||
effect.noise_effect.lightness = l;
|
||||
});
|
||||
}
|
||||
|
||||
remove_background_actors() {
|
||||
Main.layoutManager.overviewGroup.get_children().forEach(child => {
|
||||
if (child instanceof Meta.BackgroundActor
|
||||
&& child.get_name() == "blur-my-shell_background_actor"
|
||||
) {
|
||||
child.get_effects().forEach(effect => {
|
||||
this.effects_manager.remove(effect);
|
||||
});
|
||||
Main.layoutManager.overviewGroup.remove_child(child);
|
||||
child.destroy();
|
||||
}
|
||||
this.overview_background_group.remove_all_children();
|
||||
this.animation_background_group.remove_all_children();
|
||||
this.overview_background_managers.forEach(background_manager => {
|
||||
background_manager._bms_pipeline.destroy();
|
||||
background_manager.destroy();
|
||||
});
|
||||
this.effects = [];
|
||||
this.animation_background_managers.forEach(background_manager => {
|
||||
background_manager._bms_pipeline.destroy();
|
||||
background_manager.destroy();
|
||||
});
|
||||
this.overview_background_managers = [];
|
||||
this.animation_background_managers = [];
|
||||
}
|
||||
|
||||
disable() {
|
||||
this._log("removing blur from overview");
|
||||
|
||||
this.remove_background_actors();
|
||||
Main.uiGroup.remove_style_class_name("blurred-overview");
|
||||
OVERVIEW_COMPONENTS_STYLE.forEach(
|
||||
style => Main.uiGroup.remove_style_class_name(style)
|
||||
);
|
||||
|
||||
// make sure to absolutely not do this if the component was not enabled
|
||||
// prior, as this would cause infinite recursion
|
||||
if (this.enabled) {
|
||||
// restore original behavior
|
||||
this.connections.disconnect_all();
|
||||
this.enabled = false;
|
||||
}
|
||||
|
||||
restore_patched_proto() {
|
||||
if (this.proto_patched) {
|
||||
if (this._original_PrepareSwitch)
|
||||
wac_proto._prepareWorkspaceSwitch = this._original_PrepareSwitch;
|
||||
if (this._original_FinishSwitch)
|
||||
wac_proto._finishWorkspaceSwitch = this._original_FinishSwitch;
|
||||
}
|
||||
|
||||
this.connections.disconnect_all();
|
||||
this.enabled = false;
|
||||
this.proto_patched = false;
|
||||
}
|
||||
}
|
||||
|
||||
_log(str) {
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import St from 'gi://St';
|
||||
import Shell from 'gi://Shell';
|
||||
import Meta from 'gi://Meta';
|
||||
import Mtk from 'gi://Mtk';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
|
||||
import { PaintSignals } from '../effects/paint_signals.js';
|
||||
import { PaintSignals } from '../conveniences/paint_signals.js';
|
||||
|
||||
import { Pipeline } from '../conveniences/pipeline.js';
|
||||
import { DummyPipeline } from '../conveniences/dummy_pipeline.js';
|
||||
|
||||
const DASH_TO_PANEL_UUID = 'dash-to-panel@jderose9.github.com';
|
||||
const PANEL_STYLES = [
|
||||
@ -56,26 +57,9 @@ export const PanelBlur = class PanelBlur {
|
||||
// update the classname if the panel to have or have not light text
|
||||
this.update_light_text_classname();
|
||||
|
||||
// connect to every background change (even without changing image)
|
||||
// FIXME this signal is fired very often, so we should find another one
|
||||
// fired only when necessary (but that still catches all cases)
|
||||
this.connections.connect(
|
||||
Main.layoutManager._backgroundGroup,
|
||||
'notify',
|
||||
_ => this.actors_list.forEach(actors =>
|
||||
this.update_wallpaper(actors)
|
||||
)
|
||||
);
|
||||
|
||||
// connect to monitors change
|
||||
this.connections.connect(
|
||||
Main.layoutManager,
|
||||
'monitors-changed',
|
||||
_ => {
|
||||
if (Main.screenShield && !Main.screenShield.locked) {
|
||||
this.reset();
|
||||
}
|
||||
}
|
||||
// connect to workareas change
|
||||
this.connections.connect(global.display, 'workareas-changed',
|
||||
_ => this.reset()
|
||||
);
|
||||
|
||||
this.enabled = true;
|
||||
@ -131,9 +115,6 @@ export const PanelBlur = class PanelBlur {
|
||||
if (!actors)
|
||||
// if the actors is not blurred, blur it
|
||||
this.blur_panel(panel);
|
||||
else
|
||||
// if it is blurred, update the blur anyway
|
||||
this.change_blur_type(actors);
|
||||
}
|
||||
|
||||
/// Blur a panel
|
||||
@ -145,71 +126,74 @@ export const PanelBlur = class PanelBlur {
|
||||
panel_box = panel_box.get_parent();
|
||||
}
|
||||
|
||||
let monitor = this.find_monitor_for(panel);
|
||||
let monitor = Main.layoutManager.findMonitorForActor(panel);
|
||||
if (!monitor)
|
||||
return;
|
||||
|
||||
let background_parent = new St.Widget({
|
||||
name: 'topbar-blurred-background-parent',
|
||||
x: 0, y: 0, width: 0, height: 0
|
||||
});
|
||||
let background_group = new Meta.BackgroundGroup(
|
||||
{ name: 'bms-panel-backgroundgroup', width: 0, height: 0 }
|
||||
);
|
||||
|
||||
let background = this.settings.panel.STATIC_BLUR
|
||||
? new Meta.BackgroundActor({
|
||||
meta_display: global.display,
|
||||
monitor: monitor.index
|
||||
})
|
||||
: new St.Widget;
|
||||
let background, bg_manager;
|
||||
let static_blur = this.settings.panel.STATIC_BLUR;
|
||||
if (static_blur) {
|
||||
let bg_manager_list = [];
|
||||
const pipeline = new Pipeline(
|
||||
this.effects_manager,
|
||||
global.blur_my_shell._pipelines_manager,
|
||||
this.settings.panel.PIPELINE
|
||||
);
|
||||
background = pipeline.create_background_with_effects(
|
||||
monitor.index, bg_manager_list,
|
||||
background_group, 'bms-panel-blurred-widget'
|
||||
);
|
||||
bg_manager = bg_manager_list[0];
|
||||
}
|
||||
else {
|
||||
const pipeline = new DummyPipeline(this.effects_manager, this.settings.panel);
|
||||
[background, bg_manager] = pipeline.create_background_with_effect(
|
||||
background_group, 'bms-panel-blurred-widget'
|
||||
);
|
||||
|
||||
background_parent.add_child(background);
|
||||
let paint_signals = new PaintSignals(this.connections);
|
||||
|
||||
// insert background parent
|
||||
panel_box.insert_child_at_index(background_parent, 0);
|
||||
// HACK
|
||||
//
|
||||
//`Shell.BlurEffect` does not repaint when shadows are under it. [1]
|
||||
//
|
||||
// This does not entirely fix this bug (shadows caused by windows
|
||||
// still cause artifacts), but it prevents the shadows of the panel
|
||||
// buttons to cause artifacts on the panel itself
|
||||
//
|
||||
// [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857
|
||||
|
||||
let blur = new Shell.BlurEffect({
|
||||
brightness: this.settings.panel.CUSTOMIZE
|
||||
? this.settings.panel.BRIGHTNESS
|
||||
: this.settings.BRIGHTNESS,
|
||||
radius: (this.settings.panel.CUSTOMIZE
|
||||
? this.settings.panel.SIGMA
|
||||
: this.settings.SIGMA) * 2 * monitor.geometry_scale,
|
||||
mode: this.settings.panel.STATIC_BLUR
|
||||
? Shell.BlurMode.ACTOR
|
||||
: Shell.BlurMode.BACKGROUND
|
||||
});
|
||||
{
|
||||
if (this.settings.HACKS_LEVEL === 1) {
|
||||
this._log("panel hack level 1");
|
||||
|
||||
// store the scale in the effect in order to retrieve it in set_sigma
|
||||
blur.scale = monitor.geometry_scale;
|
||||
paint_signals.disconnect_all();
|
||||
paint_signals.connect(background, pipeline.effect);
|
||||
} else {
|
||||
paint_signals.disconnect_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let color = this.effects_manager.new_color_effect({
|
||||
color: this.settings.panel.CUSTOMIZE
|
||||
? this.settings.panel.COLOR
|
||||
: this.settings.COLOR
|
||||
}, this.settings);
|
||||
|
||||
let noise = this.effects_manager.new_noise_effect({
|
||||
noise: this.settings.panel.CUSTOMIZE
|
||||
? this.settings.panel.NOISE_AMOUNT
|
||||
: this.settings.NOISE_AMOUNT,
|
||||
lightness: this.settings.panel.CUSTOMIZE
|
||||
? this.settings.panel.NOISE_LIGHTNESS
|
||||
: this.settings.NOISE_LIGHTNESS
|
||||
}, this.settings);
|
||||
|
||||
let paint_signals = new PaintSignals(this.connections);
|
||||
// insert the background group to the panel box
|
||||
panel_box.insert_child_at_index(background_group, 0);
|
||||
|
||||
// the object that is used to remembering each elements that is linked to the blur effect
|
||||
let actors = {
|
||||
widgets: { panel, panel_box, background, background_parent },
|
||||
effects: { blur, color, noise },
|
||||
paint_signals,
|
||||
widgets: { panel, panel_box, background, background_group },
|
||||
static_blur,
|
||||
monitor,
|
||||
bg_manager,
|
||||
is_dtp_panel
|
||||
};
|
||||
|
||||
this.actors_list.push(actors);
|
||||
|
||||
// perform updates
|
||||
this.change_blur_type(actors);
|
||||
// update the size of the actor
|
||||
this.update_size(actors);
|
||||
|
||||
// connect to panel, panel_box and its parent position or size change
|
||||
// this should fire update_size every time one of its params change
|
||||
@ -228,157 +212,47 @@ export const PanelBlur = class PanelBlur {
|
||||
'notify::position',
|
||||
_ => this.update_size(actors)
|
||||
);
|
||||
}
|
||||
|
||||
update_all_blur_type() {
|
||||
this.actors_list.forEach(actors => this.change_blur_type(actors));
|
||||
}
|
||||
|
||||
change_blur_type(actors) {
|
||||
let is_static = this.settings.panel.STATIC_BLUR;
|
||||
|
||||
// reset widgets to right state
|
||||
actors.widgets.background_parent.remove_child(actors.widgets.background);
|
||||
this.effects_manager.remove(actors.effects.blur);
|
||||
this.effects_manager.remove(actors.effects.color);
|
||||
this.effects_manager.remove(actors.effects.noise);
|
||||
|
||||
// create new background actor
|
||||
actors.widgets.background = is_static
|
||||
? new Meta.BackgroundActor({
|
||||
meta_display: global.display,
|
||||
monitor: this.find_monitor_for(actors.widgets.panel).index
|
||||
})
|
||||
: new St.Widget;
|
||||
|
||||
// change blur mode
|
||||
actors.effects.blur.set_mode(is_static ? 0 : 1);
|
||||
|
||||
// disable other effects if the blur is dynamic, as they makes it opaque
|
||||
actors.effects.color._static = is_static;
|
||||
actors.effects.noise._static = is_static;
|
||||
actors.effects.color.update_enabled();
|
||||
actors.effects.noise.update_enabled();
|
||||
|
||||
// add the effects in order
|
||||
actors.widgets.background.add_effect(actors.effects.color);
|
||||
actors.widgets.background.add_effect(actors.effects.noise);
|
||||
actors.widgets.background.add_effect(actors.effects.blur);
|
||||
|
||||
// add the background actor behing the panel
|
||||
actors.widgets.background_parent.add_child(actors.widgets.background);
|
||||
|
||||
// perform updates
|
||||
this.update_wallpaper(actors);
|
||||
this.update_size(actors);
|
||||
|
||||
|
||||
// HACK
|
||||
//
|
||||
//`Shell.BlurEffect` does not repaint when shadows are under it. [1]
|
||||
//
|
||||
// This does not entirely fix this bug (shadows caused by windows
|
||||
// still cause artifacts), but it prevents the shadows of the panel
|
||||
// buttons to cause artifacts on the panel itself
|
||||
//
|
||||
// [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857
|
||||
|
||||
if (!is_static) {
|
||||
if (this.settings.HACKS_LEVEL === 1) {
|
||||
this._log("panel hack level 1");
|
||||
actors.paint_signals.disconnect_all();
|
||||
|
||||
let rp = () => { actors.effects.blur.queue_repaint(); };
|
||||
|
||||
this.connections.connect(actors.widgets.panel, [
|
||||
'enter-event', 'leave-event', 'button-press-event'
|
||||
], rp);
|
||||
|
||||
actors.widgets.panel.get_children().forEach(child => {
|
||||
this.connections.connect(child, [
|
||||
'enter-event', 'leave-event', 'button-press-event'
|
||||
], rp);
|
||||
});
|
||||
} else if (this.settings.HACKS_LEVEL === 2) {
|
||||
this._log("panel hack level 2");
|
||||
actors.paint_signals.disconnect_all();
|
||||
|
||||
actors.paint_signals.connect(
|
||||
actors.widgets.background, actors.effects.blur
|
||||
);
|
||||
} else {
|
||||
actors.paint_signals.disconnect_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_wallpaper(actors) {
|
||||
// if static blur, get right wallpaper and update blur with it
|
||||
if (this.settings.panel.STATIC_BLUR) {
|
||||
let bg = Main.layoutManager._backgroundGroup.get_child_at_index(
|
||||
Main.layoutManager.monitors.length
|
||||
- this.find_monitor_for(actors.widgets.panel).index - 1
|
||||
);
|
||||
if (bg && bg.get_content())
|
||||
actors.widgets.background.content.set({
|
||||
background: bg.get_content().background
|
||||
});
|
||||
else
|
||||
this._warn("could not get background for panel");
|
||||
}
|
||||
// connect to the panel getting destroyed
|
||||
this.connections.connect(
|
||||
panel,
|
||||
'destroy',
|
||||
_ => this.destroy_blur(actors, true)
|
||||
);
|
||||
}
|
||||
|
||||
update_size(actors) {
|
||||
let panel = actors.widgets.panel;
|
||||
let panel_box = actors.widgets.panel_box;
|
||||
let background = actors.widgets.background;
|
||||
let monitor = this.find_monitor_for(panel);
|
||||
if (!monitor)
|
||||
return;
|
||||
|
||||
let [width, height] = panel_box.get_size();
|
||||
background.width = width;
|
||||
background.height = height;
|
||||
|
||||
// if static blur, need to clip the background
|
||||
if (this.settings.panel.STATIC_BLUR) {
|
||||
if (actors.static_blur) {
|
||||
let monitor = Main.layoutManager.findMonitorForActor(panel);
|
||||
if (!monitor)
|
||||
return;
|
||||
|
||||
// an alternative to panel.get_transformed_position, because it
|
||||
// sometimes yields NaN (probably when the actor is not fully
|
||||
// positionned yet)
|
||||
let [p_x, p_y] = panel_box.get_position();
|
||||
let [p_p_x, p_p_y] = panel_box.get_parent().get_position();
|
||||
let x = p_x + p_p_x - monitor.x;
|
||||
let y = p_y + p_p_y - monitor.y;
|
||||
let x = p_x + p_p_x - monitor.x + (width - panel.width) / 2;
|
||||
let y = p_y + p_p_y - monitor.y + (height - panel.height) / 2;
|
||||
|
||||
background.set_clip(x, y, width, height);
|
||||
background.x = -x;
|
||||
background.y = -y;
|
||||
|
||||
// fixes a bug where the blur is washed away when changing the sigma
|
||||
this.invalidate_blur(actors);
|
||||
background.set_clip(x, y, panel.width, panel.height);
|
||||
background.x = (width - panel.width) / 2 - x;
|
||||
background.y = .5 + (height - panel.height) / 2 - y;
|
||||
} else {
|
||||
background.x = panel.x;
|
||||
background.y = panel.y;
|
||||
background.width = panel.width;
|
||||
background.height = panel.height;
|
||||
}
|
||||
|
||||
// update the monitor panel is on
|
||||
actors.monitor = this.find_monitor_for(panel);
|
||||
}
|
||||
|
||||
/// An helper function to find the monitor in which an actor is situated,
|
||||
/// there might be a pre-existing function in GLib already
|
||||
find_monitor_for(actor) {
|
||||
let extents = actor.get_transformed_extents();
|
||||
let rect = new Mtk.Rectangle({
|
||||
x: extents.get_x(),
|
||||
y: extents.get_y(),
|
||||
width: extents.get_width(),
|
||||
height: extents.get_height(),
|
||||
});
|
||||
|
||||
let index = global.display.get_monitor_index_for_rect(rect);
|
||||
|
||||
return Main.layoutManager.monitors[index];
|
||||
actors.monitor = Main.layoutManager.findMonitorForActor(panel);
|
||||
}
|
||||
|
||||
/// Connect when overview if opened/closed to hide/show the blur accordingly
|
||||
@ -396,22 +270,22 @@ export const PanelBlur = class PanelBlur {
|
||||
) {
|
||||
if (!this.settings.hidetopbar.COMPATIBILITY) {
|
||||
this.connections.connect(
|
||||
Main.overview, 'showing', this.hide.bind(this)
|
||||
Main.overview, 'showing', _ => this.hide()
|
||||
);
|
||||
this.connections.connect(
|
||||
Main.overview, 'hidden', this.show.bind(this)
|
||||
Main.overview, 'hidden', _ => this.show()
|
||||
);
|
||||
} else {
|
||||
let appDisplay = Main.overview._overview._controls._appDisplay;
|
||||
|
||||
this.connections.connect(
|
||||
appDisplay, 'show', this.hide.bind(this)
|
||||
appDisplay, 'show', _ => this.hide()
|
||||
);
|
||||
this.connections.connect(
|
||||
appDisplay, 'hide', this.show.bind(this)
|
||||
appDisplay, 'hide', _ => this.show()
|
||||
);
|
||||
this.connections.connect(
|
||||
Main.overview, 'hidden', this.show.bind(this)
|
||||
Main.overview, 'hidden', _ => this.show()
|
||||
);
|
||||
}
|
||||
|
||||
@ -425,12 +299,12 @@ export const PanelBlur = class PanelBlur {
|
||||
) {
|
||||
// connect to overview opening/closing
|
||||
this.connections.connect(Main.overview, ['showing', 'hiding'],
|
||||
this.update_visibility.bind(this)
|
||||
_ => this.update_visibility()
|
||||
);
|
||||
|
||||
// connect to session mode update
|
||||
this.connections.connect(Main.sessionMode, 'updated',
|
||||
this.update_visibility.bind(this)
|
||||
_ => this.update_visibility()
|
||||
);
|
||||
|
||||
// manage already-existing windows
|
||||
@ -450,7 +324,7 @@ export const PanelBlur = class PanelBlur {
|
||||
|
||||
// connect to a workspace change
|
||||
this.connections.connect(global.window_manager, 'switch-workspace',
|
||||
this.update_visibility.bind(this)
|
||||
_ => this.update_visibility()
|
||||
);
|
||||
|
||||
// perform early update
|
||||
@ -600,75 +474,45 @@ export const PanelBlur = class PanelBlur {
|
||||
);
|
||||
}
|
||||
|
||||
/// Fixes a bug where the blur is washed away when changing the sigma, or
|
||||
/// enabling/disabling other effects.
|
||||
invalidate_blur(actors) {
|
||||
if (this.settings.panel.STATIC_BLUR && actors.widgets.background)
|
||||
actors.widgets.background.get_content()?.invalidate();
|
||||
}
|
||||
|
||||
invalidate_all_blur() {
|
||||
this.actors_list.forEach(actors => this.invalidate_blur(actors));
|
||||
}
|
||||
|
||||
set_sigma(s) {
|
||||
this.actors_list.forEach(actors => {
|
||||
actors.effects.blur.radius = s * 2 * actors.effects.blur.scale;
|
||||
this.invalidate_blur(actors);
|
||||
});
|
||||
}
|
||||
|
||||
set_brightness(b) {
|
||||
this.actors_list.forEach(actors => {
|
||||
actors.effects.blur.brightness = b;
|
||||
});
|
||||
}
|
||||
|
||||
set_color(c) {
|
||||
this.actors_list.forEach(actors => {
|
||||
actors.effects.color.color = c;
|
||||
});
|
||||
}
|
||||
|
||||
set_noise_amount(n) {
|
||||
this.actors_list.forEach(actors => {
|
||||
actors.effects.noise.noise = n;
|
||||
});
|
||||
}
|
||||
|
||||
set_noise_lightness(l) {
|
||||
this.actors_list.forEach(actors => {
|
||||
actors.effects.noise.lightness = l;
|
||||
});
|
||||
update_pipeline() {
|
||||
this.actors_list.forEach(actors =>
|
||||
actors.bg_manager._bms_pipeline.change_pipeline_to(
|
||||
this.settings.panel.PIPELINE
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
show() {
|
||||
this.actors_list.forEach(actors => {
|
||||
actors.widgets.background_parent.show();
|
||||
actors.widgets.background.show();
|
||||
});
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.actors_list.forEach(actors => {
|
||||
actors.widgets.background_parent.hide();
|
||||
actors.widgets.background.hide();
|
||||
});
|
||||
}
|
||||
|
||||
// destroy every blurred background left, necessary after sleep
|
||||
destroy_blur_effects() {
|
||||
Main.panel?.get_parent()?.get_children().forEach(
|
||||
child => {
|
||||
if (child.name === 'topbar-blurred-background-parent') {
|
||||
child.get_children().forEach(meta_background_actor => {
|
||||
meta_background_actor.get_effects().forEach(effect => {
|
||||
this.effects_manager.remove(effect);
|
||||
});
|
||||
});
|
||||
child.destroy_all_children();
|
||||
child.destroy();
|
||||
}
|
||||
}
|
||||
);
|
||||
// IMPORTANT: do never call this in a mutable `this.actors_list.forEach`
|
||||
destroy_blur(actors, panel_already_destroyed) {
|
||||
this.set_should_override_panel(actors, false);
|
||||
|
||||
actors.bg_manager._bms_pipeline.destroy();
|
||||
|
||||
if (panel_already_destroyed)
|
||||
actors.bg_manager.backgroundActor = null;
|
||||
actors.bg_manager.destroy();
|
||||
|
||||
if (!panel_already_destroyed) {
|
||||
actors.widgets.panel_box.remove_child(actors.widgets.background_group);
|
||||
actors.widgets.background_group.destroy_all_children();
|
||||
actors.widgets.background_group.destroy();
|
||||
}
|
||||
|
||||
let index = this.actors_list.indexOf(actors);
|
||||
if (index >= 0)
|
||||
this.actors_list.splice(index, 1);
|
||||
}
|
||||
|
||||
disable() {
|
||||
@ -678,21 +522,8 @@ export const PanelBlur = class PanelBlur {
|
||||
|
||||
this.update_light_text_classname(true);
|
||||
|
||||
this.actors_list.forEach(actors => {
|
||||
this.set_should_override_panel(actors, false);
|
||||
this.effects_manager.remove(actors.effects.noise);
|
||||
this.effects_manager.remove(actors.effects.color);
|
||||
this.effects_manager.remove(actors.effects.blur);
|
||||
try {
|
||||
actors.widgets.panel_box.remove_child(
|
||||
actors.widgets.background_parent
|
||||
);
|
||||
} catch (e) { }
|
||||
actors.widgets.background_parent?.destroy();
|
||||
});
|
||||
|
||||
this.destroy_blur_effects();
|
||||
|
||||
const immutable_actors_list = [...this.actors_list];
|
||||
immutable_actors_list.forEach(actors => this.destroy_blur(actors, false));
|
||||
this.actors_list = [];
|
||||
|
||||
this.connections.disconnect_all();
|
||||
|
||||
@ -1,41 +1,21 @@
|
||||
import Shell from 'gi://Shell';
|
||||
import Meta from 'gi://Meta';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
|
||||
import { Pipeline } from '../conveniences/pipeline.js';
|
||||
|
||||
export const ScreenshotBlur = class ScreenshotBlur {
|
||||
constructor(connections, settings, effects_manager) {
|
||||
this.connections = connections;
|
||||
this.effects = [];
|
||||
this.settings = settings;
|
||||
this.screenshot_background_managers = [];
|
||||
this.effects_manager = effects_manager;
|
||||
}
|
||||
|
||||
enable() {
|
||||
this._log("blurring screenshot's window selector");
|
||||
|
||||
// connect to every background change (even without changing image)
|
||||
// FIXME this signal is fired very often, so we should find another one
|
||||
// fired only when necessary (but that still catches all cases)
|
||||
this.connections.connect(
|
||||
Main.layoutManager._backgroundGroup,
|
||||
'notify',
|
||||
_ => {
|
||||
this._log("updated background for screenshot's window selector");
|
||||
this.update_backgrounds();
|
||||
}
|
||||
);
|
||||
|
||||
// connect to monitors change
|
||||
this.connections.connect(
|
||||
Main.layoutManager,
|
||||
'monitors-changed',
|
||||
_ => {
|
||||
if (Main.screenShield && !Main.screenShield.locked) {
|
||||
this._log("changed monitors for screenshot's window selector");
|
||||
this.update_backgrounds();
|
||||
}
|
||||
}
|
||||
this.connections.connect(Main.layoutManager, 'monitors-changed',
|
||||
_ => this.update_backgrounds()
|
||||
);
|
||||
|
||||
// update backgrounds when the component is enabled
|
||||
@ -44,121 +24,78 @@ export const ScreenshotBlur = class ScreenshotBlur {
|
||||
|
||||
update_backgrounds() {
|
||||
// remove every old background
|
||||
this.remove();
|
||||
|
||||
// add new backgrounds
|
||||
this.remove_background_actors();
|
||||
// create new backgrounds for the screenshot window selector
|
||||
for (let i = 0; i < Main.screenshotUI._windowSelectors.length; i++) {
|
||||
const actor = Main.screenshotUI._windowSelectors[i];
|
||||
const monitor = Main.layoutManager.monitors[i];
|
||||
const window_selector = Main.screenshotUI._windowSelectors[i];
|
||||
const pipeline = new Pipeline(
|
||||
this.effects_manager,
|
||||
global.blur_my_shell._pipelines_manager,
|
||||
this.settings.screenshot.PIPELINE
|
||||
);
|
||||
pipeline.create_background_with_effects(
|
||||
window_selector._monitorIndex, this.screenshot_background_managers,
|
||||
window_selector, 'bms-screenshot-blurred-widget', false
|
||||
);
|
||||
|
||||
if (!monitor)
|
||||
continue;
|
||||
// prevent old `BackgroundActor` from being accessed, which creates a whole bug of logs
|
||||
this.connections.connect(window_selector.get_parent(), 'destroy', _ => {
|
||||
this.screenshot_background_managers.forEach(background_manager => {
|
||||
if (background_manager.backgroundActor) {
|
||||
let widget = background_manager.backgroundActor.get_parent();
|
||||
let parent = widget?.get_parent();
|
||||
|
||||
const bg_actor = this.create_background_actor(monitor);
|
||||
actor.insert_child_at_index(bg_actor, 0);
|
||||
actor._blur_actor = bg_actor;
|
||||
if (parent == window_selector) {
|
||||
background_manager._bms_pipeline.destroy();
|
||||
parent.remove_child(widget);
|
||||
}
|
||||
}
|
||||
background_manager.destroy();
|
||||
});
|
||||
|
||||
window_selector.get_children().forEach(child => {
|
||||
if (child.get_name() == 'bms-screenshot-blurred-widget')
|
||||
window_selector.remove_child(child);
|
||||
});
|
||||
|
||||
let index = this.screenshot_background_managers.indexOf(window_selector);
|
||||
this.screenshot_background_managers.splice(index, 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
create_background_actor(monitor) {
|
||||
let bg_actor = new Meta.BackgroundActor({
|
||||
meta_display: global.display,
|
||||
monitor: monitor.index
|
||||
update_pipeline() {
|
||||
this.screenshot_background_managers.forEach(background_manager =>
|
||||
background_manager._bms_pipeline.change_pipeline_to(
|
||||
this.settings.screenshot.PIPELINE
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
remove_background_actors() {
|
||||
this.screenshot_background_managers.forEach(background_manager => {
|
||||
background_manager._bms_pipeline.destroy();
|
||||
if (background_manager.backgroundActor) {
|
||||
let widget = background_manager.backgroundActor.get_parent();
|
||||
widget?.get_parent()?.remove_child(widget);
|
||||
}
|
||||
background_manager.destroy();
|
||||
});
|
||||
let background = Main.layoutManager._backgroundGroup.get_child_at_index(
|
||||
Main.layoutManager.monitors.length - monitor.index - 1
|
||||
|
||||
Main.screenshotUI._windowSelectors.forEach(window_selector =>
|
||||
window_selector.get_children().forEach(child => {
|
||||
if (child.get_name() == 'bms-screenshot-blurred-widget')
|
||||
window_selector.remove_child(child);
|
||||
})
|
||||
);
|
||||
|
||||
if (!background) {
|
||||
this._warn("could not get background for screenshot's window selector");
|
||||
return bg_actor;
|
||||
}
|
||||
|
||||
bg_actor.content.set({
|
||||
background: background.get_content().background
|
||||
});
|
||||
|
||||
let blur_effect = new Shell.BlurEffect({
|
||||
brightness: this.settings.screenshot.CUSTOMIZE
|
||||
? this.settings.screenshot.BRIGHTNESS
|
||||
: this.settings.BRIGHTNESS,
|
||||
radius: (this.settings.screenshot.CUSTOMIZE
|
||||
? this.settings.screenshot.SIGMA
|
||||
: this.settings.SIGMA) * 2 * monitor.geometry_scale,
|
||||
mode: Shell.BlurMode.ACTOR
|
||||
});
|
||||
|
||||
// store the scale in the effect in order to retrieve it in set_sigma
|
||||
blur_effect.scale = monitor.geometry_scale;
|
||||
|
||||
let color_effect = this.effects_manager.new_color_effect({
|
||||
color: this.settings.screenshot.CUSTOMIZE
|
||||
? this.settings.screenshot.COLOR
|
||||
: this.settings.COLOR
|
||||
}, this.settings);
|
||||
|
||||
let noise_effect = this.effects_manager.new_noise_effect({
|
||||
noise: this.settings.screenshot.CUSTOMIZE
|
||||
? this.settings.screenshot.NOISE_AMOUNT
|
||||
: this.settings.NOISE_AMOUNT,
|
||||
lightness: this.settings.screenshot.CUSTOMIZE
|
||||
? this.settings.screenshot.NOISE_LIGHTNESS
|
||||
: this.settings.NOISE_LIGHTNESS
|
||||
}, this.settings);
|
||||
|
||||
bg_actor.add_effect(color_effect);
|
||||
bg_actor.add_effect(noise_effect);
|
||||
bg_actor.add_effect(blur_effect);
|
||||
this.effects.push({ blur_effect, color_effect, noise_effect });
|
||||
|
||||
return bg_actor;
|
||||
}
|
||||
|
||||
set_sigma(s) {
|
||||
this.effects.forEach(effect => {
|
||||
effect.blur_effect.radius = s * 2 * effect.blur_effect;
|
||||
});
|
||||
}
|
||||
|
||||
set_brightness(b) {
|
||||
this.effects.forEach(effect => {
|
||||
effect.blur_effect.brightness = b;
|
||||
});
|
||||
}
|
||||
|
||||
set_color(c) {
|
||||
this.effects.forEach(effect => {
|
||||
effect.color_effect.color = c;
|
||||
});
|
||||
}
|
||||
|
||||
set_noise_amount(n) {
|
||||
this.effects.forEach(effect => {
|
||||
effect.noise_effect.noise = n;
|
||||
});
|
||||
}
|
||||
|
||||
set_noise_lightness(l) {
|
||||
this.effects.forEach(effect => {
|
||||
effect.noise_effect.lightness = l;
|
||||
});
|
||||
}
|
||||
|
||||
remove() {
|
||||
Main.screenshotUI._windowSelectors.forEach(actor => {
|
||||
if (actor._blur_actor) {
|
||||
actor.remove_child(actor._blur_actor);
|
||||
actor._blur_actor.destroy();
|
||||
delete actor._blur_actor;
|
||||
}
|
||||
});
|
||||
this.effects = [];
|
||||
this.screenshot_background_managers = [];
|
||||
}
|
||||
|
||||
disable() {
|
||||
this._log("removing blur from screenshot's window selector");
|
||||
|
||||
this.remove();
|
||||
this.remove_background_actors();
|
||||
this.connections.disconnect_all();
|
||||
}
|
||||
|
||||
|
||||
@ -1,15 +1,16 @@
|
||||
import Shell from 'gi://Shell';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
|
||||
import { PaintSignals } from '../effects/paint_signals.js';
|
||||
import { PaintSignals } from '../conveniences/paint_signals.js';
|
||||
import { DummyPipeline } from '../conveniences/dummy_pipeline.js';
|
||||
|
||||
|
||||
export const WindowListBlur = class WindowListBlur {
|
||||
constructor(connections, settings, _) {
|
||||
constructor(connections, settings, effects_manager) {
|
||||
this.connections = connections;
|
||||
this.settings = settings;
|
||||
this.paint_signals = new PaintSignals(connections);
|
||||
this.effects = [];
|
||||
this.effects_manager = effects_manager;
|
||||
this.pipelines = [];
|
||||
}
|
||||
|
||||
enable() {
|
||||
@ -37,36 +38,35 @@ export const WindowListBlur = class WindowListBlur {
|
||||
});
|
||||
}
|
||||
|
||||
try_blur(child) {
|
||||
try_blur(actor) {
|
||||
if (
|
||||
child.constructor.name === "WindowList" &&
|
||||
child.style !== "background:transparent;"
|
||||
actor.constructor.name === "WindowList" &&
|
||||
actor.style !== "background:transparent;"
|
||||
) {
|
||||
this._log("found window list to blur");
|
||||
|
||||
let blur_effect = new Shell.BlurEffect({
|
||||
name: 'window-list-blur',
|
||||
radius: (this.settings.window_list.CUSTOMIZE
|
||||
? this.settings.window_list.SIGMA
|
||||
: this.settings.SIGMA) * 2,
|
||||
brightness: this.settings.window_list.CUSTOMIZE
|
||||
? this.settings.window_list.BRIGHTNESS
|
||||
: this.settings.BRIGHTNESS,
|
||||
mode: Shell.BlurMode.BACKGROUND
|
||||
});
|
||||
const pipeline = new DummyPipeline(
|
||||
this.effects_manager, this.settings.window_list
|
||||
);
|
||||
pipeline.attach_effect_to_actor(actor);
|
||||
this.pipelines.push(pipeline);
|
||||
|
||||
child.set_style("background:transparent;");
|
||||
child.add_effect(blur_effect);
|
||||
this.effects.push({ blur_effect });
|
||||
actor.set_style("background:transparent;");
|
||||
|
||||
child._windowList.get_children().forEach(
|
||||
window => this.blur_window_button(window)
|
||||
actor._windowList.get_children().forEach(
|
||||
window => this.style_window_button(window)
|
||||
);
|
||||
|
||||
this.connections.connect(
|
||||
child._windowList,
|
||||
actor._windowList,
|
||||
'child-added',
|
||||
(_, window) => this.blur_window_button(window)
|
||||
(_, window) => this.style_window_button(window)
|
||||
);
|
||||
|
||||
this.connections.connect(
|
||||
actor,
|
||||
'destroy',
|
||||
_ => this.destroy_blur(pipeline, true)
|
||||
);
|
||||
|
||||
|
||||
@ -83,75 +83,61 @@ export const WindowListBlur = class WindowListBlur {
|
||||
if (this.settings.HACKS_LEVEL === 1) {
|
||||
this._log("window list hack level 1");
|
||||
|
||||
this.paint_signals.connect(child, blur_effect);
|
||||
|
||||
} else if (this.settings.HACKS_LEVEL === 2) {
|
||||
this._log("window list hack level 2");
|
||||
|
||||
this.paint_signals.connect(child, blur_effect);
|
||||
this.paint_signals.disconnect_all_for_actor(actor);
|
||||
this.paint_signals.connect(actor, pipeline.effect);
|
||||
} else {
|
||||
this.paint_signals.disconnect_all();
|
||||
this.paint_signals.disconnect_all_for_actor(actor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blur_window_button(window) {
|
||||
style_window_button(window) {
|
||||
window.get_child_at_index(0).set_style(
|
||||
"box-shadow:none; background-color:rgba(0,0,0,0.2); border-radius:5px;"
|
||||
);
|
||||
}
|
||||
|
||||
try_remove_blur(child) {
|
||||
if (
|
||||
child.constructor.name === "WindowList" &&
|
||||
child.style === "background:transparent;"
|
||||
) {
|
||||
child.style = null;
|
||||
child.remove_effect_by_name('window-list-blur');
|
||||
// IMPORTANT: do never call this in a mutable `this.pipelines.forEach`
|
||||
destroy_blur(pipeline, actor_destroyed = false) {
|
||||
if (!actor_destroyed) {
|
||||
this.remove_style(pipeline.actor);
|
||||
this.paint_signals.disconnect_all_for_actor(pipeline.actor);
|
||||
}
|
||||
|
||||
child._windowList.get_children().forEach(
|
||||
pipeline.destroy();
|
||||
|
||||
let index = this.pipelines.indexOf(pipeline);
|
||||
if (index >= 0)
|
||||
this.pipelines.splice(pipeline, 1);
|
||||
}
|
||||
|
||||
remove_style(actor) {
|
||||
if (
|
||||
actor.constructor.name === "WindowList" &&
|
||||
actor.style === "background:transparent;"
|
||||
) {
|
||||
actor.style = null;
|
||||
actor._windowList.get_children().forEach(
|
||||
child => child.get_child_at_index(0).set_style(null)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
set_sigma(s) {
|
||||
this.effects.forEach(effect => {
|
||||
effect.blur_effect.radius = s * 2;
|
||||
});
|
||||
}
|
||||
|
||||
set_brightness(b) {
|
||||
this.effects.forEach(effect => {
|
||||
effect.blur_effect.brightness = b;
|
||||
});
|
||||
}
|
||||
|
||||
// not implemented for dynamic blur
|
||||
set_color(c) { }
|
||||
set_noise_amount(n) { }
|
||||
set_noise_lightness(l) { }
|
||||
|
||||
hide() {
|
||||
this.set_sigma(0);
|
||||
this.pipelines.forEach(pipeline => pipeline.effect?.set_enabled(false));
|
||||
}
|
||||
|
||||
show() {
|
||||
this.set_sigma(
|
||||
this.settings.window_list.CUSTOMIZE
|
||||
? this.settings.window_list.SIGMA
|
||||
: this.settings.SIGMA
|
||||
);
|
||||
this.pipelines.forEach(pipeline => pipeline.effect?.set_enabled(true));
|
||||
}
|
||||
|
||||
disable() {
|
||||
this._log("removing blur from window list");
|
||||
|
||||
Main.layoutManager.uiGroup.get_children().forEach(
|
||||
child => this.try_remove_blur(child)
|
||||
);
|
||||
const immutable_pipelines_list = [...this.pipelines];
|
||||
immutable_pipelines_list.forEach(pipeline => this.destroy_blur(pipeline));
|
||||
|
||||
this.effects = [];
|
||||
this.pipelines = [];
|
||||
this.connections.disconnect_all();
|
||||
}
|
||||
|
||||
|
||||
@ -53,6 +53,7 @@ export const Connections = class Connections {
|
||||
this.buffer.splice(index, 1);
|
||||
}
|
||||
});
|
||||
infos.destroy_id = destroy_id;
|
||||
}
|
||||
|
||||
this.buffer.push(infos);
|
||||
@ -66,10 +67,12 @@ export const Connections = class Connections {
|
||||
);
|
||||
|
||||
// remove each of them
|
||||
actor_connections.forEach((connection) => {
|
||||
actor_connections.forEach(connection => {
|
||||
// disconnect
|
||||
try {
|
||||
connection.actor.disconnect(connection.id);
|
||||
if ('destroy_id' in connection)
|
||||
connection.actor.disconnect(connection.destroy_id);
|
||||
} catch (e) {
|
||||
this._warn(`error removing connection: ${e}; continuing`);
|
||||
}
|
||||
@ -82,10 +85,12 @@ export const Connections = class Connections {
|
||||
|
||||
/// Disconnect every connection for each actor.
|
||||
disconnect_all() {
|
||||
this.buffer.forEach((connection) => {
|
||||
this.buffer.forEach(connection => {
|
||||
// disconnect
|
||||
try {
|
||||
connection.actor.disconnect(connection.id);
|
||||
if ('destroy_id' in connection)
|
||||
connection.actor.disconnect(connection.destroy_id);
|
||||
} catch (e) {
|
||||
this._warn(`error removing connection: ${e}; continuing`);
|
||||
}
|
||||
|
||||
@ -0,0 +1,112 @@
|
||||
import St from 'gi://St';
|
||||
import Clutter from 'gi://Clutter';
|
||||
|
||||
/// A dummy `Pipeline`, for dynamic blur only.
|
||||
/// Instead of a pipeline id, we take the settings of the component we want to blur.
|
||||
export const DummyPipeline = class DummyPipeline {
|
||||
constructor(effects_manager, settings, actor = null) {
|
||||
this.effects_manager = effects_manager;
|
||||
this.settings = settings;
|
||||
this.effect = null;
|
||||
this.attach_effect_to_actor(actor);
|
||||
}
|
||||
|
||||
create_background_with_effect(
|
||||
background_group,
|
||||
widget_name
|
||||
) {
|
||||
// create the new actor
|
||||
this.actor = new St.Widget({ name: widget_name });
|
||||
|
||||
this.attach_effect_to_actor(this.actor);
|
||||
|
||||
// a dummy `BackgroundManager`, just to access the pipeline easily
|
||||
let bg_manager = new Clutter.Actor;
|
||||
bg_manager.backgroundActor = this.actor;
|
||||
bg_manager._bms_pipeline = this;
|
||||
|
||||
background_group.insert_child_at_index(this.actor, 0);
|
||||
|
||||
return [this.actor, bg_manager];
|
||||
};
|
||||
|
||||
attach_effect_to_actor(actor) {
|
||||
// set the actor
|
||||
if (actor)
|
||||
this.actor = actor;
|
||||
else {
|
||||
this.remove_pipeline_from_actor();
|
||||
return;
|
||||
}
|
||||
|
||||
// build the new effect to be added
|
||||
this.build_effect({
|
||||
unscaled_radius: 2 * this.settings.SIGMA,
|
||||
brightness: this.settings.BRIGHTNESS,
|
||||
});
|
||||
|
||||
this.actor_destroy_id = this.actor.connect(
|
||||
"destroy", () => this.remove_pipeline_from_actor()
|
||||
);
|
||||
|
||||
// add the effect to the actor
|
||||
if (this.actor)
|
||||
this.actor.add_effect(this.effect);
|
||||
else
|
||||
this._warn(`could not add effect to actor, actor does not exist anymore`);
|
||||
}
|
||||
|
||||
remove_pipeline_from_actor() {
|
||||
this.remove_effect();
|
||||
if (this.actor && this.actor_destroy_id)
|
||||
this.actor.disconnect(this.actor_destroy_id);
|
||||
this.actor_destroy_id = null;
|
||||
this.actor = null;
|
||||
}
|
||||
|
||||
build_effect(params) {
|
||||
// create the effect
|
||||
this.effect = this.effects_manager.new_native_dynamic_gaussian_blur_effect(params);
|
||||
|
||||
// connect to settings changes, using the true gsettings object
|
||||
this._sigma_changed_id = this.settings.settings.connect(
|
||||
'changed::sigma', () => this.effect.unscaled_radius = 2 * this.settings.SIGMA
|
||||
);
|
||||
this._brightness_changed_id = this.settings.settings.connect(
|
||||
'changed::brightness', () => this.effect.brightness = this.settings.BRIGHTNESS
|
||||
);
|
||||
}
|
||||
|
||||
repaint_effect() {
|
||||
this.effect?.queue_repaint();
|
||||
}
|
||||
|
||||
/// Remove every effect from the actor it is attached to. Please note that they are not
|
||||
/// destroyed, but rather stored (thanks to the `EffectManager` class) to be reused later.
|
||||
remove_effect() {
|
||||
if (this.effect)
|
||||
this.effects_manager.remove(this.effect);
|
||||
this.effect = null;
|
||||
|
||||
if (this._sigma_changed_id)
|
||||
this.settings.settings.disconnect(this._sigma_changed_id);
|
||||
if (this._brightness_changed_id)
|
||||
this.settings.settings.disconnect(this._brightness_changed_id);
|
||||
delete this._sigma_changed_id;
|
||||
delete this._brightness_changed_id;
|
||||
}
|
||||
|
||||
/// Do nothing for this dummy pipeline.
|
||||
/// Note: exposed to public API.
|
||||
change_pipeline_to() { return; }
|
||||
|
||||
/// Note: exposed to public API.
|
||||
destroy() {
|
||||
this.remove_effect();
|
||||
this.remove_pipeline_from_actor();
|
||||
}
|
||||
|
||||
_warn(str) {
|
||||
console.warn(`[Blur my Shell > dummy pip] ${str}`);
|
||||
}
|
||||
};
|
||||
@ -1,21 +1,41 @@
|
||||
import { ColorEffect } from '../effects/color_effect.js';
|
||||
import { NoiseEffect } from '../effects/noise_effect.js';
|
||||
|
||||
import { get_supported_effects } from '../effects/effects.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 = [];
|
||||
this.SUPPORTED_EFFECTS = get_supported_effects();
|
||||
|
||||
Object.keys(this.SUPPORTED_EFFECTS).forEach(effect_name => {
|
||||
// init the arrays containing each unused effect
|
||||
this[effect_name + '_effects'] = [];
|
||||
|
||||
// init the functions for each effect
|
||||
this['new_' + effect_name + '_effect'] = function (params) {
|
||||
let effect;
|
||||
if (this[effect_name + '_effects'].length > 0) {
|
||||
effect = this[effect_name + '_effects'].splice(0, 1)[0];
|
||||
effect.set({
|
||||
...this.SUPPORTED_EFFECTS[effect_name].class.default_params, ...params
|
||||
});
|
||||
} else
|
||||
effect = new this.SUPPORTED_EFFECTS[effect_name].class({
|
||||
...this.SUPPORTED_EFFECTS[effect_name].class.default_params, ...params
|
||||
});
|
||||
|
||||
this.used.push(effect);
|
||||
this.connect_to_destroy(effect);
|
||||
return effect;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
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.remove(effect, true);
|
||||
});
|
||||
|
||||
this.connections.connect(effect, 'notify::actor', _ => {
|
||||
@ -24,42 +44,22 @@ export const EffectsManager = class EffectsManager {
|
||||
if (effect.old_actor && actor != effect.old_actor)
|
||||
effect.old_actor.disconnect(effect.old_actor_id);
|
||||
|
||||
if (actor) {
|
||||
if (actor && actor != effect.old_actor) {
|
||||
effect.old_actor_id = actor.connect('destroy', _ => {
|
||||
this.remove(effect);
|
||||
this.remove(effect, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
// IMPORTANT: do never call this in a mutable `this.used.forEach`
|
||||
remove(effect, actor_already_destroyed = false) {
|
||||
if (!actor_already_destroyed)
|
||||
try {
|
||||
effect.get_actor()?.remove_effect(effect);
|
||||
} catch (e) {
|
||||
this._warn(`could not remove the effect, continuing: ${e}`);
|
||||
}
|
||||
if (effect.old_actor)
|
||||
effect.old_actor.disconnect(effect.old_actor_id);
|
||||
delete effect.old_actor;
|
||||
@ -69,21 +69,22 @@ export const EffectsManager = class EffectsManager {
|
||||
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);
|
||||
Object.keys(this.SUPPORTED_EFFECTS).forEach(effect_name => {
|
||||
if (effect instanceof this.SUPPORTED_EFFECTS[effect_name].class)
|
||||
this[effect_name + '_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);
|
||||
const immutable_used_list = [...this.used];
|
||||
immutable_used_list.forEach(effect => this.remove(effect));
|
||||
Object.keys(this.SUPPORTED_EFFECTS).forEach(effect_name => {
|
||||
this[effect_name + '_effects'].splice(0, this[effect_name + '_effects'].length);
|
||||
});
|
||||
}
|
||||
|
||||
_warn(str) {
|
||||
console.warn(`[Blur my Shell > effects mng] ${str}`);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,15 +1,10 @@
|
||||
import { Type } from './settings.js';
|
||||
|
||||
// This lists the preferences keys
|
||||
export const 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.PIPELINES, name: "pipelines" },
|
||||
{ type: Type.I, name: "hacks-level" },
|
||||
{ type: Type.B, name: "debug" },
|
||||
]
|
||||
@ -17,37 +12,25 @@ export const Keys = [
|
||||
{
|
||||
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.S, name: "pipeline" },
|
||||
{ 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.B, name: "static-blur" },
|
||||
{ type: Type.S, name: "pipeline" },
|
||||
{ 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: "force-light-text" },
|
||||
{ type: Type.B, name: "override-background" },
|
||||
@ -58,29 +41,22 @@ export const Keys = [
|
||||
{
|
||||
component: "dash-to-dock", schemas: [
|
||||
{ type: Type.B, name: "blur" },
|
||||
{ type: Type.B, name: "customize" },
|
||||
{ type: Type.B, name: "static-blur" },
|
||||
{ type: Type.S, name: "pipeline" },
|
||||
{ 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" },
|
||||
{ type: Type.I, name: "corner-radius" },
|
||||
]
|
||||
},
|
||||
{
|
||||
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: "dynamic-opacity" },
|
||||
{ type: Type.B, name: "blur-on-overview" },
|
||||
{ type: Type.B, name: "enable-all" },
|
||||
{ type: Type.AS, name: "whitelist" },
|
||||
@ -90,34 +66,27 @@ export const Keys = [
|
||||
{
|
||||
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" },
|
||||
{ type: Type.S, name: "pipeline" },
|
||||
]
|
||||
},
|
||||
{
|
||||
component: "window-list", schemas: [
|
||||
{ type: Type.B, name: "blur" },
|
||||
{ type: Type.B, name: "customize" },
|
||||
{ type: Type.S, name: "pipeline" },
|
||||
{ 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: "coverflow-alt-tab", schemas: [
|
||||
{ type: Type.B, name: "blur" },
|
||||
{ type: Type.S, name: "pipeline" },
|
||||
]
|
||||
},
|
||||
{
|
||||
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" },
|
||||
{ type: Type.S, name: "pipeline" },
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -130,4 +99,90 @@ export const Keys = [
|
||||
{ type: Type.B, name: "blur-original-panel" },
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
// This lists the deprecated preferences keys
|
||||
export const DEPRECATED_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" },
|
||||
]
|
||||
},
|
||||
{
|
||||
component: "overview", schemas: [
|
||||
{ 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: "appfolder", schemas: [
|
||||
{ type: Type.B, name: "customize" },
|
||||
{ type: Type.C, name: "color" },
|
||||
{ type: Type.D, name: "noise-amount" },
|
||||
{ type: Type.D, name: "noise-lightness" },
|
||||
]
|
||||
},
|
||||
{
|
||||
component: "panel", schemas: [
|
||||
{ type: Type.B, name: "customize" },
|
||||
{ type: Type.C, name: "color" },
|
||||
{ type: Type.D, name: "noise-amount" },
|
||||
{ type: Type.D, name: "noise-lightness" },
|
||||
]
|
||||
},
|
||||
{
|
||||
component: "dash-to-dock", schemas: [
|
||||
{ type: Type.B, name: "customize" },
|
||||
{ type: Type.C, name: "color" },
|
||||
{ type: Type.D, name: "noise-amount" },
|
||||
{ type: Type.D, name: "noise-lightness" },
|
||||
{ type: Type.I, name: "corner-radius" },
|
||||
]
|
||||
},
|
||||
{
|
||||
component: "applications", schemas: [
|
||||
{ type: Type.B, name: "customize" },
|
||||
{ type: Type.C, name: "color" },
|
||||
{ type: Type.D, name: "noise-amount" },
|
||||
{ type: Type.D, name: "noise-lightness" },
|
||||
]
|
||||
},
|
||||
{
|
||||
component: "lockscreen", schemas: [
|
||||
{ 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: "customize" },
|
||||
{ type: Type.C, name: "color" },
|
||||
{ type: Type.D, name: "noise-amount" },
|
||||
{ type: Type.D, name: "noise-lightness" },
|
||||
]
|
||||
},
|
||||
{
|
||||
component: "screenshot", schemas: [
|
||||
{ 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" },
|
||||
]
|
||||
},
|
||||
];
|
||||
@ -37,7 +37,8 @@ export const PaintSignals = class PaintSignals {
|
||||
)
|
||||
)
|
||||
this.connections.connect(actor, 'destroy', () => {
|
||||
this.buffer.forEach(infos => {
|
||||
const immutable_buffer = [...this.buffer];
|
||||
immutable_buffer.forEach(infos => {
|
||||
if (infos.actor === actor) {
|
||||
// remove from buffer
|
||||
let index = this.buffer.indexOf(infos);
|
||||
@ -50,7 +51,8 @@ export const PaintSignals = class PaintSignals {
|
||||
}
|
||||
|
||||
disconnect_all_for_actor(actor) {
|
||||
this.buffer.forEach(infos => {
|
||||
const immutable_buffer = [...this.buffer];
|
||||
immutable_buffer.forEach(infos => {
|
||||
if (infos.actor === actor) {
|
||||
this.connections.disconnect_all_for(infos.paint_effect);
|
||||
infos.actor.remove_effect(infos.paint_effect);
|
||||
@ -0,0 +1,223 @@
|
||||
import St from 'gi://St';
|
||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
import * as Background from 'resource:///org/gnome/shell/ui/background.js';
|
||||
|
||||
/// A `Pipeline` object is a handy way to manage the effects attached to an actor. It only manages
|
||||
/// one actor at a time (so blurring multiple widgets will need multiple `Pipeline`), and is
|
||||
/// linked to a `pipeline_id` that has been (hopefully) defined in the settings.
|
||||
///
|
||||
/// It communicates with the settings through the `PipelinesManager` object, and receives different
|
||||
/// signals (with `pipeline_id` being an unique string):
|
||||
/// - `'pipeline_id'::pipeline-updated`, handing a new pipeline descriptor object, when the pipeline
|
||||
/// has been changed enough that it needs to rebuild the effects configuration
|
||||
/// - `'pipeline_id'::pipeline-destroyed`, when the pipeline has been destroyed; thus making the
|
||||
/// `Pipeline` change its id to `pipeline_default`
|
||||
///
|
||||
/// And each effect, with an unique `id`, is connected to the `PipelinesManager` for the signals:
|
||||
/// - `'pipeline_id'::effect-'id'-key-removed`, handing the key that was removed
|
||||
/// - `'pipeline_id'::effect-'id'-key-updated`, handing the key that was changed and its new value
|
||||
/// - `'pipeline_id'::effect-'id'-key-added`, handing the key that was added and its value
|
||||
export const Pipeline = class Pipeline {
|
||||
constructor(effects_manager, pipelines_manager, pipeline_id, actor = null) {
|
||||
this.effects_manager = effects_manager;
|
||||
this.pipelines_manager = pipelines_manager;
|
||||
this.effects = [];
|
||||
this.set_pipeline_id(pipeline_id);
|
||||
this.attach_pipeline_to_actor(actor);
|
||||
}
|
||||
|
||||
/// Create a background linked to the monitor with index `monitor_index`, with a
|
||||
/// `BackgroundManager` that is appended to the list `background_managers`. The background actor
|
||||
/// will be given the name `widget_name` and inserted into the given `background_group`.
|
||||
/// If `use_absolute_position` is false, then the position used is at (0,0); useful when the
|
||||
/// positioning is relative.
|
||||
/// Note: exposed to public API.
|
||||
create_background_with_effects(
|
||||
monitor_index,
|
||||
background_managers,
|
||||
background_group,
|
||||
widget_name,
|
||||
use_absolute_position = true
|
||||
) {
|
||||
let monitor = Main.layoutManager.monitors[monitor_index];
|
||||
|
||||
// create the new actor
|
||||
this.actor = new St.Widget({
|
||||
name: widget_name,
|
||||
x: use_absolute_position ? monitor.x : 0,
|
||||
y: .5 + (use_absolute_position ? monitor.y : 0), // add 1 to correct z-position
|
||||
z_position: 1, // seems to fix the multi-monitor glitch
|
||||
width: monitor.width,
|
||||
height: monitor.height
|
||||
});
|
||||
|
||||
// remove the effects, wether or not we attach the pipeline to the actor: if they are fired
|
||||
// while the actor has changed, this could go bad
|
||||
this.remove_all_effects();
|
||||
if (this.pipeline_id)
|
||||
this.attach_pipeline_to_actor(this.actor);
|
||||
|
||||
let bg_manager = new Background.BackgroundManager({
|
||||
container: this.actor,
|
||||
monitorIndex: monitor_index,
|
||||
controlPosition: false,
|
||||
});
|
||||
bg_manager._bms_pipeline = this;
|
||||
|
||||
background_managers.push(bg_manager);
|
||||
background_group.insert_child_at_index(this.actor, 0);
|
||||
|
||||
return this.actor;
|
||||
};
|
||||
|
||||
/// Set the pipeline id, correctly connecting the `Pipeline` object to listen the pipelines
|
||||
/// manager for pipeline-wide changes. This does not update the effects in consequence, call
|
||||
/// `change_pipeline_to` instead if you want to reconstruct the effects too.
|
||||
set_pipeline_id(pipeline_id) {
|
||||
// disconnect ancient signals
|
||||
this.remove_connections();
|
||||
|
||||
// change the id
|
||||
this.pipeline_id = pipeline_id;
|
||||
|
||||
// connect to settings changes
|
||||
this._pipeline_changed_id = this.pipelines_manager.connect(
|
||||
this.pipeline_id + '::pipeline-updated',
|
||||
(_, new_pipeline) => this.update_effects_from_pipeline(new_pipeline)
|
||||
);
|
||||
this._pipeline_destroyed_id = this.pipelines_manager.connect(
|
||||
this.pipeline_id + '::pipeline-destroyed',
|
||||
_ => this.change_pipeline_to("pipeline_default")
|
||||
);
|
||||
}
|
||||
|
||||
/// Disconnect the signals for the pipeline changes. Please note that the signals related to the
|
||||
/// effects are stored with them and removed with `remove_all_effects`.
|
||||
remove_connections() {
|
||||
if (this._pipeline_changed_id)
|
||||
this.pipelines_manager.disconnect(this._pipeline_changed_id);
|
||||
if (this._pipeline_destroyed_id)
|
||||
this.pipelines_manager.disconnect(this._pipeline_destroyed_id);
|
||||
this._pipeline_changed_id = null;
|
||||
this._pipeline_destroyed_id = null;
|
||||
}
|
||||
|
||||
/// Attach a Pipeline object with `pipeline_id` already set to an actor.
|
||||
attach_pipeline_to_actor(actor) {
|
||||
// set the actor
|
||||
if (actor)
|
||||
this.actor = actor;
|
||||
else {
|
||||
this.remove_pipeline_from_actor();
|
||||
return;
|
||||
}
|
||||
|
||||
// attach the pipeline
|
||||
let pipeline = this.pipelines_manager.pipelines[this.pipeline_id];
|
||||
if (!pipeline) {
|
||||
this._warn(`could not attach pipeline to actor, pipeline "${this.pipeline_id}" not found`);
|
||||
// do not recurse...
|
||||
if ("pipeline_default" in this.pipelines_manager.pipelines) {
|
||||
this.set_pipeline_id("pipeline_default");
|
||||
pipeline = this.pipelines_manager.pipelines["pipeline_default"];
|
||||
} else
|
||||
return;
|
||||
}
|
||||
|
||||
this.actor_destroy_id = this.actor.connect(
|
||||
"destroy", () => this.remove_pipeline_from_actor()
|
||||
);
|
||||
|
||||
// update the effects
|
||||
this.update_effects_from_pipeline(pipeline);
|
||||
}
|
||||
|
||||
remove_pipeline_from_actor() {
|
||||
this.remove_all_effects();
|
||||
if (this.actor && this.actor_destroy_id)
|
||||
this.actor.disconnect(this.actor_destroy_id);
|
||||
this.actor_destroy_id = null;
|
||||
this.actor = null;
|
||||
}
|
||||
|
||||
/// Update the effects from the given pipeline object, the hard way.
|
||||
update_effects_from_pipeline(pipeline) {
|
||||
// remove all effects
|
||||
this.remove_all_effects();
|
||||
|
||||
// build the new effects to be added
|
||||
pipeline.effects.forEach(effect => {
|
||||
if ('new_' + effect.type + '_effect' in this.effects_manager)
|
||||
this.build_effect(effect);
|
||||
else
|
||||
this._warn(`could not add effect to actor, effect "${effect.type}" not found`);
|
||||
});
|
||||
this.effects.reverse();
|
||||
|
||||
// add the effects to the actor
|
||||
if (this.actor)
|
||||
this.effects.forEach(effect => this.actor.add_effect(effect));
|
||||
else
|
||||
this._warn(`could not add effect to actor, actor does not exist anymore`);
|
||||
}
|
||||
|
||||
/// Given an `effect_infos` object containing the effect type, id and params, build an effect
|
||||
/// and append it to the effects list
|
||||
build_effect(effect_infos) {
|
||||
let effect = this.effects_manager['new_' + effect_infos.type + '_effect'](effect_infos.params);
|
||||
this.effects.push(effect);
|
||||
|
||||
// connect to settings changes
|
||||
effect._effect_key_removed_id = this.pipelines_manager.connect(
|
||||
this.pipeline_id + '::effect-' + effect_infos.id + '-key-removed',
|
||||
(_, key) => effect[key] = effect.constructor.default_params[key]
|
||||
);
|
||||
effect._effect_key_updated_id = this.pipelines_manager.connect(
|
||||
this.pipeline_id + '::effect-' + effect_infos.id + '-key-updated',
|
||||
(_, key, value) => effect[key] = value
|
||||
);
|
||||
effect._effect_key_added_id = this.pipelines_manager.connect(
|
||||
this.pipeline_id + '::effect-' + effect_infos.id + '-key-added',
|
||||
(_, key, value) => effect[key] = value
|
||||
);
|
||||
}
|
||||
|
||||
/// Remove every effect from the actor it is attached to. Please note that they are not
|
||||
/// destroyed, but rather stored (thanks to the `EffectManager` class) to be reused later.
|
||||
remove_all_effects() {
|
||||
this.effects.forEach(effect => {
|
||||
this.effects_manager.remove(effect);
|
||||
[
|
||||
effect._effect_key_removed_id,
|
||||
effect._effect_key_updated_id,
|
||||
effect._effect_key_added_id
|
||||
].forEach(
|
||||
id => { if (id) this.pipelines_manager.disconnect(id); }
|
||||
);
|
||||
delete effect._effect_key_removed_id;
|
||||
delete effect._effect_key_updated_id;
|
||||
delete effect._effect_key_added_id;
|
||||
});
|
||||
this.effects = [];
|
||||
}
|
||||
|
||||
/// Change the pipeline id, and update the effects according to this change.
|
||||
/// Note: exposed to public API.
|
||||
change_pipeline_to(pipeline_id) {
|
||||
this.set_pipeline_id(pipeline_id);
|
||||
this.attach_pipeline_to_actor(this.actor);
|
||||
}
|
||||
|
||||
/// Resets the `Pipeline` object to a sane state, removing every effect and signal.
|
||||
/// Note: exposed to public API.
|
||||
destroy() {
|
||||
this.remove_all_effects();
|
||||
this.remove_connections();
|
||||
this.remove_pipeline_from_actor();
|
||||
this.pipeline_id = null;
|
||||
}
|
||||
|
||||
_warn(str) {
|
||||
console.warn(`[Blur my Shell > pipeline] ${str}`);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,168 @@
|
||||
const Signals = imports.signals;
|
||||
|
||||
/// The `PipelinesManager` object permits to store the list of pipelines and their effects in
|
||||
/// memory. It is meant to *always* be in sync with the `org.gnome.shell.extensions.blur-my-shell`'s
|
||||
/// `pipelines` gschema. However, we do not want to re-create every effect each time this schema is
|
||||
/// changed, so the pipelines manager handles it, and dispatches the updates with targeted signals.
|
||||
///
|
||||
/// It is only connected to ONE signal (the pipelines schema being changed), and emits numerous
|
||||
/// which are connected to by both the different `Pipeline` objects in the extension, and by the
|
||||
/// different pages of the extension preferences.
|
||||
/// It emits three different types of signals:
|
||||
///
|
||||
/// - general changes to the pipelines list, connected to by the extension preferences:
|
||||
/// - `pipeline-list-changed`, when the list of pipelines has changed (by creation or deletion)
|
||||
/// - `pipeline-names-changed`, when the name of a pipeline is changed
|
||||
///
|
||||
/// - signals that are targeted towards a given pipeline, with `pipeline_id` being its unique id:
|
||||
/// - `'pipeline_id'::pipeline-updated`, handing a new pipeline descriptor object, when the
|
||||
/// pipeline has been changed quite a bit (added/destroyed/reordered the effects)
|
||||
/// - `'pipeline_id'::pipeline-destroyed`, when the pipeline has been destroyed
|
||||
/// - `'pipeline_id'::pipeline-renamed`, handing the new name, when the pipeline has been
|
||||
/// renamed, which is only important for the preferences
|
||||
///
|
||||
/// - signals that are targeted towards a given effect, with `effect_id` being its unique id, and
|
||||
/// `pipeline_id` the unique id of the pipeline it is attached to:
|
||||
/// - `'pipeline_id'::effect-'effect_id'-key-removed`, handing the key that was removed
|
||||
/// - `'pipeline_id'::effect-'effect_id'-key-updated`, handing the key that was changed and its
|
||||
/// new value
|
||||
/// - `'pipeline_id'::effect-'effect_id'-key-added`, handing the key that was added and its
|
||||
/// value
|
||||
export class PipelinesManager {
|
||||
constructor(settings) {
|
||||
this.settings = settings;
|
||||
this.pipelines = this.settings.PIPELINES;
|
||||
this.settings.PIPELINES_changed(_ => this.on_pipeline_update());
|
||||
}
|
||||
|
||||
create_pipeline(name, effects = []) {
|
||||
// select a random id for the pipeline
|
||||
let id = "pipeline_" + ("" + Math.random()).slice(2, 16);
|
||||
// add a random ID for each effect, to help tracking them
|
||||
effects.forEach(effect => effect.id = "effect_" + ("" + Math.random()).slice(2, 16));
|
||||
|
||||
this.pipelines[id] = { name, effects };
|
||||
this.settings.PIPELINES = this.pipelines;
|
||||
this._emit('pipeline-created', id, this.pipelines[id]);
|
||||
this._emit('pipeline-list-changed');
|
||||
return id;
|
||||
}
|
||||
|
||||
duplicate_pipeline(id) {
|
||||
if (!(id in this.pipelines)) {
|
||||
this._warn(`could not duplicate pipeline, id ${id} does not exist`);
|
||||
return;
|
||||
}
|
||||
const pipeline = this.pipelines[id];
|
||||
this.create_pipeline(pipeline.name + " - duplicate", [...pipeline.effects]);
|
||||
this.settings.PIPELINES = this.pipelines;
|
||||
}
|
||||
|
||||
delete_pipeline(id) {
|
||||
if (!(id in this.pipelines)) {
|
||||
this._warn(`could not delete pipeline, id ${id} does not exist`);
|
||||
return;
|
||||
}
|
||||
if (id == "pipeline_default") {
|
||||
this._warn(`could not delete pipeline "pipeline_default" as it is immutable`);
|
||||
return;
|
||||
}
|
||||
delete this.pipelines[id];
|
||||
this.settings.PIPELINES = this.pipelines;
|
||||
this._emit(id + '::pipeline-destroyed');
|
||||
this._emit('pipeline-list-changed');
|
||||
}
|
||||
|
||||
update_pipeline_effects(id, effects, emit_update_signal = true) {
|
||||
if (!(id in this.pipelines)) {
|
||||
this._warn(`could not update pipeline effects, id ${id} does not exist`);
|
||||
return;
|
||||
}
|
||||
this.pipelines[id].effects = [...effects];
|
||||
this.settings.PIPELINES = this.pipelines;
|
||||
if (emit_update_signal)
|
||||
this._emit(id + '::pipeline-updated');
|
||||
}
|
||||
|
||||
rename_pipeline(id, name) {
|
||||
if (!(id in this.pipelines)) {
|
||||
this._warn(`could not rename pipeline, id ${id} does not exist`);
|
||||
return;
|
||||
}
|
||||
this.pipelines[id].name = name.slice();
|
||||
this.settings.PIPELINES = this.pipelines;
|
||||
this._emit(id + '::pipeline-renamed', name);
|
||||
this._emit('pipeline-names-changed');
|
||||
}
|
||||
|
||||
on_pipeline_update() {
|
||||
const old_pipelines = this.pipelines;
|
||||
this.pipelines = this.settings.PIPELINES;
|
||||
|
||||
for (var pipeline_id in old_pipelines) {
|
||||
// if we find a pipeline that does not exist anymore, signal it
|
||||
if (!(pipeline_id in this.pipelines)) {
|
||||
this._emit(pipeline_id + '::pipeline-destroyed');
|
||||
continue;
|
||||
}
|
||||
|
||||
const old_pipeline = old_pipelines[pipeline_id];
|
||||
const new_pipeline = this.pipelines[pipeline_id];
|
||||
|
||||
// verify if both pipelines have effects in the same order
|
||||
// if they have, then check for their parameters
|
||||
if (
|
||||
old_pipeline.effects.length == new_pipeline.effects.length &&
|
||||
old_pipeline.effects.every((effect, i) => effect.id === new_pipeline.effects[i].id)
|
||||
) {
|
||||
for (let i = 0; i < old_pipeline.effects.length; i++) {
|
||||
const old_effect = old_pipeline.effects[i];
|
||||
const new_effect = new_pipeline.effects[i];
|
||||
const id = old_effect.id;
|
||||
for (let key in old_effect.params) {
|
||||
// if a key was removed, we emit to tell the effect to use the default value
|
||||
if (!(key in new_effect.params))
|
||||
this._emit(
|
||||
pipeline_id + '::effect-' + id + '-key-removed', key
|
||||
);
|
||||
// if a key was updated, we emit to tell the effect to change its value
|
||||
else if (old_effect.params[key] != new_effect.params[key])
|
||||
this._emit(
|
||||
pipeline_id + '::effect-' + id + '-key-updated', key, new_effect.params[key]
|
||||
);
|
||||
}
|
||||
for (let key in new_effect.params) {
|
||||
// if a key was added, we emit to tell the effect the key and its value
|
||||
if (!(key in old_effect.params))
|
||||
this._emit(
|
||||
pipeline_id + '::effect-' + id + '-key-added', key, new_effect.params[key]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if either the order has changed, or there are new effects, then rebuild it
|
||||
else
|
||||
this._emit(pipeline_id + '::pipeline-updated', new_pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.settings.PIPELINES_disconnect();
|
||||
}
|
||||
|
||||
_emit(signal, ...args) {
|
||||
this.emit(signal, ...args);
|
||||
this._log(`signal: '${signal}', arguments: ${args}`);
|
||||
}
|
||||
|
||||
_log(str) {
|
||||
if (this.settings.DEBUG)
|
||||
console.log(`[Blur my Shell > pipelines] ${str}`);
|
||||
}
|
||||
|
||||
_warn(str) {
|
||||
console.warn(`[Blur my Shell > pipelines] ${str}`);
|
||||
}
|
||||
}
|
||||
|
||||
Signals.addSignalMethods(PipelinesManager.prototype);
|
||||
@ -1,5 +1,4 @@
|
||||
import GLib from 'gi://GLib';
|
||||
|
||||
const Signals = imports.signals;
|
||||
|
||||
/// An enum non-extensively describing the type of gsettings key.
|
||||
@ -9,7 +8,8 @@ export const Type = {
|
||||
D: 'Double',
|
||||
S: 'String',
|
||||
C: 'Color',
|
||||
AS: 'StringArray'
|
||||
AS: 'StringArray',
|
||||
PIPELINES: 'Pipelines'
|
||||
};
|
||||
|
||||
/// An object to get and manage the gsettings preferences.
|
||||
@ -118,20 +118,197 @@ export const Settings = class Settings {
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case Type.PIPELINES:
|
||||
Object.defineProperty(component, property_name, {
|
||||
get() {
|
||||
let pips = component_settings.get_value(key.name).deep_unpack();
|
||||
Object.keys(pips).forEach(pipeline_id => {
|
||||
let pipeline = pips[pipeline_id];
|
||||
|
||||
if (!('name' in pipeline)) {
|
||||
this._warn('impossible to get pipelines, pipeline has not name, resetting');
|
||||
component[property_name + '_reset']();
|
||||
return component[property_name];
|
||||
}
|
||||
let name = pipeline.name.deep_unpack();
|
||||
if (typeof name !== 'string') {
|
||||
this._warn('impossible to get pipelines, pipeline name is not a string, resetting');
|
||||
component[property_name + '_reset']();
|
||||
return component[property_name];
|
||||
}
|
||||
|
||||
if (!('effects' in pipeline)) {
|
||||
this._warn('impossible to get pipelines, pipeline has not effects, resetting');
|
||||
component[property_name + '_reset']();
|
||||
return component[property_name];
|
||||
}
|
||||
let effects = pipeline.effects.deep_unpack();
|
||||
if (!Array.isArray(effects)) {
|
||||
this._warn('impossible to get pipelines, pipeline effects is not an array, resetting');
|
||||
component[property_name + '_reset']();
|
||||
return component[property_name];
|
||||
}
|
||||
|
||||
effects = effects.map(effect => effect.deep_unpack());
|
||||
effects.forEach(effect => {
|
||||
if (!('type' in effect)) {
|
||||
this._warn('impossible to get pipelines, effect has not type, resetting');
|
||||
component[property_name + '_reset']();
|
||||
return component[property_name];
|
||||
}
|
||||
let type = effect.type.deep_unpack();
|
||||
if (typeof type !== 'string') {
|
||||
this._warn('impossible to get pipelines, effect type is not a string, resetting');
|
||||
component[property_name + '_reset']();
|
||||
return component[property_name];
|
||||
}
|
||||
|
||||
if (!('id' in effect)) {
|
||||
this._warn('impossible to get pipelines, effect has not id, resetting');
|
||||
component[property_name + '_reset']();
|
||||
return component[property_name];
|
||||
}
|
||||
let id = effect.id.deep_unpack();
|
||||
if (typeof id !== 'string') {
|
||||
this._warn('impossible to get pipelines, effect id is not a string, resetting');
|
||||
component[property_name + '_reset']();
|
||||
return component[property_name];
|
||||
}
|
||||
|
||||
let params = {};
|
||||
if ('params' in effect)
|
||||
params = effect.params.deep_unpack();
|
||||
if (!(params && typeof params === 'object' && params.constructor === Object)) {
|
||||
this._warn('impossible to get pipelines, effect params is not an object, resetting');
|
||||
component[property_name + '_reset']();
|
||||
return component[property_name];
|
||||
}
|
||||
Object.keys(params).forEach(param_key => {
|
||||
params[param_key] = params[param_key].deep_unpack();
|
||||
});
|
||||
|
||||
effect.type = type;
|
||||
effect.id = id;
|
||||
effect.params = params;
|
||||
});
|
||||
pipeline.name = name;
|
||||
pipeline.effects = effects;
|
||||
});
|
||||
return pips;
|
||||
},
|
||||
set(pips) {
|
||||
let pipelines = {};
|
||||
Object.keys(pips).forEach(pipeline_id => {
|
||||
let pipeline = pips[pipeline_id];
|
||||
if (!(pipeline && typeof pipeline === 'object' && pipeline.constructor === Object)) {
|
||||
this._warn('impossible to set pipelines, pipeline is not an object');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!('name' in pipeline)) {
|
||||
this._warn('impossible to set pipelines, pipeline has no name');
|
||||
return;
|
||||
}
|
||||
if (typeof pipeline.name !== 'string') {
|
||||
this._warn('impossible to set pipelines, pipeline name is not a string');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!('effects' in pipeline)) {
|
||||
this._warn('impossible to set pipelines, pipeline has no effect');
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(pipeline.effects)) {
|
||||
this._warn('impossible to set pipelines, effects is not an array');
|
||||
return;
|
||||
}
|
||||
|
||||
let gvariant_effects = [];
|
||||
pipeline.effects.forEach(effect => {
|
||||
if (!(effect instanceof Object)) {
|
||||
this._warn('impossible to set pipelines, effect is not an object');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!('type' in effect)) {
|
||||
this._warn('impossible to set pipelines, effect has not type');
|
||||
return;
|
||||
}
|
||||
if (typeof effect.type !== 'string') {
|
||||
this._warn('impossible to set pipelines, effect type is not a string');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!('id' in effect)) {
|
||||
this._warn('impossible to set pipelines, effect has not id');
|
||||
return;
|
||||
}
|
||||
if (typeof effect.id !== 'string') {
|
||||
this._warn('impossible to set pipelines, effect id is not a string');
|
||||
return;
|
||||
}
|
||||
|
||||
let params = {};
|
||||
if ('params' in effect) {
|
||||
params = effect.params;
|
||||
}
|
||||
let gvariant_params = {};
|
||||
Object.keys(params).forEach(param_key => {
|
||||
let param = params[param_key];
|
||||
if (typeof param === 'boolean')
|
||||
gvariant_params[param_key] = GLib.Variant.new_boolean(param);
|
||||
else if (typeof param === 'number') {
|
||||
if (Number.isInteger(param))
|
||||
gvariant_params[param_key] = GLib.Variant.new_int32(param);
|
||||
else
|
||||
gvariant_params[param_key] = GLib.Variant.new_double(param);
|
||||
} else if (typeof param === 'string')
|
||||
gvariant_params[param_key] = GLib.Variant.new_string(param);
|
||||
else if (Array.isArray(param) && param.length == 4)
|
||||
gvariant_params[param_key] = new GLib.Variant("(dddd)", param);
|
||||
else
|
||||
this._warn('impossible to set pipeline, effect parameter type is unknown');
|
||||
});
|
||||
|
||||
gvariant_effects.push(
|
||||
new GLib.Variant("a{sv}", {
|
||||
type: GLib.Variant.new_string(effect.type),
|
||||
id: GLib.Variant.new_string(effect.id),
|
||||
params: new GLib.Variant("a{sv}", gvariant_params)
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
pipelines[pipeline_id] = {
|
||||
name: GLib.Variant.new_string(pipeline.name),
|
||||
effects: new GLib.Variant("av", gvariant_effects)
|
||||
};
|
||||
});
|
||||
let val = new GLib.Variant("a{sa{sv}}", pipelines);
|
||||
component_settings.set_value(key.name, val);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
component[property_name + '_reset'] = function () {
|
||||
return component_settings.reset(key.name);
|
||||
};
|
||||
|
||||
component[property_name + '_signal_ids'] = [];
|
||||
component[property_name + '_changed'] = function (cb) {
|
||||
return component_settings.connect('changed::' + key.name, cb);
|
||||
component[property_name + '_signal_ids'].push(
|
||||
component_settings.connect('changed::' + key.name, cb)
|
||||
);
|
||||
};
|
||||
|
||||
component[property_name + '_disconnect'] = function () {
|
||||
return component_settings.disconnect.apply(
|
||||
component_settings, arguments
|
||||
component[property_name + '_signal_ids'].forEach(
|
||||
id => component_settings.disconnect(id)
|
||||
);
|
||||
component[property_name + '_signal_ids'] = [];
|
||||
};
|
||||
});
|
||||
});
|
||||
@ -177,6 +354,10 @@ export const Settings = class Settings {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_warn(str) {
|
||||
console.warn(`[Blur my Shell > settings] ${str}`);
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(Settings.prototype);
|
||||
@ -0,0 +1,40 @@
|
||||
import { Settings } from './settings.js';
|
||||
import { KEYS, DEPRECATED_KEYS } from './keys.js';
|
||||
|
||||
const CURRENT_SETTINGS_VERSION = 2;
|
||||
|
||||
export function update_from_old_settings(gsettings) {
|
||||
const preferences = new Settings(KEYS, gsettings);
|
||||
const deprecated_preferences = new Settings(DEPRECATED_KEYS, gsettings);
|
||||
const old_version = preferences.settings.get_int('settings-version');
|
||||
|
||||
if (old_version < CURRENT_SETTINGS_VERSION) {
|
||||
// set artifacts hacks to be 1 at most, as it should be suitable now that most big bugs have
|
||||
// been resolved (and especially because hack levels to 2 now means disabling clipped
|
||||
// redraws entirely, which is very much not what we want for users that update)
|
||||
if (preferences.HACKS_LEVEL > 1)
|
||||
preferences.HACKS_LEVEL = 1;
|
||||
|
||||
// enable dash-to-dock blurring, as most disabled it due to the lack of rounded corners; set
|
||||
// it to static blur by default too and with transparent background
|
||||
preferences.dash_to_dock.BLUR = true;
|
||||
preferences.dash_to_dock.STATIC_BLUR = true;
|
||||
preferences.dash_to_dock.STYLE_DASH_TO_DOCK = 0;
|
||||
|
||||
// 'customize' has been removed: we merge the current used settings
|
||||
['appfolder', 'panel', 'dash_to_dock', 'applications', 'window_list'].forEach(
|
||||
component_name => {
|
||||
const deprecated_component = deprecated_preferences[component_name];
|
||||
const new_component = preferences[component_name];
|
||||
if (!deprecated_component.CUSTOMIZE) {
|
||||
new_component.SIGMA = deprecated_preferences.SIGMA;
|
||||
new_component.BRIGHTNESS = deprecated_preferences.BRIGHTNESS;
|
||||
}
|
||||
});
|
||||
|
||||
// remove old preferences in order not to clutter the gsettings
|
||||
deprecated_preferences.reset();
|
||||
}
|
||||
|
||||
preferences.settings.set_int('settings-version', CURRENT_SETTINGS_VERSION);
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
import GLib from 'gi://GLib';
|
||||
|
||||
export const IS_IN_PREFERENCES = typeof global === 'undefined';
|
||||
|
||||
// Taken from https://github.com/Schneegans/Burn-My-Windows/blob/main/src/utils.js
|
||||
// This method can be used to import a module in the GNOME Shell process only. This
|
||||
// is useful if you want to use a module in extension.js, but not in the preferences
|
||||
// process. This method returns null if it is called in the preferences process.
|
||||
export async function import_in_shell_only(module) {
|
||||
if (IS_IN_PREFERENCES)
|
||||
return null;
|
||||
return (await import(module)).default;
|
||||
}
|
||||
|
||||
// In use for the effects, to prevent boilerplate code
|
||||
export function setup_params(outer_this, params) {
|
||||
// setup each parameter, either with the given or the default value
|
||||
for (const params_name in outer_this.constructor.default_params) {
|
||||
outer_this["_" + params_name] = null;
|
||||
outer_this[params_name] = params_name in params ?
|
||||
params[params_name] :
|
||||
outer_this.constructor.default_params[params_name];
|
||||
}
|
||||
};
|
||||
|
||||
export const get_shader_source = (Shell, shader_filename, self_uri) => {
|
||||
if (!Shell)
|
||||
return;
|
||||
const shader_path = GLib.filename_from_uri(
|
||||
GLib.uri_resolve_relative(self_uri, shader_filename, GLib.UriFlags.NONE)
|
||||
)[0];
|
||||
try {
|
||||
return Shell.get_file_contents_utf8_sync(shader_path);
|
||||
} catch (e) {
|
||||
console.warn(`[Blur my Shell > effect] error loading shader from ${shader_path}: ${e}`);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
@ -1,114 +0,0 @@
|
||||
uniform sampler2D tex;
|
||||
uniform float sigma;
|
||||
uniform int dir;
|
||||
uniform float brightness;
|
||||
uniform float corner_radius;
|
||||
uniform float width;
|
||||
uniform float height;
|
||||
|
||||
float circleBounds(vec2 p, vec2 center, float clip_radius) {
|
||||
vec2 delta = p - center;
|
||||
float dist_squared = dot(delta, delta);
|
||||
|
||||
float outer_radius = clip_radius + 0.5;
|
||||
if (dist_squared >= (outer_radius * outer_radius))
|
||||
return 0.0;
|
||||
|
||||
float inner_radius = clip_radius - 0.5;
|
||||
if (dist_squared <= (inner_radius * inner_radius))
|
||||
return 1.0;
|
||||
|
||||
return outer_radius - sqrt(dist_squared);
|
||||
}
|
||||
|
||||
vec4 shapeCorner(vec4 pixel, vec2 p, vec2 center, float clip_radius) {
|
||||
float alpha = circleBounds(p, center, clip_radius);
|
||||
return vec4(pixel.rgb * alpha, min(alpha, pixel.a));
|
||||
}
|
||||
|
||||
vec4 getTexture(vec2 uv) {
|
||||
if (uv.x < 2. / width)
|
||||
uv.x = 2. / width;
|
||||
|
||||
if (uv.y < 2. / height)
|
||||
uv.y = 2. / height;
|
||||
|
||||
if (uv.x > 1. - 3. / width)
|
||||
uv.x = 1. - 3. / width;
|
||||
|
||||
if (uv.y > 1. - 3. / height)
|
||||
uv.y = 1. - 3. / height;
|
||||
|
||||
return texture2D(tex, uv);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
vec2 uv = cogl_tex_coord_in[0].xy;
|
||||
|
||||
vec2 pos = uv * vec2(width, height);
|
||||
|
||||
vec2 direction = vec2(dir, (1.0 - dir));
|
||||
|
||||
float pixel_step;
|
||||
if (dir == 0)
|
||||
pixel_step = 1.0 / height;
|
||||
else
|
||||
pixel_step = 1.0 / width;
|
||||
|
||||
vec3 gauss_coefficient;
|
||||
gauss_coefficient.x = 1.0 / (sqrt(2.0 * 3.14159265) * sigma);
|
||||
gauss_coefficient.y = exp(-0.5 / (sigma * sigma));
|
||||
gauss_coefficient.z = gauss_coefficient.y * gauss_coefficient.y;
|
||||
|
||||
float gauss_coefficient_total = gauss_coefficient.x;
|
||||
|
||||
vec4 ret = getTexture(uv) * gauss_coefficient.x;
|
||||
gauss_coefficient.xy *= gauss_coefficient.yz;
|
||||
|
||||
int n_steps = int(ceil(1.5 * sigma)) * 2;
|
||||
|
||||
for (int i = 1; i <= n_steps; i += 2) {
|
||||
float coefficient_subtotal = gauss_coefficient.x;
|
||||
gauss_coefficient.xy *= gauss_coefficient.yz;
|
||||
coefficient_subtotal += gauss_coefficient.x;
|
||||
|
||||
float gauss_ratio = gauss_coefficient.x / coefficient_subtotal;
|
||||
|
||||
float foffset = float(i) + gauss_ratio;
|
||||
vec2 offset = direction * foffset * pixel_step;
|
||||
|
||||
ret += getTexture(uv + offset) * coefficient_subtotal;
|
||||
ret += getTexture(uv - offset) * coefficient_subtotal;
|
||||
|
||||
gauss_coefficient_total += 2.0 * coefficient_subtotal;
|
||||
gauss_coefficient.xy *= gauss_coefficient.yz;
|
||||
}
|
||||
vec4 outColor = ret / gauss_coefficient_total;
|
||||
|
||||
// apply brightness and rounding on the second pass (dir==0 comes last)
|
||||
if (dir == 0) {
|
||||
// left side
|
||||
if (pos.x < corner_radius) {
|
||||
// top left corner
|
||||
if (pos.y < corner_radius) {
|
||||
outColor = shapeCorner(outColor, pos, vec2(corner_radius + 2., corner_radius + 2.), corner_radius);
|
||||
// bottom left corner
|
||||
} else if (pos.y > height - corner_radius) {
|
||||
outColor = shapeCorner(outColor, pos, vec2(corner_radius + 2., height - corner_radius - 1.), corner_radius);
|
||||
}
|
||||
// right side
|
||||
} else if (pos.x > width - corner_radius) {
|
||||
// top right corner
|
||||
if (pos.y < corner_radius) {
|
||||
outColor = shapeCorner(outColor, pos, vec2(width - corner_radius - 1., corner_radius + 2.), corner_radius);
|
||||
// bottom right corner
|
||||
} else if (pos.y > height - corner_radius) {
|
||||
outColor = shapeCorner(outColor, pos, vec2(width - corner_radius - 1., height - corner_radius - 1.), corner_radius);
|
||||
}
|
||||
}
|
||||
|
||||
outColor.rgb *= brightness;
|
||||
}
|
||||
|
||||
cogl_color_out = outColor;
|
||||
}
|
||||
@ -1,236 +0,0 @@
|
||||
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, 'blur_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 BlurEffect = new GObject.registerClass({
|
||||
GTypeName: "BlurEffect",
|
||||
Properties: {
|
||||
'radius': GObject.ParamSpec.double(
|
||||
`radius`,
|
||||
`Radius`,
|
||||
`Blur radius`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, 2000.0,
|
||||
200.0,
|
||||
),
|
||||
'brightness': GObject.ParamSpec.double(
|
||||
`brightness`,
|
||||
`Brightness`,
|
||||
`Blur brightness`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, 1.0,
|
||||
0.6,
|
||||
),
|
||||
'width': GObject.ParamSpec.double(
|
||||
`width`,
|
||||
`Width`,
|
||||
`Width`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, Number.MAX_SAFE_INTEGER,
|
||||
0.0,
|
||||
),
|
||||
'height': GObject.ParamSpec.double(
|
||||
`height`,
|
||||
`Height`,
|
||||
`Height`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, Number.MAX_SAFE_INTEGER,
|
||||
0.0,
|
||||
),
|
||||
'corner_radius': GObject.ParamSpec.double(
|
||||
`corner_radius`,
|
||||
`Corner Radius`,
|
||||
`Corner Radius`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, Number.MAX_SAFE_INTEGER,
|
||||
0,
|
||||
),
|
||||
'direction': GObject.ParamSpec.int(
|
||||
`direction`,
|
||||
`Direction`,
|
||||
`Direction`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, 1,
|
||||
0,
|
||||
),
|
||||
'chained_effect': GObject.ParamSpec.object(
|
||||
`chained_effect`,
|
||||
`Chained Effect`,
|
||||
`Chained Effect`,
|
||||
GObject.ParamFlags.READABLE,
|
||||
GObject.Object,
|
||||
),
|
||||
}
|
||||
}, class BlurEffect extends Clutter.ShaderEffect {
|
||||
constructor(params, settings) {
|
||||
super(params);
|
||||
|
||||
this._sigma = null;
|
||||
this._brightness = null;
|
||||
this._width = null;
|
||||
this._height = null;
|
||||
this._corner_radius = null;
|
||||
|
||||
this._static = true;
|
||||
this._settings = settings;
|
||||
|
||||
this._direction = 0;
|
||||
|
||||
this._chained_effect = null;
|
||||
|
||||
if (params.sigma)
|
||||
this.sigma = params.sigma;
|
||||
if (params.brightness)
|
||||
this.brightness = params.brightness;
|
||||
if (params.width)
|
||||
this.width = params.width;
|
||||
if (params.height)
|
||||
this.height = params.height;
|
||||
if (params.corner_radius)
|
||||
this.corner_radius = params.corner_radius;
|
||||
if (params.direction)
|
||||
this.direction = params.direction;
|
||||
|
||||
// set shader source
|
||||
this._source = get_shader_source();
|
||||
if (this._source)
|
||||
this.set_shader_source(this._source);
|
||||
}
|
||||
|
||||
get radius() {
|
||||
return this._radius;
|
||||
}
|
||||
|
||||
set radius(value) {
|
||||
if (this._radius !== value) {
|
||||
this._radius = value;
|
||||
|
||||
// like Clutter, we use the assumption radius = 2*sigma
|
||||
this.set_uniform_value('sigma', parseFloat(this._radius / 2 - 1e-6));
|
||||
|
||||
if (this._chained_effect) {
|
||||
this._chained_effect.radius = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get brightness() {
|
||||
return this._brightness;
|
||||
}
|
||||
|
||||
set brightness(value) {
|
||||
if (this._brightness !== value) {
|
||||
this._brightness = value;
|
||||
|
||||
this.set_uniform_value('brightness', parseFloat(this._brightness - 1e-6));
|
||||
|
||||
if (this._chained_effect) {
|
||||
this._chained_effect.brightness = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this._width;
|
||||
}
|
||||
|
||||
set width(value) {
|
||||
if (this._width !== value) {
|
||||
this._width = value;
|
||||
|
||||
this.set_uniform_value('width', parseFloat(this._width + 3.0 - 1e-6));
|
||||
|
||||
if (this._chained_effect) {
|
||||
this._chained_effect.width = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this._height;
|
||||
}
|
||||
|
||||
set height(value) {
|
||||
if (this._height !== value) {
|
||||
this._height = value;
|
||||
|
||||
this.set_uniform_value('height', parseFloat(this._height + 3.0 - 1e-6));
|
||||
|
||||
if (this._chained_effect) {
|
||||
this._chained_effect.height = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get corner_radius() {
|
||||
return this._corner_radius;
|
||||
}
|
||||
|
||||
set corner_radius(value) {
|
||||
if (this._corner_radius !== value) {
|
||||
this._corner_radius = value;
|
||||
|
||||
this.set_uniform_value('corner_radius', parseFloat(this._corner_radius - 1e-6));
|
||||
|
||||
if (this._chained_effect) {
|
||||
this._chained_effect.corner_radius = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get direction() {
|
||||
return this._direction;
|
||||
}
|
||||
|
||||
set direction(value) {
|
||||
if (this._direction !== value) {
|
||||
this._direction = value;
|
||||
}
|
||||
}
|
||||
|
||||
get chained_effect() {
|
||||
return this._chained_effect;
|
||||
}
|
||||
|
||||
vfunc_set_actor(actor) {
|
||||
super.vfunc_set_actor(actor);
|
||||
|
||||
if (this._direction == 0) {
|
||||
this._chained_effect = new BlurEffect({
|
||||
radius: this.radius,
|
||||
brightness: this.brightness,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
corner_radius: this.corner_radius,
|
||||
direction: 1
|
||||
});
|
||||
if (actor !== null)
|
||||
actor.add_effect(this._chained_effect);
|
||||
}
|
||||
}
|
||||
|
||||
vfunc_paint_target(paint_node = null, paint_context = null) {
|
||||
this.set_uniform_value("tex", 0);
|
||||
this.set_uniform_value("dir", this._direction);
|
||||
|
||||
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();
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,140 @@
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import * as utils from '../conveniences/utils.js';
|
||||
const Shell = await utils.import_in_shell_only('gi://Shell');
|
||||
const Clutter = await utils.import_in_shell_only('gi://Clutter');
|
||||
|
||||
const SHADER_FILENAME = 'color.glsl';
|
||||
const DEFAULT_PARAMS = {
|
||||
color: [0.0, 0.0, 0.0, 0.0]
|
||||
};
|
||||
|
||||
|
||||
export const ColorEffect = utils.IS_IN_PREFERENCES ?
|
||||
{ default_params: DEFAULT_PARAMS } :
|
||||
new GObject.registerClass({
|
||||
GTypeName: "ColorEffect",
|
||||
Properties: {
|
||||
'red': GObject.ParamSpec.double(
|
||||
`red`,
|
||||
`Red`,
|
||||
`Red value in shader`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, 1.0,
|
||||
0.0,
|
||||
),
|
||||
'green': GObject.ParamSpec.double(
|
||||
`green`,
|
||||
`Green`,
|
||||
`Green value in shader`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, 1.0,
|
||||
0.0,
|
||||
),
|
||||
'blue': GObject.ParamSpec.double(
|
||||
`blue`,
|
||||
`Blue`,
|
||||
`Blue value in shader`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, 1.0,
|
||||
0.0,
|
||||
),
|
||||
'blend': GObject.ParamSpec.double(
|
||||
`blend`,
|
||||
`Blend`,
|
||||
`Amount of blending between the colors`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, 1.0,
|
||||
0.0,
|
||||
),
|
||||
}
|
||||
}, class ColorEffect extends Clutter.ShaderEffect {
|
||||
constructor(params) {
|
||||
// initialize without color as a parameter
|
||||
const { color, ...parent_params } = params;
|
||||
super(parent_params);
|
||||
|
||||
this._red = null;
|
||||
this._green = null;
|
||||
this._blue = null;
|
||||
this._blend = null;
|
||||
|
||||
// set shader source
|
||||
this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url);
|
||||
if (this._source)
|
||||
this.set_shader_source(this._source);
|
||||
|
||||
// set shader color
|
||||
this.color = 'color' in params ? color : this.constructor.default_params.color;
|
||||
}
|
||||
|
||||
static get default_params() {
|
||||
return DEFAULT_PARAMS;
|
||||
}
|
||||
|
||||
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.set_enabled(this.blend > 0);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
});
|
||||
@ -1,181 +0,0 @@
|
||||
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();
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,93 @@
|
||||
// Heavily based on https://github.com/yilozt/rounded-window-corners
|
||||
// which is itself based on upstream Mutter code
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform float radius;
|
||||
uniform float width;
|
||||
uniform float height;
|
||||
uniform bool corners_top;
|
||||
uniform bool corners_bottom;
|
||||
|
||||
uniform float clip_x0;
|
||||
uniform float clip_y0;
|
||||
uniform float clip_width;
|
||||
uniform float clip_height;
|
||||
|
||||
float circle_bounds(vec2 p, vec2 center, float clip_radius) {
|
||||
vec2 delta = p - center;
|
||||
float dist_squared = dot(delta, delta);
|
||||
|
||||
float outer_radius = clip_radius + 0.5;
|
||||
if (dist_squared >= (outer_radius * outer_radius))
|
||||
return 0.0;
|
||||
|
||||
float inner_radius = clip_radius - 0.5;
|
||||
if (dist_squared <= (inner_radius * inner_radius))
|
||||
return 1.0;
|
||||
|
||||
return outer_radius - sqrt(dist_squared);
|
||||
}
|
||||
|
||||
vec4 getTexture(vec2 uv) {
|
||||
if (uv.x < 2. / width)
|
||||
uv.x = 2. / width;
|
||||
|
||||
if (uv.y < 2. / height)
|
||||
uv.y = 2. / height;
|
||||
|
||||
if (uv.x > 1. - 3. / width)
|
||||
uv.x = 1. - 3. / width;
|
||||
|
||||
if (uv.y > 1. - 3. / height)
|
||||
uv.y = 1. - 3. / height;
|
||||
|
||||
return texture2D(tex, uv);
|
||||
}
|
||||
|
||||
float rounded_rect_coverage(vec2 p, vec4 bounds, float clip_radius) {
|
||||
// Outside the bounds
|
||||
if (p.x < bounds.x || p.x > bounds.z || p.y < bounds.y || p.y > bounds.w) {
|
||||
return 0.;
|
||||
}
|
||||
|
||||
vec2 center;
|
||||
|
||||
float center_left = bounds.x + clip_radius;
|
||||
float center_right = bounds.z - clip_radius;
|
||||
|
||||
if (p.x < center_left)
|
||||
center.x = center_left + 2.;
|
||||
else if (p.x > center_right)
|
||||
center.x = center_right - 1.;
|
||||
else
|
||||
return 1.0;
|
||||
|
||||
float center_top = bounds.y + clip_radius;
|
||||
float center_bottom = bounds.w - clip_radius;
|
||||
|
||||
if (corners_top && p.y < center_top)
|
||||
center.y = center_top + 2.;
|
||||
else if (corners_bottom && p.y > center_bottom)
|
||||
center.y = center_bottom - 1.;
|
||||
else
|
||||
return 1.0;
|
||||
|
||||
return circle_bounds(p, center, clip_radius);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
vec2 uv = cogl_tex_coord_in[0].xy;
|
||||
vec2 pos = uv * vec2(width, height);
|
||||
vec4 c = getTexture(uv);
|
||||
|
||||
vec4 bounds;
|
||||
if (clip_width < 0. || clip_height < 0.) {
|
||||
bounds = vec4(clip_x0, clip_y0, clip_x0 + width, clip_y0 + height);
|
||||
} else {
|
||||
bounds = vec4(clip_x0, clip_y0, clip_x0 + clip_width, clip_y0 + clip_height);
|
||||
}
|
||||
|
||||
float alpha = rounded_rect_coverage(pos, bounds, radius);
|
||||
|
||||
cogl_color_out = vec4(c.rgb * alpha, min(alpha, c.a));
|
||||
}
|
||||
@ -0,0 +1,211 @@
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import * as utils from '../conveniences/utils.js';
|
||||
const St = await utils.import_in_shell_only('gi://St');
|
||||
const Shell = await utils.import_in_shell_only('gi://Shell');
|
||||
const Clutter = await utils.import_in_shell_only('gi://Clutter');
|
||||
|
||||
const SHADER_FILENAME = 'corner.glsl';
|
||||
const DEFAULT_PARAMS = {
|
||||
radius: 12, width: 0, height: 0,
|
||||
corners_top: true, corners_bottom: true,
|
||||
clip: [0, 0, -1, -1]
|
||||
};
|
||||
|
||||
|
||||
export const CornerEffect = utils.IS_IN_PREFERENCES ?
|
||||
{ default_params: DEFAULT_PARAMS } :
|
||||
new GObject.registerClass({
|
||||
GTypeName: "CornerEffect",
|
||||
Properties: {
|
||||
'radius': GObject.ParamSpec.double(
|
||||
`radius`,
|
||||
`Corner Radius`,
|
||||
`Corner Radius`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, Number.MAX_SAFE_INTEGER,
|
||||
12,
|
||||
),
|
||||
'width': GObject.ParamSpec.double(
|
||||
`width`,
|
||||
`Width`,
|
||||
`Width`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, Number.MAX_SAFE_INTEGER,
|
||||
0.0,
|
||||
),
|
||||
'height': GObject.ParamSpec.double(
|
||||
`height`,
|
||||
`Height`,
|
||||
`Height`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, Number.MAX_SAFE_INTEGER,
|
||||
0.0,
|
||||
),
|
||||
'corners_top': GObject.ParamSpec.boolean(
|
||||
`corners_top`,
|
||||
`Round top corners`,
|
||||
`Round top corners`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
true,
|
||||
),
|
||||
'corners_bottom': GObject.ParamSpec.boolean(
|
||||
`corners_bottom`,
|
||||
`Round bottom corners`,
|
||||
`Round bottom corners`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
true,
|
||||
),
|
||||
// FIXME this works but it logs an error, because I'm not a double...
|
||||
// I don't want to fiddle with GVariants again
|
||||
'clip': GObject.ParamSpec.double(
|
||||
`clip`,
|
||||
`Clip`,
|
||||
`Clip`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, Number.MAX_SAFE_INTEGER,
|
||||
0.0,
|
||||
),
|
||||
}
|
||||
}, class CornerEffect extends Clutter.ShaderEffect {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
|
||||
this._clip_x0 = null;
|
||||
this._clip_y0 = null;
|
||||
this._clip_width = null;
|
||||
this._clip_height = null;
|
||||
|
||||
utils.setup_params(this, params);
|
||||
|
||||
// set shader source
|
||||
this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url);
|
||||
if (this._source)
|
||||
this.set_shader_source(this._source);
|
||||
|
||||
const theme_context = St.ThemeContext.get_for_stage(global.stage);
|
||||
theme_context.connectObject('notify::scale-factor', _ => this.update_radius(), this);
|
||||
}
|
||||
|
||||
static get default_params() {
|
||||
return DEFAULT_PARAMS;
|
||||
}
|
||||
|
||||
get radius() {
|
||||
return this._radius;
|
||||
}
|
||||
|
||||
set radius(value) {
|
||||
if (this._radius !== value) {
|
||||
this._radius = value;
|
||||
|
||||
this.update_radius();
|
||||
}
|
||||
}
|
||||
|
||||
update_radius() {
|
||||
const theme_context = St.ThemeContext.get_for_stage(global.stage);
|
||||
let radius = Math.min(
|
||||
this.radius * theme_context.scale_factor,
|
||||
this.width / 2, this.height / 2
|
||||
);
|
||||
if (this._clip_width >= 0 || this._clip_height >= 0)
|
||||
radius = Math.min(radius, this._clip_width / 2, this._clip_height / 2);
|
||||
|
||||
this.set_uniform_value('radius', parseFloat(radius - 1e-6));
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this._width;
|
||||
}
|
||||
|
||||
set width(value) {
|
||||
if (this._width !== value) {
|
||||
this._width = value;
|
||||
|
||||
this.set_uniform_value('width', parseFloat(this._width + 3.0 - 1e-6));
|
||||
this.update_radius();
|
||||
}
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this._height;
|
||||
}
|
||||
|
||||
set height(value) {
|
||||
if (this._height !== value) {
|
||||
this._height = value;
|
||||
|
||||
this.set_uniform_value('height', parseFloat(this._height + 3.0 - 1e-6));
|
||||
this.update_radius();
|
||||
}
|
||||
}
|
||||
|
||||
get corners_top() {
|
||||
return this._corners_top;
|
||||
}
|
||||
|
||||
set corners_top(value) {
|
||||
if (this._corners_top !== value) {
|
||||
this._corners_top = value;
|
||||
|
||||
this.set_uniform_value('corners_top', this._corners_top ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
get corners_bottom() {
|
||||
return this._corners_bottom;
|
||||
}
|
||||
|
||||
set corners_bottom(value) {
|
||||
if (this._corners_bottom !== value) {
|
||||
this._corners_bottom = value;
|
||||
|
||||
this.set_uniform_value('corners_bottom', this._corners_bottom ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
get clip() {
|
||||
return [this._clip_x0, this._clip_y0, this._clip_width, this._clip_height];
|
||||
}
|
||||
|
||||
set clip(value) {
|
||||
[this._clip_x0, this._clip_y0, this._clip_width, this._clip_height] = value;
|
||||
this.set_uniform_value('clip_x0', parseFloat(this._clip_x0 - 1e-6));
|
||||
this.set_uniform_value('clip_y0', parseFloat(this._clip_y0 - 1e-6));
|
||||
this.set_uniform_value('clip_width', parseFloat(this._clip_width + 3 - 1e-6));
|
||||
this.set_uniform_value('clip_height', parseFloat(this._clip_height + 3 - 1e-6));
|
||||
this.update_radius();
|
||||
}
|
||||
|
||||
vfunc_set_actor(actor) {
|
||||
if (this._actor_connection_size_id) {
|
||||
let old_actor = this.get_actor();
|
||||
old_actor?.disconnect(this._actor_connection_size_id);
|
||||
}
|
||||
if (this._actor_connection_clip_rect_id) {
|
||||
let old_actor = this.get_actor();
|
||||
old_actor?.disconnect(this._actor_connection_clip_rect_id);
|
||||
}
|
||||
|
||||
if (actor) {
|
||||
this.width = actor.width;
|
||||
this.height = actor.height;
|
||||
this._actor_connection_size_id = actor.connect('notify::size', _ => {
|
||||
this.width = actor.width;
|
||||
this.height = actor.height;
|
||||
});
|
||||
|
||||
this.clip = actor.has_clip ? actor.get_clip() : [0, 0, -10, -10];
|
||||
this._actor_connection_clip_rect_id = actor.connect('notify::clip-rect', _ => {
|
||||
this.clip = actor.has_clip ? actor.get_clip() : [0, 0, -10, -10];
|
||||
});
|
||||
}
|
||||
else {
|
||||
this._actor_connection_size_id = null;
|
||||
this._actor_connection_clip_rect_id = null;
|
||||
}
|
||||
|
||||
super.vfunc_set_actor(actor);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,71 @@
|
||||
uniform sampler2D tex;
|
||||
uniform int operation;
|
||||
uniform float width;
|
||||
uniform float height;
|
||||
|
||||
#define CORRECTION 2.25
|
||||
#define SIZE_ADDITION 3
|
||||
|
||||
vec4 get_texture_at_position(vec2 position) {
|
||||
vec2 raw_position = position + vec2(CORRECTION, CORRECTION);
|
||||
vec2 raw_uv = raw_position / vec2(width + SIZE_ADDITION, height + SIZE_ADDITION);
|
||||
|
||||
return texture2D(tex, raw_uv);
|
||||
}
|
||||
|
||||
vec4 try_get_texture_at_position(vec2 position, inout int count) {
|
||||
if (any(greaterThanEqual(position, vec2(width, height))) ||
|
||||
any(lessThan(position, vec2(0, 0)))) {
|
||||
return vec4(0);
|
||||
} else {
|
||||
count++;
|
||||
return get_texture_at_position(position);
|
||||
}
|
||||
}
|
||||
|
||||
ivec2 get_corrected_position() {
|
||||
vec2 raw_uv = cogl_tex_coord0_in.st;
|
||||
vec2 raw_position = raw_uv * vec2(width + SIZE_ADDITION, height + SIZE_ADDITION);
|
||||
return ivec2(raw_position - vec2(CORRECTION, CORRECTION));
|
||||
}
|
||||
|
||||
void main() {
|
||||
ivec2 corrected_position = get_corrected_position();
|
||||
|
||||
// 1-step derivative
|
||||
if (operation == 0) {
|
||||
vec4 color = vec4(0);
|
||||
int c = 0;
|
||||
color += try_get_texture_at_position(corrected_position + vec2(0, 1), c);
|
||||
color -= try_get_texture_at_position(corrected_position + vec2(0, 0), c);
|
||||
color += try_get_texture_at_position(corrected_position + vec2(1, 0), c);
|
||||
color -= try_get_texture_at_position(corrected_position + vec2(0, 0), c);
|
||||
if (c < 4) {
|
||||
color = vec4(0);
|
||||
}
|
||||
cogl_color_out = vec4(color.xyz, 1);
|
||||
} else
|
||||
// 2-step derivative
|
||||
if (operation == 1) {
|
||||
vec4 color = vec4(0);
|
||||
int c = 0;
|
||||
color += try_get_texture_at_position(corrected_position + vec2(0, 1), c);
|
||||
color -= try_get_texture_at_position(corrected_position + vec2(0, -1), c);
|
||||
color += try_get_texture_at_position(corrected_position + vec2(1, 0), c);
|
||||
color -= try_get_texture_at_position(corrected_position + vec2(-1, 0), c);
|
||||
if (c < 4) {
|
||||
color = vec4(0);
|
||||
}
|
||||
cogl_color_out = vec4(color.xyz / 2, 1);
|
||||
} else
|
||||
// laplacian
|
||||
if (operation == 2) {
|
||||
vec4 color = vec4(0);
|
||||
color = -4 * get_texture_at_position(corrected_position);
|
||||
color += get_texture_at_position(corrected_position + vec2(0, 1));
|
||||
color += get_texture_at_position(corrected_position + vec2(0, -1));
|
||||
color += get_texture_at_position(corrected_position + vec2(1, 0));
|
||||
color += get_texture_at_position(corrected_position + vec2(-1, 0));
|
||||
cogl_color_out = vec4(color.xyz, 1);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import * as utils from '../conveniences/utils.js';
|
||||
const Shell = await utils.import_in_shell_only('gi://Shell');
|
||||
const Clutter = await utils.import_in_shell_only('gi://Clutter');
|
||||
|
||||
const SHADER_FILENAME = 'derivative.glsl';
|
||||
const DEFAULT_PARAMS = {
|
||||
operation: 0, width: 0, height: 0
|
||||
};
|
||||
|
||||
|
||||
export const DerivativeEffect = utils.IS_IN_PREFERENCES ?
|
||||
{ default_params: DEFAULT_PARAMS } :
|
||||
new GObject.registerClass({
|
||||
GTypeName: "DerivativeEffect",
|
||||
Properties: {
|
||||
'operation': GObject.ParamSpec.int(
|
||||
`operation`,
|
||||
`Operation`,
|
||||
`Operation`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, 2,
|
||||
0,
|
||||
),
|
||||
'width': GObject.ParamSpec.double(
|
||||
`width`,
|
||||
`Width`,
|
||||
`Width`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, Number.MAX_SAFE_INTEGER,
|
||||
0.0,
|
||||
),
|
||||
'height': GObject.ParamSpec.double(
|
||||
`height`,
|
||||
`Height`,
|
||||
`Height`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, Number.MAX_SAFE_INTEGER,
|
||||
0.0,
|
||||
)
|
||||
}
|
||||
}, class DerivativeEffect extends Clutter.ShaderEffect {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
|
||||
utils.setup_params(this, params);
|
||||
|
||||
// set shader source
|
||||
this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url);
|
||||
if (this._source)
|
||||
this.set_shader_source(this._source);
|
||||
}
|
||||
|
||||
static get default_params() {
|
||||
return DEFAULT_PARAMS;
|
||||
}
|
||||
|
||||
get operation() {
|
||||
return this._operation;
|
||||
}
|
||||
|
||||
set operation(value) {
|
||||
if (this._operation !== value) {
|
||||
this._operation = value;
|
||||
|
||||
this.set_uniform_value('operation', this._operation);
|
||||
}
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this._width;
|
||||
}
|
||||
|
||||
set width(value) {
|
||||
if (this._width !== value) {
|
||||
this._width = value;
|
||||
|
||||
this.set_uniform_value('width', parseFloat(this._width - 1e-6));
|
||||
}
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this._height;
|
||||
}
|
||||
|
||||
set height(value) {
|
||||
if (this._height !== value) {
|
||||
this._height = value;
|
||||
|
||||
this.set_uniform_value('height', parseFloat(this._height - 1e-6));
|
||||
}
|
||||
}
|
||||
|
||||
vfunc_set_actor(actor) {
|
||||
if (this._actor_connection_size_id) {
|
||||
let old_actor = this.get_actor();
|
||||
old_actor?.disconnect(this._actor_connection_size_id);
|
||||
}
|
||||
if (actor) {
|
||||
this.width = actor.width;
|
||||
this.height = actor.height;
|
||||
this._actor_connection_size_id = actor.connect('notify::size', _ => {
|
||||
this.width = actor.width;
|
||||
this.height = actor.height;
|
||||
});
|
||||
}
|
||||
else
|
||||
this._actor_connection_size_id = null;
|
||||
|
||||
super.vfunc_set_actor(actor);
|
||||
}
|
||||
|
||||
vfunc_paint_target(paint_node, paint_context) {
|
||||
// force setting nearest-neighbour texture filtering
|
||||
this.get_pipeline().set_layer_filters(0, 9728, 9728);
|
||||
|
||||
super.vfunc_paint_target(paint_node, paint_context);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,76 @@
|
||||
uniform sampler2D tex;
|
||||
uniform int divider;
|
||||
uniform float width;
|
||||
uniform float height;
|
||||
uniform int downsampling_mode;
|
||||
|
||||
#define CORRECTION 2.25
|
||||
#define SIZE_ADDITION 3
|
||||
|
||||
vec4 get_texture_at_position(vec2 position) {
|
||||
vec2 raw_position = position + vec2(CORRECTION, CORRECTION);
|
||||
vec2 raw_uv = raw_position / vec2(width + SIZE_ADDITION, height + SIZE_ADDITION);
|
||||
|
||||
return texture2D(tex, raw_uv);
|
||||
}
|
||||
|
||||
vec2 get_corrected_position() {
|
||||
vec2 raw_uv = cogl_tex_coord0_in.st;
|
||||
vec2 raw_position = raw_uv * vec2(width + SIZE_ADDITION, height + SIZE_ADDITION);
|
||||
return raw_position - vec2(CORRECTION, CORRECTION);
|
||||
}
|
||||
|
||||
void main() {
|
||||
ivec2 corrected_position = ivec2(get_corrected_position());
|
||||
vec2 multiplied_position = corrected_position * divider;
|
||||
|
||||
if (any(greaterThan(multiplied_position, vec2(width, height)))) {
|
||||
discard;
|
||||
}
|
||||
|
||||
// mode 0: boxcar downsampling
|
||||
if (downsampling_mode == 0) {
|
||||
|
||||
vec4 color = vec4(0.);
|
||||
int count = 0;
|
||||
for (int i = 0; i < divider; i++) {
|
||||
for (int j = 0; j < divider; j++) {
|
||||
vec2 lookup_position = multiplied_position + vec2(i, j);
|
||||
if (all(greaterThanEqual(lookup_position, vec2(0, 0))) &&
|
||||
all(lessThan(lookup_position, vec2(width, height)))) {
|
||||
color += get_texture_at_position(lookup_position);
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
cogl_color_out = color / count;
|
||||
|
||||
} else
|
||||
// mode 1: triangular downsampling
|
||||
if (downsampling_mode == 1) {
|
||||
|
||||
vec4 color = vec4(0.);
|
||||
int count = 0;
|
||||
int force = 1;
|
||||
for (int i = 0; i < divider; i++) {
|
||||
for (int j = 0; j < divider; j++) {
|
||||
vec2 lookup_position = multiplied_position + vec2(i, j);
|
||||
if (all(greaterThanEqual(lookup_position, vec2(0, 0))) &&
|
||||
all(lessThan(lookup_position, vec2(width, height)))) {
|
||||
force = 1 + divider - int(abs(divider - i - j));
|
||||
color += get_texture_at_position(lookup_position) * force;
|
||||
count += force;
|
||||
}
|
||||
}
|
||||
}
|
||||
cogl_color_out = color / count;
|
||||
|
||||
} else
|
||||
// mode 2: Dirac downsampling
|
||||
if (downsampling_mode == 2) {
|
||||
|
||||
vec2 lookup_position = min(multiplied_position + vec2(divider, divider) / 2, vec2(width - 1, height - 1));
|
||||
cogl_color_out = get_texture_at_position(lookup_position);
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,140 @@
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import * as utils from '../conveniences/utils.js';
|
||||
const Shell = await utils.import_in_shell_only('gi://Shell');
|
||||
const Clutter = await utils.import_in_shell_only('gi://Clutter');
|
||||
|
||||
const SHADER_FILENAME = 'downscale.glsl';
|
||||
const DEFAULT_PARAMS = {
|
||||
divider: 8, downsampling_mode: 0, width: 0, height: 0
|
||||
};
|
||||
|
||||
|
||||
export const DownscaleEffect = utils.IS_IN_PREFERENCES ?
|
||||
{ default_params: DEFAULT_PARAMS } :
|
||||
new GObject.registerClass({
|
||||
GTypeName: "DownscaleEffect",
|
||||
Properties: {
|
||||
'divider': GObject.ParamSpec.int(
|
||||
`divider`,
|
||||
`Divider`,
|
||||
`Divider`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, 64,
|
||||
8,
|
||||
),
|
||||
'downsampling_mode': GObject.ParamSpec.int(
|
||||
`downsampling_mode`,
|
||||
`Downsampling mode`,
|
||||
`Downsampling mode`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, 2,
|
||||
0,
|
||||
),
|
||||
'width': GObject.ParamSpec.double(
|
||||
`width`,
|
||||
`Width`,
|
||||
`Width`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, Number.MAX_SAFE_INTEGER,
|
||||
0.0,
|
||||
),
|
||||
'height': GObject.ParamSpec.double(
|
||||
`height`,
|
||||
`Height`,
|
||||
`Height`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, Number.MAX_SAFE_INTEGER,
|
||||
0.0,
|
||||
)
|
||||
}
|
||||
}, class DownscaleEffect extends Clutter.ShaderEffect {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
|
||||
utils.setup_params(this, params);
|
||||
|
||||
// set shader source
|
||||
this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url);
|
||||
if (this._source)
|
||||
this.set_shader_source(this._source);
|
||||
}
|
||||
|
||||
static get default_params() {
|
||||
return DEFAULT_PARAMS;
|
||||
}
|
||||
|
||||
get divider() {
|
||||
return this._divider;
|
||||
}
|
||||
|
||||
set divider(value) {
|
||||
if (this._divider !== value) {
|
||||
this._divider = value;
|
||||
|
||||
this.set_uniform_value('divider', this._divider);
|
||||
}
|
||||
}
|
||||
|
||||
get downsampling_mode() {
|
||||
return this._downsampling_mode;
|
||||
}
|
||||
|
||||
set downsampling_mode(value) {
|
||||
if (this._downsampling_mode !== value) {
|
||||
this._downsampling_mode = value;
|
||||
|
||||
this.set_uniform_value('downsampling_mode', this._downsampling_mode);
|
||||
}
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this._width;
|
||||
}
|
||||
|
||||
set width(value) {
|
||||
if (this._width !== value) {
|
||||
this._width = value;
|
||||
|
||||
this.set_uniform_value('width', parseFloat(this._width - 1e-6));
|
||||
}
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this._height;
|
||||
}
|
||||
|
||||
set height(value) {
|
||||
if (this._height !== value) {
|
||||
this._height = value;
|
||||
|
||||
this.set_uniform_value('height', parseFloat(this._height - 1e-6));
|
||||
}
|
||||
}
|
||||
|
||||
vfunc_set_actor(actor) {
|
||||
if (this._actor_connection_size_id) {
|
||||
let old_actor = this.get_actor();
|
||||
old_actor?.disconnect(this._actor_connection_size_id);
|
||||
}
|
||||
if (actor) {
|
||||
this.width = actor.width;
|
||||
this.height = actor.height;
|
||||
this._actor_connection_size_id = actor.connect('notify::size', _ => {
|
||||
this.width = actor.width;
|
||||
this.height = actor.height;
|
||||
});
|
||||
}
|
||||
else
|
||||
this._actor_connection_size_id = null;
|
||||
|
||||
super.vfunc_set_actor(actor);
|
||||
}
|
||||
|
||||
vfunc_paint_target(paint_node, paint_context) {
|
||||
// force setting nearest-neighbour texture filtering
|
||||
this.get_pipeline().set_layer_filters(0, 9728, 9728);
|
||||
|
||||
super.vfunc_paint_target(paint_node, paint_context);
|
||||
}
|
||||
});
|
||||
332
gnome/.local/share/gnome-shell/extensions/blur-my-shell@aunetx/effects/effects.js
vendored
Normal file
@ -0,0 +1,332 @@
|
||||
import { NativeDynamicBlurEffect } from '../effects/native_dynamic_gaussian_blur.js';
|
||||
import { NativeStaticBlurEffect } from '../effects/native_static_gaussian_blur.js';
|
||||
import { GaussianBlurEffect } from '../effects/gaussian_blur.js';
|
||||
import { MonteCarloBlurEffect } from '../effects/monte_carlo_blur.js';
|
||||
import { ColorEffect } from '../effects/color.js';
|
||||
import { NoiseEffect } from '../effects/noise.js';
|
||||
import { CornerEffect } from '../effects/corner.js';
|
||||
import { DownscaleEffect } from './downscale.js';
|
||||
import { UpscaleEffect } from './upscale.js';
|
||||
import { PixelizeEffect } from './pixelize.js';
|
||||
import { DerivativeEffect } from './derivative.js';
|
||||
import { RgbToHslEffect } from './rgb_to_hsl.js';
|
||||
import { HslToRgbEffect } from './hsl_to_rgb.js';
|
||||
|
||||
// We do in this way because I've not found another way to store our preferences in a dictionnary
|
||||
// while calling `gettext` on it while in preferences. Not so pretty, but works.
|
||||
export function get_effects_groups(_ = _ => "") {
|
||||
return {
|
||||
blur_effects: {
|
||||
name: _("Blur effects"),
|
||||
contains: [
|
||||
"native_static_gaussian_blur",
|
||||
"gaussian_blur",
|
||||
"monte_carlo_blur"
|
||||
]
|
||||
},
|
||||
texture_effects: {
|
||||
name: _("Texture effects"),
|
||||
contains: [
|
||||
"downscale",
|
||||
"upscale",
|
||||
"pixelize",
|
||||
"derivative",
|
||||
"noise",
|
||||
"color",
|
||||
"rgb_to_hsl",
|
||||
"hsl_to_rgb"
|
||||
]
|
||||
},
|
||||
shape_effects: {
|
||||
name: _("Shape effects"),
|
||||
contains: [
|
||||
"corner"
|
||||
]
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export function get_supported_effects(_ = () => "") {
|
||||
return {
|
||||
native_dynamic_gaussian_blur: {
|
||||
class: NativeDynamicBlurEffect
|
||||
},
|
||||
|
||||
native_static_gaussian_blur: {
|
||||
class: NativeStaticBlurEffect,
|
||||
name: _("Native gaussian blur"),
|
||||
description: _("An optimized blur effect that smoothly blends pixels within a given radius."),
|
||||
is_advanced: false,
|
||||
editable_params: {
|
||||
unscaled_radius: {
|
||||
name: _("Radius"),
|
||||
description: _("The intensity of the blur effect."),
|
||||
type: "float",
|
||||
min: 0.,
|
||||
max: 100.,
|
||||
increment: 1.0,
|
||||
big_increment: 10.,
|
||||
digits: 0
|
||||
},
|
||||
brightness: {
|
||||
name: _("Brightness"),
|
||||
description: _("The brightness of the blur effect, a high value might make the text harder to read."),
|
||||
type: "float",
|
||||
min: 0.,
|
||||
max: 1.,
|
||||
increment: 0.01,
|
||||
big_increment: 0.1,
|
||||
digits: 2
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
gaussian_blur: {
|
||||
class: GaussianBlurEffect,
|
||||
name: _("Gaussian blur (advanced effect)"),
|
||||
description: _("A blur effect that smoothly blends pixels within a given radius. This effect is more precise, but way less optimized."),
|
||||
is_advanced: true,
|
||||
editable_params: {
|
||||
radius: {
|
||||
name: _("Radius"),
|
||||
description: _("The intensity of the blur effect. The bigger it is, the slower it will be."),
|
||||
type: "float",
|
||||
min: 0.,
|
||||
max: 100.,
|
||||
increment: .1,
|
||||
big_increment: 10.,
|
||||
digits: 1
|
||||
},
|
||||
brightness: {
|
||||
name: _("Brightness"),
|
||||
description: _("The brightness of the blur effect, a high value might make the text harder to read."),
|
||||
type: "float",
|
||||
min: 0.,
|
||||
max: 1.,
|
||||
increment: 0.01,
|
||||
big_increment: 0.1,
|
||||
digits: 2
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
monte_carlo_blur: {
|
||||
class: MonteCarloBlurEffect,
|
||||
name: _("Monte Carlo blur"),
|
||||
description: _("A blur effect that mimics a random walk, by picking pixels further and further away from its origin and mixing them all together."),
|
||||
is_advanced: false,
|
||||
editable_params: {
|
||||
radius: {
|
||||
name: _("Radius"),
|
||||
description: _("The maximum travel distance for each step in the random walk. A higher value will make the blur more randomized."),
|
||||
type: "float",
|
||||
min: 0.,
|
||||
max: 10.,
|
||||
increment: 0.01,
|
||||
big_increment: 0.1,
|
||||
digits: 2
|
||||
},
|
||||
iterations: {
|
||||
name: _("Iterations"),
|
||||
description: _("The number of iterations. The more there are, the smoother the blur is."),
|
||||
type: "integer",
|
||||
min: 0,
|
||||
max: 50,
|
||||
increment: 1
|
||||
},
|
||||
brightness: {
|
||||
name: _("Brightness"),
|
||||
description: _("The brightness of the blur effect, a high value might make the text harder to read."),
|
||||
type: "float",
|
||||
min: 0.,
|
||||
max: 1.,
|
||||
increment: 0.01,
|
||||
big_increment: 0.1,
|
||||
digits: 2
|
||||
},
|
||||
use_base_pixel: {
|
||||
name: _("Use base pixel"),
|
||||
description: _("Whether or not the original pixel is counted for the blur. If it is, the image will be more legible."),
|
||||
type: "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
color: {
|
||||
class: ColorEffect,
|
||||
name: _("Color"),
|
||||
description: _("An effect that blends a color into the pipeline."),
|
||||
is_advanced: false,
|
||||
// TODO make this RGB + blend
|
||||
editable_params: {
|
||||
color: {
|
||||
name: _("Color"),
|
||||
description: _("The color to blend in. The blending amount is controled by the opacity of the color."),
|
||||
type: "rgba"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
pixelize: {
|
||||
class: PixelizeEffect,
|
||||
name: _("Pixelize"),
|
||||
description: _("An effect that pixelizes the image."),
|
||||
is_advanced: false,
|
||||
editable_params: {
|
||||
factor: {
|
||||
name: _("Factor"),
|
||||
description: _("How much to scale down the image."),
|
||||
type: "integer",
|
||||
min: 1,
|
||||
max: 50,
|
||||
increment: 1
|
||||
},
|
||||
downsampling_mode: {
|
||||
name: _("Downsampling mode"),
|
||||
description: _("The downsampling method that is used."),
|
||||
type: "dropdown",
|
||||
options: [
|
||||
_("Boxcar"),
|
||||
_("Triangular"),
|
||||
_("Dirac")
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
downscale: {
|
||||
class: DownscaleEffect,
|
||||
name: _("Downscale (advanced effect)"),
|
||||
description: _("An effect that downscales the image and put it on the top-left corner."),
|
||||
is_advanced: true,
|
||||
editable_params: {
|
||||
divider: {
|
||||
name: _("Factor"),
|
||||
description: _("How much to scale down the image."),
|
||||
type: "integer",
|
||||
min: 1,
|
||||
max: 50,
|
||||
increment: 1
|
||||
},
|
||||
downsampling_mode: {
|
||||
name: _("Downsampling mode"),
|
||||
description: _("The downsampling method that is used."),
|
||||
type: "dropdown",
|
||||
options: [
|
||||
_("Boxcar"),
|
||||
_("Triangular"),
|
||||
_("Dirac")
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
upscale: {
|
||||
class: UpscaleEffect,
|
||||
name: _("Upscale (advanced effect)"),
|
||||
description: _("An effect that upscales the image from the top-left corner."),
|
||||
is_advanced: true,
|
||||
editable_params: {
|
||||
factor: {
|
||||
name: _("Factor"),
|
||||
description: _("How much to scale up the image."),
|
||||
type: "integer",
|
||||
min: 1,
|
||||
max: 50,
|
||||
increment: 1
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
derivative: {
|
||||
class: DerivativeEffect,
|
||||
name: _("Derivative"),
|
||||
description: _("Apply a spatial derivative, or a laplacian."),
|
||||
is_advanced: false,
|
||||
editable_params: {
|
||||
operation: {
|
||||
name: _("Operation"),
|
||||
description: _("The mathematical operation to apply."),
|
||||
type: "dropdown",
|
||||
options: [
|
||||
_("1-step derivative"),
|
||||
_("2-step derivative"),
|
||||
_("Laplacian")
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
noise: {
|
||||
class: NoiseEffect,
|
||||
name: _("Noise"),
|
||||
description: _("An effect that adds a random noise. Prefer the Monte Carlo blur for a more organic effect if needed."),
|
||||
is_advanced: false,
|
||||
editable_params: {
|
||||
noise: {
|
||||
name: _("Noise"),
|
||||
description: _("The amount of noise to add."),
|
||||
type: "float",
|
||||
min: 0.,
|
||||
max: 1.,
|
||||
increment: 0.01,
|
||||
big_increment: 0.1,
|
||||
digits: 2
|
||||
},
|
||||
lightness: {
|
||||
name: _("Lightness"),
|
||||
description: _("The luminosity of the noise. A setting of '1.0' will make the effect transparent."),
|
||||
type: "float",
|
||||
min: 0.,
|
||||
max: 2.,
|
||||
increment: 0.01,
|
||||
big_increment: 0.1,
|
||||
digits: 2
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
rgb_to_hsl: {
|
||||
class: RgbToHslEffect,
|
||||
name: _("RGB to HSL (advanced effect)"),
|
||||
description: _("Converts the image from RGBA colorspace to HSLA."),
|
||||
is_advanced: true,
|
||||
editable_params: {}
|
||||
},
|
||||
|
||||
hsl_to_rgb: {
|
||||
class: HslToRgbEffect,
|
||||
name: _("HSL to RGB (advanced effect)"),
|
||||
description: _("Converts the image from HSLA colorspace to RGBA."),
|
||||
is_advanced: true,
|
||||
editable_params: {}
|
||||
},
|
||||
|
||||
corner: {
|
||||
class: CornerEffect,
|
||||
name: _("Corner"),
|
||||
description: _("An effect that draws corners. Add it last not to have the other effects perturb the corners."),
|
||||
is_advanced: false,
|
||||
editable_params: {
|
||||
radius: {
|
||||
name: _("Radius"),
|
||||
description: _("The radius of the corner. GNOME apps use a radius of 12 px by default."),
|
||||
type: "integer",
|
||||
min: 0,
|
||||
max: 50,
|
||||
increment: 1,
|
||||
},
|
||||
corners_top: {
|
||||
name: _("Top corners"),
|
||||
description: _("Whether or not to round the top corners."),
|
||||
type: "boolean"
|
||||
},
|
||||
corners_bottom: {
|
||||
name: _("Bottom corners"),
|
||||
description: _("Whether or not to round the bottom corners."),
|
||||
type: "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,70 @@
|
||||
uniform sampler2D tex;
|
||||
uniform float sigma;
|
||||
uniform int dir;
|
||||
uniform float brightness;
|
||||
uniform float width;
|
||||
uniform float height;
|
||||
|
||||
vec4 getTexture(vec2 uv) {
|
||||
if (uv.x < 3. / width)
|
||||
uv.x = 3. / width;
|
||||
|
||||
if (uv.y < 3. / height)
|
||||
uv.y = 3. / height;
|
||||
|
||||
if (uv.x > 1. - 3. / width)
|
||||
uv.x = 1. - 3. / width;
|
||||
|
||||
if (uv.y > 1. - 3. / height)
|
||||
uv.y = 1. - 3. / height;
|
||||
|
||||
return texture2D(tex, uv);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
vec2 uv = cogl_tex_coord_in[0].xy;
|
||||
vec2 direction = vec2(dir, (1.0 - dir));
|
||||
|
||||
float pixel_step;
|
||||
if (dir == 0)
|
||||
pixel_step = 1.0 / height;
|
||||
else
|
||||
pixel_step = 1.0 / width;
|
||||
|
||||
vec3 gauss_coefficient;
|
||||
gauss_coefficient.x = 1.0 / (sqrt(2.0 * 3.14159265) * sigma);
|
||||
gauss_coefficient.y = exp(-0.5 / (sigma * sigma));
|
||||
gauss_coefficient.z = gauss_coefficient.y * gauss_coefficient.y;
|
||||
|
||||
float gauss_coefficient_total = gauss_coefficient.x;
|
||||
|
||||
vec4 ret = getTexture(uv) * gauss_coefficient.x;
|
||||
gauss_coefficient.xy *= gauss_coefficient.yz;
|
||||
|
||||
int n_steps = int(ceil(1.5 * sigma)) * 2;
|
||||
|
||||
for (int i = 1; i <= n_steps; i += 2) {
|
||||
float coefficient_subtotal = gauss_coefficient.x;
|
||||
gauss_coefficient.xy *= gauss_coefficient.yz;
|
||||
coefficient_subtotal += gauss_coefficient.x;
|
||||
|
||||
float gauss_ratio = gauss_coefficient.x / coefficient_subtotal;
|
||||
|
||||
float foffset = float(i) + gauss_ratio;
|
||||
vec2 offset = direction * foffset * pixel_step;
|
||||
|
||||
ret += getTexture(uv + offset) * coefficient_subtotal;
|
||||
ret += getTexture(uv - offset) * coefficient_subtotal;
|
||||
|
||||
gauss_coefficient_total += 2.0 * coefficient_subtotal;
|
||||
gauss_coefficient.xy *= gauss_coefficient.yz;
|
||||
}
|
||||
vec4 outColor = ret / gauss_coefficient_total;
|
||||
|
||||
// apply brightness on the second pass (dir==0 comes last)
|
||||
if (dir == 0) {
|
||||
outColor.rgb *= brightness;
|
||||
}
|
||||
|
||||
cogl_color_out = outColor;
|
||||
}
|
||||
@ -0,0 +1,213 @@
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import * as utils from '../conveniences/utils.js';
|
||||
const St = await utils.import_in_shell_only('gi://St');
|
||||
const Shell = await utils.import_in_shell_only('gi://Shell');
|
||||
const Clutter = await utils.import_in_shell_only('gi://Clutter');
|
||||
|
||||
const SHADER_FILENAME = 'gaussian_blur.glsl';
|
||||
const DEFAULT_PARAMS = {
|
||||
radius: 30, brightness: .6,
|
||||
width: 0, height: 0, direction: 0, chained_effect: null
|
||||
};
|
||||
|
||||
|
||||
export const GaussianBlurEffect = utils.IS_IN_PREFERENCES ?
|
||||
{ default_params: DEFAULT_PARAMS } :
|
||||
new GObject.registerClass({
|
||||
GTypeName: "GaussianBlurEffect",
|
||||
Properties: {
|
||||
'radius': GObject.ParamSpec.double(
|
||||
`radius`,
|
||||
`Radius`,
|
||||
`Blur radius`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, 2000.0,
|
||||
30.0,
|
||||
),
|
||||
'brightness': GObject.ParamSpec.double(
|
||||
`brightness`,
|
||||
`Brightness`,
|
||||
`Blur brightness`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, 1.0,
|
||||
0.6,
|
||||
),
|
||||
'width': GObject.ParamSpec.double(
|
||||
`width`,
|
||||
`Width`,
|
||||
`Width`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, Number.MAX_SAFE_INTEGER,
|
||||
0.0,
|
||||
),
|
||||
'height': GObject.ParamSpec.double(
|
||||
`height`,
|
||||
`Height`,
|
||||
`Height`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, Number.MAX_SAFE_INTEGER,
|
||||
0.0,
|
||||
),
|
||||
'direction': GObject.ParamSpec.int(
|
||||
`direction`,
|
||||
`Direction`,
|
||||
`Direction`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, 1,
|
||||
0,
|
||||
),
|
||||
'chained_effect': GObject.ParamSpec.object(
|
||||
`chained_effect`,
|
||||
`Chained Effect`,
|
||||
`Chained Effect`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
GObject.Object,
|
||||
),
|
||||
}
|
||||
}, class GaussianBlurEffect extends Clutter.ShaderEffect {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
|
||||
utils.setup_params(this, params);
|
||||
|
||||
// set shader source
|
||||
this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url);
|
||||
if (this._source)
|
||||
this.set_shader_source(this._source);
|
||||
|
||||
const theme_context = St.ThemeContext.get_for_stage(global.stage);
|
||||
theme_context.connectObject(
|
||||
'notify::scale-factor', _ =>
|
||||
this.set_uniform_value('sigma',
|
||||
parseFloat(this.radius * theme_context.scale_factor / 2 - 1e-6)
|
||||
),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
static get default_params() {
|
||||
return DEFAULT_PARAMS;
|
||||
}
|
||||
|
||||
get radius() {
|
||||
return this._radius;
|
||||
}
|
||||
|
||||
set radius(value) {
|
||||
if (this._radius !== value) {
|
||||
this._radius = value;
|
||||
|
||||
const scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
|
||||
// like Clutter, we use the assumption radius = 2*sigma
|
||||
this.set_uniform_value('sigma', parseFloat(this._radius * scale_factor / 2 - 1e-6));
|
||||
this.set_enabled(this.radius > 0.);
|
||||
|
||||
if (this.chained_effect)
|
||||
this.chained_effect.radius = value;
|
||||
}
|
||||
}
|
||||
|
||||
get brightness() {
|
||||
return this._brightness;
|
||||
}
|
||||
|
||||
set brightness(value) {
|
||||
if (this._brightness !== value) {
|
||||
this._brightness = value;
|
||||
|
||||
this.set_uniform_value('brightness', parseFloat(this._brightness - 1e-6));
|
||||
|
||||
if (this.chained_effect)
|
||||
this.chained_effect.brightness = value;
|
||||
}
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this._width;
|
||||
}
|
||||
|
||||
set width(value) {
|
||||
if (this._width !== value) {
|
||||
this._width = value;
|
||||
|
||||
this.set_uniform_value('width', parseFloat(this._width + 3.0 - 1e-6));
|
||||
|
||||
if (this.chained_effect)
|
||||
this.chained_effect.width = value;
|
||||
}
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this._height;
|
||||
}
|
||||
|
||||
set height(value) {
|
||||
if (this._height !== value) {
|
||||
this._height = value;
|
||||
|
||||
this.set_uniform_value('height', parseFloat(this._height + 3.0 - 1e-6));
|
||||
|
||||
if (this.chained_effect)
|
||||
this.chained_effect.height = value;
|
||||
}
|
||||
}
|
||||
|
||||
get direction() {
|
||||
return this._direction;
|
||||
}
|
||||
|
||||
set direction(value) {
|
||||
if (this._direction !== value)
|
||||
this._direction = value;
|
||||
}
|
||||
|
||||
get chained_effect() {
|
||||
return this._chained_effect;
|
||||
}
|
||||
|
||||
set chained_effect(value) {
|
||||
this._chained_effect = value;
|
||||
}
|
||||
|
||||
vfunc_set_actor(actor) {
|
||||
if (this._actor_connection_size_id) {
|
||||
let old_actor = this.get_actor();
|
||||
old_actor?.disconnect(this._actor_connection_size_id);
|
||||
}
|
||||
if (actor) {
|
||||
this.width = actor.width;
|
||||
this.height = actor.height;
|
||||
this._actor_connection_size_id = actor.connect('notify::size', _ => {
|
||||
this.width = actor.width;
|
||||
this.height = actor.height;
|
||||
});
|
||||
}
|
||||
else
|
||||
this._actor_connection_size_id = null;
|
||||
|
||||
super.vfunc_set_actor(actor);
|
||||
|
||||
if (this.direction == 0) {
|
||||
if (this.chained_effect)
|
||||
this.chained_effect.get_actor()?.remove_effect(this.chained_effect);
|
||||
else
|
||||
this.chained_effect = new GaussianBlurEffect({
|
||||
radius: this.radius,
|
||||
brightness: this.brightness,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
direction: 1
|
||||
});
|
||||
if (actor !== null)
|
||||
actor.add_effect(this.chained_effect);
|
||||
}
|
||||
}
|
||||
|
||||
vfunc_paint_target(paint_node, paint_context) {
|
||||
this.set_uniform_value("dir", this.direction);
|
||||
|
||||
super.vfunc_paint_target(paint_node, paint_context);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,14 @@
|
||||
uniform sampler2D tex;
|
||||
|
||||
vec3 hsl_to_rgb(vec3 c) {
|
||||
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
vec2 uv = cogl_tex_coord_in[0].xy;
|
||||
vec4 hsla = texture2D(tex, uv);
|
||||
vec4 rgba = vec4(hsl_to_rgb(hsla.xyz), hsla.w);
|
||||
cogl_color_out = rgba;
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import * as utils from '../conveniences/utils.js';
|
||||
const Shell = await utils.import_in_shell_only('gi://Shell');
|
||||
const Clutter = await utils.import_in_shell_only('gi://Clutter');
|
||||
|
||||
const SHADER_FILENAME = 'hsl_to_rgb.glsl';
|
||||
const DEFAULT_PARAMS = {};
|
||||
|
||||
|
||||
export const HslToRgbEffect = utils.IS_IN_PREFERENCES ?
|
||||
{ default_params: DEFAULT_PARAMS } :
|
||||
new GObject.registerClass({
|
||||
GTypeName: "HslToRgbEffect",
|
||||
Properties: {}
|
||||
}, class HslToRgbEffect extends Clutter.ShaderEffect {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
|
||||
utils.setup_params(this, params);
|
||||
|
||||
// set shader source
|
||||
this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url);
|
||||
if (this._source)
|
||||
this.set_shader_source(this._source);
|
||||
}
|
||||
|
||||
static get default_params() {
|
||||
return DEFAULT_PARAMS;
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,44 @@
|
||||
uniform sampler2D tex;
|
||||
uniform float radius;
|
||||
uniform int iterations;
|
||||
uniform float brightness;
|
||||
uniform float width;
|
||||
uniform float height;
|
||||
uniform bool use_base_pixel;
|
||||
|
||||
float srand(vec2 a) {
|
||||
return sin(dot(a, vec2(1233.224, 1743.335)));
|
||||
}
|
||||
|
||||
float rand(inout float r) {
|
||||
r = fract(3712.65 * r + 0.61432);
|
||||
return (r - 0.5) * 2.0;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 uv = cogl_tex_coord0_in.st;
|
||||
vec2 p = 16 * radius / vec2(width, height);
|
||||
float r = srand(uv);
|
||||
vec2 rv;
|
||||
|
||||
int count = 0;
|
||||
vec4 c = vec4(0.);
|
||||
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
rv.x = rand(r);
|
||||
rv.y = rand(r);
|
||||
vec2 new_uv = uv + rv * p;
|
||||
if (new_uv.x > 2. / width && new_uv.y > 2. / height && new_uv.x < 1. - 3. / width && new_uv.y < 1. - 3. / height) {
|
||||
c += texture2D(tex, new_uv);
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0 || use_base_pixel) {
|
||||
c += texture2D(tex, uv);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
c.xyz *= brightness;
|
||||
cogl_color_out = c / count;
|
||||
}
|
||||
@ -0,0 +1,187 @@
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import * as utils from '../conveniences/utils.js';
|
||||
const St = await utils.import_in_shell_only('gi://St');
|
||||
const Shell = await utils.import_in_shell_only('gi://Shell');
|
||||
const Clutter = await utils.import_in_shell_only('gi://Clutter');
|
||||
|
||||
const SHADER_FILENAME = 'monte_carlo_blur.glsl';
|
||||
const DEFAULT_PARAMS = {
|
||||
radius: 2., iterations: 5, brightness: .6,
|
||||
width: 0, height: 0, use_base_pixel: true
|
||||
};
|
||||
|
||||
|
||||
export const MonteCarloBlurEffect = utils.IS_IN_PREFERENCES ?
|
||||
{ default_params: DEFAULT_PARAMS } :
|
||||
new GObject.registerClass({
|
||||
GTypeName: "MonteCarloBlurEffect",
|
||||
Properties: {
|
||||
'radius': GObject.ParamSpec.double(
|
||||
`radius`,
|
||||
`Radius`,
|
||||
`Blur radius`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, 2000.0,
|
||||
2.0,
|
||||
),
|
||||
'iterations': GObject.ParamSpec.int(
|
||||
`iterations`,
|
||||
`Iterations`,
|
||||
`Blur iterations`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, 64,
|
||||
5,
|
||||
),
|
||||
'brightness': GObject.ParamSpec.double(
|
||||
`brightness`,
|
||||
`Brightness`,
|
||||
`Blur brightness`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, 1.0,
|
||||
0.6,
|
||||
),
|
||||
'width': GObject.ParamSpec.double(
|
||||
`width`,
|
||||
`Width`,
|
||||
`Width`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, Number.MAX_SAFE_INTEGER,
|
||||
0.0,
|
||||
),
|
||||
'height': GObject.ParamSpec.double(
|
||||
`height`,
|
||||
`Height`,
|
||||
`Height`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, Number.MAX_SAFE_INTEGER,
|
||||
0.0,
|
||||
),
|
||||
'use_base_pixel': GObject.ParamSpec.boolean(
|
||||
`use_base_pixel`,
|
||||
`Use base pixel`,
|
||||
`Use base pixel`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
true,
|
||||
),
|
||||
}
|
||||
}, class MonteCarloBlurEffect extends Clutter.ShaderEffect {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
|
||||
utils.setup_params(this, params);
|
||||
|
||||
// set shader source
|
||||
this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url);
|
||||
if (this._source)
|
||||
this.set_shader_source(this._source);
|
||||
|
||||
const theme_context = St.ThemeContext.get_for_stage(global.stage);
|
||||
theme_context.connectObject(
|
||||
'notify::scale-factor',
|
||||
_ => this.set_uniform_value('radius',
|
||||
parseFloat(this._radius * theme_context.scale_factor - 1e-6)
|
||||
),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
static get default_params() {
|
||||
return DEFAULT_PARAMS;
|
||||
}
|
||||
|
||||
get radius() {
|
||||
return this._radius;
|
||||
}
|
||||
|
||||
set radius(value) {
|
||||
if (this._radius !== value) {
|
||||
this._radius = value;
|
||||
|
||||
const scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
|
||||
this.set_uniform_value('radius', parseFloat(this._radius * scale_factor - 1e-6));
|
||||
this.set_enabled(this.radius > 0. && this.iterations > 0);
|
||||
}
|
||||
}
|
||||
|
||||
get iterations() {
|
||||
return this._iterations;
|
||||
}
|
||||
|
||||
set iterations(value) {
|
||||
if (this._iterations !== value) {
|
||||
this._iterations = value;
|
||||
|
||||
this.set_uniform_value('iterations', this._iterations);
|
||||
this.set_enabled(this.radius > 0. && this.iterations > 0);
|
||||
}
|
||||
}
|
||||
|
||||
get brightness() {
|
||||
return this._brightness;
|
||||
}
|
||||
|
||||
set brightness(value) {
|
||||
if (this._brightness !== value) {
|
||||
this._brightness = value;
|
||||
|
||||
this.set_uniform_value('brightness', parseFloat(this._brightness - 1e-6));
|
||||
}
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this._width;
|
||||
}
|
||||
|
||||
set width(value) {
|
||||
if (this._width !== value) {
|
||||
this._width = value;
|
||||
|
||||
this.set_uniform_value('width', parseFloat(this._width + 3.0 - 1e-6));
|
||||
}
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this._height;
|
||||
}
|
||||
|
||||
set height(value) {
|
||||
if (this._height !== value) {
|
||||
this._height = value;
|
||||
|
||||
this.set_uniform_value('height', parseFloat(this._height + 3.0 - 1e-6));
|
||||
}
|
||||
}
|
||||
|
||||
get use_base_pixel() {
|
||||
return this._use_base_pixel;
|
||||
}
|
||||
|
||||
set use_base_pixel(value) {
|
||||
if (this._use_base_pixel !== value) {
|
||||
this._use_base_pixel = value;
|
||||
|
||||
this.set_uniform_value('use_base_pixel', this._use_base_pixel ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
vfunc_set_actor(actor) {
|
||||
if (this._actor_connection_size_id) {
|
||||
let old_actor = this.get_actor();
|
||||
old_actor?.disconnect(this._actor_connection_size_id);
|
||||
}
|
||||
if (actor) {
|
||||
this.width = actor.width;
|
||||
this.height = actor.height;
|
||||
this._actor_connection_size_id = actor.connect('notify::size', _ => {
|
||||
this.width = actor.width;
|
||||
this.height = actor.height;
|
||||
});
|
||||
}
|
||||
else
|
||||
this._actor_connection_size_id = null;
|
||||
|
||||
super.vfunc_set_actor(actor);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,43 @@
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import * as utils from '../conveniences/utils.js';
|
||||
const St = await utils.import_in_shell_only('gi://St');
|
||||
const Shell = await utils.import_in_shell_only('gi://Shell');
|
||||
|
||||
const DEFAULT_PARAMS = {
|
||||
unscaled_radius: 30, brightness: 0.6
|
||||
};
|
||||
|
||||
|
||||
export const NativeDynamicBlurEffect = utils.IS_IN_PREFERENCES ?
|
||||
{ default_params: DEFAULT_PARAMS } :
|
||||
new GObject.registerClass({
|
||||
GTypeName: "NativeDynamicBlurEffect"
|
||||
}, class NativeDynamicBlurEffect extends Shell.BlurEffect {
|
||||
constructor(params) {
|
||||
const { unscaled_radius, brightness, ...parent_params } = params;
|
||||
super({ ...parent_params, mode: Shell.BlurMode.BACKGROUND });
|
||||
|
||||
this._theme_context = St.ThemeContext.get_for_stage(global.stage);
|
||||
this._theme_context.connectObject(
|
||||
'notify::scale-factor',
|
||||
_ => this.radius = this.unscaled_radius * this._theme_context.scale_factor,
|
||||
this
|
||||
);
|
||||
|
||||
utils.setup_params(this, params);
|
||||
}
|
||||
|
||||
static get default_params() {
|
||||
return DEFAULT_PARAMS;
|
||||
}
|
||||
|
||||
get unscaled_radius() {
|
||||
return this._unscaled_radius;
|
||||
}
|
||||
|
||||
set unscaled_radius(value) {
|
||||
this._unscaled_radius = value;
|
||||
this.radius = value * this._theme_context.scale_factor;
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,43 @@
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import * as utils from '../conveniences/utils.js';
|
||||
const St = await utils.import_in_shell_only('gi://St');
|
||||
const Shell = await utils.import_in_shell_only('gi://Shell');
|
||||
|
||||
const DEFAULT_PARAMS = {
|
||||
unscaled_radius: 30, brightness: 0.6
|
||||
};
|
||||
|
||||
|
||||
export const NativeStaticBlurEffect = utils.IS_IN_PREFERENCES ?
|
||||
{ default_params: DEFAULT_PARAMS } :
|
||||
new GObject.registerClass({
|
||||
GTypeName: "NativeStaticBlurEffect"
|
||||
}, class NativeStaticBlurEffect extends Shell.BlurEffect {
|
||||
constructor(params) {
|
||||
const { unscaled_radius, brightness, ...parent_params } = params;
|
||||
super({ ...parent_params, mode: Shell.BlurMode.ACTOR });
|
||||
|
||||
this._theme_context = St.ThemeContext.get_for_stage(global.stage);
|
||||
this._theme_context.connectObject(
|
||||
'notify::scale-factor',
|
||||
_ => this.radius = this.unscaled_radius * this._theme_context.scale_factor,
|
||||
this
|
||||
);
|
||||
|
||||
utils.setup_params(this, params);
|
||||
}
|
||||
|
||||
static get default_params() {
|
||||
return DEFAULT_PARAMS;
|
||||
}
|
||||
|
||||
get unscaled_radius() {
|
||||
return this._unscaled_radius;
|
||||
}
|
||||
|
||||
set unscaled_radius(value) {
|
||||
this._unscaled_radius = value;
|
||||
this.radius = value * this._theme_context.scale_factor;
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,76 @@
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import * as utils from '../conveniences/utils.js';
|
||||
const Shell = await utils.import_in_shell_only('gi://Shell');
|
||||
const Clutter = await utils.import_in_shell_only('gi://Clutter');
|
||||
|
||||
const SHADER_FILENAME = 'noise.glsl';
|
||||
const DEFAULT_PARAMS = {
|
||||
noise: 0.4, lightness: 0.4
|
||||
};
|
||||
|
||||
|
||||
export const NoiseEffect = utils.IS_IN_PREFERENCES ?
|
||||
{ default_params: DEFAULT_PARAMS } :
|
||||
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 NoiseEffect extends Clutter.ShaderEffect {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
|
||||
utils.setup_params(this, params);
|
||||
|
||||
// set shader source
|
||||
this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url);
|
||||
if (this._source)
|
||||
this.set_shader_source(this._source);
|
||||
}
|
||||
|
||||
static get default_params() {
|
||||
return DEFAULT_PARAMS;
|
||||
}
|
||||
|
||||
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.set_enabled(this.noise > 0. && this.lightness != 1);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
this.set_enabled(this.noise > 0. && this.lightness != 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,109 +0,0 @@
|
||||
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();
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,88 @@
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import * as utils from '../conveniences/utils.js';
|
||||
const Clutter = await utils.import_in_shell_only('gi://Clutter');
|
||||
|
||||
import { UpscaleEffect } from './upscale.js';
|
||||
import { DownscaleEffect } from './downscale.js';
|
||||
|
||||
const DEFAULT_PARAMS = {
|
||||
factor: 8, downsampling_mode: 0
|
||||
};
|
||||
|
||||
|
||||
export const PixelizeEffect = utils.IS_IN_PREFERENCES ?
|
||||
{ default_params: DEFAULT_PARAMS } :
|
||||
new GObject.registerClass({
|
||||
GTypeName: "PixelizeEffect",
|
||||
Properties: {
|
||||
'factor': GObject.ParamSpec.int(
|
||||
`factor`,
|
||||
`Factor`,
|
||||
`Factor`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, 64,
|
||||
8,
|
||||
),
|
||||
'downsampling_mode': GObject.ParamSpec.int(
|
||||
`downsampling_mode`,
|
||||
`Downsampling mode`,
|
||||
`Downsampling mode`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, 2,
|
||||
0,
|
||||
)
|
||||
}
|
||||
}, class PixelizeEffect extends Clutter.Effect {
|
||||
constructor(params) {
|
||||
super();
|
||||
|
||||
this.upscale_effect = new UpscaleEffect({});
|
||||
this.downscale_effect = new DownscaleEffect({});
|
||||
|
||||
utils.setup_params(this, params);
|
||||
}
|
||||
|
||||
static get default_params() {
|
||||
return DEFAULT_PARAMS;
|
||||
}
|
||||
|
||||
get factor() {
|
||||
// should be the same as `this.downscale_effect.divider`
|
||||
return this.upscale_effect.factor;
|
||||
}
|
||||
|
||||
set factor(value) {
|
||||
this.upscale_effect.factor = value;
|
||||
this.downscale_effect.divider = value;
|
||||
}
|
||||
|
||||
get downsampling_mode() {
|
||||
return this.downscale_effect.downsampling_mode;
|
||||
}
|
||||
|
||||
set downsampling_mode(value) {
|
||||
this.downscale_effect.downsampling_mode = value;
|
||||
}
|
||||
|
||||
vfunc_set_actor(actor) {
|
||||
// deattach effects from old actor
|
||||
this.upscale_effect?.actor?.remove_effect(this.upscale_effect);
|
||||
this.downscale_effect?.actor?.remove_effect(this.downscale_effect);
|
||||
// attach effects to new actor
|
||||
if (actor) {
|
||||
if (this.upscale_effect)
|
||||
actor.add_effect(this.upscale_effect);
|
||||
if (this.downscale_effect)
|
||||
actor.add_effect(this.downscale_effect);
|
||||
}
|
||||
|
||||
super.vfunc_set_actor(actor);
|
||||
}
|
||||
|
||||
vfunc_set_enabled(is_enabled) {
|
||||
this.upscale_effect?.set_enabled(is_enabled);
|
||||
this.downscale_effect?.set_enabled(is_enabled);
|
||||
super.vfunc_set_enabled(is_enabled);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,18 @@
|
||||
uniform sampler2D tex;
|
||||
|
||||
vec3 rgb_to_hsl(vec3 c) {
|
||||
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
||||
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
|
||||
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
|
||||
|
||||
float d = q.x - min(q.w, q.y);
|
||||
float e = 1.0e-10;
|
||||
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
vec2 uv = cogl_tex_coord_in[0].xy;
|
||||
vec4 rgba = texture2D(tex, uv);
|
||||
vec4 hsla = vec4(rgb_to_hsl(rgba.xyz), rgba.w);
|
||||
cogl_color_out = hsla;
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import * as utils from '../conveniences/utils.js';
|
||||
const Shell = await utils.import_in_shell_only('gi://Shell');
|
||||
const Clutter = await utils.import_in_shell_only('gi://Clutter');
|
||||
|
||||
const SHADER_FILENAME = 'rgb_to_hsl.glsl';
|
||||
const DEFAULT_PARAMS = {};
|
||||
|
||||
|
||||
export const RgbToHslEffect = utils.IS_IN_PREFERENCES ?
|
||||
{ default_params: DEFAULT_PARAMS } :
|
||||
new GObject.registerClass({
|
||||
GTypeName: "RgbToHslEffect",
|
||||
Properties: {}
|
||||
}, class RgbToHslEffect extends Clutter.ShaderEffect {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
|
||||
utils.setup_params(this, params);
|
||||
|
||||
// set shader source
|
||||
this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url);
|
||||
if (this._source)
|
||||
this.set_shader_source(this._source);
|
||||
}
|
||||
|
||||
static get default_params() {
|
||||
return DEFAULT_PARAMS;
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,57 @@
|
||||
uniform sampler2D tex;
|
||||
uniform int factor;
|
||||
uniform float width;
|
||||
uniform float height;
|
||||
|
||||
#define CORRECTION 2.25
|
||||
#define SIZE_ADDITION 3
|
||||
|
||||
vec4 get_texture_at_position(vec2 position) {
|
||||
vec2 raw_position = position + vec2(CORRECTION, CORRECTION);
|
||||
vec2 raw_uv = raw_position / vec2(width + SIZE_ADDITION, height + SIZE_ADDITION);
|
||||
|
||||
return texture2D(tex, raw_uv);
|
||||
}
|
||||
|
||||
ivec2 get_corrected_position() {
|
||||
vec2 raw_uv = cogl_tex_coord0_in.st;
|
||||
vec2 raw_position = raw_uv * vec2(width + SIZE_ADDITION, height + SIZE_ADDITION);
|
||||
return ivec2(raw_position - vec2(CORRECTION, CORRECTION));
|
||||
}
|
||||
|
||||
void main() {
|
||||
ivec2 corrected_position = get_corrected_position();
|
||||
|
||||
vec2 adjusted_position = corrected_position / factor;
|
||||
|
||||
cogl_color_out = get_texture_at_position(adjusted_position);
|
||||
|
||||
// round
|
||||
if (distance(corrected_position, (floor(adjusted_position) + 0.5) * factor) < factor / 2.5) {
|
||||
//cogl_color_out = get_texture_at_position(adjusted_position);
|
||||
} else {
|
||||
//cogl_color_out = vec4(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
// square
|
||||
if (mod(corrected_position.x, factor) >= 2 && mod(corrected_position.y, factor) >= 2) {
|
||||
//cogl_color_out = get_texture_at_position(adjusted_position);
|
||||
} else {
|
||||
//cogl_color_out = vec4(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
// local mix
|
||||
vec4 color = vec4(0);
|
||||
int count = 0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
vec2 lookup_position = adjusted_position + vec2(i, j);
|
||||
if (all(greaterThanEqual(lookup_position, vec2(0, 0))) &&
|
||||
all(lessThan(lookup_position, vec2(width, height) / factor))) {
|
||||
color += get_texture_at_position(lookup_position);
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
//cogl_color_out = color / count;
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
import GObject from 'gi://GObject';
|
||||
|
||||
import * as utils from '../conveniences/utils.js';
|
||||
const Shell = await utils.import_in_shell_only('gi://Shell');
|
||||
const Clutter = await utils.import_in_shell_only('gi://Clutter');
|
||||
|
||||
const SHADER_FILENAME = 'upscale.glsl';
|
||||
const DEFAULT_PARAMS = {
|
||||
factor: 8, width: 0, height: 0
|
||||
};
|
||||
|
||||
|
||||
export const UpscaleEffect = utils.IS_IN_PREFERENCES ?
|
||||
{ default_params: DEFAULT_PARAMS } :
|
||||
new GObject.registerClass({
|
||||
GTypeName: "UpscaleEffect",
|
||||
Properties: {
|
||||
'factor': GObject.ParamSpec.int(
|
||||
`factor`,
|
||||
`Factor`,
|
||||
`Factor`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, 64,
|
||||
8,
|
||||
),
|
||||
'width': GObject.ParamSpec.double(
|
||||
`width`,
|
||||
`Width`,
|
||||
`Width`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, Number.MAX_SAFE_INTEGER,
|
||||
0.0,
|
||||
),
|
||||
'height': GObject.ParamSpec.double(
|
||||
`height`,
|
||||
`Height`,
|
||||
`Height`,
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0.0, Number.MAX_SAFE_INTEGER,
|
||||
0.0,
|
||||
)
|
||||
}
|
||||
}, class UpscaleEffect extends Clutter.ShaderEffect {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
|
||||
utils.setup_params(this, params);
|
||||
|
||||
// set shader source
|
||||
this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url);
|
||||
if (this._source)
|
||||
this.set_shader_source(this._source);
|
||||
}
|
||||
|
||||
static get default_params() {
|
||||
return DEFAULT_PARAMS;
|
||||
}
|
||||
|
||||
get factor() {
|
||||
return this._factor;
|
||||
}
|
||||
|
||||
set factor(value) {
|
||||
if (this._factor !== value) {
|
||||
this._factor = value;
|
||||
|
||||
this.set_uniform_value('factor', this._factor);
|
||||
}
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this._width;
|
||||
}
|
||||
|
||||
set width(value) {
|
||||
if (this._width !== value) {
|
||||
this._width = value;
|
||||
|
||||
this.set_uniform_value('width', parseFloat(this._width - 1e-6));
|
||||
}
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this._height;
|
||||
}
|
||||
|
||||
set height(value) {
|
||||
if (this._height !== value) {
|
||||
this._height = value;
|
||||
|
||||
this.set_uniform_value('height', parseFloat(this._height - 1e-6));
|
||||
}
|
||||
}
|
||||
|
||||
vfunc_set_actor(actor) {
|
||||
if (this._actor_connection_size_id) {
|
||||
let old_actor = this.get_actor();
|
||||
old_actor?.disconnect(this._actor_connection_size_id);
|
||||
}
|
||||
if (actor) {
|
||||
this.width = actor.width;
|
||||
this.height = actor.height;
|
||||
this._actor_connection_size_id = actor.connect('notify::size', _ => {
|
||||
this.width = actor.width;
|
||||
this.height = actor.height;
|
||||
});
|
||||
}
|
||||
else
|
||||
this._actor_connection_size_id = null;
|
||||
|
||||
super.vfunc_set_actor(actor);
|
||||
}
|
||||
|
||||
vfunc_paint_target(paint_node, paint_context) {
|
||||
// force setting nearest-neighbour texture filtering
|
||||
this.get_pipeline().set_layer_filters(0, 9728, 9728);
|
||||
|
||||
super.vfunc_paint_target(paint_node, paint_context);
|
||||
}
|
||||
});
|
||||
@ -4,10 +4,12 @@ import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||
|
||||
import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||
|
||||
import { update_from_old_settings } from './conveniences/settings_updater.js';
|
||||
import { PipelinesManager } from './conveniences/pipelines_manager.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 { KEYS } from './conveniences/keys.js';
|
||||
|
||||
import { PanelBlur } from './components/panel.js';
|
||||
import { OverviewBlur } from './components/overview.js';
|
||||
@ -15,16 +17,10 @@ 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 { CoverflowAltTabBlur } from './components/coverflow_alt_tab.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 {
|
||||
@ -34,9 +30,12 @@ export default class BlurMyShell extends Extension {
|
||||
// create it first as it is very useful when debugging crashes
|
||||
global.blur_my_shell = this;
|
||||
|
||||
// update from old settings, very important for hacks level specifically
|
||||
update_from_old_settings(this.getSettings());
|
||||
|
||||
// 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._settings = new Settings(KEYS, this.getSettings());
|
||||
|
||||
this._log("enabling extension...");
|
||||
|
||||
@ -49,8 +48,11 @@ export default class BlurMyShell extends Extension {
|
||||
// create a global effects manager (to prevent RAM bleeding)
|
||||
this._effects_manager = new EffectsManager(this._connection);
|
||||
|
||||
// create a global pipelines manager, that helps talking with preferences
|
||||
this._pipelines_manager = new PipelinesManager(this._settings);
|
||||
|
||||
// create an instance of each component, with its associated Connections
|
||||
let init = _ => {
|
||||
let init = () => {
|
||||
// create a Connections instance, to manage signals
|
||||
let connection = new Connections;
|
||||
|
||||
@ -66,6 +68,7 @@ export default class BlurMyShell extends Extension {
|
||||
this._lockscreen_blur = new LockscreenBlur(...init());
|
||||
this._appfolder_blur = new AppFoldersBlur(...init());
|
||||
this._window_list_blur = new WindowListBlur(...init());
|
||||
this._coverflow_alt_tab_blur = new CoverflowAltTabBlur(...init());
|
||||
this._applications_blur = new ApplicationsBlur(...init());
|
||||
this._screenshot_blur = new ScreenshotBlur(...init());
|
||||
|
||||
@ -82,7 +85,7 @@ export default class BlurMyShell extends Extension {
|
||||
|
||||
// watch for changes to the session mode
|
||||
this._connection.connect(Main.sessionMode, 'updated',
|
||||
_ => this._on_session_mode_changed(Main.sessionMode)
|
||||
() => this._on_session_mode_changed(Main.sessionMode)
|
||||
);
|
||||
}
|
||||
|
||||
@ -100,11 +103,10 @@ export default class BlurMyShell extends Extension {
|
||||
this._connection.connect(
|
||||
Main.layoutManager,
|
||||
'startup-complete',
|
||||
this._enable_components.bind(this)
|
||||
() => this._enable_components()
|
||||
);
|
||||
} else {
|
||||
} 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
|
||||
@ -155,6 +157,7 @@ export default class BlurMyShell extends Extension {
|
||||
// disable every component from user session mode
|
||||
if (this._user_session_mode_enabled)
|
||||
this._disable_user_session();
|
||||
this._overview_blur.restore_patched_proto();
|
||||
|
||||
// disable lockscreen blur too
|
||||
this._lockscreen_blur.disable();
|
||||
@ -166,6 +169,7 @@ export default class BlurMyShell extends Extension {
|
||||
this._appfolder_blur = null;
|
||||
this._lockscreen_blur = null;
|
||||
this._window_list_blur = null;
|
||||
this._coverflow_alt_tab_blur = null;
|
||||
this._applications_blur = null;
|
||||
this._screenshot_blur = null;
|
||||
|
||||
@ -199,6 +203,7 @@ export default class BlurMyShell extends Extension {
|
||||
this._overview_blur.disable();
|
||||
this._appfolder_blur.disable();
|
||||
this._window_list_blur.disable();
|
||||
this._coverflow_alt_tab_blur.disable();
|
||||
this._applications_blur.disable();
|
||||
this._screenshot_blur.disable();
|
||||
|
||||
@ -240,7 +245,7 @@ export default class BlurMyShell extends Extension {
|
||||
/// 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)
|
||||
if (this._settings.HACKS_LEVEL === 2)
|
||||
this._disable_clipped_redraws();
|
||||
else
|
||||
this._reenable_clipped_redraws();
|
||||
@ -283,6 +288,9 @@ export default class BlurMyShell extends Extension {
|
||||
if (this._settings.window_list.BLUR)
|
||||
this._window_list_blur.enable();
|
||||
|
||||
if (this._settings.coverflow_alt_tab.BLUR)
|
||||
this._coverflow_alt_tab_blur.enable();
|
||||
|
||||
if (this._settings.screenshot.BLUR)
|
||||
this._screenshot_blur.enable();
|
||||
|
||||
@ -291,58 +299,31 @@ export default class BlurMyShell extends Extension {
|
||||
|
||||
/// 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());
|
||||
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) {
|
||||
if (this._settings.overview.BLUR)
|
||||
this._overview_blur.enable();
|
||||
} else {
|
||||
else
|
||||
this._overview_blur.disable();
|
||||
}
|
||||
});
|
||||
|
||||
// overview pipeline changed
|
||||
this._settings.overview.PIPELINE_changed(() => {
|
||||
if (this._settings.overview.BLUR)
|
||||
this._overview_blur.update_backgrounds();
|
||||
});
|
||||
|
||||
// overview components style changed
|
||||
this._settings.overview.STYLE_COMPONENTS_changed(() => {
|
||||
if (this._settings.overview.BLUR) {
|
||||
if (this._settings.overview.BLUR)
|
||||
this._overview_blur.update_components_classname();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -350,11 +331,26 @@ export default class BlurMyShell extends Extension {
|
||||
|
||||
// toggled on/off
|
||||
this._settings.appfolder.BLUR_changed(() => {
|
||||
if (this._settings.appfolder.BLUR) {
|
||||
if (this._settings.appfolder.BLUR)
|
||||
this._appfolder_blur.enable();
|
||||
} else {
|
||||
else
|
||||
this._appfolder_blur.disable();
|
||||
}
|
||||
});
|
||||
|
||||
// appfolder sigma changed
|
||||
this._settings.appfolder.SIGMA_changed(() => {
|
||||
if (this._settings.appfolder.BLUR)
|
||||
this._appfolder_blur.set_sigma(
|
||||
this._settings.appfolder.SIGMA
|
||||
);
|
||||
});
|
||||
|
||||
// appfolder brightness changed
|
||||
this._settings.appfolder.BRIGHTNESS_changed(() => {
|
||||
if (this._settings.appfolder.BLUR)
|
||||
this._appfolder_blur.set_brightness(
|
||||
this._settings.appfolder.BRIGHTNESS
|
||||
);
|
||||
});
|
||||
|
||||
// appfolder dialogs style changed
|
||||
@ -368,24 +364,22 @@ export default class BlurMyShell extends Extension {
|
||||
|
||||
// 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();
|
||||
this._panel_blur.enable();
|
||||
else
|
||||
this._panel_blur.disable();
|
||||
});
|
||||
|
||||
// static blur toggled on/off
|
||||
// static blur toggled on/off, really we can just reload the blur at this point
|
||||
this._settings.panel.STATIC_BLUR_changed(() => {
|
||||
if (this._settings.panel.BLUR)
|
||||
this._panel_blur.update_all_blur_type();
|
||||
this._panel_blur.reset();
|
||||
});
|
||||
|
||||
// panel pipeline changed
|
||||
this._settings.panel.PIPELINE_changed(() => {
|
||||
if (this._settings.panel.BLUR)
|
||||
this._panel_blur.update_pipeline();
|
||||
});
|
||||
|
||||
// panel blur's overview connection toggled on/off
|
||||
@ -422,11 +416,10 @@ export default class BlurMyShell extends Extension {
|
||||
|
||||
// toggled on/off
|
||||
this._settings.dash_to_dock.BLUR_changed(() => {
|
||||
if (this._settings.dash_to_dock.BLUR) {
|
||||
if (this._settings.dash_to_dock.BLUR)
|
||||
this._dash_to_dock_blur.enable();
|
||||
} else {
|
||||
else
|
||||
this._dash_to_dock_blur.disable();
|
||||
}
|
||||
});
|
||||
|
||||
// static blur toggled on/off
|
||||
@ -435,10 +428,10 @@ export default class BlurMyShell extends Extension {
|
||||
this._dash_to_dock_blur.change_blur_type();
|
||||
});
|
||||
|
||||
// dash-to-dock corner radius changed
|
||||
this._settings.dash_to_dock.CORNER_RADIUS_changed(() => {
|
||||
if (this._settings.dash_to_dock.STATIC_BLUR)
|
||||
this._dash_to_dock_blur.set_corner_radius(this._settings.dash_to_dock.CORNER_RADIUS);
|
||||
// overview pipeline changed
|
||||
this._settings.dash_to_dock.PIPELINE_changed(() => {
|
||||
if (this._settings.dash_to_dock.BLUR)
|
||||
this._dash_to_dock_blur.update_pipeline();
|
||||
});
|
||||
|
||||
// dash-to-dock override background toggled on/off
|
||||
@ -464,35 +457,40 @@ export default class BlurMyShell extends Extension {
|
||||
|
||||
// toggled on/off
|
||||
this._settings.applications.BLUR_changed(() => {
|
||||
if (this._settings.applications.BLUR) {
|
||||
if (this._settings.applications.BLUR)
|
||||
this._applications_blur.enable();
|
||||
} else {
|
||||
else
|
||||
this._applications_blur.disable();
|
||||
}
|
||||
});
|
||||
|
||||
// application opacity changed
|
||||
this._settings.applications.OPACITY_changed(_ => {
|
||||
this._settings.applications.OPACITY_changed(() => {
|
||||
if (this._settings.applications.BLUR)
|
||||
this._applications_blur.set_opacity(
|
||||
this._settings.applications.OPACITY
|
||||
);
|
||||
});
|
||||
|
||||
// application dynamic-opacity changed
|
||||
this._settings.applications.DYNAMIC_OPACITY_changed(() => {
|
||||
if (this._settings.applications.BLUR)
|
||||
this._applications_blur.init_dynamic_opacity();
|
||||
});
|
||||
|
||||
// application blur-on-overview changed
|
||||
this._settings.applications.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(_ => {
|
||||
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(_ => {
|
||||
this._settings.applications.WHITELIST_changed(() => {
|
||||
if (
|
||||
this._settings.applications.BLUR
|
||||
&& !this._settings.applications.ENABLE_ALL
|
||||
@ -501,7 +499,7 @@ export default class BlurMyShell extends Extension {
|
||||
});
|
||||
|
||||
// application blacklist changed
|
||||
this._settings.applications.BLACKLIST_changed(_ => {
|
||||
this._settings.applications.BLACKLIST_changed(() => {
|
||||
if (
|
||||
this._settings.applications.BLUR
|
||||
&& this._settings.applications.ENABLE_ALL
|
||||
@ -514,11 +512,16 @@ export default class BlurMyShell extends Extension {
|
||||
|
||||
// toggled on/off
|
||||
this._settings.lockscreen.BLUR_changed(() => {
|
||||
if (this._settings.lockscreen.BLUR) {
|
||||
if (this._settings.lockscreen.BLUR)
|
||||
this._lockscreen_blur.enable();
|
||||
} else {
|
||||
else
|
||||
this._lockscreen_blur.disable();
|
||||
}
|
||||
});
|
||||
|
||||
// lockscreen pipeline changed
|
||||
this._settings.lockscreen.PIPELINE_changed(() => {
|
||||
if (this._settings.lockscreen.BLUR)
|
||||
this._lockscreen_blur.update_lockscreen();
|
||||
});
|
||||
|
||||
|
||||
@ -526,11 +529,21 @@ export default class BlurMyShell extends Extension {
|
||||
|
||||
// toggled on/off
|
||||
this._settings.window_list.BLUR_changed(() => {
|
||||
if (this._settings.window_list.BLUR) {
|
||||
if (this._settings.window_list.BLUR)
|
||||
this._window_list_blur.enable();
|
||||
} else {
|
||||
else
|
||||
this._window_list_blur.disable();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// ---------- COVERFLOW ALT-TAB ----------
|
||||
|
||||
// toggled on/off
|
||||
this._settings.coverflow_alt_tab.BLUR_changed(() => {
|
||||
if (this._settings.coverflow_alt_tab.BLUR)
|
||||
this._coverflow_alt_tab_blur.enable();
|
||||
else
|
||||
this._coverflow_alt_tab_blur.disable();
|
||||
});
|
||||
|
||||
|
||||
@ -556,157 +569,16 @@ export default class BlurMyShell extends Extension {
|
||||
|
||||
// toggled on/off
|
||||
this._settings.screenshot.BLUR_changed(() => {
|
||||
if (this._settings.screenshot.BLUR) {
|
||||
if (this._settings.screenshot.BLUR)
|
||||
this._screenshot_blur.enable();
|
||||
} else {
|
||||
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);
|
||||
// screenshot pipeline changed
|
||||
this._settings.screenshot.PIPELINE_changed(() => {
|
||||
if (this._settings.screenshot.BLUR)
|
||||
this._screenshot_blur.update_pipeline();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 249 B After Width: | Height: | Size: 249 B |
@ -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.292969 6.707031 l 5 5 c 0.390625 0.390625 1.023437 0.390625 1.414062 0 l 5 -5 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 s -1.023437 -0.390625 -1.414062 0 l -4.292969 4.292969 l -4.292969 -4.292969 c -0.390625 -0.390625 -1.023437 -0.390625 -1.414062 0 s -0.390625 1.023437 0 1.414062 z m 0 0" fill="#222222" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 484 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M7 5c-1.108 0-2 .892-2 2v7c0 1.108.892 2 2 2h7c1.108 0 2-.892 2-2V7c0-1.108-.892-2-2-2Zm0 1h7c.554 0 1 .446 1 1v7c0 .554-.446 1-1 1H7c-.554 0-1-.446-1-1V7c0-.554.446-1 1-1Z" style="fill:#dedede;stroke:none;stroke-linecap:round;stroke-linejoin:round;paint-order:stroke fill markers;stop-color:#000"/><path d="M2 0C.892 0 0 .892 0 2v7c0 1.108.892 2 2 2h2v-1H2c-.554 0-1-.446-1-1V2c0-.554.446-1 1-1h7c.554 0 1 .446 1 1v2h1V2c0-1.108-.892-2-2-2Z" style="fill:#dedede;stroke:none;stroke-linecap:round;stroke-linejoin:round;paint-order:stroke fill markers;stop-color:#000"/></svg>
|
||||
|
After Width: | Height: | Size: 646 B |
@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="16px"
|
||||
height="16px"
|
||||
viewBox="0 0 16 16"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
sodipodi:docname="dynamic-mode-symbolic.svg"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
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="defs5" />
|
||||
<sodipodi:namedview
|
||||
id="namedview5"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="44.75"
|
||||
inkscape:cx="7.9888268"
|
||||
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="svg5"
|
||||
showguides="true" />
|
||||
<path
|
||||
d="m 11.5,11.34375 a 5.75,5.75 0 0 1 -1,0.134766 v 2.234375 C 10.5,14.425813 9.9258135,15 9.2128906,15 H 2.2871094 C 1.5741865,15 1,14.425813 1,13.712891 V 6.7871094 C 1,6.0741865 1.5741865,5.5 2.2871094,5.5 h 2.234375 A 5.75,5.75 0 0 1 4.65625,4.5 H 1.5585937 C 0.69558189,4.5 0,5.1955819 0,6.0585937 V 14.441406 C 0,15.304418 0.69558189,16 1.5585937,16 H 9.9414063 C 10.804418,16 11.5,15.304418 11.5,14.441406 Z"
|
||||
style="opacity:1;fill:#dedede;stroke-linejoin:round"
|
||||
id="path14" />
|
||||
<path
|
||||
d="M 10.5,11.478516 A 5.75,5.75 0 0 1 10.25,11.5 5.75,5.75 0 0 1 4.5,5.75 5.75,5.75 0 0 1 4.5214844,5.5 H 2.2871094 C 1.5741865,5.5 1,6.0741865 1,6.7871094 V 13.712891 C 1,14.425813 1.5741865,15 2.2871094,15 H 9.2128906 C 9.9258135,15 10.5,14.425813 10.5,13.712891 Z"
|
||||
style="opacity:0.25;fill:#dedede;stroke-width:0.826087;stroke-linejoin:round"
|
||||
id="path15" />
|
||||
<path
|
||||
d="m 11.5,11.34375 v -1.029297 a 4.75,4.75 0 0 1 -1,0.164063 v 1 a 5.75,5.75 0 0 0 1,-0.134766 z"
|
||||
style="opacity:1;vector-effect:non-scaling-stroke;fill:#dedede;stroke-width:1.25351;stroke-linejoin:round;-inkscape-stroke:hairline"
|
||||
id="path22" />
|
||||
<path
|
||||
d="M 10.25,0 A 5.75,5.75 0 0 0 4.65625,4.5 H 5.6855469 A 4.75,4.75 0 0 1 10.25,1 4.75,4.75 0 0 1 15,5.75 4.75,4.75 0 0 1 11.5,10.314453 V 11.34375 A 5.75,5.75 0 0 0 16,5.75 5.75,5.75 0 0 0 10.25,0 Z"
|
||||
style="opacity:1;vector-effect:non-scaling-stroke;fill:#dedede;stroke-width:1.25351;stroke-linejoin:round;-inkscape-stroke:hairline"
|
||||
id="path18" />
|
||||
<path
|
||||
d="m 4.5214844,5.5 h 1 a 4.75,4.75 0 0 1 0.1640625,-1 H 4.65625 a 5.75,5.75 0 0 0 -0.1347656,1 z"
|
||||
style="opacity:1;vector-effect:non-scaling-stroke;fill:#dedede;stroke-width:1.25351;stroke-linejoin:round;-inkscape-stroke:hairline"
|
||||
id="path17" />
|
||||
<path
|
||||
d="m 10.5,11.478516 v -1 A 4.75,4.75 0 0 1 10.25,10.5 4.75,4.75 0 0 1 5.5,5.75 4.75,4.75 0 0 1 5.5214844,5.5 h -1 A 5.75,5.75 0 0 0 4.5,5.75 a 5.75,5.75 0 0 0 5.75,5.75 5.75,5.75 0 0 0 0.25,-0.02148 z"
|
||||
style="opacity:1;vector-effect:non-scaling-stroke;fill:#dedede;stroke-width:1.25351;stroke-linejoin:round;-inkscape-stroke:hairline"
|
||||
id="path16" />
|
||||
<path
|
||||
d="M 10.5,10.478516 V 6.7871094 C 10.5,6.0741865 9.9258135,5.5 9.2128906,5.5 H 5.5214844 A 4.75,4.75 0 0 0 5.5,5.75 a 4.75,4.75 0 0 0 4.75,4.75 4.75,4.75 0 0 0 0.25,-0.02148 z"
|
||||
style="opacity:0.125;vector-effect:non-scaling-stroke;fill:#dedede;stroke-width:1.03551;stroke-linejoin:round;-inkscape-stroke:hairline;fill-opacity:1"
|
||||
id="path21" />
|
||||
<path
|
||||
d="m 5.6855469,4.5 a 4.75,4.75 0 0 0 -0.1640625,1 H 9.2128906 C 9.9258135,5.5 10.5,6.0741865 10.5,6.7871094 v 3.6914066 a 4.75,4.75 0 0 0 1,-0.164063 V 6.0585937 C 11.5,5.1955819 10.804418,4.5 9.9414063,4.5 Z"
|
||||
style="opacity:0.5;vector-effect:non-scaling-stroke;fill:#dedede;stroke-width:1.03551;stroke-linejoin:round;-inkscape-stroke:hairline;fill-opacity:1"
|
||||
id="path20" />
|
||||
<path
|
||||
d="M 5.6855469,4.5 H 9.9414063 C 10.804418,4.5 11.5,5.1955819 11.5,6.0585937 V 10.314453 A 4.75,4.75 0 0 0 15,5.75 4.75,4.75 0 0 0 10.25,1 4.75,4.75 0 0 0 5.6855469,4.5 Z"
|
||||
style="opacity:0;vector-effect:non-scaling-stroke;fill:#dedede;stroke-width:1.03551;stroke-linejoin:round;-inkscape-stroke:hairline;fill-opacity:1"
|
||||
id="path19" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="16" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<metadata>
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<path d="m4 1c-1.108 0-2 0.892-2 2v10c0 1.108 0.892 2 2 2h8c1.108 0 2-0.892 2-2v-5.0488l-1 1v4.0488c0 0.554-0.446 1-1 1h-8c-0.554 0-1-0.446-1-1v-10c0-0.554 0.446-1 1-1h6.0488l1-1z" fill="#dedede"/>
|
||||
<path class="ColorScheme-Text" d="m14.607 1.6863c-0.78347-0.78347-2.045-0.78347-2.8284 0l3.5355 3.5355c0.78347-0.78347 0.78348-2.045 0-2.8284zm-3.5355 0.70711-7.0711 7.0711-6e-7 3.5355h3.5355l7.0711-7.0711zm0 1.4142 2.1213 2.1213-5.6569 5.6569-2.1213-2.1213z" fill="#dedede"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 959 B |
@ -1,64 +0,0 @@
|
||||
<?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>
|
||||
|
Before Width: | Height: | Size: 2.4 KiB |
@ -1,40 +0,0 @@
|
||||
<?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>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@ -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 5.074219 1.9375 c -3.136719 -0.3125 -5.875 3.914062 -2.816407 6.613281 l 5.742188 5.117188 l 5.746094 -5.117188 c 2.585937 -2.238281 1.070312 -6.492187 -2.351563 -6.585937 c -0.972656 -0.027344 -1.921875 0.324218 -2.636719 0.984375 l -0.757812 0.675781 l -0.753906 -0.675781 c -0.703125 -0.628907 -1.449219 -0.941407 -2.171875 -1.011719 z m -0.097657 0.988281 c 0.507813 0.046875 1.039063 0.265625 1.597657 0.769531 h 0.003906 l 1.421875 1.269532 l 1.425781 -1.273438 l 0.007813 -0.007812 c 0.523437 -0.480469 1.21875 -0.738282 1.933594 -0.71875 c 1.300781 0.035156 2.15625 0.816406 2.515624 1.824218 c 0.355469 1.007813 0.191407 2.15625 -0.792968 3.003907 l -0.003906 0.007812 l -5.085938 4.527344 l -5.078125 -4.527344 h -0.003906 c -0.753907 -0.664062 -0.992188 -1.332031 -0.996094 -2 c 0 -0.667969 0.285156 -1.351562 0.761719 -1.890625 c 0.480468 -0.535156 1.128906 -0.898437 1.789062 -0.976562 c 0.167969 -0.015625 0.335938 -0.019532 0.503906 -0.007813 z m 0 0" fill="#222222"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@ -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="pipelines-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.5 KiB |
|
Before Width: | Height: | Size: 740 B After Width: | Height: | Size: 740 B |
@ -1,2 +0,0 @@
|
||||
<?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>
|
||||
|
Before Width: | Height: | Size: 346 B |
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="16px" viewBox="0 0 16 16" width="16px"><filter id="a" height="100%" width="100%" x="0%" y="0%"><feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/></filter><mask id="b"><g filter="url(#a)"><path d="m -1.6 -1.6 h 19.2 v 19.2 h -19.2 z" fill-opacity="0.5"/></g></mask><clipPath id="c"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask id="d"><g filter="url(#a)"><path d="m -1.6 -1.6 h 19.2 v 19.2 h -19.2 z" fill-opacity="0.7"/></g></mask><clipPath id="e"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask id="f"><g filter="url(#a)"><path d="m -1.6 -1.6 h 19.2 v 19.2 h -19.2 z" fill-opacity="0.35"/></g></mask><clipPath id="g"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><g mask="url(#b)"><g clip-path="url(#c)" transform="matrix(1 0 0 1 -860 -60)"><path d="m 550 182 c -0.351562 0.003906 -0.695312 0.101562 -1 0.28125 v 3.4375 c 0.304688 0.179688 0.648438 0.277344 1 0.28125 c 1.105469 0 2 -0.894531 2 -2 s -0.894531 -2 -2 -2 z m 0 5 c -0.339844 0 -0.679688 0.058594 -1 0.175781 v 6.824219 h 4 v -4 c 0 -1.65625 -1.34375 -3 -3 -3 z m 0 0"/></g></g><g mask="url(#d)"><g clip-path="url(#e)" transform="matrix(1 0 0 1 -860 -60)"><path d="m 569 182 v 4 c 1.105469 0 2 -0.894531 2 -2 s -0.894531 -2 -2 -2 z m 0 5 v 7 h 3 v -4 c 0 -1.65625 -1.34375 -3 -3 -3 z m 0 0"/></g></g><g mask="url(#f)"><g clip-path="url(#g)" transform="matrix(1 0 0 1 -860 -60)"><path d="m 573 182.269531 v 3.449219 c 0.613281 -0.355469 0.996094 -1.007812 1 -1.71875 c 0 -0.714844 -0.382812 -1.375 -1 -1.730469 z m 0 4.90625 v 6.824219 h 2 v -4 c 0 -1.269531 -0.800781 -2.402344 -2 -2.824219 z m 0 0"/></g></g><path d="m 7.292969 1.707031 l 7 7 v -1.414062 l -7 7 c -0.390625 0.390625 -0.390625 1.023437 0 1.414062 s 1.023437 0.390625 1.414062 0 l 7 -7 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 l -7 -7 c -0.390625 -0.3906252 -1.023437 -0.3906252 -1.414062 0 c -0.390625 0.390625 -0.390625 1.023437 0 1.414062 z m 0 0"/><path d="m 15 7 h -14 c -0.550781 0 -1 0.449219 -1 1 s 0.449219 1 1 1 h 14 c 0.550781 0 1 -0.449219 1 -1 s -0.449219 -1 -1 -1 z m 0 0"/></svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="16px"
|
||||
height="16px"
|
||||
viewBox="0 0 16 16"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
sodipodi:docname="static-mode-symbolic.svg"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
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="defs5" />
|
||||
<sodipodi:namedview
|
||||
id="namedview5"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="44.75"
|
||||
inkscape:cx="8"
|
||||
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="svg5"
|
||||
showguides="true" />
|
||||
<path
|
||||
d="m 11.5,11.34375 a 5.75,5.75 0 0 1 -1,0.134766 v 2.234375 C 10.5,14.425813 9.9258135,15 9.2128906,15 H 2.2871094 C 1.5741865,15 1,14.425813 1,13.712891 V 6.7871094 C 1,6.0741865 1.5741865,5.5 2.2871094,5.5 h 2.234375 A 5.75,5.75 0 0 1 4.65625,4.5 H 1.5585937 C 0.69558189,4.5 0,5.1955819 0,6.0585937 V 14.441406 C 0,15.304418 0.69558189,16 1.5585937,16 H 9.9414063 C 10.804418,16 11.5,15.304418 11.5,14.441406 Z"
|
||||
style="opacity:1;fill:#dedede;stroke-linejoin:round"
|
||||
id="path14" />
|
||||
<path
|
||||
d="M 10.5,11.478516 A 5.75,5.75 0 0 1 10.25,11.5 5.75,5.75 0 0 1 4.5,5.75 5.75,5.75 0 0 1 4.5214844,5.5 H 2.2871094 C 1.5741865,5.5 1,6.0741865 1,6.7871094 V 13.712891 C 1,14.425813 1.5741865,15 2.2871094,15 H 9.2128906 C 9.9258135,15 10.5,14.425813 10.5,13.712891 Z"
|
||||
style="opacity:0.25;fill:#dedede;stroke-width:0.826087;stroke-linejoin:round"
|
||||
id="path15" />
|
||||
<path
|
||||
d="m 11.5,11.34375 v -1.029297 a 4.75,4.75 0 0 1 -1,0.164063 v 1 a 5.75,5.75 0 0 0 1,-0.134766 z"
|
||||
style="opacity:1;vector-effect:non-scaling-stroke;fill:#dedede;stroke-width:1.25351;stroke-linejoin:round;-inkscape-stroke:hairline"
|
||||
id="path22" />
|
||||
<path
|
||||
d="M 10.25,0 A 5.75,5.75 0 0 0 4.65625,4.5 H 5.6855469 A 4.75,4.75 0 0 1 10.25,1 4.75,4.75 0 0 1 15,5.75 4.75,4.75 0 0 1 11.5,10.314453 V 11.34375 A 5.75,5.75 0 0 0 16,5.75 5.75,5.75 0 0 0 10.25,0 Z"
|
||||
style="opacity:1;vector-effect:non-scaling-stroke;fill:#dedede;stroke-width:1.25351;stroke-linejoin:round;-inkscape-stroke:hairline"
|
||||
id="path18" />
|
||||
<path
|
||||
d="m 4.5214844,5.5 h 1 a 4.75,4.75 0 0 1 0.1640625,-1 H 4.65625 a 5.75,5.75 0 0 0 -0.1347656,1 z"
|
||||
style="opacity:1;vector-effect:non-scaling-stroke;fill:#dedede;stroke-width:1.25351;stroke-linejoin:round;-inkscape-stroke:hairline"
|
||||
id="path17" />
|
||||
<path
|
||||
d="m 10.5,11.478516 v -1 A 4.75,4.75 0 0 1 10.25,10.5 4.75,4.75 0 0 1 5.5,5.75 4.75,4.75 0 0 1 5.5214844,5.5 h -1 A 5.75,5.75 0 0 0 4.5,5.75 a 5.75,5.75 0 0 0 5.75,5.75 5.75,5.75 0 0 0 0.25,-0.02148 z"
|
||||
style="opacity:1;vector-effect:non-scaling-stroke;fill:#dedede;stroke-width:1.25351;stroke-linejoin:round;-inkscape-stroke:hairline"
|
||||
id="path16" />
|
||||
<path
|
||||
d="M 10.5,10.478516 V 6.7871094 C 10.5,6.0741865 9.9258135,5.5 9.2128906,5.5 H 5.5214844 A 4.75,4.75 0 0 0 5.5,5.75 a 4.75,4.75 0 0 0 4.75,4.75 4.75,4.75 0 0 0 0.25,-0.02148 z"
|
||||
style="opacity:0;vector-effect:non-scaling-stroke;fill:#dedede;stroke-width:1.03551;stroke-linejoin:round;-inkscape-stroke:hairline;fill-opacity:1"
|
||||
id="path21" />
|
||||
<path
|
||||
d="m 5.6855469,4.5 a 4.75,4.75 0 0 0 -0.1640625,1 H 9.2128906 C 9.9258135,5.5 10.5,6.0741865 10.5,6.7871094 v 3.6914066 a 4.75,4.75 0 0 0 1,-0.164063 V 6.0585937 C 11.5,5.1955819 10.804418,4.5 9.9414063,4.5 Z"
|
||||
style="opacity:0;vector-effect:non-scaling-stroke;fill:#dedede;stroke-width:1.03551;stroke-linejoin:round;-inkscape-stroke:hairline;fill-opacity:1"
|
||||
id="path20" />
|
||||
<path
|
||||
d="M 5.6855469,4.5 H 9.9414063 C 10.804418,4.5 11.5,5.1955819 11.5,6.0585937 V 10.314453 A 4.75,4.75 0 0 0 15,5.75 4.75,4.75 0 0 0 10.25,1 4.75,4.75 0 0 0 5.6855469,4.5 Z"
|
||||
style="opacity:0;vector-effect:non-scaling-stroke;fill:#dedede;stroke-width:1.03551;stroke-linejoin:round;-inkscape-stroke:hairline;fill-opacity:1"
|
||||
id="path19" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"_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.",
|
||||
"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\nIf you use Ubuntu, you may want to change the radius of the corner effect for Dash-to-Dock in preferences, else you may see unpleasantly mixed radii in your dock.\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"
|
||||
@ -16,9 +16,10 @@
|
||||
],
|
||||
"settings-schema": "org.gnome.shell.extensions.blur-my-shell",
|
||||
"shell-version": [
|
||||
"46"
|
||||
"46",
|
||||
"47"
|
||||
],
|
||||
"url": "https://github.com/aunetx/blur-my-shell",
|
||||
"uuid": "blur-my-shell@aunetx",
|
||||
"version": 59
|
||||
"version": 67
|
||||
}
|
||||