]> Pileus Git - ~andy/gtk/blob - gtk/gtkwidgetpath.c
GtkWidgetPath documentation tweaks
[~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   g_return_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET));
243
244   new.type = type;
245   g_array_prepend_val (path->elems, new);
246 }
247
248 /**
249  * gtk_widget_path_append_type:
250  * @path: a #GtkWidgetPath
251  * @type: widget type to append
252  *
253  * Appends a widget type to the widget hierachy represented by @path.
254  *
255  * Returns: the position where the element was inserted
256  *
257  * Since: 3.0
258  **/
259 gint
260 gtk_widget_path_append_type (GtkWidgetPath *path,
261                              GType          type)
262 {
263   GtkPathElement new = { 0 };
264
265   g_return_val_if_fail (path != NULL, 0);
266   g_return_val_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET), 0);
267
268   new.type = type;
269   g_array_append_val (path->elems, new);
270
271   return path->elems->len - 1;
272 }
273
274 /**
275  * gtk_widget_path_iter_get_widget_type:
276  * @path: a #GtkWidgetPath
277  * @pos: position to get the widget type for, -1 for the path head
278  *
279  * Returns the widget #GType that is at position @pos in the widget
280  * hierarchy defined in @path.
281  *
282  * Returns: a widget type
283  *
284  * Since: 3.0
285  **/
286 GType
287 gtk_widget_path_iter_get_widget_type (const GtkWidgetPath *path,
288                                       gint                 pos)
289 {
290   GtkPathElement *elem;
291
292   g_return_val_if_fail (path != NULL, G_TYPE_INVALID);
293   g_return_val_if_fail (path->elems->len != 0, G_TYPE_INVALID);
294
295   if (pos < 0 || pos > path->elems->len)
296     pos = path->elems->len - 1;
297
298   elem = &g_array_index (path->elems, GtkPathElement, pos);
299   return elem->type;
300 }
301
302 /**
303  * gtk_widget_path_iter_set_widget_type:
304  * @path: a #GtkWidgetPath
305  * @pos: position to modify, -1 for the path head
306  * @type: widget type to set
307  *
308  * Sets the widget type for a given position in the widget hierarchy
309  * defined by @path. @type must be a #GtkWidget derived #GType.
310  *
311  * Since: 3.0
312  **/
313 void
314 gtk_widget_path_iter_set_widget_type (GtkWidgetPath *path,
315                                       gint           pos,
316                                       GType          type)
317 {
318   GtkPathElement *elem;
319
320   g_return_if_fail (path != NULL);
321   g_return_if_fail (path->elems->len != 0);
322   g_return_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET));
323
324   if (pos < 0 || pos > path->elems->len)
325     pos = path->elems->len - 1;
326
327   elem = &g_array_index (path->elems, GtkPathElement, pos);
328   elem->type = type;
329 }
330
331 /**
332  * gtk_widget_path_iter_get_name:
333  * @path: a #GtkWidgetPath
334  * @pos: position to get the widget name for, -1 for the path head
335  *
336  * Returns the name corresponding to the widget found at
337  * the position @pos in the widget hierarchy defined by
338  * @path
339  *
340  * Returns: The widget name, or %NULL if none was set.
341  **/
342 G_CONST_RETURN gchar *
343 gtk_widget_path_iter_get_name (const GtkWidgetPath *path,
344                                gint                 pos)
345 {
346   GtkPathElement *elem;
347
348   g_return_val_if_fail (path != NULL, NULL);
349   g_return_val_if_fail (path->elems->len != 0, NULL);
350
351   if (pos < 0 || pos > path->elems->len)
352     pos = path->elems->len - 1;
353
354   elem = &g_array_index (path->elems, GtkPathElement, pos);
355   return g_quark_to_string (elem->name);
356 }
357
358 /**
359  * gtk_widget_path_iter_set_name:
360  * @path: a #GtkWidgetPath
361  * @pos: position to modify, -1 for the path head
362  * @name: widget name
363  *
364  * Sets the widget name for the widget found at position @pos
365  * in the widget hierarchy defined by @path.
366  *
367  * Since: 3.0
368  **/
369 void
370 gtk_widget_path_iter_set_name (GtkWidgetPath *path,
371                                gint           pos,
372                                const gchar   *name)
373 {
374   GtkPathElement *elem;
375
376   g_return_if_fail (path != NULL);
377   g_return_if_fail (path->elems->len != 0);
378   g_return_if_fail (name != NULL);
379
380   if (pos < 0 || pos > path->elems->len)
381     pos = path->elems->len - 1;
382
383   elem = &g_array_index (path->elems, GtkPathElement, pos);
384
385   elem->name = g_quark_from_string (name);
386 }
387
388 /**
389  * gtk_widget_path_iter_has_qname:
390  * @path: a #GtkWidgetPath
391  * @pos: position to query, -1 for the path head
392  * @qname: widget name as a #GQuark
393  *
394  * See gtk_widget_path_iter_has_name(). This is a version
395  * that operates on #GQuark<!-- -->s.
396  *
397  * Returns: %TRUE if the widget at @pos has this name
398  *
399  * Since: 3.0
400  **/
401 gboolean
402 gtk_widget_path_iter_has_qname (const GtkWidgetPath *path,
403                                 gint                 pos,
404                                 GQuark               qname)
405 {
406   GtkPathElement *elem;
407
408   g_return_val_if_fail (path != NULL, FALSE);
409   g_return_val_if_fail (path->elems->len != 0, FALSE);
410   g_return_val_if_fail (qname != 0, FALSE);
411
412   if (pos < 0 || pos > path->elems->len)
413     pos = path->elems->len - 1;
414
415   elem = &g_array_index (path->elems, GtkPathElement, pos);
416
417   return (elem->name == qname);
418 }
419
420 /**
421  * gtk_widget_path_iter_has_name:
422  * @path: a #GtkWidgetPath
423  * @pos: position to query, -1 for the path head
424  * @name: a widget name
425  *
426  * Returns %TRUE if the widget at position @pos has the name @name,
427  * %FALSE otherwise.
428  *
429  * Returns: %TRUE if the widget at @pos has this name
430  *
431  * Since: 3.0
432  **/
433 gboolean
434 gtk_widget_path_iter_has_name (const GtkWidgetPath *path,
435                                gint                 pos,
436                                const gchar         *name)
437 {
438   GQuark qname;
439
440   g_return_val_if_fail (path != NULL, FALSE);
441   g_return_val_if_fail (path->elems->len != 0, FALSE);
442
443   if (pos < 0 || pos > path->elems->len)
444     pos = path->elems->len - 1;
445
446   qname = g_quark_try_string (name);
447
448   if (qname == 0)
449     return FALSE;
450
451   return gtk_widget_path_iter_has_qname (path, pos, qname);
452 }
453
454 /**
455  * gtk_widget_path_iter_add_class:
456  * @path: a #GtkWidget
457  * @pos: position to modify, -1 for the path head
458  * @name: a class name
459  *
460  * Adds the class @name to the widget at position @pos in
461  * the hierarchy defined in @path. See
462  * gtk_style_context_add_class().
463  *
464  * Since: 3.0
465  **/
466 void
467 gtk_widget_path_iter_add_class (GtkWidgetPath *path,
468                                 gint           pos,
469                                 const gchar   *name)
470 {
471   GtkPathElement *elem;
472   gboolean added = FALSE;
473   GQuark qname;
474   guint i;
475
476   g_return_if_fail (path != NULL);
477   g_return_if_fail (path->elems->len != 0);
478   g_return_if_fail (name != NULL);
479
480   if (pos < 0 || pos > path->elems->len)
481     pos = path->elems->len - 1;
482
483   elem = &g_array_index (path->elems, GtkPathElement, pos);
484   qname = g_quark_from_string (name);
485
486   if (!elem->classes)
487     elem->classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
488
489   for (i = 0; i < elem->classes->len; i++)
490     {
491       GQuark quark;
492
493       quark = g_array_index (elem->classes, GQuark, i);
494
495       if (qname == quark)
496         {
497           /* Already there */
498           added = TRUE;
499           break;
500         }
501       if (qname < quark)
502         {
503           g_array_insert_val (elem->classes, i, qname);
504           added = TRUE;
505           break;
506         }
507     }
508
509   if (!added)
510     g_array_append_val (elem->classes, qname);
511 }
512
513 /**
514  * gtk_widget_path_iter_remove_class:
515  * @path: a #GtkWidgetPath
516  * @pos: position to modify, -1 for the path head
517  * @name: class name
518  *
519  * Removes the class @name from the widget at position @pos in
520  * the hierarchy defined in @path.
521  *
522  * Since: 3.0
523  **/
524 void
525 gtk_widget_path_iter_remove_class (GtkWidgetPath *path,
526                                    gint           pos,
527                                    const gchar   *name)
528 {
529   GtkPathElement *elem;
530   GQuark qname;
531   guint i;
532
533   g_return_if_fail (path != NULL);
534   g_return_if_fail (path->elems->len != 0);
535   g_return_if_fail (name != NULL);
536
537   if (pos < 0 || pos > path->elems->len)
538     pos = path->elems->len - 1;
539
540   qname = g_quark_try_string (name);
541
542   if (qname == 0)
543     return;
544
545   elem = &g_array_index (path->elems, GtkPathElement, pos);
546
547   if (!elem->classes)
548     return;
549
550   for (i = 0; i < elem->classes->len; i++)
551     {
552       GQuark quark;
553
554       quark = g_array_index (elem->classes, GQuark, i);
555
556       if (quark > qname)
557         break;
558       else if (quark == qname)
559         {
560           g_array_remove_index (elem->classes, i);
561           break;
562         }
563     }
564 }
565
566 /**
567  * gtk_widget_path_iter_clear_classes:
568  * @path: a #GtkWidget
569  * @pos: position to modify, -1 for the path head
570  *
571  * Removes all classes from the widget at position @pos in the
572  * hierarchy defined in @path.
573  *
574  * Since: 3.0
575  **/
576 void
577 gtk_widget_path_iter_clear_classes (GtkWidgetPath *path,
578                                     gint           pos)
579 {
580   GtkPathElement *elem;
581
582   g_return_if_fail (path != NULL);
583   g_return_if_fail (path->elems->len != 0);
584
585   if (pos < 0 || pos > path->elems->len)
586     pos = path->elems->len - 1;
587
588   elem = &g_array_index (path->elems, GtkPathElement, pos);
589
590   if (!elem->classes)
591     return;
592
593   if (elem->classes->len > 0)
594     g_array_remove_range (elem->classes, 0, elem->classes->len);
595 }
596
597 /**
598  * gtk_widget_path_iter_list_classes:
599  * @path: a #GtkWidgetPath
600  * @pos: position to query, -1 for the path head
601  *
602  * Returns a list with all the class names defined for the widget
603  * at position @pos in the hierarchy defined in @path.
604  *
605  * Returns: (transfer container) (type utf8): The list of classes,
606  *          This is a list of strings, the #GSList contents are
607  *          owned by GTK+, but you should use g_slist_free() to
608  *          free the list itself.
609  *
610  * Since: 3.0
611  **/
612 GSList *
613 gtk_widget_path_iter_list_classes (const GtkWidgetPath *path,
614                                    gint                 pos)
615 {
616   GtkPathElement *elem;
617   GSList *list = NULL;
618   guint i;
619
620   g_return_val_if_fail (path != NULL, NULL);
621   g_return_val_if_fail (path->elems->len != 0, NULL);
622
623   if (pos < 0 || pos > path->elems->len)
624     pos = path->elems->len - 1;
625
626   elem = &g_array_index (path->elems, GtkPathElement, pos);
627
628   if (!elem->classes)
629     return NULL;
630
631   for (i = 0; i < elem->classes->len; i++)
632     {
633       GQuark quark;
634
635       quark = g_array_index (elem->classes, GQuark, i);
636       list = g_slist_prepend (list, (gchar *) g_quark_to_string (quark));
637     }
638
639   return g_slist_reverse (list);
640 }
641
642 /**
643  * gtk_widget_path_iter_has_qclass:
644  * @path: a #GtkWidgetPath
645  * @pos: position to query, -1 for the path head
646  * @qname: class name as a #GQuark
647  *
648  * See gtk_widget_path_iter_has_class(). This is a version that operates
649  * with GQuark<!-- -->s.
650  *
651  * Returns: %TRUE if the widget at @pos has the class defined.
652  *
653  * Since: 3.0
654  **/
655 gboolean
656 gtk_widget_path_iter_has_qclass (const GtkWidgetPath *path,
657                                  gint                 pos,
658                                  GQuark               qname)
659 {
660   GtkPathElement *elem;
661   guint i;
662
663   g_return_val_if_fail (path != NULL, FALSE);
664   g_return_val_if_fail (path->elems->len != 0, FALSE);
665   g_return_val_if_fail (qname != 0, FALSE);
666
667   if (pos < 0 || pos > path->elems->len)
668     pos = path->elems->len - 1;
669
670   elem = &g_array_index (path->elems, GtkPathElement, pos);
671
672   if (!elem->classes)
673     return FALSE;
674
675   for (i = 0; i < elem->classes->len; i++)
676     {
677       GQuark quark;
678
679       quark = g_array_index (elem->classes, GQuark, i);
680
681       if (quark == qname)
682         return TRUE;
683       else if (quark > qname)
684         break;
685     }
686
687   return FALSE;
688 }
689
690 /**
691  * gtk_widget_path_iter_has_class:
692  * @path: a #GtkWidgetPath
693  * @pos: position to query, -1 for the path head
694  * @name: class name
695  *
696  * Returns %TRUE if the widget at position @pos has the class @name
697  * defined, %FALSE otherwise.
698  *
699  * Returns: %TRUE if the class @name is defined for the widget at @pos
700  *
701  * Since: 3.0
702  **/
703 gboolean
704 gtk_widget_path_iter_has_class (const GtkWidgetPath *path,
705                                 gint                 pos,
706                                 const gchar         *name)
707 {
708   GQuark qname;
709
710   g_return_val_if_fail (path != NULL, FALSE);
711   g_return_val_if_fail (path->elems->len != 0, FALSE);
712   g_return_val_if_fail (name != NULL, FALSE);
713
714   if (pos < 0 || pos > path->elems->len)
715     pos = path->elems->len - 1;
716
717   qname = g_quark_try_string (name);
718
719   if (qname == 0)
720     return FALSE;
721
722   return gtk_widget_path_iter_has_qclass (path, pos, qname);
723 }
724
725 /**
726  * gtk_widget_path_iter_add_region:
727  * @path: a #GtkWidgetPath
728  * @pos: position to modify, -1 for the path head
729  * @name: region name
730  * @flags: flags affecting the region
731  *
732  * Adds the region @name to the widget at position @pos in
733  * the hierarchy defined in @path. See
734  * gtk_style_context_add_region().
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
751   if (pos < 0 || pos > path->elems->len)
752     pos = path->elems->len - 1;
753
754   elem = &g_array_index (path->elems, GtkPathElement, pos);
755   qname = g_quark_from_string (name);
756
757   if (!elem->regions)
758     elem->regions = g_hash_table_new (NULL, NULL);
759
760   g_hash_table_insert (elem->regions,
761                        GUINT_TO_POINTER (qname),
762                        GUINT_TO_POINTER (flags));
763 }
764
765 /**
766  * gtk_widget_path_iter_remove_region:
767  * @path: a #GtkWidgetPath
768  * @pos: position to modify, -1 for the path head
769  * @name: region name
770  *
771  * Removes the region @name from the widget at position @pos in
772  * the hierarchy defined in @path.
773  *
774  * Since: 3.0
775  **/
776 void
777 gtk_widget_path_iter_remove_region (GtkWidgetPath *path,
778                                     gint           pos,
779                                     const gchar   *name)
780 {
781   GtkPathElement *elem;
782   GQuark qname;
783
784   g_return_if_fail (path != NULL);
785   g_return_if_fail (path->elems->len != 0);
786   g_return_if_fail (name != NULL);
787
788   if (pos < 0 || pos > path->elems->len)
789     pos = path->elems->len - 1;
790
791   qname = g_quark_try_string (name);
792
793   if (qname == 0)
794     return;
795
796   elem = &g_array_index (path->elems, GtkPathElement, pos);
797
798   if (elem->regions)
799     g_hash_table_remove (elem->regions, GUINT_TO_POINTER (qname));
800 }
801
802 /**
803  * gtk_widget_path_iter_clear_regions:
804  * @path: a #GtkWidgetPath
805  * @pos: position to modify, -1 for the path head
806  *
807  * Removes all regions from the widget at position @pos in the
808  * hierarchy defined in @path.
809  *
810  * Since: 3.0
811  **/
812 void
813 gtk_widget_path_iter_clear_regions (GtkWidgetPath *path,
814                                     gint           pos)
815 {
816   GtkPathElement *elem;
817
818   g_return_if_fail (path != NULL);
819   g_return_if_fail (path->elems->len != 0);
820
821   if (pos < 0 || pos > path->elems->len)
822     pos = path->elems->len - 1;
823
824   elem = &g_array_index (path->elems, GtkPathElement, pos);
825
826   if (elem->regions)
827     g_hash_table_remove_all (elem->regions);
828 }
829
830 /**
831  * gtk_widget_path_iter_list_regions:
832  * @path: a #GtkWidgetPath
833  * @pos: position to query, -1 for the path head
834  *
835  * Returns a list with all the region names defined for the widget
836  * at position @pos in the hierarchy defined in @path.
837  *
838  * Returns: (transfer container) (type utf8): The list of regions,
839  *          This is a list of strings, the #GSList contents are
840  *          owned by GTK+, but you should use g_slist_free() to
841  *          free the list itself.
842  *
843  * Since: 3.0
844  **/
845 GSList *
846 gtk_widget_path_iter_list_regions (const GtkWidgetPath *path,
847                                    gint                 pos)
848 {
849   GtkPathElement *elem;
850   GHashTableIter iter;
851   GSList *list = NULL;
852   gpointer key;
853
854   g_return_val_if_fail (path != NULL, NULL);
855   g_return_val_if_fail (path->elems->len != 0, NULL);
856
857   if (pos < 0 || pos > path->elems->len)
858     pos = path->elems->len - 1;
859
860   elem = &g_array_index (path->elems, GtkPathElement, pos);
861
862   if (!elem->regions)
863     return NULL;
864
865   g_hash_table_iter_init (&iter, elem->regions);
866
867   while (g_hash_table_iter_next (&iter, &key, NULL))
868     {
869       GQuark qname;
870
871       qname = GPOINTER_TO_UINT (key);
872       list = g_slist_prepend (list, (gchar *) g_quark_to_string (qname));
873     }
874
875   return list;
876 }
877
878 /**
879  * gtk_widget_path_iter_has_qregion:
880  * @path: a #GtkWidgetPath
881  * @pos: position to query, -1 for the path head
882  * @qname: region name as a #GQuark
883  * @flags: (out): return location for the region flags
884  *
885  * See gtk_widget_path_iter_has_region(). This is a version that operates
886  * with GQuark<!-- -->s.
887  *
888  * Returns: %TRUE if the widget at @pos has the region defined.
889  *
890  * Since: 3.0
891  **/
892 gboolean
893 gtk_widget_path_iter_has_qregion (const GtkWidgetPath *path,
894                                   gint                 pos,
895                                   GQuark               qname,
896                                   GtkRegionFlags      *flags)
897 {
898   GtkPathElement *elem;
899   gpointer value;
900
901   g_return_val_if_fail (path != NULL, FALSE);
902   g_return_val_if_fail (path->elems->len != 0, FALSE);
903   g_return_val_if_fail (qname != 0, FALSE);
904
905   if (pos < 0 || pos > path->elems->len)
906     pos = path->elems->len - 1;
907
908   elem = &g_array_index (path->elems, GtkPathElement, pos);
909
910   if (!elem->regions)
911     return FALSE;
912
913   if (!g_hash_table_lookup_extended (elem->regions,
914                                      GUINT_TO_POINTER (qname),
915                                      NULL, &value))
916     return FALSE;
917
918   if (flags)
919     *flags = GPOINTER_TO_UINT (value);
920
921   return TRUE;
922 }
923
924 /**
925  * gtk_widget_path_iter_has_region:
926  * @path: a #GtkWidgetPath
927  * @pos: position to query, -1 for the path head
928  * @name: region name
929  * @flags: (out): return location for the region flags
930  *
931  * Returns %TRUE if the widget at position @pos has the class @name
932  * defined, %FALSE otherwise.
933  *
934  * Returns: %TRUE if the class @name is defined for the widget at @pos
935  *
936  * Since: 3.0
937  **/
938 gboolean
939 gtk_widget_path_iter_has_region (const GtkWidgetPath *path,
940                                  gint                 pos,
941                                  const gchar         *name,
942                                  GtkRegionFlags      *flags)
943 {
944   GQuark qname;
945
946   g_return_val_if_fail (path != NULL, FALSE);
947   g_return_val_if_fail (path->elems->len != 0, FALSE);
948   g_return_val_if_fail (name != NULL, FALSE);
949
950   if (pos < 0 || pos > path->elems->len)
951     pos = path->elems->len - 1;
952
953   qname = g_quark_try_string (name);
954
955   if (qname == 0)
956     return FALSE;
957
958   return gtk_widget_path_iter_has_qregion (path, pos, qname, flags);
959 }
960
961 /**
962  * gtk_widget_path_get_widget_type:
963  * @path: a #GtkWidget
964  *
965  * Returns the topmost widget type, that is, the widget type this path
966  * is representing.
967  *
968  * Returns: The widget type
969  *
970  * Since: 3.0
971  **/
972 GType
973 gtk_widget_path_get_widget_type (const GtkWidgetPath *path)
974 {
975   GtkPathElement *elem;
976
977   g_return_val_if_fail (path != NULL, G_TYPE_INVALID);
978
979   elem = &g_array_index (path->elems, GtkPathElement,
980                          path->elems->len - 1);
981   return elem->type;
982 }
983
984 /**
985  * gtk_widget_path_is_type:
986  * @path: a #GtkWidgetPath
987  * @type: widget type to match
988  *
989  * Returns %TRUE if the widget type represented by this path
990  * is @type, or a subtype of it.
991  *
992  * Returns: %TRUE if the widget represented by @path is of type @type
993  *
994  * Since: 3.0
995  **/
996 gboolean
997 gtk_widget_path_is_type (const GtkWidgetPath *path,
998                          GType                type)
999 {
1000   GtkPathElement *elem;
1001
1002   g_return_val_if_fail (path != NULL, FALSE);
1003   g_return_val_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET), 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   g_return_val_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET), FALSE);
1035
1036   for (i = 0; i < path->elems->len - 1; i++)
1037     {
1038       GtkPathElement *elem;
1039
1040       elem = &g_array_index (path->elems, GtkPathElement, i);
1041
1042       if (elem->type == type ||
1043           g_type_is_a (elem->type, type))
1044         return TRUE;
1045     }
1046
1047   return FALSE;
1048 }