diff options
Diffstat (limited to 'gtk/gtksignal.c')
-rw-r--r-- | gtk/gtksignal.c | 110 |
1 files changed, 104 insertions, 6 deletions
diff --git a/gtk/gtksignal.c b/gtk/gtksignal.c index f9b3bec44c..7bfd9ee17b 100644 --- a/gtk/gtksignal.c +++ b/gtk/gtksignal.c @@ -36,7 +36,7 @@ enum EMISSION_DONE }; -#define GTK_RUN_TYPE(x) ((x) & GTK_RUN_MASK) +#define GTK_RUN_TYPE(x) ((x) & GTK_RUN_BOTH) typedef struct _GtkSignal GtkSignal; @@ -55,11 +55,12 @@ struct _GtkSignal GtkType object_type; gchar *name; guint function_offset; - GtkSignalRunType signal_flags; GtkSignalMarshaller marshaller; GtkType return_val; + GtkSignalRunType signal_flags : 16; + guint nparams : 16; GtkType *params; - guint nparams; + GHookList *hook_list; }; struct _GtkSignalHash @@ -145,7 +146,9 @@ static gint gtk_handlers_run (GtkHandler *handlers, GtkObject *object, GtkArg *params, gint after); -static gboolean gtk_signal_collect_params (GtkArg *params, +static gboolean gtk_emission_hook_marshaller (GHook *hook, + gpointer data); +static gboolean gtk_signal_collect_params (GtkArg *params, guint nparams, GtkType *param_types, GtkType return_type, @@ -303,10 +306,11 @@ gtk_signal_newv (const gchar *r_name, signal->object_type = object_type; signal->name = name; signal->function_offset = function_offset; - signal->signal_flags = signal_flags; signal->marshaller = marshaller; signal->return_val = return_val; + signal->signal_flags = signal_flags; signal->nparams = nparams; + signal->hook_list = NULL; if (nparams > 0) { @@ -1419,7 +1423,17 @@ gtk_signal_real_emit (GtkObject *object, } } } - + + /* do *not* reorder this call! */ + if (signal.hook_list) + { + gpointer data[2]; + + data[0] = &signal; + data[1] = object; + g_hook_list_marshal_check (signal.hook_list, TRUE, gtk_emission_hook_marshaller, &data); + } + emission_done: gtk_emission_remove (¤t_emissions, object, signal_id); @@ -1517,6 +1531,90 @@ gtk_signal_handler_pending_by_func (GtkObject *object, return handler_id; } +guint +gtk_signal_add_emission_hook (guint signal_id, + GtkEmissionHook hook_func, + gpointer data) +{ + return gtk_signal_add_emission_hook_full (signal_id, hook_func, data, NULL); +} + +guint +gtk_signal_add_emission_hook_full (guint signal_id, + GtkEmissionHook hook_func, + gpointer data, + GDestroyNotify destroy) +{ + static guint seq_hook_id = 1; + GtkSignal *signal; + GHook *hook; + + g_return_val_if_fail (signal_id > 0, 0); + g_return_val_if_fail (hook_func != NULL, 0); + + signal = LOOKUP_SIGNAL_ID (signal_id); + g_return_val_if_fail (signal != NULL, 0); + if (signal->signal_flags & GTK_RUN_NO_HOOKS) + { + g_warning ("gtk_signal_add_emission_hook_full(): signal \"%s\" does not support emission hooks", + signal->name); + return 0; + } + + if (!signal->hook_list) + { + signal->hook_list = g_new (GHookList, 1); + g_hook_list_init (signal->hook_list, sizeof (GHook)); + } + + hook = g_hook_alloc (signal->hook_list); + hook->data = data; + hook->func = hook_func; + hook->destroy = destroy; + + signal->hook_list->seq_id = seq_hook_id; + g_hook_prepend (signal->hook_list, hook); + seq_hook_id = signal->hook_list->seq_id; + + return hook->hook_id; +} + +void +gtk_signal_remove_emission_hook (guint signal_id, + guint hook_id) +{ + GtkSignal *signal; + + g_return_if_fail (signal_id > 0); + g_return_if_fail (hook_id > 0); + + signal = LOOKUP_SIGNAL_ID (signal_id); + g_return_if_fail (signal != NULL); + + if (!signal->hook_list || !g_hook_destroy (signal->hook_list, hook_id)) + g_warning ("gtk_signal_remove_emission_hook(): could not find hook (%u)", hook_id); + if (signal->hook_list && !signal->hook_list->hooks) + { + g_hook_list_clear (signal->hook_list); + g_free (signal->hook_list); + signal->hook_list = NULL; + } +} + +static gboolean +gtk_emission_hook_marshaller (GHook *hook, + gpointer data_p) +{ + gpointer *data = data_p; + GtkSignal *signal; + GtkEmissionHook func; + + signal = data[0]; + func = hook->func; + + return func (data[1], signal->signal_id, hook->data); +} + static guint gtk_signal_connect_by_type (GtkObject *object, guint signal_id, |