[gnome-shell] Implement -st-shadow for StWidget
- From: Florian Müllner <fmuellner src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-shell] Implement -st-shadow for StWidget
- Date: Tue, 5 Jan 2010 20:40:18 +0000 (UTC)
commit 2dfe113a4251ebfd89931dcaff45374748958193
Author: Florian Müllner <fmuellner src gnome org>
Date: Sat Nov 21 04:19:56 2009 +0100
Implement -st-shadow for StWidget
Add support for a new -st-shadow property, which is based loosely
on the CSS3 box-shadow property:
http://www.css3.info/preview/box-shadow/
It defers from the specification as follows:
* no multiple shadows
* the optional color argument may be placed anywhere
* the shape is not determined by the widget's bounding box,
but by the background-image property
https://bugzilla.gnome.org/show_bug.cgi?id=603691
src/Makefile-st.am | 4 +
src/st/st-shadow-texture.c | 274 ++++++++++++++++++++++++++++++++++++++++++++
src/st/st-shadow-texture.h | 30 +++++
src/st/st-shadow.c | 89 ++++++++++++++
src/st/st-shadow.h | 42 +++++++
src/st/st-theme-node.c | 89 ++++++++++++++
src/st/st-theme-node.h | 2 +
src/st/st-widget.c | 86 ++++++++++++++-
8 files changed, 614 insertions(+), 2 deletions(-)
---
diff --git a/src/Makefile-st.am b/src/Makefile-st.am
index bd7d15b..bf44016 100644
--- a/src/Makefile-st.am
+++ b/src/Makefile-st.am
@@ -83,6 +83,8 @@ st_source_h = \
st/st-scrollable.h \
st/st-scroll-bar.h \
st/st-scroll-view.h \
+ st/st-shadow-texture.h \
+ st/st-shadow.h \
st/st-subtexture.h \
st/st-table.h \
st/st-table-child.h \
@@ -122,6 +124,8 @@ st_source_c = \
st/st-scrollable.c \
st/st-scroll-bar.c \
st/st-scroll-view.c \
+ st/st-shadow-texture.c \
+ st/st-shadow.c \
st/st-subtexture.c \
st/st-table.c \
st/st-table-child.c \
diff --git a/src/st/st-shadow-texture.c b/src/st/st-shadow-texture.c
new file mode 100644
index 0000000..57090ba
--- /dev/null
+++ b/src/st/st-shadow-texture.c
@@ -0,0 +1,274 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#include <math.h>
+#include <string.h>
+
+#include "st-shadow-texture.h"
+
+/**
+ * SECTION: st-shadow-texture
+ * @short_description: a class for creating soft shadow textures
+ *
+ * #StShadowTexture is a #ClutterTexture holding a soft shadow texture for
+ * another #ClutterActor.
+ * It is used to implement the box-shadow property in StWidget and should
+ * not be used stand-alone.
+ */
+
+struct _StShadowTexture {
+ ClutterTexture parent;
+
+ CoglColor color;
+ gdouble sigma;
+ gdouble blur_radius;
+};
+
+struct _StShadowTextureClass {
+ ClutterTextureClass parent_class;
+};
+
+G_DEFINE_TYPE (StShadowTexture, st_shadow_texture, CLUTTER_TYPE_TEXTURE);
+
+static gdouble *
+calculate_gaussian_kernel (gdouble sigma, guint n_values)
+{
+ gdouble *ret, sum;
+ gdouble exp_divisor;
+ gint half, i;
+
+ g_return_val_if_fail ((int) sigma > 0, NULL);
+
+ half = n_values / 2;
+
+ ret = g_malloc (n_values * sizeof (gdouble));
+ sum = 0.0;
+
+ exp_divisor = 2 * sigma * sigma;
+
+ /* n_values of 1D Gauss function */
+ for (i = 0; i < n_values; i++)
+ {
+ ret[i] = exp (-(i - half) * (i - half) / exp_divisor);
+ sum += ret[i];
+ }
+
+ /* normalize */
+ for (i = 0; i < n_values; i++)
+ ret[i] /= sum;
+
+ return ret;
+}
+
+static void
+st_shadow_texture_create_shadow (StShadowTexture *st,
+ ClutterActor *actor)
+{
+ CoglHandle texture, material;
+ guchar *pixels_in, *pixels_out;
+ gint width_in, height_in, rowstride_in;
+ gint width_out, height_out, rowstride_out;
+
+ g_return_if_fail (ST_IS_SHADOW_TEXTURE (st));
+
+ /* Right now we only deal with actors of type ClutterTexture.
+ It would be nice to extend this to generic actors with some
+ clutter_texture_new_from_actor magic in the future */
+ g_return_if_fail (CLUTTER_IS_TEXTURE (actor));
+
+ texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (actor));
+ if (texture == COGL_INVALID_HANDLE)
+ return;
+
+ width_in = cogl_texture_get_width (texture);
+ height_in = cogl_texture_get_height (texture);
+ rowstride_in = (width_in + 3) & ~3;
+
+ pixels_in = g_malloc0 (rowstride_in * height_in);
+
+ cogl_texture_get_data (texture, COGL_PIXEL_FORMAT_A_8,
+ rowstride_in, pixels_in);
+ cogl_texture_unref (texture);
+
+ if ((guint) st->blur_radius == 0)
+ {
+ width_out = width_in;
+ height_out = height_in;
+ rowstride_out = rowstride_in;
+ pixels_out = g_memdup (pixels_in, rowstride_out * height_out);
+ }
+ else
+ {
+ gdouble *kernel;
+ guchar *line;
+ gint n_values, half;
+ gint x_in, y_in, x_out, y_out, i;
+
+ n_values = (gint) 5 * st->sigma;
+ half = n_values / 2;
+
+ width_out = width_in + 2 * half;
+ height_out = height_in + 2 * half;
+ rowstride_out = (width_out + 3) & ~3;
+
+ pixels_out = g_malloc0 (rowstride_out * height_out);
+ line = g_malloc0 (rowstride_out);
+
+ kernel = calculate_gaussian_kernel (st->sigma, n_values);
+
+ /* vertical blur */
+ for (x_in = 0; x_in < width_in; x_in++)
+ for (y_out = 0; y_out < height_out; y_out++)
+ {
+ guchar *pixel_in, *pixel_out;
+ gint i0, i1;
+
+ y_in = y_out - half;
+
+ /* We read from the source at 'y = y_in + i - half'; clamp the
+ * full i range [0, n_values) so that y is in [0, height_in).
+ */
+ i0 = MAX (half - y_in, 0);
+ i1 = MIN (height_in + half - y_in, n_values);
+
+ pixel_in = pixels_in + (y_in + i0 - half) * rowstride_in + x_in;
+ pixel_out = pixels_out + y_out * rowstride_out + (x_in + half);
+
+ for (i = i0; i < i1; i++)
+ {
+ *pixel_out += *pixel_in * kernel[i];
+ pixel_in += rowstride_in;
+ }
+ }
+
+ /* horizontal blur */
+ for (y_out = 0; y_out < height_out; y_out++)
+ {
+ memcpy (line, pixels_out + y_out * rowstride_out, rowstride_out);
+
+ for (x_out = 0; x_out < width_out; x_out++)
+ {
+ gint i0, i1;
+ guchar *pixel_out, *pixel_in;
+
+ /* We read from the source at 'x = x_out + i - half'; clamp the
+ * full i range [0, n_values) so that x is in [0, width_out).
+ */
+ i0 = MAX (half - x_out, 0);
+ i1 = MIN (width_out + half - x_out, n_values);
+
+ pixel_in = line + x_out + i0 - half;
+ pixel_out = pixels_out + rowstride_out * y_out + x_out;
+
+ *pixel_out = 0;
+ for (i = i0; i < i1; i++)
+ {
+ *pixel_out += *pixel_in * kernel[i];
+ pixel_in++;
+ }
+ }
+ }
+ g_free (kernel);
+ g_free (line);
+ }
+
+ material = cogl_material_new ();
+ texture = cogl_texture_new_from_data (width_out,
+ height_out,
+ COGL_TEXTURE_NONE,
+ COGL_PIXEL_FORMAT_A_8,
+ COGL_PIXEL_FORMAT_A_8,
+ rowstride_out,
+ pixels_out);
+
+ cogl_material_set_layer_combine_constant (material, 0, &st->color);
+ cogl_material_set_layer (material, 0, texture);
+
+ /* We ignore the material color, which encodes the overall opacity of the
+ * actor, so setting an ancestor of the shadow to partially opaque won't
+ * work. The easiest way to fix this would be to override paint(). */
+
+ cogl_material_set_layer_combine (material, 0,
+ "RGBA = MODULATE (CONSTANT, TEXTURE[A])",
+ NULL);
+
+ clutter_texture_set_cogl_material (CLUTTER_TEXTURE (st), material);
+
+ cogl_texture_unref (texture);
+ cogl_material_unref (material);
+
+ g_free (pixels_in);
+ g_free (pixels_out);
+}
+
+
+/**
+ * st_shadow_texture_adjust_allocation:
+ * @shadow: a #StShadowTexture
+ * @allocation: the original allocation of @shadow
+ *
+ * Adjust @allocation to account for size change caused by blurrimg
+ */
+void
+st_shadow_texture_adjust_allocation (StShadowTexture *shadow,
+ ClutterActorBox *allocation)
+{
+ g_return_if_fail (ST_IS_SHADOW_TEXTURE (shadow));
+ g_return_if_fail (allocation != NULL);
+
+ allocation->x1 -= shadow->blur_radius;
+ allocation->y1 -= shadow->blur_radius;
+ allocation->x2 += shadow->blur_radius;
+ allocation->y2 += shadow->blur_radius;
+}
+
+
+/**
+ * st_shadow_texture_new:
+ * @actor: the original actor
+ * @color: (allow-none): the shadow color
+ * @blur: the shadow's blur radius
+ *
+ * Create a shadow texture for @actor. When %NULL is passed for @color, it
+ * defaults to fully opaque black.
+ *
+ * Returns: a new #ClutterActor holding a shadow texture for @actor
+ */
+ClutterActor *
+st_shadow_texture_new (ClutterActor *actor,
+ ClutterColor *color,
+ gdouble blur)
+{
+ StShadowTexture *st = g_object_new (ST_TYPE_SHADOW_TEXTURE, NULL);
+
+ if (color)
+ {
+ cogl_color_set_from_4ub (&st->color,
+ color->red, color->green,
+ color->blue, color->alpha);
+ cogl_color_premultiply (&st->color);
+ }
+
+ st->blur_radius = blur;
+ /* we use an approximation of the sigma - blur radius relationship used
+ in Firefox for doing SVG blurs; see
+ http://mxr.mozilla.org/mozilla-central/source/gfx/thebes/src/gfxBlur.cpp#280
+ */
+ st->sigma = blur / 1.9;
+
+ st_shadow_texture_create_shadow (st, actor);
+
+ return CLUTTER_ACTOR (st);
+}
+
+static void
+st_shadow_texture_init (StShadowTexture *st)
+{
+ st->sigma = 0.0;
+ st->blur_radius = 0.0;
+
+ cogl_color_set_from_4ub (&st->color, 0x0, 0x0, 0x0, 0xff);
+}
+
+static void
+st_shadow_texture_class_init (StShadowTextureClass *klass)
+{
+}
diff --git a/src/st/st-shadow-texture.h b/src/st/st-shadow-texture.h
new file mode 100644
index 0000000..3f5b28a
--- /dev/null
+++ b/src/st/st-shadow-texture.h
@@ -0,0 +1,30 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#ifndef __ST_SHADOW_TEXTURE__
+#define __ST_SHADOW_TEXTURE__
+
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+typedef struct _StShadowTexture StShadowTexture;
+typedef struct _StShadowTextureClass StShadowTextureClass;
+
+#define ST_TYPE_SHADOW_TEXTURE (st_shadow_texture_get_type ())
+#define ST_SHADOW_TEXTURE(object) (G_TYPE_CHECK_INSTANCE_CAST((object),ST_TYPE_SHADOW_TEXTURE, StShadowTexture))
+#define ST_IS_SHADOW_TEXTURE(object) (G_TYPE_CHECK_INSTANCE_TYPE((object),ST_TYPE_SHADOW_TEXTURE))
+#define ST_SHADOW_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), ST_TYPE_SHADOW_TEXTURE, StShadowTextureClass))
+#define ST_IS_SHADOW_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), ST_TYPE_SHADOW_TEXTURE))
+#define ST_SHADOW_TEXTURE_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), ST_TYPE_SHADOW_TEXTURE, StShadowTextureClass))
+
+GType st_shadow_texture_get_type (void) G_GNUC_CONST;
+
+ClutterActor *st_shadow_texture_new (ClutterActor *actor,
+ ClutterColor *color,
+ gdouble blur_radius);
+
+void st_shadow_texture_adjust_allocation (StShadowTexture *shadow,
+ ClutterActorBox *allocation);
+
+G_END_DECLS
+
+#endif /* __ST_SHADOW_TEXTURE__ */
diff --git a/src/st/st-shadow.c b/src/st/st-shadow.c
new file mode 100644
index 0000000..0f11a6c
--- /dev/null
+++ b/src/st/st-shadow.c
@@ -0,0 +1,89 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#include "config.h"
+
+#include "st-shadow.h"
+
+/**
+ * SECTION: st-shadow
+ * @short_description: Boxed type for -st-shadow attributes
+ *
+ * #StShadow is a boxed type for storing attributes of the -st-shadow
+ * property, modelled liberally after the CSS3 box-shadow property.
+ * See http://www.css3.info/preview/box-shadow/
+ *
+ */
+
+/**
+ * st_shadow_new:
+ * @color: shadow's color
+ * @xoffset: horizontal offset
+ * @yoffset: vertical offset
+ * @blur: blur radius
+ *
+ * Creates a new #StShadow
+ *
+ * Returns: the newly allocated shadow. Use st_shadow_free() when done
+ */
+StShadow *
+st_shadow_new (ClutterColor *color,
+ gdouble xoffset,
+ gdouble yoffset,
+ gdouble blur)
+{
+ StShadow *shadow;
+
+ shadow = g_slice_new (StShadow);
+
+ shadow->color = *color;
+ shadow->xoffset = xoffset;
+ shadow->yoffset = yoffset;
+ shadow->blur = blur;
+
+ return shadow;
+}
+
+/**
+ * st_shadow_copy:
+ * @shadow: a #StShadow
+ *
+ * Makes a copy of @shadow.
+ *
+ * Returns: an allocated copy of @shadow - the result must be freed with
+ * st_shadow_free() when done
+ */
+StShadow *
+st_shadow_copy (const StShadow *shadow)
+{
+ g_return_val_if_fail (shadow != NULL, NULL);
+
+ return g_slice_dup (StShadow, shadow);
+}
+
+/**
+ * st_shadow_free:
+ * @shadow: a #StShadow
+ *
+ * Frees the shadow structure created with st_shadow_new() or
+ * st_shadow_copy()
+ */
+void
+st_shadow_free (StShadow *shadow)
+{
+ g_return_if_fail (shadow != NULL);
+
+ g_slice_free (StShadow, shadow);
+}
+
+GType
+st_shadow_get_type (void)
+{
+ static GType _st_shadow_type = 0;
+
+ if (G_UNLIKELY (_st_shadow_type == 0))
+ _st_shadow_type =
+ g_boxed_type_register_static ("StShadow",
+ (GBoxedCopyFunc) st_shadow_copy,
+ (GBoxedFreeFunc) st_shadow_free);
+
+ return _st_shadow_type;
+}
diff --git a/src/st/st-shadow.h b/src/st/st-shadow.h
new file mode 100644
index 0000000..cf5bffb
--- /dev/null
+++ b/src/st/st-shadow.h
@@ -0,0 +1,42 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#ifndef __ST_SHADOW__
+#define __ST_SHADOW__
+
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define ST_TYPE_SHADOW (st_shadow_get_type ())
+
+typedef struct _StShadow StShadow;
+
+/**
+ * StShadow:
+ * @color: shadow's color
+ * @xoffset: horizontal offset - positive values mean placement to the right,
+ * negative values placement to the left of the element.
+ * @yoffset: vertical offset - positive values mean placement below, negative
+ * values placement above the element.
+ * @blur: shadow's blur radius - a value of 0.0 will result in a hard shadow.
+ *
+ * Attributes of the -st-shadow property.
+ */
+struct _StShadow {
+ ClutterColor color;
+ gdouble xoffset;
+ gdouble yoffset;
+ gdouble blur;
+};
+
+GType st_shadow_get_type (void) G_GNUC_CONST;
+
+StShadow *st_shadow_new (ClutterColor *color,
+ gdouble xoffset,
+ gdouble yoffset,
+ gdouble blur);
+StShadow *st_shadow_copy (const StShadow *shadow);
+void st_shadow_free (StShadow *shadow);
+
+G_END_DECLS
+
+#endif /* __ST_SHADOW__ */
diff --git a/src/st/st-theme-node.c b/src/st/st-theme-node.c
index fb14c68..f8998e8 100644
--- a/src/st/st-theme-node.c
+++ b/src/st/st-theme-node.c
@@ -39,6 +39,7 @@ struct _StThemeNode {
char *background_image;
StBorderImage *border_image;
+ StShadow *shadow;
GType element_type;
char *element_id;
@@ -57,6 +58,7 @@ struct _StThemeNode {
guint background_computed : 1;
guint foreground_computed : 1;
guint border_image_computed : 1;
+ guint shadow_computed : 1;
guint link_type : 2;
};
@@ -118,6 +120,12 @@ st_theme_node_finalize (GObject *object)
node->border_image = NULL;
}
+ if (node->shadow)
+ {
+ st_shadow_free (node->shadow);
+ node->shadow = NULL;
+ }
+
if (node->background_image)
g_free (node->background_image);
@@ -2116,6 +2124,87 @@ st_theme_node_get_border_image (StThemeNode *node)
return NULL;
}
+/**
+ * st_theme_node_get_shadow:
+ * @node: a #StThemeNode
+ *
+ * Gets the value for the -st-shadow style property
+ *
+ * Return value: (transfer none): the node's shadow, or %NULL
+ * if node has no shadow
+ */
+StShadow *
+st_theme_node_get_shadow (StThemeNode *node)
+{
+ int i;
+
+ if (node->shadow_computed)
+ return node->shadow;
+
+ node->shadow = NULL;
+ node->shadow_computed = TRUE;
+
+ ensure_properties (node);
+
+ for (i = node->n_properties - 1; i >= 0; i--)
+ {
+ CRDeclaration *decl = node->properties[i];
+
+ if (strcmp (decl->property->stryng->str, "-st-shadow") == 0)
+ {
+ /* Set value for width/color/blur in any order */
+ CRTerm *term;
+ ClutterColor color = { 0x0, 0x0, 0x0, 0xff };
+ gdouble xoffset = 0.;
+ gdouble yoffset = 0.;
+ gdouble blur = 0.;
+ int n_offsets = 0;
+
+ for (term = decl->value; term; term = term->next)
+ {
+ GetFromTermResult result;
+
+ if (term->type == TERM_NUMBER)
+ {
+ gdouble value;
+ gdouble multiplier;
+
+ multiplier = (term->unary_op == MINUS_UOP) ? -1. : 1.;
+ result = get_length_from_term (node, term, FALSE, &value);
+ if (result != VALUE_NOT_FOUND)
+ {
+ switch (n_offsets++)
+ {
+ case 0:
+ xoffset = multiplier * value;
+ break;
+ case 1:
+ yoffset = multiplier * value;
+ break;
+ case 2:
+ if (multiplier < 0)
+ g_warning ("Negative blur values are "
+ "not allowed");
+ blur = value;
+ }
+ continue;
+ }
+ }
+
+ result = get_color_from_term (node, term, &color);
+ if (result != VALUE_NOT_FOUND)
+ {
+ continue;
+ }
+ }
+ node->shadow = st_shadow_new (&color, xoffset, yoffset, blur);
+
+ return node->shadow;
+ }
+ }
+ return NULL;
+}
+
static float
get_width_inc (StThemeNode *node)
{
diff --git a/src/st/st-theme-node.h b/src/st/st-theme-node.h
index 0f92214..31fb08e 100644
--- a/src/st/st-theme-node.h
+++ b/src/st/st-theme-node.h
@@ -4,6 +4,7 @@
#include <clutter/clutter.h>
#include "st-border-image.h"
+#include "st-shadow.h"
G_BEGIN_DECLS
@@ -142,6 +143,7 @@ StTextDecoration st_theme_node_get_text_decoration (StThemeNode *node);
const PangoFontDescription *st_theme_node_get_font (StThemeNode *node);
StBorderImage *st_theme_node_get_border_image (StThemeNode *node);
+StShadow *st_theme_node_get_shadow (StThemeNode *node);
/* Helpers for get_preferred_width()/get_preferred_height() ClutterActor vfuncs */
void st_theme_node_adjust_for_height (StThemeNode *node,
diff --git a/src/st/st-widget.c b/src/st/st-widget.c
index ba2c7a6..023be7d 100644
--- a/src/st/st-widget.c
+++ b/src/st/st-widget.c
@@ -37,6 +37,7 @@
#include "st-marshal.h"
#include "st-private.h"
+#include "st-shadow-texture.h"
#include "st-texture-cache.h"
#include "st-texture-frame.h"
#include "st-theme-context.h"
@@ -57,11 +58,15 @@ struct _StWidgetPrivate
ClutterActor *border_image;
ClutterActor *background_image;
+ ClutterActor *background_image_shadow;
ClutterColor bg_color;
StGradientType bg_gradient_type;
ClutterColor bg_gradient_end;
+ gdouble shadow_xoffset;
+ gdouble shadow_yoffset;
+
gboolean is_stylable : 1;
gboolean has_tooltip : 1;
gboolean is_style_dirty : 1;
@@ -227,6 +232,12 @@ st_widget_dispose (GObject *gobject)
priv->border_image = NULL;
}
+ if (priv->background_image_shadow)
+ {
+ clutter_actor_unparent (priv->background_image_shadow);
+ priv->background_image_shadow = NULL;
+ }
+
if (priv->tooltip)
{
ClutterContainer *parent;
@@ -356,6 +367,28 @@ st_widget_allocate (ClutterActor *actor,
frame_box.y2 = frame_box.y1 + h;
}
+ if (priv->background_image_shadow)
+ {
+ StShadowTexture *shadow;
+ ClutterActorBox shadow_box;
+
+ shadow_box.x1 = frame_box.x1 + priv->shadow_xoffset;
+ shadow_box.y1 = frame_box.y1 + priv->shadow_yoffset;
+ shadow_box.x2 = frame_box.x2 + priv->shadow_xoffset;
+ shadow_box.y2 = frame_box.y2 + priv->shadow_yoffset;
+
+ /* The shadow texture is larger than the original image due
+ to blurring, so we let it adjust its size.
+ When the original image has been scaled, this will change
+ the effective blur radius - we ignore this for now. */
+ shadow = ST_SHADOW_TEXTURE (priv->background_image_shadow);
+ st_shadow_texture_adjust_allocation (shadow, &shadow_box);
+
+ clutter_actor_allocate (priv->background_image_shadow,
+ &shadow_box, flags);
+ }
+
+
clutter_actor_allocate (CLUTTER_ACTOR (priv->background_image),
&frame_box,
flags);
@@ -497,7 +530,11 @@ st_widget_paint (ClutterActor *self)
klass->draw_background (ST_WIDGET (self));
if (priv->background_image != NULL)
- clutter_actor_paint (priv->background_image);
+ {
+ if (priv->background_image_shadow)
+ clutter_actor_paint (priv->background_image_shadow);
+ clutter_actor_paint (priv->background_image);
+ }
}
static void
@@ -527,6 +564,9 @@ st_widget_map (ClutterActor *actor)
st_widget_ensure_style ((StWidget*) actor);
+ if (priv->background_image_shadow)
+ clutter_actor_map (priv->background_image_shadow);
+
if (priv->border_image)
clutter_actor_map (priv->border_image);
@@ -544,6 +584,9 @@ st_widget_unmap (ClutterActor *actor)
CLUTTER_ACTOR_CLASS (st_widget_parent_class)->unmap (actor);
+ if (priv->background_image_shadow)
+ clutter_actor_unmap (priv->background_image_shadow);
+
if (priv->border_image)
clutter_actor_unmap (priv->border_image);
@@ -659,6 +702,7 @@ st_widget_real_style_changed (StWidget *self)
StWidgetPrivate *priv = ST_WIDGET (self)->priv;
StThemeNode *theme_node;
StBorderImage *border_image;
+ StShadow *shadow;
StTextureCache *texture_cache;
ClutterTexture *texture;
const char *bg_file = NULL;
@@ -706,6 +750,12 @@ st_widget_real_style_changed (StWidget *self)
has_changed = TRUE;
}
+ if (priv->background_image_shadow)
+ {
+ clutter_actor_unparent (priv->background_image_shadow);
+ priv->background_image_shadow = NULL;
+ }
+
if (priv->border_image)
{
clutter_actor_unparent (priv->border_image);
@@ -877,7 +927,39 @@ st_widget_real_style_changed (StWidget *self)
relayout_needed = TRUE;
}
- /* If there are any properties above that need to cause a relayout thay
+ /* CSS based drop shadows
+ *
+ * Drop shadows in ST are modelled after the CSS3 box-shadow property;
+ * see http://www.css3.info/preview/box-shadow/ for a detailed description.
+ *
+ * While the syntax of the property is mostly identical - we do not support
+ * multiple shadows and allow for a more liberal placement of the color
+ * parameter - its interpretation defers significantly in that the shadow's
+ * shape is not determined by the bounding box, but by the CSS background
+ * image (we could exend this in the future to take other CSS properties
+ * like boder and background color into account).
+ */
+ shadow = st_theme_node_get_shadow (theme_node);
+ if (shadow != NULL)
+ {
+ priv->shadow_xoffset = shadow->xoffset;
+ priv->shadow_yoffset = shadow->yoffset;
+
+ if (priv->background_image)
+ {
+ priv->background_image_shadow =
+ st_shadow_texture_new (priv->background_image,
+ &shadow->color,
+ shadow->blur);
+
+ clutter_actor_set_parent (priv->background_image_shadow,
+ CLUTTER_ACTOR (self));
+ has_changed = TRUE;
+ relayout_needed = TRUE;
+ }
+ }
+
+ /* If there are any properties above that need to cause a relayout they
* should set this flag.
*/
if (has_changed)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]