--- /dev/null
+NAME := jscorebus
+VERSION := 0.0.1
+SOURCES := $(wildcard jscorebus/*.c)
+CFLAGS := -ggdb -DDEBUG
+PKGS := gobject-2.0 dbus-1 dbus-glib-1 webkit-1.0
+
+INCDIR := $(DESTDIR)/$(PREFIX)/include/$(NAME)
+PCDIR := $(DESTDIR)/$(PREFIX)/lib/pkgconfig
+
+include build/library.mk
+
+install::
+ifneq ($(wildcard $(O_LIBRARY)),)
+ install -d $(INCDIR) $(PCDIR)
+ install -m 0644 jscorebus/jscorebus.h $(INCDIR)
+ install -m 0644 jscorebus/jscorebus.pc $(PCDIR)
+ sed -i s,@PREFIX@,$(PREFIX), $(PCDIR)/jscorebus.pc
+else
+ @echo JSCoreBus has not been built, not installing
+endif
--- /dev/null
+/**
+ * Browser D-Bus Bridge, JavaScriptCore version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ * Contact: Movial Creative Technologies Inc, <info@movial.com>
+ * Authors: Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <JavaScriptCore/JavaScript.h>
+#include <glib.h>
+
+#include "jscorebus-classfactory.h"
+
+static
+GHashTable *definitions = NULL;
+static
+GHashTable *classes = NULL;
+
+void
+jsclassdef_insert(const char *class_name, const JSClassDefinition *definition)
+{
+ if (G_UNLIKELY(definitions == NULL))
+ {
+ definitions = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ g_hash_table_insert(definitions, (gpointer)class_name, (gpointer)definition);
+}
+
+const JSClassDefinition *
+jsclassdef_lookup(const char *class_name)
+{
+ if (class_name == NULL)
+ {
+ return NULL;
+ }
+
+ if (G_UNLIKELY(definitions == NULL))
+ {
+ return NULL;
+ }
+
+ return (const JSClassDefinition *) g_hash_table_lookup(definitions,
+ (gpointer)class_name);
+}
+
+JSClassRef
+jsclass_lookup(const JSClassDefinition *definition)
+{
+ JSClassRef jsclass;
+
+ if (G_UNLIKELY(classes == NULL))
+ {
+ classes = g_hash_table_new(NULL, NULL);
+ }
+
+ jsclass = g_hash_table_lookup(classes, (gpointer)definition);
+ if (G_UNLIKELY(jsclass == NULL))
+ {
+ jsclass = JSClassCreate(definition);
+ g_hash_table_insert(classes, (gpointer)definition, (gpointer)jsclass);
+ }
+
+ return jsclass;
+}
+
--- /dev/null
+/**
+ * Browser D-Bus Bridge, JavaScriptCore version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ * Contact: Movial Creative Technologies Inc, <info@movial.com>
+ * Authors: Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __JSCOREBUS_CLASSFACTORY_H___
+#define __JSCOREBUS_CLASSFACTORY_H___
+
+G_BEGIN_DECLS
+
+void
+jsclassdef_insert(const char *class_name, const JSClassDefinition *definition);
+
+const JSClassDefinition *
+jsclassdef_lookup(const char *class_name);
+
+JSClassRef
+jsclass_lookup(const JSClassDefinition *definition);
+
+G_END_DECLS
+
+#endif /* __JSCOREBUS_CLASSFACTORY_H___ */
+
--- /dev/null
+/**
+ * Browser D-Bus Bridge, JavaScriptCore version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ * Contact: Movial Creative Technologies Inc, <info@movial.com>
+ * Authors: Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <string.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <JavaScriptCore/JavaScript.h>
+
+#include "jscorebus-classfactory.h"
+#include "jscorebus-marshal.h"
+
+static gboolean
+jsvalue_append_basic(JSContextRef context,
+ JSValueRef jsvalue,
+ int type,
+ DBusMessageIter *iter);
+
+
+gboolean jsvalue_array_append_to_message_iter (JSContextRef context,
+ const JSValueRef jsvalues[],
+ int n_values,
+ DBusMessageIter *iter,
+ const char *signature)
+{
+ DBusSignatureIter siter;
+ DBusError error;
+ char *sig = (char*) signature; /* This is a bit silly, I know */
+ int i = 0;
+
+ /* If there is no signature, we need to do some autodetection */
+ if (signature == NULL)
+ {
+ char **parts;
+ parts = g_new0(char*, n_values + 1);
+ for (i = 0; i < n_values; i++)
+ {
+ parts[i] = jsvalue_to_signature(context, jsvalues[i]);
+ }
+ sig = g_strjoinv(NULL, parts);
+ g_strfreev(parts);
+ }
+
+ /* If there *still* is no signature, or it is empty, we bork.
+ * Empty messages have no business going through this code path.
+ */
+ if (sig == NULL || strlen(sig) == 0)
+ {
+ g_warning("Could not autodetect signature for message arguments!");
+ g_free(sig);
+ return FALSE;
+ }
+
+ /* First of all, we need to validate the signature */
+ dbus_error_init(&error);
+ if (!dbus_signature_validate(sig, &error))
+ {
+ g_warning(error.message);
+ if (sig != signature)
+ g_free(sig);
+ return FALSE;
+ }
+
+ dbus_signature_iter_init(&siter, sig);
+ i = 0;
+ do {
+ const char *arg_sig = dbus_signature_iter_get_signature(&siter);
+ if (!jsvalue_append_to_message_iter(context, jsvalues[i++], iter, arg_sig))
+ {
+ g_warning("Appending '%s' to message failed!", arg_sig);
+ if (sig != signature)
+ g_free(sig);
+ return FALSE;
+ }
+ } while (dbus_signature_iter_next(&siter));
+
+ if (sig != signature)
+ g_free(sig);
+
+ return TRUE;
+}
+
+gboolean jsvalue_append_to_message_iter(JSContextRef context,
+ JSValueRef jsvalue,
+ DBusMessageIter *iter,
+ const char *signature)
+{
+ DBusSignatureIter siter;
+
+ dbus_signature_iter_init(&siter, signature);
+
+ switch (dbus_signature_iter_get_current_type(&siter))
+ {
+ /* JSValueToBoolean follows the JS rules of what's true and false so we can
+ * simply take the value without checking the type of it
+ */
+ case DBUS_TYPE_BOOLEAN:
+ {
+ dbus_bool_t value = JSValueToBoolean(context, jsvalue);
+ if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value))
+ {
+ g_warning("Could not append a boolean to message iter");
+ return FALSE;
+ }
+ break;
+ }
+ /* Basic types */
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_INT32:
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_UINT16:
+ case DBUS_TYPE_UINT32:
+ case DBUS_TYPE_UINT64:
+ case DBUS_TYPE_BYTE:
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ {
+ int type = dbus_signature_iter_get_current_type(&siter);
+ if (!jsvalue_append_basic(context, jsvalue, type, iter))
+ {
+ g_warning("Could not append a '%c' to message iter", type);
+ return FALSE;
+ }
+ break;
+ }
+ case DBUS_TYPE_DOUBLE:
+ {
+ /* Conversions between dbus_uint64_t and double seem to loose precision,
+ * that's why doubles are special-cased
+ */
+ double value = JSValueToNumber(context, jsvalue, NULL);
+ if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &value))
+ {
+ g_warning("Could not append a double to message iter");
+ return FALSE;
+ }
+ break;
+ }
+ case DBUS_TYPE_ARRAY:
+ {
+ /* Dicts are implemented as arrays of entries in D-Bus */
+ if (dbus_signature_iter_get_element_type(&siter) == DBUS_TYPE_DICT_ENTRY)
+ {
+ int i, props;
+ JSPropertyNameArrayRef propnames;
+ char *dict_signature;
+ DBusMessageIter subiter;
+ DBusSignatureIter dictsiter;
+ DBusSignatureIter dictsubsiter;
+
+ dbus_signature_iter_recurse(&siter, &dictsiter);
+ dict_signature = dbus_signature_iter_get_signature(&dictsiter);
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ dict_signature, &subiter))
+ {
+ g_warning("Memory exhausted!");
+ return FALSE;
+ }
+ propnames = JSObjectCopyPropertyNames(context, (JSObjectRef)jsvalue);
+ props = JSPropertyNameArrayGetCount(propnames);
+
+ /* Move the signature iter to the value part of the signature
+ * We only support string->value dicts currently, though we coud do
+ * numbers too...
+ */
+ dbus_signature_iter_recurse(&dictsiter, &dictsubsiter); /* Now at key */
+ dbus_signature_iter_next(&dictsubsiter); /* Now at value */
+
+ for (i = 0; i < props; i++)
+ {
+ JSStringRef jsstr;
+ DBusMessageIter dictiter;
+ char *cstr;
+ if (!dbus_message_iter_open_container(&subiter, DBUS_TYPE_DICT_ENTRY,
+ NULL, &dictiter))
+ {
+ g_warning("Memory exhausted!");
+ return FALSE;
+ }
+ jsstr = JSPropertyNameArrayGetNameAtIndex(propnames, i);
+ cstr = string_from_jsstring(context, jsstr);
+ dbus_message_iter_append_basic(&dictiter, DBUS_TYPE_STRING, &cstr);
+ g_free(cstr);
+ jsvalue_append_to_message_iter(context,
+ JSObjectGetProperty(context, (JSObjectRef)jsvalue, jsstr, NULL),
+ &dictiter, dbus_signature_iter_get_signature(&dictsubsiter));
+ dbus_message_iter_close_container(&subiter, &dictiter);
+ }
+ dbus_message_iter_close_container(iter, &subiter);
+ break;
+ } else {
+ int i, props;
+ JSPropertyNameArrayRef propnames;
+ JSValueRef *jsvalues;
+ DBusMessageIter subiter;
+ DBusSignatureIter arraysiter;
+ char *array_signature = NULL;
+ if (!jsvalue_instanceof(context, jsvalue, "Array"))
+ {
+ g_warning("Expected JavaScript Array type, got %i",
+ JSValueGetType(context, jsvalue));
+ return FALSE;
+ }
+
+ dbus_signature_iter_recurse(&siter, &arraysiter);
+ array_signature = dbus_signature_iter_get_signature(&arraysiter);
+
+ propnames = JSObjectCopyPropertyNames(context, (JSObjectRef)jsvalue);
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ array_signature, &subiter))
+ {
+ g_warning("Memory exhausted!");
+ JSPropertyNameArrayRelease(propnames);
+ g_free(array_signature);
+ return FALSE;
+ }
+
+ props = JSPropertyNameArrayGetCount(propnames);
+
+ for (i = 0; i < props; i++)
+ {
+ JSValueRef value = JSObjectGetPropertyAtIndex(context,
+ (JSObjectRef)jsvalue,
+ i,
+ NULL);
+ jsvalue_append_to_message_iter(context, value,
+ &subiter, array_signature);
+ }
+ dbus_message_iter_close_container(iter, &subiter);
+ g_free(array_signature);
+ JSPropertyNameArrayRelease(propnames);
+ break;
+ }
+ }
+ case DBUS_TYPE_VARIANT:
+ {
+ DBusMessageIter subiter;
+ DBusSignatureIter vsiter;
+ char *vsignature;
+ JSValueRef value = NULL;
+
+ if (jsvalue_typeof(context, jsvalue, "DBusVariant"))
+ {
+ value = (JSValueRef)JSObjectGetPrivate((JSObjectRef)jsvalue);
+ } else {
+ value = jsvalue;
+ }
+
+ dbus_signature_iter_recurse(&siter, &vsiter);
+ vsignature = jsvalue_to_signature(context, value);
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ vsignature, &subiter))
+ {
+ g_warning("Memory exhausted!");
+ g_free(vsignature);
+ return FALSE;
+ }
+
+ if (!jsvalue_append_to_message_iter(context, value,
+ &subiter, vsignature))
+ {
+ g_warning("Failed to append variant contents with signature %s",
+ vsignature);
+ g_free(vsignature);
+ return FALSE;
+ }
+
+ g_free(vsignature);
+ dbus_message_iter_close_container(iter, &subiter);
+ break;
+ }
+ case DBUS_TYPE_STRUCT:
+ {
+ int i, props;
+ JSPropertyNameArrayRef propnames;
+ DBusMessageIter subiter;
+ DBusSignatureIter stsiter;
+ char *stsignature;
+ JSValueRef value = NULL;
+
+ if (jsvalue_typeof(context, jsvalue, "DBusStruct"))
+ {
+ value = (JSValueRef)JSObjectGetPrivate((JSObjectRef)jsvalue);
+ } else {
+ value = jsvalue;
+ }
+
+ propnames = JSObjectCopyPropertyNames(context, (JSObjectRef)value);
+ props = JSPropertyNameArrayGetCount(propnames);
+
+ if (props == 0)
+ {
+ g_warning("Empty struct not allowed");
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
+ NULL, &subiter))
+ {
+ g_warning("Memory exhausted!");
+ return FALSE;
+ }
+
+ dbus_signature_iter_recurse(&siter, &stsiter);
+
+ for (i = 0; i < props; i++)
+ {
+ const char *sig = dbus_signature_iter_get_signature(&stsiter);
+ JSValueRef child_value = JSObjectGetProperty(context,
+ (JSObjectRef)value,
+ JSPropertyNameArrayGetNameAtIndex(propnames, i),
+ NULL);
+
+ if (!jsvalue_append_to_message_iter(context, child_value,
+ &subiter, sig))
+ {
+ g_warning("Failed to append struct contents with signature %s",
+ sig);
+ return FALSE;
+ }
+
+ if (!dbus_signature_iter_next(&stsiter))
+ {
+ break;
+ }
+ }
+ JSPropertyNameArrayRelease(propnames);
+ dbus_message_iter_close_container(iter, &subiter);
+ break;
+ }
+ default:
+ g_warning("Tried to append invalid or unsupported argument '%s' "
+ "(base type '%c') to a message", signature,
+ dbus_signature_iter_get_current_type(&siter));
+ break;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+jsvalue_append_basic(JSContextRef context,
+ JSValueRef jsvalue,
+ int type,
+ DBusMessageIter *iter)
+{
+ dbus_uint64_t v = 0;
+ dbus_uint64_t *value = NULL;
+ char *strvalue = NULL;
+ switch (JSValueGetType(context, jsvalue))
+ {
+ case kJSTypeNumber:
+ {
+ v = (dbus_uint64_t)JSValueToNumber(context, jsvalue, NULL);
+ value = &v;
+ break;
+ }
+ case kJSTypeString:
+ {
+ strvalue = string_from_jsvalue(context, jsvalue);
+ break;
+ }
+ case kJSTypeObject:
+ {
+ int i;
+ for (i = 0; i < JSCOREBUS_N_NUMBER_CLASSES; i++)
+ {
+ if (jscorebus_number_class_types[i] == type
+ && jsvalue_typeof(context, jsvalue, jscorebus_number_class_names[i]))
+ {
+ value = (dbus_uint64_t *)JSObjectGetPrivate((JSObjectRef)jsvalue);
+ break;
+ }
+ }
+
+ if (jsvalue_typeof(context, jsvalue, "DBusObjectPath"))
+ {
+ strvalue = string_from_jsvalue(context,
+ JSObjectGetPrivate((JSObjectRef)jsvalue));
+ break;
+ }
+
+ if (jsvalue_typeof(context, jsvalue, "DBusSignature"))
+ {
+ strvalue = string_from_jsvalue(context,
+ JSObjectGetPrivate((JSObjectRef)jsvalue));
+ break;
+ }
+
+ /* Intentionally falls through to default */
+ }
+ case kJSTypeUndefined:
+ case kJSTypeNull:
+ {
+ g_warning("Tried to pass undefined or null as basic type");
+ break;
+ }
+ default:
+ g_warning("JSValue wasn't a '%c' (it was %i), or it is not supported",
+ type, JSValueGetType(context, jsvalue));
+ break;
+ }
+
+ if (value != NULL && dbus_message_iter_append_basic(iter, type, value))
+ {
+ return TRUE;
+ } else if (strvalue != NULL
+ && dbus_message_iter_append_basic(iter, type, &strvalue)) {
+ g_free(strvalue);
+ return TRUE;
+ }
+
+ g_free(strvalue);
+ return FALSE;
+}
+
+#define NUMERIC_VALUE(NAME) \
+ DBUS_TYPE_## NAME: \
+ { \
+ dbus_uint64_t value = 0; \
+ dbus_message_iter_get_basic(iter, &value); \
+ jsvalue = JSValueMakeNumber(context, (double)value); \
+ break; \
+ }
+
+JSValueRef jsvalue_from_message_iter(JSContextRef context,
+ DBusMessageIter *iter)
+{
+ JSValueRef jsvalue;
+
+ switch (dbus_message_iter_get_arg_type (iter))
+ {
+ case DBUS_TYPE_BOOLEAN:
+ {
+ gboolean value;
+ dbus_message_iter_get_basic(iter, &value);
+ jsvalue = JSValueMakeBoolean(context, value);
+ break;
+ }
+ case NUMERIC_VALUE(BYTE)
+ case NUMERIC_VALUE(INT16)
+ case NUMERIC_VALUE(UINT16)
+ case NUMERIC_VALUE(INT32)
+ case NUMERIC_VALUE(UINT32)
+ case NUMERIC_VALUE(INT64)
+ case NUMERIC_VALUE(UINT64)
+ case DBUS_TYPE_DOUBLE:
+ {
+ double value = 0;
+ dbus_message_iter_get_basic(iter, &value);
+ jsvalue = JSValueMakeNumber(context, value);
+ break;
+ }
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ case DBUS_TYPE_STRING:
+ {
+ const char *value;
+ JSStringRef jsstr;
+ dbus_message_iter_get_basic(iter, &value);
+ jsstr = JSStringCreateWithUTF8CString(value);
+ jsvalue = JSValueMakeString(context, jsstr);
+ JSStringRelease(jsstr);
+ break;
+ }
+ case DBUS_TYPE_ARRAY:
+ {
+ JSStringRef arrayProperty;
+ JSObjectRef arrayConstructor;
+ DBusMessageIter child_iter;
+ int i;
+
+ arrayProperty = JSStringCreateWithUTF8CString("Array");
+ arrayConstructor = JSValueToObject(context,
+ JSObjectGetProperty(context,
+ JSContextGetGlobalObject(context),
+ arrayProperty, NULL),
+ NULL);
+ JSStringRelease(arrayProperty);
+
+ jsvalue = JSObjectCallAsConstructor(context, arrayConstructor,
+ 0, NULL, NULL);
+
+ dbus_message_iter_recurse(iter, &child_iter);
+
+ i = 0;
+ do
+ {
+ if (dbus_message_iter_get_arg_type(&child_iter) == DBUS_TYPE_DICT_ENTRY)
+ {
+ JSValueRef key;
+ JSStringRef key_str;
+ JSValueRef value;
+ DBusMessageIter dictiter;
+
+ dbus_message_iter_recurse(&child_iter, &dictiter);
+ key = jsvalue_from_message_iter(context, &dictiter);
+ key_str = JSValueToStringCopy(context, key, NULL);
+ dbus_message_iter_next(&dictiter);
+ value = jsvalue_from_message_iter(context, &dictiter);
+
+ JSObjectSetProperty(context, (JSObjectRef)jsvalue,
+ key_str, value, 0, NULL);
+ JSStringRelease(key_str);
+ } else {
+ JSObjectSetPropertyAtIndex(context, (JSObjectRef)jsvalue, i++,
+ jsvalue_from_message_iter(context, &child_iter), NULL);
+ }
+ } while (dbus_message_iter_next(&child_iter));
+
+ break;
+ }
+ case DBUS_TYPE_VARIANT:
+ {
+ DBusMessageIter child_iter;
+ dbus_message_iter_recurse(iter, &child_iter);
+ jsvalue = jsvalue_from_message_iter(context, &child_iter);
+ break;
+ }
+ case DBUS_TYPE_INVALID:
+ /* Convert invalid to undefined */
+ jsvalue = JSValueMakeUndefined(context);
+ break;
+ case DBUS_TYPE_DICT_ENTRY:
+ /* Dict entries should always be handled in the array branch */
+ g_assert_not_reached();
+ default:
+ g_warning("Could not convert value from type %c (%i)",
+ dbus_message_iter_get_arg_type (iter),
+ dbus_message_iter_get_arg_type (iter));
+ jsvalue = JSValueMakeUndefined(context);
+ break;
+ }
+
+ return jsvalue;
+}
+
+
+char *string_from_jsstring(JSContextRef context, JSStringRef jsstr)
+{
+ size_t len;
+ char *cstr;
+
+ len = JSStringGetMaximumUTF8CStringSize(jsstr);
+ cstr = g_new(char, len);
+ JSStringGetUTF8CString(jsstr, cstr, len);
+
+ return cstr;
+}
+
+char *string_from_jsvalue(JSContextRef context, JSValueRef jsvalue)
+{
+ JSStringRef jsstr;
+ char *cstr;
+
+ if (!JSValueIsString(context, jsvalue))
+ {
+ return NULL;
+ }
+
+ jsstr = JSValueToStringCopy(context, jsvalue, NULL);
+ cstr = string_from_jsstring(context, jsstr);
+ JSStringRelease(jsstr);
+
+ return cstr;
+}
+
+JSObjectRef function_from_jsvalue(JSContextRef context,
+ JSValueRef value,
+ JSValueRef* exception)
+{
+ JSObjectRef function;
+
+ if (JSValueIsNull(context, value))
+ {
+ return NULL;
+ }
+
+ if (!JSValueIsObject(context, value) )
+ {
+ /* TODO: set exception */
+ g_warning("%s: Value wasn't an object", G_STRFUNC);
+ return NULL;
+ }
+
+ function = JSValueToObject(context, value, exception);
+ if (!JSObjectIsFunction(context, function))
+ {
+ /* TODO: set exception */
+ g_warning("%s: Value wasn't a function", G_STRFUNC);
+ return NULL;
+ }
+
+ return function;
+}
+
+void call_function_with_message_args(JSContextRef context,
+ JSObjectRef thisObject,
+ JSObjectRef function,
+ DBusMessage *message)
+{
+ size_t argumentCount;
+ JSValueRef *args;
+ int arg_type;
+ DBusMessageIter iter;
+
+ /**
+ * Iterate over the message arguments and append them to args
+ */
+ dbus_message_iter_init (message, &iter);
+ argumentCount = 0;
+ args = NULL;
+
+ /* Error messages should have the error name as the first param */
+ if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR)
+ {
+ const char *error_name = dbus_message_get_error_name(message);
+
+ if (error_name != NULL)
+ {
+ JSValueRef *tmp;
+ JSStringRef jsstr;
+
+ jsstr = JSStringCreateWithUTF8CString(error_name);
+ argumentCount++;
+ tmp = g_renew(JSValueRef, args, argumentCount);
+ args = tmp;
+ args[argumentCount-1] = JSValueMakeString(context, jsstr);;
+ JSStringRelease(jsstr);
+ }
+ }
+
+ while ((arg_type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
+ {
+ JSValueRef *tmp;
+
+ argumentCount++;
+ tmp = g_renew(JSValueRef, args, argumentCount);
+ args = tmp;
+ args[argumentCount-1] = (JSValueRef)jsvalue_from_message_iter(context, &iter);
+ if (args[argumentCount-1] == NULL) {
+ g_warning("Couldn't get argument from argument type %c", arg_type);
+ args[argumentCount-1] = JSValueMakeUndefined(context);
+ }
+ dbus_message_iter_next (&iter);
+ }
+
+ JSObjectCallAsFunction(context, function, thisObject,
+ argumentCount, args, NULL);
+}
+
--- /dev/null
+/**
+ * Browser D-Bus Bridge, JavaScriptCore version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ * Contact: Movial Creative Technologies Inc, <info@movial.com>
+ * Authors: Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* Functions to convert between D-Bus types and JSCore types */
+
+#ifndef __JSCOREBUS_CONVERT_H___
+#define __JSCOREBUS_CONVERT_H___
+
+#include <dbus/dbus.h>
+#include <JavaScriptCore/JavaScript.h>
+
+/* The number class names are in guestimated usage frequency order to speed up
+ * iteration over them.
+ */
+#define JSCOREBUS_N_NUMBER_CLASSES 8
+char *jscorebus_number_class_names[JSCOREBUS_N_NUMBER_CLASSES];
+int jscorebus_number_class_types[JSCOREBUS_N_NUMBER_CLASSES];
+
+/* Append JSValues to a D-Bus message iter */
+gboolean jsvalue_array_append_to_message_iter(JSContextRef context,
+ const JSValueRef jsvalues[],
+ int n_values,
+ DBusMessageIter *iter,
+ const char *signature);
+gboolean jsvalue_append_to_message_iter(JSContextRef context,
+ const JSValueRef jsvalue,
+ DBusMessageIter *iter,
+ const char *signature);
+
+/* Call a JS function with the arguments from a message */
+void call_function_with_message_args(JSContextRef context,
+ JSObjectRef thisObject,
+ JSObjectRef function,
+ DBusMessage *message);
+
+/* To JavaScript types */
+JSValueRef jsvalue_from_message_iter(JSContextRef context,
+ DBusMessageIter *iter);
+JSObjectRef function_from_jsvalue(JSContextRef context,
+ JSValueRef value,
+ JSValueRef* exception);
+
+/* To D-Bus types */
+char *string_from_jsstring(JSContextRef context, JSStringRef jsstring);
+char *string_from_jsvalue(JSContextRef context, JSValueRef jsvalue);
+dbus_uint64_t jsvalue_to_number_value (JSContextRef context,
+ JSValueRef jsvalue,
+ int *number_type);
+
+/* JSValue to D-Bus signature (autodetection) */
+char *jsvalue_to_signature(JSContextRef context, JSValueRef jsvalue);
+gboolean
+jsarray_get_signature(JSContextRef context,
+ JSValueRef jsvalue,
+ JSPropertyNameArrayRef propNames,
+ char **signature);
+gboolean
+jsdict_get_signature(JSContextRef context,
+ JSValueRef jsvalue,
+ JSPropertyNameArrayRef propNames,
+ char **signature);
+
+
+/* Helper functions */
+gboolean jsvalue_typeof(JSContextRef context,
+ JSValueRef jsvalue,
+ const char *type);
+gboolean jsvalue_instanceof(JSContextRef context,
+ JSValueRef jsvalue,
+ const char *constructor);
+
+
+
+#endif /* __JSCOREBUS_CONVERT_H___ */
+
--- /dev/null
+/**
+ * Browser D-Bus Bridge, JavaScriptCore version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ * Contact: Movial Creative Technologies Inc, <info@movial.com>
+ * Authors: Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <JavaScriptCore/JavaScript.h>
+
+#include "jscorebus-marshal.h"
+#include "jscorebus-method.h"
+
+/* Private data for methods */
+typedef struct _MethodPrivate
+{
+ char *destination;
+ char *object_path;
+ char *method_name;
+ char *interface;
+ char *signature;
+
+ DBusConnection *connection;
+ DBusMessage *message;
+ DBusPendingCall *pending_reply;
+
+ JSGlobalContextRef context;
+ JSObjectRef this;
+ JSObjectRef onreply;
+ JSObjectRef onerror;
+ gboolean async;
+} MethodPrivate;
+
+/* Utility functions */
+static
+JSClassRef get_class ();
+
+static
+JSValueRef call_sync(JSContextRef context, MethodPrivate *priv);
+static
+JSValueRef call_async(JSContextRef context, MethodPrivate *priv);
+static
+void call_onreply(JSContextRef context,
+ MethodPrivate *priv,
+ DBusMessage *message);
+static
+void call_onerror(JSContextRef context,
+ MethodPrivate *priv,
+ DBusMessage *message);
+
+/* JSCore methods */
+static
+void method_finalize(JSObjectRef object);
+
+static
+bool method_set_property(JSContextRef context,
+ JSObjectRef object,
+ JSStringRef propertyName,
+ JSValueRef value,
+ JSValueRef* exception);
+
+static
+JSValueRef method_call (JSContextRef context,
+ JSObjectRef function,
+ JSObjectRef thisObject,
+ size_t argumentCount,
+ const JSValueRef arguments[],
+ JSValueRef *exception);
+
+/* The Method Class */
+static const
+JSClassDefinition method_jsclass_def =
+{
+ 0,
+ kJSClassAttributeNone,
+ "DBusMethod",
+ NULL,
+
+ NULL,
+ NULL,
+
+ NULL, /* Initialize */
+ method_finalize,
+
+ NULL,
+ NULL,
+ method_set_property, /* SetProperty */
+ NULL,
+ NULL,
+
+ method_call, /* CallAsFunction */
+ NULL, /* Constructor */
+ NULL,
+ NULL
+};
+
+/*** JSCore methods */
+
+static
+void method_finalize(JSObjectRef object)
+{
+ MethodPrivate *priv = (MethodPrivate *)JSObjectGetPrivate(object);
+
+ if (priv != NULL)
+ {
+
+ if (priv->pending_reply != NULL)
+ {
+ dbus_pending_call_cancel(priv->pending_reply);
+ }
+
+ g_free(priv->destination);
+ g_free(priv->object_path);
+ g_free(priv->method_name);
+ g_free(priv->interface);
+ g_free(priv->signature);
+
+ dbus_connection_unref(priv->connection);
+
+ priv->this = NULL;
+ priv->onreply = NULL;
+ priv->onerror = NULL;
+ priv->context = NULL;
+
+ g_free(priv);
+ priv = NULL;
+ }
+}
+
+static
+bool method_set_property(JSContextRef context,
+ JSObjectRef object,
+ JSStringRef propertyName,
+ JSValueRef value,
+ JSValueRef* exception)
+{
+ MethodPrivate *priv;
+
+ priv = (MethodPrivate *)JSObjectGetPrivate(object);
+ g_assert(priv != NULL);
+
+ if (JSStringIsEqualToUTF8CString(propertyName, "async"))
+ {
+ if (JSValueIsBoolean(context, value))
+ {
+ priv->async = JSValueToBoolean(context, value);
+ return TRUE;
+ }
+
+ /* TODO: set exception */
+ g_warning("Tried to set a non-boolean to 'async'");
+ return TRUE;
+ } else if (JSStringIsEqualToUTF8CString(propertyName, "onreply")) {
+ priv->onreply = function_from_jsvalue(context, value, exception);
+ return TRUE;
+ } else if (JSStringIsEqualToUTF8CString(propertyName, "onerror")) {
+ priv->onerror = function_from_jsvalue(context, value, exception);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static
+JSValueRef method_call (JSContextRef context,
+ JSObjectRef function,
+ JSObjectRef thisObject,
+ size_t argumentCount,
+ const JSValueRef arguments[],
+ JSValueRef *exception)
+{
+ int i;
+ MethodPrivate *priv;
+ DBusMessageIter iter;
+ JSValueRef ret;
+
+ priv = (MethodPrivate *)JSObjectGetPrivate(function);
+ g_assert(priv != NULL);
+
+ priv->message = dbus_message_new_method_call(priv->destination,
+ priv->object_path,
+ priv->interface,
+ priv->method_name);
+
+ if (argumentCount > 0)
+ {
+ /* Push arguments to the message */
+ dbus_message_iter_init_append (priv->message, &iter);
+ if (!jsvalue_array_append_to_message_iter(context,
+ arguments, argumentCount,
+ &iter, priv->signature))
+ {
+ dbus_message_unref(priv->message);
+ priv->message = NULL;
+ }
+ }
+
+ if (priv->async)
+ {
+ ret = call_async(context, priv);
+ } else {
+ ret = call_sync(context, priv);
+ }
+
+ if (priv->message != NULL)
+ {
+ dbus_message_unref(priv->message);
+ }
+ priv->message = NULL;
+
+ return ret;
+}
+
+/*** Utility functions */
+
+static
+JSClassRef get_class ()
+{
+ JSClassRef jsclass = (JSClassRef)jsclass_lookup(&method_jsclass_def);
+
+ if (G_LIKELY(jsclass != NULL))
+ {
+ return jsclass;
+ }
+
+ jsclassdef_insert("DBusMethod", &method_jsclass_def);
+ jsclass = (JSClassRef)jsclass_lookup(&method_jsclass_def);
+
+ g_assert(jsclass != NULL);
+
+ return jsclass;
+}
+
+static
+JSValueRef call_sync(JSContextRef context, MethodPrivate *priv)
+{
+ /**
+ * Set up reply callback from the method.onReply property if available and
+ * send the message
+ */
+
+ if (priv->message == NULL)
+ {
+ call_onerror(context, priv, NULL);
+ return JSValueMakeUndefined(context);
+ }
+
+ if (priv->onreply != NULL)
+ {
+ DBusMessage *reply_message;
+
+ reply_message = dbus_connection_send_with_reply_and_block(
+ priv->connection,
+ priv->message, -1, NULL);
+ if (reply_message != NULL)
+ {
+ if (dbus_message_get_type(reply_message) == DBUS_MESSAGE_TYPE_ERROR)
+ {
+ call_onerror(context, priv, reply_message);
+ } else if (dbus_message_get_type(reply_message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) {
+ call_onreply(context, priv, reply_message);
+ } else {
+ g_warning("Unknown reply!");
+ }
+ } else {
+ // TODO: set exception
+ g_warning("Failed to send message to %s", priv->destination);
+ call_onerror(context, priv, NULL);
+ }
+ } else {
+ if (!dbus_connection_send(priv->connection, priv->message, NULL))
+ {
+ // TODO: set exception
+ g_warning("Failed to send message to %s", priv->destination);
+ call_onerror(context, priv, NULL);
+ }
+ }
+
+ return JSValueMakeUndefined(context);
+}
+
+static
+void pending_call_notify(DBusPendingCall *pending,
+ void *user_data)
+{
+ DBusMessage *reply_message;
+ MethodPrivate *priv;
+
+ g_assert(user_data != NULL);
+
+ priv = (MethodPrivate *)user_data;
+ g_assert(priv->pending_reply != NULL);
+
+ if (pending == NULL)
+ {
+ /* Disconnected!
+ * TODO: How do we handle these?
+ */
+ g_warning("Disconnected from the bus!");
+ priv->pending_reply = NULL;
+ return;
+ }
+
+ priv->pending_reply = NULL;
+ reply_message = dbus_pending_call_steal_reply(pending);
+
+ if (dbus_message_get_type(reply_message) == DBUS_MESSAGE_TYPE_ERROR)
+ {
+ call_onerror(priv->context, priv, reply_message);
+ } else if (dbus_message_get_type(reply_message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) {
+ call_onreply(priv->context, priv, reply_message);
+ } else {
+ g_warning("Unknown reply!");
+ }
+
+}
+
+static
+JSValueRef call_async(JSContextRef context, MethodPrivate *priv)
+{
+ dbus_uint32_t serial = 0;
+
+ if (priv->message == NULL)
+ {
+ call_onerror(context, priv, NULL);
+ }
+
+ if (priv->onreply != NULL)
+ {
+ if (dbus_connection_send_with_reply(
+ priv->connection,
+ priv->message, &priv->pending_reply, -1))
+ {
+ dbus_pending_call_set_notify(priv->pending_reply, pending_call_notify,
+ priv, NULL);
+ } else {
+ // TODO: set exception
+ g_warning("Failed to send message to %s", priv->destination);
+ call_onerror(context, priv, NULL);
+ }
+ } else {
+ dbus_message_set_no_reply(priv->message, TRUE);
+
+ if (!dbus_connection_send(priv->connection, priv->message, &serial))
+ {
+ // TODO: set exception
+ call_onerror(context, priv, NULL);
+ }
+ }
+
+ return JSValueMakeUndefined(context);
+}
+
+static
+void call_onreply(JSContextRef context,
+ MethodPrivate *priv,
+ DBusMessage *message)
+{
+ if (priv->onreply == NULL)
+ {
+ return;
+ }
+
+ call_function_with_message_args(context, priv->this, priv->onreply, message);
+}
+
+static
+void call_onerror(JSContextRef context,
+ MethodPrivate *priv,
+ DBusMessage *message)
+{
+ if (priv->onerror == NULL)
+ {
+ return;
+ }
+
+ if (message == NULL)
+ {
+ /* We couldn't send the message */
+ JSStringRef name = JSStringCreateWithUTF8CString("MessageError");
+ JSStringRef str = JSStringCreateWithUTF8CString("Could not send message");
+ JSValueRef *args = g_new(JSValueRef, 2);
+
+ args[0] = JSValueMakeString(context, name);
+ args[1] = JSValueMakeString(context, str);
+
+ JSObjectCallAsFunction(context, priv->onerror, priv->this,
+ 2, args, NULL);
+ JSStringRelease(name);
+ JSStringRelease(str);
+ return;
+ }
+
+ call_function_with_message_args(context, priv->this, priv->onerror, message);
+}
+
+/*** Public API */
+
+/* NOTE: Takes ownership of the arguments! */
+JSObjectRef jscorebus_create_method (JSGlobalContextRef context,
+ DBusConnection *connection,
+ char *destination,
+ char *object_path,
+ char *method_name,
+ char *interface,
+ char *signature,
+ JSObjectRef thisObject,
+ JSValueRef* exception)
+{
+ MethodPrivate *priv = NULL;
+
+ g_return_val_if_fail(destination != NULL
+ && object_path != NULL
+ && method_name != NULL,
+ NULL);
+
+ priv = g_new0(MethodPrivate, 1);
+
+ /* TODO: Maybe these should be JSStrings after all, to avoid copies? */
+ priv->destination = destination;
+ priv->object_path = object_path;
+ priv->method_name = method_name;
+
+ priv->interface = interface;
+ priv->signature = signature;
+
+ priv->async = true;
+
+ priv->connection = dbus_connection_ref(connection);
+
+ priv->context = context;
+
+ priv->this = thisObject;
+
+ return JSObjectMake(context, get_class(), priv);
+}
--- /dev/null
+/**
+ * Browser D-Bus Bridge, JavaScriptCore version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ * Contact: Movial Creative Technologies Inc, <info@movial.com>
+ * Authors: Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __JSCOREBUS_METHOD_H__
+#define __JSCOREBUS_METHOD_H__
+
+#include <dbus/dbus.h>
+#include <JavaScriptCore/JavaScript.h>
+
+/* NOTE: Takes ownership of the arguments! */
+JSObjectRef jscorebus_create_method (JSGlobalContextRef context,
+ DBusConnection *connection,
+ char *destination,
+ char *object_path,
+ char *method_name,
+ char *interface,
+ char *signature,
+ JSObjectRef thisObject,
+ JSValueRef* exception);
+
+#endif /* __JSCOREBUS_METHOD_H__ */
+
--- /dev/null
+/**
+ * Browser D-Bus Bridge, JavaScriptCore version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ * Contact: Movial Creative Technologies Inc, <info@movial.com>
+ * Authors: Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <JavaScriptCore/JavaScript.h>
+
+#include "jscorebus-marshal.h"
+
+/* Private data for signals */
+typedef struct _SignalPrivate
+{
+ char *interface;
+ char *signal_name;
+ char *sender;
+ char *object_path;
+
+ DBusConnection *connection;
+ char *match_rule;
+
+ JSGlobalContextRef context;
+ JSObjectRef this;
+ JSObjectRef onemit;
+ gboolean enabled;
+} SignalPrivate;
+
+/* Utility functions */
+static
+JSClassRef get_class ();
+
+static
+void add_match_and_handler(SignalPrivate *priv);
+static
+void remove_match_and_handler(SignalPrivate *priv);
+
+/* JSCore methods */
+static
+void signal_finalize(JSObjectRef object);
+
+static
+bool signal_set_property(JSContextRef context,
+ JSObjectRef object,
+ JSStringRef propertyName,
+ JSValueRef value,
+ JSValueRef* exception);
+
+/* We keep a hash table to track the signals callbacks */
+static GHashTable *signal_hash;
+
+/* The Signal Class */
+static const
+JSClassDefinition signal_jsclass_def =
+{
+ 0,
+ kJSClassAttributeNone,
+ "DBusSignal",
+ NULL,
+
+ NULL,
+ NULL,
+
+ NULL, /* Initialize */
+ signal_finalize,
+
+ NULL,
+ NULL,
+ signal_set_property, /* SetProperty */
+ NULL,
+ NULL,
+
+ NULL, /* CallAsFunction */
+ NULL, /* Constructor */
+ NULL,
+ NULL
+};
+
+/*** JSCore methods */
+
+static
+void signal_finalize(JSObjectRef object)
+{
+ SignalPrivate *priv = (SignalPrivate *)JSObjectGetPrivate(object);
+
+ if (priv != NULL)
+ {
+ remove_match_and_handler(priv);
+
+ g_free(priv->object_path);
+ g_free(priv->signal_name);
+ g_free(priv->interface);
+ g_free(priv->sender);
+ g_free(priv->object_path);
+ g_free(priv->match_rule);
+ dbus_connection_unref(priv->connection);
+
+ priv->this = NULL;
+ priv->onemit = NULL;
+ priv->context = NULL;
+
+ g_free(priv);
+ priv = NULL;
+ }
+}
+
+static
+bool signal_set_property(JSContextRef context,
+ JSObjectRef object,
+ JSStringRef propertyName,
+ JSValueRef value,
+ JSValueRef* exception)
+{
+ SignalPrivate *priv;
+
+ priv = (SignalPrivate *)JSObjectGetPrivate(object);
+ g_assert(priv != NULL);
+
+ if (JSStringIsEqualToUTF8CString(propertyName, "enabled"))
+ {
+ /* We don't enable unless we have a callback */
+ if (priv->onemit == NULL)
+ {
+ /* TODO: Throw exception */
+ return TRUE;
+ }
+ if (JSValueIsBoolean(context, value))
+ {
+ priv->enabled = JSValueToBoolean(context, value);
+ if (priv->enabled)
+ {
+ add_match_and_handler(priv);
+ }
+ return TRUE;
+ }
+
+ /* TODO: set exception */
+ g_warning("Tried to set a non-boolean to 'enabled'");
+ return TRUE;
+ } else if (JSStringIsEqualToUTF8CString(propertyName, "onemit")) {
+ priv->onemit = function_from_jsvalue(context, value, exception);
+
+ /* If the callback function goes away, we need to disable the signal,
+ * remove match and remove our entry from the handlers
+ */
+ if (priv->onemit == NULL)
+ {
+ remove_match_and_handler(priv);
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*** Utility functions */
+
+static
+JSClassRef get_class ()
+{
+ JSClassRef jsclass = (JSClassRef)jsclass_lookup(&signal_jsclass_def);
+
+ if (G_LIKELY(jsclass != NULL))
+ {
+ return jsclass;
+ }
+
+ jsclassdef_insert("DBusSignal", &signal_jsclass_def);
+ jsclass = (JSClassRef)jsclass_lookup(&signal_jsclass_def);
+
+ g_assert(jsclass != NULL);
+
+ return jsclass;
+}
+
+static
+void add_match_and_handler(SignalPrivate *priv)
+{
+ char *signal_str;
+ GPtrArray *handlers;
+
+ dbus_bus_add_match(priv->connection, priv->match_rule, NULL);
+
+ signal_str = g_strdup_printf("%s.%s", priv->interface, priv->signal_name);
+ handlers = g_hash_table_lookup(signal_hash, signal_str);
+
+ if (handlers == NULL)
+ {
+ handlers = g_ptr_array_new();
+ g_hash_table_insert(signal_hash, signal_str, handlers);
+ } else {
+ g_free(signal_str);
+ }
+
+ g_ptr_array_add(handlers, priv);
+}
+
+static
+void remove_match_and_handler(SignalPrivate *priv)
+{
+ char *signal_str;
+ GPtrArray *handlers;
+
+ signal_str = g_strdup_printf("%s.%s", priv->interface, priv->signal_name);
+
+ handlers = g_hash_table_lookup(signal_hash, signal_str);
+
+ if (handlers != NULL)
+ {
+ g_ptr_array_remove(handlers, priv);
+ if (handlers->len == 0)
+ {
+ g_hash_table_remove(signal_hash, signal_str);
+ g_ptr_array_free(handlers, TRUE);
+ }
+ }
+
+ g_free(signal_str);
+
+ dbus_bus_remove_match(priv->connection, priv->match_rule, NULL);
+
+}
+
+static
+void call_onemit(SignalPrivate *priv,
+ DBusMessage *message)
+{
+
+ if (priv->enabled == FALSE
+ || priv->onemit == NULL)
+ {
+ return;
+ }
+
+ /* If the signal was created with a sender, we need to check for it
+ * and not deliver if it does not match
+ */
+ if (priv->sender != NULL)
+ {
+ if (!dbus_message_has_sender(message, priv->sender))
+ {
+ return;
+ }
+ }
+ /* Ditto for object paths */
+ if (priv->object_path != NULL)
+ {
+ if (!dbus_message_has_path(message, priv->object_path))
+ {
+ return;
+ }
+ }
+
+ call_function_with_message_args(priv->context, priv->this, priv->onemit, message);
+}
+
+static
+DBusHandlerResult signal_filter(DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ char *signal_str;
+ GPtrArray *handlers;
+
+ if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
+ {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ signal_str = g_strdup_printf("%s.%s",
+ dbus_message_get_interface(message),
+ dbus_message_get_member(message));
+
+ handlers = g_hash_table_lookup(signal_hash, signal_str);
+ g_free(signal_str);
+
+ if (handlers == NULL || handlers->len == 0)
+ {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ g_ptr_array_foreach(handlers, (GFunc)call_onemit, message);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+/*** Public API */
+
+/* NOTE: Takes ownership of the arguments! */
+JSObjectRef jscorebus_create_signal (JSGlobalContextRef context,
+ DBusConnection *connection,
+ char *interface,
+ char *signal_name,
+ char *sender,
+ char *object_path,
+ JSObjectRef thisObject,
+ JSValueRef* exception)
+{
+ int i;
+ char **matchv;
+ char *signal_str;
+ GPtrArray *handlers;
+ SignalPrivate *priv = NULL;
+ static gboolean filter_added = FALSE;
+
+ g_return_val_if_fail(interface != NULL
+ && signal_name != NULL,
+ NULL);
+
+ priv = g_new0(SignalPrivate, 1);
+
+ priv->object_path = object_path;
+ priv->interface = interface;
+ priv->signal_name = signal_name;
+ priv->sender = sender;
+ priv->object_path = object_path;
+
+ priv->enabled = false;
+
+ priv->connection = dbus_connection_ref(connection);
+
+ priv->context = context;
+ priv->this = thisObject;
+
+ /* If we don't already have a filter function for the signals, add one */
+ if (G_UNLIKELY(!filter_added))
+ {
+ signal_hash = g_hash_table_new(g_str_hash, g_str_equal);
+ dbus_connection_add_filter(connection, signal_filter, NULL, NULL);
+ filter_added = TRUE;
+ }
+
+ /* Add the match rule for the signal */
+ matchv = g_new0(char*, 4);
+ i = 0;
+ matchv[i++] = g_strdup_printf("type=signal,interface=%s,member=%s",
+ priv->interface, priv->signal_name);
+ if (priv->sender != NULL)
+ {
+ matchv[i++] = g_strdup_printf("sender=%s", priv->sender);
+ }
+ if (priv->object_path != NULL)
+ {
+ matchv[i++] = g_strdup_printf("object_path=%s", priv->object_path);
+ }
+
+ priv->match_rule = g_strjoinv(",", matchv);
+ g_strfreev(matchv);
+
+ return JSObjectMake(context, get_class(), priv);
+}
+
--- /dev/null
+/**
+ * Browser D-Bus Bridge, JavaScriptCore version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ * Contact: Movial Creative Technologies Inc, <info@movial.com>
+ * Authors: Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __JSCOREBUS_SIGNAL_H__
+#define __JSCOREBUS_SIGNAL_H__
+
+#include <dbus/dbus.h>
+#include <JavaScriptCore/JavaScript.h>
+
+/* NOTE: Takes ownership of the arguments! */
+JSObjectRef jscorebus_create_signal (JSGlobalContextRef context,
+ DBusConnection *connection,
+ char *interface,
+ char *signal_name,
+ char *sender,
+ char *object_path,
+ JSObjectRef thisObject,
+ JSValueRef* exception);
+
+#endif /* __JSCOREBUS_SIGNAL_H__ */
+
--- /dev/null
+/**
+ * Browser D-Bus Bridge, JavaScriptCore version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ * Contact: Movial Creative Technologies Inc, <info@movial.com>
+ * Authors: Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <JavaScriptCore/JavaScript.h>
+
+#include "jscorebus-classfactory.h"
+#include "jscorebus-marshal.h"
+
+gboolean jsvalue_typeof(JSContextRef context,
+ JSValueRef jsvalue,
+ const char *type)
+{
+ const JSClassDefinition *jsclassdef;
+ JSClassRef jsclass;
+
+ jsclassdef = jsclassdef_lookup(type);
+ if (G_UNLIKELY(jsclassdef == NULL))
+ return FALSE;
+ jsclass = jsclass_lookup(jsclassdef);
+
+ return JSValueIsObjectOfClass(context, jsvalue, jsclass);
+}
+
+gboolean jsvalue_instanceof(JSContextRef context,
+ JSValueRef jsvalue,
+ const char *constructor)
+{
+ JSStringRef property;
+ JSObjectRef ctor;
+
+ property = JSStringCreateWithUTF8CString(constructor);
+ ctor = JSValueToObject(context,
+ JSObjectGetProperty(context,
+ JSContextGetGlobalObject(context),
+ property,
+ NULL),
+ NULL);
+ JSStringRelease(property);
+
+ return JSValueIsInstanceOfConstructor(context, jsvalue, ctor, NULL);
+}
+
+char *jsvalue_to_signature(JSContextRef context,
+ JSValueRef jsvalue)
+{
+ char *signature = NULL;
+
+ switch (JSValueGetType(context, jsvalue))
+ {
+ case kJSTypeBoolean:
+ {
+ signature = g_strdup(DBUS_TYPE_BOOLEAN_AS_STRING);
+ break;
+ }
+ case kJSTypeNumber:
+ {
+ /* JavaScript numbers are always doubles */
+ signature = g_strdup(DBUS_TYPE_DOUBLE_AS_STRING);
+ break;
+ }
+ case kJSTypeString:
+ {
+ signature = g_strdup(DBUS_TYPE_STRING_AS_STRING);
+ break;
+ }
+ case kJSTypeObject:
+ {
+ int i;
+ char *dict_signature = NULL;
+ JSPropertyNameArrayRef propnames;
+
+ /* Check for number types */
+ for (i = 0; i < JSCOREBUS_N_NUMBER_CLASSES; i++)
+ {
+ if (jsvalue_typeof(context, jsvalue, jscorebus_number_class_names[i]))
+ {
+ switch (jscorebus_number_class_types[i])
+ {
+#define NUMBER_SIGNATURE(t) \
+ case DBUS_TYPE_## t: \
+ signature = g_strdup(DBUS_TYPE_## t ##_AS_STRING); \
+ break;
+ NUMBER_SIGNATURE(UINT32)
+ NUMBER_SIGNATURE(INT32)
+ NUMBER_SIGNATURE(BYTE)
+ NUMBER_SIGNATURE(UINT64)
+ NUMBER_SIGNATURE(INT64)
+ NUMBER_SIGNATURE(UINT16)
+ NUMBER_SIGNATURE(INT16)
+
+ default:
+ break;
+ }
+ }
+ }
+
+ /* Check for arrays */
+ if (jsvalue_instanceof(context, jsvalue, "Array"))
+ {
+ JSPropertyNameArrayRef propnames;
+ char *array_signature;
+
+ propnames = JSObjectCopyPropertyNames(context, (JSObjectRef)jsvalue);
+ if (!jsarray_get_signature(context, jsvalue, propnames, &array_signature))
+ {
+ g_warning("Could not create array signature");
+ break;
+ }
+ signature = g_strdup_printf("a%s", array_signature);
+ g_free(array_signature);
+ break;
+ }
+
+ /* Check variants */
+ if (jsvalue_typeof(context, jsvalue, "DBusVariant"))
+ {
+ signature = g_strdup("v");
+ break;
+ }
+
+ if (jsvalue_typeof(context, jsvalue, "DBusObjectPath"))
+ {
+ signature = g_strdup(DBUS_TYPE_OBJECT_PATH_AS_STRING);
+ break;
+ }
+
+ if (jsvalue_typeof(context, jsvalue, "DBusSignature"))
+ {
+ signature = g_strdup(DBUS_TYPE_SIGNATURE_AS_STRING);
+ break;
+ }
+
+ /* Check structs */
+ if (jsvalue_typeof(context, jsvalue, "DBusStruct"))
+ {
+ JSPropertyNameArrayRef propnames;
+ JSObjectRef value = (JSObjectRef)JSObjectGetPrivate((JSObjectRef)jsvalue);
+ propnames = JSObjectCopyPropertyNames(context, value);
+ jsstruct_get_signature(context, value, propnames, &signature);
+ break;
+ }
+
+ /* Default conversion is to dict */
+ propnames = JSObjectCopyPropertyNames(context, jsvalue);
+ jsdict_get_signature(context, jsvalue, propnames, &dict_signature);
+ if (dict_signature != NULL)
+ {
+ signature = g_strdup_printf("a%s", dict_signature);
+ g_free(dict_signature);
+ }
+
+ break;
+ }
+ case kJSTypeUndefined:
+ case kJSTypeNull:
+ default:
+ g_warning("Signature lookup failed for unsupported type %i", JSValueGetType(context, jsvalue));
+ break;
+ }
+ return signature;
+}
+
+gboolean
+jsarray_get_signature(JSContextRef context,
+ JSValueRef jsvalue,
+ JSPropertyNameArrayRef propNames,
+ char **signature)
+{
+ int i, props;
+
+ *signature = NULL;
+ props = JSPropertyNameArrayGetCount(propNames);
+ /* Arrays are restricted to single complete types so we only need to look
+ * at the first property
+ */
+ if (props > 0)
+ {
+ *signature = jsvalue_to_signature(context,
+ JSObjectGetPropertyAtIndex(context, (JSObjectRef)jsvalue, 0, NULL));
+ }
+ return *signature == NULL ? FALSE : TRUE;
+}
+
+gboolean
+jsdict_get_signature(JSContextRef context,
+ JSValueRef jsvalue,
+ JSPropertyNameArrayRef propNames,
+ char **signature)
+{
+ int i, props;
+
+ *signature = NULL;
+ props = JSPropertyNameArrayGetCount(propNames);
+ /* Dicts support only string keys currently, though numbers would be another
+ * possibility...
+ */
+ if (props > 0)
+ {
+ char **signatures = g_new0(char*, 5);
+
+ signatures[0] = g_strdup(DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING);
+ signatures[1] = g_strdup(DBUS_TYPE_STRING_AS_STRING);
+ signatures[2] = jsvalue_to_signature(context,
+ JSObjectGetProperty(context, (JSObjectRef)jsvalue,
+ JSPropertyNameArrayGetNameAtIndex(propNames, 0), NULL));
+ signatures[3] = g_strdup(DBUS_DICT_ENTRY_END_CHAR_AS_STRING);
+
+ *signature = g_strjoinv(NULL, signatures);
+ g_strfreev(signatures);
+ }
+ return *signature == NULL ? FALSE : TRUE;
+}
+
+gboolean
+jsstruct_get_signature(JSContextRef context,
+ JSValueRef jsvalue,
+ JSPropertyNameArrayRef propNames,
+ char **signature)
+{
+ int props;
+
+ *signature = NULL;
+ props = JSPropertyNameArrayGetCount(propNames);
+ if (props > 0)
+ {
+ char **signatures = g_new0(char*, props + 2);
+ int i = 0;
+ signatures[i] = g_strdup(DBUS_STRUCT_BEGIN_CHAR_AS_STRING);
+ while (i < props)
+ {
+ signatures[i+1] = jsvalue_to_signature(context,
+ JSObjectGetProperty(context, (JSObjectRef)jsvalue,
+ JSPropertyNameArrayGetNameAtIndex(propNames, i++), NULL));
+ }
+ signatures[props + 1] = g_strdup(DBUS_STRUCT_END_CHAR_AS_STRING);
+
+ *signature = g_strjoinv(NULL, signatures);
+ g_strfreev(signatures);
+ }
+ return *signature == NULL ? FALSE : TRUE;
+}
+
--- /dev/null
+/**
+ * Browser D-Bus Bridge, JavaScriptCore version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ * Contact: Movial Creative Technologies Inc, <info@movial.com>
+ * Authors: Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <string.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <JavaScriptCore/JavaScript.h>
+
+#include "jscorebus-marshal.h"
+#include "jscorebus-method.h"
+#include "jscorebus-signal.h"
+
+/* Globals */
+static DBusConnection *session;
+static DBusConnection *system;
+
+
+/* Getters for the bus type properties */
+static
+JSValueRef _get_bus_type (JSContextRef context,
+ JSObjectRef object,
+ JSStringRef propertyName,
+ JSValueRef *exception)
+{
+ if (JSStringIsEqualToUTF8CString(propertyName, "SESSION"))
+ {
+ return JSValueMakeNumber(context, DBUS_BUS_SESSION);
+ }
+ if (JSStringIsEqualToUTF8CString(propertyName, "SYSTEM"))
+ {
+ return JSValueMakeNumber(context, DBUS_BUS_SYSTEM);
+ }
+
+ return JSValueMakeUndefined(context);
+}
+
+/* Static members */
+static const
+JSStaticValue dbus_jsclass_staticvalues[] =
+{
+ { "SESSION", _get_bus_type, NULL, kJSPropertyAttributeReadOnly },
+ { "SYSTEM", _get_bus_type, NULL, kJSPropertyAttributeReadOnly },
+ { NULL, NULL, NULL, 0 }
+};
+
+static
+void _number_finalize (JSObjectRef object)
+{
+ g_free(JSObjectGetPrivate(object));
+}
+
+static inline
+JSValueRef _get_number_object (JSContextRef context,
+ JSObjectRef function,
+ JSObjectRef thisObject,
+ size_t argumentCount,
+ const JSValueRef arguments[],
+ JSValueRef *exception,
+ JSClassRef number_class)
+{
+ dbus_uint64_t *value;
+
+ if (argumentCount != 1)
+ {
+ /* TODO: set exception */
+ return JSValueMakeUndefined(context);
+ }
+
+ /* dbus_uint64_t should be large enough to hold any number so we just
+ * carry the value in private data as a pointer to dbus_uint64_t.
+ * The object class tells us later which type it is.
+ */
+ value = g_new0(dbus_uint64_t, 1);
+ *value = (dbus_uint64_t)JSValueToNumber(context, arguments[0], NULL);
+
+ return JSObjectMake(context, number_class, value);
+}
+
+JSValueRef _convert_number_object(JSContextRef context,
+ JSObjectRef object,
+ JSType type,
+ JSValueRef* exception)
+{
+ /* FIXME: this isn't called at all... */
+ g_debug("%s(%p to %d)", __FUNCTION__, object, type);
+#if 0
+ switch (type)
+ {
+ case kJSTypeNumber:
+ {
+ dbus_uint64_t value = jsvalue_to_number_value(context, object, NULL);
+ return JSValueMakeNumber(context, (double)value);
+ }
+ case kJSTypeString:
+ {
+ JSValueRef jsvalue;
+ JSStringRef jsstr;
+ char *str;
+ dbus_uint64_t value = jsvalue_to_number_value(context, object, NULL);
+ str = g_strdup_printf("%llu", value);
+ jsstr = JSStringCreateWithUTF8CString(str);
+ g_free(str);
+ jsvalue = JSValueMakeString(context, jsstr);
+ JSStringRelease(jsstr);
+ return jsvalue;
+ }
+ default:
+ break;
+ }
+#endif
+ return NULL;
+}
+
+#define MAKE_NUMBER_CLASS_AND_GETTER(classname, shortname) \
+ static const JSClassDefinition shortname ##_jsclass_def = \
+ { \
+ 0, kJSClassAttributeNone, classname, \
+ NULL, NULL, NULL, NULL, _number_finalize, NULL, NULL, \
+ NULL, NULL, NULL, NULL, NULL, NULL, _convert_number_object \
+ }; \
+ \
+ static JSValueRef _get_ ##shortname (JSContextRef context, \
+ JSObjectRef function, \
+ JSObjectRef thisObject, \
+ size_t argumentCount, \
+ const JSValueRef arguments[], \
+ JSValueRef *exception) \
+ { \
+ return _get_number_object(context, function, thisObject, \
+ argumentCount, arguments, exception, \
+ (JSClassRef)jsclass_lookup(&shortname ##_jsclass_def)); \
+ }
+
+MAKE_NUMBER_CLASS_AND_GETTER("DBusUInt32", uint32)
+MAKE_NUMBER_CLASS_AND_GETTER("DBusInt32", int32)
+MAKE_NUMBER_CLASS_AND_GETTER("DBusDouble", double)
+MAKE_NUMBER_CLASS_AND_GETTER("DBusByte", byte)
+MAKE_NUMBER_CLASS_AND_GETTER("DBusUInt64", uint64)
+MAKE_NUMBER_CLASS_AND_GETTER("DBusInt64", int64)
+MAKE_NUMBER_CLASS_AND_GETTER("DBusUInt16", uint16)
+MAKE_NUMBER_CLASS_AND_GETTER("DBusInt16", int16)
+
+static const JSClassDefinition variant_jsclass_def =
+{
+ 0, kJSClassAttributeNone, "DBusVariant",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static
+JSValueRef _construct_variant (JSContextRef context,
+ JSObjectRef function,
+ JSObjectRef thisObject,
+ size_t argumentCount,
+ const JSValueRef arguments[],
+ JSValueRef *exception)
+{
+
+ if (argumentCount != 1)
+ {
+ /* TODO: set exception */
+ return JSValueMakeUndefined(context);
+ }
+
+ /* Just carry the value in private data */
+ return JSObjectMake(context, (JSClassRef)jsclass_lookup(&variant_jsclass_def), (void*)arguments[0]);
+}
+
+static const JSClassDefinition struct_jsclass_def =
+{
+ 0, kJSClassAttributeNone, "DBusStruct",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static
+JSValueRef _construct_struct (JSContextRef context,
+ JSObjectRef function,
+ JSObjectRef thisObject,
+ size_t argumentCount,
+ const JSValueRef arguments[],
+ JSValueRef *exception)
+{
+ if (argumentCount != 1)
+ {
+ /* TODO: set exception */
+ return JSValueMakeUndefined(context);
+ }
+
+ /* Just carry the object in private data */
+ return JSObjectMake(context,
+ (JSClassRef)jsclass_lookup(&struct_jsclass_def),
+ (void*)arguments[0]);
+}
+
+static const JSClassDefinition object_path_jsclass_def =
+{
+ 0, kJSClassAttributeNone, "DBusObjectPath",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static
+gboolean is_valid_path (const char *path)
+{
+ const char *this = path;
+ const char *prev = this;
+
+ if (strlen(path) == 0)
+ return FALSE;
+
+ /* MUST begin with zero */
+ if (*this++ != '/')
+ return FALSE;
+
+ /* The path is guranteed to be null-terminated */
+ while (*this != '\0')
+ {
+ /* Two slashes can't be together */
+ if (*this == '/' && *prev == '/')
+ {
+ return FALSE;
+ } else if (!(((*this) >= '0' && (*this) <= '9') ||
+ ((*this) >= 'A' && (*this) <= 'Z') ||
+ ((*this) >= 'a' && (*this) <= 'z') ||
+ (*this) == '_' || (*this) == '/')) {
+ return FALSE;
+ }
+ prev = this;
+ this++;
+ }
+
+ return TRUE;
+}
+
+static
+JSValueRef _construct_object_path (JSContextRef context,
+ JSObjectRef function,
+ JSObjectRef thisObject,
+ size_t argumentCount,
+ const JSValueRef arguments[],
+ JSValueRef *exception)
+{
+ const char *path;
+
+ if (argumentCount != 1)
+ {
+ /* TODO: set exception */
+ return JSValueMakeUndefined(context);
+ }
+
+ /* D-Bus doesn't like invalid object paths _at all_, so instead of risking
+ * disconnection, we'll validate the path now.
+ */
+ path = string_from_jsvalue(context, arguments[0]);
+ if (!is_valid_path(path))
+ {
+ g_free((gpointer)path);
+ /* TODO: set exception */
+ return JSValueMakeUndefined(context);
+ }
+ g_free((gpointer)path);
+
+ /* Just carry the value in private data */
+ return JSObjectMake(context,
+ (JSClassRef)jsclass_lookup(&object_path_jsclass_def),
+ (void*)arguments[0]);
+}
+
+static const JSClassDefinition signature_jsclass_def =
+{
+ 0, kJSClassAttributeNone, "DBusSignature",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static
+JSValueRef _construct_signature (JSContextRef context,
+ JSObjectRef function,
+ JSObjectRef thisObject,
+ size_t argumentCount,
+ const JSValueRef arguments[],
+ JSValueRef *exception)
+{
+ if (argumentCount != 1)
+ {
+ /* TODO: set exception */
+ return JSValueMakeUndefined(context);
+ }
+
+ /* Just carry the value in private data */
+ return JSObjectMake(context,
+ (JSClassRef)jsclass_lookup(&signature_jsclass_def),
+ (void*)arguments[0]);
+}
+
+static
+JSValueRef getMethod (JSContextRef context,
+ JSObjectRef function,
+ JSObjectRef thisObject,
+ size_t argumentCount,
+ const JSValueRef arguments[],
+ JSValueRef *exception)
+{
+ JSGlobalContextRef global_context = JSObjectGetPrivate(thisObject);
+
+ if (argumentCount < 4)
+ {
+ /* TODO: set exception */
+ return JSValueMakeUndefined(context);
+ }
+
+ return jscorebus_create_method(global_context,
+ JSValueToNumber(context, arguments[0], NULL)
+ == DBUS_BUS_SYSTEM ? system : session,
+ string_from_jsvalue(context, arguments[1]),
+ string_from_jsvalue(context, arguments[2]),
+ string_from_jsvalue(context, arguments[3]),
+ argumentCount > 4 ?
+ string_from_jsvalue(context, arguments[4])
+ : NULL,
+ argumentCount > 5 ?
+ string_from_jsvalue(context, arguments[5])
+ : NULL,
+ argumentCount > 6 ?
+ JSValueToObject(context, arguments[6], NULL)
+ : NULL,
+ exception);
+}
+
+static
+JSValueRef getSignal (JSContextRef context,
+ JSObjectRef function,
+ JSObjectRef thisObject,
+ size_t argumentCount,
+ const JSValueRef arguments[],
+ JSValueRef *exception)
+{
+ JSGlobalContextRef global_context = JSObjectGetPrivate(thisObject);
+
+ if (argumentCount < 3)
+ {
+ /* TODO: set exception */
+ return JSValueMakeUndefined(context);
+ }
+
+ return jscorebus_create_signal(global_context,
+ JSValueToNumber(context, arguments[0], NULL)
+ == DBUS_BUS_SYSTEM ? system : session,
+ string_from_jsvalue(context, arguments[1]),
+ string_from_jsvalue(context, arguments[2]),
+ argumentCount > 3 ?
+ string_from_jsvalue(context, arguments[3])
+ : NULL,
+ argumentCount > 4 ?
+ string_from_jsvalue(context, arguments[4])
+ : NULL,
+ argumentCount > 5 ?
+ JSValueToObject(context, arguments[5], NULL)
+ : NULL,
+ exception);
+}
+
+static
+void dbus_finalize(JSObjectRef object)
+{
+ g_debug(G_STRFUNC);
+ JSObjectSetPrivate(object, NULL);
+}
+
+static const
+JSStaticFunction dbus_jsclass_staticfuncs[] =
+{
+ /* Type constructors */
+ { "Int32", _get_int32, kJSPropertyAttributeReadOnly },
+ { "UInt32", _get_uint32, kJSPropertyAttributeReadOnly },
+ { "Double", _get_double, kJSPropertyAttributeReadOnly },
+ { "Byte", _get_byte, kJSPropertyAttributeReadOnly },
+ { "Int64", _get_int64, kJSPropertyAttributeReadOnly },
+ { "UInt64", _get_uint64, kJSPropertyAttributeReadOnly },
+ { "Int16", _get_int16, kJSPropertyAttributeReadOnly },
+ { "UInt16", _get_uint16, kJSPropertyAttributeReadOnly },
+ { "ObjectPath", _construct_object_path, kJSPropertyAttributeReadOnly },
+ { "Signature", _construct_signature, kJSPropertyAttributeReadOnly },
+ { "Variant", _construct_variant, kJSPropertyAttributeReadOnly },
+ { "Struct", _construct_struct, kJSPropertyAttributeReadOnly },
+
+ /* Methods */
+ { "getMethod", getMethod, kJSPropertyAttributeReadOnly },
+ { "getSignal", getSignal, kJSPropertyAttributeReadOnly },
+ { NULL, NULL, 0 }
+};
+
+/* The DBus Class */
+static const
+JSClassDefinition dbus_jsclass_def =
+{
+ 0,
+ kJSClassAttributeNone,
+ "DBus",
+ NULL,
+
+ dbus_jsclass_staticvalues,
+ dbus_jsclass_staticfuncs,
+
+ NULL,
+ dbus_finalize,
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+/**
+ * Public API
+ */
+
+void jscorebus_init(DBusConnection *psession, DBusConnection *psystem)
+{
+ session = psession;
+ system = psystem;
+
+#define INIT_NUMBER_CLASS(name, def, type, num) \
+ jsclassdef_insert(name, def); \
+ jscorebus_number_class_names[num] = name; \
+ jscorebus_number_class_types[num] = type;
+
+ INIT_NUMBER_CLASS("DBusInt32", &int32_jsclass_def, DBUS_TYPE_INT32, 0);
+ INIT_NUMBER_CLASS("DBusUInt32", &uint32_jsclass_def, DBUS_TYPE_UINT32, 1);
+ INIT_NUMBER_CLASS("DBusDouble", &double_jsclass_def, DBUS_TYPE_DOUBLE, 2);
+ INIT_NUMBER_CLASS("DBusByte", &byte_jsclass_def, DBUS_TYPE_BYTE, 3);
+ INIT_NUMBER_CLASS("DBusUInt64", &uint64_jsclass_def, DBUS_TYPE_UINT64, 4);
+ INIT_NUMBER_CLASS("DBusInt64", &int64_jsclass_def, DBUS_TYPE_INT64, 5);
+ INIT_NUMBER_CLASS("DBusUInt16", &uint16_jsclass_def, DBUS_TYPE_UINT16, 6);
+ INIT_NUMBER_CLASS("DBusInt16", &int16_jsclass_def, DBUS_TYPE_INT16, 7);
+
+ jsclassdef_insert("DBusObjectPath", &object_path_jsclass_def);
+ jsclassdef_insert("DBusSignature", &signature_jsclass_def);
+
+ jsclassdef_insert("DBusVariant", &variant_jsclass_def);
+ jsclassdef_insert("DBusStruct", &struct_jsclass_def);
+
+}
+
+void jscorebus_export(JSGlobalContextRef context)
+{
+ JSObjectRef globalObject;
+ JSObjectRef dbus;
+ JSStringRef jsstr;
+ JSClassRef dbus_jsclass;
+
+// global_context = context;
+
+ dbus_jsclass = JSClassCreate(&dbus_jsclass_def);
+ dbus = JSObjectMake(context, dbus_jsclass, context);
+
+ globalObject = JSContextGetGlobalObject(context);
+ jsstr = JSStringCreateWithUTF8CString("DBus");
+ JSObjectSetProperty(context, globalObject,
+ jsstr, dbus,
+ kJSPropertyAttributeNone, NULL);
+}
+
--- /dev/null
+/**
+ * Browser D-Bus Bridge, JavaScriptCore version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ * Contact: Movial Creative Technologies Inc, <info@movial.com>
+ * Authors: Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __JSCOREBUS_H___
+#define __JSCOREBUS_H___
+
+#include <dbus/dbus.h>
+#include <JavaScriptCore/JavaScript.h>
+
+/**
+ * Initialize the JSCoreBus bindings.
+ *
+ * Pass NULL if you wish to omit one of the connections.
+ */
+void jscorebus_init(DBusConnection *session, DBusConnection *system);
+
+/**
+ * Export the D-Bus object to the JavaScript execution context.
+ */
+void jscorebus_export(JSGlobalContextRef context);
+
+#endif /* __JSCOREBUS_H___ */
+
--- /dev/null
+prefix=@PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: JSCoreBus
+Description: JavaScriptCore bindings for D-Bus
+Version: 0.1
+Requires: glib-2.0 gobject-2.0 dbus-1 dbus-glib-1 webkit-1.0
+Libs: -L${libdir} -ljscorebus
+Cflags: -I${includedir}