1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include "gtkstylecontextprivate.h"
21 
22 #include <gdk/gdk.h>
23 #include <math.h>
24 #include <stdlib.h>
25 #include <gobject/gvaluecollector.h>
26 
27 #include "gtkcontainerprivate.h"
28 #include "gtkcssanimatedstyleprivate.h"
29 #include "gtkcsscolorvalueprivate.h"
30 #include "gtkcssenumvalueprivate.h"
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"
38 #include "gtkcssshadowsvalueprivate.h"
39 #include "gtkcssstaticstyleprivate.h"
40 #include "gtkcssstylepropertyprivate.h"
41 #include "gtkcsstransformvalueprivate.h"
42 #include "gtkcsstransientnodeprivate.h"
43 #include "gtkcsswidgetnodeprivate.h"
44 #include "gtkdebug.h"
45 #include "gtkintl.h"
46 #include "gtkprivate.h"
47 #include "gtkrenderbackgroundprivate.h"
48 #include "gtkrendericonprivate.h"
49 #include "gtksettings.h"
50 #include "gtksettingsprivate.h"
51 #include "gtkstylecascadeprivate.h"
52 #include "gtkstyleproviderprivate.h"
53 #include "gtktypebuiltins.h"
54 #include "gtkwindow.h"
55 #include "gtkwidgetpath.h"
56 #include "gtkwidgetprivate.h"
57 
58 #include "deprecated/gtkgradientprivate.h"
59 #include "deprecated/gtksymboliccolorprivate.h"
60 
61 #include "fallback-c89.c"
62 
63 /**
64  * SECTION:gtkstylecontext
65  * @Short_description: Rendering UI elements
66  * @Title: GtkStyleContext
67  *
68  * #GtkStyleContext is an object that stores styling information affecting
69  * a widget defined by #GtkWidgetPath.
70  *
71  * In order to construct the final style information, #GtkStyleContext
72  * queries information from all attached #GtkStyleProviders. Style providers
73  * can be either attached explicitly to the context through
74  * gtk_style_context_add_provider(), or to the screen through
75  * gtk_style_context_add_provider_for_screen(). The resulting style is a
76  * combination of all providers’ information in priority order.
77  *
78  * For GTK+ widgets, any #GtkStyleContext returned by
79  * gtk_widget_get_style_context() will already have a #GtkWidgetPath, a
80  * #GdkScreen and RTL/LTR information set. The style context will also be
81  * updated automatically if any of these settings change on the widget.
82  *
83  * If you are using the theming layer standalone, you will need to set a
84  * widget path and a screen yourself to the created style context through
85  * gtk_style_context_set_path() and possibly gtk_style_context_set_screen(). See
86  * the “Foreign drawing“ example in gtk3-demo.
87  *
88  * # Style Classes # {#gtkstylecontext-classes}
89  *
90  * Widgets can add style classes to their context, which can be used to associate
91  * different styles by class. The documentation for individual widgets lists
92  * which style classes it uses itself, and which style classes may be added by
93  * applications to affect their appearance.
94  *
95  * GTK+ defines macros for a number of style classes.
96  *
97  * # Style Regions
98  *
99  * Widgets can also add regions with flags to their context. This feature is
100  * deprecated and will be removed in a future GTK+ update. Please use style
101  * classes instead.
102  *
103  * GTK+ defines macros for a number of style regions.
104  *
105  * # Custom styling in UI libraries and applications
106  *
107  * If you are developing a library with custom #GtkWidgets that
108  * render differently than standard components, you may need to add a
109  * #GtkStyleProvider yourself with the %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK
110  * priority, either a #GtkCssProvider or a custom object implementing the
111  * #GtkStyleProvider interface. This way themes may still attempt
112  * to style your UI elements in a different way if needed so.
113  *
114  * If you are using custom styling on an applications, you probably want then
115  * to make your style information prevail to the theme’s, so you must use
116  * a #GtkStyleProvider with the %GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
117  * priority, keep in mind that the user settings in
118  * `XDG_CONFIG_HOME/gtk-3.0/gtk.css` will
119  * still take precedence over your changes, as it uses the
120  * %GTK_STYLE_PROVIDER_PRIORITY_USER priority.
121  */
122 
123 typedef struct PropertyValue PropertyValue;
124 
125 struct PropertyValue
126 {
127   GType       widget_type;
128   GParamSpec *pspec;
129   GValue      value;
130 };
131 
132 struct _GtkStyleContextPrivate
133 {
134   GdkScreen *screen;
135 
136   guint cascade_changed_id;
137   GtkStyleCascade *cascade;
138   GtkStyleContext *parent;
139   GtkCssNode *cssnode;
140   GSList *saved_nodes;
141   GArray *property_cache;
142 
143   GdkFrameClock *frame_clock;
144 
145   GtkCssStyleChange *invalidating_context;
146 };
147 
148 enum {
149   PROP_0,
150   PROP_SCREEN,
151   PROP_DIRECTION,
152   PROP_FRAME_CLOCK,
153   PROP_PARENT,
154   LAST_PROP
155 };
156 
157 enum {
158   CHANGED,
159   LAST_SIGNAL
160 };
161 
162 static GParamSpec *properties[LAST_PROP] = { NULL, };
163 
164 static guint signals[LAST_SIGNAL] = { 0 };
165 
166 static void gtk_style_context_finalize (GObject *object);
167 
168 static void gtk_style_context_impl_set_property (GObject      *object,
169                                                  guint         prop_id,
170                                                  const GValue *value,
171                                                  GParamSpec   *pspec);
172 static void gtk_style_context_impl_get_property (GObject      *object,
173                                                  guint         prop_id,
174                                                  GValue       *value,
175                                                  GParamSpec   *pspec);
176 
177 static GtkCssNode * gtk_style_context_get_root (GtkStyleContext *context);
178 
G_DEFINE_TYPE_WITH_PRIVATE(GtkStyleContext,gtk_style_context,G_TYPE_OBJECT)179 G_DEFINE_TYPE_WITH_PRIVATE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT)
180 
181 static void
182 gtk_style_context_real_changed (GtkStyleContext *context)
183 {
184   GtkStyleContextPrivate *priv = context->priv;
185 
186   if (GTK_IS_CSS_WIDGET_NODE (priv->cssnode))
187     {
188       GtkWidget *widget = gtk_css_widget_node_get_widget (GTK_CSS_WIDGET_NODE (priv->cssnode));
189       if (widget != NULL)
190         _gtk_widget_style_context_invalidated (widget);
191     }
192 }
193 
194 static void
gtk_style_context_class_init(GtkStyleContextClass * klass)195 gtk_style_context_class_init (GtkStyleContextClass *klass)
196 {
197   GObjectClass *object_class = G_OBJECT_CLASS (klass);
198 
199   object_class->finalize = gtk_style_context_finalize;
200   object_class->set_property = gtk_style_context_impl_set_property;
201   object_class->get_property = gtk_style_context_impl_get_property;
202 
203   klass->changed = gtk_style_context_real_changed;
204 
205   /**
206    * GtkStyleContext::changed:
207    *
208    * The ::changed signal is emitted when there is a change in the
209    * #GtkStyleContext.
210    *
211    * For a #GtkStyleContext returned by gtk_widget_get_style_context(), the
212    * #GtkWidget::style-updated signal/vfunc might be more convenient to use.
213    *
214    * This signal is useful when using the theming layer standalone.
215    *
216    * Since: 3.0
217    */
218   signals[CHANGED] =
219     g_signal_new (I_("changed"),
220                   G_TYPE_FROM_CLASS (object_class),
221                   G_SIGNAL_RUN_FIRST,
222                   G_STRUCT_OFFSET (GtkStyleContextClass, changed),
223                   NULL, NULL,
224                   NULL,
225                   G_TYPE_NONE, 0);
226 
227   properties[PROP_SCREEN] =
228       g_param_spec_object ("screen",
229                            P_("Screen"),
230                            P_("The associated GdkScreen"),
231                            GDK_TYPE_SCREEN,
232                            GTK_PARAM_READWRITE);
233 
234   properties[PROP_FRAME_CLOCK] =
235       g_param_spec_object ("paint-clock",
236                            P_("FrameClock"),
237                            P_("The associated GdkFrameClock"),
238                            GDK_TYPE_FRAME_CLOCK,
239                            GTK_PARAM_READWRITE);
240 
241   properties[PROP_DIRECTION] =
242       g_param_spec_enum ("direction",
243                          P_("Direction"),
244                          P_("Text direction"),
245                          GTK_TYPE_TEXT_DIRECTION,
246                          GTK_TEXT_DIR_LTR,
247                          GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_DEPRECATED);
248 
249   /**
250    * GtkStyleContext:parent:
251    *
252    * Sets or gets the style context’s parent. See gtk_style_context_set_parent()
253    * for details.
254    *
255    * Since: 3.4
256    */
257   properties[PROP_PARENT] =
258       g_param_spec_object ("parent",
259                            P_("Parent"),
260                            P_("The parent style context"),
261                            GTK_TYPE_STYLE_CONTEXT,
262                            GTK_PARAM_READWRITE);
263 
264   g_object_class_install_properties (object_class, LAST_PROP, properties);
265 }
266 
267 void
gtk_style_context_clear_property_cache(GtkStyleContext * context)268 gtk_style_context_clear_property_cache (GtkStyleContext *context)
269 {
270   GtkStyleContextPrivate *priv = context->priv;
271   guint i;
272 
273   for (i = 0; i < priv->property_cache->len; i++)
274     {
275       PropertyValue *node = &g_array_index (priv->property_cache, PropertyValue, i);
276 
277       g_param_spec_unref (node->pspec);
278       g_value_unset (&node->value);
279     }
280 
281   g_array_set_size (priv->property_cache, 0);
282 }
283 
284 static void
gtk_style_context_pop_style_node(GtkStyleContext * context)285 gtk_style_context_pop_style_node (GtkStyleContext *context)
286 {
287   GtkStyleContextPrivate *priv = context->priv;
288 
289   g_return_if_fail (priv->saved_nodes != NULL);
290 
291   if (GTK_IS_CSS_TRANSIENT_NODE (priv->cssnode))
292     gtk_css_node_set_parent (priv->cssnode, NULL);
293   g_object_unref (priv->cssnode);
294   priv->cssnode = priv->saved_nodes->data;
295   priv->saved_nodes = g_slist_remove (priv->saved_nodes, priv->cssnode);
296 }
297 
298 static void
gtk_style_context_cascade_changed(GtkStyleCascade * cascade,GtkStyleContext * context)299 gtk_style_context_cascade_changed (GtkStyleCascade *cascade,
300                                    GtkStyleContext *context)
301 {
302   gtk_css_node_invalidate_style_provider (gtk_style_context_get_root (context));
303 }
304 
305 static void
gtk_style_context_set_cascade(GtkStyleContext * context,GtkStyleCascade * cascade)306 gtk_style_context_set_cascade (GtkStyleContext *context,
307                                GtkStyleCascade *cascade)
308 {
309   GtkStyleContextPrivate *priv;
310 
311   priv = context->priv;
312 
313   if (priv->cascade == cascade)
314     return;
315 
316   if (priv->cascade)
317     {
318       g_signal_handler_disconnect (priv->cascade, priv->cascade_changed_id);
319       priv->cascade_changed_id = 0;
320       g_object_unref (priv->cascade);
321     }
322 
323   if (cascade)
324     {
325       g_object_ref (cascade);
326       priv->cascade_changed_id = g_signal_connect (cascade,
327                                                    "-gtk-private-changed",
328                                                    G_CALLBACK (gtk_style_context_cascade_changed),
329                                                    context);
330     }
331 
332   priv->cascade = cascade;
333 
334   if (cascade && priv->cssnode != NULL)
335     gtk_style_context_cascade_changed (cascade, context);
336 }
337 
338 static void
gtk_style_context_init(GtkStyleContext * context)339 gtk_style_context_init (GtkStyleContext *context)
340 {
341   GtkStyleContextPrivate *priv;
342 
343   priv = context->priv = gtk_style_context_get_instance_private (context);
344 
345   priv->screen = gdk_screen_get_default ();
346 
347   if (priv->screen == NULL)
348     g_error ("Can't create a GtkStyleContext without a display connection");
349 
350   priv->property_cache = g_array_new (FALSE, FALSE, sizeof (PropertyValue));
351 
352   gtk_style_context_set_cascade (context,
353                                  _gtk_settings_get_style_cascade (gtk_settings_get_for_screen (priv->screen), 1));
354 
355   /* Create default info store */
356   priv->cssnode = gtk_css_path_node_new (context);
357   gtk_css_node_set_state (priv->cssnode, GTK_STATE_FLAG_DIR_LTR);
358 }
359 
360 static void
gtk_style_context_clear_parent(GtkStyleContext * context)361 gtk_style_context_clear_parent (GtkStyleContext *context)
362 {
363   GtkStyleContextPrivate *priv = context->priv;
364 
365   if (priv->parent)
366     g_object_unref (priv->parent);
367 }
368 
369 static void
gtk_style_context_finalize(GObject * object)370 gtk_style_context_finalize (GObject *object)
371 {
372   GtkStyleContext *context = GTK_STYLE_CONTEXT (object);
373   GtkStyleContextPrivate *priv = context->priv;
374 
375   while (priv->saved_nodes)
376     gtk_style_context_pop_style_node (context);
377 
378   if (GTK_IS_CSS_PATH_NODE (priv->cssnode))
379     gtk_css_path_node_unset_context (GTK_CSS_PATH_NODE (priv->cssnode));
380 
381   gtk_style_context_clear_parent (context);
382   gtk_style_context_set_cascade (context, NULL);
383 
384   g_object_unref (priv->cssnode);
385 
386   gtk_style_context_clear_property_cache (context);
387   g_array_free (priv->property_cache, TRUE);
388 
389   G_OBJECT_CLASS (gtk_style_context_parent_class)->finalize (object);
390 }
391 
392 static void
gtk_style_context_impl_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)393 gtk_style_context_impl_set_property (GObject      *object,
394                                      guint         prop_id,
395                                      const GValue *value,
396                                      GParamSpec   *pspec)
397 {
398   GtkStyleContext *context = GTK_STYLE_CONTEXT (object);
399 
400   switch (prop_id)
401     {
402     case PROP_SCREEN:
403       gtk_style_context_set_screen (context, g_value_get_object (value));
404       break;
405     case PROP_DIRECTION:
406       G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
407       gtk_style_context_set_direction (context, g_value_get_enum (value));
408       G_GNUC_END_IGNORE_DEPRECATIONS;
409       break;
410     case PROP_FRAME_CLOCK:
411       gtk_style_context_set_frame_clock (context, g_value_get_object (value));
412       break;
413     case PROP_PARENT:
414       gtk_style_context_set_parent (context, g_value_get_object (value));
415       break;
416     default:
417       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
418       break;
419     }
420 }
421 
422 static void
gtk_style_context_impl_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)423 gtk_style_context_impl_get_property (GObject    *object,
424                                      guint       prop_id,
425                                      GValue     *value,
426                                      GParamSpec *pspec)
427 {
428   GtkStyleContext *context = GTK_STYLE_CONTEXT (object);
429   GtkStyleContextPrivate *priv = context->priv;
430 
431   switch (prop_id)
432     {
433     case PROP_SCREEN:
434       g_value_set_object (value, priv->screen);
435       break;
436     case PROP_DIRECTION:
437       G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
438       g_value_set_enum (value, gtk_style_context_get_direction (context));
439       G_GNUC_END_IGNORE_DEPRECATIONS;
440       break;
441     case PROP_FRAME_CLOCK:
442       g_value_set_object (value, priv->frame_clock);
443       break;
444     case PROP_PARENT:
445       g_value_set_object (value, priv->parent);
446       break;
447     default:
448       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
449       break;
450     }
451 }
452 
453 /* returns TRUE if someone called gtk_style_context_save() but hasn’t
454  * called gtk_style_context_restore() yet.
455  * In those situations we don’t invalidate the context when somebody
456  * changes state/regions/classes.
457  */
458 static gboolean
gtk_style_context_is_saved(GtkStyleContext * context)459 gtk_style_context_is_saved (GtkStyleContext *context)
460 {
461   return context->priv->saved_nodes != NULL;
462 }
463 
464 static GtkCssNode *
gtk_style_context_get_root(GtkStyleContext * context)465 gtk_style_context_get_root (GtkStyleContext *context)
466 {
467   GtkStyleContextPrivate *priv = context->priv;
468 
469   if (priv->saved_nodes != NULL)
470     return g_slist_last (priv->saved_nodes)->data;
471   else
472     return priv->cssnode;
473 }
474 
475 GtkStyleProviderPrivate *
gtk_style_context_get_style_provider(GtkStyleContext * context)476 gtk_style_context_get_style_provider (GtkStyleContext *context)
477 {
478   return GTK_STYLE_PROVIDER_PRIVATE (context->priv->cascade);
479 }
480 
481 static gboolean
gtk_style_context_has_custom_cascade(GtkStyleContext * context)482 gtk_style_context_has_custom_cascade (GtkStyleContext *context)
483 {
484   GtkStyleContextPrivate *priv = context->priv;
485   GtkSettings *settings = gtk_settings_get_for_screen (priv->screen);
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 gtk_style_context_lookup_style (GtkStyleContext *context)
492 {
493   /* Code will recreate style if it was changed */
494   return gtk_css_node_get_style (context->priv->cssnode);
495 }
496 
497 GtkCssNode*
gtk_style_context_get_node(GtkStyleContext * context)498 gtk_style_context_get_node (GtkStyleContext *context)
499 {
500   return context->priv->cssnode;
501 }
502 
503 static GtkStateFlags
gtk_style_context_push_state(GtkStyleContext * context,GtkStateFlags state)504 gtk_style_context_push_state (GtkStyleContext *context,
505                               GtkStateFlags    state)
506 {
507   GtkStyleContextPrivate *priv = context->priv;
508   GtkStateFlags current_state;
509   GtkCssNode *root;
510 
511   current_state = gtk_css_node_get_state (priv->cssnode);
512 
513   if (current_state == state)
514     return state;
515 
516   root = gtk_style_context_get_root (context);
517 
518   if (GTK_IS_CSS_TRANSIENT_NODE (priv->cssnode))
519     {
520       /* don't emit a warning, changing state here is fine */
521     }
522   else if (GTK_IS_CSS_WIDGET_NODE (root))
523     {
524       GtkWidget *widget = gtk_css_widget_node_get_widget (GTK_CSS_WIDGET_NODE (root));
525       g_debug ("State %u for %s %p doesn't match state %u set via gtk_style_context_set_state ()",
526                state, (widget == NULL) ? "(null)" : gtk_widget_get_name (widget),
527                widget, gtk_css_node_get_state (priv->cssnode));
528     }
529   else
530     {
531       g_debug ("State %u for context %p doesn't match state %u set via gtk_style_context_set_state ()",
532                state, context, gtk_css_node_get_state (priv->cssnode));
533     }
534 
535   gtk_css_node_set_state (priv->cssnode, state);
536 
537   return current_state;
538 }
539 
540 static void
gtk_style_context_pop_state(GtkStyleContext * context,GtkStateFlags saved_state)541 gtk_style_context_pop_state (GtkStyleContext *context,
542                              GtkStateFlags    saved_state)
543 {
544   gtk_css_node_set_state (context->priv->cssnode, saved_state);
545 }
546 
547 /**
548  * gtk_style_context_new:
549  *
550  * Creates a standalone #GtkStyleContext, this style context
551  * won’t be attached to any widget, so you may want
552  * to call gtk_style_context_set_path() yourself.
553  *
554  * This function is only useful when using the theming layer
555  * separated from GTK+, if you are using #GtkStyleContext to
556  * theme #GtkWidgets, use gtk_widget_get_style_context()
557  * in order to get a style context ready to theme the widget.
558  *
559  * Returns: A newly created #GtkStyleContext.
560  **/
561 GtkStyleContext *
gtk_style_context_new(void)562 gtk_style_context_new (void)
563 {
564   return g_object_new (GTK_TYPE_STYLE_CONTEXT, NULL);
565 }
566 
567 GtkStyleContext *
gtk_style_context_new_for_node(GtkCssNode * node)568 gtk_style_context_new_for_node (GtkCssNode *node)
569 {
570   GtkStyleContext *context;
571 
572   g_return_val_if_fail (GTK_IS_CSS_NODE (node), NULL);
573 
574   context = gtk_style_context_new ();
575   g_set_object (&context->priv->cssnode, node);
576 
577   return context;
578 }
579 
580 /**
581  * gtk_style_context_add_provider:
582  * @context: a #GtkStyleContext
583  * @provider: a #GtkStyleProvider
584  * @priority: the priority of the style provider. The lower
585  *            it is, the earlier it will be used in the style
586  *            construction. Typically this will be in the range
587  *            between %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK and
588  *            %GTK_STYLE_PROVIDER_PRIORITY_USER
589  *
590  * Adds a style provider to @context, to be used in style construction.
591  * Note that a style provider added by this function only affects
592  * the style of the widget to which @context belongs. If you want
593  * to affect the style of all widgets, use
594  * gtk_style_context_add_provider_for_screen().
595  *
596  * Note: If both priorities are the same, a #GtkStyleProvider
597  * added through this function takes precedence over another added
598  * through gtk_style_context_add_provider_for_screen().
599  *
600  * Since: 3.0
601  **/
602 void
gtk_style_context_add_provider(GtkStyleContext * context,GtkStyleProvider * provider,guint priority)603 gtk_style_context_add_provider (GtkStyleContext  *context,
604                                 GtkStyleProvider *provider,
605                                 guint             priority)
606 {
607   GtkStyleContextPrivate *priv;
608 
609   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
610   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
611 
612   priv = context->priv;
613 
614   if (!gtk_style_context_has_custom_cascade (context))
615     {
616       GtkStyleCascade *new_cascade;
617 
618       new_cascade = _gtk_style_cascade_new ();
619       _gtk_style_cascade_set_scale (new_cascade, _gtk_style_cascade_get_scale (priv->cascade));
620       _gtk_style_cascade_set_parent (new_cascade,
621                                      _gtk_settings_get_style_cascade (gtk_settings_get_for_screen (priv->screen), 1));
622       _gtk_style_cascade_add_provider (new_cascade, provider, priority);
623       gtk_style_context_set_cascade (context, new_cascade);
624       g_object_unref (new_cascade);
625     }
626   else
627     {
628       _gtk_style_cascade_add_provider (priv->cascade, provider, priority);
629     }
630 }
631 
632 /**
633  * gtk_style_context_remove_provider:
634  * @context: a #GtkStyleContext
635  * @provider: a #GtkStyleProvider
636  *
637  * Removes @provider from the style providers list in @context.
638  *
639  * Since: 3.0
640  **/
641 void
gtk_style_context_remove_provider(GtkStyleContext * context,GtkStyleProvider * provider)642 gtk_style_context_remove_provider (GtkStyleContext  *context,
643                                    GtkStyleProvider *provider)
644 {
645   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
646   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
647 
648   if (!gtk_style_context_has_custom_cascade (context))
649     return;
650 
651   _gtk_style_cascade_remove_provider (context->priv->cascade, provider);
652 }
653 
654 /**
655  * gtk_style_context_reset_widgets:
656  * @screen: a #GdkScreen
657  *
658  * This function recomputes the styles for all widgets under a particular
659  * #GdkScreen. This is useful when some global parameter has changed that
660  * affects the appearance of all widgets, because when a widget gets a new
661  * style, it will both redraw and recompute any cached information about
662  * its appearance. As an example, it is used when the color scheme changes
663  * in the related #GtkSettings object.
664  *
665  * Since: 3.0
666  **/
667 void
gtk_style_context_reset_widgets(GdkScreen * screen)668 gtk_style_context_reset_widgets (GdkScreen *screen)
669 {
670   GList *list, *toplevels;
671 
672   toplevels = gtk_window_list_toplevels ();
673   g_list_foreach (toplevels, (GFunc) g_object_ref, NULL);
674 
675   for (list = toplevels; list; list = list->next)
676     {
677       if (gtk_widget_get_screen (list->data) == screen)
678         gtk_widget_reset_style (list->data);
679 
680       g_object_unref (list->data);
681     }
682 
683   g_list_free (toplevels);
684 }
685 
686 /**
687  * gtk_style_context_add_provider_for_screen:
688  * @screen: a #GdkScreen
689  * @provider: a #GtkStyleProvider
690  * @priority: the priority of the style provider. The lower
691  *            it is, the earlier it will be used in the style
692  *            construction. Typically this will be in the range
693  *            between %GTK_STYLE_PROVIDER_PRIORITY_FALLBACK and
694  *            %GTK_STYLE_PROVIDER_PRIORITY_USER
695  *
696  * Adds a global style provider to @screen, which will be used
697  * in style construction for all #GtkStyleContexts under @screen.
698  *
699  * GTK+ uses this to make styling information from #GtkSettings
700  * available.
701  *
702  * Note: If both priorities are the same, A #GtkStyleProvider
703  * added through gtk_style_context_add_provider() takes precedence
704  * over another added through this function.
705  *
706  * Since: 3.0
707  **/
708 void
gtk_style_context_add_provider_for_screen(GdkScreen * screen,GtkStyleProvider * provider,guint priority)709 gtk_style_context_add_provider_for_screen (GdkScreen        *screen,
710                                            GtkStyleProvider *provider,
711                                            guint             priority)
712 {
713   GtkStyleCascade *cascade;
714 
715   g_return_if_fail (GDK_IS_SCREEN (screen));
716   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
717   g_return_if_fail (!GTK_IS_SETTINGS (provider) || _gtk_settings_get_screen (GTK_SETTINGS (provider)) == screen);
718 
719   cascade = _gtk_settings_get_style_cascade (gtk_settings_get_for_screen (screen), 1);
720   _gtk_style_cascade_add_provider (cascade, provider, priority);
721 }
722 
723 /**
724  * gtk_style_context_remove_provider_for_screen:
725  * @screen: a #GdkScreen
726  * @provider: a #GtkStyleProvider
727  *
728  * Removes @provider from the global style providers list in @screen.
729  *
730  * Since: 3.0
731  **/
732 void
gtk_style_context_remove_provider_for_screen(GdkScreen * screen,GtkStyleProvider * provider)733 gtk_style_context_remove_provider_for_screen (GdkScreen        *screen,
734                                               GtkStyleProvider *provider)
735 {
736   GtkStyleCascade *cascade;
737 
738   g_return_if_fail (GDK_IS_SCREEN (screen));
739   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
740   g_return_if_fail (!GTK_IS_SETTINGS (provider));
741 
742   cascade = _gtk_settings_get_style_cascade (gtk_settings_get_for_screen (screen), 1);
743   _gtk_style_cascade_remove_provider (cascade, provider);
744 }
745 
746 /**
747  * gtk_style_context_get_section:
748  * @context: a #GtkStyleContext
749  * @property: style property name
750  *
751  * Queries the location in the CSS where @property was defined for the
752  * current @context. Note that the state to be queried is taken from
753  * gtk_style_context_get_state().
754  *
755  * If the location is not available, %NULL will be returned. The
756  * location might not be available for various reasons, such as the
757  * property being overridden, @property not naming a supported CSS
758  * property or tracking of definitions being disabled for performance
759  * reasons.
760  *
761  * Shorthand CSS properties cannot be queried for a location and will
762  * always return %NULL.
763  *
764  * Returns: (nullable) (transfer none): %NULL or the section where a value
765  * for @property was defined
766  **/
767 GtkCssSection *
gtk_style_context_get_section(GtkStyleContext * context,const gchar * property)768 gtk_style_context_get_section (GtkStyleContext *context,
769                                const gchar     *property)
770 {
771   GtkCssStyle *values;
772   GtkStyleProperty *prop;
773 
774   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
775   g_return_val_if_fail (property != NULL, NULL);
776 
777   prop = _gtk_style_property_lookup (property);
778   if (!GTK_IS_CSS_STYLE_PROPERTY (prop))
779     return NULL;
780 
781   values = gtk_style_context_lookup_style (context);
782   return gtk_css_style_get_section (values, _gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (prop)));
783 }
784 
785 static GtkCssValue *
gtk_style_context_query_func(guint id,gpointer values)786 gtk_style_context_query_func (guint    id,
787                               gpointer values)
788 {
789   return gtk_css_style_get_value (values, id);
790 }
791 
792 /**
793  * gtk_style_context_get_property:
794  * @context: a #GtkStyleContext
795  * @property: style property name
796  * @state: state to retrieve the property value for
797  * @value: (out) (transfer full):  return location for the style property value
798  *
799  * Gets a style property from @context for the given state.
800  *
801  * Note that not all CSS properties that are supported by GTK+ can be
802  * retrieved in this way, since they may not be representable as #GValue.
803  * GTK+ defines macros for a number of properties that can be used
804  * with this function.
805  *
806  * Note that passing a state other than the current state of @context
807  * is not recommended unless the style context has been saved with
808  * gtk_style_context_save().
809  *
810  * When @value is no longer needed, g_value_unset() must be called
811  * to free any allocated memory.
812  *
813  * Since: 3.0
814  **/
815 void
gtk_style_context_get_property(GtkStyleContext * context,const gchar * property,GtkStateFlags state,GValue * value)816 gtk_style_context_get_property (GtkStyleContext *context,
817                                 const gchar     *property,
818                                 GtkStateFlags    state,
819                                 GValue          *value)
820 {
821   GtkStateFlags saved_state;
822   GtkStyleProperty *prop;
823 
824   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
825   g_return_if_fail (property != NULL);
826   g_return_if_fail (value != NULL);
827 
828   prop = _gtk_style_property_lookup (property);
829   if (prop == NULL)
830     {
831       g_warning ("Style property \"%s\" is not registered", property);
832       return;
833     }
834   if (_gtk_style_property_get_value_type (prop) == G_TYPE_NONE)
835     {
836       g_warning ("Style property \"%s\" is not gettable", property);
837       return;
838     }
839 
840   saved_state = gtk_style_context_push_state (context, state);
841   _gtk_style_property_query (prop,
842                              value,
843                              gtk_style_context_query_func,
844                              gtk_css_node_get_style (context->priv->cssnode));
845   gtk_style_context_pop_state (context, saved_state);
846 }
847 
848 /**
849  * gtk_style_context_get_valist:
850  * @context: a #GtkStyleContext
851  * @state: state to retrieve the property values for
852  * @args: va_list of property name/return location pairs, followed by %NULL
853  *
854  * Retrieves several style property values from @context for a given state.
855  *
856  * See gtk_style_context_get_property() for details.
857  *
858  * Since: 3.0
859  */
860 void
gtk_style_context_get_valist(GtkStyleContext * context,GtkStateFlags state,va_list args)861 gtk_style_context_get_valist (GtkStyleContext *context,
862                               GtkStateFlags    state,
863                               va_list          args)
864 {
865   const gchar *property_name;
866 
867   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
868 
869   property_name = va_arg (args, const gchar *);
870 
871   while (property_name)
872     {
873       gchar *error = NULL;
874       GValue value = G_VALUE_INIT;
875 
876       gtk_style_context_get_property (context,
877                                       property_name,
878                                       state,
879                                       &value);
880 
881       G_VALUE_LCOPY (&value, args, 0, &error);
882       g_value_unset (&value);
883 
884       if (error)
885         {
886           g_warning ("Could not get style property \"%s\": %s", property_name, error);
887           g_free (error);
888           break;
889         }
890 
891       property_name = va_arg (args, const gchar *);
892     }
893 }
894 
895 /**
896  * gtk_style_context_get:
897  * @context: a #GtkStyleContext
898  * @state: state to retrieve the property values for
899  * @...: property name /return value pairs, followed by %NULL
900  *
901  * Retrieves several style property values from @context for a
902  * given state.
903  *
904  * See gtk_style_context_get_property() for details.
905  *
906  * Since: 3.0
907  */
908 void
gtk_style_context_get(GtkStyleContext * context,GtkStateFlags state,...)909 gtk_style_context_get (GtkStyleContext *context,
910                        GtkStateFlags    state,
911                        ...)
912 {
913   va_list args;
914 
915   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
916 
917   va_start (args, state);
918   gtk_style_context_get_valist (context, state, args);
919   va_end (args);
920 }
921 
922 /*
923  * gtk_style_context_set_id:
924  * @context: a #GtkStyleContext
925  * @id: (allow-none): the id to use or %NULL for none.
926  *
927  * Sets the CSS ID to be used when obtaining style information.
928  **/
929 void
gtk_style_context_set_id(GtkStyleContext * context,const char * id)930 gtk_style_context_set_id (GtkStyleContext *context,
931                           const char      *id)
932 {
933   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
934 
935   gtk_css_node_set_id (context->priv->cssnode, id);
936 }
937 
938 /*
939  * gtk_style_context_get_id:
940  * @context: a #GtkStyleContext
941  *
942  * Returns the CSS ID used when obtaining style information.
943  *
944  * Returns: (nullable): the ID or %NULL if no ID is set.
945  **/
946 const char *
gtk_style_context_get_id(GtkStyleContext * context)947 gtk_style_context_get_id (GtkStyleContext *context)
948 {
949   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
950 
951   return gtk_css_node_get_id (context->priv->cssnode);
952 }
953 
954 /**
955  * gtk_style_context_set_state:
956  * @context: a #GtkStyleContext
957  * @flags: state to represent
958  *
959  * Sets the state to be used for style matching.
960  *
961  * Since: 3.0
962  **/
963 void
gtk_style_context_set_state(GtkStyleContext * context,GtkStateFlags flags)964 gtk_style_context_set_state (GtkStyleContext *context,
965                              GtkStateFlags    flags)
966 {
967   GtkStateFlags old_flags;
968 
969   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
970 
971   old_flags = gtk_css_node_get_state (context->priv->cssnode);
972 
973   gtk_css_node_set_state (context->priv->cssnode, flags);
974 
975   if (((old_flags ^ flags) & (GTK_STATE_FLAG_DIR_LTR | GTK_STATE_FLAG_DIR_RTL)) &&
976       !gtk_style_context_is_saved (context))
977     g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_DIRECTION]);
978 }
979 
980 /**
981  * gtk_style_context_get_state:
982  * @context: a #GtkStyleContext
983  *
984  * Returns the state used for style matching.
985  *
986  * This method should only be used to retrieve the #GtkStateFlags
987  * to pass to #GtkStyleContext methods, like gtk_style_context_get_padding().
988  * If you need to retrieve the current state of a #GtkWidget, use
989  * gtk_widget_get_state_flags().
990  *
991  * Returns: the state flags
992  *
993  * Since: 3.0
994  **/
995 GtkStateFlags
gtk_style_context_get_state(GtkStyleContext * context)996 gtk_style_context_get_state (GtkStyleContext *context)
997 {
998   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
999 
1000   return gtk_css_node_get_state (context->priv->cssnode);
1001 }
1002 
1003 /**
1004  * gtk_style_context_set_scale:
1005  * @context: a #GtkStyleContext
1006  * @scale: scale
1007  *
1008  * Sets the scale to use when getting image assets for the style.
1009  *
1010  * Since: 3.10
1011  **/
1012 void
gtk_style_context_set_scale(GtkStyleContext * context,gint scale)1013 gtk_style_context_set_scale (GtkStyleContext *context,
1014                              gint             scale)
1015 {
1016   GtkStyleContextPrivate *priv;
1017 
1018   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1019 
1020   priv = context->priv;
1021 
1022   if (scale == _gtk_style_cascade_get_scale (priv->cascade))
1023     return;
1024 
1025   if (gtk_style_context_has_custom_cascade (context))
1026     {
1027       _gtk_style_cascade_set_scale (priv->cascade, scale);
1028     }
1029   else
1030     {
1031       GtkStyleCascade *new_cascade;
1032 
1033       new_cascade = _gtk_settings_get_style_cascade (gtk_settings_get_for_screen (priv->screen),
1034                                                      scale);
1035       gtk_style_context_set_cascade (context, new_cascade);
1036     }
1037 }
1038 
1039 /**
1040  * gtk_style_context_get_scale:
1041  * @context: a #GtkStyleContext
1042  *
1043  * Returns the scale used for assets.
1044  *
1045  * Returns: the scale
1046  *
1047  * Since: 3.10
1048  **/
1049 gint
gtk_style_context_get_scale(GtkStyleContext * context)1050 gtk_style_context_get_scale (GtkStyleContext *context)
1051 {
1052   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
1053 
1054   return _gtk_style_cascade_get_scale (context->priv->cascade);
1055 }
1056 
1057 /**
1058  * gtk_style_context_state_is_running:
1059  * @context: a #GtkStyleContext
1060  * @state: a widget state
1061  * @progress: (out): return location for the transition progress
1062  *
1063  * Returns %TRUE if there is a transition animation running for the
1064  * current region (see gtk_style_context_push_animatable_region()).
1065  *
1066  * If @progress is not %NULL, the animation progress will be returned
1067  * there, 0.0 means the state is closest to being unset, while 1.0 means
1068  * it’s closest to being set. This means transition animation will
1069  * run from 0 to 1 when @state is being set and from 1 to 0 when
1070  * it’s being unset.
1071  *
1072  * Returns: %TRUE if there is a running transition animation for @state.
1073  *
1074  * Since: 3.0
1075  *
1076  * Deprecated: 3.6: This function always returns %FALSE
1077  **/
1078 gboolean
gtk_style_context_state_is_running(GtkStyleContext * context,GtkStateType state,gdouble * progress)1079 gtk_style_context_state_is_running (GtkStyleContext *context,
1080                                     GtkStateType     state,
1081                                     gdouble         *progress)
1082 {
1083   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1084 
1085   return FALSE;
1086 }
1087 
1088 /**
1089  * gtk_style_context_set_path:
1090  * @context: a #GtkStyleContext
1091  * @path: a #GtkWidgetPath
1092  *
1093  * Sets the #GtkWidgetPath used for style matching. As a
1094  * consequence, the style will be regenerated to match
1095  * the new given path.
1096  *
1097  * If you are using a #GtkStyleContext returned from
1098  * gtk_widget_get_style_context(), you do not need to call
1099  * this yourself.
1100  *
1101  * Since: 3.0
1102  **/
1103 void
gtk_style_context_set_path(GtkStyleContext * context,GtkWidgetPath * path)1104 gtk_style_context_set_path (GtkStyleContext *context,
1105                             GtkWidgetPath   *path)
1106 {
1107   GtkCssNode *root;
1108 
1109   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1110   g_return_if_fail (path != NULL);
1111 
1112   root = gtk_style_context_get_root (context);
1113   g_return_if_fail (GTK_IS_CSS_PATH_NODE (root));
1114 
1115   if (path && gtk_widget_path_length (path) > 0)
1116     {
1117       GtkWidgetPath *copy = gtk_widget_path_copy (path);
1118       gtk_css_path_node_set_widget_path (GTK_CSS_PATH_NODE (root), copy);
1119       gtk_css_node_set_widget_type (root,
1120                                     gtk_widget_path_iter_get_object_type (copy, -1));
1121       gtk_css_node_set_name (root, gtk_widget_path_iter_get_object_name (copy, -1));
1122       gtk_widget_path_unref (copy);
1123     }
1124   else
1125     {
1126       gtk_css_path_node_set_widget_path (GTK_CSS_PATH_NODE (root), NULL);
1127       gtk_css_node_set_widget_type (root, G_TYPE_NONE);
1128       gtk_css_node_set_name (root, NULL);
1129     }
1130 }
1131 
1132 /**
1133  * gtk_style_context_get_path:
1134  * @context: a #GtkStyleContext
1135  *
1136  * Returns the widget path used for style matching.
1137  *
1138  * Returns: (transfer none): A #GtkWidgetPath
1139  *
1140  * Since: 3.0
1141  **/
1142 const GtkWidgetPath *
gtk_style_context_get_path(GtkStyleContext * context)1143 gtk_style_context_get_path (GtkStyleContext *context)
1144 {
1145   return gtk_css_node_get_widget_path (gtk_style_context_get_root (context));
1146 }
1147 
1148 /**
1149  * gtk_style_context_set_parent:
1150  * @context: a #GtkStyleContext
1151  * @parent: (allow-none): the new parent or %NULL
1152  *
1153  * Sets the parent style context for @context. The parent style
1154  * context is used to implement
1155  * [inheritance](http://www.w3.org/TR/css3-cascade/#inheritance)
1156  * of properties.
1157  *
1158  * If you are using a #GtkStyleContext returned from
1159  * gtk_widget_get_style_context(), the parent will be set for you.
1160  *
1161  * Since: 3.4
1162  **/
1163 void
gtk_style_context_set_parent(GtkStyleContext * context,GtkStyleContext * parent)1164 gtk_style_context_set_parent (GtkStyleContext *context,
1165                               GtkStyleContext *parent)
1166 {
1167   GtkStyleContextPrivate *priv;
1168 
1169   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1170   g_return_if_fail (parent == NULL || GTK_IS_STYLE_CONTEXT (parent));
1171 
1172   priv = context->priv;
1173 
1174   if (priv->parent == parent)
1175     return;
1176 
1177   if (parent)
1178     {
1179       GtkCssNode *root = gtk_style_context_get_root (context);
1180       g_object_ref (parent);
1181 
1182       if (gtk_css_node_get_parent (root) == NULL)
1183         gtk_css_node_set_parent (root, gtk_style_context_get_root (parent));
1184     }
1185   else
1186     {
1187       gtk_css_node_set_parent (gtk_style_context_get_root (context), NULL);
1188     }
1189 
1190   gtk_style_context_clear_parent (context);
1191 
1192   priv->parent = parent;
1193 
1194   g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_PARENT]);
1195   gtk_css_node_invalidate (gtk_style_context_get_root (context), GTK_CSS_CHANGE_ANY_PARENT | GTK_CSS_CHANGE_ANY_SIBLING);
1196 }
1197 
1198 /**
1199  * gtk_style_context_get_parent:
1200  * @context: a #GtkStyleContext
1201  *
1202  * Gets the parent context set via gtk_style_context_set_parent().
1203  * See that function for details.
1204  *
1205  * Returns: (nullable) (transfer none): the parent context or %NULL
1206  *
1207  * Since: 3.4
1208  **/
1209 GtkStyleContext *
gtk_style_context_get_parent(GtkStyleContext * context)1210 gtk_style_context_get_parent (GtkStyleContext *context)
1211 {
1212   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
1213 
1214   return context->priv->parent;
1215 }
1216 
1217 /*
1218  * gtk_style_context_save_to_node:
1219  * @context: a #GtkStyleContext
1220  * @node: the node to save to
1221  *
1222  * Saves the @context state, so temporary modifications done through
1223  * gtk_style_context_add_class(), gtk_style_context_remove_class(),
1224  * gtk_style_context_set_state(), etc. and rendering using
1225  * gtk_render_background() or similar functions are done using the
1226  * given @node.
1227  *
1228  * To undo, call gtk_style_context_restore().
1229  *
1230  * The matching call to gtk_style_context_restore() must be done
1231  * before GTK returns to the main loop.
1232  **/
1233 void
gtk_style_context_save_to_node(GtkStyleContext * context,GtkCssNode * node)1234 gtk_style_context_save_to_node (GtkStyleContext *context,
1235                                 GtkCssNode      *node)
1236 {
1237   GtkStyleContextPrivate *priv;
1238 
1239   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1240   g_return_if_fail (GTK_IS_CSS_NODE (node));
1241 
1242   priv = context->priv;
1243 
1244   priv->saved_nodes = g_slist_prepend (priv->saved_nodes, priv->cssnode);
1245   priv->cssnode = g_object_ref (node);
1246 }
1247 
1248 void
gtk_style_context_save_named(GtkStyleContext * context,const char * name)1249 gtk_style_context_save_named (GtkStyleContext *context,
1250                               const char      *name)
1251 {
1252   GtkStyleContextPrivate *priv;
1253   GtkCssNode *cssnode;
1254 
1255   priv = context->priv;
1256 
1257   /* Make sure we have the style existing. It is the
1258    * parent of the new saved node after all.
1259    */
1260   if (!gtk_style_context_is_saved (context))
1261     gtk_style_context_lookup_style (context);
1262 
1263   cssnode = gtk_css_transient_node_new (priv->cssnode);
1264   gtk_css_node_set_parent (cssnode, gtk_style_context_get_root (context));
1265   if (name)
1266     gtk_css_node_set_name (cssnode, g_intern_string (name));
1267 
1268   gtk_style_context_save_to_node (context, cssnode);
1269 
1270   g_object_unref (cssnode);
1271 }
1272 
1273 /**
1274  * gtk_style_context_save:
1275  * @context: a #GtkStyleContext
1276  *
1277  * Saves the @context state, so temporary modifications done through
1278  * gtk_style_context_add_class(), gtk_style_context_remove_class(),
1279  * gtk_style_context_set_state(), etc. can quickly be reverted
1280  * in one go through gtk_style_context_restore().
1281  *
1282  * The matching call to gtk_style_context_restore() must be done
1283  * before GTK returns to the main loop.
1284  *
1285  * Since: 3.0
1286  **/
1287 void
gtk_style_context_save(GtkStyleContext * context)1288 gtk_style_context_save (GtkStyleContext *context)
1289 {
1290   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1291 
1292   gtk_style_context_save_named (context, NULL);
1293 }
1294 
1295 /**
1296  * gtk_style_context_restore:
1297  * @context: a #GtkStyleContext
1298  *
1299  * Restores @context state to a previous stage.
1300  * See gtk_style_context_save().
1301  *
1302  * Since: 3.0
1303  **/
1304 void
gtk_style_context_restore(GtkStyleContext * context)1305 gtk_style_context_restore (GtkStyleContext *context)
1306 {
1307   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1308 
1309   if (context->priv->saved_nodes == NULL)
1310     {
1311       g_warning ("Unpaired gtk_style_context_restore() call");
1312       return;
1313     }
1314 
1315   gtk_style_context_pop_style_node (context);
1316 }
1317 
1318 /**
1319  * gtk_style_context_add_class:
1320  * @context: a #GtkStyleContext
1321  * @class_name: class name to use in styling
1322  *
1323  * Adds a style class to @context, so posterior calls to
1324  * gtk_style_context_get() or any of the gtk_render_*()
1325  * functions will make use of this new class for styling.
1326  *
1327  * In the CSS file format, a #GtkEntry defining a “search”
1328  * class, would be matched by:
1329  *
1330  * |[ <!-- language="CSS" -->
1331  * entry.search { ... }
1332  * ]|
1333  *
1334  * While any widget defining a “search” class would be
1335  * matched by:
1336  * |[ <!-- language="CSS" -->
1337  * .search { ... }
1338  * ]|
1339  *
1340  * Since: 3.0
1341  **/
1342 void
gtk_style_context_add_class(GtkStyleContext * context,const gchar * class_name)1343 gtk_style_context_add_class (GtkStyleContext *context,
1344                              const gchar     *class_name)
1345 {
1346   GQuark class_quark;
1347 
1348   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1349   g_return_if_fail (class_name != NULL);
1350 
1351   class_quark = g_quark_from_string (class_name);
1352 
1353   gtk_css_node_add_class (context->priv->cssnode, class_quark);
1354 }
1355 
1356 /**
1357  * gtk_style_context_remove_class:
1358  * @context: a #GtkStyleContext
1359  * @class_name: class name to remove
1360  *
1361  * Removes @class_name from @context.
1362  *
1363  * Since: 3.0
1364  **/
1365 void
gtk_style_context_remove_class(GtkStyleContext * context,const gchar * class_name)1366 gtk_style_context_remove_class (GtkStyleContext *context,
1367                                 const gchar     *class_name)
1368 {
1369   GQuark class_quark;
1370 
1371   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1372   g_return_if_fail (class_name != NULL);
1373 
1374   class_quark = g_quark_try_string (class_name);
1375   if (!class_quark)
1376     return;
1377 
1378   gtk_css_node_remove_class (context->priv->cssnode, class_quark);
1379 }
1380 
1381 /**
1382  * gtk_style_context_has_class:
1383  * @context: a #GtkStyleContext
1384  * @class_name: a class name
1385  *
1386  * Returns %TRUE if @context currently has defined the
1387  * given class name.
1388  *
1389  * Returns: %TRUE if @context has @class_name defined
1390  *
1391  * Since: 3.0
1392  **/
1393 gboolean
gtk_style_context_has_class(GtkStyleContext * context,const gchar * class_name)1394 gtk_style_context_has_class (GtkStyleContext *context,
1395                              const gchar     *class_name)
1396 {
1397   GQuark class_quark;
1398 
1399   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1400   g_return_val_if_fail (class_name != NULL, FALSE);
1401 
1402   class_quark = g_quark_try_string (class_name);
1403   if (!class_quark)
1404     return FALSE;
1405 
1406   return gtk_css_node_has_class (context->priv->cssnode, class_quark);
1407 }
1408 
1409 /**
1410  * gtk_style_context_list_classes:
1411  * @context: a #GtkStyleContext
1412  *
1413  * Returns the list of classes currently defined in @context.
1414  *
1415  * Returns: (transfer container) (element-type utf8): a #GList of
1416  *          strings with the currently defined classes. The contents
1417  *          of the list are owned by GTK+, but you must free the list
1418  *          itself with g_list_free() when you are done with it.
1419  *
1420  * Since: 3.0
1421  **/
1422 GList *
gtk_style_context_list_classes(GtkStyleContext * context)1423 gtk_style_context_list_classes (GtkStyleContext *context)
1424 {
1425   GList *classes_list = NULL;
1426   const GQuark *classes;
1427   guint n_classes, i;
1428 
1429   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
1430 
1431   classes = gtk_css_node_list_classes (context->priv->cssnode, &n_classes);
1432   for (i = n_classes; i > 0; i--)
1433     classes_list = g_list_prepend (classes_list, (gchar *)g_quark_to_string (classes[i - 1]));
1434 
1435   return classes_list;
1436 }
1437 
1438 /**
1439  * gtk_style_context_list_regions:
1440  * @context: a #GtkStyleContext
1441  *
1442  * Returns the list of regions currently defined in @context.
1443  *
1444  * Returns: (transfer container) (element-type utf8): a #GList of
1445  *          strings with the currently defined regions. The contents
1446  *          of the list are owned by GTK+, but you must free the list
1447  *          itself with g_list_free() when you are done with it.
1448  *
1449  * Since: 3.0
1450  *
1451  * Deprecated: 3.14
1452  **/
1453 GList *
gtk_style_context_list_regions(GtkStyleContext * context)1454 gtk_style_context_list_regions (GtkStyleContext *context)
1455 {
1456   GList *regions, *l;
1457 
1458   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
1459 
1460   regions = gtk_css_node_list_regions (context->priv->cssnode);
1461   for (l = regions; l; l = l->next)
1462     l->data = (char *) g_quark_to_string (GPOINTER_TO_UINT (l->data));
1463 
1464   return regions;
1465 }
1466 
1467 gboolean
_gtk_style_context_check_region_name(const gchar * str)1468 _gtk_style_context_check_region_name (const gchar *str)
1469 {
1470   g_return_val_if_fail (str != NULL, FALSE);
1471 
1472   if (!g_ascii_islower (str[0]))
1473     return FALSE;
1474 
1475   while (*str)
1476     {
1477       if (*str != '-' &&
1478           !g_ascii_islower (*str))
1479         return FALSE;
1480 
1481       str++;
1482     }
1483 
1484   return TRUE;
1485 }
1486 
1487 /**
1488  * gtk_style_context_add_region:
1489  * @context: a #GtkStyleContext
1490  * @region_name: region name to use in styling
1491  * @flags: flags that apply to the region
1492  *
1493  * Adds a region to @context, so posterior calls to
1494  * gtk_style_context_get() or any of the gtk_render_*()
1495  * functions will make use of this new region for styling.
1496  *
1497  * In the CSS file format, a #GtkTreeView defining a “row”
1498  * region, would be matched by:
1499  *
1500  * |[ <!-- language="CSS" -->
1501  * treeview row { ... }
1502  * ]|
1503  *
1504  * Pseudo-classes are used for matching @flags, so the two
1505  * following rules:
1506  * |[ <!-- language="CSS" -->
1507  * treeview row:nth-child(even) { ... }
1508  * treeview row:nth-child(odd) { ... }
1509  * ]|
1510  *
1511  * would apply to even and odd rows, respectively.
1512  *
1513  * Region names must only contain lowercase letters
1514  * and “-”, starting always with a lowercase letter.
1515  *
1516  * Since: 3.0
1517  *
1518  * Deprecated: 3.14
1519  **/
1520 void
gtk_style_context_add_region(GtkStyleContext * context,const gchar * region_name,GtkRegionFlags flags)1521 gtk_style_context_add_region (GtkStyleContext *context,
1522                               const gchar     *region_name,
1523                               GtkRegionFlags   flags)
1524 {
1525   GQuark region_quark;
1526 
1527   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1528   g_return_if_fail (region_name != NULL);
1529   g_return_if_fail (_gtk_style_context_check_region_name (region_name));
1530 
1531   region_quark = g_quark_from_string (region_name);
1532 
1533   gtk_css_node_add_region (context->priv->cssnode, region_quark, flags);
1534 }
1535 
1536 /**
1537  * gtk_style_context_remove_region:
1538  * @context: a #GtkStyleContext
1539  * @region_name: region name to unset
1540  *
1541  * Removes a region from @context.
1542  *
1543  * Since: 3.0
1544  *
1545  * Deprecated: 3.14
1546  **/
1547 void
gtk_style_context_remove_region(GtkStyleContext * context,const gchar * region_name)1548 gtk_style_context_remove_region (GtkStyleContext *context,
1549                                  const gchar     *region_name)
1550 {
1551   GQuark region_quark;
1552 
1553   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1554   g_return_if_fail (region_name != NULL);
1555 
1556   region_quark = g_quark_try_string (region_name);
1557   if (!region_quark)
1558     return;
1559 
1560   gtk_css_node_remove_region (context->priv->cssnode, region_quark);
1561 }
1562 
1563 /**
1564  * gtk_style_context_has_region:
1565  * @context: a #GtkStyleContext
1566  * @region_name: a region name
1567  * @flags_return: (out) (allow-none): return location for region flags
1568  *
1569  * Returns %TRUE if @context has the region defined.
1570  * If @flags_return is not %NULL, it is set to the flags
1571  * affecting the region.
1572  *
1573  * Returns: %TRUE if region is defined
1574  *
1575  * Since: 3.0
1576  *
1577  * Deprecated: 3.14
1578  **/
1579 gboolean
gtk_style_context_has_region(GtkStyleContext * context,const gchar * region_name,GtkRegionFlags * flags_return)1580 gtk_style_context_has_region (GtkStyleContext *context,
1581                               const gchar     *region_name,
1582                               GtkRegionFlags  *flags_return)
1583 {
1584   GQuark region_quark;
1585 
1586   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
1587   g_return_val_if_fail (region_name != NULL, FALSE);
1588 
1589   if (flags_return)
1590     *flags_return = 0;
1591 
1592   region_quark = g_quark_try_string (region_name);
1593   if (!region_quark)
1594     return FALSE;
1595 
1596   return gtk_css_node_has_region (context->priv->cssnode, region_quark, flags_return);
1597 }
1598 
1599 static gint
style_property_values_cmp(gconstpointer bsearch_node1,gconstpointer bsearch_node2)1600 style_property_values_cmp (gconstpointer bsearch_node1,
1601                            gconstpointer bsearch_node2)
1602 {
1603   const PropertyValue *val1 = bsearch_node1;
1604   const PropertyValue *val2 = bsearch_node2;
1605 
1606   if (val1->widget_type != val2->widget_type)
1607     return val1->widget_type < val2->widget_type ? -1 : 1;
1608 
1609   if (val1->pspec != val2->pspec)
1610     return val1->pspec < val2->pspec ? -1 : 1;
1611 
1612   return 0;
1613 }
1614 
1615 GtkCssValue *
_gtk_style_context_peek_property(GtkStyleContext * context,guint property_id)1616 _gtk_style_context_peek_property (GtkStyleContext *context,
1617                                   guint            property_id)
1618 {
1619   GtkCssStyle *values = gtk_style_context_lookup_style (context);
1620 
1621   return gtk_css_style_get_value (values, property_id);
1622 }
1623 
1624 const GValue *
_gtk_style_context_peek_style_property(GtkStyleContext * context,GType widget_type,GParamSpec * pspec)1625 _gtk_style_context_peek_style_property (GtkStyleContext *context,
1626                                         GType            widget_type,
1627                                         GParamSpec      *pspec)
1628 {
1629   GtkStyleContextPrivate *priv;
1630   GtkWidgetPath *path;
1631   PropertyValue *pcache, key = { 0 };
1632   guint i;
1633 
1634   priv = context->priv;
1635 
1636   /* ensure the style cache is valid by forcing a validation */
1637   gtk_style_context_lookup_style (context);
1638 
1639   key.widget_type = widget_type;
1640   key.pspec = pspec;
1641 
1642   /* need value cache array */
1643   pcache = bsearch (&key,
1644                     priv->property_cache->data, priv->property_cache->len,
1645                     sizeof (PropertyValue), style_property_values_cmp);
1646   if (pcache)
1647     return &pcache->value;
1648 
1649   i = 0;
1650   while (i < priv->property_cache->len &&
1651          style_property_values_cmp (&key, &g_array_index (priv->property_cache, PropertyValue, i)) >= 0)
1652     i++;
1653 
1654   g_array_insert_val (priv->property_cache, i, key);
1655   pcache = &g_array_index (priv->property_cache, PropertyValue, i);
1656 
1657   /* cache miss, initialize value type, then set contents */
1658   g_param_spec_ref (pcache->pspec);
1659   g_value_init (&pcache->value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1660 
1661   path = gtk_css_node_create_widget_path (gtk_style_context_get_root (context));
1662   if (path && gtk_widget_path_length (path) > 0)
1663     {
1664       if (gtk_style_provider_get_style_property (GTK_STYLE_PROVIDER (priv->cascade),
1665                                                  path,
1666                                                  gtk_widget_path_iter_get_state (path, -1),
1667                                                  pspec, &pcache->value))
1668         {
1669           G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1670 
1671           /* Resolve symbolic colors to GdkColor/GdkRGBA */
1672           if (G_VALUE_TYPE (&pcache->value) == GTK_TYPE_SYMBOLIC_COLOR)
1673             {
1674               GtkSymbolicColor *color;
1675               GdkRGBA rgba;
1676 
1677               color = g_value_dup_boxed (&pcache->value);
1678 
1679               g_value_unset (&pcache->value);
1680 
1681               if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
1682                 g_value_init (&pcache->value, GDK_TYPE_RGBA);
1683               else
1684                 g_value_init (&pcache->value, GDK_TYPE_COLOR);
1685 
1686               if (_gtk_style_context_resolve_color (context, _gtk_symbolic_color_get_css_value (color), &rgba))
1687                 {
1688                   if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
1689                     g_value_set_boxed (&pcache->value, &rgba);
1690                   else
1691                     {
1692                       GdkColor rgb;
1693 
1694                       rgb.red = rgba.red * 65535. + 0.5;
1695                       rgb.green = rgba.green * 65535. + 0.5;
1696                       rgb.blue = rgba.blue * 65535. + 0.5;
1697 
1698                       g_value_set_boxed (&pcache->value, &rgb);
1699                     }
1700                 }
1701               else
1702                 g_param_value_set_default (pspec, &pcache->value);
1703 
1704               gtk_symbolic_color_unref (color);
1705             }
1706 
1707           G_GNUC_END_IGNORE_DEPRECATIONS;
1708 
1709           gtk_widget_path_unref (path);
1710 
1711           return &pcache->value;
1712         }
1713     }
1714 
1715   gtk_widget_path_unref (path);
1716 
1717   /* not supplied by any provider, revert to default */
1718   g_param_value_set_default (pspec, &pcache->value);
1719 
1720   return &pcache->value;
1721 }
1722 
1723 /**
1724  * gtk_style_context_get_style_property:
1725  * @context: a #GtkStyleContext
1726  * @property_name: the name of the widget style property
1727  * @value: Return location for the property value
1728  *
1729  * Gets the value for a widget style property.
1730  *
1731  * When @value is no longer needed, g_value_unset() must be called
1732  * to free any allocated memory.
1733  **/
1734 void
gtk_style_context_get_style_property(GtkStyleContext * context,const gchar * property_name,GValue * value)1735 gtk_style_context_get_style_property (GtkStyleContext *context,
1736                                       const gchar     *property_name,
1737                                       GValue          *value)
1738 {
1739   GtkCssNode *root;
1740   GtkWidgetClass *widget_class;
1741   GParamSpec *pspec;
1742   const GValue *peek_value;
1743   GType widget_type;
1744 
1745   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1746   g_return_if_fail (property_name != NULL);
1747   g_return_if_fail (value != NULL);
1748 
1749   root = gtk_style_context_get_root (context);
1750 
1751   if (GTK_IS_CSS_WIDGET_NODE (root))
1752     {
1753       GtkWidget *widget;
1754 
1755       widget = gtk_css_widget_node_get_widget (GTK_CSS_WIDGET_NODE (root));
1756       if (widget == NULL)
1757         return;
1758 
1759       widget_type = G_OBJECT_TYPE (widget);
1760     }
1761   else if (GTK_IS_CSS_PATH_NODE (root))
1762     {
1763       GtkWidgetPath *path;
1764 
1765       path = gtk_css_path_node_get_widget_path (GTK_CSS_PATH_NODE (root));
1766       if (path == NULL)
1767         return;
1768 
1769       widget_type = gtk_widget_path_get_object_type (path);
1770 
1771       if (!g_type_is_a (widget_type, GTK_TYPE_WIDGET))
1772         {
1773           g_warning ("%s: can't get style properties for non-widget class '%s'",
1774                      G_STRLOC,
1775                      g_type_name (widget_type));
1776           return;
1777         }
1778     }
1779   else
1780     {
1781       return;
1782     }
1783 
1784   widget_class = g_type_class_ref (widget_type);
1785   pspec = gtk_widget_class_find_style_property (widget_class, property_name);
1786   g_type_class_unref (widget_class);
1787 
1788   if (!pspec)
1789     {
1790       g_warning ("%s: widget class '%s' has no style property named '%s'",
1791                  G_STRLOC,
1792                  g_type_name (widget_type),
1793                  property_name);
1794       return;
1795     }
1796 
1797   peek_value = _gtk_style_context_peek_style_property (context, widget_type, pspec);
1798 
1799   if (G_VALUE_TYPE (value) == G_VALUE_TYPE (peek_value))
1800     g_value_copy (peek_value, value);
1801   else if (g_value_type_transformable (G_VALUE_TYPE (peek_value), G_VALUE_TYPE (value)))
1802     g_value_transform (peek_value, value);
1803   else
1804     g_warning ("can't retrieve style property '%s' of type '%s' as value of type '%s'",
1805                pspec->name,
1806                G_VALUE_TYPE_NAME (peek_value),
1807                G_VALUE_TYPE_NAME (value));
1808 }
1809 
1810 /**
1811  * gtk_style_context_get_style_valist:
1812  * @context: a #GtkStyleContext
1813  * @args: va_list of property name/return location pairs, followed by %NULL
1814  *
1815  * Retrieves several widget style properties from @context according to the
1816  * current style.
1817  *
1818  * Since: 3.0
1819  **/
1820 void
gtk_style_context_get_style_valist(GtkStyleContext * context,va_list args)1821 gtk_style_context_get_style_valist (GtkStyleContext *context,
1822                                     va_list          args)
1823 {
1824   GtkCssNode *root;
1825   const gchar *prop_name;
1826   GType widget_type;
1827 
1828   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1829 
1830   prop_name = va_arg (args, const gchar *);
1831   root = gtk_style_context_get_root (context);
1832 
1833   if (GTK_IS_CSS_WIDGET_NODE (root))
1834     {
1835       GtkWidget *widget;
1836 
1837       widget = gtk_css_widget_node_get_widget (GTK_CSS_WIDGET_NODE (root));
1838       if (widget == NULL)
1839         return;
1840 
1841       widget_type = G_OBJECT_TYPE (widget);
1842     }
1843   else if (GTK_IS_CSS_PATH_NODE (root))
1844     {
1845       GtkWidgetPath *path;
1846 
1847       path = gtk_css_path_node_get_widget_path (GTK_CSS_PATH_NODE (root));
1848       if (path == NULL)
1849         return;
1850 
1851       widget_type = gtk_widget_path_get_object_type (path);
1852 
1853       if (!g_type_is_a (widget_type, GTK_TYPE_WIDGET))
1854         {
1855           g_warning ("%s: can't get style properties for non-widget class '%s'",
1856                      G_STRLOC,
1857                      g_type_name (widget_type));
1858           return;
1859         }
1860     }
1861   else
1862     {
1863       return;
1864     }
1865 
1866   while (prop_name)
1867     {
1868       GtkWidgetClass *widget_class;
1869       GParamSpec *pspec;
1870       const GValue *peek_value;
1871       gchar *error;
1872 
1873       widget_class = g_type_class_ref (widget_type);
1874       pspec = gtk_widget_class_find_style_property (widget_class, prop_name);
1875       g_type_class_unref (widget_class);
1876 
1877       if (!pspec)
1878         {
1879           g_warning ("%s: widget class '%s' has no style property named '%s'",
1880                      G_STRLOC,
1881                      g_type_name (widget_type),
1882                      prop_name);
1883           break;
1884         }
1885 
1886       peek_value = _gtk_style_context_peek_style_property (context, widget_type, pspec);
1887 
1888       G_VALUE_LCOPY (peek_value, args, 0, &error);
1889 
1890       if (error)
1891         {
1892           g_warning ("can't retrieve style property '%s' of type '%s': %s",
1893                      pspec->name,
1894                      G_VALUE_TYPE_NAME (peek_value),
1895                      error);
1896           g_free (error);
1897           break;
1898         }
1899 
1900       prop_name = va_arg (args, const gchar *);
1901     }
1902 }
1903 
1904 /**
1905  * gtk_style_context_get_style:
1906  * @context: a #GtkStyleContext
1907  * @...: property name /return value pairs, followed by %NULL
1908  *
1909  * Retrieves several widget style properties from @context according to the
1910  * current style.
1911  *
1912  * Since: 3.0
1913  **/
1914 void
gtk_style_context_get_style(GtkStyleContext * context,...)1915 gtk_style_context_get_style (GtkStyleContext *context,
1916                              ...)
1917 {
1918   va_list args;
1919 
1920   va_start (args, context);
1921   gtk_style_context_get_style_valist (context, args);
1922   va_end (args);
1923 }
1924 
1925 
1926 /**
1927  * gtk_style_context_lookup_icon_set:
1928  * @context: a #GtkStyleContext
1929  * @stock_id: an icon name
1930  *
1931  * Looks up @stock_id in the icon factories associated to @context and
1932  * the default icon factory, returning an icon set if found, otherwise
1933  * %NULL.
1934  *
1935  * Returns: (nullable) (transfer none): The looked up %GtkIconSet, or %NULL
1936  *
1937  * Deprecated: 3.10: Use gtk_icon_theme_lookup_icon() instead.
1938  **/
1939 GtkIconSet *
gtk_style_context_lookup_icon_set(GtkStyleContext * context,const gchar * stock_id)1940 gtk_style_context_lookup_icon_set (GtkStyleContext *context,
1941                                    const gchar     *stock_id)
1942 {
1943   GtkIconSet *icon_set;
1944 
1945   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
1946   g_return_val_if_fail (stock_id != NULL, NULL);
1947 
1948   G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1949 
1950   icon_set = gtk_icon_factory_lookup_default (stock_id);
1951 
1952   G_GNUC_END_IGNORE_DEPRECATIONS;
1953 
1954   return icon_set;
1955 }
1956 
1957 /**
1958  * gtk_style_context_set_screen:
1959  * @context: a #GtkStyleContext
1960  * @screen: a #GdkScreen
1961  *
1962  * Attaches @context to the given screen.
1963  *
1964  * The screen is used to add style information from “global” style
1965  * providers, such as the screen’s #GtkSettings instance.
1966  *
1967  * If you are using a #GtkStyleContext returned from
1968  * gtk_widget_get_style_context(), you do not need to
1969  * call this yourself.
1970  *
1971  * Since: 3.0
1972  **/
1973 void
gtk_style_context_set_screen(GtkStyleContext * context,GdkScreen * screen)1974 gtk_style_context_set_screen (GtkStyleContext *context,
1975                               GdkScreen       *screen)
1976 {
1977   GtkStyleContextPrivate *priv;
1978   GtkStyleCascade *screen_cascade;
1979 
1980   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
1981   g_return_if_fail (GDK_IS_SCREEN (screen));
1982 
1983   priv = context->priv;
1984   if (priv->screen == screen)
1985     return;
1986 
1987   if (gtk_style_context_has_custom_cascade (context))
1988     {
1989       screen_cascade = _gtk_settings_get_style_cascade (gtk_settings_get_for_screen (screen), 1);
1990       _gtk_style_cascade_set_parent (priv->cascade, screen_cascade);
1991     }
1992   else
1993     {
1994       screen_cascade = _gtk_settings_get_style_cascade (gtk_settings_get_for_screen (screen),
1995                                                         _gtk_style_cascade_get_scale (priv->cascade));
1996       gtk_style_context_set_cascade (context, screen_cascade);
1997     }
1998 
1999   priv->screen = screen;
2000 
2001   g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_SCREEN]);
2002 }
2003 
2004 /**
2005  * gtk_style_context_get_screen:
2006  * @context: a #GtkStyleContext
2007  *
2008  * Returns the #GdkScreen to which @context is attached.
2009  *
2010  * Returns: (transfer none): a #GdkScreen.
2011  **/
2012 GdkScreen *
gtk_style_context_get_screen(GtkStyleContext * context)2013 gtk_style_context_get_screen (GtkStyleContext *context)
2014 {
2015   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2016 
2017   return context->priv->screen;
2018 }
2019 
2020 /**
2021  * gtk_style_context_set_frame_clock:
2022  * @context: a #GdkFrameClock
2023  * @frame_clock: a #GdkFrameClock
2024  *
2025  * Attaches @context to the given frame clock.
2026  *
2027  * The frame clock is used for the timing of animations.
2028  *
2029  * If you are using a #GtkStyleContext returned from
2030  * gtk_widget_get_style_context(), you do not need to
2031  * call this yourself.
2032  *
2033  * Since: 3.8
2034  **/
2035 void
gtk_style_context_set_frame_clock(GtkStyleContext * context,GdkFrameClock * frame_clock)2036 gtk_style_context_set_frame_clock (GtkStyleContext *context,
2037                                    GdkFrameClock   *frame_clock)
2038 {
2039   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2040   g_return_if_fail (frame_clock == NULL || GDK_IS_FRAME_CLOCK (frame_clock));
2041 
2042   if (g_set_object (&context->priv->frame_clock, frame_clock))
2043     g_object_notify_by_pspec (G_OBJECT (context), properties[PROP_FRAME_CLOCK]);
2044 }
2045 
2046 /**
2047  * gtk_style_context_get_frame_clock:
2048  * @context: a #GtkStyleContext
2049  *
2050  * Returns the #GdkFrameClock to which @context is attached.
2051  *
2052  * Returns: (nullable) (transfer none): a #GdkFrameClock, or %NULL
2053  *  if @context does not have an attached frame clock.
2054  *
2055  * Since: 3.8
2056  **/
2057 GdkFrameClock *
gtk_style_context_get_frame_clock(GtkStyleContext * context)2058 gtk_style_context_get_frame_clock (GtkStyleContext *context)
2059 {
2060   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2061 
2062   return context->priv->frame_clock;
2063 }
2064 
2065 /**
2066  * gtk_style_context_set_direction:
2067  * @context: a #GtkStyleContext
2068  * @direction: the new direction.
2069  *
2070  * Sets the reading direction for rendering purposes.
2071  *
2072  * If you are using a #GtkStyleContext returned from
2073  * gtk_widget_get_style_context(), you do not need to
2074  * call this yourself.
2075  *
2076  * Since: 3.0
2077  *
2078  * Deprecated: 3.8: Use gtk_style_context_set_state() with
2079  *   #GTK_STATE_FLAG_DIR_LTR and #GTK_STATE_FLAG_DIR_RTL
2080  *   instead.
2081  **/
2082 void
gtk_style_context_set_direction(GtkStyleContext * context,GtkTextDirection direction)2083 gtk_style_context_set_direction (GtkStyleContext  *context,
2084                                  GtkTextDirection  direction)
2085 {
2086   GtkStateFlags state;
2087 
2088   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2089 
2090   state = gtk_style_context_get_state (context);
2091   state &= ~(GTK_STATE_FLAG_DIR_LTR | GTK_STATE_FLAG_DIR_RTL);
2092 
2093   switch (direction)
2094     {
2095     case GTK_TEXT_DIR_LTR:
2096       state |= GTK_STATE_FLAG_DIR_LTR;
2097       break;
2098 
2099     case GTK_TEXT_DIR_RTL:
2100       state |= GTK_STATE_FLAG_DIR_RTL;
2101       break;
2102 
2103     case GTK_TEXT_DIR_NONE:
2104     default:
2105       break;
2106     }
2107 
2108   gtk_style_context_set_state (context, state);
2109 }
2110 
2111 /**
2112  * gtk_style_context_get_direction:
2113  * @context: a #GtkStyleContext
2114  *
2115  * Returns the widget direction used for rendering.
2116  *
2117  * Returns: the widget direction
2118  *
2119  * Since: 3.0
2120  *
2121  * Deprecated: 3.8: Use gtk_style_context_get_state() and
2122  *   check for #GTK_STATE_FLAG_DIR_LTR and
2123  *   #GTK_STATE_FLAG_DIR_RTL instead.
2124  **/
2125 GtkTextDirection
gtk_style_context_get_direction(GtkStyleContext * context)2126 gtk_style_context_get_direction (GtkStyleContext *context)
2127 {
2128   GtkStateFlags state;
2129 
2130   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), GTK_TEXT_DIR_LTR);
2131 
2132   state = gtk_style_context_get_state (context);
2133 
2134   if (state & GTK_STATE_FLAG_DIR_LTR)
2135     return GTK_TEXT_DIR_LTR;
2136   else if (state & GTK_STATE_FLAG_DIR_RTL)
2137     return GTK_TEXT_DIR_RTL;
2138   else
2139     return GTK_TEXT_DIR_NONE;
2140 }
2141 
2142 /**
2143  * gtk_style_context_set_junction_sides:
2144  * @context: a #GtkStyleContext
2145  * @sides: sides where rendered elements are visually connected to
2146  *     other elements
2147  *
2148  * Sets the sides where rendered elements (mostly through
2149  * gtk_render_frame()) will visually connect with other visual elements.
2150  *
2151  * This is merely a hint that may or may not be honored
2152  * by themes.
2153  *
2154  * Container widgets are expected to set junction hints as appropriate
2155  * for their children, so it should not normally be necessary to call
2156  * this function manually.
2157  *
2158  * Since: 3.0
2159  **/
2160 void
gtk_style_context_set_junction_sides(GtkStyleContext * context,GtkJunctionSides sides)2161 gtk_style_context_set_junction_sides (GtkStyleContext  *context,
2162                                       GtkJunctionSides  sides)
2163 {
2164   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2165 
2166   gtk_css_node_set_junction_sides (context->priv->cssnode, sides);
2167 }
2168 
2169 /**
2170  * gtk_style_context_get_junction_sides:
2171  * @context: a #GtkStyleContext
2172  *
2173  * Returns the sides where rendered elements connect visually with others.
2174  *
2175  * Returns: the junction sides
2176  *
2177  * Since: 3.0
2178  **/
2179 GtkJunctionSides
gtk_style_context_get_junction_sides(GtkStyleContext * context)2180 gtk_style_context_get_junction_sides (GtkStyleContext *context)
2181 {
2182   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
2183 
2184   return gtk_css_node_get_junction_sides (context->priv->cssnode);
2185 }
2186 
2187 gboolean
_gtk_style_context_resolve_color(GtkStyleContext * context,GtkCssValue * color,GdkRGBA * result)2188 _gtk_style_context_resolve_color (GtkStyleContext    *context,
2189                                   GtkCssValue        *color,
2190                                   GdkRGBA            *result)
2191 {
2192   GtkCssValue *val;
2193 
2194   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2195   g_return_val_if_fail (color != NULL, FALSE);
2196   g_return_val_if_fail (result != NULL, FALSE);
2197 
2198   val = _gtk_css_color_value_resolve (color,
2199                                       GTK_STYLE_PROVIDER_PRIVATE (context->priv->cascade),
2200                                       _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR),
2201                                       NULL);
2202   if (val == NULL)
2203     return FALSE;
2204 
2205   *result = *_gtk_css_rgba_value_get_rgba (val);
2206   _gtk_css_value_unref (val);
2207   return TRUE;
2208 }
2209 
2210 /**
2211  * gtk_style_context_lookup_color:
2212  * @context: a #GtkStyleContext
2213  * @color_name: color name to lookup
2214  * @color: (out): Return location for the looked up color
2215  *
2216  * Looks up and resolves a color name in the @context color map.
2217  *
2218  * Returns: %TRUE if @color_name was found and resolved, %FALSE otherwise
2219  **/
2220 gboolean
gtk_style_context_lookup_color(GtkStyleContext * context,const gchar * color_name,GdkRGBA * color)2221 gtk_style_context_lookup_color (GtkStyleContext *context,
2222                                 const gchar     *color_name,
2223                                 GdkRGBA         *color)
2224 {
2225   GtkCssValue *value;
2226 
2227   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
2228   g_return_val_if_fail (color_name != NULL, FALSE);
2229   g_return_val_if_fail (color != NULL, FALSE);
2230 
2231   value = _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (context->priv->cascade), color_name);
2232   if (value == NULL)
2233     return FALSE;
2234 
2235   return _gtk_style_context_resolve_color (context, value, color);
2236 }
2237 
2238 /**
2239  * gtk_style_context_notify_state_change:
2240  * @context: a #GtkStyleContext
2241  * @window: a #GdkWindow
2242  * @region_id: (allow-none): animatable region to notify on, or %NULL.
2243  *     See gtk_style_context_push_animatable_region()
2244  * @state: state to trigger transition for
2245  * @state_value: %TRUE if @state is the state we are changing to,
2246  *     %FALSE if we are changing away from it
2247  *
2248  * Notifies a state change on @context, so if the current style makes use
2249  * of transition animations, one will be started so all rendered elements
2250  * under @region_id are animated for state @state being set to value
2251  * @state_value.
2252  *
2253  * The @window parameter is used in order to invalidate the rendered area
2254  * as the animation runs, so make sure it is the same window that is being
2255  * rendered on by the gtk_render_*() functions.
2256  *
2257  * If @region_id is %NULL, all rendered elements using @context will be
2258  * affected by this state transition.
2259  *
2260  * As a practical example, a #GtkButton notifying a state transition on
2261  * the prelight state:
2262  * |[ <!-- language="C" -->
2263  * gtk_style_context_notify_state_change (context,
2264  *                                        gtk_widget_get_window (widget),
2265  *                                        NULL,
2266  *                                        GTK_STATE_PRELIGHT,
2267  *                                        button->in_button);
2268  * ]|
2269  *
2270  * Can be handled in the CSS file like this:
2271  * |[ <!-- language="CSS" -->
2272  * button {
2273  *     background-color: #f00
2274  * }
2275  *
2276  * button:hover {
2277  *     background-color: #fff;
2278  *     transition: 200ms linear
2279  * }
2280  * ]|
2281  *
2282  * This combination will animate the button background from red to white
2283  * if a pointer enters the button, and back to red if the pointer leaves
2284  * the button.
2285  *
2286  * Note that @state is used when finding the transition parameters, which
2287  * is why the style places the transition under the :hover pseudo-class.
2288  *
2289  * Since: 3.0
2290  *
2291  * Deprecated: 3.6: This function does nothing.
2292  **/
2293 void
gtk_style_context_notify_state_change(GtkStyleContext * context,GdkWindow * window,gpointer region_id,GtkStateType state,gboolean state_value)2294 gtk_style_context_notify_state_change (GtkStyleContext *context,
2295                                        GdkWindow       *window,
2296                                        gpointer         region_id,
2297                                        GtkStateType     state,
2298                                        gboolean         state_value)
2299 {
2300   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2301   g_return_if_fail (GDK_IS_WINDOW (window));
2302   g_return_if_fail (state > GTK_STATE_NORMAL && state <= GTK_STATE_FOCUSED);
2303 }
2304 
2305 /**
2306  * gtk_style_context_cancel_animations:
2307  * @context: a #GtkStyleContext
2308  * @region_id: (allow-none): animatable region to stop, or %NULL.
2309  *     See gtk_style_context_push_animatable_region()
2310  *
2311  * Stops all running animations for @region_id and all animatable
2312  * regions underneath.
2313  *
2314  * A %NULL @region_id will stop all ongoing animations in @context,
2315  * when dealing with a #GtkStyleContext obtained through
2316  * gtk_widget_get_style_context(), this is normally done for you
2317  * in all circumstances you would expect all widget to be stopped,
2318  * so this should be only used in complex widgets with different
2319  * animatable regions.
2320  *
2321  * Since: 3.0
2322  *
2323  * Deprecated: 3.6: This function does nothing.
2324  **/
2325 void
gtk_style_context_cancel_animations(GtkStyleContext * context,gpointer region_id)2326 gtk_style_context_cancel_animations (GtkStyleContext *context,
2327                                      gpointer         region_id)
2328 {
2329   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2330 }
2331 
2332 /**
2333  * gtk_style_context_scroll_animations:
2334  * @context: a #GtkStyleContext
2335  * @window: a #GdkWindow used previously in
2336  *          gtk_style_context_notify_state_change()
2337  * @dx: Amount to scroll in the X axis
2338  * @dy: Amount to scroll in the Y axis
2339  *
2340  * This function is analogous to gdk_window_scroll(), and
2341  * should be called together with it so the invalidation
2342  * areas for any ongoing animation are scrolled together
2343  * with it.
2344  *
2345  * Since: 3.0
2346  *
2347  * Deprecated: 3.6: This function does nothing.
2348  **/
2349 void
gtk_style_context_scroll_animations(GtkStyleContext * context,GdkWindow * window,gint dx,gint dy)2350 gtk_style_context_scroll_animations (GtkStyleContext *context,
2351                                      GdkWindow       *window,
2352                                      gint             dx,
2353                                      gint             dy)
2354 {
2355   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2356   g_return_if_fail (GDK_IS_WINDOW (window));
2357 }
2358 
2359 /**
2360  * gtk_style_context_push_animatable_region:
2361  * @context: a #GtkStyleContext
2362  * @region_id: unique identifier for the animatable region
2363  *
2364  * Pushes an animatable region, so all further gtk_render_*() calls between
2365  * this call and the following gtk_style_context_pop_animatable_region()
2366  * will potentially show transition animations for this region if
2367  * gtk_style_context_notify_state_change() is called for a given state,
2368  * and the current theme/style defines transition animations for state
2369  * changes.
2370  *
2371  * The @region_id used must be unique in @context so the themes
2372  * can uniquely identify rendered elements subject to a state transition.
2373  *
2374  * Since: 3.0
2375  *
2376  * Deprecated: 3.6: This function does nothing.
2377  **/
2378 void
gtk_style_context_push_animatable_region(GtkStyleContext * context,gpointer region_id)2379 gtk_style_context_push_animatable_region (GtkStyleContext *context,
2380                                           gpointer         region_id)
2381 {
2382   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2383   g_return_if_fail (region_id != NULL);
2384 }
2385 
2386 /**
2387  * gtk_style_context_pop_animatable_region:
2388  * @context: a #GtkStyleContext
2389  *
2390  * Pops an animatable region from @context.
2391  * See gtk_style_context_push_animatable_region().
2392  *
2393  * Since: 3.0
2394  *
2395  * Deprecated: 3.6: This function does nothing.
2396  **/
2397 void
gtk_style_context_pop_animatable_region(GtkStyleContext * context)2398 gtk_style_context_pop_animatable_region (GtkStyleContext *context)
2399 {
2400   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2401 }
2402 
2403 static GtkCssStyleChange magic_number;
2404 
2405 void
gtk_style_context_validate(GtkStyleContext * context,GtkCssStyleChange * change)2406 gtk_style_context_validate (GtkStyleContext  *context,
2407                             GtkCssStyleChange *change)
2408 {
2409   GtkStyleContextPrivate *priv;
2410 
2411   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2412 
2413   priv = context->priv;
2414 
2415   /* Avoid reentrancy */
2416   if (priv->invalidating_context)
2417     return;
2418 
2419   if (change)
2420     priv->invalidating_context = change;
2421   else
2422     priv->invalidating_context = &magic_number;
2423 
2424   g_signal_emit (context, signals[CHANGED], 0);
2425 
2426   g_object_set_data (G_OBJECT (context), "font-cache-for-get_font", NULL);
2427 
2428   priv->invalidating_context = NULL;
2429 }
2430 
2431 /**
2432  * gtk_style_context_invalidate:
2433  * @context: a #GtkStyleContext.
2434  *
2435  * Invalidates @context style information, so it will be reconstructed
2436  * again. It is useful if you modify the @context and need the new
2437  * information immediately.
2438  *
2439  * Since: 3.0
2440  *
2441  * Deprecated: 3.12: Style contexts are invalidated automatically.
2442  **/
2443 void
gtk_style_context_invalidate(GtkStyleContext * context)2444 gtk_style_context_invalidate (GtkStyleContext *context)
2445 {
2446   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2447 
2448   gtk_style_context_clear_property_cache (context);
2449 
2450   gtk_style_context_validate (context, NULL);
2451 }
2452 
2453 /**
2454  * gtk_style_context_set_background:
2455  * @context: a #GtkStyleContext
2456  * @window: a #GdkWindow
2457  *
2458  * Sets the background of @window to the background pattern or
2459  * color specified in @context for its current state.
2460  *
2461  * Since: 3.0
2462  *
2463  * Deprecated: 3.18: Use gtk_render_background() instead.
2464  *   Note that clients still using this function are now responsible
2465  *   for calling this function again whenever @context is invalidated.
2466  **/
2467 void
gtk_style_context_set_background(GtkStyleContext * context,GdkWindow * window)2468 gtk_style_context_set_background (GtkStyleContext *context,
2469                                   GdkWindow       *window)
2470 {
2471   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2472   g_return_if_fail (GDK_IS_WINDOW (window));
2473 
2474   /* This is a sophisticated optimization.
2475    * If we know the GDK window's background will be opaque, we mark
2476    * it as opaque. This is so GDK can do all the optimizations it does
2477    * for opaque windows and be fast.
2478    * This is mainly used when scrolling.
2479    *
2480    * We could indeed just set black instead of the color we have.
2481    */
2482 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
2483   if (gtk_css_style_render_background_is_opaque (gtk_style_context_lookup_style (context)))
2484     {
2485       const GdkRGBA *color;
2486 
2487       color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BACKGROUND_COLOR));
2488 
2489       gdk_window_set_background_rgba (window, color);
2490     }
2491   else
2492     {
2493       GdkRGBA transparent = { 0.0, 0.0, 0.0, 0.0 };
2494       gdk_window_set_background_rgba (window, &transparent);
2495     }
2496 G_GNUC_END_IGNORE_DEPRECATIONS
2497 }
2498 
2499 /**
2500  * gtk_style_context_get_color:
2501  * @context: a #GtkStyleContext
2502  * @state: state to retrieve the color for
2503  * @color: (out): return value for the foreground color
2504  *
2505  * Gets the foreground color for a given state.
2506  *
2507  * See gtk_style_context_get_property() and
2508  * #GTK_STYLE_PROPERTY_COLOR for details.
2509  *
2510  * Since: 3.0
2511  **/
2512 void
gtk_style_context_get_color(GtkStyleContext * context,GtkStateFlags state,GdkRGBA * color)2513 gtk_style_context_get_color (GtkStyleContext *context,
2514                              GtkStateFlags    state,
2515                              GdkRGBA         *color)
2516 {
2517   GdkRGBA *c;
2518 
2519   g_return_if_fail (color != NULL);
2520   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2521 
2522   gtk_style_context_get (context,
2523                          state,
2524                          "color", &c,
2525                          NULL);
2526 
2527   *color = *c;
2528   gdk_rgba_free (c);
2529 }
2530 
2531 /**
2532  * gtk_style_context_get_background_color:
2533  * @context: a #GtkStyleContext
2534  * @state: state to retrieve the color for
2535  * @color: (out): return value for the background color
2536  *
2537  * Gets the background color for a given state.
2538  *
2539  * This function is far less useful than it seems, and it should not be used in
2540  * newly written code. CSS has no concept of "background color", as a background
2541  * can be an image, or a gradient, or any other pattern including solid colors.
2542  *
2543  * The only reason why you would call gtk_style_context_get_background_color() is
2544  * to use the returned value to draw the background with it; the correct way to
2545  * achieve this result is to use gtk_render_background() instead, along with CSS
2546  * style classes to modify the color to be rendered.
2547  *
2548  * Since: 3.0
2549  *
2550  * Deprecated: 3.16: Use gtk_render_background() instead.
2551  **/
2552 void
gtk_style_context_get_background_color(GtkStyleContext * context,GtkStateFlags state,GdkRGBA * color)2553 gtk_style_context_get_background_color (GtkStyleContext *context,
2554                                         GtkStateFlags    state,
2555                                         GdkRGBA         *color)
2556 {
2557   GdkRGBA *c;
2558 
2559   g_return_if_fail (color != NULL);
2560   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2561 
2562   gtk_style_context_get (context,
2563                          state,
2564                          "background-color", &c,
2565                          NULL);
2566 
2567   *color = *c;
2568   gdk_rgba_free (c);
2569 }
2570 
2571 /**
2572  * gtk_style_context_get_border_color:
2573  * @context: a #GtkStyleContext
2574  * @state: state to retrieve the color for
2575  * @color: (out): return value for the border color
2576  *
2577  * Gets the border color for a given state.
2578  *
2579  * Since: 3.0
2580  *
2581  * Deprecated: 3.16: Use gtk_render_frame() instead.
2582  **/
2583 void
gtk_style_context_get_border_color(GtkStyleContext * context,GtkStateFlags state,GdkRGBA * color)2584 gtk_style_context_get_border_color (GtkStyleContext *context,
2585                                     GtkStateFlags    state,
2586                                     GdkRGBA         *color)
2587 {
2588   GdkRGBA *c;
2589 
2590   g_return_if_fail (color != NULL);
2591   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2592 
2593   gtk_style_context_get (context,
2594                          state,
2595                          "border-color", &c,
2596                          NULL);
2597 
2598   *color = *c;
2599   gdk_rgba_free (c);
2600 }
2601 
2602 /**
2603  * gtk_style_context_get_border:
2604  * @context: a #GtkStyleContext
2605  * @state: state to retrieve the border for
2606  * @border: (out): return value for the border settings
2607  *
2608  * Gets the border for a given state as a #GtkBorder.
2609  *
2610  * See gtk_style_context_get_property() and
2611  * #GTK_STYLE_PROPERTY_BORDER_WIDTH for details.
2612  *
2613  * Since: 3.0
2614  **/
2615 void
gtk_style_context_get_border(GtkStyleContext * context,GtkStateFlags state,GtkBorder * border)2616 gtk_style_context_get_border (GtkStyleContext *context,
2617                               GtkStateFlags    state,
2618                               GtkBorder       *border)
2619 {
2620   GtkCssStyle *style;
2621   GtkStateFlags saved_state;
2622   double top, left, bottom, right;
2623 
2624   g_return_if_fail (border != NULL);
2625   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2626 
2627   saved_state = gtk_style_context_push_state (context, state);
2628   style = gtk_style_context_lookup_style (context);
2629 
2630   top = round (_gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100));
2631   right = round (_gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100));
2632   bottom = round (_gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100));
2633   left = round (_gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100));
2634 
2635   border->top = top;
2636   border->left = left;
2637   border->bottom = bottom;
2638   border->right = right;
2639 
2640   gtk_style_context_pop_state (context, saved_state);
2641 }
2642 
2643 /**
2644  * gtk_style_context_get_padding:
2645  * @context: a #GtkStyleContext
2646  * @state: state to retrieve the padding for
2647  * @padding: (out): return value for the padding settings
2648  *
2649  * Gets the padding for a given state as a #GtkBorder.
2650  * See gtk_style_context_get() and #GTK_STYLE_PROPERTY_PADDING
2651  * for details.
2652  *
2653  * Since: 3.0
2654  **/
2655 void
gtk_style_context_get_padding(GtkStyleContext * context,GtkStateFlags state,GtkBorder * padding)2656 gtk_style_context_get_padding (GtkStyleContext *context,
2657                                GtkStateFlags    state,
2658                                GtkBorder       *padding)
2659 {
2660   GtkCssStyle *style;
2661   GtkStateFlags saved_state;
2662   double top, left, bottom, right;
2663 
2664   g_return_if_fail (padding != NULL);
2665   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2666 
2667   saved_state = gtk_style_context_push_state (context, state);
2668   style = gtk_style_context_lookup_style (context);
2669 
2670   top = round (_gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_PADDING_TOP), 100));
2671   right = round (_gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_PADDING_RIGHT), 100));
2672   bottom = round (_gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_PADDING_BOTTOM), 100));
2673   left = round (_gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_PADDING_LEFT), 100));
2674 
2675   padding->top = top;
2676   padding->left = left;
2677   padding->bottom = bottom;
2678   padding->right = right;
2679 
2680   gtk_style_context_pop_state (context, saved_state);
2681 }
2682 
2683 /**
2684  * gtk_style_context_get_margin:
2685  * @context: a #GtkStyleContext
2686  * @state: state to retrieve the border for
2687  * @margin: (out): return value for the margin settings
2688  *
2689  * Gets the margin for a given state as a #GtkBorder.
2690  * See gtk_style_property_get() and #GTK_STYLE_PROPERTY_MARGIN
2691  * for details.
2692  *
2693  * Since: 3.0
2694  **/
2695 void
gtk_style_context_get_margin(GtkStyleContext * context,GtkStateFlags state,GtkBorder * margin)2696 gtk_style_context_get_margin (GtkStyleContext *context,
2697                               GtkStateFlags    state,
2698                               GtkBorder       *margin)
2699 {
2700   GtkCssStyle *style;
2701   GtkStateFlags saved_state;
2702   double top, left, bottom, right;
2703 
2704   g_return_if_fail (margin != NULL);
2705   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2706 
2707   saved_state = gtk_style_context_push_state (context, state);
2708   style = gtk_style_context_lookup_style (context);
2709 
2710   top = round (_gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_MARGIN_TOP), 100));
2711   right = round (_gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_MARGIN_RIGHT), 100));
2712   bottom = round (_gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_MARGIN_BOTTOM), 100));
2713   left = round (_gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_MARGIN_LEFT), 100));
2714 
2715   margin->top = top;
2716   margin->left = left;
2717   margin->bottom = bottom;
2718   margin->right = right;
2719 
2720   gtk_style_context_pop_state (context, saved_state);
2721 }
2722 
2723 /**
2724  * gtk_style_context_get_font:
2725  * @context: a #GtkStyleContext
2726  * @state: state to retrieve the font for
2727  *
2728  * Returns the font description for a given state. The returned
2729  * object is const and will remain valid until the
2730  * #GtkStyleContext::changed signal happens.
2731  *
2732  * Returns: (transfer none): the #PangoFontDescription for the given
2733  *          state.  This object is owned by GTK+ and should not be
2734  *          freed.
2735  *
2736  * Since: 3.0
2737  *
2738  * Deprecated: 3.8: Use gtk_style_context_get() for "font" or
2739  *     subproperties instead.
2740  **/
2741 const PangoFontDescription *
gtk_style_context_get_font(GtkStyleContext * context,GtkStateFlags state)2742 gtk_style_context_get_font (GtkStyleContext *context,
2743                             GtkStateFlags    state)
2744 {
2745   GHashTable *hash;
2746   PangoFontDescription *description, *previous;
2747 
2748   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
2749 
2750   /* Yuck, fonts are created on-demand but we don't return a ref.
2751    * Do bad things to achieve this requirement */
2752   gtk_style_context_get (context, state, "font", &description, NULL);
2753 
2754   hash = g_object_get_data (G_OBJECT (context), "font-cache-for-get_font");
2755 
2756   if (hash == NULL)
2757     {
2758       hash = g_hash_table_new_full (g_direct_hash, g_direct_equal,
2759                                     NULL,
2760                                     (GDestroyNotify) pango_font_description_free);
2761       g_object_set_data_full (G_OBJECT (context),
2762                               "font-cache-for-get_font",
2763                               hash,
2764                               (GDestroyNotify) g_hash_table_unref);
2765     }
2766 
2767   previous = g_hash_table_lookup (hash, GUINT_TO_POINTER (state));
2768   if (previous)
2769     {
2770       pango_font_description_merge (previous, description, TRUE);
2771       pango_font_description_free (description);
2772       description = previous;
2773     }
2774   else
2775     {
2776       g_hash_table_insert (hash, GUINT_TO_POINTER (state), description);
2777     }
2778 
2779   return description;
2780 }
2781 
2782 void
_gtk_style_context_get_cursor_color(GtkStyleContext * context,GdkRGBA * primary_color,GdkRGBA * secondary_color)2783 _gtk_style_context_get_cursor_color (GtkStyleContext *context,
2784                                      GdkRGBA         *primary_color,
2785                                      GdkRGBA         *secondary_color)
2786 {
2787   GdkRGBA *pc, *sc;
2788 
2789   gtk_style_context_get (context,
2790                          gtk_style_context_get_state (context),
2791                          "caret-color", &pc,
2792                          "-gtk-secondary-caret-color", &sc,
2793                          NULL);
2794   if (primary_color)
2795     *primary_color = *pc;
2796 
2797   if (secondary_color)
2798     *secondary_color = *sc;
2799 
2800   gdk_rgba_free (pc);
2801   gdk_rgba_free (sc);
2802 }
2803 
2804 static void
draw_insertion_cursor(GtkStyleContext * context,cairo_t * cr,gdouble x,gdouble y,gdouble height,float aspect_ratio,gboolean is_primary,PangoDirection direction,gboolean draw_arrow)2805 draw_insertion_cursor (GtkStyleContext *context,
2806                        cairo_t         *cr,
2807                        gdouble          x,
2808                        gdouble          y,
2809                        gdouble          height,
2810                        float            aspect_ratio,
2811                        gboolean         is_primary,
2812                        PangoDirection   direction,
2813                        gboolean         draw_arrow)
2814 
2815 {
2816   GdkRGBA primary_color;
2817   GdkRGBA secondary_color;
2818   gint stem_width;
2819   gint offset;
2820 
2821   cairo_save (cr);
2822   cairo_new_path (cr);
2823 
2824   _gtk_style_context_get_cursor_color (context, &primary_color, &secondary_color);
2825   gdk_cairo_set_source_rgba (cr, is_primary ? &primary_color : &secondary_color);
2826 
2827   /* When changing the shape or size of the cursor here,
2828    * propagate the changes to gtktextview.c:text_window_invalidate_cursors().
2829    */
2830 
2831   stem_width = height * aspect_ratio + 1;
2832 
2833   /* put (stem_width % 2) on the proper side of the cursor */
2834   if (direction == PANGO_DIRECTION_LTR)
2835     offset = stem_width / 2;
2836   else
2837     offset = stem_width - stem_width / 2;
2838 
2839   cairo_rectangle (cr, x - offset, y, stem_width, height);
2840   cairo_fill (cr);
2841 
2842   if (draw_arrow)
2843     {
2844       gint arrow_width;
2845       gint ax, ay;
2846 
2847       arrow_width = stem_width + 1;
2848 
2849       if (direction == PANGO_DIRECTION_RTL)
2850         {
2851           ax = x - offset - 1;
2852           ay = y + height - arrow_width * 2 - arrow_width + 1;
2853 
2854           cairo_move_to (cr, ax, ay + 1);
2855           cairo_line_to (cr, ax - arrow_width, ay + arrow_width);
2856           cairo_line_to (cr, ax, ay + 2 * arrow_width);
2857           cairo_fill (cr);
2858         }
2859       else if (direction == PANGO_DIRECTION_LTR)
2860         {
2861           ax = x + stem_width - offset;
2862           ay = y + height - arrow_width * 2 - arrow_width + 1;
2863 
2864           cairo_move_to (cr, ax, ay + 1);
2865           cairo_line_to (cr, ax + arrow_width, ay + arrow_width);
2866           cairo_line_to (cr, ax, ay + 2 * arrow_width);
2867           cairo_fill (cr);
2868         }
2869       else
2870         g_assert_not_reached();
2871     }
2872 
2873   cairo_restore (cr);
2874 }
2875 
2876 /**
2877  * gtk_render_insertion_cursor:
2878  * @context: a #GtkStyleContext
2879  * @cr: a #cairo_t
2880  * @x: X origin
2881  * @y: Y origin
2882  * @layout: the #PangoLayout of the text
2883  * @index: the index in the #PangoLayout
2884  * @direction: the #PangoDirection of the text
2885  *
2886  * Draws a text caret on @cr at the specified index of @layout.
2887  *
2888  * Since: 3.4
2889  **/
2890 void
gtk_render_insertion_cursor(GtkStyleContext * context,cairo_t * cr,gdouble x,gdouble y,PangoLayout * layout,int index,PangoDirection direction)2891 gtk_render_insertion_cursor (GtkStyleContext *context,
2892                              cairo_t         *cr,
2893                              gdouble          x,
2894                              gdouble          y,
2895                              PangoLayout     *layout,
2896                              int              index,
2897                              PangoDirection   direction)
2898 {
2899   GtkStyleContextPrivate *priv;
2900   gboolean split_cursor;
2901   float aspect_ratio;
2902   PangoRectangle strong_pos, weak_pos;
2903   PangoRectangle *cursor1, *cursor2;
2904   PangoDirection keymap_direction;
2905   PangoDirection direction2;
2906 
2907   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
2908   g_return_if_fail (cr != NULL);
2909   g_return_if_fail (PANGO_IS_LAYOUT (layout));
2910   g_return_if_fail (index >= 0);
2911 
2912   priv = context->priv;
2913 
2914   g_object_get (gtk_settings_get_for_screen (priv->screen),
2915                 "gtk-split-cursor", &split_cursor,
2916                 "gtk-cursor-aspect-ratio", &aspect_ratio,
2917                 NULL);
2918 
2919   /* Fall back to style property if the GtkSetting property is unchanged */
2920   if (aspect_ratio == 0.04f)
2921     {
2922       gtk_style_context_get_style (context,
2923                                    "cursor-aspect-ratio", &aspect_ratio,
2924                                    NULL);
2925     }
2926 
2927   keymap_direction = gdk_keymap_get_direction (gdk_keymap_get_for_display (gdk_screen_get_display (priv->screen)));
2928 
2929   pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
2930 
2931   direction2 = PANGO_DIRECTION_NEUTRAL;
2932 
2933   if (split_cursor)
2934     {
2935       cursor1 = &strong_pos;
2936 
2937       if (strong_pos.x != weak_pos.x || strong_pos.y != weak_pos.y)
2938         {
2939           direction2 = (direction == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
2940           cursor2 = &weak_pos;
2941         }
2942     }
2943   else
2944     {
2945       if (keymap_direction == direction)
2946         cursor1 = &strong_pos;
2947       else
2948         cursor1 = &weak_pos;
2949     }
2950 
2951   draw_insertion_cursor (context,
2952                          cr,
2953                          x + PANGO_PIXELS (cursor1->x),
2954                          y + PANGO_PIXELS (cursor1->y),
2955                          PANGO_PIXELS (cursor1->height),
2956                          aspect_ratio,
2957                          TRUE,
2958                          direction,
2959                          direction2 != PANGO_DIRECTION_NEUTRAL);
2960 
2961   if (direction2 != PANGO_DIRECTION_NEUTRAL)
2962     {
2963       draw_insertion_cursor (context,
2964                              cr,
2965                              x + PANGO_PIXELS (cursor2->x),
2966                              y + PANGO_PIXELS (cursor2->y),
2967                              PANGO_PIXELS (cursor2->height),
2968                              aspect_ratio,
2969                              FALSE,
2970                              direction2,
2971                              TRUE);
2972     }
2973 }
2974 
2975 /**
2976  * gtk_draw_insertion_cursor:
2977  * @widget:  a #GtkWidget
2978  * @cr: cairo context to draw to
2979  * @location: location where to draw the cursor (@location->width is ignored)
2980  * @is_primary: if the cursor should be the primary cursor color.
2981  * @direction: whether the cursor is left-to-right or
2982  *             right-to-left. Should never be #GTK_TEXT_DIR_NONE
2983  * @draw_arrow: %TRUE to draw a directional arrow on the
2984  *        cursor. Should be %FALSE unless the cursor is split.
2985  *
2986  * Draws a text caret on @cr at @location. This is not a style function
2987  * but merely a convenience function for drawing the standard cursor shape.
2988  *
2989  * Since: 3.0
2990  * Deprecated: 3.4: Use gtk_render_insertion_cursor() instead.
2991  */
2992 void
gtk_draw_insertion_cursor(GtkWidget * widget,cairo_t * cr,const GdkRectangle * location,gboolean is_primary,GtkTextDirection direction,gboolean draw_arrow)2993 gtk_draw_insertion_cursor (GtkWidget          *widget,
2994                            cairo_t            *cr,
2995                            const GdkRectangle *location,
2996                            gboolean            is_primary,
2997                            GtkTextDirection    direction,
2998                            gboolean            draw_arrow)
2999 {
3000   GtkStyleContext *context;
3001   float aspect_ratio;
3002 
3003   g_return_if_fail (GTK_IS_WIDGET (widget));
3004   g_return_if_fail (cr != NULL);
3005   g_return_if_fail (location != NULL);
3006   g_return_if_fail (direction != GTK_TEXT_DIR_NONE);
3007 
3008   context = gtk_widget_get_style_context (widget);
3009 
3010   g_object_get (gtk_settings_get_for_screen (context->priv->screen),
3011                 "gtk-cursor-aspect-ratio", &aspect_ratio,
3012                 NULL);
3013 
3014   /* Fall back to style property if the GtkSetting property is unchanged */
3015   if (aspect_ratio == 0.04f)
3016     {
3017       gtk_style_context_get_style (context,
3018                                    "cursor-aspect-ratio", &aspect_ratio,
3019                                    NULL);
3020     }
3021 
3022   draw_insertion_cursor (context, cr,
3023                          location->x, location->y, location->height,
3024                          aspect_ratio,
3025                          is_primary,
3026                          (direction == GTK_TEXT_DIR_RTL) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR,
3027                          draw_arrow);
3028 }
3029 
3030 /**
3031  * gtk_style_context_get_change:
3032  * @context: the context to query
3033  *
3034  * Queries the context for the changes for the currently executing
3035  * GtkStyleContext::invalidate signal. If no signal is currently
3036  * emitted or the signal has not been triggered by a CssNode
3037  * invalidation, this function returns %NULL.
3038  *
3039  * FIXME 4.0: Make this part of the signal.
3040  *
3041  * Returns: %NULL or the currently invalidating changes
3042  **/
3043 GtkCssStyleChange *
gtk_style_context_get_change(GtkStyleContext * context)3044 gtk_style_context_get_change (GtkStyleContext *context)
3045 {
3046   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
3047 
3048   if (context->priv->invalidating_context == &magic_number)
3049     return NULL;
3050 
3051   return context->priv->invalidating_context;
3052 }
3053 
3054 void
_gtk_style_context_get_icon_extents(GtkStyleContext * context,GdkRectangle * extents,gint x,gint y,gint width,gint height)3055 _gtk_style_context_get_icon_extents (GtkStyleContext *context,
3056                                      GdkRectangle    *extents,
3057                                      gint             x,
3058                                      gint             y,
3059                                      gint             width,
3060                                      gint             height)
3061 {
3062   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
3063   g_return_if_fail (extents != NULL);
3064 
3065   if (_gtk_css_image_value_get_image (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ICON_SOURCE)) == NULL)
3066     {
3067       extents->x = extents->y = extents->width = extents->height = 0;
3068       return;
3069     }
3070 
3071   gtk_css_style_render_icon_get_extents (gtk_style_context_lookup_style (context),
3072                                          extents,
3073                                          x, y, width, height);
3074 }
3075 
3076 PangoAttrList *
_gtk_style_context_get_pango_attributes(GtkStyleContext * context)3077 _gtk_style_context_get_pango_attributes (GtkStyleContext *context)
3078 {
3079   return gtk_css_style_get_pango_attributes (gtk_style_context_lookup_style (context));
3080 }
3081 
3082 static AtkAttributeSet *
add_attribute(AtkAttributeSet * attributes,AtkTextAttribute attr,const gchar * value)3083 add_attribute (AtkAttributeSet  *attributes,
3084                AtkTextAttribute  attr,
3085                const gchar      *value)
3086 {
3087   AtkAttribute *at;
3088 
3089   at = g_new (AtkAttribute, 1);
3090   at->name = g_strdup (atk_text_attribute_get_name (attr));
3091   at->value = g_strdup (value);
3092 
3093   return g_slist_prepend (attributes, at);
3094 }
3095 
3096 /*
3097  * _gtk_style_context_get_attributes:
3098  * @attributes: a #AtkAttributeSet to add attributes to
3099  * @context: the #GtkStyleContext to get attributes from
3100  * @flags: the state to use with @context
3101  *
3102  * Adds the foreground and background color from @context to
3103  * @attributes, after translating them to ATK attributes.
3104  *
3105  * This is a convenience function that can be used in
3106  * implementing the #AtkText interface in widgets.
3107  *
3108  * Returns: the modified #AtkAttributeSet
3109  */
3110 AtkAttributeSet *
_gtk_style_context_get_attributes(AtkAttributeSet * attributes,GtkStyleContext * context,GtkStateFlags flags)3111 _gtk_style_context_get_attributes (AtkAttributeSet *attributes,
3112                                    GtkStyleContext *context,
3113                                    GtkStateFlags    flags)
3114 {
3115   GdkRGBA color;
3116   gchar *value;
3117 
3118 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
3119   gtk_style_context_get_background_color (context, flags, &color);
3120 G_GNUC_END_IGNORE_DEPRECATIONS
3121   value = g_strdup_printf ("%u,%u,%u",
3122                            (guint) ceil (color.red * 65536 - color.red),
3123                            (guint) ceil (color.green * 65536 - color.green),
3124                            (guint) ceil (color.blue * 65536 - color.blue));
3125   attributes = add_attribute (attributes, ATK_TEXT_ATTR_BG_COLOR, value);
3126   g_free (value);
3127 
3128   gtk_style_context_get_color (context, flags, &color);
3129   value = g_strdup_printf ("%u,%u,%u",
3130                            (guint) ceil (color.red * 65536 - color.red),
3131                            (guint) ceil (color.green * 65536 - color.green),
3132                            (guint) ceil (color.blue * 65536 - color.blue));
3133   attributes = add_attribute (attributes, ATK_TEXT_ATTR_FG_COLOR, value);
3134   g_free (value);
3135 
3136   return attributes;
3137 }
3138 
3139 cairo_pattern_t *
gtk_gradient_resolve_for_context(GtkGradient * gradient,GtkStyleContext * context)3140 gtk_gradient_resolve_for_context (GtkGradient     *gradient,
3141                                   GtkStyleContext *context)
3142 {
3143   GtkStyleContextPrivate *priv = context->priv;
3144 
3145   g_return_val_if_fail (gradient != NULL, NULL);
3146   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
3147 
3148   return _gtk_gradient_resolve_full (gradient,
3149                                      GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
3150                                      gtk_style_context_lookup_style (context),
3151                                      priv->parent ? gtk_style_context_lookup_style (priv->parent) : NULL);
3152 }
3153 
3154 /**
3155  * GtkStyleContextPrintFlags:
3156  * @GTK_STYLE_CONTEXT_PRINT_RECURSE: Print the entire tree of
3157  *     CSS nodes starting at the style context's node
3158  * @GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE: Show the values of the
3159  *     CSS properties for each node
3160  *
3161  * Flags that modify the behavior of gtk_style_context_to_string().
3162  * New values may be added to this enumeration.
3163  */
3164 
3165 /**
3166  * gtk_style_context_to_string:
3167  * @context: a #GtkStyleContext
3168  * @flags: Flags that determine what to print
3169  *
3170  * Converts the style context into a string representation.
3171  *
3172  * The string representation always includes information about
3173  * the name, state, id, visibility and style classes of the CSS
3174  * node that is backing @context. Depending on the flags, more
3175  * information may be included.
3176  *
3177  * This function is intended for testing and debugging of the
3178  * CSS implementation in GTK+. There are no guarantees about
3179  * the format of the returned string, it may change.
3180  *
3181  * Returns: a newly allocated string representing @context
3182  *
3183  * Since: 3.20
3184  */
3185 char *
gtk_style_context_to_string(GtkStyleContext * context,GtkStyleContextPrintFlags flags)3186 gtk_style_context_to_string (GtkStyleContext           *context,
3187                              GtkStyleContextPrintFlags  flags)
3188 {
3189   GString *string;
3190 
3191   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
3192 
3193   string = g_string_new ("");
3194 
3195   gtk_css_node_print (context->priv->cssnode, flags, string, 0);
3196 
3197   return g_string_free (string, FALSE);
3198 }
3199