mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-04 23:46:43 +00:00
0e15441c8c
DynamicSignal class. git-svn-id: svn://anonsvn.mono-project.com/source/branches/abock/gstreamer-sharp@63336 e3ebcda4-bce8-0310-ba0a-eca2169e7518
206 lines
5 KiB
C
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);
|
|
}
|
|
|