diff --git a/.circleci/config.yml b/.circleci/config.yml index 70b70f2946a76..d096f0c263c76 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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. # @@ -69,7 +79,7 @@ parameters: # Build machines configs. docker-image: &docker-image docker: - - image: electron.azurecr.io/build:4cec2c5ab66765caa724e37bae2bffb9b29722a5 + - image: electron.azurecr.io/build:d818f06a9b1540c7fd38f75ad5a2c493dd6843b6 machine-linux-medium: &machine-linux-medium <<: *docker-image @@ -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 " + 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 @@ -308,9 +337,11 @@ step-setup-goma-for-build: &step-setup-goma-for-build npm install mkdir third_party node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })" - node -e "require('./src/utils/goma.js').ensure()" + export GOMA_FALLBACK_ON_AUTH_FAILURE=true + third_party/goma/goma_ctl.py ensure_start echo 'export GN_GOMA_FILE='`node -e "console.log(require('./src/utils/goma.js').gnFilePath)"` >> $BASH_ENV echo 'export LOCAL_GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV + echo 'export GOMA_FALLBACK_ON_AUTH_FAILURE=true' >> $BASH_ENV cd .. step-restore-brew-cache: &step-restore-brew-cache @@ -512,6 +543,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 @@ -666,6 +698,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: @@ -728,7 +761,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: @@ -855,23 +892,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 @@ -1286,8 +1306,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: | @@ -1308,6 +1334,8 @@ steps-tests: &steps-tests - *step-maybe-notify-slack-failure + - *step-maybe-cleanup-arm + steps-test-nan: &steps-test-nan steps: - attach_workspace: @@ -1580,9 +1608,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: @@ -1910,7 +1935,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 @@ -1968,7 +1993,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 @@ -2356,6 +2381,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: @@ -2536,15 +2579,19 @@ workflows: - osx-publish-x64-skip-checkout: requires: - mac-checkout + context: release-env - mas-publish-x64-skip-checkout: requires: - mac-checkout + context: release-env - osx-publish-arm64-skip-checkout: requires: - mac-checkout + context: release-env - mas-publish-arm64-skip-checkout: requires: - mac-checkout + context: release-env lint: when: << pipeline.parameters.run-lint >> @@ -2584,8 +2631,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 diff --git a/.env.example b/.env.example index eb3df4b6bdf9c..4d218327bd60e 100644 --- a/.env.example +++ b/.env.example @@ -4,4 +4,3 @@ APPVEYOR_CLOUD_TOKEN= CIRCLE_TOKEN= ELECTRON_GITHUB_TOKEN= -VSTS_TOKEN= \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3819e9cb62d45..b014b762747ef 100644 --- a/.gitignore +++ b/.gitignore @@ -68,4 +68,6 @@ ts-gen .depshash-target # Used to accelerate builds after sync -patches/mtime-cache.json \ No newline at end of file +patches/mtime-cache.json + +spec/fixtures/logo.png \ No newline at end of file diff --git a/DEPS b/DEPS index 920c6868c4bd6..f7bd58bb0180e 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ gclient_gn_args = [ vars = { 'chromium_version': - '89.0.4389.69', + '89.0.4389.128', 'node_version': 'v14.16.0', 'nan_version': diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION index b0d364502ebe9..088fb930350b6 100644 --- a/ELECTRON_VERSION +++ b/ELECTRON_VERSION @@ -1 +1 @@ -12.0.0 \ No newline at end of file +12.2.3 \ No newline at end of file diff --git a/README.md b/README.md index 9dc43bf9e8bdc..e679d3bbdc1bd 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/appveyor.yml b/appveyor.yml index 62f6fb5633cd0..3b98330222aa8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -36,6 +36,7 @@ environment: ELECTRON_ENABLE_STACK_DUMPING: 1 MOCHA_REPORTER: mocha-multi-reporters MOCHA_MULTI_REPORTERS: mocha-appveyor-reporter, tap + GOMA_FALLBACK_ON_AUTH_FAILURE: true notifications: - provider: Webhook url: https://electron-mission-control.herokuapp.com/rest/appveyor-hook diff --git a/build/npm-run.py b/build/npm-run.py index a786aa5da62d8..da20f462391b0 100644 --- a/build/npm-run.py +++ b/build/npm-run.py @@ -21,6 +21,6 @@ + "' failed with code '" + str(e.returncode) + "':\n" - + e.output + + e.output.decode('utf8') ) sys.exit(e.returncode) diff --git a/build/webpack/webpack.config.base.js b/build/webpack/webpack.config.base.js index b23ffb95e7748..d09f896c10753 100644 --- a/build/webpack/webpack.config.base.js +++ b/build/webpack/webpack.config.base.js @@ -163,7 +163,7 @@ if ((globalThis.process || binding.process).argv.includes("--profile-electron-in setImmediate: false }, optimization: { - minimize: true, + minimize: env.mode === 'production', minimizer: [ new TerserPlugin({ terserOptions: { diff --git a/build/webpack/webpack.gni b/build/webpack/webpack.gni index f2bddbd5ae2bc..2157cceabe320 100644 --- a/build/webpack/webpack.gni +++ b/build/webpack/webpack.gni @@ -22,6 +22,11 @@ template("webpack_build") { "//electron/typings/internal-electron.d.ts", ] + invoker.inputs + mode = "development" + if (is_official_build) { + mode = "production" + } + args = [ "--config", rebase_path(invoker.config_file), @@ -29,6 +34,7 @@ template("webpack_build") { "--output-path=" + rebase_path(get_path_info(invoker.out_file, "dir")), "--env.buildflags=" + rebase_path("$target_gen_dir/buildflags/buildflags.h"), + "--env.mode=" + mode, ] deps += [ "buildflags" ] diff --git a/chromium_src/BUILD.gn b/chromium_src/BUILD.gn index 0430c46bd1ded..efa039cfcd25c 100644 --- a/chromium_src/BUILD.gn +++ b/chromium_src/BUILD.gn @@ -139,6 +139,8 @@ static_library("chrome") { if (enable_color_chooser) { sources += [ + "//chrome/browser/devtools/devtools_eye_dropper.cc", + "//chrome/browser/devtools/devtools_eye_dropper.h", "//chrome/browser/platform_util.cc", "//chrome/browser/platform_util.h", "//chrome/browser/ui/browser_dialogs.h", diff --git a/default_app/default_app.ts b/default_app/default_app.ts index 7c2d8a3b9eecb..08d1c7ce39558 100644 --- a/default_app/default_app.ts +++ b/default_app/default_app.ts @@ -41,14 +41,14 @@ ipcMain.handle('bootstrap', (event) => { return isTrustedSender(event.sender) ? electronPath : null; }); -async function createWindow () { +async function createWindow (backgroundColor?: string) { await app.whenReady(); const options: Electron.BrowserWindowConstructorOptions = { width: 960, height: 620, autoHideMenuBar: true, - backgroundColor: '#2f3241', + backgroundColor, webPreferences: { preload: path.resolve(__dirname, 'preload.js'), contextIsolation: true, @@ -96,7 +96,7 @@ export const loadURL = async (appUrl: string) => { }; export const loadFile = async (appPath: string) => { - mainWindow = await createWindow(); + mainWindow = await createWindow(appPath === 'index.html' ? '#2f3241' : undefined); mainWindow.loadFile(appPath); mainWindow.focus(); }; diff --git a/docs/README.md b/docs/README.md index e561b4d1b0ddd..75444671fb71b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -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) @@ -91,11 +87,6 @@ These individual tutorials expand on topics discussed in the guide above. * Electron Releases & Developer Feedback * [Versioning Policy](tutorial/electron-versioning.md) * [Release Timelines](tutorial/electron-timelines.md) -* [Packaging App Source Code with asar](tutorial/application-packaging.md) - * [Generating asar Archives](tutorial/application-packaging.md#generating-asar-archives) - * [Using asar Archives](tutorial/application-packaging.md#using-asar-archives) - * [Limitations](tutorial/application-packaging.md#limitations-of-the-node-api) - * [Adding Unpacked Files to asar Archives](tutorial/application-packaging.md#adding-unpacked-files-to-asar-archives) * [Testing Widevine CDM](tutorial/testing-widevine-cdm.md) --- @@ -131,6 +122,8 @@ These individual tutorials expand on topics discussed in the guide above. * [ipcMain](api/ipc-main.md) * [Menu](api/menu.md) * [MenuItem](api/menu-item.md) +* [MessageChannelMain](api/message-channel-main.md) +* [MessagePortMain](api/message-port-main.md) * [net](api/net.md) * [netLog](api/net-log.md) * [nativeTheme](api/native-theme.md) @@ -140,6 +133,7 @@ These individual tutorials expand on topics discussed in the guide above. * [protocol](api/protocol.md) * [screen](api/screen.md) * [session](api/session.md) +* [ShareMenu](api/share-menu.md) * [systemPreferences](api/system-preferences.md) * [TouchBar](api/touch-bar.md) * [Tray](api/tray.md) @@ -149,15 +143,14 @@ These individual tutorials expand on topics discussed in the guide above. ### Modules for the Renderer Process (Web Page): * [contextBridge](api/context-bridge.md) -* [desktopCapturer](api/desktop-capturer.md) * [ipcRenderer](api/ipc-renderer.md) -* [remote](api/remote.md) * [webFrame](api/web-frame.md) ### Modules for Both Processes: * [clipboard](api/clipboard.md) * [crashReporter](api/crash-reporter.md) +* [desktopCapturer](api/desktop-capturer.md) * [nativeImage](api/native-image.md) * [shell](api/shell.md) diff --git a/docs/api/accelerator.md b/docs/api/accelerator.md index 6c5dfd1a4bfe6..f8d4cc421e689 100644 --- a/docs/api/accelerator.md +++ b/docs/api/accelerator.md @@ -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 diff --git a/docs/api/app.md b/docs/api/app.md index 2f01e65a91f6c..7961e3fe33aea 100755 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -753,7 +753,8 @@ Overrides the current application's name. ### `app.getLocale()` -Returns `String` - The current application locale. Possible return values are documented [here](locales.md). +Returns `String` - The current application locale, fetched using Chromium's `l10n_util` library. +Possible return values are documented [here](https://source.chromium.org/chromium/chromium/src/+/master:ui/base/l10n/l10n_util.cc). To set the locale, you'll want to use a command line switch at app startup, which may be found [here](https://github.com/electron/electron/blob/master/docs/api/command-line-switches.md). @@ -929,6 +930,10 @@ re-add a removed item to a custom category earlier than that will result in the entire custom category being omitted from the Jump List. The list of removed items can be obtained using `app.getJumpListSettings()`. +**Note:** The maximum length of a Jump List item's `description` property is +260 characters. Beyond this limit, the item will not be added to the Jump +List, nor will it be displayed. + Here's a very simple example of creating a custom Jump List: ```javascript diff --git a/docs/api/browser-view.md b/docs/api/browser-view.md index 0b7c1ef1ec8e5..dc8a5e9558082 100644 --- a/docs/api/browser-view.md +++ b/docs/api/browser-view.md @@ -1,14 +1,16 @@ -## Class: BrowserView - -> Create and control views. - -Process: [Main](../glossary.md#main-process) +# BrowserView A `BrowserView` can be used to embed additional web content into a [`BrowserWindow`](browser-window.md). It is like a child window, except that it is positioned relative to its owning window. It is meant to be an alternative to the `webview` tag. +## Class: BrowserView + +> Create and control views. + +Process: [Main](../glossary.md#main-process) + ### Example ```javascript diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index fd45e3c431128..2ef54f3a73e2b 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -265,12 +265,12 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. be the absolute file path to the script. When node integration is turned off, the preload script can reintroduce Node global symbols back to the global scope. See example - [here](process.md#event-loaded). + [here](context-bridge.md#exposing-node-global-symbols). * `sandbox` Boolean (optional) - If set, this will sandbox the renderer 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 @@ -337,7 +337,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. more details. * `contextIsolation` Boolean (optional) - Whether to run Electron APIs and the specified `preload` script in a separate JavaScript context. Defaults - to `false`. The context that the `preload` script runs in will only have + to `true`. The context that the `preload` script runs in will only have access to its own dedicated `document` and `window` globals, as well as its own set of JavaScript builtins (`Array`, `Object`, `JSON`, etc.), which are all invisible to the loaded content. The Electron API will only @@ -349,8 +349,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. context in the dev tools by selecting the 'Electron Isolated Context' entry in the combo box at the top of the Console tab. * `worldSafeExecuteJavaScript` Boolean (optional) - If true, values returned from `webFrame.executeJavaScript` will be sanitized to ensure JS values - can't unsafely cross between worlds when using `contextIsolation`. The default - is `false`. In Electron 12, the default will be changed to `true`. _Deprecated_ + can't unsafely cross between worlds when using `contextIsolation`. Defaults to `true`. _Deprecated_ * `nativeWindowOpen` Boolean (optional) - Whether to use native `window.open()`. Defaults to `false`. Child windows will always have node integration disabled unless `nodeIntegrationInSubFrames` is true. **Note:** This option is currently @@ -1387,7 +1386,7 @@ can be be used to listen to changes to tablet mode. #### `win.getMediaSourceId()` -Returns `String` - Window id in the format of DesktopCapturerSource's id. For example "window:1234:0". +Returns `String` - Window id in the format of DesktopCapturerSource's id. For example "window:1324:0". More precisely the format is `window:id:other_id` where `id` is `HWND` on Windows, `CGWindowID` (`uint64_t`) on macOS and `Window` (`unsigned long`) on @@ -1405,6 +1404,8 @@ The native type of the handle is `HWND` on Windows, `NSView*` on macOS, and * `message` Integer * `callback` Function + * `wParam` any - The `wParam` provided to the WndProc + * `lParam` any - The `lParam` provided to the WndProc Hooks a windows message. The `callback` is called when the message is received in the WndProc. @@ -1457,7 +1458,7 @@ Returns `Boolean` - Whether the window's document has been edited. Returns `Promise` - Resolves with a [NativeImage](native-image.md) -Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. +Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. If the page is not visible, `rect` may be empty. #### `win.loadURL(url[, options])` diff --git a/docs/api/client-request.md b/docs/api/client-request.md index 865f733d78474..d2c018b7e34cb 100644 --- a/docs/api/client-request.md +++ b/docs/api/client-request.md @@ -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' diff --git a/docs/api/command-line-switches.md b/docs/api/command-line-switches.md index 4d9deec60945c..2dd561942407d 100644 --- a/docs/api/command-line-switches.md +++ b/docs/api/command-line-switches.md @@ -80,6 +80,12 @@ 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` + +Field trials to be forcefully enabled or disabled. + +For example: `WebRTC-Audio-Red-For-Opus/Enabled/` + ### --host-rules=`rules` A comma-separated list of `rules` that control how hostnames are mapped. @@ -136,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` diff --git a/docs/api/context-bridge.md b/docs/api/context-bridge.md index 9f25516af58e1..8dc4c7ec1087d 100644 --- a/docs/api/context-bridge.md +++ b/docs/api/context-bridge.md @@ -33,7 +33,7 @@ page you load in your renderer executes code in this world. ### Isolated World -When `contextIsolation` is enabled in your `webPreferences`, your `preload` scripts run in an +When `contextIsolation` is enabled in your `webPreferences` (this is the default behavior since Electron 12.0.0), your `preload` scripts run in an "Isolated World". You can read more about context isolation and what it affects in the [security](../tutorial/security.md#3-enable-context-isolation-for-remote-content) docs. @@ -109,3 +109,22 @@ has been included below for completeness: | `Symbol` | N/A | ❌ | ❌ | Symbols cannot be copied across contexts so they are dropped | If the type you care about is not in the above table, it is probably not supported. + +### Exposing Node Global Symbols + +The `contextBridge` can be used by the preload script to give your renderer access to Node APIs. +The table of supported types described above also applies to Node APIs that you expose through `contextBridge`. +Please note that many Node APIs grant access to local system resources. +Be very cautious about which globals and APIs you expose to untrusted remote content. + +```javascript +const { contextBridge } = require('electron') +const crypto = require('crypto') +contextBridge.exposeInMainWorld('nodeCrypto', { + sha256sum (data) { + const hash = crypto.createHash('sha256') + hash.update(data) + return hash.digest('hex') + } +}) +``` diff --git a/docs/api/cookies.md b/docs/api/cookies.md index 4eab77d4d5996..cd598bfeece88 100644 --- a/docs/api/cookies.md +++ b/docs/api/cookies.md @@ -45,6 +45,8 @@ The following events are available on instances of `Cookies`: #### Event: 'changed' +Returns: + * `event` Event * `cookie` [Cookie](structures/cookie.md) - The cookie that was changed. * `cause` String - The cause of the change with one of the following values: diff --git a/docs/api/dialog.md b/docs/api/dialog.md index 483ff271d2372..6cefc50a27c6e 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -24,7 +24,7 @@ The `dialog` module has the following methods: * `buttonLabel` String (optional) - Custom label for the confirmation button, when left empty the default label will be used. * `filters` [FileFilter[]](structures/file-filter.md) (optional) - * `properties` String[] (optional) - Contains which features the dialog should + * `properties` String[] (optional) - Contains which features the dialog should use. The following values are supported: * `openFile` - Allow files to be selected. * `openDirectory` - Allow directories to be selected. @@ -87,7 +87,7 @@ dialog.showOpenDialogSync(mainWindow, { * `buttonLabel` String (optional) - Custom label for the confirmation button, when left empty the default label will be used. * `filters` [FileFilter[]](structures/file-filter.md) (optional) - * `properties` String[] (optional) - Contains which features the dialog should + * `properties` String[] (optional) - Contains which features the dialog should use. The following values are supported: * `openFile` - Allow files to be selected. * `openDirectory` - Allow directories to be selected. @@ -112,7 +112,7 @@ Returns `Promise` - Resolve with an object containing the following: * `canceled` Boolean - whether or not the dialog was canceled. * `filePaths` String[] - An array of file paths chosen by the user. If the dialog is cancelled this will be an empty array. -* `bookmarks` String[] (optional) _macOS_ _mas_ - An array matching the `filePaths` array of base64 encoded strings which contains security scoped bookmark data. `securityScopedBookmarks` must be enabled for this to be populated. (For return values, see [table here](#bookmarks-array).) +* `bookmarks` String[] (optional) _macOS_ _mas_ - An array matching the `filePaths` array of base64 encoded strings which contains security scoped bookmark data. `securityScopedBookmarks` must be enabled for this to be populated. (For return values, see [table here](#bookmarks-array).) The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal. @@ -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 @@ -165,7 +165,7 @@ dialog.showOpenDialog(mainWindow, { displayed in front of the filename text field. * `showsTagField` Boolean (optional) _macOS_ - Show the tags input box, defaults to `true`. - * `properties` String[] (optional) + * `properties` String[] (optional) * `showHiddenFiles` - Show hidden files in dialog. * `createDirectory` _macOS_ - Allow creating new directories from dialog. * `treatPackageAsDirectory` _macOS_ - Treat packages, such as `.app` folders, @@ -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 @@ -195,7 +195,7 @@ The `filters` specifies an array of file types that can be displayed, see * `nameFieldLabel` String (optional) _macOS_ - Custom label for the text displayed in front of the filename text field. * `showsTagField` Boolean (optional) _macOS_ - Show the tags input box, defaults to `true`. - * `properties` String[] (optional) + * `properties` String[] (optional) * `showHiddenFiles` - Show hidden files in dialog. * `createDirectory` _macOS_ - Allow creating new directories from dialog. * `treatPackageAsDirectory` _macOS_ - Treat packages, such as `.app` folders, @@ -227,7 +227,7 @@ expanding and collapsing the dialog. `"warning"`. On Windows, `"question"` displays the same icon as `"info"`, unless you set an icon using the `"icon"` option. On macOS, both `"warning"` and `"error"` display the same warning icon. - * `buttons` String[] (optional) - Array of texts for buttons. On Windows, an empty array + * `buttons` String[] (optional) - Array of texts for buttons. On Windows, an empty array will result in one button labeled "OK". * `defaultId` Integer (optional) - Index of the button in the buttons array which will be selected by default when the message box opens. @@ -273,7 +273,7 @@ If `browserWindow` is not shown dialog will not be attached to it. In such case `"warning"`. On Windows, `"question"` displays the same icon as `"info"`, unless you set an icon using the `"icon"` option. On macOS, both `"warning"` and `"error"` display the same warning icon. - * `buttons` String[] (optional) - Array of texts for buttons. On Windows, an empty array + * `buttons` String[] (optional) - Array of texts for buttons. On Windows, an empty array will result in one button labeled "OK". * `defaultId` Integer (optional) - Index of the button in the buttons array which will be selected by default when the message box opens. diff --git a/docs/api/frameless-window.md b/docs/api/frameless-window.md index b7d893d4b257b..8bb253e1948c2 100644 --- a/docs/api/frameless-window.md +++ b/docs/api/frameless-window.md @@ -82,8 +82,11 @@ win.show() * The `blur` filter only applies to the web page, so there is no way to apply blur effect to the content below the window (i.e. other applications open on the user's system). -* On Windows operating systems, transparent windows will not work when DWM is +* The window will not be transparent when DevTools is opened. +* On Windows operating systems, + * transparent windows will not work when DWM is disabled. + * transparent windows can not be maximized using the Windows system menu or by double clicking the title bar. The reasoning behind this can be seen on [this pull request](https://github.com/electron/electron/pull/28207). * On Linux, users have to put `--enable-transparent-visuals --disable-gpu` in the command line to disable GPU and allow ARGB to make transparent window, this is caused by an upstream bug that [alpha channel doesn't work on some diff --git a/docs/api/locales.md b/docs/api/locales.md deleted file mode 100644 index a45fdbcbe5774..0000000000000 --- a/docs/api/locales.md +++ /dev/null @@ -1,142 +0,0 @@ -# Locales - -> Locale values returned by `app.getLocale()`. - -Electron uses Chromium's `l10n_util` library to fetch the locale. Possible -values are listed below: - -| Language Code | Language Name | -|---------------|---------------| -| af | Afrikaans | -| am | Amharic | -| ar | Arabic | -| az | Azerbaijani | -| be | Belarusian | -| bg | Bulgarian | -| bh | Bihari | -| bn | Bengali | -| br | Breton | -| bs | Bosnian | -| ca | Catalan | -| co | Corsican | -| cs | Czech | -| cy | Welsh | -| da | Danish | -| de | German | -| de-AT | German (Austria) | -| de-CH | German (Switzerland) | -| de-DE | German (Germany) | -| el | Greek | -| en | English | -| en-AU | English (Australia) | -| en-CA | English (Canada) | -| en-GB | English (UK) | -| en-NZ | English (New Zealand) | -| en-US | English (US) | -| en-ZA | English (South Africa) | -| eo | Esperanto | -| es | Spanish | -| es-419 | Spanish (Latin America) | -| et | Estonian | -| eu | Basque | -| fa | Persian | -| fi | Finnish | -| fil | Filipino | -| fo | Faroese | -| fr | French | -| fr-CA | French (Canada) | -| fr-CH | French (Switzerland) | -| fr-FR | French (France) | -| fy | Frisian | -| ga | Irish | -| gd | Scots Gaelic | -| gl | Galician | -| gn | Guarani | -| gu | Gujarati | -| ha | Hausa | -| haw | Hawaiian | -| he | Hebrew | -| hi | Hindi | -| hr | Croatian | -| hu | Hungarian | -| hy | Armenian | -| ia | Interlingua | -| id | Indonesian | -| is | Icelandic | -| it | Italian | -| it-CH | Italian (Switzerland) | -| it-IT | Italian (Italy) | -| ja | Japanese | -| jw | Javanese | -| ka | Georgian | -| kk | Kazakh | -| km | Cambodian | -| kn | Kannada | -| ko | Korean | -| ku | Kurdish | -| ky | Kyrgyz | -| la | Latin | -| ln | Lingala | -| lo | Laothian | -| lt | Lithuanian | -| lv | Latvian | -| mk | Macedonian | -| ml | Malayalam | -| mn | Mongolian | -| mo | Moldavian | -| mr | Marathi | -| ms | Malay | -| mt | Maltese | -| nb | Norwegian (Bokmal) | -| ne | Nepali | -| nl | Dutch | -| nn | Norwegian (Nynorsk) | -| no | Norwegian | -| oc | Occitan | -| om | Oromo | -| or | Oriya | -| pa | Punjabi | -| pl | Polish | -| ps | Pashto | -| pt | Portuguese | -| pt-BR | Portuguese (Brazil) | -| pt-PT | Portuguese (Portugal) | -| qu | Quechua | -| rm | Romansh | -| ro | Romanian | -| ru | Russian | -| sd | Sindhi | -| sh | Serbo-Croatian | -| si | Sinhalese | -| sk | Slovak | -| sl | Slovenian | -| sn | Shona | -| so | Somali | -| sq | Albanian | -| sr | Serbian | -| st | Sesotho | -| su | Sundanese | -| sv | Swedish | -| sw | Swahili | -| ta | Tamil | -| te | Telugu | -| tg | Tajik | -| th | Thai | -| ti | Tigrinya | -| tk | Turkmen | -| to | Tonga | -| tr | Turkish | -| tt | Tatar | -| tw | Twi | -| ug | Uighur | -| uk | Ukrainian | -| ur | Urdu | -| uz | Uzbek | -| vi | Vietnamese | -| xh | Xhosa | -| yi | Yiddish | -| yo | Yoruba | -| zh | Chinese | -| zh-CN | Chinese (Simplified) | -| zh-TW | Chinese (Traditional) | -| zu | Zulu | diff --git a/docs/api/menu.md b/docs/api/menu.md index 4aea3a9351fe8..d5d47e68e46d7 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -1,3 +1,5 @@ +# Menu + ## Class: Menu > Create native application menus and context menus. diff --git a/docs/api/message-channel-main.md b/docs/api/message-channel-main.md index 86cdce4e5099b..670cda868f599 100644 --- a/docs/api/message-channel-main.md +++ b/docs/api/message-channel-main.md @@ -9,12 +9,15 @@ channel messaging. ## Class: MessageChannelMain +> Channel interface for channel messaging in the main process. + Process: [Main](../glossary.md#main-process) Example: ```js // Main process +const { MessageChannelMain } = require('electron') const { port1, port2 } = new MessageChannelMain() w.webContents.postMessage('port', null, [port2]) port1.postMessage({ some: 'message' }) diff --git a/docs/api/message-port-main.md b/docs/api/message-port-main.md index 2f75f2f996fc2..6c84c28c49bbc 100644 --- a/docs/api/message-port-main.md +++ b/docs/api/message-port-main.md @@ -14,6 +14,8 @@ channel messaging. ## Class: MessagePortMain +> Port interface for channel messaging in the main process. + Process: [Main](../glossary.md#main-process) ### Instance Methods diff --git a/docs/api/process.md b/docs/api/process.md index d3de0264c48bd..77e0e95014e0b 100644 --- a/docs/api/process.md +++ b/docs/api/process.md @@ -42,19 +42,6 @@ In sandboxed renderers the `process` object contains only a subset of the APIs: Emitted when Electron has loaded its internal initialization script and is beginning to load the web page or the main script. -It can be used by the preload script to add removed Node global symbols back to -the global scope when node integration is turned off: - -```javascript -// preload.js -const _setImmediate = setImmediate -const _clearImmediate = clearImmediate -process.once('loaded', () => { - global.setImmediate = _setImmediate - global.clearImmediate = _clearImmediate -}) -``` - ## Properties ### `process.defaultApp` _Readonly_ diff --git a/docs/api/sandbox-option.md b/docs/api/sandbox-option.md deleted file mode 100644 index da8b530911fdd..0000000000000 --- a/docs/api/sandbox-option.md +++ /dev/null @@ -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. diff --git a/docs/api/share-menu.md b/docs/api/share-menu.md index 007028db3bc95..61e64ab912b47 100644 --- a/docs/api/share-menu.md +++ b/docs/api/share-menu.md @@ -1,8 +1,4 @@ -## Class: ShareMenu - -> Create share menu on macOS. - -Process: [Main](../glossary.md#main-process) +# ShareMenu The `ShareMenu` class creates [Share Menu][share-menu] on macOS, which can be used to share information from the current context to apps, social media @@ -11,6 +7,12 @@ accounts, and other services. For including the share menu as a submenu of other menus, please use the `shareMenu` role of [`MenuItem`](menu-item.md). +## Class: ShareMenu + +> Create share menu on macOS. + +Process: [Main](../glossary.md#main-process) + ### `new ShareMenu(sharingItem)` * `sharingItem` SharingItem - The item to share. diff --git a/docs/api/structures/display.md b/docs/api/structures/display.md index f10636d05b700..5d296e6f1d849 100644 --- a/docs/api/structures/display.md +++ b/docs/api/structures/display.md @@ -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 diff --git a/docs/api/structures/jump-list-category.md b/docs/api/structures/jump-list-category.md index 07627e78c98e7..0f27f2085f6eb 100644 --- a/docs/api/structures/jump-list-category.md +++ b/docs/api/structures/jump-list-category.md @@ -19,3 +19,7 @@ property set then its `type` is assumed to be `tasks`. If the `name` property is set but the `type` property is omitted then the `type` is assumed to be `custom`. + +**Note:** The maximum length of a Jump List item's `description` property is +260 characters. Beyond this limit, the item will not be added to the Jump +List, nor will it be displayed. diff --git a/docs/api/structures/jump-list-item.md b/docs/api/structures/jump-list-item.md index d75637cb472dc..491abf80d301d 100644 --- a/docs/api/structures/jump-list-item.md +++ b/docs/api/structures/jump-list-item.md @@ -17,7 +17,7 @@ * `title` String (optional) - The text to be displayed for the item in the Jump List. Should only be set if `type` is `task`. * `description` String (optional) - Description of the task (displayed in a tooltip). - Should only be set if `type` is `task`. + Should only be set if `type` is `task`. Maximum length 260 characters. * `iconPath` String (optional) - The absolute path to an icon to be displayed in a Jump List, which can be an arbitrary resource file that contains an icon (e.g. `.ico`, `.exe`, `.dll`). You can usually specify `process.execPath` to diff --git a/docs/api/structures/upload-file.md b/docs/api/structures/upload-file.md index ae231bdaf895f..b7cdd98aab8a9 100644 --- a/docs/api/structures/upload-file.md +++ b/docs/api/structures/upload-file.md @@ -1,6 +1,6 @@ # UploadFile Object -* `type` String - `file`. +* `type` 'file' - `file`. * `filePath` String - Path of file to be uploaded. * `offset` Integer - Defaults to `0`. * `length` Integer - Number of bytes to read from `offset`. diff --git a/docs/api/structures/upload-raw-data.md b/docs/api/structures/upload-raw-data.md index 4fe162311fa1f..e80eaa9075833 100644 --- a/docs/api/structures/upload-raw-data.md +++ b/docs/api/structures/upload-raw-data.md @@ -1,4 +1,4 @@ # UploadRawData Object -* `type` String - `rawData`. +* `type` 'rawData' - `rawData`. * `bytes` Buffer - Data to be uploaded. diff --git a/docs/api/synopsis.md b/docs/api/synopsis.md index ce1349615e32b..667c1dcd35a4d 100644 --- a/docs/api/synopsis.md +++ b/docs/api/synopsis.md @@ -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: ``` -To run your app, read [Run your app](../tutorial/quick-start.md#run-your-application). - ## Destructuring assignment As of 0.37, you can use diff --git a/docs/api/system-preferences.md b/docs/api/system-preferences.md index 3936cd7c2f8d6..9bec30ff37608 100644 --- a/docs/api/system-preferences.md +++ b/docs/api/system-preferences.md @@ -130,6 +130,8 @@ This is necessary for events such as `NSUserDefaultsDidChangeNotification`. * `userInfo` Record * `object` String +Returns `Number` - The ID of this subscription + Same as `subscribeNotification`, but uses `NSWorkspace.sharedWorkspace.notificationCenter`. This is necessary for events such as `NSWorkspaceDidActivateApplicationNotification`. diff --git a/docs/api/touch-bar.md b/docs/api/touch-bar.md index 62afc0e251067..10bf400ab47b0 100644 --- a/docs/api/touch-bar.md +++ b/docs/api/touch-bar.md @@ -1,3 +1,5 @@ +# TouchBar + ## Class: TouchBar > Create TouchBar layouts for native macOS applications diff --git a/docs/api/tray.md b/docs/api/tray.md index 1a6b9cf9a5942..ffa93669b1872 100644 --- a/docs/api/tray.md +++ b/docs/api/tray.md @@ -1,3 +1,5 @@ +# Tray + ## Class: Tray > Add icons and context menus to the system's notification area. diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 7c1d916c04a6b..2b810454d816d 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -45,6 +45,26 @@ returns `null`. Returns `WebContents` | undefined - A WebContents instance with the given ID, or `undefined` if there is no WebContents associated with the given ID. +### `webContents.fromDevToolsTargetId(targetId)` + +* `targetId` String - The Chrome DevTools Protocol [TargetID](https://chromedevtools.github.io/devtools-protocol/tot/Target/#type-TargetID) associated with the WebContents instance. + +Returns `WebContents` | undefined - A WebContents instance with the given TargetID, or +`undefined` if there is no WebContents associated with the given TargetID. + +When communicating with the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/), +it can be useful to lookup a WebContents instance based on its assigned TargetID. + +```js +async function lookupTargetId (browserWindow) { + const wc = browserWindow.webContents + await wc.debugger.attach('1.3') + const { targetInfo } = await wc.debugger.sendCommand('Target.getTargetInfo') + const { targetId } = targetInfo + const targetWebContents = await webContents.fromDevToolsTargetId(targetId) +} +``` + ## Class: WebContents > Render and control the contents of a BrowserWindow instance. @@ -1169,6 +1189,7 @@ Ignore application menu shortcuts while this web contents is focused. * `url` String - The _resolved_ version of the URL passed to `window.open()`. e.g. opening a window with `window.open('foo')` will yield something like `https://the-origin/the/current/path/foo`. * `frameName` String - Name of the window provided in `window.open()` * `features` String - Comma separated list of window features provided to `window.open()`. + Returns `{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}` - `deny` cancels the creation of the new window. `allow` will allow the new window to be created. Specifying `overrideBrowserWindowOptions` allows customization of the created window. Returning an unrecognized value such as a null, undefined, or an object @@ -1305,8 +1326,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`. diff --git a/docs/api/web-request.md b/docs/api/web-request.md index 6ab12dad8287d..5f6be21269be0 100644 --- a/docs/api/web-request.md +++ b/docs/api/web-request.md @@ -154,7 +154,6 @@ response are visible by the time this listener is fired. * `timestamp` Double * `statusLine` String * `statusCode` Integer - * `requestHeaders` Record * `responseHeaders` Record (optional) * `callback` Function * `headersReceivedResponse` Object diff --git a/docs/api/webview-tag.md b/docs/api/webview-tag.md index 10fbd67bb23cc..4daf81f2c0fc5 100644 --- a/docs/api/webview-tag.md +++ b/docs/api/webview-tag.md @@ -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`. @@ -719,6 +718,10 @@ Corresponds to the points in time when the spinner of the tab starts spinning. Corresponds to the points in time when the spinner of the tab stops spinning. +### Event: 'did-attach' + +Fired when attached to the embedder web contents. + ### Event: 'dom-ready' Fired when document in the given frame is loaded. @@ -839,6 +842,19 @@ this purpose. Calling `event.preventDefault()` does __NOT__ have any effect. +### Event: 'did-start-navigation' + +Returns: + +* `url` String +* `isInPlace` Boolean +* `isMainFrame` Boolean +* `frameProcessId` Integer +* `frameRoutingId` Integer + +Emitted when any frame (including main) starts navigating. `isInPlace` will be +`true` for in-page navigations. + ### Event: 'did-navigate' Returns: @@ -851,6 +867,23 @@ This event is not emitted for in-page navigations, such as clicking anchor links or updating the `window.location.hash`. Use `did-navigate-in-page` event for this purpose. +### Event: 'did-frame-navigate' + +Returns: + +* `url` String +* `httpResponseCode` Integer - -1 for non HTTP navigations +* `httpStatusText` String - empty for non HTTP navigations, +* `isMainFrame` Boolean +* `frameProcessId` Integer +* `frameRoutingId` Integer + +Emitted when any frame navigation is done. + +This event is not emitted for in-page navigations, such as clicking anchor links +or updating the `window.location.hash`. Use `did-navigate-in-page` event for +this purpose. + ### Event: 'did-navigate-in-page' Returns: diff --git a/docs/api/window-open.md b/docs/api/window-open.md index 2323731d1cda0..c6cc1aac527a0 100644 --- a/docs/api/window-open.md +++ b/docs/api/window-open.md @@ -83,9 +83,9 @@ const mainWindow = new BrowserWindow() mainWindow.webContents.setWindowOpenHandler(({ url }) => { if (url.startsWith('https://github.com/')) { - return true + return { action: 'allow' } } - return false + return { action: 'deny' } }) mainWindow.webContents.on('did-create-window', (childWindow) => { @@ -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' } }) ``` diff --git a/docs/breaking-changes.md b/docs/breaking-changes.md index a24386c12ef13..23c0c9cf09a2a 100644 --- a/docs/breaking-changes.md +++ b/docs/breaking-changes.md @@ -6,14 +6,20 @@ Breaking changes will be documented here, and deprecation warnings added to JS c This document uses the following convention to categorize breaking changes: -- **API Changed:** An API was changed in such a way that code that has not been updated is guaranteed to throw an exception. -- **Behavior Changed:** The behavior of Electron has changed, but not in such a way that an exception will necessarily be thrown. -- **Default Changed:** Code depending on the old default may break, not necessarily throwing an exception. The old behavior can be restored by explicitly specifying the value. -- **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release. -- **Removed:** An API or feature was removed, and is no longer supported by Electron. +* **API Changed:** An API was changed in such a way that code that has not been updated is guaranteed to throw an exception. +* **Behavior Changed:** The behavior of Electron has changed, but not in such a way that an exception will necessarily be thrown. +* **Default Changed:** Code depending on the old default may break, not necessarily throwing an exception. The old behavior can be restored by explicitly specifying the value. +* **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release. +* **Removed:** An API or feature was removed, and is no longer supported by Electron. ## Planned Breaking API Changes (14.0) +### API Changed: `window.(open)` + +The optional parameter `frameName` will no longer set the title of the window. This now follows the specification described by the [native documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#parameters) under the corresponding parameter `windowName`. + +If you were using this parameter to set the title of a window, you can instead use [win.setTitle(title)](https://www.electronjs.org/docs/api/browser-window#winsettitletitle). + ### Removed: `worldSafeExecuteJavaScript` In Electron 14, `worldSafeExecuteJavaScript` will be removed. There is no alternative, please @@ -24,6 +30,28 @@ You will be affected by this change if you use either `webFrame.executeJavaScrip ## Planned Breaking API Changes (13.0) +### API Changed: `session.setPermissionCheckHandler(handler)` + +The `handler` methods first parameter was previously always a `webContents`, it can now sometimes be `null`. You should use the `requestingOrigin`, `embeddingOrigin` and `securityOrigin` properties to respond to the permission check correctly. As the `webContents` can be `null` it can no longer be relied on. + +```js +// Old code +session.setPermissionCheckHandler((webContents, permission) => { + if (webContents.getURL().startsWith('https://google.com/') && permission === 'notification') { + return true + } + return false +}) + +// Replace with +session.setPermissionCheckHandler((webContents, permission, requestingOrigin) => { + if (new URL(requestingOrigin).hostname === 'google.com' && permission === 'notification') { + return true + } + return false +}) +``` + ### Removed: `shell.moveItemToTrash()` The deprecated synchronous `shell.moveItemToTrash()` API has been removed. Use @@ -36,6 +64,78 @@ shell.moveItemToTrash(path) shell.trashItem(path).then(/* ... */) ``` +### Removed: `BrowserWindow` extension APIs + +The deprecated extension APIs have been removed: + +* `BrowserWindow.addExtension(path)` +* `BrowserWindow.addDevToolsExtension(path)` +* `BrowserWindow.removeExtension(name)` +* `BrowserWindow.removeDevToolsExtension(name)` +* `BrowserWindow.getExtensions()` +* `BrowserWindow.getDevToolsExtensions()` + +Use the session APIs instead: + +* `ses.loadExtension(path)` +* `ses.removeExtension(extension_id)` +* `ses.getAllExtensions()` + +```js +// Removed in Electron 13 +BrowserWindow.addExtension(path) +BrowserWindow.addDevToolsExtension(path) +// Replace with +session.defaultSession.loadExtension(path) +``` + +```js +// Removed in Electron 13 +BrowserWindow.removeExtension(name) +BrowserWindow.removeDevToolsExtension(name) +// Replace with +session.defaultSession.removeExtension(extension_id) +``` + +```js +// Removed in Electron 13 +BrowserWindow.getExtensions() +BrowserWindow.getDevToolsExtensions() +// Replace with +session.defaultSession.getAllExtensions() +``` + +### Removed: methods in `systemPreferences` + +The following `systemPreferences` methods have been deprecated: + +* `systemPreferences.isDarkMode()` +* `systemPreferences.isInvertedColorScheme()` +* `systemPreferences.isHighContrastColorScheme()` + +Use the following `nativeTheme` properties instead: + +* `nativeTheme.shouldUseDarkColors` +* `nativeTheme.shouldUseInvertedColorScheme` +* `nativeTheme.shouldUseHighContrastColors` + +```js +// Removed in Electron 13 +systemPreferences.isDarkMode() +// Replace with +nativeTheme.shouldUseDarkColors + +// Removed in Electron 13 +systemPreferences.isInvertedColorScheme() +// Replace with +nativeTheme.shouldUseInvertedColorScheme + +// Removed in Electron 13 +systemPreferences.isHighContrastColorScheme() +// Replace with +nativeTheme.shouldUseHighContrastColors +``` + ## Planned Breaking API Changes (12.0) ### Removed: Pepper Flash support @@ -60,6 +160,9 @@ the previous behavior, `contextIsolation: false` must be specified in WebPrefere We [recommend having contextIsolation enabled](https://github.com/electron/electron/blob/master/docs/tutorial/security.md#3-enable-context-isolation-for-remote-content) for the security of your application. +Another implication is that `require()` cannot be used in the renderer process unless +`nodeIntegration` is `true` and `contextIsolation` is `false`. + For more details see: https://github.com/electron/electron/issues/23506 ### Removed: `crashReporter.getCrashesDirectory()` @@ -79,12 +182,12 @@ app.getPath('crashDumps') The following `crashReporter` methods are no longer available in the renderer process: -- `crashReporter.start` -- `crashReporter.getLastCrashReport` -- `crashReporter.getUploadedReports` -- `crashReporter.getUploadToServer` -- `crashReporter.setUploadToServer` -- `crashReporter.getCrashesDirectory` +* `crashReporter.start` +* `crashReporter.getLastCrashReport` +* `crashReporter.getUploadedReports` +* `crashReporter.getUploadToServer` +* `crashReporter.setUploadToServer` +* `crashReporter.getCrashesDirectory` They should be called only from the main process. @@ -135,6 +238,7 @@ shell.trashItem(path).then(/* ... */) ## Planned Breaking API Changes (11.0) ### Removed: `BrowserView.{destroy, fromId, fromWebContents, getAllViews}` and `id` property of `BrowserView` + The experimental APIs `BrowserView.{destroy, fromId, fromWebContents, getAllViews}` have now been removed. Additionally, the `id` property of `BrowserView` has also been removed. @@ -174,12 +278,12 @@ app.getPath('crashDumps') Calling the following `crashReporter` methods from the renderer process is deprecated: -- `crashReporter.start` -- `crashReporter.getLastCrashReport` -- `crashReporter.getUploadedReports` -- `crashReporter.getUploadToServer` -- `crashReporter.setUploadToServer` -- `crashReporter.getCrashesDirectory` +* `crashReporter.start` +* `crashReporter.getLastCrashReport` +* `crashReporter.getUploadedReports` +* `crashReporter.getUploadToServer` +* `crashReporter.setUploadToServer` +* `crashReporter.getCrashesDirectory` The only non-deprecated methods remaining in the `crashReporter` module in the renderer are `addExtraParameter`, `removeExtraParameter` and `getParameters`. @@ -221,6 +325,7 @@ We [recommend moving away from the remote module](https://medium.com/@nornagon/electrons-remote-module-considered-harmful-70d69500f31). ### `protocol.unregisterProtocol` + ### `protocol.uninterceptProtocol` The APIs are now synchronous and the optional callback is no longer needed. @@ -233,14 +338,23 @@ protocol.unregisterProtocol(scheme) ``` ### `protocol.registerFileProtocol` + ### `protocol.registerBufferProtocol` + ### `protocol.registerStringProtocol` + ### `protocol.registerHttpProtocol` + ### `protocol.registerStreamProtocol` + ### `protocol.interceptFileProtocol` + ### `protocol.interceptStringProtocol` + ### `protocol.interceptBufferProtocol` + ### `protocol.interceptHttpProtocol` + ### `protocol.interceptStreamProtocol` The APIs are now synchronous and the optional callback is no longer needed. @@ -285,6 +399,7 @@ For more detailed information see [#18397](https://github.com/electron/electron/ ### Deprecated: `BrowserWindow` extension APIs The following extension APIs have been deprecated: + * `BrowserWindow.addExtension(path)` * `BrowserWindow.addDevToolsExtension(path)` * `BrowserWindow.removeExtension(name)` @@ -293,6 +408,7 @@ The following extension APIs have been deprecated: * `BrowserWindow.getDevToolsExtensions()` Use the session APIs instead: + * `ses.loadExtension(path)` * `ses.removeExtension(extension_id)` * `ses.getAllExtensions()` @@ -373,7 +489,7 @@ Clone Algorithm][SCA], the same algorithm used to serialize messages for `postMessage`. This brings about a 2x performance improvement for large messages, but also brings some breaking changes in behavior. -- Sending Functions, Promises, WeakMaps, WeakSets, or objects containing any +* Sending Functions, Promises, WeakMaps, WeakSets, or objects containing any such values, over IPC will now throw an exception, instead of silently converting the functions to `undefined`. @@ -387,21 +503,21 @@ ipcRenderer.send('channel', { value: 3, someFunction: () => {} }) // => throws Error("() => {} could not be cloned.") ``` -- `NaN`, `Infinity` and `-Infinity` will now be correctly serialized, instead +* `NaN`, `Infinity` and `-Infinity` will now be correctly serialized, instead of being converted to `null`. -- Objects containing cyclic references will now be correctly serialized, +* Objects containing cyclic references will now be correctly serialized, instead of being converted to `null`. -- `Set`, `Map`, `Error` and `RegExp` values will be correctly serialized, +* `Set`, `Map`, `Error` and `RegExp` values will be correctly serialized, instead of being converted to `{}`. -- `BigInt` values will be correctly serialized, instead of being converted to +* `BigInt` values will be correctly serialized, instead of being converted to `null`. -- Sparse arrays will be serialized as such, instead of being converted to dense +* Sparse arrays will be serialized as such, instead of being converted to dense arrays with `null`s. -- `Date` objects will be transferred as `Date` objects, instead of being +* `Date` objects will be transferred as `Date` objects, instead of being converted to their ISO string representation. -- Typed Arrays (such as `Uint8Array`, `Uint16Array`, `Uint32Array` and so on) +* Typed Arrays (such as `Uint8Array`, `Uint16Array`, `Uint32Array` and so on) will be transferred as such, instead of being converted to Node.js `Buffer`. -- Node.js `Buffer` objects will be transferred as `Uint8Array`s. You can +* Node.js `Buffer` objects will be transferred as `Uint8Array`s. You can convert a `Uint8Array` back to a Node.js `Buffer` by wrapping the underlying `ArrayBuffer`: @@ -470,6 +586,7 @@ limits are now fixed at a minimum of 0.25 and a maximum of 5.0, as defined ### Deprecated events in `systemPreferences` The following `systemPreferences` events have been deprecated: + * `inverted-color-scheme-changed` * `high-contrast-color-scheme-changed` @@ -487,11 +604,13 @@ nativeTheme.on('updated', () => { /* ... */ }) ### Deprecated: methods in `systemPreferences` The following `systemPreferences` methods have been deprecated: + * `systemPreferences.isDarkMode()` * `systemPreferences.isInvertedColorScheme()` * `systemPreferences.isHighContrastColorScheme()` Use the following `nativeTheme` properties instead: + * `nativeTheme.shouldUseDarkColors` * `nativeTheme.shouldUseInvertedColorScheme` * `nativeTheme.shouldUseHighContrastColors` diff --git a/docs/development/build-instructions-gn.md b/docs/development/build-instructions-gn.md index 80b56f9344bee..cfea03e8c2e34 100644 --- a/docs/development/build-instructions-gn.md +++ b/docs/development/build-instructions-gn.md @@ -1,6 +1,8 @@ # Build Instructions -Follow the guidelines below for building Electron. +Follow the guidelines below for building **Electron itself**, for the purposes of creating custom Electron binaries. For bundling and distributing your app code with the prebuilt Electron binaries, see the [application distribution][application-distribution] guide. + +[application-distribution]: ../tutorial/application-distribution.md ## Platform prerequisites @@ -86,8 +88,6 @@ $ gclient sync -f ```sh $ cd src $ export CHROMIUM_BUILDTOOLS_PATH=`pwd`/buildtools -# this next line is needed only if building with sccache -$ export GN_EXTRA_ARGS="${GN_EXTRA_ARGS} cc_wrapper=\"${PWD}/electron/external_binaries/sccache\"" $ gn gen out/Testing --args="import(\"//electron/build/args/testing.gn\") $GN_EXTRA_ARGS" ``` @@ -141,12 +141,6 @@ This will build all of what was previously 'libchromiumcontent' (i.e. the `content/` directory of `chromium` and its dependencies, incl. WebKit and V8), so it will take a while. -To speed up subsequent builds, you can use [sccache][sccache]. Add the GN arg -`cc_wrapper = "sccache"` by running `gn args out/Testing` to bring up an -editor and adding a line to the end of the file. - -[sccache]: https://github.com/mozilla/sccache - The built executable will be under `./out/Testing`: ```sh @@ -189,7 +183,6 @@ Not all combinations of source and target CPU/OS are supported by Chromium. | Windows x64 | Windows x86 | Automatically tested | | Linux x64 | Linux x86 | Automatically tested | - If you test other combinations and find them to work, please update this document :) See the GN reference for allowable values of [`target_os`][target_os values] diff --git a/docs/development/build-instructions-linux.md b/docs/development/build-instructions-linux.md index a83436ab788ff..d3aeb85a8ff3e 100644 --- a/docs/development/build-instructions-linux.md +++ b/docs/development/build-instructions-linux.md @@ -1,6 +1,8 @@ # Build Instructions (Linux) -Follow the guidelines below for building Electron on Linux. +Follow the guidelines below for building **Electron itself** on Linux, for the purposes of creating custom Electron binaries. For bundling and distributing your app code with the prebuilt Electron binaries, see the [application distribution][application-distribution] guide. + +[application-distribution]: ../tutorial/application-distribution.md ## Prerequisites @@ -55,6 +57,15 @@ $ sudo dnf install clang dbus-devel gtk3-devel libnotify-devel \ nss-devel python-dbusmock openjdk-8-jre ``` +On Arch Linux / Manjaro, install the following libraries: + +```sh +$ sudo pacman -Syu base-devel clang libdbus gtk2 libnotify \ + libgnome-keyring alsa-lib libcap libcups libxtst \ + libxss nss gcc-multilib curl gperf bison \ + python2 python-dbusmock jdk8-openjdk +``` + Other distributions may offer similar packages for installation via package managers such as pacman. Or one can compile from source code. diff --git a/docs/development/build-instructions-macos.md b/docs/development/build-instructions-macos.md index 3a150568b2332..0461e78095b56 100644 --- a/docs/development/build-instructions-macos.md +++ b/docs/development/build-instructions-macos.md @@ -1,6 +1,8 @@ # Build Instructions (macOS) -Follow the guidelines below for building Electron on macOS. +Follow the guidelines below for building **Electron itself** on macOS, for the purposes of creating custom Electron binaries. For bundling and distributing your app code with the prebuilt Electron binaries, see the [application distribution][application-distribution] guide. + +[application-distribution]: ../tutorial/application-distribution.md ## Prerequisites diff --git a/docs/development/build-instructions-windows.md b/docs/development/build-instructions-windows.md index 258d88dba2b3a..299f4d4a6a782 100644 --- a/docs/development/build-instructions-windows.md +++ b/docs/development/build-instructions-windows.md @@ -1,6 +1,8 @@ # Build Instructions (Windows) -Follow the guidelines below for building Electron on Windows. +Follow the guidelines below for building **Electron itself** on Windows, for the purposes of creating custom Electron binaries. For bundling and distributing your app code with the prebuilt Electron binaries, see the [application distribution][application-distribution] guide. + +[application-distribution]: ../tutorial/application-distribution.md ## Prerequisites diff --git a/docs/development/clang-tidy.md b/docs/development/clang-tidy.md index 21210b8f6c7b4..b529d91b889b1 100644 --- a/docs/development/clang-tidy.md +++ b/docs/development/clang-tidy.md @@ -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) diff --git a/docs/development/coding-style.md b/docs/development/coding-style.md index 2eb0eb3a796bb..498740061f574 100644 --- a/docs/development/coding-style.md +++ b/docs/development/coding-style.md @@ -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. @@ -66,11 +66,11 @@ formatted correctly. Electron APIs uses the same capitalization scheme as Node.js: -- When the module itself is a class like `BrowserWindow`, use `PascalCase`. -- When the module is a set of APIs, like `globalShortcut`, use `camelCase`. -- When the API is a property of object, and it is complex enough to be in a +* When the module itself is a class like `BrowserWindow`, use `PascalCase`. +* When the module is a set of APIs, like `globalShortcut`, use `camelCase`. +* When the API is a property of object, and it is complex enough to be in a separate chapter like `win.webContents`, use `mixedCase`. -- For other non-module APIs, use natural titles, like ` Tag` or +* For other non-module APIs, use natural titles, like ` Tag` or `Process Object`. When creating a new API, it is preferred to use getters and setters instead of diff --git a/docs/development/debugging-instructions-macos.md b/docs/development/debugging-instructions-macos.md index d3af2d2a1a28f..e059ac5f972cd 100644 --- a/docs/development/debugging-instructions-macos.md +++ b/docs/development/debugging-instructions-macos.md @@ -26,7 +26,9 @@ you prefer a graphical interface. * **.lldbinit**: Create or edit `~/.lldbinit` to allow Chromium code to be properly source-mapped. ```text - command script import ~/electron/src/tools/lldb/lldbinit.py + # e.g: ['~/electron/src/tools/lldb'] + script sys.path[:0] = ['<...path/to/electron/src/tools/lldb>'] + script import lldbinit ``` ## Attaching to and Debugging Electron diff --git a/docs/development/issues.md b/docs/development/issues.md index 7478433cdd53a..ec0ad5dc04f36 100644 --- a/docs/development/issues.md +++ b/docs/development/issues.md @@ -33,8 +33,7 @@ contributing, and more. Please use the issue tracker for bugs only! To submit a bug report: When opening a new issue in the [`electron/electron` issue tracker](https://github.com/electron/electron/issues/new/choose), users -will be presented with [a template](https://github.com/electron/electron/blob/master/.github/ISSUE_TEMPLATE/Bug_report.md) -that should be filled in. +will be presented with a template that should be filled in. If you believe that you have found a bug in Electron, please fill out the template to the best of your ability. diff --git a/docs/development/pull-requests.md b/docs/development/pull-requests.md index b3f8350ead9a4..6179f46907a32 100644 --- a/docs/development/pull-requests.md +++ b/docs/development/pull-requests.md @@ -36,9 +36,9 @@ $ git fetch upstream Build steps and dependencies differ slightly depending on your operating system. See these detailed guides on building Electron locally: -* [Building on macOS](https://electronjs.org/docs/development/build-instructions-macos) -* [Building on Linux](https://electronjs.org/docs/development/build-instructions-linux) -* [Building on Windows](https://electronjs.org/docs/development/build-instructions-windows) +* [Building on macOS](build-instructions-macos.md) +* [Building on Linux](build-instructions-linux.md) +* [Building on Windows](build-instructions-windows.md) Once you've built the project locally, you're ready to start making changes! @@ -63,7 +63,7 @@ or tests in the `spec/` folder. Please be sure to run `npm run lint` from time to time on any code changes to ensure that they follow the project's code style. -See [coding style](https://electronjs.org/docs/development/coding-style) for +See [coding style](coding-style.md) for more information about best practice when modifying code in different parts of the project. @@ -91,29 +91,29 @@ Before a pull request can be merged, it **must** have a pull request title with Examples of commit messages with semantic prefixes: -- `fix: don't overwrite prevent_default if default wasn't prevented` -- `feat: add app.isPackaged() method` -- `docs: app.isDefaultProtocolClient is now available on Linux` +* `fix: don't overwrite prevent_default if default wasn't prevented` +* `feat: add app.isPackaged() method` +* `docs: app.isDefaultProtocolClient is now available on Linux` Common prefixes: -- fix: A bug fix -- feat: A new feature -- docs: Documentation changes -- test: Adding missing tests or correcting existing tests -- build: Changes that affect the build system -- ci: Changes to our CI configuration files and scripts -- perf: A code change that improves performance -- refactor: A code change that neither fixes a bug nor adds a feature -- style: Changes that do not affect the meaning of the code (linting) -- vendor: Bumping a dependency like libchromiumcontent or node +* fix: A bug fix +* feat: A new feature +* docs: Documentation changes +* test: Adding missing tests or correcting existing tests +* build: Changes that affect the build system +* ci: Changes to our CI configuration files and scripts +* perf: A code change that improves performance +* refactor: A code change that neither fixes a bug nor adds a feature +* style: Changes that do not affect the meaning of the code (linting) +* vendor: Bumping a dependency like libchromiumcontent or node Other things to keep in mind when writing a commit message: 1. The first line should: - - contain a short description of the change (preferably 50 characters or less, + * contain a short description of the change (preferably 50 characters or less, and no more than 72 characters) - - be entirely in lowercase with the exception of proper nouns, acronyms, and + * be entirely in lowercase with the exception of proper nouns, acronyms, and the words that refer to code, like function/variable names 2. Keep the second line blank. 3. Wrap all other lines at 72 columns. @@ -144,7 +144,7 @@ master. ### Step 7: Test Bug fixes and features should always come with tests. A -[testing guide](https://electronjs.org/docs/development/testing) has been +[testing guide](testing.md) has been provided to make the process easier. Looking at other tests to see how they should be structured can also help. diff --git a/docs/development/source-code-directory-structure.md b/docs/development/source-code-directory-structure.md index fffab3d525c10..72ebb347b798a 100644 --- a/docs/development/source-code-directory-structure.md +++ b/docs/development/source-code-directory-structure.md @@ -100,7 +100,5 @@ script/ - The set of all scripts Electron runs for a variety of purposes. └── uploaders/ - Uploads various release-related files during release. ``` -* **tools** - Helper scripts used by GN files. - * Scripts put here should never be invoked by users directly, unlike those in `script`. * **typings** - TypeScript typings for Electron's internal code. * **vendor** - Source code for some third party dependencies. diff --git a/docs/fiddles/features/drag-and-drop/index.html b/docs/fiddles/features/drag-and-drop/index.html index d451042521a5d..7541c174b86fd 100644 --- a/docs/fiddles/features/drag-and-drop/index.html +++ b/docs/fiddles/features/drag-and-drop/index.html @@ -7,12 +7,9 @@

