diff --git a/data/gala.css b/data/gala.css index c8e347ba..8ff8562f 100644 --- a/data/gala.css +++ b/data/gala.css @@ -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); +} diff --git a/src/ShadowEffect.vala b/src/ShadowEffect.vala index 9e63facf..3c0779b9 100644 --- a/src/ShadowEffect.vala +++ b/src/ShadowEffect.vala @@ -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 shadow_cache; + static Gtk.StyleContext style_context; - static construct + class construct { shadow_cache = new Gee.HashMap (); + 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); diff --git a/src/Widgets/WindowClone.vala b/src/Widgets/WindowClone.vala index 82ea2341..26fd34d4 100644 --- a/src/Widgets/WindowClone.vala +++ b/src/Widgets/WindowClone.vala @@ -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); } diff --git a/src/Widgets/WorkspaceClone.vala b/src/Widgets/WorkspaceClone.vala index cb40869a..4a53e87a 100644 --- a/src/Widgets/WorkspaceClone.vala +++ b/src/Widgets/WorkspaceClone.vala @@ -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 ()