diff --git a/lib/gui/app/app.js b/lib/gui/app/app.js index e37f8684..24b6df34 100644 --- a/lib/gui/app/app.js +++ b/lib/gui/app/app.js @@ -45,6 +45,7 @@ const driveScanner = require('./modules/drive-scanner') const osDialog = require('./os/dialog') const exceptionReporter = require('./modules/exception-reporter') const updateLock = require('./modules/update-lock') +const screensaver = require('./modules/screensaver') /* eslint-disable lodash/prefer-lodash-method,lodash/prefer-get */ @@ -506,3 +507,5 @@ angular.element(document).ready(() => { angular.bootstrap(document, [ 'Etcher' ]) }).catch(exceptionReporter.report) }) + +screensaver.init() diff --git a/lib/gui/app/modules/screensaver.ts b/lib/gui/app/modules/screensaver.ts new file mode 100644 index 00000000..b42cd7cc --- /dev/null +++ b/lib/gui/app/modules/screensaver.ts @@ -0,0 +1,63 @@ +/* + * Copyright 2019 resin.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { execFile } from 'child_process'; +import { promisify } from 'util'; + +const execFileAsync = promisify(execFile); +const EVENT_TYPES = [ + 'focus', + 'keydown', + 'keyup', + 'pointerdown', + 'pointermove', + 'pointerup', +] as const; +const SCREENSAVER_DELAY = 30 * 1000; // TODO: make this configurable + +function exec( + command: string, + ...args: string[] +): Promise<{ stdout: string; stderr: string }> { + return execFileAsync(command, args); +} + +async function screenOff(): Promise { + await exec('xset', 'dpms', 'force', 'suspend'); +} + +async function ledsOn(): Promise { + // TODO +} + +async function ledsOff(): Promise { + // TODO +} + +async function off() { + await Promise.all([ledsOff(), screenOff()]); +} + +export function init(): void { + let timeout = setTimeout(screenOff, SCREENSAVER_DELAY); + for (const eventType of EVENT_TYPES) { + addEventListener(eventType, async () => { + clearTimeout(timeout); + timeout = setTimeout(off, SCREENSAVER_DELAY); + await ledsOn(); + }); + } +} diff --git a/lib/gui/app/pages/settings/controllers/settings.js b/lib/gui/app/pages/settings/controllers/settings.js index 21f4cf1b..62f79685 100644 --- a/lib/gui/app/pages/settings/controllers/settings.js +++ b/lib/gui/app/pages/settings/controllers/settings.js @@ -120,4 +120,19 @@ module.exports = function (WarningModalService) { this.shouldShowUnsafeMode = () => { return !settings.get('disableUnsafeMode') } + + /** + * @summary Show the enableScreensaver setting + * @function + * @public + * + * @returns {Boolean} + * + * + * @example + * SettingsController.shouldShowEnableScreensaver() + */ + this.shouldShowEnableScreensaver = () => { + return settings.get('showEnableScreensaver') + } } diff --git a/lib/gui/app/pages/settings/templates/settings.tpl.html b/lib/gui/app/pages/settings/templates/settings.tpl.html index 5a0a5d64..917b13d5 100644 --- a/lib/gui/app/pages/settings/templates/settings.tpl.html +++ b/lib/gui/app/pages/settings/templates/settings.tpl.html @@ -77,4 +77,14 @@ Unsafe mode Dangerous + +
+ +
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index da16190a..bc7881dd 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1054,9 +1054,9 @@ "dev": true }, "@types/node": { - "version": "6.14.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-6.14.3.tgz", - "integrity": "sha512-V2VrQBCKo4U0rni6tW4AASRDqIO5ZTLDN/Xzrm4mNBr9SGQYZ+7zZJn+hMs89Q8ZCIHzp4aWQPyCpK+rux1YGA==" + "version": "10.14.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.9.tgz", + "integrity": "sha512-NelG/dSahlXYtSoVPErrp06tYFrvzj8XLWmKA+X8x0W//4MqbUyZu++giUG/v0bjAT6/Qxa8IjodrfdACyb0Fg==" }, "@types/optimist": { "version": "0.0.29", @@ -5500,6 +5500,13 @@ "unzip-stream": "^0.3.0", "xxhash": "github:balena-io-modules/node-xxhash#70ac31da1a41c6f8c53d931b5802c6c93f7b6b83", "yauzl": "^2.9.2" + }, + "dependencies": { + "@types/node": { + "version": "6.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.14.6.tgz", + "integrity": "sha512-rFs9zCFtSHuseiNXxYxFlun8ibu+jtZPgRM+2ILCmeLiGeGLiIGxuOzD+cNyHegI1GD+da3R/cIbs9+xCLp13w==" + } } }, "event-emitter": { @@ -8670,6 +8677,13 @@ "@types/usb": "^1.5.1", "debug": "^3.1.0", "usb": "github:resin-io/node-usb#1.3.6" + }, + "dependencies": { + "@types/node": { + "version": "6.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.14.6.tgz", + "integrity": "sha512-rFs9zCFtSHuseiNXxYxFlun8ibu+jtZPgRM+2ILCmeLiGeGLiIGxuOzD+cNyHegI1GD+da3R/cIbs9+xCLp13w==" + } } }, "node-releases": { diff --git a/package.json b/package.json index 774c3cbc..58ebb495 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "@babel/plugin-proposal-function-bind": "^7.2.0", "@babel/preset-env": "^7.2.0", "@babel/preset-react": "^7.0.0", + "@types/node": "^10.14.9", "@types/react-dom": "^16.8.4", "acorn": "^6.0.5", "angular-mocks": "1.7.6", @@ -117,9 +118,9 @@ "simple-progress-webpack-plugin": "^1.1.2", "spectron": "^5.0.0", "style-loader": "^0.23.1", - "webpack": "^4.31.0", "ts-loader": "^6.0.2", "typescript": "^3.5.1", + "webpack": "^4.31.0", "webpack-cli": "^3.1.2", "webpack-node-externals": "^1.7.2" } diff --git a/tsconfig.json b/tsconfig.json index 0cd1d5fd..d99d78fd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,6 +11,7 @@ }, "include": [ "lib/**/*.ts", + "node_modules/electron/**/*.d.ts", "typings/**/*.d.ts" ] }