browser-view.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  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') {
  30. throw new Error('Invalid auto resize options');
  31. }
  32. this.#autoResizeFlags = {
  33. width: !!options.width,
  34. height: !!options.height,
  35. horizontal: !!options.horizontal,
  36. vertical: !!options.vertical
  37. };
  38. this.#autoHorizontalProportion = null;
  39. this.#autoVerticalProportion = null;
  40. }
  41. setBackgroundColor (color: string) {
  42. this.#webContentsView.setBackgroundColor(color);
  43. }
  44. // Internal methods
  45. get ownerWindow (): BrowserWindow | null {
  46. return !this.webContents.isDestroyed() ? this.webContents.getOwnerBrowserWindow() : null;
  47. }
  48. set ownerWindow (w: BrowserWindow | null) {
  49. if (this.webContents.isDestroyed()) return;
  50. const oldWindow = this.webContents.getOwnerBrowserWindow();
  51. if (oldWindow && this.#resizeListener) {
  52. oldWindow.off('resize', this.#resizeListener);
  53. this.#resizeListener = null;
  54. }
  55. this.webContents._setOwnerWindow(w);
  56. if (w) {
  57. this.#lastWindowSize = w.getBounds();
  58. w.on('resize', this.#resizeListener = this.#autoResize.bind(this));
  59. }
  60. }
  61. #autoHorizontalProportion: {width: number, left: number} | null = null;
  62. #autoVerticalProportion: {height: number, top: number} | null = null;
  63. #autoResize () {
  64. if (!this.ownerWindow) {
  65. throw new Error('Electron bug: #autoResize called without owner window');
  66. };
  67. if (this.#autoResizeFlags.horizontal && this.#autoHorizontalProportion == null) {
  68. const viewBounds = this.#webContentsView.getBounds();
  69. this.#autoHorizontalProportion = {
  70. width: this.#lastWindowSize.width / viewBounds.width,
  71. left: this.#lastWindowSize.width / viewBounds.x
  72. };
  73. }
  74. if (this.#autoResizeFlags.vertical && this.#autoVerticalProportion == null) {
  75. const viewBounds = this.#webContentsView.getBounds();
  76. this.#autoVerticalProportion = {
  77. height: this.#lastWindowSize.height / viewBounds.height,
  78. top: this.#lastWindowSize.height / viewBounds.y
  79. };
  80. }
  81. const newBounds = this.ownerWindow.getBounds();
  82. let widthDelta = newBounds.width - this.#lastWindowSize.width;
  83. let heightDelta = newBounds.height - this.#lastWindowSize.height;
  84. if (!this.#autoResizeFlags.width) widthDelta = 0;
  85. if (!this.#autoResizeFlags.height) heightDelta = 0;
  86. const newViewBounds = this.#webContentsView.getBounds();
  87. if (widthDelta || heightDelta) {
  88. this.#webContentsView.setBounds({
  89. ...newViewBounds,
  90. width: newViewBounds.width + widthDelta,
  91. height: newViewBounds.height + heightDelta
  92. });
  93. }
  94. if (this.#autoHorizontalProportion) {
  95. newViewBounds.width = newBounds.width / this.#autoHorizontalProportion.width;
  96. newViewBounds.x = newBounds.width / this.#autoHorizontalProportion.left;
  97. }
  98. if (this.#autoVerticalProportion) {
  99. newViewBounds.height = newBounds.height / this.#autoVerticalProportion.height;
  100. newViewBounds.y = newBounds.y / this.#autoVerticalProportion.top;
  101. }
  102. if (this.#autoHorizontalProportion || this.#autoVerticalProportion) {
  103. this.#webContentsView.setBounds(newViewBounds);
  104. }
  105. }
  106. get webContentsView () {
  107. return this.#webContentsView;
  108. }
  109. }