]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkwidgetpath.c
Place the search icon in the primary slot of the entry
[~andy/gtk] / gtk / gtkwidgetpath.c
index 633fe43c4470018900bd20a4d47bc2a1aaa9352b..855902fd6835e09ebb35d4f9659bb294ab692962 100644 (file)
@@ -12,9 +12,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
@@ -23,6 +21,7 @@
 
 #include "gtkwidget.h"
 #include "gtkwidgetpath.h"
+#include "gtkstylecontextprivate.h"
 
 /**
  * SECTION:gtkwidgetpath
  * @Title: GtkWidgetPath
  * @See_also: #GtkStyleContext
  *
- * #GtkWidgetPath is a boxed type that represents a widget hierarchy from
+ * GtkWidgetPath is a boxed type that represents a widget hierarchy from
  * the topmost widget, typically a toplevel, to any child. This widget
  * path abstraction is used in #GtkStyleContext on behalf of the real
  * widget in order to query style information.
  *
- * If you are using GTK+ widgets, there are many chances you don't
- * need this API directly, as there is gtk_widget_get_path(), and the
- * style context returned by gtk_widget_get_style_context() will be
- * automatically updated on widget hierarchy changes.
+ * If you are using GTK+ widgets, you probably will not need to use
+ * this API directly, as there is gtk_widget_get_path(), and the style
+ * context returned by gtk_widget_get_style_context() will be automatically
+ * updated on widget hierarchy changes.
  *
  * The widget path generation is generally simple:
  * <example>
@@ -81,7 +80,7 @@
  **/
 
 G_DEFINE_BOXED_TYPE (GtkWidgetPath, gtk_widget_path,
-                    gtk_widget_path_copy, gtk_widget_path_free)
+                    gtk_widget_path_ref, gtk_widget_path_unref)
 
 
 typedef struct GtkPathElement GtkPathElement;
@@ -92,10 +91,14 @@ struct GtkPathElement
   GQuark name;
   GHashTable *regions;
   GArray *classes;
+  GtkWidgetPath *siblings;
+  guint sibling_index;
 };
 
 struct _GtkWidgetPath
 {
+  volatile guint ref_count;
+
   GArray *elems; /* First element contains the described widget */
 };
 
@@ -115,10 +118,42 @@ gtk_widget_path_new (void)
 
   path = g_slice_new0 (GtkWidgetPath);
   path->elems = g_array_new (FALSE, TRUE, sizeof (GtkPathElement));
+  path->ref_count = 1;
 
   return path;
 }
 
+static void
+gtk_path_element_copy (GtkPathElement       *dest,
+                       const GtkPathElement *src)
+{
+  memset (dest, 0, sizeof (GtkPathElement));
+
+  dest->type = src->type;
+  dest->name = src->name;
+  if (src->siblings)
+    dest->siblings = gtk_widget_path_ref (src->siblings);
+  dest->sibling_index = src->sibling_index;
+
+  if (src->regions)
+    {
+      GHashTableIter iter;
+      gpointer key, value;
+
+      g_hash_table_iter_init (&iter, src->regions);
+      dest->regions = g_hash_table_new (NULL, NULL);
+
+      while (g_hash_table_iter_next (&iter, &key, &value))
+        g_hash_table_insert (dest->regions, key, value);
+    }
+
+  if (src->classes)
+    {
+      dest->classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
+      g_array_append_vals (dest->classes, src->classes->data, src->classes->len);
+    }
+}
+
 /**
  * gtk_widget_path_copy:
  * @path: a #GtkWidgetPath
@@ -139,54 +174,60 @@ gtk_widget_path_copy (const GtkWidgetPath *path)
 
   new_path = gtk_widget_path_new ();
 
+  g_array_set_size (new_path->elems, path->elems->len);
+
   for (i = 0; i < path->elems->len; i++)
     {
-      GtkPathElement *elem, new = { 0 };
+      GtkPathElement *elem, *dest;
 
       elem = &g_array_index (path->elems, GtkPathElement, i);
+      dest = &g_array_index (new_path->elems, GtkPathElement, i);
 
-      new.type = elem->type;
-      new.name = elem->name;
-
-      if (elem->regions)
-        {
-          GHashTableIter iter;
-          gpointer key, value;
-
-          g_hash_table_iter_init (&iter, elem->regions);
-          new.regions = g_hash_table_new (NULL, NULL);
+      gtk_path_element_copy (dest, elem);
+    }
 
-          while (g_hash_table_iter_next (&iter, &key, &value))
-            g_hash_table_insert (new.regions, key, value);
-        }
+  return new_path;
+}
 
-      if (elem->classes)
-        {
-          new.classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
-          g_array_append_vals (new.classes, elem->classes->data, elem->classes->len);
-        }
+/**
+ * gtk_widget_path_ref:
+ * @path: a #GtkWidgetPath
+ *
+ * Increments the reference count on @path.
+ *
+ * Returns: @path itself.
+ *
+ * Since: 3.2
+ **/
+GtkWidgetPath *
+gtk_widget_path_ref (GtkWidgetPath *path)
+{
+  g_return_val_if_fail (path != NULL, path);
 
-      g_array_append_val (new_path->elems, new);
-    }
+  g_atomic_int_add (&path->ref_count, 1);
 
