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 --- */
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<GWeakRef *>, protected by weak_locations_lock */
static GQuark quark_weak_locations = 0;
static GRWLock weak_locations_lock;
#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;
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;
{
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;
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;
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);
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)
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
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
* 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,
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);
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);
* 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.
*/
/* 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));
{
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,
}
static void
-object_interface_check_properties (gpointer func_data,
+object_interface_check_properties (gpointer check_data,
gpointer g_iface)
{
GTypeInterface *iface_class = g_iface;
return object;
}
-static gboolean
-slist_maybe_remove (GSList **slist,
- gconstpointer data)
-{
- GSList *last = NULL, *node = *slist;
- while (node)
- {
- if (node->data == data)
- {
- if (last)
- last->next = node->next;
- else
- *slist = node->next;
- g_slist_free_1 (node);
- return TRUE;
- }
- last = node;
- node = last->next;
- }
- return FALSE;
-}
-
-static inline gboolean
-object_in_construction_list (GObject *object)
-{
- gboolean in_construction;
- G_LOCK (construction_mutex);
- in_construction = g_slist_find (construction_objects, object) != NULL;
- G_UNLOCK (construction_mutex);
- return in_construction;
-}
-
static gpointer
g_object_new_with_custom_constructor (GObjectClass *class,
GObjectConstructParam *params,
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
- * and will leak memory, but since the code is already out there...
+ * 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). Unable to remove object "
- "from construction_objects list, so memory was probably just leaked. Please use GInitable "
- "instead.", G_OBJECT_CLASS_NAME (class));
+ 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 added us to the construction_objects
- * list. Check if we're in it (and remove us) in order to find
- * out if we were newly-constructed or this is an already-existing
- * singleton (in which case we should not do 'constructed').
+ /* 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').
*/
- G_LOCK (construction_mutex);
- newly_constructed = slist_maybe_remove (&construction_objects, object);
- G_UNLOCK (construction_mutex);
+ 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 G_UNLIKELY (!pspec)
{
- g_critical ("%s: object class `%s' has no property named `%s'",
+ g_critical ("%s: object class '%s' has no property named '%s'",
G_STRFUNC, g_type_name (object_type), parameters[i].name);
continue;
}
if G_UNLIKELY (~pspec->flags & G_PARAM_WRITABLE)
{
- g_critical ("%s: property `%s' of object class `%s' is not writable",
+ g_critical ("%s: property '%s' of object class '%s' is not writable",
G_STRFUNC, pspec->name, g_type_name (object_type));
continue;
}
break;
if G_UNLIKELY (k != j)
{
- g_critical ("%s: construct property `%s' for type `%s' cannot be set twice",
+ g_critical ("%s: construct property '%s' for type '%s' cannot be set twice",
G_STRFUNC, parameters[i].name, g_type_name (object_type));
continue;
}
if G_UNLIKELY (!pspec)
{
- g_critical ("%s: object class `%s' has no property named `%s'",
+ 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_critical ("%s: property '%s' of object class '%s' is not writable",
G_STRFUNC, pspec->name, g_type_name (object_type));
break;
}
break;
if G_UNLIKELY (i != n_params)
{
- g_critical ("%s: property `%s' for type `%s' cannot be set twice",
+ g_critical ("%s: property '%s' for type '%s' cannot be set twice",
G_STRFUNC, name, g_type_name (object_type));
break;
}
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);
}
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;
}
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);
}
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));
* 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,
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);
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));
}
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));
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))
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);
*
* If the previous value was replaced then ownership of the
* old value (@oldval) is passed to the caller, including
- * the registred destroy notify for it (passed out in @old_destroy).
+ * 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.
*
* If the previous value was replaced then ownership of the
* old value (@oldval) is passed to the caller, including
- * the registred destroy notify for it (passed out in @old_destroy).
+ * 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.
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);
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;