gtk2/gtk/gtkobject.c
Tim Janik 347efc33b8 deleted most of the argument handling code, since that is now implemented
Fri Jul 10 00:02:04 1998  Tim Janik  <timj@gtk.org>

	* gtk/gtkcontainer.h:
	* gtk/gtkcontainer.c: deleted most of the argument handling code, since
	that is now implemented in gtkarg.c. similar to gtk_object_args_collect,
	we now export a new function gtk_container_child_args_collect().
	for consistency with the object arguments, a few functions got renamed:
	gtk_container_child_arg_get -> gtk_container_child_get,
	gtk_container_child_arg_set -> gtk_container_child_set,
	gtk_container_child_arg_getv -> gtk_container_child_getv,
	gtk_container_child_arg_setv -> gtk_container_child_setv,
	gtk_container_add_with_argv -> gtk_container_addv.
	note, gtk_container_add_with_args() remained, because its equivalent
	would be gtk_container_add(,, ...) which would break all existing code.
	(gtk_container_add_child_arg_type): similar to gtk_object_add_arg_type,
	we expect the `arg_name' argument to be a const static string now.
	(gtk_container_get_child_arg_type): function removed.

Thu Jul  9 07:03:04 1998  Tim Janik  <timj@gtk.org>

	* gtk/gtkargcollector.c: new file which holds gtk_arg_collect_value().
	this is a static inline function that collects command line arguments
	from a va_list. this file can just be included in all places that
	need this functionality.

	* gtk/gtkarg.h:
	* gtk/gtkarg.c: new files which implement most of the argument
	handling stuff from gtkobject.c. also collected a few more
	gtk_arg_* utility functions from else places.

	* gtk/gtkobject.h:
	* gtk/gtkobject.c: moved most of the argument handling code into
 	gtkarg.c. we now export gtk_object_args_collect() as a non-public
	method with a blind va_list pointer.
	(gtk_object_add_arg_type): the `arg_name' argument is required to be a
	const static string now.
	(gtk_object_get_arg_type): function got removed.

	* gtk/gtkwidget.c:
	(gtk_widget_set):
	(gtk_widget_new): adaptions for gtk_object_args_collect().

	* gtk/gtktypeutils.c (gtk_type_init_builtin_types): changed the internal
 	fundamental type name so as to have a valid prefix, e.g. "bool"->
	"gboolean", "string"->"GtkString" and somesuch, left "void" as is,
	though that should probably be something like GtkNone since the
	type itself is called GTK_TYPE_NONE.
	even the internal type names need to avoid name clashes and must live
	in their own namespace, several code portions rely on that.
	we should relly have typedefs such as typedef gchar* GtkString; so the
	fundamental type names can be used for code dumpers just like with all
	the Gtk/Gdk types.
1998-07-09 23:00:34 +00:00

1273 lines
29 KiB
C

