main.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. 'use strict';
  2. const os = require('os');
  3. const electron = require('electron');
  4. const electronLocalshortcut = require('electron-localshortcut');
  5. const core = require('./core');
  6. const cmd = require('./cmd');
  7. const config = require('./config/config');
  8. const constants = require('./config/constants');
  9. const menu = require('./components/menu');
  10. const tray = require('./components/tray');
  11. const file = require('./lib/file');
  12. const page = require('./lib/page');
  13. const websocket = require('./lib/websocket');
  14. const process = require('./lib/process');
  15. const ipcRender = require('./ipc/render-proecss');
  16. require('./ipc/main-process');
  17. const app = electron.app;
  18. const BrowserWindow = electron.BrowserWindow;
  19. const singletonLock = app.requestSingleInstanceLock({
  20. argv: cmd.argv
  21. });
  22. let isEnableCloseToHide = function() {
  23. return (tray.isEnabled() || os.platform() === 'darwin') && config.minimizedToTray;
  24. };
  25. let executeCustomCommand = function () {
  26. const options = {
  27. command: config.execCommandOnStartup,
  28. args: config.execCommandArgumentsOnStartup,
  29. detached: config.execDetachedCommandOnStartup,
  30. };
  31. options.onoutput = function (output) {
  32. if (!core.isDevMode) {
  33. return;
  34. }
  35. const lastOutput = (core.startupCommandOutput.length > 1 ? core.startupCommandOutput[core.startupCommandOutput.length - 1] : null);
  36. if (lastOutput && lastOutput.source === output.source && lastOutput.content === output.content) {
  37. lastOutput.count++
  38. } else {
  39. if (core.startupCommandOutput.length >= constants.startupCommandConstants.outputLogLimit) {
  40. core.startupCommandOutput.shift();
  41. }
  42. core.startupCommandOutput.push({
  43. time: new Date(),
  44. type: 'output',
  45. source: output.source,
  46. content: output.content,
  47. count: output.count
  48. });
  49. }
  50. };
  51. options.onerror = function (error) {
  52. if (!core.isDevMode) {
  53. return;
  54. }
  55. if (core.startupCommandOutput.length >= constants.startupCommandConstants.outputLogLimit) {
  56. core.startupCommandOutput.shift();
  57. }
  58. core.startupCommandOutput.push({
  59. time: new Date(),
  60. type: 'error',
  61. source: error.type,
  62. content: error.error
  63. });
  64. };
  65. process.execCommandAsync(options);
  66. };
  67. let setWindowPositionAndSize = function () {
  68. let displays = electron.screen.getAllDisplays();
  69. let isLastPositionInScreen = false;
  70. if (config.x >= 0 && config.y >= 0) {
  71. for (let i = 0; i < displays.length; i++) {
  72. let x1 = displays[i].bounds.x;
  73. let x2 = x1 + displays[i].workAreaSize.width;
  74. let y1 = displays[i].bounds.y;
  75. let y2 = y1 + displays[i].workAreaSize.height;
  76. if (config.x >= x1 && config.x <= x2 && config.y >= y1 && config.y <= y2) {
  77. isLastPositionInScreen = true;
  78. break;
  79. }
  80. }
  81. }
  82. if (config.defaultPosition === 'last-position' && isLastPositionInScreen) {
  83. core.mainWindow.setPosition(config.x, config.y);
  84. } else if (config.defaultPosition === 'screen-center') {
  85. core.mainWindow.center();
  86. }
  87. if (config.maximized) {
  88. core.mainWindow.maximize();
  89. }
  90. };
  91. let registerDevToolShortcut = function () {
  92. electronLocalshortcut.register(core.mainWindow, 'F12', () => {
  93. if (core.isDevMode) {
  94. core.mainWindow.webContents.openDevTools();
  95. }
  96. });
  97. if (os.platform() === 'darwin') {
  98. electronLocalshortcut.register(core.mainWindow, 'Cmd+Alt+I', () => {
  99. if (core.isDevMode) {
  100. core.mainWindow.webContents.openDevTools();
  101. }
  102. });
  103. }
  104. };
  105. let main = function () {
  106. if (!singletonLock) {
  107. app.quit();
  108. return;
  109. }
  110. app.setAppUserModelId(core.appid);
  111. core.isDevMode = !app.isPackaged || !!cmd.argv.development;
  112. core.useCustomAppTitle = os.platform() === 'win32' && !cmd.argv.classic;
  113. const minimalWindow = !!cmd.argv.minimal;
  114. let filePathInCommandLine = cmd.argv.file;
  115. if (os.platform() === 'darwin') {
  116. app.on('will-finish-launching', () => {
  117. app.on('open-file', (event, filePath) => {
  118. event.preventDefault();
  119. if (!filePath) {
  120. return;
  121. }
  122. if (core.mainWindow && core.mainWindow.webContents) {
  123. let location = page.parseLocationFromFullUrl(core.mainWindow.webContents.getURL());
  124. if (location.indexOf('/new') === 0) {
  125. ipcRender.notifyRenderProcessNewTaskFromFile(filePath);
  126. } else {
  127. ipcRender.notifyRenderProcessNewNewTaskFromFileAfterViewLoaded(filePath);
  128. ipcRender.notifyRenderProcessNavigateToNewTask();
  129. }
  130. } else {
  131. filePathInCommandLine = filePath;
  132. }
  133. });
  134. });
  135. app.on('before-quit', () => {
  136. core.isConfirmExit = true;
  137. });
  138. app.on('activate', () => {
  139. if (core.mainWindow) {
  140. core.mainWindow.show();
  141. }
  142. });
  143. }
  144. if (config.execCommandOnStartup) {
  145. executeCustomCommand();
  146. }
  147. app.on('window-all-closed', () => {
  148. app.quit();
  149. });
  150. app.on('second-instance', (event, argv, workingDirectory, additionalData) => {
  151. if (core.mainWindow) {
  152. if (core.mainWindow.isMinimized()) {
  153. core.mainWindow.restore();
  154. } else if (!core.mainWindow.isVisible()) {
  155. core.mainWindow.show();
  156. }
  157. core.mainWindow.focus();
  158. let secondInstanceArgv = null;
  159. if (additionalData) {
  160. secondInstanceArgv = additionalData.argv;
  161. }
  162. if (!secondInstanceArgv) {
  163. secondInstanceArgv = cmd.parseArguments(argv);
  164. }
  165. if (secondInstanceArgv && secondInstanceArgv.development) {
  166. core.isDevMode = !!secondInstanceArgv.development;
  167. ipcRender.notifyRenderProcessChangeDevMode(core.isDevMode);
  168. }
  169. if (secondInstanceArgv && secondInstanceArgv.file && file.isContainsSupportedFileArg(secondInstanceArgv.file)) {
  170. let location = '';
  171. if (core.mainWindow.webContents) {
  172. location = page.parseLocationFromFullUrl(core.mainWindow.webContents.getURL());
  173. }
  174. if (location.indexOf('/new') === 0) {
  175. ipcRender.notifyRenderProcessNewTaskFromFile(secondInstanceArgv.file);
  176. } else {
  177. ipcRender.notifyRenderProcessNewNewTaskFromFileAfterViewLoaded(secondInstanceArgv.file);
  178. ipcRender.notifyRenderProcessNavigateToNewTask();
  179. }
  180. }
  181. }
  182. });
  183. app.on('ready', () => {
  184. core.mainWindow = new BrowserWindow({
  185. title: 'AriaNg Native',
  186. width: config.width,
  187. height: config.height,
  188. minWidth: 800,
  189. minHeight: 400,
  190. fullscreenable: false,
  191. titleBarStyle: core.useCustomAppTitle ? 'hidden' : undefined,
  192. titleBarOverlay: core.useCustomAppTitle,
  193. frame: !core.useCustomAppTitle,
  194. show: false,
  195. webPreferences: {
  196. nodeIntegration: true,
  197. contextIsolation: false,
  198. spellcheck: false
  199. }
  200. });
  201. setWindowPositionAndSize();
  202. registerDevToolShortcut();
  203. menu.init();
  204. tray.init();
  205. if (file.isContainsSupportedFileArg(filePathInCommandLine)) {
  206. ipcRender.notifyRenderProcessNewNewTaskFromFileAfterViewLoaded(filePathInCommandLine);
  207. core.mainWindow.loadURL(page.getPageFullUrl(constants.ariaNgPageLocations.NewTask));
  208. } else {
  209. core.mainWindow.loadURL(page.getPageFullUrl());
  210. }
  211. core.mainWindow.once('ready-to-show', () => {
  212. if (!minimalWindow) {
  213. core.mainWindow.show();
  214. }
  215. });
  216. core.mainWindow.on('resize', () => {
  217. let sizes = core.mainWindow.getSize();
  218. config.width = sizes[0];
  219. config.height = sizes[1];
  220. });
  221. core.mainWindow.on('maximize', () => {
  222. config.maximized = core.mainWindow.isMaximized();
  223. });
  224. core.mainWindow.on('unmaximize', () => {
  225. config.maximized = core.mainWindow.isMaximized();
  226. });
  227. core.mainWindow.on('move', () => {
  228. let positions = core.mainWindow.getPosition();
  229. config.x = positions[0];
  230. config.y = positions[1];
  231. });
  232. core.mainWindow.on('close', (event) => {
  233. if (isEnableCloseToHide() && !core.isConfirmExit) {
  234. event.preventDefault();
  235. core.mainWindow.hide();
  236. event.returnValue = false;
  237. }
  238. });
  239. core.mainWindow.on('closed', () => {
  240. try {
  241. if (!config.maximized) {
  242. if (config.width > 0) {
  243. config.save('width');
  244. }
  245. if (config.height > 0) {
  246. config.save('height');
  247. }
  248. if (config.x > 0 && config.y > 0) {
  249. config.save('x');
  250. config.save('y');
  251. }
  252. }
  253. config.save('maximized');
  254. } catch (ex) {
  255. ; // Do Nothing
  256. }
  257. core.mainWindow = null;
  258. });
  259. ipcRender.onRenderProcessElectronServiceInited((event) => {
  260. websocket.init();
  261. });
  262. ipcRender.onRenderProcessNewDropFile((event, arg) => {
  263. if (!arg) {
  264. return;
  265. }
  266. let filePath = arg.filePath;
  267. let location = arg.location;
  268. if (location.indexOf('/new') === 0) {
  269. ipcRender.notifyRenderProcessNewTaskFromFile(filePath);
  270. } else {
  271. ipcRender.notifyRenderProcessNewNewTaskFromFileAfterViewLoaded(filePath);
  272. ipcRender.notifyRenderProcessNavigateToNewTask();
  273. }
  274. });
  275. ipcRender.onRenderProcessNewDropText((event, arg) => {
  276. if (!arg) {
  277. return;
  278. }
  279. let text = arg.text;
  280. let location = arg.location;
  281. if (location.indexOf('/new') === 0) {
  282. ipcRender.notifyRenderProcessNewTaskFromText(text);
  283. } else {
  284. ipcRender.notifyRenderProcessNewNewTaskFromTextAfterViewLoaded(text);
  285. ipcRender.notifyRenderProcessNavigateToNewTask();
  286. }
  287. });
  288. });
  289. }
  290. main();