-  return new_path;
+  return path;
 }
 
 /**
- * gtk_widget_path_free:
+ * gtk_widget_path_unref:
  * @path: a #GtkWidgetPath
  *
- * Frees a #GtkWidgetPath.
+ * Decrements the reference count on @path, freeing the structure
+ * if the reference count reaches 0.
  *
- * Since: 3.0
+ * Since: 3.2
  **/
 void
-gtk_widget_path_free (GtkWidgetPath *path)
+gtk_widget_path_unref (GtkWidgetPath *path)
 {
   guint i;
 
   g_return_if_fail (path != NULL);
 
+  if (!g_atomic_int_dec_and_test (&path->ref_count))
+    return;
+
   for (i = 0; i < path->elems->len; i++)
     {
       GtkPathElement *elem;
@@ -198,12 +239,32 @@ gtk_widget_path_free (GtkWidgetPath *path)
 
       if (elem->classes)
         g_array_free (elem->classes, TRUE);
+
+      if (elem->siblings)
+        gtk_widget_path_unref (elem->siblings);
     }
 
   g_array_free (path->elems, TRUE);
   g_slice_free (GtkWidgetPath, path);
 }
 
+/**
+ * gtk_widget_path_free:
+ * @path: a #GtkWidgetPath
+ *
+ * Decrements the reference count on @path, freeing the structure
+ * if the reference count reaches 0.
+ *
+ * Since: 3.0
+ **/
+void
+gtk_widget_path_free (GtkWidgetPath *path)
+{
+  g_return_if_fail (path != NULL);
+
+  gtk_widget_path_unref (path);
+}
+
 /**
  * gtk_widget_path_length:
  * @path: a #GtkWidgetPath
@@ -215,7 +276,7 @@ gtk_widget_path_free (GtkWidgetPath *path)
  *
  * Since: 3.0
  **/
-guint
+gint
 gtk_widget_path_length (const GtkWidgetPath *path)
 {
   g_return_val_if_fail (path != NULL, 0);
@@ -223,6 +284,99 @@ gtk_widget_path_length (const GtkWidgetPath *path)
   return path->elems->len;
 }
 
+/**
+ * gtk_widget_path_to_string:
+ * @path: the path
+ *
+ * Dumps the widget path into a string representation. It tries to match
+ * the CSS style as closely as possible (Note that there might be paths
+ * that cannot be represented in CSS).
+ *
+ * The main use of this code is for debugging purposes, so that you can
+ * g_print() the path or dump it in a gdb session.
+ *
+ * Returns: A new string describing @path.
+ *
+ * Since: 3.2
+ **/
+char *
+gtk_widget_path_to_string (const GtkWidgetPath *path)
+{
+  GString *string;
+  guint i, j;
+
+  g_return_val_if_fail (path != NULL, NULL);
+
+  string = g_string_new ("");
+
+  for (i = 0; i < path->elems->len; i++)
+    {
+      GtkPathElement *elem;
+
+      elem = &g_array_index (path->elems, GtkPathElement, i);
+
+      if (i > 0)
+        g_string_append_c (string, ' ');
+
+      g_string_append (string, g_type_name (elem->type));
+
+      if (elem->name)
+        {
+          g_string_append_c (string, '(');
+          g_string_append (string, g_quark_to_string (elem->name));
+          g_string_append_c (string, ')');
+        }
+
+
+      if (elem->siblings)
+        g_string_append_printf (string, "[%d/%d]",
+                                elem->sibling_index + 1,
+                                gtk_widget_path_length (elem->siblings));
+
+      if (elem->classes)
+        {
+          for (j = 0; j < elem->classes->len; j++)
+            {
+              g_string_append_c (string, '.');
+              g_string_append (string, g_quark_to_string (g_array_index (elem->classes, GQuark, j)));
+            }
+        }
+
+      if (elem->regions)
+        {
+          GHashTableIter iter;
+          gpointer key, value;
+
+          g_hash_table_iter_init (&iter, elem->regions);
+          while (g_hash_table_iter_next (&iter, &key, &value))
+            {
+              GtkRegionFlags flags = GPOINTER_TO_UINT (value);
+              static const char *flag_names[] = {
+                "even",
+                "odd",
+                "first",
+                "last",
+                "only",
+                "sorted"
+              };
+
+              g_string_append_c (string, ' ');
+              g_string_append (string, g_quark_to_string (GPOINTER_TO_UINT (key)));
+              for (j = 0; j < G_N_ELEMENTS(flag_names); j++)
+                {
+                  if (flags & (1 << j))
+                    {
+                      g_string_append_c (string, ':');
+                      g_string_append (string, flag_names[j]);
+                    }
+                }
+            }
+        }
+    }
+
+  return g_string_free (string, FALSE);
+}
+
 /**
  * gtk_widget_path_prepend_type:
  * @path: a #GtkWidgetPath
@@ -239,7 +393,6 @@ gtk_widget_path_prepend_type (GtkWidgetPath *path,
   GtkPathElement new = { 0 };
 
   g_return_if_fail (path != NULL);
-  g_return_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET));
 
   new.type = type;
   g_array_prepend_val (path->elems, new);
@@ -250,20 +403,19 @@ gtk_widget_path_prepend_type (GtkWidgetPath *path,
  * @path: a #GtkWidgetPath
  * @type: widget type to append
  *
- * Appends a widget type to the widget hierachy represented by @path.
+ * Appends a widget type to the widget hierarchy represented by @path.
  *
  * Returns: the position where the element was inserted
  *
  * Since: 3.0
  **/
