mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
74 Commits
moar-adapt
...
v12.0.0-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e7ff69a4e | ||
|
|
f5af20d1d6 | ||
|
|
3f2ccce9e1 | ||
|
|
8e7862ed4b | ||
|
|
48a8fdfdb6 | ||
|
|
e9c39163bf | ||
|
|
dc657515b7 | ||
|
|
8eb4ab0ae1 | ||
|
|
92c8614e14 | ||
|
|
f3ce79936a | ||
|
|
d498d4bf18 | ||
|
|
df21f17131 | ||
|
|
c6d144d550 | ||
|
|
6553c4418f | ||
|
|
ecf981a91a | ||
|
|
b5cfa03a63 | ||
|
|
1bbf71c090 | ||
|
|
97b40e4e45 | ||
|
|
975123b6bf | ||
|
|
011315574c | ||
|
|
cfd848c32f | ||
|
|
81db78daec | ||
|
|
ce0faeed90 | ||
|
|
e6885668d4 | ||
|
|
a1df860b66 | ||
|
|
ba76f6846e | ||
|
|
ce8d301921 | ||
|
|
39f865e4e3 | ||
|
|
e6727fb7bd | ||
|
|
c9564ff648 | ||
|
|
76be3b9211 | ||
|
|
d132800944 | ||
|
|
558bcc65bc | ||
|
|
bf25d484a4 | ||
|
|
d2c4b594bd | ||
|
|
601af0b016 | ||
|
|
130a65d008 | ||
|
|
fe022df628 | ||
|
|
5b47fd7cbf | ||
|
|
9b1913b613 | ||
|
|
36c695ce2a | ||
|
|
afcdf661a0 | ||
|
|
3d01b83daa | ||
|
|
e77d9ff3b9 | ||
|
|
fb35356b47 | ||
|
|
37d21bb80e | ||
|
|
e84539f2e0 | ||
|
|
d2591ed4f8 | ||
|
|
6b54fe37de | ||
|
|
561fe63813 | ||
|
|
9543f8b30a | ||
|
|
cec2c73733 | ||
|
|
2e9305d964 | ||
|
|
0491cc6906 | ||
|
|
badcdd6566 | ||
|
|
a0d0bd60a5 | ||
|
|
c0f0a02419 | ||
|
|
8046f0560a | ||
|
|
2a8961b52f | ||
|
|
36163af228 | ||
|
|
29f42e943e | ||
|
|
4597cb6499 | ||
|
|
4ba78b81c1 | ||
|
|
80e0473649 | ||
|
|
db0d4c8224 | ||
|
|
4fbb58020c | ||
|
|
c9801ab5a5 | ||
|
|
46441c1bd7 | ||
|
|
1cac3354e7 | ||
|
|
57c69ab3ac | ||
|
|
39b9c40a05 | ||
|
|
66a22a28a5 | ||
|
|
17a8b7724b | ||
|
|
c512995426 |
@@ -295,10 +295,10 @@ step-setup-goma-for-build: &step-setup-goma-for-build
|
||||
run:
|
||||
name: Setup Goma
|
||||
command: |
|
||||
if [ "`uname`" == "Linux" ]; then
|
||||
echo 'export NUMBER_OF_NINJA_PROCESSES=300' >> $BASH_ENV
|
||||
else
|
||||
echo 'export NUMBER_OF_NINJA_PROCESSES=25' >> $BASH_ENV
|
||||
echo 'export NUMBER_OF_NINJA_PROCESSES=300' >> $BASH_ENV
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
echo 'ulimit -n 10000' >> $BASH_ENV
|
||||
echo 'sudo launchctl limit maxfiles 65536 200000' >> $BASH_ENV
|
||||
fi
|
||||
if [ ! -z "$RAW_GOMA_AUTH" ]; then
|
||||
echo $RAW_GOMA_AUTH > ~/.goma_oauth2_config
|
||||
@@ -307,7 +307,7 @@ step-setup-goma-for-build: &step-setup-goma-for-build
|
||||
cd build-tools
|
||||
npm install
|
||||
mkdir third_party
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare()"
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
|
||||
node -e "require('./src/utils/goma.js').ensure()"
|
||||
echo 'export GN_GOMA_FILE='`node -e "console.log(require('./src/utils/goma.js').gnFilePath)"` >> $BASH_ENV
|
||||
echo 'export LOCAL_GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV
|
||||
@@ -316,15 +316,17 @@ step-setup-goma-for-build: &step-setup-goma-for-build
|
||||
step-restore-brew-cache: &step-restore-brew-cache
|
||||
restore_cache:
|
||||
paths:
|
||||
- /usr/local/Homebrew
|
||||
- /usr/local/Cellar/gnu-tar
|
||||
- /usr/local/bin/gtar
|
||||
keys:
|
||||
- v2-brew-cache-{{ arch }}
|
||||
- v4-brew-cache-{{ arch }}
|
||||
|
||||
step-save-brew-cache: &step-save-brew-cache
|
||||
save_cache:
|
||||
paths:
|
||||
- /usr/local/Homebrew
|
||||
key: v2-brew-cache-{{ arch }}
|
||||
- /usr/local/Cellar/gnu-tar
|
||||
- /usr/local/bin/gtar
|
||||
key: v4-brew-cache-{{ arch }}
|
||||
name: Persisting brew cache
|
||||
|
||||
step-get-more-space-on-mac: &step-get-more-space-on-mac
|
||||
@@ -464,8 +466,10 @@ step-install-gnutar-on-mac: &step-install-gnutar-on-mac
|
||||
name: Install gnu-tar on macos
|
||||
command: |
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
brew update
|
||||
brew install gnu-tar
|
||||
if [ ! -d /usr/local/Cellar/gnu-tar/ ]; then
|
||||
brew update
|
||||
brew install gnu-tar
|
||||
fi
|
||||
ln -fs /usr/local/bin/gtar /usr/local/bin/tar
|
||||
fi
|
||||
|
||||
@@ -893,6 +897,8 @@ step-ninja-summary: &step-ninja-summary
|
||||
run:
|
||||
name: Print ninja summary
|
||||
command: |
|
||||
set +e
|
||||
set +o pipefail
|
||||
python depot_tools/post_build_ninja_summary.py -C src/out/Default
|
||||
|
||||
step-ninja-report: &step-ninja-report
|
||||
@@ -1196,7 +1202,6 @@ steps-electron-ts-compile-for-doc-change: &steps-electron-ts-compile-for-doc-cha
|
||||
- *step-depot-tools-add-to-path
|
||||
- *step-setup-env-for-build
|
||||
- *step-setup-goma-for-build
|
||||
- *step-restore-brew-cache
|
||||
- *step-get-more-space-on-mac
|
||||
- *step-install-npm-deps-on-mac
|
||||
- *step-fix-sync-on-mac
|
||||
|
||||
2
DEPS
2
DEPS
@@ -20,7 +20,7 @@ vars = {
|
||||
'nan_version':
|
||||
'2c4ee8a32a299eada3cd6e468bbd0a473bfea96d',
|
||||
'squirrel.mac_version':
|
||||
'a3a5b3f03b824441c014893b18f99a103b2603e9',
|
||||
'cdc0729c8bf8576bfef18629186e1e9ecf1b0d9f',
|
||||
|
||||
'pyyaml_version': '3.12',
|
||||
'requests_version': 'e4d59bedfd3c7f4f254f4f5d036587bcd8152458',
|
||||
|
||||
@@ -1 +1 @@
|
||||
12.0.0-nightly.20201118
|
||||
12.0.0-beta.14
|
||||
@@ -141,7 +141,8 @@ build_script:
|
||||
- cd build-tools
|
||||
- npm install
|
||||
- mkdir third_party
|
||||
- node -e "require('./src/utils/goma.js').downloadAndPrepare()"
|
||||
- ps: >-
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
|
||||
- ps: $env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)"
|
||||
- ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)"
|
||||
- cd ..
|
||||
|
||||
@@ -1051,7 +1051,7 @@ Returns `Boolean` - Whether the window is in simple (pre-Lion) fullscreen mode.
|
||||
|
||||
Returns `Boolean` - Whether the window is in normal state (not maximized, not minimized, not in fullscreen mode).
|
||||
|
||||
#### `win.setAspectRatio(aspectRatio[, extraSize])` _macOS_ _Linux_
|
||||
#### `win.setAspectRatio(aspectRatio[, extraSize])`
|
||||
|
||||
* `aspectRatio` Float - The aspect ratio to maintain for some portion of the
|
||||
content view.
|
||||
@@ -1072,6 +1072,9 @@ the player itself we would call this function with arguments of 16/9 and
|
||||
are within the content view--only that they exist. Sum any extra width and
|
||||
height areas you have within the overall content view.
|
||||
|
||||
The aspect ratio is not respected when window is resized programmingly with
|
||||
APIs like `win.setSize`.
|
||||
|
||||
#### `win.setBackgroundColor(backgroundColor)`
|
||||
|
||||
* `backgroundColor` String - Window's background color as a hexadecimal value,
|
||||
|
||||
@@ -16,7 +16,7 @@ const { app, contentTracing } = require('electron')
|
||||
app.whenReady().then(() => {
|
||||
(async () => {
|
||||
await contentTracing.startRecording({
|
||||
include_categories: ['*']
|
||||
included_categories: ['*']
|
||||
})
|
||||
console.log('Tracing started')
|
||||
await new Promise(resolve => setTimeout(resolve, 5000))
|
||||
|
||||
@@ -128,7 +128,7 @@ must be at most 39 bytes long, and values must be no longer than 127 bytes.
|
||||
Keys with names longer than the maximum will be silently ignored. Key values
|
||||
longer than the maximum length will be truncated.
|
||||
|
||||
**Note:** Calling this method from the renderer process is deprecated.
|
||||
**Note:** This method is only available in the main process.
|
||||
|
||||
### `crashReporter.getLastCrashReport()`
|
||||
|
||||
@@ -137,7 +137,7 @@ last crash report. Only crash reports that have been uploaded will be returned;
|
||||
even if a crash report is present on disk it will not be returned until it is
|
||||
uploaded. In the case that there are no uploaded reports, `null` is returned.
|
||||
|
||||
**Note:** Calling this method from the renderer process is deprecated.
|
||||
**Note:** This method is only available in the main process.
|
||||
|
||||
### `crashReporter.getUploadedReports()`
|
||||
|
||||
@@ -146,14 +146,14 @@ Returns [`CrashReport[]`](structures/crash-report.md):
|
||||
Returns all uploaded crash reports. Each report contains the date and uploaded
|
||||
ID.
|
||||
|
||||
**Note:** Calling this method from the renderer process is deprecated.
|
||||
**Note:** This method is only available in the main process.
|
||||
|
||||
### `crashReporter.getUploadToServer()`
|
||||
|
||||
Returns `Boolean` - Whether reports should be submitted to the server. Set through
|
||||
the `start` method or `setUploadToServer`.
|
||||
|
||||
**Note:** Calling this method from the renderer process is deprecated.
|
||||
**Note:** This method is only available in the main process.
|
||||
|
||||
### `crashReporter.setUploadToServer(uploadToServer)`
|
||||
|
||||
@@ -162,13 +162,7 @@ the `start` method or `setUploadToServer`.
|
||||
This would normally be controlled by user preferences. This has no effect if
|
||||
called before `start` is called.
|
||||
|
||||
**Note:** Calling this method from the renderer process is deprecated.
|
||||
|
||||
### `crashReporter.getCrashesDirectory()` _Deprecated_
|
||||
|
||||
Returns `String` - The directory where crashes are temporarily stored before being uploaded.
|
||||
|
||||
**Note:** This method is deprecated, use `app.getPath('crashDumps')` instead.
|
||||
**Note:** This method is only available in the main process.
|
||||
|
||||
### `crashReporter.addExtraParameter(key, value)`
|
||||
|
||||
|
||||
@@ -115,3 +115,9 @@ The following methods of `chrome.management` are supported:
|
||||
- `chrome.management.getPermissionWarningsByManifest`
|
||||
- `chrome.management.onEnabled`
|
||||
- `chrome.management.onDisabled`
|
||||
|
||||
### `chrome.webRequest`
|
||||
|
||||
All features of this API are supported.
|
||||
|
||||
> **NOTE:** Electron's [`webRequest`](web-request.md) module takes precedence over `chrome.webRequest` if there are conflicting handlers.
|
||||
|
||||
@@ -9,7 +9,7 @@ with the operating system so that you can customize the operations for various
|
||||
shortcuts.
|
||||
|
||||
**Note:** The shortcut is global; it will work even if the app does
|
||||
not have the keyboard focus. You should not use this module until the `ready`
|
||||
not have the keyboard focus. This module cannot be used before the `ready`
|
||||
event of the app module is emitted.
|
||||
|
||||
```javascript
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# IpcMainEvent Object extends `Event`
|
||||
|
||||
* `processId` Integer - The internal ID of the renderer process that sent this message
|
||||
* `frameId` Integer - The ID of the renderer frame that sent this message
|
||||
* `returnValue` any - Set this to the value to be returned in a synchronous message
|
||||
* `sender` WebContents - Returns the `webContents` that sent the message
|
||||
* `senderFrame` WebFrameMain _Readonly_ - The frame that sent this message
|
||||
* `ports` MessagePortMain[] - A list of MessagePorts that were transferred with this message
|
||||
* `reply` Function - A function that will send an IPC message to the renderer frame that sent the original message that you are currently handling. You should use this method to "reply" to the sent message in order to guarantee the reply will go to the correct process and frame.
|
||||
* `channel` String
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# IpcMainInvokeEvent Object extends `Event`
|
||||
|
||||
* `processId` Integer - The internal ID of the renderer process that sent this message
|
||||
* `frameId` Integer - The ID of the renderer frame that sent this message
|
||||
* `sender` WebContents - Returns the `webContents` that sent the message
|
||||
* `senderFrame` WebFrameMain _Readonly_ - The frame that sent this message
|
||||
|
||||
@@ -42,7 +42,8 @@ returns `null`.
|
||||
|
||||
* `id` Integer
|
||||
|
||||
Returns `WebContents` - A WebContents instance with the given ID.
|
||||
Returns `WebContents` | undefined - A WebContents instance with the given ID, or
|
||||
`undefined` if there is no WebContents associated with the given ID.
|
||||
|
||||
## Class: WebContents
|
||||
|
||||
@@ -155,7 +156,7 @@ Returns:
|
||||
be set. If no post data is to be sent, the value will be `null`. Only defined
|
||||
when the window is being created by a form that set `target=_blank`.
|
||||
|
||||
Deprecated in favor of [`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
|
||||
Deprecated in favor of [`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandlerhandler).
|
||||
|
||||
Emitted when the page requests to open a new window for a `url`. It could be
|
||||
requested by `window.open` or an external link like `<a target='_blank'>`.
|
||||
@@ -203,7 +204,7 @@ Returns:
|
||||
BrowserWindow. They are merged in increasing precedence: options inherited
|
||||
from the parent, parsed options from the `features` string from
|
||||
`window.open()`, and options given by
|
||||
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
|
||||
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandlerhandler).
|
||||
Unrecognized options are not filtered out.
|
||||
* `additionalFeatures` String[] - The non-standard features (features not
|
||||
handled Chromium or Electron) _Deprecated_
|
||||
@@ -220,7 +221,7 @@ Returns:
|
||||
|
||||
Emitted _after_ successful creation of a window via `window.open` in the renderer.
|
||||
Not emitted if the creation of the window is canceled from
|
||||
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
|
||||
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandlerhandler).
|
||||
|
||||
See [`window.open()`](window-open.md) for more details and how to use this in conjunction with `webContents.setWindowOpenHandler`.
|
||||
|
||||
@@ -1694,7 +1695,9 @@ app.whenReady().then(() => {
|
||||
|
||||
#### `contents.sendToFrame(frameId, channel, ...args)`
|
||||
|
||||
* `frameId` Integer
|
||||
* `frameId` Integer | [number, number] - the ID of the frame to send to, or a
|
||||
pair of `[processId, frameId]` if the frame is in a different process to the
|
||||
main frame.
|
||||
* `channel` String
|
||||
* `...args` any[]
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ win.webContents.on(
|
||||
)
|
||||
```
|
||||
|
||||
You can also access frames of existing pages by using the `webFrame` property
|
||||
You can also access frames of existing pages by using the `mainFrame` property
|
||||
of [`WebContents`](web-contents.md).
|
||||
|
||||
```javascript
|
||||
@@ -57,13 +57,14 @@ These methods can be accessed from the `webFrameMain` module:
|
||||
|
||||
### `webFrameMain.fromId(processId, routingId)`
|
||||
|
||||
* `processId` Integer - An `Integer` representing the id of the process which owns the frame.
|
||||
* `routingId` Integer - An `Integer` representing the unique frame id in the
|
||||
* `processId` Integer - An `Integer` representing the internal ID of the process which owns the frame.
|
||||
* `routingId` Integer - An `Integer` representing the unique frame ID in the
|
||||
current renderer process. Routing IDs can be retrieved from `WebFrameMain`
|
||||
instances (`frame.routingId`) and are also passed by frame
|
||||
specific `WebContents` navigation events (e.g. `did-frame-navigate`).
|
||||
|
||||
Returns `WebFrameMain` - A frame with the given process and routing IDs.
|
||||
Returns `WebFrameMain | undefined` - A frame with the given process and routing IDs,
|
||||
or `undefined` if there is no WebFrameMain associated with the given IDs.
|
||||
|
||||
## Class: WebFrameMain
|
||||
|
||||
@@ -85,6 +86,17 @@ In the browser window some HTML APIs like `requestFullScreen` can only be
|
||||
invoked by a gesture from the user. Setting `userGesture` to `true` will remove
|
||||
this limitation.
|
||||
|
||||
#### `frame.executeJavaScriptInIsolatedWorld(worldId, code[, userGesture])`
|
||||
|
||||
* `worldId` Integer - The ID of the world to run the javascript in, `0` is the default world, `999` is the world used by Electron's `contextIsolation` feature. You can provide any integer here.
|
||||
* `code` String
|
||||
* `userGesture` Boolean (optional) - Default is `false`.
|
||||
|
||||
Returns `Promise<unknown>` - A promise that resolves with the result of the executed
|
||||
code or is rejected if execution throws or results in a rejected promise.
|
||||
|
||||
Works like `executeJavaScript` but evaluates `scripts` in an isolated context.
|
||||
|
||||
#### `frame.reload()`
|
||||
|
||||
Returns `boolean` - Whether the reload was initiated successfully. Only results in `false` when the frame has no history.
|
||||
|
||||
@@ -966,4 +966,4 @@ Emitted when DevTools is closed.
|
||||
Emitted when DevTools is focused / opened.
|
||||
|
||||
[runtime-enabled-features]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/runtime_enabled_features.json5?l=70
|
||||
[chrome-webview]: https://developer.chrome.com/apps/tags/webview
|
||||
[chrome-webview]: https://developer.chrome.com/docs/extensions/reference/webviewTag/
|
||||
|
||||
@@ -26,7 +26,7 @@ BrowserWindow constructor options are set by, in increasing precedence
|
||||
order: options inherited from the parent, parsed options
|
||||
from the `features` string from `window.open()`, security-related webPreferences
|
||||
inherited from the parent, and options given by
|
||||
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
|
||||
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandlerhandler).
|
||||
Note that `webContents.setWindowOpenHandler` has final say and full privilege
|
||||
because it is invoked in the main process.
|
||||
|
||||
|
||||
@@ -43,6 +43,18 @@ We [recommend having contextIsolation enabled](https://github.com/electron/elect
|
||||
|
||||
For more details see: https://github.com/electron/electron/issues/23506
|
||||
|
||||
### Removed: `crashReporter.getCrashesDirectory()`
|
||||
|
||||
The `crashReporter.getCrashesDirectory` method has been removed. Usage
|
||||
should be replaced by `app.getPath('crashDumps')`.
|
||||
|
||||
```js
|
||||
// Removed in Electron 12
|
||||
crashReporter.getCrashesDirectory()
|
||||
// Replace with
|
||||
app.getPath('crashDumps')
|
||||
```
|
||||
|
||||
### Removed: `crashReporter` methods in the renderer process
|
||||
|
||||
The following `crashReporter` methods are no longer available in the renderer
|
||||
@@ -251,6 +263,45 @@ you should plan to update your native modules to be context aware.
|
||||
|
||||
For more detailed information see [#18397](https://github.com/electron/electron/issues/18397).
|
||||
|
||||
### Deprecated: `BrowserWindow` extension APIs
|
||||
|
||||
The following extension APIs have been deprecated:
|
||||
* `BrowserWindow.addExtension(path)`
|
||||
* `BrowserWindow.addDevToolsExtension(path)`
|
||||
* `BrowserWindow.removeExtension(name)`
|
||||
* `BrowserWindow.removeDevToolsExtension(name)`
|
||||
* `BrowserWindow.getExtensions()`
|
||||
* `BrowserWindow.getDevToolsExtensions()`
|
||||
|
||||
Use the session APIs instead:
|
||||
* `ses.loadExtension(path)`
|
||||
* `ses.removeExtension(extension_id)`
|
||||
* `ses.getAllExtensions()`
|
||||
|
||||
```js
|
||||
// Deprecated in Electron 9
|
||||
BrowserWindow.addExtension(path)
|
||||
BrowserWindow.addDevToolsExtension(path)
|
||||
// Replace with
|
||||
session.defaultSession.loadExtension(path)
|
||||
```
|
||||
|
||||
```js
|
||||
// Deprecated in Electron 9
|
||||
BrowserWindow.removeExtension(name)
|
||||
BrowserWindow.removeDevToolsExtension(name)
|
||||
// Replace with
|
||||
session.defaultSession.removeExtension(extension_id)
|
||||
```
|
||||
|
||||
```js
|
||||
// Deprecated in Electron 9
|
||||
BrowserWindow.getExtensions()
|
||||
BrowserWindow.getDevToolsExtensions()
|
||||
// Replace with
|
||||
session.defaultSession.getAllExtensions()
|
||||
```
|
||||
|
||||
### Removed: `<webview>.getWebContents()`
|
||||
|
||||
This API, which was deprecated in Electron 8.0, is now removed.
|
||||
@@ -397,6 +448,52 @@ in Electron 8.x, and cease to exist in Electron 9.x. The layout zoom level
|
||||
limits are now fixed at a minimum of 0.25 and a maximum of 5.0, as defined
|
||||
[here](https://chromium.googlesource.com/chromium/src/+/938b37a6d2886bf8335fc7db792f1eb46c65b2ae/third_party/blink/common/page/page_zoom.cc#11).
|
||||
|
||||
### Deprecated events in `systemPreferences`
|
||||
|
||||
The following `systemPreferences` events have been deprecated:
|
||||
* `inverted-color-scheme-changed`
|
||||
* `high-contrast-color-scheme-changed`
|
||||
|
||||
Use the new `updated` event on the `nativeTheme` module instead.
|
||||
|
||||
```js
|
||||
// Deprecated
|
||||
systemPreferences.on('inverted-color-scheme-changed', () => { /* ... */ })
|
||||
systemPreferences.on('high-contrast-color-scheme-changed', () => { /* ... */ })
|
||||
|
||||
// Replace with
|
||||
nativeTheme.on('updated', () => { /* ... */ })
|
||||
```
|
||||
|
||||
### Deprecated: methods in `systemPreferences`
|
||||
|
||||
The following `systemPreferences` methods have been deprecated:
|
||||
* `systemPreferences.isDarkMode()`
|
||||
* `systemPreferences.isInvertedColorScheme()`
|
||||
* `systemPreferences.isHighContrastColorScheme()`
|
||||
|
||||
Use the following `nativeTheme` properties instead:
|
||||
* `nativeTheme.shouldUseDarkColors`
|
||||
* `nativeTheme.shouldUseInvertedColorScheme`
|
||||
* `nativeTheme.shouldUseHighContrastColors`
|
||||
|
||||
```js
|
||||
// Deprecated
|
||||
systemPreferences.isDarkMode()
|
||||
// Replace with
|
||||
nativeTheme.shouldUseDarkColors
|
||||
|
||||
// Deprecated
|
||||
systemPreferences.isInvertedColorScheme()
|
||||
// Replace with
|
||||
nativeTheme.shouldUseInvertedColorScheme
|
||||
|
||||
// Deprecated
|
||||
systemPreferences.isHighContrastColorScheme()
|
||||
// Replace with
|
||||
nativeTheme.shouldUseHighContrastColors
|
||||
```
|
||||
|
||||
## Planned Breaking API Changes (7.0)
|
||||
|
||||
### Deprecated: Atom.io Node Headers URL
|
||||
|
||||
18
docs/fiddles/features/drag-and-drop/index.html
Normal file
18
docs/fiddles/features/drag-and-drop/index.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
<a href="#" id="drag">Drag me</a>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
41
docs/fiddles/features/drag-and-drop/main.js
Normal file
41
docs/fiddles/features/drag-and-drop/main.js
Normal file
@@ -0,0 +1,41 @@
|
||||
const { app, BrowserWindow, ipcMain, nativeImage, NativeImage } = require('electron')
|
||||
const fs = require('fs');
|
||||
const http = require('http');
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
const iconName = 'iconForDragAndDrop.png';
|
||||
const icon = fs.createWriteStream(`${process.cwd()}/${iconName}`);
|
||||
http.get('http://img.icons8.com/ios/452/drag-and-drop.png', (response) => {
|
||||
response.pipe(icon);
|
||||
});
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
ipcMain.on('ondragstart', (event, filePath) => {
|
||||
event.sender.startDrag({
|
||||
file: filePath,
|
||||
icon: `${process.cwd()}/${iconName}`
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
9
docs/fiddles/features/drag-and-drop/renderer.js
Normal file
9
docs/fiddles/features/drag-and-drop/renderer.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { ipcRenderer } = require('electron')
|
||||
const fs = require('fs')
|
||||
|
||||
document.getElementById('drag').ondragstart = (event) => {
|
||||
const fileName = 'drag-and-drop.md'
|
||||
fs.writeFileSync(fileName, '# Test drag and drop');
|
||||
event.preventDefault()
|
||||
ipcRenderer.send('ondragstart', process.cwd() + `/${fileName}`)
|
||||
}
|
||||
16
docs/fiddles/features/keyboard-shortcuts/global/index.html
Normal file
16
docs/fiddles/features/keyboard-shortcuts/global/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
31
docs/fiddles/features/keyboard-shortcuts/global/main.js
Normal file
31
docs/fiddles/features/keyboard-shortcuts/global/main.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const { app, BrowserWindow, globalShortcut } = require('electron')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
globalShortcut.register('Alt+CommandOrControl+I', () => {
|
||||
console.log('Electron loves global shortcuts!')
|
||||
})
|
||||
}).then(createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
app.whenReady().then(() => {
|
||||
const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true } })
|
||||
|
||||
win.loadFile('index.html')
|
||||
win.webContents.on('before-input-event', (event, input) => {
|
||||
if (input.control && input.key.toLowerCase() === 'i') {
|
||||
console.log('Pressed Control+I')
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
})
|
||||
16
docs/fiddles/features/keyboard-shortcuts/local/index.html
Normal file
16
docs/fiddles/features/keyboard-shortcuts/local/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
39
docs/fiddles/features/keyboard-shortcuts/local/main.js
Normal file
39
docs/fiddles/features/keyboard-shortcuts/local/main.js
Normal file
@@ -0,0 +1,39 @@
|
||||
const { app, BrowserWindow, Menu, MenuItem } = require('electron')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
const menu = new Menu()
|
||||
menu.append(new MenuItem({
|
||||
label: 'Electron',
|
||||
submenu: [{
|
||||
role: 'help',
|
||||
accelerator: process.platform === 'darwin' ? 'Alt+Cmd+I' : 'Alt+Shift+I',
|
||||
click: () => { console.log('Electron rocks!') }
|
||||
}]
|
||||
}))
|
||||
|
||||
Menu.setApplicationMenu(menu)
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
19
docs/fiddles/features/macos-dark-mode/index.html
Normal file
19
docs/fiddles/features/macos-dark-mode/index.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
<link rel="stylesheet" type="text/css" href="./styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>Current theme source: <strong id="theme-source">System</strong></p>
|
||||
|
||||
<button id="toggle-dark-mode">Toggle Dark Mode</button>
|
||||
<button id="reset-to-system">Reset to System Theme</button>
|
||||
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
40
docs/fiddles/features/macos-dark-mode/main.js
Normal file
40
docs/fiddles/features/macos-dark-mode/main.js
Normal file
@@ -0,0 +1,40 @@
|
||||
const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
|
||||
ipcMain.handle('dark-mode:toggle', () => {
|
||||
if (nativeTheme.shouldUseDarkColors) {
|
||||
nativeTheme.themeSource = 'light'
|
||||
} else {
|
||||
nativeTheme.themeSource = 'dark'
|
||||
}
|
||||
return nativeTheme.shouldUseDarkColors
|
||||
})
|
||||
|
||||
ipcMain.handle('dark-mode:system', () => {
|
||||
nativeTheme.themeSouce = 'system'
|
||||
})
|
||||
}
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
11
docs/fiddles/features/macos-dark-mode/renderer.js
Normal file
11
docs/fiddles/features/macos-dark-mode/renderer.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
document.getElementById('toggle-dark-mode').addEventListener('click', async () => {
|
||||
const isDarkMode = await ipcRenderer.invoke('dark-mode:toggle')
|
||||
document.getElementById('theme-source').innerHTML = isDarkMode ? 'Dark' : 'Light'
|
||||
})
|
||||
|
||||
document.getElementById('reset-to-system').addEventListener('click', async () => {
|
||||
await ipcRenderer.invoke('dark-mode:system')
|
||||
document.getElementById('theme-source').innerHTML = 'System'
|
||||
})
|
||||
7
docs/fiddles/features/macos-dark-mode/styles.css
Normal file
7
docs/fiddles/features/macos-dark-mode/styles.css
Normal file
@@ -0,0 +1,7 @@
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body { background: #333; color: white; }
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
body { background: #ddd; color: black; }
|
||||
}
|
||||
16
docs/fiddles/features/macos-dock-menu/index.html
Normal file
16
docs/fiddles/features/macos-dock-menu/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
43
docs/fiddles/features/macos-dock-menu/main.js
Normal file
43
docs/fiddles/features/macos-dock-menu/main.js
Normal file
@@ -0,0 +1,43 @@
|
||||
const { app, BrowserWindow, Menu } = require('electron')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
const dockMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: 'New Window',
|
||||
click () { console.log('New Window') }
|
||||
}, {
|
||||
label: 'New Window with Settings',
|
||||
submenu: [
|
||||
{ label: 'Basic' },
|
||||
{ label: 'Pro' }
|
||||
]
|
||||
},
|
||||
{ label: 'New Command...' }
|
||||
])
|
||||
|
||||
app.whenReady().then(() => {
|
||||
app.dock.setMenu(dockMenu)
|
||||
}).then(createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
16
docs/fiddles/features/notifications/main/index.html
Normal file
16
docs/fiddles/features/notifications/main/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
35
docs/fiddles/features/notifications/main/main.js
Normal file
35
docs/fiddles/features/notifications/main/main.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const { app, BrowserWindow, Notification } = require('electron')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
function showNotification () {
|
||||
const notification = {
|
||||
title: 'Basic Notification',
|
||||
body: 'Notification from the Main process'
|
||||
}
|
||||
new Notification(notification).show()
|
||||
}
|
||||
|
||||
app.whenReady().then(createWindow).then(showNotification)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
17
docs/fiddles/features/notifications/renderer/index.html
Normal file
17
docs/fiddles/features/notifications/renderer/index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
27
docs/fiddles/features/notifications/renderer/main.js
Normal file
27
docs/fiddles/features/notifications/renderer/main.js
Normal file
@@ -0,0 +1,27 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
7
docs/fiddles/features/notifications/renderer/renderer.js
Normal file
7
docs/fiddles/features/notifications/renderer/renderer.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const myNotification = new Notification('Title', {
|
||||
body: 'Notification from the Renderer process'
|
||||
})
|
||||
|
||||
myNotification.onclick = () => {
|
||||
console.log('Notification clicked')
|
||||
}
|
||||
15
docs/fiddles/features/offscreen-rendering/index.html
Normal file
15
docs/fiddles/features/offscreen-rendering/index.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
28
docs/fiddles/features/offscreen-rendering/main.js
Normal file
28
docs/fiddles/features/offscreen-rendering/main.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const fs = require('fs')
|
||||
|
||||
app.disableHardwareAcceleration()
|
||||
|
||||
let win
|
||||
|
||||
app.whenReady().then(() => {
|
||||
win = new BrowserWindow({ webPreferences: { offscreen: true } })
|
||||
win.loadURL('https://github.com')
|
||||
win.webContents.on('paint', (event, dirty, image) => {
|
||||
fs.writeFileSync('ex.png', image.toPNG())
|
||||
})
|
||||
win.webContents.setFrameRate(60)
|
||||
console.log(`The screenshot has been successfully saved to ${process.cwd()}/ex.png`)
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
17
docs/fiddles/features/online-detection/main/index.html
Normal file
17
docs/fiddles/features/online-detection/main/index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
24
docs/fiddles/features/online-detection/main/main.js
Normal file
24
docs/fiddles/features/online-detection/main/main.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const { app, BrowserWindow, ipcMain } = require('electron')
|
||||
|
||||
let onlineStatusWindow
|
||||
|
||||
app.whenReady().then(() => {
|
||||
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false, webPreferences: { nodeIntegration: true } })
|
||||
onlineStatusWindow.loadURL(`file://${__dirname}/index.html`)
|
||||
})
|
||||
|
||||
ipcMain.on('online-status-changed', (event, status) => {
|
||||
console.log(status)
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
7
docs/fiddles/features/online-detection/main/renderer.js
Normal file
7
docs/fiddles/features/online-detection/main/renderer.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const { ipcRenderer } = require('electron')
|
||||
const updateOnlineStatus = () => { ipcRenderer.send('online-status-changed', navigator.onLine ? 'online' : 'offline') }
|
||||
|
||||
window.addEventListener('online', updateOnlineStatus)
|
||||
window.addEventListener('offline', updateOnlineStatus)
|
||||
|
||||
updateOnlineStatus()
|
||||
17
docs/fiddles/features/online-detection/renderer/index.html
Normal file
17
docs/fiddles/features/online-detection/renderer/index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
20
docs/fiddles/features/online-detection/renderer/main.js
Normal file
20
docs/fiddles/features/online-detection/renderer/main.js
Normal file
@@ -0,0 +1,20 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
let onlineStatusWindow
|
||||
|
||||
app.whenReady().then(() => {
|
||||
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false })
|
||||
onlineStatusWindow.loadURL(`file://${__dirname}/index.html`)
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,6 @@
|
||||
const alertOnlineStatus = () => { window.alert(navigator.onLine ? 'online' : 'offline') }
|
||||
|
||||
window.addEventListener('online', alertOnlineStatus)
|
||||
window.addEventListener('offline', alertOnlineStatus)
|
||||
|
||||
alertOnlineStatus()
|
||||
16
docs/fiddles/features/progress-bar/index.html
Normal file
16
docs/fiddles/features/progress-bar/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
30
docs/fiddles/features/progress-bar/main.js
Normal file
30
docs/fiddles/features/progress-bar/main.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
win.setProgressBar(0.5)
|
||||
}
|
||||
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
16
docs/fiddles/features/recent-documents/index.html
Normal file
16
docs/fiddles/features/recent-documents/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
34
docs/fiddles/features/recent-documents/main.js
Normal file
34
docs/fiddles/features/recent-documents/main.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
const fileName = 'recently-used.md'
|
||||
fs.writeFile(fileName, 'Lorem Ipsum', () => {
|
||||
app.addRecentDocument(path.join(process.cwd(), `${fileName}`))
|
||||
})
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
app.clearRecentDocuments()
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
16
docs/fiddles/features/represented-file/index.html
Normal file
16
docs/fiddles/features/represented-file/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
33
docs/fiddles/features/represented-file/main.js
Normal file
33
docs/fiddles/features/represented-file/main.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const os = require('os');
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
const win = new BrowserWindow()
|
||||
|
||||
win.setRepresentedFilename(os.homedir())
|
||||
win.setDocumentEdited(true)
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
16
docs/fiddles/quick-start/index.html
Normal file
16
docs/fiddles/quick-start/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
<p>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
27
docs/fiddles/quick-start/main.js
Normal file
27
docs/fiddles/quick-start/main.js
Normal file
@@ -0,0 +1,27 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
@@ -818,7 +818,7 @@ which potential security issues are not as widely known.
|
||||
[browser-view]: ../api/browser-view.md
|
||||
[webview-tag]: ../api/webview-tag.md
|
||||
[web-contents]: ../api/web-contents.md
|
||||
[window-open-handler]: ../api/web-contents.md#contentssetwindowopenhandler-handler
|
||||
[window-open-handler]: ../api/web-contents.md#contentssetwindowopenhandlerhandler
|
||||
[will-navigate]: ../api/web-contents.md#event-will-navigate
|
||||
[open-external]: ../api/shell.md#shellopenexternalurl-options
|
||||
[sandbox]: ../api/sandbox-option.md
|
||||
|
||||
@@ -91,8 +91,10 @@ template("electron_extra_paks") {
|
||||
}
|
||||
|
||||
# New paks should be added here by default.
|
||||
sources +=
|
||||
[ "$root_gen_dir/content/browser/devtools/devtools_resources.pak" ]
|
||||
sources += [
|
||||
"$root_gen_dir/content/browser/devtools/devtools_resources.pak",
|
||||
"$root_gen_dir/ui/resources/webui_generated_resources.pak",
|
||||
]
|
||||
deps += [ "//content/browser/devtools:devtools_resources" ]
|
||||
if (enable_print_preview) {
|
||||
sources += [ "$root_gen_dir/chrome/print_preview_resources.pak" ]
|
||||
|
||||
@@ -615,9 +615,10 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
if (options.withFileTypes) {
|
||||
const dirents = [];
|
||||
for (const file of files) {
|
||||
const stats = archive.stat(file);
|
||||
const childPath = path.join(filePath, file);
|
||||
const stats = archive.stat(childPath);
|
||||
if (!stats) {
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath: file });
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath: childPath });
|
||||
nextTick(callback!, [error]);
|
||||
return;
|
||||
}
|
||||
@@ -657,9 +658,10 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
if (options && (options as any).withFileTypes) {
|
||||
const dirents = [];
|
||||
for (const file of files) {
|
||||
const stats = archive.stat(file);
|
||||
const childPath = path.join(filePath, file);
|
||||
const stats = archive.stat(childPath);
|
||||
if (!stats) {
|
||||
throw createError(AsarError.NOT_FOUND, { asarPath, filePath: file });
|
||||
throw createError(AsarError.NOT_FOUND, { asarPath, filePath: childPath });
|
||||
}
|
||||
if (stats.isFile) {
|
||||
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_FILE));
|
||||
@@ -689,7 +691,8 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
if (info.size === 0) return ['', false];
|
||||
if (info.unpacked) {
|
||||
const realPath = archive.copyFileOut(filePath);
|
||||
return fs.readFileSync(realPath, { encoding: 'utf8' });
|
||||
const str = fs.readFileSync(realPath, { encoding: 'utf8' });
|
||||
return [str, str.length > 0];
|
||||
}
|
||||
|
||||
logASARAccess(asarPath, filePath, info.offset);
|
||||
|
||||
@@ -51,10 +51,6 @@ class CrashReporter {
|
||||
return binding.getUploadedReports();
|
||||
}
|
||||
|
||||
getCrashesDirectory () {
|
||||
return app.getPath('crashDumps');
|
||||
}
|
||||
|
||||
getUploadToServer () {
|
||||
if (process.type === 'browser') {
|
||||
return binding.getUploadToServer();
|
||||
|
||||
@@ -17,8 +17,12 @@ Object.setPrototypeOf(protocol, new Proxy({}, {
|
||||
|
||||
ownKeys () {
|
||||
if (!app.isReady()) return [];
|
||||
return Reflect.ownKeys(session.defaultSession!.protocol);
|
||||
},
|
||||
|
||||
return Object.getOwnPropertyNames(Object.getPrototypeOf(session.defaultSession!.protocol));
|
||||
has: (target, property: string) => {
|
||||
if (!app.isReady()) return false;
|
||||
return Reflect.has(session.defaultSession!.protocol, property);
|
||||
},
|
||||
|
||||
getOwnPropertyDescriptor () {
|
||||
|
||||
@@ -1,20 +1,47 @@
|
||||
import { EventEmitter } from 'events';
|
||||
const { createScreen } = process._linkedBinding('electron_common_screen');
|
||||
|
||||
let _screen: Electron.Screen;
|
||||
|
||||
const createScreenIfNeeded = () => {
|
||||
if (_screen === undefined) {
|
||||
_screen = createScreen();
|
||||
}
|
||||
};
|
||||
|
||||
// We can't call createScreen until after app.on('ready'), but this module
|
||||
// exposes an instance created by createScreen. In order to avoid
|
||||
// side-effecting and calling createScreen upon import of this module, instead
|
||||
// we export a proxy which lazily calls createScreen on first access.
|
||||
export default new Proxy({}, {
|
||||
get: (target, prop: keyof Electron.Screen) => {
|
||||
if (_screen === undefined) {
|
||||
_screen = createScreen();
|
||||
get: (target, property: keyof Electron.Screen) => {
|
||||
createScreenIfNeeded();
|
||||
const value = _screen[property];
|
||||
if (typeof value === 'function') {
|
||||
return value.bind(_screen);
|
||||
}
|
||||
const v = _screen[prop];
|
||||
if (typeof v === 'function') {
|
||||
return v.bind(_screen);
|
||||
}
|
||||
return v;
|
||||
return value;
|
||||
},
|
||||
set: (target, property: string, value: unknown) => {
|
||||
createScreenIfNeeded();
|
||||
return Reflect.set(_screen, property, value);
|
||||
},
|
||||
ownKeys: () => {
|
||||
createScreenIfNeeded();
|
||||
return Reflect.ownKeys(_screen);
|
||||
},
|
||||
has: (target, property: string) => {
|
||||
createScreenIfNeeded();
|
||||
return property in _screen;
|
||||
},
|
||||
getOwnPropertyDescriptor: (target, property: string) => {
|
||||
createScreenIfNeeded();
|
||||
return Reflect.getOwnPropertyDescriptor(_screen, property);
|
||||
},
|
||||
getPrototypeOf: () => {
|
||||
// This is necessary as a result of weirdness with EventEmitterMixin
|
||||
// and FunctionTemplate - we need to explicitly ensure it's returned
|
||||
// in the prototype.
|
||||
return EventEmitter.prototype;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ if ('getAppLevelAppearance' in systemPreferences) {
|
||||
}
|
||||
|
||||
if ('getEffectiveAppearance' in systemPreferences) {
|
||||
const nativeEAGetter = systemPreferences.getAppLevelAppearance;
|
||||
const nativeEAGetter = systemPreferences.getEffectiveAppearance;
|
||||
Object.defineProperty(systemPreferences, 'effectiveAppearance', {
|
||||
get: () => nativeEAGetter.call(systemPreferences)
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { app, ipcMain, session, deprecate, BrowserWindowConstructorOptions } from 'electron/main';
|
||||
import type { MenuItem, MenuItemConstructorOptions, LoadURLOptions } from 'electron/main';
|
||||
import { app, ipcMain, session, deprecate, webFrameMain } from 'electron/main';
|
||||
import type { BrowserWindowConstructorOptions, MenuItem, MenuItemConstructorOptions, LoadURLOptions } from 'electron/main';
|
||||
|
||||
import * as url from 'url';
|
||||
import * as path from 'path';
|
||||
@@ -164,29 +164,29 @@ WebContents.prototype._sendInternalToAll = function (channel, ...args) {
|
||||
|
||||
return this._send(internal, sendToAll, channel, args);
|
||||
};
|
||||
WebContents.prototype.sendToFrame = function (frameId, channel, ...args) {
|
||||
WebContents.prototype.sendToFrame = function (frame, channel, ...args) {
|
||||
if (typeof channel !== 'string') {
|
||||
throw new Error('Missing required channel argument');
|
||||
} else if (typeof frameId !== 'number') {
|
||||
throw new Error('Missing required frameId argument');
|
||||
} else if (!(typeof frame === 'number' || Array.isArray(frame))) {
|
||||
throw new Error('Missing required frame argument (must be number or array)');
|
||||
}
|
||||
|
||||
const internal = false;
|
||||
const sendToAll = false;
|
||||
|
||||
return this._sendToFrame(internal, sendToAll, frameId, channel, args);
|
||||
return this._sendToFrame(internal, sendToAll, frame, channel, args);
|
||||
};
|
||||
WebContents.prototype._sendToFrameInternal = function (frameId, channel, ...args) {
|
||||
WebContents.prototype._sendToFrameInternal = function (frame, channel, ...args) {
|
||||
if (typeof channel !== 'string') {
|
||||
throw new Error('Missing required channel argument');
|
||||
} else if (typeof frameId !== 'number') {
|
||||
throw new Error('Missing required frameId argument');
|
||||
} else if (!(typeof frame === 'number' || Array.isArray(frame))) {
|
||||
throw new Error('Missing required frame argument (must be number or array)');
|
||||
}
|
||||
|
||||
const internal = true;
|
||||
const sendToAll = false;
|
||||
|
||||
return this._sendToFrame(internal, sendToAll, frameId, channel, args);
|
||||
return this._sendToFrame(internal, sendToAll, frame, channel, args);
|
||||
};
|
||||
|
||||
// Following methods are mapped to webFrame.
|
||||
@@ -478,8 +478,9 @@ WebContents.prototype._callWindowOpenHandler = function (event: any, url: string
|
||||
};
|
||||
|
||||
const addReplyToEvent = (event: any) => {
|
||||
const { processId, frameId } = event;
|
||||
event.reply = (...args: any[]) => {
|
||||
event.sender.sendToFrame(event.frameId, ...args);
|
||||
event.sender.sendToFrame([processId, frameId], ...args);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -493,6 +494,13 @@ const addReplyInternalToEvent = (event: any) => {
|
||||
});
|
||||
};
|
||||
|
||||
const addSenderFrameToEvent = (event: any) => {
|
||||
const { processId, frameId } = event;
|
||||
Object.defineProperty(event, 'senderFrame', {
|
||||
get: () => webFrameMain.fromId(processId, frameId)
|
||||
});
|
||||
};
|
||||
|
||||
const addReturnValueToEvent = (event: any) => {
|
||||
Object.defineProperty(event, 'returnValue', {
|
||||
set: (value) => event.sendReply(value),
|
||||
@@ -527,6 +535,13 @@ WebContents.prototype._init = function () {
|
||||
this.goToOffset = navigationController.goToOffset.bind(navigationController);
|
||||
this.getActiveIndex = navigationController.getActiveIndex.bind(navigationController);
|
||||
this.length = navigationController.length.bind(navigationController);
|
||||
// Read off the ID at construction time, so that it's accessible even after
|
||||
// the underlying C++ WebContents is destroyed.
|
||||
const id = this.id;
|
||||
Object.defineProperty(this, 'id', {
|
||||
value: id,
|
||||
writable: false
|
||||
});
|
||||
|
||||
this._windowOpenHandler = null;
|
||||
|
||||
@@ -536,6 +551,7 @@ WebContents.prototype._init = function () {
|
||||
|
||||
// Dispatch IPC messages to the ipc module.
|
||||
this.on('-ipc-message' as any, function (this: Electron.WebContents, event: any, internal: boolean, channel: string, args: any[]) {
|
||||
addSenderFrameToEvent(event);
|
||||
if (internal) {
|
||||
addReplyInternalToEvent(event);
|
||||
ipcMainInternal.emit(channel, event, ...args);
|
||||
@@ -547,6 +563,7 @@ WebContents.prototype._init = function () {
|
||||
});
|
||||
|
||||
this.on('-ipc-invoke' as any, function (event: any, internal: boolean, channel: string, args: any[]) {
|
||||
addSenderFrameToEvent(event);
|
||||
event._reply = (result: any) => event.sendReply({ result });
|
||||
event._throw = (error: Error) => {
|
||||
console.error(`Error occurred in handler for '${channel}':`, error);
|
||||
@@ -561,6 +578,7 @@ WebContents.prototype._init = function () {
|
||||
});
|
||||
|
||||
this.on('-ipc-message-sync' as any, function (this: Electron.WebContents, event: any, internal: boolean, channel: string, args: any[]) {
|
||||
addSenderFrameToEvent(event);
|
||||
addReturnValueToEvent(event);
|
||||
if (internal) {
|
||||
addReplyInternalToEvent(event);
|
||||
|
||||
@@ -48,6 +48,9 @@ export const getSourcesImpl = (event: Electron.IpcMainEvent | null, args: Electr
|
||||
}
|
||||
// Remove from currentlyRunning once we resolve or reject
|
||||
currentlyRunning = currentlyRunning.filter(running => running.options !== options);
|
||||
if (event) {
|
||||
event.sender.removeListener('destroyed', stopRunning);
|
||||
}
|
||||
};
|
||||
|
||||
capturer._onerror = (error: string) => {
|
||||
@@ -66,7 +69,7 @@ export const getSourcesImpl = (event: Electron.IpcMainEvent | null, args: Electr
|
||||
// reference to emit and the capturer itself so that it never dispatches
|
||||
// back to the renderer
|
||||
if (event) {
|
||||
event.sender.once('destroyed', () => stopRunning());
|
||||
event.sender.once('destroyed', stopRunning);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ const FUNCTION_PROPERTIES = [
|
||||
];
|
||||
|
||||
type RendererFunctionId = [string, number] // [contextId, funcId]
|
||||
type FinalizerInfo = { id: RendererFunctionId, webContents: electron.WebContents, frameId: number };
|
||||
type FinalizerInfo = { id: RendererFunctionId, webContents: electron.WebContents, frameId: [number, number] };
|
||||
type CallIntoRenderer = (...args: any[]) => void
|
||||
|
||||
// The remote functions in renderer processes.
|
||||
@@ -31,7 +31,7 @@ const finalizationRegistry = new FinalizationRegistry((fi: FinalizerInfo) => {
|
||||
const ref = rendererFunctionCache.get(mapKey);
|
||||
if (ref !== undefined && ref.deref() === undefined) {
|
||||
rendererFunctionCache.delete(mapKey);
|
||||
if (!fi.webContents.isDestroyed()) { fi.webContents.sendToFrame(fi.frameId, IPC_MESSAGES.RENDERER_RELEASE_CALLBACK, fi.id[0], fi.id[1]); }
|
||||
if (!fi.webContents.isDestroyed()) { fi.webContents._sendToFrameInternal(fi.frameId, IPC_MESSAGES.RENDERER_RELEASE_CALLBACK, fi.id[0], fi.id[1]); }
|
||||
}
|
||||
});
|
||||
|
||||
@@ -43,7 +43,7 @@ function getCachedRendererFunction (id: RendererFunctionId): CallIntoRenderer |
|
||||
if (deref !== undefined) return deref;
|
||||
}
|
||||
}
|
||||
function setCachedRendererFunction (id: RendererFunctionId, wc: electron.WebContents, frameId: number, value: CallIntoRenderer) {
|
||||
function setCachedRendererFunction (id: RendererFunctionId, wc: electron.WebContents, frameId: [number, number], value: CallIntoRenderer) {
|
||||
// eslint-disable-next-line no-undef
|
||||
const wr = new WeakRef<CallIntoRenderer>(value);
|
||||
const mapKey = id[0] + '~' + id[1];
|
||||
@@ -218,7 +218,7 @@ const fakeConstructor = (constructor: Function, name: string) =>
|
||||
});
|
||||
|
||||
// Convert array of meta data from renderer into array of real values.
|
||||
const unwrapArgs = function (sender: electron.WebContents, frameId: number, contextId: string, args: any[]) {
|
||||
const unwrapArgs = function (sender: electron.WebContents, frameId: [number, number], contextId: string, args: any[]) {
|
||||
const metaToValue = function (meta: MetaTypeFromRenderer): any {
|
||||
switch (meta.type) {
|
||||
case 'nativeimage':
|
||||
@@ -421,7 +421,7 @@ handleRemoteCommand(IPC_MESSAGES.BROWSER_GET_CURRENT_WEB_CONTENTS, function (eve
|
||||
});
|
||||
|
||||
handleRemoteCommand(IPC_MESSAGES.BROWSER_CONSTRUCTOR, function (event, contextId, id, args) {
|
||||
args = unwrapArgs(event.sender, event.frameId, contextId, args);
|
||||
args = unwrapArgs(event.sender, [event.processId, event.frameId], contextId, args);
|
||||
const constructor = objectsRegistry.get(id);
|
||||
|
||||
if (constructor == null) {
|
||||
@@ -432,7 +432,7 @@ handleRemoteCommand(IPC_MESSAGES.BROWSER_CONSTRUCTOR, function (event, contextId
|
||||
});
|
||||
|
||||
handleRemoteCommand(IPC_MESSAGES.BROWSER_FUNCTION_CALL, function (event, contextId, id, args) {
|
||||
args = unwrapArgs(event.sender, event.frameId, contextId, args);
|
||||
args = unwrapArgs(event.sender, [event.processId, event.frameId], contextId, args);
|
||||
const func = objectsRegistry.get(id);
|
||||
|
||||
if (func == null) {
|
||||
@@ -449,7 +449,7 @@ handleRemoteCommand(IPC_MESSAGES.BROWSER_FUNCTION_CALL, function (event, context
|
||||
});
|
||||
|
||||
handleRemoteCommand(IPC_MESSAGES.BROWSER_MEMBER_CONSTRUCTOR, function (event, contextId, id, method, args) {
|
||||
args = unwrapArgs(event.sender, event.frameId, contextId, args);
|
||||
args = unwrapArgs(event.sender, [event.processId, event.frameId], contextId, args);
|
||||
const object = objectsRegistry.get(id);
|
||||
|
||||
if (object == null) {
|
||||
@@ -460,7 +460,7 @@ handleRemoteCommand(IPC_MESSAGES.BROWSER_MEMBER_CONSTRUCTOR, function (event, co
|
||||
});
|
||||
|
||||
handleRemoteCommand(IPC_MESSAGES.BROWSER_MEMBER_CALL, function (event, contextId, id, method, args) {
|
||||
args = unwrapArgs(event.sender, event.frameId, contextId, args);
|
||||
args = unwrapArgs(event.sender, [event.processId, event.frameId], contextId, args);
|
||||
const object = objectsRegistry.get(id);
|
||||
|
||||
if (object == null) {
|
||||
@@ -477,7 +477,7 @@ handleRemoteCommand(IPC_MESSAGES.BROWSER_MEMBER_CALL, function (event, contextId
|
||||
});
|
||||
|
||||
handleRemoteCommand(IPC_MESSAGES.BROWSER_MEMBER_SET, function (event, contextId, id, name, args) {
|
||||
args = unwrapArgs(event.sender, event.frameId, contextId, args);
|
||||
args = unwrapArgs(event.sender, [event.processId, event.frameId], contextId, args);
|
||||
const obj = objectsRegistry.get(id);
|
||||
|
||||
if (obj == null) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { app } from 'electron/main';
|
||||
import type { WebContents } from 'electron/main';
|
||||
import { clipboard, crashReporter, nativeImage } from 'electron/common';
|
||||
import { clipboard, nativeImage } from 'electron/common';
|
||||
import * as fs from 'fs';
|
||||
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
|
||||
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
|
||||
@@ -114,26 +114,6 @@ ipcMainInternal.on(IPC_MESSAGES.BROWSER_PRELOAD_ERROR, function (event, preloadP
|
||||
event.sender.emit('preload-error', event, preloadPath, error);
|
||||
});
|
||||
|
||||
ipcMainUtils.handleSync(IPC_MESSAGES.CRASH_REPORTER_GET_LAST_CRASH_REPORT, () => {
|
||||
return crashReporter.getLastCrashReport();
|
||||
});
|
||||
|
||||
ipcMainUtils.handleSync(IPC_MESSAGES.CRASH_REPORTER_GET_UPLOADED_REPORTS, () => {
|
||||
return crashReporter.getUploadedReports();
|
||||
});
|
||||
|
||||
ipcMainUtils.handleSync(IPC_MESSAGES.CRASH_REPORTER_GET_UPLOAD_TO_SERVER, () => {
|
||||
return crashReporter.getUploadToServer();
|
||||
});
|
||||
|
||||
ipcMainUtils.handleSync(IPC_MESSAGES.CRASH_REPORTER_SET_UPLOAD_TO_SERVER, (event, uploadToServer: boolean) => {
|
||||
return crashReporter.setUploadToServer(uploadToServer);
|
||||
});
|
||||
|
||||
ipcMainUtils.handleSync(IPC_MESSAGES.CRASH_REPORTER_GET_CRASHES_DIRECTORY, () => {
|
||||
return crashReporter.getCrashesDirectory();
|
||||
});
|
||||
|
||||
ipcMainInternal.handle(IPC_MESSAGES.NATIVE_IMAGE_CREATE_THUMBNAIL_FROM_PATH, async (_, path: string, size: Electron.Size) => {
|
||||
return typeUtils.serialize(await nativeImage.createThumbnailFromPath(path, size));
|
||||
});
|
||||
|
||||
@@ -5,12 +5,6 @@ export const enum IPC_MESSAGES {
|
||||
BROWSER_SANDBOX_LOAD = 'BROWSER_SANDBOX_LOAD',
|
||||
BROWSER_WINDOW_CLOSE = 'BROWSER_WINDOW_CLOSE',
|
||||
|
||||
CRASH_REPORTER_GET_LAST_CRASH_REPORT = 'CRASH_REPORTER_GET_LAST_CRASH_REPORT',
|
||||
CRASH_REPORTER_GET_UPLOADED_REPORTS = 'CRASH_REPORTER_GET_UPLOADED_REPORTS',
|
||||
CRASH_REPORTER_GET_UPLOAD_TO_SERVER = 'CRASH_REPORTER_GET_UPLOAD_TO_SERVER',
|
||||
CRASH_REPORTER_SET_UPLOAD_TO_SERVER = 'CRASH_REPORTER_SET_UPLOAD_TO_SERVER',
|
||||
CRASH_REPORTER_GET_CRASHES_DIRECTORY = 'CRASH_REPORTER_GET_CRASHES_DIRECTORY',
|
||||
|
||||
GUEST_INSTANCE_VISIBILITY_CHANGE = 'GUEST_INSTANCE_VISIBILITY_CHANGE',
|
||||
|
||||
GUEST_VIEW_INTERNAL_DESTROY_GUEST = 'GUEST_VIEW_INTERNAL_DESTROY_GUEST',
|
||||
|
||||
@@ -1,42 +1,6 @@
|
||||
import { invokeSync } from '../ipc-renderer-internal-utils';
|
||||
import { deprecate } from 'electron';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
const binding = process._linkedBinding('electron_renderer_crash_reporter');
|
||||
|
||||
export default {
|
||||
start (options: Electron.CrashReporterStartOptions) {
|
||||
deprecate.log('crashReporter.start is deprecated in the renderer process. Call it from the main process instead.');
|
||||
for (const [k, v] of Object.entries(options.extra || {})) {
|
||||
binding.addExtraParameter(k, String(v));
|
||||
}
|
||||
},
|
||||
|
||||
getLastCrashReport (): Electron.CrashReport | null {
|
||||
deprecate.log('crashReporter.getLastCrashReport is deprecated in the renderer process. Call it from the main process instead.');
|
||||
return invokeSync(IPC_MESSAGES.CRASH_REPORTER_GET_LAST_CRASH_REPORT);
|
||||
},
|
||||
|
||||
getUploadedReports () {
|
||||
deprecate.log('crashReporter.getUploadedReports is deprecated in the renderer process. Call it from the main process instead.');
|
||||
return invokeSync(IPC_MESSAGES.CRASH_REPORTER_GET_UPLOADED_REPORTS);
|
||||
},
|
||||
|
||||
getUploadToServer () {
|
||||
deprecate.log('crashReporter.getUploadToServer is deprecated in the renderer process. Call it from the main process instead.');
|
||||
return invokeSync(IPC_MESSAGES.CRASH_REPORTER_GET_UPLOAD_TO_SERVER);
|
||||
},
|
||||
|
||||
setUploadToServer (uploadToServer: boolean) {
|
||||
deprecate.log('crashReporter.setUploadToServer is deprecated in the renderer process. Call it from the main process instead.');
|
||||
return invokeSync(IPC_MESSAGES.CRASH_REPORTER_SET_UPLOAD_TO_SERVER, uploadToServer);
|
||||
},
|
||||
|
||||
getCrashesDirectory () {
|
||||
deprecate.log('crashReporter.getCrashesDirectory is deprecated in the renderer process. Call it from the main process instead.');
|
||||
return invokeSync(IPC_MESSAGES.CRASH_REPORTER_GET_CRASHES_DIRECTORY);
|
||||
},
|
||||
|
||||
addExtraParameter (key: string, value: string) {
|
||||
binding.addExtraParameter(key, value);
|
||||
},
|
||||
|
||||
@@ -180,7 +180,7 @@ const warnAboutInsecureCSP = function () {
|
||||
|
||||
console.warn('%cElectron Security Warning (Insecure Content-Security-Policy)',
|
||||
'font-weight: bold;', warning);
|
||||
});
|
||||
}).catch(() => {});
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "12.0.0-nightly.20201118",
|
||||
"version": "12.0.0-beta.14",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -15,6 +15,7 @@ webview_cross_drag.patch
|
||||
gin_enable_disable_v8_platform.patch
|
||||
blink-worker-enable-csp-in-file-scheme.patch
|
||||
disable-redraw-lock.patch
|
||||
enable_reset_aspect_ratio.patch
|
||||
v8_context_snapshot_generator.patch
|
||||
boringssl_build_gn.patch
|
||||
pepper_plugin_support.patch
|
||||
@@ -103,3 +104,5 @@ fix_use_electron_generated_resources.patch
|
||||
chore_expose_v8_initialization_isolate_callbacks.patch
|
||||
export_gin_v8platform_pageallocator_for_usage_outside_of_the_gin.patch
|
||||
use_public_apis_to_determine_if_a_font_is_a_system_font_in_mas_build.patch
|
||||
cherry-pick-47e21abe349a.patch
|
||||
fix_setparentacessibile_crash_win.patch
|
||||
|
||||
727
patches/chromium/cherry-pick-47e21abe349a.patch
Normal file
727
patches/chromium/cherry-pick-47e21abe349a.patch
Normal file
@@ -0,0 +1,727 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Robinson <mrobinson@igalia.com>
|
||||
Date: Thu, 19 Nov 2020 21:28:45 +0000
|
||||
Subject: Improve AXTextStateChangeType in
|
||||
NSAccessibilitySelectedTextChangedNotification
|
||||
|
||||
When setting the AXTextStateChangeType key in the user info data
|
||||
structure for the notification, use AXTextStateChangeTypeSelectionMove
|
||||
when we detect a focus change. This causes VoiceOver to properly
|
||||
announce the label and type of form entries when their contents are
|
||||
selected due to focus changes.
|
||||
|
||||
type are now announced.
|
||||
|
||||
Bug: 1127421
|
||||
Change-Id: I42d66ad60fbcba7c8c34396fdbc3f6e0c739d1a2
|
||||
AX-Relnotes: When focus changes moves to form inputs, the input label and
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2512913
|
||||
Commit-Queue: Martin Robinson <mrobinson@igalia.com>
|
||||
Reviewed-by: Nektarios Paisios <nektar@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/master@{#829380}
|
||||
|
||||
diff --git a/content/browser/accessibility/accessibility_event_recorder_mac.mm b/content/browser/accessibility/accessibility_event_recorder_mac.mm
|
||||
index 6efa579decbfef81ddd38b27696133f7f68673ee..cdf4f8f87cf1554044e698f8b85c0f8a28a741e8 100644
|
||||
--- a/content/browser/accessibility/accessibility_event_recorder_mac.mm
|
||||
+++ b/content/browser/accessibility/accessibility_event_recorder_mac.mm
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
+#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "base/logging.h"
|
||||
@@ -15,6 +16,7 @@
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "content/browser/accessibility/accessibility_tools_utils_mac.h"
|
||||
#include "content/browser/accessibility/browser_accessibility_manager.h"
|
||||
+#include "ui/accessibility/platform/ax_private_webkit_constants_mac.h"
|
||||
|
||||
namespace content {
|
||||
|
||||
@@ -28,7 +30,11 @@
|
||||
~AccessibilityEventRecorderMac() override;
|
||||
|
||||
// Callback executed every time we receive an event notification.
|
||||
- void EventReceived(AXUIElementRef element, CFStringRef notification);
|
||||
+ void EventReceived(AXUIElementRef element,
|
||||
+ CFStringRef notification,
|
||||
+ CFDictionaryRef user_info);
|
||||
+ static std::string SerializeTextSelectionChangedProperties(
|
||||
+ CFDictionaryRef user_info);
|
||||
|
||||
private:
|
||||
// Add one notification to the list of notifications monitored by our
|
||||
@@ -54,10 +60,11 @@
|
||||
static void EventReceivedThunk(AXObserverRef observer_ref,
|
||||
AXUIElementRef element,
|
||||
CFStringRef notification,
|
||||
+ CFDictionaryRef user_info,
|
||||
void* refcon) {
|
||||
AccessibilityEventRecorderMac* this_ptr =
|
||||
static_cast<AccessibilityEventRecorderMac*>(refcon);
|
||||
- this_ptr->EventReceived(element, notification);
|
||||
+ this_ptr->EventReceived(element, notification, user_info);
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -95,8 +102,9 @@ static void EventReceivedThunk(AXObserverRef observer_ref,
|
||||
base::ProcessId pid,
|
||||
AXUIElementRef node)
|
||||
: AccessibilityEventRecorder(manager), observer_run_loop_source_(NULL) {
|
||||
- if (kAXErrorSuccess != AXObserverCreate(pid, EventReceivedThunk,
|
||||
- observer_ref_.InitializeInto())) {
|
||||
+ if (kAXErrorSuccess !=
|
||||
+ AXObserverCreateWithInfoCallback(pid, EventReceivedThunk,
|
||||
+ observer_ref_.InitializeInto())) {
|
||||
LOG(FATAL) << "Failed to create AXObserverRef";
|
||||
}
|
||||
|
||||
@@ -157,7 +165,8 @@ static void EventReceivedThunk(AXObserverRef observer_ref,
|
||||
}
|
||||
|
||||
void AccessibilityEventRecorderMac::EventReceived(AXUIElementRef element,
|
||||
- CFStringRef notification) {
|
||||
+ CFStringRef notification,
|
||||
+ CFDictionaryRef user_info) {
|
||||
std::string notification_str = base::SysCFStringRefToUTF8(notification);
|
||||
std::string role = GetAXAttributeValue(element, NSAccessibilityRoleAttribute);
|
||||
if (role.empty())
|
||||
@@ -180,7 +189,49 @@ static void EventReceivedThunk(AXObserverRef observer_ref,
|
||||
if (!value.empty())
|
||||
log += base::StringPrintf(" AXValue=\"%s\"", value.c_str());
|
||||
|
||||
+ if (notification_str ==
|
||||
+ base::SysNSStringToUTF8(NSAccessibilitySelectedTextChangedNotification))
|
||||
+ log += " " + SerializeTextSelectionChangedProperties(user_info);
|
||||
+
|
||||
OnEvent(log);
|
||||
}
|
||||
|
||||
+std::string
|
||||
+AccessibilityEventRecorderMac::SerializeTextSelectionChangedProperties(
|
||||
+ CFDictionaryRef user_info) {
|
||||
+ std::vector<std::string> serialized_info;
|
||||
+ CFDictionaryApplyFunction(
|
||||
+ user_info,
|
||||
+ [](const void* raw_key, const void* raw_value, void* context) {
|
||||
+ auto* key = static_cast<NSString*>(raw_key);
|
||||
+ auto* value = static_cast<NSObject*>(raw_value);
|
||||
+ auto* serialized_info = static_cast<std::vector<std::string>*>(context);
|
||||
+ std::string value_string;
|
||||
+ if ([key isEqual:ui::NSAccessibilityTextStateChangeTypeKey]) {
|
||||
+ value_string = ToString(static_cast<ui::AXTextStateChangeType>(
|
||||
+ [static_cast<NSNumber*>(value) intValue]));
|
||||
+ } else if ([key isEqual:ui::NSAccessibilityTextSelectionDirection]) {
|
||||
+ value_string = ToString(static_cast<ui::AXTextSelectionDirection>(
|
||||
+ [static_cast<NSNumber*>(value) intValue]));
|
||||
+ } else if ([key isEqual:ui::NSAccessibilityTextSelectionGranularity]) {
|
||||
+ value_string = ToString(static_cast<ui::AXTextSelectionGranularity>(
|
||||
+ [static_cast<NSNumber*>(value) intValue]));
|
||||
+ } else if ([key isEqual:ui::NSAccessibilityTextEditType]) {
|
||||
+ value_string = ToString(static_cast<ui::AXTextEditType>(
|
||||
+ [static_cast<NSNumber*>(value) intValue]));
|
||||
+ } else {
|
||||
+ return;
|
||||
+ }
|
||||
+ serialized_info->push_back(base::SysNSStringToUTF8(key) + "=" +
|
||||
+ value_string);
|
||||
+ },
|
||||
+ &serialized_info);
|
||||
+
|
||||
+ // Always sort the info so that we don't depend on CFDictionary for
|
||||
+ // consistent output ordering.
|
||||
+ std::sort(serialized_info.begin(), serialized_info.end());
|
||||
+
|
||||
+ return base::JoinString(serialized_info, " ");
|
||||
+}
|
||||
+
|
||||
} // namespace content
|
||||
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.h b/content/browser/accessibility/browser_accessibility_manager_mac.h
|
||||
index b4043f56341e72bcf75ef71c56cb8cf9fc442579..925bfe1ea191ab846805fdbff1b0314e779b1c9e 100644
|
||||
--- a/content/browser/accessibility/browser_accessibility_manager_mac.h
|
||||
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.h
|
||||
@@ -54,7 +54,8 @@ class CONTENT_EXPORT BrowserAccessibilityManagerMac
|
||||
const std::vector<Change>& changes) override;
|
||||
|
||||
// Returns an autoreleased object.
|
||||
- NSDictionary* GetUserInfoForSelectedTextChangedNotification();
|
||||
+ NSDictionary* GetUserInfoForSelectedTextChangedNotification(
|
||||
+ bool focus_changed);
|
||||
|
||||
// Returns an autoreleased object.
|
||||
NSDictionary* GetUserInfoForValueChangedNotification(
|
||||
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm
|
||||
index 122e517ddcb3944847fc289eb45c87d5fb156afc..5a2b73f664646efc0bc8e506e93b179b8e96635a 100644
|
||||
--- a/content/browser/accessibility/browser_accessibility_manager_mac.mm
|
||||
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
|
||||
@@ -19,91 +19,13 @@
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
|
||||
#include "ui/accessibility/ax_role_properties.h"
|
||||
+#include "ui/accessibility/platform/ax_private_webkit_constants_mac.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Use same value as in Safari's WebKit.
|
||||
const int kLiveRegionChangeIntervalMS = 20;
|
||||
|
||||
-// Declare undocumented accessibility constants and enums only present in
|
||||
-// WebKit.
|
||||
-
|
||||
-enum AXTextStateChangeType {
|
||||
- AXTextStateChangeTypeUnknown,
|
||||
- AXTextStateChangeTypeEdit,
|
||||
- AXTextStateChangeTypeSelectionMove,
|
||||
- AXTextStateChangeTypeSelectionExtend
|
||||
-};
|
||||
-
|
||||
-enum AXTextSelectionDirection {
|
||||
- AXTextSelectionDirectionUnknown,
|
||||
- AXTextSelectionDirectionBeginning,
|
||||
- AXTextSelectionDirectionEnd,
|
||||
- AXTextSelectionDirectionPrevious,
|
||||
- AXTextSelectionDirectionNext,
|
||||
- AXTextSelectionDirectionDiscontiguous
|
||||
-};
|
||||
-
|
||||
-enum AXTextSelectionGranularity {
|
||||
- AXTextSelectionGranularityUnknown,
|
||||
- AXTextSelectionGranularityCharacter,
|
||||
- AXTextSelectionGranularityWord,
|
||||
- AXTextSelectionGranularityLine,
|
||||
- AXTextSelectionGranularitySentence,
|
||||
- AXTextSelectionGranularityParagraph,
|
||||
- AXTextSelectionGranularityPage,
|
||||
- AXTextSelectionGranularityDocument,
|
||||
- AXTextSelectionGranularityAll
|
||||
-};
|
||||
-
|
||||
-enum AXTextEditType {
|
||||
- AXTextEditTypeUnknown,
|
||||
- AXTextEditTypeDelete,
|
||||
- AXTextEditTypeInsert,
|
||||
- AXTextEditTypeTyping,
|
||||
- AXTextEditTypeDictation,
|
||||
- AXTextEditTypeCut,
|
||||
- AXTextEditTypePaste,
|
||||
- AXTextEditTypeAttributesChange
|
||||
-};
|
||||
-
|
||||
-// Native mac notifications fired.
|
||||
-NSString* const NSAccessibilityAutocorrectionOccurredNotification =
|
||||
- @"AXAutocorrectionOccurred";
|
||||
-NSString* const NSAccessibilityLoadCompleteNotification = @"AXLoadComplete";
|
||||
-NSString* const NSAccessibilityInvalidStatusChangedNotification =
|
||||
- @"AXInvalidStatusChanged";
|
||||
-NSString* const NSAccessibilityLiveRegionCreatedNotification =
|
||||
- @"AXLiveRegionCreated";
|
||||
-NSString* const NSAccessibilityLiveRegionChangedNotification =
|
||||
- @"AXLiveRegionChanged";
|
||||
-NSString* const NSAccessibilityExpandedChanged = @"AXExpandedChanged";
|
||||
-NSString* const NSAccessibilityMenuItemSelectedNotification =
|
||||
- @"AXMenuItemSelected";
|
||||
-
|
||||
-// The following native mac notifications are not fired:
|
||||
-// AXLayoutComplete: Voiceover does not use this, it is considered too spammy.
|
||||
-
|
||||
-// Attributes used for NSAccessibilitySelectedTextChangedNotification and
|
||||
-// NSAccessibilityValueChangedNotification.
|
||||
-NSString* const NSAccessibilityTextStateChangeTypeKey =
|
||||
- @"AXTextStateChangeType";
|
||||
-NSString* const NSAccessibilityTextStateSyncKey = @"AXTextStateSync";
|
||||
-NSString* const NSAccessibilityTextSelectionDirection =
|
||||
- @"AXTextSelectionDirection";
|
||||
-NSString* const NSAccessibilityTextSelectionGranularity =
|
||||
- @"AXTextSelectionGranularity";
|
||||
-NSString* const NSAccessibilityTextSelectionChangedFocus =
|
||||
- @"AXTextSelectionChangedFocus";
|
||||
-NSString* const NSAccessibilityTextChangeElement = @"AXTextChangeElement";
|
||||
-NSString* const NSAccessibilityTextEditType = @"AXTextEditType";
|
||||
-NSString* const NSAccessibilityTextChangeValue = @"AXTextChangeValue";
|
||||
-NSString* const NSAccessibilityChangeValueStartMarker =
|
||||
- @"AXTextChangeValueStartMarker";
|
||||
-NSString* const NSAccessibilityTextChangeValueLength =
|
||||
- @"AXTextChangeValueLength";
|
||||
-NSString* const NSAccessibilityTextChangeValues = @"AXTextChangeValues";
|
||||
-
|
||||
} // namespace
|
||||
|
||||
namespace content {
|
||||
@@ -164,7 +86,7 @@
|
||||
NSString* mac_notification = nullptr;
|
||||
switch (event_type) {
|
||||
case ax::mojom::Event::kAutocorrectionOccured:
|
||||
- mac_notification = NSAccessibilityAutocorrectionOccurredNotification;
|
||||
+ mac_notification = ui::NSAccessibilityAutocorrectionOccurredNotification;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@@ -203,6 +125,8 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
auto native_node = ToBrowserAccessibilityCocoa(node);
|
||||
DCHECK(native_node);
|
||||
|
||||
+ bool focus_changed = GetFocus() != GetLastFocusedNode();
|
||||
+
|
||||
// Refer to |AXObjectCache::postPlatformNotification| in WebKit source code.
|
||||
NSString* mac_notification = nullptr;
|
||||
switch (event_type) {
|
||||
@@ -223,7 +147,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
break;
|
||||
case ui::AXEventGenerator::Event::ALERT:
|
||||
NSAccessibilityPostNotification(
|
||||
- native_node, NSAccessibilityLiveRegionCreatedNotification);
|
||||
+ native_node, ui::NSAccessibilityLiveRegionCreatedNotification);
|
||||
// Voiceover requires a live region changed notification to actually
|
||||
// announce the live region.
|
||||
FireGeneratedEvent(ui::AXEventGenerator::Event::LIVE_REGION_CHANGED,
|
||||
@@ -242,7 +166,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
node->GetRole() == ax::mojom::Role::kTreeItem) {
|
||||
mac_notification = NSAccessibilityRowCollapsedNotification;
|
||||
} else {
|
||||
- mac_notification = NSAccessibilityExpandedChanged;
|
||||
+ mac_notification = ui::NSAccessibilityExpandedChanged;
|
||||
}
|
||||
break;
|
||||
case ui::AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED: {
|
||||
@@ -259,7 +183,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
// API has been present on versions of OS X since 10.7 but doesn't
|
||||
// appear to be needed by Voiceover before version 10.11.
|
||||
NSDictionary* user_info =
|
||||
- GetUserInfoForSelectedTextChangedNotification();
|
||||
+ GetUserInfoForSelectedTextChangedNotification(focus_changed);
|
||||
|
||||
BrowserAccessibilityManager* root_manager = GetRootManager();
|
||||
if (!root_manager)
|
||||
@@ -284,11 +208,11 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
node->GetRole() == ax::mojom::Role::kTreeItem) {
|
||||
mac_notification = NSAccessibilityRowExpandedNotification;
|
||||
} else {
|
||||
- mac_notification = NSAccessibilityExpandedChanged;
|
||||
+ mac_notification = ui::NSAccessibilityExpandedChanged;
|
||||
}
|
||||
break;
|
||||
case ui::AXEventGenerator::Event::INVALID_STATUS_CHANGED:
|
||||
- mac_notification = NSAccessibilityInvalidStatusChangedNotification;
|
||||
+ mac_notification = ui::NSAccessibilityInvalidStatusChangedNotification;
|
||||
break;
|
||||
case ui::AXEventGenerator::Event::LIVE_REGION_CHANGED: {
|
||||
// Voiceover seems to drop live region changed notifications if they come
|
||||
@@ -297,7 +221,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
|
||||
if (never_suppress_or_delay_events_for_testing_) {
|
||||
NSAccessibilityPostNotification(
|
||||
- native_node, NSAccessibilityLiveRegionChangedNotification);
|
||||
+ native_node, ui::NSAccessibilityLiveRegionChangedNotification);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -321,7 +245,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
[](base::scoped_nsobject<BrowserAccessibilityCocoa> node) {
|
||||
if (node && [node instanceActive]) {
|
||||
NSAccessibilityPostNotification(
|
||||
- node, NSAccessibilityLiveRegionChangedNotification);
|
||||
+ node, ui::NSAccessibilityLiveRegionChangedNotification);
|
||||
}
|
||||
},
|
||||
std::move(retained_node)),
|
||||
@@ -329,7 +253,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
return;
|
||||
}
|
||||
case ui::AXEventGenerator::Event::LIVE_REGION_CREATED:
|
||||
- mac_notification = NSAccessibilityLiveRegionCreatedNotification;
|
||||
+ mac_notification = ui::NSAccessibilityLiveRegionCreatedNotification;
|
||||
break;
|
||||
case ui::AXEventGenerator::Event::LOAD_COMPLETE:
|
||||
// On MacOS 10.15, firing AXLoadComplete causes focus to move to the
|
||||
@@ -343,7 +267,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
// |NSAccessibilityLoadCompleteNotification| should only be fired on the
|
||||
// top document and when the document is not Chrome's new tab page.
|
||||
if (IsRootTree() && !IsChromeNewTabPage()) {
|
||||
- mac_notification = NSAccessibilityLoadCompleteNotification;
|
||||
+ mac_notification = ui::NSAccessibilityLoadCompleteNotification;
|
||||
} else {
|
||||
// Voiceover moves focus to the web content when it receives an
|
||||
// AXLoadComplete event. On Chrome's new tab page, focus should stay
|
||||
@@ -353,7 +277,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
}
|
||||
break;
|
||||
case ui::AXEventGenerator::Event::MENU_ITEM_SELECTED:
|
||||
- mac_notification = NSAccessibilityMenuItemSelectedNotification;
|
||||
+ mac_notification = ui::NSAccessibilityMenuItemSelectedNotification;
|
||||
break;
|
||||
case ui::AXEventGenerator::Event::RANGE_VALUE_CHANGED:
|
||||
DCHECK(node->GetData().IsRangeValueSupported());
|
||||
@@ -532,18 +456,32 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
}
|
||||
}
|
||||
|
||||
-NSDictionary* BrowserAccessibilityManagerMac::
|
||||
- GetUserInfoForSelectedTextChangedNotification() {
|
||||
+NSDictionary*
|
||||
+BrowserAccessibilityManagerMac::GetUserInfoForSelectedTextChangedNotification(
|
||||
+ bool focus_changed) {
|
||||
NSMutableDictionary* user_info =
|
||||
[[[NSMutableDictionary alloc] init] autorelease];
|
||||
- [user_info setObject:@YES forKey:NSAccessibilityTextStateSyncKey];
|
||||
- [user_info setObject:@(AXTextStateChangeTypeUnknown)
|
||||
- forKey:NSAccessibilityTextStateChangeTypeKey];
|
||||
- [user_info setObject:@(AXTextSelectionDirectionUnknown)
|
||||
- forKey:NSAccessibilityTextSelectionDirection];
|
||||
- [user_info setObject:@(AXTextSelectionGranularityUnknown)
|
||||
- forKey:NSAccessibilityTextSelectionGranularity];
|
||||
- [user_info setObject:@YES forKey:NSAccessibilityTextSelectionChangedFocus];
|
||||
+ [user_info setObject:@YES forKey:ui::NSAccessibilityTextStateSyncKey];
|
||||
+ [user_info setObject:@(ui::AXTextSelectionDirectionUnknown)
|
||||
+ forKey:ui::NSAccessibilityTextSelectionDirection];
|
||||
+ [user_info setObject:@(ui::AXTextSelectionGranularityUnknown)
|
||||
+ forKey:ui::NSAccessibilityTextSelectionGranularity];
|
||||
+ [user_info setObject:@YES
|
||||
+ forKey:ui::NSAccessibilityTextSelectionChangedFocus];
|
||||
+
|
||||
+ // Try to detect when the text selection changes due to a focus change.
|
||||
+ // This is necessary so that VoiceOver also anounces information about the
|
||||
+ // element that contains this selection.
|
||||
+ // TODO(mrobinson): Determine definitively what the type of this text
|
||||
+ // selection change is. This requires passing this information here from
|
||||
+ // blink.
|
||||
+ if (focus_changed) {
|
||||
+ [user_info setObject:@(ui::AXTextStateChangeTypeSelectionMove)
|
||||
+ forKey:ui::NSAccessibilityTextStateChangeTypeKey];
|
||||
+ } else {
|
||||
+ [user_info setObject:@(ui::AXTextStateChangeTypeUnknown)
|
||||
+ forKey:ui::NSAccessibilityTextStateChangeTypeKey];
|
||||
+ }
|
||||
|
||||
int32_t focus_id = ax_tree()->GetUnignoredSelection().focus_object_id;
|
||||
BrowserAccessibility* focus_object = GetFromID(focus_id);
|
||||
@@ -552,7 +490,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
auto native_focus_object = ToBrowserAccessibilityCocoa(focus_object);
|
||||
if (native_focus_object && [native_focus_object instanceActive]) {
|
||||
[user_info setObject:native_focus_object
|
||||
- forKey:NSAccessibilityTextChangeElement];
|
||||
+ forKey:ui::NSAccessibilityTextChangeElement];
|
||||
|
||||
#ifndef MAS_BUILD
|
||||
id selected_text = [native_focus_object selectedTextMarkerRange];
|
||||
@@ -583,38 +521,39 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||
if (!deleted_text.empty()) {
|
||||
NSMutableDictionary* change =
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
- NSAccessibilityTextEditType : @(AXTextEditTypeDelete),
|
||||
- NSAccessibilityTextChangeValueLength : @(deleted_text.length()),
|
||||
- NSAccessibilityTextChangeValue :
|
||||
+ ui::NSAccessibilityTextEditType : @(ui::AXTextEditTypeDelete),
|
||||
+ ui::NSAccessibilityTextChangeValueLength : @(deleted_text.length()),
|
||||
+ ui::NSAccessibilityTextChangeValue :
|
||||
base::SysUTF16ToNSString(deleted_text)
|
||||
}];
|
||||
if (edit_text_marker) {
|
||||
- change[NSAccessibilityChangeValueStartMarker] = edit_text_marker;
|
||||
+ change[ui::NSAccessibilityChangeValueStartMarker] = edit_text_marker;
|
||||
}
|
||||
[changes addObject:change];
|
||||
}
|
||||
if (!inserted_text.empty()) {
|
||||
// TODO(nektar): Figure out if this is a paste, insertion or typing.
|
||||
// Changes to Blink would be required. A heuristic is currently used.
|
||||
- auto edit_type = inserted_text.length() > 1 ? @(AXTextEditTypeInsert)
|
||||
- : @(AXTextEditTypeTyping);
|
||||
+ auto edit_type = inserted_text.length() > 1 ? @(ui::AXTextEditTypeInsert)
|
||||
+ : @(ui::AXTextEditTypeTyping);
|
||||
NSMutableDictionary* change =
|
||||
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||
- NSAccessibilityTextEditType : edit_type,
|
||||
- NSAccessibilityTextChangeValueLength : @(inserted_text.length()),
|
||||
- NSAccessibilityTextChangeValue :
|
||||
+ ui::NSAccessibilityTextEditType : edit_type,
|
||||
+ ui::NSAccessibilityTextChangeValueLength : @(inserted_text.length()),
|
||||
+ ui::NSAccessibilityTextChangeValue :
|
||||
base::SysUTF16ToNSString(inserted_text)
|
||||
}];
|
||||
if (edit_text_marker) {
|
||||
- change[NSAccessibilityChangeValueStartMarker] = edit_text_marker;
|
||||
+ change[ui::NSAccessibilityChangeValueStartMarker] = edit_text_marker;
|
||||
}
|
||||
[changes addObject:change];
|
||||
}
|
||||
|
||||
return @{
|
||||
- NSAccessibilityTextStateChangeTypeKey : @(AXTextStateChangeTypeEdit),
|
||||
- NSAccessibilityTextChangeValues : changes,
|
||||
- NSAccessibilityTextChangeElement : native_node
|
||||
+ ui::
|
||||
+ NSAccessibilityTextStateChangeTypeKey : @(ui::AXTextStateChangeTypeEdit),
|
||||
+ ui::NSAccessibilityTextChangeValues : changes,
|
||||
+ ui::NSAccessibilityTextChangeElement : native_node
|
||||
};
|
||||
}
|
||||
|
||||
diff --git a/content/test/data/accessibility/event/aria-combo-box-focus-expected-mac.txt b/content/test/data/accessibility/event/aria-combo-box-focus-expected-mac.txt
|
||||
index ad5e2bf2c8029185c51eecc94cac1dbe7608c99e..67e07a89f77f7c61a57eb51cecea211df5227341 100644
|
||||
--- a/content/test/data/accessibility/event/aria-combo-box-focus-expected-mac.txt
|
||||
+++ b/content/test/data/accessibility/event/aria-combo-box-focus-expected-mac.txt
|
||||
@@ -1,3 +1,3 @@
|
||||
AXFocusedUIElementChanged on AXStaticText AXValue="Apple not selected"
|
||||
-AXSelectedTextChanged on AXStaticText AXValue="Apple not selected"
|
||||
-AXSelectedTextChanged on AXWebArea
|
||||
\ No newline at end of file
|
||||
+AXSelectedTextChanged on AXStaticText AXValue="Apple not selected" AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeSelectionMove
|
||||
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeSelectionMove
|
||||
diff --git a/content/test/data/accessibility/event/caret-browsing-disabled-expected-mac.txt b/content/test/data/accessibility/event/caret-browsing-disabled-expected-mac.txt
|
||||
index ec0b74d984ade9928705242f9b0682a743e20fb2..87447c5a4b14efde5b64b1d340a3fa2fb6574b80 100644
|
||||
--- a/content/test/data/accessibility/event/caret-browsing-disabled-expected-mac.txt
|
||||
+++ b/content/test/data/accessibility/event/caret-browsing-disabled-expected-mac.txt
|
||||
@@ -1,5 +1,5 @@
|
||||
-AXSelectedTextChanged on AXWebArea
|
||||
-AXSelectedTextChanged on AXWebArea
|
||||
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||
=== Start Continuation ===
|
||||
-AXSelectedTextChanged on AXWebArea
|
||||
-AXSelectedTextChanged on AXWebArea
|
||||
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||
diff --git a/content/test/data/accessibility/event/caret-browsing-enabled-expected-mac.txt b/content/test/data/accessibility/event/caret-browsing-enabled-expected-mac.txt
|
||||
index ec0b74d984ade9928705242f9b0682a743e20fb2..87447c5a4b14efde5b64b1d340a3fa2fb6574b80 100644
|
||||
--- a/content/test/data/accessibility/event/caret-browsing-enabled-expected-mac.txt
|
||||
+++ b/content/test/data/accessibility/event/caret-browsing-enabled-expected-mac.txt
|
||||
@@ -1,5 +1,5 @@
|
||||
-AXSelectedTextChanged on AXWebArea
|
||||
-AXSelectedTextChanged on AXWebArea
|
||||
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||
=== Start Continuation ===
|
||||
-AXSelectedTextChanged on AXWebArea
|
||||
-AXSelectedTextChanged on AXWebArea
|
||||
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||
diff --git a/content/test/data/accessibility/event/text-selection-changed-expected-mac.txt b/content/test/data/accessibility/event/text-selection-changed-expected-mac.txt
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..9213c873393d595bba8796cdb0e2325d3ee37ee9
|
||||
--- /dev/null
|
||||
+++ b/content/test/data/accessibility/event/text-selection-changed-expected-mac.txt
|
||||
@@ -0,0 +1,10 @@
|
||||
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||
+=== Start Continuation ===
|
||||
+AXFocusedUIElementChanged on AXTextField AXDescription="input" AXValue="input"
|
||||
+AXSelectedTextChanged on AXTextField AXDescription="input" AXValue="input" AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeSelectionMove
|
||||
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeSelectionMove
|
||||
+=== Start Continuation ===
|
||||
+AXFocusedUIElementChanged on AXTextArea AXDescription="textarea"
|
||||
+AXSelectedTextChanged on AXTextArea AXDescription="textarea" AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeSelectionMove
|
||||
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeSelectionMove
|
||||
diff --git a/ui/accessibility/platform/BUILD.gn b/ui/accessibility/platform/BUILD.gn
|
||||
index 99df759347f899a78dc37846e30598f82edb34f7..47d57fcf7aa02b5b2c5afab18a96666dda3b79bb 100644
|
||||
--- a/ui/accessibility/platform/BUILD.gn
|
||||
+++ b/ui/accessibility/platform/BUILD.gn
|
||||
@@ -118,6 +118,8 @@ source_set("platform") {
|
||||
"ax_event_intent_mac.mm",
|
||||
"ax_platform_node_mac.h",
|
||||
"ax_platform_node_mac.mm",
|
||||
+ "ax_private_webkit_constants_mac.h",
|
||||
+ "ax_private_webkit_constants_mac.mm",
|
||||
]
|
||||
|
||||
frameworks = [
|
||||
diff --git a/ui/accessibility/platform/ax_private_webkit_constants_mac.h b/ui/accessibility/platform/ax_private_webkit_constants_mac.h
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..5f1776a3aeac89b70d6d852b8e5209a1208271ae
|
||||
--- /dev/null
|
||||
+++ b/ui/accessibility/platform/ax_private_webkit_constants_mac.h
|
||||
@@ -0,0 +1,96 @@
|
||||
+// Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+#ifndef UI_ACCESSIBILITY_PLATFORM_AX_PRIVATE_WEBKIT_CONSTANTS_MAC_H_
|
||||
+#define UI_ACCESSIBILITY_PLATFORM_AX_PRIVATE_WEBKIT_CONSTANTS_MAC_H_
|
||||
+
|
||||
+#import <Cocoa/Cocoa.h>
|
||||
+#include "ui/accessibility/ax_export.h"
|
||||
+
|
||||
+namespace ui {
|
||||
+
|
||||
+enum AXTextStateChangeType {
|
||||
+ AXTextStateChangeTypeUnknown,
|
||||
+ AXTextStateChangeTypeEdit,
|
||||
+ AXTextStateChangeTypeSelectionMove,
|
||||
+ AXTextStateChangeTypeSelectionExtend
|
||||
+};
|
||||
+
|
||||
+enum AXTextSelectionDirection {
|
||||
+ AXTextSelectionDirectionUnknown,
|
||||
+ AXTextSelectionDirectionBeginning,
|
||||
+ AXTextSelectionDirectionEnd,
|
||||
+ AXTextSelectionDirectionPrevious,
|
||||
+ AXTextSelectionDirectionNext,
|
||||
+ AXTextSelectionDirectionDiscontiguous
|
||||
+};
|
||||
+
|
||||
+enum AXTextSelectionGranularity {
|
||||
+ AXTextSelectionGranularityUnknown,
|
||||
+ AXTextSelectionGranularityCharacter,
|
||||
+ AXTextSelectionGranularityWord,
|
||||
+ AXTextSelectionGranularityLine,
|
||||
+ AXTextSelectionGranularitySentence,
|
||||
+ AXTextSelectionGranularityParagraph,
|
||||
+ AXTextSelectionGranularityPage,
|
||||
+ AXTextSelectionGranularityDocument,
|
||||
+ AXTextSelectionGranularityAll
|
||||
+};
|
||||
+
|
||||
+enum AXTextEditType {
|
||||
+ AXTextEditTypeUnknown,
|
||||
+ AXTextEditTypeDelete,
|
||||
+ AXTextEditTypeInsert,
|
||||
+ AXTextEditTypeTyping,
|
||||
+ AXTextEditTypeDictation,
|
||||
+ AXTextEditTypeCut,
|
||||
+ AXTextEditTypePaste,
|
||||
+ AXTextEditTypeAttributesChange
|
||||
+};
|
||||
+
|
||||
+// Native mac notifications fired.
|
||||
+NSString* const NSAccessibilityAutocorrectionOccurredNotification =
|
||||
+ @"AXAutocorrectionOccurred";
|
||||
+NSString* const NSAccessibilityLoadCompleteNotification = @"AXLoadComplete";
|
||||
+NSString* const NSAccessibilityInvalidStatusChangedNotification =
|
||||
+ @"AXInvalidStatusChanged";
|
||||
+NSString* const NSAccessibilityLiveRegionCreatedNotification =
|
||||
+ @"AXLiveRegionCreated";
|
||||
+NSString* const NSAccessibilityLiveRegionChangedNotification =
|
||||
+ @"AXLiveRegionChanged";
|
||||
+NSString* const NSAccessibilityExpandedChanged = @"AXExpandedChanged";
|
||||
+NSString* const NSAccessibilityMenuItemSelectedNotification =
|
||||
+ @"AXMenuItemSelected";
|
||||
+
|
||||
+// The following native mac notifications are not fired:
|
||||
+// AXLayoutComplete: Voiceover does not use this, it is considered too spammy.
|
||||
+
|
||||
+// Attributes used for NSAccessibilitySelectedTextChangedNotification and
|
||||
+// NSAccessibilityValueChangedNotification.
|
||||
+NSString* const NSAccessibilityTextStateChangeTypeKey =
|
||||
+ @"AXTextStateChangeType";
|
||||
+NSString* const NSAccessibilityTextStateSyncKey = @"AXTextStateSync";
|
||||
+NSString* const NSAccessibilityTextSelectionDirection =
|
||||
+ @"AXTextSelectionDirection";
|
||||
+NSString* const NSAccessibilityTextSelectionGranularity =
|
||||
+ @"AXTextSelectionGranularity";
|
||||
+NSString* const NSAccessibilityTextSelectionChangedFocus =
|
||||
+ @"AXTextSelectionChangedFocus";
|
||||
+NSString* const NSAccessibilityTextChangeElement = @"AXTextChangeElement";
|
||||
+NSString* const NSAccessibilityTextEditType = @"AXTextEditType";
|
||||
+NSString* const NSAccessibilityTextChangeValue = @"AXTextChangeValue";
|
||||
+NSString* const NSAccessibilityChangeValueStartMarker =
|
||||
+ @"AXTextChangeValueStartMarker";
|
||||
+NSString* const NSAccessibilityTextChangeValueLength =
|
||||
+ @"AXTextChangeValueLength";
|
||||
+NSString* const NSAccessibilityTextChangeValues = @"AXTextChangeValues";
|
||||
+
|
||||
+AX_EXPORT const char* ToString(AXTextStateChangeType);
|
||||
+AX_EXPORT const char* ToString(AXTextSelectionDirection);
|
||||
+AX_EXPORT const char* ToString(AXTextSelectionGranularity);
|
||||
+AX_EXPORT const char* ToString(AXTextEditType);
|
||||
+
|
||||
+} // namespace ui
|
||||
+
|
||||
+#endif // UI_ACCESSIBILITY_PLATFORM_AX_PRIVATE_WEBKIT_CONSTANTS_MAC_H_
|
||||
diff --git a/ui/accessibility/platform/ax_private_webkit_constants_mac.mm b/ui/accessibility/platform/ax_private_webkit_constants_mac.mm
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..7de31a487dd6e0e6a4af2f4fa62e463f41a0d96a
|
||||
--- /dev/null
|
||||
+++ b/ui/accessibility/platform/ax_private_webkit_constants_mac.mm
|
||||
@@ -0,0 +1,91 @@
|
||||
+// Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+#include "ui/accessibility/platform/ax_private_webkit_constants_mac.h"
|
||||
+
|
||||
+namespace ui {
|
||||
+
|
||||
+const char* ToString(AXTextStateChangeType type) {
|
||||
+ switch (type) {
|
||||
+ case AXTextStateChangeTypeUnknown:
|
||||
+ return "AXTextStateChangeTypeUnknown";
|
||||
+ case AXTextStateChangeTypeEdit:
|
||||
+ return "AXTextStateChangeTypeEdit";
|
||||
+ case AXTextStateChangeTypeSelectionMove:
|
||||
+ return "AXTextStateChangeTypeSelectionMove";
|
||||
+ case AXTextStateChangeTypeSelectionExtend:
|
||||
+ return "AXTextStateChangeTypeSelectionExtend";
|
||||
+ }
|
||||
+
|
||||
+ return "";
|
||||
+}
|
||||
+
|
||||
+const char* ToString(AXTextSelectionDirection direction) {
|
||||
+ switch (direction) {
|
||||
+ case AXTextSelectionDirectionUnknown:
|
||||
+ return "AXTextSelectionDirectionUnknown";
|
||||
+ case AXTextSelectionDirectionBeginning:
|
||||
+ return "AXTextSelectionDirectionBeginning";
|
||||
+ case AXTextSelectionDirectionEnd:
|
||||
+ return "AXTextSelectionDirectionEnd";
|
||||
+ case AXTextSelectionDirectionPrevious:
|
||||
+ return "AXTextSelectionDirectionPrevious";
|
||||
+ case AXTextSelectionDirectionNext:
|
||||
+ return "AXTextSelectionDirectionNext";
|
||||
+ case AXTextSelectionDirectionDiscontiguous:
|
||||
+ return "AXTextSelectionDirectionDiscontiguous";
|
||||
+ }
|
||||
+
|
||||
+ return "";
|
||||
+}
|
||||
+
|
||||
+const char* ToString(AXTextSelectionGranularity granularity) {
|
||||
+ switch (granularity) {
|
||||
+ case AXTextSelectionGranularityUnknown:
|
||||
+ return "AXTextSelectionGranularityUnknown";
|
||||
+ case AXTextSelectionGranularityCharacter:
|
||||
+ return "AXTextSelectionGranularityCharacter";
|
||||
+ case AXTextSelectionGranularityWord:
|
||||
+ return "AXTextSelectionGranularityWord";
|
||||
+ case AXTextSelectionGranularityLine:
|
||||
+ return "AXTextSelectionGranularityLine";
|
||||
+ case AXTextSelectionGranularitySentence:
|
||||
+ return "AXTextSelectionGranularitySentence";
|
||||
+ case AXTextSelectionGranularityParagraph:
|
||||
+ return "AXTextSelectionGranularityParagraph";
|
||||
+ case AXTextSelectionGranularityPage:
|
||||
+ return "AXTextSelectionGranularityPage";
|
||||
+ case AXTextSelectionGranularityDocument:
|
||||
+ return "AXTextSelectionGranularityDocument";
|
||||
+ case AXTextSelectionGranularityAll:
|
||||
+ return "AXTextSelectionGranularityAll";
|
||||
+ }
|
||||
+
|
||||
+ return "";
|
||||
+}
|
||||
+
|
||||
+const char* ToString(AXTextEditType type) {
|
||||
+ switch (type) {
|
||||
+ case AXTextEditTypeUnknown:
|
||||
+ return "AXTextEditTypeUnknown";
|
||||
+ case AXTextEditTypeDelete:
|
||||
+ return "AXTextEditTypeDelete";
|
||||
+ case AXTextEditTypeInsert:
|
||||
+ return "AXTextEditTypeInsert";
|
||||
+ case AXTextEditTypeTyping:
|
||||
+ return "AXTextEditTypeTyping";
|
||||
+ case AXTextEditTypeDictation:
|
||||
+ return "AXTextEditTypeDictation";
|
||||
+ case AXTextEditTypeCut:
|
||||
+ return "AXTextEditTypeCut";
|
||||
+ case AXTextEditTypePaste:
|
||||
+ return "AXTextEditTypePaste";
|
||||
+ case AXTextEditTypeAttributesChange:
|
||||
+ return "AXTextEditTypeAttributesChange";
|
||||
+ }
|
||||
+
|
||||
+ return "";
|
||||
+}
|
||||
+
|
||||
+} // namespace ui
|
||||
38
patches/chromium/enable_reset_aspect_ratio.patch
Normal file
38
patches/chromium/enable_reset_aspect_ratio.patch
Normal file
@@ -0,0 +1,38 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Cheng Zhao <zcbenz@gmail.com>
|
||||
Date: Thu, 4 Oct 2018 14:57:02 -0700
|
||||
Subject: feat: enable setting aspect ratio to 0
|
||||
|
||||
Make SetAspectRatio accept 0 as valid input, which would reset to null.
|
||||
|
||||
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
|
||||
index 3b132d4d7618e11b851b315e82fa67442c852fb3..af2c2f2bbc1f52f4455fb973ab2fc0d0dd013ca5 100644
|
||||
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
|
||||
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
|
||||
@@ -484,7 +484,7 @@ void DesktopWindowTreeHostWin::SetOpacity(float opacity) {
|
||||
}
|
||||
|
||||
void DesktopWindowTreeHostWin::SetAspectRatio(const gfx::SizeF& aspect_ratio) {
|
||||
- DCHECK(!aspect_ratio.IsEmpty());
|
||||
+ DCHECK_NE(aspect_ratio.height(), 0);
|
||||
message_handler_->SetAspectRatio(aspect_ratio.width() /
|
||||
aspect_ratio.height());
|
||||
}
|
||||
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
|
||||
index 9efbc5d9bdfb3fc659560b57394446158babe6b3..7389272fe6ba455be1663ab7b7328e7ea9f53c66 100644
|
||||
--- a/ui/views/win/hwnd_message_handler.cc
|
||||
+++ b/ui/views/win/hwnd_message_handler.cc
|
||||
@@ -923,8 +923,11 @@ void HWNDMessageHandler::SetFullscreen(bool fullscreen) {
|
||||
}
|
||||
|
||||
void HWNDMessageHandler::SetAspectRatio(float aspect_ratio) {
|
||||
- // If the aspect ratio is not in the valid range, do nothing.
|
||||
- DCHECK_GT(aspect_ratio, 0.0f);
|
||||
+ // If the aspect ratio is 0, reset it to null.
|
||||
+ if (aspect_ratio == 0.0f) {
|
||||
+ aspect_ratio_.reset();
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
aspect_ratio_ = aspect_ratio;
|
||||
|
||||
28
patches/chromium/fix_setparentacessibile_crash_win.patch
Normal file
28
patches/chromium/fix_setparentacessibile_crash_win.patch
Normal file
@@ -0,0 +1,28 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Biru Mohanathas <birunthan@mohanathas.com>
|
||||
Date: Thu, 10 Dec 2020 19:02:37 +0200
|
||||
Subject: fix crash in NativeViewHost::SetParentAccessible
|
||||
|
||||
This fixes random crashes on Windows 10. It presumably started happening
|
||||
after the changes in
|
||||
https://chromium.googlesource.com/chromium/src.git/+/5c6c8e994bce2bfb867279ae5068e9f9134e70c3%5E!/#F15
|
||||
|
||||
For context, see: https://github.com/electron/electron/issues/26905
|
||||
|
||||
This patch can likely be upstreamed. The crash cannot be fixed without
|
||||
patching something in Chromium - this is the least invasive change.
|
||||
|
||||
diff --git a/ui/views/controls/native/native_view_host.cc b/ui/views/controls/native/native_view_host.cc
|
||||
index f9e1aa1b455ae49b59d53a75ae0634d0c092a130..4785f0c0368e0ab22db0cc968ad85d23a9b26240 100644
|
||||
--- a/ui/views/controls/native/native_view_host.cc
|
||||
+++ b/ui/views/controls/native/native_view_host.cc
|
||||
@@ -55,6 +55,9 @@ void NativeViewHost::Detach() {
|
||||
}
|
||||
|
||||
void NativeViewHost::SetParentAccessible(gfx::NativeViewAccessible accessible) {
|
||||
+ if (!native_wrapper_.get())
|
||||
+ return;
|
||||
+
|
||||
native_wrapper_->SetParentAccessible(accessible);
|
||||
}
|
||||
|
||||
@@ -4,14 +4,12 @@ refactor_alter_child_process_fork_to_use_execute_script_with.patch
|
||||
feat_add_uv_loop_watcher_queue_code.patch
|
||||
feat_initialize_asar_support.patch
|
||||
expose_get_builtin_module_function.patch
|
||||
fix_expose_internalcallbackscope.patch
|
||||
build_add_gn_build_files.patch
|
||||
fix_add_default_values_for_enable_lto_and_build_v8_with_gn_in.patch
|
||||
feat_add_new_built_with_electron_variable_to_config_gypi.patch
|
||||
feat_add_flags_for_low-level_hooks_and_exceptions.patch
|
||||
fix_expose_tracing_agent_and_use_tracing_tracingcontroller_instead.patch
|
||||
pass_all_globals_through_require.patch
|
||||
fixme_remove_async_id_assertion_check.patch
|
||||
fixme_comment_trace_event_macro.patch
|
||||
fix_key_gen_apis_are_not_available_in_boringssl.patch
|
||||
build_modify_js2c_py_to_allow_injection_of_original-fs_and_custom_embedder_js.patch
|
||||
@@ -29,3 +27,5 @@ fix_-wincompatible-pointer-types-discards-qualifiers_error.patch
|
||||
fix_add_v8_enable_reverse_jsargs_defines_in_common_gypi.patch
|
||||
fix_allow_preventing_initializeinspector_in_env.patch
|
||||
src_allow_embedders_to_provide_a_custom_pageallocator_to.patch
|
||||
allow_preventing_preparestacktracecallback.patch
|
||||
fix_add_safeforterminationscopes_for_sigint_interruptions.patch
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Mon, 7 Dec 2020 16:54:23 -0800
|
||||
Subject: Allow preventing PrepareStackTraceCallback
|
||||
|
||||
Node.js sets a stack trace handler specific to the v8::Context
|
||||
corresponding to the current Environment. When we're running in a
|
||||
non-Node.js v8::Context, there will be no correspondent Environment - we
|
||||
therefore need to prevent this handler being set so that Blink falls back to its
|
||||
default handling and displays the correct stacktrace.
|
||||
|
||||
diff --git a/src/api/environment.cc b/src/api/environment.cc
|
||||
index a8cf0d763f78c2752e3aa22479dadd9fa53c222f..8ccc0638b32039571c4a56725e21f0353b592984 100644
|
||||
--- a/src/api/environment.cc
|
||||
+++ b/src/api/environment.cc
|
||||
@@ -228,9 +228,11 @@ void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
|
||||
s.fatal_error_callback : OnFatalError;
|
||||
isolate->SetFatalErrorHandler(fatal_error_cb);
|
||||
|
||||
- auto* prepare_stack_trace_cb = s.prepare_stack_trace_callback ?
|
||||
- s.prepare_stack_trace_callback : PrepareStackTraceCallback;
|
||||
- isolate->SetPrepareStackTraceCallback(prepare_stack_trace_cb);
|
||||
+ if ((s.flags & SHOULD_NOT_SET_PREPARE_STACK_TRACE_CALLBACK) == 0) {
|
||||
+ auto* prepare_stack_trace_cb = s.prepare_stack_trace_callback ?
|
||||
+ s.prepare_stack_trace_callback : PrepareStackTraceCallback;
|
||||
+ isolate->SetPrepareStackTraceCallback(prepare_stack_trace_cb);
|
||||
+ }
|
||||
}
|
||||
|
||||
void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
|
||||
diff --git a/src/node.h b/src/node.h
|
||||
index 14893ad605b9f8c64b0b8fc28625e235655dcd63..f150725b54ee1315476d202797963369490d5152 100644
|
||||
--- a/src/node.h
|
||||
+++ b/src/node.h
|
||||
@@ -340,7 +340,8 @@ class NODE_EXTERN MultiIsolatePlatform : public v8::Platform {
|
||||
enum IsolateSettingsFlags {
|
||||
MESSAGE_LISTENER_WITH_ERROR_LEVEL = 1 << 0,
|
||||
DETAILED_SOURCE_POSITIONS_FOR_PROFILING = 1 << 1,
|
||||
- SHOULD_NOT_SET_PROMISE_REJECTION_CALLBACK = 1 << 2
|
||||
+ SHOULD_NOT_SET_PROMISE_REJECTION_CALLBACK = 1 << 2,
|
||||
+ SHOULD_NOT_SET_PREPARE_STACK_TRACE_CALLBACK = 1 << 3
|
||||
};
|
||||
|
||||
struct IsolateSettings {
|
||||
@@ -0,0 +1,39 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Thu, 10 Dec 2020 14:39:33 -0800
|
||||
Subject: fix: add SafeForTerminationScopes for SIGINT interruptions
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
We start Node.js with only_terminate_in_safe_scope set to true becuase
|
||||
it's set by gin’s IsolateHolder. In those cases, parts of the API that
|
||||
expect execution termination to happen need to be marked as able to
|
||||
receive those events.
|
||||
|
||||
Upstreamed at https://github.com/nodejs/node/pull/36344.
|
||||
|
||||
diff --git a/src/module_wrap.cc b/src/module_wrap.cc
|
||||
index f778b089dc4009912361342077793e7918286de3..9302fa6f68d83717a02b82891466ce12b6af2cfd 100644
|
||||
--- a/src/module_wrap.cc
|
||||
+++ b/src/module_wrap.cc
|
||||
@@ -350,6 +350,7 @@ void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
ShouldNotAbortOnUncaughtScope no_abort_scope(env);
|
||||
TryCatchScope try_catch(env);
|
||||
+ Isolate::SafeForTerminationScope safe_for_termination(env->isolate());
|
||||
|
||||
bool timed_out = false;
|
||||
bool received_signal = false;
|
||||
diff --git a/src/node_contextify.cc b/src/node_contextify.cc
|
||||
index 848e883a829a9725649d837bff09b30156f4f661..a69570400cd897699b1033102767b3389ff8ef38 100644
|
||||
--- a/src/node_contextify.cc
|
||||
+++ b/src/node_contextify.cc
|
||||
@@ -933,6 +933,7 @@ bool ContextifyScript::EvalMachine(Environment* env,
|
||||
return false;
|
||||
}
|
||||
TryCatchScope try_catch(env);
|
||||
+ Isolate::SafeForTerminationScope safe_for_termination(env->isolate());
|
||||
ContextifyScript* wrapped_script;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder(), false);
|
||||
Local<UnboundScript> unbound_script =
|
||||
@@ -1,20 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: deepak1556 <hop2deep@gmail.com>
|
||||
Date: Sat, 6 Jan 2018 18:28:10 +0530
|
||||
Subject: fix: expose InternalCallbackScope
|
||||
|
||||
This commit exposes InternalCallbackScope in order to allow us access to its internal flags.
|
||||
|
||||
diff --git a/src/node_internals.h b/src/node_internals.h
|
||||
index aa7180e18544cab4004a0ef87ba230bd2e732d28..9a5b2165d5648045ea18d66b0c15d29b4ea1cced 100644
|
||||
--- a/src/node_internals.h
|
||||
+++ b/src/node_internals.h
|
||||
@@ -200,7 +200,7 @@ v8::MaybeLocal<v8::Value> InternalMakeCallback(
|
||||
v8::Local<v8::Value> argv[],
|
||||
async_context asyncContext);
|
||||
|
||||
-class InternalCallbackScope {
|
||||
+class NODE_EXTERN InternalCallbackScope {
|
||||
public:
|
||||
enum Flags {
|
||||
kNoFlags = 0,
|
||||
@@ -7,7 +7,7 @@ This broke the build at some point. Does it still? We should probably remove
|
||||
this patch and find out!
|
||||
|
||||
diff --git a/src/node_internals.h b/src/node_internals.h
|
||||
index 9a5b2165d5648045ea18d66b0c15d29b4ea1cced..6aff1a4ee7f708437dbf581b9eacc21e5bdd1c43 100644
|
||||
index aa7180e18544cab4004a0ef87ba230bd2e732d28..0a01dcd8ed194b205d7fe510451315610e5a60be 100644
|
||||
--- a/src/node_internals.h
|
||||
+++ b/src/node_internals.h
|
||||
@@ -368,10 +368,11 @@ class TraceEventScope {
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Thu, 13 Sep 2018 09:08:10 -0700
|
||||
Subject: FIXME: remove async_id assertion check
|
||||
|
||||
async hooks are hella broken in Electron. This was checking that they weren't,
|
||||
but they are, so we just disabled the check. YOLO.
|
||||
|
||||
diff --git a/src/api/callback.cc b/src/api/callback.cc
|
||||
index 3d4f91a866ea3966689992e996b62142b207a602..8b9850dd6a7f76c9384eca65ab5308da69377e26 100644
|
||||
--- a/src/api/callback.cc
|
||||
+++ b/src/api/callback.cc
|
||||
@@ -116,12 +116,14 @@ void InternalCallbackScope::Close() {
|
||||
perform_stopping_check();
|
||||
}
|
||||
|
||||
+#if 0 // FIXME(codebytere): figure out why this check fails/causes crash
|
||||
// Make sure the stack unwound properly. If there are nested MakeCallback's
|
||||
// then it should return early and not reach this code.
|
||||
if (env_->async_hooks()->fields()[AsyncHooks::kTotals]) {
|
||||
CHECK_EQ(env_->execution_async_id(), 0);
|
||||
CHECK_EQ(env_->trigger_async_id(), 0);
|
||||
}
|
||||
+#endif
|
||||
|
||||
if (!tick_info->has_tick_scheduled() && !tick_info->has_rejection_to_warn()) {
|
||||
return;
|
||||
@@ -305,7 +305,7 @@ index e42332ab13fb01000c73cf0b3b757d1f7141da6f..f8754dbd6a1490d2b50f1014e2daa5c1
|
||||
|
||||
NSString * const SQRLCodeSignatureErrorDomain = @"SQRLCodeSignatureErrorDomain";
|
||||
diff --git a/Squirrel/SQRLDirectoryManager.m b/Squirrel/SQRLDirectoryManager.m
|
||||
index 34f321077f0bf59de98a41dea2cea95eff72486d..200891ca73ac67754219204340881ef85aff4845 100644
|
||||
index fb130fa5dca4570e0822c8cfdab6831bb57ab5ad..d439906827e0f9fb5550bb6c9840a4e75352f3d7 100644
|
||||
--- a/Squirrel/SQRLDirectoryManager.m
|
||||
+++ b/Squirrel/SQRLDirectoryManager.m
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
@@ -146,7 +146,6 @@
|
||||
"parallel/test-v8-flags",
|
||||
"parallel/test-vm-module-basic",
|
||||
"parallel/test-vm-parse-abort-on-uncaught-exception",
|
||||
"parallel/test-vm-sigint",
|
||||
"parallel/test-vm-sigint-existing-handler",
|
||||
"parallel/test-vm-timeout",
|
||||
"parallel/test-whatwg-encoding-custom-textdecoder",
|
||||
|
||||
@@ -29,6 +29,8 @@ PDB_LIST = [
|
||||
os.path.join(RELEASE_DIR, '{0}.exe.pdb'.format(PROJECT_NAME))
|
||||
]
|
||||
|
||||
PDB_LIST += glob.glob(os.path.join(RELEASE_DIR, '*.dll.pdb'))
|
||||
|
||||
NPX_CMD = "npx"
|
||||
if sys.platform == "win32":
|
||||
NPX_CMD += ".cmd"
|
||||
|
||||
@@ -206,7 +206,7 @@ int NodeMain(int argc, char* argv[]) {
|
||||
exec_argv + exec_argc); // NOLINT
|
||||
env = node::CreateEnvironment(isolate_data, gin_env.context(), args,
|
||||
exec_args);
|
||||
CHECK_NE(nullptr, env);
|
||||
CHECK_NOT_NULL(env);
|
||||
|
||||
node::IsolateSettings is;
|
||||
node::SetIsolateUpForNode(isolate, is);
|
||||
@@ -239,14 +239,8 @@ int NodeMain(int argc, char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(codebytere): we should try to handle this upstream.
|
||||
{
|
||||
v8::HandleScope scope(isolate);
|
||||
node::InternalCallbackScope callback_scope(
|
||||
env, v8::Object::New(isolate), {1, 0},
|
||||
node::InternalCallbackScope::kSkipAsyncHooks);
|
||||
node::LoadEnvironment(env);
|
||||
}
|
||||
v8::HandleScope scope(isolate);
|
||||
node::LoadEnvironment(env);
|
||||
|
||||
env->set_trace_sync_io(env->options()->trace_sync_io);
|
||||
|
||||
|
||||
@@ -99,13 +99,9 @@ BaseWindow::BaseWindow(v8::Isolate* isolate,
|
||||
window_->AddObserver(this);
|
||||
|
||||
#if defined(TOOLKIT_VIEWS)
|
||||
{
|
||||
v8::TryCatch try_catch(isolate);
|
||||
gin::Handle<NativeImage> icon;
|
||||
if (options.Get(options::kIcon, &icon) && !icon.IsEmpty())
|
||||
SetIcon(icon);
|
||||
if (try_catch.HasCaught())
|
||||
LOG(ERROR) << "Failed to convert NativeImage";
|
||||
v8::Local<v8::Value> icon;
|
||||
if (options.Get(options::kIcon, &icon)) {
|
||||
SetIcon(isolate, icon);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -759,6 +755,14 @@ void BaseWindow::AddBrowserView(v8::Local<v8::Value> value) {
|
||||
auto get_that_view = browser_views_.find(browser_view->ID());
|
||||
if (get_that_view == browser_views_.end()) {
|
||||
if (browser_view->web_contents()) {
|
||||
// If we're reparenting a BrowserView, ensure that it's detached from
|
||||
// its previous owner window.
|
||||
auto* owner_window = browser_view->web_contents()->owner_window();
|
||||
if (owner_window && owner_window != window_.get()) {
|
||||
owner_window->RemoveBrowserView(browser_view->view());
|
||||
browser_view->web_contents()->SetOwnerWindow(nullptr);
|
||||
}
|
||||
|
||||
window_->AddBrowserView(browser_view->view());
|
||||
browser_view->web_contents()->SetOwnerWindow(window_.get());
|
||||
}
|
||||
@@ -998,14 +1002,18 @@ bool BaseWindow::SetThumbarButtons(gin_helper::Arguments* args) {
|
||||
}
|
||||
|
||||
#if defined(TOOLKIT_VIEWS)
|
||||
void BaseWindow::SetIcon(gin::Handle<NativeImage> icon) {
|
||||
void BaseWindow::SetIcon(v8::Isolate* isolate, v8::Local<v8::Value> icon) {
|
||||
NativeImage* native_image = nullptr;
|
||||
if (!NativeImage::TryConvertNativeImage(isolate, icon, &native_image))
|
||||
return;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
static_cast<NativeWindowViews*>(window_.get())
|
||||
->SetIcon(icon->GetHICON(GetSystemMetrics(SM_CXSMICON)),
|
||||
icon->GetHICON(GetSystemMetrics(SM_CXICON)));
|
||||
->SetIcon(native_image->GetHICON(GetSystemMetrics(SM_CXSMICON)),
|
||||
native_image->GetHICON(GetSystemMetrics(SM_CXICON)));
|
||||
#elif defined(OS_LINUX)
|
||||
static_cast<NativeWindowViews*>(window_.get())
|
||||
->SetIcon(icon->image().AsImageSkia());
|
||||
->SetIcon(native_image->image().AsImageSkia());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -1071,9 +1079,14 @@ void BaseWindow::ResetBrowserViews() {
|
||||
v8::Local<v8::Value>::New(isolate(), item.second),
|
||||
&browser_view) &&
|
||||
!browser_view.IsEmpty()) {
|
||||
// There's a chance that the BrowserView may have been reparented - only
|
||||
// reset if the owner window is *this* window.
|
||||
if (browser_view->web_contents()) {
|
||||
window_->RemoveBrowserView(browser_view->view());
|
||||
browser_view->web_contents()->SetOwnerWindow(nullptr);
|
||||
auto* owner_window = browser_view->web_contents()->owner_window();
|
||||
if (owner_window == window_.get()) {
|
||||
browser_view->web_contents()->SetOwnerWindow(nullptr);
|
||||
owner_window->RemoveBrowserView(browser_view->view());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "shell/browser/native_window.h"
|
||||
#include "shell/browser/native_window_observer.h"
|
||||
#include "shell/common/api/electron_api_native_image.h"
|
||||
#include "shell/common/gin_helper/error_thrower.h"
|
||||
#include "shell/common/gin_helper/trackable_object.h"
|
||||
|
||||
namespace electron {
|
||||
@@ -221,7 +222,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
|
||||
// Extra APIs added in JS.
|
||||
bool SetThumbarButtons(gin_helper::Arguments* args);
|
||||
#if defined(TOOLKIT_VIEWS)
|
||||
void SetIcon(gin::Handle<NativeImage> icon);
|
||||
void SetIcon(v8::Isolate* isolate, v8::Local<v8::Value> icon);
|
||||
#endif
|
||||
#if defined(OS_WIN)
|
||||
typedef base::RepeatingCallback<void(v8::Local<v8::Value>,
|
||||
|
||||
@@ -78,8 +78,17 @@ BrowserView::BrowserView(gin::Arguments* args,
|
||||
gin::Dictionary::CreateEmpty(isolate);
|
||||
options.Get(options::kWebPreferences, &web_preferences);
|
||||
web_preferences.Set("type", "browserView");
|
||||
gin::Handle<class WebContents> web_contents =
|
||||
WebContents::New(isolate, web_preferences);
|
||||
|
||||
v8::Local<v8::Value> value;
|
||||
|
||||
// Copy the webContents option to webPreferences. This is only used internally
|
||||
// to implement nativeWindowOpen option.
|
||||
if (options.Get("webContents", &value)) {
|
||||
web_preferences.SetHidden("webContents", value);
|
||||
}
|
||||
|
||||
auto web_contents =
|
||||
WebContents::CreateFromWebPreferences(args->isolate(), web_preferences);
|
||||
|
||||
web_contents_.Reset(isolate, web_contents.ToV8());
|
||||
api_web_contents_ = web_contents.get();
|
||||
|
||||
@@ -309,10 +309,8 @@ void BrowserWindow::OnWindowResize() {
|
||||
if (!draggable_regions_.empty()) {
|
||||
UpdateDraggableRegions(draggable_regions_);
|
||||
} else {
|
||||
// Ensure draggable bounds are recalculated for BrowserViews if any exist.
|
||||
auto browser_views = window_->browser_views();
|
||||
for (NativeBrowserView* view : browser_views) {
|
||||
view->UpdateDraggableRegions(draggable_regions_);
|
||||
for (NativeBrowserView* view : window_->browser_views()) {
|
||||
view->UpdateDraggableRegions(view->GetDraggableRegions());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -71,25 +71,21 @@ void BrowserWindow::UpdateDraggableRegions(
|
||||
|
||||
// Draggable regions are implemented by having the whole web view draggable
|
||||
// and overlaying regions that are not draggable.
|
||||
if (&draggable_regions_ != ®ions) {
|
||||
draggable_regions_.clear();
|
||||
for (const auto& r : regions)
|
||||
draggable_regions_.push_back(r.Clone());
|
||||
}
|
||||
|
||||
auto browser_views = window_->browser_views();
|
||||
for (NativeBrowserView* view : browser_views) {
|
||||
view->UpdateDraggableRegions(draggable_regions_);
|
||||
}
|
||||
if (&draggable_regions_ != ®ions)
|
||||
draggable_regions_ = mojo::Clone(regions);
|
||||
|
||||
std::vector<gfx::Rect> drag_exclude_rects;
|
||||
if (regions.empty()) {
|
||||
drag_exclude_rects.push_back(gfx::Rect(0, 0, webViewWidth, webViewHeight));
|
||||
drag_exclude_rects.emplace_back(0, 0, webViewWidth, webViewHeight);
|
||||
} else {
|
||||
drag_exclude_rects = CalculateNonDraggableRegions(
|
||||
DraggableRegionsToSkRegion(regions), webViewWidth, webViewHeight);
|
||||
}
|
||||
|
||||
for (NativeBrowserView* view : window_->browser_views()) {
|
||||
view->UpdateDraggableRegions(drag_exclude_rects);
|
||||
}
|
||||
|
||||
// Create and add a ControlRegionView for each region that needs to be
|
||||
// excluded from the dragging.
|
||||
for (const auto& rect : drag_exclude_rects) {
|
||||
|
||||
@@ -66,15 +66,26 @@ base::Optional<base::FilePath> CreateTemporaryFileOnIO() {
|
||||
|
||||
void StopTracing(gin_helper::Promise<base::FilePath> promise,
|
||||
base::Optional<base::FilePath> file_path) {
|
||||
auto resolve_or_reject = base::AdaptCallbackForRepeating(base::BindOnce(
|
||||
[](gin_helper::Promise<base::FilePath> promise,
|
||||
const base::FilePath& path, base::Optional<std::string> error) {
|
||||
if (error) {
|
||||
promise.RejectWithErrorMessage(error.value());
|
||||
} else {
|
||||
promise.Resolve(path);
|
||||
}
|
||||
},
|
||||
std::move(promise), *file_path));
|
||||
if (file_path) {
|
||||
auto endpoint = TracingController::CreateFileEndpoint(
|
||||
*file_path, base::AdaptCallbackForRepeating(base::BindOnce(
|
||||
&gin_helper::Promise<base::FilePath>::ResolvePromise,
|
||||
std::move(promise), *file_path)));
|
||||
TracingController::GetInstance()->StopTracing(endpoint);
|
||||
*file_path, base::BindRepeating(resolve_or_reject, base::nullopt));
|
||||
if (!TracingController::GetInstance()->StopTracing(endpoint)) {
|
||||
resolve_or_reject.Run(base::make_optional(
|
||||
"Failed to stop tracing (was a trace in progress?)"));
|
||||
}
|
||||
} else {
|
||||
promise.RejectWithErrorMessage(
|
||||
"Failed to create temporary file for trace data");
|
||||
resolve_or_reject.Run(
|
||||
base::make_optional("Failed to create temporary file for trace data"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "gin/dictionary.h"
|
||||
#include "gin/object_template_builder.h"
|
||||
#include "shell/browser/api/electron_api_system_preferences.h"
|
||||
#include "shell/browser/browser.h"
|
||||
#include "shell/common/gin_converters/accelerator_converter.h"
|
||||
#include "shell/common/gin_converters/callback_converter.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
@@ -84,6 +85,11 @@ void GlobalShortcut::OnKeyPressed(const ui::Accelerator& accelerator) {
|
||||
bool GlobalShortcut::RegisterAll(
|
||||
const std::vector<ui::Accelerator>& accelerators,
|
||||
const base::Closure& callback) {
|
||||
if (!electron::Browser::Get()->is_ready()) {
|
||||
gin_helper::ErrorThrower(JavascriptEnvironment::GetIsolate())
|
||||
.ThrowError("globalShortcut cannot be used before the app is ready");
|
||||
return false;
|
||||
}
|
||||
std::vector<ui::Accelerator> registered;
|
||||
|
||||
for (auto& accelerator : accelerators) {
|
||||
@@ -100,6 +106,11 @@ bool GlobalShortcut::RegisterAll(
|
||||
|
||||
bool GlobalShortcut::Register(const ui::Accelerator& accelerator,
|
||||
const base::Closure& callback) {
|
||||
if (!electron::Browser::Get()->is_ready()) {
|
||||
gin_helper::ErrorThrower(JavascriptEnvironment::GetIsolate())
|
||||
.ThrowError("globalShortcut cannot be used before the app is ready");
|
||||
return false;
|
||||
}
|
||||
#if defined(OS_MAC)
|
||||
if (Command::IsMediaKey(accelerator)) {
|
||||
if (RegisteringMediaKeyForUntrustedClient(accelerator))
|
||||
@@ -119,6 +130,11 @@ bool GlobalShortcut::Register(const ui::Accelerator& accelerator,
|
||||
}
|
||||
|
||||
void GlobalShortcut::Unregister(const ui::Accelerator& accelerator) {
|
||||
if (!electron::Browser::Get()->is_ready()) {
|
||||
gin_helper::ErrorThrower(JavascriptEnvironment::GetIsolate())
|
||||
.ThrowError("globalShortcut cannot be used before the app is ready");
|
||||
return;
|
||||
}
|
||||
if (accelerator_callback_map_.erase(accelerator) == 0)
|
||||
return;
|
||||
|
||||
@@ -145,6 +161,11 @@ bool GlobalShortcut::IsRegistered(const ui::Accelerator& accelerator) {
|
||||
}
|
||||
|
||||
void GlobalShortcut::UnregisterAll() {
|
||||
if (!electron::Browser::Get()->is_ready()) {
|
||||
gin_helper::ErrorThrower(JavascriptEnvironment::GetIsolate())
|
||||
.ThrowError("globalShortcut cannot be used before the app is ready");
|
||||
return;
|
||||
}
|
||||
accelerator_callback_map_.clear();
|
||||
GlobalShortcutListener::GetInstance()->UnregisterAccelerators(this);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,9 @@ printing::PrinterList GetPrinterList() {
|
||||
|
||||
namespace {
|
||||
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
using electron::api::GetPrinterList;
|
||||
#endif
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
v8::Local<v8::Value> unused,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "shell/browser/browser.h"
|
||||
#include "shell/browser/javascript_environment.h"
|
||||
#include "shell/common/api/electron_api_native_image.h"
|
||||
#include "shell/common/gin_converters/file_path_converter.h"
|
||||
#include "shell/common/gin_converters/gfx_converter.h"
|
||||
#include "shell/common/gin_converters/guid_converter.h"
|
||||
#include "shell/common/gin_converters/image_converter.h"
|
||||
@@ -61,11 +62,11 @@ namespace api {
|
||||
|
||||
gin::WrapperInfo Tray::kWrapperInfo = {gin::kEmbedderNativeGin};
|
||||
|
||||
Tray::Tray(gin::Handle<NativeImage> image,
|
||||
base::Optional<UUID> guid,
|
||||
gin::Arguments* args)
|
||||
Tray::Tray(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> image,
|
||||
base::Optional<UUID> guid)
|
||||
: tray_icon_(TrayIcon::Create(guid)) {
|
||||
SetImage(image);
|
||||
SetImage(isolate, image);
|
||||
tray_icon_->AddObserver(this);
|
||||
}
|
||||
|
||||
@@ -73,7 +74,7 @@ Tray::~Tray() = default;
|
||||
|
||||
// static
|
||||
gin::Handle<Tray> Tray::New(gin_helper::ErrorThrower thrower,
|
||||
gin::Handle<NativeImage> image,
|
||||
v8::Local<v8::Value> image,
|
||||
base::Optional<UUID> guid,
|
||||
gin::Arguments* args) {
|
||||
if (!Browser::Get()->is_ready()) {
|
||||
@@ -88,7 +89,8 @@ gin::Handle<Tray> Tray::New(gin_helper::ErrorThrower thrower,
|
||||
}
|
||||
#endif
|
||||
|
||||
return gin::CreateHandle(thrower.isolate(), new Tray(image, guid, args));
|
||||
return gin::CreateHandle(thrower.isolate(),
|
||||
new Tray(args->isolate(), image, guid));
|
||||
}
|
||||
|
||||
void Tray::OnClicked(const gfx::Rect& bounds,
|
||||
@@ -186,23 +188,34 @@ bool Tray::IsDestroyed() {
|
||||
return !tray_icon_;
|
||||
}
|
||||
|
||||
void Tray::SetImage(gin::Handle<NativeImage> image) {
|
||||
void Tray::SetImage(v8::Isolate* isolate, v8::Local<v8::Value> image) {
|
||||
if (!CheckAlive())
|
||||
return;
|
||||
|
||||
NativeImage* native_image = nullptr;
|
||||
if (!NativeImage::TryConvertNativeImage(isolate, image, &native_image))
|
||||
return;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
tray_icon_->SetImage(image->GetHICON(GetSystemMetrics(SM_CXSMICON)));
|
||||
tray_icon_->SetImage(native_image->GetHICON(GetSystemMetrics(SM_CXSMICON)));
|
||||
#else
|
||||
tray_icon_->SetImage(image->image());
|
||||
tray_icon_->SetImage(native_image->image());
|
||||
#endif
|
||||
}
|
||||
|
||||
void Tray::SetPressedImage(gin::Handle<NativeImage> image) {
|
||||
void Tray::SetPressedImage(v8::Isolate* isolate, v8::Local<v8::Value> image) {
|
||||
if (!CheckAlive())
|
||||
return;
|
||||
|
||||
NativeImage* native_image = nullptr;
|
||||
if (!NativeImage::TryConvertNativeImage(isolate, image, &native_image))
|
||||
return;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
tray_icon_->SetPressedImage(image->GetHICON(GetSystemMetrics(SM_CXSMICON)));
|
||||
tray_icon_->SetPressedImage(
|
||||
native_image->GetHICON(GetSystemMetrics(SM_CXSMICON)));
|
||||
#else
|
||||
tray_icon_->SetPressedImage(image->image());
|
||||
tray_icon_->SetPressedImage(native_image->image());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -282,14 +295,20 @@ void Tray::DisplayBalloon(gin_helper::ErrorThrower thrower,
|
||||
return;
|
||||
}
|
||||
|
||||
gin::Handle<NativeImage> icon;
|
||||
options.Get("icon", &icon);
|
||||
v8::Local<v8::Value> icon_value;
|
||||
NativeImage* icon = nullptr;
|
||||
if (options.Get("icon", &icon_value) &&
|
||||
!NativeImage::TryConvertNativeImage(thrower.isolate(), icon_value,
|
||||
&icon)) {
|
||||
return;
|
||||
}
|
||||
|
||||
options.Get("iconType", &balloon_options.icon_type);
|
||||
options.Get("largeIcon", &balloon_options.large_icon);
|
||||
options.Get("noSound", &balloon_options.no_sound);
|
||||
options.Get("respectQuietTime", &balloon_options.respect_quiet_time);
|
||||
|
||||
if (!icon.IsEmpty()) {
|
||||
if (icon) {
|
||||
#if defined(OS_WIN)
|
||||
balloon_options.icon = icon->GetHICON(
|
||||
GetSystemMetrics(balloon_options.large_icon ? SM_CXICON : SM_CXSMICON));
|
||||
|
||||
@@ -43,7 +43,7 @@ class Tray : public gin::Wrappable<Tray>,
|
||||
public:
|
||||
// gin_helper::Constructible
|
||||
static gin::Handle<Tray> New(gin_helper::ErrorThrower thrower,
|
||||
gin::Handle<NativeImage> image,
|
||||
v8::Local<v8::Value> image,
|
||||
base::Optional<UUID> guid,
|
||||
gin::Arguments* args);
|
||||
static v8::Local<v8::ObjectTemplate> FillObjectTemplate(
|
||||
@@ -54,9 +54,9 @@ class Tray : public gin::Wrappable<Tray>,
|
||||
static gin::WrapperInfo kWrapperInfo;
|
||||
|
||||
private:
|
||||
Tray(gin::Handle<NativeImage> image,
|
||||
base::Optional<UUID> guid,
|
||||
gin::Arguments* args);
|
||||
Tray(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> image,
|
||||
base::Optional<UUID> guid);
|
||||
~Tray() override;
|
||||
|
||||
// TrayIconObserver:
|
||||
@@ -83,8 +83,8 @@ class Tray : public gin::Wrappable<Tray>,
|
||||
// JS API:
|
||||
void Destroy();
|
||||
bool IsDestroyed();
|
||||
void SetImage(gin::Handle<NativeImage> image);
|
||||
void SetPressedImage(gin::Handle<NativeImage> image);
|
||||
void SetImage(v8::Isolate* isolate, v8::Local<v8::Value> image);
|
||||
void SetPressedImage(v8::Isolate* isolate, v8::Local<v8::Value> image);
|
||||
void SetToolTip(const std::string& tool_tip);
|
||||
void SetTitle(const std::string& title,
|
||||
const base::Optional<gin_helper::Dictionary>& options,
|
||||
|
||||
@@ -1447,12 +1447,12 @@ void WebContents::DidStartLoading() {
|
||||
}
|
||||
|
||||
void WebContents::DidStopLoading() {
|
||||
Emit("did-stop-loading");
|
||||
|
||||
auto* web_preferences = WebContentsPreferences::From(web_contents());
|
||||
if (web_preferences &&
|
||||
web_preferences->IsEnabled(options::kEnablePreferredSizeMode))
|
||||
web_contents()->GetRenderViewHost()->EnablePreferredSizeMode();
|
||||
|
||||
Emit("did-stop-loading");
|
||||
}
|
||||
|
||||
bool WebContents::EmitNavigationEvent(
|
||||
@@ -2726,7 +2726,7 @@ bool WebContents::SendIPCMessageWithSender(bool internal,
|
||||
|
||||
bool WebContents::SendIPCMessageToFrame(bool internal,
|
||||
bool send_to_all,
|
||||
int32_t frame_id,
|
||||
v8::Local<v8::Value> frame,
|
||||
const std::string& channel,
|
||||
v8::Local<v8::Value> args) {
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
@@ -2736,17 +2736,30 @@ bool WebContents::SendIPCMessageToFrame(bool internal,
|
||||
gin::StringToV8(isolate, "Failed to serialize arguments")));
|
||||
return false;
|
||||
}
|
||||
auto frames = web_contents()->GetAllFrames();
|
||||
auto iter = std::find_if(frames.begin(), frames.end(), [frame_id](auto* f) {
|
||||
return f->GetRoutingID() == frame_id;
|
||||
});
|
||||
if (iter == frames.end())
|
||||
return false;
|
||||
if (!(*iter)->IsRenderFrameLive())
|
||||
int32_t frame_id;
|
||||
int32_t process_id;
|
||||
if (gin::ConvertFromV8(isolate, frame, &frame_id)) {
|
||||
process_id = web_contents()->GetMainFrame()->GetProcess()->GetID();
|
||||
} else {
|
||||
std::vector<int32_t> id_pair;
|
||||
if (gin::ConvertFromV8(isolate, frame, &id_pair) && id_pair.size() == 2) {
|
||||
process_id = id_pair[0];
|
||||
frame_id = id_pair[1];
|
||||
} else {
|
||||
isolate->ThrowException(v8::Exception::Error(gin::StringToV8(
|
||||
isolate,
|
||||
"frameId must be a number or a pair of [processId, frameId]")));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto* rfh = content::RenderFrameHost::FromID(process_id, frame_id);
|
||||
if (!rfh || !rfh->IsRenderFrameLive() ||
|
||||
content::WebContents::FromRenderFrameHost(rfh) != web_contents())
|
||||
return false;
|
||||
|
||||
mojo::AssociatedRemote<mojom::ElectronRenderer> electron_renderer;
|
||||
(*iter)->GetRemoteAssociatedInterfaces()->GetInterface(&electron_renderer);
|
||||
rfh->GetRemoteAssociatedInterfaces()->GetInterface(&electron_renderer);
|
||||
electron_renderer->Message(internal, send_to_all, channel, std::move(message),
|
||||
0 /* sender_id */);
|
||||
return true;
|
||||
@@ -2846,10 +2859,16 @@ void WebContents::StartDrag(const gin_helper::Dictionary& item,
|
||||
files.push_back(file);
|
||||
}
|
||||
|
||||
gin::Handle<NativeImage> icon;
|
||||
if (!item.Get("icon", &icon) || icon->image().IsEmpty()) {
|
||||
v8::Local<v8::Value> icon_value;
|
||||
if (!item.Get("icon", &icon_value)) {
|
||||
gin_helper::ErrorThrower(args->isolate())
|
||||
.ThrowError("Must specify non-empty 'icon' option");
|
||||
.ThrowError("'icon' parameter is required");
|
||||
return;
|
||||
}
|
||||
|
||||
NativeImage* icon = nullptr;
|
||||
if (!NativeImage::TryConvertNativeImage(args->isolate(), icon_value, &icon) ||
|
||||
icon->image().IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3764,6 +3783,33 @@ gin::Handle<WebContents> WebContents::FromOrCreate(
|
||||
return gin::CreateHandle(isolate, api_web_contents);
|
||||
}
|
||||
|
||||
// static
|
||||
gin::Handle<WebContents> WebContents::CreateFromWebPreferences(
|
||||
v8::Isolate* isolate,
|
||||
const gin_helper::Dictionary& web_preferences) {
|
||||
// Check if webPreferences has |webContents| option.
|
||||
gin::Handle<WebContents> web_contents;
|
||||
if (web_preferences.GetHidden("webContents", &web_contents) &&
|
||||
!web_contents.IsEmpty()) {
|
||||
// Set webPreferences from options if using an existing webContents.
|
||||
// These preferences will be used when the webContent launches new
|
||||
// render processes.
|
||||
auto* existing_preferences =
|
||||
WebContentsPreferences::From(web_contents->web_contents());
|
||||
base::DictionaryValue web_preferences_dict;
|
||||
if (gin::ConvertFromV8(isolate, web_preferences.GetHandle(),
|
||||
&web_preferences_dict)) {
|
||||
existing_preferences->Clear();
|
||||
existing_preferences->Merge(web_preferences_dict);
|
||||
}
|
||||
} else {
|
||||
// Create one if not.
|
||||
web_contents = WebContents::New(isolate, web_preferences);
|
||||
}
|
||||
|
||||
return web_contents;
|
||||
}
|
||||
|
||||
// static
|
||||
WebContents* WebContents::FromID(int32_t id) {
|
||||
return GetAllWebContents().Lookup(id);
|
||||
@@ -3781,6 +3827,12 @@ namespace {
|
||||
using electron::api::GetAllWebContents;
|
||||
using electron::api::WebContents;
|
||||
|
||||
gin::Handle<WebContents> WebContentsFromID(v8::Isolate* isolate, int32_t id) {
|
||||
WebContents* contents = WebContents::FromID(id);
|
||||
return contents ? gin::CreateHandle(isolate, contents)
|
||||
: gin::Handle<WebContents>();
|
||||
}
|
||||
|
||||
std::vector<gin::Handle<WebContents>> GetAllWebContentsAsV8(
|
||||
v8::Isolate* isolate) {
|
||||
std::vector<gin::Handle<WebContents>> list;
|
||||
@@ -3798,7 +3850,7 @@ void Initialize(v8::Local<v8::Object> exports,
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
gin_helper::Dictionary dict(isolate, exports);
|
||||
dict.Set("WebContents", WebContents::GetConstructor(context));
|
||||
dict.SetMethod("fromId", &WebContents::FromID);
|
||||
dict.SetMethod("fromId", &WebContentsFromID);
|
||||
dict.SetMethod("getAllWebContents", &GetAllWebContentsAsV8);
|
||||
}
|
||||
|
||||
|
||||
@@ -135,6 +135,10 @@ class WebContents : public gin::Wrappable<WebContents>,
|
||||
v8::Isolate* isolate,
|
||||
content::WebContents* web_contents);
|
||||
|
||||
static gin::Handle<WebContents> CreateFromWebPreferences(
|
||||
v8::Isolate* isolate,
|
||||
const gin_helper::Dictionary& web_preferences);
|
||||
|
||||
// gin::Wrappable
|
||||
static gin::WrapperInfo kWrapperInfo;
|
||||
static v8::Local<v8::ObjectTemplate> FillObjectTemplate(
|
||||
@@ -261,7 +265,7 @@ class WebContents : public gin::Wrappable<WebContents>,
|
||||
|
||||
bool SendIPCMessageToFrame(bool internal,
|
||||
bool send_to_all,
|
||||
int32_t frame_id,
|
||||
v8::Local<v8::Value> frame,
|
||||
const std::string& channel,
|
||||
v8::Local<v8::Value> args);
|
||||
|
||||
|
||||
@@ -97,25 +97,9 @@ v8::Local<v8::Function> WebContentsView::GetConstructor(v8::Isolate* isolate) {
|
||||
gin_helper::WrappableBase* WebContentsView::New(
|
||||
gin_helper::Arguments* args,
|
||||
const gin_helper::Dictionary& web_preferences) {
|
||||
// Check if BrowserWindow has passend |webContents| option to us.
|
||||
gin::Handle<WebContents> web_contents;
|
||||
if (web_preferences.GetHidden("webContents", &web_contents) &&
|
||||
!web_contents.IsEmpty()) {
|
||||
// Set webPreferences from options if using an existing webContents.
|
||||
// These preferences will be used when the webContent launches new
|
||||
// render processes.
|
||||
auto* existing_preferences =
|
||||
WebContentsPreferences::From(web_contents->web_contents());
|
||||
base::DictionaryValue web_preferences_dict;
|
||||
if (gin::ConvertFromV8(args->isolate(), web_preferences.GetHandle(),
|
||||
&web_preferences_dict)) {
|
||||
existing_preferences->Clear();
|
||||
existing_preferences->Merge(web_preferences_dict);
|
||||
}
|
||||
} else {
|
||||
// Create one if not.
|
||||
web_contents = WebContents::New(args->isolate(), web_preferences);
|
||||
}
|
||||
auto web_contents =
|
||||
WebContents::CreateFromWebPreferences(args->isolate(), web_preferences);
|
||||
|
||||
// Constructor call.
|
||||
auto* view = new WebContentsView(args->isolate(), web_contents);
|
||||
view->InitWithArgs(args);
|
||||
|
||||
@@ -108,6 +108,49 @@ v8::Local<v8::Promise> WebFrameMain::ExecuteJavaScript(
|
||||
return handle;
|
||||
}
|
||||
|
||||
v8::Local<v8::Promise> WebFrameMain::ExecuteJavaScriptInIsolatedWorld(
|
||||
gin::Arguments* args,
|
||||
int world_id,
|
||||
const base::string16& code) {
|
||||
gin_helper::Promise<base::Value> promise(args->isolate());
|
||||
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||
|
||||
// Optional userGesture parameter
|
||||
bool user_gesture;
|
||||
if (!args->PeekNext().IsEmpty()) {
|
||||
if (args->PeekNext()->IsBoolean()) {
|
||||
args->GetNext(&user_gesture);
|
||||
} else {
|
||||
args->ThrowTypeError("userGesture must be a boolean");
|
||||
return handle;
|
||||
}
|
||||
} else {
|
||||
user_gesture = false;
|
||||
}
|
||||
|
||||
if (render_frame_disposed_) {
|
||||
promise.RejectWithErrorMessage(
|
||||
"Render frame was disposed before WebFrameMain could be accessed");
|
||||
return handle;
|
||||
}
|
||||
|
||||
if (user_gesture) {
|
||||
auto* ftn = content::FrameTreeNode::From(render_frame_);
|
||||
ftn->UpdateUserActivationState(
|
||||
blink::mojom::UserActivationUpdateType::kNotifyActivation,
|
||||
blink::mojom::UserActivationNotificationType::kTest);
|
||||
}
|
||||
|
||||
render_frame_->ExecuteJavaScriptForTests(
|
||||
code,
|
||||
base::BindOnce([](gin_helper::Promise<base::Value> promise,
|
||||
base::Value value) { promise.Resolve(value); },
|
||||
std::move(promise)),
|
||||
world_id);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
bool WebFrameMain::Reload(v8::Isolate* isolate) {
|
||||
if (!CheckRenderFrame())
|
||||
return false;
|
||||
@@ -222,6 +265,8 @@ gin::ObjectTemplateBuilder WebFrameMain::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return gin::Wrappable<WebFrameMain>::GetObjectTemplateBuilder(isolate)
|
||||
.SetMethod("executeJavaScript", &WebFrameMain::ExecuteJavaScript)
|
||||
.SetMethod("executeJavaScriptInIsolatedWorld",
|
||||
&WebFrameMain::ExecuteJavaScriptInIsolatedWorld)
|
||||
.SetMethod("reload", &WebFrameMain::Reload)
|
||||
.SetProperty("frameTreeNodeId", &WebFrameMain::FrameTreeNodeID)
|
||||
.SetProperty("name", &WebFrameMain::Name)
|
||||
|
||||
@@ -66,6 +66,10 @@ class WebFrameMain : public gin::Wrappable<WebFrameMain> {
|
||||
|
||||
v8::Local<v8::Promise> ExecuteJavaScript(gin::Arguments* args,
|
||||
const base::string16& code);
|
||||
v8::Local<v8::Promise> ExecuteJavaScriptInIsolatedWorld(
|
||||
gin::Arguments* args,
|
||||
int world_id,
|
||||
const base::string16& code);
|
||||
bool Reload(v8::Isolate* isolate);
|
||||
|
||||
int FrameTreeNodeID(v8::Isolate* isolate) const;
|
||||
|
||||
@@ -21,11 +21,15 @@ Event::Event() {}
|
||||
Event::~Event() {
|
||||
if (callback_) {
|
||||
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto message = gin::DataObjectBuilder(isolate)
|
||||
.Set("error", "reply was never sent")
|
||||
.Build();
|
||||
SendReply(isolate, message);
|
||||
// If there's no current context, it means we're shutting down, so we don't
|
||||
// need to send an event.
|
||||
if (!isolate->GetCurrentContext().IsEmpty()) {
|
||||
v8::HandleScope scope(isolate);
|
||||
auto message = gin::DataObjectBuilder(isolate)
|
||||
.Set("error", "reply was never sent")
|
||||
.Build();
|
||||
SendReply(isolate, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +66,7 @@ gin::ObjectTemplateBuilder Event::GetObjectTemplateBuilder(
|
||||
}
|
||||
|
||||
const char* Event::GetTypeName() {
|
||||
return "WebRequest";
|
||||
return "Event";
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -223,7 +223,7 @@ class Browser : public WindowListObserver {
|
||||
void DockSetMenu(ElectronMenuModel* model);
|
||||
|
||||
// Set docks' icon.
|
||||
void DockSetIcon(const gfx::Image& image);
|
||||
void DockSetIcon(v8::Isolate* isolate, v8::Local<v8::Value> icon);
|
||||
|
||||
#endif // defined(OS_MAC)
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "shell/browser/mac/electron_application_delegate.h"
|
||||
#include "shell/browser/native_window.h"
|
||||
#include "shell/browser/window_list.h"
|
||||
#include "shell/common/api/electron_api_native_image.h"
|
||||
#include "shell/common/application_info.h"
|
||||
#include "shell/common/gin_converters/image_converter.h"
|
||||
#include "shell/common/gin_helper/arguments.h"
|
||||
@@ -451,7 +452,16 @@ void Browser::DockSetMenu(ElectronMenuModel* model) {
|
||||
[delegate setApplicationDockMenu:model];
|
||||
}
|
||||
|
||||
void Browser::DockSetIcon(const gfx::Image& image) {
|
||||
void Browser::DockSetIcon(v8::Isolate* isolate, v8::Local<v8::Value> icon) {
|
||||
gfx::Image image;
|
||||
|
||||
if (!icon->IsNull()) {
|
||||
api::NativeImage* native_image = nullptr;
|
||||
if (!api::NativeImage::TryConvertNativeImage(isolate, icon, &native_image))
|
||||
return;
|
||||
image = native_image->image();
|
||||
}
|
||||
|
||||
[[AtomApplication sharedApplication]
|
||||
setApplicationIconImage:image.AsNSImage()];
|
||||
}
|
||||
|
||||
@@ -137,6 +137,7 @@
|
||||
#include "content/public/browser/file_url_loader.h"
|
||||
#include "content/public/browser/web_ui_url_loader_factory.h"
|
||||
#include "extensions/browser/api/mime_handler_private/mime_handler_private.h"
|
||||
#include "extensions/browser/api/web_request/web_request_api.h"
|
||||
#include "extensions/browser/browser_context_keyed_api_factory.h"
|
||||
#include "extensions/browser/extension_host.h"
|
||||
#include "extensions/browser/extension_message_filter.h"
|
||||
@@ -1449,7 +1450,17 @@ bool ElectronBrowserClient::WillInterceptWebSocket(
|
||||
if (!web_request.get())
|
||||
return false;
|
||||
|
||||
return web_request->HasListener();
|
||||
bool has_listener = web_request->HasListener();
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
const auto* web_request_api =
|
||||
extensions::BrowserContextKeyedAPIFactory<extensions::WebRequestAPI>::Get(
|
||||
browser_context);
|
||||
|
||||
if (web_request_api)
|
||||
has_listener |= web_request_api->MayHaveProxies();
|
||||
#endif
|
||||
|
||||
return has_listener;
|
||||
}
|
||||
|
||||
void ElectronBrowserClient::CreateWebSocket(
|
||||
@@ -1463,8 +1474,24 @@ void ElectronBrowserClient::CreateWebSocket(
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto* browser_context = frame->GetProcess()->GetBrowserContext();
|
||||
|
||||
auto web_request = api::WebRequest::FromOrCreate(isolate, browser_context);
|
||||
DCHECK(web_request.get());
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
if (!web_request->HasListener()) {
|
||||
auto* web_request_api = extensions::BrowserContextKeyedAPIFactory<
|
||||
extensions::WebRequestAPI>::Get(browser_context);
|
||||
|
||||
if (web_request_api && web_request_api->MayHaveProxies()) {
|
||||
web_request_api->ProxyWebSocket(frame, std::move(factory), url,
|
||||
site_for_cookies.RepresentativeUrl(),
|
||||
user_agent, std::move(handshake_client));
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ProxyingWebSocket::StartProxying(
|
||||
web_request.get(), std::move(factory), url,
|
||||
site_for_cookies.RepresentativeUrl(), user_agent,
|
||||
@@ -1492,6 +1519,24 @@ bool ElectronBrowserClient::WillCreateURLLoaderFactory(
|
||||
auto web_request = api::WebRequest::FromOrCreate(isolate, browser_context);
|
||||
DCHECK(web_request.get());
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
if (!web_request->HasListener()) {
|
||||
auto* web_request_api = extensions::BrowserContextKeyedAPIFactory<
|
||||
extensions::WebRequestAPI>::Get(browser_context);
|
||||
|
||||
DCHECK(web_request_api);
|
||||
bool use_proxy_for_web_request =
|
||||
web_request_api->MaybeProxyURLLoaderFactory(
|
||||
browser_context, frame_host, render_process_id, type, navigation_id,
|
||||
ukm_source_id, factory_receiver, header_client);
|
||||
|
||||
if (bypass_redirect_checks)
|
||||
*bypass_redirect_checks = use_proxy_for_web_request;
|
||||
if (use_proxy_for_web_request)
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto proxied_receiver = std::move(*factory_receiver);
|
||||
mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory_remote;
|
||||
*factory_receiver = target_factory_remote.InitWithNewPipeAndPassReceiver();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user