nw-skeleton

Source: app-wrapper/js/lib/windowManager.js

/**
 * @fileOverview WindowManager class file
 * @author Dino Ivankov <dinoivankov@gmail.com>
 * @version 1.3.1
 */

const _ = require('lodash');
const AppBaseClass = require('./appBase').AppBaseClass;

let _appWrapper;
var appState;

/**
 * WindowManager class - for managing windows in application
 *
 * @class
 * @extends {appWrapper.AppBaseClass}
 * @memberOf appWrapper
 *
 * @property {window}           win                 Reference to nwjs Window object
 * @property {window}           window              Reference to window object
 * @property {document}         document            Reference to document object
 * @property {Number}           screenWidth         Value to store screen width value
 * @property {Number}           screenHeight        Value to store screen height value
 */
class WindowManager extends AppBaseClass {

    /**
     * Creates WindowManager instance
     *
     * @constructor
     * @return {WindowManager}              Instance of WindowManager class
     */
    constructor(){
        super();

        _appWrapper = window.getAppWrapper();
        appState = _appWrapper.getAppState();

        this.win = nw.Window.get();
        this.window = this.win.window;
        this.document = this.win.window.document;

        this.screenWidth = null;
        this.screenHeight = null;

        this.boundMethods = {
            minimizeWindow: null,
            toggleMaximize: null,
            reloadWindow: null,
            toggleDevTools: null,
            closeWindow: null,
            toggleFullScreen: null,
            dragWindow: null,
            moveWindowMousedown: null,
            moveWindowMouseup: null,
            winStateChanged: null,
            windowRestored: null,
            windowResize: null,
            windowBlur: null,
            windowFocus: null,
            beforeUnload: null,
            mouseMoveHandler: null,
        };

        this.timeouts = {
            resize: null,
            showHeader: null,
        };

        this.headerTimer = null;

        this.ignoreResize = false;

        this.initWinState();
    }

    /**
     * Initializes WindowManager object
     *
     * @async
     * @return {WindowManager} Instance of WindowManager class
     */
    async initialize(){
        await super.initialize();
        await this.initWindow();
        this.addEventListeners();
        return this;
    }

    /**
     * Adds event listeners for the WindowManager instance
     *
     * @return {undefined}
     */
    addEventListeners () {
        this.on('winStateChange', this.boundMethods.winStateChanged);
        this.win.on('restore', this.boundMethods.windowRestored);
        this.window.addEventListener('resize', this.boundMethods.windowResize);
        this.window.addEventListener('blur', this.boundMethods.windowBlur);
        this.window.addEventListener('focus', this.boundMethods.windowFocus);
        this.window.addEventListener('beforeunload', this.boundMethods.beforeUnload);
        this.window.addEventListener('mousemove', this.boundMethods.mouseMoveHandler);
    }

    /**
     * Removes event listeners for the WindowManager instance
     *
     * @return {undefined}
     */
    removeEventListeners () {
        this.removeListener('winStateChange', this.boundMethods.winStateChanged);
        this.win.removeListener('restore', this.boundMethods.windowRestored);
        this.window.removeEventListener('resize', this.boundMethods.windowResize);
        this.window.removeEventListener('blur', this.boundMethods.windowBlur);
        this.window.removeEventListener('focus', this.boundMethods.windowFocus);
        this.window.removeEventListener('beforeunload', this.boundMethods.beforeUnload);
        this.window.removeEventListener('mousemove', this.boundMethods.mouseMoveHandler);

        Object.keys(this.boundMethods).forEach((key) => {
            this.boundMethods[key] = null;
        });

        this.boundMethods = null;
    }

    /**
     * Gets winState object
     *
     * @return {Object} winState object
     */
    getWinState (){
        return this.winState;
    }

    /**
     * Sets winState object
     *
     * @param {Object} winState New winState object
     * @return {undefined}
     */
    setWinState (winState) {
        this.winState = winState;
    }

    /**
     * Listener for winState changes
     *
     * @param  {Object} data Changeds in winState object ( properties: name and value )
     * @return {undefined}
     */
    winStateChanged (data) {
        this.log('WindowManager: winState changed listener: "{1}" to "{2}"', 'debug', [data.name, data.value]);
        appState.windowState[data.name] = data.value;
    }

