]> Pileus Git - ~andy/gtk/blob - gtk/gtkobject.c
f94b485d46d02ea0bb7ff03b1258519d29806c7e
[~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   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     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                 ...)
626 {
627   GtkObject *object;
628   va_list var_args;
629   GSList *arg_list = NULL;
630   GSList *info_list = NULL;
631   gchar *error;
632
633   g_return_val_if_fail (GTK_FUNDAMENTAL_TYPE (object_type) == GTK_TYPE_OBJECT, NULL);
634
635   object = gtk_type_new (object_type);
636
637   va_start (var_args, object_type);
638   error = gtk_object_args_collect (GTK_OBJECT_TYPE (object),
639                                    &arg_list,
640                                    &info_list,
641                                    &var_args);
642   va_end (var_args);
643   
644   if (error)
645     {
646       g_warning ("gtk_object_new(): %s", error);
647       g_free (error);
648     }
649   else
650     {
651       GSList *slist_arg;
652       GSList *slist_info;
653       
654       slist_arg = arg_list;
655       slist_info = info_list;
656       while (slist_arg)
657         {
658           gtk_object_arg_set (object, slist_arg->data, slist_info->data);
659           slist_arg = slist_arg->next;
660           slist_info = slist_info->next;
661         }
662       gtk_args_collect_cleanup (arg_list, info_list);
663     }
664
665   return object;
666 }
667
668 GtkObject*
669 gtk_object_newv (GtkType  object_type,
670                  guint    n_args,
671                  GtkArg  *args)
672 {
673   GtkObject *object;
674   GtkArg *max_args;
675   
676   g_return_val_if_fail (GTK_FUNDAMENTAL_TYPE (object_type) == GTK_TYPE_OBJECT, NULL);
677   if (n_args)
678     g_return_val_if_fail (args != NULL, NULL);
679   
680   object = gtk_type_new (object_type);
681   
682   for (max_args = args + n_args; args < max_args; args++)
683     gtk_object_arg_set (object, args, NULL);
684   
685   return object;
686 }
687
688 void
689 gtk_object_setv (GtkObject *object,
690                  guint      n_args,
691                  GtkArg    *args)
692 {
693   GtkArg *max_args;
694   
695   g_return_if_fail (object != NULL);
696   g_return_if_fail (GTK_IS_OBJECT (object));
697   if (n_args)
698     g_return_if_fail (args != NULL);
699
700   for (max_args = args + n_args; args < max_args; args++)
701     gtk_object_arg_set (object, args, NULL);
702 }
703
704 void
705 gtk_object_getv (GtkObject           *object,
706                  guint                n_args,
707                  GtkArg              *args)
708 {
709   GtkArg *max_args;
710   
711   g_return_if_fail (object != NULL);
712   g_return_if_fail (GTK_IS_OBJECT (object));
713   if (n_args)
714     g_return_if_fail (args != NULL);
715   
716   for (max_args = args + n_args; args < max_args; args++)
717     gtk_object_arg_get (object, args, NULL);
718 }
719
720 void
721 gtk_object_set (GtkObject *object,
722                 ...)
723 {
724   va_list var_args;
725   GSList *arg_list = NULL;
726   GSList *info_list = NULL;
727   gchar *error;
728   
729   g_return_if_fail (object != NULL);
730   g_return_if_fail (GTK_IS_OBJECT (object));
731   
732   va_start (var_args, object);
733   error = gtk_object_args_collect (GTK_OBJECT_TYPE (object),
734                                    &arg_list,
735                                    &info_list,
736                                    &var_args);
737   va_end (var_args);
738   
739   if (error)
740     {
741       g_warning ("gtk_object_set(): %s", error);
742       g_free (error);
743     }
744   else
745     {
746       GSList *slist_arg;
747       GSList *slist_info;
748       
749       slist_arg = arg_list;
750       slist_info = info_list;
751       while (slist_arg)
752         {
753           gtk_object_arg_set (object, slist_arg->data, slist_info->data);
754           slist_arg = slist_arg->next;
755           slist_info = slist_info->next;
756         }
757       gtk_args_collect_cleanup (arg_list, info_list);
758     }
759 }
760
761 void
762 gtk_object_arg_set (GtkObject *object,
763                     GtkArg      *arg,
764                     GtkArgInfo  *info)
765 {
766   GtkObjectClass *oclass;
767
768   g_return_if_fail (object != NULL);
769   g_return_if_fail (GTK_IS_OBJECT (object));
770   g_return_if_fail (arg != NULL);
771
772   if (!info)
773     {
774       gchar *error;
775
776       error = gtk_arg_get_info (GTK_OBJECT_TYPE (object),
777                                 object_arg_info_ht,
778                                 arg->name,
779                                 &info);
780       if (error)
781         {
782           g_warning ("gtk_object_arg_set(): %s", error);
783           g_free (error);
784           return;
785         }
786     }
787   
788   if (! (info->arg_flags & GTK_ARG_WRITABLE))
789     {
790       g_warning ("gtk_object_arg_set(): argument \"%s\" is not writable",
791                  info->full_name);
792       return;
793     }
794   if (info->type != arg->type)
795     {
796       g_warning ("gtk_object_arg_set(): argument \"%s\" has invalid type `%s'",
797                  info->full_name,
798                  gtk_type_name (arg->type));
799       return;
800     }
801   
802   oclass = gtk_type_class (info->class_type);
803   g_assert (oclass->set_arg != NULL);
804   oclass->set_arg (object, arg, info->arg_id);
805 }
806
807 void
808 gtk_object_arg_get (GtkObject           *object,
809                     GtkArg              *arg,
810                     GtkArgInfo          *info)
811 {
812   GtkObjectClass *oclass;
813   
814   g_return_if_fail (object != NULL);
815   g_return_if_fail (GTK_IS_OBJECT (object));
816   g_return_if_fail (arg != NULL);
817
818   if (!info)
819     {
820       gchar *error;
821
822       error = gtk_arg_get_info (GTK_OBJECT_TYPE (object),
823                                 object_arg_info_ht,
824                                 arg->name,
825                                 &info);
826       if (error)
827         {
828           g_warning ("gtk_object_arg_get(): %s", error);
829           g_free (error);
830           arg->type = GTK_TYPE_INVALID;
831           return;
832         }
833     }
834   
835   if (! (info->arg_flags & GTK_ARG_READABLE))
836     {
837       g_warning ("gtk_object_arg_get(): argument \"%s\" is not readable",
838                  info->full_name);
839       arg->type = GTK_TYPE_INVALID;
840       return;
841     }
842   
843   oclass = gtk_type_class (info->class_type);
844   g_assert (oclass->get_arg != NULL);
845   arg->type = info->type;
846   oclass->get_arg (object, arg, info->arg_id);
847 }
848
849 void
850 gtk_object_add_arg_type (const char *arg_name,
851                          GtkType     arg_type,
852                          guint       arg_flags,
853                          guint       arg_id)
854 {
855   g_return_if_fail (arg_name != NULL);
856   g_return_if_fail (arg_type > GTK_TYPE_NONE);
857   g_return_if_fail (arg_id > 0);
858   g_return_if_fail ((arg_flags & GTK_ARG_CHILD_ARG) == 0);
859   if (arg_flags & GTK_ARG_CONSTRUCT)
860     g_return_if_fail ((arg_flags & GTK_ARG_READWRITE) == GTK_ARG_READWRITE);
861   else
862     g_return_if_fail ((arg_flags & GTK_ARG_READWRITE) != 0);
863     
864   if (!object_arg_info_ht)
865     object_arg_info_ht = g_hash_table_new (gtk_arg_info_hash,
866                                            gtk_arg_info_equal);
867
868   gtk_arg_type_new_static (GTK_TYPE_OBJECT,
869                            arg_name,
870                            GTK_STRUCT_OFFSET (GtkObjectClass, n_args),
871                            object_arg_info_ht,
872                            arg_type,
873                            arg_flags,
874                            arg_id);
875 }
876
877 gchar*
878 gtk_object_args_collect (GtkType      object_type,
879                          GSList      **arg_list_p,
880                          GSList      **info_list_p,
881                          gpointer      var_args_p)
882 {
883   return gtk_args_collect (object_type,
884                            object_arg_info_ht,
885                            arg_list_p,
886                            info_list_p,
887                            var_args_p);
888 }
889
890 gchar*
891 gtk_object_arg_get_info (GtkType      object_type,
892                          const gchar *arg_name,
893                          GtkArgInfo **info_p)
894 {
895   return gtk_arg_get_info (object_type,
896                            object_arg_info_ht,
897                            arg_name,
898                            info_p);
899 }
900
901 GtkArg*
902 gtk_object_query_args (GtkType        class_type,
903                        guint32      **arg_flags,
904                        guint         *n_args)
905 {
906   g_return_val_if_fail (n_args != NULL, NULL);
907   *n_args = 0;
908   g_return_val_if_fail (GTK_FUNDAMENTAL_TYPE (class_type) == GTK_TYPE_OBJECT, NULL);
909
910   return gtk_args_query (class_type, object_arg_info_ht, arg_flags, n_args);
911 }
912
913 /********************************************************
914  * GtkObject and GtkObjectClass cast checking functions
915  *
916  ********************************************************/
917
918 static gchar*
919 gtk_object_descriptive_type_name (GtkType type)
920 {
921   gchar *name;
922
923   name = gtk_type_name (type);
924   if (!name)
925     name = "(unknown)";
926
927   return name;
928 }
929
930 GtkObject*
931 gtk_object_check_cast (GtkObject *obj,
932                        GtkType    cast_type)
933 {
934   if (!obj)
935     {
936       g_warning ("invalid cast from (NULL) pointer to `%s'",
937                  gtk_object_descriptive_type_name (cast_type));
938       return obj;
939     }
940   if (!obj->klass)
941     {
942       g_warning ("invalid unclassed pointer in cast to `%s'",
943                  gtk_object_descriptive_type_name (cast_type));
944       return obj;
945     }
946   if (obj->klass->type < GTK_TYPE_OBJECT)
947     {
948       g_warning ("invalid class type `%s' in cast to `%s'",
949                  gtk_object_descriptive_type_name (obj->klass->type),
950                  gtk_object_descriptive_type_name (cast_type));
951       return obj;
952     }
953   if (!gtk_type_is_a (obj->klass->type, cast_type))
954     {
955       g_warning ("invalid cast from `%s' to `%s'",
956                  gtk_object_descriptive_type_name (obj->klass->type),
957                  gtk_object_descriptive_type_name (cast_type));
958       return obj;
959     }
960   
961   return obj;
962 }
963
964 GtkObjectClass*
965 gtk_object_check_class_cast (GtkObjectClass *klass,
966                              GtkType         cast_type)
967 {
968   if (!klass)
969     {
970       g_warning ("invalid class cast from (NULL) pointer to `%s'",
971                  gtk_object_descriptive_type_name (cast_type));
972       return klass;
973     }
974   if (klass->type < GTK_TYPE_OBJECT)
975     {
976       g_warning ("invalid class type `%s' in class cast to `%s'",
977                  gtk_object_descriptive_type_name (klass->type),
978                  gtk_object_descriptive_type_name (cast_type));
979       return klass;
980     }
981   if (!gtk_type_is_a (klass->type, cast_type))
982     {
983       g_warning ("invalid class cast from `%s' to `%s'",
984                  gtk_object_descriptive_type_name (klass->type),
985                  gtk_object_descriptive_type_name (cast_type));
986       return klass;
987     }
988
989   return klass;
990 }
991
992 /*****************************************
993  * GtkObject object_data mechanism
994  *
995  *****************************************/
996
997 void
998 gtk_object_set_data_by_id (GtkObject        *object,
999                            GQuark            data_id,
1000                            gpointer          data)
1001 {
1002   g_return_if_fail (data_id > 0);
1003   
1004   gtk_object_set_data_by_id_full (object, data_id, data, NULL);
1005 }
1006
1007 void
1008 gtk_object_set_data (GtkObject        *object,
1009                      const gchar      *key,
1010                      gpointer          data)
1011 {
1012   g_return_if_fail (key != NULL);
1013   
1014   gtk_object_set_data_by_id_full (object, gtk_object_data_force_id (key), data, NULL);
1015 }
1016
1017 void
1018 gtk_object_set_data_by_id_full (GtkObject        *object,
1019                                 GQuark            data_id,
1020                                 gpointer          data,
1021                                 GtkDestroyNotify  destroy)
1022 {
1023   GtkObjectData *odata;
1024   
1025   g_return_if_fail (object != NULL);
1026   g_return_if_fail (GTK_IS_OBJECT (object));
1027   g_return_if_fail (data_id > 0);
1028
1029   odata = object->object_data;
1030   if (!data)
1031     {
1032       GtkObjectData *prev;
1033       
1034       prev = NULL;
1035       
1036       while (odata)
1037         {
1038           if (odata->id == data_id)
1039             {
1040               if (prev)
1041                 prev->next = odata->next;
1042               else
1043                 object->object_data = odata->next;
1044               
1045               GTK_OBJECT_DATA_DESTROY (odata);
1046               return;
1047             }
1048           
1049           prev = odata;
1050           odata = odata->next;
1051         }
1052     }
1053   else
1054     {
1055       while (odata)
1056         {
1057           if (odata->id == data_id)
1058             {
1059               register GtkDestroyNotify dfunc;
1060               register gpointer ddata;
1061
1062               dfunc = odata->destroy;
1063               ddata = odata->data;
1064               odata->destroy = destroy;
1065               odata->data = data;
1066
1067               /* we need to have updated all structures prior to
1068                * invokation of the destroy function
1069                */
1070               if (dfunc)
1071                 dfunc (ddata);
1072
1073               return;
1074             }
1075
1076           odata = odata->next;
1077         }
1078       
1079       if (gtk_object_data_free_list)
1080         {
1081           odata = gtk_object_data_free_list;
1082           gtk_object_data_free_list = odata->next;
1083         }
1084       else
1085         {
1086           GtkObjectData *odata_block;
1087           guint i;
1088
1089           odata_block = g_new0 (GtkObjectData, GTK_OBJECT_DATA_BLOCK_SIZE);
1090           for (i = 1; i < GTK_OBJECT_DATA_BLOCK_SIZE; i++)
1091             {
1092               (odata_block + i)->next = gtk_object_data_free_list;
1093               gtk_object_data_free_list = (odata_block + i);
1094             }
1095
1096           odata = odata_block;
1097         }
1098       
1099       odata->id = data_id;
1100       odata->data = data;
1101       odata->destroy = destroy;
1102       odata->next = object->object_data;
1103       
1104       object->object_data = odata;
1105     }
1106 }
1107
1108 void
1109 gtk_object_set_data_full (GtkObject        *object,
1110                           const gchar      *key,
1111                           gpointer          data,
1112                           GtkDestroyNotify  destroy)
1113 {
1114   g_return_if_fail (key != NULL);
1115
1116   gtk_object_set_data_by_id_full (object, gtk_object_data_force_id (key), data, destroy);
1117 }
1118
1119 gpointer
1120 gtk_object_get_data_by_id (GtkObject   *object,
1121                            GQuark       data_id)
1122 {
1123   GtkObjectData *odata;
1124
1125   g_return_val_if_fail (object != NULL, NULL);
1126   g_return_val_if_fail (GTK_IS_OBJECT (object), NULL);
1127
1128   if (data_id)
1129     {
1130       odata = object->object_data;
1131       while (odata)
1132         {
1133           if (odata->id == data_id)
1134             return odata->data;
1135           odata = odata->next;
1136         }
1137     }
1138   
1139   return NULL;
1140 }
1141
1142 gpointer
1143 gtk_object_get_data (GtkObject   *object,
1144                      const gchar *key)
1145 {
1146   guint id;
1147
1148   g_return_val_if_fail (key != NULL, NULL);
1149
1150   id = gtk_object_data_try_key (key);
1151   if (id)
1152     return gtk_object_get_data_by_id (object, id);
1153
1154   return NULL;
1155 }
1156
1157 void
1158 gtk_object_remove_data_by_id (GtkObject   *object,
1159                               GQuark       data_id)
1160 {
1161   if (data_id)
1162     gtk_object_set_data_by_id_full (object, data_id, NULL, NULL);
1163 }
1164
1165 void
1166 gtk_object_remove_data (GtkObject   *object,
1167                         const gchar *key)
1168 {
1169   gint id;
1170
1171   g_return_if_fail (key != NULL);
1172
1173   id = gtk_object_data_try_key (key);
1174   if (id)
1175     gtk_object_set_data_by_id_full (object, id, NULL, NULL);
1176 }
1177
1178 void
1179 gtk_object_set_user_data (GtkObject *object,
1180                           gpointer   data)
1181 {
1182   if (!user_data_key_id)
1183     user_data_key_id = g_quark_from_static_string (user_data_key);
1184
1185   gtk_object_set_data_by_id_full (object, user_data_key_id, data, NULL);
1186 }
1187
1188 gpointer
1189 gtk_object_get_user_data (GtkObject *object)
1190 {
1191   if (user_data_key_id)
1192     return gtk_object_get_data_by_id (object, user_data_key_id);
1193
1194   return NULL;
1195 }
1196
1197 /*******************************************
1198  * GtkObject referencing and unreferencing
1199  *
1200  *******************************************/
1201
1202 #undef  gtk_object_ref
1203 #undef  gtk_object_unref
1204
1205 void
1206 gtk_object_ref (GtkObject *object)
1207 {
1208   g_return_if_fail (object != NULL);
1209   g_return_if_fail (GTK_IS_OBJECT (object));
1210
1211   object->ref_count += 1;
1212 }
1213
1214 void
1215 gtk_object_unref (GtkObject *object)
1216 {
1217   g_return_if_fail (object != NULL);
1218   g_return_if_fail (GTK_IS_OBJECT (object));
1219   
1220   if (object->ref_count == 1)
1221     gtk_object_destroy (object);
1222   
1223   if (object->ref_count > 0)
1224     object->ref_count -= 1;
1225
1226   if (object->ref_count == 0)
1227     {
1228 #ifdef G_ENABLE_DEBUG
1229       if (gtk_debug_flags & GTK_DEBUG_OBJECTS)
1230         {
1231           g_assert (g_hash_table_lookup (living_objs_ht, object) == object);
1232           g_hash_table_remove (living_objs_ht, object);
1233           obj_count--;
1234         }
1235 #endif /* G_ENABLE_DEBUG */      
1236       object->klass->finalize (object);
1237     }
1238 }
1239
1240 static GtkObject *gtk_trace_object = NULL;
1241 void
1242 gtk_trace_referencing (GtkObject   *object,
1243                        const gchar *func,
1244                        guint       dummy,
1245                        guint       line,
1246                        gboolean    do_ref)
1247 {
1248   if (gtk_debug_flags & GTK_DEBUG_OBJECTS)
1249     {
1250       gboolean exists = TRUE;
1251
1252       g_return_if_fail (object != NULL);
1253       g_return_if_fail (GTK_IS_OBJECT (object));
1254
1255 #ifdef  G_ENABLE_DEBUG
1256       exists = g_hash_table_lookup (living_objs_ht, object) != NULL;
1257 #endif  /* G_ENABLE_DEBUG */
1258       
1259       if (exists &&
1260           (object == gtk_trace_object ||
1261            gtk_trace_object == (void*)42))
1262         fprintf (stdout, "trace: object_%s: (%s:%p)->ref_count=%d %s (%s:%d)\n",
1263                  do_ref ? "ref" : "unref",
1264                  gtk_type_name (GTK_OBJECT_TYPE (object)),
1265                  object,
1266                  object->ref_count,
1267                  do_ref ? "+ 1" : "- 1",
1268                  func,
1269                  line);
1270       else if (!exists)
1271         fprintf (stdout, "trace: object_%s(%p): no such object! (%s:%d)\n",
1272                  do_ref ? "ref" : "unref",
1273                  object,
1274                  func,
1275                  line);
1276     }
1277   
1278   if (do_ref)
1279     gtk_object_ref (object);
1280   else
1281     gtk_object_unref (object);
1282 }