Hello World!

-

- We are using node , - Chrome , - and Electron . -

- Drag me +

Drag the boxes below to somewhere in your OS (Finder/Explorer, Desktop, etc.) to copy an example markdown file.

+
Drag me - File 1
+
Drag me - File 2
diff --git a/docs/fiddles/features/drag-and-drop/main.js b/docs/fiddles/features/drag-and-drop/main.js index bdc28bbf45000..9ad158beafd5e 100644 --- a/docs/fiddles/features/drag-and-drop/main.js +++ b/docs/fiddles/features/drag-and-drop/main.js @@ -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, }) }) diff --git a/docs/fiddles/features/drag-and-drop/preload.js b/docs/fiddles/features/drag-and-drop/preload.js new file mode 100644 index 0000000000000..4609e12c75528 --- /dev/null +++ b/docs/fiddles/features/drag-and-drop/preload.js @@ -0,0 +1,8 @@ +const { contextBridge, ipcRenderer } = require('electron') +const path = require('path') + +contextBridge.exposeInMainWorld('electron', { + startDrag: (fileName) => { + ipcRenderer.send('ondragstart', fileName) + } +}) diff --git a/docs/fiddles/features/drag-and-drop/renderer.js b/docs/fiddles/features/drag-and-drop/renderer.js index 33f328e30aedd..b402fa3929258 100644 --- a/docs/fiddles/features/drag-and-drop/renderer.js +++ b/docs/fiddles/features/drag-and-drop/renderer.js @@ -1,9 +1,9 @@ -const { ipcRenderer } = require('electron') -const fs = require('fs') +document.getElementById('drag1').ondragstart = (event) => { + event.preventDefault() + window.electron.startDrag('drag-and-drop-1.md') +} -document.getElementById('drag').ondragstart = (event) => { - const fileName = 'drag-and-drop.md' - fs.writeFileSync(fileName, '# Test drag and drop'); +document.getElementById('drag2').ondragstart = (event) => { event.preventDefault() - ipcRenderer.send('ondragstart', process.cwd() + `/${fileName}`) + window.electron.startDrag('drag-and-drop-2.md') } diff --git a/docs/fiddles/features/keyboard-shortcuts/global/index.html b/docs/fiddles/features/keyboard-shortcuts/global/index.html index a3855d2640d8a..fbe7e6323c996 100644 --- a/docs/fiddles/features/keyboard-shortcuts/global/index.html +++ b/docs/fiddles/features/keyboard-shortcuts/global/index.html @@ -7,10 +7,6 @@

Hello World!

-

- We are using node , - Chrome , - and Electron . -

+

Hit Alt+Ctrl+I on Windows or Opt+Cmd+I on Mac to see a message printed to the console.

diff --git a/docs/fiddles/features/keyboard-shortcuts/global/main.js b/docs/fiddles/features/keyboard-shortcuts/global/main.js index 5b4196f7781ab..24b2d343fbaaa 100644 --- a/docs/fiddles/features/keyboard-shortcuts/global/main.js +++ b/docs/fiddles/features/keyboard-shortcuts/global/main.js @@ -4,9 +4,6 @@ function createWindow () { const win = new BrowserWindow({ width: 800, height: 600, - webPreferences: { - nodeIntegration: true - } }) win.loadFile('index.html') diff --git a/docs/fiddles/features/keyboard-shortcuts/interception-from-main/index.html b/docs/fiddles/features/keyboard-shortcuts/interception-from-main/index.html index 6f9d1abf860a5..ff4540a3c9b2e 100644 --- a/docs/fiddles/features/keyboard-shortcuts/interception-from-main/index.html +++ b/docs/fiddles/features/keyboard-shortcuts/interception-from-main/index.html @@ -7,8 +7,6 @@

Hello World!

- We are using node , - Chrome , - and Electron . +

Hit Ctrl+I to see a message printed to the console.

diff --git a/docs/fiddles/features/keyboard-shortcuts/interception-from-main/main.js b/docs/fiddles/features/keyboard-shortcuts/interception-from-main/main.js index 767e574b11aad..80e4012c812d1 100644 --- a/docs/fiddles/features/keyboard-shortcuts/interception-from-main/main.js +++ b/docs/fiddles/features/keyboard-shortcuts/interception-from-main/main.js @@ -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) => { diff --git a/docs/fiddles/features/keyboard-shortcuts/local/index.html b/docs/fiddles/features/keyboard-shortcuts/local/index.html index a3855d2640d8a..3aeae635b41d2 100644 --- a/docs/fiddles/features/keyboard-shortcuts/local/index.html +++ b/docs/fiddles/features/keyboard-shortcuts/local/index.html @@ -7,10 +7,6 @@

Hello World!

-

- We are using node , - Chrome , - and Electron . -

+

Hit Alt+Shift+I on Windows, or Opt+Cmd+I on mac to see a message printed to the console.

diff --git a/docs/fiddles/features/keyboard-shortcuts/local/main.js b/docs/fiddles/features/keyboard-shortcuts/local/main.js index d4c5006ef7ee0..c583469df4820 100644 --- a/docs/fiddles/features/keyboard-shortcuts/local/main.js +++ b/docs/fiddles/features/keyboard-shortcuts/local/main.js @@ -4,9 +4,6 @@ function createWindow () { const win = new BrowserWindow({ width: 800, height: 600, - webPreferences: { - nodeIntegration: true - } }) win.loadFile('index.html') diff --git a/docs/fiddles/features/keyboard-shortcuts/web-apis/index.html b/docs/fiddles/features/keyboard-shortcuts/web-apis/index.html new file mode 100644 index 0000000000000..b19f3e92fd070 --- /dev/null +++ b/docs/fiddles/features/keyboard-shortcuts/web-apis/index.html @@ -0,0 +1,17 @@ + + + + + + + + Hello World! + + +

Hello World!

+ +

Hit any key with this window focused to see it captured here.

+
Last Key Pressed:
+ + + diff --git a/docs/fiddles/features/keyboard-shortcuts/web-apis/main.js b/docs/fiddles/features/keyboard-shortcuts/web-apis/main.js new file mode 100644 index 0000000000000..5944f55c83f15 --- /dev/null +++ b/docs/fiddles/features/keyboard-shortcuts/web-apis/main.js @@ -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() +}) diff --git a/docs/fiddles/features/keyboard-shortcuts/web-apis/renderer.js b/docs/fiddles/features/keyboard-shortcuts/web-apis/renderer.js new file mode 100644 index 0000000000000..7f7e406c4b2cc --- /dev/null +++ b/docs/fiddles/features/keyboard-shortcuts/web-apis/renderer.js @@ -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) diff --git a/docs/fiddles/features/macos-dark-mode/main.js b/docs/fiddles/features/macos-dark-mode/main.js index e74b345d367aa..9503efb5f9a92 100644 --- a/docs/fiddles/features/macos-dark-mode/main.js +++ b/docs/fiddles/features/macos-dark-mode/main.js @@ -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() - } -}) diff --git a/docs/fiddles/features/macos-dark-mode/preload.js b/docs/fiddles/features/macos-dark-mode/preload.js new file mode 100644 index 0000000000000..3def9e06ed8ea --- /dev/null +++ b/docs/fiddles/features/macos-dark-mode/preload.js @@ -0,0 +1,6 @@ +const { contextBridge, ipcRenderer } = require('electron') + +contextBridge.exposeInMainWorld('darkMode', { + toggle: () => ipcRenderer.invoke('dark-mode:toggle'), + system: () => ipcRenderer.invoke('dark-mode:system') +}) diff --git a/docs/fiddles/features/macos-dark-mode/renderer.js b/docs/fiddles/features/macos-dark-mode/renderer.js index 737f19f51cbe1..637f714c22406 100644 --- a/docs/fiddles/features/macos-dark-mode/renderer.js +++ b/docs/fiddles/features/macos-dark-mode/renderer.js @@ -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' }) diff --git a/docs/fiddles/features/macos-dock-menu/index.html b/docs/fiddles/features/macos-dock-menu/index.html index a3855d2640d8a..02eb6e015a9c6 100644 --- a/docs/fiddles/features/macos-dock-menu/index.html +++ b/docs/fiddles/features/macos-dock-menu/index.html @@ -7,10 +7,6 @@

