grim/purple-signals

initial revision

2009-07-09, Gary Kramlich
ccb48ffaf202
Parents
Children ce6377086ad5
initial revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore Thu Jul 09 21:56:37 2009 -0500
@@ -0,0 +1,4 @@
+syntax: glob
+marshallers.[ch]
+purple_signals
+.*.swp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile Thu Jul 09 21:56:37 2009 -0500
@@ -0,0 +1,28 @@
+TARGET=purple_signals
+
+SOURCES=purple_signals.c
+
+BUILT_SOURCES=marshallers.c marshallers.h
+
+GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0`
+
+CC=gcc
+ARGS=\
+ `pkg-config --libs --cflags glib-2.0` \
+ `pkg-config --libs --cflags gobject-2.0` \
+ -g -g3 -Wall
+
+all: $(TARGET)
+
+$(TARGET): $(SOURCES) $(BUILT_SOURCES)
+ $(CC) $(ARGS) $(SOURCES) $(BUILT_SOURCES) -o $(TARGET)
+
+marshallers.h: marshallers.list
+ $(GLIB_GENMARSHAL) --prefix=purple_marshal marshallers.list --header > marshallers.h
+
+marshallers.c: marshallers.list marshallers.h
+ $(GLIB_GENMARSHAL) --prefix=purple_marshal marshallers.list --body > marshallers.c
+
+clean:
+ rm -f *.o $(TARGET) $(BUILT_SOURCES)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/marshallers.list Thu Jul 09 21:56:37 2009 -0500
@@ -0,0 +1,2 @@
+VOID:OBJECT
+BOOLEAN:OBJECT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/purple_signals.c Thu Jul 09 21:56:37 2009 -0500
@@ -0,0 +1,237 @@
+#include <glib.h>
+#include <glib-object.h>
+
+#include <stdio.h>
+
+#include "marshallers.h"
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+enum {
+ SIG_SIMPLE,
+ SIG_BOOLEAN_RETURN,
+ SIG_LAST
+};
+
+static guint signals[SIG_LAST] = { 0, };
+
+typedef struct {
+ GObject parent;
+} PurpleObject;
+
+typedef struct {
+ GObjectClass parent;
+
+ void (*simple_signal)(PurpleObject *obj);
+ gboolean (*boolean_ret_signal)(PurpleObject *obj);
+} PurpleObjectClass;
+
+#define PURPLE_TYPE_OBJECT (purple_object_get_type())
+
+G_DEFINE_TYPE(PurpleObject, purple_object, G_TYPE_OBJECT);
+
+static void
+purple_object_init(PurpleObject *obj) {
+}
+
+static void
+purple_object_class_init(PurpleObjectClass *klass) {
+ GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+ signals[SIG_SIMPLE] =
+ g_signal_new("simple",
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(PurpleObjectClass, simple_signal),
+ NULL, NULL,
+ purple_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1, PURPLE_TYPE_OBJECT);
+
+ signals[SIG_BOOLEAN_RETURN] =
+ g_signal_new("boolean-return",
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(PurpleObjectClass, boolean_ret_signal),
+ NULL, NULL,
+ purple_marshal_BOOLEAN__OBJECT,
+ G_TYPE_BOOLEAN,
+ 1, PURPLE_TYPE_OBJECT);
+}
+
+static void
+purple_object_emit_signals(PurpleObject *obj) {
+ gboolean ret = FALSE;
+
+ g_return_if_fail(G_TYPE_CHECK_INSTANCE_TYPE(obj, PURPLE_TYPE_OBJECT));
+ printf("passed error check\n");
+
+ g_signal_emit_by_name(obj, "simple");
+ printf("emitted simple\n\n");
+// g_signal_emit_by_name(obj, "boolean-return", &ret);
+ printf("emitted boolean\n");
+
+ printf("boolean return was '%s'\n", (ret) ? "True" : "False");
+}
+
+/******************************************************************************
+ * Purple Signal Stuff
+ *****************************************************************************/
+typedef struct {
+ GType type;
+ GCallback callback;
+ gpointer user_data;
+ GConnectFlags flags;
+ GQuark detail;
+} PurpleSignalData;
+
+static gboolean
+purple_signal_emission_hook(GSignalInvocationHint *hint, guint n_params,
+ const GValue *pvalues, gpointer data)
+{
+ PurpleSignalData *sd = data;
+ PurpleObject *obj = NULL;
+ gint flags = G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC;
+
+ printf("emission_hook\n");
+ obj = g_value_get_object(pvalues + 0);
+
+ if(!G_TYPE_CHECK_INSTANCE_TYPE(obj, sd->type))
+ return TRUE;
+
+ if(g_signal_handler_find(obj, flags, hint->signal_id, sd->detail, NULL,
+ sd->callback, sd->user_data) != 0)
+ {
+ gboolean swap = FALSE, after = FALSE;
+ GClosure *closure = NULL;
+
+ printf("found handler\n");
+
+ swap = (sd->flags & G_CONNECT_SWAPPED);
+ after = (sd->flags & G_CONNECT_AFTER);
+
+ if(swap)
+ closure = g_cclosure_new_swap(sd->callback, sd->user_data, NULL);
+ else
+ closure = g_cclosure_new(sd->callback, sd->user_data, NULL);
+
+ g_signal_connect_closure_by_id(obj, hint->signal_id, sd->detail, closure, after);
+ g_closure_invoke(closure, NULL, n_params, pvalues, hint);
+ }
+
+ return TRUE;
+}
+
+gulong
+purple_g_signal_connect(GType t, const gchar *n, GCallback cb, gpointer d) {
+ PurpleSignalData *sd = NULL;
+ GQuark detail = 0;
+ guint sig_id = 0;
+ gulong ret = 0;
+ gpointer *klass = NULL;
+
+ klass = g_type_class_ref(t);
+
+ if(!g_signal_parse_name(n, t, &sig_id, &detail, TRUE)) {
+ printf("failed to find signal '%s' for object '%s'!\n", n, g_type_name(t));
+
+ return 0;
+ }
+
+ printf("sig_id: %d; detail: %d\n", sig_id, detail);
+ sd = g_new0(PurpleSignalData, 1);
+ sd->callback = cb;
+ sd->user_data = d;
+ sd->flags = 0;
+ sd->detail = detail;
+ sd->type = t;
+
+ ret = g_signal_add_emission_hook(sig_id, detail,
+ purple_signal_emission_hook, sd, g_free);
+
+ g_type_class_unref(klass);
+
+ return ret;
+}
+
+/******************************************************************************
+ * callbacks
+ *****************************************************************************/
+static void
+simple_cb_1(PurpleObject *obj, gpointer d) {
+ printf("simple_cb_1\n");
+}
+
+static void
+simple_cb_2(PurpleObject *obj, gpointer d) {
+ printf("simple_cb_2\n");
+}
+
+static gboolean
+boolean_return_cb_1(PurpleObject *obj, gpointer d) {
+ printf("boolean_return_cb_1\n");
+
+ return TRUE;
+}
+
+static gboolean
+boolean_return_cb_2(PurpleObject *obj, gpointer d) {
+ printf("boolean_return_cb_2\n");
+
+ return FALSE;
+}
+
+/******************************************************************************
+ * timeout cb
+ *****************************************************************************/
+static GMainLoop *loop = NULL;
+
+gboolean
+timeout_cb(gpointer data) {
+ PurpleObject *obj = NULL;
+
+ printf("timeout_cb\n");
+
+ obj = g_object_new(PURPLE_TYPE_OBJECT, NULL);
+ printf("created obj\n");
+ purple_object_emit_signals(obj);
+ printf("emitted signals\n");
+ g_object_unref(obj);
+ printf("unrefed\n");
+
+ g_main_loop_quit(loop);
+
+ return FALSE;
+}
+
+/******************************************************************************
+ * Main
+ *****************************************************************************/
+gint
+main(gint argc, gchar **argv) {
+ g_type_init();
+
+ loop = g_main_loop_new(NULL, FALSE);
+
+ purple_g_signal_connect(PURPLE_TYPE_OBJECT, "simple",
+ G_CALLBACK(simple_cb_1), NULL);
+#if 0
+ purple_g_signal_connect(PURPLE_TYPE_OBJECT, "simple",
+ G_CALLBACK(simple_cb_2), NULL);
+#endif
+
+ purple_g_signal_connect(PURPLE_TYPE_OBJECT, "boolean-return",
+ G_CALLBACK(boolean_return_cb_1), NULL);
+ purple_g_signal_connect(PURPLE_TYPE_OBJECT, "boolean-return",
+ G_CALLBACK(boolean_return_cb_2), NULL);
+
+ g_timeout_add_seconds(1, timeout_cb, NULL);
+
+ g_main_loop_run(loop);
+
+ g_main_loop_unref(loop);
+
+ return 0;
+}
+