Compare commits

..

107 Commits

Author SHA1 Message Date
Electron Bot
14ae30aa9b Bump v12.0.13 2021-06-28 15:18:48 -07:00
John Kleinschmidt
e3a78f62b5 ci: fixup cross arch mksnapshot testing (#29923) 2021-06-28 16:53:10 -04:00
trop[bot]
5bef67a468 fix: stop window.open from hanging when prevented (#29881)
* fix: stop window.open from hanging when prevented

* add test

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2021-06-28 15:24:38 +09:00
trop[bot]
a6f26b5788 fix: properly order out child windows (#29887)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-06-25 17:55:22 +09:00
Pedro Pontes
54a7f6d865 chore: cherry-pick b77b38a3380c from chromium (#29822)
* chore: cherry-pick b77b38a3380c from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2021-06-23 15:08:18 +09:00
Pedro Pontes
de7ec574e2 chore: cherry-pick 50de6a8ddad9 from v8 (#29838)
* chore: cherry-pick 50de6a8ddad9 from v8

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-06-23 10:41:23 +09:00
Pedro Pontes
bfa682dfa3 chore: cherry-pick 910e9e40d376 from chromium (#29818)
* chore: cherry-pick 910e9e40d376 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2021-06-23 10:10:09 +09:00
trop[bot]
4baa634d7b fix: properly handle optional requestHeaders with onBeforeSendHeaders (#29834)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-06-23 10:08:34 +09:00
Pedro Pontes
3822bc8432 chore: cherry-pick d9556a80a790 from chromium (#29816)
* chore: cherry-pick d9556a80a790 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-06-22 15:11:05 +09:00
Pedro Pontes
1acec5d48b chore: cherry-pick b9ad6a864c79 from v8 (#29814)
* chore: cherry-pick b9ad6a864c79 from v8

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-06-22 15:08:30 +09:00
Pedro Pontes
31e8f75795 chore: cherry-pick 3d4f87ab5b9b from angle (#29789)
* chore: cherry-pick 3d4f87ab5b9b from angle

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-06-22 15:00:28 +09:00
Pedro Pontes
905bc4a946 chore: cherry-pick d0aadee1a60a from v8 (#29784)
* chore: cherry-pick d0aadee1a60a from v8

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2021-06-22 14:59:46 +09:00
John Kleinschmidt
9a48f2322f ci: run linux arm tests on CircleCI (#29767)
* ci: run linux arm tests on CircleCI

(cherry picked from commit c0d93a1772)

* cleanup electron dirs after testing

* use start-stop-daemon to kill Xvfb

(cherry picked from commit 1d10a68c31)

* actually call cleanup step
2021-06-22 14:58:00 +09:00
Electron Bot
088bc334f0 Bump v12.0.12 2021-06-21 10:04:07 -07:00
trop[bot]
8836c814b9 fix: do not cancel CORS preflight request on proxy auth. (#29810)
* fix: do not cancel CORS preflight request on proxy auth. (#29266)

* fix: do not cancel CORS preflight request on proxy auth.

If connecting via proxy, preflight request can receive 407
header response from proxy. This does not mean request
was finished even though it received headers (from proxy,
not the destination server), so prevent "completing"
and most importantly deleting it, which causes request
to be canceled in network layer. Just continue to monitor it
and await proper response from server. Also add circut breaker
to cancel request if proxy auth failed 3 times (for example
user keeps cancelling auth). This behavior happens only
when app registered WebRequest api listeners.

* Port chromium webrequest changes to electron code.

Move relevant parts of chromium WebRequestProxyingURLLoaderFactory from
https://chromium-review.googlesource.com/c/chromium/src/+/2011781
into electron ProxyingURLLoaderFactory.

* Update code to upstreamed version and remove retyr count failsafe.

Co-authored-by: Milan Burda <milan.burda@gmail.com>

* chore: add required header

Co-authored-by: marekharanczyk <48673767+marekharanczyk@users.noreply.github.com>
Co-authored-by: Milan Burda <milan.burda@gmail.com>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2021-06-21 21:20:27 +09:00
Pedro Pontes
5b6e117041 chore: cherry-pick 34d5af37f9ac from chromium (#29776)
* chore: cherry-pick 34d5af37f9ac from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2021-06-21 19:08:10 +09:00
trop[bot]
845716019a fix: microtasks policy in CreateEnvironment (#29807)
* fix: microtasks policy in CreateEnvironment

Microtasks policy should not be updated for the renderer because
`NodeBindings::CreateEnvironment` might be entered with or without
`UvRunOnce()` on stack. One of the examples of such calls is
`window.open()` which is possible to invoke while `uv_run()` is still
running (e.g. with `setImmediate()`).

All in all, it doesn't matter that much which policy we use since
`v8::MicrotasksScope` has a check for the policy in its destructor and
no commits will be made if the policy is `kExplicit`. It is important,
however, to not change the policy in the middle of `UvRunOnce()` so we
should respect whatever we currently have and move on.

Fix: #29463

* Move test to a better place

* Update spec-main/fixtures/crash-cases/setimmediate-window-open-crash/index.html

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

* Update spec-main/fixtures/crash-cases/setimmediate-window-open-crash/index.html

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

* simplify crash-case

* comment

* fix comment

Co-authored-by: Fedor Indutny <fedor@indutny.com>
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
Co-authored-by: Fedor Indutny <indutny@signal.org>
2021-06-21 19:06:50 +09:00
Pedro Pontes
308470c98d fix: cherry-pick 9a9c936879 from v8 (#29779)
* cherry-pick 9a9c936879 from v8

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-06-21 15:53:37 +09:00
Pedro Pontes
9a8ebbb471 chore: cherry-pick b7a1f498f1 and fad297a48a from chromium (#29786)
* cherry-pick b7a1f498f1 and fad297a48a from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-06-21 15:51:40 +09:00
trop[bot]
c90f41d0c4 fix: fix hover state not clear bug when BrowserWindow is not resizable (#611) (#29799)
Co-authored-by: sssooonnnggg <sssooonnnggg111@gmail.com>
2021-06-21 13:59:14 +09:00
trop[bot]
f275211555 fix: ensure detached devtools are not always draggable (#29736)
Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
2021-06-17 15:29:49 +09:00
trop[bot]
5b04b64397 fix: draggable regions with devtools open (#29733)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-06-17 15:20:52 +09:00
trop[bot]
066f5136d5 fix setWindowOpenHandler call syntax (#29725)
Co-authored-by: kdau <kevin@kdau.com>
2021-06-16 10:13:12 -07:00
trop[bot]
c0cc008368 fix: don't warn about enableRemoteModule when it's undefined (#29701)
* fix: don't warn about enableRemoteModule when it's undefined

* fix tests

Co-authored-by: Jeremy Rose <jeremya@chromium.org>
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2021-06-15 14:26:54 -07:00
Milan Burda
b8e7bcb621 fix: don't warn about enableRemoteModule when it's disabled at build time (#29712) 2021-06-15 14:26:44 -07:00
trop[bot]
170fb689c0 docs: coordinate system of Display.bounds and Display.workArea (#29708)
They are in DIP points (rather than screen points). We can use
screen.dipToScreen* to convert to screen points.

Co-authored-by: Jim Fisher <jameshfisher@gmail.com>
2021-06-15 16:17:49 -04:00
trop[bot]
15b11599a2 docs: Update represented-file fiddle tutorial (#29692)
* Update represented-file fiddle.

* add index and code back to guide

Co-authored-by: Kevin Hartman <kevin@hart.mn>
Co-authored-by: Ethan Arrowood <ethan.arrowood@gmail.com>
2021-06-15 11:37:04 +09:00
trop[bot]
621cc90674 docs: fix file mode of versioning-sketch-2.png (#29680)
Unlike the other files, this file had its executable bit set in its file
mode. This change removes the executable bit to align its file mode with
the rest of the files.

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

Co-authored-by: Darshan Sen <raisinten@gmail.com>
2021-06-14 10:12:24 -07:00
trop[bot]
7d791b7f46 fix: use correct spelling of attachment with Content-Disposition header (#29671)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-06-14 20:59:20 +09:00
trop[bot]
4e61bc3cfd fix: copy received data in URLPipeLoader to prevent corruption (#29668)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-06-14 17:47:00 +09:00
trop[bot]
d82832d8bc fix: improper wrapping of fs.promises.readFile (#29575)
* fix: improper wrapping of fs.promises.readFile

* test: add a regression test

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-06-14 09:35:35 +09:00
trop[bot]
7cb6f61af0 docs: fix image links in performance.md (#29630)
* docs: fix image links in performance.md

Fixes https://github.com/electron/electron/issues/29580

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

* Apply suggestions from code review

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

Co-authored-by: Darshan Sen <raisinten@gmail.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-06-14 09:33:41 +09:00
trop[bot]
4ab2254879 fix: select-bluetooth-device on Windows (#29612)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2021-06-09 12:56:02 -04:00
Electron Bot
78ce1d9758 Bump v12.0.11 2021-06-09 09:39:24 -07:00
trop[bot]
3a1d65c7c3 docs: fix typo (#29581) 2021-06-08 10:32:31 +02:00
trop[bot]
7b6b15d1ca fix: make intermediates work with 'select-client-certificate' (#29568)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-06-08 11:39:33 +09:00
Cheng Zhao
b11aed574e fix: keep shifted character in menu accelerator (#29483)
* fix: keep shifted character in menu accelerator

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-06-07 10:36:35 -04:00
trop[bot]
61e987167c docs: Update notifications (renderer) docs (#29565)
* remove version information from html

* change format for readability

* clarify which console the message should appear in

* minor changes to renderer.md

* update UI on click instead of developer console

* remove node-integration and fix md

* update content

* chore: remove ****

Co-authored-by: Jeremy Foster <jeremy.foster@live.com>
Co-authored-by: Ethan Arrowood <ethan.arrowood@gmail.com>
Co-authored-by: Cheng Zhao <github@zcbenz.com>
2021-06-07 14:44:09 +09:00
trop[bot]
4e5ce3ff98 docs: Updated "recent documents" fiddle tutorial (#29560)
* Port recent-documents fiddle to 12-x-y.

* Update recent-documents tutorial.

* update for review comments

Co-authored-by: Kevin Hartman <kevin@hart.mn>
Co-authored-by: Ethan Arrowood <ethan.arrowood@gmail.com>
2021-06-07 14:42:45 +09:00
David Sanders
7dfe949d39 fix: change ASAR archive cache to per-process to fix leak (#29548)
* fix: change ASAR archive cache to per-process to fix leak (#29292)

* chore: address code review comments

* chore: tighten up thread-safety

* chore: better address code review comments

* chore: more code review changes
2021-06-07 10:29:18 +09:00
trop[bot]
74216ec38b chore: return early on promise rejection (#29537)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-06-07 10:17:46 +09:00
Electron Bot
22e7d58365 Bump v12.0.10 2021-06-03 02:39:14 -07:00
trop[bot]
4514c34721 docs: link to IncomingMessage (#29515)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-06-03 16:19:25 +09:00
Milan Burda
43384a10f0 test: add spec for --require filtering in NODE_OPTIONS (#29506) 2021-06-03 14:45:01 +09:00
trop[bot]
6173129400 refactor: point prepare-release at main (#29497)
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2021-06-02 14:05:20 -07:00
trop[bot]
cd75862431 build: Support building Electron on msys2 (#29477)
Electron already seems to support `cygwin`, so `msys` is a natural
addition. This is the only required change as far as I can see on my
local development environment, as otherwise the build scripts don't
realize that msys = windows.

Notes: none
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>

Co-authored-by: Juan Cruz Viotti <jv@jviotti.com>
2021-06-02 22:24:44 +09:00
trop[bot]
c1a11c72e0 docs: Updated "progress bar" fiddle feature in docs (#29469)
* improve progress bar fiddle

* add comments to code snippet

* edits to progress-bar tutorial

* remove versions and nodeIntegration

* limit line length to 100

* implement standard linter suggestions

* add indeterminate and clear timers

* update to have reader replace all of main.js

* remove extra button

* loop the progress bar

* add logic to show reset state briefly

* Update docs/tutorial/progress-bar.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

* chore: fix lint

Co-authored-by: Jeremy Foster <jeremy.foster@live.com>
Co-authored-by: Cheng Zhao <github@zcbenz.com>
Co-authored-by: Erick Zhao <erick@hotmail.ca>
2021-06-02 16:17:03 +09:00
trop[bot]
473c394315 refactor: use main in release-notes (#29411)
* refactor: use main in release-notes

* fix: use default_branch in release-notes (#29415)

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2021-06-01 14:06:59 -07:00
trop[bot]
60e01470c7 chore: remove duplicate option get for CustomScheme (#29454)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-06-01 19:12:55 +09:00
trop[bot]
7c3b3a4b11 fix: Alt+Click should not toggle menu bar (#29451)
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2021-06-01 19:12:10 +09:00
David Sanders
1ab28065bb fix: add service worker schemes from command line in renderer (#29425) (#29447) 2021-06-01 17:51:34 +09:00
Cheng Zhao
6d82808adc fix: correctly handle Alt+Key shortcuts (#29445) 2021-06-01 17:43:01 +09:00
trop[bot]
4ea8896c97 Fixes issue with reference links (#29431)
Co-authored-by: Vishal <34849822+vthukral94@users.noreply.github.com>
2021-06-01 10:37:21 +09:00
trop[bot]
d6324fb942 refactor: publish-to-npm respects main (#29407) 2021-05-31 10:33:36 +02:00
trop[bot]
454f78c7a6 docs: update link to Chromium's coding style guide (#29396)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-05-31 10:20:04 +02:00
trop[bot]
cff843ae18 Update quick-start.md (#29373)
In version 13.0.1 preload process should added to webPreferences.

Co-authored-by: aydon <41415004+congjiye@users.noreply.github.com>
2021-05-27 18:53:19 -07:00
trop[bot]
36793b7fb8 docs: fix typos in clang-tidy examples (#29352)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2021-05-27 18:52:24 -07:00
trop[bot]
66f0852fdf refactor: version-utils respects main (#29390)
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2021-05-27 18:44:44 -07:00
trop[bot]
bf39abb5db refactor: getCurrentBranch respects main (#29388)
* refactor: getCurrentBranch respects main

* add note about migration

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2021-05-27 18:44:03 -07:00
trop[bot]
453a35ca13 docs: Update notifications (main) docs (#29356)
* remove version info from index.html page

* remove nodeIntegration

* format code and update readme

* add note to user in index.html

Co-authored-by: Jeremy Foster <jeremy.foster@live.com>
2021-05-27 12:41:37 -07:00
trop[bot]
5e1ccfa39a docs: fix link to docs/fiddle/quick-start (#29350)
Co-authored-by: Erick Zhao <erick@hotmail.ca>
2021-05-27 12:39:34 -07:00
John Kleinschmidt
8b02dba041 build: ensure that mksnapshot for Apple Silicon has all of the needed files for snapshot generation (#29338) (#29341)
* build: include mksnapshot args in arm64 mksnapshot.zip

* get gen/v8/embedded.S from proper location

(cherry picked from commit d0b9a931cc)
2021-05-26 19:03:41 -04:00
trop[bot]
c4b04c5d08 docs: rework introduction docs (#29300)
* docs: add 'introduction' doc

* note

* wip

* updates

* wip

* wip

* wip

* add missing code

* wip

* add image for chrome processes

* process model wip

* finish line?

* update links

* Update docs/README.md

Co-authored-by: Cheng Zhao <github@zcbenz.com>

* Update docs/tutorial/introduction.md

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

* Update docs/tutorial/quick-start.md

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

* Update docs/tutorial/process-model.md

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

* Update docs/tutorial/process-model.md

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

* Update docs/tutorial/process-model.md

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

* Update docs/tutorial/quick-start.md

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

* Update docs/tutorial/quick-start.md

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

* Update docs/tutorial/quick-start.md

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

* Update docs/tutorial/quick-start.md

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

* address code review

* Update docs/tutorial/application-distribution.md

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

* remove wip doc

* chore: fix lint error

Co-authored-by: Erick Zhao <erick@hotmail.ca>
Co-authored-by: Cheng Zhao <github@zcbenz.com>
Co-authored-by: Mark Lee <malept@users.noreply.github.com>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2021-05-24 20:29:45 +09:00
trop[bot]
a22bcb51b3 docs: Update online detection doc and fiddle (#29308)
* rework online detection doc and fiddle

* add footnote

* Update docs/tutorial/online-offline-events.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

* Update docs/tutorial/online-offline-events.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

* Update docs/tutorial/online-offline-events.md

* Update docs/tutorial/online-offline-events.md

* Update docs/tutorial/online-offline-events.md

* chore: fix lint error

Co-authored-by: Ethan Arrowood <ethan.arrowood@gmail.com>
Co-authored-by: Ethan Arrowood <ethan@arrowood.dev>
Co-authored-by: Erick Zhao <erick@hotmail.ca>
Co-authored-by: Cheng Zhao <github@zcbenz.com>
2021-05-24 20:29:07 +09:00
trop[bot]
f3a26f6911 Use path.join when logging screenshot path. (#29304)
Remove index.html from offscreen-rendering tutorial.
It is not used.

Update offscreen-rendering.md to reflect changes to fiddle.

Co-authored-by: Kevin Hartman <kevin@hart.mn>
2021-05-24 16:47:35 +09:00
trop[bot]
a4cc2af8f4 docs: Update docs for keyboard shortcuts (#29302)
* Update docs for keyboard shortcuts

* Add a fiddle for web-apis

* Apply suggestions from code review

Co-authored-by: Erick Zhao <erick@hotmail.ca>

* Cleanup a few formatting errors and missed copies

* Add descriptions to index.html

* Focus on renderer

Co-authored-by: Tony Ferrell <anf@microsoft.com>
Co-authored-by: Tony Ferrell <tonyjf@gmail.com>
Co-authored-by: Erick Zhao <erick@hotmail.ca>
2021-05-24 16:36:07 +09:00
trop[bot]
5cbfa5f975 fix: dnd for some wm that does not set _NET_CLIENT_LIST_STACKING (#29272)
* fix: dnd for some wm that does not set _NET_CLIENT_LIST_STACKING

Backports https://chromium-review.googlesource.com/c/chromium/src/+/2844104

* chore: update patches

Co-authored-by: deepak1556 <hop2deep@gmail.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-05-21 15:19:39 -07:00
Andrey Belenko
354dab3bac chore: backport security fixes from Chromium release M90-3 (#29251)
* Backports of security fixes in Chromium release M90-3
https://chromereleases.googleblog.com/2021/05/stable-channel-update-for-desktop.html

Includes backports for the following Chromium issues:
https://crbug.com/1204071
https://crbug.com/1203590 (CVE-2021-30518)
https://crbug.com/1201446 (CVE-2021-30516)
https://crbug.com/1201073 (CVE-2021-30515)
https://crbug.com/1200490 (CVE-2021-30513)
https://crbug.com/1200019 (CVE-2021-30512)
https://crbug.com/1197436 (CVE-2021-30510)
https://crbug.com/1195340 (CVE-2021-30508)
https://crbug.com/1180126
https://crbug.com/1203667
https://crbug.com/1201340
https://crbug.com/1201938

* chore: update patches

* lint: remove trailing whitespaces

* chore: update patches

Co-authored-by: Andrey Belenko <anbelen@microsoft.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-05-20 10:50:38 -07:00
Electron Bot
30f82dd1cb Bump v12.0.9 2021-05-19 13:52:49 -07:00
Robo
c285da9071 fix: adjust initial webContents focus calculation (#29204) (#29235)
* fix: adjust initial webContents focus calculation

* fix: active window check on mac

* fix: about:blank focus behavior

* chore: add spec

Co-authored-by: Raymond Zhao <raymondzhao@microsoft.com>

Co-authored-by: Raymond Zhao <raymondzhao@microsoft.com>
2021-05-19 07:53:49 -07:00
trop[bot]
4590e51c53 docs: option title for showSaveDialog is not supported for some platforms (#29231) 2021-05-19 16:05:56 +02:00
trop[bot]
301ad4982a docs: update style guide (#29229)
* clearer heading rules

* docs: clarify documentation style guide rules

* Update docs/styleguide.md

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

* fixes

Co-authored-by: Erick Zhao <erick@hotmail.ca>
Co-authored-by: Mark Lee <malept@users.noreply.github.com>
2021-05-19 16:19:37 +09:00
trop[bot]
b530792f6c fix: window bounds not scaled from screen coordinates (#29226)
Co-authored-by: samuelmaddock <samuel.maddock@gmail.com>
2021-05-19 16:18:40 +09:00
trop[bot]
eed685ca7a fix: AdjustAmountOfExternalAllocatedMemory regression in NativeImage destructor (#29222)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2021-05-19 11:55:03 +09:00
trop[bot]
419b675827 docs: Update the macos Dock Instructions (#29221)
* Update the macos Dock Instructions

* Remove preload and ;'s

* Mixed ;s

* Update dock doc

* Add informational text to index.html

Co-authored-by: Tony Ferrell <anf@microsoft.com>
2021-05-19 11:54:29 +09:00
trop[bot]
fe120bcd8d docs: Update macos-dark-mode fiddle and guide content (#29218)
* update macos dark mode docs for Electron v12

* pr review fixes

* more pr review fixes

* reorg paragraphs for better flow

* Update docs/tutorial/dark-mode.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

* pr fixes

Co-authored-by: Ethan Arrowood <ethan.arrowood@gmail.com>
Co-authored-by: Ethan Arrowood <ethan@arrowood.dev>
Co-authored-by: Erick Zhao <erick@hotmail.ca>
2021-05-19 11:53:44 +09:00
trop[bot]
8a0f89cfae docs: update drag and drop tutorial (#29217)
* Working

* Working

* Make the native-file drag and drop documents use context bridge

* Add per-file sections

* Use the updated link format

* Use path.join instead of string interpolation.

Co-authored-by: Antón Molleda <molant@users.noreply.github.com>

* Use fs.promises

Co-authored-by: Antón Molleda <molant@users.noreply.github.com>

* Update docs/tutorial/native-file-drag-drop.md

Co-authored-by: Antón Molleda <molant@users.noreply.github.com>

* fix formatting

Co-authored-by: Antón Molleda <molant@users.noreply.github.com>

* Update docs/tutorial/native-file-drag-drop.md

Co-authored-by: Antón Molleda <molant@users.noreply.github.com>

* Use more path.join instead of interpolation

* Update with PR suggestions

* Remove process.cwd() and add more example elements

* Minor text fix

* Fix typo

Co-authored-by: Erick Zhao <erick@hotmail.ca>

Co-authored-by: Tony Ferrell <anf@microsoft.com>
Co-authored-by: Tony Ferrell <tonyjf@gmail.com>
Co-authored-by: Antón Molleda <molant@users.noreply.github.com>
Co-authored-by: Erick Zhao <erick@hotmail.ca>
2021-05-19 11:53:20 +09:00
trop[bot]
8e40d97538 Update accelerator.md (#29214)
`Meta` is a valid alternative for `Super` and should be listed as an available modifier.

Co-authored-by: Thomas Kainrad <7394822+tkainrad@users.noreply.github.com>
2021-05-19 11:52:34 +09:00
Jeremy Rose
a26758c44d chore: cherry-pick 8089dbfc616f from chromium (#29130)
* chore: cherry-pick 8089dbfc616f from chromium

* resolve conflicts
2021-05-17 15:42:42 -04:00
trop[bot]
f8fbb15b47 build: make patch auto fixes come from PatchUp rather than Electron Bot (#29155)
Co-authored-by: Samuel Attard <sattard@slack-corp.com>
2021-05-17 14:45:34 -04:00
Electron Bot
343a879a97 Bump v12.0.8 2021-05-17 11:04:51 -07:00
trop[bot]
4877292934 docs: --force-fieldtrials was h2 rather than h3 (#29182)
All the other argument headers were h3 (`###`) but `--force-fieldtrials` was h2 (`##`) for some reason.
I changed it to make it consistent with the others.

Co-authored-by: Noelle Leigh <5957867+noelleleigh@users.noreply.github.com>
2021-05-16 18:15:46 -07:00
trop[bot]
8c23e08e67 fix: illegal access errors with nodeIntegrationInSubFrames (#29169)
* fix: illegal access errors with nodeIntegrationInSubFrames

* test: fixup on windows

* Address feedback from review

* Update shell/renderer/electron_render_frame_observer.cc

Co-authored-by: Robo <hop2deep@gmail.com>

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: Robo <hop2deep@gmail.com>
2021-05-14 18:30:03 -07:00
trop[bot]
4b439def13 fix: ensure extensions w/o a background page have file access (#29172)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-05-14 15:32:04 +02:00
trop[bot]
eb5ce11b41 docs: Improve description of findInPage options (#29145) 2021-05-13 23:38:55 +02:00
trop[bot]
f537755314 docs: revise Mac App Store Submission Guide (#29141) 2021-05-13 10:47:16 +02:00
trop[bot]
59ad90d135 Create README.md (#29148)
Co-authored-by: Ondreas <74183220+OndreasCZ@users.noreply.github.com>
2021-05-12 23:40:47 -07:00
Erick Zhao
7eceb43859 docs: rework sandbox guide (#29103)
Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
Co-authored-by: Biru Mohanathas <birunthan@mohanathas.com>
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>

Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
Co-authored-by: Biru Mohanathas <birunthan@mohanathas.com>
Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
2021-05-13 11:08:37 +09:00
trop[bot]
23bfc37825 fix: Menu.setApplicationMenu can return a useless array 29088 (#29128)
Co-authored-by: tabishmahfuz1 <tabish.mahfuz1@gmail.com>
2021-05-12 17:35:28 -07:00
Milan Burda
5643831c14 fix: webFrame spell checker APIs crashing in sandboxed renderers (#29053) (#29086) 2021-05-10 18:21:08 -04:00
Shatyuka
63344fed13 fix: increase corner radius for vibrancy view on big sur (#29071) 2021-05-10 13:21:40 -04:00
Electron Bot
8d55658bfa Bump v12.0.7 2021-05-07 02:22:40 -07:00
trop[bot]
47431a5d96 chore: cherry-pick 7abc7e45b2 from node (#29047)
Backports: https://github.com/nodejs/node/pull/38506

Co-authored-by: Fedor Indutny <fedor@indutny.com>
2021-05-07 00:20:32 -07:00
trop[bot]
6fd4bb27e3 fix: drag region BrowserView calculations on macOS (#29019)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-05-06 20:29:36 +09:00
trop[bot]
546cb983be fix: <webview> focus / blur events don't work with contextIsolation enabled (#29024)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2021-05-06 20:25:33 +09:00
trop[bot]
c5426713af docs: menu must be added on whenReady (#29042)
* Add that that menu must be added on whenReady

When an application menu is added before 'whenReady' all items seem to work except 'recent documents'

This causes the issue listed here: https://github.com/electron/electron/issues/17388

* Make example more complete

* Remove semicolons

* Update docs/tutorial/recent-documents.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

Co-authored-by: Matthijs Groen <matthijs.groen@gmail.com>
Co-authored-by: Erick Zhao <erick@hotmail.ca>
2021-05-06 20:23:35 +09:00
trop[bot]
5512f1d11b spec: attempt to fix flaky nativeTheme spec (#29034)
Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
2021-05-05 21:50:07 -07:00
Electron Bot
70e2fc58f9 Revert "Bump v12.0.7"
This reverts commit 37c30e1d91.
2021-05-05 20:01:58 -07:00
Electron Bot
37c30e1d91 Bump v12.0.7 2021-05-05 19:52:40 -07:00
Electron Bot
67e3206bd3 Revert "Bump v12.0.7"
This reverts commit 20ac113527.
2021-05-05 19:44:57 -07:00
Electron Bot
20ac113527 Bump v12.0.7 2021-05-05 19:33:33 -07:00
trop[bot]
405724cdd5 docs: link to BrowserView from webview page (#29009)
* docs: Link to `BrowserView` from `webview` page

* fix relative link

Co-authored-by: Hamish Macpherson <hamstu@gmail.com>
2021-05-05 10:57:34 -05:00
trop[bot]
9b98f906e0 refactor: use "as const" for constant mappings (#28999)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2021-05-05 15:59:52 +09:00
trop[bot]
2f93d874ef fix: close attached sheet on window close (#28989)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2021-05-04 09:58:45 -04:00
trop[bot]
9ae1cbebe0 docs: update REPL guide (#28985) 2021-05-04 11:51:16 +02:00
trop[bot]
a4c590e288 fix: allow Node.js to manage microtasks queue (#28972)
* fix: allow Node.js to manage microtasks queue

When `uv_run()` resulted in invocation of JS functions the microtask
queue checkpoint in Node's CallbackScope was a no-op because the
expected microtask queue policy was `kExplicit` and Electron ran under
`kScoped` policy. This change switches policy to `kExplicit` right
before `uv_run()` and reverts it back to original value after `uv_run()`
completes to provide better compatibility with Node.

* add comment

Co-authored-by: Fedor Indutny <fedor@indutny.com>
2021-05-03 23:01:13 -07:00
trop[bot]
1b9220525f docs: remove reference to global Electron install (#28968)
* docs: remove reference to global Electron install

This is a pattern that we actively want to discourage.

* docs: update as per review suggestion

Co-authored-by: Erick Zhao <erick@hotmail.ca>
2021-05-03 11:39:24 -04:00
207 changed files with 6270 additions and 1625 deletions

View File

@@ -57,6 +57,16 @@ parameters:
type: boolean
default: false
# Executors
executors:
linux-arm:
resource_class: electronjs/linux-arm
machine: true
linux-arm64:
resource_class: electronjs/linux-arm64
machine: true
# The config expects the following environment variables to be set:
# - "SLACK_WEBHOOK" Slack hook URL to send notifications.
#
@@ -225,6 +235,25 @@ step-maybe-notify-slack-success: &step-maybe-notify-slack-success
fi
when: on_success
step-maybe-cleanup-arm: &step-maybe-cleanup-arm
run:
name: Cleanup after testing
command: |
if [ "$TARGET_ARCH" == "arm64" ] &&[ "`uname`" == "Darwin" ]; then
killall Electron || echo "No Electron processes left running"
killall Safari || echo "No Safari processes left running"
rm -rf ~/Library/Application\ Support/Electron*
rm -rf ~/Library/Application\ Support/electron*
elif [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then
XVFB=/usr/bin/Xvfb
/sbin/start-stop-daemon --stop --exec $XVFB || echo "Xvfb not running"
pkill electron || echo "electron not running"
rm -rf ~/.config/Electron*
rm -rf ~/.config/electron*
fi
when: always
step-checkout-electron: &step-checkout-electron
checkout:
path: src/electron
@@ -261,7 +290,7 @@ step-gclient-sync: &step-gclient-sync
if ! git diff-index --quiet HEAD --; then
# There are changes to the patches. Make a git commit with the updated patches
git add patches
GIT_COMMITTER_NAME="Electron Bot" GIT_COMMITTER_EMAIL="electron@github.com" git commit -m "update patches" --author="Electron Bot <electron@github.com>"
GIT_COMMITTER_NAME="PatchUp" GIT_COMMITTER_EMAIL="73610968+patchup[bot]@users.noreply.github.com" git commit -m "chore: update patches" --author="PatchUp <73610968+patchup[bot]@users.noreply.github.com>"
# Export it
mkdir -p ../../patches
git format-patch -1 --stdout --keep-subject --no-stat --full-index > ../../patches/update-patches.patch
@@ -513,6 +542,7 @@ step-electron-build: &step-electron-build
ninja -C out/Default electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES
ninja -C out/Default tools/v8_context_snapshot -j $NUMBER_OF_NINJA_PROCESSES
gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args
(cd out/Default; zip mksnapshot.zip mksnapshot_args clang_x64_v8_arm64/gen/v8/embedded.S)
rm -rf out/Default/clang_x64_v8_arm64/obj
# Regenerate because we just deleted some ninja files
@@ -667,6 +697,7 @@ step-persist-data-for-tests: &step-persist-data-for-tests
- src/electron
- src/third_party/electron_node
- src/third_party/nan
- src/cross-arch-snapshots
step-electron-dist-unzip: &step-electron-dist-unzip
run:
@@ -729,7 +760,11 @@ step-verify-mksnapshot: &step-verify-mksnapshot
name: Verify mksnapshot
command: |
cd src
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default
if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --snapshot-files-dir $PWD/cross-arch-snapshots
else
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default
fi
step-verify-chromedriver: &step-verify-chromedriver
run:
@@ -856,23 +891,6 @@ step-maybe-cross-arch-snapshot-store: &step-maybe-cross-arch-snapshot-store
path: src/cross-arch-snapshots
destination: cross-arch-snapshots
step-maybe-trigger-arm-test: &step-maybe-trigger-arm-test
run:
name: Trigger an arm test on VSTS if applicable
command: |
cd src
# Only run for non-fork prs
if [ "$TRIGGER_ARM_TEST" == "true" ] && [ -z "$CIRCLE_PR_NUMBER" ]; then
#Trigger VSTS job, passing along CircleCI job number and branch to build
if [ "`uname`" == "Darwin" ]; then
echo "Triggering electron-arm2-testing build on Azure DevOps"
node electron/script/release/ci-release-build.js --job=electron-arm2-testing --ci=DevOps --armTest --circleBuildNum=$CIRCLE_BUILD_NUM $CIRCLE_BRANCH
else
echo "Triggering electron-$TARGET_ARCH-testing build on VSTS"
node electron/script/release/ci-release-build.js --job=electron-$TARGET_ARCH-testing --ci=VSTS --armTest --circleBuildNum=$CIRCLE_BUILD_NUM $CIRCLE_BRANCH
fi
fi
step-maybe-generate-typescript-defs: &step-maybe-generate-typescript-defs
run:
name: Generate type declarations
@@ -1287,8 +1305,14 @@ steps-tests: &steps-tests
ELECTRON_DISABLE_SECURITY_WARNINGS: 1
command: |
cd src
(cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging --files $(circleci tests glob spec-main/*-spec.ts | circleci tests split))
(cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging --files $(circleci tests glob spec/*-spec.js | circleci tests split))
if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then
export ELECTRON_SKIP_NATIVE_MODULE_TESTS=true
(cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging)
(cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging)
else
(cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging --files $(circleci tests glob spec-main/*-spec.ts | circleci tests split))
(cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging --files $(circleci tests glob spec/*-spec.js | circleci tests split))
fi
- run:
name: Check test results existence
command: |
@@ -1309,6 +1333,8 @@ steps-tests: &steps-tests
- *step-maybe-notify-slack-failure
- *step-maybe-cleanup-arm
steps-test-nan: &steps-test-nan
steps:
- attach_workspace:
@@ -1581,9 +1607,6 @@ commands:
steps:
- *step-save-out-cache
# Trigger tests on arm hardware if needed
- *step-maybe-trigger-arm-test
- *step-maybe-notify-slack-failure
electron-publish:
@@ -1911,7 +1934,7 @@ jobs:
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
steps:
- electron-build:
persist: false
persist: true
checkout: true
use-out-cache: false
@@ -1969,7 +1992,7 @@ jobs:
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
steps:
- electron-build:
persist: false
persist: true
checkout: true
use-out-cache: false
@@ -2357,6 +2380,24 @@ jobs:
<<: *env-send-slack-notifications
<<: *steps-verify-ffmpeg
linux-arm-testing-tests:
executor: linux-arm
environment:
<<: *env-arm
<<: *env-global
<<: *env-headless-testing
<<: *env-stack-dumping
<<: *steps-tests
linux-arm64-testing-tests:
executor: linux-arm64
environment:
<<: *env-arm64
<<: *env-global
<<: *env-headless-testing
<<: *env-stack-dumping
<<: *steps-tests
osx-testing-x64-tests:
<<: *machine-mac-large
environment:
@@ -2589,8 +2630,23 @@ workflows:
- linux-ia32-testing
- linux-arm-testing
- linux-arm-testing-tests:
filters:
branches:
# Do not run this on forked pull requests
ignore: /pull\/[0-9]+/
requires:
- linux-arm-testing
- linux-arm64-testing
- linux-arm64-testing-tests:
filters:
branches:
# Do not run this on forked pull requests
ignore: /pull\/[0-9]+/
requires:
- linux-arm64-testing
- linux-arm64-testing-gn-check:
requires:
- linux-checkout-fast

View File

@@ -1 +1 @@
12.0.6
12.0.13

View File

@@ -6,7 +6,7 @@
[![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron?type=dev)
[![Electron Discord Invite](https://img.shields.io/discord/745037351163527189?color=%237289DA&label=chat&logo=discord&logoColor=white)](https://discord.com/invite/electron)
:memo: Available Translations: 🇨🇳 🇹🇼 🇧🇷 🇪🇸 🇰🇷 🇯🇵 🇷🇺 🇫🇷 🇹🇭 🇳🇱 🇹🇷 🇮🇩 🇺🇦 🇨🇿 🇮🇹 🇵🇱.
:memo: Available Translations: 🇨🇳 🇧🇷 🇪🇸 🇯🇵 🇷🇺 🇫🇷 🇺🇸 🇩🇪.
View these docs in other languages at [electron/i18n](https://github.com/electron/i18n/tree/master/content/).
The Electron framework lets you write cross-platform desktop applications

View File

@@ -18,20 +18,14 @@ an issue:
## Guides and Tutorials
### Quickstart
### Getting started
* [Quick Start Guide](tutorial/quick-start.md)
* [Prerequisites](tutorial/quick-start.md#prerequisites)
* [Create a basic application](tutorial/quick-start.md#create-a-basic-application)
* [Run your application](tutorial/quick-start.md#run-your-application)
* [Package and distribute the application](tutorial/quick-start.md#package-and-distribute-the-application)
* [Introduction](tutorial/introduction.md)
* [Quick Start](tutorial/quick-start.md)
* [Process Model](tutorial/process-model.md)
### Learning the basics
* [Electron's Process Model](tutorial/quick-start.md#application-architecture)
* [Main and Renderer Processes](tutorial/quick-start.md#main-and-renderer-processes)
* [Electron API](tutorial/quick-start.md#electron-api)
* [Node.js API](tutorial/quick-start.md#nodejs-api)
* Adding Features to Your App
* [Notifications](tutorial/notifications.md)
* [Recent Documents](tutorial/recent-documents.md)
@@ -59,6 +53,7 @@ an issue:
* [Using Native Node.js Modules](tutorial/using-native-node-modules.md)
* [Performance Strategies](tutorial/performance.md)
* [Security Strategies](tutorial/security.md)
* [Process Sandboxing](tutorial/sandbox.md)
* [Accessibility](tutorial/accessibility.md)
* [Manually Enabling Accessibility Features](tutorial/accessibility.md#manually-enabling-accessibility-features)
* [Testing and Debugging](tutorial/application-debugging.md)
@@ -68,6 +63,7 @@ an issue:
* [Testing on Headless CI Systems (Travis, Jenkins)](tutorial/testing-on-headless-ci.md)
* [DevTools Extension](tutorial/devtools-extension.md)
* [Automated Testing with a Custom Driver](tutorial/automated-testing-with-a-custom-driver.md)
* [REPL](tutorial/repl.md)
* [Distribution](tutorial/application-distribution.md)
* [Supported Platforms](tutorial/support.md#supported-platforms)
* [Code Signing](tutorial/code-signing.md)

View File

@@ -35,7 +35,7 @@ Linux and Windows to define some accelerators.
Use `Alt` instead of `Option`. The `Option` key only exists on macOS, whereas
the `Alt` key is available on all platforms.
The `Super` key is mapped to the `Windows` key on Windows and Linux and
The `Super` (or `Meta`) key is mapped to the `Windows` key on Windows and Linux and
`Cmd` on macOS.
## Available modifiers
@@ -48,6 +48,7 @@ The `Super` key is mapped to the `Windows` key on Windows and Linux and
* `AltGr`
* `Shift`
* `Super`
* `Meta`
## Available key codes

View File

@@ -270,7 +270,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
associated with the window, making it compatible with the Chromium
OS-level sandbox and disabling the Node.js engine. This is not the same as
the `nodeIntegration` option and the APIs available to the preload script
are more limited. Read more about the option [here](sandbox-option.md).
are more limited. Read more about the option [here](../tutorial/sandbox.md).
* `enableRemoteModule` Boolean (optional) - Whether to enable the [`remote`](remote.md) module.
Default is `false`.
* `session` [Session](session.md#class-session) (optional) - Sets the session used by the

View File

@@ -71,7 +71,7 @@ const request = net.request({
Returns:
* `response` IncomingMessage - An object representing the HTTP response message.
* `response` [IncomingMessage](incoming-message.md) - An object representing the HTTP response message.
#### Event: 'login'

View File

@@ -80,7 +80,7 @@ This switch can not be used in `app.commandLine.appendSwitch` since it is parsed
earlier than user's app is loaded, but you can set the `ELECTRON_ENABLE_LOGGING`
environment variable to achieve the same effect.
## --force-fieldtrials=`trials`
### --force-fieldtrials=`trials`
Field trials to be forcefully enabled or disabled.
@@ -142,7 +142,8 @@ proxy server flags that are passed.
### --no-sandbox
Disables Chromium sandbox, which is now enabled by default.
Disables the Chromium [sandbox](https://www.chromium.org/developers/design-documents/sandbox).
Forces renderer process and Chromium helper processes to run un-sandboxed.
Should only be used for testing.
### --proxy-bypass-list=`hosts`

View File

@@ -154,7 +154,7 @@ dialog.showOpenDialog(mainWindow, {
* `browserWindow` [BrowserWindow](browser-window.md) (optional)
* `options` Object
* `title` String (optional)
* `title` String (optional) - The dialog title. Cannot be displayed on some _Linux_ desktop environments.
* `defaultPath` String (optional) - Absolute directory path, absolute file
path, or file name to use by default.
* `buttonLabel` String (optional) - Custom label for the confirmation button, when
@@ -185,7 +185,7 @@ The `filters` specifies an array of file types that can be displayed, see
* `browserWindow` [BrowserWindow](browser-window.md) (optional)
* `options` Object
* `title` String (optional)
* `title` String (optional) - The dialog title. Cannot be displayed on some _Linux_ desktop environments.
* `defaultPath` String (optional) - Absolute directory path, absolute file
path, or file name to use by default.
* `buttonLabel` String (optional) - Custom label for the confirmation button, when

View File

@@ -1,182 +0,0 @@
# `sandbox` Option
> Create a browser window with a sandboxed renderer. With this
option enabled, the renderer must communicate via IPC to the main process in order to access node APIs.
One of the key security features of Chromium is that all blink rendering/JavaScript
code is executed within a sandbox. This sandbox uses OS-specific features to ensure
that exploits in the renderer process cannot harm the system.
In other words, when the sandbox is enabled, the renderers can only make changes
to the system by delegating tasks to the main process via IPC.
[Here's](https://www.chromium.org/developers/design-documents/sandbox) more
information about the sandbox.
Since a major feature in Electron is the ability to run Node.js in the
renderer process (making it easier to develop desktop applications using web
technologies), the sandbox is disabled by electron. This is because
most Node.js APIs require system access. `require()` for example, is not
possible without file system permissions, which are not available in a sandboxed
environment.
Usually this is not a problem for desktop applications since the code is always
trusted, but it makes Electron less secure than Chromium for displaying
untrusted web content. For applications that require more security, the
`sandbox` flag will force Electron to spawn a classic Chromium renderer that is
compatible with the sandbox.
A sandboxed renderer doesn't have a Node.js environment running and doesn't
expose Node.js JavaScript APIs to client code. The only exception is the preload script,
which has access to a subset of the Electron renderer API.
Another difference is that sandboxed renderers don't modify any of the default
JavaScript APIs. Consequently, some APIs such as `window.open` will work as they
do in Chromium (i.e. they do not return a [`BrowserWindowProxy`](browser-window-proxy.md)).
## Example
To create a sandboxed window, pass `sandbox: true` to `webPreferences`:
```js
let win
app.whenReady().then(() => {
win = new BrowserWindow({
webPreferences: {
sandbox: true
}
})
win.loadURL('http://google.com')
})
```
In the above code the [`BrowserWindow`](browser-window.md) that was created has Node.js disabled and can communicate
only via IPC. The use of this option stops Electron from creating a Node.js runtime in the renderer. Also,
within this new window `window.open` follows the native behavior (by default Electron creates a [`BrowserWindow`](browser-window.md)
and returns a proxy to this via `window.open`).
[`app.enableSandbox`](app.md#appenablesandbox) can be used to force `sandbox: true` for all `BrowserWindow` instances.
```js
let win
app.enableSandbox()
app.whenReady().then(() => {
// no need to pass `sandbox: true` since `app.enableSandbox()` was called.
win = new BrowserWindow()
win.loadURL('http://google.com')
})
```
## Preload
An app can make customizations to sandboxed renderers using a preload script.
Here's an example:
```js
let win
app.whenReady().then(() => {
win = new BrowserWindow({
webPreferences: {
sandbox: true,
preload: path.join(app.getAppPath(), 'preload.js')
}
})
win.loadURL('http://google.com')
})
```
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. Without
// contextIsolation enabled, it's possible to accidentally leak privileged
// globals like ipcRenderer to web content.
const { ipcRenderer } = require('electron')
const defaultWindowOpen = window.open
window.open = function customWindowOpen (url, ...args) {
ipcRenderer.send('report-window-open', location.origin, url, args)
return defaultWindowOpen(url + '?from_electron=1', ...args)
}
```
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 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.
To create a browserify bundle and use it as a preload script, something like
the following should be used:
```sh
browserify preload/index.js \
-x electron \
--insert-global-vars=__filename,__dirname -o preload.js
```
The `-x` flag should be used with any required module that is already exposed in
the preload scope, and tells browserify to use the enclosing `require` function
for it. `--insert-global-vars` will ensure that `process`, `Buffer` and
`setImmediate` are also taken from the enclosing scope(normally browserify
injects code for those).
Currently the `require` function provided in the preload scope exposes the
following modules:
- `electron`
- `crashReporter`
- `desktopCapturer`
- `ipcRenderer`
- `nativeImage`
- `webFrame`
- `events`
- `timers`
- `url`
More may be added as needed to expose more Electron APIs in the sandbox.
## Rendering untrusted content
Rendering untrusted content in Electron is still somewhat uncharted territory,
though some apps are finding success (e.g. Beaker Browser). Our goal is to get
as close to Chrome as we can in terms of the security of sandboxed content, but
ultimately we will always be behind due to a few fundamental issues:
1. We do not have the dedicated resources or expertise that Chromium has to
apply to the security of its product. We do our best to make use of what we
have, to inherit everything we can from Chromium, and to respond quickly to
security issues, but Electron cannot be as secure as Chromium without the
resources that Chromium is able to dedicate.
2. Some security features in Chrome (such as Safe Browsing and Certificate
Transparency) require a centralized authority and dedicated servers, both of
which run counter to the goals of the Electron project. As such, we disable
those features in Electron, at the cost of the associated security they
would otherwise bring.
3. There is only one Chromium, whereas there are many thousands of apps built
on Electron, all of which behave slightly differently. Accounting for those
differences can yield a huge possibility space, and make it challenging to
ensure the security of the platform in unusual use cases.
4. We can't push security updates to users directly, so we rely on app vendors
to upgrade the version of Electron underlying their app in order for
security updates to reach users.
Here are some things to consider before rendering untrusted content:
- A preload script can accidentally leak privileged APIs to untrusted code,
unless [`contextIsolation`](../tutorial/security.md#3-enable-context-isolation-for-remote-content)
is also enabled.
- Some bug in the V8 engine may allow malicious code to access the renderer
preload APIs, effectively granting full access to the system through the
`remote` module. Therefore, it is highly recommended to [disable the `remote`
module](../tutorial/security.md#15-disable-the-remote-module).
If disabling is not feasible, you should selectively [filter the `remote`
module](../tutorial/security.md#16-filter-the-remote-module).
- While we make our best effort to backport Chromium security fixes to older
versions of Electron, we do not make a guarantee that every fix will be
backported. Your best chance at staying secure is to be on the latest stable
version of Electron.

View File

@@ -11,9 +11,9 @@
* `colorDepth` Number - The number of bits per pixel.
* `depthPerComponent` Number - The number of bits per color component.
* `displayFrequency` Number - The display refresh rate.
* `bounds` [Rectangle](rectangle.md)
* `bounds` [Rectangle](rectangle.md) - the bounds of the display in DIP points.
* `size` [Size](size.md)
* `workArea` [Rectangle](rectangle.md)
* `workArea` [Rectangle](rectangle.md) - the work area of the display in DIP points.
* `workAreaSize` [Size](size.md)
* `internal` Boolean - `true` for an internal display and `false` for an external display

View File

@@ -13,7 +13,7 @@ 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
the concept of [main process vs. renderer process](../tutorial/quick-start.md#main-and-renderer-processes)
the concept of main process vs. renderer process
scripts to be able to use those modules.
The main process script is like a normal Node.js script:
@@ -43,8 +43,6 @@ extra ability to use node modules if `nodeIntegration` is enabled:
</html>
```
To run your app, read [Run your app](../tutorial/quick-start.md#run-your-application).
## Destructuring assignment
As of 0.37, you can use

View File

@@ -1306,8 +1306,7 @@ Inserts `text` to the focused element.
* `text` String - Content to be searched, must not be empty.
* `options` Object (optional)
* `forward` Boolean (optional) - Whether to search forward or backward, defaults to `true`.
* `findNext` Boolean (optional) - Whether the operation is first request or a follow up,
defaults to `false`.
* `findNext` Boolean (optional) - Whether to begin a new text finding session with this request. Should be `true` for initial requests, and `false` for follow-up requests. Defaults to `false`.
* `matchCase` Boolean (optional) - Whether search should be case-sensitive,
defaults to `false`.

View File

@@ -5,7 +5,7 @@
Electron's `webview` tag is based on [Chromium's `webview`][chrome-webview], which
is undergoing dramatic architectural changes. This impacts the stability of `webviews`,
including rendering, navigation, and event routing. We currently recommend to not
use the `webview` tag and to consider alternatives, like `iframe`, Electron's `BrowserView`,
use the `webview` tag and to consider alternatives, like `iframe`, [Electron's `BrowserView`](browser-view.md),
or an architecture that avoids embedded content altogether.
## Enabling
@@ -515,8 +515,7 @@ Inserts `text` to the focused element.
* `text` String - Content to be searched, must not be empty.
* `options` Object (optional)
* `forward` Boolean (optional) - Whether to search forward or backward, defaults to `true`.
* `findNext` Boolean (optional) - Whether the operation is first request or a follow up,
defaults to `false`.
* `findNext` Boolean (optional) - Whether to begin a new text finding session with this request. Should be `true` for initial requests, and `false` for follow-up requests. Defaults to `false`.
* `matchCase` Boolean (optional) - Whether search should be case-sensitive,
defaults to `false`.

View File

@@ -117,15 +117,18 @@ const mainWindow = new BrowserWindow({
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
if (url === 'about:blank') {
return {
frame: false,
fullscreenable: false,
backgroundColor: 'black',
webPreferences: {
preload: 'my-child-window-preload-script.js'
action: 'allow',
overrideBrowserWindowOptions: {
frame: false,
fullscreenable: false,
backgroundColor: 'black',
webPreferences: {
preload: 'my-child-window-preload-script.js'
}
}
}
}
return false
return { action: 'deny' }
})
```

View File

@@ -10,12 +10,12 @@ files, you need to have built Electron so that it knows which compiler flags
were used. There is one required option for the script `--output-dir`, which
tells the script which build directory to pull the compilation information
from. A typical usage would be:
`npm run lint:clang-tiy --out-dir ../out/Testing`
`npm run lint:clang-tidy --out-dir ../out/Testing`
With no filenames provided, all C/C++/Objective-C files will be checked.
You can provide a list of files to be checked by passing the filenames after
the options:
`npm run lint:clang-tiy --out-dir ../out/Testing shell/browser/api/electron_api_app.cc`
`npm run lint:clang-tidy --out-dir ../out/Testing shell/browser/api/electron_api_app.cc`
While `clang-tidy` has a
[long list](https://clang.llvm.org/extra/clang-tidy/checks/list.html)

View File

@@ -25,7 +25,7 @@ You can run `npm run lint` to show any style issues detected by `cpplint` and
## C++ and Python
For C++ and Python, we follow Chromium's [Coding
Style](https://www.chromium.org/developers/coding-style). You can use
Style](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/styleguide/styleguide.md). You can use
[clang-format](clang-format.md) to format the C++ code automatically. There is
also a script `script/cpplint.py` to check whether all files conform.

View File

@@ -7,12 +7,9 @@
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</p>
<a href="#" id="drag">Drag me</a>
<p>Drag the boxes below to somewhere in your OS (Finder/Explorer, Desktop, etc.) to copy an example markdown file.</p>
<div style="border:2px solid black;border-radius:3px;padding:5px;display:inline-block" draggable="true" id="drag1">Drag me - File 1</div>
<div style="border:2px solid black;border-radius:3px;padding:5px;display:inline-block" draggable="true" id="drag2">Drag me - File 2</div>
<script src="renderer.js"></script>
</body>
</html>

View File

@@ -1,21 +1,28 @@
const { app, BrowserWindow, ipcMain, nativeImage, NativeImage } = require('electron')
const fs = require('fs');
const http = require('http');
const path = require('path')
const fs = require('fs')
const https = require('https')
function createWindow () {
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
preload: path.join(__dirname, 'preload.js')
}
})
win.loadFile('index.html')
}
const iconName = 'iconForDragAndDrop.png';
const icon = fs.createWriteStream(`${process.cwd()}/${iconName}`);
http.get('http://img.icons8.com/ios/452/drag-and-drop.png', (response) => {
const iconName = path.join(__dirname, 'iconForDragAndDrop.png');
const icon = fs.createWriteStream(iconName);
// Create a new file to copy - you can also copy existing files.
fs.writeFileSync(path.join(__dirname, 'drag-and-drop-1.md'), '# First file to test drag and drop')
fs.writeFileSync(path.join(__dirname, 'drag-and-drop-2.md'), '# Second file to test drag and drop')
https.get('https://img.icons8.com/ios/452/drag-and-drop.png', (response) => {
response.pipe(icon);
});
@@ -23,8 +30,8 @@ app.whenReady().then(createWindow)
ipcMain.on('ondragstart', (event, filePath) => {
event.sender.startDrag({
file: filePath,
icon: `${process.cwd()}/${iconName}`
file: path.join(__dirname, filePath),
icon: iconName,
})
})

View File

@@ -0,0 +1,8 @@
const { contextBridge, ipcRenderer } = require('electron')
const path = require('path')
contextBridge.exposeInMainWorld('electron', {
startDrag: (fileName) => {
ipcRenderer.send('ondragstart', fileName)
}
})

View File

@@ -1,9 +1,9 @@
const { ipcRenderer } = require('electron')
const fs = require('fs')
document.getElementById('drag').ondragstart = (event) => {
const fileName = 'drag-and-drop.md'
fs.writeFileSync(fileName, '# Test drag and drop');
document.getElementById('drag1').ondragstart = (event) => {
event.preventDefault()
ipcRenderer.send('ondragstart', process.cwd() + `/${fileName}`)
window.electron.startDrag('drag-and-drop-1.md')
}
document.getElementById('drag2').ondragstart = (event) => {
event.preventDefault()
window.electron.startDrag('drag-and-drop-2.md')
}

View File

@@ -7,10 +7,6 @@
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</p>
<p>Hit Alt+Ctrl+I on Windows or Opt+Cmd+I on Mac to see a message printed to the console.</p>
</body>
</html>

View File

@@ -4,9 +4,6 @@ function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
win.loadFile('index.html')

View File

@@ -7,8 +7,6 @@
</head>
<body>
<h1>Hello World!</h1>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
<p>Hit Ctrl+I to see a message printed to the console.</p>
</body>
</html>

View File

@@ -1,7 +1,7 @@
const { app, BrowserWindow } = require('electron')
app.whenReady().then(() => {
const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true } })
const win = new BrowserWindow({ width: 800, height: 600 })
win.loadFile('index.html')
win.webContents.on('before-input-event', (event, input) => {

View File

@@ -7,10 +7,6 @@
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</p>
<p>Hit Alt+Shift+I on Windows, or Opt+Cmd+I on mac to see a message printed to the console.</p>
</body>
</html>

View File

@@ -4,9 +4,6 @@ function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
win.loadFile('index.html')

View File

@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
<p>Hit any key with this window focused to see it captured here.</p>
<div><span>Last Key Pressed: </span><span id="last-keypress"></span></div>
<script src="./renderer.js"></script>
</body>
</html>

View File

@@ -0,0 +1,35 @@
// Modules to control application life and create native browser window
const {app, BrowserWindow} = require('electron')
const path = require('path')
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
})
// 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()
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})

View File

@@ -0,0 +1,7 @@
function handleKeyPress (event) {
// You can put code here to handle the keypress.
document.getElementById("last-keypress").innerText = event.key
console.log(`You pressed ${event.key}`)
}
window.addEventListener('keyup', handleKeyPress, true)

View File

@@ -1,11 +1,12 @@
const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron')
const path = require('path')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
preload: path.join(__dirname, 'preload.js')
}
})
@@ -21,20 +22,22 @@ function createWindow () {
})
ipcMain.handle('dark-mode:system', () => {
nativeTheme.themeSouce = 'system'
nativeTheme.themeSource = 'system'
})
}
app.whenReady().then(createWindow)
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})

View File

@@ -0,0 +1,6 @@
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('darkMode', {
toggle: () => ipcRenderer.invoke('dark-mode:toggle'),
system: () => ipcRenderer.invoke('dark-mode:system')
})

View File

@@ -1,11 +1,9 @@
const { ipcRenderer } = require('electron')
document.getElementById('toggle-dark-mode').addEventListener('click', async () => {
const isDarkMode = await ipcRenderer.invoke('dark-mode:toggle')
const isDarkMode = await window.darkMode.toggle()
document.getElementById('theme-source').innerHTML = isDarkMode ? 'Dark' : 'Light'
})
document.getElementById('reset-to-system').addEventListener('click', async () => {
await ipcRenderer.invoke('dark-mode:system')
await window.darkMode.system()
document.getElementById('theme-source').innerHTML = 'System'
})

View File

@@ -7,10 +7,6 @@
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</p>
<p>Right click the dock icon to see the custom menu options.</p>
</body>
</html>

View File

@@ -4,9 +4,6 @@ function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
win.loadFile('index.html')
@@ -27,7 +24,9 @@ const dockMenu = Menu.buildFromTemplate([
])
app.whenReady().then(() => {
app.dock.setMenu(dockMenu)
if (process.platform === 'darwin') {
app.dock.setMenu(dockMenu)
}
}).then(createWindow)
app.on('window-all-closed', () => {

View File

@@ -7,10 +7,6 @@
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</p>
<p>After launching this application, you should see the system notification.</p>
</body>
</html>

View File

@@ -3,21 +3,17 @@ const { app, BrowserWindow, Notification } = require('electron')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
height: 600
})
win.loadFile('index.html')
}
const NOTIFICATION_TITLE = 'Basic Notification'
const NOTIFICATION_BODY = 'Notification from the Main process'
function showNotification () {
const notification = {
title: 'Basic Notification',
body: 'Notification from the Main process'
}
new Notification(notification).show()
new Notification({ title: NOTIFICATION_TITLE, body: NOTIFICATION_BODY }).show()
}
app.whenReady().then(createWindow).then(showNotification)

View File

@@ -7,11 +7,9 @@
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</p>
<p>After launching this application, you should see the system notification.</p>
<p id="output">Click it to see the effect in this interface.</p>
<script src="renderer.js"></script>
</body>
</html>

View File

@@ -3,10 +3,7 @@ const { app, BrowserWindow } = require('electron')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
height: 600
})
win.loadFile('index.html')

View File

@@ -1,7 +1,6 @@
const myNotification = new Notification('Title', {
body: 'Notification from the Renderer process'
})
const NOTIFICATION_TITLE = 'Title'
const NOTIFICATION_BODY = 'Notification from the Renderer process. Click to log to console.'
const CLICK_MESSAGE = 'Notification clicked!'
myNotification.onclick = () => {
console.log('Notification clicked')
}
new Notification(NOTIFICATION_TITLE, { body: NOTIFICATION_BODY })
.onclick = () => document.getElementById("output").innerText = CLICK_MESSAGE

View File

@@ -1,15 +0,0 @@
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</p>
</body>
</html>

View File

@@ -1,5 +1,6 @@
const { app, BrowserWindow } = require('electron')
const fs = require('fs')
const path = require('path')
app.disableHardwareAcceleration()
@@ -12,7 +13,7 @@ app.whenReady().then(() => {
fs.writeFileSync('ex.png', image.toPNG())
})
win.webContents.setFrameRate(60)
console.log(`The screenshot has been successfully saved to ${process.cwd()}/ex.png`)
console.log(`The screenshot has been successfully saved to ${path.join(process.cwd(), 'ex.png')}`)
})
app.on('window-all-closed', () => {

View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
<h1>Connection status: <strong id='status'></strong></h1>
<script src="renderer.js"></script>
</body>
</html>

View File

@@ -0,0 +1,26 @@
const { app, BrowserWindow } = require('electron')
function createWindow () {
const onlineStatusWindow = new BrowserWindow({
width: 300,
height: 200
})
onlineStatusWindow.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})

View File

@@ -1,17 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</p>
<script src="renderer.js"></script>
</body>
</html>

View File

@@ -1,24 +0,0 @@
const { app, BrowserWindow, ipcMain } = require('electron')
let onlineStatusWindow
app.whenReady().then(() => {
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false, webPreferences: { nodeIntegration: true } })
onlineStatusWindow.loadURL(`file://${__dirname}/index.html`)
})
ipcMain.on('online-status-changed', (event, status) => {
console.log(status)
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})

View File

@@ -1,7 +0,0 @@
const { ipcRenderer } = require('electron')
const updateOnlineStatus = () => { ipcRenderer.send('online-status-changed', navigator.onLine ? 'online' : 'offline') }
window.addEventListener('online', updateOnlineStatus)
window.addEventListener('offline', updateOnlineStatus)
updateOnlineStatus()

View File

@@ -0,0 +1,8 @@
function onlineStatusIndicator () {
document.getElementById('status').innerHTML = navigator.onLine ? 'online' : 'offline'
}
window.addEventListener('online', onlineStatusIndicator)
window.addEventListener('offline', onlineStatusIndicator)
onlineStatusIndicator()

View File

@@ -1,17 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</p>
<script src="renderer.js"></script>
</body>
</html>

View File

@@ -1,20 +0,0 @@
const { app, BrowserWindow } = require('electron')
let onlineStatusWindow
app.whenReady().then(() => {
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false })
onlineStatusWindow.loadURL(`file://${__dirname}/index.html`)
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})

View File

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

View File

@@ -7,10 +7,9 @@
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</p>
<p>Keep an eye on the dock (Mac) or taskbar (Windows, Unity) for this application!</p>
<p>It should indicate a progress that advances from 0 to 100%.</p>
<p>It should then show indeterminate (Windows) or pin at 100% (other operating systems)
briefly and then loop.</p>
</body>
</html>

View File

@@ -1,21 +1,39 @@
const { app, BrowserWindow } = require('electron')
let progressInterval
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
height: 600
})
win.loadFile('index.html')
win.setProgressBar(0.5)
}
const INCREMENT = 0.03
const INTERVAL_DELAY = 100 // ms
let c = 0
progressInterval = setInterval(() => {
// update progress bar to next value
// values between 0 and 1 will show progress, >1 will show indeterminate or stick at 100%
win.setProgressBar(c)
// increment or reset progress bar
if (c < 2) {
c += INCREMENT
} else {
c = (-INCREMENT * 5) // reset to a bit less than 0 to show reset state
}
}, INTERVAL_DELAY)
}
app.whenReady().then(createWindow)
// before the app is terminated, clear both timers
app.on('before-quit', () => {
clearInterval(progressInterval)
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {

View File

@@ -2,15 +2,14 @@
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<title>Recent Documents</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
<h1>Hello World!</h1>
<h1>Recent Documents</h1>
<p>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
Right click on the app icon to see recent documents.
You should see `recently-used.md` added to the list of recent files
</p>
</body>
</html>

View File

@@ -5,17 +5,15 @@ const path = require('path')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
height: 600
})
win.loadFile('index.html')
}
const fileName = 'recently-used.md'
fs.writeFile(fileName, 'Lorem Ipsum', () => {
app.addRecentDocument(path.join(process.cwd(), `${fileName}`))
app.addRecentDocument(path.join(__dirname, fileName))
})
app.whenReady().then(createWindow)

View File

@@ -4,13 +4,14 @@
<meta charset="UTF-8">
<title>Hello World!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
<link rel="stylesheet" type="text/css" href="./styles.css">
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
Click on the title with the <pre>Command</pre> or <pre>Control</pre> key pressed.
You should see a popup with the represented file at the top.
</p>
</body>
</body>
</html>

View File

@@ -4,10 +4,7 @@ const os = require('os');
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
height: 600
})
win.loadFile('index.html')

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 32 KiB

0
docs/images/versioning-sketch-2.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -2,15 +2,14 @@
These are the guidelines for writing Electron documentation.
## Titles
## Headings
* Each page must have a single `#`-level title at the top.
* Chapters in the same page must have `##`-level titles.
* Sub-chapters need to increase the number of `#` in the title according to
* Chapters in the same page must have `##`-level headings.
* Sub-chapters need to increase the number of `#` in the heading according to
their nesting depth.
* All words in the page's title must be capitalized, except for conjunctions
like "of" and "and" .
* Only the first word of a chapter title must be capitalized.
* The page's title must follow [APA title case][title-case].
* All chapters must follow [APA sentence case][sentence-case].
Using `Quick Start` as example:
@@ -44,12 +43,20 @@ For API references, there are exceptions to this rule.
## Markdown rules
This repository uses the [`markdownlint`][markdownlint] package to enforce consistent
Markdown styling. For the exact rules, see the `.markdownlint.json` file in the root
folder.
There are a few style guidelines that aren't covered by the linter rules:
<!--TODO(erickzhao): make sure this matches with the lint:markdownlint task-->
* Use `sh` instead of `cmd` in code blocks (due to the syntax highlighter).
* Lines should be wrapped at 80 columns.
* Keep line lengths between 80 and 100 characters if possible for readability
purposes.
* No nesting lists more than 2 levels (due to the markdown renderer).
* All `js` and `javascript` code blocks are linted with
[standard-markdown](https://www.npmjs.com/package/standard-markdown).
* For unordered lists, use asterisks instead of dashes
* For unordered lists, use asterisks instead of dashes.
## Picking words
@@ -60,14 +67,15 @@ For API references, there are exceptions to this rule.
The following rules only apply to the documentation of APIs.
### Page title
### Title and description
Each page must use the actual object name returned by `require('electron')`
as the title, such as `BrowserWindow`, `autoUpdater`, and `session`.
Each module's API doc must use the actual object name returned by `require('electron')`
as its title (such as `BrowserWindow`, `autoUpdater`, and `session`).
Under the page title must be a one-line description starting with `>`.
Directly under the page title, add a one-line description of the module
as a markdown quote (beginning with `>`).
Using `session` as example:
Using the `session` module as an example:
```markdown
# session
@@ -99,14 +107,19 @@ Using `autoUpdater` as an example:
* API classes or classes that are part of modules must be listed under a
`## Class: TheClassName` chapter.
* One page can have multiple classes.
* Constructors must be listed with `###`-level titles.
* [Static Methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static) must be listed under a `### Static Methods` chapter.
* [Instance Methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Prototype_methods) must be listed under an `### Instance Methods` chapter.
* All methods that have a return value must start their description with "Returns `[TYPE]` - Return description"
* If the method returns an `Object`, its structure can be specified using a colon followed by a newline then an unordered list of properties in the same style as function parameters.
* Constructors must be listed with `###`-level headings.
* [Static Methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static)
must be listed under a `### Static Methods` chapter.
* [Instance Methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Prototype_methods)
must be listed under an `### Instance Methods` chapter.
* All methods that have a return value must start their description with
"Returns `[TYPE]` - [Return description]"
* If the method returns an `Object`, its structure can be specified using a colon
followed by a newline then an unordered list of properties in the same style as
function parameters.
* Instance Events must be listed under an `### Instance Events` chapter.
* Instance Properties must be listed under an `### Instance Properties` chapter.
* Instance properties must start with "A [Property Type] ..."
* Instance Properties must start with "A [Property Type] ..."
Using the `Session` and `Cookies` classes as an example:
@@ -142,7 +155,7 @@ Using the `Session` and `Cookies` classes as an example:
#### `cookies.get(filter, callback)`
```
### Methods
### Methods and their arguments
The methods chapter must be in the following form:
@@ -155,8 +168,12 @@ The methods chapter must be in the following form:
...
```
The title can be `###` or `####`-levels depending on whether it is a method of
a module or a class.
#### Heading level
The heading can be `###` or `####`-levels depending on whether the method
belongs to a module or a class.
#### Function signature
For modules, the `objectName` is the module's name. For classes, it must be the
name of the instance of the class, and must not be the same as the module's
@@ -165,23 +182,33 @@ name.
For example, the methods of the `Session` class under the `session` module must
use `ses` as the `objectName`.
The optional arguments are notated by square brackets `[]` surrounding the optional argument
as well as the comma required if this optional argument follows another
Optional arguments are notated by square brackets `[]` surrounding the optional
argument as well as the comma required if this optional argument follows another
argument:
```sh
```markdown
required[, optional]
```
Below the method is more detailed information on each of the arguments. The type
of argument is notated by either the common types:
#### Argument descriptions
* [`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)
* [`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)
* [`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
* [`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
* [`Boolean`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)
* Or a custom type like Electron's [`WebContent`](api/web-contents.md)
More detailed information on each of the arguments is noted in an unordered list
below the method. The type of argument is notated by either JavaScript primitives
(e.g. `String`, `Promise`, or `Object`), a custom API structure like Electron's
[`Cookie`](api/structures/cookie.md), or the wildcard `any`.
If the argument is of type `Array`, use `[]` shorthand with the type of value
inside the array (for example,`any[]` or `String[]`).
If the argument is of type `Promise`, parametrize the type with what the promise
resolves to (for example, `Promise<void>` or `Promise<String>`).
If an argument can be of multiple types, separate the types with `|`.
The description for `Function` type arguments should make it clear how it may be
called and list the types of the parameters that will be passed to it.
#### Platform-specific functionality
If an argument or a method is unique to certain platforms, those platforms are
denoted using a space-delimited italicized list following the datatype. Values
@@ -191,12 +218,6 @@ can be `macOS`, `Windows` or `Linux`.
* `animate` Boolean (optional) _macOS_ _Windows_ - Animate the thing.
```
`Array` type arguments must specify what elements the array may include in
the description below.
The description for `Function` type arguments should make it clear how it may be
called and list the types of the parameters that will be passed to it.
### Events
The events chapter must be in following form:
@@ -211,8 +232,8 @@ Returns:
...
```
The title can be `###` or `####`-levels depending on whether it is an event of
a module or a class.
The heading can be `###` or `####`-levels depending on whether the event
belongs to a module or a class.
The arguments of an event follow the same rules as methods.
@@ -226,9 +247,13 @@ The properties chapter must be in following form:
...
```
The title can be `###` or `####`-levels depending on whether it is a property of
a module or a class.
The heading can be `###` or `####`-levels depending on whether the property
belongs to a module or a class.
## Documentation Translations
## Documentation translations
See [electron/i18n](https://github.com/electron/i18n#readme)
[title-case]: https://apastyle.apa.org/style-grammar-guidelines/capitalization/title-case
[sentence-case]: https://apastyle.apa.org/style-grammar-guidelines/capitalization/sentence-case
[markdownlint]: https://github.com/DavidAnson/markdownlint

View File

@@ -18,7 +18,7 @@ distributable Electron application, such as bundling your application,
rebranding the executable, and setting the right icons.
You can check the example of how to package your app with `electron-forge` in
our [Quick Start Guide](quick-start.md#package-and-distribute-the-application).
the [Quick Start guide](quick-start.md#package-and-distribute-your-application).
## Manual distribution

View File

@@ -47,18 +47,18 @@ of this theming, due to the use of the macOS 10.14 SDK.
## Example
We'll start with a working application from the
[Quick Start Guide](quick-start.md) and add functionality gradually.
This example demonstrates an Electron application that derives its theme colors from the
`nativeTheme`. Additionally, it provides theme toggle and reset controls using IPC channels.
First, let's edit our interface so users can toggle between light and dark
modes. This basic UI contains buttons to change the `nativeTheme.themeSource`
setting and a text element indicating which `themeSource` value is selected.
By default, Electron follows the system's dark mode preference, so we
will hardcode the theme source as "System".
```javascript fiddle='docs/fiddles/features/macos-dark-mode'
Add the following lines to the `index.html` file:
```
```html
### How does this work?
Starting with the `index.html` file:
```html title='index.html'
<!DOCTYPE html>
<html>
<head>
@@ -80,65 +80,70 @@ Add the following lines to the `index.html` file:
</html>
```
Next, add [event listeners](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
that listen for `click` events on the toggle buttons. Because the `nativeTheme`
module only exposed in the Main process, you need to set up each listener's
callback to use IPC to send messages to and handle responses from the Main
process:
And the `style.css` file:
* when the "Toggle Dark Mode" button is clicked, we send the
`dark-mode:toggle` message (event) to tell the Main process to trigger a theme
change, and update the "Current Theme Source" label in the UI based on the
response from the Main process.
* when the "Reset to System Theme" button is clicked, we send the
`dark-mode:system` message (event) to tell the Main process to use the system
color scheme, and update the "Current Theme Source" label to `System`.
```css title='style.css'
@media (prefers-color-scheme: dark) {
body { background: #333; color: white; }
}
To add listeners and handlers, add the following lines to the `renderer.js` file:
@media (prefers-color-scheme: light) {
body { background: #ddd; color: black; }
}
```
```javascript
const { ipcRenderer } = require('electron')
The example renders an HTML page with a couple elements. The `<strong id="theme-source">`
element shows which theme is currently selected, and the two `<button>` elements are the
controls. The CSS file uses the [`prefers-color-scheme`][prefers-color-scheme] media query
to set the `<body>` element background and text colors.
The `preload.js` script adds a new API to the `window` object called `darkMode`. This API
exposes two IPC channels to the renderer process, `'dark-mode:toggle'` and `'dark-mode:system'`.
It also assigns two methods, `toggle` and `system`, which pass messages from the renderer to the
main process.
```js title='preload.js'
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('darkMode', {
toggle: () => ipcRenderer.invoke('dark-mode:toggle'),
system: () => ipcRenderer.invoke('dark-mode:system')
})
```
Now the renderer process can communicate with the main process securely and perform the necessary
mutations to the `nativeTheme` object.
The `renderer.js` file is responsible for controlling the `<button>` functionality.
```js title='renderer.js'
document.getElementById('toggle-dark-mode').addEventListener('click', async () => {
const isDarkMode = await ipcRenderer.invoke('dark-mode:toggle')
const isDarkMode = await window.darkMode.toggle()
document.getElementById('theme-source').innerHTML = isDarkMode ? 'Dark' : 'Light'
})
document.getElementById('reset-to-system').addEventListener('click', async () => {
await ipcRenderer.invoke('dark-mode:system')
await window.darkMode.system()
document.getElementById('theme-source').innerHTML = 'System'
})
```
If you run your code at this point, you'll see that your buttons don't do
anything just yet, and your Main process will output an error like this when
you click on your buttons:
`Error occurred in handler for 'dark-mode:toggle': No handler registered for 'dark-mode:toggle'`
This is expected — we haven't actually touched any `nativeTheme` code yet.
Using `addEventListener`, the `renderer.js` file adds `'click'` [event listeners][event-listeners]
to each button element. Each event listener handler makes calls to the respective `window.darkMode`
API methods.
Now that we're done wiring the IPC from the Renderer's side, the next step
is to update the `main.js` file to handle events from the Renderer process.
Finally, the `main.js` file represents the main process and contains the actual `nativeTheme` API.
Depending on the received event, we update the
[`nativeTheme.themeSource`](../api/native-theme.md#nativethemethemesource)
property to apply the desired theme on the system's native UI elements
(e.g. context menus) and propagate the preferred color scheme to the Renderer
process:
* Upon receiving `dark-mode:toggle`, we check if the dark theme is currently
active using the `nativeTheme.shouldUseDarkColors` property, and set the
`themeSource` to the opposite theme.
* Upon receiving `dark-mode:system`, we reset the `themeSource` to `system`.
```javascript
```js
const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron')
const path = require('path')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
preload: path.join(__dirname, 'preload.js')
}
})
@@ -158,40 +163,37 @@ function createWindow () {
})
}
app.whenReady().then(createWindow)
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
```
The final step is to add a bit of styling to enable dark mode for the web parts
of the UI by leveraging the [`prefers-color-scheme`][prefer-color-scheme] CSS
attribute. The value of `prefers-color-scheme` will follow your
`nativeTheme.themeSource` setting.
The `ipcMain.handle` methods are how the main process responds to the click events from the buttons
on the HTML page.
Create a `styles.css` file and add the following lines:
The `'dark-mode:toggle'` IPC channel handler method checks the `shouldUseDarkColors` boolean property,
sets the corresponding `themeSource`, and then returns the current `shouldUseDarkColors` property.
Looking back on the renderer process event listener for this IPC channel, the return value from this
handler is utilized to assign the correct text to the `<strong id='theme-source'>` element.
```css fiddle='docs/fiddles/features/macos-dark-mode'
@media (prefers-color-scheme: dark) {
body { background: #333; color: white; }
}
The `'dark-mode:system'` IPC channel handler method assigns the string `'system'` to the `themeSource`
and returns nothing. This also corresponds with the relative renderer process event listener as the
method is awaited with no return value expected.
@media (prefers-color-scheme: light) {
body { background: #ddd; color: black; }
}
```
After launching the Electron application, you can change modes or reset the
theme to system default by clicking corresponding buttons:
Run the example using Electron Fiddle and then click the "Toggle Dark Mode" button; the app should
start alternating between a light and dark background color.
![Dark Mode](../images/dark_mode.gif)
@@ -199,4 +201,5 @@ theme to system default by clicking corresponding buttons:
[electron-forge]: https://www.electronforge.io/
[electron-packager]: https://github.com/electron/electron-packager
[packager-darwindarkmode-api]: https://electron.github.io/electron-packager/master/interfaces/electronpackager.options.html#darwindarkmodesupport
[prefer-color-scheme]: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme
[prefers-color-scheme]: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme
[event-listeners]: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

View File

@@ -11,14 +11,19 @@ npm install electron --save-dev
See the [Electron versioning doc][versioning] for info on how to
manage Electron versions in your apps.
## Global Installation
## Running Electron ad-hoc
You can also install the `electron` command globally in your `$PATH`:
If you're in a pinch and would prefer to not use `npm install` in your local
project, you can also run Electron ad-hoc using the [`npx`][npx] command runner
bundled with `npm`:
```sh
npm install electron -g
npx electron .
```
The above command will run the current working directory with Electron. Note that
any dependencies in your app will not be installed.
## Customization
If you want to change the architecture that is downloaded (e.g., `ia32` on an
@@ -178,6 +183,7 @@ If you need to force a re-download of the asset and the SHASUM file set the
[npm]: https://docs.npmjs.com
[versioning]: ./electron-versioning.md
[npx]: https://docs.npmjs.com/cli/v7/commands/npx
[releases]: https://github.com/electron/electron/releases
[proxy-env-10]: https://github.com/gajus/global-agent/blob/v2.1.5/README.md#environment-variables
[proxy-env]: https://github.com/np-maintain/global-tunnel/blob/v2.7.1/README.md#auto-config

View File

@@ -0,0 +1,59 @@
# Introduction
Welcome to the Electron documentation! If this is your first time developing
an Electron app, read through this Getting Started section to get familiar with the
basics. Otherwise, feel free to explore our guides and API documentation!
## What is Electron?
Electron is a framework for building desktop applications using JavaScript,
HTML, and CSS. By embedding [Chromium][chromium] and [Node.js][node] into its
binary, Electron allows you to maintain one JavaScript codebase and create
cross-platform apps that work on Windows, macOS, and Linux — no native development
experience required.
## Prerequisites
These docs operate under the assumption that the reader is familiar with both
Node.js and general web development. If you need to get more comfortable with
either of these areas, we recommend the following resources:
* [Getting started with the Web (MDN)][mdn-guide]
* [Introduction to Node.js][node-guide]
Moreover, you'll have a better time understanding how Electron works if you get
acquainted with Chromium's process model. You can get a brief overview of
Chrome architecture with the [Chrome comic][comic], which was released alongside
Chrome's launch back in 2008. Although it's been over a decade since then, the
core principles introduced in the comic remain helpful to understand Electron.
## Running examples with Electron Fiddle
[Electron Fiddle][fiddle] is a sandbox app written with Electron and supported by
Electron's maintainers. We highly recommend installing it as a learning tool to
experiment with Electron's APIs or to prototype features during development.
Fiddle also integrates nicely with our documentation. When browsing through examples
in our tutorials, you'll frequently see an "Open in Electron Fiddle" button underneath
a code block. If you have Fiddle installed, this button will open a
`fiddle.electronjs.org` link that will automatically load the example into Fiddle,
no copy-pasting required.
## Getting help
Are you getting stuck anywhere? Here are a few links to places to look:
* If you need help with developing your app, our [community Discord server][discord]
is a great place to get advice from other Electron app developers.
* If you suspect you're running into a bug with the `electron` package, please check
the [GitHub issue tracker][issue-tracker] to see if any existing issues match your
problem. If not, feel free to fill out our bug report template and submit a new issue.
[chromium]: https://www.chromium.org/
[node]: https://nodejs.org/
[mdn-guide]: https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web
[node-guide]: https://nodejs.dev/learn
[comic]: https://www.google.com/googlebooks/chrome/
[fiddle]: https://electronjs.org/fiddle
[issue-tracker]: https://github.com/electron/electron/issues
[discord]: https://discord.gg/electron

View File

@@ -81,11 +81,17 @@ If you want to handle keyboard shortcuts within a [BrowserWindow], you can
listen for the `keyup` and `keydown` [DOM events][dom-events] inside the
renderer process using the [addEventListener() API][addEventListener-api].
```js
window.addEventListener('keyup', doSomething, true)
```javascript fiddle='docs/fiddles/features/keyboard-shortcuts/web-apis|focus=renderer.js'
function handleKeyPress(event) {
// You can put code here to handle the keypress.
document.getElementById("last-keypress").innerText = event.key;
console.log(`You pressed ${event.key}`);
}
window.addEventListener('keyup', handleKeyPress, true);
```
Note the third parameter `true` indicates that the listener will always receive
> Note: the third parameter `true` indicates that the listener will always receive
key presses before other listeners so they can't have `stopPropagation()`
called on them.
@@ -95,8 +101,6 @@ The [`before-input-event`](../api/web-contents.md#event-before-input-event) even
is emitted before dispatching `keydown` and `keyup` events in the page. It can
be used to catch and handle custom shortcuts that are not visible in the menu.
##### Example
Starting with a working application from the
[Quick Start Guide](quick-start.md), update the `main.js` file with the
following lines:
@@ -105,7 +109,7 @@ following lines:
const { app, BrowserWindow } = require('electron')
app.whenReady().then(() => {
const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true } })
const win = new BrowserWindow({ width: 800, height: 600 })
win.loadFile('index.html')
win.webContents.on('before-input-event', (event, input) => {

View File

@@ -1,53 +1,111 @@
# Mac App Store Submission Guide
Since v0.34.0, Electron allows submitting packaged apps to the Mac App Store
(MAS). This guide provides information on: how to submit your app and the
limitations of the MAS build.
This guide provides information on:
**Note:** Submitting an app to Mac App Store requires enrolling in the [Apple Developer
Program][developer-program], which costs money.
* How to sign Electron apps on macOS;
* How to submit Electron apps to Mac App Store (MAS);
* The limitations of the MAS build.
## How to Submit Your App
## Requirements
The following steps introduce a simple way to submit your app to Mac App Store.
However, these steps do not ensure your app will be approved by Apple; you
still need to read Apple's [Submitting Your App][submitting-your-app] guide on
how to meet the Mac App Store requirements.
To sign Electron apps, the following tools must be installed first:
### Get Certificate
* Xcode 11 or above.
* The [electron-osx-sign][electron-osx-sign] npm module.
To submit your app to the Mac App Store, you first must get a certificate from
Apple. You can follow these [existing guides][nwjs-guide] on web.
You also have to register an Apple Developer account and join the
[Apple Developer Program][developer-program].
### Get Team ID
## Sign Electron apps
Before signing your app, you need to know the Team ID of your account. To locate
your Team ID, Sign in to [Apple Developer Center](https://developer.apple.com/account/),
and click Membership in the sidebar. Your Team ID appears in the Membership
Information section under the team name.
Electron apps can be distributed through Mac App Store or outside it. Each way
requires different ways of signing and testing. This guide focuses on
distribution via Mac App Store, but will also mention other methods.
### Sign Your App
The following steps describe how to get the certificates from Apple, how to sign
Electron apps, and how to test them.
After finishing the preparation work, you can package your app by following
[Application Distribution](application-distribution.md), and then proceed to
signing your app.
### Get certificates
First, you have to add a `ElectronTeamID` key to your app's `Info.plist`, which
has your Team ID as its value:
The simplest way to get signing certificates is to use Xcode:
```xml
<plist version="1.0">
<dict>
...
<key>ElectronTeamID</key>
<string>TEAM_ID</string>
</dict>
</plist>
```
1. Open Xcode and open "Accounts" preferences;
2. Sign in with your Apple account;
3. Select a team and click "Manage Certificates";
4. In the lower-left corner of the signing certificates sheet, click the Add
button (+), and add following certificates:
* "Apple Development"
* "Apple Distribution"
Then, you need to prepare three entitlements files.
The "Apple Development" certificate is used to sign apps for development and
testing, on machines that have been registered on Apple Developer website. The
method of registration will be described in
[Prepare provisioning profile](#prepare-provisioning-profile).
`child.plist`:
Apps signed with the "Apple Development" certificate cannot be submitted to Mac
App Store. For that purpose, apps must be signed with the "Apple Distribution"
certificate instead. But note that apps signed with the "Apple Distribution"
certificate cannot run directly, they must be re-signed by Apple to be able to
run, which will only be possible after being downloaded from the Mac App Store.
#### Other certificates
You may notice that there are also other kinds of certificates.
The "Developer ID Application" certificate is used to sign apps before
distributing them outside the Mac App Store.
The "Developer ID Installer" and "Mac Installer Distribution" certificates are
used to sign the Mac Installer Package instead of the app itself. Most Electron
apps do not use Mac Installer Package so they are generally not needed.
The full list of certificate types can be found
[here](https://help.apple.com/xcode/mac/current/#/dev80c6204ec).
Apps signed with "Apple Development" and "Apple Distribution" certificates can
only run under [App Sandbox][app-sandboxing], so they must use the MAS build of
Electron. However, the "Developer ID Application" certificate does not have this
restrictions, so apps signed with it can use either the normal build or the MAS
build of Electron.
#### Legacy certificate names
Apple has been changing the names of certificates during past years, you might
encounter them when reading old documentations, and some utilities are still
using one of the old names.
* The "Apple Distribution" certificate was also named as "3rd Party Mac
Developer Application" and "Mac App Distribution".
* The "Apple Development" certificate was also named as "Mac Developer" and
"Development".
### Prepare provisioning profile
If you want to test your app on your local machine before submitting your app to
the Mac App Store, you have to sign the app with the "Apple Development"
certificate with the provisioning profile embedded in the app bundle.
To [create a provisioning profile](https://help.apple.com/developer-account/#/devf2eb157f8),
you can follow the below steps:
1. Open the "Certificates, Identifiers & Profiles" page on the
[Apple Developer](https://developer.apple.com/account) website.
2. Add a new App ID for your app in the "Identifiers" page.
3. Register your local machine in the "Devices" page. You can find your
machine's "Device ID" in the "Hardware" page of the "System Information" app.
4. Register a new Provisioning Profile in the "Profiles" page, and download it
to `/path/to/yourapp.provisionprofile`.
### Enable Apple's App Sandbox
Apps submitted to the Mac App Store must run under Apple's
[App Sandbox][app-sandboxing], and only the MAS build of Electron can run with
the App Sandbox. The standard darwin build of Electron will fail to launch
when run under App Sandbox.
When signing the app with `electron-osx-sign`, it will automatically add the
necessary entitlements to your app's entitlements, but if you are using custom
entitlements, you must ensure App Sandbox capacity is added:
```xml
<?xml version="1.0" encoding="UTF-8"?>
@@ -56,13 +114,14 @@ Then, you need to prepare three entitlements files.
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>
```
`parent.plist`:
#### Extra steps without `electron-osx-sign`
If you are signing your app without using `electron-osx-sign`, you must ensure
the app bundle's entitlements have at least following keys:
```xml
<?xml version="1.0" encoding="UTF-8"?>
@@ -79,7 +138,11 @@ Then, you need to prepare three entitlements files.
</plist>
```
`loginhelper.plist`:
The `TEAM_ID` should be replaced with your Apple Developer account's Team ID,
and the `your.bundle.id` should be replaced with the App ID of the app.
And the following entitlements must be added to the binaries and helpers in
the app's bundle:
```xml
<?xml version="1.0" encoding="UTF-8"?>
@@ -88,80 +151,97 @@ Then, you need to prepare three entitlements files.
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>
```
You have to replace `TEAM_ID` with your Team ID, and replace `your.bundle.id`
with the Bundle ID of your app.
And the app bundle's `Info.plist` must include `ElectronTeamID` key, which has
your Apple Developer account's Team ID as its value:
And then sign your app with the following script:
```sh
#!/bin/bash
# Name of your app.
APP="YourApp"
# The path of your app to sign.
APP_PATH="/path/to/YourApp.app"
# The path to the location you want to put the signed package.
RESULT_PATH="~/Desktop/$APP.pkg"
# The name of certificates you requested.
APP_KEY="3rd Party Mac Developer Application: Company Name (APPIDENTITY)"
INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)"
# The path of your plist files.
CHILD_PLIST="/path/to/child.plist"
PARENT_PLIST="/path/to/parent.plist"
LOGINHELPER_PLIST="/path/to/loginhelper.plist"
FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Electron Framework"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libnode.dylib"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/Contents/MacOS/$APP Helper"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/"
codesign -s "$APP_KEY" -f --entitlements "$LOGINHELPER_PLIST" "$APP_PATH/Contents/Library/LoginItems/$APP Login Helper.app/Contents/MacOS/$APP Login Helper"
codesign -s "$APP_KEY" -f --entitlements "$LOGINHELPER_PLIST" "$APP_PATH/Contents/Library/LoginItems/$APP Login Helper.app/"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$APP_PATH/Contents/MacOS/$APP"
codesign -s "$APP_KEY" -f --entitlements "$PARENT_PLIST" "$APP_PATH"
productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH"
```xml
<plist version="1.0">
<dict>
...
<key>ElectronTeamID</key>
<string>TEAM_ID</string>
</dict>
</plist>
```
If you are new to app sandboxing under macOS, you should also read through
Apple's [Enabling App Sandbox][enable-app-sandbox] to have a basic idea, then
add keys for the permissions needed by your app to the entitlements files.
When using `electron-osx-sign` the `ElectronTeamID` key will be added
automatically by extracting the Team ID from the certificate's name. You may
need to manually add this key if `electron-osx-sign` could not find the correct
Team ID.
Apart from manually signing your app, you can also choose to use the
[electron-osx-sign][electron-osx-sign] module to do the job.
### Sign apps for development
#### Sign Native Modules
To sign an app that can run on your development machine, you must sign it with
the "Apple Development" certificate and pass the provisioning profile to
`electron-osx-sign`.
Native modules used in your app also need to be signed. If using
electron-osx-sign, be sure to include the path to the built binaries in the
argument list:
```sh
electron-osx-sign YourApp.app YourApp.app/Contents/Resources/app/node_modules/nativemodule/build/release/nativemodule
```bash
electron-osx-sign YourApp.app --identity='Apple Development' --provisioning-profile=/path/to/yourapp.provisionprofile
```
Also note that native modules may have intermediate files produced which should
not be included (as they would also need to be signed). If you use
[electron-packager][electron-packager] before version 8.1.0, add
`--ignore=.+\.o$` to your build step to ignore these files. Versions 8.1.0 and
later ignore those files by default.
If you are signing without `electron-osx-sign`, you must place the provisioning
profile to `YourApp.app/Contents/embedded.provisionprofile`.
### Upload Your App
The signed app can only run on the machines that registered by the provisioning
profile, and this is the only way to test the signed app before submitting to
Mac App Store.
After signing your app, you can use Application Loader to upload it to iTunes
### Sign apps for submitting to the Mac App Store
To sign an app that will be submitted to Mac App Store, you must sign it with
the "Apple Distribution" certificate. Note that apps signed with this
certificate will not run anywhere, unless it is downloaded from Mac App Store.
```bash
electron-osx-sign YourApp.app --identity='Apple Distribution'
```
### Sign apps for distribution outside the Mac App Store
If you don't plan to submit the app to Mac App Store, you can sign it the
"Developer ID Application" certificate. In this way there is no requirement on
App Sandbox, and you should use the normal darwin build of Electron if you don't
use App Sandbox.
```bash
electron-osx-sign YourApp.app --identity='Developer ID Application' --no-gatekeeper-assess
```
By passing `--no-gatekeeper-assess`, the `electron-osx-sign` will skip the macOS
GateKeeper check as your app usually has not been notarized yet by this step.
<!-- TODO(zcbenz): Add a chapter about App Notarization -->
This guide does not cover [App Notarization][app-notarization], but you might
want to do it otherwise Apple may prevent users from using your app outside Mac
App Store.
## Submit Apps to the Mac App Store
After signing the app with the "Apple Distribution" certificate, you can
continue to submit it to Mac App Store.
However, this guide do not ensure your app will be approved by Apple; you
still need to read Apple's [Submitting Your App][submitting-your-app] guide on
how to meet the Mac App Store requirements.
### Upload
The Application Loader should be used to upload the signed app to iTunes
Connect for processing, making sure you have [created a record][create-record]
before uploading.
### Submit Your App for Review
If you are seeing errors like private APIs uses, you should check if the app is
using the MAS build of Electron.
After these steps, you can [submit your app for review][submit-for-review].
### Submit for review
After uploading, you should [submit your app for review][submit-for-review].
## Limitations of MAS Build
@@ -181,13 +261,13 @@ Also, due to the usage of app sandboxing, the resources which can be accessed by
the app are strictly limited; you can read [App Sandboxing][app-sandboxing] for
more information.
### Additional Entitlements
### Additional entitlements
Depending on which Electron APIs your app uses, you may need to add additional
entitlements to your `parent.plist` file to be able to use these APIs from your
app's Mac App Store build.
entitlements to your app's entitlements file. Otherwise, the App Sandbox may
prevent you from using them.
#### Network Access
#### Network access
Enable outgoing network connections to allow your app to connect to a server:
@@ -261,15 +341,12 @@ Electron uses following cryptographic algorithms:
* RIPEMD - [ISO/IEC 10118-3](https://webstore.ansi.org/RecordDetail.aspx?sku=ISO%2FIEC%2010118-3:2004)
[developer-program]: https://developer.apple.com/support/compare-memberships/
[submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html
[nwjs-guide]: https://github.com/nwjs/nw.js/wiki/Mac-App-Store-%28MAS%29-Submission-Guideline#first-steps
[enable-app-sandbox]: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html
[create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html
[electron-osx-sign]: https://github.com/electron-userland/electron-osx-sign
[electron-packager]: https://github.com/electron/electron-packager
[submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html
[electron-osx-sign]: https://github.com/electron/electron-osx-sign
[app-sandboxing]: https://developer.apple.com/app-sandboxing/
[app-notarization]: https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution
[submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html
[create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html
[submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html
[export-compliance]: https://help.apple.com/app-store-connect/#/devc3f64248f
[temporary-exception]: https://developer.apple.com/library/mac/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/AppSandboxTemporaryExceptionEntitlements.html
[user-selected]: https://developer.apple.com/library/mac/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html#//apple_ref/doc/uid/TP40011195-CH4-SW6
[network-access]: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html#//apple_ref/doc/uid/TP40011195-CH4-SW9

View File

@@ -1,6 +1,4 @@
# macOS Dock
## Overview
# Configuring the macOS Dock
Electron has APIs to configure the app's icon in the macOS Dock. A macOS-only
API exists to create a custom dock menu, but Electron also uses the app dock
@@ -25,7 +23,16 @@ Starting with a working application from the
following lines:
```javascript fiddle='docs/fiddles/features/macos-dock-menu'
const { app, Menu } = require('electron')
const { app, BrowserWindow, Menu } = require('electron')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
})
win.loadFile('index.html')
}
const dockMenu = Menu.buildFromTemplate([
{
@@ -42,8 +49,23 @@ const dockMenu = Menu.buildFromTemplate([
])
app.whenReady().then(() => {
app.dock.setMenu(dockMenu)
if (process.platform === 'darwin') {
app.dock.setMenu(dockMenu)
}
}).then(createWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
```
After launching the Electron application, right click the application icon.

View File

@@ -14,30 +14,46 @@ API in response to the `ondragstart` event.
## Example
Starting with a working application from the
[Quick Start Guide](quick-start.md), add the following lines to the
`index.html` file:
An example demonstrating how you can create a file on the fly to be dragged out of the window.
### Preload.js
In `preload.js` use the [`contextBridge`] to inject a method `window.electron.startDrag(...)` that will send an IPC message to the main process.
```js
const { contextBridge, ipcRenderer } = require('electron')
const path = require('path')
contextBridge.exposeInMainWorld('electron', {
startDrag: (fileName) => {
ipcRenderer.send('ondragstart', path.join(process.cwd(), fileName))
}
})
```
### Index.html
Add a draggable element to `index.html`, and reference your renderer script:
```html
<a href="#" id="drag">Drag me</a>
<div style="border:2px solid black;border-radius:3px;padding:5px;display:inline-block" draggable="true" id="drag">Drag me</div>
<script src="renderer.js"></script>
```
and add the following lines to the `renderer.js` file:
### Renderer.js
In `renderer.js` set up the renderer process to handle drag events by calling the method you added via the [`contextBridge`] above.
```javascript
const { ipcRenderer } = require('electron')
document.getElementById('drag').ondragstart = (event) => {
event.preventDefault()
ipcRenderer.send('ondragstart', '/absolute/path/to/the/item')
window.electron.startDrag('drag-and-drop.md')
}
```
The code above instructs the Renderer process to handle the `ondragstart` event
and forward the information to the Main process.
### Main.js
In the Main process(`main.js` file), expand the received event with a path to the file that is
In the Main process (`main.js` file), expand the received event with a path to the file that is
being dragged and an icon:
```javascript fiddle='docs/fiddles/features/drag-and-drop'
@@ -56,3 +72,5 @@ the item from the BrowserWindow onto your desktop. In this guide,
the item is a Markdown file located in the root of the project:
![Drag and drop](../images/drag-and-drop.gif)
[`contextBridge`]: ../api/context-bridge.md

View File

@@ -18,7 +18,7 @@ To show notifications in the Main process, you need to use the
### Show notifications in the Renderer process
Assuming you have a working Electron application from the
Starting with a working application from the
[Quick Start Guide](quick-start.md), add the following line to the
`index.html` file before the closing `</body>` tag:
@@ -26,26 +26,22 @@ Assuming you have a working Electron application from the
<script src="renderer.js"></script>
```
and add the `renderer.js` file:
...and add the `renderer.js` file:
```javascript fiddle='docs/fiddles/features/notifications/renderer'
const myNotification = new Notification('Title', {
body: 'Notification from the Renderer process'
})
const NOTIFICATION_TITLE = 'Title'
const NOTIFICATION_BODY = 'Notification from the Renderer process. Click to log to console.'
const CLICK_MESSAGE = 'Notification clicked'
myNotification.onclick = () => {
console.log('Notification clicked')
}
new Notification(NOTIFICATION_TITLE, { body: NOTIFICATION_BODY })
.onclick = () => console.log(CLICK_MESSAGE)
```
After launching the Electron application, you should see the notification:
![Notification in the Renderer process](../images/notification-renderer.png)
If you open the Console and then click the notification, you will see the
message that was generated after triggering the `onclick` event:
![Onclick message for the notification](../images/message-notification-renderer.png)
Additionally, if you click on the notification, the DOM will update to show "Notification clicked!".
### Show notifications in the Main process
@@ -55,18 +51,17 @@ Starting with a working application from the
```javascript fiddle='docs/fiddles/features/notifications/main'
const { Notification } = require('electron')
const NOTIFICATION_TITLE = 'Basic Notification'
const NOTIFICATION_BODY = 'Notification from the Main process'
function showNotification () {
const notification = {
title: 'Basic Notification',
body: 'Notification from the Main process'
}
new Notification(notification).show()
new Notification({ title: NOTIFICATION_TITLE, body: NOTIFICATION_BODY }).show()
}
app.whenReady().then(createWindow).then(showNotification)
```
After launching the Electron application, you should see the notification:
After launching the Electron application, you should see the system notification:
![Notification in the Main process](../images/notification-main.png)

View File

@@ -39,10 +39,6 @@ To enable this mode, GPU acceleration has to be disabled by calling the
## Example
Starting with a working application from the
[Quick Start Guide](quick-start.md), add the following lines to the
`main.js` file:
```javascript fiddle='docs/fiddles/features/offscreen-rendering'
const { app, BrowserWindow } = require('electron')
const fs = require('fs')
@@ -63,5 +59,5 @@ app.whenReady().then(() => {
```
After launching the Electron application, navigate to your application's
working folder.
working folder, where you'll find the rendered image.
[disablehardwareacceleration]: ../api/app.md#appdisablehardwareacceleration

View File

@@ -21,83 +21,29 @@ status of Electron, you should develop additional means for this check.
## Example
### Event detection in the Renderer process
Starting with an HTML file `index.html`, this example will demonstrate how the `navigator.onLine` API can be used to build a connection status indicator.
Starting with a working application from the
[Quick Start Guide](quick-start.md), update the `main.js` file
with the following lines:
```javascript
const { app, BrowserWindow } = require('electron')
let onlineStatusWindow
app.whenReady().then(() => {
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false })
onlineStatusWindow.loadURL(`file://${__dirname}/index.html`)
})
```html title="index.html"
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
<h1>Connection status: <strong id='status'></strong></h1>
<script src="renderer.js"></script>
</body>
</html>
```
in the `index.html` file, add the following line before the
closing `</body>` tag:
In order to mutate the DOM, create a `renderer.js` file that adds event listeners to the `'online'` and `'offline'` `window` events. The event handler sets the content of the `<strong id='status'>` element depending on the result of `navigator.onLine`.
```html
<script src="renderer.js"></script>
```
and add the `renderer.js` file:
```javascript fiddle='docs/fiddles/features/online-detection/renderer'
const alertOnlineStatus = () => { window.alert(navigator.onLine ? 'online' : 'offline') }
window.addEventListener('online', alertOnlineStatus)
window.addEventListener('offline', alertOnlineStatus)
alertOnlineStatus()
```
After launching the Electron application, you should see the notification:
![Online-offline-event detection](../images/online-event-detection.png)
### Event detection in the Main process
There may be situations when you want to respond to online/offline events in
the Main process as well. The Main process, however, does not have a
`navigator` object and cannot detect these events directly. In this case, you
need to forward the events to the Main process using Electron's inter-process
communication (IPC) utilities.
Starting with a working application from the
[Quick Start Guide](quick-start.md), update the `main.js` file
with the following lines:
```javascript
const { app, BrowserWindow, ipcMain } = require('electron')
let onlineStatusWindow
app.whenReady().then(() => {
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false, webPreferences: { nodeIntegration: true } })
onlineStatusWindow.loadURL(`file://${__dirname}/index.html`)
})
ipcMain.on('online-status-changed', (event, status) => {
console.log(status)
})
```
in the `index.html` file, add the following line before the
closing `</body>` tag:
```html
<script src="renderer.js"></script>
```
and add the `renderer.js` file:
```javascript fiddle='docs/fiddles/features/online-detection/main'
const { ipcRenderer } = require('electron')
const updateOnlineStatus = () => { ipcRenderer.send('online-status-changed', navigator.onLine ? 'online' : 'offline') }
```js title='renderer.js'
function updateOnlineStatus () {
document.getElementById('status').innerHTML = navigator.onLine ? 'online' : 'offline'
}
window.addEventListener('online', updateOnlineStatus)
window.addEventListener('offline', updateOnlineStatus)
@@ -105,14 +51,39 @@ window.addEventListener('offline', updateOnlineStatus)
updateOnlineStatus()
```
After launching the Electron application, you should see the notification in the
Console:
Finally, create a `main.js` file for main process that creates the window.
```sh
npm start
```js title='main.js'
const { app, BrowserWindow } = require('electron')
> electron@1.0.0 start /electron
> electron .
function createWindow () {
const onlineStatusWindow = new BrowserWindow({
width: 400,
height: 100
})
online
onlineStatusWindow.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
```
After launching the Electron application, you should see the notification:
![Connection status](../images/connection-status.png)
> Note: If you need to communicate the connection status to the main process, use the [IPC renderer](../api/ipc-renderer.md) API.

View File

@@ -120,9 +120,9 @@ file in the directory you executed it in. Both files can be analyzed using
the Chrome Developer Tools, using the `Performance` and `Memory` tabs
respectively.
![performance-cpu-prof]
![Performance CPU Profile][performance-cpu-prof]
![performance-heap-prof]
![Performance Heap Memory Profile][performance-heap-prof]
In this example, on the author's machine, we saw that loading `request` took
almost half a second, whereas `node-fetch` took dramatically less memory

View File

@@ -0,0 +1,206 @@
# Process Model
Electron inherits its multi-process architecture from Chromium, which makes the framework
architecturally very similar to a modern web browser. In this guide, we'll expound on
the conceptual knowledge of Electron that we applied in the minimal [quick start app][].
[quick start app]: ./quick-start.md
## Why not a single process?
Web browsers are incredibly complicated applications. Aside from their primary ability
to display web content, they have many secondary responsibilities,
such as managing multiple windows (or tabs) and loading third-party extensions.
In the earlier days, browsers usually used a single process for all of this
functionality. Although this pattern meant less overhead for each tab you had open,
it also meant that one website crashing or hanging would affect the entire browser.
## The multi-process model
To solve this problem, the Chrome team decided that each tab would render in its own
process, limiting the harm that buggy or malicious code on a web page could cause to
the app as a whole. A single browser process then controls these processes, as well
as the application lifecycle as a whole. This diagram below from the [Chrome Comic]
visualizes this model:
![Chrome's multi-process architecture](../images/chrome-processes.png)
Electron applications are structured very similarly. As an app developer, you control
two types of processes: main and renderer. These are analogous to Chrome's own browser
and renderer processes outlined above.
[Chrome Comic]: https://www.google.com/googlebooks/chrome/
## The main process
Each Electron app has a single main process, which acts as the application's entry
point. The main process runs in a Node.js environment, meaning it has the ability
to `require` modules and use all of Node.js APIs.
### Window management
The main process' primary purpose is to create and manage application windows with the
[`BrowserWindow`][browser-window] module.
Each instance of the `BrowserWindow` class creates an application window that loads
a web page in a separate renderer process. You can interact with this web content
from the main process using the window's [`webContents`][web-contents] object.
```js title='main.js'
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 1500 })
win.loadURL('https://github.com')
const contents = win.webContents
console.log(contents)
```
> Note: A renderer process is also created for [web embeds][web-embed] such as the
> `BrowserView` module. The `webContents` object is also accessible for embedded
> web content.
Because the `BrowserWindow` module is an [`EventEmitter`][event-emitter], you can also
add handlers for various user events (for example, minimizing or maximizing your window).
When a `BrowserWindow` instance is destroyed, its corresponding renderer process gets
terminated as well.
[browser-window]: ../api/browser-window.md
[web-embed]: ./web-embeds.md
[web-contents]: ../api/web-contents.md
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
### Application lifecycle
The main process also controls your application's lifecycle through Electron's
[`app`][app] module. This module provides a large set of events and methods
that you can use to add custom application behaviour (for instance, programatically
quitting your application, modifying the application dock, or showing an About panel).
As a practical example, the app shown in the [quick start guide][quick-start-lifecycle]
uses `app` APIs to create a more native application window experience.
```js title='main.js'
// quitting the app when no windows are open on macOS
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
```
[app]: ../api/app.md
[quick-start-lifecycle]: ./quick-start.md#manage-your-windows-lifecycle
### Native APIs
To extend Electron's features beyond being a Chromium wrapper for web contents, the
main process also adds custom APIs to interact with the user's operating system.
Electron exposes various modules that control native desktop functionality, such
as menus, dialogs, and tray icons.
For a full list of Electron's main process modules, check out our API documentation.
## The renderer process
Each Electron app spawns a separate renderer process for each open `BrowserWindow`
(and each web embed). As its name implies, a renderer is responsible for
*rendering* web content. For all intents and purposes, code ran in renderer processes
should behave according to web standards (insofar as Chromium does, at least).
Therefore, all user interfaces and app functionality within a single browser
window should be written with the same tools and paradigms that you use on the
web.
Although explaining every web spec is out of scope for this guide, the bare minimum
to understand is:
* An HTML file is your entry point for the renderer process.
* UI styling is added through Cascading Style Sheets (CSS).
* Executable JavaScript code can be added through `<script>` elements.
Moreover, this also means that the renderer has no direct access to `require`
or other Node.js APIs. In order to directly include NPM modules in the renderer,
you must use the same bundler toolchains (for example, `webpack` or `parcel`) that you
use on the web.
> Note: Renderer processes can be spawned with a full Node.js environment for ease of
> development. Historically, this used to be the default, but this feature was disabled
> for security reasons.
At this point, you might be wondering how your renderer process user interfaces
can interact with Node.js and Electron's native desktop functionality if these
features are only accessible from the main process. In fact, there is no direct
way to import Electron's content scripts.
## Preload scripts
<!-- Note: This guide doesn't take sandboxing into account, which might fundamentally
change the statements here. -->
Preload scripts contain code that executes in a renderer process before its web content
begins loading. These scripts runs within the renderer context, but are granted more
privileges by having access to Node.js APIs.
A preload script can be attached to the main process in the `BrowserWindow` constructor's
`webPreferences` option.
```js title='main.js'
const { BrowserWindow } = require('electron')
//...
const win = new BrowserWindow({
preload: 'path/to/preload.js'
})
//...
```
Because the preload script shares a global [`Window`][window-mdn] interface with the
renderers and can access Node.js APIs, it serves to enhance your renderer by exposing
arbitrary APIs in the `window` global that your web contents can then consume.
Although preload scripts share a `window` global with the renderer they're attached to,
you cannot directly attach any variables from the preload script to `window` because of
the [`contextIsolation`][context-isolation] default.
```js title='preload.js'
window.myAPI = {
desktop: true
}
```
```js title='renderer.js'
console.log(window.myAPI)
// => undefined
```
Context Isolation means that preload scripts are isolated from the renderer's main world
to avoid leaking any privileged APIs into your web content's code.
Instead, use the [`contextBridge`][context-bridge] module to accomplish this
securely:
```js title='preload.js'
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
desktop: true
})
```
```js title='renderer.js'
console.log(window.myAPI)
// => { desktop: true }
```
This feature is incredibly useful for two main purposes:
* By exposing [`ipcRenderer`][ipcRenderer] helpers to the renderer, you can use
inter-process communication (IPC) to trigger main process tasks from the
renderer (and vice-versa).
* If you're developing an Electron wrapper for an existing web app hosted on a remote
URL, you can add custom properties onto the renderer's `window` global that can
be used for desktop-only logic on the web client's side.
[window-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Window
[context-isolation]: ./context-isolation.md
[context-bridge]: ../api/context-bridge.md
[ipcRenderer]: ../api/ipc-renderer.md

View File

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

View File

@@ -1,20 +1,23 @@
# Quick Start Guide
# Quick Start
## Quickstart
This guide will step you through the process of creating a barebones Hello World app in
Electron, similar to [`electron/electron-quick-start`][quick-start].
Electron is a framework that enables you to create desktop applications with JavaScript, HTML, and CSS. These applications can then be packaged to run directly on macOS, Windows, or Linux, or distributed via the Mac App Store or the Microsoft Store.
By the end of this tutorial, your app will open a browser window that displays a web page
with information about which Chromium, Node.js, and Electron versions are running.
Typically, you create a desktop application for an operating system (OS) using each operating system's specific native application frameworks. Electron makes it possible to write your application once using technologies that you already know.
[quick-start]: https://github.com/electron/electron-quick-start
### Prerequisites
## Prerequisites
Before proceeding with Electron you need to install [Node.js][node-download].
We recommend that you install either the latest `LTS` or `Current` version available.
To use Electron, you need to install [Node.js][node-download]. We recommend that you
use the latest `LTS` version available.
> Please install Node.js using pre-built installers for your platform.
> You may encounter incompatibility issues with different development tools otherwise.
To check that Node.js was installed correctly, type the following commands in your terminal client:
To check that Node.js was installed correctly, type the following commands in your
terminal client:
```sh
node -v
@@ -22,42 +25,276 @@ npm -v
```
The commands should print the versions of Node.js and npm accordingly.
If both commands succeeded, you are ready to install Electron.
### Create a basic application
**Note:** Since Electron embeds Node.js into its binary, the version of Node.js running
your code is unrelated to the version running on your system.
From a development perspective, an Electron application is essentially a Node.js application. This means that the starting point of your Electron application will be a `package.json` file like in any other Node.js application. A minimal Electron application has the following structure:
[node-download]: https://nodejs.org/en/download/
```plaintext
my-electron-app/
├── package.json
├── main.js
├── preload.js
└── index.html
```
## Create your application
Let's create a basic application based on the structure above.
### Scaffold the project
#### Install Electron
Electron apps follow the same general structure as other Node.js projects.
Start by creating a folder and initializing an npm package.
Create a folder for your project and install Electron there:
```sh
```sh npm2yarn
mkdir my-electron-app && cd my-electron-app
npm init -y
npm i --save-dev electron
npm init
```
#### Create the main script file
The interactive `init` command will prompt you to set some fields in your config.
There are a few rules to follow for the purposes of this tutorial:
The main script specifies the entry point of your Electron application (in our case, the `main.js` file) that will run the Main process. Typically, the script that runs in the Main process controls the lifecycle of the application, displays the graphical user interface and its elements, performs native operating system interactions, and creates Renderer processes within web pages. An Electron application can have only one Main process.
* `entry point` should be `main.js`.
* `author` and `description` can be any value, but are necessary for
[app packaging](#package-and-distribute-your-application).
The main script may look as follows:
Your `package.json` file should look something like this:
```javascript fiddle='docs/fiddles/quick-start'
```json
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"author": "Jane Doe",
"license": "MIT"
}
```
Then, install the `electron` package into your app's `devDependencies`.
```sh npm2yarn
$ npm install --save-dev electron
```
> Note: If you're encountering any issues with installing Electron, please
> refer to the [Advanced Installation][advanced-installation] guide.
Finally, you want to be able to execute Electron. In the [`scripts`][package-scripts]
field of your `package.json` config, add a `start` command like so:
```json
{
"scripts": {
"start": "electron ."
}
}
```
This `start` command will let you open your app in development mode.
```sh npm2yarn
npm start
```
> Note: This script tells Electron to run on your project's root folder. At this stage,
> your app will immediately throw an error telling you that it cannot find an app to run.
[advanced-installation]: ./installation.md
[package-scripts]: https://docs.npmjs.com/cli/v7/using-npm/scripts
### Run the main process
The entry point of any Electron application is its `main` script. This script controls the
**main process**, which runs in a full Node.js environment and is responsible for
controlling your app's lifecycle, displaying native interfaces, performing privileged
operations, and managing renderer processes (more on that later).
During execution, Electron will look for this script in the [`main`][package-json-main]
field of the app's `package.json` config, which you should have configured during the
[app scaffolding](#scaffold-the-project) step.
To initialize the `main` script, create an empty file named `main.js` in the root folder
of your project.
> Note: If you run the `start` script again at this point, your app will no longer throw
> any errors! However, it won't do anything yet because we haven't added any code into
> `main.js`.
[package-json-main]: https://docs.npmjs.com/cli/v7/configuring-npm/package-json#main
### Create a web page
Before we can create a window for our application, we need to create the content that
will be loaded into it. In Electron, each window displays web contents that can be loaded
from either from a local HTML file or a remote URL.
For this tutorial, you will be doing the former. Create an `index.html` file in the root
folder of your project:
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
</body>
</html>
```
> Note: Looking at this HTML document, you can observe that the version numbers are
> missing from the body text. We'll manually insert them later using JavaScript.
### Opening your web page in a browser window
Now that you have a web page, load it into an application window. To do so, you'll
need two Electron modules:
* The [`app`][app] module, which controls your application's event lifecycle.
* The [`BrowserWindow`][browser-window] module, which creates and manages application
windows.
Because the main process runs Node.js, you can import these as [CommonJS][commonjs]
modules at the top of your file:
```js
const { app, BrowserWindow } = require('electron')
```
Then, add a `createWindow()` function that loads `index.html` into a new `BrowserWindow`
instance.
```js
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
```
Next, call this `createWindow()` function to open your window.
In Electron, browser windows can only be created after the `app` module's
[`ready`][app-ready] event is fired. You can wait for this event by using the
[`app.whenReady()`][app-when-ready] API. Call `createWindow()` after `whenReady()`
resolves its Promise.
```js
app.whenReady().then(() => {
createWindow()
})
```
> Note: At this point, your Electron application should successfully
> open a window that displays your web page!
[app]: ../api/app.md
[browser-window]: ../api/browser-window.md
[commonjs]: https://nodejs.org/docs/latest/api/modules.html#modules_modules_commonjs_modules
[app-ready]: ../api/app.md#event-ready
[app-when-ready]: ../api/app.md#appwhenready
### Manage your window's lifecycle
Although you can now open a browser window, you'll need some additional boilerplate code
to make it feel more native to each platform. Application windows behave differently on
each OS, and Electron puts the responsibility on developers to implement these
conventions in their app.
In general, you can use the `process` global's [`platform`][node-platform] attribute
to run code specifically for certain operating systems.
#### Quit the app when all windows are closed (Windows & Linux)
On Windows and Linux, exiting all windows generally quits an application entirely.
To implement this, listen for the `app` module's [`'window-all-closed'`][window-all-closed]
event, and call [`app.quit()`][app-quit] if the user is not on macOS (`darwin`).
```js
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
```
[node-platform]: https://nodejs.org/api/process.html#process_process_platform
[window-all-closed]: ../api/app.md#event-window-all-closed
[window-all-closed]: ../api/app.md#appquit
#### Open a window if none are open (macOS)
Whereas Linux and Windows apps quit when they have no windows open, macOS apps generally
continue running even without any windows open, and activating the app when no windows
are available should open a new one.
To implement this feature, listen for the `app` module's [`activate`][activate]
event, and call your existing `createWindow()` method if no browser windows are open.
Because windows cannot be created before the `ready` event, you should only listen for
`activate` events after your app is initialized. Do this by attaching your event listener
from within your existing `whenReady()` callback.
[activate]: ../api/app.md#event-activate-macos
```js
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
```
> Note: At this point, your window controls should be fully functional!
### Access Node.js from the renderer with a preload script
Now, the last thing to do is print out the version numbers for Electron and its
dependencies onto your web page.
Accessing this information is trivial to do in the main process through Node's
global `process` object. However, you can't just edit the DOM from the main
process because it has no access to the renderer's `document` context.
They're in entirely different processes!
> Note: If you need a more in-depth look at Electron processes, see the
> [Process Model][] document.
This is where attaching a **preload** script to your renderer comes in handy.
A preload script runs before the renderer process is loaded, and has access to both
renderer globals (e.g. `window` and `document`) and a Node.js environment.
Create a new script named `preload.js` as such:
```js
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const dependency of ['chrome', 'node', 'electron']) {
replaceText(`${dependency}-version`, process.versions[dependency])
}
})
```
The above code accesses the Node.js `process.versions` object and runs a basic `replaceText`
helper function to insert the version numbers into the HTML document.
To attach this script to your renderer process, pass in the path to your preload script
to the `webPreferences.preload` option in your existing `BrowserWindow` constructor.
```js
// include the Node.js 'path' module at the top of your file
const path = require('path')
// modify your existing createWindow() function
function createWindow () {
const win = new BrowserWindow({
width: 800,
@@ -69,133 +306,164 @@ function createWindow () {
win.loadFile('index.html')
}
// ...
```
There are two Node.js concepts that are used here:
* The [`__dirname`][dirname] string points to the path of the currently executing script
(in this case, your project's root folder).
* The [`path.join`][path-join] API joins multiple path segments together, creating a
combined path string that works across all platforms.
We use a path relative to the currently executing JavaScript file so that your relative
path will work in both development and packaged mode.
[Process Model]: ./process-model.md
[dirname]: https://nodejs.org/api/modules.html#modules_dirname
[path-join]: https://nodejs.org/api/path.html#path_path_join_paths
### Bonus: Add functionality to your web contents
At this point, you might be wondering how to add more functionality to your application.
For any interactions with your web contents, you want to add scripts to your
renderer process. Because the renderer runs in a normal web environment, you can add a
`<script>` tag right before your `index.html` file's closing `</body>` tag to include
any arbitrary scripts you want:
```html
<script src="./renderer.js"></script>
```
The code contained in `renderer.js` can then use the same JavaScript APIs and tooling
you use for typical front-end development, such as using [`webpack`][webpack] to bundle
and minify your code or [React][react] to manage your user interfaces.
[webpack]: https://webpack.js.org
[react]: https://reactjs.org
### Recap
After following the above steps, you should have a fully functional
Electron application that looks like this:
![Simplest Electron app](../images/simplest-electron-app.png)
<!--TODO(erickzhao): Remove the individual code blocks for static website -->
The full code is available below:
```js
// main.js
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
const path = require('path')
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
// 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()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
// 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.
```
##### What is going on above?
```js
// preload.js
1. Line 1: First, you import the `app` and `BrowserWindow` modules of the `electron` package to be able to manage your application's lifecycle events, as well as create and control browser windows.
2. Line 2: Second, you import the `path` package which provides utility functions for file paths.
3. Line 4: After that, you define a function that creates a [new browser window](../api/browser-window.md#new-browserwindowoptions) with a preload script, loads `index.html` file into this window (line 13, we will discuss the file later).
4. Line 16: You create a new browser window by invoking the `createWindow` function once the Electron application [is initialized](../api/app.md#appwhenready).
5. Line 18: You add a new listener that creates a new browser window only if when the application has no visible windows after being activated. For example, after launching the application for the first time, or re-launching the already running application.
6. Line 25: You add a new listener that tries to quit the application when it no longer has any open windows. This listener is a no-op on macOS due to the operating system's [window management behavior](https://support.apple.com/en-ca/guide/mac-help/mchlp2469/mac).
#### Create a web page
This is the web page you want to display once the application is initialized. This web page represents the Renderer process. You can create multiple browser windows, where each window uses its own independent Renderer. You can optionally grant access to additional Node.js APIs by exposing them from your preload script.
The `index.html` page looks as follows:
```html fiddle='docs/fiddles/quick-start'
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body style="background: white;">
<h1>Hello World!</h1>
<p>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
</p>
</body>
</html>
```
#### Define a preload script
Your preload script (in our case, the `preload.js` file) acts as a bridge between Node.js and your web page. It allows you to expose specific APIs and behaviors to your web page rather than insecurely exposing the entire Node.js API. In this example we will use the preload script to read version information from the `process` object and update the web page with that info.
```javascript fiddle='docs/fiddles/quick-start'
// All of the Node.js APIs are available in the preload process.
// It has the same sandbox as a Chrome extension.
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const type of ['chrome', 'node', 'electron']) {
replaceText(`${type}-version`, process.versions[type])
for (const dependency of ['chrome', 'node', 'electron']) {
replaceText(`${dependency}-version`, process.versions[dependency])
}
})
```
##### What's going on above?
```html
<!--index.html-->
1. On line 1: First you define an event listener that tells you when the web page has loaded
2. On line 2: Second you define a utility function used to set the text of the placeholders in the `index.html`
3. On line 7: Next you loop through the list of components whose version you want to display
4. On line 8: Finally, you call `replaceText` to look up the version placeholders in `index.html` and set their text value to the values from `process.versions`
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
#### Modify your package.json file
Your Electron application uses the `package.json` file as the main entry point (as any other Node.js application). The main script of your application is `main.js`, so modify the `package.json` file accordingly:
```json
{
"name": "my-electron-app",
"version": "0.1.0",
"author": "your name",
"description": "My Electron app",
"main": "main.js"
}
<!-- You can also require other files to run in this process -->
<script src="./renderer.js"></script>
</body>
</html>
```
> NOTE: If the `main` field is omitted, Electron will attempt to load an `index.js` file from the directory containing `package.json`.
> NOTE: The `author` and `description` fields are required for packaging, otherwise error will occur when running `npm run make`.
By default, the `npm start` command will run the main script with Node.js. To run the script with Electron, you need to change it as such:
```json
{
"name": "my-electron-app",
"version": "0.1.0",
"author": "your name",
"description": "My Electron app",
"main": "main.js",
"scripts": {
"start": "electron ."
}
}
```fiddle docs/fiddles/quick-start
```
#### Run your application
To summarize all the steps we've done:
```sh
npm start
```
* We bootstrapped a Node.js application and added Electron as a dependency.
* We created a `main.js` script that runs our main process, which controls our app
and runs in a Node.js environment. In this script, we used Electron's `app` and
`BrowserWindow` modules to create a browser window that displays web content
in a separate process (the renderer).
* In order to access certain Node.js functionality in the renderer, we attached
a preload script to our `BrowserWindow` constructor.
Your running Electron app should look as follows:
## Package and distribute your application
![Simplest Electron app](../images/simplest-electron-app.png)
### Package and distribute the application
The simplest and the fastest way to distribute your newly created app is using
The fastest way to distribute your newly created app is using
[Electron Forge](https://www.electronforge.io).
1. Import Electron Forge to your app folder:
1. Add Electron Forge as a development dependency of your app, and use its `import` command to set up
Forge's scaffolding:
```sh
```sh npm2yarn
npm install --save-dev @electron-forge/cli
npx electron-forge import
@@ -211,12 +479,12 @@ The simplest and the fastest way to distribute your newly created app is using
Thanks for using "electron-forge"!!!
```
1. Create a distributable:
1. Create a distributable using Forge's `make` command:
```sh
```sh npm2yarn
npm run make
> my-gsod-electron-app@1.0.0 make /my-electron-app
> my-electron-app@1.0.0 make /my-electron-app
> electron-forge make
✔ Checking your system
@@ -229,109 +497,12 @@ The simplest and the fastest way to distribute your newly created app is using
✔ Making for target: zip - On platform: darwin - For arch: x64
```
Electron-forge creates the `out` folder where your package will be located:
Electron Forge creates the `out` folder where your package will be located:
```plain
// Example for MacOS
// Example for macOS
out/
├── out/make/zip/darwin/x64/my-electron-app-darwin-x64-1.0.0.zip
├── ...
└── out/my-electron-app-darwin-x64/my-electron-app.app/Contents/MacOS/my-electron-app
```
[node-download]: https://nodejs.org/en/download/
## Learning the basics
This section guides you through the basics of how Electron works under the hood. It aims at strengthening knowledge about Electron and the application created earlier in the Quickstart section.
### Application architecture
Electron consists of three main pillars:
* **Chromium** for displaying web content.
* **Node.js** for working with the local filesystem and the operating system.
* **Custom APIs** for working with often-needed OS native functions.
Developing an application with Electron is like building a Node.js app with a web interface or building web pages with seamless Node.js integration.
#### Main and Renderer Processes
As it was mentioned before, Electron has two types of processes: Main and Renderer.
* The Main process **creates** web pages by creating `BrowserWindow` instances. Each `BrowserWindow` instance runs the web page in its Renderer process. When a `BrowserWindow` instance is destroyed, the corresponding Renderer process gets terminated as well.
* The Main process **manages** all web pages and their corresponding Renderer processes.
----
* The Renderer process **manages** only the corresponding web page. A crash in one Renderer process does not affect other Renderer processes.
* The Renderer process **communicates** with the Main process via IPC to perform GUI operations in a web page. Calling native GUI-related APIs from the Renderer process directly is restricted due to security concerns and potential resource leakage.
----
The communication between processes is possible via Inter-Process Communication (IPC) modules: [`ipcMain`](../api/ipc-main.md) and [`ipcRenderer`](../api/ipc-renderer.md).
#### APIs
##### Electron API
Electron APIs are assigned based on the process type, meaning that some modules can be used from either the Main or Renderer process, and some from both. Electron's API documentation indicates which process each module can be used from.
For example, to access the Electron API in both processes, require its included module:
```js
const electron = require('electron')
```
To create a window, call the `BrowserWindow` class, which is only available in the Main process:
```js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
```
To call the Main process from the Renderer, use the IPC module:
```js
// In the Main process
const { ipcMain } = require('electron')
ipcMain.handle('perform-action', (event, ...args) => {
// ... do actions on behalf of the Renderer
})
```
```js
// In the Renderer process
const { ipcRenderer } = require('electron')
ipcRenderer.invoke('perform-action', ...args)
```
> NOTE: Because Renderer processes may run untrusted code (especially from third parties), it is important to carefully validate the requests that come to the Main process.
##### Node.js API
> NOTE: To access the Node.js API from the Renderer process, you need to set the `nodeIntegration` preference to `true` and the `contextIsolation` preference to `false`. Please note that access to the Node.js API in any renderer that loads remote content is not recommended for [security reasons](../tutorial/security.md#2-do-not-enable-nodejs-integration-for-remote-content).
Electron exposes full access to Node.js API and its modules both in the Main and the Renderer processes. For example, you can read all the files from the root directory:
```js
const fs = require('fs')
const root = fs.readdirSync('/')
console.log(root)
```
To use a Node.js module, you first need to install it as a dependency:
```sh
npm install --save aws-sdk
```
Then, in your Electron application, require the module:
```js
const S3 = require('aws-sdk/clients/s3')
```

View File

@@ -13,39 +13,62 @@ __Application dock menu:__
![macOS Dock Menu][dock-menu-image]
To add a file to recent documents, you need to use the
[app.addRecentDocument][addrecentdocument] API.
## Example
### Add an item to recent documents
Starting with a working application from the
[Quick Start Guide](quick-start.md), add the following lines to the
`main.js` file:
### Managing recent documents
```javascript fiddle='docs/fiddles/features/recent-documents'
const { app } = require('electron')
const { app, BrowserWindow } = require('electron')
const fs = require('fs')
const path = require('path')
app.addRecentDocument('/Users/USERNAME/Desktop/work.type')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
const fileName = 'recently-used.md'
fs.writeFile(fileName, 'Lorem Ipsum', () => {
app.addRecentDocument(path.join(__dirname, fileName))
})
app.whenReady().then(createWindow)
app.on('window-all-closed', () => {
app.clearRecentDocuments()
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
```
#### Adding a recent document
To add a file to recent documents, use the
[app.addRecentDocument][addrecentdocument] API.
After launching the Electron application, right click the application icon.
You should see the item you just added. In this guide, the item is a Markdown
file located in the root of the project:
In this guide, the item is a Markdown file located in the root of the project.
You should see `recently-used.md` added to the list of recent files:
![Recent document](../images/recent-documents.png)
### Clear the list of recent documents
#### Clearing the list of recent documents
To clear the list of recent documents, you need to use
[app.clearRecentDocuments][clearrecentdocuments] API in the `main.js` file:
```javascript
const { app } = require('electron')
app.clearRecentDocuments()
```
To clear the list of recent documents, use the
[app.clearRecentDocuments][clearrecentdocuments] API.
In this guide, the list of documents is cleared once all windows have been
closed.
## Additional information
@@ -83,6 +106,22 @@ following code snippet to your menu template:
}
```
Make sure the application menu is added after the [`'ready'`](../api/app.md#event-ready)
event and not before, or the menu item will be disabled:
```javascript
const { app, Menu } = require('electron')
const template = [
// Menu template here
]
const menu = Menu.buildFromTemplate(template)
app.whenReady().then(() => {
Menu.setApplicationMenu(menu)
})
```
![macOS Recent Documents menu item][menu-item-image]
When a file is requested from the recent documents menu, the `open-file` event

View File

@@ -1,27 +1,23 @@
# REPL
Read-Eval-Print-Loop (REPL) is a simple, interactive computer programming
environment that takes single user inputs (i.e. single expressions), evaluates
them, and returns the result to the user.
[Read-Eval-Print-Loop](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) (REPL)
is a simple, interactive computer programming environment that takes single user
inputs (i.e. single expressions), evaluates them, and returns the result to the user.
The `repl` module provides a REPL implementation that can be accessed using:
## Main process
* Assuming you have `electron` or `electron-prebuilt` installed as a local
project dependency:
Electron exposes the [Node.js `repl` module](https://nodejs.org/dist/latest/docs/api/repl.html)
through the `--interactive` CLI flag. Assuming you have `electron` installed as a local project
dependency, you should be able to access the REPL with the following command:
```sh
./node_modules/.bin/electron --interactive
```
* Assuming you have `electron` or `electron-prebuilt` installed globally:
**Note:** `electron --interactive` is not available on Windows
(see [electron/electron#5776](https://github.com/electron/electron/pull/5776) for more details).
```sh
electron --interactive
```
## Renderer process
This only creates a REPL for the main process. You can use the Console
tab of the Dev Tools to get a REPL for the renderer processes.
**Note:** `electron --interactive` is not available on Windows.
More information can be found in the [Node.js REPL docs](https://nodejs.org/dist/latest/docs/api/repl.html).
You can use the DevTools Console tab to get a REPL for any renderer process.
To learn more, read [the Chrome documentation](https://developer.chrome.com/docs/devtools/console/).

View File

@@ -20,23 +20,40 @@ To set the represented file of window, you can use the
## Example
Starting with a working application from the
[Quick Start Guide](quick-start.md), add the following lines to the
`main.js` file:
```javascript fiddle='docs/fiddles/features/represented-file'
const { app, BrowserWindow } = require('electron')
const os = require('os');
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600
})
}
app.whenReady().then(() => {
const win = new BrowserWindow()
win.setRepresentedFilename('/etc/passwd')
win.setRepresentedFilename(os.homedir())
win.setDocumentEdited(true)
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
```
After launching the Electron application, click on the title with `Command` or
`Control` key pressed. You should see a popup with the file you just defined:
`Control` key pressed. You should see a popup with the represented file at the top.
In this guide, this is the current user's home directory:
![Represented file](../images/represented-file.png)

169
docs/tutorial/sandbox.md Normal file
View File

@@ -0,0 +1,169 @@
# Process Sandboxing
One key security feature in Chromium is that processes can be executed within a sandbox.
The sandbox limits the harm that malicious code can cause by limiting access to most
system resources — sandboxed processes can only freely use CPU cycles and memory.
In order to perform operations requiring additional privilege, sandboxed processes
use dedicated communication channels to delegate tasks to more privileged processes.
In Chromium, sandboxing is applied to most processes other than the main process.
This includes renderer processes, as well as utility processes such as the audio service,
the GPU service and the network service.
See Chromium's [Sandbox design document][sandbox] for more information.
## Electron's sandboxing policies
Electron comes with a mixed sandbox environment, meaning sandboxed processes can run
alongside privileged ones. By default, renderer processes are not sandboxed, but
utility processes are. Note that as in Chromium, the main (browser) process is
privileged and cannot be sandboxed.
Historically, this mixed sandbox approach was established because having Node.js available
in the renderer is an extremely powerful tool for app developers. Unfortunately, this
feature is also an equally massive security vulnerability.
Theoretically, unsandboxed renderers are not a problem for desktop applications that
only display trusted code, but they make Electron less secure than Chromium for
displaying untrusted web content. However, even purportedly trusted code may be
dangerous — there are countless attack vectors that malicious actors can use, from
cross-site scripting to content injection to man-in-the-middle attacks on remotely loaded
websites, just to name a few. For this reason, we recommend enabling renderer sandboxing
for the vast majority of cases under an abundance of caution.
<!--TODO: update this guide when #28466 is either solved or closed -->
Note that there is an active discussion in the issue tracker to enable renderer sandboxing
by default. See [#28466][issue-28466]) for details.
## Sandbox behaviour in Electron
Sandboxed processes in Electron behave _mostly_ in the same way as Chromium's do, but
Electron has a few additional concepts to consider because it interfaces with Node.js.
### Renderer processes
When renderer processes in Electron are sandboxed, they behave in the same way as a
regular Chrome renderer would. A sandboxed renderer won't have a Node.js
environment initialized.
<!-- TODO(erickzhao): when we have a solid guide for IPC, link it here -->
Therefore, when the sandbox is enabled, renderer processes can only perform privileged
tasks (such as interacting with the filesystem, making changes to the system, or spawning
subprocesses) by delegating these tasks to the main process via inter-process
communication (IPC).
### Preload scripts
In order to allow renderer processes to communicate with the main process, preload
scripts attached to sandboxed renderers will still have a polyfilled subset of Node.js
APIs available. A `require` function similar to Node's `require` module is exposed,
but can only import a subset of Electron and Node's built-in modules:
* `electron` (only renderer process modules)
* [`events`](https://nodejs.org/api/events.html)
* [`timers`](https://nodejs.org/api/timers.html)
* [`url`](https://nodejs.org/api/url.html)
In addition, the preload script also polyfills certain Node.js primitives as globals:
* [`Buffer`](https://nodejs.org/api/Buffer.html)
* [`process`](../api/process.md)
* [`clearImmediate`](https://nodejs.org/api/timers.html#timers_clearimmediate_immediate)
* [`setImmediate`](https://nodejs.org/api/timers.html#timers_setimmediate_callback_args)
Because the `require` function is a polyfill with limited functionality, you will not be
able to use [CommonJS modules][commonjs] to separate your preload script into multiple
files. If you need to split your preload code, use a bundler such as [webpack][webpack]
or [Parcel][parcel].
Note that because the environment presented to the `preload` script is substantially
more privileged than that of a sandboxed renderer, it is still possible to leak
privileged APIs to untrusted code running in the renderer process unless
[`contextIsolation`][contextIsolation] is enabled.
## Configuring the sandbox
### Enabling the sandbox for a single process
In Electron, renderer sandboxing can be enabled on a per-process basis with
the `sandbox: true` preference in the [`BrowserWindow`][browser-window] constructor.
```js
// main.js
app.whenReady().then(() => {
const win = new BrowserWindow({
webPreferences: {
sandbox: true
}
})
win.loadURL('https://google.com')
})
```
### Enabling the sandbox globally
If you want to force sandboxing for all renderers, you can also use the
[`app.enableSandbox`][enable-sandbox] API. Note that this API has to be called before the
app's `ready` event.
```js
// main.js
app.enableSandbox()
app.whenReady().then(() => {
// no need to pass `sandbox: true` since `app.enableSandbox()` was called.
const win = new BrowserWindow()
win.loadURL('https://google.com')
})
```
### Disabling Chromium's sandbox (testing only)
You can also disable Chromium's sandbox entirely with the [`--no-sandbox`][no-sandbox]
CLI flag, which will disable the sandbox for all processes (including utility processes).
We highly recommend that you only use this flag for testing purposes, and **never**
in production.
Note that the `sandbox: true` option will still disable the renderer's Node.js
environment.
## A note on rendering untrusted content
Rendering untrusted content in Electron is still somewhat uncharted territory,
though some apps are finding success (e.g. [Beaker Browser][beaker]).
Our goal is to get as close to Chrome as we can in terms of the security of
sandboxed content, but ultimately we will always be behind due to a few fundamental
issues:
1. We do not have the dedicated resources or expertise that Chromium has to
apply to the security of its product. We do our best to make use of what we
have, to inherit everything we can from Chromium, and to respond quickly to
security issues, but Electron cannot be as secure as Chromium without the
resources that Chromium is able to dedicate.
2. Some security features in Chrome (such as Safe Browsing and Certificate
Transparency) require a centralized authority and dedicated servers, both of
which run counter to the goals of the Electron project. As such, we disable
those features in Electron, at the cost of the associated security they
would otherwise bring.
3. There is only one Chromium, whereas there are many thousands of apps built
on Electron, all of which behave slightly differently. Accounting for those
differences can yield a huge possibility space, and make it challenging to
ensure the security of the platform in unusual use cases.
4. We can't push security updates to users directly, so we rely on app vendors
to upgrade the version of Electron underlying their app in order for
security updates to reach users.
While we make our best effort to backport Chromium security fixes to older
versions of Electron, we do not make a guarantee that every fix will be
backported. Your best chance at staying secure is to be on the latest stable
version of Electron.
[sandbox]: https://chromium.googlesource.com/chromium/src/+/master/docs/design/sandbox.md
[issue-28466]: https://github.com/electron/electron/issues/28466
[browser-window]: ../api/browser-window.md
[enable-sandbox]: ../api/app.md#appenablesandbox
[no-sandbox]: ../api/command-line-switches.md#--no-sandbox
[commonjs]: https://nodejs.org/api/modules.html#modules_modules_commonjs_modules
[webpack]: https://webpack.js.org/
[parcel]: https://parceljs.org/
[context-isolation]: ./context-isolation.md
[beaker]: https://github.com/beakerbrowser/beaker

View File

@@ -692,5 +692,5 @@ which potential security issues are not as widely known.
[window-open-handler]: ../api/web-contents.md#contentssetwindowopenhandlerhandler
[will-navigate]: ../api/web-contents.md#event-will-navigate
[open-external]: ../api/shell.md#shellopenexternalurl-options
[sandbox]: ../api/sandbox-option.md
[sandbox]: ../tutorial/sandbox.md
[responsible-disclosure]: https://en.wikipedia.org/wiki/Responsible_disclosure

View File

@@ -43,7 +43,6 @@ auto_filenames = {
"docs/api/process.md",
"docs/api/protocol.md",
"docs/api/remote.md",
"docs/api/sandbox-option.md",
"docs/api/screen.md",
"docs/api/service-workers.md",
"docs/api/session.md",

View File

@@ -490,63 +490,83 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
}
};
function fsReadFileAsar (pathArgument: string, options: any, callback: any) {
const pathInfo = splitPath(pathArgument);
if (pathInfo.isAsar) {
const { asarPath, filePath } = pathInfo;
if (typeof options === 'function') {
callback = options;
options = { encoding: null };
} else if (typeof options === 'string') {
options = { encoding: options };
} else if (options === null || options === undefined) {
options = { encoding: null };
} else if (typeof options !== 'object') {
throw new TypeError('Bad arguments');
}
const { encoding } = options;
const archive = getOrCreateArchive(asarPath);
if (!archive) {
const error = createError(AsarError.INVALID_ARCHIVE, { asarPath });
nextTick(callback, [error]);
return;
}
const info = archive.getFileInfo(filePath);
if (!info) {
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
nextTick(callback, [error]);
return;
}
if (info.size === 0) {
nextTick(callback, [null, encoding ? '' : Buffer.alloc(0)]);
return;
}
if (info.unpacked) {
const realPath = archive.copyFileOut(filePath);
return fs.readFile(realPath, options, callback);
}
const buffer = Buffer.alloc(info.size);
const fd = archive.getFd();
if (!(fd >= 0)) {
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
nextTick(callback, [error]);
return;
}
logASARAccess(asarPath, filePath, info.offset);
fs.read(fd, buffer, 0, info.size, info.offset, (error: Error) => {
callback(error, encoding ? buffer.toString(encoding) : buffer);
});
}
}
const { readFile } = fs;
fs.readFile = function (pathArgument: string, options: any, callback: any) {
const pathInfo = splitPath(pathArgument);
if (!pathInfo.isAsar) return readFile.apply(this, arguments);
const { asarPath, filePath } = pathInfo;
if (typeof options === 'function') {
callback = options;
options = { encoding: null };
} else if (typeof options === 'string') {
options = { encoding: options };
} else if (options === null || options === undefined) {
options = { encoding: null };
} else if (typeof options !== 'object') {
throw new TypeError('Bad arguments');
if (!pathInfo.isAsar) {
return readFile.apply(this, arguments);
}
const { encoding } = options;
const archive = getOrCreateArchive(asarPath);
if (!archive) {
const error = createError(AsarError.INVALID_ARCHIVE, { asarPath });
nextTick(callback, [error]);
return;
}
const info = archive.getFileInfo(filePath);
if (!info) {
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
nextTick(callback, [error]);
return;
}
if (info.size === 0) {
nextTick(callback, [null, encoding ? '' : Buffer.alloc(0)]);
return;
}
if (info.unpacked) {
const realPath = archive.copyFileOut(filePath);
return fs.readFile(realPath, options, callback);
}
const buffer = Buffer.alloc(info.size);
const fd = archive.getFd();
if (!(fd >= 0)) {
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
nextTick(callback, [error]);
return;
}
logASARAccess(asarPath, filePath, info.offset);
fs.read(fd, buffer, 0, info.size, info.offset, (error: Error) => {
callback(error, encoding ? buffer.toString(encoding) : buffer);
});
return fsReadFileAsar(pathArgument, options, callback);
};
fs.promises.readFile = util.promisify(fs.readFile);
const { readFile: readFilePromise } = fs.promises;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fs.promises.readFile = function (pathArgument: string, options: any) {
const pathInfo = splitPath(pathArgument);
if (!pathInfo.isAsar) {
return readFilePromise.apply(this, arguments);
}
const p = util.promisify(fsReadFileAsar);
return p(pathArgument, options);
};
const { readFileSync } = fs;
fs.readFileSync = function (pathArgument: string, options: any) {

View File

@@ -20,20 +20,6 @@ BrowserWindow.prototype._init = function (this: BWT) {
nativeSetBounds.call(this, bounds, ...opts);
};
// Sometimes the webContents doesn't get focus when window is shown, so we
// have to force focusing on webContents in this case. The safest way is to
// focus it when we first start to load URL, if we do it earlier it won't
// have effect, if we do it later we might move focus in the page.
//
// 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.
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) => {
app.emit('browser-window-blur', event, this);

View File

@@ -2,10 +2,10 @@ import { app, BrowserWindow } from 'electron/main';
import type { OpenDialogOptions, OpenDialogReturnValue, MessageBoxOptions, SaveDialogOptions, SaveDialogReturnValue, MessageBoxReturnValue, CertificateTrustDialogOptions } from 'electron/main';
const dialogBinding = process._linkedBinding('electron_browser_dialog');
const DialogType = {
OPEN: 'OPEN' as 'OPEN',
SAVE: 'SAVE' as 'SAVE'
};
enum DialogType {
OPEN = 'OPEN',
SAVE = 'SAVE'
}
enum SaveFileDialogProperties {
createDirectory = 1 << 0,
@@ -72,7 +72,7 @@ const setupSaveDialogProperties = (properties: (keyof typeof SaveFileDialogPrope
return dialogProperties;
};
const setupDialogProperties = (type: keyof typeof DialogType, properties: string[]): number => {
const setupDialogProperties = (type: DialogType, properties: string[]): number => {
if (type === DialogType.OPEN) {
return setupOpenDialogProperties(properties as (keyof typeof OpenFileDialogProperties)[]);
} else if (type === DialogType.SAVE) {

View File

@@ -177,7 +177,7 @@ Menu.setApplicationMenu = function (menu: MenuType) {
bindings.setApplicationMenu(menu);
} else {
const windows = BaseWindow.getAllWindows();
return windows.map(w => w.setMenu(menu));
windows.map(w => w.setMenu(menu));
}
};

View File

@@ -71,7 +71,7 @@ const PDFPageSizes: Record<string, MediaSize> = {
width_microns: 279400,
custom_display_name: 'Tabloid'
}
};
} as const;
// The minimum micron size Chromium accepts is that where:
// Per printing/units.h:
@@ -120,7 +120,7 @@ const defaultPrintingSetting = {
printerType: 2,
title: undefined as string | undefined,
url: undefined as string | undefined
};
} as const;
// JavaScript implementations of WebContents.
const binding = process._linkedBinding('electron_browser_web_contents');
@@ -202,7 +202,7 @@ WebContents.prototype.executeJavaScriptInIsolatedWorld = async function (worldId
let pendingPromise: Promise<any> | undefined;
WebContents.prototype.printToPDF = async function (options) {
const printSettings = {
const printSettings: Record<string, any> = {
...defaultPrintingSetting,
requestID: getNextId()
};

View File

@@ -75,6 +75,7 @@ ipcMainInternal.on(
const browserWindowOptions = (event.sender as any)._callWindowOpenHandler(event, url, frameName, features);
if (event.defaultPrevented) {
event.returnValue = null;
return;
}
const guest = openGuestWindow({

View File

@@ -1,4 +1,4 @@
export const webViewEvents: Record<string, string[]> = {
export const webViewEvents: Record<string, readonly string[]> = {
'load-commit': ['url', 'isMainFrame'],
'did-attach': [],
'did-finish-load': [],
@@ -33,4 +33,4 @@ export const webViewEvents: Record<string, string[]> = {
'found-in-page': ['result'],
'did-change-theme-color': ['themeColor'],
'update-target-url': ['url']
};
} as const;

View File

@@ -271,7 +271,7 @@ const warnAboutAllowedPopups = function () {
const warnAboutRemoteModuleWithRemoteContent = function (webPreferences?: Electron.WebPreferences) {
if (!webPreferences || isLocalhost()) return;
const remoteModuleEnabled = webPreferences.enableRemoteModule != null ? !!webPreferences.enableRemoteModule : true;
const remoteModuleEnabled = webPreferences.enableRemoteModule != null ? !!webPreferences.enableRemoteModule : false;
if (!remoteModuleEnabled) return;
if (getIsRemoteProtocol()) {
@@ -298,7 +298,9 @@ const logSecurityWarnings = function (
warnAboutEnableBlinkFeatures(webPreferences);
warnAboutInsecureCSP();
warnAboutAllowedPopups();
warnAboutRemoteModuleWithRemoteContent(webPreferences);
if (BUILDFLAG(ENABLE_REMOTE_MODULE)) {
warnAboutRemoteModuleWithRemoteContent(webPreferences);
}
};
const getWebPreferences = async function () {

View File

@@ -8,7 +8,7 @@ import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
const DEPRECATED_EVENTS: Record<string, string> = {
'page-title-updated': 'page-title-set'
};
} as const;
const dispatchEvent = function (
webView: WebViewImpl, eventName: string, eventKey: string, ...args: Array<any>

View File

@@ -162,7 +162,7 @@ export class WebViewImpl {
// Emits focus/blur events.
onFocusChange () {
const hasFocus = document.activeElement === this.webviewNode;
const hasFocus = this.webviewNode.ownerDocument.activeElement === this.webviewNode;
if (hasFocus !== this.hasFocus) {
this.hasFocus = hasFocus;
this.dispatchEvent(hasFocus ? 'focus' : 'blur');

View File

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

View File

@@ -1 +1,2 @@
d3d11_skip_blits_if_there_is_no_intersection_of_dest_areas.patch
cherry-pick-3d4f87ab5b9b.patch

View File

@@ -0,0 +1,59 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jamie Madill <jmadill@chromium.org>
Date: Thu, 20 May 2021 12:22:46 -0400
Subject: D3D11: Fix respecifying 3D textures.
The missing check for the "Depth" dimension could lead to a bug
where we would not recreate a texture when the dimension changed.
Bug: chromium:1210414
Change-Id: Id59097ad14ae77ff80d27081f61786dad17a77ea
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2911032
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
(cherry picked from commit 2697358464cf20576701987f60300b6c4086c11e)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2937026
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/d3d11/Image11.cpp b/src/libANGLE/renderer/d3d/d3d11/Image11.cpp
index c502d00fac032ea708015bbbf4f51db2dc2b3c59..daa5c3abc3ab4f4460ec48d0aba9649cf66897ac 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Image11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Image11.cpp
@@ -223,8 +223,8 @@ bool Image11::redefine(gl::TextureType type,
const gl::Extents &size,
bool forceRelease)
{
- if (mWidth != size.width || mHeight != size.height || mInternalFormat != internalformat ||
- forceRelease)
+ if (mWidth != size.width || mHeight != size.height || mDepth != size.depth ||
+ mInternalFormat != internalformat || forceRelease)
{
// End the association with the TextureStorage, since that data will be out of date.
// Also reset mRecoveredFromStorageCount since this Image is getting completely redefined.
diff --git a/src/tests/gl_tests/MipmapTest.cpp b/src/tests/gl_tests/MipmapTest.cpp
index b335d4901ef11b27e57d0ee6445b15ce5e7567fe..4b6046d4f8d3da97d70a837422c2ddd8d7599fc6 100644
--- a/src/tests/gl_tests/MipmapTest.cpp
+++ b/src/tests/gl_tests/MipmapTest.cpp
@@ -2044,6 +2044,22 @@ void main()
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::green);
}
+// Tests respecifying 3D mipmaps.
+TEST_P(MipmapTestES3, Generate3DMipmapRespecification)
+{
+ std::vector<GLColor> pixels(256 * 256 * 100, GLColor::black);
+
+ GLTexture texture;
+ glBindTexture(GL_TEXTURE_3D, texture);
+ glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 256, 256, 100, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixels.data());
+ glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA, 128, 128, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixels.data());
+ glGenerateMipmap(GL_TEXTURE_3D);
+
+ ASSERT_GL_NO_ERROR();
+}
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(MipmapTest);

View File

@@ -120,3 +120,19 @@ cherry-pick-e4abe032f3ad.patch
add_crashkeys_to_identify_where_target_is_assigned_to_a_stale_value.patch
add_weak_pointer_to_rwhier_framesinkidownermap_and_rwhier_targetmap.patch
add_null_pointer_check_in_renderwidgethostinputeventrouter.patch
cherry-pick-8089dbfc616f.patch
replace_std_vector_with_base_observerlist_to_support_container.patch
guard_webcontents_downloadimage_against_malformed_renderer.patch
fileapi_terminate_filereaderloader_before_dispatching_onabort_event.patch
notifications_crash_if_improper_action_icons_sent_from_renderer.patch
reland_views_handle_deletion_when_toggling_fullscreen.patch
media_feeds_disable_media_feeds_and_related_features.patch
remove_tabs_and_line_breaks_from_the_middle_of_app_names_when.patch
autofill_fixed_refill_of_changed_form.patch
x11_fix_window_enumeration_order_when_wm_doesn_t_set.patch
cherry-pick-34d5af37f9ac.patch
m90-lts_longtaskdetector_remove_container_mutation_during.patch
m90-lts_reduce_memory_consumption_on.patch
cherry-pick-b77b38a3380c.patch
cherry-pick-910e9e40d376.patch
cherry-pick-d9556a80a790.patch

View File

@@ -1,16 +1,16 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Cheng Zhao <zcbenz@gmail.com>
Date: Thu, 4 Oct 2018 14:57:02 -0700
Subject: accelerator.patch
Subject: fix: improve shortcut text of Accelerator
This patch makes three changes to Accelerator::GetShortcutText to improve shortcut display text in menus:
1. Ctrl-Alt-<Key> accelerators show as Ctrl-Alt-<Key> instead of as Ctrl-<Key>
2. F2-F24 accelerators show up as such
3. Ctrl-Shift-= should show as Ctrl-+
3. Ctrl-Shift-= and Ctrl-Plus show up as such
diff --git a/ui/base/accelerators/accelerator.cc b/ui/base/accelerators/accelerator.cc
index 17e1739c12ee38864e735130792321adadb43f08..7b0bfec6f18e883eb7ad7e3bfe564163592f584e 100644
index 17e1739c12ee38864e735130792321adadb43f08..df75c885e702e6b92ce0441f1a85ddddb9aa70b6 100644
--- a/ui/base/accelerators/accelerator.cc
+++ b/ui/base/accelerators/accelerator.cc
@@ -12,6 +12,7 @@
@@ -21,61 +21,39 @@ index 17e1739c12ee38864e735130792321adadb43f08..7b0bfec6f18e883eb7ad7e3bfe564163
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
@@ -24,9 +25,7 @@
#include <windows.h>
@@ -206,6 +207,11 @@ base::string16 Accelerator::GetShortcutText() const {
#endif
-#if !defined(OS_WIN) && (defined(USE_AURA) || defined(OS_APPLE))
#include "ui/events/keycodes/keyboard_code_conversion.h"
-#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/base/ui_base_features.h"
@@ -205,7 +204,15 @@ base::string16 Accelerator::GetShortcutText() const {
shortcut = KeyCodeToName();
#endif
+ unsigned int flags = 0;
if (shortcut.empty()) {
+ const uint16_t c = DomCodeToUsLayoutCharacter(
+ UsLayoutKeyboardCodeToDomCode(key_code_), flags);
+ if (c != 0) {
+ shortcut =
+ static_cast<base::string16::value_type>(
+ base::ToUpperASCII(static_cast<base::char16>(c)));
+ }
+ // When a shifted char is explicitly specified, for example Ctrl+Plus,
+ // use the shifted char directly.
+ if (shifted_char) {
+ shortcut += *shifted_char;
+ } else {
#if defined(OS_WIN)
// Our fallback is to try translate the key code to a regular character
// unless it is one of digits (VK_0 to VK_9). Some keyboard
@@ -214,21 +221,14 @@ base::string16 Accelerator::GetShortcutText() const {
// accent' for '0'). For display in the menu (e.g. Ctrl-0 for the
// default zoom level), we leave VK_[0-9] alone without translation.
wchar_t key;
- if (base::IsAsciiDigit(key_code_))
+ if (base::IsAsciiDigit(key_code_)) {
key = static_cast<wchar_t>(key_code_);
- else
- key = LOWORD(::MapVirtualKeyW(key_code_, MAPVK_VK_TO_CHAR));
- // If there is no translation for the given |key_code_| (e.g.
- // VKEY_UNKNOWN), |::MapVirtualKeyW| returns 0.
- if (key != 0)
- shortcut += key;
-#elif defined(USE_AURA) || defined(OS_APPLE) || defined(OS_ANDROID)
- const uint16_t c = DomCodeToUsLayoutCharacter(
- UsLayoutKeyboardCodeToDomCode(key_code_), false);
- if (c != 0)
- shortcut +=
- static_cast<base::string16::value_type>(base::ToUpperASCII(c));
+ shortcut = key;
+ }
@@ -229,6 +235,10 @@ base::string16 Accelerator::GetShortcutText() const {
shortcut +=
static_cast<base::string16::value_type>(base::ToUpperASCII(c));
#endif
+ }
+ if (key_code_ > VKEY_F1 && key_code_ <= VKEY_F24)
+ shortcut = base::UTF8ToUTF16(
+ base::StringPrintf("F%d", key_code_ - VKEY_F1 + 1));
}
#if defined(OS_APPLE)
@@ -411,7 +411,7 @@ base::string16 Accelerator::ApplyLongFormModifiers(
@@ -403,7 +413,7 @@ base::string16 Accelerator::KeyCodeToName() const {
base::string16 Accelerator::ApplyLongFormModifiers(
base::string16 shortcut) const {
- if (IsShiftDown())
+ if (!shifted_char && IsShiftDown())
shortcut = ApplyModifierToAcceleratorString(shortcut, IDS_APP_SHIFT_KEY);
// Note that we use 'else-if' in order to avoid using Ctrl+Alt as a shortcut.
@@ -411,7 +421,7 @@ base::string16 Accelerator::ApplyLongFormModifiers(
// more information.
if (IsCtrlDown())
shortcut = ApplyModifierToAcceleratorString(shortcut, IDS_APP_CTRL_KEY);
@@ -84,3 +62,24 @@ index 17e1739c12ee38864e735130792321adadb43f08..7b0bfec6f18e883eb7ad7e3bfe564163
shortcut = ApplyModifierToAcceleratorString(shortcut, IDS_APP_ALT_KEY);
if (IsCmdDown()) {
diff --git a/ui/base/accelerators/accelerator.h b/ui/base/accelerators/accelerator.h
index 35a9bb01aef4b3fea34caf06f97944405a0212fe..45f07a97c834d6716210aadb1e8f3f83aa08b5e9 100644
--- a/ui/base/accelerators/accelerator.h
+++ b/ui/base/accelerators/accelerator.h
@@ -15,6 +15,7 @@
#include <utility>
#include "base/component_export.h"
+#include "base/optional.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "build/build_config.h"
@@ -100,6 +101,8 @@ class COMPONENT_EXPORT(UI_BASE) Accelerator {
return interrupted_by_mouse_event_;
}
+ base::Optional<base::char16> shifted_char;
+
private:
base::string16 ApplyLongFormModifiers(base::string16 shortcut) const;
base::string16 ApplyShortFormModifiers(base::string16 shortcut) const;

View File

@@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Andrey Belenko <andrey.belenko@gmail.com>
Date: Wed, 19 May 2021 17:20:52 +0200
Subject: Fixed refill of changed form.
(cherry picked from commit 533bb3adcfe3499f90e2646fc60312f303b963ac)
Bug: 1203667
Change-Id: I2693a024531775e0e60cc330107d77d10558f466
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2867655
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2874611
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index 866d4b98a839d73777edafc681af7d809cbfc56b..a49386223c864395768970a44840fa1f462fad24 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -1669,7 +1669,10 @@ void AutofillManager::FillOrPreviewDataModelForm(
form_structure->RationalizePhoneNumbersInSection(autofill_field->section);
FormData result = form;
- DCHECK_EQ(form_structure->field_count(), form.fields.size());
+ // TODO(crbug/1203667#c9): Skip if the form has changed in the meantime, which
+ // may happen with refills.
+ if (form_structure->field_count() != form.fields.size())
+ return;
if (action == AutofillDriver::FORM_DATA_ACTION_FILL && !is_refill) {
SetFillingContext(
@@ -1710,8 +1713,10 @@ void AutofillManager::FillOrPreviewDataModelForm(
continue;
}
- // The field order should be the same in |form_structure| and |result|.
- DCHECK(form_structure->field(i)->SameFieldAs(result.fields[i]));
+ // TODO(crbug/1203667#c9): Skip if the form has changed in the meantime,
+ // which may happen with refills.
+ if (!form_structure->field(i)->SameFieldAs(result.fields[i]))
+ continue;
AutofillField* cached_field = form_structure->field(i);
FieldTypeGroup field_group_type = cached_field->Type().group();

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