Hello World!

-

- We are using node , - Chrome , - and Electron . -

+

Right click the dock icon to see the custom menu options.

diff --git a/docs/fiddles/features/macos-dock-menu/main.js b/docs/fiddles/features/macos-dock-menu/main.js index f57caf628cf65..f7f86a2361a80 100644 --- a/docs/fiddles/features/macos-dock-menu/main.js +++ b/docs/fiddles/features/macos-dock-menu/main.js @@ -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', () => { diff --git a/docs/fiddles/features/notifications/main/index.html b/docs/fiddles/features/notifications/main/index.html index a3855d2640d8a..3c23f9066d9c1 100644 --- a/docs/fiddles/features/notifications/main/index.html +++ b/docs/fiddles/features/notifications/main/index.html @@ -7,10 +7,6 @@

Hello World!

-

- We are using node , - Chrome , - and Electron . -

+

After launching this application, you should see the system notification.

diff --git a/docs/fiddles/features/notifications/main/main.js b/docs/fiddles/features/notifications/main/main.js index 2f9dec51e70e0..f6e6f867ccc88 100644 --- a/docs/fiddles/features/notifications/main/main.js +++ b/docs/fiddles/features/notifications/main/main.js @@ -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) diff --git a/docs/fiddles/features/notifications/renderer/index.html b/docs/fiddles/features/notifications/renderer/index.html index 4d6de7642e14d..206eadb3a3dd6 100644 --- a/docs/fiddles/features/notifications/renderer/index.html +++ b/docs/fiddles/features/notifications/renderer/index.html @@ -7,11 +7,9 @@

