From db6a8d4a8a6b817458b1fe1f8e334bb24aef4dfa Mon Sep 17 00:00:00 2001 From: Tim Janik Date: Thu, 29 Jan 1998 20:44:14 +0000 Subject: [PATCH] new user signal, and possibility to query signal information. -timj --- gtk/gtkobject.c | 55 +++++++++++++++++ gtk/gtkobject.h | 21 +++++++ gtk/gtksignal.c | 143 +++++++++++++++++++++++++++++++++++---------- gtk/gtksignal.h | 35 ++++++++--- gtk/gtktypeutils.c | 2 + 5 files changed, 216 insertions(+), 40 deletions(-) diff --git a/gtk/gtkobject.c b/gtk/gtkobject.c index e307538dec..8a28f9063b 100644 --- a/gtk/gtkobject.c +++ b/gtk/gtkobject.c @@ -256,10 +256,65 @@ gtk_object_class_add_signals (GtkObjectClass *class, for (i = 0; i < nsignals; i++) new_signals[class->nsignals + i] = signals[i]; + g_free (class->signals); class->signals = new_signals; class->nsignals += nsignals; } +/***************************************** + * gtk_object_class_add_user_signal: + * + * arguments: + * + * results: + *****************************************/ + +gint +gtk_object_class_add_user_signal (GtkObjectClass *class, + const gchar *name, + GtkSignalMarshaller marshaller, + GtkType return_val, + gint nparams, + ...) +{ + GtkType *params; + guint i; + va_list args; + gint 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; +} + /***************************************** * gtk_object_ref: * diff --git a/gtk/gtkobject.h b/gtk/gtkobject.h index a7ae98a2a3..97a77fc3fd 100644 --- a/gtk/gtkobject.h +++ b/gtk/gtkobject.h @@ -161,6 +161,18 @@ struct _GtkObjectClass }; +/* For the purpose of user signals we need the signal function + * and signal marshaller signatures already in this place. + */ +#define GTK_SIGNAL_FUNC(f) ((GtkSignalFunc) f) + +typedef void (*GtkSignalFunc) (void); +typedef void (*GtkSignalMarshaller) (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); + + /* Get the type identifier for GtkObject's. */ guint gtk_object_get_type (void); @@ -171,6 +183,15 @@ void gtk_object_class_add_signals (GtkObjectClass *klass, gint *signals, gint nsignals); +/* Append a user defined signal without default handler to a class. + */ +gint gtk_object_class_add_user_signal (GtkObjectClass *klass, + const gchar *name, + GtkSignalMarshaller marshaller, + GtkType return_val, + gint nparams, + ...); + GtkObject* gtk_object_new (guint type, ...); diff --git a/gtk/gtksignal.c b/gtk/gtksignal.c index 00a54fb166..2857262954 100644 --- a/gtk/gtksignal.c +++ b/gtk/gtksignal.c @@ -161,15 +161,60 @@ gtk_signal_new (const gchar *name, ...) { GtkType *params; + guint i; + va_list args; + gint return_id; + + g_return_val_if_fail (nparams < 16, 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; + + return_id = gtk_signal_newv (name, + run_type, + object_type, + function_offset, + marshaller, + return_val, + nparams, + params); + + g_free (params); + + return return_id; +} + +gint +gtk_signal_newv (const gchar *name, + GtkSignalRunType run_type, + gint object_type, + gint function_offset, + GtkSignalMarshaller marshaller, + GtkType return_val, + gint nparams, + GtkType *params) +{ GtkSignal *signal; GtkSignalInfo info; gint *type; - gint i; - va_list args; + guint i; g_return_val_if_fail (name != NULL, 0); g_return_val_if_fail (marshaller != NULL, 0); - g_return_val_if_fail (nparams < 10, 0); + g_return_val_if_fail (nparams < 16, 0); + if (nparams) + g_return_val_if_fail (params != NULL, 0); if (initialize) gtk_signal_init (); @@ -186,35 +231,56 @@ gtk_signal_new (const gchar *name, } signal = g_new (GtkSignal, 1); - signal->info.name = g_strdup(name); + signal->info.name = g_strdup (name); signal->info.object_type = object_type; signal->info.signal_type = next_signal++; signal->function_offset = function_offset; signal->run_type = run_type; signal->marshaller = marshaller; signal->return_val = return_val; - signal->params = NULL; signal->nparams = nparams; - g_hash_table_insert (signal_hash_table, &signal->info.signal_type, signal); - g_hash_table_insert (signal_info_hash_table, &signal->info, &signal->info.signal_type); - if (nparams > 0) { signal->params = g_new (GtkType, nparams); - params = signal->params; - - va_start (args, nparams); for (i = 0; i < nparams; i++) - params[i] = va_arg (args, GtkType); - - va_end (args); + signal->params[i] = params[i]; } + else + signal->params = NULL; + + g_hash_table_insert (signal_hash_table, &signal->info.signal_type, signal); + g_hash_table_insert (signal_info_hash_table, &signal->info, &signal->info.signal_type); return signal->info.signal_type; } +GtkSignalQuery* +gtk_signal_query (gint signal_num) +{ + GtkSignalQuery *query; + GtkSignal *signal; + + signal = g_hash_table_lookup (signal_hash_table, &signal_num); + if (signal) + { + query = g_new (GtkSignalQuery, 1); + + query->object_type = signal->info.object_type; + query->signal_name = signal->info.name; + query->is_user_signal = signal->function_offset == 0; + query->run_type = signal->run_type; + query->return_val = signal->return_val; + query->nparams = signal->nparams; + query->params = signal->params; + } + else + query = NULL; + + return query; +} + gint gtk_signal_lookup (const gchar *name, gint object_type) @@ -871,7 +937,7 @@ gtk_signal_real_emit (GtkObject *object, gtk_emission_add (¤t_emissions, object, signal_type); restart: - if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_LAST) + if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_LAST && signal->function_offset != 0) { signal_func_offset = (guchar**) ((guchar*) object->klass + signal->function_offset); if (*signal_func_offset) @@ -898,7 +964,7 @@ gtk_signal_real_emit (GtkObject *object, goto restart; } - if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_FIRST) + if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_FIRST && signal->function_offset != 0) { signal_func_offset = (guchar**) ((guchar*) object->klass + signal->function_offset); if (*signal_func_offset) @@ -965,31 +1031,44 @@ gtk_signal_connect_by_type (GtkObject *object, gint after, gint no_marshal) { + GtkObjectClass *class; GtkHandler *handler; - gint *object_signals; - gint nsignals; gint found_it; - gint i; g_return_val_if_fail (object != NULL, 0); g_return_val_if_fail (object->klass != NULL, 0); - g_return_val_if_fail (object->klass->signals != NULL, 0); /* Search through the signals for this object and make - * sure the one we are adding is valid. If it isn't then - * issue a warning and return. + * sure the one we are adding is valid. We need to perform + * the lookup on the objects parents as well. If it isn't + * valid then issue a warning and return. */ - object_signals = object->klass->signals; - nsignals = object->klass->nsignals; found_it = FALSE; - - for (i = 0; i < nsignals; i++) - if (object_signals[i] == signal_type) - { - found_it = TRUE; - break; - } - + class = object->klass; + while (class) + { + GtkType parent; + gint *object_signals; + gint nsignals; + guint i; + + object_signals = class->signals; + nsignals = class->nsignals; + + for (i = 0; i < nsignals; i++) + if (object_signals[i] == signal_type) + { + found_it = TRUE; + break; + } + + parent = gtk_type_parent (class->type); + if (parent) + class = gtk_type_class (parent); + else + class = NULL; + } + if (!found_it) { g_warning ("could not find signal (%d) in object's list of signals", signal_type); diff --git a/gtk/gtksignal.h b/gtk/gtksignal.h index 68ff999025..8519cf9dac 100644 --- a/gtk/gtksignal.h +++ b/gtk/gtksignal.h @@ -35,14 +35,7 @@ extern "C" { #define GTK_SIGNAL_OFFSET(t, f) ((int) ((char*) &((t*) 0)->f)) #endif /* offsetof */ -#define GTK_SIGNAL_FUNC(f) ((GtkSignalFunc) f) - - -typedef void (*GtkSignalFunc) (void); -typedef void (*GtkSignalMarshaller) (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); + typedef void (*GtkSignalMarshal) (GtkObject *object, gpointer data, gint nparams, @@ -51,6 +44,18 @@ typedef void (*GtkSignalMarshal) (GtkObject *object, GtkType return_type); typedef void (*GtkSignalDestroy) (gpointer data); +typedef struct _GtkSignalQuery GtkSignalQuery; + +struct _GtkSignalQuery +{ + gint object_type; + const gchar *signal_name; + gboolean is_user_signal; + GtkSignalRunType run_type; + GtkType return_val; + guint nparams; + const GtkType *params; +}; gint gtk_signal_new (const gchar *name, GtkSignalRunType run_type, @@ -60,6 +65,14 @@ gint gtk_signal_new (const gchar *name, GtkType return_val, gint nparams, ...); +gint gtk_signal_newv (const gchar *name, + GtkSignalRunType run_type, + gint object_type, + gint function_offset, + GtkSignalMarshaller marshaller, + GtkType return_val, + gint nparams, + GtkType *params); gint gtk_signal_lookup (const gchar *name, gint object_type); gchar* gtk_signal_name (gint signal_num); @@ -115,6 +128,12 @@ void gtk_signal_default_marshaller (GtkObject *object, void gtk_signal_set_funcs (GtkSignalMarshal marshal_func, GtkSignalDestroy destroy_func); +/* Report internal information about a signal. The caller has the response + * to invoke a supsequent g_free (returned_data); but must leave the + * contents of GtkSignalQuery untouched. + */ +GtkSignalQuery* gtk_signal_query (gint signal_num); + #ifdef __cplusplus } diff --git a/gtk/gtktypeutils.c b/gtk/gtktypeutils.c index b27b9c6dd4..599a6f3b6d 100644 --- a/gtk/gtktypeutils.c +++ b/gtk/gtktypeutils.c @@ -356,6 +356,8 @@ gtk_type_class_init (GtkTypeNode *node) object_class = node->klass; object_class->type = node->type; + object_class->signals = NULL; + object_class->nsignals = 0; object_class->n_args = 0; if (node->type_info.class_init_func)