1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
6
#include "st-theme-private.h"
7
#include "st-theme-context.h"
8
#include "st-theme-node.h"
10
static void st_theme_node_init (StThemeNode *node);
11
static void st_theme_node_class_init (StThemeNodeClass *klass);
12
static void st_theme_node_finalize (GObject *object);
17
StThemeContext *context;
18
StThemeNode *parent_node;
21
PangoFontDescription *font_desc;
23
ClutterColor background_color;
24
ClutterColor foreground_color;
25
ClutterColor border_color[4];
26
double border_width[4];
27
double border_radius[4];
30
char *background_image;
31
StBorderImage *border_image;
39
CRDeclaration **properties;
42
/* We hold onto these separately so we can destroy them on finalize */
43
CRDeclaration *inline_properties;
45
guint properties_computed : 1;
46
guint borders_computed : 1;
47
guint background_computed : 1;
48
guint foreground_computed : 1;
49
guint border_image_computed : 1;
53
struct _StThemeNodeClass {
54
GObjectClass parent_class;
58
static const ClutterColor BLACK_COLOR = { 0, 0, 0, 0xff };
59
static const ClutterColor TRANSPARENT_COLOR = { 0, 0, 0, 0 };
61
G_DEFINE_TYPE (StThemeNode, st_theme_node, G_TYPE_OBJECT)
64
st_theme_node_init (StThemeNode *node)
69
st_theme_node_class_init (StThemeNodeClass *klass)
71
GObjectClass *object_class = G_OBJECT_CLASS (klass);
73
object_class->finalize = st_theme_node_finalize;
77
st_theme_node_finalize (GObject *object)
79
StThemeNode *node = ST_THEME_NODE (object);
81
g_free (node->element_id);
82
g_free (node->element_class);
83
g_free (node->pseudo_class);
84
g_free (node->inline_style);
88
g_free (node->properties);
89
node->properties = NULL;
90
node->n_properties = 0;
93
if (node->inline_properties)
95
/* This destroys the list, not just the head of the list */
96
cr_declaration_destroy (node->inline_properties);
101
pango_font_description_free (node->font_desc);
102
node->font_desc = NULL;
105
if (node->border_image)
107
g_object_unref (node->border_image);
108
node->border_image = NULL;
111
if (node->background_image)
112
g_free (node->background_image);
114
G_OBJECT_CLASS (st_theme_node_parent_class)->finalize (object);
119
* @context: the context representing global state for this themed tree
120
* @parent_node: (allow-none): the parent node of this node
121
* @theme: (allow-none): a theme (stylesheet set) that overrides the
122
* theme inherited from the parent node
123
* @element_type: the type of the GObject represented by this node
124
* in the tree (corresponding to an element if we were theming an XML
125
* document. %G_TYPE_NONE means this style was created for the stage
126
* actor and matches a selector element name of 'stage'.
127
* @element_id: (allow-none): the ID to match CSS rules against
128
* @element_class: (allow-none): a whitespace-separated list of classes
129
* to match CSS rules against
130
* @pseudo_class: (allow-none): a whitespace-separated list of pseudo-classes
131
* (like 'hover' or 'visited') to match CSS rules against
133
* Creates a new #StThemeNode. Once created, a node is immutable. Of any
134
* of the attributes of the node (like the @element_class) change the node
135
* and its child nodes must be destroyed and recreated.
137
* Return value: (transfer full): the theme node
140
st_theme_node_new (StThemeContext *context,
141
StThemeNode *parent_node,
144
const char *element_id,
145
const char *element_class,
146
const char *pseudo_class,
147
const char *inline_style)
151
g_return_val_if_fail (ST_IS_THEME_CONTEXT (context), NULL);
152
g_return_val_if_fail (parent_node == NULL || ST_IS_THEME_NODE (parent_node), NULL);
154
node = g_object_new (ST_TYPE_THEME_NODE, NULL);
156
node->context = g_object_ref (context);
157
if (parent_node != NULL)
158
node->parent_node = g_object_ref (parent_node);
160
node->parent_node = NULL;
162
if (theme == NULL && parent_node != NULL)
163
theme = parent_node->theme;
166
node->theme = g_object_ref (theme);
168
node->element_type = element_type;
169
node->element_id = g_strdup (element_id);
170
node->element_class = g_strdup (element_class);
171
node->pseudo_class = g_strdup (pseudo_class);
172
node->inline_style = g_strdup (inline_style);
178
* st_theme_node_get_parent:
179
* @node: a #StThemeNode
181
* Gets the parent themed element node.
183
* Return value: (transfer none): the parent #StThemeNode, or %NULL if this
184
* is the root node of the tree of theme elements.
187
st_theme_node_get_parent (StThemeNode *node)
189
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
191
return node->parent_node;
195
* st_theme_node_get_theme:
196
* @node: a #StThemeNode
198
* Gets the theme stylesheet set that styles this node
200
* Return value: (transfer none): the theme stylesheet set
203
st_theme_node_get_theme (StThemeNode *node)
205
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
211
st_theme_node_get_element_type (StThemeNode *node)
213
g_return_val_if_fail (ST_IS_THEME_NODE (node), G_TYPE_NONE);
215
return node->element_type;
219
st_theme_node_get_element_id (StThemeNode *node)
221
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
223
return node->element_id;
227
st_theme_node_get_element_class (StThemeNode *node)
229
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
231
return node->element_class;
235
st_theme_node_get_pseudo_class (StThemeNode *node)
237
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
239
return node->pseudo_class;
243
ensure_properties (StThemeNode *node)
245
if (!node->properties_computed)
247
GPtrArray *properties = NULL;
249
node->properties_computed = TRUE;
252
properties = _st_theme_get_matched_properties (node->theme, node);
254
if (node->inline_style)
256
CRDeclaration *cur_decl;
259
properties = g_ptr_array_new ();
261
node->inline_properties = _st_theme_parse_declaration_list (node->inline_style);
262
for (cur_decl = node->inline_properties; cur_decl; cur_decl = cur_decl->next)
263
g_ptr_array_add (properties, cur_decl);
268
node->n_properties = properties->len;
269
node->properties = (CRDeclaration **)g_ptr_array_free (properties, FALSE);
281
term_is_inherit (CRTerm *term)
283
return (term->type == TERM_IDENT &&
284
strcmp (term->content.str->stryng->str, "inherit") == 0);
288
term_is_none (CRTerm *term)
290
return (term->type == TERM_IDENT &&
291
strcmp (term->content.str->stryng->str, "none") == 0);
295
term_is_transparent (CRTerm *term)
297
return (term->type == TERM_IDENT &&
298
strcmp (term->content.str->stryng->str, "transparent") == 0);
302
color_component_from_double (double component)
304
/* We want to spread the range 0-1 equally over 0..255, but
305
* 1.0 should map to 255 not 256, so we need to special-case it.
306
* See http://people.redhat.com/otaylor/pixel-converting.html
307
* for (very) detailed discussion of related issues. */
308
if (component >= 1.0)
311
return (int)(component * 256);
314
static GetFromTermResult
315
get_color_from_rgba_term (CRTerm *term,
318
CRTerm *arg = term->ext_content.func_param;
320
double r = 0, g = 0, b = 0, a = 0;
323
for (i = 0; i < 4; i++)
328
return VALUE_NOT_FOUND;
330
if ((i == 0 && arg->the_operator != NO_OP) ||
331
(i > 0 && arg->the_operator != COMMA))
332
return VALUE_NOT_FOUND;
334
if (arg->type != TERM_NUMBER)
335
return VALUE_NOT_FOUND;
337
num = arg->content.num;
339
/* For simplicity, we convert a,r,g,b to [0,1.0] floats and then
340
* convert them back below. Then when we set them on a cairo content
341
* we convert them back to floats, and then cairo converts them
342
* back to integers to pass them to X, and so forth...
346
if (num->type == NUM_PERCENTAGE)
347
value = num->val / 100;
348
else if (num->type == NUM_GENERIC)
349
value = num->val / 255;
351
return VALUE_NOT_FOUND;
355
if (num->type != NUM_GENERIC)
356
return VALUE_NOT_FOUND;
361
value = CLAMP (value, 0, 1);
382
color->red = color_component_from_double (r);
383
color->green = color_component_from_double (g);
384
color->blue = color_component_from_double (b);
385
color->alpha = color_component_from_double (a);
390
static GetFromTermResult
391
get_color_from_term (StThemeNode *node,
396
enum CRStatus status;
398
/* Since libcroco doesn't know about rgba colors, it can't handle
399
* the transparent keyword
401
if (term_is_transparent (term))
403
*color = TRANSPARENT_COLOR;
406
/* rgba () colors - a CSS3 addition, are not supported by libcroco,
407
* but they are parsed as a "function", so we can emulate the
410
* libcroco < 0.6.2 has a bug where functions starting with 'r' are
411
* misparsed. We workaround this by pre-converting 'rgba' to 'RGBA'
412
* before parsing the stylesheet. Since libcroco isn't
413
* case-insensitive (a bug), it's fine with functions starting with
414
* 'R'. (In theory, we should be doing a case-insensitive compare
415
* everywhere, not just here, but that doesn't make much sense when
416
* the built-in parsing of libcroco is case-sensitive and things
417
* like 10PX don't work.)
419
else if (term->type == TERM_FUNCTION &&
421
term->content.str->stryng &&
422
term->content.str->stryng->str &&
423
g_ascii_strcasecmp (term->content.str->stryng->str, "rgba") == 0)
425
return get_color_from_rgba_term (term, color);
428
status = cr_rgb_set_from_term (&rgb, term);
430
return VALUE_NOT_FOUND;
433
return VALUE_INHERIT;
435
if (rgb.is_percentage)
436
cr_rgb_compute_from_percentage (&rgb);
438
color->red = rgb.red;
439
color->green = rgb.green;
440
color->blue = rgb.blue;
447
* st_theme_node_get_color:
448
* @node: a #StThemeNode
449
* @property_name: The name of the color property
450
* @inherit: if %TRUE, if a value is not found for the property on the
451
* node, then it will be looked up on the parent node, and then on the
452
* parent's parent, and so forth. Note that if the property has a
453
* value of 'inherit' it will be inherited even if %FALSE is passed
454
* in for @inherit; this only affects the default behavior for inheritance.
455
* @color: (out): location to store the color that was determined.
456
* If the property is not found, the value in this location
457
* will not be changed.
459
* Generically looks up a property containing a single color value. When
460
* specific getters (like st_theme_node_get_background_color()) exist, they
461
* should be used instead. They are cached, so more efficient, and have
462
* handling for shortcut properties and other details of CSS.
464
* Return value: %TRUE if the property was found in the properties for this
465
* theme node (or in the properties of parent nodes when inheriting.)
468
st_theme_node_get_color (StThemeNode *node,
469
const char *property_name,
476
ensure_properties (node);
478
for (i = node->n_properties - 1; i >= 0; i--)
480
CRDeclaration *decl = node->properties[i];
482
if (strcmp (decl->property->stryng->str, property_name) == 0)
484
GetFromTermResult result = get_color_from_term (node, decl->value, color);
485
if (result == VALUE_FOUND)
489
else if (result == VALUE_INHERIT)
491
if (node->parent_node)
492
return st_theme_node_get_color (node->parent_node, property_name, inherit, color);
503
* st_theme_node_get_double:
504
* @node: a #StThemeNode
505
* @property_name: The name of the numeric property
506
* @inherit: if %TRUE, if a value is not found for the property on the
507
* node, then it will be looked up on the parent node, and then on the
508
* parent's parent, and so forth. Note that if the property has a
509
* value of 'inherit' it will be inherited even if %FALSE is passed
510
* in for @inherit; this only affects the default behavior for inheritance.
511
* @value: (out): location to store the value that was determined.
512
* If the property is not found, the value in this location
513
* will not be changed.
515
* Generically looks up a property containing a single numeric value
518
* Return value: %TRUE if the property was found in the properties for this
519
* theme node (or in the properties of parent nodes when inheriting.)
522
st_theme_node_get_double (StThemeNode *node,
523
const char *property_name,
527
gboolean result = FALSE;
530
ensure_properties (node);
532
for (i = node->n_properties - 1; i >= 0; i--)
534
CRDeclaration *decl = node->properties[i];
536
if (strcmp (decl->property->stryng->str, property_name) == 0)
538
CRTerm *term = decl->value;
540
if (term->type != TERM_NUMBER || term->content.num->type != NUM_GENERIC)
543
*value = term->content.num->val;
549
if (!result && inherit && node->parent_node)
550
result = st_theme_node_get_double (node->parent_node, property_name, inherit, value);
555
static const PangoFontDescription *
556
get_parent_font (StThemeNode *node)
558
if (node->parent_node)
559
return st_theme_node_get_font (node->parent_node);
561
return st_theme_context_get_font (node->context);
564
static GetFromTermResult
565
get_length_from_term (StThemeNode *node,
567
gboolean use_parent_font,
578
double multiplier = 1.0;
580
if (term->type != TERM_NUMBER)
582
g_warning ("Ignoring length property that isn't a number");
586
num = term->content.num;
604
multiplier = 72. / 2.54;
608
multiplier = 72. / 25.4;
612
multiplier = 12. / 25.4;
616
type = FONT_RELATIVE;
622
/* Doing better would require actually resolving the font description
623
* to a specific font, and Pango doesn't have an ex metric anyways,
624
* so we'd have to try and synthesize it by complicated means.
626
* The 0.5em is the CSS spec suggested thing to use when nothing
627
* better is available.
629
type = FONT_RELATIVE;
635
return VALUE_INHERIT;
638
g_warning ("'auto' not supported for lengths");
639
return VALUE_NOT_FOUND;
642
g_warning ("length values must specify a unit");
643
return VALUE_NOT_FOUND;
646
g_warning ("percentage lengths not currently supported");
647
return VALUE_NOT_FOUND;
656
case NUM_UNKNOWN_TYPE:
658
g_warning ("Ignoring invalid type of number of length property");
659
return VALUE_NOT_FOUND;
665
*length = num->val * multiplier;
669
double resolution = st_theme_context_get_resolution (node->context);
670
*length = num->val * multiplier * (resolution / 72.);
675
const PangoFontDescription *desc;
679
desc = get_parent_font (node);
681
desc = st_theme_node_get_font (node);
683
font_size = (double)pango_font_description_get_size (desc) / PANGO_SCALE;
685
if (pango_font_description_get_size_is_absolute (desc))
687
*length = num->val * multiplier * font_size;
691
double resolution = st_theme_context_get_resolution (node->context);
692
*length = num->val * multiplier * (resolution / 72.) * font_size;
697
g_assert_not_reached ();
703
static GetFromTermResult
704
get_length_internal (StThemeNode *node,
705
const char *property_name,
706
const char *suffixed,
711
ensure_properties (node);
713
for (i = node->n_properties - 1; i >= 0; i--)
715
CRDeclaration *decl = node->properties[i];
717
if (strcmp (decl->property->stryng->str, property_name) == 0 ||
718
(suffixed != NULL && strcmp (decl->property->stryng->str, suffixed) == 0))
720
GetFromTermResult result = get_length_from_term (node, decl->value, FALSE, length);
721
if (result != VALUE_NOT_FOUND)
726
return VALUE_NOT_FOUND;
730
* st_theme_node_get_length:
731
* @node: a #StThemeNode
732
* @property_name: The name of the length property
733
* @inherit: if %TRUE, if a value is not found for the property on the
734
* node, then it will be looked up on the parent node, and then on the
735
* parent's parent, and so forth. Note that if the property has a
736
* value of 'inherit' it will be inherited even if %FALSE is passed
737
* in for @inherit; this only affects the default behavior for inheritance.
738
* @length: (out): location to store the length that was determined.
739
* If the property is not found, the value in this location
740
* will not be changed. The returned length is resolved
743
* Generically looks up a property containing a single length value. When
744
* specific getters (like st_theme_node_get_border_width()) exist, they
745
* should be used instead. They are cached, so more efficient, and have
746
* handling for shortcut properties and other details of CSS.
748
* Return value: %TRUE if the property was found in the properties for this
749
* theme node (or in the properties of parent nodes when inheriting.)
752
st_theme_node_get_length (StThemeNode *node,
753
const char *property_name,
757
GetFromTermResult result = get_length_internal (node, property_name, NULL, length);
758
if (result == VALUE_FOUND)
760
else if (result == VALUE_INHERIT)
763
if (inherit && node->parent_node &&
764
st_theme_node_get_length (node->parent_node, property_name, inherit, length))
771
do_border_radius_term (StThemeNode *node,
775
gboolean bottomright,
780
if (get_length_from_term (node, term, FALSE, &value) != VALUE_FOUND)
784
node->border_radius[ST_CORNER_TOPLEFT] = value;
786
node->border_radius[ST_CORNER_TOPRIGHT] = value;
788
node->border_radius[ST_CORNER_BOTTOMRIGHT] = value;
790
node->border_radius[ST_CORNER_BOTTOMLEFT] = value;
794
do_border_radius (StThemeNode *node,
797
const char *property_name = decl->property->stryng->str + 13; /* Skip 'border-radius' */
799
if (strcmp (property_name, "") == 0)
801
/* Slight deviation ... if we don't understand some of the terms and understand others,
802
* then we set the ones we understand and ignore the others instead of ignoring the
805
if (decl->value == NULL) /* 0 values */
807
else if (decl->value->next == NULL) /* 1 value */
809
do_border_radius_term (node, decl->value, TRUE, TRUE, TRUE, TRUE); /* all corners */
812
else if (decl->value->next->next == NULL) /* 2 values */
814
do_border_radius_term (node, decl->value, TRUE, FALSE, TRUE, FALSE); /* topleft/bottomright */
815
do_border_radius_term (node, decl->value->next, FALSE, TRUE, FALSE, TRUE); /* topright/bottomleft */
817
else if (decl->value->next->next->next == NULL) /* 3 values */
819
do_border_radius_term (node, decl->value, TRUE, FALSE, FALSE, FALSE); /* topleft */
820
do_border_radius_term (node, decl->value->next, FALSE, TRUE, FALSE, TRUE); /* topright/bottomleft */
821
do_border_radius_term (node, decl->value->next->next, FALSE, FALSE, TRUE, FALSE); /* bottomright */
823
else if (decl->value->next->next->next->next == NULL) /* 4 values */
825
do_border_radius_term (node, decl->value, TRUE, FALSE, FALSE, FALSE); /* topleft */
826
do_border_radius_term (node, decl->value->next, FALSE, TRUE, FALSE, FALSE); /* topright */
827
do_border_radius_term (node, decl->value->next->next, FALSE, FALSE, TRUE, FALSE); /* bottomright */
828
do_border_radius_term (node, decl->value->next->next->next, FALSE, FALSE, FALSE, TRUE); /* bottomleft */
832
g_warning ("Too many values for border-radius property");
838
if (decl->value == NULL || decl->value->next != NULL)
841
if (strcmp (property_name, "-topleft") == 0)
842
do_border_radius_term (node, decl->value, TRUE, FALSE, FALSE, FALSE);
843
else if (strcmp (property_name, "-topright") == 0)
844
do_border_radius_term (node, decl->value, FALSE, TRUE, FALSE, FALSE);
845
else if (strcmp (property_name, "-bottomright") == 0)
846
do_border_radius_term (node, decl->value, FALSE, FALSE, TRUE, FALSE);
847
else if (strcmp (property_name, "-bottomleft") == 0)
848
do_border_radius_term (node, decl->value, FALSE, FALSE, FALSE, TRUE);
853
do_border_property (StThemeNode *node,
856
const char *property_name = decl->property->stryng->str + 6; /* Skip 'border' */
857
StSide side = (StSide)-1;
859
gboolean color_set = FALSE;
861
gboolean width_set = FALSE;
864
if (g_str_has_prefix (property_name, "-radius"))
866
do_border_radius (node, decl);
870
if (g_str_has_prefix (property_name, "-left"))
875
else if (g_str_has_prefix (property_name, "-right"))
877
side = ST_SIDE_RIGHT;
880
else if (g_str_has_prefix (property_name, "-top"))
885
else if (g_str_has_prefix (property_name, "-bottom"))
887
side = ST_SIDE_BOTTOM;
891
if (strcmp (property_name, "") == 0)
893
/* Set value for width/color/node in any order */
896
for (term = decl->value; term; term = term->next)
898
GetFromTermResult result;
900
if (term->type == TERM_IDENT)
902
const char *ident = term->content.str->stryng->str;
903
if (strcmp (ident, "none") == 0 || strcmp (ident, "hidden") == 0)
908
else if (strcmp (ident, "solid") == 0)
910
/* The only thing we support */
913
else if (strcmp (ident, "dotted") == 0 ||
914
strcmp (ident, "dashed") == 0 ||
915
strcmp (ident, "solid") == 0 ||
916
strcmp (ident, "double") == 0 ||
917
strcmp (ident, "groove") == 0 ||
918
strcmp (ident, "ridge") == 0 ||
919
strcmp (ident, "inset") == 0 ||
920
strcmp (ident, "outset") == 0)
922
/* Treat the same as solid */
926
/* Presumably a color, fall through */
929
if (term->type == TERM_NUMBER)
931
result = get_length_from_term (node, term, FALSE, &width);
932
if (result != VALUE_NOT_FOUND)
934
width_set = result == VALUE_FOUND;
939
result = get_color_from_term (node, term, &color);
940
if (result != VALUE_NOT_FOUND)
942
color_set = result == VALUE_FOUND;
948
else if (strcmp (property_name, "-color") == 0)
950
if (decl->value == NULL || decl->value->next != NULL)
953
if (get_color_from_term (node, decl->value, &color) == VALUE_FOUND)
957
else if (strcmp (property_name, "-width") == 0)
959
if (decl->value == NULL || decl->value->next != NULL)
962
if (get_length_from_term (node, decl->value, FALSE, &width) == VALUE_FOUND)
967
if (side == (StSide)-1)
969
for (j = 0; j < 4; j++)
972
node->border_color[j] = color;
974
node->border_width[j] = width;
980
node->border_color[side] = color;
982
node->border_width[side] = width;
987
do_padding_property_term (StThemeNode *node,
996
if (get_length_from_term (node, term, FALSE, &value) != VALUE_FOUND)
1000
node->padding[ST_SIDE_LEFT] = value;
1002
node->padding[ST_SIDE_RIGHT] = value;
1004
node->padding[ST_SIDE_TOP] = value;
1006
node->padding[ST_SIDE_BOTTOM] = value;
1010
do_padding_property (StThemeNode *node,
1011
CRDeclaration *decl)
1013
const char *property_name = decl->property->stryng->str + 7; /* Skip 'padding' */
1015
if (strcmp (property_name, "") == 0)
1017
/* Slight deviation ... if we don't understand some of the terms and understand others,
1018
* then we set the ones we understand and ignore the others instead of ignoring the
1021
if (decl->value == NULL) /* 0 values */
1023
else if (decl->value->next == NULL) /* 1 value */
1025
do_padding_property_term (node, decl->value, TRUE, TRUE, TRUE, TRUE); /* left/right/top/bottom */
1028
else if (decl->value->next->next == NULL) /* 2 values */
1030
do_padding_property_term (node, decl->value, FALSE, FALSE, TRUE, TRUE); /* top/bottom */
1031
do_padding_property_term (node, decl->value->next, TRUE, TRUE, FALSE, FALSE); /* left/right */
1033
else if (decl->value->next->next->next == NULL) /* 3 values */
1035
do_padding_property_term (node, decl->value, FALSE, FALSE, TRUE, FALSE); /* top */
1036
do_padding_property_term (node, decl->value->next, TRUE, TRUE, FALSE, FALSE); /* left/right */
1037
do_padding_property_term (node, decl->value->next->next, FALSE, FALSE, FALSE, TRUE); /* bottom */
1039
else if (decl->value->next->next->next->next == NULL) /* 4 values */
1041
do_padding_property_term (node, decl->value, FALSE, FALSE, TRUE, FALSE); /* top */
1042
do_padding_property_term (node, decl->value->next, FALSE, TRUE, FALSE, FALSE); /* right */
1043
do_padding_property_term (node, decl->value->next->next, FALSE, FALSE, FALSE, TRUE); /* bottom */
1044
do_padding_property_term (node, decl->value->next->next->next, TRUE, FALSE, FALSE, FALSE); /* left */
1048
g_warning ("Too many values for padding property");
1054
if (decl->value == NULL || decl->value->next != NULL)
1057
if (strcmp (property_name, "-left") == 0)
1058
do_padding_property_term (node, decl->value, TRUE, FALSE, FALSE, FALSE);
1059
else if (strcmp (property_name, "-right") == 0)
1060
do_padding_property_term (node, decl->value, FALSE, TRUE, FALSE, FALSE);
1061
else if (strcmp (property_name, "-top") == 0)
1062
do_padding_property_term (node, decl->value, FALSE, FALSE, TRUE, FALSE);
1063
else if (strcmp (property_name, "-bottom") == 0)
1064
do_padding_property_term (node, decl->value, FALSE, FALSE, FALSE, TRUE);
1069
ensure_borders (StThemeNode *node)
1073
if (node->borders_computed)
1076
node->borders_computed = TRUE;
1078
ensure_properties (node);
1080
for (j = 0; j < 4; j++)
1082
node->border_width[j] = 0;
1083
node->border_color[j] = TRANSPARENT_COLOR;
1086
for (i = 0; i < node->n_properties; i++)
1088
CRDeclaration *decl = node->properties[i];
1089
const char *property_name = decl->property->stryng->str;
1091
if (g_str_has_prefix (property_name, "border"))
1092
do_border_property (node, decl);
1093
else if (g_str_has_prefix (property_name, "padding"))
1094
do_padding_property (node, decl);
1099
st_theme_node_get_border_width (StThemeNode *node,
1102
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
1103
g_return_val_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT, 0.);
1105
ensure_borders (node);
1107
return node->border_width[side];
1111
st_theme_node_get_border_radius (StThemeNode *node,
1114
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
1115
g_return_val_if_fail (corner >= ST_CORNER_TOPLEFT && corner <= ST_CORNER_BOTTOMLEFT, 0.);
1117
ensure_borders (node);
1119
return node->border_radius[corner];
1122
static GetFromTermResult
1123
get_background_color_from_term (StThemeNode *node,
1125
ClutterColor *color)
1127
GetFromTermResult result = get_color_from_term (node, term, color);
1128
if (result == VALUE_NOT_FOUND)
1130
if (term_is_transparent (term))
1132
*color = TRANSPARENT_COLOR;
1141
ensure_background (StThemeNode *node)
1145
if (node->background_computed)
1148
node->background_computed = TRUE;
1149
node->background_color = TRANSPARENT_COLOR;
1151
ensure_properties (node);
1153
for (i = 0; i < node->n_properties; i++)
1155
CRDeclaration *decl = node->properties[i];
1156
const char *property_name = decl->property->stryng->str;
1158
if (g_str_has_prefix (property_name, "background"))
1159
property_name += 10;
1163
if (strcmp (property_name, "") == 0)
1165
/* We're very liberal here ... if we recognize any term in the expression we take it, and
1166
* we ignore the rest. The actual specification is:
1168
* background: [<'background-color'> || <'background-image'> || <'background-repeat'> || <'background-attachment'> || <'background-position'>] | inherit
1172
/* background: property sets all terms to specified or default values */
1173
node->background_color = TRANSPARENT_COLOR;
1174
g_free (node->background_image);
1175
node->background_image = NULL;
1177
for (term = decl->value; term; term = term->next)
1179
GetFromTermResult result = get_background_color_from_term (node, term, &node->background_color);
1180
if (result == VALUE_FOUND)
1182
/* color stored in node->background_color */
1184
else if (result == VALUE_INHERIT)
1186
if (node->parent_node)
1188
st_theme_node_get_background_color (node->parent_node, &node->background_color);
1189
node->background_image = g_strdup (st_theme_node_get_background_image (node->parent_node));
1192
else if (term_is_none (term))
1194
/* leave node->background_color as transparent */
1196
else if (term->type == TERM_URI)
1198
node->background_image = _st_theme_resolve_url (node->theme,
1199
decl->parent_statement->parent_sheet,
1200
term->content.str->stryng->str);
1204
else if (strcmp (property_name, "-color") == 0)
1206
GetFromTermResult result;
1208
if (decl->value == NULL || decl->value->next != NULL)
1211
result = get_background_color_from_term (node, decl->value, &node->background_color);
1212
if (result == VALUE_FOUND)
1214
/* color stored in node->background_color */
1216
else if (result == VALUE_INHERIT)
1218
if (node->parent_node)
1219
st_theme_node_get_background_color (node->parent_node, &node->background_color);
1222
else if (strcmp (property_name, "-image") == 0)
1224
if (decl->value == NULL || decl->value->next != NULL)
1227
if (decl->value->type == TERM_URI)
1229
g_free (node->background_image);
1230
node->background_image = _st_theme_resolve_url (node->theme,
1231
decl->parent_statement->parent_sheet,
1232
decl->value->content.str->stryng->str);
1234
else if (term_is_inherit (decl->value))
1236
g_free (node->background_image);
1237
node->background_image = g_strdup (st_theme_node_get_background_image (node->parent_node));
1239
else if (term_is_none (decl->value))
1241
g_free (node->background_image);
1242
node->background_image = NULL;
1249
st_theme_node_get_background_color (StThemeNode *node,
1250
ClutterColor *color)
1252
g_return_if_fail (ST_IS_THEME_NODE (node));
1254
ensure_background (node);
1256
*color = node->background_color;
1260
st_theme_node_get_background_image (StThemeNode *node)
1262
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
1264
ensure_background (node);
1266
return node->background_image;
1270
st_theme_node_get_foreground_color (StThemeNode *node,
1271
ClutterColor *color)
1273
g_return_if_fail (ST_IS_THEME_NODE (node));
1275
if (!node->foreground_computed)
1279
node->foreground_computed = TRUE;
1281
ensure_properties (node);
1283
for (i = node->n_properties - 1; i >= 0; i--)
1285
CRDeclaration *decl = node->properties[i];
1287
if (strcmp (decl->property->stryng->str, "color") == 0)
1289
GetFromTermResult result = get_color_from_term (node, decl->value, &node->foreground_color);
1290
if (result == VALUE_FOUND)
1292
else if (result == VALUE_INHERIT)
1297
if (node->parent_node)
1298
st_theme_node_get_foreground_color (node->parent_node, &node->foreground_color);
1300
node->foreground_color = BLACK_COLOR; /* default to black */
1304
*color = node->foreground_color;
1308
st_theme_node_get_border_color (StThemeNode *node,
1310
ClutterColor *color)
1312
g_return_if_fail (ST_IS_THEME_NODE (node));
1313
g_return_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT);
1315
ensure_borders (node);
1317
*color = node->border_color[side];
1321
st_theme_node_get_padding (StThemeNode *node,
1324
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
1325
g_return_val_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT, 0.);
1327
ensure_borders (node);
1329
return node->padding[side];
1333
st_theme_node_get_text_decoration (StThemeNode *node)
1337
ensure_properties (node);
1339
for (i = node->n_properties - 1; i >= 0; i--)
1341
CRDeclaration *decl = node->properties[i];
1343
if (strcmp (decl->property->stryng->str, "text-decoration") == 0)
1345
CRTerm *term = decl->value;
1346
StTextDecoration decoration = 0;
1348
/* Specification is none | [ underline || overline || line-through || blink ] | inherit
1350
* We're a bit more liberal, and for example treat 'underline none' as the same as
1353
for (; term; term = term->next)
1355
if (term->type != TERM_IDENT)
1358
if (strcmp (term->content.str->stryng->str, "none") == 0)
1362
else if (strcmp (term->content.str->stryng->str, "inherit") == 0)
1364
if (node->parent_node)
1365
return st_theme_node_get_text_decoration (node->parent_node);
1367
else if (strcmp (term->content.str->stryng->str, "underline") == 0)
1369
decoration |= ST_TEXT_DECORATION_UNDERLINE;
1371
else if (strcmp (term->content.str->stryng->str, "overline") == 0)
1373
decoration |= ST_TEXT_DECORATION_OVERLINE;
1375
else if (strcmp (term->content.str->stryng->str, "line-through") == 0)
1377
decoration |= ST_TEXT_DECORATION_LINE_THROUGH;
1379
else if (strcmp (term->content.str->stryng->str, "blink") == 0)
1381
decoration |= ST_TEXT_DECORATION_BLINK;
1400
font_family_from_terms (CRTerm *term,
1403
GString *family_string;
1404
gboolean result = FALSE;
1405
gboolean last_was_quoted = FALSE;
1410
family_string = g_string_new (NULL);
1414
if (term->type != TERM_STRING && term->type != TERM_IDENT)
1419
if (family_string->len > 0)
1421
if (term->the_operator != COMMA && term->the_operator != NO_OP)
1423
/* Can concatenate two bare words, but not two quoted strings */
1424
if ((term->the_operator == NO_OP && last_was_quoted) || term->type == TERM_STRING)
1427
if (term->the_operator == NO_OP)
1428
g_string_append (family_string, " ");
1430
g_string_append (family_string, ", ");
1434
if (term->the_operator != NO_OP)
1438
g_string_append (family_string, term->content.str->stryng->str);
1448
*family = g_string_free (family_string, FALSE);
1453
*family = g_string_free (family_string, TRUE);
1459
static int font_sizes[] = {
1460
6 * 1024, /* xx-small */
1461
8 * 1024, /* x-small */
1462
10 * 1024, /* small */
1463
12 * 1024, /* medium */
1464
16 * 1024, /* large */
1465
20 * 1024, /* x-large */
1466
24 * 1024, /* xx-large */
1470
font_size_from_term (StThemeNode *node,
1474
if (term->type == TERM_IDENT)
1476
double resolution = st_theme_context_get_resolution (node->context);
1477
/* We work in integers to avoid double comparisons when converting back
1478
* from a size in pixels to a logical size.
1480
int size_points = (int)(0.5 + *size * (72. / resolution));
1482
if (strcmp (term->content.str->stryng->str, "xx-small") == 0)
1483
size_points = font_sizes[0];
1484
else if (strcmp (term->content.str->stryng->str, "x-small") == 0)
1485
size_points = font_sizes[1];
1486
else if (strcmp (term->content.str->stryng->str, "small") == 0)
1487
size_points = font_sizes[2];
1488
else if (strcmp (term->content.str->stryng->str, "medium") == 0)
1489
size_points = font_sizes[3];
1490
else if (strcmp (term->content.str->stryng->str, "large") == 0)
1491
size_points = font_sizes[4];
1492
else if (strcmp (term->content.str->stryng->str, "x-large") == 0)
1493
size_points = font_sizes[5];
1494
else if (strcmp (term->content.str->stryng->str, "xx-large") == 0)
1495
size_points = font_sizes[6];
1496
else if (strcmp (term->content.str->stryng->str, "smaller") == 0)
1498
/* Find the standard size equal to or smaller than the current size */
1501
while (i <= 6 && font_sizes[i] < size_points)
1506
/* original size greater than any standard size */
1507
size_points = (int)(0.5 + size_points / 1.2);
1511
/* Go one smaller than that, if possible */
1515
size_points = font_sizes[i];
1518
else if (strcmp (term->content.str->stryng->str, "larger") == 0)
1520
/* Find the standard size equal to or larger than the current size */
1523
while (i >= 0 && font_sizes[i] > size_points)
1526
if (i < 0) /* original size smaller than any standard size */
1529
/* Go one larger than that, if possible */
1533
size_points = font_sizes[i];
1540
*size = size_points * (resolution / 72.);
1544
else if (term->type == TERM_NUMBER && term->content.num->type == NUM_PERCENTAGE)
1546
*size *= term->content.num->val / 100.;
1549
else if (get_length_from_term (node, term, TRUE, size) == VALUE_FOUND)
1551
/* Convert from pixels to Pango units */
1560
font_weight_from_term (CRTerm *term,
1561
PangoWeight *weight,
1562
gboolean *weight_absolute)
1564
if (term->type == TERM_NUMBER)
1568
/* The spec only allows numeric weights from 100-900, though Pango
1569
* will handle any number. We just let anything through.
1571
if (term->content.num->type != NUM_GENERIC)
1574
weight_int = (int)(0.5 + term->content.num->val);
1576
*weight = weight_int;
1577
*weight_absolute = TRUE;
1580
else if (term->type == TERM_IDENT)
1582
/* FIXME: handle INHERIT */
1584
if (strcmp (term->content.str->stryng->str, "bold") == 0)
1586
*weight = PANGO_WEIGHT_BOLD;
1587
*weight_absolute = TRUE;
1589
else if (strcmp (term->content.str->stryng->str, "normal") == 0)
1591
*weight = PANGO_WEIGHT_NORMAL;
1592
*weight_absolute = TRUE;
1594
else if (strcmp (term->content.str->stryng->str, "bolder") == 0)
1596
*weight = PANGO_WEIGHT_BOLD;
1597
*weight_absolute = FALSE;
1599
else if (strcmp (term->content.str->stryng->str, "lighter") == 0)
1601
*weight = PANGO_WEIGHT_LIGHT;
1602
*weight_absolute = FALSE;
1619
font_style_from_term (CRTerm *term,
1622
if (term->type != TERM_IDENT)
1625
/* FIXME: handle INHERIT */
1627
if (strcmp (term->content.str->stryng->str, "normal") == 0)
1628
*style = PANGO_STYLE_NORMAL;
1629
else if (strcmp (term->content.str->stryng->str, "oblique") == 0)
1630
*style = PANGO_STYLE_OBLIQUE;
1631
else if (strcmp (term->content.str->stryng->str, "italic") == 0)
1632
*style = PANGO_STYLE_ITALIC;
1640
font_variant_from_term (CRTerm *term,
1641
PangoVariant *variant)
1643
if (term->type != TERM_IDENT)
1646
/* FIXME: handle INHERIT */
1648
if (strcmp (term->content.str->stryng->str, "normal") == 0)
1649
*variant = PANGO_VARIANT_NORMAL;
1650
else if (strcmp (term->content.str->stryng->str, "small-caps") == 0)
1651
*variant = PANGO_VARIANT_SMALL_CAPS;
1658
const PangoFontDescription *
1659
st_theme_node_get_font (StThemeNode *node)
1661
PangoStyle font_style;
1662
gboolean font_style_set = FALSE;
1663
PangoVariant variant;
1664
gboolean variant_set = FALSE;
1666
gboolean weight_absolute;
1667
gboolean weight_set = FALSE;
1669
double size = 0.; /* Suppress warning */
1670
gboolean size_set = FALSE;
1671
char *family = NULL;
1674
if (node->font_desc)
1675
return node->font_desc;
1677
node->font_desc = pango_font_description_copy (get_parent_font (node));
1678
parent_size = pango_font_description_get_size (node->font_desc);
1679
if (!pango_font_description_get_size_is_absolute (node->font_desc))
1681
double resolution = st_theme_context_get_resolution (node->context);
1682
parent_size *= (resolution / 72.);
1685
ensure_properties (node);
1687
for (i = 0; i < node->n_properties; i++)
1689
CRDeclaration *decl = node->properties[i];
1691
if (strcmp (decl->property->stryng->str, "font") == 0)
1693
PangoStyle tmp_style = PANGO_STYLE_NORMAL;
1694
PangoVariant tmp_variant = PANGO_VARIANT_NORMAL;
1695
PangoWeight tmp_weight = PANGO_WEIGHT_NORMAL;
1696
gboolean tmp_weight_absolute = TRUE;
1698
CRTerm *term = decl->value;
1700
/* A font specification starts with node/variant/weight
1701
* in any order. Each is allowed to be specified only once,
1702
* but we don't enforce that.
1704
for (; term; term = term->next)
1706
if (font_style_from_term (term, &tmp_style))
1708
if (font_variant_from_term (term, &tmp_variant))
1710
if (font_weight_from_term (term, &tmp_weight, &tmp_weight_absolute))
1716
/* The size is mandatory */
1718
if (term == NULL || term->type != TERM_NUMBER)
1720
g_warning ("Size missing from font property");
1724
tmp_size = parent_size;
1725
if (!font_size_from_term (node, term, &tmp_size))
1727
g_warning ("Couldn't parse size in font property");
1733
if (term != NULL && term->type && TERM_NUMBER && term->the_operator == DIVIDE)
1735
/* Ignore line-height specification */
1739
/* the font family is mandatory - it is a comma-separated list of
1742
if (!font_family_from_terms (term, &family))
1744
g_warning ("Couldn't parse family in font property");
1748
font_style = tmp_style;
1749
font_style_set = TRUE;
1750
weight = tmp_weight;
1751
weight_absolute = tmp_weight_absolute;
1753
variant = tmp_variant;
1760
else if (strcmp (decl->property->stryng->str, "font-family") == 0)
1762
if (!font_family_from_terms (decl->value, &family))
1764
g_warning ("Couldn't parse family in font property");
1768
else if (strcmp (decl->property->stryng->str, "font-weight") == 0)
1770
if (decl->value == NULL || decl->value->next != NULL)
1773
if (font_weight_from_term (decl->value, &weight, &weight_absolute))
1776
else if (strcmp (decl->property->stryng->str, "font-style") == 0)
1778
if (decl->value == NULL || decl->value->next != NULL)
1781
if (font_style_from_term (decl->value, &font_style))
1782
font_style_set = TRUE;
1784
else if (strcmp (decl->property->stryng->str, "font-variant") == 0)
1786
if (decl->value == NULL || decl->value->next != NULL)
1789
if (font_variant_from_term (decl->value, &variant))
1792
else if (strcmp (decl->property->stryng->str, "font-size") == 0)
1795
if (decl->value == NULL || decl->value->next != NULL)
1798
tmp_size = parent_size;
1799
if (font_size_from_term (node, decl->value, &tmp_size))
1808
pango_font_description_set_family (node->font_desc, family);
1811
pango_font_description_set_absolute_size (node->font_desc, size);
1815
if (!weight_absolute)
1817
/* bolder/lighter are supposed to switch between available styles, but with
1818
* font substitution, that gets to be a pretty fuzzy concept. So we use
1819
* a fixed step of 200. (The spec says 100, but that might not take us from
1823
PangoWeight old_weight = pango_font_description_get_weight (node->font_desc);
1824
if (weight == PANGO_WEIGHT_BOLD)
1825
weight = old_weight + 200;
1827
weight = old_weight - 200;
1835
pango_font_description_set_weight (node->font_desc, weight);
1839
pango_font_description_set_style (node->font_desc, font_style);
1841
pango_font_description_set_variant (node->font_desc, variant);
1843
return node->font_desc;
1847
* st_theme_node_get_border_image:
1848
* @node: a #StThemeNode
1850
* Gets the value for the border-image style property
1852
* Return value: (transfer none): the border image, or %NULL
1853
* if there is no border image.
1856
st_theme_node_get_border_image (StThemeNode *node)
1860
if (node->border_image_computed)
1861
return node->border_image;
1863
node->border_image = NULL;
1864
node->border_image_computed = TRUE;
1866
ensure_properties (node);
1868
for (i = node->n_properties - 1; i >= 0; i--)
1870
CRDeclaration *decl = node->properties[i];
1872
if (strcmp (decl->property->stryng->str, "border-image") == 0)
1874
CRTerm *term = decl->value;
1887
/* First term must be the URL to the image */
1888
if (term->type != TERM_URI)
1891
url = term->content.str->stryng->str;
1895
/* Followed by 0 to 4 numbers or percentages. *Not lengths*. The interpretation
1896
* of a number is supposed to be pixels if the image is pixel based, otherwise CSS pixels.
1898
for (i = 0; i < 4; i++)
1903
if (term->type != TERM_NUMBER)
1906
if (term->content.num->type == NUM_GENERIC)
1908
borders[n_borders] = (int)(0.5 + term->content.num->val);
1911
else if (term->content.num->type == NUM_PERCENTAGE)
1913
/* This would be easiest to support if we moved image handling into StBorderImage */
1914
g_warning ("Percentages not supported for border-image");
1926
border_top = border_right = border_bottom = border_left = 0;
1929
border_top = border_right = border_bottom = border_left = borders[0];
1932
border_top = border_bottom = borders[0];
1933
border_left = border_right = borders[1];
1936
border_top = borders[0];
1937
border_left = border_right = borders[1];
1938
border_bottom = borders[2];
1942
border_top = borders[0];
1943
border_right = borders[1];
1944
border_bottom = borders[2];
1945
border_left = borders[3];
1949
filename = _st_theme_resolve_url (node->theme, decl->parent_statement->parent_sheet, url);
1950
if (filename == NULL)
1953
node->border_image = st_border_image_new (filename,
1954
border_top, border_right, border_bottom, border_left);
1958
return node->border_image;
1969
get_width_inc (StThemeNode *node)
1971
return ((int)(0.5 + node->border_width[ST_SIDE_LEFT]) + node->padding[ST_SIDE_LEFT] +
1972
(int)(0.5 + node->border_width[ST_SIDE_RIGHT]) + node->padding[ST_SIDE_RIGHT]);
1976
get_height_inc (StThemeNode *node)
1978
return ((int)(0.5 + node->border_width[ST_SIDE_TOP]) + node->padding[ST_SIDE_TOP] +
1979
(int)(0.5 + node->border_width[ST_SIDE_BOTTOM]) + node->padding[ST_SIDE_BOTTOM]);
1983
* st_theme_node_adjust_for_height:
1984
* @node: a #StThemeNode
1985
* @for_height: (inout): the "for height" to adjust
1987
* Adjusts a "for height" passed to clutter_actor_get_preferred_width() to
1988
* account for borders and padding. This is a convenience function meant
1989
* to be called from a get_preferred_width() method of a #ClutterActor
1990
* subclass. The value after adjustment is the height available for the actor's
1994
st_theme_node_adjust_for_height (StThemeNode *node,
1997
g_return_if_fail (ST_IS_THEME_NODE (node));
1998
g_return_if_fail (for_height != NULL);
2000
if (*for_height >= 0)
2002
float height_inc = get_height_inc (node);
2003
*for_height = MAX (0, *for_height - height_inc);
2008
* st_theme_node_adjust_preferred_width:
2009
* @node: a #StThemeNode
2010
* @min_width_p: (inout) (allow-none): the width to adjust
2011
* @for_height: (inout): the height to adjust
2013
* Adjusts the minimum and natural width computed for an actor by
2014
* adding on the necessary space for borders and padding. This is a
2015
* convenience function meant to be called from the get_preferred_width()
2016
* method of a #ClutterActor subclass
2019
st_theme_node_adjust_preferred_width (StThemeNode *node,
2021
float *natural_width_p)
2025
g_return_if_fail (ST_IS_THEME_NODE (node));
2027
ensure_borders (node);
2029
width_inc = get_width_inc (node);
2032
*min_width_p += width_inc;
2033
if (natural_width_p)
2034
*natural_width_p += width_inc;
2038
* st_theme_node_adjust_for_width:
2039
* @node: a #StThemeNode
2040
* @for_width: (inout): the "for width" to adjust
2042
* Adjusts a "for width" passed to clutter_actor_get_preferred_height() to
2043
* account for borders and padding. This is a convenience function meant
2044
* to be called from a get_preferred_height() method of a #ClutterActor
2045
* subclass. The value after adjustmnet is the width available for the actor's
2049
st_theme_node_adjust_for_width (StThemeNode *node,
2052
g_return_if_fail (ST_IS_THEME_NODE (node));
2053
g_return_if_fail (for_width != NULL);
2055
if (*for_width >= 0)
2057
float width_inc = get_width_inc (node);
2058
*for_width = MAX (0, *for_width - width_inc);
2063
* st_theme_node_adjust_preferred_height:
2064
* @node: a #StThemeNode
2065
* @min_height_p: (inout) (allow-none): the height to adjust
2066
* @for_height: (inout): the height to adjust
2068
* Adjusts the minimum and natural height computed for an actor by
2069
* adding on the necessary space for borders and padding. This is a
2070
* convenience function meant to be called from the get_preferred_height()
2071
* method of a #ClutterActor subclass
2074
st_theme_node_adjust_preferred_height (StThemeNode *node,
2075
float *min_height_p,
2076
float *natural_height_p)
2080
g_return_if_fail (ST_IS_THEME_NODE (node));
2082
ensure_borders (node);
2084
height_inc = get_height_inc (node);
2087
*min_height_p += height_inc;
2088
if (natural_height_p)
2089
*natural_height_p += height_inc;
2093
* st_theme_node_get_content_box:
2094
* @node: a #StThemeNode
2095
* @allocation: the box allocated to a #ClutterAlctor
2096
* @content_box: (out): computed box occupied by the actor's content
2098
* Gets the box within an actor's allocation that contents the content
2099
* of an actor (excluding borders and padding). This is a convenience function
2100
* meant to be used from the allocate() or paint() methods of a #ClutterActor
2104
st_theme_node_get_content_box (StThemeNode *node,
2105
const ClutterActorBox *allocation,
2106
ClutterActorBox *content_box)
2108
g_return_if_fail (ST_IS_THEME_NODE (node));
2110
ensure_borders (node);
2112
content_box->x1 = (int)(0.5 + node->border_width[ST_SIDE_LEFT]) + node->padding[ST_SIDE_LEFT];
2113
content_box->y1 = (int)(0.5 + node->border_width[ST_SIDE_TOP]) + node->padding[ST_SIDE_TOP];
2114
content_box->x2 = allocation->x2 - allocation->x1 - ((int)(0.5 + node->border_width[ST_SIDE_RIGHT]) + node->padding[ST_SIDE_RIGHT]);
2115
content_box->y2 = allocation->y2 - allocation->y1 - ((int)(0.5 + node->border_width[ST_SIDE_BOTTOM]) + node->padding[ST_SIDE_BOTTOM]);
2120
* st_theme_node_geometry_equal:
2121
* @node: a #StThemeNode
2122
* @node: a different #StThemeNode
2124
* Tests if two theme nodes have the same borders and padding; this can be
2125
* used to optimize having to relayout when the style applied to a Clutter
2126
* actor changes colors without changing the geometry.
2129
st_theme_node_geometry_equal (StThemeNode *node,
2134
ensure_borders (node);
2135
ensure_borders (other);
2137
for (side = ST_SIDE_TOP; side <= ST_SIDE_LEFT; side++)
2139
if (node->border_width[side] != other->border_width[side])
2141
if (node->padding[side] != other->padding[side])