Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions data/gala.gresource.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<file alias="buttons/resize.svg" compressed="true" preprocess="xml-stripblanks">resize.svg</file>
</gresource>
<gresource prefix="/io/elementary/desktop/gala">
<file compressed="true">shaders/box-blur.frag</file>
<file compressed="true">shaders/colorblindness-correction.frag</file>
<file compressed="true">shaders/monochrome.frag</file>
<file compressed="true">shaders/rounded-corners.frag</file>
Expand Down
28 changes: 28 additions & 0 deletions data/shaders/box-blur.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2026 elementary, Inc. <https://elementary.io>
* SPDX-License-Identifier: GPL-3.0-or-later
*/

uniform sampler2D tex;
uniform int RADIUS;
uniform vec2 PIXEL_STEP;
uniform vec2 DIRECTION;

void main() {
if (RADIUS == 0) {
cogl_color_out = texture2D(tex, cogl_tex_coord0_in.xy);
return;
}

vec4 sum = vec4(0, 0, 0, 0);
int count = 0;

for (int i = -RADIUS; i <= RADIUS; i++) {
vec2 offset = DIRECTION * PIXEL_STEP * i;

sum += texture2D(tex, cogl_tex_coord0_in.xy + offset);
count += 1;
}

cogl_color_out = sum / count;
}
8 changes: 5 additions & 3 deletions lib/Drawing/Color.vala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 elementary, Inc. (https://elementary.io)
* Copyright 2019-2026 elementary, Inc. (https://elementary.io)
* Copyright 2011–2013 Robert Dyer
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
Expand All @@ -16,17 +16,19 @@ namespace Gala.Drawing {
public const Clutter.Color DARK_BORDER = { 0, 0, 0, 191};
public const Clutter.Color LIGHT_HIGHLIGHT = { 255, 255, 255, 255};
public const Clutter.Color DARK_HIGHLIGHT = { 255, 255, 255, 13};
public const Clutter.Color TOOLTIP_BACKGROUND = { 0, 0, 0, 255};
public const Clutter.Color TOOLTIP_BACKGROUND = { 26, 26, 26, 230};
public const Clutter.Color TOOLTIP_TEXT_COLOR = { 255, 255, 255, 255};
public const Clutter.Color TOOLTIP_TEXT_SHADOW_COLOR = { 0, 0, 0, 153};
#else
public const Cogl.Color LIGHT_BACKGROUND = { 250, 250, 250, 255};
public const Cogl.Color DARK_BACKGROUND = { 51, 51, 51, 255};
public const Cogl.Color LIGHT_BORDER = { 0, 0, 0, 51};
public const Cogl.Color DARK_BORDER = { 0, 0, 0, 191};
public const Cogl.Color LIGHT_HIGHLIGHT = { 255, 255, 255, 255};
public const Cogl.Color DARK_HIGHLIGHT = { 255, 255, 255, 13};
public const Cogl.Color TOOLTIP_BACKGROUND = { 0, 0, 0, 255};
public const Cogl.Color TOOLTIP_BACKGROUND = { 26, 26, 26, 230};
public const Cogl.Color TOOLTIP_TEXT_COLOR = { 255, 255, 255, 255};
public const Cogl.Color TOOLTIP_TEXT_SHADOW_COLOR = { 0, 0, 0, 153};
#endif

/**
Expand Down
88 changes: 88 additions & 0 deletions lib/Effects/BoxBlurManager.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2026 elementary, Inc. <https://elementary.io>
* SPDX-License-Identifier: GPL-3.0-or-later
*/

public class Gala.BoxBlurManager : Object {
private int _radius = 0;
public int radius {
get {
return _radius;
}
set {
_radius = value;
horizontal_effect.radius = value;
vertical_effect.radius = value;
}
}

private BoxBlurEffect horizontal_effect;
private BoxBlurEffect vertical_effect;

public BoxBlurManager (Clutter.Actor actor) {
horizontal_effect = new BoxBlurEffect (HORIZONTAL);
vertical_effect = new BoxBlurEffect (VERTICAL);

actor.add_effect (horizontal_effect);
actor.add_effect (vertical_effect);
}

private class BoxBlurEffect : Clutter.ShaderEffect {
public enum PassDirection {
HORIZONTAL,
VERTICAL;
}

private const float[] HORIZONTAL_PASS_DATA = { 1.0f, 0.0f };
private const float[] VERTICAL_PASS_DATA = { 0.0f, 1.0f };

public int radius { set { set_uniform_value ("RADIUS", value); } }

public BoxBlurEffect (PassDirection direction) {
Object (
#if HAS_MUTTER48
shader_type: Cogl.ShaderType.FRAGMENT
#else
shader_type: Clutter.ShaderType.FRAGMENT_SHADER
#endif
);

try {
var bytes = GLib.resources_lookup_data ("/io/elementary/desktop/gala/shaders/box-blur.frag", NONE);
set_shader_source ((string) bytes.get_data ());
} catch (Error e) {
critical ("Unable to load box-blur.frag: %s", e.message);
}

radius = 0;

var direction_value = GLib.Value (typeof (Clutter.ShaderFloat));
var direction_data = direction == HORIZONTAL ? HORIZONTAL_PASS_DATA : VERTICAL_PASS_DATA;
Clutter.Value.set_shader_float (direction_value, direction_data);

set_uniform_value ("DIRECTION", direction_value);
}

public override void set_actor (Clutter.Actor? new_actor) {
if (actor != null) {
actor.notify["width"].disconnect (update_pixel_step);
actor.notify["height"].disconnect (update_pixel_step);
}

base.set_actor (new_actor);

if (actor != null) {
actor.notify["width"].connect (update_pixel_step);
actor.notify["height"].connect (update_pixel_step);
update_pixel_step ();
}
}

private void update_pixel_step () {
var pixel_step_value = GLib.Value (typeof (Clutter.ShaderFloat));
Clutter.Value.set_shader_float (pixel_step_value, { 1 / actor.width, 1 / actor.height });

set_uniform_value ("PIXEL_STEP", pixel_step_value);
}
}
}
43 changes: 34 additions & 9 deletions lib/Widgets/Text.vala
Original file line number Diff line number Diff line change
@@ -1,31 +1,48 @@
/*
* SPDX-License-Identifier: LGPL-3.0-or-later
* SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
* SPDX-FileCopyrightText: 2025-2026 elementary, Inc. (https://elementary.io)
*/

/*
* Clutter.Text that automatically changes font-name to the system one
* Clutter.Text that automatically changes font-name to the system one and supports text shadow
*/
public class Gala.Text : Clutter.Actor {
private static GLib.Settings gnome_interface_settings;
private static GLib.Settings gnome_interface_settings = new GLib.Settings ("org.gnome.desktop.interface");

#if HAS_MUTTER47
public Cogl.Color color { get { return text_actor.color; } set { text_actor.color = value; } }
#else
public Clutter.Color color { get { return text_actor.color; } set { text_actor.color = value; } }
#endif
public Pango.EllipsizeMode ellipsize { get { return text_actor.ellipsize; } set { text_actor.ellipsize = value; } }
public Pango.Alignment line_alignment {
get { return text_actor.line_alignment; } set { text_actor.line_alignment = value; }
}
public Pango.Alignment line_alignment { get { return text_actor.line_alignment; } set { text_actor.line_alignment = value; }}
public string text { get { return text_actor.text; } set { text_actor.text = value; } }

private Clutter.Text text_actor;
#if HAS_MUTTER47
public Cogl.Color shadow_color {
#else
public Clutter.Color shadow_color {
#endif
get { return shadow_actor.color; }
set {
shadow_actor.color = value;

static construct {
gnome_interface_settings = new GLib.Settings ("org.gnome.desktop.interface");
if (shadow_actor.color.alpha != 0 && shadow_actor.get_parent () == null) {
insert_child_below (shadow_actor, null);
} else if (shadow_actor.color.alpha == 0 && shadow_actor.get_parent () == this) {
remove_child (shadow_actor);
}
}
}

public float shadow_offset_x { get { return shadow_actor.translation_x; } set { shadow_actor.translation_x = value; } }
public float shadow_offset_y { get { return shadow_actor.translation_y; } set { shadow_actor.translation_y = value; } }
public int shadow_blur_radius { get { return box_blur_manager.radius; } set { box_blur_manager.radius = value; } }

private Clutter.Text text_actor;
private Clutter.Text shadow_actor;
private BoxBlurManager box_blur_manager;

class construct {
set_layout_manager_type (typeof (Clutter.BinLayout));
}
Expand All @@ -34,6 +51,14 @@ public class Gala.Text : Clutter.Actor {
text_actor = new Clutter.Text ();
add_child (text_actor);

shadow_actor = new Clutter.Text ();
box_blur_manager = new BoxBlurManager (shadow_actor);

text_actor.bind_property ("ellipsize", shadow_actor, "ellipsize");
text_actor.bind_property ("line-alignment", shadow_actor, "line-alignment");
text_actor.bind_property ("text", shadow_actor, "text");
text_actor.bind_property ("font-name", shadow_actor, "font-name");

set_system_font_name ();
gnome_interface_settings.changed["font-name"].connect (set_system_font_name);
}
Expand Down
1 change: 1 addition & 0 deletions lib/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ gala_lib_sources = files(
'Drawing/StyleManager.vala',
'Drawing/Utilities.vala',
'Effects/BackgroundBlurEffect.vala',
'Effects/BoxBlurManager.vala',
'Effects/RoundedCornersEffect.vala',
'Effects/ShadowEffect.vala',
'Gestures/Backends/GestureBackend.vala',
Expand Down
7 changes: 6 additions & 1 deletion src/Widgets/MultitaskingView/Tooltip.vala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
public class Gala.Tooltip : Clutter.Actor {
private const int TEXT_MARGIN = 6;
private const int CORNER_RADIUS = 3;
private const int TEXT_SHADOW_Y_OFFSET = 1;
private const int TEXT_SHADOW_BLUR_RADIUS = 2;

public float monitor_scale { get; construct set; }

Expand All @@ -22,7 +24,10 @@ public class Gala.Tooltip : Clutter.Actor {
construct {
text_actor = new Gala.Text () {
ellipsize = Pango.EllipsizeMode.MIDDLE,
color = Drawing.Color.TOOLTIP_TEXT_COLOR
color = Drawing.Color.TOOLTIP_TEXT_COLOR,
shadow_color = Drawing.Color.TOOLTIP_TEXT_SHADOW_COLOR,
shadow_offset_y = TEXT_SHADOW_Y_OFFSET,
shadow_blur_radius = TEXT_SHADOW_BLUR_RADIUS
};
bind_property ("monitor-scale", text_actor, "margin-left", SYNC_CREATE, transform_monitor_scale_to_margin);
bind_property ("monitor-scale", text_actor, "margin-top", SYNC_CREATE, transform_monitor_scale_to_margin);
Expand Down