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