mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
39 Commits
refactor/a
...
v14.0.0-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bdbf78dca8 | ||
|
|
40dbeb6836 | ||
|
|
3ff100521d | ||
|
|
f1752a0b6f | ||
|
|
e67b244571 | ||
|
|
fef79701e0 | ||
|
|
c2877a342c | ||
|
|
4e610b1948 | ||
|
|
4d30e7618a | ||
|
|
7381738d85 | ||
|
|
0f2ad3e384 | ||
|
|
b8812c8942 | ||
|
|
7a11390b8a | ||
|
|
6ab2684234 | ||
|
|
80f051d859 | ||
|
|
95e7c6d53a | ||
|
|
1b4c3428a9 | ||
|
|
8edb7b456f | ||
|
|
6362736703 | ||
|
|
670ae438b9 | ||
|
|
10c6959c7f | ||
|
|
1066dce975 | ||
|
|
d584afdf5b | ||
|
|
0d69ba8ca2 | ||
|
|
c2ba3ab114 | ||
|
|
72a33e79d0 | ||
|
|
3ee0536b1d | ||
|
|
846a12056d | ||
|
|
e0f6313739 | ||
|
|
8866b312ad | ||
|
|
cb8fada7a0 | ||
|
|
b983bda721 | ||
|
|
3125ec093d | ||
|
|
a27329d9ad | ||
|
|
5362882cf6 | ||
|
|
c58446d9d7 | ||
|
|
1c2ed2ba95 | ||
|
|
1c0e496ee2 | ||
|
|
0f32b0f1ce |
8
BUILD.gn
8
BUILD.gn
@@ -1,6 +1,7 @@
|
|||||||
import("//build/config/locales.gni")
|
import("//build/config/locales.gni")
|
||||||
import("//build/config/ui.gni")
|
import("//build/config/ui.gni")
|
||||||
import("//build/config/win/manifest.gni")
|
import("//build/config/win/manifest.gni")
|
||||||
|
import("//components/os_crypt/features.gni")
|
||||||
import("//components/spellcheck/spellcheck_build_features.gni")
|
import("//components/spellcheck/spellcheck_build_features.gni")
|
||||||
import("//content/public/app/mac_helpers.gni")
|
import("//content/public/app/mac_helpers.gni")
|
||||||
import("//extensions/buildflags/buildflags.gni")
|
import("//extensions/buildflags/buildflags.gni")
|
||||||
@@ -296,7 +297,7 @@ templated_file("electron_version_header") {
|
|||||||
action("electron_fuses") {
|
action("electron_fuses") {
|
||||||
script = "build/fuses/build.py"
|
script = "build/fuses/build.py"
|
||||||
|
|
||||||
inputs = [ "build/fuses/fuses.json" ]
|
inputs = [ "build/fuses/fuses.json5" ]
|
||||||
|
|
||||||
outputs = [
|
outputs = [
|
||||||
"$target_gen_dir/fuses.h",
|
"$target_gen_dir/fuses.h",
|
||||||
@@ -335,6 +336,7 @@ source_set("electron_lib") {
|
|||||||
"//components/network_hints/common:mojo_bindings",
|
"//components/network_hints/common:mojo_bindings",
|
||||||
"//components/network_hints/renderer",
|
"//components/network_hints/renderer",
|
||||||
"//components/network_session_configurator/common",
|
"//components/network_session_configurator/common",
|
||||||
|
"//components/os_crypt",
|
||||||
"//components/pref_registry",
|
"//components/pref_registry",
|
||||||
"//components/prefs",
|
"//components/prefs",
|
||||||
"//components/security_state/content",
|
"//components/security_state/content",
|
||||||
@@ -684,6 +686,10 @@ source_set("electron_lib") {
|
|||||||
]
|
]
|
||||||
libs += [ "uxtheme.lib" ]
|
libs += [ "uxtheme.lib" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (allow_runtime_configurable_key_storage) {
|
||||||
|
defines += [ "ALLOW_RUNTIME_CONFIGURABLE_KEY_STORAGE" ]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
electron_paks("packed_resources") {
|
electron_paks("packed_resources") {
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
14.0.0-nightly.20210524
|
14.0.0-beta.4
|
||||||
@@ -30,3 +30,6 @@ enable_pseudolocales = false
|
|||||||
is_cfi = false
|
is_cfi = false
|
||||||
|
|
||||||
enable_pak_file_integrity_checks = false
|
enable_pak_file_integrity_checks = false
|
||||||
|
|
||||||
|
# Make application name configurable at runtime for cookie crypto
|
||||||
|
allow_runtime_configurable_key_storage = true
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ const volatile char kFuseWire[] = { /* sentinel */ {sentinel}, /* fuse_version *
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
with open(os.path.join(dir_path, "fuses.json"), 'r') as f:
|
with open(os.path.join(dir_path, "fuses.json5"), 'r') as f:
|
||||||
fuse_defaults = json.load(f)
|
fuse_defaults = json.loads(''.join(line for line in f.readlines() if not line.strip()[0] == "/"))
|
||||||
|
|
||||||
fuse_version = fuse_defaults['_version']
|
fuse_version = fuse_defaults['_version']
|
||||||
del fuse_defaults['_version']
|
del fuse_defaults['_version']
|
||||||
|
|||||||
@@ -2,5 +2,6 @@
|
|||||||
"_comment": "Modifying the fuse schema in any breaking way should result in the _version prop being incremented. NEVER remove a fuse or change its meaning, instead mark it as removed with 'r'",
|
"_comment": "Modifying the fuse schema in any breaking way should result in the _version prop being incremented. NEVER remove a fuse or change its meaning, instead mark it as removed with 'r'",
|
||||||
"_schema": "0 == off, 1 == on, r == removed fuse",
|
"_schema": "0 == off, 1 == on, r == removed fuse",
|
||||||
"_version": 1,
|
"_version": 1,
|
||||||
"run_as_node": "1"
|
"run_as_node": "1",
|
||||||
|
"cookie_encryption": "0"
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ const request = net.request({
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
* `response` IncomingMessage - An object representing the HTTP response message.
|
* `response` [IncomingMessage](incoming-message.md) - An object representing the HTTP response message.
|
||||||
|
|
||||||
#### Event: 'login'
|
#### Event: 'login'
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ files, you need to have built Electron so that it knows which compiler flags
|
|||||||
were used. There is one required option for the script `--output-dir`, which
|
were used. There is one required option for the script `--output-dir`, which
|
||||||
tells the script which build directory to pull the compilation information
|
tells the script which build directory to pull the compilation information
|
||||||
from. A typical usage would be:
|
from. A typical usage would be:
|
||||||
`npm run lint:clang-tiy --out-dir ../out/Testing`
|
`npm run lint:clang-tidy --out-dir ../out/Testing`
|
||||||
|
|
||||||
With no filenames provided, all C/C++/Objective-C files will be checked.
|
With no filenames provided, all C/C++/Objective-C files will be checked.
|
||||||
You can provide a list of files to be checked by passing the filenames after
|
You can provide a list of files to be checked by passing the filenames after
|
||||||
the options:
|
the options:
|
||||||
`npm run lint:clang-tiy --out-dir ../out/Testing shell/browser/api/electron_api_app.cc`
|
`npm run lint:clang-tidy --out-dir ../out/Testing shell/browser/api/electron_api_app.cc`
|
||||||
|
|
||||||
While `clang-tidy` has a
|
While `clang-tidy` has a
|
||||||
[long list](https://clang.llvm.org/extra/clang-tidy/checks/list.html)
|
[long list](https://clang.llvm.org/extra/clang-tidy/checks/list.html)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ You can run `npm run lint` to show any style issues detected by `cpplint` and
|
|||||||
## C++ and Python
|
## C++ and Python
|
||||||
|
|
||||||
For C++ and Python, we follow Chromium's [Coding
|
For C++ and Python, we follow Chromium's [Coding
|
||||||
Style](https://www.chromium.org/developers/coding-style). You can use
|
Style](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/styleguide/styleguide.md). You can use
|
||||||
[clang-format](clang-format.md) to format the C++ code automatically. There is
|
[clang-format](clang-format.md) to format the C++ code automatically. There is
|
||||||
also a script `script/cpplint.py` to check whether all files conform.
|
also a script `script/cpplint.py` to check whether all files conform.
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,6 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Hello World!</h1>
|
<h1>Hello World!</h1>
|
||||||
<p>
|
<p>After launching this application, you should see the system notification.</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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,21 +3,17 @@ const { app, BrowserWindow, Notification } = require('electron')
|
|||||||
function createWindow () {
|
function createWindow () {
|
||||||
const win = new BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600
|
||||||
webPreferences: {
|
|
||||||
nodeIntegration: true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
win.loadFile('index.html')
|
win.loadFile('index.html')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NOTIFICATION_TITLE = 'Basic Notification'
|
||||||
|
const NOTIFICATION_BODY = 'Notification from the Main process'
|
||||||
|
|
||||||
function showNotification () {
|
function showNotification () {
|
||||||
const notification = {
|
new Notification({ title: NOTIFICATION_TITLE, body: NOTIFICATION_BODY }).show()
|
||||||
title: 'Basic Notification',
|
|
||||||
body: 'Notification from the Main process'
|
|
||||||
}
|
|
||||||
new Notification(notification).show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.whenReady().then(createWindow).then(showNotification)
|
app.whenReady().then(createWindow).then(showNotification)
|
||||||
|
|||||||
@@ -7,11 +7,9 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Hello World!</h1>
|
<h1>Hello World!</h1>
|
||||||
<p>
|
<p>After launching this application, you should see the system notification.</p>
|
||||||
We are using node <script>document.write(process.versions.node)</script>,
|
<p id="output">Click it to see the effect in this interface.</p>
|
||||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
|
||||||
and Electron <script>document.write(process.versions.electron)</script>.
|
|
||||||
</p>
|
|
||||||
<script src="renderer.js"></script>
|
<script src="renderer.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,10 +3,7 @@ const { app, BrowserWindow } = require('electron')
|
|||||||
function createWindow () {
|
function createWindow () {
|
||||||
const win = new BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600
|
||||||
webPreferences: {
|
|
||||||
nodeIntegration: true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
win.loadFile('index.html')
|
win.loadFile('index.html')
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
const myNotification = new Notification('Title', {
|
const NOTIFICATION_TITLE = 'Title'
|
||||||
body: 'Notification from the Renderer process'
|
const NOTIFICATION_BODY = 'Notification from the Renderer process. Click to log to console.'
|
||||||
})
|
const CLICK_MESSAGE = 'Notification clicked!'
|
||||||
|
|
||||||
myNotification.onclick = () => {
|
new Notification(NOTIFICATION_TITLE, { body: NOTIFICATION_BODY })
|
||||||
console.log('Notification clicked')
|
.onclick = () => document.getElementById("output").innerText = CLICK_MESSAGE
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,10 +7,9 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Hello World!</h1>
|
<h1>Hello World!</h1>
|
||||||
<p>
|
<p>Keep an eye on the dock (Mac) or taskbar (Windows, Unity) for this application!</p>
|
||||||
We are using node <script>document.write(process.versions.node)</script>,
|
<p>It should indicate a progress that advances from 0 to 100%.</p>
|
||||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
<p>It should then show indeterminate (Windows) or pin at 100% (other operating systems)
|
||||||
and Electron <script>document.write(process.versions.electron)</script>.
|
briefly and then loop.</p>
|
||||||
</p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,21 +1,39 @@
|
|||||||
const { app, BrowserWindow } = require('electron')
|
const { app, BrowserWindow } = require('electron')
|
||||||
|
|
||||||
|
let progressInterval
|
||||||
|
|
||||||
function createWindow () {
|
function createWindow () {
|
||||||
const win = new BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600
|
||||||
webPreferences: {
|
|
||||||
nodeIntegration: true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
win.loadFile('index.html')
|
win.loadFile('index.html')
|
||||||
win.setProgressBar(0.5)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const INCREMENT = 0.03
|
||||||
|
const INTERVAL_DELAY = 100 // ms
|
||||||
|
|
||||||
|
let c = 0
|
||||||
|
progressInterval = setInterval(() => {
|
||||||
|
// update progress bar to next value
|
||||||
|
// values between 0 and 1 will show progress, >1 will show indeterminate or stick at 100%
|
||||||
|
win.setProgressBar(c)
|
||||||
|
|
||||||
|
// increment or reset progress bar
|
||||||
|
if (c < 2) {
|
||||||
|
c += INCREMENT
|
||||||
|
} else {
|
||||||
|
c = (-INCREMENT * 5) // reset to a bit less than 0 to show reset state
|
||||||
|
}
|
||||||
|
}, INTERVAL_DELAY)
|
||||||
|
}
|
||||||
|
|
||||||
app.whenReady().then(createWindow)
|
app.whenReady().then(createWindow)
|
||||||
|
|
||||||
|
// before the app is terminated, clear both timers
|
||||||
|
app.on('before-quit', () => {
|
||||||
|
clearInterval(progressInterval)
|
||||||
|
})
|
||||||
|
|
||||||
app.on('window-all-closed', () => {
|
app.on('window-all-closed', () => {
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
|
|||||||
@@ -2,15 +2,14 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Hello World!</title>
|
<title>Recent Documents</title>
|
||||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Hello World!</h1>
|
<h1>Recent Documents</h1>
|
||||||
<p>
|
<p>
|
||||||
We are using node <script>document.write(process.versions.node)</script>,
|
Right click on the app icon to see recent documents.
|
||||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
You should see `recently-used.md` added to the list of recent files
|
||||||
and Electron <script>document.write(process.versions.electron)</script>.
|
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -5,17 +5,15 @@ const path = require('path')
|
|||||||
function createWindow () {
|
function createWindow () {
|
||||||
const win = new BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600
|
||||||
webPreferences: {
|
|
||||||
nodeIntegration: true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
win.loadFile('index.html')
|
win.loadFile('index.html')
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileName = 'recently-used.md'
|
const fileName = 'recently-used.md'
|
||||||
fs.writeFile(fileName, 'Lorem Ipsum', () => {
|
fs.writeFile(fileName, 'Lorem Ipsum', () => {
|
||||||
app.addRecentDocument(path.join(process.cwd(), `${fileName}`))
|
app.addRecentDocument(path.join(__dirname, fileName))
|
||||||
})
|
})
|
||||||
|
|
||||||
app.whenReady().then(createWindow)
|
app.whenReady().then(createWindow)
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 37 KiB |
@@ -51,4 +51,4 @@ Somewhere in the Electron binary there will be a sequence of bytes that look lik
|
|||||||
|
|
||||||
To flip a fuse you find its position in the fuse wire and change it to "0" or "1" depending on the state you'd like.
|
To flip a fuse you find its position in the fuse wire and change it to "0" or "1" depending on the state you'd like.
|
||||||
|
|
||||||
You can view the current schema [here](https://github.com/electron/electron/blob/master/build/fuses/fuses.json).
|
You can view the current schema [here](https://github.com/electron/electron/blob/master/build/fuses/fuses.json5).
|
||||||
|
|||||||
@@ -49,11 +49,11 @@ is a great place to get advice from other Electron app developers.
|
|||||||
the [GitHub issue tracker][issue-tracker] to see if any existing issues match your
|
the [GitHub issue tracker][issue-tracker] to see if any existing issues match your
|
||||||
problem. If not, feel free to fill out our bug report template and submit a new issue.
|
problem. If not, feel free to fill out our bug report template and submit a new issue.
|
||||||
|
|
||||||
[chromium](https://www.chromium.org/)
|
[chromium]: https://www.chromium.org/
|
||||||
[node](https://nodejs.org/)
|
[node]: https://nodejs.org/
|
||||||
[mdn-guide](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web)
|
[mdn-guide]: https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web
|
||||||
[node-guide](https://nodejs.dev/learn)
|
[node-guide]: https://nodejs.dev/learn
|
||||||
[comic](https://www.google.com/googlebooks/chrome/)
|
[comic]: https://www.google.com/googlebooks/chrome/
|
||||||
[fiddle](https://electronjs.org/fiddle)
|
[fiddle]: https://electronjs.org/fiddle
|
||||||
[issue-tracker](https://github.com/electron/electron/issues)
|
[issue-tracker]: https://github.com/electron/electron/issues
|
||||||
[discord](https://discord.gg/electron)
|
[discord]: https://discord.gg/electron
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ To show notifications in the Main process, you need to use the
|
|||||||
|
|
||||||
### Show notifications in the Renderer process
|
### Show notifications in the Renderer process
|
||||||
|
|
||||||
Assuming you have a working Electron application from the
|
Starting with a working application from the
|
||||||
[Quick Start Guide](quick-start.md), add the following line to the
|
[Quick Start Guide](quick-start.md), add the following line to the
|
||||||
`index.html` file before the closing `</body>` tag:
|
`index.html` file before the closing `</body>` tag:
|
||||||
|
|
||||||
@@ -26,26 +26,22 @@ Assuming you have a working Electron application from the
|
|||||||
<script src="renderer.js"></script>
|
<script src="renderer.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
and add the `renderer.js` file:
|
...and add the `renderer.js` file:
|
||||||
|
|
||||||
```javascript fiddle='docs/fiddles/features/notifications/renderer'
|
```javascript fiddle='docs/fiddles/features/notifications/renderer'
|
||||||
const myNotification = new Notification('Title', {
|
const NOTIFICATION_TITLE = 'Title'
|
||||||
body: 'Notification from the Renderer process'
|
const NOTIFICATION_BODY = 'Notification from the Renderer process. Click to log to console.'
|
||||||
})
|
const CLICK_MESSAGE = 'Notification clicked'
|
||||||
|
|
||||||
myNotification.onclick = () => {
|
new Notification(NOTIFICATION_TITLE, { body: NOTIFICATION_BODY })
|
||||||
console.log('Notification clicked')
|
.onclick = () => console.log(CLICK_MESSAGE)
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
After launching the Electron application, you should see the notification:
|
After launching the Electron application, you should see the notification:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
If you open the Console and then click the notification, you will see the
|
Additionally, if you click on the notification, the DOM will update to show "Notification clicked!".
|
||||||
message that was generated after triggering the `onclick` event:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Show notifications in the Main process
|
### Show notifications in the Main process
|
||||||
|
|
||||||
@@ -55,18 +51,17 @@ Starting with a working application from the
|
|||||||
```javascript fiddle='docs/fiddles/features/notifications/main'
|
```javascript fiddle='docs/fiddles/features/notifications/main'
|
||||||
const { Notification } = require('electron')
|
const { Notification } = require('electron')
|
||||||
|
|
||||||
|
const NOTIFICATION_TITLE = 'Basic Notification'
|
||||||
|
const NOTIFICATION_BODY = 'Notification from the Main process'
|
||||||
|
|
||||||
function showNotification () {
|
function showNotification () {
|
||||||
const notification = {
|
new Notification({ title: NOTIFICATION_TITLE, body: NOTIFICATION_BODY }).show()
|
||||||
title: 'Basic Notification',
|
|
||||||
body: 'Notification from the Main process'
|
|
||||||
}
|
|
||||||
new Notification(notification).show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.whenReady().then(createWindow).then(showNotification)
|
app.whenReady().then(createWindow).then(showNotification)
|
||||||
```
|
```
|
||||||
|
|
||||||
After launching the Electron application, you should see the notification:
|
After launching the Electron application, you should see the system notification:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
@@ -31,30 +31,70 @@ currently at 63% towards completion, you would call it as
|
|||||||
`setProgressBar(0.63)`.
|
`setProgressBar(0.63)`.
|
||||||
|
|
||||||
Setting the parameter to negative values (e.g. `-1`) will remove the progress
|
Setting the parameter to negative values (e.g. `-1`) will remove the progress
|
||||||
bar, whereas setting it to values greater than `1` (e.g. `2`) will switch the
|
bar. Setting it to a value greater than `1` will indicate an indeterminate progress bar
|
||||||
progress bar to indeterminate mode (Windows-only -- it will clamp to 100%
|
in Windows or clamp to 100% in other operating systems. An indeterminate progress bar
|
||||||
otherwise). In this mode, a progress bar remains active but does not show an
|
remains active but does not show an actual percentage, and is used for situations when
|
||||||
actual percentage. Use this mode for situations when you do not know how long
|
you do not know how long an operation will take to complete.
|
||||||
an operation will take to complete.
|
|
||||||
|
|
||||||
See the [API documentation for more options and modes][setprogressbar].
|
See the [API documentation for more options and modes][setprogressbar].
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
Starting with a working application from the
|
In this example, we add a progress bar to the main window that increments over time
|
||||||
[Quick Start Guide](quick-start.md), add the following lines to the
|
using Node.js timers.
|
||||||
`main.js` file:
|
|
||||||
|
|
||||||
```javascript fiddle='docs/fiddles/features/progress-bar'
|
```javascript fiddle='docs/fiddles/features/progress-bar'
|
||||||
const { BrowserWindow } = require('electron')
|
const { app, BrowserWindow } = require('electron')
|
||||||
const win = new BrowserWindow()
|
|
||||||
|
|
||||||
win.setProgressBar(0.5)
|
let progressInterval
|
||||||
|
|
||||||
|
function createWindow () {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600
|
||||||
|
})
|
||||||
|
|
||||||
|
win.loadFile('index.html')
|
||||||
|
|
||||||
|
const INCREMENT = 0.03
|
||||||
|
const INTERVAL_DELAY = 100 // ms
|
||||||
|
|
||||||
|
let c = 0
|
||||||
|
progressInterval = setInterval(() => {
|
||||||
|
// update progress bar to next value
|
||||||
|
// values between 0 and 1 will show progress, >1 will show indeterminate or stick at 100%
|
||||||
|
win.setProgressBar(c)
|
||||||
|
|
||||||
|
// increment or reset progress bar
|
||||||
|
if (c < 2) c += INCREMENT
|
||||||
|
else c = 0
|
||||||
|
}, INTERVAL_DELAY)
|
||||||
|
}
|
||||||
|
|
||||||
|
app.whenReady().then(createWindow)
|
||||||
|
|
||||||
|
// before the app is terminated, clear both timers
|
||||||
|
app.on('before-quit', () => {
|
||||||
|
clearInterval(progressInterval)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
After launching the Electron application, you should see the bar in
|
After launching the Electron application, the dock (macOS) or taskbar (Windows, Unity)
|
||||||
the dock (macOS) or taskbar (Windows, Unity), indicating the progress
|
should show a progress bar that starts at zero and progresses through 100% to completion.
|
||||||
percentage you just defined.
|
It should then show indeterminate (Windows) or pin to 100% (other operating systems)
|
||||||
|
briefly and then loop.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
@@ -299,7 +299,9 @@ function createWindow () {
|
|||||||
const win = new BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
preload: path.join(__dirname, 'preload.js')
|
webPreferences: {
|
||||||
|
preload: path.join(__dirname, 'preload.js')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
win.loadFile('index.html')
|
win.loadFile('index.html')
|
||||||
@@ -440,7 +442,7 @@ window.addEventListener('DOMContentLoaded', () => {
|
|||||||
</html>
|
</html>
|
||||||
```
|
```
|
||||||
|
|
||||||
```fiddle docs/fiddles/quickstart
|
```fiddle docs/fiddles/quick-start
|
||||||
```
|
```
|
||||||
|
|
||||||
To summarize all the steps we've done:
|
To summarize all the steps we've done:
|
||||||
|
|||||||
@@ -13,39 +13,62 @@ __Application dock menu:__
|
|||||||
|
|
||||||
![macOS Dock Menu][dock-menu-image]
|
![macOS Dock Menu][dock-menu-image]
|
||||||
|
|
||||||
To add a file to recent documents, you need to use the
|
|
||||||
[app.addRecentDocument][addrecentdocument] API.
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
### Add an item to recent documents
|
### Managing recent documents
|
||||||
|
|
||||||
Starting with a working application from the
|
|
||||||
[Quick Start Guide](quick-start.md), add the following lines to the
|
|
||||||
`main.js` file:
|
|
||||||
|
|
||||||
```javascript fiddle='docs/fiddles/features/recent-documents'
|
```javascript fiddle='docs/fiddles/features/recent-documents'
|
||||||
const { app } = require('electron')
|
const { app, BrowserWindow } = require('electron')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
app.addRecentDocument('/Users/USERNAME/Desktop/work.type')
|
function createWindow () {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600
|
||||||
|
})
|
||||||
|
|
||||||
|
win.loadFile('index.html')
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileName = 'recently-used.md'
|
||||||
|
fs.writeFile(fileName, 'Lorem Ipsum', () => {
|
||||||
|
app.addRecentDocument(path.join(__dirname, 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()
|
||||||
|
}
|
||||||
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Adding a recent document
|
||||||
|
|
||||||
|
To add a file to recent documents, use the
|
||||||
|
[app.addRecentDocument][addrecentdocument] API.
|
||||||
|
|
||||||
After launching the Electron application, right click the application icon.
|
After launching the Electron application, right click the application icon.
|
||||||
You should see the item you just added. In this guide, the item is a Markdown
|
In this guide, the item is a Markdown file located in the root of the project.
|
||||||
file located in the root of the project:
|
You should see `recently-used.md` added to the list of recent files:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### Clear the list of recent documents
|
#### Clearing the list of recent documents
|
||||||
|
|
||||||
To clear the list of recent documents, you need to use
|
To clear the list of recent documents, use the
|
||||||
[app.clearRecentDocuments][clearrecentdocuments] API in the `main.js` file:
|
[app.clearRecentDocuments][clearrecentdocuments] API.
|
||||||
|
In this guide, the list of documents is cleared once all windows have been
|
||||||
```javascript
|
closed.
|
||||||
const { app } = require('electron')
|
|
||||||
|
|
||||||
app.clearRecentDocuments()
|
|
||||||
```
|
|
||||||
|
|
||||||
## Additional information
|
## Additional information
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ you can interact with the community in these locations:
|
|||||||
* Sharing ideas with other Electron app developers
|
* Sharing ideas with other Electron app developers
|
||||||
* And more!
|
* And more!
|
||||||
* [`electron`](https://discuss.atom.io/c/electron) category on the Atom forums
|
* [`electron`](https://discuss.atom.io/c/electron) category on the Atom forums
|
||||||
* `#atom-shell` channel on Freenode
|
|
||||||
* `#electron` channel on [Atom's Slack](https://discuss.atom.io/t/join-us-on-slack/16638?source_topic_id=25406)
|
* `#electron` channel on [Atom's Slack](https://discuss.atom.io/t/join-us-on-slack/16638?source_topic_id=25406)
|
||||||
* [`electron-ru`](https://telegram.me/electron_ru) *(Russian)*
|
* [`electron-ru`](https://telegram.me/electron_ru) *(Russian)*
|
||||||
* [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)*
|
* [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)*
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ const isChromeDevTools = function (pageURL: string) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const assertChromeDevTools = function (contents: Electron.WebContents, api: string) {
|
const assertChromeDevTools = function (contents: Electron.WebContents, api: string) {
|
||||||
const pageURL = contents._getURL();
|
const pageURL = contents.getURL();
|
||||||
if (!isChromeDevTools(pageURL)) {
|
if (!isChromeDevTools(pageURL)) {
|
||||||
console.error(`Blocked ${pageURL} from calling ${api}`);
|
console.error(`Blocked ${pageURL} from calling ${api}`);
|
||||||
throw new Error(`Blocked ${api}`);
|
throw new Error(`Blocked ${api}`);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "electron",
|
"name": "electron",
|
||||||
"version": "14.0.0-nightly.20210524",
|
"version": "14.0.0-beta.4",
|
||||||
"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": {
|
||||||
|
|||||||
@@ -102,3 +102,4 @@ add_setter_for_browsermainloop_result_code.patch
|
|||||||
chore_allow_overriding_of_enable_pak_file_integrity_checks.patch
|
chore_allow_overriding_of_enable_pak_file_integrity_checks.patch
|
||||||
make_include_of_stack_trace_h_unconditional.patch
|
make_include_of_stack_trace_h_unconditional.patch
|
||||||
build_libc_as_static_library.patch
|
build_libc_as_static_library.patch
|
||||||
|
support_runtime_configurable_key_storage_on_linux_os_crypto.patch
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: Cheng Zhao <zcbenz@gmail.com>
|
From: Cheng Zhao <zcbenz@gmail.com>
|
||||||
Date: Thu, 4 Oct 2018 14:57:02 -0700
|
Date: Thu, 4 Oct 2018 14:57:02 -0700
|
||||||
Subject: accelerator.patch
|
Subject: fix: improve shortcut text of Accelerator
|
||||||
|
|
||||||
This patch makes three changes to Accelerator::GetShortcutText to improve shortcut display text in menus:
|
This patch makes three changes to Accelerator::GetShortcutText to improve shortcut display text in menus:
|
||||||
|
|
||||||
1. Ctrl-Alt-<Key> accelerators show as Ctrl-Alt-<Key> instead of as Ctrl-<Key>
|
1. Ctrl-Alt-<Key> accelerators show as Ctrl-Alt-<Key> instead of as Ctrl-<Key>
|
||||||
2. F2-F24 accelerators show up as such
|
2. F2-F24 accelerators show up as such
|
||||||
3. Ctrl-Shift-= should show as Ctrl-+
|
3. Ctrl-Shift-= and Ctrl-Plus show up as such
|
||||||
|
|
||||||
diff --git a/ui/base/accelerators/accelerator.cc b/ui/base/accelerators/accelerator.cc
|
diff --git a/ui/base/accelerators/accelerator.cc b/ui/base/accelerators/accelerator.cc
|
||||||
index d6913b15149f773cad28b5e2278b0f80df3d2896..15f944c4bb2fde7241b643f6a979a81ebce844b1 100644
|
index d6913b15149f773cad28b5e2278b0f80df3d2896..25342f62acdc28806a0e6ae0bd129c59083ccf06 100644
|
||||||
--- a/ui/base/accelerators/accelerator.cc
|
--- a/ui/base/accelerators/accelerator.cc
|
||||||
+++ b/ui/base/accelerators/accelerator.cc
|
+++ b/ui/base/accelerators/accelerator.cc
|
||||||
@@ -11,6 +11,7 @@
|
@@ -11,6 +11,7 @@
|
||||||
@@ -21,61 +21,39 @@ index d6913b15149f773cad28b5e2278b0f80df3d2896..15f944c4bb2fde7241b643f6a979a81e
|
|||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "build/build_config.h"
|
#include "build/build_config.h"
|
||||||
#include "build/chromeos_buildflags.h"
|
#include "build/chromeos_buildflags.h"
|
||||||
@@ -27,9 +28,7 @@
|
@@ -234,6 +235,11 @@ std::u16string Accelerator::GetShortcutText() const {
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
-#if !defined(OS_WIN) && (defined(USE_AURA) || defined(OS_MAC))
|
|
||||||
#include "ui/events/keycodes/keyboard_code_conversion.h"
|
|
||||||
-#endif
|
|
||||||
|
|
||||||
#if defined(OS_CHROMEOS)
|
|
||||||
#include "ui/base/ui_base_features.h"
|
|
||||||
@@ -233,7 +232,15 @@ std::u16string Accelerator::GetShortcutText() const {
|
|
||||||
shortcut = KeyCodeToName();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+ unsigned int flags = 0;
|
|
||||||
if (shortcut.empty()) {
|
if (shortcut.empty()) {
|
||||||
+ const uint16_t c = DomCodeToUsLayoutCharacter(
|
+ // When a shifted char is explicitly specified, for example Ctrl+Plus,
|
||||||
+ UsLayoutKeyboardCodeToDomCode(key_code_), flags);
|
+ // use the shifted char directly.
|
||||||
+ if (c != 0) {
|
+ if (shifted_char) {
|
||||||
+ shortcut =
|
+ shortcut += *shifted_char;
|
||||||
+ static_cast<std::u16string::value_type>(
|
+ } else {
|
||||||
+ base::ToUpperASCII(static_cast<char16_t>(c)));
|
|
||||||
+ }
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
// Our fallback is to try translate the key code to a regular character
|
// Our fallback is to try translate the key code to a regular character
|
||||||
// unless it is one of digits (VK_0 to VK_9). Some keyboard
|
// unless it is one of digits (VK_0 to VK_9). Some keyboard
|
||||||
@@ -242,21 +249,14 @@ std::u16string Accelerator::GetShortcutText() const {
|
@@ -257,6 +263,10 @@ std::u16string Accelerator::GetShortcutText() const {
|
||||||
// accent' for '0'). For display in the menu (e.g. Ctrl-0 for the
|
shortcut +=
|
||||||
// default zoom level), we leave VK_[0-9] alone without translation.
|
static_cast<std::u16string::value_type>(base::ToUpperASCII(c));
|
||||||
wchar_t key;
|
|
||||||
- if (base::IsAsciiDigit(key_code_))
|
|
||||||
+ if (base::IsAsciiDigit(key_code_)) {
|
|
||||||
key = static_cast<wchar_t>(key_code_);
|
|
||||||
- else
|
|
||||||
- key = LOWORD(::MapVirtualKeyW(key_code_, MAPVK_VK_TO_CHAR));
|
|
||||||
- // If there is no translation for the given |key_code_| (e.g.
|
|
||||||
- // VKEY_UNKNOWN), |::MapVirtualKeyW| returns 0.
|
|
||||||
- if (key != 0)
|
|
||||||
- shortcut += key;
|
|
||||||
-#elif defined(USE_AURA) || defined(OS_MAC) || defined(OS_ANDROID)
|
|
||||||
- const uint16_t c = DomCodeToUsLayoutCharacter(
|
|
||||||
- UsLayoutKeyboardCodeToDomCode(key_code_), false);
|
|
||||||
- if (c != 0)
|
|
||||||
- shortcut +=
|
|
||||||
- static_cast<std::u16string::value_type>(base::ToUpperASCII(c));
|
|
||||||
+ shortcut = key;
|
|
||||||
+ }
|
|
||||||
#endif
|
#endif
|
||||||
|
+ }
|
||||||
+ if (key_code_ > VKEY_F1 && key_code_ <= VKEY_F24)
|
+ if (key_code_ > VKEY_F1 && key_code_ <= VKEY_F24)
|
||||||
+ shortcut = base::UTF8ToUTF16(
|
+ shortcut = base::UTF8ToUTF16(
|
||||||
+ base::StringPrintf("F%d", key_code_ - VKEY_F1 + 1));
|
+ base::StringPrintf("F%d", key_code_ - VKEY_F1 + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(OS_MAC)
|
#if defined(OS_MAC)
|
||||||
@@ -452,7 +452,7 @@ std::u16string Accelerator::ApplyLongFormModifiers(
|
@@ -444,7 +454,7 @@ std::u16string Accelerator::ApplyLongFormModifiers(
|
||||||
|
const std::u16string& shortcut) const {
|
||||||
|
std::u16string result = shortcut;
|
||||||
|
|
||||||
|
- if (IsShiftDown())
|
||||||
|
+ if (!shifted_char && IsShiftDown())
|
||||||
|
result = ApplyModifierToAcceleratorString(result, IDS_APP_SHIFT_KEY);
|
||||||
|
|
||||||
|
// Note that we use 'else-if' in order to avoid using Ctrl+Alt as a shortcut.
|
||||||
|
@@ -452,7 +462,7 @@ std::u16string Accelerator::ApplyLongFormModifiers(
|
||||||
// more information.
|
// more information.
|
||||||
if (IsCtrlDown())
|
if (IsCtrlDown())
|
||||||
result = ApplyModifierToAcceleratorString(result, IDS_APP_CTRL_KEY);
|
result = ApplyModifierToAcceleratorString(result, IDS_APP_CTRL_KEY);
|
||||||
@@ -84,3 +62,24 @@ index d6913b15149f773cad28b5e2278b0f80df3d2896..15f944c4bb2fde7241b643f6a979a81e
|
|||||||
result = ApplyModifierToAcceleratorString(result, IDS_APP_ALT_KEY);
|
result = ApplyModifierToAcceleratorString(result, IDS_APP_ALT_KEY);
|
||||||
|
|
||||||
if (IsCmdDown()) {
|
if (IsCmdDown()) {
|
||||||
|
diff --git a/ui/base/accelerators/accelerator.h b/ui/base/accelerators/accelerator.h
|
||||||
|
index 780a45f9ca2dd60e0deac27cc6e8f69e72cd8435..b740fbbfb14b5737b18b84c07c8e9f79cfc645c0 100644
|
||||||
|
--- a/ui/base/accelerators/accelerator.h
|
||||||
|
+++ b/ui/base/accelerators/accelerator.h
|
||||||
|
@@ -16,6 +16,7 @@
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "base/component_export.h"
|
||||||
|
+#include "base/optional.h"
|
||||||
|
#include "base/time/time.h"
|
||||||
|
#include "build/build_config.h"
|
||||||
|
#include "ui/events/event_constants.h"
|
||||||
|
@@ -129,6 +130,8 @@ class COMPONENT_EXPORT(UI_BASE) Accelerator {
|
||||||
|
return interrupted_by_mouse_event_;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ base::Optional<char16_t> shifted_char;
|
||||||
|
+
|
||||||
|
private:
|
||||||
|
std::u16string ApplyLongFormModifiers(const std::u16string& shortcut) const;
|
||||||
|
std::u16string ApplyShortFormModifiers(const std::u16string& shortcut) const;
|
||||||
|
|||||||
@@ -0,0 +1,288 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samuel Attard <samuel.r.attard@gmail.com>
|
||||||
|
Date: Mon, 10 May 2021 17:10:25 -0700
|
||||||
|
Subject: support runtime configurable key storage on linux (os_crypto)
|
||||||
|
|
||||||
|
This modifies the OsCrypt::Config struct used on linux to support
|
||||||
|
runtime configurable application names which are used in the Keyring and
|
||||||
|
LibSecret implementations of os_crypt on linux.
|
||||||
|
|
||||||
|
Change-Id: Ifc287b589f118da8fcd5afaf39e5ba7ffe46f5fd
|
||||||
|
|
||||||
|
diff --git a/components/os_crypt/key_storage_config_linux.h b/components/os_crypt/key_storage_config_linux.h
|
||||||
|
index a856604756aa65c52171a9eff84ba2b316d8609c..72c16682e5df615ab84f67af66cc36c2b76c30e3 100644
|
||||||
|
--- a/components/os_crypt/key_storage_config_linux.h
|
||||||
|
+++ b/components/os_crypt/key_storage_config_linux.h
|
||||||
|
@@ -26,6 +26,12 @@ struct COMPONENT_EXPORT(OS_CRYPT) Config {
|
||||||
|
std::string store;
|
||||||
|
// The product name to use for permission prompts.
|
||||||
|
std::string product_name;
|
||||||
|
+ // The application name to store the key under. For Chromium/Chrome builds
|
||||||
|
+ // leave this unset and it will default correctly. This config option is
|
||||||
|
+ // for embedders to provide their application name in place of "Chromium".
|
||||||
|
+ // Only used when the allow_runtime_configurable_key_storage feature is
|
||||||
|
+ // enabled.
|
||||||
|
+ std::string application_name;
|
||||||
|
// A runner on the main thread for gnome-keyring to be called from.
|
||||||
|
// TODO(crbug/466975): Libsecret and KWallet don't need this. We can remove
|
||||||
|
// this when we stop supporting keyring.
|
||||||
|
diff --git a/components/os_crypt/key_storage_keyring.cc b/components/os_crypt/key_storage_keyring.cc
|
||||||
|
index 29720b8e8ff81791970e054050b37bbc5f338eb3..3ad654cf4a893f497ac4567aea77f8d1f2e1525f 100644
|
||||||
|
--- a/components/os_crypt/key_storage_keyring.cc
|
||||||
|
+++ b/components/os_crypt/key_storage_keyring.cc
|
||||||
|
@@ -15,12 +15,6 @@
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
|
||||||
|
-const char kApplicationName[] = "chrome";
|
||||||
|
-#else
|
||||||
|
-const char kApplicationName[] = "chromium";
|
||||||
|
-#endif
|
||||||
|
-
|
||||||
|
const GnomeKeyringPasswordSchema kSchema = {
|
||||||
|
GNOME_KEYRING_ITEM_GENERIC_SECRET,
|
||||||
|
{{"application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, {nullptr}}};
|
||||||
|
@@ -28,8 +22,10 @@ const GnomeKeyringPasswordSchema kSchema = {
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
KeyStorageKeyring::KeyStorageKeyring(
|
||||||
|
- scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner)
|
||||||
|
- : main_thread_runner_(main_thread_runner) {}
|
||||||
|
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
|
||||||
|
+ std::string application_name)
|
||||||
|
+ : main_thread_runner_(main_thread_runner),
|
||||||
|
+ application_name_(std::move(application_name)) {}
|
||||||
|
|
||||||
|
KeyStorageKeyring::~KeyStorageKeyring() {}
|
||||||
|
|
||||||
|
@@ -49,7 +45,8 @@ absl::optional<std::string> KeyStorageKeyring::GetKeyImpl() {
|
||||||
|
gchar* password_c = nullptr;
|
||||||
|
GnomeKeyringResult result =
|
||||||
|
GnomeKeyringLoader::gnome_keyring_find_password_sync_ptr(
|
||||||
|
- &kSchema, &password_c, "application", kApplicationName, nullptr);
|
||||||
|
+ &kSchema, &password_c, "application", application_name_.c_str(),
|
||||||
|
+ nullptr);
|
||||||
|
if (result == GNOME_KEYRING_RESULT_OK) {
|
||||||
|
password = password_c;
|
||||||
|
GnomeKeyringLoader::gnome_keyring_free_password_ptr(password_c);
|
||||||
|
@@ -71,7 +68,7 @@ absl::optional<std::string> KeyStorageKeyring::AddRandomPasswordInKeyring() {
|
||||||
|
GnomeKeyringResult result =
|
||||||
|
GnomeKeyringLoader::gnome_keyring_store_password_sync_ptr(
|
||||||
|
&kSchema, nullptr /* default keyring */, KeyStorageLinux::kKey,
|
||||||
|
- password.c_str(), "application", kApplicationName, nullptr);
|
||||||
|
+ password.c_str(), "application", application_name_.c_str(), nullptr);
|
||||||
|
if (result != GNOME_KEYRING_RESULT_OK) {
|
||||||
|
VLOG(1) << "OSCrypt failed to store generated password to gnome-keyring";
|
||||||
|
return absl::nullopt;
|
||||||
|
diff --git a/components/os_crypt/key_storage_keyring.h b/components/os_crypt/key_storage_keyring.h
|
||||||
|
index 26a3f587b49cdea3e4913ce0e08eeade6d1853a0..598c8b8ad35efa002a29dd98c9cba98453bef5ac 100644
|
||||||
|
--- a/components/os_crypt/key_storage_keyring.h
|
||||||
|
+++ b/components/os_crypt/key_storage_keyring.h
|
||||||
|
@@ -20,8 +20,9 @@ class SingleThreadTaskRunner;
|
||||||
|
// Specialisation of KeyStorageLinux that uses Libsecret.
|
||||||
|
class COMPONENT_EXPORT(OS_CRYPT) KeyStorageKeyring : public KeyStorageLinux {
|
||||||
|
public:
|
||||||
|
- explicit KeyStorageKeyring(
|
||||||
|
- scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner);
|
||||||
|
+ KeyStorageKeyring(
|
||||||
|
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
|
||||||
|
+ std::string application_name);
|
||||||
|
~KeyStorageKeyring() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
@@ -37,6 +38,8 @@ class COMPONENT_EXPORT(OS_CRYPT) KeyStorageKeyring : public KeyStorageLinux {
|
||||||
|
// Keyring calls need to originate from the main thread.
|
||||||
|
scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner_;
|
||||||
|
|
||||||
|
+ const std::string application_name_;
|
||||||
|
+
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(KeyStorageKeyring);
|
||||||
|
};
|
||||||
|
|
||||||
|
diff --git a/components/os_crypt/key_storage_keyring_unittest.cc b/components/os_crypt/key_storage_keyring_unittest.cc
|
||||||
|
index aba31971dc33f4b60c2847fd037c419baf084eaa..93fc216d54168eb3fd7e9f1b23f71a77f6e6735d 100644
|
||||||
|
--- a/components/os_crypt/key_storage_keyring_unittest.cc
|
||||||
|
+++ b/components/os_crypt/key_storage_keyring_unittest.cc
|
||||||
|
@@ -130,7 +130,7 @@ class GnomeKeyringTest : public testing::Test {
|
||||||
|
};
|
||||||
|
|
||||||
|
GnomeKeyringTest::GnomeKeyringTest()
|
||||||
|
- : task_runner_(new base::TestSimpleTaskRunner()), keyring_(task_runner_) {
|
||||||
|
+ : task_runner_(new base::TestSimpleTaskRunner()), keyring_(task_runner_, "chromium") {
|
||||||
|
MockGnomeKeyringLoader::ResetForOSCrypt();
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/components/os_crypt/key_storage_libsecret.cc b/components/os_crypt/key_storage_libsecret.cc
|
||||||
|
index 0857cc1874f4153541c7f21dd8cc6bdc1d59b39d..ccc60522791508f02dc759e55e781dbb9627967b 100644
|
||||||
|
--- a/components/os_crypt/key_storage_libsecret.cc
|
||||||
|
+++ b/components/os_crypt/key_storage_libsecret.cc
|
||||||
|
@@ -14,12 +14,6 @@
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
|
||||||
|
-const char kApplicationName[] = "chrome";
|
||||||
|
-#else
|
||||||
|
-const char kApplicationName[] = "chromium";
|
||||||
|
-#endif
|
||||||
|
-
|
||||||
|
const SecretSchema kKeystoreSchemaV2 = {
|
||||||
|
"chrome_libsecret_os_crypt_password_v2",
|
||||||
|
SECRET_SCHEMA_DONT_MATCH_NAME,
|
||||||
|
@@ -64,6 +58,9 @@ void AnalyseKeyHistory(GList* secret_items) {
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
+KeyStorageLibsecret::KeyStorageLibsecret(std::string application_name)
|
||||||
|
+ : application_name_(std::move(application_name)) {}
|
||||||
|
+
|
||||||
|
absl::optional<std::string>
|
||||||
|
KeyStorageLibsecret::AddRandomPasswordInLibsecret() {
|
||||||
|
std::string password;
|
||||||
|
@@ -71,7 +68,7 @@ KeyStorageLibsecret::AddRandomPasswordInLibsecret() {
|
||||||
|
GError* error = nullptr;
|
||||||
|
bool success = LibsecretLoader::secret_password_store_sync(
|
||||||
|
&kKeystoreSchemaV2, nullptr, KeyStorageLinux::kKey, password.c_str(),
|
||||||
|
- nullptr, &error, "application", kApplicationName, nullptr);
|
||||||
|
+ nullptr, &error, "application", application_name_.c_str(), nullptr);
|
||||||
|
if (error) {
|
||||||
|
VLOG(1) << "Libsecret lookup failed: " << error->message;
|
||||||
|
g_error_free(error);
|
||||||
|
@@ -88,7 +85,7 @@ KeyStorageLibsecret::AddRandomPasswordInLibsecret() {
|
||||||
|
|
||||||
|
absl::optional<std::string> KeyStorageLibsecret::GetKeyImpl() {
|
||||||
|
LibsecretAttributesBuilder attrs;
|
||||||
|
- attrs.Append("application", kApplicationName);
|
||||||
|
+ attrs.Append("application", application_name_);
|
||||||
|
|
||||||
|
LibsecretLoader::SearchHelper helper;
|
||||||
|
helper.Search(&kKeystoreSchemaV2, attrs.Get(),
|
||||||
|
diff --git a/components/os_crypt/key_storage_libsecret.h b/components/os_crypt/key_storage_libsecret.h
|
||||||
|
index 4759d076ea0017a41b398491dd24dde76a61e463..5292e21b8e7e1a873591e474571adb5b4ed8fe16 100644
|
||||||
|
--- a/components/os_crypt/key_storage_libsecret.h
|
||||||
|
+++ b/components/os_crypt/key_storage_libsecret.h
|
||||||
|
@@ -15,7 +15,7 @@
|
||||||
|
// Specialisation of KeyStorageLinux that uses Libsecret.
|
||||||
|
class COMPONENT_EXPORT(OS_CRYPT) KeyStorageLibsecret : public KeyStorageLinux {
|
||||||
|
public:
|
||||||
|
- KeyStorageLibsecret() = default;
|
||||||
|
+ explicit KeyStorageLibsecret(std::string application_name);
|
||||||
|
~KeyStorageLibsecret() override = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
@@ -26,6 +26,8 @@ class COMPONENT_EXPORT(OS_CRYPT) KeyStorageLibsecret : public KeyStorageLinux {
|
||||||
|
private:
|
||||||
|
absl::optional<std::string> AddRandomPasswordInLibsecret();
|
||||||
|
|
||||||
|
+ const std::string application_name_;
|
||||||
|
+
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(KeyStorageLibsecret);
|
||||||
|
};
|
||||||
|
|
||||||
|
diff --git a/components/os_crypt/key_storage_libsecret_unittest.cc b/components/os_crypt/key_storage_libsecret_unittest.cc
|
||||||
|
index ebe9a6b4bcbf748cd7f7e5fcf941b78ab1835749..a17bbc1f8061b33d55444919f546256d63bc809b 100644
|
||||||
|
--- a/components/os_crypt/key_storage_libsecret_unittest.cc
|
||||||
|
+++ b/components/os_crypt/key_storage_libsecret_unittest.cc
|
||||||
|
@@ -236,7 +236,7 @@ class LibsecretTest : public testing::Test {
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(LibsecretTest, LibsecretRepeats) {
|
||||||
|
- KeyStorageLibsecret libsecret;
|
||||||
|
+ KeyStorageLibsecret libsecret("chromium");
|
||||||
|
MockLibsecretLoader::ResetForOSCrypt();
|
||||||
|
g_password_store.Pointer()->SetPassword("initial password");
|
||||||
|
absl::optional<std::string> password = libsecret.GetKey();
|
||||||
|
@@ -248,7 +248,7 @@ TEST_F(LibsecretTest, LibsecretRepeats) {
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LibsecretTest, LibsecretCreatesRandomised) {
|
||||||
|
- KeyStorageLibsecret libsecret;
|
||||||
|
+ KeyStorageLibsecret libsecret("chromium");
|
||||||
|
MockLibsecretLoader::ResetForOSCrypt();
|
||||||
|
absl::optional<std::string> password = libsecret.GetKey();
|
||||||
|
MockLibsecretLoader::ResetForOSCrypt();
|
||||||
|
diff --git a/components/os_crypt/key_storage_linux.cc b/components/os_crypt/key_storage_linux.cc
|
||||||
|
index 8feb147c96baa2f853a647eb648297b4b747f515..53b1903ff04043e2d058deda086e116a0e00fdca 100644
|
||||||
|
--- a/components/os_crypt/key_storage_linux.cc
|
||||||
|
+++ b/components/os_crypt/key_storage_linux.cc
|
||||||
|
@@ -11,6 +11,7 @@
|
||||||
|
#include "base/logging.h"
|
||||||
|
#include "base/metrics/histogram_macros.h"
|
||||||
|
#include "base/nix/xdg_util.h"
|
||||||
|
+#include "base/no_destructor.h"
|
||||||
|
#include "base/sequenced_task_runner.h"
|
||||||
|
#include "base/synchronization/waitable_event.h"
|
||||||
|
#include "base/task_runner_util.h"
|
||||||
|
@@ -147,12 +148,29 @@ std::unique_ptr<KeyStorageLinux> KeyStorageLinux::CreateService(
|
||||||
|
std::unique_ptr<KeyStorageLinux> KeyStorageLinux::CreateServiceInternal(
|
||||||
|
os_crypt::SelectedLinuxBackend selected_backend,
|
||||||
|
const os_crypt::Config& config) {
|
||||||
|
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
|
||||||
|
+ static const base::NoDestructor<std::string> kDefaultApplicationName("chrome");
|
||||||
|
+#else
|
||||||
|
+ static const base::NoDestructor<std::string> kDefaultApplicationName("chromium");
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
std::unique_ptr<KeyStorageLinux> key_storage;
|
||||||
|
|
||||||
|
+#if defined(USE_LIBSECRET) || defined(USE_KEYRING)
|
||||||
|
+#if defined(ALLOW_RUNTIME_CONFIGURABLE_KEY_STORAGE)
|
||||||
|
+ std::string application_name = config.application_name;
|
||||||
|
+ if (application_name.empty()) {
|
||||||
|
+ application_name = *kDefaultApplicationName;
|
||||||
|
+ }
|
||||||
|
+#else
|
||||||
|
+ std::string application_name = *kDefaultApplicationName;
|
||||||
|
+#endif
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#if defined(USE_LIBSECRET)
|
||||||
|
if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY ||
|
||||||
|
selected_backend == os_crypt::SelectedLinuxBackend::GNOME_LIBSECRET) {
|
||||||
|
- key_storage = std::make_unique<KeyStorageLibsecret>();
|
||||||
|
+ key_storage = std::make_unique<KeyStorageLibsecret>(std::move(application_name));
|
||||||
|
if (key_storage->WaitForInitOnTaskRunner()) {
|
||||||
|
VLOG(1) << "OSCrypt using Libsecret as backend.";
|
||||||
|
return key_storage;
|
||||||
|
@@ -164,8 +182,8 @@ std::unique_ptr<KeyStorageLinux> KeyStorageLinux::CreateServiceInternal(
|
||||||
|
#if defined(USE_KEYRING)
|
||||||
|
if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY ||
|
||||||
|
selected_backend == os_crypt::SelectedLinuxBackend::GNOME_KEYRING) {
|
||||||
|
- key_storage =
|
||||||
|
- std::make_unique<KeyStorageKeyring>(config.main_thread_runner);
|
||||||
|
+ key_storage = std::make_unique<KeyStorageKeyring>(config.main_thread_runner,
|
||||||
|
+ std::move(application_name));
|
||||||
|
if (key_storage->WaitForInitOnTaskRunner()) {
|
||||||
|
VLOG(1) << "OSCrypt using Keyring as backend.";
|
||||||
|
return key_storage;
|
||||||
|
diff --git a/services/network/network_service.cc b/services/network/network_service.cc
|
||||||
|
index 02c8af43258f6a31f3cc667e73f55f8f67330b51..bea06f626cc2b302ca8a25c753c37cea0d4c9e8c 100644
|
||||||
|
--- a/services/network/network_service.cc
|
||||||
|
+++ b/services/network/network_service.cc
|
||||||
|
@@ -622,6 +622,7 @@ void NetworkService::SetCryptConfig(mojom::CryptConfigPtr crypt_config) {
|
||||||
|
auto config = std::make_unique<os_crypt::Config>();
|
||||||
|
config->store = crypt_config->store;
|
||||||
|
config->product_name = crypt_config->product_name;
|
||||||
|
+ config->application_name = crypt_config->application_name;
|
||||||
|
config->main_thread_runner = base::ThreadTaskRunnerHandle::Get();
|
||||||
|
config->should_use_preference = crypt_config->should_use_preference;
|
||||||
|
config->user_data_path = crypt_config->user_data_path;
|
||||||
|
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
|
||||||
|
index 3a1abc4d1b64ad9480f5218cd1de8fd61a064f34..0edbe59d3a70b5bca759cd8a726baded6b81ea71 100644
|
||||||
|
--- a/services/network/public/mojom/network_service.mojom
|
||||||
|
+++ b/services/network/public/mojom/network_service.mojom
|
||||||
|
@@ -99,6 +99,13 @@ struct CryptConfig {
|
||||||
|
// The product name to use for permission prompts.
|
||||||
|
string product_name;
|
||||||
|
|
||||||
|
+ // The application name to store the crypto key against. For Chromium/Chrome
|
||||||
|
+ // builds leave this unset and it will default correctly. This config option
|
||||||
|
+ // is for embedders to provide their application name in place of "Chromium".
|
||||||
|
+ // Only used when the allow_runtime_configurable_key_storage feature is
|
||||||
|
+ // enabled
|
||||||
|
+ string application_name;
|
||||||
|
+
|
||||||
|
// Controls whether preference on using or ignoring backends is used.
|
||||||
|
bool should_use_preference;
|
||||||
|
|
||||||
@@ -508,7 +508,7 @@ index 0000000000000000000000000000000000000000..bdfaf95f3eca65b3e0831db1b66f651d
|
|||||||
+}
|
+}
|
||||||
diff --git a/build/xcrun.py b/build/xcrun.py
|
diff --git a/build/xcrun.py b/build/xcrun.py
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000000000000000000000000000000000..20d0cdb51cc933f56b7a7193c195457e82500870
|
index 0000000000000000000000000000000000000000..18ac587f80441106405d00fafd9ee1f25b147772
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/build/xcrun.py
|
+++ b/build/xcrun.py
|
||||||
@@ -0,0 +1,14 @@
|
@@ -0,0 +1,14 @@
|
||||||
@@ -524,7 +524,7 @@ index 0000000000000000000000000000000000000000..20d0cdb51cc933f56b7a7193c195457e
|
|||||||
+try:
|
+try:
|
||||||
+ subprocess.check_output(args, stderr=subprocess.STDOUT)
|
+ subprocess.check_output(args, stderr=subprocess.STDOUT)
|
||||||
+except subprocess.CalledProcessError as e:
|
+except subprocess.CalledProcessError as e:
|
||||||
+ print("xcrun script '" + sys.argv[2] + "' failed with code '" + str(e.returncode) + "':\n" + e.output)
|
+ print("xcrun script '" + ' '.join(sys.argv[1:]) + "' failed with code '" + str(e.returncode) + "':\n" + e.output)
|
||||||
+ sys.exit(e.returncode)
|
+ sys.exit(e.returncode)
|
||||||
diff --git a/filenames.gni b/filenames.gni
|
diff --git a/filenames.gni b/filenames.gni
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import sys
|
|||||||
|
|
||||||
PLATFORM = {
|
PLATFORM = {
|
||||||
'cygwin': 'win32',
|
'cygwin': 'win32',
|
||||||
|
'msys': 'win32',
|
||||||
'darwin': 'darwin',
|
'darwin': 'darwin',
|
||||||
'linux': 'linux',
|
'linux': 'linux',
|
||||||
'linux2': 'linux',
|
'linux2': 'linux',
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ const ELECTRON_DIR = path.resolve(__dirname, '..', '..');
|
|||||||
const SRC_DIR = path.resolve(ELECTRON_DIR, '..');
|
const SRC_DIR = path.resolve(ELECTRON_DIR, '..');
|
||||||
|
|
||||||
const RELEASE_BRANCH_PATTERN = /(\d)+-(?:(?:[0-9]+-x$)|(?:x+-y$))/;
|
const RELEASE_BRANCH_PATTERN = /(\d)+-(?:(?:[0-9]+-x$)|(?:x+-y$))/;
|
||||||
|
// TODO(main-migration): Simplify once main branch is renamed
|
||||||
|
const MAIN_BRANCH_PATTERN = /^(main|master)$/;
|
||||||
|
const ORIGIN_MAIN_BRANCH_PATTERN = /^origin\/(main|master)$/;
|
||||||
|
|
||||||
require('colors');
|
require('colors');
|
||||||
const pass = '✓'.green;
|
const pass = '✓'.green;
|
||||||
@@ -73,7 +76,7 @@ async function handleGitCall (args, gitDir) {
|
|||||||
|
|
||||||
async function getCurrentBranch (gitDir) {
|
async function getCurrentBranch (gitDir) {
|
||||||
let branch = await handleGitCall(['rev-parse', '--abbrev-ref', 'HEAD'], gitDir);
|
let branch = await handleGitCall(['rev-parse', '--abbrev-ref', 'HEAD'], gitDir);
|
||||||
if (branch !== 'master' && !RELEASE_BRANCH_PATTERN.test(branch)) {
|
if (!MAIN_BRANCH_PATTERN.test(branch) && !RELEASE_BRANCH_PATTERN.test(branch)) {
|
||||||
const lastCommit = await handleGitCall(['rev-parse', 'HEAD'], gitDir);
|
const lastCommit = await handleGitCall(['rev-parse', 'HEAD'], gitDir);
|
||||||
const branches = (await handleGitCall([
|
const branches = (await handleGitCall([
|
||||||
'branch',
|
'branch',
|
||||||
@@ -82,7 +85,7 @@ async function getCurrentBranch (gitDir) {
|
|||||||
'--remote'
|
'--remote'
|
||||||
], gitDir)).split('\n');
|
], gitDir)).split('\n');
|
||||||
|
|
||||||
branch = branches.filter(b => b.trim() === 'master' || b.trim() === 'origin/master' || RELEASE_BRANCH_PATTERN.test(b.trim()))[0];
|
branch = branches.find(b => MAIN_BRANCH_PATTERN.test(b.trim()) || ORIGIN_MAIN_BRANCH_PATTERN.test(b.trim()) || RELEASE_BRANCH_PATTERN.test(b.trim()));
|
||||||
if (!branch) {
|
if (!branch) {
|
||||||
console.log(`${fail} no release branch exists for this ref`);
|
console.log(`${fail} no release branch exists for this ref`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ const semver = require('semver');
|
|||||||
const { ELECTRON_DIR } = require('../../lib/utils');
|
const { ELECTRON_DIR } = require('../../lib/utils');
|
||||||
const notesGenerator = require('./notes.js');
|
const notesGenerator = require('./notes.js');
|
||||||
|
|
||||||
|
const { Octokit } = require('@octokit/rest');
|
||||||
|
const octokit = new Octokit({
|
||||||
|
auth: process.env.ELECTRON_GITHUB_TOKEN
|
||||||
|
});
|
||||||
|
|
||||||
const semverify = version => version.replace(/^origin\//, '').replace(/[xy]/g, '0').replace(/-/g, '.');
|
const semverify = version => version.replace(/^origin\//, '').replace(/[xy]/g, '0').replace(/-/g, '.');
|
||||||
|
|
||||||
const runGit = async (args) => {
|
const runGit = async (args) => {
|
||||||
@@ -37,13 +42,17 @@ const getTagsOf = async (point) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getTagsOnBranch = async (point) => {
|
const getTagsOnBranch = async (point) => {
|
||||||
const masterTags = await getTagsOf('master');
|
const { data: { default_branch: defaultBranch } } = await octokit.repos.get({
|
||||||
if (point === 'master') {
|
owner: 'electron',
|
||||||
return masterTags;
|
repo: 'electron'
|
||||||
|
});
|
||||||
|
const mainTags = await getTagsOf(defaultBranch);
|
||||||
|
if (point === defaultBranch) {
|
||||||
|
return mainTags;
|
||||||
}
|
}
|
||||||
|
|
||||||
const masterTagsSet = new Set(masterTags);
|
const mainTagsSet = new Set(mainTags);
|
||||||
return (await getTagsOf(point)).filter(tag => !masterTagsSet.has(tag));
|
return (await getTagsOf(point)).filter(tag => !mainTagsSet.has(tag));
|
||||||
};
|
};
|
||||||
|
|
||||||
const getBranchOf = async (point) => {
|
const getBranchOf = async (point) => {
|
||||||
@@ -66,7 +75,8 @@ const getAllBranches = async () => {
|
|||||||
return branches.split('\n')
|
return branches.split('\n')
|
||||||
.map(branch => branch.trim())
|
.map(branch => branch.trim())
|
||||||
.filter(branch => !!branch)
|
.filter(branch => !!branch)
|
||||||
.filter(branch => branch !== 'origin/HEAD -> origin/master')
|
// TODO(main-migration): Simplify once branch rename is complete.
|
||||||
|
.filter(branch => branch !== 'origin/HEAD -> origin/master' && branch !== 'origin/HEAD -> origin/main')
|
||||||
.sort();
|
.sort();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to fetch all branches');
|
console.error('Failed to fetch all branches');
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ async function createRelease (branchToTarget, isBeta) {
|
|||||||
name: `electron ${newVersion}`,
|
name: `electron ${newVersion}`,
|
||||||
body: releaseBody,
|
body: releaseBody,
|
||||||
prerelease: releaseIsPrelease,
|
prerelease: releaseIsPrelease,
|
||||||
target_commitish: newVersion.indexOf('nightly') !== -1 ? 'master' : branchToTarget
|
target_commitish: newVersion.indexOf('nightly') !== -1 ? 'main' : branchToTarget
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
console.log(`${fail} Error creating new release: `, err);
|
console.log(`${fail} Error creating new release: `, err);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
@@ -180,7 +180,7 @@ async function promptForVersion (version) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// function to determine if there have been commits to master since the last release
|
// function to determine if there have been commits to main since the last release
|
||||||
async function changesToRelease () {
|
async function changesToRelease () {
|
||||||
const lastCommitWasRelease = new RegExp('^Bump v[0-9.]*(-beta[0-9.]*)?(-nightly[0-9.]*)?$', 'g');
|
const lastCommitWasRelease = new RegExp('^Bump v[0-9.]*(-beta[0-9.]*)?(-nightly[0-9.]*)?$', 'g');
|
||||||
const lastCommit = await GitProcess.exec(['log', '-n', '1', '--pretty=format:\'%s\''], ELECTRON_DIR);
|
const lastCommit = await GitProcess.exec(['log', '-n', '1', '--pretty=format:\'%s\''], ELECTRON_DIR);
|
||||||
|
|||||||
@@ -111,8 +111,9 @@ new Promise((resolve, reject) => {
|
|||||||
const currentBranch = await getCurrentBranch();
|
const currentBranch = await getCurrentBranch();
|
||||||
|
|
||||||
if (release.tag_name.indexOf('nightly') > 0) {
|
if (release.tag_name.indexOf('nightly') > 0) {
|
||||||
if (currentBranch === 'master') {
|
// TODO(main-migration): Simplify once main branch is renamed.
|
||||||
// Nightlies get published to their own module, so master nightlies should be tagged as latest
|
if (currentBranch === 'master' || currentBranch === 'main') {
|
||||||
|
// Nightlies get published to their own module, so they should be tagged as latest
|
||||||
npmTag = 'latest';
|
npmTag = 'latest';
|
||||||
} else {
|
} else {
|
||||||
npmTag = `nightly-${currentBranch}`;
|
npmTag = `nightly-${currentBranch}`;
|
||||||
@@ -127,10 +128,10 @@ new Promise((resolve, reject) => {
|
|||||||
JSON.stringify(currentJson, null, 2)
|
JSON.stringify(currentJson, null, 2)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
if (currentBranch === 'master') {
|
if (currentBranch === 'master' || currentBranch === 'main') {
|
||||||
// This should never happen, master releases should be nightly releases
|
// This should never happen, main releases should be nightly releases
|
||||||
// this is here just-in-case
|
// this is here just-in-case
|
||||||
npmTag = 'master';
|
throw new Error('Unreachable release phase, can\'t tag a non-nightly release on the main branch');
|
||||||
} else if (!release.prerelease) {
|
} else if (!release.prerelease) {
|
||||||
// Tag the release with a `2-0-x` style tag
|
// Tag the release with a `2-0-x` style tag
|
||||||
npmTag = currentBranch;
|
npmTag = currentBranch;
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const { GitProcess } = require('dugite');
|
const { GitProcess } = require('dugite');
|
||||||
const fs = require('fs');
|
const { promises: fs } = require('fs');
|
||||||
const semver = require('semver');
|
const semver = require('semver');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { promisify } = require('util');
|
|
||||||
const minimist = require('minimist');
|
const minimist = require('minimist');
|
||||||
|
|
||||||
const { ELECTRON_DIR } = require('../lib/utils');
|
const { ELECTRON_DIR } = require('../lib/utils');
|
||||||
const versionUtils = require('./version-utils');
|
const versionUtils = require('./version-utils');
|
||||||
|
const supported = path.resolve(ELECTRON_DIR, 'docs', 'tutorial', 'support.md');
|
||||||
|
|
||||||
const writeFile = promisify(fs.writeFile);
|
const writeFile = fs.writeFile;
|
||||||
const readFile = promisify(fs.readFile);
|
const readFile = fs.readFile;
|
||||||
|
|
||||||
function parseCommandLine () {
|
function parseCommandLine () {
|
||||||
let help;
|
let help;
|
||||||
@@ -54,6 +54,10 @@ async function main () {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shouldUpdateSupported(opts.bump, currentVersion, version)) {
|
||||||
|
await updateSupported(version, supported);
|
||||||
|
}
|
||||||
|
|
||||||
// update all version-related files
|
// update all version-related files
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
updateVersion(version),
|
updateVersion(version),
|
||||||
@@ -105,6 +109,22 @@ async function nextVersion (bumpType, version) {
|
|||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shouldUpdateSupported (bump, current, version) {
|
||||||
|
return isMajorStable(bump, current) || isMajorNightly(version, current);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMajorStable (bump, currentVersion) {
|
||||||
|
if (versionUtils.isBeta(currentVersion) && (bump === 'stable')) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMajorNightly (version, currentVersion) {
|
||||||
|
const parsed = semver.parse(version);
|
||||||
|
const current = semver.parse(currentVersion);
|
||||||
|
if (versionUtils.isNightly(currentVersion) && (parsed.major > current.major)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// update VERSION file with latest release info
|
// update VERSION file with latest release info
|
||||||
async function updateVersion (version) {
|
async function updateVersion (version) {
|
||||||
const versionPath = path.resolve(ELECTRON_DIR, 'ELECTRON_VERSION');
|
const versionPath = path.resolve(ELECTRON_DIR, 'ELECTRON_VERSION');
|
||||||
@@ -142,6 +162,22 @@ async function updateWinRC (components) {
|
|||||||
await writeFile(filePath, arr.join('\n'));
|
await writeFile(filePath, arr.join('\n'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updates support.md file with new semver values (stable only)
|
||||||
|
async function updateSupported (version, filePath) {
|
||||||
|
const v = parseInt(version);
|
||||||
|
const newVersions = [`* ${v}.x.y`, `* ${v - 1}.x.y`, `* ${v - 2}.x.y`];
|
||||||
|
const contents = await readFile(filePath, 'utf8');
|
||||||
|
const previousVersions = contents.split('\n').filter((elem) => {
|
||||||
|
return (/[^\n]*\.x\.y[^\n]*/).test(elem);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const newContents = previousVersions.reduce((contents, current, i) => {
|
||||||
|
return contents.replace(current, newVersions[i]);
|
||||||
|
}, contents);
|
||||||
|
|
||||||
|
await writeFile(filePath, newContents, 'utf8');
|
||||||
|
}
|
||||||
|
|
||||||
if (process.mainModule === module) {
|
if (process.mainModule === module) {
|
||||||
main().catch((error) => {
|
main().catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@@ -149,4 +185,4 @@ if (process.mainModule === module) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { nextVersion };
|
module.exports = { nextVersion, shouldUpdateSupported, updateSupported };
|
||||||
|
|||||||
@@ -65,8 +65,9 @@ async function nextNightly (v) {
|
|||||||
const pre = `nightly.${getCurrentDate()}`;
|
const pre = `nightly.${getCurrentDate()}`;
|
||||||
|
|
||||||
const branch = (await GitProcess.exec(['rev-parse', '--abbrev-ref', 'HEAD'], ELECTRON_DIR)).stdout.trim();
|
const branch = (await GitProcess.exec(['rev-parse', '--abbrev-ref', 'HEAD'], ELECTRON_DIR)).stdout.trim();
|
||||||
if (branch === 'master') {
|
// TODO(main-migration): Simplify once main branch is renamed
|
||||||
next = semver.inc(await getLastMajorForMaster(), 'major');
|
if (branch === 'master' || branch === 'main') {
|
||||||
|
next = semver.inc(await getLastMajorForMain(), 'major');
|
||||||
} else if (isStable(v)) {
|
} else if (isStable(v)) {
|
||||||
next = semver.inc(next, 'patch');
|
next = semver.inc(next, 'patch');
|
||||||
}
|
}
|
||||||
@@ -74,7 +75,7 @@ async function nextNightly (v) {
|
|||||||
return `${next}-${pre}`;
|
return `${next}-${pre}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getLastMajorForMaster () {
|
async function getLastMajorForMain () {
|
||||||
let branchNames;
|
let branchNames;
|
||||||
const result = await GitProcess.exec(['branch', '-a', '--remote', '--list', 'origin/[0-9]*-x-y'], ELECTRON_DIR);
|
const result = await GitProcess.exec(['branch', '-a', '--remote', '--list', 'origin/[0-9]*-x-y'], ELECTRON_DIR);
|
||||||
if (result.exitCode === 0) {
|
if (result.exitCode === 0) {
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ class App : public ElectronBrowserClient::Delegate,
|
|||||||
base::OnceClosure SelectClientCertificate(
|
base::OnceClosure SelectClientCertificate(
|
||||||
content::WebContents* web_contents,
|
content::WebContents* web_contents,
|
||||||
net::SSLCertRequestInfo* cert_request_info,
|
net::SSLCertRequestInfo* cert_request_info,
|
||||||
net::ClientCertIdentityList client_certs,
|
net::ClientCertIdentityList identities,
|
||||||
std::unique_ptr<content::ClientCertificateDelegate> delegate) override;
|
std::unique_ptr<content::ClientCertificateDelegate> delegate) override;
|
||||||
bool CanCreateWindow(content::RenderFrameHost* opener,
|
bool CanCreateWindow(content::RenderFrameHost* opener,
|
||||||
const GURL& opener_url,
|
const GURL& opener_url,
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class AutoUpdater : public gin::Wrappable<AutoUpdater>,
|
|||||||
~AutoUpdater() override;
|
~AutoUpdater() override;
|
||||||
|
|
||||||
// Delegate implementations.
|
// Delegate implementations.
|
||||||
void OnError(const std::string& error) override;
|
void OnError(const std::string& message) override;
|
||||||
void OnError(const std::string& message,
|
void OnError(const std::string& message,
|
||||||
const int code,
|
const int code,
|
||||||
const std::string& domain) override;
|
const std::string& domain) override;
|
||||||
|
|||||||
@@ -291,6 +291,7 @@ v8::Local<v8::Promise> Cookies::Set(v8::Isolate* isolate,
|
|||||||
const std::string* url_string = details.FindStringKey("url");
|
const std::string* url_string = details.FindStringKey("url");
|
||||||
if (!url_string) {
|
if (!url_string) {
|
||||||
promise.RejectWithErrorMessage("Missing required option 'url'");
|
promise.RejectWithErrorMessage("Missing required option 'url'");
|
||||||
|
return handle;
|
||||||
}
|
}
|
||||||
const std::string* name = details.FindStringKey("name");
|
const std::string* name = details.FindStringKey("name");
|
||||||
const std::string* value = details.FindStringKey("value");
|
const std::string* value = details.FindStringKey("value");
|
||||||
|
|||||||
@@ -74,17 +74,15 @@ const void* kElectronApiDownloadItemKey = &kElectronApiDownloadItemKey;
|
|||||||
gin::WrapperInfo DownloadItem::kWrapperInfo = {gin::kEmbedderNativeGin};
|
gin::WrapperInfo DownloadItem::kWrapperInfo = {gin::kEmbedderNativeGin};
|
||||||
|
|
||||||
// static
|
// static
|
||||||
DownloadItem* DownloadItem::FromDownloadItem(
|
DownloadItem* DownloadItem::FromDownloadItem(download::DownloadItem* item) {
|
||||||
download::DownloadItem* download_item) {
|
|
||||||
// ^- say that 7 times fast in a row
|
// ^- say that 7 times fast in a row
|
||||||
auto* data = static_cast<UserDataLink*>(
|
auto* data = static_cast<UserDataLink*>(
|
||||||
download_item->GetUserData(kElectronApiDownloadItemKey));
|
item->GetUserData(kElectronApiDownloadItemKey));
|
||||||
return data ? data->download_item.get() : nullptr;
|
return data ? data->download_item.get() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadItem::DownloadItem(v8::Isolate* isolate,
|
DownloadItem::DownloadItem(v8::Isolate* isolate, download::DownloadItem* item)
|
||||||
download::DownloadItem* download_item)
|
: download_item_(item), isolate_(isolate) {
|
||||||
: download_item_(download_item), isolate_(isolate) {
|
|
||||||
download_item_->AddObserver(this);
|
download_item_->AddObserver(this);
|
||||||
download_item_->SetUserData(
|
download_item_->SetUserData(
|
||||||
kElectronApiDownloadItemKey,
|
kElectronApiDownloadItemKey,
|
||||||
@@ -119,7 +117,7 @@ void DownloadItem::OnDownloadUpdated(download::DownloadItem* item) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadItem::OnDownloadDestroyed(download::DownloadItem* download_item) {
|
void DownloadItem::OnDownloadDestroyed(download::DownloadItem* /*item*/) {
|
||||||
download_item_ = nullptr;
|
download_item_ = nullptr;
|
||||||
Unpin();
|
Unpin();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class DownloadItem : public gin::Wrappable<DownloadItem>,
|
|||||||
static gin::Handle<DownloadItem> FromOrCreate(v8::Isolate* isolate,
|
static gin::Handle<DownloadItem> FromOrCreate(v8::Isolate* isolate,
|
||||||
download::DownloadItem* item);
|
download::DownloadItem* item);
|
||||||
|
|
||||||
static DownloadItem* FromDownloadItem(download::DownloadItem*);
|
static DownloadItem* FromDownloadItem(download::DownloadItem* item);
|
||||||
|
|
||||||
// gin::Wrappable
|
// gin::Wrappable
|
||||||
static gin::WrapperInfo kWrapperInfo;
|
static gin::WrapperInfo kWrapperInfo;
|
||||||
@@ -44,14 +44,14 @@ class DownloadItem : public gin::Wrappable<DownloadItem>,
|
|||||||
file_dialog::DialogSettings GetSaveDialogOptions() const;
|
file_dialog::DialogSettings GetSaveDialogOptions() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DownloadItem(v8::Isolate* isolate, download::DownloadItem* download_item);
|
DownloadItem(v8::Isolate* isolate, download::DownloadItem* item);
|
||||||
~DownloadItem() override;
|
~DownloadItem() override;
|
||||||
|
|
||||||
bool CheckAlive() const;
|
bool CheckAlive() const;
|
||||||
|
|
||||||
// download::DownloadItem::Observer
|
// download::DownloadItem::Observer
|
||||||
void OnDownloadUpdated(download::DownloadItem* download) override;
|
void OnDownloadUpdated(download::DownloadItem* item) override;
|
||||||
void OnDownloadDestroyed(download::DownloadItem* download) override;
|
void OnDownloadDestroyed(download::DownloadItem* item) override;
|
||||||
|
|
||||||
// JS API
|
// JS API
|
||||||
void Pause();
|
void Pause();
|
||||||
|
|||||||
@@ -236,11 +236,13 @@ std::u16string Menu::GetToolTipAt(int index) const {
|
|||||||
return model_->GetToolTipAt(index);
|
return model_->GetToolTipAt(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::u16string Menu::GetAcceleratorTextAt(int index) const {
|
#ifdef DCHECK_IS_ON
|
||||||
|
std::u16string Menu::GetAcceleratorTextAtForTesting(int index) const {
|
||||||
ui::Accelerator accelerator;
|
ui::Accelerator accelerator;
|
||||||
model_->GetAcceleratorAtWithParams(index, true, &accelerator);
|
model_->GetAcceleratorAtWithParams(index, true, &accelerator);
|
||||||
return accelerator.GetShortcutText();
|
return accelerator.GetShortcutText();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool Menu::IsItemCheckedAt(int index) const {
|
bool Menu::IsItemCheckedAt(int index) const {
|
||||||
return model_->IsItemCheckedAt(index);
|
return model_->IsItemCheckedAt(index);
|
||||||
@@ -289,13 +291,15 @@ v8::Local<v8::ObjectTemplate> Menu::FillObjectTemplate(
|
|||||||
.SetMethod("getLabelAt", &Menu::GetLabelAt)
|
.SetMethod("getLabelAt", &Menu::GetLabelAt)
|
||||||
.SetMethod("getSublabelAt", &Menu::GetSublabelAt)
|
.SetMethod("getSublabelAt", &Menu::GetSublabelAt)
|
||||||
.SetMethod("getToolTipAt", &Menu::GetToolTipAt)
|
.SetMethod("getToolTipAt", &Menu::GetToolTipAt)
|
||||||
.SetMethod("getAcceleratorTextAt", &Menu::GetAcceleratorTextAt)
|
|
||||||
.SetMethod("isItemCheckedAt", &Menu::IsItemCheckedAt)
|
.SetMethod("isItemCheckedAt", &Menu::IsItemCheckedAt)
|
||||||
.SetMethod("isEnabledAt", &Menu::IsEnabledAt)
|
.SetMethod("isEnabledAt", &Menu::IsEnabledAt)
|
||||||
.SetMethod("worksWhenHiddenAt", &Menu::WorksWhenHiddenAt)
|
.SetMethod("worksWhenHiddenAt", &Menu::WorksWhenHiddenAt)
|
||||||
.SetMethod("isVisibleAt", &Menu::IsVisibleAt)
|
.SetMethod("isVisibleAt", &Menu::IsVisibleAt)
|
||||||
.SetMethod("popupAt", &Menu::PopupAt)
|
.SetMethod("popupAt", &Menu::PopupAt)
|
||||||
.SetMethod("closePopupAt", &Menu::ClosePopupAt)
|
.SetMethod("closePopupAt", &Menu::ClosePopupAt)
|
||||||
|
#ifdef DCHECK_IS_ON
|
||||||
|
.SetMethod("getAcceleratorTextAt", &Menu::GetAcceleratorTextAtForTesting)
|
||||||
|
#endif
|
||||||
.Build();
|
.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,9 @@ class Menu : public gin::Wrappable<Menu>,
|
|||||||
int positioning_item,
|
int positioning_item,
|
||||||
base::OnceClosure callback) = 0;
|
base::OnceClosure callback) = 0;
|
||||||
virtual void ClosePopupAt(int32_t window_id) = 0;
|
virtual void ClosePopupAt(int32_t window_id) = 0;
|
||||||
|
#ifdef DCHECK_IS_ON
|
||||||
|
virtual std::u16string GetAcceleratorTextAtForTesting(int index) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
std::unique_ptr<ElectronMenuModel> model_;
|
std::unique_ptr<ElectronMenuModel> model_;
|
||||||
Menu* parent_ = nullptr;
|
Menu* parent_ = nullptr;
|
||||||
@@ -111,7 +114,6 @@ class Menu : public gin::Wrappable<Menu>,
|
|||||||
std::u16string GetLabelAt(int index) const;
|
std::u16string GetLabelAt(int index) const;
|
||||||
std::u16string GetSublabelAt(int index) const;
|
std::u16string GetSublabelAt(int index) const;
|
||||||
std::u16string GetToolTipAt(int index) const;
|
std::u16string GetToolTipAt(int index) const;
|
||||||
std::u16string GetAcceleratorTextAt(int index) const;
|
|
||||||
bool IsItemCheckedAt(int index) const;
|
bool IsItemCheckedAt(int index) const;
|
||||||
bool IsEnabledAt(int index) const;
|
bool IsEnabledAt(int index) const;
|
||||||
bool IsVisibleAt(int index) const;
|
bool IsVisibleAt(int index) const;
|
||||||
|
|||||||
@@ -35,11 +35,14 @@ class MenuMac : public Menu {
|
|||||||
int positioning_item,
|
int positioning_item,
|
||||||
base::OnceClosure callback);
|
base::OnceClosure callback);
|
||||||
void ClosePopupAt(int32_t window_id) override;
|
void ClosePopupAt(int32_t window_id) override;
|
||||||
void ClosePopupOnUI(int32_t window_id);
|
#ifdef DCHECK_IS_ON
|
||||||
|
std::u16string GetAcceleratorTextAtForTesting(int index) const override;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Menu;
|
friend class Menu;
|
||||||
|
|
||||||
|
void ClosePopupOnUI(int32_t window_id);
|
||||||
void OnClosed(int32_t window_id, base::OnceClosure callback);
|
void OnClosed(int32_t window_id, base::OnceClosure callback);
|
||||||
|
|
||||||
scoped_nsobject<ElectronMenuController> menu_controller_;
|
scoped_nsobject<ElectronMenuController> menu_controller_;
|
||||||
|
|||||||
@@ -127,6 +127,44 @@ void MenuMac::ClosePopupAt(int32_t window_id) {
|
|||||||
std::move(close_popup));
|
std::move(close_popup));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DCHECK_IS_ON
|
||||||
|
std::u16string MenuMac::GetAcceleratorTextAtForTesting(int index) const {
|
||||||
|
// A least effort to get the real shortcut text of NSMenuItem, the code does
|
||||||
|
// not need to be perfect since it is test only.
|
||||||
|
base::scoped_nsobject<ElectronMenuController> controller(
|
||||||
|
[[ElectronMenuController alloc] initWithModel:model()
|
||||||
|
useDefaultAccelerator:NO]);
|
||||||
|
NSMenuItem* item = [[controller menu] itemAtIndex:index];
|
||||||
|
std::u16string text;
|
||||||
|
NSEventModifierFlags modifiers = [item keyEquivalentModifierMask];
|
||||||
|
if (modifiers & NSEventModifierFlagControl)
|
||||||
|
text += u"Ctrl";
|
||||||
|
if (modifiers & NSEventModifierFlagShift) {
|
||||||
|
if (!text.empty())
|
||||||
|
text += u"+";
|
||||||
|
text += u"Shift";
|
||||||
|
}
|
||||||
|
if (modifiers & NSEventModifierFlagOption) {
|
||||||
|
if (!text.empty())
|
||||||
|
text += u"+";
|
||||||
|
text += u"Alt";
|
||||||
|
}
|
||||||
|
if (modifiers & NSEventModifierFlagCommand) {
|
||||||
|
if (!text.empty())
|
||||||
|
text += u"+";
|
||||||
|
text += u"Command";
|
||||||
|
}
|
||||||
|
if (!text.empty())
|
||||||
|
text += u"+";
|
||||||
|
auto key = base::ToUpperASCII(base::SysNSStringToUTF16([item keyEquivalent]));
|
||||||
|
if (key == u"\t")
|
||||||
|
text += u"Tab";
|
||||||
|
else
|
||||||
|
text += key;
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void MenuMac::ClosePopupOnUI(int32_t window_id) {
|
void MenuMac::ClosePopupOnUI(int32_t window_id) {
|
||||||
auto controller = popup_controllers_.find(window_id);
|
auto controller = popup_controllers_.find(window_id);
|
||||||
if (controller != popup_controllers_.end()) {
|
if (controller != popup_controllers_.end()) {
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ class Notification : public gin::Wrappable<Notification>,
|
|||||||
void SetHasReply(bool new_has_reply);
|
void SetHasReply(bool new_has_reply);
|
||||||
void SetUrgency(const std::u16string& new_urgency);
|
void SetUrgency(const std::u16string& new_urgency);
|
||||||
void SetTimeoutType(const std::u16string& new_timeout_type);
|
void SetTimeoutType(const std::u16string& new_timeout_type);
|
||||||
void SetReplyPlaceholder(const std::u16string& new_reply_placeholder);
|
void SetReplyPlaceholder(const std::u16string& new_placeholder);
|
||||||
void SetSound(const std::u16string& sound);
|
void SetSound(const std::u16string& sound);
|
||||||
void SetActions(const std::vector<electron::NotificationAction>& actions);
|
void SetActions(const std::vector<electron::NotificationAction>& actions);
|
||||||
void SetCloseButtonText(const std::u16string& text);
|
void SetCloseButtonText(const std::u16string& text);
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ struct Converter<CustomScheme> {
|
|||||||
// options are optional. Default values specified in SchemeOptions are used
|
// options are optional. Default values specified in SchemeOptions are used
|
||||||
if (dict.Get("privileges", &opt)) {
|
if (dict.Get("privileges", &opt)) {
|
||||||
opt.Get("standard", &(out->options.standard));
|
opt.Get("standard", &(out->options.standard));
|
||||||
opt.Get("supportFetchAPI", &(out->options.supportFetchAPI));
|
|
||||||
opt.Get("secure", &(out->options.secure));
|
opt.Get("secure", &(out->options.secure));
|
||||||
opt.Get("bypassCSP", &(out->options.bypassCSP));
|
opt.Get("bypassCSP", &(out->options.bypassCSP));
|
||||||
opt.Get("allowServiceWorkers", &(out->options.allowServiceWorkers));
|
opt.Get("allowServiceWorkers", &(out->options.allowServiceWorkers));
|
||||||
@@ -89,6 +88,16 @@ std::vector<std::string> GetStandardSchemes() {
|
|||||||
return g_standard_schemes;
|
return g_standard_schemes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddServiceWorkerScheme(const std::string& scheme) {
|
||||||
|
// There is no API to add service worker scheme, but there is an API to
|
||||||
|
// return const reference to the schemes vector.
|
||||||
|
// If in future the API is changed to return a copy instead of reference,
|
||||||
|
// the compilation will fail, and we should add a patch at that time.
|
||||||
|
auto& mutable_schemes =
|
||||||
|
const_cast<std::vector<std::string>&>(content::GetServiceWorkerSchemes());
|
||||||
|
mutable_schemes.push_back(scheme);
|
||||||
|
}
|
||||||
|
|
||||||
void RegisterSchemesAsPrivileged(gin_helper::ErrorThrower thrower,
|
void RegisterSchemesAsPrivileged(gin_helper::ErrorThrower thrower,
|
||||||
v8::Local<v8::Value> val) {
|
v8::Local<v8::Value> val) {
|
||||||
std::vector<CustomScheme> custom_schemes;
|
std::vector<CustomScheme> custom_schemes;
|
||||||
@@ -125,13 +134,7 @@ void RegisterSchemesAsPrivileged(gin_helper::ErrorThrower thrower,
|
|||||||
}
|
}
|
||||||
if (custom_scheme.options.allowServiceWorkers) {
|
if (custom_scheme.options.allowServiceWorkers) {
|
||||||
service_worker_schemes.push_back(custom_scheme.scheme);
|
service_worker_schemes.push_back(custom_scheme.scheme);
|
||||||
// There is no API to add service worker scheme, but there is an API to
|
AddServiceWorkerScheme(custom_scheme.scheme);
|
||||||
// return const reference to the schemes vector.
|
|
||||||
// If in future the API is changed to return a copy instead of reference,
|
|
||||||
// the compilation will fail, and we should add a patch at that time.
|
|
||||||
auto& mutable_schemes = const_cast<std::vector<std::string>&>(
|
|
||||||
content::GetServiceWorkerSchemes());
|
|
||||||
mutable_schemes.push_back(custom_scheme.scheme);
|
|
||||||
}
|
}
|
||||||
if (custom_scheme.options.stream) {
|
if (custom_scheme.options.stream) {
|
||||||
g_streaming_schemes.push_back(custom_scheme.scheme);
|
g_streaming_schemes.push_back(custom_scheme.scheme);
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ namespace api {
|
|||||||
|
|
||||||
std::vector<std::string> GetStandardSchemes();
|
std::vector<std::string> GetStandardSchemes();
|
||||||
|
|
||||||
|
void AddServiceWorkerScheme(const std::string& scheme);
|
||||||
|
|
||||||
void RegisterSchemesAsPrivileged(gin_helper::ErrorThrower thrower,
|
void RegisterSchemesAsPrivileged(gin_helper::ErrorThrower thrower,
|
||||||
v8::Local<v8::Value> val);
|
v8::Local<v8::Value> val);
|
||||||
|
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ class SimpleURLLoaderWrapper
|
|||||||
int64_t sent_bytes) override {}
|
int64_t sent_bytes) override {}
|
||||||
void Clone(
|
void Clone(
|
||||||
mojo::PendingReceiver<network::mojom::URLLoaderNetworkServiceObserver>
|
mojo::PendingReceiver<network::mojom::URLLoaderNetworkServiceObserver>
|
||||||
listener) override;
|
observer) override;
|
||||||
|
|
||||||
// SimpleURLLoader callbacks
|
// SimpleURLLoader callbacks
|
||||||
void OnResponseStarted(const GURL& final_url,
|
void OnResponseStarted(const GURL& final_url,
|
||||||
|
|||||||
@@ -1978,7 +1978,8 @@ void WebContents::LoadURL(const GURL& url,
|
|||||||
// Calling LoadURLWithParams() can trigger JS which destroys |this|.
|
// Calling LoadURLWithParams() can trigger JS which destroys |this|.
|
||||||
auto weak_this = GetWeakPtr();
|
auto weak_this = GetWeakPtr();
|
||||||
|
|
||||||
params.transition_type = ui::PAGE_TRANSITION_TYPED;
|
params.transition_type = ui::PageTransitionFromInt(
|
||||||
|
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
|
||||||
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
|
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
|
||||||
// Discord non-committed entries to ensure that we don't re-use a pending
|
// Discord non-committed entries to ensure that we don't re-use a pending
|
||||||
// entry
|
// entry
|
||||||
|
|||||||
@@ -387,7 +387,7 @@ void WebRequest::SetListener(Event event,
|
|||||||
std::set<std::string> filter_patterns;
|
std::set<std::string> filter_patterns;
|
||||||
gin::Dictionary dict(args->isolate());
|
gin::Dictionary dict(args->isolate());
|
||||||
if (args->GetNext(&arg) && !arg->IsFunction()) {
|
if (args->GetNext(&arg) && !arg->IsFunction()) {
|
||||||
// Note that gin treats Function as Dictionary when doing convertions, so we
|
// Note that gin treats Function as Dictionary when doing conversions, so we
|
||||||
// have to explicitly check if the argument is Function before trying to
|
// have to explicitly check if the argument is Function before trying to
|
||||||
// convert it to Dictionary.
|
// convert it to Dictionary.
|
||||||
if (gin::ConvertFromV8(args->isolate(), arg, &dict)) {
|
if (gin::ConvertFromV8(args->isolate(), arg, &dict)) {
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ namespace auto_updater {
|
|||||||
class Delegate {
|
class Delegate {
|
||||||
public:
|
public:
|
||||||
// An error happened.
|
// An error happened.
|
||||||
virtual void OnError(const std::string& error) {}
|
virtual void OnError(const std::string& message) {}
|
||||||
|
|
||||||
virtual void OnError(const std::string& error,
|
virtual void OnError(const std::string& message,
|
||||||
const int code,
|
const int code,
|
||||||
const std::string& domain) {}
|
const std::string& domain) {}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,12 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
|
#include "base/files/file_path.h"
|
||||||
|
#include "base/path_service.h"
|
||||||
#include "chrome/common/chrome_switches.h"
|
#include "chrome/common/chrome_switches.h"
|
||||||
|
#include "components/os_crypt/os_crypt.h"
|
||||||
#include "components/prefs/in_memory_pref_store.h"
|
#include "components/prefs/in_memory_pref_store.h"
|
||||||
|
#include "components/prefs/json_pref_store.h"
|
||||||
#include "components/prefs/overlay_user_pref_store.h"
|
#include "components/prefs/overlay_user_pref_store.h"
|
||||||
#include "components/prefs/pref_registry.h"
|
#include "components/prefs/pref_registry.h"
|
||||||
#include "components/prefs/pref_registry_simple.h"
|
#include "components/prefs/pref_registry_simple.h"
|
||||||
@@ -20,11 +24,13 @@
|
|||||||
#include "components/proxy_config/proxy_config_pref_names.h"
|
#include "components/proxy_config/proxy_config_pref_names.h"
|
||||||
#include "content/public/browser/child_process_security_policy.h"
|
#include "content/public/browser/child_process_security_policy.h"
|
||||||
#include "content/public/common/content_switches.h"
|
#include "content/public/common/content_switches.h"
|
||||||
|
#include "electron/fuses.h"
|
||||||
#include "extensions/common/constants.h"
|
#include "extensions/common/constants.h"
|
||||||
#include "net/proxy_resolution/proxy_config.h"
|
#include "net/proxy_resolution/proxy_config.h"
|
||||||
#include "net/proxy_resolution/proxy_config_service.h"
|
#include "net/proxy_resolution/proxy_config_service.h"
|
||||||
#include "net/proxy_resolution/proxy_config_with_annotation.h"
|
#include "net/proxy_resolution/proxy_config_with_annotation.h"
|
||||||
#include "services/network/public/cpp/network_switches.h"
|
#include "services/network/public/cpp/network_switches.h"
|
||||||
|
#include "shell/common/electron_paths.h"
|
||||||
|
|
||||||
#if BUILDFLAG(ENABLE_PRINTING)
|
#if BUILDFLAG(ENABLE_PRINTING)
|
||||||
#include "chrome/browser/printing/print_job_manager.h"
|
#include "chrome/browser/printing/print_job_manager.h"
|
||||||
@@ -83,15 +89,32 @@ BuildState* BrowserProcessImpl::GetBuildState() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BrowserProcessImpl::PostEarlyInitialization() {
|
void BrowserProcessImpl::PostEarlyInitialization() {
|
||||||
// Mock user prefs, as we only need to track changes for a
|
|
||||||
// in memory pref store. There are no persistent preferences
|
|
||||||
PrefServiceFactory prefs_factory;
|
PrefServiceFactory prefs_factory;
|
||||||
auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
|
auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
|
||||||
PrefProxyConfigTrackerImpl::RegisterPrefs(pref_registry.get());
|
PrefProxyConfigTrackerImpl::RegisterPrefs(pref_registry.get());
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
OSCrypt::RegisterLocalPrefs(pref_registry.get());
|
||||||
|
#endif
|
||||||
|
|
||||||
auto pref_store = base::MakeRefCounted<ValueMapPrefStore>();
|
auto pref_store = base::MakeRefCounted<ValueMapPrefStore>();
|
||||||
ApplyProxyModeFromCommandLine(pref_store.get());
|
ApplyProxyModeFromCommandLine(pref_store.get());
|
||||||
prefs_factory.set_command_line_prefs(std::move(pref_store));
|
prefs_factory.set_command_line_prefs(std::move(pref_store));
|
||||||
prefs_factory.set_user_prefs(new OverlayUserPrefStore(new InMemoryPrefStore));
|
|
||||||
|
// Only use a persistent prefs store when cookie encryption is enabled as that
|
||||||
|
// is the only key that needs it
|
||||||
|
if (electron::fuses::IsCookieEncryptionEnabled()) {
|
||||||
|
base::FilePath prefs_path;
|
||||||
|
CHECK(base::PathService::Get(electron::DIR_USER_DATA, &prefs_path));
|
||||||
|
prefs_path = prefs_path.Append(FILE_PATH_LITERAL("Local State"));
|
||||||
|
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||||
|
scoped_refptr<JsonPrefStore> user_pref_store =
|
||||||
|
base::MakeRefCounted<JsonPrefStore>(prefs_path);
|
||||||
|
user_pref_store->ReadPrefs();
|
||||||
|
prefs_factory.set_user_prefs(user_pref_store);
|
||||||
|
} else {
|
||||||
|
prefs_factory.set_user_prefs(
|
||||||
|
new OverlayUserPrefStore(new InMemoryPrefStore));
|
||||||
|
}
|
||||||
local_state_ = prefs_factory.Create(std::move(pref_registry));
|
local_state_ = prefs_factory.Create(std::move(pref_registry));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "base/strings/string_number_conversions.h"
|
#include "base/strings/string_number_conversions.h"
|
||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "chrome/browser/icon_manager.h"
|
#include "chrome/browser/icon_manager.h"
|
||||||
|
#include "components/os_crypt/os_crypt.h"
|
||||||
#include "content/browser/browser_main_loop.h" // nogncheck
|
#include "content/browser/browser_main_loop.h" // nogncheck
|
||||||
#include "content/public/browser/browser_thread.h"
|
#include "content/public/browser/browser_thread.h"
|
||||||
#include "content/public/browser/child_process_security_policy.h"
|
#include "content/public/browser/child_process_security_policy.h"
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
#include "content/public/common/content_switches.h"
|
#include "content/public/common/content_switches.h"
|
||||||
#include "content/public/common/result_codes.h"
|
#include "content/public/common/result_codes.h"
|
||||||
#include "electron/buildflags/buildflags.h"
|
#include "electron/buildflags/buildflags.h"
|
||||||
|
#include "electron/fuses.h"
|
||||||
#include "media/base/localized_strings.h"
|
#include "media/base/localized_strings.h"
|
||||||
#include "services/network/public/cpp/features.h"
|
#include "services/network/public/cpp/features.h"
|
||||||
#include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
|
#include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
|
||||||
@@ -42,7 +44,6 @@
|
|||||||
#include "shell/browser/ui/devtools_manager_delegate.h"
|
#include "shell/browser/ui/devtools_manager_delegate.h"
|
||||||
#include "shell/common/api/electron_bindings.h"
|
#include "shell/common/api/electron_bindings.h"
|
||||||
#include "shell/common/application_info.h"
|
#include "shell/common/application_info.h"
|
||||||
#include "shell/common/asar/asar_util.h"
|
|
||||||
#include "shell/common/electron_paths.h"
|
#include "shell/common/electron_paths.h"
|
||||||
#include "shell/common/gin_helper/trackable_object.h"
|
#include "shell/common/gin_helper/trackable_object.h"
|
||||||
#include "shell/common/node_bindings.h"
|
#include "shell/common/node_bindings.h"
|
||||||
@@ -207,9 +208,7 @@ ElectronBrowserMainParts::ElectronBrowserMainParts(
|
|||||||
self_ = this;
|
self_ = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ElectronBrowserMainParts::~ElectronBrowserMainParts() {
|
ElectronBrowserMainParts::~ElectronBrowserMainParts() = default;
|
||||||
asar::ClearArchives();
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
ElectronBrowserMainParts* ElectronBrowserMainParts::Get() {
|
ElectronBrowserMainParts* ElectronBrowserMainParts::Get() {
|
||||||
@@ -538,6 +537,16 @@ void ElectronBrowserMainParts::PreCreateMainMessageLoopCommon() {
|
|||||||
RegisterURLHandler();
|
RegisterURLHandler();
|
||||||
#endif
|
#endif
|
||||||
media::SetLocalizedStringProvider(MediaStringProvider);
|
media::SetLocalizedStringProvider(MediaStringProvider);
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
if (electron::fuses::IsCookieEncryptionEnabled()) {
|
||||||
|
auto* local_state = g_browser_process->local_state();
|
||||||
|
DCHECK(local_state);
|
||||||
|
|
||||||
|
bool os_crypt_init = OSCrypt::Init(local_state);
|
||||||
|
DCHECK(os_crypt_init);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
device::mojom::GeolocationControl*
|
device::mojom::GeolocationControl*
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class ElectronMessagingDelegate : public MessagingDelegate {
|
|||||||
void QueryIncognitoConnectability(
|
void QueryIncognitoConnectability(
|
||||||
content::BrowserContext* context,
|
content::BrowserContext* context,
|
||||||
const Extension* extension,
|
const Extension* extension,
|
||||||
content::WebContents* web_contents,
|
content::WebContents* source_contents,
|
||||||
const GURL& url,
|
const GURL& url,
|
||||||
base::OnceCallback<void(bool)> callback) override;
|
base::OnceCallback<void(bool)> callback) override;
|
||||||
|
|
||||||
|
|||||||
@@ -74,11 +74,11 @@ class FileSelectHelper : public content::WebContentsObserver,
|
|||||||
// of the package.
|
// of the package.
|
||||||
void ProcessSelectedFilesMac(const std::vector<ui::SelectedFileInfo>& files);
|
void ProcessSelectedFilesMac(const std::vector<ui::SelectedFileInfo>& files);
|
||||||
|
|
||||||
// Saves the paths of |zipped_files| for later deletion. Passes |files| to the
|
// Saves the paths of |temporary_files| for later deletion. Passes |files| to
|
||||||
// render view host.
|
// the render view host.
|
||||||
void ProcessSelectedFilesMacOnUIThread(
|
void ProcessSelectedFilesMacOnUIThread(
|
||||||
const std::vector<ui::SelectedFileInfo>& files,
|
const std::vector<ui::SelectedFileInfo>& files,
|
||||||
const std::vector<base::FilePath>& zipped_files);
|
const std::vector<base::FilePath>& temporary_files);
|
||||||
|
|
||||||
// Zips the package at |path| into a temporary destination. Returns the
|
// Zips the package at |path| into a temporary destination. Returns the
|
||||||
// temporary destination, if the zip was successful. Otherwise returns an
|
// temporary destination, if the zip was successful. Otherwise returns an
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ class NativeWindow : public base::SupportsUserData,
|
|||||||
virtual bool IsNormal();
|
virtual bool IsNormal();
|
||||||
virtual gfx::Rect GetNormalBounds() = 0;
|
virtual gfx::Rect GetNormalBounds() = 0;
|
||||||
virtual void SetSizeConstraints(
|
virtual void SetSizeConstraints(
|
||||||
const extensions::SizeConstraints& size_constraints);
|
const extensions::SizeConstraints& window_constraints);
|
||||||
virtual extensions::SizeConstraints GetSizeConstraints() const;
|
virtual extensions::SizeConstraints GetSizeConstraints() const;
|
||||||
virtual void SetContentSizeConstraints(
|
virtual void SetContentSizeConstraints(
|
||||||
const extensions::SizeConstraints& size_constraints);
|
const extensions::SizeConstraints& size_constraints);
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class NativeWindowMac : public NativeWindow,
|
|||||||
bool IsClosable() override;
|
bool IsClosable() override;
|
||||||
void SetAlwaysOnTop(ui::ZOrderLevel z_order,
|
void SetAlwaysOnTop(ui::ZOrderLevel z_order,
|
||||||
const std::string& level,
|
const std::string& level,
|
||||||
int relativeLevel) override;
|
int relative_level) override;
|
||||||
ui::ZOrderLevel GetZOrderLevel() override;
|
ui::ZOrderLevel GetZOrderLevel() override;
|
||||||
void Center() override;
|
void Center() override;
|
||||||
void Invalidate() override;
|
void Invalidate() override;
|
||||||
|
|||||||
@@ -1465,7 +1465,7 @@ void NativeWindowMac::SetTrafficLightPosition(
|
|||||||
base::Optional<gfx::Point> position) {
|
base::Optional<gfx::Point> position) {
|
||||||
traffic_light_position_ = std::move(position);
|
traffic_light_position_ = std::move(position);
|
||||||
if (buttons_view_) {
|
if (buttons_view_) {
|
||||||
[buttons_view_ setMargin:position];
|
[buttons_view_ setMargin:traffic_light_position_];
|
||||||
[buttons_view_ viewDidMoveToWindow];
|
[buttons_view_ viewDidMoveToWindow];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -332,12 +332,12 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options,
|
|||||||
last_window_state_ = ui::SHOW_STATE_NORMAL;
|
last_window_state_ = ui::SHOW_STATE_NORMAL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(OS_LINUX)
|
// Listen to mouse events.
|
||||||
// Listen to move events.
|
|
||||||
aura::Window* window = GetNativeWindow();
|
aura::Window* window = GetNativeWindow();
|
||||||
if (window)
|
if (window)
|
||||||
window->AddPreTargetHandler(this);
|
window->AddPreTargetHandler(this);
|
||||||
|
|
||||||
|
#if defined(OS_LINUX)
|
||||||
// On linux after the widget is initialized we might have to force set the
|
// On linux after the widget is initialized we might have to force set the
|
||||||
// bounds if the bounds are smaller than the current display
|
// bounds if the bounds are smaller than the current display
|
||||||
SetBounds(gfx::Rect(GetPosition(), bounds.size()), false);
|
SetBounds(gfx::Rect(GetPosition(), bounds.size()), false);
|
||||||
@@ -352,11 +352,9 @@ NativeWindowViews::~NativeWindowViews() {
|
|||||||
SetForwardMouseMessages(false);
|
SetForwardMouseMessages(false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(OS_LINUX)
|
|
||||||
aura::Window* window = GetNativeWindow();
|
aura::Window* window = GetNativeWindow();
|
||||||
if (window)
|
if (window)
|
||||||
window->RemovePreTargetHandler(this);
|
window->RemovePreTargetHandler(this);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeWindowViews::SetGTKDarkThemeEnabled(bool use_dark_theme) {
|
void NativeWindowViews::SetGTKDarkThemeEnabled(bool use_dark_theme) {
|
||||||
@@ -1461,11 +1459,9 @@ void NativeWindowViews::OnWidgetBoundsChanged(views::Widget* changed_widget,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void NativeWindowViews::OnWidgetDestroying(views::Widget* widget) {
|
void NativeWindowViews::OnWidgetDestroying(views::Widget* widget) {
|
||||||
#if defined(OS_LINUX)
|
|
||||||
aura::Window* window = GetNativeWindow();
|
aura::Window* window = GetNativeWindow();
|
||||||
if (window)
|
if (window)
|
||||||
window->RemovePreTargetHandler(this);
|
window->RemovePreTargetHandler(this);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeWindowViews::OnWidgetDestroyed(views::Widget* changed_widget) {
|
void NativeWindowViews::OnWidgetDestroyed(views::Widget* changed_widget) {
|
||||||
@@ -1583,17 +1579,20 @@ void NativeWindowViews::HandleKeyboardEvent(
|
|||||||
root_view_->HandleKeyEvent(event);
|
root_view_->HandleKeyEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(OS_LINUX)
|
|
||||||
void NativeWindowViews::OnMouseEvent(ui::MouseEvent* event) {
|
void NativeWindowViews::OnMouseEvent(ui::MouseEvent* event) {
|
||||||
if (event->type() != ui::ET_MOUSE_PRESSED)
|
if (event->type() != ui::ET_MOUSE_PRESSED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Alt+Click should not toggle menu bar.
|
||||||
|
root_view_->ResetAltState();
|
||||||
|
|
||||||
|
#if defined(OS_LINUX)
|
||||||
if (event->changed_button_flags() == ui::EF_BACK_MOUSE_BUTTON)
|
if (event->changed_button_flags() == ui::EF_BACK_MOUSE_BUTTON)
|
||||||
NotifyWindowExecuteAppCommand(kBrowserBackward);
|
NotifyWindowExecuteAppCommand(kBrowserBackward);
|
||||||
else if (event->changed_button_flags() == ui::EF_FORWARD_MOUSE_BUTTON)
|
else if (event->changed_button_flags() == ui::EF_FORWARD_MOUSE_BUTTON)
|
||||||
NotifyWindowExecuteAppCommand(kBrowserForward);
|
NotifyWindowExecuteAppCommand(kBrowserForward);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
ui::WindowShowState NativeWindowViews::GetRestoredState() {
|
ui::WindowShowState NativeWindowViews::GetRestoredState() {
|
||||||
if (IsMaximized())
|
if (IsMaximized())
|
||||||
|
|||||||
@@ -225,10 +225,8 @@ class NativeWindowViews : public NativeWindow,
|
|||||||
content::WebContents*,
|
content::WebContents*,
|
||||||
const content::NativeWebKeyboardEvent& event) override;
|
const content::NativeWebKeyboardEvent& event) override;
|
||||||
|
|
||||||
#if defined(OS_LINUX)
|
|
||||||
// ui::EventHandler:
|
// ui::EventHandler:
|
||||||
void OnMouseEvent(ui::MouseEvent* event) override;
|
void OnMouseEvent(ui::MouseEvent* event) override;
|
||||||
#endif
|
|
||||||
|
|
||||||
// Returns the restore state for the window.
|
// Returns the restore state for the window.
|
||||||
ui::WindowShowState GetRestoredState();
|
ui::WindowShowState GetRestoredState();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "chrome/common/chrome_constants.h"
|
#include "chrome/common/chrome_constants.h"
|
||||||
#include "content/public/browser/network_service_instance.h"
|
#include "content/public/browser/network_service_instance.h"
|
||||||
#include "content/public/browser/shared_cors_origin_access_list.h"
|
#include "content/public/browser/shared_cors_origin_access_list.h"
|
||||||
|
#include "electron/fuses.h"
|
||||||
#include "net/net_buildflags.h"
|
#include "net/net_buildflags.h"
|
||||||
#include "services/network/network_service.h"
|
#include "services/network/network_service.h"
|
||||||
#include "services/network/public/cpp/cors/origin_access_list.h"
|
#include "services/network/public/cpp/cors/origin_access_list.h"
|
||||||
@@ -77,9 +78,8 @@ void NetworkContextService::ConfigureNetworkContextParams(
|
|||||||
network_context_params->restore_old_session_cookies = false;
|
network_context_params->restore_old_session_cookies = false;
|
||||||
network_context_params->persist_session_cookies = false;
|
network_context_params->persist_session_cookies = false;
|
||||||
|
|
||||||
// TODO(deepak1556): Matches the existing behavior https://git.io/fxHMl,
|
network_context_params->enable_encrypted_cookies =
|
||||||
// enable encryption as a followup.
|
electron::fuses::IsCookieEncryptionEnabled();
|
||||||
network_context_params->enable_encrypted_cookies = false;
|
|
||||||
|
|
||||||
network_context_params->transport_security_persister_path = path;
|
network_context_params->transport_security_persister_path = path;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,16 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
|
#include "base/path_service.h"
|
||||||
#include "chrome/browser/browser_process.h"
|
#include "chrome/browser/browser_process.h"
|
||||||
#include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h"
|
#include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h"
|
||||||
|
#include "chrome/common/chrome_switches.h"
|
||||||
|
#include "components/os_crypt/os_crypt.h"
|
||||||
#include "content/public/browser/browser_thread.h"
|
#include "content/public/browser/browser_thread.h"
|
||||||
#include "content/public/browser/network_service_instance.h"
|
#include "content/public/browser/network_service_instance.h"
|
||||||
#include "content/public/common/content_features.h"
|
#include "content/public/common/content_features.h"
|
||||||
|
#include "content/public/common/network_service_util.h"
|
||||||
|
#include "electron/fuses.h"
|
||||||
#include "mojo/public/cpp/bindings/pending_receiver.h"
|
#include "mojo/public/cpp/bindings/pending_receiver.h"
|
||||||
#include "net/net_buildflags.h"
|
#include "net/net_buildflags.h"
|
||||||
#include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
|
#include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
|
||||||
@@ -21,11 +26,17 @@
|
|||||||
#include "services/network/public/cpp/features.h"
|
#include "services/network/public/cpp/features.h"
|
||||||
#include "services/network/public/cpp/shared_url_loader_factory.h"
|
#include "services/network/public/cpp/shared_url_loader_factory.h"
|
||||||
#include "services/network/public/mojom/network_context.mojom.h"
|
#include "services/network/public/mojom/network_context.mojom.h"
|
||||||
|
#include "shell/browser/browser.h"
|
||||||
#include "shell/browser/electron_browser_client.h"
|
#include "shell/browser/electron_browser_client.h"
|
||||||
#include "shell/common/application_info.h"
|
#include "shell/common/application_info.h"
|
||||||
|
#include "shell/common/electron_paths.h"
|
||||||
#include "shell/common/options_switches.h"
|
#include "shell/common/options_switches.h"
|
||||||
#include "url/gurl.h"
|
#include "url/gurl.h"
|
||||||
|
|
||||||
|
#if defined(OS_MAC)
|
||||||
|
#include "components/os_crypt/keychain_password_mac.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// The global instance of the SystemNetworkContextmanager.
|
// The global instance of the SystemNetworkContextmanager.
|
||||||
@@ -218,6 +229,39 @@ void SystemNetworkContextManager::OnNetworkServiceCreated(
|
|||||||
network_service->CreateNetworkContext(
|
network_service->CreateNetworkContext(
|
||||||
network_context_.BindNewPipeAndPassReceiver(),
|
network_context_.BindNewPipeAndPassReceiver(),
|
||||||
CreateNetworkContextParams());
|
CreateNetworkContextParams());
|
||||||
|
|
||||||
|
if (electron::fuses::IsCookieEncryptionEnabled()) {
|
||||||
|
std::string app_name = electron::Browser::Get()->GetName();
|
||||||
|
#if defined(OS_MAC)
|
||||||
|
*KeychainPassword::service_name = app_name + " Safe Storage";
|
||||||
|
*KeychainPassword::account_name = app_name;
|
||||||
|
#endif
|
||||||
|
// The OSCrypt keys are process bound, so if network service is out of
|
||||||
|
// process, send it the required key.
|
||||||
|
if (content::IsOutOfProcessNetworkService()) {
|
||||||
|
#if defined(OS_LINUX)
|
||||||
|
// c.f.
|
||||||
|
// https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/net/system_network_context_manager.cc;l=515;drc=9d82515060b9b75fa941986f5db7390299669ef1;bpv=1;bpt=1
|
||||||
|
const base::CommandLine& command_line =
|
||||||
|
*base::CommandLine::ForCurrentProcess();
|
||||||
|
|
||||||
|
network::mojom::CryptConfigPtr config =
|
||||||
|
network::mojom::CryptConfig::New();
|
||||||
|
config->application_name = app_name;
|
||||||
|
config->product_name = app_name;
|
||||||
|
// c.f.
|
||||||
|
// https://source.chromium.org/chromium/chromium/src/+/master:chrome/common/chrome_switches.cc;l=689;drc=9d82515060b9b75fa941986f5db7390299669ef1
|
||||||
|
config->store =
|
||||||
|
command_line.GetSwitchValueASCII(::switches::kPasswordStore);
|
||||||
|
config->should_use_preference =
|
||||||
|
command_line.HasSwitch(::switches::kEnableEncryptionSelection);
|
||||||
|
base::PathService::Get(electron::DIR_USER_DATA, &config->user_data_path);
|
||||||
|
network_service->SetCryptConfig(std::move(config));
|
||||||
|
#else
|
||||||
|
network_service->SetEncryptionKey(OSCrypt::GetRawEncryptionKey());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
network::mojom::NetworkContextParamsPtr
|
network::mojom::NetworkContextParamsPtr
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class CocoaNotification;
|
|||||||
|
|
||||||
class NotificationPresenterMac : public NotificationPresenter {
|
class NotificationPresenterMac : public NotificationPresenter {
|
||||||
public:
|
public:
|
||||||
CocoaNotification* GetNotification(NSUserNotification* notif);
|
CocoaNotification* GetNotification(NSUserNotification* ns_notification);
|
||||||
|
|
||||||
NotificationPresenterMac();
|
NotificationPresenterMac();
|
||||||
~NotificationPresenterMac() override;
|
~NotificationPresenterMac() override;
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
|
|||||||
// content::RenderWidgetHostViewBase:
|
// content::RenderWidgetHostViewBase:
|
||||||
|
|
||||||
void ResetFallbackToFirstNavigationSurface() override;
|
void ResetFallbackToFirstNavigationSurface() override;
|
||||||
void InitAsPopup(content::RenderWidgetHostView* rwhv,
|
void InitAsPopup(content::RenderWidgetHostView* parent_host_view,
|
||||||
const gfx::Rect& rect) override;
|
const gfx::Rect& rect) override;
|
||||||
void UpdateCursor(const content::WebCursor&) override;
|
void UpdateCursor(const content::WebCursor&) override;
|
||||||
void SetIsLoading(bool is_loading) override;
|
void SetIsLoading(bool is_loading) override;
|
||||||
@@ -127,7 +127,7 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
|
|||||||
const gfx::Rect& src_rect,
|
const gfx::Rect& src_rect,
|
||||||
const gfx::Size& output_size,
|
const gfx::Size& output_size,
|
||||||
base::OnceCallback<void(const SkBitmap&)> callback) override;
|
base::OnceCallback<void(const SkBitmap&)> callback) override;
|
||||||
void GetScreenInfo(blink::ScreenInfo* results) override;
|
void GetScreenInfo(blink::ScreenInfo* screen_info) override;
|
||||||
void TransformPointToRootSurface(gfx::PointF* point) override;
|
void TransformPointToRootSurface(gfx::PointF* point) override;
|
||||||
gfx::Rect GetBoundsInRootWindow(void) override;
|
gfx::Rect GetBoundsInRootWindow(void) override;
|
||||||
base::Optional<content::DisplayFeature> GetDisplayFeature() override;
|
base::Optional<content::DisplayFeature> GetDisplayFeature() override;
|
||||||
|
|||||||
@@ -50,10 +50,10 @@ using StringVector = base::CommandLine::StringVector;
|
|||||||
|
|
||||||
// Relaunches the application using the helper application associated with the
|
// Relaunches the application using the helper application associated with the
|
||||||
// currently running instance of Chrome in the parent browser process as the
|
// currently running instance of Chrome in the parent browser process as the
|
||||||
// executable for the relauncher process. |args| is an argv-style vector of
|
// executable for the relauncher process. |argv| is an argv-style vector of
|
||||||
// command line arguments of the form normally passed to execv. args[0] is
|
// command line arguments of the form normally passed to execv. argv[0] is
|
||||||
// also the path to the relaunched process. Because the relauncher process
|
// also the path to the relaunched process. Because the relauncher process
|
||||||
// will ultimately launch the relaunched process via Launch Services, args[0]
|
// will ultimately launch the relaunched process via Launch Services, argv[0]
|
||||||
// may be either a pathname to an executable file or a pathname to an .app
|
// may be either a pathname to an executable file or a pathname to an .app
|
||||||
// bundle directory. The caller should exit soon after RelaunchApp returns
|
// bundle directory. The caller should exit soon after RelaunchApp returns
|
||||||
// successfully. Returns true on success, although some failures can occur
|
// successfully. Returns true on success, although some failures can occur
|
||||||
@@ -63,7 +63,7 @@ bool RelaunchApp(const StringVector& argv);
|
|||||||
|
|
||||||
// Identical to RelaunchApp, but uses |helper| as the path to the relauncher
|
// Identical to RelaunchApp, but uses |helper| as the path to the relauncher
|
||||||
// process, and allows additional arguments to be supplied to the relauncher
|
// process, and allows additional arguments to be supplied to the relauncher
|
||||||
// process in relauncher_args. Unlike args[0], |helper| must be a pathname to
|
// process in relauncher_args. Unlike argv[0], |helper| must be a pathname to
|
||||||
// an executable file. The helper path given must be from the same version of
|
// an executable file. The helper path given must be from the same version of
|
||||||
// Chrome as the running parent browser process, as there are no guarantees
|
// Chrome as the running parent browser process, as there are no guarantees
|
||||||
// that the parent and relauncher processes from different versions will be
|
// that the parent and relauncher processes from different versions will be
|
||||||
@@ -72,7 +72,7 @@ bool RelaunchApp(const StringVector& argv);
|
|||||||
// location's helper.
|
// location's helper.
|
||||||
bool RelaunchAppWithHelper(const base::FilePath& helper,
|
bool RelaunchAppWithHelper(const base::FilePath& helper,
|
||||||
const StringVector& relauncher_args,
|
const StringVector& relauncher_args,
|
||||||
const StringVector& args);
|
const StringVector& argv);
|
||||||
|
|
||||||
// The entry point from ChromeMain into the relauncher process.
|
// The entry point from ChromeMain into the relauncher process.
|
||||||
int RelauncherMain(const content::MainFunctionParams& main_parameters);
|
int RelauncherMain(const content::MainFunctionParams& main_parameters);
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ END
|
|||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 14,0,0,20210524
|
FILEVERSION 14,0,0,4
|
||||||
PRODUCTVERSION 14,0,0,20210524
|
PRODUCTVERSION 14,0,0,4
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ bool StringToAccelerator(const std::string& shortcut,
|
|||||||
// Now, parse it into an accelerator.
|
// Now, parse it into an accelerator.
|
||||||
int modifiers = ui::EF_NONE;
|
int modifiers = ui::EF_NONE;
|
||||||
ui::KeyboardCode key = ui::VKEY_UNKNOWN;
|
ui::KeyboardCode key = ui::VKEY_UNKNOWN;
|
||||||
|
base::Optional<char16_t> shifted_char;
|
||||||
for (const auto& token : tokens) {
|
for (const auto& token : tokens) {
|
||||||
bool shifted = false;
|
ui::KeyboardCode code = electron::KeyboardCodeFromStr(token, &shifted_char);
|
||||||
ui::KeyboardCode code = electron::KeyboardCodeFromStr(token, &shifted);
|
if (shifted_char)
|
||||||
if (shifted)
|
|
||||||
modifiers |= ui::EF_SHIFT_DOWN;
|
modifiers |= ui::EF_SHIFT_DOWN;
|
||||||
switch (code) {
|
switch (code) {
|
||||||
// The token can be a modifier.
|
// The token can be a modifier.
|
||||||
@@ -65,6 +65,7 @@ bool StringToAccelerator(const std::string& shortcut,
|
|||||||
}
|
}
|
||||||
|
|
||||||
*accelerator = ui::Accelerator(key, modifiers);
|
*accelerator = ui::Accelerator(key, modifiers);
|
||||||
|
accelerator->shifted_char = shifted_char;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ typedef struct {
|
|||||||
typedef std::map<ui::Accelerator, MenuItem> AcceleratorTable;
|
typedef std::map<ui::Accelerator, MenuItem> AcceleratorTable;
|
||||||
|
|
||||||
// Parse a string as an accelerator.
|
// Parse a string as an accelerator.
|
||||||
bool StringToAccelerator(const std::string& description,
|
bool StringToAccelerator(const std::string& shortcut,
|
||||||
ui::Accelerator* accelerator);
|
ui::Accelerator* accelerator);
|
||||||
|
|
||||||
// Generate a table that contains memu model's accelerators and command ids.
|
// Generate a table that contains menu model's accelerators and command ids.
|
||||||
void GenerateAcceleratorTable(AcceleratorTable* table,
|
void GenerateAcceleratorTable(AcceleratorTable* table,
|
||||||
electron::ElectronMenuModel* model);
|
electron::ElectronMenuModel* model);
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,9 @@
|
|||||||
#include "shell/browser/ui/electron_menu_model.h"
|
#include "shell/browser/ui/electron_menu_model.h"
|
||||||
#include "shell/browser/window_list.h"
|
#include "shell/browser/window_list.h"
|
||||||
#include "ui/base/accelerators/accelerator.h"
|
#include "ui/base/accelerators/accelerator.h"
|
||||||
#include "ui/base/accelerators/platform_accelerator_cocoa.h"
|
|
||||||
#include "ui/base/l10n/l10n_util_mac.h"
|
#include "ui/base/l10n/l10n_util_mac.h"
|
||||||
#include "ui/events/cocoa/cocoa_event_utils.h"
|
#include "ui/events/cocoa/cocoa_event_utils.h"
|
||||||
|
#include "ui/events/keycodes/keyboard_code_conversion_mac.h"
|
||||||
#include "ui/gfx/image/image.h"
|
#include "ui/gfx/image/image.h"
|
||||||
#include "ui/strings/grit/ui_strings.h"
|
#include "ui/strings/grit/ui_strings.h"
|
||||||
|
|
||||||
@@ -392,11 +392,31 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
|
|||||||
ui::Accelerator accelerator;
|
ui::Accelerator accelerator;
|
||||||
if (model->GetAcceleratorAtWithParams(index, useDefaultAccelerator_,
|
if (model->GetAcceleratorAtWithParams(index, useDefaultAccelerator_,
|
||||||
&accelerator)) {
|
&accelerator)) {
|
||||||
NSString* key_equivalent;
|
// Note that we are not using Chromium's
|
||||||
NSUInteger modifier_mask;
|
// GetKeyEquivalentAndModifierMaskFromAccelerator API,
|
||||||
GetKeyEquivalentAndModifierMaskFromAccelerator(
|
// because it will convert Shift+Character to ShiftedCharacter, for
|
||||||
accelerator, &key_equivalent, &modifier_mask);
|
// example Shift+/ would be converted to ?, which is against macOS HIG.
|
||||||
[item setKeyEquivalent:key_equivalent];
|
// See also https://github.com/electron/electron/issues/21790.
|
||||||
|
NSUInteger modifier_mask = 0;
|
||||||
|
if (accelerator.IsCtrlDown())
|
||||||
|
modifier_mask |= NSEventModifierFlagControl;
|
||||||
|
if (accelerator.IsAltDown())
|
||||||
|
modifier_mask |= NSEventModifierFlagOption;
|
||||||
|
if (accelerator.IsCmdDown())
|
||||||
|
modifier_mask |= NSEventModifierFlagCommand;
|
||||||
|
unichar character;
|
||||||
|
if (accelerator.shifted_char) {
|
||||||
|
// When a shifted char is explicitly specified, for example Ctrl+Plus,
|
||||||
|
// use the shifted char directly.
|
||||||
|
character = static_cast<unichar>(*accelerator.shifted_char);
|
||||||
|
} else {
|
||||||
|
// Otherwise use the unshifted combinations, for example Ctrl+Shift+=.
|
||||||
|
if (accelerator.IsShiftDown())
|
||||||
|
modifier_mask |= NSEventModifierFlagShift;
|
||||||
|
ui::MacKeyCodeForWindowsKeyCode(accelerator.key_code(), modifier_mask,
|
||||||
|
nullptr, &character);
|
||||||
|
}
|
||||||
|
[item setKeyEquivalent:[NSString stringWithFormat:@"%C", character]];
|
||||||
[item setKeyEquivalentModifierMask:modifier_mask];
|
[item setKeyEquivalentModifierMask:modifier_mask];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ void MenuBar::SetAcceleratorVisibility(bool visible) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MenuBar::View* MenuBar::FindAccelChild(char16_t key) {
|
MenuBar::View* MenuBar::FindAccelChild(char16_t key) {
|
||||||
|
if (key == 0)
|
||||||
|
return nullptr;
|
||||||
for (auto* child : GetChildrenInZOrder()) {
|
for (auto* child : GetChildrenInZOrder()) {
|
||||||
if (static_cast<SubmenuButton*>(child)->accelerator() == key)
|
if (static_cast<SubmenuButton*>(child)->accelerator() == key)
|
||||||
return child;
|
return child;
|
||||||
@@ -124,7 +126,10 @@ bool MenuBar::AcceleratorPressed(const ui::Accelerator& accelerator) {
|
|||||||
? ui::Accelerator(ui::VKEY_ESCAPE, accelerator.modifiers(),
|
? ui::Accelerator(ui::VKEY_ESCAPE, accelerator.modifiers(),
|
||||||
accelerator.key_state(), accelerator.time_stamp())
|
accelerator.key_state(), accelerator.time_stamp())
|
||||||
: accelerator;
|
: accelerator;
|
||||||
return views::AccessiblePaneView::AcceleratorPressed(translated);
|
bool result = views::AccessiblePaneView::AcceleratorPressed(translated);
|
||||||
|
if (result && !pane_has_focus())
|
||||||
|
root_view_->RestoreFocus();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MenuBar::SetPaneFocusAndFocusDefault() {
|
bool MenuBar::SetPaneFocusAndFocusDefault() {
|
||||||
@@ -149,6 +154,8 @@ void MenuBar::OnThemeChanged() {
|
|||||||
void MenuBar::OnDidChangeFocus(View* focused_before, View* focused_now) {
|
void MenuBar::OnDidChangeFocus(View* focused_before, View* focused_now) {
|
||||||
views::AccessiblePaneView::OnDidChangeFocus(focused_before, focused_now);
|
views::AccessiblePaneView::OnDidChangeFocus(focused_before, focused_now);
|
||||||
SetAcceleratorVisibility(pane_has_focus());
|
SetAcceleratorVisibility(pane_has_focus());
|
||||||
|
if (!pane_has_focus())
|
||||||
|
root_view_->RestoreFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* MenuBar::GetClassName() const {
|
const char* MenuBar::GetClassName() const {
|
||||||
|
|||||||
@@ -119,18 +119,18 @@ void RootView::HandleKeyEvent(const content::NativeWebKeyboardEvent& event) {
|
|||||||
|
|
||||||
// Show the submenu when "Alt+Key" is pressed.
|
// Show the submenu when "Alt+Key" is pressed.
|
||||||
if (event.GetType() == blink::WebInputEvent::Type::kRawKeyDown &&
|
if (event.GetType() == blink::WebInputEvent::Type::kRawKeyDown &&
|
||||||
!IsAltKey(event) && IsAltModifier(event)) {
|
event.windows_key_code >= ui::VKEY_A &&
|
||||||
if (menu_bar_->HasAccelerator(event.windows_key_code)) {
|
event.windows_key_code <= ui::VKEY_Z && IsAltModifier(event) &&
|
||||||
if (!menu_bar_visible_) {
|
menu_bar_->HasAccelerator(event.windows_key_code)) {
|
||||||
SetMenuBarVisibility(true);
|
if (!menu_bar_visible_) {
|
||||||
|
SetMenuBarVisibility(true);
|
||||||
|
|
||||||
View* focused_view = GetFocusManager()->GetFocusedView();
|
View* focused_view = GetFocusManager()->GetFocusedView();
|
||||||
last_focused_view_tracker_->SetView(focused_view);
|
last_focused_view_tracker_->SetView(focused_view);
|
||||||
menu_bar_->RequestFocus();
|
menu_bar_->RequestFocus();
|
||||||
}
|
|
||||||
|
|
||||||
menu_bar_->ActivateAccelerator(event.windows_key_code);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
menu_bar_->ActivateAccelerator(event.windows_key_code);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class WebDialogHelper {
|
|||||||
const blink::mojom::FileChooserParams& params);
|
const blink::mojom::FileChooserParams& params);
|
||||||
void EnumerateDirectory(content::WebContents* web_contents,
|
void EnumerateDirectory(content::WebContents* web_contents,
|
||||||
scoped_refptr<content::FileSelectListener> listener,
|
scoped_refptr<content::FileSelectListener> listener,
|
||||||
const base::FilePath& path);
|
const base::FilePath& dir);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NativeWindow* window_;
|
NativeWindow* window_;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "base/check.h"
|
||||||
#include "base/files/file.h"
|
#include "base/files/file.h"
|
||||||
#include "base/files/file_util.h"
|
#include "base/files/file_util.h"
|
||||||
#include "base/json/json_reader.h"
|
#include "base/json/json_reader.h"
|
||||||
@@ -118,7 +119,7 @@ bool FillFileInfoWithNode(Archive::FileInfo* info,
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Archive::Archive(const base::FilePath& path)
|
Archive::Archive(const base::FilePath& path)
|
||||||
: path_(path), file_(base::File::FILE_OK) {
|
: initialized_(false), path_(path), file_(base::File::FILE_OK) {
|
||||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||||
file_.Initialize(path_, base::File::FLAG_OPEN | base::File::FLAG_READ);
|
file_.Initialize(path_, base::File::FLAG_OPEN | base::File::FLAG_READ);
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
@@ -141,6 +142,10 @@ Archive::~Archive() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Archive::Init() {
|
bool Archive::Init() {
|
||||||
|
// Should only be initialized once
|
||||||
|
CHECK(!initialized_);
|
||||||
|
initialized_ = true;
|
||||||
|
|
||||||
if (!file_.IsValid()) {
|
if (!file_.IsValid()) {
|
||||||
if (file_.error_details() != base::File::FILE_ERROR_NOT_FOUND) {
|
if (file_.error_details() != base::File::FILE_ERROR_NOT_FOUND) {
|
||||||
LOG(WARNING) << "Opening " << path_.value() << ": "
|
LOG(WARNING) << "Opening " << path_.value() << ": "
|
||||||
@@ -198,7 +203,7 @@ bool Archive::Init() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Archive::GetFileInfo(const base::FilePath& path, FileInfo* info) {
|
bool Archive::GetFileInfo(const base::FilePath& path, FileInfo* info) const {
|
||||||
if (!header_)
|
if (!header_)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -213,7 +218,7 @@ bool Archive::GetFileInfo(const base::FilePath& path, FileInfo* info) {
|
|||||||
return FillFileInfoWithNode(info, header_size_, node);
|
return FillFileInfoWithNode(info, header_size_, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Archive::Stat(const base::FilePath& path, Stats* stats) {
|
bool Archive::Stat(const base::FilePath& path, Stats* stats) const {
|
||||||
if (!header_)
|
if (!header_)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -237,7 +242,7 @@ bool Archive::Stat(const base::FilePath& path, Stats* stats) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Archive::Readdir(const base::FilePath& path,
|
bool Archive::Readdir(const base::FilePath& path,
|
||||||
std::vector<base::FilePath>* list) {
|
std::vector<base::FilePath>* files) const {
|
||||||
if (!header_)
|
if (!header_)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -245,19 +250,20 @@ bool Archive::Readdir(const base::FilePath& path,
|
|||||||
if (!GetNodeFromPath(path.AsUTF8Unsafe(), header_.get(), &node))
|
if (!GetNodeFromPath(path.AsUTF8Unsafe(), header_.get(), &node))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const base::DictionaryValue* files;
|
const base::DictionaryValue* files_node;
|
||||||
if (!GetFilesNode(header_.get(), node, &files))
|
if (!GetFilesNode(header_.get(), node, &files_node))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
base::DictionaryValue::Iterator iter(*files);
|
base::DictionaryValue::Iterator iter(*files_node);
|
||||||
while (!iter.IsAtEnd()) {
|
while (!iter.IsAtEnd()) {
|
||||||
list->push_back(base::FilePath::FromUTF8Unsafe(iter.key()));
|
files->push_back(base::FilePath::FromUTF8Unsafe(iter.key()));
|
||||||
iter.Advance();
|
iter.Advance();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Archive::Realpath(const base::FilePath& path, base::FilePath* realpath) {
|
bool Archive::Realpath(const base::FilePath& path,
|
||||||
|
base::FilePath* realpath) const {
|
||||||
if (!header_)
|
if (!header_)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -276,6 +282,11 @@ bool Archive::Realpath(const base::FilePath& path, base::FilePath* realpath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) {
|
bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) {
|
||||||
|
if (!header_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
base::AutoLock auto_lock(external_files_lock_);
|
||||||
|
|
||||||
auto it = external_files_.find(path.value());
|
auto it = external_files_.find(path.value());
|
||||||
if (it != external_files_.end()) {
|
if (it != external_files_.end()) {
|
||||||
*out = it->second->path();
|
*out = it->second->path();
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "base/files/file.h"
|
#include "base/files/file.h"
|
||||||
#include "base/files/file_path.h"
|
#include "base/files/file_path.h"
|
||||||
|
#include "base/synchronization/lock.h"
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
class DictionaryValue;
|
class DictionaryValue;
|
||||||
@@ -21,7 +22,7 @@ namespace asar {
|
|||||||
class ScopedTemporaryFile;
|
class ScopedTemporaryFile;
|
||||||
|
|
||||||
// This class represents an asar package, and provides methods to read
|
// This class represents an asar package, and provides methods to read
|
||||||
// information from it.
|
// information from it. It is thread-safe after |Init| has been called.
|
||||||
class Archive {
|
class Archive {
|
||||||
public:
|
public:
|
||||||
struct FileInfo {
|
struct FileInfo {
|
||||||
@@ -46,16 +47,17 @@ class Archive {
|
|||||||
bool Init();
|
bool Init();
|
||||||
|
|
||||||
// Get the info of a file.
|
// Get the info of a file.
|
||||||
bool GetFileInfo(const base::FilePath& path, FileInfo* info);
|
bool GetFileInfo(const base::FilePath& path, FileInfo* info) const;
|
||||||
|
|
||||||
// Fs.stat(path).
|
// Fs.stat(path).
|
||||||
bool Stat(const base::FilePath& path, Stats* stats);
|
bool Stat(const base::FilePath& path, Stats* stats) const;
|
||||||
|
|
||||||
// Fs.readdir(path).
|
// Fs.readdir(path).
|
||||||
bool Readdir(const base::FilePath& path, std::vector<base::FilePath>* files);
|
bool Readdir(const base::FilePath& path,
|
||||||
|
std::vector<base::FilePath>* files) const;
|
||||||
|
|
||||||
// Fs.realpath(path).
|
// Fs.realpath(path).
|
||||||
bool Realpath(const base::FilePath& path, base::FilePath* realpath);
|
bool Realpath(const base::FilePath& path, base::FilePath* realpath) const;
|
||||||
|
|
||||||
// Copy the file into a temporary file, and return the new path.
|
// Copy the file into a temporary file, and return the new path.
|
||||||
// For unpacked file, this method will return its real path.
|
// For unpacked file, this method will return its real path.
|
||||||
@@ -65,16 +67,17 @@ class Archive {
|
|||||||
int GetFD() const;
|
int GetFD() const;
|
||||||
|
|
||||||
base::FilePath path() const { return path_; }
|
base::FilePath path() const { return path_; }
|
||||||
base::DictionaryValue* header() const { return header_.get(); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
base::FilePath path_;
|
bool initialized_;
|
||||||
|
const base::FilePath path_;
|
||||||
base::File file_;
|
base::File file_;
|
||||||
int fd_ = -1;
|
int fd_ = -1;
|
||||||
uint32_t header_size_ = 0;
|
uint32_t header_size_ = 0;
|
||||||
std::unique_ptr<base::DictionaryValue> header_;
|
std::unique_ptr<base::DictionaryValue> header_;
|
||||||
|
|
||||||
// Cached external temporary files.
|
// Cached external temporary files.
|
||||||
|
base::Lock external_files_lock_;
|
||||||
std::unordered_map<base::FilePath::StringType,
|
std::unordered_map<base::FilePath::StringType,
|
||||||
std::unique_ptr<ScopedTemporaryFile>>
|
std::unique_ptr<ScopedTemporaryFile>>
|
||||||
external_files_;
|
external_files_;
|
||||||
|
|||||||
@@ -6,11 +6,14 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "base/files/file_path.h"
|
#include "base/files/file_path.h"
|
||||||
#include "base/files/file_util.h"
|
#include "base/files/file_util.h"
|
||||||
#include "base/lazy_instance.h"
|
#include "base/lazy_instance.h"
|
||||||
|
#include "base/no_destructor.h"
|
||||||
#include "base/stl_util.h"
|
#include "base/stl_util.h"
|
||||||
|
#include "base/synchronization/lock.h"
|
||||||
#include "base/threading/thread_local.h"
|
#include "base/threading/thread_local.h"
|
||||||
#include "base/threading/thread_restrictions.h"
|
#include "base/threading/thread_restrictions.h"
|
||||||
#include "shell/common/asar/archive.h"
|
#include "shell/common/asar/archive.h"
|
||||||
@@ -19,30 +22,41 @@ namespace asar {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// The global instance of ArchiveMap, will be destroyed on exit.
|
|
||||||
typedef std::map<base::FilePath, std::shared_ptr<Archive>> ArchiveMap;
|
typedef std::map<base::FilePath, std::shared_ptr<Archive>> ArchiveMap;
|
||||||
base::LazyInstance<base::ThreadLocalPointer<ArchiveMap>>::Leaky
|
|
||||||
g_archive_map_tls = LAZY_INSTANCE_INITIALIZER;
|
|
||||||
|
|
||||||
const base::FilePath::CharType kAsarExtension[] = FILE_PATH_LITERAL(".asar");
|
const base::FilePath::CharType kAsarExtension[] = FILE_PATH_LITERAL(".asar");
|
||||||
|
|
||||||
std::map<base::FilePath, bool> g_is_directory_cache;
|
|
||||||
|
|
||||||
bool IsDirectoryCached(const base::FilePath& path) {
|
bool IsDirectoryCached(const base::FilePath& path) {
|
||||||
auto it = g_is_directory_cache.find(path);
|
static base::NoDestructor<std::map<base::FilePath, bool>>
|
||||||
if (it != g_is_directory_cache.end()) {
|
s_is_directory_cache;
|
||||||
|
static base::NoDestructor<base::Lock> lock;
|
||||||
|
|
||||||
|
base::AutoLock auto_lock(*lock);
|
||||||
|
auto& is_directory_cache = *s_is_directory_cache;
|
||||||
|
|
||||||
|
auto it = is_directory_cache.find(path);
|
||||||
|
if (it != is_directory_cache.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||||
return g_is_directory_cache[path] = base::DirectoryExists(path);
|
return is_directory_cache[path] = base::DirectoryExists(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
ArchiveMap& GetArchiveCache() {
|
||||||
|
static base::NoDestructor<ArchiveMap> s_archive_map;
|
||||||
|
return *s_archive_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
base::Lock& GetArchiveCacheLock() {
|
||||||
|
static base::NoDestructor<base::Lock> lock;
|
||||||
|
return *lock;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<Archive> GetOrCreateAsarArchive(const base::FilePath& path) {
|
std::shared_ptr<Archive> GetOrCreateAsarArchive(const base::FilePath& path) {
|
||||||
if (!g_archive_map_tls.Pointer()->Get())
|
base::AutoLock auto_lock(GetArchiveCacheLock());
|
||||||
g_archive_map_tls.Pointer()->Set(new ArchiveMap);
|
ArchiveMap& map = GetArchiveCache();
|
||||||
ArchiveMap& map = *g_archive_map_tls.Pointer()->Get();
|
|
||||||
|
|
||||||
// if we have it, return it
|
// if we have it, return it
|
||||||
const auto lower = map.lower_bound(path);
|
const auto lower = map.lower_bound(path);
|
||||||
@@ -61,8 +75,10 @@ std::shared_ptr<Archive> GetOrCreateAsarArchive(const base::FilePath& path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ClearArchives() {
|
void ClearArchives() {
|
||||||
if (g_archive_map_tls.Pointer()->Get())
|
base::AutoLock auto_lock(GetArchiveCacheLock());
|
||||||
delete g_archive_map_tls.Pointer()->Get();
|
ArchiveMap& map = GetArchiveCache();
|
||||||
|
|
||||||
|
map.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetAsarArchivePath(const base::FilePath& full_path,
|
bool GetAsarArchivePath(const base::FilePath& full_path,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace asar {
|
|||||||
|
|
||||||
class Archive;
|
class Archive;
|
||||||
|
|
||||||
// Gets or creates a new Archive from the path.
|
// Gets or creates and caches a new Archive from the path.
|
||||||
std::shared_ptr<Archive> GetOrCreateAsarArchive(const base::FilePath& path);
|
std::shared_ptr<Archive> GetOrCreateAsarArchive(const base::FilePath& path);
|
||||||
|
|
||||||
// Destroy cached Archive objects.
|
// Destroy cached Archive objects.
|
||||||
|
|||||||
@@ -187,10 +187,10 @@ bool Converter<blink::WebKeyboardEvent>::FromV8(v8::Isolate* isolate,
|
|||||||
if (!dict.Get("keyCode", &str))
|
if (!dict.Get("keyCode", &str))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool shifted = false;
|
base::Optional<char16_t> shifted_char;
|
||||||
ui::KeyboardCode keyCode = electron::KeyboardCodeFromStr(str, &shifted);
|
ui::KeyboardCode keyCode = electron::KeyboardCodeFromStr(str, &shifted_char);
|
||||||
out->windows_key_code = keyCode;
|
out->windows_key_code = keyCode;
|
||||||
if (shifted)
|
if (shifted_char)
|
||||||
out->SetModifiers(out->GetModifiers() |
|
out->SetModifiers(out->GetModifiers() |
|
||||||
blink::WebInputEvent::Modifiers::kShiftKey);
|
blink::WebInputEvent::Modifiers::kShiftKey);
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
#include "shell/common/gin_helper/function_template.h"
|
#include "shell/common/gin_helper/function_template.h"
|
||||||
#include "shell/common/gin_helper/locker.h"
|
#include "shell/common/gin_helper/locker.h"
|
||||||
#include "shell/common/gin_helper/microtasks_scope.h"
|
#include "shell/common/gin_helper/microtasks_scope.h"
|
||||||
// Implements safe convertions between JS functions and base::RepeatingCallback.
|
// Implements safe conversions between JS functions and base::RepeatingCallback.
|
||||||
|
|
||||||
namespace gin_helper {
|
namespace gin_helper {
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ struct V8FunctionInvoker<ReturnType(ArgTypes...)> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper to pass a C++ funtion to JavaScript.
|
// Helper to pass a C++ function to JavaScript.
|
||||||
using Translater = base::RepeatingCallback<void(gin::Arguments* args)>;
|
using Translater = base::RepeatingCallback<void(gin::Arguments* args)>;
|
||||||
v8::Local<v8::Value> CreateFunctionFromTranslater(v8::Isolate* isolate,
|
v8::Local<v8::Value> CreateFunctionFromTranslater(v8::Isolate* isolate,
|
||||||
const Translater& translater,
|
const Translater& translater,
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ bool GetNextArgument(gin::Arguments* args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Support base::Optional as output, which would be empty and do not throw error
|
// Support base::Optional as output, which would be empty and do not throw error
|
||||||
// when convertion to T fails.
|
// when conversion to T fails.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool GetNextArgument(gin::Arguments* args,
|
bool GetNextArgument(gin::Arguments* args,
|
||||||
int create_flags,
|
int create_flags,
|
||||||
|
|||||||
@@ -15,8 +15,9 @@ namespace electron {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Return key code represented by |str|.
|
// Return key code represented by |str|.
|
||||||
ui::KeyboardCode KeyboardCodeFromKeyIdentifier(const std::string& s,
|
ui::KeyboardCode KeyboardCodeFromKeyIdentifier(
|
||||||
bool* shifted) {
|
const std::string& s,
|
||||||
|
base::Optional<char16_t>* shifted_char) {
|
||||||
std::string str = base::ToLowerASCII(s);
|
std::string str = base::ToLowerASCII(s);
|
||||||
if (str == "ctrl" || str == "control") {
|
if (str == "ctrl" || str == "control") {
|
||||||
return ui::VKEY_CONTROL;
|
return ui::VKEY_CONTROL;
|
||||||
@@ -36,7 +37,7 @@ ui::KeyboardCode KeyboardCodeFromKeyIdentifier(const std::string& s,
|
|||||||
} else if (str == "altgr") {
|
} else if (str == "altgr") {
|
||||||
return ui::VKEY_ALTGR;
|
return ui::VKEY_ALTGR;
|
||||||
} else if (str == "plus") {
|
} else if (str == "plus") {
|
||||||
*shifted = true;
|
shifted_char->emplace('+');
|
||||||
return ui::VKEY_OEM_PLUS;
|
return ui::VKEY_OEM_PLUS;
|
||||||
} else if (str == "capslock") {
|
} else if (str == "capslock") {
|
||||||
return ui::VKEY_CAPITAL;
|
return ui::VKEY_CAPITAL;
|
||||||
@@ -319,11 +320,17 @@ ui::KeyboardCode KeyboardCodeFromCharCode(char16_t c, bool* shifted) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui::KeyboardCode KeyboardCodeFromStr(const std::string& str, bool* shifted) {
|
ui::KeyboardCode KeyboardCodeFromStr(const std::string& str,
|
||||||
if (str.size() == 1)
|
base::Optional<char16_t>* shifted_char) {
|
||||||
return KeyboardCodeFromCharCode(str[0], shifted);
|
if (str.size() == 1) {
|
||||||
else
|
bool shifted = false;
|
||||||
return KeyboardCodeFromKeyIdentifier(str, shifted);
|
auto ret = KeyboardCodeFromCharCode(str[0], &shifted);
|
||||||
|
if (shifted)
|
||||||
|
shifted_char->emplace(str[0]);
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
return KeyboardCodeFromKeyIdentifier(str, shifted_char);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace electron
|
} // namespace electron
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "base/optional.h"
|
||||||
#include "ui/events/keycodes/keyboard_codes.h"
|
#include "ui/events/keycodes/keyboard_codes.h"
|
||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
@@ -15,9 +16,11 @@ namespace electron {
|
|||||||
// pressed.
|
// pressed.
|
||||||
ui::KeyboardCode KeyboardCodeFromCharCode(char16_t c, bool* shifted);
|
ui::KeyboardCode KeyboardCodeFromCharCode(char16_t c, bool* shifted);
|
||||||
|
|
||||||
// Return key code of the |str|, and also determine whether the SHIFT key is
|
// Return key code of the |str|, if the original key is a shifted character,
|
||||||
|
// for example + and /, set it in |shifted_char|.
|
||||||
// pressed.
|
// pressed.
|
||||||
ui::KeyboardCode KeyboardCodeFromStr(const std::string& str, bool* shifted);
|
ui::KeyboardCode KeyboardCodeFromStr(const std::string& str,
|
||||||
|
base::Optional<char16_t>* shifted_char);
|
||||||
|
|
||||||
} // namespace electron
|
} // namespace electron
|
||||||
|
|
||||||
|
|||||||
@@ -131,6 +131,10 @@ void stop_and_close_uv_loop(uv_loop_t* loop) {
|
|||||||
bool g_is_initialized = false;
|
bool g_is_initialized = false;
|
||||||
|
|
||||||
bool IsPackagedApp() {
|
bool IsPackagedApp() {
|
||||||
|
auto env = base::Environment::Create();
|
||||||
|
if (env->HasVar("ELECTRON_FORCE_IS_PACKAGED"))
|
||||||
|
return true;
|
||||||
|
|
||||||
base::FilePath exe_path;
|
base::FilePath exe_path;
|
||||||
base::PathService::Get(base::FILE_EXE, &exe_path);
|
base::PathService::Get(base::FILE_EXE, &exe_path);
|
||||||
base::FilePath::StringType base_name =
|
base::FilePath::StringType base_name =
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class SpellCheckClient : public blink::WebSpellCheckPanelHostClient,
|
|||||||
// Output variable contraction_words will contain individual
|
// Output variable contraction_words will contain individual
|
||||||
// words in the contraction.
|
// words in the contraction.
|
||||||
bool IsContraction(const SpellCheckScope& scope,
|
bool IsContraction(const SpellCheckScope& scope,
|
||||||
const std::u16string& word,
|
const std::u16string& contraction,
|
||||||
std::vector<std::u16string>* contraction_words);
|
std::vector<std::u16string>* contraction_words);
|
||||||
|
|
||||||
// Callback for the JS API which returns the list of misspelled words.
|
// Callback for the JS API which returns the list of misspelled words.
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "content/public/renderer/render_frame.h"
|
#include "content/public/renderer/render_frame.h"
|
||||||
#include "electron/buildflags/buildflags.h"
|
#include "electron/buildflags/buildflags.h"
|
||||||
#include "shell/common/api/electron_bindings.h"
|
#include "shell/common/api/electron_bindings.h"
|
||||||
#include "shell/common/asar/asar_util.h"
|
|
||||||
#include "shell/common/gin_helper/dictionary.h"
|
#include "shell/common/gin_helper/dictionary.h"
|
||||||
#include "shell/common/gin_helper/event_emitter_caller.h"
|
#include "shell/common/gin_helper/event_emitter_caller.h"
|
||||||
#include "shell/common/node_bindings.h"
|
#include "shell/common/node_bindings.h"
|
||||||
@@ -39,9 +38,7 @@ ElectronRendererClient::ElectronRendererClient()
|
|||||||
NodeBindings::Create(NodeBindings::BrowserEnvironment::kRenderer)),
|
NodeBindings::Create(NodeBindings::BrowserEnvironment::kRenderer)),
|
||||||
electron_bindings_(new ElectronBindings(node_bindings_->uv_loop())) {}
|
electron_bindings_(new ElectronBindings(node_bindings_->uv_loop())) {}
|
||||||
|
|
||||||
ElectronRendererClient::~ElectronRendererClient() {
|
ElectronRendererClient::~ElectronRendererClient() = default;
|
||||||
asar::ClearArchives();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ElectronRendererClient::RenderFrameCreated(
|
void ElectronRendererClient::RenderFrameCreated(
|
||||||
content::RenderFrame* render_frame) {
|
content::RenderFrame* render_frame) {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "electron/buildflags/buildflags.h"
|
#include "electron/buildflags/buildflags.h"
|
||||||
#include "media/blink/multibuffer_data_source.h"
|
#include "media/blink/multibuffer_data_source.h"
|
||||||
#include "printing/buildflags/buildflags.h"
|
#include "printing/buildflags/buildflags.h"
|
||||||
|
#include "shell/browser/api/electron_api_protocol.h"
|
||||||
#include "shell/common/api/electron_api_native_image.h"
|
#include "shell/common/api/electron_api_native_image.h"
|
||||||
#include "shell/common/color_util.h"
|
#include "shell/common/color_util.h"
|
||||||
#include "shell/common/gin_helper/dictionary.h"
|
#include "shell/common/gin_helper/dictionary.h"
|
||||||
@@ -111,6 +112,11 @@ RendererClientBase* g_renderer_client_base = nullptr;
|
|||||||
|
|
||||||
RendererClientBase::RendererClientBase() {
|
RendererClientBase::RendererClientBase() {
|
||||||
auto* command_line = base::CommandLine::ForCurrentProcess();
|
auto* command_line = base::CommandLine::ForCurrentProcess();
|
||||||
|
// Parse --service-worker-schemes=scheme1,scheme2
|
||||||
|
std::vector<std::string> service_worker_schemes_list =
|
||||||
|
ParseSchemesCLISwitch(command_line, switches::kServiceWorkerSchemes);
|
||||||
|
for (const std::string& scheme : service_worker_schemes_list)
|
||||||
|
electron::api::AddServiceWorkerScheme(scheme);
|
||||||
// Parse --standard-schemes=scheme1,scheme2
|
// Parse --standard-schemes=scheme1,scheme2
|
||||||
std::vector<std::string> standard_schemes_list =
|
std::vector<std::string> standard_schemes_list =
|
||||||
ParseSchemesCLISwitch(command_line, switches::kStandardSchemes);
|
ParseSchemesCLISwitch(command_line, switches::kStandardSchemes);
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class RendererClientBase : public content::ContentRendererClient
|
|||||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||||
// service_manager::LocalInterfaceProvider implementation.
|
// service_manager::LocalInterfaceProvider implementation.
|
||||||
void GetInterface(const std::string& name,
|
void GetInterface(const std::string& name,
|
||||||
mojo::ScopedMessagePipeHandle request_handle) override;
|
mojo::ScopedMessagePipeHandle interface_pipe) override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
virtual void DidCreateScriptContext(v8::Handle<v8::Context> context,
|
virtual void DidCreateScriptContext(v8::Handle<v8::Context> context,
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#include "base/lazy_instance.h"
|
#include "base/lazy_instance.h"
|
||||||
#include "base/threading/thread_local.h"
|
#include "base/threading/thread_local.h"
|
||||||
#include "shell/common/api/electron_bindings.h"
|
#include "shell/common/api/electron_bindings.h"
|
||||||
#include "shell/common/asar/asar_util.h"
|
|
||||||
#include "shell/common/gin_helper/event_emitter_caller.h"
|
#include "shell/common/gin_helper/event_emitter_caller.h"
|
||||||
#include "shell/common/node_bindings.h"
|
#include "shell/common/node_bindings.h"
|
||||||
#include "shell/common/node_includes.h"
|
#include "shell/common/node_includes.h"
|
||||||
@@ -39,7 +38,6 @@ WebWorkerObserver::~WebWorkerObserver() {
|
|||||||
lazy_tls.Pointer()->Set(nullptr);
|
lazy_tls.Pointer()->Set(nullptr);
|
||||||
node::FreeEnvironment(node_bindings_->uv_env());
|
node::FreeEnvironment(node_bindings_->uv_env());
|
||||||
node::FreeIsolateData(node_bindings_->isolate_data());
|
node::FreeIsolateData(node_bindings_->isolate_data());
|
||||||
asar::ClearArchives();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebWorkerObserver::WorkerScriptReadyForEvaluation(
|
void WebWorkerObserver::WorkerScriptReadyForEvaluation(
|
||||||
|
|||||||
@@ -462,9 +462,9 @@ describe('MenuItems', () => {
|
|||||||
{ label: 'text', accelerator: 'Alt+A' }
|
{ label: 'text', accelerator: 'Alt+A' }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(menu.getAcceleratorTextAt(0)).to.equal(isDarwin() ? '⌘A' : 'Ctrl+A');
|
expect(menu.getAcceleratorTextAt(0)).to.equal(isDarwin() ? 'Command+A' : 'Ctrl+A');
|
||||||
expect(menu.getAcceleratorTextAt(1)).to.equal(isDarwin() ? '⇧A' : 'Shift+A');
|
expect(menu.getAcceleratorTextAt(1)).to.equal('Shift+A');
|
||||||
expect(menu.getAcceleratorTextAt(2)).to.equal(isDarwin() ? '⌥A' : 'Alt+A');
|
expect(menu.getAcceleratorTextAt(2)).to.equal('Alt+A');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display modifiers correctly for special keys', () => {
|
it('should display modifiers correctly for special keys', () => {
|
||||||
@@ -474,9 +474,9 @@ describe('MenuItems', () => {
|
|||||||
{ label: 'text', accelerator: 'Alt+Tab' }
|
{ label: 'text', accelerator: 'Alt+Tab' }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(menu.getAcceleratorTextAt(0)).to.equal(isDarwin() ? '⌘⇥' : 'Ctrl+Tab');
|
expect(menu.getAcceleratorTextAt(0)).to.equal(isDarwin() ? 'Command+Tab' : 'Ctrl+Tab');
|
||||||
expect(menu.getAcceleratorTextAt(1)).to.equal(isDarwin() ? '⇧⇥' : 'Shift+Tab');
|
expect(menu.getAcceleratorTextAt(1)).to.equal('Shift+Tab');
|
||||||
expect(menu.getAcceleratorTextAt(2)).to.equal(isDarwin() ? '⌥⇥' : 'Alt+Tab');
|
expect(menu.getAcceleratorTextAt(2)).to.equal('Alt+Tab');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not display modifiers twice', () => {
|
it('should not display modifiers twice', () => {
|
||||||
@@ -485,18 +485,26 @@ describe('MenuItems', () => {
|
|||||||
{ label: 'text', accelerator: 'Shift+Shift+Tab' }
|
{ label: 'text', accelerator: 'Shift+Shift+Tab' }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(menu.getAcceleratorTextAt(0)).to.equal(isDarwin() ? '⇧A' : 'Shift+A');
|
expect(menu.getAcceleratorTextAt(0)).to.equal('Shift+A');
|
||||||
expect(menu.getAcceleratorTextAt(1)).to.equal(isDarwin() ? '⇧⇥' : 'Shift+Tab');
|
expect(menu.getAcceleratorTextAt(1)).to.equal('Shift+Tab');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display correctly for edge cases', () => {
|
it('should display correctly for shifted keys', () => {
|
||||||
const menu = Menu.buildFromTemplate([
|
const menu = Menu.buildFromTemplate([
|
||||||
{ label: 'text', accelerator: 'Control+Shift+=' },
|
{ label: 'text', accelerator: 'Control+Shift+=' },
|
||||||
{ label: 'text', accelerator: 'Control+Plus' }
|
{ label: 'text', accelerator: 'Control+Plus' },
|
||||||
|
{ label: 'text', accelerator: 'Control+Shift+3' },
|
||||||
|
{ label: 'text', accelerator: 'Control+#' },
|
||||||
|
{ label: 'text', accelerator: 'Control+Shift+/' },
|
||||||
|
{ label: 'text', accelerator: 'Control+?' }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(menu.getAcceleratorTextAt(0)).to.equal(isDarwin() ? '⌃⇧=' : 'Ctrl+Shift+=');
|
expect(menu.getAcceleratorTextAt(0)).to.equal('Ctrl+Shift+=');
|
||||||
expect(menu.getAcceleratorTextAt(1)).to.equal(isDarwin() ? '⌃⇧=' : 'Ctrl+Shift+=');
|
expect(menu.getAcceleratorTextAt(1)).to.equal('Ctrl++');
|
||||||
|
expect(menu.getAcceleratorTextAt(2)).to.equal('Ctrl+Shift+3');
|
||||||
|
expect(menu.getAcceleratorTextAt(3)).to.equal('Ctrl+#');
|
||||||
|
expect(menu.getAcceleratorTextAt(4)).to.equal('Ctrl+Shift+/');
|
||||||
|
expect(menu.getAcceleratorTextAt(5)).to.equal('Ctrl+?');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -586,6 +586,43 @@ describe('chromium features', () => {
|
|||||||
w.loadFile(path.join(fixturesPath, 'pages', 'service-worker', 'index.html'));
|
w.loadFile(path.join(fixturesPath, 'pages', 'service-worker', 'index.html'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should register for custom scheme', (done) => {
|
||||||
|
const customSession = session.fromPartition('custom-scheme');
|
||||||
|
const { serviceWorkerScheme } = global as any;
|
||||||
|
customSession.protocol.registerFileProtocol(serviceWorkerScheme, (request, callback) => {
|
||||||
|
let file = url.parse(request.url).pathname!;
|
||||||
|
if (file[0] === '/' && process.platform === 'win32') file = file.slice(1);
|
||||||
|
|
||||||
|
callback({ path: path.normalize(file) } as any);
|
||||||
|
});
|
||||||
|
|
||||||
|
const w = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true,
|
||||||
|
session: customSession,
|
||||||
|
contextIsolation: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
w.webContents.on('ipc-message', (event, channel, message) => {
|
||||||
|
if (channel === 'reload') {
|
||||||
|
w.webContents.reload();
|
||||||
|
} else if (channel === 'error') {
|
||||||
|
done(`unexpected error : ${message}`);
|
||||||
|
} else if (channel === 'response') {
|
||||||
|
expect(message).to.equal('Hello from serviceWorker!');
|
||||||
|
customSession.clearStorageData({
|
||||||
|
storages: ['serviceworkers']
|
||||||
|
}).then(() => {
|
||||||
|
customSession.protocol.uninterceptProtocol(serviceWorkerScheme);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
w.webContents.on('crashed', () => done(new Error('WebContents crashed.')));
|
||||||
|
w.loadFile(path.join(fixturesPath, 'pages', 'service-worker', 'custom-scheme-index.html'));
|
||||||
|
});
|
||||||
|
|
||||||
it('should not crash when nodeIntegration is enabled', (done) => {
|
it('should not crash when nodeIntegration is enabled', (done) => {
|
||||||
const w = new BrowserWindow({
|
const w = new BrowserWindow({
|
||||||
show: false,
|
show: false,
|
||||||
|
|||||||
121
spec-main/fixtures/version-bumper/fixture_support.md
Normal file
121
spec-main/fixtures/version-bumper/fixture_support.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
# Electron Support
|
||||||
|
|
||||||
|
## Finding Support
|
||||||
|
|
||||||
|
If you have a security concern,
|
||||||
|
please see the [security document](https://github.com/electron/electron/tree/master/SECURITY.md).
|
||||||
|
|
||||||
|
If you're looking for programming help,
|
||||||
|
for answers to questions,
|
||||||
|
or to join in discussion with other developers who use Electron,
|
||||||
|
you can interact with the community in these locations:
|
||||||
|
|
||||||
|
* [`Electron's Discord`](https://discord.com/invite/electron) has channels for:
|
||||||
|
* Getting help
|
||||||
|
* Ecosystem apps like [Electron Forge](https://github.com/electron-userland/electron-forge) and [Electron Fiddle](https://github.com/electron/fiddle)
|
||||||
|
* Sharing ideas with other Electron app developers
|
||||||
|
* And more!
|
||||||
|
* [`electron`](https://discuss.atom.io/c/electron) category on the Atom forums
|
||||||
|
* `#atom-shell` channel on Freenode
|
||||||
|
* `#electron` channel on [Atom's Slack](https://discuss.atom.io/t/join-us-on-slack/16638?source_topic_id=25406)
|
||||||
|
* [`electron-ru`](https://telegram.me/electron_ru) *(Russian)*
|
||||||
|
* [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)*
|
||||||
|
* [`electron-kr`](https://electron-kr.github.io/electron-kr) *(Korean)*
|
||||||
|
* [`electron-jp`](https://electron-jp.slack.com) *(Japanese)*
|
||||||
|
* [`electron-tr`](https://electron-tr.herokuapp.com) *(Turkish)*
|
||||||
|
* [`electron-id`](https://electron-id.slack.com) *(Indonesia)*
|
||||||
|
* [`electron-pl`](https://electronpl.github.io) *(Poland)*
|
||||||
|
|
||||||
|
If you'd like to contribute to Electron,
|
||||||
|
see the [contributing document](https://github.com/electron/electron/blob/master/CONTRIBUTING.md).
|
||||||
|
|
||||||
|
If you've found a bug in a [supported version](#supported-versions) of Electron,
|
||||||
|
please report it with the [issue tracker](../development/issues.md).
|
||||||
|
|
||||||
|
[awesome-electron](https://github.com/sindresorhus/awesome-electron)
|
||||||
|
is a community-maintained list of useful example apps,
|
||||||
|
tools and resources.
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
The latest three *stable* major versions are supported by the Electron team.
|
||||||
|
For example, if the latest release is 6.1.x, then the 5.0.x as well
|
||||||
|
as the 4.2.x series are supported. We only support the latest minor release
|
||||||
|
for each stable release series. This means that in the case of a security fix
|
||||||
|
6.1.x will receive the fix, but we will not release a new version of 6.0.x.
|
||||||
|
|
||||||
|
The latest stable release unilaterally receives all fixes from `master`,
|
||||||
|
and the version prior to that receives the vast majority of those fixes
|
||||||
|
as time and bandwidth warrants. The oldest supported release line will receive
|
||||||
|
only security fixes directly.
|
||||||
|
|
||||||
|
All supported release lines will accept external pull requests to backport
|
||||||
|
fixes previously merged to `master`, though this may be on a case-by-case
|
||||||
|
basis for some older supported lines. All contested decisions around release
|
||||||
|
line backports will be resolved by the [Releases Working Group](https://github.com/electron/governance/tree/master/wg-releases) as an agenda item at their weekly meeting the week the backport PR is raised.
|
||||||
|
|
||||||
|
When an API is changed or removed in a way that breaks existing functionality, the
|
||||||
|
previous functionality will be supported for a minimum of two major versions when
|
||||||
|
possible before being removed. For example, if a function takes three arguments,
|
||||||
|
and that number is reduced to two in major version 10, the three-argument version would
|
||||||
|
continue to work until, at minimum, major version 12. Past the minimum two-version
|
||||||
|
threshold, we will attempt to support backwards compatibility beyond two versions
|
||||||
|
until the maintainers feel the maintenance burden is too high to continue doing so.
|
||||||
|
|
||||||
|
### Currently supported versions
|
||||||
|
|
||||||
|
* 3.x.y
|
||||||
|
* 2.x.y
|
||||||
|
* 1.x.y
|
||||||
|
|
||||||
|
### End-of-life
|
||||||
|
|
||||||
|
When a release branch reaches the end of its support cycle, the series
|
||||||
|
will be deprecated in NPM and a final end-of-support release will be
|
||||||
|
made. This release will add a warning to inform that an unsupported
|
||||||
|
version of Electron is in use.
|
||||||
|
|
||||||
|
These steps are to help app developers learn when a branch they're
|
||||||
|
using becomes unsupported, but without being excessively intrusive
|
||||||
|
to end users.
|
||||||
|
|
||||||
|
If an application has exceptional circumstances and needs to stay
|
||||||
|
on an unsupported series of Electron, developers can silence the
|
||||||
|
end-of-support warning by omitting the final release from the app's
|
||||||
|
`package.json` `devDependencies`. For example, since the 1-6-x series
|
||||||
|
ended with an end-of-support 1.6.18 release, developers could choose
|
||||||
|
to stay in the 1-6-x series without warnings with `devDependency` of
|
||||||
|
`"electron": 1.6.0 - 1.6.17`.
|
||||||
|
|
||||||
|
## Supported Platforms
|
||||||
|
|
||||||
|
Following platforms are supported by Electron:
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
Only 64bit binaries are provided for macOS, and the minimum macOS version
|
||||||
|
supported is macOS 10.11 (El Capitan).
|
||||||
|
|
||||||
|
Native support for Apple Silicon (`arm64`) devices was added in Electron 11.0.0.
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
Windows 7 and later are supported, older operating systems are not supported
|
||||||
|
(and do not work).
|
||||||
|
|
||||||
|
Both `ia32` (`x86`) and `x64` (`amd64`) binaries are provided for Windows.
|
||||||
|
[Native support for Windows on Arm (`arm64`) devices was added in Electron 6.0.8.](windows-arm.md).
|
||||||
|
Running apps packaged with previous versions is possible using the ia32 binary.
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
The prebuilt binaries of Electron are built on Ubuntu 18.04.
|
||||||
|
|
||||||
|
Whether the prebuilt binary can run on a distribution depends on whether the
|
||||||
|
distribution includes the libraries that Electron is linked to on the building
|
||||||
|
platform, so only Ubuntu 18.04 is guaranteed to work, but following platforms
|
||||||
|
are also verified to be able to run the prebuilt binaries of Electron:
|
||||||
|
|
||||||
|
* Ubuntu 14.04 and newer
|
||||||
|
* Fedora 24 and newer
|
||||||
|
* Debian 8 and newer
|
||||||
@@ -132,6 +132,29 @@ describe('node feature', () => {
|
|||||||
child.stderr.on('data', listener);
|
child.stderr.on('data', listener);
|
||||||
child.stdout.on('data', listener);
|
child.stdout.on('data', listener);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does allow --require in non-packaged apps', async () => {
|
||||||
|
const appPath = path.join(fixtures, 'module', 'noop.js');
|
||||||
|
const env = Object.assign({}, process.env, {
|
||||||
|
NODE_OPTIONS: `--require=${path.join(fixtures, 'module', 'fail.js')}`
|
||||||
|
});
|
||||||
|
// App should exit with code 1.
|
||||||
|
const child = childProcess.spawn(process.execPath, [appPath], { env });
|
||||||
|
const [code] = await emittedOnce(child, 'exit');
|
||||||
|
expect(code).to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not allow --require in packaged apps', async () => {
|
||||||
|
const appPath = path.join(fixtures, 'module', 'noop.js');
|
||||||
|
const env = Object.assign({}, process.env, {
|
||||||
|
ELECTRON_FORCE_IS_PACKAGED: 'true',
|
||||||
|
NODE_OPTIONS: `--require=${path.join(fixtures, 'module', 'fail.js')}`
|
||||||
|
});
|
||||||
|
// App should exit with code 0.
|
||||||
|
const child = childProcess.spawn(process.execPath, [appPath], { env });
|
||||||
|
const [code] = await emittedOnce(child, 'exit');
|
||||||
|
expect(code).to.equal(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
ifdescribe(features.isRunAsNodeEnabled())('Node.js cli flags', () => {
|
ifdescribe(features.isRunAsNodeEnabled())('Node.js cli flags', () => {
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { nextVersion } from '../script/release/version-bumper';
|
import { nextVersion, shouldUpdateSupported, updateSupported } from '../script/release/version-bumper';
|
||||||
import * as utils from '../script/release/version-utils';
|
import * as utils from '../script/release/version-utils';
|
||||||
import { ifdescribe } from './spec-helpers';
|
import { ifdescribe } from './spec-helpers';
|
||||||
|
const { promises: fs } = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const fixtureDir = path.resolve(__dirname, 'fixtures', 'version-bumper', 'fixture_support.md');
|
||||||
|
const readFile = fs.readFile;
|
||||||
|
const writeFile = fs.writeFile;
|
||||||
|
|
||||||
describe('version-bumper', () => {
|
describe('version-bumper', () => {
|
||||||
describe('makeVersion', () => {
|
describe('makeVersion', () => {
|
||||||
@@ -41,6 +47,94 @@ describe('version-bumper', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('updateSupported', () => {
|
||||||
|
let restore: any;
|
||||||
|
before(async () => {
|
||||||
|
restore = await readFile(fixtureDir, 'utf8');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await writeFile(fixtureDir, restore, 'utf8');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('updates correctly when a new stable version is promoted from beta', async () => {
|
||||||
|
const version = '4.0.0';
|
||||||
|
const currentVersion = '4.0.0-beta.29';
|
||||||
|
if (shouldUpdateSupported('stable', currentVersion, version)) {
|
||||||
|
await updateSupported(version, fixtureDir);
|
||||||
|
}
|
||||||
|
const contents = await readFile(fixtureDir, 'utf8');
|
||||||
|
|
||||||
|
expect(contents).to.contain('4.x.y\n* 3.x.y\n* 2.x.y');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update when a new stable patch version is promoted', async () => {
|
||||||
|
const version = '3.0.1';
|
||||||
|
const currentVersion = '3.0.0';
|
||||||
|
if (shouldUpdateSupported('stable', currentVersion, version)) {
|
||||||
|
await updateSupported(version, fixtureDir);
|
||||||
|
}
|
||||||
|
const contents = await readFile(fixtureDir, 'utf8');
|
||||||
|
|
||||||
|
expect(contents).to.contain('3.x.y\n* 2.x.y\n* 1.x.y');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update when a new stable minor version is promoted', async () => {
|
||||||
|
const version = '3.1.0';
|
||||||
|
const currentVersion = '3.0.0';
|
||||||
|
if (shouldUpdateSupported('minor', currentVersion, version)) {
|
||||||
|
await updateSupported(version, fixtureDir);
|
||||||
|
}
|
||||||
|
const contents = await readFile(fixtureDir, 'utf8');
|
||||||
|
|
||||||
|
expect(contents).to.contain('3.x.y\n* 2.x.y\n* 1.x.y');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update when a new beta.1 version is promoted', async () => {
|
||||||
|
const version = '5.0.0-beta.1';
|
||||||
|
const currentVersion = '4.0.0-beta.29';
|
||||||
|
if (shouldUpdateSupported('beta', currentVersion, version)) {
|
||||||
|
await updateSupported(version, fixtureDir);
|
||||||
|
}
|
||||||
|
const contents = await readFile(fixtureDir, 'utf8');
|
||||||
|
|
||||||
|
expect(contents).to.contain('3.x.y\n* 2.x.y\n* 1.x.y');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update when a new beta.12 version is promoted', async () => {
|
||||||
|
const version = '4.0.0-beta.12';
|
||||||
|
const currentVersion = '4.0.0-beta.11';
|
||||||
|
if (shouldUpdateSupported('beta', currentVersion, version)) {
|
||||||
|
await updateSupported(version, fixtureDir);
|
||||||
|
}
|
||||||
|
const contents = await readFile(fixtureDir, 'utf8');
|
||||||
|
|
||||||
|
expect(contents).to.contain('3.x.y\n* 2.x.y\n* 1.x.y');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update when a new major nightly version is promoted', async () => {
|
||||||
|
const version = '4.0.0-nightly.19950901';
|
||||||
|
const currentVersion = '3.0.0-nightly.19950828';
|
||||||
|
if (shouldUpdateSupported('nightly', currentVersion, version)) {
|
||||||
|
await updateSupported(version, fixtureDir);
|
||||||
|
}
|
||||||
|
const contents = await readFile(fixtureDir, 'utf8');
|
||||||
|
|
||||||
|
expect(contents).to.contain('4.x.y\n* 3.x.y\n* 2.x.y');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update when a new nightly version is promoted', async () => {
|
||||||
|
const version = '3.0.0-nightly.19950901';
|
||||||
|
const currentVersion = '3.0.0-nightly.19950828';
|
||||||
|
if (shouldUpdateSupported('nightly', currentVersion, version)) {
|
||||||
|
await updateSupported(version, fixtureDir);
|
||||||
|
}
|
||||||
|
const contents = await readFile(fixtureDir, 'utf8');
|
||||||
|
|
||||||
|
expect(contents).to.contain('3.x.y\n* 2.x.y\n* 1.x.y');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// On macOS Circle CI we don't have a real git environment due to running
|
// On macOS Circle CI we don't have a real git environment due to running
|
||||||
// gclient sync on a linux machine. These tests therefore don't run as expected.
|
// gclient sync on a linux machine. These tests therefore don't run as expected.
|
||||||
ifdescribe(!(process.platform === 'linux' && process.arch === 'arm') && process.platform !== 'darwin')('nextVersion', () => {
|
ifdescribe(!(process.platform === 'linux' && process.arch === 'arm') && process.platform !== 'darwin')('nextVersion', () => {
|
||||||
|
|||||||
1
spec/fixtures/module/fail.js
vendored
Normal file
1
spec/fixtures/module/fail.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
process.exit(1);
|
||||||
21
spec/fixtures/pages/service-worker/custom-scheme-index.html
vendored
Normal file
21
spec/fixtures/pages/service-worker/custom-scheme-index.html
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<script>
|
||||||
|
const ipcRenderer = require('electron').ipcRenderer;
|
||||||
|
navigator.serviceWorker.register('service-worker.js', {scope: './'}).then(() => {
|
||||||
|
if (navigator.serviceWorker.controller) {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', 'sw://dummy/echo');
|
||||||
|
xhr.setRequestHeader('X-Mock-Response', 'yes');
|
||||||
|
xhr.addEventListener('error', error => {
|
||||||
|
ipcRenderer.send('error', `${error.message}\n${error.stack}`);
|
||||||
|
})
|
||||||
|
xhr.addEventListener('load', () => {
|
||||||
|
ipcRenderer.send('response', xhr.responseText);
|
||||||
|
});
|
||||||
|
xhr.send();
|
||||||
|
} else {
|
||||||
|
ipcRenderer.send('reload');
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
ipcRenderer.send('error', `${error.message}\n${error.stack}`);
|
||||||
|
})
|
||||||
|
</script>
|
||||||
5
typings/internal-electron.d.ts
vendored
5
typings/internal-electron.d.ts
vendored
@@ -56,12 +56,7 @@ declare namespace Electron {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface WebContents {
|
interface WebContents {
|
||||||
_getURL(): string;
|
|
||||||
_loadURL(url: string, options: ElectronInternal.LoadURLOptions): void;
|
_loadURL(url: string, options: ElectronInternal.LoadURLOptions): void;
|
||||||
_stop(): void;
|
|
||||||
_goBack(): void;
|
|
||||||
_goForward(): void;
|
|
||||||
_goToOffset(offset: number): void;
|
|
||||||
getOwnerBrowserWindow(): Electron.BrowserWindow;
|
getOwnerBrowserWindow(): Electron.BrowserWindow;
|
||||||
getWebPreferences(): Electron.WebPreferences;
|
getWebPreferences(): Electron.WebPreferences;
|
||||||
getLastWebPreferences(): Electron.WebPreferences;
|
getLastWebPreferences(): Electron.WebPreferences;
|
||||||
|
|||||||
Reference in New Issue
Block a user