mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
105 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a89ff06c9 | ||
|
|
7c2df8860b | ||
|
|
56e45baeb8 | ||
|
|
5f712fa325 | ||
|
|
ba8915242a | ||
|
|
c9eb3deab5 | ||
|
|
58fd8825d2 | ||
|
|
6a8b70639b | ||
|
|
1766511e34 | ||
|
|
28eda03aba | ||
|
|
7685f27b31 | ||
|
|
463586a6c5 | ||
|
|
a39c0ee659 | ||
|
|
0b0a8a5ef3 | ||
|
|
986becdb4d | ||
|
|
75ea294b6f | ||
|
|
18717ee62d | ||
|
|
73e33bc876 | ||
|
|
c8544e25df | ||
|
|
9c7086074e | ||
|
|
d7e4bb6608 | ||
|
|
706653d5e4 | ||
|
|
65952abc99 | ||
|
|
50ce02c312 | ||
|
|
fb6b92076e | ||
|
|
d6c04a3787 | ||
|
|
2791474a01 | ||
|
|
f6e8a42c48 | ||
|
|
650ef9a51c | ||
|
|
a1c44a18e2 | ||
|
|
ec9c8476fe | ||
|
|
470a14d8d4 | ||
|
|
5bff0fe342 | ||
|
|
16aec702b4 | ||
|
|
ac040bf734 | ||
|
|
aceb432f45 | ||
|
|
d182794179 | ||
|
|
ab185c058f | ||
|
|
2324c4d8fd | ||
|
|
792037b338 | ||
|
|
0b44f433c8 | ||
|
|
5fa9dee68a | ||
|
|
75bad34131 | ||
|
|
0a064cece9 | ||
|
|
f6e8544ef6 | ||
|
|
029127a8b6 | ||
|
|
e71a56d11e | ||
|
|
65901f4c6a | ||
|
|
feb804cea8 | ||
|
|
34b79c15c2 | ||
|
|
d9ba26273a | ||
|
|
c96bb9958f | ||
|
|
d76a35afe4 | ||
|
|
c5b20eeb13 | ||
|
|
4cc0f6fb78 | ||
|
|
f27b034045 | ||
|
|
54d8402a6c | ||
|
|
89659fa9c9 | ||
|
|
89117fdd99 | ||
|
|
0b0707145b | ||
|
|
7858921a1f | ||
|
|
ac031bf8de | ||
|
|
b8ac798344 | ||
|
|
2182202e8e | ||
|
|
e66c1f6c56 | ||
|
|
9280b79112 | ||
|
|
2e79f34c84 | ||
|
|
f30fbebb98 | ||
|
|
f0ad357af2 | ||
|
|
5078cae861 | ||
|
|
b5997a012d | ||
|
|
f369b144d6 | ||
|
|
f2f83a73fc | ||
|
|
d42a94ddde | ||
|
|
3bdc7ce64a | ||
|
|
48e14bc54e | ||
|
|
83760bd5c6 | ||
|
|
e14964ccd0 | ||
|
|
33000c4b42 | ||
|
|
33e66b5cd0 | ||
|
|
2affecd4dd | ||
|
|
381c955bca | ||
|
|
35969939a1 | ||
|
|
a8999bc529 | ||
|
|
522bba3dc6 | ||
|
|
ddc7e3ebb3 | ||
|
|
2481f94b4e | ||
|
|
e1d63794e5 | ||
|
|
bfa58df7c9 | ||
|
|
c1898c39bf | ||
|
|
3102a257af | ||
|
|
90865fa97d | ||
|
|
3a91d1f1e1 | ||
|
|
09190085c0 | ||
|
|
9937a2bbe8 | ||
|
|
95bf9d8adb | ||
|
|
c75e193a3e | ||
|
|
0621f39296 | ||
|
|
aeb89b143b | ||
|
|
213388cd87 | ||
|
|
8374b9c2ad | ||
|
|
00746e662b | ||
|
|
31dfde7fa6 | ||
|
|
dd8df3b0c4 | ||
|
|
b04ce6a5c8 |
@@ -655,12 +655,11 @@ step-nodejs-headers-build: &step-nodejs-headers-build
|
||||
name: Build Node.js headers
|
||||
command: |
|
||||
cd src
|
||||
ninja -C out/Default third_party/electron_node:headers
|
||||
ninja -C out/Default electron:node_headers
|
||||
|
||||
step-electron-publish: &step-electron-publish
|
||||
run:
|
||||
name: Publish Electron Dist
|
||||
no_output_timeout: 30m
|
||||
command: |
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
rm -rf src/out/Default/obj
|
||||
@@ -755,8 +754,8 @@ step-show-goma-stats: &step-show-goma-stats
|
||||
command: |
|
||||
set +e
|
||||
set +o pipefail
|
||||
python3 $GOMA_DIR/goma_ctl.py stat
|
||||
python3 $GOMA_DIR/diagnose_goma_log.py
|
||||
$GOMA_DIR/goma_ctl.py stat
|
||||
$GOMA_DIR/diagnose_goma_log.py
|
||||
true
|
||||
when: always
|
||||
background: true
|
||||
@@ -1210,7 +1209,7 @@ commands:
|
||||
build-type: << parameters.build-type >>
|
||||
- *step-maybe-electron-dist-strip
|
||||
- step-electron-dist-build:
|
||||
additional-targets: shell_browser_ui_unittests third_party/electron_node:headers third_party/electron_node:overlapped-checker electron:hunspell_dictionaries_zip
|
||||
additional-targets: shell_browser_ui_unittests electron:node_headers third_party/electron_node:overlapped-checker electron:hunspell_dictionaries_zip
|
||||
|
||||
- *step-show-goma-stats
|
||||
|
||||
|
||||
13
.github/workflows/branch-created.yml
vendored
13
.github/workflows/branch-created.yml
vendored
@@ -60,16 +60,15 @@ jobs:
|
||||
done
|
||||
- name: Generate GitHub App token
|
||||
if: ${{ steps.check-major-version.outputs.MAJOR }}
|
||||
uses: electron/github-app-auth-action@cc6751b3b5e4edc5b9a4ad0a021ac455653b6dc8 # v1.0.0
|
||||
id: generate-token
|
||||
env:
|
||||
RELEASE_BOARD_GH_APP_CREDS: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }}
|
||||
run: |
|
||||
TOKEN=$(npx @electron/github-app-auth --creds=$RELEASE_BOARD_GH_APP_CREDS --org=electron)
|
||||
echo "TOKEN=$TOKEN" >> "$GITHUB_OUTPUT"
|
||||
with:
|
||||
creds: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }}
|
||||
org: electron
|
||||
- name: Create Release Project Board
|
||||
if: ${{ steps.check-major-version.outputs.MAJOR }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.generate-token.outputs.TOKEN }}
|
||||
GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
MAJOR: ${{ steps.check-major-version.outputs.MAJOR }}
|
||||
ELECTRON_ORG_ID: "O_kgDOAMybxg"
|
||||
ELECTRON_REPO_ID: "R_kgDOAI8xSw"
|
||||
@@ -135,7 +134,7 @@ jobs:
|
||||
#
|
||||
# Do template replacement for draft issues
|
||||
#
|
||||
echo "{\"major\": $MAJOR, \"next-major\": $((MAJOR + 1))}" > variables.json
|
||||
echo "{\"major\": $MAJOR, \"next-major\": $((MAJOR + 1)), \"prev-major\": $((MAJOR - 1))}" > variables.json
|
||||
|
||||
# npx mustache is annoyingly slow, so install mustache directly
|
||||
yarn add -D mustache
|
||||
|
||||
14
.github/workflows/issue-commented.yml
vendored
14
.github/workflows/issue-commented.yml
vendored
@@ -5,20 +5,22 @@ on:
|
||||
types:
|
||||
- created
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
issue-commented:
|
||||
name: Remove blocked/need-repro on comment
|
||||
if: ${{ contains(github.event.issue.labels.*.name, 'blocked/need-repro') && !contains(fromJSON('["MEMBER", "OWNER"]'), github.event.comment.author_association) }}
|
||||
permissions:
|
||||
issues: write
|
||||
if: ${{ contains(github.event.issue.labels.*.name, 'blocked/need-repro') && !contains(fromJSON('["MEMBER", "OWNER"]'), github.event.comment.author_association) && github.event.comment.user.type != 'Bot' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Generate GitHub App token
|
||||
uses: electron/github-app-auth-action@cc6751b3b5e4edc5b9a4ad0a021ac455653b6dc8 # v1.0.0
|
||||
id: generate-token
|
||||
with:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
- name: Remove label
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
ISSUE_URL: ${{ github.event.issue.html_url }}
|
||||
run: |
|
||||
gh issue edit $ISSUE_URL --remove-label 'blocked/need-repro'
|
||||
|
||||
22
.github/workflows/issue-labeled.yml
vendored
22
.github/workflows/issue-labeled.yml
vendored
@@ -14,18 +14,15 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Generate GitHub App token
|
||||
uses: electron/github-app-auth-action@cc6751b3b5e4edc5b9a4ad0a021ac455653b6dc8 # v1.0.0
|
||||
id: generate-token
|
||||
env:
|
||||
RELEASE_BOARD_GH_APP_CREDS: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }}
|
||||
run: |
|
||||
set -eo pipefail
|
||||
TOKEN=$(npx @electron/github-app-auth --creds=$RELEASE_BOARD_GH_APP_CREDS --org=electron)
|
||||
echo "TOKEN=$TOKEN" >> "$GITHUB_OUTPUT"
|
||||
with:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
org: electron
|
||||
- name: Set status
|
||||
if: ${{ steps.generate-token.outputs.TOKEN }}
|
||||
uses: github/update-project-action@2d475e08804f11f4022df7e21f5816531e97cb64 # v2
|
||||
with:
|
||||
github_token: ${{ steps.generate-token.outputs.TOKEN }}
|
||||
github_token: ${{ steps.generate-token.outputs.token }}
|
||||
organization: electron
|
||||
project_number: 90
|
||||
content_id: ${{ github.event.issue.node_id }}
|
||||
@@ -45,15 +42,22 @@ jobs:
|
||||
GH_REPO: electron/electron
|
||||
run: |
|
||||
set -eo pipefail
|
||||
COMMENT_COUNT=$(gh issue view ${{ github.event.issue.number }} --comments --json comments | jq '[ .comments[] | select(.author.login == "github-actions" or .authorAssociation == "OWNER" or .authorAssociation == "MEMBER") | select(.body | startswith("<!-- blocked/need-repro -->")) ] | length')
|
||||
COMMENT_COUNT=$(gh issue view ${{ github.event.issue.number }} --comments --json comments | jq '[ .comments[] | select(.author.login == "electron-issue-triage" or .authorAssociation == "OWNER" or .authorAssociation == "MEMBER") | select(.body | startswith("<!-- blocked/need-repro -->")) ] | length')
|
||||
if [[ $COMMENT_COUNT -eq 0 ]]; then
|
||||
echo "SHOULD_COMMENT=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
- name: Generate GitHub App token
|
||||
if: ${{ steps.check-for-comment.outputs.SHOULD_COMMENT }}
|
||||
uses: electron/github-app-auth-action@cc6751b3b5e4edc5b9a4ad0a021ac455653b6dc8 # v1.0.0
|
||||
id: generate-token
|
||||
with:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
- name: Create comment
|
||||
if: ${{ steps.check-for-comment.outputs.SHOULD_COMMENT }}
|
||||
uses: actions-cool/issues-helper@275328970dbc3bfc3bc43f5fe741bf3638300c0a # v3.3.3
|
||||
with:
|
||||
actions: 'create-comment'
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
body: |
|
||||
<!-- blocked/need-repro -->
|
||||
|
||||
|
||||
16
.github/workflows/issue-unlabeled.yml
vendored
16
.github/workflows/issue-unlabeled.yml
vendored
@@ -10,7 +10,7 @@ permissions:
|
||||
jobs:
|
||||
issue-unlabeled-blocked:
|
||||
name: All blocked/* labels removed
|
||||
if: startsWith(github.event.label.name, 'blocked/')
|
||||
if: startsWith(github.event.label.name, 'blocked/') && github.event.issue.state == 'open'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check for any blocked labels
|
||||
@@ -23,18 +23,16 @@ jobs:
|
||||
fi
|
||||
- name: Generate GitHub App token
|
||||
if: ${{ steps.check-for-blocked-labels.outputs.NOT_BLOCKED }}
|
||||
uses: electron/github-app-auth-action@cc6751b3b5e4edc5b9a4ad0a021ac455653b6dc8 # v1.0.0
|
||||
id: generate-token
|
||||
env:
|
||||
RELEASE_BOARD_GH_APP_CREDS: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }}
|
||||
run: |
|
||||
set -eo pipefail
|
||||
TOKEN=$(npx @electron/github-app-auth --creds=$RELEASE_BOARD_GH_APP_CREDS --org=electron)
|
||||
echo "TOKEN=$TOKEN" >> "$GITHUB_OUTPUT"
|
||||
with:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
org: electron
|
||||
- name: Set status
|
||||
if: ${{ steps.generate-token.outputs.TOKEN }}
|
||||
if: ${{ steps.check-for-blocked-labels.outputs.NOT_BLOCKED }}
|
||||
uses: github/update-project-action@2d475e08804f11f4022df7e21f5816531e97cb64 # v2
|
||||
with:
|
||||
github_token: ${{ steps.generate-token.outputs.TOKEN }}
|
||||
github_token: ${{ steps.generate-token.outputs.token }}
|
||||
organization: electron
|
||||
project_number: 90
|
||||
content_id: ${{ github.event.issue.node_id }}
|
||||
|
||||
17
.github/workflows/pull-request-labeled.yml
vendored
17
.github/workflows/pull-request-labeled.yml
vendored
@@ -14,18 +14,15 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Generate GitHub App token
|
||||
uses: electron/github-app-auth-action@cc6751b3b5e4edc5b9a4ad0a021ac455653b6dc8 # v1.0.0
|
||||
id: generate-token
|
||||
env:
|
||||
RELEASE_BOARD_GH_APP_CREDS: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }}
|
||||
run: |
|
||||
set -eo pipefail
|
||||
TOKEN=$(npx @electron/github-app-auth --creds=$RELEASE_BOARD_GH_APP_CREDS --org=electron)
|
||||
echo "TOKEN=$TOKEN" >> "$GITHUB_OUTPUT"
|
||||
- name: Set status
|
||||
if: ${{ steps.generate-token.outputs.TOKEN }}
|
||||
uses: github/update-project-action@2d475e08804f11f4022df7e21f5816531e97cb64 # v2
|
||||
with:
|
||||
github_token: ${{ steps.generate-token.outputs.TOKEN }}
|
||||
creds: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }}
|
||||
org: electron
|
||||
- name: Set status
|
||||
uses: dsanders11/update-project-action@7ade91760df70df76770a238abee7a4869e01cf8
|
||||
with:
|
||||
github_token: ${{ steps.generate-token.outputs.token }}
|
||||
organization: electron
|
||||
project_number: 94
|
||||
content_id: ${{ github.event.pull_request.node_id }}
|
||||
|
||||
17
.github/workflows/stale.yml
vendored
17
.github/workflows/stale.yml
vendored
@@ -5,15 +5,20 @@ on:
|
||||
# 1:30am every day
|
||||
- cron: '30 1 * * *'
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Generate GitHub App token
|
||||
uses: electron/github-app-auth-action@cc6751b3b5e4edc5b9a4ad0a021ac455653b6dc8 # v1.0.0
|
||||
id: generate-token
|
||||
with:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
- uses: actions/stale@5ebf00ea0e4c1561e9b43a292ed34424fb1d4578 # tag: v6.0.1
|
||||
with:
|
||||
repo-token: ${{ steps.generate-token.outputs.token }}
|
||||
days-before-stale: 90
|
||||
days-before-close: 30
|
||||
stale-issue-label: stale
|
||||
@@ -22,15 +27,21 @@ jobs:
|
||||
This issue has been automatically marked as stale. **If this issue is still affecting you, please leave any comment** (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the [latest version of Electron](https://www.electronjs.org/releases/stable) or in the [beta](https://www.electronjs.org/releases/beta)—please include it with your comment!
|
||||
close-issue-message: >
|
||||
This issue has been closed due to inactivity, and will not be monitored. If this is a bug and you can reproduce this issue on a [supported version of Electron](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#timeline) please open a new issue and include instructions for reproducing the issue.
|
||||
exempt-issue-labels: "discussion,security \U0001F512,enhancement :sparkles:"
|
||||
exempt-issue-labels: "discussion,security \U0001F512,enhancement :sparkles:,status/confirmed"
|
||||
only-pr-labels: not-a-real-label
|
||||
pending-repro:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ always() }}
|
||||
needs: stale
|
||||
steps:
|
||||
- name: Generate GitHub App token
|
||||
uses: electron/github-app-auth-action@cc6751b3b5e4edc5b9a4ad0a021ac455653b6dc8 # v1.0.0
|
||||
id: generate-token
|
||||
with:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
- uses: actions/stale@5ebf00ea0e4c1561e9b43a292ed34424fb1d4578 # tag: v6.0.1
|
||||
with:
|
||||
repo-token: ${{ steps.generate-token.outputs.token }}
|
||||
days-before-stale: -1
|
||||
days-before-close: 10
|
||||
remove-stale-when-updated: false
|
||||
|
||||
154
BUILD.gn
154
BUILD.gn
@@ -9,6 +9,7 @@ import("//pdf/features.gni")
|
||||
import("//ppapi/buildflags/buildflags.gni")
|
||||
import("//printing/buildflags/buildflags.gni")
|
||||
import("//testing/test.gni")
|
||||
import("//third_party/electron_node/node.gni")
|
||||
import("//third_party/ffmpeg/ffmpeg_options.gni")
|
||||
import("//tools/generate_library_loader/generate_library_loader.gni")
|
||||
import("//tools/grit/grit_rule.gni")
|
||||
@@ -103,26 +104,14 @@ branding = read_file("shell/app/BRANDING.json", "json")
|
||||
electron_project_name = branding.project_name
|
||||
electron_product_name = branding.product_name
|
||||
electron_mac_bundle_id = branding.mac_bundle_id
|
||||
|
||||
if (override_electron_version != "") {
|
||||
electron_version = override_electron_version
|
||||
} else {
|
||||
# When building from source code tarball there is no git tag available and
|
||||
# builders must explicitly pass override_electron_version in gn args.
|
||||
# This read_file call will assert if there is no git information, without it
|
||||
# gn will generate a malformed build configuration and ninja will get into
|
||||
# infinite loop.
|
||||
read_file(".git/packed-refs", "string")
|
||||
|
||||
# Set electron version from git tag.
|
||||
electron_version = exec_script("script/get-git-version.py",
|
||||
[],
|
||||
"trim string",
|
||||
[
|
||||
".git/packed-refs",
|
||||
".git/HEAD",
|
||||
])
|
||||
}
|
||||
electron_version = exec_script("script/print-version.py",
|
||||
[],
|
||||
"trim string",
|
||||
[
|
||||
".git/packed-refs",
|
||||
".git/HEAD",
|
||||
"script/lib/get-version.js",
|
||||
])
|
||||
|
||||
if (is_mas_build) {
|
||||
assert(is_mac,
|
||||
@@ -554,7 +543,6 @@ source_set("electron_lib") {
|
||||
|
||||
if (is_mac) {
|
||||
deps += [
|
||||
":electron_lib_arc",
|
||||
"//components/remote_cocoa/app_shim",
|
||||
"//components/remote_cocoa/browser",
|
||||
"//content/browser:mac_helpers",
|
||||
@@ -756,63 +744,6 @@ source_set("electron_lib") {
|
||||
}
|
||||
}
|
||||
|
||||
if (is_mac) {
|
||||
source_set("electron_lib_arc") {
|
||||
public_configs = [ ":branding" ]
|
||||
include_dirs = [ "." ]
|
||||
sources = [
|
||||
"shell/app/electron_main_delegate_mac.h",
|
||||
"shell/app/electron_main_delegate_mac.mm",
|
||||
"shell/browser/api/electron_api_menu_mac.h",
|
||||
"shell/browser/api/electron_api_menu_mac.mm",
|
||||
"shell/browser/api/electron_api_native_theme_mac.mm",
|
||||
"shell/browser/api/electron_api_push_notifications_mac.mm",
|
||||
"shell/browser/api/electron_api_system_preferences_mac.mm",
|
||||
"shell/browser/browser_mac.mm",
|
||||
"shell/browser/electron_browser_main_parts_mac.mm",
|
||||
"shell/browser/mac/dict_util.h",
|
||||
"shell/browser/mac/dict_util.mm",
|
||||
"shell/browser/mac/electron_application.h",
|
||||
"shell/browser/mac/electron_application.mm",
|
||||
"shell/browser/mac/electron_application_delegate.h",
|
||||
"shell/browser/mac/electron_application_delegate.mm",
|
||||
"shell/browser/native_window_mac.h",
|
||||
"shell/browser/native_window_mac.mm",
|
||||
"shell/browser/ui/cocoa/delayed_native_view_host.h",
|
||||
"shell/browser/ui/cocoa/delayed_native_view_host.mm",
|
||||
"shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h",
|
||||
"shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm",
|
||||
"shell/browser/ui/cocoa/electron_menu_controller.mm",
|
||||
"shell/browser/ui/cocoa/electron_ns_window.h",
|
||||
"shell/browser/ui/cocoa/electron_ns_window.mm",
|
||||
"shell/browser/ui/cocoa/electron_ns_window_delegate.h",
|
||||
"shell/browser/ui/cocoa/electron_ns_window_delegate.mm",
|
||||
"shell/browser/ui/cocoa/electron_touch_bar.h",
|
||||
"shell/browser/ui/cocoa/electron_touch_bar.mm",
|
||||
"shell/browser/ui/inspectable_web_contents_view_mac.h",
|
||||
"shell/browser/ui/inspectable_web_contents_view_mac.mm",
|
||||
"shell/browser/ui/tray_icon_cocoa.h",
|
||||
"shell/browser/ui/tray_icon_cocoa.mm",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"buildflags",
|
||||
"shell/common/api:mojo",
|
||||
"//base",
|
||||
"//content/public/browser",
|
||||
"//skia",
|
||||
"//third_party/electron_node:node_lib",
|
||||
"//third_party/webrtc_overrides:webrtc_component",
|
||||
"//v8",
|
||||
]
|
||||
|
||||
configs += [
|
||||
"//electron/build/config:mas_build",
|
||||
"//third_party/electron_node:node_internals",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
electron_paks("packed_resources") {
|
||||
if (is_mac) {
|
||||
output_dir = "$root_gen_dir/electron_repack"
|
||||
@@ -1580,3 +1511,70 @@ action("libcxx_objects_zip") {
|
||||
group("electron") {
|
||||
public_deps = [ ":electron_app" ]
|
||||
}
|
||||
|
||||
##### node_headers
|
||||
|
||||
node_dir = "../third_party/electron_node"
|
||||
node_files = read_file("$node_dir/filenames.json", "json")
|
||||
node_headers_dir = "$root_gen_dir/node_headers"
|
||||
|
||||
header_group_index = 0
|
||||
header_groups = []
|
||||
foreach(header_group, node_files.headers) {
|
||||
copy("node_headers_${header_group_index}") {
|
||||
sources = rebase_path(header_group.files, ".", node_dir)
|
||||
outputs =
|
||||
[ "$node_headers_dir/${header_group.dest_dir}/{{source_file_part}}" ]
|
||||
}
|
||||
header_groups += [ ":node_headers_${header_group_index}" ]
|
||||
header_group_index += 1
|
||||
}
|
||||
|
||||
copy("zlib_headers") {
|
||||
sources = [
|
||||
"$node_dir/deps/zlib/zconf.h",
|
||||
"$node_dir/deps/zlib/zlib.h",
|
||||
]
|
||||
outputs = [ "$node_headers_dir/include/node/{{source_file_part}}" ]
|
||||
}
|
||||
|
||||
copy("node_gypi_headers") {
|
||||
deps = [ ":generate_config_gypi" ]
|
||||
sources = [
|
||||
"$node_dir/common.gypi",
|
||||
"$root_gen_dir/config.gypi",
|
||||
]
|
||||
outputs = [ "$node_headers_dir/include/node/{{source_file_part}}" ]
|
||||
}
|
||||
|
||||
action("node_version_header") {
|
||||
inputs = [ "$node_dir/src/node_version.h" ]
|
||||
outputs = [ "$node_headers_dir/include/node/node_version.h" ]
|
||||
script = "script/generate_node_version_header.py"
|
||||
args = rebase_path(inputs) + rebase_path(outputs)
|
||||
if (node_module_version != "") {
|
||||
args += [ "$node_module_version" ]
|
||||
}
|
||||
}
|
||||
|
||||
action("tar_node_headers") {
|
||||
deps = [ ":copy_node_headers" ]
|
||||
outputs = [ "$root_gen_dir/node_headers.tar.gz" ]
|
||||
script = "script/tar.py"
|
||||
args = [
|
||||
rebase_path("$root_gen_dir/node_headers"),
|
||||
rebase_path(outputs[0]),
|
||||
]
|
||||
}
|
||||
|
||||
group("copy_node_headers") {
|
||||
public_deps = header_groups + [
|
||||
":node_gypi_headers",
|
||||
":node_version_header",
|
||||
":zlib_headers",
|
||||
]
|
||||
}
|
||||
|
||||
group("node_headers") {
|
||||
public_deps = [ ":tar_node_headers" ]
|
||||
}
|
||||
|
||||
6
DEPS
6
DEPS
@@ -2,11 +2,11 @@ gclient_gn_args_from = 'src'
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'118.0.5993.144',
|
||||
'119.0.6019.2',
|
||||
'node_version':
|
||||
'v18.17.1',
|
||||
'v18.18.0',
|
||||
'nan_version':
|
||||
'16fa32231e2ccd89d2804b3f765319128b20c4ac',
|
||||
'e14bdcd1f72d62bca1d541b66da43130384ec213',
|
||||
'squirrel.mac_version':
|
||||
'0e5d146ba13101a1302d59ea6e6e0b3cace4ae38',
|
||||
'reactiveobjc_version':
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electronhq-16-core
|
||||
image: e-118.0.5993.0
|
||||
image: e-119.0.6019.2
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
@@ -167,7 +167,7 @@ for:
|
||||
- cd ..\..
|
||||
- ninja -C out/Default electron:hunspell_dictionaries_zip
|
||||
- ninja -C out/Default electron:electron_chromedriver_zip
|
||||
- ninja -C out/Default third_party/electron_node:headers
|
||||
- ninja -C out/Default electron:node_headers
|
||||
- python3 %LOCAL_GOMA_DIR%\goma_ctl.py stat
|
||||
- ps: >-
|
||||
Get-CimInstance -Namespace root\cimv2 -Class Win32_product | Select vendor, description, @{l='install_location';e='InstallLocation'}, @{l='install_date';e='InstallDate'}, @{l='install_date_2';e='InstallDate2'}, caption, version, name, @{l='sku_number';e='SKUNumber'} | ConvertTo-Json | Out-File -Encoding utf8 -FilePath .\installed_software.json
|
||||
@@ -319,4 +319,4 @@ for:
|
||||
on_finish:
|
||||
# Uncomment these lines to enable RDP
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
- if exist electron\electron.log ( appveyor-retry appveyor PushArtifact electron\electron.log )
|
||||
- if exist electron\electron.log ( appveyor-retry appveyor PushArtifact electron\electron.log )
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electronhq-16-core
|
||||
image: e-118.0.5993.0
|
||||
image: e-119.0.6019.2
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
@@ -165,7 +165,7 @@ for:
|
||||
- cd ..\..
|
||||
- ninja -C out/Default electron:hunspell_dictionaries_zip
|
||||
- ninja -C out/Default electron:electron_chromedriver_zip
|
||||
- ninja -C out/Default third_party/electron_node:headers
|
||||
- ninja -C out/Default electron:node_headers
|
||||
- python3 %LOCAL_GOMA_DIR%\goma_ctl.py stat
|
||||
- ps: >-
|
||||
Get-CimInstance -Namespace root\cimv2 -Class Win32_product | Select vendor, description, @{l='install_location';e='InstallLocation'}, @{l='install_date';e='InstallDate'}, @{l='install_date_2';e='InstallDate2'}, caption, version, name, @{l='sku_number';e='SKUNumber'} | ConvertTo-Json | Out-File -Encoding utf8 -FilePath .\installed_software.json
|
||||
@@ -319,4 +319,4 @@ for:
|
||||
on_finish:
|
||||
# Uncomment these lines to enable RDP
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
- if exist electron\electron.log ( appveyor-retry appveyor PushArtifact electron\electron.log )
|
||||
- if exist electron\electron.log ( appveyor-retry appveyor PushArtifact electron\electron.log )
|
||||
|
||||
@@ -56,3 +56,7 @@ v8_builtins_profiling_log_file = ""
|
||||
# https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md
|
||||
# TODO(vertedinde): hunt down dangling pointers on Linux
|
||||
enable_dangling_raw_ptr_checks = false
|
||||
|
||||
# This flag speeds up the performance of fork/execve on linux systems.
|
||||
# Ref: https://chromium-review.googlesource.com/c/v8/v8/+/4602858
|
||||
v8_enable_private_mapping_fork_optimization = true
|
||||
|
||||
@@ -18,9 +18,4 @@ declare_args() {
|
||||
|
||||
# Enable Spellchecker support
|
||||
enable_builtin_spellchecker = true
|
||||
|
||||
# The version of Electron.
|
||||
# Packagers and vendor builders should set this in gn args to avoid running
|
||||
# the script that reads git tag.
|
||||
override_electron_version = ""
|
||||
}
|
||||
|
||||
@@ -55,6 +55,8 @@ static_library("chrome") {
|
||||
"//chrome/browser/net/proxy_config_monitor.h",
|
||||
"//chrome/browser/net/proxy_service_factory.cc",
|
||||
"//chrome/browser/net/proxy_service_factory.h",
|
||||
"//chrome/browser/picture_in_picture/picture_in_picture_bounds_cache.cc",
|
||||
"//chrome/browser/picture_in_picture/picture_in_picture_bounds_cache.h",
|
||||
"//chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc",
|
||||
"//chrome/browser/picture_in_picture/picture_in_picture_window_manager.h",
|
||||
"//chrome/browser/platform_util.cc",
|
||||
@@ -202,10 +204,6 @@ static_library("chrome") {
|
||||
"//chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc",
|
||||
"//chrome/browser/ui/views/status_icons/status_icon_linux_dbus.h",
|
||||
]
|
||||
sources += [
|
||||
"//chrome/browser/ui/views/dark_mode_manager_linux.cc",
|
||||
"//chrome/browser/ui/views/dark_mode_manager_linux.h",
|
||||
]
|
||||
public_deps += [
|
||||
"//components/dbus/menu",
|
||||
"//components/dbus/thread_linux",
|
||||
@@ -221,7 +219,20 @@ static_library("chrome") {
|
||||
}
|
||||
|
||||
if (is_mac) {
|
||||
public_deps += [ ":chrome_lib_arc" ]
|
||||
sources += [
|
||||
"//chrome/browser/extensions/global_shortcut_listener_mac.h",
|
||||
"//chrome/browser/extensions/global_shortcut_listener_mac.mm",
|
||||
"//chrome/browser/icon_loader_mac.mm",
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_mac.h",
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm",
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.h",
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.mm",
|
||||
"//chrome/browser/media/webrtc/window_icon_util_mac.mm",
|
||||
"//chrome/browser/platform_util_mac.mm",
|
||||
"//chrome/browser/process_singleton_mac.mm",
|
||||
"//chrome/browser/ui/views/eye_dropper/eye_dropper_view_mac.h",
|
||||
"//chrome/browser/ui/views/eye_dropper/eye_dropper_view_mac.mm",
|
||||
]
|
||||
}
|
||||
|
||||
if (enable_widevine) {
|
||||
@@ -323,34 +334,6 @@ static_library("chrome") {
|
||||
"//components/pdf/renderer",
|
||||
]
|
||||
}
|
||||
} else {
|
||||
# These are required by the webRequest module.
|
||||
sources += [
|
||||
"//extensions/browser/api/declarative_net_request/request_action.cc",
|
||||
"//extensions/browser/api/declarative_net_request/request_action.h",
|
||||
"//extensions/browser/api/web_request/form_data_parser.cc",
|
||||
"//extensions/browser/api/web_request/form_data_parser.h",
|
||||
"//extensions/browser/api/web_request/upload_data_presenter.cc",
|
||||
"//extensions/browser/api/web_request/upload_data_presenter.h",
|
||||
"//extensions/browser/api/web_request/web_request_api_constants.cc",
|
||||
"//extensions/browser/api/web_request/web_request_api_constants.h",
|
||||
"//extensions/browser/api/web_request/web_request_info.cc",
|
||||
"//extensions/browser/api/web_request/web_request_info.h",
|
||||
"//extensions/browser/api/web_request/web_request_resource_type.cc",
|
||||
"//extensions/browser/api/web_request/web_request_resource_type.h",
|
||||
"//extensions/browser/extension_api_frame_id_map.cc",
|
||||
"//extensions/browser/extension_api_frame_id_map.h",
|
||||
"//extensions/browser/extension_navigation_ui_data.cc",
|
||||
"//extensions/browser/extension_navigation_ui_data.h",
|
||||
"//extensions/browser/extensions_browser_client.cc",
|
||||
"//extensions/browser/extensions_browser_client.h",
|
||||
"//extensions/browser/guest_view/web_view/web_view_renderer_state.cc",
|
||||
"//extensions/browser/guest_view/web_view/web_view_renderer_state.h",
|
||||
]
|
||||
|
||||
public_deps += [
|
||||
"//extensions/browser/api/declarative_net_request/flat:extension_ruleset",
|
||||
]
|
||||
}
|
||||
|
||||
if (!is_mas_build) {
|
||||
@@ -365,35 +348,6 @@ static_library("chrome") {
|
||||
}
|
||||
}
|
||||
|
||||
if (is_mac) {
|
||||
source_set("chrome_lib_arc") {
|
||||
include_dirs = [ "." ]
|
||||
sources = [
|
||||
"//chrome/browser/extensions/global_shortcut_listener_mac.h",
|
||||
"//chrome/browser/extensions/global_shortcut_listener_mac.mm",
|
||||
"//chrome/browser/icon_loader_mac.mm",
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_mac.h",
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm",
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.h",
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.mm",
|
||||
"//chrome/browser/media/webrtc/window_icon_util_mac.mm",
|
||||
"//chrome/browser/platform_util_mac.mm",
|
||||
"//chrome/browser/process_singleton_mac.mm",
|
||||
"//chrome/browser/ui/views/eye_dropper/eye_dropper_view_mac.h",
|
||||
"//chrome/browser/ui/views/eye_dropper/eye_dropper_view_mac.mm",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//base",
|
||||
"//content/public/browser",
|
||||
"//skia",
|
||||
"//third_party/electron_node:node_lib",
|
||||
"//third_party/webrtc_overrides:webrtc_component",
|
||||
"//v8",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
source_set("plugins") {
|
||||
sources = []
|
||||
deps = []
|
||||
|
||||
@@ -51,16 +51,17 @@ async function createWindow (backgroundColor?: string) {
|
||||
autoHideMenuBar: true,
|
||||
backgroundColor,
|
||||
webPreferences: {
|
||||
preload: path.resolve(__dirname, 'preload.js'),
|
||||
preload: url.fileURLToPath(new URL('preload.js', import.meta.url)),
|
||||
contextIsolation: true,
|
||||
sandbox: true
|
||||
sandbox: true,
|
||||
nodeIntegration: false
|
||||
},
|
||||
useContentSize: true,
|
||||
show: false
|
||||
};
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
options.icon = path.join(__dirname, 'icon.png');
|
||||
options.icon = url.fileURLToPath(new URL('icon.png', import.meta.url));
|
||||
}
|
||||
|
||||
mainWindow = new BrowserWindow(options);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as electron from 'electron/main';
|
||||
|
||||
import * as fs from 'node:fs';
|
||||
import { Module } from 'node:module';
|
||||
import * as path from 'node:path';
|
||||
import * as url from 'node:url';
|
||||
const { app, dialog } = electron;
|
||||
@@ -15,8 +16,6 @@ type DefaultAppOptions = {
|
||||
modules: string[];
|
||||
}
|
||||
|
||||
const Module = require('node:module');
|
||||
|
||||
// Parse command line options.
|
||||
const argv = process.argv.slice(1);
|
||||
|
||||
@@ -71,10 +70,10 @@ if (nextArgIsRequire) {
|
||||
|
||||
// Set up preload modules
|
||||
if (option.modules.length > 0) {
|
||||
Module._preloadModules(option.modules);
|
||||
(Module as any)._preloadModules(option.modules);
|
||||
}
|
||||
|
||||
function loadApplicationPackage (packagePath: string) {
|
||||
async function loadApplicationPackage (packagePath: string) {
|
||||
// Add a flag indicating app is started from default app.
|
||||
Object.defineProperty(process, 'defaultApp', {
|
||||
configurable: false,
|
||||
@@ -89,11 +88,19 @@ function loadApplicationPackage (packagePath: string) {
|
||||
let appPath;
|
||||
if (fs.existsSync(packageJsonPath)) {
|
||||
let packageJson;
|
||||
const emitWarning = process.emitWarning;
|
||||
try {
|
||||
packageJson = require(packageJsonPath);
|
||||
process.emitWarning = () => {};
|
||||
packageJson = (await import(url.pathToFileURL(packageJsonPath).toString(), {
|
||||
assert: {
|
||||
type: 'json'
|
||||
}
|
||||
})).default;
|
||||
} catch (e) {
|
||||
showErrorMessage(`Unable to parse ${packageJsonPath}\n\n${(e as Error).message}`);
|
||||
return;
|
||||
} finally {
|
||||
process.emitWarning = emitWarning;
|
||||
}
|
||||
|
||||
if (packageJson.version) {
|
||||
@@ -112,13 +119,15 @@ function loadApplicationPackage (packagePath: string) {
|
||||
// Set v8 flags, deliberately lazy load so that apps that do not use this
|
||||
// feature do not pay the price
|
||||
if (packageJson.v8Flags) {
|
||||
require('node:v8').setFlagsFromString(packageJson.v8Flags);
|
||||
(await import('node:v8')).setFlagsFromString(packageJson.v8Flags);
|
||||
}
|
||||
appPath = packagePath;
|
||||
}
|
||||
|
||||
let filePath: string;
|
||||
|
||||
try {
|
||||
const filePath = Module._resolveFilename(packagePath, module, true);
|
||||
filePath = (Module as any)._resolveFilename(packagePath, null, true);
|
||||
app.setAppPath(appPath || path.dirname(filePath));
|
||||
} catch (e) {
|
||||
showErrorMessage(`Unable to find Electron app at ${packagePath}\n\n${(e as Error).message}`);
|
||||
@@ -126,7 +135,7 @@ function loadApplicationPackage (packagePath: string) {
|
||||
}
|
||||
|
||||
// Run the app.
|
||||
Module._load(packagePath, module, true);
|
||||
await import(url.pathToFileURL(filePath).toString());
|
||||
} catch (e) {
|
||||
console.error('App threw an error during load');
|
||||
console.error((e as Error).stack || e);
|
||||
@@ -141,16 +150,16 @@ function showErrorMessage (message: string) {
|
||||
}
|
||||
|
||||
async function loadApplicationByURL (appUrl: string) {
|
||||
const { loadURL } = await import('./default_app');
|
||||
const { loadURL } = await import('./default_app.js');
|
||||
loadURL(appUrl);
|
||||
}
|
||||
|
||||
async function loadApplicationByFile (appPath: string) {
|
||||
const { loadFile } = await import('./default_app');
|
||||
const { loadFile } = await import('./default_app.js');
|
||||
loadFile(appPath);
|
||||
}
|
||||
|
||||
function startRepl () {
|
||||
async function startRepl () {
|
||||
if (process.platform === 'win32') {
|
||||
console.error('Electron REPL not currently supported on Windows');
|
||||
process.exit(1);
|
||||
@@ -171,8 +180,8 @@ function startRepl () {
|
||||
Using: Node.js ${nodeVersion} and Electron.js ${electronVersion}
|
||||
`);
|
||||
|
||||
const { REPLServer } = require('node:repl');
|
||||
const repl = new REPLServer({
|
||||
const { start } = await import('node:repl');
|
||||
const repl = start({
|
||||
prompt: '> '
|
||||
}).on('exit', () => {
|
||||
process.exit(0);
|
||||
@@ -225,8 +234,8 @@ function startRepl () {
|
||||
|
||||
const electronBuiltins = [...Object.keys(electron), 'original-fs', 'electron'];
|
||||
|
||||
const defaultComplete = repl.completer;
|
||||
repl.completer = (line: string, callback: Function) => {
|
||||
const defaultComplete: Function = repl.completer;
|
||||
(repl as any).completer = (line: string, callback: Function) => {
|
||||
const lastSpace = line.lastIndexOf(' ');
|
||||
const currentSymbol = line.substring(lastSpace + 1, repl.cursor);
|
||||
|
||||
@@ -249,11 +258,11 @@ if (option.file && !option.webdriver) {
|
||||
const protocol = url.parse(file).protocol;
|
||||
const extension = path.extname(file);
|
||||
if (protocol === 'http:' || protocol === 'https:' || protocol === 'file:' || protocol === 'chrome:') {
|
||||
loadApplicationByURL(file);
|
||||
await loadApplicationByURL(file);
|
||||
} else if (extension === '.html' || extension === '.htm') {
|
||||
loadApplicationByFile(path.resolve(file));
|
||||
await loadApplicationByFile(path.resolve(file));
|
||||
} else {
|
||||
loadApplicationPackage(file);
|
||||
await loadApplicationPackage(file);
|
||||
}
|
||||
} else if (option.version) {
|
||||
console.log('v' + process.versions.electron);
|
||||
@@ -262,7 +271,7 @@ if (option.file && !option.webdriver) {
|
||||
console.log(process.versions.modules);
|
||||
process.exit(0);
|
||||
} else if (option.interactive) {
|
||||
startRepl();
|
||||
await startRepl();
|
||||
} else {
|
||||
if (!option.noHelp) {
|
||||
const welcomeMessage = `
|
||||
@@ -285,5 +294,5 @@ Options:
|
||||
console.log(welcomeMessage);
|
||||
}
|
||||
|
||||
loadApplicationByFile('index.html');
|
||||
await loadApplicationByFile('index.html');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"productName": "Electron",
|
||||
"main": "main.js"
|
||||
"main": "main.js",
|
||||
"type": "module"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ipcRenderer, contextBridge } from 'electron/renderer';
|
||||
const { ipcRenderer, contextBridge } = require('electron/renderer');
|
||||
|
||||
const policy = window.trustedTypes.createPolicy('electron-default-app', {
|
||||
// we trust the SVG contents
|
||||
|
||||
@@ -1134,11 +1134,11 @@ indicates success while any other value indicates failure according to Chromium
|
||||
resolver will attempt to use the system's DNS settings to do DNS lookups
|
||||
itself. Enabled by default on macOS, disabled by default on Windows and
|
||||
Linux.
|
||||
* `secureDnsMode` string (optional) - Can be 'off', 'automatic' or 'secure'.
|
||||
Configures the DNS-over-HTTP mode. When 'off', no DoH lookups will be
|
||||
performed. When 'automatic', DoH lookups will be performed first if DoH is
|
||||
* `secureDnsMode` string (optional) - Can be "off", "automatic" or "secure".
|
||||
Configures the DNS-over-HTTP mode. When "off", no DoH lookups will be
|
||||
performed. When "automatic", DoH lookups will be performed first if DoH is
|
||||
available, and insecure DNS lookups will be performed as a fallback. When
|
||||
'secure', only DoH lookups will be performed. Defaults to 'automatic'.
|
||||
"secure", only DoH lookups will be performed. Defaults to "automatic".
|
||||
* `secureDnsServers` string[] (optional) - A list of DNS-over-HTTP
|
||||
server templates. See [RFC8484 § 3][] for details on the template format.
|
||||
Most servers support the POST method; the template for such servers is
|
||||
|
||||
@@ -367,36 +367,6 @@ The following app commands are explicitly supported on Linux:
|
||||
* `browser-backward`
|
||||
* `browser-forward`
|
||||
|
||||
#### Event: 'scroll-touch-begin' _macOS_ _Deprecated_
|
||||
|
||||
Emitted when scroll wheel event phase has begun.
|
||||
|
||||
> **Note**
|
||||
> This event is deprecated beginning in Electron 22.0.0. See [Breaking
|
||||
> Changes](../breaking-changes.md#deprecated-browserwindow-scroll-touch--events)
|
||||
> for details of how to migrate to using the [WebContents
|
||||
> `input-event`](./web-contents.md#event-input-event) event.
|
||||
|
||||
#### Event: 'scroll-touch-end' _macOS_ _Deprecated_
|
||||
|
||||
Emitted when scroll wheel event phase has ended.
|
||||
|
||||
> **Note**
|
||||
> This event is deprecated beginning in Electron 22.0.0. See [Breaking
|
||||
> Changes](../breaking-changes.md#deprecated-browserwindow-scroll-touch--events)
|
||||
> for details of how to migrate to using the [WebContents
|
||||
> `input-event`](./web-contents.md#event-input-event) event.
|
||||
|
||||
#### Event: 'scroll-touch-edge' _macOS_ _Deprecated_
|
||||
|
||||
Emitted when scroll wheel event phase filed upon reaching the edge of element.
|
||||
|
||||
> **Note**
|
||||
> This event is deprecated beginning in Electron 22.0.0. See [Breaking
|
||||
> Changes](../breaking-changes.md#deprecated-browserwindow-scroll-touch--events)
|
||||
> for details of how to migrate to using the [WebContents
|
||||
> `input-event`](./web-contents.md#event-input-event) event.
|
||||
|
||||
#### Event: 'swipe' _macOS_
|
||||
|
||||
Returns:
|
||||
@@ -505,10 +475,6 @@ events.
|
||||
|
||||
A `Integer` property representing the unique ID of the window. Each ID is unique among all `BrowserWindow` instances of the entire Electron application.
|
||||
|
||||
#### `win.tabbingIdentifier` _macOS_ _Readonly_
|
||||
|
||||
A `string` (optional) property that is equal to the `tabbingIdentifier` passed to the `BrowserWindow` constructor or `undefined` if none was set.
|
||||
|
||||
#### `win.autoHideMenuBar`
|
||||
|
||||
A `boolean` property that determines whether the window menu bar should hide itself automatically. Once set, the menu bar will only show when users press the single `Alt` key.
|
||||
@@ -1599,25 +1565,6 @@ Passing `null` will reset the position to default.
|
||||
Returns `Point | null` - The custom position for the traffic light buttons in
|
||||
frameless window, `null` will be returned when there is no custom position.
|
||||
|
||||
#### `win.setTrafficLightPosition(position)` _macOS_ _Deprecated_
|
||||
|
||||
* `position` [Point](structures/point.md)
|
||||
|
||||
Set a custom position for the traffic light buttons in frameless window.
|
||||
Passing `{ x: 0, y: 0 }` will reset the position to default.
|
||||
|
||||
> **Note**
|
||||
> This function is deprecated. Use [setWindowButtonPosition](#winsetwindowbuttonpositionposition-macos) instead.
|
||||
|
||||
#### `win.getTrafficLightPosition()` _macOS_ _Deprecated_
|
||||
|
||||
Returns `Point` - The custom position for the traffic light buttons in
|
||||
frameless window, `{ x: 0, y: 0 }` will be returned when there is no custom
|
||||
position.
|
||||
|
||||
> **Note**
|
||||
> This function is deprecated. Use [getWindowButtonPosition](#wingetwindowbuttonposition-macos) instead.
|
||||
|
||||
#### `win.setTouchBar(touchBar)` _macOS_
|
||||
|
||||
* `touchBar` TouchBar | null
|
||||
@@ -1670,7 +1617,7 @@ removed in future Electron releases.
|
||||
* `options` Object
|
||||
* `color` String (optional) _Windows_ - The CSS color of the Window Controls Overlay when enabled.
|
||||
* `symbolColor` String (optional) _Windows_ - The CSS color of the symbols on the Window Controls Overlay when enabled.
|
||||
* `height` Integer (optional) _Windows_ - The height of the title bar and Window Controls Overlay in pixels.
|
||||
* `height` Integer (optional) _macOS_ _Windows_ - The height of the title bar and Window Controls Overlay in pixels.
|
||||
|
||||
On a Window with Window Controls Overlay already enabled, this method updates
|
||||
the style of the title bar overlay.
|
||||
|
||||
@@ -111,6 +111,16 @@ Options:
|
||||
* `kioclient5`
|
||||
* `kioclient`
|
||||
|
||||
### `ELECTRON_OZONE_PLATFORM_HINT` _Linux_
|
||||
|
||||
Selects the preferred platform backend used on Linux. The default one is `x11`. `auto` selects Wayland if possible, X11 otherwise.
|
||||
|
||||
Options:
|
||||
|
||||
* `auto`
|
||||
* `wayland`
|
||||
* `x11`
|
||||
|
||||
## Development Variables
|
||||
|
||||
The following environment variables are intended primarily for development and
|
||||
|
||||
@@ -32,6 +32,15 @@ The `ipcRenderer` module has the following method to listen for events and send
|
||||
Listens to `channel`, when a new message arrives `listener` would be called with
|
||||
`listener(event, args...)`.
|
||||
|
||||
### `ipcRenderer.off(channel, listener)`
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function
|
||||
* `event` [IpcRendererEvent][ipc-renderer-event]
|
||||
* `...args` any[]
|
||||
|
||||
Alias for [`ipcRenderer.removeListener`](#ipcrendererremovelistenerchannel-listener).
|
||||
|
||||
### `ipcRenderer.once(channel, listener)`
|
||||
|
||||
* `channel` string
|
||||
@@ -42,10 +51,20 @@ Listens to `channel`, when a new message arrives `listener` would be called with
|
||||
Adds a one time `listener` function for the event. This `listener` is invoked
|
||||
only the next time a message is sent to `channel`, after which it is removed.
|
||||
|
||||
### `ipcRenderer.addListener(channel, listener)`
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function
|
||||
* `event` [IpcRendererEvent][ipc-renderer-event]
|
||||
* `...args` any[]
|
||||
|
||||
Alias for [`ipcRenderer.on`](#ipcrendereronchannel-listener).
|
||||
|
||||
### `ipcRenderer.removeListener(channel, listener)`
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function
|
||||
* `event` [IpcRendererEvent][ipc-renderer-event]
|
||||
* `...args` any[]
|
||||
|
||||
Removes the specified `listener` from the listener array for the specified
|
||||
@@ -192,14 +211,6 @@ ipcMain.on('port', (e, msg) => {
|
||||
For more information on using `MessagePort` and `MessageChannel`, see the [MDN
|
||||
documentation](https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel).
|
||||
|
||||
### `ipcRenderer.sendTo(webContentsId, channel, ...args)` _Deprecated_
|
||||
|
||||
* `webContentsId` number
|
||||
* `channel` string
|
||||
* `...args` any[]
|
||||
|
||||
Sends a message to a window with `webContentsId` via `channel`.
|
||||
|
||||
### `ipcRenderer.sendToHost(channel, ...args)`
|
||||
|
||||
* `channel` string
|
||||
|
||||
@@ -85,8 +85,6 @@ Emitted when the notification is closed by manual intervention from the user.
|
||||
This event is not guaranteed to be emitted in all cases where the notification
|
||||
is closed.
|
||||
|
||||
On Windows, the `close` event can be emitted in one of three ways: programmatic dismissal with `notification.close()`, by the user closing the notification, or via system timeout. If a notification is in the Action Center after the initial `close` event is emitted, a call to `notification.close()` will remove the notification from the action center but the `close` event will not be emitted again.
|
||||
|
||||
#### Event: 'reply' _macOS_
|
||||
|
||||
Returns:
|
||||
@@ -129,8 +127,6 @@ shown notification and create a new one with identical properties.
|
||||
|
||||
Dismisses the notification.
|
||||
|
||||
On Windows, calling `notification.close()` while the notification is visible on screen will dismiss the notification and remove it from the Action Center. If `notification.close()` is called after the notification is no longer visible on screen, calling `notification.close()` will try remove it from the Action Center.
|
||||
|
||||
### Instance Properties
|
||||
|
||||
#### `notification.title`
|
||||
|
||||
@@ -266,7 +266,7 @@ Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `device` [HIDDevice](structures/hid-device.md)
|
||||
* `device` [HIDDevice[]](structures/hid-device.md)
|
||||
* `frame` [WebFrameMain](web-frame-main.md)
|
||||
|
||||
Emitted after `navigator.hid.requestDevice` has been called and
|
||||
@@ -281,7 +281,7 @@ Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `device` [HIDDevice](structures/hid-device.md)
|
||||
* `device` [HIDDevice[]](structures/hid-device.md)
|
||||
* `frame` [WebFrameMain](web-frame-main.md)
|
||||
|
||||
Emitted after `navigator.hid.requestDevice` has been called and
|
||||
@@ -296,7 +296,7 @@ Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `device` [HIDDevice](structures/hid-device.md)
|
||||
* `device` [HIDDevice[]](structures/hid-device.md)
|
||||
* `origin` string (optional) - The origin that the device has been revoked from.
|
||||
|
||||
Emitted after `HIDDevice.forget()` has been called. This event can be used
|
||||
@@ -785,7 +785,7 @@ Returns `Promise<void>` - Resolves when all connections are closed.
|
||||
#### `ses.fetch(input[, init])`
|
||||
|
||||
* `input` string | [GlobalRequest](https://nodejs.org/api/globals.html#request)
|
||||
* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) & { bypassCustomProtocolHandlers?: boolean } (optional)
|
||||
* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) (optional)
|
||||
|
||||
Returns `Promise<GlobalResponse>` - see [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response).
|
||||
|
||||
@@ -901,7 +901,6 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
|
||||
* `midiSysex` - Request the use of system exclusive messages in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API).
|
||||
* `notifications` - Request notification creation and the ability to display them in the user's system tray using the [Notifications API](https://developer.mozilla.org/en-US/docs/Web/API/notification)
|
||||
* `pointerLock` - Request to directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame.
|
||||
* `keyboardLock` - Request capture of keypresses for any or all of the keys on the physical keyboard via the [Keyboard Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Keyboard/lock). These requests always appear to originate from the main frame.
|
||||
* `openExternal` - Request to open links in external applications.
|
||||
* `window-management` - Request access to enumerate screens using the [`getScreenDetails`](https://developer.chrome.com/en/articles/multi-screen-window-placement/) API.
|
||||
* `unknown` - An unrecognized permission request.
|
||||
|
||||
@@ -97,9 +97,6 @@
|
||||
* `roundedCorners` boolean (optional) _macOS_ - Whether frameless window
|
||||
should have rounded corners on macOS. Default is `true`. Setting this property
|
||||
to `false` will prevent the window from being fullscreenable.
|
||||
* `fullscreenWindowTitle` boolean (optional) _macOS_ _Deprecated_ - Shows
|
||||
the title in the title bar in full screen mode on macOS for `hiddenInset`
|
||||
titleBarStyle. Default is `false`.
|
||||
* `thickFrame` boolean (optional) - Use `WS_THICKFRAME` style for frameless windows on
|
||||
Windows, which adds standard window frame. Setting it to `false` will remove
|
||||
window shadow and window animations. Default is `true`.
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
# IpcRendererEvent Object extends `Event`
|
||||
|
||||
* `sender` [IpcRenderer](../ipc-renderer.md) - The `IpcRenderer` instance that emitted the event originally
|
||||
* `senderId` Integer _Deprecated_ - The `webContents.id` that sent the message, you can call `event.sender.sendTo(event.senderId, ...)` to reply to the message, see [ipcRenderer.sendTo][ipc-renderer-sendto] for more information. This only applies to messages sent from a different renderer. Messages sent directly from the main process set `event.senderId` to `0`.
|
||||
* `senderIsMainFrame` boolean (optional) _Deprecated_ - Whether the message sent via [ipcRenderer.sendTo][ipc-renderer-sendto] was sent by the main frame. This is relevant when `nodeIntegrationInSubFrames` is enabled in the originating `webContents`.
|
||||
* `ports` [MessagePort][][] - A list of MessagePorts that were transferred with this message
|
||||
|
||||
[ipc-renderer-sendto]: ../ipc-renderer.md#ipcrenderersendtowebcontentsid-channel-args-deprecated
|
||||
[MessagePort]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort
|
||||
|
||||
@@ -29,7 +29,7 @@ Process: [Main](../glossary.md#main-process)<br />
|
||||
* `inherit`: equivalent to \['ignore', 'inherit', 'inherit']
|
||||
* `serviceName` string (optional) - Name of the process that will appear in `name` property of
|
||||
[`child-process-gone` event of `app`](app.md#event-child-process-gone).
|
||||
Default is `Node Utility Process`.
|
||||
Default is `node.mojom.NodeService`.
|
||||
* `allowLoadingUnsignedLibraries` boolean (optional) _macOS_ - With this flag, the utility process will be
|
||||
launched via the `Electron Helper (Plugin).app` helper executable on macOS, which can be
|
||||
codesigned with `com.apple.security.cs.disable-library-validation` and
|
||||
|
||||
@@ -1211,7 +1211,7 @@ Returns `string` - The user agent for this web page.
|
||||
|
||||
* `css` string
|
||||
* `options` Object (optional)
|
||||
* `cssOrigin` string (optional) - Can be 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
|
||||
* `cssOrigin` string (optional) - Can be either 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
|
||||
|
||||
Returns `Promise<string>` - A promise that resolves with a key for the inserted CSS that can later be used to remove the CSS via `contents.removeInsertedCSS(key)`.
|
||||
|
||||
@@ -1618,6 +1618,7 @@ win.webContents.print(options, (success, errorType) => {
|
||||
* `headerTemplate` string (optional) - HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them: `date` (formatted print date), `title` (document title), `url` (document location), `pageNumber` (current page number) and `totalPages` (total pages in the document). For example, `<span class=title></span>` would generate span containing the title.
|
||||
* `footerTemplate` string (optional) - HTML template for the print footer. Should use the same format as the `headerTemplate`.
|
||||
* `preferCSSPageSize` boolean (optional) - Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size.
|
||||
* `generateTaggedPDF` boolean (optional) _Experimental_ - Whether or not to generate a tagged (accessible) PDF. Defaults to false. As this property is experimental, the generated PDF may not adhere fully to PDF/UA and WCAG standards.
|
||||
|
||||
Returns `Promise<Buffer>` - Resolves with the generated PDF data.
|
||||
|
||||
@@ -2060,6 +2061,24 @@ Setting the WebRTC IP handling policy allows you to control which IPs are
|
||||
exposed via WebRTC. See [BrowserLeaks](https://browserleaks.com/webrtc) for
|
||||
more details.
|
||||
|
||||
#### `contents.getWebRTCUDPPortRange()`
|
||||
|
||||
Returns `Object`:
|
||||
|
||||
* `min` Integer - The minimum UDP port number that WebRTC should use.
|
||||
* `max` Integer - The maximum UDP port number that WebRTC should use.
|
||||
|
||||
By default this value is `{ min: 0, max: 0 }` , which would apply no restriction on the udp port range.
|
||||
|
||||
#### `contents.setWebRTCUDPPortRange(udpPortRange)`
|
||||
|
||||
* `udpPortRange` Object
|
||||
* `min` Integer - The minimum UDP port number that WebRTC should use.
|
||||
* `max` Integer - The maximum UDP port number that WebRTC should use.
|
||||
|
||||
Setting the WebRTC UDP Port Range allows you to restrict the udp port range used by WebRTC. By default the port range is unrestricted.
|
||||
**Note:** To reset to an unrestricted port range this value should be set to `{ min: 0, max: 0 }`.
|
||||
|
||||
#### `contents.getMediaSourceId(requestWebContents)`
|
||||
|
||||
* `requestWebContents` WebContents - Web contents that the id will be registered to.
|
||||
|
||||
@@ -113,7 +113,7 @@ webFrame.setSpellCheckProvider('en-US', {
|
||||
|
||||
* `css` string
|
||||
* `options` Object (optional)
|
||||
* `cssOrigin` string (optional) - Can be 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
|
||||
* `cssOrigin` string (optional) - Can be either 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
|
||||
|
||||
Returns `string` - A key for the inserted CSS that can later be used to remove
|
||||
the CSS via `webFrame.removeInsertedCSS(key)`.
|
||||
|
||||
@@ -607,6 +607,7 @@ Prints `webview`'s web page. Same as `webContents.print([options])`.
|
||||
* `headerTemplate` string (optional) - HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them: `date` (formatted print date), `title` (document title), `url` (document location), `pageNumber` (current page number) and `totalPages` (total pages in the document). For example, `<span class=title></span>` would generate span containing the title.
|
||||
* `footerTemplate` string (optional) - HTML template for the print footer. Should use the same format as the `headerTemplate`.
|
||||
* `preferCSSPageSize` boolean (optional) - Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size.
|
||||
* `generateTaggedPDF` boolean (optional) _Experimental_ - Whether or not to generate a tagged (accessible) PDF. Defaults to false. As this property is experimental, the generated PDF may not adhere fully to PDF/UA and WCAG standards.
|
||||
|
||||
Returns `Promise<Uint8Array>` - Resolves with the generated PDF data.
|
||||
|
||||
|
||||
@@ -12,6 +12,52 @@ This document uses the following convention to categorize breaking changes:
|
||||
* **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release.
|
||||
* **Removed:** An API or feature was removed, and is no longer supported by Electron.
|
||||
|
||||
## Planned Breaking API Changes (28.0)
|
||||
|
||||
### Removed: `BrowserWindow.setTrafficLightPosition(position)`
|
||||
|
||||
`BrowserWindow.setTrafficLightPosition(position)` has been removed, the
|
||||
`BrowserWindow.setWindowButtonPosition(position)` API should be used instead
|
||||
which accepts `null` instead of `{ x: 0, y: 0 }` to reset the position to
|
||||
system default.
|
||||
|
||||
```js
|
||||
// Removed in Electron 28
|
||||
win.setTrafficLightPosition({ x: 10, y: 10 })
|
||||
win.setTrafficLightPosition({ x: 0, y: 0 })
|
||||
|
||||
// Replace with
|
||||
win.setWindowButtonPosition({ x: 10, y: 10 })
|
||||
win.setWindowButtonPosition(null)
|
||||
```
|
||||
|
||||
### Removed: `BrowserWindow.getTrafficLightPosition()`
|
||||
|
||||
`BrowserWindow.getTrafficLightPosition()` has been removed, the
|
||||
`BrowserWindow.getWindowButtonPosition()` API should be used instead
|
||||
which returns `null` instead of `{ x: 0, y: 0 }` when there is no custom
|
||||
position.
|
||||
|
||||
```js
|
||||
// Removed in Electron 28
|
||||
const pos = win.getTrafficLightPosition()
|
||||
if (pos.x === 0 && pos.y === 0) {
|
||||
// No custom position.
|
||||
}
|
||||
|
||||
// Replace with
|
||||
const ret = win.getWindowButtonPosition()
|
||||
if (ret === null) {
|
||||
// No custom position.
|
||||
}
|
||||
```
|
||||
|
||||
### Removed: `ipcRenderer.sendTo()`
|
||||
|
||||
The `ipcRenderer.sendTo()` API has been removed. It should be replaced by setting up a [`MessageChannel`](tutorial/message-ports.md#setting-up-a-messagechannel-between-two-renderers) between the renderers.
|
||||
|
||||
The `senderId` and `senderIsMainFrame` properties of `IpcRendererEvent` have been removed as well.
|
||||
|
||||
## Planned Breaking API Changes (27.0)
|
||||
|
||||
### Removed: macOS 10.13 / 10.14 support
|
||||
@@ -670,18 +716,6 @@ to open synchronously scriptable child windows, among other incompatibilities.
|
||||
See the documentation for [window.open in Electron](api/window-open.md)
|
||||
for more details.
|
||||
|
||||
### Deprecated: `app.runningUnderRosettaTranslation`
|
||||
|
||||
The `app.runningUnderRosettaTranslation` property has been deprecated.
|
||||
Use `app.runningUnderARM64Translation` instead.
|
||||
|
||||
```js
|
||||
// Deprecated
|
||||
console.log(app.runningUnderRosettaTranslation)
|
||||
// Replace with
|
||||
console.log(app.runningUnderARM64Translation)
|
||||
```
|
||||
|
||||
## Planned Breaking API Changes (14.0)
|
||||
|
||||
### Removed: `remote` module
|
||||
|
||||
@@ -225,7 +225,7 @@ generate build headers for the modules to compile against, run the following
|
||||
under `src/` directory.
|
||||
|
||||
```sh
|
||||
$ ninja -C out/Testing third_party/electron_node:headers
|
||||
$ ninja -C out/Testing electron:node_headers
|
||||
```
|
||||
|
||||
You can now [run the tests](testing.md#unit-tests).
|
||||
|
||||
@@ -66,7 +66,7 @@ the Node.js source tree.
|
||||
2. Node headers have to be compiled for your configuration.
|
||||
|
||||
```powershell
|
||||
ninja -C out\Testing third_party\electron_node:headers
|
||||
ninja -C out\Testing electron:node_headers
|
||||
```
|
||||
|
||||
3. The electron.lib has to be copied as node.lib.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron/main')
|
||||
const path = require('node:path')
|
||||
|
||||
function createWindow () {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
const { contextBridge, ipcRenderer } = require('electron/renderer')
|
||||
|
||||
contextBridge.exposeInMainWorld('darkMode', {
|
||||
toggle: () => ipcRenderer.invoke('dark-mode:toggle'),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow, ipcMain } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain } = require('electron/main')
|
||||
const path = require('node:path')
|
||||
const fs = require('node:fs')
|
||||
const https = require('node:https')
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
const { contextBridge, ipcRenderer } = require('electron/renderer')
|
||||
|
||||
contextBridge.exposeInMainWorld('electron', {
|
||||
startDrag: (fileName) => {
|
||||
ipcRenderer.send('ondragstart', fileName)
|
||||
}
|
||||
startDrag: (fileName) => ipcRenderer.send('ondragstart', fileName)
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow, globalShortcut } = require('electron')
|
||||
const { app, BrowserWindow, globalShortcut } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
|
||||
app.whenReady().then(() => {
|
||||
const win = new BrowserWindow({ width: 800, height: 600 })
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow, Menu, MenuItem } = require('electron')
|
||||
const { app, BrowserWindow, Menu, MenuItem } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow, Menu } = require('electron')
|
||||
const { app, BrowserWindow, Menu } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow, Notification } = require('electron')
|
||||
const { app, BrowserWindow, Notification } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
const win = new BrowserWindow({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
const onlineStatusWindow = new BrowserWindow({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
|
||||
let progressInterval
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
const os = require('node:os')
|
||||
|
||||
function createWindow () {
|
||||
@@ -7,20 +7,14 @@ function createWindow () {
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.setRepresentedFilename(os.homedir())
|
||||
win.setDocumentEdited(true)
|
||||
|
||||
win.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
const win = new BrowserWindow()
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
win.setRepresentedFilename(os.homedir())
|
||||
win.setDocumentEdited(true)
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
@@ -28,3 +22,9 @@ app.on('window-all-closed', () => {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow, ipcMain } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain } = require('electron/main')
|
||||
const path = require('node:path')
|
||||
|
||||
let bluetoothPinCallback
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
const { contextBridge, ipcRenderer } = require('electron/renderer')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
cancelBluetoothRequest: (callback) => ipcRenderer.send('cancel-bluetooth-request', callback),
|
||||
bluetoothPairingRequest: (callback) => ipcRenderer.on('bluetooth-pairing-request', callback),
|
||||
cancelBluetoothRequest: () => ipcRenderer.send('cancel-bluetooth-request'),
|
||||
bluetoothPairingRequest: (callback) => ipcRenderer.on('bluetooth-pairing-request', () => callback()),
|
||||
bluetoothPairingResponse: (response) => ipcRenderer.send('bluetooth-pairing-response', response)
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
const mainWindow = new BrowserWindow({
|
||||
|
||||
@@ -1,19 +1,10 @@
|
||||
async function testIt () {
|
||||
const grantedDevices = await navigator.hid.getDevices()
|
||||
let grantedDeviceList = ''
|
||||
grantedDevices.forEach(device => {
|
||||
grantedDeviceList += `<hr>${device.productName}</hr>`
|
||||
})
|
||||
document.getElementById('granted-devices').innerHTML = grantedDeviceList
|
||||
const grantedDevices2 = await navigator.hid.requestDevice({
|
||||
filters: []
|
||||
})
|
||||
function formatDevices (devices) {
|
||||
return devices.map(device => device.productName).join('<hr>')
|
||||
}
|
||||
|
||||
grantedDeviceList = ''
|
||||
grantedDevices2.forEach(device => {
|
||||
grantedDeviceList += `<hr>${device.productName}</hr>`
|
||||
})
|
||||
document.getElementById('granted-devices2').innerHTML = grantedDeviceList
|
||||
async function testIt () {
|
||||
document.getElementById('granted-devices').innerHTML = formatDevices(await navigator.hid.getDevices())
|
||||
document.getElementById('granted-devices2').innerHTML = formatDevices(await navigator.hid.requestDevice({ filters: [] }))
|
||||
}
|
||||
|
||||
document.getElementById('clickme').addEventListener('click', testIt)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
const mainWindow = new BrowserWindow({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
|
||||
function createWindow () {
|
||||
const mainWindow = new BrowserWindow({
|
||||
|
||||
@@ -7,9 +7,9 @@ async function testIt () {
|
||||
const grantedDevices = await navigator.usb.getDevices()
|
||||
let grantedDeviceList = ''
|
||||
if (grantedDevices.length > 0) {
|
||||
grantedDevices.forEach(device => {
|
||||
for (const device of grantedDevices) {
|
||||
grantedDeviceList += `<hr>${getDeviceDetails(device)}</hr>`
|
||||
})
|
||||
}
|
||||
} else {
|
||||
grantedDeviceList = noDevicesFoundMsg
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow, ipcMain } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain } = require('electron/main')
|
||||
const path = require('node:path')
|
||||
|
||||
function createWindow () {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
const { contextBridge, ipcRenderer } = require('electron/renderer')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
setTitle: (title) => ipcRenderer.send('set-title', title)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain, dialog } = require('electron/main')
|
||||
const path = require('node:path')
|
||||
|
||||
async function handleFileOpen () {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
const { contextBridge, ipcRenderer } = require('electron/renderer')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
openFile: () => ipcRenderer.invoke('dialog:openFile')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, BrowserWindow, Menu, ipcMain } = require('electron')
|
||||
const { app, BrowserWindow, Menu, ipcMain } = require('electron/main')
|
||||
const path = require('node:path')
|
||||
|
||||
function createWindow () {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
const { contextBridge, ipcRenderer } = require('electron/renderer')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
handleCounter: (callback) => ipcRenderer.on('update-counter', callback)
|
||||
handleCounter: (callback) => ipcRenderer.on('update-counter', () => callback())
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
const path = require('node:path')
|
||||
|
||||
function createWindow () {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { ipcRenderer } = require('electron')
|
||||
const { ipcRenderer } = require('electron/renderer')
|
||||
const webview = document.getElementById('webview')
|
||||
ipcRenderer.on('webview-new-window', (e, webContentsId, details) => {
|
||||
console.log('webview-new-window', webContentsId, details)
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
<p>Clicking the demo button will take a screenshot of your current screen and open it in your default viewer.</p>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require('./renderer.js')
|
||||
</script>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,14 +1,38 @@
|
||||
const { BrowserWindow, app, screen, ipcMain, desktopCapturer } = require('electron')
|
||||
const { BrowserWindow, app, screen, ipcMain, desktopCapturer, shell } = require('electron/main')
|
||||
const fs = require('node:fs').promises
|
||||
const os = require('node:os')
|
||||
const path = require('node:path')
|
||||
|
||||
let mainWindow = null
|
||||
|
||||
ipcMain.handle('get-screen-size', () => {
|
||||
return screen.getPrimaryDisplay().workAreaSize
|
||||
})
|
||||
function determineScreenShotSize (devicePixelRatio) {
|
||||
const screenSize = screen.getPrimaryDisplay().workAreaSize
|
||||
const maxDimension = Math.max(screenSize.width, screenSize.height)
|
||||
return {
|
||||
width: maxDimension * devicePixelRatio,
|
||||
height: maxDimension * devicePixelRatio
|
||||
}
|
||||
}
|
||||
|
||||
ipcMain.handle('get-sources', (event, options) => {
|
||||
return desktopCapturer.getSources(options)
|
||||
})
|
||||
async function takeScreenshot (devicePixelRatio) {
|
||||
const thumbSize = determineScreenShotSize(devicePixelRatio)
|
||||
const options = { types: ['screen'], thumbnailSize: thumbSize }
|
||||
|
||||
const sources = await desktopCapturer.getSources(options)
|
||||
for (const source of sources) {
|
||||
const sourceName = source.name.toLowerCase()
|
||||
if (sourceName === 'entire screen' || sourceName === 'screen 1') {
|
||||
const screenshotPath = path.join(os.tmpdir(), 'screenshot.png')
|
||||
|
||||
await fs.writeFile(screenshotPath, source.thumbnail.toPNG())
|
||||
shell.openExternal(`file://${screenshotPath}`)
|
||||
|
||||
return `Saved screenshot to: ${screenshotPath}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ipcMain.handle('take-screenshot', (event, devicePixelRatio) => takeScreenshot(devicePixelRatio))
|
||||
|
||||
function createWindow () {
|
||||
const windowOptions = {
|
||||
@@ -16,8 +40,7 @@ function createWindow () {
|
||||
height: 300,
|
||||
title: 'Take a Screenshot',
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
nodeIntegration: true
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
5
docs/fiddles/media/screenshot/take-screenshot/preload.js
Normal file
5
docs/fiddles/media/screenshot/take-screenshot/preload.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron/renderer')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
takeScreenshot: () => ipcRenderer.invoke('take-screenshot', window.devicePixelRatio)
|
||||
})
|
||||
@@ -1,37 +1,7 @@
|
||||
const { shell, ipcRenderer } = require('electron')
|
||||
|
||||
const fs = require('node:fs').promises
|
||||
const os = require('node:os')
|
||||
const path = require('node:path')
|
||||
|
||||
const screenshot = document.getElementById('screen-shot')
|
||||
const screenshotMsg = document.getElementById('screenshot-path')
|
||||
|
||||
screenshot.addEventListener('click', async (event) => {
|
||||
screenshotMsg.textContent = 'Gathering screens...'
|
||||
const thumbSize = await determineScreenShotSize()
|
||||
const options = { types: ['screen'], thumbnailSize: thumbSize }
|
||||
|
||||
const sources = await ipcRenderer.invoke('get-sources', options)
|
||||
for (const source of sources) {
|
||||
const sourceName = source.name.toLowerCase()
|
||||
if (sourceName === 'entire screen' || sourceName === 'screen 1') {
|
||||
const screenshotPath = path.join(os.tmpdir(), 'screenshot.png')
|
||||
|
||||
await fs.writeFile(screenshotPath, source.thumbnail.toPNG())
|
||||
shell.openExternal(`file://${screenshotPath}`)
|
||||
|
||||
const message = `Saved screenshot to: ${screenshotPath}`
|
||||
screenshotMsg.textContent = message
|
||||
}
|
||||
}
|
||||
screenshotMsg.textContent = await window.electronAPI.takeScreenshot()
|
||||
})
|
||||
|
||||
async function determineScreenShotSize () {
|
||||
const screenSize = await ipcRenderer.invoke('get-screen-size')
|
||||
const maxDimension = Math.max(screenSize.width, screenSize.height)
|
||||
return {
|
||||
width: maxDimension * window.devicePixelRatio,
|
||||
height: maxDimension * window.devicePixelRatio
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,10 +119,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -6,8 +6,10 @@ const {
|
||||
ipcMain,
|
||||
app,
|
||||
shell,
|
||||
dialog
|
||||
} = require('electron')
|
||||
dialog,
|
||||
autoUpdater
|
||||
} = require('electron/main')
|
||||
const path = require('node:path')
|
||||
|
||||
const menu = new Menu()
|
||||
menu.append(new MenuItem({ label: 'Hello' }))
|
||||
@@ -66,9 +68,9 @@ const template = [
|
||||
// on reload, start fresh and close any old
|
||||
// open secondary windows
|
||||
if (focusedWindow.id === 1) {
|
||||
BrowserWindow.getAllWindows().forEach(win => {
|
||||
for (const win of BrowserWindow.getAllWindows()) {
|
||||
if (win.id > 1) win.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
focusedWindow.reload()
|
||||
}
|
||||
@@ -185,7 +187,7 @@ function addUpdateMenuItems (items, position) {
|
||||
visible: false,
|
||||
key: 'checkForUpdate',
|
||||
click: () => {
|
||||
require('electron').autoUpdater.checkForUpdates()
|
||||
autoUpdater.checkForUpdates()
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -194,7 +196,7 @@ function addUpdateMenuItems (items, position) {
|
||||
visible: false,
|
||||
key: 'restartToUpdate',
|
||||
click: () => {
|
||||
require('electron').autoUpdater.quitAndInstall()
|
||||
autoUpdater.quitAndInstall()
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -207,15 +209,15 @@ function findReopenMenuItem () {
|
||||
if (!menu) return
|
||||
|
||||
let reopenMenuItem
|
||||
menu.items.forEach(item => {
|
||||
for (const item of menu.items) {
|
||||
if (item.submenu) {
|
||||
item.submenu.items.forEach(item => {
|
||||
if (item.key === 'reopenMenuItem') {
|
||||
reopenMenuItem = item
|
||||
for (const subitem of item.submenu.items) {
|
||||
if (subitem.key === 'reopenMenuItem') {
|
||||
reopenMenuItem = subitem
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return reopenMenuItem
|
||||
}
|
||||
|
||||
@@ -294,8 +296,7 @@ function createWindow () {
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
nodeIntegration: true
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
5
docs/fiddles/menus/customize-menus/preload.js
Normal file
5
docs/fiddles/menus/customize-menus/preload.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron/renderer')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
showContextMenu: () => ipcRenderer.send('show-context-menu')
|
||||
})
|
||||
@@ -1,8 +1,6 @@
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
// Tell main process to show the menu when demo button is clicked
|
||||
const contextMenuBtn = document.getElementById('context-menu')
|
||||
|
||||
contextMenuBtn.addEventListener('click', () => {
|
||||
ipcRenderer.send('show-context-menu')
|
||||
window.electronAPI.showContextMenu()
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, globalShortcut, dialog, shell } = require('electron')
|
||||
const { app, BrowserWindow, globalShortcut, dialog, shell } = require('electron/main')
|
||||
|
||||
// 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.
|
||||
@@ -9,11 +9,7 @@ function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
nodeIntegration: true
|
||||
}
|
||||
height: 600
|
||||
})
|
||||
|
||||
globalShortcut.register('CommandOrControl+Alt+K', () => {
|
||||
|
||||
@@ -73,9 +73,6 @@ ipcMain.on('open-error-dialog', (event) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron/main')
|
||||
const path = require('node: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.
|
||||
@@ -11,8 +12,7 @@ function createWindow () {
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
nodeIntegration: true
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
5
docs/fiddles/native-ui/dialogs/error-dialog/preload.js
Normal file
5
docs/fiddles/native-ui/dialogs/error-dialog/preload.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron/renderer')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
openErrorDialog: () => ipcRenderer.send('open-error-dialog')
|
||||
})
|
||||
@@ -1,7 +1,5 @@
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
const errorBtn = document.getElementById('error-dialog')
|
||||
|
||||
errorBtn.addEventListener('click', event => {
|
||||
ipcRenderer.send('open-error-dialog')
|
||||
errorBtn.addEventListener('click', () => {
|
||||
window.electronAPI.openErrorDialog()
|
||||
})
|
||||
|
||||
@@ -96,9 +96,6 @@ ipcMain.on('open-information-dialog', (event) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron/main')
|
||||
const path = require('node: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.
|
||||
@@ -11,8 +12,7 @@ function createWindow () {
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
nodeIntegration: true
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
@@ -59,16 +59,14 @@ app.on('activate', function () {
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('open-information-dialog', event => {
|
||||
ipcMain.handle('open-information-dialog', async () => {
|
||||
const options = {
|
||||
type: 'info',
|
||||
title: 'Information',
|
||||
message: "This is an information dialog. Isn't it nice?",
|
||||
buttons: ['Yes', 'No']
|
||||
}
|
||||
dialog.showMessageBox(options, index => {
|
||||
event.sender.send('information-dialog-selection', index)
|
||||
})
|
||||
return (await dialog.showMessageBox(options)).response
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron/renderer')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
openInformationDialog: () => ipcRenderer.invoke('open-information-dialog')
|
||||
})
|
||||
@@ -1,14 +1,7 @@
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
const informationBtn = document.getElementById('information-dialog')
|
||||
|
||||
informationBtn.addEventListener('click', event => {
|
||||
ipcRenderer.send('open-information-dialog')
|
||||
})
|
||||
|
||||
ipcRenderer.on('information-dialog-selection', (event, index) => {
|
||||
let message = 'You selected '
|
||||
if (index === 0) message += 'yes.'
|
||||
else message += 'no.'
|
||||
informationBtn.addEventListener('click', async () => {
|
||||
const index = await window.electronAPI.openInformationDialog()
|
||||
const message = `You selected: ${index === 0 ? 'yes' : 'no'}`
|
||||
document.getElementById('info-selection').innerHTML = message
|
||||
})
|
||||
|
||||
@@ -100,9 +100,6 @@ ipc.on('open-file-dialog-sheet', function (event) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron/main')
|
||||
const path = require('node: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.
|
||||
@@ -11,8 +12,7 @@ function createWindow () {
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
nodeIntegration: true
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
@@ -59,17 +59,11 @@ app.on('activate', function () {
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('open-file-dialog', event => {
|
||||
dialog.showOpenDialog(
|
||||
{
|
||||
properties: ['openFile', 'openDirectory']
|
||||
},
|
||||
files => {
|
||||
if (files) {
|
||||
event.sender.send('selected-directory', files)
|
||||
}
|
||||
}
|
||||
)
|
||||
ipcMain.handle('open-file-dialog', async () => {
|
||||
const options = {
|
||||
properties: ['openFile', 'openDirectory']
|
||||
}
|
||||
return (await dialog.showOpenDialog(options)).filePaths
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron/renderer')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
openFileDialog: () => ipcRenderer.invoke('open-file-dialog')
|
||||
})
|
||||
@@ -1,11 +1,6 @@
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
const selectDirBtn = document.getElementById('select-directory')
|
||||
|
||||
selectDirBtn.addEventListener('click', event => {
|
||||
ipcRenderer.send('open-file-dialog')
|
||||
})
|
||||
|
||||
ipcRenderer.on('selected-directory', (event, path) => {
|
||||
selectDirBtn.addEventListener('click', async () => {
|
||||
const path = await window.electronAPI.openFileDialog()
|
||||
document.getElementById('selected-file').innerHTML = `You selected: ${path}`
|
||||
})
|
||||
|
||||
@@ -83,9 +83,6 @@ ipcMain.on('save-dialog', (event) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron/main')
|
||||
const path = require('node: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.
|
||||
@@ -11,8 +12,7 @@ function createWindow () {
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
nodeIntegration: true
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
@@ -59,14 +59,12 @@ app.on('activate', function () {
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('save-dialog', event => {
|
||||
ipcMain.handle('save-dialog', async () => {
|
||||
const options = {
|
||||
title: 'Save an Image',
|
||||
filters: [{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }]
|
||||
}
|
||||
dialog.showSaveDialog(options, filename => {
|
||||
event.sender.send('saved-file', filename)
|
||||
})
|
||||
return (await dialog.showSaveDialog(options)).filePath
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
|
||||
5
docs/fiddles/native-ui/dialogs/save-dialog/preload.js
Normal file
5
docs/fiddles/native-ui/dialogs/save-dialog/preload.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron/renderer')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
saveDialog: () => ipcRenderer.invoke('save-dialog')
|
||||
})
|
||||
@@ -1,12 +1,6 @@
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
const saveBtn = document.getElementById('save-dialog')
|
||||
|
||||
saveBtn.addEventListener('click', event => {
|
||||
ipcRenderer.send('save-dialog')
|
||||
})
|
||||
|
||||
ipcRenderer.on('saved-file', (event, path) => {
|
||||
if (!path) path = 'No path'
|
||||
saveBtn.addEventListener('click', async () => {
|
||||
const path = await window.electronAPI.saveDialog()
|
||||
document.getElementById('file-saved').innerHTML = `Path selected: ${path}`
|
||||
})
|
||||
|
||||
@@ -68,9 +68,6 @@ ipcMain.on('ondragstart', (event, filepath) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, nativeImage, shell } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain, nativeImage, shell } = require('electron/main')
|
||||
const path = require('node: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
|
||||
@@ -10,8 +12,7 @@ function createWindow () {
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
nodeIntegration: true
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
@@ -58,7 +59,8 @@ app.on('activate', function () {
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('ondragstart', (event, filepath) => {
|
||||
ipcMain.on('ondragstart', (event) => {
|
||||
const filepath = path.join(__dirname, 'renderer.js')
|
||||
const icon = nativeImage.createFromDataURL('data:image/png;base64,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')
|
||||
|
||||
event.sender.startDrag({
|
||||
|
||||
5
docs/fiddles/native-ui/drag-and-drop/preload.js
Normal file
5
docs/fiddles/native-ui/drag-and-drop/preload.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron/renderer')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
dragStart: () => ipcRenderer.send('ondragstart')
|
||||
})
|
||||
@@ -1,8 +1,6 @@
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
const dragFileLink = document.getElementById('drag-file-link')
|
||||
|
||||
dragFileLink.addEventListener('dragstart', event => {
|
||||
event.preventDefault()
|
||||
ipcRenderer.send('ondragstart', __filename)
|
||||
window.electronAPI.dragStart()
|
||||
})
|
||||
|
||||
@@ -95,10 +95,6 @@ for (const link of links) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, shell } = require('electron')
|
||||
const { app, BrowserWindow, shell, ipcMain } = require('electron/main')
|
||||
const path = require('node:path')
|
||||
const os = require('node:os')
|
||||
|
||||
ipcMain.on('open-home-dir', () => {
|
||||
shell.showItemInFolder(os.homedir())
|
||||
})
|
||||
|
||||
ipcMain.on('open-external', (event, url) => {
|
||||
shell.openExternal(url)
|
||||
})
|
||||
|
||||
// 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.
|
||||
@@ -11,8 +21,7 @@ function createWindow () {
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
nodeIntegration: true
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron/renderer')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
openHomeDir: () => ipcRenderer.send('open-home-dir'),
|
||||
openExternal: (url) => ipcRenderer.send('open-external', url)
|
||||
})
|
||||
@@ -1,13 +1,10 @@
|
||||
const { shell } = require('electron')
|
||||
const os = require('node:os')
|
||||
|
||||
const exLinksBtn = document.getElementById('open-ex-links')
|
||||
const fileManagerBtn = document.getElementById('open-file-manager')
|
||||
|
||||
fileManagerBtn.addEventListener('click', (event) => {
|
||||
shell.showItemInFolder(os.homedir())
|
||||
window.electronAPI.openHomeDir()
|
||||
})
|
||||
|
||||
exLinksBtn.addEventListener('click', (event) => {
|
||||
shell.openExternal('https://electronjs.org')
|
||||
window.electronAPI.openExternal('https://electronjs.org')
|
||||
})
|
||||
|
||||
@@ -59,9 +59,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require("./renderer.js");
|
||||
</script>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, shell } = require('electron')
|
||||
const { app, BrowserWindow, shell } = require('electron/main')
|
||||
|
||||
// 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.
|
||||
@@ -9,11 +9,7 @@ function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
nodeIntegration: true
|
||||
}
|
||||
height: 600
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { app, Tray, Menu, nativeImage } = require('electron')
|
||||
const { app, Tray, Menu, nativeImage } = require('electron/main')
|
||||
|
||||
let tray
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user