gstreamer/gstreamer-sharp/glue/dynamicsignal.c
Aaron Bockover 0c76171b89 2006-07-12 Aaron Bockover <aaron@abock.org>
* sample/HelloWorld.cs: Cleaned up, works with new dynamic signal stuff

    * gstreamer-sharp.mdp: Updated MonoDevelop project

    * gstreamer-sharp/glue/dynamicsignal.c:
    * gstreamer-sharp/DynamicSignal.cs: Added DynamicSignal support for
    runtime GObject signal binding

    * gstreamer-sharp/glue/Makefile.am:
    * gstreamer-sharp/Makefile.am: Updated build

    * gstreamer-sharp/Element.custom: Removed old DynamicSignal
    stuff and added pass-thru/proxy Connect/Disconnect methods on
    top of GLib.DynamicSignal

    * gstreamer-sharp/DynamicSignalHandlerGenerator.cs:
    * gstreamer-sharp/DynamicSignalMarshalHandler.cs: Removed

    * gstreamer-sharp/gstreamer-sharp.dll.config.in: Updated maps, removed
    old 0.8 maps



git-svn-id: svn://anonsvn.mono-project.com/source/branches/abock/gstreamer-sharp@62542 e3ebcda4-bce8-0310-ba0a-eca2169e7518
2006-07-12 22:47:30 +00:00

191 lines
4.6 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 struct {
GObject *object;
gpointer userdata;
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);
}