Hello World!

-

- We are using node , - Chrome , - and Electron . -

+

After launching this application, you should see the system notification.

+

Click it to see the effect in this interface.

+ diff --git a/docs/fiddles/features/notifications/renderer/main.js b/docs/fiddles/features/notifications/renderer/main.js index 4502be6814764..e24a66dd52b8f 100644 --- a/docs/fiddles/features/notifications/renderer/main.js +++ b/docs/fiddles/features/notifications/renderer/main.js @@ -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') diff --git a/docs/fiddles/features/notifications/renderer/renderer.js b/docs/fiddles/features/notifications/renderer/renderer.js index 7ea004cba1523..a6c88f9a79464 100644 --- a/docs/fiddles/features/notifications/renderer/renderer.js +++ b/docs/fiddles/features/notifications/renderer/renderer.js @@ -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 diff --git a/docs/fiddles/features/offscreen-rendering/index.html b/docs/fiddles/features/offscreen-rendering/index.html deleted file mode 100644 index 0da80aefd88a3..0000000000000 --- a/docs/fiddles/features/offscreen-rendering/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - Hello World! - - - -

Hello World!

-

- We are using node , - Chrome , - and Electron . -

- - diff --git a/docs/fiddles/features/offscreen-rendering/main.js b/docs/fiddles/features/offscreen-rendering/main.js index 38bbb991a2d04..10ad35d3d9a80 100644 --- a/docs/fiddles/features/offscreen-rendering/main.js +++ b/docs/fiddles/features/offscreen-rendering/main.js @@ -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', () => { diff --git a/docs/fiddles/features/online-detection/index.html b/docs/fiddles/features/online-detection/index.html new file mode 100644 index 0000000000000..372e5a963f770 --- /dev/null +++ b/docs/fiddles/features/online-detection/index.html @@ -0,0 +1,13 @@ + + + + + Hello World! + + + +

