2009-09-20 00:43:49 +00:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
2010-11-10 22:00:45 +00:00
|
|
|
/*
|
|
|
|
* st-theme-node.c: style information for one node in a tree of themed objects
|
|
|
|
*
|
|
|
|
* Copyright 2008-2010 Red Hat, Inc.
|
|
|
|
* Copyright 2009 Steve Frécinaux
|
|
|
|
* Copyright 2009, 2010 Florian Müllner
|
|
|
|
* Copyright 2010 Adel Gadllah
|
|
|
|
* Copyright 2010 Giovanni Campagna
|
2011-12-23 17:59:20 +00:00
|
|
|
* Copyright 2011 Quentin "Sardem FF7" Glidic
|
2010-11-10 22:00:45 +00:00
|
|
|
*
|
|
|
|
* This program 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.1 of
|
|
|
|
* the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope 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 program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "st-theme-private.h"
|
|
|
|
#include "st-theme-context.h"
|
2010-02-08 18:40:25 +00:00
|
|
|
#include "st-theme-node-private.h"
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
static void st_theme_node_init (StThemeNode *node);
|
|
|
|
static void st_theme_node_class_init (StThemeNodeClass *klass);
|
2010-04-02 13:39:05 +00:00
|
|
|
static void st_theme_node_dispose (GObject *object);
|
2009-09-20 00:43:49 +00:00
|
|
|
static void st_theme_node_finalize (GObject *object);
|
|
|
|
|
|
|
|
static const ClutterColor BLACK_COLOR = { 0, 0, 0, 0xff };
|
|
|
|
static const ClutterColor TRANSPARENT_COLOR = { 0, 0, 0, 0 };
|
2010-11-01 02:06:48 +00:00
|
|
|
static const ClutterColor DEFAULT_SUCCESS_COLOR = { 0x4e, 0x9a, 0x06, 0xff };
|
|
|
|
static const ClutterColor DEFAULT_WARNING_COLOR = { 0xf5, 0x79, 0x3e, 0xff };
|
|
|
|
static const ClutterColor DEFAULT_ERROR_COLOR = { 0xcc, 0x00, 0x00, 0xff };
|
2009-09-20 00:43:49 +00:00
|
|
|
|
2010-06-20 02:16:06 +00:00
|
|
|
extern gfloat st_slow_down_factor;
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
G_DEFINE_TYPE (StThemeNode, st_theme_node, G_TYPE_OBJECT)
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_theme_node_init (StThemeNode *node)
|
|
|
|
{
|
2010-05-30 21:06:37 +00:00
|
|
|
node->transition_duration = -1;
|
2013-04-05 01:22:34 +00:00
|
|
|
node->background_texture = COGL_INVALID_HANDLE;
|
|
|
|
node->background_material = COGL_INVALID_HANDLE;
|
|
|
|
node->background_shadow_material = COGL_INVALID_HANDLE;
|
|
|
|
node->border_slices_texture = COGL_INVALID_HANDLE;
|
|
|
|
node->border_slices_material = COGL_INVALID_HANDLE;
|
2013-07-08 16:24:47 +00:00
|
|
|
|
|
|
|
st_theme_node_paint_state_init (&node->cached_state);
|
2009-09-20 00:43:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_theme_node_class_init (StThemeNodeClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
2010-04-02 13:39:05 +00:00
|
|
|
object_class->dispose = st_theme_node_dispose;
|
2009-09-20 00:43:49 +00:00
|
|
|
object_class->finalize = st_theme_node_finalize;
|
|
|
|
}
|
|
|
|
|
2013-01-28 19:38:36 +00:00
|
|
|
static void
|
|
|
|
on_custom_stylesheets_changed (StTheme *theme,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
StThemeNode *node = data;
|
|
|
|
node->properties_computed = FALSE;
|
|
|
|
}
|
|
|
|
|
2010-04-02 13:39:05 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
st_theme_node_dispose (GObject *gobject)
|
|
|
|
{
|
|
|
|
StThemeNode *node = ST_THEME_NODE (gobject);
|
|
|
|
|
|
|
|
if (node->parent_node)
|
|
|
|
{
|
|
|
|
g_object_unref (node->parent_node);
|
|
|
|
node->parent_node = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->border_image)
|
|
|
|
{
|
|
|
|
g_object_unref (node->border_image);
|
|
|
|
node->border_image = NULL;
|
|
|
|
}
|
|
|
|
|
2011-12-19 04:34:00 +00:00
|
|
|
if (node->icon_colors)
|
|
|
|
{
|
|
|
|
st_icon_colors_unref (node->icon_colors);
|
|
|
|
node->icon_colors = NULL;
|
|
|
|
}
|
|
|
|
|
2013-01-28 19:38:36 +00:00
|
|
|
if (node->theme)
|
|
|
|
g_signal_handlers_disconnect_by_func (node->theme,
|
|
|
|
on_custom_stylesheets_changed, node);
|
|
|
|
|
2013-07-04 13:26:08 +00:00
|
|
|
st_theme_node_paint_state_free (&node->cached_state);
|
|
|
|
|
2012-06-25 12:08:56 +00:00
|
|
|
g_clear_object (&node->theme);
|
|
|
|
|
2010-04-02 13:39:05 +00:00
|
|
|
G_OBJECT_CLASS (st_theme_node_parent_class)->dispose (gobject);
|
|
|
|
}
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
static void
|
|
|
|
st_theme_node_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
StThemeNode *node = ST_THEME_NODE (object);
|
|
|
|
|
|
|
|
g_free (node->element_id);
|
2012-11-07 18:44:33 +00:00
|
|
|
g_strfreev (node->element_classes);
|
|
|
|
g_strfreev (node->pseudo_classes);
|
2009-09-20 02:56:09 +00:00
|
|
|
g_free (node->inline_style);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
if (node->properties)
|
|
|
|
{
|
|
|
|
g_free (node->properties);
|
|
|
|
node->properties = NULL;
|
|
|
|
node->n_properties = 0;
|
|
|
|
}
|
|
|
|
|
2009-09-20 02:56:09 +00:00
|
|
|
if (node->inline_properties)
|
|
|
|
{
|
|
|
|
/* This destroys the list, not just the head of the list */
|
|
|
|
cr_declaration_destroy (node->inline_properties);
|
|
|
|
}
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
if (node->font_desc)
|
|
|
|
{
|
|
|
|
pango_font_description_free (node->font_desc);
|
|
|
|
node->font_desc = NULL;
|
|
|
|
}
|
|
|
|
|
2011-01-13 23:27:24 +00:00
|
|
|
if (node->box_shadow)
|
2009-11-21 03:19:56 +00:00
|
|
|
{
|
2011-01-13 23:27:24 +00:00
|
|
|
st_shadow_unref (node->box_shadow);
|
|
|
|
node->box_shadow = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->background_image_shadow)
|
|
|
|
{
|
|
|
|
st_shadow_unref (node->background_image_shadow);
|
|
|
|
node->background_image_shadow = NULL;
|
2009-11-21 03:19:56 +00:00
|
|
|
}
|
|
|
|
|
2010-07-24 14:56:50 +00:00
|
|
|
if (node->text_shadow)
|
|
|
|
{
|
|
|
|
st_shadow_unref (node->text_shadow);
|
|
|
|
node->text_shadow = NULL;
|
|
|
|
}
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
if (node->background_image)
|
2014-09-19 00:04:00 +00:00
|
|
|
{
|
|
|
|
g_object_unref (node->background_image);
|
|
|
|
node->background_image = NULL;
|
|
|
|
}
|
2009-09-20 00:43:49 +00:00
|
|
|
|
2013-04-05 01:22:34 +00:00
|
|
|
if (node->background_texture != COGL_INVALID_HANDLE)
|
|
|
|
cogl_handle_unref (node->background_texture);
|
|
|
|
if (node->background_material != COGL_INVALID_HANDLE)
|
|
|
|
cogl_handle_unref (node->background_material);
|
|
|
|
if (node->background_shadow_material != COGL_INVALID_HANDLE)
|
|
|
|
cogl_handle_unref (node->background_shadow_material);
|
|
|
|
if (node->border_slices_texture != COGL_INVALID_HANDLE)
|
|
|
|
cogl_handle_unref (node->border_slices_texture);
|
|
|
|
if (node->border_slices_material != COGL_INVALID_HANDLE)
|
|
|
|
cogl_handle_unref (node->border_slices_material);
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
G_OBJECT_CLASS (st_theme_node_parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
2012-11-07 18:44:33 +00:00
|
|
|
static GStrv
|
|
|
|
split_on_whitespace (const gchar *s)
|
|
|
|
{
|
|
|
|
gchar *cur;
|
|
|
|
gchar *l;
|
|
|
|
gchar *temp;
|
|
|
|
GPtrArray *arr;
|
|
|
|
|
|
|
|
if (s == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
arr = g_ptr_array_new ();
|
|
|
|
l = g_strdup (s);
|
|
|
|
|
|
|
|
cur = strtok_r (l, " \t\f\r\n", &temp);
|
|
|
|
|
|
|
|
while (cur != NULL)
|
|
|
|
{
|
|
|
|
g_ptr_array_add (arr, g_strdup (cur));
|
|
|
|
cur = strtok_r (NULL, " \t\f\r\n", &temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (l);
|
|
|
|
g_ptr_array_add (arr, NULL);
|
|
|
|
return (GStrv) g_ptr_array_free (arr, FALSE);
|
|
|
|
}
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_new:
|
|
|
|
* @context: the context representing global state for this themed tree
|
2014-05-28 19:54:02 +00:00
|
|
|
* @parent_node: (nullable): the parent node of this node
|
|
|
|
* @theme: (nullable): a theme (stylesheet set) that overrides the
|
2009-09-20 00:43:49 +00:00
|
|
|
* theme inherited from the parent node
|
|
|
|
* @element_type: the type of the GObject represented by this node
|
|
|
|
* in the tree (corresponding to an element if we were theming an XML
|
|
|
|
* document. %G_TYPE_NONE means this style was created for the stage
|
|
|
|
* actor and matches a selector element name of 'stage'.
|
2014-05-28 19:54:02 +00:00
|
|
|
* @element_id: (nullable): the ID to match CSS rules against
|
|
|
|
* @element_class: (nullable): a whitespace-separated list of classes
|
2009-09-20 00:43:49 +00:00
|
|
|
* to match CSS rules against
|
2014-05-28 19:54:02 +00:00
|
|
|
* @pseudo_class: (nullable): a whitespace-separated list of pseudo-classes
|
2009-09-20 00:43:49 +00:00
|
|
|
* (like 'hover' or 'visited') to match CSS rules against
|
|
|
|
*
|
|
|
|
* Creates a new #StThemeNode. Once created, a node is immutable. Of any
|
|
|
|
* of the attributes of the node (like the @element_class) change the node
|
|
|
|
* and its child nodes must be destroyed and recreated.
|
|
|
|
*
|
|
|
|
* Return value: (transfer full): the theme node
|
|
|
|
*/
|
|
|
|
StThemeNode *
|
|
|
|
st_theme_node_new (StThemeContext *context,
|
|
|
|
StThemeNode *parent_node,
|
|
|
|
StTheme *theme,
|
|
|
|
GType element_type,
|
|
|
|
const char *element_id,
|
|
|
|
const char *element_class,
|
2009-09-20 02:56:09 +00:00
|
|
|
const char *pseudo_class,
|
|
|
|
const char *inline_style)
|
2009-09-20 00:43:49 +00:00
|
|
|
{
|
|
|
|
StThemeNode *node;
|
|
|
|
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_CONTEXT (context), NULL);
|
|
|
|
g_return_val_if_fail (parent_node == NULL || ST_IS_THEME_NODE (parent_node), NULL);
|
|
|
|
|
|
|
|
node = g_object_new (ST_TYPE_THEME_NODE, NULL);
|
|
|
|
|
2012-06-24 06:26:39 +00:00
|
|
|
node->context = context;
|
2009-09-20 00:43:49 +00:00
|
|
|
if (parent_node != NULL)
|
|
|
|
node->parent_node = g_object_ref (parent_node);
|
|
|
|
else
|
|
|
|
node->parent_node = NULL;
|
|
|
|
|
|
|
|
if (theme == NULL && parent_node != NULL)
|
|
|
|
theme = parent_node->theme;
|
|
|
|
|
|
|
|
if (theme != NULL)
|
2013-01-28 19:38:36 +00:00
|
|
|
{
|
|
|
|
node->theme = g_object_ref (theme);
|
|
|
|
g_signal_connect (node->theme, "custom-stylesheets-changed",
|
|
|
|
G_CALLBACK (on_custom_stylesheets_changed), node);
|
|
|
|
}
|
2012-06-25 12:08:56 +00:00
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
node->element_type = element_type;
|
|
|
|
node->element_id = g_strdup (element_id);
|
2012-11-07 18:44:33 +00:00
|
|
|
node->element_classes = split_on_whitespace (element_class);
|
|
|
|
node->pseudo_classes = split_on_whitespace (pseudo_class);
|
2009-09-20 02:56:09 +00:00
|
|
|
node->inline_style = g_strdup (inline_style);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_theme_node_get_parent:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
*
|
|
|
|
* Gets the parent themed element node.
|
|
|
|
*
|
|
|
|
* Return value: (transfer none): the parent #StThemeNode, or %NULL if this
|
|
|
|
* is the root node of the tree of theme elements.
|
|
|
|
*/
|
|
|
|
StThemeNode *
|
|
|
|
st_theme_node_get_parent (StThemeNode *node)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
|
|
|
|
|
|
|
|
return node->parent_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_theme_node_get_theme:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
*
|
|
|
|
* Gets the theme stylesheet set that styles this node
|
|
|
|
*
|
|
|
|
* Return value: (transfer none): the theme stylesheet set
|
|
|
|
*/
|
|
|
|
StTheme *
|
|
|
|
st_theme_node_get_theme (StThemeNode *node)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
|
|
|
|
|
|
|
|
return node->theme;
|
|
|
|
}
|
|
|
|
|
|
|
|
GType
|
|
|
|
st_theme_node_get_element_type (StThemeNode *node)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), G_TYPE_NONE);
|
|
|
|
|
|
|
|
return node->element_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *
|
|
|
|
st_theme_node_get_element_id (StThemeNode *node)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
|
|
|
|
|
|
|
|
return node->element_id;
|
|
|
|
}
|
|
|
|
|
2012-11-07 18:44:33 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_get_element_classes:
|
|
|
|
*
|
|
|
|
* Returns: (transfer none): the element's classes
|
|
|
|
*/
|
|
|
|
GStrv
|
|
|
|
st_theme_node_get_element_classes (StThemeNode *node)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
|
|
|
|
|
|
|
|
return node->element_classes;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_theme_node_get_pseudo_classes:
|
|
|
|
*
|
|
|
|
* Returns: (transfer none): the element's pseudo-classes
|
|
|
|
*/
|
|
|
|
GStrv
|
|
|
|
st_theme_node_get_pseudo_classes (StThemeNode *node)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
|
|
|
|
|
|
|
|
return node->pseudo_classes;
|
|
|
|
}
|
|
|
|
|
2010-05-25 18:07:53 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_equal:
|
|
|
|
* @node_a: first #StThemeNode
|
|
|
|
* @node_b: second #StThemeNode
|
|
|
|
*
|
|
|
|
* Compare two #StThemeNodes. Two nodes which compare equal will match
|
|
|
|
* the same CSS rules and have the same style properties. However, two
|
|
|
|
* nodes that have ended up with identical style properties do not
|
|
|
|
* necessarily compare equal.
|
|
|
|
* In detail, @node_a and @node_b are considered equal iff
|
|
|
|
* <itemizedlist>
|
|
|
|
* <listitem>
|
|
|
|
* <para>they share the same #StTheme and #StThemeContext</para>
|
|
|
|
* </listitem>
|
|
|
|
* <listitem>
|
|
|
|
* <para>they have the same parent</para>
|
|
|
|
* </listitem>
|
|
|
|
* <listitem>
|
|
|
|
* <para>they have the same element type</para>
|
|
|
|
* </listitem>
|
|
|
|
* <listitem>
|
|
|
|
* <para>their id, class, pseudo-class and inline-style match</para>
|
|
|
|
* </listitem>
|
|
|
|
* </itemizedlist>
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if @node_a equals @node_b
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
st_theme_node_equal (StThemeNode *node_a, StThemeNode *node_b)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node_a), FALSE);
|
2012-11-15 15:16:12 +00:00
|
|
|
|
|
|
|
if (node_a == node_b)
|
|
|
|
return TRUE;
|
|
|
|
|
2010-05-25 18:07:53 +00:00
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node_b), FALSE);
|
|
|
|
|
2012-11-07 18:52:20 +00:00
|
|
|
if (node_a->parent_node != node_b->parent_node ||
|
|
|
|
node_a->context != node_b->context ||
|
|
|
|
node_a->theme != node_b->theme ||
|
|
|
|
node_a->element_type != node_b->element_type ||
|
|
|
|
g_strcmp0 (node_a->element_id, node_b->element_id) ||
|
|
|
|
g_strcmp0 (node_a->inline_style, node_b->inline_style))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if ((node_a->element_classes == NULL) != (node_b->element_classes == NULL))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if ((node_a->pseudo_classes == NULL) != (node_b->pseudo_classes == NULL))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (node_a->element_classes != NULL)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; ; i++)
|
|
|
|
{
|
|
|
|
if (g_strcmp0 (node_a->element_classes[i],
|
|
|
|
node_b->element_classes[i]))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (node_a->element_classes[i] == NULL)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node_a->pseudo_classes != NULL)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; ; i++)
|
|
|
|
{
|
|
|
|
if (g_strcmp0 (node_a->pseudo_classes[i],
|
|
|
|
node_b->pseudo_classes[i]))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (node_a->pseudo_classes[i] == NULL)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
2010-05-25 18:07:53 +00:00
|
|
|
}
|
|
|
|
|
2012-11-08 17:50:01 +00:00
|
|
|
guint
|
|
|
|
st_theme_node_hash (StThemeNode *node)
|
|
|
|
{
|
|
|
|
guint hash = GPOINTER_TO_UINT (node->parent_node);
|
|
|
|
|
|
|
|
hash = hash * 33 + GPOINTER_TO_UINT (node->context);
|
|
|
|
hash = hash * 33 + GPOINTER_TO_UINT (node->theme);
|
|
|
|
hash = hash * 33 + ((guint) node->element_type);
|
|
|
|
|
|
|
|
if (node->element_id != NULL)
|
|
|
|
hash = hash * 33 + g_str_hash (node->element_id);
|
|
|
|
|
|
|
|
if (node->inline_style != NULL)
|
|
|
|
hash = hash * 33 + g_str_hash (node->inline_style);
|
|
|
|
|
|
|
|
if (node->element_classes != NULL)
|
|
|
|
{
|
|
|
|
gchar **it;
|
|
|
|
|
|
|
|
for (it = node->element_classes; *it != NULL; it++)
|
|
|
|
hash = hash * 33 + g_str_hash (*it) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->pseudo_classes != NULL)
|
|
|
|
{
|
|
|
|
gchar **it;
|
|
|
|
|
|
|
|
for (it = node->pseudo_classes; *it != NULL; it++)
|
|
|
|
hash = hash * 33 + g_str_hash (*it) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
2010-03-24 18:24:25 +00:00
|
|
|
static void
|
2009-09-20 00:43:49 +00:00
|
|
|
ensure_properties (StThemeNode *node)
|
|
|
|
{
|
|
|
|
if (!node->properties_computed)
|
|
|
|
{
|
2009-09-20 02:56:09 +00:00
|
|
|
GPtrArray *properties = NULL;
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
node->properties_computed = TRUE;
|
|
|
|
|
|
|
|
if (node->theme)
|
2009-09-20 02:56:09 +00:00
|
|
|
properties = _st_theme_get_matched_properties (node->theme, node);
|
|
|
|
|
|
|
|
if (node->inline_style)
|
|
|
|
{
|
|
|
|
CRDeclaration *cur_decl;
|
|
|
|
|
|
|
|
if (!properties)
|
|
|
|
properties = g_ptr_array_new ();
|
|
|
|
|
2009-10-05 14:10:23 +00:00
|
|
|
node->inline_properties = _st_theme_parse_declaration_list (node->inline_style);
|
2009-09-20 02:56:09 +00:00
|
|
|
for (cur_decl = node->inline_properties; cur_decl; cur_decl = cur_decl->next)
|
|
|
|
g_ptr_array_add (properties, cur_decl);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (properties)
|
|
|
|
{
|
|
|
|
node->n_properties = properties->len;
|
|
|
|
node->properties = (CRDeclaration **)g_ptr_array_free (properties, FALSE);
|
|
|
|
}
|
2009-09-20 00:43:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
VALUE_FOUND,
|
|
|
|
VALUE_NOT_FOUND,
|
|
|
|
VALUE_INHERIT
|
|
|
|
} GetFromTermResult;
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
term_is_inherit (CRTerm *term)
|
|
|
|
{
|
|
|
|
return (term->type == TERM_IDENT &&
|
|
|
|
strcmp (term->content.str->stryng->str, "inherit") == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
term_is_none (CRTerm *term)
|
|
|
|
{
|
|
|
|
return (term->type == TERM_IDENT &&
|
|
|
|
strcmp (term->content.str->stryng->str, "none") == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
term_is_transparent (CRTerm *term)
|
|
|
|
{
|
|
|
|
return (term->type == TERM_IDENT &&
|
|
|
|
strcmp (term->content.str->stryng->str, "transparent") == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
color_component_from_double (double component)
|
|
|
|
{
|
|
|
|
/* We want to spread the range 0-1 equally over 0..255, but
|
|
|
|
* 1.0 should map to 255 not 256, so we need to special-case it.
|
|
|
|
* See http://people.redhat.com/otaylor/pixel-converting.html
|
|
|
|
* for (very) detailed discussion of related issues. */
|
|
|
|
if (component >= 1.0)
|
|
|
|
return 255;
|
|
|
|
else
|
|
|
|
return (int)(component * 256);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GetFromTermResult
|
|
|
|
get_color_from_rgba_term (CRTerm *term,
|
|
|
|
ClutterColor *color)
|
|
|
|
{
|
|
|
|
CRTerm *arg = term->ext_content.func_param;
|
|
|
|
CRNum *num;
|
|
|
|
double r = 0, g = 0, b = 0, a = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
double value;
|
|
|
|
|
|
|
|
if (arg == NULL)
|
|
|
|
return VALUE_NOT_FOUND;
|
|
|
|
|
|
|
|
if ((i == 0 && arg->the_operator != NO_OP) ||
|
|
|
|
(i > 0 && arg->the_operator != COMMA))
|
|
|
|
return VALUE_NOT_FOUND;
|
|
|
|
|
|
|
|
if (arg->type != TERM_NUMBER)
|
|
|
|
return VALUE_NOT_FOUND;
|
|
|
|
|
|
|
|
num = arg->content.num;
|
|
|
|
|
|
|
|
/* For simplicity, we convert a,r,g,b to [0,1.0] floats and then
|
|
|
|
* convert them back below. Then when we set them on a cairo content
|
|
|
|
* we convert them back to floats, and then cairo converts them
|
|
|
|
* back to integers to pass them to X, and so forth...
|
|
|
|
*/
|
|
|
|
if (i < 3)
|
|
|
|
{
|
|
|
|
if (num->type == NUM_PERCENTAGE)
|
|
|
|
value = num->val / 100;
|
|
|
|
else if (num->type == NUM_GENERIC)
|
|
|
|
value = num->val / 255;
|
|
|
|
else
|
|
|
|
return VALUE_NOT_FOUND;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (num->type != NUM_GENERIC)
|
|
|
|
return VALUE_NOT_FOUND;
|
|
|
|
|
|
|
|
value = num->val;
|
|
|
|
}
|
|
|
|
|
|
|
|
value = CLAMP (value, 0, 1);
|
|
|
|
|
|
|
|
switch (i)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
r = value;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
g = value;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
b = value;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
a = value;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
arg = arg->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
color->red = color_component_from_double (r);
|
|
|
|
color->green = color_component_from_double (g);
|
|
|
|
color->blue = color_component_from_double (b);
|
|
|
|
color->alpha = color_component_from_double (a);
|
|
|
|
|
|
|
|
return VALUE_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GetFromTermResult
|
|
|
|
get_color_from_term (StThemeNode *node,
|
|
|
|
CRTerm *term,
|
|
|
|
ClutterColor *color)
|
|
|
|
{
|
|
|
|
CRRgb rgb;
|
|
|
|
enum CRStatus status;
|
|
|
|
|
|
|
|
/* Since libcroco doesn't know about rgba colors, it can't handle
|
|
|
|
* the transparent keyword
|
|
|
|
*/
|
|
|
|
if (term_is_transparent (term))
|
|
|
|
{
|
|
|
|
*color = TRANSPARENT_COLOR;
|
|
|
|
return VALUE_FOUND;
|
|
|
|
}
|
|
|
|
/* rgba () colors - a CSS3 addition, are not supported by libcroco,
|
|
|
|
* but they are parsed as a "function", so we can emulate the
|
|
|
|
* functionality.
|
|
|
|
*/
|
|
|
|
else if (term->type == TERM_FUNCTION &&
|
|
|
|
term->content.str &&
|
|
|
|
term->content.str->stryng &&
|
|
|
|
term->content.str->stryng->str &&
|
2011-04-04 18:02:19 +00:00
|
|
|
strcmp (term->content.str->stryng->str, "rgba") == 0)
|
2009-09-20 00:43:49 +00:00
|
|
|
{
|
|
|
|
return get_color_from_rgba_term (term, color);
|
|
|
|
}
|
|
|
|
|
|
|
|
status = cr_rgb_set_from_term (&rgb, term);
|
|
|
|
if (status != CR_OK)
|
|
|
|
return VALUE_NOT_FOUND;
|
|
|
|
|
|
|
|
if (rgb.inherit)
|
|
|
|
return VALUE_INHERIT;
|
|
|
|
|
|
|
|
if (rgb.is_percentage)
|
|
|
|
cr_rgb_compute_from_percentage (&rgb);
|
|
|
|
|
|
|
|
color->red = rgb.red;
|
|
|
|
color->green = rgb.green;
|
|
|
|
color->blue = rgb.blue;
|
|
|
|
color->alpha = 0xff;
|
|
|
|
|
|
|
|
return VALUE_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
* st_theme_node_lookup_color:
|
2009-09-20 00:43:49 +00:00
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @property_name: The name of the color property
|
|
|
|
* @inherit: if %TRUE, if a value is not found for the property on the
|
|
|
|
* node, then it will be looked up on the parent node, and then on the
|
|
|
|
* parent's parent, and so forth. Note that if the property has a
|
|
|
|
* value of 'inherit' it will be inherited even if %FALSE is passed
|
|
|
|
* in for @inherit; this only affects the default behavior for inheritance.
|
2011-02-14 14:20:22 +00:00
|
|
|
* @color: (out caller-allocates): location to store the color that was
|
|
|
|
* determined. If the property is not found, the value in this location
|
2009-09-20 00:43:49 +00:00
|
|
|
* will not be changed.
|
|
|
|
*
|
|
|
|
* Generically looks up a property containing a single color value. When
|
|
|
|
* specific getters (like st_theme_node_get_background_color()) exist, they
|
|
|
|
* should be used instead. They are cached, so more efficient, and have
|
|
|
|
* handling for shortcut properties and other details of CSS.
|
|
|
|
*
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
* See also st_theme_node_get_color(), which provides a simpler API.
|
|
|
|
*
|
2009-09-20 00:43:49 +00:00
|
|
|
* Return value: %TRUE if the property was found in the properties for this
|
|
|
|
* theme node (or in the properties of parent nodes when inheriting.)
|
|
|
|
*/
|
|
|
|
gboolean
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
st_theme_node_lookup_color (StThemeNode *node,
|
|
|
|
const char *property_name,
|
|
|
|
gboolean inherit,
|
|
|
|
ClutterColor *color)
|
2009-09-20 00:43:49 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ensure_properties (node);
|
|
|
|
|
|
|
|
for (i = node->n_properties - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
CRDeclaration *decl = node->properties[i];
|
|
|
|
|
|
|
|
if (strcmp (decl->property->stryng->str, property_name) == 0)
|
|
|
|
{
|
|
|
|
GetFromTermResult result = get_color_from_term (node, decl->value, color);
|
|
|
|
if (result == VALUE_FOUND)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else if (result == VALUE_INHERIT)
|
|
|
|
{
|
|
|
|
if (node->parent_node)
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
return st_theme_node_lookup_color (node->parent_node, property_name, inherit, color);
|
2009-09-20 00:43:49 +00:00
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-19 17:59:49 +00:00
|
|
|
if (inherit && node->parent_node)
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
return st_theme_node_lookup_color (node->parent_node, property_name, inherit, color);
|
2010-10-19 17:59:49 +00:00
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
* st_theme_node_get_color:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @property_name: The name of the color property
|
2011-02-14 14:20:22 +00:00
|
|
|
* @color: (out caller-allocates): location to store the color that
|
|
|
|
* was determined.
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
*
|
|
|
|
* Generically looks up a property containing a single color value. When
|
|
|
|
* specific getters (like st_theme_node_get_background_color()) exist, they
|
|
|
|
* should be used instead. They are cached, so more efficient, and have
|
|
|
|
* handling for shortcut properties and other details of CSS.
|
|
|
|
*
|
|
|
|
* If @property_name is not found, a warning will be logged and a
|
|
|
|
* default color returned.
|
|
|
|
*
|
|
|
|
* See also st_theme_node_lookup_color(), which provides more options,
|
|
|
|
* and lets you handle the case where the theme does not specify the
|
|
|
|
* indicated color.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
st_theme_node_get_color (StThemeNode *node,
|
|
|
|
const char *property_name,
|
|
|
|
ClutterColor *color)
|
|
|
|
{
|
|
|
|
if (!st_theme_node_lookup_color (node, property_name, FALSE, color))
|
|
|
|
{
|
|
|
|
g_warning ("Did not find color property '%s'", property_name);
|
|
|
|
memset (color, 0, sizeof (ClutterColor));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_theme_node_lookup_double:
|
2009-09-20 00:43:49 +00:00
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @property_name: The name of the numeric property
|
|
|
|
* @inherit: if %TRUE, if a value is not found for the property on the
|
|
|
|
* node, then it will be looked up on the parent node, and then on the
|
|
|
|
* parent's parent, and so forth. Note that if the property has a
|
|
|
|
* value of 'inherit' it will be inherited even if %FALSE is passed
|
|
|
|
* in for @inherit; this only affects the default behavior for inheritance.
|
2009-11-14 23:00:54 +00:00
|
|
|
* @value: (out): location to store the value that was determined.
|
2009-09-20 00:43:49 +00:00
|
|
|
* If the property is not found, the value in this location
|
|
|
|
* will not be changed.
|
|
|
|
*
|
|
|
|
* Generically looks up a property containing a single numeric value
|
|
|
|
* without units.
|
|
|
|
*
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
* See also st_theme_node_get_double(), which provides a simpler API.
|
|
|
|
*
|
2009-09-20 00:43:49 +00:00
|
|
|
* Return value: %TRUE if the property was found in the properties for this
|
|
|
|
* theme node (or in the properties of parent nodes when inheriting.)
|
|
|
|
*/
|
|
|
|
gboolean
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
st_theme_node_lookup_double (StThemeNode *node,
|
|
|
|
const char *property_name,
|
|
|
|
gboolean inherit,
|
|
|
|
double *value)
|
2009-09-20 00:43:49 +00:00
|
|
|
{
|
|
|
|
gboolean result = FALSE;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ensure_properties (node);
|
|
|
|
|
|
|
|
for (i = node->n_properties - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
CRDeclaration *decl = node->properties[i];
|
|
|
|
|
|
|
|
if (strcmp (decl->property->stryng->str, property_name) == 0)
|
|
|
|
{
|
|
|
|
CRTerm *term = decl->value;
|
|
|
|
|
|
|
|
if (term->type != TERM_NUMBER || term->content.num->type != NUM_GENERIC)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
*value = term->content.num->val;
|
|
|
|
result = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!result && inherit && node->parent_node)
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
result = st_theme_node_lookup_double (node->parent_node, property_name, inherit, value);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-08-07 14:20:43 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_lookup_time:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @property_name: The name of the time property
|
|
|
|
* @inherit: if %TRUE, if a value is not found for the property on the
|
|
|
|
* node, then it will be looked up on the parent node, and then on the
|
|
|
|
* parent's parent, and so forth. Note that if the property has a
|
|
|
|
* value of 'inherit' it will be inherited even if %FALSE is passed
|
|
|
|
* in for @inherit; this only affects the default behavior for inheritance.
|
|
|
|
* @value: (out): location to store the value that was determined.
|
|
|
|
* If the property is not found, the value in this location
|
|
|
|
* will not be changed.
|
|
|
|
*
|
|
|
|
* Generically looks up a property containing a single time value,
|
|
|
|
* which is converted to milliseconds.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if the property was found in the properties for this
|
|
|
|
* theme node (or in the properties of parent nodes when inheriting.)
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
st_theme_node_lookup_time (StThemeNode *node,
|
|
|
|
const char *property_name,
|
|
|
|
gboolean inherit,
|
|
|
|
double *value)
|
|
|
|
{
|
|
|
|
gboolean result = FALSE;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ensure_properties (node);
|
|
|
|
|
|
|
|
for (i = node->n_properties - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
CRDeclaration *decl = node->properties[i];
|
|
|
|
|
|
|
|
if (strcmp (decl->property->stryng->str, property_name) == 0)
|
|
|
|
{
|
|
|
|
CRTerm *term = decl->value;
|
|
|
|
|
|
|
|
if (term->type != TERM_NUMBER)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
switch (term->content.num->type)
|
|
|
|
{
|
|
|
|
case NUM_TIME_S:
|
|
|
|
*value = 1000 * term->content.num->val;
|
|
|
|
result = TRUE;
|
|
|
|
break;
|
|
|
|
case NUM_TIME_MS:
|
|
|
|
*value = term->content.num->val;
|
|
|
|
result = TRUE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!result && inherit && node->parent_node)
|
|
|
|
result = st_theme_node_lookup_time (node->parent_node, property_name, inherit, value);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_get_double:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @property_name: The name of the numeric property
|
|
|
|
*
|
|
|
|
* Generically looks up a property containing a single numeric value
|
|
|
|
* without units.
|
|
|
|
*
|
|
|
|
* See also st_theme_node_lookup_double(), which provides more options,
|
|
|
|
* and lets you handle the case where the theme does not specify the
|
|
|
|
* indicated value.
|
|
|
|
*
|
|
|
|
* Return value: the value found. If @property_name is not
|
|
|
|
* found, a warning will be logged and 0 will be returned.
|
|
|
|
*/
|
|
|
|
gdouble
|
|
|
|
st_theme_node_get_double (StThemeNode *node,
|
|
|
|
const char *property_name)
|
|
|
|
{
|
|
|
|
gdouble value;
|
|
|
|
|
|
|
|
if (st_theme_node_lookup_double (node, property_name, FALSE, &value))
|
|
|
|
return value;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("Did not find double property '%s'", property_name);
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-16 12:43:51 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_lookup_url:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @property_name: The name of the string property
|
|
|
|
* @inherit: if %TRUE, if a value is not found for the property on the
|
|
|
|
* node, then it will be looked up on the parent node, and then on the
|
|
|
|
* parent's parent, and so forth. Note that if the property has a
|
|
|
|
* value of 'inherit' it will be inherited even if %FALSE is passed
|
|
|
|
* in for @inherit; this only affects the default behavior for inheritance.
|
2014-09-19 00:04:00 +00:00
|
|
|
* @file: (out) (transfer full): location to store the newly allocated value that was
|
2013-04-16 12:43:51 +00:00
|
|
|
* determined. If the property is not found, the value in this location
|
|
|
|
* will not be changed.
|
|
|
|
*
|
|
|
|
* Looks up a property containing a single URL value.
|
|
|
|
*
|
|
|
|
* See also st_theme_node_get_url(), which provides a simpler API.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if the property was found in the properties for this
|
|
|
|
* theme node (or in the properties of parent nodes when inheriting.)
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
st_theme_node_lookup_url (StThemeNode *node,
|
|
|
|
const char *property_name,
|
|
|
|
gboolean inherit,
|
2014-09-19 00:04:00 +00:00
|
|
|
GFile **file)
|
2013-04-16 12:43:51 +00:00
|
|
|
{
|
|
|
|
gboolean result = FALSE;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ensure_properties (node);
|
|
|
|
|
|
|
|
for (i = node->n_properties - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
CRDeclaration *decl = node->properties[i];
|
|
|
|
|
|
|
|
if (strcmp (decl->property->stryng->str, property_name) == 0)
|
|
|
|
{
|
|
|
|
CRTerm *term = decl->value;
|
|
|
|
CRStyleSheet *base_stylesheet;
|
|
|
|
|
|
|
|
if (term->type != TERM_URI && term->type != TERM_STRING)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (decl->parent_statement != NULL)
|
|
|
|
base_stylesheet = decl->parent_statement->parent_sheet;
|
|
|
|
else
|
|
|
|
base_stylesheet = NULL;
|
|
|
|
|
2014-09-19 00:04:00 +00:00
|
|
|
*file = _st_theme_resolve_url (node->theme,
|
|
|
|
base_stylesheet,
|
|
|
|
decl->value->content.str->stryng->str);
|
2013-04-16 12:43:51 +00:00
|
|
|
result = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!result && inherit && node->parent_node)
|
2014-09-19 00:04:00 +00:00
|
|
|
result = st_theme_node_lookup_url (node->parent_node, property_name, inherit, file);
|
2013-04-16 12:43:51 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2014-09-19 00:04:00 +00:00
|
|
|
/**
|
2013-04-16 12:43:51 +00:00
|
|
|
* st_theme_node_get_url:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @property_name: The name of the string property
|
|
|
|
*
|
|
|
|
* Looks up a property containing a single URL value.
|
|
|
|
*
|
|
|
|
* See also st_theme_node_lookup_url(), which provides more options,
|
|
|
|
* and lets you handle the case where the theme does not specify the
|
|
|
|
* indicated value.
|
|
|
|
*
|
2014-09-19 00:04:00 +00:00
|
|
|
* Returns: (transfer full): the newly allocated value if found.
|
2013-04-16 12:43:51 +00:00
|
|
|
* If @property_name is not found, a warning will be logged and %NULL
|
|
|
|
* will be returned.
|
|
|
|
*/
|
2014-09-19 00:04:00 +00:00
|
|
|
GFile *
|
2013-04-16 12:43:51 +00:00
|
|
|
st_theme_node_get_url (StThemeNode *node,
|
|
|
|
const char *property_name)
|
|
|
|
{
|
2014-09-19 00:04:00 +00:00
|
|
|
GFile *file;
|
2013-04-16 12:43:51 +00:00
|
|
|
|
2014-09-19 00:04:00 +00:00
|
|
|
if (st_theme_node_lookup_url (node, property_name, FALSE, &file))
|
|
|
|
return file;
|
2013-04-16 12:43:51 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("Did not find string property '%s'", property_name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
static const PangoFontDescription *
|
|
|
|
get_parent_font (StThemeNode *node)
|
|
|
|
{
|
|
|
|
if (node->parent_node)
|
|
|
|
return st_theme_node_get_font (node->parent_node);
|
|
|
|
else
|
|
|
|
return st_theme_context_get_font (node->context);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GetFromTermResult
|
|
|
|
get_length_from_term (StThemeNode *node,
|
|
|
|
CRTerm *term,
|
|
|
|
gboolean use_parent_font,
|
|
|
|
gdouble *length)
|
|
|
|
{
|
|
|
|
CRNum *num;
|
|
|
|
|
|
|
|
enum {
|
|
|
|
ABSOLUTE,
|
|
|
|
POINTS,
|
|
|
|
FONT_RELATIVE,
|
|
|
|
} type = ABSOLUTE;
|
|
|
|
|
|
|
|
double multiplier = 1.0;
|
2014-02-12 16:29:08 +00:00
|
|
|
int scale_factor;
|
|
|
|
|
|
|
|
g_object_get (node->context, "scale-factor", &scale_factor, NULL);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
if (term->type != TERM_NUMBER)
|
|
|
|
{
|
|
|
|
g_warning ("Ignoring length property that isn't a number");
|
2010-11-14 18:33:48 +00:00
|
|
|
return VALUE_NOT_FOUND;
|
2009-09-20 00:43:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
num = term->content.num;
|
|
|
|
|
|
|
|
switch (num->type)
|
|
|
|
{
|
|
|
|
case NUM_LENGTH_PX:
|
|
|
|
type = ABSOLUTE;
|
2014-02-12 16:29:08 +00:00
|
|
|
multiplier = 1 * scale_factor;
|
2009-09-20 00:43:49 +00:00
|
|
|
break;
|
|
|
|
case NUM_LENGTH_PT:
|
|
|
|
type = POINTS;
|
|
|
|
multiplier = 1;
|
|
|
|
break;
|
|
|
|
case NUM_LENGTH_IN:
|
|
|
|
type = POINTS;
|
|
|
|
multiplier = 72;
|
|
|
|
break;
|
|
|
|
case NUM_LENGTH_CM:
|
|
|
|
type = POINTS;
|
|
|
|
multiplier = 72. / 2.54;
|
|
|
|
break;
|
|
|
|
case NUM_LENGTH_MM:
|
|
|
|
type = POINTS;
|
|
|
|
multiplier = 72. / 25.4;
|
|
|
|
break;
|
|
|
|
case NUM_LENGTH_PC:
|
|
|
|
type = POINTS;
|
|
|
|
multiplier = 12. / 25.4;
|
|
|
|
break;
|
|
|
|
case NUM_LENGTH_EM:
|
|
|
|
{
|
|
|
|
type = FONT_RELATIVE;
|
|
|
|
multiplier = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NUM_LENGTH_EX:
|
|
|
|
{
|
|
|
|
/* Doing better would require actually resolving the font description
|
|
|
|
* to a specific font, and Pango doesn't have an ex metric anyways,
|
|
|
|
* so we'd have to try and synthesize it by complicated means.
|
|
|
|
*
|
|
|
|
* The 0.5em is the CSS spec suggested thing to use when nothing
|
|
|
|
* better is available.
|
|
|
|
*/
|
|
|
|
type = FONT_RELATIVE;
|
|
|
|
multiplier = 0.5;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NUM_INHERIT:
|
|
|
|
return VALUE_INHERIT;
|
|
|
|
|
|
|
|
case NUM_AUTO:
|
|
|
|
g_warning ("'auto' not supported for lengths");
|
|
|
|
return VALUE_NOT_FOUND;
|
|
|
|
|
|
|
|
case NUM_GENERIC:
|
2010-09-01 16:13:43 +00:00
|
|
|
{
|
|
|
|
if (num->val != 0)
|
|
|
|
{
|
|
|
|
g_warning ("length values must specify a unit");
|
|
|
|
return VALUE_NOT_FOUND;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
type = ABSOLUTE;
|
|
|
|
multiplier = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
case NUM_PERCENTAGE:
|
|
|
|
g_warning ("percentage lengths not currently supported");
|
|
|
|
return VALUE_NOT_FOUND;
|
|
|
|
|
|
|
|
case NUM_ANGLE_DEG:
|
|
|
|
case NUM_ANGLE_RAD:
|
|
|
|
case NUM_ANGLE_GRAD:
|
|
|
|
case NUM_TIME_MS:
|
|
|
|
case NUM_TIME_S:
|
|
|
|
case NUM_FREQ_HZ:
|
|
|
|
case NUM_FREQ_KHZ:
|
|
|
|
case NUM_UNKNOWN_TYPE:
|
|
|
|
case NB_NUM_TYPE:
|
|
|
|
g_warning ("Ignoring invalid type of number of length property");
|
|
|
|
return VALUE_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case ABSOLUTE:
|
|
|
|
*length = num->val * multiplier;
|
|
|
|
break;
|
|
|
|
case POINTS:
|
|
|
|
{
|
2012-03-26 14:14:31 +00:00
|
|
|
double resolution = clutter_backend_get_resolution (clutter_get_default_backend ());
|
2009-09-20 00:43:49 +00:00
|
|
|
*length = num->val * multiplier * (resolution / 72.);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FONT_RELATIVE:
|
|
|
|
{
|
|
|
|
const PangoFontDescription *desc;
|
|
|
|
double font_size;
|
|
|
|
|
|
|
|
if (use_parent_font)
|
|
|
|
desc = get_parent_font (node);
|
|
|
|
else
|
|
|
|
desc = st_theme_node_get_font (node);
|
|
|
|
|
|
|
|
font_size = (double)pango_font_description_get_size (desc) / PANGO_SCALE;
|
|
|
|
|
|
|
|
if (pango_font_description_get_size_is_absolute (desc))
|
|
|
|
{
|
|
|
|
*length = num->val * multiplier * font_size;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-03-26 14:14:31 +00:00
|
|
|
double resolution = clutter_backend_get_resolution (clutter_get_default_backend ());
|
2009-09-20 00:43:49 +00:00
|
|
|
*length = num->val * multiplier * (resolution / 72.) * font_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
}
|
|
|
|
|
|
|
|
return VALUE_FOUND;
|
|
|
|
}
|
|
|
|
|
2010-02-11 02:10:49 +00:00
|
|
|
static GetFromTermResult
|
|
|
|
get_length_from_term_int (StThemeNode *node,
|
|
|
|
CRTerm *term,
|
|
|
|
gboolean use_parent_font,
|
|
|
|
gint *length)
|
|
|
|
{
|
|
|
|
double value;
|
|
|
|
GetFromTermResult result;
|
|
|
|
|
|
|
|
result = get_length_from_term (node, term, use_parent_font, &value);
|
2010-11-14 18:33:48 +00:00
|
|
|
if (result == VALUE_FOUND)
|
2010-02-11 02:10:49 +00:00
|
|
|
*length = (int) (0.5 + value);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
static GetFromTermResult
|
|
|
|
get_length_internal (StThemeNode *node,
|
|
|
|
const char *property_name,
|
|
|
|
const char *suffixed,
|
|
|
|
gdouble *length)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ensure_properties (node);
|
|
|
|
|
|
|
|
for (i = node->n_properties - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
CRDeclaration *decl = node->properties[i];
|
|
|
|
|
|
|
|
if (strcmp (decl->property->stryng->str, property_name) == 0 ||
|
|
|
|
(suffixed != NULL && strcmp (decl->property->stryng->str, suffixed) == 0))
|
|
|
|
{
|
|
|
|
GetFromTermResult result = get_length_from_term (node, decl->value, FALSE, length);
|
|
|
|
if (result != VALUE_NOT_FOUND)
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return VALUE_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
* st_theme_node_lookup_length:
|
2009-09-20 00:43:49 +00:00
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @property_name: The name of the length property
|
|
|
|
* @inherit: if %TRUE, if a value is not found for the property on the
|
|
|
|
* node, then it will be looked up on the parent node, and then on the
|
|
|
|
* parent's parent, and so forth. Note that if the property has a
|
|
|
|
* value of 'inherit' it will be inherited even if %FALSE is passed
|
|
|
|
* in for @inherit; this only affects the default behavior for inheritance.
|
2009-11-14 23:00:54 +00:00
|
|
|
* @length: (out): location to store the length that was determined.
|
2009-09-20 00:43:49 +00:00
|
|
|
* If the property is not found, the value in this location
|
|
|
|
* will not be changed. The returned length is resolved
|
|
|
|
* to pixels.
|
|
|
|
*
|
|
|
|
* Generically looks up a property containing a single length value. When
|
|
|
|
* specific getters (like st_theme_node_get_border_width()) exist, they
|
|
|
|
* should be used instead. They are cached, so more efficient, and have
|
|
|
|
* handling for shortcut properties and other details of CSS.
|
|
|
|
*
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
* See also st_theme_node_get_length(), which provides a simpler API.
|
|
|
|
*
|
2009-09-20 00:43:49 +00:00
|
|
|
* Return value: %TRUE if the property was found in the properties for this
|
|
|
|
* theme node (or in the properties of parent nodes when inheriting.)
|
|
|
|
*/
|
|
|
|
gboolean
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
st_theme_node_lookup_length (StThemeNode *node,
|
|
|
|
const char *property_name,
|
|
|
|
gboolean inherit,
|
|
|
|
gdouble *length)
|
2009-09-20 00:43:49 +00:00
|
|
|
{
|
|
|
|
GetFromTermResult result = get_length_internal (node, property_name, NULL, length);
|
|
|
|
if (result == VALUE_FOUND)
|
|
|
|
return TRUE;
|
|
|
|
else if (result == VALUE_INHERIT)
|
|
|
|
inherit = TRUE;
|
|
|
|
|
|
|
|
if (inherit && node->parent_node &&
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
st_theme_node_lookup_length (node->parent_node, property_name, inherit, length))
|
2009-09-20 00:43:49 +00:00
|
|
|
return TRUE;
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_get_length:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @property_name: The name of the length property
|
|
|
|
*
|
|
|
|
* Generically looks up a property containing a single length value. When
|
|
|
|
* specific getters (like st_theme_node_get_border_width()) exist, they
|
|
|
|
* should be used instead. They are cached, so more efficient, and have
|
|
|
|
* handling for shortcut properties and other details of CSS.
|
|
|
|
*
|
|
|
|
* Unlike st_theme_node_get_color() and st_theme_node_get_double(),
|
|
|
|
* this does not print a warning if the property is not found; it just
|
|
|
|
* returns 0.
|
|
|
|
*
|
|
|
|
* See also st_theme_node_lookup_length(), which provides more options.
|
|
|
|
*
|
|
|
|
* Return value: the length, in pixels, or 0 if the property was not found.
|
|
|
|
*/
|
|
|
|
gdouble
|
|
|
|
st_theme_node_get_length (StThemeNode *node,
|
|
|
|
const char *property_name)
|
|
|
|
{
|
|
|
|
gdouble length;
|
|
|
|
|
|
|
|
if (st_theme_node_lookup_length (node, property_name, FALSE, &length))
|
|
|
|
return length;
|
|
|
|
else
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
2009-09-20 13:08:08 +00:00
|
|
|
static void
|
|
|
|
do_border_radius_term (StThemeNode *node,
|
|
|
|
CRTerm *term,
|
|
|
|
gboolean topleft,
|
|
|
|
gboolean topright,
|
|
|
|
gboolean bottomright,
|
|
|
|
gboolean bottomleft)
|
|
|
|
{
|
2010-02-11 02:10:49 +00:00
|
|
|
int value;
|
2009-09-20 13:08:08 +00:00
|
|
|
|
2010-02-11 02:10:49 +00:00
|
|
|
if (get_length_from_term_int (node, term, FALSE, &value) != VALUE_FOUND)
|
2009-09-20 13:08:08 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (topleft)
|
|
|
|
node->border_radius[ST_CORNER_TOPLEFT] = value;
|
|
|
|
if (topright)
|
|
|
|
node->border_radius[ST_CORNER_TOPRIGHT] = value;
|
|
|
|
if (bottomright)
|
|
|
|
node->border_radius[ST_CORNER_BOTTOMRIGHT] = value;
|
|
|
|
if (bottomleft)
|
|
|
|
node->border_radius[ST_CORNER_BOTTOMLEFT] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
do_border_radius (StThemeNode *node,
|
|
|
|
CRDeclaration *decl)
|
|
|
|
{
|
|
|
|
const char *property_name = decl->property->stryng->str + 13; /* Skip 'border-radius' */
|
|
|
|
|
|
|
|
if (strcmp (property_name, "") == 0)
|
|
|
|
{
|
|
|
|
/* Slight deviation ... if we don't understand some of the terms and understand others,
|
|
|
|
* then we set the ones we understand and ignore the others instead of ignoring the
|
|
|
|
* whole thing
|
|
|
|
*/
|
|
|
|
if (decl->value == NULL) /* 0 values */
|
|
|
|
return;
|
|
|
|
else if (decl->value->next == NULL) /* 1 value */
|
|
|
|
{
|
|
|
|
do_border_radius_term (node, decl->value, TRUE, TRUE, TRUE, TRUE); /* all corners */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (decl->value->next->next == NULL) /* 2 values */
|
|
|
|
{
|
|
|
|
do_border_radius_term (node, decl->value, TRUE, FALSE, TRUE, FALSE); /* topleft/bottomright */
|
|
|
|
do_border_radius_term (node, decl->value->next, FALSE, TRUE, FALSE, TRUE); /* topright/bottomleft */
|
|
|
|
}
|
|
|
|
else if (decl->value->next->next->next == NULL) /* 3 values */
|
|
|
|
{
|
|
|
|
do_border_radius_term (node, decl->value, TRUE, FALSE, FALSE, FALSE); /* topleft */
|
|
|
|
do_border_radius_term (node, decl->value->next, FALSE, TRUE, FALSE, TRUE); /* topright/bottomleft */
|
|
|
|
do_border_radius_term (node, decl->value->next->next, FALSE, FALSE, TRUE, FALSE); /* bottomright */
|
|
|
|
}
|
|
|
|
else if (decl->value->next->next->next->next == NULL) /* 4 values */
|
|
|
|
{
|
|
|
|
do_border_radius_term (node, decl->value, TRUE, FALSE, FALSE, FALSE); /* topleft */
|
|
|
|
do_border_radius_term (node, decl->value->next, FALSE, TRUE, FALSE, FALSE); /* topright */
|
|
|
|
do_border_radius_term (node, decl->value->next->next, FALSE, FALSE, TRUE, FALSE); /* bottomright */
|
|
|
|
do_border_radius_term (node, decl->value->next->next->next, FALSE, FALSE, FALSE, TRUE); /* bottomleft */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("Too many values for border-radius property");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (decl->value == NULL || decl->value->next != NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (strcmp (property_name, "-topleft") == 0)
|
|
|
|
do_border_radius_term (node, decl->value, TRUE, FALSE, FALSE, FALSE);
|
|
|
|
else if (strcmp (property_name, "-topright") == 0)
|
|
|
|
do_border_radius_term (node, decl->value, FALSE, TRUE, FALSE, FALSE);
|
|
|
|
else if (strcmp (property_name, "-bottomright") == 0)
|
|
|
|
do_border_radius_term (node, decl->value, FALSE, FALSE, TRUE, FALSE);
|
|
|
|
else if (strcmp (property_name, "-bottomleft") == 0)
|
|
|
|
do_border_radius_term (node, decl->value, FALSE, FALSE, FALSE, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
static void
|
|
|
|
do_border_property (StThemeNode *node,
|
|
|
|
CRDeclaration *decl)
|
|
|
|
{
|
|
|
|
const char *property_name = decl->property->stryng->str + 6; /* Skip 'border' */
|
|
|
|
StSide side = (StSide)-1;
|
|
|
|
ClutterColor color;
|
|
|
|
gboolean color_set = FALSE;
|
2010-11-14 18:33:48 +00:00
|
|
|
int width = 0; /* suppress warning */
|
2009-09-20 00:43:49 +00:00
|
|
|
gboolean width_set = FALSE;
|
|
|
|
int j;
|
|
|
|
|
2009-09-20 13:08:08 +00:00
|
|
|
if (g_str_has_prefix (property_name, "-radius"))
|
|
|
|
{
|
|
|
|
do_border_radius (node, decl);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
if (g_str_has_prefix (property_name, "-left"))
|
|
|
|
{
|
|
|
|
side = ST_SIDE_LEFT;
|
|
|
|
property_name += 5;
|
|
|
|
}
|
|
|
|
else if (g_str_has_prefix (property_name, "-right"))
|
|
|
|
{
|
|
|
|
side = ST_SIDE_RIGHT;
|
|
|
|
property_name += 6;
|
|
|
|
}
|
|
|
|
else if (g_str_has_prefix (property_name, "-top"))
|
|
|
|
{
|
|
|
|
side = ST_SIDE_TOP;
|
|
|
|
property_name += 4;
|
|
|
|
}
|
|
|
|
else if (g_str_has_prefix (property_name, "-bottom"))
|
|
|
|
{
|
|
|
|
side = ST_SIDE_BOTTOM;
|
|
|
|
property_name += 7;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp (property_name, "") == 0)
|
|
|
|
{
|
2010-05-26 20:50:24 +00:00
|
|
|
/* Set value for width/color/style in any order */
|
2009-09-20 00:43:49 +00:00
|
|
|
CRTerm *term;
|
|
|
|
|
|
|
|
for (term = decl->value; term; term = term->next)
|
|
|
|
{
|
|
|
|
GetFromTermResult result;
|
|
|
|
|
|
|
|
if (term->type == TERM_IDENT)
|
|
|
|
{
|
|
|
|
const char *ident = term->content.str->stryng->str;
|
|
|
|
if (strcmp (ident, "none") == 0 || strcmp (ident, "hidden") == 0)
|
|
|
|
{
|
2010-11-14 18:33:48 +00:00
|
|
|
width = 0;
|
|
|
|
width_set = TRUE;
|
2009-09-20 00:43:49 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (strcmp (ident, "solid") == 0)
|
|
|
|
{
|
|
|
|
/* The only thing we support */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (strcmp (ident, "dotted") == 0 ||
|
|
|
|
strcmp (ident, "dashed") == 0 ||
|
|
|
|
strcmp (ident, "double") == 0 ||
|
|
|
|
strcmp (ident, "groove") == 0 ||
|
|
|
|
strcmp (ident, "ridge") == 0 ||
|
|
|
|
strcmp (ident, "inset") == 0 ||
|
|
|
|
strcmp (ident, "outset") == 0)
|
|
|
|
{
|
|
|
|
/* Treat the same as solid */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Presumably a color, fall through */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (term->type == TERM_NUMBER)
|
|
|
|
{
|
2010-02-11 02:10:49 +00:00
|
|
|
result = get_length_from_term_int (node, term, FALSE, &width);
|
2009-09-20 00:43:49 +00:00
|
|
|
if (result != VALUE_NOT_FOUND)
|
|
|
|
{
|
|
|
|
width_set = result == VALUE_FOUND;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = get_color_from_term (node, term, &color);
|
|
|
|
if (result != VALUE_NOT_FOUND)
|
|
|
|
{
|
|
|
|
color_set = result == VALUE_FOUND;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (strcmp (property_name, "-color") == 0)
|
|
|
|
{
|
|
|
|
if (decl->value == NULL || decl->value->next != NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (get_color_from_term (node, decl->value, &color) == VALUE_FOUND)
|
|
|
|
/* Ignore inherit */
|
|
|
|
color_set = TRUE;
|
|
|
|
}
|
|
|
|
else if (strcmp (property_name, "-width") == 0)
|
|
|
|
{
|
|
|
|
if (decl->value == NULL || decl->value->next != NULL)
|
|
|
|
return;
|
|
|
|
|
2010-02-11 02:10:49 +00:00
|
|
|
if (get_length_from_term_int (node, decl->value, FALSE, &width) == VALUE_FOUND)
|
2009-09-20 00:43:49 +00:00
|
|
|
/* Ignore inherit */
|
|
|
|
width_set = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (side == (StSide)-1)
|
|
|
|
{
|
|
|
|
for (j = 0; j < 4; j++)
|
|
|
|
{
|
|
|
|
if (color_set)
|
|
|
|
node->border_color[j] = color;
|
|
|
|
if (width_set)
|
|
|
|
node->border_width[j] = width;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (color_set)
|
|
|
|
node->border_color[side] = color;
|
|
|
|
if (width_set)
|
|
|
|
node->border_width[side] = width;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-26 20:50:24 +00:00
|
|
|
static void
|
|
|
|
do_outline_property (StThemeNode *node,
|
|
|
|
CRDeclaration *decl)
|
|
|
|
{
|
|
|
|
const char *property_name = decl->property->stryng->str + 7; /* Skip 'outline' */
|
|
|
|
ClutterColor color;
|
|
|
|
gboolean color_set = FALSE;
|
2010-11-14 18:33:48 +00:00
|
|
|
int width = 0; /* suppress warning */
|
2010-05-26 20:50:24 +00:00
|
|
|
gboolean width_set = FALSE;
|
|
|
|
|
|
|
|
if (strcmp (property_name, "") == 0)
|
|
|
|
{
|
|
|
|
/* Set value for width/color/style in any order */
|
|
|
|
CRTerm *term;
|
|
|
|
|
|
|
|
for (term = decl->value; term; term = term->next)
|
|
|
|
{
|
|
|
|
GetFromTermResult result;
|
|
|
|
|
|
|
|
if (term->type == TERM_IDENT)
|
|
|
|
{
|
|
|
|
const char *ident = term->content.str->stryng->str;
|
|
|
|
if (strcmp (ident, "none") == 0 || strcmp (ident, "hidden") == 0)
|
|
|
|
{
|
2010-11-14 18:33:48 +00:00
|
|
|
width = 0;
|
|
|
|
width_set = TRUE;
|
2010-05-26 20:50:24 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (strcmp (ident, "solid") == 0)
|
|
|
|
{
|
|
|
|
/* The only thing we support */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (strcmp (ident, "dotted") == 0 ||
|
|
|
|
strcmp (ident, "dashed") == 0 ||
|
|
|
|
strcmp (ident, "double") == 0 ||
|
|
|
|
strcmp (ident, "groove") == 0 ||
|
|
|
|
strcmp (ident, "ridge") == 0 ||
|
|
|
|
strcmp (ident, "inset") == 0 ||
|
|
|
|
strcmp (ident, "outset") == 0)
|
|
|
|
{
|
|
|
|
/* Treat the same as solid */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Presumably a color, fall through */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (term->type == TERM_NUMBER)
|
|
|
|
{
|
|
|
|
result = get_length_from_term_int (node, term, FALSE, &width);
|
|
|
|
if (result != VALUE_NOT_FOUND)
|
|
|
|
{
|
|
|
|
width_set = result == VALUE_FOUND;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = get_color_from_term (node, term, &color);
|
|
|
|
if (result != VALUE_NOT_FOUND)
|
|
|
|
{
|
|
|
|
color_set = result == VALUE_FOUND;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (strcmp (property_name, "-color") == 0)
|
|
|
|
{
|
|
|
|
if (decl->value == NULL || decl->value->next != NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (get_color_from_term (node, decl->value, &color) == VALUE_FOUND)
|
|
|
|
/* Ignore inherit */
|
|
|
|
color_set = TRUE;
|
|
|
|
}
|
|
|
|
else if (strcmp (property_name, "-width") == 0)
|
|
|
|
{
|
|
|
|
if (decl->value == NULL || decl->value->next != NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (get_length_from_term_int (node, decl->value, FALSE, &width) == VALUE_FOUND)
|
|
|
|
/* Ignore inherit */
|
|
|
|
width_set = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (color_set)
|
|
|
|
node->outline_color = color;
|
|
|
|
if (width_set)
|
|
|
|
node->outline_width = width;
|
|
|
|
}
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
static void
|
|
|
|
do_padding_property_term (StThemeNode *node,
|
|
|
|
CRTerm *term,
|
|
|
|
gboolean left,
|
|
|
|
gboolean right,
|
|
|
|
gboolean top,
|
|
|
|
gboolean bottom)
|
|
|
|
{
|
2010-02-11 02:10:49 +00:00
|
|
|
int value;
|
2009-09-20 00:43:49 +00:00
|
|
|
|
2010-02-11 02:10:49 +00:00
|
|
|
if (get_length_from_term_int (node, term, FALSE, &value) != VALUE_FOUND)
|
2009-09-20 00:43:49 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (left)
|
2010-02-11 02:10:49 +00:00
|
|
|
node->padding[ST_SIDE_LEFT] = value;
|
2009-09-20 00:43:49 +00:00
|
|
|
if (right)
|
2010-02-11 02:10:49 +00:00
|
|
|
node->padding[ST_SIDE_RIGHT] = value;
|
2009-09-20 00:43:49 +00:00
|
|
|
if (top)
|
2010-02-11 02:10:49 +00:00
|
|
|
node->padding[ST_SIDE_TOP] = value;
|
2009-09-20 00:43:49 +00:00
|
|
|
if (bottom)
|
2010-02-11 02:10:49 +00:00
|
|
|
node->padding[ST_SIDE_BOTTOM] = value;
|
2009-09-20 00:43:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
do_padding_property (StThemeNode *node,
|
|
|
|
CRDeclaration *decl)
|
|
|
|
{
|
|
|
|
const char *property_name = decl->property->stryng->str + 7; /* Skip 'padding' */
|
|
|
|
|
|
|
|
if (strcmp (property_name, "") == 0)
|
|
|
|
{
|
|
|
|
/* Slight deviation ... if we don't understand some of the terms and understand others,
|
|
|
|
* then we set the ones we understand and ignore the others instead of ignoring the
|
|
|
|
* whole thing
|
|
|
|
*/
|
|
|
|
if (decl->value == NULL) /* 0 values */
|
|
|
|
return;
|
2009-09-20 03:28:39 +00:00
|
|
|
else if (decl->value->next == NULL) /* 1 value */
|
|
|
|
{
|
2009-09-20 00:43:49 +00:00
|
|
|
do_padding_property_term (node, decl->value, TRUE, TRUE, TRUE, TRUE); /* left/right/top/bottom */
|
|
|
|
return;
|
|
|
|
}
|
2009-09-20 03:28:39 +00:00
|
|
|
else if (decl->value->next->next == NULL) /* 2 values */
|
|
|
|
{
|
2009-09-20 00:43:49 +00:00
|
|
|
do_padding_property_term (node, decl->value, FALSE, FALSE, TRUE, TRUE); /* top/bottom */
|
|
|
|
do_padding_property_term (node, decl->value->next, TRUE, TRUE, FALSE, FALSE); /* left/right */
|
|
|
|
}
|
2009-09-20 03:28:39 +00:00
|
|
|
else if (decl->value->next->next->next == NULL) /* 3 values */
|
|
|
|
{
|
2009-09-20 00:43:49 +00:00
|
|
|
do_padding_property_term (node, decl->value, FALSE, FALSE, TRUE, FALSE); /* top */
|
|
|
|
do_padding_property_term (node, decl->value->next, TRUE, TRUE, FALSE, FALSE); /* left/right */
|
|
|
|
do_padding_property_term (node, decl->value->next->next, FALSE, FALSE, FALSE, TRUE); /* bottom */
|
|
|
|
}
|
2009-09-20 03:28:39 +00:00
|
|
|
else if (decl->value->next->next->next->next == NULL) /* 4 values */
|
|
|
|
{
|
|
|
|
do_padding_property_term (node, decl->value, FALSE, FALSE, TRUE, FALSE); /* top */
|
|
|
|
do_padding_property_term (node, decl->value->next, FALSE, TRUE, FALSE, FALSE); /* right */
|
|
|
|
do_padding_property_term (node, decl->value->next->next, FALSE, FALSE, FALSE, TRUE); /* bottom */
|
|
|
|
do_padding_property_term (node, decl->value->next->next->next, TRUE, FALSE, FALSE, FALSE); /* left */
|
2009-09-20 00:43:49 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("Too many values for padding property");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (decl->value == NULL || decl->value->next != NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (strcmp (property_name, "-left") == 0)
|
|
|
|
do_padding_property_term (node, decl->value, TRUE, FALSE, FALSE, FALSE);
|
|
|
|
else if (strcmp (property_name, "-right") == 0)
|
|
|
|
do_padding_property_term (node, decl->value, FALSE, TRUE, FALSE, FALSE);
|
|
|
|
else if (strcmp (property_name, "-top") == 0)
|
|
|
|
do_padding_property_term (node, decl->value, FALSE, FALSE, TRUE, FALSE);
|
|
|
|
else if (strcmp (property_name, "-bottom") == 0)
|
|
|
|
do_padding_property_term (node, decl->value, FALSE, FALSE, FALSE, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-11 14:04:46 +00:00
|
|
|
static void
|
|
|
|
do_margin_property_term (StThemeNode *node,
|
|
|
|
CRTerm *term,
|
|
|
|
gboolean left,
|
|
|
|
gboolean right,
|
|
|
|
gboolean top,
|
|
|
|
gboolean bottom)
|
|
|
|
{
|
|
|
|
int value;
|
|
|
|
|
|
|
|
if (get_length_from_term_int (node, term, FALSE, &value) != VALUE_FOUND)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (left)
|
|
|
|
{
|
|
|
|
node->margin[ST_SIDE_LEFT] = value;
|
|
|
|
node->margin_set |= 1 << ST_SIDE_LEFT;
|
|
|
|
}
|
|
|
|
if (right)
|
|
|
|
{
|
|
|
|
node->margin[ST_SIDE_RIGHT] = value;
|
|
|
|
node->margin_set |= 1 << ST_SIDE_RIGHT;
|
|
|
|
}
|
|
|
|
if (top)
|
|
|
|
{
|
|
|
|
node->margin[ST_SIDE_TOP] = value;
|
|
|
|
node->margin_set |= 1 << ST_SIDE_TOP;
|
|
|
|
}
|
|
|
|
if (bottom)
|
|
|
|
{
|
|
|
|
node->margin[ST_SIDE_BOTTOM] = value;
|
|
|
|
node->margin_set |= 1 << ST_SIDE_BOTTOM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
do_margin_property (StThemeNode *node,
|
|
|
|
CRDeclaration *decl)
|
|
|
|
{
|
|
|
|
const char *property_name = decl->property->stryng->str + 6; /* Skip 'margin' */
|
|
|
|
|
|
|
|
if (strcmp (property_name, "") == 0)
|
|
|
|
{
|
|
|
|
/* Slight deviation ... if we don't understand some of the terms and understand others,
|
|
|
|
* then we set the ones we understand and ignore the others instead of ignoring the
|
|
|
|
* whole thing
|
|
|
|
*/
|
|
|
|
if (decl->value == NULL) /* 0 values */
|
|
|
|
return;
|
|
|
|
else if (decl->value->next == NULL) /* 1 value */
|
|
|
|
{
|
|
|
|
do_margin_property_term (node, decl->value, TRUE, TRUE, TRUE, TRUE); /* left/right/top/bottom */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (decl->value->next->next == NULL) /* 2 values */
|
|
|
|
{
|
|
|
|
do_margin_property_term (node, decl->value, FALSE, FALSE, TRUE, TRUE); /* top/bottom */
|
|
|
|
do_margin_property_term (node, decl->value->next, TRUE, TRUE, FALSE, FALSE); /* left/right */
|
|
|
|
}
|
|
|
|
else if (decl->value->next->next->next == NULL) /* 3 values */
|
|
|
|
{
|
|
|
|
do_margin_property_term (node, decl->value, FALSE, FALSE, TRUE, FALSE); /* top */
|
|
|
|
do_margin_property_term (node, decl->value->next, TRUE, TRUE, FALSE, FALSE); /* left/right */
|
|
|
|
do_margin_property_term (node, decl->value->next->next, FALSE, FALSE, FALSE, TRUE); /* bottom */
|
|
|
|
}
|
|
|
|
else if (decl->value->next->next->next->next == NULL) /* 4 values */
|
|
|
|
{
|
|
|
|
do_margin_property_term (node, decl->value, FALSE, FALSE, TRUE, FALSE); /* top */
|
|
|
|
do_margin_property_term (node, decl->value->next, FALSE, TRUE, FALSE, FALSE); /* right */
|
|
|
|
do_margin_property_term (node, decl->value->next->next, FALSE, FALSE, FALSE, TRUE); /* bottom */
|
|
|
|
do_margin_property_term (node, decl->value->next->next->next, TRUE, FALSE, FALSE, FALSE); /* left */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("Too many values for margin property");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (decl->value == NULL || decl->value->next != NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (strcmp (property_name, "-left") == 0)
|
|
|
|
do_margin_property_term (node, decl->value, TRUE, FALSE, FALSE, FALSE);
|
|
|
|
else if (strcmp (property_name, "-right") == 0)
|
|
|
|
do_margin_property_term (node, decl->value, FALSE, TRUE, FALSE, FALSE);
|
|
|
|
else if (strcmp (property_name, "-top") == 0)
|
|
|
|
do_margin_property_term (node, decl->value, FALSE, FALSE, TRUE, FALSE);
|
|
|
|
else if (strcmp (property_name, "-bottom") == 0)
|
|
|
|
do_margin_property_term (node, decl->value, FALSE, FALSE, FALSE, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
static void
|
2009-10-17 00:05:30 +00:00
|
|
|
do_size_property (StThemeNode *node,
|
|
|
|
CRDeclaration *decl,
|
2010-02-11 02:10:49 +00:00
|
|
|
int *node_value)
|
2009-10-17 00:05:30 +00:00
|
|
|
{
|
2010-02-11 02:10:49 +00:00
|
|
|
get_length_from_term_int (node, decl->value, FALSE, node_value);
|
2009-10-17 00:05:30 +00:00
|
|
|
}
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
void
|
|
|
|
_st_theme_node_ensure_geometry (StThemeNode *node)
|
2009-09-20 00:43:49 +00:00
|
|
|
{
|
|
|
|
int i, j;
|
2012-11-30 16:03:45 +00:00
|
|
|
int width, height;
|
2009-09-20 00:43:49 +00:00
|
|
|
|
2009-10-17 00:05:30 +00:00
|
|
|
if (node->geometry_computed)
|
2009-09-20 00:43:49 +00:00
|
|
|
return;
|
|
|
|
|
2009-10-17 00:05:30 +00:00
|
|
|
node->geometry_computed = TRUE;
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
ensure_properties (node);
|
|
|
|
|
|
|
|
for (j = 0; j < 4; j++)
|
|
|
|
{
|
|
|
|
node->border_width[j] = 0;
|
|
|
|
node->border_color[j] = TRANSPARENT_COLOR;
|
|
|
|
}
|
|
|
|
|
2010-05-26 20:50:24 +00:00
|
|
|
node->outline_width = 0;
|
|
|
|
node->outline_color = TRANSPARENT_COLOR;
|
|
|
|
|
2012-11-30 16:03:45 +00:00
|
|
|
width = -1;
|
|
|
|
height = -1;
|
2009-10-17 00:05:30 +00:00
|
|
|
node->width = -1;
|
|
|
|
node->height = -1;
|
|
|
|
node->min_width = -1;
|
|
|
|
node->min_height = -1;
|
2010-02-12 18:58:24 +00:00
|
|
|
node->max_width = -1;
|
|
|
|
node->max_height = -1;
|
2009-10-17 00:05:30 +00:00
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
for (i = 0; i < node->n_properties; i++)
|
|
|
|
{
|
|
|
|
CRDeclaration *decl = node->properties[i];
|
|
|
|
const char *property_name = decl->property->stryng->str;
|
|
|
|
|
|
|
|
if (g_str_has_prefix (property_name, "border"))
|
|
|
|
do_border_property (node, decl);
|
2010-05-26 20:50:24 +00:00
|
|
|
else if (g_str_has_prefix (property_name, "outline"))
|
|
|
|
do_outline_property (node, decl);
|
2009-09-20 00:43:49 +00:00
|
|
|
else if (g_str_has_prefix (property_name, "padding"))
|
|
|
|
do_padding_property (node, decl);
|
2014-11-11 14:04:46 +00:00
|
|
|
else if (g_str_has_prefix (property_name, "margin"))
|
|
|
|
do_margin_property (node, decl);
|
2009-10-17 00:05:30 +00:00
|
|
|
else if (strcmp (property_name, "width") == 0)
|
2012-11-30 16:03:45 +00:00
|
|
|
do_size_property (node, decl, &width);
|
2009-10-17 00:05:30 +00:00
|
|
|
else if (strcmp (property_name, "height") == 0)
|
2012-11-30 16:03:45 +00:00
|
|
|
do_size_property (node, decl, &height);
|
|
|
|
else if (strcmp (property_name, "-st-natural-width") == 0)
|
|
|
|
do_size_property (node, decl, &node->width);
|
|
|
|
else if (strcmp (property_name, "-st-natural-height") == 0)
|
2009-10-17 00:05:30 +00:00
|
|
|
do_size_property (node, decl, &node->height);
|
|
|
|
else if (strcmp (property_name, "min-width") == 0)
|
|
|
|
do_size_property (node, decl, &node->min_width);
|
|
|
|
else if (strcmp (property_name, "min-height") == 0)
|
|
|
|
do_size_property (node, decl, &node->min_height);
|
2010-02-12 18:58:24 +00:00
|
|
|
else if (strcmp (property_name, "max-width") == 0)
|
|
|
|
do_size_property (node, decl, &node->max_width);
|
|
|
|
else if (strcmp (property_name, "max-height") == 0)
|
|
|
|
do_size_property (node, decl, &node->max_height);
|
2009-10-17 00:05:30 +00:00
|
|
|
}
|
|
|
|
|
2012-11-30 16:03:45 +00:00
|
|
|
/*
|
|
|
|
* Setting width sets max-width, min-width and -st-natural-width,
|
|
|
|
* unless one of them is set individually.
|
|
|
|
* Setting min-width sets natural width too, so that the minimum
|
|
|
|
* width reported by get_preferred_width() is always not greater
|
|
|
|
* than the natural width.
|
|
|
|
* The natural width in node->width is actually a lower bound, the
|
|
|
|
* actor is allowed to request something greater than that, but
|
|
|
|
* not greater than max-width.
|
|
|
|
* We don't need to clamp node->width to be less than max_width,
|
|
|
|
* that's done by adjust_preferred_width.
|
|
|
|
*/
|
|
|
|
if (width != -1)
|
2009-10-17 00:05:30 +00:00
|
|
|
{
|
2012-11-30 16:03:45 +00:00
|
|
|
if (node->width == -1)
|
|
|
|
node->width = width;
|
2009-10-17 00:05:30 +00:00
|
|
|
if (node->min_width == -1)
|
2012-11-30 16:03:45 +00:00
|
|
|
node->min_width = width;
|
2010-02-12 18:58:24 +00:00
|
|
|
if (node->max_width == -1)
|
2012-11-30 16:03:45 +00:00
|
|
|
node->max_width = width;
|
2009-09-20 00:43:49 +00:00
|
|
|
}
|
2009-10-17 00:05:30 +00:00
|
|
|
|
2012-11-30 16:03:45 +00:00
|
|
|
if (node->width < node->min_width)
|
|
|
|
node->width = node->min_width;
|
|
|
|
|
|
|
|
if (height != -1)
|
2009-10-17 00:05:30 +00:00
|
|
|
{
|
2012-11-30 16:03:45 +00:00
|
|
|
if (node->height == -1)
|
|
|
|
node->height = height;
|
2009-10-17 00:05:30 +00:00
|
|
|
if (node->min_height == -1)
|
2012-11-30 16:03:45 +00:00
|
|
|
node->min_height = height;
|
2010-02-12 18:58:24 +00:00
|
|
|
if (node->max_height == -1)
|
2012-11-30 16:03:45 +00:00
|
|
|
node->max_height = height;
|
2009-10-17 00:05:30 +00:00
|
|
|
}
|
2012-11-30 16:03:45 +00:00
|
|
|
|
|
|
|
if (node->height < node->min_height)
|
|
|
|
node->height = node->min_height;
|
2009-09-20 00:43:49 +00:00
|
|
|
}
|
|
|
|
|
2010-02-11 02:10:49 +00:00
|
|
|
int
|
2009-09-20 00:43:49 +00:00
|
|
|
st_theme_node_get_border_width (StThemeNode *node,
|
|
|
|
StSide side)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
|
2009-09-20 13:08:08 +00:00
|
|
|
g_return_val_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT, 0.);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_geometry (node);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
return node->border_width[side];
|
|
|
|
}
|
|
|
|
|
2010-02-11 02:10:49 +00:00
|
|
|
int
|
2009-09-20 13:08:08 +00:00
|
|
|
st_theme_node_get_border_radius (StThemeNode *node,
|
|
|
|
StCorner corner)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
|
|
|
|
g_return_val_if_fail (corner >= ST_CORNER_TOPLEFT && corner <= ST_CORNER_BOTTOMLEFT, 0.);
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_geometry (node);
|
2009-09-20 13:08:08 +00:00
|
|
|
|
|
|
|
return node->border_radius[corner];
|
|
|
|
}
|
|
|
|
|
2010-05-26 20:50:24 +00:00
|
|
|
int
|
|
|
|
st_theme_node_get_outline_width (StThemeNode *node)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0);
|
|
|
|
|
|
|
|
_st_theme_node_ensure_geometry (node);
|
|
|
|
|
|
|
|
return node->outline_width;
|
|
|
|
}
|
|
|
|
|
2011-02-14 14:20:22 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_get_outline_color:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @color: (out caller-allocates): location to store the color
|
|
|
|
*
|
2011-11-02 16:24:49 +00:00
|
|
|
* Gets the color of @node's outline.
|
2011-02-14 14:20:22 +00:00
|
|
|
*/
|
2010-05-26 20:50:24 +00:00
|
|
|
void
|
|
|
|
st_theme_node_get_outline_color (StThemeNode *node,
|
|
|
|
ClutterColor *color)
|
|
|
|
{
|
|
|
|
g_return_if_fail (ST_IS_THEME_NODE (node));
|
|
|
|
|
|
|
|
_st_theme_node_ensure_geometry (node);
|
|
|
|
|
|
|
|
*color = node->outline_color;
|
|
|
|
}
|
|
|
|
|
2009-10-17 00:05:30 +00:00
|
|
|
int
|
|
|
|
st_theme_node_get_width (StThemeNode *node)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_geometry (node);
|
2009-10-17 00:05:30 +00:00
|
|
|
return node->width;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
st_theme_node_get_height (StThemeNode *node)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_geometry (node);
|
2009-10-17 00:05:30 +00:00
|
|
|
return node->height;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
st_theme_node_get_min_width (StThemeNode *node)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_geometry (node);
|
2009-10-17 00:05:30 +00:00
|
|
|
return node->min_width;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
st_theme_node_get_min_height (StThemeNode *node)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_geometry (node);
|
2009-10-17 00:05:30 +00:00
|
|
|
return node->min_height;
|
|
|
|
}
|
|
|
|
|
2010-02-12 18:58:24 +00:00
|
|
|
int
|
|
|
|
st_theme_node_get_max_width (StThemeNode *node)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_geometry (node);
|
2010-02-12 18:58:24 +00:00
|
|
|
return node->max_width;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
st_theme_node_get_max_height (StThemeNode *node)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), -1);
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_geometry (node);
|
2010-02-12 18:58:24 +00:00
|
|
|
return node->max_height;
|
|
|
|
}
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
static GetFromTermResult
|
|
|
|
get_background_color_from_term (StThemeNode *node,
|
|
|
|
CRTerm *term,
|
|
|
|
ClutterColor *color)
|
|
|
|
{
|
|
|
|
GetFromTermResult result = get_color_from_term (node, term, color);
|
|
|
|
if (result == VALUE_NOT_FOUND)
|
|
|
|
{
|
|
|
|
if (term_is_transparent (term))
|
|
|
|
{
|
|
|
|
*color = TRANSPARENT_COLOR;
|
|
|
|
return VALUE_FOUND;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
void
|
|
|
|
_st_theme_node_ensure_background (StThemeNode *node)
|
2009-09-20 00:43:49 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (node->background_computed)
|
|
|
|
return;
|
|
|
|
|
2012-07-28 08:36:20 +00:00
|
|
|
node->background_repeat = FALSE;
|
2009-09-20 00:43:49 +00:00
|
|
|
node->background_computed = TRUE;
|
|
|
|
node->background_color = TRANSPARENT_COLOR;
|
2009-11-14 21:39:22 +00:00
|
|
|
node->background_gradient_type = ST_GRADIENT_NONE;
|
2010-09-01 16:13:43 +00:00
|
|
|
node->background_position_set = FALSE;
|
2011-12-23 17:59:20 +00:00
|
|
|
node->background_size = ST_BACKGROUND_SIZE_AUTO;
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
ensure_properties (node);
|
|
|
|
|
|
|
|
for (i = 0; i < node->n_properties; i++)
|
|
|
|
{
|
|
|
|
CRDeclaration *decl = node->properties[i];
|
|
|
|
const char *property_name = decl->property->stryng->str;
|
|
|
|
|
|
|
|
if (g_str_has_prefix (property_name, "background"))
|
|
|
|
property_name += 10;
|
|
|
|
else
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (strcmp (property_name, "") == 0)
|
|
|
|
{
|
|
|
|
/* We're very liberal here ... if we recognize any term in the expression we take it, and
|
|
|
|
* we ignore the rest. The actual specification is:
|
|
|
|
*
|
|
|
|
* background: [<'background-color'> || <'background-image'> || <'background-repeat'> || <'background-attachment'> || <'background-position'>] | inherit
|
|
|
|
*/
|
|
|
|
|
|
|
|
CRTerm *term;
|
|
|
|
/* background: property sets all terms to specified or default values */
|
|
|
|
node->background_color = TRANSPARENT_COLOR;
|
2014-09-19 00:04:00 +00:00
|
|
|
g_clear_object (&node->background_image);
|
2010-09-01 16:13:43 +00:00
|
|
|
node->background_position_set = FALSE;
|
2011-12-23 17:59:20 +00:00
|
|
|
node->background_size = ST_BACKGROUND_SIZE_AUTO;
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
for (term = decl->value; term; term = term->next)
|
|
|
|
{
|
|
|
|
GetFromTermResult result = get_background_color_from_term (node, term, &node->background_color);
|
|
|
|
if (result == VALUE_FOUND)
|
|
|
|
{
|
|
|
|
/* color stored in node->background_color */
|
|
|
|
}
|
|
|
|
else if (result == VALUE_INHERIT)
|
|
|
|
{
|
|
|
|
if (node->parent_node)
|
|
|
|
{
|
|
|
|
st_theme_node_get_background_color (node->parent_node, &node->background_color);
|
2014-09-19 00:04:00 +00:00
|
|
|
node->background_image = g_object_ref (st_theme_node_get_background_image (node->parent_node));
|
2009-09-20 00:43:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (term_is_none (term))
|
|
|
|
{
|
|
|
|
/* leave node->background_color as transparent */
|
|
|
|
}
|
|
|
|
else if (term->type == TERM_URI)
|
|
|
|
{
|
2010-12-08 23:05:31 +00:00
|
|
|
CRStyleSheet *base_stylesheet;
|
2012-11-22 00:13:59 +00:00
|
|
|
GFile *file;
|
2010-12-08 23:05:31 +00:00
|
|
|
|
|
|
|
if (decl->parent_statement != NULL)
|
|
|
|
base_stylesheet = decl->parent_statement->parent_sheet;
|
|
|
|
else
|
|
|
|
base_stylesheet = NULL;
|
|
|
|
|
2012-11-22 00:13:59 +00:00
|
|
|
file = _st_theme_resolve_url (node->theme,
|
|
|
|
base_stylesheet,
|
|
|
|
term->content.str->stryng->str);
|
|
|
|
|
2014-09-19 00:04:00 +00:00
|
|
|
node->background_image = file;
|
2009-09-20 00:43:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-09-01 16:13:43 +00:00
|
|
|
else if (strcmp (property_name, "-position") == 0)
|
|
|
|
{
|
|
|
|
GetFromTermResult result = get_length_from_term_int (node, decl->value, FALSE, &node->background_position_x);
|
|
|
|
if (result == VALUE_NOT_FOUND)
|
|
|
|
{
|
|
|
|
node->background_position_set = FALSE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
node->background_position_set = TRUE;
|
2012-07-28 07:49:14 +00:00
|
|
|
|
|
|
|
result = get_length_from_term_int (node, decl->value->next, FALSE, &node->background_position_y);
|
2010-09-01 16:13:43 +00:00
|
|
|
|
|
|
|
if (result == VALUE_NOT_FOUND)
|
|
|
|
{
|
|
|
|
node->background_position_set = FALSE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
node->background_position_set = TRUE;
|
|
|
|
}
|
2012-07-28 08:36:20 +00:00
|
|
|
else if (strcmp (property_name, "-repeat") == 0)
|
|
|
|
{
|
|
|
|
if (decl->value->type == TERM_IDENT)
|
|
|
|
{
|
|
|
|
if (strcmp (decl->value->content.str->stryng->str, "repeat") == 0)
|
|
|
|
node->background_repeat = TRUE;
|
|
|
|
}
|
|
|
|
}
|
2011-12-23 17:59:20 +00:00
|
|
|
else if (strcmp (property_name, "-size") == 0)
|
|
|
|
{
|
|
|
|
if (decl->value->type == TERM_IDENT)
|
|
|
|
{
|
|
|
|
if (strcmp (decl->value->content.str->stryng->str, "contain") == 0)
|
|
|
|
node->background_size = ST_BACKGROUND_SIZE_CONTAIN;
|
|
|
|
else if (strcmp (decl->value->content.str->stryng->str, "cover") == 0)
|
|
|
|
node->background_size = ST_BACKGROUND_SIZE_COVER;
|
|
|
|
else if ((strcmp (decl->value->content.str->stryng->str, "auto") == 0) && (decl->value->next) && (decl->value->next->type == TERM_NUMBER))
|
|
|
|
{
|
|
|
|
GetFromTermResult result = get_length_from_term_int (node, decl->value->next, FALSE, &node->background_size_h);
|
|
|
|
|
|
|
|
node->background_size_w = -1;
|
|
|
|
node->background_size = (result == VALUE_FOUND) ? ST_BACKGROUND_SIZE_FIXED : ST_BACKGROUND_SIZE_AUTO;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
node->background_size = ST_BACKGROUND_SIZE_AUTO;
|
|
|
|
}
|
|
|
|
else if (decl->value->type == TERM_NUMBER)
|
|
|
|
{
|
|
|
|
GetFromTermResult result = get_length_from_term_int (node, decl->value, FALSE, &node->background_size_w);
|
|
|
|
if (result == VALUE_NOT_FOUND)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
node->background_size = ST_BACKGROUND_SIZE_FIXED;
|
|
|
|
|
|
|
|
if ((decl->value->next) && (decl->value->next->type == TERM_NUMBER))
|
|
|
|
{
|
|
|
|
result = get_length_from_term_int (node, decl->value->next, FALSE, &node->background_size_h);
|
|
|
|
|
|
|
|
if (result == VALUE_FOUND)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
node->background_size_h = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
node->background_size = ST_BACKGROUND_SIZE_AUTO;
|
|
|
|
}
|
2009-09-20 00:43:49 +00:00
|
|
|
else if (strcmp (property_name, "-color") == 0)
|
|
|
|
{
|
|
|
|
GetFromTermResult result;
|
|
|
|
|
|
|
|
if (decl->value == NULL || decl->value->next != NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
result = get_background_color_from_term (node, decl->value, &node->background_color);
|
|
|
|
if (result == VALUE_FOUND)
|
|
|
|
{
|
|
|
|
/* color stored in node->background_color */
|
|
|
|
}
|
|
|
|
else if (result == VALUE_INHERIT)
|
|
|
|
{
|
|
|
|
if (node->parent_node)
|
|
|
|
st_theme_node_get_background_color (node->parent_node, &node->background_color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (strcmp (property_name, "-image") == 0)
|
|
|
|
{
|
|
|
|
if (decl->value == NULL || decl->value->next != NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (decl->value->type == TERM_URI)
|
|
|
|
{
|
2010-12-08 23:05:31 +00:00
|
|
|
CRStyleSheet *base_stylesheet;
|
|
|
|
|
|
|
|
if (decl->parent_statement != NULL)
|
|
|
|
base_stylesheet = decl->parent_statement->parent_sheet;
|
|
|
|
else
|
|
|
|
base_stylesheet = NULL;
|
|
|
|
|
2014-09-19 00:04:00 +00:00
|
|
|
g_clear_object (&node->background_image);
|
|
|
|
node->background_image = _st_theme_resolve_url (node->theme,
|
|
|
|
base_stylesheet,
|
|
|
|
decl->value->content.str->stryng->str);
|
2009-09-20 00:43:49 +00:00
|
|
|
}
|
|
|
|
else if (term_is_inherit (decl->value))
|
|
|
|
{
|
2014-09-19 00:04:00 +00:00
|
|
|
g_clear_object (&node->background_image);
|
|
|
|
node->background_image = g_object_ref (st_theme_node_get_background_image (node->parent_node));
|
2009-09-20 00:43:49 +00:00
|
|
|
}
|
|
|
|
else if (term_is_none (decl->value))
|
|
|
|
{
|
2014-09-19 00:04:00 +00:00
|
|
|
g_clear_object (&node->background_image);
|
2009-09-20 00:43:49 +00:00
|
|
|
}
|
|
|
|
}
|
2009-11-14 21:39:22 +00:00
|
|
|
else if (strcmp (property_name, "-gradient-direction") == 0)
|
|
|
|
{
|
|
|
|
CRTerm *term = decl->value;
|
|
|
|
if (strcmp (term->content.str->stryng->str, "vertical") == 0)
|
|
|
|
{
|
|
|
|
node->background_gradient_type = ST_GRADIENT_VERTICAL;
|
|
|
|
}
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "horizontal") == 0)
|
|
|
|
{
|
|
|
|
node->background_gradient_type = ST_GRADIENT_HORIZONTAL;
|
|
|
|
}
|
2010-01-10 01:17:01 +00:00
|
|
|
else if (strcmp (term->content.str->stryng->str, "radial") == 0)
|
|
|
|
{
|
|
|
|
node->background_gradient_type = ST_GRADIENT_RADIAL;
|
|
|
|
}
|
2010-02-23 16:13:58 +00:00
|
|
|
else if (strcmp (term->content.str->stryng->str, "none") == 0)
|
|
|
|
{
|
|
|
|
node->background_gradient_type = ST_GRADIENT_NONE;
|
|
|
|
}
|
2009-11-14 21:39:22 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("Unrecognized background-gradient-direction \"%s\"",
|
|
|
|
term->content.str->stryng->str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (strcmp (property_name, "-gradient-start") == 0)
|
|
|
|
{
|
|
|
|
get_color_from_term (node, decl->value, &node->background_color);
|
|
|
|
}
|
|
|
|
else if (strcmp (property_name, "-gradient-end") == 0)
|
|
|
|
{
|
|
|
|
get_color_from_term (node, decl->value, &node->background_gradient_end);
|
|
|
|
}
|
2009-09-20 00:43:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-14 14:20:22 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_get_background_color:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @color: (out caller-allocates): location to store the color
|
|
|
|
*
|
2011-11-02 16:24:49 +00:00
|
|
|
* Gets @node's background color.
|
2011-02-14 14:20:22 +00:00
|
|
|
*/
|
2009-09-20 00:43:49 +00:00
|
|
|
void
|
|
|
|
st_theme_node_get_background_color (StThemeNode *node,
|
|
|
|
ClutterColor *color)
|
|
|
|
{
|
|
|
|
g_return_if_fail (ST_IS_THEME_NODE (node));
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_background (node);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
*color = node->background_color;
|
|
|
|
}
|
|
|
|
|
2014-09-19 00:04:00 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_get_background_image:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
*
|
|
|
|
* Returns: (transfer none): @node's background image.
|
|
|
|
*/
|
|
|
|
GFile *
|
2009-09-20 00:43:49 +00:00
|
|
|
st_theme_node_get_background_image (StThemeNode *node)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_background (node);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
return node->background_image;
|
|
|
|
}
|
|
|
|
|
2011-02-14 14:20:22 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_get_foreground_color:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @color: (out caller-allocates): location to store the color
|
|
|
|
*
|
2011-11-02 16:24:49 +00:00
|
|
|
* Gets @node's foreground color.
|
2011-02-14 14:20:22 +00:00
|
|
|
*/
|
2009-09-20 00:43:49 +00:00
|
|
|
void
|
|
|
|
st_theme_node_get_foreground_color (StThemeNode *node,
|
|
|
|
ClutterColor *color)
|
|
|
|
{
|
|
|
|
g_return_if_fail (ST_IS_THEME_NODE (node));
|
|
|
|
|
|
|
|
if (!node->foreground_computed)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
node->foreground_computed = TRUE;
|
|
|
|
|
|
|
|
ensure_properties (node);
|
|
|
|
|
|
|
|
for (i = node->n_properties - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
CRDeclaration *decl = node->properties[i];
|
|
|
|
|
|
|
|
if (strcmp (decl->property->stryng->str, "color") == 0)
|
|
|
|
{
|
|
|
|
GetFromTermResult result = get_color_from_term (node, decl->value, &node->foreground_color);
|
|
|
|
if (result == VALUE_FOUND)
|
|
|
|
goto out;
|
|
|
|
else if (result == VALUE_INHERIT)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->parent_node)
|
|
|
|
st_theme_node_get_foreground_color (node->parent_node, &node->foreground_color);
|
|
|
|
else
|
|
|
|
node->foreground_color = BLACK_COLOR; /* default to black */
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
*color = node->foreground_color;
|
|
|
|
}
|
|
|
|
|
2009-11-14 21:39:22 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* st_theme_node_get_background_gradient:
|
|
|
|
* @node: A #StThemeNode
|
|
|
|
* @type: (out): Type of gradient
|
2011-02-14 14:20:22 +00:00
|
|
|
* @start: (out caller-allocates): Color at start of gradient
|
|
|
|
* @end: (out caller-allocates): Color at end of gradient
|
2009-11-14 21:39:22 +00:00
|
|
|
*
|
|
|
|
* The @start and @end arguments will only be set if @type is not #ST_GRADIENT_NONE.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
st_theme_node_get_background_gradient (StThemeNode *node,
|
|
|
|
StGradientType *type,
|
|
|
|
ClutterColor *start,
|
|
|
|
ClutterColor *end)
|
|
|
|
{
|
|
|
|
g_return_if_fail (ST_IS_THEME_NODE (node));
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_background (node);
|
2009-11-14 21:39:22 +00:00
|
|
|
|
|
|
|
*type = node->background_gradient_type;
|
|
|
|
if (*type != ST_GRADIENT_NONE)
|
|
|
|
{
|
|
|
|
*start = node->background_color;
|
|
|
|
*end = node->background_gradient_end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-14 14:20:22 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_get_border_color:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @side: a #StSide
|
|
|
|
* @color: (out caller-allocates): location to store the color
|
|
|
|
*
|
2011-11-02 16:24:49 +00:00
|
|
|
* Gets the color of @node's border on @side
|
2011-02-14 14:20:22 +00:00
|
|
|
*/
|
2009-09-20 00:43:49 +00:00
|
|
|
void
|
|
|
|
st_theme_node_get_border_color (StThemeNode *node,
|
|
|
|
StSide side,
|
|
|
|
ClutterColor *color)
|
|
|
|
{
|
|
|
|
g_return_if_fail (ST_IS_THEME_NODE (node));
|
2009-09-20 13:08:08 +00:00
|
|
|
g_return_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_geometry (node);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
*color = node->border_color[side];
|
|
|
|
}
|
|
|
|
|
|
|
|
double
|
|
|
|
st_theme_node_get_padding (StThemeNode *node,
|
|
|
|
StSide side)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
|
2009-09-20 13:08:08 +00:00
|
|
|
g_return_val_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT, 0.);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_geometry (node);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
return node->padding[side];
|
|
|
|
}
|
|
|
|
|
2014-11-11 14:04:46 +00:00
|
|
|
double
|
|
|
|
st_theme_node_get_margin (StThemeNode *node,
|
|
|
|
StSide side)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
|
|
|
|
g_return_val_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT, 0.);
|
|
|
|
|
|
|
|
_st_theme_node_ensure_geometry (node);
|
|
|
|
|
|
|
|
return node->margin[side];
|
|
|
|
}
|
|
|
|
|
2010-05-30 21:06:37 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_get_transition_duration:
|
|
|
|
* @node: an #StThemeNode
|
|
|
|
*
|
|
|
|
* Get the value of the transition-duration property, which
|
|
|
|
* specifies the transition time between the previous #StThemeNode
|
|
|
|
* and @node.
|
|
|
|
*
|
|
|
|
* Returns: the node's transition duration in milliseconds
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
st_theme_node_get_transition_duration (StThemeNode *node)
|
|
|
|
{
|
|
|
|
gdouble value = 0.0;
|
|
|
|
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), 0);
|
|
|
|
|
|
|
|
if (node->transition_duration > -1)
|
2010-06-20 02:16:06 +00:00
|
|
|
return st_slow_down_factor * node->transition_duration;
|
2010-05-30 21:06:37 +00:00
|
|
|
|
2012-08-07 14:20:43 +00:00
|
|
|
st_theme_node_lookup_time (node, "transition-duration", FALSE, &value);
|
2010-05-30 21:06:37 +00:00
|
|
|
|
|
|
|
node->transition_duration = (int)value;
|
|
|
|
|
2010-06-20 02:16:06 +00:00
|
|
|
return st_slow_down_factor * node->transition_duration;
|
2010-05-30 21:06:37 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 14:53:36 +00:00
|
|
|
StIconStyle
|
|
|
|
st_theme_node_get_icon_style (StThemeNode *node)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ensure_properties (node);
|
|
|
|
|
|
|
|
for (i = node->n_properties - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
CRDeclaration *decl = node->properties[i];
|
|
|
|
|
|
|
|
if (strcmp (decl->property->stryng->str, "-st-icon-style") == 0)
|
|
|
|
{
|
|
|
|
CRTerm *term;
|
|
|
|
|
|
|
|
for (term = decl->value; term; term = term->next)
|
|
|
|
{
|
|
|
|
if (term->type != TERM_IDENT)
|
|
|
|
goto next_decl;
|
|
|
|
|
|
|
|
if (strcmp (term->content.str->stryng->str, "requested") == 0)
|
|
|
|
return ST_ICON_STYLE_REQUESTED;
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "regular") == 0)
|
|
|
|
return ST_ICON_STYLE_REGULAR;
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "symbolic") == 0)
|
|
|
|
return ST_ICON_STYLE_SYMBOLIC;
|
|
|
|
else
|
|
|
|
g_warning ("Unknown -st-icon-style \"%s\"",
|
|
|
|
term->content.str->stryng->str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
next_decl:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->parent_node)
|
|
|
|
return st_theme_node_get_icon_style (node->parent_node);
|
|
|
|
|
|
|
|
return ST_ICON_STYLE_REQUESTED;
|
|
|
|
}
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
StTextDecoration
|
|
|
|
st_theme_node_get_text_decoration (StThemeNode *node)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ensure_properties (node);
|
|
|
|
|
|
|
|
for (i = node->n_properties - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
CRDeclaration *decl = node->properties[i];
|
|
|
|
|
|
|
|
if (strcmp (decl->property->stryng->str, "text-decoration") == 0)
|
|
|
|
{
|
|
|
|
CRTerm *term = decl->value;
|
|
|
|
StTextDecoration decoration = 0;
|
|
|
|
|
|
|
|
/* Specification is none | [ underline || overline || line-through || blink ] | inherit
|
|
|
|
*
|
|
|
|
* We're a bit more liberal, and for example treat 'underline none' as the same as
|
|
|
|
* none.
|
|
|
|
*/
|
|
|
|
for (; term; term = term->next)
|
|
|
|
{
|
|
|
|
if (term->type != TERM_IDENT)
|
|
|
|
goto next_decl;
|
|
|
|
|
|
|
|
if (strcmp (term->content.str->stryng->str, "none") == 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "inherit") == 0)
|
|
|
|
{
|
|
|
|
if (node->parent_node)
|
|
|
|
return st_theme_node_get_text_decoration (node->parent_node);
|
|
|
|
}
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "underline") == 0)
|
|
|
|
{
|
|
|
|
decoration |= ST_TEXT_DECORATION_UNDERLINE;
|
|
|
|
}
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "overline") == 0)
|
|
|
|
{
|
|
|
|
decoration |= ST_TEXT_DECORATION_OVERLINE;
|
|
|
|
}
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "line-through") == 0)
|
|
|
|
{
|
|
|
|
decoration |= ST_TEXT_DECORATION_LINE_THROUGH;
|
|
|
|
}
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "blink") == 0)
|
|
|
|
{
|
|
|
|
decoration |= ST_TEXT_DECORATION_BLINK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
goto next_decl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return decoration;
|
|
|
|
}
|
|
|
|
|
|
|
|
next_decl:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-06-22 20:04:45 +00:00
|
|
|
StTextAlign
|
|
|
|
st_theme_node_get_text_align(StThemeNode *node)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ensure_properties(node);
|
|
|
|
|
|
|
|
for (i = node->n_properties - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
CRDeclaration *decl = node->properties[i];
|
|
|
|
|
|
|
|
if (strcmp(decl->property->stryng->str, "text-align") == 0)
|
|
|
|
{
|
|
|
|
CRTerm *term = decl->value;
|
|
|
|
|
|
|
|
if (term->type != TERM_IDENT || term->next)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (strcmp(term->content.str->stryng->str, "inherit") == 0)
|
|
|
|
{
|
|
|
|
if (node->parent_node)
|
|
|
|
return st_theme_node_get_text_align(node->parent_node);
|
|
|
|
return ST_TEXT_ALIGN_LEFT;
|
|
|
|
}
|
|
|
|
else if (strcmp(term->content.str->stryng->str, "left") == 0)
|
|
|
|
{
|
|
|
|
return ST_TEXT_ALIGN_LEFT;
|
|
|
|
}
|
|
|
|
else if (strcmp(term->content.str->stryng->str, "right") == 0)
|
|
|
|
{
|
|
|
|
return ST_TEXT_ALIGN_RIGHT;
|
|
|
|
}
|
|
|
|
else if (strcmp(term->content.str->stryng->str, "center") == 0)
|
|
|
|
{
|
|
|
|
return ST_TEXT_ALIGN_CENTER;
|
|
|
|
}
|
|
|
|
else if (strcmp(term->content.str->stryng->str, "justify") == 0)
|
|
|
|
{
|
|
|
|
return ST_TEXT_ALIGN_JUSTIFY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(node->parent_node)
|
|
|
|
return st_theme_node_get_text_align(node->parent_node);
|
|
|
|
return ST_TEXT_ALIGN_LEFT;
|
|
|
|
}
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
static gboolean
|
|
|
|
font_family_from_terms (CRTerm *term,
|
|
|
|
char **family)
|
|
|
|
{
|
|
|
|
GString *family_string;
|
|
|
|
gboolean result = FALSE;
|
|
|
|
gboolean last_was_quoted = FALSE;
|
|
|
|
|
|
|
|
if (!term)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
family_string = g_string_new (NULL);
|
|
|
|
|
|
|
|
while (term)
|
|
|
|
{
|
|
|
|
if (term->type != TERM_STRING && term->type != TERM_IDENT)
|
|
|
|
{
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (family_string->len > 0)
|
|
|
|
{
|
|
|
|
if (term->the_operator != COMMA && term->the_operator != NO_OP)
|
|
|
|
goto out;
|
|
|
|
/* Can concatenate two bare words, but not two quoted strings */
|
|
|
|
if ((term->the_operator == NO_OP && last_was_quoted) || term->type == TERM_STRING)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (term->the_operator == NO_OP)
|
|
|
|
g_string_append (family_string, " ");
|
|
|
|
else
|
|
|
|
g_string_append (family_string, ", ");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (term->the_operator != NO_OP)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_string_append (family_string, term->content.str->stryng->str);
|
|
|
|
|
|
|
|
term = term->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = TRUE;
|
|
|
|
|
|
|
|
out:
|
|
|
|
if (result)
|
|
|
|
{
|
|
|
|
*family = g_string_free (family_string, FALSE);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*family = g_string_free (family_string, TRUE);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* In points */
|
|
|
|
static int font_sizes[] = {
|
|
|
|
6 * 1024, /* xx-small */
|
|
|
|
8 * 1024, /* x-small */
|
|
|
|
10 * 1024, /* small */
|
|
|
|
12 * 1024, /* medium */
|
|
|
|
16 * 1024, /* large */
|
|
|
|
20 * 1024, /* x-large */
|
|
|
|
24 * 1024, /* xx-large */
|
|
|
|
};
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
font_size_from_term (StThemeNode *node,
|
|
|
|
CRTerm *term,
|
|
|
|
double *size)
|
|
|
|
{
|
|
|
|
if (term->type == TERM_IDENT)
|
|
|
|
{
|
2012-03-26 14:14:31 +00:00
|
|
|
double resolution = clutter_backend_get_resolution (clutter_get_default_backend ());
|
2009-09-20 00:43:49 +00:00
|
|
|
/* We work in integers to avoid double comparisons when converting back
|
|
|
|
* from a size in pixels to a logical size.
|
|
|
|
*/
|
|
|
|
int size_points = (int)(0.5 + *size * (72. / resolution));
|
|
|
|
|
|
|
|
if (strcmp (term->content.str->stryng->str, "xx-small") == 0)
|
|
|
|
size_points = font_sizes[0];
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "x-small") == 0)
|
|
|
|
size_points = font_sizes[1];
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "small") == 0)
|
|
|
|
size_points = font_sizes[2];
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "medium") == 0)
|
|
|
|
size_points = font_sizes[3];
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "large") == 0)
|
|
|
|
size_points = font_sizes[4];
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "x-large") == 0)
|
|
|
|
size_points = font_sizes[5];
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "xx-large") == 0)
|
|
|
|
size_points = font_sizes[6];
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "smaller") == 0)
|
|
|
|
{
|
|
|
|
/* Find the standard size equal to or smaller than the current size */
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
while (i <= 6 && font_sizes[i] < size_points)
|
|
|
|
i++;
|
|
|
|
|
|
|
|
if (i > 6)
|
|
|
|
{
|
|
|
|
/* original size greater than any standard size */
|
|
|
|
size_points = (int)(0.5 + size_points / 1.2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Go one smaller than that, if possible */
|
|
|
|
if (i > 0)
|
|
|
|
i--;
|
|
|
|
|
|
|
|
size_points = font_sizes[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "larger") == 0)
|
|
|
|
{
|
|
|
|
/* Find the standard size equal to or larger than the current size */
|
|
|
|
int i = 6;
|
|
|
|
|
|
|
|
while (i >= 0 && font_sizes[i] > size_points)
|
|
|
|
i--;
|
|
|
|
|
|
|
|
if (i < 0) /* original size smaller than any standard size */
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
/* Go one larger than that, if possible */
|
|
|
|
if (i < 6)
|
|
|
|
i++;
|
|
|
|
|
|
|
|
size_points = font_sizes[i];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*size = size_points * (resolution / 72.);
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (term->type == TERM_NUMBER && term->content.num->type == NUM_PERCENTAGE)
|
|
|
|
{
|
|
|
|
*size *= term->content.num->val / 100.;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else if (get_length_from_term (node, term, TRUE, size) == VALUE_FOUND)
|
|
|
|
{
|
|
|
|
/* Convert from pixels to Pango units */
|
|
|
|
*size *= 1024;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
font_weight_from_term (CRTerm *term,
|
|
|
|
PangoWeight *weight,
|
|
|
|
gboolean *weight_absolute)
|
|
|
|
{
|
|
|
|
if (term->type == TERM_NUMBER)
|
|
|
|
{
|
|
|
|
int weight_int;
|
|
|
|
|
|
|
|
/* The spec only allows numeric weights from 100-900, though Pango
|
|
|
|
* will handle any number. We just let anything through.
|
|
|
|
*/
|
|
|
|
if (term->content.num->type != NUM_GENERIC)
|
|
|
|
return FALSE;
|
|
|
|
|
2009-10-01 20:32:38 +00:00
|
|
|
weight_int = (int)(0.5 + term->content.num->val);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
*weight = weight_int;
|
|
|
|
*weight_absolute = TRUE;
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (term->type == TERM_IDENT)
|
|
|
|
{
|
|
|
|
/* FIXME: handle INHERIT */
|
|
|
|
|
|
|
|
if (strcmp (term->content.str->stryng->str, "bold") == 0)
|
|
|
|
{
|
|
|
|
*weight = PANGO_WEIGHT_BOLD;
|
|
|
|
*weight_absolute = TRUE;
|
|
|
|
}
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "normal") == 0)
|
|
|
|
{
|
|
|
|
*weight = PANGO_WEIGHT_NORMAL;
|
|
|
|
*weight_absolute = TRUE;
|
|
|
|
}
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "bolder") == 0)
|
|
|
|
{
|
|
|
|
*weight = PANGO_WEIGHT_BOLD;
|
|
|
|
*weight_absolute = FALSE;
|
|
|
|
}
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "lighter") == 0)
|
|
|
|
{
|
|
|
|
*weight = PANGO_WEIGHT_LIGHT;
|
|
|
|
*weight_absolute = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
font_style_from_term (CRTerm *term,
|
|
|
|
PangoStyle *style)
|
|
|
|
{
|
|
|
|
if (term->type != TERM_IDENT)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* FIXME: handle INHERIT */
|
|
|
|
|
|
|
|
if (strcmp (term->content.str->stryng->str, "normal") == 0)
|
|
|
|
*style = PANGO_STYLE_NORMAL;
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "oblique") == 0)
|
|
|
|
*style = PANGO_STYLE_OBLIQUE;
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "italic") == 0)
|
|
|
|
*style = PANGO_STYLE_ITALIC;
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
font_variant_from_term (CRTerm *term,
|
|
|
|
PangoVariant *variant)
|
|
|
|
{
|
|
|
|
if (term->type != TERM_IDENT)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* FIXME: handle INHERIT */
|
|
|
|
|
|
|
|
if (strcmp (term->content.str->stryng->str, "normal") == 0)
|
|
|
|
*variant = PANGO_VARIANT_NORMAL;
|
|
|
|
else if (strcmp (term->content.str->stryng->str, "small-caps") == 0)
|
|
|
|
*variant = PANGO_VARIANT_SMALL_CAPS;
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
const PangoFontDescription *
|
|
|
|
st_theme_node_get_font (StThemeNode *node)
|
|
|
|
{
|
2010-11-14 18:33:48 +00:00
|
|
|
/* Initialized despite _set flags to suppress compiler warnings */
|
|
|
|
PangoStyle font_style = PANGO_STYLE_NORMAL;
|
2009-09-20 00:43:49 +00:00
|
|
|
gboolean font_style_set = FALSE;
|
2010-11-14 18:33:48 +00:00
|
|
|
PangoVariant variant = PANGO_VARIANT_NORMAL;
|
2009-09-20 00:43:49 +00:00
|
|
|
gboolean variant_set = FALSE;
|
2010-11-14 18:33:48 +00:00
|
|
|
PangoWeight weight = PANGO_WEIGHT_NORMAL;
|
|
|
|
gboolean weight_absolute = TRUE;
|
2009-09-20 00:43:49 +00:00
|
|
|
gboolean weight_set = FALSE;
|
2010-11-14 18:33:48 +00:00
|
|
|
double size = 0.;
|
2009-09-20 00:43:49 +00:00
|
|
|
gboolean size_set = FALSE;
|
2010-11-14 18:33:48 +00:00
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
char *family = NULL;
|
2010-11-14 18:33:48 +00:00
|
|
|
double parent_size;
|
2009-09-20 00:43:49 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (node->font_desc)
|
|
|
|
return node->font_desc;
|
|
|
|
|
|
|
|
node->font_desc = pango_font_description_copy (get_parent_font (node));
|
|
|
|
parent_size = pango_font_description_get_size (node->font_desc);
|
|
|
|
if (!pango_font_description_get_size_is_absolute (node->font_desc))
|
|
|
|
{
|
2012-03-26 14:14:31 +00:00
|
|
|
double resolution = clutter_backend_get_resolution (clutter_get_default_backend ());
|
2009-09-20 00:43:49 +00:00
|
|
|
parent_size *= (resolution / 72.);
|
|
|
|
}
|
|
|
|
|
|
|
|
ensure_properties (node);
|
|
|
|
|
|
|
|
for (i = 0; i < node->n_properties; i++)
|
|
|
|
{
|
|
|
|
CRDeclaration *decl = node->properties[i];
|
|
|
|
|
|
|
|
if (strcmp (decl->property->stryng->str, "font") == 0)
|
|
|
|
{
|
|
|
|
PangoStyle tmp_style = PANGO_STYLE_NORMAL;
|
|
|
|
PangoVariant tmp_variant = PANGO_VARIANT_NORMAL;
|
|
|
|
PangoWeight tmp_weight = PANGO_WEIGHT_NORMAL;
|
|
|
|
gboolean tmp_weight_absolute = TRUE;
|
|
|
|
double tmp_size;
|
|
|
|
CRTerm *term = decl->value;
|
|
|
|
|
|
|
|
/* A font specification starts with node/variant/weight
|
|
|
|
* in any order. Each is allowed to be specified only once,
|
|
|
|
* but we don't enforce that.
|
|
|
|
*/
|
|
|
|
for (; term; term = term->next)
|
|
|
|
{
|
|
|
|
if (font_style_from_term (term, &tmp_style))
|
|
|
|
continue;
|
|
|
|
if (font_variant_from_term (term, &tmp_variant))
|
|
|
|
continue;
|
|
|
|
if (font_weight_from_term (term, &tmp_weight, &tmp_weight_absolute))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The size is mandatory */
|
|
|
|
|
|
|
|
if (term == NULL || term->type != TERM_NUMBER)
|
|
|
|
{
|
|
|
|
g_warning ("Size missing from font property");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp_size = parent_size;
|
|
|
|
if (!font_size_from_term (node, term, &tmp_size))
|
|
|
|
{
|
|
|
|
g_warning ("Couldn't parse size in font property");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
term = term->next;
|
|
|
|
|
|
|
|
if (term != NULL && term->type && TERM_NUMBER && term->the_operator == DIVIDE)
|
|
|
|
{
|
|
|
|
/* Ignore line-height specification */
|
|
|
|
term = term->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* the font family is mandatory - it is a comma-separated list of
|
|
|
|
* names.
|
|
|
|
*/
|
|
|
|
if (!font_family_from_terms (term, &family))
|
|
|
|
{
|
|
|
|
g_warning ("Couldn't parse family in font property");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
font_style = tmp_style;
|
|
|
|
font_style_set = TRUE;
|
|
|
|
weight = tmp_weight;
|
|
|
|
weight_absolute = tmp_weight_absolute;
|
|
|
|
weight_set = TRUE;
|
|
|
|
variant = tmp_variant;
|
|
|
|
variant_set = TRUE;
|
|
|
|
|
|
|
|
size = tmp_size;
|
|
|
|
size_set = TRUE;
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (strcmp (decl->property->stryng->str, "font-family") == 0)
|
|
|
|
{
|
|
|
|
if (!font_family_from_terms (decl->value, &family))
|
|
|
|
{
|
|
|
|
g_warning ("Couldn't parse family in font property");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (strcmp (decl->property->stryng->str, "font-weight") == 0)
|
|
|
|
{
|
|
|
|
if (decl->value == NULL || decl->value->next != NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (font_weight_from_term (decl->value, &weight, &weight_absolute))
|
|
|
|
weight_set = TRUE;
|
|
|
|
}
|
|
|
|
else if (strcmp (decl->property->stryng->str, "font-style") == 0)
|
|
|
|
{
|
|
|
|
if (decl->value == NULL || decl->value->next != NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (font_style_from_term (decl->value, &font_style))
|
|
|
|
font_style_set = TRUE;
|
|
|
|
}
|
|
|
|
else if (strcmp (decl->property->stryng->str, "font-variant") == 0)
|
|
|
|
{
|
|
|
|
if (decl->value == NULL || decl->value->next != NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (font_variant_from_term (decl->value, &variant))
|
|
|
|
variant_set = TRUE;
|
|
|
|
}
|
|
|
|
else if (strcmp (decl->property->stryng->str, "font-size") == 0)
|
|
|
|
{
|
|
|
|
gdouble tmp_size;
|
|
|
|
if (decl->value == NULL || decl->value->next != NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
tmp_size = parent_size;
|
|
|
|
if (font_size_from_term (node, decl->value, &tmp_size))
|
|
|
|
{
|
|
|
|
size = tmp_size;
|
|
|
|
size_set = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (family)
|
2010-01-04 18:48:27 +00:00
|
|
|
{
|
|
|
|
pango_font_description_set_family (node->font_desc, family);
|
|
|
|
g_free (family);
|
|
|
|
}
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
if (size_set)
|
|
|
|
pango_font_description_set_absolute_size (node->font_desc, size);
|
|
|
|
|
|
|
|
if (weight_set)
|
|
|
|
{
|
|
|
|
if (!weight_absolute)
|
|
|
|
{
|
|
|
|
/* bolder/lighter are supposed to switch between available styles, but with
|
|
|
|
* font substitution, that gets to be a pretty fuzzy concept. So we use
|
|
|
|
* a fixed step of 200. (The spec says 100, but that might not take us from
|
|
|
|
* normal to bold.
|
|
|
|
*/
|
|
|
|
|
|
|
|
PangoWeight old_weight = pango_font_description_get_weight (node->font_desc);
|
|
|
|
if (weight == PANGO_WEIGHT_BOLD)
|
|
|
|
weight = old_weight + 200;
|
|
|
|
else
|
|
|
|
weight = old_weight - 200;
|
|
|
|
|
|
|
|
if (weight < 100)
|
|
|
|
weight = 100;
|
|
|
|
if (weight > 900)
|
|
|
|
weight = 900;
|
|
|
|
}
|
|
|
|
|
|
|
|
pango_font_description_set_weight (node->font_desc, weight);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (font_style_set)
|
|
|
|
pango_font_description_set_style (node->font_desc, font_style);
|
|
|
|
if (variant_set)
|
|
|
|
pango_font_description_set_variant (node->font_desc, variant);
|
|
|
|
|
|
|
|
return node->font_desc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-09-20 20:50:42 +00:00
|
|
|
* st_theme_node_get_border_image:
|
2009-09-20 00:43:49 +00:00
|
|
|
* @node: a #StThemeNode
|
|
|
|
*
|
2009-09-20 20:50:42 +00:00
|
|
|
* Gets the value for the border-image style property
|
2009-09-20 00:43:49 +00:00
|
|
|
*
|
2009-09-20 20:50:42 +00:00
|
|
|
* Return value: (transfer none): the border image, or %NULL
|
|
|
|
* if there is no border image.
|
2009-09-20 00:43:49 +00:00
|
|
|
*/
|
2009-09-20 20:50:42 +00:00
|
|
|
StBorderImage *
|
|
|
|
st_theme_node_get_border_image (StThemeNode *node)
|
2009-09-20 00:43:49 +00:00
|
|
|
{
|
|
|
|
int i;
|
2014-03-23 03:43:35 +00:00
|
|
|
int scale_factor;
|
2009-09-20 00:43:49 +00:00
|
|
|
|
2009-09-20 20:50:42 +00:00
|
|
|
if (node->border_image_computed)
|
|
|
|
return node->border_image;
|
2009-09-20 00:43:49 +00:00
|
|
|
|
2009-09-20 20:50:42 +00:00
|
|
|
node->border_image = NULL;
|
|
|
|
node->border_image_computed = TRUE;
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
ensure_properties (node);
|
2014-03-23 03:43:35 +00:00
|
|
|
g_object_get (node->context, "scale-factor", &scale_factor, NULL);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
for (i = node->n_properties - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
CRDeclaration *decl = node->properties[i];
|
|
|
|
|
2009-09-20 20:50:42 +00:00
|
|
|
if (strcmp (decl->property->stryng->str, "border-image") == 0)
|
2009-09-20 00:43:49 +00:00
|
|
|
{
|
|
|
|
CRTerm *term = decl->value;
|
2010-12-08 23:05:31 +00:00
|
|
|
CRStyleSheet *base_stylesheet;
|
2009-09-20 20:50:42 +00:00
|
|
|
int borders[4];
|
|
|
|
int n_borders = 0;
|
2009-09-20 00:43:49 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
const char *url;
|
|
|
|
int border_top;
|
|
|
|
int border_right;
|
|
|
|
int border_bottom;
|
|
|
|
int border_left;
|
|
|
|
|
2012-11-22 00:13:59 +00:00
|
|
|
GFile *file;
|
2009-09-20 00:43:49 +00:00
|
|
|
|
2011-03-21 00:49:40 +00:00
|
|
|
/* Support border-image: none; to suppress a previously specified border image */
|
|
|
|
if (term_is_none (term))
|
|
|
|
{
|
|
|
|
if (term->next == NULL)
|
|
|
|
return NULL;
|
|
|
|
else
|
|
|
|
goto next_property;
|
|
|
|
}
|
|
|
|
|
2009-09-20 00:43:49 +00:00
|
|
|
/* First term must be the URL to the image */
|
|
|
|
if (term->type != TERM_URI)
|
|
|
|
goto next_property;
|
|
|
|
|
|
|
|
url = term->content.str->stryng->str;
|
|
|
|
|
|
|
|
term = term->next;
|
|
|
|
|
2009-09-20 20:50:42 +00:00
|
|
|
/* Followed by 0 to 4 numbers or percentages. *Not lengths*. The interpretation
|
|
|
|
* of a number is supposed to be pixels if the image is pixel based, otherwise CSS pixels.
|
|
|
|
*/
|
2009-09-20 00:43:49 +00:00
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
if (term == NULL)
|
|
|
|
break;
|
|
|
|
|
2009-09-20 20:50:42 +00:00
|
|
|
if (term->type != TERM_NUMBER)
|
2009-09-20 00:43:49 +00:00
|
|
|
goto next_property;
|
|
|
|
|
2009-09-20 20:50:42 +00:00
|
|
|
if (term->content.num->type == NUM_GENERIC)
|
|
|
|
{
|
2009-10-01 20:32:38 +00:00
|
|
|
borders[n_borders] = (int)(0.5 + term->content.num->val);
|
2009-09-20 20:50:42 +00:00
|
|
|
n_borders++;
|
|
|
|
}
|
|
|
|
else if (term->content.num->type == NUM_PERCENTAGE)
|
|
|
|
{
|
|
|
|
/* This would be easiest to support if we moved image handling into StBorderImage */
|
|
|
|
g_warning ("Percentages not supported for border-image");
|
|
|
|
goto next_property;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
goto next_property;
|
2009-09-20 00:43:49 +00:00
|
|
|
|
|
|
|
term = term->next;
|
|
|
|
}
|
|
|
|
|
2009-09-20 20:50:42 +00:00
|
|
|
switch (n_borders)
|
2009-09-20 00:43:49 +00:00
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
border_top = border_right = border_bottom = border_left = 0;
|
|
|
|
break;
|
|
|
|
case 1:
|
2009-09-20 20:50:42 +00:00
|
|
|
border_top = border_right = border_bottom = border_left = borders[0];
|
2009-09-20 00:43:49 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2009-09-20 20:50:42 +00:00
|
|
|
border_top = border_bottom = borders[0];
|
|
|
|
border_left = border_right = borders[1];
|
2009-09-20 00:43:49 +00:00
|
|
|
break;
|
|
|
|
case 3:
|
2009-09-20 20:50:42 +00:00
|
|
|
border_top = borders[0];
|
|
|
|
border_left = border_right = borders[1];
|
|
|
|
border_bottom = borders[2];
|
2009-09-20 00:43:49 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
default:
|
2009-09-20 20:50:42 +00:00
|
|
|
border_top = borders[0];
|
|
|
|
border_right = borders[1];
|
|
|
|
border_bottom = borders[2];
|
|
|
|
border_left = borders[3];
|
2009-09-20 00:43:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-12-08 23:05:31 +00:00
|
|
|
if (decl->parent_statement != NULL)
|
|
|
|
base_stylesheet = decl->parent_statement->parent_sheet;
|
|
|
|
else
|
|
|
|
base_stylesheet = NULL;
|
|
|
|
|
2012-11-22 00:13:59 +00:00
|
|
|
file = _st_theme_resolve_url (node->theme, base_stylesheet, url);
|
|
|
|
|
2014-09-19 00:04:00 +00:00
|
|
|
if (file == NULL)
|
2009-09-20 00:43:49 +00:00
|
|
|
goto next_property;
|
|
|
|
|
2014-09-19 00:04:00 +00:00
|
|
|
node->border_image = st_border_image_new (file,
|
2014-03-23 03:43:35 +00:00
|
|
|
border_top, border_right, border_bottom, border_left,
|
|
|
|
scale_factor);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
2014-09-19 00:04:00 +00:00
|
|
|
g_object_unref (file);
|
2009-09-20 00:43:49 +00:00
|
|
|
|
2009-09-20 20:50:42 +00:00
|
|
|
return node->border_image;
|
2009-09-20 00:43:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
next_property:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2009-09-20 17:41:13 +00:00
|
|
|
|
2010-03-11 17:04:08 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_get_horizontal_padding:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
*
|
|
|
|
* Gets the total horizonal padding (left + right padding)
|
|
|
|
*
|
|
|
|
* Return value: the total horizonal padding
|
|
|
|
* in pixels
|
|
|
|
*/
|
|
|
|
double
|
|
|
|
st_theme_node_get_horizontal_padding (StThemeNode *node)
|
|
|
|
{
|
|
|
|
double padding = 0.0;
|
|
|
|
padding += st_theme_node_get_padding (node, ST_SIDE_LEFT);
|
|
|
|
padding += st_theme_node_get_padding (node, ST_SIDE_RIGHT);
|
|
|
|
|
|
|
|
return padding;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_theme_node_get_vertical_padding:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
*
|
|
|
|
* Gets the total vertical padding (top + bottom padding)
|
|
|
|
*
|
|
|
|
* Return value: the total vertical padding
|
|
|
|
* in pixels
|
|
|
|
*/
|
|
|
|
double
|
|
|
|
st_theme_node_get_vertical_padding (StThemeNode *node)
|
|
|
|
{
|
|
|
|
double padding = 0.0;
|
|
|
|
padding += st_theme_node_get_padding (node, ST_SIDE_TOP);
|
|
|
|
padding += st_theme_node_get_padding (node, ST_SIDE_BOTTOM);
|
|
|
|
|
|
|
|
return padding;
|
|
|
|
}
|
|
|
|
|
2014-11-11 14:04:46 +00:00
|
|
|
void
|
|
|
|
_st_theme_node_apply_margins (StThemeNode *node,
|
|
|
|
ClutterActor *actor)
|
|
|
|
{
|
|
|
|
g_return_if_fail (ST_IS_THEME_NODE (node));
|
|
|
|
|
|
|
|
_st_theme_node_ensure_geometry (node);
|
|
|
|
|
|
|
|
// In the case that a CSS margin is not specified, we don't to set a value
|
|
|
|
// of 0 to the clutter actor margin. In this manner it allows to use Clutter
|
|
|
|
// margin values set in the code. However, the margins that are set both in
|
|
|
|
// the code and in the CSS on the same side, the result is unpredictable.
|
|
|
|
if (node->margin_set & 1 << ST_SIDE_LEFT)
|
|
|
|
clutter_actor_set_margin_left (actor, st_theme_node_get_margin(node, ST_SIDE_LEFT));
|
|
|
|
if (node->margin_set & 1 << ST_SIDE_RIGHT)
|
|
|
|
clutter_actor_set_margin_right (actor, st_theme_node_get_margin(node, ST_SIDE_RIGHT));
|
|
|
|
if (node->margin_set & 1 << ST_SIDE_TOP)
|
|
|
|
clutter_actor_set_margin_top (actor, st_theme_node_get_margin(node, ST_SIDE_TOP));
|
|
|
|
if (node->margin_set & 1 << ST_SIDE_BOTTOM)
|
|
|
|
clutter_actor_set_margin_bottom (actor, st_theme_node_get_margin(node, ST_SIDE_BOTTOM));
|
|
|
|
}
|
|
|
|
|
2011-01-13 23:27:24 +00:00
|
|
|
static GetFromTermResult
|
|
|
|
parse_shadow_property (StThemeNode *node,
|
|
|
|
CRDeclaration *decl,
|
|
|
|
ClutterColor *color,
|
|
|
|
gdouble *xoffset,
|
|
|
|
gdouble *yoffset,
|
|
|
|
gdouble *blur,
|
2011-02-14 01:07:14 +00:00
|
|
|
gdouble *spread,
|
|
|
|
gboolean *inset)
|
2010-07-24 14:56:50 +00:00
|
|
|
{
|
2011-01-13 23:27:24 +00:00
|
|
|
GetFromTermResult result;
|
2010-07-24 14:56:50 +00:00
|
|
|
CRTerm *term;
|
|
|
|
int n_offsets = 0;
|
|
|
|
|
|
|
|
/* default values */
|
|
|
|
color->red = 0x0; color->green = 0x0; color->blue = 0x0; color->alpha = 0xff;
|
|
|
|
*xoffset = 0.;
|
|
|
|
*yoffset = 0.;
|
|
|
|
*blur = 0.;
|
|
|
|
*spread = 0.;
|
2011-02-14 01:07:14 +00:00
|
|
|
*inset = FALSE;
|
|
|
|
|
|
|
|
/* The CSS3 draft of the box-shadow property[0] is a lot stricter
|
|
|
|
* regarding the order of terms:
|
|
|
|
* If the 'inset' keyword is specified, it has to be first or last,
|
|
|
|
* and the color may not be mixed with the lengths; while we parse
|
|
|
|
* length values in the correct order, we allow for arbitrary
|
|
|
|
* placement of the color and 'inset' keyword.
|
|
|
|
*
|
|
|
|
* [0] http://www.w3.org/TR/css3-background/#box-shadow
|
|
|
|
*/
|
2010-07-24 14:56:50 +00:00
|
|
|
for (term = decl->value; term; term = term->next)
|
|
|
|
{
|
2013-06-20 21:51:33 +00:00
|
|
|
/* if we found "none", we're all set with the default values */
|
|
|
|
if (term_is_none (term))
|
|
|
|
return VALUE_FOUND;
|
|
|
|
|
2010-07-24 14:56:50 +00:00
|
|
|
if (term->type == TERM_NUMBER)
|
|
|
|
{
|
|
|
|
gdouble value;
|
|
|
|
gdouble multiplier;
|
|
|
|
|
|
|
|
multiplier = (term->unary_op == MINUS_UOP) ? -1. : 1.;
|
|
|
|
result = get_length_from_term (node, term, FALSE, &value);
|
2011-01-13 23:27:24 +00:00
|
|
|
|
|
|
|
if (result == VALUE_INHERIT)
|
|
|
|
{
|
|
|
|
/* we only allow inherit on the line by itself */
|
|
|
|
if (n_offsets > 0)
|
|
|
|
return VALUE_NOT_FOUND;
|
|
|
|
else
|
|
|
|
return VALUE_INHERIT;
|
|
|
|
}
|
|
|
|
else if (result == VALUE_FOUND)
|
2010-07-24 14:56:50 +00:00
|
|
|
{
|
|
|
|
switch (n_offsets++)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
*xoffset = multiplier * value;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
*yoffset = multiplier * value;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (multiplier < 0)
|
|
|
|
g_warning ("Negative blur values are "
|
|
|
|
"not allowed");
|
|
|
|
*blur = value;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (multiplier < 0)
|
|
|
|
g_warning ("Negative spread values are "
|
|
|
|
"not allowed");
|
|
|
|
*spread = value;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2011-02-14 01:07:14 +00:00
|
|
|
else if (term->type == TERM_IDENT &&
|
|
|
|
strcmp (term->content.str->stryng->str, "inset") == 0)
|
|
|
|
{
|
|
|
|
*inset = TRUE;
|
|
|
|
continue;
|
|
|
|
}
|
2010-07-24 14:56:50 +00:00
|
|
|
|
|
|
|
result = get_color_from_term (node, term, color);
|
2011-01-13 23:27:24 +00:00
|
|
|
|
|
|
|
if (result == VALUE_INHERIT)
|
|
|
|
{
|
|
|
|
if (n_offsets > 0)
|
|
|
|
return VALUE_NOT_FOUND;
|
|
|
|
else
|
|
|
|
return VALUE_INHERIT;
|
|
|
|
}
|
|
|
|
else if (result == VALUE_FOUND)
|
2010-07-24 14:56:50 +00:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2011-01-13 23:27:24 +00:00
|
|
|
|
|
|
|
/* The only required terms are the x and y offsets
|
|
|
|
*/
|
|
|
|
if (n_offsets >= 2)
|
|
|
|
return VALUE_FOUND;
|
|
|
|
else
|
|
|
|
return VALUE_NOT_FOUND;
|
2010-07-24 14:56:50 +00:00
|
|
|
}
|
|
|
|
|
2009-11-21 03:19:56 +00:00
|
|
|
/**
|
2011-01-13 23:27:24 +00:00
|
|
|
* st_theme_node_lookup_shadow:
|
2009-11-21 03:19:56 +00:00
|
|
|
* @node: a #StThemeNode
|
2011-01-13 23:27:24 +00:00
|
|
|
* @property_name: The name of the shadow property
|
|
|
|
* @inherit: if %TRUE, if a value is not found for the property on the
|
|
|
|
* node, then it will be looked up on the parent node, and then on the
|
|
|
|
* parent's parent, and so forth. Note that if the property has a
|
|
|
|
* value of 'inherit' it will be inherited even if %FALSE is passed
|
|
|
|
* in for @inherit; this only affects the default behavior for inheritance.
|
|
|
|
* @shadow: (out): location to store the shadow
|
2009-11-21 03:19:56 +00:00
|
|
|
*
|
2011-01-13 23:27:24 +00:00
|
|
|
* If the property is not found, the value in the shadow variable will not
|
|
|
|
* be changed.
|
2009-11-21 03:19:56 +00:00
|
|
|
*
|
2011-01-13 23:27:24 +00:00
|
|
|
* Generically looks up a property containing a set of shadow values. When
|
|
|
|
* specific getters (like st_theme_node_get_box_shadow ()) exist, they
|
|
|
|
* should be used instead. They are cached, so more efficient, and have
|
|
|
|
* handling for shortcut properties and other details of CSS.
|
|
|
|
*
|
|
|
|
* See also st_theme_node_get_shadow(), which provides a simpler API.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if the property was found in the properties for this
|
|
|
|
* theme node (or in the properties of parent nodes when inheriting.)
|
2009-11-21 03:19:56 +00:00
|
|
|
*/
|
2011-01-13 23:27:24 +00:00
|
|
|
gboolean
|
|
|
|
st_theme_node_lookup_shadow (StThemeNode *node,
|
|
|
|
const char *property_name,
|
|
|
|
gboolean inherit,
|
|
|
|
StShadow **shadow)
|
2009-11-21 03:19:56 +00:00
|
|
|
{
|
2011-01-13 23:27:24 +00:00
|
|
|
ClutterColor color = { 0., };
|
|
|
|
gdouble xoffset = 0.;
|
|
|
|
gdouble yoffset = 0.;
|
|
|
|
gdouble blur = 0.;
|
|
|
|
gdouble spread = 0.;
|
2011-02-14 01:07:14 +00:00
|
|
|
gboolean inset = FALSE;
|
2009-11-21 03:19:56 +00:00
|
|
|
|
2011-01-13 23:27:24 +00:00
|
|
|
int i;
|
2009-11-21 03:19:56 +00:00
|
|
|
|
|
|
|
ensure_properties (node);
|
|
|
|
|
|
|
|
for (i = node->n_properties - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
CRDeclaration *decl = node->properties[i];
|
|
|
|
|
2011-01-13 23:27:24 +00:00
|
|
|
if (strcmp (decl->property->stryng->str, property_name) == 0)
|
2009-11-21 03:19:56 +00:00
|
|
|
{
|
2011-01-13 23:27:24 +00:00
|
|
|
GetFromTermResult result = parse_shadow_property (node,
|
|
|
|
decl,
|
|
|
|
&color,
|
|
|
|
&xoffset,
|
|
|
|
&yoffset,
|
|
|
|
&blur,
|
2011-02-14 01:07:14 +00:00
|
|
|
&spread,
|
|
|
|
&inset);
|
2011-01-13 23:27:24 +00:00
|
|
|
if (result == VALUE_FOUND)
|
|
|
|
{
|
2011-02-14 01:07:14 +00:00
|
|
|
*shadow = st_shadow_new (&color,
|
|
|
|
xoffset, yoffset,
|
|
|
|
blur, spread,
|
|
|
|
inset);
|
2011-01-13 23:27:24 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else if (result == VALUE_INHERIT)
|
|
|
|
{
|
|
|
|
if (node->parent_node)
|
|
|
|
return st_theme_node_lookup_shadow (node->parent_node,
|
|
|
|
property_name,
|
|
|
|
inherit,
|
|
|
|
shadow);
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-11-21 03:19:56 +00:00
|
|
|
|
2011-01-13 23:27:24 +00:00
|
|
|
if (inherit && node->parent_node)
|
|
|
|
return st_theme_node_lookup_shadow (node->parent_node,
|
|
|
|
property_name,
|
|
|
|
inherit,
|
|
|
|
shadow);
|
2009-11-21 03:19:56 +00:00
|
|
|
|
2011-01-13 23:27:24 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2009-11-21 03:19:56 +00:00
|
|
|
|
2011-01-13 23:27:24 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_get_shadow:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @property_name: The name of the shadow property
|
|
|
|
*
|
|
|
|
* Generically looks up a property containing a set of shadow values. When
|
|
|
|
* specific getters (like st_theme_node_get_box_shadow()) exist, they
|
|
|
|
* should be used instead. They are cached, so more efficient, and have
|
|
|
|
* handling for shortcut properties and other details of CSS.
|
|
|
|
*
|
|
|
|
* Like st_theme_get_length(), this does not print a warning if the property is
|
|
|
|
* not found; it just returns %NULL
|
|
|
|
*
|
|
|
|
* See also st_theme_node_lookup_shadow (), which provides more options.
|
|
|
|
*
|
|
|
|
* Return value: (transfer full): the shadow, or %NULL if the property was not found.
|
|
|
|
*/
|
|
|
|
StShadow *
|
|
|
|
st_theme_node_get_shadow (StThemeNode *node,
|
|
|
|
const char *property_name)
|
|
|
|
{
|
|
|
|
StShadow *shadow;
|
|
|
|
|
|
|
|
if (st_theme_node_lookup_shadow (node, property_name, FALSE, &shadow))
|
|
|
|
return shadow;
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_theme_node_get_box_shadow:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
*
|
|
|
|
* Gets the value for the box-shadow style property
|
|
|
|
*
|
|
|
|
* Return value: (transfer none): the node's shadow, or %NULL
|
|
|
|
* if node has no shadow
|
|
|
|
*/
|
|
|
|
StShadow *
|
|
|
|
st_theme_node_get_box_shadow (StThemeNode *node)
|
|
|
|
{
|
|
|
|
StShadow *shadow;
|
|
|
|
|
|
|
|
if (node->box_shadow_computed)
|
|
|
|
return node->box_shadow;
|
|
|
|
|
|
|
|
node->box_shadow = NULL;
|
|
|
|
node->box_shadow_computed = TRUE;
|
|
|
|
|
|
|
|
if (st_theme_node_lookup_shadow (node,
|
|
|
|
"box-shadow",
|
|
|
|
FALSE,
|
|
|
|
&shadow))
|
|
|
|
{
|
|
|
|
node->box_shadow = shadow;
|
|
|
|
|
|
|
|
return node->box_shadow;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_theme_node_get_background_image_shadow:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
*
|
|
|
|
* Gets the value for the -st-background-image-shadow style property
|
|
|
|
*
|
|
|
|
* Return value: (transfer none): the node's background image shadow, or %NULL
|
|
|
|
* if node has no such shadow
|
|
|
|
*/
|
|
|
|
StShadow *
|
|
|
|
st_theme_node_get_background_image_shadow (StThemeNode *node)
|
|
|
|
{
|
|
|
|
StShadow *shadow;
|
|
|
|
|
|
|
|
if (node->background_image_shadow_computed)
|
|
|
|
return node->background_image_shadow;
|
|
|
|
|
|
|
|
node->background_image_shadow = NULL;
|
|
|
|
node->background_image_shadow_computed = TRUE;
|
|
|
|
|
|
|
|
if (st_theme_node_lookup_shadow (node,
|
|
|
|
"-st-background-image-shadow",
|
|
|
|
FALSE,
|
|
|
|
&shadow))
|
|
|
|
{
|
2011-02-14 01:07:14 +00:00
|
|
|
if (shadow->inset)
|
|
|
|
{
|
|
|
|
g_warning ("The -st-background-image-shadow property does not "
|
|
|
|
"support inset shadows");
|
|
|
|
st_shadow_unref (shadow);
|
|
|
|
shadow = NULL;
|
|
|
|
}
|
|
|
|
|
2011-01-13 23:27:24 +00:00
|
|
|
node->background_image_shadow = shadow;
|
|
|
|
|
|
|
|
return node->background_image_shadow;
|
2009-11-21 03:19:56 +00:00
|
|
|
}
|
2011-01-13 23:27:24 +00:00
|
|
|
|
2009-11-21 03:19:56 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-07-24 14:56:50 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_get_text_shadow:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
*
|
|
|
|
* Gets the value for the text-shadow style property
|
|
|
|
*
|
|
|
|
* Return value: (transfer none): the node's text-shadow, or %NULL
|
|
|
|
* if node has no text-shadow
|
|
|
|
*/
|
|
|
|
StShadow *
|
|
|
|
st_theme_node_get_text_shadow (StThemeNode *node)
|
|
|
|
{
|
|
|
|
StShadow *result = NULL;
|
|
|
|
|
|
|
|
if (node->text_shadow_computed)
|
|
|
|
return node->text_shadow;
|
|
|
|
|
|
|
|
ensure_properties (node);
|
|
|
|
|
2011-01-13 23:27:24 +00:00
|
|
|
if (!st_theme_node_lookup_shadow (node,
|
|
|
|
"text-shadow",
|
|
|
|
FALSE,
|
|
|
|
&result))
|
2010-07-24 14:56:50 +00:00
|
|
|
{
|
2011-01-13 23:27:24 +00:00
|
|
|
if (node->parent_node)
|
2010-07-24 14:56:50 +00:00
|
|
|
{
|
2011-01-13 23:27:24 +00:00
|
|
|
result = st_theme_node_get_text_shadow (node->parent_node);
|
|
|
|
if (result)
|
|
|
|
st_shadow_ref (result);
|
2010-07-24 14:56:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-14 01:07:14 +00:00
|
|
|
if (result && result->inset)
|
|
|
|
{
|
|
|
|
g_warning ("The text-shadow property does not support inset shadows");
|
|
|
|
st_shadow_unref (result);
|
|
|
|
result = NULL;
|
|
|
|
}
|
|
|
|
|
2010-07-24 14:56:50 +00:00
|
|
|
node->text_shadow = result;
|
|
|
|
node->text_shadow_computed = TRUE;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2010-11-01 02:06:48 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_get_icon_colors:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
*
|
|
|
|
* Gets the colors that should be used for colorizing symbolic icons according
|
|
|
|
* the style of this node.
|
|
|
|
*
|
|
|
|
* Return value: (transfer none): the icon colors to use for this theme node
|
|
|
|
*/
|
|
|
|
StIconColors *
|
|
|
|
st_theme_node_get_icon_colors (StThemeNode *node)
|
|
|
|
{
|
|
|
|
/* Foreground here will always be the same as st_theme_node_get_foreground_color(),
|
|
|
|
* but there's a loss of symmetry and little efficiency win if we try to exploit
|
|
|
|
* that. */
|
|
|
|
|
|
|
|
enum {
|
|
|
|
FOREGROUND = 1 << 0,
|
|
|
|
WARNING = 1 << 1,
|
|
|
|
ERROR = 1 << 2,
|
|
|
|
SUCCESS = 1 << 3
|
|
|
|
};
|
|
|
|
|
|
|
|
gboolean shared_with_parent;
|
|
|
|
int i;
|
|
|
|
ClutterColor color = { 0, };
|
|
|
|
|
|
|
|
guint still_need = FOREGROUND | WARNING | ERROR | SUCCESS;
|
|
|
|
|
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
|
|
|
|
|
|
|
|
if (node->icon_colors)
|
|
|
|
return node->icon_colors;
|
|
|
|
|
|
|
|
if (node->parent_node)
|
|
|
|
{
|
|
|
|
node->icon_colors = st_theme_node_get_icon_colors (node->parent_node);
|
|
|
|
shared_with_parent = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
node->icon_colors = st_icon_colors_new ();
|
|
|
|
node->icon_colors->foreground = BLACK_COLOR;
|
|
|
|
node->icon_colors->warning = DEFAULT_WARNING_COLOR;
|
|
|
|
node->icon_colors->error = DEFAULT_ERROR_COLOR;
|
|
|
|
node->icon_colors->success = DEFAULT_SUCCESS_COLOR;
|
|
|
|
shared_with_parent = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ensure_properties (node);
|
|
|
|
|
|
|
|
for (i = node->n_properties - 1; i >= 0 && still_need != 0; i--)
|
|
|
|
{
|
|
|
|
CRDeclaration *decl = node->properties[i];
|
|
|
|
GetFromTermResult result = VALUE_NOT_FOUND;
|
|
|
|
guint found = 0;
|
|
|
|
|
|
|
|
if ((still_need & FOREGROUND) != 0 &&
|
|
|
|
strcmp (decl->property->stryng->str, "color") == 0)
|
|
|
|
{
|
|
|
|
found = FOREGROUND;
|
|
|
|
result = get_color_from_term (node, decl->value, &color);
|
|
|
|
}
|
|
|
|
else if ((still_need & WARNING) != 0 &&
|
|
|
|
strcmp (decl->property->stryng->str, "warning-color") == 0)
|
|
|
|
{
|
|
|
|
found = WARNING;
|
|
|
|
result = get_color_from_term (node, decl->value, &color);
|
|
|
|
}
|
|
|
|
else if ((still_need & ERROR) != 0 &&
|
|
|
|
strcmp (decl->property->stryng->str, "error-color") == 0)
|
|
|
|
{
|
|
|
|
found = ERROR;
|
|
|
|
result = get_color_from_term (node, decl->value, &color);
|
|
|
|
}
|
|
|
|
else if ((still_need & SUCCESS) != 0 &&
|
|
|
|
strcmp (decl->property->stryng->str, "success-color") == 0)
|
|
|
|
{
|
|
|
|
found = SUCCESS;
|
|
|
|
result = get_color_from_term (node, decl->value, &color);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result == VALUE_INHERIT)
|
|
|
|
{
|
|
|
|
still_need &= ~found;
|
|
|
|
}
|
|
|
|
else if (result == VALUE_FOUND)
|
|
|
|
{
|
|
|
|
still_need &= ~found;
|
|
|
|
if (shared_with_parent)
|
|
|
|
{
|
|
|
|
node->icon_colors = st_icon_colors_copy (node->icon_colors);
|
|
|
|
shared_with_parent = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (found)
|
|
|
|
{
|
|
|
|
case FOREGROUND:
|
|
|
|
node->icon_colors->foreground = color;
|
|
|
|
break;
|
|
|
|
case WARNING:
|
|
|
|
node->icon_colors->warning = color;
|
|
|
|
break;
|
|
|
|
case ERROR:
|
|
|
|
node->icon_colors->error = color;
|
|
|
|
break;
|
|
|
|
case SUCCESS:
|
|
|
|
node->icon_colors->success = color;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shared_with_parent)
|
|
|
|
st_icon_colors_ref (node->icon_colors);
|
|
|
|
|
|
|
|
return node->icon_colors;
|
|
|
|
}
|
|
|
|
|
2009-09-20 17:41:13 +00:00
|
|
|
static float
|
|
|
|
get_width_inc (StThemeNode *node)
|
|
|
|
{
|
2009-10-01 20:32:38 +00:00
|
|
|
return ((int)(0.5 + node->border_width[ST_SIDE_LEFT]) + node->padding[ST_SIDE_LEFT] +
|
|
|
|
(int)(0.5 + node->border_width[ST_SIDE_RIGHT]) + node->padding[ST_SIDE_RIGHT]);
|
2009-09-20 17:41:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static float
|
|
|
|
get_height_inc (StThemeNode *node)
|
|
|
|
{
|
2009-10-01 20:32:38 +00:00
|
|
|
return ((int)(0.5 + node->border_width[ST_SIDE_TOP]) + node->padding[ST_SIDE_TOP] +
|
|
|
|
(int)(0.5 + node->border_width[ST_SIDE_BOTTOM]) + node->padding[ST_SIDE_BOTTOM]);
|
2009-09-20 17:41:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_theme_node_adjust_for_height:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @for_height: (inout): the "for height" to adjust
|
|
|
|
*
|
|
|
|
* Adjusts a "for height" passed to clutter_actor_get_preferred_width() to
|
|
|
|
* account for borders and padding. This is a convenience function meant
|
|
|
|
* to be called from a get_preferred_width() method of a #ClutterActor
|
|
|
|
* subclass. The value after adjustment is the height available for the actor's
|
|
|
|
* content.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
st_theme_node_adjust_for_height (StThemeNode *node,
|
|
|
|
float *for_height)
|
|
|
|
{
|
|
|
|
g_return_if_fail (ST_IS_THEME_NODE (node));
|
|
|
|
g_return_if_fail (for_height != NULL);
|
|
|
|
|
|
|
|
if (*for_height >= 0)
|
|
|
|
{
|
|
|
|
float height_inc = get_height_inc (node);
|
|
|
|
*for_height = MAX (0, *for_height - height_inc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_theme_node_adjust_preferred_width:
|
|
|
|
* @node: a #StThemeNode
|
2014-05-28 19:54:02 +00:00
|
|
|
* @min_width_p: (inout) (nullable): the minimum width to adjust
|
2010-09-15 00:56:34 +00:00
|
|
|
* @natural_width_p: (inout): the natural width to adjust
|
2009-09-20 17:41:13 +00:00
|
|
|
*
|
|
|
|
* Adjusts the minimum and natural width computed for an actor by
|
2010-02-12 18:58:24 +00:00
|
|
|
* adding on the necessary space for borders and padding and taking
|
|
|
|
* into account any minimum or maximum width. This is a convenience
|
|
|
|
* function meant to be called from the get_preferred_width() method
|
|
|
|
* of a #ClutterActor subclass
|
2009-09-20 17:41:13 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
st_theme_node_adjust_preferred_width (StThemeNode *node,
|
|
|
|
float *min_width_p,
|
|
|
|
float *natural_width_p)
|
|
|
|
{
|
|
|
|
float width_inc;
|
|
|
|
|
|
|
|
g_return_if_fail (ST_IS_THEME_NODE (node));
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_geometry (node);
|
2009-09-20 17:41:13 +00:00
|
|
|
|
|
|
|
width_inc = get_width_inc (node);
|
|
|
|
|
|
|
|
if (min_width_p)
|
2009-10-17 00:05:30 +00:00
|
|
|
{
|
|
|
|
if (node->min_width != -1)
|
|
|
|
*min_width_p = node->min_width;
|
|
|
|
*min_width_p += width_inc;
|
|
|
|
}
|
|
|
|
|
2009-09-20 17:41:13 +00:00
|
|
|
if (natural_width_p)
|
2009-10-17 00:05:30 +00:00
|
|
|
{
|
|
|
|
if (node->width != -1)
|
2012-11-30 16:03:45 +00:00
|
|
|
*natural_width_p = MAX (*natural_width_p, node->width);
|
2010-02-12 18:58:24 +00:00
|
|
|
if (node->max_width != -1)
|
|
|
|
*natural_width_p = MIN (*natural_width_p, node->max_width);
|
2009-10-17 00:05:30 +00:00
|
|
|
*natural_width_p += width_inc;
|
|
|
|
}
|
2009-09-20 17:41:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_theme_node_adjust_for_width:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @for_width: (inout): the "for width" to adjust
|
|
|
|
*
|
|
|
|
* Adjusts a "for width" passed to clutter_actor_get_preferred_height() to
|
|
|
|
* account for borders and padding. This is a convenience function meant
|
|
|
|
* to be called from a get_preferred_height() method of a #ClutterActor
|
2010-09-15 00:56:34 +00:00
|
|
|
* subclass. The value after adjustment is the width available for the actor's
|
2009-09-20 17:41:13 +00:00
|
|
|
* content.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
st_theme_node_adjust_for_width (StThemeNode *node,
|
|
|
|
float *for_width)
|
|
|
|
{
|
|
|
|
g_return_if_fail (ST_IS_THEME_NODE (node));
|
|
|
|
g_return_if_fail (for_width != NULL);
|
|
|
|
|
|
|
|
if (*for_width >= 0)
|
|
|
|
{
|
|
|
|
float width_inc = get_width_inc (node);
|
|
|
|
*for_width = MAX (0, *for_width - width_inc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_theme_node_adjust_preferred_height:
|
|
|
|
* @node: a #StThemeNode
|
2014-05-28 19:54:02 +00:00
|
|
|
* @min_height_p: (inout) (nullable): the minimum height to adjust
|
2010-09-15 00:56:34 +00:00
|
|
|
* @natural_height_p: (inout): the natural height to adjust
|
2009-09-20 17:41:13 +00:00
|
|
|
*
|
|
|
|
* Adjusts the minimum and natural height computed for an actor by
|
2010-02-12 18:58:24 +00:00
|
|
|
* adding on the necessary space for borders and padding and taking
|
|
|
|
* into account any minimum or maximum height. This is a convenience
|
|
|
|
* function meant to be called from the get_preferred_height() method
|
|
|
|
* of a #ClutterActor subclass
|
2009-09-20 17:41:13 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
st_theme_node_adjust_preferred_height (StThemeNode *node,
|
|
|
|
float *min_height_p,
|
|
|
|
float *natural_height_p)
|
|
|
|
{
|
|
|
|
float height_inc;
|
|
|
|
|
|
|
|
g_return_if_fail (ST_IS_THEME_NODE (node));
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_geometry (node);
|
2009-09-20 17:41:13 +00:00
|
|
|
|
|
|
|
height_inc = get_height_inc (node);
|
|
|
|
|
|
|
|
if (min_height_p)
|
2009-10-17 00:05:30 +00:00
|
|
|
{
|
|
|
|
if (node->min_height != -1)
|
|
|
|
*min_height_p = node->min_height;
|
|
|
|
*min_height_p += height_inc;
|
|
|
|
}
|
2009-09-20 17:41:13 +00:00
|
|
|
if (natural_height_p)
|
2009-10-17 00:05:30 +00:00
|
|
|
{
|
|
|
|
if (node->height != -1)
|
2012-11-30 16:03:45 +00:00
|
|
|
*natural_height_p = MAX (*natural_height_p, node->height);
|
2010-02-12 18:58:24 +00:00
|
|
|
if (node->max_height != -1)
|
|
|
|
*natural_height_p = MIN (*natural_height_p, node->max_height);
|
2009-10-17 00:05:30 +00:00
|
|
|
*natural_height_p += height_inc;
|
|
|
|
}
|
2009-09-20 17:41:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* st_theme_node_get_content_box:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @allocation: the box allocated to a #ClutterAlctor
|
2011-02-12 20:22:33 +00:00
|
|
|
* @content_box: (out caller-allocates): computed box occupied by the actor's content
|
2009-09-20 17:41:13 +00:00
|
|
|
*
|
|
|
|
* Gets the box within an actor's allocation that contents the content
|
|
|
|
* of an actor (excluding borders and padding). This is a convenience function
|
|
|
|
* meant to be used from the allocate() or paint() methods of a #ClutterActor
|
|
|
|
* subclass.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
st_theme_node_get_content_box (StThemeNode *node,
|
|
|
|
const ClutterActorBox *allocation,
|
|
|
|
ClutterActorBox *content_box)
|
|
|
|
{
|
2009-11-04 20:48:26 +00:00
|
|
|
double noncontent_left, noncontent_top, noncontent_right, noncontent_bottom;
|
|
|
|
double avail_width, avail_height, content_width, content_height;
|
|
|
|
|
2009-09-20 17:41:13 +00:00
|
|
|
g_return_if_fail (ST_IS_THEME_NODE (node));
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_geometry (node);
|
2009-09-20 17:41:13 +00:00
|
|
|
|
2009-11-04 20:48:26 +00:00
|
|
|
avail_width = allocation->x2 - allocation->x1;
|
|
|
|
avail_height = allocation->y2 - allocation->y1;
|
|
|
|
|
|
|
|
noncontent_left = node->border_width[ST_SIDE_LEFT] + node->padding[ST_SIDE_LEFT];
|
|
|
|
noncontent_top = node->border_width[ST_SIDE_TOP] + node->padding[ST_SIDE_TOP];
|
|
|
|
noncontent_right = node->border_width[ST_SIDE_RIGHT] + node->padding[ST_SIDE_RIGHT];
|
|
|
|
noncontent_bottom = node->border_width[ST_SIDE_BOTTOM] + node->padding[ST_SIDE_BOTTOM];
|
|
|
|
|
|
|
|
content_box->x1 = (int)(0.5 + noncontent_left);
|
|
|
|
content_box->y1 = (int)(0.5 + noncontent_top);
|
|
|
|
|
|
|
|
content_width = avail_width - noncontent_left - noncontent_right;
|
|
|
|
if (content_width < 0)
|
|
|
|
content_width = 0;
|
|
|
|
content_height = avail_height - noncontent_top - noncontent_bottom;
|
|
|
|
if (content_height < 0)
|
|
|
|
content_height = 0;
|
|
|
|
|
|
|
|
content_box->x2 = (int)(0.5 + content_box->x1 + content_width);
|
|
|
|
content_box->y2 = (int)(0.5 + content_box->y1 + content_height);
|
2009-09-20 17:41:13 +00:00
|
|
|
}
|
|
|
|
|
2011-02-04 00:45:16 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_get_background_paint_box:
|
|
|
|
* @node: a #StThemeNode
|
|
|
|
* @allocation: the box allocated to a #ClutterActor
|
2011-02-12 20:22:33 +00:00
|
|
|
* @paint_box: (out caller-allocates): computed box occupied when painting the actor's background
|
2011-02-04 00:45:16 +00:00
|
|
|
*
|
|
|
|
* Gets the box used to paint the actor's background, including the area
|
|
|
|
* occupied by properties which paint outside the actor's assigned allocation.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
st_theme_node_get_background_paint_box (StThemeNode *node,
|
|
|
|
const ClutterActorBox *actor_box,
|
|
|
|
ClutterActorBox *paint_box)
|
|
|
|
{
|
|
|
|
StShadow *background_image_shadow;
|
|
|
|
ClutterActorBox shadow_box;
|
|
|
|
|
|
|
|
g_return_if_fail (ST_IS_THEME_NODE (node));
|
|
|
|
g_return_if_fail (actor_box != NULL);
|
|
|
|
g_return_if_fail (paint_box != NULL);
|
|
|
|
|
|
|
|
background_image_shadow = st_theme_node_get_background_image_shadow (node);
|
|
|
|
|
|
|
|
*paint_box = *actor_box;
|
|
|
|
|
|
|
|
if (!background_image_shadow)
|
|
|
|
return;
|
|
|
|
|
|
|
|
st_shadow_get_box (background_image_shadow, actor_box, &shadow_box);
|
|
|
|
|
|
|
|
paint_box->x1 = MIN (paint_box->x1, shadow_box.x1);
|
|
|
|
paint_box->x2 = MAX (paint_box->x2, shadow_box.x2);
|
|
|
|
paint_box->y1 = MIN (paint_box->y1, shadow_box.y1);
|
|
|
|
paint_box->y2 = MAX (paint_box->y2, shadow_box.y2);
|
|
|
|
}
|
|
|
|
|
2010-06-04 13:21:59 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_get_paint_box:
|
|
|
|
* @node: a #StThemeNode
|
2010-05-26 20:50:24 +00:00
|
|
|
* @allocation: the box allocated to a #ClutterActor
|
2011-02-12 20:22:33 +00:00
|
|
|
* @paint_box: (out caller-allocates): computed box occupied when painting the actor
|
2010-06-04 13:21:59 +00:00
|
|
|
*
|
2010-05-26 20:50:24 +00:00
|
|
|
* Gets the box used to paint the actor, including the area occupied
|
|
|
|
* by properties which paint outside the actor's assigned allocation.
|
|
|
|
* When painting @node to an offscreen buffer, this function can be
|
|
|
|
* used to determine the necessary size of the buffer.
|
2010-06-04 13:21:59 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
st_theme_node_get_paint_box (StThemeNode *node,
|
|
|
|
const ClutterActorBox *actor_box,
|
|
|
|
ClutterActorBox *paint_box)
|
|
|
|
{
|
2011-01-13 23:27:24 +00:00
|
|
|
StShadow *box_shadow;
|
2010-05-26 20:50:24 +00:00
|
|
|
ClutterActorBox shadow_box;
|
|
|
|
int outline_width;
|
2010-06-04 13:21:59 +00:00
|
|
|
|
|
|
|
g_return_if_fail (ST_IS_THEME_NODE (node));
|
|
|
|
g_return_if_fail (actor_box != NULL);
|
|
|
|
g_return_if_fail (paint_box != NULL);
|
|
|
|
|
2011-01-13 23:27:24 +00:00
|
|
|
box_shadow = st_theme_node_get_box_shadow (node);
|
2010-05-26 20:50:24 +00:00
|
|
|
outline_width = st_theme_node_get_outline_width (node);
|
2011-01-13 23:27:24 +00:00
|
|
|
|
2011-02-04 00:45:16 +00:00
|
|
|
st_theme_node_get_background_paint_box (node, actor_box, paint_box);
|
2011-01-13 23:27:24 +00:00
|
|
|
|
2011-02-04 00:45:16 +00:00
|
|
|
if (!box_shadow && !outline_width)
|
2011-01-13 23:27:24 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
paint_box->x1 -= outline_width;
|
|
|
|
paint_box->x2 += outline_width;
|
|
|
|
paint_box->y1 -= outline_width;
|
|
|
|
paint_box->y2 += outline_width;
|
|
|
|
|
|
|
|
if (box_shadow)
|
2010-06-04 13:21:59 +00:00
|
|
|
{
|
2011-01-13 23:27:24 +00:00
|
|
|
st_shadow_get_box (box_shadow, actor_box, &shadow_box);
|
|
|
|
|
|
|
|
paint_box->x1 = MIN (paint_box->x1, shadow_box.x1);
|
|
|
|
paint_box->x2 = MAX (paint_box->x2, shadow_box.x2);
|
|
|
|
paint_box->y1 = MIN (paint_box->y1, shadow_box.y1);
|
|
|
|
paint_box->y2 = MAX (paint_box->y2, shadow_box.y2);
|
|
|
|
}
|
2010-06-04 13:21:59 +00:00
|
|
|
}
|
|
|
|
|
2009-09-20 17:41:13 +00:00
|
|
|
/**
|
|
|
|
* st_theme_node_geometry_equal:
|
|
|
|
* @node: a #StThemeNode
|
2010-03-23 15:28:25 +00:00
|
|
|
* @other: a different #StThemeNode
|
2009-09-20 17:41:13 +00:00
|
|
|
*
|
|
|
|
* Tests if two theme nodes have the same borders and padding; this can be
|
|
|
|
* used to optimize having to relayout when the style applied to a Clutter
|
|
|
|
* actor changes colors without changing the geometry.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
st_theme_node_geometry_equal (StThemeNode *node,
|
|
|
|
StThemeNode *other)
|
|
|
|
{
|
|
|
|
StSide side;
|
|
|
|
|
2010-08-26 18:10:46 +00:00
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (node), FALSE);
|
2012-11-15 15:16:12 +00:00
|
|
|
|
|
|
|
if (node == other)
|
|
|
|
return TRUE;
|
|
|
|
|
2010-08-26 18:10:46 +00:00
|
|
|
g_return_val_if_fail (ST_IS_THEME_NODE (other), FALSE);
|
|
|
|
|
2010-02-08 18:40:25 +00:00
|
|
|
_st_theme_node_ensure_geometry (node);
|
|
|
|
_st_theme_node_ensure_geometry (other);
|
2009-09-20 17:41:13 +00:00
|
|
|
|
|
|
|
for (side = ST_SIDE_TOP; side <= ST_SIDE_LEFT; side++)
|
|
|
|
{
|
|
|
|
if (node->border_width[side] != other->border_width[side])
|
|
|
|
return FALSE;
|
|
|
|
if (node->padding[side] != other->padding[side])
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2009-10-17 00:05:30 +00:00
|
|
|
if (node->width != other->width || node->height != other->height)
|
|
|
|
return FALSE;
|
|
|
|
if (node->min_width != other->min_width || node->min_height != other->min_height)
|
|
|
|
return FALSE;
|
2010-02-12 18:58:24 +00:00
|
|
|
if (node->max_width != other->max_width || node->max_height != other->max_height)
|
|
|
|
return FALSE;
|
2009-10-17 00:05:30 +00:00
|
|
|
|
2009-09-20 17:41:13 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
2010-08-26 18:10:46 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* st_theme_node_paint_equal:
|
2014-05-28 19:54:02 +00:00
|
|
|
* @node: (nullable): a #StThemeNode
|
|
|
|
* @other: (nullable): a different #StThemeNode
|
2010-08-26 18:10:46 +00:00
|
|
|
*
|
|
|
|
* Check if st_theme_node_paint() will paint identically for @node as it does
|
|
|
|
* for @other. Note that in some cases this function may return %TRUE even
|
|
|
|
* if there is no visible difference in the painting.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if the two theme nodes paint identically. %FALSE if the
|
|
|
|
* two nodes potentially paint differently.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
st_theme_node_paint_equal (StThemeNode *node,
|
|
|
|
StThemeNode *other)
|
|
|
|
{
|
|
|
|
StBorderImage *border_image, *other_border_image;
|
|
|
|
StShadow *shadow, *other_shadow;
|
|
|
|
int i;
|
|
|
|
|
2013-04-05 03:06:29 +00:00
|
|
|
/* Make sure NULL != NULL */
|
|
|
|
if (node == NULL || other == NULL)
|
2013-05-07 06:51:02 +00:00
|
|
|
return FALSE;
|
2012-11-15 15:16:12 +00:00
|
|
|
|
|
|
|
if (node == other)
|
|
|
|
return TRUE;
|
|
|
|
|
2010-08-26 18:10:46 +00:00
|
|
|
_st_theme_node_ensure_background (node);
|
|
|
|
_st_theme_node_ensure_background (other);
|
|
|
|
|
|
|
|
if (!clutter_color_equal (&node->background_color, &other->background_color))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (node->background_gradient_type != other->background_gradient_type)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (node->background_gradient_type != ST_GRADIENT_NONE &&
|
|
|
|
!clutter_color_equal (&node->background_gradient_end, &other->background_gradient_end))
|
|
|
|
return FALSE;
|
|
|
|
|
2014-09-19 00:04:00 +00:00
|
|
|
if ((node->background_image != NULL) &&
|
|
|
|
(other->background_image != NULL) &&
|
|
|
|
!g_file_equal (node->background_image, other->background_image))
|
2010-08-26 18:10:46 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
_st_theme_node_ensure_geometry (node);
|
|
|
|
_st_theme_node_ensure_geometry (other);
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
if (node->border_width[i] != other->border_width[i])
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (node->border_width[i] > 0 &&
|
|
|
|
!clutter_color_equal (&node->border_color[i], &other->border_color[i]))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (node->border_radius[i] != other->border_radius[i])
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->outline_width != other->outline_width)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (node->outline_width > 0 &&
|
|
|
|
!clutter_color_equal (&node->outline_color, &other->outline_color))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
border_image = st_theme_node_get_border_image (node);
|
|
|
|
other_border_image = st_theme_node_get_border_image (other);
|
|
|
|
|
|
|
|
if ((border_image == NULL) != (other_border_image == NULL))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (border_image != NULL && !st_border_image_equal (border_image, other_border_image))
|
|
|
|
return FALSE;
|
|
|
|
|
2011-01-13 23:27:24 +00:00
|
|
|
shadow = st_theme_node_get_box_shadow (node);
|
|
|
|
other_shadow = st_theme_node_get_box_shadow (other);
|
|
|
|
|
|
|
|
if ((shadow == NULL) != (other_shadow == NULL))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (shadow != NULL && !st_shadow_equal (shadow, other_shadow))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
shadow = st_theme_node_get_background_image_shadow (node);
|
|
|
|
other_shadow = st_theme_node_get_background_image_shadow (other);
|
2010-08-26 18:10:46 +00:00
|
|
|
|
|
|
|
if ((shadow == NULL) != (other_shadow == NULL))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (shadow != NULL && !st_shadow_equal (shadow, other_shadow))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
2013-04-05 01:43:42 +00:00
|
|
|
|
|
|
|
gchar *
|
|
|
|
st_theme_node_to_string (StThemeNode *node)
|
|
|
|
{
|
|
|
|
GString *desc;
|
|
|
|
gchar **it;
|
|
|
|
|
|
|
|
if (!node)
|
|
|
|
return g_strdup ("[null]");
|
|
|
|
|
|
|
|
desc = g_string_new (NULL);
|
|
|
|
g_string_append_printf (desc,
|
|
|
|
"[%p %s#%s",
|
|
|
|
node,
|
|
|
|
g_type_name (node->element_type),
|
|
|
|
node->element_id);
|
|
|
|
|
|
|
|
for (it = node->element_classes; it && *it; it++)
|
|
|
|
g_string_append_printf (desc, ".%s", *it);
|
|
|
|
|
|
|
|
for (it = node->pseudo_classes; it && *it; it++)
|
|
|
|
g_string_append_printf (desc, ":%s", *it);
|
|
|
|
|
|
|
|
g_string_append_c (desc, ']');
|
|
|
|
|
|
|
|
return g_string_free (desc, FALSE);
|
|
|
|
}
|