gtkcssvalue.c 15 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 97 98 99
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);
}

100
static const GtkCssValueClass GTK_CSS_VALUE_DEFAULT = {
101
  gtk_css_value_default_free,
102
  gtk_css_value_default_equal,
103
  gtk_css_value_default_print
104 105
};

106 107 108
G_DEFINE_BOXED_TYPE (GtkCssValue, _gtk_css_value, _gtk_css_value_ref, _gtk_css_value_unref)

static GtkCssValue *
109
gtk_css_value_new (GType type)
110 111 112
{
  GtkCssValue *value;

113
  value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_DEFAULT);
114

115
  value->type = type;
116 117 118 119 120 121 122 123

  return value;
}

GtkCssValue *
_gtk_css_value_new_from_gvalue (const GValue *g_value)
{
  GtkCssValue *value;
124
  GType type;
125 126 127

  g_return_val_if_fail (g_value != NULL, NULL);

128
  type = G_VALUE_TYPE (g_value);
129

130 131 132 133 134
  /* 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
    {
135
      value = gtk_css_value_new (type);
136 137 138 139 140 141 142

      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);
143 144
      else if (g_type_is_a (type, G_TYPE_UINT))
	value->u.guint = g_value_get_uint (g_value);
145 146 147 148
      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);
149 150
      else if (g_type_is_a (type, G_TYPE_FLAGS))
	value->u.guint = g_value_get_flags (g_value);
151 152 153 154
      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);
155 156
      else if (g_type_is_a (type, G_TYPE_FLOAT))
	value->u.flt = g_value_get_float (g_value);
157
      else
158 159 160 161 162
        {
          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);
        }
163
    }
164 165 166 167 168 169 170 171

  return value;
}

GtkCssValue *
_gtk_css_value_new_from_int (gint val)
{
  GtkCssValue *value;
172 173 174 175 176 177
  static GtkCssValue *singletons[4] = {NULL};

  if (val >= 0 && val < G_N_ELEMENTS (singletons))
    {
      if (singletons[val] == NULL)
	{
178
	  value = gtk_css_value_new (G_TYPE_INT);
179
	  value->u.gint = val;
180 181 182 183
	  singletons[val] = value;
	}
      return _gtk_css_value_ref (singletons[val]);
    }
184

185
  value = gtk_css_value_new (G_TYPE_INT);
186
  value->u.gint = val;
187 188 189 190

  return value;
}

191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
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_from_double (double d)
{
  GtkCssValue *value;

  value = gtk_css_value_new (G_TYPE_DOUBLE);
  value->u.dbl = d;

  return value;
}

216 217 218 219 220
GtkCssValue *
_gtk_css_value_new_take_string (char *string)
{
  GtkCssValue *value;

221
  value = gtk_css_value_new (G_TYPE_STRING);
222
  value->u.ptr = string;
223 224 225 226

  return value;
}

227 228 229 230 231 232 233 234 235 236 237
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;
}

238 239 240 241 242 243 244 245 246
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);
}

247 248 249 250 251 252 253 254 255 256 257 258 259 260
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;
}

261 262 263 264 265
GtkCssValue *
_gtk_css_value_new_take_pattern (cairo_pattern_t *v)
{
  GtkCssValue *value;

266
  value = gtk_css_value_new (CAIRO_GOBJECT_TYPE_PATTERN);
267
  value->u.ptr = v;
268 269 270 271 272 273 274 275 276

  return value;
}

GtkCssValue *
_gtk_css_value_new_take_image (GtkCssImage *v)
{
  GtkCssValue *value;

277
  value = gtk_css_value_new (GTK_TYPE_CSS_IMAGE);
278
  value->u.ptr = v;
279 280 281 282

  return value;
}

283 284 285 286 287 288 289 290 291 292 293
GtkCssValue *
_gtk_css_value_new_from_theming_engine (GtkThemingEngine *v)
{
  GtkCssValue *value;

  value = gtk_css_value_new (GTK_TYPE_THEMING_ENGINE);
  value->u.ptr = g_object_ref (v);

  return value;
}

294 295 296 297 298 299 300 301 302 303 304
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;
}

305 306 307 308 309
GtkCssValue *
_gtk_css_value_new_from_rgba (const GdkRGBA *v)
{
  GtkCssValue *value;

310
  value = gtk_css_value_new (GDK_TYPE_RGBA);
311
  value->u.ptr = g_boxed_copy0 (GDK_TYPE_RGBA, v);
312 313 314 315 316 317 318 319 320

  return value;
}

GtkCssValue *
_gtk_css_value_new_from_color (const GdkColor *v)
{
  GtkCssValue *value;

321
  value = gtk_css_value_new (GDK_TYPE_COLOR);
322
  value->u.ptr = g_boxed_copy0 (GDK_TYPE_COLOR, v);
323 324 325 326 327 328 329 330 331

  return value;
}

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

332
  value = gtk_css_value_new (GTK_TYPE_CSS_BACKGROUND_SIZE);
333
  value->u.ptr = g_boxed_copy0 (GTK_TYPE_CSS_BACKGROUND_SIZE, v);
334 335 336 337

  return value;
}

338 339 340 341 342
GtkCssValue *
_gtk_css_value_new_from_background_position (const GtkCssBackgroundPosition *v)
{
  GtkCssValue *value;

343
  value = gtk_css_value_new (GTK_TYPE_CSS_BACKGROUND_POSITION);
344 345 346 347 348
  value->u.ptr = g_boxed_copy0 (GTK_TYPE_CSS_BACKGROUND_POSITION, v);

  return value;
}

349 350 351 352 353 354 355 356 357 358 359
GtkCssValue *
_gtk_css_value_new_from_border_corner_radius (const GtkCssBorderCornerRadius *v)
{
  GtkCssValue *value;

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

  return value;
}

360 361 362 363 364 365 366 367 368 369 370
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;
}

371 372 373 374 375 376 377 378 379 380 381
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;
}

382 383 384 385 386
GtkCssValue *
_gtk_css_value_new_take_symbolic_color (GtkSymbolicColor *v)
{
  GtkCssValue *value;

387
  value = gtk_css_value_new (GTK_TYPE_SYMBOLIC_COLOR);
388
  value->u.ptr = v;
389 390 391 392

  return value;
}

393 394 395 396 397 398 399 400 401 402 403 404 405 406
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;
}

407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
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;

426
  value->class->free (value);
427 428
}

429 430 431 432 433 434 435 436 437 438 439 440 441
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);
}

442 443 444 445 446 447 448 449 450 451
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);
}

452
GType
453
_gtk_css_value_get_content_type (const GtkCssValue *value)
454
{
455
  return value->type;
456 457 458
}

gboolean
459
_gtk_css_value_holds (const GtkCssValue *value, GType type)
460
{
461 462 463 464
  return g_type_is_a (value->type, type);
}

static void
465 466
fill_gvalue (const GtkCssValue *value,
	     GValue            *g_value)
467 468 469 470 471 472 473 474 475 476 477
{
  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);
478 479
  else if (g_type_is_a (type, G_TYPE_UINT))
    g_value_set_uint (g_value, value->u.guint);
480 481 482 483
  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);
484 485
  else if (g_type_is_a (type, G_TYPE_FLAGS))
    g_value_set_flags (g_value, value->u.guint);
486 487 488 489
  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);
490 491
  else if (g_type_is_a (type, G_TYPE_FLOAT))
    g_value_set_float (g_value, value->u.flt);
492
  else
493
    g_value_copy (value->u.ptr, g_value);
494 495 496
}

void
497 498
_gtk_css_value_init_gvalue (const GtkCssValue *value,
			    GValue            *g_value)
499 500 501
{
  if (value != NULL)
    {
502 503
      g_value_init (g_value, value->type);
      fill_gvalue (value, g_value);
504 505 506 507
    }
}

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

int
515
_gtk_css_value_get_int (const GtkCssValue *value)
516 517
{
  g_return_val_if_fail (_gtk_css_value_holds (value, G_TYPE_INT), 0);
518
  return value->u.gint;
519 520
}

521 522 523 524 525 526 527
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;
}

528
double
529
_gtk_css_value_get_double (const GtkCssValue *value)
530 531
{
  g_return_val_if_fail (_gtk_css_value_holds (value, G_TYPE_DOUBLE), 0);
532
  return value->u.dbl;
533 534 535
}

const char *
536
_gtk_css_value_get_string (const GtkCssValue *value)
537 538
{
  g_return_val_if_fail (_gtk_css_value_holds (value, G_TYPE_STRING), 0);
539
  return value->u.ptr;
540 541 542
}

gpointer
543
_gtk_css_value_dup_object (const GtkCssValue *value)
544 545
{
  g_return_val_if_fail (_gtk_css_value_holds (value, G_TYPE_OBJECT), NULL);
546 547 548
  if (value->u.ptr)
    return g_object_ref (value->u.ptr);
  return NULL;
549 550 551
}

gpointer
552
_gtk_css_value_get_object (const GtkCssValue *value)
553 554
{
  g_return_val_if_fail (_gtk_css_value_holds (value, G_TYPE_OBJECT), NULL);
555
  return value->u.ptr;
556 557 558
}

gpointer
559
_gtk_css_value_get_boxed (const GtkCssValue *value)
560 561
{
  g_return_val_if_fail (_gtk_css_value_holds (value, G_TYPE_BOXED), NULL);
562
  return value->u.ptr;
563 564 565
}

const char **
566
_gtk_css_value_get_strv (const GtkCssValue *value)
567 568
{
  g_return_val_if_fail (_gtk_css_value_holds (value, G_TYPE_STRV), NULL);
569
  return value->u.ptr;
570 571 572
}

GtkCssImage *
573
_gtk_css_value_get_image (const GtkCssValue *value)
574 575
{
  g_return_val_if_fail (_gtk_css_value_holds (value, GTK_TYPE_CSS_IMAGE), NULL);
576
  return value->u.ptr;
577 578 579
}

GtkBorderStyle
580
_gtk_css_value_get_border_style (const GtkCssValue *value)
581 582
{
  g_return_val_if_fail (_gtk_css_value_holds (value, GTK_TYPE_BORDER_STYLE), 0);
583
  return value->u.gint;
584 585
}

586
const GtkCssBackgroundSize *
587
_gtk_css_value_get_background_size (const GtkCssValue *value)
588 589
{
  g_return_val_if_fail (_gtk_css_value_holds (value, GTK_TYPE_CSS_BACKGROUND_SIZE), NULL);
590
  return value->u.ptr;
591 592
}

593
const GtkCssBackgroundPosition *
594
_gtk_css_value_get_background_position (const GtkCssValue *value)
595 596 597 598 599
{
  g_return_val_if_fail (_gtk_css_value_holds (value, GTK_TYPE_CSS_BACKGROUND_POSITION), NULL);
  return value->u.ptr;
}

600
const GtkCssBorderImageRepeat *
601
_gtk_css_value_get_border_image_repeat (const GtkCssValue *value)
602 603
{
  g_return_val_if_fail (_gtk_css_value_holds (value, GTK_TYPE_CSS_BORDER_IMAGE_REPEAT), NULL);
604
  return value->u.ptr;
605 606
}

607
const GtkCssBorderCornerRadius *
608
_gtk_css_value_get_border_corner_radius (const GtkCssValue *value)
609 610
{
  g_return_val_if_fail (_gtk_css_value_holds (value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS), NULL);
611
  return value->u.ptr;
612 613 614
}

PangoStyle
615
_gtk_css_value_get_pango_style (const GtkCssValue *value)
616 617
{
  g_return_val_if_fail (_gtk_css_value_holds (value, PANGO_TYPE_STYLE), 0);
618
  return value->u.gint;
619 620 621
}

PangoVariant
622
_gtk_css_value_get_pango_variant (const GtkCssValue *value)
623 624
{
  g_return_val_if_fail (_gtk_css_value_holds (value, PANGO_TYPE_VARIANT), 0);
625
  return value->u.gint;
626 627 628
}

PangoWeight
629
_gtk_css_value_get_pango_weight (const GtkCssValue *value)
630 631
{
  g_return_val_if_fail (_gtk_css_value_holds (value, PANGO_TYPE_WEIGHT), 0);
632
  return value->u.gint;
633 634
}

635
const GdkRGBA *
636
_gtk_css_value_get_rgba (const GtkCssValue *value)
637 638
{
  g_return_val_if_fail (_gtk_css_value_holds (value, GDK_TYPE_RGBA), NULL);
639
  return value->u.ptr;
640 641 642
}

cairo_pattern_t *
643
_gtk_css_value_get_pattern (const GtkCssValue *value)
644 645
{
  g_return_val_if_fail (_gtk_css_value_holds (value, CAIRO_GOBJECT_TYPE_PATTERN), NULL);
646
  return value->u.ptr;
647 648 649
}

GtkGradient *
650
_gtk_css_value_get_gradient (const GtkCssValue *value)
651 652
{
  g_return_val_if_fail (_gtk_css_value_holds (value, GTK_TYPE_GRADIENT), NULL);
653
  return value->u.ptr;
654 655
}