]> Pileus Git - ~andy/gtk/blob - gtk/gtkstylecascade.c
a05d36dd77619f2abf927ada295bca88a809572a
[~andy/gtk] / gtk / gtkstylecascade.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2012 Benjamin Otte <otte@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 "gtkstylecascadeprivate.h"
21
22 #include "gtkstyleprovider.h"
23 #include "gtkstyleproviderprivate.h"
24
25 typedef struct _GtkStyleCascadeIter GtkStyleCascadeIter;
26 typedef struct _GtkStyleProviderData GtkStyleProviderData;
27
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 */
31 };
32
33 struct _GtkStyleProviderData
34 {
35   GtkStyleProvider *provider;
36   guint priority;
37 };
38
39 static GtkStyleProvider *
40 gtk_style_cascade_iter_next (GtkStyleCascade     *cascade,
41                              GtkStyleCascadeIter *iter)
42 {
43   if (iter->parent_index > 0)
44     {
45       if (iter->index > 0)
46         {
47           GtkStyleProviderData *data, *parent_data;
48
49           data = &g_array_index (cascade->providers, GtkStyleProviderData, iter->index - 1);
50           parent_data = &g_array_index (cascade->parent->providers, GtkStyleProviderData, iter->parent_index - 1);
51
52           if (data->priority >= parent_data->priority)
53             {
54               iter->index--;
55               return data->provider;
56             }
57           else
58             {
59               iter->parent_index--;
60               return parent_data->provider;
61             }
62         }
63       else
64         {
65           iter->parent_index--;
66           return g_array_index (cascade->parent->providers, GtkStyleProviderData, iter->parent_index).provider;
67         }
68     }
69   else
70     {
71       if (iter->index > 0)
72         {
73           iter->index--;
74           return g_array_index (cascade->providers, GtkStyleProviderData, iter->index).provider;
75         }
76       else
77         {
78           return NULL;
79         }
80     }
81 }
82
83 static GtkStyleProvider *
84 gtk_style_cascade_iter_init (GtkStyleCascade     *cascade,
85                              GtkStyleCascadeIter *iter)
86 {
87   iter->parent_index = cascade->parent ? cascade->parent->providers->len : 0;
88   iter->index = cascade->providers->len;
89
90   return gtk_style_cascade_iter_next (cascade, iter);
91 }
92
93 static GtkStyleProperties * 
94 gtk_style_cascade_get_style (GtkStyleProvider *provider,
95                              GtkWidgetPath    *path)
96 {
97   /* This function is not used anymore by GTK and nobody
98    * else is ever supposed to call it */
99   g_warn_if_reached ();
100   return NULL;
101 }
102
103 static gboolean
104 gtk_style_cascade_get_style_property (GtkStyleProvider *provider,
105                                       GtkWidgetPath    *path,
106                                       GtkStateFlags     state,
107                                       GParamSpec       *pspec,
108                                       GValue           *value)
109 {
110   GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
111   GtkStyleCascadeIter iter;
112   GtkStyleProvider *item;
113
114   for (item = gtk_style_cascade_iter_init (cascade, &iter);
115        item;
116        item = gtk_style_cascade_iter_next (cascade, &iter))
117     {
118       if (gtk_style_provider_get_style_property (item,
119                                                  path,
120                                                  state,
121                                                  pspec,
122                                                  value))
123         return TRUE;
124     }
125
126   return FALSE;
127 }
128
129 static GtkIconFactory *
130 gtk_style_cascade_get_icon_factory (GtkStyleProvider *provider,
131                                     GtkWidgetPath    *path)
132 {
133   /* If anyone ever implements get_icon_factory(), I'll
134    * look at this function. Until then I'll just: */
135   return NULL;
136 }
137
138 static void
139 gtk_style_cascade_provider_iface_init (GtkStyleProviderIface *iface)
140 {
141   iface->get_style = gtk_style_cascade_get_style;
142   iface->get_style_property = gtk_style_cascade_get_style_property;
143   iface->get_icon_factory = gtk_style_cascade_get_icon_factory;
144 }
145
146 static GtkSymbolicColor *
147 gtk_style_cascade_get_color (GtkStyleProviderPrivate *provider,
148                              const char              *name)
149 {
150   GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
151   GtkStyleCascadeIter iter;
152   GtkSymbolicColor *symbolic;
153   GtkStyleProvider *item;
154
155   for (item = gtk_style_cascade_iter_init (cascade, &iter);
156        item;
157        item = gtk_style_cascade_iter_next (cascade, &iter))
158     {
159       if (GTK_IS_STYLE_PROVIDER_PRIVATE (item))
160         {
161           symbolic = _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (item), name);
162           if (symbolic)
163             return symbolic;
164         }
165       else
166         {
167           /* If somebody hits this code path, shout at them */
168         }
169     }
170
171   return NULL;
172 }
173
174 static void
175 gtk_style_cascade_lookup (GtkStyleProviderPrivate *provider,
176                           const GtkCssMatcher     *matcher,
177                           GtkCssLookup            *lookup)
178 {
179   GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
180   GtkStyleCascadeIter iter;
181   GtkStyleProvider *item;
182
183   for (item = gtk_style_cascade_iter_init (cascade, &iter);
184        item;
185        item = gtk_style_cascade_iter_next (cascade, &iter))
186     {
187       if (GTK_IS_STYLE_PROVIDER_PRIVATE (item))
188         {
189           _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (item),
190                                               matcher,
191                                               lookup);
192         }
193       else
194         {
195           /* you lose */
196           g_warn_if_reached ();
197         }
198     }
199 }
200
201 static GtkCssChange
202 gtk_style_cascade_get_change (GtkStyleProviderPrivate *provider,
203                               const GtkCssMatcher     *matcher)
204 {
205   GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider);
206   GtkStyleCascadeIter iter;
207   GtkStyleProvider *item;
208   GtkCssChange change = 0;
209
210   for (item = gtk_style_cascade_iter_init (cascade, &iter);
211        item;
212        item = gtk_style_cascade_iter_next (cascade, &iter))
213     {
214       if (GTK_IS_STYLE_PROVIDER_PRIVATE (item))
215         {
216           change |= _gtk_style_provider_private_get_change (GTK_STYLE_PROVIDER_PRIVATE (item),
217                                                             matcher);
218         }
219       else
220         {
221           g_return_val_if_reached (GTK_CSS_CHANGE_ANY);
222         }
223     }
224
225   return change;
226 }
227
228 static void
229 gtk_style_cascade_provider_private_iface_init (GtkStyleProviderPrivateInterface *iface)
230 {
231   iface->get_color = gtk_style_cascade_get_color;
232   iface->lookup = gtk_style_cascade_lookup;
233   iface->get_change = gtk_style_cascade_get_change;
234 }
235
236 G_DEFINE_TYPE_EXTENDED (GtkStyleCascade, _gtk_style_cascade, G_TYPE_OBJECT, 0,
237                         G_IMPLEMENT_INTERFACE (GTK_TYPE_STYLE_PROVIDER,
238                                                gtk_style_cascade_provider_iface_init)
239                         G_IMPLEMENT_INTERFACE (GTK_TYPE_STYLE_PROVIDER_PRIVATE,
240                                                gtk_style_cascade_provider_private_iface_init));
241
242 static void
243 gtk_style_cascade_dispose (GObject *object)
244 {
245   GtkStyleCascade *cascade = GTK_STYLE_CASCADE (object);
246
247   _gtk_style_cascade_set_parent (cascade, NULL);
248   g_array_unref (cascade->providers);
249
250   G_OBJECT_CLASS (_gtk_style_cascade_parent_class)->dispose (object);
251 }
252
253 static void
254 _gtk_style_cascade_class_init (GtkStyleCascadeClass *klass)
255 {
256   GObjectClass *object_class = G_OBJECT_CLASS (klass);
257
258   object_class->dispose = gtk_style_cascade_dispose;
259 }
260
261 static void
262 style_provider_data_clear (gpointer data_)
263 {
264   GtkStyleProviderData *data = data_;
265
266   g_object_unref (data->provider);
267 }
268
269 static void
270 _gtk_style_cascade_init (GtkStyleCascade *cascade)
271 {
272   cascade->providers = g_array_new (FALSE, FALSE, sizeof (GtkStyleProviderData));
273   g_array_set_clear_func (cascade->providers, style_provider_data_clear);
274 }
275
276 GtkStyleCascade *
277 _gtk_style_cascade_new (void)
278 {
279   return g_object_new (GTK_TYPE_STYLE_CASCADE, NULL);
280 }
281
282 GtkStyleCascade *
283 _gtk_style_cascade_get_for_screen (GdkScreen *screen)
284 {
285   GtkStyleCascade *cascade;
286   static GQuark quark = 0;
287
288   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
289
290   if (G_UNLIKELY (!quark))
291     quark = g_quark_from_static_string ("gtk-style-cascade");
292
293   cascade = g_object_get_qdata (G_OBJECT (screen), quark);
294   if (cascade == NULL)
295     {
296       cascade = _gtk_style_cascade_new ();
297       g_object_set_qdata_full (G_OBJECT (screen), quark, cascade, g_object_unref);
298     }
299
300   return cascade;
301 }
302
303 void
304 _gtk_style_cascade_set_parent (GtkStyleCascade *cascade,
305                                GtkStyleCascade *parent)
306 {
307   g_return_if_fail (GTK_IS_STYLE_CASCADE (cascade));
308   g_return_if_fail (parent == NULL || GTK_IS_STYLE_CASCADE (parent));
309   if (parent)
310     g_return_if_fail (parent->parent == NULL);
311
312   if (cascade->parent == parent)
313     return;
314
315   if (parent)
316     g_object_ref (parent);
317
318   if (cascade->parent)
319     g_object_unref (cascade->parent);
320
321   cascade->parent = parent;
322 }
323
324 void
325 _gtk_style_cascade_add_provider (GtkStyleCascade  *cascade,
326                                  GtkStyleProvider *provider,
327                                  guint             priority)
328 {
329   GtkStyleProviderData data;
330   guint i;
331
332   g_return_if_fail (GTK_IS_STYLE_CASCADE (cascade));
333   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
334   g_return_if_fail (GTK_STYLE_PROVIDER (cascade) != provider);
335
336   data.provider = g_object_ref (provider);
337   data.priority = priority;
338
339   /* ensure it gets removed first */
340   _gtk_style_cascade_remove_provider (cascade, provider);
341
342   for (i = 0; i < cascade->providers->len; i++)
343     {
344       if (g_array_index (cascade->providers, GtkStyleProviderData, i).priority > priority)
345         break;
346     }
347   g_array_insert_val (cascade->providers, i, data);
348 }
349
350 void
351 _gtk_style_cascade_remove_provider (GtkStyleCascade  *cascade,
352                                     GtkStyleProvider *provider)
353 {
354   guint i;
355
356   g_return_if_fail (GTK_IS_STYLE_CASCADE (cascade));
357   g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
358
359   for (i = 0; i < cascade->providers->len; i++)
360     {
361       GtkStyleProviderData *data = &g_array_index (cascade->providers, GtkStyleProviderData, i);
362
363       if (data->provider == provider)
364         {
365           g_array_remove_index (cascade->providers, i);
366           break;
367         }
368     }
369 }
370