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