| Index: build_tools/naclprocess.js
|
| diff --git a/build_tools/naclprocess.js b/build_tools/naclprocess.js
|
| index fe03393f7d0717444e63b5fd8910a97874bce990..69034b42cadad3a60a06e4e407a9a9bc5cf67eeb 100644
|
| --- a/build_tools/naclprocess.js
|
| +++ b/build_tools/naclprocess.js
|
| @@ -37,15 +37,131 @@ var g_mount = {
|
| };
|
|
|
| /**
|
| + * This creates a popup that runs a NaCl process inside.
|
| + *
|
| + * @param {Object} process The NaCl process to be run.
|
| + * @param {number} width
|
| + * @param {number} height
|
| + * @param {string} title
|
| + */
|
| +function GraphicalPopup(process, width, height, title) {
|
| + this.process = process || null;
|
| + this.width = width || GraphicalPopup.DEFAULT_WIDTH;
|
| + this.height = height || GraphicalPopup.DEFAULT_HEIGHT;
|
| + this.title = title || '';
|
| + this.win = null;
|
| + this.onClosed = null;
|
| +}
|
| +
|
| +/**
|
| + * The default width of the popup.
|
| + * @type {number}
|
| + */
|
| +GraphicalPopup.DEFAULT_WIDTH = 600;
|
| +
|
| +/**
|
| + * The default height of the popup.
|
| + * @type {number}
|
| + */
|
| +GraphicalPopup.DEFAULT_HEIGHT = 400;
|
| +
|
| +/**
|
| + * The (empty) HTML file to which the NaCl module is added.
|
| + * @const
|
| + */
|
| +GraphicalPopup.HTML_FILE = 'graphical.html';
|
| +
|
| +/**
|
| + * Focus the window in which this code is run.
|
| + */
|
| +GraphicalPopup.focusCurrentWindow = function () {
|
| + chrome.app.window.current().focus();
|
| +};
|
| +
|
| +/**
|
| + * This callback is called when the popup is closed.
|
| + * @callback closedCallback
|
| + */
|
| +
|
| +/**
|
| + * Set a function to be called as a callback when the popup is closed.
|
| + * @param {closedCallback} listener
|
| + */
|
| +GraphicalPopup.prototype.setClosedListener = function (listener) {
|
| + if (this.win) {
|
| + throw new Error("Cannot set closed listener after creating window.");
|
| + }
|
| + this.onClosed = listener;
|
| +};
|
| +
|
| +/**
|
| + * Create the window.
|
| + */
|
| +GraphicalPopup.prototype.create = function () {
|
| + var self = this;
|
| + chrome.app.window.create('graphical.html', {
|
| + 'bounds': {
|
| + 'width': self.width,
|
| + 'height': self.height
|
| + },
|
| + }, function (win) {
|
| + var process = self.process;
|
| + var popup = win.contentWindow;
|
| +
|
| + self.win = process.window = win;
|
| +
|
| + popup.document.title = self.title;
|
| +
|
| + popup.addEventListener('load', function () {
|
| + process.style.position = 'absolute';
|
| + process.style.top = '0';
|
| + process.style.left = '0';
|
| + process.style.width = '100%';
|
| + process.style.height = '100%';
|
| + popup.document.body.appendChild(process);
|
| + });
|
| +
|
| + popup.focused = true;
|
| + popup.addEventListener('focus', function () {
|
| + this.focused = true;
|
| + });
|
| + popup.addEventListener('blur', function () {
|
| + this.focused = false;
|
| + });
|
| +
|
| + if (self.onClosed) {
|
| + win.onClosed.addListener(self.onClosed);
|
| + }
|
| + });
|
| +};
|
| +
|
| +/**
|
| + * Close the popup.
|
| + */
|
| +GraphicalPopup.prototype.destroy = function () {
|
| + if (this.win.contentWindow.focused) {
|
| + GraphicalPopup.focusCurrentWindow();
|
| + }
|
| + if (this.onClosed) {
|
| + this.win.onClosed.removeListener(this.onClosed);
|
| + }
|
| + this.win.close();
|
| +
|
| + this.process = null;
|
| + this.win = null;
|
| +};
|
| +
|
| +
|
| +/**
|
| * NaClProcessManager provides a framework for NaCl executables to run within a
|
| * web-based terminal.
|
| */
|
| function NaClProcessManager() {
|
| var self = this;
|
| - self.onError = function() {};
|
| - self.onStdout = function() {};
|
| - self.onRootProgress = function() {};
|
| - self.onRootLoad = function() {};
|
| + self.onError = null;
|
| + self.onStdout = null;
|
| + self.onRootProgress = null;
|
| + self.onRootLoad = null;
|
|
|
| // The process which gets the input from the user.
|
| self.foregroundProcess = null;
|
| @@ -273,23 +389,22 @@ NaClProcessManager.EMBED_HEIGHT_DEFAULT = '50%';
|
| * @param {naclArchCallback} callback.
|
| */
|
| function getNaClArch(callback) {
|
| - if (getNaClArch.naclArch_ === undefined) {
|
| + if (getNaClArch.naclArch === undefined) {
|
| if (chrome && chrome.runtime && chrome.runtime.getPlatformInfo) {
|
| - chrome.runtime.getPlatformInfo(function(platformInfo) {
|
| - getNaClArch.naclArch_ = {
|
| + chrome.runtime.getPlatformInfo(function (platformInfo) {
|
| + getNaClArch.naclArch = {
|
| 'x86-32': 'i686',
|
| 'x86-64': 'x86_64',
|
| 'arm': 'arm',
|
| }[platformInfo.nacl_arch] || platformInfo.nacl_arch;
|
| - callback(getNaClArch.naclArch_);
|
| + callback(getNaClArch.naclArch);
|
| });
|
| return;
|
| - } else {
|
| - getNaClArch.naclArch_ = null;
|
| }
|
| + getNaClArch.naclArch = null;
|
| }
|
| - setTimeout(function() {
|
| - callback(getNaClArch.naclArch_);
|
| + setTimeout(function () {
|
| + callback(getNaClArch.naclArch);
|
| }, 0);
|
| }
|
|
|
| @@ -303,7 +418,7 @@ function getNaClArch(callback) {
|
| * Listen for stdout from the spawned processes.
|
| * @param {stdoutCallback} callback The callback to be called on a stdout write.
|
| */
|
| -NaClProcessManager.prototype.setStdoutListener = function(callback) {
|
| +NaClProcessManager.prototype.setStdoutListener = function (callback) {
|
| this.onStdout = callback;
|
| };
|
|
|
| @@ -318,7 +433,7 @@ NaClProcessManager.prototype.setStdoutListener = function(callback) {
|
| * Listen for errors from the spawned processes.
|
| * @param {errorCallback} callback The callback to be called on error.
|
| */
|
| -NaClProcessManager.prototype.setErrorListener = function(callback) {
|
| +NaClProcessManager.prototype.setErrorListener = function (callback) {
|
| this.onError = callback;
|
| };
|
|
|
| @@ -335,7 +450,7 @@ NaClProcessManager.prototype.setErrorListener = function(callback) {
|
| * Listen for a progress event from the root process.
|
| * @param {rootProgressCallback} callback The callback to be called on progress.
|
| */
|
| -NaClProcessManager.prototype.setRootProgressListener = function(callback) {
|
| +NaClProcessManager.prototype.setRootProgressListener = function (callback) {
|
| this.onRootProgress = callback;
|
| };
|
|
|
| @@ -348,7 +463,7 @@ NaClProcessManager.prototype.setRootProgressListener = function(callback) {
|
| * Listen for a load event from the root process.
|
| * @param {rootLoadCallback} callback The callback to be called on load.
|
| */
|
| -NaClProcessManager.prototype.setRootLoadListener = function(callback) {
|
| +NaClProcessManager.prototype.setRootLoadListener = function (callback) {
|
| this.onRootLoad = callback;
|
| };
|
|
|
| @@ -358,7 +473,7 @@ NaClProcessManager.prototype.setRootLoadListener = function(callback) {
|
| * another process.
|
| * @param {HTMLObjectElement} process The element about which one is inquiring.
|
| */
|
| -NaClProcessManager.prototype.isRootProcess = function(process) {
|
| +NaClProcessManager.prototype.isRootProcess = function (process) {
|
| return !process.parent;
|
| };
|
|
|
| @@ -368,29 +483,29 @@ NaClProcessManager.prototype.isRootProcess = function(process) {
|
| * @callback callback to be stashed away and called when
|
| * a process responds with a mount status update
|
| */
|
| -NaClProcessManager.prototype.broadcastMessage = function(message, callback) {
|
| +NaClProcessManager.prototype.broadcastMessage = function (message, callback) {
|
| this.mountUpdateCallback = callback;
|
| - for (var p in this.processes) {
|
| - this.processes[p].domElement.postMessage(message);
|
| - }
|
| + Object.keys(this.processes).forEach(function (key) {
|
| + this.processes[key].domElement.postMessage(message);
|
| + });
|
| };
|
|
|
| /**
|
| * Sync Mount status every time a mount/unmount message
|
| * is recieved from a process.
|
| */
|
| -NaClProcessManager.prototype.syncMountStatus_ = function() {
|
| +NaClProcessManager.prototype.syncMountStatus_ = function () {
|
| var result = true;
|
|
|
| if (g_mount.available) {
|
| - for (var p in this.processes) {
|
| + Object.keys(this.processes).forEach(function (p) {
|
| result = (result && this.processes[p].mounted);
|
| - }
|
| + });
|
| } else {
|
| result = false;
|
| - for (var p in this.processes) {
|
| + Object.keys(this.processes).forEach(function (p) {
|
| result = (result || this.processes[p].mounted);
|
| - }
|
| + });
|
| }
|
|
|
| g_mount.mounted = result;
|
| @@ -404,20 +519,20 @@ NaClProcessManager.prototype.syncMountStatus_ = function() {
|
| * Makes the path in a NMF entry to fully specified path.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.adjustNmfEntry_ = function(entry) {
|
| - for (var arch in entry) {
|
| +NaClProcessManager.prototype.adjustNmfEntry_ = function (entry) {
|
| + Object.keys(entry).forEach(function (arch) {
|
| var path;
|
| if (arch === 'portable') {
|
| if (entry[arch]['pnacl-translate'] === undefined ||
|
| - entry[arch]['pnacl-translate']['url'] === undefined) {
|
| + entry[arch]['pnacl-translate'].url === undefined) {
|
| return;
|
| }
|
| - path = entry[arch]['pnacl-translate']['url'];
|
| + path = entry[arch]['pnacl-translate'].url;
|
| } else {
|
| - if (entry[arch]['url'] === undefined) {
|
| + if (entry[arch].url === undefined) {
|
| return;
|
| }
|
| - path = entry[arch]['url'];
|
| + path = entry[arch].url;
|
| }
|
|
|
| // Convert 'path' from the NaCl VFS into an HTML5 filesystem: URL
|
| @@ -441,18 +556,18 @@ NaClProcessManager.prototype.adjustNmfEntry_ = function(entry) {
|
| }
|
|
|
| if (arch === 'portable') {
|
| - entry[arch]['pnacl-translate']['url'] = path;
|
| + entry[arch]['pnacl-translate'].url = path;
|
| } else {
|
| - entry[arch]['url'] = path;
|
| + entry[arch].url = path;
|
| }
|
| - }
|
| + });
|
| };
|
|
|
| /**
|
| * Handle messages sent to us from NaCl.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.handleMessage_ = function(e) {
|
| +NaClProcessManager.prototype.handleMessage_ = function (e) {
|
| var msg = e.data;
|
| var src = e.srcElement;
|
|
|
| @@ -476,42 +591,45 @@ NaClProcessManager.prototype.handleMessage_ = function(e) {
|
| this.pipeServer.handleMessageAPipeClose],
|
| nacl_jseval: [this, this.handleMessageJSEval_],
|
| nacl_deadpid: [this, this.handleMessageDeadPid_],
|
| - nacl_mountfs: [this,this.handleMessageMountFs_],
|
| + nacl_mountfs: [this, this.handleMessageMountFs_],
|
| };
|
|
|
| // TODO(channingh): Once pinned applications support "result" instead of
|
| // "pid", change calls to reply() to set "result."
|
| function reply(contents) {
|
| var message = {};
|
| - message[msg['id']] = contents;
|
| + message[msg.id] = contents;
|
| // Enable to debug message stream (disabled for speed).
|
| // console.log(src.pid + '> reply: ' + JSON.stringify(reply));
|
| src.postMessage(message);
|
| }
|
|
|
| - if (msg['command'] && handlers[msg['command']]) {
|
| + if (msg.command && handlers[msg.command]) {
|
| // Enable to debug message stream (disabled for speed).
|
| - //console.log(src.pid + '> ' + msg['command'] + ': ' + JSON.stringify(msg));
|
| - var handler = handlers[msg['command']];
|
| + //console.log(src.pid + '> ' + msg.command + ': ' + JSON.stringify(msg));
|
| + var handler = handlers[msg.command];
|
| handler[1].call(handler[0], msg, reply, src);
|
| - } else if (msg['mount_status'] == 'success') {
|
| + } else if (msg.mount_status === 'success') {
|
| // TODO(gdeepti): Remove monitoring mount status with strings.
|
| this.processes[src.pid].mounted = true;
|
| this.syncMountStatus_();
|
| - } else if (msg['unmount_status'] == 'success') {
|
| + } else if (msg.unmount_status === 'success') {
|
| this.processes[src.pid].mounted = false;
|
| this.syncMountStatus_();
|
| - } else if (msg['mount_status'] == 'fail' || msg['unmount_status'] == 'fail') {
|
| + } else if (msg.mount_status === 'fail' || msg.unmount_status === 'fail') {
|
| console.log('mounter_status: ' + JSON.stringify(msg));
|
| - } else if (typeof msg == 'string' &&
|
| + } else if (typeof msg === 'string' &&
|
| msg.indexOf(NaClProcessManager.prefix) === 0) {
|
| var out = msg.substring(NaClProcessManager.prefix.length);
|
| - this.onStdout(out);
|
| - } else if (typeof msg == 'string' &&
|
| + if (this.onStdout) {
|
| + this.onStdout(out);
|
| + }
|
| + } else if (typeof msg === 'string' &&
|
| msg.indexOf('exited') === 0) {
|
| - var exitCode = parseInt(msg.split(':', 2)[1]);
|
| - if (isNaN(exitCode))
|
| + var exitCode = parseInt(msg.split(':', 2)[1], 10);
|
| + if (isNaN(exitCode)) {
|
| exitCode = 0;
|
| + }
|
| this.exit(exitCode, src);
|
| } else {
|
| console.log('unexpected message: ' + JSON.stringify(msg));
|
| @@ -523,23 +641,24 @@ NaClProcessManager.prototype.handleMessage_ = function(e) {
|
| * Handle a nacl_spawn call.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.handleMessageSpawn_ = function(msg, reply, src) {
|
| +NaClProcessManager.prototype.handleMessageSpawn_ = function (msg, reply, src) {
|
| var self = this;
|
| - var args = msg['args'];
|
| - var envs = msg['envs'];
|
| - var cwd = msg['cwd'];
|
| + var args = msg.args;
|
| + var envs = msg.envs;
|
| + var cwd = msg.cwd;
|
| var executable = args[0];
|
| - var nmf = msg['nmf'];
|
| + var nmf = msg.nmf;
|
| if (nmf) {
|
| - if (nmf['files']) {
|
| - for (var key in nmf['files'])
|
| - self.adjustNmfEntry_(nmf['files'][key]);
|
| + if (nmf.files) {
|
| + Object.keys(nmf.files).forEach(function (key) {
|
| + self.adjustNmfEntry_(nmf.files[key]);
|
| + });
|
| }
|
| - self.adjustNmfEntry_(nmf['program']);
|
| + self.adjustNmfEntry_(nmf.program);
|
| var blob = new Blob([JSON.stringify(nmf)], {type: 'text/plain'});
|
| var nmfUrl = window.URL.createObjectURL(blob);
|
| - var naclType = self.checkNaClManifestType_(nmf) || 'nacl';
|
| - self.spawn(nmfUrl, args, envs, cwd, naclType, src, function(pid) {
|
| + var naclType = self.checkNaClManifestType(nmf) || 'nacl';
|
| + self.spawn(nmfUrl, args, envs, cwd, naclType, src, function (pid) {
|
| reply({pid: pid});
|
| });
|
| } else {
|
| @@ -553,16 +672,13 @@ NaClProcessManager.prototype.handleMessageSpawn_ = function(msg, reply, src) {
|
| return;
|
| }
|
| nmf = executable + '.nmf';
|
| - self.checkUrlNaClManifestType(nmf, function(naclType) {
|
| - self.spawn(nmf, args, envs, cwd, naclType, src, function(pid) {
|
| + self.checkUrlNaClManifestType(nmf, function (naclType) {
|
| + self.spawn(nmf, args, envs, cwd, naclType, src, function (pid) {
|
| reply({pid: pid});
|
| });
|
| - }, function(msg) {
|
| - var replyMsg = {
|
| - pid: -Errno.ENOENT,
|
| - };
|
| + }, function (msg) {
|
| console.log('nacl_spawn(error): ' + msg);
|
| - reply(replyMsg);
|
| + reply({pid: -Errno.ENOENT});
|
| });
|
| }
|
| };
|
| @@ -572,8 +688,8 @@ NaClProcessManager.prototype.handleMessageSpawn_ = function(msg, reply, src) {
|
| * Handle a waitpid call.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.handleMessageWait_ = function(msg, reply, src) {
|
| - this.waitpid(msg['pid'], msg['options'], function(pid, status) {
|
| +NaClProcessManager.prototype.handleMessageWait_ = function (msg, reply, src) {
|
| + this.waitpid(msg.pid, msg.options, function (pid, status) {
|
| reply({
|
| pid: pid,
|
| status: status
|
| @@ -585,9 +701,10 @@ NaClProcessManager.prototype.handleMessageWait_ = function(msg, reply, src) {
|
| * Handle a getpgid call.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.handleMessageGetPGID_ = function(msg, reply, src) {
|
| +NaClProcessManager.prototype.handleMessageGetPGID_ = function (msg, reply,
|
| + src) {
|
| var pgid;
|
| - var pid = parseInt(msg['pid']) || src.pid;
|
| + var pid = parseInt(msg.pid, 10) || src.pid;
|
|
|
| if (pid < 0) {
|
| pgid = -Errno.EINVAL;
|
| @@ -605,11 +722,12 @@ NaClProcessManager.prototype.handleMessageGetPGID_ = function(msg, reply, src) {
|
| * Handle a setpgid call.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.handleMessageSetPGID_ = function(msg, reply, src) {
|
| +NaClProcessManager.prototype.handleMessageSetPGID_ = function (msg, reply,
|
| + src) {
|
| var self = this;
|
| function setpgid() {
|
| - var pid = parseInt(msg['pid']) || src.pid;
|
| - var newPgid = parseInt(msg['pgid']) || pid;
|
| + var pid = parseInt(msg.pid, 10) || src.pid;
|
| + var newPgid = parseInt(msg.pgid, 10) || pid;
|
|
|
| if (newPgid < 0) {
|
| return -Errno.EINVAL;
|
| @@ -642,11 +760,11 @@ NaClProcessManager.prototype.handleMessageSetPGID_ = function(msg, reply, src) {
|
| return -Errno.EPERM;
|
| }
|
|
|
| - self.deleteProcessFromGroup_(pid);
|
| + self.deleteProcessFromGroup(pid);
|
| if (self.processGroups[newPgid]) {
|
| self.processGroups[newPgid].processes[pid] = true;
|
| } else {
|
| - self.createProcessGroup_(newPgid, sid);
|
| + self.createProcessGroup(newPgid, sid);
|
| }
|
| self.processes[pid].pgid = newPgid;
|
| return 0;
|
| @@ -660,9 +778,9 @@ NaClProcessManager.prototype.handleMessageSetPGID_ = function(msg, reply, src) {
|
| * Handle a getsid call.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.handleMessageGetSID_ = function(msg, reply, src) {
|
| +NaClProcessManager.prototype.handleMessageGetSID_ = function (msg, reply, src) {
|
| var sid;
|
| - var pid = parseInt(msg['pid']) || src.pid;
|
| + var pid = parseInt(msg.pid, 10) || src.pid;
|
| var process = this.processes[pid];
|
|
|
| if (!process || process.exitCode !== null) {
|
| @@ -679,7 +797,7 @@ NaClProcessManager.prototype.handleMessageGetSID_ = function(msg, reply, src) {
|
| * Handle a setsid call.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.handleMessageSetSID_ = function(msg, reply, src) {
|
| +NaClProcessManager.prototype.handleMessageSetSID_ = function (msg, reply, src) {
|
| var pid = src.pid;
|
| var sid;
|
|
|
| @@ -687,8 +805,8 @@ NaClProcessManager.prototype.handleMessageSetSID_ = function(msg, reply, src) {
|
| if (this.processGroups[pid]) {
|
| sid = -Errno.EPERM;
|
| } else {
|
| - this.deleteProcessFromGroup_(pid);
|
| - this.createProcessGroup_(pid, pid);
|
| + this.deleteProcessFromGroup(pid);
|
| + this.createProcessGroup(pid, pid);
|
| sid = this.processes[pid].pgid = pid;
|
| }
|
|
|
| @@ -701,9 +819,9 @@ NaClProcessManager.prototype.handleMessageSetSID_ = function(msg, reply, src) {
|
| * Handle a javascript invocation.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.handleMessageJSEval_ = function(msg, reply) {
|
| +NaClProcessManager.prototype.handleMessageJSEval_ = function (msg, reply) {
|
| // Using '' + so that undefined can be emitted as a string.
|
| - reply({result: '' + eval(msg['cmd'])});
|
| + reply({result: String(eval(msg.cmd))});
|
| };
|
|
|
| /**
|
| @@ -711,13 +829,14 @@ NaClProcessManager.prototype.handleMessageJSEval_ = function(msg, reply) {
|
| * Used to implement vfork calling _exit.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.handleMessageDeadPid_ = function(msg, reply, src) {
|
| +NaClProcessManager.prototype.handleMessageDeadPid_ = function (msg, reply,
|
| + src) {
|
| var self = this;
|
| // TODO(bradnelson): Avoid needing to frivolously manipulate the DOM to
|
| // generate a dead pid by separating the process data structure manipulation
|
| // parts of spawn + exit from the DOM / module ones.
|
| - self.spawn(null, [], [], '/', 'pnacl', src, function(pid, element) {
|
| - self.exit(msg['status'], element);
|
| + self.spawn(null, [], [], '/', 'pnacl', src, function (pid, element) {
|
| + self.exit(msg.status, element);
|
| reply({pid: pid});
|
| });
|
| };
|
| @@ -725,7 +844,8 @@ NaClProcessManager.prototype.handleMessageDeadPid_ = function(msg, reply, src) {
|
| /**
|
| * Handle a mount filesystem call.
|
| */
|
| -NaClProcessManager.prototype.handleMessageMountFs_ = function(msg, reply, src) {
|
| +NaClProcessManager.prototype.handleMessageMountFs_ = function (msg, reply,
|
| + src) {
|
| if (g_mount.available) {
|
| reply({
|
| filesystem: g_mount.filesystem,
|
| @@ -744,9 +864,9 @@ NaClProcessManager.prototype.handleMessageMountFs_ = function(msg, reply, src) {
|
| * Handle progress event from NaCl.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.handleProgress_ = function(e) {
|
| +NaClProcessManager.prototype.handleProgress_ = function (e) {
|
| e.srcElement.moduleResponded = true;
|
| - if (this.isRootProcess(e.srcElement)) {
|
| + if (this.onRootProgress && this.isRootProcess(e.srcElement)) {
|
| this.onRootProgress(e.url, e.lengthComputable, e.loaded, e.total);
|
| }
|
| };
|
| @@ -755,9 +875,9 @@ NaClProcessManager.prototype.handleProgress_ = function(e) {
|
| * Handle load event from NaCl.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.handleLoad_ = function(e) {
|
| +NaClProcessManager.prototype.handleLoad_ = function (e) {
|
| e.srcElement.moduleResponded = true;
|
| - if (this.isRootProcess(e.srcElement)) {
|
| + if (this.onRootLoad && this.isRootProcess(e.srcElement)) {
|
| this.onRootLoad();
|
| }
|
| };
|
| @@ -766,7 +886,7 @@ NaClProcessManager.prototype.handleLoad_ = function(e) {
|
| * Handle a timeout around module startup.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.handleStartupTimeout_ = function(src) {
|
| +NaClProcessManager.prototype.handleStartupTimeout_ = function (src) {
|
| if (!src.moduleResponded) {
|
| this.exit(NaClProcessManager.EX_NO_EXEC, src);
|
| }
|
| @@ -776,7 +896,7 @@ NaClProcessManager.prototype.handleStartupTimeout_ = function(src) {
|
| * Handle abort event from NaCl.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.handleLoadAbort_ = function(e) {
|
| +NaClProcessManager.prototype.handleLoadAbort_ = function (e) {
|
| e.srcElement.moduleResponded = true;
|
| this.exit(NaClProcessManager.EXIT_CODE_KILL, e.srcElement);
|
| };
|
| @@ -785,9 +905,11 @@ NaClProcessManager.prototype.handleLoadAbort_ = function(e) {
|
| * Handle load error event from NaCl.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.handleLoadError_ = function(e) {
|
| +NaClProcessManager.prototype.handleLoadError_ = function (e) {
|
| e.srcElement.moduleResponded = true;
|
| - this.onError(e.srcElement.commandName, e.srcElement.lastError);
|
| + if (this.onError) {
|
| + this.onError(e.srcElement.commandName, e.srcElement.lastError);
|
| + }
|
| this.exit(NaClProcessManager.EX_NO_EXEC, e.srcElement);
|
| };
|
|
|
| @@ -795,7 +917,7 @@ NaClProcessManager.prototype.handleLoadError_ = function(e) {
|
| * Handle crash event from NaCl.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.handleCrash_ = function(e) {
|
| +NaClProcessManager.prototype.handleCrash_ = function (e) {
|
| e.srcElement.moduleResponded = true;
|
| this.exit(e.srcElement.exitStatus, e.srcElement);
|
| };
|
| @@ -808,9 +930,9 @@ NaClProcessManager.prototype.handleCrash_ = function(e) {
|
| * @param {number} sid The session ID of the session to which the process
|
| * group belongs.
|
| */
|
| -NaClProcessManager.prototype.createProcessGroup_ = function(pid, sid) {
|
| +NaClProcessManager.prototype.createProcessGroup = function (pid, sid) {
|
| if (this.processGroups[pid] !== undefined) {
|
| - throw new Error('createProcessGroup_(): process group already exists');
|
| + throw new Error('createProcessGroup(): process group already exists');
|
| }
|
| this.processGroups[pid] = {
|
| sid: sid,
|
| @@ -825,14 +947,14 @@ NaClProcessManager.prototype.createProcessGroup_ = function(pid, sid) {
|
| * @private
|
| * @param {number} pid The process to be deleted.
|
| */
|
| -NaClProcessManager.prototype.deleteProcessFromGroup_ = function(pid) {
|
| +NaClProcessManager.prototype.deleteProcessFromGroup = function (pid) {
|
| if (this.processes[pid] === undefined) {
|
| - throw new Error('deleteProcessFromGroup_(): process does not exist');
|
| + throw new Error('deleteProcessFromGroup(): process does not exist');
|
| }
|
| var pgid = this.processes[pid].pgid;
|
| if (this.processGroups[pgid] === undefined ||
|
| this.processGroups[pgid].processes[pid] === undefined) {
|
| - throw new Error('deleteProcessFromGroup_(): process group not found');
|
| + throw new Error('deleteProcessFromGroup(): process group not found');
|
| }
|
| delete this.processGroups[pgid].processes[pid];
|
| if (Object.keys(this.processGroups[pgid].processes).length === 0) {
|
| @@ -844,7 +966,7 @@ NaClProcessManager.prototype.deleteProcessFromGroup_ = function(pid) {
|
| * Remove entries for a process from the process table.
|
| * @private
|
| */
|
| -NaClProcessManager.prototype.deleteProcessEntry_ = function(pid) {
|
| +NaClProcessManager.prototype.deleteProcessEntry = function (pid) {
|
| delete this.processes[pid];
|
| };
|
|
|
| @@ -853,31 +975,28 @@ NaClProcessManager.prototype.deleteProcessEntry_ = function(pid) {
|
| * @param {number} code The exit code of the process.
|
| * @param {HTMLObjectElement} element The HTML element of the exited process.
|
| */
|
| -NaClProcessManager.prototype.exit = function(code, element) {
|
| +NaClProcessManager.prototype.exit = function (code, element) {
|
| var pid = element.pid;
|
| var ppid = this.processes[pid].ppid;
|
| var pgid = this.processes[pid].pgid;
|
|
|
| this.pipeServer.deleteProcess(pid);
|
| - this.deleteProcessFromGroup_(pid);
|
| + this.deleteProcessFromGroup(pid);
|
|
|
| // Reply to processes waiting on the exited process.
|
| - var waitersToCheck = [pid, -1, -pgid];
|
| var reaped = false;
|
| var waiters = this.waiters;
|
| - waitersToCheck.forEach(function(currPid) {
|
| + [pid, -1, -pgid].forEach(function (currPid) {
|
| if (waiters[currPid] === undefined) {
|
| return;
|
| }
|
| - var currPidWaiters = waiters[currPid];
|
| - for (var j = 0; j < currPidWaiters.length; j++) {
|
| - var waiter = currPidWaiters[j];
|
| + waiters[currPid].forEach(function (waiter) {
|
| if (waiter.srcPid === ppid) {
|
| waiter.reply(pid, code);
|
| reaped = true;
|
| }
|
| - }
|
| - waiters[currPid] = currPidWaiters.filter(function(waiter) {
|
| + });
|
| + waiters[currPid] = waiters[currPid].filter(function (waiter) {
|
| return waiter.srcPid !== ppid;
|
| });
|
| if (waiters[currPid].length === 0) {
|
| @@ -885,7 +1004,7 @@ NaClProcessManager.prototype.exit = function(code, element) {
|
| }
|
| });
|
| if (reaped) {
|
| - this.deleteProcessEntry_(pid);
|
| + this.deleteProcessEntry(pid);
|
| } else {
|
| this.processes[pid].exitCode = code;
|
| }
|
| @@ -907,8 +1026,9 @@ NaClProcessManager.prototype.exit = function(code, element) {
|
| nextForegroundProcess = element.parent;
|
| // When the parent has already finished, give the control to the
|
| // grand parent.
|
| - while (nextForegroundProcess && nextForegroundProcess.pid === -1)
|
| + while (nextForegroundProcess && nextForegroundProcess.pid === -1) {
|
| nextForegroundProcess = nextForegroundProcess.parent;
|
| + }
|
|
|
| this.foregroundProcess = nextForegroundProcess;
|
| }
|
| @@ -920,17 +1040,15 @@ NaClProcessManager.prototype.exit = function(code, element) {
|
| * @param {object} manifest A manifest to examine.
|
| * @return {string} 'nacl' or 'pnacl' on success, or null on failure..
|
| */
|
| -NaClProcessManager.prototype.checkNaClManifestType_ = function(manifest) {
|
| - if ('program' in manifest) {
|
| - if ('portable' in manifest.program &&
|
| - 'pnacl-translate' in manifest.program.portable) {
|
| +NaClProcessManager.prototype.checkNaClManifestType = function (manifest) {
|
| + if (manifest.hasOwnProperty('program')) {
|
| + if (manifest.program.hasOwnProperty('portable') &&
|
| + manifest.program.portable.hasOwnProperty('pnacl-translate')) {
|
| return 'pnacl';
|
| - } else {
|
| - return 'nacl';
|
| }
|
| - } else {
|
| - return null;
|
| + return 'nacl';
|
| }
|
| + return null;
|
| };
|
|
|
| /**
|
| @@ -940,27 +1058,27 @@ NaClProcessManager.prototype.checkNaClManifestType_ = function(manifest) {
|
| * @callback typeCallback Called with 'nacl' or 'pnacl' on success.
|
| * @callback errorCallback Called with error message on failure.
|
| */
|
| -NaClProcessManager.prototype.checkUrlNaClManifestType = function(
|
| +NaClProcessManager.prototype.checkUrlNaClManifestType = function (
|
| url, typeCallback, errorCallback) {
|
| var self = this;
|
| var request = new XMLHttpRequest();
|
| request.open('GET', url, true);
|
| - request.onload = function() {
|
| + request.onload = function () {
|
| var manifest;
|
| try {
|
| manifest = JSON.parse(request.responseText);
|
| - } catch(e) {
|
| + } catch (e) {
|
| errorCallback('NaCl Manifest is not valid JSON at ' + url);
|
| return;
|
| }
|
| - var kind = self.checkNaClManifestType_(manifest);
|
| + var kind = self.checkNaClManifestType(manifest);
|
| if (kind === null) {
|
| errorCallback('NaCl Manifest has bad format at ' + url);
|
| } else {
|
| typeCallback(kind);
|
| }
|
| };
|
| - request.onerror = function() {
|
| + request.onerror = function () {
|
| errorCallback('NaCl Manifest is unreachable at ' + url);
|
| };
|
| request.send();
|
| @@ -991,19 +1109,21 @@ NaClProcessManager.prototype.checkUrlNaClManifestType = function(
|
| * process.
|
| * @param {spawnCallback} callback.
|
| */
|
| -NaClProcessManager.prototype.spawn = function(
|
| - nmf, argv, envs, cwd, naclType, parent, callback) {
|
| +NaClProcessManager.prototype.spawn = function (
|
| + nmf, argv, envs, cwd, naclType, parent, callback) {
|
| var self = this;
|
|
|
| - getNaClArch(function(arch) {
|
| + getNaClArch(function (arch) {
|
| var mimetype = 'application/x-' + naclType;
|
| if (navigator.mimeTypes[mimetype] === undefined) {
|
| - if (mimetype.indexOf('pnacl') != -1) {
|
| + if (mimetype.indexOf('pnacl') !== -1) {
|
| console.log(
|
| - 'Browser does not support PNaCl or PNaCl is disabled.');
|
| + 'Browser does not support PNaCl or PNaCl is disabled.'
|
| + );
|
| } else {
|
| console.log(
|
| - 'Browser does not support NaCl or NaCl is disabled.');
|
| + 'Browser does not support NaCl or NaCl is disabled.'
|
| + );
|
| }
|
| callback(-Errno.ENOEXEC);
|
| return;
|
| @@ -1019,7 +1139,7 @@ NaClProcessManager.prototype.spawn = function(
|
| self.foregroundProcess = fg;
|
|
|
| fg.pid = self.pid;
|
| - ++self.pid;
|
| + self.pid += 1;
|
|
|
| fg.width = 0;
|
| fg.height = 0;
|
| @@ -1047,54 +1167,55 @@ NaClProcessManager.prototype.spawn = function(
|
| mounted: false,
|
| };
|
| if (!parent) {
|
| - self.createProcessGroup_(fg.pid, fg.pid);
|
| + self.createProcessGroup(fg.pid, fg.pid);
|
| }
|
| self.processGroups[pgid].processes[fg.pid] = true;
|
|
|
| var params = {};
|
| // Default environment variables (can be overridden by envs)
|
| - params['PS_VERBOSITY'] = '2';
|
| - params['TERM'] = 'xterm-256color';
|
| - params['PS_STDIN'] = '/dev/tty';
|
| - params['PS_STDOUT'] = '/dev/tty';
|
| - params['PS_STDERR'] = '/dev/tty';
|
| -
|
| - for (var i = 0; i < envs.length; i++) {
|
| - var env = envs[i];
|
| + params.PS_VERBOSITY = '2';
|
| + params.TERM = 'xterm-256color';
|
| + params.PS_STDIN = '/dev/tty';
|
| + params.PS_STDOUT = '/dev/tty';
|
| + params.PS_STDERR = '/dev/tty';
|
| +
|
| + envs.forEach(function (env) {
|
| var index = env.indexOf('=');
|
| if (index < 0) {
|
| console.error('Broken env: ' + env);
|
| - continue;
|
| + return;
|
| }
|
| var key = env.substring(0, index);
|
| - if (key === 'SRC' || key === 'DATA' || key.match(/^ARG\d+$/i))
|
| - continue;
|
| + if (key === 'SRC' || key === 'DATA' || key.match(/^ARG\d+$/i)) {
|
| + return;
|
| + }
|
| params[key] = env.substring(index + 1);
|
| - }
|
| + });
|
|
|
| // Addition environment variables (these override the incoming env)
|
| - params['PS_TTY_PREFIX'] = NaClProcessManager.prefix;
|
| - params['PS_TTY_RESIZE'] = 'tty_resize';
|
| - params['PS_TTY_COLS'] = self.ttyWidth;
|
| - params['PS_TTY_ROWS'] = self.ttyHeight;
|
| - params['PS_EXIT_MESSAGE'] = 'exited';
|
| - params['LOCATION_ORIGIN'] = location.origin;
|
| - params['PWD'] = cwd;
|
| - params['NACL_PROCESS'] = '1';
|
| - params['NACL_PID'] = fg.pid;
|
| - params['NACL_PPID'] = ppid;
|
| + params.PS_TTY_PREFIX = NaClProcessManager.prefix;
|
| + params.PS_TTY_RESIZE = 'tty_resize';
|
| + params.PS_TTY_COLS = self.ttyWidth;
|
| + params.PS_TTY_ROWS = self.ttyHeight;
|
| + params.PS_EXIT_MESSAGE = 'exited';
|
| + params.LOCATION_ORIGIN = location.origin;
|
| + params.PWD = cwd;
|
| + params.NACL_PROCESS = '1';
|
| + params.NACL_PID = fg.pid;
|
| + params.NACL_PPID = ppid;
|
| if (NaClProcessManager.fsroot !== undefined) {
|
| - params['NACL_HTML5_ROOT'] = NaClProcessManager.fsroot;
|
| + params.NACL_HTML5_ROOT = NaClProcessManager.fsroot;
|
| }
|
|
|
| if (chrome && chrome.runtime && chrome.runtime.getPlatformInfo) {
|
| if (arch === null) {
|
| console.log(
|
| - 'Browser does not support NaCl/PNaCl or is disabled.');
|
| + 'Browser does not support NaCl/PNaCl or is disabled.'
|
| + );
|
| callback(-Errno.ENOEXEC, fg);
|
| return;
|
| }
|
| - params['NACL_ARCH'] = arch;
|
| + params.NACL_ARCH = arch;
|
| }
|
|
|
| function addParam(name, value) {
|
| @@ -1109,9 +1230,9 @@ NaClProcessManager.prototype.spawn = function(
|
| fg.appendChild(param);
|
| }
|
|
|
| - for (var key in params) {
|
| + Object.keys(params).forEach(function (key) {
|
| addParam(key, params[key]);
|
| - }
|
| + });
|
|
|
| // Add ARGV arguments from query parameters.
|
| function parseQuery(query) {
|
| @@ -1120,25 +1241,26 @@ NaClProcessManager.prototype.spawn = function(
|
| }
|
| var splitArgs = query.split('&');
|
| var args = {};
|
| - for (var i = 0; i < splitArgs.length; i++) {
|
| - var keyValue = splitArgs[i].split('=');
|
| + splitArgs.forEach(function (value) {
|
| + var keyValue = value.split('=');
|
| args[decodeURIComponent(keyValue[0])] =
|
| decodeURIComponent(keyValue[1]);
|
| - }
|
| + });
|
| return args;
|
| }
|
| +
|
| var args = parseQuery(document.location.search);
|
| - for (var argname in args) {
|
| + Object.keys(args).forEach(function (argname) {
|
| addParam(argname, args[argname]);
|
| - }
|
| + });
|
|
|
| // If the application has set NaClTerm.argv and there were
|
| // no arguments set in the query parameters then add the default
|
| // NaClTerm.argv arguments.
|
| // TODO(bradnelson): Consider dropping this method of passing in parameters.
|
| - if (args['arg0'] === undefined && args['arg1'] === undefined && argv) {
|
| + if (args.arg0 === undefined && args.arg1 === undefined && argv) {
|
| var argn = 0;
|
| - argv.forEach(function(arg) {
|
| + argv.forEach(function (arg) {
|
| var argname = 'arg' + argn;
|
| addParam(argname, arg);
|
| argn = argn + 1;
|
| @@ -1152,12 +1274,12 @@ NaClProcessManager.prototype.spawn = function(
|
| var popup = new GraphicalPopup(
|
| fg,
|
| parseInt(params[NaClProcessManager.ENV_POPUP_WIDTH] ||
|
| - NaClProcessManager.POPUP_WIDTH_DEFAULT),
|
| + NaClProcessManager.POPUP_WIDTH_DEFAULT, 10),
|
| parseInt(params[NaClProcessManager.ENV_POPUP_HEIGHT] ||
|
| - NaClProcessManager.POPUP_HEIGHT_DEFAULT),
|
| + NaClProcessManager.POPUP_HEIGHT_DEFAULT, 10),
|
| argv[0]
|
| );
|
| - popup.setClosedListener(function() {
|
| + popup.setClosedListener(function () {
|
| self.exit(NaClProcessManager.EXIT_CODE_KILL, popup.process);
|
| GraphicalPopup.focusCurrentWindow();
|
| });
|
| @@ -1181,12 +1303,12 @@ NaClProcessManager.prototype.spawn = function(
|
| }
|
|
|
| // Work around crbug.com/350445
|
| - var junk = fg.offsetTop;
|
| + window.junk = fg.offsetTop;
|
|
|
| // Set a startup timeout to detect the case when running a module
|
| // from html5 storage but nacl is not enabled.
|
| fg.moduleResponded = false;
|
| - setTimeout(function() {
|
| + setTimeout(function () {
|
| self.handleStartupTimeout_(fg);
|
| }, 500);
|
|
|
| @@ -1216,8 +1338,7 @@ NaClProcessManager.prototype.spawn = function(
|
| * @param {number} [srcPid=1] The process PID of the calling process. Assume
|
| * the init process if omitted.
|
| */
|
| -NaClProcessManager.prototype.waitpid = function(pid, options, reply, srcPid) {
|
| - var self = this;
|
| +NaClProcessManager.prototype.waitpid = function (pid, options, reply, srcPid) {
|
| if (srcPid === undefined) {
|
| srcPid = NaClProcessManager.INIT_PID;
|
| }
|
| @@ -1232,7 +1353,7 @@ NaClProcessManager.prototype.waitpid = function(pid, options, reply, srcPid) {
|
| // The specified process has already finished.
|
| if (pid > 0 && this.processes[pid].exitCode !== null) {
|
| var exitCode = this.processes[pid].exitCode;
|
| - this.deleteProcessEntry_(pid);
|
| + this.deleteProcessEntry(pid);
|
| reply(pid, exitCode);
|
| return;
|
| }
|
| @@ -1250,19 +1371,21 @@ NaClProcessManager.prototype.waitpid = function(pid, options, reply, srcPid) {
|
|
|
| if (pid < 0) {
|
| var finishedPid = null;
|
| - for (var processPid in this.processes) {
|
| - var process = this.processes[processPid];
|
| + var that = this;
|
| + Object.keys(this.processes).some(function (processPid) {
|
| + var process = that.processes[processPid];
|
| if (process.exitCode !== null &&
|
| process.ppid === srcPid &&
|
| (pid === -1 || process.pgid === -pid)) {
|
| - finishedPid = parseInt(processPid);
|
| - break;
|
| + finishedPid = parseInt(processPid, 10);
|
| + return true;
|
| }
|
| - }
|
| + return false;
|
| + });
|
|
|
| if (finishedPid !== null) {
|
| reply(finishedPid, this.processes[finishedPid].exitCode);
|
| - this.deleteProcessEntry_(finishedPid);
|
| + this.deleteProcessEntry(finishedPid);
|
| return;
|
| }
|
| }
|
| @@ -1288,7 +1411,7 @@ NaClProcessManager.prototype.waitpid = function(pid, options, reply, srcPid) {
|
| * @param {number} width The width of the terminal.
|
| * @param {number} height The height of the terminal.
|
| */
|
| -NaClProcessManager.prototype.onTerminalResize = function(width, height) {
|
| +NaClProcessManager.prototype.onTerminalResize = function (width, height) {
|
| this.ttyWidth = width;
|
| this.ttyHeight = height;
|
| if (this.foregroundProcess) {
|
| @@ -1300,9 +1423,10 @@ NaClProcessManager.prototype.onTerminalResize = function(width, height) {
|
| * Handle a SIGINT signal.
|
| * @returns {boolean} Whether or not the interrupt succeeded.
|
| */
|
| -NaClProcessManager.prototype.sigint = function() {
|
| - if (!this.foregroundProcess)
|
| +NaClProcessManager.prototype.sigint = function () {
|
| + if (!this.foregroundProcess) {
|
| throw new Error(NaClProcessManager.NO_FG_ERROR);
|
| + }
|
|
|
| // TODO(bradnelson): Change this once we support signals.
|
| // Abort on Control+C, but don't quit bash.
|
| @@ -1322,122 +1446,12 @@ NaClProcessManager.prototype.sigint = function() {
|
| * Send standard input to the foreground process.
|
| * @param {string} str The string to be sent to as stdin.
|
| */
|
| -NaClProcessManager.prototype.sendStdinForeground = function(str) {
|
| - if (!this.foregroundProcess)
|
| +NaClProcessManager.prototype.sendStdinForeground = function (str) {
|
| + if (!this.foregroundProcess) {
|
| throw new Error(NaClProcessManager.NO_FG_ERROR);
|
| + }
|
|
|
| var message = {};
|
| message[NaClProcessManager.prefix] = str;
|
| this.foregroundProcess.postMessage(message);
|
| };
|
| -
|
| -/**
|
| - * This creates a popup that runs a NaCl process inside.
|
| - *
|
| - * @param {Object} process The NaCl process to be run.
|
| - * @param {number} width
|
| - * @param {number} height
|
| - * @param {string} title
|
| - */
|
| -function GraphicalPopup(process, width, height, title) {
|
| - this.process = process || null;
|
| - this.width = width || GraphicalPopup.DEFAULT_WIDTH;
|
| - this.height = height || GraphicalPopup.DEFAULT_HEIGHT;
|
| - this.title = title || '';
|
| - this.win = null;
|
| - this.onClosed = function () {};
|
| -}
|
| -
|
| -/**
|
| - * The default width of the popup.
|
| - * @type {number}
|
| - */
|
| -GraphicalPopup.DEFAULT_WIDTH = 600;
|
| -
|
| -/**
|
| - * The default height of the popup.
|
| - * @type {number}
|
| - */
|
| -GraphicalPopup.DEFAULT_HEIGHT = 400;
|
| -
|
| -/**
|
| - * The (empty) HTML file to which the NaCl module is added.
|
| - * @const
|
| - */
|
| -GraphicalPopup.HTML_FILE = 'graphical.html';
|
| -
|
| -/**
|
| - * Focus the window in which this code is run.
|
| - */
|
| -GraphicalPopup.focusCurrentWindow = function() {
|
| - chrome.app.window.current().focus();
|
| -};
|
| -
|
| -/**
|
| - * This callback is called when the popup is closed.
|
| - * @callback closedCallback
|
| - */
|
| -
|
| -/**
|
| - * Set a function to be called as a callback when the popup is closed.
|
| - * @param {closedCallback} listener
|
| - */
|
| -GraphicalPopup.prototype.setClosedListener = function(listener) {
|
| - if (this.win) {
|
| - throw new Error("Cannot set closed listener after creating window.");
|
| - }
|
| - this.onClosed = listener;
|
| -};
|
| -
|
| -/**
|
| - * Create the window.
|
| - */
|
| -GraphicalPopup.prototype.create = function() {
|
| - var self = this;
|
| - chrome.app.window.create('graphical.html', {
|
| - 'bounds': {
|
| - 'width': self.width,
|
| - 'height': self.height
|
| - },
|
| - }, function(win) {
|
| - var process = self.process;
|
| - var popup = win.contentWindow;
|
| -
|
| - self.win = process.window = win;
|
| -
|
| - popup.document.title = self.title;
|
| -
|
| - popup.addEventListener('load', function() {
|
| - process.style.position = 'absolute';
|
| - process.style.top = '0';
|
| - process.style.left = '0';
|
| - process.style.width = '100%';
|
| - process.style.height = '100%';
|
| - popup.document.body.appendChild(process);
|
| - });
|
| -
|
| - popup.focused = true;
|
| - popup.addEventListener('focus', function() {
|
| - this.focused = true;
|
| - });
|
| - popup.addEventListener('blur', function() {
|
| - this.focused = false;
|
| - });
|
| -
|
| - win.onClosed.addListener(self.onClosed);
|
| - });
|
| -};
|
| -
|
| -/**
|
| - * Close the popup.
|
| - */
|
| -GraphicalPopup.prototype.destroy = function() {
|
| - if (this.win.contentWindow.focused) {
|
| - GraphicalPopup.focusCurrentWindow();
|
| - }
|
| - this.win.onClosed.removeListener(this.onClosed);
|
| - this.win.close();
|
| -
|
| - this.process = null;
|
| - this.win = null;
|
| -};
|
|
|