/* GTK - The GIMP Toolkit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "gtkobject.h"
#include "gtksignal.h"
#define GTK_OBJECT_DATA_ID_BLOCK_SIZE (1024)
#define GTK_OBJECT_DATA_BLOCK_SIZE (1024)
enum {
DESTROY,
LAST_SIGNAL
};
enum {
ARG_0,
ARG_USER_DATA,
ARG_SIGNAL,
ARG_SIGNAL_AFTER,
ARG_OBJECT_SIGNAL,
ARG_OBJECT_SIGNAL_AFTER
};
typedef struct _GtkObjectData GtkObjectData;
struct _GtkObjectData
{
guint id;
gpointer data;
GtkDestroyNotify destroy;
GtkObjectData *next;
};
void gtk_object_init_type (void);
static void gtk_object_base_class_init (GtkObjectClass *klass);
static void gtk_object_class_init (GtkObjectClass *klass);
static void gtk_object_init (GtkObject *object);
static void gtk_object_set_arg (GtkObject *object,
GtkArg *arg,
guint arg_id);
static void gtk_object_get_arg (GtkObject *object,
GtkArg *arg,
guint arg_id);
static void gtk_object_shutdown (GtkObject *object);
static void gtk_object_real_destroy (GtkObject *object);
static void gtk_object_finalize (GtkObject *object);
static void gtk_object_notify_weaks (GtkObject *object);
static guint object_signals[LAST_SIGNAL] = { 0 };
static GHashTable *object_arg_info_ht = NULL;
static const gchar *user_data_key = "user_data";
static guint user_data_key_id = 0;
static const gchar *weakrefs_key = "gtk-weakrefs";
static guint weakrefs_key_id = 0;
static GtkObjectData *gtk_object_data_free_list = NULL;
#define GTK_OBJECT_DATA_DESTROY( odata ) { \
if (odata->destroy) \
odata->destroy (odata->data); \
odata->next = gtk_object_data_free_list; \
gtk_object_data_free_list = odata; \
}
#ifdef G_ENABLE_DEBUG
static guint obj_count = 0;
static GHashTable *living_objs_ht = NULL;
static void
gtk_object_debug_foreach (gpointer key, gpointer value, gpointer user_data)
{
GtkObject *object;
object = (GtkObject*) value;
g_print ("GTK-DEBUG: %p: %s ref_count=%d%s%s\n",
object,
gtk_type_name (GTK_OBJECT_TYPE (object)),
object->ref_count,
GTK_OBJECT_FLOATING (object) ? " (floating)" : "",
GTK_OBJECT_DESTROYED (object) ? " (destroyed)" : "");
}
static void
gtk_object_debug (void)
{
g_hash_table_foreach (living_objs_ht, gtk_object_debug_foreach, NULL);
g_print ("GTK-DEBUG: living objects count = %d\n", obj_count);
}
#endif /* G_ENABLE_DEBUG */
/****************************************************
* GtkObject type, class and instance initialization
*
****************************************************/
void
gtk_object_init_type (void)
{
GtkType object_type = 0;
GtkTypeInfo object_info =
{
"GtkObject",
sizeof (GtkObject),
sizeof (GtkObjectClass),
(GtkClassInitFunc) gtk_object_class_init,
(GtkObjectInitFunc) gtk_object_init,
/* reserved_1 */ NULL,
/* reserved_2 */ NULL,
(GtkClassInitFunc) gtk_object_base_class_init,
};
object_type = gtk_type_unique (0, &object_info);
g_assert (object_type == GTK_TYPE_OBJECT);
#ifdef G_ENABLE_DEBUG
if (gtk_debug_flags & GTK_DEBUG_OBJECTS)
ATEXIT (gtk_object_debug);
#endif /* G_ENABLE_DEBUG */
}
GtkType
gtk_object_get_type (void)
{
return GTK_TYPE_OBJECT;
}
static void
gtk_object_base_class_init (GtkObjectClass *class)
{
/* reset instance specific fields that don't get inhrited */
class->signals = NULL;
class->nsignals = 0;
class->n_args = 0;
/* reset instance specifc methods that don't get inherited */
class->get_arg = NULL;
class->set_arg = NULL;
}
static void
gtk_object_class_init (GtkObjectClass *class)
{
gtk_object_add_arg_type ("GtkObject::user_data",
GTK_TYPE_POINTER,
GTK_ARG_READWRITE,
ARG_USER_DATA);
gtk_object_add_arg_type ("GtkObject::signal",
GTK_TYPE_SIGNAL,
GTK_ARG_WRITABLE,
ARG_SIGNAL);
gtk_object_add_arg_type ("GtkObject::signal_after",
GTK_TYPE_SIGNAL,
GTK_ARG_WRITABLE,
ARG_SIGNAL_AFTER);
gtk_object_add_arg_type ("GtkObject::object_signal",
GTK_TYPE_SIGNAL,
GTK_ARG_WRITABLE,
ARG_OBJECT_SIGNAL);
gtk_object_add_arg_type ("GtkObject::object_signal_after",
GTK_TYPE_SIGNAL,
GTK_ARG_WRITABLE,
ARG_OBJECT_SIGNAL_AFTER);
object_signals[DESTROY] =
gtk_signal_new ("destroy",
GTK_RUN_LAST,
class->type,
GTK_SIGNAL_OFFSET (GtkObjectClass, destroy),
gtk_signal_default_marshaller,
GTK_TYPE_NONE, 0);
gtk_object_class_add_signals (class, object_signals, LAST_SIGNAL);
class->get_arg = gtk_object_get_arg;
class->set_arg = gtk_object_set_arg;
class->shutdown = gtk_object_shutdown;
class->destroy = gtk_object_real_destroy;
class->finalize = gtk_object_finalize;
}
static void
gtk_object_init (GtkObject *object)
{
GTK_OBJECT_FLAGS (object) = GTK_FLOATING;
object->ref_count = 1;
object->object_data = NULL;
#ifdef G_ENABLE_DEBUG
if (gtk_debug_flags & GTK_DEBUG_OBJECTS)
{
obj_count++;
if (!living_objs_ht)
living_objs_ht = g_hash_table_new (g_direct_hash, NULL);
g_hash_table_insert (living_objs_ht, object, object);
}
#endif /* G_ENABLE_DEBUG */
}
/********************************************
* Functions to end a GtkObject's life time
*
********************************************/
void
gtk_object_destroy (GtkObject *object)
{
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_OBJECT (object));
if (!GTK_OBJECT_DESTROYED (object))
{
/* we will hold a reference on the object in this place, so
* to ease all classes shutdown and destroy implementations.
* i.e. they don't have to bother about referencing at all.
*/
gtk_object_ref (object);
object->klass->shutdown (object);
gtk_object_unref (object);
}
}
static void
gtk_object_shutdown (GtkObject *object)
{
GTK_OBJECT_SET_FLAGS (object, GTK_DESTROYED);
gtk_signal_emit (object, object_signals[DESTROY]);
}
static void
gtk_object_real_destroy (GtkObject *object)
{
if (GTK_OBJECT_CONNECTED (object))
gtk_signal_handlers_destroy (object);
}
static void
gtk_object_finalize (GtkObject *object)
{
gtk_object_notify_weaks (object);
while (object->object_data)
{
GtkObjectData *odata;
odata = object->object_data;
object->object_data = odata->next;
GTK_OBJECT_DATA_DESTROY (odata);
}
gtk_type_free (GTK_OBJECT_TYPE (object), object);
}
/*****************************************
* GtkObject argument handlers
*
*****************************************/
static void
gtk_object_set_arg (GtkObject *object,
GtkArg *arg,
guint arg_id)
{
guint n = 0;
switch (arg_id)
{
gchar *arg_name;
case ARG_USER_DATA:
gtk_object_set_user_data (object, GTK_VALUE_POINTER (*arg));
break;
case ARG_OBJECT_SIGNAL_AFTER:
n += 6;
case ARG_OBJECT_SIGNAL:
n += 1;
case ARG_SIGNAL_AFTER:
n += 6;
case ARG_SIGNAL:
n += 6;
arg_name = gtk_arg_name_strip_type (arg->name);
if (arg_name &&
arg_name[n] == ':' &&
arg_name[n + 1] == ':' &&
arg_name[n + 2] != 0)
{
gtk_signal_connect_full (object,
arg_name + n + 2,
(GtkSignalFunc) GTK_VALUE_SIGNAL (*arg).f, NULL,
GTK_VALUE_SIGNAL (*arg).d,
NULL,
(arg_id == ARG_OBJECT_SIGNAL ||
arg_id == ARG_OBJECT_SIGNAL_AFTER),
(arg_id == ARG_OBJECT_SIGNAL_AFTER ||
arg_id == ARG_SIGNAL_AFTER));
}
else
g_warning ("gtk_object_set_arg(): invalid signal argument: \"%s\"\n", arg->name);
break;
default:
break;
}
}
static void
gtk_object_get_arg (GtkObject *object,
GtkArg *arg,
guint arg_id)
{
switch (arg_id)
{
case ARG_USER_DATA:
GTK_VALUE_POINTER (*arg) = gtk_object_get_user_data (object);
break;
case ARG_SIGNAL:
case ARG_OBJECT_SIGNAL:
default:
arg->type = GTK_TYPE_INVALID;
break;
}
}
/*****************************************
* gtk_object_class_add_signals:
*
* arguments:
*
* results:
*****************************************/
void
gtk_object_class_add_signals (GtkObjectClass *class,
guint *signals,
guint nsignals)
{
guint *new_signals;
guint i;
g_return_if_fail (class != NULL);
new_signals = g_new (guint, class->nsignals + nsignals);
for (i = 0; i < class->nsignals; i++)
new_signals[i] = class->signals[i];
for (i = 0; i < nsignals; i++)
new_signals[class->nsignals + i] = signals[i];
g_free (class->signals);
class->signals = new_signals;
class->nsignals += nsignals;
}
guint
gtk_object_class_add_user_signal (GtkObjectClass *class,
const gchar *name,
GtkSignalMarshaller marshaller,
GtkType return_val,
guint nparams,
...)
{
GtkType *params;
guint i;
va_list args;
guint signal_id;
g_return_val_if_fail (class != NULL, 0);
if (nparams > 0)
{
params = g_new (GtkType, nparams);
va_start (args, nparams);
for (i = 0; i < nparams; i++)
params[i] = va_arg (args, GtkType);
va_end (args);
}
else
params = NULL;
signal_id = gtk_signal_newv (name,
0,
class->type,
0,
marshaller,
return_val,
nparams,
params);
g_free (params);
if (signal_id)
gtk_object_class_add_signals (class, &signal_id, 1);
return signal_id;
}
guint
gtk_object_class_user_signal_new (GtkObjectClass *class,
const gchar *name,
GtkSignalRunType signal_flags,
GtkSignalMarshaller marshaller,
GtkType return_val,
guint nparams,
...)
{
GtkType *params;
guint i;
va_list args;
guint signal_id;
g_return_val_if_fail (class != NULL, 0);
if (nparams > 0)
{
params = g_new (GtkType, nparams);
va_start (args, nparams);
for (i = 0; i < nparams; i++)
params[i] = va_arg (args, GtkType);
va_end (args);
}
else
params = NULL;
signal_id = gtk_signal_newv (name,
signal_flags,
class->type,
0,
marshaller,
return_val,
nparams,
params);
g_free (params);
if (signal_id)
gtk_object_class_add_signals (class, &signal_id, 1);
return signal_id;
}
guint
gtk_object_class_user_signal_newv (GtkObjectClass *class,
const gchar *name,
GtkSignalRunType signal_flags,
GtkSignalMarshaller marshaller,
GtkType return_val,
guint nparams,
GtkType *params)
{
guint signal_id;
g_return_val_if_fail (class != NULL, 0);
if (nparams > 0)
g_return_val_if_fail (params != NULL, 0);
signal_id = gtk_signal_newv (name,
signal_flags,
class->type,
0,
marshaller,
return_val,
nparams,
params);
if (signal_id)
gtk_object_class_add_signals (class, &signal_id, 1);
return signal_id;
}
/*****************************************
* gtk_object_sink:
*
* arguments:
*
* results:
*****************************************/
void
gtk_object_sink (GtkObject *object)
{
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_OBJECT (object));
if (GTK_OBJECT_FLOATING (object))
{
GTK_OBJECT_UNSET_FLAGS (object, GTK_FLOATING);
gtk_object_unref (object);
}
}
/*****************************************
* Weak references.
*
* Weak refs are very similar to the old "destroy" signal. They allow
* one to register a callback that is called when the weakly
* referenced object is finalized.
*
* They are not implemented as a signal because they really are
* special and need to be used with great care. Unlike signals, which
* should be able to execute any code whatsoever.
*
* A weakref callback is not allowed to retain a reference to the
* object. Object data keys may be retrieved in a weak reference
* callback.
*
* A weakref callback is called at most once.
*
*****************************************/
typedef struct _GtkWeakRef GtkWeakRef;
struct _GtkWeakRef
{
GtkWeakRef *next;
GtkDestroyNotify notify;
gpointer data;
};
void
gtk_object_weakref (GtkObject *object,
GtkDestroyNotify notify,
gpointer data)
{
GtkWeakRef *weak;
g_return_if_fail (object != NULL);
g_return_if_fail (notify != NULL);
g_return_if_fail (GTK_IS_OBJECT (object));
if (!weakrefs_key_id)
weakrefs_key_id = g_quark_from_static_string (weakrefs_key);
weak = g_new (GtkWeakRef, 1);
weak->next = gtk_object_get_data_by_id (object, weakrefs_key_id);
weak->notify = notify;
weak->data = data;
gtk_object_set_data_by_id (object, weakrefs_key_id, weak);
}
void
gtk_object_weakunref (GtkObject *object,
GtkDestroyNotify notify,
gpointer data)
{
GtkWeakRef *weaks, *w, **wp;
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_OBJECT (object));
if (!weakrefs_key_id)
return;
weaks = gtk_object_get_data_by_id (object, weakrefs_key_id);
for (wp = &weaks; *wp; wp = &(*wp)->next)
{
w = *wp;
if (w->notify == notify && w->data == data)
{
if (w == weaks)
gtk_object_set_data_by_id (object, weakrefs_key_id, w->next);
else
*wp = w->next;
g_free (w);
return;
}
}
}
static void
gtk_object_notify_weaks (GtkObject *object)
{
if (weakrefs_key_id)
{
GtkWeakRef *w1, *w2;
w1 = gtk_object_get_data_by_id (object, weakrefs_key_id);
while (w1)
{
w1->notify (w1->data);
w2 = w1->next;
g_free (w1);
w1 = w2;
}
}
}
/****************************************************
* GtkObject argument mechanism and object creation
*
****************************************************/
GtkObject*
gtk_object_new (GtkType object_type,
...)
{
GtkObject *object;
va_list var_args;
GSList *arg_list = NULL;
GSList *info_list = NULL;
gchar *error;
g_return_val_if_fail (GTK_FUNDAMENTAL_TYPE (object_type) == GTK_TYPE_OBJECT, NULL);
object = gtk_type_new (object_type);
va_start (var_args, object_type);
error = gtk_object_args_collect (GTK_OBJECT_TYPE (object),
&arg_list,
&info_list,
&var_args);
va_end (var_args);
if (error)
{
g_warning ("gtk_object_new(): %s", error);
g_free (error);
}
else
{
GSList *slist_arg;
GSList *slist_info;
slist_arg = arg_list;
slist_info = info_list;
while (slist_arg)
{
gtk_object_arg_set (object, slist_arg->data, slist_info->data);
slist_arg = slist_arg->next;
slist_info = slist_info->next;
}
gtk_args_collect_cleanup (arg_list, info_list);
}
return object;
}
GtkObject*
gtk_object_newv (GtkType object_type,
guint n_args,
GtkArg *args)
{
GtkObject *object;
GtkArg *max_args;
g_return_val_if_fail (GTK_FUNDAMENTAL_TYPE (object_type) == GTK_TYPE_OBJECT, NULL);
if (n_args)
g_return_val_if_fail (args != NULL, NULL);
object = gtk_type_new (object_type);
for (max_args = args + n_args; args < max_args; args++)
gtk_object_arg_set (object, args, NULL);
return object;
}
void
gtk_object_setv (GtkObject *object,
guint n_args,
GtkArg *args)
{
GtkArg *max_args;
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_OBJECT (object));
if (n_args)
g_return_if_fail (args != NULL);
for (max_args = args + n_args; args < max_args; args++)
gtk_object_arg_set (object, args, NULL);
}
void
gtk_object_getv (GtkObject *object,
guint n_args,
GtkArg *args)
{
GtkArg *max_args;
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_OBJECT (object));
if (n_args)
g_return_if_fail (args != NULL);
for (max_args = args + n_args; args < max_args; args++)
gtk_object_arg_get (object, args, NULL);
}
void
gtk_object_set (GtkObject *object,
...)
{
va_list var_args;
GSList *arg_list = NULL;
GSList *info_list = NULL;
gchar *error;
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_OBJECT (object));
va_start (var_args, object);
error = gtk_object_args_collect (GTK_OBJECT_TYPE (object),
&arg_list,
&info_list,
&var_args);
va_end (var_args);
if (error)
{
g_warning ("gtk_object_set(): %s", error);
g_free (error);
}
else
{
GSList *slist_arg;
GSList *slist_info;
slist_arg = arg_list;
slist_info = info_list;
while (slist_arg)
{
gtk_object_arg_set (object, slist_arg->data, slist_info->data);
slist_arg = slist_arg->next;
slist_info = slist_info->next;
}
gtk_args_collect_cleanup (arg_list, info_list);
}
}
void
gtk_object_arg_set (GtkObject *object,
GtkArg *arg,
GtkArgInfo *info)
{
GtkObjectClass *oclass;
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_OBJECT (object));
g_return_if_fail (arg != NULL);
if (!info)
{
gchar *error;
error = gtk_arg_get_info (GTK_OBJECT_TYPE (object),
object_arg_info_ht,
arg->name,
&info);
if (error)
{
g_warning ("gtk_object_arg_set(): %s", error);
g_free (error);
return;
}
}
if (! (info->arg_flags & GTK_ARG_WRITABLE))
{
g_warning ("gtk_object_arg_set(): argument \"%s\" is not writable",
info->full_name);
return;
}
if (info->type != arg->type)
{
g_warning ("gtk_object_arg_set(): argument \"%s\" has invalid type `%s'",
info->full_name,
gtk_type_name (arg->type));
return;
}
oclass = gtk_type_class (info->class_type);
if (oclass->set_arg)
oclass->set_arg (object, arg, info->arg_id);
}
void
gtk_object_arg_get (GtkObject *object,
GtkArg *arg,
GtkArgInfo *info)
{
GtkObjectClass *oclass;
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_OBJECT (object));
g_return_if_fail (arg != NULL);
if (!info)
{
gchar *error;
error = gtk_arg_get_info (GTK_OBJECT_TYPE (object),
object_arg_info_ht,
arg->name,
&info);
if (error)
{
g_warning ("gtk_object_arg_get(): %s", error);
g_free (error);
arg->type = GTK_TYPE_INVALID;
return;
}
}
if (! (info->arg_flags & GTK_ARG_READABLE))
{
g_warning ("gtk_object_arg_get(): argument \"%s\" is not readable",
info->full_name);
arg->type = GTK_TYPE_INVALID;
return;
}
oclass = gtk_type_class (info->class_type);
if (oclass->get_arg)
{
arg->type = info->type;
oclass->get_arg (object, arg, info->arg_id);
}
else
arg->type = GTK_TYPE_INVALID;
}
void
gtk_object_add_arg_type (const char *arg_name,
GtkType arg_type,
guint arg_flags,
guint arg_id)
{
g_return_if_fail (arg_name != NULL);
g_return_if_fail (arg_type > GTK_TYPE_NONE);
g_return_if_fail (arg_id > 0);
g_return_if_fail ((arg_flags & GTK_ARG_READWRITE) != 0);
g_return_if_fail ((arg_flags & GTK_ARG_CHILD_ARG) == 0);
if (!object_arg_info_ht)
object_arg_info_ht = g_hash_table_new (gtk_arg_info_hash,
gtk_arg_info_equal);
gtk_arg_type_new_static (GTK_TYPE_OBJECT,
arg_name,
GTK_STRUCT_OFFSET (GtkObjectClass, n_args),
object_arg_info_ht,
arg_type,
arg_flags,
arg_id);
}
gchar*
gtk_object_args_collect (GtkType object_type,
GSList **arg_list_p,
GSList **info_list_p,
gpointer var_args_p)
{
return gtk_args_collect (object_type,
object_arg_info_ht,
arg_list_p,
info_list_p,
var_args_p);
}
GtkArg*
gtk_object_query_args (GtkType class_type,
guint32 **arg_flags,
guint *n_args)
{
g_return_val_if_fail (n_args != NULL, NULL);
*n_args = 0;
g_return_val_if_fail (GTK_FUNDAMENTAL_TYPE (class_type) == GTK_TYPE_OBJECT, NULL);
return gtk_args_query (class_type, object_arg_info_ht, arg_flags, n_args);
}
/********************************************************
* GtkObject and GtkObjectClass cast checking functions
*
********************************************************/
static gchar*
gtk_object_descriptive_type_name (GtkType type)
{
gchar *name;
name = gtk_type_name (type);
if (!name)
name = "(unknown)";
return name;
}
GtkObject*
gtk_object_check_cast (GtkObject *obj,
GtkType cast_type)
{
if (!obj)
{
g_warning ("invalid cast from (NULL) pointer to `%s'",
gtk_object_descriptive_type_name (cast_type));
return obj;
}
if (!obj->klass)
{
g_warning ("invalid unclassed pointer in cast to `%s'",
gtk_object_descriptive_type_name (cast_type));
return obj;
}
if (obj->klass->type < GTK_TYPE_OBJECT)
{
g_warning ("invalid class type `%s' in cast to `%s'",
gtk_object_descriptive_type_name (obj->klass->type),
gtk_object_descriptive_type_name (cast_type));
return obj;
}
if (!gtk_type_is_a (obj->klass->type, cast_type))
{
g_warning ("invalid cast from `%s' to `%s'",
gtk_object_descriptive_type_name (obj->klass->type),
gtk_object_descriptive_type_name (cast_type));
return obj;
}
return obj;
}
GtkObjectClass*
gtk_object_check_class_cast (GtkObjectClass *klass,
GtkType cast_type)
{
if (!klass)
{
g_warning ("invalid class cast from (NULL) pointer to `%s'",
gtk_object_descriptive_type_name (cast_type));
return klass;
}
if (klass->type < GTK_TYPE_OBJECT)
{
g_warning ("invalid class type `%s' in class cast to `%s'",
gtk_object_descriptive_type_name (klass->type),
gtk_object_descriptive_type_name (cast_type));
return klass;
}
if (!gtk_type_is_a (klass->type, cast_type))
{
g_warning ("invalid class cast from `%s' to `%s'",
gtk_object_descriptive_type_name (klass->type),
gtk_object_descriptive_type_name (cast_type));
return klass;
}
return klass;
}
/*****************************************
* GtkObject object_data mechanism
*
*****************************************/
void
gtk_object_set_data_by_id (GtkObject *object,
GQuark data_id,
gpointer data)
{
g_return_if_fail (data_id > 0);
gtk_object_set_data_by_id_full (object, data_id, data, NULL);
}
void
gtk_object_set_data (GtkObject *object,
const gchar *key,
gpointer data)
{
g_return_if_fail (key != NULL);
gtk_object_set_data_by_id_full (object, gtk_object_data_force_id (key), data, NULL);
}
void
gtk_object_set_data_by_id_full (GtkObject *object,
GQuark data_id,
gpointer data,
GtkDestroyNotify destroy)
{
GtkObjectData *odata;
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_OBJECT (object));
g_return_if_fail (data_id > 0);
odata = object->object_data;
if (!data)
{
GtkObjectData *prev;
prev = NULL;
while (odata)
{
if (odata->id == data_id)
{
if (prev)
prev->next = odata->next;
else
object->object_data = odata->next;
GTK_OBJECT_DATA_DESTROY (odata);
return;
}
prev = odata;
odata = odata->next;
}
}
else
{
while (odata)
{
if (odata->id == data_id)
{
register GtkDestroyNotify dfunc;
register gpointer ddata;
dfunc = odata->destroy;
ddata = odata->data;
odata->destroy = destroy;
odata->data = data;
/* we need to have updated all structures prior to
* invokation of the destroy function
*/
if (dfunc)
dfunc (ddata);
return;
}
odata = odata->next;
}
if (gtk_object_data_free_list)
{
odata = gtk_object_data_free_list;
gtk_object_data_free_list = odata->next;
}
else
{
GtkObjectData *odata_block;
guint i;
odata_block = g_new0 (GtkObjectData, GTK_OBJECT_DATA_BLOCK_SIZE);
for (i = 1; i < GTK_OBJECT_DATA_BLOCK_SIZE; i++)
{
(odata_block + i)->next = gtk_object_data_free_list;
gtk_object_data_free_list = (odata_block + i);
}
odata = odata_block;
}
odata->id = data_id;
odata->data = data;
odata->destroy = destroy;
odata->next = object->object_data;
object->object_data = odata;
}
}
void
gtk_object_set_data_full (GtkObject *object,
const gchar *key,
gpointer data,
GtkDestroyNotify destroy)
{
g_return_if_fail (key != NULL);
gtk_object_set_data_by_id_full (object, gtk_object_data_force_id (key), data, destroy);
}
gpointer
gtk_object_get_data_by_id (GtkObject *object,
GQuark data_id)
{
GtkObjectData *odata;
g_return_val_if_fail (object != NULL, NULL);
g_return_val_if_fail (GTK_IS_OBJECT (object), NULL);
if (data_id)
{
odata = object->object_data;
while (odata)
{
if (odata->id == data_id)
return odata->data;
odata = odata->next;
}
}
return NULL;
}
gpointer
gtk_object_get_data (GtkObject *object,
const gchar *key)
{
guint id;
g_return_val_if_fail (key != NULL, NULL);
id = gtk_object_data_try_key (key);
if (id)
return gtk_object_get_data_by_id (object, id);
return NULL;
}
void
gtk_object_remove_data_by_id (GtkObject *object,
GQuark data_id)
{
if (data_id)
gtk_object_set_data_by_id_full (object, data_id, NULL, NULL);
}
void
gtk_object_remove_data (GtkObject *object,
const gchar *key)
{
gint id;
g_return_if_fail (key != NULL);
id = gtk_object_data_try_key (key);
if (id)
gtk_object_set_data_by_id_full (object, id, NULL, NULL);
}
void
gtk_object_set_user_data (GtkObject *object,
gpointer data)
{
if (!user_data_key_id)
user_data_key_id = g_quark_from_static_string (user_data_key);
gtk_object_set_data_by_id_full (object, user_data_key_id, data, NULL);
}
gpointer
gtk_object_get_user_data (GtkObject *object)
{
if (user_data_key_id)
return gtk_object_get_data_by_id (object, user_data_key_id);
return NULL;
}
/*******************************************
* GtkObject referencing and unreferencing
*
*******************************************/
#undef gtk_object_ref
#undef gtk_object_unref
void
gtk_object_ref (GtkObject *object)
{
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_OBJECT (object));
object->ref_count += 1;
}
void
gtk_object_unref (GtkObject *object)
{
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_OBJECT (object));
if (object->ref_count == 1)
gtk_object_destroy (object);
if (object->ref_count > 0)
object->ref_count -= 1;
if (object->ref_count == 0)
{
#ifdef G_ENABLE_DEBUG
if (gtk_debug_flags & GTK_DEBUG_OBJECTS)
{
g_assert (g_hash_table_lookup (living_objs_ht, object) == object);
g_hash_table_remove (living_objs_ht, object);
obj_count--;
}
#endif /* G_ENABLE_DEBUG */
object->klass->finalize (object);
}
}
static GtkObject *gtk_trace_object = NULL;
void
gtk_trace_referencing (GtkObject *object,
const gchar *func,
guint dummy,
guint line,
gboolean do_ref)
{
if (gtk_debug_flags & GTK_DEBUG_OBJECTS)
{
gboolean exists = TRUE;
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_OBJECT (object));
#ifdef G_ENABLE_DEBUG
exists = g_hash_table_lookup (living_objs_ht, object) != NULL;
#endif /* G_ENABLE_DEBUG */
if (exists &&
(object == gtk_trace_object ||
gtk_trace_object == (void*)42))
fprintf (stdout, "trace: object_%s: (%s:%p)->ref_count=%d %s (%s:%d)\n",
do_ref ? "ref" : "unref",
gtk_type_name (GTK_OBJECT_TYPE (object)),
object,
object->ref_count,
do_ref ? "+ 1" : "- 1",
func,
line);
else if (!exists)
fprintf (stdout, "trace: object_%s(%p): no such object! (%s:%d)\n",
do_ref ? "ref" : "unref",
object,
func,
line);
}
if (do_ref)
gtk_object_ref (object);
else
gtk_object_unref (object);
}