[gtk+] Add some more child property API



commit 93f8f12e3933524c86fec4c495017ce13c80b8d1
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Sep 7 18:10:56 2015 -0400

    Add some more child property API
    
    Add gtk_container_install_child_properties and
    gtk_container_child_notify_by_pspec to mirror te corresponding
    GObject APIs.

 docs/reference/gtk/gtk3-sections.txt |    2 +
 gtk/gtkcontainer.c                   |  199 +++++++++++++++++++++++++---------
 gtk/gtkcontainer.h                   |    9 ++
 3 files changed, 161 insertions(+), 49 deletions(-)
---
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index 55e4d49..1894312 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -1020,6 +1020,7 @@ gtk_container_child_set_property
 gtk_container_child_get_valist
 gtk_container_child_set_valist
 gtk_container_child_notify
+gtk_container_child_notify_by_pspec
 gtk_container_forall
 gtk_container_get_border_width
 gtk_container_set_border_width
@@ -1029,6 +1030,7 @@ gtk_container_set_focus_chain
 gtk_container_unset_focus_chain
 gtk_container_class_find_child_property
 gtk_container_class_install_child_property
+gtk_container_class_install_child_properties
 gtk_container_class_list_child_properties
 gtk_container_class_handle_border_width
 
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index c0e0473..20cb4ea 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -602,6 +602,42 @@ gtk_container_buildable_add_child (GtkBuildable  *buildable,
                g_type_name (G_OBJECT_TYPE (child)), g_type_name (G_OBJECT_TYPE (buildable)));
 }
 
