gnome-shell-3.6.3.1/src/st/st-shadow.c

No issues found

  1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
  2 /*
  3  * st-shadow.c: Boxed type holding for -st-shadow attributes
  4  *
  5  * Copyright 2009, 2010 Florian Mç«Żllner
  6  *
  7  * This program is free software; you can redistribute it and/or modify
  8  * it under the terms of the GNU Lesser General Public License as
  9  * published by the Free Software Foundation, either version 2.1 of
 10  * the License, or (at your option) any later version.
 11  *
 12  * This program is distributed in the hope it will be useful, but WITHOUT ANY
 13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 14  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 15  * more details.
 16  *
 17  * You should have received a copy of the GNU Lesser General Public License
 18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
 19  */
 20 
 21 #include "config.h"
 22 
 23 #include "st-shadow.h"
 24 #include "st-private.h"
 25 
 26 G_DEFINE_BOXED_TYPE (StShadow, st_shadow, st_shadow_ref, st_shadow_unref)
 27 G_DEFINE_BOXED_TYPE (StShadowHelper, st_shadow_helper, st_shadow_helper_copy, st_shadow_helper_free)
 28 
 29 /**
 30  * SECTION: st-shadow
 31  * @short_description: Boxed type for -st-shadow attributes
 32  *
 33  * #StShadow is a boxed type for storing attributes of the -st-shadow
 34  * property, modelled liberally after the CSS3 box-shadow property.
 35  * See http://www.css3.info/preview/box-shadow/
 36  *
 37  */
 38 
 39 /**
 40  * st_shadow_new:
 41  * @color: shadow's color
 42  * @xoffset: horizontal offset
 43  * @yoffset: vertical offset
 44  * @blur: blur radius
 45  * @spread: spread radius
 46  * @inset: whether the shadow should be inset
 47  *
 48  * Creates a new #StShadow
 49  *
 50  * Returns: the newly allocated shadow. Use st_shadow_free() when done
 51  */
 52 StShadow *
 53 st_shadow_new (ClutterColor *color,
 54                gdouble       xoffset,
 55                gdouble       yoffset,
 56                gdouble       blur,
 57                gdouble       spread,
 58                gboolean      inset)
 59 {
 60   StShadow *shadow;
 61 
 62   shadow = g_slice_new (StShadow);
 63 
 64   shadow->color     = *color;
 65   shadow->xoffset   = xoffset;
 66   shadow->yoffset   = yoffset;
 67   shadow->blur      = blur;
 68   shadow->spread    = spread;
 69   shadow->inset     = inset;
 70   shadow->ref_count = 1;
 71 
 72   return shadow;
 73 }
 74 
 75 /**
 76  * st_shadow_ref:
 77  * @shadow: a #StShadow
 78  *
 79  * Atomically increments the reference count of @shadow by one.
 80  *
 81  * Returns: the passed in #StShadow.
 82  */
 83 StShadow *
 84 st_shadow_ref (StShadow *shadow)
 85 {
 86   g_return_val_if_fail (shadow != NULL, NULL);
 87   g_return_val_if_fail (shadow->ref_count > 0, shadow);
 88 
 89   g_atomic_int_inc (&shadow->ref_count);
 90   return shadow;
 91 }
 92 
 93 /**
 94  * st_shadow_unref:
 95  * @shadow: a #StShadow
 96  *
 97  * Atomically decrements the reference count of @shadow by one.
 98  * If the reference count drops to 0, all memory allocated by the
 99  * #StShadow is released.
100  */
101 void
102 st_shadow_unref (StShadow *shadow)
103 {
104   g_return_if_fail (shadow != NULL);
105   g_return_if_fail (shadow->ref_count > 0);
106 
107   if (g_atomic_int_dec_and_test (&shadow->ref_count))
108     g_slice_free (StShadow, shadow);
109 }
110 
111 /**
112  * st_shadow_equal:
113  * @shadow: a #StShadow
114  * @other: a different #StShadow
115  *
116  * Check if two shadow objects are identical. Note that two shadows may
117  * compare non-identically if they differ only by floating point rounding
118  * errors.
119  *
120  * Return value: %TRUE if the two shadows are identical
121  */
122 gboolean
123 st_shadow_equal (StShadow *shadow,
124                  StShadow *other)
125 {
126   g_return_val_if_fail (shadow != NULL, FALSE);
127   g_return_val_if_fail (other != NULL, FALSE);
128 
129   /* We use strict equality to compare double quantities; this means
130    * that, for example, a shadow offset of 0.25in does not necessarily
131    * compare equal to a shadow offset of 18pt in this test. Assume
132    * that a few false negatives are mostly harmless.
133    */
134 
135   return (clutter_color_equal (&shadow->color, &other->color) &&
136           shadow->xoffset == other->xoffset &&
137           shadow->yoffset == other->yoffset &&
138           shadow->blur == other->blur &&
139           shadow->spread == other->spread &&
140           shadow->inset == other->inset);
141 }
142 
143 /**
144  * st_shadow_get_box:
145  * @shadow: a #StShadow
146  * @actor_box: the box allocated to a #ClutterAlctor
147  * @shadow_box: computed box occupied by @shadow
148  *
149  * Gets the box used to paint @shadow, which will be partly
150  * outside of @actor_box
151  */
152 void
153 st_shadow_get_box (StShadow              *shadow,
154                    const ClutterActorBox *actor_box,
155                    ClutterActorBox       *shadow_box)
156 {
157   g_return_if_fail (shadow != NULL);
158   g_return_if_fail (actor_box != NULL);
159   g_return_if_fail (shadow_box != NULL);
160 
161   /* Inset shadows are drawn below the border, so returning
162    * the original box is not actually correct; still, it's
163    * good enough for the purpose of determing additional space
164    * required outside the actor box.
165    */
166   if (shadow->inset)
167     {
168       *shadow_box = *actor_box;
169       return;
170     }
171 
172   shadow_box->x1 = actor_box->x1 + shadow->xoffset
173                    - shadow->blur - shadow->spread;
174   shadow_box->x2 = actor_box->x2 + shadow->xoffset
175                    + shadow->blur + shadow->spread;
176   shadow_box->y1 = actor_box->y1 + shadow->yoffset
177                    - shadow->blur - shadow->spread;
178   shadow_box->y2 = actor_box->y2 + shadow->yoffset
179                    + shadow->blur + shadow->spread;
180 }
181 
182 /**
183  * SECTION:st-shadow-helper:
184  *
185  * An helper for implementing a drop shadow on a actor.
186  * The actor is expected to recreate the helper whenever its contents
187  * or size change. Then, it would call st_shadow_helper_paint() inside
188  * its paint() virtual function.
189  */
190 
191 struct _StShadowHelper {
192   StShadow     *shadow;
193   CoglMaterial *material;
194 
195   gfloat        width;
196   gfloat        height;
197 };
198 
199 /**
200  * st_shadow_helper_new:
201  * @shadow: a #StShadow representing the shadow properties
202  *
203  * Builds a #StShadowHelper that will build a drop shadow
204  * using @source as the mask.
205  *
206  * Returns: (transfer full): a new #StShadowHelper
207  */
208 StShadowHelper *
209 st_shadow_helper_new (StShadow     *shadow)
210 {
211   StShadowHelper *helper;
212 
213   helper = g_slice_new0 (StShadowHelper);
214   helper->shadow = st_shadow_ref (shadow);
215 
216   return helper;
217 }
218 
219 void
220 st_shadow_helper_update (StShadowHelper *helper,
221                          ClutterActor   *source)
222 {
223   gfloat width, height;
224 
225   clutter_actor_get_size (source, &width, &height);
226 
227   if (helper->material == NULL ||
228       helper->width != width ||
229       helper->height != height)
230     {
231       if (helper->material)
232         cogl_object_unref (helper->material);
233 
234       helper->material = _st_create_shadow_material_from_actor (helper->shadow, source);
235       helper->width = width;
236       helper->height = height;
237     }
238 }
239 
240 /**
241  * st_shadow_helper_copy:
242  * @helper: the #StShadowHelper to copy
243  *
244  * Returns: (transfer full): a copy of @helper
245  */
246 StShadowHelper *
247 st_shadow_helper_copy (StShadowHelper *helper)
248 {
249   StShadowHelper *copy;
250 
251   copy = g_slice_new (StShadowHelper);
252   *copy = *helper;
253   if (copy->material)
254     cogl_object_ref (copy->material);
255   st_shadow_ref (copy->shadow);
256 
257   return copy;
258 }
259 
260 /**
261  * st_shadow_helper_free:
262  * @helper: a #StShadowHelper
263  *
264  * Free resources associated with @helper.
265  */
266 void
267 st_shadow_helper_free (StShadowHelper *helper)
268 {
269   if (helper->material)
270     cogl_object_unref (helper->material);
271   st_shadow_unref (helper->shadow);
272 
273   g_slice_free (StShadowHelper, helper);
274 }
275 
276 /**
277  * st_shadow_helper_paint:
278  * @helper: a #StShadowHelper
279  * @actor_box: the bounding box of the shadow
280  * @paint_opacity: the opacity at which the shadow is painted
281  *
282  * Paints the shadow associated with @helper This must only
283  * be called from the implementation of ClutterActor::paint().
284  */
285 void
286 st_shadow_helper_paint (StShadowHelper  *helper,
287                         ClutterActorBox *actor_box,
288                         guint8           paint_opacity)
289 {
290   ClutterActorBox allocation;
291   float width, height;
292 
293   clutter_actor_box_get_size (actor_box, &width, &height);
294 
295   allocation.x1 = (width - helper->width) / 2;
296   allocation.y1 = (height - helper->height) / 2;
297   allocation.x2 = allocation.x1 + helper->width;
298   allocation.y2 = allocation.y1 + helper->height;
299 
300   _st_paint_shadow_with_opacity (helper->shadow,
301                                  helper->material,
302                                  &allocation,
303                                  paint_opacity);
304 }