Connection status:

+ + + + diff --git a/docs/fiddles/features/online-detection/main.js b/docs/fiddles/features/online-detection/main.js new file mode 100644 index 0000000000000..7bc42d7725670 --- /dev/null +++ b/docs/fiddles/features/online-detection/main.js @@ -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() + } +}) diff --git a/docs/fiddles/features/online-detection/main/index.html b/docs/fiddles/features/online-detection/main/index.html deleted file mode 100644 index 4d6de7642e14d..0000000000000 --- a/docs/fiddles/features/online-detection/main/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Hello World! - - - -

Hello World!

-

- We are using node , - Chrome , - and Electron . -

- - - diff --git a/docs/fiddles/features/online-detection/main/main.js b/docs/fiddles/features/online-detection/main/main.js deleted file mode 100644 index 66066a3a7caf2..0000000000000 --- a/docs/fiddles/features/online-detection/main/main.js +++ /dev/null @@ -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() - } -}) diff --git a/docs/fiddles/features/online-detection/main/renderer.js b/docs/fiddles/features/online-detection/main/renderer.js deleted file mode 100644 index 0cf53e658669c..0000000000000 --- a/docs/fiddles/features/online-detection/main/renderer.js +++ /dev/null @@ -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() diff --git a/docs/fiddles/features/online-detection/renderer.js b/docs/fiddles/features/online-detection/renderer.js new file mode 100644 index 0000000000000..223a517ae1677 --- /dev/null +++ b/docs/fiddles/features/online-detection/renderer.js @@ -0,0 +1,8 @@ +function onlineStatusIndicator () { + document.getElementById('status').innerHTML = navigator.onLine ? 'online' : 'offline' +} + +window.addEventListener('online', onlineStatusIndicator) +window.addEventListener('offline', onlineStatusIndicator) + +onlineStatusIndicator() diff --git a/docs/fiddles/features/online-detection/renderer/index.html b/docs/fiddles/features/online-detection/renderer/index.html deleted file mode 100644 index 4d6de7642e14d..0000000000000 --- a/docs/fiddles/features/online-detection/renderer/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Hello World! - - - -

