示例#1
0
 setTimeout(function() {
   mainWindow.close();
 }, 100);
示例#2
0
 /**
 * @return true if the window is visible
 */
 isVisible () {
   return this.window.isVisible()
 }
 const proxyWindowEvent = (name) => {
   mainWindow.on(name, (...args) => Emitter.sendToGooglePlayMusic(`BrowserWindow:${name}`, ...args));
 };
示例#4
0
 /**
 * Focuses a window
 */
 focus () {
   this.window.focus()
 }
示例#5
0
 /**
 * Hide the app menu
 */
 hideAppMenu () {
   this.window.setMenuBarVisibility(false)
 }
 mainWindow.webContents.on('did-finish-load', () => {
   mainWindow.show();
   mainWindow.focus();
 });
示例#7
0
 /**
 * Shows the window
 */
 show () {
   this.window.show()
 }
示例#8
0
electron.app.on('ready', () => {

  // No menu bar
  electron.Menu.setApplicationMenu(null);

  mainWindow = new electron.BrowserWindow({
    width: 800,
    height: 380,
    useContentSize: true,
    show: false,
    resizable: false,
    fullscreen: false,
    titleBarStyle: 'hidden-inset',
    icon: path.join(__dirname, '..', '..', 'assets', 'icon.png')
  });

  // Prevent flash of white when starting the application
  // https://github.com/atom/electron/issues/2172
  mainWindow.webContents.on('did-finish-load', () => {

    // The flash of white is still present for a very short
    // while after the WebView reports it finished loading
    setTimeout(() => {
      mainWindow.show();
    }, 100);

  });

  mainWindow.on('closed', () => {
    mainWindow = null;
  });

  // For some reason, Electron shortcuts are registered
  // globally, which means that the app listers for shorcuts
  // even if its not currently focused, potentially interferring
  // with shorcuts registered by other applications.
  // As a workaround, we register all shortcuts when the windows
  // gains focus, and unregister them when the windows loses focus.
  // See http://electron.atom.io/docs/api/global-shortcut/

  mainWindow.on('focus', () => {
    electron.globalShortcut.register('CmdOrCtrl+Alt+I', () => {
      mainWindow.webContents.openDevTools({
        mode: 'undocked'
      });
    });
  });

  mainWindow.on('blur', () => {
    electron.globalShortcut.unregisterAll();
  });

  // Prevent external resources from being loaded (like images)
  // when dropping them on the WebView.
  // See https://github.com/electron/electron/issues/5919
  mainWindow.webContents.on('will-navigate', (event) => {
    event.preventDefault();
  });

  mainWindow.loadURL(`file://${path.join(__dirname, 'index.html')}`);
});
示例#9
0
 setTimeout(() => {
   mainWindow.show();
 }, 100);
示例#10
0
 ipcMain.on('shell-window:ready', function (e) {
   var win = BrowserWindow.fromWebContents(e.sender)
   queue.forEach(url => viewManager.create(win, url))
   queue.length = 0
   isLoaded = true
 })
示例#11
0
文件: app.js 项目: elainte/g6
 win.on('close', () => {
   windowBoundsConfig.set('demos', win.getBounds());
 });
