gtkcssvalue.c 12.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* GTK - The GIMP Toolkit
 * Copyright (C) 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 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
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 */

#include "config.h"

#include "gtkcssvalueprivate.h"
21
#include "gtkcssstylefuncsprivate.h"
22 23 24 25 26
#include "gtktypebuiltins.h"
#include "gtkgradient.h"
#include <cairo-gobject.h>
#include "gtkprivatetypebuiltins.h"

27 28
#include "fallback-c89.c"

29 30
struct _GtkCssValue
{
31
  GTK_CSS_VALUE_BASE
32 33 34 35
  GType type;
  union {
    gpointer ptr;
    gint gint;
36
    guint guint;
37
    double dbl;
38
    float flt;
39
  } u;
40 41
};

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
static void
gtk_css_value_default_free (GtkCssValue *value)
{
  GType type = value->type;

  if (g_type_is_a (type, G_TYPE_OBJECT))
    {
      if (value->u.ptr != NULL)
        g_object_unref (value->u.ptr);
    }
  else if (g_type_is_a (type, G_TYPE_BOXED))
    {
      if (value->u.ptr != NULL)
        g_boxed_free (type, value->u.ptr);
    }
  else if (g_type_is_a (type, G_TYPE_STRING))
    g_free (value->u.ptr);
  else if (g_type_is_a (type, G_TYPE_INT))
    {}
  else if (g_type_is_a (type, G_TYPE_UINT))
    {}
  else if (g_type_is_a (type, G_TYPE_BOOLEAN))
    {}
  else if (g_type_is_a (type, G_TYPE_ENUM))
    {}
  else if (g_type_is_a (type, G_TYPE_FLAGS))
    {}
  else if (g_type_is_a (type, G_TYPE_DOUBLE))
    {}
  else if (g_type_is_a (type, G_TYPE_FLOAT))
    {}
  else
    {
      g_value_unset (value->u.ptr);
      g_slice_free (GValue, value->u.ptr);
    }

  g_slice_free (GtkCssValue, value);
}

82 83 84 85 86 87 88
static gboolean
gtk_css_value_default_equal (const GtkCssValue *value1,
                             const GtkCssValue *value2)
{
  return FALSE;
}

89 90 91 92 93 94 95 96
static GtkCssValue *
gtk_css_value_default_transition (GtkCssValue *start,
                                  GtkCssValue *end,
                                  double       progress)
{
  return NULL;
}

97 98 99 100 101 102 103 104 105 106 107
static void
gtk_css_value_default_print (const GtkCssValue *value,
                             GString           *string)
{
  GValue g_value = G_VALUE_INIT;

  _gtk_css_value_init_gvalue (value, &g_value);
  _gtk_css_style_print_value (&g_value, string);
  g_value_unset (&g_value);
}

108
static const GtkCssValueClass GTK_CSS_VALUE_DEFAULT = {
109
  gtk_css_value_default_free,
110
  gtk_css_value_default_equal,
111
  gtk_css_value_default_transition,
112
  gtk_css_value_default_print
113 114
};

115 116 117
G_DEFINE_BOXED_TYPE (GtkCssValue, _gtk_css_value, _gtk_css_value_ref, _gtk_css_value_unref)

static GtkCssValue *
118
gtk_css_value_new (GType type)
119 120 121
{
  GtkCssValue *value;

122
  value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_DEFAULT);
123

124
  value->type = type;
125 126 127 128 129 130 131 132

  return value;
}

