[html] Restructure JS wrapper, 'DBus' is now a constructor and the
authorKalle Vahlman <kalle.vahlman@movial.com>
Mon, 20 Apr 2009 06:32:03 +0000 (09:32 +0300)
committerKalle Vahlman <kalle.vahlman@movial.com>
Mon, 20 Apr 2009 06:35:05 +0000 (09:35 +0300)
namespace is lowercased. Add introspection support through the
DBus.getInterface() method.

html/DBus.js [deleted file]
html/dbus.js [new file with mode: 0644]

diff --git a/html/DBus.js b/html/DBus.js
deleted file mode 100644 (file)
index 8d92bcd..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/* 
- * DBus.js, a JS wrapper for the Browser D-Bus Bridge
- * Copyright © 2008 Movial Creative Technologies Inc
- *
- * Contact: Movial Creative Technologies Inc, <info@movial.com>
- * Authors: Lauri Mylläri, <lauri.myllari@movial.fi>
- *          Kalle Vahlman, <kalle.vahlman@movial.com>
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following
- * conditions:
- * 
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE. 
- */
-if (!window.DBus)
-{
-function unWrap(method, user_data) {
-  return function() {
-    if (method)
-      method.apply(user_data, arguments[0]);
-  }
-}
-
-function makeVariantMaker(variant_type) {
-  var ret = function(val) {
-    dump("make " + variant_type + " from " + val + "\n");
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var variant = Components.classes["@mozilla.org/variant;1"].createInstance(Components.interfaces.nsIWritableVariant);
-    variant['setAs' + variant_type](val);
-    dump("made " + variant.QueryInterface(Components.interfaces.nsIVariant) + " from " + variant_type + " " + val + "\n");
-    return variant;
-  };
-  return ret;
-}
-
-function DBusWrapper() {
-  dump("DBusWrapper() enter\n");
-
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  this.dbus = Components.classes["@movial.fi/dbus/service;1"].getService();
-  this.dbus = this.dbus.QueryInterface(Components.interfaces.IDBusService);
-  dump("this.dbus: " + this.dbus + "\n");
-
-  this.SYSTEM = this.dbus.SYSTEM;
-  this.SESSION = this.dbus.SESSION;
-
-  var types = {
-    Int32:  "Int32",
-    UInt32: "Uint32",
-    Int16:  "Int16",
-    UInt16: "Uint16",
-    Int64:  "Int64",
-    UInt64: "Uint64",
-    Double: "Double",
-    Byte:   "Int8"
-  };
-
-  /* TODO: These need their own XPCOM types/handling:
-       - ObjectPath
-       - Signature
-       - Variant?
-       - Struct?
-   */
-
-  for (var type in types) {
-    this[type] = makeVariantMaker(types[type]);
-  }
-
-  this.getMethod = function(bustype,
-                            destination,
-                            object_path,
-                            method_name,
-                            interface,
-                            signature,
-                            user_data) {
-    dump("DBusWrapper.getMethod() enter\n");
-    dump("  bustype: " + bustype + "\n");
-    dump("  destination: " + destination + "\n");
-    dump("  object_path: " + object_path + "\n");
-    dump("  method_name: " + method_name + "\n");
-    dump("  interface: " + interface + "\n");
-    dump("  signature: " + signature + "\n");
-    var method = function() {
-      dump("DBusMethod.call()\n");
-      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-      method.dbusmethod.doCall(Array.prototype.slice.call(arguments),
-                               arguments.length);
-    }
-    method.user_data = user_data;
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    method.dbusmethod = this.dbus.getMethod(bustype,
-                                            destination,
-                                            object_path,
-                                            method_name,
-                                            interface,
-                                            signature);
-    method.dbusmethod.onReply = unWrap(method.onreply, method.user_data);
-    method.dbusmethod.onError = unWrap(method.onerror, method.user_data);
-
-    method.watch("onreply", function(id, oldval, newval) {
-                              netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-                              method.dbusmethod.onReply = unWrap(newval, method.user_data);
-                            });
-    method.watch("onerror", function(id, oldval, newval) {
-                              netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-                              method.dbusmethod.onError = unWrap(newval, method.user_data);
-                            });
-
-    method.async = true;
-    method.watch("async", function(id, oldval, newval) {
-                            netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-                            method.dbusmethod.async = newval;
-                          });
-    dump("DBusWrapper.getMethod() leave\n");
-    return method;
-  }
-
-  this.getSignal = function(bustype,
-                            interface,
-                            signal_name,
-                            sender,
-                            object_path,
-                            user_data) {
-    dump("DBusWrapper.getSignal() enter\n");
-    dump("  bustype: " + bustype + "\n");
-    dump("  interface: " + interface + "\n");
-    dump("  signal_name: " + signal_name + "\n");
-    dump("  sender: " + sender + "\n");
-    dump("  object_path: " + object_path + "\n");
-
-    var signal = {};
-
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    signal.dbussignal = this.dbus.getSignal(bustype,
-                                            interface,
-                                            signal_name,
-                                            sender,
-                                            object_path);
-    signal.user_data = user_data;
-
-    signal.dbussignal.onEmit = unWrap(signal.onemit, signal.user_data);
-    signal.watch("onemit", function(id, oldval, newval) {
-                             netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-                             signal.dbussignal.onEmit = unWrap(newval, signal.user_data);
-                           });
-
-    signal.enabled = false;
-    signal.watch("enabled", function(id, oldval, newval) {
-                              netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-                              signal.dbussignal.enabled = newval;
-                            });
-
-    dump("DBusWrapper.getSignal() leave\n");
-    return signal;
-  }
-
-  this.emitSignal = function() {
-    var args = new Array();
-    for (var i = 0; i < arguments.length; i++)
-    {
-      if (i < 5)
-        continue;
-      args[i - 5] = arguments[i];
-    }
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    this.dbus.emitSignal(arguments[0], arguments[1],
-                         arguments[2], arguments[3],
-                         arguments[4], args, args.length);
- };
-
-  dump("DBusWrapper() leave\n");
-}
-
-window.DBus = new DBusWrapper();
-
-}xa
diff --git a/html/dbus.js b/html/dbus.js
new file mode 100644 (file)
index 0000000..72564b9
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * DBus.js, a JS wrapper for the Browser D-Bus Bridge
+ * Copyright (c) 2008-2009  Movial Creative Technologies Inc
+ *
+ * Contact: Movial Creative Technologies Inc, <info@movial.com>
+ * Authors: Lauri Mylläri, <lauri.myllari@movial.fi>
+ *          Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+if (!window.DBus)
+{
+    /* This is the Gecko wrapping for the Browser D-Bus Bridge API
+     * You can use the XPCOM API directly, but the Bridge API
+     *  - is easier to use
+     *  - has few utility features over the "raw" API (like introspection)
+     *  - generally feels a bit more JavaScriptish (hopefully)
+     */
+
+    /* For readability */
+    var ep = netscape.security.PrivilegeManager.enablePrivilege;
+    ep("UniversalXPConnect");
+    var cc = Components.classes;
+    var ci = Components.interfaces;
+
+    /* Utility function that creates a wrapper function which handles signature
+     * conversion from wrapper(argarray) to method(arg1, ..., argN) and sets
+     * 'this' to point to the user-specified object. This is mainly used to
+     * convert the variant arrays from the XPCOM service to callback arguments.
+     */
+    var unWrap = function(method, user_data) {
+        return function() {
+            if (method){
+                method.apply(user_data, arguments[0]);
+            }
+        };
+    };
+
+    var makeVariantMaker = function(variant_type) {
+        return function(val) {
+            ep("UniversalXPConnect");
+            var variant = cc["@mozilla.org/variant;1"].createInstance(ci.nsIWritableVariant);
+            variant['setAs' + variant_type](val);
+            return variant;
+        };
+        return ret;
+    };
+
+    // Bridge API: The DBus singleton class
+    window.DBus = function() {
+
+        ep("UniversalXPConnect");
+        this.dbus = cc["@movial.fi/dbus/service;1"].getService();
+        this.dbus = this.dbus.QueryInterface(Components.interfaces.IDBusService);
+
+        // Mirror static properties
+        this.SYSTEM = this.dbus.SYSTEM;
+        this.SESSION = this.dbus.SESSION;
+
+        // Bridge API: DBus.[some type]()
+        // These are types we can wrap to variants directly for the
+        // DBus.Int32() etc conversion methods
+        var types = {
+            Int32:  "Int32",
+            UInt32: "Uint32",
+            Int16:  "Int16",
+            UInt16: "Uint16",
+            Int64:  "Int64",
+            UInt64: "Uint64",
+            Double: "Double",
+            Byte:   "Int8"
+        };
+
+        for (var type in types) {
+            if(type !== null ){
+                this[type] = makeVariantMaker(types[type]);
+            }
+        }
+
+        /* TODO: These need their own XPCOM types/handling:
+       - ObjectPath
+       - Signature
+       - Variant?
+       - Struct?
+         */
+
+    };
+
+    // Bridge API: dbus.getMethod()
+    window.DBus.prototype.getMethod = function(bustype,
+                                               destination,
+                                               object_path,
+                                               method_name,
+                                               interface,
+                                               signature,
+                                               user_data) {
+
+        /* A wrapper function for method calls
+         * Executes the actual call through the XPCOM interface
+         */
+        var method = function() {
+            ep("UniversalXPConnect");
+            // FIXME: Is the copy really necessary? Why?
+            method.dbusmethod.doCall(Array.prototype.slice.call(arguments),
+            arguments.length);
+
+        };
+
+        // Store the user specified "this" object
+        method.user_data = user_data;
+
+        // Create the XPCOM method object
+        ep("UniversalXPConnect");
+        method.dbusmethod = this.dbus.getMethod(bustype,
+                                                destination,
+                                                object_path,
+                                                method_name,
+                                                interface,
+                                                signature);
+
+        /* XXX: Hmm? onreply and onerror are undefined here, no? */
+        method.dbusmethod.onReply = unWrap(method.onreply, method.user_data);
+        method.dbusmethod.onError = unWrap(method.onerror, method.user_data);
+
+        // Watch the onreply property and assign the callback through our
+        // wrapper
+        method.watch("onreply", function(id, oldval, newval) {
+            ep("UniversalXPConnect");
+            method.dbusmethod.onReply = unWrap(newval, method.user_data);
+        });
+
+        // Ditto for onerror
+        method.watch("onerror", function(id, oldval, newval) {
+            ep("UniversalXPConnect");
+            method.dbusmethod.onError = unWrap(newval, method.user_data);
+        });
+
+        // Mirror the async property
+        method.async = true;
+        method.watch("async", function(id, oldval, newval) {
+            ep("UniversalXPConnect");
+            method.dbusmethod.async = newval;
+        });
+
+        return method;
+    };
+
+    // Bridge API: dbus.getSignal()
+    window.DBus.prototype.getSignal = function(bustype,
+                                        interface,
+                                        signal_name,
+                                        sender,
+                                        object_path,
+                                        user_data) {
+        var signal = {};
+
+        // Create the XPCOM signal object
+        ep("UniversalXPConnect");
+        signal.dbussignal = this.dbus.getSignal(bustype,
+                                                interface,
+                                                signal_name,
+                                                sender,
+                                                object_path);
+
+        // Store user-specified "this" for callbacks
+        signal.user_data = user_data;
+
+        // XXX: ummm.... onemit == undefined?
+        signal.dbussignal.onEmit = unWrap(signal.onemit, signal.user_data);
+
+        // Watch the onemit property for wrapping
+        signal.watch("onemit", function(id, oldval, newval) {
+            ep("UniversalXPConnect");
+            signal.dbussignal.onEmit = unWrap(newval, signal.user_data);
+        });
+
+        // Watch the enabled property for wrapping
+        signal.enabled = false;
+        signal.watch("enabled", function(id, oldval, newval) {
+            ep("UniversalXPConnect");
+            signal.dbussignal.enabled = newval;
+        });
+
+        return signal;
+    };
+
+    // Bridge API: dbus.emitSignal()
+    window.DBus.prototype.emitSignal = function() {
+        var args = arguments.splice(5);
+        ep("UniversalXPConnect");
+        this.dbus.emitSignal(arguments[0], arguments[1],
+                             arguments[2], arguments[3],
+                             arguments[4], args, args.length);
+    };
+
+}
+
+// Instantiate the Bridge API singleton
+try {
+  window.dbus = new window.DBus();
+} catch (e) {
+  window.dbus = null;
+}
+
+/**
+ *  @private
+ */
+
+DBus.prototype.parseInterface = function(doc, dest, path, inter){
+    var ret = {};
+    var temp = doc.getElementsByTagName("interface");
+    //interesting interface is last
+    for( var i = temp.length - 1; i >=0; i--){
+        if( temp[i].getAttribute("name") != inter ) { continue; }
+        //method name
+        var methods = temp[i].getElementsByTagName("method");
+        for ( var j = 0, jl = methods.length; j < jl; j ++){
+            var name = methods[j].getAttribute("name");
+            //params
+            var args = methods[j].getElementsByTagName("arg");
+            var type = [];
+
+            for( var z = 0, zl = args.length; z < zl; z ++){
+
+                if(  args[z].getAttribute("direction") == "in"){
+                    type.push(args[z].getAttribute("type") );
+                }
+
+            }
+            ret[name] = dbus.getMethod(window.DBus.SESSION, dest, path,
+                                       name, inter, type.join(""), ret );
+        }
+
+        //signals
+        var signals = temp[i].getElementsByTagName("signal");
+        for ( var j = 0, jl = signals.length; j < jl; j ++){
+            name = signals[j].getAttribute("name");
+            ret[name] = dbus.getSignal(window.DBus.SESSION,
+                                       inter, name, null,
+                                       this.object_path, ret);
+            ret[name].enabled = false;
+            ret[name].onemit = null;
+        }
+        ret.xml = (new XMLSerializer()).serializeToString(doc);
+        return ret;
+        // break; //interface found
+    }
+};
+
+/**
+    *  @constructor
+    *  @class This method uses the <code>Introspect</code> method on the standard
+    *  <code>org.freedesktop.DBus.Introspectable</code> interface to map a given
+    *  D-Bus interface to a JavaScript object. The produced object works as
+    *  <code>this</code> in all its methods.<br/> Note that introspecting is
+    *  not done asynchronously so the function call will block until the service
+    *  responds.
+    *  <br/>
+    *  for example:<br/>
+    *  <code>
+    *  var myinterface = DBus.getInterface( mydest, mypath, myinterface);<br/>
+    *  var myname = "";<br/>
+    *  myinterface.getName.onreply = function(name){<br/>
+    *  &nbsp;&nbsp;myname = name;<br/>
+    *  };<br/>
+    *  myinterface.getName.onerror = function(message){<br/>
+    *  &nbsp;&nbsp;alert('name getting failed:'+message );<br/>
+    *  };<br/>
+    *  myinterface.getName( me );<br/>
+    *  </code>
+    *  @param dest {String} destination
+    *  @param path {String} object path
+    *  @param inter {String} interface
+    */
+DBus.prototype.getInterface = function(dest, path, inter){
+    var doc = null;
+    var introspect = dbus.getMethod(dbus.SESSION, dest, path,
+                                    "Introspect",
+                                    "org.freedesktop.DBus.Introspectable" );
+    introspect.onreply = function(s){
+        doc = s.replace(/^\s*|\s*$/g,"");
+    };
+    introspect.onerror = function(s){
+        doc = null;
+    };
+    introspect.async = false;
+    introspect();
+
+    if (doc === null) {
+        return null;
+    }
+
+    doc = (new DOMParser()).parseFromString(doc, "text/xml");
+
+    return this.parseInterface(doc, dest, path, inter);
+};