[color] allow alpha to omitted when converting from strings
[profile/ivi/clutter.git] / clutter / clutter-color.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006 OpenedHand
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */
25
26 /**
27  * SECTION:clutter-color
28  * @short_description: Color management and manipulation.
29  *
30  * #ClutterColor is a simple type for representing colors in Clutter.
31  *
32  * A #ClutterColor is expressed as a 4-tuple of values ranging from
33  * zero to 255, one for each color channel plus one for the alpha.
34  */
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <pango/pango-attributes.h>
41 #include <gobject/gvaluecollector.h>
42
43 #include "clutter-main.h"
44 #include "clutter-color.h"
45 #include "clutter-private.h"
46 #include "clutter-debug.h"
47
48 /**
49  * clutter_color_add:
50  * @a: a #ClutterColor
51  * @b: a #ClutterColor
52  * @result: (out): return location for the result
53  *
54  * Adds @a to @b and saves the resulting color inside @result.
55  *
56  * The alpha channel of @result is set as as the maximum value
57  * between the alpha channels of @a and @b.
58  */
59 void
60 clutter_color_add (const ClutterColor *a,
61                    const ClutterColor *b,
62                    ClutterColor       *result)
63 {
64   g_return_if_fail (a != NULL);
65   g_return_if_fail (b != NULL);
66   g_return_if_fail (result != NULL);
67
68   result->red   = CLAMP (a->red   + b->red,   0, 255);
69   result->green = CLAMP (a->green + b->green, 0, 255);
70   result->blue  = CLAMP (a->blue  + b->blue,  0, 255);
71
72   result->alpha = MAX (a->alpha, b->alpha);
73 }
74
75 /**
76  * clutter_color_subtract:
77  * @a: a #ClutterColor
78  * @b: a #ClutterColor
79  * @result: (out): return location for the result
80  *
81  * Subtracts @b from @a and saves the resulting color inside @result.
82  *
83  * This function assumes that the components of @a are greater than the
84  * components of @b; the result is, otherwise, undefined.
85  *
86  * The alpha channel of @result is set as the minimum value
87  * between the alpha channels of @a and @b.
88  */
89 void
90 clutter_color_subtract (const ClutterColor *a,
91                         const ClutterColor *b,
92                         ClutterColor       *result)
93 {
94   g_return_if_fail (a != NULL);
95   g_return_if_fail (b != NULL);
96   g_return_if_fail (result != NULL);
97
98   result->red   = CLAMP (a->red   - b->red,   0, 255);
99   result->green = CLAMP (a->green - b->green, 0, 255);
100   result->blue  = CLAMP (a->blue  - b->blue,  0, 255);
101
102   result->alpha = MIN (a->alpha, b->alpha);
103 }
104
105 /**
106  * clutter_color_lighten:
107  * @color: a #ClutterColor
108  * @result: (out): return location for the lighter color
109  *
110  * Lightens @color by a fixed amount, and saves the changed color
111  * in @result.
112  */
113 void
114 clutter_color_lighten (const ClutterColor *color,
115                        ClutterColor       *result)
116 {
117   clutter_color_shade (color, 1.3, result);
118 }
119
120 /**
121  * clutter_color_darken:
122  * @color: a #ClutterColor
123  * @result: (out): return location for the darker color
124  *
125  * Darkens @color by a fixed amount, and saves the changed color
126  * in @result.
127  */
128 void
129 clutter_color_darken (const ClutterColor *color,
130                       ClutterColor       *result)
131 {
132   clutter_color_shade (color, 0.7, result);
133 }
134
135 /**
136  * clutter_color_to_hls:
137  * @color: a #ClutterColor
138  * @hue: return location for the hue value or %NULL
139  * @luminance: return location for the luminance value or %NULL
140  * @saturation: return location for the saturation value or %NULL
141  *
142  * Converts @color to the HLS format.
143  *
144  * The @hue value is in the 0 .. 360 range. The @luminance and
145  * @saturation values are in the 0 .. 1 range.
146  */
147 void
148 clutter_color_to_hls (const ClutterColor *color,
149                       float              *hue,
150                       float              *luminance,
151                       float              *saturation)
152 {
153   float red, green, blue;
154   float min, max, delta;
155   float h, l, s;
156   
157   g_return_if_fail (color != NULL);
158
159   red   = color->red / 255.0;
160   green = color->green / 255.0;
161   blue  = color->blue / 255.0;
162
163   if (red > green)
164     {
165       if (red > blue)
166         max = red;
167       else
168         max = blue;
169
170       if (green < blue)
171         min = green;
172       else
173         min = blue;
174     }
175   else
176     {
177       if (green > blue)
178         max = green;
179       else
180         max = blue;
181
182       if (red < blue)
183         min = red;
184       else
185         min = blue;
186     }
187
188   l = (max + min) / 2;
189   s = 0;
190   h = 0;
191
192   if (max != min)
193     {
194       if (l <= 0.5)
195         s = (max - min) / (max + min);
196       else
197         s = (max - min) / (2.0 - max - min);
198
199       delta = max - min;
200
201       if (red == max)
202         h = (green - blue) / delta;
203       else if (green == max)
204         h = 2.0 + (blue - red) / delta;
205       else if (blue == max)
206         h = 4.0 + (red - green) / delta;
207
208       h *= 60;
209
210       if (h < 0)
211         h += 360.0;
212     }
213
214   if (hue)
215     *hue = h;
216
217   if (luminance)
218     *luminance = l;
219
220   if (saturation)
221     *saturation = s;
222 }
223
224 /**
225  * clutter_color_from_hls:
226  * @color: (out): return location for a #ClutterColor
227  * @hue: hue value, in the 0 .. 360 range
228  * @luminance: luminance value, in the 0 .. 1 range
229  * @saturation: saturation value, in the 0 .. 1 range
230  *
231  * Converts a color expressed in HLS (hue, luminance and saturation)
232  * values into a #ClutterColor.
233  */
234 void
235 clutter_color_from_hls (ClutterColor *color,
236                         float         hue,
237                         float         luminance,
238                         float         saturation)
239 {
240   float tmp1, tmp2;
241   float tmp3[3];
242   float clr[3];
243   int   i;
244
245   hue /= 360.0;
246
247   if (saturation == 0)
248     {
249       color->red = color->green = color->blue = (luminance * 255);
250
251       return;
252     }
253
254   if (luminance <= 0.5)
255     tmp2 = luminance * (1.0 + saturation);
256   else
257     tmp2 = luminance + saturation - (luminance * saturation);
258
259   tmp1 = 2.0 * luminance - tmp2;
260
261   tmp3[0] = hue + 1.0 / 3.0;
262   tmp3[1] = hue;
263   tmp3[2] = hue - 1.0 / 3.0;
264
265   for (i = 0; i < 3; i++)
266     {
267       if (tmp3[i] < 0)
268         tmp3[i] += 1.0;
269
270       if (tmp3[i] > 1)
271         tmp3[i] -= 1.0;
272
273       if (6.0 * tmp3[i] < 1.0)
274         clr[i] = tmp1 + (tmp2 - tmp1) * tmp3[i] * 6.0;
275       else if (2.0 * tmp3[i] < 1.0)
276         clr[i] = tmp2;
277       else if (3.0 * tmp3[i] < 2.0)
278         clr[i] = (tmp1 + (tmp2 - tmp1) * ((2.0 / 3.0) - tmp3[i]) * 6.0);
279       else
280         clr[i] = tmp1;
281     }
282
283   color->red   = clr[0] * 255.0;
284   color->green = clr[1] * 255.0;
285   color->blue  = clr[2] * 255.0;
286 }
287
288 /**
289  * clutter_color_shade:
290  * @color: a #ClutterColor
291  * @factor: the shade factor to apply
292  * @result: (out): return location for the shaded color
293  *
294  * Shades @color by @factor and saves the modified color into @result.
295  */
296 void
297 clutter_color_shade (const ClutterColor *color,
298                      gdouble             factor,
299                      ClutterColor       *result)
300 {
301   float h, l, s;
302
303   g_return_if_fail (color != NULL);
304   g_return_if_fail (result != NULL);
305   
306   clutter_color_to_hls (color, &h, &l, &s);
307
308   l *= factor;
309   if (l > 1.0)
310     l = 1.0;
311   else if (l < 0)
312     l = 0;
313
314   s *= factor;
315   if (s > 1.0)
316     s = 1.0;
317   else if (s < 0)
318     s = 0;
319   
320   clutter_color_from_hls (result, h, l, s);
321
322   result->alpha = color->alpha;
323 }
324
325 /**
326  * clutter_color_to_pixel:
327  * @color: a #ClutterColor
328  *
329  * Converts @color into a packed 32 bit integer, containing
330  * all the four 8 bit channels used by #ClutterColor.
331  *
332  * Return value: a packed color
333  */
334 guint32
335 clutter_color_to_pixel (const ClutterColor *color)
336 {
337   g_return_val_if_fail (color != NULL, 0);
338   
339   return (color->alpha       |
340           color->blue  << 8  |
341           color->green << 16 |
342           color->red   << 24);
343 }
344
345 /**
346  * clutter_color_from_pixel:
347  * @color: (out): return location for a #ClutterColor
348  * @pixel: a 32 bit packed integer containing a color
349  *
350  * Converts @pixel from the packed representation of a four 8 bit channel
351  * color to a #ClutterColor.
352  */
353 void
354 clutter_color_from_pixel (ClutterColor *color,
355                           guint32       pixel)
356 {
357   g_return_if_fail (color != NULL);
358
359   color->red   =  pixel >> 24;
360   color->green = (pixel >> 16) & 0xff;
361   color->blue  = (pixel >> 8)  & 0xff;
362   color->alpha =  pixel        & 0xff;
363 }
364
365 /**
366  * clutter_color_from_string:
367  * @color: (out): return location for a #ClutterColor
368  * @str: a string specifiying a color (named color or #RRGGBBAA)
369  *
370  * Parses a string definition of a color, filling the
371  * <structfield>red</structfield>, <structfield>green</structfield>, 
372  * <structfield>blue</structfield> and <structfield>alpha</structfield> 
373  * channels of @color. If alpha is not specified it will be set full opaque.
374  *
375  * The @color is not allocated.
376  *
377  * The color may be defined by any of the formats understood by
378  * pango_color_from_string(); these include literal color names, like
379  * <literal>Red</literal> or <literal>DarkSlateGray</literal>, or
380  * hexadecimal specifications like <literal>&num;3050b2</literal> or
381  * <literal>&num;333</literal>.
382  *
383  * Return value: %TRUE if parsing succeeded.
384  *
385  * Since: 1.0
386  */
387 gboolean
388 clutter_color_from_string (ClutterColor *color,
389                            const gchar  *str)
390 {
391   PangoColor pango_color = { 0, };
392
393   g_return_val_if_fail (color != NULL, FALSE);
394   g_return_val_if_fail (str != NULL, FALSE);
395
396   /* if the string contains a color encoded using the hexadecimal
397    * notations (#rrggbbaa or #rgba) we attempt a rough pass at
398    * parsing the color ourselves, as we need the alpha channel that
399    * Pango can't retrieve.
400    */
401   if (str[0] == '#')
402     {
403       gint32 result;
404
405       if (sscanf (str + 1, "%x", &result))
406         {
407           if (strlen (str) == 9)
408             {
409               /* #rrggbbaa */
410               color->red   = (result >> 24) & 0xff;
411               color->green = (result >> 16) & 0xff;
412               color->blue  = (result >>  8) & 0xff;
413
414               color->alpha = result & 0xff;
415
416               return TRUE;
417             }
418           else if (strlen (str) == 5)
419             {
420               /* #rgba */
421               color->red   = ((result >> 12) & 0xf);
422               color->green = ((result >>  8) & 0xf);
423               color->blue  = ((result >>  4) & 0xf);
424               color->alpha = result & 0xf;
425
426               color->red   = (color->red   << 4) | color->red;
427               color->green = (color->green << 4) | color->green;
428               color->blue  = (color->blue  << 4) | color->blue;
429               color->alpha = (color->alpha << 4) | color->alpha;
430
431               return TRUE;
432             }
433           else if (strlen (str) == 7)
434             {
435               /* #rrggbb */
436               color->red   = (result >> 24) & 0xff;
437               color->green = (result >> 16) & 0xff;
438               color->blue  = (result >>  8) & 0xff;
439
440               color->alpha = 0xff;
441             }
442           else if (strlen (str) == 4)
443             {
444               /* #rgb */
445               color->red   = ((result >> 12) & 0xf);
446               color->green = ((result >>  8) & 0xf);
447               color->blue  = ((result >>  4) & 0xf);
448
449               color->red   = (color->red   << 4) | color->red;
450               color->green = (color->green << 4) | color->green;
451               color->blue  = (color->blue  << 4) | color->blue;
452
453               color->alpha = 0xff;
454             }
455         }
456     }
457   
458   /* Fall back to pango for named colors */
459   if (pango_color_parse (&pango_color, str))
460     {
461       color->red   = pango_color.red;
462       color->green = pango_color.green;
463       color->blue  = pango_color.blue;
464
465       color->alpha = 0xff;
466
467       return TRUE;
468     }
469
470   return FALSE;
471 }
472
473 /**
474  * clutter_color_to_string:
475  * @color: a #ClutterColor
476  *
477  * Returns a textual specification of @color in the hexadecimal form
478  * <literal>&num;rrggbbaa</literal>, where <literal>r</literal>,
479  * <literal>g</literal>, <literal>b</literal> and <literal>a</literal> are
480  * hex digits representing the red, green, blue and alpha components
481  * respectively.
482  *
483  * Return value: a newly-allocated text string
484  *
485  * Since: 0.2
486  */
487 gchar *
488 clutter_color_to_string (const ClutterColor *color)
489 {
490   g_return_val_if_fail (color != NULL, NULL);
491
492   return g_strdup_printf ("#%02x%02x%02x%02x",
493                           color->red,
494                           color->green,
495                           color->blue,
496                           color->alpha);
497 }
498
499 /**
500  * clutter_color_equal:
501  * @v1: a #ClutterColor
502  * @v2: a #ClutterColor
503  *
504  * Compares two #ClutterColor<!-- -->s and checks if they are the same.
505  *
506  * This function can be passed to g_hash_table_new() as the @key_equal_func
507  * parameter, when using #ClutterColor<!-- -->s as keys in a #GHashTable.
508  *
509  * Return value: %TRUE if the two colors are the same.
510  *
511  * Since: 0.2
512  */
513 gboolean
514 clutter_color_equal (gconstpointer v1,
515                      gconstpointer v2)
516 {
517   const ClutterColor *a, *b;
518
519   g_return_val_if_fail (v1 != NULL, FALSE);
520   g_return_val_if_fail (v2 != NULL, FALSE);
521
522   if (v1 == v2)
523     return TRUE;
524
525   a = v1;
526   b = v2;
527
528   return (a->red   == b->red   &&
529           a->green == b->green &&
530           a->blue  == b->blue  &&
531           a->alpha == b->alpha);
532 }
533
534 /**
535  * clutter_color_hash:
536  * @v: a #ClutterColor
537  *
538  * Converts a #ClutterColor to a hash value.
539  *
540  * This function can be passed to g_hash_table_new() as the @hash_func
541  * parameter, when using #ClutterColor<!-- -->s as keys in a #GHashTable.
542  *
543  * Return value: a hash value corresponding to the color
544  *
545  * Since: 1.0
546  */
547 guint
548 clutter_color_hash (gconstpointer v)
549 {
550   return clutter_color_to_pixel ((const ClutterColor *) v);
551 }
552
553 /**
554  * clutter_color_copy:
555  * @color: a #ClutterColor
556  *
557  * Makes a copy of the color structure.  The result must be
558  * freed using clutter_color_free().
559  *
560  * Return value: an allocated copy of @color.
561  *
562  * Since: 0.2
563  */
564 ClutterColor *
565 clutter_color_copy (const ClutterColor *color)
566 {
567   if (G_LIKELY (color != NULL))
568     return g_slice_dup (ClutterColor, color);
569
570   return NULL;
571 }
572
573 /**
574  * clutter_color_free:
575  * @color: a #ClutterColor
576  *
577  * Frees a color structure created with clutter_color_copy().
578  *
579  * Since: 0.2
580  */
581 void
582 clutter_color_free (ClutterColor *color)
583 {
584   if (G_LIKELY (color != NULL))
585     g_slice_free (ClutterColor, color);
586 }
587
588 /**
589  * clutter_color_new:
590  * @red: red component of the color, between 0 and 255
591  * @green: green component of the color, between 0 and 255
592  * @blue: blue component of the color, between 0 and 255
593  * @alpha: alpha component of the color, between 0 and 255
594  *
595  * Creates a new #ClutterColor with the given values.
596  *
597  * Return value: the newly allocated color. Use clutter_color_free()
598  *   when done
599  *
600  * Since: 0.8.4
601  */
602 ClutterColor *
603 clutter_color_new (guint8 red,
604                    guint8 green,
605                    guint8 blue,
606                    guint8 alpha)
607 {
608   ClutterColor *color;
609
610   color = g_slice_new (ClutterColor);
611
612   color->red   = red;
613   color->green = green;
614   color->blue  = blue;
615   color->alpha = alpha;
616
617   return color;
618 }
619
620 static void
621 clutter_value_transform_color_string (const GValue *src,
622                                       GValue       *dest)
623 {
624   gchar *string = clutter_color_to_string (src->data[0].v_pointer);
625
626   g_value_take_string (dest, string);
627 }
628
629 static void
630 clutter_value_transform_string_color (const GValue *src,
631                                       GValue       *dest)
632 {
633   ClutterColor color = { 0, };
634
635   clutter_color_from_string (&color, g_value_get_string (src));
636
637   clutter_value_set_color (dest, &color);
638 }
639
640 GType
641 clutter_color_get_type (void)
642 {
643   static GType _clutter_color_type = 0;
644   
645   if (G_UNLIKELY (_clutter_color_type == 0))
646     {
647        _clutter_color_type =
648          g_boxed_type_register_static (I_("ClutterColor"),
649                                        (GBoxedCopyFunc) clutter_color_copy,
650                                        (GBoxedFreeFunc) clutter_color_free);
651
652        g_value_register_transform_func (_clutter_color_type, G_TYPE_STRING,
653                                         clutter_value_transform_color_string);
654        g_value_register_transform_func (G_TYPE_STRING, _clutter_color_type,
655                                         clutter_value_transform_string_color);
656     }
657
658   return _clutter_color_type;
659 }
660
661 static void
662 clutter_value_init_color (GValue *value)
663 {
664   value->data[0].v_pointer = NULL;
665 }
666
667 static void
668 clutter_value_free_color (GValue *value)
669 {
670   if (!(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
671     clutter_color_free (value->data[0].v_pointer);
672 }
673
674 static void
675 clutter_value_copy_color (const GValue *src,
676                           GValue       *dest)
677 {
678   dest->data[0].v_pointer = clutter_color_copy (src->data[0].v_pointer);
679 }
680
681 static gpointer
682 clutter_value_peek_color (const GValue *value)
683 {
684   return value->data[0].v_pointer;
685 }
686
687 static gchar *
688 clutter_value_collect_color (GValue      *value,
689                              guint        n_collect_values,
690                              GTypeCValue *collect_values,
691                              guint        collect_flags)
692 {
693   if (!collect_values[0].v_pointer)
694       value->data[0].v_pointer = NULL;
695   else
696     {
697       if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
698         {
699           value->data[0].v_pointer = collect_values[0].v_pointer;
700           value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
701         }
702       else
703         {
704           value->data[0].v_pointer =
705             clutter_color_copy (collect_values[0].v_pointer);
706         }
707     }
708
709   return NULL;
710 }
711
712 static gchar *
713 clutter_value_lcopy_color (const GValue *value,
714                            guint         n_collect_values,
715                            GTypeCValue  *collect_values,
716                            guint         collect_flags)
717 {
718   ClutterColor **color_p = collect_values[0].v_pointer;
719
720   if (!color_p)
721     return g_strdup_printf ("value location for '%s' passed as NULL",
722                             G_VALUE_TYPE_NAME (value));
723
724   if (!value->data[0].v_pointer)
725     *color_p = NULL;
726   else
727     {
728       if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
729         *color_p = value->data[0].v_pointer;
730       else
731         *color_p = clutter_color_copy (value->data[0].v_pointer);
732     }
733
734   return NULL;
735 }
736
737 /**
738  * clutter_value_set_color:
739  * @value: a #GValue initialized to #CLUTTER_TYPE_COLOR
740  * @color: the color to set
741  *
742  * Sets @value to @color.
743  *
744  * Since: 0.8.4
745  */
746 void
747 clutter_value_set_color (GValue             *value,
748                          const ClutterColor *color)
749 {
750   g_return_if_fail (CLUTTER_VALUE_HOLDS_COLOR (value));
751
752   value->data[0].v_pointer = clutter_color_copy (color);
753 }
754
755 /**
756  * clutter_value_get_color:
757  * @value: a #GValue initialized to #CLUTTER_TYPE_COLOR
758  *
759  * Gets the #ClutterColor contained in @value.
760  *
761  * Return value: the colors inside the passed #GValue
762  *
763  * Since: 0.8.4
764  */
765 G_CONST_RETURN ClutterColor *
766 clutter_value_get_color (const GValue *value)
767 {
768   g_return_val_if_fail (CLUTTER_VALUE_HOLDS_COLOR (value), NULL);
769
770   return value->data[0].v_pointer;
771 }
772
773 static void
774 param_color_init (GParamSpec *pspec)
775 {
776   ClutterParamSpecColor *cspec = CLUTTER_PARAM_SPEC_COLOR (pspec);
777
778   cspec->default_value = NULL;
779 }
780
781 static void
782 param_color_finalize (GParamSpec *pspec)
783 {
784   ClutterParamSpecColor *cspec = CLUTTER_PARAM_SPEC_COLOR (pspec);
785
786   clutter_color_free (cspec->default_value);
787 }
788
789 static void
790 param_color_set_default (GParamSpec *pspec,
791                         GValue     *value)
792 {
793   value->data[0].v_pointer = CLUTTER_PARAM_SPEC_COLOR (pspec)->default_value;
794   value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
795 }
796
797 static gint
798 param_color_values_cmp (GParamSpec   *pspec,
799                         const GValue *value1,
800                         const GValue *value2)
801 {
802   guint32 color1, color2;
803
804   color1 = clutter_color_to_pixel (value1->data[0].v_pointer);
805   color2 = clutter_color_to_pixel (value2->data[0].v_pointer);
806
807   if (color1 < color2)
808     return -1;
809   else if (color1 == color2)
810     return 0;
811   else
812     return 1;
813 }
814
815 static const GTypeValueTable _clutter_color_value_table = {
816   clutter_value_init_color,
817   clutter_value_free_color,
818   clutter_value_copy_color,
819   clutter_value_peek_color,
820   "p",
821   clutter_value_collect_color,
822   "p",
823   clutter_value_lcopy_color
824 };
825
826 GType
827 clutter_param_color_get_type (void)
828 {
829   static GType pspec_type = 0;
830
831   if (G_UNLIKELY (pspec_type == 0))
832     {
833       const GParamSpecTypeInfo pspec_info = {
834         sizeof (ClutterParamSpecColor),
835         16,
836         param_color_init,
837         CLUTTER_TYPE_COLOR,
838         param_color_finalize,
839         param_color_set_default,
840         NULL,
841         param_color_values_cmp,
842       };
843
844       pspec_type = g_param_type_register_static (I_("ClutterParamSpecColor"),
845                                                  &pspec_info);
846     }
847
848   return pspec_type;
849 }
850
851 /**
852  * clutter_param_spec_color:
853  * @name: name of the property
854  * @nick: short name
855  * @blurb: description (can be translatable)
856  * @default_value: default value
857  * @flags: flags for the param spec
858  *
859  * Creates a #GParamSpec for properties using #ClutterColor.
860  *
861  * Return value: the newly created #GParamSpec
862  *
863  * Since: 0.8.4
864  */
865 GParamSpec *
866 clutter_param_spec_color (const gchar        *name,
867                           const gchar        *nick,
868                           const gchar        *blurb,
869                           const ClutterColor *default_value,
870                           GParamFlags         flags)
871 {
872   ClutterParamSpecColor *cspec;
873
874   cspec = g_param_spec_internal (CLUTTER_TYPE_PARAM_COLOR,
875                                  name, nick, blurb, flags);
876
877   cspec->default_value = clutter_color_copy (default_value);
878
879   return G_PARAM_SPEC (cspec);
880 }