gtkstylecontext.c 92.7 KB
Newer Older
Carlos Garnacho's avatar
Carlos Garnacho committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* GTK - The GIMP Toolkit
 * Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org>
 *
 * 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
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Carlos Garnacho's avatar
Carlos Garnacho committed
16 17 18 19
 */

#include "config.h"

Benjamin Otte's avatar
Benjamin Otte committed
20 21
#include "gtkstylecontextprivate.h"

Carlos Garnacho's avatar
Carlos Garnacho committed
22
#include <gdk/gdk.h>
23
#include <math.h>
24
#include <stdlib.h>
25
#include <gobject/gvaluecollector.h>
Carlos Garnacho's avatar
Carlos Garnacho committed
26

27
#include "gtkcontainerprivate.h"
28
#include "gtkcssanimatedstyleprivate.h"
29
#include "gtkcsscolorvalueprivate.h"
30
#include "gtkcssenumvalueprivate.h"
Benjamin Otte's avatar
Benjamin Otte committed
31
#include "gtkcssimagevalueprivate.h"
32
#include "gtkcssnodedeclarationprivate.h"
33
#include "gtkcssnodeprivate.h"
34
#include "gtkcssnumbervalueprivate.h"
35
#include "gtkcsspathnodeprivate.h"
36
#include "gtkcssrgbavalueprivate.h"
37
#include "gtkcsscolorvalueprivate.h"
Benjamin Otte's avatar
Benjamin Otte committed
38
#include "gtkcssshadowsvalueprivate.h"
39
#include "gtkcssstaticstyleprivate.h"
40
#include "gtkcssstylepropertyprivate.h"
Benjamin Otte's avatar
Benjamin Otte committed
41
#include "gtkcsstransformvalueprivate.h"
42 43
#include "gtkcsstransientnodeprivate.h"
#include "gtkcsswidgetnodeprivate.h"
44
#include "gtkdebug.h"
Carlos Garnacho's avatar
Carlos Garnacho committed
45
#include "gtkintl.h"
46
#include "gtkprivate.h"
47
#include "gtkrenderbackgroundprivate.h"
Benjamin Otte's avatar
Benjamin Otte committed
48
#include "gtkrendericonprivate.h"
49
#include "gtksettings.h"
50
#include "gtksettingsprivate.h"
Benjamin Otte's avatar
Benjamin Otte committed
51 52 53 54 55 56
#include "gtkstylecascadeprivate.h"
#include "gtkstyleproviderprivate.h"
#include "gtktypebuiltins.h"
#include "gtkwindow.h"
#include "gtkwidgetpath.h"
#include "gtkwidgetprivate.h"
Carlos Garnacho's avatar
Carlos Garnacho committed
57

58 59 60
#include "deprecated/gtkgradientprivate.h"
#include "deprecated/gtksymboliccolorprivate.h"

61 62
#include "fallback-c89.c"

Carlos Garnacho's avatar
Carlos Garnacho committed
63 64
/**
 * SECTION:gtkstylecontext
Matthias Clasen's avatar
Matthias Clasen committed
65
 * @Short_description: Rendering UI elements
Carlos Garnacho's avatar
Carlos Garnacho committed
66 67 68 69 70 71
 * @Title: GtkStyleContext
 *
 * #GtkStyleContext is an object that stores styling information affecting
 * a widget defined by #GtkWidgetPath.
 *
 * In order to construct the final style information, #GtkStyleContext
Matthias Clasen's avatar
Matthias Clasen committed
72 73 74 75
 * queries information from all attached #GtkStyleProviders. Style providers
 * can be either attached explicitly to the context through
 * gtk_style_context_add_provider(), or to the screen through
 * gtk_style_context_add_provider_for_screen(). The resulting style is a
76
 * combination of all providers’ information in priority order.
Carlos Garnacho's avatar
Carlos Garnacho committed
77 78 79
 *
 * For GTK+ widgets, any #GtkStyleContext returned by
 * gtk_widget_get_style_context() will already have a #GtkWidgetPath, a
80 81
 * #GdkScreen and RTL/LTR information set. The style context will also be
 * updated automatically if any of these settings change on the widget.
Carlos Garnacho's avatar
Carlos Garnacho committed
82
 *
83
 * If you are using the theming layer standalone, you will need to set a
Carlos Garnacho's avatar
Carlos Garnacho committed
84 85 86 87
 * widget path and a screen yourself to the created style context through
 * gtk_style_context_set_path() and gtk_style_context_set_screen(), as well
 * as updating the context yourself using gtk_style_context_invalidate()
 * whenever any of the conditions change, such as a change in the
88
 * #GtkSettings:gtk-theme-name setting or a hierarchy change in the rendered
89
 * widget. See the “Foreign drawing“ example in gtk3-demo.
Carlos Garnacho's avatar
Carlos Garnacho committed
90
 *
91
 * # Style Classes # {#gtkstylecontext-classes}
Matthias Clasen's avatar
Matthias Clasen committed
92
 *
93 94 95 96 97 98
 * Widgets can add style classes to their context, which can be used to associate
 * different styles by class. The documentation for individual widgets lists
 * which style classes it uses itself, and which style classes may be added by
 * applications to affect their appearance.
 *
 * GTK+ defines macros for a number of style classes.
Matthias Clasen's avatar
Matthias Clasen committed
99
 *
100 101 102 103 104
 * # Style Regions
 *
 * Widgets can also add regions with flags to their context. This feature is
 * deprecated and will be removed in a future GTK+ update. Please use style
 * classes instead.
105
 *
106
 * GTK+ defines macros for a number of style regions.
Matthias Clasen's avatar
Matthias Clasen committed
107
 *
108
 * # Custom styling in UI libraries and applications
Matthias Clasen's avatar
Matthias Clasen committed
109
 *
110
 * If you are developing a library with custom #GtkWidgets that
Carlos Garnacho's avatar
Carlos Garnacho committed
111 112 113
 * render differently than standard components, you may need to add a
 * #GtkStyleProvider yourself with the %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK
 * priority, either a #GtkCssProvider or a custom object implementing the
114
 * #GtkStyleProvider interface. This way themes may still attempt
Carlos Garnacho's avatar
Carlos Garnacho committed
115
 * to style your UI elements in a different way if needed so.
Matthias Clasen's avatar
Matthias Clasen committed
116
 *
Carlos Garnacho's avatar
Carlos Garnacho committed
117
 * If you are using custom styling on an applications, you probably want then
118
 * to make your style information prevail to the theme’s, so you must use
Carlos Garnacho's avatar
Carlos Garnacho committed
119
 * a #GtkStyleProvider with the %GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
120
 * priority, keep in mind that the user settings in
121
 * `XDG_CONFIG_HOME/gtk-3.0/gtk.css` will
Carlos Garnacho's avatar
Carlos Garnacho committed
122 123 124 125
 * still take precedence over your changes, as it uses the
 * %GTK_STYLE_PROVIDER_PRIORITY_USER priority.
 */

