fixed dealing with collection/lcopy of NULL values.
[platform/upstream/glib.git] / gobject / gobject.c
1 /* GObject - GLib Type, Object, Parameter and Signal Library
2  * Copyright (C) 1998, 1999, 2000 Tim Janik and Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General
15  * Public License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include        "gobject.h"
20
21
22 #include        "gvaluecollector.h"
23 #include        "gsignal.h"
24 #include        "gparamspecs.h"
25 #include        "gvaluetypes.h"
26 #include        <string.h>
27
28
29 #define PREALLOC_CPARAMS        (8)
30 #define DEBUG_OBJECTS
31
32
33 /* --- macros --- */
34 #define PARAM_SPEC_PARAM_ID(pspec)      (GPOINTER_TO_UINT (g_param_spec_get_qdata ((pspec), quark_property_id)))
35
36
37 /* --- signals --- */
38 enum {
39   PROPERTIES_CHANGED,
40   NOTIFY,
41   LAST_SIGNAL
42 };
43
44
45 /* --- properties --- */
46 enum {
47   PROP_NONE,
48   PROP_DATA,
49   PROP_SIGNAL,
50   PROP_SWAPPED_SIGNAL,
51   PROP_SIGNAL_AFTER,
52   PROP_SWAPPED_SIGNAL_AFTER
53 };
54
55
56 /* --- typedefs --- */
57 typedef struct _NotifyQueue NotifyQueue;
58
59
60 /* --- prototypes --- */
61 static void     g_object_base_class_init                (GObjectClass   *class);
62 static void     g_object_base_class_finalize            (GObjectClass   *class);
63 static void     g_object_do_class_init                  (GObjectClass   *class);
64 static void     g_object_init                           (GObject        *object);
65 static GObject* g_object_constructor                    (GType                  type,
66                                                          guint                  n_construct_properties,
67                                                          GObjectConstructParam *construct_params);
68 static void     g_object_last_unref                     (GObject        *object);
69 static void     g_object_shutdown                       (GObject        *object);
70 static void     g_object_finalize                       (GObject        *object);
71 static void     g_object_do_set_property                (GObject        *object,
72                                                          guint           property_id,
73                                                          const GValue   *value,
74                                                          GParamSpec     *pspec,
75                                                          const gchar    *trailer);
76 static void     g_object_do_get_property                (GObject        *object,
77                                                          guint           property_id,
78                                                          GValue         *value,
79                                                          GParamSpec     *pspec,
80                                                          const gchar    *trailer);
81 static void     g_value_object_init                     (GValue         *value);
82 static void     g_value_object_free_value               (GValue         *value);
83 static void     g_value_object_copy_value               (const GValue   *src_value,
84                                                          GValue         *dest_value);
85 static gpointer g_value_object_peek_pointer             (const GValue   *value);
86 static gchar*   g_value_object_collect_value            (GValue         *value,
87                                                          guint           nth_value,
88                                                          GType          *collect_type,
89                                                          GTypeCValue    *collect_value);
90 static gchar*   g_value_object_lcopy_value              (const GValue   *value,
91                                                          guint           nth_value,
92                                                          GType          *collect_type,
93                                                          GTypeCValue    *collect_value);
94 static void     g_object_dispatch_properties_changed    (GObject        *object,
95                                                          guint           n_pspecs,
96                                                          GParamSpec    **pspecs);
97 static void     g_object_properties_changed             (GObject        *object,
98                                                          guint           n_pspecs,
99                                                          GParamSpec    **pspecs);
100 static void     g_object_notify_property_changed        (GObject        *object,
101                                                          GParamSpec     *pspec);
102 static inline NotifyQueue* object_freeze_notifies       (GObject        *object);
103 static inline void         object_queue_property        (GObject        *object,
104                                                          GParamSpec     *pspec,
105                                                          NotifyQueue    *nqueue);
106 static inline void         object_thaw_notifies         (GObject        *object,
107                                                          NotifyQueue    *nqueue);
108 static inline void         object_get_property          (GObject        *object,
109                                                          GValue         *value,
110                                                          GParamSpec     *pspec,
111                                                          const gchar    *trailer);
112 static inline void         object_set_property          (GObject        *object,
113                                                          GValue         *value,
114                                                          GParamSpec     *pspec,
115                                                          const gchar    *trailer,
116                                                          NotifyQueue    *nqueue);
117
118
119 /* --- structures --- */
120 struct _NotifyQueue
121 {
122   GSList *pspecs;
123   guint   n_pspecs;
124   guint   freeze_count;
125 };
126
127
128 /* --- variables --- */
129 static GQuark            quark_notify_queue = 0;
130 static GQuark            quark_property_id = 0;
131 static GQuark            quark_closure_array = 0;
132 static GHashTable       *pspec_hash_table = NULL;
133 static gulong            gobject_signals[LAST_SIGNAL] = { 0, };
134
135
136 /* --- functions --- */
137 #ifdef  DEBUG_OBJECTS
138
139 /* We need an actual method for handling debug keys in GLib.
140  * For now, we'll simply use, as a method
141  * 'extern gboolean glib_debug_objects'
142  */
143 gboolean glib_debug_objects = FALSE;
144
145 static guint              debug_objects_count = 0;
146 static GHashTable        *debug_objects_ht = NULL;
147 static void
148 debug_objects_foreach (gpointer key,
149                        gpointer value,
150                        gpointer user_data)
151 {
152   GObject *object = value;
153   
154   g_message ("[%p] stale %s\tref_count=%u",
155              object,
156              G_OBJECT_TYPE_NAME (object),
157              object->ref_count);
158 }
159 static void
160 debug_objects_atexit (void)
161 {
162   if (glib_debug_objects)
163     {
164       if (debug_objects_ht)
165         {
166           g_message ("stale GObjects: %u", debug_objects_count);
167           g_hash_table_foreach (debug_objects_ht, debug_objects_foreach, NULL);
168         }
169     }
170 }
171 #endif /* DEBUG_OBJECTS */
172
173 void
174 g_object_type_init (void)       /* sync with gtype.c */
175 {
176   static gboolean initialized = FALSE;
177   static const GTypeFundamentalInfo finfo = {
178     G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE,
179   };
180   static GTypeInfo info = {
181     sizeof (GObjectClass),
182     (GBaseInitFunc) g_object_base_class_init,
183     (GBaseFinalizeFunc) g_object_base_class_finalize,
184     (GClassInitFunc) g_object_do_class_init,
185     NULL        /* class_destroy */,
186     NULL        /* class_data */,
187     sizeof (GObject),
188     0           /* n_preallocs */,
189     (GInstanceInitFunc) g_object_init,
190     NULL,       /* value_table */
191   };
192   static const GTypeValueTable value_table = {
193     g_value_object_init,          /* value_init */
194     g_value_object_free_value,    /* value_free */
195     g_value_object_copy_value,    /* value_copy */
196     g_value_object_peek_pointer,  /* value_peek_pointer */
197     G_VALUE_COLLECT_POINTER,      /* collect_type */
198     g_value_object_collect_value, /* collect_value */
199     G_VALUE_COLLECT_POINTER,      /* lcopy_type */
200     g_value_object_lcopy_value,   /* lcopy_value */
201   };
202   GType type;
203   
204   g_return_if_fail (initialized == FALSE);
205   initialized = TRUE;
206   
207   /* G_TYPE_OBJECT
208    */
209   info.value_table = &value_table;
210   type = g_type_register_fundamental (G_TYPE_OBJECT, "GObject", &info, &finfo, 0);
211   g_assert (type == G_TYPE_OBJECT);
212   
213 #ifdef  DEBUG_OBJECTS
214   g_atexit (debug_objects_atexit);
215 #endif /* DEBUG_OBJECTS */
216 }
217
218 static void
219 g_object_base_class_init (GObjectClass *class)
220 {
221   /* reset instance specific fields and methods that don't get inherited */
222   class->n_property_specs = 0;
223   class->property_specs = NULL;
224   class->get_property = NULL;
225   class->set_property = NULL;
226 }
227
228 static void
229 g_object_base_class_finalize (GObjectClass *class)
230 {
231   guint i;
232   
233   g_message ("finallizing base class of %s", G_OBJECT_CLASS_NAME (class));
234
235   _g_signals_destroy (G_OBJECT_CLASS_TYPE (class));
236   
237   for (i = 0; i < class->n_property_specs; i++)
238     {
239       GParamSpec *pspec = class->property_specs[i];
240       
241       g_param_spec_hash_table_remove (pspec_hash_table, pspec);
242       g_param_spec_set_qdata (pspec, quark_property_id, NULL);
243       g_param_spec_unref (pspec);
244     }
245   class->n_property_specs = 0;
246   g_free (class->property_specs);
247   class->property_specs = NULL;
248 }
249
250 static void
251 g_object_do_class_init (GObjectClass *class)
252 {
253   quark_notify_queue = g_quark_from_static_string ("GObject-notify-queue");
254   quark_property_id = g_quark_from_static_string ("GObject-property-id");
255   quark_closure_array = g_quark_from_static_string ("GObject-closure-array");
256   pspec_hash_table = g_param_spec_hash_table_new ();
257   
258   class->constructor = g_object_constructor;
259   class->set_property = g_object_do_set_property;
260   class->get_property = g_object_do_get_property;
261   class->shutdown = g_object_shutdown;
262   class->finalize = g_object_finalize;
263   class->dispatch_properties_changed = g_object_dispatch_properties_changed;
264   class->properties_changed = g_object_properties_changed;
265   class->notify = g_object_notify_property_changed;
266
267   g_object_class_install_property (class,
268                                    PROP_DATA,
269                                    g_param_spec_pointer ("data", "Named Data",
270                                                          "Named anonymous pointers",
271                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
272   g_object_class_install_property (class,
273                                    PROP_SIGNAL,
274                                    g_param_spec_ccallback ("signal", "Signal Connection",
275                                                            "Signal connection consisting of a callback function "
276                                                            "and a data pointer",
277                                                            G_PARAM_WRITABLE));
278   g_object_class_install_property (class,
279                                    PROP_SWAPPED_SIGNAL,
280                                    g_param_spec_ccallback ("swapped_signal", "Swapped Signal Connection",
281                                                            "Signal connection consisting of a callback function "
282                                                            "and a data pointer",
283                                                            G_PARAM_WRITABLE));
284   g_object_class_install_property (class,
285                                    PROP_SIGNAL_AFTER,
286                                    g_param_spec_ccallback ("signal_after", "Signal After Connection",
287                                                            "Signal connection consisting of a callback function "
288                                                            "and a data pointer",
289                                                            G_PARAM_WRITABLE));
290   g_object_class_install_property (class,
291                                    PROP_SWAPPED_SIGNAL_AFTER,
292                                    g_param_spec_ccallback ("swapped_signal_after", "Swapped Signal After Connection",
293                                                            "Signal connection consisting of a callback function "
294                                                            "and a data pointer",
295                                                            G_PARAM_WRITABLE));
296   gobject_signals[PROPERTIES_CHANGED] =
297     g_signal_new ("properties_changed",
298                   G_TYPE_FROM_CLASS (class),
299                   G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
300                   g_signal_type_cclosure_new (G_TYPE_FROM_CLASS (class),
301                                               G_STRUCT_OFFSET (GObjectClass, properties_changed)),
302                   NULL, /* accumulator */
303                   g_cclosure_marshal_VOID__UINT_POINTER,
304                   G_TYPE_NONE,
305                   2, G_TYPE_UINT, G_TYPE_POINTER);
306   gobject_signals[NOTIFY] =
307     g_signal_new ("notify",
308                   G_TYPE_FROM_CLASS (class),
309                   G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS,
310                   g_signal_type_cclosure_new (G_TYPE_FROM_CLASS (class),
311                                               G_STRUCT_OFFSET (GObjectClass, notify)),
312                   NULL, /* accumulator */
313                   g_cclosure_marshal_VOID__PARAM,
314                   G_TYPE_NONE,
315                   1, G_TYPE_PARAM);
316 }
317
318 void
319 g_object_class_install_property (GObjectClass *class,
320                                  guint         property_id,
321                                  GParamSpec   *pspec)
322 {
323   guint i;
324   
325   g_return_if_fail (G_IS_OBJECT_CLASS (class));
326   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
327   if (pspec->flags & G_PARAM_WRITABLE)
328     g_return_if_fail (class->set_property != NULL);
329   if (pspec->flags & G_PARAM_READABLE)
330     g_return_if_fail (class->get_property != NULL);
331   g_return_if_fail (property_id > 0);
332   g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0);  /* paranoid */
333   if (pspec->flags & G_PARAM_CONSTRUCT)
334     g_return_if_fail ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
335   if (pspec->flags & (G_PARAM_CONSTRUCT || G_PARAM_CONSTRUCT_ONLY))
336     g_return_if_fail (pspec->flags & G_PARAM_WRITABLE);
337
338   /* expensive paranoia checks ;( */
339   for (i = 0; i < class->n_property_specs; i++)
340     if (PARAM_SPEC_PARAM_ID (class->property_specs[i]) == property_id)
341       {
342         g_warning (G_STRLOC ": class `%s' already contains a property `%s' with id %u, "
343                    "cannot install property `%s'",
344                    G_OBJECT_CLASS_NAME (class),
345                    class->property_specs[i]->name,
346                    property_id,
347                    pspec->name);
348         return;
349       }
350   if (g_object_class_find_property (class, pspec->name))
351     {
352       g_warning (G_STRLOC ": class `%s' already contains a property named `%s'",
353                  G_OBJECT_CLASS_NAME (class),
354                  pspec->name);
355       return;
356     }
357
358   g_param_spec_ref (pspec);
359   g_param_spec_sink (pspec);
360   g_param_spec_set_qdata (pspec, quark_property_id, GUINT_TO_POINTER (property_id));
361   g_param_spec_hash_table_insert (pspec_hash_table, pspec, G_OBJECT_CLASS_TYPE (class));
362   i = class->n_property_specs++;
363   class->property_specs = g_renew (GParamSpec*, class->property_specs, class->n_property_specs);
364   class->property_specs[i] = pspec;
365 }
366
367 GParamSpec*
368 g_object_class_find_property (GObjectClass *class,
369                               const gchar  *property_name)
370 {
371   g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL);
372   g_return_val_if_fail (property_name != NULL, NULL);
373   
374   return g_param_spec_hash_table_lookup (pspec_hash_table,
375                                          property_name,
376                                          G_OBJECT_CLASS_TYPE (class),
377                                          TRUE, NULL);
378 }
379
380 static void
381 free_notify_queue (gpointer data)
382 {
383   NotifyQueue *nqueue = data;
384   
385   g_slist_free (nqueue->pspecs);
386   g_free (nqueue);
387 }
388
389 static inline NotifyQueue*
390 object_freeze_notifies (GObject *object)
391 {
392   NotifyQueue *nqueue;
393
394   nqueue = g_object_get_qdata (object, quark_notify_queue);
395   if (!nqueue)
396     {
397       nqueue = g_new0 (NotifyQueue, 1);
398       g_object_set_qdata_full (object, quark_notify_queue, nqueue, free_notify_queue);
399     }
400   nqueue->freeze_count++;
401
402   return nqueue;
403 }
404
405 static inline void
406 object_queue_property (GObject     *object,
407                        GParamSpec  *pspec,
408                        NotifyQueue *nqueue)
409 {
410   /* we will dedup later */
411   nqueue->pspecs = g_slist_prepend (nqueue->pspecs, pspec);
412   nqueue->n_pspecs++;
413 }
414
415 static void
416 g_object_init (GObject *object)
417 {
418   object->ref_count = 1;
419   object->qdata = NULL;
420   
421   /* freeze object's notification queue, g_object_new_valist() takes care of that */
422   object_freeze_notifies (object);
423
424 #ifdef  DEBUG_OBJECTS
425   if (glib_debug_objects)
426     {
427       if (!debug_objects_ht)
428         debug_objects_ht = g_hash_table_new (g_direct_hash, NULL);
429       debug_objects_count++;
430       g_hash_table_insert (debug_objects_ht, object, object);
431     }
432 #endif /* DEBUG_OBJECTS */
433 }
434
435 static void
436 g_object_do_set_property (GObject      *object,
437                           guint         property_id,
438                           const GValue *value,
439                           GParamSpec   *pspec,
440                           const gchar  *trailer)
441 {
442   guint i = 0;
443   
444   switch (property_id)
445     {
446       gboolean swapped, after;
447       gpointer callback, data;
448     case PROP_DATA:
449       g_return_if_fail (trailer[0] == ':' && trailer[1] == ':');
450
451       g_object_set_data (object, trailer + 2, g_value_get_pointer (value));
452       break;
453     case PROP_SWAPPED_SIGNAL_AFTER:
454       i++;
455     case PROP_SIGNAL_AFTER:
456       i++;
457     case PROP_SWAPPED_SIGNAL:
458       i++;
459     case PROP_SIGNAL:
460       after = i > 2;
461       swapped = i & 1;
462       g_return_if_fail (trailer[0] == ':' && trailer[1] == ':');
463
464       g_value_get_ccallback (value, &callback, &data);
465       g_signal_connect_data (object, trailer + 2,
466                              callback, data, NULL,
467                              swapped, after);
468       break;
469     default:
470       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
471       break;
472     }
473 }
474
475 static void
476 g_object_do_get_property (GObject     *object,
477                           guint        property_id,
478                           GValue      *value,
479                           GParamSpec  *pspec,
480                           const gchar *trailer)
481 {
482   switch (property_id)
483     {
484     case PROP_DATA:
485       g_return_if_fail (trailer[0] == ':' && trailer[1] == ':');
486
487       g_value_set_pointer (value, g_object_get_data (object, trailer + 2));
488       break;
489     default:
490       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
491       break;
492     }
493 }
494
495 static void
496 g_object_last_unref (GObject *object)
497 {
498   g_return_if_fail (object->ref_count > 0);
499   
500   if (object->ref_count == 1)   /* may have been re-referenced meanwhile */
501     G_OBJECT_GET_CLASS (object)->shutdown (object);
502   
503   object->ref_count -= 1;
504   
505   if (object->ref_count == 0)   /* may have been re-referenced meanwhile */
506     {
507       G_OBJECT_GET_CLASS (object)->finalize (object);
508 #ifdef  DEBUG_OBJECTS
509       if (glib_debug_objects && debug_objects_ht)
510         g_assert (g_hash_table_lookup (debug_objects_ht, object) == NULL);
511 #endif /* DEBUG_OBJECTS */
512       g_type_free_instance ((GTypeInstance*) object);
513     }
514 }
515
516 static void
517 g_object_shutdown (GObject *object)
518 {
519   /* this function needs to be always present for unconditional
520    * chaining, we also might add some code here later.
521    * beware though, subclasses may invoke shutdown() arbitrarily.
522    */
523 }
524
525 static void
526 g_object_finalize (GObject *object)
527 {
528   g_signal_handlers_destroy (object);
529   g_datalist_clear (&object->qdata);
530   
531 #ifdef  DEBUG_OBJECTS
532   if (glib_debug_objects)
533     {
534       g_assert (g_hash_table_lookup (debug_objects_ht, object) == object);
535       
536       g_hash_table_remove (debug_objects_ht, object);
537       debug_objects_count--;
538     }
539 #endif /* DEBUG_OBJECTS */
540 }
541
542 static inline void
543 object_thaw_notifies (GObject     *object,
544                       NotifyQueue *nqueue)
545 {
546   GParamSpec **pspecs;
547   GSList *slist;
548   guint n_pspecs = 0;
549   
550   nqueue->freeze_count--;
551   if (nqueue->freeze_count)
552     return;
553   g_return_if_fail (object->ref_count > 0);
554   
555   pspecs = g_new (GParamSpec*, nqueue->n_pspecs);
556   for (slist = nqueue->pspecs; slist; slist = slist->next)
557     {
558       GParamSpec *pspec = slist->data;
559       gint i = 0;
560       
561       /* dedup, make pspecs in the list unique */
562     redo_dedup_check:
563       if (pspecs[i] == pspec)
564         continue;
565       if (++i < n_pspecs)
566         goto redo_dedup_check;
567       
568       pspecs[n_pspecs++] = pspec;
569     }
570   g_object_set_qdata (object, quark_notify_queue, NULL);
571   
572   if (n_pspecs)
573     G_OBJECT_GET_CLASS (object)->dispatch_properties_changed (object, n_pspecs, pspecs);
574   
575   g_free (pspecs);
576 }
577
578 static void
579 g_object_dispatch_properties_changed (GObject     *object,
580                                       guint        n_pspecs,
581                                       GParamSpec **pspecs)
582 {
583   g_signal_emit (object, gobject_signals[PROPERTIES_CHANGED], 0, n_pspecs, pspecs);
584 }
585
586 static void
587 g_object_properties_changed (GObject     *object,
588                              guint        n_pspecs,
589                              GParamSpec **pspecs)
590 {
591   guint i;
592
593   for (i = 0; i < n_pspecs; i++)
594     g_signal_emit (object, gobject_signals[NOTIFY], g_quark_from_string (pspecs[i]->name), pspecs[i]);
595 }
596
597 static void
598 g_object_notify_property_changed (GObject    *object,
599                                   GParamSpec *pspec)
600 {
601   g_message ("NOTIFICATION: %s property changed on object `%s'",
602              pspec->name,
603              G_OBJECT_TYPE_NAME (object));
604 }
605
606 void
607 g_object_freeze_notify (GObject *object)
608 {
609   g_return_if_fail (G_IS_OBJECT (object));
610   if (!object->ref_count)
611     return;
612
613   g_object_ref (object);
614   object_freeze_notifies (object);
615   g_object_unref (object);
616 }
617
618 void
619 g_object_notify (GObject     *object,
620                  const gchar *property_name)
621 {
622   GParamSpec *pspec;
623   
624   g_return_if_fail (G_IS_OBJECT (object));
625   g_return_if_fail (property_name != NULL);
626   if (!object->ref_count)
627     return;
628   
629   g_object_ref (object);
630   pspec = g_param_spec_hash_table_lookup (pspec_hash_table,
631                                           property_name,
632                                           G_OBJECT_TYPE (object),
633                                           TRUE, NULL);
634   if (!pspec)
635     g_warning ("%s: object class `%s' has no property named `%s'",
636                G_STRLOC,
637                G_OBJECT_TYPE_NAME (object),
638                property_name);
639   else
640     {
641       NotifyQueue *nqueue = object_freeze_notifies (object);
642
643       object_queue_property (object, pspec, nqueue);
644       object_thaw_notifies (object, nqueue);
645     }
646   g_object_unref (object);
647 }
648
649 void
650 g_object_thaw_notify (GObject *object)
651 {
652   NotifyQueue *nqueue;
653   
654   g_return_if_fail (G_IS_OBJECT (object));
655   if (!object->ref_count)
656     return;
657   
658   g_object_ref (object);
659   nqueue = g_object_get_qdata (object, quark_notify_queue);
660   if (!nqueue || !nqueue->freeze_count)
661     g_warning (G_STRLOC ": property-changed notification for %s(%p) is not frozen",
662                G_OBJECT_TYPE_NAME (object), object);
663   else
664     object_thaw_notifies (object, nqueue);
665   g_object_unref (object);
666 }
667
668 static inline void
669 object_get_property (GObject     *object,
670                      GValue      *value,
671                      GParamSpec  *pspec,
672                      const gchar *trailer)
673 {
674   GObjectClass *class;
675   
676   g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (object), pspec->owner_type));   /* paranoid */
677   
678   class = g_type_class_peek (pspec->owner_type);
679   
680   class->get_property (object, PARAM_SPEC_PARAM_ID (pspec), value, pspec, trailer);
681 }
682
683 static inline void
684 object_set_property (GObject     *object,
685                      GValue      *value,
686                      GParamSpec  *pspec,
687                      const gchar *trailer,
688                      NotifyQueue *nqueue)
689 {
690   GObjectClass *class;
691   
692   g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (object), pspec->owner_type));   /* paranoid */
693   
694   class = g_type_class_peek (pspec->owner_type);
695   
696   class->set_property (object, PARAM_SPEC_PARAM_ID (pspec), value, pspec, trailer);
697   object_queue_property (object, pspec, nqueue);
698 }
699
700 gpointer
701 g_object_new (GType        object_type,
702               const gchar *first_property_name,
703               ...)
704 {
705   GObject *object;
706   va_list var_args;
707   
708   g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL);
709   
710   va_start (var_args, first_property_name);
711   object = g_object_new_valist (object_type, first_property_name, var_args);
712   va_end (var_args);
713   
714   return object;
715 }
716
717 gpointer
718 g_object_new_valist (GType        object_type,
719                      const gchar *first_property_name,
720                      va_list      var_args)
721 {
722   NotifyQueue *nqueue;
723   GObject *object;
724   GObjectClass *class;
725   const gchar *name;
726   GObjectConstructParam *cparams = NULL, *nparams = NULL;
727   guint n_cparams = 0, n_nparams = 0;
728   
729   g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL);
730
731   /* collect parameters, sort into construction and normal ones */
732   name = first_property_name;
733   while (name)
734     {
735       const gchar *trailer = NULL;
736       GValue *value;
737       GParamSpec *pspec;
738       gchar *error = NULL;
739
740       pspec = g_param_spec_hash_table_lookup (pspec_hash_table,
741                                               name,
742                                               object_type,
743                                               TRUE,
744                                               &trailer);
745       if (!pspec)
746         {
747           g_warning ("%s: object class `%s' has no property named `%s'",
748                      G_STRLOC,
749                      g_type_name (object_type),
750                      name);
751           break;
752         }
753       if (!(pspec->flags & G_PARAM_WRITABLE))
754         {
755           g_warning ("%s: property `%s' of object class `%s' is not writable",
756                      G_STRLOC,
757                      pspec->name,
758                      g_type_name (object_type));
759           break;
760         }
761
762       value = g_new (GValue, 1);
763       value->g_type = 0;
764       g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
765       G_VALUE_COLLECT (value, var_args, &error);
766       if (error)
767         {
768           g_warning ("%s: %s", G_STRLOC, error);
769           g_free (error);
770
771           /* we purposely leak the value here, it might not be
772            * in a sane state if an error condition occoured
773            */
774           break;
775         }
776       if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))
777         {
778           if (!n_cparams || n_cparams >= PREALLOC_CPARAMS)
779             cparams = g_renew (GObjectConstructParam, cparams, n_cparams + 1);
780           cparams[n_cparams].pspec = pspec;
781           cparams[n_cparams].value = value;
782           cparams[n_cparams].trailer = trailer;
783           n_cparams++;
784         }
785       else
786         {
787           if (!n_nparams || n_nparams >= PREALLOC_CPARAMS)
788             nparams = g_renew (GObjectConstructParam, nparams, n_nparams + 1);
789           nparams[n_nparams].pspec = pspec;
790           nparams[n_nparams].value = value;
791           nparams[n_nparams].trailer = trailer;
792           n_nparams++;
793         }
794
795       name = va_arg (var_args, gchar*);
796     }
797
798   /* construct object from construction parameters */
799   class = g_type_class_ref (object_type);
800   object = class->constructor (object_type, n_cparams, cparams);
801   g_type_class_unref (class);
802
803   /* free construction values */
804   while (n_cparams--)
805     {
806       g_value_unset (cparams[n_cparams].value);
807       g_free (cparams[n_cparams].value);
808     }
809   g_free (cparams);
810
811   /* release g_object_init() notification queue freeze_count */
812   nqueue = object_freeze_notifies (object);
813   nqueue->freeze_count--;
814   
815   /* set remaining properties */
816   while (n_nparams--)
817     {
818       GValue *value = nparams[n_nparams].value;
819       GParamSpec *pspec = nparams[n_nparams].pspec;
820       const gchar *trailer = nparams[n_nparams].trailer;
821
822       /* convert if necessary */
823       if (!g_type_is_a (G_VALUE_TYPE (value), G_PARAM_SPEC_VALUE_TYPE (pspec)))
824         {
825           GValue tmp_value = { 0, };
826
827           g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
828           if (!g_value_convert (value, &tmp_value) ||
829               g_param_value_validate (pspec, &tmp_value))
830             g_warning ("%s: cannot convert `%s' value to property `%s' value of type `%s'",
831                        G_STRLOC,
832                        G_VALUE_TYPE_NAME (value),
833                        pspec->name,
834                        g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
835           else
836             object_set_property (object, &tmp_value, pspec, trailer, nqueue);
837           g_value_unset (&tmp_value);
838         }
839       else
840         object_set_property (object, value, pspec, trailer, nqueue);
841       
842       g_value_unset (value);
843       g_free (value);
844     }
845   g_free (nparams);
846
847   /* release our own freeze count and handle notifications */
848   object_thaw_notifies (object, nqueue);
849   
850   return object;
851 }
852
853 static GObject*
854 g_object_constructor (GType                  type,
855                       guint                  n_construct_properties,
856                       GObjectConstructParam *construct_params)
857 {
858   GObject *object;
859
860   /* create object */
861   object = (GObject*) g_type_create_instance (type);
862
863   /* set construction parameters */
864   if (n_construct_properties)
865     {
866       NotifyQueue *nqueue = object_freeze_notifies (object);
867       
868       /* set construct properties */
869       while (n_construct_properties--)
870         {
871           GValue *value = construct_params[n_construct_properties].value;
872           GParamSpec *pspec = construct_params[n_construct_properties].pspec;
873           const gchar *trailer = construct_params[n_construct_properties].trailer;
874           
875           /* convert if necessary */
876           if (!g_type_is_a (G_VALUE_TYPE (value), G_PARAM_SPEC_VALUE_TYPE (pspec)))
877             {
878               GValue tmp_value = { 0, };
879               
880               g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
881               if (!g_value_convert (value, &tmp_value) ||
882                   g_param_value_validate (pspec, &tmp_value))
883                 g_warning ("%s: cannot convert `%s' value to property `%s' value of type `%s'",
884                            G_STRLOC,
885                            G_VALUE_TYPE_NAME (value),
886                            pspec->name,
887                            g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
888               else
889                 object_set_property (object, &tmp_value, pspec, trailer, nqueue);
890               g_value_unset (&tmp_value);
891             }
892           else
893             object_set_property (object, value, pspec, trailer, nqueue);
894         }
895       nqueue->freeze_count--;
896       /* the notification queue is still frozen from g_object_init(), so
897        * we don't need to handle it here, g_object_new_valist() takes
898        * care of that
899        */
900     }
901
902   return object;
903 }
904
905 void
906 g_object_set_valist (GObject     *object,
907                      const gchar *first_property_name,
908                      va_list      var_args)
909 {
910   NotifyQueue *nqueue;
911   const gchar *name;
912   
913   g_return_if_fail (G_IS_OBJECT (object));
914   
915   g_object_ref (object);
916   nqueue = object_freeze_notifies (object);
917   
918   name = first_property_name;
919   while (name)
920     {
921       const gchar *trailer = NULL;
922       GValue value = { 0, };
923       GParamSpec *pspec;
924       gchar *error = NULL;
925       
926       pspec = g_param_spec_hash_table_lookup (pspec_hash_table,
927                                               name,
928                                               G_OBJECT_TYPE (object),
929                                               TRUE,
930                                               &trailer);
931       if (!pspec)
932         {
933           g_warning ("%s: object class `%s' has no property named `%s'",
934                      G_STRLOC,
935                      G_OBJECT_TYPE_NAME (object),
936                      name);
937           break;
938         }
939       if (!(pspec->flags & G_PARAM_WRITABLE))
940         {
941           g_warning ("%s: property `%s' of object class `%s' is not writable",
942                      G_STRLOC,
943                      pspec->name,
944                      G_OBJECT_TYPE_NAME (object));
945           break;
946         }
947       
948       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
949       
950       G_VALUE_COLLECT (&value, var_args, &error);
951       if (error)
952         {
953           g_warning ("%s: %s", G_STRLOC, error);
954           g_free (error);
955           
956           /* we purposely leak the value here, it might not be
957            * in a sane state if an error condition occoured
958            */
959           break;
960         }
961       
962       object_set_property (object, &value, pspec, trailer, nqueue);
963       
964       g_value_unset (&value);
965       
966       name = va_arg (var_args, gchar*);
967     }
968
969   object_thaw_notifies (object, nqueue);
970   g_object_unref (object);
971 }
972
973 void
974 g_object_get_valist (GObject     *object,
975                      const gchar *first_property_name,
976                      va_list      var_args)
977 {
978   const gchar *name;
979   
980   g_return_if_fail (G_IS_OBJECT (object));
981   
982   g_object_ref (object);
983   
984   name = first_property_name;
985   
986   while (name)
987     {
988       const gchar *trailer = NULL;
989       GValue value = { 0, };
990       GParamSpec *pspec;
991       gchar *error;
992       
993       pspec = g_param_spec_hash_table_lookup (pspec_hash_table,
994                                               name,
995                                               G_OBJECT_TYPE (object),
996                                               TRUE,
997                                               &trailer);
998       if (!pspec)
999         {
1000           g_warning ("%s: object class `%s' has no property named `%s'",
1001                      G_STRLOC,
1002                      G_OBJECT_TYPE_NAME (object),
1003                      name);
1004           break;
1005         }
1006       if (!(pspec->flags & G_PARAM_READABLE))
1007         {
1008           g_warning ("%s: property `%s' of object class `%s' is not readable",
1009                      G_STRLOC,
1010                      pspec->name,
1011                      G_OBJECT_TYPE_NAME (object));
1012           break;
1013         }
1014       
1015       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1016       
1017       object_get_property (object, &value, pspec, trailer);
1018       
1019       G_VALUE_LCOPY (&value, var_args, &error);
1020       if (error)
1021         {
1022           g_warning ("%s: %s", G_STRLOC, error);
1023           g_free (error);
1024           
1025           /* we purposely leak the value here, it might not be
1026            * in a sane state if an error condition occoured
1027            */
1028           break;
1029         }
1030       
1031       g_value_unset (&value);
1032       
1033       name = va_arg (var_args, gchar*);
1034     }
1035   
1036   g_object_unref (object);
1037 }
1038
1039 void
1040 g_object_set (GObject     *object,
1041               const gchar *first_property_name,
1042               ...)
1043 {
1044   va_list var_args;
1045   
1046   g_return_if_fail (G_IS_OBJECT (object));
1047   
1048   va_start (var_args, first_property_name);
1049   g_object_set_valist (object, first_property_name, var_args);
1050   va_end (var_args);
1051 }
1052
1053 void
1054 g_object_get (GObject     *object,
1055               const gchar *first_property_name,
1056               ...)
1057 {
1058   va_list var_args;
1059   
1060   g_return_if_fail (G_IS_OBJECT (object));
1061   
1062   va_start (var_args, first_property_name);
1063   g_object_get_valist (object, first_property_name, var_args);
1064   va_end (var_args);
1065 }
1066
1067 void
1068 g_object_set_property (GObject      *object,
1069                        const gchar  *property_name,
1070                        const GValue *value)
1071 {
1072   NotifyQueue *nqueue;
1073   GParamSpec *pspec;
1074   const gchar *trailer;
1075   
1076   g_return_if_fail (G_IS_OBJECT (object));
1077   g_return_if_fail (property_name != NULL);
1078   g_return_if_fail (G_IS_VALUE (value));
1079   
1080   g_object_ref (object);
1081   nqueue = object_freeze_notifies (object);
1082   
1083   pspec = g_param_spec_hash_table_lookup (pspec_hash_table,
1084                                           property_name,
1085                                           G_OBJECT_TYPE (object),
1086                                           TRUE,
1087                                           &trailer);
1088   if (!pspec)
1089     g_warning ("%s: object class `%s' has no property named `%s'",
1090                G_STRLOC,
1091                G_OBJECT_TYPE_NAME (object),
1092                property_name);
1093   else
1094     {
1095       GValue tmp_value = { 0, };
1096       
1097       /* provide a copy to work from and convert if necessary */
1098       g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1099       
1100       if (!g_value_convert (value, &tmp_value) ||
1101           g_param_value_validate (pspec, &tmp_value))
1102         g_warning ("%s: cannot convert `%s' value to property `%s' value of type `%s'",
1103                    G_STRLOC,
1104                    G_VALUE_TYPE_NAME (value),
1105                    pspec->name,
1106                    g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1107       else
1108         object_set_property (object, &tmp_value, pspec, trailer, nqueue);
1109       
1110       g_value_unset (&tmp_value);
1111     }
1112   
1113   object_thaw_notifies (object, nqueue);
1114   g_object_unref (object);
1115 }
1116
1117 void
1118 g_object_get_property (GObject     *object,
1119                        const gchar *property_name,
1120                        GValue      *value)
1121 {
1122   GParamSpec *pspec;
1123   const gchar *trailer;
1124   
1125   g_return_if_fail (G_IS_OBJECT (object));
1126   g_return_if_fail (property_name != NULL);
1127   g_return_if_fail (G_IS_VALUE (value));
1128   
1129   g_object_ref (object);
1130   
1131   pspec = g_param_spec_hash_table_lookup (pspec_hash_table,
1132                                           property_name,
1133                                           G_OBJECT_TYPE (object),
1134                                           TRUE,
1135                                           &trailer);
1136   if (!pspec)
1137     g_warning ("%s: object class `%s' has no property named `%s'",
1138                G_STRLOC,
1139                G_OBJECT_TYPE_NAME (object),
1140                property_name);
1141   else
1142     {
1143       GValue tmp_value = { 0, };
1144       
1145       /* provide a copy to work from and later convert if necessary, so
1146        * _get_property() implementations need *not* care about freeing values
1147        * that might be already set in the property to get.
1148        * (though, at this point, GValue should exclusively be modified
1149        * through the accessor functions anyways)
1150        */
1151       g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1152       
1153       if (!g_value_types_exchangable (G_VALUE_TYPE (value), G_PARAM_SPEC_VALUE_TYPE (pspec)))
1154         g_warning ("%s: can't retrive property `%s' value of type `%s' as value of type `%s'",
1155                    G_STRLOC,
1156                    pspec->name,
1157                    g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1158                    G_VALUE_TYPE_NAME (value));
1159       else
1160         {
1161           object_get_property (object, &tmp_value, pspec, trailer);
1162           g_value_convert (&tmp_value, value);
1163           /* g_value_validate (value, pspec); */
1164         }
1165       
1166       g_value_unset (&tmp_value);
1167     }
1168   
1169   g_object_unref (object);
1170 }
1171
1172 GObject*
1173 g_object_ref (GObject *object)
1174 {
1175   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
1176   g_return_val_if_fail (object->ref_count > 0, NULL);
1177   
1178   object->ref_count += 1;
1179   
1180   return object;
1181 }
1182
1183 void
1184 g_object_unref (GObject *object)
1185 {
1186   g_return_if_fail (G_IS_OBJECT (object));
1187   g_return_if_fail (object->ref_count > 0);
1188   
1189   if (object->ref_count > 1)
1190     object->ref_count -= 1;
1191   else
1192     g_object_last_unref (object);
1193 }
1194
1195 gpointer
1196 g_object_get_qdata (GObject *object,
1197                     GQuark   quark)
1198 {
1199   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
1200   
1201   return quark ? g_datalist_id_get_data (&object->qdata, quark) : NULL;
1202 }
1203
1204 void
1205 g_object_set_qdata (GObject *object,
1206                     GQuark   quark,
1207                     gpointer data)
1208 {
1209   g_return_if_fail (G_IS_OBJECT (object));
1210   g_return_if_fail (quark > 0);
1211   
1212   g_datalist_id_set_data (&object->qdata, quark, data);
1213 }
1214
1215 void
1216 g_object_set_qdata_full (GObject       *object,
1217                          GQuark         quark,
1218                          gpointer       data,
1219                          GDestroyNotify destroy)
1220 {
1221   g_return_if_fail (G_IS_OBJECT (object));
1222   g_return_if_fail (quark > 0);
1223   
1224   g_datalist_id_set_data_full (&object->qdata, quark, data, data ? destroy : NULL);
1225 }
1226
1227 gpointer
1228 g_object_steal_qdata (GObject *object,
1229                       GQuark   quark)
1230 {
1231   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
1232   g_return_val_if_fail (quark > 0, NULL);
1233   
1234   return g_datalist_id_remove_no_notify (&object->qdata, quark);
1235 }
1236
1237 gpointer
1238 g_object_get_data (GObject     *object,
1239                    const gchar *key)
1240 {
1241   GQuark quark;
1242
1243   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
1244   g_return_val_if_fail (key != NULL, NULL);
1245
1246   quark = g_quark_try_string (key);
1247
1248   return quark ? g_datalist_id_get_data (&object->qdata, quark) : NULL;
1249 }
1250
1251 void
1252 g_object_set_data (GObject     *object,
1253                    const gchar *key,
1254                    gpointer     data)
1255 {
1256   g_return_if_fail (G_IS_OBJECT (object));
1257   g_return_if_fail (key != NULL);
1258
1259   g_datalist_id_set_data (&object->qdata, g_quark_from_string (key), data);
1260 }
1261
1262 void
1263 g_object_set_data_full (GObject       *object,
1264                         const gchar   *key,
1265                         gpointer       data,
1266                         GDestroyNotify destroy)
1267 {
1268   g_return_if_fail (G_IS_OBJECT (object));
1269   g_return_if_fail (key != NULL);
1270
1271   g_datalist_id_set_data_full (&object->qdata, g_quark_from_string (key), data, data ? destroy : NULL);
1272 }
1273
1274 gpointer
1275 g_object_steal_data (GObject     *object,
1276                      const gchar *key)
1277 {
1278   GQuark quark;
1279
1280   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
1281   g_return_val_if_fail (key != NULL, NULL);
1282
1283   quark = g_quark_try_string (key);
1284
1285   return quark ? g_datalist_id_remove_no_notify (&object->qdata, quark) : NULL;
1286 }
1287
1288 static void
1289 g_value_object_init (GValue *value)
1290 {
1291   value->data[0].v_pointer = NULL;
1292 }
1293
1294 static void
1295 g_value_object_free_value (GValue *value)
1296 {
1297   if (value->data[0].v_pointer)
1298     g_object_unref (value->data[0].v_pointer);
1299 }
1300
1301 static void
1302 g_value_object_copy_value (const GValue *src_value,
1303                            GValue       *dest_value)
1304 {
1305   if (src_value->data[0].v_pointer)
1306     dest_value->data[0].v_pointer = g_object_ref (src_value->data[0].v_pointer);
1307   else
1308     dest_value->data[0].v_pointer = NULL;
1309 }
1310
1311 static gpointer
1312 g_value_object_peek_pointer (const GValue *value)
1313 {
1314   return value->data[0].v_pointer;
1315 }
1316
1317 static gchar*
1318 g_value_object_collect_value (GValue      *value,
1319                               guint        nth_value,
1320                               GType       *collect_type,
1321                               GTypeCValue *collect_value)
1322 {
1323   if (collect_value->v_pointer)
1324     {
1325       GObject *object = collect_value->v_pointer;
1326       
1327       if (object->g_type_instance.g_class == NULL)
1328         return g_strconcat ("invalid unclassed object pointer for value type `",
1329                             G_VALUE_TYPE_NAME (value),
1330                             "'",
1331                             NULL);
1332       else if (!g_type_is_a (G_OBJECT_TYPE (object), G_VALUE_TYPE (value)))
1333         return g_strconcat ("invalid object type `",
1334                             G_OBJECT_TYPE_NAME (object),
1335                             "' for value type `",
1336                             G_VALUE_TYPE_NAME (value),
1337                             "'",
1338                             NULL);
1339       value->data[0].v_pointer = g_object_ref (object);
1340     }
1341   else
1342     value->data[0].v_pointer = NULL;
1343   
1344   *collect_type = 0;
1345   return NULL;
1346 }
1347
1348 static gchar*
1349 g_value_object_lcopy_value (const GValue *value,
1350                             guint         nth_value,
1351                             GType        *collect_type,
1352                             GTypeCValue  *collect_value)
1353 {
1354   GObject **object_p = collect_value->v_pointer;
1355   
1356   if (!object_p)
1357     return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
1358   
1359   *object_p = value->data[0].v_pointer ? g_object_ref (value->data[0].v_pointer) : NULL;
1360   
1361   *collect_type = 0;
1362   return NULL;
1363 }
1364
1365 void
1366 g_value_set_object (GValue  *value,
1367                     GObject *v_object)
1368 {
1369   g_return_if_fail (G_IS_VALUE_OBJECT (value));
1370   
1371   if (value->data[0].v_pointer)
1372     {
1373       g_object_unref (value->data[0].v_pointer);
1374       value->data[0].v_pointer = NULL;
1375     }
1376
1377   if (v_object)
1378     {
1379       g_return_if_fail (G_IS_OBJECT (v_object));
1380       g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (v_object), G_VALUE_TYPE (value)));
1381
1382       value->data[0].v_pointer = v_object;
1383       g_object_ref (value->data[0].v_pointer);
1384     }
1385 }
1386
1387 GObject*
1388 g_value_get_object (const GValue *value)
1389 {
1390   g_return_val_if_fail (G_IS_VALUE_OBJECT (value), NULL);
1391   
1392   return value->data[0].v_pointer;
1393 }
1394
1395 GObject*
1396 g_value_dup_object (const GValue *value)
1397 {
1398   g_return_val_if_fail (G_IS_VALUE_OBJECT (value), NULL);
1399   
1400   return value->data[0].v_pointer ? g_object_ref (value->data[0].v_pointer) : NULL;
1401 }
1402
1403 guint
1404 g_signal_connect_object (gpointer     instance,
1405                          const gchar *detailed_signal,
1406                          GCallback    c_handler,
1407                          gpointer     gobject,
1408                          gboolean     swapped,
1409                          gboolean     after)
1410 {
1411   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
1412   g_return_val_if_fail (detailed_signal != NULL, 0);
1413   g_return_val_if_fail (c_handler != NULL, 0);
1414
1415   if (gobject)
1416     {
1417       GClosure *closure;
1418
1419       g_return_val_if_fail (G_IS_OBJECT (gobject), 0);
1420
1421       closure = (swapped ? g_cclosure_new_object_swap : g_cclosure_new_object) (c_handler, gobject);
1422
1423       return g_signal_connect_closure (instance, detailed_signal, closure, after);
1424     }
1425   else
1426     return g_signal_connect_data (instance, detailed_signal, c_handler, NULL, NULL, swapped, after);
1427 }
1428
1429 typedef struct {
1430   GObject  *object;
1431   guint     n_closures;
1432   GClosure *closures[1]; /* flexible array */
1433 } CArray;
1434
1435 static void
1436 object_remove_closure (gpointer  data,
1437                        GClosure *closure)
1438 {
1439   GObject *object = data;
1440   CArray *carray = g_object_get_qdata (object, quark_closure_array);
1441   guint i;
1442   
1443   for (i = 0; i < carray->n_closures; i++)
1444     if (carray->closures[i] == closure)
1445       {
1446         carray->n_closures--;
1447         if (i < carray->n_closures)
1448           carray->closures[i] = carray->closures[carray->n_closures];
1449         return;
1450       }
1451   g_assert_not_reached ();
1452 }
1453
1454 static void
1455 destroy_closure_array (gpointer data)
1456 {
1457   CArray *carray = data;
1458   GObject *object = carray->object;
1459   guint i, n = carray->n_closures;
1460   
1461   for (i = 0; i < n; i++)
1462     {
1463       GClosure *closure = carray->closures[i];
1464       
1465       /* removing object_remove_closure() upfront is probably faster than
1466        * letting it fiddle with quark_closure_array which is empty anyways
1467        */
1468       g_closure_remove_inotify (closure, object, object_remove_closure);
1469       g_closure_invalidate (closure);
1470     }
1471   g_free (carray);
1472 }
1473
1474 void
1475 g_object_watch_closure (GObject  *object,
1476                         GClosure *closure)
1477 {
1478   CArray *carray;
1479   
1480   g_return_if_fail (G_IS_OBJECT (object));
1481   g_return_if_fail (closure != NULL);
1482   g_return_if_fail (closure->is_invalid == FALSE);
1483   g_return_if_fail (closure->in_marshal == FALSE);
1484   g_return_if_fail (object->ref_count > 0);     /* this doesn't work on finalizing objects */
1485   
1486   g_closure_add_inotify (closure, object, object_remove_closure);
1487   g_closure_add_marshal_guards (closure,
1488                                 object, (GClosureNotify) g_object_ref,
1489                                 object, (GClosureNotify) g_object_unref);
1490   carray = g_object_steal_qdata (object, quark_closure_array);
1491   if (!carray)
1492     {
1493       carray = g_renew (CArray, NULL, 1);
1494       carray->object = object;
1495       carray->n_closures = 1;
1496       carray->closures[0] = closure;
1497       g_object_set_qdata_full (object, quark_closure_array, carray, destroy_closure_array);
1498     }
1499   else
1500     {
1501       guint i = carray->n_closures++;
1502       
1503       carray = g_realloc (carray, sizeof (*carray) + sizeof (carray->closures[0]) * i);
1504       carray->closures[i] = closure;
1505       g_object_set_qdata_full (object, quark_closure_array, carray, destroy_closure_array);
1506     }
1507 }
1508
1509 GClosure*
1510 g_closure_new_object (guint    sizeof_closure,
1511                       GObject *object)
1512 {
1513   GClosure *closure;
1514
1515   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
1516   g_return_val_if_fail (object->ref_count > 0, NULL);     /* this doesn't work on finalizing objects */
1517
1518   closure = g_closure_new_simple (sizeof_closure, object);
1519   g_object_watch_closure (object, closure);
1520
1521   return closure;
1522 }
1523
1524 GClosure*
1525 g_cclosure_new_object (GCallback callback_func,
1526                        gpointer  _object)
1527 {
1528   GObject *object = _object;
1529   GClosure *closure;
1530
1531   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
1532   g_return_val_if_fail (object->ref_count > 0, NULL);     /* this doesn't work on finalizing objects */
1533   g_return_val_if_fail (callback_func != NULL, NULL);
1534
1535   closure = g_cclosure_new (callback_func, object, NULL);
1536   g_object_watch_closure (object, closure);
1537
1538   return closure;
1539 }
1540
1541 GClosure*
1542 g_cclosure_new_object_swap (GCallback callback_func,
1543                             gpointer  _object)
1544 {
1545   GObject *object = _object;
1546   GClosure *closure;
1547
1548   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
1549   g_return_val_if_fail (object->ref_count > 0, NULL);     /* this doesn't work on finalizing objects */
1550   g_return_val_if_fail (callback_func != NULL, NULL);
1551
1552   closure = g_cclosure_new_swap (callback_func, object, NULL);
1553   g_object_watch_closure (object, closure);
1554
1555   return closure;
1556 }