browser-view.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { BrowserWindow, AutoResizeOptions, Rectangle, WebContentsView, WebPreferences, WebContents } from 'electron/main';
  2. const v8Util = process._linkedBinding('electron_common_v8_util');
  3. export default class BrowserView {
  4. #webContentsView: WebContentsView;
  5. // AutoResize state
  6. #resizeListener: ((...args: any[]) => void) | null = null;
  7. #lastWindowSize: {width: number, height: number} = { width: 0, height: 0 };
  8. #autoResizeFlags: AutoResizeOptions = {};
  9. constructor (options: {webPreferences: WebPreferences, webContents?: WebContents} = { webPreferences: {} }) {
  10. const { webPreferences = {}, webContents } = options;
  11. if (webContents) {
  12. v8Util.setHiddenValue(webPreferences, 'webContents', webContents);
  13. }
  14. webPreferences.type = 'browserView';
  15. this.#webContentsView = new WebContentsView({ webPreferences });
  16. }
  17. get webContents () {
  18. return this.#webContentsView.webContents;
  19. }
  20. setBounds (bounds: Rectangle) {
  21. this.#webContentsView.setBounds(bounds);
  22. this.#autoHorizontalProportion = null;
  23. this.#autoVerticalProportion = null;
  24. }
  25. getBounds () {
  26. return this.#webContentsView.getBounds();
  27. }
  28. setAutoResize (options: AutoResizeOptions) {
  29. if (options == null || typeof options !== 'object') { throw new Error('Invalid auto resize options'); }
  30. this.#autoResizeFlags = {
  31. width: !!options.width,
  32. height: !!options.height,
  33. horizontal: !!options.horizontal,
  34. vertical: !!options.vertical
  35. };
  36. this.#autoHorizontalProportion = null;
  37. this.#autoVerticalProportion = null;
  38. }
  39. setBackgroundColor (color: string) {
  40. this.#webContentsView.setBackgroundColor(color);
  41. }
  42. // Internal methods
  43. get ownerWindow (): BrowserWindow | null {
  44. return !this.webContents.isDestroyed() ? this.webContents.getOwnerBrowserWindow() : null;
  45. }
  46. set ownerWindow (w: BrowserWindow | null) {
  47. if (this.webContents.isDestroyed()) return;
  48. const oldWindow = this.webContents.getOwnerBrowserWindow();
  49. if (oldWindow && this.#resizeListener) {
  50. oldWindow.off('resize', this.#resizeListener);
  51. this.#resizeListener = null;
  52. }
  53. this.webContents._setOwnerWindow(w);
  54. if (w) {
  55. this.#lastWindowSize = w.getBounds();
  56. w.on('resize', this.#resizeListener = this.#autoResize.bind(this));
  57. }
  58. }
  59. #autoHorizontalProportion: {width: number, left: number} | null = null;
  60. #autoVerticalProportion: {height: number, top: number} | null = null;
  61. #autoResize () {
  62. if (!this.ownerWindow) throw new Error('Electron bug: #autoResize called without owner window');
  63. if (this.#autoResizeFlags.horizontal && this.#autoHorizontalProportion == null) {
  64. const viewBounds = this.#webContentsView.getBounds();
  65. this.#autoHorizontalProportion = {
  66. width: this.#lastWindowSize.width / viewBounds.width,
  67. left: this.#lastWindowSize.width / viewBounds.x
  68. };
  69. }
  70. if (this.#autoResizeFlags.vertical && this.#autoVerticalProportion == null) {
  71. const viewBounds = this.#webContentsView.getBounds();
  72. this.#autoVerticalProportion = {
  73. height: this.#lastWindowSize.height / viewBounds.height,
  74. top: this.#lastWindowSize.height / viewBounds.y
  75. };
  76. }
  77. const newBounds = this.ownerWindow.getBounds();
  78. let widthDelta = newBounds.width - this.#lastWindowSize.width;
  79. let heightDelta = newBounds.height - this.#lastWindowSize.height;
  80. if (!this.#autoResizeFlags.width) widthDelta = 0;
  81. if (!this.#autoResizeFlags.height) heightDelta = 0;
  82. const newViewBounds = this.#webContentsView.getBounds();
  83. if (widthDelta || heightDelta) {
  84. this.#webContentsView.setBounds({
  85. ...newViewBounds,
  86. width: newViewBounds.width + widthDelta,
  87. height: newViewBounds.height + heightDelta
  88. });
  89. }
  90. if (this.#autoHorizontalProportion) {
  91. newViewBounds.width = newBounds.width / this.#autoHorizontalProportion.width;
  92. newViewBounds.x = newBounds.width / this.#autoHorizontalProportion.left;
  93. }
  94. if (this.#autoVerticalProportion) {
  95. newViewBounds.height = newBounds.height / this.#autoVerticalProportion.height;
  96. newViewBounds.y = newBounds.y / this.#autoVerticalProportion.top;
  97. }
  98. if (this.#autoHorizontalProportion || this.#autoVerticalProportion) {
  99. this.#webContentsView.setBounds(newViewBounds);
  100. }
  101. }
  102. get webContentsView () {
  103. return this.#webContentsView;
  104. }
  105. }