From 8fbe8fffeca89efdd9ddec0028e7f288bd49a0a0 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Thu, 20 Jan 2011 00:30:14 -0500 Subject: [PATCH] Fix overlong stack generated by key events received during feedkeys, along with related "Attempt to execute mapping recursively" errors. --- common/content/events.js | 84 +++++++++++++++++++++------------------- common/modules/util.jsm | 23 +++++++---- 2 files changed, 59 insertions(+), 48 deletions(-) diff --git a/common/content/events.js b/common/content/events.js index 21417394..c387edb8 100644 --- a/common/content/events.js +++ b/common/content/events.js @@ -272,7 +272,6 @@ var Events = Module("events", { try { var wasFeeding = this.feedingKeys; this.feedingKeys = true; - this.duringFeed = this.duringFeed || []; var wasQuiet = commandline.quiet; if (quiet) @@ -315,13 +314,6 @@ var Events = Module("events", { this.feedingKeys = wasFeeding; if (quiet) commandline.quiet = wasQuiet; - - if (this.duringFeed.length) { - let duringFeed = this.duringFeed; - this.duringFeed = []; - for (let [, event] in Iterator(duringFeed)) - events.dispatch(event.originalTarget, event, event); - } } }, @@ -868,43 +860,45 @@ var Events = Module("events", { event.stopPropagation(); } - if (this.feedingEvent && [!(k in event) || event[k] === v for ([k, v] in Iterator(this.feedingEvent))].every(util.identity)) { - for (let [k, v] in Iterator(this.feedingEvent)) - if (!(k in event)) - event[k] = v; - this.feedingEvent = null; - } - - let key = events.toString(event); - if (!key) - return null; - - if (modes.recording && (!this._input || !mappings.userHive.hasMap(modes.main, this._input.buffer + key))) - events._macroKeys.push(key); - - // feedingKeys needs to be separate from interrupted so - // we can differentiate between a recorded - // interrupting whatever it's started and a real - // interrupting our playback. - if (events.feedingKeys && !event.isMacro) { - if (key == "") { - events.feedingKeys = false; - if (modes.replaying) { - modes.replaying = false; - this.timeout(function () { dactyl.echomsg("Canceled playback of macro '" + this._lastMacro + "'"); }, 100); - } - } - else - events.duringFeed.push(event); - - return kill(event); - } - function shouldPass() (!dactyl.focusedElement || events.isContentNode(dactyl.focusedElement)) && options.get("passkeys").has(events.toString(event)); + let duringFeed = this.duringFeed; + this.duringFeed = []; try { + if (this.feedingEvent && [!(k in event) || event[k] === v for ([k, v] in Iterator(this.feedingEvent))].every(util.identity)) { + for (let [k, v] in Iterator(this.feedingEvent)) + if (!(k in event)) + event[k] = v; + this.feedingEvent = null; + } + + let key = events.toString(event); + if (!key) + return null; + + if (modes.recording && (!this._input || !mappings.userHive.hasMap(modes.main, this._input.buffer + key))) + events._macroKeys.push(key); + + // feedingKeys needs to be separate from interrupted so + // we can differentiate between a recorded + // interrupting whatever it's started and a real + // interrupting our playback. + if (events.feedingKeys && !event.isMacro) { + if (key == "") { + events.feedingKeys = false; + if (modes.replaying) { + modes.replaying = false; + this.timeout(function () { dactyl.echomsg("Canceled playback of macro '" + this._lastMacro + "'"); }, 100); + } + } + else + events.duringFeed.push(event); + + return kill(event); + } + let mode = modes.getStack(0); if (event.dactylMode) mode = Modes.StackElement(event.dactylMode); @@ -1020,6 +1014,16 @@ var Events = Module("events", { catch (e) { dactyl.reportError(e); } + finally { + [duringFeed, this.duringFeed] = [this.duringFeed, duringFeed]; + for (let event in this.duringFeed) + try { + this.dispatch(event.originalTarget, event, event); + } + catch (e) { + util.reportError(e); + } + } }, onKeyUpOrDown: function onKeyUpOrDown(event) { diff --git a/common/modules/util.jsm b/common/modules/util.jsm index 70ecdd53..2c3f5d02 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -1465,16 +1465,23 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), return results; }, + yielders: 0, threadYield: function (flush, interruptable) { - let mainThread = services.threading.mainThread; - /* FIXME */ - util.interrupted = false; - do { - mainThread.processNextEvent(!flush); - if (util.interrupted) - throw new Error("Interrupted"); + this.yielders++; + try { + let mainThread = services.threading.mainThread; + /* FIXME */ + util.interrupted = false; + do { + mainThread.processNextEvent(!flush); + if (util.interrupted) + throw new Error("Interrupted"); + } + while (flush === true && mainThread.hasPendingEvents()); + } + finally { + this.yielders--; } - while (flush === true && mainThread.hasPendingEvents()); }, yieldable: function yieldable(func)