[gnome-shell] Implement box-shadow for StWidget
- From: Florian Müllner <fmuellner src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-shell] Implement box-shadow for StWidget
- Date: Sat, 19 Dec 2009 23:36:34 +0000 (UTC)
commit 5b11118a2697203248b71cc10cc163f2b3647145
Author: Florian Müllner <fmuellner src gnome org>
Date: Sat Nov 21 04:19:56 2009 +0100
Implement box-shadow for StWidget
Add support for 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 the element's other CSS properties - right now,
only for background-images a shadow is drawn; it may be
extended to more properties, if desired.
https://bugzilla.gnome.org/show_bug.cgi?id=603691
src/Makefile-st.am | 4 +
src/st/st-box-shadow.c | 89 +++++++++++++++
src/st/st-box-shadow.h | 42 +++++++
src/st/st-shadow-texture.c | 256 ++++++++++++++++++++++++++++++++++++++++++++
src/st/st-shadow-texture.h | 28 +++++
src/st/st-theme-node.c | 90 ++++++++++++++++
src/st/st-theme-node.h | 2 +
src/st/st-widget.c | 90 +++++++++++++++-
8 files changed, 599 insertions(+), 2 deletions(-)
---
diff --git a/src/Makefile-st.am b/src/Makefile-st.am
index bd7d15b..b93bf35 100644
--- a/src/Makefile-st.am
+++ b/src/Makefile-st.am
@@ -75,6 +75,7 @@ st_source_h = \
st/st-clickable.h \
st/st-clipboard.h \
st/st-drawing-area.h \
+ st/st-box-shadow.h \
st/st-entry.h \
st/st-im-text.h \
st/st-label.h \
@@ -83,6 +84,7 @@ st_source_h = \
st/st-scrollable.h \
st/st-scroll-bar.h \
st/st-scroll-view.h \
+ st/st-shadow-texture.h \
st/st-subtexture.h \
st/st-table.h \
st/st-table-child.h \
@@ -114,6 +116,7 @@ st_source_c = \
st/st-clickable.c \
st/st-clipboard.c \
st/st-drawing-area.c \
+ st/st-box-shadow.c \
st/st-entry.c \
st/st-im-text.c \
st/st-label.c \
@@ -122,6 +125,7 @@ st_source_c = \
st/st-scrollable.c \
st/st-scroll-bar.c \
st/st-scroll-view.c \
+ st/st-shadow-texture.c \
st/st-subtexture.c \
st/st-table.c \
st/st-table-child.c \
diff --git a/src/st/st-box-shadow.c b/src/st/st-box-shadow.c
new file mode 100644
index 0000000..5fc6a73
--- /dev/null
+++ b/src/st/st-box-shadow.c
@@ -0,0 +1,89 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#include "config.h"
+
+#include "st-box-shadow.h"
+
+/**
+ * SECTION: st-box-shadow
+ * @short_description: Boxed type for box-shadow attributes
+ *
+ * #StBoxShadow is a boxed type for storing attributes of the CSS3 box-shadow
+ * property.
+ * See http://www.css3.info/preview/box-shadow/
+ *
+ */
+
+/**
+ * st_box_shadow_new:
+ * @color: shadow's color
+ * @xoffset: horizontal offset
+ * @yoffset: vertical offset
+ * @blur: blur radius
+ *
+ * Creates a new #StBoxShadow
+ *
+ * Returns: the newly allocated shadow. Use st_box_shadow_free() when done
+ */
+StBoxShadow *
+st_box_shadow_new (ClutterColor *color,
+ gdouble xoffset,
+ gdouble yoffset,
+ gdouble blur)
+{
+ StBoxShadow *shadow;
+
+ shadow = g_slice_new (StBoxShadow);
+
+ shadow->color = *color;
+ shadow->xoffset = xoffset;
+ shadow->yoffset = yoffset;
+ shadow->blur = blur;
+
+ return shadow;
+}
+
+/**
+ * st_box_shadow_copy:
+ * @shadow: a #StBoxShadow
+ *
+ * Makes a copy of @shadow.
+ *
+ * Returns: an allocated copy of @shadow - the result must be freed with
+ * st_box_shadow_free() when done
+ */
+StBoxShadow *
+st_box_shadow_copy (const StBoxShadow *shadow)
+{
+ g_return_val_if_fail (shadow != NULL, NULL);
+
+ return g_slice_dup (StBoxShadow, shadow);
+}
+
+/**
+ * st_box_shadow_free:
+ * @shadow: a #StBoxShadow
+ *
+ * Frees the shadow structure created with st_box_shadow_new() or
+ * st_box_shadow_copy()
+ */
+void
+st_box_shadow_free (StBoxShadow *shadow)
+{
+ g_return_if_fail (shadow != NULL);
+
+ g_slice_free (StBoxShadow, shadow);
+}
+
+GType
+st_box_shadow_get_type (void)
+{
+ static GType _st_box_shadow_type = 0;
+
+ if (G_UNLIKELY (_st_box_shadow_type == 0))
+ _st_box_shadow_type =
+ g_boxed_type_register_static ("StBoxShadow",
+ (GBoxedCopyFunc) st_box_shadow_copy,
+ (GBoxedFreeFunc) st_box_shadow_free);
+
+ return _st_box_shadow_type;
+}
diff --git a/src/st/st-box-shadow.h b/src/st/st-box-shadow.h
new file mode 100644
index 0000000..579e6f2
--- /dev/null
+++ b/src/st/st-box-shadow.h
@@ -0,0 +1,42 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#ifndef __ST_BOX_SHADOW__
+#define __ST_BOX_SHADOW__
+
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define ST_TYPE_BOX_SHADOW (st_box_shadow_get_type ())
+
+typedef struct _StBoxShadow StBoxShadow;
+
+/**
+ * StBoxShadow:
+ * @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 box-shadow property.
+ */
+struct _StBoxShadow {
+ ClutterColor color;
+ gdouble xoffset;
+ gdouble yoffset;
+ gdouble blur;
+};
+
+GType st_box_shadow_get_type (void) G_GNUC_CONST;
+
+StBoxShadow *st_box_shadow_new (ClutterColor *color,
+ gdouble xoffset,
+ gdouble yoffset,
+ gdouble blur);
+StBoxShadow *st_box_shadow_copy (const StBoxShadow *shadow);
+void st_box_shadow_free (StBoxShadow *shadow);
+
+G_END_DECLS
+
+#endif /* __ST_BOX_SHADOW__ */
diff --git a/src/st/st-shadow-texture.c b/src/st/st-shadow-texture.c
new file mode 100644
index 0000000..842197e
--- /dev/null
+++ b/src/st/st-shadow-texture.c
@@ -0,0 +1,256 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#include <math.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;
+
+ guint blur_window;
+};
+
+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 gboolean
+st_shadow_texture_create_shadow (StShadowTexture *st,
+ ClutterActor *actor,
+ GError **error)
+{
+ CoglHandle texture, material;
+ guchar *pixels_in, *pixels_out;
+ gint width_in, height_in;
+ gint width_out, height_out;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (ST_IS_SHADOW_TEXTURE (st), FALSE);
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ /* 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_val_if_fail (CLUTTER_IS_TEXTURE (actor), FALSE);
+
+ texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (actor));
+ if (texture == COGL_INVALID_HANDLE)
+ return FALSE;
+
+ width_in = cogl_texture_get_width (texture);
+ height_in = cogl_texture_get_height (texture);
+
+ pixels_in = g_malloc0 (width_in * height_in);
+
+ cogl_texture_get_data (texture, COGL_PIXEL_FORMAT_A_8, width_in, pixels_in);
+ cogl_texture_unref (texture);
+
+ if ((guint) st->sigma == 0)
+ {
+ width_out = width_in;
+ height_out = height_in;
+ pixels_out = g_memdup (pixels_in, width_out * height_out);
+ }
+ else
+ {
+ gdouble *kernel;
+ gint n_values;
+ gint x, y, i;
+
+ n_values = 2 * st->blur_window + 1;
+
+ width_out = width_in + n_values;
+ height_out = height_in + n_values;
+
+ pixels_out = g_malloc0 (width_out * height_out);
+
+ kernel = calculate_gaussian_kernel (st->sigma, n_values);
+
+ /* vertical blur */
+ for (x = 0; x < width_in; x++)
+ for (y = 0; y < height_out; y++)
+ {
+ gint index = y * width_out + x + st->blur_window;
+
+ for (i = 0; i < n_values; i++)
+ {
+ gint _y = y + i - n_values;
+ gint _index = _y * width_in + x;
+
+ if (_y >= 0 && _y <= height_in)
+ pixels_out[index] += pixels_in[_index] * kernel[i];
+ }
+ }
+
+ /* horizontal blur */
+ for (y = 0; y < height_out; y++)
+ {
+ guchar *line = g_memdup (pixels_out + y * width_out, width_out);
+
+ for (x = 0; x < width_out; x++)
+ {
+ gint index = x + y * width_out;
+
+ pixels_out[index] = 0;
+ for (i = 0; i < n_values; i++)
+ {
+ gint _x = x + i - st->blur_window;
+
+ if (_x > 0 && _x < width_out)
+ pixels_out[index] += line[_x] * kernel[i];
+ }
+ }
+
+ g_free (line);
+ }
+ g_free (kernel);
+ }
+
+ 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,
+ width_out,
+ pixels_out);
+
+ cogl_material_set_layer_combine_constant (material, 0, &st->color);
+ cogl_material_set_layer (material, 0, texture);
+
+ success = cogl_material_set_layer_combine (material, 0,
+ "RGBA = MODULATE (CONSTANT,TEXTURE[A])",
+ error);
+
+ if (success)
+ {
+ 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);
+
+ return success;
+}
+
+
+/**
+ * st_shadow_texture_get_blur_window_size:
+ * @shadow: a #StShadowTexture
+ *
+ * Get the size of the window used in the convulsion
+ *
+ * Returns: the blur window size
+ */
+guint
+st_shadow_texture_get_blur_window_size (StShadowTexture *shadow)
+{
+ g_return_val_if_fail (ST_IS_SHADOW_TEXTURE (shadow), 0);
+
+ return shadow->blur_window;
+}
+
+
+/**
+ * st_shadow_texture_new:
+ * @actor: the original actor
+ * @color: (allow-none): the shadow color
+ * @sigma: 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 sigma)
+{
+ GError *error = NULL;
+ 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);
+ st->sigma = sigma;
+ st->blur_window = (guint) (5 * sigma - 2.5);
+
+ if (!st_shadow_texture_create_shadow (st, actor, &error))
+ {
+ if (error)
+ {
+ g_warning ("Failed to initialize shadow: %s", error->message);
+ g_error_free (error);
+ }
+ else
+ g_warning ("Failed to initialize shadow.");
+
+ g_object_unref (st);
+
+ return NULL;
+ }
+
+ return CLUTTER_ACTOR (st);
+}
+
+static void
+st_shadow_texture_init (StShadowTexture *st)
+{
+ st->sigma = 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..5e2ebf4
--- /dev/null
+++ b/src/st/st-shadow-texture.h
@@ -0,0 +1,28 @@
+/* -*- 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 sigma);
+guint st_shadow_texture_get_blur_window_size (StShadowTexture *shadow);
+
+G_END_DECLS
+
+#endif /* __ST_SHADOW_TEXTURE__ */
diff --git a/src/st/st-theme-node.c b/src/st/st-theme-node.c
index 29acbd8..e9f2585 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;
+ StBoxShadow *box_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 box_shadow_computed : 1;
guint link_type : 2;
};
@@ -118,6 +120,12 @@ st_theme_node_finalize (GObject *object)
node->border_image = NULL;
}
+ if (node->box_shadow)
+ {
+ st_box_shadow_free (node->box_shadow);
+ node->box_shadow = NULL;
+ }
+
if (node->background_image)
g_free (node->background_image);
@@ -2113,6 +2121,88 @@ st_theme_node_get_border_image (StThemeNode *node)
return NULL;
}
+/**
+ * st_theme_node_get_box_shadow:
+ * @node: a #StThemeNode
+ *
+ * Gets the value for the box-shadow style property
+ *
+ * Return value: (transfer none): the box shadow, or %NULL
+ * if there is no box shadow.
+ */
+StBoxShadow *
+st_theme_node_get_box_shadow (StThemeNode *node)
+{
+ int i;
+
+ if (node->box_shadow_computed)
+ return node->box_shadow;
+
+ node->box_shadow = NULL;
+ node->box_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, "box-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->box_shadow = st_box_shadow_new (&color,
+ xoffset, yoffset, blur);
+
+ return node->box_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..b46a75e 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-box-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);
+StBoxShadow *st_theme_node_get_box_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..29a8c32 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,30 @@ st_widget_allocate (ClutterActor *actor,
frame_box.y2 = frame_box.y1 + h;
}
+ if (priv->background_image_shadow)
+ {
+ StShadowTexture *shadow;
+ ClutterActorBox shadow_box;
+ gdouble blur_size;
+
+ /* To avoid sharp edges of the blurred texture, the shadow texture
+ is larger than the original texture - on each side, blur_window_size
+ pixels are added, which we have to consider for the allocation box.
+ A blur_size of the entire blur_window_size will make the shadow quite
+ massive though, so we use a fraction.
+ A factor of .5 seems to work reasonably well. */
+ shadow = ST_SHADOW_TEXTURE (priv->background_image_shadow);
+ blur_size = .5 * st_shadow_texture_get_blur_window_size (shadow);
+
+ shadow_box.x1 = frame_box.x1 - blur_size + priv->shadow_xoffset;
+ shadow_box.y1 = frame_box.y1 - blur_size + priv->shadow_yoffset;
+ shadow_box.x2 = frame_box.x2 + blur_size + priv->shadow_xoffset;
+ shadow_box.y2 = frame_box.y2 + blur_size + priv->shadow_yoffset;
+
+ clutter_actor_allocate (priv->background_image_shadow, &shadow_box, flags);
+ }
+
+
clutter_actor_allocate (CLUTTER_ACTOR (priv->background_image),
&frame_box,
flags);
@@ -497,7 +532,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 +566,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 +586,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 +704,7 @@ st_widget_real_style_changed (StWidget *self)
StWidgetPrivate *priv = ST_WIDGET (self)->priv;
StThemeNode *theme_node;
StBorderImage *border_image;
+ StBoxShadow *box_shadow;
StTextureCache *texture_cache;
ClutterTexture *texture;
const char *bg_file = NULL;
@@ -706,6 +752,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 +929,41 @@ 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 the element's other CSS properties.
+ *
+ * Note that the current implementation only takes the background-image property into
+ * account though.
+ */
+ box_shadow = st_theme_node_get_box_shadow (theme_node);
+ if (box_shadow != NULL)
+ {
+ priv->shadow_xoffset = box_shadow->xoffset;
+ priv->shadow_yoffset = box_shadow->yoffset;
+
+ if (priv->background_image)
+ priv->background_image_shadow =
+ st_shadow_texture_new (priv->background_image,
+ &box_shadow->color,
+ box_shadow->blur);
+
+ if (priv->background_image_shadow)
+ {
+ 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]