GtkCssValue *
_gtk_css_value_new_from_gvalue (const GValue *g_value)
{
  GtkCssValue *value;
133
  GType type;
134 135 136

  g_return_val_if_fail (g_value != NULL, NULL);

137
  type = G_VALUE_TYPE (g_value);
138

139 140 141 142 143
  /* Make sure we reuse the int/number singletons */
  if (type == G_TYPE_INT)
    value = _gtk_css_value_new_from_int (g_value_get_int (g_value));
  else
    {
144
      value = gtk_css_value_new (type);
145 146 147 148 149 150 151

      if (g_type_is_a (type, G_TYPE_OBJECT))
	value->u.ptr = g_value_dup_object (g_value);
      else if (g_type_is_a (type, G_TYPE_BOXED))
	value->u.ptr = g_value_dup_boxed (g_value);
      else if (g_type_is_a (type, G_TYPE_INT))
	value->u.gint = g_value_get_int (g_value);
152 153
      else if (g_type_is_a (type, G_TYPE_UINT))
	value->u.guint = g_value_get_uint (g_value);
154 155 156 157
      else if (g_type_is_a (type, G_TYPE_BOOLEAN))
	value->u.gint = g_value_get_boolean (g_value);
      else if (g_type_is_a (type, G_TYPE_ENUM))
	value->u.gint = g_value_get_enum (g_value);
158 159
      else if (g_type_is_a (type, G_TYPE_FLAGS))
	value->u.guint = g_value_get_flags (g_value);
160 161 162 163
      else if (g_type_is_a (type, G_TYPE_STRING))
	value->u.ptr = g_value_dup_string (g_value);
      else if (g_type_is_a (type, G_TYPE_DOUBLE))
	value->u.dbl = g_value_get_double (g_value);
164 165
      else if (g_type_is_a (type, G_TYPE_FLOAT))
	value->u.flt = g_value_get_float (g_value);
166
      else
167 168 169 170 171
        {
          value->u.ptr = g_slice_new0 (GValue);
          g_value_init (value->u.ptr, G_VALUE_TYPE (g_value));
          g_value_copy (g_value, value->u.ptr);
        }
172
    }
173 174 175 176 177 178 179 180

  return value;
}

GtkCssValue *
_gtk_css_value_new_from_int (gint val)
{
  GtkCssValue *value;
181 182 183 184 185 186
  static GtkCssValue *singletons[4] = {NULL};

  if (val >= 0 && val < G_N_ELEMENTS (singletons))
    {
      if (singletons[val] == NULL)
	{
187
	  value = gtk_css_value_new (G_TYPE_INT);
188
	  value->u.gint = val;
189 190 191 192
	  singletons[val] = value;
	}
      return _gtk_css_value_ref (singletons[val]);
    }
193

194
  value = gtk_css_value_new (G_TYPE_INT);
195
  value->u.gint = val;
196 197 198 199

  return value;
}

200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
GtkCssValue *
_gtk_css_value_new_from_enum (GType type,
                              gint  val)
{
  GtkCssValue *value;

  g_return_val_if_fail (g_type_is_a (type, G_TYPE_ENUM), NULL);

  value = gtk_css_value_new (type);
  value->u.gint = val;

  return value;
}

GtkCssValue *
_gtk_css_value_new_take_strv (char **strv)
{
  GtkCssValue *value;

  value = gtk_css_value_new (G_TYPE_STRV);
  value->u.ptr = strv;

  return value;
}

225 226 227 228 229 230 231 232 233
static gpointer
g_boxed_copy0 (GType         boxed_type,
	       gconstpointer src_boxed)
{
  if (src_boxed == NULL)
    return NULL;
  return g_boxed_copy (boxed_type, src_boxed);
}

234 235 236 237 238 239 240 241 242 243 244 245 246 247
GtkCssValue *
_gtk_css_value_new_from_boxed (GType    type,
                               gpointer boxed)
{
  GtkCssValue *value;

  g_return_val_if_fail (g_type_is_a (type, G_TYPE_BOXED), NULL);

  value = gtk_css_value_new (type);
  value->u.ptr = g_boxed_copy0 (type, boxed);

  return value;
}

248 249 250 251 252
GtkCssValue *
_gtk_css_value_new_take_pattern (cairo_pattern_t *v)
{
  GtkCssValue *value;

253
  value = gtk_css_value_new (CAIRO_GOBJECT_TYPE_PATTERN);
254
  value->u.ptr = v;
255 256 257 258

  return value;
}

259 260 261 262 263 264 265 266 267 268 269
GtkCssValue *
_gtk_css_value_new_take_binding_sets (GPtrArray *array)
{
  GtkCssValue *value;

  value = gtk_css_value_new (G_TYPE_PTR_ARRAY);
  value->u.ptr = array;

  return value;
}

270 271 272 273 274
GtkCssValue *
_gtk_css_value_new_from_color (const GdkColor *v)
{
  GtkCssValue *value;

275
  value = gtk_css_value_new (GDK_TYPE_COLOR);
276
  value->u.ptr = g_boxed_copy0 (GDK_TYPE_COLOR, v);
277 278 279 280 281 282 283 284 285

  return value;
}

GtkCssValue *
_gtk_css_value_new_from_background_size (const GtkCssBackgroundSize *v)
{
  GtkCssValue *value;

286
  value = gtk_css_value_new (GTK_TYPE_CSS_BACKGROUND_SIZE);
287
  value->u.ptr = g_boxed_copy0 (GTK_TYPE_CSS_BACKGROUND_SIZE, v);
288 289 290 291

  return value;
}

