Compare commits

...

52 Commits

Author SHA1 Message Date
Sudowoodo Release Bot
d35270ebb1 Bump v17.1.1 2022-03-07 11:01:48 -08:00
Shelley Vohr
8ee96a13e7 test: disable consistently flaky WOA JS test (#33144) 2022-03-07 09:18:00 -05:00
trop[bot]
5691f1c67e docs: Updated list numbering (#33146)
* docs: Updated list numbering

The steps to package and distribute an application using electron had incorrect numbering

* Indented text within ordered list sections

* Removed single space

* Fixed indentation

Co-authored-by: Alvin Philips <alvinphilips257@gmail.com>
2022-03-03 16:54:45 -08:00
trop[bot]
a582a4376f docs: remove platform notices from tutorial titles (#33137)
* docs: remove platform notices from tutorial titles

* Update docs/tutorial/launch-app-from-url-in-another-app.md

Co-authored-by: Mark Lee <malept@users.noreply.github.com>

Co-authored-by: Erick Zhao <erick@hotmail.ca>
Co-authored-by: Mark Lee <malept@users.noreply.github.com>
2022-03-03 15:37:59 -08:00
trop[bot]
2ea5521940 fix: macOS tray icon alternate images (#33105)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-03-03 14:52:45 -08:00
trop[bot]
d02dd1b894 fix: disable partition alloc on mac (#33116)
Co-authored-by: VerteDinde <vertedinde@electronjs.org>
2022-03-01 17:10:57 -08:00
electron-roller[bot]
f0815caf98 chore: bump chromium in DEPS to 98.0.4758.109 (#33085)
Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2022-02-28 14:11:40 -08:00
trop[bot]
795a79e06e Update main.js (#33079)
Co-authored-by: Ruslan <62350279+2BC-Wasabi@users.noreply.github.com>
2022-02-28 11:47:04 -08:00
trop[bot]
1d57a87c64 fix: DCHECK when calling app.exit() (#33057)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-02-28 11:37:00 -08:00
trop[bot]
931db4a747 fix: tray garbage collection (#33076)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-02-25 14:18:22 +01:00
trop[bot]
bbe5808090 fix: broken OSR transparent option (#33052)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-02-24 12:09:21 +01:00
Sudowoodo Release Bot
08efa9a9b9 Bump v17.1.0 2022-02-23 10:06:23 -08:00
Michaela Laurencin
2c282517de feat: add WCO height option (#31222) (#32939)
* feat: add WCO height option

* add docs and mac functionality

* add macOS functionality and height lowerbound

* Update docs/api/browser-window.md

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

* update macOS functionality

* add chromium related notes

* add test and fix pixel under button bug and fix typo

* revert changes to docs/api/frameless-window.md

* modify `useCustomHeight` calls

* update `useCustomHeight` and `getCurrentMargin`

* modify margin calculation

* fix minimum custom height on macOS

* Update window_buttons_proxy.mm

* fix specified traffic light positions

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-02-22 14:30:55 -05:00
trop[bot]
1a346eaba5 fix: savePage throw on relative paths (#33016)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-02-22 16:29:47 +09:00
Shelley Vohr
74cc0023f8 fix: crash on printer dialog cancellation (#33015) 2022-02-22 16:28:01 +09:00
trop[bot]
594e905218 fix: don't restore maximized BrowserWindow when calling showInactive (#33021)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2022-02-22 16:25:40 +09:00
trop[bot]
680e2041b5 fix: webContents.openDevTools({mode}) not working (#32945)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-02-22 16:18:44 +09:00
trop[bot]
fb7cf29086 chore: backport EPROTOTYPE fixes from libuv (#32943)
* chore: backport EPROTOTYPE fixes from libuv

This commit backports three commits from libuv's 1.x branch to fix
issues with CPU going to 100% on macOS when EPROTOTYPE is returned.

See: abb109f30f
See: 3a7b95593a
See: de24da8c11

* Update .patches

Co-authored-by: Fedor Indutny <fedor@indutny.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-02-22 16:18:21 +09:00
electron-roller[bot]
d0e8f9b306 chore: bump chromium to 98.0.4758.102 (17-x-y) (#32906)
Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-02-21 14:29:20 -08:00
trop[bot]
58218f2735 chore: add @electron/wg-security to patches/ CODEOWNERS (#33006)
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2022-02-21 15:04:40 +01:00
trop[bot]
0891d2f7f7 fix: command string for windows protocol handler (#33012)
Co-authored-by: deepak1556 <hop2deep@gmail.com>
2022-02-21 14:59:40 +01:00
trop[bot]
122cc8d9e5 Fix broken link to GNOME notifications spec (#33000)
Co-authored-by: Kev <kevslashnull@gmail.com>
2022-02-21 10:27:59 +01:00
trop[bot]
029b445c53 fix: stale renderer process on quit (#32970)
Co-authored-by: Micha Hanselmann <micha.hanselmann@gmail.com>
2022-02-21 10:25:18 +09:00
trop[bot]
9ab1ecdd5f docs: update checklists (#32932)
Co-authored-by: Erick Zhao <erick@hotmail.ca>
2022-02-21 10:21:28 +09:00
trop[bot]
9825a202b0 docs: fix relative link in developer documentation (#32921)
Co-authored-by: Erick Zhao <erick@hotmail.ca>
2022-02-15 14:36:23 -08:00
Sudowoodo Release Bot
2cc6113a04 Bump v17.0.1 2022-02-14 12:02:53 -08:00
trop[bot]
6d794ca879 docs: add IPC doc (#32840)
* docs: add IPC doc

* fix: use "string" primitive

* use 'string' ipcrenderer

* use "number" primitive

* Update docs/tutorial/ipc.md

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>

* Update docs/tutorial/ipc.md

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>

* add code sample

Co-authored-by: Erick Zhao <erick@hotmail.ca>
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2022-02-09 16:51:56 -05:00
electron-roller[bot]
23d3ad9d1a chore: bump chromium in DEPS to 98.0.4758.82 (#32832)
Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2022-02-09 15:37:12 -05:00
trop[bot]
3001b69f58 Make ElectronBrowser mojo interface frame associated. (#32815)
Co-authored-by: Marek Haranczyk <marek@openfin.co>
2022-02-09 10:57:18 -05:00
trop[bot]
a729c8c048 test: disable the test that makes spec runner hang on exit (#32839)
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2022-02-09 10:55:08 -05:00
trop[bot]
4ce0b50f4b build: rebuild the dist_zips when the deps get modified (#32818)
* build: rebuild the dist_zips when the deps get modified

The dist.zip generated by the electron_dist_zip action was not getting
updated when changes were being made to the dependencies, like the
source files. It turns out, we were using data_deps for the dependencies
instead of deps. Here is the difference:

data_deps: things needed to ultimately run the thing built by a target
deps: things needed to build the target

So the difference in treatment of both sets of dependencies is actually
intentional.

Signed-off-by: Darshan Sen <raisinten@gmail.com>

* fixup! build: rebuild the dist_zips when the deps get modified

Signed-off-by: Darshan Sen <raisinten@gmail.com>

Co-authored-by: Darshan Sen <raisinten@gmail.com>
2022-02-09 09:49:18 -05:00
trop[bot]
ffdf4f3dd9 test: improve webContents.savePage() specs (#32744)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-02-09 11:58:04 +01:00
trop[bot]
e4b5c94192 docs: clarify meaning of cssOrigin (#32811)
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2022-02-08 16:16:46 -05:00
trop[bot]
32988f18eb fix: WCO window hover on window controls on Windows (#32719) 2022-02-03 10:05:47 +01:00
trop[bot]
124cfcaf88 docs: Update E18 release date (#32721)
Co-authored-by: Sofia Nguy <sofianguy@gmail.com>
2022-02-02 09:27:43 -08:00
trop[bot]
e01c215a0a docs: fix missing tag end in clipboard example (#32695)
Co-authored-by: Paul Hollinsky <paulhollinsky@gmail.com>
2022-02-02 10:12:26 -05:00
trop[bot]
a23c93a6a0 fix: some frameless windows showing a frame on Windows (#32707)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-02-02 15:11:31 +01:00
electron-roller[bot]
a63456bb82 chore: bump chromium in DEPS to 98.0.4758.80 (#32700)
Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2022-02-01 19:22:10 -05:00
Sudowoodo Release Bot
34769dd981 Bump v17.0.0 2022-01-31 16:01:59 -08:00
trop[bot]
a9b71c121f fix: transparent window max/unmax event firing (#32690)
* fix: transparent window max/unmax event firing

* chore: fixup tests

* Update spec-main/api-browser-window-spec.ts

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>

* chore: update patches

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-01-31 18:59:15 -05:00
trop[bot]
2abe74e9f0 docs: update the build docs for electron (#32679)
Co-authored-by: Harshil Jain <twitharshil@gmail.com>
2022-01-31 18:51:26 -05:00
trop[bot]
d2aeb53317 fix: re-enable PartitionAlloc on macOS (#32683)
* fix: re-enable PartitionAlloc on macOS

* no need to copy ignore_result on linux

* factor out FixStdioStreams

* include buildflags.h in electron_main_linux

* #include electron/fuses

* more missing includes

* chore: fixup patches after rebase

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-01-31 18:39:08 -05:00
trop[bot]
b69c4dfa3b fix: expose all serial devices to setDevicePermissionHandler (#32685)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-01-31 16:17:48 -05:00
electron-roller[bot]
57ddb3bd6d chore: bump chromium to 98.0.4758.74 (17-x-y) (#32655)
* chore: bump chromium in DEPS to 98.0.4758.74

* chore: update patches

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-01-31 15:32:45 -05:00
trop[bot]
a4fd5ed5fb chore: update config.py (#32678)
* Fix missing comma

Co-authored-by: Marek Šuppa <mrshu@users.noreply.github.com>
2022-01-31 16:13:55 +01:00
Shelley Vohr
a2268557c4 fix: undefined backgroundColor (#32653) 2022-01-31 14:40:52 +01:00
Sudowoodo Release Bot
97f88f102c Bump v17.0.0-beta.9 2022-01-31 05:31:11 -08:00
trop[bot]
0c3c6cc8fa fix: Add support for Wayland window decorations (#29618) (#32650)
Co-authored-by: Ryan Gonzalez <rymg19@gmail.com>
2022-01-28 10:16:55 -08:00
trop[bot]
94da1f3106 fix: css transparent background being lost (#32649)
* fix: css transparent background being lost

* fix: also call SetContentBackgroundColor initially

* spec: add a test for correct behavior

* chore: address feedback from review

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-01-28 19:59:43 +09:00
trop[bot]
c8e08fd2f0 docs: update context bridge docs about Promises and Errors (#32644)
* Update context bridge docs about Promises

From my testing it doesn't remove Promises in nested objects,
also according to the test suite it does not:
80577a4f08/spec-main/api-context-bridge-spec.ts (L693)

* docs: Update docs for errors too

Co-authored-by: Mikael Finstad <finstaden@gmail.com>
2022-01-28 19:59:14 +09:00
Jeremy Rose
3f521cad0c chore: cherry-pick f5101995acd2 from chromium (#32638) 2022-01-27 16:54:06 -08:00
trop[bot]
c63ef8529e build(deps): bump node-fetch from 2.6.1 to 2.6.7 (#32635)
Bumps [node-fetch](https://github.com/node-fetch/node-fetch) from 2.6.1 to 2.6.7.
- [Release notes](https://github.com/node-fetch/node-fetch/releases)
- [Changelog](https://github.com/node-fetch/node-fetch/blob/main/docs/CHANGELOG.md)
- [Commits](https://github.com/node-fetch/node-fetch/compare/v2.6.1...v2.6.7)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-27 21:00:50 +01:00
141 changed files with 3949 additions and 974 deletions

2
.github/CODEOWNERS vendored
View File

@@ -4,7 +4,7 @@
# https://git-scm.com/docs/gitignore
# Upgrades WG
/patches/ @electron/wg-upgrades
/patches/ @electron/wg-upgrades @electron/wg-security
DEPS @electron/wg-upgrades
# Releases WG

View File

@@ -900,8 +900,12 @@ if (is_mac) {
deps += [ "//sandbox/mac:seatbelt" ]
}
defines = [ "HELPER_EXECUTABLE" ]
sources = filenames.app_sources
sources += [ "shell/common/electron_constants.cc" ]
sources = [
"shell/app/electron_main_mac.cc",
"shell/app/uv_stdio_fix.cc",
"shell/app/uv_stdio_fix.h",
"shell/common/electron_constants.cc",
]
include_dirs = [ "." ]
info_plist = "shell/renderer/resources/mac/Info.plist"
extra_substitutions =
@@ -1040,15 +1044,18 @@ if (is_mac) {
mac_app_bundle("electron_app") {
output_name = electron_product_name
sources = filenames.app_sources
sources += [ "shell/common/electron_constants.cc" ]
sources = [
"shell/app/electron_main_mac.cc",
"shell/app/uv_stdio_fix.cc",
"shell/app/uv_stdio_fix.h",
"shell/common/electron_constants.cc",
]
include_dirs = [ "." ]
deps = [
":electron_app_framework_bundle_data",
":electron_app_plist",
":electron_app_resources",
":electron_fuses",
"//base",
"//electron/buildflags",
]
if (is_mas_build) {
@@ -1150,7 +1157,15 @@ if (is_mac) {
executable("electron_app") {
output_name = electron_project_name
sources = filenames.app_sources
if (is_win) {
sources = [ "shell/app/electron_main_win.cc" ]
} else if (is_linux) {
sources = [
"shell/app/electron_main_linux.cc",
"shell/app/uv_stdio_fix.cc",
"shell/app/uv_stdio_fix.h",
]
}
include_dirs = [ "." ]
deps = [
":default_app_asar",
@@ -1386,11 +1401,13 @@ dist_zip("electron_dist_zip") {
if (is_linux) {
data_deps += [ "//sandbox/linux:chrome_sandbox" ]
}
deps = data_deps
outputs = [ "$root_build_dir/dist.zip" ]
}
dist_zip("electron_ffmpeg_zip") {
data_deps = [ "//third_party/ffmpeg" ]
deps = data_deps
outputs = [ "$root_build_dir/ffmpeg.zip" ]
}
@@ -1408,6 +1425,7 @@ group("electron_chromedriver") {
dist_zip("electron_chromedriver_zip") {
testonly = true
data_deps = electron_chromedriver_deps
deps = data_deps
outputs = [ "$root_build_dir/chromedriver.zip" ]
}
@@ -1426,6 +1444,7 @@ group("electron_mksnapshot") {
dist_zip("electron_mksnapshot_zip") {
data_deps = mksnapshot_deps
deps = data_deps
outputs = [ "$root_build_dir/mksnapshot.zip" ]
}
@@ -1436,6 +1455,7 @@ copy("hunspell_dictionaries") {
dist_zip("hunspell_dictionaries_zip") {
data_deps = [ ":hunspell_dictionaries" ]
deps = data_deps
flatten = true
outputs = [ "$root_build_dir/hunspell_dictionaries.zip" ]
@@ -1449,6 +1469,7 @@ copy("libcxx_headers") {
dist_zip("libcxx_headers_zip") {
data_deps = [ ":libcxx_headers" ]
deps = data_deps
flatten = true
flatten_relative_to = rebase_path(
"$target_gen_dir/electron_libcxx_include/buildtools/third_party/libc++/trunk",
@@ -1464,6 +1485,7 @@ copy("libcxxabi_headers") {
dist_zip("libcxxabi_headers_zip") {
data_deps = [ ":libcxxabi_headers" ]
deps = data_deps
flatten = true
flatten_relative_to = rebase_path(
"$target_gen_dir/electron_libcxxabi_include/buildtools/third_party/libc++abi/trunk",

2
DEPS
View File

@@ -15,7 +15,7 @@ gclient_gn_args = [
vars = {
'chromium_version':
'98.0.4758.11',
'98.0.4758.109',
'node_version':
'v16.13.0',
'nan_version':

View File

@@ -1 +1 @@
17.0.0-beta.8
17.1.1

View File

@@ -391,9 +391,10 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
contain the layout of the document—without requiring scrolling. Enabling
this will cause the `preferred-size-changed` event to be emitted on the
`WebContents` when the preferred size changes. Default is `false`.
* `titleBarOverlay` Object | boolean (optional) - When using a frameless window in conjuction with `win.setWindowButtonVisibility(true)` on macOS or using a `titleBarStyle` so that the standard window controls ("traffic lights" on macOS) are visible, this property enables the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars]. Specifying `true` will result in an overlay with default system colors. Default is `false`.
* `color` string (optional) _Windows_ - The CSS color of the Window Controls Overlay when enabled. Default is the system color.
* `symbolColor` string (optional) _Windows_ - The CSS color of the symbols on the Window Controls Overlay when enabled. Default is the system color.
* `titleBarOverlay` Object | Boolean (optional) - When using a frameless window in conjuction with `win.setWindowButtonVisibility(true)` on macOS or using a `titleBarStyle` so that the standard window controls ("traffic lights" on macOS) are visible, this property enables the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars]. Specifying `true` will result in an overlay with default system colors. Default is `false`.
* `color` String (optional) _Windows_ - The CSS color of the Window Controls Overlay when enabled. Default is the system color.
* `symbolColor` String (optional) _Windows_ - The CSS color of the symbols on the Window Controls Overlay when enabled. Default is the system color.
* `height` Integer (optional) _macOS_ _Windows_ - The height of the title bar and Window Controls Overlay in pixels. Default is system height.
When setting minimum or maximum window size with `minWidth`/`maxWidth`/
`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from

View File

@@ -76,7 +76,7 @@ Writes `markup` to the clipboard.
```js
const { clipboard } = require('electron')
clipboard.writeHTML('<b>Hi</b')
clipboard.writeHTML('<b>Hi</b>')
```
### `clipboard.readImage([type])`

View File

@@ -102,8 +102,8 @@ has been included below for completeness:
| `boolean` | Simple | ✅ | ✅ | N/A |
| `Object` | Complex | ✅ | ✅ | Keys must be supported using only "Simple" types in this table. Values must be supported in this table. Prototype modifications are dropped. Sending custom classes will copy values but not the prototype. |
| `Array` | Complex | ✅ | ✅ | Same limitations as the `Object` type |
| `Error` | Complex | ✅ | ✅ | Errors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context |
| `Promise` | Complex | ✅ | ✅ | Promises are only proxied if they are the return value or exact parameter. Promises nested in arrays or objects will be dropped. |
| `Error` | Complex | ✅ | ✅ | Errors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context, and any custom properties on the Error object [will be lost](https://github.com/electron/electron/issues/25596) |
| `Promise` | Complex | ✅ | ✅ | N/A
| `Function` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending classes or constructors will not work. |
| [Cloneable Types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) | Simple | ✅ | ✅ | See the linked document on cloneable types |
| `Element` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending custom elements will not work. |

View File

@@ -1,3 +1,10 @@
---
title: "ipcMain"
description: "Communicate asynchronously from the main process to renderer processes."
slug: ipc-main
hide_title: false
---
# ipcMain
> Communicate asynchronously from the main process to renderer processes.
@@ -9,7 +16,9 @@ process, it handles asynchronous and synchronous messages sent from a renderer
process (web page). Messages sent from a renderer will be emitted to this
module.
## Sending Messages
For usage examples, check out the [IPC tutorial].
## Sending messages
It is also possible to send messages from the main process to the renderer
process, see [webContents.send][web-contents-send] for more information.
@@ -21,36 +30,6 @@ process, see [webContents.send][web-contents-send] for more information.
coming from frames that aren't the main frame (e.g. iframes) whereas
`event.sender.send(...)` will always send to the main frame.
An example of sending and handling messages between the render and main
processes:
```javascript
// In main process.
const { ipcMain } = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.reply('asynchronous-reply', 'pong')
})
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.returnValue = 'pong'
})
```
```javascript
// In renderer process (web page).
// NB. Electron APIs are only accessible from preload, unless contextIsolation is disabled.
// See https://www.electronjs.org/docs/tutorial/process-model#preload-scripts for more details.
const { ipcRenderer } = require('electron')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"
ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log(arg) // prints "pong"
})
ipcRenderer.send('asynchronous-message', 'ping')
```
## Methods
The `ipcMain` module has the following method to listen for events:
@@ -59,7 +38,7 @@ The `ipcMain` module has the following method to listen for events:
* `channel` string
* `listener` Function
* `event` IpcMainEvent
* `event` [IpcMainEvent][ipc-main-event]
* `...args` any[]
Listens to `channel`, when a new message arrives `listener` would be called with
@@ -69,7 +48,7 @@ Listens to `channel`, when a new message arrives `listener` would be called with
* `channel` string
* `listener` Function
* `event` IpcMainEvent
* `event` [IpcMainEvent][ipc-main-event]
* `...args` any[]
Adds a one time `listener` function for the event. This `listener` is invoked
@@ -93,8 +72,8 @@ Removes listeners of the specified `channel`.
### `ipcMain.handle(channel, listener)`
* `channel` string
* `listener` Function<Promise\<void> | any>
* `event` IpcMainInvokeEvent
* `listener` Function<Promise\<void&#62; | any&#62;
* `event` [IpcMainInvokeEvent][ipc-main-invoke-event]
* `...args` any[]
Adds a handler for an `invoke`able IPC. This handler will be called whenever a
@@ -104,14 +83,14 @@ If `listener` returns a Promise, the eventual result of the promise will be
returned as a reply to the remote caller. Otherwise, the return value of the
listener will be used as the value of the reply.
```js
// Main process
```js title='Main Process'
ipcMain.handle('my-invokable-ipc', async (event, ...args) => {
const result = await somePromise(...args)
return result
})
```
// Renderer process
```js title='Renderer Process'
async () => {
const result = await ipcRenderer.invoke('my-invokable-ipc', arg1, arg2)
// ...
@@ -130,7 +109,7 @@ provided to the renderer process. Please refer to
### `ipcMain.handleOnce(channel, listener)`
* `channel` string
* `listener` Function<Promise\<void> | any>
* `listener` Function<Promise\<void&#62; | any&#62;
* `event` IpcMainInvokeEvent
* `...args` any[]
@@ -146,13 +125,16 @@ Removes any handler for `channel`, if present.
## IpcMainEvent object
The documentation for the `event` object passed to the `callback` can be found
in the [`ipc-main-event`](structures/ipc-main-event.md) structure docs.
in the [`ipc-main-event`][ipc-main-event] structure docs.
## IpcMainInvokeEvent object
The documentation for the `event` object passed to `handle` callbacks can be
found in the [`ipc-main-invoke-event`](structures/ipc-main-invoke-event.md)
found in the [`ipc-main-invoke-event`][ipc-main-invoke-event]
structure docs.
[IPC tutorial]: ../tutorial/ipc.md
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
[web-contents-send]: web-contents.md#contentssendchannel-args
[web-contents-send]: ../api/web-contents.md#contentssendchannel-args
[ipc-main-event]:../api/structures/ipc-main-event.md
[ipc-main-invoke-event]:../api/structures/ipc-main-invoke-event.md

View File

@@ -1,3 +1,10 @@
---
title: "ipcRenderer"
description: "Communicate asynchronously from a renderer process to the main process."
slug: ipc-renderer
hide_title: false
---
# ipcRenderer
> Communicate asynchronously from a renderer process to the main process.
@@ -9,7 +16,7 @@ methods so you can send synchronous and asynchronous messages from the render
process (web page) to the main process. You can also receive replies from the
main process.
See [ipcMain](ipc-main.md) for code examples.
See [IPC tutorial](../tutorial/ipc.md) for code examples.
## Methods
@@ -70,7 +77,7 @@ throw an exception.
> them. Attempting to send such objects over IPC will result in an error.
The main process handles it by listening for `channel` with the
[`ipcMain`](ipc-main.md) module.
[`ipcMain`](./ipc-main.md) module.
If you need to transfer a [`MessagePort`][] to the main process, use [`ipcRenderer.postMessage`](#ipcrendererpostmessagechannel-message-transfer).
@@ -98,7 +105,7 @@ throw an exception.
> them. Attempting to send such objects over IPC will result in an error.
The main process should listen for `channel` with
[`ipcMain.handle()`](ipc-main.md#ipcmainhandlechannel-listener).
[`ipcMain.handle()`](./ipc-main.md#ipcmainhandlechannel-listener).
For example:
@@ -124,11 +131,11 @@ If you do not need a response to the message, consider using [`ipcRenderer.send`
* `channel` string
* `...args` any[]
Returns `any` - The value sent back by the [`ipcMain`](ipc-main.md) handler.
Returns `any` - The value sent back by the [`ipcMain`](./ipc-main.md) handler.
Send a message to the main process via `channel` and expect a result
synchronously. Arguments will be serialized with the [Structured Clone
Algorithm][SCA], just like [`window.postMessage`][], so prototype chains will not be
Algorithm][SCA], just like [`window.postMessage`], so prototype chains will not be
included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will
throw an exception.
@@ -140,13 +147,13 @@ throw an exception.
> Electron's IPC to the main process, as the main process would have no way to decode
> them. Attempting to send such objects over IPC will result in an error.
The main process handles it by listening for `channel` with [`ipcMain`](ipc-main.md) module,
The main process handles it by listening for `channel` with [`ipcMain`](./ipc-main.md) module,
and replies by setting `event.returnValue`.
> :warning: **WARNING**: Sending a synchronous message will block the whole
> renderer process until the reply is received, so use this method only as a
> last resort. It's much better to use the asynchronous version,
> [`invoke()`](ipc-renderer.md#ipcrendererinvokechannel-args).
> [`invoke()`](./ipc-renderer.md#ipcrendererinvokechannel-args).
### `ipcRenderer.postMessage(channel, message, [transfer])`
@@ -158,7 +165,7 @@ Send a message to the main process, optionally transferring ownership of zero
or more [`MessagePort`][] objects.
The transferred `MessagePort` objects will be available in the main process as
[`MessagePortMain`](message-port-main.md) objects by accessing the `ports`
[`MessagePortMain`](./message-port-main.md) objects by accessing the `ports`
property of the emitted event.
For example:
@@ -197,7 +204,7 @@ the host page instead of the main process.
## Event object
The documentation for the `event` object passed to the `callback` can be found
in the [`ipc-renderer-event`](structures/ipc-renderer-event.md) structure docs.
in the [`ipc-renderer-event`](./structures/ipc-renderer-event.md) structure docs.
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
[SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm

View File

@@ -1084,7 +1084,7 @@ Returns `string` - The user agent for this web page.
* `css` string
* `options` Object (optional)
* `cssOrigin` string (optional) - Can be either 'user' or 'author'; Specifying 'user' enables you to prevent websites from overriding the CSS you insert. Default is 'author'.
* `cssOrigin` string (optional) - Can be either 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
Returns `Promise<string>` - A promise that resolves with a key for the inserted CSS that can later be used to remove the CSS via `contents.removeInsertedCSS(key)`.
@@ -1839,7 +1839,7 @@ the cursor when dragging.
#### `contents.savePage(fullPath, saveType)`
* `fullPath` string - The full file path.
* `fullPath` string - The absolute file path.
* `saveType` string - Specify the save type.
* `HTMLOnly` - Save only the HTML of the page.
* `HTMLComplete` - Save complete-html page.

View File

@@ -98,42 +98,37 @@ $ gclient sync -f
## Building
**Set the environment variable for chromium build tools**
On Linux & MacOS
```sh
$ cd src
$ export CHROMIUM_BUILDTOOLS_PATH=`pwd`/buildtools
$ gn gen out/Testing --args="import(\"//electron/build/args/testing.gn\") $GN_EXTRA_ARGS"
```
Or on Windows (without the optional argument):
On Windows:
```sh
$ cd src
$ set CHROMIUM_BUILDTOOLS_PATH=%cd%\buildtools
```
**To generate Testing build config of Electron:**
```sh
$ gn gen out/Testing --args="import(\"//electron/build/args/testing.gn\")"
```
This will generate a build directory `out/Testing` under `src/` with
the testing build configuration. You can replace `Testing` with another name,
but it should be a subdirectory of `out`.
Also you shouldn't have to run `gn gen` again—if you want to change the
build arguments, you can run `gn args out/Testing` to bring up an editor.
To see the list of available build configuration options, run `gn args
out/Testing --list`.
**For generating Testing build config of
Electron:**
**To generate Release build config of Electron:**
```sh
$ gn gen out/Testing --args="import(\"//electron/build/args/testing.gn\") $GN_EXTRA_ARGS"
$ gn gen out/Release --args="import(\"//electron/build/args/release.gn\")"
```
**For generating Release (aka "non-component" or "static") build config of
Electron:**
**Note:** This will generate a `out/Testing` or `out/Release` build directory under `src/` with the testing or release build depending upon the configuration passed above. You can replace `Testing|Release` with another names, but it should be a subdirectory of `out`.
```sh
$ gn gen out/Release --args="import(\"//electron/build/args/release.gn\") $GN_EXTRA_ARGS"
```
Also you shouldn't have to run `gn gen` again—if you want to change the build arguments, you can run `gn args out/Testing` to bring up an editor. To see the list of available build configuration options, run `gn args out/Testing --list`.
**To build, run `ninja` with the `electron` target:**
Nota Bene: This will also take a while and probably heat up your lap.
@@ -169,13 +164,13 @@ $ ./out/Testing/electron
On linux, first strip the debugging and symbol information:
```sh
electron/script/strip-binaries.py -d out/Release
$ electron/script/strip-binaries.py -d out/Release
```
To package the electron build as a distributable zip file:
```sh
ninja -C out/Release electron:electron_dist_zip
$ ninja -C out/Release electron:electron_dist_zip
```
### Cross-compiling

View File

@@ -180,7 +180,7 @@ $ git push origin my-branch
### Step 9: Opening the Pull Request
From within GitHub, opening a new pull request will present you with a template
that should be filled out. It can be found [here](../../.github/PULL_REQUEST_TEMPLATE.md).
that should be filled out. It can be found [here](https://github.com/electron/electron/blob/main/.github/PULL_REQUEST_TEMPLATE.md).
If you do not adequately complete this template, your PR may be delayed in being merged as maintainers
seek more information or clarify ambiguities.

View File

@@ -1,27 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div>
<div>
<h1>Asynchronous messages</h1>
<i>Supports: Win, macOS, Linux <span>|</span> Process: Both</i>
<div>
<div>
<button id="async-msg">Ping</button>
<span id="async-reply"></span>
</div>
<p>Using <code>ipc</code> to send messages between processes asynchronously is the preferred method since it will return when finished without blocking other operations in the same process.</p>
<p>This example sends a "ping" from this process (renderer) to the main process. The main process then replies with "pong".</p>
</div>
</div>
</div>
<script>
// You can also require other files to run in this process
require('./renderer.js')
</script>
</body>
</html>

View File

@@ -1,29 +0,0 @@
const { app, BrowserWindow, ipcMain } = require('electron')
let mainWindow = null
function createWindow () {
const windowOptions = {
width: 600,
height: 400,
title: 'Asynchronous messages',
webPreferences: {
nodeIntegration: true
}
}
mainWindow = new BrowserWindow(windowOptions)
mainWindow.loadFile('index.html')
mainWindow.on('closed', () => {
mainWindow = null
})
}
app.whenReady().then(() => {
createWindow()
})
ipcMain.on('asynchronous-message', (event, arg) => {
event.sender.send('asynchronous-reply', 'pong')
})

View File

@@ -1,12 +0,0 @@
const { ipcRenderer } = require('electron')
const asyncMsgBtn = document.getElementById('async-msg')
asyncMsgBtn.addEventListener('click', () => {
ipcRenderer.send('asynchronous-message', 'ping')
})
ipcRenderer.on('asynchronous-reply', (event, arg) => {
const message = `Asynchronous message reply: ${arg}`
document.getElementById('async-reply').innerHTML = message
})

View File

@@ -1,27 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div>
<div>
<h1>Synchronous messages</h1>
<i>Supports: Win, macOS, Linux <span>|</span> Process: Both</i>
<div>
<div>
<button id="sync-msg">Ping</button>
<span id="sync-reply"></span>
</div>
<p>You can use the <code>ipc</code> module to send synchronous messages between processes as well, but note that the synchronous nature of this method means that it <b>will block</b> other operations while completing its task.</p>
<p>This example sends a synchronous message, "ping", from this process (renderer) to the main process. The main process then replies with "pong".</p>
</div>
</div>
</div>
<script>
// You can also require other files to run in this process
require('./renderer.js')
</script>
</body>
</html>

View File

@@ -1,29 +0,0 @@
const { app, BrowserWindow, ipcMain } = require('electron')
let mainWindow = null
function createWindow () {
const windowOptions = {
width: 600,
height: 400,
title: 'Synchronous Messages',
webPreferences: {
nodeIntegration: true
}
}
mainWindow = new BrowserWindow(windowOptions)
mainWindow.loadFile('index.html')
mainWindow.on('closed', () => {
mainWindow = null
})
}
app.whenReady().then(() => {
createWindow()
})
ipcMain.on('synchronous-message', (event, arg) => {
event.returnValue = 'pong'
})

View File

@@ -1,9 +0,0 @@
const { ipcRenderer } = require('electron')
const syncMsgBtn = document.getElementById('sync-msg')
syncMsgBtn.addEventListener('click', () => {
const reply = ipcRenderer.sendSync('synchronous-message', 'ping')
const message = `Synchronous message reply: ${reply}`
document.getElementById('sync-reply').innerHTML = message
})

View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Hello World!</title>
</head>
<body>
Title: <input id="title"/>
<button id="btn" type="button">Set</button>
<script src="./renderer.js"></script>
</body>
</html>

View File

@@ -0,0 +1,30 @@
const {app, BrowserWindow, ipcMain} = require('electron')
const path = require('path')
function createWindow () {
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
ipcMain.on('set-title', (event, title) => {
const webContents = event.sender
const win = BrowserWindow.fromWebContents(webContents)
win.setTitle(title)
})
mainWindow.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})

View File

@@ -0,0 +1,5 @@
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
setTitle: (title) => ipcRenderer.send('set-title', title)
})

View File

@@ -0,0 +1,6 @@
const setButton = document.getElementById('btn')
const titleInput = document.getElementById('title')
setButton.addEventListener('click', () => {
const title = titleInput.value
window.electronAPI.setTitle(title)
});

View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Dialog</title>
</head>
<body>
<button type="button" id="btn">Open a File</button>
File path: <strong id="filePath"></strong>
<script src='./renderer.js'></script>
</body>
</html>

View File

@@ -0,0 +1,32 @@
const {app, BrowserWindow, ipcMain,dialog} = require('electron')
const path = require('path')
async function handleFileOpen() {
const { canceled, filePaths } = await dialog.showOpenDialog()
if (canceled) {
return
} else {
return filePaths[0]
}
}
function createWindow () {
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
mainWindow.loadFile('index.html')
}
app.whenReady().then(() => {
ipcMain.handle('dialog:openFile', handleFileOpen)
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})

View File

@@ -0,0 +1,5 @@
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI',{
openFile: () => ipcRenderer.invoke('dialog:openFile')
})

View File

@@ -0,0 +1,7 @@
const btn = document.getElementById('btn')
const filePathElement = document.getElementById('filePath')
btn.addEventListener('click', async () => {
const filePath = await window.electronAPI.openFile()
filePathElement.innerText = filePath
})

View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Menu Counter</title>
</head>
<body>
Current value: <strong id="counter">0</strong>
<script src="./renderer.js"></script>
</body>
</html>

View File

@@ -0,0 +1,48 @@
const {app, BrowserWindow, Menu} = require('electron')
const path = require('path')
function createWindow () {
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
const menu = Menu.buildFromTemplate([
{
label: app.name,
submenu: [
{
click: () => mainWindow.webContents.send('update-counter', 1),
label: 'Increment',
},
{
click: () => mainWindow.webContents.send('update-counter', -1),
label: 'Decrement',
}
]
}
])
Menu.setApplicationMenu(menu)
mainWindow.loadFile('index.html')
// Open the DevTools.
mainWindow.webContents.openDevTools()
}
app.whenReady().then(() => {
ipcMain.on('counter-value', (_event, value) => {
console.log(value) // will print value to Node console
})
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})

View File

@@ -0,0 +1,5 @@
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
handleCounter: (callback) => ipcRenderer.on('update-counter', callback)
})

View File

@@ -0,0 +1,8 @@
const counter = document.getElementById('counter')
window.electronAPI.handleCounter((event, value) => {
const oldValue = Number(counter.innerText)
const newValue = oldValue + value
counter.innerText = newValue
event.reply('counter-value', newValue)
})

View File

@@ -26,4 +26,5 @@ Special notes:
| 14.0.0 | -- | 2021-May-27 | 2021-Aug-31 | M93 | v14.17 |
| 15.0.0 | 2021-Jul-20 | 2021-Sep-01 | 2021-Sep-21 | M94 | v16.5 |
| 16.0.0 | 2021-Sep-23 | 2021-Oct-20 | 2021-Nov-16 | M96 | v16.9 |
| 17.0.0 | 2021-Nov-18 | 2022-Jan-06 | 2022-Feb-01 | M98 | TBD |
| 17.0.0 | 2021-Nov-18 | 2022-Jan-06 | 2022-Feb-01 | M98 | v16.13 |
| 18.0.0 | 2022-Feb-03 | 2022-Mar-03 | 2022-Mar-29 | M100 | TBD |

View File

@@ -1,4 +1,11 @@
# In-App Purchases (macOS)
---
title: In-App Purchases
description: Add in-app purchases to your Mac App Store (MAS) application
slug: in-app-purchases
hide_title: true
---
# In-App Purchases
## Preparing

571
docs/tutorial/ipc.md Normal file
View File

@@ -0,0 +1,571 @@
---
title: Inter-Process Communication
description: Use the ipcMain and ipcRenderer modules to communicate between Electron processes
slug: ipc
hide_title: false
---
# Inter-Process Communication
Inter-process communication (IPC) is a key part of building feature-rich desktop applications
in Electron. Because the main and renderer processes have different responsibilities in
Electron's process model, IPC is the only way to perform many common tasks, such as calling a
native API from your UI or triggering changes in your web contents from native menus.
## IPC channels
In Electron, processes communicate by passing messages through developer-defined "channels"
with the [`ipcMain`] and [`ipcRenderer`] modules. These channels are
**arbitrary** (you can name them anything you want) and **bidirectional** (you can use the
same channel name for both modules).
In this guide, we'll be going over some fundamental IPC patterns with concrete examples that
you can use as a reference for your app code.
## Understanding context-isolated processes
Before proceeding to implementation details, you should be familiar with the idea of using a
[preload script] to import Node.js and Electron modules in a context-isolated renderer process.
* For a full overview of Electron's process model, you can read the [process model docs].
* For a primer into exposing APIs from your preload script using the `contextBridge` module, check
out the [context isolation tutorial].
## Pattern 1: Renderer to main (one-way)
To fire a one-way IPC message from a renderer process to the main process, you can use the
[`ipcRenderer.send`] API to send a message that is then received by the [`ipcMain.on`] API.
You usually use this pattern to call a main process API from your web contents. We'll demonstrate
this pattern by creating a simple app that can programmatically change its window title.
For this demo, you'll need to add code to your main process, your renderer process, and a preload
script. The full code is below, but we'll be explaining each file individually in the following
sections.
```fiddle docs/fiddles/ipc/pattern-1
```
### 1. Listen for events with `ipcMain.on`
In the main process, set an IPC listener on the `set-title` channel with the `ipcMain.on` API:
```javascript {6-10,22} title='main.js (Main Process)'
const {app, BrowserWindow, ipcMain} = require('electron')
const path = require('path')
//...
function handleSetTitle (event, title) {
const webContents = event.sender
const win = BrowserWindow.fromWebContents(webContents)
win.setTitle(title)
}
function createWindow () {
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
mainWindow.loadFile('index.html')
}
app.whenReady().then(() => {
ipcMain.on('set-title', handleSetTitle)
createWindow()
}
//...
```
The above `handleSetTitle` callback has two parameters: an [IpcMainEvent] structure and a
`title` string. Whenever a message comes through the `set-title` channel, this function will
find the BrowserWindow instance attached to the message sender and use the `win.setTitle`
API on it.
:::info
Make sure you're loading the `index.html` and `preload.js` entry points for the following steps!
:::
### 2. Expose `ipcRenderer.send` via preload
To send messages to the listener created above, you can use the `ipcRenderer.send` API.
By default, the renderer process has no Node.js or Electron module access. As an app developer,
you need to choose which APIs to expose from your preload script using the `contextBridge` API.
In your preload script, add the following code, which will expose a global `window.electronAPI`
variable to your renderer process.
```javascript title='preload.js (Preload Script)'
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
setTitle: (title) => ipcRenderer.send('set-title', title)
})
```
At this point, you'll be able to use the `window.electronAPI.setTitle()` function in the renderer
process.
:::caution Security warning
We don't directly expose the whole `ipcRenderer.send` API for [security reasons]. Make sure to
limit the renderer's access to Electron APIs as much as possible.
:::
### 3. Build the renderer process UI
In our BrowserWindow's loaded HTML file, add a basic user interface consisting of a text input
and a button:
```html {11-12} title='index.html'
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Hello World!</title>
</head>
<body>
Title: <input id="title"/>
<button id="btn" type="button">Set</button>
<script src="./renderer.js"></script>
</body>
</html>
```
To make these elements interactive, we'll be adding a few lines of code in the imported
`renderer.js` file that leverages the `window.electronAPI` functionality exposed from the preload
script:
```javascript title='renderer.js (Renderer Process)'
const setButton = document.getElementById('btn')
const titleInput = document.getElementById('title')
setButton.addEventListener('click', () => {
const title = titleInput.value
window.electronAPI.setTitle(title)
});
```
At this point, your demo should be fully functional. Try using the input field and see what happens
to your BrowserWindow title!
## Pattern 2: Renderer to main (two-way)
A common application for two-way IPC is calling a main process module from your renderer process
code and waiting for a result. This can be done by using [`ipcRenderer.invoke`] paired with
[`ipcMain.handle`].
In the following example, we'll be opening a native file dialog from the renderer process and
returning the selected file's path.
For this demo, you'll need to add code to your main process, your renderer process, and a preload
script. The full code is below, but we'll be explaining each file individually in the following
sections.
```fiddle docs/fiddles/ipc/pattern-2
```
### 1. Listen for events with `ipcMain.handle`
In the main process, we'll be creating a `handleFileOpen()` function that calls
`dialog.showOpenDialog` and returns the value of the file path selected by the user. This function
is used as a callback whenever an `ipcRender.invoke` message is sent through the `dialog:openFile`
channel from the renderer process. The return value is then returned as a Promise to the original
`invoke` call.
:::caution A word on error handling
Errors thrown through `handle` in the main process are not transparent as they
are serialized and only the `message` property from the original error is
provided to the renderer process. Please refer to
[#24427](https://github.com/electron/electron/issues/24427) for details.
:::
```javascript {6-13,25} title='main.js (Main Process)'
const { BrowserWindow, dialog, ipcMain } = require('electron')
const path = require('path')
//...
async function handleFileOpen() {
const { canceled, filePaths } = await dialog.showOpenDialog()
if (canceled) {
return
} else {
return filePaths[0]
}
}
function createWindow () {
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
mainWindow.loadFile('index.html')
}
app.whenReady(() => {
ipcMain.handle('dialog:openFile', handleFileOpen)
createWindow()
})
//...
```
:::tip on channel names
The `dialog:` prefix on the IPC channel name has no effect on the code. It only serves
as a namespace that helps with code readability.
:::
:::info
Make sure you're loading the `index.html` and `preload.js` entry points for the following steps!
:::
### 2. Expose `ipcRenderer.invoke` via preload
In the preload script, we expose a one-line `openFile` function that calls and returns the value of
`ipcRenderer.invoke('dialog:openFile')`. We'll be using this API in the next step to call the
native dialog from our renderer's user interface.
```javascript title='preload.js (Preload Script)'
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
openFile: () => ipcRenderer.invoke('dialog:openFile')
})
```
:::caution Security warning
We don't directly expose the whole `ipcRenderer.invoke` API for [security reasons]. Make sure to
limit the renderer's access to Electron APIs as much as possible.
:::
### 3. Build the renderer process UI
Finally, let's build the HTML file that we load into our BrowserWindow.
```html {10-11} title='index.html'
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Dialog</title>
</head>
<body>
<button type="button" id="btn">Open a File</button>
File path: <strong id="filePath"></strong>
<script src='./renderer.js'></script>
</body>
</html>
```
The UI consists of a single `#btn` button element that will be used to trigger our preload API, and
a `#filePath` element that will be used to display the path of the selected file. Making these
pieces work will take a few lines of code in the renderer process script:
```javascript title='renderer.js (Renderer Process)'
const btn = document.getElementById('btn')
const filePathElement = document.getElementById('filePath')
btn.addEventListener('click', async () => {
const filePath = await window.electronAPI.openFile()
filePathElement.innerText = filePath
})
```
In the above snippet, we listen for clicks on the `#btn` button, and call our
`window.electronAPI.openFile()` API to activate the native Open File dialog. We then display the
selected file path in the `#filePath` element.
### Note: legacy approaches
The `ipcRenderer.invoke` API was added in Electron 7 as a developer-friendly way to tackle two-way
IPC from the renderer process. However, there exist a couple alternative approaches to this IPC
pattern.
:::warning Avoid legacy approaches if possible
We recommend using `ipcRenderer.invoke` whenever possible. The following two-way renderer-to-main
patterns are documented for historical purposes.
:::
:::info
For the following examples, we're calling `ipcRenderer` directly from the preload script to keep
the code samples small.
:::
#### Using `ipcRenderer.send`
The `ipcRenderer.send` API that we used for single-way communication can also be leveraged to
perform two-way communication. This was the recommended way for asynchronous two-way communication
via IPC prior to Electron 7.
```javascript title='preload.js (Preload Script)'
// You can also put expose this code to the renderer
// process with the `contextBridge` API
const { ipcRenderer } = require('electron')
ipcRenderer.on('asynchronous-reply', (_event, arg) => {
console.log(arg) // prints "pong" in the DevTools console
})
ipcRenderer.send('asynchronous-message', 'ping')
```
```javascript title='main.js (Main Process)'
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // prints "ping" in the Node console
// works like `send`, but returning a message back
// to the renderer that sent the original message
event.reply('asynchronous-reply', 'pong')
})
```
There are a couple downsides to this approach:
* You need to set up a second `ipcRenderer.on` listener to handle the response in the renderer
process. With `invoke`, you get the response value returned as a Promise to the original API call.
* There's no obvious way to pair the `asynchronous-reply` message to the original
`asynchronous-message` one. If you have very frequent messages going back and forth through these
channels, you would need to add additional app code to track each call and response individually.
#### Using `ipcRenderer.sendSync`
The `ipcRenderer.sendSync` API sends a message to the main process and waits _synchronously_ for a
response.
```javascript title='main.js (Main Process)'
const { ipcMain } = require('electron')
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg) // prints "ping" in the Node console
event.returnValue = 'pong'
})
```
```javascript title='preload.js (Preload Script)'
// You can also put expose this code to the renderer
// process with the `contextBridge` API
const { ipcRenderer } = require('electron')
const result = ipcRenderer.sendSync('synchronous-message', 'ping')
console.log(result) // prints "pong" in the DevTools console
```
The structure of this code is very similar to the `invoke` model, but we recommend
**avoiding this API** for performance reasons. Its synchronous nature means that it'll block the
renderer process until a reply is received.
## Pattern 3: Main to renderer
When sending a message from the main process to a renderer process, you need to specify which
renderer is receiving the message. Messages need to be sent to a renderer process
via its [`WebContents`] instance. This WebContents instance contains a [`send`][webcontents-send] method
that can be used in the same way as `ipcRenderer.send`.
To demonstrate this pattern, we'll be building a number counter controlled by the native operating
system menu.
For this demo, you'll need to add code to your main process, your renderer process, and a preload
script. The full code is below, but we'll be explaining each file individually in the following
sections.
```fiddle docs/fiddles/ipc/pattern-3
```
### 1. Send messages with the `webContents` module
For this demo, we'll need to first build a custom menu in the main process using Electron's `Menu`
module that uses the `webContents.send` API to send an IPC message from the main process to the
target renderer.
```javascript {11-26} title='main.js (Main Process)'
const {app, BrowserWindow, Menu} = require('electron')
const path = require('path')
function createWindow () {
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
const menu = Menu.buildFromTemplate([
{
label: app.name,
submenu: [
{
click: () => mainWindow.webContents.send('update-counter', 1),
label: 'Increment',
},
{
click: () => mainWindow.webContents.send('update-counter', -1),
label: 'Decrement',
}
]
}
])
Menu.setApplicationMenu(menu)
mainWindow.loadFile('index.html')
}
//...
```
For the purposes of the tutorial, it's important to note that the `click` handler
sends a message (either `1` or `-1`) to the renderer process through the `counter` channel.
```javascript
click: () => mainWindow.webContents.send('update-counter', -1)
```
:::info
Make sure you're loading the `index.html` and `preload.js` entry points for the following steps!
:::
### 2. Expose `ipcRenderer.on` via preload
Like in the previous renderer-to-main example, we use the `contextBridge` and `ipcRenderer`
modules in the preload script to expose IPC functionality to the renderer process:
```javascript title='preload.js (Preload Script)'
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
onUpdateCounter: (callback) => ipcRenderer.on('update-counter', callback)
})
```
After loading the preload script, your renderer process should have access to the
`window.electronAPI.onUpdateCounter()` listener function.
:::caution Security warning
We don't directly expose the whole `ipcRenderer.on` API for [security reasons]. Make sure to
limit the renderer's access to Electron APIs as much as possible.
:::
:::info
In the case of this minimal example, you can call `ipcRenderer.on` directly in the preload script
rather than exposing it over the context bridge.
```javascript title='preload.js (Preload Script)'
const { ipcRenderer } = require('electron')
window.addEventListener('DOMContentLoaded', () => {
const counter = document.getElementById('counter')
ipcRenderer.on('update-counter', (_event, value) => {
const oldValue = Number(counter.innerText)
const newValue = oldValue + value
counter.innerText = newValue
})
})
```
However, this approach has limited flexibility compared to exposing your preload APIs
over the context bridge, since your listener can't directly interact with your renderer code.
:::
### 3. Build the renderer process UI
To tie it all together, we'll create an interface in the loaded HTML file that contains a
`#counter` element that we'll use to display the values:
```html {10} title='index.html'
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Menu Counter</title>
</head>
<body>
Current value: <strong id="counter">0</strong>
<script src="./renderer.js"></script>
</body>
</html>
```
Finally, to make the values update in the HTML document, we'll add a few lines of DOM manipulation
so that the value of the `#counter` element is updated whenever we fire an `update-counter` event.
```javascript title='renderer.js (Renderer Process)'
const counter = document.getElementById('counter')
window.electronAPI.onUpdateCounter((_event, value) => {
const oldValue = Number(counter.innerText)
const newValue = oldValue + value
counter.innerText = newValue
})
```
In the above code, we're passing in a callback to the `window.electronAPI.onUpdateCounter` function
exposed from our preload script. The second `value` parameter corresponds to the `1` or `-1` we
were passing in from the `webContents.send` call from the native menu.
### Optional: returning a reply
There's no equivalent for `ipcRenderer.invoke` for main-to-renderer IPC. Instead, you can
send a reply back to the main process from within the `ipcRenderer.on` callback.
We can demonstrate this with slight modifications to the code from the previous example. In the
renderer process, use the `event` parameter to send a reply back to the main process through the
`counter-value` channel.
```javascript title='renderer.js (Renderer Process)'
const counter = document.getElementById('counter')
window.electronAPI.onUpdateCounter((event, value) => {
const oldValue = Number(counter.innerText)
const newValue = oldValue + value
counter.innerText = newValue
event.reply('counter-value', newValue)
})
```
In the main process, listen for `counter-value` events and handle them appropriately.
```javascript title='main.js (Main Process)'
//...
ipcMain.on('counter-value', (_event, value) => {
console.log(value) // will print value to Node console
})
//...
```
## Pattern 4: Renderer to renderer
There's no direct way to send messages between renderer processes in Electron using the `ipcMain`
and `ipcRenderer` modules. To achieve this, you have two options:
* Use the main process as a message broker between renderers. This would involve sending a message
from one renderer to the main process, which would forward the message to the other renderer.
* Pass a [MessagePort] from the main process to both renderers. This will allow direct communication
between renderers after the initial setup.
## Object serialization
Electron's IPC implementation uses the HTML standard
[Structured Clone Algorithm][sca] to serialize objects passed between processes, meaning that
only certain types of objects can be passed through IPC channels.
In particular, DOM objects (e.g. `Element`, `Location` and `DOMMatrix`), Node.js objects
backed by C++ classes (e.g. `process.env`, some members of `Stream`), and Electron objects
backed by C++ classes (e.g. `WebContents`, `BrowserWindow` and `WebFrame`) are not serializable
with Structured Clone.
[context isolation tutorial]: context-isolation.md
[security reasons]: ./context-isolation.md#security-considerations
[`ipcMain`]: ../api/ipc-main.md
[`ipcMain.handle`]: ../api/ipc-main.md#ipcmainhandlechannel-listener
[`ipcMain.on`]: ../api/ipc-main.md
[IpcMainEvent]: ../api/structures/ipc-main-event.md
[`ipcRenderer`]: ../api/ipc-renderer.md
[`ipcRenderer.invoke`]: ../api/ipc-renderer.md#ipcrendererinvokechannel-args
[`ipcRenderer.send`]: ../api/ipc-renderer.md
[MessagePort]: ./message-ports.md
[preload script]: process-model.md#preload-scripts
[process model docs]: process-model.md
[sca]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
[`WebContents`]: ../api/web-contents.md
[webcontents-send]: ../api/web-contents.md#contentssendchannel-args

View File

@@ -1,11 +1,11 @@
---
title: Launching Your Electron App From a URL In Another App
description: This guide will take you through the process of setting your electron app as the default handler for a specific protocol.
title: Deep Links
description: Set your Electron app as the default handler for a specific protocol.
slug: launch-app-from-url-in-another-app
hide_title: true
---
# Launching Your Electron App From A URL In Another App
# Deep Links
## Overview

View File

@@ -1,4 +1,11 @@
# Desktop Launcher Actions (Linux)
---
title: Desktop Launcher Actions
description: Add actions to the system launcher on Linux environments.
slug: linux-desktop-actions
hide_title: true
---
# Desktop Launcher Actions
## Overview
@@ -42,4 +49,4 @@ parameters. You can find them in your application in the global variable
[unity-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher
[audacious-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles?action=AttachFile&do=get&target=shortcuts.png
[spec]: https://specifications.freedesktop.org/desktop-entry-spec/1.1/ar01s11.html
[spec]: https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html

View File

@@ -1,4 +1,11 @@
# Dock (macOS)
---
title: Dock
description: Configure your application's Dock presence on macOS.
slug: macos-dock
hide_title: true
---
# Dock
Electron has APIs to configure the app's icon in the macOS Dock. A macOS-only
API exists to create a custom dock menu, but Electron also uses the app dock
@@ -16,12 +23,6 @@ To set your custom dock menu, you need to use the
[`app.dock.setMenu`](../api/dock.md#docksetmenumenu-macos) API,
which is only available on macOS.
## Example
Starting with a working application from the
[Quick Start Guide](quick-start.md), update the `main.js` file with the
following lines:
```javascript fiddle='docs/fiddles/features/macos-dock-menu'
const { app, BrowserWindow, Menu } = require('electron')

View File

@@ -146,7 +146,7 @@ desktop environment that follows [Desktop Notifications
Specification][notification-spec], including Cinnamon, Enlightenment, Unity,
GNOME, KDE.
[notification-spec]: https://developer.gnome.org/notification-spec/
[notification-spec]: https://developer-old.gnome.org/notification-spec/
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx
[set-app-user-model-id]: ../api/app.md#appsetappusermodelidid-windows
[squirrel-events]: https://github.com/electron/windows-installer/blob/master/README.md#handling-squirrel-events

View File

@@ -1,3 +1,11 @@
---
title: Performance
description: A set of guidelines for building performant Electron apps
slug: performance
hide_title: true
toc_max_heading_level: 3
---
# Performance
Developers frequently ask about strategies to optimize the performance of
@@ -49,7 +57,7 @@ at once, consider the [Chrome Tracing](https://www.chromium.org/developers/how-t
* [Get Started With Analyzing Runtime Performance][chrome-devtools-tutorial]
* [Talk: "Visual Studio Code - The First Second"][vscode-first-second]
## Checklist
## Checklist: Performance recommendations
Chances are that your app could be a little leaner, faster, and generally less
resource-hungry if you attempt these steps.
@@ -62,7 +70,7 @@ resource-hungry if you attempt these steps.
6. [Unnecessary or blocking network requests](#6-unnecessary-or-blocking-network-requests)
7. [Bundle your code](#7-bundle-your-code)
## 1) Carelessly including modules
### 1. Carelessly including modules
Before adding a Node.js module to your application, examine said module. How
many dependencies does that module include? What kind of resources does
@@ -70,7 +78,7 @@ it need to simply be called in a `require()` statement? You might find
that the module with the most downloads on the NPM package registry or the most stars on GitHub
is not in fact the leanest or smallest one available.
### Why?
#### Why?
The reasoning behind this recommendation is best illustrated with a real-world
example. During the early days of Electron, reliable detection of network
@@ -99,7 +107,7 @@ running Linux might be bad news for your app's performance. In this particular
example, the correct solution was to use no module at all, and to instead use
connectivity checks included in later versions of Chromium.
### How?
#### How?
When considering a module, we recommend that you check:
@@ -128,7 +136,7 @@ In this example, on the author's machine, we saw that loading `request` took
almost half a second, whereas `node-fetch` took dramatically less memory
and less than 50ms.
## 2) Loading and running code too soon
### 2. Loading and running code too soon
If you have expensive setup operations, consider deferring those. Inspect all
the work being executed right after the application starts. Instead of firing
@@ -141,7 +149,7 @@ using the same strategy _and_ are using sizable modules that you do not
immediately need, apply the same strategy and defer loading to a more
opportune time.
### Why?
#### Why?
Loading modules is a surprisingly expensive operation, especially on Windows.
When your app starts, it should not make users wait for operations that are
@@ -157,14 +165,14 @@ immediately display the file to you without any code highlighting, prioritizing
your ability to interact with the text. Once it has done that work, it will
move on to code highlighting.
### How?
#### How?
Let's consider an example and assume that your application is parsing files
in the fictitious `.foo` format. In order to do that, it relies on the
equally fictitious `foo-parser` module. In traditional Node.js development,
you might write code that eagerly loads dependencies:
```js
```js title='parser.js'
const fs = require('fs')
const fooParser = require('foo-parser')
@@ -187,7 +195,7 @@ In the above example, we're doing a lot of work that's being executed as soon
as the file is loaded. Do we need to get parsed files right away? Could we
do this work a little later, when `getParsedFiles()` is actually called?
```js
```js title='parser.js'
// "fs" is likely already being loaded, so the `require()` call is cheap
const fs = require('fs')
@@ -223,7 +231,7 @@ module.exports = { parser }
In short, allocate resources "just in time" rather than allocating them all
when your app starts.
## 3) Blocking the main process
### 3. Blocking the main process
Electron's main process (sometimes called "browser process") is special: It is
the parent process to all your app's other processes and the primary process
@@ -235,7 +243,7 @@ Under no circumstances should you block this process and the UI thread with
long-running operations. Blocking the UI thread means that your entire app
will freeze until the main process is ready to continue processing.
### Why?
#### Why?
The main process and its UI thread are essentially the control tower for major
operations inside your app. When the operating system tells your app about a
@@ -246,31 +254,31 @@ the GPU process about that once again going through the main process.
Electron and Chromium are careful to put heavy disk I/O and CPU-bound operations
onto new threads to avoid blocking the UI thread. You should do the same.
### How?
#### How?
Electron's powerful multi-process architecture stands ready to assist you with
your long-running tasks, but also includes a small number of performance traps.
1) For long running CPU-heavy tasks, make use of
1. For long running CPU-heavy tasks, make use of
[worker threads][worker-threads], consider moving them to the BrowserWindow, or
(as a last resort) spawn a dedicated process.
2) Avoid using the synchronous IPC and the `remote` module as much as possible.
While there are legitimate use cases, it is far too easy to unknowingly block
the UI thread using the `remote` module.
2. Avoid using the synchronous IPC and the `@electron/remote` module as much
as possible. While there are legitimate use cases, it is far too easy to
unknowingly block the UI thread.
3) Avoid using blocking I/O operations in the main process. In short, whenever
3. Avoid using blocking I/O operations in the main process. In short, whenever
core Node.js modules (like `fs` or `child_process`) offer a synchronous or an
asynchronous version, you should prefer the asynchronous and non-blocking
variant.
## 4) Blocking the renderer process
### 4. Blocking the renderer process
Since Electron ships with a current version of Chrome, you can make use of the
latest and greatest features the Web Platform offers to defer or offload heavy
operations in a way that keeps your app smooth and responsive.
### Why?
#### Why?
Your app probably has a lot of JavaScript to run in the renderer process. The
trick is to execute operations as quickly as possible without taking away
@@ -280,7 +288,7 @@ at 60fps.
Orchestrating the flow of operations in your renderer's code is
particularly useful if users complain about your app sometimes "stuttering".
### How?
#### How?
Generally speaking, all advice for building performant web apps for modern
browsers apply to Electron's renderers, too. The two primary tools at your
@@ -300,14 +308,14 @@ some caveats to consider  consult Electron's
for any operation that requires a lot of CPU power for an extended period of
time.
## 5) Unnecessary polyfills
### 5. Unnecessary polyfills
One of Electron's great benefits is that you know exactly which engine will
parse your JavaScript, HTML, and CSS. If you're re-purposing code that was
written for the web at large, make sure to not polyfill features included in
Electron.
### Why?
#### Why?
When building a web application for today's Internet, the oldest environments
dictate what features you can and cannot use. Even though Electron supports
@@ -323,7 +331,7 @@ It is rare for a JavaScript-based polyfill to be faster than the equivalent
native feature in Electron. Do not slow down your Electron app by shipping your
own version of standard web platform features.
### How?
#### How?
Operate under the assumption that polyfills in current versions of Electron
are unnecessary. If you have doubts, check [caniuse.com](https://caniuse.com/)
@@ -338,12 +346,12 @@ If you're using a transpiler/compiler like TypeScript, examine its configuration
and ensure that you're targeting the latest ECMAScript version supported by
Electron.
## 6) Unnecessary or blocking network requests
### 6. Unnecessary or blocking network requests
Avoid fetching rarely changing resources from the internet if they could easily
be bundled with your application.
### Why?
#### Why?
Many users of Electron start with an entirely web-based app that they're
turning into a desktop application. As web developers, we are used to loading
@@ -360,7 +368,7 @@ will take care of the rest.
When building an Electron app, your users are better served if you download
the fonts and include them in your app's bundle.
### How?
#### How?
In an ideal world, your application wouldn't need the network to operate at
all. To get there, you must understand what resources your app is downloading
@@ -387,21 +395,21 @@ without shipping an application update is a powerful strategy. For advanced
control over how resources are being loaded, consider investing in
[Service Workers][service-workers].
## 7) Bundle your code
### 7. Bundle your code
As already pointed out in
"[Loading and running code too soon](#2-loading-and-running-code-too-soon)",
calling `require()` is an expensive operation. If you are able to do so,
bundle your application's code into a single file.
### Why?
#### Why?
Modern JavaScript development usually involves many files and modules. While
that's perfectly fine for developing with Electron, we heavily recommend that
you bundle all your code into one single file to ensure that the overhead
included in calling `require()` is only paid once when your application loads.
### How?
#### How?
There are numerous JavaScript bundlers out there and we know better than to
anger the community by recommending one tool over another. We do however

View File

@@ -1,4 +1,11 @@
# Taskbar Progress Bar (Windows & macOS)
---
title: Progress Bars
description: Provide progress information to users outside of a BrowserWindow.
slug: progress-bar
hide_title: true
---
# Progress Bars
## Overview

View File

@@ -463,46 +463,46 @@ The fastest way to distribute your newly created app is using
1. Add Electron Forge as a development dependency of your app, and use its `import` command to set up
Forge's scaffolding:
```sh npm2yarn
npm install --save-dev @electron-forge/cli
npx electron-forge import
```sh npm2yarn
npm install --save-dev @electron-forge/cli
npx electron-forge import
✔ Checking your system
✔ Initializing Git Repository
✔ Writing modified package.json file
✔ Installing dependencies
✔ Writing modified package.json file
✔ Fixing .gitignore
✔ Checking your system
✔ Initializing Git Repository
✔ Writing modified package.json file
✔ Installing dependencies
✔ Writing modified package.json file
✔ Fixing .gitignore
We have ATTEMPTED to convert your app to be in a format that electron-forge understands.
We have ATTEMPTED to convert your app to be in a format that electron-forge understands.
Thanks for using "electron-forge"!!!
```
Thanks for using "electron-forge"!!!
```
1. Create a distributable using Forge's `make` command:
2. Create a distributable using Forge's `make` command:
```sh npm2yarn
npm run make
```sh npm2yarn
npm run make
> my-electron-app@1.0.0 make /my-electron-app
> electron-forge make
> my-electron-app@1.0.0 make /my-electron-app
> electron-forge make
✔ Checking your system
✔ Resolving Forge Config
We need to package your application before we can make it
✔ Preparing to Package Application for arch: x64
✔ Preparing native dependencies
✔ Packaging Application
Making for the following targets: zip
✔ Making for target: zip - On platform: darwin - For arch: x64
```
✔ Checking your system
✔ Resolving Forge Config
We need to package your application before we can make it
✔ Preparing to Package Application for arch: x64
✔ Preparing native dependencies
✔ Packaging Application
Making for the following targets: zip
✔ Making for target: zip - On platform: darwin - For arch: x64
```
Electron Forge creates the `out` folder where your package will be located:
Electron Forge creates the `out` folder where your package will be located:
```plain
// Example for macOS
out/
├── out/make/zip/darwin/x64/my-electron-app-darwin-x64-1.0.0.zip
├── ...
└── out/my-electron-app-darwin-x64/my-electron-app.app/Contents/MacOS/my-electron-app
```
```plain
// Example for macOS
out/
├── out/make/zip/darwin/x64/my-electron-app-darwin-x64-1.0.0.zip
├── ...
└── out/my-electron-app-darwin-x64/my-electron-app.app/Contents/MacOS/my-electron-app
```

View File

@@ -1,4 +1,11 @@
# Recent Documents (Windows & macOS)
---
title: Recent Documents
description: Provide a list of recent documents via Windows JumpList or macOS Dock
slug: recent-documents
hide_title: true
---
# Recent Documents
## Overview

View File

@@ -1,4 +1,11 @@
# Representing Files in a BrowserWindow (macOS)
---
title: Representing Files in a BrowserWindow
description: Set a represented file in the macOS title bar.
slug: represented-file
hide_title: true
---
# Representing Files in a BrowserWindow
## Overview

View File

@@ -1,6 +1,24 @@
# Security, Native Capabilities, and Your Responsibility
---
title: Security
description: A set of guidelines for building secure Electron apps
slug: security
hide_title: true
toc_max_heading_level: 3
---
# Security
As web developers, we usually enjoy the strong security net of the browser -
:::info Reporting security issues
For information on how to properly disclose an Electron vulnerability,
see [SECURITY.md](https://github.com/electron/electron/tree/main/SECURITY.md).
For upstream Chromium vulnerabilities: Electron keeps up to date with alternating
Chromium releases. For more information, see the
[Electron Release Timelines](../tutorial/electron-timelines.md) document.
:::
## Preface
As web developers, we usually enjoy the strong security net of the browser —
the risks associated with the code we write are relatively small. Our websites
are granted limited powers in a sandbox, and we trust that our users enjoy a
browser built by a large team of engineers that is able to quickly respond to
@@ -17,20 +35,12 @@ With that in mind, be aware that displaying arbitrary content from untrusted
sources poses a severe security risk that Electron is not intended to handle.
In fact, the most popular Electron apps (Atom, Slack, Visual Studio Code, etc)
display primarily local content (or trusted, secure remote content without Node
integration) if your application executes code from an online source, it is
integration) if your application executes code from an online source, it is
your responsibility to ensure that the code is not malicious.
## Reporting Security Issues
## General guidelines
For information on how to properly disclose an Electron vulnerability,
see [SECURITY.md](https://github.com/electron/electron/tree/main/SECURITY.md)
## Chromium Security Issues and Upgrades
Electron keeps up to date with alternating Chromium releases. For more information,
see the [Electron Release Cadence blog post](https://electronjs.org/blog/12-week-cadence).
## Security Is Everyone's Responsibility
### Security is everyone's responsibility
It is important to remember that the security of your Electron application is
the result of the overall security of the framework foundation
@@ -56,7 +66,7 @@ is your own code. Common web vulnerabilities, such as Cross-Site Scripting (XSS)
have a higher security impact on Electron applications hence it is highly recommended
to adopt secure software development best practices and perform security testing.
## Isolation For Untrusted Content
### Isolation for untrusted content
A security issue exists whenever you receive code from an untrusted source (e.g.
a remote server) and execute it locally. As an example, consider a remote
@@ -65,72 +75,74 @@ an attacker somehow manages to change said content (either by attacking the
source directly, or by sitting between your app and the actual destination), they
will be able to execute native code on the user's machine.
> :warning: Under no circumstances should you load and execute remote code with
:::warning
Under no circumstances should you load and execute remote code with
Node.js integration enabled. Instead, use only local files (packaged together
with your application) to execute Node.js code. To display remote content, use
the [`<webview>`][webview-tag] tag or [`BrowserView`][browser-view], make sure
to disable the `nodeIntegration` and enable `contextIsolation`.
:::
## Electron Security Warnings
From Electron 2.0 on, developers will see warnings and recommendations printed
to the developer console. They only show up when the binary's name is Electron,
indicating that a developer is currently looking at the console.
:::info Electron security warnings
Security warnings and recommendations are printed to the developer console.
They only show up when the binary's name is Electron, indicating that a developer
is currently looking at the console.
You can force-enable or force-disable these warnings by setting
`ELECTRON_ENABLE_SECURITY_WARNINGS` or `ELECTRON_DISABLE_SECURITY_WARNINGS` on
either `process.env` or the `window` object.
:::
## Checklist: Security Recommendations
## Checklist: Security recommendations
You should at least follow these steps to improve the security of your application:
1. [Only load secure content](#1-only-load-secure-content)
2. [Disable the Node.js integration in all renderers that display remote content](#2-do-not-enable-nodejs-integration-for-remote-content)
3. [Enable context isolation in all renderers that display remote content](#3-enable-context-isolation-for-remote-content)
4. [Enable sandboxing](#4-enable-sandboxing)
4. [Enable process sandboxing](#4-enable-process-sandboxing)
5. [Use `ses.setPermissionRequestHandler()` in all sessions that load remote content](#5-handle-session-permission-requests-from-remote-content)
6. [Do not disable `webSecurity`](#6-do-not-disable-websecurity)
7. [Define a `Content-Security-Policy`](#7-define-a-content-security-policy) and use restrictive rules (i.e. `script-src 'self'`)
8. [Do not set `allowRunningInsecureContent` to `true`](#8-do-not-set-allowrunninginsecurecontent-to-true)
8. [Do not enable `allowRunningInsecureContent`](#8-do-not-enable-allowrunninginsecurecontent)
9. [Do not enable experimental features](#9-do-not-enable-experimental-features)
10. [Do not use `enableBlinkFeatures`](#10-do-not-use-enableblinkfeatures)
11. [`<webview>`: Do not use `allowpopups`](#11-do-not-use-allowpopups)
11. [`<webview>`: Do not use `allowpopups`](#11-do-not-use-allowpopups-for-webviews)
12. [`<webview>`: Verify options and params](#12-verify-webview-options-before-creation)
13. [Disable or limit navigation](#13-disable-or-limit-navigation)
14. [Disable or limit creation of new windows](#14-disable-or-limit-creation-of-new-windows)
15. [Do not use `openExternal` with untrusted content](#15-do-not-use-openexternal-with-untrusted-content)
15. [Do not use `shell.openExternal` with untrusted content](#15-do-not-use-shellopenexternal-with-untrusted-content)
16. [Use a current version of Electron](#16-use-a-current-version-of-electron)
To automate the detection of misconfigurations and insecure patterns, it is
possible to use
[electronegativity](https://github.com/doyensec/electronegativity). For
[Electronegativity](https://github.com/doyensec/electronegativity). For
additional details on potential weaknesses and implementation bugs when
developing applications using Electron, please refer to this [guide for
developers and auditors](https://doyensec.com/resources/us-17-Carettoni-Electronegativity-A-Study-Of-Electron-Security-wp.pdf)
developers and auditors](https://doyensec.com/resources/us-17-Carettoni-Electronegativity-A-Study-Of-Electron-Security-wp.pdf).
## 1) Only Load Secure Content
### 1. Only load secure content
Any resources not included with your application should be loaded using a
secure protocol like `HTTPS`. In other words, do not use insecure protocols
like `HTTP`. Similarly, we recommend the use of `WSS` over `WS`, `FTPS` over
`FTP`, and so on.
### Why?
#### Why?
`HTTPS` has three main benefits:
1) It authenticates the remote server, ensuring your app connects to the correct
1. It authenticates the remote server, ensuring your app connects to the correct
host instead of an impersonator.
2) It ensures data integrity, asserting that the data was not modified while in
1. It ensures data integrity, asserting that the data was not modified while in
transit between your application and the host.
3) It encrypts the traffic between your user and the destination host, making it
1. It encrypts the traffic between your user and the destination host, making it
more difficult to eavesdrop on the information sent between your app and
the host.
### How?
#### How?
```js
```js title='main.js (Main Process)'
// Bad
browserWindow.loadURL('http://example.com')
@@ -138,7 +150,7 @@ browserWindow.loadURL('http://example.com')
browserWindow.loadURL('https://example.com')
```
```html
```html title='index.html (Renderer Process)'
<!-- Bad -->
<script crossorigin src="http://example.com/react.js"></script>
<link rel="stylesheet" href="http://example.com/style.css">
@@ -148,9 +160,11 @@ browserWindow.loadURL('https://example.com')
<link rel="stylesheet" href="https://example.com/style.css">
```
## 2) Do not enable Node.js Integration for Remote Content
### 2. Do not enable Node.js integration for remote content
_This recommendation is the default behavior in Electron since 5.0.0._
:::info
This recommendation is the default behavior in Electron since 5.0.0.
:::
It is paramount that you do not enable Node.js integration in any renderer
([`BrowserWindow`][browser-window], [`BrowserView`][browser-view], or
@@ -163,7 +177,7 @@ After this, you can grant additional permissions for specific hosts. For example
if you are opening a BrowserWindow pointed at `https://example.com/`, you can
give that website exactly the abilities it needs, but no more.
### Why?
#### Why?
A cross-site-scripting (XSS) attack is more dangerous if an attacker can jump
out of the renderer process and execute code on the user's computer.
@@ -172,12 +186,13 @@ power is usually limited to messing with the website that they are executed on.
Disabling Node.js integration helps prevent an XSS from being escalated into a
so-called "Remote Code Execution" (RCE) attack.
### How?
#### How?
```js
```js title='main.js (Main Process)'
// Bad
const mainWindow = new BrowserWindow({
webPreferences: {
contextIsolation: false,
nodeIntegration: true,
nodeIntegrationInWorker: true
}
@@ -186,7 +201,7 @@ const mainWindow = new BrowserWindow({
mainWindow.loadURL('https://example.com')
```
```js
```js title='main.js (Main Process)'
// Good
const mainWindow = new BrowserWindow({
webPreferences: {
@@ -197,7 +212,7 @@ const mainWindow = new BrowserWindow({
mainWindow.loadURL('https://example.com')
```
```html
```html title='index.html (Renderer Process)'
<!-- Bad -->
<webview nodeIntegration src="page.html"></webview>
@@ -208,21 +223,13 @@ mainWindow.loadURL('https://example.com')
When disabling Node.js integration, you can still expose APIs to your website that
do consume Node.js modules or features. Preload scripts continue to have access
to `require` and other Node.js features, allowing developers to expose a custom
API to remotely loaded content.
API to remotely loaded content via the [contextBridge API](../api/context-bridge.md).
In the following example preload script, the later loaded website will have
access to a `window.readConfig()` method, but no Node.js features.
### 3. Enable Context Isolation for remote content
```js
const { readFileSync } = require('fs')
window.readConfig = () => {
const data = readFileSync('./config.json')
return data
}
```
## 3) Enable Context Isolation for Remote Content
:::info
This recommendation is the default behavior in Electron since 12.0.0.
:::
Context isolation is an Electron feature that allows developers to run code
in preload scripts and in Electron APIs in a dedicated JavaScript context. In
@@ -235,48 +242,42 @@ to enable this behavior.
Even when `nodeIntegration: false` is used, to truly enforce strong isolation
and prevent the use of Node primitives `contextIsolation` **must** also be used.
### Why & How?
:::info
For more information on what `contextIsolation` is and how to enable it please
see our dedicated [Context Isolation](context-isolation.md) document.
:::info
## 4) Enable Sandboxing
### 4. Enable process sandboxing
[Sandboxing](sandbox.md) is a Chromium feature that uses the operating system to
[Sandboxing](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/design/sandbox.md)
is a Chromium feature that uses the operating system to
significantly limit what renderer processes have access to. You should enable
the sandbox in all renderers. Loading, reading or processing any untrusted
content in an unsandboxed process, including the main process, is not advised.
### How?
:::info
For more information on what `contextIsolation` is and how to enable it please
see our dedicated [Process Sandboxing](sandbox.md) document.
:::info
When creating a window, pass the `sandbox: true` option in `webPreferences`:
### 5. Handle session permission requests from remote content
```js
const win = new BrowserWindow({
webPreferences: {
sandbox: true
}
})
```
## 5) Handle Session Permission Requests From Remote Content
You may have seen permission requests while using Chrome: They pop up whenever
You may have seen permission requests while using Chrome: they pop up whenever
the website attempts to use a feature that the user has to manually approve (
like notifications).
The API is based on the [Chromium permissions API](https://developer.chrome.com/extensions/permissions)
and implements the same types of permissions.
### Why?
#### Why?
By default, Electron will automatically approve all permission requests unless
the developer has manually configured a custom handler. While a solid default,
security-conscious developers might want to assume the very opposite.
### How?
#### How?
```js
```js title='main.js (Main Process)'
const { session } = require('electron')
session
@@ -297,9 +298,11 @@ session
})
```
## 6) Do Not Disable WebSecurity
### 6. Do not disable `webSecurity`
_Recommendation is Electron's default_
:::info
This recommendation is Electron's default.
:::
You may have already guessed that disabling the `webSecurity` property on a
renderer process ([`BrowserWindow`][browser-window],
@@ -308,15 +311,15 @@ security features.
Do not disable `webSecurity` in production applications.
### Why?
#### Why?
Disabling `webSecurity` will disable the same-origin policy and set
`allowRunningInsecureContent` property to `true`. In other words, it allows
the execution of insecure code from different domains.
### How?
#### How?
```js
```js title='main.js (Main Process)'
// Bad
const mainWindow = new BrowserWindow({
webPreferences: {
@@ -325,12 +328,12 @@ const mainWindow = new BrowserWindow({
})
```
```js
```js title='main.js (Main Process)'
// Good
const mainWindow = new BrowserWindow()
```
```html
```html title='index.html (Renderer Process)'
<!-- Bad -->
<webview disablewebsecurity src="page.html"></webview>
@@ -338,13 +341,13 @@ const mainWindow = new BrowserWindow()
<webview src="page.html"></webview>
```
## 7) Define a Content Security Policy
### 7. Define a Content Security Policy
A Content Security Policy (CSP) is an additional layer of protection against
cross-site-scripting attacks and data injection attacks. We recommend that they
be enabled by any website you load inside Electron.
### Why?
#### Why?
CSP allows the server serving content to restrict and control the resources
Electron can load for that given web page. `https://example.com` should
@@ -352,6 +355,8 @@ be allowed to load scripts from the origins you defined while scripts from
`https://evil.attacker.com` should not be allowed to run. Defining a CSP is an
easy way to improve your application's security.
#### How?
The following CSP will allow Electron to execute scripts from the current
website and from `apis.example.com`.
@@ -363,14 +368,14 @@ Content-Security-Policy: '*'
Content-Security-Policy: script-src 'self' https://apis.example.com
```
### CSP HTTP Header
#### CSP HTTP headers
Electron respects the [`Content-Security-Policy` HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)
which can be set using Electron's
[`webRequest.onHeadersReceived`](../api/web-request.md#webrequestonheadersreceivedfilter-listener)
handler:
```javascript
```javascript title='main.js (Main Process)'
const { session } = require('electron')
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
@@ -383,20 +388,22 @@ session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
})
```
### CSP Meta Tag
#### CSP meta tag
CSP's preferred delivery mechanism is an HTTP header, however it is not possible
CSP's preferred delivery mechanism is an HTTP header. However, it is not possible
to use this method when loading a resource using the `file://` protocol. It can
be useful in some cases, such as using the `file://` protocol, to set a policy
on a page directly in the markup using a `<meta>` tag:
be useful in some cases to set a policy on a page directly in the markup using a
`<meta>` tag:
```html
```html title='index.html (Renderer Process)'
<meta http-equiv="Content-Security-Policy" content="default-src 'none'">
```
## 8) Do Not Set `allowRunningInsecureContent` to `true`
### 8. Do not enable `allowRunningInsecureContent`
_Recommendation is Electron's default_
:::info
This recommendation is Electron's default.
:::
By default, Electron will not allow websites loaded over `HTTPS` to load and
execute scripts, CSS, or plugins from insecure sources (`HTTP`). Setting the
@@ -405,15 +412,15 @@ property `allowRunningInsecureContent` to `true` disables that protection.
Loading the initial HTML of a website over `HTTPS` and attempting to load
subsequent resources via `HTTP` is also known as "mixed content".
### Why?
#### Why?
Loading content over `HTTPS` assures the authenticity and integrity
of the loaded resources while encrypting the traffic itself. See the section on
[only displaying secure content](#1-only-load-secure-content) for more details.
### How?
#### How?
```js
```js title='main.js (Main Process)'
// Bad
const mainWindow = new BrowserWindow({
webPreferences: {
@@ -422,19 +429,21 @@ const mainWindow = new BrowserWindow({
})
```
```js
```js title='main.js (Main Process)'
// Good
const mainWindow = new BrowserWindow({})
```
## 9) Do Not Enable Experimental Features
### 9. Do not enable experimental features
_Recommendation is Electron's default_
:::info
This recommendation is Electron's default.
:::
Advanced users of Electron can enable experimental Chromium features using the
`experimentalFeatures` property.
### Why?
#### Why?
Experimental features are, as the name suggests, experimental and have not been
enabled for all Chromium users. Furthermore, their impact on Electron as a whole
@@ -443,9 +452,9 @@ has likely not been tested.
Legitimate use cases exist, but unless you know what you are doing, you should
not enable this property.
### How?
#### How?
```js
```js title='main.js (Main Process)'
// Bad
const mainWindow = new BrowserWindow({
webPreferences: {
@@ -454,20 +463,22 @@ const mainWindow = new BrowserWindow({
})
```
```js
```js title='main.js (Main Process)'
// Good
const mainWindow = new BrowserWindow({})
```
## 10) Do Not Use `enableBlinkFeatures`
### 10. Do not use `enableBlinkFeatures`
_Recommendation is Electron's default_
:::info
This recommendation is Electron's default.
:::
Blink is the name of the rendering engine behind Chromium. As with
`experimentalFeatures`, the `enableBlinkFeatures` property allows developers to
enable features that have been disabled by default.
### Why?
#### Why?
Generally speaking, there are likely good reasons if a feature was not enabled
by default. Legitimate use cases for enabling specific features exist. As a
@@ -475,9 +486,9 @@ developer, you should know exactly why you need to enable a feature, what the
ramifications are, and how it impacts the security of your application. Under
no circumstances should you enable features speculatively.
### How?
#### How?
```js
```js title='main.js (Main Process)'
// Bad
const mainWindow = new BrowserWindow({
webPreferences: {
@@ -486,14 +497,16 @@ const mainWindow = new BrowserWindow({
})
```
```js
```js title='main.js (Main Process)'
// Good
const mainWindow = new BrowserWindow()
```
## 11) Do Not Use `allowpopups`
### 11. Do not use `allowpopups` for WebViews
_Recommendation is Electron's default_
:::info
This recommendation is Electron's default.
:::
If you are using [`<webview>`][webview-tag], you might need the pages and scripts
loaded in your `<webview>` tag to open new windows. The `allowpopups` attribute
@@ -501,16 +514,16 @@ enables them to create new [`BrowserWindows`][browser-window] using the
`window.open()` method. `<webview>` tags are otherwise not allowed to create new
windows.
### Why?
#### Why?
If you do not need popups, you are better off not allowing the creation of
new [`BrowserWindows`][browser-window] by default. This follows the principle
of minimally required access: Don't let a website create new popups unless
you know it needs that feature.
### How?
#### How?
```html
```html title='index.html (Renderer Process)'
<!-- Bad -->
<webview allowpopups src="page.html"></webview>
@@ -518,7 +531,7 @@ you know it needs that feature.
<webview src="page.html"></webview>
```
## 12) Verify WebView Options Before Creation
### 12. Verify WebView options before creation
A WebView created in a renderer process that does not have Node.js integration
enabled will not be able to enable integration itself. However, a WebView will
@@ -528,7 +541,7 @@ It is a good idea to control the creation of new [`<webview>`][webview-tag] tags
from the main process and to verify that their webPreferences do not disable
security features.
### Why?
#### Why?
Since `<webview>` live in the DOM, they can be created by a script running on your
website even if Node.js integration is otherwise disabled.
@@ -538,13 +551,13 @@ a renderer process. In most cases, developers do not need to disable any of
those features - and you should therefore not allow different configurations
for newly created [`<webview>`][webview-tag] tags.
### How?
#### How?
Before a [`<webview>`][webview-tag] tag is attached, Electron will fire the
`will-attach-webview` event on the hosting `webContents`. Use the event to
prevent the creation of `webViews` with possibly insecure options.
```js
```js title='main.js (Main Process)'
app.on('web-contents-created', (event, contents) => {
contents.on('will-attach-webview', (event, webPreferences, params) => {
// Strip away preload scripts if unused or verify their location is legitimate
@@ -562,16 +575,16 @@ app.on('web-contents-created', (event, contents) => {
})
```
Again, this list merely minimizes the risk, it does not remove it. If your goal
Again, this list merely minimizes the risk, but does not remove it. If your goal
is to display a website, a browser will be a more secure option.
## 13) Disable or limit navigation
### 13. Disable or limit navigation
If your app has no need to navigate or only needs to navigate to known pages,
it is a good idea to limit navigation outright to that known scope, disallowing
any other kinds of navigation.
### Why?
#### Why?
Navigation is a common attack vector. If an attacker can convince your app to
navigate away from its current page, they can possibly force your app to open
@@ -584,7 +597,7 @@ A common attack pattern is that the attacker convinces your app's users to
interact with the app in such a way that it navigates to one of the attacker's
pages. This is usually done via links, plugins, or other user-generated content.
### How?
#### How?
If your app has no need for navigation, you can call `event.preventDefault()`
in a [`will-navigate`][will-navigate] handler. If you know which pages your app
@@ -595,7 +608,7 @@ We recommend that you use Node's parser for URLs. Simple string comparisons can
sometimes be fooled - a `startsWith('https://example.com')` test would let
`https://example.com.attacker.com` through.
```js
```js title='main.js (Main Process)'
const URL = require('url').URL
app.on('web-contents-created', (event, contents) => {
@@ -609,12 +622,12 @@ app.on('web-contents-created', (event, contents) => {
})
```
## 14) Disable or limit creation of new windows
### 14. Disable or limit creation of new windows
If you have a known set of windows, it's a good idea to limit the creation of
additional windows in your app.
### Why?
#### Why?
Much like navigation, the creation of new `webContents` is a common attack
vector. Attackers attempt to convince your app to create new windows, frames,
@@ -627,7 +640,7 @@ security at no cost. This is commonly the case for apps that open one
`BrowserWindow` and do not need to open an arbitrary number of additional
windows at runtime.
### How?
#### How?
[`webContents`][web-contents] will delegate to its [window open
handler][window-open-handler] before creating new windows. The handler will
@@ -635,7 +648,7 @@ receive, amongst other parameters, the `url` the window was requested to open
and the options used to create it. We recommend that you register a handler to
monitor the creation of windows, and deny any unexpected window creation.
```js
```js title='main.js (Main Process)'
const { shell } = require('electron')
app.on('web-contents-created', (event, contents) => {
@@ -656,40 +669,40 @@ app.on('web-contents-created', (event, contents) => {
})
```
## 15) Do not use `openExternal` with untrusted content
### 15. Do not use `shell.openExternal` with untrusted content
Shell's [`openExternal`][open-external] allows opening a given protocol URI with
the desktop's native utilities. On macOS, for instance, this function is similar
to the `open` terminal command utility and will open the specific application
based on the URI and filetype association.
The shell module's [`openExternal`][open-external] API allows opening a given
protocol URI with the desktop's native utilities. On macOS, for instance, this
function is similar to the `open` terminal command utility and will open the
specific application based on the URI and filetype association.
### Why?
#### Why?
Improper use of [`openExternal`][open-external] can be leveraged to compromise
the user's host. When openExternal is used with untrusted content, it can be
leveraged to execute arbitrary commands.
### How?
#### How?
```js
```js title='main.js (Main Process)'
// Bad
const { shell } = require('electron')
shell.openExternal(USER_CONTROLLED_DATA_HERE)
```
```js
```js title='main.js (Main Process)'
// Good
const { shell } = require('electron')
shell.openExternal('https://example.com/index.html')
```
## 16) Use a current version of Electron
### 16. Use a current version of Electron
You should strive for always using the latest available version of Electron.
Whenever a new major version is released, you should attempt to update your
app as quickly as possible.
### Why?
#### Why?
An application built with an older version of Electron, Chromium, and Node.js
is an easier target than an application that is using more recent versions of
@@ -705,6 +718,13 @@ to fix issues before publishing them. Your application will be more secure if
it is running a recent version of Electron (and thus, Chromium and Node.js) for
which potential security issues are not as widely known.
#### How?
Migrate your app one major version at a time, while referring to Electron's
[Breaking Changes][breaking-changes] document to see if any code needs to
be updated.
[breaking-changes]: ../breaking-changes.md
[browser-window]: ../api/browser-window.md
[browser-view]: ../api/browser-view.md
[webview-tag]: ../api/webview-tag.md
@@ -712,5 +732,4 @@ which potential security issues are not as widely known.
[window-open-handler]: ../api/web-contents.md#contentssetwindowopenhandlerhandler
[will-navigate]: ../api/web-contents.md#event-will-navigate
[open-external]: ../api/shell.md#shellopenexternalurl-options
[sandbox]: ../tutorial/sandbox.md
[responsible-disclosure]: https://en.wikipedia.org/wiki/Responsible_disclosure

View File

@@ -1,4 +1,11 @@
# Taskbar Customization (Windows)
---
title: Taskbar Customization
description: Customize the look and feel of your app's Windows taskbar presence.
slug: windows-taskbar
hide_title: true
---
# Taskbar Customization
## Overview

View File

@@ -32,10 +32,13 @@ filenames = {
"shell/browser/notifications/linux/notification_presenter_linux.cc",
"shell/browser/notifications/linux/notification_presenter_linux.h",
"shell/browser/relauncher_linux.cc",
"shell/browser/ui/electron_desktop_window_tree_host_linux.cc",
"shell/browser/ui/file_dialog_gtk.cc",
"shell/browser/ui/message_box_gtk.cc",
"shell/browser/ui/tray_icon_gtk.cc",
"shell/browser/ui/tray_icon_gtk.h",
"shell/browser/ui/views/client_frame_view_linux.cc",
"shell/browser/ui/views/client_frame_view_linux.h",
"shell/common/application_info_linux.cc",
"shell/common/language_util_linux.cc",
"shell/common/node_bindings_linux.cc",
@@ -413,6 +416,8 @@ filenames = {
"shell/browser/native_browser_view.h",
"shell/browser/native_window.cc",
"shell/browser/native_window.h",
"shell/browser/native_window_features.cc",
"shell/browser/native_window_features.h",
"shell/browser/native_window_observer.h",
"shell/browser/net/asar/asar_file_validator.cc",
"shell/browser/net/asar/asar_file_validator.h",
@@ -734,11 +739,6 @@ filenames = {
"shell/renderer/extensions/electron_extensions_renderer_client.h",
]
app_sources = [
"shell/app/electron_main.cc",
"shell/app/electron_main.h",
]
framework_sources = [
"shell/app/electron_library_main.h",
"shell/app/electron_library_main.mm",

View File

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

View File

@@ -110,7 +110,8 @@ mas_gate_private_enterprise_APIs.patch
load_v8_snapshot_in_browser_process.patch
fix_patch_out_permissions_checks_in_exclusive_access.patch
fix_aspect_ratio_with_max_size.patch
build_disable_partitionalloc_on_mac.patch
revert_stop_using_nsrunloop_in_renderer_process.patch
fix_dont_delete_SerialPortManager_on_main_thread.patch
fix_crash_when_saving_edited_pdf_files.patch
cherry-pick-f5101995acd2.patch
fix_don_t_restore_maximized_windows_when_calling_showinactive.patch
build_disable_partition_alloc_on_mac.patch

View File

@@ -85,10 +85,10 @@ index 14d4a00293ab0b11e733676844ce483992d6cd8e..c6c2dbb9dddd1eaa21e8c7b276d871a3
// Visibility -----------------------------------------------------------
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 68dfddc7d98a25767d11d6f6082205890c5fae78..d2adf1d956c8cb1598294600ead6f2de71a2df61 100644
index 567ea9b7bd78a229b113ae11849f3e86942c92d6..d525df56c4e33a19431b2980a932956cb1986865 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -3663,6 +3663,13 @@ PageScheduler* WebViewImpl::Scheduler() const {
@@ -3667,6 +3667,13 @@ PageScheduler* WebViewImpl::Scheduler() const {
return GetPage()->GetPageScheduler();
}
@@ -102,7 +102,7 @@ index 68dfddc7d98a25767d11d6f6082205890c5fae78..d2adf1d956c8cb1598294600ead6f2de
void WebViewImpl::SetVisibilityState(
mojom::blink::PageVisibilityState visibility_state,
bool is_initial_state) {
@@ -3674,7 +3681,8 @@ void WebViewImpl::SetVisibilityState(
@@ -3678,7 +3685,8 @@ void WebViewImpl::SetVisibilityState(
}
GetPage()->SetVisibilityState(visibility_state, is_initial_state);
GetPage()->GetPageScheduler()->SetPageVisible(

View File

@@ -0,0 +1,23 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: VerteDinde <vertedinde@electronjs.org>
Date: Tue, 1 Mar 2022 16:02:22 -0800
Subject: build: disable partition alloc on mac
Enabling partition alloc caused a crash when spawning
a child process. This patch disables partition alloc for mac,
and can be removed when the crash in fork is resolved.
Related issue: https://github.com/electron/electron/issues/32718
diff --git a/base/allocator/allocator.gni b/base/allocator/allocator.gni
index 2c35e82ec5ad94840cc894cc55bb90e7c4c00d4f..af34f85f686f61a1d4dc2ee1248af4d0b61e4cb6 100644
--- a/base/allocator/allocator.gni
+++ b/base/allocator/allocator.gni
@@ -18,7 +18,7 @@ _is_using_sanitizers = is_asan || is_hwasan || is_lsan || is_tsan || is_msan
# - Windows: debug CRT is not compatible, see below.
_disable_partition_alloc = is_component_build || (is_win && is_debug)
_is_partition_alloc_platform =
- is_android || is_win || is_mac || is_linux || is_chromeos ||
+ is_android || is_win || is_linux || is_chromeos ||
# TODO(crbug.com/1278780): Allow x64 once compatible with safe-stack.
(is_fuchsia && target_cpu == "arm64")

View File

@@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: clavin <cwatford@slack-corp.com>
Date: Tue, 21 Dec 2021 10:17:37 -0700
Subject: build: disable PartitionAlloc on mac
PartitionAlloc on mac requires some restructuring in Electron as well as considerations about the mas build. In the mean time, disabling it should be fine.
This patch can be removed once the mac app runs safely with PartitionAlloc on (i.e. removing dependency to //base in the main app) & the situation with mas is figured out.
diff --git a/base/allocator/allocator.gni b/base/allocator/allocator.gni
index 7d579d6e2297c047415eeeb641c70871b5c3f80d..e6edb52dd15af0f369160696fb2a34b0f80680a4 100644
--- a/base/allocator/allocator.gni
+++ b/base/allocator/allocator.gni
@@ -18,7 +18,7 @@ _is_using_sanitizers = is_asan || is_hwasan || is_lsan || is_tsan || is_msan
# - Windows: debug CRT is not compatible, see below.
_disable_partition_alloc = is_component_build || (is_win && is_debug)
_is_partition_alloc_platform =
- is_android || is_win || is_mac || is_linux || is_chromeos
+ is_android || is_win || is_linux || is_chromeos
# The debug CRT on Windows has some debug features that are incompatible with
# the shim. NaCl in particular does seem to link some binaries statically

View File

@@ -33,10 +33,10 @@ index 3f9990b36dcd0a1e8956dc3f390ed289b6166024..829fb27d568c4e556182523fa5cd9e69
"//base",
"//build:branding_buildflags",
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 763ad6279b0ca8ab4cc09a48610d63836dc1fa17..eff1169631d686bc878eeb8c86e505a6c547a3a4 100644
index 0982cfa1db7233153af8b2ab7cd1c18dfb4dea49..b0f575de4c9dc6e23da5822a1591d78478aeece8 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4521,7 +4521,7 @@ static_library("browser") {
@@ -4522,7 +4522,7 @@ static_library("browser") {
# On Windows, the hashes are embedded in //chrome:chrome_initial rather
# than here in :chrome_dll.
@@ -46,7 +46,7 @@ index 763ad6279b0ca8ab4cc09a48610d63836dc1fa17..eff1169631d686bc878eeb8c86e505a6
}
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index cf07780786f235b567b754f4f91a4d716bd86778..a575ed30de3991c1c5189a0aad9f63aee9f93374 100644
index 19387561ba18f2f9bf3a6ef42fc32b9adc7ac375..9c6ae050454f6e0c5032f3aea43e4123e06f3ff3 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -5529,7 +5529,6 @@ test("unit_tests") {

View File

@@ -9,10 +9,10 @@ potentially prevent a window from being created.
TODO(loc): this patch is currently broken.
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 948c63986ec11f329a9a77298faacc1a9eb31d40..e6528700d5328a5a301b2c36c5ea25fcddf81143 100644
index 7cb5a62e40953f7cb99ba8225551004649110d9f..6ebceb4b5c47ada6d228ef00825b10fb7326d78c 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -6602,6 +6602,7 @@ void RenderFrameHostImpl::CreateNewWindow(
@@ -6626,6 +6626,7 @@ void RenderFrameHostImpl::CreateNewWindow(
last_committed_origin_, params->window_container_type,
params->target_url, params->referrer.To<Referrer>(),
params->frame_name, params->disposition, *params->features,
@@ -21,10 +21,10 @@ index 948c63986ec11f329a9a77298faacc1a9eb31d40..e6528700d5328a5a301b2c36c5ea25fc
&no_javascript_access);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index a3ff7b5dece60658b5f407a6d88e53e90cb5fb27..6ab76b93f7733d201590389f8e1ff617d7fa3269 100644
index 031ae3493232e571abb96533f379fa0265fa299c..495f2f355984a304e71fe0b2f2fe670bdc8bc833 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3864,6 +3864,14 @@ FrameTree* WebContentsImpl::CreateNewWindow(
@@ -3868,6 +3868,14 @@ FrameTree* WebContentsImpl::CreateNewWindow(
}
auto* new_contents_impl = new_contents.get();
@@ -39,7 +39,7 @@ index a3ff7b5dece60658b5f407a6d88e53e90cb5fb27..6ab76b93f7733d201590389f8e1ff617
new_contents_impl->GetController().SetSessionStorageNamespace(
partition_id, session_storage_namespace);
@@ -3906,12 +3914,6 @@ FrameTree* WebContentsImpl::CreateNewWindow(
@@ -3910,12 +3918,6 @@ FrameTree* WebContentsImpl::CreateNewWindow(
AddWebContentsDestructionObserver(new_contents_impl);
}

View File

@@ -0,0 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jeremy Rose <jeremya@chromium.org>
Date: Wed, 26 Jan 2022 23:39:50 +0000
Subject: fix draggable regions not updating without layout
This fixes draggable regions not being updated when styles change, but there is
no layout as a result of the style change. Some changes to styles can cause a
change in draggable regions without causing a layout (e.g. applying the
`-webkit-app-region: drag` style to an element without changing its size).
Bug: 1051562
Change-Id: Ifdf835be9e6c762131529b4309c6579366b80d6d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3416279
Reviewed-by: Stefan Zager <szager@chromium.org>
Commit-Queue: Jeremy Apthorp <jeremya@chromium.org>
Cr-Commit-Position: refs/heads/main@{#963777}
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index d09106d45ec411bc1cbb89aef8617f2bcd7bdb09..b5b47226898f962c751c9a79fe6741f81d891396 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -1914,8 +1914,6 @@ void LocalFrameView::PerformPostLayoutTasks(bool visual_viewport_size_changed) {
}
}
- UpdateDocumentAnnotatedRegions();
-
GetLayoutView()->EnclosingLayer()->UpdateLayerPositionsAfterLayout();
frame_->Selection().DidLayout();
@@ -3306,6 +3304,7 @@ void LocalFrameView::UpdateStyleAndLayout() {
PerformPostLayoutTasks(visual_viewport_size_changed);
GetFrame().GetDocument()->LayoutUpdated();
}
+ UpdateDocumentAnnotatedRegions();
UpdateGeometriesIfNeeded();
}

View File

@@ -232,10 +232,10 @@ index c1926fc79e9982739d17f4b971f5e7296afd0cf8..31f036c9d224f7e03d7fe38861db45b8
void AddNewContents(content::WebContents* source,
std::unique_ptr<content::WebContents> new_contents,
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 882110cce5d67936597e0c18378a907c536a5674..b13209969b5a01abcdf35e93fe130a1fe756ca41 100644
index a6236e242c061445e50cb155b2a8a6d1365c90f4..f126c82f3f3f9faf3bfbff4c2d4a673cc41decaf 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3812,8 +3812,7 @@ FrameTree* WebContentsImpl::CreateNewWindow(
@@ -3816,8 +3816,7 @@ FrameTree* WebContentsImpl::CreateNewWindow(
if (delegate_ && delegate_->IsWebContentsCreationOverridden(
source_site_instance, params.window_container_type,
@@ -344,10 +344,10 @@ index 7d9e445c8b2c727787854aa6e296f2e3784942fb..c82b0b86ab93aceb0d8c0bd5562e72d8
// can catch bad client behavior while not interfering with normal operation.
constexpr size_t kMaxPendingWebContentsCount = 10;
diff --git a/fuchsia/engine/browser/frame_impl.h b/fuchsia/engine/browser/frame_impl.h
index 38b5f8871464fc59c26e619dc2cdcc00711e2ce5..1ba0ac9d291a06f8a23e814742c38fdf382a05ec 100644
index ea50835c2f8631851659db6abb3ba779a5fcb6e0..14207edb850689c126b2d09eff8d8feb1246ebb7 100644
--- a/fuchsia/engine/browser/frame_impl.h
+++ b/fuchsia/engine/browser/frame_impl.h
@@ -290,8 +290,7 @@ class FrameImpl : public fuchsia::web::Frame,
@@ -292,8 +292,7 @@ class FrameImpl : public fuchsia::web::Frame,
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,

View File

@@ -7,10 +7,10 @@ spellchecker uses a few IDS_ resources. We need to load these from
Electrons grit header instead of Chromes
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 97023673450811be77b35d47bc55eda7f3fa5776..763ad6279b0ca8ab4cc09a48610d63836dc1fa17 100644
index f88e5e225c4b4d23b024ba71f4e0742020952519..0982cfa1db7233153af8b2ab7cd1c18dfb4dea49 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -7009,6 +7009,7 @@ static_library("browser") {
@@ -7010,6 +7010,7 @@ static_library("browser") {
deps += [
"//components/spellcheck/browser",
"//components/spellcheck/common",

View File

@@ -241,7 +241,7 @@ index ec1ba57d8b0fc42c3c1dc85542f70c595e1eb464..c88cdac173ec22ea5df27a166f9e87eb
sandbox::policy::switches::kGpuSandboxAllowSysVShm,
sandbox::policy::switches::kGpuSandboxFailuresFatal,
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 80158f16579a35d9376761e97e6066ff9b4f5416..719e49b7b65196cc16eaea3f23d3d8f818847f82 100644
index 9e7c599106f318dcfb63ae049ed1dd3a49427597..4eca6fdb154a39fea6e62433ddc8e107e7f97a86 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -185,6 +185,7 @@
@@ -252,7 +252,7 @@ index 80158f16579a35d9376761e97e6066ff9b4f5416..719e49b7b65196cc16eaea3f23d3d8f8
#include "ui/gl/gl_switches.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -3262,6 +3263,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
@@ -3265,6 +3266,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
// Propagate the following switches to the renderer command line (along
// with any associated values) if present in the browser command line.
static const char* const kSwitchNames[] = {

View File

@@ -24,7 +24,7 @@ This patch temporarily disables the metrics so we can have green CI, and we
should continue seeking for a real fix.
diff --git a/content/browser/renderer_host/navigator.cc b/content/browser/renderer_host/navigator.cc
index 79e5b753c512d9162370f019a81a2ad7c5e1b15b..b0291cdb33083ce557964db41d132c99eaf28fd9 100644
index 784a93c30513dbf822b5885f1a7dd3f8769077eb..8de12b787cc46cd6b30af4f07e8d72c0e483319e 100644
--- a/content/browser/renderer_host/navigator.cc
+++ b/content/browser/renderer_host/navigator.cc
@@ -1147,6 +1147,7 @@ void Navigator::RecordNavigationMetrics(

View File

@@ -12,7 +12,7 @@ Ideally we could add an embedder observer pattern here but that can be
done in future work.
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index d2adf1d956c8cb1598294600ead6f2de71a2df61..eebea635bce1299b94bc1577bb43ff8374e96ec5 100644
index d525df56c4e33a19431b2980a932956cb1986865..d52fe3a6f7bd7d70f0b595ada0dd06c9155399b8 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -159,6 +159,7 @@
@@ -23,7 +23,7 @@ index d2adf1d956c8cb1598294600ead6f2de71a2df61..eebea635bce1299b94bc1577bb43ff83
#include "third_party/blink/renderer/platform/graphics/image.h"
#include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
@@ -1793,6 +1794,7 @@ void WebView::ApplyWebPreferences(const web_pref::WebPreferences& prefs,
@@ -1797,6 +1798,7 @@ void WebView::ApplyWebPreferences(const web_pref::WebPreferences& prefs,
#if defined(OS_MAC)
web_view_impl->SetMaximumLegibleScale(
prefs.default_maximum_page_scale_factor);

View File

@@ -103,7 +103,7 @@ index 76a0a192fda9578fd243063ebad5831762539cf6..47234af6519479ea77d503bacda1a84b
string mime_type;
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index e53ff47c6f43d00fd89695c4ef08ef5f455df103..56dce34839df7569361bfe7076f6dd2f7ef307c7 100644
index 4fa80ce0d531a115eb23a58236847c42218f9cb3..a7e5e699940181d6f345de354694239686fa57f6 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -532,6 +532,7 @@ URLLoader::URLLoader(
@@ -123,7 +123,7 @@ index e53ff47c6f43d00fd89695c4ef08ef5f455df103..56dce34839df7569361bfe7076f6dd2f
url_request_->SetResponseHeadersCallback(base::BindRepeating(
&URLLoader::SetRawResponseHeaders, base::Unretained(this)));
}
@@ -1340,6 +1341,19 @@ void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) {
@@ -1358,6 +1359,19 @@ void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) {
response_ = network::mojom::URLResponseHead::New();
PopulateResourceResponse(url_request_.get(), is_load_timing_enabled_,
options_, response_.get());

View File

@@ -13,10 +13,10 @@ This patch can be removed should we choose to support chrome.fileSystem
or support it enough to fix the crash.
diff --git a/chrome/browser/resources/pdf/pdf_viewer.js b/chrome/browser/resources/pdf/pdf_viewer.js
index 42407ef7c214bed1eb44165a87c6d0dc44f0ad7f..64225caf3738549520b35259628559ec6c15d901 100644
index c8990a298babd90eea17d1aedfcf91e24a2a1cf8..0acf768b94a6f2b6eb0854f49248d86f1fb66f5b 100644
--- a/chrome/browser/resources/pdf/pdf_viewer.js
+++ b/chrome/browser/resources/pdf/pdf_viewer.js
@@ -967,25 +967,12 @@ export class PDFViewerElement extends PDFViewerBaseElement {
@@ -964,25 +964,12 @@ export class PDFViewerElement extends PDFViewerBaseElement {
dataArray = [result.dataToSave];
}
@@ -47,7 +47,7 @@ index 42407ef7c214bed1eb44165a87c6d0dc44f0ad7f..64225caf3738549520b35259628559ec
}
/**
@@ -1112,30 +1099,13 @@ export class PDFViewerElement extends PDFViewerBaseElement {
@@ -1109,30 +1096,13 @@ export class PDFViewerElement extends PDFViewerBaseElement {
if (!fileName.toLowerCase().endsWith('.pdf')) {
fileName = fileName + '.pdf';
}

View File

@@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: David Sanders <dsanders11@ucsbalum.com>
Date: Fri, 11 Feb 2022 22:37:39 +0000
Subject: fix: don't restore maximized windows when calling ShowInactive
This is a backport from Chromium of
https://chromium-review.googlesource.com/c/chromium/src/+/3371573.
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 067861bb743ee2f3c1916794d45efb7dd591b230..6507557bf5a47492343602607e0dbb7d8f88246d 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -664,9 +664,16 @@ void HWNDMessageHandler::Show(ui::WindowShowState show_state,
SetWindowPlacement(hwnd(), &placement);
native_show_state = SW_SHOWMAXIMIZED;
} else {
+ const bool is_maximized = IsMaximized();
+
+ // Use SW_SHOW/SW_SHOWNA instead of SW_SHOWNORMAL/SW_SHOWNOACTIVATE so that
+ // the window is not restored to its original position if it is maximized.
+ // This could be used unconditionally for ui::SHOW_STATE_INACTIVE, but
+ // cross-platform behavior when showing a minimized window is inconsistent,
+ // some platforms restore the position, some do not. See crbug.com/1296710
switch (show_state) {
case ui::SHOW_STATE_INACTIVE:
- native_show_state = SW_SHOWNOACTIVATE;
+ native_show_state = is_maximized ? SW_SHOWNA : SW_SHOWNOACTIVATE;
break;
case ui::SHOW_STATE_MAXIMIZED:
native_show_state = SW_SHOWMAXIMIZED;
@@ -677,9 +684,9 @@ void HWNDMessageHandler::Show(ui::WindowShowState show_state,
case ui::SHOW_STATE_NORMAL:
if ((GetWindowLong(hwnd(), GWL_EXSTYLE) & WS_EX_TRANSPARENT) ||
(GetWindowLong(hwnd(), GWL_EXSTYLE) & WS_EX_NOACTIVATE)) {
- native_show_state = SW_SHOWNOACTIVATE;
+ native_show_state = is_maximized ? SW_SHOWNA : SW_SHOWNOACTIVATE;
} else {
- native_show_state = SW_SHOWNORMAL;
+ native_show_state = is_maximized ? SW_SHOW : SW_SHOWNORMAL;
}
break;
case ui::SHOW_STATE_FULLSCREEN:

View File

@@ -8,7 +8,7 @@ we invoke it in order to expose contents.decrementCapturerCount([stayHidden, sta
to users. We should try to upstream this.
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 3d585150674979ba461b6e37d437a36446fb568b..8cf61baf4fc32ed986f66137623523d19c07ca3a 100644
index 7695f9082b9b1f00893fcdccbf2420e5faf7f541..68a875c2c011e5bc329cb6855148bd2884ca161d 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -1814,7 +1814,7 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,

View File

@@ -10,10 +10,10 @@ them should they exist.
This will be upstreamed.
diff --git a/printing/printing_context_mac.h b/printing/printing_context_mac.h
index 36f2e09d563a610128305cf4890e2af3bf6f4cdd..85363bd922bf0ab2630e3d5f350de0c58792963a 100644
index 3725aa4cd902a9c84e22bbcbd702bd47e1901fe4..221019f5df71e1d66accbf2ea2d161bd1125666f 100644
--- a/printing/printing_context_mac.h
+++ b/printing/printing_context_mac.h
@@ -85,6 +85,10 @@ class COMPONENT_EXPORT(PRINTING) PrintingContextMac : public PrintingContext {
@@ -83,6 +83,10 @@ class COMPONENT_EXPORT(PRINTING) PrintingContextMac : public PrintingContext {
// Returns true if the orientation was set.
bool SetOrientationIsLandscape(bool landscape);

View File

@@ -6,10 +6,10 @@ Subject: frame_host_manager.patch
Allows embedder to intercept site instances created by chromium.
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
index a1b908eda7221522b7b59ea75d6b7d45534d4318..ae373073d1f9281cfde5e1e68e99c08a93bcf164 100644
index 5b4639dadd8faace17df464c078a8553931b2065..82b61ac83a3f0f9f780037de2311dc58a79c7508 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -3114,6 +3114,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
@@ -3115,6 +3115,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
request->ResetStateForSiteInstanceChange();
}

View File

@@ -107,7 +107,7 @@ index 951075749b24814606f494c5a89ee2adf527f512..7036323ff8ee38ae92790dfd2e216df6
const GURL& document_url,
mojo::PendingReceiver<blink::mojom::NotificationService> receiver);
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 3727d99b6dffb07d8db7ac7a1883b0d8eb33601f..f4c7cbdf1ee0e643d770990ced0d72d96004cb95 100644
index d5a91455141a42205c35044b9f2d6f331a4eb077..d957bc3d4c0a9fcd4ddf5713bfcc9ba9a5c01106 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2109,7 +2109,7 @@ void RenderProcessHostImpl::CreateNotificationService(

View File

@@ -61,7 +61,7 @@ index 7b711bdbaf4afddd6ccf300af7bab26487942243..987a60b81554b676661d8f1a53facbc9
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/paint_vector_icon.h"
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc
index d63256af63e93c7aab4ce348b9d27953d5346c6c..0f708806aa0e4555c288da38e0f9ecd4c89b1c3e 100644
index 3f445de452d608500885351194c471cb821f9a04..1420255c5143745de5e43c2803906a11a21df6d0 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -16,9 +16,11 @@

View File

@@ -11,7 +11,7 @@ majority of changes originally come from these PRs:
This patch also fixes callback for manual user cancellation and success.
diff --git a/chrome/browser/printing/print_job.cc b/chrome/browser/printing/print_job.cc
index 0de0532d64897c91ce0f72d165976e12e1dec03e..13167ca3f9c0d4895fecd40ab1e2d397c6e85a0b 100644
index 0de0532d64897c91ce0f72d165976e12e1dec03e..735da67a83b10c56d747e2a2b512f7b7d1aae142 100644
--- a/chrome/browser/printing/print_job.cc
+++ b/chrome/browser/printing/print_job.cc
@@ -88,6 +88,7 @@ bool PrintWithReducedRasterization(PrefService* prefs) {
@@ -54,50 +54,11 @@ index 0de0532d64897c91ce0f72d165976e12e1dec03e..13167ca3f9c0d4895fecd40ab1e2d397
? PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3_WITH_TYPE42_FONTS
: PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3;
}
@@ -504,6 +510,20 @@ void PrintJob::OnPageDone(PrintedPage* page) {
}
#endif // defined(OS_WIN)
+void PrintJob::OnUserInitCancelled() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // Make sure a `Cancel()` is broadcast.
+ auto details = base::MakeRefCounted<JobEventDetails>(JobEventDetails::USER_INIT_CANCELED,
+ 0, nullptr);
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_PRINT_JOB_EVENT, content::Source<PrintJob>(this),
+ content::Details<JobEventDetails>(details.get()));
+
+ for (auto& observer : observers_) {
+ observer.OnUserInitCancelled();
+ }
+}
+
void PrintJob::OnFailed() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/printing/print_job.h b/chrome/browser/printing/print_job.h
index e19f62354edb8acad722c6680296b7d2f55f51fe..b5539171655d78634ee89faf3516d23ce5718353 100644
index e19f62354edb8acad722c6680296b7d2f55f51fe..51c41b4dbab81ffe5840d59ef45b661cf5c5534b 100644
--- a/chrome/browser/printing/print_job.h
+++ b/chrome/browser/printing/print_job.h
@@ -53,6 +53,7 @@ class PrintJob : public base::RefCountedThreadSafe<PrintJob> {
public:
virtual void OnDocDone(int job_id, PrintedDocument* document) {}
virtual void OnJobDone() {}
+ virtual void OnUserInitCancelled() {}
virtual void OnFailed() {}
};
@@ -100,6 +101,9 @@ class PrintJob : public base::RefCountedThreadSafe<PrintJob> {
// Called when the document is done printing.
virtual void OnDocDone(int job_id, PrintedDocument* document);
+ // Called if the user cancels the print job.
+ virtual void OnUserInitCancelled();
+
// Called if the document fails to print.
virtual void OnFailed();
@@ -257,6 +261,9 @@ class JobEventDetails : public base::RefCountedThreadSafe<JobEventDetails> {
@@ -257,6 +257,9 @@ class JobEventDetails : public base::RefCountedThreadSafe<JobEventDetails> {
public:
// Event type.
enum Type {
@@ -108,7 +69,7 @@ index e19f62354edb8acad722c6680296b7d2f55f51fe..b5539171655d78634ee89faf3516d23c
NEW_DOC,
diff --git a/chrome/browser/printing/print_job_worker.cc b/chrome/browser/printing/print_job_worker.cc
index d8f67ab5116483eb2eeb4cc09f19bbcbccb74b37..b4ab0984765c9711ddacf32f7147108cdfbc5096 100644
index e3fb49f7f612120d9f7297ba13ee15da5acc707b..992a59c32ea082e3593c0183819d1b174fc8db7a 100644
--- a/chrome/browser/printing/print_job_worker.cc
+++ b/chrome/browser/printing/print_job_worker.cc
@@ -20,13 +20,13 @@
@@ -126,18 +87,7 @@ index d8f67ab5116483eb2eeb4cc09f19bbcbccb74b37..b4ab0984765c9711ddacf32f7147108c
#include "printing/backend/print_backend.h"
#include "printing/buildflags/buildflags.h"
#include "printing/mojom/print.mojom.h"
@@ -125,6 +125,10 @@ void FailedNotificationCallback(PrintJob* print_job) {
print_job->OnFailed();
}
+void UserInitCancelledNotificationCallback(PrintJob* print_job) {
+ print_job->OnUserInitCancelled();
+}
+
#if defined(OS_WIN)
void PageNotificationCallback(PrintJob* print_job, PrintedPage* page) {
print_job->OnPageDone(page);
@@ -245,16 +249,21 @@ void PrintJobWorker::UpdatePrintSettings(base::Value new_settings,
@@ -245,16 +245,21 @@ void PrintJobWorker::UpdatePrintSettings(base::Value new_settings,
#endif // defined(OS_LINUX) && defined(USE_CUPS)
}
@@ -162,21 +112,8 @@ index d8f67ab5116483eb2eeb4cc09f19bbcbccb74b37..b4ab0984765c9711ddacf32f7147108c
}
#if defined(OS_CHROMEOS)
@@ -270,6 +279,12 @@ void PrintJobWorker::UpdatePrintSettingsFromPOD(
void PrintJobWorker::GetSettingsDone(SettingsCallback callback,
mojom::ResultCode result) {
+ if (result == mojom::ResultCode::kCanceled) {
+ print_job_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&UserInitCancelledNotificationCallback,
+ base::RetainedRef(print_job_.get())));
+ }
std::move(callback).Run(printing_context_->TakeAndResetSettings(), result);
}
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
index c9f1502da55d89de0eede73a7d39047c090594d0..1320afa83016ea72e5dbc23b1ed63cf91d439102 100644
index 772a5cfdc75bf63b5bac4e5e7ec68e6650058d92..2660276ca116d1bc66cbc4a36df3b3d0fa22e944 100644
--- a/chrome/browser/printing/print_view_manager_base.cc
+++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -29,10 +29,10 @@
@@ -228,7 +165,26 @@ index c9f1502da55d89de0eede73a7d39047c090594d0..1320afa83016ea72e5dbc23b1ed63cf9
RenderParamsFromPrintSettings(printer_query->settings(),
params->params.get());
params->params->document_cookie = printer_query->cookie();
@@ -319,12 +325,14 @@ PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents)
@@ -270,6 +276,7 @@ void ScriptedPrintReplyOnIO(
mojom::PrintManagerHost::ScriptedPrintCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
mojom::PrintPagesParamsPtr params = CreateEmptyPrintPagesParamsPtr();
+
if (printer_query->last_status() == mojom::ResultCode::kSuccess &&
printer_query->settings().dpi()) {
RenderParamsFromPrintSettings(printer_query->settings(),
@@ -279,8 +286,9 @@ void ScriptedPrintReplyOnIO(
}
bool has_valid_cookie = params->params->document_cookie;
bool has_dpi = !params->params->dpi.IsEmpty();
+ bool canceled = printer_query->last_status() == mojom::ResultCode::kCanceled;
content::GetUIThreadTaskRunner({})->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), std::move(params)));
+ FROM_HERE, base::BindOnce(std::move(callback), std::move(params), canceled));
if (has_dpi && has_valid_cookie) {
queue->QueuePrinterQuery(std::move(printer_query));
@@ -319,12 +327,14 @@ PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents)
: PrintManager(web_contents),
queue_(g_browser_process->print_job_manager()->queue()) {
DCHECK(queue_);
@@ -243,7 +199,7 @@ index c9f1502da55d89de0eede73a7d39047c090594d0..1320afa83016ea72e5dbc23b1ed63cf9
}
PrintViewManagerBase::~PrintViewManagerBase() {
@@ -332,7 +340,10 @@ PrintViewManagerBase::~PrintViewManagerBase() {
@@ -332,7 +342,10 @@ PrintViewManagerBase::~PrintViewManagerBase() {
DisconnectFromCurrentPrintJob();
}
@@ -252,25 +208,42 @@ index c9f1502da55d89de0eede73a7d39047c090594d0..1320afa83016ea72e5dbc23b1ed63cf9
+ bool silent,
+ base::Value settings,
+ CompletionCallback callback) {
auto weak_this = weak_ptr_factory_.GetWeakPtr();
DisconnectFromCurrentPrintJob();
if (!weak_this)
@@ -347,7 +358,13 @@ bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh) {
// Remember the ID for `rfh`, to enable checking that the `RenderFrameHost`
// is still valid after a possible inner message loop runs in
// `DisconnectFromCurrentPrintJob()`.
@@ -355,7 +368,9 @@ bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh) {
// go in `ReleasePrintJob()`.
SetPrintingRFH(rfh);
- GetPrintRenderFrame(rfh)->PrintRequestedPages();
+ callback_ = std::move(callback);
+
+ if (!callback_.is_null()) {
+ print_job_->AddObserver(*this);
+ }
+
+ GetPrintRenderFrame(rfh)->PrintRequestedPages(silent, std::move(settings));
for (auto& observer : GetObservers())
observer.OnPrintNow(rfh);
@@ -506,9 +523,9 @@ void PrintViewManagerBase::ScriptedPrintReply(
@@ -499,7 +514,8 @@ void PrintViewManagerBase::GetDefaultPrintSettingsReply(
void PrintViewManagerBase::ScriptedPrintReply(
ScriptedPrintCallback callback,
int process_id,
- mojom::PrintPagesParamsPtr params) {
+ mojom::PrintPagesParamsPtr params,
+ bool canceled) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!content::RenderProcessHost::FromID(process_id)) {
@@ -507,16 +523,19 @@ void PrintViewManagerBase::ScriptedPrintReply(
return;
}
+ if (canceled)
+ UserInitCanceled();
+
set_cookie(params->params->document_cookie);
- std::move(callback).Run(std::move(params));
+ std::move(callback).Run(std::move(params), canceled);
}
void PrintViewManagerBase::UpdatePrintingEnabled() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// The Unretained() is safe because ForEachFrame() is synchronous.
@@ -283,7 +256,7 @@ index c9f1502da55d89de0eede73a7d39047c090594d0..1320afa83016ea72e5dbc23b1ed63cf9
}
void PrintViewManagerBase::NavigationStopped() {
@@ -622,12 +639,13 @@ void PrintViewManagerBase::DidPrintDocument(
@@ -630,12 +649,13 @@ void PrintViewManagerBase::DidPrintDocument(
void PrintViewManagerBase::GetDefaultPrintSettings(
GetDefaultPrintSettingsCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -298,7 +271,7 @@ index c9f1502da55d89de0eede73a7d39047c090594d0..1320afa83016ea72e5dbc23b1ed63cf9
content::RenderFrameHost* render_frame_host = GetCurrentTargetFrame();
auto callback_wrapper =
base::BindOnce(&PrintViewManagerBase::GetDefaultPrintSettingsReply,
@@ -645,18 +663,20 @@ void PrintViewManagerBase::UpdatePrintSettings(
@@ -653,18 +673,20 @@ void PrintViewManagerBase::UpdatePrintSettings(
base::Value job_settings,
UpdatePrintSettingsCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -320,7 +293,7 @@ index c9f1502da55d89de0eede73a7d39047c090594d0..1320afa83016ea72e5dbc23b1ed63cf9
content::BrowserContext* context =
web_contents() ? web_contents()->GetBrowserContext() : nullptr;
PrefService* prefs =
@@ -666,6 +686,7 @@ void PrintViewManagerBase::UpdatePrintSettings(
@@ -674,6 +696,7 @@ void PrintViewManagerBase::UpdatePrintSettings(
if (value > 0)
job_settings.SetIntKey(kSettingRasterizePdfDpi, value);
}
@@ -328,7 +301,16 @@ index c9f1502da55d89de0eede73a7d39047c090594d0..1320afa83016ea72e5dbc23b1ed63cf9
auto callback_wrapper =
base::BindOnce(&PrintViewManagerBase::UpdatePrintSettingsReply,
@@ -714,7 +735,6 @@ void PrintViewManagerBase::PrintingFailed(int32_t cookie) {
@@ -699,7 +722,7 @@ void PrintViewManagerBase::ScriptedPrint(mojom::ScriptedPrintParamsPtr params,
// didn't happen for some reason.
bad_message::ReceivedBadMessage(
render_process_host, bad_message::PVMB_SCRIPTED_PRINT_FENCED_FRAME);
- std::move(callback).Run(CreateEmptyPrintPagesParamsPtr());
+ std::move(callback).Run(CreateEmptyPrintPagesParamsPtr(), false);
return;
}
int process_id = render_process_host->GetID();
@@ -722,7 +745,6 @@ void PrintViewManagerBase::PrintingFailed(int32_t cookie) {
PrintManager::PrintingFailed(cookie);
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
@@ -336,7 +318,7 @@ index c9f1502da55d89de0eede73a7d39047c090594d0..1320afa83016ea72e5dbc23b1ed63cf9
#endif
ReleasePrinterQuery();
@@ -729,6 +749,11 @@ void PrintViewManagerBase::RemoveObserver(Observer& observer) {
@@ -737,6 +759,11 @@ void PrintViewManagerBase::RemoveObserver(Observer& observer) {
}
void PrintViewManagerBase::ShowInvalidPrinterSettingsError() {
@@ -348,7 +330,7 @@ index c9f1502da55d89de0eede73a7d39047c090594d0..1320afa83016ea72e5dbc23b1ed63cf9
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&ShowWarningMessageBox,
l10n_util::GetStringUTF16(
@@ -739,8 +764,10 @@ void PrintViewManagerBase::RenderFrameHostStateChanged(
@@ -747,8 +774,10 @@ void PrintViewManagerBase::RenderFrameHostStateChanged(
content::RenderFrameHost* render_frame_host,
content::RenderFrameHost::LifecycleState /*old_state*/,
content::RenderFrameHost::LifecycleState new_state) {
@@ -359,19 +341,19 @@ index c9f1502da55d89de0eede73a7d39047c090594d0..1320afa83016ea72e5dbc23b1ed63cf9
}
void PrintViewManagerBase::DidStartLoading() {
@@ -808,6 +835,11 @@ void PrintViewManagerBase::OnJobDone() {
@@ -816,6 +845,11 @@ void PrintViewManagerBase::OnJobDone() {
ReleasePrintJob();
}
+void PrintViewManagerBase::OnUserInitCancelled() {
+ printing_cancelled_ = true;
+void PrintViewManagerBase::UserInitCanceled() {
+ printing_canceled_ = true;
+ ReleasePrintJob();
+}
+
void PrintViewManagerBase::OnFailed() {
TerminatePrintJob(true);
}
@@ -869,7 +901,10 @@ bool PrintViewManagerBase::CreateNewPrintJob(
@@ -877,7 +911,10 @@ bool PrintViewManagerBase::CreateNewPrintJob(
// Disconnect the current |print_job_|.
auto weak_this = weak_ptr_factory_.GetWeakPtr();
@@ -383,40 +365,21 @@ index c9f1502da55d89de0eede73a7d39047c090594d0..1320afa83016ea72e5dbc23b1ed63cf9
if (!weak_this)
return false;
@@ -891,8 +926,6 @@ bool PrintViewManagerBase::CreateNewPrintJob(
: PrintJob::Source::PRINT_PREVIEW,
/*source_id=*/"");
#endif
- print_job_->AddObserver(*this);
-
printing_succeeded_ = false;
return true;
}
@@ -944,14 +977,21 @@ void PrintViewManagerBase::ReleasePrintJob() {
@@ -952,6 +989,13 @@ void PrintViewManagerBase::ReleasePrintJob() {
content::RenderFrameHost* rfh = printing_rfh_;
printing_rfh_ = nullptr;
+ if (!callback_.is_null()) {
+ print_job_->RemoveObserver(*this);
+
+ std::string cb_str = "";
+ if (!printing_succeeded_)
+ cb_str = printing_cancelled_ ? "cancelled" : "failed";
+ cb_str = printing_canceled_ ? "canceled" : "failed";
+ std::move(callback_).Run(printing_succeeded_, cb_str);
+ }
+
if (!print_job_)
return;
if (rfh)
GetPrintRenderFrame(rfh)->PrintingDone(printing_succeeded_);
- print_job_->RemoveObserver(*this);
-
// Don't close the worker thread.
print_job_ = nullptr;
}
@@ -989,7 +1029,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() {
@@ -1001,7 +1045,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() {
}
bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) {
@@ -426,7 +389,7 @@ index c9f1502da55d89de0eede73a7d39047c090594d0..1320afa83016ea72e5dbc23b1ed63cf9
if (!cookie) {
diff --git a/chrome/browser/printing/print_view_manager_base.h b/chrome/browser/printing/print_view_manager_base.h
index 5771a3ebd76145c6cf8a2ccc33abc886802ed59f..1562d6331a9cafd530db42c436e878bac427566d 100644
index 5771a3ebd76145c6cf8a2ccc33abc886802ed59f..fb3af5e3f57f868fd00716f76f70aa63c4cb99c9 100644
--- a/chrome/browser/printing/print_view_manager_base.h
+++ b/chrome/browser/printing/print_view_manager_base.h
@@ -37,6 +37,8 @@ namespace printing {
@@ -450,15 +413,25 @@ index 5771a3ebd76145c6cf8a2ccc33abc886802ed59f..1562d6331a9cafd530db42c436e878ba
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
// Prints the document in |print_data| with settings specified in
@@ -143,6 +148,7 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
// PrintJob::Observer overrides:
void OnDocDone(int job_id, PrintedDocument* document) override;
void OnJobDone() override;
+ void OnUserInitCancelled() override;
void OnFailed() override;
@@ -106,6 +111,7 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
ScriptedPrintCallback callback) override;
void ShowInvalidPrinterSettingsError() override;
void PrintingFailed(int32_t cookie) override;
+ void UserInitCanceled();
base::ObserverList<Observer>& GetObservers() { return observers_; }
@@ -252,9 +258,15 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
// Adds and removes observers for `PrintViewManagerBase` events. The order in
// which notifications are sent to observers is undefined. Observers must be
@@ -197,7 +203,8 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
// Runs `callback` with `params` to reply to ScriptedPrint().
void ScriptedPrintReply(ScriptedPrintCallback callback,
int process_id,
- mojom::PrintPagesParamsPtr params);
+ mojom::PrintPagesParamsPtr params,
+ bool canceled);
// Requests the RenderView to render all the missing pages for the print job.
// No-op if no print job is pending. Returns true if at least one page has
@@ -252,9 +259,15 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
// The current RFH that is printing with a system printing dialog.
raw_ptr<content::RenderFrameHost> printing_rfh_ = nullptr;
@@ -468,14 +441,14 @@ index 5771a3ebd76145c6cf8a2ccc33abc886802ed59f..1562d6331a9cafd530db42c436e878ba
// Indication of success of the print job.
bool printing_succeeded_ = false;
+ // Indication of whether the print job was manually cancelled
+ bool printing_cancelled_ = false;
+ // Indication of whether the print job was manually canceled
+ bool printing_canceled_ = false;
+
// Set while running an inner message loop inside RenderAllMissingPagesNow().
// This means we are _blocking_ until all the necessary pages have been
// rendered or the print settings are being loaded.
diff --git a/components/printing/common/print.mojom b/components/printing/common/print.mojom
index 51ebcb4ae399018d3fd8566656596a7ef1f148af..5f2b807fc364131f4c3e6a1646ec522ddc826d9c 100644
index 51ebcb4ae399018d3fd8566656596a7ef1f148af..c0fbff95137e2e5bccb9702a8cc858df2d989964 100644
--- a/components/printing/common/print.mojom
+++ b/components/printing/common/print.mojom
@@ -274,7 +274,7 @@ interface PrintPreviewUI {
@@ -487,8 +460,17 @@ index 51ebcb4ae399018d3fd8566656596a7ef1f148af..5f2b807fc364131f4c3e6a1646ec522d
// Tells the RenderFrame to switch the CSS to print media type, render every
// requested page using the print preview document's frame/node, and then
@@ -341,7 +341,7 @@ interface PrintManagerHost {
// Request the print settings from the user. This step is about showing
// UI to the user to select the final print settings.
[Sync]
- ScriptedPrint(ScriptedPrintParams params) => (PrintPagesParams settings);
+ ScriptedPrint(ScriptedPrintParams params) => (PrintPagesParams settings, bool canceled);
// Tells the browser that there are invalid printer settings.
ShowInvalidPrinterSettingsError();
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index 650b5550f982fa5c5c522efaa9b8e305b7edc5e7..260b5521dccadf07eba2c67fa3d9c3da80b49104 100644
index 650b5550f982fa5c5c522efaa9b8e305b7edc5e7..1b776a614d6e0f6c3ae13ef3c705bc19544cfe12 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -39,6 +39,7 @@
@@ -657,6 +639,15 @@ index 650b5550f982fa5c5c522efaa9b8e305b7edc5e7..260b5521dccadf07eba2c67fa3d9c3da
notify_browser_of_print_failure_ = false;
GetPrintManagerHost()->ShowInvalidPrinterSettingsError();
return false;
@@ -2350,7 +2380,7 @@ mojom::PrintPagesParamsPtr PrintRenderFrameHelper::GetPrintSettingsFromUser(
std::move(params),
base::BindOnce(
[](base::OnceClosure quit_closure, mojom::PrintPagesParamsPtr* output,
- mojom::PrintPagesParamsPtr input) {
+ mojom::PrintPagesParamsPtr input, bool canceled) {
*output = std::move(input);
std::move(quit_closure).Run();
},
@@ -2579,18 +2609,7 @@ void PrintRenderFrameHelper::RequestPrintPreview(PrintPreviewRequestType type) {
}
@@ -731,12 +722,12 @@ index f8f0f4bdfbb8db883f883f62f9d6e4b987d7b113..c2505f5e0049dc7ee8783056538ca4c2
std::unique_ptr<PrintSettings> settings =
PrintSettingsFromJobSettings(job_settings);
diff --git a/printing/printing_context.h b/printing/printing_context.h
index 7d937e7e3f19df351d410185fc4dc3b7c8937f2e..e87170e6957733f06bcc296bcca3fc331557ed46 100644
index e34fb070b5d1ee5ebea9e924569847ff5999b417..3f4d7d5f656e2f6e10ced048370283eedbfb110b 100644
--- a/printing/printing_context.h
+++ b/printing/printing_context.h
@@ -175,6 +175,9 @@ class COMPONENT_EXPORT(PRINTING) PrintingContext {
@@ -171,6 +171,9 @@ class COMPONENT_EXPORT(PRINTING) PrintingContext {
std::unique_ptr<PrintSettings> TakeAndResetSettings();
bool PrintingAborted() const { return abort_printing_; }
+ // Reinitializes the settings for object reuse.
+ void ResetSettings();
@@ -744,7 +735,7 @@ index 7d937e7e3f19df351d410185fc4dc3b7c8937f2e..e87170e6957733f06bcc296bcca3fc33
int job_id() const { return job_id_; }
protected:
@@ -185,9 +188,6 @@ class COMPONENT_EXPORT(PRINTING) PrintingContext {
@@ -181,9 +184,6 @@ class COMPONENT_EXPORT(PRINTING) PrintingContext {
static std::unique_ptr<PrintingContext> CreateImpl(Delegate* delegate,
bool skip_system_calls);

View File

@@ -43,10 +43,10 @@ index b0820c4411952ee0adf3dd4cbc6abb26c0368373..cd2770dee3fac7f6b09c3fafbf87a553
void RenderWidgetHostImpl::ShowContextMenuAtPoint(
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 6ab76b93f7733d201590389f8e1ff617d7fa3269..882110cce5d67936597e0c18378a907c536a5674 100644
index 495f2f355984a304e71fe0b2f2fe670bdc8bc833..a6236e242c061445e50cb155b2a8a6d1365c90f4 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4415,6 +4415,11 @@ TextInputManager* WebContentsImpl::GetTextInputManager() {
@@ -4419,6 +4419,11 @@ TextInputManager* WebContentsImpl::GetTextInputManager() {
return text_input_manager_.get();
}
@@ -59,7 +59,7 @@ index 6ab76b93f7733d201590389f8e1ff617d7fa3269..882110cce5d67936597e0c18378a907c
RenderWidgetHostImpl* render_widget_host) {
return render_widget_host == GetMainFrame()->GetRenderWidgetHost();
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index d50ca21709c981e3c967571507f7a31465087efd..3d585150674979ba461b6e37d437a36446fb568b 100644
index 90f4082c383f1a32af98b80a88f88e44d23eb733..7695f9082b9b1f00893fcdccbf2420e5faf7f541 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -963,6 +963,7 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,

View File

@@ -1,28 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Tue, 4 Jan 2022 11:10:27 +0100
Subject: revert: stop using NSRunLoop in renderer process
https://chromium-review.googlesource.com/c/chromium/src/+/3344749
This can be removed once we update to a DEPS has which
includes 4787f034924d0b05a2e4815a197a8ecf4a9c623c.
diff --git a/content/renderer/renderer_main.cc b/content/renderer/renderer_main.cc
index 261e6de9ad03cb017fd2c71e30aef14f51312b60..625c984fc5255fe7ab01f5e38767ada73c21ffec 100644
--- a/content/renderer/renderer_main.cc
+++ b/content/renderer/renderer_main.cc
@@ -91,7 +91,12 @@ void HandleRendererErrorTestParameters(const base::CommandLine& command_line) {
}
std::unique_ptr<base::MessagePump> CreateMainThreadMessagePump() {
-#if defined(OS_FUCHSIA)
+#if defined(OS_MAC)
+ // As long as scrollbars on Mac are painted with Cocoa, the message pump
+ // needs to be backed by a Foundation-level loop to process NSTimers. See
+ // http://crbug.com/306348#c24 for details.
+ return base::MessagePump::Create(base::MessagePumpType::NS_RUNLOOP);
+#elif defined(OS_FUCHSIA)
// Allow FIDL APIs on renderer main thread.
return base::MessagePump::Create(base::MessagePumpType::IO);
#else

View File

@@ -22,7 +22,7 @@ However, the patch would need to be reviewed by the security team, as it
does touch a security-sensitive class.
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index f4c7cbdf1ee0e643d770990ced0d72d96004cb95..80158f16579a35d9376761e97e6066ff9b4f5416 100644
index d957bc3d4c0a9fcd4ddf5713bfcc9ba9a5c01106..9e7c599106f318dcfb63ae049ed1dd3a49427597 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1828,9 +1828,15 @@ bool RenderProcessHostImpl::Init() {

View File

@@ -9,10 +9,10 @@ is needed for OSR.
Originally landed in https://github.com/electron/libchromiumcontent/pull/226.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index b13209969b5a01abcdf35e93fe130a1fe756ca41..a54e7c0d45dc2d345e9ac803bb934c41cdd2e5da 100644
index f126c82f3f3f9faf3bfbff4c2d4a673cc41decaf..00a701c92c6b3ab7aa00e6f7bfc40febc7d0439e 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -2971,6 +2971,13 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params) {
@@ -2975,6 +2975,13 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params) {
params.renderer_initiated_creation,
params.main_frame_name, GetOriginalOpener());
@@ -26,7 +26,7 @@ index b13209969b5a01abcdf35e93fe130a1fe756ca41..a54e7c0d45dc2d345e9ac803bb934c41
WebContentsViewDelegate* delegate =
GetContentClient()->browser()->GetWebContentsViewDelegate(this);
@@ -2981,6 +2988,7 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params) {
@@ -2985,6 +2992,7 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params) {
view_.reset(CreateWebContentsView(this, delegate,
&render_view_host_delegate_view_));
}

View File

@@ -14,10 +14,10 @@ Note that we also need to manually update embedder's
`api::WebContents::IsFullscreenForTabOrPending` value.
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index e6528700d5328a5a301b2c36c5ea25fcddf81143..d18f48b6d1c82bd4bffae063b01ce15bce868ce3 100644
index 6ebceb4b5c47ada6d228ef00825b10fb7326d78c..6bcd908794675c046bbfed26a979f7fbf123b190 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -6004,6 +6004,15 @@ void RenderFrameHostImpl::EnterFullscreen(
@@ -6028,6 +6028,15 @@ void RenderFrameHostImpl::EnterFullscreen(
notified_instances.insert(parent_site_instance);
}

View File

@@ -3,6 +3,8 @@
"src/electron/patches/boringssl": "src/third_party/boringssl/src",
"src/electron/patches/devtools_frontend": "src/third_party/devtools-frontend/src",
"src/electron/patches/webrtc": "src/third_party/webrtc",
"src/electron/patches/v8": "src/v8",

View File

@@ -0,0 +1 @@
fix_expose_globals_to_allow_patching_devtools_dock.patch

View File

@@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Wed, 9 Feb 2022 10:55:54 +0100
Subject: fix: expose globals to allow patching Devtools dock
Electron calls into UI.DockController.instance().setDockSide(side) in
order to allow users to set the devtools dock position via
webContents.openDevTools({ mode }). In https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/3310870
the globals which we used to enable this were removed, and so we need to
re-expose them to fix this broken functionality. We should look to
upstream a more durable approach to allowing us to do this, at which
point this patch can be removed.
diff --git a/front_end/entrypoints/shell/BUILD.gn b/front_end/entrypoints/shell/BUILD.gn
index bf96adcaa42a2406cf1dd7cd2468802886aa4fd7..cd84442cab4a0da772dd37cd4e921041b3b6173a 100644
--- a/front_end/entrypoints/shell/BUILD.gn
+++ b/front_end/entrypoints/shell/BUILD.gn
@@ -31,6 +31,7 @@ devtools_entrypoint("shell") {
"../../ui/legacy/components/perf_ui:meta",
"../../ui/legacy/components/quick_open:meta",
"../../ui/legacy/components/source_frame:meta",
+ "../../ui/legacy:legacy",
]
visibility = [
diff --git a/front_end/entrypoints/shell/shell.ts b/front_end/entrypoints/shell/shell.ts
index 89255a0927a647ca32d1a9508853425a3207b441..f0e1e32f80d79e400ad139818edce60aff6aeb89 100644
--- a/front_end/entrypoints/shell/shell.ts
+++ b/front_end/entrypoints/shell/shell.ts
@@ -20,6 +20,7 @@ import '../../models/logs/logs-meta.js';
import '../main/main-meta.js';
import '../../ui/legacy/components/perf_ui/perf_ui-meta.js';
import '../../ui/legacy/components/quick_open/quick_open-meta.js';
+import '../../ui/legacy/legacy-legacy.js';
import '../../core/sdk/sdk-meta.js';
import '../../ui/legacy/components/source_frame/source_frame-meta.js';
import '../../panels/console_counters/console_counters-meta.js';
diff --git a/front_end/ui/legacy/BUILD.gn b/front_end/ui/legacy/BUILD.gn
index fe7c150cf6ce24b10821fa5a91d55f82cf865222..7177d495ec9e2b31a641c7a531b63584c597cf97 100644
--- a/front_end/ui/legacy/BUILD.gn
+++ b/front_end/ui/legacy/BUILD.gn
@@ -182,5 +182,6 @@ devtools_entrypoint("legacy") {
visibility = [
"../..:legacy_entrypoints",
"../../legacy_test_runner/*",
+ "../../entrypoints/shell/*",
]
}

View File

@@ -29,3 +29,6 @@ test_add_fixture_trim_option.patch
fix_crash_caused_by_gethostnamew_on_windows_7.patch
fix_suppress_clang_-wdeprecated-declarations_in_libuv.patch
fix_don_t_create_console_window_when_creating_process.patch
darwin_remove_eprototype_error_workaround_3405.patch
darwin_translate_eprototype_to_econnreset_3413.patch
darwin_bump_minimum_supported_version_to_10_15_3406.patch

View File

@@ -0,0 +1,25 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ben Noordhuis <info@bnoordhuis.nl>
Date: Tue, 8 Feb 2022 14:18:29 +0100
Subject: darwin: bump minimum supported version to 10.15 (#3406)
We can't realistically claim to support 10.7 or any version that Apple
no longer supports so let's bump the baseline to something more
realistic.
Refs: https://github.com/libuv/libuv/pull/482
Refs: https://github.com/libuv/libuv/pull/3405
diff --git a/deps/uv/SUPPORTED_PLATFORMS.md b/deps/uv/SUPPORTED_PLATFORMS.md
index 30e0ea617a6fcaa5b4b7c7c5b117652e61f367d3..dc57dfb12dc7ddf8d29308ac44f46084a933d5ca 100644
--- a/deps/uv/SUPPORTED_PLATFORMS.md
+++ b/deps/uv/SUPPORTED_PLATFORMS.md
@@ -3,7 +3,7 @@
| System | Support type | Supported versions | Notes |
|---|---|---|---|
| GNU/Linux | Tier 1 | Linux >= 2.6.32 with glibc >= 2.12 | |
-| macOS | Tier 1 | macOS >= 10.7 | |
+| macOS | Tier 1 | macOS >= 10.15 | Current and previous macOS release |
| Windows | Tier 1 | >= Windows 8 | VS 2015 and later are supported |
| FreeBSD | Tier 1 | >= 10 | |
| AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix |

View File

@@ -0,0 +1,65 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ben Noordhuis <info@bnoordhuis.nl>
Date: Sun, 9 Jan 2022 12:20:15 +0100
Subject: darwin: remove EPROTOTYPE error workaround (#3405)
It's been reported in the past that OS X 10.10, because of a race
condition in the XNU kernel, sometimes returns a transient EPROTOTYPE
error when trying to write to a socket. Libuv handles that by retrying
the operation until it succeeds or fails with a different error.
Recently it's been reported that current versions of the operating
system formerly known as OS X fail permanently with EPROTOTYPE under
certain conditions, resulting in an infinite loop.
Because Apple isn't exactly forthcoming with bug fixes or even details,
I'm opting to simply remove the workaround and have the error bubble up.
Refs: https://github.com/libuv/libuv/pull/482
diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c
index bc64fe8f44b26d9f4c0d4d0d282b65cdf11a531b..1af448e7691392c3f7794eed1905d9132394e207 100644
--- a/deps/uv/src/unix/stream.c
+++ b/deps/uv/src/unix/stream.c
@@ -58,20 +58,6 @@ struct uv__stream_select_s {
fd_set* swrite;
size_t swrite_sz;
};
-
-/* Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
- * EPROTOTYPE can be returned while trying to write to a socket that is
- * shutting down. If we retry the write, we should get the expected EPIPE
- * instead.
- */
-# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR || errno == EPROTOTYPE)
-# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \
- (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \
- (errno == EMSGSIZE && send_handle != NULL))
-#else
-# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR)
-# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \
- (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
#endif /* defined(__APPLE__) */
static void uv__stream_connect(uv_stream_t*);
@@ -866,17 +852,17 @@ static int uv__try_write(uv_stream_t* stream,
do
n = sendmsg(uv__stream_fd(stream), &msg, 0);
- while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
+ while (n == -1 && errno == EINTR);
} else {
do
n = uv__writev(uv__stream_fd(stream), iov, iovcnt);
- while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
+ while (n == -1 && errno == EINTR);
}
if (n >= 0)
return n;
- if (IS_TRANSIENT_WRITE_ERROR(errno, send_handle))
+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
return UV_EAGAIN;
return UV__ERR(errno);

View File

@@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ben Noordhuis <info@bnoordhuis.nl>
Date: Wed, 12 Jan 2022 16:11:43 +0100
Subject: darwin: translate EPROTOTYPE to ECONNRESET (#3413)
macOS versions 10.10 and 10.15 - and presumbaly 10.11 to 10.14, too -
have a bug where a race condition causes the kernel to return EPROTOTYPE
because the socket isn't fully constructed.
It's probably the result of the peer closing the connection and that is
why libuv translates it to ECONNRESET.
Previously, libuv retried until the EPROTOTYPE error went away but some
VPN software causes the same behavior except the error is permanent, not
transient, turning the retry mechanism into an infinite loop.
Refs: https://github.com/libuv/libuv/pull/482
Refs: https://github.com/libuv/libuv/pull/3405
diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c
index 1af448e7691392c3f7794eed1905d9132394e207..9d22debf2bf5bd5912ade152e55a85ad652e3819 100644
--- a/deps/uv/src/unix/stream.c
+++ b/deps/uv/src/unix/stream.c
@@ -865,6 +865,20 @@ static int uv__try_write(uv_stream_t* stream,
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
return UV_EAGAIN;
+#ifdef __APPLE__
+ /* macOS versions 10.10 and 10.15 - and presumbaly 10.11 to 10.14, too -
+ * have a bug where a race condition causes the kernel to return EPROTOTYPE
+ * because the socket isn't fully constructed. It's probably the result of
+ * the peer closing the connection and that is why libuv translates it to
+ * ECONNRESET. Previously, libuv retried until the EPROTOTYPE error went
+ * away but some VPN software causes the same behavior except the error is
+ * permanent, not transient, turning the retry mechanism into an infinite
+ * loop. See https://github.com/libuv/libuv/pull/482.
+ */
+ if (errno == EPROTOTYPE)
+ return UV_ECONNRESET;
+#endif /* __APPLE__ */
+
return UV__ERR(errno);
}

View File

@@ -6,10 +6,10 @@ Subject: Export symbols needed for Windows build
These symbols are required to build v8 with BUILD_V8_SHARED on Windows.
diff --git a/src/objects/objects.h b/src/objects/objects.h
index d064f4e27ffeb239d42562b401f353d1e557e9a7..22b63674e11a700c98f2dc2d3b32944894e68f28 100644
index 82e1680b4778f5f643dcd763e5b7e1ef7418a7ac..45c1690e280d9903c236d1d3b1cfc5aa195176d9 100644
--- a/src/objects/objects.h
+++ b/src/objects/objects.h
@@ -886,7 +886,7 @@ enum AccessorComponent { ACCESSOR_GETTER, ACCESSOR_SETTER };
@@ -893,7 +893,7 @@ enum AccessorComponent { ACCESSOR_GETTER, ACCESSOR_SETTER };
// Utility superclass for stack-allocated objects that must be updated
// on gc. It provides two ways for the gc to update instances, either
// iterating or updating after gc.

View File

@@ -20,7 +20,7 @@ LINUX_BINARIES = [
'libEGL.so',
'libGLESv2.so',
'libffmpeg.so',
'libvk_swiftshader.so'
'libvk_swiftshader.so',
'swiftshader/libEGL.so',
'swiftshader/libGLESv2.so',
]

View File

@@ -1,10 +0,0 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ELECTRON_SHELL_APP_ELECTRON_MAIN_H_
#define ELECTRON_SHELL_APP_ELECTRON_MAIN_H_
#include "content/public/app/content_main.h"
#endif // ELECTRON_SHELL_APP_ELECTRON_MAIN_H_

View File

@@ -0,0 +1,52 @@
// Copyright (c) 2022 Slack Technologies, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include <cstdlib>
#include <utility>
#include "base/at_exit.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/i18n/icu_util.h"
#include "content/public/app/content_main.h"
#include "electron/buildflags/buildflags.h"
#include "electron/fuses.h"
#include "shell/app/electron_main_delegate.h" // NOLINT
#include "shell/app/node_main.h"
#include "shell/app/uv_stdio_fix.h"
#include "shell/common/electron_command_line.h"
#include "shell/common/electron_constants.h"
namespace {
ALLOW_UNUSED_TYPE bool IsEnvSet(const char* name) {
char* indicator = getenv(name);
return indicator && indicator[0] != '\0';
}
} // namespace
int main(int argc, char* argv[]) {
FixStdioStreams();
#if BUILDFLAG(ENABLE_RUN_AS_NODE)
if (electron::fuses::IsRunAsNodeEnabled() && IsEnvSet(electron::kRunAsNode)) {
base::i18n::InitializeICU();
base::AtExitManager atexit_manager;
return electron::NodeMain(argc, argv);
}
#endif
electron::ElectronMainDelegate delegate;
content::ContentMainParams params(&delegate);
electron::ElectronCommandLine::Init(argc, argv);
params.argc = argc;
params.argv = const_cast<const char**>(argv);
base::CommandLine::Init(params.argc, params.argv);
// TODO(https://crbug.com/1176772): Remove when Chrome Linux is fully migrated
// to Crashpad.
base::CommandLine::ForCurrentProcess()->AppendSwitch(
::switches::kEnableCrashpad);
return content::ContentMain(std::move(params));
}

View File

@@ -0,0 +1,69 @@
// Copyright (c) 2022 Slack Technologies, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include <cstdlib>
#include <memory>
#include "electron/buildflags/buildflags.h"
#include "electron/fuses.h"
#include "shell/app/electron_library_main.h"
#include "shell/app/uv_stdio_fix.h"
#include "shell/common/electron_constants.h"
#if defined(HELPER_EXECUTABLE) && !defined(MAS_BUILD)
#include <mach-o/dyld.h>
#include <cstdio>
#include "sandbox/mac/seatbelt_exec.h" // nogncheck
#endif
namespace {
ALLOW_UNUSED_TYPE bool IsEnvSet(const char* name) {
char* indicator = getenv(name);
return indicator && indicator[0] != '\0';
}
} // namespace
int main(int argc, char* argv[]) {
FixStdioStreams();
#if BUILDFLAG(ENABLE_RUN_AS_NODE)
if (electron::fuses::IsRunAsNodeEnabled() && IsEnvSet(electron::kRunAsNode)) {
return ElectronInitializeICUandStartNode(argc, argv);
}
#endif
#if defined(HELPER_EXECUTABLE) && !defined(MAS_BUILD)
uint32_t exec_path_size = 0;
int rv = _NSGetExecutablePath(NULL, &exec_path_size);
if (rv != -1) {
fprintf(stderr, "_NSGetExecutablePath: get length failed\n");
abort();
}
auto exec_path = std::make_unique<char[]>(exec_path_size);
rv = _NSGetExecutablePath(exec_path.get(), &exec_path_size);
if (rv != 0) {
fprintf(stderr, "_NSGetExecutablePath: get path failed\n");
abort();
}
sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt =
sandbox::SeatbeltExecServer::CreateFromArguments(exec_path.get(), argc,
argv);
if (seatbelt.sandbox_required) {
if (!seatbelt.server) {
fprintf(stderr, "Failed to create seatbelt sandbox server.\n");
abort();
}
if (!seatbelt.server->InitializeSandbox()) {
fprintf(stderr, "Failed to initialize sandbox.\n");
abort();
}
}
#endif // defined(HELPER_EXECUTABLE) && !defined(MAS_BUILD)
return ElectronMain(argc, argv);
}

View File

@@ -1,8 +1,13 @@
// Copyright (c) 2013 GitHub, Inc.
// Copyright (c) 2022 Slack Technologies, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/app/electron_main.h"
#include <windows.h> // windows.h must be included first
#include <atlbase.h> // ensures that ATL statics like `_AtlWinModule` are initialized (it's an issue in static debug build)
#include <shellapi.h>
#include <shellscalingapi.h>
#include <tchar.h>
#include <algorithm>
#include <cstdlib>
@@ -11,101 +16,42 @@
#include <utility>
#include <vector>
#if defined(OS_POSIX)
#include <sys/stat.h>
#include "base/ignore_result.h"
#endif
#if defined(OS_WIN)
#include <windows.h> // windows.h must be included first
#include <atlbase.h> // ensures that ATL statics like `_AtlWinModule` are initialized (it's an issue in static debug build)
#include <shellapi.h>
#include <shellscalingapi.h>
#include <tchar.h>
#include "base/at_exit.h"
#include "base/environment.h"
#include "base/i18n/icu_util.h"
#include "base/process/launch.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/windows_version.h"
#include "components/browser_watcher/exit_code_watcher_win.h"
#include "components/crash/core/app/crash_switches.h"
#include "components/crash/core/app/run_as_crashpad_handler_win.h"
#include "content/public/app/content_main.h"
#include "content/public/app/sandbox_helper_win.h"
#include "electron/buildflags/buildflags.h"
#include "electron/fuses.h"
#include "sandbox/win/src/sandbox_types.h"
#include "shell/app/command_line_args.h"
#include "shell/app/electron_main_delegate.h"
#include "third_party/crashpad/crashpad/util/win/initial_client_data.h"
#elif defined(OS_LINUX) // defined(OS_WIN)
#include <unistd.h>
#include <cstdio>
#include "base/base_switches.h"
#include "base/command_line.h"
#include "content/public/app/content_main.h"
#include "shell/app/electron_main_delegate.h" // NOLINT
#else // defined(OS_LINUX)
#include <mach-o/dyld.h>
#include <unistd.h>
#include <cstdio>
#include "shell/app/electron_library_main.h"
#endif // defined(OS_MAC)
#include "base/at_exit.h"
#include "base/i18n/icu_util.h"
#include "electron/buildflags/buildflags.h"
#include "electron/fuses.h"
#include "shell/app/node_main.h"
#include "shell/common/electron_command_line.h"
#include "shell/common/electron_constants.h"
#if defined(HELPER_EXECUTABLE) && !defined(MAS_BUILD)
#include "sandbox/mac/seatbelt_exec.h" // nogncheck
#endif
#include "third_party/crashpad/crashpad/util/win/initial_client_data.h"
namespace {
#if defined(OS_WIN)
// Redefined here so we don't have to introduce a dependency on //content
// from //electron:electron_app
const char kUserDataDir[] = "user-data-dir";
const char kProcessType[] = "type";
#endif
ALLOW_UNUSED_TYPE bool IsEnvSet(const char* name) {
#if defined(OS_WIN)
size_t required_size;
getenv_s(&required_size, nullptr, 0, name);
return required_size != 0;
#else
char* indicator = getenv(name);
return indicator && indicator[0] != '\0';
#endif
}
#if defined(OS_POSIX)
void FixStdioStreams() {
// libuv may mark stdin/stdout/stderr as close-on-exec, which interferes
// with chromium's subprocess spawning. As a workaround, we detect if these
// streams are closed on startup, and reopen them as /dev/null if necessary.
// Otherwise, an unrelated file descriptor will be assigned as stdout/stderr
// which may cause various errors when attempting to write to them.
//
// For details see https://github.com/libuv/libuv/issues/2062
struct stat st;
if (fstat(STDIN_FILENO, &st) < 0 && errno == EBADF)
ignore_result(freopen("/dev/null", "r", stdin));
if (fstat(STDOUT_FILENO, &st) < 0 && errno == EBADF)
ignore_result(freopen("/dev/null", "w", stdout));
if (fstat(STDERR_FILENO, &st) < 0 && errno == EBADF)
ignore_result(freopen("/dev/null", "w", stderr));
}
#endif
} // namespace
#if defined(OS_WIN)
namespace crash_reporter {
extern const char kCrashpadProcess[];
}
@@ -291,74 +237,3 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
electron::ElectronCommandLine::Init(arguments.argc, arguments.argv);
return content::ContentMain(std::move(params));
}
#elif defined(OS_LINUX) // defined(OS_WIN)
int main(int argc, char* argv[]) {
FixStdioStreams();
#if BUILDFLAG(ENABLE_RUN_AS_NODE)
if (electron::fuses::IsRunAsNodeEnabled() && IsEnvSet(electron::kRunAsNode)) {
base::i18n::InitializeICU();
base::AtExitManager atexit_manager;
return electron::NodeMain(argc, argv);
}
#endif
electron::ElectronMainDelegate delegate;
content::ContentMainParams params(&delegate);
electron::ElectronCommandLine::Init(argc, argv);
params.argc = argc;
params.argv = const_cast<const char**>(argv);
base::CommandLine::Init(params.argc, params.argv);
// TODO(https://crbug.com/1176772): Remove when Chrome Linux is fully migrated
// to Crashpad.
base::CommandLine::ForCurrentProcess()->AppendSwitch(
::switches::kEnableCrashpad);
return content::ContentMain(std::move(params));
}
#else // defined(OS_LINUX)
int main(int argc, char* argv[]) {
FixStdioStreams();
#if BUILDFLAG(ENABLE_RUN_AS_NODE)
if (electron::fuses::IsRunAsNodeEnabled() && IsEnvSet(electron::kRunAsNode)) {
return ElectronInitializeICUandStartNode(argc, argv);
}
#endif
#if defined(HELPER_EXECUTABLE) && !defined(MAS_BUILD)
uint32_t exec_path_size = 0;
int rv = _NSGetExecutablePath(NULL, &exec_path_size);
if (rv != -1) {
fprintf(stderr, "_NSGetExecutablePath: get length failed\n");
abort();
}
auto exec_path = std::make_unique<char[]>(exec_path_size);
rv = _NSGetExecutablePath(exec_path.get(), &exec_path_size);
if (rv != 0) {
fprintf(stderr, "_NSGetExecutablePath: get path failed\n");
abort();
}
sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt =
sandbox::SeatbeltExecServer::CreateFromArguments(exec_path.get(), argc,
argv);
if (seatbelt.sandbox_required) {
if (!seatbelt.server) {
fprintf(stderr, "Failed to create seatbelt sandbox server.\n");
abort();
}
if (!seatbelt.server->InitializeSandbox()) {
fprintf(stderr, "Failed to initialize sandbox.\n");
abort();
}
}
#endif // defined(HELPER_EXECUTABLE) && !defined(MAS_BUILD)
return ElectronMain(argc, argv);
}
#endif // defined(OS_MAC)

32
shell/app/uv_stdio_fix.cc Normal file
View File

@@ -0,0 +1,32 @@
// Copyright (c) 2022 Slack Technologies, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/app/uv_stdio_fix.h"
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstdio>
// Copied from //base/ignore_result.h to avoid taking a dependency on //base on
// macOS.
template <typename T>
inline void ignore_result(const T&) {}
void FixStdioStreams() {
// libuv may mark stdin/stdout/stderr as close-on-exec, which interferes
// with chromium's subprocess spawning. As a workaround, we detect if these
// streams are closed on startup, and reopen them as /dev/null if necessary.
// Otherwise, an unrelated file descriptor will be assigned as stdout/stderr
// which may cause various errors when attempting to write to them.
//
// For details see https://github.com/libuv/libuv/issues/2062
struct stat st;
if (fstat(STDIN_FILENO, &st) < 0 && errno == EBADF)
ignore_result(freopen("/dev/null", "r", stdin));
if (fstat(STDOUT_FILENO, &st) < 0 && errno == EBADF)
ignore_result(freopen("/dev/null", "w", stdout));
if (fstat(STDERR_FILENO, &st) < 0 && errno == EBADF)
ignore_result(freopen("/dev/null", "w", stderr));
}

10
shell/app/uv_stdio_fix.h Normal file
View File

@@ -0,0 +1,10 @@
// Copyright (c) 2022 Slack Technologies, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ELECTRON_SHELL_APP_UV_STDIO_FIX_H_
#define ELECTRON_SHELL_APP_UV_STDIO_FIX_H_
void FixStdioStreams();
#endif // ELECTRON_SHELL_APP_UV_STDIO_FIX_H_

View File

@@ -37,7 +37,6 @@ BrowserWindow::BrowserWindow(gin::Arguments* args,
gin::Dictionary::CreateEmpty(isolate);
options.Get(options::kWebPreferences, &web_preferences);
v8::Local<v8::Value> value;
bool transparent = false;
options.Get(options::kTransparent, &transparent);
@@ -47,8 +46,9 @@ BrowserWindow::BrowserWindow(gin::Arguments* args,
#endif
// Copy the backgroundColor to webContents.
if (options.Get(options::kBackgroundColor, &value)) {
web_preferences.SetHidden(options::kBackgroundColor, value);
std::string color;
if (options.Get(options::kBackgroundColor, &color)) {
web_preferences.SetHidden(options::kBackgroundColor, color);
} else if (!vibrancy_type.empty() || transparent) {
// If the BrowserWindow is transparent or a vibrancy type has been set,
// also propagate transparency to the WebContents unless a separate
@@ -80,6 +80,7 @@ BrowserWindow::BrowserWindow(gin::Arguments* args,
// Copy the webContents option to webPreferences. This is only used internally
// to implement nativeWindowOpen option.
v8::Local<v8::Value> value;
if (options.Get("webContents", &value)) {
web_preferences.SetHidden("webContents", value);
}
@@ -373,8 +374,11 @@ void BrowserWindow::SetBackgroundColor(const std::string& color_name) {
SkColor color = ParseHexColor(color_name);
web_contents()->SetPageBaseBackgroundColor(color);
auto* rwhv = web_contents()->GetRenderWidgetHostView();
if (rwhv)
if (rwhv) {
rwhv->SetBackgroundColor(color);
static_cast<content::RenderWidgetHostViewBase*>(rwhv)
->SetContentBackgroundColor(color);
}
// Also update the web preferences object otherwise the view will be reset on
// the next load URL call
if (api_web_contents_) {

View File

@@ -89,8 +89,10 @@ gin::Handle<Tray> Tray::New(gin_helper::ErrorThrower thrower,
}
#endif
return gin::CreateHandle(thrower.isolate(),
new Tray(args->isolate(), image, guid));
auto handle = gin::CreateHandle(args->isolate(),
new Tray(args->isolate(), image, guid));
handle->Pin(args->isolate());
return handle;
}
void Tray::OnClicked(const gfx::Rect& bounds,
@@ -180,6 +182,7 @@ void Tray::OnDragEnded() {
}
void Tray::Destroy() {
Unpin();
menu_.Reset();
tray_icon_.reset();
}

View File

@@ -19,6 +19,7 @@
#include "shell/common/gin_helper/cleaned_up_at_exit.h"
#include "shell/common/gin_helper/constructible.h"
#include "shell/common/gin_helper/error_thrower.h"
#include "shell/common/gin_helper/pinnable.h"
namespace gfx {
class Image;
@@ -38,6 +39,7 @@ class Tray : public gin::Wrappable<Tray>,
public gin_helper::EventEmitterMixin<Tray>,
public gin_helper::Constructible<Tray>,
public gin_helper::CleanedUpAtExit,
public gin_helper::Pinnable<Tray>,
public TrayIconObserver {
public:
// gin_helper::Constructible

View File

@@ -599,6 +599,12 @@ bool IsDevToolsFileSystemAdded(content::WebContents* web_contents,
return file_system_paths.find(file_system_path) != file_system_paths.end();
}
void SetBackgroundColor(content::RenderWidgetHostView* rwhv, SkColor color) {
rwhv->SetBackgroundColor(color);
static_cast<content::RenderWidgetHostViewBase*>(rwhv)
->SetContentBackgroundColor(color);
}
} // namespace
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
@@ -760,8 +766,12 @@ WebContents::WebContents(v8::Isolate* isolate,
#if BUILDFLAG(ENABLE_OSR)
}
} else if (IsOffScreen()) {
bool transparent = false;
options.Get(options::kTransparent, &transparent);
// webPreferences does not have a transparent option, so if the window needs
// to be transparent, that will be set at electron_api_browser_window.cc#L57
// and we then need to pull it back out and check it here.
std::string background_color;
options.GetHidden(options::kBackgroundColor, &background_color);
bool transparent = ParseHexColor(background_color) == SK_ColorTRANSPARENT;
content::WebContents::CreateParams params(session->browser_context());
auto* view = new OffScreenWebContentsView(
@@ -1457,7 +1467,7 @@ void WebContents::HandleNewRenderFrame(
absl::optional<SkColor> color =
guest ? SK_ColorTRANSPARENT : web_preferences->GetBackgroundColor();
web_contents()->SetPageBaseBackgroundColor(color);
rwhv->SetBackgroundColor(color.value_or(SK_ColorWHITE));
SetBackgroundColor(rwhv, color.value_or(SK_ColorWHITE));
}
if (!background_throttling_)
@@ -1473,6 +1483,15 @@ void WebContents::HandleNewRenderFrame(
web_frame->Connect();
}
void WebContents::OnBackgroundColorChanged() {
absl::optional<SkColor> color = web_contents()->GetBackgroundColor();
if (color.has_value()) {
auto* const view = web_contents()->GetRenderWidgetHostView();
static_cast<content::RenderWidgetHostViewBase*>(view)
->SetContentBackgroundColor(color.value());
}
}
void WebContents::RenderFrameCreated(
content::RenderFrameHost* render_frame_host) {
HandleNewRenderFrame(render_frame_host);
@@ -2328,6 +2347,11 @@ v8::Local<v8::Promise> WebContents::SavePage(
gin_helper::Promise<void> promise(isolate);
v8::Local<v8::Promise> handle = promise.GetHandle();
if (!full_file_path.IsAbsolute()) {
promise.RejectWithErrorMessage("Path must be absolute");
return handle;
}
auto* handler = new SavePageHandler(web_contents(), std::move(promise));
handler->Handle(full_file_path, save_type);
@@ -4053,7 +4077,7 @@ gin::Handle<WebContents> WebContents::CreateFromWebPreferences(
// only set rwhv background color if a color exists
auto* rwhv = web_contents->web_contents()->GetRenderWidgetHostView();
if (rwhv && color.has_value())
rwhv->SetBackgroundColor(color.value());
SetBackgroundColor(rwhv, color.value());
}
} else {
// Create one if not.

View File

@@ -579,6 +579,7 @@ class WebContents : public ExclusiveAccessContext,
// content::WebContentsObserver:
void BeforeUnloadFired(bool proceed,
const base::TimeTicks& proceed_time) override;
void OnBackgroundColorChanged() override;
void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
void RenderFrameHostChanged(content::RenderFrameHost* old_host,

View File

@@ -67,7 +67,7 @@ bool GetProtocolLaunchPath(gin::Arguments* args, std::wstring* exe) {
std::vector<std::wstring> launch_args;
if (args->GetNext(&launch_args) && !launch_args.empty())
*exe = base::StringPrintf(L"\"%ls\" \"%ls\" \"%%1\"", exe->c_str(),
base::JoinString(launch_args, L" ").c_str());
base::JoinString(launch_args, L"\" \"").c_str());
else
*exe = base::StringPrintf(L"\"%ls\" \"%%1\"", exe->c_str());
return true;

View File

@@ -1450,6 +1450,12 @@ bool ElectronBrowserClient::PreSpawnChild(sandbox::TargetPolicy* policy,
}
#endif // defined(OS_WIN)
void BindElectronBrowser(
mojo::PendingAssociatedReceiver<electron::mojom::ElectronBrowser> receiver,
content::RenderFrameHost* frame_host) {
ElectronBrowserHandlerImpl::Create(frame_host, std::move(receiver));
}
bool ElectronBrowserClient::BindAssociatedReceiverFromFrame(
content::RenderFrameHost* render_frame_host,
const std::string& interface_name,
@@ -1461,6 +1467,13 @@ bool ElectronBrowserClient::BindAssociatedReceiverFromFrame(
render_frame_host);
return true;
}
if (interface_name == electron::mojom::ElectronBrowser::Name_) {
BindElectronBrowser(
mojo::PendingAssociatedReceiver<electron::mojom::ElectronBrowser>(
std::move(*handle)),
render_frame_host);
return true;
}
#if BUILDFLAG(ENABLE_PRINTING)
if (interface_name == printing::mojom::PrintManagerHost::Name_) {
mojo::PendingAssociatedReceiver<printing::mojom::PrintManagerHost> receiver(
@@ -1522,12 +1535,6 @@ void ElectronBrowserClient::BindHostReceiverForRenderer(
#endif
}
void BindElectronBrowser(
content::RenderFrameHost* frame_host,
mojo::PendingReceiver<electron::mojom::ElectronBrowser> receiver) {
ElectronBrowserHandlerImpl::Create(frame_host, std::move(receiver));
}
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
void BindMimeHandlerService(
content::RenderFrameHost* frame_host,
@@ -1576,8 +1583,6 @@ void ElectronBrowserClient::RegisterBrowserInterfaceBindersForFrame(
base::BindRepeating(&BindNetworkHintsHandler));
map->Add<blink::mojom::BadgeService>(
base::BindRepeating(&badging::BadgeManager::BindFrameReceiver));
map->Add<electron::mojom::ElectronBrowser>(
base::BindRepeating(&BindElectronBrowser));
map->Add<blink::mojom::KeyboardLockService>(base::BindRepeating(
&content::KeyboardLockServiceImpl::CreateMojoService));
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)

View File

@@ -15,7 +15,7 @@
namespace electron {
ElectronBrowserHandlerImpl::ElectronBrowserHandlerImpl(
content::RenderFrameHost* frame_host,
mojo::PendingReceiver<mojom::ElectronBrowser> receiver)
mojo::PendingAssociatedReceiver<mojom::ElectronBrowser> receiver)
: render_process_id_(frame_host->GetProcess()->GetID()),
render_frame_id_(frame_host->GetRoutingID()) {
content::WebContents* web_contents =
@@ -135,7 +135,7 @@ content::RenderFrameHost* ElectronBrowserHandlerImpl::GetRenderFrameHost() {
// static
void ElectronBrowserHandlerImpl::Create(
content::RenderFrameHost* frame_host,
mojo::PendingReceiver<mojom::ElectronBrowser> receiver) {
mojo::PendingAssociatedReceiver<mojom::ElectronBrowser> receiver) {
new ElectronBrowserHandlerImpl(frame_host, std::move(receiver));
}
} // namespace electron

View File

@@ -23,10 +23,11 @@ class ElectronBrowserHandlerImpl : public mojom::ElectronBrowser,
public:
explicit ElectronBrowserHandlerImpl(
content::RenderFrameHost* render_frame_host,
mojo::PendingReceiver<mojom::ElectronBrowser> receiver);
mojo::PendingAssociatedReceiver<mojom::ElectronBrowser> receiver);
static void Create(content::RenderFrameHost* frame_host,
mojo::PendingReceiver<mojom::ElectronBrowser> receiver);
static void Create(
content::RenderFrameHost* frame_host,
mojo::PendingAssociatedReceiver<mojom::ElectronBrowser> receiver);
// disable copy
ElectronBrowserHandlerImpl(const ElectronBrowserHandlerImpl&) = delete;
@@ -75,7 +76,7 @@ class ElectronBrowserHandlerImpl : public mojom::ElectronBrowser,
const int render_process_id_;
const int render_frame_id_;
mojo::Receiver<mojom::ElectronBrowser> receiver_{this};
mojo::AssociatedReceiver<mojom::ElectronBrowser> receiver_{this};
base::WeakPtrFactory<ElectronBrowserHandlerImpl> weak_factory_{this};
};

View File

@@ -455,7 +455,8 @@ void ElectronBrowserMainParts::WillRunMainMessageLoop(
std::unique_ptr<base::RunLoop>& run_loop) {
js_env_->OnMessageLoopCreated();
exit_code_ = content::RESULT_CODE_NORMAL_EXIT;
Browser::Get()->SetMainMessageLoopQuitClosure(run_loop->QuitClosure());
Browser::Get()->SetMainMessageLoopQuitClosure(
run_loop->QuitWhenIdleClosure());
}
void ElectronBrowserMainParts::PostCreateMainMessageLoop() {

View File

@@ -12,6 +12,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "shell/browser/browser.h"
#include "shell/browser/native_window_features.h"
#include "shell/browser/window_list.h"
#include "shell/common/color_util.h"
#include "shell/common/gin_helper/dictionary.h"
@@ -24,6 +25,11 @@
#include "ui/display/win/screen_win.h"
#endif
#if defined(USE_OZONE) || defined(USE_X11)
#include "ui/base/ui_base_features.h"
#include "ui/ozone/public/ozone_platform.h"
#endif
namespace gin {
template <>
@@ -90,7 +96,15 @@ NativeWindow::NativeWindow(const gin_helper::Dictionary& options,
options.Get(options::ktitleBarOverlay, &titlebar_overlay_);
} else if (titlebar_overlay->IsObject()) {
titlebar_overlay_ = true;
#if !defined(OS_WIN)
gin_helper::Dictionary titlebar_overlay =
gin::Dictionary::CreateEmpty(options.isolate());
options.Get(options::ktitleBarOverlay, &titlebar_overlay);
int height;
if (titlebar_overlay.Get(options::kOverlayHeight, &height))
titlebar_overlay_height_ = height;
#if !(defined(OS_WIN) || defined(OS_MAC))
DCHECK(false);
#endif
}
@@ -99,6 +113,17 @@ NativeWindow::NativeWindow(const gin_helper::Dictionary& options,
if (parent)
options.Get("modal", &is_modal_);
#if defined(USE_OZONE)
// Ozone X11 likes to prefer custom frames, but we don't need them unless
// on Wayland.
if (base::FeatureList::IsEnabled(features::kWaylandWindowDecorations) &&
!ui::OzonePlatform::GetInstance()
->GetPlatformRuntimeProperties()
.supports_server_side_window_decorations) {
has_client_frame_ = true;
}
#endif
WindowList::AddWindow(this);
}

View File

@@ -327,10 +327,12 @@ class NativeWindow : public base::SupportsUserData,
kCustomButtonsOnHover,
};
TitleBarStyle title_bar_style() const { return title_bar_style_; }
int titlebar_overlay_height() const { return titlebar_overlay_height_; }
bool has_frame() const { return has_frame_; }
void set_has_frame(bool has_frame) { has_frame_ = has_frame; }
bool has_client_frame() const { return has_client_frame_; }
bool transparent() const { return transparent_; }
bool enable_larger_than_screen() const { return enable_larger_than_screen_; }
@@ -362,6 +364,10 @@ class NativeWindow : public base::SupportsUserData,
// The boolean parsing of the "titleBarOverlay" option
bool titlebar_overlay_ = false;
// The custom height parsed from the "height" option in a Object
// "titleBarOverlay"
int titlebar_overlay_height_ = 0;
// The "titleBarStyle" option.
TitleBarStyle title_bar_style_ = TitleBarStyle::kNormal;
@@ -376,6 +382,11 @@ class NativeWindow : public base::SupportsUserData,
// Whether window has standard frame.
bool has_frame_ = true;
// Whether window has standard frame, but it's drawn by Electron (the client
// application) instead of the OS. Currently only has meaning on Linux for
// Wayland hosts.
bool has_client_frame_ = false;
// Whether window is transparent.
bool transparent_ = false;

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