chore: tsify browser-window (#24326)

* chore: tsify browser-window

* fix focus

* also tsify top-level-window
This commit is contained in:
Jeremy Rose 2020-06-28 18:22:55 -07:00 committed by GitHub
parent 1c49e4e376
commit 80e5007c47
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 227 additions and 194 deletions

View file

@ -692,7 +692,7 @@ Returns `BrowserWindow | null` - The window that owns the given `browserView`. I
* `id` Integer * `id` Integer
Returns `BrowserWindow` - The window with the given `id`. Returns `BrowserWindow | null` - The window with the given `id`.
#### `BrowserWindow.addExtension(path)` _Deprecated_ #### `BrowserWindow.addExtension(path)` _Deprecated_

View file

@ -191,7 +191,7 @@ auto_filenames = {
"lib/browser/api/auto-updater/auto-updater-win.js", "lib/browser/api/auto-updater/auto-updater-win.js",
"lib/browser/api/auto-updater/squirrel-update-win.js", "lib/browser/api/auto-updater/squirrel-update-win.js",
"lib/browser/api/browser-view.ts", "lib/browser/api/browser-view.ts",
"lib/browser/api/browser-window.js", "lib/browser/api/browser-window.ts",
"lib/browser/api/content-tracing.ts", "lib/browser/api/content-tracing.ts",
"lib/browser/api/crash-reporter.ts", "lib/browser/api/crash-reporter.ts",
"lib/browser/api/desktop-capturer.ts", "lib/browser/api/desktop-capturer.ts",
@ -216,7 +216,7 @@ auto_filenames = {
"lib/browser/api/screen.ts", "lib/browser/api/screen.ts",
"lib/browser/api/session.ts", "lib/browser/api/session.ts",
"lib/browser/api/system-preferences.ts", "lib/browser/api/system-preferences.ts",
"lib/browser/api/top-level-window.js", "lib/browser/api/top-level-window.ts",
"lib/browser/api/touch-bar.js", "lib/browser/api/touch-bar.js",
"lib/browser/api/tray.ts", "lib/browser/api/tray.ts",
"lib/browser/api/view.ts", "lib/browser/api/view.ts",

View file

@ -1,168 +0,0 @@
'use strict';
const electron = require('electron');
const { TopLevelWindow, deprecate } = electron;
const { BrowserWindow } = process._linkedBinding('electron_browser_window');
Object.setPrototypeOf(BrowserWindow.prototype, TopLevelWindow.prototype);
BrowserWindow.prototype._init = function () {
// Call parent class's _init.
TopLevelWindow.prototype._init.call(this);
// Avoid recursive require.
const { app } = electron;
const nativeSetBounds = this.setBounds;
this.setBounds = (bounds, ...opts) => {
bounds = {
...this.getBounds(),
...bounds
};
nativeSetBounds.call(this, bounds, ...opts);
};
// Sometimes the webContents doesn't get focus when window is shown, so we
// have to force focusing on webContents in this case. The safest way is to
// focus it when we first start to load URL, if we do it earlier it won't
// have effect, if we do it later we might move focus in the page.
//
// Though this hack is only needed on macOS when the app is launched from
// Finder, we still do it on all platforms in case of other bugs we don't
// know.
this.webContents.once('load-url', function () {
this.focus();
});
// Redirect focus/blur event to app instance too.
this.on('blur', (event) => {
app.emit('browser-window-blur', event, this);
});
this.on('focus', (event) => {
app.emit('browser-window-focus', event, this);
});
// Subscribe to visibilityState changes and pass to renderer process.
let isVisible = this.isVisible() && !this.isMinimized();
const visibilityChanged = () => {
const newState = this.isVisible() && !this.isMinimized();
if (isVisible !== newState) {
isVisible = newState;
const visibilityState = isVisible ? 'visible' : 'hidden';
this.webContents.emit('-window-visibility-change', visibilityState);
}
};
const visibilityEvents = ['show', 'hide', 'minimize', 'maximize', 'restore'];
for (const event of visibilityEvents) {
this.on(event, visibilityChanged);
}
// Notify the creation of the window.
const event = process._linkedBinding('electron_browser_event').createEmpty();
app.emit('browser-window-created', event, this);
Object.defineProperty(this, 'devToolsWebContents', {
enumerable: true,
configurable: false,
get () {
return this.webContents.devToolsWebContents;
}
});
};
const isBrowserWindow = (win) => {
return win && win.constructor.name === 'BrowserWindow';
};
BrowserWindow.fromId = (id) => {
const win = TopLevelWindow.fromId(id);
return isBrowserWindow(win) ? win : null;
};
BrowserWindow.getAllWindows = () => {
return TopLevelWindow.getAllWindows().filter(isBrowserWindow);
};
BrowserWindow.getFocusedWindow = () => {
for (const window of BrowserWindow.getAllWindows()) {
if (window.isFocused() || window.isDevToolsFocused()) return window;
}
return null;
};
BrowserWindow.fromWebContents = (webContents) => {
for (const window of BrowserWindow.getAllWindows()) {
if (window.webContents && window.webContents.equal(webContents)) return window;
}
return null;
};
BrowserWindow.fromBrowserView = (browserView) => {
for (const window of BrowserWindow.getAllWindows()) {
if (window.getBrowserView() === browserView) return window;
}
return null;
};
// Helpers.
Object.assign(BrowserWindow.prototype, {
loadURL (...args) {
return this.webContents.loadURL(...args);
},
getURL (...args) {
return this.webContents.getURL();
},
loadFile (...args) {
return this.webContents.loadFile(...args);
},
reload (...args) {
return this.webContents.reload(...args);
},
send (...args) {
return this.webContents.send(...args);
},
openDevTools (...args) {
return this.webContents.openDevTools(...args);
},
closeDevTools () {
return this.webContents.closeDevTools();
},
isDevToolsOpened () {
return this.webContents.isDevToolsOpened();
},
isDevToolsFocused () {
return this.webContents.isDevToolsFocused();
},
toggleDevTools () {
return this.webContents.toggleDevTools();
},
inspectElement (...args) {
return this.webContents.inspectElement(...args);
},
inspectSharedWorker () {
return this.webContents.inspectSharedWorker();
},
inspectServiceWorker () {
return this.webContents.inspectServiceWorker();
},
showDefinitionForSelection () {
return this.webContents.showDefinitionForSelection();
},
capturePage (...args) {
return this.webContents.capturePage(...args);
},
setTouchBar (touchBar) {
electron.TouchBar._setOnWindow(touchBar, this);
},
getBackgroundThrottling () {
return this.webContents.getBackgroundThrottling();
},
setBackgroundThrottling (allowed) {
this.webContents.setBackgroundThrottling(allowed);
}
});
module.exports = BrowserWindow;

View file

@ -0,0 +1,182 @@
import { TopLevelWindow, WebContents, Event, BrowserView, TouchBar } from 'electron';
import type { BrowserWindow as BWT } from 'electron';
const { BrowserWindow } = process._linkedBinding('electron_browser_window') as { BrowserWindow: typeof BWT };
Object.setPrototypeOf(BrowserWindow.prototype, TopLevelWindow.prototype);
(BrowserWindow.prototype as any)._init = function (this: BWT) {
// Call parent class's _init.
(TopLevelWindow.prototype as any)._init.call(this);
// Avoid recursive require.
const { app } = require('electron');
const nativeSetBounds = this.setBounds;
this.setBounds = (bounds, ...opts) => {
bounds = {
...this.getBounds(),
...bounds
};
nativeSetBounds.call(this, bounds, ...opts);
};
// Sometimes the webContents doesn't get focus when window is shown, so we
// have to force focusing on webContents in this case. The safest way is to
// focus it when we first start to load URL, if we do it earlier it won't
// have effect, if we do it later we might move focus in the page.
//
// Though this hack is only needed on macOS when the app is launched from
// Finder, we still do it on all platforms in case of other bugs we don't
// know.
this.webContents.once('load-url' as any, function (this: WebContents) {
this.focus();
});
// Redirect focus/blur event to app instance too.
this.on('blur', (event: Event) => {
app.emit('browser-window-blur', event, this);
});
this.on('focus', (event: Event) => {
app.emit('browser-window-focus', event, this);
});
// Subscribe to visibilityState changes and pass to renderer process.
let isVisible = this.isVisible() && !this.isMinimized();
const visibilityChanged = () => {
const newState = this.isVisible() && !this.isMinimized();
if (isVisible !== newState) {
isVisible = newState;
const visibilityState = isVisible ? 'visible' : 'hidden';
this.webContents.emit('-window-visibility-change', visibilityState);
}
};
const visibilityEvents = ['show', 'hide', 'minimize', 'maximize', 'restore'];
for (const event of visibilityEvents) {
this.on(event as any, visibilityChanged);
}
// Notify the creation of the window.
const event = process._linkedBinding('electron_browser_event').createEmpty();
app.emit('browser-window-created', event, this);
Object.defineProperty(this, 'devToolsWebContents', {
enumerable: true,
configurable: false,
get () {
return this.webContents.devToolsWebContents;
}
});
};
const isBrowserWindow = (win: any) => {
return win && win.constructor.name === 'BrowserWindow';
};
BrowserWindow.fromId = (id: number) => {
const win = TopLevelWindow.fromId(id);
return isBrowserWindow(win) ? win as any as BWT : null;
};
BrowserWindow.getAllWindows = () => {
return TopLevelWindow.getAllWindows().filter(isBrowserWindow) as any[] as BWT[];
};
BrowserWindow.getFocusedWindow = () => {
for (const window of BrowserWindow.getAllWindows()) {
if (window.isFocused() || window.isDevToolsFocused()) return window;
}
return null;
};
BrowserWindow.fromWebContents = (webContents: WebContents) => {
for (const window of BrowserWindow.getAllWindows()) {
if (window.webContents && window.webContents.equal(webContents)) return window;
}
return null;
};
BrowserWindow.fromBrowserView = (browserView: BrowserView) => {
for (const window of BrowserWindow.getAllWindows()) {
if (window.getBrowserView() === browserView) return window;
}
return null;
};
BrowserWindow.prototype.setTouchBar = function (touchBar) {
(TouchBar as any)._setOnWindow(touchBar, this);
};
// Forwarded to webContents:
BrowserWindow.prototype.loadURL = function (...args) {
return this.webContents.loadURL(...args);
};
BrowserWindow.prototype.getURL = function () {
return this.webContents.getURL();
};
BrowserWindow.prototype.loadFile = function (...args) {
return this.webContents.loadFile(...args);
};
BrowserWindow.prototype.reload = function (...args) {
return this.webContents.reload(...args);
};
BrowserWindow.prototype.send = function (...args) {
return this.webContents.send(...args);
};
BrowserWindow.prototype.openDevTools = function (...args) {
return this.webContents.openDevTools(...args);
};
BrowserWindow.prototype.closeDevTools = function () {
return this.webContents.closeDevTools();
};
BrowserWindow.prototype.isDevToolsOpened = function () {
return this.webContents.isDevToolsOpened();
};
BrowserWindow.prototype.isDevToolsFocused = function () {
return this.webContents.isDevToolsFocused();
};
BrowserWindow.prototype.toggleDevTools = function () {
return this.webContents.toggleDevTools();
};
BrowserWindow.prototype.inspectElement = function (...args) {
return this.webContents.inspectElement(...args);
};
BrowserWindow.prototype.inspectSharedWorker = function () {
return this.webContents.inspectSharedWorker();
};
BrowserWindow.prototype.inspectServiceWorker = function () {
return this.webContents.inspectServiceWorker();
};
BrowserWindow.prototype.showDefinitionForSelection = function () {
return this.webContents.showDefinitionForSelection();
};
BrowserWindow.prototype.capturePage = function (...args) {
return this.webContents.capturePage(...args);
};
BrowserWindow.prototype.getBackgroundThrottling = function () {
return this.webContents.getBackgroundThrottling();
};
BrowserWindow.prototype.setBackgroundThrottling = function (allowed: boolean) {
return this.webContents.setBackgroundThrottling(allowed);
};
module.exports = BrowserWindow;

View file

@ -1,14 +1,12 @@
'use strict'; import { EventEmitter } from 'events';
import type { TopLevelWindow as TLWT } from 'electron';
const electron = require('electron'); const { TopLevelWindow } = process._linkedBinding('electron_browser_top_level_window') as { TopLevelWindow: typeof TLWT };
const { EventEmitter } = require('events');
const { TopLevelWindow } = process._linkedBinding('electron_browser_top_level_window');
Object.setPrototypeOf(TopLevelWindow.prototype, EventEmitter.prototype); Object.setPrototypeOf(TopLevelWindow.prototype, EventEmitter.prototype);
TopLevelWindow.prototype._init = function () { (TopLevelWindow.prototype as any)._init = function () {
// Avoid recursive require. // Avoid recursive require.
const { app } = electron; const { app } = require('electron');
// Simulate the application menu on platforms other than macOS. // Simulate the application menu on platforms other than macOS.
if (process.platform !== 'darwin') { if (process.platform !== 'darwin') {

View file

@ -19,21 +19,6 @@ declare namespace Electron {
interface Session { interface Session {
destroy(): void; destroy(): void;
} }
// Experimental views API
class TopLevelWindow {
constructor(args: {show: boolean})
setContentView(view: View): void
}
class WebContentsView {
constructor(options: BrowserWindowConstructorOptions)
}
namespace Main {
class TopLevelWindow extends Electron.TopLevelWindow {}
class View extends Electron.View {}
class WebContentsView extends Electron.WebContentsView {}
}
} }
declare module 'dbus-native'; declare module 'dbus-native';

View file

@ -1495,7 +1495,7 @@ describe('BrowserWindow module', () => {
afterEach(closeAllWindows); afterEach(closeAllWindows);
it('returns the window with id', () => { it('returns the window with id', () => {
const w = new BrowserWindow({ show: false }); const w = new BrowserWindow({ show: false });
expect(BrowserWindow.fromId(w.id).id).to.equal(w.id); expect(BrowserWindow.fromId(w.id)!.id).to.equal(w.id);
}); });
}); });

View file

@ -34,6 +34,7 @@ declare namespace Electron {
getOwnerBrowserWindow(): Electron.BrowserWindow; getOwnerBrowserWindow(): Electron.BrowserWindow;
getLastWebPreferences(): Electron.WebPreferences; getLastWebPreferences(): Electron.WebPreferences;
_getPreloadPaths(): string[]; _getPreloadPaths(): string[];
equal(other: WebContents): boolean;
} }
interface WebPreferences { interface WebPreferences {
@ -96,6 +97,41 @@ declare namespace Electron {
} }
class View {} class View {}
// Experimental views API
class TopLevelWindow {
constructor(args: {show: boolean})
setContentView(view: View): void
static fromId(id: number): TopLevelWindow;
static getAllWindows(): TopLevelWindow[];
isFocused(): boolean;
static getFocusedWindow(): TopLevelWindow | undefined;
}
class WebContentsView {
constructor(options: BrowserWindowConstructorOptions)
}
// Deprecated / undocumented BrowserWindow methods
interface BrowserWindow {
getURL(): string;
send(channel: string, ...args: any[]): void;
openDevTools(options?: Electron.OpenDevToolsOptions): void;
closeDevTools(): void;
isDevToolsOpened(): void;
isDevToolsFocused(): void;
toggleDevTools(): void;
inspectElement(x: number, y: number): void;
inspectSharedWorker(): void;
inspectServiceWorker(): void;
getBackgroundThrottling(): void;
setBackgroundThrottling(allowed: boolean): void;
}
namespace Main {
class TopLevelWindow extends Electron.TopLevelWindow {}
class View extends Electron.View {}
class WebContentsView extends Electron.WebContentsView {}
}
} }
declare namespace ElectronInternal { declare namespace ElectronInternal {