windowManage.ts 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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: 960,
  37. minHeight: 760,
  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. if (mainWindow.isFocused()) {
  92. return
  93. }
  94. notification.show();
  95. });
  96. // 语音视频通话 聚焦窗口
  97. ipcMain.handle('window:focus', (event, data) => {
  98. console.log('execute window focus');
  99. console.log('execute window focus');
  100. console.log('execute window focus');
  101. console.log('execute window focus');
  102. console.log('execute window focus');
  103. console.log('execute window focus');
  104. showWindow()
  105. })
  106. return mainWindow;
  107. }
  108. export function splashEnd() {
  109. splashWindow?.close();
  110. mainWindow?.show();
  111. }
  112. // utils
  113. export const isExistMainWindow = (): boolean =>
  114. !!mainWindow && !mainWindow?.isDestroyed();
  115. export const isShowMainWindow = (): boolean => {
  116. if (!mainWindow) return false;
  117. return mainWindow.isVisible() && (isWin ? true : mainWindow.isFocused());
  118. };
  119. export const closeWindow = () => {
  120. if (!mainWindow) return;
  121. mainWindow.close();
  122. };
  123. export const sendEvent = (name: string, ...args: any[]) => {
  124. if (!mainWindow) return;
  125. mainWindow.webContents.send(name, ...args);
  126. };
  127. export const minimize = () => {
  128. if (!mainWindow) return;
  129. mainWindow.minimize();
  130. };
  131. export const updateMaximize = () => {
  132. if (!mainWindow) return;
  133. if (mainWindow.isMaximized()) {
  134. mainWindow.unmaximize();
  135. } else {
  136. mainWindow.maximize();
  137. }
  138. };
  139. export const toggleHide = () => {
  140. if (!mainWindow) return;
  141. mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
  142. };
  143. export const toggleMinimize = () => {
  144. if (!mainWindow) return;
  145. if (mainWindow.isMinimized()) {
  146. if (!mainWindow.isVisible()) {
  147. mainWindow.show();
  148. }
  149. mainWindow.restore();
  150. mainWindow.focus();
  151. } else {
  152. mainWindow.minimize();
  153. }
  154. };
  155. export const showWindow = () => {
  156. if (!mainWindow) return;
  157. if (mainWindow.isMinimized()) {
  158. mainWindow.restore();
  159. }
  160. if (mainWindow.isVisible()) {
  161. mainWindow.focus();
  162. } else {
  163. mainWindow.show();
  164. }
  165. mainWindow.focus();
  166. console.log(mainWindow.isMinimized());
  167. console.log(mainWindow.isVisible());
  168. };
  169. export const hideWindow = () => {
  170. if (!mainWindow) return;
  171. mainWindow.hide();
  172. };
  173. export const setFullScreen = (isFullscreen: boolean): boolean => {
  174. if (!mainWindow) return false;
  175. if (isLinux) {
  176. // linux It needs to be resizable before it can be full screen
  177. if (isFullscreen) {
  178. mainWindow.setResizable(isFullscreen);
  179. mainWindow.setFullScreen(isFullscreen);
  180. } else {
  181. mainWindow.setFullScreen(isFullscreen);
  182. mainWindow.setResizable(isFullscreen);
  183. }
  184. } else {
  185. mainWindow.setFullScreen(isFullscreen);
  186. }
  187. return isFullscreen;
  188. };
  189. export const getWebContents = (): Electron.WebContents => {
  190. if (!mainWindow) throw new Error("main window is undefined");
  191. return mainWindow.webContents;
  192. };
  193. export const toggleDevTools = () => {
  194. if (!mainWindow) return;
  195. if (mainWindow.webContents.isDevToolsOpened()) {
  196. mainWindow.webContents.closeDevTools();
  197. } else {
  198. mainWindow.webContents.openDevTools({
  199. mode: "detach",
  200. });
  201. }
  202. };