1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2012 Benjamin Otte <otte@gnome.org>
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.
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.
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/>.
20 #include "gtkstylecascadeprivate.h"
22 #include "gtkstyleprovider.h"
23 #include "gtkstyleproviderprivate.h"
25 typedef struct _GtkStyleCascadeIter GtkStyleCascadeIter;
26 typedef struct _GtkStyleProviderData GtkStyleProviderData;
28 struct _GtkStyleCascadeIter {
29 int parent_index; /* pointing at last index that was returned, not next one that should be returned */
30 int index; /* pointing at last index that was returned, not next one that should be returned */
33 struct _GtkStyleProviderData
35 GtkStyleProvider *provider;
37 guint changed_signal_id;
40 static GtkStyleProvider *
41 gtk_style_cascade_iter_next (GtkStyleCascade *cascade,
42 GtkStyleCascadeIter *iter)
44 if (iter->parent_index > 0)
48 GtkStyleProviderData *data, *parent_data;
50 data = &g_array_index (cascade->providers, GtkStyleProviderData, iter->index - 1);
51 parent_data = &g_array_index (cascade->parent->providers, GtkStyleProviderData, iter->parent_index - 1);
53 if (data->priority >= parent_data->priority)
56 return data->provider;
61 return parent_data->provider;
67 return g_array_index (cascade->parent->providers, GtkStyleProviderData, iter->parent_index).provider;
75 return g_array_index (cascade->providers, GtkStyleProviderData, iter->index).provider;
84 static GtkStyleProvider *
85 gtk_style_cascade_iter_init (GtkStyleCascade *cascade,
86 GtkStyleCascadeIter *iter)
88 iter->parent_index = cascade->parent ? cascade->parent->providers->len : 0;
89 iter->index = cascade->providers->len;
91 return gtk_style_cascade_iter_next (cascade, iter);
95 gtk_style_cascade_get_style_property (GtkStyleProvider *provider,
101 GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
102 GtkStyleCascadeIter iter;
103 GtkStyleProvider *item;
105 for (item = gtk_style_cascade_iter_init (cascade, &iter);
107 item = gtk_style_cascade_iter_next (cascade, &iter))
109 if (gtk_style_provider_get_style_property (item,
121 gtk_style_cascade_provider_iface_init (GtkStyleProviderIface *iface)
123 iface->get_style_property = gtk_style_cascade_get_style_property;
127 gtk_style_cascade_get_settings (GtkStyleProviderPrivate *provider)
129 GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
130 GtkStyleCascadeIter iter;
131 GtkSettings *settings;
132 GtkStyleProvider *item;
134 for (item = gtk_style_cascade_iter_init (cascade, &iter);
136 item = gtk_style_cascade_iter_next (cascade, &iter))
138 if (!GTK_IS_STYLE_PROVIDER_PRIVATE (item))
141 settings = _gtk_style_provider_private_get_settings (GTK_STYLE_PROVIDER_PRIVATE (item));
150 gtk_style_cascade_get_color (GtkStyleProviderPrivate *provider,
153 GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
154 GtkStyleCascadeIter iter;
156 GtkStyleProvider *item;
158 for (item = gtk_style_cascade_iter_init (cascade, &iter);
160 item = gtk_style_cascade_iter_next (cascade, &iter))
162 if (GTK_IS_STYLE_PROVIDER_PRIVATE (item))
164 color = _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (item), name);
170 /* If somebody hits this code path, shout at them */
177 static GtkCssKeyframes *
178 gtk_style_cascade_get_keyframes (GtkStyleProviderPrivate *provider,
181 GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
182 GtkStyleCascadeIter iter;
183 GtkCssKeyframes *keyframes;
184 GtkStyleProvider *item;
186 for (item = gtk_style_cascade_iter_init (cascade, &iter);
188 item = gtk_style_cascade_iter_next (cascade, &iter))
190 if (!GTK_IS_STYLE_PROVIDER_PRIVATE (item))
193 keyframes = _gtk_style_provider_private_get_keyframes (GTK_STYLE_PROVIDER_PRIVATE (item), name);
202 gtk_style_cascade_lookup (GtkStyleProviderPrivate *provider,
203 const GtkCssMatcher *matcher,
204 GtkCssLookup *lookup)
206 GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
207 GtkStyleCascadeIter iter;
208 GtkStyleProvider *item;
210 for (item = gtk_style_cascade_iter_init (cascade, &iter);
212 item = gtk_style_cascade_iter_next (cascade, &iter))
214 if (GTK_IS_STYLE_PROVIDER_PRIVATE (item))
216 _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (item),
223 g_warn_if_reached ();
229 gtk_style_cascade_get_change (GtkStyleProviderPrivate *provider,
230 const GtkCssMatcher *matcher)
232 GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
233 GtkStyleCascadeIter iter;
234 GtkStyleProvider *item;
235 GtkCssChange change = 0;
237 for (item = gtk_style_cascade_iter_init (cascade, &iter);
239 item = gtk_style_cascade_iter_next (cascade, &iter))
241 if (GTK_IS_STYLE_PROVIDER_PRIVATE (item))
243 change |= _gtk_style_provider_private_get_change (GTK_STYLE_PROVIDER_PRIVATE (item),
248 g_return_val_if_reached (GTK_CSS_CHANGE_ANY);
256 gtk_style_cascade_provider_private_iface_init (GtkStyleProviderPrivateInterface *iface)
258 iface->get_color = gtk_style_cascade_get_color;
259 iface->get_settings = gtk_style_cascade_get_settings;
260 iface->get_keyframes = gtk_style_cascade_get_keyframes;
261 iface->lookup = gtk_style_cascade_lookup;
262 iface->get_change = gtk_style_cascade_get_change;
265 G_DEFINE_TYPE_EXTENDED (GtkStyleCascade, _gtk_style_cascade, G_TYPE_OBJECT, 0,
266 G_IMPLEMENT_INTERFACE (GTK_TYPE_STYLE_PROVIDER,
267 gtk_style_cascade_provider_iface_init)
268 G_IMPLEMENT_INTERFACE (GTK_TYPE_STYLE_PROVIDER_PRIVATE,
269 gtk_style_cascade_provider_private_iface_init));
272 gtk_style_cascade_dispose (GObject *object)
274 GtkStyleCascade *cascade = GTK_STYLE_CASCADE (object);
276 _gtk_style_cascade_set_parent (cascade, NULL);
277 g_array_unref (cascade->providers);
279 G_OBJECT_CLASS (_gtk_style_cascade_parent_class)->dispose (object);
283 _gtk_style_cascade_class_init (GtkStyleCascadeClass *klass)
285 GObjectClass *object_class = G_OBJECT_CLASS (klass);
287 object_class->dispose = gtk_style_cascade_dispose;
291 style_provider_data_clear (gpointer data_)
293 GtkStyleProviderData *data = data_;
295 g_signal_handler_disconnect (data->provider, data->changed_signal_id);
296 g_object_unref (data->provider);
300 _gtk_style_cascade_init (GtkStyleCascade *cascade)
302 cascade->providers = g_array_new (FALSE, FALSE, sizeof (GtkStyleProviderData));
303 g_array_set_clear_func (cascade->providers, style_provider_data_clear);
307 _gtk_style_cascade_new (void)
309 return g_object_new (GTK_TYPE_STYLE_CASCADE, NULL);
313 _gtk_style_cascade_get_for_screen (GdkScreen *screen)
315 GtkStyleCascade *cascade;
316 static GQuark quark = 0;
318 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
320 if (G_UNLIKELY (!quark))
321 quark = g_quark_from_static_string ("gtk-style-cascade");
323 cascade = g_object_get_qdata (G_OBJECT (screen), quark);
326 cascade = _gtk_style_cascade_new ();
327 g_object_set_qdata_full (G_OBJECT (screen), quark, cascade, g_object_unref);
334 _gtk_style_cascade_set_parent (GtkStyleCascade *cascade,
335 GtkStyleCascade *parent)
337 g_return_if_fail (GTK_IS_STYLE_CASCADE (cascade));
338 g_return_if_fail (parent == NULL || GTK_IS_STYLE_CASCADE (parent));
340 g_return_if_fail (parent->parent == NULL);
342 if (cascade->parent == parent)
347 g_object_ref (parent);
348 g_signal_connect_swapped (parent,
349 "-gtk-private-changed",
350 G_CALLBACK (_gtk_style_provider_private_changed),
356 g_signal_handlers_disconnect_by_func (cascade->parent,
357 _gtk_style_provider_private_changed,
359 g_object_unref (cascade->parent);
362 cascade->parent = parent;
366 _gtk_style_cascade_add_provider (GtkStyleCascade *cascade,
367 GtkStyleProvider *provider,
370 GtkStyleProviderData data;
373 g_return_if_fail (GTK_IS_STYLE_CASCADE (cascade));
374 g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
375 g_return_if_fail (GTK_STYLE_PROVIDER (cascade) != provider);
377 data.provider = g_object_ref (provider);
378 data.priority = priority;
379 data.changed_signal_id = g_signal_connect_swapped (provider,
380 "-gtk-private-changed",
381 G_CALLBACK (_gtk_style_provider_private_changed),
384 /* ensure it gets removed first */
385 _gtk_style_cascade_remove_provider (cascade, provider);
387 for (i = 0; i < cascade->providers->len; i++)
389 if (g_array_index (cascade->providers, GtkStyleProviderData, i).priority > priority)
392 g_array_insert_val (cascade->providers, i, data);
394 _gtk_style_provider_private_changed (GTK_STYLE_PROVIDER_PRIVATE (cascade));
398 _gtk_style_cascade_remove_provider (GtkStyleCascade *cascade,
399 GtkStyleProvider *provider)
403 g_return_if_fail (GTK_IS_STYLE_CASCADE (cascade));
404 g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
406 for (i = 0; i < cascade->providers->len; i++)
408 GtkStyleProviderData *data = &g_array_index (cascade->providers, GtkStyleProviderData, i);
410 if (data->provider == provider)
412 g_array_remove_index (cascade->providers, i);
414 _gtk_style_provider_private_changed (GTK_STYLE_PROVIDER_PRIVATE (cascade));