mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
190 Commits
v2.0.0-bet
...
v2.0.11
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f6d86c872 | ||
|
|
bdc9faa083 | ||
|
|
3e35f77da4 | ||
|
|
464f144a2b | ||
|
|
8f92396ed4 | ||
|
|
4e41a79404 | ||
|
|
d3c153e85a | ||
|
|
503b488153 | ||
|
|
005a65da79 | ||
|
|
36da7dcd5f | ||
|
|
0e5f734a1a | ||
|
|
3aeaf10e64 | ||
|
|
d70942190c | ||
|
|
ac400e5cb9 | ||
|
|
333d5fb5d2 | ||
|
|
f2c12ccbf5 | ||
|
|
79af1ea6f1 | ||
|
|
1ed7875b0b | ||
|
|
67a690e536 | ||
|
|
5f3bedd1e0 | ||
|
|
670a875792 | ||
|
|
faf82245dc | ||
|
|
066eeb5b5f | ||
|
|
77ec86b894 | ||
|
|
bf82dc7896 | ||
|
|
b4c5a30469 | ||
|
|
7ed6e2b909 | ||
|
|
8edd18be90 | ||
|
|
3bc9ae7f5b | ||
|
|
760c2327b4 | ||
|
|
fcb5069d24 | ||
|
|
221ab080a1 | ||
|
|
addf069f26 | ||
|
|
80221e52d9 | ||
|
|
3403b4a4de | ||
|
|
a1ac930f4d | ||
|
|
ed8396c6f5 | ||
|
|
a457d8823a | ||
|
|
2d44dcb8be | ||
|
|
85da731867 | ||
|
|
3af5fdb831 | ||
|
|
f1b197acbb | ||
|
|
d483c81887 | ||
|
|
3ef980ae2b | ||
|
|
36e68b46df | ||
|
|
f611dfdb5c | ||
|
|
148d0d8d29 | ||
|
|
79a1382126 | ||
|
|
b0d5ba1996 | ||
|
|
088dc70dae | ||
|
|
ad686cca68 | ||
|
|
48a4b58cc1 | ||
|
|
c1ef824e4c | ||
|
|
a2eb532720 | ||
|
|
0cb53ceb9d | ||
|
|
afe4e610ae | ||
|
|
74d90fbb33 | ||
|
|
f3bd8f6133 | ||
|
|
863c511fbf | ||
|
|
03d8689ded | ||
|
|
ff2bc1d705 | ||
|
|
a1df8befde | ||
|
|
75909685f7 | ||
|
|
2e0a015168 | ||
|
|
740b2797c5 | ||
|
|
5f372f7ecc | ||
|
|
e4f4a1d9f9 | ||
|
|
bdc255fa9e | ||
|
|
e8e542b3e8 | ||
|
|
dd89aa6c77 | ||
|
|
79caff69f5 | ||
|
|
67b10135b6 | ||
|
|
6a86831b7c | ||
|
|
dffd17ab70 | ||
|
|
cf98934dd9 | ||
|
|
2fff138740 | ||
|
|
82bc83c1de | ||
|
|
3a699741da | ||
|
|
237ad9a49d | ||
|
|
45158bdad5 | ||
|
|
cf4861b575 | ||
|
|
a76adba2b3 | ||
|
|
6689dce5ba | ||
|
|
9667b835ca | ||
|
|
58295a3198 | ||
|
|
b60125f782 | ||
|
|
2af6d9ced7 | ||
|
|
664c184fcb | ||
|
|
c125576d48 | ||
|
|
6030146b45 | ||
|
|
17297d85f8 | ||
|
|
65bbf21c08 | ||
|
|
00da6ab43b | ||
|
|
d6d2a46821 | ||
|
|
423bdda1b1 | ||
|
|
849aeced8f | ||
|
|
05a7485880 | ||
|
|
3db1b5a49a | ||
|
|
1c272503c3 | ||
|
|
1ebb8975a8 | ||
|
|
fcf4c9cef1 | ||
|
|
3e5349bf39 | ||
|
|
66988adb0e | ||
|
|
91be3f343f | ||
|
|
475006c10d | ||
|
|
d71a7d89bb | ||
|
|
abcba2b509 | ||
|
|
d06c20f836 | ||
|
|
3ab99663eb | ||
|
|
a253323ea1 | ||
|
|
4abe5a2963 | ||
|
|
aada5fb167 | ||
|
|
4efed0f5ed | ||
|
|
475a1e30d9 | ||
|
|
4aedc2c21a | ||
|
|
71668858db | ||
|
|
2573d52860 | ||
|
|
989c2605b3 | ||
|
|
afcfd473d0 | ||
|
|
1499bafe59 | ||
|
|
419fae76b4 | ||
|
|
c7b85a104a | ||
|
|
c6ea424858 | ||
|
|
ba23c0d600 | ||
|
|
d4e716477e | ||
|
|
34dbe5f176 | ||
|
|
a09fa53d80 | ||
|
|
c140c84b32 | ||
|
|
55ab1d7370 | ||
|
|
cfa247967f | ||
|
|
311f7ac6bb | ||
|
|
52a44facfd | ||
|
|
5acb7a0226 | ||
|
|
afcf94a85c | ||
|
|
c42b468966 | ||
|
|
e0257acdf5 | ||
|
|
b555434aa0 | ||
|
|
9574a4f472 | ||
|
|
2f167ce3d1 | ||
|
|
8655d5e9ae | ||
|
|
2e06e0eccd | ||
|
|
773f08ca43 | ||
|
|
13850b9dff | ||
|
|
1c57c76496 | ||
|
|
e459b38c5d | ||
|
|
9796513b83 | ||
|
|
d3e5f430c7 | ||
|
|
df22eccfc1 | ||
|
|
214c352f71 | ||
|
|
0070637b5a | ||
|
|
72b944f862 | ||
|
|
2fbb371689 | ||
|
|
e2e70e9b1e | ||
|
|
324b769751 | ||
|
|
e1d54d55be | ||
|
|
1d54032ba4 | ||
|
|
c6e4de16de | ||
|
|
f39cc1cc46 | ||
|
|
6af89eb260 | ||
|
|
d33b71cc2d | ||
|
|
d0bbf3fb3c | ||
|
|
289db66fee | ||
|
|
6b90807cb8 | ||
|
|
cf4f078aca | ||
|
|
4eedd1455d | ||
|
|
9c167b63f2 | ||
|
|
d18ab0ca08 | ||
|
|
724cbc967c | ||
|
|
b9d589439f | ||
|
|
f37bc4a9d4 | ||
|
|
597c8964f6 | ||
|
|
652f83fc88 | ||
|
|
d432038aab | ||
|
|
5d8f36c53c | ||
|
|
85dfdd6665 | ||
|
|
de428ebec0 | ||
|
|
c6c49b9e4b | ||
|
|
98495fabfb | ||
|
|
06c33c7e56 | ||
|
|
33aad6ae11 | ||
|
|
6c00b37dd1 | ||
|
|
d209e59c30 | ||
|
|
14f8a2a0e8 | ||
|
|
65e1252da0 | ||
|
|
2903d7608c | ||
|
|
0bc72961ab | ||
|
|
b55a24c025 | ||
|
|
51bca764f7 | ||
|
|
35976a0a07 | ||
|
|
283ab23524 |
@@ -64,13 +64,17 @@ jobs:
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ] && [ "$AUTO_RELEASE" == "true" ]; then
|
||||
echo 'Trying to finish release'
|
||||
node script/release.js --automaticRelease
|
||||
node script/release.js --validateRelease --automaticRelease
|
||||
releaseExitCode=$?
|
||||
if [ $releaseExitCode -eq 0 ]; then
|
||||
echo 'Release successful, now publishing to npm'
|
||||
echo "//registry.npmjs.org/:_authToken=$ELECTRON_NPM_TOKEN" >> ~/.npmrc
|
||||
npm run publish-to-npm
|
||||
echo 'Release has been published to npm'
|
||||
echo 'Release is ready to go; releasing'
|
||||
node script/release.js--automaticRelease
|
||||
if [ $releaseExitCode -eq 0 ]; then
|
||||
echo 'Release successful, now publishing to npm'
|
||||
echo "//registry.npmjs.org/:_authToken=$ELECTRON_NPM_TOKEN" >> ~/.npmrc
|
||||
npm run publish-to-npm
|
||||
echo 'Release has been published to npm'
|
||||
fi
|
||||
else
|
||||
echo 'Release is not complete, skipping publish for now'
|
||||
fi
|
||||
@@ -176,13 +180,17 @@ jobs:
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ] && [ "$AUTO_RELEASE" == "true" ]; then
|
||||
echo 'Trying to finish release'
|
||||
node script/release.js --automaticRelease
|
||||
node script/release.js --validateRelease --automaticRelease
|
||||
releaseExitCode=$?
|
||||
if [ $releaseExitCode -eq 0 ]; then
|
||||
echo 'Release successful, now publishing to npm'
|
||||
echo "//registry.npmjs.org/:_authToken=$ELECTRON_NPM_TOKEN" >> ~/.npmrc
|
||||
npm run publish-to-npm
|
||||
echo 'Release has been published to npm'
|
||||
echo 'Release is ready to go; releasing'
|
||||
node script/release.js--automaticRelease
|
||||
if [ $releaseExitCode -eq 0 ]; then
|
||||
echo 'Release successful, now publishing to npm'
|
||||
echo "//registry.npmjs.org/:_authToken=$ELECTRON_NPM_TOKEN" >> ~/.npmrc
|
||||
npm run publish-to-npm
|
||||
echo 'Release has been published to npm'
|
||||
fi
|
||||
else
|
||||
echo 'Release is not complete, skipping publish for now'
|
||||
fi
|
||||
@@ -292,13 +300,17 @@ jobs:
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ] && [ "$AUTO_RELEASE" == "true" ]; then
|
||||
echo 'Trying to finish release'
|
||||
node script/release.js --automaticRelease
|
||||
node script/release.js --validateRelease --automaticRelease
|
||||
releaseExitCode=$?
|
||||
if [ $releaseExitCode -eq 0 ]; then
|
||||
echo 'Release successful, now publishing to npm'
|
||||
echo "//registry.npmjs.org/:_authToken=$ELECTRON_NPM_TOKEN" >> ~/.npmrc
|
||||
npm run publish-to-npm
|
||||
echo 'Release has been published to npm'
|
||||
echo 'Release is ready to go; releasing'
|
||||
node script/release.js--automaticRelease
|
||||
if [ $releaseExitCode -eq 0 ]; then
|
||||
echo 'Release successful, now publishing to npm'
|
||||
echo "//registry.npmjs.org/:_authToken=$ELECTRON_NPM_TOKEN" >> ~/.npmrc
|
||||
npm run publish-to-npm
|
||||
echo 'Release has been published to npm'
|
||||
fi
|
||||
else
|
||||
echo 'Release is not complete, skipping publish for now'
|
||||
fi
|
||||
@@ -391,13 +403,17 @@ jobs:
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ] && [ "$AUTO_RELEASE" == "true" ]; then
|
||||
echo 'Trying to finish release'
|
||||
node script/release.js --automaticRelease
|
||||
node script/release.js --validateRelease --automaticRelease
|
||||
releaseExitCode=$?
|
||||
if [ $releaseExitCode -eq 0 ]; then
|
||||
echo 'Release successful, now publishing to npm'
|
||||
echo "//registry.npmjs.org/:_authToken=$ELECTRON_NPM_TOKEN" >> ~/.npmrc
|
||||
npm run publish-to-npm
|
||||
echo 'Release has been published to npm'
|
||||
echo 'Release is ready to go; releasing'
|
||||
node script/release.js--automaticRelease
|
||||
if [ $releaseExitCode -eq 0 ]; then
|
||||
echo 'Release successful, now publishing to npm'
|
||||
echo "//registry.npmjs.org/:_authToken=$ELECTRON_NPM_TOKEN" >> ~/.npmrc
|
||||
npm run publish-to-npm
|
||||
echo 'Release has been published to npm'
|
||||
fi
|
||||
else
|
||||
echo 'Release is not complete, skipping publish for now'
|
||||
fi
|
||||
@@ -472,13 +488,17 @@ jobs:
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ] && [ "$AUTO_RELEASE" == "true" ]; then
|
||||
echo 'Trying to finish release'
|
||||
node script/release.js --automaticRelease
|
||||
node script/release.js --validateRelease --automaticRelease
|
||||
releaseExitCode=$?
|
||||
if [ $releaseExitCode -eq 0 ]; then
|
||||
echo 'Release successful, now publishing to npm'
|
||||
echo "//registry.npmjs.org/:_authToken=$ELECTRON_NPM_TOKEN" >> ~/.npmrc
|
||||
npm run publish-to-npm
|
||||
echo 'Release has been published to npm'
|
||||
echo 'Release is ready to go; releasing'
|
||||
node script/release.js--automaticRelease
|
||||
if [ $releaseExitCode -eq 0 ]; then
|
||||
echo 'Release successful, now publishing to npm'
|
||||
echo "//registry.npmjs.org/:_authToken=$ELECTRON_NPM_TOKEN" >> ~/.npmrc
|
||||
npm run publish-to-npm
|
||||
echo 'Release has been published to npm'
|
||||
fi
|
||||
else
|
||||
echo 'Release is not complete, skipping publish for now'
|
||||
fi
|
||||
@@ -519,6 +539,201 @@ jobs:
|
||||
- store_artifacts:
|
||||
path: out/electron-api.json
|
||||
|
||||
electron-osx-x64:
|
||||
environment:
|
||||
TARGET_ARCH: x64
|
||||
macos:
|
||||
xcode: "9.0"
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Reclaim disk space
|
||||
command: |
|
||||
df -h
|
||||
sudo rm -rf /Library/Developer/CoreSimulator
|
||||
df -h
|
||||
sysctl -n hw.ncpu
|
||||
- run:
|
||||
name: Check for release
|
||||
command: |
|
||||
if [ -n "${RUN_RELEASE_BUILD}" ]; then
|
||||
echo 'release build triggered from api'
|
||||
echo 'export ELECTRON_RELEASE=1 TRIGGERED_BY_API=1' >> $BASH_ENV
|
||||
fi
|
||||
- run:
|
||||
name: Bootstrap
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ]; then
|
||||
echo 'Bootstrapping Electron for release build'
|
||||
script/bootstrap.py --target_arch=$TARGET_ARCH
|
||||
else
|
||||
echo 'Bootstrapping Electron for debug build'
|
||||
script/bootstrap.py --target_arch=$TARGET_ARCH --dev
|
||||
fi
|
||||
- run: npm run lint
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ]; then
|
||||
echo 'Building Electron for release'
|
||||
script/build.py -c R
|
||||
else
|
||||
echo 'Building Electron for debug'
|
||||
script/build.py -c D
|
||||
fi
|
||||
- run:
|
||||
name: Create distribution
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ]; then
|
||||
echo 'Creating Electron release distribution'
|
||||
script/create-dist.py
|
||||
else
|
||||
echo 'Skipping create distribution because build is not for release'
|
||||
fi
|
||||
- run:
|
||||
name: Upload distribution
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ] && [ "$TRIGGERED_BY_API" != "1" ]; then
|
||||
echo 'Uploading Electron release distribution to github releases'
|
||||
script/upload.py
|
||||
elif [ "$ELECTRON_RELEASE" == "1" ] && [ "$TRIGGERED_BY_API" == "1" ]; then
|
||||
echo 'Uploading Electron release distribution to s3'
|
||||
script/upload.py --upload_to_s3
|
||||
else
|
||||
echo 'Skipping upload distribution because build is not for release'
|
||||
fi
|
||||
- run:
|
||||
name: Test
|
||||
environment:
|
||||
MOCHA_FILE: junit/test-results.xml
|
||||
MOCHA_REPORTER: mocha-junit-reporter
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" != "1" ]; then
|
||||
echo 'Testing Electron debug build'
|
||||
mkdir junit
|
||||
script/test.py --ci --rebuild_native_modules
|
||||
else
|
||||
echo 'Skipping testing on release build'
|
||||
fi
|
||||
- run:
|
||||
name: Verify FFmpeg
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" != "1" ]; then
|
||||
echo 'Verifying ffmpeg on debug build'
|
||||
script/verify-ffmpeg.py
|
||||
else
|
||||
echo 'Skipping verify ffmpeg on release build'
|
||||
fi
|
||||
- run:
|
||||
name: Generate Typescript Definitions
|
||||
command: npm run create-typescript-definitions
|
||||
- store_test_results:
|
||||
path: junit
|
||||
- store_artifacts:
|
||||
path: junit
|
||||
- store_artifacts:
|
||||
path: out/electron.d.ts
|
||||
- store_artifacts:
|
||||
path: out/electron-api.json
|
||||
|
||||
electron-mas-x64:
|
||||
environment:
|
||||
TARGET_ARCH: x64
|
||||
MAS_BUILD: 1
|
||||
macos:
|
||||
xcode: "9.0"
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Reclaim disk space
|
||||
command: |
|
||||
df -h
|
||||
sudo rm -rf /Library/Developer/CoreSimulator
|
||||
df -h
|
||||
sysctl -n hw.ncpu
|
||||
- run:
|
||||
name: Check for release
|
||||
command: |
|
||||
if [ -n "${RUN_RELEASE_BUILD}" ]; then
|
||||
echo 'release build triggered from api'
|
||||
echo 'export ELECTRON_RELEASE=1 TRIGGERED_BY_API=1' >> $BASH_ENV
|
||||
fi
|
||||
- run:
|
||||
name: Bootstrap
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ]; then
|
||||
echo 'Bootstrapping Electron for release build'
|
||||
script/bootstrap.py --target_arch=$TARGET_ARCH
|
||||
else
|
||||
echo 'Bootstrapping Electron for debug build'
|
||||
script/bootstrap.py --target_arch=$TARGET_ARCH --dev
|
||||
fi
|
||||
- run: npm run lint
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ]; then
|
||||
echo 'Building Electron for release'
|
||||
script/build.py -c R
|
||||
else
|
||||
echo 'Building Electron for debug'
|
||||
script/build.py -c D
|
||||
fi
|
||||
- run:
|
||||
name: Create distribution
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ]; then
|
||||
echo 'Creating Electron release distribution'
|
||||
script/create-dist.py
|
||||
else
|
||||
echo 'Skipping create distribution because build is not for release'
|
||||
fi
|
||||
- run:
|
||||
name: Upload distribution
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ] && [ "$TRIGGERED_BY_API" != "1" ]; then
|
||||
echo 'Uploading Electron release distribution to github releases'
|
||||
script/upload.py
|
||||
elif [ "$ELECTRON_RELEASE" == "1" ] && [ "$TRIGGERED_BY_API" == "1" ]; then
|
||||
echo 'Uploading Electron release distribution to s3'
|
||||
script/upload.py --upload_to_s3
|
||||
else
|
||||
echo 'Skipping upload distribution because build is not for release'
|
||||
fi
|
||||
- run:
|
||||
name: Test
|
||||
environment:
|
||||
MOCHA_FILE: junit/test-results.xml
|
||||
MOCHA_REPORTER: mocha-junit-reporter
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" != "1" ]; then
|
||||
echo 'Testing Electron debug build'
|
||||
mkdir junit
|
||||
script/test.py --ci --rebuild_native_modules
|
||||
else
|
||||
echo 'Skipping testing on release build'
|
||||
fi
|
||||
- run:
|
||||
name: Verify FFmpeg
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" != "1" ]; then
|
||||
echo 'Verifying ffmpeg on debug build'
|
||||
script/verify-ffmpeg.py
|
||||
else
|
||||
echo 'Skipping verify ffmpeg on release build'
|
||||
fi
|
||||
- run:
|
||||
name: Generate Typescript Definitions
|
||||
command: npm run create-typescript-definitions
|
||||
- store_test_results:
|
||||
path: junit
|
||||
- store_artifacts:
|
||||
path: junit
|
||||
- store_artifacts:
|
||||
path: out/electron.d.ts
|
||||
- store_artifacts:
|
||||
path: out/electron-api.json
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build-arm:
|
||||
@@ -537,5 +752,11 @@ workflows:
|
||||
jobs:
|
||||
- electron-linux-ia32
|
||||
build-x64:
|
||||
jobs:
|
||||
- electron-linux-x64
|
||||
jobs:
|
||||
- electron-linux-x64
|
||||
build-osx-x64:
|
||||
jobs:
|
||||
- electron-osx-x64
|
||||
build-mas-x64:
|
||||
jobs:
|
||||
- electron-mas-x64
|
||||
|
||||
7
.env.example
Normal file
7
.env.example
Normal file
@@ -0,0 +1,7 @@
|
||||
# These env vars are only necessary for creating Electron releases.
|
||||
# See docs/development/releasing.md
|
||||
|
||||
APPVEYOR_TOKEN=
|
||||
CIRCLE_TOKEN=
|
||||
ELECTRON_GITHUB_TOKEN=
|
||||
VSTS_TOKEN=
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -43,6 +43,8 @@
|
||||
/vendor/llvm/
|
||||
/vendor/npm/
|
||||
/vendor/python_26/
|
||||
/vendor/native_mksnapshot
|
||||
/vendor/LICENSES.chromium.html
|
||||
node_modules/
|
||||
SHASUMS256.txt
|
||||
**/package-lock.json
|
||||
|
||||
18
README.md
18
README.md
@@ -89,22 +89,8 @@ Find documentation translations in [electron/electron-i18n](https://github.com/e
|
||||
|
||||
## Community
|
||||
|
||||
You can ask questions and interact with the community in the following
|
||||
locations:
|
||||
- [`electron`](https://discuss.atom.io/c/electron) category on the Atom
|
||||
forums
|
||||
- `#atom-shell` channel on Freenode
|
||||
- [`Atom`](https://atom-slack.herokuapp.com) channel on Slack
|
||||
- [`electron-ru`](https://telegram.me/electron_ru) *(Russian)*
|
||||
- [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)*
|
||||
- [`electron-kr`](https://electron-kr.github.io/electron-kr) *(Korean)*
|
||||
- [`electron-jp`](https://electron-jp.slack.com) *(Japanese)*
|
||||
- [`electron-tr`](https://electron-tr.herokuapp.com) *(Turkish)*
|
||||
- [`electron-id`](https://electron-id.slack.com) *(Indonesia)*
|
||||
- [`electron-pl`](https://electronpl.github.io) *(Poland)*
|
||||
|
||||
Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron)
|
||||
for a community maintained list of useful example apps, tools and resources.
|
||||
Info on reporting bugs, getting help, finding third-party tools and sample apps,
|
||||
and more can be found in the [support document](docs/tutorial/support.md#finding-support).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
69
appveyor.yml
Normal file
69
appveyor.yml
Normal file
@@ -0,0 +1,69 @@
|
||||
build_cloud: electron-16
|
||||
image: electron-16-vs2015
|
||||
build_script:
|
||||
- ps: >-
|
||||
if($env:SKIP_GYP_BUILD -eq "true") {
|
||||
Write-warning "Skipping debug build for older branch"; Exit-AppveyorBuild
|
||||
} elseif(($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME -split "/")[0] -eq ($env:APPVEYOR_REPO_NAME -split "/")[0]) {
|
||||
Write-warning "Skipping PR build for branch"; Exit-AppveyorBuild
|
||||
} else {
|
||||
Add-Path "$env:ProgramFiles (x86)\Windows Kits\10\Debuggers\x64"
|
||||
$env:path = "$env:ProgramFiles (x86)\Windows Kits\10\Debuggers\x64;$env:path"
|
||||
if($env:APPVEYOR_SCHEDULED_BUILD -eq 'True') {
|
||||
$env:RUN_RELEASE_BUILD = "1"
|
||||
}
|
||||
$Message = (git log --format=%B -n 1 HEAD) | Out-String
|
||||
if ((Test-Path Env:\RUN_RELEASE_BUILD)) {
|
||||
$env:ELECTRON_RELEASE = '1'
|
||||
Write-Output "release build triggered from api"
|
||||
}
|
||||
if ((Test-Path Env:\ELECTRON_RELEASE)) {
|
||||
Write-Output "Running release build"
|
||||
python script\bootstrap.py --target_arch=$env:TARGET_ARCH
|
||||
python script\build.py -c R
|
||||
python script\create-dist.py
|
||||
} else {
|
||||
Write-Output "Running debug build"
|
||||
python script\bootstrap.py --target_arch=$env:TARGET_ARCH --dev
|
||||
python script\build.py -c D
|
||||
}
|
||||
if ($? -ne 'True') {
|
||||
throw "Build failed with exit code $?"
|
||||
} else {
|
||||
"Build succeeded."
|
||||
}
|
||||
Push-AppveyorArtifact out
|
||||
}
|
||||
test_script:
|
||||
- ps: >-
|
||||
if (Test-Path Env:\ELECTRON_RELEASE) {
|
||||
Write-Output "Skipping tests for release build"
|
||||
} else {
|
||||
Write-Output "Running tests for debug build"
|
||||
python script\test.py --ci --rebuild_native_modules
|
||||
if ($LASTEXITCODE -ne '0') {
|
||||
throw "Tests failed with exit code $LASTEXITCODE"
|
||||
} else {
|
||||
Write-Output "Tests succeeded."
|
||||
}
|
||||
python script\verify-ffmpeg.py
|
||||
if ($LASTEXITCODE -ne '0') {
|
||||
throw "Verify ffmpeg failed with exit code $LASTEXITCODE"
|
||||
} else {
|
||||
"Verify ffmpeg succeeded."
|
||||
}
|
||||
}
|
||||
artifacts:
|
||||
- path: test-results.xml
|
||||
name: test-results.xml
|
||||
deploy_script:
|
||||
- ps: >-
|
||||
if (Test-Path Env:\ELECTRON_RELEASE) {
|
||||
if (Test-Path Env:\RUN_RELEASE_BUILD) {
|
||||
Write-Output "Uploading Electron release distribution to s3"
|
||||
& python script\upload.py --upload_to_s3
|
||||
} else {
|
||||
Write-Output "Uploading Electron release distribution to github releases"
|
||||
& python script\upload.py
|
||||
}
|
||||
}
|
||||
@@ -43,12 +43,12 @@ bool IsUrlArg(const base::CommandLine::CharType* arg) {
|
||||
* Update the list by pasting the following command into bash
|
||||
* in libchromiumcontent/src/:
|
||||
|
||||
(find ./ -name "*switches.cc" | \
|
||||
xargs grep -P --no-filename "\"\S+\";" | \
|
||||
perl -pe 's|^.*?"(\S+)";| "$1",|'; \
|
||||
(find ./ \( -name "*switches.cc" -o -name "*switch_list.h" \) | \
|
||||
xargs grep -P --no-filename '"\S+"[);]$' | \
|
||||
perl -pe 's|^.*?"(\S+)"[);]$| "$1",|'; \
|
||||
echo ' "inspect",'; \
|
||||
echo ' "inspect-brk",') | \
|
||||
LANG=C sort | \
|
||||
LANG="C" sort | \
|
||||
uniq > blacklist-switches.txt
|
||||
|
||||
*/
|
||||
@@ -62,7 +62,10 @@ const char* kBlacklist[] = {
|
||||
"/prefetch:8",
|
||||
"0",
|
||||
"?",
|
||||
"BlacklistOnly",
|
||||
"ChromeOSMemoryPressureHandling",
|
||||
"Disabled",
|
||||
"OnlineCheckOnly",
|
||||
"SafeSites",
|
||||
"accept-resource-provider",
|
||||
"account-consistency",
|
||||
@@ -72,7 +75,6 @@ const char* kBlacklist[] = {
|
||||
"aggressive",
|
||||
"aggressive-cache-discard",
|
||||
"aggressive-tab-discard",
|
||||
"all",
|
||||
"all-toolchains",
|
||||
"allarticles",
|
||||
"allow-cross-origin-auth-prompt",
|
||||
@@ -113,7 +115,6 @@ const char* kBlacklist[] = {
|
||||
"always-on",
|
||||
"always-use-complex-text",
|
||||
"alwaystrue",
|
||||
"amd-switchable",
|
||||
"android-fonts-path",
|
||||
"android-stderr-port",
|
||||
"android-stdin-port",
|
||||
@@ -141,11 +142,12 @@ const char* kBlacklist[] = {
|
||||
"arc-transition-migration-required",
|
||||
"args",
|
||||
"artifacts-dir",
|
||||
"ash-animate-from-boot-splash-screen",
|
||||
"ash-constrain-pointer-to-root",
|
||||
"ash-copy-host-background-at-boot",
|
||||
"ash-debug-shortcuts",
|
||||
"ash-dev-shortcuts",
|
||||
"ash-disable-smooth-screen-rotation",
|
||||
"ash-disable-tablet-autohide-titlebars",
|
||||
"ash-disable-touch-exploration-mode",
|
||||
"ash-enable-magnifier-key-scroller",
|
||||
"ash-enable-mirrored-screen",
|
||||
@@ -174,8 +176,6 @@ const char* kBlacklist[] = {
|
||||
"autoplay-policy",
|
||||
"blink-settings",
|
||||
"bootstrap",
|
||||
"browser",
|
||||
"browser-startup-dialog",
|
||||
"browser-subprocess-path",
|
||||
"browser-test",
|
||||
"bwsi",
|
||||
@@ -220,6 +220,7 @@ const char* kBlacklist[] = {
|
||||
"crash-test",
|
||||
"crashpad-handler",
|
||||
"create-browser-on-startup-for-tests",
|
||||
"create-default-gl-context",
|
||||
"cros-gaia-api-v1",
|
||||
"cros-region",
|
||||
"cros-regions-mode",
|
||||
@@ -228,7 +229,6 @@ const char* kBlacklist[] = {
|
||||
"custom-devtools-frontend",
|
||||
"custom-launcher-page",
|
||||
"custom_summary",
|
||||
"d3d-support",
|
||||
"d3d11",
|
||||
"d3d9",
|
||||
"daemon",
|
||||
@@ -254,6 +254,7 @@ const char* kBlacklist[] = {
|
||||
"default-wallpaper-is-oem",
|
||||
"default-wallpaper-large",
|
||||
"default-wallpaper-small",
|
||||
"delay-reload-stop-button-change",
|
||||
"demo",
|
||||
"derelict-detection-timeout",
|
||||
"derelict-idle-timeout",
|
||||
@@ -267,7 +268,6 @@ const char* kBlacklist[] = {
|
||||
"diagnostics-format",
|
||||
"diagnostics-recovery",
|
||||
"dice",
|
||||
"dice_fix_auth_errors",
|
||||
"disable",
|
||||
"disable-2d-canvas-clip-aa",
|
||||
"disable-2d-canvas-image-chromium",
|
||||
@@ -289,6 +289,7 @@ const char* kBlacklist[] = {
|
||||
"disable-backgrounding-occluded-windows",
|
||||
"disable-backing-store-limit",
|
||||
"disable-blink-features",
|
||||
"disable-bookmark-reordering",
|
||||
"disable-boot-animation",
|
||||
"disable-breakpad",
|
||||
"disable-browser-task-scheduler",
|
||||
@@ -316,6 +317,7 @@ const char* kBlacklist[] = {
|
||||
"disable-direct-composition",
|
||||
"disable-direct-composition-layers",
|
||||
"disable-directwrite-for-ui",
|
||||
"disable-display-color-calibration",
|
||||
"disable-display-list-2d-canvas",
|
||||
"disable-distance-field-text",
|
||||
"disable-domain-blocking-for-3d-apis",
|
||||
@@ -330,6 +332,7 @@ const char* kBlacklist[] = {
|
||||
"disable-extensions-except",
|
||||
"disable-extensions-file-access-check",
|
||||
"disable-extensions-http-throttling",
|
||||
"disable-fast-web-scroll-view-insets",
|
||||
"disable-features",
|
||||
"disable-field-trial-config",
|
||||
"disable-file-manager-touch-mode",
|
||||
@@ -364,11 +367,14 @@ const char* kBlacklist[] = {
|
||||
"disable-histogram-customizer",
|
||||
"disable-hosted-app-shim-creation",
|
||||
"disable-hosted-apps-in-windows",
|
||||
"disable-http2",
|
||||
"disable-in-process-stack-traces",
|
||||
"disable-infobars",
|
||||
"disable-input-ime-api",
|
||||
"disable-input-view",
|
||||
"disable-ios-password-generation",
|
||||
"disable-ios-password-suggestions",
|
||||
"disable-ios-physical-web",
|
||||
"disable-javascript-harmony-shipping",
|
||||
"disable-kill-after-bad-ipc",
|
||||
"disable-lcd-text",
|
||||
@@ -382,6 +388,7 @@ const char* kBlacklist[] = {
|
||||
"disable-low-end-device-mode",
|
||||
"disable-low-latency-dxva",
|
||||
"disable-low-res-tiling",
|
||||
"disable-lru-snapshot-cache",
|
||||
"disable-mac-overlays",
|
||||
"disable-mac-views-native-app-windows",
|
||||
"disable-machine-cert-request",
|
||||
@@ -398,6 +405,7 @@ const char* kBlacklist[] = {
|
||||
"disable-namespace-sandbox",
|
||||
"disable-native-gpu-memory-buffers",
|
||||
"disable-network-portal-notification",
|
||||
"disable-new-channel-switcher-ui",
|
||||
"disable-new-korean-ime",
|
||||
"disable-new-virtual-keyboard-behavior",
|
||||
"disable-new-zip-unpacker",
|
||||
@@ -417,7 +425,6 @@ const char* kBlacklist[] = {
|
||||
"disable-password-generation",
|
||||
"disable-pepper-3d",
|
||||
"disable-pepper-3d-image-chromium",
|
||||
"disable-per-user-timezone",
|
||||
"disable-permission-action-reporting",
|
||||
"disable-permissions-api",
|
||||
"disable-physical-keyboard-autocorrect",
|
||||
@@ -431,12 +438,15 @@ const char* kBlacklist[] = {
|
||||
"disable-proximity-auth-bluetooth-low-energy-discovery",
|
||||
"disable-pull-to-refresh-effect",
|
||||
"disable-push-api-background-mode",
|
||||
"disable-quic",
|
||||
"disable-reading-from-canvas",
|
||||
"disable-remote-core-animation",
|
||||
"disable-remote-fonts",
|
||||
"disable-remote-playback-api",
|
||||
"disable-renderer-accessibility",
|
||||
"disable-renderer-backgrounding",
|
||||
"disable-renderer-priority-management",
|
||||
"disable-request-mobile-site",
|
||||
"disable-resize-lock",
|
||||
"disable-rgba-4444-textures",
|
||||
"disable-rollback-option",
|
||||
@@ -444,6 +454,7 @@ const char* kBlacklist[] = {
|
||||
"disable-screen-orientation-lock",
|
||||
"disable-search-geolocation-disclosure",
|
||||
"disable-seccomp-filter-sandbox",
|
||||
"disable-settings-window",
|
||||
"disable-setuid-sandbox",
|
||||
"disable-shader-name-hashing",
|
||||
"disable-shared-workers",
|
||||
@@ -457,17 +468,16 @@ const char* kBlacklist[] = {
|
||||
"disable-software-rasterizer",
|
||||
"disable-speech-api",
|
||||
"disable-suggestions-ui",
|
||||
"disable-surface-references",
|
||||
"disable-sync",
|
||||
"disable-sync-app-list",
|
||||
"disable-sync-types",
|
||||
"disable-system-timezone-automatic-detection",
|
||||
"disable-tab-for-desktop-share",
|
||||
"disable-tab-strip-autoscroll-new-tabs",
|
||||
"disable-third-party-keyboard-workaround",
|
||||
"disable-threaded-animation",
|
||||
"disable-threaded-compositing",
|
||||
"disable-threaded-scrolling",
|
||||
"disable-timeouts-for-profiling",
|
||||
"disable-touch-adjustment",
|
||||
"disable-touch-drag-drop",
|
||||
"disable-translate-new-ux",
|
||||
@@ -528,18 +538,16 @@ const char* kBlacklist[] = {
|
||||
"enable-appcontainer",
|
||||
"enable-arc",
|
||||
"enable-arc-oobe-optin",
|
||||
"enable-async-event-targeting",
|
||||
"enable-audio-debug-recordings-from-extension",
|
||||
"enable-audio-focus",
|
||||
"enable-automation",
|
||||
"enable-background-fetch-persistence",
|
||||
"enable-benchmarking",
|
||||
"enable-ble-advertising-in-apps",
|
||||
"enable-blink-features",
|
||||
"enable-bookmark-reordering",
|
||||
"enable-bookmark-undo",
|
||||
"enable-browser-side-navigation",
|
||||
"enable-browser-task-scheduler",
|
||||
"enable-cast-receiver",
|
||||
"enable-checker-imaging",
|
||||
"enable-chromevox-arc-support",
|
||||
"enable-clear-browsing-data-counters",
|
||||
@@ -579,8 +587,8 @@ const char* kBlacklist[] = {
|
||||
"enable-extension-activity-log-testing",
|
||||
"enable-extension-activity-logging",
|
||||
"enable-extension-assets-sharing",
|
||||
"enable-external-drive-rename",
|
||||
"enable-fast-unload",
|
||||
"enable-fast-web-scroll-view-insets",
|
||||
"enable-features",
|
||||
"enable-file-manager-touch-mode",
|
||||
"enable-first-run-ui-transitions",
|
||||
@@ -603,6 +611,7 @@ const char* kBlacklist[] = {
|
||||
"enable-gpu-service-tracing",
|
||||
"enable-hardware-overlays",
|
||||
"enable-harfbuzz-rendertext",
|
||||
"enable-hdr",
|
||||
"enable-heap-profiling",
|
||||
"enable-hosted-app-quit-notification",
|
||||
"enable-hosted-apps-in-windows",
|
||||
@@ -610,9 +619,10 @@ const char* kBlacklist[] = {
|
||||
"enable-hung-renderer-infobar",
|
||||
"enable-inband-text-tracks",
|
||||
"enable-input-ime-api",
|
||||
"enable-instant-tethering",
|
||||
"enable-internal-media-session",
|
||||
"enable-ios-handoff-to-other-devices",
|
||||
"enable-ios-password-generation",
|
||||
"enable-ios-physical-web",
|
||||
"enable-layer-lists",
|
||||
"enable-lcd-text",
|
||||
"enable-leak-detection",
|
||||
@@ -622,9 +632,11 @@ const char* kBlacklist[] = {
|
||||
"enable-longpress-drag-selection",
|
||||
"enable-low-end-device-mode",
|
||||
"enable-low-res-tiling",
|
||||
"enable-lru-snapshot-cache",
|
||||
"enable-mac-views-native-app-windows",
|
||||
"enable-main-frame-before-activation",
|
||||
"enable-md-feedback",
|
||||
"enable-md-policy-page",
|
||||
"enable-media-suspend",
|
||||
"enable-merge-key-char-events",
|
||||
"enable-message-center-always-scroll-up-upon-notification-removal",
|
||||
@@ -645,7 +657,6 @@ const char* kBlacklist[] = {
|
||||
"enable-offer-upload-credit-cards",
|
||||
"enable-offline-auto-reload",
|
||||
"enable-offline-auto-reload-visible-only",
|
||||
"enable-oop-rasterization",
|
||||
"enable-osk-overscroll",
|
||||
"enable-override-bookmarks-ui",
|
||||
"enable-partial-raster",
|
||||
@@ -655,7 +666,6 @@ const char* kBlacklist[] = {
|
||||
"enable-physical-keyboard-autocorrect",
|
||||
"enable-picture-in-picture",
|
||||
"enable-pinch",
|
||||
"enable-pixel-canvas-recording",
|
||||
"enable-pixel-output-in-tests",
|
||||
"enable-plugin-placeholder-testing",
|
||||
"enable-potentially-annoying-security-features",
|
||||
@@ -667,6 +677,8 @@ const char* kBlacklist[] = {
|
||||
"enable-profile-shortcut-manager",
|
||||
"enable-profiling",
|
||||
"enable-push-api-background-mode",
|
||||
"enable-quic",
|
||||
"enable-reader-mode-toolbar-icon",
|
||||
"enable-refresh-token-annotation-request",
|
||||
"enable-request-tablet-site",
|
||||
"enable-rgba-4444-textures",
|
||||
@@ -676,6 +688,7 @@ const char* kBlacklist[] = {
|
||||
"enable-scripts-require-action",
|
||||
"enable-scroll-prediction",
|
||||
"enable-service-manager-tracing",
|
||||
"enable-settings-window",
|
||||
"enable-sgi-video-sync",
|
||||
"enable-signin-promo",
|
||||
"enable-single-click-autofill",
|
||||
@@ -718,6 +731,7 @@ const char* kBlacklist[] = {
|
||||
"enable-translate-new-ux",
|
||||
"enable-ui-devtools",
|
||||
"enable-use-zoom-for-dsf",
|
||||
"enable-user-controlled-alternate-protocol-ports",
|
||||
"enable-user-metrics",
|
||||
"enable-usermedia-screen-capturing",
|
||||
"enable-video-player-chromecast-support",
|
||||
@@ -734,9 +748,8 @@ const char* kBlacklist[] = {
|
||||
"enable-webgl-image-chromium",
|
||||
"enable-webrtc-event-logging-from-extension",
|
||||
"enable-webrtc-srtp-aes-gcm",
|
||||
"enable-webrtc-srtp-encrypted-headers",
|
||||
"enable-webrtc-stun-origin",
|
||||
"enable-webview-variations",
|
||||
"enable-webview-finch",
|
||||
"enable-webvr",
|
||||
"enable-wifi-credential-sync",
|
||||
"enable-win7-webrtc-hw-h264-decoding",
|
||||
@@ -759,8 +772,6 @@ const char* kBlacklist[] = {
|
||||
"enterprise-enrollment-initial-modulus",
|
||||
"enterprise-enrollment-modulus-limit",
|
||||
"error-console",
|
||||
"evaluate-type",
|
||||
"evaluate_capability",
|
||||
"experiment",
|
||||
"explicitly-allowed-ports",
|
||||
"expose-internals-for-testing",
|
||||
@@ -808,7 +819,6 @@ const char* kBlacklist[] = {
|
||||
"force-overlay-fullscreen-video",
|
||||
"force-password-reauth",
|
||||
"force-pnacl-subzero",
|
||||
"force-presentation-receiver-for-testing",
|
||||
"force-renderer-accessibility",
|
||||
"force-show-update-menu-badge",
|
||||
"force-show-update-menu-item",
|
||||
@@ -838,6 +848,7 @@ const char* kBlacklist[] = {
|
||||
"gpu-active-device-id",
|
||||
"gpu-active-vendor-id",
|
||||
"gpu-device-id",
|
||||
"gpu-driver-bug-workarounds",
|
||||
"gpu-driver-date",
|
||||
"gpu-driver-vendor",
|
||||
"gpu-driver-version",
|
||||
@@ -863,7 +874,6 @@ const char* kBlacklist[] = {
|
||||
"gpu-testing-secondary-vendor-ids",
|
||||
"gpu-testing-vendor-id",
|
||||
"gpu-vendor-id",
|
||||
"graphics-buffer-count",
|
||||
"guest-wallpaper-large",
|
||||
"guest-wallpaper-small",
|
||||
"h",
|
||||
@@ -881,6 +891,7 @@ const char* kBlacklist[] = {
|
||||
"host",
|
||||
"host-pairing-oobe",
|
||||
"host-resolver-rules",
|
||||
"host-rules",
|
||||
"icu-data-dir",
|
||||
"ignore-autocomplete-off-autofill",
|
||||
"ignore-autoplay-restrictions",
|
||||
@@ -928,10 +939,6 @@ const char* kBlacklist[] = {
|
||||
"login-manager",
|
||||
"login-profile",
|
||||
"login-user",
|
||||
"loopback-i2s-bits",
|
||||
"loopback-i2s-bus-name",
|
||||
"loopback-i2s-channels",
|
||||
"loopback-i2s-rate-hz",
|
||||
"lso-url",
|
||||
"ltr",
|
||||
"main-frame-resizes-are-orientation-changes",
|
||||
@@ -953,11 +960,11 @@ const char* kBlacklist[] = {
|
||||
"media-cache-size",
|
||||
"mem-pressure-system-reserved-kb",
|
||||
"memlog",
|
||||
"memlog-pipe",
|
||||
"memory-pressure-off",
|
||||
"memory-pressure-thresholds",
|
||||
"memory-pressure-thresholds-mb",
|
||||
"message-center-changes-while-open",
|
||||
"method",
|
||||
"metrics-client-id",
|
||||
"metrics-recording-only",
|
||||
"mhtml-generator-option",
|
||||
@@ -1013,6 +1020,7 @@ const char* kBlacklist[] = {
|
||||
"normal_vibrant",
|
||||
"note-taking-app-ids",
|
||||
"ntp-snippets-add-incomplete",
|
||||
"ntp-switch-to-existing-tab",
|
||||
"null",
|
||||
"num-raster-threads",
|
||||
"oauth2-client-id",
|
||||
@@ -1026,6 +1034,7 @@ const char* kBlacklist[] = {
|
||||
"oobe-timer-interval",
|
||||
"open-ash",
|
||||
"opengraph",
|
||||
"origin-to-force-quic-on",
|
||||
"origin-trial-disabled-features",
|
||||
"origin-trial-disabled-tokens",
|
||||
"origin-trial-public-key",
|
||||
@@ -1058,6 +1067,7 @@ const char* kBlacklist[] = {
|
||||
"ppapi-plugin-launcher",
|
||||
"ppapi-startup-dialog",
|
||||
"ppapi-subpixel-rendering-setting",
|
||||
"prerender-from-omnibox",
|
||||
"previous-app",
|
||||
"primary",
|
||||
"print-to-pdf",
|
||||
@@ -1067,6 +1077,7 @@ const char* kBlacklist[] = {
|
||||
"product-version",
|
||||
"profile-directory",
|
||||
"profiler-timing",
|
||||
"profiling",
|
||||
"profiling-at-start",
|
||||
"profiling-file",
|
||||
"profiling-flush",
|
||||
@@ -1077,8 +1088,10 @@ const char* kBlacklist[] = {
|
||||
"proxy-bypass-list",
|
||||
"proxy-pac-url",
|
||||
"proxy-server",
|
||||
"pull-to-refresh",
|
||||
"q",
|
||||
"quic-connection-options",
|
||||
"quic-max-packet-length",
|
||||
"quic-version",
|
||||
"rdp_desktop_session",
|
||||
"reader-mode-feedback",
|
||||
"reader-mode-heuristics",
|
||||
@@ -1110,7 +1123,6 @@ const char* kBlacklist[] = {
|
||||
"root",
|
||||
"root-layer-scrolls",
|
||||
"rtl",
|
||||
"run-all-compositor-stages-before-draw",
|
||||
"run-layout-test",
|
||||
"runtime-deps-list-file",
|
||||
"safebrowsing-disable-auto-update",
|
||||
@@ -1123,6 +1135,7 @@ const char* kBlacklist[] = {
|
||||
"screenshot",
|
||||
"script-executable",
|
||||
"scripts-require-action",
|
||||
"scroll-end-effect",
|
||||
"search-provider-logo-url",
|
||||
"secondary",
|
||||
"secondary-display-layout",
|
||||
@@ -1169,7 +1182,6 @@ const char* kBlacklist[] = {
|
||||
"skip-reencoding-on-skp-capture",
|
||||
"slow",
|
||||
"slow-connections-only",
|
||||
"slow-down-compositing-scale-factor",
|
||||
"slow-down-raster-scale-factor",
|
||||
"sms-test-messages",
|
||||
"spdy-proxy-auth-fallback",
|
||||
@@ -1192,6 +1204,7 @@ const char* kBlacklist[] = {
|
||||
"started",
|
||||
"stub",
|
||||
"stub-cros-settings",
|
||||
"supports-dual-gpus",
|
||||
"surface",
|
||||
"swiftshader",
|
||||
"swiftshader-webgl",
|
||||
@@ -1208,7 +1221,6 @@ const char* kBlacklist[] = {
|
||||
"system-log-upload-frequency",
|
||||
"tab-management-experiment-type-disabled",
|
||||
"tab-management-experiment-type-elderberry",
|
||||
"task-manager-show-extra-renderers",
|
||||
"task-profiler",
|
||||
"team-drives",
|
||||
"test-auto-update-ui",
|
||||
@@ -1240,7 +1252,6 @@ const char* kBlacklist[] = {
|
||||
"testing-fixed-http-port",
|
||||
"testing-fixed-https-port",
|
||||
"tether-stub",
|
||||
"third-party-doodle-url",
|
||||
"threads",
|
||||
"time",
|
||||
"timeout",
|
||||
@@ -1300,6 +1311,7 @@ const char* kBlacklist[] = {
|
||||
"unsafely-treat-insecure-origin-as-secure",
|
||||
"use-angle",
|
||||
"use-cras",
|
||||
"use-double-buffering",
|
||||
"use-fake-device-for-media-stream",
|
||||
"use-fake-jpeg-decode-accelerator",
|
||||
"use-fake-ui-for-media-stream",
|
||||
@@ -1312,10 +1324,9 @@ const char* kBlacklist[] = {
|
||||
"use-mobile-user-agent",
|
||||
"use-mock-keychain",
|
||||
"use-passthrough-cmd-decoder",
|
||||
"use-skia-renderer",
|
||||
"use-simple-cache-backend",
|
||||
"use-system-default-printer",
|
||||
"use-test-config",
|
||||
"use-viz-hit-test",
|
||||
"user-agent",
|
||||
"user-always-affiliated",
|
||||
"user-data-dir",
|
||||
@@ -1325,8 +1336,6 @@ const char* kBlacklist[] = {
|
||||
"utility-allowed-dir",
|
||||
"utility-cmd-prefix",
|
||||
"utility-run-elevated",
|
||||
"utility-sandbox-type",
|
||||
"utility-startup-dialog",
|
||||
"v",
|
||||
"v2-sandbox",
|
||||
"v2-sandbox-enabled",
|
||||
@@ -1350,6 +1359,7 @@ const char* kBlacklist[] = {
|
||||
"watcher",
|
||||
"waveout-buffers",
|
||||
"webapk-server-url",
|
||||
"webrtc-max-cpu-consumption-percentage",
|
||||
"webrtc-stun-probe-trial",
|
||||
"webview-enable-safebrowsing-support",
|
||||
"webview-sandboxed-renderer",
|
||||
|
||||
@@ -18,6 +18,12 @@
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace {
|
||||
|
||||
static scoped_nsobject<NSMenu> applicationMenu_;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
@@ -135,7 +141,18 @@ void Menu::SetApplicationMenu(Menu* base_menu) {
|
||||
base::scoped_nsobject<AtomMenuController> menu_controller(
|
||||
[[AtomMenuController alloc] initWithModel:menu->model_.get()
|
||||
useDefaultAccelerator:YES]);
|
||||
[NSApp setMainMenu:[menu_controller menu]];
|
||||
|
||||
NSRunLoop* currentRunLoop = [NSRunLoop currentRunLoop];
|
||||
[currentRunLoop cancelPerformSelector:@selector(setMainMenu:)
|
||||
target:NSApp
|
||||
argument:applicationMenu_];
|
||||
applicationMenu_.reset([[menu_controller menu] retain]);
|
||||
[[NSRunLoop currentRunLoop]
|
||||
performSelector:@selector(setMainMenu:)
|
||||
target:NSApp
|
||||
argument:applicationMenu_
|
||||
order:0
|
||||
modes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];
|
||||
|
||||
// Ensure the menu_controller_ is destroyed after main menu is set.
|
||||
menu_controller.swap(menu->menu_controller_);
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "base/guid.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "brightray/browser/media/media_device_id_salt.h"
|
||||
#include "brightray/browser/net/devtools_network_conditions.h"
|
||||
#include "brightray/browser/net/devtools_network_controller_handle.h"
|
||||
@@ -47,7 +46,6 @@
|
||||
#include "net/http/http_auth_handler_factory.h"
|
||||
#include "net/http/http_auth_preferences.h"
|
||||
#include "net/proxy/proxy_config_service_fixed.h"
|
||||
#include "net/proxy/proxy_service.h"
|
||||
#include "net/url_request/static_http_user_agent_settings.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
@@ -232,59 +230,6 @@ const char kPersistPrefix[] = "persist:";
|
||||
// Referenced session objects.
|
||||
std::map<uint32_t, v8::Global<v8::Object>> g_sessions;
|
||||
|
||||
class ResolveProxyHelper {
|
||||
public:
|
||||
ResolveProxyHelper(AtomBrowserContext* browser_context,
|
||||
const GURL& url,
|
||||
const Session::ResolveProxyCallback& callback)
|
||||
: callback_(callback),
|
||||
original_thread_(base::ThreadTaskRunnerHandle::Get()) {
|
||||
scoped_refptr<net::URLRequestContextGetter> context_getter =
|
||||
browser_context->url_request_context_getter();
|
||||
context_getter->GetNetworkTaskRunner()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&ResolveProxyHelper::ResolveProxy,
|
||||
base::Unretained(this), context_getter, url));
|
||||
}
|
||||
|
||||
void OnResolveProxyCompleted(int result) {
|
||||
std::string proxy;
|
||||
if (result == net::OK)
|
||||
proxy = proxy_info_.ToPacString();
|
||||
original_thread_->PostTask(FROM_HERE,
|
||||
base::Bind(callback_, proxy));
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
void ResolveProxy(scoped_refptr<net::URLRequestContextGetter> context_getter,
|
||||
const GURL& url) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
|
||||
net::ProxyService* proxy_service =
|
||||
context_getter->GetURLRequestContext()->proxy_service();
|
||||
net::CompletionCallback completion_callback =
|
||||
base::Bind(&ResolveProxyHelper::OnResolveProxyCompleted,
|
||||
base::Unretained(this));
|
||||
|
||||
// Start the request.
|
||||
int result = proxy_service->ResolveProxy(
|
||||
url, "GET", &proxy_info_, completion_callback, &pac_req_, nullptr,
|
||||
net::NetLogWithSource());
|
||||
|
||||
// Completed synchronously.
|
||||
if (result != net::ERR_IO_PENDING)
|
||||
completion_callback.Run(result);
|
||||
}
|
||||
|
||||
Session::ResolveProxyCallback callback_;
|
||||
net::ProxyInfo proxy_info_;
|
||||
net::ProxyService::PacRequest* pac_req_;
|
||||
scoped_refptr<base::SingleThreadTaskRunner> original_thread_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ResolveProxyHelper);
|
||||
};
|
||||
|
||||
// Runs the callback in UI thread.
|
||||
void RunCallbackInUI(const base::Callback<void()>& callback) {
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
|
||||
@@ -490,8 +435,10 @@ void Session::OnDownloadCreated(content::DownloadManager* manager,
|
||||
}
|
||||
}
|
||||
|
||||
void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) {
|
||||
new ResolveProxyHelper(browser_context(), url, callback);
|
||||
void Session::ResolveProxy(
|
||||
const GURL& url,
|
||||
const ResolveProxyHelper::ResolveProxyCallback& callback) {
|
||||
browser_context_->GetResolveProxyHelper()->ResolveProxy(url, callback);
|
||||
}
|
||||
|
||||
template<Session::CacheAction action>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "atom/browser/atom_blob_reader.h"
|
||||
#include "atom/browser/net/resolve_proxy_helper.h"
|
||||
#include "base/values.h"
|
||||
#include "content/public/browser/download_manager.h"
|
||||
#include "native_mate/handle.h"
|
||||
@@ -39,8 +40,6 @@ namespace api {
|
||||
class Session: public mate::TrackableObject<Session>,
|
||||
public content::DownloadManager::Observer {
|
||||
public:
|
||||
using ResolveProxyCallback = base::Callback<void(std::string)>;
|
||||
|
||||
enum class CacheAction {
|
||||
CLEAR,
|
||||
STATS,
|
||||
@@ -62,7 +61,8 @@ class Session: public mate::TrackableObject<Session>,
|
||||
v8::Local<v8::FunctionTemplate> prototype);
|
||||
|
||||
// Methods.
|
||||
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
|
||||
void ResolveProxy(const GURL& url,
|
||||
const ResolveProxyHelper::ResolveProxyCallback& callback);
|
||||
template<CacheAction action>
|
||||
void DoCacheAction(const net::CompletionCallback& callback);
|
||||
void ClearStorageData(mate::Arguments* args);
|
||||
|
||||
@@ -206,7 +206,7 @@ void Tray::PopUpContextMenu(mate::Arguments* args) {
|
||||
|
||||
void Tray::SetContextMenu(v8::Isolate* isolate, mate::Handle<Menu> menu) {
|
||||
menu_.Reset(isolate, menu.ToV8());
|
||||
tray_icon_->SetContextMenu(menu->model());
|
||||
tray_icon_->SetContextMenu(menu.IsEmpty() ? nullptr : menu->model());
|
||||
}
|
||||
|
||||
gfx::Rect Tray::GetBounds() {
|
||||
|
||||
@@ -113,7 +113,7 @@ struct Converter<atom::SetSizeParams> {
|
||||
return false;
|
||||
bool autosize;
|
||||
if (params.Get("enableAutoSize", &autosize))
|
||||
out->enable_auto_size.reset(new bool(true));
|
||||
out->enable_auto_size.reset(new bool(autosize));
|
||||
gfx::Size size;
|
||||
if (params.Get("min", &size))
|
||||
out->min_size.reset(new gfx::Size(size));
|
||||
@@ -272,6 +272,9 @@ content::ServiceWorkerContext* GetServiceWorkerContext(
|
||||
void OnCapturePageDone(const base::Callback<void(const gfx::Image&)>& callback,
|
||||
const SkBitmap& bitmap,
|
||||
content::ReadbackResponse response) {
|
||||
// Hack to enable transparency in captured image
|
||||
// TODO(nitsakh) Remove hack once fixed in chromium
|
||||
const_cast<SkBitmap&>(bitmap).setAlphaType(kPremul_SkAlphaType);
|
||||
callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap));
|
||||
}
|
||||
|
||||
@@ -1954,9 +1957,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("startDrag", &WebContents::StartDrag)
|
||||
.SetMethod("setSize", &WebContents::SetSize)
|
||||
.SetMethod("isGuest", &WebContents::IsGuest)
|
||||
#if defined(ENABLE_OSR)
|
||||
.SetMethod("isOffscreen", &WebContents::IsOffScreen)
|
||||
#endif
|
||||
.SetMethod("startPainting", &WebContents::StartPainting)
|
||||
.SetMethod("stopPainting", &WebContents::StopPainting)
|
||||
.SetMethod("isPainting", &WebContents::IsPainting)
|
||||
|
||||
@@ -448,7 +448,6 @@ void AtomBrowserClient::SiteInstanceDeleting(
|
||||
|
||||
brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts(
|
||||
const content::MainFunctionParams&) {
|
||||
v8::V8::Initialize(); // Init V8 before creating main parts.
|
||||
return new AtomBrowserMainParts;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "atom/browser/net/atom_network_delegate.h"
|
||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||
#include "atom/browser/net/http_protocol_handler.h"
|
||||
#include "atom/browser/net/resolve_proxy_helper.h"
|
||||
#include "atom/browser/web_view_manager.h"
|
||||
#include "atom/common/atom_version.h"
|
||||
#include "atom/common/chrome_version.h"
|
||||
@@ -226,6 +227,14 @@ AtomBlobReader* AtomBrowserContext::GetBlobReader() {
|
||||
return blob_reader_.get();
|
||||
}
|
||||
|
||||
ResolveProxyHelper* AtomBrowserContext::GetResolveProxyHelper() {
|
||||
if (!resolve_proxy_helper_.get()) {
|
||||
resolve_proxy_helper_ =
|
||||
base::MakeRefCounted<ResolveProxyHelper>(url_request_context_getter());
|
||||
}
|
||||
return resolve_proxy_helper_.get();
|
||||
}
|
||||
|
||||
// static
|
||||
scoped_refptr<AtomBrowserContext> AtomBrowserContext::From(
|
||||
const std::string& partition, bool in_memory,
|
||||
|
||||
@@ -18,6 +18,7 @@ class AtomBlobReader;
|
||||
class AtomDownloadManagerDelegate;
|
||||
class AtomNetworkDelegate;
|
||||
class AtomPermissionManager;
|
||||
class ResolveProxyHelper;
|
||||
class WebViewManager;
|
||||
|
||||
class AtomBrowserContext : public brightray::BrowserContext {
|
||||
@@ -51,6 +52,8 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
||||
// brightray::BrowserContext:
|
||||
void RegisterPrefs(PrefRegistrySimple* pref_registry) override;
|
||||
|
||||
ResolveProxyHelper* GetResolveProxyHelper();
|
||||
|
||||
AtomBlobReader* GetBlobReader();
|
||||
AtomCookieDelegate* cookie_delegate() const {
|
||||
return cookie_delegate_.get();
|
||||
@@ -62,6 +65,7 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
||||
~AtomBrowserContext() override;
|
||||
|
||||
private:
|
||||
scoped_refptr<ResolveProxyHelper> resolve_proxy_helper_;
|
||||
std::unique_ptr<AtomDownloadManagerDelegate> download_manager_delegate_;
|
||||
std::unique_ptr<WebViewManager> guest_manager_;
|
||||
std::unique_ptr<AtomPermissionManager> permission_manager_;
|
||||
|
||||
@@ -151,6 +151,14 @@ void AtomBrowserMainParts::PostEarlyInitialization() {
|
||||
|
||||
// Wrap the uv loop with global env.
|
||||
node_bindings_->set_uv_env(env);
|
||||
|
||||
// We already initialized the feature list in
|
||||
// brightray::BrowserMainParts::PreEarlyInitialization(), but
|
||||
// the user JS script would not have had a chance to alter the command-line
|
||||
// switches at that point. Lets reinitialize it here to pick up the
|
||||
// command-line changes.
|
||||
base::FeatureList::ClearInstanceForTesting();
|
||||
brightray::BrowserMainParts::InitializeFeatureList();
|
||||
}
|
||||
|
||||
int AtomBrowserMainParts::PreCreateThreads() {
|
||||
|
||||
@@ -77,6 +77,11 @@ bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol,
|
||||
}
|
||||
}
|
||||
|
||||
// No other app was found set it to none instead of setting it back to itself.
|
||||
if ([identifier isEqualToString:(__bridge NSString*)other]) {
|
||||
other = base::mac::NSToCFCast(@"None");
|
||||
}
|
||||
|
||||
OSStatus return_code = LSSetDefaultHandlerForURLScheme(protocol_cf, other);
|
||||
return return_code == noErr;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "atom/browser/native_window.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -47,10 +48,35 @@
|
||||
#include "ui/gfx/font_render_params.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "ui/base/win/shell.h"
|
||||
#include "ui/display/win/screen_win.h"
|
||||
#endif
|
||||
|
||||
DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::NativeWindowRelay);
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(OS_WIN)
|
||||
gfx::Size GetExpandedWindowSize(const NativeWindow* window, gfx::Size size) {
|
||||
if (!window->transparent() || !ui::win::IsAeroGlassEnabled())
|
||||
return size;
|
||||
|
||||
gfx::Size min_size = display::win::ScreenWin::ScreenToDIPSize(
|
||||
window->GetAcceleratedWidget(), gfx::Size(64, 64));
|
||||
|
||||
// Some AMD drivers can't display windows that are less than 64x64 pixels,
|
||||
// so expand them to be at least that size. http://crbug.com/286609
|
||||
gfx::Size expanded(std::max(size.width(), min_size.width()),
|
||||
std::max(size.height(), min_size.height()));
|
||||
return expanded;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
NativeWindow::NativeWindow(
|
||||
brightray::InspectableWebContents* inspectable_web_contents,
|
||||
const mate::Dictionary& options,
|
||||
@@ -307,6 +333,21 @@ gfx::Size NativeWindow::GetMaximumSize() const {
|
||||
return GetSizeConstraints().GetMaximumSize();
|
||||
}
|
||||
|
||||
gfx::Size NativeWindow::GetContentMinimumSize() const {
|
||||
return GetContentSizeConstraints().GetMinimumSize();
|
||||
}
|
||||
|
||||
gfx::Size NativeWindow::GetContentMaximumSize() const {
|
||||
gfx::Size maximum_size = GetContentSizeConstraints().GetMaximumSize();
|
||||
#if defined(OS_WIN)
|
||||
return GetContentSizeConstraints().HasMaximumSize()
|
||||
? GetExpandedWindowSize(this, maximum_size)
|
||||
: maximum_size;
|
||||
#else
|
||||
return maximum_size;
|
||||
#endif
|
||||
}
|
||||
|
||||
void NativeWindow::SetSheetOffset(const double offsetX, const double offsetY) {
|
||||
sheet_offset_x_ = offsetX;
|
||||
sheet_offset_y_ = offsetY;
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace gfx {
|
||||
class Point;
|
||||
class Rect;
|
||||
class Size;
|
||||
}
|
||||
} // namespace gfx
|
||||
|
||||
namespace mate {
|
||||
class Dictionary;
|
||||
@@ -109,6 +109,8 @@ class NativeWindow : public base::SupportsUserData,
|
||||
virtual gfx::Size GetMinimumSize() const;
|
||||
virtual void SetMaximumSize(const gfx::Size& size);
|
||||
virtual gfx::Size GetMaximumSize() const;
|
||||
virtual gfx::Size GetContentMinimumSize() const;
|
||||
virtual gfx::Size GetContentMaximumSize() const;
|
||||
virtual void SetSheetOffset(const double offsetX, const double offsetY);
|
||||
virtual double GetSheetOffsetX();
|
||||
virtual double GetSheetOffsetY();
|
||||
@@ -160,15 +162,14 @@ class NativeWindow : public base::SupportsUserData,
|
||||
|
||||
// Taskbar/Dock APIs.
|
||||
enum ProgressState {
|
||||
PROGRESS_NONE, // no progress, no marking
|
||||
PROGRESS_INDETERMINATE, // progress, indeterminate
|
||||
PROGRESS_ERROR, // progress, errored (red)
|
||||
PROGRESS_PAUSED, // progress, paused (yellow)
|
||||
PROGRESS_NORMAL, // progress, not marked (green)
|
||||
PROGRESS_NONE, // no progress, no marking
|
||||
PROGRESS_INDETERMINATE, // progress, indeterminate
|
||||
PROGRESS_ERROR, // progress, errored (red)
|
||||
PROGRESS_PAUSED, // progress, paused (yellow)
|
||||
PROGRESS_NORMAL, // progress, not marked (green)
|
||||
};
|
||||
|
||||
virtual void SetProgressBar(double progress,
|
||||
const ProgressState state) = 0;
|
||||
virtual void SetProgressBar(double progress, const ProgressState state) = 0;
|
||||
virtual void SetOverlayIcon(const gfx::Image& overlay,
|
||||
const std::string& description) = 0;
|
||||
|
||||
@@ -230,12 +231,11 @@ class NativeWindow : public base::SupportsUserData,
|
||||
virtual void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {}
|
||||
virtual void ShowAutofillPopup(
|
||||
content::RenderFrameHost* frame_host,
|
||||
content::WebContents* web_contents,
|
||||
const gfx::RectF& bounds,
|
||||
const std::vector<base::string16>& values,
|
||||
const std::vector<base::string16>& labels) {}
|
||||
virtual void ShowAutofillPopup(content::RenderFrameHost* frame_host,
|
||||
content::WebContents* web_contents,
|
||||
const gfx::RectF& bounds,
|
||||
const std::vector<base::string16>& values,
|
||||
const std::vector<base::string16>& labels) {}
|
||||
virtual void HideAutofillPopup(content::RenderFrameHost* frame_host) {}
|
||||
|
||||
virtual void UpdateDraggableRegionViews() {}
|
||||
@@ -270,13 +270,11 @@ class NativeWindow : public base::SupportsUserData,
|
||||
const base::DictionaryValue& details);
|
||||
void NotifyNewWindowForTab();
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#if defined(OS_WIN)
|
||||
void NotifyWindowMessage(UINT message, WPARAM w_param, LPARAM l_param);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void AddObserver(NativeWindowObserver* obs) {
|
||||
observers_.AddObserver(obs);
|
||||
}
|
||||
void AddObserver(NativeWindowObserver* obs) { observers_.AddObserver(obs); }
|
||||
void RemoveObserver(NativeWindowObserver* obs) {
|
||||
observers_.RemoveObserver(obs);
|
||||
}
|
||||
@@ -390,11 +388,11 @@ class NativeWindow : public base::SupportsUserData,
|
||||
};
|
||||
|
||||
// This class provides a hook to get a NativeWindow from a WebContents.
|
||||
class NativeWindowRelay :
|
||||
public content::WebContentsUserData<NativeWindowRelay> {
|
||||
class NativeWindowRelay
|
||||
: public content::WebContentsUserData<NativeWindowRelay> {
|
||||
public:
|
||||
explicit NativeWindowRelay(base::WeakPtr<NativeWindow> window)
|
||||
: key(UserDataKey()), window(window) {}
|
||||
: key(UserDataKey()), window(window) {}
|
||||
|
||||
static void* UserDataKey() {
|
||||
return content::WebContentsUserData<NativeWindowRelay>::UserDataKey();
|
||||
|
||||
@@ -380,6 +380,7 @@ bool ScopedDisableResize::disable_resize_ = false;
|
||||
|
||||
// Set window style to hide the toolbar, otherwise the toolbar will show in
|
||||
// fullscreen mode.
|
||||
[window setTitlebarAppearsTransparent:NO];
|
||||
shell_->SetStyleMask(true, NSFullSizeContentViewWindowMask);
|
||||
}
|
||||
}
|
||||
@@ -397,6 +398,7 @@ bool ScopedDisableResize::disable_resize_ = false;
|
||||
// Turn off the style for toolbar.
|
||||
if (base::mac::IsAtLeastOS10_10() &&
|
||||
shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) {
|
||||
[window setTitlebarAppearsTransparent:YES];
|
||||
shell_->SetStyleMask(false, NSFullSizeContentViewWindowMask);
|
||||
}
|
||||
}
|
||||
@@ -728,10 +730,20 @@ enum {
|
||||
|
||||
// Custom window button methods
|
||||
|
||||
- (BOOL)windowShouldClose:(id)sender { return YES; }
|
||||
|
||||
- (void)performClose:(id)sender {
|
||||
if (shell_->title_bar_style() == atom::NativeWindowMac::CUSTOM_BUTTONS_ON_HOVER)
|
||||
if (shell_->title_bar_style() ==
|
||||
atom::NativeWindowMac::CUSTOM_BUTTONS_ON_HOVER) {
|
||||
[[self delegate] windowShouldClose:self];
|
||||
else
|
||||
} else if (shell_->IsSimpleFullScreen()) {
|
||||
if([[self delegate] respondsToSelector:@selector(windowShouldClose:)]) {
|
||||
if(![[self delegate] windowShouldClose:self]) return;
|
||||
} else if([self respondsToSelector:@selector(windowShouldClose:)]) {
|
||||
if(![self windowShouldClose:self]) return;
|
||||
}
|
||||
[self close];
|
||||
} else
|
||||
[super performClose:sender];
|
||||
}
|
||||
|
||||
|
||||
85
atom/browser/net/resolve_proxy_helper.cc
Normal file
85
atom/browser/net/resolve_proxy_helper.cc
Normal file
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2018 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/net/resolve_proxy_helper.h"
|
||||
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
ResolveProxyHelper::ResolveProxyHelper(net::URLRequestContextGetter* getter)
|
||||
: context_getter_(getter),
|
||||
original_thread_(base::ThreadTaskRunnerHandle::Get()) {}
|
||||
|
||||
ResolveProxyHelper::~ResolveProxyHelper() {
|
||||
// Clear all pending requests if the ProxyService is still alive.
|
||||
pending_requests_.clear();
|
||||
}
|
||||
|
||||
void ResolveProxyHelper::ResolveProxy(const GURL& url,
|
||||
const ResolveProxyCallback& callback) {
|
||||
// Enqueue the pending request.
|
||||
pending_requests_.push_back(PendingRequest(url, callback));
|
||||
|
||||
// If nothing is in progress, start.
|
||||
if (pending_requests_.size() == 1)
|
||||
StartPendingRequest();
|
||||
}
|
||||
|
||||
void ResolveProxyHelper::SendProxyResult(const std::string& proxy) {
|
||||
CHECK(!pending_requests_.empty());
|
||||
|
||||
const auto& completed_request = pending_requests_.front();
|
||||
if (!completed_request.callback.is_null())
|
||||
completed_request.callback.Run(proxy);
|
||||
|
||||
// Clear the current (completed) request.
|
||||
pending_requests_.pop_front();
|
||||
|
||||
// Start the next request.
|
||||
if (!pending_requests_.empty())
|
||||
StartPendingRequest();
|
||||
}
|
||||
|
||||
void ResolveProxyHelper::StartPendingRequest() {
|
||||
auto& request = pending_requests_.front();
|
||||
context_getter_->GetNetworkTaskRunner()->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&ResolveProxyHelper::StartPendingRequestInIO,
|
||||
base::Unretained(this), request.url, request.pac_req));
|
||||
}
|
||||
|
||||
void ResolveProxyHelper::OnResolveProxyCompleted(int result) {
|
||||
std::string proxy;
|
||||
if (result == net::OK)
|
||||
proxy = proxy_info_.ToPacString();
|
||||
|
||||
original_thread_->PostTask(
|
||||
FROM_HERE, base::BindOnce(&ResolveProxyHelper::SendProxyResult,
|
||||
base::Unretained(this), proxy));
|
||||
}
|
||||
|
||||
void ResolveProxyHelper::StartPendingRequestInIO(
|
||||
const GURL& url,
|
||||
net::ProxyService::PacRequest* pac_req) {
|
||||
// Verify the request wasn't started yet.
|
||||
DCHECK(nullptr == pac_req);
|
||||
|
||||
auto proxy_service = context_getter_->GetURLRequestContext()->proxy_service();
|
||||
|
||||
// Start the request.
|
||||
int result = proxy_service->ResolveProxy(
|
||||
url, std::string(), &proxy_info_,
|
||||
base::Bind(&ResolveProxyHelper::OnResolveProxyCompleted,
|
||||
base::Unretained(this)),
|
||||
&pac_req, nullptr, net::NetLogWithSource());
|
||||
|
||||
// Completed synchronously.
|
||||
if (result != net::ERR_IO_PENDING)
|
||||
OnResolveProxyCompleted(result);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
59
atom/browser/net/resolve_proxy_helper.h
Normal file
59
atom/browser/net/resolve_proxy_helper.h
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2018 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_NET_RESOLVE_PROXY_HELPER_H_
|
||||
#define ATOM_BROWSER_NET_RESOLVE_PROXY_HELPER_H_
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "net/proxy/proxy_service.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
namespace net {
|
||||
class URLRequestContextGetter;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class ResolveProxyHelper
|
||||
: public base::RefCountedThreadSafe<ResolveProxyHelper> {
|
||||
public:
|
||||
using ResolveProxyCallback = base::Callback<void(std::string)>;
|
||||
explicit ResolveProxyHelper(net::URLRequestContextGetter* getter);
|
||||
|
||||
void ResolveProxy(const GURL& url, const ResolveProxyCallback& callback);
|
||||
|
||||
private:
|
||||
friend class base::RefCountedThreadSafe<ResolveProxyHelper>;
|
||||
struct PendingRequest {
|
||||
public:
|
||||
PendingRequest(const GURL& url, const ResolveProxyCallback& callback)
|
||||
: url(url), callback(callback), pac_req(nullptr) {}
|
||||
|
||||
GURL url;
|
||||
ResolveProxyCallback callback;
|
||||
net::ProxyService::PacRequest* pac_req;
|
||||
};
|
||||
|
||||
~ResolveProxyHelper();
|
||||
|
||||
void StartPendingRequest();
|
||||
void StartPendingRequestInIO(const GURL& request,
|
||||
net::ProxyService::PacRequest* pac_req);
|
||||
void SendProxyResult(const std::string& proxy);
|
||||
void OnResolveProxyCompleted(int result);
|
||||
|
||||
net::ProxyInfo proxy_info_;
|
||||
std::deque<PendingRequest> pending_requests_;
|
||||
scoped_refptr<net::URLRequestContextGetter> context_getter_;
|
||||
scoped_refptr<base::SingleThreadTaskRunner> original_thread_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ResolveProxyHelper);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NET_RESOLVE_PROXY_HELPER_H_
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "atom/browser/node_debugger.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "libplatform/libplatform.h"
|
||||
@@ -28,10 +30,15 @@ void NodeDebugger::Start(node::NodePlatform* platform) {
|
||||
node::DebugOptions options;
|
||||
for (auto& arg : base::CommandLine::ForCurrentProcess()->argv()) {
|
||||
#if defined(OS_WIN)
|
||||
options.ParseOption("Electron", base::UTF16ToUTF8(arg));
|
||||
const std::string nice_arg = base::UTF16ToUTF8(arg);
|
||||
#else
|
||||
options.ParseOption("Electron", arg);
|
||||
const std::string& nice_arg = arg;
|
||||
#endif
|
||||
// Stop handling arguments after a "--" to be consistent with Chromium
|
||||
if (nice_arg == "--")
|
||||
break;
|
||||
|
||||
options.ParseOption("Electron", nice_arg);
|
||||
}
|
||||
|
||||
if (options.inspector_enabled()) {
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>electron.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2.0.0</string>
|
||||
<string>2.0.11</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.0.0</string>
|
||||
<string>2.0.11</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.developer-tools</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
@@ -56,8 +56,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,0,0,5
|
||||
PRODUCTVERSION 2,0,0,5
|
||||
FILEVERSION 2,0,11,0
|
||||
PRODUCTVERSION 2,0,11,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -74,12 +74,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "2.0.0"
|
||||
VALUE "FileVersion", "2.0.11"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "2.0.0"
|
||||
VALUE "ProductVersion", "2.0.11"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
||||
@@ -91,7 +91,9 @@ bool TriggerAcceleratorTableCommand(AcceleratorTable* table,
|
||||
if (base::ContainsKey(*table, accelerator)) {
|
||||
const accelerator_util::MenuItem& item = (*table)[accelerator];
|
||||
if (item.model->IsEnabledAt(item.position)) {
|
||||
item.model->ActivatedAt(item.position);
|
||||
const auto event_flags =
|
||||
accelerator.MaskOutKeyEventFlags(accelerator.modifiers());
|
||||
item.model->ActivatedAt(item.position, event_flags);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,9 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
|
||||
[menu_ cancelTracking];
|
||||
isMenuOpen_ = NO;
|
||||
model_->MenuWillClose();
|
||||
closeCallback.Run();
|
||||
if (!closeCallback.is_null()) {
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, closeCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,72 +15,99 @@
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
|
||||
@interface PopUpButtonHandler : NSObject
|
||||
@property (nonatomic, strong) NSSavePanel *savePanel;
|
||||
@property (nonatomic, strong) NSArray *fileTypes;
|
||||
- (instancetype)initWithPanel:(NSSavePanel *)panel andTypes:(NSArray *)types;
|
||||
|
||||
@property(nonatomic, assign) NSSavePanel* savePanel;
|
||||
@property(nonatomic, strong) NSArray* fileTypesList;
|
||||
|
||||
- (instancetype)initWithPanel:(NSSavePanel*)panel
|
||||
andTypesList:(NSArray*)typesList;
|
||||
- (void)selectFormat:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
@implementation PopUpButtonHandler
|
||||
- (instancetype)initWithPanel:(NSSavePanel *)panel andTypes:(NSArray *)types {
|
||||
|
||||
- (instancetype)initWithPanel:(NSSavePanel*)panel
|
||||
andTypesList:(NSArray*)typesList {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_savePanel = panel;
|
||||
_fileTypes = types;
|
||||
[self setSavePanel:panel];
|
||||
[self setFileTypesList:typesList];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)selectFormat:(id)sender {
|
||||
NSPopUpButton *button = (NSPopUpButton *)sender;
|
||||
NSPopUpButton* button = (NSPopUpButton*)sender;
|
||||
NSInteger selectedItemIndex = [button indexOfSelectedItem];
|
||||
NSString *nameFieldString = [[self savePanel] nameFieldStringValue];
|
||||
NSString *trimmedNameFieldString = [nameFieldString stringByDeletingPathExtension];
|
||||
NSString *extension = [[self fileTypes] objectAtIndex: selectedItemIndex];
|
||||
NSArray* list = [self fileTypesList];
|
||||
NSArray* fileTypes = [list objectAtIndex:selectedItemIndex];
|
||||
|
||||
NSString *nameFieldStringWithExt = [NSString stringWithFormat:@"%@.%@", trimmedNameFieldString, extension];
|
||||
[[self savePanel] setNameFieldStringValue:nameFieldStringWithExt];
|
||||
[[self savePanel] setAllowedFileTypes:@[extension]];
|
||||
// If we meet a '*' file extension, we allow all the file types and no
|
||||
// need to set the specified file types.
|
||||
if ([fileTypes count] == 0 || [fileTypes containsObject:@"*"])
|
||||
[[self savePanel] setAllowedFileTypes:nil];
|
||||
else
|
||||
[[self savePanel] setAllowedFileTypes:fileTypes];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// Manages the PopUpButtonHandler.
|
||||
@interface AtomAccessoryView : NSView
|
||||
@end
|
||||
|
||||
@implementation AtomAccessoryView
|
||||
|
||||
- (void)dealloc {
|
||||
auto* popupButton = static_cast<NSPopUpButton*>([[self subviews] objectAtIndex: 1]);
|
||||
[[popupButton target] release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
namespace file_dialog {
|
||||
|
||||
namespace {
|
||||
|
||||
static PopUpButtonHandler *popUpButtonHandler;
|
||||
|
||||
void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) {
|
||||
NSMutableSet* file_type_set = [NSMutableSet set];
|
||||
for (size_t i = 0; i < filters.size(); ++i) {
|
||||
const Filter& filter = filters[i];
|
||||
for (size_t j = 0; j < filter.second.size(); ++j) {
|
||||
// If we meet a '*' file extension, we allow all the file types and no
|
||||
// need to set the specified file types.
|
||||
NSMutableArray* file_types_list = [NSMutableArray array];
|
||||
NSMutableArray* filter_names = [NSMutableArray array];
|
||||
|
||||
if (filter.second[j] == "*") {
|
||||
[dialog setAllowsOtherFileTypes:YES];
|
||||
return;
|
||||
}
|
||||
base::ScopedCFTypeRef<CFStringRef> ext_cf(
|
||||
base::SysUTF8ToCFStringRef(filter.second[j]));
|
||||
// Create array to keep file types and their name.
|
||||
for (const Filter& filter : filters) {
|
||||
NSMutableSet* file_type_set = [NSMutableSet set];
|
||||
base::ScopedCFTypeRef<CFStringRef> name_cf(
|
||||
base::SysUTF8ToCFStringRef(filter.first));
|
||||
[filter_names addObject:base::mac::CFToNSCast(name_cf.get())];
|
||||
for (const std::string& ext : filter.second) {
|
||||
base::ScopedCFTypeRef<CFStringRef> ext_cf(base::SysUTF8ToCFStringRef(ext));
|
||||
[file_type_set addObject:base::mac::CFToNSCast(ext_cf.get())];
|
||||
}
|
||||
[file_types_list addObject:[file_type_set allObjects]];
|
||||
}
|
||||
|
||||
// Passing empty array to setAllowedFileTypes will cause exception.
|
||||
NSArray* file_types = nil;
|
||||
if ([file_type_set count])
|
||||
file_types = [file_type_set allObjects];
|
||||
|
||||
NSUInteger count = [file_types_list count];
|
||||
if (count > 0) {
|
||||
file_types = [[file_types_list objectAtIndex:0] allObjects];
|
||||
// If we meet a '*' file extension, we allow all the file types and no
|
||||
// need to set the specified file types.
|
||||
if ([file_types count] == 0 || [file_types containsObject:@"*"])
|
||||
file_types = nil;
|
||||
}
|
||||
[dialog setAllowedFileTypes:file_types];
|
||||
|
||||
if (!popUpButtonHandler)
|
||||
popUpButtonHandler = [[PopUpButtonHandler alloc] initWithPanel:dialog andTypes:file_types];
|
||||
if (count <= 1)
|
||||
return; // don't add file format picker
|
||||
|
||||
// add file format picker
|
||||
NSView *accessoryView = [[NSView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 200, 32.0)];
|
||||
NSTextField *label = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 60, 22)];
|
||||
// Add file format picker.
|
||||
AtomAccessoryView* accessoryView =
|
||||
[[AtomAccessoryView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 200, 32.0)];
|
||||
NSTextField* label =
|
||||
[[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 60, 22)];
|
||||
|
||||
[label setEditable:NO];
|
||||
[label setStringValue:@"Format:"];
|
||||
@@ -88,15 +115,18 @@ void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) {
|
||||
[label setBezeled:NO];
|
||||
[label setDrawsBackground:NO];
|
||||
|
||||
NSPopUpButton *popupButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(50.0, 2, 140, 22.0) pullsDown:NO];
|
||||
[popupButton addItemsWithTitles:file_types];
|
||||
NSPopUpButton* popupButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(50.0, 2, 140, 22.0)
|
||||
pullsDown:NO];
|
||||
PopUpButtonHandler* popUpButtonHandler = [[PopUpButtonHandler alloc] initWithPanel:dialog
|
||||
andTypesList:file_types_list];
|
||||
[popupButton addItemsWithTitles:filter_names];
|
||||
[popupButton setTarget:popUpButtonHandler];
|
||||
[popupButton setAction:@selector(selectFormat:)];
|
||||
|
||||
[accessoryView addSubview:label];
|
||||
[accessoryView addSubview:popupButton];
|
||||
[accessoryView addSubview:[label autorelease]];
|
||||
[accessoryView addSubview:[popupButton autorelease]];
|
||||
|
||||
[dialog setAccessoryView:accessoryView];
|
||||
[dialog setAccessoryView:[accessoryView autorelease]];
|
||||
}
|
||||
|
||||
void SetupDialog(NSSavePanel* dialog,
|
||||
@@ -118,6 +148,7 @@ void SetupDialog(NSSavePanel* dialog,
|
||||
NSString* default_dir = nil;
|
||||
NSString* default_filename = nil;
|
||||
if (!settings.default_path.empty()) {
|
||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
if (base::DirectoryExists(settings.default_path)) {
|
||||
default_dir = base::SysUTF8ToNSString(settings.default_path.value());
|
||||
} else {
|
||||
@@ -283,8 +314,9 @@ void ShowOpenDialog(const DialogSettings& settings,
|
||||
|
||||
if (!settings.parent_window || !settings.parent_window->GetNativeWindow() ||
|
||||
settings.force_detached) {
|
||||
int chosen = [dialog runModal];
|
||||
OpenDialogCompletion(chosen, dialog, settings, callback);
|
||||
[dialog beginWithCompletionHandler:^(NSInteger chosen) {
|
||||
OpenDialogCompletion(chosen, dialog, settings, callback);
|
||||
}];
|
||||
} else {
|
||||
NSWindow* window = settings.parent_window->GetNativeWindow();
|
||||
[dialog beginSheetModalForWindow:window
|
||||
@@ -343,8 +375,9 @@ void ShowSaveDialog(const DialogSettings& settings,
|
||||
|
||||
if (!settings.parent_window || !settings.parent_window->GetNativeWindow() ||
|
||||
settings.force_detached) {
|
||||
int chosen = [dialog runModal];
|
||||
SaveDialogCompletion(chosen, dialog, settings, callback);
|
||||
[dialog beginWithCompletionHandler:^(NSInteger chosen) {
|
||||
SaveDialogCompletion(chosen, dialog, settings, callback);
|
||||
}];
|
||||
} else {
|
||||
NSWindow* window = settings.parent_window->GetNativeWindow();
|
||||
[dialog beginSheetModalForWindow:window
|
||||
|
||||
@@ -96,11 +96,6 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
|
||||
NSArray* ns_buttons = [alert buttons];
|
||||
int button_count = static_cast<int>([ns_buttons count]);
|
||||
|
||||
// Bind cancel id button to escape key if there is more than one button
|
||||
if (button_count > 1 && cancel_id >= 0 && cancel_id < button_count) {
|
||||
[[ns_buttons objectAtIndex:cancel_id] setKeyEquivalent:@"\e"];
|
||||
}
|
||||
|
||||
if (default_id >= 0 && default_id < button_count) {
|
||||
// Focus the button at default_id if the user opted to do so.
|
||||
// The first button added gets set as the default selected.
|
||||
@@ -109,6 +104,11 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
|
||||
[[ns_buttons objectAtIndex:default_id] setKeyEquivalent:@"\r"];
|
||||
}
|
||||
|
||||
// Bind cancel id button to escape key if there is more than one button
|
||||
if (button_count > 1 && cancel_id >= 0 && cancel_id < button_count) {
|
||||
[[ns_buttons objectAtIndex:cancel_id] setKeyEquivalent:@"\e"];
|
||||
}
|
||||
|
||||
if (!checkbox_label.empty()) {
|
||||
alert.showsSuppressionButton = YES;
|
||||
alert.suppressionButton.title = base::SysUTF8ToNSString(checkbox_label);
|
||||
|
||||
@@ -40,9 +40,16 @@ const CGFloat kVerticalTitleMargin = 2;
|
||||
|
||||
@implementation StatusItemView
|
||||
|
||||
- (void)dealloc {
|
||||
trayIcon_ = nil;
|
||||
menuController_ = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)initWithImage:(NSImage*)image icon:(atom::TrayIconCocoa*)icon {
|
||||
image_.reset([image copy]);
|
||||
trayIcon_ = icon;
|
||||
menuController_ = nil;
|
||||
highlight_mode_ = atom::TrayIcon::HighlightMode::SELECTION;
|
||||
forceHighlight_ = NO;
|
||||
inMouseEventSequence_ = NO;
|
||||
@@ -85,6 +92,7 @@ const CGFloat kVerticalTitleMargin = 2;
|
||||
trackingArea_.reset();
|
||||
}
|
||||
[[NSStatusBar systemStatusBar] removeStatusItem:statusItem_];
|
||||
[statusItem_ setView:nil];
|
||||
statusItem_.reset();
|
||||
}
|
||||
|
||||
@@ -98,7 +106,7 @@ const CGFloat kVerticalTitleMargin = 2;
|
||||
|
||||
// Draw the system bar background.
|
||||
[statusItem_ drawStatusBarBackgroundInRect:self.bounds
|
||||
withHighlight:[self isHighlighted]];
|
||||
withHighlight:[self shouldHighlight]];
|
||||
|
||||
// Determine which image to use.
|
||||
NSImage* image = image_.get();
|
||||
@@ -230,8 +238,13 @@ const CGFloat kVerticalTitleMargin = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
// check title_ being nil
|
||||
NSString *title = @"";
|
||||
if (title_)
|
||||
title = title_;
|
||||
|
||||
attributedTitle_.reset([[NSMutableAttributedString alloc]
|
||||
initWithString:title_
|
||||
initWithString:title
|
||||
attributes:attributes]);
|
||||
|
||||
//NSFontAttributeName:[NSFont menuBarFontOfSize:0],
|
||||
@@ -384,6 +397,11 @@ const CGFloat kVerticalTitleMargin = 2;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)setNeedsDisplay:(BOOL)display {
|
||||
[self updateAttributedTitle];
|
||||
[super setNeedsDisplay:display];
|
||||
}
|
||||
|
||||
- (BOOL)shouldHighlight {
|
||||
switch (highlight_mode_) {
|
||||
case atom::TrayIcon::HighlightMode::ALWAYS:
|
||||
@@ -444,11 +462,18 @@ void TrayIconCocoa::SetContextMenu(AtomMenuModel* menu_model) {
|
||||
// Substribe to MenuClosed event.
|
||||
if (menu_model_)
|
||||
menu_model_->RemoveObserver(this);
|
||||
menu_model->AddObserver(this);
|
||||
|
||||
// Create native menu.
|
||||
menu_.reset([[AtomMenuController alloc] initWithModel:menu_model
|
||||
useDefaultAccelerator:NO]);
|
||||
menu_model_ = menu_model;
|
||||
|
||||
if (menu_model) {
|
||||
menu_model->AddObserver(this);
|
||||
// Create native menu.
|
||||
menu_.reset([[AtomMenuController alloc] initWithModel:menu_model
|
||||
useDefaultAccelerator:NO]);
|
||||
} else {
|
||||
menu_.reset();
|
||||
}
|
||||
|
||||
[status_item_view_ setMenuController:menu_.get()];
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "atom/browser/browser.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "brightray/common/application_info.h"
|
||||
#include "chrome/browser/ui/libgtkui/app_indicator_icon.h"
|
||||
#include "chrome/browser/ui/libgtkui/gtk_status_icon.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
@@ -32,16 +33,17 @@ void TrayIconGtk::SetImage(const gfx::Image& image) {
|
||||
return;
|
||||
}
|
||||
|
||||
base::string16 empty;
|
||||
const auto toolTip = base::UTF8ToUTF16(brightray::GetApplicationName());
|
||||
|
||||
if (libgtkui::AppIndicatorIcon::CouldOpen()) {
|
||||
++indicators_count;
|
||||
icon_.reset(new libgtkui::AppIndicatorIcon(
|
||||
base::StringPrintf(
|
||||
"%s%d", Browser::Get()->GetName().c_str(), indicators_count),
|
||||
image.AsImageSkia(),
|
||||
empty));
|
||||
toolTip));
|
||||
} else {
|
||||
icon_.reset(new libgtkui::Gtk2StatusIcon(image.AsImageSkia(), empty));
|
||||
icon_.reset(new libgtkui::Gtk2StatusIcon(image.AsImageSkia(), toolTip));
|
||||
}
|
||||
icon_->set_delegate(this);
|
||||
}
|
||||
|
||||
@@ -104,11 +104,11 @@ gfx::Size FramelessView::CalculatePreferredSize() const {
|
||||
}
|
||||
|
||||
gfx::Size FramelessView::GetMinimumSize() const {
|
||||
return window_->GetContentSizeConstraints().GetMinimumSize();
|
||||
return window_->GetContentMinimumSize();
|
||||
}
|
||||
|
||||
gfx::Size FramelessView::GetMaximumSize() const {
|
||||
return window_->GetContentSizeConstraints().GetMaximumSize();
|
||||
return window_->GetContentMaximumSize();
|
||||
}
|
||||
|
||||
const char* FramelessView::GetClassName() const {
|
||||
|
||||
@@ -209,7 +209,9 @@ void GlobalMenuBarX11::SetMenu(AtomMenuModel* menu_model) {
|
||||
DbusmenuMenuitem* root_item = menuitem_new();
|
||||
menuitem_property_set(root_item, kPropertyLabel, "Root");
|
||||
menuitem_property_set_bool(root_item, kPropertyVisible, true);
|
||||
BuildMenuFromModel(menu_model, root_item);
|
||||
if (menu_model != nullptr) {
|
||||
BuildMenuFromModel(menu_model, root_item);
|
||||
}
|
||||
|
||||
server_set_root(server_, root_item);
|
||||
g_object_unref(root_item);
|
||||
|
||||
@@ -4,12 +4,19 @@
|
||||
|
||||
#include "atom/browser/ui/views/menu_bar.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/ui/views/menu_delegate.h"
|
||||
#include "atom/browser/ui/views/submenu_button.h"
|
||||
#include "ui/base/models/menu_model.h"
|
||||
#include "ui/views/background.h"
|
||||
#include "ui/views/layout/box_layout.h"
|
||||
|
||||
#if defined(USE_X11)
|
||||
#include "chrome/browser/ui/libgtkui/gtk_util.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "ui/gfx/color_utils.h"
|
||||
#endif
|
||||
@@ -130,13 +137,17 @@ void MenuBar::RefreshColorCache(const ui::NativeTheme* theme) {
|
||||
if (!theme)
|
||||
theme = ui::NativeTheme::GetInstanceForNativeUi();
|
||||
if (theme) {
|
||||
background_color_ =
|
||||
theme->GetSystemColor(ui::NativeTheme::kColorId_MenuBackgroundColor);
|
||||
#if defined(USE_X11)
|
||||
const std::string menubar_selector = "GtkMenuBar#menubar";
|
||||
background_color_ = libgtkui::GetBgColor(menubar_selector);
|
||||
|
||||
enabled_color_ = theme->GetSystemColor(
|
||||
ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor);
|
||||
disabled_color_ = theme->GetSystemColor(
|
||||
ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor);
|
||||
#else
|
||||
background_color_ =
|
||||
theme->GetSystemColor(ui::NativeTheme::kColorId_MenuBackgroundColor);
|
||||
#endif
|
||||
}
|
||||
#if defined(OS_WIN)
|
||||
|
||||
@@ -25,4 +25,11 @@ bool AtomDesktopWindowTreeHostWin::PreHandleMSG(
|
||||
return delegate_->PreHandleMSG(message, w_param, l_param, result);
|
||||
}
|
||||
|
||||
bool AtomDesktopWindowTreeHostWin::HasNativeFrame() const {
|
||||
// Since we never use chromium's titlebar implementation, we can just say
|
||||
// that we use a native titlebar. This will disable the repaint locking when
|
||||
// DWM composition is disabled.
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -27,6 +27,7 @@ class AtomDesktopWindowTreeHostWin : public views::DesktopWindowTreeHostWin {
|
||||
protected:
|
||||
bool PreHandleMSG(
|
||||
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override;
|
||||
bool HasNativeFrame() const override;
|
||||
|
||||
private:
|
||||
MessageHandlerDelegate* delegate_; // weak ref
|
||||
|
||||
@@ -63,8 +63,15 @@ WebContentsPreferences::WebContentsPreferences(
|
||||
SetDefaultBoolIfUndefined("images", true);
|
||||
SetDefaultBoolIfUndefined("textAreasAreResizable", true);
|
||||
SetDefaultBoolIfUndefined("webgl", true);
|
||||
SetDefaultBoolIfUndefined("webSecurity", true);
|
||||
SetDefaultBoolIfUndefined("allowRunningInsecureContent", false);
|
||||
bool webSecurity = true;
|
||||
SetDefaultBoolIfUndefined("webSecurity", webSecurity);
|
||||
// If webSecurity was explicity set to false, let's inherit that into
|
||||
// insecureContent
|
||||
if (web_preferences.Get("webSecurity", &webSecurity) && !webSecurity) {
|
||||
SetDefaultBoolIfUndefined("allowRunningInsecureContent", true);
|
||||
} else {
|
||||
SetDefaultBoolIfUndefined("allowRunningInsecureContent", false);
|
||||
}
|
||||
#if defined(OS_MACOSX)
|
||||
SetDefaultBoolIfUndefined(options::kScrollBounce, false);
|
||||
#endif
|
||||
|
||||
@@ -168,10 +168,10 @@ file_dialog::Filters GetFileTypesFromAcceptType(
|
||||
|
||||
filters.push_back(file_dialog::Filter());
|
||||
|
||||
if (valid_type_count > 1 ||
|
||||
(valid_type_count == 1 && description.empty() && extensions.size() > 1))
|
||||
if (valid_type_count > 1 || (valid_type_count == 1 && description.empty()))
|
||||
description = "Custom Files";
|
||||
|
||||
DCHECK(!description.empty());
|
||||
filters[0].first = description;
|
||||
|
||||
for (const auto& extension : extensions) {
|
||||
@@ -227,6 +227,7 @@ void WebDialogHelper::RunFileChooser(
|
||||
flags |= file_dialog::FILE_DIALOG_MULTI_SELECTIONS;
|
||||
case content::FileChooserParams::Open:
|
||||
flags |= file_dialog::FILE_DIALOG_OPEN_FILE;
|
||||
flags |= file_dialog::FILE_DIALOG_TREAT_PACKAGE_APP_AS_DIRECTORY;
|
||||
break;
|
||||
case content::FileChooserParams::UploadFolder:
|
||||
flags |= file_dialog::FILE_DIALOG_OPEN_DIRECTORY;
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace std {
|
||||
template <typename Type1, typename Type2>
|
||||
struct hash<std::pair<Type1, Type2>> {
|
||||
std::size_t operator()(std::pair<Type1, Type2> value) const {
|
||||
return base::HashInts<Type1, Type2>(value.first, value.second);
|
||||
return base::HashInts(base::Hash(value.first), value.second);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -114,8 +114,9 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||
dict.SetMethod("setRemoteCallbackFreer", &atom::RemoteCallbackFreer::BindTo);
|
||||
dict.SetMethod("setRemoteObjectFreer", &atom::RemoteObjectFreer::BindTo);
|
||||
dict.SetMethod("createIDWeakMap", &atom::api::KeyWeakMap<int32_t>::Create);
|
||||
dict.SetMethod("createDoubleIDWeakMap",
|
||||
&atom::api::KeyWeakMap<std::pair<int64_t, int32_t>>::Create);
|
||||
dict.SetMethod(
|
||||
"createDoubleIDWeakMap",
|
||||
&atom::api::KeyWeakMap<std::pair<std::string, int32_t>>::Create);
|
||||
dict.SetMethod("requestGarbageCollectionForTesting",
|
||||
&RequestGarbageCollectionForTesting);
|
||||
dict.SetMethod("isSameOrigin", &IsSameOrigin);
|
||||
|
||||
@@ -15,17 +15,20 @@ namespace atom {
|
||||
// static
|
||||
void RemoteCallbackFreer::BindTo(v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> target,
|
||||
const std::string& context_id,
|
||||
int object_id,
|
||||
content::WebContents* web_contents) {
|
||||
new RemoteCallbackFreer(isolate, target, object_id, web_contents);
|
||||
new RemoteCallbackFreer(isolate, target, context_id, object_id, web_contents);
|
||||
}
|
||||
|
||||
RemoteCallbackFreer::RemoteCallbackFreer(v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> target,
|
||||
const std::string& context_id,
|
||||
int object_id,
|
||||
content::WebContents* web_contents)
|
||||
: ObjectLifeMonitor(isolate, target),
|
||||
content::WebContentsObserver(web_contents),
|
||||
context_id_(context_id),
|
||||
object_id_(object_id) {
|
||||
}
|
||||
|
||||
@@ -36,6 +39,7 @@ void RemoteCallbackFreer::RunDestructor() {
|
||||
base::string16 channel =
|
||||
base::ASCIIToUTF16("ELECTRON_RENDERER_RELEASE_CALLBACK");
|
||||
base::ListValue args;
|
||||
args.AppendString(context_id_);
|
||||
args.AppendInteger(object_id_);
|
||||
auto frame_host = web_contents()->GetMainFrame();
|
||||
if (frame_host) {
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
#ifndef ATOM_COMMON_API_REMOTE_CALLBACK_FREER_H_
|
||||
#define ATOM_COMMON_API_REMOTE_CALLBACK_FREER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/api/object_life_monitor.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
|
||||
@@ -14,12 +17,14 @@ class RemoteCallbackFreer : public ObjectLifeMonitor,
|
||||
public:
|
||||
static void BindTo(v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> target,
|
||||
const std::string& context_id,
|
||||
int object_id,
|
||||
content::WebContents* web_conents);
|
||||
|
||||
protected:
|
||||
RemoteCallbackFreer(v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> target,
|
||||
const std::string& context_id,
|
||||
int object_id,
|
||||
content::WebContents* web_conents);
|
||||
~RemoteCallbackFreer() override;
|
||||
@@ -30,6 +35,7 @@ class RemoteCallbackFreer : public ObjectLifeMonitor,
|
||||
void RenderViewDeleted(content::RenderViewHost*) override;
|
||||
|
||||
private:
|
||||
std::string context_id_;
|
||||
int object_id_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RemoteCallbackFreer);
|
||||
|
||||
@@ -27,14 +27,19 @@ content::RenderFrame* GetCurrentRenderFrame() {
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
void RemoteObjectFreer::BindTo(
|
||||
v8::Isolate* isolate, v8::Local<v8::Object> target, int object_id) {
|
||||
new RemoteObjectFreer(isolate, target, object_id);
|
||||
void RemoteObjectFreer::BindTo(v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> target,
|
||||
const std::string& context_id,
|
||||
int object_id) {
|
||||
new RemoteObjectFreer(isolate, target, context_id, object_id);
|
||||
}
|
||||
|
||||
RemoteObjectFreer::RemoteObjectFreer(
|
||||
v8::Isolate* isolate, v8::Local<v8::Object> target, int object_id)
|
||||
RemoteObjectFreer::RemoteObjectFreer(v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> target,
|
||||
const std::string& context_id,
|
||||
int object_id)
|
||||
: ObjectLifeMonitor(isolate, target),
|
||||
context_id_(context_id),
|
||||
object_id_(object_id),
|
||||
routing_id_(MSG_ROUTING_NONE) {
|
||||
content::RenderFrame* render_frame = GetCurrentRenderFrame();
|
||||
@@ -55,6 +60,7 @@ void RemoteObjectFreer::RunDestructor() {
|
||||
base::string16 channel = base::ASCIIToUTF16("ipc-message");
|
||||
base::ListValue args;
|
||||
args.AppendString("ELECTRON_BROWSER_DEREFERENCE");
|
||||
args.AppendString(context_id_);
|
||||
args.AppendInteger(object_id_);
|
||||
render_frame->Send(new AtomFrameHostMsg_Message(render_frame->GetRoutingID(),
|
||||
channel, args));
|
||||
|
||||
@@ -5,23 +5,30 @@
|
||||
#ifndef ATOM_COMMON_API_REMOTE_OBJECT_FREER_H_
|
||||
#define ATOM_COMMON_API_REMOTE_OBJECT_FREER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/api/object_life_monitor.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class RemoteObjectFreer : public ObjectLifeMonitor {
|
||||
public:
|
||||
static void BindTo(
|
||||
v8::Isolate* isolate, v8::Local<v8::Object> target, int object_id);
|
||||
static void BindTo(v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> target,
|
||||
const std::string& context_id,
|
||||
int object_id);
|
||||
|
||||
protected:
|
||||
RemoteObjectFreer(
|
||||
v8::Isolate* isolate, v8::Local<v8::Object> target, int object_id);
|
||||
RemoteObjectFreer(v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> target,
|
||||
const std::string& context_id,
|
||||
int object_id);
|
||||
~RemoteObjectFreer() override;
|
||||
|
||||
void RunDestructor() override;
|
||||
|
||||
private:
|
||||
std::string context_id_;
|
||||
int object_id_;
|
||||
int routing_id_;
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
#define ATOM_MAJOR_VERSION 2
|
||||
#define ATOM_MINOR_VERSION 0
|
||||
#define ATOM_PATCH_VERSION 0
|
||||
#define ATOM_PRE_RELEASE_VERSION -beta.5
|
||||
#define ATOM_PATCH_VERSION 11
|
||||
// #define ATOM_PRE_RELEASE_VERSION
|
||||
|
||||
#ifndef ATOM_STRINGIFY
|
||||
#define ATOM_STRINGIFY(n) ATOM_STRINGIFY_HELPER(n)
|
||||
|
||||
@@ -168,6 +168,7 @@ void NodeBindings::Initialize() {
|
||||
|
||||
// Init node.
|
||||
// (we assume node::Init would not modify the parameters under embedded mode).
|
||||
// NOTE: If you change this line, please ping @codebytere or @MarshallOfSound
|
||||
node::Init(nullptr, nullptr, nullptr, nullptr);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
@@ -152,6 +152,7 @@ double WebFrame::GetZoomFactor() const {
|
||||
|
||||
void WebFrame::SetVisualZoomLevelLimits(double min_level, double max_level) {
|
||||
web_frame_->View()->SetDefaultPageScaleLimits(min_level, max_level);
|
||||
web_frame_->View()->SetIgnoreViewportTagScaleLimits(true);
|
||||
}
|
||||
|
||||
void WebFrame::SetLayoutZoomLevelLimits(double min_level, double max_level) {
|
||||
|
||||
@@ -82,6 +82,8 @@ void AtomRendererClient::RunScriptsAtDocumentEnd(
|
||||
|
||||
void AtomRendererClient::DidCreateScriptContext(
|
||||
v8::Handle<v8::Context> context, content::RenderFrame* render_frame) {
|
||||
RendererClientBase::DidCreateScriptContext(context, render_frame);
|
||||
|
||||
// Only allow node integration for the main frame, unless it is a devtools
|
||||
// extension page.
|
||||
if (!render_frame->IsMainFrame() && !IsDevToolsExtension(render_frame))
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
#include "atom/renderer/api/atom_api_renderer_ipc.h"
|
||||
#include "atom/renderer/atom_render_frame_observer.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "chrome/renderer/printing/print_web_view_helper.h"
|
||||
#include "content/public/renderer/render_frame.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "third_party/WebKit/public/web/WebDocument.h"
|
||||
#include "third_party/WebKit/public/web/WebKit.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
@@ -30,6 +32,11 @@ namespace {
|
||||
const std::string kIpcKey = "ipcNative";
|
||||
const std::string kModuleCacheKey = "native-module-cache";
|
||||
|
||||
bool IsDevTools(content::RenderFrame* render_frame) {
|
||||
return render_frame->GetWebFrame()->GetDocument().Url()
|
||||
.ProtocolIs("chrome-devtools");
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> GetModuleCache(v8::Isolate* isolate) {
|
||||
mate::Dictionary global(isolate, isolate->GetCurrentContext()->Global());
|
||||
v8::Local<v8::Value> cache;
|
||||
@@ -146,16 +153,16 @@ void AtomSandboxedRendererClient::RenderViewCreated(
|
||||
|
||||
void AtomSandboxedRendererClient::DidCreateScriptContext(
|
||||
v8::Handle<v8::Context> context, content::RenderFrame* render_frame) {
|
||||
RendererClientBase::DidCreateScriptContext(context, render_frame);
|
||||
|
||||
// Only allow preload for the main frame
|
||||
if (!render_frame->IsMainFrame())
|
||||
// Only allow preload for the main frame or
|
||||
// For devtools we still want to run the preload_bundle script
|
||||
if (!render_frame->IsMainFrame() && !IsDevTools(render_frame))
|
||||
return;
|
||||
|
||||
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
|
||||
std::string preload_script = command_line->GetSwitchValueASCII(
|
||||
base::FilePath preload_script_path = command_line->GetSwitchValuePath(
|
||||
switches::kPreloadScript);
|
||||
if (preload_script.empty())
|
||||
return;
|
||||
|
||||
auto isolate = context->GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
@@ -180,7 +187,7 @@ void AtomSandboxedRendererClient::DidCreateScriptContext(
|
||||
AddRenderBindings(isolate, binding);
|
||||
v8::Local<v8::Value> args[] = {
|
||||
binding,
|
||||
mate::ConvertToV8(isolate, preload_script)
|
||||
mate::ConvertToV8(isolate, preload_script_path.value())
|
||||
};
|
||||
// Execute the function with proper arguments
|
||||
ignore_result(func->Call(context, v8::Null(isolate), 2, args));
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
#include "atom/renderer/preferences_manager.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/process/process_handle.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "chrome/renderer/media/chrome_key_systems.h"
|
||||
#include "chrome/renderer/pepper/pepper_helper.h"
|
||||
#include "chrome/renderer/printing/print_web_view_helper.h"
|
||||
@@ -44,6 +46,14 @@
|
||||
#include <shlobj.h>
|
||||
#endif
|
||||
|
||||
// This is defined in later versions of Chromium, remove this if you see
|
||||
// compiler complaining duplicate defines.
|
||||
#if defined(OS_WIN) || defined(OS_FUCHSIA)
|
||||
#define CrPRIdPid "ld"
|
||||
#else
|
||||
#define CrPRIdPid "d"
|
||||
#endif
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
@@ -78,6 +88,19 @@ RendererClientBase::RendererClientBase() {
|
||||
RendererClientBase::~RendererClientBase() {
|
||||
}
|
||||
|
||||
void RendererClientBase::DidCreateScriptContext(
|
||||
v8::Handle<v8::Context> context,
|
||||
content::RenderFrame* render_frame) {
|
||||
// global.setHidden("contextId", `${processId}-${++nextContextId}`)
|
||||
std::string context_id = base::StringPrintf(
|
||||
"%" CrPRIdPid "-%d", base::GetCurrentProcId(), ++next_context_id_);
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::Local<v8::String> key = mate::StringToSymbol(isolate, "contextId");
|
||||
v8::Local<v8::Private> private_key = v8::Private::ForApi(isolate, key);
|
||||
v8::Local<v8::Value> value = mate::ConvertToV8(isolate, context_id);
|
||||
context->Global()->SetPrivate(context, private_key, value);
|
||||
}
|
||||
|
||||
void RendererClientBase::AddRenderBindings(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> binding_object) {
|
||||
|
||||
@@ -21,7 +21,7 @@ class RendererClientBase : public content::ContentRendererClient {
|
||||
virtual ~RendererClientBase();
|
||||
|
||||
virtual void DidCreateScriptContext(
|
||||
v8::Handle<v8::Context> context, content::RenderFrame* render_frame) = 0;
|
||||
v8::Handle<v8::Context> context, content::RenderFrame* render_frame);
|
||||
virtual void WillReleaseScriptContext(
|
||||
v8::Handle<v8::Context> context, content::RenderFrame* render_frame) = 0;
|
||||
virtual void DidClearWindowObject(content::RenderFrame* render_frame);
|
||||
@@ -57,6 +57,9 @@ class RendererClientBase : public content::ContentRendererClient {
|
||||
private:
|
||||
std::unique_ptr<PreferencesManager> preferences_manager_;
|
||||
bool isolated_world_;
|
||||
|
||||
// An increasing ID used for indentifying an V8 context in this process.
|
||||
int next_context_id_ = 0;
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
|
||||
#include "atom/utility/atom_content_utility_client.h"
|
||||
|
||||
#include "content/public/common/service_manager_connection.h"
|
||||
#include "content/public/common/simple_connection_filter.h"
|
||||
#include "content/public/utility/utility_thread.h"
|
||||
#include "mojo/public/cpp/bindings/strong_binding.h"
|
||||
#include "net/proxy/mojo_proxy_resolver_factory_impl.h"
|
||||
#include "services/service_manager/public/cpp/binder_registry.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "chrome/utility/printing_handler_win.h"
|
||||
@@ -11,6 +18,16 @@
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
void CreateProxyResolverFactory(
|
||||
net::interfaces::ProxyResolverFactoryRequest request) {
|
||||
mojo::MakeStrongBinding(base::MakeUnique<net::MojoProxyResolverFactoryImpl>(),
|
||||
std::move(request));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AtomContentUtilityClient::AtomContentUtilityClient() {
|
||||
#if defined(OS_WIN)
|
||||
handlers_.push_back(base::MakeUnique<printing::PrintingHandlerWin>());
|
||||
@@ -20,6 +37,23 @@ AtomContentUtilityClient::AtomContentUtilityClient() {
|
||||
AtomContentUtilityClient::~AtomContentUtilityClient() {
|
||||
}
|
||||
|
||||
void AtomContentUtilityClient::UtilityThreadStarted() {
|
||||
content::ServiceManagerConnection* connection =
|
||||
content::ChildThread::Get()->GetServiceManagerConnection();
|
||||
|
||||
// NOTE: Some utility process instances are not connected to the Service
|
||||
// Manager. Nothing left to do in that case.
|
||||
if (!connection)
|
||||
return;
|
||||
|
||||
auto registry = base::MakeUnique<service_manager::BinderRegistry>();
|
||||
registry->AddInterface<net::interfaces::ProxyResolverFactory>(
|
||||
base::Bind(CreateProxyResolverFactory),
|
||||
base::ThreadTaskRunnerHandle::Get());
|
||||
connection->AddConnectionFilter(
|
||||
base::MakeUnique<content::SimpleConnectionFilter>(std::move(registry)));
|
||||
}
|
||||
|
||||
bool AtomContentUtilityClient::OnMessageReceived(
|
||||
const IPC::Message& message) {
|
||||
#if defined(OS_WIN)
|
||||
|
||||
@@ -20,6 +20,7 @@ class AtomContentUtilityClient : public content::ContentUtilityClient {
|
||||
AtomContentUtilityClient();
|
||||
~AtomContentUtilityClient() override;
|
||||
|
||||
void UtilityThreadStarted() override;
|
||||
bool OnMessageReceived(const IPC::Message& message) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -116,6 +116,8 @@
|
||||
'<(libchromiumcontent_dir)/libcommon.a',
|
||||
# services/device/wake_lock/power_save_blocker/
|
||||
'<(libchromiumcontent_dir)/libpower_save_blocker.a',
|
||||
# net/proxy/mojo_*
|
||||
'<(libchromiumcontent_dir)/libnet_proxy_service.a',
|
||||
# Friends of libpdf.a:
|
||||
# On Linux we have to use "--whole-archive" to include
|
||||
# all symbols, otherwise there will be plenty of
|
||||
@@ -200,6 +202,8 @@
|
||||
'<(libchromiumcontent_dir)/libcommon.a',
|
||||
# services/device/wake_lock/power_save_blocker/
|
||||
'<(libchromiumcontent_dir)/libpower_save_blocker.a',
|
||||
# net/proxy/mojo_*
|
||||
'<(libchromiumcontent_dir)/libnet_proxy_service.a',
|
||||
# Friends of libpdf.a:
|
||||
'<(libchromiumcontent_dir)/libpdf.a',
|
||||
'<(libchromiumcontent_dir)/libppapi_cpp_objects.a',
|
||||
@@ -268,6 +272,20 @@
|
||||
],
|
||||
},
|
||||
}],
|
||||
# In the OSX 10.10 SDK, CoreBluetooth became a top level framework.
|
||||
# Previously, it was nested in IOBluetooth. In order for Chrome to run on
|
||||
# OSes older than OSX 10.10, the top level CoreBluetooth framework must be
|
||||
# weakly linked.
|
||||
['mac_sdk=="10.10" and libchromiumcontent_component==0', {
|
||||
'direct_dependent_settings': {
|
||||
'xcode_settings': {
|
||||
'OTHER_LDFLAGS': [
|
||||
'-weak_framework',
|
||||
'CoreBluetooth',
|
||||
],
|
||||
},
|
||||
},
|
||||
}],
|
||||
]
|
||||
}], # OS=="mac"
|
||||
['OS=="win"', {
|
||||
@@ -296,6 +314,8 @@
|
||||
'<(libchromiumcontent_dir)/common.lib',
|
||||
# services/device/wake_lock/power_save_blocker/
|
||||
'<(libchromiumcontent_dir)/power_save_blocker.lib',
|
||||
# net/proxy/mojo_*
|
||||
'<(libchromiumcontent_dir)/net_proxy_service.lib',
|
||||
# Friends of pdf.lib:
|
||||
'<(libchromiumcontent_dir)/pdf.lib',
|
||||
'<(libchromiumcontent_dir)/ppapi_cpp_objects.lib',
|
||||
|
||||
@@ -100,14 +100,12 @@ BrowserContext::~BrowserContext() {
|
||||
}
|
||||
|
||||
void BrowserContext::InitPrefs() {
|
||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
auto prefs_path = GetPath().Append(FILE_PATH_LITERAL("Preferences"));
|
||||
PrefServiceFactory prefs_factory;
|
||||
scoped_refptr<JsonPrefStore> pref_store =
|
||||
base::MakeRefCounted<JsonPrefStore>(prefs_path);
|
||||
{
|
||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
pref_store->ReadPrefs(); // Synchronous.
|
||||
}
|
||||
pref_store->ReadPrefs(); // Synchronous.
|
||||
prefs_factory.set_user_prefs(pref_store);
|
||||
|
||||
auto registry = make_scoped_refptr(new PrefRegistrySimple);
|
||||
|
||||
@@ -184,10 +184,20 @@ void OverrideAppLogsPath() {
|
||||
}
|
||||
#endif
|
||||
|
||||
void BrowserMainParts::PreEarlyInitialization() {
|
||||
void BrowserMainParts::InitializeFeatureList() {
|
||||
auto* cmd_line = base::CommandLine::ForCurrentProcess();
|
||||
const auto enable_features =
|
||||
cmd_line->GetSwitchValueASCII(switches::kEnableFeatures);
|
||||
const auto disable_features =
|
||||
cmd_line->GetSwitchValueASCII(switches::kDisableFeatures);
|
||||
|
||||
std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
|
||||
feature_list->InitializeFromCommandLine("", "");
|
||||
feature_list->InitializeFromCommandLine(enable_features, disable_features);
|
||||
base::FeatureList::SetInstance(std::move(feature_list));
|
||||
}
|
||||
|
||||
void BrowserMainParts::PreEarlyInitialization() {
|
||||
InitializeFeatureList();
|
||||
OverrideAppLogsPath();
|
||||
#if defined(USE_X11)
|
||||
views::LinuxUI::SetInstance(BuildGtkUi());
|
||||
|
||||
@@ -46,6 +46,8 @@ class BrowserMainParts : public content::BrowserMainParts {
|
||||
int PreCreateThreads() override;
|
||||
void PostDestroyThreads() override;
|
||||
|
||||
void InitializeFeatureList();
|
||||
|
||||
private:
|
||||
#if defined(OS_MACOSX)
|
||||
void InitializeMainNib();
|
||||
|
||||
@@ -698,6 +698,8 @@ void InspectableWebContentsImpl::WebContentsDestroyed() {
|
||||
for (const auto& pair : pending_requests_)
|
||||
delete pair.first;
|
||||
|
||||
pending_requests_.clear();
|
||||
|
||||
if (view_ && view_->GetDelegate())
|
||||
view_->GetDelegate()->DevToolsClosed();
|
||||
}
|
||||
|
||||
117
brightray/browser/net/chrome_mojo_proxy_resolver_factory.cc
Normal file
117
brightray/browser/net/chrome_mojo_proxy_resolver_factory.cc
Normal file
@@ -0,0 +1,117 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "brightray/browser/net/chrome_mojo_proxy_resolver_factory.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/memory/singleton.h"
|
||||
#include "base/single_thread_task_runner.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/utility_process_host.h"
|
||||
#include "content/public/browser/utility_process_host_client.h"
|
||||
#include "services/service_manager/public/cpp/interface_provider.h"
|
||||
|
||||
namespace {
|
||||
const int kUtilityProcessIdleTimeoutSeconds = 5;
|
||||
}
|
||||
|
||||
// static
|
||||
ChromeMojoProxyResolverFactory* ChromeMojoProxyResolverFactory::GetInstance() {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
return base::Singleton<
|
||||
ChromeMojoProxyResolverFactory,
|
||||
base::LeakySingletonTraits<ChromeMojoProxyResolverFactory>>::get();
|
||||
}
|
||||
|
||||
ChromeMojoProxyResolverFactory::ChromeMojoProxyResolverFactory() {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
}
|
||||
|
||||
ChromeMojoProxyResolverFactory::~ChromeMojoProxyResolverFactory() {
|
||||
DCHECK(thread_checker_.CalledOnValidThread());
|
||||
}
|
||||
|
||||
std::unique_ptr<base::ScopedClosureRunner>
|
||||
ChromeMojoProxyResolverFactory::CreateResolver(
|
||||
const std::string& pac_script,
|
||||
mojo::InterfaceRequest<net::interfaces::ProxyResolver> req,
|
||||
net::interfaces::ProxyResolverFactoryRequestClientPtr client) {
|
||||
DCHECK(thread_checker_.CalledOnValidThread());
|
||||
if (!resolver_factory_)
|
||||
CreateFactory();
|
||||
|
||||
if (!resolver_factory_) {
|
||||
// If factory creation failed, close |req|'s message pipe, which should
|
||||
// cause a connection error.
|
||||
req = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
idle_timer_.Stop();
|
||||
num_proxy_resolvers_++;
|
||||
resolver_factory_->CreateResolver(pac_script, std::move(req),
|
||||
std::move(client));
|
||||
return base::MakeUnique<base::ScopedClosureRunner>(
|
||||
base::Bind(&ChromeMojoProxyResolverFactory::OnResolverDestroyed,
|
||||
base::Unretained(this)));
|
||||
}
|
||||
|
||||
void ChromeMojoProxyResolverFactory::CreateFactory() {
|
||||
DCHECK(thread_checker_.CalledOnValidThread());
|
||||
DCHECK(!resolver_factory_);
|
||||
DCHECK(!weak_utility_process_host_);
|
||||
|
||||
DVLOG(1) << "Attempting to create utility process for proxy resolver";
|
||||
content::UtilityProcessHost* utility_process_host =
|
||||
content::UtilityProcessHost::Create(
|
||||
scoped_refptr<content::UtilityProcessHostClient>(),
|
||||
base::ThreadTaskRunnerHandle::Get());
|
||||
utility_process_host->SetName(base::ASCIIToUTF16("Electron Proxy Resolver"));
|
||||
bool process_started = utility_process_host->Start();
|
||||
if (process_started) {
|
||||
BindInterface(utility_process_host, &resolver_factory_);
|
||||
weak_utility_process_host_ = utility_process_host->AsWeakPtr();
|
||||
} else {
|
||||
LOG(ERROR) << "Unable to connect to utility process";
|
||||
return;
|
||||
}
|
||||
|
||||
resolver_factory_.set_connection_error_handler(base::Bind(
|
||||
&ChromeMojoProxyResolverFactory::DestroyFactory, base::Unretained(this)));
|
||||
}
|
||||
|
||||
void ChromeMojoProxyResolverFactory::DestroyFactory() {
|
||||
resolver_factory_.reset();
|
||||
delete weak_utility_process_host_.get();
|
||||
weak_utility_process_host_.reset();
|
||||
}
|
||||
|
||||
void ChromeMojoProxyResolverFactory::OnResolverDestroyed() {
|
||||
DCHECK(thread_checker_.CalledOnValidThread());
|
||||
DCHECK_GT(num_proxy_resolvers_, 0u);
|
||||
if (--num_proxy_resolvers_ == 0) {
|
||||
// When all proxy resolvers have been destroyed, the proxy resolver factory
|
||||
// is no longer needed. However, new proxy resolvers may be created
|
||||
// shortly after being destroyed (e.g. due to a network change).
|
||||
//
|
||||
// On desktop, where a utility process is used, if the utility process is
|
||||
// shut down immediately, this would cause unnecessary process churn, so
|
||||
// wait for an idle timeout before shutting down the proxy resolver utility
|
||||
// process.
|
||||
idle_timer_.Start(
|
||||
FROM_HERE,
|
||||
base::TimeDelta::FromSeconds(kUtilityProcessIdleTimeoutSeconds), this,
|
||||
&ChromeMojoProxyResolverFactory::OnIdleTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
void ChromeMojoProxyResolverFactory::OnIdleTimeout() {
|
||||
DCHECK(thread_checker_.CalledOnValidThread());
|
||||
DCHECK_EQ(num_proxy_resolvers_, 0u);
|
||||
DestroyFactory();
|
||||
}
|
||||
73
brightray/browser/net/chrome_mojo_proxy_resolver_factory.h
Normal file
73
brightray/browser/net/chrome_mojo_proxy_resolver_factory.h
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BRIGHTRAY_BROWSER_NET_CHROME_MOJO_PROXY_RESOLVER_FACTORY_H_
|
||||
#define BRIGHTRAY_BROWSER_NET_CHROME_MOJO_PROXY_RESOLVER_FACTORY_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/threading/thread_checker.h"
|
||||
#include "base/timer/timer.h"
|
||||
#include "net/proxy/mojo_proxy_resolver_factory.h"
|
||||
|
||||
namespace content {
|
||||
class UtilityProcessHost;
|
||||
}
|
||||
|
||||
namespace base {
|
||||
template <typename Type>
|
||||
struct DefaultSingletonTraits;
|
||||
} // namespace base
|
||||
|
||||
// A factory used to create connections to Mojo proxy resolver services. On
|
||||
// Android, the proxy resolvers will run in the browser process, and on other
|
||||
// platforms, they'll all be run in the same utility process. Utility process
|
||||
// crashes are detected and the utility process is automatically restarted.
|
||||
class ChromeMojoProxyResolverFactory : public net::MojoProxyResolverFactory {
|
||||
public:
|
||||
static ChromeMojoProxyResolverFactory* GetInstance();
|
||||
|
||||
// Overridden from net::MojoProxyResolverFactory:
|
||||
std::unique_ptr<base::ScopedClosureRunner> CreateResolver(
|
||||
const std::string& pac_script,
|
||||
mojo::InterfaceRequest<net::interfaces::ProxyResolver> req,
|
||||
net::interfaces::ProxyResolverFactoryRequestClientPtr client) override;
|
||||
|
||||
private:
|
||||
friend struct base::DefaultSingletonTraits<ChromeMojoProxyResolverFactory>;
|
||||
ChromeMojoProxyResolverFactory();
|
||||
~ChromeMojoProxyResolverFactory() override;
|
||||
|
||||
// Creates the proxy resolver factory. On desktop, creates a new utility
|
||||
// process before creating it out of process. On Android, creates it on the
|
||||
// current thread.
|
||||
void CreateFactory();
|
||||
|
||||
// Destroys |resolver_factory_|.
|
||||
void DestroyFactory();
|
||||
|
||||
// Invoked each time a proxy resolver is destroyed.
|
||||
void OnResolverDestroyed();
|
||||
|
||||
// Invoked once an idle timeout has elapsed after all proxy resolvers are
|
||||
// destroyed.
|
||||
void OnIdleTimeout();
|
||||
|
||||
net::interfaces::ProxyResolverFactoryPtr resolver_factory_;
|
||||
|
||||
base::WeakPtr<content::UtilityProcessHost> weak_utility_process_host_;
|
||||
|
||||
size_t num_proxy_resolvers_ = 0;
|
||||
|
||||
base::OneShotTimer idle_timer_;
|
||||
|
||||
base::ThreadChecker thread_checker_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ChromeMojoProxyResolverFactory);
|
||||
};
|
||||
|
||||
#endif // BRIGHTRAY_BROWSER_NET_CHROME_MOJO_PROXY_RESOLVER_FACTORY_H_
|
||||
@@ -52,8 +52,7 @@ void NetLog::StartLogging() {
|
||||
base::FilePath log_path =
|
||||
command_line->GetSwitchValuePath(switches::kLogNetLog);
|
||||
std::unique_ptr<base::Value> constants(GetConstants());
|
||||
net::NetLogCaptureMode capture_mode =
|
||||
net::NetLogCaptureMode::IncludeCookiesAndCredentials();
|
||||
net::NetLogCaptureMode capture_mode = net::NetLogCaptureMode::Default();
|
||||
|
||||
file_net_log_observer_ =
|
||||
net::FileNetLogObserver::CreateUnbounded(log_path, std::move(constants));
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "base/threading/sequenced_worker_pool.h"
|
||||
#include "base/threading/worker_pool.h"
|
||||
#include "brightray/browser/browser_client.h"
|
||||
#include "brightray/browser/net/chrome_mojo_proxy_resolver_factory.h"
|
||||
#include "brightray/browser/net/devtools_network_controller_handle.h"
|
||||
#include "brightray/browser/net/devtools_network_transaction_factory.h"
|
||||
#include "brightray/browser/net/require_ct_delegate.h"
|
||||
@@ -41,7 +42,7 @@
|
||||
#include "net/proxy/proxy_config_service.h"
|
||||
#include "net/proxy/proxy_script_fetcher_impl.h"
|
||||
#include "net/proxy/proxy_service.h"
|
||||
#include "net/proxy/proxy_service_v8.h"
|
||||
#include "net/proxy/proxy_service_mojo.h"
|
||||
#include "net/ssl/channel_id_service.h"
|
||||
#include "net/ssl/default_channel_id_store.h"
|
||||
#include "net/ssl/ssl_config_service_defaults.h"
|
||||
@@ -229,14 +230,12 @@ net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() {
|
||||
storage_->set_proxy_service(net::ProxyService::CreateFixed(
|
||||
proxy_config));
|
||||
} else {
|
||||
storage_->set_proxy_service(
|
||||
net::CreateProxyServiceUsingV8ProxyResolver(
|
||||
std::move(proxy_config_service_),
|
||||
new net::ProxyScriptFetcherImpl(url_request_context_.get()),
|
||||
dhcp_factory.Create(url_request_context_.get()),
|
||||
host_resolver.get(),
|
||||
nullptr,
|
||||
url_request_context_->network_delegate()));
|
||||
storage_->set_proxy_service(net::CreateProxyServiceUsingMojoFactory(
|
||||
ChromeMojoProxyResolverFactory::GetInstance(),
|
||||
std::move(proxy_config_service_),
|
||||
new net::ProxyScriptFetcherImpl(url_request_context_.get()),
|
||||
dhcp_factory.Create(url_request_context_.get()), host_resolver.get(),
|
||||
nullptr, url_request_context_->network_delegate()));
|
||||
}
|
||||
|
||||
std::vector<std::string> schemes;
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
'browser/net/devtools_network_transaction.h',
|
||||
'browser/net/devtools_network_upload_data_stream.cc',
|
||||
'browser/net/devtools_network_upload_data_stream.h',
|
||||
'browser/net/chrome_mojo_proxy_resolver_factory.cc',
|
||||
'browser/net/chrome_mojo_proxy_resolver_factory.h',
|
||||
'browser/net/require_ct_delegate.cc',
|
||||
'browser/net/require_ct_delegate.h',
|
||||
'browser/net_log.cc',
|
||||
|
||||
@@ -147,6 +147,7 @@
|
||||
'BUILDING_V8_SHARED',
|
||||
'BUILDING_V8_PLATFORM_SHARED',
|
||||
'BUILDING_V8_BASE_SHARED',
|
||||
'NODE_WITHOUT_NODE_OPTIONS',
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="mac" and libchromiumcontent_component==0', {
|
||||
|
||||
@@ -17,7 +17,7 @@ an issue:
|
||||
## Guides
|
||||
|
||||
* [Glossary of Terms](glossary.md)
|
||||
* [Supported Platforms](tutorial/supported-platforms.md)
|
||||
* [Support](tutorial/support.md)
|
||||
* [Security](tutorial/security.md)
|
||||
* [Versioning](tutorial/electron-versioning.md)
|
||||
* [Application Distribution](tutorial/application-distribution.md)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> Define keyboard shortcuts.
|
||||
|
||||
Accelerators are Strings that can contain multiple modifiers and key codes,
|
||||
Accelerators are Strings that can contain multiple modifiers and a single key code,
|
||||
combined by the `+` character, and are used to define keyboard shortcuts
|
||||
throughout your application.
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@ terminating the application.
|
||||
then `before-quit` is emitted *after* emitting `close` event on all windows and
|
||||
closing them.
|
||||
|
||||
**Note:** On Windows, this event will not be emitted if the app is closed due
|
||||
to a shutdown/restart of the system or a user logout.
|
||||
|
||||
### Event: 'will-quit'
|
||||
|
||||
Returns:
|
||||
@@ -77,6 +80,9 @@ terminating the application.
|
||||
See the description of the `window-all-closed` event for the differences between
|
||||
the `will-quit` and `window-all-closed` events.
|
||||
|
||||
**Note:** On Windows, this event will not be emitted if the app is closed due
|
||||
to a shutdown/restart of the system or a user logout.
|
||||
|
||||
### Event: 'quit'
|
||||
|
||||
Returns:
|
||||
@@ -86,6 +92,9 @@ Returns:
|
||||
|
||||
Emitted when the application is quitting.
|
||||
|
||||
**Note:** On Windows, this event will not be emitted if the app is closed due
|
||||
to a shutdown/restart of the system or a user logout.
|
||||
|
||||
### Event: 'open-file' _macOS_
|
||||
|
||||
Returns:
|
||||
@@ -356,6 +365,23 @@ assistive technologies, such as screen readers, are enabled or disabled.
|
||||
See https://www.chromium.org/developers/design-documents/accessibility for more
|
||||
details.
|
||||
|
||||
### Event: 'session-created'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `session` [Session](session.md)
|
||||
|
||||
Emitted when Electron has created a new `session`.
|
||||
|
||||
```javascript
|
||||
const {app} = require('electron')
|
||||
|
||||
app.on('session-created', (event, session) => {
|
||||
console.log(session)
|
||||
})
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
The `app` object has the following methods:
|
||||
@@ -522,8 +548,9 @@ Overrides the current application's name.
|
||||
|
||||
### `app.getLocale()`
|
||||
|
||||
Returns `String` - The current application locale. Possible return values are documented
|
||||
[here](locales.md).
|
||||
Returns `String` - The current application locale. Possible return values are documented [here](locales.md).
|
||||
|
||||
To set the locale, you'll want to use a command line switch at app startup, which may be found [here](https://github.com/electron/electron/blob/master/docs/api/chrome-command-line-switches.md).
|
||||
|
||||
**Note:** When distributing your packaged app, you have to also ship the
|
||||
`locales` folder.
|
||||
|
||||
@@ -202,7 +202,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
than screen. Default is `false`.
|
||||
* `backgroundColor` String (optional) - Window's background color as a hexadecimal value,
|
||||
like `#66CD00` or `#FFF` or `#80FFFFFF` (alpha is supported). Default is
|
||||
`#FFF` (white).
|
||||
`#FFF` (white). If `transparent` is set to `true`, only values with transparent (`#00-------`) or opaque (`#FF-----`) alpha values are respected.
|
||||
* `hasShadow` Boolean (optional) - Whether window should have a shadow. This is only
|
||||
implemented on macOS. Default is `true`.
|
||||
* `opacity` Number (optional) - Set the initial opacity of the window, between 0.0 (fully
|
||||
@@ -287,7 +287,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
between the web pages even when you specified different values for them,
|
||||
including but not limited to `preload`, `sandbox` and `nodeIntegration`.
|
||||
So it is suggested to use exact same `webPreferences` for web pages with
|
||||
the same `affinity`.
|
||||
the same `affinity`. _This property is experimental_
|
||||
* `zoomFactor` Number (optional) - The default zoom factor of the page, `3.0` represents
|
||||
`300%`. Default is `1.0`.
|
||||
* `javascript` Boolean (optional) - Enables JavaScript support. Default is `true`.
|
||||
@@ -361,7 +361,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
script. You can use the `will-attach-webview` event on [webContents](web-contents.md)
|
||||
to strip away the `preload` script and to validate or alter the
|
||||
`<webview>`'s initial settings.
|
||||
* `additionArguments` String[] (optional) - A list of strings that will be appended
|
||||
* `additionalArguments` String[] (optional) - A list of strings that will be appended
|
||||
to `process.argv` in the renderer process of this app. Useful for passing small
|
||||
bits of data down to renderer process preload scripts.
|
||||
|
||||
@@ -1199,7 +1199,7 @@ menu bar.
|
||||
|
||||
* `progress` Double
|
||||
* `options` Object (optional)
|
||||
* `mode` String _Windows_ - Mode for the progress bar. Can be `none`, `normal`, `indeterminate`, `error`, or `paused`.
|
||||
* `mode` String _Windows_ - Mode for the progress bar. Can be `none`, `normal`, `indeterminate`, `error` or `paused`.
|
||||
|
||||
Sets progress value in progress bar. Valid range is [0, 1.0].
|
||||
|
||||
@@ -1216,7 +1216,7 @@ mode set (but with a value within the valid range), `normal` will be assumed.
|
||||
|
||||
#### `win.setOverlayIcon(overlay, description)` _Windows_
|
||||
|
||||
* `overlay` [NativeImage](native-image.md) - the icon to display on the bottom
|
||||
* `overlay` [NativeImage](native-image.md) | null - the icon to display on the bottom
|
||||
right corner of the taskbar icon. If this parameter is `null`, the overlay is
|
||||
cleared
|
||||
* `description` String - a description that will be provided to Accessibility
|
||||
|
||||
@@ -30,7 +30,7 @@ The `inAppPurchase` module has the following methods:
|
||||
|
||||
### `inAppPurchase.canMakePayments()`
|
||||
|
||||
Returns `true` if the user can make a payment and `false` otherwise.
|
||||
Returns `Boolean`, whether a user can make a payment.
|
||||
|
||||
### `inAppPurchase.getReceiptURL()`
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ Sets the `image` associated with this tray icon.
|
||||
|
||||
#### `tray.setPressedImage(image)` _macOS_
|
||||
|
||||
* `image` [NativeImage](native-image.md)
|
||||
* `image` ([NativeImage](native-image.md) | String)
|
||||
|
||||
Sets the `image` associated with this tray icon when pressed on macOS.
|
||||
|
||||
@@ -262,7 +262,7 @@ The `position` is only available on Windows, and it is (0, 0) by default.
|
||||
|
||||
#### `tray.setContextMenu(menu)`
|
||||
|
||||
* `menu` Menu
|
||||
* `menu` Menu | null
|
||||
|
||||
Sets the context menu for this icon.
|
||||
|
||||
|
||||
@@ -1367,11 +1367,17 @@ Shows pop-up dictionary that searches the selected word on the page.
|
||||
Set the size of the page. This is only supported for `<webview>` guest contents.
|
||||
|
||||
* `options` Object
|
||||
* `normal` Object (optional) - Normal size of the page. This can be used in
|
||||
* `enableAutoSize` Boolean (optional) - true to make the webview container automatically
|
||||
resize within the bounds specified by the attributes normal, min and max.
|
||||
* `normal` [Size](structures/size.md) (optional) - Normal size of the page. This can be used in
|
||||
combination with the [`disableguestresize`](webview-tag.md#disableguestresize)
|
||||
attribute to manually resize the webview guest contents.
|
||||
* `min` [Size](structures/size.md) (optional) - Minimum size of the page. This can be used in
|
||||
combination with the [`disableguestresize`](webview-tag.md#disableguestresize)
|
||||
attribute to manually resize the webview guest contents.
|
||||
* `max` [Size](structures/size.md) (optional) - Maximium size of the page. This can be used in
|
||||
combination with the [`disableguestresize`](webview-tag.md#disableguestresize)
|
||||
attribute to manually resize the webview guest contents.
|
||||
* `width` Integer
|
||||
* `height` Integer
|
||||
|
||||
#### `contents.isOffscreen()`
|
||||
|
||||
|
||||
@@ -173,6 +173,7 @@ Set the security origin of the isolated world.
|
||||
Returns `Object`:
|
||||
|
||||
* `images` [MemoryUsageDetails](structures/memory-usage-details.md)
|
||||
* `scripts` [MemoryUsageDetails](structures/memory-usage-details.md)
|
||||
* `cssStyleSheets` [MemoryUsageDetails](structures/memory-usage-details.md)
|
||||
* `xslStyleSheets` [MemoryUsageDetails](structures/memory-usage-details.md)
|
||||
* `fonts` [MemoryUsageDetails](structures/memory-usage-details.md)
|
||||
|
||||
@@ -24,7 +24,12 @@ Returns [`BrowserWindowProxy`](browser-window-proxy.md) - Creates a new window
|
||||
and returns an instance of `BrowserWindowProxy` class.
|
||||
|
||||
The `features` string follows the format of standard browser, but each feature
|
||||
has to be a field of `BrowserWindow`'s options.
|
||||
has to be a field of `BrowserWindow`'s options. These are the features you can set via `features` string: `zoomFactor`, `nodeIntegration`, `preload`, `javascript`, `contextIsolation`, `webviewTag`.
|
||||
|
||||
For example:
|
||||
```js
|
||||
window.open('https://github.com', '_blank', 'nodeIntegration=no')
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
|
||||
|
||||
@@ -26,10 +26,9 @@ contribute:
|
||||
|
||||
## Asking for General Help
|
||||
|
||||
Because the level of activity in the `electron/electron` repository is
|
||||
so high, questions or requests for general help using Electron should
|
||||
be directed at the [community slack channel](https://atomio.slack.com)
|
||||
or the [forum](https://discuss.atom.io/c/electron).
|
||||
["Finding Support"](../tutorial/support.md#finding-support) has a
|
||||
list of resources for getting programming help, reporting security issues,
|
||||
contributing, and more. Please use the issue tracker for bugs only!
|
||||
|
||||
## Submitting a Bug Report
|
||||
|
||||
|
||||
@@ -2,11 +2,31 @@
|
||||
|
||||
This document describes the process for releasing a new version of Electron.
|
||||
|
||||
## Set your tokens and environment variables
|
||||
You'll need Electron S3 credentials in order to create and
|
||||
upload an Electron release. Contact a team member for more
|
||||
information.
|
||||
|
||||
There are a handful of `*_TOKEN` environment variables needed by the release
|
||||
scripts. Once you've generated these per-user tokens, you may want to keep
|
||||
them in a local file that you can `source` when starting a release.
|
||||
* `ELECTRON_GITHUB_TOKEN`:
|
||||
Create as described at https://github.com/settings/tokens/new,
|
||||
giving the token repo access scope.
|
||||
* `APPVEYOR_TOKEN`:
|
||||
Create a token from https://windows-ci.electronjs.org/api-token
|
||||
If you don't have an account, ask a team member to add you.
|
||||
* `CIRCLE_TOKEN`:
|
||||
Create a token from "Personal API Tokens" at https://circleci.com/account/api
|
||||
* `VSTS_TOKEN`:
|
||||
Create a Personal Access Token at https://github.visualstudio.com/_usersSettings/tokens
|
||||
with the scope of `Build (read and execute)`.
|
||||
|
||||
## Determine which branch to release from
|
||||
|
||||
- **If releasing beta,** run the scripts below from `master`.
|
||||
- **If releasing a stable version,** run the scripts below from `1-7-x` or
|
||||
`1-6-x`, depending on which version you are releasing for.
|
||||
- **If releasing a stable version,** run the scripts below from the branch
|
||||
you're stabilizing.
|
||||
|
||||
## Find out what version change is needed
|
||||
Run `npm run prepare-release -- --notesOnly` to view auto generated release
|
||||
@@ -14,6 +34,11 @@ notes. The notes generated should help you determine if this is a major, minor,
|
||||
patch, or beta version change. Read the
|
||||
[Version Change Rules](../tutorial/electron-versioning.md#semver) for more information.
|
||||
|
||||
**NB:** If releasing from a branch, e.g. 1-8-x, check out the branch with
|
||||
`git checkout 1-8-x` rather than `git checkout -b remotes/origin/1-8-x`.
|
||||
The scripts need `git rev-parse --abbrev-ref HEAD` to return a short name,
|
||||
e.g. no `remotes/origin/`
|
||||
|
||||
## Run the prepare-release script
|
||||
The prepare release script will do the following:
|
||||
1. Check if a release is already in process and if so it will halt.
|
||||
@@ -55,10 +80,11 @@ npm run prepare-release -- --stable
|
||||
The `prepare-release` script will trigger the builds via API calls.
|
||||
To monitor the build progress, see the following pages:
|
||||
|
||||
- [mac-ci.electronjs.org/blue/organizations/jenkins/electron-mas-x64-release/activity](https://mac-ci.electronjs.org/blue/organizations/jenkins/electron-mas-x64-release/activity) for Mac App Store
|
||||
- [mac-ci.electronjs.org/blue/organizations/jenkins/electron-osx-x64-release/activity](https://mac-ci.electronjs.org/blue/organizations/jenkins/electron-osx-x64-release/activity) for OS X
|
||||
- [circleci.com/gh/electron/electron](https://circleci.com/gh/electron) for Linux
|
||||
- [windows-ci.electronjs.org/project/AppVeyor/electron](https://windows-ci.electronjs.org/project/AppVeyor/electron) for Windows
|
||||
- [electron-release-mas-x64](https://github.visualstudio.com/electron/_build/index?context=allDefinitions&path=%5C&definitionId=19&_a=completed) for MAS builds.
|
||||
- [electron-release-osx-x64](https://github.visualstudio.com/electron/_build/index?context=allDefinitions&path=%5C&definitionId=18&_a=completed) for OSX builds.
|
||||
- [circleci.com/gh/electron/electron](https://circleci.com/gh/electron) for Linux builds.
|
||||
- [windows-ci.electronjs.org/project/AppVeyor/electron-39ng6](https://windows-ci.electronjs.org/project/AppVeyor/electron-39ng6) for Windows 32-bit builds.
|
||||
- [windows-ci.electronjs.org/project/AppVeyor/electron](https://windows-ci.electronjs.org/project/AppVeyor/electron) for Windows 64-bit builds.
|
||||
|
||||
## Compile release notes
|
||||
|
||||
@@ -159,14 +185,15 @@ This release is published to [npm](https://www.npmjs.com/package/electron) under
|
||||
|
||||
## Edit the release draft
|
||||
|
||||
1. Visit [the releases page] and you'll see a new draft release with placeholder release notes.
|
||||
1. Edit the release and add release notes.
|
||||
1. Uncheck the `prerelease` checkbox if you're publishing a stable release; leave it checked for beta releases.
|
||||
1. Click 'Save draft'. **Do not click 'Publish release'!**
|
||||
1. Wait for all builds to pass before proceeding.
|
||||
1. You can run `npm run release -- --validateRelease` to verify that all of the
|
||||
required files have been created for the release.
|
||||
|
||||
1. Visit [the releases page] and you'll see a new draft release with placeholder
|
||||
release notes.
|
||||
2. Edit the release and add release notes.
|
||||
3. Click 'Save draft'. **Do not click 'Publish release'!**
|
||||
4. Wait for all builds to pass before proceeding.
|
||||
5. In the branch, verify that the release's files have been created:
|
||||
```sh
|
||||
$ npm run release -- --validateRelease
|
||||
```
|
||||
|
||||
## Publish the release
|
||||
|
||||
@@ -181,17 +208,68 @@ on Windows by node-gyp to build native modules.
|
||||
5. Validate that all of the required files are present on GitHub and S3 and have
|
||||
the correct checksums as specified in the SHASUMS files.
|
||||
6. Publish the release on GitHub
|
||||
7. Delete the `release` branch.
|
||||
|
||||
## Publish to npm
|
||||
|
||||
Once the publish is successful, run `npm run publish-to-npm` to publish to
|
||||
release to npm.
|
||||
Before publishing to npm, you'll need to log into npm as Electron. Optionally,
|
||||
you may find [npmrc](https://www.npmjs.com/package/npmrc) to be a useful way
|
||||
to keep Electron's profile side-by-side with your own:
|
||||
```sh
|
||||
$ sudo npm install -g npmrc
|
||||
$ npmrc -c electron
|
||||
Removing old .npmrc (default)
|
||||
Activating .npmrc "electron"
|
||||
```
|
||||
|
||||
The Electron account's credentials are kept by GitHub.
|
||||
"Electron - NPM" for the URL "https://www.npmjs.com/login".
|
||||
```sh
|
||||
$ npm login
|
||||
Username: electron
|
||||
Password:
|
||||
Email: (this IS public) electron@github.com
|
||||
```
|
||||
|
||||
Publish the release to npm.
|
||||
```sh
|
||||
$ npm whoami
|
||||
electron
|
||||
$ npm run publish-to-npm
|
||||
```
|
||||
|
||||
[the releases page]: https://github.com/electron/electron/releases
|
||||
[this bump commit]: https://github.com/electron/electron/commit/78ec1b8f89b3886b856377a1756a51617bc33f5a
|
||||
[versioning]: /docs/tutorial/electron-versioning.md
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
## Rerun broken builds
|
||||
|
||||
If a release build fails for some reason, you can use `script/ci-release-build.js` to rerun a release build:
|
||||
|
||||
### Rerun all linux builds:
|
||||
```sh
|
||||
node script/ci-release-build.js --ci=CircleCI --ghRelease TARGET_BRANCH
|
||||
(TARGET_BRANCH) is the branch you are releasing from.
|
||||
```
|
||||
|
||||
### Rerun all macOS builds:
|
||||
```sh
|
||||
node script/ci-release-build.js --ci=VSTS --ghRelease TARGET_BRANCH
|
||||
(TARGET_BRANCH) is the branch you are releasing from.
|
||||
```
|
||||
|
||||
### Rerun all Windows builds:
|
||||
```sh
|
||||
node script/ci-release-build.js --ci=AppVeyor --ghRelease TARGET_BRANCH
|
||||
(TARGET_BRANCH) is the branch you are releasing from.
|
||||
```
|
||||
|
||||
Additionally you can pass a job name to the script to run an individual job, eg:
|
||||
````sh
|
||||
node script/ci-release-build.js --ci=AppVeyor --ghRelease --job=electron-x64 TARGET_BRANCH
|
||||
```
|
||||
|
||||
## Fix missing binaries of a release manually
|
||||
|
||||
In the case of a corrupted release with broken CI machines, we might have to
|
||||
|
||||
94
docs/tutorial/support.md
Normal file
94
docs/tutorial/support.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# Electron Support
|
||||
|
||||
## Finding Support
|
||||
|
||||
If you have a security concern,
|
||||
please see the [security document](../../SECURITY.md).
|
||||
|
||||
If you're looking for programming help,
|
||||
for answers to questions,
|
||||
or to join in discussion with other developers who use Electron,
|
||||
you can interact with the community in these locations:
|
||||
- [`electron`](https://discuss.atom.io/c/electron) category on the Atom
|
||||
forums
|
||||
- `#atom-shell` channel on Freenode
|
||||
- [`Electron`](https://atom-slack.herokuapp.com) channel on Atom's Slack
|
||||
- [`electron-ru`](https://telegram.me/electron_ru) *(Russian)*
|
||||
- [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)*
|
||||
- [`electron-kr`](https://electron-kr.github.io/electron-kr) *(Korean)*
|
||||
- [`electron-jp`](https://electron-jp.slack.com) *(Japanese)*
|
||||
- [`electron-tr`](https://electron-tr.herokuapp.com) *(Turkish)*
|
||||
- [`electron-id`](https://electron-id.slack.com) *(Indonesia)*
|
||||
- [`electron-pl`](https://electronpl.github.io) *(Poland)*
|
||||
|
||||
If you'd like to contribute to Electron,
|
||||
see the [contributing document](../../CONTRIBUTING.md).
|
||||
|
||||
If you've found a bug in a [supported version](#supported-versions) of Electron,
|
||||
please report it with the [issue tracker](../development/issues.md).
|
||||
|
||||
[awesome-electron](https://github.com/sindresorhus/awesome-electron)
|
||||
is a community-maintained list of useful example apps,
|
||||
tools and resources.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
The latest three release branches are supported by the Electron team.
|
||||
For example, if the latest release is 2.0.x, then the 2-0-x series
|
||||
is supported, as are the two previous release series 1-7-x and 1-8-x.
|
||||
|
||||
When a release branch reaches the end of its support cycle, the series
|
||||
will be deprecated in NPM and a final end-of-support release will be
|
||||
made. This release will add a warning to inform that an unsupported
|
||||
version of Electron is in use.
|
||||
|
||||
These steps are to help app developers learn when a branch they're
|
||||
using becomes unsupported, but without being excessively intrusive
|
||||
to end users.
|
||||
|
||||
If an application has exceptional circumstances and needs to stay
|
||||
on an unsupported series of Electron, developers can silence the
|
||||
end-of-support warning by omitting the final release from the app's
|
||||
`package.json` `devDependencies`. For example, since the 1-6-x series
|
||||
ended with an end-of-support 1.6.18 release, developers could choose
|
||||
to stay in the 1-6-x series without warnings with `devDependency` of
|
||||
`"electron": 1.6.0 - 1.6.17`.
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
Following platforms are supported by Electron:
|
||||
|
||||
### macOS
|
||||
|
||||
Only 64bit binaries are provided for macOS, and the minimum macOS version
|
||||
supported is macOS 10.9.
|
||||
|
||||
### Windows
|
||||
|
||||
Windows 7 and later are supported, older operating systems are not supported
|
||||
(and do not work).
|
||||
|
||||
Both `ia32` (`x86`) and `x64` (`amd64`) binaries are provided for Windows.
|
||||
Running Electron apps on Windows for ARM devices is possible by using the
|
||||
ia32 binary.
|
||||
|
||||
### Linux
|
||||
|
||||
The prebuilt `ia32` (`i686`) and `x64` (`amd64`) binaries of Electron are built on
|
||||
Ubuntu 12.04, the `armv7l` binary is built against ARM v7 with hard-float ABI and
|
||||
NEON for Debian Wheezy.
|
||||
|
||||
[Until the release of Electron 2.0][arm-breaking-change], Electron will also
|
||||
continue to release the `armv7l` binary with a simple `arm` suffix. Both binaries
|
||||
are identical.
|
||||
|
||||
Whether the prebuilt binary can run on a distribution depends on whether the
|
||||
distribution includes the libraries that Electron is linked to on the building
|
||||
platform, so only Ubuntu 12.04 is guaranteed to work, but following platforms
|
||||
are also verified to be able to run the prebuilt binaries of Electron:
|
||||
|
||||
* Ubuntu 12.04 and newer
|
||||
* Fedora 21
|
||||
* Debian 8
|
||||
|
||||
[arm-breaking-change]: https://github.com/electron/electron/blob/master/docs/tutorial/planned-breaking-changes.md#duplicate-arm-assets
|
||||
@@ -1,37 +1 @@
|
||||
# Supported Platforms
|
||||
|
||||
Following platforms are supported by Electron:
|
||||
|
||||
### macOS
|
||||
|
||||
Only 64bit binaries are provided for macOS, and the minimum macOS version
|
||||
supported is macOS 10.9.
|
||||
|
||||
### Windows
|
||||
|
||||
Windows 7 and later are supported, older operating systems are not supported
|
||||
(and do not work).
|
||||
|
||||
Both `ia32` (`x86`) and `x64` (`amd64`) binaries are provided for Windows.
|
||||
Please note, the `ARM` version of Windows is not supported for now.
|
||||
|
||||
### Linux
|
||||
|
||||
The prebuilt `ia32` (`i686`) and `x64` (`amd64`) binaries of Electron are built on
|
||||
Ubuntu 12.04, the `armv7l` binary is built against ARM v7 with hard-float ABI and
|
||||
NEON for Debian Wheezy.
|
||||
|
||||
[Until the release of Electron 2.0][arm-breaking-change], Electron will also
|
||||
continue to release the `armv7l` binary with a simple `arm` suffix. Both binaries
|
||||
are identical.
|
||||
|
||||
Whether the prebuilt binary can run on a distribution depends on whether the
|
||||
distribution includes the libraries that Electron is linked to on the building
|
||||
platform, so only Ubuntu 12.04 is guaranteed to work, but following platforms
|
||||
are also verified to be able to run the prebuilt binaries of Electron:
|
||||
|
||||
* Ubuntu 12.04 and later
|
||||
* Fedora 21
|
||||
* Debian 8
|
||||
|
||||
[arm-breaking-change]: https://github.com/electron/electron/blob/master/docs/tutorial/planned-breaking-changes.md#duplicate-arm-assets
|
||||
Moved to [support.md](support.md)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
'product_name%': 'Electron',
|
||||
'company_name%': 'GitHub, Inc',
|
||||
'company_abbr%': 'github',
|
||||
'version%': '2.0.0-beta.5',
|
||||
'version%': '2.0.11',
|
||||
'js2c_input_dir': '<(SHARED_INTERMEDIATE_DIR)/js2c',
|
||||
},
|
||||
'includes': [
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
'lib/renderer/inspector.js',
|
||||
'lib/renderer/override.js',
|
||||
'lib/renderer/security-warnings.js',
|
||||
'lib/renderer/web-frame-init.js',
|
||||
'lib/renderer/window-setup.js',
|
||||
'lib/renderer/web-view/guest-view-internal.js',
|
||||
'lib/renderer/web-view/web-view.js',
|
||||
@@ -273,6 +274,8 @@
|
||||
'atom/browser/net/http_protocol_handler.h',
|
||||
'atom/browser/net/js_asker.cc',
|
||||
'atom/browser/net/js_asker.h',
|
||||
'atom/browser/net/resolve_proxy_helper.cc',
|
||||
'atom/browser/net/resolve_proxy_helper.h',
|
||||
'atom/browser/net/url_request_about_job.cc',
|
||||
'atom/browser/net/url_request_about_job.h',
|
||||
'atom/browser/net/url_request_async_asar_job.cc',
|
||||
|
||||
@@ -133,7 +133,7 @@ BrowserWindow.prototype._init = function () {
|
||||
|
||||
BrowserWindow.getFocusedWindow = () => {
|
||||
for (let window of BrowserWindow.getAllWindows()) {
|
||||
if (window.isFocused()) return window
|
||||
if (window.isFocused() || window.isDevToolsFocused()) return window
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
'use strict'
|
||||
|
||||
if (process.platform !== 'darwin') {
|
||||
throw new Error('The inAppPurchase module can only be used on macOS')
|
||||
if (process.platform === 'darwin') {
|
||||
const {EventEmitter} = require('events')
|
||||
const {inAppPurchase, InAppPurchase} = process.atomBinding('in_app_purchase')
|
||||
|
||||
// inAppPurchase is an EventEmitter.
|
||||
Object.setPrototypeOf(InAppPurchase.prototype, EventEmitter.prototype)
|
||||
EventEmitter.call(inAppPurchase)
|
||||
|
||||
module.exports = inAppPurchase
|
||||
} else {
|
||||
module.exports = {
|
||||
purchaseProduct: (productID, quantity, callback) => {
|
||||
throw new Error('The inAppPurchase module can only be used on macOS')
|
||||
},
|
||||
canMakePayments: () => false,
|
||||
getReceiptURL: () => ''
|
||||
}
|
||||
}
|
||||
|
||||
const {EventEmitter} = require('events')
|
||||
const {inAppPurchase, InAppPurchase} = process.atomBinding('in_app_purchase')
|
||||
|
||||
// inAppPurchase is an EventEmitter.
|
||||
Object.setPrototypeOf(InAppPurchase.prototype, EventEmitter.prototype)
|
||||
EventEmitter.call(inAppPurchase)
|
||||
|
||||
module.exports = inAppPurchase
|
||||
|
||||
@@ -20,7 +20,7 @@ const delegate = {
|
||||
getAcceleratorForCommandId: (menu, id, useDefaultAccelerator) => {
|
||||
const command = menu.commandsMap[id]
|
||||
if (!command) return
|
||||
if (command.accelerator) return command.accelerator
|
||||
if (command.accelerator != null) return command.accelerator
|
||||
if (useDefaultAccelerator) return command.getDefaultRoleAccelerator()
|
||||
},
|
||||
executeCommand: (menu, event, id) => {
|
||||
@@ -154,7 +154,7 @@ Menu.setApplicationMenu = function (menu) {
|
||||
}
|
||||
|
||||
Menu.buildFromTemplate = function (template) {
|
||||
if (!(template instanceof Array)) {
|
||||
if (!Array.isArray(template)) {
|
||||
throw new TypeError('Invalid template for Menu')
|
||||
}
|
||||
|
||||
@@ -240,14 +240,19 @@ function indexToInsertByPosition (items, position) {
|
||||
}
|
||||
|
||||
function removeExtraSeparators (items) {
|
||||
// remove invisible items
|
||||
let ret = items.filter(e => e.visible !== false)
|
||||
|
||||
// fold adjacent separators together
|
||||
ret = ret.filter((e, idx, arr) => e.type !== 'separator' || idx === 0 || arr[idx - 1].type !== 'separator')
|
||||
let ret = items.filter((e, idx, arr) => {
|
||||
if (e.visible === false) return true
|
||||
return e.type !== 'separator' || idx === 0 || arr[idx - 1].type !== 'separator'
|
||||
})
|
||||
|
||||
// remove edge separators
|
||||
return ret.filter((e, idx, arr) => e.type !== 'separator' || (idx !== 0 && idx !== arr.length - 1))
|
||||
ret = ret.filter((e, idx, arr) => {
|
||||
if (e.visible === false) return true
|
||||
return e.type !== 'separator' || (idx !== 0 && idx !== arr.length - 1)
|
||||
})
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
function insertItemByType (item, pos) {
|
||||
|
||||
@@ -118,6 +118,18 @@ class TouchBar extends EventEmitter {
|
||||
window.removeListener('closed', removeListeners)
|
||||
window._touchBar = null
|
||||
delete this.windowListeners[id]
|
||||
const unregisterItems = (items) => {
|
||||
for (const item of items) {
|
||||
item.removeListener('change', this.changeListener)
|
||||
if (item.child instanceof TouchBar) {
|
||||
unregisterItems(item.child.ordereredItems)
|
||||
}
|
||||
}
|
||||
}
|
||||
unregisterItems(this.ordereredItems)
|
||||
if (this.escapeItem) {
|
||||
this.escapeItem.removeListener('change', this.changeListener)
|
||||
}
|
||||
}
|
||||
window.once('closed', removeListeners)
|
||||
this.windowListeners[id] = removeListeners
|
||||
|
||||
@@ -331,6 +331,10 @@ ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', function (event, params,
|
||||
event.sender.send(`ELECTRON_RESPONSE_${requestId}`, createGuest(event.sender, params))
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST_SYNC', function (event, params) {
|
||||
event.returnValue = createGuest(event.sender, params)
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', function (event, elementInstanceId, guestInstanceId, params) {
|
||||
attachGuest(event, elementInstanceId, guestInstanceId, params)
|
||||
})
|
||||
|
||||
@@ -27,11 +27,11 @@ const mergeOptions = function (child, parent, visited) {
|
||||
for (const key in parent) {
|
||||
if (key === 'isBrowserView') continue
|
||||
if (!hasProp.call(parent, key)) continue
|
||||
if (key in child) continue
|
||||
if (key in child && key !== 'webPreferences') continue
|
||||
|
||||
const value = parent[key]
|
||||
if (typeof value === 'object') {
|
||||
child[key] = mergeOptions({}, value, visited)
|
||||
child[key] = mergeOptions(child[key] || {}, value, visited)
|
||||
} else {
|
||||
child[key] = value
|
||||
}
|
||||
|
||||
@@ -162,8 +162,23 @@ require('./api/protocol')
|
||||
// Set main startup script of the app.
|
||||
const mainStartupScript = packageJson.main || 'index.js'
|
||||
|
||||
const KNOWN_XDG_DESKTOP_VALUES = ['Pantheon', 'Unity:Unity7', 'pop:GNOME']
|
||||
|
||||
function currentPlatformSupportsAppIndicator () {
|
||||
if (process.platform !== 'linux') return false
|
||||
const currentDesktop = process.env.XDG_CURRENT_DESKTOP
|
||||
|
||||
if (!currentDesktop) return false
|
||||
if (KNOWN_XDG_DESKTOP_VALUES.includes(currentDesktop)) return true
|
||||
// ubuntu based or derived session (default ubuntu one, communitheme…) supports
|
||||
// indicator too.
|
||||
if (/ubuntu/ig.test(currentDesktop)) return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Workaround for electron/electron#5050 and electron/electron#9046
|
||||
if (process.platform === 'linux' && ['Pantheon', 'Unity:Unity7', 'ubuntu:GNOME', 'pop:GNOME'].includes(process.env.XDG_CURRENT_DESKTOP)) {
|
||||
if (currentPlatformSupportsAppIndicator()) {
|
||||
process.env.XDG_CURRENT_DESKTOP = 'Unity'
|
||||
}
|
||||
|
||||
|
||||
@@ -11,22 +11,22 @@ class ObjectsRegistry {
|
||||
this.storage = {}
|
||||
|
||||
// Stores the IDs of objects referenced by WebContents.
|
||||
// (webContentsId) => [id]
|
||||
// (webContentsContextId) => [id]
|
||||
this.owners = {}
|
||||
}
|
||||
|
||||
// Register a new object and return its assigned ID. If the object is already
|
||||
// registered then the already assigned ID would be returned.
|
||||
add (webContents, obj) {
|
||||
add (webContents, contextId, obj) {
|
||||
// Get or assign an ID to the object.
|
||||
const id = this.saveToStorage(obj)
|
||||
|
||||
// Add object to the set of referenced objects.
|
||||
const webContentsId = webContents.getId()
|
||||
let owner = this.owners[webContentsId]
|
||||
const webContentsContextId = `${webContents.id}-${contextId}`
|
||||
let owner = this.owners[webContentsContextId]
|
||||
if (!owner) {
|
||||
owner = this.owners[webContentsId] = new Set()
|
||||
this.registerDeleteListener(webContents, webContentsId)
|
||||
owner = this.owners[webContentsContextId] = new Set()
|
||||
this.registerDeleteListener(webContents, contextId)
|
||||
}
|
||||
if (!owner.has(id)) {
|
||||
owner.add(id)
|
||||
@@ -43,25 +43,28 @@ class ObjectsRegistry {
|
||||
}
|
||||
|
||||
// Dereference an object according to its ID.
|
||||
remove (webContentsId, id) {
|
||||
// Dereference from the storage.
|
||||
this.dereference(id)
|
||||
|
||||
// Also remove the reference in owner.
|
||||
let owner = this.owners[webContentsId]
|
||||
// Note that an object may be double-freed (cleared when page is reloaded, and
|
||||
// then garbage collected in old page).
|
||||
remove (webContents, contextId, id) {
|
||||
const webContentsContextId = `${webContents.id}-${contextId}`
|
||||
let owner = this.owners[webContentsContextId]
|
||||
if (owner) {
|
||||
// Remove the reference in owner.
|
||||
owner.delete(id)
|
||||
// Dereference from the storage.
|
||||
this.dereference(id)
|
||||
}
|
||||
}
|
||||
|
||||
// Clear all references to objects refrenced by the WebContents.
|
||||
clear (webContentsId) {
|
||||
let owner = this.owners[webContentsId]
|
||||
clear (webContents, contextId) {
|
||||
const webContentsContextId = `${webContents.id}-${contextId}`
|
||||
let owner = this.owners[webContentsContextId]
|
||||
if (!owner) return
|
||||
|
||||
for (let id of owner) this.dereference(id)
|
||||
|
||||
delete this.owners[webContentsId]
|
||||
delete this.owners[webContentsContextId]
|
||||
}
|
||||
|
||||
// Private: Saves the object into storage and assigns an ID for it.
|
||||
@@ -80,6 +83,8 @@ class ObjectsRegistry {
|
||||
|
||||
// Private: Dereference the object from store.
|
||||
dereference (id) {
|
||||
if (process.env.ELECTRON_DISABLE_REMOTE_DEREFERENCING) return
|
||||
|
||||
let pointer = this.storage[id]
|
||||
if (pointer == null) {
|
||||
return
|
||||
@@ -91,13 +96,13 @@ class ObjectsRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
// Private: Clear the storage when webContents is reloaded/navigated.
|
||||
registerDeleteListener (webContents, webContentsId) {
|
||||
// Private: Clear the storage when renderer process is destoryed.
|
||||
registerDeleteListener (webContents, contextId) {
|
||||
const processId = webContents.getProcessId()
|
||||
const listener = (event, deletedProcessId) => {
|
||||
if (deletedProcessId === processId) {
|
||||
webContents.removeListener('render-view-deleted', listener)
|
||||
this.clear(webContentsId)
|
||||
this.clear(webContents, contextId)
|
||||
}
|
||||
}
|
||||
webContents.on('render-view-deleted', listener)
|
||||
|
||||
@@ -55,7 +55,7 @@ let getObjectPrototype = function (object) {
|
||||
}
|
||||
|
||||
// Convert a real value into meta data.
|
||||
let valueToMeta = function (sender, value, optimizeSimpleObject = false) {
|
||||
let valueToMeta = function (sender, contextId, value, optimizeSimpleObject = false) {
|
||||
// Determine the type of value.
|
||||
const meta = { type: typeof value }
|
||||
if (meta.type === 'object') {
|
||||
@@ -83,14 +83,14 @@ let valueToMeta = function (sender, value, optimizeSimpleObject = false) {
|
||||
|
||||
// Fill the meta object according to value's type.
|
||||
if (meta.type === 'array') {
|
||||
meta.members = value.map((el) => valueToMeta(sender, el))
|
||||
meta.members = value.map((el) => valueToMeta(sender, contextId, el))
|
||||
} else if (meta.type === 'object' || meta.type === 'function') {
|
||||
meta.name = value.constructor ? value.constructor.name : ''
|
||||
|
||||
// Reference the original value if it's an object, because when it's
|
||||
// passed to renderer we would assume the renderer keeps a reference of
|
||||
// it.
|
||||
meta.id = objectsRegistry.add(sender, value)
|
||||
meta.id = objectsRegistry.add(sender, contextId, value)
|
||||
meta.members = getObjectMembers(value)
|
||||
meta.proto = getObjectPrototype(value)
|
||||
} else if (meta.type === 'buffer') {
|
||||
@@ -100,7 +100,7 @@ let valueToMeta = function (sender, value, optimizeSimpleObject = false) {
|
||||
// Instead they should appear in the renderer process
|
||||
value.then(function () {}, function () {})
|
||||
|
||||
meta.then = valueToMeta(sender, function (onFulfilled, onRejected) {
|
||||
meta.then = valueToMeta(sender, contextId, function (onFulfilled, onRejected) {
|
||||
value.then(onFulfilled, onRejected)
|
||||
})
|
||||
} else if (meta.type === 'error') {
|
||||
@@ -168,7 +168,7 @@ const removeRemoteListenersAndLogWarning = (meta, args, callIntoRenderer) => {
|
||||
}
|
||||
|
||||
// Convert array of meta data from renderer into array of real values.
|
||||
const unwrapArgs = function (sender, args) {
|
||||
const unwrapArgs = function (sender, contextId, args) {
|
||||
const metaToValue = function (meta) {
|
||||
let i, len, member, ref, returnValue
|
||||
switch (meta.type) {
|
||||
@@ -177,7 +177,7 @@ const unwrapArgs = function (sender, args) {
|
||||
case 'remote-object':
|
||||
return objectsRegistry.get(meta.id)
|
||||
case 'array':
|
||||
return unwrapArgs(sender, meta.value)
|
||||
return unwrapArgs(sender, contextId, meta.value)
|
||||
case 'buffer':
|
||||
return Buffer.from(meta.value)
|
||||
case 'date':
|
||||
@@ -203,26 +203,26 @@ const unwrapArgs = function (sender, args) {
|
||||
return returnValue
|
||||
}
|
||||
case 'function': {
|
||||
// Merge webContentsId and meta.id, since meta.id can be the same in
|
||||
// Merge contextId and meta.id, since meta.id can be the same in
|
||||
// different webContents.
|
||||
const webContentsId = sender.getId()
|
||||
const objectId = [webContentsId, meta.id]
|
||||
const objectId = [contextId, meta.id]
|
||||
|
||||
// Cache the callbacks in renderer.
|
||||
if (rendererFunctions.has(objectId)) {
|
||||
return rendererFunctions.get(objectId)
|
||||
}
|
||||
|
||||
const webContentsId = sender.getId()
|
||||
let callIntoRenderer = function (...args) {
|
||||
if (!sender.isDestroyed() && webContentsId === sender.getId()) {
|
||||
sender.send('ELECTRON_RENDERER_CALLBACK', meta.id, valueToMeta(sender, args))
|
||||
sender.send('ELECTRON_RENDERER_CALLBACK', contextId, meta.id, valueToMeta(sender, contextId, args))
|
||||
} else {
|
||||
removeRemoteListenersAndLogWarning(meta, args, callIntoRenderer)
|
||||
}
|
||||
}
|
||||
Object.defineProperty(callIntoRenderer, 'length', { value: meta.length })
|
||||
|
||||
v8Util.setRemoteCallbackFreer(callIntoRenderer, meta.id, sender)
|
||||
v8Util.setRemoteCallbackFreer(callIntoRenderer, contextId, meta.id, sender)
|
||||
rendererFunctions.set(objectId, callIntoRenderer)
|
||||
return callIntoRenderer
|
||||
}
|
||||
@@ -235,19 +235,19 @@ const unwrapArgs = function (sender, args) {
|
||||
|
||||
// Call a function and send reply asynchronously if it's a an asynchronous
|
||||
// style function and the caller didn't pass a callback.
|
||||
const callFunction = function (event, func, caller, args) {
|
||||
const callFunction = function (event, contextId, func, caller, args) {
|
||||
let funcMarkedAsync, funcName, funcPassedCallback, ref, ret
|
||||
funcMarkedAsync = v8Util.getHiddenValue(func, 'asynchronous')
|
||||
funcPassedCallback = typeof args[args.length - 1] === 'function'
|
||||
try {
|
||||
if (funcMarkedAsync && !funcPassedCallback) {
|
||||
args.push(function (ret) {
|
||||
event.returnValue = valueToMeta(event.sender, ret, true)
|
||||
event.returnValue = valueToMeta(event.sender, contextId, ret, true)
|
||||
})
|
||||
func.apply(caller, args)
|
||||
} else {
|
||||
ret = func.apply(caller, args)
|
||||
event.returnValue = valueToMeta(event.sender, ret, true)
|
||||
event.returnValue = valueToMeta(event.sender, contextId, ret, true)
|
||||
}
|
||||
} catch (error) {
|
||||
// Catch functions thrown further down in function invocation and wrap
|
||||
@@ -258,45 +258,45 @@ const callFunction = function (event, func, caller, args) {
|
||||
}
|
||||
}
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_REQUIRE', function (event, module) {
|
||||
ipcMain.on('ELECTRON_BROWSER_REQUIRE', function (event, contextId, module) {
|
||||
try {
|
||||
event.returnValue = valueToMeta(event.sender, process.mainModule.require(module))
|
||||
event.returnValue = valueToMeta(event.sender, contextId, process.mainModule.require(module))
|
||||
} catch (error) {
|
||||
event.returnValue = exceptionToMeta(error)
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_GET_BUILTIN', function (event, module) {
|
||||
ipcMain.on('ELECTRON_BROWSER_GET_BUILTIN', function (event, contextId, module) {
|
||||
try {
|
||||
event.returnValue = valueToMeta(event.sender, electron[module])
|
||||
event.returnValue = valueToMeta(event.sender, contextId, electron[module])
|
||||
} catch (error) {
|
||||
event.returnValue = exceptionToMeta(error)
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_GLOBAL', function (event, name) {
|
||||
ipcMain.on('ELECTRON_BROWSER_GLOBAL', function (event, contextId, name) {
|
||||
try {
|
||||
event.returnValue = valueToMeta(event.sender, global[name])
|
||||
event.returnValue = valueToMeta(event.sender, contextId, global[name])
|
||||
} catch (error) {
|
||||
event.returnValue = exceptionToMeta(error)
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_CURRENT_WINDOW', function (event) {
|
||||
ipcMain.on('ELECTRON_BROWSER_CURRENT_WINDOW', function (event, contextId) {
|
||||
try {
|
||||
event.returnValue = valueToMeta(event.sender, event.sender.getOwnerBrowserWindow())
|
||||
event.returnValue = valueToMeta(event.sender, contextId, event.sender.getOwnerBrowserWindow())
|
||||
} catch (error) {
|
||||
event.returnValue = exceptionToMeta(error)
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_CURRENT_WEB_CONTENTS', function (event) {
|
||||
event.returnValue = valueToMeta(event.sender, event.sender)
|
||||
ipcMain.on('ELECTRON_BROWSER_CURRENT_WEB_CONTENTS', function (event, contextId) {
|
||||
event.returnValue = valueToMeta(event.sender, contextId, event.sender)
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_CONSTRUCTOR', function (event, id, args) {
|
||||
ipcMain.on('ELECTRON_BROWSER_CONSTRUCTOR', function (event, contextId, id, args) {
|
||||
try {
|
||||
args = unwrapArgs(event.sender, args)
|
||||
args = unwrapArgs(event.sender, contextId, args)
|
||||
let constructor = objectsRegistry.get(id)
|
||||
|
||||
if (constructor == null) {
|
||||
@@ -306,30 +306,30 @@ ipcMain.on('ELECTRON_BROWSER_CONSTRUCTOR', function (event, id, args) {
|
||||
// Call new with array of arguments.
|
||||
// http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
|
||||
let obj = new (Function.prototype.bind.apply(constructor, [null].concat(args)))()
|
||||
event.returnValue = valueToMeta(event.sender, obj)
|
||||
event.returnValue = valueToMeta(event.sender, contextId, obj)
|
||||
} catch (error) {
|
||||
event.returnValue = exceptionToMeta(error)
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_FUNCTION_CALL', function (event, id, args) {
|
||||
ipcMain.on('ELECTRON_BROWSER_FUNCTION_CALL', function (event, contextId, id, args) {
|
||||
try {
|
||||
args = unwrapArgs(event.sender, args)
|
||||
args = unwrapArgs(event.sender, contextId, args)
|
||||
let func = objectsRegistry.get(id)
|
||||
|
||||
if (func == null) {
|
||||
throwRPCError(`Cannot call function on missing remote object ${id}`)
|
||||
}
|
||||
|
||||
callFunction(event, func, global, args)
|
||||
callFunction(event, contextId, func, global, args)
|
||||
} catch (error) {
|
||||
event.returnValue = exceptionToMeta(error)
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', function (event, id, method, args) {
|
||||
ipcMain.on('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', function (event, contextId, id, method, args) {
|
||||
try {
|
||||
args = unwrapArgs(event.sender, args)
|
||||
args = unwrapArgs(event.sender, contextId, args)
|
||||
let object = objectsRegistry.get(id)
|
||||
|
||||
if (object == null) {
|
||||
@@ -339,30 +339,30 @@ ipcMain.on('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', function (event, id, method, a
|
||||
// Call new with array of arguments.
|
||||
let constructor = object[method]
|
||||
let obj = new (Function.prototype.bind.apply(constructor, [null].concat(args)))()
|
||||
event.returnValue = valueToMeta(event.sender, obj)
|
||||
event.returnValue = valueToMeta(event.sender, contextId, obj)
|
||||
} catch (error) {
|
||||
event.returnValue = exceptionToMeta(error)
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_MEMBER_CALL', function (event, id, method, args) {
|
||||
ipcMain.on('ELECTRON_BROWSER_MEMBER_CALL', function (event, contextId, id, method, args) {
|
||||
try {
|
||||
args = unwrapArgs(event.sender, args)
|
||||
args = unwrapArgs(event.sender, contextId, args)
|
||||
let obj = objectsRegistry.get(id)
|
||||
|
||||
if (obj == null) {
|
||||
throwRPCError(`Cannot call function '${method}' on missing remote object ${id}`)
|
||||
}
|
||||
|
||||
callFunction(event, obj[method], obj, args)
|
||||
callFunction(event, contextId, obj[method], obj, args)
|
||||
} catch (error) {
|
||||
event.returnValue = exceptionToMeta(error)
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_MEMBER_SET', function (event, id, name, args) {
|
||||
ipcMain.on('ELECTRON_BROWSER_MEMBER_SET', function (event, contextId, id, name, args) {
|
||||
try {
|
||||
args = unwrapArgs(event.sender, args)
|
||||
args = unwrapArgs(event.sender, contextId, args)
|
||||
let obj = objectsRegistry.get(id)
|
||||
|
||||
if (obj == null) {
|
||||
@@ -376,7 +376,7 @@ ipcMain.on('ELECTRON_BROWSER_MEMBER_SET', function (event, id, name, args) {
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_MEMBER_GET', function (event, id, name) {
|
||||
ipcMain.on('ELECTRON_BROWSER_MEMBER_GET', function (event, contextId, id, name) {
|
||||
try {
|
||||
let obj = objectsRegistry.get(id)
|
||||
|
||||
@@ -384,25 +384,25 @@ ipcMain.on('ELECTRON_BROWSER_MEMBER_GET', function (event, id, name) {
|
||||
throwRPCError(`Cannot get property '${name}' on missing remote object ${id}`)
|
||||
}
|
||||
|
||||
event.returnValue = valueToMeta(event.sender, obj[name])
|
||||
event.returnValue = valueToMeta(event.sender, contextId, obj[name])
|
||||
} catch (error) {
|
||||
event.returnValue = exceptionToMeta(error)
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_DEREFERENCE', function (event, id) {
|
||||
objectsRegistry.remove(event.sender.getId(), id)
|
||||
ipcMain.on('ELECTRON_BROWSER_DEREFERENCE', function (event, contextId, id) {
|
||||
objectsRegistry.remove(event.sender, contextId, id)
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_CONTEXT_RELEASE', (e, contextId) => {
|
||||
objectsRegistry.clear(contextId)
|
||||
e.returnValue = null
|
||||
ipcMain.on('ELECTRON_BROWSER_CONTEXT_RELEASE', (event, contextId) => {
|
||||
objectsRegistry.clear(event.sender, contextId)
|
||||
event.returnValue = null
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_GUEST_WEB_CONTENTS', function (event, guestInstanceId) {
|
||||
ipcMain.on('ELECTRON_BROWSER_GUEST_WEB_CONTENTS', function (event, contextId, guestInstanceId) {
|
||||
try {
|
||||
let guestViewManager = require('./guest-view-manager')
|
||||
event.returnValue = valueToMeta(event.sender, guestViewManager.getGuest(guestInstanceId))
|
||||
event.returnValue = valueToMeta(event.sender, contextId, guestViewManager.getGuest(guestInstanceId))
|
||||
} catch (error) {
|
||||
event.returnValue = exceptionToMeta(error)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
const {Buffer} = require('buffer')
|
||||
const childProcess = require('child_process')
|
||||
const path = require('path')
|
||||
const util = require('util')
|
||||
|
||||
const hasProp = {}.hasOwnProperty
|
||||
|
||||
@@ -66,47 +67,40 @@
|
||||
let nextInode = 0
|
||||
|
||||
const uid = process.getuid != null ? process.getuid() : 0
|
||||
|
||||
const gid = process.getgid != null ? process.getgid() : 0
|
||||
|
||||
const fakeTime = new Date()
|
||||
const msec = (date) => (date || fakeTime).getTime()
|
||||
|
||||
const asarStatsToFsStats = function (stats) {
|
||||
return {
|
||||
dev: 1,
|
||||
ino: ++nextInode,
|
||||
mode: 33188,
|
||||
nlink: 1,
|
||||
uid: uid,
|
||||
gid: gid,
|
||||
rdev: 0,
|
||||
atime: stats.atime || fakeTime,
|
||||
birthtime: stats.birthtime || fakeTime,
|
||||
mtime: stats.mtime || fakeTime,
|
||||
ctime: stats.ctime || fakeTime,
|
||||
size: stats.size,
|
||||
isFile: function () {
|
||||
return stats.isFile
|
||||
},
|
||||
isDirectory: function () {
|
||||
return stats.isDirectory
|
||||
},
|
||||
isSymbolicLink: function () {
|
||||
return stats.isLink
|
||||
},
|
||||
isBlockDevice: function () {
|
||||
return false
|
||||
},
|
||||
isCharacterDevice: function () {
|
||||
return false
|
||||
},
|
||||
isFIFO: function () {
|
||||
return false
|
||||
},
|
||||
isSocket: function () {
|
||||
return false
|
||||
}
|
||||
const {Stats, constants} = require('fs')
|
||||
|
||||
let mode = constants.S_IROTH ^ constants.S_IRGRP ^ constants.S_IRUSR ^ constants.S_IWUSR
|
||||
|
||||
if (stats.isFile) {
|
||||
mode ^= constants.S_IFREG
|
||||
} else if (stats.isDirectory) {
|
||||
mode ^= constants.S_IFDIR
|
||||
} else if (stats.isLink) {
|
||||
mode ^= constants.S_IFLNK
|
||||
}
|
||||
|
||||
return new Stats(
|
||||
1, // dev
|
||||
mode, // mode
|
||||
1, // nlink
|
||||
uid,
|
||||
gid,
|
||||
0, // rdev
|
||||
undefined, // blksize
|
||||
++nextInode, // ino
|
||||
stats.size,
|
||||
undefined, // blocks,
|
||||
msec(stats.atime), // atim_msec
|
||||
msec(stats.mtime), // mtim_msec
|
||||
msec(stats.ctime), // ctim_msec
|
||||
msec(stats.birthtime) // birthtim_msec
|
||||
)
|
||||
}
|
||||
|
||||
// Create a ENOENT error.
|
||||
@@ -217,6 +211,28 @@
|
||||
arguments[arg] = newPath
|
||||
return old.apply(this, arguments)
|
||||
}
|
||||
if (old[util.promisify.custom]) {
|
||||
module[name][util.promisify.custom] = function () {
|
||||
const p = arguments[arg]
|
||||
const [isAsar, asarPath, filePath] = splitPath(p)
|
||||
if (!isAsar) {
|
||||
return old[util.promisify.custom].apply(this, arguments)
|
||||
}
|
||||
|
||||
const archive = getOrCreateArchive(asarPath)
|
||||
if (!archive) {
|
||||
return new Promise(() => invalidArchiveError(asarPath))
|
||||
}
|
||||
|
||||
const newPath = archive.copyFileOut(filePath)
|
||||
if (!newPath) {
|
||||
return new Promise(() => notFoundError(asarPath, filePath))
|
||||
}
|
||||
|
||||
arguments[arg] = newPath
|
||||
return old[util.promisify.custom].apply(this, arguments)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Override fs APIs.
|
||||
@@ -373,6 +389,18 @@
|
||||
})
|
||||
}
|
||||
|
||||
fs.exists[util.promisify.custom] = function (p) {
|
||||
const [isAsar, asarPath, filePath] = splitPath(p)
|
||||
if (!isAsar) {
|
||||
return exists[util.promisify.custom](p)
|
||||
}
|
||||
const archive = getOrCreateArchive(asarPath)
|
||||
if (!archive) {
|
||||
return new Promise(() => invalidArchiveError(asarPath))
|
||||
}
|
||||
return Promise.resolve(archive.stat(filePath) !== false)
|
||||
}
|
||||
|
||||
const {existsSync} = fs
|
||||
fs.existsSync = function (p) {
|
||||
const [isAsar, asarPath, filePath] = splitPath(p)
|
||||
@@ -680,18 +708,22 @@
|
||||
// called by `childProcess.{exec,execSync}`, causing
|
||||
// Electron to consider the full command as a single path
|
||||
// to an archive.
|
||||
['exec', 'execSync'].forEach(function (functionName) {
|
||||
const old = childProcess[functionName]
|
||||
childProcess[functionName] = function () {
|
||||
const {exec, execSync} = childProcess
|
||||
childProcess.exec = invokeWithNoAsar(exec)
|
||||
childProcess.exec[util.promisify.custom] = invokeWithNoAsar(exec[util.promisify.custom])
|
||||
childProcess.execSync = invokeWithNoAsar(execSync)
|
||||
|
||||
function invokeWithNoAsar (func) {
|
||||
return function () {
|
||||
const processNoAsarOriginalValue = process.noAsar
|
||||
process.noAsar = true
|
||||
try {
|
||||
return old.apply(this, arguments)
|
||||
return func.apply(this, arguments)
|
||||
} finally {
|
||||
process.noAsar = processNoAsarOriginalValue
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
overrideAPI(fs, 'open')
|
||||
overrideAPI(childProcess, 'execFile')
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const timers = require('timers')
|
||||
const util = require('util')
|
||||
|
||||
process.atomBinding = require('./atom-binding-setup')(process.binding, process.type)
|
||||
|
||||
@@ -8,11 +9,21 @@ process.atomBinding = require('./atom-binding-setup')(process.binding, process.t
|
||||
// which would delay the callbacks for arbitrary long time. So we should
|
||||
// initiatively activate the uv loop once setImmediate and process.nextTick is
|
||||
// called.
|
||||
var wrapWithActivateUvLoop = function (func) {
|
||||
return function () {
|
||||
process.activateUvLoop()
|
||||
return func.apply(this, arguments)
|
||||
const wrapWithActivateUvLoop = function (func) {
|
||||
return wrap(func, function (func) {
|
||||
return function () {
|
||||
process.activateUvLoop()
|
||||
return func.apply(this, arguments)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function wrap (func, wrapper) {
|
||||
const wrapped = wrapper(func)
|
||||
if (func[util.promisify.custom]) {
|
||||
wrapped[util.promisify.custom] = wrapper(func[util.promisify.custom])
|
||||
}
|
||||
return wrapped
|
||||
}
|
||||
|
||||
process.nextTick = wrapWithActivateUvLoop(process.nextTick)
|
||||
|
||||
@@ -11,6 +11,18 @@ const resolvePromise = Promise.resolve.bind(Promise)
|
||||
const callbacksRegistry = new CallbacksRegistry()
|
||||
const remoteObjectCache = v8Util.createIDWeakMap()
|
||||
|
||||
// An unique ID that can represent current context.
|
||||
const contextId = v8Util.getHiddenValue(global, 'contextId')
|
||||
|
||||
// Notify the main process when current context is going to be released.
|
||||
// Note that when the renderer process is destroyed, the message may not be
|
||||
// sent, we also listen to the "render-view-deleted" event in the main process
|
||||
// to guard that situation.
|
||||
process.on('exit', () => {
|
||||
const command = 'ELECTRON_BROWSER_CONTEXT_RELEASE'
|
||||
ipcRenderer.sendSync(command, contextId)
|
||||
})
|
||||
|
||||
// Convert the arguments object into an array of meta data.
|
||||
function wrapArgs (args, visited = new Set()) {
|
||||
const valueToMeta = (value) => {
|
||||
@@ -109,7 +121,7 @@ function setObjectMembers (ref, object, metaId, members) {
|
||||
} else {
|
||||
command = 'ELECTRON_BROWSER_MEMBER_CALL'
|
||||
}
|
||||
const ret = ipcRenderer.sendSync(command, metaId, member.name, wrapArgs(args))
|
||||
const ret = ipcRenderer.sendSync(command, contextId, metaId, member.name, wrapArgs(args))
|
||||
return metaToValue(ret)
|
||||
}
|
||||
|
||||
@@ -128,7 +140,7 @@ function setObjectMembers (ref, object, metaId, members) {
|
||||
} else if (member.type === 'get') {
|
||||
descriptor.get = () => {
|
||||
const command = 'ELECTRON_BROWSER_MEMBER_GET'
|
||||
const meta = ipcRenderer.sendSync(command, metaId, member.name)
|
||||
const meta = ipcRenderer.sendSync(command, contextId, metaId, member.name)
|
||||
return metaToValue(meta)
|
||||
}
|
||||
|
||||
@@ -136,7 +148,7 @@ function setObjectMembers (ref, object, metaId, members) {
|
||||
descriptor.set = (value) => {
|
||||
const args = wrapArgs([value])
|
||||
const command = 'ELECTRON_BROWSER_MEMBER_SET'
|
||||
const meta = ipcRenderer.sendSync(command, metaId, member.name, args)
|
||||
const meta = ipcRenderer.sendSync(command, contextId, metaId, member.name, args)
|
||||
if (meta != null) metaToValue(meta)
|
||||
return value
|
||||
}
|
||||
@@ -166,7 +178,7 @@ function proxyFunctionProperties (remoteMemberFunction, metaId, name) {
|
||||
if (loaded) return
|
||||
loaded = true
|
||||
const command = 'ELECTRON_BROWSER_MEMBER_GET'
|
||||
const meta = ipcRenderer.sendSync(command, metaId, name)
|
||||
const meta = ipcRenderer.sendSync(command, contextId, metaId, name)
|
||||
setObjectMembers(remoteMemberFunction, remoteMemberFunction, meta.id, meta.members)
|
||||
}
|
||||
|
||||
@@ -226,7 +238,7 @@ function metaToValue (meta) {
|
||||
} else {
|
||||
command = 'ELECTRON_BROWSER_FUNCTION_CALL'
|
||||
}
|
||||
const obj = ipcRenderer.sendSync(command, meta.id, wrapArgs(args))
|
||||
const obj = ipcRenderer.sendSync(command, contextId, meta.id, wrapArgs(args))
|
||||
return metaToValue(obj)
|
||||
}
|
||||
ret = remoteFunction
|
||||
@@ -239,7 +251,7 @@ function metaToValue (meta) {
|
||||
Object.defineProperty(ret.constructor, 'name', { value: meta.name })
|
||||
|
||||
// Track delegate obj's lifetime & tell browser to clean up when object is GCed.
|
||||
v8Util.setRemoteObjectFreer(ret, meta.id)
|
||||
v8Util.setRemoteObjectFreer(ret, contextId, meta.id)
|
||||
v8Util.setHiddenValue(ret, 'atomId', meta.id)
|
||||
remoteObjectCache.set(meta.id, ret)
|
||||
return ret
|
||||
@@ -257,57 +269,51 @@ function metaToPlainObject (meta) {
|
||||
}
|
||||
|
||||
// Browser calls a callback in renderer.
|
||||
ipcRenderer.on('ELECTRON_RENDERER_CALLBACK', (event, id, args) => {
|
||||
ipcRenderer.on('ELECTRON_RENDERER_CALLBACK', (event, passedContextId, id, args) => {
|
||||
if (passedContextId !== contextId) {
|
||||
// The invoked callback belongs to an old page in this renderer.
|
||||
return
|
||||
}
|
||||
callbacksRegistry.apply(id, metaToValue(args))
|
||||
})
|
||||
|
||||
// A callback in browser is released.
|
||||
ipcRenderer.on('ELECTRON_RENDERER_RELEASE_CALLBACK', (event, id) => {
|
||||
ipcRenderer.on('ELECTRON_RENDERER_RELEASE_CALLBACK', (event, passedContextId, id) => {
|
||||
if (passedContextId !== contextId) {
|
||||
// The freed callback belongs to an old page in this renderer.
|
||||
return
|
||||
}
|
||||
callbacksRegistry.remove(id)
|
||||
})
|
||||
|
||||
process.on('exit', () => {
|
||||
const command = 'ELECTRON_BROWSER_CONTEXT_RELEASE'
|
||||
ipcRenderer.sendSync(command, initialContext)
|
||||
})
|
||||
|
||||
exports.require = (module) => {
|
||||
const command = 'ELECTRON_BROWSER_REQUIRE'
|
||||
const meta = ipcRenderer.sendSync(command, module)
|
||||
const meta = ipcRenderer.sendSync(command, contextId, module)
|
||||
return metaToValue(meta)
|
||||
}
|
||||
|
||||
// Alias to remote.require('electron').xxx.
|
||||
exports.getBuiltin = (module) => {
|
||||
const command = 'ELECTRON_BROWSER_GET_BUILTIN'
|
||||
const meta = ipcRenderer.sendSync(command, module)
|
||||
const meta = ipcRenderer.sendSync(command, contextId, module)
|
||||
return metaToValue(meta)
|
||||
}
|
||||
|
||||
exports.getCurrentWindow = () => {
|
||||
const command = 'ELECTRON_BROWSER_CURRENT_WINDOW'
|
||||
const meta = ipcRenderer.sendSync(command)
|
||||
const meta = ipcRenderer.sendSync(command, contextId)
|
||||
return metaToValue(meta)
|
||||
}
|
||||
|
||||
// Get current WebContents object.
|
||||
exports.getCurrentWebContents = () => {
|
||||
return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_CURRENT_WEB_CONTENTS'))
|
||||
}
|
||||
|
||||
const CONTEXT_ARG = '--context-id='
|
||||
let initialContext = process.argv.find(arg => arg.startsWith(CONTEXT_ARG))
|
||||
if (initialContext) {
|
||||
initialContext = parseInt(initialContext.substr(CONTEXT_ARG.length), 10)
|
||||
} else {
|
||||
// In sandbox we need to pull this from remote
|
||||
initialContext = exports.getCurrentWebContents().getId()
|
||||
return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_CURRENT_WEB_CONTENTS', contextId))
|
||||
}
|
||||
|
||||
// Get a global object in browser.
|
||||
exports.getGlobal = (name) => {
|
||||
const command = 'ELECTRON_BROWSER_GLOBAL'
|
||||
const meta = ipcRenderer.sendSync(command, name)
|
||||
const meta = ipcRenderer.sendSync(command, contextId, name)
|
||||
return metaToValue(meta)
|
||||
}
|
||||
|
||||
@@ -324,7 +330,7 @@ exports.createFunctionWithReturnValue = (returnValue) => {
|
||||
// Get the guest WebContents from guestInstanceId.
|
||||
exports.getGuestWebContents = (guestInstanceId) => {
|
||||
const command = 'ELECTRON_BROWSER_GUEST_WEB_CONTENTS'
|
||||
const meta = ipcRenderer.sendSync(command, guestInstanceId)
|
||||
const meta = ipcRenderer.sendSync(command, contextId, guestInstanceId)
|
||||
return metaToValue(meta)
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,12 @@ const runContentScript = function (extensionId, url, code) {
|
||||
return compiledWrapper.call(this, context.chrome)
|
||||
}
|
||||
|
||||
const runAllContentScript = function (scripts, extensionId) {
|
||||
for (const {url, code} of scripts) {
|
||||
runContentScript.call(window, extensionId, url, code)
|
||||
}
|
||||
}
|
||||
|
||||
const runStylesheet = function (url, code) {
|
||||
const wrapper = `((code) => {
|
||||
function init() {
|
||||
@@ -40,34 +46,36 @@ const runStylesheet = function (url, code) {
|
||||
return compiledWrapper.call(this, code)
|
||||
}
|
||||
|
||||
const runAllStylesheet = function (css) {
|
||||
for (const {url, code} of css) {
|
||||
runStylesheet.call(window, url, code)
|
||||
}
|
||||
}
|
||||
|
||||
// Run injected scripts.
|
||||
// https://developer.chrome.com/extensions/content_scripts
|
||||
const injectContentScript = function (extensionId, script) {
|
||||
if (!script.matches.some(matchesPattern)) return
|
||||
|
||||
if (script.js) {
|
||||
for (const {url, code} of script.js) {
|
||||
const fire = runContentScript.bind(window, extensionId, url, code)
|
||||
if (script.runAt === 'document_start') {
|
||||
process.once('document-start', fire)
|
||||
} else if (script.runAt === 'document_end') {
|
||||
process.once('document-end', fire)
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', fire)
|
||||
}
|
||||
const fire = runAllContentScript.bind(window, script.js, extensionId)
|
||||
if (script.runAt === 'document_start') {
|
||||
process.once('document-start', fire)
|
||||
} else if (script.runAt === 'document_end') {
|
||||
process.once('document-end', fire)
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', fire)
|
||||
}
|
||||
}
|
||||
|
||||
if (script.css) {
|
||||
for (const {url, code} of script.css) {
|
||||
const fire = runStylesheet.bind(window, url, code)
|
||||
if (script.runAt === 'document_start') {
|
||||
process.once('document-start', fire)
|
||||
} else if (script.runAt === 'document_end') {
|
||||
process.once('document-end', fire)
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', fire)
|
||||
}
|
||||
const fire = runAllStylesheet.bind(window, script.css)
|
||||
if (script.runAt === 'document_start') {
|
||||
process.once('document-start', fire)
|
||||
} else if (script.runAt === 'document_end') {
|
||||
process.once('document-end', fire)
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', fire)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
const events = require('events')
|
||||
const path = require('path')
|
||||
const Module = require('module')
|
||||
const resolvePromise = Promise.resolve.bind(Promise)
|
||||
|
||||
// We modified the original process.argv to let node.js load the
|
||||
// init.js, we need to restore it here.
|
||||
@@ -26,7 +25,6 @@ var v8Util = process.atomBinding('v8_util')
|
||||
v8Util.setHiddenValue(global, 'ipc', new events.EventEmitter())
|
||||
|
||||
// Use electron module after everything is ready.
|
||||
const electron = require('electron')
|
||||
|
||||
const {
|
||||
warnAboutNodeWithRemoteContent,
|
||||
@@ -40,40 +38,7 @@ const {
|
||||
shouldLogSecurityWarnings
|
||||
} = require('./security-warnings')
|
||||
|
||||
// Call webFrame method.
|
||||
electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', (event, method, args) => {
|
||||
electron.webFrame[method](...args)
|
||||
})
|
||||
|
||||
electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_SYNC_WEB_FRAME_METHOD', (event, requestId, method, args) => {
|
||||
const result = electron.webFrame[method](...args)
|
||||
event.sender.send(`ELECTRON_INTERNAL_BROWSER_SYNC_WEB_FRAME_RESPONSE_${requestId}`, result)
|
||||
})
|
||||
|
||||
electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', (event, requestId, method, args) => {
|
||||
const responseCallback = function (result) {
|
||||
resolvePromise(result)
|
||||
.then((resolvedResult) => {
|
||||
event.sender.send(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, null, resolvedResult)
|
||||
})
|
||||
.catch((resolvedError) => {
|
||||
if (resolvedError instanceof Error) {
|
||||
// Errors get lost, because: JSON.stringify(new Error('Message')) === {}
|
||||
// Take the serializable properties and construct a generic object
|
||||
resolvedError = {
|
||||
message: resolvedError.message,
|
||||
stack: resolvedError.stack,
|
||||
name: resolvedError.name,
|
||||
__ELECTRON_SERIALIZED_ERROR__: true
|
||||
}
|
||||
}
|
||||
|
||||
event.sender.send(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, resolvedError)
|
||||
})
|
||||
}
|
||||
args.push(responseCallback)
|
||||
electron.webFrame[method](...args)
|
||||
})
|
||||
require('./web-frame-init')()
|
||||
|
||||
// Process command line arguments.
|
||||
let nodeIntegration = 'false'
|
||||
|
||||
38
lib/renderer/web-frame-init.js
Normal file
38
lib/renderer/web-frame-init.js
Normal file
@@ -0,0 +1,38 @@
|
||||
const electron = require('electron')
|
||||
|
||||
module.exports = () => {
|
||||
// Call webFrame method
|
||||
electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', (event, method, args) => {
|
||||
electron.webFrame[method](...args)
|
||||
})
|
||||
|
||||
electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_SYNC_WEB_FRAME_METHOD', (event, requestId, method, args) => {
|
||||
const result = electron.webFrame[method](...args)
|
||||
event.sender.send(`ELECTRON_INTERNAL_BROWSER_SYNC_WEB_FRAME_RESPONSE_${requestId}`, result)
|
||||
})
|
||||
|
||||
electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', (event, requestId, method, args) => {
|
||||
const responseCallback = function (result) {
|
||||
Promise.resolve(result)
|
||||
.then((resolvedResult) => {
|
||||
event.sender.send(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, null, resolvedResult)
|
||||
})
|
||||
.catch((resolvedError) => {
|
||||
if (resolvedError instanceof Error) {
|
||||
// Errors get lost, because: JSON.stringify(new Error('Message')) === {}
|
||||
// Take the serializable properties and construct a generic object
|
||||
resolvedError = {
|
||||
message: resolvedError.message,
|
||||
stack: resolvedError.stack,
|
||||
name: resolvedError.name,
|
||||
__ELECTRON_SERIALIZED_ERROR__: true
|
||||
}
|
||||
}
|
||||
|
||||
event.sender.send(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, resolvedError)
|
||||
})
|
||||
}
|
||||
args.push(responseCallback)
|
||||
electron.webFrame[method](...args)
|
||||
})
|
||||
}
|
||||
@@ -100,6 +100,9 @@ module.exports = {
|
||||
ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', params, requestId)
|
||||
ipcRenderer.once(`ELECTRON_RESPONSE_${requestId}`, callback)
|
||||
},
|
||||
createGuestSync: function (params) {
|
||||
return ipcRenderer.sendSync('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST_SYNC', params)
|
||||
},
|
||||
attachGuest: function (elementInstanceId, guestInstanceId, params) {
|
||||
ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', elementInstanceId, guestInstanceId, params)
|
||||
webFrame.attachGuest(elementInstanceId)
|
||||
|
||||
@@ -230,7 +230,7 @@ class SrcAttribute extends WebViewAttribute {
|
||||
}
|
||||
|
||||
parse () {
|
||||
if (!this.webViewImpl.elementAttached || !this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId) {
|
||||
if (!this.webViewImpl.elementAttached || !this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId || !this.getValue()) {
|
||||
return
|
||||
}
|
||||
if (this.webViewImpl.guestInstanceId == null) {
|
||||
@@ -240,9 +240,6 @@ class SrcAttribute extends WebViewAttribute {
|
||||
}
|
||||
return
|
||||
}
|
||||
if (!this.getValue()) {
|
||||
return
|
||||
}
|
||||
|
||||
// Navigate to |this.src|.
|
||||
const opts = {}
|
||||
|
||||
@@ -145,9 +145,7 @@ class WebViewImpl {
|
||||
|
||||
onElementResize (newSize) {
|
||||
// Dispatch the 'resize' event.
|
||||
const resizeEvent = new Event('resize', {
|
||||
bubbles: true
|
||||
})
|
||||
const resizeEvent = new Event('resize')
|
||||
|
||||
// Using client size values, because when a webview is transformed `newSize`
|
||||
// is incorrect
|
||||
@@ -171,6 +169,10 @@ class WebViewImpl {
|
||||
})
|
||||
}
|
||||
|
||||
createGuestSync () {
|
||||
this.attachGuestInstance(guestViewInternal.createGuestSync(this.buildParams()))
|
||||
}
|
||||
|
||||
dispatchEvent (webViewEvent) {
|
||||
this.webviewNode.dispatchEvent(webViewEvent)
|
||||
}
|
||||
@@ -418,7 +420,11 @@ const registerWebViewElement = function () {
|
||||
|
||||
// WebContents associated with this webview.
|
||||
proto.getWebContents = function () {
|
||||
return v8Util.getHiddenValue(this, 'internal').webContents
|
||||
const internal = v8Util.getHiddenValue(this, 'internal')
|
||||
if (!internal.webContents) {
|
||||
internal.createGuestSync()
|
||||
}
|
||||
return internal.webContents
|
||||
}
|
||||
|
||||
window.WebView = webFrame.registerEmbedderCustomElement('webview', {
|
||||
|
||||
@@ -32,7 +32,7 @@ const preloadModules = new Map([
|
||||
['timers', require('timers')]
|
||||
])
|
||||
|
||||
const preloadSrc = fs.readFileSync(preloadPath).toString()
|
||||
require('../renderer/web-frame-init')()
|
||||
|
||||
// Pass different process object to the preload script(which should not have
|
||||
// access to things like `process.atomBinding`).
|
||||
@@ -54,6 +54,11 @@ function preloadRequire (module) {
|
||||
throw new Error('module not found')
|
||||
}
|
||||
|
||||
if (window.location.protocol === 'chrome-devtools:') {
|
||||
// Override some inspector APIs.
|
||||
require('../renderer/inspector')
|
||||
}
|
||||
|
||||
// Wrap the script into a function executed in global scope. It won't have
|
||||
// access to the current scope, so we'll expose a few objects as arguments:
|
||||
//
|
||||
@@ -73,13 +78,16 @@ function preloadRequire (module) {
|
||||
// and any `require('electron')` calls in `preload.js` will work as expected
|
||||
// since browserify won't try to include `electron` in the bundle, falling back
|
||||
// to the `preloadRequire` function above.
|
||||
const preloadWrapperSrc = `(function(require, process, Buffer, global, setImmediate) {
|
||||
${preloadSrc}
|
||||
})`
|
||||
if (preloadPath) {
|
||||
const preloadSrc = fs.readFileSync(preloadPath).toString()
|
||||
const preloadWrapperSrc = `(function(require, process, Buffer, global, setImmediate) {
|
||||
${preloadSrc}
|
||||
})`
|
||||
|
||||
// eval in window scope:
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.2
|
||||
const geval = eval
|
||||
const preloadFn = geval(preloadWrapperSrc)
|
||||
const {setImmediate} = require('timers')
|
||||
preloadFn(preloadRequire, preloadProcess, Buffer, global, setImmediate)
|
||||
// eval in window scope:
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.2
|
||||
const geval = eval
|
||||
const preloadFn = geval(preloadWrapperSrc)
|
||||
const {setImmediate} = require('timers')
|
||||
preloadFn(preloadRequire, preloadProcess, Buffer, global, setImmediate)
|
||||
}
|
||||
|
||||
11
npm/cli.js
11
npm/cli.js
@@ -8,3 +8,14 @@ var child = proc.spawn(electron, process.argv.slice(2), {stdio: 'inherit'})
|
||||
child.on('close', function (code) {
|
||||
process.exit(code)
|
||||
})
|
||||
|
||||
const handleTerminationSignal = function (signal) {
|
||||
process.on(signal, function signalHandler () {
|
||||
if (!child.killed) {
|
||||
child.kill(signal)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
handleTerminationSignal('SIGINT')
|
||||
handleTerminationSignal('SIGTERM')
|
||||
|
||||
@@ -21,6 +21,12 @@ if (installedVersion === version && fs.existsSync(path.join(__dirname, platformP
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
var mirror
|
||||
|
||||
if (version.indexOf('nightly') !== -1) {
|
||||
mirror = 'https://github.com/electron/nightlies/releases/download/v'
|
||||
}
|
||||
|
||||
// downloads if not cached
|
||||
download({
|
||||
cache: process.env.electron_config_cache,
|
||||
@@ -29,7 +35,8 @@ download({
|
||||
arch: process.env.npm_config_arch,
|
||||
strictSSL: process.env.npm_config_strict_ssl === 'true',
|
||||
force: process.env.force_no_cache === 'true',
|
||||
quiet: process.env.npm_config_loglevel === 'silent' || process.env.CI
|
||||
quiet: process.env.npm_config_loglevel === 'silent' || process.env.CI,
|
||||
mirror
|
||||
}, extractFile)
|
||||
|
||||
// unzips and makes path.txt point at the correct executable
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "2.0.0-beta.5",
|
||||
"version": "2.0.11",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
@@ -12,7 +12,7 @@
|
||||
"dugite": "^1.45.0",
|
||||
"electabul": "~0.0.4",
|
||||
"electron-docs-linter": "^2.3.4",
|
||||
"electron-typescript-definitions": "^1.3.2",
|
||||
"electron-typescript-definitions": "1.3.2",
|
||||
"github": "^9.2.0",
|
||||
"husky": "^0.14.3",
|
||||
"minimist": "^1.2.0",
|
||||
|
||||
@@ -40,6 +40,9 @@ def main():
|
||||
if args.target_arch == 'mips64el':
|
||||
download_mips64el_toolchain()
|
||||
|
||||
if args.target_arch.startswith('arm'):
|
||||
download_native_mksnapshot(args.target_arch)
|
||||
|
||||
# Redirect to use local libchromiumcontent build.
|
||||
if args.build_release_libcc or args.build_debug_libcc:
|
||||
build_libchromiumcontent(args.verbose, args.target_arch, defines,
|
||||
@@ -110,6 +113,8 @@ def parse_args():
|
||||
help='The static library path of libchromiumcontent.')
|
||||
parser.add_argument('--defines', default='',
|
||||
help='The build variables passed to gyp')
|
||||
parser.add_argument('--cc_wrapper',
|
||||
help='Sets cc_wrapper for build. E.g. $(which sccache)')
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
@@ -120,6 +125,8 @@ def args_to_defines(args):
|
||||
if args.clang_dir:
|
||||
defines += ' make_clang_dir=' + args.clang_dir
|
||||
defines += ' clang_use_chrome_plugins=0'
|
||||
if args.cc_wrapper is not None:
|
||||
defines += ' cc_wrapper=' + args.cc_wrapper
|
||||
return defines
|
||||
|
||||
|
||||
@@ -218,6 +225,15 @@ def download_mips64el_toolchain():
|
||||
subprocess.check_call(['tar', '-xf', tar_name, '-C', VENDOR_DIR])
|
||||
os.remove(tar_name)
|
||||
|
||||
def download_native_mksnapshot(arch):
|
||||
if not os.path.exists(os.path.join(VENDOR_DIR,
|
||||
'native_mksnapshot')):
|
||||
tar_name = 'native-mksnapshot.tar.bz2'
|
||||
url = '{0}/linux/{1}/{2}/{3}'.format(BASE_URL, arch,
|
||||
get_libchromiumcontent_commit(), tar_name)
|
||||
download(tar_name, url, os.path.join(SOURCE_ROOT, tar_name))
|
||||
subprocess.call(['tar', '-jxf', tar_name, '-C', VENDOR_DIR])
|
||||
os.remove(tar_name)
|
||||
|
||||
def create_chrome_version_h():
|
||||
version_file = os.path.join(VENDOR_DIR, 'libchromiumcontent', 'VERSION')
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user