browser-window.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. import { BaseWindow, WebContents, TouchBar, BrowserView } from 'electron/main';
  2. import type { BrowserWindow as BWT } from 'electron/main';
  3. const { BrowserWindow } = process._linkedBinding('electron_browser_window') as { BrowserWindow: typeof BWT };
  4. Object.setPrototypeOf(BrowserWindow.prototype, BaseWindow.prototype);
  5. BrowserWindow.prototype._init = function (this: BWT) {
  6. // Call parent class's _init.
  7. (BaseWindow.prototype as any)._init.call(this);
  8. // Avoid recursive require.
  9. const { app } = require('electron');
  10. // Set ID at construction time so it's accessible after
  11. // underlying window destruction.
  12. const id = this.id;
  13. Object.defineProperty(this, 'id', {
  14. value: id,
  15. writable: false
  16. });
  17. const nativeSetBounds = this.setBounds;
  18. this.setBounds = (bounds, ...opts) => {
  19. bounds = {
  20. ...this.getBounds(),
  21. ...bounds
  22. };
  23. nativeSetBounds.call(this, bounds, ...opts);
  24. };
  25. // Redirect focus/blur event to app instance too.
  26. this.on('blur', (event: Electron.Event) => {
  27. app.emit('browser-window-blur', event, this);
  28. });
  29. this.on('focus', (event: Electron.Event) => {
  30. app.emit('browser-window-focus', event, this);
  31. });
  32. // Subscribe to visibilityState changes and pass to renderer process.
  33. let isVisible = this.isVisible() && !this.isMinimized();
  34. const visibilityChanged = () => {
  35. const newState = this.isVisible() && !this.isMinimized();
  36. if (isVisible !== newState) {
  37. isVisible = newState;
  38. const visibilityState = isVisible ? 'visible' : 'hidden';
  39. this.webContents.emit('-window-visibility-change', visibilityState);
  40. }
  41. };
  42. const visibilityEvents = ['show', 'hide', 'minimize', 'maximize', 'restore'];
  43. for (const event of visibilityEvents) {
  44. this.on(event as any, visibilityChanged);
  45. }
  46. this._browserViews = [];
  47. this.on('close', () => {
  48. this._browserViews.forEach(b => b.webContents?.close({ waitForBeforeUnload: true }));
  49. });
  50. // Notify the creation of the window.
  51. app.emit('browser-window-created', { preventDefault () {} }, this);
  52. Object.defineProperty(this, 'devToolsWebContents', {
  53. enumerable: true,
  54. configurable: false,
  55. get () {
  56. return this.webContents.devToolsWebContents;
  57. }
  58. });
  59. };
  60. const isBrowserWindow = (win: any) => {
  61. return win && win.constructor.name === 'BrowserWindow';
  62. };
  63. BrowserWindow.fromId = (id: number) => {
  64. const win = BaseWindow.fromId(id);
  65. return isBrowserWindow(win) ? win as any as BWT : null;
  66. };
  67. BrowserWindow.getAllWindows = () => {
  68. return BaseWindow.getAllWindows().filter(isBrowserWindow) as any[] as BWT[];
  69. };
  70. BrowserWindow.getFocusedWindow = () => {
  71. for (const window of BrowserWindow.getAllWindows()) {
  72. if (!window.isDestroyed() && window.webContents && !window.webContents.isDestroyed()) {
  73. if (window.isFocused() || window.webContents.isDevToolsFocused()) return window;
  74. }
  75. }
  76. return null;
  77. };
  78. BrowserWindow.fromWebContents = (webContents: WebContents) => {
  79. return webContents.getOwnerBrowserWindow();
  80. };
  81. BrowserWindow.fromBrowserView = (browserView: BrowserView) => {
  82. return BrowserWindow.fromWebContents(browserView.webContents);
  83. };
  84. BrowserWindow.prototype.setTouchBar = function (touchBar) {
  85. (TouchBar as any)._setOnWindow(touchBar, this);
  86. };
  87. // Forwarded to webContents:
  88. BrowserWindow.prototype.loadURL = function (...args) {
  89. return this.webContents.loadURL(...args);
  90. };
  91. BrowserWindow.prototype.getURL = function () {
  92. return this.webContents.getURL();
  93. };
  94. BrowserWindow.prototype.loadFile = function (...args) {
  95. return this.webContents.loadFile(...args);
  96. };
  97. BrowserWindow.prototype.reload = function (...args) {
  98. return this.webContents.reload(...args);
  99. };
  100. BrowserWindow.prototype.send = function (...args) {
  101. return this.webContents.send(...args);
  102. };
  103. BrowserWindow.prototype.openDevTools = function (...args) {
  104. return this.webContents.openDevTools(...args);
  105. };
  106. BrowserWindow.prototype.closeDevTools = function () {
  107. return this.webContents.closeDevTools();
  108. };
  109. BrowserWindow.prototype.isDevToolsOpened = function () {
  110. return this.webContents.isDevToolsOpened();
  111. };
  112. BrowserWindow.prototype.isDevToolsFocused = function () {
  113. return this.webContents.isDevToolsFocused();
  114. };
  115. BrowserWindow.prototype.toggleDevTools = function () {
  116. return this.webContents.toggleDevTools();
  117. };
  118. BrowserWindow.prototype.inspectElement = function (...args) {
  119. return this.webContents.inspectElement(...args);
  120. };
  121. BrowserWindow.prototype.inspectSharedWorker = function () {
  122. return this.webContents.inspectSharedWorker();
  123. };
  124. BrowserWindow.prototype.inspectServiceWorker = function () {
  125. return this.webContents.inspectServiceWorker();
  126. };
  127. BrowserWindow.prototype.showDefinitionForSelection = function () {
  128. return this.webContents.showDefinitionForSelection();
  129. };
  130. BrowserWindow.prototype.capturePage = function (...args) {
  131. return this.webContents.capturePage(...args);
  132. };
  133. BrowserWindow.prototype.getBackgroundThrottling = function () {
  134. return this.webContents.getBackgroundThrottling();
  135. };
  136. BrowserWindow.prototype.setBackgroundThrottling = function (allowed: boolean) {
  137. return this.webContents.setBackgroundThrottling(allowed);
  138. };
  139. BrowserWindow.prototype.addBrowserView = function (browserView: BrowserView) {
  140. if (browserView.ownerWindow) { browserView.ownerWindow.removeBrowserView(browserView); }
  141. this.contentView.addChildView(browserView.webContentsView);
  142. browserView.ownerWindow = this;
  143. browserView.webContents._setOwnerWindow(this);
  144. this._browserViews.push(browserView);
  145. };
  146. BrowserWindow.prototype.setBrowserView = function (browserView: BrowserView) {
  147. this._browserViews.forEach(bv => {
  148. this.removeBrowserView(bv);
  149. });
  150. if (browserView) { this.addBrowserView(browserView); }
  151. };
  152. BrowserWindow.prototype.removeBrowserView = function (browserView: BrowserView) {
  153. const idx = this._browserViews.indexOf(browserView);
  154. if (idx >= 0) {
  155. this.contentView.removeChildView(browserView.webContentsView);
  156. browserView.ownerWindow = null;
  157. this._browserViews.splice(idx, 1);
  158. }
  159. };
  160. BrowserWindow.prototype.getBrowserView = function () {
  161. if (this._browserViews.length > 1) { throw new Error('This BrowserWindow has multiple BrowserViews, use getBrowserViews() instead'); }
  162. return this._browserViews[0] ?? null;
  163. };
  164. BrowserWindow.prototype.getBrowserViews = function () {
  165. return [...this._browserViews];
  166. };
  167. BrowserWindow.prototype.setTopBrowserView = function (browserView: BrowserView) {
  168. if (browserView.ownerWindow !== this) { throw new Error('Given BrowserView is not attached to the window'); }
  169. this.addBrowserView(browserView);
  170. };
  171. module.exports = BrowserWindow;