/*
* Copyright (c) 2015-2017, Michael A. Updike All rights reserved.
* Licensed under the BSD-3-Clause
* https://opensource.org/licenses/BSD-3-Clause
* https://github.com/opus1269/photo-screen-saver/blob/master/LICENSE.md
*/
window.app = window.app || {};
/**
* Controller for the screen saver
* @namespace
*/
app.SSControl = (function() {
'use strict';
new ExceptionHandler();
const chromep = new ChromePromise();
/**
* Screensaver URL
* @type {string}
* @const
* @private
* @memberOf app.SSControl
*/
const _SS_URL = '/html/screensaver.html';
/**
* Error showing Screensaver
* @type {string}
* @const
* @private
* @memberOf app.SSControl
*/
const _ERR_SHOW = Chrome.Locale.localize('err_show_ss');
/**
* Determine if there is a full screen chrome window running on a display
* @param {Object} display - a connected display
* @returns {Promise<boolean>} true if there is a full screen
* window on the display
* @private
* @memberOf app.SSControl
*/
function _hasFullscreen(display) {
if (Chrome.Storage.getBool('chromeFullscreen')) {
return chromep.windows.getAll({populate: false}).then((wins) => {
let ret = false;
const left = display ? display.bounds.left : 0;
const top = display ? display.bounds.top : 0;
for (let i = 0; i < wins.length; i++) {
const win = wins[i];
if ((win.state === 'fullscreen') &&
(!display || (win.top === top && win.left === left))) {
ret = true;
break;
}
}
return Promise.resolve(ret);
});
} else {
return Promise.resolve(false);
}
}
/**
* Determine if the screen saver is currently showing
* @returns {Promise<boolean>} true if showing
* @private
* @memberOf app.SSControl
*/
function _isShowing() {
// send message to the screensaver to see if he is around
return Chrome.Msg.send(app.Msg.SS_IS_SHOWING).then(() => {
return Promise.resolve(true);
}).catch(() => {
// no one listening
return Promise.resolve(false);
});
}
/**
* Open a screen saver window on the given display
* @param {Object} display - a connected display
* @private
* @memberOf app.SSControl
*/
function _open(display) {
// window creation options
const winOpts = {
url: _SS_URL,
focused: true,
type: 'popup',
};
_hasFullscreen(display).then((isTrue) => {
if (isTrue) {
// don't display if there is a fullscreen window
return null;
}
if (Chrome.Utils.getChromeVersion() >= 44 && !display) {
// Chrome supports fullscreen option on create since version 44
winOpts.state = 'fullscreen';
} else {
const left = display ? display.bounds.left : 0;
const top = display ? display.bounds.top : 0;
winOpts.left = left;
winOpts.top = top;
winOpts.width = 1;
winOpts.height = 1;
}
return chromep.windows.create(winOpts);
}).then((win) => {
if (win && (winOpts.state !== 'fullscreen')) {
chrome.windows.update(win.id, {state: 'fullscreen'});
}
return null;
}).catch((err) => {
Chrome.Log.error(err.message, 'SSControl._open', _ERR_SHOW);
});
}
/**
* Open a screensaver on every display
* @private
* @memberOf app.SSControl
*/
function _openOnAllDisplays() {
chromep.system.display.getInfo().then((displayArr) => {
if (displayArr.length === 1) {
_open(null);
} else {
for (const display of displayArr) {
_open(display);
}
}
return Promise.resolve();
}).catch((err) => {
Chrome.Log.error(err.message, 'SSControl._openOnAllDisplays', _ERR_SHOW);
});
}
/**
* Event: Fired when the system changes to an active, idle or locked state.
* The event fires with "locked" if the screen is locked or the screensaver
* activates, "idle" if the system is unlocked and the user has not
* generated any input for a specified number of seconds, and "active"
* when the user generates input on an idle system.
* @see https://developer.chrome.com/extensions/idle#event-onStateChanged
* @param {string} state - current state of computer
* @private
* @memberOf app.SSControl
*/
function _onIdleStateChanged(state) {
_isShowing().then((isShowing) => {
if (state === 'idle') {
if (app.Alarm.isActive() && !isShowing) {
app.SSControl.display(false);
}
return Promise.resolve();
} else {
// eslint-disable-next-line promise/no-nesting
return Chrome.Utils.isWindows().then((isTrue) => {
if (!isTrue) {
// Windows 10 Creators triggers an 'active' state
// when the window is created, so we have to skip closing here.
// Wouldn't need this at all if ChromeOS handled keyboard right
app.SSControl.close();
}
return Promise.resolve();
});
}
}).catch((err) => {
Chrome.Log.error(err.message, 'SSControl._isShowing', _ERR_SHOW);
});
}
// noinspection JSUnusedLocalSymbols
/**
* Event: Fired when a message is sent from either an extension process<br>
* (by runtime.sendMessage) or a content script (by tabs.sendMessage).
* @see https://developer.chrome.com/extensions/runtime#event-onMessage
* @param {Chrome.Msg.Message} request - details for the message
* @param {Object} [sender] - MessageSender object
* @param {Function} [response] - function to call once after processing
* @returns {boolean} true if asynchronous
* @private
* @memberOf app.SSControl
*/
function _onChromeMessage(request, sender, response) {
if (request.message === app.Msg.SS_SHOW.message) {
// preview the screensaver
app.SSControl.display(true);
}
return false;
}
// listen for changes to the idle state of the computer
chrome.idle.onStateChanged.addListener(_onIdleStateChanged);
// listen for chrome messages
Chrome.Msg.listen(_onChromeMessage);
return {
/**
* Display the screen saver(s)
* !Important: Always request screensaver through this call
* @param {boolean} single - if true, only show on one display
* @memberOf app.SSControl
*/
display: function(single) {
if (!single && Chrome.Storage.getBool('allDisplays')) {
_openOnAllDisplays();
} else {
_open(null);
}
},
/**
* Close all the screen saver windows
* @memberOf app.SSControl
*/
close: function() {
// send message to the screen savers to close themselves
Chrome.Msg.send(app.Msg.SS_CLOSE).catch(() => {});
},
};
})();