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