windowManage.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import { join } from "node:path";
  2. import { BrowserWindow, globalShortcut, ipcMain, shell, Notification } from "electron";
  3. import { isLinux, isMac, isWin } from "../utils";
  4. import { destroyTray } from "./trayManage";
  5. import { getStore } from "./storeManage";
  6. import { getIsForceQuit } from "./appManage";
  7. import { registerShortcuts, unregisterShortcuts } from "./shortcutManage";
  8. interface NotificationData {
  9. title: string;
  10. body: string;
  11. }
  12. const url = process.env.VITE_DEV_SERVER_URL;
  13. let mainWindow: BrowserWindow | null = null;
  14. let splashWindow: BrowserWindow | null = null;
  15. const store = getStore();
  16. function createSplashWindow() {
  17. splashWindow = new BrowserWindow({
  18. frame: false,
  19. width: 200,
  20. height: 200,
  21. resizable: false,
  22. transparent: true,
  23. });
  24. splashWindow.loadFile(global.pathConfig.splashHtml);
  25. splashWindow.on("closed", () => {
  26. splashWindow = null;
  27. });
  28. }
  29. export function createMainWindow() {
  30. createSplashWindow();
  31. mainWindow = new BrowserWindow({
  32. title: "OpenIM",
  33. icon: join(global.pathConfig.publicPath, "favicon.ico"),
  34. frame: false,
  35. show: false,
  36. minWidth: 680,
  37. minHeight: 550,
  38. titleBarStyle: "hiddenInset",
  39. webPreferences: {
  40. preload: global.pathConfig.preload,
  41. // Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
  42. // Consider using contextBridge.exposeInMainWorld
  43. // Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
  44. nodeIntegration: false,
  45. contextIsolation: true,
  46. sandbox: false,
  47. devTools: true,
  48. webSecurity: false,
  49. },
  50. });
  51. if (process.env.VITE_DEV_SERVER_URL) {
  52. // Open devTool if the app is not packaged
  53. mainWindow.loadURL(url);
  54. // mainWindow.webContents.openDevTools()
  55. } else {
  56. mainWindow.loadFile(global.pathConfig.indexHtml);
  57. }
  58. // // Make all links open with the browser, not with the application
  59. mainWindow.webContents.setWindowOpenHandler(({ url }) => {
  60. if (url.startsWith("https:")) shell.openExternal(url);
  61. return { action: "deny" };
  62. });
  63. mainWindow.on("focus", () => {
  64. mainWindow?.flashFrame(false);
  65. registerShortcuts();
  66. });
  67. mainWindow.on("blur", () => {
  68. unregisterShortcuts();
  69. });
  70. mainWindow.on("close", (e) => {
  71. if (
  72. getIsForceQuit() ||
  73. !mainWindow.isVisible() ||
  74. store.get("closeAction") === "quit"
  75. ) {
  76. mainWindow = null;
  77. destroyTray();
  78. } else {
  79. e.preventDefault();
  80. if (isMac && mainWindow.isFullScreen()) {
  81. mainWindow.setFullScreen(false);
  82. }
  83. mainWindow?.hide();
  84. }
  85. });
  86. // globalShortcut.register('CommandOrControl+shift+l', () => {
  87. // mainWindow.webContents.openDevTools()
  88. // })
  89. ipcMain.handle('show-notification', (event, { title, body }: NotificationData) => {
  90. const notification = new Notification({ title, body });
  91. notification.show();
  92. });
  93. return mainWindow;
  94. }
  95. export function splashEnd() {
  96. splashWindow?.close();
  97. mainWindow?.show();
  98. }
  99. // utils
  100. export const isExistMainWindow = (): boolean =>
  101. !!mainWindow && !mainWindow?.isDestroyed();
  102. export const isShowMainWindow = (): boolean => {
  103. if (!mainWindow) return false;
  104. return mainWindow.isVisible() && (isWin ? true : mainWindow.isFocused());
  105. };
  106. export const closeWindow = () => {
  107. if (!mainWindow) return;
  108. mainWindow.close();
  109. };
  110. export const sendEvent = (name: string, ...args: any[]) => {
  111. if (!mainWindow) return;
  112. mainWindow.webContents.send(name, ...args);
  113. };
  114. export const minimize = () => {
  115. if (!mainWindow) return;
  116. mainWindow.minimize();
  117. };
  118. export const updateMaximize = () => {
  119. if (!mainWindow) return;
  120. if (mainWindow.isMaximized()) {
  121. mainWindow.unmaximize();
  122. } else {
  123. mainWindow.maximize();
  124. }
  125. };
  126. export const toggleHide = () => {
  127. if (!mainWindow) return;
  128. mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
  129. };
  130. export const toggleMinimize = () => {
  131. if (!mainWindow) return;
  132. if (mainWindow.isMinimized()) {
  133. if (!mainWindow.isVisible()) {
  134. mainWindow.show();
  135. }
  136. mainWindow.restore();
  137. mainWindow.focus();
  138. } else {
  139. mainWindow.minimize();
  140. }
  141. };
  142. export const showWindow = () => {
  143. if (!mainWindow) return;
  144. if (mainWindow.isMinimized()) {
  145. mainWindow.restore();
  146. }
  147. if (mainWindow.isVisible()) {
  148. mainWindow.focus();
  149. } else {
  150. mainWindow.show();
  151. }
  152. };
  153. export const hideWindow = () => {
  154. if (!mainWindow) return;
  155. mainWindow.hide();
  156. };
  157. export const setFullScreen = (isFullscreen: boolean): boolean => {
  158. if (!mainWindow) return false;
  159. if (isLinux) {
  160. // linux It needs to be resizable before it can be full screen
  161. if (isFullscreen) {
  162. mainWindow.setResizable(isFullscreen);
  163. mainWindow.setFullScreen(isFullscreen);
  164. } else {
  165. mainWindow.setFullScreen(isFullscreen);
  166. mainWindow.setResizable(isFullscreen);
  167. }
  168. } else {
  169. mainWindow.setFullScreen(isFullscreen);
  170. }
  171. return isFullscreen;
  172. };
  173. export const getWebContents = (): Electron.WebContents => {
  174. if (!mainWindow) throw new Error("main window is undefined");
  175. return mainWindow.webContents;
  176. };
  177. export const toggleDevTools = () => {
  178. if (!mainWindow) return;
  179. if (mainWindow.webContents.isDevToolsOpened()) {
  180. mainWindow.webContents.closeDevTools();
  181. } else {
  182. mainWindow.webContents.openDevTools({
  183. mode: "detach",
  184. });
  185. }
  186. };