示例#12
0
    constructor(mgr, type, opts) {
        super();

        opts = opts || {};

        this._mgr = mgr;
        this._log = log.create(type);
        this.isPrimary = !!opts.primary;
        this.type = type;
        this.isPopup = !!opts.isPopup;
        this.ownerId = opts.ownerId; // the window which creates this new window

        let electronOptions = {
            title: Settings.appName,
            show: false,
            width: 1100,
            height: 720,
            icon: global.icon,
            titleBarStyle: 'hidden-inset', // hidden-inset: more space
            backgroundColor: '#F6F6F6',
            acceptFirstMouse: true,
            darkTheme: true,
            webPreferences: {
                nodeIntegration: false,
                webaudio: true,
                webgl: false,
                webSecurity: false, // necessary to make routing work on file:// protocol for assets in windows and popups. Not webviews!
                textAreasAreResizable: true,
            },
        };

        electronOptions = _.deepExtend(electronOptions, opts.electronOptions);

        this._log.debug('Creating browser window');

        this.window = new BrowserWindow(electronOptions);

        this.webContents = this.window.webContents;

        this.webContents.once('did-finish-load', () => {
            this.isContentReady = true;

            this._log.debug(`Content loaded, id: ${this.id}`);

            if (opts.sendData) {
                if (_.isString(opts.sendData)) {
                    this.send(opts.sendData);
                } else if (_.isObject(opts.sendData)) {
                    for (const key in opts.sendData) {
                        if ({}.hasOwnProperty.call(opts.sendData, key)) {
                            this.send(key, opts.sendData[key]);
                        }
                    }
                }
            }

            if (opts.show) {
                this.show();
            }

            this.emit('ready');
        });


        // prevent droping files
        this.webContents.on('will-navigate', (e) => {
            e.preventDefault();
        });


        this.window.once('closed', () => {
            this._log.debug('Closed');

            this.isShown = false;
            this.isClosed = true;
            this.isContentReady = false;

            this.emit('closed');
        });

        this.window.once('close', (e) => {
            this.emit('close', e);
        });

        this.window.on('show', (e) => {
            this.emit('show', e);
        });

        this.window.on('hide', (e) => {
            this.emit('hide', e);
        });

        if (opts.url) {
            this.load(opts.url);
        }
    }
示例#13
0
const createWindow = () => {
  mainWindow = new BrowserWindow({ width: 800, heitht: 600 });
  mainWindow.loadURL(`file://${ __dirname }/../../index.html`);
  // mainWindow.openDevTools();
  mainWindow.on('closed', () => { mainWindow = null; });
};
示例#14
0
 mainWindow.on('ready-to-show', () => {
   mainWindow.show();
 })
示例#15
0
	win.webContents.on('did-finish-load', function () {
		win.send('shell:load', modulePath);
	});
