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