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.
This commit is contained in:
Matthias Clasen 2015-09-07 18:10:56 -04:00
parent e3025f2325
commit 93f8f12e39
3 changed files with 161 additions and 49 deletions

View File

@ -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

View File

@ -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));
}
/**

View File

@ -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()