]> Pileus Git - ~andy/gtk/blob - gtk/gtkobject.c
use g_atexit() instead of ATEXIT.
[~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 "gtkobject.h"
23 #include "gtksignal.h"
24
25
26 #define GTK_OBJECT_DATA_ID_BLOCK_SIZE   (1024)
27 #define GTK_OBJECT_DATA_BLOCK_SIZE      (1024)
28
29 enum {
30   DESTROY,
31   LAST_SIGNAL
32 };
33 enum {
34   ARG_0,
35   ARG_USER_DATA,
36   ARG_SIGNAL,
37   ARG_SIGNAL_AFTER,
38   ARG_OBJECT_SIGNAL,
39   ARG_OBJECT_SIGNAL_AFTER
40 };
41
42
43 typedef struct _GtkObjectData  GtkObjectData;
44
45 struct _GtkObjectData
46 {
47   guint id;
48   gpointer data;
49   GtkDestroyNotify destroy;
50   GtkObjectData *next;
51 };
52
53
54 void                  gtk_object_init_type       (void);
55 static void           gtk_object_base_class_init (GtkObjectClass *klass);
56 static void           gtk_object_class_init      (GtkObjectClass *klass);
57 static void           gtk_object_init            (GtkObject      *object);
58 static void           gtk_object_set_arg         (GtkObject      *object,
59                                                   GtkArg         *arg,
60                                                   guint           arg_id);
61 static void           gtk_object_get_arg         (GtkObject      *object,
62                                                   GtkArg         *arg,
63                                                   guint           arg_id);
64 static void           gtk_object_shutdown        (GtkObject      *object);
65 static void           gtk_object_real_destroy    (GtkObject      *object);
66 static void           gtk_object_finalize        (GtkObject      *object);
67 static void           gtk_object_notify_weaks    (GtkObject      *object);
68
69 static guint object_signals[LAST_SIGNAL] = { 0 };
70
71 static GHashTable *object_arg_info_ht = NULL;
72
73 static const gchar *user_data_key = "user_data";
74 static guint user_data_key_id = 0;
75 static const gchar *weakrefs_key = "gtk-weakrefs";
76 static guint weakrefs_key_id = 0;
77
78 static GtkObjectData *gtk_object_data_free_list = NULL;
79
80 #define GTK_OBJECT_DATA_DESTROY( odata )        { \
81   if (odata->destroy) \
82     odata->destroy (odata->data); \
83   odata->next = gtk_object_data_free_list; \
84   gtk_object_data_free_list = odata; \
85 }
86
87
88 #ifdef G_ENABLE_DEBUG
89 static guint obj_count = 0;
90 static GHashTable *living_objs_ht = NULL;
91 static void
92 gtk_object_debug_foreach (gpointer key, gpointer value, gpointer user_data)
93 {
94   GtkObject *object;
95   
96   object = (GtkObject*) value;
97   g_message ("[%p] %s\tref_count=%d%s%s",
98              object,
99              gtk_type_name (GTK_OBJECT_TYPE (object)),
100              object->ref_count,
101              GTK_OBJECT_FLOATING (object) ? " (floating)" : "",
102              GTK_OBJECT_DESTROYED (object) ? " (destroyed)" : "");
103 }
104 static void
105 gtk_object_debug (void)
106 {
107   if (living_objs_ht)
108     g_hash_table_foreach (living_objs_ht, gtk_object_debug_foreach, NULL);
109   
110   g_message ("living objects count = %d", obj_count);
111 }
112 #endif  /* G_ENABLE_DEBUG */
113
114 /****************************************************
115  * GtkObject type, class and instance initialization
116  *
117  ****************************************************/
118
119 void
120 gtk_object_init_type (void)
121 {
122   GtkType object_type = 0;
123   GtkTypeInfo object_info =
124   {
125     "GtkObject",
126     sizeof (GtkObject),
127     sizeof (GtkObjectClass),
128     (GtkClassInitFunc) gtk_object_class_init,
129     (GtkObjectInitFunc) gtk_object_init,
130     /* reserved_1 */ NULL,
131     /* reserved_2 */ NULL,
132     (GtkClassInitFunc) gtk_object_base_class_init,
133   };
134
135   object_type = gtk_type_unique (0, &object_info);
136   g_assert (object_type == GTK_TYPE_OBJECT);
137
138 #ifdef G_ENABLE_DEBUG
139   if (gtk_debug_flags & GTK_DEBUG_OBJECTS)
140     g_atexit (gtk_object_debug);
141 #endif  /* G_ENABLE_DEBUG */
142 }
143
144 GtkType
145 gtk_object_get_type (void)
146 {
147   return GTK_TYPE_OBJECT;
148 }
149
150 static void
151 gtk_object_base_class_init (GtkObjectClass *class)
152 {
153   /* reset instance specific fields that don't get inhrited */
154   class->signals = NULL;
155   class->nsignals = 0;
156   class->n_args = 0;
157
158   /* reset instance specifc methods that don't get inherited */
159   class->get_arg = NULL;
160   class->set_arg = NULL;
161 }
162
163 static void
164 gtk_object_class_init (GtkObjectClass *class)
165 {
166   gtk_object_add_arg_type ("GtkObject::user_data",
167                            GTK_TYPE_POINTER,
168                            GTK_ARG_READWRITE,
169                            ARG_USER_DATA);
170   gtk_object_add_arg_type ("GtkObject::signal",
171                            GTK_TYPE_SIGNAL,
172                            GTK_ARG_WRITABLE,
173                            ARG_SIGNAL);
174   gtk_object_add_arg_type ("GtkObject::signal_after",
175                            GTK_TYPE_SIGNAL,
176                            GTK_ARG_WRITABLE,
177                            ARG_SIGNAL_AFTER);
178   gtk_object_add_arg_type ("GtkObject::object_signal",
179                            GTK_TYPE_SIGNAL,
180                            GTK_ARG_WRITABLE,
181                            ARG_OBJECT_SIGNAL);
182   gtk_object_add_arg_type ("GtkObject::object_signal_after",
183                            GTK_TYPE_SIGNAL,
184                            GTK_ARG_WRITABLE,
185                            ARG_OBJECT_SIGNAL_AFTER);
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_marshal_NONE__NONE,
193                     GTK_TYPE_NONE, 0);
194
195   gtk_object_class_add_signals (class, object_signals, LAST_SIGNAL);
196
197   class->get_arg = gtk_object_get_arg;
198   class->set_arg = gtk_object_set_arg;
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 (g_direct_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   gtk_type_free (GTK_OBJECT_TYPE (object), 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   guint n = 0;
289
290   switch (arg_id)
291     {
292       gchar *arg_name;
293
294     case ARG_USER_DATA:
295       gtk_object_set_user_data (object, GTK_VALUE_POINTER (*arg));
296       break;
297     case ARG_OBJECT_SIGNAL_AFTER:
298       n += 6;
299     case ARG_OBJECT_SIGNAL:
300       n += 1;
301     case ARG_SIGNAL_AFTER:
302       n += 6;
303     case ARG_SIGNAL:
304       n += 6;
305       arg_name = gtk_arg_name_strip_type (arg->name);
306       if (arg_name &&
307           arg_name[n] == ':' &&
308           arg_name[n + 1] == ':' &&
309           arg_name[n + 2] != 0)
310         {
311           gtk_signal_connect_full (object,
312                                    arg_name + n + 2,
313                                    GTK_VALUE_SIGNAL (*arg).f, NULL,
314                                    GTK_VALUE_SIGNAL (*arg).d,
315                                    NULL,
316                                    (arg_id == ARG_OBJECT_SIGNAL ||
317                                     arg_id == ARG_OBJECT_SIGNAL_AFTER),
318                                    (arg_id == ARG_OBJECT_SIGNAL_AFTER ||
319                                     arg_id == ARG_SIGNAL_AFTER));
320         }
321       else
322         g_warning ("gtk_object_set_arg(): invalid signal argument: \"%s\"\n", arg->name);
323       break;
324     default:
325       break;
326     }
327 }
328
329 static void
330 gtk_object_get_arg (GtkObject *object,
331                     GtkArg    *arg,
332                     guint      arg_id)
333 {
334   switch (arg_id)
335     {
336     case ARG_USER_DATA:
337       GTK_VALUE_POINTER (*arg) = gtk_object_get_user_data (object);
338       break;
339     case ARG_SIGNAL:
340     case ARG_OBJECT_SIGNAL:
341     default:
342       arg->type = GTK_TYPE_INVALID;
343       break;
344     }
345 }
346
347 /*****************************************
348  * gtk_object_class_add_signals:
349  *
350  *   arguments:
351  *
352  *   results:
353  *****************************************/
354
355 void
356 gtk_object_class_add_signals (GtkObjectClass *class,
357                               guint          *signals,
358                               guint           nsignals)
359 {
360   guint *new_signals;
361   guint i;
362
363   g_return_if_fail (class != NULL);
364
365   new_signals = g_new (guint, class->nsignals + nsignals);
366   for (i = 0; i < class->nsignals; i++)
367     new_signals[i] = class->signals[i];
368   for (i = 0; i < nsignals; i++)
369     new_signals[class->nsignals + i] = signals[i];
370
371   g_free (class->signals);
372   class->signals = new_signals;
373   class->nsignals += nsignals;
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 guint
423 gtk_object_class_user_signal_new (GtkObjectClass     *class,
424                                   const gchar        *name,
425                                   GtkSignalRunType    signal_flags,
426                                   GtkSignalMarshaller marshaller,
427                                   GtkType             return_val,
428                                   guint               nparams,
429                                   ...)
430 {
431   GtkType *params;
432   guint i;
433   va_list args;
434   guint signal_id;
435
436   g_return_val_if_fail (class != NULL, 0);
437
438   if (nparams > 0)
439     {
440       params = g_new (GtkType, nparams);
441
442       va_start (args, nparams);
443
444       for (i = 0; i < nparams; i++)
445         params[i] = va_arg (args, GtkType);
446
447       va_end (args);
448     }
449   else
450     params = NULL;
451
452   signal_id = gtk_signal_newv (name,
453                                signal_flags,
454                                class->type,
455                                0,
456                                marshaller,
457                                return_val,
458                                nparams,
459                                params);
460
461   g_free (params);
462
463   if (signal_id)
464     gtk_object_class_add_signals (class, &signal_id, 1);
465
466   return signal_id;
467 }
468
469 guint
470 gtk_object_class_user_signal_newv (GtkObjectClass     *class,
471                                    const gchar        *name,
472                                    GtkSignalRunType    signal_flags,
473                                    GtkSignalMarshaller marshaller,
474                                    GtkType             return_val,
475                                    guint               nparams,
476                                    GtkType            *params)
477 {
478   guint signal_id;
479
480   g_return_val_if_fail (class != NULL, 0);
481
482   if (nparams > 0)
483     g_return_val_if_fail (params != NULL, 0);
484
485   signal_id = gtk_signal_newv (name,
486                                signal_flags,
487                                class->type,
488                                0,
489                                marshaller,
490                                return_val,
491                                nparams,
492                                params);
493
494   if (signal_id)
495     gtk_object_class_add_signals (class, &signal_id, 1);
496
497   return signal_id;
498 }
499
500 /*****************************************
501  * gtk_object_sink:
502  *
503  *   arguments:
504  *
505  *   results:
506  *****************************************/
507
508 void
509 gtk_object_sink (GtkObject *object)
510 {
511   g_return_if_fail (object != NULL);
512   g_return_if_fail (GTK_IS_OBJECT (object));
513
514   if (GTK_OBJECT_FLOATING (object))
515     {
516       GTK_OBJECT_UNSET_FLAGS (object, GTK_FLOATING);
517       gtk_object_unref (object);
518     }
519 }
520
521 /*****************************************
522  * Weak references.
523  *
524  * Weak refs are very similar to the old "destroy" signal.  They allow
525  * one to register a callback that is called when the weakly
526  * referenced object is finalized.
527  *  
528  * They are not implemented as a signal because they really are
529  * special and need to be used with great care.  Unlike signals, which
530  * should be able to execute any code whatsoever.
531  * 
532  * A weakref callback is not allowed to retain a reference to the
533  * object.  Object data keys may be retrieved in a weak reference
534  * callback.
535  * 
536  * A weakref callback is called at most once.
537  *
538  *****************************************/
539
540 typedef struct _GtkWeakRef      GtkWeakRef;
541
542 struct _GtkWeakRef
543 {
544   GtkWeakRef       *next;
545   GtkDestroyNotify  notify;
546   gpointer          data;
547 };
548
549 void
550 gtk_object_weakref (GtkObject        *object,
551                     GtkDestroyNotify  notify,
552                     gpointer          data)
553 {
554   GtkWeakRef *weak;
555
556   g_return_if_fail (object != NULL);
557   g_return_if_fail (notify != NULL);
558   g_return_if_fail (GTK_IS_OBJECT (object));
559
560   if (!weakrefs_key_id)
561     weakrefs_key_id = g_quark_from_static_string (weakrefs_key);
562
563   weak = g_new (GtkWeakRef, 1);
564   weak->next = gtk_object_get_data_by_id (object, weakrefs_key_id);
565   weak->notify = notify;
566   weak->data = data;
567   gtk_object_set_data_by_id (object, weakrefs_key_id, weak);
568 }
569
570 void
571 gtk_object_weakunref (GtkObject        *object,
572                       GtkDestroyNotify  notify,
573                       gpointer          data)
574 {
575   GtkWeakRef *weaks, *w, **wp;
576
577   g_return_if_fail (object != NULL);
578   g_return_if_fail (GTK_IS_OBJECT (object));
579
580   if (!weakrefs_key_id)
581     return;
582
583   weaks = gtk_object_get_data_by_id (object, weakrefs_key_id);
584   for (wp = &weaks; *wp; wp = &(*wp)->next)
585     {
586       w = *wp;
587       if (w->notify == notify && w->data == data)
588         {
589           if (w == weaks)
590             gtk_object_set_data_by_id (object, weakrefs_key_id, w->next);
591           else
592             *wp = w->next;
593           g_free (w);
594           return;
595         }
596     }
597 }
598
599 static void
600 gtk_object_notify_weaks (GtkObject *object)
601 {
602   if (weakrefs_key_id)
603     {
604       GtkWeakRef *w1, *w2;
605       
606       w1 = gtk_object_get_data_by_id (object, weakrefs_key_id);
607       
608       while (w1)
609         {
610           w1->notify (w1->data);
611           w2 = w1->next;
612           g_free (w1);
613           w1 = w2;
614         }
615     }
616 }
617
618 /****************************************************
619  * GtkObject argument mechanism and object creation
620  *
621  ****************************************************/
622
623 GtkObject*
624 gtk_object_new (GtkType      object_type,
625                 const gchar *first_arg_name,
626                 ...)
627 {
628   GtkObject *object;
629   va_list var_args;
630   GSList *arg_list = NULL;
631   GSList *info_list = NULL;
632   gchar *error;
633
634   g_return_val_if_fail (GTK_FUNDAMENTAL_TYPE (object_type) == GTK_TYPE_OBJECT, NULL);
635
636   object = gtk_type_new (object_type);
637
638   va_start (var_args, first_arg_name);
639   error = gtk_object_args_collect (GTK_OBJECT_TYPE (object),
640                                    &arg_list,
641                                    &info_list,
642                                    first_arg_name,
643                                    var_args);
644   va_end (var_args);
645   
646   if (error)
647     {
648       g_warning ("gtk_object_new(): %s", error);
649       g_free (error);
650     }
651   else
652     {
653       GSList *slist_arg;
654       GSList *slist_info;
655       
656       slist_arg = arg_list;
657       slist_info = info_list;
658       while (slist_arg)
659         {
660           gtk_object_arg_set (object, slist_arg->data, slist_info->data);
661           slist_arg = slist_arg->next;
662           slist_info = slist_info->next;
663         }
664       gtk_args_collect_cleanup (arg_list, info_list);
665     }
666
667   return object;
668 }
669
670 GtkObject*
671 gtk_object_newv (GtkType  object_type,
672                  guint    n_args,
673                  GtkArg  *args)
674 {
675   GtkObject *object;
676   GtkArg *max_args;
677   
678   g_return_val_if_fail (GTK_FUNDAMENTAL_TYPE (object_type) == GTK_TYPE_OBJECT, NULL);
679   if (n_args)
680     g_return_val_if_fail (args != NULL, NULL);
681   
682   object = gtk_type_new (object_type);
683   
684   for (max_args = args + n_args; args < max_args; args++)
685     gtk_object_arg_set (object, args, NULL);
686   
687   return object;
688 }
689
690 void
691 gtk_object_setv (GtkObject *object,
692                  guint      n_args,
693                  GtkArg    *args)
694 {
695   GtkArg *max_args;
696   
697   g_return_if_fail (object != NULL);
698   g_return_if_fail (GTK_IS_OBJECT (object));
699   if (n_args)
700     g_return_if_fail (args != NULL);
701
702   for (max_args = args + n_args; args < max_args; args++)
703     gtk_object_arg_set (object, args, NULL);
704 }
705
706 void
707 gtk_object_getv (GtkObject           *object,
708                  guint                n_args,
709                  GtkArg              *args)
710 {
711   GtkArg *max_args;
712   
713   g_return_if_fail (object != NULL);
714   g_return_if_fail (GTK_IS_OBJECT (object));
715   if (n_args)
716     g_return_if_fail (args != NULL);
717   
718   for (max_args = args + n_args; args < max_args; args++)
719     gtk_object_arg_get (object, args, NULL);
720 }
721
722 void
723 gtk_object_set (GtkObject *object,
724                 const gchar    *first_arg_name,
725                 ...)
726 {
727   va_list var_args;
728   GSList *arg_list = NULL;
729   GSList *info_list = NULL;
730   gchar *error;
731   
732   g_return_if_fail (object != NULL);
733   g_return_if_fail (GTK_IS_OBJECT (object));
734   
735   va_start (var_args, first_arg_name);
736   error = gtk_object_args_collect (GTK_OBJECT_TYPE (object),
737                                    &arg_list,
738                                    &info_list,
739                                    first_arg_name,
740                                    var_args);
741   va_end (var_args);
742   
743   if (error)
744     {
745       g_warning ("gtk_object_set(): %s", error);
746       g_free (error);
747     }
748   else
749     {
750       GSList *slist_arg;
751       GSList *slist_info;
752       
753       slist_arg = arg_list;
754       slist_info = info_list;
755       while (slist_arg)
756         {
757           gtk_object_arg_set (object, slist_arg->data, slist_info->data);
758           slist_arg = slist_arg->next;
759           slist_info = slist_info->next;
760         }
761       gtk_args_collect_cleanup (arg_list, info_list);
762     }
763 }
764
765 void
766 gtk_object_arg_set (GtkObject *object,
767                     GtkArg      *arg,
768                     GtkArgInfo  *info)
769 {
770   GtkObjectClass *oclass;
771
772   g_return_if_fail (object != NULL);
773   g_return_if_fail (GTK_IS_OBJECT (object));
774   g_return_if_fail (arg != NULL);
775
776   if (!info)
777     {
778       gchar *error;
779
780       error = gtk_arg_get_info (GTK_OBJECT_TYPE (object),
781                                 object_arg_info_ht,
782                                 arg->name,
783                                 &info);
784       if (error)
785         {
786           g_warning ("gtk_object_arg_set(): %s", error);
787           g_free (error);
788           return;
789         }
790     }
791   
792   if (! (info->arg_flags & GTK_ARG_WRITABLE))
793     {
794       g_warning ("gtk_object_arg_set(): argument \"%s\" is not writable",
795                  info->full_name);
796       return;
797     }
798   if (info->type != arg->type)
799     {
800       g_warning ("gtk_object_arg_set(): argument \"%s\" has invalid type `%s'",
801                  info->full_name,
802                  gtk_type_name (arg->type));
803       return;
804     }
805   
806   oclass = gtk_type_class (info->class_type);
807   g_assert (oclass->set_arg != NULL);
808   oclass->set_arg (object, arg, info->arg_id);
809 }
810
811 void
812 gtk_object_arg_get (GtkObject           *object,
813                     GtkArg              *arg,
814                     GtkArgInfo          *info)
815 {
816   GtkObjectClass *oclass;
817   
818   g_return_if_fail (object != NULL);
819   g_return_if_fail (GTK_IS_OBJECT (object));
820   g_return_if_fail (arg != NULL);
821
822   if (!info)
823     {
824       gchar *error;
825
826       error = gtk_arg_get_info (GTK_OBJECT_TYPE (object),
827                                 object_arg_info_ht,
828                                 arg->name,
829                                 &info);
830       if (error)
831         {
832           g_warning ("gtk_object_arg_get(): %s", error);
833           g_free (error);
834           arg->type = GTK_TYPE_INVALID;
835           return;
836         }
837     }
838   
839   if (! (info->arg_flags & GTK_ARG_READABLE))
840     {
841       g_warning ("gtk_object_arg_get(): argument \"%s\" is not readable",
842                  info->full_name);
843       arg->type = GTK_TYPE_INVALID;
844       return;
845     }
846   
847   oclass = gtk_type_class (info->class_type);
848   g_assert (oclass->get_arg != NULL);
849   arg->type = info->type;
850   oclass->get_arg (object, arg, info->arg_id);
851 }
852
853 void
854 gtk_object_add_arg_type (const char *arg_name,
855                          GtkType     arg_type,
856                          guint       arg_flags,
857                          guint       arg_id)
858 {
859   g_return_if_fail (arg_name != NULL);
860   g_return_if_fail (arg_type > GTK_TYPE_NONE);
861   g_return_if_fail (arg_id > 0);
862   g_return_if_fail ((arg_flags & GTK_ARG_CHILD_ARG) == 0);
863   if (arg_flags & GTK_ARG_CONSTRUCT)
864     g_return_if_fail ((arg_flags & GTK_ARG_READWRITE) == GTK_ARG_READWRITE);
865   else
866     g_return_if_fail ((arg_flags & GTK_ARG_READWRITE) != 0);
867     
868   if (!object_arg_info_ht)
869     object_arg_info_ht = g_hash_table_new (gtk_arg_info_hash,
870                                            gtk_arg_info_equal);
871
872   gtk_arg_type_new_static (GTK_TYPE_OBJECT,
873                            arg_name,
874                            GTK_STRUCT_OFFSET (GtkObjectClass, n_args),
875                            object_arg_info_ht,
876                            arg_type,
877                            arg_flags,
878                            arg_id);
879 }
880
881 gchar*
882 gtk_object_args_collect (GtkType      object_type,
883                          GSList      **arg_list_p,
884                          GSList      **info_list_p,
885                          const gchar  *first_arg_name,
886                          va_list       var_args)
887 {
888   return gtk_args_collect (object_type,
889                            object_arg_info_ht,
890                            arg_list_p,
891                            info_list_p,
892                            first_arg_name,
893                            var_args);
894 }
895
896 gchar*
897 gtk_object_arg_get_info (GtkType      object_type,
898                          const gchar *arg_name,
899                          GtkArgInfo **info_p)
900 {
901   return gtk_arg_get_info (object_type,
902                            object_arg_info_ht,
903                            arg_name,
904                            info_p);
905 }
906
907 GtkArg*
908 gtk_object_query_args (GtkType        class_type,
909                        guint32      **arg_flags,
910                        guint         *n_args)
911 {
912   g_return_val_if_fail (n_args != NULL, NULL);
913   *n_args = 0;
914   g_return_val_if_fail (GTK_FUNDAMENTAL_TYPE (class_type) == GTK_TYPE_OBJECT, NULL);
915
916   return gtk_args_query (class_type, object_arg_info_ht, arg_flags, n_args);
917 }
918
919 /*****************************************
920  * GtkObject object_data mechanism
921  *
922  *****************************************/
923
924 void
925 gtk_object_set_data_by_id (GtkObject        *object,
926                            GQuark            data_id,
927                            gpointer          data)
928 {
929   g_return_if_fail (data_id > 0);
930   
931   gtk_object_set_data_by_id_full (object, data_id, data, NULL);
932 }
933
934 void
935 gtk_object_set_data (GtkObject        *object,
936                      const gchar      *key,
937                      gpointer          data)
938 {
939   g_return_if_fail (key != NULL);
940   
941   gtk_object_set_data_by_id_full (object, gtk_object_data_force_id (key), data, NULL);
942 }
943
944 void
945 gtk_object_set_data_by_id_full (GtkObject        *object,
946                                 GQuark            data_id,
947                                 gpointer          data,
948                                 GtkDestroyNotify  destroy)
949 {
950   GtkObjectData *odata;
951   
952   g_return_if_fail (object != NULL);
953   g_return_if_fail (GTK_IS_OBJECT (object));
954   g_return_if_fail (data_id > 0);
955
956   odata = object->object_data;
957   if (!data)
958     {
959       GtkObjectData *prev;
960       
961       prev = NULL;
962       
963       while (odata)
964         {
965           if (odata->id == data_id)
966             {
967               if (prev)
968                 prev->next = odata->next;
969               else
970                 object->object_data = odata->next;
971               
972               GTK_OBJECT_DATA_DESTROY (odata);
973               return;
974             }
975           
976           prev = odata;
977           odata = odata->next;
978         }
979     }
980   else
981     {
982       while (odata)
983         {
984           if (odata->id == data_id)
985             {
986               register GtkDestroyNotify dfunc;
987               register gpointer ddata;
988
989               dfunc = odata->destroy;
990               ddata = odata->data;
991               odata->destroy = destroy;
992               odata->data = data;
993
994               /* we need to have updated all structures prior to
995                * invokation of the destroy function
996                */
997               if (dfunc)
998                 dfunc (ddata);
999
1000               return;
1001             }
1002
1003           odata = odata->next;
1004         }
1005       
1006       if (gtk_object_data_free_list)
1007         {
1008           odata = gtk_object_data_free_list;
1009           gtk_object_data_free_list = odata->next;
1010         }
1011       else
1012         {
1013           GtkObjectData *odata_block;
1014           guint i;
1015
1016           odata_block = g_new0 (GtkObjectData, GTK_OBJECT_DATA_BLOCK_SIZE);
1017           for (i = 1; i < GTK_OBJECT_DATA_BLOCK_SIZE; i++)
1018             {
1019               (odata_block + i)->next = gtk_object_data_free_list;
1020               gtk_object_data_free_list = (odata_block + i);
1021             }
1022
1023           odata = odata_block;
1024         }
1025       
1026       odata->id = data_id;
1027       odata->data = data;
1028       odata->destroy = destroy;
1029       odata->next = object->object_data;
1030       
1031       object->object_data = odata;
1032     }
1033 }
1034
1035 void
1036 gtk_object_set_data_full (GtkObject        *object,
1037                           const gchar      *key,
1038                           gpointer          data,
1039                           GtkDestroyNotify  destroy)
1040 {
1041   g_return_if_fail (key != NULL);
1042
1043   gtk_object_set_data_by_id_full (object, gtk_object_data_force_id (key), data, destroy);
1044 }
1045
1046 gpointer
1047 gtk_object_get_data_by_id (GtkObject   *object,
1048                            GQuark       data_id)
1049 {
1050   GtkObjectData *odata;
1051
1052   g_return_val_if_fail (object != NULL, NULL);
1053   g_return_val_if_fail (GTK_IS_OBJECT (object), NULL);
1054
1055   if (data_id)
1056     {
1057       odata = object->object_data;
1058       while (odata)
1059         {
1060           if (odata->id == data_id)
1061             return odata->data;
1062           odata = odata->next;
1063         }
1064     }
1065   
1066   return NULL;
1067 }
1068
1069 gpointer
1070 gtk_object_get_data (GtkObject   *object,
1071                      const gchar *key)
1072 {
1073   guint id;
1074
1075   g_return_val_if_fail (key != NULL, NULL);
1076
1077   id = gtk_object_data_try_key (key);
1078   if (id)
1079     return gtk_object_get_data_by_id (object, id);
1080
1081   return NULL;
1082 }
1083
1084 void
1085 gtk_object_remove_data_by_id (GtkObject   *object,
1086                               GQuark       data_id)
1087 {
1088   if (data_id)
1089     gtk_object_set_data_by_id_full (object, data_id, NULL, NULL);
1090 }
1091
1092 void
1093 gtk_object_remove_data (GtkObject   *object,
1094                         const gchar *key)
1095 {
1096   gint id;
1097
1098   g_return_if_fail (key != NULL);
1099
1100   id = gtk_object_data_try_key (key);
1101   if (id)
1102     gtk_object_set_data_by_id_full (object, id, NULL, NULL);
1103 }
1104
1105 void
1106 gtk_object_set_user_data (GtkObject *object,
1107                           gpointer   data)
1108 {
1109   if (!user_data_key_id)
1110     user_data_key_id = g_quark_from_static_string (user_data_key);
1111
1112   gtk_object_set_data_by_id_full (object, user_data_key_id, data, NULL);
1113 }
1114
1115 gpointer
1116 gtk_object_get_user_data (GtkObject *object)
1117 {
1118   if (user_data_key_id)
1119     return gtk_object_get_data_by_id (object, user_data_key_id);
1120
1121   return NULL;
1122 }
1123
1124 /*******************************************
1125  * GtkObject referencing and unreferencing
1126  *
1127  *******************************************/
1128
1129 #undef  gtk_object_ref
1130 #undef  gtk_object_unref
1131
1132 void
1133 gtk_object_ref (GtkObject *object)
1134 {
1135   g_return_if_fail (object != NULL);
1136   g_return_if_fail (GTK_IS_OBJECT (object));
1137
1138   object->ref_count += 1;
1139 }
1140
1141 void
1142 gtk_object_unref (GtkObject *object)
1143 {
1144   g_return_if_fail (object != NULL);
1145   g_return_if_fail (GTK_IS_OBJECT (object));
1146   
1147   if (object->ref_count == 1)
1148     gtk_object_destroy (object);
1149   
1150   if (object->ref_count > 0)
1151     object->ref_count -= 1;
1152
1153   if (object->ref_count == 0)
1154     {
1155 #ifdef G_ENABLE_DEBUG
1156       if (gtk_debug_flags & GTK_DEBUG_OBJECTS)
1157         {
1158           g_assert (g_hash_table_lookup (living_objs_ht, object) == object);
1159           g_hash_table_remove (living_objs_ht, object);
1160           obj_count--;
1161         }
1162 #endif /* G_ENABLE_DEBUG */      
1163       object->klass->finalize (object);
1164     }
1165 }
1166
1167 static GtkObject *gtk_trace_object = NULL;
1168 void
1169 gtk_trace_referencing (GtkObject   *object,
1170                        const gchar *func,
1171                        guint       dummy,
1172                        guint       line,
1173                        gboolean    do_ref)
1174 {
1175   if (gtk_debug_flags & GTK_DEBUG_OBJECTS)
1176     {
1177       gboolean exists = TRUE;
1178
1179       g_return_if_fail (object != NULL);
1180       g_return_if_fail (GTK_IS_OBJECT (object));
1181
1182 #ifdef  G_ENABLE_DEBUG
1183       exists = g_hash_table_lookup (living_objs_ht, object) != NULL;
1184 #endif  /* G_ENABLE_DEBUG */
1185       
1186       if (exists &&
1187           (object == gtk_trace_object ||
1188            gtk_trace_object == (void*)42))
1189         fprintf (stdout, "trace: object_%s: (%s:%p)->ref_count=%d %s (%s:%d)\n",
1190                  do_ref ? "ref" : "unref",
1191                  gtk_type_name (GTK_OBJECT_TYPE (object)),
1192                  object,
1193                  object->ref_count,
1194                  do_ref ? "+ 1" : "- 1",
1195                  func,
1196                  line);
1197       else if (!exists)
1198         fprintf (stdout, "trace: object_%s(%p): no such object! (%s:%d)\n",
1199                  do_ref ? "ref" : "unref",
1200                  object,
1201                  func,
1202                  line);
1203     }
1204   
1205   if (do_ref)
1206     gtk_object_ref (object);
1207   else
1208     gtk_object_unref (object);
1209 }