]> Pileus Git - ~andy/gtk/blob - gtk/gtkobject.c
827d8186cc527e2b4bfad7a9c2e3d427ccdbfdb8
[~andy/gtk] / gtk / gtkobject.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * 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 <stdarg.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include "gtkobject.h"
24 #include "gtksignal.h"
25
26
27 #define GTK_OBJECT_DATA_ID_BLOCK_SIZE   (1024)
28 #define GTK_OBJECT_DATA_BLOCK_SIZE      (1024)
29
30 enum {
31   DESTROY,
32   LAST_SIGNAL
33 };
34 enum {
35   ARG_0,
36   ARG_USER_DATA,
37   ARG_SIGNAL,
38   ARG_OBJECT_SIGNAL
39 };
40
41
42 typedef struct _GtkObjectData  GtkObjectData;
43 typedef struct _GtkArgInfo     GtkArgInfo;
44
45 struct _GtkObjectData
46 {
47   guint id;
48   gpointer data;
49   GtkDestroyNotify destroy;
50   GtkObjectData *next;
51 };
52
53 struct _GtkArgInfo
54 {
55   gchar *name;
56   GtkType type;
57   GtkType class_type;
58   guint arg_flags;
59   guint arg_id;
60   guint seq_id;
61 };
62
63
64 void                  gtk_object_init_type     (void);
65 static void           gtk_object_class_init    (GtkObjectClass *klass);
66 static void           gtk_object_init          (GtkObject      *object);
67 static void           gtk_object_set_arg       (GtkObject      *object,
68                                                 GtkArg         *arg,
69                                                 guint           arg_id);
70 static void           gtk_object_get_arg       (GtkObject      *object,
71                                                 GtkArg         *arg,
72                                                 guint           arg_id);
73 static void           gtk_object_shutdown      (GtkObject      *object);
74 static void           gtk_object_real_destroy  (GtkObject      *object);
75 static void           gtk_object_finalize      (GtkObject      *object);
76 static void           gtk_object_notify_weaks  (GtkObject      *object);
77
78 GtkArg*               gtk_object_collect_args  (guint   *nargs,
79                                                 GtkType (*) (const gchar*),
80                                                 va_list  args1,
81                                                 va_list  args2);
82
83 static guint object_signals[LAST_SIGNAL] = { 0 };
84
85 static GHashTable *arg_info_ht = NULL;
86
87 static const gchar *user_data_key = "user_data";
88 static guint user_data_key_id = 0;
89 static const gchar *weakrefs_key = "gtk-weakrefs";
90 static guint weakrefs_key_id = 0;
91
92 static GtkObjectData *gtk_object_data_free_list = NULL;
93
94 #define GTK_OBJECT_DATA_DESTROY( odata )        { \
95   if (odata->destroy) \
96     odata->destroy (odata->data); \
97   odata->next = gtk_object_data_free_list; \
98   gtk_object_data_free_list = odata; \
99 }
100
101
102 #ifdef G_ENABLE_DEBUG
103 static guint obj_count = 0;
104 static GHashTable *living_objs_ht = NULL;
105 static void
106 gtk_object_debug_foreach (gpointer key, gpointer value, gpointer user_data)
107 {
108   GtkObject *object;
109   
110   object = (GtkObject*) value;
111   g_print ("GTK-DEBUG: %p: %s ref_count=%d%s%s\n",
112            object,
113            gtk_type_name (GTK_OBJECT_TYPE (object)),
114            object->ref_count,
115            GTK_OBJECT_FLOATING (object) ? " (floating)" : "",
116            GTK_OBJECT_DESTROYED (object) ? " (destroyed)" : "");
117 }
118 static void
119 gtk_object_debug (void)
120 {
121   g_hash_table_foreach (living_objs_ht, gtk_object_debug_foreach, NULL);
122
123   g_print ("GTK-DEBUG: living objects count = %d\n", obj_count);
124 }
125 #endif  /* G_ENABLE_DEBUG */
126
127 /****************************************************
128  * GtkObject type, class and instance initialization
129  *
130  ****************************************************/
131
132 void
133 gtk_object_init_type (void)
134 {
135   GtkType object_type = 0;
136   GtkTypeInfo object_info =
137   {
138     "GtkObject",
139     sizeof (GtkObject),
140     sizeof (GtkObjectClass),
141     (GtkClassInitFunc) gtk_object_class_init,
142     (GtkObjectInitFunc) gtk_object_init,
143     gtk_object_set_arg,
144     gtk_object_get_arg,
145   };
146
147   object_type = gtk_type_unique (0, &object_info);
148   g_assert (object_type == GTK_TYPE_OBJECT);
149
150 #ifdef G_ENABLE_DEBUG
151   if (gtk_debug_flags & GTK_DEBUG_OBJECTS)
152     ATEXIT (gtk_object_debug);
153 #endif  /* G_ENABLE_DEBUG */
154 }
155
156 GtkType
157 gtk_object_get_type (void)
158 {
159   return GTK_TYPE_OBJECT;
160 }
161
162 static void
163 gtk_object_class_init (GtkObjectClass *class)
164 {
165   class->signals = NULL;
166   class->nsignals = 0;
167   class->n_args = 0;
168
169   gtk_object_add_arg_type ("GtkObject::user_data",
170                            GTK_TYPE_POINTER,
171                            GTK_ARG_READWRITE,
172                            ARG_USER_DATA);
173   gtk_object_add_arg_type ("GtkObject::signal",
174                            GTK_TYPE_SIGNAL,
175                            GTK_ARG_WRITABLE,
176                            ARG_SIGNAL);
177   gtk_object_add_arg_type ("GtkObject::object_signal",
178                            GTK_TYPE_SIGNAL,
179                            GTK_ARG_WRITABLE,
180                            ARG_OBJECT_SIGNAL);
181
182   object_signals[DESTROY] =
183     gtk_signal_new ("destroy",
184                     GTK_RUN_LAST,
185                     class->type,
186                     GTK_SIGNAL_OFFSET (GtkObjectClass, destroy),
187                     gtk_signal_default_marshaller,
188                     GTK_TYPE_NONE, 0);
189
190   gtk_object_class_add_signals (class, object_signals, LAST_SIGNAL);
191
192   class->shutdown = gtk_object_shutdown;
193   class->destroy = gtk_object_real_destroy;
194   class->finalize = gtk_object_finalize;
195 }
196
197 static void
198 gtk_object_init (GtkObject *object)
199 {
200   GTK_OBJECT_FLAGS (object) = GTK_FLOATING;
201
202   object->ref_count = 1;
203   object->object_data = NULL;
204
205 #ifdef G_ENABLE_DEBUG
206   if (gtk_debug_flags & GTK_DEBUG_OBJECTS)
207     {
208       obj_count++;
209       
210       if (!living_objs_ht)
211         living_objs_ht = g_hash_table_new (g_direct_hash, NULL);
212
213       g_hash_table_insert (living_objs_ht, object, object);
214     }
215 #endif /* G_ENABLE_DEBUG */
216 }
217
218 /********************************************
219  * Functions to end a GtkObject's life time
220  *
221  ********************************************/
222 void
223 gtk_object_destroy (GtkObject *object)
224 {
225   g_return_if_fail (object != NULL);
226   g_return_if_fail (GTK_IS_OBJECT (object));
227   
228   if (!GTK_OBJECT_DESTROYED (object))
229     {
230       /* we will hold a reference on the object in this place, so
231        * to ease all classes shutdown and destroy implementations.
232        * i.e. they don't have to bother about referencing at all.
233        */
234       gtk_object_ref (object);
235       object->klass->shutdown (object);
236       gtk_object_unref (object);
237     }
238 }
239
240 static void
241 gtk_object_shutdown (GtkObject *object)
242 {
243   GTK_OBJECT_SET_FLAGS (object, GTK_DESTROYED);
244   gtk_signal_emit (object, object_signals[DESTROY]);
245 }
246
247 static void
248 gtk_object_real_destroy (GtkObject *object)
249 {
250   if (GTK_OBJECT_CONNECTED (object))
251     gtk_signal_handlers_destroy (object);
252 }
253
254 static void
255 gtk_object_finalize (GtkObject *object)
256 {
257   gtk_object_notify_weaks (object);
258
259   while (object->object_data)
260     {
261       GtkObjectData *odata;
262
263       odata = object->object_data;
264       object->object_data = odata->next;
265       GTK_OBJECT_DATA_DESTROY (odata);
266     }
267   
268   gtk_type_free (GTK_OBJECT_TYPE (object), object);
269 }
270
271 /*****************************************
272  * GtkObject argument handlers
273  *
274  *****************************************/
275
276 static void
277 gtk_object_set_arg (GtkObject *object,
278                     GtkArg    *arg,
279                     guint      arg_id)
280 {
281   switch (arg_id)
282     {
283     case ARG_USER_DATA:
284       gtk_object_set_user_data (object, GTK_VALUE_POINTER (*arg));
285       break;
286     case ARG_SIGNAL:
287       if ((arg->name[9 + 2 + 6] != ':') || (arg->name[9 + 2 + 7] != ':'))
288         {
289           g_warning ("invalid signal argument: \"%s\"\n", arg->name);
290           return;
291         }
292       gtk_signal_connect (object, arg->name + 9 + 2 + 6 + 2,
293                           (GtkSignalFunc) GTK_VALUE_SIGNAL (*arg).f,
294                           GTK_VALUE_SIGNAL (*arg).d);
295       break;
296     case ARG_OBJECT_SIGNAL:
297       if ((arg->name[9 + 2 + 13] != ':') || (arg->name[9 + 2 + 14] != ':'))
298         {
299           g_warning ("invalid signal argument: \"%s\"\n", arg->name);
300           return;
301         }
302       gtk_signal_connect_object (object, arg->name + 9 + 2 + 13 + 2,
303                                  (GtkSignalFunc) GTK_VALUE_SIGNAL (*arg).f,
304                                  (GtkObject*) GTK_VALUE_SIGNAL (*arg).d);
305       break;
306     default:
307       break;
308     }
309 }
310
311 static void
312 gtk_object_get_arg (GtkObject *object,
313                     GtkArg    *arg,
314                     guint      arg_id)
315 {
316   switch (arg_id)
317     {
318     case ARG_USER_DATA:
319       GTK_VALUE_POINTER (*arg) = gtk_object_get_user_data (object);
320       break;
321     case ARG_SIGNAL:
322     case ARG_OBJECT_SIGNAL:
323     default:
324       arg->type = GTK_TYPE_INVALID;
325       break;
326     }
327 }
328
329 /*****************************************
330  * gtk_object_class_add_signals:
331  *
332  *   arguments:
333  *
334  *   results:
335  *****************************************/
336
337 void
338 gtk_object_class_add_signals (GtkObjectClass *class,
339                               guint          *signals,
340                               guint           nsignals)
341 {
342   guint *new_signals;
343   guint i;
344
345   g_return_if_fail (class != NULL);
346
347   new_signals = g_new (guint, class->nsignals + nsignals);
348   for (i = 0; i < class->nsignals; i++)
349     new_signals[i] = class->signals[i];
350   for (i = 0; i < nsignals; i++)
351     new_signals[class->nsignals + i] = signals[i];
352
353   g_free (class->signals);
354   class->signals = new_signals;
355   class->nsignals += nsignals;
356 }
357
358 guint
359 gtk_object_class_add_user_signal (GtkObjectClass     *class,
360                                   const gchar        *name,
361                                   GtkSignalMarshaller marshaller,
362                                   GtkType             return_val,
363                                   guint               nparams,
364                                   ...)
365 {
366   GtkType *params;
367   guint i;
368   va_list args;
369   guint signal_id;
370
371   g_return_val_if_fail (class != NULL, 0);
372
373   if (nparams > 0)
374     {
375       params = g_new (GtkType, nparams);
376
377       va_start (args, nparams);
378
379       for (i = 0; i < nparams; i++)
380         params[i] = va_arg (args, GtkType);
381
382       va_end (args);
383     }
384   else
385     params = NULL;
386
387   signal_id = gtk_signal_newv (name,
388                                0,
389                                class->type,
390                                0,
391                                marshaller,
392                                return_val,
393                                nparams,
394                                params);
395
396   g_free (params);
397
398   if (signal_id)
399     gtk_object_class_add_signals (class, &signal_id, 1);
400
401   return signal_id;
402 }
403
404 guint
405 gtk_object_class_user_signal_new (GtkObjectClass     *class,
406                                   const gchar        *name,
407                                   GtkSignalRunType    signal_flags,
408                                   GtkSignalMarshaller marshaller,
409                                   GtkType             return_val,
410                                   guint               nparams,
411                                   ...)
412 {
413   GtkType *params;
414   guint i;
415   va_list args;
416   guint signal_id;
417
418   g_return_val_if_fail (class != NULL, 0);
419
420   if (nparams > 0)
421     {
422       params = g_new (GtkType, nparams);
423
424       va_start (args, nparams);
425
426       for (i = 0; i < nparams; i++)
427         params[i] = va_arg (args, GtkType);
428
429       va_end (args);
430     }
431   else
432     params = NULL;
433
434   signal_id = gtk_signal_newv (name,
435                                signal_flags,
436                                class->type,
437                                0,
438                                marshaller,
439                                return_val,
440                                nparams,
441                                params);
442
443   g_free (params);
444
445   if (signal_id)
446     gtk_object_class_add_signals (class, &signal_id, 1);
447
448   return signal_id;
449 }
450
451 guint
452 gtk_object_class_user_signal_newv (GtkObjectClass     *class,
453                                    const gchar        *name,
454                                    GtkSignalRunType    signal_flags,
455                                    GtkSignalMarshaller marshaller,
456                                    GtkType             return_val,
457                                    guint               nparams,
458                                    GtkType            *params)
459 {
460   guint signal_id;
461
462   g_return_val_if_fail (class != NULL, 0);
463
464   if (nparams > 0)
465     g_return_val_if_fail (params != NULL, 0);
466
467   signal_id = gtk_signal_newv (name,
468                                signal_flags,
469                                class->type,
470                                0,
471                                marshaller,
472                                return_val,
473                                nparams,
474                                params);
475
476   if (signal_id)
477     gtk_object_class_add_signals (class, &signal_id, 1);
478
479   return signal_id;
480 }
481
482 /*****************************************
483  * gtk_object_sink:
484  *
485  *   arguments:
486  *
487  *   results:
488  *****************************************/
489
490 void
491 gtk_object_sink (GtkObject *object)
492 {
493   g_return_if_fail (object != NULL);
494   g_return_if_fail (GTK_IS_OBJECT (object));
495
496   if (GTK_OBJECT_FLOATING (object))
497     {
498       GTK_OBJECT_UNSET_FLAGS (object, GTK_FLOATING);
499       gtk_object_unref (object);
500     }
501 }
502
503 /*****************************************
504  * Weak references.
505  *
506  * Weak refs are very similar to the old "destroy" signal.  They allow
507  * one to register a callback that is called when the weakly
508  * referenced object is finalized.
509  *  
510  * They are not implemented as a signal because they really are
511  * special and need to be used with great care.  Unlike signals, which
512  * should be able to execute any code whatsoever.
513  * 
514  * A weakref callback is not allowed to retain a reference to the
515  * object.  Object data keys may be retrieved in a weak reference
516  * callback.
517  * 
518  * A weakref callback is called at most once.
519  *
520  *****************************************/
521
522 typedef struct _GtkWeakRef      GtkWeakRef;
523
524 struct _GtkWeakRef
525 {
526   GtkWeakRef       *next;
527   GtkDestroyNotify  notify;
528   gpointer          data;
529 };
530
531 void
532 gtk_object_weakref (GtkObject        *object,
533                     GtkDestroyNotify  notify,
534                     gpointer          data)
535 {
536   GtkWeakRef *weak;
537
538   g_return_if_fail (object != NULL);
539   g_return_if_fail (notify != NULL);
540   g_return_if_fail (GTK_IS_OBJECT (object));
541
542   if (!weakrefs_key_id)
543     weakrefs_key_id = g_quark_from_static_string (weakrefs_key);
544
545   weak = g_new (GtkWeakRef, 1);
546   weak->next = gtk_object_get_data_by_id (object, weakrefs_key_id);
547   weak->notify = notify;
548   weak->data = data;
549   gtk_object_set_data_by_id (object, weakrefs_key_id, weak);
550 }
551
552 void
553 gtk_object_weakunref (GtkObject        *object,
554                       GtkDestroyNotify  notify,
555                       gpointer          data)
556 {
557   GtkWeakRef *weaks, *w, **wp;
558
559   g_return_if_fail (object != NULL);
560   g_return_if_fail (GTK_IS_OBJECT (object));
561
562   if (!weakrefs_key_id)
563     return;
564
565   weaks = gtk_object_get_data_by_id (object, weakrefs_key_id);
566   for (wp = &weaks; *wp; wp = &(*wp)->next)
567     {
568       w = *wp;
569       if (w->notify == notify && w->data == data)
570         {
571           if (w == weaks)
572             gtk_object_set_data_by_id (object, weakrefs_key_id, w->next);
573           else
574             *wp = w->next;
575           g_free (w);
576           return;
577         }
578     }
579 }
580
581 static void
582 gtk_object_notify_weaks (GtkObject *object)
583 {
584   if (weakrefs_key_id)
585     {
586       GtkWeakRef *w1, *w2;
587       
588       w1 = gtk_object_get_data_by_id (object, weakrefs_key_id);
589       
590       while (w1)
591         {
592           w1->notify (w1->data);
593           w2 = w1->next;
594           g_free (w1);
595           w1 = w2;
596         }
597     }
598 }
599
600 /*****************************************
601  * gtk_object_new:
602  *
603  *   arguments:
604  *
605  *   results:
606  *****************************************/
607
608 GtkObject*
609 gtk_object_new (GtkType type,
610                 ...)
611 {
612   GtkObject *obj;
613   GtkArg *args;
614   guint nargs;
615   va_list args1;
616   va_list args2;
617
618   obj = gtk_type_new (type);
619
620   va_start (args1, type);
621   va_start (args2, type);
622
623   args = gtk_object_collect_args (&nargs, gtk_object_get_arg_type, args1, args2);
624   gtk_object_setv (obj, nargs, args);
625   g_free (args);
626
627   va_end (args1);
628   va_end (args2);
629
630   return obj;
631 }
632
633 /*****************************************
634  * gtk_object_newv:
635  *
636  *   arguments:
637  *
638  *   results:
639  *****************************************/
640
641 GtkObject*
642 gtk_object_newv (GtkType  type,
643                  guint    nargs,
644                  GtkArg *args)
645 {
646   gpointer obj;
647
648   obj = gtk_type_new (type);
649   gtk_object_setv (obj, nargs, args);
650
651   return obj;
652 }
653
654 /*****************************************
655  * gtk_object_getv:
656  *
657  *   arguments:
658  *
659  *   results:
660  *****************************************/
661
662 void
663 gtk_object_getv (GtkObject           *object,
664                  guint               nargs,
665                  GtkArg              *args)
666 {
667   guint i;
668   
669   g_return_if_fail (object != NULL);
670   g_return_if_fail (GTK_IS_OBJECT (object));
671   
672   if (!arg_info_ht)
673     return;
674   
675   for (i = 0; i < nargs; i++)
676     {
677       GtkArgInfo *info;
678       gchar *lookup_name;
679       gchar *d;
680       
681       
682       /* hm, the name cutting shouldn't be needed on gets, but what the heck...
683        */
684       lookup_name = g_strdup (args[i].name);
685       d = strchr (lookup_name, ':');
686       if (d && d[1] == ':')
687         {
688           d = strchr (d + 2, ':');
689           if (d)
690             *d = 0;
691           
692           info = g_hash_table_lookup (arg_info_ht, lookup_name);
693         }
694       else
695         info = NULL;
696       
697       if (!info)
698         {
699           g_warning ("gtk_object_getv(): invalid arg name: \"%s\"\n",
700                      lookup_name);
701           args[i].type = GTK_TYPE_INVALID;
702           g_free (lookup_name);
703           continue;
704         }
705       else if (!gtk_type_is_a (object->klass->type, info->class_type))
706         {
707           g_warning ("gtk_object_getv(): invalid arg for %s: \"%s\"\n",
708                      gtk_type_name (object->klass->type), lookup_name);
709           args[i].type = GTK_TYPE_INVALID;
710           g_free (lookup_name);
711           continue;
712         }
713       else if (! (info->arg_flags & GTK_ARG_READABLE))
714         {
715           g_warning ("gtk_object_getv(): arg is not supplied for read-access: \"%s\"\n",
716                      lookup_name);
717           args[i].type = GTK_TYPE_INVALID;
718           g_free (lookup_name);
719           continue;
720         }
721       else
722         g_free (lookup_name);
723
724       args[i].type = info->type;
725       gtk_type_get_arg (object, info->class_type, &args[i], info->arg_id);
726     }
727 }
728
729 /*****************************************
730  * gtk_object_query_args:
731  *
732  *   arguments:
733  *
734  *   results:
735  *****************************************/
736
737 struct _GtkQueryArgData
738 {
739   GList *arg_list;
740   GtkType class_type;
741 };
742 typedef struct  _GtkQueryArgData        GtkQueryArgData;
743
744 static void
745 gtk_query_arg_foreach (gpointer key,
746                        gpointer value,
747                        gpointer user_data)
748 {
749   register GtkArgInfo *info;
750   register GtkQueryArgData *data;
751
752   info = value;
753   data = user_data;
754
755   if (info->class_type == data->class_type)
756     data->arg_list = g_list_prepend (data->arg_list, info);
757 }
758
759 GtkArg*
760 gtk_object_query_args (GtkType  class_type,
761                        guint32  **arg_flags,
762                        guint    *nargs)
763 {
764   GtkArg *args;
765   GtkQueryArgData query_data;
766
767   if (arg_flags)
768     *arg_flags = NULL;
769   g_return_val_if_fail (nargs != NULL, NULL);
770   *nargs = 0;
771   g_return_val_if_fail (gtk_type_is_a (class_type, GTK_TYPE_OBJECT), NULL);
772
773   if (!arg_info_ht)
774     return NULL;
775
776   /* make sure the types class has been initialized, because
777    * the argument setup happens in the gtk_*_class_init() functions.
778    */
779   gtk_type_class (class_type);
780
781   query_data.arg_list = NULL;
782   query_data.class_type = class_type;
783   g_hash_table_foreach (arg_info_ht, gtk_query_arg_foreach, &query_data);
784
785   if (query_data.arg_list)
786     {
787       register GList    *list;
788       register guint    len;
789
790       list = query_data.arg_list;
791       len = 1;
792       while (list->next)
793         {
794           len++;
795           list = list->next;
796         }
797       g_assert (len == ((GtkObjectClass*) gtk_type_class (class_type))->n_args); /* paranoid */
798
799       args = g_new0 (GtkArg, len);
800       *nargs = len;
801       if (arg_flags)
802         *arg_flags = g_new (guint32, len);
803
804       do
805         {
806           GtkArgInfo *info;
807
808           info = list->data;
809           list = list->prev;
810
811           g_assert (info->seq_id > 0 && info->seq_id <= len); /* paranoid */
812
813           args[info->seq_id - 1].type = info->type;
814           args[info->seq_id - 1].name = info->name;
815           if (arg_flags)
816             (*arg_flags)[info->seq_id - 1] = info->arg_flags;
817         }
818       while (list);
819
820       g_list_free (query_data.arg_list);
821     }
822   else
823     args = NULL;
824
825   return args;
826 }
827
828 /*****************************************
829  * gtk_object_set:
830  *
831  *   arguments:
832  *
833  *   results:
834  *****************************************/
835
836 void
837 gtk_object_set (GtkObject *object,
838                 ...)
839 {
840   GtkArg *args;
841   guint nargs;
842   va_list args1;
843   va_list args2;
844
845   g_return_if_fail (object != NULL);
846
847   va_start (args1, object);
848   va_start (args2, object);
849
850   args = gtk_object_collect_args (&nargs, gtk_object_get_arg_type, args1, args2);
851   gtk_object_setv (object, nargs, args);
852   g_free (args);
853
854   va_end (args1);
855   va_end (args2);
856 }
857
858 /*****************************************
859  * gtk_object_setv:
860  *
861  *   arguments:
862  *
863  *   results:
864  *****************************************/
865
866 void
867 gtk_object_setv (GtkObject *object,
868                  guint      nargs,
869                  GtkArg    *args)
870 {
871   guint i;
872
873   g_return_if_fail (object != NULL);
874   g_return_if_fail (GTK_OBJECT (object));
875
876   if (!arg_info_ht)
877     return;
878
879   for (i = 0; i < nargs; i++)
880     {
881       GtkArgInfo *info;
882       gchar *lookup_name;
883       gchar *d;
884       gboolean arg_ok;
885
886       lookup_name = g_strdup (args[i].name);
887       d = strchr (lookup_name, ':');
888       if (d && d[1] == ':')
889         {
890           d = strchr (d + 2, ':');
891           if (d)
892             *d = 0;
893
894           info = g_hash_table_lookup (arg_info_ht, lookup_name);
895         }
896       else
897         info = NULL;
898
899       arg_ok = TRUE;
900       
901       if (!info)
902         {
903           g_warning ("gtk_object_setv(): invalid arg name: \"%s\"\n",
904                      lookup_name);
905           arg_ok = FALSE;
906         }
907       else if (info->type != args[i].type)
908         {
909           g_warning ("gtk_object_setv(): invalid arg type for: \"%s\"\n",
910                      lookup_name);
911           arg_ok = FALSE;
912         }
913       else if (!gtk_type_is_a (object->klass->type, info->class_type))
914         {
915           g_warning ("gtk_object_setv(): invalid arg for %s: \"%s\"\n",
916                      gtk_type_name (object->klass->type), lookup_name);
917           arg_ok = FALSE;
918         }
919       else if (! (info->arg_flags & GTK_ARG_WRITABLE))
920         {
921           g_warning ("gtk_object_setv(): arg is not supplied for write-access: \"%s\"\n",
922                      lookup_name);
923           arg_ok = FALSE;
924         }
925       
926       g_free (lookup_name);
927
928       if (!arg_ok)
929         continue;
930
931       gtk_type_set_arg (object, info->class_type, &args[i], info->arg_id);
932     }
933 }
934
935 /*****************************************
936  * gtk_object_add_arg_type:
937  *
938  *   arguments:
939  *
940  *   results:
941  *****************************************/
942
943 void
944 gtk_object_add_arg_type (const char *arg_name,
945                          GtkType     arg_type,
946                          guint       arg_flags,
947                          guint       arg_id)
948 {
949   GtkArgInfo *info;
950   gchar class_part[1024];
951   gchar *arg_part;
952   GtkType class_type;
953
954   g_return_if_fail (arg_name != NULL);
955   g_return_if_fail (arg_type > GTK_TYPE_NONE);
956   g_return_if_fail (arg_id > 0);
957   g_return_if_fail ((arg_flags & GTK_ARG_READWRITE) != 0);
958   g_return_if_fail ((arg_flags & GTK_ARG_CHILD_ARG) == 0);
959   
960   arg_flags &= GTK_ARG_MASK;
961
962   arg_part = strchr (arg_name, ':');
963   if (!arg_part || (arg_part[0] != ':') || (arg_part[1] != ':'))
964     {
965       g_warning ("invalid arg name: \"%s\"\n", arg_name);
966       return;
967     }
968
969   strncpy (class_part, arg_name, (glong) (arg_part - arg_name));
970   class_part[(glong) (arg_part - arg_name)] = '\0';
971
972   class_type = gtk_type_from_name (class_part);
973   if (!class_type)
974     {
975       g_warning ("gtk_object_add_arg_type(): invalid class name in arg: \"%s\"\n", arg_name);
976       return;
977     }
978
979   info = g_new (GtkArgInfo, 1);
980   info->name = g_strdup (arg_name);
981   info->type = arg_type;
982   info->class_type = class_type;
983   info->arg_flags = arg_flags;
984   info->arg_id = arg_id;
985   info->seq_id = ++((GtkObjectClass*) gtk_type_class (class_type))->n_args;
986
987   if (!arg_info_ht)
988     arg_info_ht = g_hash_table_new (g_str_hash, g_str_equal);
989
990   g_hash_table_insert (arg_info_ht, info->name, info);
991 }
992
993 /*****************************************
994  * gtk_object_get_arg_type:
995  *
996  *   arguments:
997  *
998  *   results:
999  *****************************************/
1000
1001 GtkType
1002 gtk_object_get_arg_type (const gchar *arg_name)
1003 {
1004   GtkArgInfo *info;
1005   gchar buffer[128];
1006   gchar *t;
1007
1008   g_return_val_if_fail (arg_name != NULL, 0);
1009
1010   if (!arg_info_ht)
1011     return GTK_TYPE_INVALID;
1012
1013   if (!arg_name || strlen (arg_name) > 120)
1014     {
1015       /* security audit
1016        */
1017       g_warning ("gtk_object_get_arg_type(): argument `arg_name' exceeds maximum size.");
1018       return GTK_TYPE_INVALID;
1019     }
1020
1021   t = strchr (arg_name, ':');
1022   if (!t || (t[0] != ':') || (t[1] != ':'))
1023     {
1024       g_warning ("gtk_object_get_arg_type(): invalid arg name: \"%s\"\n", arg_name);
1025       return GTK_TYPE_INVALID;
1026     }
1027
1028   t = strchr (t + 2, ':');
1029   if (t)
1030     {
1031       strncpy (buffer, arg_name, (long) (t - arg_name));
1032       buffer[(long) (t - arg_name)] = '\0';
1033       arg_name = buffer;
1034     }
1035
1036   info = g_hash_table_lookup (arg_info_ht, arg_name);
1037   if (info)
1038     return info->type;
1039
1040   return GTK_TYPE_INVALID;
1041 }
1042
1043 /*****************************************
1044  * GtkObject object_data mechanism
1045  *
1046  *****************************************/
1047
1048 void
1049 gtk_object_set_data_by_id (GtkObject        *object,
1050                            GQuark            data_id,
1051                            gpointer          data)
1052 {
1053   g_return_if_fail (data_id > 0);
1054   
1055   gtk_object_set_data_by_id_full (object, data_id, data, NULL);
1056 }
1057
1058 void
1059 gtk_object_set_data (GtkObject        *object,
1060                      const gchar      *key,
1061                      gpointer          data)
1062 {
1063   g_return_if_fail (key != NULL);
1064   
1065   gtk_object_set_data_by_id_full (object, gtk_object_data_force_id (key), data, NULL);
1066 }
1067
1068 void
1069 gtk_object_set_data_by_id_full (GtkObject        *object,
1070                                 GQuark            data_id,
1071                                 gpointer          data,
1072                                 GtkDestroyNotify  destroy)
1073 {
1074   GtkObjectData *odata;
1075   
1076   g_return_if_fail (object != NULL);
1077   g_return_if_fail (GTK_IS_OBJECT (object));
1078   g_return_if_fail (data_id > 0);
1079
1080   odata = object->object_data;
1081   if (!data)
1082     {
1083       GtkObjectData *prev;
1084       
1085       prev = NULL;
1086       
1087       while (odata)
1088         {
1089           if (odata->id == data_id)
1090             {
1091               if (prev)
1092                 prev->next = odata->next;
1093               else
1094                 object->object_data = odata->next;
1095               
1096               GTK_OBJECT_DATA_DESTROY (odata);
1097               return;
1098             }
1099           
1100           prev = odata;
1101           odata = odata->next;
1102         }
1103     }
1104   else
1105     {
1106       while (odata)
1107         {
1108           if (odata->id == data_id)
1109             {
1110               register GtkDestroyNotify dfunc;
1111               register gpointer ddata;
1112
1113               dfunc = odata->destroy;
1114               ddata = odata->data;
1115               odata->destroy = destroy;
1116               odata->data = data;
1117
1118               /* we need to have updated all structures prior to
1119                * invokation of the destroy function
1120                */
1121               if (dfunc)
1122                 dfunc (ddata);
1123
1124               return;
1125             }
1126
1127           odata = odata->next;
1128         }
1129       
1130       if (gtk_object_data_free_list)
1131         {
1132           odata = gtk_object_data_free_list;
1133           gtk_object_data_free_list = odata->next;
1134         }
1135       else
1136         {
1137           GtkObjectData *odata_block;
1138           guint i;
1139
1140           odata_block = g_new0 (GtkObjectData, GTK_OBJECT_DATA_BLOCK_SIZE);
1141           for (i = 1; i < GTK_OBJECT_DATA_BLOCK_SIZE; i++)
1142             {
1143               (odata_block + i)->next = gtk_object_data_free_list;
1144               gtk_object_data_free_list = (odata_block + i);
1145             }
1146
1147           odata = odata_block;
1148         }
1149       
1150       odata->id = data_id;
1151       odata->data = data;
1152       odata->destroy = destroy;
1153       odata->next = object->object_data;
1154       
1155       object->object_data = odata;
1156     }
1157 }
1158
1159 void
1160 gtk_object_set_data_full (GtkObject        *object,
1161                           const gchar      *key,
1162                           gpointer          data,
1163                           GtkDestroyNotify  destroy)
1164 {
1165   g_return_if_fail (key != NULL);
1166
1167   gtk_object_set_data_by_id_full (object, gtk_object_data_force_id (key), data, destroy);
1168 }
1169
1170 gpointer
1171 gtk_object_get_data_by_id (GtkObject   *object,
1172                            GQuark       data_id)
1173 {
1174   GtkObjectData *odata;
1175
1176   g_return_val_if_fail (object != NULL, NULL);
1177   g_return_val_if_fail (GTK_IS_OBJECT (object), NULL);
1178
1179   if (data_id)
1180     {
1181       odata = object->object_data;
1182       while (odata)
1183         {
1184           if (odata->id == data_id)
1185             return odata->data;
1186           odata = odata->next;
1187         }
1188     }
1189   
1190   return NULL;
1191 }
1192
1193 gpointer
1194 gtk_object_get_data (GtkObject   *object,
1195                      const gchar *key)
1196 {
1197   guint id;
1198
1199   g_return_val_if_fail (key != NULL, NULL);
1200
1201   id = gtk_object_data_try_key (key);
1202   if (id)
1203     return gtk_object_get_data_by_id (object, id);
1204
1205   return NULL;
1206 }
1207
1208 void
1209 gtk_object_remove_data_by_id (GtkObject   *object,
1210                               GQuark       data_id)
1211 {
1212   if (data_id)
1213     gtk_object_set_data_by_id_full (object, data_id, NULL, NULL);
1214 }
1215
1216 void
1217 gtk_object_remove_data (GtkObject   *object,
1218                         const gchar *key)
1219 {
1220   gint id;
1221
1222   g_return_if_fail (key != NULL);
1223
1224   id = gtk_object_data_try_key (key);
1225   if (id)
1226     gtk_object_set_data_by_id_full (object, id, NULL, NULL);
1227 }
1228
1229 /*****************************************
1230  * gtk_object_set_user_data:
1231  *
1232  *   arguments:
1233  *
1234  *   results:
1235  *****************************************/
1236
1237 void
1238 gtk_object_set_user_data (GtkObject *object,
1239                           gpointer   data)
1240 {
1241   if (!user_data_key_id)
1242     user_data_key_id = g_quark_from_static_string (user_data_key);
1243
1244   gtk_object_set_data_by_id_full (object, user_data_key_id, data, NULL);
1245 }
1246
1247 /*****************************************
1248  * gtk_object_get_user_data:
1249  *
1250  *   arguments:
1251  *
1252  *   results:
1253  *****************************************/
1254
1255 gpointer
1256 gtk_object_get_user_data (GtkObject *object)
1257 {
1258   if (user_data_key_id)
1259     return gtk_object_get_data_by_id (object, user_data_key_id);
1260
1261   return NULL;
1262 }
1263
1264 /*****************************************
1265  * gtk_object_check_cast:
1266  *
1267  *   arguments:
1268  *
1269  *   results:
1270  *****************************************/
1271
1272 static gchar*
1273 gtk_object_descriptive_type_name (GtkType type)
1274 {
1275   gchar *name;
1276
1277   name = gtk_type_name (type);
1278   if (!name)
1279     name = "(unknown)";
1280
1281   return name;
1282 }
1283
1284 GtkObject*
1285 gtk_object_check_cast (GtkObject *obj,
1286                        GtkType    cast_type)
1287 {
1288   if (!obj)
1289     {
1290       g_warning ("invalid cast from (NULL) pointer to `%s'",
1291                  gtk_object_descriptive_type_name (cast_type));
1292       return obj;
1293     }
1294   if (!obj->klass)
1295     {
1296       g_warning ("invalid unclassed pointer in cast to `%s'",
1297                  gtk_object_descriptive_type_name (cast_type));
1298       return obj;
1299     }
1300   if (obj->klass->type < GTK_TYPE_OBJECT)
1301     {
1302       g_warning ("invalid class type `%s' in cast to `%s'",
1303                  gtk_object_descriptive_type_name (obj->klass->type),
1304                  gtk_object_descriptive_type_name (cast_type));
1305       return obj;
1306     }
1307   if (!gtk_type_is_a (obj->klass->type, cast_type))
1308     {
1309       g_warning ("invalid cast from `%s' to `%s'",
1310                  gtk_object_descriptive_type_name (obj->klass->type),
1311                  gtk_object_descriptive_type_name (cast_type));
1312       return obj;
1313     }
1314   
1315   return obj;
1316 }
1317
1318 /*****************************************
1319  * gtk_object_check_class_cast:
1320  *
1321  *   arguments:
1322  *
1323  *   results:
1324  *****************************************/
1325
1326 GtkObjectClass*
1327 gtk_object_check_class_cast (GtkObjectClass *klass,
1328                              GtkType         cast_type)
1329 {
1330   if (!klass)
1331     {
1332       g_warning ("invalid class cast from (NULL) pointer to `%s'",
1333                  gtk_object_descriptive_type_name (cast_type));
1334       return klass;
1335     }
1336   if (klass->type < GTK_TYPE_OBJECT)
1337     {
1338       g_warning ("invalid class type `%s' in class cast to `%s'",
1339                  gtk_object_descriptive_type_name (klass->type),
1340                  gtk_object_descriptive_type_name (cast_type));
1341       return klass;
1342     }
1343   if (!gtk_type_is_a (klass->type, cast_type))
1344     {
1345       g_warning ("invalid class cast from `%s' to `%s'",
1346                  gtk_object_descriptive_type_name (klass->type),
1347                  gtk_object_descriptive_type_name (cast_type));
1348       return klass;
1349     }
1350
1351   return klass;
1352 }
1353
1354 /*****************************************
1355  * gtk_object_collect_args:
1356  *
1357  *   arguments:
1358  *
1359  *   results:
1360  *****************************************/
1361
1362 GtkArg*
1363 gtk_object_collect_args (guint   *nargs,
1364                          GtkType (*get_arg_type) (const gchar*),
1365                          va_list  args1,
1366                          va_list  args2)
1367 {
1368   GtkArg *args;
1369   GtkType type;
1370   gchar *name;
1371   gint done;
1372   gint i, n;
1373
1374   n = 0;
1375   done = FALSE;
1376
1377   while (!done)
1378     {
1379       name = va_arg (args1, char *);
1380       if (!name)
1381         {
1382           done = TRUE;
1383           continue;
1384         }
1385
1386       type = get_arg_type (name);
1387
1388       switch (GTK_FUNDAMENTAL_TYPE (type))
1389         {
1390         case GTK_TYPE_INVALID:
1391           g_warning ("GTK: invalid arg name: \"%s\" %x\n", name, type);
1392           (void) va_arg (args1, long);
1393           continue;
1394         case GTK_TYPE_NONE:
1395           break;
1396         case GTK_TYPE_CHAR:
1397         case GTK_TYPE_BOOL:
1398         case GTK_TYPE_INT:
1399         case GTK_TYPE_UINT:
1400         case GTK_TYPE_ENUM:
1401         case GTK_TYPE_FLAGS:
1402           (void) va_arg (args1, gint);
1403           break;
1404         case GTK_TYPE_LONG:
1405         case GTK_TYPE_ULONG:
1406           (void) va_arg (args1, glong);
1407           break;
1408         case GTK_TYPE_FLOAT:
1409           (void) va_arg (args1, gfloat);
1410           break;
1411         case GTK_TYPE_DOUBLE:
1412           (void) va_arg (args1, gdouble);
1413           break;
1414         case GTK_TYPE_STRING:
1415           (void) va_arg (args1, gchar*);
1416           break;
1417         case GTK_TYPE_POINTER:
1418         case GTK_TYPE_BOXED:
1419           (void) va_arg (args1, gpointer);
1420           break;
1421         case GTK_TYPE_SIGNAL:
1422           (void) va_arg (args1, GtkFunction);
1423           (void) va_arg (args1, gpointer);
1424           break;
1425         case GTK_TYPE_FOREIGN:
1426           (void) va_arg (args1, gpointer);
1427           (void) va_arg (args1, GtkDestroyNotify);
1428           break;
1429         case GTK_TYPE_CALLBACK:
1430           (void) va_arg (args1, GtkCallbackMarshal);
1431           (void) va_arg (args1, gpointer);
1432           (void) va_arg (args1, GtkDestroyNotify);
1433           break;
1434         case GTK_TYPE_C_CALLBACK:
1435           (void) va_arg (args1, GtkFunction);
1436           (void) va_arg (args1, gpointer);
1437           break;
1438         case GTK_TYPE_ARGS:
1439           (void) va_arg (args1, gint);
1440           (void) va_arg (args1, GtkArg*);
1441           break;
1442         case GTK_TYPE_OBJECT:
1443           (void) va_arg (args1, GtkObject*);
1444           break;
1445         default:
1446           g_error ("unsupported type %s in args", gtk_type_name (type));
1447           break;
1448         }
1449
1450       n += 1;
1451     }
1452
1453   *nargs = n;
1454   args = NULL;
1455
1456   if (n > 0)
1457     {
1458       args = g_new0 (GtkArg, n);
1459
1460       for (i = 0; i < n; i++)
1461         {
1462           args[i].name = va_arg (args2, char *);
1463           args[i].type = get_arg_type (args[i].name);
1464
1465           switch (GTK_FUNDAMENTAL_TYPE (args[i].type))
1466             {
1467             case GTK_TYPE_INVALID:
1468               (void) va_arg (args2, long);
1469               i -= 1;
1470               continue;
1471             case GTK_TYPE_NONE:
1472               break;
1473             case GTK_TYPE_CHAR:
1474               GTK_VALUE_CHAR(args[i]) = va_arg (args2, gint);
1475               break;
1476             case GTK_TYPE_BOOL:
1477               GTK_VALUE_BOOL(args[i]) = va_arg (args2, gint);
1478               break;
1479             case GTK_TYPE_INT:
1480               GTK_VALUE_INT(args[i]) = va_arg (args2, gint);
1481               break;
1482             case GTK_TYPE_UINT:
1483               GTK_VALUE_UINT(args[i]) = va_arg (args2, guint);
1484               break;
1485             case GTK_TYPE_ENUM:
1486               GTK_VALUE_ENUM(args[i]) = va_arg (args2, gint);
1487               break;
1488             case GTK_TYPE_FLAGS:
1489               GTK_VALUE_FLAGS(args[i]) = va_arg (args2, gint);
1490               break;
1491             case GTK_TYPE_LONG:
1492               GTK_VALUE_LONG(args[i]) = va_arg (args2, glong);
1493               break;
1494             case GTK_TYPE_ULONG:
1495               GTK_VALUE_ULONG(args[i]) = va_arg (args2, gulong);
1496               break;
1497             case GTK_TYPE_FLOAT:
1498               GTK_VALUE_FLOAT(args[i]) = va_arg (args2, gfloat);
1499               break;
1500             case GTK_TYPE_DOUBLE:
1501               GTK_VALUE_DOUBLE(args[i]) = va_arg (args2, gdouble);
1502               break;
1503             case GTK_TYPE_STRING:
1504               GTK_VALUE_STRING(args[i]) = va_arg (args2, gchar*);
1505               break;
1506             case GTK_TYPE_POINTER:
1507               GTK_VALUE_POINTER(args[i]) = va_arg (args2, gpointer);
1508               break;
1509             case GTK_TYPE_BOXED:
1510               GTK_VALUE_BOXED(args[i]) = va_arg (args2, gpointer);
1511               break;
1512             case GTK_TYPE_SIGNAL:
1513               GTK_VALUE_SIGNAL(args[i]).f = va_arg (args2, GtkFunction);
1514               GTK_VALUE_SIGNAL(args[i]).d = va_arg (args2, gpointer);
1515               break;
1516             case GTK_TYPE_FOREIGN:
1517               GTK_VALUE_FOREIGN(args[i]).data = va_arg (args2, gpointer);
1518               GTK_VALUE_FOREIGN(args[i]).notify =
1519                 va_arg (args2, GtkDestroyNotify);
1520               break;
1521             case GTK_TYPE_CALLBACK:
1522               GTK_VALUE_CALLBACK(args[i]).marshal =
1523                 va_arg (args2, GtkCallbackMarshal);
1524               GTK_VALUE_CALLBACK(args[i]).data = va_arg (args2, gpointer);
1525               GTK_VALUE_CALLBACK(args[i]).notify =
1526                 va_arg (args2, GtkDestroyNotify);
1527               break;
1528             case GTK_TYPE_C_CALLBACK:
1529               GTK_VALUE_C_CALLBACK(args[i]).func = va_arg (args2, GtkFunction);
1530               GTK_VALUE_C_CALLBACK(args[i]).func_data =
1531                 va_arg (args2, gpointer);
1532               break;
1533             case GTK_TYPE_ARGS:
1534               GTK_VALUE_ARGS(args[i]).n_args = va_arg (args2, gint);
1535               GTK_VALUE_ARGS(args[i]).args = va_arg (args2, GtkArg*);
1536               break;
1537             case GTK_TYPE_OBJECT:
1538               GTK_VALUE_OBJECT(args[i]) = va_arg (args2, GtkObject*);
1539               g_assert (GTK_VALUE_OBJECT(args[i]) == NULL ||
1540                         GTK_CHECK_TYPE (GTK_VALUE_OBJECT(args[i]),
1541                                         args[i].type));
1542               break;
1543             default:
1544               g_error ("unsupported type %s in args",
1545                        gtk_type_name (args[i].type));
1546               break;
1547             }
1548         }
1549     }
1550
1551   return args;
1552 }
1553
1554
1555
1556 #undef  gtk_object_ref
1557 #undef  gtk_object_unref
1558
1559 void
1560 gtk_object_ref (GtkObject *object)
1561 {
1562   g_return_if_fail (object != NULL);
1563   g_return_if_fail (GTK_IS_OBJECT (object));
1564
1565   object->ref_count += 1;
1566 }
1567
1568 void
1569 gtk_object_unref (GtkObject *object)
1570 {
1571   g_return_if_fail (object != NULL);
1572   g_return_if_fail (GTK_IS_OBJECT (object));
1573   
1574   if (object->ref_count == 1)
1575     gtk_object_destroy (object);
1576   
1577   if (object->ref_count > 0)
1578     object->ref_count -= 1;
1579
1580   if (object->ref_count == 0)
1581     {
1582 #ifdef G_ENABLE_DEBUG
1583       if (gtk_debug_flags & GTK_DEBUG_OBJECTS)
1584         {
1585           g_assert (g_hash_table_lookup (living_objs_ht, object) == object);
1586           g_hash_table_remove (living_objs_ht, object);
1587           obj_count--;
1588         }
1589 #endif /* G_ENABLE_DEBUG */      
1590       object->klass->finalize (object);
1591     }
1592 }
1593
1594 static GtkObject *gtk_trace_object = NULL;
1595 void
1596 gtk_trace_referencing (GtkObject   *object,
1597                        const gchar *func,
1598                        guint       dummy,
1599                        guint       line,
1600                        gboolean    do_ref)
1601 {
1602   if (gtk_debug_flags & GTK_DEBUG_OBJECTS)
1603     {
1604       gboolean exists = TRUE;
1605
1606       g_return_if_fail (object != NULL);
1607       g_return_if_fail (GTK_IS_OBJECT (object));
1608
1609 #ifdef  G_ENABLE_DEBUG
1610       exists = g_hash_table_lookup (living_objs_ht, object) != NULL;
1611 #endif  /* G_ENABLE_DEBUG */
1612       
1613       if (exists &&
1614           (object == gtk_trace_object ||
1615            gtk_trace_object == (void*)42))
1616         fprintf (stdout, "trace: object_%s: (%s:%p)->ref_count=%d %s (%s:%d)\n",
1617                  do_ref ? "ref" : "unref",
1618                  gtk_type_name (GTK_OBJECT_TYPE (object)),
1619                  object,
1620                  object->ref_count,
1621                  do_ref ? "+ 1" : "- 1",
1622                  func,
1623                  line);
1624       else if (!exists)
1625         fprintf (stdout, "trace: object_%s(%p): no such object! (%s:%d)\n",
1626                  do_ref ? "ref" : "unref",
1627                  object,
1628                  func,
1629                  line);
1630     }
1631   
1632   if (do_ref)
1633     gtk_object_ref (object);
1634   else
1635     gtk_object_unref (object);
1636 }