Source: background/ss_controller.js

/*
 *  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(() => {});
    },
  };
})();