Hello World!

-

- We are using node , - Chrome , - and Electron . -

- - - diff --git a/docs/fiddles/features/online-detection/renderer/main.js b/docs/fiddles/features/online-detection/renderer/main.js deleted file mode 100644 index 0c5ff987b5b80..0000000000000 --- a/docs/fiddles/features/online-detection/renderer/main.js +++ /dev/null @@ -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() - } -}) diff --git a/docs/fiddles/features/online-detection/renderer/renderer.js b/docs/fiddles/features/online-detection/renderer/renderer.js deleted file mode 100644 index 724b6c36bc9fa..0000000000000 --- a/docs/fiddles/features/online-detection/renderer/renderer.js +++ /dev/null @@ -1,6 +0,0 @@ -const alertOnlineStatus = () => { window.alert(navigator.onLine ? 'online' : 'offline') } - -window.addEventListener('online', alertOnlineStatus) -window.addEventListener('offline', alertOnlineStatus) - -alertOnlineStatus() diff --git a/docs/fiddles/features/progress-bar/index.html b/docs/fiddles/features/progress-bar/index.html index a3855d2640d8a..d68c5129a6c2b 100644 --- a/docs/fiddles/features/progress-bar/index.html +++ b/docs/fiddles/features/progress-bar/index.html @@ -7,10 +7,9 @@

Hello World!

-

- We are using node , - Chrome , - and Electron . -

+

Keep an eye on the dock (Mac) or taskbar (Windows, Unity) for this application!

+

It should indicate a progress that advances from 0 to 100%.

+

It should then show indeterminate (Windows) or pin at 100% (other operating systems) + briefly and then loop.

diff --git a/docs/fiddles/features/progress-bar/main.js b/docs/fiddles/features/progress-bar/main.js index a53bf6b9856f0..c400638359011 100644 --- a/docs/fiddles/features/progress-bar/main.js +++ b/docs/fiddles/features/progress-bar/main.js @@ -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') { diff --git a/docs/fiddles/features/recent-documents/index.html b/docs/fiddles/features/recent-documents/index.html index a3855d2640d8a..62aae8f8a25c3 100644 --- a/docs/fiddles/features/recent-documents/index.html +++ b/docs/fiddles/features/recent-documents/index.html @@ -2,15 +2,14 @@ - Hello World! + Recent Documents -

Hello World!

+

Recent Documents

- We are using node , - Chrome , - and Electron . + Right click on the app icon to see recent documents. + You should see `recently-used.md` added to the list of recent files

diff --git a/docs/fiddles/features/recent-documents/main.js b/docs/fiddles/features/recent-documents/main.js index 60ba1f814dbe7..d11a5bcc6705a 100644 --- a/docs/fiddles/features/recent-documents/main.js +++ b/docs/fiddles/features/recent-documents/main.js @@ -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) diff --git a/docs/fiddles/features/represented-file/index.html b/docs/fiddles/features/represented-file/index.html index a3855d2640d8a..67583b9d9ddd0 100644 --- a/docs/fiddles/features/represented-file/index.html +++ b/docs/fiddles/features/represented-file/index.html @@ -4,13 +4,14 @@ Hello World! +

Hello World!

- We are using node , - Chrome , - and Electron . + Click on the title with the

Command
or
Control
key pressed. + You should see a popup with the represented file at the top.

+ diff --git a/docs/fiddles/features/represented-file/main.js b/docs/fiddles/features/represented-file/main.js index 61b6ef3316beb..204a3fc4586eb 100644 --- a/docs/fiddles/features/represented-file/main.js +++ b/docs/fiddles/features/represented-file/main.js @@ -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') diff --git a/docs/fiddles/quick-start/index.html b/docs/fiddles/quick-start/index.html index a3855d2640d8a..f008d867a0f89 100644 --- a/docs/fiddles/quick-start/index.html +++ b/docs/fiddles/quick-start/index.html @@ -8,9 +8,9 @@

Hello World!

- We are using node , - Chrome , - and Electron . + We are using Node.js , + Chromium , + and Electron .

