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