mutter/clutter/clutter-color.c
Emmanuele Bassi 7d674db9d2 Clean up of the ClutterColor API
The ClutterColor API has some inconsistencies:

  - the string deserialization function does not match the rest of
    the conversion function naming policy; the naming should be:

        clutter_color_parse()   ->      clutter_color_from_string()

    and the first parameter should be the ClutterColor that will
    be set from the string, not the string itself (a GDK-ism).

  - the fixed point API should not be exposed, especially in the
    form of ClutterFixed values

  - the non-fixed point HLS conversion functions do not make any
    sense. The values returned should be:

      hue        := range [ 0, 360 ]
      luminance  := range [ 0,   1 ]
      saturation := range [ 0,   1 ]

    like the current fixed point API does. Returning a value in
    the [ 0, 255 ] range is completely useless

  - the clutter_color_equal() should be converted for its use inside
    a GHashTable; a clutter_color_hash() should be added as well

  - the second parameter of the clutter_color_shade() function should
    be the shading factor, not the result (another GDK-ism). this way
    the function call can be translated from this:

      color.shade(out result, factor)

    to the more natural:

      color.shade(factor, out result)

This somewhat large commit fixes all these issues and updates the
internal users of the API.
2009-03-10 12:38:02 +00:00

1001 lines
25 KiB
C

