gtkcsscustomproperty.c 10.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * Copyright © 2011 Red Hat Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 17 18 19 20 21 22 23 24 25
 *
 * Authors: Benjamin Otte <otte@gnome.org>
 */

#include "config.h"

#include "gtkcsscustompropertyprivate.h"

#include <string.h>

26
#include "gtkcssstylefuncsprivate.h"
27
#include "gtkcsstypedvalueprivate.h"
28
#include "gtkstylepropertiesprivate.h"
29 30
#include "gtkthemingengine.h"

31 32
#include "deprecated/gtksymboliccolor.h"

33 34
G_DEFINE_TYPE (GtkCssCustomProperty, _gtk_css_custom_property, GTK_TYPE_CSS_STYLE_PROPERTY)

35 36 37
static GType
gtk_css_custom_property_get_specified_type (GParamSpec *pspec)
{
Benjamin Otte's avatar
Benjamin Otte committed
38 39
  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;

40 41 42 43 44
  if (pspec->value_type == GDK_TYPE_RGBA ||
      pspec->value_type == GDK_TYPE_COLOR)
    return GTK_TYPE_SYMBOLIC_COLOR;
  else
    return pspec->value_type;
Benjamin Otte's avatar
Benjamin Otte committed
45 46

  G_GNUC_END_IGNORE_DEPRECATIONS;
47 48
}

49
static GtkCssValue *
50
gtk_css_custom_property_parse_value (GtkStyleProperty *property,
51
                                     GtkCssParser     *parser)
52
{
53
  GtkCssCustomProperty *custom = GTK_CSS_CUSTOM_PROPERTY (property);
54
  GValue value = G_VALUE_INIT;
55 56
  gboolean success;

57
  if (custom->property_parse_func)
58 59 60 61
    {
      GError *error = NULL;
      char *value_str;
      
62
      g_value_init (&value, _gtk_style_property_get_value_type (property));
63

64 65 66
      value_str = _gtk_css_parser_read_value (parser);
      if (value_str != NULL)
        {
67
          success = (* custom->property_parse_func) (value_str, &value, &error);
68 69 70 71 72 73
          g_free (value_str);
        }
      else
        success = FALSE;
    }
  else
74
    {
75
      g_value_init (&value, gtk_css_custom_property_get_specified_type (custom->pspec));
76

77
      success = _gtk_css_style_parse_value (&value, parser);
78
    }
79 80

  if (!success)
81 82 83 84 85
    {
      g_value_unset (&value);
      return NULL;
    }

86
  return _gtk_css_typed_value_new_take (&value);
87 88
}

89 90 91 92 93 94 95
static void
gtk_css_custom_property_query (GtkStyleProperty   *property,
                               GValue             *value,
                               GtkStyleQueryFunc   query_func,
                               gpointer            query_data)
{
  GtkCssStyleProperty *style = GTK_CSS_STYLE_PROPERTY (property);
96
  GtkCssCustomProperty *custom = GTK_CSS_CUSTOM_PROPERTY (property);
97 98 99 100
  GtkCssValue *css_value;
  
  css_value = (* query_func) (_gtk_css_style_property_get_id (style), query_data);
  if (css_value == NULL)
101
    css_value = _gtk_css_style_property_get_initial_value (style);
102

103 104
  g_value_init (value, custom->pspec->value_type);
  g_value_copy (_gtk_css_typed_value_get (css_value), value);
105 106
}

107 108 109 110 111 112
static void
gtk_css_custom_property_assign (GtkStyleProperty   *property,
                                GtkStyleProperties *props,
                                GtkStateFlags       state,
                                const GValue       *value)
{
113
  GtkCssValue *css_value = _gtk_css_typed_value_new (value);
114 115 116 117 118 119 120
  _gtk_style_properties_set_property_by_property (props,
                                                  GTK_CSS_STYLE_PROPERTY (property),
                                                  state,
                                                  css_value);
  _gtk_css_value_unref (css_value);
}