126
typedef struct PropertyValue PropertyValue;
127

128 129 130 131 132 133 134
struct PropertyValue
{
  GType       widget_type;
  GParamSpec *pspec;
  GValue      value;
};

135
struct _GtkStyleContextPrivate
Carlos Garnacho's avatar
Carlos Garnacho committed
136
{
137 138
  GdkScreen *screen;

139
  guint cascade_changed_id;
140
  GtkStyleCascade *cascade;
141
  GtkStyleContext *parent;
142
  GtkCssNode *cssnode;
143
  GSList *saved_nodes;
144
  GArray *property_cache;
145

146
  GdkFrameClock *frame_clock;
147

148
  GtkCssStyleChange *invalidating_context;
Carlos Garnacho's avatar
Carlos Garnacho committed
149 150
};

151 152
enum {
  PROP_0,
153
  PROP_SCREEN,
154
  PROP_DIRECTION,
155
  PROP_FRAME_CLOCK,
156 157
  PROP_PARENT,
  LAST_PROP
158 159
};

160 161 162 163 164
enum {
  CHANGED,
  LAST_SIGNAL
};

165 166
static GParamSpec *properties[LAST_PROP] = { NULL, };

167
static guint signals[LAST_SIGNAL] = { 0 };
168

Carlos Garnacho's avatar
Carlos Garnacho committed
169 170
static void gtk_style_context_finalize (GObject *object);

171 172 173 174 175 176 177 178 179
static void gtk_style_context_impl_set_property (GObject      *object,
                                                 guint         prop_id,
                                                 const GValue *value,
                                                 GParamSpec   *pspec);
static void gtk_style_context_impl_get_property (GObject      *object,
                                                 guint         prop_id,
                                                 GValue       *value,
                                                 GParamSpec   *pspec);

180
static GtkCssNode * gtk_style_context_get_root (GtkStyleContext *context);
Carlos Garnacho's avatar
Carlos Garnacho committed
181

182
G_DEFINE_TYPE_WITH_PRIVATE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT)
Carlos Garnacho's avatar
Carlos Garnacho committed
183

184 185 186 187 188
static void
gtk_style_context_real_changed (GtkStyleContext *context)
{
  GtkStyleContextPrivate *priv = context->priv;

189 190
  if (GTK_IS_CSS_WIDGET_NODE (priv->cssnode))
    _gtk_widget_style_context_invalidated (gtk_css_widget_node_get_widget (GTK_CSS_WIDGET_NODE (priv->cssnode)));
191 192
}

Carlos Garnacho's avatar
Carlos Garnacho committed
193 194 195 196 197 198
static void
gtk_style_context_class_init (GtkStyleContextClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->finalize = gtk_style_context_finalize;
199 200 201
  object_class->set_property = gtk_style_context_impl_set_property;
  object_class->get_property = gtk_style_context_impl_get_property;

202 203
  klass->changed = gtk_style_context_real_changed;

204 205 206 207 208 209 210 211 212 213 214 215 216
  /**
   * GtkStyleContext::changed:
   *
   * The ::changed signal is emitted when there is a change in the
   * #GtkStyleContext.
   *
   * For a #GtkStyleContext returned by gtk_widget_get_style_context(), the
   * #GtkWidget::style-updated signal/vfunc might be more convenient to use.
   *
   * This signal is useful when using the theming layer standalone.
   *
   * Since: 3.0
   */
217 218
  signals[CHANGED] =
    g_signal_new (I_("changed"),
219 220 221 222
                  G_TYPE_FROM_CLASS (object_class),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GtkStyleContextClass, changed),
                  NULL, NULL,
223 224 225
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
  properties[PROP_SCREEN] =
      g_param_spec_object ("screen",
                           P_("Screen"),
                           P_("The associated GdkScreen"),
                           GDK_TYPE_SCREEN,
                           GTK_PARAM_READWRITE);

  properties[PROP_FRAME_CLOCK] =
      g_param_spec_object ("paint-clock",
                           P_("FrameClock"),
                           P_("The associated GdkFrameClock"),
                           GDK_TYPE_FRAME_CLOCK,
                           GTK_PARAM_READWRITE);

  properties[PROP_DIRECTION] =
      g_param_spec_enum ("direction",
                         P_("Direction"),
                         P_("Text direction"),
                         GTK_TYPE_TEXT_DIRECTION,
                         GTK_TEXT_DIR_LTR,
                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_DEPRECATED);
247

248 249 250
  /**
   * GtkStyleContext:parent:
   *
251
   * Sets or gets the style context’s parent. See gtk_style_context_set_parent()
252 253 254 255
   * for details.
   *
   * Since: 3.4
   */
256 257 258 259 260 261 262 263
  properties[PROP_PARENT] =
      g_param_spec_object ("parent",
                           P_("Parent"),
                           P_("The parent style context"),
                           GTK_TYPE_STYLE_CONTEXT,
                           GTK_PARAM_READWRITE);

  g_object_class_install_properties (object_class, LAST_PROP, properties);
Carlos Garnacho's avatar
Carlos Garnacho committed
264 265
}