292 293 294 295 296 297 298 299 300 301 302
GtkCssValue *
_gtk_css_value_new_from_border_image_repeat (const GtkCssBorderImageRepeat *v)
{
  GtkCssValue *value;

  value = gtk_css_value_new (GTK_TYPE_CSS_BORDER_IMAGE_REPEAT);
  value->u.ptr = g_boxed_copy0 (GTK_TYPE_CSS_BORDER_IMAGE_REPEAT, v);

  return value;
}

303 304 305 306 307 308 309 310 311 312 313
GtkCssValue *
_gtk_css_value_new_from_border_style (GtkBorderStyle style)
{
  GtkCssValue *value;

  value = gtk_css_value_new (GTK_TYPE_BORDER_STYLE);
  value->u.gint = style;

  return value;
}

314 315 316 317 318
GtkCssValue *
_gtk_css_value_new_take_symbolic_color (GtkSymbolicColor *v)
{
  GtkCssValue *value;

319
  value = gtk_css_value_new (GTK_TYPE_SYMBOLIC_COLOR);
320
  value->u.ptr = v;
321 322 323 324

  return value;
}

325 326 327 328 329 330 331 332 333 334 335 336 337 338
GtkCssValue *
_gtk_css_value_alloc (const GtkCssValueClass *klass,
                      gsize                   size)
{
  GtkCssValue *value;

  value = g_slice_alloc0 (size);

  value->class = klass;
  value->ref_count = 1;

  return value;
}

339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
GtkCssValue *
_gtk_css_value_ref (GtkCssValue *value)
{
  g_return_val_if_fail (value != NULL, NULL);

  g_atomic_int_add (&value->ref_count, 1);

  return value;
}

void
_gtk_css_value_unref (GtkCssValue *value)
{
  if (value == NULL)
    return;

  if (!g_atomic_int_dec_and_test (&value->ref_count))
    return;

358
  value->class->free (value);
359 360
}

361 362 363 364 365 366 367 368 369 370 371 372 373
gboolean
_gtk_css_value_equal (const GtkCssValue *value1,
                      const GtkCssValue *value2)
{
  g_return_val_if_fail (value1 != NULL, FALSE);
  g_return_val_if_fail (value2 != NULL, FALSE);

  if (value1->class != value2->class)
    return FALSE;

  return value1->class->equal (value1, value2);
}

374 375 376 377 378 379 380 381 382 383 384 385 386 387
GtkCssValue *
_gtk_css_value_transition (GtkCssValue *start,
                           GtkCssValue *end,
                           double       progress)
{
  g_return_val_if_fail (start != NULL, FALSE);
  g_return_val_if_fail (end != NULL, FALSE);

  if (start->class != end->class)
    return NULL;

  return start->class->transition (start, end, progress);
}

388 389 390 391 392 393 394 395 396 397 398 399
char *
_gtk_css_value_to_string (const GtkCssValue *value)
{
  GString *string;

  g_return_val_if_fail (value != NULL, NULL);

  string = g_string_new (NULL);
  _gtk_css_value_print (value, string);
  return g_string_free (string, FALSE);
}

400 401 402 403 404 405 406 407 408 409
void
_gtk_css_value_print (const GtkCssValue *value,
                      GString           *string)
{
  g_return_if_fail (value != NULL);
  g_return_if_fail (string != NULL);

  value->class->print (value, string);
}

410
GType
411
_gtk_css_value_get_content_type (const GtkCssValue *value)
412
{
413 414
  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_DEFAULT, G_TYPE_NONE);

415
  return value->type;
416 417 418
}

gboolean
419
_gtk_css_value_holds (const GtkCssValue *value, GType type)
420
{
421 422
  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_DEFAULT, FALSE);

423 424 425 426
  return g_type_is_a (value->type, type);
}

static void
427 428
fill_gvalue (const GtkCssValue *value,
	     GValue            *g_value)