    /**
     * Handler for window restored event
     *
     * @return {undefined}
     */
    windowRestored (){
        if (this.winState && this.winState.length && this.propagateChange && this.propagateChange.length){
            this.propagateChange.maximized = false;
            this.winState.maximized = false;
            this.propagateChange.maximized = true;
            this.propagateChange.minimized = false;
            this.winState.minimized = false;
            this.propagateChange.minimized = true;
        }
        if (appState && appState.length && appState.windowState && appState.windowState.length){
            appState.windowState.minimized = false;
            appState.windowState.maximized = false;
        }
    }

    /**
     * Initializes window for the application
     *
     * @async
     * @return {boolean} Window initialization result
     */
    async initWindow () {
        var returnPromise;
        var resolveReference;
        returnPromise = new Promise((resolve) => {
            resolveReference = resolve;
        });
        nw.Screen.Init();
        this.screenWidth = nw.Screen.screens[0].bounds.width;
        this.screenHeight = nw.Screen.screens[0].bounds.height;
        var appW = parseInt(this.screenWidth * 0.50, 10);
        var appH = parseInt(this.screenHeight * 0.66, 10);
        var windowPosition = 'center';
        var windowLeft;
        var windowTop;

        if (appState.isDebugWindow){
            appW = 550;
            appH = 400;
            windowPosition = '';
        } else {
            if (appState.config.appConfig.windowConfig){
                if (appState.config.appConfig.windowConfig.width){
                    appW = appState.config.appConfig.windowConfig.width;
                }
                if (appState.config.appConfig.windowConfig.height){
                    appH = appState.config.appConfig.windowConfig.height;
                }
                if (appState.config.appConfig.windowConfig.left){
                    windowLeft = appState.config.appConfig.windowConfig.left;
                }
                if (appState.config.appConfig.windowConfig.top){
                    windowTop = appState.config.appConfig.windowConfig.top;
                }
            }
        }

        if (appState.config.debug.enabled){
            this.document.body.className = this.document.body.className + ' nw-body-debug';
        }

        setTimeout(() => {
            this.winState.width = appW;
            this.winState.height = appH;
            if (appState.config.debug.enabled){
                if (appState.isDebugWindow){
                    this.winState.x = 0;
                    this.winState.y = 0;
                } else {
                    if (windowLeft && windowTop){
                        this.winState.x = windowLeft;
                        this.winState.y = windowTop;
                    } else {
                        this.winState.x = this.screenWidth - (this.winState.width + 5);
                    }
                    // if (this.getConfig('appConfig.windowConfig.fullscreen') != this.winState.fullscreen){
                    //     this.win.toggleFullscreen();
                    // }
                }
                // this.document.body.className = this.document.body.className + ' nw-body-initialized';
                // this.win.focus();
                // this.window.focus();
            } else {
                if (appState.isDebugWindow){
                    this.winState.x = 0;
                    this.winState.y = 0;
                } else {
                    if (windowLeft && windowTop){
                        this.winState.x = windowLeft;
                        this.winState.y = windowTop;
                    } else {
                        if (windowPosition){
                            this.winState.position = windowPosition;
                        } else {
                            this.winState.x = this.screenWidth - (this.winState.width + 5);
                        }
                    }
                    // if (this.getConfig('appConfig.windowConfig.fullscreen') != this.winState.fullscreen){
                    //     this.win.toggleFullscreen();
                    // }
                }
            }
            this.document.body.className = this.document.body.className + ' nw-body-initialized';
            resolveReference(true);
        }, 200);
        return returnPromise;
    }