示例#16
0
app.once('ready', function () {
  // The public API to add/remove extensions.
  BrowserWindow.addExtension = function (srcDirectory) {
    const manifest = getManifestFromPath(srcDirectory)
    if (manifest) {
      loadExtension(manifest)
      for (const webContents of getAllWebContents()) {
        if (isWindowOrWebView(webContents)) {
          loadDevToolsExtensions(webContents, [manifest])
        }
      }
      return manifest.name
    }
  }

  BrowserWindow.removeExtension = function (name) {
    const manifest = manifestNameMap[name]
    if (!manifest) return

    removeBackgroundPages(manifest)
    removeContentScripts(manifest)
    delete manifestMap[manifest.extensionId]
    delete manifestNameMap[name]
  }

  BrowserWindow.getExtensions = function () {
    const extensions = {}
    Object.keys(manifestNameMap).forEach(function (name) {
      const manifest = manifestNameMap[name]
      extensions[name] = { name: manifest.name, version: manifest.version }
    })
    return extensions
  }

  BrowserWindow.addDevToolsExtension = function (srcDirectory) {
    const manifestName = BrowserWindow.addExtension(srcDirectory)
    if (manifestName) {
      devToolsExtensionNames.add(manifestName)
    }
    return manifestName
  }

  BrowserWindow.removeDevToolsExtension = function (name) {
    BrowserWindow.removeExtension(name)
    devToolsExtensionNames.delete(name)
  }

  BrowserWindow.getDevToolsExtensions = function () {
    const extensions = BrowserWindow.getExtensions()
    const devExtensions = {}
    Array.from(devToolsExtensionNames).forEach(function (name) {
      if (!extensions[name]) return
      devExtensions[name] = extensions[name]
    })
    return devExtensions
  }

  // Load persisted extensions.
  loadedDevToolsExtensionsPath = path.join(app.getPath('userData'), 'DevTools Extensions')
  try {
    const loadedDevToolsExtensions = JSON.parse(fs.readFileSync(loadedDevToolsExtensionsPath))
    if (Array.isArray(loadedDevToolsExtensions)) {
      for (const srcDirectory of loadedDevToolsExtensions) {
        // Start background pages and set content scripts.
        BrowserWindow.addDevToolsExtension(srcDirectory)
      }
    }
  } catch (error) {
    if (process.env.ELECTRON_ENABLE_LOGGING && error.code !== 'ENOENT') {
      console.error('Failed to load browser extensions from directory:', loadedDevToolsExtensionsPath)
      console.error(error)
    }
  }
})
app.on('ready', () => {
  mainWindow = new BrowserWindow({
    show: false,
    width: 1024,
    height: 728
  });

  mainWindow.loadURL(`file://${ __dirname }/app/app.html`);

  mainWindow.webContents.on('did-finish-load', () => {
    mainWindow.show();
    mainWindow.focus();
  });

  mainWindow.on('closed', () => {
    mainWindow = null;
  });

  if (process.env.NODE_ENV === 'development') {
    mainWindow.openDevTools();
  }

  if (process.platform === 'darwin') {
    template = [{
      label: 'Electron',
      submenu: [{
        label: 'About ElectronReact',
        selector: 'orderFrontStandardAboutPanel:'
      }, {
        type: 'separator'
      }, {
        label: 'Services',
        submenu: []
      }, {
        type: 'separator'
      }, {
        label: 'Hide ElectronReact',
        accelerator: 'Command+H',
        selector: 'hide:'
      }, {
        label: 'Hide Others',
        accelerator: 'Command+Shift+H',
        selector: 'hideOtherApplications:'
      }, {
        label: 'Show All',
        selector: 'unhideAllApplications:'
      }, {
        type: 'separator'
      }, {
        label: 'Quit',
        accelerator: 'Command+Q',
        click() {
          app.quit();
        }
      }]
    }, {
      label: 'Edit',
      submenu: [{
        label: 'Undo',
        accelerator: 'Command+Z',
        selector: 'undo:'
      }, {
        label: 'Redo',
        accelerator: 'Shift+Command+Z',
        selector: 'redo:'
      }, {
        type: 'separator'
      }, {
        label: 'Cut',
        accelerator: 'Command+X',
        selector: 'cut:'
      }, {
        label: 'Copy',
        accelerator: 'Command+C',
        selector: 'copy:'
      }, {
        label: 'Paste',
        accelerator: 'Command+V',
        selector: 'paste:'
      }, {
        label: 'Select All',
        accelerator: 'Command+A',
        selector: 'selectAll:'
      }]
    }, {
      label: 'View',
      submenu: process.env.NODE_ENV === 'development' ? [{
        label: 'Reload',
        accelerator: 'Command+R',
        click() {
          mainWindow.webContents.reload();
        }
      }, {
        label: 'Toggle Full Screen',
        accelerator: 'Ctrl+Command+F',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen());
        }
      }, {
        label: 'Toggle Developer Tools',
        accelerator: 'Alt+Command+I',
        click() {
          mainWindow.toggleDevTools();
        }
      }] : [{
        label: 'Toggle Full Screen',
        accelerator: 'Ctrl+Command+F',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen());
        }
      }]
    }, {
      label: 'Window',
      submenu: [{
        label: 'Minimize',
        accelerator: 'Command+M',
        selector: 'performMiniaturize:'
      }, {
        label: 'Close',
        accelerator: 'Command+W',
        selector: 'performClose:'
      }, {
        type: 'separator'
      }, {
        label: 'Bring All to Front',
        selector: 'arrangeInFront:'
      }]
    }, {
      label: 'Help',
      submenu: [{
        label: 'Learn More',
        click() {
          shell.openExternal('http://electron.atom.io');
        }
      }, {
        label: 'Documentation',
        click() {
          shell.openExternal('https://github.com/atom/electron/tree/master/docs#readme');
        }
      }, {
        label: 'Community Discussions',
        click() {
          shell.openExternal('https://discuss.atom.io/c/electron');
        }
      }, {
        label: 'Search Issues',
        click() {
          shell.openExternal('https://github.com/atom/electron/issues');
        }
      }]
    }];

    menu = Menu.buildFromTemplate(template);
    Menu.setApplicationMenu(menu);
  } else {
    template = [{
      label: '&File',
      submenu: [{
        label: '&Open',
        accelerator: 'Ctrl+O'
      }, {
        label: '&Close',
        accelerator: 'Ctrl+W',
        click() {
          mainWindow.close();
        }
      }]
    }, {
      label: '&View',
      submenu: process.env.NODE_ENV === 'development' ? [{
        label: '&Reload',
        accelerator: 'Ctrl+R',
        click() {
          mainWindow.webContents.reload();
        }
      }, {
        label: 'Toggle &Full Screen',
        accelerator: 'F11',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen());
        }
      }, {
        label: 'Toggle &Developer Tools',
        accelerator: 'Alt+Ctrl+I',
        click() {
          mainWindow.toggleDevTools();
        }
      }] : [{
        label: 'Toggle &Full Screen',
        accelerator: 'F11',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen());
        }
      }]
    }, {
      label: 'Help',
      submenu: [{
        label: 'Learn More',
        click() {
          shell.openExternal('http://electron.atom.io');
        }
      }, {
        label: 'Documentation',
        click() {
          shell.openExternal('https://github.com/atom/electron/tree/master/docs#readme');
        }
      }, {
        label: 'Community Discussions',
        click() {
          shell.openExternal('https://discuss.atom.io/c/electron');
        }
      }, {
        label: 'Search Issues',
        click() {
          shell.openExternal('https://github.com/atom/electron/issues');
        }
      }]
    }];
    menu = Menu.buildFromTemplate(template);
    mainWindow.setMenu(menu);
  }
});
示例#18
0
 BrowserWindow.removeDevToolsExtension = function (name) {
   BrowserWindow.removeExtension(name)
   devToolsExtensionNames.delete(name)
 }