266
void
267
gtk_style_context_clear_property_cache (GtkStyleContext *context)
268
{
269
  GtkStyleContextPrivate *priv = context->priv;
270 271
  guint i;

272
  for (i = 0; i < priv->property_cache->len; i++)
273
    {
274
      PropertyValue *node = &g_array_index (priv->property_cache, PropertyValue, i);
275 276 277 278 279

      g_param_spec_unref (node->pspec);
      g_value_unset (&node->value);
    }

280
  g_array_set_size (priv->property_cache, 0);
281 282
}

283
static void
284
gtk_style_context_pop_style_node (GtkStyleContext *context)
285
{
286
  GtkStyleContextPrivate *priv = context->priv;
287

288
  g_return_if_fail (priv->saved_nodes != NULL);
289

290 291
  if (GTK_IS_CSS_TRANSIENT_NODE (priv->cssnode))
    gtk_css_node_set_parent (priv->cssnode, NULL);
Benjamin Otte's avatar
Benjamin Otte committed
292
  g_object_unref (priv->cssnode);
293 294
  priv->cssnode = priv->saved_nodes->data;
  priv->saved_nodes = g_slist_remove (priv->saved_nodes, priv->cssnode);
295 296
}

297 298 299 300
static void
gtk_style_context_cascade_changed (GtkStyleCascade *cascade,
                                   GtkStyleContext *context)
{
301
  gtk_css_node_invalidate_style_provider (gtk_style_context_get_root (context));
302 303 304 305 306 307 308 309 310 311 312 313 314
}

static void
gtk_style_context_set_cascade (GtkStyleContext *context,
                               GtkStyleCascade *cascade)
{
  GtkStyleContextPrivate *priv;

  priv = context->priv;

  if (priv->cascade == cascade)
    return;

315
  if (priv->cascade)
316
    {
317 318 319
      g_signal_handler_disconnect (priv->cascade, priv->cascade_changed_id);
      priv->cascade_changed_id = 0;
      g_object_unref (priv->cascade);
320 321
    }

322
  if (cascade)
323
    {
324 325 326 327 328
      g_object_ref (cascade);
      priv->cascade_changed_id = g_signal_connect (cascade,
                                                   "-gtk-private-changed",
                                                   G_CALLBACK (gtk_style_context_cascade_changed),
                                                   context);
329 330 331 332
    }

  priv->cascade = cascade;

Benjamin Otte's avatar
Benjamin Otte committed
333
  if (cascade && priv->cssnode != NULL)
334 335 336
    gtk_style_context_cascade_changed (cascade, context);
}

Carlos Garnacho's avatar
Carlos Garnacho committed
337
static void
338
gtk_style_context_init (GtkStyleContext *context)
Carlos Garnacho's avatar
Carlos Garnacho committed
339 340 341
{
  GtkStyleContextPrivate *priv;

342
  priv = context->priv = gtk_style_context_get_instance_private (context);
343

344 345
  priv->screen = gdk_screen_get_default ();

346 347 348
  if (priv->screen == NULL)
    g_error ("Can't create a GtkStyleContext without a display connection");

349 350
  priv->property_cache = g_array_new (FALSE, FALSE, sizeof (PropertyValue));

351
  gtk_style_context_set_cascade (context,
352
                                 _gtk_settings_get_style_cascade (gtk_settings_get_for_screen (priv->screen), 1));
Benjamin Otte's avatar
Benjamin Otte committed
353 354

  /* Create default info store */
355
  priv->cssnode = gtk_css_path_node_new (context);
Benjamin Otte's avatar
Benjamin Otte committed
356
  gtk_css_node_set_state (priv->cssnode, GTK_STATE_FLAG_DIR_LTR);
Carlos Garnacho's avatar
Carlos Garnacho committed
357 358
}

359 360 361 362 363 364
static void
gtk_style_context_clear_parent (GtkStyleContext *context)
{
  GtkStyleContextPrivate *priv = context->priv;

  if (priv->parent)
365
    g_object_unref (priv->parent);
366 367
}

Carlos Garnacho's avatar
Carlos Garnacho committed
368 369 370
static void
gtk_style_context_finalize (GObject *object)
{
371 372
  GtkStyleContext *context = GTK_STYLE_CONTEXT (object);
  GtkStyleContextPrivate *priv = context->priv;
Carlos Garnacho's avatar
Carlos Garnacho committed
373

374
  while (priv->saved_nodes)
375 376
    gtk_style_context_pop_style_node (context);

377 378 379
  if (GTK_IS_CSS_PATH_NODE (priv->cssnode))
    gtk_css_path_node_unset_context (GTK_CSS_PATH_NODE (priv->cssnode));

380 381
  gtk_style_context_clear_parent (context);
  gtk_style_context_set_cascade (context, NULL);
382

Benjamin Otte's avatar
Benjamin Otte committed
383
  g_object_unref (priv->cssnode);
384

385
  gtk_style_context_clear_property_cache (context);
386 387
  g_array_free (priv->property_cache, TRUE);

Carlos Garnacho's avatar
Carlos Garnacho committed
388 389 390
  G_OBJECT_CLASS (gtk_style_context_parent_class)->finalize (object);
}

