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