121 122 123
static void
_gtk_css_custom_property_class_init (GtkCssCustomPropertyClass *klass)
{
124 125 126
  GtkStylePropertyClass *property_class = GTK_STYLE_PROPERTY_CLASS (klass);

  property_class->parse_value = gtk_css_custom_property_parse_value;
127
  property_class->query = gtk_css_custom_property_query;
128
  property_class->assign = gtk_css_custom_property_assign;
129 130 131
}

static void
132
_gtk_css_custom_property_init (GtkCssCustomProperty *custom)
133 134 135
{
}

136 137
static GtkCssValue *
gtk_css_custom_property_create_initial_value (GParamSpec *pspec)
138
{
139
  GValue value = G_VALUE_INIT;
140
  GtkCssValue *result;
141

142
  g_value_init (&value, pspec->value_type);
143 144

  if (pspec->value_type == GTK_TYPE_THEMING_ENGINE)
145
    g_value_set_object (&value, gtk_theming_engine_load (NULL));
146
  else if (pspec->value_type == PANGO_TYPE_FONT_DESCRIPTION)
147
    g_value_take_boxed (&value, pango_font_description_from_string ("Sans 10"));
148
  else if (pspec->value_type == GDK_TYPE_RGBA)
149 150 151
    {
      GdkRGBA color;
      gdk_rgba_parse (&color, "pink");
152
      g_value_set_boxed (&value, &color);
153 154 155 156 157
    }
  else if (pspec->value_type == GDK_TYPE_COLOR)
    {
      GdkColor color;
      gdk_color_parse ("pink", &color);
158
      g_value_set_boxed (&value, &color);
159 160 161
    }
  else if (pspec->value_type == GTK_TYPE_BORDER)
    {
162
      g_value_take_boxed (&value, gtk_border_new ());
163 164
    }
  else
165 166
    g_param_value_set_default (pspec, &value);

167
  result = _gtk_css_typed_value_new (&value);
168 169 170
  g_value_unset (&value);

  return result;
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
}

/* Property registration functions */

/**
 * gtk_theming_engine_register_property: (skip)
 * @name_space: namespace for the property name
 * @parse_func: parsing function to use, or %NULL
 * @pspec: the #GParamSpec for the new property
 *
 * Registers a property so it can be used in the CSS file format,
 * on the CSS file the property will look like
 * "-${@name_space}-${property_name}". being
 * ${property_name} the given to @pspec. @name_space will usually
 * be the theme engine name.
 *
 * For any type a @parse_func may be provided, being this function
 * used for turning any property value (between ':' and ';') in
 * CSS to the #GValue needed. For basic types there is already
 * builtin parsing support, so %NULL may be provided for these
 * cases.
 *
 * <note>
 * Engines must ensure property registration happens exactly once,
 * usually GTK+ deals with theming engines as singletons, so this
 * should be guaranteed to happen once, but bear this in mind
 * when creating #GtkThemeEngine<!-- -->s yourself.
 * </note>
 *
 * <note>
 * In order to make use of the custom registered properties in
 * the CSS file, make sure the engine is loaded first by specifying
 * the engine property, either in a previous rule or within the same
 * one.
 * <programlisting>
 * &ast; {
 *     engine: someengine;
 *     -SomeEngine-custom-property: 2;
 * }
 * </programlisting>
 * </note>
 *
 * Since: 3.0
214 215
 *
 * Deprecated: 3.8: Code should use the default properties provided by CSS.
216 217 218 219 220 221
 **/