391 392 393 394 395 396
static void
gtk_style_context_impl_set_property (GObject      *object,
                                     guint         prop_id,
                                     const GValue *value,
                                     GParamSpec   *pspec)
{
397
  GtkStyleContext *context = GTK_STYLE_CONTEXT (object);
398 399 400 401

  switch (prop_id)
    {
    case PROP_SCREEN:
402
      gtk_style_context_set_screen (context, g_value_get_object (value));
403
      break;
404
    case PROP_DIRECTION:
405
      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
406
      gtk_style_context_set_direction (context, g_value_get_enum (value));
407
      G_GNUC_END_IGNORE_DEPRECATIONS;
408
      break;
409
    case PROP_FRAME_CLOCK:
410
      gtk_style_context_set_frame_clock (context, g_value_get_object (value));
411
      break;
412
    case PROP_PARENT:
413
      gtk_style_context_set_parent (context, g_value_get_object (value));
414
      break;
415 416 417 418 419 420 421 422 423 424 425 426
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_style_context_impl_get_property (GObject    *object,
                                     guint       prop_id,
                                     GValue     *value,
                                     GParamSpec *pspec)
{
427 428
  GtkStyleContext *context = GTK_STYLE_CONTEXT (object);
  GtkStyleContextPrivate *priv = context->priv;
429 430 431 432 433 434

  switch (prop_id)
    {
    case PROP_SCREEN:
      g_value_set_object (value, priv->screen);
      break;
435
    case PROP_DIRECTION:
436
      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
437
      g_value_set_enum (value, gtk_style_context_get_direction (context));
438
      G_GNUC_END_IGNORE_DEPRECATIONS;
439
      break;
440 441 442
    case PROP_FRAME_CLOCK:
      g_value_set_object (value, priv->frame_clock);
      break;
443 444 445
    case PROP_PARENT:
      g_value_set_object (value, priv->parent);
      break;
446 447 448 449 450 451
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

452 453 454 455 456 457 458 459
/* returns TRUE if someone called gtk_style_context_save() but hasn’t
 * called gtk_style_context_restore() yet.
 * In those situations we don’t invalidate the context when somebody
 * changes state/regions/classes.
 */
static gboolean
gtk_style_context_is_saved (GtkStyleContext *context)
{
460
  return context->priv->saved_nodes != NULL;
461 462
}

463
static GtkCssNode *
464 465
gtk_style_context_get_root (GtkStyleContext *context)
{
466
  GtkStyleContextPrivate *priv = context->priv;
467 468 469 470

  if (priv->saved_nodes != NULL)
    return g_slist_last (priv->saved_nodes)->data;
  else
471
    return priv->cssnode;
472 473
}

474 475 476 477 478 479
GtkStyleProviderPrivate *
gtk_style_context_get_style_provider (GtkStyleContext *context)
{
  return GTK_STYLE_PROVIDER_PRIVATE (context->priv->cascade);
}

480
static gboolean
481
gtk_style_context_has_custom_cascade (GtkStyleContext *context)
482 483
{
  GtkStyleContextPrivate *priv = context->priv;
484
  GtkSettings *settings = gtk_settings_get_for_screen (priv->screen);
485 486 487

  return priv->cascade != _gtk_settings_get_style_cascade (settings, _gtk_style_cascade_get_scale (priv->cascade));
}
488

489 490
GtkCssStyle *
gtk_style_context_lookup_style (GtkStyleContext *context)
491
{
492 493
  /* Code will recreate style if it was changed */
  return gtk_css_node_get_style (context->priv->cssnode);
494 495
}

496 497 498 499 500 501
GtkCssNode*
gtk_style_context_get_node (GtkStyleContext *context)
{
  return context->priv->cssnode;
}

502 503 504
static GtkStateFlags
gtk_style_context_push_state (GtkStyleContext *context,
                              GtkStateFlags    state)
505
{
506
  GtkStyleContextPrivate *priv = context->priv;
507
  GtkStateFlags current_state;
508
  GtkCssNode *root;
509

510
  current_state = gtk_css_node_get_state (priv->cssnode);
511

512 513
  if (current_state == state)
    return state;
514

515 516
  root = gtk_style_context_get_root (context);

517 518 519 520 521
  if (GTK_IS_CSS_TRANSIENT_NODE (priv->cssnode))
    {
      /* don't emit a warning, changing state here is fine */
    }
  else if (GTK_IS_CSS_WIDGET_NODE (root))
522 523
    {
      GtkWidget *widget = gtk_css_widget_node_get_widget (GTK_CSS_WIDGET_NODE (root));
524 525
      g_debug ("State %u for %s %p doesn't match state %u set via gtk_style_context_set_state ()",
               state, gtk_widget_get_name (widget), widget, gtk_css_node_get_state (priv->cssnode));
526 527
    }
  else
528
    {
529 530
      g_debug ("State %u for context %p doesn't match state %u set via gtk_style_context_set_state ()",
               state, context, gtk_css_node_get_state (priv->cssnode));
531
    }
532

533
  gtk_css_node_set_state (priv->cssnode, state);
534

535 536 537 538 539 540 541 542
  return current_state;
}

static void
gtk_style_context_pop_state (GtkStyleContext *context,
                             GtkStateFlags    saved_state)
{
  gtk_css_node_set_state (context->priv->cssnode, saved_state);
543 544
}

545 546 547 548
/**
 * gtk_style_context_new:
 *
 * Creates a standalone #GtkStyleContext, this style context
549
 * won’t be attached to any widget, so you may want
550
 * to call gtk_style_context_set_path() yourself.
551 552 553
 *
 * This function is only useful when using the theming layer
 * separated from GTK+, if you are using #GtkStyleContext to
554
 * theme #GtkWidgets, use gtk_widget_get_style_context()
555 556 557 558 559 560 561 562 563 564
 * in order to get a style context ready to theme the widget.
 *
 * Returns: A newly created #GtkStyleContext.
 **/
GtkStyleContext *
gtk_style_context_new (void)
{
  return g_object_new (GTK_TYPE_STYLE_CONTEXT, NULL);
}

Benjamin Otte's avatar
Benjamin Otte committed
565 566
GtkStyleContext *
gtk_style_context_new_for_node (GtkCssNode *node)
567
{
Benjamin Otte's avatar
Benjamin Otte committed
568
  GtkStyleContext *context;
569

Benjamin Otte's avatar
Benjamin Otte committed
570
  g_return_val_if_fail (GTK_IS_CSS_NODE (node), NULL);
571

Benjamin Otte's avatar
Benjamin Otte committed
572
  context = gtk_style_context_new ();
573
  g_set_object (&context->priv->cssnode, node);
574

Benjamin Otte's avatar
Benjamin Otte committed
575
  return context;
576 577
}

Carlos Garnacho's avatar
Carlos Garnacho committed
578 579 580 581 582 583 584 585 586 587 588
/**
 * gtk_style_context_add_provider:
 * @context: a #GtkStyleContext
 * @provider: a #GtkStyleProvider
 * @priority: the priority of the style provider. The lower
 *            it is, the earlier it will be used in the style
 *            construction. Typically this will be in the range
 *            between %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK and
 *            %GTK_STYLE_PROVIDER_PRIORITY_USER
 *
 * Adds a style provider to @context, to be used in style construction.
589 590 591 592
 * Note that a style provider added by this function only affects
 * the style of the widget to which @context belongs. If you want
 * to affect the style of all widgets, use
 * gtk_style_context_add_provider_for_screen().
Carlos Garnacho's avatar
Carlos Garnacho committed
593
 *
594
 * Note: If both priorities are the same, a #GtkStyleProvider
595
 * added through this function takes precedence over another added
596
 * through gtk_style_context_add_provider_for_screen().
597
 *
Carlos Garnacho's avatar
Carlos Garnacho committed
598 599
 * Since: 3.0
 **/
600 601 602 603 604 605 606 607 608 609 610
void
gtk_style_context_add_provider (GtkStyleContext  *context,
                                GtkStyleProvider *provider,
                                guint             priority)
{
  GtkStyleContextPrivate *priv;

  g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
  g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));

  priv = context->priv;
611

612
  if (!gtk_style_context_has_custom_cascade (context))
613 614
    {
      GtkStyleCascade *new_cascade;
615

616
      new_cascade = _gtk_style_cascade_new ();
617 618 619
      _gtk_style_cascade_set_scale (new_cascade, _gtk_style_cascade_get_scale (priv->cascade));
      _gtk_style_cascade_set_parent (new_cascade,
                                     _gtk_settings_get_style_cascade (gtk_settings_get_for_screen (priv->screen), 1));
620 621 622 623 624 625 626
      _gtk_style_cascade_add_provider (new_cascade, provider, priority);
      gtk_style_context_set_cascade (context, new_cascade);
      g_object_unref (new_cascade);
    }
  else
    {
      _gtk_style_cascade_add_provider (priv->cascade, provider, priority);
627
    }
Carlos Garnacho's avatar
Carlos Garnacho committed
628 629
}

Carlos Garnacho's avatar
Carlos Garnacho committed
630 631 632 633 634 635 636 637 638
/**
 * gtk_style_context_remove_provider:
 * @context: a #GtkStyleContext
 * @provider: a #GtkStyleProvider
 *
 * Removes @provider from the style providers list in @context.
 *
 * Since: 3.0
 **/
Carlos Garnacho's avatar
Carlos Garnacho committed
639 640 641 642 643 644 645
void
gtk_style_context_remove_provider (GtkStyleContext  *context,
                                   GtkStyleProvider *provider)
{
  g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
  g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));

646
  if (!gtk_style_context_has_custom_cascade (context))
647
    return;
Carlos Garnacho's avatar
Carlos Garnacho committed
648

649
  _gtk_style_cascade_remove_provider (context->priv->cascade, provider);
650
}
Carlos Garnacho's avatar
Carlos Garnacho committed
651

