X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gobject%2Fgobject.c;h=d7002665a656e467494da0484a42f8085fa69372;hb=a35d8a4c77fbb9a8dd143742c29c0807ec99412b;hp=9c4ca6374531fec885ea92581b9bef4d3b41a1c6;hpb=f642209ef4c7f13f5ff03ca3c315cd237f8f26bb;p=platform%2Fupstream%2Fglib.git diff --git a/gobject/gobject.c b/gobject/gobject.c index 9c4ca63..d700266 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -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. + * Public License along with this library; if not, see . */ /* @@ -51,31 +49,31 @@ * * GInitiallyUnowned is derived from GObject. The only difference between * the two is that the initial reference of a GInitiallyUnowned is flagged - * as a floating reference. - * This means that it is not specifically claimed to be "owned" by - * any code portion. The main motivation for providing floating references is - * C convenience. In particular, it allows code to be written as: - * |[ + * as a "floating" reference. This means that it is not specifically + * claimed to be "owned" by any code portion. The main motivation for + * providing floating references is C convenience. In particular, it + * allows code to be written as: + * |[ * container = create_container (); * container_add_child (container, create_child()); * ]| - * If container_add_child() will g_object_ref_sink() the - * passed in child, no reference of the newly created child is leaked. - * Without floating references, container_add_child() - * can only g_object_ref() the new child, so to implement this code without - * reference leaks, it would have to be written as: - * |[ + * If container_add_child() calls g_object_ref_sink() on the passed-in child, + * no reference of the newly created child is leaked. Without floating + * references, container_add_child() can only g_object_ref() the new child, + * so to implement this code without reference leaks, it would have to be + * written as: + * |[ * Child *child; * container = create_container (); * child = create_child (); * container_add_child (container, child); * g_object_unref (child); * ]| - * The floating reference can be converted into - * an ordinary reference by calling g_object_ref_sink(). - * For already sunken objects (objects that don't have a floating reference - * anymore), g_object_ref_sink() is equivalent to g_object_ref() and returns - * a new reference. + * The floating reference can be converted into an ordinary reference by + * calling g_object_ref_sink(). For already sunken objects (objects that + * don't have a floating reference anymore), g_object_ref_sink() is equivalent + * to g_object_ref() and returns a new reference. + * * Since floating references are useful almost exclusively for C convenience, * language bindings that provide automated reference and memory ownership * maintenance (such as smart pointers or garbage collection) should not @@ -86,7 +84,7 @@ * across certain code portions (an example is #GtkMenu), to achieve this, * the following sequence can be used: * - * |[ + * |[ * /* save floating state */ * gboolean was_floating = g_object_is_floating (object); * g_object_ref_sink (object); @@ -95,7 +93,8 @@ * /* restore floating state */ * if (was_floating) * g_object_force_floating (object); - * g_object_unref (object); /* release previously acquired reference */ + * else + * g_object_unref (object); /* release previously acquired reference */ * ]| */ @@ -175,7 +174,7 @@ static void g_object_dispatch_properties_changed (GObject *object, static guint object_floating_flag_handler (GObject *object, gint job); -static void object_interface_check_properties (gpointer func_data, +static void object_interface_check_properties (gpointer check_data, gpointer g_iface); /* --- typedefs --- */ @@ -196,11 +195,10 @@ static GQuark quark_closure_array = 0; static GQuark quark_weak_refs = 0; static GQuark quark_toggle_refs = 0; static GQuark quark_notify_queue; +static GQuark quark_in_construction; static GParamSpecPool *pspec_pool = NULL; static gulong gobject_signals[LAST_SIGNAL] = { 0, }; static guint (*floating_flag_handler) (GObject*, gint) = object_floating_flag_handler; -G_LOCK_DEFINE_STATIC (construction_mutex); -static GSList *construction_objects = NULL; /* qdata pointing to GSList, protected by weak_locations_lock */ static GQuark quark_weak_locations = 0; static GRWLock weak_locations_lock; @@ -313,7 +311,6 @@ g_object_notify_queue_add (GObject *object, #ifdef G_ENABLE_DEBUG #define IF_DEBUG(debug_type) if (_g_type_debug_flags & G_TYPE_DEBUG_ ## debug_type) G_LOCK_DEFINE_STATIC (debug_objects); -static volatile GObject *g_trap_object_ref = NULL; static guint debug_objects_count = 0; static GHashTable *debug_objects_ht = NULL; @@ -450,6 +447,7 @@ g_object_do_class_init (GObjectClass *class) quark_weak_locations = g_quark_from_static_string ("GObject-weak-locations"); quark_toggle_refs = g_quark_from_static_string ("GObject-toggle-references"); quark_notify_queue = g_quark_from_static_string ("GObject-notify-queue"); + quark_in_construction = g_quark_from_static_string ("GObject-in-construction"); pspec_pool = g_param_spec_pool_new (TRUE); class->constructor = g_object_constructor; @@ -475,7 +473,7 @@ g_object_do_class_init (GObjectClass *class) * This signal is typically used to obtain change notification for a * single property, by specifying the property name as a detail in the * g_signal_connect() call, like this: - * |[ + * |[ * g_signal_connect (text_view->buffer, "notify::paste-target-list", * G_CALLBACK (gtk_text_view_target_list_notify), * text_view) @@ -507,7 +505,7 @@ install_property_internal (GType g_type, { 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_warning ("When installing property: type '%s' already has a property named '%s'", g_type_name (g_type), pspec->name); return; @@ -539,8 +537,10 @@ g_object_class_install_property (GObjectClass *class, g_return_if_fail (G_IS_PARAM_SPEC (pspec)); if (CLASS_HAS_DERIVED_CLASS (class)) - g_error ("Attempt to add property %s::%s to class after it was derived", - G_OBJECT_CLASS_NAME (class), pspec->name); + g_error ("Attempt to add property %s::%s to class after it was derived", G_OBJECT_CLASS_NAME (class), pspec->name); + + if (!g_type_is_in_init (G_OBJECT_CLASS_TYPE (class))) + g_warning ("Attempt to add property %s::%s after class was initialised", G_OBJECT_CLASS_NAME (class), pspec->name); class->flags |= CLASS_HAS_PROPS_FLAG; @@ -559,7 +559,7 @@ g_object_class_install_property (GObjectClass *class, install_property_internal (G_OBJECT_CLASS_TYPE (class), property_id, pspec); if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) - class->construct_properties = g_slist_prepend (class->construct_properties, pspec); + class->construct_properties = g_slist_append (class->construct_properties, pspec); /* for property overrides of construct properties, we have to get rid * of the overidden inherited construct property @@ -572,11 +572,11 @@ g_object_class_install_property (GObjectClass *class, /** * g_object_class_install_properties: * @oclass: a #GObjectClass - * @n_pspecs: the length of the #GParamSpecs array - * @pspecs: (array length=n_pspecs): the #GParamSpecs array + * @n_pspecs: the length of the #GParamSpecs array + * @pspecs: (array length=n_pspecs): the #GParamSpecs array * defining the new properties * - * Installs new properties from an array of #GParamSpecs. This is + * Installs new properties from an array of #GParamSpecs. This is * usually done in the class initializer. * * The property id of each property is the index of each #GParamSpec in @@ -586,10 +586,10 @@ g_object_class_install_property (GObjectClass *class, * be used to store a #GParamSpec. * * This function should be used if you plan to use a static array of - * #GParamSpecs and g_object_notify_by_pspec(). For instance, this + * #GParamSpecs and g_object_notify_by_pspec(). For instance, this * class initialization: * - * |[ + * |[ * enum { * PROP_0, PROP_FOO, PROP_BAR, N_PROPERTIES * }; @@ -622,7 +622,7 @@ g_object_class_install_property (GObjectClass *class, * * allows calling g_object_notify_by_pspec() to notify of property changes: * - * |[ + * |[ * void * my_object_set_foo (MyObject *self, gint foo) * { @@ -652,6 +652,9 @@ g_object_class_install_properties (GObjectClass *oclass, g_error ("Attempt to add properties to %s after it was derived", G_OBJECT_CLASS_NAME (oclass)); + if (!g_type_is_in_init (G_OBJECT_CLASS_TYPE (oclass))) + g_warning ("Attempt to add properties to %s after it was initialised", G_OBJECT_CLASS_NAME (oclass)); + oclass_type = G_OBJECT_CLASS_TYPE (oclass); parent_type = g_type_parent (oclass_type); @@ -676,7 +679,7 @@ g_object_class_install_properties (GObjectClass *oclass, install_property_internal (oclass_type, i, pspec); if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) - oclass->construct_properties = g_slist_prepend (oclass->construct_properties, pspec); + oclass->construct_properties = g_slist_append (oclass->construct_properties, pspec); /* for property overrides of construct properties, we have to get rid * of the overidden inherited construct property @@ -806,13 +809,12 @@ g_object_interface_find_property (gpointer g_iface, * @name: the name of a property registered in a parent class or * in an interface of this class. * - * Registers @property_id as referring to a property with the - * name @name in a parent class or in an interface implemented - * by @oclass. This allows this class to override - * a property implementation in a parent class or to provide - * the implementation of a property from an interface. + * Registers @property_id as referring to a property with the name + * @name in a parent class or in an interface implemented by @oclass. + * This allows this class to "override" a property implementation in + * a parent class or to provide the implementation of a property from + * an interface. * - * * Internally, overriding is implemented by creating a property of type * #GParamSpecOverride; generally operations that query the properties of * the object class, such as g_object_class_find_property() or @@ -823,7 +825,6 @@ g_object_interface_find_property (gpointer g_iface, * correct. For virtually all uses, this makes no difference. If you * need to get the overridden property, you can call * g_param_spec_get_redirect_target(). - * * * Since: 2.4 */ @@ -944,6 +945,12 @@ g_object_interface_list_properties (gpointer g_iface, return pspecs; } +static inline gboolean +object_in_construction (GObject *object) +{ + return g_datalist_id_get_data (&object->qdata, quark_in_construction) != NULL; +} + static void g_object_init (GObject *object, GObjectClass *class) @@ -959,10 +966,8 @@ g_object_init (GObject *object, if (CLASS_HAS_CUSTOM_CONSTRUCTOR (class)) { - /* enter construction list for notify_queue_thaw() and to allow construct-only properties */ - G_LOCK (construction_mutex); - construction_objects = g_slist_prepend (construction_objects, object); - G_UNLOCK (construction_mutex); + /* mark object in-construction for notify_queue_thaw() and to allow construct-only properties */ + g_datalist_id_set_data (&object->qdata, quark_in_construction, object); } #ifdef G_ENABLE_DEBUG @@ -1015,6 +1020,12 @@ g_object_real_dispose (GObject *object) static void g_object_finalize (GObject *object) { + if (object_in_construction (object)) + { + g_error ("object %s %p finalized while still in-construction", + G_OBJECT_TYPE_NAME (object), object); + } + g_datalist_clear (&object->qdata); #ifdef G_ENABLE_DEBUG @@ -1146,6 +1157,11 @@ g_object_notify_by_spec_internal (GObject *object, * When possible, eg. when signaling a property change from within the class * that registered the property, you should use g_object_notify_by_pspec() * instead. + * + * Note that emission of the notify signal may be blocked with + * g_object_freeze_notify(). In this case, the signal emissions are queued + * and will be emitted (in reverse order) when g_object_thaw_notify() is + * called. */ void g_object_notify (GObject *object, @@ -1169,7 +1185,7 @@ g_object_notify (GObject *object, TRUE); if (!pspec) - g_warning ("%s: object class `%s' has no property named `%s'", + g_warning ("%s: object class '%s' has no property named '%s'", G_STRFUNC, G_OBJECT_TYPE_NAME (object), property_name); @@ -1193,7 +1209,7 @@ g_object_notify (GObject *object, * instead, is to store the GParamSpec used with * g_object_class_install_property() inside a static array, e.g.: * - *|[ + *|[ * enum * { * PROP_0, @@ -1218,7 +1234,7 @@ g_object_notify (GObject *object, * * and then notify a change on the "foo" property with: * - * |[ + * |[ * g_object_notify_by_pspec (self, properties[PROP_FOO]); * ]| * @@ -1232,6 +1248,9 @@ g_object_notify_by_pspec (GObject *object, g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (G_IS_PARAM_SPEC (pspec)); + if (g_atomic_int_get (&object->ref_count) == 0) + return; + g_object_ref (object); g_object_notify_by_spec_internal (object, pspec); g_object_unref (object); @@ -1246,7 +1265,8 @@ g_object_notify_by_pspec (GObject *object, * and when it reaches zero, queued "notify" signals are emitted. * * Duplicate notifications for each property are squashed so that at most one - * #GObject::notify signal is emitted for each property. + * #GObject::notify signal is emitted for each property, in the reverse order + * in which they have been queued. * * It is an error to call this function when the freeze count is zero. */ @@ -1335,7 +1355,7 @@ object_set_property (GObject *object, /* provide a copy to work from, convert (if necessary) and validate */ g_value_init (&tmp_value, pspec->value_type); if (!g_value_transform (value, &tmp_value)) - g_warning ("unable to set property `%s' of type `%s' from value of type `%s'", + g_warning ("unable to set property '%s' of type '%s' from value of type '%s'", pspec->name, g_type_name (pspec->value_type), G_VALUE_TYPE_NAME (value)); @@ -1343,7 +1363,7 @@ object_set_property (GObject *object, { gchar *contents = g_strdup_value_contents (value); - g_warning ("value \"%s\" of type `%s' is invalid or out of range for property `%s' of type `%s'", + g_warning ("value \"%s\" of type '%s' is invalid or out of range for property '%s' of type '%s'", contents, G_VALUE_TYPE_NAME (value), pspec->name, @@ -1365,7 +1385,7 @@ object_set_property (GObject *object, } static void -object_interface_check_properties (gpointer func_data, +object_interface_check_properties (gpointer check_data, gpointer g_iface) { GTypeInterface *iface_class = g_iface; @@ -1553,36 +1573,210 @@ g_object_new (GType object_type, return object; } -static gboolean -slist_maybe_remove (GSList **slist, - gconstpointer data) +static gpointer +g_object_new_with_custom_constructor (GObjectClass *class, + GObjectConstructParam *params, + guint n_params) { - GSList *last = NULL, *node = *slist; - while (node) + GObjectNotifyQueue *nqueue = NULL; + gboolean newly_constructed; + GObjectConstructParam *cparams; + GObject *object; + GValue *cvalues; + gint n_cparams; + gint cvals_used; + GSList *node; + gint i; + + /* If we have ->constructed() then we have to do a lot more work. + * It's possible that this is a singleton and it's also possible + * that the user's constructor() will attempt to modify the values + * that we pass in, so we'll need to allocate copies of them. + * It's also possible that the user may attempt to call + * g_object_set() from inside of their constructor, so we need to + * add ourselves to a list of objects for which that is allowed + * while their constructor() is running. + */ + + /* Create the array of GObjectConstructParams for constructor() */ + n_cparams = g_slist_length (class->construct_properties); + cparams = g_new (GObjectConstructParam, n_cparams); + cvalues = g_new0 (GValue, n_cparams); + cvals_used = 0; + i = 0; + + /* As above, we may find the value in the passed-in params list. + * + * If we have the value passed in then we can use the GValue from + * it directly because it is safe to modify. If we use the + * default value from the class, we had better not pass that in + * and risk it being modified, so we create a new one. + * */ + for (node = class->construct_properties; node; node = node->next) { - if (node->data == data) + GParamSpec *pspec; + GValue *value; + gint j; + + pspec = node->data; + value = NULL; /* to silence gcc... */ + + for (j = 0; j < n_params; j++) + if (params[j].pspec == pspec) + { + value = params[j].value; + break; + } + + if (j == n_params) { - if (last) - last->next = node->next; - else - *slist = node->next; - g_slist_free_1 (node); - return TRUE; + value = &cvalues[cvals_used++]; + g_value_init (value, pspec->value_type); + g_param_value_set_default (pspec, value); } - last = node; - node = last->next; + + cparams[i].pspec = pspec; + cparams[i].value = value; + i++; + } + + /* construct object from construction parameters */ + object = class->constructor (class->g_type_class.g_type, n_cparams, cparams); + /* free construction values */ + g_free (cparams); + while (cvals_used--) + g_value_unset (&cvalues[cvals_used]); + g_free (cvalues); + + /* There is code in the wild that relies on being able to return NULL + * from its custom constructor. This was never a supported operation, + * but since the code is already out there... + */ + if (object == NULL) + { + g_critical ("Custom constructor for class %s returned NULL (which is invalid). " + "Please use GInitable instead.", G_OBJECT_CLASS_NAME (class)); + return NULL; + } + + /* g_object_init() will have marked the object as being in-construction. + * Check if the returned object still is so marked, or if this is an + * already-existing singleton (in which case we should not do 'constructed'). + */ + newly_constructed = object_in_construction (object); + if (newly_constructed) + g_datalist_id_set_data (&object->qdata, quark_in_construction, NULL); + + if (CLASS_HAS_PROPS (class)) + { + /* If this object was newly_constructed then g_object_init() + * froze the queue. We need to freeze it here in order to get + * the handle so that we can thaw it below (otherwise it will + * be frozen forever). + * + * We also want to do a freeze if we have any params to set, + * even on a non-newly_constructed object. + * + * It's possible that we have the case of non-newly created + * singleton and all of the passed-in params were construct + * properties so n_params > 0 but we will actually set no + * properties. This is a pretty lame case to optimise, so + * just ignore it and freeze anyway. + */ + if (newly_constructed || n_params) + nqueue = g_object_notify_queue_freeze (object, FALSE); + + /* Remember: if it was newly_constructed then g_object_init() + * already did a freeze, so we now have two. Release one. + */ + if (newly_constructed) + g_object_notify_queue_thaw (object, nqueue); } - return FALSE; + + /* run 'constructed' handler if there is a custom one */ + if (newly_constructed && CLASS_HAS_CUSTOM_CONSTRUCTED (class)) + class->constructed (object); + + /* set remaining properties */ + for (i = 0; i < n_params; i++) + if (!(params[i].pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))) + object_set_property (object, params[i].pspec, params[i].value, nqueue); + + /* If nqueue is non-NULL then we are frozen. Thaw it. */ + if (nqueue) + g_object_notify_queue_thaw (object, nqueue); + + return object; } -static inline gboolean -object_in_construction_list (GObject *object) +static gpointer +g_object_new_internal (GObjectClass *class, + GObjectConstructParam *params, + guint n_params) { - gboolean in_construction; - G_LOCK (construction_mutex); - in_construction = g_slist_find (construction_objects, object) != NULL; - G_UNLOCK (construction_mutex); - return in_construction; + GObjectNotifyQueue *nqueue = NULL; + GObject *object; + + if G_UNLIKELY (CLASS_HAS_CUSTOM_CONSTRUCTOR (class)) + return g_object_new_with_custom_constructor (class, params, n_params); + + object = (GObject *) g_type_create_instance (class->g_type_class.g_type); + + if (CLASS_HAS_PROPS (class)) + { + GSList *node; + + /* This will have been setup in g_object_init() */ + nqueue = g_datalist_id_get_data (&object->qdata, quark_notify_queue); + g_assert (nqueue != NULL); + + /* We will set exactly n_construct_properties construct + * properties, but they may come from either the class default + * values or the passed-in parameter list. + */ + for (node = class->construct_properties; node; node = node->next) + { + const GValue *value; + GParamSpec *pspec; + gint j; + + pspec = node->data; + value = NULL; /* to silence gcc... */ + + for (j = 0; j < n_params; j++) + if (params[j].pspec == pspec) + { + value = params[j].value; + break; + } + + if (j == n_params) + value = g_param_spec_get_default_value (pspec); + + object_set_property (object, pspec, value, nqueue); + } + } + + /* run 'constructed' handler if there is a custom one */ + if (CLASS_HAS_CUSTOM_CONSTRUCTED (class)) + class->constructed (object); + + if (nqueue) + { + gint i; + + /* Set remaining properties. The construct properties will + * already have been taken, so set only the non-construct + * ones. + */ + for (i = 0; i < n_params; i++) + if (!(params[i].pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))) + object_set_property (object, params[i].pspec, params[i].value, nqueue); + + g_object_notify_queue_thaw (object, nqueue); + } + + return object; } /** @@ -1602,160 +1796,75 @@ object_in_construction_list (GObject *object) */ gpointer g_object_newv (GType object_type, - guint n_parameters, - GParameter *parameters) + guint n_parameters, + GParameter *parameters) { - GObjectConstructParam *cparams = NULL, *oparams; - GObjectNotifyQueue *nqueue = NULL; /* shouldn't be initialized, just to silence compiler */ - GObject *object; GObjectClass *class, *unref_class = NULL; - GSList *slist; - guint n_total_cparams = 0, n_cparams = 0, n_oparams = 0, n_cvalues; - GValue *cvalues; - GList *clist = NULL; - gboolean newly_constructed; - guint i; + GObject *object; g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL); + g_return_val_if_fail (n_parameters == 0 || parameters != NULL, NULL); + /* Try to avoid thrashing the ref_count if we don't need to (since + * it's a locked operation). + */ class = g_type_class_peek_static (object_type); + if (!class) class = unref_class = g_type_class_ref (object_type); - for (slist = class->construct_properties; slist; slist = slist->next) - { - clist = g_list_prepend (clist, slist->data); - n_total_cparams += 1; - } - if (n_parameters == 0 && n_total_cparams == 0) + if (n_parameters) { - /* This is a simple object with no construct properties, and - * no properties are being set, so short circuit the parameter - * handling. This speeds up simple object construction. - */ - oparams = NULL; - object = class->constructor (object_type, 0, NULL); - goto did_construction; - } + GObjectConstructParam *cparams; + guint i, j; - /* collect parameters, sort into construction and normal ones */ - oparams = g_new (GObjectConstructParam, n_parameters); - cparams = g_new (GObjectConstructParam, n_total_cparams); - for (i = 0; i < n_parameters; i++) - { - GValue *value = ¶meters[i].value; - GParamSpec *pspec = g_param_spec_pool_lookup (pspec_pool, - parameters[i].name, - object_type, - TRUE); - if (!pspec) - { - g_warning ("%s: object class `%s' has no property named `%s'", - G_STRFUNC, - g_type_name (object_type), - parameters[i].name); - continue; - } - if (!(pspec->flags & G_PARAM_WRITABLE)) - { - g_warning ("%s: property `%s' of object class `%s' is not writable", - G_STRFUNC, - pspec->name, - g_type_name (object_type)); - continue; - } - if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) - { - GList *list = g_list_find (clist, pspec); + cparams = g_newa (GObjectConstructParam, n_parameters); + j = 0; - if (!list) - { - g_warning ("%s: construct property \"%s\" for object `%s' can't be set twice", - G_STRFUNC, pspec->name, g_type_name (object_type)); - continue; - } - cparams[n_cparams].pspec = pspec; - cparams[n_cparams].value = value; - n_cparams++; - if (!list->prev) - clist = list->next; - else - list->prev->next = list->next; - if (list->next) - list->next->prev = list->prev; - g_list_free_1 (list); - } - else - { - oparams[n_oparams].pspec = pspec; - oparams[n_oparams].value = value; - n_oparams++; - } - } + for (i = 0; i < n_parameters; i++) + { + GParamSpec *pspec; + gint k; - /* set remaining construction properties to default values */ - n_cvalues = n_total_cparams - n_cparams; - cvalues = g_new (GValue, n_cvalues); - while (clist) - { - GList *tmp = clist->next; - GParamSpec *pspec = clist->data; - GValue *value = cvalues + n_total_cparams - n_cparams - 1; + pspec = g_param_spec_pool_lookup (pspec_pool, parameters[i].name, object_type, TRUE); - value->g_type = 0; - g_value_init (value, pspec->value_type); - g_param_value_set_default (pspec, value); + if G_UNLIKELY (!pspec) + { + g_critical ("%s: object class '%s' has no property named '%s'", + G_STRFUNC, g_type_name (object_type), parameters[i].name); + continue; + } - cparams[n_cparams].pspec = pspec; - cparams[n_cparams].value = value; - n_cparams++; + if G_UNLIKELY (~pspec->flags & G_PARAM_WRITABLE) + { + g_critical ("%s: property '%s' of object class '%s' is not writable", + G_STRFUNC, pspec->name, g_type_name (object_type)); + continue; + } - g_list_free_1 (clist); - clist = tmp; - } + if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) + { + for (k = 0; k < j; k++) + if (cparams[k].pspec == pspec) + break; + if G_UNLIKELY (k != j) + { + g_critical ("%s: construct property '%s' for type '%s' cannot be set twice", + G_STRFUNC, parameters[i].name, g_type_name (object_type)); + continue; + } + } - /* construct object from construction parameters */ - object = class->constructor (object_type, n_total_cparams, cparams); - /* free construction values */ - g_free (cparams); - while (n_cvalues--) - g_value_unset (cvalues + n_cvalues); - g_free (cvalues); + cparams[j].pspec = pspec; + cparams[j].value = ¶meters[i].value; + j++; + } - did_construction: - if (CLASS_HAS_CUSTOM_CONSTRUCTOR (class)) - { - /* adjust freeze_count according to g_object_init() and remaining properties */ - G_LOCK (construction_mutex); - newly_constructed = slist_maybe_remove (&construction_objects, object); - G_UNLOCK (construction_mutex); + object = g_object_new_internal (class, cparams, j); } else - newly_constructed = TRUE; - - if (CLASS_HAS_PROPS (class)) - { - if (newly_constructed || n_oparams) - nqueue = g_object_notify_queue_freeze (object, FALSE); - if (newly_constructed) - g_object_notify_queue_thaw (object, nqueue); - } - - /* run 'constructed' handler if there is a custom one */ - if (newly_constructed && CLASS_HAS_CUSTOM_CONSTRUCTED (class)) - class->constructed (object); - - /* set remaining properties */ - for (i = 0; i < n_oparams; i++) - object_set_property (object, oparams[i].pspec, oparams[i].value, nqueue); - g_free (oparams); - - if (CLASS_HAS_PROPS (class)) - { - /* release our own freeze count and handle notifications */ - if (newly_constructed || n_oparams) - g_object_notify_queue_thaw (object, nqueue); - } + /* Fast case: no properties passed in. */ + object = g_object_new_internal (class, NULL, 0); if (unref_class) g_type_class_unref (unref_class); @@ -1778,67 +1887,109 @@ g_object_newv (GType object_type, * Returns: a new instance of @object_type */ GObject* -g_object_new_valist (GType object_type, - const gchar *first_property_name, - va_list var_args) +g_object_new_valist (GType object_type, + const gchar *first_property_name, + va_list var_args) { - GObjectClass *class; - GParameter *params; - const gchar *name; + GObjectClass *class, *unref_class = NULL; GObject *object; - guint n_params = 0, n_alloced_params = 16; - + g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL); - if (!first_property_name) - return g_object_newv (object_type, 0, NULL); + /* Try to avoid thrashing the ref_count if we don't need to (since + * it's a locked operation). + */ + class = g_type_class_peek_static (object_type); - class = g_type_class_ref (object_type); + if (!class) + class = unref_class = g_type_class_ref (object_type); - params = g_new0 (GParameter, n_alloced_params); - name = first_property_name; - while (name) + if (first_property_name) { - gchar *error = NULL; - GParamSpec *pspec = g_param_spec_pool_lookup (pspec_pool, - name, - object_type, - TRUE); - if (!pspec) - { - g_warning ("%s: object class `%s' has no property named `%s'", - G_STRFUNC, - g_type_name (object_type), - name); - break; - } - if (n_params >= n_alloced_params) - { - n_alloced_params += 16; - params = g_renew (GParameter, params, n_alloced_params); - memset (params + n_params, 0, 16 * (sizeof *params)); - } - params[n_params].name = name; - G_VALUE_COLLECT_INIT (¶ms[n_params].value, pspec->value_type, - var_args, 0, &error); - if (error) - { - g_warning ("%s: %s", G_STRFUNC, error); - g_free (error); - g_value_unset (¶ms[n_params].value); - break; - } - n_params++; - name = va_arg (var_args, gchar*); - } + GObjectConstructParam stack_params[16]; + GObjectConstructParam *params; + const gchar *name; + gint n_params = 0; - object = g_object_newv (object_type, n_params, params); + name = first_property_name; + params = stack_params; - while (n_params--) - g_value_unset (¶ms[n_params].value); - g_free (params); + do + { + gchar *error = NULL; + GParamSpec *pspec; + gint i; - g_type_class_unref (class); + pspec = g_param_spec_pool_lookup (pspec_pool, name, object_type, TRUE); + + if G_UNLIKELY (!pspec) + { + g_critical ("%s: object class '%s' has no property named '%s'", + G_STRFUNC, g_type_name (object_type), name); + /* Can't continue because arg list will be out of sync. */ + break; + } + + if G_UNLIKELY (~pspec->flags & G_PARAM_WRITABLE) + { + g_critical ("%s: property '%s' of object class '%s' is not writable", + G_STRFUNC, pspec->name, g_type_name (object_type)); + break; + } + + if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) + { + for (i = 0; i < n_params; i++) + if (params[i].pspec == pspec) + break; + if G_UNLIKELY (i != n_params) + { + g_critical ("%s: property '%s' for type '%s' cannot be set twice", + G_STRFUNC, name, g_type_name (object_type)); + break; + } + } + + if (n_params == 16) + { + params = g_new (GObjectConstructParam, n_params + 1); + memcpy (params, stack_params, sizeof stack_params); + } + else if (n_params > 16) + params = g_renew (GObjectConstructParam, params, n_params + 1); + + params[n_params].pspec = pspec; + params[n_params].value = g_newa (GValue, 1); + memset (params[n_params].value, 0, sizeof (GValue)); + + G_VALUE_COLLECT_INIT (params[n_params].value, pspec->value_type, var_args, 0, &error); + + if (error) + { + g_critical ("%s: %s", G_STRFUNC, error); + g_value_unset (params[n_params].value); + g_free (error); + break; + } + + n_params++; + } + while ((name = va_arg (var_args, const gchar *))); + + object = g_object_new_internal (class, params, n_params); + + while (n_params--) + g_value_unset (params[n_params].value); + + if (params != stack_params) + g_free (params); + } + else + /* Fast case: no properties passed in. */ + object = g_object_new_internal (class, NULL, 0); + + if (unref_class) + g_type_class_unref (unref_class); return object; } @@ -1918,7 +2069,7 @@ g_object_set_valist (GObject *object, TRUE); if (!pspec) { - g_warning ("%s: object class `%s' has no property named `%s'", + g_warning ("%s: object class '%s' has no property named '%s'", G_STRFUNC, G_OBJECT_TYPE_NAME (object), name); @@ -1926,15 +2077,15 @@ g_object_set_valist (GObject *object, } if (!(pspec->flags & G_PARAM_WRITABLE)) { - g_warning ("%s: property `%s' of object class `%s' is not writable", + g_warning ("%s: property '%s' of object class '%s' is not writable", G_STRFUNC, pspec->name, G_OBJECT_TYPE_NAME (object)); break; } - if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) && !object_in_construction_list (object)) + if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) && !object_in_construction (object)) { - g_warning ("%s: construct property \"%s\" for object `%s' can't be set after construction", + g_warning ("%s: construct property \"%s\" for object '%s' can't be set after construction", G_STRFUNC, pspec->name, G_OBJECT_TYPE_NAME (object)); break; } @@ -1999,7 +2150,7 @@ g_object_get_valist (GObject *object, TRUE); if (!pspec) { - g_warning ("%s: object class `%s' has no property named `%s'", + g_warning ("%s: object class '%s' has no property named '%s'", G_STRFUNC, G_OBJECT_TYPE_NAME (object), name); @@ -2007,7 +2158,7 @@ g_object_get_valist (GObject *object, } if (!(pspec->flags & G_PARAM_READABLE)) { - g_warning ("%s: property `%s' of object class `%s' is not readable", + g_warning ("%s: property '%s' of object class '%s' is not readable", G_STRFUNC, pspec->name, G_OBJECT_TYPE_NAME (object)); @@ -2043,6 +2194,10 @@ g_object_get_valist (GObject *object, * name/value pairs, followed by %NULL * * Sets properties on an object. + * + * Note that the "notify" signals are queued and only emitted (in + * reverse order) after all properties have been set. See + * g_object_freeze_notify(). */ void g_object_set (gpointer _object, @@ -2072,12 +2227,9 @@ g_object_set (gpointer _object, * is responsible for freeing the memory in the appropriate manner for * the type, for instance by calling g_free() or g_object_unref(). * - * - * Using g_object_get(<!-- -->) - * An example of using g_object_get() to get the contents - * of three properties - one of type #G_TYPE_INT, - * one of type #G_TYPE_STRING, and one of type #G_TYPE_OBJECT: - * + * Here is an example of using g_object_get() to get the contents + * of three properties: an integer, a string and an object: + * |[ * gint intval; * gchar *strval; * GObject *objval; @@ -2088,12 +2240,11 @@ g_object_set (gpointer _object, * "obj-property", &objval, * NULL); * - * // Do something with intval, strval, objval + * /* Do something with intval, strval, objval */ * * g_free (strval); * g_object_unref (objval); - * - * + * ]| */ void g_object_get (gpointer _object, @@ -2138,17 +2289,17 @@ g_object_set_property (GObject *object, G_OBJECT_TYPE (object), TRUE); if (!pspec) - g_warning ("%s: object class `%s' has no property named `%s'", + g_warning ("%s: object class '%s' has no property named '%s'", G_STRFUNC, G_OBJECT_TYPE_NAME (object), property_name); else if (!(pspec->flags & G_PARAM_WRITABLE)) - g_warning ("%s: property `%s' of object class `%s' is not writable", + g_warning ("%s: property '%s' of object class '%s' is not writable", G_STRFUNC, pspec->name, G_OBJECT_TYPE_NAME (object)); - else if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) && !object_in_construction_list (object)) - g_warning ("%s: construct property \"%s\" for object `%s' can't be set after construction", + else if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) && !object_in_construction (object)) + g_warning ("%s: construct property \"%s\" for object '%s' can't be set after construction", G_STRFUNC, pspec->name, G_OBJECT_TYPE_NAME (object)); else object_set_property (object, pspec, value, nqueue); @@ -2191,12 +2342,12 @@ g_object_get_property (GObject *object, G_OBJECT_TYPE (object), TRUE); if (!pspec) - g_warning ("%s: object class `%s' has no property named `%s'", + g_warning ("%s: object class '%s' has no property named '%s'", G_STRFUNC, G_OBJECT_TYPE_NAME (object), property_name); else if (!(pspec->flags & G_PARAM_READABLE)) - g_warning ("%s: property `%s' of object class `%s' is not readable", + g_warning ("%s: property '%s' of object class '%s' is not readable", G_STRFUNC, pspec->name, G_OBJECT_TYPE_NAME (object)); @@ -2213,7 +2364,7 @@ g_object_get_property (GObject *object, } else if (!g_value_type_transformable (pspec->value_type, G_VALUE_TYPE (value))) { - g_warning ("%s: can't retrieve property `%s' of type `%s' as value of type `%s'", + g_warning ("%s: can't retrieve property '%s' of type '%s' as value of type '%s'", G_STRFUNC, pspec->name, g_type_name (pspec->value_type), G_VALUE_TYPE_NAME (value)); @@ -2248,72 +2399,23 @@ g_object_get_property (GObject *object, * * The signal specs expected by this function have the form * "modifier::signal_name", where modifier can be one of the following: - * - * - * signal - * - * equivalent to g_signal_connect_data (..., NULL, 0) - * - * - * - * object_signal - * object-signal - * - * equivalent to g_signal_connect_object (..., 0) - * - * - * - * swapped_signal - * swapped-signal - * - * equivalent to g_signal_connect_data (..., NULL, G_CONNECT_SWAPPED) - * - * - * - * swapped_object_signal - * swapped-object-signal - * - * equivalent to g_signal_connect_object (..., G_CONNECT_SWAPPED) - * - * - * - * signal_after - * signal-after - * - * equivalent to g_signal_connect_data (..., NULL, G_CONNECT_AFTER) - * - * - * - * object_signal_after - * object-signal-after - * - * equivalent to g_signal_connect_object (..., G_CONNECT_AFTER) - * - * - * - * swapped_signal_after - * swapped-signal-after - * - * equivalent to g_signal_connect_data (..., NULL, G_CONNECT_SWAPPED | G_CONNECT_AFTER) - * - * - * - * swapped_object_signal_after - * swapped-object-signal-after - * - * equivalent to g_signal_connect_object (..., G_CONNECT_SWAPPED | G_CONNECT_AFTER) - * - * - * - * - * |[ + * * - signal: equivalent to g_signal_connect_data (..., NULL, 0) + * - object-signal, object_signal: equivalent to g_signal_connect_object (..., 0) + * - swapped-signal, swapped_signal: equivalent to g_signal_connect_data (..., NULL, G_CONNECT_SWAPPED) + * - swapped_object_signal, swapped-object-signal: equivalent to g_signal_connect_object (..., G_CONNECT_SWAPPED) + * - signal_after, signal-after: equivalent to g_signal_connect_data (..., NULL, G_CONNECT_AFTER) + * - object_signal_after, object-signal-after: equivalent to g_signal_connect_object (..., G_CONNECT_AFTER) + * - swapped_signal_after, swapped-signal-after: equivalent to g_signal_connect_data (..., NULL, G_CONNECT_SWAPPED | G_CONNECT_AFTER) + * - swapped_object_signal_after, swapped-object-signal-after: equivalent to g_signal_connect_object (..., G_CONNECT_SWAPPED | G_CONNECT_AFTER) + * + * |[ * menu->toplevel = g_object_connect (g_object_new (GTK_TYPE_WINDOW, * "type", GTK_WINDOW_POPUP, * "child", menu, * NULL), * "signal::event", gtk_menu_window_event, menu, * "signal::size_request", gtk_menu_window_size_request, menu, - * "signal::destroy", gtk_widget_destroyed, &menu->toplevel, + * "signal::destroy", gtk_widget_destroyed, &menu->toplevel, * NULL); * ]| * @@ -2691,7 +2793,7 @@ g_object_ref_sink (gpointer _object) * This function is intended for #GObject implementations to re-enforce a * floating object reference. * Doing this is seldom required: all - * #GInitiallyUnowneds are created with a floating reference which + * #GInitiallyUnowneds are created with a floating reference which * usually just needs to be sunken by calling g_object_ref_sink(). * * Since: 2.10 @@ -2756,8 +2858,8 @@ toggle_refs_notify (GObject *object, * to the proxy object, but when there are other references held to * @object, a strong reference is held. The @notify callback is called * when the reference from @object to the proxy object should be - * toggled from strong to weak (@is_last_ref - * true) or weak to strong (@is_last_ref false). + * "toggled" from strong to weak (@is_last_ref true) or weak to strong + * (@is_last_ref false). * * Since a (normal) reference must be held to the object before * calling g_object_add_toggle_ref(), the initial state of the reverse @@ -2883,12 +2985,6 @@ g_object_ref (gpointer _object) g_return_val_if_fail (G_IS_OBJECT (object), NULL); g_return_val_if_fail (object->ref_count > 0, NULL); -#ifdef G_ENABLE_DEBUG - if (g_trap_object_ref == object) - G_BREAKPOINT (); -#endif /* G_ENABLE_DEBUG */ - - old_val = g_atomic_int_add (&object->ref_count, 1); if (old_val == 1 && OBJECT_HAS_TOGGLE_REF (object)) @@ -2915,11 +3011,6 @@ g_object_unref (gpointer _object) g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (object->ref_count > 0); -#ifdef G_ENABLE_DEBUG - if (g_trap_object_ref == object) - G_BREAKPOINT (); -#endif /* G_ENABLE_DEBUG */ - /* here we want to atomically do: if (ref_count>1) { ref_count--; return; } */ retry_atomic_decrement1: old_ref = g_atomic_int_get (&object->ref_count); @@ -3106,11 +3197,96 @@ g_object_set_qdata (GObject *object, { g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (quark > 0); - + g_datalist_id_set_data (&object->qdata, quark, data); } /** + * g_object_dup_qdata: + * @object: the #GObject to store user data on + * @quark: a #GQuark, naming the user data pointer + * @dup_func: (allow-none): function to dup the value + * @user_data: (allow-none): passed as user_data to @dup_func + * + * This is a variant of g_object_get_qdata() which returns + * a 'duplicate' of the value. @dup_func defines the + * meaning of 'duplicate' in this context, it could e.g. + * take a reference on a ref-counted object. + * + * If the @quark is not set on the object then @dup_func + * will be called with a %NULL argument. + * + * Note that @dup_func is called while user data of @object + * is locked. + * + * This function can be useful to avoid races when multiple + * threads are using object data on the same key on the same + * object. + * + * Returns: the result of calling @dup_func on the value + * associated with @quark on @object, or %NULL if not set. + * If @dup_func is %NULL, the value is returned + * unmodified. + * + * Since: 2.34 + */ +gpointer +g_object_dup_qdata (GObject *object, + GQuark quark, + GDuplicateFunc dup_func, + gpointer user_data) +{ + g_return_val_if_fail (G_IS_OBJECT (object), NULL); + g_return_val_if_fail (quark > 0, NULL); + + return g_datalist_id_dup_data (&object->qdata, quark, dup_func, user_data); +} + +/** + * g_object_replace_qdata: + * @object: the #GObject to store user data on + * @quark: a #GQuark, naming the user data pointer + * @oldval: (allow-none): the old value to compare against + * @newval: (allow-none): the new value + * @destroy: (allow-none): a destroy notify for the new value + * @old_destroy: (allow-none): destroy notify for the existing value + * + * Compares the user data for the key @quark on @object with + * @oldval, and if they are the same, replaces @oldval with + * @newval. + * + * This is like a typical atomic compare-and-exchange + * operation, for user data on an object. + * + * If the previous value was replaced then ownership of the + * old value (@oldval) is passed to the caller, including + * the registered destroy notify for it (passed out in @old_destroy). + * Its up to the caller to free this as he wishes, which may + * or may not include using @old_destroy as sometimes replacement + * should not destroy the object in the normal way. + * + * Return: %TRUE if the existing value for @quark was replaced + * by @newval, %FALSE otherwise. + * + * Since: 2.34 + */ +gboolean +g_object_replace_qdata (GObject *object, + GQuark quark, + gpointer oldval, + gpointer newval, + GDestroyNotify destroy, + GDestroyNotify *old_destroy) +{ + g_return_val_if_fail (G_IS_OBJECT (object), FALSE); + g_return_val_if_fail (quark > 0, FALSE); + + return g_datalist_id_replace_data (&object->qdata, quark, + oldval, newval, destroy, + old_destroy); +} + +/** * g_object_set_qdata_full: (skip) * @object: The GObject to set store a user data pointer * @quark: A #GQuark, naming the user data pointer @@ -3148,7 +3324,7 @@ g_object_set_qdata_full (GObject *object, * set). * Usually, calling this function is only required to update * user data pointers with a destroy notifier, for example: - * |[ + * |[ * void * object_add_to_user_list (GObject *object, * const gchar *new_string) @@ -3233,6 +3409,94 @@ g_object_set_data (GObject *object, } /** + * g_object_dup_data: + * @object: the #GObject to store user data on + * @key: a string, naming the user data pointer + * @dup_func: (allow-none): function to dup the value + * @user_data: (allow-none): passed as user_data to @dup_func + * + * This is a variant of g_object_get_data() which returns + * a 'duplicate' of the value. @dup_func defines the + * meaning of 'duplicate' in this context, it could e.g. + * take a reference on a ref-counted object. + * + * If the @key is not set on the object then @dup_func + * will be called with a %NULL argument. + * + * Note that @dup_func is called while user data of @object + * is locked. + * + * This function can be useful to avoid races when multiple + * threads are using object data on the same key on the same + * object. + * + * Returns: the result of calling @dup_func on the value + * associated with @key on @object, or %NULL if not set. + * If @dup_func is %NULL, the value is returned + * unmodified. + * + * Since: 2.34 + */ +gpointer +g_object_dup_data (GObject *object, + const gchar *key, + GDuplicateFunc dup_func, + gpointer user_data) +{ + g_return_val_if_fail (G_IS_OBJECT (object), NULL); + g_return_val_if_fail (key != NULL, NULL); + + return g_datalist_id_dup_data (&object->qdata, + g_quark_from_string (key), + dup_func, user_data); +} + +/** + * g_object_replace_data: + * @object: the #GObject to store user data on + * @key: a string, naming the user data pointer + * @oldval: (allow-none): the old value to compare against + * @newval: (allow-none): the new value + * @destroy: (allow-none): a destroy notify for the new value + * @old_destroy: (allow-none): destroy notify for the existing value + * + * Compares the user data for the key @key on @object with + * @oldval, and if they are the same, replaces @oldval with + * @newval. + * + * This is like a typical atomic compare-and-exchange + * operation, for user data on an object. + * + * If the previous value was replaced then ownership of the + * old value (@oldval) is passed to the caller, including + * the registered destroy notify for it (passed out in @old_destroy). + * Its up to the caller to free this as he wishes, which may + * or may not include using @old_destroy as sometimes replacement + * should not destroy the object in the normal way. + * + * Return: %TRUE if the existing value for @key was replaced + * by @newval, %FALSE otherwise. + * + * Since: 2.34 + */ +gboolean +g_object_replace_data (GObject *object, + const gchar *key, + gpointer oldval, + gpointer newval, + GDestroyNotify destroy, + GDestroyNotify *old_destroy) +{ + g_return_val_if_fail (G_IS_OBJECT (object), FALSE); + g_return_val_if_fail (key != NULL, FALSE); + + return g_datalist_id_replace_data (&object->qdata, + g_quark_from_string (key), + oldval, newval, destroy, + old_destroy); +} + +/** * g_object_set_data_full: (skip) * @object: #GObject containing the associations * @key: name of the key @@ -3332,14 +3596,14 @@ g_value_object_collect_value (GValue *value, GObject *object = collect_values[0].v_pointer; if (object->g_type_instance.g_class == NULL) - return g_strconcat ("invalid unclassed object pointer for value type `", + return g_strconcat ("invalid unclassed object pointer for value type '", G_VALUE_TYPE_NAME (value), "'", NULL); else if (!g_value_type_compatible (G_OBJECT_TYPE (object), G_VALUE_TYPE (value))) - return g_strconcat ("invalid object type `", + return g_strconcat ("invalid object type '", G_OBJECT_TYPE_NAME (object), - "' for value type `", + "' for value type '", G_VALUE_TYPE_NAME (value), "'", NULL); @@ -3361,7 +3625,7 @@ g_value_object_lcopy_value (const GValue *value, GObject **object_p = collect_values[0].v_pointer; if (!object_p) - return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); + return g_strdup_printf ("value location for '%s' passed as NULL", G_VALUE_TYPE_NAME (value)); if (!value->data[0].v_pointer) *object_p = NULL; @@ -3514,24 +3778,10 @@ g_value_dup_object (const GValue *value) * ensures that the @gobject stays alive during the call to @c_handler * by temporarily adding a reference count to @gobject. * - * Note that there is a bug in GObject that makes this function - * much less useful than it might seem otherwise. Once @gobject is - * disposed, the callback will no longer be called, but, the signal - * handler is not currently disconnected. If the - * @instance is itself being freed at the same time than this doesn't - * matter, since the signal will automatically be removed, but - * if @instance persists, then the signal handler will leak. You - * should not remove the signal yourself because in a future versions of - * GObject, the handler will automatically - * be disconnected. - * - * It's possible to work around this problem in a way that will - * continue to work with future versions of GObject by checking - * that the signal handler is still connected before disconnected it: - * - * if (g_signal_handler_is_connected (instance, id)) - * g_signal_handler_disconnect (instance, id); - * + * When the @gobject is destroyed the signal handler will be automatically + * disconnected. Note that this is not currently threadsafe (ie: + * emitting a signal while @gobject is being destroyed in another thread + * is not safe). * * Returns: the handler id. */ @@ -3817,9 +4067,9 @@ g_initially_unowned_class_init (GInitiallyUnownedClass *klass) * objects. * * If the object's #GObjectClass.dispose method results in additional - * references to the object being held, any #GWeakRefs taken + * references to the object being held, any #GWeakRefs taken * before it was disposed will continue to point to %NULL. If - * #GWeakRefs are taken after the object is disposed and + * #GWeakRefs are taken after the object is disposed and * re-referenced, they will continue to point to it until its refcount * goes back to zero, at which point they too will be invalidated. */