diff --git a/resources/ui/applications.ui b/resources/ui/applications.ui index 0b4b83ca..54b0a02b 100644 --- a/resources/ui/applications.ui +++ b/resources/ui/applications.ui @@ -27,7 +27,7 @@ To get the best results possible, make sure to choose the option “No artifact Opacity The opacity of the window on top of the blur effect, a higher value will be more legible. - opacity + opacity_scale diff --git a/resources/ui/dash.ui b/resources/ui/dash.ui index 5eac21b9..ce7db902 100644 --- a/resources/ui/dash.ui +++ b/resources/ui/dash.ui @@ -17,7 +17,46 @@ + + + + + + + Static blur + Uses a static blurred image, can be used with rounding effect. + static_blur + + + + center + + + + + + + + Rounded corner radius + The radius for the rounding effect. Only available with static blur. + corner_radius_scale + + + + + + center + true + 200px + true + right + horizontal + 0 + corner_radius + + @@ -70,4 +109,10 @@ Dark + + + 0 + 50 + 1 + \ No newline at end of file diff --git a/resources/ui/panel.ui b/resources/ui/panel.ui index 4e14b004..f7a40e0d 100644 --- a/resources/ui/panel.ui +++ b/resources/ui/panel.ui @@ -36,21 +36,6 @@ - - - Disable in overview - Disables the blur from the panel when entering the overview. - unblur_in_overview - - - - - center - - - - - Force light text @@ -104,6 +89,21 @@ Recommended unless you want to customize your GNOME theme. + + + + Disable in overview + Disables the blur from the panel when entering the overview. + unblur_in_overview + + + + + center + + + + diff --git a/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml b/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml index 2ae8267d..1e237e7b 100644 --- a/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml +++ b/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml @@ -1,11 +1,12 @@ - + 30 - Global sigma (gaussian blur radius) to use + Global gaussian sigma to use @@ -56,7 +57,8 @@ - + true @@ -70,7 +72,7 @@ 30 - Sigma (gaussian blur radius) to use for the blur effect + Gaussian sigma to use for the blur effect @@ -100,7 +102,8 @@ - + true @@ -114,7 +117,7 @@ 30 - Sigma (gaussian blur radius) to use for the blur effect + Gaussian sigma to use for the blur effect @@ -144,7 +147,8 @@ - + true @@ -158,7 +162,7 @@ 30 - Sigma (gaussian blur radius) to use for the blur effect + Gaussian sigma to use for the blur effect @@ -213,7 +217,8 @@ - + false @@ -227,7 +232,7 @@ 30 - Sigma (gaussian blur radius) to use for the blur effect + Gaussian sigma to use for the blur effect @@ -269,10 +274,16 @@ false Boolean, whether to disable blur from this component when opening the overview or not + + + 12 + Radius for the corner rounding effect + - + false @@ -286,7 +297,7 @@ 30 - Sigma (gaussian blur radius) to use for the blur effect + Gaussian sigma to use for the blur effect @@ -336,7 +347,8 @@ - + true @@ -350,7 +362,7 @@ 30 - Sigma (gaussian blur radius) to use for the blur effect + Gaussian sigma to use for the blur effect @@ -375,7 +387,8 @@ - + true @@ -389,7 +402,7 @@ 30 - Sigma (gaussian blur radius) to use for the blur effect + Gaussian sigma to use for the blur effect @@ -414,7 +427,8 @@ - + true @@ -428,7 +442,7 @@ 30 - Sigma (gaussian blur radius) to use for the blur effect + Gaussian sigma to use for the blur effect @@ -453,7 +467,8 @@ - + false @@ -462,7 +477,8 @@ - + true diff --git a/src/components/dash_to_dock.js b/src/components/dash_to_dock.js index 3c56588e..80f42319 100644 --- a/src/components/dash_to_dock.js +++ b/src/components/dash_to_dock.js @@ -1,9 +1,12 @@ 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 { PaintSignals } from '../effects/paint_signals.js'; +import { BlurEffect } from '../effects/blur_effect.js'; const DASH_STYLES = [ "transparent-dash", @@ -12,72 +15,192 @@ 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, background_parent, effect, settings) { + constructor(dash_blur, dash, dash_container, dash_background, background, background_parent, effect) { // the parent DashBlur object, to communicate this.dash_blur = dash_blur; + this.dash_container = dash_container; // the blurred dash this.dash = dash; + this.dash_background = dash_background; this.background_parent = background_parent; + this.background = background; this.effect = effect; - this.settings = settings; + 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.dash._background.style = this.old_style; - - DASH_STYLES.forEach( - style => this.dash.remove_style_class_name(style) - ); + this.remove_style(); }); dash_blur.connections.connect(dash_blur, 'update-sigma', () => { - this.effect.sigma = this.dash_blur.sigma; + if (this.dash_blur.is_static) { + this.dash_blur.update_size(); + this.effect.radius = 2 * this.dash_blur.sigma * this.effect.scale; + } else + this.effect.sigma = this.dash_blur.sigma * this.effect.scale; }); dash_blur.connections.connect(dash_blur, 'update-brightness', () => { this.effect.brightness = this.dash_blur.brightness; }); - dash_blur.connections.connect(dash_blur, 'override-background', () => { - this.dash._background.style = null; + dash_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 + ); + } + }); - DASH_STYLES.forEach( - style => this.dash.remove_style_class_name(style) - ); + dash_blur.connections.connect(dash_blur, 'override-background', () => { + 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.dash._background.style = this.old_style; - - DASH_STYLES.forEach( - style => this.dash.remove_style_class_name(style) - ); - }); + dash_blur.connections.connect(dash_blur, 'reset-background', () => this.remove_style()); dash_blur.connections.connect(dash_blur, 'show', () => { - this.effect.sigma = this.dash_blur.sigma; + if (this.dash_blur.is_static) + this.background_parent.show(); + else + this.effect.sigma = this.dash_blur.sigma * this.effect.scale; }); dash_blur.connections.connect(dash_blur, 'hide', () => { - this.effect.sigma = 0; + if (this.dash_blur.is_static) + this.background_parent.hide(); + else + this.effect.sigma = 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); + }); + } + + remove_style() { + this.dash._background.style = this.old_style; + + DASH_STYLES.forEach( + style => this.dash.remove_style_class_name(style) + ); + } + + get_dash_position(dash_container, dash_background) { + var x, y; + + let monitor = find_monitor_for(dash_container); + let dash_box = dash_container._slider.get_child(); + + if (dash_container.get_style_class_name().includes("top")) { + x = (monitor.width - dash_background.width) / 2; + y = dash_box.y; + } else if (dash_container.get_style_class_name().includes("bottom")) { + x = (monitor.width - dash_background.width) / 2; + y = monitor.height - dash_container.height; + } else if (dash_container.get_style_class_name().includes("left")) { + x = dash_box.x; + y = dash_container.y + (dash_container.height - dash_background.height) / 2 - dash_background.y; + } else if (dash_container.get_style_class_name().includes("right")) { + x = monitor.width - dash_container.width; + y = dash_container.y + (dash_container.height - dash_background.height) / 2 - dash_background.y; + } + + return [x, y]; } _log(str) { if (this.settings.DEBUG) console.log(`[Blur my Shell > dash] ${str}`); } + + _warn(str) { + console.warn(`[Blur my Shell > dash] ${str}`); + } } export const DashBlur = class DashBlur { @@ -92,6 +215,8 @@ export const DashBlur = class DashBlur { 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; } @@ -107,6 +232,9 @@ export const DashBlur = class DashBlur { this.blur_existing_dashes(); this.connect_to_overview(); + this.update_wallpaper(); + this.update_size(); + this.enabled = true; } @@ -143,13 +271,6 @@ export const DashBlur = class DashBlur { // Blurs the dash and returns a `DashInfos` containing its information blur_dash_from(dash, dash_container) { - // the effect to be applied - let effect = new Shell.BlurEffect({ - brightness: this.brightness, - sigma: this.sigma, - mode: Shell.BlurMode.BACKGROUND - }); - // dash background parent, not visible let background_parent = new St.Widget({ name: 'dash-blurred-background-parent', @@ -158,99 +279,179 @@ export const DashBlur = class DashBlur { height: 0 }); - // dash background widget - let background = new St.Widget({ - name: 'dash-blurred-background', - style_class: 'dash-blurred-background', - x: 0, - y: dash_container._slider.y, - width: dash.width, - height: dash.height, + // 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(); + // updates size and position on change - this.connections.connect(dash_container._slider, 'notify::y', _ => { - background.y = dash_container._slider.y; - }); this.connections.connect(dash, 'notify::width', _ => { - background.width = dash.width; + this.update_size(); }); this.connections.connect(dash, 'notify::height', _ => { - background.height = dash.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(); }); - // add the widget to the dash - background.add_effect(effect); background_parent.add_child(background); dash.get_parent().insert_child_at_index(background_parent, 0); - // HACK - // - //`Shell.BlurEffect` does not repaint when shadows are under it. [1] - // - // This does not entirely fix this bug (shadows caused by windows - // still cause artifacts), but it prevents the shadows of the panel - // buttons to cause artifacts on the panel itself - // - // [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 - - if (this.settings.HACKS_LEVEL === 1) { - this._log("dash hack level 1"); - this.paint_signals.disconnect_all(); - - let rp = () => { - effect.queue_repaint(); - }; - - dash._box.get_children().forEach((icon) => { - try { - let zone = icon.get_child_at_index(0); - - this.connections.connect(zone, [ - 'enter-event', 'leave-event', 'button-press-event' - ], rp); - } catch (e) { - this._warn(`${e}, continuing`); - } - }); + // create infos + let infos = new DashInfos( + this, + dash, + dash_container, + dash_background, + background, + background_parent, + effect + ); - this.connections.connect(dash._box, 'actor-added', (_, actor) => { - try { - let zone = actor.get_child_at_index(0); + // update the background + this.update_background(); - this.connections.connect(zone, [ - 'enter-event', 'leave-event', 'button-press-event' - ], rp); - } catch (e) { - this._warn(`${e}, continuing`); - } - }); + // returns infos + return infos; + } - let show_apps = dash._showAppsIcon; + add_blur(dash, dash_background, dash_container) { + let monitor = find_monitor_for(dash); - this.connections.connect(show_apps, [ - 'enter-event', 'leave-event', 'button-press-event' - ], rp); + // 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, + }); - this.connections.connect(dash, 'leave-event', rp); - } else if (this.settings.HACKS_LEVEL === 2) { - this._log("dash hack level 2"); + // 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 + }); - this.paint_signals.connect(background, effect); + // 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() + ); } else { - this.paint_signals.disconnect_all(); + effect = new Shell.BlurEffect({ + brightness: this.brightness, + sigma: this.sigma * monitor.geometry_scale, + mode: Shell.BlurMode.BACKGROUND + }); + + // HACK + // + //`Shell.BlurEffect` does not repaint when shadows are under it. [1] + // + // This does not entirely fix this bug (shadows caused by windows + // still cause artifacts), but it prevents the shadows of the panel + // buttons to cause artifacts on the panel itself + // + // [1]: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 + + if (this.settings.HACKS_LEVEL === 1) { + this._log("dash hack level 1"); + this.paint_signals.disconnect_all(); + + let rp = () => { + effect.queue_repaint(); + }; + + dash._box.get_children().forEach((icon) => { + try { + let zone = icon.get_child_at_index(0); + + this.connections.connect(zone, [ + 'enter-event', 'leave-event', 'button-press-event' + ], rp); + } catch (e) { + this._warn(`${e}, continuing`); + } + }); + + this.connections.connect(dash._box, 'actor-added', (_, actor) => { + try { + let zone = actor.get_child_at_index(0); + + this.connections.connect(zone, [ + 'enter-event', 'leave-event', 'button-press-event' + ], rp); + } catch (e) { + this._warn(`${e}, continuing`); + } + }); + + let show_apps = dash._showAppsIcon; + + this.connections.connect(show_apps, [ + 'enter-event', 'leave-event', 'button-press-event' + ], rp); + + this.connections.connect(dash, 'leave-event', rp); + } else if (this.settings.HACKS_LEVEL === 2) { + this._log("dash hack level 2"); + + this.paint_signals.connect(background, effect); + } else { + this.paint_signals.disconnect_all(); + } } - // create infos - let infos = new DashInfos( - this, dash, background_parent, effect, this.settings - ); + // store the scale in the effect in order to retrieve it in set_sigma + effect.scale = monitor.geometry_scale; - // update the background - this.update_background(); + background.add_effect(effect); - // returns infos - return infos; + return [background, effect]; + } + + change_blur_type() { + this.is_static = this.settings.dash_to_dock.STATIC_BLUR; + this.emit('change-blur-type', true); + + this.update_wallpaper(); + this.update_background(); + this.update_size(); } /// Connect when overview if opened/closed to hide/show the blur accordingly @@ -276,6 +477,15 @@ export const DashBlur = class DashBlur { this.emit('reset-background', true); } + update_wallpaper() { + if (this.is_static) + this.emit('update-wallpaper', true); + } + + update_size() { + this.emit('update-size', true); + } + set_sigma(sigma) { this.sigma = sigma; this.emit('update-sigma', true); @@ -286,6 +496,11 @@ export const DashBlur = class DashBlur { this.emit('update-brightness', true); } + 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) { } diff --git a/src/components/panel.js b/src/components/panel.js index b034a36e..ba587950 100644 --- a/src/components/panel.js +++ b/src/components/panel.js @@ -320,7 +320,7 @@ export const PanelBlur = class PanelBlur { Main.layoutManager.monitors.length - this.find_monitor_for(actors.widgets.panel).index - 1 ); - if (bg) + if (bg && bg.get_content()) actors.widgets.background.content.set({ background: bg.get_content().background }); diff --git a/src/conveniences/keys.js b/src/conveniences/keys.js index 115bb206..71a357c2 100644 --- a/src/conveniences/keys.js +++ b/src/conveniences/keys.js @@ -68,6 +68,7 @@ export const Keys = [ { 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" }, ] }, { diff --git a/src/effects/blur_effect.glsl b/src/effects/blur_effect.glsl new file mode 100644 index 00000000..567105db --- /dev/null +++ b/src/effects/blur_effect.glsl @@ -0,0 +1,97 @@ +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)); +} + +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 = texture2D(tex, 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 += texture2D(tex, uv + offset) * coefficient_subtotal; + ret += texture2D(tex, 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) { + vec2 pos = uv * vec2(width, height); + + // 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; +} \ No newline at end of file diff --git a/src/effects/blur_effect.js b/src/effects/blur_effect.js new file mode 100644 index 00000000..2bc385f0 --- /dev/null +++ b/src/effects/blur_effect.js @@ -0,0 +1,237 @@ +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._tex = null; + + 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 - 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 - 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 + }); + 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(); + } +}); \ No newline at end of file diff --git a/src/extension.js b/src/extension.js index fb933aa4..556f3722 100644 --- a/src/extension.js +++ b/src/extension.js @@ -364,11 +364,16 @@ export default class BlurMyShell extends Extension { } }); - // TODO implement static blur for dash // static blur toggled on/off this._settings.dash_to_dock.STATIC_BLUR_changed(() => { - //if (this._settings.dash_to_dock.BLUR) - // this._dash_to_dock_blur.change_blur_type(); + if (this._settings.dash_to_dock.BLUR) + 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); }); // dash-to-dock override background toggled on/off diff --git a/src/preferences/dash.js b/src/preferences/dash.js index ef8d9ed2..3a42ff20 100644 --- a/src/preferences/dash.js +++ b/src/preferences/dash.js @@ -10,6 +10,8 @@ export const Dash = GObject.registerClass({ InternalChildren: [ 'blur', 'customize', + 'static_blur', + 'corner_radius', 'override_background', 'style_dash_to_dock', 'unblur_in_overview' @@ -24,6 +26,16 @@ export const Dash = GObject.registerClass({ 'blur', this._blur, 'active', Gio.SettingsBindFlags.DEFAULT ); + this.preferences.dash_to_dock.settings.bind( + 'static-blur', + this._static_blur, 'active', + Gio.SettingsBindFlags.DEFAULT + ); + this.preferences.dash_to_dock.settings.bind( + 'corner-radius', + this._corner_radius, 'value', + Gio.SettingsBindFlags.DEFAULT + ); this.preferences.dash_to_dock.settings.bind( 'override-background', this._override_background, 'enable-expansion',