/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:clutter-color
* @short_description: Color management and manipulation.
*
* #ClutterColor is a simple type for representing colors in Clutter.
*
* A #ClutterColor is expressed as a 4-tuple of values ranging from
* zero to 255, one for each color channel plus one for the alpha.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <pango/pango-attributes.h>
#include <gobject/gvaluecollector.h>
#include "clutter-main.h"
#include "clutter-color.h"
#include "clutter-private.h"
#include "clutter-debug.h"
/**
* clutter_color_add:
* @a: a #ClutterColor
* @b: a #ClutterColor
* @result: (out): return location for the result
*
* Adds @a to @b and saves the resulting color inside @result.
*
* The alpha channel of @result is set as as the maximum value
* between the alpha channels of @a and @b.
*/
void
clutter_color_add (const ClutterColor *a,
const ClutterColor *b,
ClutterColor *result)
{
g_return_if_fail (a != NULL);
g_return_if_fail (b != NULL);
g_return_if_fail (result != NULL);
result->red = CLAMP (a->red + b->red, 0, 255);
result->green = CLAMP (a->green + b->green, 0, 255);
result->blue = CLAMP (a->blue + b->blue, 0, 255);
result->alpha = MAX (a->alpha, b->alpha);
}
/**
* clutter_color_subtract:
* @a: a #ClutterColor
* @b: a #ClutterColor
* @result: (out): return location for the result
*
* Subtracts @b from @a and saves the resulting color inside @result.
*
* This function assumes that the components of @a are greater than the
* components of @b; the result is, otherwise, undefined.
*
* The alpha channel of @result is set as the minimum value
* between the alpha channels of @a and @b.
*/
void
clutter_color_subtract (const ClutterColor *a,
const ClutterColor *b,
ClutterColor *result)
{
g_return_if_fail (a != NULL);
g_return_if_fail (b != NULL);
g_return_if_fail (result != NULL);
result->red = CLAMP (a->red - b->red, 0, 255);
result->green = CLAMP (a->green - b->green, 0, 255);
result->blue = CLAMP (a->blue - b->blue, 0, 255);
result->alpha = MIN (a->alpha, b->alpha);
}
/**
* clutter_color_lighten:
* @color: a #ClutterColor
* @result: (out): return location for the lighter color
*
* Lightens @color by a fixed amount, and saves the changed color
* in @result.
*/
void
clutter_color_lighten (const ClutterColor *color,
ClutterColor *result)
{
clutter_color_shade (color, 1.3, result);
}
/**
* clutter_color_darken:
* @color: a #ClutterColor
* @result: (out): return location for the darker color
*
* Darkens @color by a fixed amount, and saves the changed color
* in @result.
*/
void
clutter_color_darken (const ClutterColor *color,
ClutterColor *result)
{
clutter_color_shade (color, 0.7, result);
}
/*
* clutter_color_to_hlsx:
* @color: a #ClutterColor
* @hue: return location for the hue value or %NULL
* @luminance: return location for the luminance value or %NULL
* @saturation: return location for the saturation value or %NULL
*
* Converts @color to the HLS format. Returned hue is in degrees (0 .. 360),
* luminance and saturation from interval <0 .. 1>.
*
* The implementation is in fixed point because we don't particularly
* care about precision. It can be moved to floating point at any later
* date.
*/
static void
clutter_color_to_hlsx (const ClutterColor *color,
CoglFixed *hue,
CoglFixed *luminance,
CoglFixed *saturation)
{
CoglFixed red, green, blue;
CoglFixed min, max, delta;
CoglFixed h, l, s;
g_return_if_fail (color != NULL);
red = COGL_FIXED_FAST_DIV (color->red, COGL_FIXED_255);
green = COGL_FIXED_FAST_DIV (color->green, COGL_FIXED_255);
blue = COGL_FIXED_FAST_DIV (color->blue, COGL_FIXED_255);
if (red > green)
{
if (red > blue)
max = red;
else
max = blue;
if (green < blue)
min = green;
else
min = blue;
}
else
{
if (green > blue)
max = green;
else
max = blue;
if (red < blue)
min = red;
else
min = blue;
}
l = (max + min) / 2;
s = 0;
h = 0;
if (max != min)
{
if (l <= COGL_FIXED_0_5)
s = COGL_FIXED_DIV ((max - min), (max + min));
else
s = COGL_FIXED_DIV ((max - min),
(COGL_FIXED_FROM_INT (2) - max - min));
delta = max - min;
if (red == max)
h = COGL_FIXED_DIV ((green - blue), delta);
else if (green == max)
h = COGL_FIXED_FROM_INT (2) + COGL_FIXED_DIV ((blue - red), delta);
else if (blue == max)
h = COGL_FIXED_FROM_INT (4) + COGL_FIXED_DIV ((red - green), delta);
h *= 60;
if (h < 0)
h += COGL_FIXED_360;
}
if (hue)
*hue = h;
if (luminance)
*luminance = l;
if (saturation)
*saturation = s;
}
/*
* clutter_color_from_hlsx:
* @dest: (out): return location for a #ClutterColor
* @hue: hue value (0 .. 360)
* @luminance: luminance value (0 .. 1)
* @saturation: saturation value (0 .. 1)
*
* Converts a color expressed in HLS (hue, luminance and saturation)
* values into a #ClutterColor.
*/
void
clutter_color_from_hlsx (ClutterColor *color,
CoglFixed hue,
CoglFixed luminance,
CoglFixed saturation)
{
CoglFixed h, l, s;
CoglFixed m1, m2;
g_return_if_fail (color != NULL);
l = luminance;
s = saturation;
if (l <= COGL_FIXED_0_5)
m2 = COGL_FIXED_MUL (l, (COGL_FIXED_1 + s));
else
m2 = l + s - COGL_FIXED_MUL (l, s);
m1 = 2 * l - m2;
if (s == 0)
{
color->red = (guint8) (COGL_FIXED_TO_INT (l) * 255);
color->green = (guint8) (COGL_FIXED_TO_INT (l) * 255);
color->blue = (guint8) (COGL_FIXED_TO_INT (l) * 255);
}
else
{
h = hue + COGL_FIXED_120;
while (h > COGL_FIXED_360)
h -= COGL_FIXED_360;
while (h < 0)
h += COGL_FIXED_360;
if (h < COGL_FIXED_60)
{
CoglFixed tmp;
tmp = (m1 + COGL_FIXED_MUL_DIV ((m2 - m1), h, COGL_FIXED_60));
color->red = (guint8) (COGL_FIXED_TO_INT (tmp) * 255);
}
else if (h < COGL_FIXED_180)
color->red = (guint8) (COGL_FIXED_TO_INT (m2) * 255);
else if (h < COGL_FIXED_240)
{
CoglFixed tmp;
tmp = (m1 + COGL_FIXED_MUL_DIV ((m2 - m1),
(COGL_FIXED_240 - h),
COGL_FIXED_60));
color->red = (guint8) (COGL_FIXED_TO_INT (tmp) * 255);
}
else
color->red = (guint8) (COGL_FIXED_TO_INT (m1) * 255);
h = hue;
while (h > COGL_FIXED_360)
h -= COGL_FIXED_360;
while (h < 0)
h += COGL_FIXED_360;
if (h < COGL_FIXED_60)
{
CoglFixed tmp;
tmp = (m1 + COGL_FIXED_MUL_DIV ((m2 - m1), h, COGL_FIXED_60));
color->green = (guint8) (COGL_FIXED_TO_INT (tmp) * 255);
}
else if (h < COGL_FIXED_180)
color->green = (guint8) (COGL_FIXED_TO_INT (m2) * 255);
else if (h < COGL_FIXED_240)
{
CoglFixed tmp;
tmp = (m1 + COGL_FIXED_MUL_DIV ((m2 - m1),
(COGL_FIXED_240 - h),
COGL_FIXED_60));
color->green = (guint8) (COGL_FIXED_TO_INT (tmp) * 255);
}
else
color->green = (guint8) (COGL_FIXED_TO_INT (m1) * 255);
h = hue - COGL_FIXED_120;
while (h > COGL_FIXED_360)
h -= COGL_FIXED_360;
while (h < 0)
h += COGL_FIXED_360;
if (h < COGL_FIXED_60)
{
CoglFixed tmp;
tmp = (m1 + COGL_FIXED_MUL_DIV ((m2 - m1), h, COGL_FIXED_60));
color->blue = (guint8) (COGL_FIXED_TO_INT (tmp) * 255);
}
else if (h < COGL_FIXED_180)
color->blue = (guint8) (COGL_FIXED_TO_INT (m2) * 255);
else if (h < COGL_FIXED_240)
{
CoglFixed tmp;
tmp = (m1 + COGL_FIXED_MUL_DIV ((m2 - m1),
(COGL_FIXED_240 - h),
COGL_FIXED_60));
color->blue = (guint8) (COGL_FIXED_TO_INT (tmp) * 255);
}
else
color->blue = (guint8) (COGL_FIXED_TO_INT (m1) * 255);
}
}
/**
* clutter_color_to_hls:
* @color: a #ClutterColor
* @hue: return location for the hue value or %NULL
* @luminance: return location for the luminance value or %NULL
* @saturation: return location for the saturation value or %NULL
*
* Converts @color to the HLS format.
*
* The @hue value is in the 0 .. 360 range. The @luminance and
* @saturation values are in the 0 .. 1 range.
*/
void
clutter_color_to_hls (const ClutterColor *color,
gfloat *hue,
gfloat *luminance,
gfloat *saturation)
{
CoglFixed h, l, s;
clutter_color_to_hlsx (color, &h, &l, &s);
if (hue)
*hue = COGL_FIXED_TO_FLOAT (h);
if (luminance)
*luminance = COGL_FIXED_TO_FLOAT (l);
if (saturation)
*saturation = COGL_FIXED_TO_FLOAT (s);
}
/**
* clutter_color_from_hls:
* @color: (out): return location for a #ClutterColor
* @hue: hue value, in the 0 .. 360 range
* @luminance: luminance value, in the 0 .. 1 range
* @saturation: saturation value, in the 0 .. 1 range
*
* Converts a color expressed in HLS (hue, luminance and saturation)
* values into a #ClutterColor.
*/
void
clutter_color_from_hls (ClutterColor *color,
gfloat hue,
gfloat luminance,
gfloat saturation)
{
CoglFixed h, l, s;
h = COGL_FIXED_FROM_FLOAT (hue);
l = COGL_FIXED_FROM_FLOAT (luminance);
s = COGL_FIXED_FROM_FLOAT (saturation);
clutter_color_from_hlsx (color, h, l, s);
}
/*
* clutter_color_shadex:
* @color: a #ClutterColor
* @factor: the shade factor to apply, as a fixed point value
* @result: (out): return location for the shaded color
*
* Shades @color by @factor and saves the modified color into @result.
*/
static void
clutter_color_shadex (const ClutterColor *color,
CoglFixed factor,
ClutterColor *result)
{
CoglFixed h, l, s;
g_return_if_fail (color != NULL);
g_return_if_fail (result != NULL);
clutter_color_to_hlsx (color, &h, &l, &s);
l = COGL_FIXED_MUL (l, factor);
if (l > COGL_FIXED_1)
l = COGL_FIXED_1;
else if (l < 0)
l = 0;
s = COGL_FIXED_MUL (s, factor);
if (s > COGL_FIXED_1)
s = COGL_FIXED_1;
else if (s < 0)
s = 0;
clutter_color_from_hlsx (result, h, l, s);
result->alpha = color->alpha;
}
/**
* clutter_color_shade:
* @color: a #ClutterColor
* @factor: the shade factor to apply
* @result: (out): return location for the shaded color
*
* Shades @color by @factor and saves the modified color into @result.
*/
void
clutter_color_shade (const ClutterColor *color,
gdouble factor,
ClutterColor *result)
{
clutter_color_shadex (color,
COGL_FIXED_FROM_FLOAT (factor),
result);
}
/**
* clutter_color_to_pixel:
* @color: a #ClutterColor
*
* Converts @color into a packed 32 bit integer, containing
* all the four 8 bit channels used by #ClutterColor.
*
* Return value: a packed color
*/
guint32
clutter_color_to_pixel (const ClutterColor *color)
{
g_return_val_if_fail (color != NULL, 0);
return (color->alpha |
color->blue << 8 |
color->green << 16 |
color->red << 24);
}
/**
* clutter_color_from_pixel:
* @color: (out): return location for a #ClutterColor
* @pixel: a 32 bit packed integer containing a color
*
* Converts @pixel from the packed representation of a four 8 bit channel
* color to a #ClutterColor.
*/
void
clutter_color_from_pixel (ClutterColor *color,
guint32 pixel)
{
g_return_if_fail (color != NULL);
color->red = pixel >> 24;
color->green = (pixel >> 16) & 0xff;
color->blue = (pixel >> 8) & 0xff;
color->alpha = pixel & 0xff;
}
/**
* clutter_color_from_string:
* @color: (out): return location for a #ClutterColor
* @str: a string specifiying a color (named color or #RRGGBBAA)
*
* Parses a string definition of a color, filling the
* <structfield>red</structfield>, <structfield>green</structfield>,
* <structfield>blue</structfield> and <structfield>alpha</structfield>
* channels of @color. If alpha is not specified it will be set full opaque.
*
* The @color is not allocated.
*
* The color may be defined by any of the formats understood by
* pango_color_from_string(); these include literal color names, like
* <literal>Red</literal> or <literal>DarkSlateGray</literal>, or
* hexadecimal specifications like <literal>&num;3050b2</literal> or
* <literal>&num;333</literal>.
*
* Return value: %TRUE if parsing succeeded.
*
* Since: 1.0
*/
gboolean
clutter_color_from_string (ClutterColor *color,
const gchar *str)
{
PangoColor pango_color = { 0, };
g_return_val_if_fail (color != NULL, FALSE);
g_return_val_if_fail (str != NULL, FALSE);
/* if the string contains a color encoded using the hexadecimal
* notations (#rrggbbaa or #rrggbb) we attempt a rough pass at
* parsing the color ourselves, as we need the alpha channel that
* Pango can't retrieve.
*/
if (str[0] == '#')
{
gint32 result;
if (sscanf (str + 1, "%x", &result))
{
if (strlen (str) == 9)
{
/* #rrggbbaa */
color->red = (result >> 24) & 0xff;
color->green = (result >> 16) & 0xff;
color->blue = (result >> 8) & 0xff;
color->alpha = result & 0xff;
return TRUE;
}
else if (strlen (str) == 7)
{
/* #rrggbb */
color->red = (result >> 16) & 0xff;
color->green = (result >> 8) & 0xff;
color->blue = result & 0xff;
color->alpha = 0xff;
return TRUE;
}
}
/* XXX - should we return FALSE here? it's not like
* Pango is endowed with mystical parsing powers and
* will be able to do better than the code above.
* still, it doesn't hurt
*/
}
/* Fall back to pango for named colors */
if (pango_color_parse (&pango_color, str))
{
color->red = pango_color.red;
color->green = pango_color.green;
color->blue = pango_color.blue;
color->alpha = 0xff;
return TRUE;
}
return FALSE;
}
/**
* clutter_color_to_string:
* @color: a #ClutterColor
*
* Returns a textual specification of @color in the hexadecimal form
* <literal>&num;rrggbbaa</literal>, where <literal>r</literal>,
* <literal>g</literal>, <literal>b</literal> and <literal>a</literal> are
* hex digits representing the red, green, blue and alpha components
* respectively.
*
* Return value: a newly-allocated text string
*
* Since: 0.2
*/
gchar *
clutter_color_to_string (const ClutterColor *color)
{
g_return_val_if_fail (color != NULL, NULL);
return g_strdup_printf ("#%02x%02x%02x%02x",
color->red,
color->green,
color->blue,
color->alpha);
}
/**
* clutter_color_equal:
* @v1: a #ClutterColor
* @v2: a #ClutterColor
*
* Compares two #ClutterColor<!-- -->s and checks if they are the same.
*
* This function can be passed to g_hash_table_new() as the @key_equal_func
* parameter, when using #ClutterColor<!-- -->s as keys in a #GHashTable.
*
* Return value: %TRUE if the two colors are the same.
*
* Since: 0.2
*/
gboolean
clutter_color_equal (gconstpointer v1,
gconstpointer v2)
{
const ClutterColor *a, *b;
g_return_val_if_fail (v1 != NULL, FALSE);
g_return_val_if_fail (v2 != NULL, FALSE);
if (v1 == v2)
return TRUE;
a = v1;
b = v2;
return (a->red == b->red &&
a->green == b->green &&
a->blue == b->blue &&
a->alpha == b->alpha);
}
/**
* clutter_color_hash:
* @v: a #ClutterColor
*
* Converts a #ClutterColor to a hash value.
*
* This function can be passed to g_hash_table_new() as the @hash_func
* parameter, when using #ClutterColor<!-- -->s as keys in a #GHashTable.
*
* Return value: a hash value corresponding to the color
*
* Since: 1.0
*/
guint
clutter_color_hash (gconstpointer v)
{
return clutter_color_to_pixel ((const ClutterColor *) v);
}
/**
* clutter_color_copy:
* @color: a #ClutterColor
*
* Makes a copy of the color structure. The result must be
* freed using clutter_color_free().
*
* Return value: an allocated copy of @color.
*
* Since: 0.2
*/
ClutterColor *
clutter_color_copy (const ClutterColor *color)
{
if (G_LIKELY (color != NULL))
return g_slice_dup (ClutterColor, color);
return NULL;
}
/**
* clutter_color_free:
* @color: a #ClutterColor
*
* Frees a color structure created with clutter_color_copy().
*
* Since: 0.2
*/
void
clutter_color_free (ClutterColor *color)
{
if (G_LIKELY (color != NULL))
g_slice_free (ClutterColor, color);
}
/**
* clutter_color_new:
* @red: red component of the color, between 0 and 255
* @green: green component of the color, between 0 and 255
* @blue: blue component of the color, between 0 and 255
* @alpha: alpha component of the color, between 0 and 255
*
* Creates a new #ClutterColor with the given values.
*
* Return value: the newly allocated color. Use clutter_color_free()
* when done
*
* Since: 0.8.4
*/
ClutterColor *
clutter_color_new (guint8 red,
guint8 green,
guint8 blue,
guint8 alpha)
{
ClutterColor *color;
color = g_slice_new (ClutterColor);
color->red = red;
color->green = green;
color->blue = blue;
color->alpha = alpha;
return color;
}
static void
clutter_value_transform_color_string (const GValue *src,
GValue *dest)
{
gchar *string = clutter_color_to_string (src->data[0].v_pointer);
g_value_take_string (dest, string);
}
static void
clutter_value_transform_string_color (const GValue *src,
GValue *dest)
{
ClutterColor color = { 0, };
clutter_color_from_string (&color, g_value_get_string (src));
clutter_value_set_color (dest, &color);
}
GType
clutter_color_get_type (void)
{
static GType _clutter_color_type = 0;
if (G_UNLIKELY (_clutter_color_type == 0))
{
_clutter_color_type =
g_boxed_type_register_static (I_("ClutterColor"),
(GBoxedCopyFunc) clutter_color_copy,
(GBoxedFreeFunc) clutter_color_free);
g_value_register_transform_func (_clutter_color_type, G_TYPE_STRING,
clutter_value_transform_color_string);
g_value_register_transform_func (G_TYPE_STRING, _clutter_color_type,
clutter_value_transform_string_color);
}
return _clutter_color_type;
}
static void
clutter_value_init_color (GValue *value)
{
value->data[0].v_pointer = NULL;
}
static void
clutter_value_free_color (GValue *value)
{
if (!(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
clutter_color_free (value->data[0].v_pointer);
}
static void
clutter_value_copy_color (const GValue *src,
GValue *dest)
{
dest->data[0].v_pointer = clutter_color_copy (src->data[0].v_pointer);
}
static gpointer
clutter_value_peek_color (const GValue *value)
{
return value->data[0].v_pointer;
}
static gchar *
clutter_value_collect_color (GValue *value,
guint n_collect_values,
GTypeCValue *collect_values,
guint collect_flags)
{
if (!collect_values[0].v_pointer)
value->data[0].v_pointer = NULL;
else
{
if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
{
value->data[0].v_pointer = collect_values[0].v_pointer;
value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
}
else
{
value->data[0].v_pointer =
clutter_color_copy (collect_values[0].v_pointer);
}
}
return NULL;
}
static gchar *
clutter_value_lcopy_color (const GValue *value,
guint n_collect_values,
GTypeCValue *collect_values,
guint collect_flags)
{
ClutterColor **color_p = collect_values[0].v_pointer;
if (!color_p)
return g_strdup_printf ("value location for `%s' passed as NULL",
G_VALUE_TYPE_NAME (value));
if (!value->data[0].v_pointer)
*color_p = NULL;
else
{
if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
*color_p = value->data[0].v_pointer;
else
*color_p = clutter_color_copy (value->data[0].v_pointer);
}
return NULL;
}
/**
* clutter_value_set_color:
* @value: a #GValue initialized to #CLUTTER_TYPE_COLOR
* @color: the color to set
*
* Sets @value to @color.
*
* Since: 0.8.4
*/
void
clutter_value_set_color (GValue *value,
const ClutterColor *color)
{
g_return_if_fail (CLUTTER_VALUE_HOLDS_COLOR (value));
value->data[0].v_pointer = clutter_color_copy (color);
}
/**
* clutter_value_get_color:
* @value: a #GValue initialized to #CLUTTER_TYPE_COLOR
*
* Gets the #ClutterColor contained in @value.
*
* Return value: the colors inside the passed #GValue
*
* Since: 0.8.4
*/
G_CONST_RETURN ClutterColor *
clutter_value_get_color (const GValue *value)
{
g_return_val_if_fail (CLUTTER_VALUE_HOLDS_COLOR (value), NULL);
return value->data[0].v_pointer;
}
static void
param_color_init (GParamSpec *pspec)
{
ClutterParamSpecColor *cspec = CLUTTER_PARAM_SPEC_COLOR (pspec);
cspec->default_value = NULL;
}
static void
param_color_finalize (GParamSpec *pspec)
{
ClutterParamSpecColor *cspec = CLUTTER_PARAM_SPEC_COLOR (pspec);
clutter_color_free (cspec->default_value);
}
static void
param_color_set_default (GParamSpec *pspec,
GValue *value)
{
value->data[0].v_pointer = CLUTTER_PARAM_SPEC_COLOR (pspec)->default_value;
value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
}
static gint
param_color_values_cmp (GParamSpec *pspec,
const GValue *value1,
const GValue *value2)
{
guint32 color1, color2;
color1 = clutter_color_to_pixel (value1->data[0].v_pointer);
color2 = clutter_color_to_pixel (value2->data[0].v_pointer);
if (color1 < color2)
return -1;
else if (color1 == color2)
return 0;
else
return 1;
}
static const GTypeValueTable _clutter_color_value_table = {
clutter_value_init_color,
clutter_value_free_color,
clutter_value_copy_color,
clutter_value_peek_color,
"p",
clutter_value_collect_color,
"p",
clutter_value_lcopy_color
};
GType
clutter_param_color_get_type (void)
{
static GType pspec_type = 0;
if (G_UNLIKELY (pspec_type == 0))
{
const GParamSpecTypeInfo pspec_info = {
sizeof (ClutterParamSpecColor),
16,
param_color_init,
CLUTTER_TYPE_COLOR,
param_color_finalize,
param_color_set_default,
NULL,
param_color_values_cmp,
};
pspec_type = g_param_type_register_static (I_("ClutterParamSpecColor"),
&pspec_info);
}
return pspec_type;
}
/**
* clutter_param_spec_color:
* @name: name of the property
* @nick: short name
* @blurb: description (can be translatable)
* @default_value: default value
* @flags: flags for the param spec
*
* Creates a #GParamSpec for properties using #ClutterColor.
*
* Return value: the newly created #GParamSpec
*
* Since: 0.8.4
*/
GParamSpec *
clutter_param_spec_color (const gchar *name,
const gchar *nick,
const gchar *blurb,
const ClutterColor *default_value,
GParamFlags flags)
{
ClutterParamSpecColor *cspec;
cspec = g_param_spec_internal (CLUTTER_TYPE_PARAM_COLOR,
name, nick, blurb, flags);
cspec->default_value = clutter_color_copy (default_value);
return G_PARAM_SPEC (cspec);
}