]> Pileus Git - ~andy/gtk/blob - gtk/gtkwidgetpath.c
GtkContainer: Add method to get the GtkWidgetPath for a child.
[~andy/gtk] / gtk / gtkwidgetpath.c
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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include <string.h>
23
24 #include "gtkwidget.h"
25 #include "gtkwidgetpath.h"
26
27 typedef struct GtkPathElement GtkPathElement;
28
29 struct GtkPathElement
30 {
31   GType type;
32   GQuark name;
33   GHashTable *regions;
34   GArray *classes;
35 };
36
37 struct GtkWidgetPath
38 {
39   GArray *elems; /* First element contains the described widget */
40 };
41
42 GtkWidgetPath *
43 gtk_widget_path_new (void)
44 {
45   GtkWidgetPath *path;
46
47   path = g_slice_new0 (GtkWidgetPath);
48   path->elems = g_array_new (FALSE, TRUE, sizeof (GtkPathElement));
49
50   return path;
51 }
52
53 GtkWidgetPath *
54 gtk_widget_path_copy (const GtkWidgetPath *path)
55 {
56   GtkWidgetPath *new_path;
57   guint i;
58
59   g_return_val_if_fail (path != NULL, NULL);
60
61   new_path = gtk_widget_path_new ();
62
63   for (i = 0; i < path->elems->len; i++)
64     {
65       GtkPathElement *elem, new = { 0 };
66
67       elem = &g_array_index (path->elems, GtkPathElement, i);
68
69       new.type = elem->type;
70       new.name = elem->name;
71
72       if (elem->regions)
73         {
74           GHashTableIter iter;
75           gpointer key, value;
76
77           g_hash_table_iter_init (&iter, elem->regions);
78           new.regions = g_hash_table_new (NULL, NULL);
79
80           while (g_hash_table_iter_next (&iter, &key, &value))
81             g_hash_table_insert (new.regions, key, value);
82         }
83
84       g_array_append_val (new_path->elems, new);
85     }
86
87   return new_path;
88 }
89
90 void
91 gtk_widget_path_free (GtkWidgetPath *path)
92 {
93   guint i;
94
95   g_return_if_fail (path != NULL);
96
97   for (i = 0; i < path->elems->len; i++)
98     {
99       GtkPathElement *elem;
100
101       elem = &g_array_index (path->elems, GtkPathElement, i);
102
103       if (elem->regions)
104         g_hash_table_destroy (elem->regions);
105
106       if (elem->classes)
107         g_array_free (elem->classes, TRUE);
108     }
109
110   g_array_free (path->elems, TRUE);
111   g_slice_free (GtkWidgetPath, path);
112 }
113
114 guint
115 gtk_widget_path_length (const GtkWidgetPath *path)
116 {
117   g_return_val_if_fail (path != NULL, 0);
118
119   return path->elems->len;
120 }
121
122 guint
123 gtk_widget_path_prepend_type (GtkWidgetPath *path,
124                               GType          type)
125 {
126   GtkPathElement new = { 0 };
127
128   g_return_val_if_fail (path != NULL, 0);
129   g_return_val_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET), 0);
130
131   new.type = type;
132   g_array_prepend_val (path->elems, new);
133
134   return 0;
135 }
136
137 guint
138 gtk_widget_path_append_type (GtkWidgetPath *path,
139                              GType          type)
140 {
141   GtkPathElement new = { 0 };
142
143   g_return_val_if_fail (path != NULL, 0);
144   g_return_val_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET), 0);
145
146   new.type = type;
147   g_array_append_val (path->elems, new);
148
149   return path->elems->len - 1;
150 }
151
152 GType
153 gtk_widget_path_iter_get_widget_type (const GtkWidgetPath *path,
154                                       guint                pos)
155 {
156   GtkPathElement *elem;
157
158   g_return_val_if_fail (path != NULL, G_TYPE_INVALID);
159   g_return_val_if_fail (pos < path->elems->len, G_TYPE_INVALID);
160
161   elem = &g_array_index (path->elems, GtkPathElement, pos);
162   return elem->type;
163 }
164
165 void
166 gtk_widget_path_iter_set_widget_type (GtkWidgetPath *path,
167                                       guint          pos,
168                                       GType          type)
169 {
170   GtkPathElement *elem;
171
172   g_return_if_fail (path != NULL);
173   g_return_if_fail (pos < path->elems->len);
174   g_return_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET));
175
176   elem = &g_array_index (path->elems, GtkPathElement, pos);
177   elem->type = type;
178 }
179
180 G_CONST_RETURN gchar *
181 gtk_widget_path_iter_get_name (const GtkWidgetPath *path,
182                                guint                pos)
183 {
184   GtkPathElement *elem;
185
186   g_return_val_if_fail (path != NULL, NULL);
187   g_return_val_if_fail (pos < path->elems->len, NULL);
188
189   elem = &g_array_index (path->elems, GtkPathElement, pos);
190   return g_quark_to_string (elem->name);
191 }
192
193 void
194 gtk_widget_path_iter_set_name (GtkWidgetPath *path,
195                                guint          pos,
196                                const gchar   *name)
197 {
198   GtkPathElement *elem;
199
200   g_return_if_fail (path != NULL);
201   g_return_if_fail (pos < path->elems->len);
202   g_return_if_fail (name != NULL);
203
204   elem = &g_array_index (path->elems, GtkPathElement, pos);
205
206   elem->name = g_quark_from_string (name);
207 }
208
209 gboolean
210 gtk_widget_path_iter_has_qname (const GtkWidgetPath *path,
211                                 guint                pos,
212                                 GQuark               qname)
213 {
214   GtkPathElement *elem;
215
216   g_return_val_if_fail (path != NULL, FALSE);
217   g_return_val_if_fail (qname != 0, FALSE);
218   g_return_val_if_fail (pos < path->elems->len, FALSE);
219
220   elem = &g_array_index (path->elems, GtkPathElement, pos);
221
222   return (elem->name == qname);
223 }
224
225 gboolean
226 gtk_widget_path_iter_has_name (const GtkWidgetPath *path,
227                                guint                pos,
228                                const gchar         *name)
229 {
230   GQuark qname;
231
232   g_return_val_if_fail (path != NULL, FALSE);
233   g_return_val_if_fail (name != NULL, FALSE);
234   g_return_val_if_fail (pos < path->elems->len, FALSE);
235
236   qname = g_quark_try_string (name);
237
238   if (qname == 0)
239     return FALSE;
240
241   return gtk_widget_path_iter_has_qname (path, pos, qname);
242 }
243
244 void
245 gtk_widget_path_iter_add_class (GtkWidgetPath *path,
246                                 guint          pos,
247                                 const gchar   *name)
248 {
249   GtkPathElement *elem;
250   gboolean added = FALSE;
251   GQuark qname;
252   guint i;
253
254   g_return_if_fail (path != NULL);
255   g_return_if_fail (pos < path->elems->len);
256   g_return_if_fail (name != NULL);
257
258   elem = &g_array_index (path->elems, GtkPathElement, pos);
259   qname = g_quark_from_string (name);
260
261   if (!elem->classes)
262     elem->classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
263
264   for (i = 0; i < elem->classes->len; i++)
265     {
266       GQuark quark;
267
268       quark = g_array_index (elem->classes, GQuark, i);
269
270       if (qname == quark)
271         {
272           /* Already there */
273           added = TRUE;
274           break;
275         }
276       if (qname < quark)
277         {
278           g_array_insert_val (elem->classes, i, qname);
279           added = TRUE;
280           break;
281         }
282     }
283
284   if (!added)
285     g_array_append_val (elem->classes, qname);
286 }
287
288 void
289 gtk_widget_path_iter_remove_class (GtkWidgetPath *path,
290                                    guint          pos,
291                                    const gchar   *name)
292 {
293   GtkPathElement *elem;
294   GQuark qname;
295   guint i;
296
297   g_return_if_fail (path != NULL);
298   g_return_if_fail (pos < path->elems->len);
299   g_return_if_fail (name != NULL);
300
301   qname = g_quark_try_string (name);
302
303   if (qname == 0)
304     return;
305
306   elem = &g_array_index (path->elems, GtkPathElement, pos);
307
308   if (!elem->classes)
309     return;
310
311   for (i = 0; i < elem->classes->len; i++)
312     {
313       GQuark quark;
314
315       quark = g_array_index (elem->classes, GQuark, i);
316
317       if (quark > qname)
318         break;
319       else if (quark == qname)
320         {
321           g_array_remove_index (elem->classes, i);
322           break;
323         }
324     }
325 }
326
327 void
328 gtk_widget_path_iter_clear_classes (GtkWidgetPath *path,
329                                     guint          pos)
330 {
331   GtkPathElement *elem;
332
333   g_return_if_fail (path != NULL);
334   g_return_if_fail (pos < path->elems->len);
335
336   elem = &g_array_index (path->elems, GtkPathElement, pos);
337
338   if (!elem->classes)
339     return;
340
341   if (elem->classes->len > 0)
342     g_array_remove_range (elem->classes, 0, elem->classes->len);
343 }
344
345 GSList *
346 gtk_widget_path_iter_list_classes (const GtkWidgetPath *path,
347                                    guint                pos)
348 {
349   GtkPathElement *elem;
350   GSList *list = NULL;
351   guint i;
352
353   g_return_val_if_fail (path != NULL, NULL);
354   g_return_val_if_fail (pos < path->elems->len, NULL);
355
356   elem = &g_array_index (path->elems, GtkPathElement, pos);
357
358   if (!elem->classes)
359     return NULL;
360
361   for (i = 0; i < elem->classes->len; i++)
362     {
363       GQuark quark;
364
365       quark = g_array_index (elem->classes, GQuark, i);
366       list = g_slist_prepend (list, (gchar *) g_quark_to_string (quark));
367     }
368
369   return g_slist_reverse (list);
370 }
371
372 gboolean
373 gtk_widget_path_iter_has_qclass (const GtkWidgetPath *path,
374                                  guint                pos,
375                                  GQuark               qname)
376 {
377   GtkPathElement *elem;
378   guint i;
379
380   g_return_val_if_fail (path != NULL, FALSE);
381   g_return_val_if_fail (pos < path->elems->len, FALSE);
382   g_return_val_if_fail (qname != 0, FALSE);
383
384   elem = &g_array_index (path->elems, GtkPathElement, pos);
385
386   if (!elem->classes)
387     return FALSE;
388
389   for (i = 0; i < elem->classes->len; i++)
390     {
391       GQuark quark;
392
393       quark = g_array_index (elem->classes, GQuark, i);
394
395       if (quark == qname)
396         return TRUE;
397       else if (quark > qname)
398         break;
399     }
400
401   return FALSE;
402 }
403
404 gboolean
405 gtk_widget_path_iter_has_class (const GtkWidgetPath *path,
406                                 guint                pos,
407                                 const gchar         *name)
408 {
409   GQuark qname;
410
411   g_return_val_if_fail (path != NULL, FALSE);
412   g_return_val_if_fail (pos < path->elems->len, FALSE);
413   g_return_val_if_fail (name != NULL, FALSE);
414
415   qname = g_quark_try_string (name);
416
417   if (qname == 0)
418     return FALSE;
419
420   return gtk_widget_path_iter_has_qclass (path, pos, qname);
421 }
422
423 void
424 gtk_widget_path_iter_add_region (GtkWidgetPath  *path,
425                                  guint           pos,
426                                  const gchar    *name,
427                                  GtkRegionFlags  flags)
428 {
429   GtkPathElement *elem;
430   GQuark qname;
431
432   g_return_if_fail (path != NULL);
433   g_return_if_fail (pos < path->elems->len);
434   g_return_if_fail (name != NULL);
435
436   elem = &g_array_index (path->elems, GtkPathElement, pos);
437   qname = g_quark_from_string (name);
438
439   if (!elem->regions)
440     elem->regions = g_hash_table_new (NULL, NULL);
441
442   g_hash_table_insert (elem->regions,
443                        GUINT_TO_POINTER (qname),
444                        GUINT_TO_POINTER (flags));
445 }
446
447 void
448 gtk_widget_path_iter_remove_region (GtkWidgetPath *path,
449                                     guint          pos,
450                                     const gchar   *name)
451 {
452   GtkPathElement *elem;
453   GQuark qname;
454
455   g_return_if_fail (path != NULL);
456   g_return_if_fail (pos < path->elems->len);
457   g_return_if_fail (name != NULL);
458
459   qname = g_quark_try_string (name);
460
461   if (qname == 0)
462     return;
463
464   elem = &g_array_index (path->elems, GtkPathElement, pos);
465
466   if (elem->regions)
467     g_hash_table_remove (elem->regions, GUINT_TO_POINTER (qname));
468 }
469
470 void
471 gtk_widget_path_iter_clear_regions (GtkWidgetPath *path,
472                                     guint          pos)
473 {
474   GtkPathElement *elem;
475
476   g_return_if_fail (path != NULL);
477   g_return_if_fail (pos < path->elems->len);
478
479   elem = &g_array_index (path->elems, GtkPathElement, pos);
480
481   if (elem->regions)
482     g_hash_table_remove_all (elem->regions);
483 }
484
485 GSList *
486 gtk_widget_path_iter_list_regions (const GtkWidgetPath *path,
487                                    guint                pos)
488 {
489   GtkPathElement *elem;
490   GHashTableIter iter;
491   GSList *list = NULL;
492   gpointer key;
493
494   g_return_val_if_fail (path != NULL, NULL);
495   g_return_val_if_fail (pos < path->elems->len, NULL);
496
497   elem = &g_array_index (path->elems, GtkPathElement, pos);
498
499   if (!elem->regions)
500     return NULL;
501
502   g_hash_table_iter_init (&iter, elem->regions);
503
504   while (g_hash_table_iter_next (&iter, &key, NULL))
505     {
506       GQuark qname;
507
508       qname = GPOINTER_TO_UINT (key);
509       list = g_slist_prepend (list, (gchar *) g_quark_to_string (qname));
510     }
511
512   return list;
513 }
514
515 gboolean
516 gtk_widget_path_iter_has_qregion (const GtkWidgetPath *path,
517                                   guint                pos,
518                                   GQuark               qname,
519                                   GtkRegionFlags      *flags)
520 {
521   GtkPathElement *elem;
522   gpointer value;
523
524   g_return_val_if_fail (path != NULL, FALSE);
525   g_return_val_if_fail (pos < path->elems->len, FALSE);
526   g_return_val_if_fail (qname != 0, FALSE);
527
528   elem = &g_array_index (path->elems, GtkPathElement, pos);
529
530   if (!elem->regions)
531     return FALSE;
532
533   if (!g_hash_table_lookup_extended (elem->regions,
534                                      GUINT_TO_POINTER (qname),
535                                      NULL, &value))
536     return FALSE;
537
538   if (flags)
539     *flags = GPOINTER_TO_UINT (value);
540
541   return TRUE;
542 }
543
544 gboolean
545 gtk_widget_path_iter_has_region (const GtkWidgetPath *path,
546                                  guint                pos,
547                                  const gchar         *name,
548                                  GtkRegionFlags      *flags)
549 {
550   GQuark qname;
551
552   g_return_val_if_fail (path != NULL, FALSE);
553   g_return_val_if_fail (pos < path->elems->len, FALSE);
554   g_return_val_if_fail (name != NULL, FALSE);
555
556   qname = g_quark_try_string (name);
557
558   if (qname == 0)
559     return FALSE;
560
561   return gtk_widget_path_iter_has_qregion (path, pos, qname, flags);
562 }
563
564 GType
565 gtk_widget_path_get_widget_type (const GtkWidgetPath *path)
566 {
567   GtkPathElement *elem;
568
569   g_return_val_if_fail (path != NULL, G_TYPE_INVALID);
570
571   elem = &g_array_index (path->elems, GtkPathElement, 0);
572   return elem->type;
573 }
574
575 gboolean
576 gtk_widget_path_is_type (const GtkWidgetPath *path,
577                          GType                type)
578 {
579   GtkPathElement *elem;
580
581   g_return_val_if_fail (path != NULL, FALSE);
582   g_return_val_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET), FALSE);
583
584   elem = &g_array_index (path->elems, GtkPathElement, 0);
585
586   if (elem->type == type ||
587       g_type_is_a (elem->type, type))
588     return TRUE;
589
590   return FALSE;
591 }
592
593 gboolean
594 gtk_widget_path_has_parent (const GtkWidgetPath *path,
595                             GType                type)
596 {
597   guint i;
598
599   g_return_val_if_fail (path != NULL, FALSE);
600   g_return_val_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET), FALSE);
601
602   for (i = 1; i < path->elems->len; i++)
603     {
604       GtkPathElement *elem;
605
606       elem = &g_array_index (path->elems, GtkPathElement, i);
607
608       if (elem->type == type ||
609           g_type_is_a (elem->type, type))
610         return TRUE;
611     }
612
613   return FALSE;
614 }