[gnome] Update extensions

This commit is contained in:
2026-04-09 09:51:44 -04:00
parent dadc78f2f4
commit 505c67d292
61 changed files with 1729 additions and 365 deletions

View File

@ -1,10 +1,58 @@
import Meta from 'gi://Meta';
import Gio from 'gi://Gio';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as Config from 'resource:///org/gnome/shell/misc/config.js';
import { ApplicationsService } from '../dbus/services.js';
import { PaintSignals } from '../conveniences/paint_signals.js';
import { DummyPipeline } from '../conveniences/dummy_pipeline.js';
import { Pipeline } from '../conveniences/pipeline.js';
/// Converts a wildcard pattern to a RegExp object.
/// Supports * (matches any sequence) and ? (matches any single character).
/// Matching is case-insensitive.
///
/// @param {string} pattern - The wildcard pattern (e.g., "Firefox*", "*Code*")
/// @returns {RegExp} The compiled regex pattern
function wildcardToRegex(pattern) {
// Escape special regex characters except * and ?
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&');
// Convert wildcards: * -> .*, ? -> .
const regex = '^' + escaped.replace(/\*/g, '.*').replace(/\?/g, '.') + '$';
return new RegExp(regex, 'i');
}
/// Compiles an array of wildcard patterns into RegExp objects.
/// Caches the results to avoid recompilation on every check.
///
/// @param {string[]} patterns - Array of wildcard patterns
/// @param {Map} cache - Cache map storing pattern -> regex mappings
/// @returns {RegExp[]} Array of compiled regex patterns
function compilePatterns(patterns, cache) {
return patterns.map(pattern => {
if (cache.has(pattern)) {
return cache.get(pattern);
}
const regex = wildcardToRegex(pattern);
cache.set(pattern, regex);
return regex;
});
}
/// Tests if a value matches any of the compiled patterns.
///
/// @param {string} value - The value to test (e.g., wm_class)
/// @param {RegExp[]} patterns - Array of compiled regex patterns
/// @returns {boolean} True if value matches any pattern
function matchesAnyPattern(value, patterns) {
if (!value || patterns.length === 0) {
return false;
}
return patterns.some(pattern => pattern.test(value));
}
export const ApplicationsBlur = class ApplicationsBlur {
constructor(connections, settings, effects_manager) {
@ -15,6 +63,27 @@ export const ApplicationsBlur = class ApplicationsBlur {
// stores every blurred meta window
this.meta_window_map = new Map();
// cache for compiled patterns to avoid recompilation
this._whitelist_pattern_cache = new Map();
this._blacklist_pattern_cache = new Map();
this._compiled_whitelist = [];
this._compiled_blacklist = [];
// compile initial patterns
this._update_patterns();
}
/// Updates the compiled whitelist and blacklist patterns from settings.
/// Called during initialization and when whitelist/blacklist settings change.
_update_patterns() {
const whitelist = this.settings.applications.WHITELIST || [];
const blacklist = this.settings.applications.BLACKLIST || [];
this._compiled_whitelist = compilePatterns(whitelist, this._whitelist_pattern_cache);
this._compiled_blacklist = compilePatterns(blacklist, this._blacklist_pattern_cache);
this._log(`Patterns updated - whitelist: ${whitelist.length}, blacklist: ${blacklist.length}`);
}
enable() {
@ -97,7 +166,7 @@ export const ApplicationsBlur = class ApplicationsBlur {
let window_actor = meta_window.get_compositor_private();
if (
!meta_window.get_workspace().active
(!meta_window.get_workspace().active) || meta_window.minimized
)
window_actor.hide();
});
@ -108,6 +177,9 @@ export const ApplicationsBlur = class ApplicationsBlur {
/// Iterate through all existing windows and add blur as needed.
update_all_windows() {
// Recompile patterns in case whitelist/blacklist changed
this._update_patterns();
// remove all previously blurred windows, in the case where the
// whitelist was changed
this.meta_window_map.forEach(((_meta_window, pid) => {
@ -145,11 +217,17 @@ export const ApplicationsBlur = class ApplicationsBlur {
_ => this.check_blur(meta_window)
);
// update the position and size when the window size changes
// update the clip, position, and/or size when the window changes
this.connections.connect(
meta_window, 'size-changed',
_ => this.update_size(pid)
);
if (this.settings.applications.STATIC_BLUR) {
this.connections.connect(
meta_window, 'position-changed',
_ => this.update_size(pid)
);
}
// remove the blur when the window is unmanaged
this.connections.connect(
@ -158,6 +236,18 @@ export const ApplicationsBlur = class ApplicationsBlur {
);
this.check_blur(meta_window);
if (this.settings.applications.STATIC_BLUR && meta_window.get_client_type() === Meta.WindowClientType.X11) {
const window_actor = meta_window.get_compositor_private();
window_actor.connect('child-added', _ => {
if (!meta_window.blur_actor) {
this._warn("can't move blur actor to back, it doesn't exist");
return;
}
window_actor.set_child_below_sibling(meta_window.blur_actor, null);
});
}
}
/// Updates the size of the blur actor associated to a meta window from its pid.
@ -167,11 +257,39 @@ export const ApplicationsBlur = class ApplicationsBlur {
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;
if (this.settings.applications.STATIC_BLUR) {
const bg_manager = meta_window.bg_manager;
const bg_actor_monitor_index = bg_manager.backgroundActor.monitor;
const window_monitor_index = meta_window.get_monitor();
const monitor = Main.layoutManager.monitors[window_monitor_index];
if (bg_actor_monitor_index !== window_monitor_index) {
this._log(`application (pid ${pid}) switching to monitor: ${window_monitor_index}`);
// Recreate the BackgroundActor on the right monitor. This is necessary to make sure differently
// sized monitors have the correct scaled image of the wallpaper.
bg_manager._monitorIndex = window_monitor_index;
bg_manager._updateBackgroundActor();
// Also to fix differently sized monitor issues.
blur_actor.width = monitor.width;
blur_actor.height = monitor.height;
}
const frame = meta_window.get_frame_rect();
const buffer = meta_window.get_buffer_rect();
blur_actor.x = monitor.x - buffer.x;
blur_actor.y = monitor.y - buffer.y;
// set_clip(x-offset, y-offset, width, height)
blur_actor.set_clip(frame.x - monitor.x, frame.y - monitor.y, frame.width, frame.height);
} else {
const allocation = this.compute_allocation(meta_window);
blur_actor.x = allocation.x;
blur_actor.y = allocation.y;
blur_actor.width = allocation.width;
blur_actor.height = allocation.height;
}
}
} else
// the pid was visibly not removed
@ -184,11 +302,14 @@ export const ApplicationsBlur = class ApplicationsBlur {
/// In order to be blurred, a window either:
/// - is whitelisted in the user preferences if not enable-all
/// - is not blacklisted if enable-all
///
/// Whitelist and blacklist support wildcard patterns:
/// - * matches any sequence of characters
/// - ? matches any single character
/// - Matching is case-insensitive
check_blur(meta_window) {
const window_wm_class = meta_window.get_wm_class();
const enable_all = this.settings.applications.ENABLE_ALL;
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}`);
@ -197,8 +318,8 @@ export const ApplicationsBlur = class ApplicationsBlur {
// 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))
&& ((enable_all && !matchesAnyPattern(window_wm_class, this._compiled_blacklist))
|| (!enable_all && matchesAnyPattern(window_wm_class, this._compiled_whitelist))
)
&& [
Meta.FrameType.NORMAL,
@ -222,23 +343,37 @@ export const ApplicationsBlur = class ApplicationsBlur {
const pid = meta_window.bms_pid;
const window_actor = meta_window.get_compositor_private();
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'
);
let blur_actor;
if (this.settings.applications.STATIC_BLUR) {
const pipeline = new Pipeline(this.effects_manager, global.blur_my_shell._pipelines_manager, this.settings.applications.PIPELINE);
const bg_managers = [];
blur_actor = pipeline.create_background_with_effects(
meta_window.get_monitor(), bg_managers, window_actor,
'bms-application-blurred-widget'
);
if (bg_managers.length > 0) meta_window.bg_manager = bg_managers[0];
else // I've never seen this happen, but just in case
this._warn(`no bg_manager on blur creation for pid ${pid}`);
} else {
const pipeline = new DummyPipeline(this.effects_manager, this.settings.applications);
[blur_actor, meta_window.bg_manager] = pipeline.create_background_with_effect(
window_actor, 'bms-application-blurred-widget'
);
// if hacks are selected, force to repaint the window
if (this.settings.HACKS_LEVEL === 1) {
this._log("hack level 1");
this.paint_signals.disconnect_all_for_actor(blur_actor);
this.paint_signals.connect(blur_actor, pipeline.effect);
} else {
this.paint_signals.disconnect_all_for_actor(blur_actor);
}
}
meta_window.blur_actor = blur_actor;
meta_window.bg_manager = bg_manager;
// if hacks are selected, force to repaint the window
if (this.settings.HACKS_LEVEL === 1) {
this._log("hack level 1");
this.paint_signals.disconnect_all_for_actor(blur_actor);
this.paint_signals.connect(blur_actor, pipeline.effect);
} else {
this.paint_signals.disconnect_all_for_actor(blur_actor);
}
// make sure window is blurred in overview
if (this.settings.applications.BLUR_ON_OVERVIEW)
@ -328,8 +463,7 @@ export const ApplicationsBlur = class ApplicationsBlur {
) {
window_actor.show();
window_actor.get_last_child().hide();
}
else if (
} else if (
window_actor.visible
)
window_actor.get_last_child().show();
@ -358,18 +492,29 @@ export const ApplicationsBlur = class ApplicationsBlur {
}));
}
/// Compute the size and position for a blur actor.
/// Find the system's window scaling.
/// If `scale-monitor-framebuffer` experimental feature if on, we don't need to manage scaling.
/// Else, on wayland, we need to divide by the scale to get the correct result.
compute_allocation(meta_window) {
const scale_monitor_framebuffer = this.mutter_gsettings.get_strv('experimental-features')
.includes('scale-monitor-framebuffer');
const is_wayland = Meta.is_wayland_compositor();
compute_scale(meta_window) {
// TODO: Drop GNOME <50 compatibility
const gnome_shell_major_version = parseInt(Config.PACKAGE_VERSION.split('.')[0]);
const scale_monitor_framebuffer =
gnome_shell_major_version >= 50 ||
this.mutter_gsettings
.get_strv('experimental-features')
.includes('scale-monitor-framebuffer');
const is_wayland = gnome_shell_major_version >= 50 || Meta.is_wayland_compositor();
const monitor_index = meta_window.get_monitor();
// check if the window is using wayland, or xwayland/xorg for rendering
const scale = !scale_monitor_framebuffer && is_wayland && meta_window.get_client_type() == 0
return !scale_monitor_framebuffer && is_wayland && meta_window.get_client_type() == 0
? Main.layoutManager.monitors[monitor_index].geometry_scale
: 1;
}
/// Compute the size and position for a blur actor.
/// Coordinates are relative to window buffer's corner.
compute_allocation(meta_window) {
const scale = this.compute_scale(meta_window);
let frame = meta_window.get_frame_rect();
let buffer = meta_window.get_buffer_rect();
@ -382,6 +527,17 @@ export const ApplicationsBlur = class ApplicationsBlur {
};
}
change_blur_type() {
this._log("resetting...");
this.disable();
setTimeout(_ => this.enable(), 1);
}
change_pipeline() {
this.update_all_windows();
}
/// Removes the blur actor to make a blurred window become normal again.
/// It however does not untrack the meta window itself.
/// Accepts a pid corresponding (or not) to a blurred (or not) meta window.
@ -448,4 +604,8 @@ export const ApplicationsBlur = class ApplicationsBlur {
if (this.settings.DEBUG)
console.log(`[Blur my Shell > applications] ${str}`);
}
_warn(str) {
console.warn(`[Blur my Shell > applications] ${str}`);
}
};

View File

@ -66,7 +66,7 @@ export const CoverflowAltTabBlur = class CoverflowAltTabBlur {
}
remove_background_actors() {
this.background_actors.forEach((actor) => actor.destroy);
this.background_actors.forEach((actor) => actor.destroy());
this.background_actors = [];
this.background_managers.forEach((background_manager) => {

View File

@ -16,6 +16,9 @@ const PANEL_STYLES = [
"contrasted-panel"
];
// global listener, so we don't miss the panel destruction event
let isMainPanelAlive = true;
Main.panel.connect('destroy', () => isMainPanelAlive = false);
export const PanelBlur = class PanelBlur {
constructor(connections, settings, effects_manager) {
@ -28,6 +31,11 @@ export const PanelBlur = class PanelBlur {
}
enable() {
if (this.enabled) {
this._log("blur already enabled");
return;
}
this._log("blurring top panel");
// check for panels when Dash to Panel is activated
@ -64,6 +72,11 @@ export const PanelBlur = class PanelBlur {
}
reset() {
if (!this.enabled) {
this._log("reset called but blur is not enabled");
return;
}
this._log("resetting...");
this.disable();
@ -77,6 +90,10 @@ export const PanelBlur = class PanelBlur {
// blur already existing ones
if (global.dashToPanel.panels)
this.blur_dtp_panels();
// blur main panel if requested in settings
if (this.settings.dash_to_panel.BLUR_ORIGINAL_PANEL && isMainPanelAlive)
this.maybe_blur_panel(Main.panel);
} else {
// if no dash-to-panel, blur the main and only panel
this.maybe_blur_panel(Main.panel);
@ -92,24 +109,15 @@ export const PanelBlur = class PanelBlur {
if (!global.dashToPanel?.panels) {
return GLib.SOURCE_REMOVE;
}
this._log("Blurring Dash to Panel panels after idle.");
// blur every panel found
// blur every panel, except Main.panel (this is handled in blur_existing_panels() method above)
global.dashToPanel.panels.forEach(p => {
this.maybe_blur_panel(p.panel);
if (p.panel != Main.panel)
this.maybe_blur_panel(p.panel);
});
// if main panel is not included in the previous panels, blur it
if (
!global.dashToPanel.panels
.map(p => p.panel)
.includes(Main.panel)
&&
this.settings.dash_to_panel.BLUR_ORIGINAL_PANEL
)
this.maybe_blur_panel(Main.panel);
return GLib.SOURCE_REMOVE;
});
};
@ -377,6 +385,11 @@ export const PanelBlur = class PanelBlur {
/// Update the css classname of the panel for light theme
update_light_text_classname(disable = false) {
if (!isMainPanelAlive) {
this._log("cannot update light text classname, Main.panel is not alive");
return;
}
if (this.settings.panel.FORCE_LIGHT_TEXT && !disable)
Main.panel.add_style_class_name("panel-light-text");
else
@ -408,7 +421,7 @@ export const PanelBlur = class PanelBlur {
/// Update the visibility of the blur effect
update_visibility() {
if (
Main.panel.has_style_pseudo_class('overview')
isMainPanelAlive && Main.panel.has_style_pseudo_class('overview')
|| !Main.sessionMode.hasWindows
) {
this.actors_list.forEach(
@ -533,6 +546,11 @@ export const PanelBlur = class PanelBlur {
}
disable() {
if (!this.enabled) {
this._log("blur already removed");
return;
}
this._log("removing blur from top panel");
this.disconnect_from_windows_and_overview();

View File

@ -53,6 +53,8 @@ export const KEYS = [
{
component: "applications", schemas: [
{ type: Type.B, name: "blur" },
{ type: Type.B, name: "static-blur" },
{ type: Type.S, name: "pipeline" },
{ type: Type.I, name: "sigma" },
{ type: Type.D, name: "brightness" },
{ type: Type.I, name: "opacity" },

View File

@ -3,11 +3,109 @@ uniform float red;
uniform float green;
uniform float blue;
uniform float blend;
uniform int mode;
const int NORMAL = 0;
const int MULTIPLY = 1;
const int SCREEN = 2;
const int OVERLAY = 3;
const int DARKEN = 4;
const int LIGHTEN = 5;
const int PLUS_DARKER = 6;
const int PLUS_LIGHTER = 7;
const int COLOR_DODGE = 8;
const int COLOR_BURN = 9;
const int HARD_LIGHT = 10;
const int SOFT_LIGHT = 11;
const int DIFFERENCE = 12;
const int EXCLUSION = 13;
const int HUE = 14;
const int SATURATION = 15;
const int COLOR = 16;
const int LUMINOSITY = 17;
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);
}
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);
}
float soft_light_channel(float base, float _blend) {
if (_blend < 0.5) {
return base - (1.0 - 2.0 * _blend) * base * (1.0 - base);
} else {
float d = (base < 0.25)
? ((16.0 * base - 12.0) * base + 4.0) * base
: sqrt(base);
return base + (2.0 * _blend - 1.0) * (d - base);
}
}
vec3 get_blend(vec3 base, vec3 _blend) {
if (mode == MULTIPLY) return base * _blend;
if (mode == SCREEN) return 1 - (1 - base) * (1 - _blend);
if (mode == OVERLAY) {
vec3 result;
result.r = base.r < 0.5 ? (2.0 * base.r * _blend.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - _blend.r));
result.g = base.g < 0.5 ? (2.0 * base.g * _blend.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - _blend.g));
result.b = base.b < 0.5 ? (2.0 * base.b * _blend.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - _blend.b));
return result;
}
if (mode == DARKEN) return min(base, _blend);
if (mode == LIGHTEN) return max(base, _blend);
if (mode == PLUS_DARKER) return base + _blend - 1;
if (mode == PLUS_LIGHTER) return base + _blend;
if (mode == COLOR_DODGE) return base / (1 - _blend);
if (mode == COLOR_BURN) return 1 - (1 - base) / _blend;
if (mode == HARD_LIGHT) {
vec3 result;
result.r = _blend.r < 0.5 ? (2.0 * base.r * _blend.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - _blend.r));
result.g = _blend.g < 0.5 ? (2.0 * base.g * _blend.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - _blend.g));
result.b = _blend.b < 0.5 ? (2.0 * base.b * _blend.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - _blend.b));
return result;
}
if (mode == SOFT_LIGHT) {
return vec3(soft_light_channel(base.r, _blend.r), soft_light_channel(base.g, _blend.g), soft_light_channel(base.b, _blend.b));
}
if (mode == DIFFERENCE) return abs(base - _blend);
if (mode == EXCLUSION) return 0.5 - 2 * (base - 0.5) * (_blend - 0.5);
if (mode == HUE) {
vec3 base_hsl = rgb_to_hsl(base);
vec3 blend_hsl = rgb_to_hsl(_blend);
return hsl_to_rgb(vec3(blend_hsl.x, base_hsl.y, base_hsl.z));
}
if (mode == SATURATION) {
vec3 base_hsl = rgb_to_hsl(base);
vec3 blend_hsl = rgb_to_hsl(_blend);
return hsl_to_rgb(vec3(base_hsl.x, blend_hsl.y, base_hsl.z));
}
if (mode == COLOR) {
vec3 base_hsl = rgb_to_hsl(base);
vec3 blend_hsl = rgb_to_hsl(_blend);
return hsl_to_rgb(vec3(blend_hsl.x, blend_hsl.y, base_hsl.z));
}
if (mode == LUMINOSITY) {
vec3 base_hsl = rgb_to_hsl(base);
vec3 blend_hsl = rgb_to_hsl(_blend);
return hsl_to_rgb(vec3(base_hsl.x, base_hsl.y, blend_hsl.z));
}
return _blend; // For NORMAL
}
void main() {
vec4 c = texture2D(tex, cogl_tex_coord_in[0].st);
vec3 pix_color = c.xyz;
vec3 color = vec3(red, green, blue);
vec3 color = get_blend(pix_color, vec3(red, green, blue));
cogl_color_out = vec4(mix(pix_color, color, blend), 1.);
}

View File

@ -1,12 +1,14 @@
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]
color: [0.0, 0.0, 0.0, 0.0],
blend_mode: 0
};
@ -47,7 +49,18 @@ export const ColorEffect = utils.IS_IN_PREFERENCES ?
0.0, 1.0,
0.0,
),
'blend_mode': GObject.ParamSpec.int(
`blend_mode`,
`Blend mode`,
`Blend mode`,
GObject.ParamFlags.READWRITE,
0, 17,
0,
)
}
// Normal (0), Multiply (1), Screen (2), Overlay (3), Darken (4), Lighten (5), Plus darker (6), Plus lighter (7), Color dodge (8),
// Color burn (9), Hard light (10), Soft light (11), Difference (12), Exclusion (13), Hue (14), Saturation (15), Color (16),
// Luminosity (17)
}, class ColorEffect extends Clutter.ShaderEffect {
constructor(params) {
// initialize without color as a parameter
@ -58,14 +71,16 @@ export const ColorEffect = utils.IS_IN_PREFERENCES ?
this._green = null;
this._blue = null;
this._blend = null;
this._blend_mode = 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
// set params; utils.setup_params doesn't work here with color
this.color = 'color' in params ? color : this.constructor.default_params.color;
this.blend_mode = 'blend_mode' in params ? params.blend_mode : this.constructor.default_params.blend_mode;
}
static get default_params() {
@ -121,6 +136,18 @@ export const ColorEffect = utils.IS_IN_PREFERENCES ?
}
}
get blend_mode() {
return this._blend_mode;
}
set blend_mode(value) {
if (this._blend_mode !== value) {
this._blend_mode = value;
this.set_uniform_value('mode', this._blend_mode);
}
}
set color(rgba) {
let [r, g, b, a] = rgba;
this.red = r;
@ -136,5 +163,6 @@ export const ColorEffect = utils.IS_IN_PREFERENCES ?
/// False set function, only cares about the color. Too hard to change.
set(params) {
this.color = params.color;
this.blend_mode = params.blend_mode;
}
});

View File

@ -168,6 +168,31 @@ export function get_supported_effects(_ = () => "") {
name: _("Color"),
description: _("The color to blend in. The blending amount is controled by the opacity of the color."),
type: "rgba"
},
blend_mode: {
name: _("Blend mode"),
description: _("How the color is blended in."),
type: "dropdown",
options: [
_("Normal"),
_("Multiply"),
_("Screen"),
_("Overlay"),
_("Darken"),
_("Lighten"),
_("Plus darker"),
_("Plus lighter"),
_("Color dodge"),
_("Color burn"),
_("Hard light"),
_("Soft light"),
_("Difference"),
_("Exclusion"),
_("Hue"),
_("Saturation"),
_("Color"),
_("Luminosity")
]
}
}
},

View File

@ -476,6 +476,18 @@ export default class BlurMyShell extends Extension {
this._applications_blur.disable();
});
// static blur toggled on/off
this._settings.applications.STATIC_BLUR_changed(() => {
if (this._settings.applications.BLUR)
this._applications_blur.change_blur_type();
});
// pipeline changed
this._settings.applications.PIPELINE_changed(() => {
if (this._settings.applications.BLUR)
this._applications_blur.change_pipeline();
});
// application opacity changed
this._settings.applications.OPACITY_changed(() => {
if (this._settings.applications.BLUR)

View File

@ -19,9 +19,10 @@
"46",
"47",
"48",
"49"
"49",
"50"
],
"url": "https://github.com/aunetx/blur-my-shell",
"uuid": "blur-my-shell@aunetx",
"version": 70
"version": 71
}

View File

@ -30,7 +30,12 @@ export const Applications = GObject.registerClass({
Template: GLib.uri_resolve_relative(import.meta.url, '../ui/applications.ui', GLib.UriFlags.NONE),
InternalChildren: [
'blur',
'pipeline_choose_row',
'mode_static',
'mode_dynamic',
'sigma_row',
'sigma',
'brightness_row',
'brightness',
'opacity',
'dynamic_opacity',
@ -42,16 +47,32 @@ export const Applications = GObject.registerClass({
'add_window_blacklist'
],
}, class Applications extends Adw.PreferencesPage {
constructor(preferences, preferences_window) {
constructor(preferences, preferences_window, pipelines_manager, pipelines_page) {
super({});
this._preferences_window = preferences_window;
this.preferences = preferences;
this.pipelines_manager = pipelines_manager;
this.pipelines_page = pipelines_page;
this.preferences.applications.settings.bind(
'blur', this._blur, 'active',
Gio.SettingsBindFlags.DEFAULT
);
this._pipeline_choose_row.initialize(
this.preferences.applications, this.pipelines_manager, this.pipelines_page
);
this.change_blur_mode(this.preferences.applications.STATIC_BLUR, true);
this._mode_static.connect('toggled',
() => this.preferences.applications.STATIC_BLUR = this._mode_static.active
);
this.preferences.applications.STATIC_BLUR_changed(
() => this.change_blur_mode(this.preferences.applications.STATIC_BLUR, false)
);
this.preferences.applications.settings.bind(
'opacity', this._opacity, 'value',
Gio.SettingsBindFlags.DEFAULT
@ -183,4 +204,14 @@ export const Applications = GObject.registerClass({
this._blacklist.remove(widget);
this.update_blacklist_titles();
}
change_blur_mode(is_static_blur, first_run) {
this._mode_static.set_active(is_static_blur);
if (first_run)
this._mode_dynamic.set_active(!is_static_blur);
this._pipeline_choose_row.set_visible(is_static_blur);
this._sigma_row.set_visible(!is_static_blur);
this._brightness_row.set_visible(!is_static_blur);
}
});

View File

@ -43,7 +43,7 @@ export default class BlurMyShellPreferences extends ExtensionPreferences {
window.add(new Panel(preferences, pipelines_manager, pipelines_page));
window.add(new Overview(preferences, pipelines_manager, pipelines_page));
window.add(new Dash(preferences, pipelines_manager, pipelines_page));
window.add(new Applications(preferences, window));
window.add(new Applications(preferences, window, pipelines_manager, pipelines_page));
window.add(new Other(preferences, pipelines_manager, pipelines_page));
window.search_enabled = true;

View File

@ -351,6 +351,16 @@
<default>false</default>
<summary>Boolean, whether to blur activate the blur for this component or not</summary>
</key>
<!-- PIPELINE -->
<key type="s" name="pipeline">
<default>"pipeline_default"</default>
<summary>String, the name of the pipeline to use. It must exist, else "pipeline_default" will be used</summary>
</key>
<!-- STATIC BLUR -->
<key type="b" name="static-blur">
<default>false</default>
<summary>Boolean, whether to use static or dynamic blur for this component</summary>
</key>
<!-- CUSTOMIZE -->
<key type="b" name="customize">
<default>true</default>

View File

@ -18,6 +18,57 @@ To get the best results possible, although with reduced performances, you can ch
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Blur type</property>
<property name="subtitle" translatable="yes">The dynamic blur is slower and only compatible with a gaussian blur effect, but shows content behind windows.</property>
<property name="activatable-widget">blur_mode_choose</property>
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
<child>
<object class="GtkBox" id="blur_mode_choose">
<property name="valign">center</property>
<property name="hexpand">false</property>
<style>
<class name="linked" />
</style>
<child>
<object class="GtkToggleButton" id="mode_static">
<property name="valign">center</property>
<property name="hexpand">true</property>
<property name="group">mode_dynamic</property>
<property name="child">
<object class="AdwButtonContent">
<property name="icon-name">static-mode-symbolic</property>
<property name="label" translatable="yes">Static</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkToggleButton" id="mode_dynamic">
<property name="valign">center</property>
<property name="hexpand">true</property>
<property name="child">
<object class="AdwButtonContent">
<property name="icon-name">dynamic-mode-symbolic</property>
<property name="label" translatable="yes">Dynamic</property>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="PipelineChooseRow" id="pipeline_choose_row">
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
</object>
</child>
<child>
<object class="AdwActionRow" id="sigma_row">
<property name="title" translatable="yes">Sigma</property>
<property name="subtitle" translatable="yes">The intensity of the blur.</property>
<property name="activatable-widget">sigma_scale</property>
@ -38,7 +89,7 @@ To get the best results possible, although with reduced performances, you can ch
</child>
<child>
<object class="AdwActionRow">
<object class="AdwActionRow" id="brightness_row">
<property name="title" translatable="yes">Brightness</property>
<property name="subtitle" translatable="yes">The brightness of the blur effect, a high value might make the text harder to read.</property>
<property name="activatable-widget">brightness_scale</property>
@ -131,7 +182,8 @@ This may cause some latency or performance issues.</property>
<child>
<object class="AdwPreferencesGroup" id="whitelist">
<property name="title" translatable="yes">Whitelist</property>
<property name="description" translatable="yes">A list of windows to blur.</property>
<property name="description" translatable="yes">A list of windows to blur.
Use * to match any sequence of characters (e.g., Firefox* or *Code*), and ? for a single one.</property>
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
<property name="header-suffix">
<object class="GtkButton" id="add_window_whitelist">
@ -168,7 +220,8 @@ This may cause some latency or performance issues.</property>
<child>
<object class="AdwPreferencesGroup" id="blacklist">
<property name="title" translatable="yes">Blacklist</property>
<property name="description" translatable="yes">A list of windows not to blur.</property>
<property name="description" translatable="yes">A list of windows not to blur.
Use * to match any sequence of characters (e.g., Firefox* or *Code*), and ? for a single one.</property>
<property name="sensitive" bind-source="blur" bind-property="state" bind-flags="sync-create" />
<property name="header-suffix">
<object class="GtkButton" id="add_window_blacklist">
@ -220,4 +273,4 @@ This may cause some latency or performance issues.</property>
<property name="upper">255</property>
<property name="step-increment">1</property>
</object>
</interface>
</interface>