Carlos Garnacho's avatar
Carlos Garnacho committed
652 653 654 655 656 657 658 659 660 661 662 663 664
/**
 * gtk_style_context_reset_widgets:
 * @screen: a #GdkScreen
 *
 * This function recomputes the styles for all widgets under a particular
 * #GdkScreen. This is useful when some global parameter has changed that
 * affects the appearance of all widgets, because when a widget gets a new
 * style, it will both redraw and recompute any cached information about
 * its appearance. As an example, it is used when the color scheme changes
 * in the related #GtkSettings object.
 *
 * Since: 3.0
 **/
665 666
void
gtk_style_context_reset_widgets (GdkScreen *screen)
667 668
{
  GList *list, *toplevels;
Carlos Garnacho's avatar
Carlos Garnacho committed
669

670
  toplevels = gtk_window_list_toplevels ();
671
  g_list_foreach (toplevels, (GFunc) g_object_ref, NULL);
Carlos Garnacho's avatar
Carlos Garnacho committed
672

673 674 675 676
  for (list = toplevels; list; list = list->next)
    {
      if (gtk_widget_get_screen (list->data) == screen)
        gtk_widget_reset_style (list->data);
Carlos Garnacho's avatar
Carlos Garnacho committed
677

678
      g_object_unref (list->data);
Carlos Garnacho's avatar
Carlos Garnacho committed
679 680
    }

681 682 683
  g_list_free (toplevels);
}

