1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2011 Red Hat, Inc.
4 * Author: Cosimo Cecchi <cosimoc@gnome.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
24 #include "gtkshadowprivate.h"
26 #include "gtkstylecontextprivate.h"
27 #include "gtkthemingengineprivate.h"
30 typedef struct _GtkShadowElement GtkShadowElement;
32 struct _GtkShadowElement {
41 GtkSymbolicColor *symbolic_color;
45 shadow_element_print (GtkShadowElement *element,
51 g_string_append (str, "inset ");
53 g_string_append_printf (str, "%d %d ",
54 (gint) element->hoffset,
55 (gint) element->voffset);
57 if (element->radius != 0)
58 g_string_append_printf (str, "%d ", (gint) element->radius);
60 if (element->spread != 0)
61 g_string_append_printf (str, "%d ", (gint) element->spread);
63 if (element->symbolic_color != NULL)
64 color_str = gtk_symbolic_color_to_string (element->symbolic_color);
66 color_str = gdk_rgba_to_string (&element->color);
68 g_string_append (str, color_str);
73 shadow_element_free (GtkShadowElement *element)
75 if (element->symbolic_color != NULL)
76 gtk_symbolic_color_unref (element->symbolic_color);
78 g_slice_free (GtkShadowElement, element);
81 static GtkShadowElement *
82 shadow_element_new (gdouble hoffset,
88 GtkSymbolicColor *symbolic_color)
90 GtkShadowElement *retval;
92 retval = g_slice_new0 (GtkShadowElement);
94 retval->hoffset = hoffset;
95 retval->voffset = voffset;
96 retval->radius = radius;
97 retval->spread = spread;
98 retval->inset = inset;
100 if (symbolic_color != NULL)
101 retval->symbolic_color = gtk_symbolic_color_ref (symbolic_color);
104 retval->color = *color;
113 G_DEFINE_BOXED_TYPE (GtkShadow, _gtk_shadow,
114 _gtk_shadow_ref, _gtk_shadow_unref)
124 _gtk_shadow_new (void)
128 retval = g_slice_new0 (GtkShadow);
129 retval->ref_count = 1;
130 retval->resolved = FALSE;
136 _gtk_shadow_ref (GtkShadow *shadow)
138 g_return_val_if_fail (shadow != NULL, NULL);
146 _gtk_shadow_get_resolved (GtkShadow *shadow)
148 return shadow->resolved;
152 _gtk_shadow_unref (GtkShadow *shadow)
154 g_return_if_fail (shadow != NULL);
158 if (shadow->ref_count == 0)
160 g_list_free_full (shadow->elements,
161 (GDestroyNotify) shadow_element_free);
162 g_slice_free (GtkShadow, shadow);
167 _gtk_shadow_append (GtkShadow *shadow,
173 GtkSymbolicColor *color)
175 GtkShadowElement *element;
177 g_return_if_fail (shadow != NULL);
178 g_return_if_fail (color != NULL);
180 element = shadow_element_new (hoffset, voffset,
181 radius, spread, inset,
184 shadow->elements = g_list_append (shadow->elements, element);
188 _gtk_shadow_resolve (GtkShadow *shadow,
189 GtkStyleContext *context)
191 GtkShadow *resolved_shadow;
192 GtkShadowElement *element, *resolved_element;
196 if (shadow->resolved)
197 return _gtk_shadow_ref (shadow);
199 resolved_shadow = _gtk_shadow_new ();
201 for (l = shadow->elements; l != NULL; l = l->next)
205 if (!_gtk_style_context_resolve_color (context,
206 element->symbolic_color,
209 _gtk_shadow_unref (resolved_shadow);
214 shadow_element_new (element->hoffset, element->voffset,
215 element->radius, element->spread, element->inset,
218 resolved_shadow->elements =
219 g_list_append (resolved_shadow->elements, resolved_element);
222 resolved_shadow->resolved = TRUE;
224 return resolved_shadow;
228 _gtk_shadow_print (GtkShadow *shadow,
234 length = g_list_length (shadow->elements);
239 shadow_element_print (shadow->elements->data, str);
244 for (l = g_list_next (shadow->elements); l != NULL; l = l->next)
246 g_string_append (str, ", ");
247 shadow_element_print (l->data, str);
252 _gtk_text_shadow_paint_layout (GtkShadow *shadow,
257 GtkShadowElement *element;
259 if (!cairo_has_current_point (cr))
260 cairo_move_to (cr, 0, 0);
262 /* render shadows starting from the last one,
263 * and the others on top.
265 for (l = g_list_last (shadow->elements); l != NULL; l = l->prev)
271 cairo_rel_move_to (cr, element->hoffset, element->voffset);
272 gdk_cairo_set_source_rgba (cr, &element->color);
273 _gtk_pango_fill_layout (cr, layout);
275 cairo_rel_move_to (cr, -element->hoffset, -element->voffset);
281 _gtk_icon_shadow_paint (GtkShadow *shadow,
285 GtkShadowElement *element;
286 cairo_pattern_t *pattern;
288 for (l = g_list_last (shadow->elements); l != NULL; l = l->prev)
293 pattern = cairo_pattern_reference (cairo_get_source (cr));
294 gdk_cairo_set_source_rgba (cr, &element->color);
296 cairo_translate (cr, element->hoffset, element->voffset);
297 cairo_mask (cr, pattern);
300 cairo_pattern_destroy (pattern);
305 _gtk_icon_shadow_paint_spinner (GtkShadow *shadow,
310 GtkShadowElement *element;
313 for (l = g_list_last (shadow->elements); l != NULL; l = l->prev)
319 cairo_translate (cr, element->hoffset, element->voffset);
320 _gtk_theming_engine_paint_spinner (cr,
329 _gtk_box_shadow_render (GtkShadow *shadow,
331 const GtkRoundedBox *padding_box)
333 GtkShadowElement *element;
338 cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
340 _gtk_rounded_box_path (padding_box, cr);
343 /* render shadows starting from the last one,
344 * and the others on top.
346 for (l = g_list_last (shadow->elements); l != NULL; l = l->prev)
354 _gtk_rounded_box_move (&box, element->hoffset, element->voffset);
355 _gtk_rounded_box_shrink (&box,
356 element->spread, element->spread,
357 element->spread, element->spread);
359 _gtk_rounded_box_path (&box, cr);
360 _gtk_rounded_box_clip_path (padding_box, cr);
362 gdk_cairo_set_source_rgba (cr, &element->color);