+static inline void
+container_set_child_property (GtkContainer       *container,
+                              GtkWidget          *child,
+                              GParamSpec         *pspec,
+                              const GValue       *value,
+                              GObjectNotifyQueue *nqueue)
+{
+  GValue tmp_value = G_VALUE_INIT;
+  GtkContainerClass *class = g_type_class_peek (pspec->owner_type);
+
+  /* provide a copy to work from, convert (if necessary) and validate */
+  g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+  if (!g_value_transform (value, &tmp_value))
+    g_warning ("unable to set child property `%s' of type `%s' from value of type `%s'",
+               pspec->name,
+               g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
+               G_VALUE_TYPE_NAME (value));
+  else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
+    {
+      gchar *contents = g_strdup_value_contents (value);
+
+      g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
+                 contents,
+                 G_VALUE_TYPE_NAME (value),
+                 pspec->name,
+                 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
+      g_free (contents);
+    }
+  else
+    {
+      class->set_child_property (container, child, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
+      g_object_notify_queue_add (G_OBJECT (child), nqueue, pspec);
+    }
+  g_value_unset (&tmp_value);
+}
+
 static void
 gtk_container_buildable_set_child_property (GtkContainer *container,
                                             GtkBuilder   *builder,
@@ -612,6 +648,7 @@ gtk_container_buildable_set_child_property (GtkContainer *container,
   GParamSpec *pspec;
   GValue gvalue = G_VALUE_INIT;
   GError *error = NULL;
+  GObjectNotifyQueue *nqueue;
 
   if (_gtk_widget_get_parent (child) != (GtkWidget *)container &&
       !GTK_IS_ASSISTANT (container) &&
@@ -628,8 +665,14 @@ gtk_container_buildable_set_child_property (GtkContainer *container,
   pspec = gtk_container_class_find_child_property (G_OBJECT_GET_CLASS (container), name);
   if (!pspec)
     {
-      g_warning ("%s does not have a property called %s",
-                 g_type_name (G_OBJECT_TYPE (container)), name);
+      g_warning ("%s does not have a child property called %s",
+                 G_OBJECT_TYPE_NAME (container), name);
+      return;
+    }
+  else if (!(pspec->flags & G_PARAM_WRITABLE))
+    {
+      g_warning ("Child property `%s' of container class `%s' is not writable",
+                 name, G_OBJECT_TYPE_NAME (container));
       return;
     }
 
@@ -645,7 +688,13 @@ gtk_container_buildable_set_child_property (GtkContainer *container,
       return;
     }
 
-  gtk_container_child_set_property (container, child, name, &gvalue);
+  g_object_ref (container);
+  g_object_ref (child);
+  nqueue = g_object_notify_queue_freeze (G_OBJECT (child), _gtk_widget_child_property_notify_context);
+  container_set_child_property (container, child, pspec, &gvalue, nqueue);
+  g_object_notify_queue_thaw (G_OBJECT (child), nqueue);
+  g_object_unref (container);
+  g_object_unref (child);
   g_value_unset (&gvalue);
 }
 
@@ -992,7 +1041,7 @@ gtk_container_child_type (GtkContainer *container)
  *
  * Emits a #GtkWidget::child-notify signal for the
  * [child property][child-properties]
- * @child_property on widget.
+ * @child_property on the child.
  *
  * This is an analogue of g_object_notify() for child properties.
  *
@@ -1044,6 +1093,46 @@ gtk_container_child_notify (GtkContainer *container,
   g_object_unref (obj);
 }
 
+/**
+ * gtk_container_child_notify_by_pspec:
+ * @container: the #GtkContainer
+ * @child: the child widget
+ * @pspec: the #GParamSpec of a child property instealled on
+ *     the class of @container
+ *
+ * Emits a #GtkWidget::child-notify signal for the
+ * [child property][child-properties] specified by
+ * @pspec on the child.
+ *
+ * This is an analogue of g_object_notify_by_pspec() for child properties.
+ *
+ * Since: 3.18
+ */
+void
+gtk_container_child_notify_by_pspec (GtkContainer *container,
+                                     GtkWidget    *child,
+                                     GParamSpec   *pspec)
+{
+  GObject *obj = G_OBJECT (child);
+  GObjectNotifyQueue *nqueue;
+
+  g_return_if_fail (GTK_IS_CONTAINER (container));
+  g_return_if_fail (GTK_IS_WIDGET (child));
+  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+
+  if (obj->ref_count == 0)
+    return;
+
+  g_object_ref (obj);
+
+  nqueue = g_object_notify_queue_freeze (obj, _gtk_widget_child_property_notify_context);
+
+  g_object_notify_queue_add (obj, nqueue, pspec);
+  g_object_notify_queue_thaw (obj, nqueue);
+
+  g_object_unref (obj);
+}
+
 static inline void
 container_get_child_property (GtkContainer *container,
                               GtkWidget    *child,
@@ -1055,42 +1144,6 @@ container_get_child_property (GtkContainer *container,
   class->get_child_property (container, child, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
 }
 
-static inline void
-container_set_child_property (GtkContainer       *container,
-                              GtkWidget          *child,
-                              GParamSpec         *pspec,
-                              const GValue       *value,
-                              GObjectNotifyQueue *nqueue)
-{
-  GValue tmp_value = G_VALUE_INIT;
-  GtkContainerClass *class = g_type_class_peek (pspec->owner_type);
-
-  /* provide a copy to work from, convert (if necessary) and validate */
-  g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
-  if (!g_value_transform (value, &tmp_value))
-    g_warning ("unable to set child property `%s' of type `%s' from value of type `%s'",
-               pspec->name,
-               g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
-               G_VALUE_TYPE_NAME (value));
-  else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
-    {
-      gchar *contents = g_strdup_value_contents (value);
-
-      g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
-                 contents,
-                 G_VALUE_TYPE_NAME (value),
-                 pspec->name,
-                 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
-      g_free (contents);
-    }
-  else
-    {
-      class->set_child_property (container, child, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
-      g_object_notify_queue_add (G_OBJECT (child), nqueue, pspec);
-    }
-  g_value_unset (&tmp_value);
-}
-
 /**
  * gtk_container_child_get_valist:
  * @container: a #GtkContainer
@@ -1441,6 +1494,24 @@ gtk_container_child_get (GtkContainer      *container,
   va_end (var_args);
 }
 
+static inline void
+install_child_property_internal (GType       g_type,
+                                 guint       property_id,
+                                 GParamSpec *pspec)
+{
+  if (g_param_spec_pool_lookup (_gtk_widget_child_property_pool, pspec->name, g_type, FALSE))
+    {
+      g_warning ("Class '%s' already contains a child property named '%s'",
+                 g_type_name (g_type),
+                 pspec->name);
+      return;
+    }
+  g_param_spec_ref (pspec);
+  g_param_spec_sink (pspec);
+  PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
+  g_param_spec_pool_insert (_gtk_widget_child_property_pool, pspec, g_type);
+}
+
 /**
  * gtk_container_class_install_child_property:
  * @cclass: a #GtkContainerClass
@@ -1465,17 +1536,47 @@ gtk_container_class_install_child_property (GtkContainerClass *cclass,
   if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))
     g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
 
-  if (g_param_spec_pool_lookup (_gtk_widget_child_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (cclass), 
FALSE))
+  install_child_property_internal (G_OBJECT_CLASS_TYPE (cclass), property_id, pspec);
+}
+
+/**
+ * gtk_container_class_install_child_properties:
+ * @cclass: a #GtkContainerClass
+ * @n_pspecs: the length of the #GParamSpec array
+ * @pspec: (array length=n_pspecs): the #GParamSpec array defining the new
+ *     child properties
+ *
+ * Installs child properties on a container class.
+ *
+ * Since: 3.18
+ */
+void
+gtk_container_class_install_child_properties (GtkContainerClass  *cclass,
+                                              guint               n_pspecs,
+                                              GParamSpec        **pspecs)
+{
+  gint i;
+
+  g_return_if_fail (GTK_IS_CONTAINER_CLASS (cclass));
+  g_return_if_fail (n_pspecs > 1);
+  g_return_if_fail (pspecs[0] == NULL);
+
+  /* we skip the first element of the array as it would have a 0 prop_id */
+  for (i = 1; i < n_pspecs; i++)
     {
-      g_warning (G_STRLOC ": class `%s' already contains a child property named `%s'",
-                 G_OBJECT_CLASS_NAME (cclass),
-                 pspec->name);
-      return;
+      GParamSpec *pspec = pspecs[i];
+
+      g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+      if (pspec->flags & G_PARAM_WRITABLE)
+        g_return_if_fail (cclass->set_child_property != NULL);
+      if (pspec->flags & G_PARAM_READABLE)
+        g_return_if_fail (cclass->get_child_property != NULL);
+      g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0);  /* paranoid */
+      if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))
+        g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
+
+      install_child_property_internal (G_OBJECT_CLASS_TYPE (cclass), i, pspec);
     }
-  g_param_spec_ref (pspec);
-  g_param_spec_sink (pspec);
-  PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
-  g_param_spec_pool_insert (_gtk_widget_child_property_pool, pspec, G_OBJECT_CLASS_TYPE (cclass));
 }
 
 /**
diff --git a/gtk/gtkcontainer.h b/gtk/gtkcontainer.h
index a3e9b66..d6cc8ed 100644
--- a/gtk/gtkcontainer.h
+++ b/gtk/gtkcontainer.h
@@ -218,6 +218,10 @@ GDK_AVAILABLE_IN_ALL
 void         gtk_container_class_install_child_property (GtkContainerClass *cclass,
                                                         guint              property_id,
                                                         GParamSpec        *pspec);
+GDK_AVAILABLE_IN_3_18
+void         gtk_container_class_install_child_properties (GtkContainerClass *cclass,
+                                                           guint              n_pspecs,
+                                                           GParamSpec       **pspecs);
 GDK_AVAILABLE_IN_ALL
 GParamSpec*  gtk_container_class_find_child_property   (GObjectClass      *cclass,
                                                         const gchar       *property_name);
@@ -265,6 +269,11 @@ void gtk_container_child_notify (GtkContainer *container,
                                  GtkWidget    *child,
                                  const gchar  *child_property);
 
+GDK_AVAILABLE_IN_3_18
+void gtk_container_child_notify_by_pspec (GtkContainer *container,
+                                          GtkWidget    *child,
+                                          GParamSpec   *pspec);
+
 /**
  * GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID:
  * @object: the #GObject on which set_child_property() or get_child_property()


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]