|
1 | | -const electron = require('electron') |
2 | | -// Module to control application life. |
3 | | -const app = electron.app |
4 | | -// Module to create native browser window. |
5 | | -const BrowserWindow = electron.BrowserWindow |
| 1 | +const { app, BrowserWindow, ipcMain } = require('electron'); |
| 2 | +const path = require('path'); |
| 3 | +const os = require('os'); |
| 4 | +const pty = require('node-pty'); |
6 | 5 |
|
7 | | -const path = require('path') |
8 | | -const url = require('url') |
| 6 | +let mainWindow; |
| 7 | +let ptyProcess; |
9 | 8 |
|
10 | | -// Keep a global reference of the window object, if you don't, the window will |
11 | | -// be closed automatically when the JavaScript object is garbage collected. |
12 | | -let mainWindow |
13 | | - |
14 | | -// node-pty is not yet context aware |
15 | | -app.allowRendererProcessReuse = false; |
16 | | - |
17 | | -function createWindow () { |
18 | | - // Create the browser window. |
| 9 | +function createWindow() { |
19 | 10 | mainWindow = new BrowserWindow({ |
20 | 11 | width: 800, |
21 | 12 | height: 600, |
22 | | - // Node integration is required to run node-pty in the renderer process |
23 | 13 | webPreferences: { |
24 | | - nodeIntegration: true |
| 14 | + preload: path.join(__dirname, 'preload.js'), |
| 15 | + contextIsolation: true, |
| 16 | + nodeIntegration: false |
25 | 17 | } |
26 | | - }) |
| 18 | + }); |
27 | 19 |
|
28 | | - // and load the index.html of the app. |
29 | | - mainWindow.loadURL(url.format({ |
30 | | - pathname: path.join(__dirname, 'index.html'), |
31 | | - protocol: 'file:', |
32 | | - slashes: true |
33 | | - })) |
| 20 | + mainWindow.loadFile('index.html'); |
34 | 21 |
|
35 | | - // Open the DevTools. |
36 | | - // mainWindow.webContents.openDevTools() |
37 | | - |
38 | | - // Emitted when the window is closed. |
39 | | - mainWindow.on('closed', function () { |
40 | | - // Dereference the window object, usually you would store windows |
41 | | - // in an array if your app supports multi windows, this is the time |
42 | | - // when you should delete the corresponding element. |
43 | | - mainWindow = null |
44 | | - }) |
| 22 | + mainWindow.on('closed', () => { |
| 23 | + if (ptyProcess) { |
| 24 | + ptyProcess.kill(); |
| 25 | + ptyProcess = null; |
| 26 | + } |
| 27 | + mainWindow = null; |
| 28 | + }); |
45 | 29 | } |
46 | 30 |
|
47 | | -// This method will be called when Electron has finished |
48 | | -// initialization and is ready to create browser windows. |
49 | | -// Some APIs can only be used after this event occurs. |
50 | | -app.on('ready', createWindow) |
| 31 | +// Handle pty spawn request from renderer |
| 32 | +ipcMain.on('pty-spawn', () => { |
| 33 | + if (ptyProcess) return; |
| 34 | + |
| 35 | + const shell = process.env[os.platform() === 'win32' ? 'COMSPEC' : 'SHELL']; |
| 36 | + ptyProcess = pty.spawn(shell, [], { |
| 37 | + name: 'xterm-256color', |
| 38 | + cols: 80, |
| 39 | + rows: 30, |
| 40 | + cwd: process.env.HOME || process.env.USERPROFILE, |
| 41 | + env: process.env |
| 42 | + }); |
| 43 | + |
| 44 | + ptyProcess.onData(data => { |
| 45 | + if (mainWindow && !mainWindow.isDestroyed()) { |
| 46 | + mainWindow.webContents.send('pty-data', data); |
| 47 | + } |
| 48 | + }); |
| 49 | +}); |
51 | 50 |
|
52 | | -// Quit when all windows are closed. |
53 | | -app.on('window-all-closed', function () { |
54 | | - // On OS X it is common for applications and their menu bar |
55 | | - // to stay active until the user quits explicitly with Cmd + Q |
| 51 | +// Handle pty input from renderer |
| 52 | +ipcMain.on('pty-write', (_, data) => { |
| 53 | + if (ptyProcess) { |
| 54 | + ptyProcess.write(data); |
| 55 | + } |
| 56 | +}); |
| 57 | + |
| 58 | +// Handle resize from renderer |
| 59 | +ipcMain.on('pty-resize', (_, { cols, rows }) => { |
| 60 | + if (ptyProcess) { |
| 61 | + ptyProcess.resize(cols, rows); |
| 62 | + } |
| 63 | +}); |
| 64 | + |
| 65 | +app.whenReady().then(createWindow); |
| 66 | + |
| 67 | +app.on('window-all-closed', () => { |
56 | 68 | if (process.platform !== 'darwin') { |
57 | | - app.quit() |
| 69 | + app.quit(); |
58 | 70 | } |
59 | | -}) |
| 71 | +}); |
60 | 72 |
|
61 | | -app.on('activate', function () { |
62 | | - // On OS X it's common to re-create a window in the app when the |
63 | | - // dock icon is clicked and there are no other windows open. |
| 73 | +app.on('activate', () => { |
64 | 74 | if (mainWindow === null) { |
65 | | - createWindow() |
| 75 | + createWindow(); |
66 | 76 | } |
67 | | -}) |
68 | | - |
69 | | -// In this file you can include the rest of your app's specific main process |
70 | | -// code. You can also put them in separate files and require them here. |
| 77 | +}); |
0 commit comments