Carlos Garnacho's avatar
Carlos Garnacho committed
684 685 686 687 688 689 690 691 692 693 694
/**
 * gtk_style_context_add_provider_for_screen:
 * @screen: a #GdkScreen
 * @provider: a #GtkStyleProvider
 * @priority: the priority of the style provider. The lower
 *            it is, the earlier it will be used in the style
 *            construction. Typically this will be in the range
 *            between %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK and
 *            %GTK_STYLE_PROVIDER_PRIORITY_USER
 *
 * Adds a global style provider to @screen, which will be used
695
 * in style construction for all #GtkStyleContexts under @screen.
Carlos Garnacho's avatar
Carlos Garnacho committed
696
 *
697 698 699
 * GTK+ uses this to make styling information from #GtkSettings
 * available.
 *
700
 * Note: If both priorities are the same, A #GtkStyleProvider
701
 * added through gtk_style_context_add_provider() takes precedence
702
 * over another added through this function.
703
 *
Carlos Garnacho's avatar
Carlos Garnacho committed
704 705
 * Since: 3.0
 **/
706 707 708 709 710
void
gtk_style_context_add_provider_for_screen (GdkScreen        *screen,
                                           GtkStyleProvider *provider,
                                           guint             priority)
{
711
  GtkStyleCascade *cascade;
712 713 714

  g_return_if_fail (GDK_IS_SCREEN (screen));
  g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
715
  g_return_if_fail (!GTK_IS_SETTINGS (provider) || _gtk_settings_get_screen (GTK_SETTINGS (provider)) == screen);
716

717
  cascade = _gtk_settings_get_style_cascade (gtk_settings_get_for_screen (screen), 1);
718
  _gtk_style_cascade_add_provider (cascade, provider, priority);
719 720
}

Carlos Garnacho's avatar
Carlos Garnacho committed
721 722 723 724 725 726 727 728 729
/**
 * gtk_style_context_remove_provider_for_screen:
 * @screen: a #GdkScreen
 * @provider: a #GtkStyleProvider
 *
 * Removes @provider from the global style providers list in @screen.
 *
 * Since: 3.0
 **/
730 731 732 733
void
gtk_style_context_remove_provider_for_screen (GdkScreen        *screen,
                                              GtkStyleProvider *provider)
{
734
  GtkStyleCascade *cascade;
735 736 737

  g_return_if_fail (GDK_IS_SCREEN (screen));
  g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
738
  g_return_if_fail (!GTK_IS_SETTINGS (provider));
739

740
  cascade = _gtk_settings_get_style_cascade (gtk_settings_get_for_screen (screen), 1);
741
  _gtk_style_cascade_remove_provider (cascade, provider);
Carlos Garnacho's avatar
Carlos Garnacho committed
742 743
}

744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
/**
 * gtk_style_context_get_section:
 * @context: a #GtkStyleContext
 * @property: style property name
 *
 * Queries the location in the CSS where @property was defined for the
 * current @context. Note that the state to be queried is taken from
 * gtk_style_context_get_state().
 *
 * If the location is not available, %NULL will be returned. The
 * location might not be available for various reasons, such as the
 * property being overridden, @property not naming a supported CSS
 * property or tracking of definitions being disabled for performance
 * reasons.
 *
 * Shorthand CSS properties cannot be queried for a location and will
 * always return %NULL.
 *
762 763
 * Returns: (nullable) (transfer none): %NULL or the section where a value
 * for @property was defined
764 765 766 767 768
 **/
GtkCssSection *
gtk_style_context_get_section (GtkStyleContext *context,
                               const gchar     *property)
{
769
  GtkCssStyle *values;
770 771 772 773 774 775 776 777 778
  GtkStyleProperty *prop;

  g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
  g_return_val_if_fail (property != NULL, NULL);

  prop = _gtk_style_property_lookup (property);
  if (!GTK_IS_CSS_STYLE_PROPERTY (prop))
    return NULL;

779
  values = gtk_style_context_lookup_style (context);
780
  return gtk_css_style_get_section (values, _gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (prop)));
781 782
}

783
static GtkCssValue *
784 785 786
gtk_style_context_query_func (guint    id,
                              gpointer values)
{
787
  return gtk_css_style_get_value (values, id);
788 789
}

Carlos Garnacho's avatar
Carlos Garnacho committed
790 791 792 793 794
/**
 * gtk_style_context_get_property:
 * @context: a #GtkStyleContext
 * @property: style property name
 * @state: state to retrieve the property value for
795
 * @value: (out) (transfer full):  return location for the style property value
Carlos Garnacho's avatar
Carlos Garnacho committed
796
 *
797
 * Gets a style property from @context for the given state.
798
 *
799 800
 * Note that not all CSS properties that are supported by GTK+ can be
 * retrieved in this way, since they may not be representable as #GValue.
801 802
 * GTK+ defines macros for a number of properties that can be used
 * with this function.
803
 *
804 805 806 807
 * Note that passing a state other than the current state of @context
 * is not recommended unless the style context has been saved with
 * gtk_style_context_save().
 *
808 809
 * When @value is no longer needed, g_value_unset() must be called
 * to free any allocated memory.
Carlos Garnacho's avatar
Carlos Garnacho committed
810 811 812
 *
 * Since: 3.0
 **/
813 814 815
void
gtk_style_context_get_property (GtkStyleContext *context,
                                const gchar     *property,
816
                                GtkStateFlags    state,
817 818
                                GValue          *value)
{
819
  GtkStateFlags saved_state;
820
  GtkStyleProperty *prop;
821 822 823 824 825

  g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
  g_return_if_fail (property != NULL);
  g_return_if_fail (value != NULL);

826 827 828 829 830 831 832 833 834 835 836 837
  prop = _gtk_style_property_lookup (property);
  if (prop == NULL)
    {
      g_warning ("Style property \"%s\" is not registered", property);
      return;
    }
  if (_gtk_style_property_get_value_type (prop) == G_TYPE_NONE)
    {
      g_warning ("Style property \"%s\" is not gettable", property);
      return;
    }

838
  saved_state = gtk_style_context_push_state (context, state);
839
  _gtk_style_property_query (prop,
840 841 842 843
                             value,
                             gtk_style_context_query_func,
                             gtk_css_node_get_style (context->priv->cssnode));
  gtk_style_context_pop_state (context, saved_state);
844 845
}

