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