From 85baaf4293b6ca50be9a278668e3e75668c3f1cc Mon Sep 17 00:00:00 2001 From: Kalle Vahlman Date: Mon, 3 Nov 2008 15:04:20 +0200 Subject: [PATCH] Import the WebKit version --- jscorebus/build.mk | 20 + jscorebus/jscorebus-classfactory.c | 80 ++++ jscorebus/jscorebus-classfactory.h | 40 ++ jscorebus/jscorebus-marshal.c | 673 +++++++++++++++++++++++++++++ jscorebus/jscorebus-marshal.h | 94 ++++ jscorebus/jscorebus-method.c | 452 +++++++++++++++++++ jscorebus/jscorebus-method.h | 41 ++ jscorebus/jscorebus-signal.c | 369 ++++++++++++++++ jscorebus/jscorebus-signal.h | 40 ++ jscorebus/jscorebus-signature.c | 263 +++++++++++ jscorebus/jscorebus.c | 490 +++++++++++++++++++++ jscorebus/jscorebus.h | 42 ++ jscorebus/jscorebus.pc | 11 + 13 files changed, 2615 insertions(+) create mode 100644 jscorebus/build.mk create mode 100644 jscorebus/jscorebus-classfactory.c create mode 100644 jscorebus/jscorebus-classfactory.h create mode 100644 jscorebus/jscorebus-marshal.c create mode 100644 jscorebus/jscorebus-marshal.h create mode 100644 jscorebus/jscorebus-method.c create mode 100644 jscorebus/jscorebus-method.h create mode 100644 jscorebus/jscorebus-signal.c create mode 100644 jscorebus/jscorebus-signal.h create mode 100644 jscorebus/jscorebus-signature.c create mode 100644 jscorebus/jscorebus.c create mode 100644 jscorebus/jscorebus.h create mode 100644 jscorebus/jscorebus.pc diff --git a/jscorebus/build.mk b/jscorebus/build.mk new file mode 100644 index 0000000..6edbdde --- /dev/null +++ b/jscorebus/build.mk @@ -0,0 +1,20 @@ +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 diff --git a/jscorebus/jscorebus-classfactory.c b/jscorebus/jscorebus-classfactory.c new file mode 100644 index 0000000..812eca8 --- /dev/null +++ b/jscorebus/jscorebus-classfactory.c @@ -0,0 +1,80 @@ +/** + * Browser D-Bus Bridge, JavaScriptCore version + * + * Copyright © 2008 Movial Creative Technologies Inc + * Contact: Movial Creative Technologies Inc, + * Authors: Kalle Vahlman, + * + * 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 . + * + */ + +#include +#include + +#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; +} + diff --git a/jscorebus/jscorebus-classfactory.h b/jscorebus/jscorebus-classfactory.h new file mode 100644 index 0000000..e36aa95 --- /dev/null +++ b/jscorebus/jscorebus-classfactory.h @@ -0,0 +1,40 @@ +/** + * Browser D-Bus Bridge, JavaScriptCore version + * + * Copyright © 2008 Movial Creative Technologies Inc + * Contact: Movial Creative Technologies Inc, + * Authors: Kalle Vahlman, + * + * 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 . + * + */ + +#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___ */ + diff --git a/jscorebus/jscorebus-marshal.c b/jscorebus/jscorebus-marshal.c new file mode 100644 index 0000000..b2c3600 --- /dev/null +++ b/jscorebus/jscorebus-marshal.c @@ -0,0 +1,673 @@ +/** + * Browser D-Bus Bridge, JavaScriptCore version + * + * Copyright © 2008 Movial Creative Technologies Inc + * Contact: Movial Creative Technologies Inc, + * Authors: Kalle Vahlman, + * + * 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 . + * + */ + +#include + +#include +#include +#include + +#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); +} + diff --git a/jscorebus/jscorebus-marshal.h b/jscorebus/jscorebus-marshal.h new file mode 100644 index 0000000..51622fc --- /dev/null +++ b/jscorebus/jscorebus-marshal.h @@ -0,0 +1,94 @@ +/** + * Browser D-Bus Bridge, JavaScriptCore version + * + * Copyright © 2008 Movial Creative Technologies Inc + * Contact: Movial Creative Technologies Inc, + * Authors: Kalle Vahlman, + * + * 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 . + * + */ + +/* Functions to convert between D-Bus types and JSCore types */ + +#ifndef __JSCOREBUS_CONVERT_H___ +#define __JSCOREBUS_CONVERT_H___ + +#include +#include + +/* 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___ */ + diff --git a/jscorebus/jscorebus-method.c b/jscorebus/jscorebus-method.c new file mode 100644 index 0000000..892ad88 --- /dev/null +++ b/jscorebus/jscorebus-method.c @@ -0,0 +1,452 @@ +/** + * Browser D-Bus Bridge, JavaScriptCore version + * + * Copyright © 2008 Movial Creative Technologies Inc + * Contact: Movial Creative Technologies Inc, + * Authors: Kalle Vahlman, + * + * 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 . + * + */ + +#include +#include +#include + +#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); +} diff --git a/jscorebus/jscorebus-method.h b/jscorebus/jscorebus-method.h new file mode 100644 index 0000000..fc0da1f --- /dev/null +++ b/jscorebus/jscorebus-method.h @@ -0,0 +1,41 @@ +/** + * Browser D-Bus Bridge, JavaScriptCore version + * + * Copyright © 2008 Movial Creative Technologies Inc + * Contact: Movial Creative Technologies Inc, + * Authors: Kalle Vahlman, + * + * 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 . + * + */ + +#ifndef __JSCOREBUS_METHOD_H__ +#define __JSCOREBUS_METHOD_H__ + +#include +#include + +/* 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__ */ + diff --git a/jscorebus/jscorebus-signal.c b/jscorebus/jscorebus-signal.c new file mode 100644 index 0000000..31e6561 --- /dev/null +++ b/jscorebus/jscorebus-signal.c @@ -0,0 +1,369 @@ +/** + * Browser D-Bus Bridge, JavaScriptCore version + * + * Copyright © 2008 Movial Creative Technologies Inc + * Contact: Movial Creative Technologies Inc, + * Authors: Kalle Vahlman, + * + * 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 . + * + */ + +#include +#include +#include + +#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); +} + diff --git a/jscorebus/jscorebus-signal.h b/jscorebus/jscorebus-signal.h new file mode 100644 index 0000000..c0289b1 --- /dev/null +++ b/jscorebus/jscorebus-signal.h @@ -0,0 +1,40 @@ +/** + * Browser D-Bus Bridge, JavaScriptCore version + * + * Copyright © 2008 Movial Creative Technologies Inc + * Contact: Movial Creative Technologies Inc, + * Authors: Kalle Vahlman, + * + * 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 . + * + */ + +#ifndef __JSCOREBUS_SIGNAL_H__ +#define __JSCOREBUS_SIGNAL_H__ + +#include +#include + +/* 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__ */ + diff --git a/jscorebus/jscorebus-signature.c b/jscorebus/jscorebus-signature.c new file mode 100644 index 0000000..5acdf29 --- /dev/null +++ b/jscorebus/jscorebus-signature.c @@ -0,0 +1,263 @@ +/** + * Browser D-Bus Bridge, JavaScriptCore version + * + * Copyright © 2008 Movial Creative Technologies Inc + * Contact: Movial Creative Technologies Inc, + * Authors: Kalle Vahlman, + * + * 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 . + * + */ + +#include +#include +#include + +#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; +} + diff --git a/jscorebus/jscorebus.c b/jscorebus/jscorebus.c new file mode 100644 index 0000000..a1e38b7 --- /dev/null +++ b/jscorebus/jscorebus.c @@ -0,0 +1,490 @@ +/** + * Browser D-Bus Bridge, JavaScriptCore version + * + * Copyright © 2008 Movial Creative Technologies Inc + * Contact: Movial Creative Technologies Inc, + * Authors: Kalle Vahlman, + * + * 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 . + * + */ + +#include + +#include +#include +#include + +#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); +} + diff --git a/jscorebus/jscorebus.h b/jscorebus/jscorebus.h new file mode 100644 index 0000000..d1c8806 --- /dev/null +++ b/jscorebus/jscorebus.h @@ -0,0 +1,42 @@ +/** + * Browser D-Bus Bridge, JavaScriptCore version + * + * Copyright © 2008 Movial Creative Technologies Inc + * Contact: Movial Creative Technologies Inc, + * Authors: Kalle Vahlman, + * + * 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 . + * + */ + +#ifndef __JSCOREBUS_H___ +#define __JSCOREBUS_H___ + +#include +#include + +/** + * 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___ */ + diff --git a/jscorebus/jscorebus.pc b/jscorebus/jscorebus.pc new file mode 100644 index 0000000..d7a114e --- /dev/null +++ b/jscorebus/jscorebus.pc @@ -0,0 +1,11 @@ +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} -- 2.25.1