diff options
author | Owen Taylor <otaylor@redhat.com> | 2003-10-21 19:12:27 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 2003-10-21 19:12:27 +0000 |
commit | 6f5794fad084ffa1179509c1e6ca9401884596e3 (patch) | |
tree | 82487af86773447846f0a10275acc04a6c1e4e21 /gobject | |
parent | 4a29291187c5d1b267ab87378a4f89abf4f013e0 (diff) |
Add a new GParamSpecOverride type that is a pointer to a different
Tue Oct 14 17:40:19 2003 Owen Taylor <otaylor@redhat.com>
* gparamspecs.[ch]: Add a new GParamSpecOverride type
that is a pointer to a different paramspec in a parent
class or interface.
* gparam.[ch]: Add g_paramspec_get_redirect_target()
which follows GParamSpecOverride to the real property.
Make g_param_spec_pool_list() hand redirections,
properties on interfaces.
* gobject.[ch] gobjectnotifyqueue.c: Add
g_object_interface_install_property,
g_object_interface_find_property,
g_object_interface_list_properties(). Redirect virtually all
publically exposed GParamSpec's to the redirect target if
any. (->constructor is the exception.)
(#105894)
Diffstat (limited to 'gobject')
-rw-r--r-- | gobject/ChangeLog | 19 | ||||
-rw-r--r-- | gobject/gobject.c | 257 | ||||
-rw-r--r-- | gobject/gobject.h | 11 | ||||
-rw-r--r-- | gobject/gobjectnotifyqueue.c | 8 | ||||
-rw-r--r-- | gobject/gparam.c | 124 | ||||
-rw-r--r-- | gobject/gparam.h | 4 | ||||
-rw-r--r-- | gobject/gparamspecs.c | 98 | ||||
-rw-r--r-- | gobject/gparamspecs.h | 12 |
8 files changed, 500 insertions, 33 deletions
diff --git a/gobject/ChangeLog b/gobject/ChangeLog index 1f0ed815d..785bbc8d2 100644 --- a/gobject/ChangeLog +++ b/gobject/ChangeLog @@ -1,3 +1,22 @@ +Tue Oct 14 17:40:19 2003 Owen Taylor <otaylor@redhat.com> + + * gparamspecs.[ch]: Add a new GParamSpecOverride type + that is a pointer to a different paramspec in a parent + class or interface. + + * gparam.[ch]: Add g_paramspec_get_redirect_target() + which follows GParamSpecOverride to the real property. + Make g_param_spec_pool_list() hand redirections, + properties on interfaces. + + * gobject.[ch] gobjectnotifyqueue.c: Add + g_object_interface_install_property, + g_object_interface_find_property, + g_object_interface_list_properties(). Redirect virtually all + publically exposed GParamSpec's to the redirect target if + any. (->constructor is the exception.) + (#105894) + Mon Oct 20 22:06:12 2003 Matthias Clasen <maclas@gmx.de> * gobject.h (struct _GObjectClass): Add /*< public >*/ diff --git a/gobject/gobject.c b/gobject/gobject.c index d172e5948..196490162 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -97,6 +97,9 @@ static inline void object_set_property (GObject *object, const GValue *value, GObjectNotifyQueue *nqueue); +static void object_interface_check_properties (gpointer func_data, + gpointer g_iface); + /* --- variables --- */ static GQuark quark_closure_array = 0; @@ -256,6 +259,30 @@ g_object_do_class_init (GObjectClass *class) g_cclosure_marshal_VOID__PARAM, G_TYPE_NONE, 1, G_TYPE_PARAM); + + /* Install a check function that we'll use to verify that classes that + * implement an interface implement all properties for that interface + */ + g_type_add_interface_check (NULL, object_interface_check_properties); +} + +static void +install_property_internal (GType g_type, + guint property_id, + GParamSpec *pspec) +{ + if (g_param_spec_pool_lookup (pspec_pool, pspec->name, g_type, FALSE)) + { + g_warning ("When installing property: type `%s' already has a 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 (pspec_pool, pspec, g_type); } void @@ -276,18 +303,8 @@ g_object_class_install_property (GObjectClass *class, if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) g_return_if_fail (pspec->flags & G_PARAM_WRITABLE); - if (g_param_spec_pool_lookup (pspec_pool, pspec->name, G_OBJECT_CLASS_TYPE (class), FALSE)) - { - g_warning (G_STRLOC ": class `%s' already contains a property named `%s'", - G_OBJECT_CLASS_NAME (class), - pspec->name); - return; - } + install_property_internal (G_OBJECT_CLASS_TYPE (class), property_id, pspec); - g_param_spec_ref (pspec); - g_param_spec_sink (pspec); - PARAM_SPEC_SET_PARAM_ID (pspec, property_id); - g_param_spec_pool_insert (pspec_pool, pspec, G_OBJECT_CLASS_TYPE (class)); if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) class->construct_properties = g_slist_prepend (class->construct_properties, pspec); @@ -299,17 +316,110 @@ g_object_class_install_property (GObjectClass *class, class->construct_properties = g_slist_remove (class->construct_properties, pspec); } +void +g_object_interface_install_property (gpointer g_iface, + GParamSpec *pspec) +{ + GTypeInterface *iface_class = g_iface; + + g_return_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type)); + g_return_if_fail (G_IS_PARAM_SPEC (pspec)); + g_return_if_fail (!G_IS_PARAM_SPEC_OVERRIDE (pspec)); /* paranoid */ + g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */ + + install_property_internal (iface_class->g_type, 0, pspec); +} + GParamSpec* g_object_class_find_property (GObjectClass *class, const gchar *property_name) { + GParamSpec *pspec; + GParamSpec *redirect; + g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL); g_return_val_if_fail (property_name != NULL, NULL); + pspec = g_param_spec_pool_lookup (pspec_pool, + property_name, + G_OBJECT_CLASS_TYPE (class), + TRUE); + if (pspec) + { + redirect = g_param_spec_get_redirect_target (pspec); + if (redirect) + return redirect; + else + return pspec; + } + else + return NULL; +} + +GParamSpec* +g_object_interface_find_property (gpointer g_iface, + const gchar *property_name) +{ + GTypeInterface *iface_class = g_iface; + + g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type), NULL); + g_return_val_if_fail (property_name != NULL, NULL); + return g_param_spec_pool_lookup (pspec_pool, property_name, - G_OBJECT_CLASS_TYPE (class), - TRUE); + iface_class->g_type, + FALSE); +} + +void +g_object_class_override_property (GObjectClass *oclass, + guint property_id, + const gchar *name) +{ + GParamSpec *overridden = NULL; + GParamSpec *new; + GType parent_type; + + g_return_if_fail (G_IS_OBJECT_CLASS (oclass)); + g_return_if_fail (property_id > 0); + g_return_if_fail (name != NULL); + + /* Find the overridden property; first check parent types + */ + parent_type = g_type_parent (G_OBJECT_CLASS_TYPE (oclass)); + if (parent_type != G_TYPE_NONE) + overridden = g_param_spec_pool_lookup (pspec_pool, + name, + parent_type, + TRUE); + if (!overridden) + { + GType *ifaces; + guint n_ifaces; + + /* Now check interfaces + */ + ifaces = g_type_interfaces (G_OBJECT_CLASS_TYPE (oclass), &n_ifaces); + while (n_ifaces-- && !overridden) + { + overridden = g_param_spec_pool_lookup (pspec_pool, + name, + ifaces[n_ifaces], + FALSE); + } + + g_free (ifaces); + } + + if (!overridden) + { + g_warning ("%s: Can't find property to override for '%s::%s'", + G_STRLOC, G_OBJECT_CLASS_NAME (oclass), name); + return; + } + + new = g_param_spec_override (name, overridden); + g_object_class_install_property (oclass, property_id, new); } GParamSpec** /* free result */ @@ -330,6 +440,25 @@ g_object_class_list_properties (GObjectClass *class, return pspecs; } +GParamSpec** /* free result */ +g_object_interface_list_properties (gpointer g_iface, + guint *n_properties_p) +{ + GTypeInterface *iface_class = g_iface; + GParamSpec **pspecs; + guint n; + + g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type), NULL); + + pspecs = g_param_spec_pool_list (pspec_pool, + iface_class->g_type, + &n); + if (n_properties_p) + *n_properties_p = n; + + return pspecs; +} + static void g_object_init (GObject *object) { @@ -491,10 +620,15 @@ g_object_notify (GObject *object, return; g_object_ref (object); + /* We don't need to get the redirect target + * (by, e.g. calling g_object_class_find_property()) + * because g_object_notify_queue_add() does that + */ pspec = g_param_spec_pool_lookup (pspec_pool, property_name, G_OBJECT_TYPE (object), TRUE); + if (!pspec) g_warning ("%s: object class `%s' has no property named `%s'", G_STRLOC, @@ -535,8 +669,14 @@ object_get_property (GObject *object, GValue *value) { GObjectClass *class = g_type_class_peek (pspec->owner_type); + guint param_id = PARAM_SPEC_PARAM_ID (pspec); + GParamSpec *redirect; + + redirect = g_param_spec_get_redirect_target (pspec); + if (redirect) + pspec = redirect; - class->get_property (object, PARAM_SPEC_PARAM_ID (pspec), value, pspec); + class->get_property (object, param_id, value, pspec); } static inline void @@ -547,6 +687,12 @@ object_set_property (GObject *object, { GValue tmp_value = { 0, }; GObjectClass *class = g_type_class_peek (pspec->owner_type); + guint param_id = PARAM_SPEC_PARAM_ID (pspec); + GParamSpec *redirect; + + redirect = g_param_spec_get_redirect_target (pspec); + if (redirect) + pspec = redirect; /* provide a copy to work from, convert (if necessary) and validate */ g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); @@ -568,12 +714,93 @@ object_set_property (GObject *object, } else { - class->set_property (object, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec); + class->set_property (object, param_id, &tmp_value, pspec); g_object_notify_queue_add (object, nqueue, pspec); } g_value_unset (&tmp_value); } +static void +object_interface_check_properties (gpointer func_data, + gpointer g_iface) +{ + GTypeInterface *iface_class = g_iface; + GObjectClass *class = g_type_class_peek (iface_class->g_instance_type); + GType iface_type = iface_class->g_type; + GParamSpec **pspecs; + guint n; + + if (!G_IS_OBJECT_CLASS (class)) + return; + + pspecs = g_param_spec_pool_list (pspec_pool, iface_type, &n); + + while (n--) + { + GParamSpec *class_pspec = g_param_spec_pool_lookup (pspec_pool, + pspecs[n]->name, + G_OBJECT_CLASS_TYPE (class), + TRUE); + + if (!class_pspec) + { + g_critical ("Object class %s doesn't implement property " + "'%s' from interface '%s'", + g_type_name (G_OBJECT_CLASS_TYPE (class)), + pspecs[n]->name, + g_type_name (iface_type)); + + continue; + } + + /* The implementation paramspec must have a less restrictive + * type than the interface parameter spec for set() and a + * more restrictive type for get(). We just require equality, + * rather than doing something more complicated checking + * the READABLE and WRITABLE flags. We also simplify here + * by only checking the value type, not the G_PARAM_SPEC_TYPE. + */ + if (class_pspec && + !g_type_is_a (G_PARAM_SPEC_VALUE_TYPE (pspecs[n]), + G_PARAM_SPEC_VALUE_TYPE (class_pspec))) + { + g_critical ("Property '%s' on class '%s' has type '%s' " + "which is different from the type '%s', " + "of the property on interface '%s'\n", + pspecs[n]->name, + g_type_name (G_OBJECT_CLASS_TYPE (class)), + g_type_name (G_PARAM_SPEC_VALUE_TYPE (class_pspec)), + g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspecs[n])), + g_type_name (iface_type)); + } + +#define SUBSET(a,b,mask) (((a) & ~(b) & (mask)) == 0) + + /* CONSTRUCT and CONSTRUCT_ONLY add restrictions. + * READABLE and WRITABLE remove restrictions. The implementation + * paramspec must have less restrictive flags. + */ + if (class_pspec && + (!SUBSET (class_pspec->flags, + pspecs[n]->flags, + G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY) || + !SUBSET (pspecs[n]->flags, + class_pspec->flags, + G_PARAM_READABLE | G_PARAM_WRITABLE))) + { + g_critical ("Flags for property '%s' on class '%s' " + "are not compatible with the property on" + "interface '%s'\n", + pspecs[n]->name, + g_type_name (G_OBJECT_CLASS_TYPE (class)), + g_type_name (iface_type)); + } +#undef SUBSET + } + + g_free (pspecs); +} + gpointer g_object_new (GType object_type, const gchar *first_property_name, diff --git a/gobject/gobject.h b/gobject/gobject.h index 733ce0afa..6522a0087 100644 --- a/gobject/gobject.h +++ b/gobject/gobject.h @@ -118,6 +118,17 @@ GParamSpec* g_object_class_find_property (GObjectClass *oclass, const gchar *property_name); GParamSpec**g_object_class_list_properties (GObjectClass *oclass, guint *n_properties); +void g_object_class_override_property (GObjectClass *oclass, + guint property_id, + const gchar *name); + +void g_object_interface_install_property (gpointer g_iface, + GParamSpec *pspec); +GParamSpec* g_object_interface_find_property (gpointer g_iface, + const gchar *property_name); +GParamSpec**g_object_interface_list_properties (gpointer g_iface, + guint *n_properties_p); + gpointer g_object_new (GType object_type, const gchar *first_property_name, ...); diff --git a/gobject/gobjectnotifyqueue.c b/gobject/gobjectnotifyqueue.c index 03db5c2c7..c816a86f5 100644 --- a/gobject/gobjectnotifyqueue.c +++ b/gobject/gobjectnotifyqueue.c @@ -142,8 +142,14 @@ g_object_notify_queue_add (GObject *object, { if (pspec->flags & G_PARAM_READABLE) { + GParamSpec *redirect; + g_return_if_fail (nqueue->n_pspecs < 65535); - + + redirect = g_param_spec_get_redirect_target (pspec); + if (redirect) + pspec = redirect; + /* we do the deduping in _thaw */ nqueue->pspecs = g_slist_prepend (nqueue->pspecs, pspec); nqueue->n_pspecs++; diff --git a/gobject/gparam.c b/gobject/gparam.c index da5123e1c..f2edcbbe3 100644 --- a/gobject/gparam.c +++ b/gobject/gparam.c @@ -22,7 +22,7 @@ */ #include "gparam.h" - +#include "gparamspecs.h" #include "gvaluecollector.h" #include <string.h> @@ -246,7 +246,18 @@ g_param_spec_get_nick (GParamSpec *pspec) { g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL); - return pspec->_nick ? pspec->_nick : pspec->name; + if (pspec->_nick) + return pspec->_nick; + else + { + GParamSpec *redirect_target; + + redirect_target = g_param_spec_get_redirect_target (pspec); + if (redirect_target && redirect_target->_nick) + return redirect_target->_nick; + } + + return pspec->name; } G_CONST_RETURN gchar* @@ -254,7 +265,18 @@ g_param_spec_get_blurb (GParamSpec *pspec) { g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL); - return pspec->_blurb; + if (pspec->_blurb) + return pspec->_blurb; + else + { + GParamSpec *redirect_target; + + redirect_target = g_param_spec_get_redirect_target (pspec); + if (redirect_target && redirect_target->_blurb) + return redirect_target->_blurb; + } + + return NULL; } static void @@ -339,6 +361,21 @@ g_param_spec_steal_qdata (GParamSpec *pspec, return g_datalist_id_remove_no_notify (&pspec->qdata, quark); } +GParamSpec* +g_param_spec_get_redirect_target (GParamSpec *pspec) +{ + g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL); + + if (G_IS_PARAM_SPEC_OVERRIDE (pspec)) + { + GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec); + + return ospec->overridden; + } + else + return NULL; +} + void g_param_value_set_default (GParamSpec *pspec, GValue *value) @@ -793,10 +830,10 @@ pspec_compare_id (gconstpointer a, } static inline GSList* -pspec_list_remove_overridden (GSList *plist, - GHashTable *ht, - GType owner_type, - guint *n_p) +pspec_list_remove_overridden_and_redirected (GSList *plist, + GHashTable *ht, + GType owner_type, + guint *n_p) { GSList *rlist = NULL; @@ -804,9 +841,31 @@ pspec_list_remove_overridden (GSList *plist, { GSList *tmp = plist->next; GParamSpec *pspec = plist->data; + GParamSpec *found; + gboolean remove = FALSE; + + /* Remove paramspecs that are redirected, and also paramspecs + * that have are overridden by non-redirected properties. + * The idea is to get the single paramspec for each name that + * best corresponds to what the application sees. + */ + if (g_param_spec_get_redirect_target (pspec)) + remove = TRUE; + else + { + found = param_spec_ht_lookup (ht, pspec->name, owner_type, TRUE); + if (found != pspec) + { + GParamSpec *redirect = g_param_spec_get_redirect_target (found); + if (redirect != pspec) + remove = TRUE; + } + } - if (param_spec_ht_lookup (ht, pspec->name, owner_type, TRUE) != pspec) - g_slist_free_1 (plist); + if (remove) + { + g_slist_free_1 (plist); + } else { plist->next = rlist; @@ -830,12 +889,42 @@ pool_depth_list (gpointer key, if (g_type_is_a (owner_type, pspec->owner_type)) { - guint d = g_type_depth (pspec->owner_type); + if (G_TYPE_IS_INTERFACE (pspec->owner_type)) + { + slists[0] = g_slist_prepend (slists[0], pspec); + } + else + { + guint d = g_type_depth (pspec->owner_type); - slists[d - 1] = g_slist_prepend (slists[d - 1], pspec); + slists[d - 1] = g_slist_prepend (slists[d - 1], pspec); + } } } +/* We handle interfaces specially since we don't want to + * count interface prerequsites like normal inheritance; + * the property comes from the direct inheritance from + * the prerequisite class, not from the interface that + * prerequires it. + * + * also 'depth' isn't a meaningful concept for interface + * prerequites. + */ +static void +pool_depth_list_for_interface (gpointer key, + gpointer value, + gpointer user_data) +{ + GParamSpec *pspec = value; + gpointer *data = user_data; + GSList **slists = data[0]; + GType owner_type = (GType) data[1]; + + if (pspec->owner_type == owner_type) + slists[0] = g_slist_prepend (slists[0], pspec); +} + GParamSpec** /* free result */ g_param_spec_pool_list (GParamSpecPool *pool, GType owner_type, @@ -856,10 +945,15 @@ g_param_spec_pool_list (GParamSpecPool *pool, slists = g_new0 (GSList*, d); data[0] = slists; data[1] = (gpointer) owner_type; - g_hash_table_foreach (pool->hash_table, pool_depth_list, &data); - for (i = 0; i < d - 1; i++) - slists[i] = pspec_list_remove_overridden (slists[i], pool->hash_table, owner_type, n_pspecs_p); - *n_pspecs_p += g_slist_length (slists[i]); + + g_hash_table_foreach (pool->hash_table, + G_TYPE_IS_INTERFACE (owner_type) ? + pool_depth_list_for_interface : + pool_depth_list, + &data); + + for (i = 0; i < d; i++) + slists[i] = pspec_list_remove_overridden_and_redirected (slists[i], pool->hash_table, owner_type, n_pspecs_p); pspecs = g_new (GParamSpec*, *n_pspecs_p + 1); p = pspecs; for (i = 0; i < d; i++) diff --git a/gobject/gparam.h b/gobject/gparam.h index 024a44abc..f86ebdd38 100644 --- a/gobject/gparam.h +++ b/gobject/gparam.h @@ -73,7 +73,7 @@ struct _GParamSpec gchar *name; GParamFlags flags; GType value_type; - GType owner_type; /* class using this property */ + GType owner_type; /* class or interface using this property */ /*< private >*/ gchar *_nick; @@ -122,6 +122,8 @@ void g_param_spec_set_qdata_full (GParamSpec *pspec, GDestroyNotify destroy); gpointer g_param_spec_steal_qdata (GParamSpec *pspec, GQuark quark); +GParamSpec* g_param_spec_get_redirect_target (GParamSpec *pspec); + void g_param_value_set_default (GParamSpec *pspec, GValue *value); gboolean g_param_value_defaults (GParamSpec *pspec, diff --git a/gobject/gparamspecs.c b/gobject/gparamspecs.c index 45d90de52..93f9b9ded 100644 --- a/gobject/gparamspecs.c +++ b/gobject/gparamspecs.c @@ -966,6 +966,54 @@ param_object_values_cmp (GParamSpec *pspec, return p1 < p2 ? -1 : p1 > p2; } +static void +param_override_init (GParamSpec *pspec) +{ + /* GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec); */ +} + +static void +param_override_finalize (GParamSpec *pspec) +{ + GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec); + GParamSpecClass *parent_class = g_type_class_peek (g_type_parent (G_TYPE_PARAM_OVERRIDE)); + + if (ospec->overridden) + { + g_param_spec_unref (ospec->overridden); + ospec->overridden = NULL; + } + + parent_class->finalize (pspec); +} + +static void +param_override_set_default (GParamSpec *pspec, + GValue *value) +{ + GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec); + + g_param_value_set_default (ospec->overridden, value); +} + +static gboolean +param_override_validate (GParamSpec *pspec, + GValue *value) +{ + GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec); + + return g_param_value_validate (ospec->overridden, value); +} + +static gint +param_override_values_cmp (GParamSpec *pspec, + const GValue *value1, + const GValue *value2) +{ + GParamSpecOverride *ospec = G_PARAM_SPEC_OVERRIDE (pspec); + + return g_param_values_cmp (ospec->overridden, value1, value2); +} /* --- type initialization --- */ GType *g_param_spec_types = NULL; @@ -973,7 +1021,7 @@ GType *g_param_spec_types = NULL; void g_param_spec_types_init (void) /* sync with gtype.c */ { - const guint n_types = 20; + const guint n_types = 21; GType type, *spec_types, *spec_types_bound; g_param_spec_types = g_new0 (GType, n_types); @@ -1341,6 +1389,24 @@ g_param_spec_types_init (void) /* sync with gtype.c */ g_assert (type == G_TYPE_PARAM_OBJECT); } + /* G_TYPE_PARAM_OVERRIDE + */ + { + static const GParamSpecTypeInfo pspec_info = { + sizeof (GParamSpecOverride), /* instance_size */ + 16, /* n_preallocs */ + param_override_init, /* instance_init */ + G_TYPE_NONE, /* value_type */ + param_override_finalize, /* finalize */ + param_override_set_default, /* value_set_default */ + param_override_validate, /* value_validate */ + param_override_values_cmp, /* values_cmp */ + }; + type = g_param_type_register_static ("GParamOverride", &pspec_info); + *spec_types++ = type; + g_assert (type == G_TYPE_PARAM_OVERRIDE); + } + g_assert (spec_types == spec_types_bound); } @@ -1831,3 +1897,33 @@ g_param_spec_object (const gchar *name, return G_PARAM_SPEC (ospec); } + +GParamSpec* +g_param_spec_override (const gchar *name, + GParamSpec *overridden) +{ + GParamSpec *pspec; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (G_IS_PARAM_SPEC (overridden), NULL); + + /* Dereference further redirections for property that was passed in + */ + while (TRUE) + { + GParamSpec *indirect = g_param_spec_get_redirect_target (overridden); + if (indirect) + overridden = indirect; + else + break; + } + + pspec = g_param_spec_internal (G_TYPE_PARAM_OVERRIDE, + name, NULL, NULL, + overridden->flags); + + pspec->value_type = G_PARAM_SPEC_VALUE_TYPE (overridden); + G_PARAM_SPEC_OVERRIDE (pspec)->overridden = g_param_spec_ref (overridden); + + return pspec; +} diff --git a/gobject/gparamspecs.h b/gobject/gparamspecs.h index 6d354b738..137e1d0bb 100644 --- a/gobject/gparamspecs.h +++ b/gobject/gparamspecs.h @@ -93,6 +93,9 @@ G_BEGIN_DECLS #define G_TYPE_PARAM_OBJECT (g_param_spec_types[19]) #define G_IS_PARAM_SPEC_OBJECT(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_OBJECT)) #define G_PARAM_SPEC_OBJECT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_OBJECT, GParamSpecObject)) +#define G_TYPE_PARAM_OVERRIDE (g_param_spec_types[20]) +#define G_IS_PARAM_SPEC_OVERRIDE(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_OVERRIDE)) +#define G_PARAM_SPEC_OVERRIDE(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_OVERRIDE, GParamSpecOverride)) /* --- typedefs & structures --- */ @@ -116,6 +119,7 @@ typedef struct _GParamSpecBoxed GParamSpecBoxed; typedef struct _GParamSpecPointer GParamSpecPointer; typedef struct _GParamSpecValueArray GParamSpecValueArray; typedef struct _GParamSpecObject GParamSpecObject; +typedef struct _GParamSpecOverride GParamSpecOverride; struct _GParamSpecChar { @@ -258,6 +262,12 @@ struct _GParamSpecObject { GParamSpec parent_instance; }; +struct _GParamSpecOverride +{ + /*< private >*/ + GParamSpec parent_instance; + GParamSpec *overridden; +}; /* --- GParamSpec prototypes --- */ GParamSpec* g_param_spec_char (const gchar *name, @@ -382,6 +392,8 @@ GParamSpec* g_param_spec_object (const gchar *name, GType object_type, GParamFlags flags); +GParamSpec* g_param_spec_override (const gchar *name, + GParamSpec *overridden); /* --- internal --- */ /* We prefix variable declarations so they can |