diff options
author | portix <none@none> | 2013-03-19 01:05:10 +0100 |
---|---|---|
committer | portix <none@none> | 2013-03-19 01:05:10 +0100 |
commit | 34a5c436db3271c72f91cf0f028c934d6474c902 (patch) | |
tree | 184218d2dcb9adaddd52f857fb386f3b5f944825 | |
parent | f98991177a2c21acfe737d9180ce6e18fa924ffa (diff) | |
download | dwb-34a5c436db3271c72f91cf0f028c934d6474c902.zip |
New Signal api
-rw-r--r-- | extensions/perdomainsettings | 4 | ||||
-rw-r--r-- | extensions/requestpolicy | 31 | ||||
-rw-r--r-- | extensions/unique_tabs | 28 | ||||
-rw-r--r-- | extensions/userscripts | 8 | ||||
-rw-r--r-- | scripts/lib/dwb.js | 20 | ||||
-rw-r--r-- | scripts/lib/signals.js | 653 | ||||
-rw-r--r-- | src/scripts.c | 58 |
7 files changed, 548 insertions, 254 deletions
diff --git a/extensions/perdomainsettings b/extensions/perdomainsettings index df2645ca..a6fcc7fd 100644 --- a/extensions/perdomainsettings +++ b/extensions/perdomainsettings @@ -243,12 +243,12 @@ var perdomainsettings = { exports.uris = uris = config.uris || defaultConfig.uris; uris && getDefaultValue(uris); - signals.connect("navigation", onNavigation.debug(script)); + Signal.connect("navigation", onNavigation.debug(script)); return true; }, end : function () { - signals.disconnect(onNavigation); + Signal.disconnect(onNavigation); } }; return perdomainsettings; diff --git a/extensions/requestpolicy b/extensions/requestpolicy index 9af23275..6ceee7a3 100644 --- a/extensions/requestpolicy +++ b/extensions/requestpolicy @@ -109,12 +109,6 @@ var defaultConfig = { }; var config = {}; -var sigs = { - resource : -1, - navigation : -1, - loadFinished : -1 -}; - var persistentList = null; var tmpList = {}; @@ -412,23 +406,6 @@ function loadFinishedCB(wv) io.notify("RP: blocked " + blocked + " requests"); } -function connect() -{ - sigs.resource = signals.connect("resource", resourceCB); - sigs.navigation = signals.connect("navigation", navigationCB); - if (config.notify) - sigs.loadFinished = signals.connect("loadFinished", loadFinishedCB); -} -function disconnect() -{ - sigs.forEach(function (key, value) { - if (value != -1) - { - signals.disconnect(value); - sigs[key] = -1; - } - }); -}//}}} var requestpolicy = { defaultConfig : defaultConfig, init : function(c) @@ -448,7 +425,10 @@ var requestpolicy = { } } persistentList = persistentList || {}; - connect(); + Signal.connect("resource", resourceCB); + Signal.connect("navigation", navigationCB); + if (config.notify) + Signal.connect("loadFinished", loadFinishedCB); bind(config.shortcut, showMenu, "requestpolicy"); bind(config.unblockCurrent, unblockCurrent, "requestpolicyUnblockCurrent"); bind(config.unblockAll, unblockAll, "requestpolicyUnblockAll"); @@ -457,6 +437,9 @@ var requestpolicy = { end : function () { disconnect(); + Signal.disconnect(resourceCB); + Signal.disconnect(navigationCB); + Signal.disconnect(loadFinishedCB); unbind("requestpolicy"); unbind("requestpolicyUnblockCurrent"); unbind("requestpolicyUnblockAll"); diff --git a/extensions/unique_tabs b/extensions/unique_tabs index 3496a1c3..535e72f0 100644 --- a/extensions/unique_tabs +++ b/extensions/unique_tabs @@ -44,7 +44,7 @@ commandToggleAutoFocus : "ut_toggle_autofocus", //>DEFAULT_CONFIG }; -var signalId = -1; +var signal; var removeDuplicates = function() { @@ -73,28 +73,17 @@ var onNavigation = function(wv, frame, request) } return false; }; -var connectAutoFocus = function() -{ - signalId = signals.connect("navigation", onNavigation); -}; -var disconnectAutoFocus = function() -{ - if (signalId != -1) - { - signals.disconnect(signalId); - signalId = -1; - return true; - } - return false; -}; var toggleAutoFocus = function() { - if (disconnectAutoFocus()) + if (signal.isConnected()) + { + signal.disconnect(); io.notify("unique_tabs: autofocus disabled"); + } else { + signal.connect(); io.notify("unique_tabs: autofocus enabled"); - connectAutoFocus(); } }; @@ -110,14 +99,15 @@ var uniqueTabs = { bind(c.shortcutToggleAutoFocus, toggleAutoFocus, c.commandToggleAutoFocus); } + signal = new Signal("navigation", onNavigation); if (c.autoFocus) - connectAutoFocus(); + signal.connect(); return true; }, end : function() { unbind(removeDuplicates); unbind(toggleAutoFocus); - disconnectAutoFocus(); + signal.disconnect(); return true; } }; diff --git a/extensions/userscripts b/extensions/userscripts index e8fd71ee..9d86d7ca 100644 --- a/extensions/userscripts +++ b/extensions/userscripts @@ -489,13 +489,13 @@ function userscriptsStart() if (onStart.length > 0) { onStart.sort(function(a, b) { return b.priority - a.priority; }); - signals.connect("loadCommitted", loadCommittedCallback); + Signal.connect("loadCommitted", loadCommittedCallback); ret = true; } if (onEnd.length > 0) { onEnd.sort(function(a, b) { return b.priority - a.priority; }); - signals.connect("documentLoaded", loadFinishedCallback); + Signal.connect("documentLoaded", loadFinishedCallback); ret = true; } //metaData = {}; @@ -541,8 +541,8 @@ var userscripts = { return parseScripts(c ? c.scripts || [] : []); }, end : function () { - signals.disconnect(loadFinishedCallback); - signals.disconnect(loadCommittedCallback); + Signal.disconnect(loadFinishedCallback); + Signal.disconnect(loadCommittedCallback); } }; diff --git a/scripts/lib/dwb.js b/scripts/lib/dwb.js index 0d946dc6..72f8c985 100644 --- a/scripts/lib/dwb.js +++ b/scripts/lib/dwb.js @@ -335,17 +335,27 @@ return _deprecated("sendRequestSync", "net.sendRequestSync", arguments); } }, + "_deprecationWarning" : + { + value : function(on, nn) + { + io.print("\033[31;1mDWB DEPRECATION:\033[0m " + on + "() is deprecated, use " + nn + "() instead!"); + } + }, "_deprecated" : { value : function(on, nn, args) { var i, l, ns, ctx; io.print("\033[31;1mDWB DEPRECATION:\033[0m " + on + "() is deprecated, use " + nn + "() instead!"); - ns = nn.split("."); - ctx = this; - for (i=0, l=ns.length; i<l-1; i++) - ctx = ctx[ns[i]]; - return ctx[ns[l-1]].apply(this, args); + if (args) + { + ns = nn.split("."); + ctx = this; + for (i=0, l=ns.length; i<l-1; i++) + ctx = ctx[ns[i]]; + return ctx[ns[l-1]].apply(this, args); + } } }, "_initNewContext" : diff --git a/scripts/lib/signals.js b/scripts/lib/signals.js index 3078d42c..4e87342a 100644 --- a/scripts/lib/signals.js +++ b/scripts/lib/signals.js @@ -1,144 +1,479 @@ (function () { - var _registered = {}; - var _blocked = false; - var _pending = []; - function _disconnect(sig) + var _regCount = {}; + var _connectedSignals = {}; + var _connectedMapping = {}; + + var _disconnect = function(signal) { - signals[sig] = null; - delete _registered[sig]; - } - var _disconnectByProp = function(prop, obj) + var name = signal.name, id = signal.id; + _regCount[name]--; + + _connectedSignals[name][id] = null; + delete _connectedSignals[name][id]; + + _connectedMapping[id] = null; + delete _connectedMapping[id]; + + + if (_regCount[name] == 0) + signals[name] = null; + return signal; + }; + var _getSignalByCallback = function(callback) { - var sig, i, sigs; - if (_blocked) + var id; + for (id in _connectedMapping) { - _pending.push({prop : prop, obj : obj}); - return; + if (callback == _connectedMapping[id].callback) + { + return _connectedMapping[id]; + } } - for (sig in _registered) - { - sigs = _registered[sig]; - for (i = 0; i<sigs.length; i++) + return null; + }; + var _getSignalBySelfOrCallback = function(selfOrCallback) + { + if (selfOrCallback instanceof Signal) + return selfOrCallback; + return _getSignalByCallback(selfOrCallback); + }; + /** + * + * @name Signal + * @class + * A Signal can be used to connect to certain browser events. For a list + * of available signals see {@link signals}. Signals are directly + * emitted on {@link signals}, this class is just a convience + * class to handle signals. + * @description + * Constructs a new Signal + * @example + * function navigationCallback(wv, frame, request, response) + * { + * ... + * } + * + * // Create a new signal + * var a = new Signal("navigation", navigationCallback); + * var b = new Signal("navigation"); + * + * // The following patterns are equivalent + * a.connect(); + * + * b.connect(navigationCallback); + * + * // using the static method + * var c = Signal.connect("navigation", navigationCallback); + * + * // set the signal callback directly on {@link signals} + * // you won't get the constructed signal then + * signals.onNavigation = navigationCallback; + * + * @param {String} name + * The event to connect to + * @param {Function} [callback] + * Callback that will be called when the signal is emitted. If omitted + * a callback must be passed to {@link connect}. + * + * @returns {Signal} + * A new Signal + * */ + Object.defineProperty(this, "Signal", { + writable : true, + value : (function() { + var id = 0; + return function(name, callback) + { + id++; + if (!name) + { + throw new Error("new Signal() : missing signal name"); + } + return Object.create(Signal.prototype, + { + /** + * The id of the signal + * @name id + * @memberOf Signal.prototype + * @readonly + * + * */ + "id" : { value : id }, + /** + * The callback that will be called when the signal + * is emitted, the context of the signal will be the + * signal itself (i.e. <i>this</i> refers to the + * connected Signal). + * + * @name callback + * @memberOf Signal.prototype + * + * @example + * function a() { + * io.print("Calling from a"); + * this.callback = b; + * } + * function b() { + * io.print("Calling from b"); + * this.callback = a; + * } + * var s = new Signal("createTab", a).connect(); + * */ + "callback" : { value : callback, writable : true }, + /** + * The name of the event + * @name name + * @memberOf Signal.prototype + * @readonly + * */ + "name" : { value : name }, + /** + * Disconnect this signal from the event, if disconnected the + * callback will no longer be called, to reconnect + * call signal.connect() + * + * @name disconnect + * @function + * @memberOf Signal.prototype + * + * @returns {Signal} + * self + * + * @example + * var i = 0; + * var signal = new Signal("navigation", function(wv, frame, request) { + * i++; + * if (i == 3) + * this.disconnect(); + * }); + * */ + "disconnect" : + { + value : function() + { + if (this.isConnected()) + _disconnect(this); + return this; + } + }, + /** + * Connect this signal to the event + * + * @name connect + * @function + * @memberOf Signal.prototype + * + * @param {Function} [callback] + * The callback function to call, if no + * callback was passed to the constructor + * callback is mandatory. + * + * @returns {Signal} + * self + * @example + * function a() { + * ... + * } + * function b() { + * ... + * } + * var signal = new Signal("navigation", a); + * // connect to a + * signal.connect(); + * // connect to b + * signal.connect(b); + * */ + "connect" : + { + value : function(callback) + { + if (callback) + this.callback = callback; + if (this.isConnected()) + return; + + if (!this.callback) + throw new Error("Signal.connect() : missing callback"); + var name = this.name, id = this.id; + if (!_regCount[name]) + _regCount[name] = 0; + if (!_connectedSignals[name]) + _connectedSignals[name] = {}; + if (_regCount[name] == 0) + { + signals[name] = function() { return Signal.emit(name, arguments); }; + } + _regCount[name]++; + _connectedSignals[name][id] = this; + _connectedMapping[id] = this; + return this; + } + }, + /** + * Checks if a signal is connected + * + * @name isConnected + * @memberOf Signal.prototype + * @function + * + * @return {Boolean} + * <i>true</i> if the signal is connected + * */ + "isConnected" : + { + value : function() + { + return Boolean(_connectedMapping[this.id]); + } + } + } + ); + }; + })() + }); + Object.defineProperties(Signal, { + /** + * Connects to an event + * + * @name connect + * @memberOf Signal + * @function + * + * @param {String} name + * The signal to connect to + * @param {Function} callback + * Callback that will be called when the signal is emitted. + * + * @returns {Signal} + * A new Signal + * + * @example + * function onCloseTab() + * { + * ... + * } + * var s = Signal.connect("closeTab", onCloseTab); + * // equivalent to + * var s = new Signal("closeTab", onCloseTab); + * s.connect(); + * */ + "connect" : { - if (sigs[i][prop] == obj) + value : function(name, callback) { - if (_registered[sig].length === 1) + var signal = new Signal(name, callback); + return signal.connect(); + } + }, + /** + * Disconnects from an event. + * @name disconnect + * @memberOf Signal + * @function + * + * @param {Signal|Callback} object + * Either a Signal or the callback of a signal + * If a callback is passed to this function and the same + * callback is connected multiple times only the first matching + * callback will be disconnected, to disconnect all matching + * callbacks call use {@link Signal.disconnectAll} + * + * @returns {Signal} + * The disconnected Signal + * + * @example + * function callback(wv) + * { + * ... + * } + * var s = new Signal("loadStatus").connect(callback); + * + * // Disconnect from the first matching callback + * Signal.disconnect(callback); + * + * Signal.disconnect(s); + * // or equivalently + * s.disconnect(); + * */ + "disconnect" : + { + value : function(selfOrCallback) + { + return _getSignalBySelfOrCallback(selfOrCallback); + } + }, + /** + * Connects all webviews to a GObject signal. + * + * @name connectWebView + * @memberOf Signal + * @function + * + * @param {String} signal The signal name + * @param {GObject~connectCallback} callback + * A callback function the will be called when the signal is + * emitted, the arguments of the callback correspond to the GObject + * callback + * @example + * Signal.connectWebView("hovering-over-link", function(title, uri) { + * io.write("/tmp/hovered_sites", "a", uri + " " + title); + * }); + * + * */ + "connectWebView" : + { + value : function(name, callback) + { + Signal.connect("createTab", function(wv) { + wv.connect(name, function() { callback.apply(wv, arguments);}); + }); + } + }, + /** + * Emits a signal, can be used to implement custom signals. + * + * @name emit + * @memberOf Signal + * @function + * + * @param {String} signal The signal name + * @param {varargs} args Arguments passed to the callback function of + * {@link signals.connect} + * + * @returns {Boolean} + * The overall return value of all callback function, if one + * callback function returns <i>true</i> the overall return value + * will be <i>true</i> + * */ + "emit" : + { + value : function(signal, args) + { + var id, current; + var ret = false; + var connected = _connectedSignals[signal]; + for (id in connected) + { + current = connected[id]; + ret = current.callback.apply(current, args) || ret; + } + return ret; + } + }, + /** + * Disconnect from all signals with matching callback function + * + * @name disconnectAll + * @memberOf Signal + * @function + * + * @param {Function} callback + * A callback function + * + * @returns {Array} + * Array of signals that were disconnected + * + * @example + * function onNavigation(wv, frame, request) + * { + * ... + * } + * var a = new Signal("navigation", onNavigation).connect(); + * var b = new Signal("navigation", onNavigation).connect(); + * + * Signals.disconnectAll(onNavigation); + * */ + "disconnectAll" : + { + value : function(callback) + { + var signals = []; + var signal; + while((signal = _getSignalBySelfOrCallback(callback))) { - _disconnect(sig); + signals.push(signal); + signal.disconnect(); } + return signals; + + } + }, + /** + * Connect to more than one signal at once + * + * @name connectAll + * @memberOf Signal + * @function + * + * @param {Array} signals + * Array of signals + * @param {Function} [callback] + * Callbackfunction to connect to + * + * + * @example + * function onNavigation(wv, frame, request) + * { + * ... + * } + * function onNavigation2(wv, frame, request) + * { + * ... + * } + * var a = new Signal("navigation", onNavigation).connect(); + * var b = new Signal("navigation", onNavigation).connect(); + * + * // disconnect from all signals + * var signals = Signal.disconnectAll(onNavigation); + * + * // reconnect to all signals + * Signal.connectAll(signals); + * + * // Reconnect to all signals with a new callback + * Signal.connectAll([a, b], onNavigation2); + * */ + "connectAll" : + { + value : function(signalOrArray, callback) + { + var i, l; + if (signalOrArray instanceof Signal) + signalOrArray.connect(callback); else { - sigs.splice(i, 1); + for (i=signalOrArray.length-1; i>=0; i--) + signalOrArray[i].connect(callback); } - return; } } - } - }; - var _connect = function(id, sig, func, pre) - { - pre = pre || 0; - if (func === null || typeof func !== "function") - { - return -1; - } - if (_registered[sig] === undefined || _registered[sig] === null) - { - _registered[sig] = []; - signals[sig] = function () { return signals.emit(sig, arguments); }; - } - _registered[sig].push({ callback : func, id : id, pre : pre }); - _registered[sig].sort(function(a, b) { return b.pre - a.pre; }); - return id; - }; - Object.defineProperties(signals, - { + }); + Object.defineProperties(signals, { /** - * Emits a signal, can be used to implement custom signals. - * * @name emit * @memberOf signals - * @function - * - * @param {String} signal The signal name - * @param {varargs} args Arguments passed to the callback function of - * {@link signals.connect} - * - * @returns {Boolean} - * The overall return value of all callback function, if one - * callback function returns <i>true</i> the overall return value - * will be <i>true</i> + * @function + * @deprecated use {@link Signal.emit} instead * */ "emit" : { - value : function(sig, args) + value : function(sig, func, pre) { - var sigs = _registered[sig]; - var currentSig, pending; - var ret = false; - var i, l; - _blocked = true; - for (i=0, l=sigs.length; i<l; i++) - { - currentSig = sigs[i]; - ret = currentSig.callback.apply(currentSig.callback, args) || ret; - } - _blocked = false; - if (_pending.length > 0) - { - for (i=_pending.length-1; i>=0; --i) - { - pending = _pending[i]; - _disconnectByProp(pending.prop, pending.obj); - } - _pending = []; - } - return ret; + return _deprecated("signals.emit", "Signal.emit", arguments); } }, /** - * Connects to a signal. Use this function to connect to a signal, - * setting a callback function directly on an event will overwrite - * all existing callbacks. The callbacks are executed in order they are - * connected except precedence is set for some signals. - * - * @example - * signals.connect("navigation", function(webview, frame, request, action) { - * ... - * }); - * * @name connect * @memberOf signals * @function - * - * @param {String} event - * The event name, see Events for details - * @param {Function} callback - * A callback function the will be called when the signal is - * emitted, see Type Definitions for details - * @param {Number} [precedence] - * A number indicating the precedence of executing the callback, - * the higher the number the earlier the function will be executed - * in the callback queue, note that all callbacks connected from - * scripts will be executed regardless of precedence. The default - * precedence is 0. - * - * @returns {Number} - * A unique signal id + * @deprecated use {@link Signal.connect} instead * */ "connect" : { - value : (function () + value : function(sig, func, pre) { - var id = 0; - return function(sig, func, pre) - { - id++; - _connect(id, sig, func, pre); - return id; - }; - })() + return _deprecated("signals.connect", "Signal.connect", arguments); + } }, /** * Connects all webviews to a GObject signal. @@ -146,127 +481,53 @@ * @name connectWebView * @memberOf signals * @function + * @deprecated use {@link Signal.connectWebView} instead * - * @param {String} signal The signal name - * @param {GObject~connectCallback} callback - * A callback function the will be called when the signal is - * emitted, the arguments of the callback correspond to the GObject - * callback - * @example - * signals.connectWebView("hovering-over-link", function(title, uri) { - * io.write("/tmp/hovered_sites", "a", uri + " " + title); - * }); * */ "connectWebView" : { - value : function(name, callback) + value : function() { - this.connect("createTab", function(wv) { - wv.connect(name, function() { callback.apply(wv, arguments);}); - }); + return _deprecated("signals.connectWebView", "Signal.connectWebView", arguments); } }, /** - * Disconnect from a signal - * * @name disconnect * @memberOf signals * @function - * - * @param {Number|Function} id|callback - * The id returned from {@link connect} or the callback - * function passed to connect. Note that if the same callback - * is used more than once the signal must be disconnected by - * id, otherwise the behaviour is undefined. - * @example - * signals.connect("loadFinished", function(wv) { - * ... - * signals.disconnect(this); - * }); - * var id = signals.connect("loadCommitted", function(wv) { - * ... - * signals.disconnect(id); - * }); + * @deprecated use {@link Signal.disconnect} instead * */ "disconnect" : { - value : function(obj) { - if (typeof obj == "function") - _disconnectByProp("callback", obj); - else - _disconnectByProp("id", obj); - + value : function() + { + return _deprecated("signals.connect", "Signal.disconnect", arguments); } }, /** - * Disconnect from all signals with matching name. Use with care, it - * will stop the emission of the signal in <b>all scripts</b>. Can be used to - * temporarily disable the emission of the signal. - * To reconnect to all signals pass the returned object to - * {@link signals.connectAll}. - * * @name disconnectAll * @memberOf signals * @function - * - * @param {String} signal - * The signal name - * - * @returns {Object} - * An object that can be passed to {@link signals.connectAll} or - * <i>null</i>. + * @deprecated use {@link Signal.disconnectAll} * */ "disconnectAll" : { - value : function (name) + value : function(callback) { - var sigs = null; - if (signals[name] !== null && signals[name] !== undefined) - { - var ret = []; - for (var i=0; i<_registered[name].length; i++) - ret.push(_registered[name][i]); - _disconnect(name); - - return { name : name, signals : ret }; - } - return null; + return _deprecated("signals.disconnectAll", "Signal.disconnectAll", arguments); } }, /** - * Reconnect to a signal previously disconnected with - * {@link signals.disconnectAll}. - * * @name connectAll * @memberOf signals * @function - * - * @param {Object} detail - * Object retrieved from {@link signals.disconnectAll} - * @param {String} detail.name - * Name of the signal - * @param {Array[Object]} detail.signals[] - * Array of signal data - * @param {Number} detail.signals[].id - * The id of the signal - * @param {Function} detail.signals[].callback - * The callback passed to {@link signals.connect} - * @param {Number} detail.signals[].pre - * The precedence - * + * @deprecated use {@link Signal.connectAll} instead * */ "connectAll" : { - value : function(sigs) + value : function() { - var sig, i, l; - var name = sigs.name; - var s = sigs.signals; - for (i=0, l=s.length; i<l; i++) - { - sig = s[i]; - _connect(sig.id, name, sig.callback, sig.pre); - } + return _deprecated("signals.connectAll", "Signal.connectAll", arguments); } } }); diff --git a/src/scripts.c b/src/scripts.c index 3e75685b..05a62807 100644 --- a/src/scripts.c +++ b/src/scripts.c @@ -166,7 +166,8 @@ static JSClassRef s_gobject_class, s_deferred_class, s_history_class; static gboolean s_commandline = false; -static JSObjectRef s_array_contructor; +static JSObjectRef s_array_contructor, + s_signal_connect; static JSObjectRef s_completion_callback; static GQuark s_ref_quark; static JSObjectRef s_init_before, s_init_after; // s_private; @@ -2850,6 +2851,8 @@ watch_spawn(GPid pid, gint status, JSObjectRef deferred) * needed and environment variables should be set * @param {Object} [environ] Object that can be used to add environment * variables to the childs environment + * @param {Boolean} [toStdin] If set to <i>true</i> stdout- and stderr-callback can be + * used to write to stdin of the childs * * @returns {Deferred} * A deferred, it will be resolved if the child exits normally, it will be @@ -2868,6 +2871,7 @@ system_spawn(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, siz SpawnChannel *out = NULL, *err = NULL; JSObjectRef oc = NULL, ec = NULL; GPid pid; + gboolean get_stdin = false; if (argc == 0) @@ -2891,12 +2895,14 @@ system_spawn(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, siz if (argc > 3) envp = get_environment(ctx, argv[3], exc); + if (argc > 4) + get_stdin = JSValueToBoolean(ctx, argv[4]); if (!g_shell_parse_argv(cmdline, &srgc, &srgv, NULL) || !g_spawn_async_with_pipes(NULL, srgv, envp, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, - oc != NULL || ec != NULL ? &infd : NULL, + get_stdin && (oc != NULL || ec != NULL) ? NULL : &infd, oc != NULL ? &outfd : NULL, ec != NULL ? &errfd : NULL, NULL)) { @@ -3877,6 +3883,22 @@ signal_set(JSContextRef ctx, JSObjectRef object, JSStringRef js_name, JSValueRef if (name == NULL) return false; + if (g_str_has_prefix(name, "on") && strlen(name) > 3 && g_ascii_isupper(*(name+2))) + { + JSObjectRef func = js_value_to_function(ctx, value, exception); + if (func) + { + name[2] = g_ascii_tolower(name[2]); + const char *tmp = name+2; + JSValueRef js_value = js_char_to_value(ctx, tmp); + JSValueRef argv[] = { js_value, func }; + puts(tmp); + JSObjectCallAsFunction(s_global_context, s_signal_connect, NULL, 2, argv, exception); + + g_free(name); + return true; + } + } for (int i = SCRIPTS_SIG_FIRST; i<SCRIPTS_SIG_LAST; i++) { @@ -4671,11 +4693,34 @@ create_global_object() * All events are emitted on the signals object itself, for example * "signals.keyPress = function() { ... };" would connect to the keyPress * signal but it is <b>strongly discouraged</b> to use this pattern since it will - * only allow to connect one callback to a certain signal, so {@link signals.connect} - * which manages all signals should be used instead. + * only allow to connect one callback to a certain signal. To handle signals + * {@link Signal}-objects can be used, it manages signals, allows to connect + * more than one signal and also allows to easily disconnect/reconnect to + * signals. + * + * There is just one convenient pattern that allows setting + * callbacks directly on signals: if the signal name starts with "on" + * dwb will internally create a new Signal and connect to it with the given + * callback function, i.e. using + * <b>signals.onResource = function () {...}</b> allows to connect more than + * one callback to the "resource"-event, however it doesn't give you as much + * control as creating a {@link Signal}. * * @namespace * @name signals + * @example + * function onNavigation(wv, frame, request) + * { + * ... + * if (request.uri == "http://www.example.com") + * this.disconnect(); + * } + * // Connect to the navigation event + * // this is the preferred way. + * var s = new Signal("navigation", onNavigation).connect(); + * // or equivalently, gi + * signals.onNavigation = onNavigation; + * * */ cd = kJSClassDefinitionEmpty; cd.className = "signals"; @@ -5262,6 +5307,10 @@ scripts_init(gboolean force) g_string_free(content, true); g_free(dir); } + JSObjectRef signal = js_get_object_property(s_global_context, JSContextGetGlobalObject(s_global_context), "Signal"); + s_signal_connect = js_get_object_property(s_global_context, signal, "connect"); + JSValueProtect(s_global_context, s_signal_connect); + UNDEFINED = JSValueMakeUndefined(s_global_context); JSValueProtect(s_global_context, UNDEFINED); NIL = JSValueMakeNull(s_global_context); @@ -5369,6 +5418,7 @@ scripts_end() JSValueUnprotect(s_global_context, UNDEFINED); JSValueUnprotect(s_global_context, NIL); JSValueUnprotect(s_global_context, s_soup_session); + JSValueUnprotect(s_global_context, s_signal_connect); //JSValueUnprotect(s_global_context, s_private); JSClassRelease(s_gobject_class); JSClassRelease(s_webview_class); |