mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
10 Commits
v9.0.0-bet
...
v9.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d47b788e03 | ||
|
|
a985865f65 | ||
|
|
729019b974 | ||
|
|
e83d6be20c | ||
|
|
69eddfb2f9 | ||
|
|
71c3c2b65e | ||
|
|
cf230bc709 | ||
|
|
6d3a6ce307 | ||
|
|
3d8b2af151 | ||
|
|
45174dfc19 |
2
DEPS
2
DEPS
@@ -12,7 +12,7 @@ gclient_gn_args = [
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'83.0.4103.24',
|
||||
'83.0.4103.26',
|
||||
'node_version':
|
||||
'v12.14.1',
|
||||
'nan_version':
|
||||
|
||||
@@ -1 +1 @@
|
||||
9.0.0-beta.19
|
||||
9.0.0-beta.21
|
||||
@@ -54,7 +54,7 @@ The `Super` key is mapped to the `Windows` key on Windows and Linux and
|
||||
* `0` to `9`
|
||||
* `A` to `Z`
|
||||
* `F1` to `F24`
|
||||
* Punctuations like `~`, `!`, `@`, `#`, `$`, etc.
|
||||
* Punctuation like `~`, `!`, `@`, `#`, `$`, etc.
|
||||
* `Plus`
|
||||
* `Space`
|
||||
* `Tab`
|
||||
|
||||
@@ -75,7 +75,7 @@ Returns:
|
||||
* `event` Event
|
||||
|
||||
Emitted when all windows have been closed and the application will quit.
|
||||
Calling `event.preventDefault()` will prevent the default behaviour, which is
|
||||
Calling `event.preventDefault()` will prevent the default behavior, which is
|
||||
terminating the application.
|
||||
|
||||
See the description of the `window-all-closed` event for the differences between
|
||||
@@ -204,7 +204,7 @@ Returns:
|
||||
[`NSUserActivity.activityType`][activity-type].
|
||||
* `userInfo` unknown - Contains app-specific state stored by the activity.
|
||||
|
||||
Emitted when [Handoff][handoff] is about to be resumed on another device. If you need to update the state to be transferred, you should call `event.preventDefault()` immediately, construct a new `userInfo` dictionary and call `app.updateCurrentActiviy()` in a timely manner. Otherwise, the operation will fail and `continue-activity-error` will be called.
|
||||
Emitted when [Handoff][handoff] is about to be resumed on another device. If you need to update the state to be transferred, you should call `event.preventDefault()` immediately, construct a new `userInfo` dictionary and call `app.updateCurrentActivity()` in a timely manner. Otherwise, the operation will fail and `continue-activity-error` will be called.
|
||||
|
||||
### Event: 'new-window-for-tab' _macOS_
|
||||
|
||||
@@ -1021,7 +1021,7 @@ This method can only be called before app is ready.
|
||||
|
||||
By default, Chromium disables 3D APIs (e.g. WebGL) until restart on a per
|
||||
domain basis if the GPU processes crashes too frequently. This function
|
||||
disables that behaviour.
|
||||
disables that behavior.
|
||||
|
||||
This method can only be called before app is ready.
|
||||
|
||||
@@ -1190,7 +1190,7 @@ Show the app's about panel options. These options can be overridden with `app.se
|
||||
* `website` String (optional) _Linux_ - The app's website.
|
||||
* `iconPath` String (optional) _Linux_ _Windows_ - Path to the app's icon. On Linux, will be shown as 64x64 pixels while retaining aspect ratio.
|
||||
|
||||
Set the about panel options. This will override the values defined in the app's `.plist` file on MacOS. See the [Apple docs][about-panel-options] for more details. On Linux, values must be set in order to be shown; there are no defaults.
|
||||
Set the about panel options. This will override the values defined in the app's `.plist` file on macOS. See the [Apple docs][about-panel-options] for more details. On Linux, values must be set in order to be shown; there are no defaults.
|
||||
|
||||
If you do not set `credits` but still wish to surface them in your app, AppKit will look for a file named "Credits.html", "Credits.rtf", and "Credits.rtfd", in that order, in the bundle returned by the NSBundle class method main. The first file found is used, and if none is found, the info area is left blank. See Apple [documentation](https://developer.apple.com/documentation/appkit/nsaboutpaneloptioncredits?language=objc) for more information.
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
* `simpleFullscreen` Boolean (optional) - Use pre-Lion fullscreen on macOS. Default is `false`.
|
||||
* `skipTaskbar` Boolean (optional) - Whether to show the window in taskbar. Default is
|
||||
`false`.
|
||||
* `kiosk` Boolean (optional) - The kiosk mode. Default is `false`.
|
||||
* `kiosk` Boolean (optional) - Whether the window is in kiosk mode. Default is `false`.
|
||||
* `title` String (optional) - Default window title. Default is `"Electron"`. If the HTML tag `<title>` is defined in the HTML file loaded by `loadURL()`, this property will be ignored.
|
||||
* `icon` ([NativeImage](native-image.md) | String) (optional) - The window icon. On Windows it is
|
||||
recommended to use `ICO` icons to get best visual effects, you can also
|
||||
@@ -207,7 +207,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
* `opacity` Number (optional) - Set the initial opacity of the window, between 0.0 (fully
|
||||
transparent) and 1.0 (fully opaque). This is only implemented on Windows and macOS.
|
||||
* `darkTheme` Boolean (optional) - Forces using dark theme for the window, only works on
|
||||
some GTK+3 desktop environments. Default is `false`.
|
||||
some GTK desktop environments. Default is `false`.
|
||||
* `transparent` Boolean (optional) - Makes the window [transparent](frameless-window.md#transparent-window).
|
||||
Default is `false`. On Windows, does not work unless the window is frameless.
|
||||
* `type` String (optional) - The type of window, default is normal window. See more about
|
||||
@@ -803,6 +803,47 @@ A `Boolean` property that determines whether the window menu bar should hide its
|
||||
If the menu bar is already visible, setting this property to `true` won't
|
||||
hide it immediately.
|
||||
|
||||
#### `win.simpleFullScreen`
|
||||
|
||||
A `Boolean` property that determines whether the window is in simple (pre-Lion) fullscreen mode.
|
||||
|
||||
#### `win.visibleOnAllWorkspaces`
|
||||
|
||||
A `Boolean` property that determines whether the window is visible on all workspaces.
|
||||
|
||||
**Note:** Always returns false on Windows.
|
||||
|
||||
#### `win.shadow`
|
||||
|
||||
A `Boolean` property that determines whether the window has a shadow.
|
||||
|
||||
#### `win.menuBarVisible` _Windows_ _Linux_
|
||||
|
||||
A `Boolean` property that determines whether the menu bar should be visible.
|
||||
|
||||
**Note:** If the menu bar is auto-hide, users can still bring up the menu bar by pressing the single `Alt` key.
|
||||
|
||||
#### `win.kiosk`
|
||||
|
||||
A `Boolean` property that determines whether the window is in kiosk mode.
|
||||
|
||||
#### `win.documentEdited` _macOS_
|
||||
|
||||
A `Boolean` property that specifies whether the window’s document has been edited.
|
||||
|
||||
The icon in title bar will become gray when set to `true`.
|
||||
|
||||
#### `win.representedFilename` _macOS_
|
||||
|
||||
A `String` property that determines the pathname of the file the window represents,
|
||||
and the icon of the file will show in window's title bar.
|
||||
|
||||
#### `win.title`
|
||||
|
||||
A `String` property that determines the title of the native window.
|
||||
|
||||
**Note:** The title of the web page can be different from the title of the native window.
|
||||
|
||||
#### `win.minimizable`
|
||||
|
||||
A `Boolean` property that determines whether the window can be manually minimized by user.
|
||||
@@ -958,7 +999,7 @@ Returns `Boolean` - Whether the window is in fullscreen mode.
|
||||
|
||||
Enters or leaves simple fullscreen mode.
|
||||
|
||||
Simple fullscreen mode emulates the native fullscreen behavior found in versions of Mac OS X prior to Lion (10.7).
|
||||
Simple fullscreen mode emulates the native fullscreen behavior found in versions of macOS prior to Lion (10.7).
|
||||
|
||||
#### `win.isSimpleFullScreen()` _macOS_
|
||||
|
||||
@@ -1282,7 +1323,7 @@ Makes the window not show in the taskbar.
|
||||
|
||||
* `flag` Boolean
|
||||
|
||||
Enters or leaves the kiosk mode.
|
||||
Enters or leaves kiosk mode.
|
||||
|
||||
#### `win.isKiosk()`
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ win.show()
|
||||
Uses custom drawn close, and miniaturize buttons that display
|
||||
when hovering in the top left of the window. The fullscreen button
|
||||
is not available due to restrictions of frameless windows as they
|
||||
interface with Apple's MacOS window masks. These custom buttons prevent
|
||||
interface with Apple's macOS window masks. These custom buttons prevent
|
||||
issues with mouse events that occur with the standard window toolbar buttons.
|
||||
This option is only applicable for frameless windows.
|
||||
|
||||
@@ -158,7 +158,7 @@ buttons in titlebar non-draggable.
|
||||
|
||||
## Text selection
|
||||
|
||||
In a frameless window the dragging behaviour may conflict with selecting text.
|
||||
In a frameless window the dragging behavior may conflict with selecting text.
|
||||
For example, when you drag the titlebar you may accidentally select the text on
|
||||
the titlebar. To prevent this, you need to disable text selection within a
|
||||
draggable area like this:
|
||||
|
||||
@@ -117,7 +117,7 @@ When specifying a `role` on macOS, `label` and `accelerator` are the only
|
||||
options that will affect the menu item. All other options will be ignored.
|
||||
Lowercase `role`, e.g. `toggledevtools`, is still supported.
|
||||
|
||||
**Nota Bene:** The `enabled` and `visibility` properties are not available for top-level menu items in the tray on MacOS.
|
||||
**Nota Bene:** The `enabled` and `visibility` properties are not available for top-level menu items in the tray on macOS.
|
||||
|
||||
### Instance Properties
|
||||
|
||||
|
||||
@@ -5,14 +5,7 @@ The Electron team is currently undergoing an initiative to convert separate gett
|
||||
## Candidates
|
||||
|
||||
* `BrowserWindow`
|
||||
* `fullscreen`
|
||||
* `simpleFullscreen`
|
||||
* `alwaysOnTop`
|
||||
* `title`
|
||||
* `documentEdited`
|
||||
* `hasShadow`
|
||||
* `menubarVisible`
|
||||
* `visibleOnAllWorkspaces`
|
||||
* `crashReporter` module
|
||||
* `uploadToServer`
|
||||
* `webFrame` modules
|
||||
|
||||
@@ -51,7 +51,7 @@ app.whenReady().then(() => {
|
||||
|
||||
In the above code the [`BrowserWindow`](browser-window.md) that was created has Node.js disabled and can communicate
|
||||
only via IPC. The use of this option stops Electron from creating a Node.js runtime in the renderer. Also,
|
||||
within this new window `window.open` follows the native behaviour (by default Electron creates a [`BrowserWindow`](browser-window.md)
|
||||
within this new window `window.open` follows the native behavior (by default Electron creates a [`BrowserWindow`](browser-window.md)
|
||||
and returns a proxy to this via `window.open`).
|
||||
|
||||
[`app.enableSandbox`](app.md#appenablesandbox-experimental) can be used to force `sandbox: true` for all `BrowserWindow` instances.
|
||||
|
||||
@@ -326,7 +326,7 @@ This API is only available on macOS 10.14 Mojave or newer.
|
||||
* `window-frame-text` - The text in the window's titlebar area.
|
||||
|
||||
Returns `String` - The system color setting in RGB hexadecimal form (`#ABCDEF`).
|
||||
See the [Windows docs][windows-colors] and the [MacOS docs][macos-colors] for more details.
|
||||
See the [Windows docs][windows-colors] and the [macOS docs][macos-colors] for more details.
|
||||
|
||||
The following colors are only available on macOS 10.14: `find-highlight`, `selected-content-background`, `separator`, `unemphasized-selected-content-background`, `unemphasized-selected-text-background`, and `unemphasized-selected-text`.
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ Follow the guidelines below for building Electron on Linux.
|
||||
Doing so permits installing Node on your own home directory as a standard user.
|
||||
Or try repositories such as [NodeSource](https://nodesource.com/blog/nodejs-v012-iojs-and-the-nodesource-linux-repositories).
|
||||
* [clang](https://clang.llvm.org/get_started.html) 3.4 or later.
|
||||
* Development headers of GTK+ and libnotify.
|
||||
* Development headers of GTK 3 and libnotify.
|
||||
|
||||
On Ubuntu, install the following libraries:
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ $ pip install pyobjc
|
||||
If you're developing Electron and don't plan to redistribute your
|
||||
custom Electron build, you may skip this section.
|
||||
|
||||
Official Electron builds are built with [Xcode 9.4.1](http://adcdownload.apple.com/Developer_Tools/Xcode_9.4.1/Xcode_9.4.1.xip), and the MacOS 10.13 SDK. Building with a newer SDK works too, but the releases currently use the 10.13 SDK.
|
||||
Official Electron builds are built with [Xcode 9.4.1](http://adcdownload.apple.com/Developer_Tools/Xcode_9.4.1/Xcode_9.4.1.xip), and the macOS 10.13 SDK. Building with a newer SDK works too, but the releases currently use the 10.13 SDK.
|
||||
|
||||
## Building Electron
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ you prefer a graphical interface.
|
||||
tail calls, and other compiler optimizations.
|
||||
|
||||
* **Xcode**: In addition to Xcode, also install the Xcode command line tools.
|
||||
They include LLDB, the default debugger in Xcode on Mac OS X. It supports
|
||||
They include LLDB, the default debugger in Xcode on macOS. It supports
|
||||
debugging C, Objective-C and C++ on the desktop and iOS devices and simulator.
|
||||
|
||||
* **.lldbinit**: Create or edit `~/.lldbinit` to allow Chromium code to be properly source-mapped.
|
||||
|
||||
@@ -35,7 +35,7 @@ $ git fetch upstream
|
||||
|
||||
Build steps and dependencies differ slightly depending on your operating system.
|
||||
See these detailed guides on building Electron locally:
|
||||
* [Building on MacOS](https://electronjs.org/docs/development/build-instructions-macos)
|
||||
* [Building on macOS](https://electronjs.org/docs/development/build-instructions-macos)
|
||||
* [Building on Linux](https://electronjs.org/docs/development/build-instructions-linux)
|
||||
* [Building on Windows](https://electronjs.org/docs/development/build-instructions-windows)
|
||||
|
||||
|
||||
@@ -324,7 +324,7 @@ app.whenReady().then(() => {
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
const reopenMenuItem = findReopenMenuItem()
|
||||
if (reopenMenuItem) reopenMenuItem.enabled = true
|
||||
@@ -335,7 +335,7 @@ app.on('window-all-closed', function () {
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
|
||||
@@ -46,7 +46,7 @@ app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
@@ -54,7 +54,7 @@ app.on('window-all-closed', function () {
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
|
||||
@@ -37,7 +37,7 @@ app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
@@ -45,7 +45,7 @@ app.on('window-all-closed', function () {
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
|
||||
@@ -37,7 +37,7 @@ app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
@@ -45,7 +45,7 @@ app.on('window-all-closed', function () {
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
|
||||
@@ -37,7 +37,7 @@ app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
@@ -45,7 +45,7 @@ app.on('window-all-closed', function () {
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
|
||||
@@ -37,7 +37,7 @@ app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
@@ -45,7 +45,7 @@ app.on('window-all-closed', function () {
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
|
||||
@@ -36,7 +36,7 @@ app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
@@ -44,7 +44,7 @@ app.on('window-all-closed', function () {
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
|
||||
@@ -37,7 +37,7 @@ app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
@@ -45,7 +45,7 @@ app.on('window-all-closed', function () {
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
|
||||
@@ -37,7 +37,7 @@ app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
@@ -45,7 +45,7 @@ app.on('window-all-closed', function () {
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
|
||||
@@ -38,7 +38,7 @@ app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
@@ -46,7 +46,7 @@ app.on('window-all-closed', function () {
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
|
||||
@@ -38,7 +38,7 @@ app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
@@ -46,7 +46,7 @@ app.on('window-all-closed', function () {
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
|
||||
@@ -37,7 +37,7 @@ app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
@@ -45,7 +45,7 @@ app.on('window-all-closed', function () {
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
|
||||
@@ -37,7 +37,7 @@ app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
@@ -45,7 +45,7 @@ app.on('window-all-closed', function () {
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<h2>Create a new window</h2>
|
||||
<h3>Supports: Win, MacOS, Linux <span>|</span> Process: Main</h3>
|
||||
<h3>Supports: Win, macOS, Linux <span>|</span> Process: Main</h3>
|
||||
<button id="new-window">View Demo</button>
|
||||
<p>The <code>BrowserWindow</code> module gives you the ability to create new windows in your app. This main process module can be used from the renderer process with the <code>remote</code> module, as is shown in this demo.</p>
|
||||
<p>There are a lot of options when creating a new window. A few are in this demo, but visit the <a id="browser-window-link" href="">documentation<span>(opens in new window)</span></a>
|
||||
|
||||
@@ -37,7 +37,7 @@ app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
@@ -45,7 +45,7 @@ app.on('window-all-closed', function () {
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
|
||||
@@ -37,7 +37,7 @@ app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
@@ -45,7 +45,7 @@ app.on('window-all-closed', function () {
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
|
||||
@@ -76,7 +76,7 @@ that cache folder to provide custom builds of Electron or to avoid making contac
|
||||
with the network at all.
|
||||
|
||||
* Linux: `$XDG_CACHE_HOME` or `~/.cache/electron/`
|
||||
* MacOS: `~/Library/Caches/electron/`
|
||||
* macOS: `~/Library/Caches/electron/`
|
||||
* Windows: `$LOCALAPPDATA/electron/Cache` or `~/AppData/Local/electron/Cache/`
|
||||
|
||||
On environments that have been using older versions of Electron, you might find the
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# MacOS Dock
|
||||
# macOS Dock
|
||||
|
||||
Electron has APIs to configure the app's icon in the macOS Dock. A macOS-only
|
||||
API exists to create a custom dock menu, but
|
||||
|
||||
@@ -49,7 +49,7 @@ The library file `widevinecdm.dll` will be under
|
||||
`Program Files(x86)/Google/Chrome/Application/CHROME_VERSION/WidevineCdm/_platform_specific/win_(x86|x64)/`
|
||||
directory.
|
||||
|
||||
### On MacOS
|
||||
### On macOS
|
||||
|
||||
The library file `libwidevinecdm.dylib` will be under
|
||||
`/Applications/Google Chrome.app/Contents/Versions/CHROME_VERSION/Google Chrome Framework.framework/Versions/A/Libraries/WidevineCdm/_platform_specific/mac_(x86|x64)/`
|
||||
|
||||
@@ -178,11 +178,8 @@ auto_filenames = {
|
||||
isolated_bundle_deps = [
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/isolated_renderer/init.js",
|
||||
"lib/renderer/ipc-renderer-internal-utils.ts",
|
||||
"lib/renderer/ipc-renderer-internal.ts",
|
||||
"lib/renderer/web-view/web-view-constants.ts",
|
||||
"lib/renderer/web-view/web-view-element.ts",
|
||||
"lib/renderer/window-setup.ts",
|
||||
"package.json",
|
||||
"tsconfig.electron.json",
|
||||
"tsconfig.json",
|
||||
@@ -192,6 +189,7 @@ auto_filenames = {
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/common/webpack-globals-provider.ts",
|
||||
"lib/content_script/init.js",
|
||||
"lib/renderer/api/context-bridge.ts",
|
||||
"lib/renderer/chrome-api.ts",
|
||||
"lib/renderer/extensions/event.ts",
|
||||
"lib/renderer/extensions/i18n.ts",
|
||||
|
||||
@@ -92,43 +92,6 @@ BrowserWindow.prototype._init = function () {
|
||||
return this.webContents.devToolsWebContents;
|
||||
}
|
||||
});
|
||||
|
||||
// Properties
|
||||
|
||||
Object.defineProperty(this, 'autoHideMenuBar', {
|
||||
get: () => this.isMenuBarAutoHide(),
|
||||
set: (autoHide) => this.setAutoHideMenuBar(autoHide)
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'minimizable', {
|
||||
get: () => this.isMinimizable(),
|
||||
set: (min) => this.setMinimizable(min)
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'maximizable', {
|
||||
get: () => this.isMaximizable(),
|
||||
set: (max) => this.setMaximizable(max)
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'resizable', {
|
||||
get: () => this.isResizable(),
|
||||
set: (res) => this.setResizable(res)
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'fullScreenable', {
|
||||
get: () => this.isFullScreenable(),
|
||||
set: (full) => this.setFullScreenable(full)
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'closable', {
|
||||
get: () => this.isClosable(),
|
||||
set: (close) => this.setClosable(close)
|
||||
});
|
||||
|
||||
Object.defineProperty(this, 'movable', {
|
||||
get: () => this.isMovable(),
|
||||
set: (move) => this.setMovable(move)
|
||||
});
|
||||
};
|
||||
|
||||
const isBrowserWindow = (win) => {
|
||||
|
||||
@@ -17,6 +17,83 @@ TopLevelWindow.prototype._init = function () {
|
||||
}
|
||||
};
|
||||
|
||||
// Properties
|
||||
|
||||
Object.defineProperty(TopLevelWindow.prototype, 'autoHideMenuBar', {
|
||||
get: function () { return this.isMenuBarAutoHide(); },
|
||||
set: function (autoHide) { this.setAutoHideMenuBar(autoHide); }
|
||||
});
|
||||
|
||||
Object.defineProperty(TopLevelWindow.prototype, 'visibleOnAllWorkspaces', {
|
||||
get: function () { return this.isVisibleOnAllWorkspaces(); },
|
||||
set: function (visible) { this.setVisibleOnAllWorkspaces(visible); }
|
||||
});
|
||||
|
||||
Object.defineProperty(TopLevelWindow.prototype, 'simpleFullScreen', {
|
||||
get: function () { return this.isSimpleFullScreen(); },
|
||||
set: function (simple) { this.setSimpleFullScreen(simple); }
|
||||
});
|
||||
|
||||
Object.defineProperty(TopLevelWindow.prototype, 'kiosk', {
|
||||
get: function () { return this.isKiosk(); },
|
||||
set: function (kiosk) { this.setKiosk(kiosk); }
|
||||
});
|
||||
|
||||
Object.defineProperty(TopLevelWindow.prototype, 'documentEdited', {
|
||||
get: function () { return this.isFullscreen(); },
|
||||
set: function (edited) { this.setDocumentEdited(edited); }
|
||||
});
|
||||
|
||||
Object.defineProperty(TopLevelWindow.prototype, 'shadow', {
|
||||
get: function () { return this.hasShadow(); },
|
||||
set: function (shadow) { this.setHasShadow(shadow); }
|
||||
});
|
||||
|
||||
Object.defineProperty(TopLevelWindow.prototype, 'representedFilename', {
|
||||
get: function () { return this.getRepresentedFilename(); },
|
||||
set: function (filename) { this.setRepresentedFilename(filename); }
|
||||
});
|
||||
|
||||
Object.defineProperty(TopLevelWindow.prototype, 'minimizable', {
|
||||
get: function () { return this.isMinimizable(); },
|
||||
set: function (min) { this.setMinimizable(min); }
|
||||
});
|
||||
|
||||
Object.defineProperty(TopLevelWindow.prototype, 'title', {
|
||||
get: function () { return this.getTitle(); },
|
||||
set: function (title) { this.setTitle(title); }
|
||||
});
|
||||
|
||||
Object.defineProperty(TopLevelWindow.prototype, 'maximizable', {
|
||||
get: function () { return this.isMaximizable(); },
|
||||
set: function (max) { this.setMaximizable(max); }
|
||||
});
|
||||
|
||||
Object.defineProperty(TopLevelWindow.prototype, 'resizable', {
|
||||
get: function () { return this.isResizable(); },
|
||||
set: function (res) { this.setResizable(res); }
|
||||
});
|
||||
|
||||
Object.defineProperty(TopLevelWindow.prototype, 'menuBarVisible', {
|
||||
get: function () { return this.isMenuBarVisible(); },
|
||||
set: function (visible) { this.setMenuBarVisibility(visible); }
|
||||
});
|
||||
|
||||
Object.defineProperty(TopLevelWindow.prototype, 'fullScreenable', {
|
||||
get: function () { return this.isFullScreenable(); },
|
||||
set: function (full) { this.setFullScreenable(full); }
|
||||
});
|
||||
|
||||
Object.defineProperty(TopLevelWindow.prototype, 'closable', {
|
||||
get: function () { return this.isClosable(); },
|
||||
set: function (close) { this.setClosable(close); }
|
||||
});
|
||||
|
||||
Object.defineProperty(TopLevelWindow.prototype, 'movable', {
|
||||
get: function () { return this.isMovable(); },
|
||||
set: function (move) { this.setMovable(move); }
|
||||
});
|
||||
|
||||
TopLevelWindow.getFocusedWindow = () => {
|
||||
return TopLevelWindow.getAllWindows().find((win) => win.isFocused());
|
||||
};
|
||||
|
||||
@@ -528,6 +528,11 @@ WebContents.prototype._init = function () {
|
||||
const referrer = { url: '', policy: 'default' };
|
||||
internalWindowOpen(event, url, referrer, frameName, disposition, options);
|
||||
});
|
||||
|
||||
const prefs = this.getWebPreferences() || {};
|
||||
if (prefs.webviewTag && prefs.contextIsolation) {
|
||||
electron.deprecate.log('Security Warning: A WebContents was just created with both webviewTag and contextIsolation enabled. This combination is fundamentally less secure and effectively bypasses the protections of contextIsolation. We strongly recommend you move away from webviews to OOPIF or BrowserView in order for your app to be more secure');
|
||||
}
|
||||
}
|
||||
|
||||
this.on('login', (event, ...args) => {
|
||||
|
||||
@@ -203,10 +203,9 @@ const { setDefaultApplicationMenu } = require('@electron/internal/browser/defaul
|
||||
|
||||
// Create default menu.
|
||||
//
|
||||
// Note that the task must be added before loading any app, so we can make sure
|
||||
// the call is maded before any user window is created, otherwise the default
|
||||
// menu may show even when user explicitly hides the menu.
|
||||
app.whenReady().then(setDefaultApplicationMenu);
|
||||
// The |will-finish-launching| event is emitted before |ready| event, so default
|
||||
// menu is set before any user window is created.
|
||||
app.once('will-finish-launching', setDefaultApplicationMenu);
|
||||
|
||||
if (packagePath) {
|
||||
// Finally load app's main.js and transfer control to C++.
|
||||
|
||||
@@ -6,10 +6,6 @@ process.electronBinding = require('@electron/internal/common/electron-binding-se
|
||||
|
||||
const v8Util = process.electronBinding('v8_util');
|
||||
|
||||
// The `lib/renderer/ipc-renderer-internal.js` module looks for the ipc object in the
|
||||
// "ipc-internal" hidden value
|
||||
v8Util.setHiddenValue(global, 'ipc-internal', v8Util.getHiddenValue(isolatedWorld, 'ipc-internal'));
|
||||
|
||||
const webViewImpl = v8Util.getHiddenValue(isolatedWorld, 'web-view-impl');
|
||||
|
||||
if (webViewImpl) {
|
||||
@@ -17,11 +13,3 @@ if (webViewImpl) {
|
||||
const { setupWebView } = require('@electron/internal/renderer/web-view/web-view-element');
|
||||
setupWebView(v8Util, webViewImpl);
|
||||
}
|
||||
|
||||
const isolatedWorldArgs = v8Util.getHiddenValue(isolatedWorld, 'isolated-world-args');
|
||||
|
||||
if (isolatedWorldArgs) {
|
||||
const { guestInstanceId, isHiddenPage, openerId, usesNativeWindowOpen } = isolatedWorldArgs;
|
||||
const { windowSetup } = require('@electron/internal/renderer/window-setup');
|
||||
windowSetup(guestInstanceId, openerId, isHiddenPage, usesNativeWindowOpen);
|
||||
}
|
||||
|
||||
@@ -18,3 +18,17 @@ const contextBridge = {
|
||||
if (!binding._debugGCMaps) delete contextBridge.debugGC;
|
||||
|
||||
export default contextBridge;
|
||||
|
||||
export const internalContextBridge = {
|
||||
contextIsolationEnabled,
|
||||
overrideGlobalValueFromIsolatedWorld: (keys: string[], value: any) => {
|
||||
return binding._overrideGlobalValueFromIsolatedWorld(keys, value, false);
|
||||
},
|
||||
overrideGlobalValueWithDynamicPropsFromIsolatedWorld: (keys: string[], value: any) => {
|
||||
return binding._overrideGlobalValueFromIsolatedWorld(keys, value, true);
|
||||
},
|
||||
overrideGlobalPropertyFromIsolatedWorld: (keys: string[], getter: Function, setter?: Function) => {
|
||||
return binding._overrideGlobalPropertyFromIsolatedWorld(keys, getter, setter || null);
|
||||
},
|
||||
isInMainWorld: () => binding._isCalledFromMainWorld() as boolean
|
||||
};
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
|
||||
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils';
|
||||
import { internalContextBridge } from '@electron/internal/renderer/api/context-bridge';
|
||||
|
||||
// This file implements the following APIs:
|
||||
// - window.history.back()
|
||||
// - window.history.forward()
|
||||
// - window.history.go()
|
||||
// - window.history.length
|
||||
const { contextIsolationEnabled } = internalContextBridge;
|
||||
|
||||
// This file implements the following APIs over the ctx bridge:
|
||||
// - window.open()
|
||||
// - window.opener.blur()
|
||||
// - window.opener.close()
|
||||
@@ -13,7 +12,12 @@ import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-inte
|
||||
// - window.opener.focus()
|
||||
// - window.opener.location
|
||||
// - window.opener.print()
|
||||
// - window.opener.closed
|
||||
// - window.opener.postMessage()
|
||||
// - window.history.back()
|
||||
// - window.history.forward()
|
||||
// - window.history.go()
|
||||
// - window.history.length
|
||||
// - window.prompt()
|
||||
// - document.hidden
|
||||
// - document.visibilityState
|
||||
@@ -30,13 +34,13 @@ const toString = (value: any) => {
|
||||
|
||||
const windowProxies = new Map<number, BrowserWindowProxy>();
|
||||
|
||||
const getOrCreateProxy = (guestId: number) => {
|
||||
const getOrCreateProxy = (guestId: number): SafelyBoundBrowserWindowProxy => {
|
||||
let proxy = windowProxies.get(guestId);
|
||||
if (proxy == null) {
|
||||
proxy = new BrowserWindowProxy(guestId);
|
||||
windowProxies.set(guestId, proxy);
|
||||
}
|
||||
return proxy;
|
||||
return proxy.getSafe();
|
||||
};
|
||||
|
||||
const removeProxy = (guestId: number) => {
|
||||
@@ -64,6 +68,8 @@ class LocationProxy {
|
||||
*/
|
||||
private static ProxyProperty<T> (target: LocationProxy, propertyKey: LocationProperties) {
|
||||
Object.defineProperty(target, propertyKey, {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get: function (this: LocationProxy): T | string {
|
||||
const guestURL = this.getGuestURL();
|
||||
const value = guestURL ? guestURL[propertyKey] : '';
|
||||
@@ -82,6 +88,30 @@ class LocationProxy {
|
||||
});
|
||||
}
|
||||
|
||||
public getSafe = () => {
|
||||
const that = this;
|
||||
return {
|
||||
get href () { return that.href; },
|
||||
set href (newValue) { that.href = newValue; },
|
||||
get hash () { return that.hash; },
|
||||
set hash (newValue) { that.hash = newValue; },
|
||||
get host () { return that.host; },
|
||||
set host (newValue) { that.host = newValue; },
|
||||
get hostname () { return that.hostname; },
|
||||
set hostname (newValue) { that.hostname = newValue; },
|
||||
get origin () { return that.origin; },
|
||||
set origin (newValue) { that.origin = newValue; },
|
||||
get pathname () { return that.pathname; },
|
||||
set pathname (newValue) { that.pathname = newValue; },
|
||||
get port () { return that.port; },
|
||||
set port (newValue) { that.port = newValue; },
|
||||
get protocol () { return that.protocol; },
|
||||
set protocol (newValue) { that.protocol = newValue; },
|
||||
get search () { return that.search; },
|
||||
set search (newValue) { that.search = newValue; }
|
||||
};
|
||||
}
|
||||
|
||||
constructor (guestId: number) {
|
||||
// eslint will consider the constructor "useless"
|
||||
// unless we assign them in the body. It's fine, that's what
|
||||
@@ -114,6 +144,17 @@ class LocationProxy {
|
||||
}
|
||||
}
|
||||
|
||||
interface SafelyBoundBrowserWindowProxy {
|
||||
location: WindowProxy['location'];
|
||||
blur: WindowProxy['blur'];
|
||||
close: WindowProxy['close'];
|
||||
eval: typeof eval; // eslint-disable-line no-eval
|
||||
focus: WindowProxy['focus'];
|
||||
print: WindowProxy['print'];
|
||||
postMessage: WindowProxy['postMessage'];
|
||||
closed: boolean;
|
||||
}
|
||||
|
||||
class BrowserWindowProxy {
|
||||
public closed: boolean = false
|
||||
|
||||
@@ -124,7 +165,7 @@ class BrowserWindowProxy {
|
||||
// so for now, we'll have to make do with an "any" in the mix.
|
||||
// https://github.com/Microsoft/TypeScript/issues/2521
|
||||
public get location (): LocationProxy | any {
|
||||
return this._location;
|
||||
return this._location.getSafe();
|
||||
}
|
||||
public set location (url: string | any) {
|
||||
url = resolveURL(url, this.location.href);
|
||||
@@ -141,27 +182,48 @@ class BrowserWindowProxy {
|
||||
});
|
||||
}
|
||||
|
||||
public close () {
|
||||
public getSafe = (): SafelyBoundBrowserWindowProxy => {
|
||||
const that = this;
|
||||
return {
|
||||
postMessage: this.postMessage,
|
||||
blur: this.blur,
|
||||
close: this.close,
|
||||
focus: this.focus,
|
||||
print: this.print,
|
||||
eval: this.eval,
|
||||
get location () {
|
||||
return that.location;
|
||||
},
|
||||
set location (url: string | any) {
|
||||
that.location = url;
|
||||
},
|
||||
get closed () {
|
||||
return that.closed;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public close = () => {
|
||||
this._invokeWindowMethod('destroy');
|
||||
}
|
||||
|
||||
public focus () {
|
||||
public focus = () => {
|
||||
this._invokeWindowMethod('focus');
|
||||
}
|
||||
|
||||
public blur () {
|
||||
public blur = () => {
|
||||
this._invokeWindowMethod('blur');
|
||||
}
|
||||
|
||||
public print () {
|
||||
public print = () => {
|
||||
this._invokeWebContentsMethod('print');
|
||||
}
|
||||
|
||||
public postMessage (message: any, targetOrigin: string) {
|
||||
public postMessage = (message: any, targetOrigin: string) => {
|
||||
ipcRendererInternal.invoke('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', this.guestId, message, toString(targetOrigin), window.location.origin);
|
||||
}
|
||||
|
||||
public eval (code: string) {
|
||||
public eval = (code: string) => {
|
||||
this._invokeWebContentsMethod('executeJavaScript', code);
|
||||
}
|
||||
|
||||
@@ -182,9 +244,11 @@ export const windowSetup = (
|
||||
window.close = function () {
|
||||
ipcRendererInternal.send('ELECTRON_BROWSER_WINDOW_CLOSE');
|
||||
};
|
||||
if (contextIsolationEnabled) internalContextBridge.overrideGlobalValueFromIsolatedWorld(['close'], window.close);
|
||||
}
|
||||
|
||||
if (!usesNativeWindowOpen) {
|
||||
// TODO(MarshallOfSound): Make compatible with ctx isolation without hole-punch
|
||||
// Make the browser window or guest view emit "new-window" event.
|
||||
(window as any).open = function (url?: string, frameName?: string, features?: string) {
|
||||
if (url != null && url !== '') {
|
||||
@@ -197,16 +261,19 @@ export const windowSetup = (
|
||||
return null;
|
||||
}
|
||||
};
|
||||
if (contextIsolationEnabled) internalContextBridge.overrideGlobalValueWithDynamicPropsFromIsolatedWorld(['open'], window.open);
|
||||
}
|
||||
|
||||
if (openerId != null) {
|
||||
window.opener = getOrCreateProxy(openerId);
|
||||
if (contextIsolationEnabled) internalContextBridge.overrideGlobalValueWithDynamicPropsFromIsolatedWorld(['opener'], window.opener);
|
||||
}
|
||||
|
||||
// But we do not support prompt().
|
||||
window.prompt = function () {
|
||||
throw new Error('prompt() is and will not be supported.');
|
||||
};
|
||||
if (contextIsolationEnabled) internalContextBridge.overrideGlobalValueFromIsolatedWorld(['prompt'], window.prompt);
|
||||
|
||||
if (!usesNativeWindowOpen || openerId != null) {
|
||||
ipcRendererInternal.on('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (
|
||||
@@ -233,21 +300,24 @@ export const windowSetup = (
|
||||
window.history.back = function () {
|
||||
ipcRendererInternal.send('ELECTRON_NAVIGATION_CONTROLLER_GO_BACK');
|
||||
};
|
||||
if (contextIsolationEnabled) internalContextBridge.overrideGlobalValueFromIsolatedWorld(['history', 'back'], window.history.back);
|
||||
|
||||
window.history.forward = function () {
|
||||
ipcRendererInternal.send('ELECTRON_NAVIGATION_CONTROLLER_GO_FORWARD');
|
||||
};
|
||||
if (contextIsolationEnabled) internalContextBridge.overrideGlobalValueFromIsolatedWorld(['history', 'forward'], window.history.forward);
|
||||
|
||||
window.history.go = function (offset: number) {
|
||||
ipcRendererInternal.send('ELECTRON_NAVIGATION_CONTROLLER_GO_TO_OFFSET', +offset);
|
||||
};
|
||||
if (contextIsolationEnabled) internalContextBridge.overrideGlobalValueFromIsolatedWorld(['history', 'go'], window.history.go);
|
||||
|
||||
const getHistoryLength = () => ipcRendererInternal.sendSync('ELECTRON_NAVIGATION_CONTROLLER_LENGTH');
|
||||
Object.defineProperty(window.history, 'length', {
|
||||
get: function () {
|
||||
return ipcRendererInternal.sendSync('ELECTRON_NAVIGATION_CONTROLLER_LENGTH');
|
||||
},
|
||||
get: getHistoryLength,
|
||||
set () {}
|
||||
});
|
||||
if (contextIsolationEnabled) internalContextBridge.overrideGlobalPropertyFromIsolatedWorld(['history', 'length'], getHistoryLength);
|
||||
}
|
||||
|
||||
if (guestInstanceId != null) {
|
||||
@@ -269,16 +339,16 @@ export const windowSetup = (
|
||||
});
|
||||
|
||||
// Make document.hidden and document.visibilityState return the correct value.
|
||||
const getDocumentHidden = () => cachedVisibilityState !== 'visible';
|
||||
Object.defineProperty(document, 'hidden', {
|
||||
get: function () {
|
||||
return cachedVisibilityState !== 'visible';
|
||||
}
|
||||
get: getDocumentHidden
|
||||
});
|
||||
if (contextIsolationEnabled) internalContextBridge.overrideGlobalPropertyFromIsolatedWorld(['document', 'hidden'], getDocumentHidden);
|
||||
|
||||
const getDocumentVisibilityState = () => cachedVisibilityState;
|
||||
Object.defineProperty(document, 'visibilityState', {
|
||||
get: function () {
|
||||
return cachedVisibilityState;
|
||||
}
|
||||
get: getDocumentVisibilityState
|
||||
});
|
||||
if (contextIsolationEnabled) internalContextBridge.overrideGlobalPropertyFromIsolatedWorld(['document', 'visibilityState'], getDocumentVisibilityState);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "9.0.0-beta.19",
|
||||
"version": "9.0.0-beta.21",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -39,7 +39,7 @@ async function checkIfDocOnlyChange () {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (nonDocChange) {
|
||||
if (nonDocChange || filesChanged.data.length === 0) {
|
||||
process.exit(1);
|
||||
} else {
|
||||
process.exit(0);
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "ui/base/resource/resource_bundle.h"
|
||||
#include "url/url_constants.h"
|
||||
// In SHARED_INTERMEDIATE_DIR.
|
||||
#include "widevine_cdm_version.h" // NOLINT(build/include)
|
||||
#include "widevine_cdm_version.h" // NOLINT(build/include_directory)
|
||||
|
||||
#if defined(WIDEVINE_CDM_AVAILABLE)
|
||||
#include "base/native_library.h"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "base/callback.h"
|
||||
#include "base/location.h"
|
||||
#include "base/single_thread_task_runner.h"
|
||||
#include "uv.h" // NOLINT(build/include)
|
||||
#include "uv.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace electron {
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "gin/public/isolate_holder.h"
|
||||
#include "uv.h" // NOLINT(build/include)
|
||||
#include "uv.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace node {
|
||||
class Environment;
|
||||
|
||||
@@ -50,8 +50,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 9,0,0,19
|
||||
PRODUCTVERSION 9,0,0,19
|
||||
FILEVERSION 9,0,0,21
|
||||
PRODUCTVERSION 9,0,0,21
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
namespace electron {
|
||||
|
||||
WindowStateWatcher::WindowStateWatcher(NativeWindowViews* window)
|
||||
: window_(window), widget_(window->GetAcceleratedWidget()) {
|
||||
: window_(window),
|
||||
widget_(window->GetAcceleratedWidget()),
|
||||
window_state_atom_(gfx::GetAtom("_NET_WM_STATE")) {
|
||||
ui::X11EventSource::GetInstance()->AddXEventObserver(this);
|
||||
}
|
||||
|
||||
@@ -54,9 +56,8 @@ void WindowStateWatcher::DidProcessXEvent(XEvent* xev) {
|
||||
}
|
||||
}
|
||||
|
||||
bool WindowStateWatcher::IsWindowStateEvent(XEvent* xev) {
|
||||
::Atom changed_atom = xev->xproperty.atom;
|
||||
return (changed_atom == gfx::GetAtom("_NET_WM_STATE") &&
|
||||
bool WindowStateWatcher::IsWindowStateEvent(XEvent* xev) const {
|
||||
return (xev->xproperty.atom == window_state_atom_ &&
|
||||
xev->type == PropertyNotify && xev->xproperty.window == widget_);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,11 @@ class WindowStateWatcher : public ui::XEventObserver {
|
||||
void DidProcessXEvent(XEvent* xev) override;
|
||||
|
||||
private:
|
||||
bool IsWindowStateEvent(XEvent* xev);
|
||||
bool IsWindowStateEvent(XEvent* xev) const;
|
||||
|
||||
NativeWindowViews* window_;
|
||||
gfx::AcceleratedWidget widget_;
|
||||
const ::XAtom window_state_atom_;
|
||||
|
||||
bool was_minimized_ = false;
|
||||
bool was_maximized_ = false;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "base/process/process_metrics.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
#include "uv.h" // NOLINT(build/include)
|
||||
#include "uv.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace gin_helper {
|
||||
class Arguments;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "shell/common/electron_command_line.h"
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "uv.h" // NOLINT(build/include)
|
||||
#include "uv.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace electron {
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/single_thread_task_runner.h"
|
||||
#include "uv.h" // NOLINT(build/include)
|
||||
#include "uv.h" // NOLINT(build/include_directory)
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
@@ -146,6 +146,7 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
||||
v8::Local<v8::Value> value,
|
||||
context_bridge::RenderFrameFunctionStore* store,
|
||||
context_bridge::ObjectCache* object_cache,
|
||||
bool support_dynamic_properties,
|
||||
int recursion_depth) {
|
||||
if (recursion_depth >= kMaxRecursion) {
|
||||
v8::Context::Scope source_scope(source_context);
|
||||
@@ -179,7 +180,8 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
||||
{
|
||||
v8::Local<v8::Value> proxy_func = gin_helper::CallbackToV8Leaked(
|
||||
destination_context->GetIsolate(),
|
||||
base::BindRepeating(&ProxyFunctionWrapper, store, func_id));
|
||||
base::BindRepeating(&ProxyFunctionWrapper, store, func_id,
|
||||
support_dynamic_properties));
|
||||
FunctionLifeMonitor::BindTo(destination_context->GetIsolate(),
|
||||
v8::Local<v8::Object>::Cast(proxy_func),
|
||||
store->GetWeakPtr(), func_id);
|
||||
@@ -209,7 +211,7 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
||||
auto val =
|
||||
PassValueToOtherContext(global_source_context.Get(isolate),
|
||||
global_destination_context.Get(isolate),
|
||||
result, store, &object_cache, 0);
|
||||
result, store, &object_cache, false, 0);
|
||||
if (!val.IsEmpty())
|
||||
proxied_promise->Resolve(val.ToLocalChecked());
|
||||
delete proxied_promise;
|
||||
@@ -230,7 +232,7 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
||||
auto val =
|
||||
PassValueToOtherContext(global_source_context.Get(isolate),
|
||||
global_destination_context.Get(isolate),
|
||||
result, store, &object_cache, 0);
|
||||
result, store, &object_cache, false, 0);
|
||||
if (!val.IsEmpty())
|
||||
proxied_promise->Reject(val.ToLocalChecked());
|
||||
delete proxied_promise;
|
||||
@@ -276,7 +278,7 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
||||
auto value_for_array = PassValueToOtherContext(
|
||||
source_context, destination_context,
|
||||
arr->Get(source_context, i).ToLocalChecked(), store, object_cache,
|
||||
recursion_depth + 1);
|
||||
support_dynamic_properties, recursion_depth + 1);
|
||||
if (value_for_array.IsEmpty())
|
||||
return v8::MaybeLocal<v8::Value>();
|
||||
|
||||
@@ -293,9 +295,9 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
||||
// Proxy all objects
|
||||
if (IsPlainObject(value)) {
|
||||
auto object_value = v8::Local<v8::Object>::Cast(value);
|
||||
auto passed_value =
|
||||
CreateProxyForAPI(object_value, source_context, destination_context,
|
||||
store, object_cache, recursion_depth + 1);
|
||||
auto passed_value = CreateProxyForAPI(
|
||||
object_value, source_context, destination_context, store, object_cache,
|
||||
support_dynamic_properties, recursion_depth + 1);
|
||||
if (passed_value.IsEmpty())
|
||||
return v8::MaybeLocal<v8::Value>();
|
||||
return v8::MaybeLocal<v8::Value>(passed_value.ToLocalChecked());
|
||||
@@ -324,6 +326,7 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
||||
v8::Local<v8::Value> ProxyFunctionWrapper(
|
||||
context_bridge::RenderFrameFunctionStore* store,
|
||||
size_t func_id,
|
||||
bool support_dynamic_properties,
|
||||
gin_helper::Arguments* args) {
|
||||
// Context the proxy function was called from
|
||||
v8::Local<v8::Context> calling_context = args->isolate()->GetCurrentContext();
|
||||
@@ -343,7 +346,8 @@ v8::Local<v8::Value> ProxyFunctionWrapper(
|
||||
|
||||
for (auto value : original_args) {
|
||||
auto arg = PassValueToOtherContext(calling_context, func_owning_context,
|
||||
value, store, &object_cache, 0);
|
||||
value, store, &object_cache,
|
||||
support_dynamic_properties, 0);
|
||||
if (arg.IsEmpty())
|
||||
return v8::Undefined(args->isolate());
|
||||
proxied_args.push_back(arg.ToLocalChecked());
|
||||
@@ -381,9 +385,10 @@ v8::Local<v8::Value> ProxyFunctionWrapper(
|
||||
if (maybe_return_value.IsEmpty())
|
||||
return v8::Undefined(args->isolate());
|
||||
|
||||
auto ret = PassValueToOtherContext(func_owning_context, calling_context,
|
||||
maybe_return_value.ToLocalChecked(),
|
||||
store, &object_cache, 0);
|
||||
auto ret =
|
||||
PassValueToOtherContext(func_owning_context, calling_context,
|
||||
maybe_return_value.ToLocalChecked(), store,
|
||||
&object_cache, support_dynamic_properties, 0);
|
||||
if (ret.IsEmpty())
|
||||
return v8::Undefined(args->isolate());
|
||||
return ret.ToLocalChecked();
|
||||
@@ -396,6 +401,7 @@ v8::MaybeLocal<v8::Object> CreateProxyForAPI(
|
||||
const v8::Local<v8::Context>& destination_context,
|
||||
context_bridge::RenderFrameFunctionStore* store,
|
||||
context_bridge::ObjectCache* object_cache,
|
||||
bool support_dynamic_properties,
|
||||
int recursion_depth) {
|
||||
gin_helper::Dictionary api(source_context->GetIsolate(), api_object);
|
||||
v8::Context::Scope destination_context_scope(destination_context);
|
||||
@@ -420,13 +426,54 @@ v8::MaybeLocal<v8::Object> CreateProxyForAPI(
|
||||
if (!gin::ConvertFromV8(api.isolate(), key, &key_str)) {
|
||||
continue;
|
||||
}
|
||||
if (support_dynamic_properties) {
|
||||
v8::Context::Scope source_context_scope(source_context);
|
||||
auto maybe_desc = api.GetHandle()->GetOwnPropertyDescriptor(
|
||||
source_context, v8::Local<v8::Name>::Cast(key));
|
||||
v8::Local<v8::Value> desc_value;
|
||||
if (!maybe_desc.ToLocal(&desc_value) || !desc_value->IsObject())
|
||||
continue;
|
||||
gin_helper::Dictionary desc(api.isolate(), desc_value.As<v8::Object>());
|
||||
if (desc.Has("get") || desc.Has("set")) {
|
||||
v8::Local<v8::Value> getter;
|
||||
v8::Local<v8::Value> setter;
|
||||
desc.Get("get", &getter);
|
||||
desc.Get("set", &setter);
|
||||
|
||||
{
|
||||
v8::Context::Scope destination_context_scope(destination_context);
|
||||
v8::Local<v8::Value> getter_proxy;
|
||||
v8::Local<v8::Value> setter_proxy;
|
||||
if (!getter.IsEmpty()) {
|
||||
if (!PassValueToOtherContext(source_context, destination_context,
|
||||
getter, store, object_cache, false,
|
||||
1)
|
||||
.ToLocal(&getter_proxy))
|
||||
continue;
|
||||
}
|
||||
if (!setter.IsEmpty()) {
|
||||
if (!PassValueToOtherContext(source_context, destination_context,
|
||||
setter, store, object_cache, false,
|
||||
1)
|
||||
.ToLocal(&setter_proxy))
|
||||
continue;
|
||||
}
|
||||
|
||||
v8::PropertyDescriptor desc(getter_proxy, setter_proxy);
|
||||
ignore_result(proxy.GetHandle()->DefineProperty(
|
||||
destination_context, gin::StringToV8(api.isolate(), key_str),
|
||||
desc));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
v8::Local<v8::Value> value;
|
||||
if (!api.Get(key_str, &value))
|
||||
continue;
|
||||
|
||||
auto passed_value =
|
||||
PassValueToOtherContext(source_context, destination_context, value,
|
||||
store, object_cache, recursion_depth + 1);
|
||||
auto passed_value = PassValueToOtherContext(
|
||||
source_context, destination_context, value, store, object_cache,
|
||||
support_dynamic_properties, recursion_depth + 1);
|
||||
if (passed_value.IsEmpty())
|
||||
return v8::MaybeLocal<v8::Object>();
|
||||
proxy.Set(key_str, passed_value.ToLocalChecked());
|
||||
@@ -472,8 +519,9 @@ void ExposeAPIInMainWorld(const std::string& key,
|
||||
context_bridge::ObjectCache object_cache;
|
||||
v8::Context::Scope main_context_scope(main_context);
|
||||
{
|
||||
v8::MaybeLocal<v8::Object> maybe_proxy = CreateProxyForAPI(
|
||||
api_object, isolated_context, main_context, store, &object_cache, 0);
|
||||
v8::MaybeLocal<v8::Object> maybe_proxy =
|
||||
CreateProxyForAPI(api_object, isolated_context, main_context, store,
|
||||
&object_cache, false, 0);
|
||||
if (maybe_proxy.IsEmpty())
|
||||
return;
|
||||
auto proxy = maybe_proxy.ToLocalChecked();
|
||||
@@ -484,6 +532,107 @@ void ExposeAPIInMainWorld(const std::string& key,
|
||||
}
|
||||
}
|
||||
|
||||
gin_helper::Dictionary TraceKeyPath(const gin_helper::Dictionary& start,
|
||||
const std::vector<std::string>& key_path) {
|
||||
gin_helper::Dictionary current = start;
|
||||
for (size_t i = 0; i < key_path.size() - 1; i++) {
|
||||
CHECK(current.Get(key_path[i], ¤t));
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
void OverrideGlobalValueFromIsolatedWorld(
|
||||
const std::vector<std::string>& key_path,
|
||||
v8::Local<v8::Object> value,
|
||||
bool support_dynamic_properties) {
|
||||
if (key_path.size() == 0)
|
||||
return;
|
||||
|
||||
auto* render_frame = GetRenderFrame(value);
|
||||
CHECK(render_frame);
|
||||
context_bridge::RenderFrameFunctionStore* store =
|
||||
GetOrCreateStore(render_frame);
|
||||
auto* frame = render_frame->GetWebFrame();
|
||||
CHECK(frame);
|
||||
v8::Local<v8::Context> main_context = frame->MainWorldScriptContext();
|
||||
gin_helper::Dictionary global(main_context->GetIsolate(),
|
||||
main_context->Global());
|
||||
|
||||
const std::string final_key = key_path[key_path.size() - 1];
|
||||
gin_helper::Dictionary target_object = TraceKeyPath(global, key_path);
|
||||
|
||||
{
|
||||
v8::Context::Scope main_context_scope(main_context);
|
||||
context_bridge::ObjectCache object_cache;
|
||||
v8::MaybeLocal<v8::Value> maybe_proxy = PassValueToOtherContext(
|
||||
value->CreationContext(), main_context, value, store, &object_cache,
|
||||
support_dynamic_properties, 1);
|
||||
DCHECK(!maybe_proxy.IsEmpty());
|
||||
auto proxy = maybe_proxy.ToLocalChecked();
|
||||
|
||||
target_object.Set(final_key, proxy);
|
||||
}
|
||||
}
|
||||
|
||||
bool OverrideGlobalPropertyFromIsolatedWorld(
|
||||
const std::vector<std::string>& key_path,
|
||||
v8::Local<v8::Object> getter,
|
||||
v8::Local<v8::Value> setter,
|
||||
gin_helper::Arguments* args) {
|
||||
if (key_path.size() == 0)
|
||||
return false;
|
||||
|
||||
auto* render_frame = GetRenderFrame(getter);
|
||||
CHECK(render_frame);
|
||||
context_bridge::RenderFrameFunctionStore* store =
|
||||
GetOrCreateStore(render_frame);
|
||||
auto* frame = render_frame->GetWebFrame();
|
||||
CHECK(frame);
|
||||
v8::Local<v8::Context> main_context = frame->MainWorldScriptContext();
|
||||
gin_helper::Dictionary global(main_context->GetIsolate(),
|
||||
main_context->Global());
|
||||
|
||||
const std::string final_key = key_path[key_path.size() - 1];
|
||||
v8::Local<v8::Object> target_object =
|
||||
TraceKeyPath(global, key_path).GetHandle();
|
||||
|
||||
{
|
||||
v8::Context::Scope main_context_scope(main_context);
|
||||
context_bridge::ObjectCache object_cache;
|
||||
v8::Local<v8::Value> getter_proxy;
|
||||
v8::Local<v8::Value> setter_proxy;
|
||||
if (!getter->IsNullOrUndefined()) {
|
||||
v8::MaybeLocal<v8::Value> maybe_getter_proxy =
|
||||
PassValueToOtherContext(getter->CreationContext(), main_context,
|
||||
getter, store, &object_cache, false, 1);
|
||||
DCHECK(!maybe_getter_proxy.IsEmpty());
|
||||
getter_proxy = maybe_getter_proxy.ToLocalChecked();
|
||||
}
|
||||
if (!setter->IsNullOrUndefined() && setter->IsObject()) {
|
||||
v8::MaybeLocal<v8::Value> maybe_setter_proxy =
|
||||
PassValueToOtherContext(getter->CreationContext(), main_context,
|
||||
setter, store, &object_cache, false, 1);
|
||||
DCHECK(!maybe_setter_proxy.IsEmpty());
|
||||
setter_proxy = maybe_setter_proxy.ToLocalChecked();
|
||||
}
|
||||
|
||||
v8::PropertyDescriptor desc(getter_proxy, setter_proxy);
|
||||
bool success = IsTrue(target_object->DefineProperty(
|
||||
main_context, gin::StringToV8(args->isolate(), final_key), desc));
|
||||
DCHECK(success);
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsCalledFromMainWorld(v8::Isolate* isolate) {
|
||||
auto* render_frame = GetRenderFrame(isolate->GetCurrentContext()->Global());
|
||||
CHECK(render_frame);
|
||||
auto* frame = render_frame->GetWebFrame();
|
||||
CHECK(frame);
|
||||
v8::Local<v8::Context> main_context = frame->MainWorldScriptContext();
|
||||
return isolate->GetCurrentContext() == main_context;
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace electron
|
||||
@@ -497,6 +646,12 @@ void Initialize(v8::Local<v8::Object> exports,
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
gin_helper::Dictionary dict(isolate, exports);
|
||||
dict.SetMethod("exposeAPIInMainWorld", &electron::api::ExposeAPIInMainWorld);
|
||||
dict.SetMethod("_overrideGlobalValueFromIsolatedWorld",
|
||||
&electron::api::OverrideGlobalValueFromIsolatedWorld);
|
||||
dict.SetMethod("_overrideGlobalPropertyFromIsolatedWorld",
|
||||
&electron::api::OverrideGlobalPropertyFromIsolatedWorld);
|
||||
dict.SetMethod("_isCalledFromMainWorld",
|
||||
&electron::api::IsCalledFromMainWorld);
|
||||
#ifdef DCHECK_IS_ON
|
||||
dict.SetMethod("_debugGCMaps", &electron::api::DebugGC);
|
||||
#endif
|
||||
|
||||
@@ -23,6 +23,7 @@ class RenderFrameFunctionStore;
|
||||
v8::Local<v8::Value> ProxyFunctionWrapper(
|
||||
context_bridge::RenderFrameFunctionStore* store,
|
||||
size_t func_id,
|
||||
bool support_dynamic_properties,
|
||||
gin_helper::Arguments* args);
|
||||
|
||||
v8::MaybeLocal<v8::Object> CreateProxyForAPI(
|
||||
@@ -31,6 +32,7 @@ v8::MaybeLocal<v8::Object> CreateProxyForAPI(
|
||||
const v8::Local<v8::Context>& target_context,
|
||||
context_bridge::RenderFrameFunctionStore* store,
|
||||
context_bridge::ObjectCache* object_cache,
|
||||
bool support_dynamic_properties,
|
||||
int recursion_depth);
|
||||
|
||||
} // namespace api
|
||||
|
||||
@@ -218,6 +218,9 @@ void ElectronRendererClient::WillDestroyWorkerContextOnWorkerThread(
|
||||
void ElectronRendererClient::SetupMainWorldOverrides(
|
||||
v8::Handle<v8::Context> context,
|
||||
content::RenderFrame* render_frame) {
|
||||
// We only need to run the isolated bundle if webview is enabled
|
||||
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kWebviewTag))
|
||||
return;
|
||||
// Setup window overrides in the main world context
|
||||
// Wrap the bundle into a function that receives the isolatedWorld as
|
||||
// an argument.
|
||||
|
||||
@@ -232,6 +232,10 @@ void ElectronSandboxedRendererClient::DidCreateScriptContext(
|
||||
void ElectronSandboxedRendererClient::SetupMainWorldOverrides(
|
||||
v8::Handle<v8::Context> context,
|
||||
content::RenderFrame* render_frame) {
|
||||
// We only need to run the isolated bundle if webview is enabled
|
||||
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kWebviewTag))
|
||||
return;
|
||||
|
||||
// Setup window overrides in the main world context
|
||||
// Wrap the bundle into a function that receives the isolatedWorld as
|
||||
// an argument.
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "third_party/blink/public/web/web_local_frame.h"
|
||||
// In SHARED_INTERMEDIATE_DIR.
|
||||
#include "widevine_cdm_version.h" // NOLINT(build/include)
|
||||
#include "widevine_cdm_version.h" // NOLINT(build/include_directory)
|
||||
|
||||
#if defined(WIDEVINE_CDM_AVAILABLE)
|
||||
#include "chrome/renderer/media/chrome_key_systems_provider.h" // nogncheck
|
||||
|
||||
@@ -943,8 +943,9 @@ describe('BrowserWindow module', () => {
|
||||
w.setPosition(pos[0], pos[1]);
|
||||
});
|
||||
});
|
||||
ifdescribe(process.platform !== 'linux')(`Maximized state`, () => {
|
||||
it(`checks normal bounds when maximized`, (done) => {
|
||||
|
||||
ifdescribe(process.platform !== 'linux')('Maximized state', () => {
|
||||
it('checks normal bounds when maximized', (done) => {
|
||||
const bounds = w.getBounds();
|
||||
w.once('maximize', () => {
|
||||
expectBoundsEqual(w.getNormalBounds(), bounds);
|
||||
@@ -966,8 +967,9 @@ describe('BrowserWindow module', () => {
|
||||
w.maximize();
|
||||
});
|
||||
});
|
||||
ifdescribe(process.platform !== 'linux')(`Minimized state`, () => {
|
||||
it(`checks normal bounds when minimized`, (done) => {
|
||||
|
||||
ifdescribe(process.platform !== 'linux')('Minimized state', () => {
|
||||
it('checks normal bounds when minimized', (done) => {
|
||||
const bounds = w.getBounds();
|
||||
w.once('minimize', () => {
|
||||
expectBoundsEqual(w.getNormalBounds(), bounds);
|
||||
@@ -989,6 +991,7 @@ describe('BrowserWindow module', () => {
|
||||
w.minimize();
|
||||
});
|
||||
});
|
||||
|
||||
ifdescribe(process.platform === 'win32')(`Fullscreen state`, () => {
|
||||
it(`checks normal bounds when fullscreen'ed`, (done) => {
|
||||
const bounds = w.getBounds();
|
||||
@@ -999,6 +1002,7 @@ describe('BrowserWindow module', () => {
|
||||
w.show();
|
||||
w.setFullScreen(true);
|
||||
});
|
||||
|
||||
it(`checks normal bounds when unfullscreen'ed`, (done) => {
|
||||
const bounds = w.getBounds();
|
||||
w.once('enter-full-screen', () => {
|
||||
@@ -3403,6 +3407,96 @@ describe('BrowserWindow module', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('visibleOnAllWorkspaces state', () => {
|
||||
it('with properties', () => {
|
||||
it('can be changed', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
expect(w.visibleOnAllWorkspaces).to.be.false();
|
||||
w.visibleOnAllWorkspaces = true;
|
||||
expect(w.visibleOnAllWorkspaces).to.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('with functions', () => {
|
||||
it('can be changed', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
expect(w.isVisibleOnAllWorkspaces()).to.be.false();
|
||||
w.setVisibleOnAllWorkspaces(true);
|
||||
expect(w.isVisibleOnAllWorkspaces()).to.be.true();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
ifdescribe(process.platform === 'darwin')('documentEdited state', () => {
|
||||
it('with properties', () => {
|
||||
it('can be changed', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
expect(w.documentEdited).to.be.false();
|
||||
w.documentEdited = true;
|
||||
expect(w.documentEdited).to.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('with functions', () => {
|
||||
it('can be changed', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
expect(w.isDocumentEdited()).to.be.false();
|
||||
w.setDocumentEdited(true);
|
||||
expect(w.isDocumentEdited()).to.be.true();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
ifdescribe(process.platform === 'darwin')('representedFilename', () => {
|
||||
it('with properties', () => {
|
||||
it('can be changed', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
expect(w.representedFilename).to.eql('');
|
||||
w.representedFilename = 'a name';
|
||||
expect(w.representedFilename).to.eql('a name');
|
||||
});
|
||||
});
|
||||
|
||||
it('with functions', () => {
|
||||
it('can be changed', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
expect(w.getRepresentedFilename()).to.eql('');
|
||||
w.setRepresentedFilename('a name');
|
||||
expect(w.getRepresentedFilename()).to.eql('a name');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('native window title', () => {
|
||||
it('with properties', () => {
|
||||
it('can be set with title constructor option', () => {
|
||||
const w = new BrowserWindow({ show: false, title: 'mYtItLe' });
|
||||
expect(w.title).to.eql('mYtItLe');
|
||||
});
|
||||
|
||||
it('can be changed', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
expect(w.title).to.eql('Electron Test Main');
|
||||
w.title = 'NEW TITLE';
|
||||
expect(w.title).to.eql('NEW TITLE');
|
||||
});
|
||||
});
|
||||
|
||||
it('with functions', () => {
|
||||
it('can be set with minimizable constructor option', () => {
|
||||
const w = new BrowserWindow({ show: false, title: 'mYtItLe' });
|
||||
expect(w.getTitle()).to.eql('mYtItLe');
|
||||
});
|
||||
|
||||
it('can be changed', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
expect(w.getTitle()).to.eql('Electron Test Main');
|
||||
w.setTitle('NEW TITLE');
|
||||
expect(w.getTitle()).to.eql('NEW TITLE');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('minimizable state', () => {
|
||||
it('with properties', () => {
|
||||
it('can be set with minimizable constructor option', () => {
|
||||
@@ -3535,23 +3629,31 @@ describe('BrowserWindow module', () => {
|
||||
});
|
||||
});
|
||||
|
||||
ifdescribe(process.platform === 'darwin')('fullscreenable state', () => {
|
||||
it('with properties', () => {
|
||||
it('can be set with fullscreenable constructor option', () => {
|
||||
const w = new BrowserWindow({ show: false, fullscreenable: false });
|
||||
expect(w.fullScreenable).to.be.false('fullScreenable');
|
||||
});
|
||||
|
||||
ifdescribe(process.platform !== 'darwin')('menuBarVisible state', () => {
|
||||
describe('with properties', () => {
|
||||
it('can be changed', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
expect(w.fullScreenable).to.be.true('fullScreenable');
|
||||
w.fullScreenable = false;
|
||||
expect(w.fullScreenable).to.be.false('fullScreenable');
|
||||
w.fullScreenable = true;
|
||||
expect(w.fullScreenable).to.be.true('fullScreenable');
|
||||
expect(w.menuBarVisible).to.be.true();
|
||||
w.menuBarVisible = false;
|
||||
expect(w.menuBarVisible).to.be.false();
|
||||
w.menuBarVisible = true;
|
||||
expect(w.menuBarVisible).to.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with functions', () => {
|
||||
it('can be changed', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
expect(w.isMenuBarVisible()).to.be.true('isMenuBarVisible');
|
||||
w.setMenuBarVisibility(false);
|
||||
expect(w.isMenuBarVisible()).to.be.false('isMenuBarVisible');
|
||||
w.setMenuBarVisibility(true);
|
||||
expect(w.isMenuBarVisible()).to.be.true('isMenuBarVisible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
ifdescribe(process.platform === 'darwin')('fullscreenable state', () => {
|
||||
it('with functions', () => {
|
||||
it('can be set with fullscreenable constructor option', () => {
|
||||
const w = new BrowserWindow({ show: false, fullscreenable: false });
|
||||
@@ -3573,18 +3675,46 @@ describe('BrowserWindow module', () => {
|
||||
const tick = () => new Promise(resolve => setTimeout(resolve));
|
||||
|
||||
ifdescribe(process.platform === 'darwin')('kiosk state', () => {
|
||||
it('can be changed with setKiosk method', (done) => {
|
||||
const w = new BrowserWindow();
|
||||
w.once('enter-full-screen', async () => {
|
||||
await tick();
|
||||
w.setKiosk(false);
|
||||
expect(w.isKiosk()).to.be.false('isKiosk');
|
||||
it('with properties', () => {
|
||||
it('can be set with a constructor property', () => {
|
||||
const w = new BrowserWindow({ kiosk: true });
|
||||
expect(w.kiosk).to.be.true();
|
||||
});
|
||||
w.once('leave-full-screen', () => {
|
||||
done();
|
||||
|
||||
it('can be changed ', (done) => {
|
||||
const w = new BrowserWindow();
|
||||
w.once('enter-full-screen', async () => {
|
||||
await tick();
|
||||
w.kiosk = false;
|
||||
expect(w.kiosk).to.be.false();
|
||||
});
|
||||
w.once('leave-full-screen', () => {
|
||||
done();
|
||||
});
|
||||
w.kiosk = true;
|
||||
expect(w.kiosk).to.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
it('with functions', () => {
|
||||
it('can be set with a constructor property', () => {
|
||||
const w = new BrowserWindow({ kiosk: true });
|
||||
expect(w.isKiosk()).to.be.true();
|
||||
});
|
||||
|
||||
it('can be changed ', (done) => {
|
||||
const w = new BrowserWindow();
|
||||
w.once('enter-full-screen', async () => {
|
||||
await tick();
|
||||
w.setKiosk(false);
|
||||
expect(w.isKiosk()).to.be.false('isKiosk');
|
||||
});
|
||||
w.once('leave-full-screen', () => {
|
||||
done();
|
||||
});
|
||||
w.setKiosk(true);
|
||||
expect(w.isKiosk()).to.be.true('isKiosk');
|
||||
});
|
||||
w.setKiosk(true);
|
||||
expect(w.isKiosk()).to.be.true('isKiosk');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3619,7 +3749,7 @@ describe('BrowserWindow module', () => {
|
||||
w.setFullScreen(true);
|
||||
});
|
||||
|
||||
it('does not crash when exiting simpleFullScreen', (done) => {
|
||||
it('does not crash when exiting simpleFullScreen (properties)', (done) => {
|
||||
const w = new BrowserWindow();
|
||||
w.setSimpleFullScreen(true);
|
||||
|
||||
@@ -3629,6 +3759,16 @@ describe('BrowserWindow module', () => {
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
it('does not crash when exiting simpleFullScreen (functions)', (done) => {
|
||||
const w = new BrowserWindow();
|
||||
w.simpleFullScreen = true;
|
||||
|
||||
setTimeout(() => {
|
||||
w.setFullScreen(!w.isFullScreen());
|
||||
done();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
it('should not be changed by setKiosk method', (done) => {
|
||||
const w = new BrowserWindow();
|
||||
w.once('enter-full-screen', async () => {
|
||||
@@ -3683,27 +3823,53 @@ describe('BrowserWindow module', () => {
|
||||
});
|
||||
|
||||
describe('hasShadow state', () => {
|
||||
it('returns a boolean on all platforms', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
const hasShadow = w.hasShadow();
|
||||
expect(hasShadow).to.be.a('boolean');
|
||||
it('with properties', () => {
|
||||
it('returns a boolean on all platforms', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
expect(w.shadow).to.be.a('boolean');
|
||||
});
|
||||
|
||||
// On Windows there's no shadow by default & it can't be changed dynamically.
|
||||
it('can be changed with hasShadow option', () => {
|
||||
const hasShadow = process.platform !== 'darwin';
|
||||
const w = new BrowserWindow({ show: false, hasShadow });
|
||||
expect(w.shadow).to.equal(hasShadow);
|
||||
});
|
||||
|
||||
it('can be changed with setHasShadow method', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
w.shadow = false;
|
||||
expect(w.shadow).to.be.false('hasShadow');
|
||||
w.shadow = true;
|
||||
expect(w.shadow).to.be.true('hasShadow');
|
||||
w.shadow = false;
|
||||
expect(w.shadow).to.be.false('hasShadow');
|
||||
});
|
||||
});
|
||||
|
||||
// On Windows there's no shadow by default & it can't be changed dynamically.
|
||||
it('can be changed with hasShadow option', () => {
|
||||
const hasShadow = process.platform !== 'darwin';
|
||||
const w = new BrowserWindow({ show: false, hasShadow });
|
||||
expect(w.hasShadow()).to.equal(hasShadow);
|
||||
});
|
||||
describe('with functions', () => {
|
||||
it('returns a boolean on all platforms', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
const hasShadow = w.hasShadow();
|
||||
expect(hasShadow).to.be.a('boolean');
|
||||
});
|
||||
|
||||
it('can be changed with setHasShadow method', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
w.setHasShadow(false);
|
||||
expect(w.hasShadow()).to.be.false('hasShadow');
|
||||
w.setHasShadow(true);
|
||||
expect(w.hasShadow()).to.be.true('hasShadow');
|
||||
w.setHasShadow(false);
|
||||
expect(w.hasShadow()).to.be.false('hasShadow');
|
||||
// On Windows there's no shadow by default & it can't be changed dynamically.
|
||||
it('can be changed with hasShadow option', () => {
|
||||
const hasShadow = process.platform !== 'darwin';
|
||||
const w = new BrowserWindow({ show: false, hasShadow });
|
||||
expect(w.hasShadow()).to.equal(hasShadow);
|
||||
});
|
||||
|
||||
it('can be changed with setHasShadow method', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
w.setHasShadow(false);
|
||||
expect(w.hasShadow()).to.be.false('hasShadow');
|
||||
w.setHasShadow(true);
|
||||
expect(w.hasShadow()).to.be.true('hasShadow');
|
||||
w.setHasShadow(false);
|
||||
expect(w.hasShadow()).to.be.false('hasShadow');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -345,16 +345,19 @@ describe('contextBridge', () => {
|
||||
getFunction: () => () => 123
|
||||
});
|
||||
});
|
||||
expect((await getGCInfo()).functionCount).to.equal(2);
|
||||
await callWithBindings(async (root: any) => {
|
||||
root.GCRunner.run();
|
||||
});
|
||||
const baseValue = (await getGCInfo()).functionCount;
|
||||
await callWithBindings(async (root: any) => {
|
||||
root.x = [root.example.getFunction()];
|
||||
});
|
||||
expect((await getGCInfo()).functionCount).to.equal(3);
|
||||
expect((await getGCInfo()).functionCount).to.equal(baseValue + 1);
|
||||
await callWithBindings(async (root: any) => {
|
||||
root.x = [];
|
||||
root.GCRunner.run();
|
||||
});
|
||||
expect((await getGCInfo()).functionCount).to.equal(2);
|
||||
expect((await getGCInfo()).functionCount).to.equal(baseValue);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -368,14 +371,14 @@ describe('contextBridge', () => {
|
||||
require('electron').ipcRenderer.send('window-ready-for-tasking');
|
||||
});
|
||||
const loadPromise = emittedOnce(ipcMain, 'window-ready-for-tasking');
|
||||
expect((await getGCInfo()).functionCount).to.equal(1);
|
||||
const baseValue = (await getGCInfo()).functionCount;
|
||||
await callWithBindings((root: any) => {
|
||||
root.location.reload();
|
||||
});
|
||||
await loadPromise;
|
||||
// If this is ever "2" it means we leaked the exposed function and
|
||||
// therefore the entire context after a reload
|
||||
expect((await getGCInfo()).functionCount).to.equal(1);
|
||||
expect((await getGCInfo()).functionCount).to.equal(baseValue);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
const { app, BrowserWindow } = require('electron');
|
||||
|
||||
let win;
|
||||
app.whenReady().then(function () {
|
||||
// This test uses "app.once('ready')" while the |test-menu-null| test uses
|
||||
// "app.whenReady()", the 2 APIs have slight difference on timing to cover
|
||||
// more cases.
|
||||
app.once('ready', function () {
|
||||
win = new BrowserWindow({});
|
||||
win.setMenuBarVisibility(false);
|
||||
|
||||
|
||||
@@ -65,13 +65,6 @@ describe('chromium feature', () => {
|
||||
});
|
||||
|
||||
describe('window.open', () => {
|
||||
it('returns a BrowserWindowProxy object', () => {
|
||||
const b = window.open('about:blank', '', 'show=no');
|
||||
expect(b.closed).to.be.false();
|
||||
expect(b.constructor.name).to.equal('BrowserWindowProxy');
|
||||
b.close();
|
||||
});
|
||||
|
||||
it('accepts "nodeIntegration" as feature', (done) => {
|
||||
let b = null;
|
||||
listener = (event) => {
|
||||
@@ -198,8 +191,8 @@ describe('chromium feature', () => {
|
||||
let b = null;
|
||||
listener = (event) => {
|
||||
window.removeEventListener('message', listener);
|
||||
expect(event.source).to.deep.equal(b);
|
||||
b.close();
|
||||
expect(event.source).to.equal(b);
|
||||
expect(event.origin).to.equal('file://');
|
||||
done();
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
window.opener.postMessage(JSON.stringify({
|
||||
origin: e.origin,
|
||||
data: e.data,
|
||||
sourceEqualsOpener: e.source === window.opener
|
||||
sourceEqualsOpener: e.source.location.href === window.opener.location.href
|
||||
}), '*');
|
||||
});
|
||||
window.opener.postMessage("ready", "*")
|
||||
|
||||
Reference in New Issue
Block a user