429 430 431 432 433 434 435 436 437 438 439
{
  GType type;

  type = value->type;

  if (g_type_is_a (type, G_TYPE_OBJECT))
    g_value_set_object (g_value, value->u.ptr);
  else if (g_type_is_a (type, G_TYPE_BOXED))
    g_value_set_boxed (g_value, value->u.ptr);
  else if (g_type_is_a (type, G_TYPE_INT))
    g_value_set_int (g_value, value->u.gint);
440 441
  else if (g_type_is_a (type, G_TYPE_UINT))
    g_value_set_uint (g_value, value->u.guint);
442 443 444 445
  else if (g_type_is_a (type, G_TYPE_BOOLEAN))
    g_value_set_boolean (g_value, value->u.gint);
  else if (g_type_is_a (type, G_TYPE_ENUM))
    g_value_set_enum (g_value, value->u.gint);
446 447
  else if (g_type_is_a (type, G_TYPE_FLAGS))
    g_value_set_flags (g_value, value->u.guint);
448 449 450 451
  else if (g_type_is_a (type, G_TYPE_STRING))
    g_value_set_string (g_value, value->u.ptr);
  else if (g_type_is_a (type, G_TYPE_DOUBLE))
    g_value_set_double (g_value, value->u.dbl);
452 453
  else if (g_type_is_a (type, G_TYPE_FLOAT))
    g_value_set_float (g_value, value->u.flt);
454
  else
455
    g_value_copy (value->u.ptr, g_value);
456 457 458
}

void
459 460
_gtk_css_value_init_gvalue (const GtkCssValue *value,
			    GValue            *g_value)
461 462 463
{
  if (value != NULL)
    {
464
      g_return_if_fail (value->class == &GTK_CSS_VALUE_DEFAULT);
465 466
      g_value_init (g_value, value->type);
      fill_gvalue (value, g_value);
467 468 469 470
    }
}

GtkSymbolicColor *
471
_gtk_css_value_get_symbolic_color (const GtkCssValue *value)
472 473
{
  g_return_val_if_fail (_gtk_css_value_holds (value, GTK_TYPE_SYMBOLIC_COLOR), NULL);
474
  return value->u.ptr;
475 476 477
}

int
478
_gtk_css_value_get_int (const GtkCssValue *value)
479 480
{
  g_return_val_if_fail (_gtk_css_value_holds (value, G_TYPE_INT), 0);
481
  return value->u.gint;
482 483
}

484 485 486 487 488 489 490
int
_gtk_css_value_get_enum (const GtkCssValue *value)
{
  g_return_val_if_fail (_gtk_css_value_holds (value, G_TYPE_ENUM), 0);
  return value->u.gint;
}

491
gpointer
492
_gtk_css_value_dup_object (const GtkCssValue *value)
493 494
{
  g_return_val_if_fail (_gtk_css_value_holds (value, G_TYPE_OBJECT), NULL);
495 496 497
  if (value->u.ptr)
    return g_object_ref (value->u.ptr);
  return NULL;
498 499 500
}

gpointer
501
_gtk_css_value_get_object (const GtkCssValue *value)
502 503
{
  g_return_val_if_fail (_gtk_css_value_holds (value, G_TYPE_OBJECT), NULL);
504
  return value->u.ptr;
505 506 507
}

gpointer
508
_gtk_css_value_get_boxed (const GtkCssValue *value)
509 510
{
  g_return_val_if_fail (_gtk_css_value_holds (value, G_TYPE_BOXED), NULL);
511
  return value->u.ptr;
512 513 514
}

const char **
515
_gtk_css_value_get_strv (const GtkCssValue *value)
516 517
{
  g_return_val_if_fail (_gtk_css_value_holds (value, G_TYPE_STRV), NULL);
518
  return value->u.ptr;
519 520 521
}

GtkBorderStyle
522
_gtk_css_value_get_border_style (const GtkCssValue *value)
523 524
{
  g_return_val_if_fail (_gtk_css_value_holds (value, GTK_TYPE_BORDER_STYLE), 0);
525
  return value->u.gint;
526 527
}

528
const GtkCssBackgroundSize *
529
_gtk_css_value_get_background_size (const GtkCssValue *value)
530 531
{
  g_return_val_if_fail (_gtk_css_value_holds (value, GTK_TYPE_CSS_BACKGROUND_SIZE), NULL);
532
  return value->u.ptr;
533 534
}

535
const GtkCssBorderImageRepeat *
536
_gtk_css_value_get_border_image_repeat (const GtkCssValue *value)
537 538
{
  g_return_val_if_fail (_gtk_css_value_holds (value, GTK_TYPE_CSS_BORDER_IMAGE_REPEAT), NULL);
539
  return value->u.ptr;
540 541 542
}

GtkGradient *
543
_gtk_css_value_get_gradient (const GtkCssValue *value)
544 545
{
  g_return_val_if_fail (_gtk_css_value_holds (value, GTK_TYPE_GRADIENT), NULL);
546
  return value->u.ptr;
547 548
}