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