mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
23 Commits
refactor/a
...
v12.0.0-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cec2c73733 | ||
|
|
2e9305d964 | ||
|
|
0491cc6906 | ||
|
|
badcdd6566 | ||
|
|
a0d0bd60a5 | ||
|
|
c0f0a02419 | ||
|
|
8046f0560a | ||
|
|
2a8961b52f | ||
|
|
36163af228 | ||
|
|
29f42e943e | ||
|
|
4597cb6499 | ||
|
|
4ba78b81c1 | ||
|
|
80e0473649 | ||
|
|
db0d4c8224 | ||
|
|
4fbb58020c | ||
|
|
c9801ab5a5 | ||
|
|
46441c1bd7 | ||
|
|
1cac3354e7 | ||
|
|
57c69ab3ac | ||
|
|
39b9c40a05 | ||
|
|
66a22a28a5 | ||
|
|
17a8b7724b | ||
|
|
c512995426 |
@@ -295,10 +295,10 @@ step-setup-goma-for-build: &step-setup-goma-for-build
|
|||||||
run:
|
run:
|
||||||
name: Setup Goma
|
name: Setup Goma
|
||||||
command: |
|
command: |
|
||||||
if [ "`uname`" == "Linux" ]; then
|
echo 'export NUMBER_OF_NINJA_PROCESSES=300' >> $BASH_ENV
|
||||||
echo 'export NUMBER_OF_NINJA_PROCESSES=300' >> $BASH_ENV
|
if [ "`uname`" == "Darwin" ]; then
|
||||||
else
|
echo 'ulimit -n 10000' >> $BASH_ENV
|
||||||
echo 'export NUMBER_OF_NINJA_PROCESSES=25' >> $BASH_ENV
|
echo 'sudo launchctl limit maxfiles 65536 200000' >> $BASH_ENV
|
||||||
fi
|
fi
|
||||||
if [ ! -z "$RAW_GOMA_AUTH" ]; then
|
if [ ! -z "$RAW_GOMA_AUTH" ]; then
|
||||||
echo $RAW_GOMA_AUTH > ~/.goma_oauth2_config
|
echo $RAW_GOMA_AUTH > ~/.goma_oauth2_config
|
||||||
@@ -307,7 +307,7 @@ step-setup-goma-for-build: &step-setup-goma-for-build
|
|||||||
cd build-tools
|
cd build-tools
|
||||||
npm install
|
npm install
|
||||||
mkdir third_party
|
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()"
|
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 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
|
echo 'export LOCAL_GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
12.0.0-nightly.20201118
|
12.0.0-beta.6
|
||||||
@@ -141,7 +141,8 @@ build_script:
|
|||||||
- cd build-tools
|
- cd build-tools
|
||||||
- npm install
|
- npm install
|
||||||
- mkdir third_party
|
- 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: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)"
|
- ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)"
|
||||||
- cd ..
|
- cd ..
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const { app, contentTracing } = require('electron')
|
|||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
await contentTracing.startRecording({
|
await contentTracing.startRecording({
|
||||||
include_categories: ['*']
|
included_categories: ['*']
|
||||||
})
|
})
|
||||||
console.log('Tracing started')
|
console.log('Tracing started')
|
||||||
await new Promise(resolve => setTimeout(resolve, 5000))
|
await new Promise(resolve => setTimeout(resolve, 5000))
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ must be at most 39 bytes long, and values must be no longer than 127 bytes.
|
|||||||
Keys with names longer than the maximum will be silently ignored. Key values
|
Keys with names longer than the maximum will be silently ignored. Key values
|
||||||
longer than the maximum length will be truncated.
|
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()`
|
### `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
|
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.
|
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()`
|
### `crashReporter.getUploadedReports()`
|
||||||
|
|
||||||
@@ -146,14 +146,14 @@ Returns [`CrashReport[]`](structures/crash-report.md):
|
|||||||
Returns all uploaded crash reports. Each report contains the date and uploaded
|
Returns all uploaded crash reports. Each report contains the date and uploaded
|
||||||
ID.
|
ID.
|
||||||
|
|
||||||
**Note:** Calling this method from the renderer process is deprecated.
|
**Note:** This method is only available in the main process.
|
||||||
|
|
||||||
### `crashReporter.getUploadToServer()`
|
### `crashReporter.getUploadToServer()`
|
||||||
|
|
||||||
Returns `Boolean` - Whether reports should be submitted to the server. Set through
|
Returns `Boolean` - Whether reports should be submitted to the server. Set through
|
||||||
the `start` method or `setUploadToServer`.
|
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)`
|
### `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
|
This would normally be controlled by user preferences. This has no effect if
|
||||||
called before `start` is called.
|
called before `start` is called.
|
||||||
|
|
||||||
**Note:** Calling this method from the renderer process is deprecated.
|
**Note:** This method is only available in the main process.
|
||||||
|
|
||||||
### `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.
|
|
||||||
|
|
||||||
### `crashReporter.addExtraParameter(key, value)`
|
### `crashReporter.addExtraParameter(key, value)`
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ returns `null`.
|
|||||||
|
|
||||||
* `id` Integer
|
* `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
|
## Class: WebContents
|
||||||
|
|
||||||
@@ -155,7 +156,7 @@ Returns:
|
|||||||
be set. If no post data is to be sent, the value will be `null`. Only defined
|
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`.
|
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
|
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'>`.
|
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
|
BrowserWindow. They are merged in increasing precedence: options inherited
|
||||||
from the parent, parsed options from the `features` string from
|
from the parent, parsed options from the `features` string from
|
||||||
`window.open()`, and options given by
|
`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.
|
Unrecognized options are not filtered out.
|
||||||
* `additionalFeatures` String[] - The non-standard features (features not
|
* `additionalFeatures` String[] - The non-standard features (features not
|
||||||
handled Chromium or Electron) _Deprecated_
|
handled Chromium or Electron) _Deprecated_
|
||||||
@@ -220,7 +221,7 @@ Returns:
|
|||||||
|
|
||||||
Emitted _after_ successful creation of a window via `window.open` in the renderer.
|
Emitted _after_ successful creation of a window via `window.open` in the renderer.
|
||||||
Not emitted if the creation of the window is canceled from
|
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`.
|
See [`window.open()`](window-open.md) for more details and how to use this in conjunction with `webContents.setWindowOpenHandler`.
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ BrowserWindow constructor options are set by, in increasing precedence
|
|||||||
order: options inherited from the parent, parsed options
|
order: options inherited from the parent, parsed options
|
||||||
from the `features` string from `window.open()`, security-related webPreferences
|
from the `features` string from `window.open()`, security-related webPreferences
|
||||||
inherited from the parent, and options given by
|
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
|
Note that `webContents.setWindowOpenHandler` has final say and full privilege
|
||||||
because it is invoked in the main process.
|
because it is invoked in the main process.
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,18 @@ We [recommend having contextIsolation enabled](https://github.com/electron/elect
|
|||||||
|
|
||||||
For more details see: https://github.com/electron/electron/issues/23506
|
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
|
### Removed: `crashReporter` methods in the renderer process
|
||||||
|
|
||||||
The following `crashReporter` methods are no longer available in the renderer
|
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).
|
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()`
|
### Removed: `<webview>.getWebContents()`
|
||||||
|
|
||||||
This API, which was deprecated in Electron 8.0, is now removed.
|
This API, which was deprecated in Electron 8.0, is now removed.
|
||||||
|
|||||||
18
docs/fiddles/features/drag-and-drop/index.html
Normal file
18
docs/fiddles/features/drag-and-drop/index.html
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Hello World!</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
<p>
|
||||||
|
We are using node <script>document.write(process.versions.node)</script>,
|
||||||
|
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||||
|
and Electron <script>document.write(process.versions.electron)</script>.
|
||||||
|
</p>
|
||||||
|
<a href="#" id="drag">Drag me</a>
|
||||||
|
<script src="renderer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
41
docs/fiddles/features/drag-and-drop/main.js
Normal file
41
docs/fiddles/features/drag-and-drop/main.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
const { app, BrowserWindow, ipcMain, nativeImage, NativeImage } = require('electron')
|
||||||
|
const fs = require('fs');
|
||||||
|
const http = require('http');
|
||||||
|
|
||||||
|
function createWindow () {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
win.loadFile('index.html')
|
||||||
|
}
|
||||||
|
const iconName = 'iconForDragAndDrop.png';
|
||||||
|
const icon = fs.createWriteStream(`${process.cwd()}/${iconName}`);
|
||||||
|
http.get('http://img.icons8.com/ios/452/drag-and-drop.png', (response) => {
|
||||||
|
response.pipe(icon);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.whenReady().then(createWindow)
|
||||||
|
|
||||||
|
ipcMain.on('ondragstart', (event, filePath) => {
|
||||||
|
event.sender.startDrag({
|
||||||
|
file: filePath,
|
||||||
|
icon: `${process.cwd()}/${iconName}`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
9
docs/fiddles/features/drag-and-drop/renderer.js
Normal file
9
docs/fiddles/features/drag-and-drop/renderer.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
const { ipcRenderer } = require('electron')
|
||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
|
document.getElementById('drag').ondragstart = (event) => {
|
||||||
|
const fileName = 'drag-and-drop.md'
|
||||||
|
fs.writeFileSync(fileName, '# Test drag and drop');
|
||||||
|
event.preventDefault()
|
||||||
|
ipcRenderer.send('ondragstart', process.cwd() + `/${fileName}`)
|
||||||
|
}
|
||||||
16
docs/fiddles/features/keyboard-shortcuts/global/index.html
Normal file
16
docs/fiddles/features/keyboard-shortcuts/global/index.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Hello World!</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
<p>
|
||||||
|
We are using node <script>document.write(process.versions.node)</script>,
|
||||||
|
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||||
|
and Electron <script>document.write(process.versions.electron)</script>.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
31
docs/fiddles/features/keyboard-shortcuts/global/main.js
Normal file
31
docs/fiddles/features/keyboard-shortcuts/global/main.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
const { app, BrowserWindow, globalShortcut } = require('electron')
|
||||||
|
|
||||||
|
function createWindow () {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
win.loadFile('index.html')
|
||||||
|
}
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
globalShortcut.register('Alt+CommandOrControl+I', () => {
|
||||||
|
console.log('Electron loves global shortcuts!')
|
||||||
|
})
|
||||||
|
}).then(createWindow)
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Hello World!</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
We are using node <script>document.write(process.versions.node)</script>,
|
||||||
|
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||||
|
and Electron <script>document.write(process.versions.electron)</script>.
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
const { app, BrowserWindow } = require('electron')
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true } })
|
||||||
|
|
||||||
|
win.loadFile('index.html')
|
||||||
|
win.webContents.on('before-input-event', (event, input) => {
|
||||||
|
if (input.control && input.key.toLowerCase() === 'i') {
|
||||||
|
console.log('Pressed Control+I')
|
||||||
|
event.preventDefault()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
16
docs/fiddles/features/keyboard-shortcuts/local/index.html
Normal file
16
docs/fiddles/features/keyboard-shortcuts/local/index.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Hello World!</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
<p>
|
||||||
|
We are using node <script>document.write(process.versions.node)</script>,
|
||||||
|
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||||
|
and Electron <script>document.write(process.versions.electron)</script>.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
39
docs/fiddles/features/keyboard-shortcuts/local/main.js
Normal file
39
docs/fiddles/features/keyboard-shortcuts/local/main.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
const { app, BrowserWindow, Menu, MenuItem } = require('electron')
|
||||||
|
|
||||||
|
function createWindow () {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
win.loadFile('index.html')
|
||||||
|
}
|
||||||
|
|
||||||
|
const menu = new Menu()
|
||||||
|
menu.append(new MenuItem({
|
||||||
|
label: 'Electron',
|
||||||
|
submenu: [{
|
||||||
|
role: 'help',
|
||||||
|
accelerator: process.platform === 'darwin' ? 'Alt+Cmd+I' : 'Alt+Shift+I',
|
||||||
|
click: () => { console.log('Electron rocks!') }
|
||||||
|
}]
|
||||||
|
}))
|
||||||
|
|
||||||
|
Menu.setApplicationMenu(menu)
|
||||||
|
|
||||||
|
app.whenReady().then(createWindow)
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
19
docs/fiddles/features/macos-dark-mode/index.html
Normal file
19
docs/fiddles/features/macos-dark-mode/index.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Hello World!</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="./styles.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
<p>Current theme source: <strong id="theme-source">System</strong></p>
|
||||||
|
|
||||||
|
<button id="toggle-dark-mode">Toggle Dark Mode</button>
|
||||||
|
<button id="reset-to-system">Reset to System Theme</button>
|
||||||
|
|
||||||
|
<script src="renderer.js"></script>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
40
docs/fiddles/features/macos-dark-mode/main.js
Normal file
40
docs/fiddles/features/macos-dark-mode/main.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron')
|
||||||
|
|
||||||
|
function createWindow () {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
win.loadFile('index.html')
|
||||||
|
|
||||||
|
ipcMain.handle('dark-mode:toggle', () => {
|
||||||
|
if (nativeTheme.shouldUseDarkColors) {
|
||||||
|
nativeTheme.themeSource = 'light'
|
||||||
|
} else {
|
||||||
|
nativeTheme.themeSource = 'dark'
|
||||||
|
}
|
||||||
|
return nativeTheme.shouldUseDarkColors
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('dark-mode:system', () => {
|
||||||
|
nativeTheme.themeSouce = 'system'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
app.whenReady().then(createWindow)
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
11
docs/fiddles/features/macos-dark-mode/renderer.js
Normal file
11
docs/fiddles/features/macos-dark-mode/renderer.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
const { ipcRenderer } = require('electron')
|
||||||
|
|
||||||
|
document.getElementById('toggle-dark-mode').addEventListener('click', async () => {
|
||||||
|
const isDarkMode = await ipcRenderer.invoke('dark-mode:toggle')
|
||||||
|
document.getElementById('theme-source').innerHTML = isDarkMode ? 'Dark' : 'Light'
|
||||||
|
})
|
||||||
|
|
||||||
|
document.getElementById('reset-to-system').addEventListener('click', async () => {
|
||||||
|
await ipcRenderer.invoke('dark-mode:system')
|
||||||
|
document.getElementById('theme-source').innerHTML = 'System'
|
||||||
|
})
|
||||||
7
docs/fiddles/features/macos-dark-mode/styles.css
Normal file
7
docs/fiddles/features/macos-dark-mode/styles.css
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
body { background: #333; color: white; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
body { background: #ddd; color: black; }
|
||||||
|
}
|
||||||
16
docs/fiddles/features/macos-dock-menu/index.html
Normal file
16
docs/fiddles/features/macos-dock-menu/index.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Hello World!</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
<p>
|
||||||
|
We are using node <script>document.write(process.versions.node)</script>,
|
||||||
|
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||||
|
and Electron <script>document.write(process.versions.electron)</script>.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
43
docs/fiddles/features/macos-dock-menu/main.js
Normal file
43
docs/fiddles/features/macos-dock-menu/main.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
const { app, BrowserWindow, Menu } = require('electron')
|
||||||
|
|
||||||
|
function createWindow () {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
win.loadFile('index.html')
|
||||||
|
}
|
||||||
|
|
||||||
|
const dockMenu = Menu.buildFromTemplate([
|
||||||
|
{
|
||||||
|
label: 'New Window',
|
||||||
|
click () { console.log('New Window') }
|
||||||
|
}, {
|
||||||
|
label: 'New Window with Settings',
|
||||||
|
submenu: [
|
||||||
|
{ label: 'Basic' },
|
||||||
|
{ label: 'Pro' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ label: 'New Command...' }
|
||||||
|
])
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
app.dock.setMenu(dockMenu)
|
||||||
|
}).then(createWindow)
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
16
docs/fiddles/features/notifications/main/index.html
Normal file
16
docs/fiddles/features/notifications/main/index.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Hello World!</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
<p>
|
||||||
|
We are using node <script>document.write(process.versions.node)</script>,
|
||||||
|
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||||
|
and Electron <script>document.write(process.versions.electron)</script>.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
35
docs/fiddles/features/notifications/main/main.js
Normal file
35
docs/fiddles/features/notifications/main/main.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
const { app, BrowserWindow, Notification } = require('electron')
|
||||||
|
|
||||||
|
function createWindow () {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
win.loadFile('index.html')
|
||||||
|
}
|
||||||
|
|
||||||
|
function showNotification () {
|
||||||
|
const notification = {
|
||||||
|
title: 'Basic Notification',
|
||||||
|
body: 'Notification from the Main process'
|
||||||
|
}
|
||||||
|
new Notification(notification).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
app.whenReady().then(createWindow).then(showNotification)
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
17
docs/fiddles/features/notifications/renderer/index.html
Normal file
17
docs/fiddles/features/notifications/renderer/index.html
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Hello World!</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
<p>
|
||||||
|
We are using node <script>document.write(process.versions.node)</script>,
|
||||||
|
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||||
|
and Electron <script>document.write(process.versions.electron)</script>.
|
||||||
|
</p>
|
||||||
|
<script src="renderer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
27
docs/fiddles/features/notifications/renderer/main.js
Normal file
27
docs/fiddles/features/notifications/renderer/main.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
const { app, BrowserWindow } = require('electron')
|
||||||
|
|
||||||
|
function createWindow () {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
win.loadFile('index.html')
|
||||||
|
}
|
||||||
|
|
||||||
|
app.whenReady().then(createWindow)
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
7
docs/fiddles/features/notifications/renderer/renderer.js
Normal file
7
docs/fiddles/features/notifications/renderer/renderer.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
const myNotification = new Notification('Title', {
|
||||||
|
body: 'Notification from the Renderer process'
|
||||||
|
})
|
||||||
|
|
||||||
|
myNotification.onclick = () => {
|
||||||
|
console.log('Notification clicked')
|
||||||
|
}
|
||||||
15
docs/fiddles/features/offscreen-rendering/index.html
Normal file
15
docs/fiddles/features/offscreen-rendering/index.html
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Hello World!</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
<p>
|
||||||
|
We are using node <script>document.write(process.versions.node)</script>,
|
||||||
|
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||||
|
and Electron <script>document.write(process.versions.electron)</script>.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
28
docs/fiddles/features/offscreen-rendering/main.js
Normal file
28
docs/fiddles/features/offscreen-rendering/main.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
const { app, BrowserWindow } = require('electron')
|
||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
|
app.disableHardwareAcceleration()
|
||||||
|
|
||||||
|
let win
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
win = new BrowserWindow({ webPreferences: { offscreen: true } })
|
||||||
|
win.loadURL('https://github.com')
|
||||||
|
win.webContents.on('paint', (event, dirty, image) => {
|
||||||
|
fs.writeFileSync('ex.png', image.toPNG())
|
||||||
|
})
|
||||||
|
win.webContents.setFrameRate(60)
|
||||||
|
console.log(`The screenshot has been successfully saved to ${process.cwd()}/ex.png`)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
17
docs/fiddles/features/online-detection/main/index.html
Normal file
17
docs/fiddles/features/online-detection/main/index.html
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Hello World!</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
<p>
|
||||||
|
We are using node <script>document.write(process.versions.node)</script>,
|
||||||
|
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||||
|
and Electron <script>document.write(process.versions.electron)</script>.
|
||||||
|
</p>
|
||||||
|
<script src="renderer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
24
docs/fiddles/features/online-detection/main/main.js
Normal file
24
docs/fiddles/features/online-detection/main/main.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
const { app, BrowserWindow, ipcMain } = require('electron')
|
||||||
|
|
||||||
|
let onlineStatusWindow
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false, webPreferences: { nodeIntegration: true } })
|
||||||
|
onlineStatusWindow.loadURL(`file://${__dirname}/index.html`)
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('online-status-changed', (event, status) => {
|
||||||
|
console.log(status)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
7
docs/fiddles/features/online-detection/main/renderer.js
Normal file
7
docs/fiddles/features/online-detection/main/renderer.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
const { ipcRenderer } = require('electron')
|
||||||
|
const updateOnlineStatus = () => { ipcRenderer.send('online-status-changed', navigator.onLine ? 'online' : 'offline') }
|
||||||
|
|
||||||
|
window.addEventListener('online', updateOnlineStatus)
|
||||||
|
window.addEventListener('offline', updateOnlineStatus)
|
||||||
|
|
||||||
|
updateOnlineStatus()
|
||||||
17
docs/fiddles/features/online-detection/renderer/index.html
Normal file
17
docs/fiddles/features/online-detection/renderer/index.html
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Hello World!</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
<p>
|
||||||
|
We are using node <script>document.write(process.versions.node)</script>,
|
||||||
|
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||||
|
and Electron <script>document.write(process.versions.electron)</script>.
|
||||||
|
</p>
|
||||||
|
<script src="renderer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
20
docs/fiddles/features/online-detection/renderer/main.js
Normal file
20
docs/fiddles/features/online-detection/renderer/main.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
const { app, BrowserWindow } = require('electron')
|
||||||
|
|
||||||
|
let onlineStatusWindow
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false })
|
||||||
|
onlineStatusWindow.loadURL(`file://${__dirname}/index.html`)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
const alertOnlineStatus = () => { window.alert(navigator.onLine ? 'online' : 'offline') }
|
||||||
|
|
||||||
|
window.addEventListener('online', alertOnlineStatus)
|
||||||
|
window.addEventListener('offline', alertOnlineStatus)
|
||||||
|
|
||||||
|
alertOnlineStatus()
|
||||||
16
docs/fiddles/features/progress-bar/index.html
Normal file
16
docs/fiddles/features/progress-bar/index.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Hello World!</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
<p>
|
||||||
|
We are using node <script>document.write(process.versions.node)</script>,
|
||||||
|
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||||
|
and Electron <script>document.write(process.versions.electron)</script>.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
30
docs/fiddles/features/progress-bar/main.js
Normal file
30
docs/fiddles/features/progress-bar/main.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
const { app, BrowserWindow } = require('electron')
|
||||||
|
|
||||||
|
function createWindow () {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
win.loadFile('index.html')
|
||||||
|
win.setProgressBar(0.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
app.whenReady().then(createWindow)
|
||||||
|
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
16
docs/fiddles/features/recent-documents/index.html
Normal file
16
docs/fiddles/features/recent-documents/index.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Hello World!</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
<p>
|
||||||
|
We are using node <script>document.write(process.versions.node)</script>,
|
||||||
|
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||||
|
and Electron <script>document.write(process.versions.electron)</script>.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
34
docs/fiddles/features/recent-documents/main.js
Normal file
34
docs/fiddles/features/recent-documents/main.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
const { app, BrowserWindow } = require('electron')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
function createWindow () {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
win.loadFile('index.html')
|
||||||
|
}
|
||||||
|
const fileName = 'recently-used.md'
|
||||||
|
fs.writeFile(fileName, 'Lorem Ipsum', () => {
|
||||||
|
app.addRecentDocument(path.join(process.cwd(), `${fileName}`))
|
||||||
|
})
|
||||||
|
|
||||||
|
app.whenReady().then(createWindow)
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
app.clearRecentDocuments()
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
16
docs/fiddles/features/represented-file/index.html
Normal file
16
docs/fiddles/features/represented-file/index.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Hello World!</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
<p>
|
||||||
|
We are using node <script>document.write(process.versions.node)</script>,
|
||||||
|
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||||
|
and Electron <script>document.write(process.versions.electron)</script>.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
33
docs/fiddles/features/represented-file/main.js
Normal file
33
docs/fiddles/features/represented-file/main.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
const { app, BrowserWindow } = require('electron')
|
||||||
|
const os = require('os');
|
||||||
|
|
||||||
|
function createWindow () {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
win.loadFile('index.html')
|
||||||
|
}
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
const win = new BrowserWindow()
|
||||||
|
|
||||||
|
win.setRepresentedFilename(os.homedir())
|
||||||
|
win.setDocumentEdited(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
16
docs/fiddles/quick-start/index.html
Normal file
16
docs/fiddles/quick-start/index.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Hello World!</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World!</h1>
|
||||||
|
<p>
|
||||||
|
We are using node <script>document.write(process.versions.node)</script>,
|
||||||
|
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||||
|
and Electron <script>document.write(process.versions.electron)</script>.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
27
docs/fiddles/quick-start/main.js
Normal file
27
docs/fiddles/quick-start/main.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
const { app, BrowserWindow } = require('electron')
|
||||||
|
|
||||||
|
function createWindow () {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
win.loadFile('index.html')
|
||||||
|
}
|
||||||
|
|
||||||
|
app.whenReady().then(createWindow)
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -818,7 +818,7 @@ which potential security issues are not as widely known.
|
|||||||
[browser-view]: ../api/browser-view.md
|
[browser-view]: ../api/browser-view.md
|
||||||
[webview-tag]: ../api/webview-tag.md
|
[webview-tag]: ../api/webview-tag.md
|
||||||
[web-contents]: ../api/web-contents.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
|
[will-navigate]: ../api/web-contents.md#event-will-navigate
|
||||||
[open-external]: ../api/shell.md#shellopenexternalurl-options
|
[open-external]: ../api/shell.md#shellopenexternalurl-options
|
||||||
[sandbox]: ../api/sandbox-option.md
|
[sandbox]: ../api/sandbox-option.md
|
||||||
|
|||||||
@@ -689,7 +689,8 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
|||||||
if (info.size === 0) return ['', false];
|
if (info.size === 0) return ['', false];
|
||||||
if (info.unpacked) {
|
if (info.unpacked) {
|
||||||
const realPath = archive.copyFileOut(filePath);
|
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);
|
logASARAccess(asarPath, filePath, info.offset);
|
||||||
|
|||||||
@@ -51,10 +51,6 @@ class CrashReporter {
|
|||||||
return binding.getUploadedReports();
|
return binding.getUploadedReports();
|
||||||
}
|
}
|
||||||
|
|
||||||
getCrashesDirectory () {
|
|
||||||
return app.getPath('crashDumps');
|
|
||||||
}
|
|
||||||
|
|
||||||
getUploadToServer () {
|
getUploadToServer () {
|
||||||
if (process.type === 'browser') {
|
if (process.type === 'browser') {
|
||||||
return binding.getUploadToServer();
|
return binding.getUploadToServer();
|
||||||
|
|||||||
@@ -16,5 +16,23 @@ export default new Proxy({}, {
|
|||||||
return v.bind(_screen);
|
return v.bind(_screen);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
|
},
|
||||||
|
ownKeys: () => {
|
||||||
|
if (_screen === undefined) {
|
||||||
|
_screen = createScreen();
|
||||||
|
}
|
||||||
|
return Reflect.ownKeys(_screen);
|
||||||
|
},
|
||||||
|
has: (target, prop: string) => {
|
||||||
|
if (_screen === undefined) {
|
||||||
|
_screen = createScreen();
|
||||||
|
}
|
||||||
|
return prop in _screen;
|
||||||
|
},
|
||||||
|
getOwnPropertyDescriptor: (target, prop: string) => {
|
||||||
|
if (_screen === undefined) {
|
||||||
|
_screen = createScreen();
|
||||||
|
}
|
||||||
|
return Reflect.getOwnPropertyDescriptor(_screen, prop);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { app } from 'electron/main';
|
import { app } from 'electron/main';
|
||||||
import type { WebContents } 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 * as fs from 'fs';
|
||||||
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
|
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
|
||||||
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
|
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);
|
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) => {
|
ipcMainInternal.handle(IPC_MESSAGES.NATIVE_IMAGE_CREATE_THUMBNAIL_FROM_PATH, async (_, path: string, size: Electron.Size) => {
|
||||||
return typeUtils.serialize(await nativeImage.createThumbnailFromPath(path, size));
|
return typeUtils.serialize(await nativeImage.createThumbnailFromPath(path, size));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,12 +5,6 @@ export const enum IPC_MESSAGES {
|
|||||||
BROWSER_SANDBOX_LOAD = 'BROWSER_SANDBOX_LOAD',
|
BROWSER_SANDBOX_LOAD = 'BROWSER_SANDBOX_LOAD',
|
||||||
BROWSER_WINDOW_CLOSE = 'BROWSER_WINDOW_CLOSE',
|
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_INSTANCE_VISIBILITY_CHANGE = 'GUEST_INSTANCE_VISIBILITY_CHANGE',
|
||||||
|
|
||||||
GUEST_VIEW_INTERNAL_DESTROY_GUEST = 'GUEST_VIEW_INTERNAL_DESTROY_GUEST',
|
GUEST_VIEW_INTERNAL_DESTROY_GUEST = 'GUEST_VIEW_INTERNAL_DESTROY_GUEST',
|
||||||
|
|||||||
@@ -1,42 +1,6 @@
|
|||||||
import { invokeSync } from '../ipc-renderer-internal-utils';
|
|
||||||
import { deprecate } from 'electron';
|
|
||||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
|
||||||
|
|
||||||
const binding = process._linkedBinding('electron_renderer_crash_reporter');
|
const binding = process._linkedBinding('electron_renderer_crash_reporter');
|
||||||
|
|
||||||
export default {
|
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) {
|
addExtraParameter (key: string, value: string) {
|
||||||
binding.addExtraParameter(key, value);
|
binding.addExtraParameter(key, value);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "electron",
|
"name": "electron",
|
||||||
"version": "12.0.0-nightly.20201118",
|
"version": "12.0.0-beta.6",
|
||||||
"repository": "https://github.com/electron/electron",
|
"repository": "https://github.com/electron/electron",
|
||||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -103,3 +103,4 @@ fix_use_electron_generated_resources.patch
|
|||||||
chore_expose_v8_initialization_isolate_callbacks.patch
|
chore_expose_v8_initialization_isolate_callbacks.patch
|
||||||
export_gin_v8platform_pageallocator_for_usage_outside_of_the_gin.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
|
use_public_apis_to_determine_if_a_font_is_a_system_font_in_mas_build.patch
|
||||||
|
cherry-pick-47e21abe349a.patch
|
||||||
|
|||||||
727
patches/chromium/cherry-pick-47e21abe349a.patch
Normal file
727
patches/chromium/cherry-pick-47e21abe349a.patch
Normal file
@@ -0,0 +1,727 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Martin Robinson <mrobinson@igalia.com>
|
||||||
|
Date: Thu, 19 Nov 2020 21:28:45 +0000
|
||||||
|
Subject: Improve AXTextStateChangeType in
|
||||||
|
NSAccessibilitySelectedTextChangedNotification
|
||||||
|
|
||||||
|
When setting the AXTextStateChangeType key in the user info data
|
||||||
|
structure for the notification, use AXTextStateChangeTypeSelectionMove
|
||||||
|
when we detect a focus change. This causes VoiceOver to properly
|
||||||
|
announce the label and type of form entries when their contents are
|
||||||
|
selected due to focus changes.
|
||||||
|
|
||||||
|
type are now announced.
|
||||||
|
|
||||||
|
Bug: 1127421
|
||||||
|
Change-Id: I42d66ad60fbcba7c8c34396fdbc3f6e0c739d1a2
|
||||||
|
AX-Relnotes: When focus changes moves to form inputs, the input label and
|
||||||
|
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2512913
|
||||||
|
Commit-Queue: Martin Robinson <mrobinson@igalia.com>
|
||||||
|
Reviewed-by: Nektarios Paisios <nektar@chromium.org>
|
||||||
|
Cr-Commit-Position: refs/heads/master@{#829380}
|
||||||
|
|
||||||
|
diff --git a/content/browser/accessibility/accessibility_event_recorder_mac.mm b/content/browser/accessibility/accessibility_event_recorder_mac.mm
|
||||||
|
index 6efa579decbfef81ddd38b27696133f7f68673ee..cdf4f8f87cf1554044e698f8b85c0f8a28a741e8 100644
|
||||||
|
--- a/content/browser/accessibility/accessibility_event_recorder_mac.mm
|
||||||
|
+++ b/content/browser/accessibility/accessibility_event_recorder_mac.mm
|
||||||
|
@@ -6,6 +6,7 @@
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
+#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "base/logging.h"
|
||||||
|
@@ -15,6 +16,7 @@
|
||||||
|
#include "base/strings/sys_string_conversions.h"
|
||||||
|
#include "content/browser/accessibility/accessibility_tools_utils_mac.h"
|
||||||
|
#include "content/browser/accessibility/browser_accessibility_manager.h"
|
||||||
|
+#include "ui/accessibility/platform/ax_private_webkit_constants_mac.h"
|
||||||
|
|
||||||
|
namespace content {
|
||||||
|
|
||||||
|
@@ -28,7 +30,11 @@
|
||||||
|
~AccessibilityEventRecorderMac() override;
|
||||||
|
|
||||||
|
// Callback executed every time we receive an event notification.
|
||||||
|
- void EventReceived(AXUIElementRef element, CFStringRef notification);
|
||||||
|
+ void EventReceived(AXUIElementRef element,
|
||||||
|
+ CFStringRef notification,
|
||||||
|
+ CFDictionaryRef user_info);
|
||||||
|
+ static std::string SerializeTextSelectionChangedProperties(
|
||||||
|
+ CFDictionaryRef user_info);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Add one notification to the list of notifications monitored by our
|
||||||
|
@@ -54,10 +60,11 @@
|
||||||
|
static void EventReceivedThunk(AXObserverRef observer_ref,
|
||||||
|
AXUIElementRef element,
|
||||||
|
CFStringRef notification,
|
||||||
|
+ CFDictionaryRef user_info,
|
||||||
|
void* refcon) {
|
||||||
|
AccessibilityEventRecorderMac* this_ptr =
|
||||||
|
static_cast<AccessibilityEventRecorderMac*>(refcon);
|
||||||
|
- this_ptr->EventReceived(element, notification);
|
||||||
|
+ this_ptr->EventReceived(element, notification, user_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
@@ -95,8 +102,9 @@ static void EventReceivedThunk(AXObserverRef observer_ref,
|
||||||
|
base::ProcessId pid,
|
||||||
|
AXUIElementRef node)
|
||||||
|
: AccessibilityEventRecorder(manager), observer_run_loop_source_(NULL) {
|
||||||
|
- if (kAXErrorSuccess != AXObserverCreate(pid, EventReceivedThunk,
|
||||||
|
- observer_ref_.InitializeInto())) {
|
||||||
|
+ if (kAXErrorSuccess !=
|
||||||
|
+ AXObserverCreateWithInfoCallback(pid, EventReceivedThunk,
|
||||||
|
+ observer_ref_.InitializeInto())) {
|
||||||
|
LOG(FATAL) << "Failed to create AXObserverRef";
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -157,7 +165,8 @@ static void EventReceivedThunk(AXObserverRef observer_ref,
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccessibilityEventRecorderMac::EventReceived(AXUIElementRef element,
|
||||||
|
- CFStringRef notification) {
|
||||||
|
+ CFStringRef notification,
|
||||||
|
+ CFDictionaryRef user_info) {
|
||||||
|
std::string notification_str = base::SysCFStringRefToUTF8(notification);
|
||||||
|
std::string role = GetAXAttributeValue(element, NSAccessibilityRoleAttribute);
|
||||||
|
if (role.empty())
|
||||||
|
@@ -180,7 +189,49 @@ static void EventReceivedThunk(AXObserverRef observer_ref,
|
||||||
|
if (!value.empty())
|
||||||
|
log += base::StringPrintf(" AXValue=\"%s\"", value.c_str());
|
||||||
|
|
||||||
|
+ if (notification_str ==
|
||||||
|
+ base::SysNSStringToUTF8(NSAccessibilitySelectedTextChangedNotification))
|
||||||
|
+ log += " " + SerializeTextSelectionChangedProperties(user_info);
|
||||||
|
+
|
||||||
|
OnEvent(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
+std::string
|
||||||
|
+AccessibilityEventRecorderMac::SerializeTextSelectionChangedProperties(
|
||||||
|
+ CFDictionaryRef user_info) {
|
||||||
|
+ std::vector<std::string> serialized_info;
|
||||||
|
+ CFDictionaryApplyFunction(
|
||||||
|
+ user_info,
|
||||||
|
+ [](const void* raw_key, const void* raw_value, void* context) {
|
||||||
|
+ auto* key = static_cast<NSString*>(raw_key);
|
||||||
|
+ auto* value = static_cast<NSObject*>(raw_value);
|
||||||
|
+ auto* serialized_info = static_cast<std::vector<std::string>*>(context);
|
||||||
|
+ std::string value_string;
|
||||||
|
+ if ([key isEqual:ui::NSAccessibilityTextStateChangeTypeKey]) {
|
||||||
|
+ value_string = ToString(static_cast<ui::AXTextStateChangeType>(
|
||||||
|
+ [static_cast<NSNumber*>(value) intValue]));
|
||||||
|
+ } else if ([key isEqual:ui::NSAccessibilityTextSelectionDirection]) {
|
||||||
|
+ value_string = ToString(static_cast<ui::AXTextSelectionDirection>(
|
||||||
|
+ [static_cast<NSNumber*>(value) intValue]));
|
||||||
|
+ } else if ([key isEqual:ui::NSAccessibilityTextSelectionGranularity]) {
|
||||||
|
+ value_string = ToString(static_cast<ui::AXTextSelectionGranularity>(
|
||||||
|
+ [static_cast<NSNumber*>(value) intValue]));
|
||||||
|
+ } else if ([key isEqual:ui::NSAccessibilityTextEditType]) {
|
||||||
|
+ value_string = ToString(static_cast<ui::AXTextEditType>(
|
||||||
|
+ [static_cast<NSNumber*>(value) intValue]));
|
||||||
|
+ } else {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ serialized_info->push_back(base::SysNSStringToUTF8(key) + "=" +
|
||||||
|
+ value_string);
|
||||||
|
+ },
|
||||||
|
+ &serialized_info);
|
||||||
|
+
|
||||||
|
+ // Always sort the info so that we don't depend on CFDictionary for
|
||||||
|
+ // consistent output ordering.
|
||||||
|
+ std::sort(serialized_info.begin(), serialized_info.end());
|
||||||
|
+
|
||||||
|
+ return base::JoinString(serialized_info, " ");
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
} // namespace content
|
||||||
|
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.h b/content/browser/accessibility/browser_accessibility_manager_mac.h
|
||||||
|
index b4043f56341e72bcf75ef71c56cb8cf9fc442579..925bfe1ea191ab846805fdbff1b0314e779b1c9e 100644
|
||||||
|
--- a/content/browser/accessibility/browser_accessibility_manager_mac.h
|
||||||
|
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.h
|
||||||
|
@@ -54,7 +54,8 @@ class CONTENT_EXPORT BrowserAccessibilityManagerMac
|
||||||
|
const std::vector<Change>& changes) override;
|
||||||
|
|
||||||
|
// Returns an autoreleased object.
|
||||||
|
- NSDictionary* GetUserInfoForSelectedTextChangedNotification();
|
||||||
|
+ NSDictionary* GetUserInfoForSelectedTextChangedNotification(
|
||||||
|
+ bool focus_changed);
|
||||||
|
|
||||||
|
// Returns an autoreleased object.
|
||||||
|
NSDictionary* GetUserInfoForValueChangedNotification(
|
||||||
|
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm
|
||||||
|
index 122e517ddcb3944847fc289eb45c87d5fb156afc..5a2b73f664646efc0bc8e506e93b179b8e96635a 100644
|
||||||
|
--- a/content/browser/accessibility/browser_accessibility_manager_mac.mm
|
||||||
|
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
|
||||||
|
@@ -19,91 +19,13 @@
|
||||||
|
#include "content/public/browser/web_contents.h"
|
||||||
|
#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
|
||||||
|
#include "ui/accessibility/ax_role_properties.h"
|
||||||
|
+#include "ui/accessibility/platform/ax_private_webkit_constants_mac.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Use same value as in Safari's WebKit.
|
||||||
|
const int kLiveRegionChangeIntervalMS = 20;
|
||||||
|
|
||||||
|
-// Declare undocumented accessibility constants and enums only present in
|
||||||
|
-// WebKit.
|
||||||
|
-
|
||||||
|
-enum AXTextStateChangeType {
|
||||||
|
- AXTextStateChangeTypeUnknown,
|
||||||
|
- AXTextStateChangeTypeEdit,
|
||||||
|
- AXTextStateChangeTypeSelectionMove,
|
||||||
|
- AXTextStateChangeTypeSelectionExtend
|
||||||
|
-};
|
||||||
|
-
|
||||||
|
-enum AXTextSelectionDirection {
|
||||||
|
- AXTextSelectionDirectionUnknown,
|
||||||
|
- AXTextSelectionDirectionBeginning,
|
||||||
|
- AXTextSelectionDirectionEnd,
|
||||||
|
- AXTextSelectionDirectionPrevious,
|
||||||
|
- AXTextSelectionDirectionNext,
|
||||||
|
- AXTextSelectionDirectionDiscontiguous
|
||||||
|
-};
|
||||||
|
-
|
||||||
|
-enum AXTextSelectionGranularity {
|
||||||
|
- AXTextSelectionGranularityUnknown,
|
||||||
|
- AXTextSelectionGranularityCharacter,
|
||||||
|
- AXTextSelectionGranularityWord,
|
||||||
|
- AXTextSelectionGranularityLine,
|
||||||
|
- AXTextSelectionGranularitySentence,
|
||||||
|
- AXTextSelectionGranularityParagraph,
|
||||||
|
- AXTextSelectionGranularityPage,
|
||||||
|
- AXTextSelectionGranularityDocument,
|
||||||
|
- AXTextSelectionGranularityAll
|
||||||
|
-};
|
||||||
|
-
|
||||||
|
-enum AXTextEditType {
|
||||||
|
- AXTextEditTypeUnknown,
|
||||||
|
- AXTextEditTypeDelete,
|
||||||
|
- AXTextEditTypeInsert,
|
||||||
|
- AXTextEditTypeTyping,
|
||||||
|
- AXTextEditTypeDictation,
|
||||||
|
- AXTextEditTypeCut,
|
||||||
|
- AXTextEditTypePaste,
|
||||||
|
- AXTextEditTypeAttributesChange
|
||||||
|
-};
|
||||||
|
-
|
||||||
|
-// Native mac notifications fired.
|
||||||
|
-NSString* const NSAccessibilityAutocorrectionOccurredNotification =
|
||||||
|
- @"AXAutocorrectionOccurred";
|
||||||
|
-NSString* const NSAccessibilityLoadCompleteNotification = @"AXLoadComplete";
|
||||||
|
-NSString* const NSAccessibilityInvalidStatusChangedNotification =
|
||||||
|
- @"AXInvalidStatusChanged";
|
||||||
|
-NSString* const NSAccessibilityLiveRegionCreatedNotification =
|
||||||
|
- @"AXLiveRegionCreated";
|
||||||
|
-NSString* const NSAccessibilityLiveRegionChangedNotification =
|
||||||
|
- @"AXLiveRegionChanged";
|
||||||
|
-NSString* const NSAccessibilityExpandedChanged = @"AXExpandedChanged";
|
||||||
|
-NSString* const NSAccessibilityMenuItemSelectedNotification =
|
||||||
|
- @"AXMenuItemSelected";
|
||||||
|
-
|
||||||
|
-// The following native mac notifications are not fired:
|
||||||
|
-// AXLayoutComplete: Voiceover does not use this, it is considered too spammy.
|
||||||
|
-
|
||||||
|
-// Attributes used for NSAccessibilitySelectedTextChangedNotification and
|
||||||
|
-// NSAccessibilityValueChangedNotification.
|
||||||
|
-NSString* const NSAccessibilityTextStateChangeTypeKey =
|
||||||
|
- @"AXTextStateChangeType";
|
||||||
|
-NSString* const NSAccessibilityTextStateSyncKey = @"AXTextStateSync";
|
||||||
|
-NSString* const NSAccessibilityTextSelectionDirection =
|
||||||
|
- @"AXTextSelectionDirection";
|
||||||
|
-NSString* const NSAccessibilityTextSelectionGranularity =
|
||||||
|
- @"AXTextSelectionGranularity";
|
||||||
|
-NSString* const NSAccessibilityTextSelectionChangedFocus =
|
||||||
|
- @"AXTextSelectionChangedFocus";
|
||||||
|
-NSString* const NSAccessibilityTextChangeElement = @"AXTextChangeElement";
|
||||||
|
-NSString* const NSAccessibilityTextEditType = @"AXTextEditType";
|
||||||
|
-NSString* const NSAccessibilityTextChangeValue = @"AXTextChangeValue";
|
||||||
|
-NSString* const NSAccessibilityChangeValueStartMarker =
|
||||||
|
- @"AXTextChangeValueStartMarker";
|
||||||
|
-NSString* const NSAccessibilityTextChangeValueLength =
|
||||||
|
- @"AXTextChangeValueLength";
|
||||||
|
-NSString* const NSAccessibilityTextChangeValues = @"AXTextChangeValues";
|
||||||
|
-
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace content {
|
||||||
|
@@ -164,7 +86,7 @@
|
||||||
|
NSString* mac_notification = nullptr;
|
||||||
|
switch (event_type) {
|
||||||
|
case ax::mojom::Event::kAutocorrectionOccured:
|
||||||
|
- mac_notification = NSAccessibilityAutocorrectionOccurredNotification;
|
||||||
|
+ mac_notification = ui::NSAccessibilityAutocorrectionOccurredNotification;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
@@ -203,6 +125,8 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||||
|
auto native_node = ToBrowserAccessibilityCocoa(node);
|
||||||
|
DCHECK(native_node);
|
||||||
|
|
||||||
|
+ bool focus_changed = GetFocus() != GetLastFocusedNode();
|
||||||
|
+
|
||||||
|
// Refer to |AXObjectCache::postPlatformNotification| in WebKit source code.
|
||||||
|
NSString* mac_notification = nullptr;
|
||||||
|
switch (event_type) {
|
||||||
|
@@ -223,7 +147,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||||
|
break;
|
||||||
|
case ui::AXEventGenerator::Event::ALERT:
|
||||||
|
NSAccessibilityPostNotification(
|
||||||
|
- native_node, NSAccessibilityLiveRegionCreatedNotification);
|
||||||
|
+ native_node, ui::NSAccessibilityLiveRegionCreatedNotification);
|
||||||
|
// Voiceover requires a live region changed notification to actually
|
||||||
|
// announce the live region.
|
||||||
|
FireGeneratedEvent(ui::AXEventGenerator::Event::LIVE_REGION_CHANGED,
|
||||||
|
@@ -242,7 +166,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||||
|
node->GetRole() == ax::mojom::Role::kTreeItem) {
|
||||||
|
mac_notification = NSAccessibilityRowCollapsedNotification;
|
||||||
|
} else {
|
||||||
|
- mac_notification = NSAccessibilityExpandedChanged;
|
||||||
|
+ mac_notification = ui::NSAccessibilityExpandedChanged;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ui::AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED: {
|
||||||
|
@@ -259,7 +183,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||||
|
// API has been present on versions of OS X since 10.7 but doesn't
|
||||||
|
// appear to be needed by Voiceover before version 10.11.
|
||||||
|
NSDictionary* user_info =
|
||||||
|
- GetUserInfoForSelectedTextChangedNotification();
|
||||||
|
+ GetUserInfoForSelectedTextChangedNotification(focus_changed);
|
||||||
|
|
||||||
|
BrowserAccessibilityManager* root_manager = GetRootManager();
|
||||||
|
if (!root_manager)
|
||||||
|
@@ -284,11 +208,11 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||||
|
node->GetRole() == ax::mojom::Role::kTreeItem) {
|
||||||
|
mac_notification = NSAccessibilityRowExpandedNotification;
|
||||||
|
} else {
|
||||||
|
- mac_notification = NSAccessibilityExpandedChanged;
|
||||||
|
+ mac_notification = ui::NSAccessibilityExpandedChanged;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ui::AXEventGenerator::Event::INVALID_STATUS_CHANGED:
|
||||||
|
- mac_notification = NSAccessibilityInvalidStatusChangedNotification;
|
||||||
|
+ mac_notification = ui::NSAccessibilityInvalidStatusChangedNotification;
|
||||||
|
break;
|
||||||
|
case ui::AXEventGenerator::Event::LIVE_REGION_CHANGED: {
|
||||||
|
// Voiceover seems to drop live region changed notifications if they come
|
||||||
|
@@ -297,7 +221,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||||
|
|
||||||
|
if (never_suppress_or_delay_events_for_testing_) {
|
||||||
|
NSAccessibilityPostNotification(
|
||||||
|
- native_node, NSAccessibilityLiveRegionChangedNotification);
|
||||||
|
+ native_node, ui::NSAccessibilityLiveRegionChangedNotification);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -321,7 +245,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||||
|
[](base::scoped_nsobject<BrowserAccessibilityCocoa> node) {
|
||||||
|
if (node && [node instanceActive]) {
|
||||||
|
NSAccessibilityPostNotification(
|
||||||
|
- node, NSAccessibilityLiveRegionChangedNotification);
|
||||||
|
+ node, ui::NSAccessibilityLiveRegionChangedNotification);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
std::move(retained_node)),
|
||||||
|
@@ -329,7 +253,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case ui::AXEventGenerator::Event::LIVE_REGION_CREATED:
|
||||||
|
- mac_notification = NSAccessibilityLiveRegionCreatedNotification;
|
||||||
|
+ mac_notification = ui::NSAccessibilityLiveRegionCreatedNotification;
|
||||||
|
break;
|
||||||
|
case ui::AXEventGenerator::Event::LOAD_COMPLETE:
|
||||||
|
// On MacOS 10.15, firing AXLoadComplete causes focus to move to the
|
||||||
|
@@ -343,7 +267,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||||
|
// |NSAccessibilityLoadCompleteNotification| should only be fired on the
|
||||||
|
// top document and when the document is not Chrome's new tab page.
|
||||||
|
if (IsRootTree() && !IsChromeNewTabPage()) {
|
||||||
|
- mac_notification = NSAccessibilityLoadCompleteNotification;
|
||||||
|
+ mac_notification = ui::NSAccessibilityLoadCompleteNotification;
|
||||||
|
} else {
|
||||||
|
// Voiceover moves focus to the web content when it receives an
|
||||||
|
// AXLoadComplete event. On Chrome's new tab page, focus should stay
|
||||||
|
@@ -353,7 +277,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ui::AXEventGenerator::Event::MENU_ITEM_SELECTED:
|
||||||
|
- mac_notification = NSAccessibilityMenuItemSelectedNotification;
|
||||||
|
+ mac_notification = ui::NSAccessibilityMenuItemSelectedNotification;
|
||||||
|
break;
|
||||||
|
case ui::AXEventGenerator::Event::RANGE_VALUE_CHANGED:
|
||||||
|
DCHECK(node->GetData().IsRangeValueSupported());
|
||||||
|
@@ -532,18 +456,32 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-NSDictionary* BrowserAccessibilityManagerMac::
|
||||||
|
- GetUserInfoForSelectedTextChangedNotification() {
|
||||||
|
+NSDictionary*
|
||||||
|
+BrowserAccessibilityManagerMac::GetUserInfoForSelectedTextChangedNotification(
|
||||||
|
+ bool focus_changed) {
|
||||||
|
NSMutableDictionary* user_info =
|
||||||
|
[[[NSMutableDictionary alloc] init] autorelease];
|
||||||
|
- [user_info setObject:@YES forKey:NSAccessibilityTextStateSyncKey];
|
||||||
|
- [user_info setObject:@(AXTextStateChangeTypeUnknown)
|
||||||
|
- forKey:NSAccessibilityTextStateChangeTypeKey];
|
||||||
|
- [user_info setObject:@(AXTextSelectionDirectionUnknown)
|
||||||
|
- forKey:NSAccessibilityTextSelectionDirection];
|
||||||
|
- [user_info setObject:@(AXTextSelectionGranularityUnknown)
|
||||||
|
- forKey:NSAccessibilityTextSelectionGranularity];
|
||||||
|
- [user_info setObject:@YES forKey:NSAccessibilityTextSelectionChangedFocus];
|
||||||
|
+ [user_info setObject:@YES forKey:ui::NSAccessibilityTextStateSyncKey];
|
||||||
|
+ [user_info setObject:@(ui::AXTextSelectionDirectionUnknown)
|
||||||
|
+ forKey:ui::NSAccessibilityTextSelectionDirection];
|
||||||
|
+ [user_info setObject:@(ui::AXTextSelectionGranularityUnknown)
|
||||||
|
+ forKey:ui::NSAccessibilityTextSelectionGranularity];
|
||||||
|
+ [user_info setObject:@YES
|
||||||
|
+ forKey:ui::NSAccessibilityTextSelectionChangedFocus];
|
||||||
|
+
|
||||||
|
+ // Try to detect when the text selection changes due to a focus change.
|
||||||
|
+ // This is necessary so that VoiceOver also anounces information about the
|
||||||
|
+ // element that contains this selection.
|
||||||
|
+ // TODO(mrobinson): Determine definitively what the type of this text
|
||||||
|
+ // selection change is. This requires passing this information here from
|
||||||
|
+ // blink.
|
||||||
|
+ if (focus_changed) {
|
||||||
|
+ [user_info setObject:@(ui::AXTextStateChangeTypeSelectionMove)
|
||||||
|
+ forKey:ui::NSAccessibilityTextStateChangeTypeKey];
|
||||||
|
+ } else {
|
||||||
|
+ [user_info setObject:@(ui::AXTextStateChangeTypeUnknown)
|
||||||
|
+ forKey:ui::NSAccessibilityTextStateChangeTypeKey];
|
||||||
|
+ }
|
||||||
|
|
||||||
|
int32_t focus_id = ax_tree()->GetUnignoredSelection().focus_object_id;
|
||||||
|
BrowserAccessibility* focus_object = GetFromID(focus_id);
|
||||||
|
@@ -552,7 +490,7 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||||
|
auto native_focus_object = ToBrowserAccessibilityCocoa(focus_object);
|
||||||
|
if (native_focus_object && [native_focus_object instanceActive]) {
|
||||||
|
[user_info setObject:native_focus_object
|
||||||
|
- forKey:NSAccessibilityTextChangeElement];
|
||||||
|
+ forKey:ui::NSAccessibilityTextChangeElement];
|
||||||
|
|
||||||
|
#ifndef MAS_BUILD
|
||||||
|
id selected_text = [native_focus_object selectedTextMarkerRange];
|
||||||
|
@@ -583,38 +521,39 @@ void PostAnnouncementNotification(NSString* announcement) {
|
||||||
|
if (!deleted_text.empty()) {
|
||||||
|
NSMutableDictionary* change =
|
||||||
|
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||||
|
- NSAccessibilityTextEditType : @(AXTextEditTypeDelete),
|
||||||
|
- NSAccessibilityTextChangeValueLength : @(deleted_text.length()),
|
||||||
|
- NSAccessibilityTextChangeValue :
|
||||||
|
+ ui::NSAccessibilityTextEditType : @(ui::AXTextEditTypeDelete),
|
||||||
|
+ ui::NSAccessibilityTextChangeValueLength : @(deleted_text.length()),
|
||||||
|
+ ui::NSAccessibilityTextChangeValue :
|
||||||
|
base::SysUTF16ToNSString(deleted_text)
|
||||||
|
}];
|
||||||
|
if (edit_text_marker) {
|
||||||
|
- change[NSAccessibilityChangeValueStartMarker] = edit_text_marker;
|
||||||
|
+ change[ui::NSAccessibilityChangeValueStartMarker] = edit_text_marker;
|
||||||
|
}
|
||||||
|
[changes addObject:change];
|
||||||
|
}
|
||||||
|
if (!inserted_text.empty()) {
|
||||||
|
// TODO(nektar): Figure out if this is a paste, insertion or typing.
|
||||||
|
// Changes to Blink would be required. A heuristic is currently used.
|
||||||
|
- auto edit_type = inserted_text.length() > 1 ? @(AXTextEditTypeInsert)
|
||||||
|
- : @(AXTextEditTypeTyping);
|
||||||
|
+ auto edit_type = inserted_text.length() > 1 ? @(ui::AXTextEditTypeInsert)
|
||||||
|
+ : @(ui::AXTextEditTypeTyping);
|
||||||
|
NSMutableDictionary* change =
|
||||||
|
[NSMutableDictionary dictionaryWithDictionary:@{
|
||||||
|
- NSAccessibilityTextEditType : edit_type,
|
||||||
|
- NSAccessibilityTextChangeValueLength : @(inserted_text.length()),
|
||||||
|
- NSAccessibilityTextChangeValue :
|
||||||
|
+ ui::NSAccessibilityTextEditType : edit_type,
|
||||||
|
+ ui::NSAccessibilityTextChangeValueLength : @(inserted_text.length()),
|
||||||
|
+ ui::NSAccessibilityTextChangeValue :
|
||||||
|
base::SysUTF16ToNSString(inserted_text)
|
||||||
|
}];
|
||||||
|
if (edit_text_marker) {
|
||||||
|
- change[NSAccessibilityChangeValueStartMarker] = edit_text_marker;
|
||||||
|
+ change[ui::NSAccessibilityChangeValueStartMarker] = edit_text_marker;
|
||||||
|
}
|
||||||
|
[changes addObject:change];
|
||||||
|
}
|
||||||
|
|
||||||
|
return @{
|
||||||
|
- NSAccessibilityTextStateChangeTypeKey : @(AXTextStateChangeTypeEdit),
|
||||||
|
- NSAccessibilityTextChangeValues : changes,
|
||||||
|
- NSAccessibilityTextChangeElement : native_node
|
||||||
|
+ ui::
|
||||||
|
+ NSAccessibilityTextStateChangeTypeKey : @(ui::AXTextStateChangeTypeEdit),
|
||||||
|
+ ui::NSAccessibilityTextChangeValues : changes,
|
||||||
|
+ ui::NSAccessibilityTextChangeElement : native_node
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/content/test/data/accessibility/event/aria-combo-box-focus-expected-mac.txt b/content/test/data/accessibility/event/aria-combo-box-focus-expected-mac.txt
|
||||||
|
index ad5e2bf2c8029185c51eecc94cac1dbe7608c99e..67e07a89f77f7c61a57eb51cecea211df5227341 100644
|
||||||
|
--- a/content/test/data/accessibility/event/aria-combo-box-focus-expected-mac.txt
|
||||||
|
+++ b/content/test/data/accessibility/event/aria-combo-box-focus-expected-mac.txt
|
||||||
|
@@ -1,3 +1,3 @@
|
||||||
|
AXFocusedUIElementChanged on AXStaticText AXValue="Apple not selected"
|
||||||
|
-AXSelectedTextChanged on AXStaticText AXValue="Apple not selected"
|
||||||
|
-AXSelectedTextChanged on AXWebArea
|
||||||
|
\ No newline at end of file
|
||||||
|
+AXSelectedTextChanged on AXStaticText AXValue="Apple not selected" AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeSelectionMove
|
||||||
|
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeSelectionMove
|
||||||
|
diff --git a/content/test/data/accessibility/event/caret-browsing-disabled-expected-mac.txt b/content/test/data/accessibility/event/caret-browsing-disabled-expected-mac.txt
|
||||||
|
index ec0b74d984ade9928705242f9b0682a743e20fb2..87447c5a4b14efde5b64b1d340a3fa2fb6574b80 100644
|
||||||
|
--- a/content/test/data/accessibility/event/caret-browsing-disabled-expected-mac.txt
|
||||||
|
+++ b/content/test/data/accessibility/event/caret-browsing-disabled-expected-mac.txt
|
||||||
|
@@ -1,5 +1,5 @@
|
||||||
|
-AXSelectedTextChanged on AXWebArea
|
||||||
|
-AXSelectedTextChanged on AXWebArea
|
||||||
|
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||||
|
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||||
|
=== Start Continuation ===
|
||||||
|
-AXSelectedTextChanged on AXWebArea
|
||||||
|
-AXSelectedTextChanged on AXWebArea
|
||||||
|
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||||
|
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||||
|
diff --git a/content/test/data/accessibility/event/caret-browsing-enabled-expected-mac.txt b/content/test/data/accessibility/event/caret-browsing-enabled-expected-mac.txt
|
||||||
|
index ec0b74d984ade9928705242f9b0682a743e20fb2..87447c5a4b14efde5b64b1d340a3fa2fb6574b80 100644
|
||||||
|
--- a/content/test/data/accessibility/event/caret-browsing-enabled-expected-mac.txt
|
||||||
|
+++ b/content/test/data/accessibility/event/caret-browsing-enabled-expected-mac.txt
|
||||||
|
@@ -1,5 +1,5 @@
|
||||||
|
-AXSelectedTextChanged on AXWebArea
|
||||||
|
-AXSelectedTextChanged on AXWebArea
|
||||||
|
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||||
|
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||||
|
=== Start Continuation ===
|
||||||
|
-AXSelectedTextChanged on AXWebArea
|
||||||
|
-AXSelectedTextChanged on AXWebArea
|
||||||
|
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||||
|
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||||
|
diff --git a/content/test/data/accessibility/event/text-selection-changed-expected-mac.txt b/content/test/data/accessibility/event/text-selection-changed-expected-mac.txt
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..9213c873393d595bba8796cdb0e2325d3ee37ee9
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/content/test/data/accessibility/event/text-selection-changed-expected-mac.txt
|
||||||
|
@@ -0,0 +1,10 @@
|
||||||
|
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||||
|
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeUnknown
|
||||||
|
+=== Start Continuation ===
|
||||||
|
+AXFocusedUIElementChanged on AXTextField AXDescription="input" AXValue="input"
|
||||||
|
+AXSelectedTextChanged on AXTextField AXDescription="input" AXValue="input" AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeSelectionMove
|
||||||
|
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeSelectionMove
|
||||||
|
+=== Start Continuation ===
|
||||||
|
+AXFocusedUIElementChanged on AXTextArea AXDescription="textarea"
|
||||||
|
+AXSelectedTextChanged on AXTextArea AXDescription="textarea" AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeSelectionMove
|
||||||
|
+AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeSelectionMove
|
||||||
|
diff --git a/ui/accessibility/platform/BUILD.gn b/ui/accessibility/platform/BUILD.gn
|
||||||
|
index 99df759347f899a78dc37846e30598f82edb34f7..47d57fcf7aa02b5b2c5afab18a96666dda3b79bb 100644
|
||||||
|
--- a/ui/accessibility/platform/BUILD.gn
|
||||||
|
+++ b/ui/accessibility/platform/BUILD.gn
|
||||||
|
@@ -118,6 +118,8 @@ source_set("platform") {
|
||||||
|
"ax_event_intent_mac.mm",
|
||||||
|
"ax_platform_node_mac.h",
|
||||||
|
"ax_platform_node_mac.mm",
|
||||||
|
+ "ax_private_webkit_constants_mac.h",
|
||||||
|
+ "ax_private_webkit_constants_mac.mm",
|
||||||
|
]
|
||||||
|
|
||||||
|
frameworks = [
|
||||||
|
diff --git a/ui/accessibility/platform/ax_private_webkit_constants_mac.h b/ui/accessibility/platform/ax_private_webkit_constants_mac.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..5f1776a3aeac89b70d6d852b8e5209a1208271ae
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/ui/accessibility/platform/ax_private_webkit_constants_mac.h
|
||||||
|
@@ -0,0 +1,96 @@
|
||||||
|
+// Copyright 2020 The Chromium Authors. All rights reserved.
|
||||||
|
+// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
+// found in the LICENSE file.
|
||||||
|
+
|
||||||
|
+#ifndef UI_ACCESSIBILITY_PLATFORM_AX_PRIVATE_WEBKIT_CONSTANTS_MAC_H_
|
||||||
|
+#define UI_ACCESSIBILITY_PLATFORM_AX_PRIVATE_WEBKIT_CONSTANTS_MAC_H_
|
||||||
|
+
|
||||||
|
+#import <Cocoa/Cocoa.h>
|
||||||
|
+#include "ui/accessibility/ax_export.h"
|
||||||
|
+
|
||||||
|
+namespace ui {
|
||||||
|
+
|
||||||
|
+enum AXTextStateChangeType {
|
||||||
|
+ AXTextStateChangeTypeUnknown,
|
||||||
|
+ AXTextStateChangeTypeEdit,
|
||||||
|
+ AXTextStateChangeTypeSelectionMove,
|
||||||
|
+ AXTextStateChangeTypeSelectionExtend
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+enum AXTextSelectionDirection {
|
||||||
|
+ AXTextSelectionDirectionUnknown,
|
||||||
|
+ AXTextSelectionDirectionBeginning,
|
||||||
|
+ AXTextSelectionDirectionEnd,
|
||||||
|
+ AXTextSelectionDirectionPrevious,
|
||||||
|
+ AXTextSelectionDirectionNext,
|
||||||
|
+ AXTextSelectionDirectionDiscontiguous
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+enum AXTextSelectionGranularity {
|
||||||
|
+ AXTextSelectionGranularityUnknown,
|
||||||
|
+ AXTextSelectionGranularityCharacter,
|
||||||
|
+ AXTextSelectionGranularityWord,
|
||||||
|
+ AXTextSelectionGranularityLine,
|
||||||
|
+ AXTextSelectionGranularitySentence,
|
||||||
|
+ AXTextSelectionGranularityParagraph,
|
||||||
|
+ AXTextSelectionGranularityPage,
|
||||||
|
+ AXTextSelectionGranularityDocument,
|
||||||
|
+ AXTextSelectionGranularityAll
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+enum AXTextEditType {
|
||||||
|
+ AXTextEditTypeUnknown,
|
||||||
|
+ AXTextEditTypeDelete,
|
||||||
|
+ AXTextEditTypeInsert,
|
||||||
|
+ AXTextEditTypeTyping,
|
||||||
|
+ AXTextEditTypeDictation,
|
||||||
|
+ AXTextEditTypeCut,
|
||||||
|
+ AXTextEditTypePaste,
|
||||||
|
+ AXTextEditTypeAttributesChange
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+// Native mac notifications fired.
|
||||||
|
+NSString* const NSAccessibilityAutocorrectionOccurredNotification =
|
||||||
|
+ @"AXAutocorrectionOccurred";
|
||||||
|
+NSString* const NSAccessibilityLoadCompleteNotification = @"AXLoadComplete";
|
||||||
|
+NSString* const NSAccessibilityInvalidStatusChangedNotification =
|
||||||
|
+ @"AXInvalidStatusChanged";
|
||||||
|
+NSString* const NSAccessibilityLiveRegionCreatedNotification =
|
||||||
|
+ @"AXLiveRegionCreated";
|
||||||
|
+NSString* const NSAccessibilityLiveRegionChangedNotification =
|
||||||
|
+ @"AXLiveRegionChanged";
|
||||||
|
+NSString* const NSAccessibilityExpandedChanged = @"AXExpandedChanged";
|
||||||
|
+NSString* const NSAccessibilityMenuItemSelectedNotification =
|
||||||
|
+ @"AXMenuItemSelected";
|
||||||
|
+
|
||||||
|
+// The following native mac notifications are not fired:
|
||||||
|
+// AXLayoutComplete: Voiceover does not use this, it is considered too spammy.
|
||||||
|
+
|
||||||
|
+// Attributes used for NSAccessibilitySelectedTextChangedNotification and
|
||||||
|
+// NSAccessibilityValueChangedNotification.
|
||||||
|
+NSString* const NSAccessibilityTextStateChangeTypeKey =
|
||||||
|
+ @"AXTextStateChangeType";
|
||||||
|
+NSString* const NSAccessibilityTextStateSyncKey = @"AXTextStateSync";
|
||||||
|
+NSString* const NSAccessibilityTextSelectionDirection =
|
||||||
|
+ @"AXTextSelectionDirection";
|
||||||
|
+NSString* const NSAccessibilityTextSelectionGranularity =
|
||||||
|
+ @"AXTextSelectionGranularity";
|
||||||
|
+NSString* const NSAccessibilityTextSelectionChangedFocus =
|
||||||
|
+ @"AXTextSelectionChangedFocus";
|
||||||
|
+NSString* const NSAccessibilityTextChangeElement = @"AXTextChangeElement";
|
||||||
|
+NSString* const NSAccessibilityTextEditType = @"AXTextEditType";
|
||||||
|
+NSString* const NSAccessibilityTextChangeValue = @"AXTextChangeValue";
|
||||||
|
+NSString* const NSAccessibilityChangeValueStartMarker =
|
||||||
|
+ @"AXTextChangeValueStartMarker";
|
||||||
|
+NSString* const NSAccessibilityTextChangeValueLength =
|
||||||
|
+ @"AXTextChangeValueLength";
|
||||||
|
+NSString* const NSAccessibilityTextChangeValues = @"AXTextChangeValues";
|
||||||
|
+
|
||||||
|
+AX_EXPORT const char* ToString(AXTextStateChangeType);
|
||||||
|
+AX_EXPORT const char* ToString(AXTextSelectionDirection);
|
||||||
|
+AX_EXPORT const char* ToString(AXTextSelectionGranularity);
|
||||||
|
+AX_EXPORT const char* ToString(AXTextEditType);
|
||||||
|
+
|
||||||
|
+} // namespace ui
|
||||||
|
+
|
||||||
|
+#endif // UI_ACCESSIBILITY_PLATFORM_AX_PRIVATE_WEBKIT_CONSTANTS_MAC_H_
|
||||||
|
diff --git a/ui/accessibility/platform/ax_private_webkit_constants_mac.mm b/ui/accessibility/platform/ax_private_webkit_constants_mac.mm
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..7de31a487dd6e0e6a4af2f4fa62e463f41a0d96a
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/ui/accessibility/platform/ax_private_webkit_constants_mac.mm
|
||||||
|
@@ -0,0 +1,91 @@
|
||||||
|
+// Copyright 2020 The Chromium Authors. All rights reserved.
|
||||||
|
+// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
+// found in the LICENSE file.
|
||||||
|
+
|
||||||
|
+#include "ui/accessibility/platform/ax_private_webkit_constants_mac.h"
|
||||||
|
+
|
||||||
|
+namespace ui {
|
||||||
|
+
|
||||||
|
+const char* ToString(AXTextStateChangeType type) {
|
||||||
|
+ switch (type) {
|
||||||
|
+ case AXTextStateChangeTypeUnknown:
|
||||||
|
+ return "AXTextStateChangeTypeUnknown";
|
||||||
|
+ case AXTextStateChangeTypeEdit:
|
||||||
|
+ return "AXTextStateChangeTypeEdit";
|
||||||
|
+ case AXTextStateChangeTypeSelectionMove:
|
||||||
|
+ return "AXTextStateChangeTypeSelectionMove";
|
||||||
|
+ case AXTextStateChangeTypeSelectionExtend:
|
||||||
|
+ return "AXTextStateChangeTypeSelectionExtend";
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return "";
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+const char* ToString(AXTextSelectionDirection direction) {
|
||||||
|
+ switch (direction) {
|
||||||
|
+ case AXTextSelectionDirectionUnknown:
|
||||||
|
+ return "AXTextSelectionDirectionUnknown";
|
||||||
|
+ case AXTextSelectionDirectionBeginning:
|
||||||
|
+ return "AXTextSelectionDirectionBeginning";
|
||||||
|
+ case AXTextSelectionDirectionEnd:
|
||||||
|
+ return "AXTextSelectionDirectionEnd";
|
||||||
|
+ case AXTextSelectionDirectionPrevious:
|
||||||
|
+ return "AXTextSelectionDirectionPrevious";
|
||||||
|
+ case AXTextSelectionDirectionNext:
|
||||||
|
+ return "AXTextSelectionDirectionNext";
|
||||||
|
+ case AXTextSelectionDirectionDiscontiguous:
|
||||||
|
+ return "AXTextSelectionDirectionDiscontiguous";
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return "";
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+const char* ToString(AXTextSelectionGranularity granularity) {
|
||||||
|
+ switch (granularity) {
|
||||||
|
+ case AXTextSelectionGranularityUnknown:
|
||||||
|
+ return "AXTextSelectionGranularityUnknown";
|
||||||
|
+ case AXTextSelectionGranularityCharacter:
|
||||||
|
+ return "AXTextSelectionGranularityCharacter";
|
||||||
|
+ case AXTextSelectionGranularityWord:
|
||||||
|
+ return "AXTextSelectionGranularityWord";
|
||||||
|
+ case AXTextSelectionGranularityLine:
|
||||||
|
+ return "AXTextSelectionGranularityLine";
|
||||||
|
+ case AXTextSelectionGranularitySentence:
|
||||||
|
+ return "AXTextSelectionGranularitySentence";
|
||||||
|
+ case AXTextSelectionGranularityParagraph:
|
||||||
|
+ return "AXTextSelectionGranularityParagraph";
|
||||||
|
+ case AXTextSelectionGranularityPage:
|
||||||
|
+ return "AXTextSelectionGranularityPage";
|
||||||
|
+ case AXTextSelectionGranularityDocument:
|
||||||
|
+ return "AXTextSelectionGranularityDocument";
|
||||||
|
+ case AXTextSelectionGranularityAll:
|
||||||
|
+ return "AXTextSelectionGranularityAll";
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return "";
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+const char* ToString(AXTextEditType type) {
|
||||||
|
+ switch (type) {
|
||||||
|
+ case AXTextEditTypeUnknown:
|
||||||
|
+ return "AXTextEditTypeUnknown";
|
||||||
|
+ case AXTextEditTypeDelete:
|
||||||
|
+ return "AXTextEditTypeDelete";
|
||||||
|
+ case AXTextEditTypeInsert:
|
||||||
|
+ return "AXTextEditTypeInsert";
|
||||||
|
+ case AXTextEditTypeTyping:
|
||||||
|
+ return "AXTextEditTypeTyping";
|
||||||
|
+ case AXTextEditTypeDictation:
|
||||||
|
+ return "AXTextEditTypeDictation";
|
||||||
|
+ case AXTextEditTypeCut:
|
||||||
|
+ return "AXTextEditTypeCut";
|
||||||
|
+ case AXTextEditTypePaste:
|
||||||
|
+ return "AXTextEditTypePaste";
|
||||||
|
+ case AXTextEditTypeAttributesChange:
|
||||||
|
+ return "AXTextEditTypeAttributesChange";
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return "";
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+} // namespace ui
|
||||||
@@ -309,10 +309,8 @@ void BrowserWindow::OnWindowResize() {
|
|||||||
if (!draggable_regions_.empty()) {
|
if (!draggable_regions_.empty()) {
|
||||||
UpdateDraggableRegions(draggable_regions_);
|
UpdateDraggableRegions(draggable_regions_);
|
||||||
} else {
|
} else {
|
||||||
// Ensure draggable bounds are recalculated for BrowserViews if any exist.
|
for (NativeBrowserView* view : window_->browser_views()) {
|
||||||
auto browser_views = window_->browser_views();
|
view->UpdateDraggableRegions(view->GetDraggableRegions());
|
||||||
for (NativeBrowserView* view : browser_views) {
|
|
||||||
view->UpdateDraggableRegions(draggable_regions_);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -71,25 +71,21 @@ void BrowserWindow::UpdateDraggableRegions(
|
|||||||
|
|
||||||
// Draggable regions are implemented by having the whole web view draggable
|
// Draggable regions are implemented by having the whole web view draggable
|
||||||
// and overlaying regions that are not draggable.
|
// and overlaying regions that are not draggable.
|
||||||
if (&draggable_regions_ != ®ions) {
|
if (&draggable_regions_ != ®ions)
|
||||||
draggable_regions_.clear();
|
draggable_regions_ = mojo::Clone(regions);
|
||||||
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_);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<gfx::Rect> drag_exclude_rects;
|
std::vector<gfx::Rect> drag_exclude_rects;
|
||||||
if (regions.empty()) {
|
if (regions.empty()) {
|
||||||
drag_exclude_rects.push_back(gfx::Rect(0, 0, webViewWidth, webViewHeight));
|
drag_exclude_rects.emplace_back(0, 0, webViewWidth, webViewHeight);
|
||||||
} else {
|
} else {
|
||||||
drag_exclude_rects = CalculateNonDraggableRegions(
|
drag_exclude_rects = CalculateNonDraggableRegions(
|
||||||
DraggableRegionsToSkRegion(regions), webViewWidth, webViewHeight);
|
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
|
// Create and add a ControlRegionView for each region that needs to be
|
||||||
// excluded from the dragging.
|
// excluded from the dragging.
|
||||||
for (const auto& rect : drag_exclude_rects) {
|
for (const auto& rect : drag_exclude_rects) {
|
||||||
|
|||||||
@@ -66,15 +66,26 @@ base::Optional<base::FilePath> CreateTemporaryFileOnIO() {
|
|||||||
|
|
||||||
void StopTracing(gin_helper::Promise<base::FilePath> promise,
|
void StopTracing(gin_helper::Promise<base::FilePath> promise,
|
||||||
base::Optional<base::FilePath> file_path) {
|
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) {
|
if (file_path) {
|
||||||
auto endpoint = TracingController::CreateFileEndpoint(
|
auto endpoint = TracingController::CreateFileEndpoint(
|
||||||
*file_path, base::AdaptCallbackForRepeating(base::BindOnce(
|
*file_path, base::BindRepeating(resolve_or_reject, base::nullopt));
|
||||||
&gin_helper::Promise<base::FilePath>::ResolvePromise,
|
if (!TracingController::GetInstance()->StopTracing(endpoint)) {
|
||||||
std::move(promise), *file_path)));
|
resolve_or_reject.Run(base::make_optional(
|
||||||
TracingController::GetInstance()->StopTracing(endpoint);
|
"Failed to stop tracing (was a trace in progress?)"));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
promise.RejectWithErrorMessage(
|
resolve_or_reject.Run(
|
||||||
"Failed to create temporary file for trace data");
|
base::make_optional("Failed to create temporary file for trace data"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,9 @@ printing::PrinterList GetPrinterList() {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
#if BUILDFLAG(ENABLE_PRINTING)
|
||||||
using electron::api::GetPrinterList;
|
using electron::api::GetPrinterList;
|
||||||
|
#endif
|
||||||
|
|
||||||
void Initialize(v8::Local<v8::Object> exports,
|
void Initialize(v8::Local<v8::Object> exports,
|
||||||
v8::Local<v8::Value> unused,
|
v8::Local<v8::Value> unused,
|
||||||
|
|||||||
@@ -1447,12 +1447,12 @@ void WebContents::DidStartLoading() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::DidStopLoading() {
|
void WebContents::DidStopLoading() {
|
||||||
Emit("did-stop-loading");
|
|
||||||
|
|
||||||
auto* web_preferences = WebContentsPreferences::From(web_contents());
|
auto* web_preferences = WebContentsPreferences::From(web_contents());
|
||||||
if (web_preferences &&
|
if (web_preferences &&
|
||||||
web_preferences->IsEnabled(options::kEnablePreferredSizeMode))
|
web_preferences->IsEnabled(options::kEnablePreferredSizeMode))
|
||||||
web_contents()->GetRenderViewHost()->EnablePreferredSizeMode();
|
web_contents()->GetRenderViewHost()->EnablePreferredSizeMode();
|
||||||
|
|
||||||
|
Emit("did-stop-loading");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebContents::EmitNavigationEvent(
|
bool WebContents::EmitNavigationEvent(
|
||||||
@@ -3781,6 +3781,12 @@ namespace {
|
|||||||
using electron::api::GetAllWebContents;
|
using electron::api::GetAllWebContents;
|
||||||
using electron::api::WebContents;
|
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(
|
std::vector<gin::Handle<WebContents>> GetAllWebContentsAsV8(
|
||||||
v8::Isolate* isolate) {
|
v8::Isolate* isolate) {
|
||||||
std::vector<gin::Handle<WebContents>> list;
|
std::vector<gin::Handle<WebContents>> list;
|
||||||
@@ -3798,7 +3804,7 @@ void Initialize(v8::Local<v8::Object> exports,
|
|||||||
v8::Isolate* isolate = context->GetIsolate();
|
v8::Isolate* isolate = context->GetIsolate();
|
||||||
gin_helper::Dictionary dict(isolate, exports);
|
gin_helper::Dictionary dict(isolate, exports);
|
||||||
dict.Set("WebContents", WebContents::GetConstructor(context));
|
dict.Set("WebContents", WebContents::GetConstructor(context));
|
||||||
dict.SetMethod("fromId", &WebContents::FromID);
|
dict.SetMethod("fromId", &WebContentsFromID);
|
||||||
dict.SetMethod("getAllWebContents", &GetAllWebContentsAsV8);
|
dict.SetMethod("getAllWebContents", &GetAllWebContentsAsV8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ class NativeBrowserView : public content::WebContentsObserver {
|
|||||||
return inspectable_web_contents_;
|
return inspectable_web_contents_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<mojom::DraggableRegionPtr>& GetDraggableRegions() const {
|
||||||
|
return draggable_regions_;
|
||||||
|
}
|
||||||
|
|
||||||
InspectableWebContentsView* GetInspectableWebContentsView();
|
InspectableWebContentsView* GetInspectableWebContentsView();
|
||||||
|
|
||||||
virtual void SetAutoResizeFlags(uint8_t flags) = 0;
|
virtual void SetAutoResizeFlags(uint8_t flags) = 0;
|
||||||
@@ -47,6 +51,9 @@ class NativeBrowserView : public content::WebContentsObserver {
|
|||||||
virtual gfx::Rect GetBounds() = 0;
|
virtual gfx::Rect GetBounds() = 0;
|
||||||
virtual void SetBackgroundColor(SkColor color) = 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.
|
// Called when the window needs to update its draggable region.
|
||||||
virtual void UpdateDraggableRegions(
|
virtual void UpdateDraggableRegions(
|
||||||
const std::vector<mojom::DraggableRegionPtr>& regions) {}
|
const std::vector<mojom::DraggableRegionPtr>& regions) {}
|
||||||
@@ -57,6 +64,7 @@ class NativeBrowserView : public content::WebContentsObserver {
|
|||||||
void WebContentsDestroyed() override;
|
void WebContentsDestroyed() override;
|
||||||
|
|
||||||
InspectableWebContents* inspectable_web_contents_;
|
InspectableWebContents* inspectable_web_contents_;
|
||||||
|
std::vector<mojom::DraggableRegionPtr> draggable_regions_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_COPY_AND_ASSIGN(NativeBrowserView);
|
DISALLOW_COPY_AND_ASSIGN(NativeBrowserView);
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ class NativeBrowserViewMac : public NativeBrowserView {
|
|||||||
void UpdateDraggableRegions(
|
void UpdateDraggableRegions(
|
||||||
const std::vector<mojom::DraggableRegionPtr>& regions) override;
|
const std::vector<mojom::DraggableRegionPtr>& regions) override;
|
||||||
|
|
||||||
private:
|
void UpdateDraggableRegions(
|
||||||
std::vector<mojom::DraggableRegionPtr> draggable_regions_;
|
const std::vector<gfx::Rect>& drag_exclude_rects) override;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(NativeBrowserViewMac);
|
DISALLOW_COPY_AND_ASSIGN(NativeBrowserViewMac);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ void NativeBrowserViewMac::SetBackgroundColor(SkColor color) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void NativeBrowserViewMac::UpdateDraggableRegions(
|
void NativeBrowserViewMac::UpdateDraggableRegions(
|
||||||
const std::vector<mojom::DraggableRegionPtr>& regions) {
|
const std::vector<gfx::Rect>& drag_exclude_rects) {
|
||||||
if (!inspectable_web_contents_)
|
if (!inspectable_web_contents_)
|
||||||
return;
|
return;
|
||||||
auto* web_contents = inspectable_web_contents_->GetWebContents();
|
auto* web_contents = inspectable_web_contents_->GetWebContents();
|
||||||
@@ -248,25 +248,6 @@ void NativeBrowserViewMac::UpdateDraggableRegions(
|
|||||||
NSView* window_content_view = inspectable_view.superview;
|
NSView* window_content_view = inspectable_view.superview;
|
||||||
const auto window_content_view_height = NSHeight(window_content_view.bounds);
|
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_ != ®ions) {
|
|
||||||
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
|
// Remove all DragRegionViews that were added last time. Note that we need
|
||||||
// to copy the `subviews` array to avoid mutation during iteration.
|
// to copy the `subviews` array to avoid mutation during iteration.
|
||||||
base::scoped_nsobject<NSArray> subviews([[web_view subviews] copy]);
|
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_ != ®ions)
|
||||||
|
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
|
// static
|
||||||
NativeBrowserView* NativeBrowserView::Create(
|
NativeBrowserView* NativeBrowserView::Create(
|
||||||
InspectableWebContents* inspectable_web_contents) {
|
InspectableWebContents* inspectable_web_contents) {
|
||||||
|
|||||||
@@ -4,6 +4,11 @@
|
|||||||
|
|
||||||
#include "shell/browser/native_browser_view_views.h"
|
#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 "shell/browser/ui/inspectable_web_contents_view.h"
|
||||||
#include "ui/gfx/geometry/rect.h"
|
#include "ui/gfx/geometry/rect.h"
|
||||||
#include "ui/views/background.h"
|
#include "ui/views/background.h"
|
||||||
@@ -22,6 +27,25 @@ void NativeBrowserViewViews::SetAutoResizeFlags(uint8_t flags) {
|
|||||||
ResetAutoResizeProportions();
|
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(
|
void NativeBrowserViewViews::SetAutoResizeProportions(
|
||||||
const gfx::Size& window_size) {
|
const gfx::Size& window_size) {
|
||||||
if ((auto_resize_flags_ & AutoResizeFlags::kAutoResizeHorizontal) &&
|
if ((auto_resize_flags_ & AutoResizeFlags::kAutoResizeHorizontal) &&
|
||||||
|
|||||||
@@ -5,7 +5,11 @@
|
|||||||
#ifndef SHELL_BROWSER_NATIVE_BROWSER_VIEW_VIEWS_H_
|
#ifndef SHELL_BROWSER_NATIVE_BROWSER_VIEW_VIEWS_H_
|
||||||
#define 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 "shell/browser/native_browser_view.h"
|
||||||
|
#include "third_party/skia/include/core/SkRegion.h"
|
||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
|
|
||||||
@@ -26,6 +30,10 @@ class NativeBrowserViewViews : public NativeBrowserView {
|
|||||||
void SetBounds(const gfx::Rect& bounds) override;
|
void SetBounds(const gfx::Rect& bounds) override;
|
||||||
gfx::Rect GetBounds() override;
|
gfx::Rect GetBounds() override;
|
||||||
void SetBackgroundColor(SkColor color) override;
|
void SetBackgroundColor(SkColor color) override;
|
||||||
|
void UpdateDraggableRegions(
|
||||||
|
const std::vector<mojom::DraggableRegionPtr>& regions) override;
|
||||||
|
|
||||||
|
SkRegion* draggable_region() const { return draggable_region_.get(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ResetAutoResizeProportions();
|
void ResetAutoResizeProportions();
|
||||||
@@ -40,6 +48,8 @@ class NativeBrowserViewViews : public NativeBrowserView {
|
|||||||
float auto_vertical_proportion_height_ = 0.;
|
float auto_vertical_proportion_height_ = 0.;
|
||||||
float auto_vertical_proportion_top_ = 0.;
|
float auto_vertical_proportion_top_ = 0.;
|
||||||
|
|
||||||
|
std::unique_ptr<SkRegion> draggable_region_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(NativeBrowserViewViews);
|
DISALLOW_COPY_AND_ASSIGN(NativeBrowserViewViews);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -530,6 +530,20 @@ void NativeWindowViews::Unmaximize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool NativeWindowViews::IsMaximized() {
|
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();
|
return widget()->IsMaximized();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1446,6 +1460,16 @@ views::View* NativeWindowViews::GetContentsView() {
|
|||||||
bool NativeWindowViews::ShouldDescendIntoChildForEventHandling(
|
bool NativeWindowViews::ShouldDescendIntoChildForEventHandling(
|
||||||
gfx::NativeView child,
|
gfx::NativeView child,
|
||||||
const gfx::Point& location) {
|
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.
|
// App window should claim mouse events that fall within the draggable region.
|
||||||
if (draggable_region() &&
|
if (draggable_region() &&
|
||||||
draggable_region()->contains(location.x(), location.y()))
|
draggable_region()->contains(location.x(), location.y()))
|
||||||
|
|||||||
@@ -149,9 +149,7 @@ std::set<NativeWindowViews*> NativeWindowViews::forwarding_windows_;
|
|||||||
HHOOK NativeWindowViews::mouse_hook_ = NULL;
|
HHOOK NativeWindowViews::mouse_hook_ = NULL;
|
||||||
|
|
||||||
void NativeWindowViews::Maximize() {
|
void NativeWindowViews::Maximize() {
|
||||||
// Only use Maximize() when:
|
// Only use Maximize() when window has WS_THICKFRAME style
|
||||||
// 1. window has WS_THICKFRAME style;
|
|
||||||
// 2. and window is not frameless when there is autohide taskbar.
|
|
||||||
if (::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME) {
|
if (::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME) {
|
||||||
if (IsVisible())
|
if (IsVisible())
|
||||||
widget()->Maximize();
|
widget()->Maximize();
|
||||||
@@ -161,8 +159,8 @@ void NativeWindowViews::Maximize() {
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
restore_bounds_ = GetBounds();
|
restore_bounds_ = GetBounds();
|
||||||
auto display =
|
auto display = display::Screen::GetScreen()->GetDisplayNearestWindow(
|
||||||
display::Screen::GetScreen()->GetDisplayNearestPoint(GetPosition());
|
GetNativeWindow());
|
||||||
SetBounds(display.work_area(), false);
|
SetBounds(display.work_area(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,5 +40,9 @@
|
|||||||
<string>This app needs access to the microphone</string>
|
<string>This app needs access to the microphone</string>
|
||||||
<key>NSCameraUsageDescription</key>
|
<key>NSCameraUsageDescription</key>
|
||||||
<string>This app needs access to the camera</string>
|
<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>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ END
|
|||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 12,0,0,20201118
|
FILEVERSION 12,0,0,6
|
||||||
PRODUCTVERSION 12,0,0,20201118
|
PRODUCTVERSION 12,0,0,6
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "shell/browser/ui/views/frameless_view.h"
|
#include "shell/browser/ui/views/frameless_view.h"
|
||||||
|
|
||||||
|
#include "shell/browser/native_browser_view_views.h"
|
||||||
#include "shell/browser/native_window_views.h"
|
#include "shell/browser/native_window_views.h"
|
||||||
#include "ui/aura/window.h"
|
#include "ui/aura/window.h"
|
||||||
#include "ui/base/hit_test.h"
|
#include "ui/base/hit_test.h"
|
||||||
@@ -68,6 +69,15 @@ int FramelessView::NonClientHitTest(const gfx::Point& cursor) {
|
|||||||
if (frame_->IsFullscreen())
|
if (frame_->IsFullscreen())
|
||||||
return HTCLIENT;
|
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
|
// Check for possible draggable region in the client area for the frameless
|
||||||
// window.
|
// window.
|
||||||
SkRegion* draggable_region = window_->draggable_region();
|
SkRegion* draggable_region = window_->draggable_region();
|
||||||
|
|||||||
@@ -1059,6 +1059,25 @@ describe('BrowserWindow module', () => {
|
|||||||
await unmaximize;
|
await unmaximize;
|
||||||
expectBoundsEqual(w.getNormalBounds(), bounds);
|
expectBoundsEqual(w.getNormalBounds(), bounds);
|
||||||
});
|
});
|
||||||
|
it('can check transparent window maximization', async () => {
|
||||||
|
w.destroy();
|
||||||
|
w = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
width: 300,
|
||||||
|
height: 300,
|
||||||
|
transparent: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const maximize = emittedOnce(w, 'resize');
|
||||||
|
w.show();
|
||||||
|
w.maximize();
|
||||||
|
await maximize;
|
||||||
|
expect(w.isMaximized()).to.equal(true);
|
||||||
|
const unmaximize = emittedOnce(w, 'resize');
|
||||||
|
w.unmaximize();
|
||||||
|
await unmaximize;
|
||||||
|
expect(w.isMaximized()).to.equal(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
ifdescribe(process.platform !== 'linux')('Minimized state', () => {
|
ifdescribe(process.platform !== 'linux')('Minimized state', () => {
|
||||||
|
|||||||
@@ -119,6 +119,10 @@ ifdescribe(!(process.platform !== 'win32' && ['arm', 'arm64'].includes(process.a
|
|||||||
const resultFilePath = await record(/* options */ {}, /* outputFilePath */ undefined);
|
const resultFilePath = await record(/* options */ {}, /* outputFilePath */ undefined);
|
||||||
expect(resultFilePath).to.be.a('string').that.is.not.empty('result path');
|
expect(resultFilePath).to.be.a('string').that.is.not.empty('result path');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('rejects if no trace is happening', async () => {
|
||||||
|
await expect(contentTracing.stopRecording()).to.be.rejected();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('captured events', () => {
|
describe('captured events', () => {
|
||||||
|
|||||||
@@ -523,10 +523,6 @@ ifdescribe(!isLinuxOnArm && !process.mas && !process.env.DISABLE_CRASH_REPORTER_
|
|||||||
expect(app.getPath('crashDumps')).to.include(app.getPath('userData'));
|
expect(app.getPath('crashDumps')).to.include(app.getPath('userData'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('matches getCrashesDirectory', async () => {
|
|
||||||
expect(app.getPath('crashDumps')).to.equal(require('electron').crashReporter.getCrashesDirectory());
|
|
||||||
});
|
|
||||||
|
|
||||||
function crash (processType: string, remotely: Function) {
|
function crash (processType: string, remotely: Function) {
|
||||||
if (processType === 'main') {
|
if (processType === 'main') {
|
||||||
return remotely(() => {
|
return remotely(() => {
|
||||||
@@ -565,9 +561,9 @@ ifdescribe(!isLinuxOnArm && !process.mas && !process.env.DISABLE_CRASH_REPORTER_
|
|||||||
it('stores crashes in the crash dump directory when uploadToServer: false', async () => {
|
it('stores crashes in the crash dump directory when uploadToServer: false', async () => {
|
||||||
const { remotely } = await startRemoteControlApp();
|
const { remotely } = await startRemoteControlApp();
|
||||||
const crashesDir = await remotely(() => {
|
const crashesDir = await remotely(() => {
|
||||||
const { crashReporter } = require('electron');
|
const { crashReporter, app } = require('electron');
|
||||||
crashReporter.start({ submitURL: 'http://127.0.0.1', uploadToServer: false, ignoreSystemCrashHandler: true });
|
crashReporter.start({ submitURL: 'http://127.0.0.1', uploadToServer: false, ignoreSystemCrashHandler: true });
|
||||||
return crashReporter.getCrashesDirectory();
|
return app.getPath('crashDumps');
|
||||||
});
|
});
|
||||||
let reportsDir = crashesDir;
|
let reportsDir = crashesDir;
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
@@ -599,7 +595,7 @@ ifdescribe(!isLinuxOnArm && !process.mas && !process.env.DISABLE_CRASH_REPORTER_
|
|||||||
const { crashReporter, app } = require('electron');
|
const { crashReporter, app } = require('electron');
|
||||||
app.setPath('crashDumps', crashesDir);
|
app.setPath('crashDumps', crashesDir);
|
||||||
crashReporter.start({ submitURL: 'http://127.0.0.1', uploadToServer: false, ignoreSystemCrashHandler: true });
|
crashReporter.start({ submitURL: 'http://127.0.0.1', uploadToServer: false, ignoreSystemCrashHandler: true });
|
||||||
return crashReporter.getCrashesDirectory();
|
return app.getPath('crashDumps');
|
||||||
}, crashesDir);
|
}, crashesDir);
|
||||||
expect(remoteCrashesDir).to.equal(crashesDir);
|
expect(remoteCrashesDir).to.equal(crashesDir);
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,12 @@ describe('webContents module', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('fromId()', () => {
|
||||||
|
it('returns undefined for an unknown id', () => {
|
||||||
|
expect(webContents.fromId(12345)).to.be.undefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('will-prevent-unload event', function () {
|
describe('will-prevent-unload event', function () {
|
||||||
afterEach(closeAllWindows);
|
afterEach(closeAllWindows);
|
||||||
it('does not emit if beforeunload returns undefined', async () => {
|
it('does not emit if beforeunload returns undefined', async () => {
|
||||||
|
|||||||
@@ -1444,7 +1444,8 @@ describe('asar package', function () {
|
|||||||
|
|
||||||
it('reads a normal file with unpacked files', function () {
|
it('reads a normal file with unpacked files', function () {
|
||||||
const p = path.join(asarDir, 'unpack.asar', 'a.txt');
|
const p = path.join(asarDir, 'unpack.asar', 'a.txt');
|
||||||
expect(internalModuleReadJSON(p).toString().trim()).to.equal('a');
|
const [s, c] = internalModuleReadJSON(p);
|
||||||
|
expect([s.toString().trim(), c]).to.eql(['a', true]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user