draw a custom shadow around windows, use window textures only which have better filtering when scaled

This commit is contained in:
Tom Beckmann 2014-06-18 18:55:22 +02:00
parent 4debed4fed
commit 4c08373810
4 changed files with 78 additions and 53 deletions

View File

@ -39,6 +39,7 @@ gala_VALASOURCES = \
PluginManager.vala \
ScreenSaver.vala \
Settings.vala \
ShadowEffect.vala \
TextShadowEffect.vala \
WindowManager.vala \
WorkspaceManager.vala \

66
src/ShadowEffect.vala Normal file
View File

@ -0,0 +1,66 @@
using Clutter;
namespace Gala
{
public class ShadowEffect : Effect
{
// 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.
// TODO keep track of user numbers and free shadows
static Gee.HashMap<string,Cogl.Texture> shadow_cache;
public int shadow_size { get; construct; }
public int shadow_spread { get; construct; }
public float scale_factor { get; set; default = 1; }
Cogl.Texture? shadow = null;
public ShadowEffect (int actor_width, int actor_height, int shadow_size, int shadow_spread)
{
Object (shadow_size: shadow_size, shadow_spread: shadow_spread);
if (shadow_cache == null) {
shadow_cache = new Gee.HashMap<string,Cogl.Texture> ();
}
var width = actor_width + shadow_size * 2;
var height = actor_height + shadow_size * 2;
var key = "%ix%i:%i:%i".printf (width, height, shadow_size, shadow_spread);
if ((shadow = shadow_cache.@get (key)) != null)
return;
// 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,
actor_width + shadow_spread * 2, actor_height + 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_surface (buffer.surface, 0, 0);
cr.paint ();
shadow = new Cogl.Texture.from_data (width, height, 0, Cogl.PixelFormat.BGRA_8888_PRE,
Cogl.PixelFormat.ANY, surface.get_stride (), surface.get_data ());
shadow_cache.@set (key, shadow);
}
public override void paint (EffectPaintFlags flags)
{
var size = shadow_size * scale_factor;
Cogl.set_source_texture (shadow);
Cogl.rectangle (-size, -size, actor.width + size, actor.height + size);
actor.continue_paint ();
}
}
}

View File

@ -117,7 +117,7 @@ namespace Gala
return;
}
clone = new Clone (actor);
clone = new Clone (actor.get_texture ());
add_child (clone);
set_child_below_sibling (active_shape, clone);
@ -129,6 +129,8 @@ namespace Gala
set_position (outer_rect.x, outer_rect.y);
set_size (outer_rect.width, outer_rect.height);
add_effect_with_name ("shadow", new ShadowEffect (outer_rect.width, outer_rect.height, 40, 5));
// if we were waiting the view was most probably already opened when our window
// finally got available. So we fade-in and make sure we took the took place.
// If the slot is not available however, the view was probably closed while this
@ -191,6 +193,9 @@ namespace Gala
var outer_rect = window.get_outer_rect ();
var scale_factor = (float)width / outer_rect.width;
var shadow_effect = get_effect ("shadow") as ShadowEffect;
shadow_effect.scale_factor = scale_factor;
var alloc = ActorBox ();
alloc.set_origin ((input_rect.x - outer_rect.x) * scale_factor,
(input_rect.y - outer_rect.y) * scale_factor);
@ -300,7 +305,7 @@ namespace Gala
return;
var scale = hovered ? 0.1 : 0.4;
var opacity = hovered ? 50 : 255;
var opacity = hovered ? 100 : 255;
var mode = hovered ? AnimationMode.EASE_IN_OUT_BACK : AnimationMode.EASE_OUT_ELASTIC;
save_easing_state ();

View File

@ -9,7 +9,10 @@ namespace Gala
base (screen, screen.get_primary_monitor (),
BackgroundSettings.get_default ().schema);
add_effect (new BackgroundShadowEffect (screen));
var primary = screen.get_primary_monitor ();
var monitor_geom = screen.get_monitor_geometry (primary);
add_effect (new ShadowEffect (monitor_geom.width, monitor_geom.height, 40, 5));
}
public override void paint ()
@ -26,56 +29,6 @@ namespace Gala
}
}
class BackgroundShadowEffect : Effect
{
static Meta.Screen screen;
static Cogl.Texture? bitmap;
const int SHADOW_SIZE = 40;
const int SHADOW_OFFSET = 5;
static int width;
static int height;
public BackgroundShadowEffect (Meta.Screen _screen)
{
if (bitmap == null) {
screen = _screen;
var primary = screen.get_primary_monitor ();
var monitor_geom = screen.get_monitor_geometry (primary);
width = monitor_geom.width + SHADOW_SIZE * 2;
height = monitor_geom.height + SHADOW_SIZE * 2;
var buffer = new Granite.Drawing.BufferSurface (width, height);
buffer.context.rectangle (SHADOW_SIZE - SHADOW_OFFSET, SHADOW_SIZE - SHADOW_OFFSET,
monitor_geom.width + SHADOW_OFFSET * 2, monitor_geom.height + SHADOW_OFFSET * 2);
buffer.context.set_source_rgba (0, 0, 0, 0.5);
buffer.context.fill ();
buffer.exponential_blur (20);
var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, width, height);
var cr = new Cairo.Context (surface);
cr.set_source_surface (buffer.surface, 0, 0);
cr.paint ();
bitmap = new Cogl.Texture.from_data (width, height, 0, Cogl.PixelFormat.BGRA_8888_PRE,
Cogl.PixelFormat.ANY, surface.get_stride (), surface.get_data ());
}
}
public override void paint (EffectPaintFlags flags)
{
Cogl.set_source_texture (bitmap);
Cogl.rectangle (-SHADOW_SIZE, -SHADOW_SIZE, width - SHADOW_SIZE, height - SHADOW_SIZE);
actor.continue_paint ();
}
}
public class WorkspaceClone : Clutter.Actor
{
public static const int BOTTOM_OFFSET = 100;