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