2 * Browser D-Bus Bridge, JavaScriptCore version
4 * Copyright © 2008 Movial Creative Technologies Inc
5 * Contact: Movial Creative Technologies Inc, <info@movial.com>
6 * Authors: Kalle Vahlman, <kalle.vahlman@movial.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
24 #include <dbus/dbus.h>
25 #include <JavaScriptCore/JavaScript.h>
27 #include "jscorebus-marshal.h"
28 #include "jscorebus-method.h"
30 /* Private data for methods */
31 typedef struct _MethodPrivate
39 DBusConnection *connection;
41 DBusPendingCall *pending_reply;
43 JSGlobalContextRef context;
50 /* Utility functions */
52 JSClassRef get_class ();
55 JSValueRef call_sync(JSContextRef context, MethodPrivate *priv);
57 JSValueRef call_async(JSContextRef context, MethodPrivate *priv);
59 void call_onreply(JSContextRef context,
61 DBusMessage *message);
63 void call_onerror(JSContextRef context,
65 DBusMessage *message);
69 void method_finalize(JSObjectRef object);
72 bool method_set_property(JSContextRef context,
74 JSStringRef propertyName,
76 JSValueRef* exception);
79 JSValueRef method_call (JSContextRef context,
81 JSObjectRef thisObject,
83 const JSValueRef arguments[],
84 JSValueRef *exception);
86 /* The Method Class */
88 JSClassDefinition method_jsclass_def =
91 kJSClassAttributeNone,
98 NULL, /* Initialize */
103 method_set_property, /* SetProperty */
107 method_call, /* CallAsFunction */
108 NULL, /* Constructor */
113 /*** JSCore methods */
116 void method_finalize(JSObjectRef object)
118 MethodPrivate *priv = (MethodPrivate *)JSObjectGetPrivate(object);
123 if (priv->pending_reply != NULL)
125 dbus_pending_call_cancel(priv->pending_reply);
128 g_free(priv->destination);
129 g_free(priv->object_path);
130 g_free(priv->method_name);
131 g_free(priv->interface);
132 g_free(priv->signature);
134 dbus_connection_unref(priv->connection);
137 priv->onreply = NULL;
138 priv->onerror = NULL;
139 priv->context = NULL;
147 bool method_set_property(JSContextRef context,
149 JSStringRef propertyName,
151 JSValueRef* exception)
155 priv = (MethodPrivate *)JSObjectGetPrivate(object);
156 g_assert(priv != NULL);
158 if (JSStringIsEqualToUTF8CString(propertyName, "async"))
160 if (JSValueIsBoolean(context, value))
162 priv->async = JSValueToBoolean(context, value);
166 /* TODO: set exception */
167 g_warning("Tried to set a non-boolean to 'async'");
169 } else if (JSStringIsEqualToUTF8CString(propertyName, "onreply")) {
170 priv->onreply = function_from_jsvalue(context, value, exception);
172 } else if (JSStringIsEqualToUTF8CString(propertyName, "onerror")) {
173 priv->onerror = function_from_jsvalue(context, value, exception);
181 JSValueRef method_call (JSContextRef context,
182 JSObjectRef function,
183 JSObjectRef thisObject,
184 size_t argumentCount,
185 const JSValueRef arguments[],
186 JSValueRef *exception)
190 DBusMessageIter iter;
193 priv = (MethodPrivate *)JSObjectGetPrivate(function);
194 g_assert(priv != NULL);
196 priv->message = dbus_message_new_method_call(priv->destination,
201 if (argumentCount > 0)
203 /* Push arguments to the message */
204 dbus_message_iter_init_append (priv->message, &iter);
205 if (!jsvalue_array_append_to_message_iter(context,
206 arguments, argumentCount,
207 &iter, priv->signature))
209 dbus_message_unref(priv->message);
210 priv->message = NULL;
216 ret = call_async(context, priv);
218 ret = call_sync(context, priv);
221 if (priv->message != NULL)
223 dbus_message_unref(priv->message);
225 priv->message = NULL;
230 /*** Utility functions */
233 JSClassRef get_class ()
235 JSClassRef jsclass = (JSClassRef)jsclass_lookup(&method_jsclass_def);
237 if (G_LIKELY(jsclass != NULL))
242 jsclassdef_insert("DBusMethod", &method_jsclass_def);
243 jsclass = (JSClassRef)jsclass_lookup(&method_jsclass_def);
245 g_assert(jsclass != NULL);
251 JSValueRef call_sync(JSContextRef context, MethodPrivate *priv)
254 * Set up reply callback from the method.onReply property if available and
258 if (priv->message == NULL)
260 call_onerror(context, priv, NULL);
261 return JSValueMakeUndefined(context);
264 if (priv->onreply != NULL)
266 DBusMessage *reply_message;
268 reply_message = dbus_connection_send_with_reply_and_block(
270 priv->message, -1, NULL);
271 if (reply_message != NULL)
273 if (dbus_message_get_type(reply_message) == DBUS_MESSAGE_TYPE_ERROR)
275 call_onerror(context, priv, reply_message);
276 } else if (dbus_message_get_type(reply_message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) {
277 call_onreply(context, priv, reply_message);
279 g_warning("Unknown reply!");
281 dbus_message_unref(reply_message);
283 // TODO: set exception
284 g_warning("Failed to send message to %s", priv->destination);
285 call_onerror(context, priv, NULL);
288 if (!dbus_connection_send(priv->connection, priv->message, NULL))
290 // TODO: set exception
291 g_warning("Failed to send message to %s", priv->destination);
292 call_onerror(context, priv, NULL);
296 return JSValueMakeUndefined(context);
300 void pending_call_notify(DBusPendingCall *pending,
303 DBusMessage *reply_message;
306 g_assert(user_data != NULL);
308 priv = (MethodPrivate *)user_data;
313 * TODO: How do we handle these?
315 g_warning("Disconnected from the bus!");
316 priv->pending_reply = NULL;
320 priv->pending_reply = NULL;
321 reply_message = dbus_pending_call_steal_reply(pending);
323 if (dbus_message_get_type(reply_message) == DBUS_MESSAGE_TYPE_ERROR)
325 call_onerror(priv->context, priv, reply_message);
326 } else if (dbus_message_get_type(reply_message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) {
327 call_onreply(priv->context, priv, reply_message);
329 g_warning("Unknown reply!");
331 if (reply_message != NULL)
333 dbus_message_unref(reply_message);
338 JSValueRef call_async(JSContextRef context, MethodPrivate *priv)
340 dbus_uint32_t serial = 0;
342 if (priv->message == NULL)
344 call_onerror(context, priv, NULL);
347 if (priv->onreply != NULL)
349 if (dbus_connection_send_with_reply(
351 priv->message, &priv->pending_reply, -1))
353 dbus_pending_call_set_notify(priv->pending_reply, pending_call_notify,
356 // TODO: set exception
357 call_onerror(context, priv, NULL);
360 dbus_message_set_no_reply(priv->message, TRUE);
362 if (!dbus_connection_send(priv->connection, priv->message, &serial))
364 // TODO: set exception
365 call_onerror(context, priv, NULL);
369 return JSValueMakeUndefined(context);
373 void call_onreply(JSContextRef context,
375 DBusMessage *message)
377 if (priv->onreply == NULL)
382 call_function_with_message_args(context, priv->this, priv->onreply, message);
386 void call_onerror(JSContextRef context,
388 DBusMessage *message)
390 if (priv->onerror == NULL)
397 /* We couldn't send the message */
398 JSStringRef name = JSStringCreateWithUTF8CString("MessageError");
399 JSStringRef str = JSStringCreateWithUTF8CString("Could not send message");
400 JSValueRef *args = g_new(JSValueRef, 2);
402 args[0] = JSValueMakeString(context, name);
403 args[1] = JSValueMakeString(context, str);
405 JSObjectCallAsFunction(context, priv->onerror, priv->this,
407 JSStringRelease(name);
408 JSStringRelease(str);
413 call_function_with_message_args(context, priv->this, priv->onerror, message);
418 /* NOTE: Takes ownership of the arguments! */
419 JSObjectRef jscorebus_create_method (JSGlobalContextRef context,
420 DBusConnection *connection,
426 JSObjectRef thisObject,
427 JSValueRef* exception)
429 MethodPrivate *priv = NULL;
431 g_return_val_if_fail(destination != NULL
432 && object_path != NULL
433 && method_name != NULL,
436 priv = g_new0(MethodPrivate, 1);
438 /* TODO: Maybe these should be JSStrings after all, to avoid copies? */
439 priv->destination = destination;
440 priv->object_path = object_path;
441 priv->method_name = method_name;
443 priv->interface = interface;
444 priv->signature = signature;
448 priv->connection = dbus_connection_ref(connection);
450 priv->context = context;
452 priv->this = thisObject;
454 return JSObjectMake(context, get_class(), priv);