[gjs] Add a JS GDBus convenience layer
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs] Add a JS GDBus convenience layer
- Date: Tue, 21 Jun 2011 16:35:03 +0000 (UTC)
commit b3efadd6dc05426a29c6166970e380198dc900a4
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Tue Jun 21 12:16:50 2011 -0400
Add a JS GDBus convenience layer
This only covers the proxy (client) side, for the skeleton (server)
side we still need glue code (but it is easy to generate it using
gdbus-binding-tool, for example)
https://bugzilla.gnome.org/show_bug.cgi?id=622921
modules/overrides/Gio.js | 202 +++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 201 insertions(+), 1 deletions(-)
---
diff --git a/modules/overrides/Gio.js b/modules/overrides/Gio.js
index bbb3bbe..9696c6b 100644
--- a/modules/overrides/Gio.js
+++ b/modules/overrides/Gio.js
@@ -1,2 +1,202 @@
-function _init() {
+// application/javascript;version=1.8
+// Copyright 2011 Giovanni Campagna
+//
+// 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.
+
+var GLib = imports.gi.GLib;
+var Signals = imports.signals;
+var Gio;
+
+function _signatureLength(sig) {
+ var counter = 0;
+ // make it an array
+ var signature = Array.prototype.slice.call(sig);
+ while (signature.length) {
+ GLib._read_single_type(sig);
+ counter++;
+ }
+ return counter;
}
+
+function _proxyInvoker(methodName, sync, inSignature, arg_array) {
+ var replyFunc;
+ var flags = 0;
+ var cancellable = null;
+
+ /* Convert arg_array to a *real* array */
+ arg_array = Array.prototype.slice.call(arg_array);
+
+ /* The default replyFunc only logs the responses */
+ replyFunc = _logReply;
+
+ var signatureLength = inSignature.length;
+ var minNumberArgs = signatureLength;
+ var maxNumberArgs = signatureLength + 3;
+
+ if (arg_array.length < minNumberArgs) {
+ throw new Error("Not enough arguments passed for method: " + methodName +
+ ". Expected " + minNumberArgs + ", got " + arg_array.length);
+ } else if (arg_array.length > maxNumberArgs) {
+ throw new Error("Too many arguments passed for method: " + methodName +
+ ". Maximum is " + maxNumberArgs +
+ " + one callback and/or flags");
+ }
+
+ while (arg_array.length > signatureLength) {
+ var argNum = arg_array.length - 1;
+ var arg = arg_array.pop();
+ if (typeof(arg) == "function" && !sync) {
+ replyFunc = arg;
+ } else if (typeof(arg) == "number") {
+ flags = arg;
+ } else if (arg instanceof Gio.Cancellable) {
+ cancellable = arg;
+ } else {
+ throw new Error("Argument " + argNum + " of method " + methodName +
+ " is " + typeof(arg) + ". It should be a callback, flags or a Gio.Cancellable");
+ }
+ }
+
+ var inVariant = GLib.Variant.new('(' + inSignature.join('') + ')', arg_array);
+
+ var asyncCallback = function (proxy, result) {
+ try {
+ var outVariant = proxy.call_finish(result);
+ // XXX: is deep_unpack appropriate here?
+ // (it converts everything to a JS type, except for nested Variants)
+ replyFunc(outVariant.deep_unpack(), null);
+ } catch (e) {
+ replyFunc(null, e);
+ }
+ };
+
+ if (sync) {
+ return this.call_sync(methodName,
+ inVariant,
+ flags,
+ -1,
+ cancellable).deep_unpack();
+ } else {
+ this.call_async(methodName,
+ inVariant,
+ flags,
+ -1,
+ cancellable,
+ asyncCallback);
+ }
+}
+
+function _logReply(result, exc) {
+ if (result != null) {
+ log("Ignored reply to dbus method: " + result.toSource());
+ }
+ if (exc != null) {
+ log("Ignored exception from dbus method: " + exc.toString());
+ }
+}
+
+function _makeProxyMethod(method, sync) {
+ /* JSON methods are the default */
+ var i;
+ var name = method.name;
+ var inArgs = method.in_args;
+ var inSignature = [ ];
+ for (i = 0; i < inArgs.length; i++)
+ inSignature.push(inArgs[i].signature);
+
+ return function() {
+ return _proxyInvoker.call(this, name, sync, inSignature, arguments);
+ };
+}
+
+function _convertToNativeSignal(proxy, sender_name, signal_name, parameters) {
+ Signals._emit.call(this, signal_name, sender_name, GLib.Variant.deep_unpack(paramters));
+}
+
+function _addDBusConvenience() {
+ var info = this.g_interface_info;
+ if (!info)
+ return;
+
+ if (info.signals.length > 0)
+ this.connect('g-signal', Lang.bind(this, _convertToNativeSignal));
+
+ var i, methods = info.methods;
+ for (i = 0; i < methods.length; i++) {
+ var method = methods[i];
+ this[method.name + 'Remote'] = _makeProxyMethod(methods[i], false);
+ this[method.name + 'Sync'] = _makeProxyMethod(methods[i], true);
+ }
+}
+
+function _injectToMethod(klass, method, addition) {
+ var previous = klass[method];
+
+ klass[method] = function() {
+ addition.apply(this, arguments);
+ return previous.apply(this, arguments);
+ }
+}
+
+ function __init__() {
+ Gio = this;
+
+ Gio.DBus = {
+ get session() {
+ return Gio.bus_get_sync(Gio.BusType.SESSION, null);
+ },
+ get system() {
+ return Gio.bus_get_sync(Gio.BusType.SYSTEM, null);
+ },
+
+ // Namespace some functions
+ get: Gio.bus_get,
+ get_finish: Gio.bus_get_finish,
+ get_sync: Gio.bus_get_sync,
+
+ own_name: Gio.bus_own_name,
+ own_name_on_connection: Gio.bus_own_name_on_connection,
+ unown_name: Gio.bus_unown_name,
+
+ watch_name: Gio.bus_watch_name,
+ watch_name_on_connection: Gio.bus_watch_name_on_connection,
+ unwatch_name: Gio.bus_unwatch_name,
+ };
+
+ // Some helpers to support current style (like DBus.system.watch_name)
+ Gio.DBusConnection.prototype.watch_name = function(name, flags, appeared, vanished) {
+ return Gio.bus_watch_name_on_connection(this, name, flags, appeared, vanished);
+ };
+ Gio.DBusConnection.prototype.unwatch_name = function(id) {
+ return Gio.bus_unwatch_name(id);
+ };
+ Gio.DBusConnection.prototype.own_name = function(name, flags, acquired, lost) {
+ return Gio.bus_own_name_on_connection(this, name, flags, acquired, lost);
+ };
+ Gio.DBusConnection.prototype.unown_name = function(id) {
+ return Gio.unown_name(id);
+ };
+
+ // This should be done inside a constructor, but it cannot currently
+
+ _injectToMethod(Gio.DBusProxy.prototype, 'init', _addDBusConvenience);
+ _injectToMethod(Gio.DBusProxy.prototype, 'async_init', _addDBusConvenience);
+ Gio.DBusProxy.prototype.connectSignal = Signals._connect;
+ Gio.DBusProxy.prototype.disconnectSignal = Signals._disconnect;
+ }
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]