#include "gvaluetypes.h"
#include "gobjectnotifyqueue.c"
#include <string.h>
+#include <signal.h>
#define PREALLOC_CPARAMS (8)
/* --- signals --- */
enum {
- PROPERTIES_CHANGED,
NOTIFY,
LAST_SIGNAL
};
guint n_construct_properties,
GObjectConstructParam *construct_params);
static void g_object_last_unref (GObject *object);
-static void g_object_shutdown (GObject *object);
+static void g_object_real_dispose (GObject *object);
static void g_object_finalize (GObject *object);
static void g_object_do_set_property (GObject *object,
guint property_id,
GObjectNotifyQueue *nqueue);
-/* --- structures --- */
-
-
/* --- variables --- */
static GQuark quark_closure_array = 0;
+static GQuark quark_weak_refs = 0;
static GParamSpecPool *pspec_pool = NULL;
static GObjectNotifyContext property_notify_context = { 0, };
static gulong gobject_signals[LAST_SIGNAL] = { 0, };
IF_DEBUG (OBJECTS)
{
G_LOCK (debug_objects);
- if (debug_objects_ht)
- {
- g_message ("stale GObjects: %u", debug_objects_count);
- g_hash_table_foreach (debug_objects_ht, debug_objects_foreach, NULL);
- }
+ g_message ("stale GObjects: %u", debug_objects_count);
+ g_hash_table_foreach (debug_objects_ht, debug_objects_foreach, NULL);
G_UNLOCK (debug_objects);
}
}
#ifdef G_ENABLE_DEBUG
IF_DEBUG (OBJECTS)
- g_atexit (debug_objects_atexit);
+ {
+ debug_objects_ht = g_hash_table_new (g_direct_hash, NULL);
+ g_atexit (debug_objects_atexit);
+ }
#endif /* G_ENABLE_DEBUG */
}
{
GList *list, *node;
- g_message ("finallizing base class of %s", G_OBJECT_CLASS_NAME (class));
-
_g_signals_destroy (G_OBJECT_CLASS_TYPE (class));
g_slist_free (class->construct_properties);
static void
g_object_do_class_init (GObjectClass *class)
{
+ /* read the comment about typedef struct CArray; on why not to change this quark */
quark_closure_array = g_quark_from_static_string ("GObject-closure-array");
+
+ quark_weak_refs = g_quark_from_static_string ("GObject-weak-references");
pspec_pool = g_param_spec_pool_new (TRUE);
property_notify_context.quark_notify_queue = g_quark_from_static_string ("GObject-notify-queue");
property_notify_context.dispatcher = g_object_notify_dispatcher;
class->constructor = g_object_constructor;
class->set_property = g_object_do_set_property;
class->get_property = g_object_do_get_property;
- class->shutdown = g_object_shutdown;
+ class->dispose = g_object_real_dispose;
class->finalize = g_object_finalize;
class->dispatch_properties_changed = g_object_dispatch_properties_changed;
class->notify = NULL;
gobject_signals[NOTIFY] =
- g_signal_newc ("notify",
- G_TYPE_FROM_CLASS (class),
- G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS,
- G_STRUCT_OFFSET (GObjectClass, notify),
- NULL, NULL,
- g_cclosure_marshal_VOID__PARAM,
- G_TYPE_NONE,
- 1, G_TYPE_PARAM);
+ g_signal_new ("notify",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS,
+ G_STRUCT_OFFSET (GObjectClass, notify),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__PARAM,
+ G_TYPE_NONE,
+ 1, G_TYPE_PARAM);
}
void
IF_DEBUG (OBJECTS)
{
G_LOCK (debug_objects);
- if (!debug_objects_ht)
- debug_objects_ht = g_hash_table_new (g_direct_hash, NULL);
debug_objects_count++;
g_hash_table_insert (debug_objects_ht, object, object);
G_UNLOCK (debug_objects);
}
static void
+g_object_real_dispose (GObject *object)
+{
+ guint ref_count;
+
+ g_signal_handlers_destroy (object);
+ g_datalist_id_set_data (&object->qdata, quark_closure_array, NULL);
+
+ /* yes, temporarily altering the ref_count is hackish, but that
+ * enforces people not jerking around with weak_ref notifiers
+ */
+ ref_count = object->ref_count;
+ object->ref_count = 0;
+ g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL);
+ object->ref_count = ref_count;
+}
+
+static void
+g_object_finalize (GObject *object)
+{
+ g_datalist_clear (&object->qdata);
+
+#ifdef G_ENABLE_DEBUG
+ IF_DEBUG (OBJECTS)
+ {
+ G_LOCK (debug_objects);
+ g_assert (g_hash_table_lookup (debug_objects_ht, object) == object);
+ g_hash_table_remove (debug_objects_ht, object);
+ debug_objects_count--;
+ G_UNLOCK (debug_objects);
+ }
+#endif /* G_ENABLE_DEBUG */
+}
+
+static void
g_object_last_unref (GObject *object)
{
g_return_if_fail (object->ref_count > 0);
if (object->ref_count == 1) /* may have been re-referenced meanwhile */
- G_OBJECT_GET_CLASS (object)->shutdown (object);
+ G_OBJECT_GET_CLASS (object)->dispose (object);
#ifdef G_ENABLE_DEBUG
if (g_trap_object_ref == object)
if (object->ref_count == 0) /* may have been re-referenced meanwhile */
{
g_signal_handlers_destroy (object);
- g_object_set_qdata (object, quark_closure_array, NULL);
+ g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL);
G_OBJECT_GET_CLASS (object)->finalize (object);
#ifdef G_ENABLE_DEBUG
IF_DEBUG (OBJECTS)
{
+ /* catch objects not chaining finalize handlers */
G_LOCK (debug_objects);
- if (debug_objects_ht)
- g_assert (g_hash_table_lookup (debug_objects_ht, object) == NULL);
+ g_assert (g_hash_table_lookup (debug_objects_ht, object) == NULL);
G_UNLOCK (debug_objects);
}
#endif /* G_ENABLE_DEBUG */
}
static void
-g_object_shutdown (GObject *object)
-{
- /* this function needs to be always present for unconditional
- * chaining, we also might add some code here later.
- * beware though, subclasses may invoke shutdown() arbitrarily.
- */
-}
-
-static void
-g_object_finalize (GObject *object)
-{
- g_signal_handlers_destroy (object);
- g_datalist_clear (&object->qdata);
-
-#ifdef G_ENABLE_DEBUG
- IF_DEBUG (OBJECTS)
- {
- G_LOCK (debug_objects);
- g_assert (g_hash_table_lookup (debug_objects_ht, object) == object);
- g_hash_table_remove (debug_objects_ht, object);
- debug_objects_count--;
- G_UNLOCK (debug_objects);
- }
-#endif /* G_ENABLE_DEBUG */
-}
-
-static void
g_object_dispatch_properties_changed (GObject *object,
guint n_pspecs,
GParamSpec **pspecs)
}
void
+g_object_run_dispose (GObject *object)
+{
+ g_return_if_fail (G_IS_OBJECT (object));
+ g_return_if_fail (object->ref_count > 0);
+
+ g_object_ref (object);
+ G_OBJECT_GET_CLASS (object)->dispose (object);
+ g_object_unref (object);
+}
+
+void
g_object_freeze_notify (GObject *object)
{
g_return_if_fail (G_IS_OBJECT (object));
return object;
}
-gpointer
+GObject*
g_object_new_valist (GType object_type,
const gchar *first_property_name,
va_list var_args)
g_object_unref (object);
}
-gpointer
+void
g_object_set (gpointer _object,
const gchar *first_property_name,
...)
GObject *object = _object;
va_list var_args;
- g_return_val_if_fail (G_IS_OBJECT (object), NULL);
+ g_return_if_fail (G_IS_OBJECT (object));
va_start (var_args, first_property_name);
g_object_set_valist (object, first_property_name, var_args);
va_end (var_args);
-
- return object;
}
void
}
else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
{
- g_warning ("can't retrive property `%s' of type `%s' as value of type `%s'",
+ g_warning ("can't retrieve property `%s' of type `%s' as value of type `%s'",
pspec->name,
g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
G_VALUE_TYPE_NAME (value));
va_start (var_args, signal_spec);
while (signal_spec)
{
- gpointer callback = va_arg (var_args, gpointer);
+ GCallback callback = va_arg (var_args, GCallback);
gpointer data = va_arg (var_args, gpointer);
- guint sid;
+ gulong sid;
if (strncmp (signal_spec, "signal::", 8) == 0)
sid = g_signal_connect_data (object, signal_spec + 8,
callback, data, NULL,
0);
+ else if (strncmp (signal_spec, "object_signal::", 15) == 0)
+ sid = g_signal_connect_object (object, signal_spec + 15,
+ callback, data,
+ 0);
else if (strncmp (signal_spec, "swapped_signal::", 16) == 0)
sid = g_signal_connect_data (object, signal_spec + 16,
callback, data, NULL,
G_CONNECT_SWAPPED);
+ else if (strncmp (signal_spec, "swapped_object_signal::", 23) == 0)
+ sid = g_signal_connect_object (object, signal_spec + 23,
+ callback, data,
+ G_CONNECT_SWAPPED);
else if (strncmp (signal_spec, "signal_after::", 14) == 0)
sid = g_signal_connect_data (object, signal_spec + 14,
callback, data, NULL,
G_CONNECT_AFTER);
+ else if (strncmp (signal_spec, "object_signal_after::", 21) == 0)
+ sid = g_signal_connect_object (object, signal_spec + 21,
+ callback, data,
+ G_CONNECT_AFTER);
else if (strncmp (signal_spec, "swapped_signal_after::", 22) == 0)
sid = g_signal_connect_data (object, signal_spec + 22,
callback, data, NULL,
G_CONNECT_SWAPPED | G_CONNECT_AFTER);
+ else if (strncmp (signal_spec, "swapped_object_signal_after::", 29) == 0)
+ sid = g_signal_connect_object (object, signal_spec + 29,
+ callback, data,
+ G_CONNECT_SWAPPED | G_CONNECT_AFTER);
else
{
g_warning ("%s: invalid signal spec \"%s\"", G_STRLOC, signal_spec);
return object;
}
-gpointer
+void
g_object_disconnect (gpointer _object,
const gchar *signal_spec,
...)
GObject *object = _object;
va_list var_args;
- g_return_val_if_fail (G_IS_OBJECT (object), NULL);
- g_return_val_if_fail (object->ref_count > 0, object);
+ g_return_if_fail (G_IS_OBJECT (object));
+ g_return_if_fail (object->ref_count > 0);
va_start (var_args, signal_spec);
while (signal_spec)
{
- gpointer callback = va_arg (var_args, gpointer);
+ GCallback callback = va_arg (var_args, GCallback);
gpointer data = va_arg (var_args, gpointer);
guint sid = 0, detail = 0, mask = 0;
g_warning ("%s: invalid signal name \"%s\"", G_STRLOC, signal_spec);
else if (!g_signal_handlers_disconnect_matched (object, mask | (detail ? G_SIGNAL_MATCH_DETAIL : 0),
sid, detail,
- NULL, callback, data))
+ NULL, (gpointer)callback, data))
g_warning (G_STRLOC ": signal handler %p(%p) is not connected", callback, data);
signal_spec = va_arg (var_args, gchar*);
}
va_end (var_args);
+}
- return object;
+typedef struct {
+ GObject *object;
+ guint n_weak_refs;
+ struct {
+ GWeakNotify notify;
+ gpointer data;
+ } weak_refs[1]; /* flexible array */
+} WeakRefStack;
+
+static void
+weak_refs_notify (gpointer data)
+{
+ WeakRefStack *wstack = data;
+ guint i;
+
+ for (i = 0; i < wstack->n_weak_refs; i++)
+ wstack->weak_refs[i].notify (wstack->weak_refs[i].data, wstack->object);
+ g_free (wstack);
+}
+
+void
+g_object_weak_ref (GObject *object,
+ GWeakNotify notify,
+ gpointer data)
+{
+ WeakRefStack *wstack;
+ guint i;
+
+ g_return_if_fail (G_IS_OBJECT (object));
+ g_return_if_fail (notify != NULL);
+ g_return_if_fail (object->ref_count >= 1);
+
+ wstack = g_datalist_id_remove_no_notify (&object->qdata, quark_weak_refs);
+ if (wstack)
+ {
+ i = wstack->n_weak_refs++;
+ wstack = g_realloc (wstack, sizeof (*wstack) + sizeof (wstack->weak_refs[0]) * i);
+ }
+ else
+ {
+ wstack = g_renew (WeakRefStack, NULL, 1);
+ wstack->object = object;
+ wstack->n_weak_refs = 1;
+ i = 0;
+ }
+ wstack->weak_refs[i].notify = notify;
+ wstack->weak_refs[i].data = data;
+ g_datalist_id_set_data_full (&object->qdata, quark_weak_refs, wstack, weak_refs_notify);
+}
+
+void
+g_object_weak_unref (GObject *object,
+ GWeakNotify notify,
+ gpointer data)
+{
+ WeakRefStack *wstack;
+ gboolean found_one = FALSE;
+
+ g_return_if_fail (G_IS_OBJECT (object));
+ g_return_if_fail (notify != NULL);
+
+ wstack = g_datalist_id_get_data (&object->qdata, quark_weak_refs);
+ if (wstack)
+ {
+ guint i;
+
+ for (i = 0; i < wstack->n_weak_refs; i++)
+ if (wstack->weak_refs[i].notify == notify &&
+ wstack->weak_refs[i].data == data)
+ {
+ found_one = TRUE;
+ wstack->n_weak_refs -= 1;
+ if (i != wstack->n_weak_refs)
+ {
+ wstack->weak_refs[i].notify = wstack->weak_refs[wstack->n_weak_refs].notify;
+ wstack->weak_refs[i].data = wstack->weak_refs[wstack->n_weak_refs].data;
+ }
+ break;
+ }
+ }
+ if (!found_one)
+ g_warning (G_STRLOC ": couldn't find weak ref %p(%p)", notify, data);
+}
+
+void
+g_object_add_weak_pointer (GObject *object,
+ gpointer *weak_pointer_location)
+{
+ g_return_if_fail (G_IS_OBJECT (object));
+ g_return_if_fail (weak_pointer_location != NULL);
+
+ g_object_weak_ref (object,
+ (GWeakNotify) g_nullify_pointer,
+ weak_pointer_location);
+}
+
+void
+g_object_remove_weak_pointer (GObject *object,
+ gpointer *weak_pointer_location)
+{
+ g_return_if_fail (G_IS_OBJECT (object));
+ g_return_if_fail (weak_pointer_location != NULL);
+
+ g_object_weak_unref (object,
+ (GWeakNotify) g_nullify_pointer,
+ weak_pointer_location);
}
gpointer
}
}
+void
+g_value_set_object_take_ownership (GValue *value,
+ gpointer v_object)
+{
+ g_return_if_fail (G_VALUE_HOLDS_OBJECT (value));
+
+ if (value->data[0].v_pointer)
+ {
+ g_object_unref (value->data[0].v_pointer);
+ value->data[0].v_pointer = NULL;
+ }
+
+ if (v_object)
+ {
+ g_return_if_fail (G_IS_OBJECT (v_object));
+ g_return_if_fail (g_value_type_compatible (G_OBJECT_TYPE (v_object), G_VALUE_TYPE (value)));
+
+ value->data[0].v_pointer = v_object; /* we take over the reference count */
+ }
+}
+
gpointer
g_value_get_object (const GValue *value)
{
return value->data[0].v_pointer ? g_object_ref (value->data[0].v_pointer) : NULL;
}
-guint
+gulong
g_signal_connect_object (gpointer instance,
const gchar *detailed_signal,
GCallback c_handler,
guint n_closures;
GClosure *closures[1]; /* flexible array */
} CArray;
+/* don't change this structure without supplying an accessor for
+ * watched closures, e.g.:
+ * GSList* g_object_list_watched_closures (GObject *object)
+ * {
+ * CArray *carray;
+ * g_return_val_if_fail (G_IS_OBJECT (object), NULL);
+ * carray = g_object_get_data (object, "GObject-closure-array");
+ * if (carray)
+ * {
+ * GSList *slist = NULL;
+ * guint i;
+ * for (i = 0; i < carray->n_closures; i++)
+ * slist = g_slist_prepend (slist, carray->closures[i]);
+ * return slist;
+ * }
+ * return NULL;
+ * }
+ */
static void
object_remove_closure (gpointer data,
GClosure *closure)
{
CArray *carray;
+ guint i;
g_return_if_fail (G_IS_OBJECT (object));
g_return_if_fail (closure != NULL);
g_closure_add_marshal_guards (closure,
object, (GClosureNotify) g_object_ref,
object, (GClosureNotify) g_object_unref);
- carray = g_object_steal_qdata (object, quark_closure_array);
+ carray = g_datalist_id_remove_no_notify (&object->qdata, quark_closure_array);
if (!carray)
{
carray = g_renew (CArray, NULL, 1);
carray->object = object;
carray->n_closures = 1;
- carray->closures[0] = closure;
- g_object_set_qdata_full (object, quark_closure_array, carray, destroy_closure_array);
+ i = 0;
}
else
{
- guint i = carray->n_closures++;
-
+ i = carray->n_closures++;
carray = g_realloc (carray, sizeof (*carray) + sizeof (carray->closures[0]) * i);
- carray->closures[i] = closure;
- g_object_set_qdata_full (object, quark_closure_array, carray, destroy_closure_array);
}
+ carray->closures[i] = closure;
+ g_datalist_id_set_data_full (&object->qdata, quark_closure_array, carray, destroy_closure_array);
}
GClosure*
GClosure*
g_cclosure_new_object (GCallback callback_func,
- gpointer _object)
+ GObject *object)
{
- GObject *object = _object;
GClosure *closure;
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
GClosure*
g_cclosure_new_object_swap (GCallback callback_func,
- gpointer _object)
+ GObject *object)
{
- GObject *object = _object;
GClosure *closure;
g_return_val_if_fail (G_IS_OBJECT (object), NULL);