示例#19
0
  /* ****************************************************************************/
  // Actions
  /* ****************************************************************************/

  /**
  * Closes the window respecting any behaviour modifiers that are set
  */
  close () {
    this.window.close()
  }
示例#20
0
ipcMain.on('editor:panel-dock', ( event, panelID ) => {
  let browserWin = Electron.BrowserWindow.fromWebContents( event.sender );
  let editorWin = Window.find(browserWin);
  _dock( panelID, editorWin );
});
示例#21
0
 /**
 * Hides the window
 */
 hide () {
   this.window.hide()
 }
示例#22
0
const createGuest = function (embedder, url, frameName, options) {
  let guest = frameToGuest[frameName]
  if (frameName && (guest != null)) {
    guest.loadURL(url)
    return guest.id
  }

  // Remember the embedder window's id.
  if (options.webPreferences == null) {
    options.webPreferences = {}
  }
  options.webPreferences.openerId = embedder.id
  guest = new BrowserWindow(options)
  if (!options.webContents || url !== 'about:blank') {
    // We should not call `loadURL` if the window was constructed from an
    // existing webContents(window.open in a sandboxed renderer) and if the url
    // is not 'about:blank'.
    //
    // Navigating to the url when creating the window from an existing
    // webContents would not be necessary(it will navigate there anyway), but
    // apparently there's a bug that allows the child window to be scripted by
    // the opener, even when the child window is from another origin.
    //
    // That's why the second condition(url !== "about:blank") is required: to
    // force `OverrideSiteInstanceForNavigation` to be called and consequently
    // spawn a new renderer if the new window is targeting a different origin.
    //
    // If the URL is "about:blank", then it is very likely that the opener just
    // wants to synchronously script the popup, for example:
    //
    //     let popup = window.open()
    //     popup.document.body.write('<h1>hello</h1>')
    //
    // The above code would not work if a navigation to "about:blank" is done
    // here, since the window would be cleared of all changes in the next tick.
    guest.loadURL(url)
  }

  // When |embedder| is destroyed we should also destroy attached guest, and if
  // guest is closed by user then we should prevent |embedder| from double
  // closing guest.
  const guestId = guest.webContents.id

  const closedByEmbedder = function () {
    guest.removeListener('closed', closedByUser)
    guest.destroy()
  }
  const closedByUser = function () {
    embedder.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_' + guestId)
    embedder.removeListener('render-view-deleted', closedByEmbedder)
  }
  if (!options.webPreferences.sandbox) {
    // These events should only be handled when the guest window is opened by a
    // non-sandboxed renderer for two reasons:
    //
    // - `render-view-deleted` is emitted when the popup is closed by the user,
    //   and that will eventually result in NativeWindow::NotifyWindowClosed
    //   using a dangling pointer since `destroy()` would have been called by
    //   `closeByEmbedded`
    // - No need to emit `ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_` since
    //   there's no renderer code listening to it.,
    embedder.once('render-view-deleted', closedByEmbedder)
    guest.once('closed', closedByUser)
  }

  if (frameName) {
    frameToGuest[frameName] = guest
    guest.frameName = frameName
    guest.once('closed', function () {
      delete frameToGuest[frameName]
    })
  }

  return guestId
}
示例#23
0
	/**
	* Show the app menu
	*/
  showAppMenu () {
    this.window.setMenuBarVisibility(true)
  }