    /**
     * Initializes winState object
     *
     * @return {undefined}
     */
    initWinState () {
        var self = this;

        var propertiesEnumerable = true;
        var propertiesConfigurable = false;

        var localState = {
            title: '',
            position: '',
            x: 0,
            y: 0,
            maximized: false,
            minimized: false,
            devTools: false,
            showInTaskbar: false,
            resizable: false,
            menu: false,
            icon: false,
            transparent: false,
            show: true,
            kiosk: false,
            frame: false,
            fullscreen: false,
            width: 0,
            height: 0
        };

        this.listeningStatus = {};
        this.propagateChange = {};
        Object.keys(localState).forEach((item) => {
            this.listeningStatus[item] = true;
            this.propagateChange[item] = true;
        });

        var properties =  {
            title: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.title;
                },
                set: (value) => {
                    localState.title = value;
                    if (this.listeningStatus.title){
                        this.emit('winStateChange', { name: 'title', value: value});
                    }
                    if (this.propagateChange.title){
                        this.win.title = localState.title;
                    }
                }
            },
            position: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.position;
                },
                set: (value) => {
                    localState.position = value;
                    if (this.listeningStatus.position){
                        this.emit('winStateChange', { name: 'position', value: value});
                    }
                    if (this.propagateChange.position){
                        this.win.setPosition(localState.position);
                    }
                }
            },
            x: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.x;
                },
                set: (value) => {
                    localState.x = value;
                    if (this.listeningStatus.x){
                        this.emit('winStateChange', { name: 'x', value: value});
                    }
                    if (this.propagateChange.x){
                        this.win.moveTo(localState.x, localState.y);
                    }
                }
            },
            y: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.y;
                },
                set: (value) => {
                    localState.y = value;
                    if (this.listeningStatus.y){
                        this.emit('winStateChange', { name: 'y', value: value});
                    }
                    if (this.propagateChange.y){
                        this.win.moveTo(localState.x, localState.y);
                    }
                }
            },
            minimized: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.minimized;
                },
                set: (value) => {
                    localState.minimized = value;
                    if (this.listeningStatus.minimized){
                        this.emit('winStateChange', { name: 'minimized', value: value});
                    }
                    if (this.propagateChange.minimized){
                        if (value){
                            self.win.minimize();
                        } else {
                            self.win.restore();
                        }
                    }
                }
            },
            maximized: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.maximized;
                },
                set: (value) => {
                    localState.maximized = value;
                    if (this.listeningStatus.maximized){
                        this.emit('winStateChange', { name: 'maximized', value: value});
                    }
                    if (this.propagateChange.maximized){
                        if (value){
                            self.win.maximize();
                        } else {
                            self.win.restore();
                        }
                    }
                }
            },
            devTools: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.devTools;
                },
                set: (value) => {
                    localState.devTools = value;
                    if (this.listeningStatus.devTools){
                        this.emit('winStateChange', { name: 'devTools', value: value});
                    }
                    if (this.propagateChange.devTools){
                        if (!value){
                            this.win.closeDevTools();
                            appState.status.devToolsOpened = false;
                        } else {
                            this.win.showDevTools();
                            appState.status.devToolsOpened = true;
                        }
                    }
                }
            },
            showInTaskbar: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.showInTaskbar;
                },
                set: (value) => {
                    localState.showInTaskbar = value;
                    if (this.listeningStatus.showInTaskbar){
                        this.emit('winStateChange', { name: 'showInTaskbar', value: value});
                    }
                    if (this.propagateChange.showInTaskbar) {
                        _.noop();
                    }
                }
            },
            resizable: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.resizable;
                },
                set: (value) => {
                    localState.resizable = value;
                    if (this.listeningStatus.resizable){
                        this.emit('winStateChange', { name: 'resizable', value: value});
                    }
                    if (this.propagateChange.resizable){
                        _.noop();
                    }
                }
            },
            menu: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.menu;
                },
                set: (value) => {
                    localState.menu = value;
                    if (this.listeningStatus.menu){
                        this.emit('winStateChange', { name: 'menu', value: value});
                    }
                    if (this.propagateChange.menu){
                        _.noop();
                    }
                }
            },
            icon: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.icon;
                },
                set: (value) => {
                    localState.icon = value;
                    if (this.listeningStatus.icon){
                        this.emit('winStateChange', { name: 'icon', value: value});
                    }
                    if (this.propagateChange.icon){
                        _.noop();
                    }
                }
            },
            transparent: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.transparent;
                },
                set: (value) => {
                    localState.transparent = value;
                    if (this.listeningStatus.transparent){
                        this.emit('winStateChange', { name: 'transparent', value: value});
                    }
                    if (this.propagateChange.transparent){
                        _.noop();
                    }
                }
            },
            show: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.show;
                },
                set: (value) => {
                    localState.show = value;
                    if (this.listeningStatus.show){
                        this.emit('winStateChange', { name: 'show', value: value});
                    }
                    if (this.propagateChange.show){
                        this.win.show(localState.show);
                    }
                }
            },
            kiosk: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.kiosk;
                },
                set: (value) => {
                    localState.kiosk = value;
                    if (this.listeningStatus.kiosk){
                        this.emit('winStateChange', { name: 'kiosk', value: value});
                    }
                    if (this.propagateChange.kiosk){
                        _.noop();
                    }
                }
            },
            frame: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.frame;
                },
                set: (value) => {
                    localState.frame = value;
                    if (this.listeningStatus.frame){
                        this.emit('winStateChange', { name: 'frame', value: value});
                    }
                    if (this.propagateChange.frame){
                        _.noop();
                    }
                }
            },
            fullscreen: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.fullscreen;
                },
                set: (value) => {
                    localState.fullscreen = value;
                    if (this.listeningStatus.fullscreen){
                        this.emit('winStateChange', { name: 'fullscreen', value: value});
                    }
                    if (this.propagateChange.fullscreen){
                        // if (this.winState.maximized){
                        //     this.toggleMaximize();
                        // }
                        self.win.toggleFullscreen();
                    }
                }
            },
            width: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.width;
                },
                set: (value) => {
                    localState.width = value;
                    if (this.listeningStatus.width){
                        this.emit('winStateChange', { name: 'width', value: value});
                    }
                    if (this.propagateChange.width){
                        this.win.resizeTo(localState.width, localState.height);
                    }
                }
            },
            height: {
                enumerable: propertiesEnumerable,
                configurable: propertiesConfigurable,
                get: () => {
                    return localState.height;
                },
                set: (value) => {
                    localState.height = value;
                    if (this.listeningStatus.height){
                        this.emit('winStateChange', { name: 'height', value: value});
                    }
                    if (this.propagateChange.height){
                        this.win.resizeTo(localState.width, localState.height);
                    }
                }
            }
        };
        this.winState = Object.create(Object, properties);
    }

    /**
     * Handler for minimize window event
     *
     * @param  {Event} e Event that triggered the method
     * @return {undefined}
     */
    minimizeWindow (e) {
        if (e && e.preventDefault && _.isFunction(e.preventDefault)){
            e.preventDefault();
        }
        // this.propagateChange.maximized = false;
        // this.winState.maximized = false;
        // this.propagateChange.maximized = true;

        this.winState.minimized = !this.winState.minimized;
    }

    /**
     * Toggles window maximized state on or off
     *
     * @param  {Event} e Event that triggered the method
     * @return {undefined}
     */
    toggleMaximize (e) {
        if (e && e.preventDefault && _.isFunction(e.preventDefault)){
            e.preventDefault();
        }
        this.ignoreResize = true;
        this.propagateChange.minimized = false;
        this.winState.minimized = false;
        this.propagateChange.minimized = true;
        this.winState.maximized = !this.winState.maximized;
    }

    /**
     * Handler for maximize window event
     *
     * @param  {Event} e Event that triggered the method
     * @return {undefined}
     */
    maximizeWindow (e) {
        if (e && e.preventDefault && _.isFunction(e.preventDefault)){
            e.preventDefault();
        }
        if (!this.winState.maximized){
            this.toggleMaximize();
        }
    }

    /**
     * Handler for restore window event
     *
     * @param  {Event} e Event that triggered the method
     * @return {undefined}
     */
    restoreWindow (e) {
        if (e && e.preventDefault && _.isFunction(e.preventDefault)){
            e.preventDefault();
        }
        if (this.winState.maximized){
            this.toggleMaximize();
        }
    }

    /**
     * Reloads application window
     *
     * @param  {Event} e            Event that triggered the method
     * @param  {boolean} force      Flag to indicate whether to force reload
     * @param  {string} message     Message to display to user
     * @return {undefined}
     */
    reloadWindow (e, force, message) {
        if (e && e.preventDefault && _.isFunction(e.preventDefault)){
            e.preventDefault();
        }
        if (appState.preventReload){
            return false;
        }

        if (!force){
            this.win.window.getAppWrapper().beforeUnload();
        } else {
            if (!message){
                message = _appWrapper.appTranslations.translate('Please wait while application restarts...');
            }
            appState.mainLoaderTitle = message;
            appState.status.appShuttingDown = true;
            this.win.reload();
        }
    }

    /**
     * Handler for toggleDevTools window event
     *
     * @param  {Event} e Event that triggered the method
     * @return {undefined}
     */
    toggleDevTools (e) {
        if (e && e.preventDefault && _.isFunction(e.preventDefault)){
            e.preventDefault();
        }
        this.winState.devTools = !this.winState.devTools;
    }

    /**
     * Handler for toggleFullscreen window event
     *
     * @param  {Event} e Event that triggered the method
     * @return {undefined}
     */
    toggleFullScreen (e) {
        if (e && e.preventDefault && _.isFunction(e.preventDefault)){
            e.preventDefault();
        }
        this.ignoreResize = true;
        this.winState.fullscreen =! this.winState.fullscreen;
        // _appWrapper.appConfig.setConfigVar('appConfig.windowConfig.fullscreen', this.winState.fullscreen);
    }

    /**
     * Handler for window closing links
     *
     * @param  {Event} e Event that triggered the method
     * @return {undefined}
     */
    closeWindow (e) {
        if (e && e.preventDefault && _.isFunction(e.preventDefault)){
            e.preventDefault();
        }
        if (!appState.preventClose){
            this.win.close();
        }
    }

    /**
     * Handler for forced window closing links
     *
     * @param  {Event} e Event that triggered the method
     * @return {undefined}
     */
    closeWindowForce (e) {
        if (e && e.preventDefault && _.isFunction(e.preventDefault)){
            e.preventDefault();
        }
        if (!appState.preventClose){
            this.win.close(true);
        }
    }

    /**
     * Closes window by window reference
     *
     * @param  {window} newWindow Window reference
     * @return {undefined}
     */
    closeNewWindow(newWindow){
        return nw.Window.get(newWindow).close();
    }

    /**
     * Handler for mousedown event on 'move' window control link
     *
     * @param  {Event} e Event that triggered the method
     * @return {undefined}
     */
    moveWindowMousedown (e) {
        if (e && e.preventDefault && _.isFunction(e.preventDefault)){
            e.preventDefault();
        }
        appState.status.movingWindow = true;
        this.window.addEventListener('mousemove', this.boundMethods.dragWindow);
        this.window.addEventListener('mouseup', this.boundMethods.moveWindowMouseup);
    }

    /**
     * Handler for mouseup event on 'move' window control link
     *
     * @param  {Event} e Event that triggered the method
     * @return {undefined}
     */
    moveWindowMouseup (e) {
        if (e && e.preventDefault && _.isFunction(e.preventDefault)){
            e.preventDefault();
        }
        appState.status.movingWindow = false;
        this.window.removeEventListener('mousemove', this.boundMethods.dragWindow);
        this.window.removeEventListener('mouseup', this.boundMethods.moveWindowMouseup);
        this.windowPositionSizeUpdated();
    }

    /**
     * Handler for mousemove event on 'move' window control link
     *
     * @param  {Event} e Event that triggered the method
     * @return {undefined}
     */
    dragWindow (e) {
        var link = this.window.document.querySelector('.window-control-move');
        /* link offset position to body */
        var offsetPosition = link.getAbsolutePosition();
        /* azimuths are half of link widths/heights */
        var widthAzimuth = -parseInt(link.parentNode.offsetWidth/2, 10);
        var heightAzimuth = -parseInt(link.parentNode.offsetHeight/2, 10);
        /* mouse pointer position */
        var screenX = e.screenX;
        var screenY = e.screenY;
        /* mouse pointer position */
        var windowX = screenX - offsetPosition.offsetLeft + widthAzimuth;
        var windowY = screenY - offsetPosition.offsetTop + heightAzimuth;
        this.win.moveTo(windowX, windowY);
    }

    /**
     * Beforeunload method called before window unloads
     *
     * @return {undefined}
     */
    beforeUnload (){
        this.document.body.className = this.document.body.className.replace(/nw-body-initialized/, '');
        this.removeEventListeners();

    }

    /**
     * Opens new window - see {@link http://docs.nwjs.io/en/latest/References/Window/#windowopenurl-options-callback}
     *
     * @param  {string} url     Url to open
     * @param  {Object} options New window options
     * @return {window}         Reference to new window
     */
    openNewWindow(url, options){
        window._newWindow = nw.Window.open(url, options);
        return window._newWindow;
    }

    /**
     * Sets window menu
     *
     * @param {Object} menu Menu definition - see {@link http://docs.nwjs.io/en/latest/References/Menu/}
     * @return {undefined}
     */
    setMenu (menu) {
        nw.Window.get().menu = menu;
    }

    /**
     * Handler for resize window event
     *
     * @return {undefined}
     */
    windowResize () {
        clearTimeout(this.timeouts.resize);
        this.timeouts.resize = setTimeout( () => {
            if (!this.ignoreResize){
                if (this.winState.maximized){
                    this.winState.maximized = false;
                }
                this.windowPositionSizeUpdated();
            } else {
                this.ignoreResize = false;
            }
        }, this.getConfig('longPauseDuration'));
    }

    /**
     * Handler called when window position or size are updated. Saves current position and/or size to userConfig
     *
     * @return {undefined}
     */
    windowPositionSizeUpdated () {
        clearTimeout(this.timeouts.resize);
        let newWidth = window.outerWidth;
        let newHeight = window.outerHeight;
        let newLeft = window.screenLeft;
        let newTop = window.screenTop;
        if (appState.status.appInitialized && !this.winState.fullscreen && !this.winState.maximized){
            let config = _.cloneDeep(appState.config.appConfig.windowConfig);
            let configChanged = false;
            if (newWidth && newWidth > 100){
                config.width = newWidth;
                configChanged = true;
            }
            if (newHeight && newHeight > 100){
                config.height = newHeight;
                configChanged = true;
            }
            if (newLeft && newLeft > 0){
                config.left = newLeft;
                configChanged = true;
            }
            if (newTop && newTop > 0){
                config.top = newTop;
                configChanged = true;
            }
            if (configChanged){
                appState.config.appConfig.windowConfig = config;
            }
        }
    }

    /**
     * Handler for window blur event
     *
     * @return {undefined}
     */
    windowBlur (){
        appState.status.windowFocused = false;
        _appWrapper.emit('window:blur');
    }

    /**
     * Handler for window focus event
     *
     * @return {undefined}
     */
    windowFocus (){
        appState.status.windowFocused = true;
        _appWrapper.emit('window:focus');
    }

    /**
     * Shows main window
     *
     * @return {undefined}
     */
    showWindow () {
        this.win.show();
        this.focusWindow();
    }

    /**
     * Hides main window
     *
     * @return {undefined}
     */
    hideWindow () {
        this.win.hide();
    }

    /**
     * Handles mouseMove event and shows or hides header based on config
     *
     * @param  {Event} e Event that triggered the handler
     * @return {undefined}
     */
    mouseMoveHandler (e) {
        if (this.getConfig('appConfig.hideFullscreenHeader') && this.getStateVar('windowState.fullscreen')){
            clearTimeout(this.timeouts.showHeader);
            let yPosition = e.clientY;
            if (!this.headerTimer){
                this.headerTimer = +new Date();
            }
            let headerDelay = + new Date() - this.headerTimer;
            if (yPosition <= 30){
                if (headerDelay > 1000) {
                    clearTimeout(this.timeouts.showHeader);
                    this.headerTimer = null;
                    if (appState.appBodyClasses.indexOf('show-header') == -1){
                        appState.appBodyClasses.push('show-header');
                    }
                }
                this.timeouts.showHeader = setTimeout( () => {
                    this.headerTimer = null;
                    if (appState.appBodyClasses.indexOf('show-header') == -1){
                        appState.appBodyClasses.push('show-header');
                    }
                }, 1000);
            } else {
                if (headerDelay > 2000) {
                    if (!document.querySelectorAll('.window-controls-wrapper .menu-opened').length){
                        clearTimeout(this.timeouts.showHeader);
                        this.headerTimer = null;
                        appState.appBodyClasses = _.without(appState.appBodyClasses, 'show-header');
                    }
                }
                this.timeouts.showHeader = setTimeout( () => {
                    if (!document.querySelectorAll('.window-controls-wrapper .menu-opened').length){
                        this.headerTimer = null;
                        appState.appBodyClasses = _.without(appState.appBodyClasses, 'show-header');
                    }
                }, 2000);
            }
        }
    }

    /**
     * Focuses main window
     *
     * @return {undefined}
     */
    focusWindow () {
        this.win.focus();
        this.window.focus();
    }
}

exports.WindowManager = WindowManager;