-guint
+gint
 gtk_widget_path_append_type (GtkWidgetPath *path,
                              GType          type)
 {
   GtkPathElement new = { 0 };
 
   g_return_val_if_fail (path != NULL, 0);
-  g_return_val_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET), 0);
 
   new.type = type;
   g_array_append_val (path->elems, new);
@@ -272,11 +424,105 @@ gtk_widget_path_append_type (GtkWidgetPath *path,
 }
 
 /**
- * gtk_widget_path_iter_get_widget_type:
+ * gtk_widget_path_append_with_siblings:
+ * @path: the widget path to append to
+ * @siblings: a widget path describing a list of siblings. This path
+ *   may not contain any siblings itself and it must not be modified
+ *   afterwards.
+ * @sibling_index: index into @siblings for where the added element is
+ *   positioned.
+ *
+ * Appends a widget type with all its siblings to the widget hierarchy
+ * represented by @path. Using this function instead of
+ * gtk_widget_path_append_type() will allow the CSS theming to use
+ * sibling matches in selectors and apply :nth-child() pseudo classes.
+ * In turn, it requires a lot more care in widget implementations as
+ * widgets need to make sure to call gtk_widget_reset_style() on all
+ * involved widgets when the @siblings path changes.
+ *
+ * Returns: the position where the element was inserted.
+ *
+ * Since: 3.2
+ **/
+gint
+gtk_widget_path_append_with_siblings (GtkWidgetPath *path,
+                                      GtkWidgetPath *siblings,
+                                      guint          sibling_index)
+{
+  GtkPathElement new;
+
+  g_return_val_if_fail (path != NULL, 0);
+  g_return_val_if_fail (siblings != NULL, 0);
+  g_return_val_if_fail (sibling_index < gtk_widget_path_length (siblings), 0);
+
+  gtk_path_element_copy (&new, &g_array_index (siblings->elems, GtkPathElement, sibling_index));
+  new.siblings = gtk_widget_path_ref (siblings);
+  new.sibling_index = sibling_index;
+  g_array_append_val (path->elems, new);
+
+  return path->elems->len - 1;
+}
+
+/**
+ * gtk_widget_path_iter_get_siblings:
  * @path: a #GtkWidgetPath
- * @pos: position to get the widget type for
+ * @pos: position to get the siblings for, -1 for the path head
+ *
+ * Returns the list of siblings for the element at @pos. If the element
+ * was not added with siblings, %NULL is returned.
  *
- * Returns the widget #GType that is at position @pos in the widget
+ * Returns: %NULL or the list of siblings for the element at @pos.
+ **/
+const GtkWidgetPath *
+gtk_widget_path_iter_get_siblings (const GtkWidgetPath *path,
+                                   gint                 pos)
+{
+  GtkPathElement *elem;
+
+  g_return_val_if_fail (path != NULL, G_TYPE_INVALID);
+  g_return_val_if_fail (path->elems->len != 0, G_TYPE_INVALID);
+
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
+
+  elem = &g_array_index (path->elems, GtkPathElement, pos);
+  return elem->siblings;
+}
+
+/**
+ * gtk_widget_path_iter_get_sibling_index:
+ * @path: a #GtkWidgetPath
+ * @pos: position to get the sibling index for, -1 for the path head
+ *
+ * Returns the index into the list of siblings for the element at @pos as
+ * returned by gtk_widget_path_iter_get_siblings(). If that function would
+ * return %NULL because the element at @pos has no siblings, this function
+ * will return 0.
+ *
+ * Returns: 0 or the index into the list of siblings for the element at @pos.
+ **/
+guint
+gtk_widget_path_iter_get_sibling_index (const GtkWidgetPath *path,
+                                        gint                 pos)
+{
+  GtkPathElement *elem;
+
+  g_return_val_if_fail (path != NULL, G_TYPE_INVALID);
+  g_return_val_if_fail (path->elems->len != 0, G_TYPE_INVALID);
+
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
+
+  elem = &g_array_index (path->elems, GtkPathElement, pos);
+  return elem->sibling_index;
+}
+
+/**
+ * gtk_widget_path_iter_get_object_type:
+ * @path: a #GtkWidgetPath
+ * @pos: position to get the object type for, -1 for the path head
+ *
+ * Returns the object #GType that is at position @pos in the widget
  * hierarchy defined in @path.
  *
  * Returns: a widget type
@@ -284,39 +530,44 @@ gtk_widget_path_append_type (GtkWidgetPath *path,
  * Since: 3.0
  **/
 GType