示例#24
0
 const closedByEmbedder = function () {
   guest.removeListener('closed', closedByUser)
   guest.destroy()
 }
示例#25
0
 /**
 * @return true if the window is focused
 */
 isFocused () {
   return this.window.isFocused()
 }
示例#26
0
文件: etcher.js 项目: lmcro/etcher
electron.app.on('ready', () => {
  // No menu bar
  electron.Menu.setApplicationMenu(null)

  mainWindow = new electron.BrowserWindow({
    width: 800,
    height: 380,
    useContentSize: true,
    show: false,
    resizable: false,
    fullscreen: false,
    titleBarStyle: 'hidden-inset',
    icon: path.join(__dirname, '..', '..', 'assets', 'icon.png')
  })

  // Prevent flash of white when starting the application
  mainWindow.on('ready-to-show', mainWindow.show)

  mainWindow.on('closed', () => {
    mainWindow = null
  })

  // For some reason, Electron shortcuts are registered
  // globally, which means that the app listers for shorcuts
  // even if its not currently focused, potentially interferring
  // with shorcuts registered by other applications.
  // As a workaround, we register all shortcuts when the windows
  // gains focus, and unregister them when the windows loses focus.
  // See http://electron.atom.io/docs/api/global-shortcut/

  mainWindow.on('focus', () => {
    electron.globalShortcut.register('CmdOrCtrl+Alt+I', () => {
      mainWindow.webContents.openDevTools({
        mode: 'detach'
      })
    })

    // Disable refreshing the browser window
    // This is supposed to be handled by the `will-navigate`
    // event, however there seems to be an issue where such
    // event is not fired in macOS
    // See: https://github.com/electron/electron/issues/8841
    electron.globalShortcut.register('CmdOrCtrl+R', _.noop)
    electron.globalShortcut.register('F5', _.noop)
  })

  mainWindow.on('blur', () => {
    electron.globalShortcut.unregisterAll()
  })

  // Prevent the user from being allowed to zoom-in the application.
  //
  // This function should be called on the renderer process. We use
  // `executeJavaScript()` rather than moving this to a file in the
  // renderer process for convenience, since we have all other
  // electron desktop experience fixes in this file.
  //
  // See https://github.com/electron/electron/issues/3609
  mainWindow.webContents.executeJavaScript('require(\'electron\').webFrame.setZoomLevelLimits(1, 1);')

  // Prevent external resources from being loaded (like images)
  // when dropping them on the WebView.
  // See https://github.com/electron/electron/issues/5919
  mainWindow.webContents.on('will-navigate', (event) => {
    event.preventDefault()
  })

  mainWindow.loadURL(`file://${path.join(__dirname, 'index.html')}`)
})
示例#27
0
 /**
 * Sets the download progress
 * @param v: the download progress to set
 */
 setProgressBar (v) {
   this.window.setProgressBar(v)
 }
示例#28
0
文件: main.js 项目: anlun214/LayaAir
 setTimeout(function(){
     win.destroy()
     var a = getNLSConfiguration();
     process.env.VSCODE_NLS_CONFIG = JSON.stringify(a), require("./bootstrap-amd").bootstrap("vs/workbench/electron-main/main")
 },2000)
