Remove all docs from gobject at Tims request. Documentation is only for
[platform/upstream/glib.git] / gobject / gobject.c
index e3c9136..e9c39b9 100644 (file)
@@ -28,6 +28,7 @@
 #include       "gvaluetypes.h"
 #include       "gobjectnotifyqueue.c"
 #include       <string.h>
+#include       <signal.h>
 
 
 #define        PREALLOC_CPARAMS        (8)
@@ -40,7 +41,6 @@
 
 /* --- signals --- */
 enum {
-  PROPERTIES_CHANGED,
   NOTIFY,
   LAST_SIGNAL
 };
@@ -61,7 +61,7 @@ static GObject*       g_object_constructor                    (GType                  type,
                                                         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,
@@ -98,11 +98,9 @@ static inline void      object_set_property          (GObject        *object,
                                                         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, };
@@ -133,11 +131,8 @@ debug_objects_atexit (void)
   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);
     }
 }
@@ -186,7 +181,10 @@ g_object_type_init (void)  /* sync with gtype.c */
   
 #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 */
 }
 
@@ -206,8 +204,6 @@ g_object_base_class_finalize (GObjectClass *class)
 {
   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);
@@ -235,7 +231,10 @@ g_object_notify_dispatcher (GObject     *object,
 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;
@@ -243,20 +242,20 @@ g_object_do_class_init (GObjectClass *class)
   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
@@ -344,8 +343,6 @@ g_object_init (GObject *object)
   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);
@@ -382,12 +379,46 @@ g_object_do_get_property (GObject     *object,
 }
 
 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)
@@ -399,14 +430,14 @@ g_object_last_unref (GObject *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 */
@@ -415,33 +446,6 @@ g_object_last_unref (GObject *object)
 }
 
 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)
@@ -453,6 +457,17 @@ g_object_dispatch_properties_changed (GObject     *object,
 }
 
 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));
@@ -702,7 +717,7 @@ g_object_newv (GType       object_type,
   return object;
 }
 
-gpointer
+GObject*
 g_object_new_valist (GType       object_type,
                     const gchar *first_property_name,
                     va_list      var_args)
@@ -931,7 +946,7 @@ g_object_get_valist (GObject         *object,
   g_object_unref (object);
 }
 
-gpointer
+void
 g_object_set (gpointer     _object,
              const gchar *first_property_name,
              ...)
@@ -939,13 +954,11 @@ g_object_set (gpointer     _object,
   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
@@ -1029,7 +1042,7 @@ g_object_get_property (GObject       *object,
        }
       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));
@@ -1066,26 +1079,42 @@ g_object_connect (gpointer     _object,
   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);
@@ -1098,7 +1127,7 @@ g_object_connect (gpointer     _object,
   return object;
 }
 
-gpointer
+void
 g_object_disconnect (gpointer     _object,
                     const gchar *signal_spec,
                     ...)
@@ -1106,13 +1135,13 @@ g_object_disconnect (gpointer     _object,
   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;
 
@@ -1137,13 +1166,119 @@ g_object_disconnect (gpointer     _object,
        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
@@ -1391,6 +1526,27 @@ g_value_set_object (GValue   *value,
     }
 }
 
+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)
 {
@@ -1407,7 +1563,7 @@ g_value_dup_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,
@@ -1437,6 +1593,24 @@ typedef struct {
   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,
@@ -1482,6 +1656,7 @@ g_object_watch_closure (GObject  *object,
                        GClosure *closure)
 {
   CArray *carray;
+  guint i;
   
   g_return_if_fail (G_IS_OBJECT (object));
   g_return_if_fail (closure != NULL);
@@ -1493,23 +1668,21 @@ g_object_watch_closure (GObject  *object,
   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*
@@ -1529,9 +1702,8 @@ g_closure_new_object (guint    sizeof_closure,
 
 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);
@@ -1546,9 +1718,8 @@ g_cclosure_new_object (GCallback callback_func,
 
 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);