-gtk_widget_path_iter_get_widget_type (const GtkWidgetPath *path,
-                                      guint                pos)
+gtk_widget_path_iter_get_object_type (const GtkWidgetPath *path,
+                                      gint                 pos)
 {
   GtkPathElement *elem;
 
   g_return_val_if_fail (path != NULL, G_TYPE_INVALID);
-  g_return_val_if_fail (pos < path->elems->len, G_TYPE_INVALID);
+  g_return_val_if_fail (path->elems->len != 0, G_TYPE_INVALID);
+
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
 
   elem = &g_array_index (path->elems, GtkPathElement, pos);
   return elem->type;
 }
 
 /**
- * gtk_widget_path_iter_set_widget_type:
+ * gtk_widget_path_iter_set_object_type:
  * @path: a #GtkWidgetPath
- * @pos: position to modify
- * @type: widget type to set
+ * @pos: position to modify, -1 for the path head
+ * @type: object type to set
  *
- * Sets the widget type for a given position in the widget hierarchy
- * defined by @path. @type must be a #GtkWidget derived #GType.
+ * Sets the object type for a given position in the widget hierarchy
+ * defined by @path.
  *
  * Since: 3.0
  **/
 void
-gtk_widget_path_iter_set_widget_type (GtkWidgetPath *path,
-                                      guint          pos,
+gtk_widget_path_iter_set_object_type (GtkWidgetPath *path,
+                                      gint           pos,
                                       GType          type)
 {
   GtkPathElement *elem;
 
   g_return_if_fail (path != NULL);
-  g_return_if_fail (pos < path->elems->len);
-  g_return_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET));
+  g_return_if_fail (path->elems->len != 0);
+
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
 
   elem = &g_array_index (path->elems, GtkPathElement, pos);
   elem->type = type;
