mirror of
https://github.com/elementary/gala.git
synced 2024-09-11 15:15:39 +03:00
Render shadows using Gtk (#250)
* Render shadows using Gtk * Do only apply shadow on fullscreen/maximized windows * Add per-workspace style-class * update shadow values * Disconnect signals
This commit is contained in:
parent
9502677835
commit
15f722ac8f
@ -28,3 +28,19 @@
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.decoration {
|
||||
border-radius: 4px 4px 0 0;
|
||||
box-shadow:
|
||||
0 0 0 1px alpha (#000, 0.3),
|
||||
0 14px 20px rgba(0, 0, 0, 0.35),
|
||||
0 10px 10px rgba(0, 0, 0, 0.22);
|
||||
}
|
||||
|
||||
.workspace.decoration {
|
||||
border-radius: 4px;
|
||||
box-shadow:
|
||||
0 0 0 1px alpha (#000, 0.2),
|
||||
0 8px 10px 1px alpha (#000, 0.14),
|
||||
0 3px 14px 2px alpha (#000, 0.12),
|
||||
0 5px 5px -3px alpha (#000, 0.4);
|
||||
}
|
||||
|
@ -36,10 +36,25 @@ namespace Gala
|
||||
// the sizes of the textures often repeat, especially for the background actor
|
||||
// so we keep a cache to avoid creating the same texture all over again.
|
||||
static Gee.HashMap<string,Shadow> shadow_cache;
|
||||
static Gtk.StyleContext style_context;
|
||||
|
||||
static construct
|
||||
class construct
|
||||
{
|
||||
shadow_cache = new Gee.HashMap<string,Shadow> ();
|
||||
var default_css = new Gtk.CssProvider ();
|
||||
try {
|
||||
default_css.load_from_path (Config.PKGDATADIR + "/gala.css");
|
||||
} catch (Error e) {
|
||||
warning ("Loading default styles failed: %s", e.message);
|
||||
}
|
||||
|
||||
var style_path = new Gtk.WidgetPath ();
|
||||
var id = style_path.append_type (typeof (Gtk.Window));
|
||||
|
||||
style_context = new Gtk.StyleContext ();
|
||||
style_context.add_provider (default_css, Gtk.STYLE_PROVIDER_PRIORITY_FALLBACK);
|
||||
style_context.add_class ("decoration");
|
||||
style_context.set_path (style_path);
|
||||
}
|
||||
|
||||
public int shadow_size { get; construct; }
|
||||
@ -47,6 +62,7 @@ namespace Gala
|
||||
|
||||
public float scale_factor { get; set; default = 1; }
|
||||
public uint8 shadow_opacity { get; set; default = 255; }
|
||||
public string? css_class { get; set; default = null; }
|
||||
|
||||
Cogl.Material material;
|
||||
string? current_key = null;
|
||||
@ -70,7 +86,6 @@ namespace Gala
|
||||
Cogl.Texture? get_shadow (int width, int height, int shadow_size, int shadow_spread)
|
||||
{
|
||||
var old_key = current_key;
|
||||
|
||||
current_key = "%ix%i:%i:%i".printf (width, height, shadow_size, shadow_spread);
|
||||
if (old_key == current_key)
|
||||
return null;
|
||||
@ -84,19 +99,24 @@ namespace Gala
|
||||
return shadow.texture;
|
||||
}
|
||||
|
||||
// fill a new texture for this size
|
||||
var buffer = new Granite.Drawing.BufferSurface (width, height);
|
||||
buffer.context.rectangle (shadow_size - shadow_spread, shadow_size - shadow_spread,
|
||||
width - shadow_size * 2 + shadow_spread * 2, height - shadow_size * 2 + shadow_spread * 2);
|
||||
buffer.context.set_source_rgba (0, 0, 0, 0.7);
|
||||
buffer.context.fill ();
|
||||
|
||||
buffer.exponential_blur (shadow_size / 2);
|
||||
|
||||
var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, height);
|
||||
var cr = new Cairo.Context (surface);
|
||||
cr.set_source_rgba (0, 0, 0, 0);
|
||||
cr.fill ();
|
||||
|
||||
cr.set_operator (Cairo.Operator.OVER);
|
||||
cr.save ();
|
||||
cr.scale (scale_factor, scale_factor);
|
||||
style_context.save ();
|
||||
if (css_class != null) {
|
||||
style_context.add_class (css_class);
|
||||
}
|
||||
|
||||
style_context.set_scale ((int)scale_factor);
|
||||
style_context.render_background (cr, shadow_size, shadow_size, width - shadow_size * 2, height - shadow_size * 2);
|
||||
style_context.restore ();
|
||||
cr.restore ();
|
||||
|
||||
cr.set_source_surface (buffer.surface, 0, 0);
|
||||
cr.paint ();
|
||||
|
||||
var texture = new Cogl.Texture.from_data (width, height, 0, Cogl.PixelFormat.BGRA_8888_PRE,
|
||||
@ -121,9 +141,10 @@ namespace Gala
|
||||
public override void paint (EffectPaintFlags flags)
|
||||
{
|
||||
var bounding_box = get_bounding_box ();
|
||||
var shadow = get_shadow ((int) (bounding_box.x2 - bounding_box.x1), (int) (bounding_box.y2 - bounding_box.y1),
|
||||
shadow_size, shadow_spread);
|
||||
var width = (int) (bounding_box.x2 - bounding_box.x1);
|
||||
var height = (int) (bounding_box.y2 - bounding_box.y1);
|
||||
|
||||
var shadow = get_shadow (width, height, shadow_size, shadow_spread);
|
||||
if (shadow != null)
|
||||
material.set_layer (0, shadow);
|
||||
|
||||
|
@ -22,7 +22,7 @@ namespace Gala
|
||||
{
|
||||
class WindowShadowEffect : ShadowEffect
|
||||
{
|
||||
public Meta.Window window { get; construct; }
|
||||
public unowned Meta.Window window { get; construct; }
|
||||
|
||||
public WindowShadowEffect (Meta.Window window, int shadow_size, int shadow_spread)
|
||||
{
|
||||
@ -136,6 +136,9 @@ namespace Gala
|
||||
|
||||
window.unmanaged.connect (unmanaged);
|
||||
window.notify["on-all-workspaces"].connect (on_all_workspaces_changed);
|
||||
window.notify["fullscreen"].connect (check_shadow_requirements);
|
||||
window.notify["maximized-horizontally"].connect (check_shadow_requirements);
|
||||
window.notify["maximized-vertically"].connect (check_shadow_requirements);
|
||||
|
||||
if (overview_mode) {
|
||||
var click_action = new ClickAction ();
|
||||
@ -184,6 +187,9 @@ namespace Gala
|
||||
{
|
||||
window.unmanaged.disconnect (unmanaged);
|
||||
window.notify["on-all-workspaces"].disconnect (on_all_workspaces_changed);
|
||||
window.notify["fullscreen"].disconnect (check_shadow_requirements);
|
||||
window.notify["maximized-horizontally"].disconnect (check_shadow_requirements);
|
||||
window.notify["maximized-vertically"].disconnect (check_shadow_requirements);
|
||||
|
||||
if (shadow_update_timeout != 0)
|
||||
Source.remove (shadow_update_timeout);
|
||||
@ -224,8 +230,7 @@ namespace Gala
|
||||
|
||||
transition_to_original_state (false);
|
||||
|
||||
shadow_effect = new WindowShadowEffect (window, 40, 5);
|
||||
clone.add_effect_with_name ("shadow", shadow_effect);
|
||||
check_shadow_requirements ();
|
||||
|
||||
if (should_fade ())
|
||||
opacity = 0;
|
||||
@ -243,6 +248,21 @@ namespace Gala
|
||||
}
|
||||
}
|
||||
|
||||
void check_shadow_requirements ()
|
||||
{
|
||||
if (window.fullscreen || window.maximized_horizontally && window.maximized_vertically) {
|
||||
if (shadow_effect == null) {
|
||||
shadow_effect = new WindowShadowEffect (window, 40, 5);
|
||||
clone.add_effect_with_name ("shadow", shadow_effect);
|
||||
}
|
||||
} else {
|
||||
if (shadow_effect != null) {
|
||||
clone.remove_effect (shadow_effect);
|
||||
shadow_effect = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If we are in overview mode, we may display windows from workspaces other than
|
||||
* the current one. To ease their appearance we have to fade them in.
|
||||
@ -423,9 +443,9 @@ namespace Gala
|
||||
shadow_transition.progress_mode = MultitaskingView.ANIMATION_MODE;
|
||||
|
||||
if (show)
|
||||
shadow_transition.interval = new Clutter.Interval (typeof (uint8), shadow_effect.shadow_opacity, 255);
|
||||
shadow_transition.interval = new Clutter.Interval (typeof (uint8), shadow_opacity, 255);
|
||||
else
|
||||
shadow_transition.interval = new Clutter.Interval (typeof (uint8), shadow_effect.shadow_opacity, 0);
|
||||
shadow_transition.interval = new Clutter.Interval (typeof (uint8), shadow_opacity, 0);
|
||||
|
||||
add_transition ("shadow-opacity", shadow_transition);
|
||||
}
|
||||
|
@ -35,7 +35,9 @@ namespace Gala
|
||||
var primary = screen.get_primary_monitor ();
|
||||
var monitor_geom = screen.get_monitor_geometry (primary);
|
||||
|
||||
add_effect (new ShadowEffect (40, 5));
|
||||
var effect = new ShadowEffect (40, 5);
|
||||
effect.css_class = "workspace";
|
||||
add_effect (effect);
|
||||
}
|
||||
|
||||
public override void paint ()
|
||||
|
Loading…
Reference in New Issue
Block a user