Compare commits

...

51 Commits

Author SHA1 Message Date
Electron Bot
e6885668d4 Bump v12.0.0-beta.11 2020-12-17 07:01:35 -08:00
trop[bot]
a1df860b66 refactor: remove last use of InternalCallbackScope (#27049)
* refactor: remove last use of InternalCallbackScope

* update patches

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: Electron Bot <electron@github.com>
2020-12-17 20:29:43 +09:00
trop[bot]
ba76f6846e fix: memory leak in desktopCapturer.getSources (#27058)
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2020-12-16 20:47:42 -08:00
trop[bot]
ce8d301921 fix: throw when using globalShortcut before ready (#27022)
* fix: throw when using globalShortcut before ready

* fix

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2020-12-17 10:06:32 +09:00
trop[bot]
39f865e4e3 fix: make protocol wrapper remote-friendly again (#27043)
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2020-12-16 12:10:41 -08:00
trop[bot]
e6727fb7bd fix: crash on exit in Event destructor (#27034)
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2020-12-16 17:29:04 +09:00
trop[bot]
c9564ff648 refactor: use public node::CallbackScope where possible (#27028)
* refactor: use public node::CallbackScope where possible

* Remove unused node_env() getter

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2020-12-15 16:36:51 -08:00
trop[bot]
76be3b9211 fix(asar): readdir(withFileTypes) fails on deep directory when using readdirSync on a deep directory within the archive, the code fails to get the stats of child paths. (#27011)
Co-authored-by: Avi Vahl <avi.vahl@wix.com>
2020-12-16 08:42:32 +09:00
trop[bot]
d132800944 ci: ignore failures on Ninja summary (#26994)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2020-12-15 13:50:54 -08:00
trop[bot]
558bcc65bc fix: window with CustomButtonsOnHover should have rounded corner (#26960)
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2020-12-15 10:06:43 +09:00
trop[bot]
bf25d484a4 fix: add SafeForTerminationScopes for SIGINT interruptions (#26971)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2020-12-14 16:44:16 -08:00
Shelley Vohr
d2c4b594bd fix: screen EventEmitter methods with remote (#26988) 2020-12-14 11:51:20 -08:00
trop[bot]
601af0b016 fix: properly emit after hooks after exception (#26990)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2020-12-14 10:25:32 -08:00
trop[bot]
130a65d008 fix: Update Squirrel.mac to fix permissions bug. (#26968)
* fix: Update Squirrel.mac to fix permissions bug.

* Update patches.

Co-authored-by: Devin Foley <dfoley@slack-corp.com>
2020-12-14 08:23:15 -08:00
trop[bot]
fe022df628 fix: stack traces in non-Node.js contexts (#26912)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2020-12-14 11:19:37 -05:00
Electron Bot
5b47fd7cbf Bump v12.0.0-beta.10 2020-12-14 07:02:28 -08:00
Electron Bot
9b1913b613 Bump v12.0.0-beta.9 2020-12-11 13:02:55 -08:00
Jeremy Rose
36c695ce2a fix: restrict sendToFrame to same-process frames by default (#26875) (#26925) 2020-12-11 13:00:17 -08:00
trop[bot]
afcdf661a0 fix: Upload all *.dll.pdb to symbol server (#26966)
Fixes #26961.

Notes: Add Electron DLLs like libGLESv2.dll to symbol server

Co-authored-by: Biru Mohanathas <birunthan@mohanathas.com>
2020-12-11 12:53:54 -08:00
trop[bot]
3d01b83daa fix: Avoid crashing in NativeViewHost::SetParentAccessible on Windows (#26952)
This fixes #26905. The patch was obtained from @deepak1556, who in turn
got it from the Microsoft Teams folks.

I believe the crash started happening due to the changes in
5c6c8e994b%5E!/#F15

This affects Electron 9 and later.

Notes: Fix occasional crash on Windows

Co-authored-by: Biru Mohanathas <birunthan@mohanathas.com>
2020-12-11 12:52:33 -08:00
trop[bot]
e77d9ff3b9 docs: add missing deprecated systemPreferences APIs to breaking-changes (#26937)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2020-12-11 11:00:53 -08:00
trop[bot]
fb35356b47 fix: message box missing an "OK" button in GTK (#26917)
Co-authored-by: Mimi <1119186082@qq.com>
2020-12-10 13:06:29 -08:00
Electron Bot
37d21bb80e Bump v12.0.0-beta.8 2020-12-10 07:01:47 -08:00
trop[bot]
e84539f2e0 fix: systemPreferences.effectiveAppearance returning systemPreferences.getAppLevelAppearance() (#26879)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2020-12-09 14:58:52 +09:00
trop[bot]
d2591ed4f8 fix: handle security warnings promise when JS is disabled (#26869)
Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
2020-12-07 13:03:48 -08:00
trop[bot]
6b54fe37de fix: add a "set" trap to the "screen" module proxy (#26868)
* fix: add a "set" trap to the "screen" module proxy

* fixup! fix: add a "set" trap to the "screen" module proxy

Co-authored-by: Aleksei Kuzmin <alkuzmin@microsoft.com>
2020-12-07 10:52:51 -08:00
Electron Bot
561fe63813 Bump v12.0.0-beta.7 2020-12-07 07:00:58 -08:00
trop[bot]
9543f8b30a fix: send IPC_MESSAGES.RENDERER_RELEASE_CALLBACK as internal message (#26833)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2020-12-04 13:36:27 -08:00
Electron Bot
cec2c73733 Bump v12.0.0-beta.6 2020-12-03 07:01:08 -08:00
Erick Zhao
2e9305d964 docs: added fiddle support for code samples (#26767)
Co-authored-by: Antonio <bandantonio@users.noreply.github.com>
2020-12-03 15:54:43 +09:00
trop[bot]
0491cc6906 docs: fix contentTracing code sample (#26778)
According to the API docs, the property is called included_categories, not include_categories.

Co-authored-by: Jim Fisher <jameshfisher@gmail.com>
2020-12-02 14:29:54 -05:00
trop[bot]
badcdd6566 fix: draggable views on BrowserViews on Windows (#26775) 2020-12-01 21:34:52 -08:00
trop[bot]
a0d0bd60a5 docs: BrowserWindow extension APIs are deprecated in Electron 9 (#26783)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2020-12-01 21:31:36 -08:00
Vadim
c0f0a02419 fix: internalModuleReadJSON for unpacked JSON (#26750) 2020-12-01 18:21:28 -06:00
Michaela Laurencin
8046f0560a fix: add check in IsMaximized for non-WS_THICKFRAME windows (#26772) 2020-12-01 18:20:24 -06:00
trop[bot]
2a8961b52f fix: Add default Bluetooth permission strings (#26769)
Co-authored-by: PalmerAL <PalmerAL@users.noreply.github.com>
2020-12-01 15:02:12 -08:00
trop[bot]
36163af228 fix: draggable regions calculation in BrowserWindow/BrowserView (#26755)
* fix: draggable regions calculation in bw/bv

* Address review feedback

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2020-12-01 15:37:16 -06:00
trop[bot]
29f42e943e build: use all-for-one goma (#26741)
* Revert "Revert "build: use one-for-all goma (#26679)" (#26689)"

This reverts commit 38ab829ea6.

* build: ensure file descriptor limit is higher on macOS

Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
2020-11-30 14:25:38 -08:00
Electron Bot
4597cb6499 Bump v12.0.0-beta.5 2020-11-30 07:02:00 -08:00
trop[bot]
4ba78b81c1 fix: uaf in WebContents::DidStopLoading (#26733)
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2020-11-30 19:30:26 +09:00
trop[bot]
80e0473649 chore: remove deprecated crashReporter APIs (#26709)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2020-11-30 16:54:17 +09:00
Electron Bot
db0d4c8224 Bump v12.0.0-beta.4 2020-11-26 07:01:59 -08:00
trop[bot]
4fbb58020c fix: make screen wrapper remote-friendly again (#26661)
This restores accessibility of screen methods via remote.screen.

Fixes #26610.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>

Co-authored-by: Anders Kaseorg <andersk@mit.edu>
2020-11-24 16:19:41 -05:00
trop[bot]
c9801ab5a5 fix: segfault on webContents.fromId(xxx) (#26651)
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2020-11-24 16:12:53 -05:00
Jeremy Rose
46441c1bd7 chore: cherry-pick 47e21abe349a from chromium (#26653)
* chore: cherry-pick 47e21abe349a from chromium

* update patches

Co-authored-by: Electron Bot <electron@github.com>
2020-11-23 17:17:06 -05:00
trop[bot]
1cac3354e7 fix: reject contentTracing.stopRecording on failure (#26656)
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2020-11-23 12:20:42 -08:00
trop[bot]
57c69ab3ac build: fix build with enable_printing=false (#26600)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2020-11-23 14:11:56 -05:00
Electron Bot
39b9c40a05 Bump v12.0.0-beta.3 2020-11-23 07:01:30 -08:00
trop[bot]
66a22a28a5 docs: fix relative link (#26601)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2020-11-19 12:41:26 -05:00
Electron Bot
17a8b7724b Bump v12.0.0-beta.2 2020-11-19 07:01:18 -08:00
Electron Bot
c512995426 Bump v12.0.0-beta.1 2020-11-18 14:04:12 -08:00
111 changed files with 2158 additions and 308 deletions

View File

@@ -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
@@ -893,6 +893,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

2
DEPS
View File

@@ -20,7 +20,7 @@ vars = {
'nan_version':
'2c4ee8a32a299eada3cd6e468bbd0a473bfea96d',
'squirrel.mac_version':
'a3a5b3f03b824441c014893b18f99a103b2603e9',
'cdc0729c8bf8576bfef18629186e1e9ecf1b0d9f',
'pyyaml_version': '3.12',
'requests_version': 'e4d59bedfd3c7f4f254f4f5d036587bcd8152458',

View File

@@ -1 +1 @@
12.0.0-nightly.20201118
12.0.0-beta.11

View File

@@ -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 ..

View File

@@ -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))

View File

@@ -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)`

View File

@@ -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

View File

@@ -1,5 +1,6 @@
# 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

View File

@@ -1,4 +1,5 @@
# 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

View File

@@ -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,7 @@ app.whenReady().then(() => {
#### `contents.sendToFrame(frameId, channel, ...args)`
* `frameId` Integer
* `frameId` Integer | [number, number]
* `channel` String
* `...args` any[]

View File

@@ -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.

View File

@@ -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

View 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>

View 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()
}
})

View 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}`)
}

View 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>

View 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()
}
})

View File

@@ -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>

View File

@@ -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()
}
})
})

View 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>

View 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()
}
})

View 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>

View 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()
}
})

View 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'
})

View 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; }
}

View 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>

View 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()
}
})

View 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>

View 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()
}
})

View 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>

View 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()
}
})

View File

@@ -0,0 +1,7 @@
const myNotification = new Notification('Title', {
body: 'Notification from the Renderer process'
})
myNotification.onclick = () => {
console.log('Notification clicked')
}

View 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>

View 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()
}
})

View 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>

View 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()
}
})

View 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()

View 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>

View 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()
}
})

View File

@@ -0,0 +1,6 @@
const alertOnlineStatus = () => { window.alert(navigator.onLine ? 'online' : 'offline') }
window.addEventListener('online', alertOnlineStatus)
window.addEventListener('offline', alertOnlineStatus)
alertOnlineStatus()

View 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>

View 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()
}
})

