* 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.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
-#include "gtksymboliccolor.h"
+#include "gtksymboliccolorprivate.h"
#include "gtkstyleproperties.h"
#include "gtkintl.h"
+#include "gtkwin32themeprivate.h"
+
+/**
+ * SECTION:gtksymboliccolor
+ * @Short_description: Symbolic colors
+ * @Title: GtkSymbolicColor
+ *
+ * GtkSymbolicColor is a boxed type that represents a symbolic color.
+ * It is the result of parsing a
+ * <link linkend="gtkcssprovider-symbolic-colors">color expression</link>.
+ * To obtain the color represented by a GtkSymbolicColor, it has to
+ * be resolved with gtk_symbolic_color_resolve(), which replaces all
+ * symbolic color references by the colors they refer to (in a given
+ * context) and evaluates mix, shade and other expressions, resulting
+ * in a #GdkRGBA value.
+ *
+ * It is not normally necessary to deal directly with #GtkSymbolicColors,
+ * since they are mostly used behind the scenes by #GtkStyleContext and
+ * #GtkCssProvider.
+ */
G_DEFINE_BOXED_TYPE (GtkSymbolicColor, gtk_symbolic_color,
- gtk_symbolic_color_ref, gtk_symbolic_color_unref)
-G_DEFINE_BOXED_TYPE (GtkGradient, gtk_gradient,
- gtk_gradient_ref, gtk_gradient_unref)
+ gtk_symbolic_color_ref, gtk_symbolic_color_unref)
/* Symbolic colors */
typedef enum {
COLOR_TYPE_NAME,
COLOR_TYPE_SHADE,
COLOR_TYPE_ALPHA,
- COLOR_TYPE_MIX
+ COLOR_TYPE_MIX,
+ COLOR_TYPE_WIN32,
+ COLOR_TYPE_CURRENT_COLOR
} ColorType;
struct _GtkSymbolicColor
GtkSymbolicColor *color2;
gdouble factor;
} mix;
- };
-};
-
-typedef struct ColorStop ColorStop;
-
-struct ColorStop
-{
- gdouble offset;
- GtkSymbolicColor *color;
-};
-
-struct _GtkGradient
-{
- gdouble x0;
- gdouble y0;
- gdouble x1;
- gdouble y1;
- gdouble radius0;
- gdouble radius1;
- GArray *stops;
-
- guint ref_count;
+ struct
+ {
+ gchar *theme_class;
+ gint id;
+ } win32;
+ };
};
/**
}
/**
- * gtk_symbolic_color_new_shade:
+ * gtk_symbolic_color_new_shade: (constructor)
* @color: another #GtkSymbolicColor
* @factor: shading factor to apply to @color
*
}
/**
- * gtk_symbolic_color_new_alpha:
+ * gtk_symbolic_color_new_alpha: (constructor)
* @color: another #GtkSymbolicColor
* @factor: factor to apply to @color alpha
*
}
/**
- * gtk_symbolic_color_new_mix:
+ * gtk_symbolic_color_new_mix: (constructor)
* @color1: color to mix
* @color2: another color to mix
* @factor: mix factor
return symbolic_color;
}
+/**
+ * gtk_symbolic_color_new_win32: (constructor)
+ * @theme_class: The theme class to pull color from
+ * @id: The color id
+ *
+ * Creates a symbolic color based on the current win32
+ * theme.
+ *
+ * Note that while this call is available on all platforms
+ * the actual value returned is not reliable on non-win32
+ * platforms.
+ *
+ * Returns: A newly created #GtkSymbolicColor
+ *
+ * Since: 3.4
+ */
+GtkSymbolicColor *
+gtk_symbolic_color_new_win32 (const gchar *theme_class,
+ gint id)
+{
+ GtkSymbolicColor *symbolic_color;
+
+ g_return_val_if_fail (theme_class != NULL, NULL);
+
+ symbolic_color = g_slice_new0 (GtkSymbolicColor);
+ symbolic_color->type = COLOR_TYPE_WIN32;
+ symbolic_color->win32.theme_class = g_strdup (theme_class);
+ symbolic_color->win32.id = id;
+ symbolic_color->ref_count = 1;
+
+ return symbolic_color;
+}
+
+/**
+ * _gtk_symbolic_color_get_current_color:
+ *
+ * Gets the color representing the CSS 'currentColor' keyword.
+ * This color will resolve to the color set for the color property.
+ *
+ * Returns: (transfer none): The singleton representing the
+ * 'currentColor' keyword
+ **/
+GtkSymbolicColor *
+_gtk_symbolic_color_get_current_color (void)
+{
+ static GtkSymbolicColor *current_color = NULL;
+
+ if (G_UNLIKELY (current_color == NULL))
+ {
+ current_color = g_slice_new0 (GtkSymbolicColor);
+ current_color->type = COLOR_TYPE_CURRENT_COLOR;
+ current_color->ref_count = 1;
+ }
+
+ return current_color;
+}
+
/**
* gtk_symbolic_color_ref:
* @color: a #GtkSymbolicColor
gtk_symbolic_color_unref (color->mix.color1);
gtk_symbolic_color_unref (color->mix.color2);
break;
+ case COLOR_TYPE_WIN32:
+ g_free (color->win32.theme_class);
+ break;
default:
break;
}
*color = temp;
}
+static GtkSymbolicColor *
+resolve_lookup_color (gpointer data, const char *name)
+{
+ if (data == NULL)
+ return NULL;
+
+ return gtk_style_properties_lookup_color (data, name);
+}
+
/**
* gtk_symbolic_color_resolve:
* @color: a #GtkSymbolicColor
- * @props: #GtkStyleProperties to use when resolving named colors
+ * @props: (allow-none): #GtkStyleProperties to use when resolving
+ * named colors, or %NULL
* @resolved_color: (out): return location for the resolved color
*
* If @color is resolvable, @resolved_color will be filled in
* if @color can't be resolved, it is due to it being defined on
* top of a named color that doesn't exist in @props.
*
+ * When @props is %NULL, resolving of named colors will fail, so if
+ * your @color is or references such a color, this function will
+ * return %FALSE.
+ *
* Returns: %TRUE if the color has been resolved
*
* Since: 3.0
{
g_return_val_if_fail (color != NULL, FALSE);
g_return_val_if_fail (resolved_color != NULL, FALSE);
+ g_return_val_if_fail (props == NULL || GTK_IS_STYLE_PROPERTIES (props), FALSE);
+
+ return _gtk_symbolic_color_resolve_full (color,
+ resolve_lookup_color,
+ props,
+ resolved_color);
+}
+
+gboolean
+_gtk_symbolic_color_resolve_full (GtkSymbolicColor *color,
+ GtkSymbolicColorLookupFunc func,
+ gpointer data,
+ GdkRGBA *resolved_color)
+{
+ g_return_val_if_fail (color != NULL, FALSE);
+ g_return_val_if_fail (resolved_color != NULL, FALSE);
+ g_return_val_if_fail (func != NULL, FALSE);
switch (color->type)
{
{
GtkSymbolicColor *named_color;
- g_return_val_if_fail (GTK_IS_STYLE_PROPERTIES (props), FALSE);
-
- named_color = gtk_style_properties_lookup_color (props, color->name);
+ named_color = func (data, color->name);
if (!named_color)
return FALSE;
- return gtk_symbolic_color_resolve (named_color, props, resolved_color);
+ return _gtk_symbolic_color_resolve_full (named_color, func, data, resolved_color);
}
break;
{
GdkRGBA shade;
- if (!gtk_symbolic_color_resolve (color->shade.color, props, &shade))
+ if (!_gtk_symbolic_color_resolve_full (color->shade.color, func, data, &shade))
return FALSE;
_shade_color (&shade, color->shade.factor);
{
GdkRGBA alpha;
- if (!gtk_symbolic_color_resolve (color->alpha.color, props, &alpha))
+ if (!_gtk_symbolic_color_resolve_full (color->alpha.color, func, data, &alpha))
return FALSE;
*resolved_color = alpha;
{
GdkRGBA color1, color2;
- if (!gtk_symbolic_color_resolve (color->mix.color1, props, &color1))
+ if (!_gtk_symbolic_color_resolve_full (color->mix.color1, func, data, &color1))
return FALSE;
- if (!gtk_symbolic_color_resolve (color->mix.color2, props, &color2))
+ if (!_gtk_symbolic_color_resolve_full (color->mix.color2, func, data, &color2))
return FALSE;
resolved_color->red = CLAMP (color1.red + ((color2.red - color1.red) * color->mix.factor), 0, 1);
return TRUE;
}
+ break;
+ case COLOR_TYPE_WIN32:
+ return _gtk_win32_theme_color_resolve (color->win32.theme_class,
+ color->win32.id,
+ resolved_color);
+
+ break;
+ case COLOR_TYPE_CURRENT_COLOR:
+ return FALSE;
break;
default:
g_assert_not_reached ();
return FALSE;
}
-/* GtkGradient */
-/**
- * gtk_gradient_new_linear:
- * @x0: X coordinate of the starting point
- * @y0: Y coordinate of the starting point
- * @x1: X coordinate of the end point
- * @y1: Y coordinate of the end point
- *
- * Creates a new linear gradient along the line defined by (x0, y0) and (x1, y1). Before using the gradient
- * a number of stop colors must be added through gtk_gradient_add_color_stop().
- *
- * Returns: A newly created #GtkGradient
- *
- * Since: 3.0
- **/
-GtkGradient *
-gtk_gradient_new_linear (gdouble x0,
- gdouble y0,
- gdouble x1,
- gdouble y1)
-{
- GtkGradient *gradient;
-
- gradient = g_slice_new (GtkGradient);
- gradient->stops = g_array_new (FALSE, FALSE, sizeof (ColorStop));
-
- gradient->x0 = x0;
- gradient->y0 = y0;
- gradient->x1 = x1;
- gradient->y1 = y1;
- gradient->radius0 = 0;
- gradient->radius1 = 0;
-
- gradient->ref_count = 1;
-
- return gradient;
-}
-
-/**
- * gtk_gradient_new_radial:
- * @x0: X coordinate of the start circle
- * @y0: Y coordinate of the start circle
- * @radius0: radius of the start circle
- * @x1: X coordinate of the end circle
- * @y1: Y coordinate of the end circle
- * @radius1: radius of the end circle
- *
- * Creates a new radial gradient along the two circles defined by (x0, y0, radius0) and
- * (x1, y1, radius1). Before using the gradient a number of stop colors must be added
- * through gtk_gradient_add_color_stop().
- *
- * Returns: A newly created #GtkGradient
- *
- * Since: 3.0
- **/
-GtkGradient *
-gtk_gradient_new_radial (gdouble x0,
- gdouble y0,
- gdouble radius0,
- gdouble x1,
- gdouble y1,
- gdouble radius1)
-{
- GtkGradient *gradient;
-
- gradient = g_slice_new (GtkGradient);
- gradient->stops = g_array_new (FALSE, FALSE, sizeof (ColorStop));
-
- gradient->x0 = x0;
- gradient->y0 = y0;
- gradient->x1 = x1;
- gradient->y1 = y1;
- gradient->radius0 = radius0;
- gradient->radius1 = radius1;
-
- gradient->ref_count = 1;
-
- return gradient;
-}
-
/**
- * gtk_gradient_add_color_stop:
- * @gradient: a #GtkGradient
- * @offset: offset for the color stop
- * @color: color to use
+ * gtk_symbolic_color_to_string:
+ * @color: color to convert to a string
*
- * Adds a stop color to @gradient.
+ * Converts the given @color to a string representation. This is useful
+ * both for debugging and for serialization of strings. The format of
+ * the string may change between different versions of GTK, but it is
+ * guaranteed that the GTK css parser is able to read the string and
+ * create the same symbolic color from it.
*
- * Since: 3.0
+ * Returns: a new string representing @color
**/
-void
-gtk_gradient_add_color_stop (GtkGradient *gradient,
- gdouble offset,
- GtkSymbolicColor *color)
+char *
+gtk_symbolic_color_to_string (GtkSymbolicColor *color)
{
- ColorStop stop;
-
- g_return_if_fail (gradient != NULL);
+ char *s;
- stop.offset = offset;
- stop.color = gtk_symbolic_color_ref (color);
-
- g_array_append_val (gradient->stops, stop);
-}
-
-/**
- * gtk_gradient_ref:
- * @gradient: a #GtkGradient
- *
- * Increases the reference count of @gradient.
- *
- * Returns: The same @gradient
- *
- * Since: 3.0
- **/
-GtkGradient *
-gtk_gradient_ref (GtkGradient *gradient)
-{
- g_return_val_if_fail (gradient != NULL, NULL);
-
- gradient->ref_count++;
-
- return gradient;
-}
-
-/**
- * gtk_gradient_unref:
- * @gradient: a #GtkGradient
- *
- * Decreases the reference count of @gradient, freeing its memory
- * if the reference count reaches 0.
- *
- * Since: 3.0
- **/
-void
-gtk_gradient_unref (GtkGradient *gradient)
-{
- g_return_if_fail (gradient != NULL);
-
- gradient->ref_count--;
+ g_return_val_if_fail (color != NULL, NULL);
- if (gradient->ref_count == 0)
+ switch (color->type)
{
- guint i;
-
- for (i = 0; i < gradient->stops->len; i++)
- {
- ColorStop *stop;
+ case COLOR_TYPE_LITERAL:
+ s = gdk_rgba_to_string (&color->color);
+ break;
+ case COLOR_TYPE_NAME:
+ s = g_strconcat ("@", color->name, NULL);
+ break;
+ case COLOR_TYPE_SHADE:
+ {
+ char *color_string = gtk_symbolic_color_to_string (color->shade.color);
+ char factor[G_ASCII_DTOSTR_BUF_SIZE];
- stop = &g_array_index (gradient->stops, ColorStop, i);
- gtk_symbolic_color_unref (stop->color);
- }
+ g_ascii_dtostr (factor, sizeof (factor), color->shade.factor);
+ s = g_strdup_printf ("shade (%s, %s)", color_string, factor);
+ g_free (color_string);
+ }
+ break;
+ case COLOR_TYPE_ALPHA:
+ {
+ char *color_string = gtk_symbolic_color_to_string (color->shade.color);
+ char factor[G_ASCII_DTOSTR_BUF_SIZE];
- g_array_free (gradient->stops, TRUE);
- g_slice_free (GtkGradient, gradient);
+ g_ascii_dtostr (factor, sizeof (factor), color->alpha.factor);
+ s = g_strdup_printf ("alpha (%s, %s)", color_string, factor);
+ g_free (color_string);
+ }
+ break;
+ case COLOR_TYPE_MIX:
+ {
+ char *color_string1 = gtk_symbolic_color_to_string (color->mix.color1);
+ char *color_string2 = gtk_symbolic_color_to_string (color->mix.color2);
+ char factor[G_ASCII_DTOSTR_BUF_SIZE];
+
+ g_ascii_dtostr (factor, sizeof (factor), color->mix.factor);
+ s = g_strdup_printf ("mix (%s, %s, %s)", color_string1, color_string2, factor);
+ g_free (color_string1);
+ g_free (color_string2);
+ }
+ break;
+ case COLOR_TYPE_WIN32:
+ {
+ s = g_strdup_printf (GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME"(%s, %d)",
+ color->win32.theme_class, color->win32.id);
+ }
+ break;
+ case COLOR_TYPE_CURRENT_COLOR:
+ s = g_strdup ("currentColor");
+ break;
+ default:
+ g_assert_not_reached ();
}
-}
-/**
- * gtk_gradient_resolve:
- * @gradient: a #GtkGradient
- * @props: #GtkStyleProperties to use when resolving named colors
- * @resolved_gradient: (out): return location for the resolved pattern
- *
- * If @gradient is resolvable, @resolved_gradient will be filled in
- * with the resolved gradient as a cairo_pattern_t, and %TRUE will
- * be returned. Generally, if @gradient can't be resolved, it is
- * due to it being defined on top of a named color that doesn't
- * exist in @props.
- *
- * Returns: %TRUE if the gradient has been resolved
- *
- * Since: 3.0
- **/
-gboolean
-gtk_gradient_resolve (GtkGradient *gradient,
- GtkStyleProperties *props,
- cairo_pattern_t **resolved_gradient)
-{
- cairo_pattern_t *pattern;
- guint i;
-
- g_return_val_if_fail (gradient != NULL, FALSE);
- g_return_val_if_fail (GTK_IS_STYLE_PROPERTIES (props), FALSE);
- g_return_val_if_fail (resolved_gradient != NULL, FALSE);
-
- if (gradient->radius0 == 0 && gradient->radius1 == 0)
- pattern = cairo_pattern_create_linear (gradient->x0, gradient->y0,
- gradient->x1, gradient->y1);
- else
- pattern = cairo_pattern_create_radial (gradient->x0, gradient->y0,
- gradient->radius0,
- gradient->x1, gradient->y1,
- gradient->radius1);
-
- for (i = 0; i < gradient->stops->len; i++)
- {
- ColorStop *stop;
- GdkRGBA color;
-
- stop = &g_array_index (gradient->stops, ColorStop, i);
-
- if (!gtk_symbolic_color_resolve (stop->color, props, &color))
- {
- cairo_pattern_destroy (pattern);
- return FALSE;
- }
-
- cairo_pattern_add_color_stop_rgba (pattern, stop->offset,
- color.red, color.green,
- color.blue, color.alpha);
- }
+ return s;
- *resolved_gradient = pattern;
- return TRUE;
}