/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { setTimeout } from "resource://gre/modules/Timer.sys.mjs"; import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; // Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref. // See LOG_LEVELS in Console.sys.mjs. Common examples: "All", "Info", "Warn", & // "Error". const PREF_LOG_LEVEL = "extensions.mozscreenshots@mozilla.org.loglevel"; const lazy = {}; XPCOMUtils.defineLazyGetter(lazy, "log", () => { let { ConsoleAPI } = ChromeUtils.importESModule( "resource://gre/modules/Console.sys.mjs" ); let consoleOptions = { maxLogLevel: "info", maxLogLevelPref: PREF_LOG_LEVEL, prefix: "mozscreenshots", }; return new ConsoleAPI(consoleOptions); }); export var Screenshot = { _extensionPath: null, _path: null, _imagePrefix: "", _imageExtension: ".png", _screenshotFunction: null, init(path, extensionPath, imagePrefix = "") { this._path = path; let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); dir.initWithPath(this._path); if (!dir.exists()) { dir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755); } this._extensionPath = extensionPath; this._imagePrefix = imagePrefix; switch (Services.appinfo.OS) { case "WINNT": this._screenshotFunction = this._screenshotWindows; break; case "Darwin": this._screenshotFunction = this._screenshotOSX; break; case "Linux": this._screenshotFunction = this._screenshotLinux; break; default: throw new Error("Unsupported operating system"); } }, _buildImagePath(baseName) { return PathUtils.join( this._path, this._imagePrefix + baseName + this._imageExtension ); }, // Capture the whole screen using an external application. async captureExternal(filename) { let imagePath = this._buildImagePath(filename); await this._screenshotFunction(imagePath); lazy.log.debug("saved screenshot: " + filename); return imagePath; }, // helpers _screenshotWindows(filename) { return new Promise((resolve, reject) => { let exe = Services.dirsvc.get("GreBinD", Ci.nsIFile); exe.append("screenshot.exe"); if (!exe.exists()) { exe = Services.dirsvc.get("CurWorkD", Ci.nsIFile).parent; exe.append("bin"); exe.append("screenshot.exe"); } let process = Cc["@mozilla.org/process/util;1"].createInstance( Ci.nsIProcess ); process.init(exe); let args = [filename]; process.runAsync( args, args.length, this._processObserver(resolve, reject) ); }); }, async _screenshotOSX(filename) { let screencapture = (windowID = null) => { return new Promise((resolve, reject) => { // Get the screencapture executable let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); file.initWithPath("/usr/sbin/screencapture"); let process = Cc["@mozilla.org/process/util;1"].createInstance( Ci.nsIProcess ); process.init(file); // Run the process. let args = ["-x", "-t", "png"]; args.push(filename); process.runAsync( args, args.length, this._processObserver(resolve, reject) ); }); }; function readWindowID() { return IOUtils.readUTF8("/tmp/mozscreenshots-windowid"); } let promiseWindowID = () => { return new Promise((resolve, reject) => { // Get the window ID of the application (assuming its front-most) let osascript = Cc["@mozilla.org/file/local;1"].createInstance( Ci.nsIFile ); osascript.initWithPath("/bin/bash"); let osascriptP = Cc["@mozilla.org/process/util;1"].createInstance( Ci.nsIProcess ); osascriptP.init(osascript); let osaArgs = [ "-c", "/usr/bin/osascript -e 'tell application (path to frontmost application as text) to set winID to id of window 1' > /tmp/mozscreenshots-windowid", ]; osascriptP.runAsync( osaArgs, osaArgs.length, this._processObserver(resolve, reject) ); }); }; await promiseWindowID(); let windowID = await readWindowID(); await screencapture(windowID); }, _screenshotLinux(filename) { return new Promise((resolve, reject) => { let exe = Services.dirsvc.get("GreBinD", Ci.nsIFile); exe.append("screentopng"); if (!exe.exists()) { exe = Services.dirsvc.get("CurWorkD", Ci.nsIFile).parent; exe.append("bin"); exe.append("screentopng"); } let process = Cc["@mozilla.org/process/util;1"].createInstance( Ci.nsIProcess ); process.init(exe); let args = [filename]; process.runAsync( args, args.length, this._processObserver(resolve, reject) ); }); }, _processObserver(resolve, reject) { return { observe(subject, topic, data) { switch (topic) { case "process-finished": try { // Wait 1s after process to resolve setTimeout(resolve, 1000); } catch (ex) { reject(ex); } break; default: reject(topic); break; } }, }; }, };