[gnome] Update extensions
This commit is contained in:
@ -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}`);
|
||||
}
|
||||
};
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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" },
|
||||
|
||||
@ -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.);
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
});
|
||||
@ -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")
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -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)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
});
|
||||
@ -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;
|
||||
|
||||
Binary file not shown.
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
Reference in New Issue
Block a user