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:
Corentin Noël 2018-07-29 02:59:03 +01:00 committed by Cassidy James Blaede
parent 9502677835
commit 15f722ac8f
4 changed files with 79 additions and 20 deletions

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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 ()