void
gtk_theming_engine_register_property (const gchar            *name_space,
                                      GtkStylePropertyParser  parse_func,
                                      GParamSpec             *pspec)
{
222
  GtkCssCustomProperty *node;
223
  GtkCssValue *initial;
224 225 226 227 228 229 230
  gchar *name;

  g_return_if_fail (name_space != NULL);
  g_return_if_fail (strchr (name_space, ' ') == NULL);
  g_return_if_fail (G_IS_PARAM_SPEC (pspec));

  name = g_strdup_printf ("-%s-%s", name_space, pspec->name);
231 232 233 234 235 236 237 238 239

  /* This also initializes the default properties */
  if (_gtk_style_property_lookup (pspec->name))
    {
      g_warning ("a property with name '%s' already exists", name);
      g_free (name);
      return;
    }
  
240
  initial = gtk_css_custom_property_create_initial_value (pspec);
241 242

  node = g_object_new (GTK_TYPE_CSS_CUSTOM_PROPERTY,
243
                       "initial-value", initial,
244 245 246
                       "name", name,
                       "value-type", pspec->value_type,
                       NULL);
247
  node->pspec = pspec;
248 249
  node->property_parse_func = parse_func;

250
  _gtk_css_value_unref (initial);
251 252 253 254 255 256 257 258 259 260 261 262 263 264
  g_free (name);
}

/**
 * gtk_style_properties_register_property: (skip)
 * @parse_func: parsing function to use, or %NULL
 * @pspec: the #GParamSpec for the new property
 *
 * Registers a property so it can be used in the CSS file format.
 * This function is the low-level equivalent of
 * gtk_theming_engine_register_property(), if you are implementing
 * a theming engine, you want to use that function instead.
 *
 * Since: 3.0
265 266
 *
 * Deprecated: 3.8: Code should use the default properties provided by CSS.
267 268 269 270 271
 **/
void
gtk_style_properties_register_property (GtkStylePropertyParser  parse_func,
                                        GParamSpec             *pspec)
{
272
  GtkCssCustomProperty *node;
273
  GtkCssValue *initial;
274 275 276

  g_return_if_fail (G_IS_PARAM_SPEC (pspec));

277 278 279 280 281 282 283
  /* This also initializes the default properties */
  if (_gtk_style_property_lookup (pspec->name))
    {
      g_warning ("a property with name '%s' already exists", pspec->name);
      return;
    }
  
284
  initial = gtk_css_custom_property_create_initial_value (pspec);
285 286

  node = g_object_new (GTK_TYPE_CSS_CUSTOM_PROPERTY,
287
                       "initial-value", initial,
288 289 290
                       "name", pspec->name,
                       "value-type", pspec->value_type,
                       NULL);
291
  node->pspec = pspec;
292 293
  node->property_parse_func = parse_func;

294
  _gtk_css_value_unref (initial);
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
}

/**
 * gtk_style_properties_lookup_property: (skip)
 * @property_name: property name to look up
 * @parse_func: (out): return location for the parse function
 * @pspec: (out) (transfer none): return location for the #GParamSpec
 *
 * Returns %TRUE if a property has been registered, if @pspec or
 * @parse_func are not %NULL, the #GParamSpec and parsing function
 * will be respectively returned.
 *
 * Returns: %TRUE if the property is registered, %FALSE otherwise
 *
 * Since: 3.0
310 311 312
 *
 * Deprecated: 3.8: This code could only look up custom properties and
 *     those are deprecated.
313 314 315 316 317 318 319 320 321 322 323 324 325
 **/
gboolean
gtk_style_properties_lookup_property (const gchar             *property_name,
                                      GtkStylePropertyParser  *parse_func,
                                      GParamSpec             **pspec)
{
  GtkStyleProperty *node;
  gboolean found = FALSE;

  g_return_val_if_fail (property_name != NULL, FALSE);

  node = _gtk_style_property_lookup (property_name);

326
  if (GTK_IS_CSS_CUSTOM_PROPERTY (node))
327
    {
328 329
      GtkCssCustomProperty *custom = GTK_CSS_CUSTOM_PROPERTY (node);

330
      if (pspec)
331
        *pspec = custom->pspec;
332 333

      if (parse_func)
334
        *parse_func = custom->property_parse_func;
335 336 337 338 339 340 341

      found = TRUE;
    }

  return found;
}