]> Pileus Git - ~andy/gtk/blob - gtk/gtkwidgetpath.c
[GI] Fixes of existing incorrect annotations
[~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 /**
28  * SECTION:gtkwidgetpath
29  * @Short_description: Widget path abstraction
30  * @Title: GtkWidgetPath
31  * @See_also: #GtkStyleContext
32  *
33  * GtkWidgetPath is a boxed type that represents a widget hierarchy from
34  * the topmost widget, typically a toplevel, to any child. This widget
35  * path abstraction is used in #GtkStyleContext on behalf of the real
36  * widget in order to query style information.
37  *
38  * If you are using GTK+ widgets, you probably will not need to use
39  * this API directly, as there is gtk_widget_get_path(), and the style
40  * context returned by gtk_widget_get_style_context() will be automatically
41  * updated on widget hierarchy changes.
42  *
43  * The widget path generation is generally simple:
44  * <example>
45  * <title>Defining a button within a window</title>
46  * <programlisting>
47  * {
48  *   GtkWidgetPath *path;
49  *
50  *   path = gtk_widget_path_new ();
51  *   gtk_widget_path_append_type (path, GTK_TYPE_WINDOW);
52  *   gtk_widget_path_append_type (path, GTK_TYPE_BUTTON);
53  * }
54  * </programlisting>
55  * </example>
56  *
57  * Although more complex information, such as widget names, or
58  * different classes (property that may be used by other widget
59  * types) and intermediate regions may be included:
60  *
61  * <example>
62  * <title>Defining the first tab widget in a notebook</title>
63  * <programlisting>
64  * {
65  *   GtkWidgetPath *path;
66  *   guint pos;
67  *
68  *   path = gtk_widget_path_new ();
69  *
70  *   pos = gtk_widget_path_append_type (path, GTK_TYPE_NOTEBOOK);
71  *   gtk_widget_path_iter_add_region (path, pos, "tab", GTK_REGION_EVEN | GTK_REGION_FIRST);
72  *
73  *   pos = gtk_widget_path_append_type (path, GTK_TYPE_LABEL);
74  *   gtk_widget_path_iter_set_name (path, pos, "first tab label");
75  * }
76  * </programlisting>
77  * </example>
78  *
79  * All this information will be used to match the style information
80  * that applies to the described widget.
81  **/
82
83 G_DEFINE_BOXED_TYPE (GtkWidgetPath, gtk_widget_path,
84                      gtk_widget_path_copy, gtk_widget_path_free)
85
86
87 typedef struct GtkPathElement GtkPathElement;
88
89 struct GtkPathElement
90 {
91   GType type;
92   GQuark name;
93   GHashTable *regions;
94   GArray *classes;
95 };
96
97 struct _GtkWidgetPath
98 {
99   GArray *elems; /* First element contains the described widget */
100 };
101
102 /**
103  * gtk_widget_path_new:
104  *
105  * Returns an empty widget path.
106  *
107  * Returns: (transfer full): A newly created, empty, #GtkWidgetPath
108  *
109  * Since: 3.0
110  **/
111 GtkWidgetPath *
112 gtk_widget_path_new (void)
113 {
114   GtkWidgetPath *path;
115
116   path = g_slice_new0 (GtkWidgetPath);
117   path->elems = g_array_new (FALSE, TRUE, sizeof (GtkPathElement));
118
119   return path;
120 }
121
122 /**
123  * gtk_widget_path_copy:
124  * @path: a #GtkWidgetPath
125  *
126  * Returns a copy of @path
127  *
128  * Returns: (transfer full): a copy of @path
129  *
130  * Since: 3.0
131  **/
132 GtkWidgetPath *
133 gtk_widget_path_copy (const GtkWidgetPath *path)
134 {
135   GtkWidgetPath *new_path;
136   guint i;
137
138   g_return_val_if_fail (path != NULL, NULL);
139
140   new_path = gtk_widget_path_new ();
141
142   for (i = 0; i < path->elems->len; i++)
143     {
144       GtkPathElement *elem, new = { 0 };
145
146       elem = &g_array_index (path->elems, GtkPathElement, i);
147
148       new.type = elem->type;
149       new.name = elem->name;
150
151       if (elem->regions)
152         {
153           GHashTableIter iter;
154           gpointer key, value;
155
156           g_hash_table_iter_init (&iter, elem->regions);
157           new.regions = g_hash_table_new (NULL, NULL);
158
159           while (g_hash_table_iter_next (&iter, &key, &value))
160             g_hash_table_insert (new.regions, key, value);
161         }
162
163       if (elem->classes)
164         {
165           new.classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
166           g_array_append_vals (new.classes, elem->classes->data, elem->classes->len);
167         }
168
169       g_array_append_val (new_path->elems, new);
170     }
171
172   return new_path;
173 }
174
175 /**
176  * gtk_widget_path_free:
177  * @path: a #GtkWidgetPath
178  *
179  * Frees a #GtkWidgetPath.
180  *
181  * Since: 3.0
182  **/
183 void
184 gtk_widget_path_free (GtkWidgetPath *path)
185 {
186   guint i;
187
188   g_return_if_fail (path != NULL);
189
190   for (i = 0; i < path->elems->len; i++)
191     {
192       GtkPathElement *elem;
193
194       elem = &g_array_index (path->elems, GtkPathElement, i);
195
196       if (elem->regions)
197         g_hash_table_destroy (elem->regions);
198
199       if (elem->classes)
200         g_array_free (elem->classes, TRUE);
201     }
202
203   g_array_free (path->elems, TRUE);
204   g_slice_free (GtkWidgetPath, path);
205 }
206
207 /**
208  * gtk_widget_path_length:
209  * @path: a #GtkWidgetPath
210  *
211  * Returns the number of #GtkWidget #GTypes between the represented
212  * widget and its topmost container.
213  *
214  * Returns: the number of elements in the path
215  *
216  * Since: 3.0
217  **/
218 gint
219 gtk_widget_path_length (const GtkWidgetPath *path)
220 {
221   g_return_val_if_fail (path != NULL, 0);
222
223   return path->elems->len;
224 }
225
226 /**
227  * gtk_widget_path_prepend_type:
228  * @path: a #GtkWidgetPath
229  * @type: widget type to prepend
230  *
231  * Prepends a widget type to the widget hierachy represented by @path.
232  *
233  * Since: 3.0
234  **/
235 void
236 gtk_widget_path_prepend_type (GtkWidgetPath *path,
237                               GType          type)
238 {
239   GtkPathElement new = { 0 };
240
241   g_return_if_fail (path != NULL);
242
243   new.type = type;
244   g_array_prepend_val (path->elems, new);
245 }
246
247 /**
248  * gtk_widget_path_append_type:
249  * @path: a #GtkWidgetPath
250  * @type: widget type to append
251  *
252  * Appends a widget type to the widget hierachy represented by @path.
253  *
254  * Returns: the position where the element was inserted
255  *
256  * Since: 3.0
257  **/
258 gint
259 gtk_widget_path_append_type (GtkWidgetPath *path,
260                              GType          type)
261 {
262   GtkPathElement new = { 0 };
263
264   g_return_val_if_fail (path != NULL, 0);
265
266   new.type = type;
267   g_array_append_val (path->elems, new);
268
269   return path->elems->len - 1;
270 }
271
272 /**
273  * gtk_widget_path_iter_get_object_type:
274  * @path: a #GtkWidgetPath
275  * @pos: position to get the object type for, -1 for the path head
276  *
277  * Returns the object #GType that is at position @pos in the widget
278  * hierarchy defined in @path.
279  *
280  * Returns: a widget type
281  *
282  * Since: 3.0
283  **/
284 GType
285 gtk_widget_path_iter_get_object_type (const GtkWidgetPath *path,
286                                       gint                 pos)
287 {
288   GtkPathElement *elem;
289
290   g_return_val_if_fail (path != NULL, G_TYPE_INVALID);
291   g_return_val_if_fail (path->elems->len != 0, G_TYPE_INVALID);
292
293   if (pos < 0 || pos > path->elems->len)
294     pos = path->elems->len - 1;
295
296   elem = &g_array_index (path->elems, GtkPathElement, pos);
297   return elem->type;
298 }
299
300 /**
301  * gtk_widget_path_iter_set_object_type:
302  * @path: a #GtkWidgetPath
303  * @pos: position to modify, -1 for the path head
304  * @type: object type to set
305  *
306  * Sets the object type for a given position in the widget hierarchy
307  * defined by @path.
308  *
309  * Since: 3.0
310  **/
311 void
312 gtk_widget_path_iter_set_object_type (GtkWidgetPath *path,
313                                       gint           pos,
314                                       GType          type)
315 {
316   GtkPathElement *elem;
317
318   g_return_if_fail (path != NULL);
319   g_return_if_fail (path->elems->len != 0);
320
321   if (pos < 0 || pos > path->elems->len)
322     pos = path->elems->len - 1;
323
324   elem = &g_array_index (path->elems, GtkPathElement, pos);
325   elem->type = type;
326 }
327
328 /**
329  * gtk_widget_path_iter_get_name:
330  * @path: a #GtkWidgetPath
331  * @pos: position to get the widget name for, -1 for the path head
332  *
333  * Returns the name corresponding to the widget found at
334  * the position @pos in the widget hierarchy defined by
335  * @path
336  *
337  * Returns: The widget name, or %NULL if none was set.
338  **/
339 G_CONST_RETURN gchar *
340 gtk_widget_path_iter_get_name (const GtkWidgetPath *path,
341                                gint                 pos)
342 {
343   GtkPathElement *elem;
344
345   g_return_val_if_fail (path != NULL, NULL);
346   g_return_val_if_fail (path->elems->len != 0, NULL);
347
348   if (pos < 0 || pos > path->elems->len)
349     pos = path->elems->len - 1;
350
351   elem = &g_array_index (path->elems, GtkPathElement, pos);
352   return g_quark_to_string (elem->name);
353 }
354
355 /**
356  * gtk_widget_path_iter_set_name:
357  * @path: a #GtkWidgetPath
358  * @pos: position to modify, -1 for the path head
359  * @name: widget name
360  *
361  * Sets the widget name for the widget found at position @pos
362  * in the widget hierarchy defined by @path.
363  *
364  * Since: 3.0
365  **/
366 void
367 gtk_widget_path_iter_set_name (GtkWidgetPath *path,
368                                gint           pos,
369                                const gchar   *name)
370 {
371   GtkPathElement *elem;
372
373   g_return_if_fail (path != NULL);
374   g_return_if_fail (path->elems->len != 0);
375   g_return_if_fail (name != NULL);
376
377   if (pos < 0 || pos > path->elems->len)
378     pos = path->elems->len - 1;
379
380   elem = &g_array_index (path->elems, GtkPathElement, pos);
381
382   elem->name = g_quark_from_string (name);
383 }
384
385 /**
386  * gtk_widget_path_iter_has_qname:
387  * @path: a #GtkWidgetPath
388  * @pos: position to query, -1 for the path head
389  * @qname: widget name as a #GQuark
390  *
391  * See gtk_widget_path_iter_has_name(). This is a version
392  * that operates on #GQuark<!-- -->s.
393  *
394  * Returns: %TRUE if the widget at @pos has this name
395  *
396  * Since: 3.0
397  **/
398 gboolean
399 gtk_widget_path_iter_has_qname (const GtkWidgetPath *path,
400                                 gint                 pos,
401                                 GQuark               qname)
402 {
403   GtkPathElement *elem;
404
405   g_return_val_if_fail (path != NULL, FALSE);
406   g_return_val_if_fail (path->elems->len != 0, FALSE);
407   g_return_val_if_fail (qname != 0, FALSE);
408
409   if (pos < 0 || pos > path->elems->len)
410     pos = path->elems->len - 1;
411
412   elem = &g_array_index (path->elems, GtkPathElement, pos);
413
414   return (elem->name == qname);
415 }
416
417 /**
418  * gtk_widget_path_iter_has_name:
419  * @path: a #GtkWidgetPath
420  * @pos: position to query, -1 for the path head
421  * @name: a widget name
422  *
423  * Returns %TRUE if the widget at position @pos has the name @name,
424  * %FALSE otherwise.
425  *
426  * Returns: %TRUE if the widget at @pos has this name
427  *
428  * Since: 3.0
429  **/
430 gboolean
431 gtk_widget_path_iter_has_name (const GtkWidgetPath *path,
432                                gint                 pos,
433                                const gchar         *name)
434 {
435   GQuark qname;
436
437   g_return_val_if_fail (path != NULL, FALSE);
438   g_return_val_if_fail (path->elems->len != 0, FALSE);
439
440   if (pos < 0 || pos > path->elems->len)
441     pos = path->elems->len - 1;
442
443   qname = g_quark_try_string (name);
444
445   if (qname == 0)
446     return FALSE;
447
448   return gtk_widget_path_iter_has_qname (path, pos, qname);
449 }
450
451 /**
452  * gtk_widget_path_iter_add_class:
453  * @path: a #GtkWidget
454  * @pos: position to modify, -1 for the path head
455  * @name: a class name
456  *
457  * Adds the class @name to the widget at position @pos in
458  * the hierarchy defined in @path. See
459  * gtk_style_context_add_class().
460  *
461  * Since: 3.0
462  **/
463 void
464 gtk_widget_path_iter_add_class (GtkWidgetPath *path,
465                                 gint           pos,
466                                 const gchar   *name)
467 {
468   GtkPathElement *elem;
469   gboolean added = FALSE;
470   GQuark qname;
471   guint i;
472
473   g_return_if_fail (path != NULL);
474   g_return_if_fail (path->elems->len != 0);
475   g_return_if_fail (name != NULL);
476
477   if (pos < 0 || pos > path->elems->len)
478     pos = path->elems->len - 1;
479
480   elem = &g_array_index (path->elems, GtkPathElement, pos);
481   qname = g_quark_from_string (name);
482
483   if (!elem->classes)
484     elem->classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
485
486   for (i = 0; i < elem->classes->len; i++)
487     {
488       GQuark quark;
489
490       quark = g_array_index (elem->classes, GQuark, i);
491
492       if (qname == quark)
493         {
494           /* Already there */
495           added = TRUE;
496           break;
497         }
498       if (qname < quark)
499         {
500           g_array_insert_val (elem->classes, i, qname);
501           added = TRUE;
502           break;
503         }
504     }
505
506   if (!added)
507     g_array_append_val (elem->classes, qname);
508 }
509
510 /**
511  * gtk_widget_path_iter_remove_class:
512  * @path: a #GtkWidgetPath
513  * @pos: position to modify, -1 for the path head
514  * @name: class name
515  *
516  * Removes the class @name from the widget at position @pos in
517  * the hierarchy defined in @path.
518  *
519  * Since: 3.0
520  **/
521 void
522 gtk_widget_path_iter_remove_class (GtkWidgetPath *path,
523                                    gint           pos,
524                                    const gchar   *name)
525 {
526   GtkPathElement *elem;
527   GQuark qname;
528   guint i;
529
530   g_return_if_fail (path != NULL);
531   g_return_if_fail (path->elems->len != 0);
532   g_return_if_fail (name != NULL);
533
534   if (pos < 0 || pos > path->elems->len)
535     pos = path->elems->len - 1;
536
537   qname = g_quark_try_string (name);
538
539   if (qname == 0)
540     return;
541
542   elem = &g_array_index (path->elems, GtkPathElement, pos);
543
544   if (!elem->classes)
545     return;
546
547   for (i = 0; i < elem->classes->len; i++)
548     {
549       GQuark quark;
550
551       quark = g_array_index (elem->classes, GQuark, i);
552
553       if (quark > qname)
554         break;
555       else if (quark == qname)
556         {
557           g_array_remove_index (elem->classes, i);
558           break;
559         }
560     }
561 }
562
563 /**
564  * gtk_widget_path_iter_clear_classes:
565  * @path: a #GtkWidget
566  * @pos: position to modify, -1 for the path head
567  *
568  * Removes all classes from the widget at position @pos in the
569  * hierarchy defined in @path.
570  *
571  * Since: 3.0
572  **/
573 void
574 gtk_widget_path_iter_clear_classes (GtkWidgetPath *path,
575                                     gint           pos)
576 {
577   GtkPathElement *elem;
578
579   g_return_if_fail (path != NULL);
580   g_return_if_fail (path->elems->len != 0);
581
582   if (pos < 0 || pos > path->elems->len)
583     pos = path->elems->len - 1;
584
585   elem = &g_array_index (path->elems, GtkPathElement, pos);
586
587   if (!elem->classes)
588     return;
589
590   if (elem->classes->len > 0)
591     g_array_remove_range (elem->classes, 0, elem->classes->len);
592 }
593
594 /**
595  * gtk_widget_path_iter_list_classes:
596  * @path: a #GtkWidgetPath
597  * @pos: position to query, -1 for the path head
598  *
599  * Returns a list with all the class names defined for the widget
600  * at position @pos in the hierarchy defined in @path.
601  *
602  * Returns: (transfer container) (element-type utf8): The list of
603  *          classes, This is a list of strings, the #GSList contents
604  *          are owned by GTK+, but you should use g_slist_free() to
605  *          free the list itself.
606  *
607  * Since: 3.0
608  **/
609 GSList *
610 gtk_widget_path_iter_list_classes (const GtkWidgetPath *path,
611                                    gint                 pos)
612 {
613   GtkPathElement *elem;
614   GSList *list = NULL;
615   guint i;
616
617   g_return_val_if_fail (path != NULL, NULL);
618   g_return_val_if_fail (path->elems->len != 0, NULL);
619
620   if (pos < 0 || pos > path->elems->len)
621     pos = path->elems->len - 1;
622
623   elem = &g_array_index (path->elems, GtkPathElement, pos);
624
625   if (!elem->classes)
626     return NULL;
627
628   for (i = 0; i < elem->classes->len; i++)
629     {
630       GQuark quark;
631
632       quark = g_array_index (elem->classes, GQuark, i);
633       list = g_slist_prepend (list, (gchar *) g_quark_to_string (quark));
634     }
635
636   return g_slist_reverse (list);
637 }
638
639 /**
640  * gtk_widget_path_iter_has_qclass:
641  * @path: a #GtkWidgetPath
642  * @pos: position to query, -1 for the path head
643  * @qname: class name as a #GQuark
644  *
645  * See gtk_widget_path_iter_has_class(). This is a version that operates
646  * with GQuark<!-- -->s.
647  *
648  * Returns: %TRUE if the widget at @pos has the class defined.
649  *
650  * Since: 3.0
651  **/
652 gboolean
653 gtk_widget_path_iter_has_qclass (const GtkWidgetPath *path,
654                                  gint                 pos,
655                                  GQuark               qname)
656 {
657   GtkPathElement *elem;
658   guint i;
659
660   g_return_val_if_fail (path != NULL, FALSE);
661   g_return_val_if_fail (path->elems->len != 0, FALSE);
662   g_return_val_if_fail (qname != 0, FALSE);
663
664   if (pos < 0 || pos > path->elems->len)
665     pos = path->elems->len - 1;
666
667   elem = &g_array_index (path->elems, GtkPathElement, pos);
668
669   if (!elem->classes)
670     return FALSE;
671
672   for (i = 0; i < elem->classes->len; i++)
673     {
674       GQuark quark;
675
676       quark = g_array_index (elem->classes, GQuark, i);
677
678       if (quark == qname)
679         return TRUE;
680       else if (quark > qname)
681         break;
682     }
683
684   return FALSE;
685 }
686
687 /**
688  * gtk_widget_path_iter_has_class:
689  * @path: a #GtkWidgetPath
690  * @pos: position to query, -1 for the path head
691  * @name: class name
692  *
693  * Returns %TRUE if the widget at position @pos has the class @name
694  * defined, %FALSE otherwise.
695  *
696  * Returns: %TRUE if the class @name is defined for the widget at @pos
697  *
698  * Since: 3.0
699  **/
700 gboolean
701 gtk_widget_path_iter_has_class (const GtkWidgetPath *path,
702                                 gint                 pos,
703                                 const gchar         *name)
704 {
705   GQuark qname;
706
707   g_return_val_if_fail (path != NULL, FALSE);
708   g_return_val_if_fail (path->elems->len != 0, FALSE);
709   g_return_val_if_fail (name != NULL, FALSE);
710
711   if (pos < 0 || pos > path->elems->len)
712     pos = path->elems->len - 1;
713
714   qname = g_quark_try_string (name);
715
716   if (qname == 0)
717     return FALSE;
718
719   return gtk_widget_path_iter_has_qclass (path, pos, qname);
720 }
721
722 /**
723  * gtk_widget_path_iter_add_region:
724  * @path: a #GtkWidgetPath
725  * @pos: position to modify, -1 for the path head
726  * @name: region name
727  * @flags: flags affecting the region
728  *
729  * Adds the region @name to the widget at position @pos in
730  * the hierarchy defined in @path. See
731  * gtk_style_context_add_region().
732  *
733  * <note><para>Region names must only contain lowercase letters
734  * and '-', starting always with a lowercase letter.</para></note>
735  *
736  * Since: 3.0
737  **/
738 void
739 gtk_widget_path_iter_add_region (GtkWidgetPath  *path,
740                                  gint            pos,
741                                  const gchar    *name,
742                                  GtkRegionFlags  flags)
743 {
744   GtkPathElement *elem;
745   GQuark qname;
746
747   g_return_if_fail (path != NULL);
748   g_return_if_fail (path->elems->len != 0);
749   g_return_if_fail (name != NULL);
750   g_return_if_fail (_gtk_style_context_check_region_name (name));
751
752   if (pos < 0 || pos > path->elems->len)
753     pos = path->elems->len - 1;
754
755   elem = &g_array_index (path->elems, GtkPathElement, pos);
756   qname = g_quark_from_string (name);
757
758   if (!elem->regions)
759     elem->regions = g_hash_table_new (NULL, NULL);
760
761   g_hash_table_insert (elem->regions,
762                        GUINT_TO_POINTER (qname),
763                        GUINT_TO_POINTER (flags));
764 }
765
766 /**
767  * gtk_widget_path_iter_remove_region:
768  * @path: a #GtkWidgetPath
769  * @pos: position to modify, -1 for the path head
770  * @name: region name
771  *
772  * Removes the region @name from the widget at position @pos in
773  * the hierarchy defined in @path.
774  *
775  * Since: 3.0
776  **/
777 void
778 gtk_widget_path_iter_remove_region (GtkWidgetPath *path,
779                                     gint           pos,
780                                     const gchar   *name)
781 {
782   GtkPathElement *elem;
783   GQuark qname;
784
785   g_return_if_fail (path != NULL);
786   g_return_if_fail (path->elems->len != 0);
787   g_return_if_fail (name != NULL);
788
789   if (pos < 0 || pos > path->elems->len)
790     pos = path->elems->len - 1;
791
792   qname = g_quark_try_string (name);
793
794   if (qname == 0)
795     return;
796
797   elem = &g_array_index (path->elems, GtkPathElement, pos);
798
799   if (elem->regions)
800     g_hash_table_remove (elem->regions, GUINT_TO_POINTER (qname));
801 }
802
803 /**
804  * gtk_widget_path_iter_clear_regions:
805  * @path: a #GtkWidgetPath
806  * @pos: position to modify, -1 for the path head
807  *
808  * Removes all regions from the widget at position @pos in the
809  * hierarchy defined in @path.
810  *
811  * Since: 3.0
812  **/
813 void
814 gtk_widget_path_iter_clear_regions (GtkWidgetPath *path,
815                                     gint           pos)
816 {
817   GtkPathElement *elem;
818
819   g_return_if_fail (path != NULL);
820   g_return_if_fail (path->elems->len != 0);
821
822   if (pos < 0 || pos > path->elems->len)
823     pos = path->elems->len - 1;
824
825   elem = &g_array_index (path->elems, GtkPathElement, pos);
826
827   if (elem->regions)
828     g_hash_table_remove_all (elem->regions);
829 }
830
831 /**
832  * gtk_widget_path_iter_list_regions:
833  * @path: a #GtkWidgetPath
834  * @pos: position to query, -1 for the path head
835  *
836  * Returns a list with all the region names defined for the widget
837  * at position @pos in the hierarchy defined in @path.
838  *
839  * Returns: (transfer container) (element-type utf8): The list of
840  *          regions, This is a list of strings, the #GSList contents
841  *          are owned by GTK+, but you should use g_slist_free() to
842  *          free the list itself.
843  *
844  * Since: 3.0
845  **/
846 GSList *
847 gtk_widget_path_iter_list_regions (const GtkWidgetPath *path,
848                                    gint                 pos)
849 {
850   GtkPathElement *elem;
851   GHashTableIter iter;
852   GSList *list = NULL;
853   gpointer key;
854
855   g_return_val_if_fail (path != NULL, NULL);
856   g_return_val_if_fail (path->elems->len != 0, NULL);
857
858   if (pos < 0 || pos > path->elems->len)
859     pos = path->elems->len - 1;
860
861   elem = &g_array_index (path->elems, GtkPathElement, pos);
862
863   if (!elem->regions)
864     return NULL;
865
866   g_hash_table_iter_init (&iter, elem->regions);
867
868   while (g_hash_table_iter_next (&iter, &key, NULL))
869     {
870       GQuark qname;
871
872       qname = GPOINTER_TO_UINT (key);
873       list = g_slist_prepend (list, (gchar *) g_quark_to_string (qname));
874     }
875
876   return list;
877 }
878
879 /**
880  * gtk_widget_path_iter_has_qregion:
881  * @path: a #GtkWidgetPath
882  * @pos: position to query, -1 for the path head
883  * @qname: region name as a #GQuark
884  * @flags: (out): return location for the region flags
885  *
886  * See gtk_widget_path_iter_has_region(). This is a version that operates
887  * with GQuark<!-- -->s.
888  *
889  * Returns: %TRUE if the widget at @pos has the region defined.
890  *
891  * Since: 3.0
892  **/
893 gboolean
894 gtk_widget_path_iter_has_qregion (const GtkWidgetPath *path,
895                                   gint                 pos,
896                                   GQuark               qname,
897                                   GtkRegionFlags      *flags)
898 {
899   GtkPathElement *elem;
900   gpointer value;
901
902   g_return_val_if_fail (path != NULL, FALSE);
903   g_return_val_if_fail (path->elems->len != 0, FALSE);
904   g_return_val_if_fail (qname != 0, FALSE);
905
906   if (pos < 0 || pos > path->elems->len)
907     pos = path->elems->len - 1;
908
909   elem = &g_array_index (path->elems, GtkPathElement, pos);
910
911   if (!elem->regions)
912     return FALSE;
913
914   if (!g_hash_table_lookup_extended (elem->regions,
915                                      GUINT_TO_POINTER (qname),
916                                      NULL, &value))
917     return FALSE;
918
919   if (flags)
920     *flags = GPOINTER_TO_UINT (value);
921
922   return TRUE;
923 }
924
925 /**
926  * gtk_widget_path_iter_has_region:
927  * @path: a #GtkWidgetPath
928  * @pos: position to query, -1 for the path head
929  * @name: region name
930  * @flags: (out): return location for the region flags
931  *
932  * Returns %TRUE if the widget at position @pos has the class @name
933  * defined, %FALSE otherwise.
934  *
935  * Returns: %TRUE if the class @name is defined for the widget at @pos
936  *
937  * Since: 3.0
938  **/
939 gboolean
940 gtk_widget_path_iter_has_region (const GtkWidgetPath *path,
941                                  gint                 pos,
942                                  const gchar         *name,
943                                  GtkRegionFlags      *flags)
944 {
945   GQuark qname;
946
947   g_return_val_if_fail (path != NULL, FALSE);
948   g_return_val_if_fail (path->elems->len != 0, FALSE);
949   g_return_val_if_fail (name != NULL, FALSE);
950
951   if (pos < 0 || pos > path->elems->len)
952     pos = path->elems->len - 1;
953
954   qname = g_quark_try_string (name);
955
956   if (qname == 0)
957     return FALSE;
958
959   return gtk_widget_path_iter_has_qregion (path, pos, qname, flags);
960 }
961
962 /**
963  * gtk_widget_path_get_object_type:
964  * @path: a #GtkWidget
965  *
966  * Returns the topmost object type, that is, the object type this path
967  * is representing.
968  *
969  * Returns: The object type
970  *
971  * Since: 3.0
972  **/
973 GType
974 gtk_widget_path_get_object_type (const GtkWidgetPath *path)
975 {
976   GtkPathElement *elem;
977
978   g_return_val_if_fail (path != NULL, G_TYPE_INVALID);
979
980   elem = &g_array_index (path->elems, GtkPathElement,
981                          path->elems->len - 1);
982   return elem->type;
983 }
984
985 /**
986  * gtk_widget_path_is_type:
987  * @path: a #GtkWidgetPath
988  * @type: widget type to match
989  *
990  * Returns %TRUE if the widget type represented by this path
991  * is @type, or a subtype of it.
992  *
993  * Returns: %TRUE if the widget represented by @path is of type @type
994  *
995  * Since: 3.0
996  **/
997 gboolean
998 gtk_widget_path_is_type (const GtkWidgetPath *path,
999                          GType                type)
1000 {
1001   GtkPathElement *elem;
1002
1003   g_return_val_if_fail (path != NULL, FALSE);
1004
1005   elem = &g_array_index (path->elems, GtkPathElement,
1006                          path->elems->len - 1);
1007
1008   if (elem->type == type ||
1009       g_type_is_a (elem->type, type))
1010     return TRUE;
1011
1012   return FALSE;
1013 }
1014
1015 /**
1016  * gtk_widget_path_has_parent:
1017  * @path: a #GtkWidgetPath
1018  * @type: widget type to check in parents
1019  *
1020  * Returns %TRUE if any of the parents of the widget represented
1021  * in @path is of type @type, or any subtype of it.
1022  *
1023  * Returns: %TRUE if any parent is of type @type
1024  *
1025  * Since: 3.0
1026  **/
1027 gboolean
1028 gtk_widget_path_has_parent (const GtkWidgetPath *path,
1029                             GType                type)
1030 {
1031   guint i;
1032
1033   g_return_val_if_fail (path != NULL, FALSE);
1034
1035   for (i = 0; i < path->elems->len - 1; i++)
1036     {
1037       GtkPathElement *elem;
1038
1039       elem = &g_array_index (path->elems, GtkPathElement, i);
1040
1041       if (elem->type == type ||
1042           g_type_is_a (elem->type, type))
1043         return TRUE;
1044     }
1045
1046   return FALSE;
1047 }