Carlos Garnacho's avatar
Carlos Garnacho committed
846 847 848 849 850 851 852 853
/**
 * gtk_style_context_get_valist:
 * @context: a #GtkStyleContext
 * @state: state to retrieve the property values for
 * @args: va_list of property name/return location pairs, followed by %NULL
 *
 * Retrieves several style property values from @context for a given state.
 *
854 855
 * See gtk_style_context_get_property() for details.
 *
Carlos Garnacho's avatar
Carlos Garnacho committed
856
 * Since: 3.0
857
 */
858 859
void
gtk_style_context_get_valist (GtkStyleContext *context,
860
                              GtkStateFlags    state,
861 862
                              va_list          args)
{
863
  const gchar *property_name;
864 865 866

  g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));

867
  property_name = va_arg (args, const gchar *);
868

869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890
  while (property_name)
    {
      gchar *error = NULL;
      GValue value = G_VALUE_INIT;

      gtk_style_context_get_property (context,
                                      property_name,
                                      state,
                                      &value);

      G_VALUE_LCOPY (&value, args, 0, &error);
      g_value_unset (&value);

      if (error)
        {
          g_warning ("Could not get style property \"%s\": %s", property_name, error);
          g_free (error);
          break;
        }

      property_name = va_arg (args, const gchar *);
    }
891 892
}

Carlos Garnacho's avatar
Carlos Garnacho committed
893 894 895 896 897 898 899 900 901
/**
 * gtk_style_context_get:
 * @context: a #GtkStyleContext
 * @state: state to retrieve the property values for
 * @...: property name /return value pairs, followed by %NULL
 *
 * Retrieves several style property values from @context for a
 * given state.
 *
902 903
 * See gtk_style_context_get_property() for details.
 *
Carlos Garnacho's avatar
Carlos Garnacho committed
904
 * Since: 3.0
905
 */
906 907
void
gtk_style_context_get (GtkStyleContext *context,
908
                       GtkStateFlags    state,
909 910 911 912 913 914 915
                       ...)
{
  va_list args;

  g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));

  va_start (args, state);
916
  gtk_style_context_get_valist (context, state, args);
917 918 919
  va_end (args);
}

920 921 922 923 924
/*
 * gtk_style_context_set_id:
 * @context: a #GtkStyleContext
 * @id: (allow-none): the id to use or %NULL for none.
 *
925
 * Sets the CSS ID to be used when obtaining style information.
926 927 928 929 930 931 932
 **/
void
gtk_style_context_set_id (GtkStyleContext *context,
                          const char      *id)
{
  g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));

Benjamin Otte's avatar
Benjamin Otte committed
933
  gtk_css_node_set_id (context->priv->cssnode, id);
934 935 936 937 938 939
}

/*
 * gtk_style_context_get_id:
 * @context: a #GtkStyleContext
 *
940
 * Returns the CSS ID used when obtaining style information.
941
 *
942
 * Returns: (nullable): the ID or %NULL if no ID is set.
943 944 945 946 947 948
 **/
const char *
gtk_style_context_get_id (GtkStyleContext *context)
{
  g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);

949
  return gtk_css_node_get_id (context->priv->cssnode);
950 951
}

Carlos Garnacho's avatar
Carlos Garnacho committed
952 953 954 955 956
/**
 * gtk_style_context_set_state:
 * @context: a #GtkStyleContext
 * @flags: state to represent
 *
957
 * Sets the state to be used for style matching.
Carlos Garnacho's avatar
Carlos Garnacho committed
958 959 960
 *
 * Since: 3.0
 **/
961 962 963 964
void
gtk_style_context_set_state (GtkStyleContext *context,
                             GtkStateFlags    flags)
{
965
  GtkStateFlags old_flags;
966

967 968
  g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));

969
  old_flags = gtk_css_node_get_state (context->priv->cssnode);
970

Benjamin Otte's avatar
Benjamin Otte committed
971
  gtk_css_node_set_state (context->priv->cssnode, flags);
972 973 974

  if (((old_flags ^ flags) & (GTK_STATE_FLAG_DIR_LTR | GTK_STATE_FLAG_DIR_RTL)) &&
      !gtk_style_context_is_saved (context))
975
    g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_DIRECTION]);
976 977
}

Carlos Garnacho's avatar
Carlos Garnacho committed
978 979 980 981
/**
 * gtk_style_context_get_state:
 * @context: a #GtkStyleContext
 *
982
 * Returns the state used for style matching.
983
 *
984 985 986 987
 * This method should only be used to retrieve the #GtkStateFlags
 * to pass to #GtkStyleContext methods, like gtk_style_context_get_padding().
 * If you need to retrieve the current state of a #GtkWidget, use
 * gtk_widget_get_state_flags().
Carlos Garnacho's avatar
Carlos Garnacho committed
988 989 990 991 992
 *
 * Returns: the state flags
 *
 * Since: 3.0
 **/
993 994 995 996 997
GtkStateFlags
gtk_style_context_get_state (GtkStyleContext *context)
{
  g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);

998
  return gtk_css_node_get_state (context->priv->cssnode);
999 1000
}

1001 1002 1003 1004 1005
/**
 * gtk_style_context_set_scale:
 * @context: a #GtkStyleContext
 * @scale: scale
 *
1006
 * Sets the scale to use when getting image assets for the style.
1007 1008 1009 1010 1011 1012 1013
 *
 * Since: 3.10
 **/
