1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "gtkobject.h"
21 #include "gtksignal.h"
24 #define OBJECT_DATA_ID_CHUNK 1024
38 typedef struct _GtkObjectData GtkObjectData;
39 typedef struct _GtkArgInfo GtkArgInfo;
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,
62 static void gtk_real_object_destroy (GtkObject *object);
63 static void gtk_object_data_init (void);
64 static GtkObjectData* gtk_object_data_new (void);
65 static void gtk_object_data_destroy (GtkObjectData *odata);
66 static guint* gtk_object_data_id_alloc (void);
67 GtkArg* gtk_object_collect_args (gint *nargs,
72 static gint object_signals[LAST_SIGNAL] = { 0 };
74 static gint object_data_init = TRUE;
75 static GHashTable *object_data_ht = NULL;
76 static GMemChunk *object_data_mem_chunk = NULL;
77 static GtkObjectData *object_data_free_list = NULL;
78 static GSList *object_data_id_list = NULL;
79 static gint object_data_id_index = 0;
81 static GHashTable *arg_info_ht = NULL;
83 static const char *user_data_key = "user_data";
86 /*****************************************
87 * gtk_object_get_type:
92 * The type identifier for GtkObject's
93 *****************************************/
96 gtk_object_init_type ()
98 GtkType object_type = 0;
99 GtkTypeInfo object_info =
103 sizeof (GtkObjectClass),
104 (GtkClassInitFunc) gtk_object_class_init,
105 (GtkObjectInitFunc) gtk_object_init,
110 object_type = gtk_type_unique (0, &object_info);
111 g_assert (object_type == GTK_TYPE_OBJECT);
115 gtk_object_get_type ()
117 return GTK_TYPE_OBJECT;
120 /*****************************************
121 * gtk_object_class_init:
126 *****************************************/
129 gtk_object_class_init (GtkObjectClass *class)
131 class->signals = NULL;
134 gtk_object_add_arg_type ("GtkObject::user_data", GTK_TYPE_POINTER, ARG_USER_DATA);
135 gtk_object_add_arg_type ("GtkObject::signal", GTK_TYPE_SIGNAL, ARG_SIGNAL);
137 object_signals[DESTROY] =
138 gtk_signal_new ("destroy",
141 GTK_SIGNAL_OFFSET (GtkObjectClass, destroy),
142 gtk_signal_default_marshaller,
145 gtk_object_class_add_signals (class, object_signals, LAST_SIGNAL);
147 class->destroy = gtk_real_object_destroy;
150 /*****************************************
156 *****************************************/
159 gtk_object_init (GtkObject *object)
162 object->ref_count = 0;
163 object->object_data = NULL;
166 /*****************************************
172 *****************************************/
175 gtk_object_set_arg (GtkObject *object,
182 gtk_object_set_user_data (object, GTK_VALUE_POINTER (*arg));
185 if ((arg->name[11 + 6] != ':') || (arg->name[11 + 7] != ':'))
187 g_print ("invalid signal argument: \"%s\"\n", arg->name);
190 gtk_signal_connect (object, arg->name + 11 + 8,
191 (GtkSignalFunc) GTK_VALUE_SIGNAL (*arg).f,
192 GTK_VALUE_SIGNAL (*arg).d);
195 g_assert_not_reached ();
199 /*****************************************
200 * gtk_object_class_add_signals:
205 *****************************************/
208 gtk_object_class_add_signals (GtkObjectClass *class,
215 g_return_if_fail (class != NULL);
217 new_signals = g_new (gint, class->nsignals + nsignals);
218 for (i = 0; i < class->nsignals; i++)
219 new_signals[i] = class->signals[i];
220 for (i = 0; i < nsignals; i++)
221 new_signals[class->nsignals + i] = signals[i];
223 class->signals = new_signals;
224 class->nsignals += nsignals;
227 /*****************************************
233 *****************************************/
236 gtk_object_ref (GtkObject *object)
238 g_return_if_fail (object != NULL);
239 g_return_if_fail (GTK_IS_OBJECT (object));
241 object->ref_count += 1;
244 /*****************************************
250 *****************************************/
253 gtk_object_unref (GtkObject *object)
255 g_return_if_fail (object != NULL);
256 g_return_if_fail (GTK_IS_OBJECT (object));
258 if (object->ref_count > 0)
259 object->ref_count -= 1;
262 /*****************************************
268 *****************************************/
271 gtk_object_new (guint type,
280 obj = gtk_type_new (type);
282 va_start (args1, type);
283 va_start (args2, type);
285 args = gtk_object_collect_args (&nargs, args1, args2);
286 gtk_object_setv (obj, nargs, args);
295 /*****************************************
301 *****************************************/
304 gtk_object_newv (guint type,
310 obj = gtk_type_new (type);
311 gtk_object_setv (obj, nargs, args);
316 /*****************************************
322 *****************************************/
325 gtk_object_set (GtkObject *obj,
333 g_return_if_fail (obj != NULL);
335 va_start (args1, obj);
336 va_start (args2, obj);
338 args = gtk_object_collect_args (&nargs, args1, args2);
339 gtk_object_setv (obj, nargs, args);
346 /*****************************************
352 *****************************************/
355 gtk_object_setv (GtkObject *obj,
361 g_return_if_fail (obj != NULL);
366 for (i = 0; i < nargs; i++)
372 lookup_name = g_strdup (args[i].name);
373 d = strchr (lookup_name, ':');
374 if (d && d[1] == ':')
376 d = strchr (d + 2, ':');
380 info = g_hash_table_lookup (arg_info_ht, lookup_name);
387 g_warning ("invalid arg name: \"%s\"\n", lookup_name);
390 g_free (lookup_name);
392 gtk_type_set_arg (obj, info->class_type, &args[i], info->arg_id);
396 /*****************************************
397 * gtk_object_add_arg_type:
402 *****************************************/
405 gtk_object_add_arg_type (const char *arg_name,
410 gchar class_part[1024];
414 g_return_if_fail (arg_id > 0);
416 arg_part = strchr (arg_name, ':');
417 if (!arg_part || (arg_part[0] != ':') || (arg_part[1] != ':'))
419 g_warning ("invalid arg name: \"%s\"\n", arg_name);
423 strncpy (class_part, arg_name, (glong) (arg_part - arg_name));
424 class_part[(glong) (arg_part - arg_name)] = '\0';
426 class_type = gtk_type_from_name (class_part);
429 g_warning ("invalid class name in arg: \"%s\"\n", arg_name);
433 info = g_new (GtkArgInfo, 1);
434 info->name = g_strdup (arg_name);
435 info->type = arg_type;
436 info->class_type = class_type;
437 info->arg_id = arg_id;
440 arg_info_ht = g_hash_table_new (g_string_hash, g_string_equal);
442 g_hash_table_insert (arg_info_ht, info->name, info);
445 /*****************************************
446 * gtk_object_get_arg_type:
451 *****************************************/
454 gtk_object_get_arg_type (const char *arg_name)
461 return GTK_TYPE_INVALID;
463 t = strchr (arg_name, ':');
464 if (!t || (t[0] != ':') || (t[1] != ':'))
466 g_warning ("invalid arg name: \"%s\"\n", arg_name);
467 return GTK_TYPE_INVALID;
470 t = strchr (t + 2, ':');
473 strncpy (buffer, arg_name, (long) (t - arg_name));
474 buffer[(long) (t - arg_name)] = '\0';
478 info = g_hash_table_lookup (arg_info_ht, (gpointer) arg_name);
482 return GTK_TYPE_INVALID;
485 /*****************************************
486 * gtk_object_destroy:
491 *****************************************/
494 gtk_object_destroy (GtkObject *object)
496 g_return_if_fail (object != NULL);
497 g_return_if_fail (GTK_IS_OBJECT (object));
499 if ((object->ref_count > 0) || GTK_OBJECT_IN_CALL (object))
501 GTK_OBJECT_SET_FLAGS (object, GTK_NEED_DESTROY);
505 GTK_OBJECT_UNSET_FLAGS (object, GTK_NEED_DESTROY);
506 GTK_OBJECT_SET_FLAGS (object, GTK_BEING_DESTROYED);
508 gtk_signal_emit (object, object_signals[DESTROY]);
512 /*****************************************
513 * gtk_object_set_data:
518 *****************************************/
521 gtk_object_set_data (GtkObject *object,
525 GtkObjectData *odata;
529 g_return_if_fail (object != NULL);
530 g_return_if_fail (GTK_IS_OBJECT (object));
531 g_return_if_fail (key != NULL);
533 if (object_data_init)
534 gtk_object_data_init ();
536 id = g_hash_table_lookup (object_data_ht, (gpointer) key);
543 odata = object->object_data;
547 if (odata->id == *id)
550 prev->next = odata->next;
551 if (odata == object->object_data)
552 object->object_data = odata->next;
554 gtk_object_data_destroy (odata);
567 id = gtk_object_data_id_alloc ();
568 g_hash_table_insert (object_data_ht, (gpointer) key, id);
571 odata = object->object_data;
574 if (odata->id == *id)
583 odata = gtk_object_data_new ();
587 odata->next = object->object_data;
588 object->object_data = odata;
592 /*****************************************
593 * gtk_object_get_data:
598 *****************************************/
601 gtk_object_get_data (GtkObject *object,
604 GtkObjectData *odata;
607 g_return_val_if_fail (object != NULL, NULL);
608 g_return_val_if_fail (GTK_IS_OBJECT (object), NULL);
609 g_return_val_if_fail (key != NULL, NULL);
611 if (object_data_init)
612 gtk_object_data_init ();
614 id = g_hash_table_lookup (object_data_ht, (gpointer) key);
617 odata = object->object_data;
620 if (odata->id == *id)
629 /*****************************************
630 * gtk_object_remove_data:
635 *****************************************/
638 gtk_object_remove_data (GtkObject *object,
641 g_return_if_fail (object != NULL);
642 g_return_if_fail (GTK_IS_OBJECT (object));
643 g_return_if_fail (key != NULL);
645 gtk_object_set_data (object, key, NULL);
648 /*****************************************
649 * gtk_object_set_user_data:
654 *****************************************/
657 gtk_object_set_user_data (GtkObject *object,
660 g_return_if_fail (object != NULL);
661 g_return_if_fail (GTK_IS_OBJECT (object));
663 gtk_object_set_data (object, user_data_key, data);
666 /*****************************************
667 * gtk_object_get_user_data:
672 *****************************************/
675 gtk_object_get_user_data (GtkObject *object)
677 g_return_val_if_fail (object != NULL, NULL);
678 g_return_val_if_fail (GTK_IS_OBJECT (object), NULL);
680 return gtk_object_get_data (object, user_data_key);
683 /*****************************************
684 * gtk_object_check_cast:
689 *****************************************/
692 gtk_object_check_cast (GtkObject *obj,
695 if (obj && obj->klass && !gtk_type_is_a (obj->klass->type, cast_type))
697 gchar *from_name = gtk_type_name (obj->klass->type);
698 gchar *to_name = gtk_type_name (cast_type);
700 g_warning ("invalid cast from \"%s\" to \"%s\"",
701 from_name ? from_name : "(unknown)",
702 to_name ? to_name : "(unknown)");
708 /*****************************************
709 * gtk_object_check_class_cast:
714 *****************************************/
717 gtk_object_check_class_cast (GtkObjectClass *klass,
720 if (klass && !gtk_type_is_a (klass->type, cast_type))
721 g_warning ("invalid cast from \"%sClass\" to \"%sClass\"",
722 gtk_type_name (klass->type),
723 gtk_type_name (cast_type));
728 /*****************************************
729 * gtk_real_object_destroy:
734 *****************************************/
737 gtk_real_object_destroy (GtkObject *object)
739 GtkObjectData *odata;
741 g_return_if_fail (object != NULL);
742 g_return_if_fail (GTK_IS_OBJECT (object));
744 gtk_signal_handlers_destroy (object);
746 if (object->object_data)
748 odata = object->object_data;
752 odata->next = object_data_free_list;
753 object_data_free_list = object->object_data;
759 /*****************************************
760 * gtk_object_data_init:
765 *****************************************/
768 gtk_object_data_init ()
770 if (object_data_init)
772 object_data_init = FALSE;
774 object_data_ht = g_hash_table_new (g_string_hash, g_string_equal);
778 /*****************************************
779 * gtk_object_data_new:
784 *****************************************/
786 static GtkObjectData*
787 gtk_object_data_new ()
789 GtkObjectData *odata;
791 if (!object_data_mem_chunk)
792 object_data_mem_chunk = g_mem_chunk_new ("object data mem chunk",
793 sizeof (GtkObjectData),
794 1024, G_ALLOC_AND_FREE);
796 odata = g_chunk_new (GtkObjectData, object_data_mem_chunk);
805 /*****************************************
806 * gtk_object_data_destroy:
811 *****************************************/
814 gtk_object_data_destroy (GtkObjectData *odata)
816 g_return_if_fail (odata != NULL);
818 g_mem_chunk_free (object_data_mem_chunk, odata);
821 /*****************************************
822 * gtk_object_data_id_alloc:
827 *****************************************/
830 gtk_object_data_id_alloc ()
832 static guint next_id = 1;
835 if (!object_data_id_list ||
836 (object_data_id_index == OBJECT_DATA_ID_CHUNK))
838 ids = g_new (guint, OBJECT_DATA_ID_CHUNK);
839 object_data_id_index = 0;
840 object_data_id_list = g_slist_prepend (object_data_id_list, ids);
844 ids = object_data_id_list->data;
847 ids[object_data_id_index] = next_id++;
848 return &ids[object_data_id_index++];
851 /*****************************************
852 * gtk_object_collect_args:
857 *****************************************/
860 gtk_object_collect_args (gint *nargs,
875 name = va_arg (args1, char *);
882 type = gtk_object_get_arg_type (name);
884 switch (GTK_FUNDAMENTAL_TYPE (type))
886 case GTK_TYPE_INVALID:
887 g_warning ("invalid arg name: \"%s\" %x\n", name, type);
888 (void) va_arg (args1, long);
898 (void) va_arg (args1, gint);
902 (void) va_arg (args1, glong);
905 (void) va_arg (args1, gfloat);
907 case GTK_TYPE_STRING:
908 (void) va_arg (args1, gchar*);
910 case GTK_TYPE_POINTER:
912 (void) va_arg (args1, gpointer);
914 case GTK_TYPE_SIGNAL:
915 (void) va_arg (args1, GtkFunction);
916 (void) va_arg (args1, gpointer);
918 case GTK_TYPE_FOREIGN:
919 (void) va_arg (args1, gpointer);
920 (void) va_arg (args1, GtkDestroyNotify);
922 case GTK_TYPE_CALLBACK:
923 (void) va_arg (args1, GtkCallbackMarshal);
924 (void) va_arg (args1, gpointer);
925 (void) va_arg (args1, GtkDestroyNotify);
927 case GTK_TYPE_C_CALLBACK:
928 (void) va_arg (args1, GtkFunction);
929 (void) va_arg (args1, gpointer);
932 (void) va_arg (args1, gint);
933 (void) va_arg (args1, GtkArg*);
935 case GTK_TYPE_OBJECT:
936 (void) va_arg (args1, GtkObject*);
939 g_error ("unsupported type %s in args", gtk_type_name (type));
951 args = g_new0 (GtkArg, n);
953 for (i = 0; i < n; i++)
955 args[i].name = va_arg (args2, char *);
956 args[i].type = gtk_object_get_arg_type (args[i].name);
958 switch (GTK_FUNDAMENTAL_TYPE (args[i].type))
960 case GTK_TYPE_INVALID:
961 (void) va_arg (args2, long);
967 GTK_VALUE_CHAR(args[i]) = va_arg (args2, gint);
970 GTK_VALUE_BOOL(args[i]) = va_arg (args2, gint);
973 GTK_VALUE_INT(args[i]) = va_arg (args2, gint);
976 GTK_VALUE_UINT(args[i]) = va_arg (args2, guint);
979 GTK_VALUE_ENUM(args[i]) = va_arg (args2, gint);
982 GTK_VALUE_FLAGS(args[i]) = va_arg (args2, gint);
985 GTK_VALUE_LONG(args[i]) = va_arg (args2, glong);
988 GTK_VALUE_ULONG(args[i]) = va_arg (args2, gulong);
991 GTK_VALUE_FLOAT(args[i]) = va_arg (args2, gfloat);
993 case GTK_TYPE_STRING:
994 GTK_VALUE_STRING(args[i]) = va_arg (args2, gchar*);
996 case GTK_TYPE_POINTER:
997 GTK_VALUE_POINTER(args[i]) = va_arg (args2, gpointer);
1000 GTK_VALUE_BOXED(args[i]) = va_arg (args2, gpointer);
1002 case GTK_TYPE_SIGNAL:
1003 GTK_VALUE_SIGNAL(args[i]).f = va_arg (args2, GtkFunction);
1004 GTK_VALUE_SIGNAL(args[i]).d = va_arg (args2, gpointer);
1006 case GTK_TYPE_FOREIGN:
1007 GTK_VALUE_FOREIGN(args[i]).data = va_arg (args2, gpointer);
1008 GTK_VALUE_FOREIGN(args[i]).notify =
1009 va_arg (args2, GtkDestroyNotify);
1011 case GTK_TYPE_CALLBACK:
1012 GTK_VALUE_CALLBACK(args[i]).marshal =
1013 va_arg (args2, GtkCallbackMarshal);
1014 GTK_VALUE_CALLBACK(args[i]).data = va_arg (args2, gpointer);
1015 GTK_VALUE_CALLBACK(args[i]).notify =
1016 va_arg (args2, GtkDestroyNotify);
1018 case GTK_TYPE_C_CALLBACK:
1019 GTK_VALUE_C_CALLBACK(args[i]).func = va_arg (args2, GtkFunction);
1020 GTK_VALUE_C_CALLBACK(args[i]).func_data =
1021 va_arg (args2, gpointer);
1024 GTK_VALUE_ARGS(args[i]).n_args = va_arg (args2, gint);
1025 GTK_VALUE_ARGS(args[i]).args = va_arg (args2, GtkArg*);
1027 case GTK_TYPE_OBJECT:
1028 GTK_VALUE_OBJECT(args[i]) = va_arg (args2, GtkObject*);
1029 g_assert (GTK_VALUE_OBJECT(args[i]) == NULL ||
1030 GTK_CHECK_TYPE (GTK_VALUE_OBJECT(args[i]),
1034 g_error ("unsupported type %s in args",
1035 gtk_type_name (args[i].type));