* methods for all object types in GTK+, Pango and other libraries
* based on GObject. The GObject class provides methods for object
* construction and destruction, property access methods, and signal
- * support. Signals are described in detail in <xref
- * linkend="gobject-Signals"/>.
+ * support. Signals are described in detail [here][gobject-Signals].
+ *
+ * ## Floating references # {#floating-ref}
*
- * <para id="floating-ref">
* GInitiallyUnowned is derived from GObject. The only difference between
* the two is that the initial reference of a GInitiallyUnowned is flagged
- * as a <firstterm>floating</firstterm> 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:
+ * |[<!-- language="C" -->
* container = create_container ();
* container_add_child (container, create_child());
* ]|
* 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:
- * |[
+ * |[<!-- language="C" -->
* Child *child;
* container = create_container ();
* child = create_child ();
* language bindings that provide automated reference and memory ownership
* maintenance (such as smart pointers or garbage collection) should not
* expose floating references in their API.
- * </para>
*
* Some object implementations may need to save an objects floating state
* across certain code portions (an example is #GtkMenu), to achieve this,
* the following sequence can be used:
*
- * |[
- * /* save floating state */
+ * |[<!-- language="C" -->
+ * // save floating state
* gboolean was_floating = g_object_is_floating (object);
* g_object_ref_sink (object);
- * /* protected code portion */
- * ...;
- * /* restore floating state */
+ * // protected code portion
+ *
+ * ...
+ *
+ * // restore floating state
* if (was_floating)
* g_object_force_floating (object);
* else
- * g_object_unref (object); /* release previously acquired reference */
+ * g_object_unref (object); // release previously acquired reference
* ]|
*/
* 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:
- * |[
+ * |[<!-- language="C" -->
* g_signal_connect (text_view->buffer, "notify::paste-target-list",
* G_CALLBACK (gtk_text_view_target_list_notify),
* text_view)
* ]|
* It is important to note that you must use
- * <link linkend="canonical-parameter-name">canonical</link> parameter names as
+ * [canonical][canonical-parameter-name] parameter names as
* detail strings for the notify signal.
*/
gobject_signals[NOTIFY] =
* @property_id: the id for the new property
* @pspec: the #GParamSpec for the new property
*
- * Installs a new property. This is usually done in the class initializer.
+ * Installs a new property.
+ *
+ * All properties should be installed during the class initializer. It
+ * is possible to install properties after that, but doing so is not
+ * recommend, and specifically, is not guaranteed to be thread-safe vs.
+ * use of properties on the same type on other threads.
*
* Note that it is possible to redefine a property in a derived class,
* by installing a property with the same name. This can be useful at times,
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);
- 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_return_if_fail (pspec->flags & (G_PARAM_READABLE | G_PARAM_WRITABLE));
* @pspecs: (array length=n_pspecs): the #GParamSpecs array
* defining the new properties
*
- * Installs new properties from an array of #GParamSpecs. This is
- * usually done in the class initializer.
+ * Installs new properties from an array of #GParamSpecs.
+ *
+ * All properties should be installed during the class initializer. It
+ * is possible to install properties after that, but doing so is not
+ * recommend, and specifically, is not guaranteed to be thread-safe vs.
+ * use of properties on the same type on other threads.
*
* The property id of each property is the index of each #GParamSpec in
* the @pspecs array.
* #GParamSpecs and g_object_notify_by_pspec(). For instance, this
* class initialization:
*
- * |[
+ * |[<!-- language="C" -->
* enum {
* PROP_0, PROP_FOO, PROP_BAR, N_PROPERTIES
* };
*
* allows calling g_object_notify_by_pspec() to notify of property changes:
*
- * |[
+ * |[<!-- language="C" -->
* void
* my_object_set_foo (MyObject *self, gint foo)
* {
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);
* @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 <firstterm>override</firstterm>
- * 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
{
if (object_in_construction (object))
{
- g_error ("object %s %p finalized while still in-construction",
- G_OBJECT_TYPE_NAME (object), object);
+ g_critical ("object %s %p finalized while still in-construction",
+ G_OBJECT_TYPE_NAME (object), object);
}
g_datalist_clear (&object->qdata);
* instead, is to store the GParamSpec used with
* g_object_class_install_property() inside a static array, e.g.:
*
- *|[
+ *|[<!-- language="C" -->
* enum
* {
* PROP_0,
*
* and then notify a change on the "foo" property with:
*
- * |[
+ * |[<!-- language="C" -->
* g_object_notify_by_pspec (self, properties[PROP_FOO]);
* ]|
*
g_object_unref (object);
}
+static void
+consider_issuing_property_deprecation_warning (const GParamSpec *pspec)
+{
+ static GHashTable *already_warned_table;
+ static const gchar *enable_diagnostic;
+ static GMutex already_warned_lock;
+ gboolean already;
+
+ if (!(pspec->flags & G_PARAM_DEPRECATED))
+ return;
+
+ if (g_once_init_enter (&enable_diagnostic))
+ {
+ const gchar *value = g_getenv ("G_ENABLE_DIAGNOSTIC");
+
+ if (!value)
+ value = "-";
+
+ g_once_init_leave (&enable_diagnostic, value);
+ }
+
+ if (enable_diagnostic[0] == '0')
+ return;
+
+ /* We hash only on property names: this means that we could end up in
+ * a situation where we fail to emit a warning about a pair of
+ * same-named deprecated properties used on two separate types.
+ * That's pretty unlikely to occur, and even if it does, you'll still
+ * have seen the warning for the first one...
+ *
+ * Doing it this way lets us hash directly on the (interned) property
+ * name pointers.
+ */
+ g_mutex_lock (&already_warned_lock);
+
+ if (already_warned_table == NULL)
+ already_warned_table = g_hash_table_new (NULL, NULL);
+
+ already = g_hash_table_contains (already_warned_table, (gpointer) pspec->name);
+ if (!already)
+ g_hash_table_add (already_warned_table, (gpointer) pspec->name);
+
+ g_mutex_unlock (&already_warned_lock);
+
+ if (!already)
+ g_warning ("The property %s:%s is deprecated and shouldn't be used "
+ "anymore. It will be removed in a future version.",
+ g_type_name (pspec->owner_type), pspec->name);
+}
+
static inline void
object_get_property (GObject *object,
GParamSpec *pspec,
redirect = g_param_spec_get_redirect_target (pspec);
if (redirect)
- pspec = redirect;
-
+ pspec = redirect;
+
+ consider_issuing_property_deprecation_warning (pspec);
+
class->get_property (object, param_id, value, pspec);
}
GObjectClass *class = g_type_class_peek (pspec->owner_type);
guint param_id = PARAM_SPEC_PARAM_ID (pspec);
GParamSpec *redirect;
- static const gchar * enable_diagnostic = NULL;
if (class == NULL)
{
if (redirect)
pspec = redirect;
- if (G_UNLIKELY (!enable_diagnostic))
- {
- enable_diagnostic = g_getenv ("G_ENABLE_DIAGNOSTIC");
- if (!enable_diagnostic)
- enable_diagnostic = "0";
- }
-
- if (enable_diagnostic[0] == '1')
- {
- if (pspec->flags & G_PARAM_DEPRECATED)
- g_warning ("The property %s:%s is deprecated and shouldn't be used "
- "anymore. It will be removed in a future version.",
- G_OBJECT_TYPE_NAME (object), pspec->name);
- }
-
/* 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))
}
else
{
- GParamSpec *notify_pspec;
-
class->set_property (object, param_id, &tmp_value, pspec);
- notify_pspec = get_notify_pspec (pspec);
+ if (~pspec->flags & G_PARAM_EXPLICIT_NOTIFY)
+ {
+ GParamSpec *notify_pspec;
+
+ notify_pspec = get_notify_pspec (pspec);
- if (notify_pspec != NULL)
- g_object_notify_queue_add (object, nqueue, notify_pspec);
+ if (notify_pspec != NULL)
+ g_object_notify_queue_add (object, nqueue, notify_pspec);
+ }
}
g_value_unset (&tmp_value);
}
class = g_type_class_ref (iface_class->g_instance_type);
- if (!G_IS_OBJECT_CLASS (class))
+ if (class == NULL)
return;
+ if (!G_IS_OBJECT_CLASS (class))
+ goto out;
+
pspecs = g_param_spec_pool_list (pspec_pool, iface_type, &n);
while (n--)
g_free (pspecs);
+ out:
g_type_class_unref (class);
}
for (j = 0; j < n_params; j++)
if (params[j].pspec == pspec)
{
+ consider_issuing_property_deprecation_warning (pspec);
value = params[j].value;
break;
}
/* 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);
+ {
+ consider_issuing_property_deprecation_warning (params[i].pspec);
+ object_set_property (object, params[i].pspec, params[i].value, nqueue);
+ }
/* If nqueue is non-NULL then we are frozen. Thaw it. */
if (nqueue)
for (j = 0; j < n_params; j++)
if (params[j].pspec == pspec)
{
+ consider_issuing_property_deprecation_warning (pspec);
value = params[j].value;
break;
}
*/
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);
+ {
+ consider_issuing_property_deprecation_warning (params[i].pspec);
+ object_set_property (object, params[i].pspec, params[i].value, nqueue);
+ }
g_object_notify_queue_thaw (object, nqueue);
}
g_value_unset (&value);
break;
}
-
+
+ consider_issuing_property_deprecation_warning (pspec);
object_set_property (object, pspec, &value, nqueue);
g_value_unset (&value);
-
+
name = va_arg (var_args, gchar*);
}
*
* Here is an example of using g_object_get() to get the contents
* of three properties: an integer, a string and an object:
- * |[
+ * |[<!-- language="C" -->
* gint intval;
* gchar *strval;
* GObject *objval;
* "obj-property", &objval,
* NULL);
*
- * /* Do something with intval, strval, objval */
+ * // Do something with intval, strval, objval
*
* g_free (strval);
* g_object_unref (objval);
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);
-
+ {
+ consider_issuing_property_deprecation_warning (pspec);
+ object_set_property (object, pspec, value, nqueue);
+ }
+
g_object_notify_queue_thaw (object, nqueue);
g_object_unref (object);
}
* - 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)
*
- * |[
+ * |[<!-- language="C" -->
* menu->toplevel = g_object_connect (g_object_new (GTK_TYPE_WINDOW,
* "type", GTK_WINDOW_POPUP,
* "child", menu,
* g_object_is_floating:
* @object: (type GObject.Object): a #GObject
*
- * Checks whether @object has a <link linkend="floating-ref">floating</link>
- * reference.
+ * Checks whether @object has a [floating][floating-ref] reference.
*
* Since: 2.10
*
* @object: (type GObject.Object): a #GObject
*
* Increase the reference count of @object, and possibly remove the
- * <link linkend="floating-ref">floating</link> reference, if @object
- * has a floating reference.
+ * [floating][floating-ref] reference, if @object has a floating reference.
*
* In other words, if the object is floating, then this call "assumes
* ownership" of the floating reference, converting it to a normal
* g_object_force_floating:
* @object: a #GObject
*
- * This function is intended for #GObject implementations to re-enforce a
- * <link linkend="floating-ref">floating</link> object reference.
- * Doing this is seldom required: all
- * #GInitiallyUnowneds are created with a floating reference which
- * usually just needs to be sunken by calling g_object_ref_sink().
+ * This function is intended for #GObject implementations to re-enforce
+ * a [floating][floating-ref] object reference. Doing this is seldom
+ * required: all #GInitiallyUnowneds are created with a floating reference
+ * which usually just needs to be sunken by calling g_object_ref_sink().
*
* Since: 2.10
*/
* 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
- * <firstterm>toggled</firstterm> 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
* Otherwise, the reference count of the object is decreased and the
* pointer is set to %NULL.
*
- * This function is threadsafe and modifies the pointer atomically,
- * using memory barriers where needed.
- *
* A macro is also included that allows this function to be used without
* pointer casts.
*
* 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
+ * Returns: %TRUE if the existing value for @quark was replaced
* by @newval, %FALSE otherwise.
*
* Since: 2.34
* set).
* Usually, calling this function is only required to update
* user data pointers with a destroy notifier, for example:
- * |[
+ * |[<!-- language="C" -->
* void
* object_add_to_user_list (GObject *object,
* const gchar *new_string)
* 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
+ * Returns: %TRUE if the existing value for @key was replaced
* by @newval, %FALSE otherwise.
*
* Since: 2.34
/**
* g_closure_new_object:
* @sizeof_closure: the size of the structure to allocate, must be at least
- * <literal>sizeof (GClosure)</literal>
+ * `sizeof (GClosure)`
* @object: a #GObject pointer to store in the @data field of the newly
* allocated #GClosure
*