diff --git a/docs/fiddles/quick-start/main.js b/docs/fiddles/quick-start/main.js index 4502be6814764..519a67947cdbb 100644 --- a/docs/fiddles/quick-start/main.js +++ b/docs/fiddles/quick-start/main.js @@ -1,18 +1,27 @@ const { app, BrowserWindow } = 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') } }) win.loadFile('index.html') } -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') { @@ -20,8 +29,3 @@ app.on('window-all-closed', () => { } }) -app.on('activate', () => { - if (BrowserWindow.getAllWindows().length === 0) { - createWindow() - } -}) diff --git a/docs/fiddles/quick-start/preload.js b/docs/fiddles/quick-start/preload.js new file mode 100644 index 0000000000000..7674d012240c4 --- /dev/null +++ b/docs/fiddles/quick-start/preload.js @@ -0,0 +1,11 @@ +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]) + } +}) + diff --git a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/index.html b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/index.html index 1c89c4ce49b13..a3ddd1b933fc0 100644 --- a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/index.html +++ b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/index.html @@ -1,92 +1,81 @@ - - - Hello World! - + + + + + + + app.setAsDefaultProtocol Demo + + -
-
-

- Protocol Handler -

-

The app module provides methods for handling protocols.

-

These methods allow you to set and unset the protocols your app should be the default app for. Similar to when a browser asks to be your default for viewing web pages.

+

App Default Protocol Demo

+ +

The protocol API allows us to register a custom protocol and intercept existing protocol requests.

+

These methods allow you to set and unset the protocols your app should be the default app for. Similar to when a + browser asks to be your default for viewing web pages.

+ +

Open the full protocol API documentation in your + browser.

+ + ----- + +

Demo

+

+ First: Launch current page in browser + +

+ +

+ Then: Launch the app from a web link! + Click here to launch the app +

+ + ---- -

Open the full app API documentation(opens in new window) in your browser.

-
+

You can set your app as the default app to open for a specific protocol. For instance, in this demo we set this app + as the default for electron-fiddle://. The demo button above will launch a page in your default + browser with a link. Click that link and it will re-launch this app.

-
- - -
-

You can set your app as the default app to open for a specific protocol. For instance, in this demo we set this app as the default for electron-api-demos://. The demo button above will launch a page in your default browser with a link. Click that link and it will re-launch this app.

-
Packaging
-

This feature will only work on macOS when your app is packaged. It will not work when you're launching it in development from the command-line. When you package your app you'll need to make sure the macOS plist for the app is updated to include the new protocol handler. If you're using electron-packager then you can add the flag --extend-info with a path to the plist you've created. The one for this app is below.

-
Renderer Process
-

-            const {shell} = require('electron')
-            const path = require('path')
-            const protocolHandlerBtn = document.getElementById('protocol-handler')
-            protocolHandlerBtn.addEventListener('click', () => {
-                const pageDirectory = __dirname.replace('app.asar', 'app.asar.unpacked')
-                const pagePath = path.join('file://', pageDirectory, '../../sections/system/protocol-link.html')
-                shell.openExternal(pagePath)
-            })
-          
-
Main Process
-

-            const {app, dialog} = require('electron')
-            const path = require('path')
 
-            if (process.defaultApp) {
-                if (process.argv.length >= 2) {
-                    app.setAsDefaultProtocolClient('electron-api-demos', process.execPath, [path.resolve(process.argv[1])])
-                }
-            } else {
-                app.setAsDefaultProtocolClient('electron-api-demos')
-            }
+  

Packaging

+

This feature will only work on macOS when your app is packaged. It will not work when you're launching it in + development from the command-line. When you package your app you'll need to make sure the macOS plist + for the app is updated to include the new protocol handler. If you're using electron-packager then you + can add the flag --extend-info with a path to the plist you've created. The one for this + app is below:

