[seed] Add some of the signal handler machinery to DBus module...also clean up a lot of warnings
- From: Robert Carr <racarr src gnome org>
- To: svn-commits-list gnome org
- Subject: [seed] Add some of the signal handler machinery to DBus module...also clean up a lot of warnings
- Date: Sat, 9 May 2009 19:21:13 -0400 (EDT)
commit e8dcfc43bdc3d934ee228253149b4f2dc869ad6e
Author: Robert Carr <racarr svn gnome org>
Date: Sat May 9 19:10:46 2009 -0400
Add some of the signal handler machinery to DBus module...also clean up a lot of warnings
---
libseed/seed-api.c | 6 +
libseed/seed.h | 1 +
modules/dbus/Makefile.am | 1 +
modules/dbus/dbus-values.c | 2 +-
modules/dbus/module.c | 225 +++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 233 insertions(+), 2 deletions(-)
diff --git a/libseed/seed-api.c b/libseed/seed-api.c
index 688f1d2..543e090 100644
--- a/libseed/seed-api.c
+++ b/libseed/seed-api.c
@@ -484,6 +484,12 @@ seed_value_is_null (JSContextRef ctx, JSValueRef value)
return JSValueIsNull (ctx, value);
}
+gboolean
+seed_value_is_undefined (JSContextRef ctx, JSValueRef value)
+{
+ return JSValueIsUndefined (ctx, value);
+}
+
/**
* seed_value_is_object:
* @ctx: A #SeedContext.
diff --git a/libseed/seed.h b/libseed/seed.h
index 9ff63a1..41176f0 100644
--- a/libseed/seed.h
+++ b/libseed/seed.h
@@ -124,6 +124,7 @@ gboolean seed_string_is_equal (SeedString a, SeedString b);
gboolean seed_string_is_equal_utf8 (SeedString a, const gchar * b);
gboolean seed_value_is_null (SeedContext ctx, SeedValue value);
+gboolean seed_value_is_undefined (SeedContext ctx, SeedValue value);
gboolean seed_value_is_object (SeedContext ctx, SeedValue value);
gboolean seed_value_is_function (SeedContext ctx, SeedObject value);
diff --git a/modules/dbus/Makefile.am b/modules/dbus/Makefile.am
index 8a296a1..d45e9b4 100644
--- a/modules/dbus/Makefile.am
+++ b/modules/dbus/Makefile.am
@@ -14,6 +14,7 @@ libdbusnative_la_SOURCES = \
libdbusnative_la_CFLAGS = \
+ -Wall \
-I top_srcdir@/libseed/ \
$(GOBJECT_INTROSPECTION_CFLAGS) \
$(DBUS_CFLAGS) \
diff --git a/modules/dbus/dbus-values.c b/modules/dbus/dbus-values.c
index 54fba92..14def6c 100644
--- a/modules/dbus/dbus-values.c
+++ b/modules/dbus/dbus-values.c
@@ -680,7 +680,7 @@ append_dict (SeedContext ctx,
SeedValue signature_value;
signature_value = seed_object_get_property (ctx, prop_signatures, name);
- if (!JSValueIsNull (ctx, signature_value))
+ if (!seed_value_is_undefined (ctx, signature_value))
{
value_signature = seed_value_to_string (ctx, signature_value, exception);
if (value_signature == NULL)
diff --git a/modules/dbus/module.c b/modules/dbus/module.c
index 6e20aeb..f65c61b 100644
--- a/modules/dbus/module.c
+++ b/modules/dbus/module.c
@@ -1,6 +1,7 @@
#include <seed.h>
#include "util/dbus.h"
+#include "dbus-values.h"
#define DBUS_CONNECTION_FROM_TYPE(type) ((type) == DBUS_BUS_SESSION ? session_bus : system_bus)
@@ -211,7 +212,7 @@ complete_call(SeedContext ctx,
g_array_free (ret_values, TRUE);
- seed_js_add_dbus_props(ctx, reply, *retval);
+ seed_js_add_dbus_props(ctx, reply, retval, exception);
return TRUE;
}
@@ -371,6 +372,228 @@ fill_with_null_or_string(SeedContext ctx, const char **string_p, SeedValue value
*string_p = seed_value_to_string (ctx, value, exception);
}
+typedef struct {
+ int refcount;
+ DBusBusType bus_type;
+ int connection_id;
+ GClosure *closure;
+} SignalHandler;
+/* allow removal by passing in the callable
+ * FIXME don't think we ever end up using this,
+ * could get rid of it, it predates having an ID
+ * to remove by
+ */
+static GHashTable *signal_handlers_by_callable = NULL;
+
+static void signal_on_closure_invalidated (void *data,
+ GClosure *closure);
+static void signal_handler_ref (SignalHandler *handler);
+static void signal_handler_unref (SignalHandler *handler);
+
+static SignalHandler*
+signal_handler_new(SeedContext ctx,
+ SeedValue callable,
+ SeedException *exception)
+{
+ SignalHandler *handler;
+
+ if (signal_handlers_by_callable &&
+ g_hash_table_lookup(signal_handlers_by_callable,
+ callable) != NULL)
+ {
+ /* To fix this, get rid of signal_handlers_by_callable
+ * and just require removal by id. Not sure we ever use
+ * removal by callable anyway.
+ */
+ seed_make_exception(ctx, exception, "ArgumentError",
+ "For now, same callback cannot be the handler for two dbus signal connections");
+ return NULL;
+ }
+
+ handler = g_slice_new0(SignalHandler);
+ handler->refcount = 1;
+
+ /* We cheat a bit here and use a closure to store a JavaScript function
+ * and deal with the GC root and other issues, even though we
+ * won't ever marshal via GValue
+ */
+ handler->closure = seed_make_gclosure(ctx,
+ callable,
+ NULL);
+ if (handler->closure == NULL) {
+ g_free(handler);
+ return NULL;
+ }
+
+ g_closure_ref(handler->closure);
+ g_closure_sink(handler->closure);
+
+ g_closure_add_invalidate_notifier(handler->closure, handler,
+ signal_on_closure_invalidated);
+
+ if (!signal_handlers_by_callable) {
+ signal_handlers_by_callable =
+ g_hash_table_new_full(g_direct_hash,
+ g_direct_equal,
+ NULL,
+ NULL);
+ }
+
+ /* We keep a weak reference on the closure in a table indexed
+ * by the object, so we can retrieve it when removing the signal
+ * watch. The signal_handlers_by_callable owns one ref to the SignalHandler.
+ */
+ signal_handler_ref(handler);
+ g_hash_table_replace(signal_handlers_by_callable,
+ callable,
+ handler);
+
+ return handler;
+}
+
+static void
+signal_handler_ref(SignalHandler *handler)
+{
+ g_assert(handler->refcount > 0);
+ handler->refcount += 1;
+}
+
+static void
+signal_handler_dispose(SignalHandler *handler)
+{
+ g_assert(handler->refcount > 0);
+
+ signal_handler_ref(handler);
+
+ if (handler->closure) {
+ /* invalidating closure could dispose
+ * re-entrantly, so set handler->closure
+ * NULL before we invalidate
+ */
+ GClosure *closure = handler->closure;
+ handler->closure = NULL;
+
+ g_hash_table_remove(signal_handlers_by_callable,
+ seed_closure_get_callable(closure));
+ if (g_hash_table_size(signal_handlers_by_callable) == 0) {
+ g_hash_table_destroy(signal_handlers_by_callable);
+ signal_handlers_by_callable = NULL;
+ }
+ /* the hash table owned 1 ref */
+ signal_handler_unref(handler);
+
+ g_closure_invalidate(closure);
+ g_closure_unref(closure);
+ }
+
+ /* remove signal if it hasn't been */
+ if (handler->connection_id != 0) {
+ int id = handler->connection_id;
+ handler->connection_id = 0;
+
+ /* this should clear another ref off the
+ * handler by calling signal_on_watch_removed
+ */
+ big_dbus_unwatch_signal_by_id(handler->bus_type,
+ id);
+ }
+
+ signal_handler_unref(handler);
+}
+
+static void
+signal_handler_unref(SignalHandler *handler)
+{
+ g_assert(handler->refcount > 0);
+
+ if (handler->refcount == 1) {
+ signal_handler_dispose(handler);
+ }
+
+ handler->refcount -= 1;
+ if (handler->refcount == 0) {
+ g_assert(handler->closure == NULL);
+ g_assert(handler->connection_id == 0);
+ g_slice_free(SignalHandler, handler);
+ }
+}
+
+static void
+signal_on_watch_removed(void *data)
+{
+ SignalHandler *handler = data;
+
+ handler->connection_id = 0; /* don't re-remove it */
+
+ /* The watch owns a ref; removing it
+ * also forces dispose, which invalidates
+ * the closure if that hasn't been done.
+ */
+ signal_handler_dispose(handler);
+ signal_handler_unref(handler);
+}
+
+static void
+signal_on_closure_invalidated(void *data,
+ GClosure *closure)
+{
+ SignalHandler *handler;
+
+ handler = data;
+
+ /* this removes the watch if it has not been */
+ signal_handler_dispose(handler);
+}
+
+static void
+signal_handler_callback(DBusConnection *connection,
+ DBusMessage *message,
+ void *data)
+{
+ SeedContext ctx;
+ SignalHandler *handler;
+ SeedValue ret_val;
+ DBusMessageIter arg_iter;
+ GArray *arguments;
+ SeedException exception;
+
+ // big_debug(BIG_DEBUG_JS_DBUS,
+ // "Signal handler called");
+
+ handler = data;
+
+ if (handler->closure == NULL) {
+ // big_debug(BIG_DEBUG_JS_DBUS, "dbus signal handler invalidated, ignoring");
+ return;
+ }
+
+ ctx = seed_context_create (group, NULL);
+ seed_prepare_global_context (ctx);
+
+ dbus_message_iter_init(message, &arg_iter);
+ if (!seed_js_values_from_dbus(ctx, &arg_iter, &arguments, &exception)) {
+ // big_debug(BIG_DEBUG_JS_DBUS, "Failed to marshal dbus signal to JS");
+ return;
+ }
+
+ signal_handler_ref(handler); /* for safety, in case handler removes itself */
+
+ g_assert(arguments != NULL);
+
+ // big_debug(BIG_DEBUG_JS_DBUS,
+ // "Invoking closure on signal received, %d args",
+ // gjs_rooted_array_get_length(context, arguments));
+ ret_val = seed_closure_invoke_with_context(ctx, handler->closure,
+ (SeedValue *)arguments->data,
+ arguments->len,
+ &exception);
+
+ g_array_free (arguments, TRUE);
+
+ signal_handler_unref(handler); /* for safety */
+}
+
+
static SeedValue
seed_js_dbus_signature_length (SeedContext ctx,
SeedObject function,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]