gstreamer/gstreamer-sharp/glue/dynamicsignal.c
Khaled Mohammed 0e15441c8c Updated DynamicSignal.cs and files plugins-base to use the new
DynamicSignal class.


git-svn-id: svn://anonsvn.mono-project.com/source/branches/abock/gstreamer-sharp@63336 e3ebcda4-bce8-0310-ba0a-eca2169e7518
2006-08-04 04:00:43 +00:00

206 lines
5 KiB
C

//
// dynamicsignal.c: new method of registering GObject signal
// handlers that uses a default signal handler to read
// callback argument stack and convert to an array of
// GValues before running the "generic" signal handler
//
// Authors:
// Aaron Bockover (abockover@novell.com)
//
// (C) 2006 Novell, Inc.
//
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <glib-object.h>
#include <gobject/gvaluecollector.h>
typedef void (* DynamicSignalHandler)(GObject *sender, guint argc,
GValue *argv, gpointer userdata);
//typedef gpointer (* DynamicSignalHandlerGPointer) (GObject *sender, guint argc,
// GValue *argv, gpointer userdata);
//typedef gint64 (* DynamicSignalHandlerGint64) (GObject *sender, guint argc, GValue *argv, gpointer userdata);
typedef struct {
GObject *object;
gpointer userdata;
/*
typedef union {
DynamicSignalHandler CBVoid;
DynamicSignalHandlerGPointer CBGPointer;
DynamicSignalHandlerGInt64 CBGInt64;
}
CallBack;
*/
DynamicSignalHandler callback;
guint id;
guint g_signal_id;
gulong handler_id;
GSignalQuery signal_details;
} DynamicSignalEntry;
static GList *dynamic_signal_table = NULL;
static guint dynamic_signal_last_id = 1;
static DynamicSignalEntry *
find_entry(GObject *object, guint signal_id)
{
GList *current = dynamic_signal_table;
while(current != NULL) {
DynamicSignalEntry *entry = (DynamicSignalEntry *)current->data;
if(entry->object == object && entry->g_signal_id == signal_id) {
return entry;
}
current = current->next;
}
return NULL;
}
static DynamicSignalEntry *
find_entry_by_name(GObject *object, const gchar *signal_name, guint *signal_id_out)
{
guint signal_id;
signal_id = g_signal_lookup(signal_name, G_OBJECT_TYPE(object));
if(signal_id_out != NULL) {
*signal_id_out = signal_id;
}
if(signal_id <= 0) {
return NULL;
}
return find_entry(object, signal_id);
}
static void
free_entry(DynamicSignalEntry *entry)
{
memset(entry, 0, sizeof(DynamicSignalEntry));
g_free(entry);
}
static void
dynamic_signal_handler(DynamicSignalEntry *entry, ...)
{
va_list argp;
GValue *args = NULL;
guint i, n;
if(entry == NULL) {
return;
}
n = entry->signal_details.n_params;
if(n <= 0) {
entry->callback(entry->object, 0, NULL, entry->userdata);
return;
}
args = g_new0(GValue, n);
va_start(argp, entry);
for(i = 0; i < n; i++) {
GType type = entry->signal_details.param_types[i];
GValue *value = &args[i];
gchar *collect_error = NULL;
if(!G_TYPE_IS_CLASSED(type) && G_TYPE_IS_VALUE_TYPE(type) &&
!G_TYPE_IS_FUNDAMENTAL(type) && G_TYPE_IS_DERIVED(type) &&
G_TYPE_HAS_VALUE_TABLE(type)) {
g_value_init(value, type);
value->data[0].v_pointer = va_arg(argp, gpointer);
} else {
g_value_init(value, type);
G_VALUE_COLLECT(value, argp, 0, &collect_error);
}
if(collect_error != NULL) {
g_warning("Could not collect value: %s", collect_error);
g_free(collect_error);
break;
}
}
va_end(argp);
entry->callback(entry->object, n, args, entry->userdata);
}
DynamicSignalEntry *
g_dynamic_signal_find_registration(GObject *object, const gchar *signal_name)
{
return find_entry_by_name(object, signal_name, NULL);
}
guint
g_dynamic_signal_connect(GObject *object, const gchar *signal_name,
DynamicSignalHandler callback, gboolean after, gpointer userdata)
{
DynamicSignalEntry *entry;
guint signal_id;
entry = find_entry_by_name(object, signal_name, &signal_id);
if(entry != NULL) {
return entry->id;
}
entry = g_new0(DynamicSignalEntry, 1);
entry->id = dynamic_signal_last_id++;
entry->object = object;
entry->g_signal_id = signal_id;
entry->callback = callback;
entry->userdata = userdata;
g_signal_query(signal_id, &(entry->signal_details));
dynamic_signal_table = g_list_prepend(dynamic_signal_table, entry);
entry->handler_id = g_signal_connect_data(object, signal_name,
G_CALLBACK(dynamic_signal_handler), entry, NULL,
G_CONNECT_SWAPPED | (after ? G_CONNECT_AFTER : 0));
return entry->id;
}
void
g_dynamic_signal_disconnect(GObject *object, const gchar *signal_name)
{
DynamicSignalEntry *entry = find_entry_by_name(object, signal_name, NULL);
if(entry == NULL) {
return;
}
g_signal_handler_disconnect(object, entry->handler_id);
dynamic_signal_table = g_list_remove(dynamic_signal_table, entry);
free_entry(entry);
entry = NULL;
}
void
g_dynamic_signal_update_entry_userdata(DynamicSignalEntry *entry, gpointer userdata)
{
if(entry != NULL) {
entry->userdata = userdata;
}
}
GType g_value_type(GValue *value)
{
return G_VALUE_TYPE(value);
}