示例#29
0
electron.app.on('ready', function () {
  var mainWindow = new electron.BrowserWindow({width: 600, height: 800})
  mainWindow.loadURL(path.join('file://', __dirname, '/index.html'))
})
示例#30
0
  function createWindow(fn, options = {}) {
    let cfg = plugins.getDecoratedConfig();

    const winSet = config.getWin();
    let [startX, startY] = winSet.position;

    const [width, height] = options.size ? options.size : (cfg.windowSize || winSet.size);
    const {screen} = require('electron');

    const winPos = options.position;

    // Open the new window roughly the height of the header away from the
    // previous window. This also ensures in multi monitor setups that the
    // new terminal is on the correct screen.
    const focusedWindow = BrowserWindow.getFocusedWindow() || app.getLastFocusedWindow();
    // In case of options defaults position and size, we should ignore the focusedWindow.
    if (winPos !== undefined) {
      [startX, startY] = winPos;
    } else if (focusedWindow) {
      const points = focusedWindow.getPosition();
      const currentScreen = screen.getDisplayNearestPoint({x: points[0], y: points[1]});

      const biggestX = ((points[0] + 100 + width) - currentScreen.bounds.x);
      const biggestY = ((points[1] + 100 + height) - currentScreen.bounds.y);

      if (biggestX > currentScreen.size.width) {
        startX = 50;
      } else {
        startX = points[0] + 34;
      }
      if (biggestY > currentScreen.size.height) {
        startY = 50;
      } else {
        startY = points[1] + 34;
      }
    }

    const browserDefaults = {
      width,
      height,
      minHeight: 190,
      minWidth: 370,
      titleBarStyle: 'hidden-inset', // macOS only
      title: 'Hyper.app',
      backgroundColor: toElectronBackgroundColor(cfg.backgroundColor || '#000'),
      // we want to go frameless on windows and linux
      frame: process.platform === 'darwin',
      transparent: process.platform === 'darwin',
      icon: resolve(__dirname, 'static/icon.png'),
      // we only want to show when the prompt is ready for user input
      // HYPERTERM_DEBUG for backwards compatibility with hyperterm
      show: process.env.HYPER_DEBUG || process.env.HYPERTERM_DEBUG || isDev,
      x: startX,
      y: startY,
      acceptFirstMouse: true
    };
    const browserOptions = plugins.getDecoratedBrowserOptions(browserDefaults);

    const win = new BrowserWindow(browserOptions);
    windowSet.add(win);

    win.loadURL(url);

    const rpc = createRPC(win);
    const sessions = new Map();

    // config changes
    const cfgUnsubscribe = config.subscribe(() => {
      const cfg_ = plugins.getDecoratedConfig();

      // notify renderer
      win.webContents.send('config change');

      // notify user that shell changes require new sessions
      if (cfg_.shell !== cfg.shell ||
        JSON.stringify(cfg_.shellArgs) !== JSON.stringify(cfg.shellArgs)) {
        notify(
          'Shell configuration changed!',
          'Open a new tab or window to start using the new shell'
        );
      }

      // update background color if necessary
      cfg = cfg_;
    });

    rpc.on('init', () => {
      // we update the backgroundColor once the init is called.
      // when we do a win.reload() we need need to reset the backgroundColor
      win.setBackgroundColor(toElectronBackgroundColor(cfg.backgroundColor || '#000'));
      win.show();

      // If no callback is passed to createWindow,
      // a new session will be created by default.
      if (!fn) {
        fn = win => win.rpc.emit('termgroup add req');
      }

      // app.windowCallback is the createWindow callback
      // that can be set before the 'ready' app event
      // and createWindow deifinition. It's executed in place of
      // the callback passed as parameter, and deleted right after.
      (app.windowCallback || fn)(win);
      delete (app.windowCallback);

      fetchNotifications(win);
      // auto updates
      if (!isDev && process.platform !== 'linux') {
        AutoUpdater(win);
      } else {
        console.log('ignoring auto updates during dev');
      }
    });

    rpc.on('new', ({rows = 40, cols = 100, cwd = process.argv[1] && isAbsolute(process.argv[1]) ? process.argv[1] : homedir(), splitDirection}) => {
      const shell = cfg.shell;
      const shellArgs = cfg.shellArgs && Array.from(cfg.shellArgs);

      initSession({rows, cols, cwd, shell, shellArgs}, (uid, session) => {
        sessions.set(uid, session);
        rpc.emit('session add', {
          rows,
          cols,
          uid,
          splitDirection,
          shell: session.shell,
          pid: session.pty.pid
        });

        session.on('data', data => {
          rpc.emit('session data', uid + data);
        });

        session.on('exit', () => {
          rpc.emit('session exit', {uid});
          sessions.delete(uid);
        });
      });
    });

    rpc.on('exit', ({uid}) => {
      const session = sessions.get(uid);
      if (session) {
        session.exit();
      } else {
        console.log('session not found by', uid);
      }
    });

    rpc.on('unmaximize', () => {
      win.unmaximize();
    });

    rpc.on('maximize', () => {
      win.maximize();
    });

    rpc.on('resize', ({uid, cols, rows}) => {
      const session = sessions.get(uid);
      session.resize({cols, rows});
    });

    rpc.on('data', ({uid, data, escaped}) => {
      const session = sessions.get(uid);

      if (escaped) {
        const escapedData = session.shell.endsWith('cmd.exe') ?
        `"${data}"` : // This is how cmd.exe does it
        `'${data.replace(/'/g, `'\\''`)}'`; // Inside a single-quoted string nothing is interpreted

        session.write(escapedData);
      } else {
        session.write(data);
      }
    });

    rpc.on('open external', ({url}) => {
      shell.openExternal(url);
    });

    rpc.win.on('move', () => {
      rpc.emit('move');
    });

    rpc.on('open hamburger menu', ({x, y}) => {
      Menu.getApplicationMenu().popup(Math.ceil(x), Math.ceil(y));
    });

    rpc.on('minimize', () => {
      win.minimize();
    });

    rpc.on('close', () => {
      win.close();
    });

    const deleteSessions = () => {
      sessions.forEach((session, key) => {
        session.removeAllListeners();
        session.destroy();
        sessions.delete(key);
      });
    };

    // we reset the rpc channel only upon
    // subsequent refreshes (ie: F5)
    let i = 0;
    win.webContents.on('did-navigate', () => {
      if (i++) {
        deleteSessions();
      }
    });

    // If file is dropped onto the terminal window, navigate event is prevented
    // and his path is added to active session.
    win.webContents.on('will-navigate', (event, url) => {
      const protocol = typeof url === 'string' && parseUrl(url).protocol;
      if (protocol === 'file:') {
        event.preventDefault();

        const path = fileUriToPath(url);

        rpc.emit('session data send', {data: path, escaped: true});
      } else if (protocol === 'http:' || protocol === 'https:') {
        event.preventDefault();
        rpc.emit('session data send', {data: url});
      }
    });

    // expose internals to extension authors
    win.rpc = rpc;
    win.sessions = sessions;

    const load = () => {
      plugins.onWindow(win);
    };

    // load plugins
    load();

    const pluginsUnsubscribe = plugins.subscribe(err => {
      if (!err) {
        load();
        win.webContents.send('plugins change');
      }
    });

    // Keep track of focus time of every window, to figure out
    // which one of the existing window is the last focused.
    // Works nicely even if a window is closed and removed.
    const updateFocusTime = () => {
      win.focusTime = process.uptime();
    };
    win.on('focus', () => {
      updateFocusTime();
    });
    // Ensure focusTime is set on window open. The focus event doesn't
    // fire from the dock (see bug #583)
    updateFocusTime();

    // the window can be closed by the browser process itself
    win.on('close', () => {
      config.winRecord(win);
      windowSet.delete(win);
      rpc.destroy();
      deleteSessions();
      cfgUnsubscribe();
      pluginsUnsubscribe();
    });

    // Same deal as above, grabbing the window titlebar when the window
    // is maximized on Windows results in unmaximize, without hitting any
    // app buttons
    for (const ev of ['maximize', 'unmaximize', 'minimize', 'restore']) {
      win.on(ev, () => rpc.emit('windowGeometry change'));
    }

    win.on('closed', () => {
      if (process.platform !== 'darwin' && windowSet.size === 0) {
        app.quit();
      }
    });
  }