- app.on('open-url', (event, url) => { - dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`) - }) +

+

macOS plist
+

+    <?xml version="1.0" encoding="UTF-8"?>
+    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+            <plist version="1.0">
+                <dict>
+                    <key>CFBundleURLTypes</key>
+                    <array>
+                        <dict>
+                            <key>CFBundleURLSchemes</key>
+                            <array>
+                                <string>electron-api-demos</string>
+                            </array>
+                            <key>CFBundleURLName</key>
+                            <string>Electron API Demos Protocol</string>
+                        </dict>
+                    </array>
+                    <key>ElectronTeamID</key>
+                    <string>VEKTX9H2N7</string>
+                </dict>
+            </plist>
+        
+    
+

-

-
macOS plist
-

-            
-                
-                    
-                        
-                            CFBundleURLTypes
-                            
-                                
-                                    CFBundleURLSchemes
-                                    
-                                        electron-api-demos
-                                    
-                                    CFBundleURLName
-                                    Electron API Demos Protocol
-                                
-                            
-                            ElectronTeamID
-                            VEKTX9H2N7
-                        
-                    
-                
-            
-
-
- -
+ + - - - + \ No newline at end of file diff --git a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/main.js b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/main.js index fe3918e6a1a70..0dd559ef397bb 100644 --- a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/main.js +++ b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/main.js @@ -1,10 +1,39 @@ // Modules to control application life and create native browser window -const { app, BrowserWindow, dialog } = require('electron') +const { app, BrowserWindow, ipcMain, shell } = require('electron') const path = require('path') -// Keep a global reference of the window object, if you don't, the window will -// be closed automatically when the JavaScript object is garbage collected. -let mainWindow +let mainWindow; + +if (process.defaultApp) { + if (process.argv.length >= 2) { + app.setAsDefaultProtocolClient('electron-fiddle', process.execPath, [path.resolve(process.argv[1])]) + } +} else { + app.setAsDefaultProtocolClient('electron-fiddle') +} + +const gotTheLock = app.requestSingleInstanceLock() + +if (!gotTheLock) { + app.quit() +} else { + app.on('second-instance', (event, commandLine, workingDirectory) => { + // Someone tried to run a second instance, we should focus our window. + if (mainWindow) { + if (mainWindow.isMinimized()) mainWindow.restore() + mainWindow.focus() + } + }) + + // Create mainWindow, load the rest of the app, etc... + app.whenReady().then(() => { + createWindow() + }) + + app.on('open-url', (event, url) => { + dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`) + }) +} function createWindow () { // Create the browser window. @@ -12,58 +41,23 @@ function createWindow () { width: 800, height: 600, webPreferences: { - nodeIntegration: true + preload: path.join(__dirname, 'preload.js'), } }) - // and load the index.html of the app. mainWindow.loadFile('index.html') - - // Open the DevTools. - mainWindow.webContents.openDevTools() - - // Emitted when the window is closed. - mainWindow.on('closed', function () { - // Dereference the window object, usually you would store windows - // in an array if your app supports multi windows, this is the time - // when you should delete the corresponding element. - mainWindow = null - }) } -// This method will be called when Electron has finished -// initialization and is ready to create browser windows. -// Some APIs can only be used after this event occurs. -app.whenReady().then(createWindow) - -// Quit when all windows are closed. +// 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 () { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit() - } -}) - -app.on('activate', function () { - // On macOS it is common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - createWindow() - } + 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. - -if (process.defaultApp) { - if (process.argv.length >= 2) { - app.setAsDefaultProtocolClient('electron-api-demos', process.execPath, [path.resolve(process.argv[1])]) - } -} else { - app.setAsDefaultProtocolClient('electron-api-demos') -} - -app.on('open-url', (event, url) => { - dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`) +// Handle window controls via IPC +ipcMain.on('shell:open', () => { + const pageDirectory = __dirname.replace('app.asar', 'app.asar.unpacked') + const pagePath = path.join('file://', pageDirectory, 'index.html') + shell.openExternal(pagePath) }) diff --git a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/preload.js b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/preload.js new file mode 100644 index 0000000000000..1eebf784ad672 --- /dev/null +++ b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/preload.js @@ -0,0 +1,11 @@ +// All of the Node.js APIs are available in the preload process. +// It has the same sandbox as a Chrome extension. +const { contextBridge, ipcRenderer } = require('electron') + +// Set up context bridge between the renderer process and the main process +contextBridge.exposeInMainWorld( + 'shell', + { + open: () => ipcRenderer.send('shell:open'), + } +) \ No newline at end of file diff --git a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/renderer.js b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/renderer.js index 8aa314d3c2c06..525f25ff2e76e 100644 --- a/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/renderer.js +++ b/docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app/renderer.js @@ -1,14 +1,8 @@ -const { shell } = require('electron') -const path = require('path') +// This file is required by the index.html file and will +// be executed in the renderer process for that window. +// All APIs exposed by the context bridge are available here. -const openInBrowserButton = document.getElementById('open-in-browser') -const openAppLink = document.getElementById('open-app-link') -// Hides openAppLink when loaded inside Electron -openAppLink.style.display = 'none' - -openInBrowserButton.addEventListener('click', () => { - console.log('clicked') - const pageDirectory = __dirname.replace('app.asar', 'app.asar.unpacked') - const pagePath = path.join('file://', pageDirectory, 'index.html') - shell.openExternal(pagePath) -}) +// Binds the buttons to the context bridge API. +document.getElementById('open-in-browser').addEventListener('click', () => { + shell.open(); +}); \ No newline at end of file diff --git a/docs/images/chrome-processes.png b/docs/images/chrome-processes.png new file mode 100644 index 0000000000000..1b0a1c0060f95 Binary files /dev/null and b/docs/images/chrome-processes.png differ diff --git a/docs/images/connection-status.png b/docs/images/connection-status.png new file mode 100644 index 0000000000000..6dcf2574e86a0 Binary files /dev/null and b/docs/images/connection-status.png differ diff --git a/docs/images/recent-documents.png b/docs/images/recent-documents.png index 331466f3b1b35..3542c1315e34a 100644 Binary files a/docs/images/recent-documents.png and b/docs/images/recent-documents.png differ diff --git a/docs/images/represented-file.png b/docs/images/represented-file.png index a2d3a3cdd7707..8ccb477ab7e5a 100644 Binary files a/docs/images/represented-file.png and b/docs/images/represented-file.png differ diff --git a/docs/images/versioning-sketch-2.png b/docs/images/versioning-sketch-2.png old mode 100755 new mode 100644 diff --git a/docs/styleguide.md b/docs/styleguide.md index 80f6699b76504..e1601a16fa589 100644 --- a/docs/styleguide.md +++ b/docs/styleguide.md @@ -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,11 +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: + + * 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. ## Picking words @@ -59,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 @@ -98,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: @@ -141,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: @@ -154,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 @@ -164,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` or `Promise`). + +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 @@ -190,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: @@ -210,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. @@ -225,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 diff --git a/docs/tutorial/application-debugging.md b/docs/tutorial/application-debugging.md index 0f4315632821c..c9619e37779af 100644 --- a/docs/tutorial/application-debugging.md +++ b/docs/tutorial/application-debugging.md @@ -43,6 +43,6 @@ If the V8 context crashes, the DevTools will display this message. `DevTools was disconnected from the page. Once page is reloaded, DevTools will automatically reconnect.` -Chromium logs can be enabled via the `ELECTRON_ENABLE_LOGGING` environment variable. For more information, see the [environment variables documentation](https://www.electronjs.org/docs/api/environment-variables#electron_enable_logging). +Chromium logs can be enabled via the `ELECTRON_ENABLE_LOGGING` environment variable. For more information, see the [environment variables documentation](../api/environment-variables.md#electron_enable_logging). -Alternatively, the command line argument `--enable-logging` can be passed. More information is available in the [command line switches documentation](https://www.electronjs.org/docs/api/command-line-switches#--enable-logging). +Alternatively, the command line argument `--enable-logging` can be passed. More information is available in the [command line switches documentation](../api/command-line-switches.md#--enable-logging). diff --git a/docs/tutorial/application-distribution.md b/docs/tutorial/application-distribution.md index b74f6a1956ebc..5dd54c629b2a4 100644 --- a/docs/tutorial/application-distribution.md +++ b/docs/tutorial/application-distribution.md @@ -1,25 +1,38 @@ # Application Distribution -To distribute your app with Electron, you need to package and rebrand it. The easiest way to do this is to use one of the following third party packaging tools: +## Overview + +To distribute your app with Electron, you need to package and rebrand it. +To do this, you can either use specialized tooling or manual approaches. + +## With tooling + +You can use the following tools to distribute your application: * [electron-forge](https://github.com/electron-userland/electron-forge) * [electron-builder](https://github.com/electron-userland/electron-builder) * [electron-packager](https://github.com/electron/electron-packager) -These tools will take care of all the steps you need to take to end up with a distributable Electron applications, such as packaging your application, rebranding the executable, setting the right icons and optionally creating installers. +These tools will take care of all the steps you need to take to end up with a +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 +the [Quick Start guide](quick-start.md#package-and-distribute-your-application). ## Manual distribution -You can also choose to manually get your app ready for distribution. The steps needed to do this are outlined below. +### With prebuilt binaries -To distribute your app with Electron, you need to download Electron's [prebuilt +To distribute your app manually, you need to download Electron's [prebuilt binaries](https://github.com/electron/electron/releases). Next, the folder containing your app should be named `app` and placed in Electron's resources -directory as shown in the following examples. Note that the location of -Electron's prebuilt binaries is indicated with `electron/` in the examples -below. +directory as shown in the following examples. + +> *NOTE:* the location of Electron's prebuilt binaries is indicated +with `electron/` in the examples below. -On macOS: +*On macOS:* ```plaintext electron/Electron.app/Contents/Resources/app/ @@ -28,7 +41,7 @@ electron/Electron.app/Contents/Resources/app/ └── index.html ``` -On Windows and Linux: +*On Windows and Linux:* ```plaintext electron/resources/app @@ -37,47 +50,44 @@ electron/resources/app └── index.html ``` -Then execute `Electron.app` (or `electron` on Linux, `electron.exe` on Windows), -and Electron will start as your app. The `electron` directory will then be -your distribution to deliver to final users. +Then execute `Electron.app` on macOS, `electron` on Linux, or `electron.exe` +on Windows, and Electron will start as your app. The `electron` directory +will then be your distribution to deliver to users. -## Packaging Your App into a File +### With an app source code archive -Apart from shipping your app by copying all of its source files, you can also -package your app into an [asar](https://github.com/electron/asar) archive to avoid -exposing your app's source code to users. +Instead of from shipping your app by copying all of its source files, you can +package your app into an [asar] archive to improve the performance of reading +files on platforms like Windows, if you are not already using a bundler such +as Parcel or Webpack. To use an `asar` archive to replace the `app` folder, you need to rename the archive to `app.asar`, and put it under Electron's resources directory like below, and Electron will then try to read the archive and start from it. -On macOS: +*On macOS:* ```plaintext electron/Electron.app/Contents/Resources/ └── app.asar ``` -On Windows and Linux: +*On Windows and Linux:* ```plaintext electron/resources/ └── app.asar ``` -More details can be found in [Application packaging](application-packaging.md). +You can find more details on how to use `asar` in the +[`electron/asar` repository][asar]. -## Rebranding with Downloaded Binaries +### Rebranding with downloaded binaries After bundling your app into Electron, you will want to rebrand Electron before distributing it to users. -### Windows - -You can rename `electron.exe` to any name you like, and edit its icon and other -information with tools like [rcedit](https://github.com/electron/rcedit). - -### macOS +#### macOS You can rename `Electron.app` to any name you want, and you also have to rename the `CFBundleDisplayName`, `CFBundleIdentifier` and `CFBundleName` fields in the @@ -104,60 +114,20 @@ MyApp.app/Contents    └── MyApp Helper ``` -### Linux +#### Windows + +You can rename `electron.exe` to any name you like, and edit its icon and other +information with tools like [rcedit](https://github.com/electron/rcedit). + +#### Linux You can rename the `electron` executable to any name you like. -## Rebranding by Rebuilding Electron from Source +### Rebranding by rebuilding Electron from source It is also possible to rebrand Electron by changing the product name and building it from source. To do this you need to set the build argument corresponding to the product name (`electron_product_name = "YourProductName"`) in the `args.gn` file and rebuild. -### Creating a Custom Electron Fork - -Creating a custom fork of Electron is almost certainly not something you will -need to do in order to build your app, even for "Production Level" applications. -Using a tool such as `electron-packager` or `electron-forge` will allow you to -"Rebrand" Electron without having to do these steps. - -You need to fork Electron when you have custom C++ code that you have patched -directly into Electron, that either cannot be upstreamed, or has been rejected -from the official version. As maintainers of Electron, we very much would like -to make your scenario work, so please try as hard as you can to get your changes -into the official version of Electron, it will be much much easier on you, and -we appreciate your help. - -#### Creating a Custom Release with surf-build - -1. Install [Surf](https://github.com/surf-build/surf), via npm: - `npm install -g surf-build@latest` - -2. Create a new S3 bucket and create the following empty directory structure: - - ```sh - - electron/ - - symbols/ - - dist/ - ``` - -3. Set the following Environment Variables: - - * `ELECTRON_GITHUB_TOKEN` - a token that can create releases on GitHub - * `ELECTRON_S3_ACCESS_KEY`, `ELECTRON_S3_BUCKET`, `ELECTRON_S3_SECRET_KEY` - - the place where you'll upload Node.js headers as well as symbols - * `ELECTRON_RELEASE` - Set to `true` and the upload part will run, leave unset - and `surf-build` will do CI-type checks, appropriate to run for every - pull request. - * `CI` - Set to `true` or else it will fail - * `GITHUB_TOKEN` - set it to the same as `ELECTRON_GITHUB_TOKEN` - * `SURF_TEMP` - set to `C:\Temp` on Windows to prevent path too long issues - * `TARGET_ARCH` - set to `ia32` or `x64` - -4. In `script/upload.py`, you _must_ set `ELECTRON_REPO` to your fork (`MYORG/electron`), - especially if you are a contributor to Electron proper. - -5. `surf-build -r https://github.com/MYORG/electron -s YOUR_COMMIT -n 'surf-PLATFORM-ARCH'` - -6. Wait a very, very long time for the build to complete. +[asar]: https://github.com/electron/asar diff --git a/docs/tutorial/application-packaging.md b/docs/tutorial/application-packaging.md deleted file mode 100644 index e0c782fe7d1e9..0000000000000 --- a/docs/tutorial/application-packaging.md +++ /dev/null @@ -1,194 +0,0 @@ -# Application Packaging - -To mitigate [issues](https://github.com/joyent/node/issues/6960) around long -path names on Windows, slightly speed up `require` and conceal your source code -from cursory inspection, you can choose to package your app into an [asar][asar] -archive with little changes to your source code. - -Most users will get this feature for free, since it's supported out of the box -by [`electron-packager`][electron-packager], [`electron-forge`][electron-forge], -and [`electron-builder`][electron-builder]. If you are not using any of these -tools, read on. - -## Generating `asar` Archives - -An [asar][asar] archive is a simple tar-like format that concatenates files -into a single file. Electron can read arbitrary files from it without unpacking -the whole file. - -Steps to package your app into an `asar` archive: - -### 1. Install the asar Utility - -```sh -$ npm install -g asar -``` - -### 2. Package with `asar pack` - -```sh -$ asar pack your-app app.asar -``` - -## Using `asar` Archives - -In Electron there are two sets of APIs: Node APIs provided by Node.js and Web -APIs provided by Chromium. Both APIs support reading files from `asar` archives. - -### Node API - -With special patches in Electron, Node APIs like `fs.readFile` and `require` -treat `asar` archives as virtual directories, and the files in it as normal -files in the filesystem. - -For example, suppose we have an `example.asar` archive under `/path/to`: - -```sh -$ asar list /path/to/example.asar -/app.js -/file.txt -/dir/module.js -/static/index.html -/static/main.css -/static/jquery.min.js -``` - -Read a file in the `asar` archive: - -```javascript -const fs = require('fs') -fs.readFileSync('/path/to/example.asar/file.txt') -``` - -List all files under the root of the archive: - -```javascript -const fs = require('fs') -fs.readdirSync('/path/to/example.asar') -``` - -Use a module from the archive: - -```javascript -require('./path/to/example.asar/dir/module.js') -``` - -You can also display a web page in an `asar` archive with `BrowserWindow`: - -```javascript -const { BrowserWindow } = require('electron') -const win = new BrowserWindow() - -win.loadURL('file:///path/to/example.asar/static/index.html') -``` - -### Web API - -In a web page, files in an archive can be requested with the `file:` protocol. -Like the Node API, `asar` archives are treated as directories. - -For example, to get a file with `$.get`: - -```html - -``` - -### Treating an `asar` Archive as a Normal File - -For some cases like verifying the `asar` archive's checksum, we need to read the -content of an `asar` archive as a file. For this purpose you can use the built-in -`original-fs` module which provides original `fs` APIs without `asar` support: - -```javascript -const originalFs = require('original-fs') -originalFs.readFileSync('/path/to/example.asar') -``` - -You can also set `process.noAsar` to `true` to disable the support for `asar` in -the `fs` module: - -```javascript -const fs = require('fs') -process.noAsar = true -fs.readFileSync('/path/to/example.asar') -``` - -## Limitations of the Node API - -Even though we tried hard to make `asar` archives in the Node API work like -directories as much as possible, there are still limitations due to the -low-level nature of the Node API. - -### Archives Are Read-only - -The archives can not be modified so all Node APIs that can modify files will not -work with `asar` archives. - -### Working Directory Can Not Be Set to Directories in Archive - -Though `asar` archives are treated as directories, there are no actual -directories in the filesystem, so you can never set the working directory to -directories in `asar` archives. Passing them as the `cwd` option of some APIs -will also cause errors. - -### Extra Unpacking on Some APIs - -Most `fs` APIs can read a file or get a file's information from `asar` archives -without unpacking, but for some APIs that rely on passing the real file path to -underlying system calls, Electron will extract the needed file into a -temporary file and pass the path of the temporary file to the APIs to make them -work. This adds a little overhead for those APIs. - -APIs that requires extra unpacking are: - -* `child_process.execFile` -* `child_process.execFileSync` -* `fs.open` -* `fs.openSync` -* `process.dlopen` - Used by `require` on native modules - -### Fake Stat Information of `fs.stat` - -The `Stats` object returned by `fs.stat` and its friends on files in `asar` -archives is generated by guessing, because those files do not exist on the -filesystem. So you should not trust the `Stats` object except for getting file -size and checking file type. - -### Executing Binaries Inside `asar` Archive - -There are Node APIs that can execute binaries like `child_process.exec`, -`child_process.spawn` and `child_process.execFile`, but only `execFile` is -supported to execute binaries inside `asar` archive. - -This is because `exec` and `spawn` accept `command` instead of `file` as input, -and `command`s are executed under shell. There is no reliable way to determine -whether a command uses a file in asar archive, and even if we do, we can not be -sure whether we can replace the path in command without side effects. - -## Adding Unpacked Files to `asar` Archives - -As stated above, some Node APIs will unpack the file to the filesystem when -called. Apart from the performance issues, various anti-virus scanners might -be triggered by this behavior. - -As a workaround, you can leave various files unpacked using the `--unpack` option. -In the following example, shared libraries of native Node.js modules will not be -packed: - -```sh -$ asar pack app app.asar --unpack *.node -``` - -After running the command, you will notice that a folder named `app.asar.unpacked` -was created together with the `app.asar` file. It contains the unpacked files -and should be shipped together with the `app.asar` archive. - -[asar]: https://github.com/electron/asar -[electron-packager]: https://github.com/electron/electron-packager -[electron-forge]: https://github.com/electron-userland/electron-forge -[electron-builder]: https://github.com/electron-userland/electron-builder diff --git a/docs/tutorial/code-signing.md b/docs/tutorial/code-signing.md index e869416d3515e..d3a3ccbac2861 100644 --- a/docs/tutorial/code-signing.md +++ b/docs/tutorial/code-signing.md @@ -189,18 +189,18 @@ You can get a code signing certificate from a lot of resellers. Prices vary, so it may be worth your time to shop around. Popular resellers include: * [digicert](https://www.digicert.com/code-signing/microsoft-authenticode.htm) -* [Comodo](https://www.comodo.com/landing/ssl-certificate/authenticode-signature/) +* [Sectigo](https://sectigo.com/ssl-certificates-tls/code-signing) * [GoDaddy](https://au.godaddy.com/web-security/code-signing-certificate) * Amongst others, please shop around to find one that suits your needs, Google is your friend 😄 There are a number of tools for signing your packaged app: -- [`electron-winstaller`] will generate an installer for windows and sign it for +* [`electron-winstaller`] will generate an installer for windows and sign it for you -- [`electron-forge`] can sign installers it generates through the +* [`electron-forge`] can sign installers it generates through the Squirrel.Windows or MSI targets. -- [`electron-builder`] can sign some of its windows targets +* [`electron-builder`] can sign some of its windows targets ## Windows Store diff --git a/docs/tutorial/dark-mode.md b/docs/tutorial/dark-mode.md index e27d3f2d2688a..bbb2f6381435f 100644 --- a/docs/tutorial/dark-mode.md +++ b/docs/tutorial/dark-mode.md @@ -19,7 +19,7 @@ the system's dark mode setting. You can do this by using the If you want to manually switch between light/dark modes, you can do this by setting the desired mode in the -[themeSource](https://www.electronjs.org/docs/api/native-theme#nativethemethemesource) +[themeSource](../api/native-theme.md#nativethemethemesource) property of the `nativeTheme` module. This property's value will be propagated to your Renderer process. Any CSS rules related to `prefers-color-scheme` will be updated accordingly. @@ -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: +``` + +### How does this work? -```html +Starting with the `index.html` file: + +```html title='index.html' @@ -80,65 +80,70 @@ Add the following lines to the `index.html` file: ``` -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: + +```css title='style.css' +@media (prefers-color-scheme: dark) { + body { background: #333; color: white; } +} + +@media (prefers-color-scheme: light) { + body { background: #ddd; color: black; } +} +``` + +The example renders an HTML page with a couple elements. The `` + element shows which theme is currently selected, and the two `