void
gtk_style_context_set_scale (GtkStyleContext *context,
                             gint             scale)
{
1014 1015
  GtkStyleContextPrivate *priv;

1016 1017
  g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));

1018 1019 1020
  priv = context->priv;

  if (scale == _gtk_style_cascade_get_scale (priv->cascade))
1021 1022
    return;

1023 1024 1025 1026 1027
  if (gtk_style_context_has_custom_cascade (context))
    {
      _gtk_style_cascade_set_scale (priv->cascade, scale);
    }
  else
1028 1029
    {
      GtkStyleCascade *new_cascade;
1030 1031 1032

      new_cascade = _gtk_settings_get_style_cascade (gtk_settings_get_for_screen (priv->screen),
                                                     scale);
1033 1034
      gtk_style_context_set_cascade (context, new_cascade);
    }
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
}

/**
 * gtk_style_context_get_scale:
 * @context: a #GtkStyleContext
 *
 * Returns the scale used for assets.
 *
 * Returns: the scale
 *
 * Since: 3.10
 **/
gint
gtk_style_context_get_scale (GtkStyleContext *context)
{
  g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);

1052
  return _gtk_style_cascade_get_scale (context->priv->cascade);
1053 1054
}

1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
/**
 * gtk_style_context_state_is_running:
 * @context: a #GtkStyleContext
 * @state: a widget state
 * @progress: (out): return location for the transition progress
 *
 * Returns %TRUE if there is a transition animation running for the
 * current region (see gtk_style_context_push_animatable_region()).
 *
 * If @progress is not %NULL, the animation progress will be returned
1065
 * there, 0.0 means the state is closest to being unset, while 1.0 means
1066
 * it’s closest to being set. This means transition animation will
1067
 * run from 0 to 1 when @state is being set and from 1 to 0 when
1068
 * it’s being unset.
1069 1070 1071 1072
 *
 * Returns: %TRUE if there is a running transition animation for @state.
 *
 * Since: 3.0
1073 1074
 *
 * Deprecated: 3.6: This function always returns %FALSE
1075
 **/
1076
gboolean
1077 1078 1079
gtk_style_context_state_is_running (GtkStyleContext *context,
                                    GtkStateType     state,
                                    gdouble         *progress)
1080 1081 1082
{
  g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);

1083
  return FALSE;
1084 1085
}

Carlos Garnacho's avatar
Carlos Garnacho committed
1086 1087 1088 1089 1090 1091 1092
/**
 * gtk_style_context_set_path:
 * @context: a #GtkStyleContext
 * @path: a #GtkWidgetPath
 *
 * Sets the #GtkWidgetPath used for style matching. As a
 * consequence, the style will be regenerated to match
1093 1094 1095 1096 1097
 * the new given path.
 *
 * If you are using a #GtkStyleContext returned from
 * gtk_widget_get_style_context(), you do not need to call
 * this yourself.
Carlos Garnacho's avatar
Carlos Garnacho committed
1098 1099 1100
 *
 * Since: 3.0
 **/
1101 1102 1103 1104
void
gtk_style_context_set_path (GtkStyleContext *context,
                            GtkWidgetPath   *path)
{
1105
  GtkCssNode *root;
1106 1107 1108 1109

  g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
  g_return_if_fail (path != NULL);

1110 1111
  root = gtk_style_context_get_root (context);
  g_return_if_fail (GTK_IS_CSS_PATH_NODE (root));
1112

1113
  if (path && gtk_widget_path_length (path) > 0)
1114
    {
1115 1116
      GtkWidgetPath *copy = gtk_widget_path_copy (path);
      gtk_css_path_node_set_widget_path (GTK_CSS_PATH_NODE (root), copy);
1117 1118 1119
      gtk_css_node_set_widget_type (root,
                                    gtk_widget_path_iter_get_object_type (copy, -1));
      gtk_css_node_set_name (root, gtk_widget_path_iter_get_object_name (copy, -1));
1120
      gtk_widget_path_unref (copy);
1121
    }
1122
  else
1123
    {
1124 1125
      gtk_css_path_node_set_widget_path (GTK_CSS_PATH_NODE (root), NULL);
      gtk_css_node_set_widget_type (root, G_TYPE_NONE);
1126
      gtk_css_node_set_name (root, NULL);
1127
    }
1128 1129
}

Carlos Garnacho's avatar
Carlos Garnacho committed
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
/**
 * gtk_style_context_get_path:
 * @context: a #GtkStyleContext
 *
 * Returns the widget path used for style matching.
 *
 * Returns: (transfer none): A #GtkWidgetPath
 *
 * Since: 3.0
 **/
1140
const GtkWidgetPath *
1141 1142
gtk_style_context_get_path (GtkStyleContext *context)
{
1143
  return gtk_css_node_get_widget_path (gtk_style_context_get_root (context));
1144 1145
}

1146 1147 1148 1149 1150 1151 1152
/**
 * gtk_style_context_set_parent:
 * @context: a #GtkStyleContext
 * @parent: (allow-none): the new parent or %NULL
 *
 * Sets the parent style context for @context. The parent style
 * context is used to implement
1153
 * [inheritance](http://www.w3.org/TR/css3-cascade/#inheritance)
Matthias Clasen's avatar
Matthias Clasen committed
1154
 * of properties.
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
 *
 * If you are using a #GtkStyleContext returned from
 * gtk_widget_get_style_context(), the parent will be set for you.
 *
 * Since: 3.4
 **/
void
gtk_style_context_set_parent (GtkStyleContext *context,
                              GtkStyleContext *parent)
{
  GtkStyleContextPrivate *priv;

  g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
  g_return_if_fail (parent == NULL || GTK_IS_STYLE_CONTEXT (parent));

  priv = context->priv;

  if (priv->parent == parent)
    return;

  if (parent)
1176
    {