gee
oldstatus
2005-09-19, Nathan Walp
* @file signals.c Signal API * Gaim is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program 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 General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /* must include this to use G_VA_COPY */ GaimSignalMarshalFunc marshal; static GHashTable *instance_table = NULL; destroy_instance_data(GaimInstanceData *instance_data) g_hash_table_destroy(instance_data->signals); destroy_signal_data(GaimSignalData *signal_data) GaimSignalHandlerData *handler_data; for (l = signal_data->handlers; l != NULL; l = l->next) handler_data = (GaimSignalHandlerData *)l->data; g_list_free(signal_data->handlers); if (signal_data->values != NULL) for (i = 0; i < signal_data->num_values; i++) gaim_value_destroy((GaimValue *)signal_data->values[i]); g_free(signal_data->values); if (signal_data->ret_value != NULL) gaim_value_destroy(signal_data->ret_value); gaim_signal_register(void *instance, const char *signal, GaimSignalMarshalFunc marshal, GaimValue *ret_value, int num_values, ...) GaimInstanceData *instance_data; GaimSignalData *signal_data; g_return_val_if_fail(instance != NULL, 0); g_return_val_if_fail(signal != NULL, 0); g_return_val_if_fail(marshal != NULL, 0); (GaimInstanceData *)g_hash_table_lookup(instance_table, instance); if (instance_data == NULL) instance_data = g_new0(GaimInstanceData, 1); instance_data->instance = instance; instance_data->next_signal_id = 1; g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)destroy_signal_data); g_hash_table_insert(instance_table, instance, instance_data); signal_data = g_new0(GaimSignalData, 1); signal_data->id = instance_data->next_signal_id; signal_data->marshal = marshal; signal_data->next_handler_id = 1; signal_data->ret_value = ret_value; signal_data->num_values = num_values; signal_data->values = g_new0(GaimValue *, num_values); va_start(args, num_values); for (i = 0; i < num_values; i++) signal_data->values[i] = va_arg(args, GaimValue *); g_hash_table_insert(instance_data->signals, g_strdup(signal), signal_data); instance_data->next_signal_id++; instance_data->signal_count++; gaim_signal_unregister(void *instance, const char *signal) GaimInstanceData *instance_data; g_return_if_fail(instance != NULL); g_return_if_fail(signal != NULL); (GaimInstanceData *)g_hash_table_lookup(instance_table, instance); g_return_if_fail(instance_data != NULL); g_hash_table_remove(instance_data->signals, signal); instance_data->signal_count--; if (instance_data->signal_count == 0) /* Unregister the instance. */ g_hash_table_remove(instance_table, instance); gaim_signals_unregister_by_instance(void *instance) g_return_if_fail(instance != NULL); found = g_hash_table_remove(instance_table, instance); * Makes things easier (more annoying?) for developers who don't have * things registering and unregistering in the right order :) gaim_signal_get_values(void *instance, const char *signal, int *num_values, GaimValue ***values) GaimInstanceData *instance_data; GaimSignalData *signal_data; g_return_if_fail(instance != NULL); g_return_if_fail(signal != NULL); g_return_if_fail(num_values != NULL); g_return_if_fail(values != NULL); /* Get the instance data */ (GaimInstanceData *)g_hash_table_lookup(instance_table, instance); g_return_if_fail(instance_data != NULL); /* Get the signal data */ (GaimSignalData *)g_hash_table_lookup(instance_data->signals, signal); g_return_if_fail(signal_data != NULL); *num_values = signal_data->num_values; *values = signal_data->values; *ret_value = signal_data->ret_value; static gint handler_priority(void * a, void * b) { GaimSignalHandlerData *ah = (GaimSignalHandlerData*)a; GaimSignalHandlerData *bh = (GaimSignalHandlerData*)b; if (ah->priority > bh->priority) return 1; if (ah->priority < bh->priority) return -1; signal_connect_common(void *instance, const char *signal, void *handle, GaimCallback func, void *data, int priority, gboolean use_vargs) GaimInstanceData *instance_data; GaimSignalData *signal_data; GaimSignalHandlerData *handler_data; g_return_val_if_fail(instance != NULL, 0); g_return_val_if_fail(signal != NULL, 0); g_return_val_if_fail(handle != NULL, 0); g_return_val_if_fail(func != NULL, 0); /* Get the instance data */ (GaimInstanceData *)g_hash_table_lookup(instance_table, instance); g_return_val_if_fail(instance_data != NULL, 0); /* Get the signal data */ (GaimSignalData *)g_hash_table_lookup(instance_data->signals, signal); gaim_debug(GAIM_DEBUG_ERROR, "signals", "Signal data for %s not found!\n", signal); /* Create the signal handler data */ handler_data = g_new0(GaimSignalHandlerData, 1); handler_data->id = signal_data->next_handler_id; handler_data->handle = handle; handler_data->data = data; handler_data->use_vargs = use_vargs; handler_data->priority = priority; signal_data->handlers = g_list_insert_sorted(signal_data->handlers, handler_data, (GCompareFunc)handler_priority); signal_data->handler_count++; signal_data->next_handler_id++; gaim_signal_connect_priority(void *instance, const char *signal, void *handle, GaimCallback func, void *data, int priority) return signal_connect_common(instance, signal, handle, func, data, priority, FALSE); gaim_signal_connect(void *instance, const char *signal, void *handle, GaimCallback func, void *data) return signal_connect_common(instance, signal, handle, func, data, GAIM_SIGNAL_PRIORITY_DEFAULT, FALSE); gaim_signal_connect_priority_vargs(void *instance, const char *signal, void *handle, GaimCallback func, void *data, int priority) return signal_connect_common(instance, signal, handle, func, data, priority, TRUE); gaim_signal_connect_vargs(void *instance, const char *signal, void *handle, GaimCallback func, void *data) return signal_connect_common(instance, signal, handle, func, data, GAIM_SIGNAL_PRIORITY_DEFAULT, TRUE); gaim_signal_disconnect(void *instance, const char *signal, void *handle, GaimCallback func) GaimInstanceData *instance_data; GaimSignalData *signal_data; GaimSignalHandlerData *handler_data; g_return_if_fail(instance != NULL); g_return_if_fail(signal != NULL); g_return_if_fail(handle != NULL); g_return_if_fail(func != NULL); /* Get the instance data */ (GaimInstanceData *)g_hash_table_lookup(instance_table, instance); g_return_if_fail(instance_data != NULL); /* Get the signal data */ (GaimSignalData *)g_hash_table_lookup(instance_data->signals, signal); gaim_debug(GAIM_DEBUG_ERROR, "signals", "Signal data for %s not found!\n", signal); /* Find the handler data. */ for (l = signal_data->handlers; l != NULL; l = l->next) handler_data = (GaimSignalHandlerData *)l->data; if (handler_data->handle == handle && handler_data->cb == func) signal_data->handlers = g_list_remove(signal_data->handlers, signal_data->handler_count--; /* See note somewhere about this actually helping developers.. */ * TODO: Make this all more efficient by storing a list of handlers, keyed disconnect_handle_from_signals(const char *signal, GaimSignalData *signal_data, void *handle) GaimSignalHandlerData *handler_data; for (l = signal_data->handlers; l != NULL; l = l_next) handler_data = (GaimSignalHandlerData *)l->data; if (handler_data->handle == handle) signal_data->handler_count--; signal_data->handlers = g_list_remove(signal_data->handlers, disconnect_handle_from_instance(void *instance, GaimInstanceData *instance_data, g_hash_table_foreach(instance_data->signals, (GHFunc)disconnect_handle_from_signals, handle); gaim_signals_disconnect_by_handle(void *handle) g_return_if_fail(handle != NULL); g_hash_table_foreach(instance_table, (GHFunc)disconnect_handle_from_instance, handle); gaim_signal_emit(void *instance, const char *signal, ...) g_return_if_fail(instance != NULL); g_return_if_fail(signal != NULL); gaim_signal_emit_vargs(instance, signal, args); gaim_signal_emit_vargs(void *instance, const char *signal, va_list args) GaimInstanceData *instance_data; GaimSignalData *signal_data; GaimSignalHandlerData *handler_data; g_return_if_fail(instance != NULL); g_return_if_fail(signal != NULL); (GaimInstanceData *)g_hash_table_lookup(instance_table, instance); g_return_if_fail(instance_data != NULL); (GaimSignalData *)g_hash_table_lookup(instance_data->signals, signal); gaim_debug(GAIM_DEBUG_ERROR, "signals", "Signal data for %s not found!\n", signal); for (l = signal_data->handlers; l != NULL; l = l_next) handler_data = (GaimSignalHandlerData *)l->data; /* This is necessary because a va_list may only be if (handler_data->use_vargs) ((void (*)(va_list, void *))handler_data->cb)(tmp, signal_data->marshal(handler_data->cb, tmp, handler_data->data, NULL); gaim_signal_emit_return_1(void *instance, const char *signal, ...) g_return_val_if_fail(instance != NULL, NULL); g_return_val_if_fail(signal != NULL, NULL); ret_val = gaim_signal_emit_vargs_return_1(instance, signal, args); gaim_signal_emit_vargs_return_1(void *instance, const char *signal, GaimInstanceData *instance_data; GaimSignalData *signal_data; GaimSignalHandlerData *handler_data; g_return_val_if_fail(instance != NULL, NULL); g_return_val_if_fail(signal != NULL, NULL); (GaimInstanceData *)g_hash_table_lookup(instance_table, instance); g_return_val_if_fail(instance_data != NULL, NULL); (GaimSignalData *)g_hash_table_lookup(instance_data->signals, signal); gaim_debug(GAIM_DEBUG_ERROR, "signals", "Signal data for %s not found!\n", signal); for (l = signal_data->handlers; l != NULL; l = l_next) handler_data = (GaimSignalHandlerData *)l->data; if (handler_data->use_vargs) ret_val = ((void *(*)(va_list, void *))handler_data->cb)( tmp, handler_data->data); signal_data->marshal(handler_data->cb, tmp, handler_data->data, &ret_val); g_return_if_fail(instance_table == NULL); g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)destroy_instance_data); g_return_if_fail(instance_table != NULL); g_hash_table_destroy(instance_table); /************************************************************************** **************************************************************************/ gaim_marshal_VOID(GaimCallback cb, va_list args, void *data, ((void (*)(void *))cb)(data); gaim_marshal_VOID__INT(GaimCallback cb, va_list args, void *data, gint arg1 = va_arg(args, gint); ((void (*)(gint, void *))cb)(arg1, data); gaim_marshal_VOID__INT_INT(GaimCallback cb, va_list args, void *data, gint arg1 = va_arg(args, gint); gint arg2 = va_arg(args, gint); ((void (*)(gint, gint, void *))cb)(arg1, arg2, data); gaim_marshal_VOID__POINTER(GaimCallback cb, va_list args, void *data, void *arg1 = va_arg(args, void *); ((void (*)(void *, void *))cb)(arg1, data); gaim_marshal_VOID__POINTER_UINT(GaimCallback cb, va_list args, void *data, void **return_val) void *arg1 = va_arg(args, void *); guint arg2 = va_arg(args, guint); ((void (*)(void *, guint, void *))cb)(arg1, arg2, data); gaim_marshal_VOID__POINTER_POINTER(GaimCallback cb, va_list args, void *data, void **return_val) void *arg1 = va_arg(args, void *); void *arg2 = va_arg(args, void *); ((void (*)(void *, void *, void *))cb)(arg1, arg2, data); gaim_marshal_VOID__POINTER_POINTER_UINT(GaimCallback cb, va_list args, void *data, void **return_val) void *arg1 = va_arg(args, void *); void *arg2 = va_arg(args, void *); guint arg3 = va_arg(args, guint); ((void (*)(void *, void *, guint, void *))cb)(arg1, arg2, arg3, data); gaim_marshal_VOID__POINTER_POINTER_UINT_UINT(GaimCallback cb, va_list args, void *data, void **return_val) void *arg1 = va_arg(args, void *); void *arg2 = va_arg(args, void *); guint arg3 = va_arg(args, guint); guint arg4 = va_arg(args, guint); ((void (*)(void *, void *, guint, guint, void *))cb)(arg1, arg2, arg3, arg4, data); gaim_marshal_VOID__POINTER_POINTER_POINTER(GaimCallback cb, va_list args, void *data, void **return_val) void *arg1 = va_arg(args, void *); void *arg2 = va_arg(args, void *); void *arg3 = va_arg(args, void *); ((void (*)(void *, void *, void *, void *))cb)(arg1, arg2, arg3, data); gaim_marshal_VOID__POINTER_POINTER_POINTER_POINTER(GaimCallback cb, void *arg1 = va_arg(args, void *); void *arg2 = va_arg(args, void *); void *arg3 = va_arg(args, void *); void *arg4 = va_arg(args, void *); ((void (*)(void *, void *, void *, void *, void *))cb)(arg1, arg2, arg3, arg4, data); gaim_marshal_VOID__POINTER_POINTER_POINTER_POINTER_POINTER(GaimCallback cb, void *arg1 = va_arg(args, void *); void *arg2 = va_arg(args, void *); void *arg3 = va_arg(args, void *); void *arg4 = va_arg(args, void *); void *arg5 = va_arg(args, void *); ((void (*)(void *, void *, void *, void *, void *, void *))cb)(arg1, arg2, arg3, arg4, arg5, data); gaim_marshal_VOID__POINTER_POINTER_POINTER_UINT(GaimCallback cb, void *arg1 = va_arg(args, void *); void *arg2 = va_arg(args, void *); void *arg3 = va_arg(args, void *); guint arg4 = va_arg(args, guint); ((void (*)(void *, void *, void *, guint, void *))cb)(arg1, arg2, arg3, arg4, data); gaim_marshal_VOID__POINTER_POINTER_POINTER_UINT_UINT(GaimCallback cb, void *arg1 = va_arg(args, void *); void *arg2 = va_arg(args, void *); void *arg3 = va_arg(args, void *); guint arg4 = va_arg(args, guint); guint arg5 = va_arg(args, guint); ((void (*)(void *, void *, void *, guint, guint, void *))cb)( arg1, arg2, arg3, arg4, arg5, data); gaim_marshal_INT__INT(GaimCallback cb, va_list args, void *data, gint arg1 = va_arg(args, gint); ret_val = ((gint (*)(gint, void *))cb)(arg1, data); *return_val = GINT_TO_POINTER(ret_val); gaim_marshal_INT__INT_INT(GaimCallback cb, va_list args, void *data, gint arg1 = va_arg(args, gint); gint arg2 = va_arg(args, gint); ret_val = ((gint (*)(gint, gint, void *))cb)(arg1, arg2, data); *return_val = GINT_TO_POINTER(ret_val); gaim_marshal_BOOLEAN__POINTER(GaimCallback cb, va_list args, void *data, void *arg1 = va_arg(args, void *); ret_val = ((gboolean (*)(void *, void *))cb)(arg1, data); *return_val = GINT_TO_POINTER(ret_val); gaim_marshal_BOOLEAN__POINTER_POINTER(GaimCallback cb, va_list args, void *data, void **return_val) void *arg1 = va_arg(args, void *); void *arg2 = va_arg(args, void *); ret_val = ((gboolean (*)(void *, void *, void *))cb)(arg1, arg2, data); *return_val = GINT_TO_POINTER(ret_val); gaim_marshal_BOOLEAN__POINTER_POINTER_POINTER(GaimCallback cb, va_list args, void *data, void **return_val) void *arg1 = va_arg(args, void *); void *arg2 = va_arg(args, void *); void *arg3 = va_arg(args, void *); ret_val = ((gboolean (*)(void *, void *, void *, void *))cb)(arg1, arg2, *return_val = GINT_TO_POINTER(ret_val); gaim_marshal_BOOLEAN__POINTER_POINTER_UINT(GaimCallback cb, void *arg1 = va_arg(args, void *); void *arg2 = va_arg(args, void *); guint arg3 = va_arg(args, guint); ret_val = ((gboolean (*)(void *, void *, guint, void *))cb)( *return_val = GINT_TO_POINTER(ret_val); gaim_marshal_BOOLEAN__POINTER_POINTER_POINTER_UINT(GaimCallback cb, void *arg1 = va_arg(args, void *); void *arg2 = va_arg(args, void *); void *arg3 = va_arg(args, void *); guint arg4 = va_arg(args, guint); ret_val = ((gboolean (*)(void *, void *, void *, guint, void *))cb)( arg1, arg2, arg3, arg4, data); *return_val = GINT_TO_POINTER(ret_val); gaim_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER(GaimCallback cb, void *arg1 = va_arg(args, void *); void *arg2 = va_arg(args, void *); void *arg3 = va_arg(args, void *); void *arg4 = va_arg(args, void *); ret_val = ((gboolean (*)(void *, void *, void *, void *, void *))cb)( arg1, arg2, arg3, arg4, data); *return_val = GINT_TO_POINTER(ret_val); gaim_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER( GaimCallback cb, va_list args, void *data, void **return_val) void *arg1 = va_arg(args, void *); void *arg2 = va_arg(args, void *); void *arg3 = va_arg(args, void *); void *arg4 = va_arg(args, void *); void *arg5 = va_arg(args, void *); ((gboolean (*)(void *, void *, void *, void *, void *, void *))cb)( arg1, arg2, arg3, arg4, arg5, data); *return_val = GINT_TO_POINTER(ret_val);