View 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>

View 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()
}
})

View 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>

View 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()
}
})

View 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>

View 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()
}
})

View File

@@ -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

View File

@@ -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);

View File

@@ -51,10 +51,6 @@ class CrashReporter {
return binding.getUploadedReports();
}
getCrashesDirectory () {
return app.getPath('crashDumps');
}
getUploadToServer () {
if (process.type === 'browser') {
return binding.getUploadToServer();

View File

@@ -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 () {

View File

@@ -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;
}
});

View File

@@ -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)
});

View File

@@ -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);
};
};

View File

@@ -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);
}
});

View File

@@ -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) {

View File

@@ -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));
});

View File

@@ -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',

View File

@@ -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);
},

View File

@@ -180,7 +180,7 @@ const warnAboutInsecureCSP = function () {
console.warn('%cElectron Security Warning (Insecure Content-Security-Policy)',
'font-weight: bold;', warning);
});
}).catch(() => {});
};
/**

View File

@@ -1,6 +1,6 @@
{
"name": "electron",
"version": "12.0.0-nightly.20201118",
"version": "12.0.0-beta.11",
"repository": "https://github.com/electron/electron",
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
"devDependencies": {

View File

@@ -103,3 +103,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

View 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

View 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);
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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 gins 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 =

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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 @@

View File

@@ -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",

View File

@@ -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"

View File

@@ -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);

View File

@@ -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

View File

@@ -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_ != &regions) {
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_ != &regions)
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) {

View File

@@ -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"));
}
}

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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;
@@ -3781,6 +3794,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 +3817,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);
}

View File

@@ -261,7 +261,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);

View File

@@ -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

View File

@@ -89,7 +89,6 @@ class ElectronBrowserMainParts : public content::BrowserMainParts {
Browser* browser() { return browser_.get(); }
BrowserProcessImpl* browser_process() { return fake_browser_process_.get(); }
NodeEnvironment* node_env() { return node_env_.get(); }
protected:
// content::BrowserMainParts:

View File

@@ -29,11 +29,9 @@ void MicrotasksRunner::DidProcessTask(const base::PendingTask& pending_task) {
// up Node.js dealying its callbacks. To fix this, now we always lets Node.js
// handle the checkpoint in the browser process.
{
auto* node_env = electron::ElectronBrowserMainParts::Get()->node_env();
v8::HandleScope scope(isolate_);
node::InternalCallbackScope microtasks_scope(
node_env->env(), v8::Object::New(isolate_), {0, 0},
node::InternalCallbackScope::kNoFlags);
node::CallbackScope microtasks_scope(isolate_, v8::Object::New(isolate_),
{0, 0});
}
}

View File

@@ -40,6 +40,10 @@ class NativeBrowserView : public content::WebContentsObserver {
return inspectable_web_contents_;
}
const std::vector<mojom::DraggableRegionPtr>& GetDraggableRegions() const {
return draggable_regions_;
}
InspectableWebContentsView* GetInspectableWebContentsView();
virtual void SetAutoResizeFlags(uint8_t flags) = 0;
@@ -47,6 +51,9 @@ class NativeBrowserView : public content::WebContentsObserver {
virtual gfx::Rect GetBounds() = 0;
virtual void SetBackgroundColor(SkColor color) = 0;
virtual void UpdateDraggableRegions(
const std::vector<gfx::Rect>& drag_exclude_rects) {}
// Called when the window needs to update its draggable region.
virtual void UpdateDraggableRegions(
const std::vector<mojom::DraggableRegionPtr>& regions) {}
@@ -57,6 +64,7 @@ class NativeBrowserView : public content::WebContentsObserver {
void WebContentsDestroyed() override;
InspectableWebContents* inspectable_web_contents_;
std::vector<mojom::DraggableRegionPtr> draggable_regions_;
private:
DISALLOW_COPY_AND_ASSIGN(NativeBrowserView);

View File

@@ -27,8 +27,8 @@ class NativeBrowserViewMac : public NativeBrowserView {
void UpdateDraggableRegions(
const std::vector<mojom::DraggableRegionPtr>& regions) override;
private:
std::vector<mojom::DraggableRegionPtr> draggable_regions_;
void UpdateDraggableRegions(
const std::vector<gfx::Rect>& drag_exclude_rects) override;
DISALLOW_COPY_AND_ASSIGN(NativeBrowserViewMac);
};

View File

@@ -238,7 +238,7 @@ void NativeBrowserViewMac::SetBackgroundColor(SkColor color) {
}
void NativeBrowserViewMac::UpdateDraggableRegions(
const std::vector<mojom::DraggableRegionPtr>& regions) {
const std::vector<gfx::Rect>& drag_exclude_rects) {
if (!inspectable_web_contents_)
return;
auto* web_contents = inspectable_web_contents_->GetWebContents();
@@ -248,25 +248,6 @@ void NativeBrowserViewMac::UpdateDraggableRegions(
NSView* window_content_view = inspectable_view.superview;
const auto window_content_view_height = NSHeight(window_content_view.bounds);
NSInteger webViewWidth = NSWidth([web_view bounds]);
NSInteger webViewHeight = NSHeight([web_view bounds]);
std::vector<gfx::Rect> drag_exclude_rects;
if (regions.empty()) {
drag_exclude_rects.push_back(gfx::Rect(0, 0, webViewWidth, webViewHeight));
} else {
drag_exclude_rects = CalculateNonDraggableRegions(
DraggableRegionsToSkRegion(regions), webViewWidth, webViewHeight);
}
// Draggable regions are implemented by having the whole web view draggable
// and overlaying regions that are not draggable.
if (&draggable_regions_ != &regions) {
draggable_regions_.clear();
for (const auto& r : regions)
draggable_regions_.push_back(r.Clone());
}
// Remove all DragRegionViews that were added last time. Note that we need
// to copy the `subviews` array to avoid mutation during iteration.
base::scoped_nsobject<NSArray> subviews([[web_view subviews] copy]);
@@ -297,6 +278,32 @@ void NativeBrowserViewMac::UpdateDraggableRegions(
}
}
void NativeBrowserViewMac::UpdateDraggableRegions(
const std::vector<mojom::DraggableRegionPtr>& regions) {
if (!inspectable_web_contents_)
return;
auto* web_contents = inspectable_web_contents_->GetWebContents();
NSView* web_view = web_contents->GetNativeView().GetNativeNSView();
NSInteger webViewWidth = NSWidth([web_view bounds]);
NSInteger webViewHeight = NSHeight([web_view bounds]);
// Draggable regions are implemented by having the whole web view draggable
// and overlaying regions that are not draggable.
if (&draggable_regions_ != &regions)
draggable_regions_ = mojo::Clone(regions);
std::vector<gfx::Rect> drag_exclude_rects;
if (regions.empty()) {
drag_exclude_rects.emplace_back(0, 0, webViewWidth, webViewHeight);
} else {
drag_exclude_rects = CalculateNonDraggableRegions(
DraggableRegionsToSkRegion(regions), webViewWidth, webViewHeight);
}
UpdateDraggableRegions(drag_exclude_rects);
}
// static
NativeBrowserView* NativeBrowserView::Create(
InspectableWebContents* inspectable_web_contents) {

View File

@@ -4,6 +4,11 @@
#include "shell/browser/native_browser_view_views.h"
#include <memory>
#include <utility>
#include <vector>
#include "shell/browser/ui/drag_util.h"
#include "shell/browser/ui/inspectable_web_contents_view.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/background.h"
@@ -22,6 +27,25 @@ void NativeBrowserViewViews::SetAutoResizeFlags(uint8_t flags) {
ResetAutoResizeProportions();
}
void NativeBrowserViewViews::UpdateDraggableRegions(
const std::vector<mojom::DraggableRegionPtr>& regions) {
// We need to snap the regions to the bounds of the current BrowserView.
// For example, if an attached BrowserView is draggable but its bounds are
// { x: 200, y: 100, width: 300, height: 300 }
// then we need to add 200 to the x-value and 100 to the
// y-value of each of the passed regions or it will be incorrectly
// assumed that the regions begin in the top left corner as they
// would for the main client window.
auto const offset = GetBounds().OffsetFromOrigin();
auto snapped_regions = mojo::Clone(regions);
for (auto& snapped_region : snapped_regions) {
snapped_region->bounds.Offset(offset);
snapped_region->draggable = true;
}
draggable_region_ = DraggableRegionsToSkRegion(snapped_regions);
}
void NativeBrowserViewViews::SetAutoResizeProportions(
const gfx::Size& window_size) {
if ((auto_resize_flags_ & AutoResizeFlags::kAutoResizeHorizontal) &&

View File

@@ -5,7 +5,11 @@
#ifndef SHELL_BROWSER_NATIVE_BROWSER_VIEW_VIEWS_H_
#define SHELL_BROWSER_NATIVE_BROWSER_VIEW_VIEWS_H_
#include <memory>
#include <vector>
#include "shell/browser/native_browser_view.h"
#include "third_party/skia/include/core/SkRegion.h"
namespace electron {
@@ -26,6 +30,10 @@ class NativeBrowserViewViews : public NativeBrowserView {
void SetBounds(const gfx::Rect& bounds) override;
gfx::Rect GetBounds() override;
void SetBackgroundColor(SkColor color) override;
void UpdateDraggableRegions(
const std::vector<mojom::DraggableRegionPtr>& regions) override;
SkRegion* draggable_region() const { return draggable_region_.get(); }
private:
void ResetAutoResizeProportions();
@@ -40,6 +48,8 @@ class NativeBrowserViewViews : public NativeBrowserView {
float auto_vertical_proportion_height_ = 0.;
float auto_vertical_proportion_top_ = 0.;
std::unique_ptr<SkRegion> draggable_region_;
DISALLOW_COPY_AND_ASSIGN(NativeBrowserViewViews);
};

View File

@@ -392,10 +392,6 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
}
NSUInteger styleMask = NSWindowStyleMaskTitled;
bool customOnHover = title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover;
if (customOnHover && (!useStandardWindow || transparent() || !has_frame()))
styleMask = NSWindowStyleMaskFullSizeContentView;
if (minimizable)
styleMask |= NSMiniaturizableWindowMask;
if (closable)
@@ -1697,24 +1693,22 @@ void NativeWindowMac::AddContentViewLayers(bool minimizable, bool closable) {
// The fullscreen button should always be hidden for frameless window.
[[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
// Create a custom window buttons view for kCustomButtonsOnHover.
if (title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover) {
buttons_view_.reset(
[[CustomWindowButtonView alloc] initWithFrame:NSZeroRect]);
// NSWindowStyleMaskFullSizeContentView does not work with zoom button
SetFullScreenable(false);
if (!minimizable)
[[buttons_view_ viewWithTag:2] removeFromSuperview];
if (!closable)
[[buttons_view_ viewWithTag:1] removeFromSuperview];
[[window_ contentView] addSubview:buttons_view_];
} else {
if (title_bar_style_ != TitleBarStyle::kNormal)
return;
}
// Hide the window buttons.
// Hide the window buttons except for kHidden and kHiddenInset.
if (title_bar_style_ == TitleBarStyle::kNormal ||
title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover) {
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES];
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES];

View File

@@ -530,6 +530,20 @@ void NativeWindowViews::Unmaximize() {
}
bool NativeWindowViews::IsMaximized() {
// For window without WS_THICKFRAME style, we can not call IsMaximized().
// This path will be used for transparent windows as well.
#if defined(OS_WIN)
if (!(::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME)) {
// Compare the size of the window with the size of the display
auto display = display::Screen::GetScreen()->GetDisplayNearestWindow(
GetNativeWindow());
// Maximized if the window is the same dimensions and placement as the
// display
return GetBounds() == display.work_area();
}
#endif
return widget()->IsMaximized();
}
@@ -1446,6 +1460,16 @@ views::View* NativeWindowViews::GetContentsView() {
bool NativeWindowViews::ShouldDescendIntoChildForEventHandling(
gfx::NativeView child,
const gfx::Point& location) {
// App window should claim mouse events that fall within any BrowserViews'
// draggable region.
for (auto* view : browser_views()) {
auto* native_view = static_cast<NativeBrowserViewViews*>(view);
auto* view_draggable_region = native_view->draggable_region();
if (view_draggable_region &&
view_draggable_region->contains(location.x(), location.y()))
return false;
}
// App window should claim mouse events that fall within the draggable region.
if (draggable_region() &&
draggable_region()->contains(location.x(), location.y()))

View File

@@ -149,9 +149,7 @@ std::set<NativeWindowViews*> NativeWindowViews::forwarding_windows_;
HHOOK NativeWindowViews::mouse_hook_ = NULL;
void NativeWindowViews::Maximize() {
// Only use Maximize() when:
// 1. window has WS_THICKFRAME style;
// 2. and window is not frameless when there is autohide taskbar.
// Only use Maximize() when window has WS_THICKFRAME style
if (::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME) {
if (IsVisible())
widget()->Maximize();
@@ -161,8 +159,8 @@ void NativeWindowViews::Maximize() {
return;
} else {
restore_bounds_ = GetBounds();
auto display =
display::Screen::GetScreen()->GetDisplayNearestPoint(GetPosition());
auto display = display::Screen::GetScreen()->GetDisplayNearestWindow(
GetNativeWindow());
SetBounds(display.work_area(), false);
}
}

View File

@@ -40,5 +40,9 @@
<string>This app needs access to the microphone</string>
<key>NSCameraUsageDescription</key>
<string>This app needs access to the camera</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app needs access to Bluetooth</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app needs access to Bluetooth</string>
</dict>
</plist>

View File

@@ -50,8 +50,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 12,0,0,20201118
PRODUCTVERSION 12,0,0,20201118
FILEVERSION 12,0,0,11
PRODUCTVERSION 12,0,0,11
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L

View File

@@ -87,9 +87,13 @@ class GtkMessageBox : public NativeWindowObserver {
// Add buttons.
GtkDialog* dialog = GTK_DIALOG(dialog_);
for (size_t i = 0; i < settings.buttons.size(); ++i) {
gtk_dialog_add_button(dialog, TranslateToStock(i, settings.buttons[i]),
i);
if (settings.buttons.size() == 0) {
gtk_dialog_add_button(dialog, TranslateToStock(0, "OK"), 0);
} else {
for (size_t i = 0; i < settings.buttons.size(); ++i) {
gtk_dialog_add_button(dialog, TranslateToStock(i, settings.buttons[i]),
i);
}
}
gtk_dialog_set_default_response(dialog, settings.default_id);
@@ -220,7 +224,7 @@ void ShowErrorBox(const base::string16& title, const base::string16& content) {
if (Browser::Get()->is_ready()) {
electron::MessageBoxSettings settings;
settings.type = electron::MessageBoxType::kError;
settings.buttons = {"OK"};
settings.buttons = {};
settings.title = "Error";
settings.message = base::UTF16ToUTF8(title);
settings.detail = base::UTF16ToUTF8(content);

View File

@@ -4,6 +4,7 @@
#include "shell/browser/ui/views/frameless_view.h"
#include "shell/browser/native_browser_view_views.h"
#include "shell/browser/native_window_views.h"
#include "ui/aura/window.h"
#include "ui/base/hit_test.h"
@@ -68,6 +69,15 @@ int FramelessView::NonClientHitTest(const gfx::Point& cursor) {
if (frame_->IsFullscreen())
return HTCLIENT;
// Check attached BrowserViews for potential draggable areas.
for (auto* view : window_->browser_views()) {
auto* native_view = static_cast<NativeBrowserViewViews*>(view);
auto* view_draggable_region = native_view->draggable_region();
if (view_draggable_region &&
view_draggable_region->contains(cursor.x(), cursor.y()))
return HTCAPTION;
}
// Check for possible draggable region in the client area for the frameless
// window.
SkRegion* draggable_region = window_->draggable_region();

View File

@@ -113,9 +113,8 @@ void ElectronBindings::OnCallNextTick(uv_async_t* handle) {
gin_helper::Locker locker(env->isolate());
v8::Context::Scope context_scope(env->context());
v8::HandleScope handle_scope(env->isolate());
node::InternalCallbackScope scope(env, v8::Object::New(env->isolate()),
{0, 0},
node::InternalCallbackScope::kNoFlags);
node::CallbackScope scope(env->isolate(), v8::Object::New(env->isolate()),
{0, 0});
}
self->pending_next_ticks_.clear();

View File

@@ -5,6 +5,7 @@
#include "shell/common/gin_helper/event_emitter.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "shell/browser/api/event.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/object_template_builder.h"
@@ -67,8 +68,10 @@ v8::Local<v8::Object> CreateNativeEvent(
Dictionary dict(isolate, event);
dict.Set("sender", sender);
// Should always set frameId even when callback is null.
if (frame)
if (frame) {
dict.Set("frameId", frame->GetRoutingID());
dict.Set("processId", frame->GetProcess()->GetID());
}
return event;
}

View File

@@ -176,14 +176,18 @@ void ErrorMessageListener(v8::Local<v8::Message> message,
v8::Isolate* isolate = v8::Isolate::GetCurrent();
node::Environment* env = node::Environment::GetCurrent(isolate);
// TODO(codebytere): properly emit the after() hooks now
// that the exception has been handled.
// See node/lib/internal/process/execution.js#L176-L180
// Ensure that the async id stack is properly cleared so the async
// hook stack does not become corrupted.
if (env) {
// Emit the after() hooks now that the exception has been handled.
// Analogous to node/lib/internal/process/execution.js#L176-L180
if (env->async_hooks()->fields()[node::AsyncHooks::kAfter]) {
while (env->async_hooks()->fields()[node::AsyncHooks::kStackLength]) {
node::AsyncWrap::EmitAfter(env, env->execution_async_id());
env->async_hooks()->pop_async_context(env->execution_async_id());
}
}
// Ensure that the async id stack is properly cleared so the async
// hook stack does not become corrupted.
env->async_hooks()->clear_async_id_stack();
}
}
@@ -499,6 +503,13 @@ node::Environment* NodeBindings::CreateEnvironment(
// context. We need to use the one Blink already provides.
is.flags |=
node::IsolateSettingsFlags::SHOULD_NOT_SET_PROMISE_REJECTION_CALLBACK;
// We do not want to use the stack trace callback that Node.js uses,
// because it relies on Node.js being aware of the current Context and
// that's not always the case. We need to use the one Blink already
// provides.
is.flags |=
node::IsolateSettingsFlags::SHOULD_NOT_SET_PREPARE_STACK_TRACE_CALLBACK;
}
node::SetIsolateUpForNode(context->GetIsolate(), is);

Some files were not shown because too many files have changed in this diff Show More