@@ -325,7 +576,7 @@ gtk_widget_path_iter_set_widget_type (GtkWidgetPath *path,
 /**
  * gtk_widget_path_iter_get_name:
  * @path: a #GtkWidgetPath
- * @pos: position to get the widget name for
+ * @pos: position to get the widget name for, -1 for the path head
  *
  * Returns the name corresponding to the widget found at
  * the position @pos in the widget hierarchy defined by
@@ -333,14 +584,17 @@ gtk_widget_path_iter_set_widget_type (GtkWidgetPath *path,
  *
  * Returns: The widget name, or %NULL if none was set.
  **/
-G_CONST_RETURN gchar *
+const gchar *
 gtk_widget_path_iter_get_name (const GtkWidgetPath *path,
-                               guint                pos)
+                               gint                 pos)
 {
   GtkPathElement *elem;
 
   g_return_val_if_fail (path != NULL, NULL);
-  g_return_val_if_fail (pos < path->elems->len, NULL);
+  g_return_val_if_fail (path->elems->len != 0, NULL);
+
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
 
   elem = &g_array_index (path->elems, GtkPathElement, pos);
   return g_quark_to_string (elem->name);
@@ -349,7 +603,7 @@ gtk_widget_path_iter_get_name (const GtkWidgetPath *path,
 /**
  * gtk_widget_path_iter_set_name:
  * @path: a #GtkWidgetPath
- * @pos: position to modify
+ * @pos: position to modify, -1 for the path head
  * @name: widget name
  *
  * Sets the widget name for the widget found at position @pos
@@ -359,15 +613,18 @@ gtk_widget_path_iter_get_name (const GtkWidgetPath *path,
  **/
 void
 gtk_widget_path_iter_set_name (GtkWidgetPath *path,
-                               guint          pos,
+                               gint           pos,
                                const gchar   *name)
 {
   GtkPathElement *elem;
 
   g_return_if_fail (path != NULL);
-  g_return_if_fail (pos < path->elems->len);
+  g_return_if_fail (path->elems->len != 0);
   g_return_if_fail (name != NULL);
 
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
+
   elem = &g_array_index (path->elems, GtkPathElement, pos);
 
   elem->name = g_quark_from_string (name);
@@ -376,7 +633,7 @@ gtk_widget_path_iter_set_name (GtkWidgetPath *path,
 /**
  * gtk_widget_path_iter_has_qname:
  * @path: a #GtkWidgetPath
- * @pos: position to query
+ * @pos: position to query, -1 for the path head
  * @qname: widget name as a #GQuark
  *
  * See gtk_widget_path_iter_has_name(). This is a version
@@ -388,14 +645,17 @@ gtk_widget_path_iter_set_name (GtkWidgetPath *path,
  **/
 gboolean
 gtk_widget_path_iter_has_qname (const GtkWidgetPath *path,
-                                guint                pos,
+                                gint                 pos,
                                 GQuark               qname)
 {
   GtkPathElement *elem;
 
   g_return_val_if_fail (path != NULL, FALSE);
+  g_return_val_if_fail (path->elems->len != 0, FALSE);
   g_return_val_if_fail (qname != 0, FALSE);
-  g_return_val_if_fail (pos < path->elems->len, FALSE);
+
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
 
   elem = &g_array_index (path->elems, GtkPathElement, pos);
 
@@ -405,7 +665,7 @@ gtk_widget_path_iter_has_qname (const GtkWidgetPath *path,
 /**
  * gtk_widget_path_iter_has_name:
  * @path: a #GtkWidgetPath
- * @pos: position to query
+ * @pos: position to query, -1 for the path head
  * @name: a widget name
  *
  * Returns %TRUE if the widget at position @pos has the name @name,
@@ -417,14 +677,16 @@ gtk_widget_path_iter_has_qname (const GtkWidgetPath *path,
  **/
 gboolean
 gtk_widget_path_iter_has_name (const GtkWidgetPath *path,
-                               guint                pos,
+                               gint                 pos,
                                const gchar         *name)
 {
   GQuark qname;
 
   g_return_val_if_fail (path != NULL, FALSE);
-  g_return_val_if_fail (name != NULL, FALSE);
-  g_return_val_if_fail (pos < path->elems->len, FALSE);
+  g_return_val_if_fail (path->elems->len != 0, FALSE);
+
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
 
   qname = g_quark_try_string (name);
 
@@ -437,7 +699,7 @@ gtk_widget_path_iter_has_name (const GtkWidgetPath *path,
 /**
  * gtk_widget_path_iter_add_class:
  * @path: a #GtkWidget
- * @pos: position to modify
+ * @pos: position to modify, -1 for the path head
  * @name: a class name
  *
  * Adds the class @name to the widget at position @pos in
@@ -448,7 +710,7 @@ gtk_widget_path_iter_has_name (const GtkWidgetPath *path,
  **/
 void
 gtk_widget_path_iter_add_class (GtkWidgetPath *path,
-                                guint          pos,
+                                gint           pos,
                                 const gchar   *name)
 {
   GtkPathElement *elem;
@@ -457,9 +719,12 @@ gtk_widget_path_iter_add_class (GtkWidgetPath *path,
   guint i;
 
   g_return_if_fail (path != NULL);
-  g_return_if_fail (pos < path->elems->len);
+  g_return_if_fail (path->elems->len != 0);
   g_return_if_fail (name != NULL);
 
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
+
   elem = &g_array_index (path->elems, GtkPathElement, pos);
   qname = g_quark_from_string (name);
 
@@ -493,7 +758,7 @@ gtk_widget_path_iter_add_class (GtkWidgetPath *path,
 /**
  * gtk_widget_path_iter_remove_class:
  * @path: a #GtkWidgetPath
- * @pos: position to modify
+ * @pos: position to modify, -1 for the path head
  * @name: class name
  *
  * Removes the class @name from the widget at position @pos in
@@ -503,7 +768,7 @@ gtk_widget_path_iter_add_class (GtkWidgetPath *path,
  **/
 void
 gtk_widget_path_iter_remove_class (GtkWidgetPath *path,
-                                   guint          pos,
+                                   gint           pos,
                                    const gchar   *name)
 {
   GtkPathElement *elem;
@@ -511,9 +776,12 @@ gtk_widget_path_iter_remove_class (GtkWidgetPath *path,
   guint i;
 
   g_return_if_fail (path != NULL);
-  g_return_if_fail (pos < path->elems->len);
+  g_return_if_fail (path->elems->len != 0);
   g_return_if_fail (name != NULL);
 
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
+
   qname = g_quark_try_string (name);
 
   if (qname == 0)
@@ -543,7 +811,7 @@ gtk_widget_path_iter_remove_class (GtkWidgetPath *path,
 /**
  * gtk_widget_path_iter_clear_classes:
  * @path: a #GtkWidget
- * @pos: position to modify
+ * @pos: position to modify, -1 for the path head
  *
  * Removes all classes from the widget at position @pos in the
  * hierarchy defined in @path.
@@ -552,12 +820,15 @@ gtk_widget_path_iter_remove_class (GtkWidgetPath *path,
  **/
 void
 gtk_widget_path_iter_clear_classes (GtkWidgetPath *path,
-                                    guint          pos)
+                                    gint           pos)
 {
   GtkPathElement *elem;
 
   g_return_if_fail (path != NULL);
-  g_return_if_fail (pos < path->elems->len);
+  g_return_if_fail (path->elems->len != 0);
+
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
 
   elem = &g_array_index (path->elems, GtkPathElement, pos);
 
@@ -571,28 +842,31 @@ gtk_widget_path_iter_clear_classes (GtkWidgetPath *path,
 /**
  * gtk_widget_path_iter_list_classes:
  * @path: a #GtkWidgetPath
- * @pos: position to query
+ * @pos: position to query, -1 for the path head
  *
  * Returns a list with all the class names defined for the widget
  * at position @pos in the hierarchy defined in @path.
  *
- * Returns: (transfer container) (type utf8): The list of classes,
- *          This is a list of strings, the #GSList contents are
- *          owned by GTK+, but you should use g_slist_free() to
+ * Returns: (transfer container) (element-type utf8): The list of
+ *          classes, This is a list of strings, the #GSList contents
+ *          are owned by GTK+, but you should use g_slist_free() to
  *          free the list itself.
  *
  * Since: 3.0
  **/
 GSList *
 gtk_widget_path_iter_list_classes (const GtkWidgetPath *path,
-                                   guint                pos)
+                                   gint                 pos)
 {
   GtkPathElement *elem;
   GSList *list = NULL;
   guint i;
 
   g_return_val_if_fail (path != NULL, NULL);
-  g_return_val_if_fail (pos < path->elems->len, NULL);
+  g_return_val_if_fail (path->elems->len != 0, NULL);
+
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
 
   elem = &g_array_index (path->elems, GtkPathElement, pos);
 
@@ -613,7 +887,7 @@ gtk_widget_path_iter_list_classes (const GtkWidgetPath *path,
 /**
  * gtk_widget_path_iter_has_qclass:
  * @path: a #GtkWidgetPath
- * @pos: position to query
+ * @pos: position to query, -1 for the path head
  * @qname: class name as a #GQuark
  *
  * See gtk_widget_path_iter_has_class(). This is a version that operates
@@ -625,16 +899,19 @@ gtk_widget_path_iter_list_classes (const GtkWidgetPath *path,
  **/
 gboolean
 gtk_widget_path_iter_has_qclass (const GtkWidgetPath *path,
-                                 guint                pos,
+                                 gint                 pos,
                                  GQuark               qname)
 {
   GtkPathElement *elem;
   guint i;
 
   g_return_val_if_fail (path != NULL, FALSE);
-  g_return_val_if_fail (pos < path->elems->len, FALSE);
+  g_return_val_if_fail (path->elems->len != 0, FALSE);
   g_return_val_if_fail (qname != 0, FALSE);
 
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
+
   elem = &g_array_index (path->elems, GtkPathElement, pos);
 
   if (!elem->classes)
@@ -658,7 +935,7 @@ gtk_widget_path_iter_has_qclass (const GtkWidgetPath *path,
 /**
  * gtk_widget_path_iter_has_class:
  * @path: a #GtkWidgetPath
- * @pos: position to query
+ * @pos: position to query, -1 for the path head
  * @name: class name
  *
  * Returns %TRUE if the widget at position @pos has the class @name
@@ -670,15 +947,18 @@ gtk_widget_path_iter_has_qclass (const GtkWidgetPath *path,
  **/
 gboolean
 gtk_widget_path_iter_has_class (const GtkWidgetPath *path,
-                                guint                pos,
+                                gint                 pos,
                                 const gchar         *name)
 {
   GQuark qname;
 
   g_return_val_if_fail (path != NULL, FALSE);
-  g_return_val_if_fail (pos < path->elems->len, FALSE);
+  g_return_val_if_fail (path->elems->len != 0, FALSE);
   g_return_val_if_fail (name != NULL, FALSE);
 
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
+
   qname = g_quark_try_string (name);
 
   if (qname == 0)
@@ -690,7 +970,7 @@ gtk_widget_path_iter_has_class (const GtkWidgetPath *path,
 /**
  * gtk_widget_path_iter_add_region:
  * @path: a #GtkWidgetPath
- * @pos: position to modify
+ * @pos: position to modify, -1 for the path head
  * @name: region name
  * @flags: flags affecting the region
  *
@@ -698,11 +978,14 @@ gtk_widget_path_iter_has_class (const GtkWidgetPath *path,
  * the hierarchy defined in @path. See
  * gtk_style_context_add_region().
  *
+ * <note><para>Region names must only contain lowercase letters
+ * and '-', starting always with a lowercase letter.</para></note>
+ *
  * Since: 3.0
  **/
 void
 gtk_widget_path_iter_add_region (GtkWidgetPath  *path,
-                                 guint           pos,
+                                 gint            pos,
                                  const gchar    *name,
                                  GtkRegionFlags  flags)
 {
@@ -710,8 +993,12 @@ gtk_widget_path_iter_add_region (GtkWidgetPath  *path,
   GQuark qname;
 
   g_return_if_fail (path != NULL);
-  g_return_if_fail (pos < path->elems->len);
+  g_return_if_fail (path->elems->len != 0);
   g_return_if_fail (name != NULL);
+  g_return_if_fail (_gtk_style_context_check_region_name (name));
+
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
 
   elem = &g_array_index (path->elems, GtkPathElement, pos);
   qname = g_quark_from_string (name);
@@ -727,7 +1014,7 @@ gtk_widget_path_iter_add_region (GtkWidgetPath  *path,
 /**
  * gtk_widget_path_iter_remove_region:
  * @path: a #GtkWidgetPath
- * @pos: position to modify
+ * @pos: position to modify, -1 for the path head
  * @name: region name
  *
  * Removes the region @name from the widget at position @pos in
@@ -737,16 +1024,19 @@ gtk_widget_path_iter_add_region (GtkWidgetPath  *path,
  **/
 void
 gtk_widget_path_iter_remove_region (GtkWidgetPath *path,
-                                    guint          pos,
+                                    gint           pos,
                                     const gchar   *name)
 {
   GtkPathElement *elem;
   GQuark qname;
 
   g_return_if_fail (path != NULL);
-  g_return_if_fail (pos < path->elems->len);
+  g_return_if_fail (path->elems->len != 0);
   g_return_if_fail (name != NULL);
 
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
+
   qname = g_quark_try_string (name);
 
   if (qname == 0)
@@ -761,7 +1051,7 @@ gtk_widget_path_iter_remove_region (GtkWidgetPath *path,
 /**
  * gtk_widget_path_iter_clear_regions:
  * @path: a #GtkWidgetPath
- * @pos: position to modify
+ * @pos: position to modify, -1 for the path head
  *
  * Removes all regions from the widget at position @pos in the
  * hierarchy defined in @path.
@@ -770,12 +1060,15 @@ gtk_widget_path_iter_remove_region (GtkWidgetPath *path,
  **/
 void
 gtk_widget_path_iter_clear_regions (GtkWidgetPath *path,
-                                    guint          pos)
+                                    gint           pos)
 {
   GtkPathElement *elem;
 
   g_return_if_fail (path != NULL);
-  g_return_if_fail (pos < path->elems->len);
+  g_return_if_fail (path->elems->len != 0);
+
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
 
   elem = &g_array_index (path->elems, GtkPathElement, pos);
 
@@ -786,21 +1079,21 @@ gtk_widget_path_iter_clear_regions (GtkWidgetPath *path,
 /**
  * gtk_widget_path_iter_list_regions:
  * @path: a #GtkWidgetPath
- * @pos: position to query
+ * @pos: position to query, -1 for the path head
  *
  * Returns a list with all the region names defined for the widget
  * at position @pos in the hierarchy defined in @path.
  *
- * Returns: (transfer container) (type utf8): The list of regions,
- *          This is a list of strings, the #GSList contents are
- *          owned by GTK+, but you should use g_slist_free() to
+ * Returns: (transfer container) (element-type utf8): The list of
+ *          regions, This is a list of strings, the #GSList contents
+ *          are owned by GTK+, but you should use g_slist_free() to
  *          free the list itself.
  *
  * Since: 3.0
  **/
 GSList *
 gtk_widget_path_iter_list_regions (const GtkWidgetPath *path,
-                                   guint                pos)
+                                   gint                 pos)
 {
   GtkPathElement *elem;
   GHashTableIter iter;
@@ -808,7 +1101,10 @@ gtk_widget_path_iter_list_regions (const GtkWidgetPath *path,
   gpointer key;
 
   g_return_val_if_fail (path != NULL, NULL);
-  g_return_val_if_fail (pos < path->elems->len, NULL);
+  g_return_val_if_fail (path->elems->len != 0, NULL);
+
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
 
   elem = &g_array_index (path->elems, GtkPathElement, pos);
 
@@ -831,7 +1127,7 @@ gtk_widget_path_iter_list_regions (const GtkWidgetPath *path,
 /**
  * gtk_widget_path_iter_has_qregion:
  * @path: a #GtkWidgetPath
- * @pos: position to query
+ * @pos: position to query, -1 for the path head
  * @qname: region name as a #GQuark
  * @flags: (out): return location for the region flags
  *
@@ -844,7 +1140,7 @@ gtk_widget_path_iter_list_regions (const GtkWidgetPath *path,
  **/
 gboolean
 gtk_widget_path_iter_has_qregion (const GtkWidgetPath *path,
-                                  guint                pos,
+                                  gint                 pos,
                                   GQuark               qname,
                                   GtkRegionFlags      *flags)
 {
@@ -852,9 +1148,12 @@ gtk_widget_path_iter_has_qregion (const GtkWidgetPath *path,
   gpointer value;
 
   g_return_val_if_fail (path != NULL, FALSE);
-  g_return_val_if_fail (pos < path->elems->len, FALSE);
+  g_return_val_if_fail (path->elems->len != 0, FALSE);
   g_return_val_if_fail (qname != 0, FALSE);
 
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
+
   elem = &g_array_index (path->elems, GtkPathElement, pos);
 
   if (!elem->regions)
@@ -874,7 +1173,7 @@ gtk_widget_path_iter_has_qregion (const GtkWidgetPath *path,
 /**
  * gtk_widget_path_iter_has_region:
  * @path: a #GtkWidgetPath
- * @pos: position to query
+ * @pos: position to query, -1 for the path head
  * @name: region name
  * @flags: (out): return location for the region flags
  *
@@ -887,16 +1186,19 @@ gtk_widget_path_iter_has_qregion (const GtkWidgetPath *path,
  **/
 gboolean
 gtk_widget_path_iter_has_region (const GtkWidgetPath *path,
-                                 guint                pos,
+                                 gint                 pos,
                                  const gchar         *name,
                                  GtkRegionFlags      *flags)
 {
   GQuark qname;
 
   g_return_val_if_fail (path != NULL, FALSE);
-  g_return_val_if_fail (pos < path->elems->len, FALSE);
+  g_return_val_if_fail (path->elems->len != 0, FALSE);
   g_return_val_if_fail (name != NULL, FALSE);
 
+  if (pos < 0 || pos >= path->elems->len)
+    pos = path->elems->len - 1;
+
   qname = g_quark_try_string (name);
 
   if (qname == 0)
@@ -906,18 +1208,18 @@ gtk_widget_path_iter_has_region (const GtkWidgetPath *path,
 }
 
 /**
- * gtk_widget_path_get_widget_type:
+ * gtk_widget_path_get_object_type:
  * @path: a #GtkWidget
  *
- * Returns the topmost widget type, that is, the widget type this path
+ * Returns the topmost object type, that is, the object type this path
  * is representing.
  *
- * Returns: The widget type
+ * Returns: The object type
  *
  * Since: 3.0
  **/
 GType
-gtk_widget_path_get_widget_type (const GtkWidgetPath *path)
+gtk_widget_path_get_object_type (const GtkWidgetPath *path)
 {
   GtkPathElement *elem;
 
@@ -947,7 +1249,6 @@ gtk_widget_path_is_type (const GtkWidgetPath *path,
   GtkPathElement *elem;
 
   g_return_val_if_fail (path != NULL, FALSE);
-  g_return_val_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET), FALSE);
 
   elem = &g_array_index (path->elems, GtkPathElement,
                          path->elems->len - 1);
@@ -978,7 +1279,6 @@ gtk_widget_path_has_parent (const GtkWidgetPath *path,
   guint i;
 
   g_return_val_if_fail (path != NULL, FALSE);
-  g_return_val_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET), FALSE);
 
   for (i = 0; i < path->elems->len - 1; i++)
     {