Compare commits

...

77 Commits

Author SHA1 Message Date
Electron Bot
735d8b84f0 Bump v12.0.0-nightly.20200918 2020-09-18 07:31:48 -07:00
Shelley Vohr
a65f7f7d42 fix: close window when leave fs crash (#25468) 2020-09-17 17:40:07 -06:00
bitdisaster
2cfa41e6e0 feat: read/write Toast Activator CLSID in shortcuts (#25493)
* read/write Toast Activator CLSID

* docs

* tests

* tweaks
2020-09-17 15:17:44 -07:00
Shelley Vohr
77038b7bda chore: upgrade to Node.js v14.9.0 (#25249) 2020-09-17 16:08:57 -06:00
Electron Bot
4d1dab849f Bump v12.0.0-nightly.20200917 2020-09-17 07:32:08 -07:00
Cheng Zhao
0b055b2fb8 test: retry the "v8 samples" test for a few times (#25477) 2020-09-17 10:04:53 +09:00
mlaurencin
53aaeb7a16 fix: prevent destroyed view references from causing crashes (#25411)
Closes #21666.

This PR is fixing crashes caused by referencing and attempting to modify previously destroyed views.
Before, when a view was destroyed and then the contents were referenced for modification, the system would crash as undefined memory was accessed. This fix explicitly makes the pointer to the destroyed view's contents null, so that this will not happen.
2020-09-16 18:10:49 -06:00
Milan Burda
e0a25cb1e3 build: fix build with enable_pdf_viewer=false (#25494) 2020-09-17 01:15:01 +03:00
Cheng Zhao
993eab691f fix: disable CORS when webSecurity is disabled (#25463) 2020-09-16 14:55:53 -07:00
Jeremy Rose
a200b15600 docs: update menu example to avoid remote (#25291) 2020-09-16 14:32:32 -07:00
Jeremy Rose
ba55aaa53b fix: check for destroyed webcontents in converter (#25431) 2020-09-16 12:25:49 -07:00
Electron Bot
1ba46a91b6 Bump v12.0.0-nightly.20200916 2020-09-16 07:31:16 -07:00
Shelley Vohr
fa7a29e84b chore: log hint on renderer crash (#25317) 2020-09-15 13:01:50 -06:00
Cheng Zhao
e5933c6910 fix: ensure ready-to-show event is fired (#25448)
* fix: ensure ready-to-show event is fired

* test: acutally draw something when capturePage
2020-09-15 12:48:39 -06:00
Cheng Zhao
2091fd7dd9 test: make a few tests hide their windows (#25466) 2020-09-15 12:48:12 -06:00
Samuel Maddock
45170fdbd7 fix(extensions): define platform info to prevent renderer crash (#25357) 2020-09-15 10:29:32 -06:00
Electron Bot
fbf32f697f Bump v12.0.0-nightly.20200915 2020-09-15 07:31:30 -07:00
Jeremy Rose
459a95aaec fix: call node::Stop on exit (#25430) 2020-09-14 14:08:46 -07:00
Samuel Attard
b1d8057ec9 chore: update dependencies (#25456) 2020-09-14 14:00:15 -07:00
Jeremy Rose
87d67a9365 refactor: use owner window for BrowserWindow.fromWebContents (#25408) 2020-09-14 13:49:57 -07:00
Jeremy Rose
9f4a097e03 feat: remove getMediaSourceIdForWebContents() (#25414)
This reverts commit 204f001c5d.
2020-09-14 10:38:05 -07:00
Jeremy Rose
5de7eb3618 docs: remove references to remote from docs (#25416) 2020-09-14 10:36:54 -07:00
Charles Kerr
7f885bd266 chore: remove unused code from our js scripts (#25419) 2020-09-14 10:22:13 -07:00
Electron Bot
bc9816b206 Bump v12.0.0-nightly.20200914 2020-09-14 07:33:06 -07:00
overkill
633e5d8503 chore: change == None to is None (#25202)
According to LGTM, this change will improve code efficiency.
https://lgtm.com/rules/7900090/
2020-09-13 20:43:16 -06:00
Charles Kerr
9b08fbefe5 chore: remove unused imports in our python scripts (#25406)
Seen at https://lgtm.com/projects/g/electron/electron/?mode=list&id=py%2Funused-import
and confirmed with manual inspection.
2020-09-14 10:25:49 +09:00
Charles Kerr
70e3aa0182 refactor: add a wrapper for wrangling uv handles. (#25332)
* refactor: add a wrapper for wrangling uv handles.

Part 1 of a fix for #25248, #22069.

Place the uv_asyncs owned by NodeBindings, ElectronBindings inside a new
UvHandle wrapper class which manages uv_handles' need for their closed()
callback to be invoked before the handles' memory can be freed.

* chore: make lint happy

* refactor: use DCHECK_EQ() instead of DCHECK()

* refactor: fix oops
2020-09-14 09:53:50 +09:00
Chris Davis
a3389d017f fix: Ensure electron delay loads the same modules as chromium (#25428)
* Ensure electron delay loads the appropriate modules as chromium on windows

This change adds the same module delay load list that chromium uses for electron.  Some modules were already getting delay loaded from other build files in chromium but not the main list via //build/config/win:delayloads.  We do not include the list of delay loads in delayloads_not_for_child_dll as those have issues being loaded in sandboxes processes.  This will reduce the overall reference set impact of the electron processes.

* fix: Ensure win modules are properly delayloaded

* chore: fix linting

Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
2020-09-11 23:01:41 -07:00
Jeremy Rose
ce86591459 chore: add wg-security as required reviewer for rpc-server changes (#25415) 2020-09-11 11:34:31 -07:00
Electron Bot
7d56ca7360 Bump v12.0.0-nightly.20200911 2020-09-11 07:31:17 -07:00
Jeremy Rose
cd455c8b40 test: reduce flakiness in pdf test (#25407) 2020-09-10 16:47:36 -07:00
John Kleinschmidt
acf5d487d2 fix: crash on nativeImage on Windows on ARM (#25396)
* fix: nativeImage on WOA

* Remove old ldflag

* maybe this will work ¯\_(ツ)_/¯
2020-09-10 14:42:41 -04:00
Jeremy Rose
dd781c4f63 chore: deprecate remote (#25293) 2020-09-10 09:17:17 -07:00
Electron Bot
98683190b4 Bump v12.0.0-nightly.20200910 2020-09-10 07:32:25 -07:00
Samuel Maddock
1815b95e74 refactor(extensions): break load warnings into newlines (#25358) 2020-09-10 11:39:45 +09:00
Valentin Hăloiu
a829ae56b2 build: use python 2 shebang for git scripts (#25335) 2020-09-10 10:05:19 +09:00
Electron Bot
e6fbbf4325 Bump v12.0.0-nightly.20200909 2020-09-09 07:31:32 -07:00
Shelley Vohr
f6df79b927 fix: bind fake mojo service for badging (#25294)
* fix: bind fake mojo service for badging

* Add a test
2020-09-08 11:13:56 -04:00
Samuel Maddock
5a8046c994 fix(extensions): devtools now open for background pages (#22217)
refactor(extensions): remove unused InitWithBrowserContext method

fix(extensions): release background page WebContents to avoid crash

The background page WebContents instance is managed by the ExtensionHost.

fix(extensions): open background page devtools detached by default

test(extensions): add background page devtools test

chore: test fix for null web_contents()

fix: close background page devtools in test after opening
2020-09-08 20:55:40 +09:00
Erick Zhao
ae5776041e docs: full links to MD files in development README (#24963) 2020-09-08 20:37:47 +09:00
Erick Zhao
f7d9d68e14 docs: clarify a11y docs (#24973)
* docs: remove misleading sentence in a11y docs

* Update accessibility.md

* link
2020-09-08 20:37:00 +09:00
Jeremy Rose
2c5c51afb9 fix: update node certdata to NSS 3.56 (#25313) 2020-09-08 20:28:04 +09:00
Samuel Maddock
860e14c0da chore(extensions): remove old renderer code (#25347) 2020-09-08 20:11:38 +09:00
Electron Bot
31322400e7 Bump v12.0.0-nightly.20200907 2020-09-07 07:31:59 -07:00
Samuel Attard
4ad9bcb8b5 fix: handle electron script errors better (#25328) 2020-09-04 14:53:49 -07:00
Electron Bot
29c1248e96 Bump v12.0.0-nightly.20200904 2020-09-04 07:31:11 -07:00
Samuel Attard
a6b9f9d8e5 fix: only focus a webContents if the window was not initially hidden (#25292) 2020-09-04 15:57:29 +09:00
Jeremy Rose
d305fe7d30 docs: breaking changes for moveItemToTrash (#25286) 2020-09-03 12:44:16 -07:00
Jeremy Rose
4dc09ea9dc feat: [crashReporter] enable compression by default (#25288) 2020-09-03 12:43:58 -07:00
Charles Kerr
4484e95fc8 chore: graceful handling of notes with sub-lists (#25279)
* chore: graceful handling of notes with sub-lists

Handle multine release notes that contain their own bullet points.

Also, if a release note begins with a bullet point, remove it because it
will confuse the markdown parser to have two bullet points.
2020-09-03 14:42:48 -05:00
Robo
03e60cce8b fix: avoid creating client_id file for empty DIR_CRASH_DUMPS (#25296) 2020-09-03 11:52:43 -07:00
Electron Bot
733d56e908 Bump v12.0.0-nightly.20200903 2020-09-03 07:32:01 -07:00
Cheng Zhao
43485b8705 fix: multiple dock icons when calling dock.show/hide (#25269)
* fix: mulitple dock icons when calling dock.show/hide

* test: run dock.show tests after dock.hide tests
2020-09-03 20:46:24 +09:00
Jeremy Rose
bda6378685 chore: remove "no breaking changes" warning in PR template (#25285) 2020-09-02 11:56:10 -07:00
Jeremy Rose
1b6534b326 feat: add shell.trashItem() to replace shell.moveItemToTrash() (#25114) 2020-09-02 10:32:33 -07:00
Shelley Vohr
e9e7eee25e fix: provide asynchronous cleanup hooks in n-api (#25135) 2020-09-02 10:22:05 -07:00
Electron Bot
7e698df8f3 Bump v12.0.0-nightly.20200902 2020-09-02 07:32:22 -07:00
morgan-sam
e0611d0946 docs: setZoomLevel chromium zoom policy (#25105) 2020-09-02 10:06:58 +09:00
Samuel Attard
184e72fafd revert: "fix: reply notifs sometimes destroyed too early" (#25247)
* Revert "fix: reply notifs sometimes destroyed too early (#25086)"

This reverts commit bea6c9e4e1.

* nothing
2020-09-02 10:02:47 +09:00
Eryk Rakowski
3745b76da8 feat(extensions): add support for some chrome.management APIs (#25098)
* fix: initialize management policy

* fix(extensions): crash when using chrome.management

* test: add tests

* docs: add a note about chrome.management

* fix: lint errors

* fix: lint errors

* fix: remove favicon_service include

* fix: add missing management permission

* docs: more supported apis

* fix: extensions.md line endings
2020-09-02 09:59:56 +09:00
Jeremy Rose
bf7dbff858 docs: note remote deprecation in docs/api/remote (#24941) 2020-08-31 11:27:00 -07:00
John Kleinschmidt
7c10f86c6e ci: cleanup up test app directories (#25145)
* ci: cleanup up test app directories

* ci: use electron prefix for a testing apps so that the can be cleaned up

* Revert "ci: cleanup up test app directories"

This reverts commit a47daba812.

* fixup test due to app name change
2020-08-31 14:07:12 -04:00
Electron Bot
9803e4d526 Bump v12.0.0-nightly.20200831 2020-08-31 07:32:25 -07:00
Robo
068b464e13 fix: client area inset calculation when maximized for framless windows (#25052)
* adopt per monitor scale factor

* fix: client area inset calculation when maximized

* address review feedback

* pass correct glass insets to GetDwmFrameInsetsInPixels

* remove unused code

* Windows 8 and 10 use the same DWM frame calculation

Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2020-08-31 16:55:50 +09:00
Milan Burda
a09694ae85 chore: replace CRLF with LF (#25161)
* chore: replace CRLF with LF

* chore: replace CRLF with LF in docs and tests

Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2020-08-31 16:52:11 +09:00
Cheng Zhao
e06a1c2746 docs: fix supported platforms of powerMonitor (#25149) 2020-08-31 16:46:10 +09:00
Shelley Vohr
c5320b3951 fix: save dialog extensions should be deterministic (#25164) 2020-08-28 09:40:47 -07:00
Electron Bot
6cc960f214 Bump v12.0.0-nightly.20200828 2020-08-28 07:32:29 -07:00
Shelley Vohr
a4b6fce907 fix: honor pageRanges when printing (#25064) 2020-08-27 20:21:29 -07:00
Cheng Zhao
8f727b3569 fix: do not reset process_id in URLLoaderFactoryParams (#25139) 2020-08-28 10:43:08 +09:00
Shelley Vohr
95073decd3 chore: remove bv before setting owner window (#25172) 2020-08-27 16:24:52 -07:00
Shelley Vohr
e8ef1ef252 chore: wrap add/remove view in extra check (#25166) 2020-08-27 13:04:06 -07:00
Samuel Attard
075502477e chore: we do not use the nightly tag on npm (#25147) 2020-08-27 12:11:27 -07:00
Milan Burda
97755bbd85 fix: resolve RegisterSuspendResumeNotification dynamically (#25162) 2020-08-27 11:20:15 -07:00
Markus Olsson
bab69ae4d2 fix: make shell.moveItemToTrash return false on Windows when move unsuccessful (#25124) 2020-08-27 09:55:33 -07:00
Electron Bot
443540fd13 Bump v12.0.0-nightly.20200827 2020-08-27 07:31:51 -07:00
Cheng Zhao
5e1950ceff chore: force source code and markdown files to use LF line ending (#25134) 2020-08-27 10:25:39 +09:00
273 changed files with 6521 additions and 4029 deletions

10
.gitattributes vendored
View File

@@ -2,3 +2,13 @@
# files to be checked out with LF endings even if core.autocrlf is true.
*.patch text eol=lf
patches/**/.patches merge=union
# Source code and markdown files should always use LF as line ending.
*.cc text eol=lf
*.mm text eol=lf
*.h text eol=lf
*.js text eol=lf
*.ts text eol=lf
*.py text eol=lf
*.ps1 text eol=lf
*.md text eol=lf

3
.github/CODEOWNERS vendored
View File

@@ -10,3 +10,6 @@ DEPS @electron/wg-upgrades
# Releases WG
/npm/ @electron/wg-releases
/script/release @electron/wg-releases
# Security WG
/lib/browser/rpc-server.ts @electron/wg-security

View File

@@ -15,7 +15,6 @@ Contributors guide: https://github.com/electron/electron/blob/master/CONTRIBUTIN
- [ ] relevant documentation is changed or added
- [ ] PR title follows semantic [commit guidelines](https://github.com/electron/electron/blob/master/docs/development/pull-requests.md#commit-message-guidelines)
- [ ] [PR release notes](https://github.com/electron/clerk/blob/master/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/master/README.md#examples).
- [ ] This is **NOT A BREAKING CHANGE**. Breaking changes may not be merged to master until 11-x-y is branched.
#### Release Notes

View File

@@ -642,6 +642,7 @@ source_set("electron_lib") {
"shell/common/extensions/api",
"shell/common/extensions/api:extensions_features",
"//chrome/browser/resources:component_extension_resources",
"//components/update_client:update_client",
"//components/zoom",
"//extensions/browser",
"//extensions/browser:core_api_provider",
@@ -1138,22 +1139,24 @@ if (is_mac) {
"//components/crash/core/app:run_as_crashpad_handler",
]
ldflags = []
libs = [
"comctl32.lib",
"uiautomationcore.lib",
"wtsapi32.lib",
]
configs += [ "//build/config/win:windowed" ]
ldflags = [
# Windows 7 doesn't have these DLLs.
# TODO: are there other DLLs we need to list here to be win7
# compatible?
"/DELAYLOAD:api-ms-win-core-winrt-l1-1-0.dll",
"/DELAYLOAD:api-ms-win-core-winrt-string-l1-1-0.dll",
configs += [
"//build/config/win:windowed",
"//build/config/win:delayloads",
]
if (target_cpu == "arm64") {
configs -= [ "//build/config/win:cfi_linker" ]
ldflags += [ "/guard:cf,nolongjmp" ]
}
# This is to support renaming of electron.exe. node-gyp has hard-coded
# executable names which it will recognise as node. This module definition
# file claims that the electron executable is in fact named "node.exe",

2
DEPS
View File

@@ -16,7 +16,7 @@ vars = {
'chromium_version':
'b04584161e07d4ac110045b7647fa8a81f5f0709',
'node_version':
'v12.18.3',
'v14.9.0',
'nan_version':
'2c4ee8a32a299eada3cd6e468bbd0a473bfea96d',
'squirrel.mac_version':

View File

@@ -1 +1 @@
11.0.0-nightly.20200826
12.0.0-nightly.20200918

View File

@@ -11,7 +11,6 @@ import find_depot_tools
from vs_toolchain import \
SetEnvironmentAndGetRuntimeDllDirs, \
SetEnvironmentAndGetSDKDir, \
GetVisualStudioVersion, \
NormalizePath
sys.path.append("%s/win_toolchain" % find_depot_tools.add_depot_tools_to_path())

View File

@@ -1,6 +1,5 @@
import sys
import os
import subprocess
def main(argv):
cwd = argv[1]

View File

@@ -10,10 +10,9 @@ config.output = {
filename: path.basename(outPath)
};
const { wrapInitWithProfilingTimeout } = config;
delete config.wrapInitWithProfilingTimeout;
const { wrapInitWithProfilingTimeout, wrapInitWithTryCatch, ...webpackConfig } = config;
webpack(config, (err, stats) => {
webpack(webpackConfig, (err, stats) => {
if (err) {
console.error(err);
process.exit(1);
@@ -21,9 +20,17 @@ webpack(config, (err, stats) => {
console.error(stats.toString('normal'));
process.exit(1);
} else {
let contents = fs.readFileSync(outPath, 'utf8');
if (wrapInitWithTryCatch) {
contents = `try {
${contents}
} catch (err) {
console.error('Electron ${webpackConfig.output.filename} script failed to run');
console.error(err);
}`;
}
if (wrapInitWithProfilingTimeout) {
const contents = fs.readFileSync(outPath, 'utf8');
const newContents = `function ___electron_webpack_init__() {
contents = `function ___electron_webpack_init__() {
${contents}
};
if ((globalThis.process || binding.process).argv.includes("--profile-electron-init")) {
@@ -31,8 +38,8 @@ if ((globalThis.process || binding.process).argv.includes("--profile-electron-in
} else {
___electron_webpack_init__();
}`;
fs.writeFileSync(outPath, newContents);
}
fs.writeFileSync(outPath, contents);
process.exit(0);
}
});

View File

@@ -69,7 +69,8 @@ module.exports = ({
loadElectronFromAlternateTarget,
targetDeletesNodeGlobals,
target,
wrapInitWithProfilingTimeout
wrapInitWithProfilingTimeout,
wrapInitWithTryCatch
}) => {
let entry = path.resolve(electronRoot, 'lib', target, 'init.ts');
if (!fs.existsSync(entry)) {
@@ -87,6 +88,7 @@ module.exports = ({
filename: `${target}.bundle.js`
},
wrapInitWithProfilingTimeout,
wrapInitWithTryCatch,
resolve: {
alias: {
'@electron/internal': path.resolve(electronRoot, 'lib'),

View File

@@ -1,4 +1,5 @@
module.exports = require('./webpack.config.base')({
target: 'isolated_renderer',
alwaysHasNode: false
alwaysHasNode: false,
wrapInitWithTryCatch: true
});

View File

@@ -2,5 +2,6 @@ module.exports = require('./webpack.config.base')({
target: 'renderer',
alwaysHasNode: true,
targetDeletesNodeGlobals: true,
wrapInitWithProfilingTimeout: true
wrapInitWithProfilingTimeout: true,
wrapInitWithTryCatch: true
});

View File

@@ -1,5 +1,6 @@
module.exports = require('./webpack.config.base')({
target: 'sandboxed_renderer',
alwaysHasNode: false,
wrapInitWithProfilingTimeout: true
wrapInitWithProfilingTimeout: true,
wrapInitWithTryCatch: true
});

View File

@@ -2,5 +2,6 @@ module.exports = require('./webpack.config.base')({
target: 'worker',
loadElectronFromAlternateTarget: 'renderer',
alwaysHasNode: true,
targetDeletesNodeGlobals: true
targetDeletesNodeGlobals: true,
wrapInitWithTryCatch: true
});

View File

@@ -56,7 +56,7 @@ an issue:
* [Accessibility](tutorial/accessibility.md)
* [Spectron](tutorial/accessibility.md#spectron)
* [Devtron](tutorial/accessibility.md#devtron)
* [Enabling Accessibility](tutorial/accessibility.md#enabling-accessibility)
* [Manually Enabling Accessibility Features](tutorial/accessibility.md#manually-enabling-accessibility-features)
* [Testing and Debugging](tutorial/application-debugging.md)
* [Debugging the Main Process](tutorial/debugging-main-process.md)
* [Debugging the Main Process with Visual Studio Code](tutorial/debugging-main-process-vscode.md)

View File

@@ -501,7 +501,7 @@ Returns:
Emitted when `desktopCapturer.getSources()` is called in the renderer process of `webContents`.
Calling `event.preventDefault()` will make it return empty sources.
### Event: 'remote-require'
### Event: 'remote-require' _Deprecated_
Returns:
@@ -513,7 +513,7 @@ Emitted when `remote.require()` is called in the renderer process of `webContent
Calling `event.preventDefault()` will prevent the module from being returned.
Custom value can be returned by setting `event.returnValue`.
### Event: 'remote-get-global'
### Event: 'remote-get-global' _Deprecated_
Returns:
@@ -525,7 +525,7 @@ Emitted when `remote.getGlobal()` is called in the renderer process of `webConte
Calling `event.preventDefault()` will prevent the global from being returned.
Custom value can be returned by setting `event.returnValue`.
### Event: 'remote-get-builtin'
### Event: 'remote-get-builtin' _Deprecated_
Returns:
@@ -537,7 +537,7 @@ Emitted when `remote.getBuiltin()` is called in the renderer process of `webCont
Calling `event.preventDefault()` will prevent the module from being returned.
Custom value can be returned by setting `event.returnValue`.
### Event: 'remote-get-current-window'
### Event: 'remote-get-current-window' _Deprecated_
Returns:
@@ -548,7 +548,7 @@ Emitted when `remote.getCurrentWindow()` is called in the renderer process of `w
Calling `event.preventDefault()` will prevent the object from being returned.
Custom value can be returned by setting `event.returnValue`.
### Event: 'remote-get-current-web-contents'
### Event: 'remote-get-current-web-contents' _Deprecated_
Returns:

View File

@@ -8,9 +8,6 @@ Process: [Main](../glossary.md#main-process)
// In the main process.
const { BrowserWindow } = require('electron')
// Or use `remote` from the renderer process.
// const { BrowserWindow } = require('electron').remote
const win = new BrowserWindow({ width: 800, height: 600 })
// Load a remote URL

View File

@@ -59,7 +59,7 @@ The `crashReporter` module has the following methods:
* `rateLimit` Boolean (optional) _macOS_ _Windows_ - If true, limit the
number of crashes uploaded to 1/hour. Default is `false`.
* `compress` Boolean (optional) - If true, crash reports will be compressed
and uploaded with `Content-Encoding: gzip`. Default is `false`.
and uploaded with `Content-Encoding: gzip`. Default is `true`.
* `extra` Record<String, String> (optional) - Extra string key/value
annotations that will be sent along with crash reports that are generated
in the main process. Only string values are supported. Crashes generated in

View File

@@ -72,50 +72,6 @@ const constraints = {
}
```
This example shows how to capture a video from a [WebContents](web-contents.md)
```javascript
// In the renderer process.
const { desktopCapturer, remote } = require('electron')
desktopCapturer.getMediaSourceIdForWebContents(remote.getCurrentWebContents().id).then(async mediaSourceId => {
try {
const stream = await navigator.mediaDevices.getUserMedia({
audio: {
mandatory: {
chromeMediaSource: 'tab',
chromeMediaSourceId: mediaSourceId
}
},
video: {
mandatory: {
chromeMediaSource: 'tab',
chromeMediaSourceId: mediaSourceId,
minWidth: 1280,
maxWidth: 1280,
minHeight: 720,
maxHeight: 720
}
}
})
handleStream(stream)
} catch (e) {
handleError(e)
}
})
function handleStream (stream) {
const video = document.querySelector('video')
video.srcObject = stream
video.onloadedmetadata = (e) => video.play()
}
function handleError (e) {
console.log(e)
}
```
## Methods
The `desktopCapturer` module has the following methods:
@@ -138,15 +94,6 @@ Returns `Promise<DesktopCapturerSource[]>` - Resolves with an array of [`Desktop
**Note** Capturing the screen contents requires user consent on macOS 10.15 Catalina or higher,
which can detected by [`systemPreferences.getMediaAccessStatus`].
### `desktopCapturer.getMediaSourceIdForWebContents(webContentsId)`
* `webContentsId` number - Id of the WebContents to get stream of
Returns `Promise<string>` - Resolves with the identifier of a WebContents stream, this identifier can be
used with [`navigator.mediaDevices.getUserMedia`].
The identifier is **only valid for 10 seconds**.
The identifier may be empty if not requested from a renderer process.
[`navigator.mediaDevices.getUserMedia`]: https://developer.mozilla.org/en/docs/Web/API/MediaDevices/getUserMedia
[`systemPreferences.getMediaAccessStatus`]: system-preferences.md#systempreferencesgetmediaaccessstatusmediatype-macos

View File

@@ -11,14 +11,6 @@ const { dialog } = require('electron')
console.log(dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] }))
```
The Dialog is opened from Electron's main thread. If you want to use the dialog
object from a renderer process, remember to access it using the remote:
```javascript
const { dialog } = require('electron').remote
console.log(dialog)
```
## Methods
The `dialog` module has the following methods:

View File

@@ -74,6 +74,7 @@ The following methods of `chrome.runtime` are supported:
- `chrome.runtime.getBackgroundPage`
- `chrome.runtime.getManifest`
- `chrome.runtime.getPlatformInfo`
- `chrome.runtime.getURL`
- `chrome.runtime.connect`
- `chrome.runtime.sendMessage`
@@ -102,3 +103,15 @@ The following methods of `chrome.tabs` are supported:
> **Note:** In Chrome, passing `-1` as a tab ID signifies the "currently active
> tab". Since Electron has no such concept, passing `-1` as a tab ID is not
> supported and will raise an error.
### `chrome.management`
The following methods of `chrome.management` are supported:
- `chrome.management.getAll`
- `chrome.management.get`
- `chrome.management.getSelf`
- `chrome.management.getPermissionWarningsById`
- `chrome.management.getPermissionWarningsByManifest`
- `chrome.management.onEnabled`
- `chrome.management.onDisabled`

View File

@@ -112,13 +112,19 @@ optional parameter can be used to forward mouse move messages to the web page,
allowing events such as `mouseleave` to be emitted:
```javascript
const win = require('electron').remote.getCurrentWindow()
const { ipcRenderer } = require('electron')
const el = document.getElementById('clickThroughElement')
el.addEventListener('mouseenter', () => {
win.setIgnoreMouseEvents(true, { forward: true })
ipcRenderer.send('set-ignore-mouse-events', true, { forward: true })
})
el.addEventListener('mouseleave', () => {
win.setIgnoreMouseEvents(false)
ipcRenderer.send('set-ignore-mouse-events', false)
})
// Main process
const { ipcMain } = require('electron')
ipcMain.on('set-ignore-mouse-events', (event, ...args) => {
BrowserWindow.fromWebContents(event.sender).setIgnoreMouseEvents(...args)
})
```

View File

@@ -141,13 +141,7 @@ can have a submenu.
## Examples
The `Menu` class is only available in the main process, but you can also use it
in the render process via the [`remote`](remote.md) module.
### Main process
An example of creating the application menu in the main process with the
simple template API:
An example of creating the application menu with the simple template API:
```javascript
const { app, Menu } = require('electron')
@@ -257,26 +251,36 @@ Menu.setApplicationMenu(menu)
### Render process
Below is an example of creating a menu dynamically in a web page
(render process) by using the [`remote`](remote.md) module, and showing it when
the user right clicks the page:
To create menus initiated by the renderer process, send the required
information to the main process using IPC and have the main process display the
menu on behalf of the renderer.
```html
<!-- index.html -->
<script>
const { remote } = require('electron')
const { Menu, MenuItem } = remote
const menu = new Menu()
menu.append(new MenuItem({ label: 'MenuItem1', click() { console.log('item 1 clicked') } }))
menu.append(new MenuItem({ type: 'separator' }))
menu.append(new MenuItem({ label: 'MenuItem2', type: 'checkbox', checked: true }))
Below is an example of showing a menu when the user right clicks the page:
```js
// renderer
window.addEventListener('contextmenu', (e) => {
e.preventDefault()
menu.popup({ window: remote.getCurrentWindow() })
}, false)
</script>
ipcRenderer.send('show-context-menu')
})
ipcRenderer.on('context-menu-command', (e, command) => {
// ...
})
// main
ipcMain.on('show-context-menu', (event) => {
const template = [
{
label: 'Menu Item 1',
click: () => { event.sender.send('context-menu-command', 'menu-item-1') }
},
{ type: 'separator' },
{ label: 'Menu Item 2', type: 'checkbox', checked: true }
]
const menu = Menu.buildFromTemplate(template)
menu.popup(BrowserWindow.fromWebContents(event.sender))
})
```
## Notes on macOS Application Menu

View File

@@ -8,19 +8,19 @@ Process: [Main](../glossary.md#main-process)
The `powerMonitor` module emits the following events:
### Event: 'suspend'
### Event: 'suspend' _macOS_ _Windows_
Emitted when the system is suspending.
### Event: 'resume'
### Event: 'resume' _macOS_ _Windows_
Emitted when system is resuming.
### Event: 'on-ac' _Windows_
### Event: 'on-ac' _macOS_ _Windows_
Emitted when the system changes to AC power.
### Event: 'on-battery' _Windows_
### Event: 'on-battery' _macOS_ _Windows_
Emitted when system changes to battery power.

View File

@@ -4,6 +4,16 @@
Process: [Renderer](../glossary.md#renderer-process)
> ⚠️ WARNING ⚠️
> The `remote` module is [deprecated](https://github.com/electron/electron/issues/21408).
> Instead of `remote`, use [`ipcRenderer`](ipc-renderer.md) and
> [`ipcMain`](ipc-main.md).
>
> Read more about why the `remote` module is deprecated [here](https://medium.com/@nornagon/electrons-remote-module-considered-harmful-70d69500f31).
>
> If you still want to use `remote` despite the performance and security
> concerns, see [@electron/remote](https://github.com/electron/remote).
The `remote` module provides a simple way to do inter-process communication
(IPC) between the renderer process (web page) and the main process.
@@ -140,11 +150,32 @@ console.log(app)
The `remote` module has the following methods:
### `remote.require(module)`
### `remote.getCurrentWindow()`
* `module` String
Returns [`BrowserWindow`](browser-window.md) - The window to which this web page
belongs.
Returns `any` - The object returned by `require(module)` in the main process.
**Note:** Do not use `removeAllListeners` on [`BrowserWindow`](browser-window.md).
Use of this can remove all [`blur`](https://developer.mozilla.org/en-US/docs/Web/Events/blur)
listeners, disable click events on touch bar buttons, and other unintended
consequences.
### `remote.getCurrentWebContents()`
Returns [`WebContents`](web-contents.md) - The web contents of this web page.
### `remote.getGlobal(name)`
* `name` String
Returns `any` - The global variable of `name` (e.g. `global[name]`) in the main
process.
## Properties
### `remote.require`
A `NodeJS.Require` function equivalent to `require(module)` in the main process.
Modules specified by their relative path will resolve relative to the entrypoint
of the main process.
@@ -176,28 +207,6 @@ module.exports = 'bar'
const foo = require('electron').remote.require('./foo') // bar
```
### `remote.getCurrentWindow()`
Returns [`BrowserWindow`](browser-window.md) - The window to which this web page
belongs.
**Note:** Do not use `removeAllListeners` on [`BrowserWindow`](browser-window.md).
Use of this can remove all [`blur`](https://developer.mozilla.org/en-US/docs/Web/Events/blur)
listeners, disable click events on touch bar buttons, and other unintended
consequences.
### `remote.getCurrentWebContents()`
Returns [`WebContents`](web-contents.md) - The web contents of this web page.
### `remote.getGlobal(name)`
* `name` String
Returns `any` - The global variable of `name` (e.g. `global[name]`) in the main
process.
## Properties
### `remote.process` _Readonly_

View File

@@ -88,26 +88,17 @@ and preload.js:
```js
// This file is loaded whenever a javascript context is created. It runs in a
// private scope that can access a subset of Electron renderer APIs. We must be
// careful to not leak any objects into the global scope!
const { ipcRenderer, remote } = require('electron')
const fs = remote.require('fs')
// read a configuration file using the `fs` module
const buf = fs.readFileSync('allowed-popup-urls.json')
const allowedUrls = JSON.parse(buf.toString('utf8'))
// private scope that can access a subset of Electron renderer APIs. Without
// contextIsolation enabled, it's possible to accidentally leak privileged
// globals like ipcRenderer to web content.
const { ipcRenderer } = require('electron')
const defaultWindowOpen = window.open
function customWindowOpen (url, ...args) {
if (allowedUrls.indexOf(url) === -1) {
ipcRenderer.sendSync('blocked-popup-notification', location.origin, url)
return null
}
return defaultWindowOpen(url, ...args)
window.open = function customWindowOpen (url, ...args) {
ipcRenderer.send('report-window-open', location.origin, url, args)
return defaultWindowOpen(url + '?from_electron=1', ...args)
}
window.open = customWindowOpen
```
Important things to notice in the preload script:
@@ -115,8 +106,6 @@ Important things to notice in the preload script:
- Even though the sandboxed renderer doesn't have Node.js running, it still has
access to a limited node-like environment: `Buffer`, `process`, `setImmediate`,
`clearImmediate` and `require` are available.
- The preload script can indirectly access all APIs from the main process through the
`remote` and `ipcRenderer` modules.
- The preload script must be contained in a single script, but it is possible to have
complex preload code composed with multiple modules by using a tool like
webpack or browserify. An example of using browserify is below.
@@ -144,15 +133,12 @@ following modules:
- `desktopCapturer`
- `ipcRenderer`
- `nativeImage`
- `remote`
- `webFrame`
- `events`
- `timers`
- `url`
More may be added as needed to expose more Electron APIs in the sandbox, but any
module in the main process can already be used through
`electron.remote.require`.
More may be added as needed to expose more Electron APIs in the sandbox.
## Rendering untrusted content

View File

@@ -45,15 +45,27 @@ Returns `Promise<void>`
Open the given external protocol URL in the desktop's default manner. (For example, mailto: URLs in the user's default mail agent).
### `shell.moveItemToTrash(fullPath[, deleteOnFail])`
### `shell.moveItemToTrash(fullPath[, deleteOnFail])` _Deprecated_
* `fullPath` String
* `deleteOnFail` Boolean (optional) - Whether or not to unilaterally remove the item if the Trash is disabled or unsupported on the volume. _macOS_
Returns `Boolean` - Whether the item was successfully moved to the trash or otherwise deleted.
> NOTE: This method is deprecated. Use `shell.trashItem` instead.
Move the given file to trash and returns a boolean status for the operation.
### `shell.trashItem(path)`
* `path` String - path to the item to be moved to the trash.
Returns `Promise<void>` - Resolves when the operation has been completed.
Rejects if there was an error while deleting the requested item.
This moves a path to the OS-specific trash location (Trash on macOS, Recycle
Bin on Windows, and a desktop-environment-specific location on Linux).
### `shell.beep()`
Play the beep sound.

View File

@@ -13,3 +13,5 @@ target's icon.
DLL or EXE. Default is 0.
* `appUserModelId` String (optional) - The Application User Model ID. Default
is empty.
* `toastActivatorClsid` String (optional) - The Application Toast Activator CLSID. Needed
for participating in Action Center.

View File

@@ -9,7 +9,7 @@ the [native modules](../tutorial/using-native-node-modules.md)).
Electron also provides some extra built-in modules for developing native
desktop applications. Some modules are only available in the main process, some
are only available in the renderer process (web page), and some can be used in
both processes.
either process type.
The basic rule is: if a module is [GUI][gui] or low-level system related, then
it should be only available in the main process. You need to be familiar with
@@ -29,15 +29,15 @@ app.whenReady().then(() => {
```
The renderer process is no different than a normal web page, except for the
extra ability to use node modules:
extra ability to use node modules if `nodeIntegration` is enabled:
```html
<!DOCTYPE html>
<html>
<body>
<script>
const { app } = require('electron').remote
console.log(app.getVersion())
const fs = require('fs')
console.log(fs.readFileSync(__filename, 'utf8'))
</script>
</body>
</html>

View File

@@ -784,7 +784,7 @@ Returns:
Emitted when `desktopCapturer.getSources()` is called in the renderer process.
Calling `event.preventDefault()` will make it return empty sources.
#### Event: 'remote-require'
#### Event: 'remote-require' _Deprecated_
Returns:
@@ -795,7 +795,7 @@ Emitted when `remote.require()` is called in the renderer process.
Calling `event.preventDefault()` will prevent the module from being returned.
Custom value can be returned by setting `event.returnValue`.
#### Event: 'remote-get-global'
#### Event: 'remote-get-global' _Deprecated_
Returns:
@@ -806,7 +806,7 @@ Emitted when `remote.getGlobal()` is called in the renderer process.
Calling `event.preventDefault()` will prevent the global from being returned.
Custom value can be returned by setting `event.returnValue`.
#### Event: 'remote-get-builtin'
#### Event: 'remote-get-builtin' _Deprecated_
Returns:
@@ -817,7 +817,7 @@ Emitted when `remote.getBuiltin()` is called in the renderer process.
Calling `event.preventDefault()` will prevent the module from being returned.
Custom value can be returned by setting `event.returnValue`.
#### Event: 'remote-get-current-window'
#### Event: 'remote-get-current-window' _Deprecated_
Returns:
@@ -827,7 +827,7 @@ Emitted when `remote.getCurrentWindow()` is called in the renderer process.
Calling `event.preventDefault()` will prevent the object from being returned.
Custom value can be returned by setting `event.returnValue`.
#### Event: 'remote-get-current-web-contents'
#### Event: 'remote-get-current-web-contents' _Deprecated_
Returns:
@@ -1117,6 +1117,10 @@ increment above or below represents zooming 20% larger or smaller to default
limits of 300% and 50% of original size, respectively. The formula for this is
`scale := 1.2 ^ level`.
> **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that the
> zoom level for a specific domain propagates across all instances of windows with
> the same domain. Differentiating the window URLs will make zoom work per-window.
#### `contents.getZoomLevel()`
Returns `Number` - the current zoom level.
@@ -1296,9 +1300,9 @@ Returns [`PrinterInfo[]`](structures/printer-info.md)
* `pagesPerSheet` Number (optional) - The number of pages to print per page sheet.
* `collate` Boolean (optional) - Whether the web page should be collated.
* `copies` Number (optional) - The number of copies of the web page to print.
* `pageRanges` Record<string, number> (optional) - The page range to print.
* `from` Number - the start page.
* `to` Number - the end page.
* `pageRanges` Object[] (optional) - The page range to print. On macOS, only one range is honored.
* `from` Number - Index of the first page to print (0-based).
* `to` Number - Index of the last page to print (inclusive) (0-based).
* `duplexMode` String (optional) - Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or `longEdge`.
* `dpi` Record<string, number> (optional)
* `horizontal` Number (optional) - The horizontal dpi.
@@ -1324,10 +1328,10 @@ Example usage:
const options = {
silent: true,
deviceName: 'My-Printer',
pageRanges: {
pageRanges: [{
from: 0,
to: 1
}
}]
}
win.webContents.print(options, (success, errorType) => {
if (!success) console.log(errorType)
@@ -1345,8 +1349,8 @@ win.webContents.print(options, (success, errorType) => {
default margin, 1 for no margin, and 2 for minimum margin.
* `scaleFactor` Number (optional) - The scale factor of the web page. Can range from 0 to 100.
* `pageRanges` Record<string, number> (optional) - The page range to print.
* `from` Number - zero-based index of the first page to print.
* `to` Number - zero-based index of the last page to print (inclusive).
* `from` Number - Index of the first page to print (0-based).
* `to` Number - Index of the last page to print (inclusive) (0-based).
* `pageSize` String | Size (optional) - Specify page size of the generated PDF. Can be `A3`,
`A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` and `width` in microns.
* `printBackground` Boolean (optional) - Whether to print CSS backgrounds.
@@ -1453,7 +1457,7 @@ An example of showing devtools in a `<webview>` tag:
<webview id="browser" src="https://github.com"></webview>
<webview id="devtools" src="about:blank"></webview>
<script>
const { webContents } = require('electron').remote
const { ipcRenderer } = require('electron')
const emittedOnce = (element, eventName) => new Promise(resolve => {
element.addEventListener(eventName, event => resolve(event), { once: true })
})
@@ -1462,16 +1466,26 @@ An example of showing devtools in a `<webview>` tag:
const browserReady = emittedOnce(browserView, 'dom-ready')
const devtoolsReady = emittedOnce(devtoolsView, 'dom-ready')
Promise.all([browserReady, devtoolsReady]).then(() => {
const browser = webContents.fromId(browserView.getWebContentsId())
const devtools = webContents.fromId(devtoolsView.getWebContentsId())
browser.setDevToolsWebContents(devtools)
browser.openDevTools()
const targetId = browserView.getWebContentsId()
const devtoolsId = devtoolsView.getWebContentsId()
ipcRenderer.send('open-devtools', targetId, devtoolsId)
})
</script>
</body>
</html>
```
```js
// Main process
const { ipcMain, webContents } = require('electron')
ipcMain.on('open-devtools', (event, targetContentsId, devtoolsContentsId) => {
const target = webContents.fromId(targetContentsId)
const devtools = webContents.fromId(devtoolsContentsId)
target.setDevToolsWebContents(devtools)
target.openDevTools()
})
```
An example of showing devtools in a `BrowserWindow`:
```js

View File

@@ -41,6 +41,10 @@ Changes the zoom level to the specified level. The original size is 0 and each
increment above or below represents zooming 20% larger or smaller to default
limits of 300% and 50% of original size, respectively.
> **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that the
> zoom level for a specific domain propagates across all instances of windows with
> the same domain. Differentiating the window URLs will make zoom work per-window.
### `webFrame.getZoomLevel()`
Returns `Number` - The current zoom level.

View File

@@ -137,7 +137,7 @@ This option is disabled by default in the guest page.
```
A `Boolean`. When this attribute is `false` the guest page in `webview` will not have access
to the [`remote`](remote.md) module. The remote module is available by default.
to the [`remote`](remote.md) module. The remote module is unavailable by default.
### `plugins`
@@ -560,9 +560,9 @@ Stops any `findInPage` request for the `webview` with the provided `action`.
* `pagesPerSheet` Number (optional) - The number of pages to print per page sheet.
* `collate` Boolean (optional) - Whether the web page should be collated.
* `copies` Number (optional) - The number of copies of the web page to print.
* `pageRanges` Record<string, number> (optional) - The page range to print.
* `from` Number - zero-based index of the first page to print.
* `to` Number - zero-based index of the last page to print (inclusive).
* `pageRanges` Object[] (optional) - The page range to print.
* `from` Number - Index of the first page to print (0-based).
* `to` Number - Index of the last page to print (inclusive) (0-based).
* `duplexMode` String (optional) - Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or `longEdge`.
* `dpi` Record<string, number> (optional)
* `horizontal` Number (optional) - The horizontal dpi.
@@ -587,9 +587,9 @@ Prints `webview`'s web page. Same as `webContents.print([options])`.
default margin, 1 for no margin, and 2 for minimum margin.
and `width` in microns.
* `scaleFactor` Number (optional) - The scale factor of the web page. Can range from 0 to 100.
* `pageRanges` Record<string, number> (optional) - The page range to print.
* `from` Number - the first page to print.
* `to` Number - the last page to print (inclusive).
* `pageRanges` Record<string, number> (optional) - The page range to print. On macOS, only the first range is honored.
* `from` Number - Index of the first page to print (0-based).
* `to` Number - Index of the last page to print (inclusive) (0-based).
* `pageSize` String | Size (optional) - Specify page size of the generated PDF. Can be `A3`,
`A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height`
* `printBackground` Boolean (optional) - Whether to print CSS backgrounds.
@@ -648,6 +648,10 @@ increment above or below represents zooming 20% larger or smaller to default
limits of 300% and 50% of original size, respectively. The formula for this is
`scale := 1.2 ^ level`.
> **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that the
> zoom level for a specific domain propagates across all instances of windows with
> the same domain. Differentiating the window URLs will make zoom work per-window.
### `<webview>.getZoomFactor()`
Returns `Number` - the current zoom factor.

View File

@@ -12,6 +12,20 @@ This document uses the following convention to categorize breaking changes:
- **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release.
- **Removed:** An API or feature was removed, and is no longer supported by Electron.
## Planned Breaking API Changes (13.0)
### Removed: `shell.moveItemToTrash()`
The deprecated synchronous `shell.moveItemToTrash()` API has been removed. Use
the asynchronous `shell.trashItem()` instead.
```js
// Removed in Electron 13
shell.moveItemToTrash(path)
// Replace with
shell.trashItem(path).then(/* ... */)
```
## Planned Breaking API Changes (12.0)
### Default Changed: `contextIsolation` defaults to `true`
@@ -50,6 +64,37 @@ If your crash ingestion server does not support compressed payloads, you can
turn off compression by specifying `{ compress: false }` in the crash reporter
options.
### Deprecated: `remote` module
The `remote` module is deprecated in Electron 12, and will be removed in
Electron 14. It is replaced by the
[`@electron/remote`](https://github.com/electron/remote) module.
```js
// Deprecated in Electron 12:
const { BrowserWindow } = require('electron').remote
```
```js
// Replace with:
const { BrowserWindow } = require('@electron/remote')
// In the main process:
require('@electron/remote/main').initialize()
```
### Deprecated: `shell.moveItemToTrash()`
The synchronous `shell.moveItemToTrash()` has been replaced by the new,
asynchronous `shell.trashItem()`.
```js
// Deprecated in Electron 12
shell.moveItemToTrash(path)
// Replace with
shell.trashItem(path).then(/* ... */)
```
## Planned Breaking API Changes (11.0)
There are no breaking changes planned for 11.0.

View File

@@ -4,8 +4,8 @@ These guides are intended for people working on the Electron project itself.
For guides on Electron app development, see
[/docs/README.md](../README.md#guides-and-tutorials).
* [Code of Conduct](../../CODE_OF_CONDUCT.md)
* [Contributing to Electron](../../CONTRIBUTING.md)
* [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md)
* [Contributing to Electron](https://github.com/electron/electron/blob/master/CONTRIBUTING.md)
* [Issues](issues.md)
* [Pull Requests](pull-requests.md)
* [Documentation Styleguide](coding-style.md#documentation)

View File

@@ -69,8 +69,7 @@ way of figuring out which is which.
### Which Process Should I Attach to?
Code executed within the main process (that is, code found in or eventually run
by your main JavaScript file) as well as code called using the remote
(`require('electron').remote`) will run inside the main process, while other
by your main JavaScript file) will run inside the main process, while other
code will execute inside its respective renderer process.
You can be attached to multiple programs when you are debugging, but only one

View File

@@ -1,7 +1,11 @@
const { BrowserWindow, app } = require('electron')
const { BrowserWindow, app, screen, ipcMain } = require('electron')
let mainWindow = null
ipcMain.handle('get-screen-size', () => {
return screen.getPrimaryDisplay().workAreaSize
})
function createWindow () {
const windowOptions = {
width: 600,

View File

@@ -1,5 +1,4 @@
const { desktopCapturer } = require('electron')
const { screen, shell } = require('electron').remote
const { desktopCapturer, shell, ipcRenderer } = require('electron')
const fs = require('fs')
const os = require('os')
@@ -8,9 +7,9 @@ const path = require('path')
const screenshot = document.getElementById('screen-shot')
const screenshotMsg = document.getElementById('screenshot-path')
screenshot.addEventListener('click', (event) => {
screenshot.addEventListener('click', async (event) => {
screenshotMsg.textContent = 'Gathering screens...'
const thumbSize = determineScreenShotSize()
const thumbSize = await determineScreenShotSize()
const options = { types: ['screen'], thumbnailSize: thumbSize }
desktopCapturer.getSources(options, (error, sources) => {
@@ -33,8 +32,8 @@ screenshot.addEventListener('click', (event) => {
})
})
function determineScreenShotSize () {
const screenSize = screen.getPrimaryDisplay().workAreaSize
async function determineScreenShotSize () {
const screenSize = await ipcRenderer.invoke('get-screen-size')
const maxDimension = Math.max(screenSize.width, screenSize.height)
return {
width: maxDimension * window.devicePixelRatio,

View File

@@ -1,95 +1,95 @@
// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
ipcMain.on('open-error-dialog', event => {
dialog.showErrorBox('An Error Message', 'Demonstrating an error message.')
})
ipcMain.on('open-information-dialog', event => {
const options = {
type: 'info',
title: 'Information',
message: "This is an information dialog. Isn't it nice?",
buttons: ['Yes', 'No']
}
dialog.showMessageBox(options, index => {
event.sender.send('information-dialog-selection', index)
})
})
ipcMain.on('open-file-dialog', event => {
dialog.showOpenDialog(
{
properties: ['openFile', 'openDirectory']
},
files => {
if (files) {
event.sender.send('selected-directory', files)
}
}
)
})
ipcMain.on('save-dialog', event => {
const options = {
title: 'Save an Image',
filters: [{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }]
}
dialog.showSaveDialog(options, filename => {
event.sender.send('saved-file', filename)
})
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
ipcMain.on('open-error-dialog', event => {
dialog.showErrorBox('An Error Message', 'Demonstrating an error message.')
})
ipcMain.on('open-information-dialog', event => {
const options = {
type: 'info',
title: 'Information',
message: "This is an information dialog. Isn't it nice?",
buttons: ['Yes', 'No']
}
dialog.showMessageBox(options, index => {
event.sender.send('information-dialog-selection', index)
})
})
ipcMain.on('open-file-dialog', event => {
dialog.showOpenDialog(
{
properties: ['openFile', 'openDirectory']
},
files => {
if (files) {
event.sender.send('selected-directory', files)
}
}
)
})
ipcMain.on('save-dialog', event => {
const options = {
title: 'Save an Image',
filters: [{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }]
}
dialog.showSaveDialog(options, filename => {
event.sender.send('saved-file', filename)
})
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

View File

@@ -1,18 +1,18 @@
const { ipcRenderer, shell } = require('electron')
const links = document.querySelectorAll('a[href]')
const errorBtn = document.getElementById('error-dialog')
errorBtn.addEventListener('click', event => {
ipcRenderer.send('open-error-dialog')
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
const { ipcRenderer, shell } = require('electron')
const links = document.querySelectorAll('a[href]')
const errorBtn = document.getElementById('error-dialog')
errorBtn.addEventListener('click', event => {
ipcRenderer.send('open-error-dialog')
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
})

View File

@@ -1,70 +1,70 @@
// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
ipcMain.on('open-information-dialog', event => {
const options = {
type: 'info',
title: 'Information',
message: "This is an information dialog. Isn't it nice?",
buttons: ['Yes', 'No']
}
dialog.showMessageBox(options, index => {
event.sender.send('information-dialog-selection', index)
})
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
ipcMain.on('open-information-dialog', event => {
const options = {
type: 'info',
title: 'Information',
message: "This is an information dialog. Isn't it nice?",
buttons: ['Yes', 'No']
}
dialog.showMessageBox(options, index => {
event.sender.send('information-dialog-selection', index)
})
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

View File

@@ -1,25 +1,25 @@
const { ipcRenderer, shell } = require('electron')
const informationBtn = document.getElementById('information-dialog')
const links = document.querySelectorAll('a[href]')
informationBtn.addEventListener('click', event => {
ipcRenderer.send('open-information-dialog')
})
ipcRenderer.on('information-dialog-selection', (event, index) => {
let message = 'You selected '
if (index === 0) message += 'yes.'
else message += 'no.'
document.getElementById('info-selection').innerHTML = message
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
const { ipcRenderer, shell } = require('electron')
const informationBtn = document.getElementById('information-dialog')
const links = document.querySelectorAll('a[href]')
informationBtn.addEventListener('click', event => {
ipcRenderer.send('open-information-dialog')
})
ipcRenderer.on('information-dialog-selection', (event, index) => {
let message = 'You selected '
if (index === 0) message += 'yes.'
else message += 'no.'
document.getElementById('info-selection').innerHTML = message
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
})

View File

@@ -1,70 +1,70 @@
// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
ipcMain.on('open-file-dialog', event => {
dialog.showOpenDialog(
{
properties: ['openFile', 'openDirectory']
},
files => {
if (files) {
event.sender.send('selected-directory', files)
}
}
)
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
ipcMain.on('open-file-dialog', event => {
dialog.showOpenDialog(
{
properties: ['openFile', 'openDirectory']
},
files => {
if (files) {
event.sender.send('selected-directory', files)
}
}
)
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

View File

@@ -1,22 +1,22 @@
const { ipcRenderer, shell } = require('electron')
const selectDirBtn = document.getElementById('select-directory')
const links = document.querySelectorAll('a[href]')
selectDirBtn.addEventListener('click', event => {
ipcRenderer.send('open-file-dialog')
})
ipcRenderer.on('selected-directory', (event, path) => {
document.getElementById('selected-file').innerHTML = `You selected: ${path}`
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
})
const { ipcRenderer, shell } = require('electron')
const selectDirBtn = document.getElementById('select-directory')
const links = document.querySelectorAll('a[href]')
selectDirBtn.addEventListener('click', event => {
ipcRenderer.send('open-file-dialog')
})
ipcRenderer.on('selected-directory', (event, path) => {
document.getElementById('selected-file').innerHTML = `You selected: ${path}`
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
})

View File

@@ -1,66 +1,66 @@
// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
ipcMain.on('save-dialog', event => {
const options = {
title: 'Save an Image',
filters: [{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }]
}
dialog.showSaveDialog(options, filename => {
event.sender.send('saved-file', filename)
})
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
ipcMain.on('save-dialog', event => {
const options = {
title: 'Save an Image',
filters: [{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }]
}
dialog.showSaveDialog(options, filename => {
event.sender.send('saved-file', filename)
})
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

View File

@@ -1,23 +1,23 @@
const { ipcRenderer, shell } = require('electron')
const saveBtn = document.getElementById('save-dialog')
const links = document.querySelectorAll('a[href]')
saveBtn.addEventListener('click', event => {
ipcRenderer.send('save-dialog')
})
ipcRenderer.on('saved-file', (event, path) => {
if (!path) path = 'No path'
document.getElementById('file-saved').innerHTML = `Path selected: ${path}`
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
const { ipcRenderer, shell } = require('electron')
const saveBtn = document.getElementById('save-dialog')
const links = document.querySelectorAll('a[href]')
saveBtn.addEventListener('click', event => {
ipcRenderer.send('save-dialog')
})
ipcRenderer.on('saved-file', (event, path) => {
if (!path) path = 'No path'
document.getElementById('file-saved').innerHTML = `Path selected: ${path}`
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
})

View File

@@ -1,56 +1,56 @@
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// In this file you can include the rest of your app's specific main process
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

View File

@@ -1,13 +1,13 @@
const { shell } = require('electron')
const os = require('os')
const exLinksBtn = document.getElementById('open-ex-links')
const fileManagerBtn = document.getElementById('open-file-manager')
fileManagerBtn.addEventListener('click', (event) => {
shell.showItemInFolder(os.homedir())
})
exLinksBtn.addEventListener('click', (event) => {
shell.openExternal('https://electronjs.org')
const { shell } = require('electron')
const os = require('os')
const exLinksBtn = document.getElementById('open-ex-links')
const fileManagerBtn = document.getElementById('open-file-manager')
fileManagerBtn.addEventListener('click', (event) => {
shell.showItemInFolder(os.homedir())
})
exLinksBtn.addEventListener('click', (event) => {
shell.openExternal('https://electronjs.org')
})

View File

@@ -1,56 +1,56 @@
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// In this file you can include the rest of your app's specific main process
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

View File

@@ -1,29 +1,29 @@
const basicNotification = {
title: 'Basic Notification',
body: 'Short message part'
}
const notification = {
title: 'Notification with image',
body: 'Short message plus a custom image',
icon: 'https://via.placeholder.com/150'
}
const basicNotificationButton = document.getElementById('basic-noti')
const notificationButton = document.getElementById('advanced-noti')
notificationButton.addEventListener('click', () => {
const myNotification = new window.Notification(notification.title, notification)
myNotification.onclick = () => {
console.log('Notification clicked')
}
})
basicNotificationButton.addEventListener('click', () => {
const myNotification = new window.Notification(basicNotification.title, basicNotification)
myNotification.onclick = () => {
console.log('Notification clicked')
}
})
const basicNotification = {
title: 'Basic Notification',
body: 'Short message part'
}
const notification = {
title: 'Notification with image',
body: 'Short message plus a custom image',
icon: 'https://via.placeholder.com/150'
}
const basicNotificationButton = document.getElementById('basic-noti')
const notificationButton = document.getElementById('advanced-noti')
notificationButton.addEventListener('click', () => {
const myNotification = new window.Notification(notification.title, notification)
myNotification.onclick = () => {
console.log('Notification clicked')
}
})
basicNotificationButton.addEventListener('click', () => {
const myNotification = new window.Notification(basicNotification.title, basicNotification)
myNotification.onclick = () => {
console.log('Notification clicked')
}
})

File diff suppressed because one or more lines are too long

View File

@@ -1,35 +1,35 @@
const { ipcRenderer, shell } = require('electron')
const trayBtn = document.getElementById('put-in-tray')
const links = document.querySelectorAll('a[href]')
let trayOn = false
trayBtn.addEventListener('click', function (event) {
if (trayOn) {
trayOn = false
document.getElementById('tray-countdown').innerHTML = ''
ipcRenderer.send('remove-tray')
} else {
trayOn = true
const message = 'Click demo again to remove.'
document.getElementById('tray-countdown').innerHTML = message
ipcRenderer.send('put-in-tray')
}
})
// Tray removed from context menu on icon
ipcRenderer.on('tray-removed', function () {
ipcRenderer.send('remove-tray')
trayOn = false
document.getElementById('tray-countdown').innerHTML = ''
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
const { ipcRenderer, shell } = require('electron')
const trayBtn = document.getElementById('put-in-tray')
const links = document.querySelectorAll('a[href]')
let trayOn = false
trayBtn.addEventListener('click', function (event) {
if (trayOn) {
trayOn = false
document.getElementById('tray-countdown').innerHTML = ''
ipcRenderer.send('remove-tray')
} else {
trayOn = true
const message = 'Click demo again to remove.'
document.getElementById('tray-countdown').innerHTML = message
ipcRenderer.send('put-in-tray')
}
})
// Tray removed from context menu on icon
ipcRenderer.on('tray-removed', function () {
ipcRenderer.send('remove-tray')
trayOn = false
document.getElementById('tray-countdown').innerHTML = ''
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
})

View File

@@ -1,23 +1,20 @@
const { app, BrowserWindow } = require('electron')
const { app, BrowserWindow, ipcMain } = require('electron')
let mainWindow = null
ipcMain.on('create-frameless-window', (event, {url}) => {
const win = new BrowserWindow({ frame: false })
win.loadURL(url)
})
function createWindow () {
const windowOptions = {
const mainWindow = new BrowserWindow({
width: 600,
height: 400,
title: 'Create a frameless window',
webPreferences: {
nodeIntegration: true
}
}
mainWindow = new BrowserWindow(windowOptions)
mainWindow.loadFile('index.html')
mainWindow.on('closed', () => {
mainWindow = null
})
mainWindow.loadFile('index.html')
}
app.whenReady().then(() => {

View File

@@ -1,12 +1,8 @@
const { BrowserWindow } = require('electron').remote
const { ipcRenderer } = require('electron')
const newWindowBtn = document.getElementById('frameless-window')
newWindowBtn.addEventListener('click', (event) => {
let win = new BrowserWindow({ frame: false })
win.on('close', () => { win = null })
win.loadURL('data:text/html,<h2>Hello World!</h2><a id="close" href="javascript:window.close()">Close this Window</a>')
win.show()
newWindowBtn.addEventListener('click', () => {
const url = 'data:text/html,<h2>Hello World!</h2><a id="close" href="javascript:window.close()">Close this Window</a>'
ipcRenderer.send('create-frameless-window', { url })
})

View File

@@ -1,56 +1,46 @@
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// In this file you can include the rest of your app's specific main process
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
ipcMain.on('create-frameless-window', (event, {url}) => {
const win = new BrowserWindow({ frame: false })
win.loadURL(url)
})
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

View File

@@ -1,25 +1,8 @@
const { BrowserWindow } = require('electron').remote
const shell = require('electron').shell
const framelessWindowBtn = document.getElementById('frameless-window')
const links = document.querySelectorAll('a[href]')
framelessWindowBtn.addEventListener('click', (event) => {
const modalPath = 'https://electronjs.org'
let win = new BrowserWindow({ frame: false })
win.on('close', () => { win = null })
win.loadURL(modalPath)
win.show()
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
})
const { ipcRenderer } = require('electron')
const newWindowBtn = document.getElementById('frameless-window')
newWindowBtn.addEventListener('click', () => {
const url = 'data:text/html,<h2>Hello World!</h2><a id="close" href="javascript:window.close()">Close this Window</a>'
ipcRenderer.send('create-frameless-window', { url })
})

View File

@@ -1,56 +1,56 @@
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// In this file you can include the rest of your app's specific main process
// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain } = require('electron')
ipcMain.on('create-demo-window', (event) => {
const win = new BrowserWindow({ width: 400, height: 275 })
function updateReply() {
event.sender.send('bounds-changed', {
size: win.getSize(),
position: win.getPosition()
})
}
win.on('resize', updateReply)
win.on('move', updateReply)
win.loadURL('https://electronjs.org')
})
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

View File

@@ -1,35 +1,25 @@
const { BrowserWindow } = require('electron').remote
const shell = require('electron').shell
const manageWindowBtn = document.getElementById('manage-window')
const links = document.querySelectorAll('a[href]')
let win
manageWindowBtn.addEventListener('click', (event) => {
const modalPath = 'https://electronjs.org'
win = new BrowserWindow({ width: 400, height: 275 })
win.on('resize', updateReply)
win.on('move', updateReply)
win.on('close', () => { win = null })
win.loadURL(modalPath)
win.show()
function updateReply () {
const manageWindowReply = document.getElementById('manage-window-reply')
const message = `Size: ${win.getSize()} Position: ${win.getPosition()}`
manageWindowReply.innerText = message
}
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
})
const { shell, ipcRenderer } = require('electron')
const manageWindowBtn = document.getElementById('manage-window')
const links = document.querySelectorAll('a[href]')
ipcRenderer.on('bounds-changed', (event, bounds) => {
const manageWindowReply = document.getElementById('manage-window-reply')
const message = `Size: ${bounds.size} Position: ${bounds.position}`
manageWindowReply.textContent = message
})
manageWindowBtn.addEventListener('click', (event) => {
ipcRenderer.send('create-demo-window')
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
})

View File

@@ -7,7 +7,7 @@
<h2>Create a new window</h2>
<h3>Supports: Win, macOS, Linux <span>|</span> Process: Main</h3>
<button id="new-window">View Demo</button>
<p>The <code>BrowserWindow</code> module gives you the ability to create new windows in your app. This main process module can be used from the renderer process with the <code>remote</code> module, as is shown in this demo.</p>
<p>The <code>BrowserWindow</code> module gives you the ability to create new windows in your app.</p>
<p>There are a lot of options when creating a new window. A few are in this demo, but visit the <a id="browser-window-link" href="">documentation<span>(opens in new window)</span></a>
<div>
<h2>ProTip</h2>

View File

@@ -1,13 +1,14 @@
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
const { app, BrowserWindow, ipcMain } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
ipcMain.on('new-window', (event, { url, width, height }) => {
const win = new BrowserWindow({ width, height })
win.loadURL(url)
})
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
@@ -17,17 +18,6 @@ function createWindow () {
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished

View File

@@ -1,16 +1,11 @@
const { BrowserWindow } = require('electron').remote
const { shell } = require('electron').remote
const { shell, ipcRenderer } = require('electron')
const newWindowBtn = document.getElementById('new-window')
const link = document.getElementById('browser-window-link')
newWindowBtn.addEventListener('click', (event) => {
let win = new BrowserWindow({ width: 400, height: 320 })
win.on('close', () => { win = null })
win.loadURL('https://electronjs.org')
win.show()
const url = 'https://electronjs.org'
ipcRenderer.send('new-window', { url, width: 400, height: 320 });
})
link.addEventListener('click', (e) => {

View File

@@ -1,56 +1,64 @@
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// In this file you can include the rest of your app's specific main process
// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain } = require('electron')
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
let demoWindow
ipcMain.on('show-demo-window', () => {
if (demoWindow) {
demoWindow.focus()
return
}
demoWindow = new BrowserWindow({ width: 600, height: 400 })
demoWindow.loadURL('https://electronjs.org')
demoWindow.on('close', () => {
mainWindow.webContents.send('window-close')
})
demoWindow.on('focus', () => {
mainWindow.webContents.send('window-focus')
})
demoWindow.on('blur', () => {
mainWindow.webContents.send('window-blur')
})
})
ipcMain.on('focus-demo-window', () => {
if (demoWindow) demoWindow.focus()
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On macOS it is common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

View File

@@ -1,48 +1,39 @@
const { BrowserWindow } = require('electron').remote
const shell = require('electron').shell
const listenToWindowBtn = document.getElementById('listen-to-window')
const focusModalBtn = document.getElementById('focus-on-modal-window')
const links = document.querySelectorAll('a[href]')
let win
listenToWindowBtn.addEventListener('click', () => {
const modalPath = 'https://electronjs.org'
win = new BrowserWindow({ width: 600, height: 400 })
const hideFocusBtn = () => {
focusModalBtn.classList.add('disappear')
focusModalBtn.classList.remove('smooth-appear')
focusModalBtn.removeEventListener('click', clickHandler)
}
const showFocusBtn = (btn) => {
if (!win) return
focusModalBtn.classList.add('smooth-appear')
focusModalBtn.classList.remove('disappear')
focusModalBtn.addEventListener('click', clickHandler)
}
win.on('focus', hideFocusBtn)
win.on('blur', showFocusBtn)
win.on('close', () => {
hideFocusBtn()
win = null
})
win.loadURL(modalPath)
win.show()
const clickHandler = () => { win.focus() }
})
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
})
const { shell, ipcRenderer } = require('electron')
const listenToWindowBtn = document.getElementById('listen-to-window')
const focusModalBtn = document.getElementById('focus-on-modal-window')
const hideFocusBtn = () => {
focusModalBtn.classList.add('disappear')
focusModalBtn.classList.remove('smooth-appear')
focusModalBtn.removeEventListener('click', focusWindow)
}
const showFocusBtn = (btn) => {
focusModalBtn.classList.add('smooth-appear')
focusModalBtn.classList.remove('disappear')
focusModalBtn.addEventListener('click', focusWindow)
}
const focusWindow = () => {
ipcRenderer.send('focus-demo-window')
}
ipcRenderer.on('window-focus', hideFocusBtn)
ipcRenderer.on('window-close', hideFocusBtn)
ipcRenderer.on('window-blur', showFocusBtn)
listenToWindowBtn.addEventListener('click', () => {
ipcRenderer.send('show-demo-window')
})
const links = document.querySelectorAll('a[href]')
Array.prototype.forEach.call(links, (link) => {
const url = link.getAttribute('href')
if (url.indexOf('http') === 0) {
link.addEventListener('click', (e) => {
e.preventDefault()
shell.openExternal(url)
})
}
})

View File

@@ -1,6 +1,6 @@
# Accessibility
Making accessible applications is important and we're happy to introduce new
Making accessible applications is important and we're happy to provide
functionality to [Devtron][devtron] and [Spectron][spectron] that gives
developers the opportunity to make their apps better for everyone.
@@ -11,7 +11,7 @@ websites because they're both ultimately HTML. With Electron apps, however,
you can't use the online resources for accessibility audits because your app
doesn't have a URL to point the auditor to.
These new features bring those auditing tools to your Electron app. You can
These features bring those auditing tools to your Electron app. You can
choose to add audits to your tests with Spectron or use them within DevTools
with Devtron. Read on for a summary of the tools.
@@ -32,7 +32,7 @@ You can read more about this feature in [Spectron's documentation][spectron-a11y
## Devtron
In Devtron, there is a new accessibility tab which will allow you to audit a
In Devtron, there is an accessibility tab which will allow you to audit a
page in your app, sort and filter the results.
![devtron screenshot][devtron-screenshot]
@@ -44,26 +44,29 @@ audit rules this library uses on that [repository's wiki][a11y-devtools-wiki].
If you know of other great accessibility tools for Electron, add them to the
accessibility documentation with a pull request.
## Enabling Accessibility
## Manually enabling accessibility features
Electron applications keep accessibility disabled by default for performance
reasons but there are multiple ways to enable it.
Electron applications will automatically enable accessibility features in the
presence of assistive technology (e.g. [JAWS](https://www.freedomscientific.com/products/software/jaws/)
on Windows or [VoiceOver](https://help.apple.com/voiceover/mac/10.15/) on macOS).
See Chrome's [accessibility documentation][a11y-docs] for more details.
### Inside Application
You can also manually toggle these features either within your Electron application
or by setting flags in third-party native software.
By using [`app.setAccessibilitySupportEnabled(enabled)`][setAccessibilitySupportEnabled],
you can expose accessibility switch to users in the application preferences.
User's system assistive utilities have priority over this setting and will
override it.
### Using Electron's API
### Assistive Technology
By using the [`app.setAccessibilitySupportEnabled(enabled)`][setAccessibilitySupportEnabled]
API, you can manually expose Chrome's accessibility tree to users in the application preferences.
Note that the user's system assistive utilities have priority over this setting and
will override it.
Electron application will enable accessibility automatically when it detects
assistive technology (Windows) or VoiceOver (macOS). See Chrome's
[accessibility documentation][a11y-docs] for more details.
### Within third-party software
On macOS, third-party assistive technology can switch accessibility inside
Electron applications by setting the attribute `AXManualAccessibility`
#### macOS
On macOS, third-party assistive technology can toggle accessibility features inside
Electron applications by setting the `AXManualAccessibility` attribute
programmatically:
```objc

View File

@@ -26,7 +26,8 @@ To test In-App Purchase in development with Electron you'll have to change the `
Here is an example that shows how to use In-App Purchases in Electron. You'll have to replace the product ids by the identifiers of the products created with iTunes Connect (the identifier of `com.example.app.product1` is `product1`). Note that you have to listen to the `transactions-updated` event as soon as possible in your app.
```javascript
const { inAppPurchase } = require('electron').remote
// Main process
const { inAppPurchase } = require('electron')
const PRODUCT_IDS = ['id1', 'id2']
// Listen for transactions as soon as possible.

View File

@@ -55,7 +55,6 @@ template("electron_extra_paks") {
output = "${invoker.output_dir}/resources.pak"
sources = [
"$root_gen_dir/chrome/dev_ui_browser_resources.pak",
"$root_gen_dir/chrome/print_preview_pdf_resources.pak",
"$root_gen_dir/components/components_resources.pak",
"$root_gen_dir/content/browser/resources/media/media_internals_resources.pak",
"$root_gen_dir/content/browser/tracing/tracing_resources.pak",
@@ -71,7 +70,6 @@ template("electron_extra_paks") {
]
deps = [
"//chrome/browser:dev_ui_browser_resources",
"//chrome/browser/resources:print_preview_pdf_resources",
"//components/resources",
"//content:content_resources",
"//content:dev_ui_content_resources",
@@ -96,6 +94,10 @@ template("electron_extra_paks") {
sources +=
[ "$root_gen_dir/content/browser/devtools/devtools_resources.pak" ]
deps += [ "//content/browser/devtools:devtools_resources" ]
if (enable_pdf_viewer) {
sources += [ "$root_gen_dir/chrome/print_preview_pdf_resources.pak" ]
deps += [ "//chrome/browser/resources:print_preview_pdf_resources" ]
}
if (enable_print_preview) {
sources += [ "$root_gen_dir/chrome/print_preview_resources.pak" ]
deps += [ "//chrome/browser/resources:print_preview_resources" ]

View File

@@ -490,6 +490,7 @@ filenames = {
"shell/common/gin_converters/file_path_converter.h",
"shell/common/gin_converters/gfx_converter.cc",
"shell/common/gin_converters/gfx_converter.h",
"shell/common/gin_converters/guid_converter.h",
"shell/common/gin_converters/gurl_converter.h",
"shell/common/gin_converters/image_converter.cc",
"shell/common/gin_converters/image_converter.h",
@@ -565,7 +566,9 @@ filenames = {
"shell/common/node_util.h",
"shell/common/options_switches.cc",
"shell/common/options_switches.h",
"shell/common/platform_util.cc",
"shell/common/platform_util.h",
"shell/common/platform_util_internal.h",
"shell/common/platform_util_linux.cc",
"shell/common/platform_util_mac.mm",
"shell/common/platform_util_win.cc",
@@ -625,6 +628,8 @@ filenames = {
"shell/browser/extensions/api/resources_private/resources_private_api.h",
"shell/browser/extensions/api/runtime/electron_runtime_api_delegate.cc",
"shell/browser/extensions/api/runtime/electron_runtime_api_delegate.h",
"shell/browser/extensions/api/management/electron_management_api_delegate.cc",
"shell/browser/extensions/api/management/electron_management_api_delegate.h",
"shell/browser/extensions/api/tabs/tabs_api.cc",
"shell/browser/extensions/api/tabs/tabs_api.h",
"shell/browser/extensions/api/streams_private/streams_private_api.cc",

View File

@@ -28,9 +28,11 @@ Object.setPrototypeOf(BrowserWindow.prototype, BaseWindow.prototype);
// Though this hack is only needed on macOS when the app is launched from
// Finder, we still do it on all platforms in case of other bugs we don't
// know.
this.webContents.once('load-url' as any, function (this: WebContents) {
this.focus();
});
if (this.webContents._initiallyShown) {
this.webContents.once('load-url' as any, function (this: WebContents) {
this.focus();
});
}
// Redirect focus/blur event to app instance too.
this.on('blur', (event: Event) => {
@@ -90,11 +92,7 @@ BrowserWindow.getFocusedWindow = () => {
};
BrowserWindow.fromWebContents = (webContents: WebContents) => {
for (const window of BrowserWindow.getAllWindows()) {
if (window.webContents && window.webContents.equal(webContents)) return window;
}
return null;
return webContents.getOwnerBrowserWindow();
};
BrowserWindow.fromBrowserView = (browserView: BrowserView) => {

View File

@@ -13,7 +13,7 @@ class CrashReporter {
submitURL,
uploadToServer = true,
rateLimit = false,
compress = false
compress = true
} = options || {};
if (submitURL == null) throw new Error('submitURL is a required option to crashReporter.start');

View File

@@ -362,7 +362,7 @@ export class ClientRequest extends Writable implements Electron.ClientRequest {
delete this._urlLoaderOptions.extraHeaders[key];
}
_write (chunk: Buffer, encoding: string, callback: () => void) {
_write (chunk: Buffer, encoding: BufferEncoding, callback: () => void) {
this._firstWrite = true;
if (!this._body) {
this._body = new SlurpStream();
@@ -481,6 +481,14 @@ export class ClientRequest extends Writable implements Electron.ClientRequest {
}
_die (err?: Error) {
// Node.js assumes that any stream which is ended is no longer capable of emitted events
// which is a faulty assumption for the case of an object that is acting like a stream
// (our urlRequest). If we don't emit here, this causes errors since we *do* expect
// that error events can be emitted after urlRequest.end().
if ((this as any)._writableState.destroyed && err) {
this.emit('error', err);
}
this.destroy(err);
if (this._urlLoader) {
this._urlLoader.cancel();

View File

@@ -461,6 +461,11 @@ const addReturnValueToEvent = (event: any) => {
});
};
const loggingEnabled = () => {
return Object.prototype.hasOwnProperty.call(process.env, 'ELECTRON_ENABLE_LOGGING') ||
process.argv.some(arg => arg.toLowerCase().startsWith('--enable-logging'));
};
// Add JavaScript wrappers for WebContents class.
WebContents.prototype._init = function () {
// The navigation controller.
@@ -543,6 +548,11 @@ WebContents.prototype._init = function () {
this.on('crashed', (event, ...args) => {
app.emit('renderer-process-crashed', event, this, ...args);
// Log out a hint to help users better debug renderer crashes.
if (loggingEnabled()) {
console.info('Renderer process crashed - see https://www.electronjs.org/docs/tutorial/application-debugging for potential debugging information.');
}
});
this.on('render-process-gone', (event, ...args) => {

View File

@@ -1,7 +1,4 @@
const {
createDesktopCapturer,
getMediaSourceIdForWebContents: getMediaSourceIdForWebContentsBinding
} = process._linkedBinding('electron_browser_desktop_capturer');
const { createDesktopCapturer } = process._linkedBinding('electron_browser_desktop_capturer');
const deepEqual = (a: ElectronInternal.GetSourcesOptions, b: ElectronInternal.GetSourcesOptions) => JSON.stringify(a) === JSON.stringify(b);
@@ -80,7 +77,3 @@ export const getSourcesImpl = (event: Electron.IpcMainEvent | null, args: Electr
return getSources;
};
export const getMediaSourceIdForWebContents = (event: Electron.IpcMainEvent, webContentsId: number) => {
return getMediaSourceIdForWebContentsBinding(event.sender.id, webContentsId);
};

View File

@@ -4,6 +4,7 @@ import * as fs from 'fs';
import { Socket } from 'net';
import * as path from 'path';
import * as util from 'util';
const Module = require('module');
// We modified the original process.argv to let node.js load the init.js,
@@ -62,7 +63,7 @@ process.on('uncaughtException', function (error) {
// Emit 'exit' event on quit.
const { app } = require('electron');
app.on('quit', function (event, exitCode) {
app.on('quit', (_event, exitCode) => {
process.emit('exit', exitCode);
});

View File

@@ -353,7 +353,7 @@ handleRemoteCommand('ELECTRON_BROWSER_REQUIRE', function (event, contextId, modu
if (customEvent.defaultPrevented) {
throw new Error(`Blocked remote.require('${moduleName}')`);
} else {
customEvent.returnValue = process.mainModule!.require(moduleName);
customEvent.returnValue = (process as any).mainModule.require(moduleName);
}
}

View File

@@ -71,10 +71,6 @@ if (BUILDFLAG(ENABLE_DESKTOP_CAPTURER)) {
return typeUtils.serialize(await desktopCapturer.getSourcesImpl(event, options));
});
ipcMainInternal.handle('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_MEDIA_SOURCE_ID_FOR_WEB_CONTENTS', function (event: IpcMainInvokeEvent, webContentsId: number) {
return desktopCapturer.getMediaSourceIdForWebContents(event, webContentsId);
});
}
const isRemoteModuleEnabled = BUILDFLAG(ENABLE_REMOTE_MODULE)

View File

@@ -1 +1,7 @@
export default process._linkedBinding('electron_common_shell');
import { deprecate } from 'electron/main';
const shell = process._linkedBinding('electron_common_shell');
shell.moveItemToTrash = deprecate.renameFunction(shell.moveItemToTrash, 'shell.trashItem');
export default shell;

View File

@@ -16,7 +16,3 @@ function getCurrentStack () {
export async function getSources (options: Electron.SourcesOptions) {
return deserialize(await ipcRendererInternal.invoke('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', options, getCurrentStack()));
}
export function getMediaSourceIdForWebContents (webContentsId: number) {
return ipcRendererInternal.invoke<string>('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_MEDIA_SOURCE_ID_FOR_WEB_CONTENTS', webContentsId, getCurrentStack());
}

View File

@@ -3,9 +3,12 @@ import { isPromise, isSerializableObject, serialize, deserialize } from '../../c
import { MetaTypeFromRenderer, ObjectMember, ObjProtoDescriptor, MetaType } from '../../common/remote/types';
import { ipcRendererInternal } from '../ipc-renderer-internal';
import type { BrowserWindow, WebContents } from 'electron/main';
import deprecate from '@electron/internal/common/api/deprecate';
import { browserModuleNames } from '@electron/internal/browser/api/module-names';
import { commonModuleList } from '@electron/internal/common/api/module-list';
deprecate.log('The remote module is deprecated. Use https://github.com/electron/remote instead.');
const v8Util = process._linkedBinding('electron_common_v8_util');
const { hasSwitch } = process._linkedBinding('electron_common_command_line');

View File

@@ -1,119 +0,0 @@
import { webFrame } from 'electron';
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils';
const v8Util = process._linkedBinding('electron_common_v8_util');
const IsolatedWorldIDs = {
/**
* Start of extension isolated world IDs, as defined in
* electron_render_frame_observer.h
*/
ISOLATED_WORLD_EXTENSIONS: 1 << 20
};
let isolatedWorldIds = IsolatedWorldIDs.ISOLATED_WORLD_EXTENSIONS;
const extensionWorldId: {[key: string]: number | undefined} = {};
// https://cs.chromium.org/chromium/src/extensions/renderer/script_injection.cc?type=cs&sq=package:chromium&g=0&l=52
const getIsolatedWorldIdForInstance = () => {
// TODO(samuelmaddock): allocate and cleanup IDs
return isolatedWorldIds++;
};
const escapePattern = function (pattern: string) {
return pattern.replace(/[\\^$+?.()|[\]{}]/g, '\\$&');
};
// Check whether pattern matches.
// https://developer.chrome.com/extensions/match_patterns
const matchesPattern = function (pattern: string) {
if (pattern === '<all_urls>') return true;
const regexp = new RegExp(`^${pattern.split('*').map(escapePattern).join('.*')}$`);
const url = `${location.protocol}//${location.host}${location.pathname}`;
return url.match(regexp);
};
// Run the code with chrome API integrated.
const runContentScript = function (this: any, extensionId: string, url: string, code: string) {
// Assign unique world ID to each extension
const worldId = extensionWorldId[extensionId] ||
(extensionWorldId[extensionId] = getIsolatedWorldIdForInstance());
// store extension ID for content script to read in isolated world
v8Util.setHiddenValue(global, `extension-${worldId}`, extensionId);
webFrame.setIsolatedWorldInfo(worldId, {
name: `${extensionId} [${worldId}]`
// TODO(samuelmaddock): read `content_security_policy` from extension manifest
// csp: manifest.content_security_policy,
});
const sources = [{ code, url }];
return webFrame.executeJavaScriptInIsolatedWorld(worldId, sources);
};
const runAllContentScript = function (scripts: Array<Electron.InjectionBase>, extensionId: string) {
for (const { url, code } of scripts) {
runContentScript.call(window, extensionId, url, code);
}
};
const runStylesheet = function (this: any, url: string, code: string) {
webFrame.insertCSS(code);
};
const runAllStylesheet = function (css: Array<Electron.InjectionBase>) {
for (const { url, code } of css) {
runStylesheet.call(window, url, code);
}
};
// Run injected scripts.
// https://developer.chrome.com/extensions/content_scripts
const injectContentScript = function (extensionId: string, script: Electron.ContentScript) {
if (!process.isMainFrame && !script.allFrames) return;
if (!script.matches.some(matchesPattern)) return;
if (script.js) {
const fire = runAllContentScript.bind(window, script.js, extensionId);
if (script.runAt === 'document_start') {
process.once('document-start', fire);
} else if (script.runAt === 'document_end') {
process.once('document-end', fire);
} else {
document.addEventListener('DOMContentLoaded', fire);
}
}
if (script.css) {
const fire = runAllStylesheet.bind(window, script.css);
if (script.runAt === 'document_start') {
process.once('document-start', fire);
} else if (script.runAt === 'document_end') {
process.once('document-end', fire);
} else {
document.addEventListener('DOMContentLoaded', fire);
}
}
};
// Handle the request of chrome.tabs.executeJavaScript.
ipcRendererUtils.handle('CHROME_TABS_EXECUTE_SCRIPT', function (
event: Electron.Event,
extensionId: string,
url: string,
code: string
) {
return runContentScript.call(window, extensionId, url, code);
});
module.exports = (entries: Electron.ContentScriptEntry[]) => {
for (const entry of entries) {
if (entry.contentScripts) {
for (const script of entry.contentScripts) {
injectContentScript(entry.extensionId, script);
}
}
}
};

View File

@@ -1,20 +0,0 @@
export class Event {
private listeners: Function[] = []
addListener (callback: Function) {
this.listeners.push(callback);
}
removeListener (callback: Function) {
const index = this.listeners.indexOf(callback);
if (index !== -1) {
this.listeners.splice(index, 1);
}
}
emit (...args: any[]) {
for (const listener of this.listeners) {
listener(...args);
}
}
}

View File

@@ -1,60 +0,0 @@
// Implementation of chrome.i18n.getMessage
// https://developer.chrome.com/extensions/i18n#method-getMessage
//
// Does not implement predefined messages:
// https://developer.chrome.com/extensions/i18n#overview-predefined
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils';
interface Placeholder {
content: string;
example?: string;
}
const getMessages = (extensionId: number) => {
try {
const data = ipcRendererUtils.invokeSync<string>('CHROME_GET_MESSAGES', extensionId);
return JSON.parse(data) || {};
} catch {
return {};
}
};
const replaceNumberedSubstitutions = (message: string, substitutions: string[]) => {
return message.replace(/\$(\d+)/, (_, number) => {
const index = parseInt(number, 10) - 1;
return substitutions[index] || '';
});
};
const replacePlaceholders = (message: string, placeholders: Record<string, Placeholder>, substitutions: string[] | string) => {
if (typeof substitutions === 'string') substitutions = [substitutions];
if (!Array.isArray(substitutions)) substitutions = [];
if (placeholders) {
Object.keys(placeholders).forEach((name: string) => {
let { content } = placeholders[name];
const substitutionsArray = Array.isArray(substitutions) ? substitutions : [];
content = replaceNumberedSubstitutions(content, substitutionsArray);
message = message.replace(new RegExp(`\\$${name}\\$`, 'gi'), content);
});
}
return replaceNumberedSubstitutions(message, substitutions);
};
const getMessage = (extensionId: number, messageName: string, substitutions: string[]) => {
const messages = getMessages(extensionId);
if (Object.prototype.hasOwnProperty.call(messages, messageName)) {
const { message, placeholders } = messages[messageName];
return replacePlaceholders(message, placeholders, substitutions);
}
};
exports.setup = (extensionId: number) => {
return {
getMessage (messageName: string, substitutions: string[]) {
return getMessage(extensionId, messageName, substitutions);
}
};
};

View File

@@ -1,86 +0,0 @@
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
const getStorage = (storageType: string, extensionId: number, callback: Function) => {
if (typeof callback !== 'function') throw new TypeError('No callback provided');
ipcRendererInternal.invoke<string>('CHROME_STORAGE_READ', storageType, extensionId)
.then(data => {
if (data !== null) {
callback(JSON.parse(data));
} else {
// Disabled due to false positive in StandardJS
// eslint-disable-next-line standard/no-callback-literal
callback({});
}
});
};
const setStorage = (storageType: string, extensionId: number, storage: Record<string, any>, callback: Function) => {
const json = JSON.stringify(storage);
ipcRendererInternal.invoke('CHROME_STORAGE_WRITE', storageType, extensionId, json)
.then(() => {
if (callback) callback();
});
};
const getStorageManager = (storageType: string, extensionId: number) => {
return {
get (keys: string[], callback: Function) {
getStorage(storageType, extensionId, (storage: Record<string, any>) => {
if (keys == null) return callback(storage);
let defaults: Record<string, any> = {};
switch (typeof keys) {
case 'string':
keys = [keys];
break;
case 'object':
if (!Array.isArray(keys)) {
defaults = keys;
keys = Object.keys(keys);
}
break;
}
// Disabled due to false positive in StandardJS
// eslint-disable-next-line standard/no-callback-literal
if (keys.length === 0) return callback({});
const items: Record<string, any> = {};
keys.forEach((key: string) => {
let value = storage[key];
if (value == null) value = defaults[key];
items[key] = value;
});
callback(items);
});
},
set (items: Record<string, any>, callback: Function) {
getStorage(storageType, extensionId, (storage: Record<string, any>) => {
Object.keys(items).forEach(name => { storage[name] = items[name]; });
setStorage(storageType, extensionId, storage, callback);
});
},
remove (keys: string[], callback: Function) {
getStorage(storageType, extensionId, (storage: Record<string, any>) => {
if (!Array.isArray(keys)) keys = [keys];
keys.forEach((key: string) => {
delete storage[key];
});
setStorage(storageType, extensionId, storage, callback);
});
},
clear (callback: Function) {
setStorage(storageType, extensionId, {}, callback);
}
};
};
export const setup = (extensionId: number) => ({
sync: getStorageManager('sync', extensionId),
local: getStorageManager('local', extensionId)
});

View File

@@ -1,19 +0,0 @@
import { Event } from '@electron/internal/renderer/extensions/event';
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
class WebNavigation {
private onBeforeNavigate = new Event()
private onCompleted = new Event()
constructor () {
ipcRendererInternal.on('CHROME_WEBNAVIGATION_ONBEFORENAVIGATE', (event: Electron.IpcRendererEvent, details: any) => {
this.onBeforeNavigate.emit(details);
});
ipcRendererInternal.on('CHROME_WEBNAVIGATION_ONCOMPLETED', (event: Electron.IpcRendererEvent, details: any) => {
this.onCompleted.emit(details);
});
}
}
export const setup = () => new WebNavigation();

View File

@@ -9,7 +9,7 @@
},
"dependencies": {
"@electron/get": "^1.0.1",
"@types/node": "^12.0.12",
"@types/node": "^14.6.2",
"extract-zip": "^1.0.3"
},
"engines": {

View File

@@ -1,11 +1,11 @@
{
"name": "electron",
"version": "11.0.0-nightly.20200826",
"version": "12.0.0-nightly.20200918",
"repository": "https://github.com/electron/electron",
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
"devDependencies": {
"@electron/docs-parser": "^0.9.1",
"@electron/typescript-definitions": "^8.7.5",
"@electron/typescript-definitions": "^8.7.9",
"@octokit/rest": "^18.0.3",
"@primer/octicons": "^10.0.0",
"@types/basic-auth": "^1.1.3",
@@ -16,7 +16,7 @@
"@types/express": "^4.17.7",
"@types/fs-extra": "^9.0.1",
"@types/mocha": "^7.0.2",
"@types/node": "^12.12.6",
"@types/node": "^14.6.2",
"@types/semver": "^7.3.3",
"@types/send": "^0.14.5",
"@types/split": "^1.0.0",

View File

@@ -100,3 +100,4 @@ remove_some_deps_that_do_not_work_on_arm64.patch
fix_check_issecureeventinputenabled_in_constructor_before_setting.patch
skip_atk_toolchain_check.patch
worker_feat_add_hook_to_notify_script_ready.patch
fix_properly_honor_printing_page_ranges.patch

View File

@@ -0,0 +1,129 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Thu, 20 Aug 2020 10:55:48 -0700
Subject: fix: properly honor printing page ranges
The print ranges in Chromium's print job settings were not being properly
plumbed through to PMPrintSettings on mcOS. This fixes that by setting
them should they exist.
This will be upstreamed.
diff --git a/printing/printing_context_mac.h b/printing/printing_context_mac.h
index 06cdc0e1a4a50e29a148c97c964c30a939e800da..5db5cdb61be0beee4506313dcde46c499e011383 100644
--- a/printing/printing_context_mac.h
+++ b/printing/printing_context_mac.h
@@ -81,6 +81,10 @@ class PRINTING_EXPORT PrintingContextMac : public PrintingContext {
// Returns true if the orientation was set.
bool SetOrientationIsLandscape(bool landscape);
+ // Set the page range in native print info object.
+ // Returns true if the range was set.
+ bool SetPrintRangeInPrintSettings(const PageRanges& ranges);
+
// Sets duplex mode in PMPrintSettings.
// Returns true if duplex mode is set.
bool SetDuplexModeInPrintSettings(mojom::DuplexMode mode);
diff --git a/printing/printing_context_mac.mm b/printing/printing_context_mac.mm
index 56bcfbe625537c7b1bc2a999c261836bb15896ba..f916e78de99b87e0dae4f5f87329886b658ccd93 100644
--- a/printing/printing_context_mac.mm
+++ b/printing/printing_context_mac.mm
@@ -188,7 +188,8 @@ PMPaper MatchPaper(CFArrayRef paper_list,
!SetCopiesInPrintSettings(settings_->copies()) ||
!SetCollateInPrintSettings(settings_->collate()) ||
!SetDuplexModeInPrintSettings(settings_->duplex_mode()) ||
- !SetOutputColor(settings_->color())) {
+ !SetOutputColor(settings_->color()) ||
+ !SetPrintRangeInPrintSettings(settings_->ranges()) ) {
return OnError();
}
}
@@ -341,6 +342,22 @@ PMPaper MatchPaper(CFArrayRef paper_list,
return PMSetCopies(print_settings, copies, false) == noErr;
}
+bool PrintingContextMac::SetPrintRangeInPrintSettings(const PageRanges& ranges) {
+ // Default is already NSPrintAllPages - we can safely bail.
+ if (ranges.empty())
+ return true;
+
+ auto* print_settings =
+ static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
+
+ // macOS does not allow multiple ranges, so pluck the first.
+ auto range = ranges.front();
+ bool set_first_page = PMSetFirstPage(print_settings, range.from + 1, false) == noErr;
+ bool set_last_page = PMSetLastPage(print_settings, range.to + 1, false) == noErr;
+
+ return set_first_page && set_last_page;
+}
+
bool PrintingContextMac::SetCollateInPrintSettings(bool collate) {
PMPrintSettings print_settings =
static_cast<PMPrintSettings>([print_info_.get() PMPrintSettings]);
diff --git a/printing/printing_context_system_dialog_win.cc b/printing/printing_context_system_dialog_win.cc
index d3c8677f30d72efc49b28f293260c74c7b8d8b4e..f6e66aaa58ab1881d64dcbb320ae8b5ac7631b28 100644
--- a/printing/printing_context_system_dialog_win.cc
+++ b/printing/printing_context_system_dialog_win.cc
@@ -52,14 +52,28 @@ void PrintingContextSystemDialogWin::AskUserForSettings(
PRINTPAGERANGE ranges[32];
dialog_options.nStartPage = START_PAGE_GENERAL;
if (max_pages) {
- // Default initialize to print all the pages.
memset(ranges, 0, sizeof(ranges));
- ranges[0].nFromPage = 1;
- ranges[0].nToPage = max_pages;
- dialog_options.nPageRanges = 1;
- dialog_options.nMaxPageRanges = base::size(ranges);
+
+ auto page_ranges = settings_->ranges();
+ if (!page_ranges.empty()) {
+ for (size_t i = 0; i < page_ranges.size(); i++) {
+ auto range = page_ranges[i];
+ ranges[i].nFromPage = range.from + 1;
+ ranges[i].nToPage = range.to + 1;
+ }
+ dialog_options.nPageRanges = page_ranges.size();
+
+ // Ensure the Pages radio button is selected.
+ dialog_options.Flags |= PD_PAGENUMS;
+ } else {
+ ranges[0].nFromPage = 1;
+ ranges[0].nToPage = max_pages;
+ dialog_options.nPageRanges = 1;
+ }
+
dialog_options.nMinPage = 1;
dialog_options.nMaxPage = max_pages;
+ dialog_options.nMaxPageRanges = base::size(ranges);
dialog_options.lpPageRanges = ranges;
} else {
// No need to bother, we don't know how many pages are available.
diff --git a/ui/gtk/printing/print_dialog_gtk.cc b/ui/gtk/printing/print_dialog_gtk.cc
index 8a78a609295a1d90208bdc7e73d7a850c319f361..2f5bc01bedf84126d8fb1597a0b813a2b7230279 100644
--- a/ui/gtk/printing/print_dialog_gtk.cc
+++ b/ui/gtk/printing/print_dialog_gtk.cc
@@ -239,6 +239,23 @@ void PrintDialogGtk::UpdateSettings(
gtk_print_settings_set_n_copies(gtk_settings_, settings->copies());
gtk_print_settings_set_collate(gtk_settings_, settings->collate());
+
+ auto print_ranges = settings->ranges();
+ if (!print_ranges.empty()) {
+ // Tell the system that we only intend to print a subset of pages.
+ gtk_print_settings_set_print_pages(gtk_settings_, GTK_PRINT_PAGES_RANGES);
+
+ GtkPageRange* ranges;
+ ranges = g_new(GtkPageRange, print_ranges.size());
+ for (size_t i = 0; i < print_ranges.size(); i++) {
+ auto range = print_ranges[i];
+ ranges[i].start = range.from;
+ ranges[i].end = range.to;
+ }
+
+ gtk_print_settings_set_page_ranges(gtk_settings_, ranges, 1);
+ g_free(ranges);
+ }
#if defined(USE_CUPS)
// Set advanced settings first so they can be overridden by user applied

View File

@@ -22,24 +22,14 @@ chore_prevent_warn_non_context-aware_native_modules_being_loaded.patch
chore_read_nobrowserglobals_from_global_not_process.patch
build_bring_back_node_with_ltcg_configuration.patch
revert_crypto_add_oaeplabel_option.patch
refactor_transferrablemodule_is_deprecated_use_compiledwasmmodule.patch
enable_31_bit_smis_on_64bit_arch_and_ptr_compression.patch
remove_deprecated_task_api_override_removed_in_latest_v8.patch
remove_serialization_deserialization_of_wasmmoduleobject.patch
override_existing_v8_reallocate.patch
fix_use_crypto_impls_for_compat.patch
avoid_calling_deprecated_method.patch
remove_deprecated_wasm_module_type_check.patch
weakrefs_rename_finalizationgroup_to_finalizationregistry_for_js.patch
weakrefs_split_out_finalizationregistry_cleanupsome.patch
fix_window_c-ares_incompatibilities.patch
chore_sethostcleanupfinalizationgroupcallback_has_been_removed_from.patch
fix_comment_out_incompatible_crypto_modules.patch
lib_src_switch_buffer_kmaxlength_to_size_t.patch
update_tests_after_increasing_typed_array_size.patch
darwin_work_around_clock_jumping_back_in_time.patch
fix_do_not_register_the_esm_loader_in_renderer_processes.patch
fix_allow_preventing_setpromiserejectcallback.patch
lib_use_non-symbols_in_isurlinstance_check.patch
feat_add_implementation_of_v8_platform_postjob.patch
fix_enable_tls_renegotiation.patch
n-api_src_provide_asynchronous_cleanup_hooks.patch
crypto_update_certdata_to_nss_3_56.patch
fix_-wincompatible-pointer-types-discards-qualifiers_error.patch
fix_allow_preventing_initializeinspector_in_env.patch
test_make_some_tests_embedder_agnostic.patch

View File

@@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <samuel.r.attard@gmail.com>
Date: Thu, 13 Feb 2020 10:34:31 -0800
Subject: Avoid calling deprecated method
The {SetExpectInlineWasm} method is deprecated and non-functional since
V8 v8.1.
This is already present in Node.js v14 and can be removed when we upgrade.
diff --git a/src/node_serdes.cc b/src/node_serdes.cc
index bcdcd19b261e8815e3c0c0f150f2eda72ef47cf5..86fb822dd5bfa9da7767418e6c6f206f8e96ca73 100644
--- a/src/node_serdes.cc
+++ b/src/node_serdes.cc
@@ -286,7 +286,6 @@ DeserializerContext::DeserializerContext(Environment* env,
length_(Buffer::Length(buffer)),
deserializer_(env->isolate(), data_, length_, this) {
object()->Set(env->context(), env->buffer_string(), buffer).Check();
- deserializer_.SetExpectInlineWasm(true);
MakeWeak();
}

View File

@@ -7,10 +7,10 @@ This adds GN build files for Node, so we don't have to build with GYP.
diff --git a/BUILD.gn b/BUILD.gn
new file mode 100644
index 0000000000000000000000000000000000000000..99192976f2bdfd900240aa58b8989fe2c9d8c771
index 0000000000000000000000000000000000000000..446119163d1f7bad577cb0b7b217ecf24b994526
--- /dev/null
+++ b/BUILD.gn
@@ -0,0 +1,361 @@
@@ -0,0 +1,360 @@
+import("//electron/build/asar.gni")
+import("//v8/gni/v8.gni")
+
@@ -205,7 +205,6 @@ index 0000000000000000000000000000000000000000..99192976f2bdfd900240aa58b8989fe2
+ ":node_js2c",
+ "deps/cares",
+ "deps/histogram",
+ "deps/http_parser",
+ "deps/llhttp",
+ "deps/nghttp2",
+ "deps/uvwasi",
@@ -532,25 +531,6 @@ index 0000000000000000000000000000000000000000..e741a2a9c238a782a674ddcb9a1f98de
+ "src/hdr_histogram.h",
+ ]
+}
diff --git a/deps/http_parser/BUILD.gn b/deps/http_parser/BUILD.gn
new file mode 100644
index 0000000000000000000000000000000000000000..da9e2b42dccacc1ed9b00202c1ff73ebc60d0e8a
--- /dev/null
+++ b/deps/http_parser/BUILD.gn
@@ -0,0 +1,13 @@
+config("http_parser_config") {
+ defines = [ "HTTP_PARSER_STRICT=0" ]
+ include_dirs = [ "." ]
+}
+
+static_library("http_parser") {
+ include_dirs = [ "." ]
+ public_configs = [ ":http_parser_config" ]
+ cflags_c = [ "-Wno-string-conversion" ]
+ sources = [
+ "http_parser.c",
+ ]
+}
diff --git a/deps/llhttp/BUILD.gn b/deps/llhttp/BUILD.gn
new file mode 100644
index 0000000000000000000000000000000000000000..ce15bc57093caa1bd84ea77e7438e892fb916427
@@ -625,7 +605,7 @@ index 0000000000000000000000000000000000000000..66af819990b338caa49ca59d1fe6c5ad
+}
diff --git a/deps/uv/BUILD.gn b/deps/uv/BUILD.gn
new file mode 100644
index 0000000000000000000000000000000000000000..67116f2070bb9200aace81afdf0b1e7a6e4fd0c0
index 0000000000000000000000000000000000000000..565819942513be6b7e9d7ad21c8531ad51a8d557
--- /dev/null
+++ b/deps/uv/BUILD.gn
@@ -0,0 +1,191 @@
@@ -664,6 +644,7 @@ index 0000000000000000000000000000000000000000..67116f2070bb9200aace81afdf0b1e7a
+ defines += [ "BUILDING_UV_SHARED=1" ]
+
+ cflags_c = [
+ "-Wno-incompatible-pointer-types",
+ "-Wno-bitwise-op-parentheses",
+ "-Wno-implicit-function-declaration",
+ "-Wno-missing-braces",
@@ -806,7 +787,6 @@ index 0000000000000000000000000000000000000000..67116f2070bb9200aace81afdf0b1e7a
+ "src/unix/procfs-exepath.c",
+ "src/unix/random-getrandom.c",
+ "src/unix/random-sysctl-linux.c",
+ "src/unix/sysinfo-loadavg.c",
+ ]
+ libs += [
+ "dl",
@@ -866,10 +846,10 @@ index 0000000000000000000000000000000000000000..2c9d2826c85bdd033f1df1d6188df636
+}
diff --git a/filenames.json b/filenames.json
new file mode 100644
index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a56f4d6751
index 0000000000000000000000000000000000000000..b09510a6048f6cff3905240e3c969f143a382047
--- /dev/null
+++ b/filenames.json
@@ -0,0 +1,519 @@
@@ -0,0 +1,527 @@
+// This file is automatically generated by generate_gn_filenames_json.py
+// DO NOT EDIT
+{
@@ -892,6 +872,7 @@ index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a5
+ "//v8/include/cppgc/allocation.h",
+ "//v8/include/cppgc/common.h",
+ "//v8/include/cppgc/custom-space.h",
+ "//v8/include/cppgc/default-platform.h",
+ "//v8/include/cppgc/garbage-collected.h",
+ "//v8/include/cppgc/heap.h",
+ "//v8/include/cppgc/liveness-broker.h",
@@ -929,6 +910,7 @@ index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a5
+ "//v8/include/v8-cppgc.h",
+ "//v8/include/v8-fast-api-calls.h",
+ "//v8/include/v8-internal.h",
+ "//v8/include/v8-metrics.h",
+ "//v8/include/v8-platform.h",
+ "//v8/include/v8-profiler.h",
+ "//v8/include/v8-util.h",
@@ -1001,6 +983,7 @@ index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a5
+ "lib/domain.js",
+ "lib/events.js",
+ "lib/fs.js",
+ "lib/fs/promises.js",
+ "lib/http.js",
+ "lib/http2.js",
+ "lib/_http_agent.js",
@@ -1045,6 +1028,7 @@ index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a5
+ "lib/zlib.js",
+ "lib/internal/assert.js",
+ "lib/internal/assert/assertion_error.js",
+ "lib/internal/assert/calltracker.js",
+ "lib/internal/async_hooks.js",
+ "lib/internal/buffer.js",
+ "lib/internal/cli_table.js",
@@ -1076,7 +1060,8 @@ index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a5
+ "lib/internal/dtrace.js",
+ "lib/internal/encoding.js",
+ "lib/internal/errors.js",
+ "lib/internal/error-serdes.js",
+ "lib/internal/error_serdes.js",
+ "lib/internal/event_target.js",
+ "lib/internal/fixed_queue.js",
+ "lib/internal/freelist.js",
+ "lib/internal/freeze_intrinsics.js",
@@ -1151,6 +1136,7 @@ index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a5
+ "lib/internal/url.js",
+ "lib/internal/util.js",
+ "lib/internal/util/comparisons.js",
+ "lib/internal/util/compositekey.js",
+ "lib/internal/util/debuglog.js",
+ "lib/internal/util/inspect.js",
+ "lib/internal/util/inspector.js",
@@ -1165,6 +1151,7 @@ index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a5
+ "lib/internal/vm/module.js",
+ "lib/internal/worker.js",
+ "lib/internal/worker/io.js",
+ "lib/internal/worker/js_transferable.js",
+ "lib/internal/watchdog.js",
+ "lib/internal/streams/lazy_transform.js",
+ "lib/internal/streams/async_iterator.js",
@@ -1223,6 +1210,7 @@ index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a5
+ "src/js_native_api_v8_internals.h",
+ "src/js_stream.cc",
+ "src/json_utils.cc",
+ "src/js_udp_wrap.cc",
+ "src/module_wrap.cc",
+ "src/node.cc",
+ "src/node_api.cc",
@@ -1236,8 +1224,7 @@ index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a5
+ "src/node_env_var.cc",
+ "src/node_errors.cc",
+ "src/node_file.cc",
+ "src/node_http_parser_llhttp.cc",
+ "src/node_http_parser_traditional.cc",
+ "src/node_http_parser.cc",
+ "src/node_http2.cc",
+ "src/node_i18n.cc",
+ "src/node_main_instance.cc",
@@ -1272,7 +1259,6 @@ index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a5
+ "src/node_zlib.cc",
+ "src/pipe_wrap.cc",
+ "src/process_wrap.cc",
+ "src/sharedarraybuffer_metadata.cc",
+ "src/signal_wrap.cc",
+ "src/spawn_sync.cc",
+ "src/stream_base.cc",
@@ -1292,6 +1278,10 @@ index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a5
+ "src/util.cc",
+ "src/uv.cc",
+ "src/aliased_buffer.h",
+ "src/aliased_struct.h",
+ "src/aliased_struct-inl.h",
+ "src/allocated_buffer.h",
+ "src/allocated_buffer-inl.h",
+ "src/async_wrap.h",
+ "src/async_wrap-inl.h",
+ "src/base_object.h",
@@ -1308,7 +1298,6 @@ index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a5
+ "src/handle_wrap.h",
+ "src/histogram.h",
+ "src/histogram-inl.h",
+ "src/http_parser_adaptor.h",
+ "src/js_stream.h",
+ "src/json_utils.h",
+ "src/large_pages/node_large_page.cc",
@@ -1328,7 +1317,8 @@ index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a5
+ "src/node_errors.h",
+ "src/node_file.h",
+ "src/node_file-inl.h",
+ "src/node_http_parser_impl.h",
+ "src/node_http_common.h",
+ "src/node_http_common-inl.h",
+ "src/node_http2.h",
+ "src/node_http2_state.h",
+ "src/node_i18n.h",
@@ -1364,7 +1354,6 @@ index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a5
+ "src/pipe_wrap.h",
+ "src/req_wrap.h",
+ "src/req_wrap-inl.h",
+ "src/sharedarraybuffer_metadata.h",
+ "src/spawn_sync.h",
+ "src/stream_base.h",
+ "src/stream_base-inl.h",
@@ -1385,8 +1374,7 @@ index 0000000000000000000000000000000000000000..2e07ea28437ee25ddaea4d730e1a65a5
+ "src/udp_wrap.h",
+ "src/util.h",
+ "src/util-inl.h",
+ "deps/http_parser/http_parser.h",
+ "deps/v8/include/v8.h"
+ "//v8/include/v8.h"
+ ]
+}
diff --git a/src/inspector/BUILD.gn b/src/inspector/BUILD.gn
@@ -1595,7 +1583,7 @@ index 0000000000000000000000000000000000000000..f3c5c798c0aefcb8cf9b1570a7b4817c
+ args = rebase_path(inputs + outputs, root_build_dir)
+}
diff --git a/src/node_version.h b/src/node_version.h
index 9252d51555f0e1bf0957bc4f8bc6e399c1ac6c23..431dd57a7dddc7476a179a5f30ce9e66814006ec 100644
index 49e4e9d16f8732641248fd3ab15be1a74d9fd45f..35f90fcae715c5421c672a9397a8e25d93f80cd6 100644
--- a/src/node_version.h
+++ b/src/node_version.h
@@ -89,7 +89,10 @@
@@ -1604,7 +1592,7 @@ index 9252d51555f0e1bf0957bc4f8bc6e399c1ac6c23..431dd57a7dddc7476a179a5f30ce9e66
*/
+// Electron sets NODE_MODULE_VERSION in their GN configuration
+#ifndef NODE_MODULE_VERSION
#define NODE_MODULE_VERSION 72
#define NODE_MODULE_VERSION 83
+#endif
// The NAPI_VERSION provided by this version of the runtime. This is the version

View File

@@ -10,7 +10,7 @@ THe fix for this should land in node-gyp as discussed in above issue,
landing this as temporary patch.
diff --git a/common.gypi b/common.gypi
index df69aecc74ef66b9501d4bed0e1311e7cda2d5b8..dfcf529cd501dc890c05425fcf9a33414a45f1a5 100644
index 2fda2d685edc6b8f45441cda017f7cabfe60d91f..bd42d6cfa6006630d316faf2cddd93bea57102ba 100644
--- a/common.gypi
+++ b/common.gypi
@@ -19,7 +19,7 @@
@@ -22,7 +22,7 @@ index df69aecc74ef66b9501d4bed0e1311e7cda2d5b8..dfcf529cd501dc890c05425fcf9a3341
'node_shared_openssl%': 'false',
'node_tag%': '',
@@ -239,6 +239,26 @@
@@ -215,6 +215,26 @@
'cflags': [ '-fPIC' ],
'ldflags': [ '-fPIC' ]
}],

View File

@@ -14,7 +14,7 @@ renderer/browser/worker/sandboxed bootstrap scripts). These are loaded
through LoadEmbedderJavaScriptSource()
diff --git a/src/node_native_module.cc b/src/node_native_module.cc
index 7362207412efa49bddfab4e32a64c7e07cf29074..acd9afa62d3aa1b01ce54f189a7261e7e61aa60d 100644
index 74729c412674be2cbf01d68be1bc496b06b8ce1e..7311f249fbb24e0612d9f4f174e96fa13ed77acb 100644
--- a/src/node_native_module.cc
+++ b/src/node_native_module.cc
@@ -20,6 +20,7 @@ NativeModuleLoader NativeModuleLoader::instance_;
@@ -26,7 +26,7 @@ index 7362207412efa49bddfab4e32a64c7e07cf29074..acd9afa62d3aa1b01ce54f189a7261e7
NativeModuleLoader* NativeModuleLoader::GetInstance() {
diff --git a/src/node_native_module.h b/src/node_native_module.h
index c0bce3bce42c848d63a10147ef483c9d4465f5ce..7f296e459d46b4cda51baf9887df060f0372227d 100644
index 3be3f2364dd252bcdd668c699a0e7ae1e754e873..b2af1bce312ffca44e7005e11f92327e7cb240f6 100644
--- a/src/node_native_module.h
+++ b/src/node_native_module.h
@@ -44,6 +44,7 @@ class NativeModuleLoader {

View File

@@ -6,10 +6,10 @@ Subject: Call process.log from fallback stream on Windows
(cherry picked from commit d31e629b4f2daf3500a485caab2b2990a41e3ad4)
diff --git a/lib/internal/bootstrap/switches/is_main_thread.js b/lib/internal/bootstrap/switches/is_main_thread.js
index ac8336fb6229e7f44eb00f43abb07bea83a9463c..2005e8ef9ebd090c1be19ff320f48b9cd365239e 100644
index 08623898edafacfa8cee47ab35bd75887f9d3e2a..828589d4047ac49d16e9080ad1f364484941aa6e 100644
--- a/lib/internal/bootstrap/switches/is_main_thread.js
+++ b/lib/internal/bootstrap/switches/is_main_thread.js
@@ -80,6 +80,11 @@ function createWritableStdioStream(fd) {
@@ -85,6 +85,11 @@ function createWritableStdioStream(fd) {
const { Writable } = require('stream');
stream = new Writable({
write(buf, enc, cb) {

View File

@@ -8,25 +8,31 @@ once we stop warning and begin to unilaterally prevent non-context aware modules
from being loaded.
diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js
index 0a7c4a47c11eb4bb360b6a46fccb4692241bd2dc..b4a0f71af5853f427a10449b52509052fbe3facd 100644
index f947c6bf27e80c534a8f72265d0139a8b5b3f13a..d7e56d9c3fe5a56897989915984cb823d27b9c52 100644
--- a/lib/internal/bootstrap/pre_execution.js
+++ b/lib/internal/bootstrap/pre_execution.js
@@ -89,8 +89,10 @@ function patchProcessObject(expandArgv1) {
@@ -92,10 +92,12 @@ function patchProcessObject(expandArgv1) {
if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-')) {
// Expand process.argv[1] into a full path.
- const path = require('path');
- try {
- process.argv[1] = path.resolve(process.argv[1]);
- } catch {}
+ if (!process.argv[1] || !process.argv[1].startsWith('electron/js2c')) {
const path = require('path');
process.argv[1] = path.resolve(process.argv[1]);
+ const path = require('path');
+ try {
+ process.argv[1] = path.resolve(process.argv[1]);
+ } catch {}
+ }
}
// TODO(joyeecheung): most of these should be deprecated and removed,
diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js
index 7d08fb05e9a0abeb82d416891968b23002dc3685..1f6f5e0cee36fb2a07963264f513a930c349b8fa 100644
index c633daa2b3557c98b05cca5f428d87775ef8a02a..4846370adb5206c53d57deef303b2c3f02342d24 100644
--- a/lib/internal/modules/cjs/loader.js
+++ b/lib/internal/modules/cjs/loader.js
@@ -1111,6 +1111,13 @@ Module.prototype._compile = function(content, filename) {
@@ -1049,6 +1049,13 @@ Module.prototype._compile = function(content, filename) {
if (getOptionValue('--inspect-brk') && process._eval == null) {
if (!resolvedArgv) {
// We enter the repl if we're not given a filename argument.
@@ -41,11 +47,11 @@ index 7d08fb05e9a0abeb82d416891968b23002dc3685..1f6f5e0cee36fb2a07963264f513a930
try {
resolvedArgv = Module._resolveFilename(process.argv[1], null, false);
diff --git a/src/env.h b/src/env.h
index d22b579b25ce4e6af8ec042e282e94248ea14162..67cefbe35f390ba25b49e422d10bca8b423a49a8 100644
index bc222804010a035333cf6d7becc9a0a8f385af85..dea62b38cb20a0a0913128e17e8904c4ca71ac1a 100644
--- a/src/env.h
+++ b/src/env.h
@@ -890,6 +890,15 @@ class Environment : public MemoryRetainer {
uint64_t thread_id = kNoThreadId);
@@ -885,6 +885,15 @@ class Environment : public MemoryRetainer {
ThreadId thread_id);
~Environment() override;
+ void ForceOnlyContextAwareNativeModules() {
@@ -57,10 +63,10 @@ index d22b579b25ce4e6af8ec042e282e94248ea14162..67cefbe35f390ba25b49e422d10bca8b
+ bool force_context_aware() { return force_context_aware_; }
+ bool warn_non_context_aware() { return warn_non_context_aware_; }
+
void InitializeLibuv(bool start_profiler_idle_notifier);
void InitializeLibuv();
inline const std::vector<std::string>& exec_argv();
inline const std::vector<std::string>& argv();
@@ -1271,6 +1280,9 @@ class Environment : public MemoryRetainer {
@@ -1235,6 +1244,9 @@ class Environment : public MemoryRetainer {
inline void ThrowError(v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
const char* errmsg);
@@ -71,7 +77,7 @@ index d22b579b25ce4e6af8ec042e282e94248ea14162..67cefbe35f390ba25b49e422d10bca8b
v8::Isolate* const isolate_;
IsolateData* const isolate_data_;
diff --git a/src/node_binding.cc b/src/node_binding.cc
index 5291858bb164a262ca1d69d2582e037aeab23d55..a9ce41fbba4e8b0c4704c1d7795308ce18916739 100644
index 0ab18f7aeda3511338cbf115a4b636a6c72437b2..51ae4c89a61a176a9629e537f9409b38c3397aa2 100644
--- a/src/node_binding.cc
+++ b/src/node_binding.cc
@@ -3,6 +3,7 @@

View File

@@ -7,7 +7,7 @@ This is used so that we can modify the flag at runtime where
config can only be set at compile time.
diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js
index 4e7c3c10255a0eae4d5333f88e51cf7178163a44..a6e33757ca00771671583203c37d9b121abf489b 100644
index e1f70addc28e4fe31d3a7089ecec3b5874dde75a..659145e31bbfb6ce782e8dcad452b59202df7573 100644
--- a/lib/internal/bootstrap/node.js
+++ b/lib/internal/bootstrap/node.js
@@ -118,7 +118,7 @@ const {

View File

@@ -1,145 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <samuel.r.attard@gmail.com>
Date: Mon, 4 May 2020 16:57:05 -0700
Subject: chore: SetHostCleanupFinalizationGroupCallback has been removed from
V8
diff --git a/src/api/environment.cc b/src/api/environment.cc
index e2aa9c821de685a022fd78935399b7d219468403..2bfba8a011c2b902932e6b1714bbb55b945cd96d 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -12,7 +12,6 @@ using errors::TryCatchScope;
using v8::Array;
using v8::Context;
using v8::EscapableHandleScope;
-using v8::FinalizationGroup;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::HandleScope;
@@ -72,15 +71,6 @@ static MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
return result;
}
-static void HostCleanupFinalizationGroupCallback(
- Local<Context> context, Local<FinalizationGroup> group) {
- Environment* env = Environment::GetCurrent(context);
- if (env == nullptr) {
- return;
- }
- env->RegisterFinalizationGroupForCleanup(group);
-}
-
void* NodeArrayBufferAllocator::Allocate(size_t size) {
void* ret;
if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
@@ -249,11 +239,6 @@ void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
s.promise_reject_callback : task_queue::PromiseRejectCallback;
isolate->SetPromiseRejectCallback(promise_reject_cb);
- auto* host_cleanup_cb = s.host_cleanup_finalization_group_callback ?
- s.host_cleanup_finalization_group_callback :
- HostCleanupFinalizationGroupCallback;
- isolate->SetHostCleanupFinalizationGroupCallback(host_cleanup_cb);
-
if (s.flags & DETAILED_SOURCE_POSITIONS_FOR_PROFILING)
v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate);
}
diff --git a/src/env-inl.h b/src/env-inl.h
index c6ef9dc13ab6f1d1a778871a62a0a98a01d84ec6..222555831aa1bf0b7b29b4b46e235c98a5dd4ac5 100644
--- a/src/env-inl.h
+++ b/src/env-inl.h
@@ -1123,12 +1123,6 @@ void Environment::RemoveCleanupHook(void (*fn)(void*), void* arg) {
cleanup_hooks_.erase(search);
}
-inline void Environment::RegisterFinalizationGroupForCleanup(
- v8::Local<v8::FinalizationGroup> group) {
- cleanup_finalization_groups_.emplace_back(isolate(), group);
- uv_async_send(&task_queues_async_);
-}
-
size_t CleanupHookCallback::Hash::operator()(
const CleanupHookCallback& cb) const {
return std::hash<void*>()(cb.arg_);
diff --git a/src/env.cc b/src/env.cc
index 18788e4ceaf208c13704c9c43f017bb1b6dfb0b6..ee76d5889e5672716ac2f0c586f1ddc47fa56be7 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -30,7 +30,6 @@ using v8::ArrayBuffer;
using v8::Boolean;
using v8::Context;
using v8::EmbedderGraph;
-using v8::FinalizationGroup;
using v8::Function;
using v8::FunctionTemplate;
using v8::HandleScope;
@@ -487,7 +486,6 @@ void Environment::InitializeLibuv(bool start_profiler_idle_notifier) {
[](uv_async_t* async) {
Environment* env = ContainerOf(
&Environment::task_queues_async_, async);
- env->CleanupFinalizationGroups();
env->RunAndClearNativeImmediates();
});
uv_unref(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
@@ -1085,25 +1083,6 @@ void Environment::RunWeakRefCleanup() {
isolate()->ClearKeptObjects();
}
-void Environment::CleanupFinalizationGroups() {
- HandleScope handle_scope(isolate());
- Context::Scope context_scope(context());
- TryCatchScope try_catch(this);
-
- while (!cleanup_finalization_groups_.empty() && can_call_into_js()) {
- Local<FinalizationGroup> fg =
- cleanup_finalization_groups_.front().Get(isolate());
- cleanup_finalization_groups_.pop_front();
- if (!FinalizationGroup::Cleanup(fg).FromMaybe(false)) {
- if (try_catch.HasCaught() && !try_catch.HasTerminated())
- errors::TriggerUncaughtException(isolate(), try_catch);
- // Re-schedule the execution of the remainder of the queue.
- uv_async_send(&task_queues_async_);
- return;
- }
- }
-}
-
// Not really any better place than env.cc at this moment.
void BaseObject::DeleteMe(void* data) {
BaseObject* self = static_cast<BaseObject*>(data);
diff --git a/src/env.h b/src/env.h
index 67cefbe35f390ba25b49e422d10bca8b423a49a8..9420bdf3f71e2df1011ddd7e583071f5c99beac8 100644
--- a/src/env.h
+++ b/src/env.h
@@ -1130,9 +1130,7 @@ class Environment : public MemoryRetainer {
void AtExit(void (*cb)(void* arg), void* arg);
void RunAtExitCallbacks();
- void RegisterFinalizationGroupForCleanup(v8::Local<v8::FinalizationGroup> fg);
void RunWeakRefCleanup();
- void CleanupFinalizationGroups();
// Strings and private symbols are shared across shared contexts
// The getters simply proxy to the per-isolate primitive.
@@ -1355,8 +1353,6 @@ class Environment : public MemoryRetainer {
uint64_t thread_id_;
std::unordered_set<worker::Worker*> sub_worker_contexts_;
- std::deque<v8::Global<v8::FinalizationGroup>> cleanup_finalization_groups_;
-
static void* const kNodeContextTagPtr;
static int const kNodeContextTag;
diff --git a/src/node.h b/src/node.h
index 638a1a85b046ce4db303d532f7cf36cca2271db5..b9b11b4331bd3ae4a87f65758ee09af25222e19a 100644
--- a/src/node.h
+++ b/src/node.h
@@ -322,8 +322,6 @@ struct IsolateSettings {
v8::PromiseRejectCallback promise_reject_callback = nullptr;
v8::AllowWasmCodeGenerationCallback
allow_wasm_code_generation_callback = nullptr;
- v8::HostCleanupFinalizationGroupCallback
- host_cleanup_finalization_group_callback = nullptr;
};
// Overriding IsolateSettings may produce unexpected behavior

File diff suppressed because it is too large Load Diff

View File

@@ -1,64 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ben Noordhuis <info@bnoordhuis.nl>
Date: Wed, 1 Jul 2020 10:32:57 +0200
Subject: darwin: work around clock jumping back in time
It was reported that mach_absolute_time() can jump backward in time when
the machine is suspended. Use mach_continuous_time() when available to
work around that (macOS 10.12 and up.)
Fixes: https://github.com/libuv/libuv/issues/2891
PR-URL: https://github.com/libuv/libuv/pull/2894
Reviewed-By: Phil Willoughby <philwill@fb.com>
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
diff --git a/deps/uv/src/unix/darwin.c b/deps/uv/src/unix/darwin.c
index 654aba26b1f9249e3e76b48ae1ad674d9fd12718..4f53ad1fc7f1907281013ca5dc4b251c692d3a7b 100644
--- a/deps/uv/src/unix/darwin.c
+++ b/deps/uv/src/unix/darwin.c
@@ -25,6 +25,7 @@
#include <stdint.h>
#include <errno.h>
+#include <dlfcn.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <mach-o/dyld.h> /* _NSGetExecutablePath */
@@ -32,6 +33,10 @@
#include <sys/sysctl.h>
#include <unistd.h> /* sysconf */
+static uv_once_t once = UV_ONCE_INIT;
+static uint64_t (*time_func)(void);
+static mach_timebase_info_data_t timebase;
+
int uv__platform_loop_init(uv_loop_t* loop) {
loop->cf_state = NULL;
@@ -48,15 +53,19 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
}
-uint64_t uv__hrtime(uv_clocktype_t type) {
- static mach_timebase_info_data_t info;
-
- if ((ACCESS_ONCE(uint32_t, info.numer) == 0 ||
- ACCESS_ONCE(uint32_t, info.denom) == 0) &&
- mach_timebase_info(&info) != KERN_SUCCESS)
+static void uv__hrtime_init_once(void) {
+ if (KERN_SUCCESS != mach_timebase_info(&timebase))
abort();
- return mach_absolute_time() * info.numer / info.denom;
+ time_func = (uint64_t (*)(void)) dlsym(RTLD_DEFAULT, "mach_continuous_time");
+ if (time_func == NULL)
+ time_func = mach_absolute_time;
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ uv_once(&once, uv__hrtime_init_once);
+ return time_func() * timebase.numer / timebase.denom;
}

View File

@@ -8,22 +8,21 @@ node modules will have different (wrong) ideas about how v8 structs are laid
out in memory on 64-bit machines, and will summarily fail to work.
diff --git a/common.gypi b/common.gypi
index dfcf529cd501dc890c05425fcf9a33414a45f1a5..38e7b2802f6225ac0e1ff4789b9ff8f4fb04cb79 100644
index bd42d6cfa6006630d316faf2cddd93bea57102ba..734c2917535c50e260192abe6acb4726104b7b6a 100644
--- a/common.gypi
+++ b/common.gypi
@@ -71,6 +71,9 @@
# TODO(refack): make v8-perfetto happen
'v8_use_perfetto': 0,
@@ -64,7 +64,7 @@
# options but default values are required here as this file is also used by
# node-gyp to build addons.
'v8_enable_pointer_compression%': 0,
- 'v8_enable_31bit_smis_on_64bit_arch%': 0,
+ 'v8_enable_31bit_smis_on_64bit_arch%': 1,
+ 'v8_enable_pointer_compression%': 0,
+ 'v8_enable_31bit_smis_on_64bit_arch': 1,
+
##### end V8 defaults #####
# When building native modules using 'npm install' with the system npm,
@@ -148,6 +151,9 @@
['OS=="mac"', {
'clang%': 1,
# Disable V8 untrusted code mitigations.
# See https://github.com/v8/v8/wiki/Untrusted-code-mitigations
@@ -124,6 +124,9 @@
'obj_dir%': '<(PRODUCT_DIR)/obj.target',
'v8_base': '<(PRODUCT_DIR)/libv8_snapshot.a',
}],
+ ['target_arch == "arm64" or target_arch == "x64"', {
+ 'v8_enable_pointer_compression': 1,
@@ -31,16 +30,3 @@ index dfcf529cd501dc890c05425fcf9a33414a45f1a5..38e7b2802f6225ac0e1ff4789b9ff8f4
['target_arch in "ppc64 s390x"', {
'v8_enable_backtrace': 1,
}],
@@ -378,6 +384,12 @@
}],
],
}],
+ ['v8_enable_pointer_compression == 1', {
+ 'defines': ['V8_COMPRESS_POINTERS'],
+ }],
+ ['v8_enable_pointer_compression == 1 or v8_enable_31bit_smis_on_64bit_arch == 1', {
+ 'defines': ['V8_31BIT_SMIS_ON_64BIT_ARCH'],
+ }],
['OS == "win"', {
'defines': [
'WIN32',

View File

@@ -9,10 +9,10 @@ modules to sandboxed renderers.
TODO(codebytere): remove and replace with a public facing API.
diff --git a/src/node_binding.cc b/src/node_binding.cc
index 0b5f6cfa038369be758e3b0857ee6fa594358b58..5291858bb164a262ca1d69d2582e037aeab23d55 100644
index 1072ed34667262d7ef729c3235766f056acd659c..0ab18f7aeda3511338cbf115a4b636a6c72437b2 100644
--- a/src/node_binding.cc
+++ b/src/node_binding.cc
@@ -605,6 +605,10 @@ void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
@@ -608,6 +608,10 @@ void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(exports);
}

View File

@@ -24,10 +24,10 @@ Environment on the V8 context of blink, so no new V8 context is created.
As a result, a renderer process may have multiple Node Environments in it.
diff --git a/src/node.cc b/src/node.cc
index 728785d5d2773df68a891a4c81e7b0ebfa6021bb..15abe45edb39597d4fcc686cca4d79314090fa6f 100644
index 0dc7040381889541d9b5257158c2564ef0e728a2..cda0220071196fb7eced326985002bf0588aa23f 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -122,6 +122,8 @@ using v8::Undefined;
@@ -134,6 +134,8 @@ using v8::Undefined;
using v8::V8;
using v8::Value;
@@ -36,7 +36,7 @@ index 728785d5d2773df68a891a4c81e7b0ebfa6021bb..15abe45edb39597d4fcc686cca4d7931
namespace per_process {
// node_revert.h
@@ -736,7 +738,9 @@ int InitializeNodeWithArgs(std::vector<std::string>* argv,
@@ -836,7 +838,9 @@ int InitializeNodeWithArgs(std::vector<std::string>* argv,
binding::RegisterBuiltinModules();
// Make inherited handles noninheritable.
@@ -47,7 +47,7 @@ index 728785d5d2773df68a891a4c81e7b0ebfa6021bb..15abe45edb39597d4fcc686cca4d7931
// Cache the original command line to be
// used in diagnostic reports.
@@ -770,6 +774,8 @@ int InitializeNodeWithArgs(std::vector<std::string>* argv,
@@ -870,6 +874,8 @@ int InitializeNodeWithArgs(std::vector<std::string>* argv,
if (exit_code != 0) return exit_code;
}
#endif
@@ -56,7 +56,7 @@ index 728785d5d2773df68a891a4c81e7b0ebfa6021bb..15abe45edb39597d4fcc686cca4d7931
const int exit_code = ProcessGlobalArgs(argv,
exec_argv,
@@ -814,6 +820,7 @@ int InitializeNodeWithArgs(std::vector<std::string>* argv,
@@ -914,6 +920,7 @@ int InitializeNodeWithArgs(std::vector<std::string>* argv,
}
per_process::metadata.versions.InitializeIntlVersions();
#endif
@@ -65,10 +65,10 @@ index 728785d5d2773df68a891a4c81e7b0ebfa6021bb..15abe45edb39597d4fcc686cca4d7931
NativeModuleEnv::InitializeCodeCache();
diff --git a/src/node.h b/src/node.h
index 886216e2cb533e7337bc4f6816e2de796f64f81e..8378553f28671e4685b4ed20279b2be5d202e527 100644
index 1914e72ee8fa4361379725b8d44892c8a62084e1..d051b422d7c5a51a8590abda382676d3f661b532 100644
--- a/src/node.h
+++ b/src/node.h
@@ -211,6 +211,8 @@ namespace node {
@@ -218,6 +218,8 @@ namespace node {
class IsolateData;
class Environment;

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