mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
344 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30ec7fdeed | ||
|
|
0e3e1be85c | ||
|
|
df9ea104c2 | ||
|
|
88b05cff3e | ||
|
|
fae2c7bc7a | ||
|
|
96130dd4c2 | ||
|
|
79e593aca6 | ||
|
|
aeafc46ded | ||
|
|
f89d28a63e | ||
|
|
d74ef5c078 | ||
|
|
85c84a0eb0 | ||
|
|
a3f62da615 | ||
|
|
95fe4beda8 | ||
|
|
d5c964c68c | ||
|
|
07adbc8e8a | ||
|
|
90e3f726e4 | ||
|
|
83ef23ff8d | ||
|
|
e36d455d51 | ||
|
|
4a6134f3f7 | ||
|
|
6182e4ce81 | ||
|
|
79d4d52172 | ||
|
|
e3ce1b50ec | ||
|
|
e9a5d05b27 | ||
|
|
61f07307cb | ||
|
|
6bfe06ec4e | ||
|
|
7b5a1b06ba | ||
|
|
d52ef50b01 | ||
|
|
93a3a946f3 | ||
|
|
afc1fff792 | ||
|
|
70e74d05e0 | ||
|
|
f9d797d1ea | ||
|
|
e14fd62f46 | ||
|
|
ca876e424b | ||
|
|
230f2760e7 | ||
|
|
f01e84a418 | ||
|
|
05c6300329 | ||
|
|
bcb78ebc00 | ||
|
|
310954713f | ||
|
|
acb2c099f6 | ||
|
|
63cc2ec369 | ||
|
|
04d3eed60e | ||
|
|
f7840e7379 | ||
|
|
15e0248d82 | ||
|
|
9411508d3e | ||
|
|
f5659cd9a9 | ||
|
|
803b3c8d5b | ||
|
|
bac3d2e372 | ||
|
|
759b6a1534 | ||
|
|
de66888051 | ||
|
|
d020a7dc86 | ||
|
|
938d68eb36 | ||
|
|
b61c2e6ff7 | ||
|
|
658a9872fb | ||
|
|
a160891a27 | ||
|
|
38d6ff79c8 | ||
|
|
73f4aa1113 | ||
|
|
444f461269 | ||
|
|
2d410ede48 | ||
|
|
ed9579a2f7 | ||
|
|
567d8e7434 | ||
|
|
d092c6acc9 | ||
|
|
99c496471b | ||
|
|
e5094fff3e | ||
|
|
fe25f3e747 | ||
|
|
b6859cab91 | ||
|
|
26d922d18d | ||
|
|
15f00db1bf | ||
|
|
4a7a09aae1 | ||
|
|
f759471e01 | ||
|
|
4bc54ac5e3 | ||
|
|
5886398f22 | ||
|
|
7491d5cfb5 | ||
|
|
b6f1729acd | ||
|
|
5d4c29a1e3 | ||
|
|
a2eedcc027 | ||
|
|
63417bc975 | ||
|
|
4a4b829cfc | ||
|
|
50fab0733b | ||
|
|
b02f89e63b | ||
|
|
cdd51fa96d | ||
|
|
c38f2fcf75 | ||
|
|
7491ae4000 | ||
|
|
4d5495a0a0 | ||
|
|
717aba9631 | ||
|
|
8288a22458 | ||
|
|
88dd1480cc | ||
|
|
c46579b1ac | ||
|
|
1b3363c811 | ||
|
|
daa65a138b | ||
|
|
d3b23a2032 | ||
|
|
05b22b9372 | ||
|
|
ff2d9759d5 | ||
|
|
90b997ef08 | ||
|
|
27fa5d880a | ||
|
|
285a4789b3 | ||
|
|
da7161d5a7 | ||
|
|
db3bc28937 | ||
|
|
a0e2af6fac | ||
|
|
1ad979f9bd | ||
|
|
f7a9b02c63 | ||
|
|
7a0db35d91 | ||
|
|
c928894627 | ||
|
|
a7a399dcd8 | ||
|
|
14e2bbe4c7 | ||
|
|
370cb5b5e1 | ||
|
|
78261973fb | ||
|
|
be36a17dbf | ||
|
|
fb8ca33d5d | ||
|
|
2c4a24d26b | ||
|
|
4005e65e28 | ||
|
|
86327fb4bb | ||
|
|
5a46147e9b | ||
|
|
bb8bb3dbea | ||
|
|
d09b09b744 | ||
|
|
bc7c7da799 | ||
|
|
9f8479e9d8 | ||
|
|
e3535d664b | ||
|
|
b3c7e2bf33 | ||
|
|
489090fcf8 | ||
|
|
0afefe13f6 | ||
|
|
7f15d63552 | ||
|
|
09ee24514e | ||
|
|
d9c7401d0b | ||
|
|
de3e16ce60 | ||
|
|
72e0da069c | ||
|
|
0d9e0a38c0 | ||
|
|
810af2f95d | ||
|
|
0aefa98e5a | ||
|
|
0e50b00fdf | ||
|
|
60b14d03e9 | ||
|
|
49d25d0069 | ||
|
|
82e6058607 | ||
|
|
c46ed897dd | ||
|
|
c7d9352972 | ||
|
|
cd2f924db8 | ||
|
|
b958982d99 | ||
|
|
a3fc25110e | ||
|
|
5ae6bd2ef4 | ||
|
|
7ac643d5f8 | ||
|
|
5e7a30deea | ||
|
|
72078f7b02 | ||
|
|
b5478eaef7 | ||
|
|
1ae4be7571 | ||
|
|
32523ae352 | ||
|
|
c0ee8f4e60 | ||
|
|
edd6032ed0 | ||
|
|
f05fc3c0ea | ||
|
|
f0825bf7ef | ||
|
|
d9fdfb711f | ||
|
|
94f64c755d | ||
|
|
4871ea715c | ||
|
|
115bb31ab4 | ||
|
|
2725068a0c | ||
|
|
5e5caf2e86 | ||
|
|
22e9c2f4eb | ||
|
|
c371c713a9 | ||
|
|
776077c8de | ||
|
|
16b9f8995d | ||
|
|
18fd126c64 | ||
|
|
7bdbe45c91 | ||
|
|
fb99e72484 | ||
|
|
0e94ccb72b | ||
|
|
aeb24b784d | ||
|
|
125444df15 | ||
|
|
facd0fbc08 | ||
|
|
3dba56c335 | ||
|
|
89527ec232 | ||
|
|
904f3c2564 | ||
|
|
d2b3d6d129 | ||
|
|
909779babf | ||
|
|
f5c25d6277 | ||
|
|
d90b598125 | ||
|
|
55d5660ddb | ||
|
|
11a49bba35 | ||
|
|
6aec8b092c | ||
|
|
f52c4af605 | ||
|
|
b61baacfe1 | ||
|
|
79311af8eb | ||
|
|
7a6ef0ec6e | ||
|
|
4270eba438 | ||
|
|
d14b59c754 | ||
|
|
95c4847d60 | ||
|
|
74d389b2b0 | ||
|
|
eb344f3f04 | ||
|
|
b47076231c | ||
|
|
51335934c1 | ||
|
|
d6842751bb | ||
|
|
96c15f19e3 | ||
|
|
9e51ff2b4b | ||
|
|
48faf74f7f | ||
|
|
df7a9b80b1 | ||
|
|
3afc9c4ebe | ||
|
|
7b57a945f8 | ||
|
|
b62e3554dc | ||
|
|
a9f5667899 | ||
|
|
644af0800c | ||
|
|
699dafc5db | ||
|
|
d152b25fb6 | ||
|
|
af8049941e | ||
|
|
d9a4a41293 | ||
|
|
ddea2fced4 | ||
|
|
34d49441b1 | ||
|
|
b9b25180f8 | ||
|
|
b9d838975d | ||
|
|
5ff97c686a | ||
|
|
460adfa1bc | ||
|
|
ff9846da48 | ||
|
|
9de9d2ecc1 | ||
|
|
799748cc5d | ||
|
|
ab1f39589a | ||
|
|
9419a2ec2c | ||
|
|
c58ca76cac | ||
|
|
36bbf5d51f | ||
|
|
8012792457 | ||
|
|
2820fa8fd4 | ||
|
|
bd95be23f3 | ||
|
|
6ec184a2ce | ||
|
|
cb903a09c0 | ||
|
|
4e8db2c3be | ||
|
|
692816f9d2 | ||
|
|
0cd1195eea | ||
|
|
71fdb91f5c | ||
|
|
6d20d37101 | ||
|
|
df12f181a4 | ||
|
|
be5f1b09f4 | ||
|
|
b5b6e30c8b | ||
|
|
ccd17f060d | ||
|
|
c71efc8ca5 | ||
|
|
8278ee533d | ||
|
|
b6cfa6f967 | ||
|
|
1896deb10e | ||
|
|
095b2e6047 | ||
|
|
e682dc7544 | ||
|
|
4392f1d77c | ||
|
|
288572f08e | ||
|
|
6cbbce544f | ||
|
|
8127bbc992 | ||
|
|
9fd46ac4db | ||
|
|
1e13159157 | ||
|
|
215ca78c7f | ||
|
|
0404cc850b | ||
|
|
fb5260eb30 | ||
|
|
28b3678159 | ||
|
|
965471d9f8 | ||
|
|
d7c67d795b | ||
|
|
841407a619 | ||
|
|
1759a71814 | ||
|
|
d61bec0fb8 | ||
|
|
442db4c5ba | ||
|
|
922fce1892 | ||
|
|
38b27bbd66 | ||
|
|
6bc59cf2d7 | ||
|
|
957de56343 | ||
|
|
1a2b5834ed | ||
|
|
59b43a6571 | ||
|
|
1a55cd3efe | ||
|
|
c8122392de | ||
|
|
8b7d2b5ce3 | ||
|
|
d9c6cf7b75 | ||
|
|
e1318ffb34 | ||
|
|
7756bb6762 | ||
|
|
d9cf9a7cbc | ||
|
|
87faae1b13 | ||
|
|
051548aa69 | ||
|
|
9dd714f056 | ||
|
|
fe4d86925b | ||
|
|
617892400f | ||
|
|
73ab6d409b | ||
|
|
55715bec23 | ||
|
|
115526424a | ||
|
|
aebc1d0650 | ||
|
|
c7dc901607 | ||
|
|
b1ae60a639 | ||
|
|
7e7b6df72b | ||
|
|
05f0b5a8a4 | ||
|
|
2978beaeb7 | ||
|
|
6f61832a34 | ||
|
|
63c1fdd22a | ||
|
|
3966441d21 | ||
|
|
579f253340 | ||
|
|
821005e6b4 | ||
|
|
871571c65e | ||
|
|
326af3cbe3 | ||
|
|
4c3fd38774 | ||
|
|
74be1d5b25 | ||
|
|
cab466f999 | ||
|
|
4cb3e2ecb5 | ||
|
|
cb22b88e6a | ||
|
|
5bdc077b48 | ||
|
|
927c3f34c3 | ||
|
|
c916baa939 | ||
|
|
3a97439fe9 | ||
|
|
c6d5a92d34 | ||
|
|
2d802d6f1e | ||
|
|
fa59ea3bc5 | ||
|
|
804cf5e8ba | ||
|
|
fc0153f0bc | ||
|
|
c823e31904 | ||
|
|
2ef66cb660 | ||
|
|
f607e81fac | ||
|
|
e06778178a | ||
|
|
f6327de7f7 | ||
|
|
8e40947938 | ||
|
|
898db4d6bd | ||
|
|
6fea6cf58a | ||
|
|
428c5b6d01 | ||
|
|
3f37439da3 | ||
|
|
db46c1b925 | ||
|
|
c3cd438d34 | ||
|
|
ccf4ed907a | ||
|
|
b70e7c6a4c | ||
|
|
4d302956d3 | ||
|
|
c8723238f8 | ||
|
|
60fb406c61 | ||
|
|
bb49515145 | ||
|
|
87e0c812e9 | ||
|
|
ea3e84e7ff | ||
|
|
239b97cde1 | ||
|
|
c22ffd863b | ||
|
|
857acd2574 | ||
|
|
3b1ee994e2 | ||
|
|
e675407552 | ||
|
|
d19ead1907 | ||
|
|
a9b0111c3e | ||
|
|
279407f7a3 | ||
|
|
a76ea00249 | ||
|
|
8577f2b52f | ||
|
|
526cee7ec3 | ||
|
|
2b9b4c6789 | ||
|
|
de24ed7cea | ||
|
|
c34c123b33 | ||
|
|
4d02fc58fa | ||
|
|
aea1f8aebb | ||
|
|
bb938b02d8 | ||
|
|
8c31c7fb59 | ||
|
|
2365ffe143 | ||
|
|
6c4016af46 | ||
|
|
154ca8575c | ||
|
|
ae5411c37b | ||
|
|
62882fe49e | ||
|
|
a8469fc79d | ||
|
|
7aa60baafb | ||
|
|
99f352228c | ||
|
|
621178f558 |
@@ -10,6 +10,7 @@ os:
|
||||
- osx
|
||||
env:
|
||||
- TARGET_ARCH=x64
|
||||
osx_image: xcode7
|
||||
|
||||
matrix:
|
||||
include:
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
:zap: *프레임워크 이름이 Atom Shell에서 Electron으로 변경되었습니다* :zap:
|
||||
|
||||
Electron 프레임워크는 JavaScript, HTML 그리고 CSS를 사용하여 Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주는 프레임워크입니다. 이 프레임워크는 [io.js](http://iojs.org) 와
|
||||
Electron 프레임워크는 JavaScript, HTML 그리고 CSS를 사용하여 Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주는 프레임워크입니다. 이 프레임워크는 [Node.js](https://nodejs.org) 와
|
||||
[Chromium](http://www.chromium.org)을 기반으로 만들어 졌으며 [Atom Editor](https://github.com/atom/atom)에 사용되고 있습니다.
|
||||
|
||||
Electron에 대한 중요한 알림을 받고 싶다면 Twitter에서 [@ElectronJS](https://twitter.com/electronjs)를 팔로우 하세요.
|
||||
@@ -47,9 +47,13 @@ Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법도 문
|
||||
- [중국어 간체](https://github.com/atom/electron/tree/master/docs-translations/zh-CN)
|
||||
- [중국어 번체](https://github.com/atom/electron/tree/master/docs-translations/zh-TW)
|
||||
|
||||
## 시작하기
|
||||
|
||||
[`atom/electron-quick-start`](https://github.com/atom/electron-quick-start) 저장소를 클론하여 Electron을 간단히 접해볼 수 있습니다.
|
||||
|
||||
## 커뮤니티
|
||||
|
||||
다음 링크를 통해 커뮤니티에 질문을 올리거나 토론을 나누실 수 있습니다:
|
||||
다음 링크를 통해 커뮤니티에 질문을 올리거나 토론을 나눌 수 있습니다:
|
||||
|
||||
- Atom 포럼의 [`electron`](http://discuss.atom.io/category/electron) 카테고리
|
||||
- Freenode 채팅의 `#atom-shell` 채널
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
:zap: *Formerly known as Atom Shell* :zap:
|
||||
|
||||
The Electron framework lets you write cross-platform desktop applications
|
||||
using JavaScript, HTML and CSS. It is based on [io.js](http://iojs.org) and
|
||||
using JavaScript, HTML and CSS. It is based on [Node.js](https://nodejs.org) and
|
||||
[Chromium](http://www.chromium.org) and is used in the [Atom
|
||||
editor](https://github.com/atom/atom).
|
||||
|
||||
@@ -53,6 +53,11 @@ contains documents describing how to build and contribute to Electron.
|
||||
- [Simplified Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-CN)
|
||||
- [Traditional Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-TW)
|
||||
|
||||
## Quick Start
|
||||
|
||||
Clone and run the [`atom/electron-quick-start`](https://github.com/atom/electron-quick-start)
|
||||
repository to see a minimal Electron app in action.
|
||||
|
||||
## Community
|
||||
|
||||
You can ask questions and interact with the community in the following
|
||||
|
||||
69
atom.gyp
69
atom.gyp
@@ -4,7 +4,7 @@
|
||||
'product_name%': 'Electron',
|
||||
'company_name%': 'GitHub, Inc',
|
||||
'company_abbr%': 'github',
|
||||
'version%': '0.33.6',
|
||||
'version%': '0.34.1',
|
||||
},
|
||||
'includes': [
|
||||
'filenames.gypi',
|
||||
@@ -64,9 +64,6 @@
|
||||
'files': [
|
||||
'<(PRODUCT_DIR)/<(product_name) Helper.app',
|
||||
'<(PRODUCT_DIR)/<(product_name) Framework.framework',
|
||||
'external_binaries/Squirrel.framework',
|
||||
'external_binaries/ReactiveCocoa.framework',
|
||||
'external_binaries/Mantle.framework',
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -109,7 +106,21 @@
|
||||
'<@(locale_dirs)',
|
||||
],
|
||||
},
|
||||
]
|
||||
],
|
||||
'conditions': [
|
||||
['mas_build==0', {
|
||||
'copies': [
|
||||
{
|
||||
'destination': '<(PRODUCT_DIR)/<(product_name).app/Contents/Frameworks',
|
||||
'files': [
|
||||
'external_binaries/Squirrel.framework',
|
||||
'external_binaries/ReactiveCocoa.framework',
|
||||
'external_binaries/Mantle.framework',
|
||||
],
|
||||
},
|
||||
],
|
||||
}],
|
||||
],
|
||||
}, { # OS=="mac"
|
||||
'dependencies': [
|
||||
'make_locale_paks',
|
||||
@@ -285,12 +296,28 @@
|
||||
'vendor/breakpad/breakpad.gyp:breakpad_sender',
|
||||
],
|
||||
}], # OS=="win"
|
||||
['OS=="mac"', {
|
||||
['OS=="mac" and mas_build==0', {
|
||||
'dependencies': [
|
||||
'vendor/crashpad/client/client.gyp:crashpad_client',
|
||||
'vendor/crashpad/handler/handler.gyp:crashpad_handler',
|
||||
],
|
||||
}], # OS=="mac"
|
||||
'link_settings': {
|
||||
# Do not link with QTKit for mas build.
|
||||
'libraries': [
|
||||
'$(SDKROOT)/System/Library/Frameworks/QTKit.framework',
|
||||
],
|
||||
},
|
||||
}], # OS=="mac" and mas_build==0
|
||||
['OS=="mac" and mas_build==1', {
|
||||
'defines': [
|
||||
'MAS_BUILD',
|
||||
],
|
||||
'sources!': [
|
||||
'atom/browser/auto_updater_mac.mm',
|
||||
'atom/common/crash_reporter/crash_reporter_mac.h',
|
||||
'atom/common/crash_reporter/crash_reporter_mac.mm',
|
||||
],
|
||||
}], # OS=="mac" and mas_build==1
|
||||
['OS=="linux"', {
|
||||
'link_settings': {
|
||||
'ldflags': [
|
||||
@@ -393,9 +420,6 @@
|
||||
'libraries': [
|
||||
'$(SDKROOT)/System/Library/Frameworks/Carbon.framework',
|
||||
'$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework',
|
||||
'external_binaries/Squirrel.framework',
|
||||
'external_binaries/ReactiveCocoa.framework',
|
||||
'external_binaries/Mantle.framework',
|
||||
],
|
||||
},
|
||||
'mac_bundle': 1,
|
||||
@@ -439,12 +463,6 @@
|
||||
'<@(copied_libraries)',
|
||||
],
|
||||
},
|
||||
{
|
||||
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Resources',
|
||||
'files': [
|
||||
'<(PRODUCT_DIR)/crashpad_handler',
|
||||
],
|
||||
},
|
||||
],
|
||||
'postbuilds': [
|
||||
{
|
||||
@@ -476,6 +494,25 @@
|
||||
],
|
||||
},
|
||||
],
|
||||
'conditions': [
|
||||
['mas_build==0', {
|
||||
'link_settings': {
|
||||
'libraries': [
|
||||
'external_binaries/Squirrel.framework',
|
||||
'external_binaries/ReactiveCocoa.framework',
|
||||
'external_binaries/Mantle.framework',
|
||||
],
|
||||
},
|
||||
'copies': [
|
||||
{
|
||||
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Resources',
|
||||
'files': [
|
||||
'<(PRODUCT_DIR)/crashpad_handler',
|
||||
],
|
||||
},
|
||||
],
|
||||
}],
|
||||
],
|
||||
}, # target framework
|
||||
{
|
||||
'target_name': '<(project_name)_helper',
|
||||
|
||||
@@ -99,7 +99,7 @@ void AtomContentClient::AddAdditionalSchemes(
|
||||
void AtomContentClient::AddPepperPlugins(
|
||||
std::vector<content::PepperPluginInfo>* plugins) {
|
||||
auto command_line = base::CommandLine::ForCurrentProcess();
|
||||
auto flash_path = command_line->GetSwitchValueNative(
|
||||
auto flash_path = command_line->GetSwitchValuePath(
|
||||
switches::kPpapiFlashPath);
|
||||
if (flash_path.empty())
|
||||
return;
|
||||
@@ -108,7 +108,7 @@ void AtomContentClient::AddPepperPlugins(
|
||||
switches::kPpapiFlashVersion);
|
||||
|
||||
plugins->push_back(
|
||||
CreatePepperFlashInfo(base::FilePath(flash_path), flash_version));
|
||||
CreatePepperFlashInfo(flash_path, flash_version));
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "base/at_exit.h"
|
||||
#include "base/i18n/icu_util.h"
|
||||
#include "base/mac/bundle_locations.h"
|
||||
#include "base/mac/scoped_nsautorelease_pool.h"
|
||||
#include "brightray/common/mac/main_application_bundle.h"
|
||||
#include "content/public/app/content_main.h"
|
||||
|
||||
@@ -25,6 +26,7 @@ int AtomMain(int argc, const char* argv[]) {
|
||||
|
||||
int AtomInitializeICUandStartNode(int argc, char *argv[]) {
|
||||
base::AtExitManager atexit_manager;
|
||||
base::mac::ScopedNSAutoreleasePool pool;
|
||||
base::mac::SetOverrideFrameworkBundlePath(
|
||||
brightray::MainApplicationBundlePath()
|
||||
.Append("Contents")
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "atom/app/atom_main_delegate.h"
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "atom/app/atom_content_client.h"
|
||||
#include "atom/browser/atom_browser_client.h"
|
||||
@@ -20,6 +21,15 @@
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsBrowserProcess(base::CommandLine* cmd) {
|
||||
std::string process_type = cmd->GetSwitchValueASCII(switches::kProcessType);
|
||||
return process_type.empty();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AtomMainDelegate::AtomMainDelegate() {
|
||||
}
|
||||
|
||||
@@ -27,8 +37,14 @@ AtomMainDelegate::~AtomMainDelegate() {
|
||||
}
|
||||
|
||||
bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||
auto command_line = base::CommandLine::ForCurrentProcess();
|
||||
|
||||
logging::LoggingSettings settings;
|
||||
#if defined(OS_WIN)
|
||||
// On Windows the terminal returns immediately, so we add a new line to
|
||||
// prevent output in the same line as the prompt.
|
||||
if (IsBrowserProcess(command_line))
|
||||
std::wcout << std::endl;
|
||||
#if defined(DEBUG)
|
||||
// Print logging to debug.log on Windows
|
||||
settings.logging_dest = logging::LOG_TO_ALL;
|
||||
@@ -43,19 +59,25 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||
#endif // !defined(OS_WIN)
|
||||
|
||||
// Only enable logging when --enable-logging is specified.
|
||||
auto command_line = base::CommandLine::ForCurrentProcess();
|
||||
if (!command_line->HasSwitch(switches::kEnableLogging))
|
||||
scoped_ptr<base::Environment> env(base::Environment::Create());
|
||||
if (!command_line->HasSwitch(switches::kEnableLogging) &&
|
||||
!env->HasVar("ELECTRON_ENABLE_LOGGING")) {
|
||||
settings.logging_dest = logging::LOG_NONE;
|
||||
logging::SetMinLogLevel(logging::LOG_NUM_SEVERITIES);
|
||||
}
|
||||
|
||||
logging::InitLogging(settings);
|
||||
|
||||
// Logging with pid and timestamp.
|
||||
logging::SetLogItems(true, false, true, false);
|
||||
|
||||
#if defined(DEBUG) && defined(OS_LINUX)
|
||||
// Enable convient stack printing.
|
||||
base::debug::EnableInProcessStackDumping();
|
||||
bool enable_stack_dumping = env->HasVar("ELECTRON_ENABLE_STACK_DUMPING");
|
||||
#if defined(DEBUG) && defined(OS_LINUX)
|
||||
enable_stack_dumping = true;
|
||||
#endif
|
||||
if (enable_stack_dumping)
|
||||
base::debug::EnableInProcessStackDumping();
|
||||
|
||||
return brightray::MainDelegate::BasicStartupComplete(exit_code);
|
||||
}
|
||||
@@ -77,7 +99,7 @@ void AtomMainDelegate::PreSandboxStartup() {
|
||||
}
|
||||
|
||||
// Only append arguments for browser process.
|
||||
if (!process_type.empty())
|
||||
if (!IsBrowserProcess(command_line))
|
||||
return;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#include "atom/app/uv_task_runner.h"
|
||||
#include "atom/browser/javascript_environment.h"
|
||||
#include "atom/browser/node_debugger.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "base/command_line.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "base/thread_task_runner_handle.h"
|
||||
#include "gin/array_buffer.h"
|
||||
#include "gin/public/isolate_holder.h"
|
||||
@@ -19,25 +19,22 @@ namespace atom {
|
||||
int NodeMain(int argc, char *argv[]) {
|
||||
base::CommandLine::Init(argc, argv);
|
||||
|
||||
argv = uv_setup_args(argc, argv);
|
||||
int exec_argc;
|
||||
const char** exec_argv;
|
||||
node::Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);
|
||||
|
||||
int exit_code = 1;
|
||||
{
|
||||
// Feed gin::PerIsolateData with a task runner.
|
||||
argv = uv_setup_args(argc, argv);
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
scoped_refptr<UvTaskRunner> uv_task_runner(new UvTaskRunner(loop));
|
||||
base::ThreadTaskRunnerHandle handle(uv_task_runner);
|
||||
|
||||
gin::V8Initializer::LoadV8Snapshot();
|
||||
gin::V8Initializer::LoadV8Natives();
|
||||
gin::IsolateHolder::Initialize(
|
||||
gin::IsolateHolder::kNonStrictMode,
|
||||
gin::ArrayBufferAllocator::SharedInstance());
|
||||
|
||||
JavascriptEnvironment gin_env;
|
||||
|
||||
int exec_argc;
|
||||
const char** exec_argv;
|
||||
node::Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);
|
||||
|
||||
node::Environment* env = node::CreateEnvironment(
|
||||
gin_env.isolate(), loop, gin_env.context(), argc, argv,
|
||||
exec_argc, exec_argv);
|
||||
|
||||
@@ -48,8 +48,13 @@ void UvTaskRunner::OnTimeout(uv_timer_t* timer) {
|
||||
|
||||
self->tasks_[timer].Run();
|
||||
self->tasks_.erase(timer);
|
||||
uv_unref(reinterpret_cast<uv_handle_t*>(timer));
|
||||
delete timer;
|
||||
uv_timer_stop(timer);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(timer), UvTaskRunner::OnClose);
|
||||
}
|
||||
|
||||
// static
|
||||
void UvTaskRunner::OnClose(uv_handle_t* handle) {
|
||||
delete reinterpret_cast<uv_timer_t*>(handle);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -31,6 +31,7 @@ class UvTaskRunner : public base::SingleThreadTaskRunner {
|
||||
|
||||
private:
|
||||
static void OnTimeout(uv_timer_t* timer);
|
||||
static void OnClose(uv_handle_t* handle);
|
||||
|
||||
uv_loop_t* loop_;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/files/file_path.h"
|
||||
@@ -27,6 +28,7 @@
|
||||
#include "brightray/browser/brightray_paths.h"
|
||||
#include "content/public/browser/client_certificate_delegate.h"
|
||||
#include "content/public/browser/gpu_data_manager.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
#include "net/ssl/ssl_cert_request_info.h"
|
||||
@@ -109,6 +111,23 @@ int GetPathConstant(const std::string& name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool NotificationCallbackWrapper(
|
||||
const ProcessSingleton::NotificationCallback& callback,
|
||||
const base::CommandLine::StringVector& cmd,
|
||||
const base::FilePath& cwd) {
|
||||
// Make sure the callback is called after app gets ready.
|
||||
if (Browser::Get()->is_ready()) {
|
||||
callback.Run(cmd, cwd);
|
||||
} else {
|
||||
scoped_refptr<base::SingleThreadTaskRunner> task_runner(
|
||||
base::ThreadTaskRunnerHandle::Get());
|
||||
task_runner->PostTask(
|
||||
FROM_HERE, base::Bind(base::IgnoreResult(callback), cmd, cwd));
|
||||
}
|
||||
// ProcessSingleton needs to know whether current process is quiting.
|
||||
return !Browser::Get()->is_shutting_down();
|
||||
}
|
||||
|
||||
void OnClientCertificateSelected(
|
||||
v8::Isolate* isolate,
|
||||
std::shared_ptr<content::ClientCertificateDelegate> delegate,
|
||||
@@ -158,6 +177,11 @@ void App::OnWindowAllClosed() {
|
||||
|
||||
void App::OnQuit() {
|
||||
Emit("quit");
|
||||
|
||||
if (process_singleton_.get()) {
|
||||
process_singleton_->Cleanup();
|
||||
process_singleton_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void App::OnOpenFile(bool* prevent_default, const std::string& file_path) {
|
||||
@@ -249,6 +273,12 @@ void App::SetAppUserModelId(const std::string& app_id) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void App::AllowNTLMCredentialsForAllDomains(bool should_allow) {
|
||||
auto browser_context = static_cast<AtomBrowserContext*>(
|
||||
AtomBrowserMainParts::Get()->browser_context());
|
||||
browser_context->AllowNTLMCredentialsForAllDomains(should_allow);
|
||||
}
|
||||
|
||||
std::string App::GetLocale() {
|
||||
return l10n_util::GetApplicationLocale("");
|
||||
}
|
||||
@@ -260,6 +290,28 @@ v8::Local<v8::Value> App::DefaultSession(v8::Isolate* isolate) {
|
||||
return v8::Local<v8::Value>::New(isolate, default_session_);
|
||||
}
|
||||
|
||||
bool App::MakeSingleInstance(
|
||||
const ProcessSingleton::NotificationCallback& callback) {
|
||||
if (process_singleton_.get())
|
||||
return false;
|
||||
|
||||
base::FilePath user_dir;
|
||||
PathService::Get(brightray::DIR_USER_DATA, &user_dir);
|
||||
process_singleton_.reset(new ProcessSingleton(
|
||||
user_dir, base::Bind(NotificationCallbackWrapper, callback)));
|
||||
|
||||
switch (process_singleton_->NotifyOtherProcessOrCreate()) {
|
||||
case ProcessSingleton::NotifyResult::LOCK_ERROR:
|
||||
case ProcessSingleton::NotifyResult::PROFILE_IN_USE:
|
||||
case ProcessSingleton::NotifyResult::PROCESS_NOTIFIED:
|
||||
process_singleton_.reset();
|
||||
return true;
|
||||
case ProcessSingleton::NotifyResult::PROCESS_NONE:
|
||||
default: // Shouldn't be needed, but VS warns if it is not there.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
auto browser = base::Unretained(Browser::Get());
|
||||
@@ -283,7 +335,10 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
|
||||
.SetMethod("getPath", &App::GetPath)
|
||||
.SetMethod("setDesktopName", &App::SetDesktopName)
|
||||
.SetMethod("setAppUserModelId", &App::SetAppUserModelId)
|
||||
.SetMethod("allowNTLMCredentialsForAllDomains",
|
||||
&App::AllowNTLMCredentialsForAllDomains)
|
||||
.SetMethod("getLocale", &App::GetLocale)
|
||||
.SetMethod("makeSingleInstance", &App::MakeSingleInstance)
|
||||
.SetProperty("defaultSession", &App::DefaultSession);
|
||||
}
|
||||
|
||||
@@ -301,6 +356,16 @@ namespace {
|
||||
|
||||
void AppendSwitch(const std::string& switch_string, mate::Arguments* args) {
|
||||
auto command_line = base::CommandLine::ForCurrentProcess();
|
||||
|
||||
if (switch_string == atom::switches::kPpapiFlashPath ||
|
||||
switch_string == atom::switches::kClientCertificate ||
|
||||
switch_string == switches::kLogNetLog) {
|
||||
base::FilePath path;
|
||||
args->GetNext(&path);
|
||||
command_line->AppendSwitchPath(switch_string, path);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string value;
|
||||
if (args->GetNext(&value))
|
||||
command_line->AppendSwitchASCII(switch_string, value);
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "atom/browser/browser_observer.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "chrome/browser/process_singleton.h"
|
||||
#include "content/public/browser/gpu_data_manager_observer.h"
|
||||
#include "native_mate/handle.h"
|
||||
|
||||
@@ -65,11 +67,16 @@ class App : public mate::EventEmitter,
|
||||
|
||||
void SetDesktopName(const std::string& desktop_name);
|
||||
void SetAppUserModelId(const std::string& app_id);
|
||||
void AllowNTLMCredentialsForAllDomains(bool should_allow);
|
||||
bool MakeSingleInstance(
|
||||
const ProcessSingleton::NotificationCallback& callback);
|
||||
std::string GetLocale();
|
||||
v8::Local<v8::Value> DefaultSession(v8::Isolate* isolate);
|
||||
|
||||
v8::Global<v8::Value> default_session_;
|
||||
|
||||
scoped_ptr<ProcessSingleton> process_singleton_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(App);
|
||||
};
|
||||
|
||||
|
||||
@@ -5,12 +5,31 @@
|
||||
#include "atom/browser/api/atom_api_auto_updater.h"
|
||||
|
||||
#include "base/time/time.h"
|
||||
#include "atom/browser/auto_updater.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<base::Time> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const base::Time& val) {
|
||||
v8::MaybeLocal<v8::Value> date = v8::Date::New(
|
||||
isolate->GetCurrentContext(), val.ToJsTime());
|
||||
if (date.IsEmpty())
|
||||
return v8::Null(isolate);
|
||||
else
|
||||
return date.ToLocalChecked();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
@@ -20,11 +39,18 @@ AutoUpdater::AutoUpdater() {
|
||||
}
|
||||
|
||||
AutoUpdater::~AutoUpdater() {
|
||||
auto_updater::AutoUpdater::SetDelegate(NULL);
|
||||
auto_updater::AutoUpdater::SetDelegate(nullptr);
|
||||
}
|
||||
|
||||
void AutoUpdater::OnError(const std::string& error) {
|
||||
Emit("error", error);
|
||||
void AutoUpdater::OnError(const std::string& message) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
auto error = v8::Exception::Error(mate::StringToV8(isolate(), message));
|
||||
EmitCustomEvent(
|
||||
"error",
|
||||
error->ToObject(isolate()->GetCurrentContext()).ToLocalChecked(),
|
||||
// Message is also emitted to keep compatibility with old code.
|
||||
message);
|
||||
}
|
||||
|
||||
void AutoUpdater::OnCheckingForUpdate() {
|
||||
@@ -42,11 +68,14 @@ void AutoUpdater::OnUpdateNotAvailable() {
|
||||
void AutoUpdater::OnUpdateDownloaded(const std::string& release_notes,
|
||||
const std::string& release_name,
|
||||
const base::Time& release_date,
|
||||
const std::string& update_url,
|
||||
const base::Closure& quit_and_install) {
|
||||
quit_and_install_ = quit_and_install;
|
||||
Emit("update-downloaded-raw", release_notes, release_name,
|
||||
release_date.ToJsTime(), update_url);
|
||||
const std::string& url) {
|
||||
Emit("update-downloaded", release_notes, release_name, release_date, url,
|
||||
// Keep compatibility with old APIs.
|
||||
base::Bind(&AutoUpdater::QuitAndInstall, base::Unretained(this)));
|
||||
}
|
||||
|
||||
void AutoUpdater::OnWindowAllClosed() {
|
||||
QuitAndInstall();
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder(
|
||||
@@ -54,14 +83,21 @@ mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder(
|
||||
return mate::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("setFeedUrl", &auto_updater::AutoUpdater::SetFeedURL)
|
||||
.SetMethod("checkForUpdates", &auto_updater::AutoUpdater::CheckForUpdates)
|
||||
.SetMethod("_quitAndInstall", &AutoUpdater::QuitAndInstall);
|
||||
.SetMethod("quitAndInstall", &AutoUpdater::QuitAndInstall);
|
||||
}
|
||||
|
||||
void AutoUpdater::QuitAndInstall() {
|
||||
if (quit_and_install_.is_null())
|
||||
Browser::Get()->Shutdown();
|
||||
else
|
||||
quit_and_install_.Run();
|
||||
// If we don't have any window then quitAndInstall immediately.
|
||||
WindowList* window_list = WindowList::GetInstance();
|
||||
if (window_list->size() == 0) {
|
||||
auto_updater::AutoUpdater::QuitAndInstall();
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise do the restart after all windows have been closed.
|
||||
window_list->AddObserver(this);
|
||||
for (NativeWindow* window : *window_list)
|
||||
window->Close();
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "atom/browser/auto_updater_delegate.h"
|
||||
#include "atom/browser/auto_updater.h"
|
||||
#include "atom/browser/window_list_observer.h"
|
||||
#include "native_mate/handle.h"
|
||||
|
||||
namespace atom {
|
||||
@@ -17,7 +17,8 @@ namespace atom {
|
||||
namespace api {
|
||||
|
||||
class AutoUpdater : public mate::EventEmitter,
|
||||
public auto_updater::AutoUpdaterDelegate {
|
||||
public auto_updater::Delegate,
|
||||
public WindowListObserver {
|
||||
public:
|
||||
static mate::Handle<AutoUpdater> Create(v8::Isolate* isolate);
|
||||
|
||||
@@ -25,17 +26,18 @@ class AutoUpdater : public mate::EventEmitter,
|
||||
AutoUpdater();
|
||||
virtual ~AutoUpdater();
|
||||
|
||||
// AutoUpdaterDelegate implementations.
|
||||
// Delegate implementations.
|
||||
void OnError(const std::string& error) override;
|
||||
void OnCheckingForUpdate() override;
|
||||
void OnUpdateAvailable() override;
|
||||
void OnUpdateNotAvailable() override;
|
||||
void OnUpdateDownloaded(
|
||||
const std::string& release_notes,
|
||||
const std::string& release_name,
|
||||
const base::Time& release_date,
|
||||
const std::string& update_url,
|
||||
const base::Closure& quit_and_install) override;
|
||||
void OnUpdateDownloaded(const std::string& release_notes,
|
||||
const std::string& release_name,
|
||||
const base::Time& release_date,
|
||||
const std::string& update_url) override;
|
||||
|
||||
// WindowListObserver:
|
||||
void OnWindowAllClosed() override;
|
||||
|
||||
// mate::Wrappable implementations:
|
||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
@@ -44,8 +46,6 @@ class AutoUpdater : public mate::EventEmitter,
|
||||
private:
|
||||
void QuitAndInstall();
|
||||
|
||||
base::Closure quit_and_install_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AutoUpdater);
|
||||
};
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "atom/browser/api/atom_api_download_item.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/browser/api/save_page_handler.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
@@ -104,6 +105,24 @@ struct Converter<ClearStorageDataOptions> {
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<net::ProxyConfig> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
net::ProxyConfig* out) {
|
||||
std::string proxy;
|
||||
if (!ConvertFromV8(isolate, val, &proxy))
|
||||
return false;
|
||||
auto pac_url = GURL(proxy);
|
||||
if (pac_url.is_valid()) {
|
||||
out->set_pac_url(pac_url);
|
||||
} else {
|
||||
out->proxy_rules().ParseFromString(proxy);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace atom {
|
||||
@@ -208,12 +227,12 @@ void ClearHttpCacheInIO(
|
||||
}
|
||||
|
||||
void SetProxyInIO(net::URLRequestContextGetter* getter,
|
||||
const std::string& proxy,
|
||||
const net::ProxyConfig& config,
|
||||
const base::Closure& callback) {
|
||||
net::ProxyConfig config;
|
||||
config.proxy_rules().ParseFromString(proxy);
|
||||
auto proxy_service = getter->GetURLRequestContext()->proxy_service();
|
||||
proxy_service->ResetConfigService(new net::ProxyConfigServiceFixed(config));
|
||||
// Refetches and applies the new pac script if provided.
|
||||
proxy_service->ForceReloadProxyConfig();
|
||||
RunCallbackInUI(callback);
|
||||
}
|
||||
|
||||
@@ -237,6 +256,8 @@ Session::~Session() {
|
||||
void Session::OnDownloadCreated(content::DownloadManager* manager,
|
||||
content::DownloadItem* item) {
|
||||
auto web_contents = item->GetWebContents();
|
||||
if (SavePageHandler::IsSavePageTypes(item->GetMimeType()))
|
||||
return;
|
||||
bool prevent_default = Emit(
|
||||
"will-download",
|
||||
DownloadItem::Create(isolate(), item),
|
||||
@@ -284,11 +305,11 @@ void Session::ClearStorageData(mate::Arguments* args) {
|
||||
base::Time(), base::Time::Max(), callback);
|
||||
}
|
||||
|
||||
void Session::SetProxy(const std::string& proxy,
|
||||
void Session::SetProxy(const net::ProxyConfig& config,
|
||||
const base::Closure& callback) {
|
||||
auto getter = browser_context_->GetRequestContext();
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&SetProxyInIO, base::Unretained(getter), proxy, callback));
|
||||
base::Bind(&SetProxyInIO, base::Unretained(getter), config, callback));
|
||||
}
|
||||
|
||||
void Session::SetDownloadPath(const base::FilePath& path) {
|
||||
|
||||
@@ -23,6 +23,10 @@ class Arguments;
|
||||
class Dictionary;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
class ProxyConfig;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomBrowserContext;
|
||||
@@ -64,7 +68,7 @@ class Session: public mate::TrackableObject<Session>,
|
||||
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
|
||||
void ClearCache(const net::CompletionCallback& callback);
|
||||
void ClearStorageData(mate::Arguments* args);
|
||||
void SetProxy(const std::string& proxy, const base::Closure& callback);
|
||||
void SetProxy(const net::ProxyConfig& config, const base::Closure& callback);
|
||||
void SetDownloadPath(const base::FilePath& path);
|
||||
void EnableNetworkEmulation(const mate::Dictionary& options);
|
||||
void DisableNetworkEmulation();
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "chrome/browser/printing/print_view_manager_basic.h"
|
||||
#include "chrome/browser/printing/print_preview_message_handler.h"
|
||||
#include "content/common/view_messages.h"
|
||||
#include "content/public/browser/browser_plugin_guest_manager.h"
|
||||
#include "content/public/browser/favicon_status.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "content/public/browser/navigation_details.h"
|
||||
@@ -51,6 +52,7 @@
|
||||
#include "net/url_request/static_http_user_agent_settings.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "third_party/WebKit/public/web/WebInputEvent.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
@@ -62,9 +64,21 @@ struct PrintSettings {
|
||||
};
|
||||
|
||||
void SetUserAgentInIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
std::string accept_lang,
|
||||
std::string user_agent) {
|
||||
getter->GetURLRequestContext()->set_http_user_agent_settings(
|
||||
new net::StaticHttpUserAgentSettings("en-us,en", user_agent));
|
||||
new net::StaticHttpUserAgentSettings(
|
||||
net::HttpUtil::GenerateAcceptLanguageHeader(accept_lang),
|
||||
user_agent));
|
||||
}
|
||||
|
||||
bool NotifyZoomLevelChanged(
|
||||
double level, content::WebContents* guest_web_contents) {
|
||||
guest_web_contents->SendToAllFrames(
|
||||
new AtomViewMsg_SetZoomLevel(MSG_ROUTING_NONE, level));
|
||||
|
||||
// Return false to iterate over all guests.
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -133,7 +147,6 @@ struct Converter<net::HttpResponseHeaders*> {
|
||||
std::string value;
|
||||
while (headers->EnumerateHeaderLines(&iter, &key, &value)) {
|
||||
key = base::StringToLowerASCII(key);
|
||||
value = base::StringToLowerASCII(value);
|
||||
if (response_headers.HasKey(key)) {
|
||||
base::ListValue* values = nullptr;
|
||||
if (response_headers.GetList(key, &values))
|
||||
@@ -149,6 +162,26 @@ struct Converter<net::HttpResponseHeaders*> {
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<content::SavePageType> {
|
||||
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
|
||||
content::SavePageType* out) {
|
||||
std::string save_type;
|
||||
if (!ConvertFromV8(isolate, val, &save_type))
|
||||
return false;
|
||||
if (save_type == "HTMLOnly") {
|
||||
*out = content::SAVE_PAGE_TYPE_AS_ONLY_HTML;
|
||||
} else if (save_type == "HTMLComplete") {
|
||||
*out = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML;
|
||||
} else if (save_type == "MHTML") {
|
||||
*out = content::SAVE_PAGE_TYPE_AS_MHTML;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
|
||||
@@ -528,6 +561,7 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
|
||||
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
|
||||
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
|
||||
OnRendererMessageSync)
|
||||
IPC_MESSAGE_HANDLER(AtomViewHostMsg_ZoomLevelChanged, OnZoomLevelChanged)
|
||||
IPC_MESSAGE_UNHANDLED(handled = false)
|
||||
IPC_END_MESSAGE_MAP()
|
||||
|
||||
@@ -637,8 +671,10 @@ void WebContents::SetUserAgent(const std::string& user_agent) {
|
||||
web_contents()->SetUserAgentOverride(user_agent);
|
||||
scoped_refptr<net::URLRequestContextGetter> getter =
|
||||
web_contents()->GetBrowserContext()->GetRequestContext();
|
||||
|
||||
auto accept_lang = l10n_util::GetApplicationLocale("");
|
||||
getter->GetNetworkTaskRunner()->PostTask(FROM_HERE,
|
||||
base::Bind(&SetUserAgentInIO, getter, user_agent));
|
||||
base::Bind(&SetUserAgentInIO, getter, accept_lang, user_agent));
|
||||
}
|
||||
|
||||
std::string WebContents::GetUserAgent() {
|
||||
@@ -649,6 +685,13 @@ void WebContents::InsertCSS(const std::string& css) {
|
||||
web_contents()->InsertCSS(css);
|
||||
}
|
||||
|
||||
bool WebContents::SavePage(const base::FilePath& full_file_path,
|
||||
const content::SavePageType& save_type,
|
||||
const SavePageHandler::SavePageCallback& callback) {
|
||||
auto handler = new SavePageHandler(web_contents(), callback);
|
||||
return handler->Handle(full_file_path, save_type);
|
||||
}
|
||||
|
||||
void WebContents::ExecuteJavaScript(const base::string16& code,
|
||||
bool has_user_gesture) {
|
||||
Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture));
|
||||
@@ -960,6 +1003,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
||||
.SetMethod("setUserAgent", &WebContents::SetUserAgent)
|
||||
.SetMethod("getUserAgent", &WebContents::GetUserAgent)
|
||||
.SetMethod("insertCSS", &WebContents::InsertCSS)
|
||||
.SetMethod("savePage", &WebContents::SavePage)
|
||||
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
|
||||
.SetMethod("openDevTools", &WebContents::OpenDevTools)
|
||||
.SetMethod("closeDevTools", &WebContents::CloseDevTools)
|
||||
@@ -1033,6 +1077,15 @@ void WebContents::OnRendererMessageSync(const base::string16& channel,
|
||||
EmitWithSender(base::UTF16ToUTF8(channel), web_contents(), message, args);
|
||||
}
|
||||
|
||||
void WebContents::OnZoomLevelChanged(double level) {
|
||||
auto manager = web_contents()->GetBrowserContext()->GetGuestManager();
|
||||
if (!manager)
|
||||
return;
|
||||
manager->ForEachGuest(web_contents(),
|
||||
base::Bind(&NotifyZoomLevelChanged,
|
||||
level));
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<WebContents> WebContents::CreateFrom(
|
||||
v8::Isolate* isolate, content::WebContents* web_contents) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/frame_subscriber.h"
|
||||
#include "atom/browser/api/save_page_handler.h"
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "atom/browser/common_web_contents_delegate.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
@@ -73,6 +74,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||
void SetUserAgent(const std::string& user_agent);
|
||||
std::string GetUserAgent();
|
||||
void InsertCSS(const std::string& css);
|
||||
bool SavePage(const base::FilePath& full_file_path,
|
||||
const content::SavePageType& save_type,
|
||||
const SavePageHandler::SavePageCallback& callback);
|
||||
void ExecuteJavaScript(const base::string16& code,
|
||||
bool has_user_gesture);
|
||||
void OpenDevTools(mate::Arguments* args);
|
||||
@@ -247,6 +251,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||
const base::ListValue& args,
|
||||
IPC::Message* message);
|
||||
|
||||
// Called when guests need to be notified of
|
||||
// embedders' zoom level change.
|
||||
void OnZoomLevelChanged(double level);
|
||||
|
||||
v8::Global<v8::Value> session_;
|
||||
v8::Global<v8::Value> devtools_web_contents_;
|
||||
|
||||
|
||||
@@ -385,6 +385,10 @@ bool Window::IsKiosk() {
|
||||
return window_->IsKiosk();
|
||||
}
|
||||
|
||||
void Window::SetBackgroundColor(const std::string& color_name) {
|
||||
window_->SetBackgroundColor(color_name);
|
||||
}
|
||||
|
||||
void Window::FocusOnWebView() {
|
||||
window_->FocusOnWebView();
|
||||
}
|
||||
@@ -564,6 +568,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("setSkipTaskbar", &Window::SetSkipTaskbar)
|
||||
.SetMethod("setKiosk", &Window::SetKiosk)
|
||||
.SetMethod("isKiosk", &Window::IsKiosk)
|
||||
.SetMethod("setBackgroundColor", &Window::SetBackgroundColor)
|
||||
.SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename)
|
||||
.SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename)
|
||||
.SetMethod("setDocumentEdited", &Window::SetDocumentEdited)
|
||||
|
||||
@@ -122,6 +122,7 @@ class Window : public mate::TrackableObject<Window>,
|
||||
void SetSkipTaskbar(bool skip);
|
||||
void SetKiosk(bool kiosk);
|
||||
bool IsKiosk();
|
||||
void SetBackgroundColor(const std::string& color_name);
|
||||
void FocusOnWebView();
|
||||
void BlurWebView();
|
||||
bool IsWebViewFocused();
|
||||
|
||||
@@ -1,24 +1,7 @@
|
||||
autoUpdater = process.atomBinding('auto_updater').autoUpdater
|
||||
EventEmitter = require('events').EventEmitter
|
||||
|
||||
autoUpdater.__proto__ = EventEmitter.prototype
|
||||
|
||||
autoUpdater.on 'update-downloaded-raw', (args...) ->
|
||||
args[3] = new Date(args[3]) # releaseDate
|
||||
@emit 'update-downloaded', args..., => @quitAndInstall()
|
||||
|
||||
autoUpdater.quitAndInstall = ->
|
||||
# If we don't have any window then quitAndInstall immediately.
|
||||
BrowserWindow = require 'browser-window'
|
||||
windows = BrowserWindow.getAllWindows()
|
||||
if windows.length is 0
|
||||
@_quitAndInstall()
|
||||
return
|
||||
|
||||
# Do the restart after all windows have been closed.
|
||||
app = require 'app'
|
||||
app.removeAllListeners 'window-all-closed'
|
||||
app.once 'window-all-closed', @_quitAndInstall.bind(this)
|
||||
win.close() for win in windows
|
||||
|
||||
module.exports = autoUpdater
|
||||
switch process.platform
|
||||
when 'win32'
|
||||
module.exports = require './auto-updater/auto-updater-win'
|
||||
when 'darwin'
|
||||
module.exports = require './auto-updater/auto-updater-mac'
|
||||
else
|
||||
throw new Error('auto-updater is not implemented on this platform')
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{EventEmitter} = require 'events'
|
||||
{autoUpdater} = process.atomBinding 'auto_updater'
|
||||
|
||||
autoUpdater.__proto__ = EventEmitter.prototype
|
||||
|
||||
module.exports = autoUpdater
|
||||
42
atom/browser/api/lib/auto-updater/auto-updater-win.coffee
Normal file
42
atom/browser/api/lib/auto-updater/auto-updater-win.coffee
Normal file
@@ -0,0 +1,42 @@
|
||||
app = require 'app'
|
||||
url = require 'url'
|
||||
{EventEmitter} = require 'events'
|
||||
|
||||
squirrelUpdate = require './squirrel-update-win'
|
||||
|
||||
class AutoUpdater extends EventEmitter
|
||||
quitAndInstall: ->
|
||||
squirrelUpdate.processStart()
|
||||
app.quit()
|
||||
|
||||
setFeedUrl: (updateUrl) ->
|
||||
@updateUrl = updateUrl
|
||||
|
||||
checkForUpdates: ->
|
||||
return @emitError 'Update URL is not set' unless @updateUrl
|
||||
return @emitError 'Can not find Squirrel' unless squirrelUpdate.supported()
|
||||
|
||||
@emit 'checking-for-update'
|
||||
|
||||
squirrelUpdate.download @updateUrl, (error, update) =>
|
||||
return @emitError error if error?
|
||||
return @emit 'update-not-available' unless update?
|
||||
|
||||
@emit 'update-available'
|
||||
|
||||
squirrelUpdate.update @updateUrl, (error) =>
|
||||
return @emitError error if error?
|
||||
|
||||
{releaseNotes, version} = update
|
||||
# Following information is not available on Windows, so fake them.
|
||||
date = new Date
|
||||
url = @updateUrl
|
||||
|
||||
@emit 'update-downloaded', {}, releaseNotes, version, date, url, => @quitAndInstall()
|
||||
|
||||
# Private: Emit both error object and message, this is to keep compatibility
|
||||
# with Old APIs.
|
||||
emitError: (message) ->
|
||||
@emit 'error', new Error(message), message
|
||||
|
||||
module.exports = new AutoUpdater
|
||||
67
atom/browser/api/lib/auto-updater/squirrel-update-win.coffee
Normal file
67
atom/browser/api/lib/auto-updater/squirrel-update-win.coffee
Normal file
@@ -0,0 +1,67 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
{spawn} = require 'child_process'
|
||||
|
||||
appFolder = path.dirname process.execPath # i.e. my-app/app-0.1.13/
|
||||
updateExe = path.resolve appFolder, '..', 'Update.exe' # i.e. my-app/Update.exe
|
||||
exeName = path.basename process.execPath
|
||||
|
||||
# Spawn a command and invoke the callback when it completes with an error
|
||||
# and the output from standard out.
|
||||
spawnUpdate = (args, detached, callback) ->
|
||||
try
|
||||
spawnedProcess = spawn updateExe, args, {detached}
|
||||
catch error
|
||||
# Shouldn't happen, but still guard it.
|
||||
process.nextTick -> callback error
|
||||
return
|
||||
|
||||
stdout = ''
|
||||
stderr = ''
|
||||
spawnedProcess.stdout.on 'data', (data) -> stdout += data
|
||||
spawnedProcess.stderr.on 'data', (data) -> stderr += data
|
||||
|
||||
errorEmitted = false
|
||||
spawnedProcess.on 'error', (error) ->
|
||||
errorEmitted = true
|
||||
callback error
|
||||
spawnedProcess.on 'exit', (code, signal) ->
|
||||
# We may have already emitted an error.
|
||||
return if errorEmitted
|
||||
|
||||
# Process terminated with error.
|
||||
if code isnt 0
|
||||
return callback "Command failed: #{signal ? code}\n#{stderr}"
|
||||
|
||||
# Success.
|
||||
callback null, stdout
|
||||
|
||||
# Start an instance of the installed app.
|
||||
exports.processStart = (callback) ->
|
||||
spawnUpdate ['--processStart', exeName], true, ->
|
||||
|
||||
# Download the releases specified by the URL and write new results to stdout.
|
||||
exports.download = (updateUrl, callback) ->
|
||||
spawnUpdate ['--download', updateUrl], false, (error, stdout) ->
|
||||
return callback(error) if error?
|
||||
|
||||
try
|
||||
# Last line of output is the JSON details about the releases
|
||||
json = stdout.trim().split('\n').pop()
|
||||
update = JSON.parse(json)?.releasesToApply?.pop?()
|
||||
catch
|
||||
return callback "Invalid result:\n#{stdout}"
|
||||
|
||||
callback null, update
|
||||
|
||||
# Update the application to the latest remote version specified by URL.
|
||||
exports.update = (updateUrl, callback) ->
|
||||
spawnUpdate ['--update', updateUrl], false, callback
|
||||
|
||||
# Is the Update.exe installed with the current application?
|
||||
exports.supported = ->
|
||||
try
|
||||
fs.accessSync updateExe, fs.R_OK
|
||||
return true
|
||||
catch
|
||||
return false
|
||||
83
atom/browser/api/save_page_handler.cc
Normal file
83
atom/browser/api/save_page_handler.cc
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/api/save_page_handler.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
SavePageHandler::SavePageHandler(content::WebContents* web_contents,
|
||||
const SavePageCallback& callback)
|
||||
: web_contents_(web_contents),
|
||||
callback_(callback) {
|
||||
}
|
||||
|
||||
SavePageHandler::~SavePageHandler() {
|
||||
}
|
||||
|
||||
void SavePageHandler::OnDownloadCreated(content::DownloadManager* manager,
|
||||
content::DownloadItem* item) {
|
||||
// OnDownloadCreated is invoked during WebContents::SavePage, so the |item|
|
||||
// here is the one stated by WebContents::SavePage.
|
||||
item->AddObserver(this);
|
||||
}
|
||||
|
||||
bool SavePageHandler::Handle(const base::FilePath& full_path,
|
||||
const content::SavePageType& save_type) {
|
||||
auto download_manager = content::BrowserContext::GetDownloadManager(
|
||||
web_contents_->GetBrowserContext());
|
||||
download_manager->AddObserver(this);
|
||||
// Chromium will create a 'foo_files' directory under the directory of saving
|
||||
// page 'foo.html' for holding other resource files of 'foo.html'.
|
||||
base::FilePath saved_main_directory_path = full_path.DirName().Append(
|
||||
full_path.RemoveExtension().BaseName().value() +
|
||||
FILE_PATH_LITERAL("_files"));
|
||||
bool result = web_contents_->SavePage(full_path,
|
||||
saved_main_directory_path,
|
||||
save_type);
|
||||
download_manager->RemoveObserver(this);
|
||||
// If initialization fails which means fail to create |DownloadItem|, we need
|
||||
// to delete the |SavePageHandler| instance to avoid memory-leak.
|
||||
if (!result)
|
||||
delete this;
|
||||
return result;
|
||||
}
|
||||
|
||||
void SavePageHandler::OnDownloadUpdated(content::DownloadItem* item) {
|
||||
if (item->IsDone()) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
if (item->GetState() == content::DownloadItem::COMPLETE) {
|
||||
callback_.Run(v8::Null(isolate));
|
||||
} else {
|
||||
v8::Local<v8::String> error_message = v8::String::NewFromUtf8(
|
||||
isolate, "Fail to save page");
|
||||
callback_.Run(v8::Exception::Error(error_message));
|
||||
}
|
||||
Destroy(item);
|
||||
}
|
||||
}
|
||||
|
||||
void SavePageHandler::Destroy(content::DownloadItem* item) {
|
||||
item->RemoveObserver(this);
|
||||
delete this;
|
||||
}
|
||||
|
||||
// static
|
||||
bool SavePageHandler::IsSavePageTypes(const std::string& type) {
|
||||
return type == "multipart/related" || type == "text/html";
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
60
atom/browser/api/save_page_handler.h
Normal file
60
atom/browser/api/save_page_handler.h
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_
|
||||
#define ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "content/public/browser/download_item.h"
|
||||
#include "content/public/browser/download_manager.h"
|
||||
#include "content/public/browser/save_page_type.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
class WebContents;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
// A self-destroyed class for handling save page request.
|
||||
class SavePageHandler : public content::DownloadManager::Observer,
|
||||
public content::DownloadItem::Observer {
|
||||
public:
|
||||
using SavePageCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||
|
||||
SavePageHandler(content::WebContents* web_contents,
|
||||
const SavePageCallback& callback);
|
||||
~SavePageHandler();
|
||||
|
||||
bool Handle(const base::FilePath& full_path,
|
||||
const content::SavePageType& save_type);
|
||||
|
||||
static bool IsSavePageTypes(const std::string& type);
|
||||
|
||||
private:
|
||||
void Destroy(content::DownloadItem* item);
|
||||
|
||||
// content::DownloadManager::Observer:
|
||||
void OnDownloadCreated(content::DownloadManager* manager,
|
||||
content::DownloadItem* item) override;
|
||||
|
||||
// content::DownloadItem::Observer:
|
||||
void OnDownloadUpdated(content::DownloadItem* item) override;
|
||||
|
||||
content::WebContents* web_contents_; // weak
|
||||
SavePageCallback callback_;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_
|
||||
@@ -60,7 +60,8 @@ std::string RemoveWhitespace(const std::string& str) {
|
||||
AtomBrowserContext::AtomBrowserContext(const std::string& partition,
|
||||
bool in_memory)
|
||||
: brightray::BrowserContext(partition, in_memory),
|
||||
job_factory_(new AtomURLRequestJobFactory) {
|
||||
job_factory_(new AtomURLRequestJobFactory),
|
||||
allow_ntlm_everywhere_(false) {
|
||||
}
|
||||
|
||||
AtomBrowserContext::~AtomBrowserContext() {
|
||||
@@ -168,6 +169,16 @@ void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
|
||||
base::FilePath());
|
||||
}
|
||||
|
||||
bool AtomBrowserContext::AllowNTLMCredentialsForDomain(const GURL& origin) {
|
||||
if (allow_ntlm_everywhere_)
|
||||
return true;
|
||||
return Delegate::AllowNTLMCredentialsForDomain(origin);
|
||||
}
|
||||
|
||||
void AtomBrowserContext::AllowNTLMCredentialsForAllDomains(bool should_allow) {
|
||||
allow_ntlm_everywhere_ = should_allow;
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
namespace brightray {
|
||||
|
||||
@@ -28,6 +28,7 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
||||
net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory(
|
||||
const base::FilePath& base_path) override;
|
||||
net::SSLConfigService* CreateSSLConfigService() override;
|
||||
bool AllowNTLMCredentialsForDomain(const GURL& auth_origin) override;
|
||||
|
||||
// content::BrowserContext:
|
||||
content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
|
||||
@@ -36,6 +37,8 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
||||
// brightray::BrowserContext:
|
||||
void RegisterPrefs(PrefRegistrySimple* pref_registry) override;
|
||||
|
||||
void AllowNTLMCredentialsForAllDomains(bool should_allow);
|
||||
|
||||
AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
|
||||
|
||||
private:
|
||||
@@ -45,6 +48,8 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
||||
// Managed by brightray::BrowserContext.
|
||||
AtomURLRequestJobFactory* job_factory_;
|
||||
|
||||
bool allow_ntlm_everywhere_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext);
|
||||
};
|
||||
|
||||
|
||||
@@ -62,17 +62,15 @@ void AtomBrowserMainParts::PreEarlyInitialization() {
|
||||
void AtomBrowserMainParts::PostEarlyInitialization() {
|
||||
brightray::BrowserMainParts::PostEarlyInitialization();
|
||||
|
||||
{
|
||||
// Temporary set the bridge_task_runner_ as current thread's task runner,
|
||||
// so we can fool gin::PerIsolateData to use it as its task runner, instead
|
||||
// of getting current message loop's task runner, which is null for now.
|
||||
bridge_task_runner_ = new BridgeTaskRunner;
|
||||
base::ThreadTaskRunnerHandle handle(bridge_task_runner_);
|
||||
// Temporary set the bridge_task_runner_ as current thread's task runner,
|
||||
// so we can fool gin::PerIsolateData to use it as its task runner, instead
|
||||
// of getting current message loop's task runner, which is null for now.
|
||||
bridge_task_runner_ = new BridgeTaskRunner;
|
||||
base::ThreadTaskRunnerHandle handle(bridge_task_runner_);
|
||||
|
||||
// The ProxyResolverV8 has setup a complete V8 environment, in order to
|
||||
// avoid conflicts we only initialize our V8 environment after that.
|
||||
js_env_.reset(new JavascriptEnvironment);
|
||||
}
|
||||
// The ProxyResolverV8 has setup a complete V8 environment, in order to
|
||||
// avoid conflicts we only initialize our V8 environment after that.
|
||||
js_env_.reset(new JavascriptEnvironment);
|
||||
|
||||
node_bindings_->Initialize();
|
||||
|
||||
@@ -107,6 +105,7 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
|
||||
1000));
|
||||
|
||||
brightray::BrowserMainParts::PreMainMessageLoopRun();
|
||||
BridgeTaskRunner::MessageLoopIsReady();
|
||||
|
||||
#if defined(USE_X11)
|
||||
libgtk2ui::GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess());
|
||||
|
||||
@@ -5,11 +5,14 @@
|
||||
#include "atom/browser/atom_ssl_config_service.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/socket/ssl_client_socket.h"
|
||||
#include "net/ssl/ssl_cipher_suite_names.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -26,6 +29,23 @@ uint16 GetSSLProtocolVersion(const std::string& version_string) {
|
||||
return version;
|
||||
}
|
||||
|
||||
std::vector<uint16> ParseCipherSuites(
|
||||
const std::vector<std::string>& cipher_strings) {
|
||||
std::vector<uint16> cipher_suites;
|
||||
cipher_suites.reserve(cipher_strings.size());
|
||||
|
||||
for (auto& cipher_string : cipher_strings) {
|
||||
uint16 cipher_suite = 0;
|
||||
if (!net::ParseSSLCipherString(cipher_string, &cipher_suite)) {
|
||||
LOG(ERROR) << "Ignoring unrecognised cipher suite : "
|
||||
<< cipher_string;
|
||||
continue;
|
||||
}
|
||||
cipher_suites.push_back(cipher_suite);
|
||||
}
|
||||
return cipher_suites;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AtomSSLConfigService::AtomSSLConfigService() {
|
||||
@@ -35,6 +55,13 @@ AtomSSLConfigService::AtomSSLConfigService() {
|
||||
cmd_line->GetSwitchValueASCII(switches::kSSLVersionFallbackMin);
|
||||
config_.version_fallback_min = GetSSLProtocolVersion(version_string);
|
||||
}
|
||||
|
||||
if (cmd_line->HasSwitch(switches::kCipherSuiteBlacklist)) {
|
||||
auto cipher_strings = base::SplitString(
|
||||
cmd_line->GetSwitchValueASCII(switches::kCipherSuiteBlacklist),
|
||||
",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
||||
config_.disabled_cipher_suites = ParseCipherSuites(cipher_strings);
|
||||
}
|
||||
}
|
||||
|
||||
AtomSSLConfigService::~AtomSSLConfigService() {
|
||||
|
||||
@@ -6,14 +6,25 @@
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
AutoUpdaterDelegate* AutoUpdater::delegate_ = NULL;
|
||||
Delegate* AutoUpdater::delegate_ = nullptr;
|
||||
|
||||
AutoUpdaterDelegate* AutoUpdater::GetDelegate() {
|
||||
Delegate* AutoUpdater::GetDelegate() {
|
||||
return delegate_;
|
||||
}
|
||||
|
||||
void AutoUpdater::SetDelegate(AutoUpdaterDelegate* delegate) {
|
||||
void AutoUpdater::SetDelegate(Delegate* delegate) {
|
||||
delegate_ = delegate;
|
||||
}
|
||||
|
||||
#if !defined(OS_MACOSX) || defined(MAS_BUILD)
|
||||
void AutoUpdater::SetFeedURL(const std::string& url) {
|
||||
}
|
||||
|
||||
void AutoUpdater::CheckForUpdates() {
|
||||
}
|
||||
|
||||
void AutoUpdater::QuitAndInstall() {
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace auto_updater
|
||||
|
||||
@@ -9,21 +9,48 @@
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace base {
|
||||
class Time;
|
||||
}
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
class AutoUpdaterDelegate;
|
||||
class Delegate {
|
||||
public:
|
||||
// An error happened.
|
||||
virtual void OnError(const std::string& error) {}
|
||||
|
||||
// Checking to see if there is an update
|
||||
virtual void OnCheckingForUpdate() {}
|
||||
|
||||
// There is an update available and it is being downloaded
|
||||
virtual void OnUpdateAvailable() {}
|
||||
|
||||
// There is no available update.
|
||||
virtual void OnUpdateNotAvailable() {}
|
||||
|
||||
// There is a new update which has been downloaded.
|
||||
virtual void OnUpdateDownloaded(const std::string& release_notes,
|
||||
const std::string& release_name,
|
||||
const base::Time& release_date,
|
||||
const std::string& update_url) {}
|
||||
|
||||
protected:
|
||||
virtual ~Delegate() {}
|
||||
};
|
||||
|
||||
class AutoUpdater {
|
||||
public:
|
||||
// Gets/Sets the delegate.
|
||||
static AutoUpdaterDelegate* GetDelegate();
|
||||
static void SetDelegate(AutoUpdaterDelegate* delegate);
|
||||
static Delegate* GetDelegate();
|
||||
static void SetDelegate(Delegate* delegate);
|
||||
|
||||
static void SetFeedURL(const std::string& url);
|
||||
static void CheckForUpdates();
|
||||
static void QuitAndInstall();
|
||||
|
||||
private:
|
||||
static AutoUpdaterDelegate* delegate_;
|
||||
static Delegate* delegate_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(AutoUpdater);
|
||||
};
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_
|
||||
#define ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/callback_forward.h"
|
||||
|
||||
namespace base {
|
||||
class Time;
|
||||
}
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
class AutoUpdaterDelegate {
|
||||
public:
|
||||
// An error happened.
|
||||
virtual void OnError(const std::string& error) {}
|
||||
|
||||
// Checking to see if there is an update
|
||||
virtual void OnCheckingForUpdate() {}
|
||||
|
||||
// There is an update available and it is being downloaded
|
||||
virtual void OnUpdateAvailable() {}
|
||||
|
||||
// There is no available update.
|
||||
virtual void OnUpdateNotAvailable() {}
|
||||
|
||||
// There is a new update which has been downloaded.
|
||||
virtual void OnUpdateDownloaded(const std::string& release_notes,
|
||||
const std::string& release_name,
|
||||
const base::Time& release_date,
|
||||
const std::string& update_url,
|
||||
const base::Closure& quit_and_install) {}
|
||||
|
||||
protected:
|
||||
virtual ~AutoUpdaterDelegate() {}
|
||||
};
|
||||
|
||||
} // namespace auto_updater
|
||||
|
||||
#endif // ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/auto_updater.h"
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
// static
|
||||
void AutoUpdater::SetFeedURL(const std::string& url) {
|
||||
}
|
||||
|
||||
// static
|
||||
void AutoUpdater::CheckForUpdates() {
|
||||
}
|
||||
|
||||
} // namespace auto_updater
|
||||
@@ -12,9 +12,6 @@
|
||||
#include "base/bind.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "atom/browser/auto_updater_delegate.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
@@ -23,20 +20,12 @@ namespace {
|
||||
// The gloal SQRLUpdater object.
|
||||
SQRLUpdater* g_updater = nil;
|
||||
|
||||
void RelaunchToInstallUpdate() {
|
||||
[[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) {
|
||||
AutoUpdaterDelegate* delegate = AutoUpdater::GetDelegate();
|
||||
if (delegate)
|
||||
delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription));
|
||||
}];
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
void AutoUpdater::SetFeedURL(const std::string& feed) {
|
||||
if (g_updater == nil) {
|
||||
AutoUpdaterDelegate* delegate = GetDelegate();
|
||||
Delegate* delegate = GetDelegate();
|
||||
if (!delegate)
|
||||
return;
|
||||
|
||||
@@ -67,7 +56,7 @@ void AutoUpdater::SetFeedURL(const std::string& feed) {
|
||||
|
||||
// static
|
||||
void AutoUpdater::CheckForUpdates() {
|
||||
AutoUpdaterDelegate* delegate = GetDelegate();
|
||||
Delegate* delegate = GetDelegate();
|
||||
if (!delegate)
|
||||
return;
|
||||
|
||||
@@ -86,8 +75,7 @@ void AutoUpdater::CheckForUpdates() {
|
||||
base::SysNSStringToUTF8(update.releaseNotes),
|
||||
base::SysNSStringToUTF8(update.releaseName),
|
||||
base::Time::FromDoubleT(update.releaseDate.timeIntervalSince1970),
|
||||
base::SysNSStringToUTF8(update.updateURL.absoluteString),
|
||||
base::Bind(RelaunchToInstallUpdate));
|
||||
base::SysNSStringToUTF8(update.updateURL.absoluteString));
|
||||
} else {
|
||||
// When the completed event is sent with no update, then we know there
|
||||
// is no update available.
|
||||
@@ -100,4 +88,12 @@ void AutoUpdater::CheckForUpdates() {
|
||||
}];
|
||||
}
|
||||
|
||||
void AutoUpdater::QuitAndInstall() {
|
||||
[[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) {
|
||||
Delegate* delegate = AutoUpdater::GetDelegate();
|
||||
if (delegate)
|
||||
delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription));
|
||||
}];
|
||||
}
|
||||
|
||||
} // namespace auto_updater
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/auto_updater.h"
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
// static
|
||||
void AutoUpdater::SetFeedURL(const std::string& url) {
|
||||
}
|
||||
|
||||
// static
|
||||
void AutoUpdater::CheckForUpdates() {
|
||||
}
|
||||
|
||||
} // namespace auto_updater
|
||||
@@ -8,13 +8,33 @@
|
||||
|
||||
namespace atom {
|
||||
|
||||
// static
|
||||
std::vector<BridgeTaskRunner::TaskPair> BridgeTaskRunner::tasks_;
|
||||
std::vector<BridgeTaskRunner::TaskPair> BridgeTaskRunner::non_nestable_tasks_;
|
||||
|
||||
// static
|
||||
void BridgeTaskRunner::MessageLoopIsReady() {
|
||||
auto message_loop = base::MessageLoop::current();
|
||||
CHECK(message_loop);
|
||||
for (const TaskPair& task : tasks_) {
|
||||
message_loop->task_runner()->PostDelayedTask(
|
||||
base::get<0>(task), base::get<1>(task), base::get<2>(task));
|
||||
}
|
||||
for (const TaskPair& task : non_nestable_tasks_) {
|
||||
message_loop->task_runner()->PostNonNestableDelayedTask(
|
||||
base::get<0>(task), base::get<1>(task), base::get<2>(task));
|
||||
}
|
||||
}
|
||||
|
||||
bool BridgeTaskRunner::PostDelayedTask(
|
||||
const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::TimeDelta delay) {
|
||||
auto message_loop = base::MessageLoop::current();
|
||||
if (!message_loop)
|
||||
return false;
|
||||
if (!message_loop) {
|
||||
tasks_.push_back(base::MakeTuple(from_here, task, delay));
|
||||
return true;
|
||||
}
|
||||
|
||||
return message_loop->task_runner()->PostDelayedTask(from_here, task, delay);
|
||||
}
|
||||
@@ -22,7 +42,7 @@ bool BridgeTaskRunner::PostDelayedTask(
|
||||
bool BridgeTaskRunner::RunsTasksOnCurrentThread() const {
|
||||
auto message_loop = base::MessageLoop::current();
|
||||
if (!message_loop)
|
||||
return false;
|
||||
return true;
|
||||
|
||||
return message_loop->task_runner()->RunsTasksOnCurrentThread();
|
||||
}
|
||||
@@ -32,8 +52,10 @@ bool BridgeTaskRunner::PostNonNestableDelayedTask(
|
||||
const base::Closure& task,
|
||||
base::TimeDelta delay) {
|
||||
auto message_loop = base::MessageLoop::current();
|
||||
if (!message_loop)
|
||||
return false;
|
||||
if (!message_loop) {
|
||||
non_nestable_tasks_.push_back(base::MakeTuple(from_here, task, delay));
|
||||
return true;
|
||||
}
|
||||
|
||||
return message_loop->task_runner()->PostNonNestableDelayedTask(
|
||||
from_here, task, delay);
|
||||
|
||||
@@ -5,17 +5,23 @@
|
||||
#ifndef ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
|
||||
#define ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/single_thread_task_runner.h"
|
||||
#include "base/tuple.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Post all tasks to the current message loop's task runner if available,
|
||||
// otherwise fail silently.
|
||||
// otherwise delay the work until message loop is ready.
|
||||
class BridgeTaskRunner : public base::SingleThreadTaskRunner {
|
||||
public:
|
||||
BridgeTaskRunner() {}
|
||||
~BridgeTaskRunner() override {}
|
||||
|
||||
// Called when message loop is ready.
|
||||
static void MessageLoopIsReady();
|
||||
|
||||
// base::SingleThreadTaskRunner:
|
||||
bool PostDelayedTask(const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
@@ -27,6 +33,11 @@ class BridgeTaskRunner : public base::SingleThreadTaskRunner {
|
||||
base::TimeDelta delay) override;
|
||||
|
||||
private:
|
||||
using TaskPair = base::Tuple<
|
||||
tracked_objects::Location, base::Closure, base::TimeDelta>;
|
||||
static std::vector<TaskPair> tasks_;
|
||||
static std::vector<TaskPair> non_nestable_tasks_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BridgeTaskRunner);
|
||||
};
|
||||
|
||||
|
||||
@@ -53,8 +53,14 @@ void Browser::Shutdown() {
|
||||
is_quiting_ = true;
|
||||
|
||||
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnQuit());
|
||||
base::MessageLoop::current()->PostTask(
|
||||
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
|
||||
|
||||
if (base::MessageLoop::current()) {
|
||||
base::MessageLoop::current()->PostTask(
|
||||
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
|
||||
} else {
|
||||
// There is no message loop available so we are in early stage.
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Browser::GetVersion() const {
|
||||
|
||||
@@ -130,6 +130,7 @@ class Browser : public WindowListObserver {
|
||||
observers_.RemoveObserver(obs);
|
||||
}
|
||||
|
||||
bool is_shutting_down() const { return is_shutdown_; }
|
||||
bool is_quiting() const { return is_quiting_; }
|
||||
bool is_ready() const { return is_ready_; }
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@ for (var i = 0; i < argv.length; i++) {
|
||||
if (argv[i] == '--version' || argv[i] == '-v') {
|
||||
option.version = true;
|
||||
break;
|
||||
} else if (argv[i].match(/^--app=/)) {
|
||||
option.file = argv[i].split('=')[1];
|
||||
break;
|
||||
} else if (argv[i] == '--help' || argv[i] == '-h') {
|
||||
option.help = true;
|
||||
break;
|
||||
@@ -260,7 +263,7 @@ if (option.file && !option.webdriver) {
|
||||
helpMessage += "A path to an Electron application may be specified. The path must be to \n";
|
||||
helpMessage += "an index.js file or to a folder containing a package.json or index.js file.\n\n";
|
||||
helpMessage += "Options:\n";
|
||||
helpMessage += " -r, --require Module to preload (option can be repeated)";
|
||||
helpMessage += " -r, --require Module to preload (option can be repeated)\n";
|
||||
helpMessage += " -h, --help Print this usage message.\n";
|
||||
helpMessage += " -v, --version Print the version.";
|
||||
console.log(helpMessage);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "atom/browser/javascript_environment.h"
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "gin/array_buffer.h"
|
||||
#include "gin/v8_initializer.h"
|
||||
|
||||
@@ -20,7 +21,12 @@ JavascriptEnvironment::JavascriptEnvironment()
|
||||
}
|
||||
|
||||
bool JavascriptEnvironment::Initialize() {
|
||||
gin::V8Initializer::LoadV8Snapshot();
|
||||
auto cmd = base::CommandLine::ForCurrentProcess();
|
||||
if (cmd->HasSwitch("debug-brk")) {
|
||||
// Need to be called before v8::Initialize().
|
||||
const char expose_debug_as[] = "--expose_debug_as=v8debug";
|
||||
v8::V8::SetFlagsFromString(expose_debug_as, sizeof(expose_debug_as) - 1);
|
||||
}
|
||||
gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode,
|
||||
gin::ArrayBufferAllocator::SharedInstance());
|
||||
return true;
|
||||
|
||||
@@ -67,7 +67,7 @@ ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', (event, guestId, method,
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', (event, guestId, message, targetOrigin) ->
|
||||
guestContents = BrowserWindow.fromId(guestId)?.webContents
|
||||
if guestContents?.getUrl().indexOf(targetOrigin) is 0 or targetOrigin is '*'
|
||||
guestContents.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', message, targetOrigin
|
||||
guestContents.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', guestId, message, targetOrigin
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', (event, guestId, message, targetOrigin, sourceOrigin) ->
|
||||
embedder = v8Util.getHiddenValue event.sender, 'embedder'
|
||||
|
||||
@@ -21,10 +21,15 @@ globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
|
||||
if process.platform is 'win32'
|
||||
# Redirect node's console to use our own implementations, since node can not
|
||||
# handle console output when running as GUI program.
|
||||
print = (args...) ->
|
||||
process.log util.format(args...)
|
||||
console.log = console.error = console.warn = print
|
||||
process.stdout.write = process.stderr.write = print
|
||||
consoleLog = (args...) ->
|
||||
process.log util.format(args...) + "\n"
|
||||
streamWrite = (chunk, encoding, callback) ->
|
||||
chunk = chunk.toString(encoding) if Buffer.isBuffer chunk
|
||||
process.log chunk
|
||||
callback() if callback
|
||||
true
|
||||
console.log = console.error = console.warn = consoleLog
|
||||
process.stdout.write = process.stderr.write = streamWrite
|
||||
|
||||
# Always returns EOF for stdin stream.
|
||||
Readable = require('stream').Readable
|
||||
|
||||
@@ -34,6 +34,7 @@ class ObjectsRegistry extends EventEmitter
|
||||
@dereference id, 1
|
||||
# Also reduce the count in owner.
|
||||
pointer = @owners[webContentsId]
|
||||
return unless pointer?
|
||||
--pointer[id]
|
||||
delete pointer[id] if pointer[id] is 0
|
||||
|
||||
@@ -57,6 +58,7 @@ class ObjectsRegistry extends EventEmitter
|
||||
# Private: Dereference the object from store.
|
||||
dereference: (id, count) ->
|
||||
pointer = @storage[id]
|
||||
return unless pointer?
|
||||
pointer.count -= count
|
||||
if pointer.count is 0
|
||||
v8Util.deleteHiddenValue pointer.object, 'atomId'
|
||||
|
||||
@@ -10,6 +10,8 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
||||
meta.type = 'buffer' if Buffer.isBuffer value
|
||||
meta.type = 'value' if value is null
|
||||
meta.type = 'array' if Array.isArray value
|
||||
meta.type = 'error' if value instanceof Error
|
||||
meta.type = 'date' if value instanceof Date
|
||||
meta.type = 'promise' if value? and value.constructor.name is 'Promise'
|
||||
|
||||
# Treat simple objects as value.
|
||||
@@ -36,6 +38,10 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
||||
meta.value = Array::slice.call value, 0
|
||||
else if meta.type is 'promise'
|
||||
meta.then = valueToMeta(sender, value.then.bind(value))
|
||||
else if meta.type is 'error'
|
||||
meta.message = value.message
|
||||
else if meta.type is 'date'
|
||||
meta.value = value.getTime()
|
||||
else
|
||||
meta.type = 'value'
|
||||
meta.value = value
|
||||
@@ -43,8 +49,8 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
||||
meta
|
||||
|
||||
# Convert Error into meta data.
|
||||
errorToMeta = (error) ->
|
||||
type: 'error', message: error.message, stack: (error.stack || error)
|
||||
exceptionToMeta = (error) ->
|
||||
type: 'exception', message: error.message, stack: (error.stack || error)
|
||||
|
||||
# Convert array of meta data from renderer into array of real values.
|
||||
unwrapArgs = (sender, args) ->
|
||||
@@ -69,7 +75,9 @@ unwrapArgs = (sender, args) ->
|
||||
rendererReleased = true
|
||||
|
||||
ret = ->
|
||||
throw new Error('Calling a callback of released renderer view') if rendererReleased
|
||||
if rendererReleased
|
||||
throw new Error("Attempting to call a function in a renderer window
|
||||
that has been closed or released. Function provided here: #{meta.id}.")
|
||||
sender.send 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, arguments)
|
||||
v8Util.setDestructor ret, ->
|
||||
return if rendererReleased
|
||||
@@ -98,19 +106,19 @@ ipc.on 'ATOM_BROWSER_REQUIRE', (event, module) ->
|
||||
try
|
||||
event.returnValue = valueToMeta event.sender, process.mainModule.require(module)
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_GLOBAL', (event, name) ->
|
||||
try
|
||||
event.returnValue = valueToMeta event.sender, global[name]
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event) ->
|
||||
try
|
||||
event.returnValue = valueToMeta event.sender, event.sender.getOwnerBrowserWindow()
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_CURRENT_WEB_CONTENTS', (event) ->
|
||||
event.returnValue = valueToMeta event.sender, event.sender
|
||||
@@ -124,7 +132,7 @@ ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, id, args) ->
|
||||
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
||||
event.returnValue = valueToMeta event.sender, obj
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, id, args) ->
|
||||
try
|
||||
@@ -132,7 +140,7 @@ ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, id, args) ->
|
||||
func = objectsRegistry.get id
|
||||
callFunction event, func, global, args
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) ->
|
||||
try
|
||||
@@ -142,7 +150,7 @@ ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) ->
|
||||
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
||||
event.returnValue = valueToMeta event.sender, obj
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, id, method, args) ->
|
||||
try
|
||||
@@ -150,7 +158,7 @@ ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, id, method, args) ->
|
||||
obj = objectsRegistry.get id
|
||||
callFunction event, obj[method], obj, args
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, id, name, value) ->
|
||||
try
|
||||
@@ -158,14 +166,14 @@ ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, id, name, value) ->
|
||||
obj[name] = value
|
||||
event.returnValue = null
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, id, name) ->
|
||||
try
|
||||
obj = objectsRegistry.get id
|
||||
event.returnValue = valueToMeta event.sender, obj[name]
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_DEREFERENCE', (event, id) ->
|
||||
objectsRegistry.remove event.sender.getId(), id
|
||||
@@ -175,4 +183,4 @@ ipc.on 'ATOM_BROWSER_GUEST_WEB_CONTENTS', (event, guestInstanceId) ->
|
||||
guestViewManager = require './guest-view-manager'
|
||||
event.returnValue = valueToMeta event.sender, guestViewManager.getGuest(guestInstanceId)
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
@@ -43,11 +43,20 @@
|
||||
atom::Browser::Get()->OpenURL(base::SysNSStringToUTF8(url));
|
||||
}
|
||||
|
||||
- (bool)voiceOverEnabled {
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults addSuiteNamed:@"com.apple.universalaccess"];
|
||||
[defaults synchronize];
|
||||
|
||||
return [defaults boolForKey:@"voiceOverOnOffKey"];
|
||||
}
|
||||
|
||||
- (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
|
||||
// Undocumented attribute that VoiceOver happens to set while running.
|
||||
// Chromium uses this too, even though it's not exactly right.
|
||||
if ([attribute isEqualToString:@"AXEnhancedUserInterface"]) {
|
||||
[self updateAccessibilityEnabled:[value boolValue]];
|
||||
bool enableAccessibility = ([self voiceOverEnabled] && [value boolValue]);
|
||||
[self updateAccessibilityEnabled:enableAccessibility];
|
||||
}
|
||||
return [super accessibilitySetValue:value forAttribute:attribute];
|
||||
}
|
||||
|
||||
@@ -43,26 +43,6 @@ DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::NativeWindowRelay);
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// Convert draggable regions in raw format to SkRegion format. Caller is
|
||||
// responsible for deleting the returned SkRegion instance.
|
||||
scoped_ptr<SkRegion> DraggableRegionsToSkRegion(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
scoped_ptr<SkRegion> sk_region(new SkRegion);
|
||||
for (const DraggableRegion& region : regions) {
|
||||
sk_region->op(
|
||||
region.bounds.x(),
|
||||
region.bounds.y(),
|
||||
region.bounds.right(),
|
||||
region.bounds.bottom(),
|
||||
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
|
||||
}
|
||||
return sk_region.Pass();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NativeWindow::NativeWindow(
|
||||
brightray::InspectableWebContents* inspectable_web_contents,
|
||||
const mate::Dictionary& options)
|
||||
@@ -112,27 +92,35 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
|
||||
int x = -1, y = -1;
|
||||
bool center;
|
||||
if (options.Get(switches::kX, &x) && options.Get(switches::kY, &y)) {
|
||||
int width = -1, height = -1;
|
||||
options.Get(switches::kWidth, &width);
|
||||
options.Get(switches::kHeight, &height);
|
||||
SetBounds(gfx::Rect(x, y, width, height));
|
||||
SetPosition(gfx::Point(x, y));
|
||||
} else if (options.Get(switches::kCenter, ¢er) && center) {
|
||||
Center();
|
||||
}
|
||||
// On Linux and Window we may already have maximum size defined.
|
||||
extensions::SizeConstraints size_constraints(GetContentSizeConstraints());
|
||||
int min_height = 0, min_width = 0;
|
||||
if (options.Get(switches::kMinHeight, &min_height) |
|
||||
options.Get(switches::kMinWidth, &min_width)) {
|
||||
SetMinimumSize(gfx::Size(min_width, min_height));
|
||||
size_constraints.set_minimum_size(gfx::Size(min_width, min_height));
|
||||
}
|
||||
int max_height = INT_MAX, max_width = INT_MAX;
|
||||
if (options.Get(switches::kMaxHeight, &max_height) |
|
||||
options.Get(switches::kMaxWidth, &max_width)) {
|
||||
SetMaximumSize(gfx::Size(max_width, max_height));
|
||||
size_constraints.set_maximum_size(gfx::Size(max_width, max_height));
|
||||
}
|
||||
bool use_content_size = false;
|
||||
options.Get(switches::kUseContentSize, &use_content_size);
|
||||
if (use_content_size) {
|
||||
SetContentSizeConstraints(size_constraints);
|
||||
} else {
|
||||
SetSizeConstraints(size_constraints);
|
||||
}
|
||||
#if defined(OS_WIN) || defined(USE_X11)
|
||||
bool resizable;
|
||||
if (options.Get(switches::kResizable, &resizable)) {
|
||||
SetResizable(resizable);
|
||||
}
|
||||
#endif
|
||||
bool top;
|
||||
if (options.Get(switches::kAlwaysOnTop, &top) && top) {
|
||||
SetAlwaysOnTop(true);
|
||||
@@ -151,6 +139,10 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
|
||||
if (options.Get(switches::kKiosk, &kiosk) && kiosk) {
|
||||
SetKiosk(kiosk);
|
||||
}
|
||||
std::string color;
|
||||
if (options.Get(switches::kBackgroundColor, &color)) {
|
||||
SetBackgroundColor(color);
|
||||
}
|
||||
std::string title("Electron");
|
||||
options.Get(switches::kTitle, &title);
|
||||
SetTitle(title);
|
||||
@@ -178,6 +170,67 @@ gfx::Point NativeWindow::GetPosition() {
|
||||
return GetBounds().origin();
|
||||
}
|
||||
|
||||
void NativeWindow::SetContentSize(const gfx::Size& size) {
|
||||
SetSize(ContentSizeToWindowSize(size));
|
||||
}
|
||||
|
||||
gfx::Size NativeWindow::GetContentSize() {
|
||||
return WindowSizeToContentSize(GetSize());
|
||||
}
|
||||
|
||||
void NativeWindow::SetSizeConstraints(
|
||||
const extensions::SizeConstraints& window_constraints) {
|
||||
extensions::SizeConstraints content_constraints;
|
||||
if (window_constraints.HasMaximumSize())
|
||||
content_constraints.set_maximum_size(
|
||||
WindowSizeToContentSize(window_constraints.GetMaximumSize()));
|
||||
if (window_constraints.HasMinimumSize())
|
||||
content_constraints.set_minimum_size(
|
||||
WindowSizeToContentSize(window_constraints.GetMinimumSize()));
|
||||
SetContentSizeConstraints(content_constraints);
|
||||
}
|
||||
|
||||
extensions::SizeConstraints NativeWindow::GetSizeConstraints() {
|
||||
extensions::SizeConstraints content_constraints = GetContentSizeConstraints();
|
||||
extensions::SizeConstraints window_constraints;
|
||||
if (content_constraints.HasMaximumSize())
|
||||
window_constraints.set_maximum_size(
|
||||
ContentSizeToWindowSize(content_constraints.GetMaximumSize()));
|
||||
if (content_constraints.HasMinimumSize())
|
||||
window_constraints.set_minimum_size(
|
||||
ContentSizeToWindowSize(content_constraints.GetMinimumSize()));
|
||||
return window_constraints;
|
||||
}
|
||||
|
||||
void NativeWindow::SetContentSizeConstraints(
|
||||
const extensions::SizeConstraints& size_constraints) {
|
||||
size_constraints_ = size_constraints;
|
||||
}
|
||||
|
||||
extensions::SizeConstraints NativeWindow::GetContentSizeConstraints() {
|
||||
return size_constraints_;
|
||||
}
|
||||
|
||||
void NativeWindow::SetMinimumSize(const gfx::Size& size) {
|
||||
extensions::SizeConstraints size_constraints;
|
||||
size_constraints.set_minimum_size(size);
|
||||
SetSizeConstraints(size_constraints);
|
||||
}
|
||||
|
||||
gfx::Size NativeWindow::GetMinimumSize() {
|
||||
return GetSizeConstraints().GetMinimumSize();
|
||||
}
|
||||
|
||||
void NativeWindow::SetMaximumSize(const gfx::Size& size) {
|
||||
extensions::SizeConstraints size_constraints;
|
||||
size_constraints.set_maximum_size(size);
|
||||
SetSizeConstraints(size_constraints);
|
||||
}
|
||||
|
||||
gfx::Size NativeWindow::GetMaximumSize() {
|
||||
return GetSizeConstraints().GetMaximumSize();
|
||||
}
|
||||
|
||||
void NativeWindow::SetRepresentedFilename(const std::string& filename) {
|
||||
}
|
||||
|
||||
@@ -411,6 +464,20 @@ void NativeWindow::NotifyWindowExecuteWindowsCommand(
|
||||
OnExecuteWindowsCommand(command));
|
||||
}
|
||||
|
||||
scoped_ptr<SkRegion> NativeWindow::DraggableRegionsToSkRegion(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
scoped_ptr<SkRegion> sk_region(new SkRegion);
|
||||
for (const DraggableRegion& region : regions) {
|
||||
sk_region->op(
|
||||
region.bounds.x(),
|
||||
region.bounds.y(),
|
||||
region.bounds.right(),
|
||||
region.bounds.bottom(),
|
||||
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
|
||||
}
|
||||
return sk_region.Pass();
|
||||
}
|
||||
|
||||
void NativeWindow::RenderViewCreated(
|
||||
content::RenderViewHost* render_view_host) {
|
||||
if (!transparent_)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "content/public/browser/readback_types.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/browser/web_contents_user_data.h"
|
||||
#include "extensions/browser/app_window/size_constraints.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
|
||||
@@ -110,12 +111,18 @@ class NativeWindow : public base::SupportsUserData,
|
||||
virtual gfx::Size GetSize();
|
||||
virtual void SetPosition(const gfx::Point& position);
|
||||
virtual gfx::Point GetPosition();
|
||||
virtual void SetContentSize(const gfx::Size& size) = 0;
|
||||
virtual gfx::Size GetContentSize() = 0;
|
||||
virtual void SetMinimumSize(const gfx::Size& size) = 0;
|
||||
virtual gfx::Size GetMinimumSize() = 0;
|
||||
virtual void SetMaximumSize(const gfx::Size& size) = 0;
|
||||
virtual gfx::Size GetMaximumSize() = 0;
|
||||
virtual void SetContentSize(const gfx::Size& size);
|
||||
virtual gfx::Size GetContentSize();
|
||||
virtual void SetSizeConstraints(
|
||||
const extensions::SizeConstraints& size_constraints);
|
||||
virtual extensions::SizeConstraints GetSizeConstraints();
|
||||
virtual void SetContentSizeConstraints(
|
||||
const extensions::SizeConstraints& size_constraints);
|
||||
virtual extensions::SizeConstraints GetContentSizeConstraints();
|
||||
virtual void SetMinimumSize(const gfx::Size& size);
|
||||
virtual gfx::Size GetMinimumSize();
|
||||
virtual void SetMaximumSize(const gfx::Size& size);
|
||||
virtual gfx::Size GetMaximumSize();
|
||||
virtual void SetResizable(bool resizable) = 0;
|
||||
virtual bool IsResizable() = 0;
|
||||
virtual void SetAlwaysOnTop(bool top) = 0;
|
||||
@@ -127,6 +134,7 @@ class NativeWindow : public base::SupportsUserData,
|
||||
virtual void SetSkipTaskbar(bool skip) = 0;
|
||||
virtual void SetKiosk(bool kiosk) = 0;
|
||||
virtual bool IsKiosk() = 0;
|
||||
virtual void SetBackgroundColor(const std::string& color_name) = 0;
|
||||
virtual void SetRepresentedFilename(const std::string& filename);
|
||||
virtual std::string GetRepresentedFilename();
|
||||
virtual void SetDocumentEdited(bool edited);
|
||||
@@ -234,6 +242,19 @@ class NativeWindow : public base::SupportsUserData,
|
||||
NativeWindow(brightray::InspectableWebContents* inspectable_web_contents,
|
||||
const mate::Dictionary& options);
|
||||
|
||||
// Convert draggable regions in raw format to SkRegion format. Caller is
|
||||
// responsible for deleting the returned SkRegion instance.
|
||||
scoped_ptr<SkRegion> DraggableRegionsToSkRegion(
|
||||
const std::vector<DraggableRegion>& regions);
|
||||
|
||||
// Converts between content size to window size.
|
||||
virtual gfx::Size ContentSizeToWindowSize(const gfx::Size& size) = 0;
|
||||
virtual gfx::Size WindowSizeToContentSize(const gfx::Size& size) = 0;
|
||||
|
||||
// Called when the window needs to update its draggable region.
|
||||
virtual void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions);
|
||||
|
||||
// content::WebContentsObserver:
|
||||
void RenderViewCreated(content::RenderViewHost* render_view_host) override;
|
||||
void BeforeUnloadDialogCancelled() override;
|
||||
@@ -241,10 +262,6 @@ class NativeWindow : public base::SupportsUserData,
|
||||
bool OnMessageReceived(const IPC::Message& message) override;
|
||||
|
||||
private:
|
||||
// Called when the window needs to update its draggable region.
|
||||
void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions);
|
||||
|
||||
// Schedule a notification unresponsive event.
|
||||
void ScheduleUnresponsiveEvent(int ms);
|
||||
|
||||
@@ -269,6 +286,9 @@ class NativeWindow : public base::SupportsUserData,
|
||||
// has to been explicitly provided.
|
||||
scoped_ptr<SkRegion> draggable_region_; // used in custom drag.
|
||||
|
||||
// Minimum and maximum size, stored as content size.
|
||||
extensions::SizeConstraints size_constraints_;
|
||||
|
||||
// Whether window can be resized larger than screen.
|
||||
bool enable_larger_than_screen_;
|
||||
|
||||
|
||||
@@ -44,12 +44,8 @@ class NativeWindowMac : public NativeWindow {
|
||||
bool IsFullscreen() const override;
|
||||
void SetBounds(const gfx::Rect& bounds) override;
|
||||
gfx::Rect GetBounds() override;
|
||||
void SetContentSize(const gfx::Size& size) override;
|
||||
gfx::Size GetContentSize() override;
|
||||
void SetMinimumSize(const gfx::Size& size) override;
|
||||
gfx::Size GetMinimumSize() override;
|
||||
void SetMaximumSize(const gfx::Size& size) override;
|
||||
gfx::Size GetMaximumSize() override;
|
||||
void SetContentSizeConstraints(
|
||||
const extensions::SizeConstraints& size_constraints) override;
|
||||
void SetResizable(bool resizable) override;
|
||||
bool IsResizable() override;
|
||||
void SetAlwaysOnTop(bool top) override;
|
||||
@@ -61,6 +57,7 @@ class NativeWindowMac : public NativeWindow {
|
||||
void SetSkipTaskbar(bool skip) override;
|
||||
void SetKiosk(bool kiosk) override;
|
||||
bool IsKiosk() override;
|
||||
void SetBackgroundColor(const std::string& color_name) override;
|
||||
void SetRepresentedFilename(const std::string& filename) override;
|
||||
std::string GetRepresentedFilename() override;
|
||||
void SetDocumentEdited(bool edited) override;
|
||||
@@ -75,12 +72,10 @@ class NativeWindowMac : public NativeWindow {
|
||||
void SetVisibleOnAllWorkspaces(bool visible) override;
|
||||
bool IsVisibleOnAllWorkspaces() override;
|
||||
|
||||
// Returns true if |point| in local Cocoa coordinate system falls within
|
||||
// the draggable region.
|
||||
bool IsWithinDraggableRegion(NSPoint point) const;
|
||||
|
||||
// Called to handle a mouse event.
|
||||
void HandleMouseEvent(NSEvent* event);
|
||||
// Refresh the DraggableRegion views.
|
||||
void UpdateDraggableRegionViews() {
|
||||
UpdateDraggableRegionViews(draggable_regions_);
|
||||
}
|
||||
|
||||
protected:
|
||||
// NativeWindow:
|
||||
@@ -88,13 +83,24 @@ class NativeWindowMac : public NativeWindow {
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent&) override;
|
||||
|
||||
// Return a vector of non-draggable regions that fill a window of size
|
||||
// |width| by |height|, but leave gaps where the window should be draggable.
|
||||
std::vector<gfx::Rect> CalculateNonDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions, int width, int height);
|
||||
|
||||
private:
|
||||
// NativeWindow:
|
||||
gfx::Size ContentSizeToWindowSize(const gfx::Size& size) override;
|
||||
gfx::Size WindowSizeToContentSize(const gfx::Size& size) override;
|
||||
void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) override;
|
||||
|
||||
void InstallView();
|
||||
void UninstallView();
|
||||
|
||||
// Install the drag view, which will cover the whole window and decides
|
||||
// whehter we can drag.
|
||||
void InstallDraggableRegionView();
|
||||
void UpdateDraggableRegionViews(const std::vector<DraggableRegion>& regions);
|
||||
|
||||
base::scoped_nsobject<AtomNSWindow> window_;
|
||||
base::scoped_nsobject<AtomNSWindowDelegate> window_delegate_;
|
||||
@@ -102,6 +108,8 @@ class NativeWindowMac : public NativeWindow {
|
||||
// The view that will fill the whole frameless window.
|
||||
base::scoped_nsobject<FullSizeContentView> content_view_;
|
||||
|
||||
std::vector<DraggableRegion> draggable_regions_;
|
||||
|
||||
bool is_kiosk_;
|
||||
|
||||
NSInteger attention_request_id_; // identifier from requestUserAttention
|
||||
@@ -109,10 +117,6 @@ class NativeWindowMac : public NativeWindow {
|
||||
// The presentation options before entering kiosk mode.
|
||||
NSApplicationPresentationOptions kiosk_options_;
|
||||
|
||||
// Mouse location since the last mouse event, in screen coordinates. This is
|
||||
// used in custom drag to compute the window movement.
|
||||
NSPoint last_mouse_offset_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowMac);
|
||||
};
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/gfx/skia_util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -146,6 +147,7 @@ bool ScopedDisableResize::disable_resize_ = false;
|
||||
}
|
||||
|
||||
- (void)windowDidResize:(NSNotification*)notification {
|
||||
shell_->UpdateDraggableRegionViews();
|
||||
shell_->NotifyWindowResize();
|
||||
}
|
||||
|
||||
@@ -257,43 +259,23 @@ bool ScopedDisableResize::disable_resize_ = false;
|
||||
|
||||
@end
|
||||
|
||||
@interface ControlRegionView : NSView {
|
||||
@private
|
||||
atom::NativeWindowMac* shellWindow_; // Weak; owns self.
|
||||
}
|
||||
@interface ControlRegionView : NSView
|
||||
@end
|
||||
|
||||
@implementation ControlRegionView
|
||||
|
||||
- (id)initWithShellWindow:(atom::NativeWindowMac*)shellWindow {
|
||||
if ((self = [super init]))
|
||||
shellWindow_ = shellWindow;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)mouseDownCanMoveWindow {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSView*)hitTest:(NSPoint)aPoint {
|
||||
if (!shellWindow_->IsWithinDraggableRegion(aPoint)) {
|
||||
return nil;
|
||||
}
|
||||
return self;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent*)event {
|
||||
shellWindow_->HandleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(NSEvent*)event {
|
||||
shellWindow_->HandleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstMouse:(NSEvent*)event {
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface NSView (WebContentsView)
|
||||
- (void)setMouseDownCanMoveWindow:(BOOL)can_move;
|
||||
@end
|
||||
|
||||
@interface AtomProgressBar : NSProgressIndicator
|
||||
@@ -350,6 +332,8 @@ NativeWindowMac::NativeWindowMac(
|
||||
|
||||
bool useStandardWindow = true;
|
||||
options.Get(switches::kStandardWindow, &useStandardWindow);
|
||||
bool resizable = true;
|
||||
options.Get(switches::kResizable, &resizable);
|
||||
|
||||
// New title bar styles are available in Yosemite or newer
|
||||
std::string titleBarStyle;
|
||||
@@ -357,10 +341,13 @@ NativeWindowMac::NativeWindowMac(
|
||||
options.Get(switches::kTitleBarStyle, &titleBarStyle);
|
||||
|
||||
NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask |
|
||||
NSMiniaturizableWindowMask | NSResizableWindowMask;
|
||||
NSMiniaturizableWindowMask;
|
||||
if (!useStandardWindow || transparent() || !has_frame()) {
|
||||
styleMask |= NSTexturedBackgroundWindowMask;
|
||||
}
|
||||
if (resizable) {
|
||||
styleMask |= NSResizableWindowMask;
|
||||
}
|
||||
if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) {
|
||||
styleMask |= NSFullSizeContentViewWindowMask;
|
||||
styleMask |= NSUnifiedTitleAndToolbarWindowMask;
|
||||
@@ -434,11 +421,6 @@ NativeWindowMac::NativeWindowMac(
|
||||
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
||||
|
||||
InstallView();
|
||||
|
||||
// Install the DraggableRegionView if it is forced to use draggable regions
|
||||
// for normal window.
|
||||
if (has_frame() && force_using_draggable_region())
|
||||
InstallDraggableRegionView();
|
||||
}
|
||||
|
||||
NativeWindowMac::~NativeWindowMac() {
|
||||
@@ -549,56 +531,30 @@ gfx::Rect NativeWindowMac::GetBounds() {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetContentSize(const gfx::Size& size) {
|
||||
if (!has_frame()) {
|
||||
SetSize(size);
|
||||
return;
|
||||
void NativeWindowMac::SetContentSizeConstraints(
|
||||
const extensions::SizeConstraints& size_constraints) {
|
||||
auto convertSize = [this](const gfx::Size& size) {
|
||||
// Our frameless window still has titlebar attached, so setting contentSize
|
||||
// will result in actual content size being larger.
|
||||
if (!has_frame()) {
|
||||
NSRect frame = NSMakeRect(0, 0, size.width(), size.height());
|
||||
NSRect content = [window_ contentRectForFrameRect:frame];
|
||||
return content.size;
|
||||
} else {
|
||||
return NSMakeSize(size.width(), size.height());
|
||||
}
|
||||
};
|
||||
|
||||
NSView* content = [window_ contentView];
|
||||
if (size_constraints.HasMinimumSize()) {
|
||||
NSSize min_size = convertSize(size_constraints.GetMinimumSize());
|
||||
[window_ setContentMinSize:[content convertSize:min_size toView:nil]];
|
||||
}
|
||||
|
||||
NSRect frame_nsrect = [window_ frame];
|
||||
NSSize frame = frame_nsrect.size;
|
||||
NSSize content = [window_ contentRectForFrameRect:frame_nsrect].size;
|
||||
|
||||
int width = size.width() + frame.width - content.width;
|
||||
int height = size.height() + frame.height - content.height;
|
||||
frame_nsrect.origin.y -= height - frame_nsrect.size.height;
|
||||
frame_nsrect.size.width = width;
|
||||
frame_nsrect.size.height = height;
|
||||
[window_ setFrame:frame_nsrect display:YES];
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowMac::GetContentSize() {
|
||||
if (!has_frame())
|
||||
return GetSize();
|
||||
|
||||
NSRect bounds = [[window_ contentView] bounds];
|
||||
return gfx::Size(bounds.size.width, bounds.size.height);
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetMinimumSize(const gfx::Size& size) {
|
||||
NSSize min_size = NSMakeSize(size.width(), size.height());
|
||||
NSView* content = [window_ contentView];
|
||||
[window_ setContentMinSize:[content convertSize:min_size toView:nil]];
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowMac::GetMinimumSize() {
|
||||
NSView* content = [window_ contentView];
|
||||
NSSize min_size = [content convertSize:[window_ contentMinSize]
|
||||
fromView:nil];
|
||||
return gfx::Size(min_size.width, min_size.height);
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetMaximumSize(const gfx::Size& size) {
|
||||
NSSize max_size = NSMakeSize(size.width(), size.height());
|
||||
NSView* content = [window_ contentView];
|
||||
[window_ setContentMaxSize:[content convertSize:max_size toView:nil]];
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowMac::GetMaximumSize() {
|
||||
NSView* content = [window_ contentView];
|
||||
NSSize max_size = [content convertSize:[window_ contentMaxSize]
|
||||
fromView:nil];
|
||||
return gfx::Size(max_size.width, max_size.height);
|
||||
if (size_constraints.HasMaximumSize()) {
|
||||
NSSize max_size = convertSize(size_constraints.GetMaximumSize());
|
||||
[window_ setContentMaxSize:[content convertSize:max_size toView:nil]];
|
||||
}
|
||||
NativeWindow::SetContentSizeConstraints(size_constraints);
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetResizable(bool resizable) {
|
||||
@@ -679,6 +635,9 @@ bool NativeWindowMac::IsKiosk() {
|
||||
return is_kiosk_;
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetBackgroundColor(const std::string& color_name) {
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetRepresentedFilename(const std::string& filename) {
|
||||
[window_ setRepresentedFilename:base::SysUTF8ToNSString(filename)];
|
||||
}
|
||||
@@ -767,36 +726,6 @@ bool NativeWindowMac::IsVisibleOnAllWorkspaces() {
|
||||
return collectionBehavior & NSWindowCollectionBehaviorCanJoinAllSpaces;
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
|
||||
if (!draggable_region())
|
||||
return false;
|
||||
if (!web_contents())
|
||||
return false;
|
||||
NSView* webView = web_contents()->GetNativeView();
|
||||
NSInteger webViewHeight = NSHeight([webView bounds]);
|
||||
// |draggable_region_| is stored in local platform-indepdent coordiate system
|
||||
// while |point| is in local Cocoa coordinate system. Do the conversion
|
||||
// to match these two.
|
||||
return draggable_region()->contains(point.x, webViewHeight - point.y);
|
||||
}
|
||||
|
||||
void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
|
||||
NSPoint eventLoc = [event locationInWindow];
|
||||
NSRect mouseRect = [window_ convertRectToScreen:NSMakeRect(eventLoc.x, eventLoc.y, 0, 0)];
|
||||
NSPoint current_mouse_location = mouseRect.origin;
|
||||
|
||||
if ([event type] == NSLeftMouseDown) {
|
||||
NSPoint frame_origin = [window_ frame].origin;
|
||||
last_mouse_offset_ = NSMakePoint(
|
||||
frame_origin.x - current_mouse_location.x,
|
||||
frame_origin.y - current_mouse_location.y);
|
||||
} else if ([event type] == NSLeftMouseDragged) {
|
||||
[window_ setFrameOrigin:NSMakePoint(
|
||||
current_mouse_location.x + last_mouse_offset_.x,
|
||||
current_mouse_location.y + last_mouse_offset_.y)];
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
@@ -821,6 +750,48 @@ void NativeWindowMac::HandleKeyboardEvent(
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<gfx::Rect> NativeWindowMac::CalculateNonDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions, int width, int height) {
|
||||
std::vector<gfx::Rect> result;
|
||||
if (regions.empty()) {
|
||||
result.push_back(gfx::Rect(0, 0, width, height));
|
||||
} else {
|
||||
scoped_ptr<SkRegion> draggable(DraggableRegionsToSkRegion(regions));
|
||||
scoped_ptr<SkRegion> non_draggable(new SkRegion);
|
||||
non_draggable->op(0, 0, width, height, SkRegion::kUnion_Op);
|
||||
non_draggable->op(*draggable, SkRegion::kDifference_Op);
|
||||
for (SkRegion::Iterator it(*non_draggable); !it.done(); it.next()) {
|
||||
result.push_back(gfx::SkIRectToRect(it.rect()));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowMac::ContentSizeToWindowSize(const gfx::Size& size) {
|
||||
if (!has_frame())
|
||||
return size;
|
||||
|
||||
NSRect content = NSMakeRect(0, 0, size.width(), size.height());
|
||||
NSRect frame = [window_ frameRectForContentRect:content];
|
||||
return gfx::Size(frame.size);
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowMac::WindowSizeToContentSize(const gfx::Size& size) {
|
||||
if (!has_frame())
|
||||
return size;
|
||||
|
||||
NSRect frame = NSMakeRect(0, 0, size.width(), size.height());
|
||||
NSRect content = [window_ contentRectForFrameRect:frame];
|
||||
return gfx::Size(content.size);
|
||||
}
|
||||
|
||||
void NativeWindowMac::UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
NativeWindow::UpdateDraggableRegions(regions);
|
||||
draggable_regions_ = regions;
|
||||
UpdateDraggableRegionViews(regions);
|
||||
}
|
||||
|
||||
void NativeWindowMac::InstallView() {
|
||||
// Make sure the bottom corner is rounded: http://crbug.com/396264.
|
||||
[[window_ contentView] setWantsLayer:YES];
|
||||
@@ -843,8 +814,6 @@ void NativeWindowMac::InstallView() {
|
||||
[view setFrame:[content_view_ bounds]];
|
||||
[content_view_ addSubview:view];
|
||||
|
||||
InstallDraggableRegionView();
|
||||
|
||||
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES];
|
||||
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
|
||||
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES];
|
||||
@@ -861,14 +830,55 @@ void NativeWindowMac::UninstallView() {
|
||||
[view removeFromSuperview];
|
||||
}
|
||||
|
||||
void NativeWindowMac::InstallDraggableRegionView() {
|
||||
void NativeWindowMac::UpdateDraggableRegionViews(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
if (has_frame() && !force_using_draggable_region())
|
||||
return;
|
||||
|
||||
// All ControlRegionViews should be added as children of the WebContentsView,
|
||||
// because WebContentsView will be removed and re-added when entering and
|
||||
// leaving fullscreen mode.
|
||||
NSView* webView = web_contents()->GetNativeView();
|
||||
base::scoped_nsobject<NSView> controlRegion(
|
||||
[[ControlRegionView alloc] initWithShellWindow:this]);
|
||||
[controlRegion setFrame:NSMakeRect(0, 0,
|
||||
NSWidth([webView bounds]),
|
||||
NSHeight([webView bounds]))];
|
||||
[webView addSubview:controlRegion];
|
||||
NSInteger webViewWidth = NSWidth([webView bounds]);
|
||||
NSInteger webViewHeight = NSHeight([webView bounds]);
|
||||
|
||||
[webView setMouseDownCanMoveWindow:YES];
|
||||
|
||||
// Remove all ControlRegionViews that are added last time.
|
||||
// Note that [webView subviews] returns the view's mutable internal array and
|
||||
// it should be copied to avoid mutating the original array while enumerating
|
||||
// it.
|
||||
base::scoped_nsobject<NSArray> subviews([[webView subviews] copy]);
|
||||
for (NSView* subview in subviews.get())
|
||||
if ([subview isKindOfClass:[ControlRegionView class]])
|
||||
[subview removeFromSuperview];
|
||||
|
||||
// Draggable regions is implemented by having the whole web view draggable
|
||||
// (mouseDownCanMoveWindow) and overlaying regions that are not draggable.
|
||||
std::vector<gfx::Rect> system_drag_exclude_areas =
|
||||
CalculateNonDraggableRegions(regions, webViewWidth, webViewHeight);
|
||||
|
||||
// Create and add a ControlRegionView for each region that needs to be
|
||||
// excluded from the dragging.
|
||||
for (std::vector<gfx::Rect>::const_iterator iter =
|
||||
system_drag_exclude_areas.begin();
|
||||
iter != system_drag_exclude_areas.end();
|
||||
++iter) {
|
||||
base::scoped_nsobject<NSView> controlRegion(
|
||||
[[ControlRegionView alloc] initWithFrame:NSZeroRect]);
|
||||
[controlRegion setFrame:NSMakeRect(iter->x(),
|
||||
webViewHeight - iter->bottom(),
|
||||
iter->width(),
|
||||
iter->height())];
|
||||
[webView addSubview:controlRegion];
|
||||
}
|
||||
|
||||
// AppKit will not update its cache of mouseDownCanMoveWindow unless something
|
||||
// changes. Previously we tried adding an NSView and removing it, but for some
|
||||
// reason it required reposting the mouse-down event, and didn't always work.
|
||||
// Calling the below seems to be an effective solution.
|
||||
[window_ setMovableByWindowBackground:NO];
|
||||
[window_ setMovableByWindowBackground:YES];
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#elif defined(OS_WIN)
|
||||
#include "atom/browser/ui/views/win_frame_view.h"
|
||||
#include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h"
|
||||
#include "skia/ext/skia_utils_win.h"
|
||||
#include "ui/base/win/shell.h"
|
||||
#include "ui/gfx/win/dpi.h"
|
||||
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
|
||||
@@ -77,69 +78,28 @@ bool IsAltModifier(const content::NativeWebKeyboardEvent& event) {
|
||||
(modifiers == (Modifiers::AltKey | Modifiers::IsRight));
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Convert Win32 WM_APPCOMMANDS to strings.
|
||||
const char* AppCommandToString(int command_id) {
|
||||
switch (command_id) {
|
||||
case APPCOMMAND_BROWSER_BACKWARD : return "browser-backward";
|
||||
case APPCOMMAND_BROWSER_FORWARD : return "browser-forward";
|
||||
case APPCOMMAND_BROWSER_REFRESH : return "browser-refresh";
|
||||
case APPCOMMAND_BROWSER_STOP : return "browser-stop";
|
||||
case APPCOMMAND_BROWSER_SEARCH : return "browser-search";
|
||||
case APPCOMMAND_BROWSER_FAVORITES : return "browser-favorites";
|
||||
case APPCOMMAND_BROWSER_HOME : return "browser-home";
|
||||
case APPCOMMAND_VOLUME_MUTE : return "volume-mute";
|
||||
case APPCOMMAND_VOLUME_DOWN : return "volume-down";
|
||||
case APPCOMMAND_VOLUME_UP : return "volume-up";
|
||||
case APPCOMMAND_MEDIA_NEXTTRACK : return "media-nexttrack";
|
||||
case APPCOMMAND_MEDIA_PREVIOUSTRACK : return "media-previoustrack";
|
||||
case APPCOMMAND_MEDIA_STOP : return "media-stop";
|
||||
case APPCOMMAND_MEDIA_PLAY_PAUSE : return "media-play_pause";
|
||||
case APPCOMMAND_LAUNCH_MAIL : return "launch-mail";
|
||||
case APPCOMMAND_LAUNCH_MEDIA_SELECT : return "launch-media-select";
|
||||
case APPCOMMAND_LAUNCH_APP1 : return "launch-app1";
|
||||
case APPCOMMAND_LAUNCH_APP2 : return "launch-app2";
|
||||
case APPCOMMAND_BASS_DOWN : return "bass-down";
|
||||
case APPCOMMAND_BASS_BOOST : return "bass-boost";
|
||||
case APPCOMMAND_BASS_UP : return "bass-up";
|
||||
case APPCOMMAND_TREBLE_DOWN : return "treble-down";
|
||||
case APPCOMMAND_TREBLE_UP : return "treble-up";
|
||||
case APPCOMMAND_MICROPHONE_VOLUME_MUTE : return "microphone-volume-mute";
|
||||
case APPCOMMAND_MICROPHONE_VOLUME_DOWN : return "microphone-volume-down";
|
||||
case APPCOMMAND_MICROPHONE_VOLUME_UP : return "microphone-volume-up";
|
||||
case APPCOMMAND_HELP : return "help";
|
||||
case APPCOMMAND_FIND : return "find";
|
||||
case APPCOMMAND_NEW : return "new";
|
||||
case APPCOMMAND_OPEN : return "open";
|
||||
case APPCOMMAND_CLOSE : return "close";
|
||||
case APPCOMMAND_SAVE : return "save";
|
||||
case APPCOMMAND_PRINT : return "print";
|
||||
case APPCOMMAND_UNDO : return "undo";
|
||||
case APPCOMMAND_REDO : return "redo";
|
||||
case APPCOMMAND_COPY : return "copy";
|
||||
case APPCOMMAND_CUT : return "cut";
|
||||
case APPCOMMAND_PASTE : return "paste";
|
||||
case APPCOMMAND_REPLY_TO_MAIL : return "reply-to-mail";
|
||||
case APPCOMMAND_FORWARD_MAIL : return "forward-mail";
|
||||
case APPCOMMAND_SEND_MAIL : return "send-mail";
|
||||
case APPCOMMAND_SPELL_CHECK : return "spell-check";
|
||||
case APPCOMMAND_MIC_ON_OFF_TOGGLE : return "mic-on-off-toggle";
|
||||
case APPCOMMAND_CORRECTION_LIST : return "correction-list";
|
||||
case APPCOMMAND_MEDIA_PLAY : return "media-play";
|
||||
case APPCOMMAND_MEDIA_PAUSE : return "media-pause";
|
||||
case APPCOMMAND_MEDIA_RECORD : return "media-record";
|
||||
case APPCOMMAND_MEDIA_FAST_FORWARD : return "media-fast-forward";
|
||||
case APPCOMMAND_MEDIA_REWIND : return "media-rewind";
|
||||
case APPCOMMAND_MEDIA_CHANNEL_UP : return "media-channel-up";
|
||||
case APPCOMMAND_MEDIA_CHANNEL_DOWN : return "media-channel-down";
|
||||
case APPCOMMAND_DELETE : return "delete";
|
||||
case APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE:
|
||||
return "dictate-or-command-control-toggle";
|
||||
default:
|
||||
return "unknown";
|
||||
SkColor ParseHexColor(const std::string& name) {
|
||||
SkColor result = 0xFF000000;
|
||||
unsigned value = 0;
|
||||
auto color = name.substr(1);
|
||||
unsigned length = color.size();
|
||||
if (length != 3 && length != 6)
|
||||
return result;
|
||||
for (unsigned i = 0; i < length; ++i) {
|
||||
if (!base::IsHexDigit(color[i]))
|
||||
return result;
|
||||
value <<= 4;
|
||||
value |= (color[i] < 'A' ? color[i] - '0' : (color[i] - 'A' + 10) & 0xF);
|
||||
}
|
||||
if (length == 6) {
|
||||
result |= value;
|
||||
return result;
|
||||
}
|
||||
result |= (value & 0xF00) << 12 | (value & 0xF00) << 8
|
||||
| (value & 0xF0) << 8 | (value & 0xF0) << 4
|
||||
| (value & 0xF) << 4 | (value & 0xF);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
class NativeWindowClientView : public views::ClientView {
|
||||
public:
|
||||
@@ -186,7 +146,8 @@ NativeWindowViews::NativeWindowViews(
|
||||
// will not allow us to resize the window larger than scree.
|
||||
// Setting directly to INT_MAX somehow doesn't work, so we just devide
|
||||
// by 10, which should still be large enough.
|
||||
maximum_size_.SetSize(INT_MAX / 10, INT_MAX / 10);
|
||||
SetContentSizeConstraints(extensions::SizeConstraints(
|
||||
gfx::Size(), gfx::Size(INT_MAX / 10, INT_MAX / 10)));
|
||||
|
||||
int width = 800, height = 600;
|
||||
options.Get(switches::kWidth, &width);
|
||||
@@ -268,13 +229,8 @@ NativeWindowViews::NativeWindowViews(
|
||||
|
||||
// Add web view.
|
||||
SetLayoutManager(new MenuLayout(this, kMenuBarHeight));
|
||||
set_background(views::Background::CreateStandardPanelBackground());
|
||||
AddChildView(web_view_);
|
||||
|
||||
if (has_frame() &&
|
||||
options.Get(switches::kUseContentSize, &use_content_size_) &&
|
||||
use_content_size_)
|
||||
bounds = ContentBoundsToWindowBounds(bounds);
|
||||
AddChildView(web_view_);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Save initial window state.
|
||||
@@ -283,6 +239,8 @@ NativeWindowViews::NativeWindowViews(
|
||||
else
|
||||
last_window_state_ = ui::SHOW_STATE_NORMAL;
|
||||
|
||||
last_normal_size_ = gfx::Size(widget_size_);
|
||||
|
||||
if (!has_frame()) {
|
||||
// Set Window style so that we get a minimize and maximize animation when
|
||||
// frameless.
|
||||
@@ -314,8 +272,14 @@ NativeWindowViews::NativeWindowViews(
|
||||
if (transparent() && !has_frame())
|
||||
wm::SetShadowType(GetNativeWindow(), wm::SHADOW_TYPE_NONE);
|
||||
|
||||
gfx::Size size = bounds.size();
|
||||
if (has_frame() &&
|
||||
options.Get(switches::kUseContentSize, &use_content_size_) &&
|
||||
use_content_size_)
|
||||
size = ContentSizeToWindowSize(size);
|
||||
|
||||
window_->UpdateWindowIcon();
|
||||
window_->CenterWindow(bounds.size());
|
||||
window_->CenterWindow(size);
|
||||
Layout();
|
||||
}
|
||||
|
||||
@@ -438,42 +402,26 @@ gfx::Rect NativeWindowViews::GetBounds() {
|
||||
return window_->GetWindowBoundsInScreen();
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetContentSize(const gfx::Size& size) {
|
||||
if (!has_frame()) {
|
||||
NativeWindow::SetSize(size);
|
||||
return;
|
||||
}
|
||||
|
||||
gfx::Rect bounds = window_->GetWindowBoundsInScreen();
|
||||
bounds.set_size(size);
|
||||
SetBounds(ContentBoundsToWindowBounds(bounds));
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetContentSize() {
|
||||
if (!has_frame())
|
||||
return GetSize();
|
||||
#if defined(OS_WIN)
|
||||
if (IsMinimized())
|
||||
return NativeWindow::GetContentSize();
|
||||
#endif
|
||||
|
||||
gfx::Size content_size =
|
||||
window_->non_client_view()->frame_view()->GetBoundsForClientView().size();
|
||||
if (menu_bar_ && menu_bar_visible_)
|
||||
content_size.set_height(content_size.height() - kMenuBarHeight);
|
||||
return content_size;
|
||||
return web_view_->size();
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetMinimumSize(const gfx::Size& size) {
|
||||
minimum_size_ = size;
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetMinimumSize() {
|
||||
return minimum_size_;
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetMaximumSize(const gfx::Size& size) {
|
||||
maximum_size_ = size;
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetMaximumSize() {
|
||||
return maximum_size_;
|
||||
void NativeWindowViews::SetContentSizeConstraints(
|
||||
const extensions::SizeConstraints& size_constraints) {
|
||||
NativeWindow::SetContentSizeConstraints(size_constraints);
|
||||
// widget_delegate() is only available after Init() is called, we make use of
|
||||
// this to determine whether native widget has initialized.
|
||||
if (window_ && window_->widget_delegate())
|
||||
window_->OnSizeConstraintsChanged();
|
||||
#if defined(USE_X11)
|
||||
if (resizable_)
|
||||
old_size_constraints_ = size_constraints;
|
||||
#endif
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetResizable(bool resizable) {
|
||||
@@ -492,11 +440,13 @@ void NativeWindowViews::SetResizable(bool resizable) {
|
||||
// On Linux there is no "resizable" property of a window, we have to set
|
||||
// both the minimum and maximum size to the window size to achieve it.
|
||||
if (resizable) {
|
||||
SetMaximumSize(gfx::Size());
|
||||
SetMinimumSize(gfx::Size());
|
||||
SetContentSizeConstraints(old_size_constraints_);
|
||||
} else {
|
||||
SetMaximumSize(GetSize());
|
||||
SetMinimumSize(GetSize());
|
||||
old_size_constraints_ = GetContentSizeConstraints();
|
||||
resizable_ = false;
|
||||
gfx::Size content_size = GetContentSize();
|
||||
SetContentSizeConstraints(
|
||||
extensions::SizeConstraints(content_size, content_size));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -570,6 +520,21 @@ bool NativeWindowViews::IsKiosk() {
|
||||
return IsFullscreen();
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetBackgroundColor(const std::string& color_name) {
|
||||
// web views' background color.
|
||||
SkColor background_color = ParseHexColor(color_name);
|
||||
set_background(views::Background::CreateSolidBackground(background_color));
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Set the background color of native window.
|
||||
HBRUSH brush = CreateSolidBrush(skia::SkColorToCOLORREF(background_color));
|
||||
ULONG_PTR previous_brush = SetClassLongPtr(
|
||||
GetAcceleratedWidget(), GCLP_HBRBACKGROUND, (LONG)brush);
|
||||
if (previous_brush)
|
||||
DeleteObject((HBRUSH)previous_brush);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
|
||||
if (menu_model == nullptr) {
|
||||
// Remove accelerators
|
||||
@@ -608,8 +573,24 @@ void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
|
||||
|
||||
if (!menu_bar_autohide_) {
|
||||
SetMenuBarVisibility(true);
|
||||
if (use_content_size_)
|
||||
if (use_content_size_) {
|
||||
// Enlarge the size constraints for the menu.
|
||||
extensions::SizeConstraints constraints = GetContentSizeConstraints();
|
||||
if (constraints.HasMinimumSize()) {
|
||||
gfx::Size min_size = constraints.GetMinimumSize();
|
||||
min_size.set_height(min_size.height() + kMenuBarHeight);
|
||||
constraints.set_minimum_size(min_size);
|
||||
}
|
||||
if (constraints.HasMaximumSize()) {
|
||||
gfx::Size max_size = constraints.GetMaximumSize();
|
||||
max_size.set_height(max_size.height() + kMenuBarHeight);
|
||||
constraints.set_maximum_size(max_size);
|
||||
}
|
||||
SetContentSizeConstraints(constraints);
|
||||
|
||||
// Resize the window to make sure content size is not changed.
|
||||
SetContentSize(content_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -812,68 +793,47 @@ void NativeWindowViews::OnWidgetMove() {
|
||||
NotifyWindowMove();
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::ContentSizeToWindowSize(const gfx::Size& size) {
|
||||
if (!has_frame())
|
||||
return size;
|
||||
|
||||
gfx::Size window_size(size);
|
||||
#if defined(OS_WIN)
|
||||
bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
|
||||
std::string command = AppCommandToString(command_id);
|
||||
NotifyWindowExecuteWindowsCommand(command);
|
||||
return false;
|
||||
}
|
||||
gfx::Rect dpi_bounds =
|
||||
gfx::Rect(gfx::Point(), gfx::win::DIPToScreenSize(size));
|
||||
gfx::Rect window_bounds = gfx::win::ScreenToDIPRect(
|
||||
window_->non_client_view()->GetWindowBoundsForClientBounds(dpi_bounds));
|
||||
window_size = window_bounds.size();
|
||||
#endif
|
||||
|
||||
if (menu_bar_ && menu_bar_visible_)
|
||||
window_size.set_height(window_size.height() + kMenuBarHeight);
|
||||
return window_size;
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::WindowSizeToContentSize(const gfx::Size& size) {
|
||||
if (!has_frame())
|
||||
return size;
|
||||
|
||||
gfx::Size content_size(size);
|
||||
#if defined(OS_WIN)
|
||||
bool NativeWindowViews::PreHandleMSG(
|
||||
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) {
|
||||
switch (message) {
|
||||
case WM_COMMAND:
|
||||
// Handle thumbar button click message.
|
||||
if (HIWORD(w_param) == THBN_CLICKED)
|
||||
return taskbar_host_.HandleThumbarButtonEvent(LOWORD(w_param));
|
||||
return false;
|
||||
case WM_SIZE:
|
||||
// Handle window state change.
|
||||
HandleSizeEvent(w_param, l_param);
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
|
||||
// Here we handle the WM_SIZE event in order to figure out what is the current
|
||||
// window state and notify the user accordingly.
|
||||
switch (w_param) {
|
||||
case SIZE_MAXIMIZED:
|
||||
last_window_state_ = ui::SHOW_STATE_MAXIMIZED;
|
||||
NotifyWindowMaximize();
|
||||
break;
|
||||
case SIZE_MINIMIZED:
|
||||
last_window_state_ = ui::SHOW_STATE_MINIMIZED;
|
||||
NotifyWindowMinimize();
|
||||
break;
|
||||
case SIZE_RESTORED:
|
||||
if (last_window_state_ == ui::SHOW_STATE_NORMAL)
|
||||
return;
|
||||
|
||||
switch (last_window_state_) {
|
||||
case ui::SHOW_STATE_MAXIMIZED:
|
||||
last_window_state_ = ui::SHOW_STATE_NORMAL;
|
||||
NotifyWindowUnmaximize();
|
||||
break;
|
||||
case ui::SHOW_STATE_MINIMIZED:
|
||||
if (IsFullscreen()) {
|
||||
last_window_state_ = ui::SHOW_STATE_FULLSCREEN;
|
||||
NotifyWindowEnterFullScreen();
|
||||
} else {
|
||||
last_window_state_ = ui::SHOW_STATE_NORMAL;
|
||||
NotifyWindowRestore();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
content_size = gfx::win::DIPToScreenSize(content_size);
|
||||
RECT rect;
|
||||
SetRectEmpty(&rect);
|
||||
HWND hwnd = GetAcceleratedWidget();
|
||||
DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
|
||||
DWORD ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
AdjustWindowRectEx(&rect, style, FALSE, ex_style);
|
||||
content_size.set_width(content_size.width() - (rect.right - rect.left));
|
||||
content_size.set_height(content_size.height() - (rect.bottom - rect.top));
|
||||
content_size = gfx::win::ScreenToDIPSize(content_size);
|
||||
#endif
|
||||
|
||||
if (menu_bar_ && menu_bar_visible_)
|
||||
content_size.set_height(content_size.height() - kMenuBarHeight);
|
||||
return content_size;
|
||||
}
|
||||
|
||||
void NativeWindowViews::HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
@@ -915,6 +875,14 @@ void NativeWindowViews::HandleKeyboardEvent(
|
||||
}
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetMinimumSize() {
|
||||
return NativeWindow::GetMinimumSize();
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetMaximumSize() {
|
||||
return NativeWindow::GetMaximumSize();
|
||||
}
|
||||
|
||||
bool NativeWindowViews::AcceleratorPressed(const ui::Accelerator& accelerator) {
|
||||
return accelerator_util::TriggerAcceleratorTableCommand(
|
||||
&accelerator_table_, accelerator);
|
||||
@@ -937,26 +905,6 @@ void NativeWindowViews::RegisterAccelerators(ui::MenuModel* menu_model) {
|
||||
}
|
||||
}
|
||||
|
||||
gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
|
||||
const gfx::Rect& bounds) {
|
||||
gfx::Point origin = bounds.origin();
|
||||
#if defined(OS_WIN)
|
||||
gfx::Rect dpi_bounds = gfx::win::DIPToScreenRect(bounds);
|
||||
gfx::Rect window_bounds = gfx::win::ScreenToDIPRect(
|
||||
window_->non_client_view()->GetWindowBoundsForClientBounds(dpi_bounds));
|
||||
#else
|
||||
gfx::Rect window_bounds =
|
||||
window_->non_client_view()->GetWindowBoundsForClientBounds(bounds);
|
||||
#endif
|
||||
// The window's position would also be changed, but we only want to change
|
||||
// the size.
|
||||
window_bounds.set_origin(origin);
|
||||
|
||||
if (menu_bar_ && menu_bar_visible_)
|
||||
window_bounds.set_height(window_bounds.height() + kMenuBarHeight);
|
||||
return window_bounds;
|
||||
}
|
||||
|
||||
ui::WindowShowState NativeWindowViews::GetRestoredState() {
|
||||
if (IsMaximized())
|
||||
return ui::SHOW_STATE_MAXIMIZED;
|
||||
|
||||
@@ -63,12 +63,9 @@ class NativeWindowViews : public NativeWindow,
|
||||
bool IsFullscreen() const override;
|
||||
void SetBounds(const gfx::Rect& bounds) override;
|
||||
gfx::Rect GetBounds() override;
|
||||
void SetContentSize(const gfx::Size& size) override;
|
||||
gfx::Size GetContentSize() override;
|
||||
void SetMinimumSize(const gfx::Size& size) override;
|
||||
gfx::Size GetMinimumSize() override;
|
||||
void SetMaximumSize(const gfx::Size& size) override;
|
||||
gfx::Size GetMaximumSize() override;
|
||||
void SetContentSizeConstraints(
|
||||
const extensions::SizeConstraints& size_constraints) override;
|
||||
void SetResizable(bool resizable) override;
|
||||
bool IsResizable() override;
|
||||
void SetAlwaysOnTop(bool top) override;
|
||||
@@ -80,6 +77,7 @@ class NativeWindowViews : public NativeWindow,
|
||||
void SetSkipTaskbar(bool skip) override;
|
||||
void SetKiosk(bool kiosk) override;
|
||||
bool IsKiosk() override;
|
||||
void SetBackgroundColor(const std::string& color_name) override;
|
||||
void SetMenu(ui::MenuModel* menu_model) override;
|
||||
gfx::NativeWindow GetNativeWindow() override;
|
||||
void SetOverlayIcon(const gfx::Image& overlay,
|
||||
@@ -140,20 +138,20 @@ class NativeWindowViews : public NativeWindow,
|
||||
#endif
|
||||
|
||||
// NativeWindow:
|
||||
gfx::Size ContentSizeToWindowSize(const gfx::Size& size) override;
|
||||
gfx::Size WindowSizeToContentSize(const gfx::Size& size) override;
|
||||
void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) override;
|
||||
|
||||
// views::View:
|
||||
gfx::Size GetMinimumSize() override;
|
||||
gfx::Size GetMaximumSize() override;
|
||||
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
|
||||
|
||||
// Register accelerators supported by the menu model.
|
||||
void RegisterAccelerators(ui::MenuModel* menu_model);
|
||||
|
||||
// Converts between client area and window area, since we include the menu bar
|
||||
// in client area we need to substract/add menu bar's height in convertions.
|
||||
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& content_bounds);
|
||||
|
||||
// Returns the restore state for the window.
|
||||
ui::WindowShowState GetRestoredState();
|
||||
|
||||
@@ -170,12 +168,23 @@ class NativeWindowViews : public NativeWindow,
|
||||
|
||||
// Handles window state events.
|
||||
scoped_ptr<WindowStateWatcher> window_state_watcher_;
|
||||
|
||||
// The "resizable" flag on Linux is implemented by setting size constraints,
|
||||
// we need to make sure size constraints are restored when window becomes
|
||||
// resizable again.
|
||||
extensions::SizeConstraints old_size_constraints_;
|
||||
#elif defined(OS_WIN)
|
||||
// Weak ref.
|
||||
AtomDesktopWindowTreeHostWin* atom_desktop_window_tree_host_win_;
|
||||
|
||||
ui::WindowShowState last_window_state_;
|
||||
|
||||
// There's an issue with restore on Windows, that sometimes causes the Window
|
||||
// to receive the wrong size (#2498). To circumvent that, we keep tabs on the
|
||||
// size of the window while in the normal state (not maximized, minimized or
|
||||
// fullscreen), so we restore it correctly.
|
||||
gfx::Size last_normal_size_;
|
||||
|
||||
// In charge of running taskbar related APIs.
|
||||
TaskbarHost taskbar_host_;
|
||||
#endif
|
||||
@@ -189,8 +198,6 @@ class NativeWindowViews : public NativeWindow,
|
||||
bool use_content_size_;
|
||||
bool resizable_;
|
||||
std::string title_;
|
||||
gfx::Size minimum_size_;
|
||||
gfx::Size maximum_size_;
|
||||
gfx::Size widget_size_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowViews);
|
||||
|
||||
145
atom/browser/native_window_views_win.cc
Normal file
145
atom/browser/native_window_views_win.cc
Normal file
@@ -0,0 +1,145 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/native_window_views.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// Convert Win32 WM_APPCOMMANDS to strings.
|
||||
const char* AppCommandToString(int command_id) {
|
||||
switch (command_id) {
|
||||
case APPCOMMAND_BROWSER_BACKWARD : return "browser-backward";
|
||||
case APPCOMMAND_BROWSER_FORWARD : return "browser-forward";
|
||||
case APPCOMMAND_BROWSER_REFRESH : return "browser-refresh";
|
||||
case APPCOMMAND_BROWSER_STOP : return "browser-stop";
|
||||
case APPCOMMAND_BROWSER_SEARCH : return "browser-search";
|
||||
case APPCOMMAND_BROWSER_FAVORITES : return "browser-favorites";
|
||||
case APPCOMMAND_BROWSER_HOME : return "browser-home";
|
||||
case APPCOMMAND_VOLUME_MUTE : return "volume-mute";
|
||||
case APPCOMMAND_VOLUME_DOWN : return "volume-down";
|
||||
case APPCOMMAND_VOLUME_UP : return "volume-up";
|
||||
case APPCOMMAND_MEDIA_NEXTTRACK : return "media-nexttrack";
|
||||
case APPCOMMAND_MEDIA_PREVIOUSTRACK : return "media-previoustrack";
|
||||
case APPCOMMAND_MEDIA_STOP : return "media-stop";
|
||||
case APPCOMMAND_MEDIA_PLAY_PAUSE : return "media-play_pause";
|
||||
case APPCOMMAND_LAUNCH_MAIL : return "launch-mail";
|
||||
case APPCOMMAND_LAUNCH_MEDIA_SELECT : return "launch-media-select";
|
||||
case APPCOMMAND_LAUNCH_APP1 : return "launch-app1";
|
||||
case APPCOMMAND_LAUNCH_APP2 : return "launch-app2";
|
||||
case APPCOMMAND_BASS_DOWN : return "bass-down";
|
||||
case APPCOMMAND_BASS_BOOST : return "bass-boost";
|
||||
case APPCOMMAND_BASS_UP : return "bass-up";
|
||||
case APPCOMMAND_TREBLE_DOWN : return "treble-down";
|
||||
case APPCOMMAND_TREBLE_UP : return "treble-up";
|
||||
case APPCOMMAND_MICROPHONE_VOLUME_MUTE : return "microphone-volume-mute";
|
||||
case APPCOMMAND_MICROPHONE_VOLUME_DOWN : return "microphone-volume-down";
|
||||
case APPCOMMAND_MICROPHONE_VOLUME_UP : return "microphone-volume-up";
|
||||
case APPCOMMAND_HELP : return "help";
|
||||
case APPCOMMAND_FIND : return "find";
|
||||
case APPCOMMAND_NEW : return "new";
|
||||
case APPCOMMAND_OPEN : return "open";
|
||||
case APPCOMMAND_CLOSE : return "close";
|
||||
case APPCOMMAND_SAVE : return "save";
|
||||
case APPCOMMAND_PRINT : return "print";
|
||||
case APPCOMMAND_UNDO : return "undo";
|
||||
case APPCOMMAND_REDO : return "redo";
|
||||
case APPCOMMAND_COPY : return "copy";
|
||||
case APPCOMMAND_CUT : return "cut";
|
||||
case APPCOMMAND_PASTE : return "paste";
|
||||
case APPCOMMAND_REPLY_TO_MAIL : return "reply-to-mail";
|
||||
case APPCOMMAND_FORWARD_MAIL : return "forward-mail";
|
||||
case APPCOMMAND_SEND_MAIL : return "send-mail";
|
||||
case APPCOMMAND_SPELL_CHECK : return "spell-check";
|
||||
case APPCOMMAND_MIC_ON_OFF_TOGGLE : return "mic-on-off-toggle";
|
||||
case APPCOMMAND_CORRECTION_LIST : return "correction-list";
|
||||
case APPCOMMAND_MEDIA_PLAY : return "media-play";
|
||||
case APPCOMMAND_MEDIA_PAUSE : return "media-pause";
|
||||
case APPCOMMAND_MEDIA_RECORD : return "media-record";
|
||||
case APPCOMMAND_MEDIA_FAST_FORWARD : return "media-fast-forward";
|
||||
case APPCOMMAND_MEDIA_REWIND : return "media-rewind";
|
||||
case APPCOMMAND_MEDIA_CHANNEL_UP : return "media-channel-up";
|
||||
case APPCOMMAND_MEDIA_CHANNEL_DOWN : return "media-channel-down";
|
||||
case APPCOMMAND_DELETE : return "delete";
|
||||
case APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE:
|
||||
return "dictate-or-command-control-toggle";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
|
||||
std::string command = AppCommandToString(command_id);
|
||||
NotifyWindowExecuteWindowsCommand(command);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NativeWindowViews::PreHandleMSG(
|
||||
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) {
|
||||
switch (message) {
|
||||
case WM_COMMAND:
|
||||
// Handle thumbar button click message.
|
||||
if (HIWORD(w_param) == THBN_CLICKED)
|
||||
return taskbar_host_.HandleThumbarButtonEvent(LOWORD(w_param));
|
||||
return false;
|
||||
case WM_SIZE:
|
||||
// Handle window state change.
|
||||
HandleSizeEvent(w_param, l_param);
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
|
||||
// Here we handle the WM_SIZE event in order to figure out what is the current
|
||||
// window state and notify the user accordingly.
|
||||
switch (w_param) {
|
||||
case SIZE_MAXIMIZED:
|
||||
last_window_state_ = ui::SHOW_STATE_MAXIMIZED;
|
||||
NotifyWindowMaximize();
|
||||
break;
|
||||
case SIZE_MINIMIZED:
|
||||
last_window_state_ = ui::SHOW_STATE_MINIMIZED;
|
||||
NotifyWindowMinimize();
|
||||
break;
|
||||
case SIZE_RESTORED:
|
||||
if (last_window_state_ == ui::SHOW_STATE_NORMAL) {
|
||||
// Window was resized so we save it's new size.
|
||||
last_normal_size_ = GetSize();
|
||||
} else {
|
||||
switch (last_window_state_) {
|
||||
case ui::SHOW_STATE_MAXIMIZED:
|
||||
last_window_state_ = ui::SHOW_STATE_NORMAL;
|
||||
|
||||
// When the window is restored we resize it to the previous known
|
||||
// normal size.
|
||||
NativeWindow::SetSize(last_normal_size_);
|
||||
|
||||
NotifyWindowUnmaximize();
|
||||
break;
|
||||
case ui::SHOW_STATE_MINIMIZED:
|
||||
if (IsFullscreen()) {
|
||||
last_window_state_ = ui::SHOW_STATE_FULLSCREEN;
|
||||
NotifyWindowEnterFullScreen();
|
||||
} else {
|
||||
last_window_state_ = ui::SHOW_STATE_NORMAL;
|
||||
|
||||
// When the window is restored we resize it to the previous known
|
||||
// normal size.
|
||||
NativeWindow::SetSize(last_normal_size_);
|
||||
|
||||
NotifyWindowRestore();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
@@ -35,17 +35,14 @@ NodeDebugger::NodeDebugger(v8::Isolate* isolate)
|
||||
weak_factory_(this) {
|
||||
bool use_debug_agent = false;
|
||||
int port = 5858;
|
||||
bool wait_for_connection = false;
|
||||
|
||||
std::string port_str;
|
||||
base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
|
||||
if (cmd->HasSwitch("debug")) {
|
||||
use_debug_agent = true;
|
||||
port_str = cmd->GetSwitchValueASCII("debug");
|
||||
}
|
||||
if (cmd->HasSwitch("debug-brk")) {
|
||||
} else if (cmd->HasSwitch("debug-brk")) {
|
||||
use_debug_agent = true;
|
||||
wait_for_connection = true;
|
||||
port_str = cmd->GetSwitchValueASCII("debug-brk");
|
||||
}
|
||||
|
||||
@@ -56,9 +53,6 @@ NodeDebugger::NodeDebugger(v8::Isolate* isolate)
|
||||
isolate_->SetData(kIsolateSlot, this);
|
||||
v8::Debug::SetMessageHandler(DebugMessageHandler);
|
||||
|
||||
if (wait_for_connection)
|
||||
v8::Debug::DebugBreak(isolate_);
|
||||
|
||||
uv_async_init(uv_default_loop(), &weak_up_ui_handle_, ProcessMessageInUI);
|
||||
|
||||
// Start a new IO thread.
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>atom.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.33.6</string>
|
||||
<string>0.34.1</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.34.1</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.developer-tools</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.8.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
|
||||
@@ -56,8 +56,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,33,6,0
|
||||
PRODUCTVERSION 0,33,6,0
|
||||
FILEVERSION 0,34,1,0
|
||||
PRODUCTVERSION 0,34,1,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -74,12 +74,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "0.33.6"
|
||||
VALUE "FileVersion", "0.34.1"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "0.33.6"
|
||||
VALUE "ProductVersion", "0.34.1"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
||||
@@ -55,7 +55,7 @@ void TrayIcon::NotifyRightClicked(const gfx::Rect& bounds, int modifiers) {
|
||||
OnRightClicked(bounds, modifiers));
|
||||
}
|
||||
|
||||
void TrayIcon::NotfiyDropFiles(const std::vector<std::string>& files) {
|
||||
void TrayIcon::NotifyDropFiles(const std::vector<std::string>& files) {
|
||||
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDropFiles(files));
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ class TrayIcon {
|
||||
void NotifyBalloonClosed();
|
||||
void NotifyRightClicked(const gfx::Rect& bounds = gfx::Rect(),
|
||||
int modifiers = 0);
|
||||
void NotfiyDropFiles(const std::vector<std::string>& files);
|
||||
void NotifyDropFiles(const std::vector<std::string>& files);
|
||||
|
||||
protected:
|
||||
TrayIcon();
|
||||
|
||||
@@ -265,7 +265,7 @@ const CGFloat kVerticalTitleMargin = 2;
|
||||
NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
|
||||
for (NSString* file in files)
|
||||
dropFiles.push_back(base::SysNSStringToUTF8(file));
|
||||
trayIcon_->NotfiyDropFiles(dropFiles);
|
||||
trayIcon_->NotifyDropFiles(dropFiles);
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
|
||||
@@ -104,11 +104,11 @@ gfx::Size FramelessView::GetPreferredSize() const {
|
||||
}
|
||||
|
||||
gfx::Size FramelessView::GetMinimumSize() const {
|
||||
return window_->GetMinimumSize();
|
||||
return window_->GetContentSizeConstraints().GetMinimumSize();
|
||||
}
|
||||
|
||||
gfx::Size FramelessView::GetMaximumSize() const {
|
||||
return window_->GetMaximumSize();
|
||||
return window_->GetContentSizeConstraints().GetMaximumSize();
|
||||
}
|
||||
|
||||
const char* FramelessView::GetClassName() const {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "atom/browser/ui/views/native_frame_view.h"
|
||||
|
||||
#include "atom/browser/native_window_views.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -14,8 +14,7 @@ const char kViewClassName[] = "AtomNativeFrameView";
|
||||
|
||||
} // namespace
|
||||
|
||||
NativeFrameView::NativeFrameView(NativeWindowViews* window,
|
||||
views::Widget* widget)
|
||||
NativeFrameView::NativeFrameView(NativeWindow* window, views::Widget* widget)
|
||||
: views::NativeFrameView(widget),
|
||||
window_(window) {
|
||||
}
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeWindowViews;
|
||||
class NativeWindow;
|
||||
|
||||
// Like the views::NativeFrameView, but returns the min/max size from the
|
||||
// NativeWindowViews.
|
||||
class NativeFrameView : public views::NativeFrameView {
|
||||
public:
|
||||
NativeFrameView(NativeWindowViews* window, views::Widget* widget);
|
||||
NativeFrameView(NativeWindow* window, views::Widget* widget);
|
||||
|
||||
protected:
|
||||
// views::View:
|
||||
@@ -24,7 +24,7 @@ class NativeFrameView : public views::NativeFrameView {
|
||||
const char* GetClassName() const override;
|
||||
|
||||
private:
|
||||
NativeWindowViews* window_; // weak ref.
|
||||
NativeWindow* window_; // weak ref.
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeFrameView);
|
||||
};
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "atom/browser/ui/views/win_frame_view.h"
|
||||
|
||||
#include "atom/browser/native_window_views.h"
|
||||
#include "ui/gfx/win/dpi.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/win/hwnd_util.h"
|
||||
|
||||
@@ -39,16 +38,6 @@ int WinFrameView::NonClientHitTest(const gfx::Point& point) {
|
||||
return FramelessView::NonClientHitTest(point);
|
||||
}
|
||||
|
||||
gfx::Size WinFrameView::GetMinimumSize() const {
|
||||
gfx::Size size = FramelessView::GetMinimumSize();
|
||||
return gfx::win::DIPToScreenSize(size);
|
||||
}
|
||||
|
||||
gfx::Size WinFrameView::GetMaximumSize() const {
|
||||
gfx::Size size = FramelessView::GetMaximumSize();
|
||||
return gfx::win::DIPToScreenSize(size);
|
||||
}
|
||||
|
||||
const char* WinFrameView::GetClassName() const {
|
||||
return kViewClassName;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ class WinFrameView : public FramelessView {
|
||||
int NonClientHitTest(const gfx::Point& point) override;
|
||||
|
||||
// views::View:
|
||||
gfx::Size GetMinimumSize() const override;
|
||||
gfx::Size GetMaximumSize() const override;
|
||||
const char* GetClassName() const override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -26,7 +26,6 @@ namespace {
|
||||
const char* kWebRuntimeFeatures[] = {
|
||||
switches::kExperimentalFeatures,
|
||||
switches::kExperimentalCanvasFeatures,
|
||||
switches::kSubpixelFontScaling,
|
||||
switches::kOverlayScrollbars,
|
||||
switches::kOverlayFullscreenVideo,
|
||||
switches::kSharedWorker,
|
||||
|
||||
@@ -30,6 +30,12 @@ IPC_SYNC_MESSAGE_ROUTED2_1(AtomViewHostMsg_Message_Sync,
|
||||
base::ListValue /* arguments */,
|
||||
base::string16 /* result (in JSON) */)
|
||||
|
||||
IPC_MESSAGE_ROUTED1(AtomViewHostMsg_ZoomLevelChanged,
|
||||
double /* level */)
|
||||
|
||||
IPC_MESSAGE_ROUTED1(AtomViewMsg_SetZoomLevel,
|
||||
double /* level */)
|
||||
|
||||
IPC_MESSAGE_ROUTED2(AtomViewMsg_Message,
|
||||
base::string16 /* channel */,
|
||||
base::ListValue /* arguments */)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "atom/common/atom_version.h"
|
||||
#include "atom/common/chrome_version.h"
|
||||
@@ -40,7 +41,7 @@ void FatalErrorCallback(const char* location, const char* message) {
|
||||
}
|
||||
|
||||
void Log(const base::string16& message) {
|
||||
logging::LogMessage("CONSOLE", 0, 0).stream() << message;
|
||||
std::cout << message << std::flush;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -71,6 +72,10 @@ void AtomBindings::BindTo(v8::Isolate* isolate,
|
||||
// Do not warn about deprecated APIs.
|
||||
dict.Set("noDeprecation", true);
|
||||
|
||||
#if defined(MAS_BUILD)
|
||||
dict.Set("mas", true);
|
||||
#endif
|
||||
|
||||
mate::Dictionary versions;
|
||||
if (dict.Get("versions", &versions)) {
|
||||
versions.Set(ATOM_PROJECT_NAME, ATOM_VERSION_STRING);
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
savedGlobal = global # the "global.global" might be deleted later
|
||||
|
||||
module.exports =
|
||||
class CallbacksRegistry
|
||||
constructor: ->
|
||||
@emptyFunc = -> throw new Error "Browser trying to call a non-exist callback
|
||||
in renderer, this usually happens when renderer code forgot to release
|
||||
a callback installed on objects in browser when renderer was going to be
|
||||
unloaded or released."
|
||||
@nextId = 0
|
||||
@callbacks = {}
|
||||
|
||||
add: (callback) ->
|
||||
id = Math.random().toString()
|
||||
id = ++@nextId
|
||||
|
||||
# Capture the location of the function and put it in the ID string,
|
||||
# so that release errors can be tracked down easily.
|
||||
regexp = /at (.*)/gi
|
||||
stackString = (new Error).stack
|
||||
|
||||
while (match = regexp.exec(stackString)) isnt null
|
||||
[x, location] = match
|
||||
continue if location.indexOf('(native)') isnt -1
|
||||
continue if location.indexOf('atom.asar') isnt -1
|
||||
[x, filenameAndLine] = /([^/^\)]*)\)?$/gi.exec(location)
|
||||
id = "#{filenameAndLine} (#{id})"
|
||||
break
|
||||
|
||||
@callbacks[id] = callback
|
||||
id
|
||||
|
||||
@@ -18,10 +27,10 @@ class CallbacksRegistry
|
||||
@callbacks[id] ? ->
|
||||
|
||||
call: (id, args...) ->
|
||||
@get(id).call savedGlobal, args...
|
||||
@get(id).call global, args...
|
||||
|
||||
apply: (id, args...) ->
|
||||
@get(id).apply savedGlobal, args...
|
||||
@get(id).apply global, args...
|
||||
|
||||
remove: (id) ->
|
||||
delete @callbacks[id]
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#define ATOM_VERSION_H
|
||||
|
||||
#define ATOM_MAJOR_VERSION 0
|
||||
#define ATOM_MINOR_VERSION 33
|
||||
#define ATOM_PATCH_VERSION 6
|
||||
#define ATOM_MINOR_VERSION 34
|
||||
#define ATOM_PATCH_VERSION 1
|
||||
|
||||
#define ATOM_VERSION_IS_RELEASE 1
|
||||
|
||||
|
||||
@@ -64,4 +64,23 @@ CrashReporter::GetUploadedReports(const std::string& path) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void CrashReporter::InitBreakpad(const std::string& product_name,
|
||||
const std::string& version,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
bool auto_submit,
|
||||
bool skip_system_crash_handler) {
|
||||
}
|
||||
|
||||
void CrashReporter::SetUploadParameters() {
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX) && defined(MAS_BUILD)
|
||||
// static
|
||||
CrashReporter* CrashReporter::GetInstance() {
|
||||
static CrashReporter crash_reporter;
|
||||
return &crash_reporter;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace crash_reporter
|
||||
|
||||
@@ -40,8 +40,8 @@ class CrashReporter {
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
bool auto_submit,
|
||||
bool skip_system_crash_handler) = 0;
|
||||
virtual void SetUploadParameters() = 0;
|
||||
bool skip_system_crash_handler);
|
||||
virtual void SetUploadParameters();
|
||||
|
||||
StringMap upload_parameters_;
|
||||
bool is_browser_;
|
||||
|
||||
@@ -11,6 +11,25 @@
|
||||
#include "base/memory/singleton.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "content/public/common/result_codes.h"
|
||||
#include "gin/public/debug.h"
|
||||
#include "sandbox/win/src/nt_internals.h"
|
||||
|
||||
#pragma intrinsic(_AddressOfReturnAddress)
|
||||
#pragma intrinsic(_ReturnAddress)
|
||||
|
||||
#ifdef _WIN64
|
||||
// See http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
|
||||
typedef struct _UNWIND_INFO {
|
||||
unsigned char Version : 3;
|
||||
unsigned char Flags : 5;
|
||||
unsigned char SizeOfProlog;
|
||||
unsigned char CountOfCodes;
|
||||
unsigned char FrameRegister : 4;
|
||||
unsigned char FrameOffset : 4;
|
||||
ULONG ExceptionHandler;
|
||||
} UNWIND_INFO, *PUNWIND_INFO;
|
||||
#endif
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
@@ -24,6 +43,94 @@ const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
|
||||
const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent";
|
||||
const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service";
|
||||
|
||||
typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle,
|
||||
NTSTATUS ExitStatus);
|
||||
char* g_real_terminate_process_stub = NULL;
|
||||
|
||||
void TerminateProcessWithoutDump() {
|
||||
// Patched stub exists based on conditions (See InitCrashReporter).
|
||||
// As a side note this function also gets called from
|
||||
// WindowProcExceptionFilter.
|
||||
if (g_real_terminate_process_stub == NULL) {
|
||||
::TerminateProcess(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
|
||||
} else {
|
||||
NtTerminateProcessPtr real_terminate_proc =
|
||||
reinterpret_cast<NtTerminateProcessPtr>(
|
||||
static_cast<char*>(g_real_terminate_process_stub));
|
||||
real_terminate_proc(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
int CrashForExceptionInNonABICompliantCodeRange(
|
||||
PEXCEPTION_RECORD ExceptionRecord,
|
||||
ULONG64 EstablisherFrame,
|
||||
PCONTEXT ContextRecord,
|
||||
PDISPATCHER_CONTEXT DispatcherContext) {
|
||||
EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord };
|
||||
if (!CrashReporter::GetInstance())
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
return static_cast<CrashReporterWin*>(CrashReporter::GetInstance())->
|
||||
CrashForException(&info);
|
||||
}
|
||||
|
||||
struct ExceptionHandlerRecord {
|
||||
RUNTIME_FUNCTION runtime_function;
|
||||
UNWIND_INFO unwind_info;
|
||||
unsigned char thunk[12];
|
||||
};
|
||||
|
||||
void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
|
||||
ExceptionHandlerRecord* record =
|
||||
reinterpret_cast<ExceptionHandlerRecord*>(start);
|
||||
|
||||
// We assume that the first page of the code range is executable and
|
||||
// committed and reserved for breakpad. What could possibly go wrong?
|
||||
|
||||
// All addresses are 32bit relative offsets to start.
|
||||
record->runtime_function.BeginAddress = 0;
|
||||
record->runtime_function.EndAddress =
|
||||
base::checked_cast<DWORD>(size_in_bytes);
|
||||
record->runtime_function.UnwindData =
|
||||
offsetof(ExceptionHandlerRecord, unwind_info);
|
||||
|
||||
// Create unwind info that only specifies an exception handler.
|
||||
record->unwind_info.Version = 1;
|
||||
record->unwind_info.Flags = UNW_FLAG_EHANDLER;
|
||||
record->unwind_info.SizeOfProlog = 0;
|
||||
record->unwind_info.CountOfCodes = 0;
|
||||
record->unwind_info.FrameRegister = 0;
|
||||
record->unwind_info.FrameOffset = 0;
|
||||
record->unwind_info.ExceptionHandler =
|
||||
offsetof(ExceptionHandlerRecord, thunk);
|
||||
|
||||
// Hardcoded thunk.
|
||||
// mov imm64, rax
|
||||
record->thunk[0] = 0x48;
|
||||
record->thunk[1] = 0xb8;
|
||||
void* handler = &CrashForExceptionInNonABICompliantCodeRange;
|
||||
memcpy(&record->thunk[2], &handler, 8);
|
||||
|
||||
// jmp rax
|
||||
record->thunk[10] = 0xff;
|
||||
record->thunk[11] = 0xe0;
|
||||
|
||||
// Protect reserved page against modifications.
|
||||
DWORD old_protect;
|
||||
CHECK(VirtualProtect(
|
||||
start, sizeof(ExceptionHandlerRecord), PAGE_EXECUTE_READ, &old_protect));
|
||||
CHECK(RtlAddFunctionTable(
|
||||
&record->runtime_function, 1, reinterpret_cast<DWORD64>(start)));
|
||||
}
|
||||
|
||||
void UnregisterNonABICompliantCodeRange(void* start) {
|
||||
ExceptionHandlerRecord* record =
|
||||
reinterpret_cast<ExceptionHandlerRecord*>(start);
|
||||
|
||||
CHECK(RtlDeleteFunctionTable(&record->runtime_function));
|
||||
}
|
||||
#endif // _WIN64
|
||||
|
||||
} // namespace
|
||||
|
||||
CrashReporterWin::CrashReporterWin() {
|
||||
@@ -63,26 +170,46 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
|
||||
// to allow any previous handler to detach in the correct order.
|
||||
breakpad_.reset();
|
||||
|
||||
int handler_types = google_breakpad::ExceptionHandler::HANDLER_EXCEPTION |
|
||||
google_breakpad::ExceptionHandler::HANDLER_PURECALL;
|
||||
breakpad_.reset(new google_breakpad::ExceptionHandler(
|
||||
temp_dir.value(),
|
||||
FilterCallback,
|
||||
MinidumpCallback,
|
||||
this,
|
||||
handler_types,
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL,
|
||||
kSmallDumpType,
|
||||
pipe_name.c_str(),
|
||||
GetCustomInfo(product_name, version, company_name)));
|
||||
|
||||
if (!breakpad_->IsOutOfProcess())
|
||||
LOG(ERROR) << "Cannot initialize out-of-process crash handler";
|
||||
|
||||
#ifdef _WIN64
|
||||
// Hook up V8 to breakpad.
|
||||
{
|
||||
// gin::Debug::SetCodeRangeCreatedCallback only runs the callback when
|
||||
// Isolate is just created, so we have to manually run following code here.
|
||||
void* code_range = nullptr;
|
||||
size_t size = 0;
|
||||
v8::Isolate::GetCurrent()->GetCodeRange(&code_range, &size);
|
||||
if (code_range && size)
|
||||
RegisterNonABICompliantCodeRange(code_range, size);
|
||||
}
|
||||
gin::Debug::SetCodeRangeDeletedCallback(UnregisterNonABICompliantCodeRange);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CrashReporterWin::SetUploadParameters() {
|
||||
upload_parameters_["platform"] = "win32";
|
||||
}
|
||||
|
||||
int CrashReporterWin::CrashForException(EXCEPTION_POINTERS* info) {
|
||||
if (breakpad_) {
|
||||
breakpad_->WriteMinidumpForException(info);
|
||||
TerminateProcessWithoutDump();
|
||||
}
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
// static
|
||||
bool CrashReporterWin::FilterCallback(void* context,
|
||||
EXCEPTION_POINTERS* exinfo,
|
||||
|
||||
@@ -29,6 +29,9 @@ class CrashReporterWin : public CrashReporter {
|
||||
bool skip_system_crash_handler) override;
|
||||
void SetUploadParameters() override;
|
||||
|
||||
// Crashes the process after generating a dump for the provided exception.
|
||||
int CrashForException(EXCEPTION_POINTERS* info);
|
||||
|
||||
private:
|
||||
friend struct DefaultSingletonTraits<CrashReporterWin>;
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ bool CrashService::Initialize(const base::string16& application_name,
|
||||
// service is initialized.
|
||||
base::string16 wait_name = ReplaceStringPlaceholders(
|
||||
kWaitEventFormat, application_name, NULL);
|
||||
HANDLE wait_event = ::CreateEventW(NULL, TRUE, FALSE, wait_name.c_str());
|
||||
HANDLE wait_event = ::CreateEventW(NULL, TRUE, TRUE, wait_name.c_str());
|
||||
::SetEvent(wait_event);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -10,9 +10,10 @@ namespace atom {
|
||||
ui::KeyboardCode KeyboardCodeFromCharCode(char c, bool* shifted) {
|
||||
*shifted = false;
|
||||
switch (c) {
|
||||
case 8: case 0x7F: return ui::VKEY_BACK;
|
||||
case 9: return ui::VKEY_TAB;
|
||||
case 0xD: case 3: return ui::VKEY_RETURN;
|
||||
case 0x08: return ui::VKEY_BACK;
|
||||
case 0x7F: return ui::VKEY_DELETE;
|
||||
case 0x09: return ui::VKEY_TAB;
|
||||
case 0x0D: return ui::VKEY_RETURN;
|
||||
case 0x1B: return ui::VKEY_ESCAPE;
|
||||
case ' ': return ui::VKEY_SPACE;
|
||||
|
||||
|
||||
@@ -263,7 +263,9 @@ exports.wrapFsWithAsar = (fs) ->
|
||||
|
||||
info = archive.getFileInfo filePath
|
||||
notFoundError asarPath, filePath unless info
|
||||
return new Buffer(0) if info.size is 0
|
||||
|
||||
if info.size is 0
|
||||
return if options then '' else new Buffer(0)
|
||||
|
||||
if info.unpacked
|
||||
realPath = archive.copyFileOut filePath
|
||||
|
||||
@@ -61,7 +61,7 @@ struct Converter<blink::WebInputEvent::Type> {
|
||||
else if (type == "mousewheel")
|
||||
*out = blink::WebInputEvent::MouseWheel;
|
||||
else if (type == "keydown")
|
||||
*out = blink::WebInputEvent::KeyDown;
|
||||
*out = blink::WebInputEvent::RawKeyDown;
|
||||
else if (type == "keyup")
|
||||
*out = blink::WebInputEvent::KeyUp;
|
||||
else if (type == "char")
|
||||
|
||||
@@ -152,6 +152,10 @@ v8::Local<v8::Value> V8ValueConverter::ToV8ValueImpl(
|
||||
return ToV8Object(isolate,
|
||||
static_cast<const base::DictionaryValue*>(value));
|
||||
|
||||
case base::Value::TYPE_BINARY:
|
||||
return ToArrayBuffer(isolate,
|
||||
static_cast<const base::BinaryValue*>(value));
|
||||
|
||||
default:
|
||||
LOG(ERROR) << "Unexpected value type: " << value->GetType();
|
||||
return v8::Null(isolate);
|
||||
@@ -200,6 +204,13 @@ v8::Local<v8::Value> V8ValueConverter::ToV8Object(
|
||||
return result.GetHandle();
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> V8ValueConverter::ToArrayBuffer(
|
||||
v8::Isolate* isolate, const base::BinaryValue* value) const {
|
||||
return node::Buffer::Copy(isolate,
|
||||
value->GetBuffer(),
|
||||
value->GetSize()).ToLocalChecked();
|
||||
}
|
||||
|
||||
base::Value* V8ValueConverter::FromV8ValueImpl(
|
||||
FromV8ValueState* state,
|
||||
v8::Local<v8::Value> val,
|
||||
|
||||
@@ -41,6 +41,9 @@ class V8ValueConverter {
|
||||
v8::Local<v8::Value> ToV8Object(
|
||||
v8::Isolate* isolate,
|
||||
const base::DictionaryValue* dictionary) const;
|
||||
v8::Local<v8::Value> ToArrayBuffer(
|
||||
v8::Isolate* isolate,
|
||||
const base::BinaryValue* value) const;
|
||||
|
||||
base::Value* FromV8ValueImpl(FromV8ValueState* state,
|
||||
v8::Local<v8::Value> value,
|
||||
|
||||
@@ -93,13 +93,15 @@ const char kDisableAutoHideCursor[] = "disable-auto-hide-cursor";
|
||||
// Use the OS X's standard window instead of the textured window.
|
||||
const char kStandardWindow[] = "standard-window";
|
||||
|
||||
// Default browser window background color.
|
||||
const char kBackgroundColor[] = "background-color";
|
||||
|
||||
// Path to client certificate.
|
||||
const char kClientCertificate[] = "client-certificate";
|
||||
|
||||
// Web runtime features.
|
||||
const char kExperimentalFeatures[] = "experimental-features";
|
||||
const char kExperimentalCanvasFeatures[] = "experimental-canvas-features";
|
||||
const char kSubpixelFontScaling[] = "subpixel-font-scaling";
|
||||
const char kOverlayScrollbars[] = "overlay-scrollbars";
|
||||
const char kOverlayFullscreenVideo[] = "overlay-fullscreen-video";
|
||||
const char kSharedWorker[] = "shared-worker";
|
||||
@@ -117,6 +119,9 @@ const char kRegisterStandardSchemes[] = "register-standard-schemes";
|
||||
// TLS fallback will accept.
|
||||
const char kSSLVersionFallbackMin[] = "ssl-version-fallback-min";
|
||||
|
||||
// Comma-separated list of SSL cipher suites to disable.
|
||||
const char kCipherSuiteBlacklist[] = "cipher-suite-blacklist";
|
||||
|
||||
// The browser process app model ID
|
||||
const char kAppUserModelId[] = "app-user-model-id";
|
||||
|
||||
|
||||
@@ -47,11 +47,11 @@ extern const char kTransparent[];
|
||||
extern const char kType[];
|
||||
extern const char kDisableAutoHideCursor[];
|
||||
extern const char kStandardWindow[];
|
||||
extern const char kBackgroundColor[];
|
||||
extern const char kClientCertificate[];
|
||||
|
||||
extern const char kExperimentalFeatures[];
|
||||
extern const char kExperimentalCanvasFeatures[];
|
||||
extern const char kSubpixelFontScaling[];
|
||||
extern const char kOverlayScrollbars[];
|
||||
extern const char kOverlayFullscreenVideo[];
|
||||
extern const char kSharedWorker[];
|
||||
@@ -60,6 +60,7 @@ extern const char kPageVisibility[];
|
||||
extern const char kDisableHttpCache[];
|
||||
extern const char kRegisterStandardSchemes[];
|
||||
extern const char kSSLVersionFallbackMin[];
|
||||
extern const char kCipherSuiteBlacklist[];
|
||||
|
||||
extern const char kAppUserModelId[];
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ void ShowItemInFolder(const base::FilePath& full_path) {
|
||||
DCHECK([NSThread isMainThread]);
|
||||
NSString* path_string = base::SysUTF8ToNSString(full_path.value());
|
||||
if (!path_string || ![[NSWorkspace sharedWorkspace] selectFile:path_string
|
||||
inFileViewerRootedAtPath:nil])
|
||||
inFileViewerRootedAtPath:@""])
|
||||
LOG(WARNING) << "NSWorkspace failed to select file " << full_path.value();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${PRODUCT_NAME} Framework</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${ATOM_BUNDLE_ID}</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME} Framework</string>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
|
||||
#include "atom/renderer/api/atom_api_web_frame.h"
|
||||
|
||||
#include "atom/common/api/api_messages.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/gfx_converter.h"
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "atom/renderer/api/atom_api_spell_check_client.h"
|
||||
#include "content/public/renderer/render_frame.h"
|
||||
#include "content/public/renderer/render_view.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
#include "third_party/WebKit/public/web/WebDocument.h"
|
||||
@@ -34,6 +36,10 @@ void WebFrame::SetName(const std::string& name) {
|
||||
}
|
||||
|
||||
double WebFrame::SetZoomLevel(double level) {
|
||||
auto render_view = content::RenderView::FromWebView(web_frame_->view());
|
||||
// Notify guests if any for zoom level change.
|
||||
render_view->Send(
|
||||
new AtomViewHostMsg_ZoomLevelChanged(MSG_ROUTING_NONE, level));
|
||||
return web_frame_->view()->setZoomLevel(level);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,9 @@ metaToValue = (meta) ->
|
||||
when 'array' then (metaToValue(el) for el in meta.members)
|
||||
when 'buffer' then new Buffer(meta.value)
|
||||
when 'promise' then Promise.resolve(then: metaToValue(meta.then))
|
||||
when 'error'
|
||||
when 'error' then new Error(meta.message)
|
||||
when 'date' then new Date(meta.value)
|
||||
when 'exception'
|
||||
throw new Error("#{meta.message}\n#{meta.stack}")
|
||||
else
|
||||
if meta.type is 'function'
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/api/api_messages.h"
|
||||
#include "atom/common/api/atom_bindings.h"
|
||||
#include "atom/common/node_bindings.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
@@ -21,11 +22,13 @@
|
||||
#include "content/public/renderer/render_frame.h"
|
||||
#include "content/public/renderer/render_frame_observer.h"
|
||||
#include "content/public/renderer/render_thread.h"
|
||||
#include "ipc/ipc_message_macros.h"
|
||||
#include "third_party/WebKit/public/web/WebCustomElement.h"
|
||||
#include "third_party/WebKit/public/web/WebLocalFrame.h"
|
||||
#include "third_party/WebKit/public/web/WebPluginParams.h"
|
||||
#include "third_party/WebKit/public/web/WebKit.h"
|
||||
#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
|
||||
#include "third_party/WebKit/public/web/WebView.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <shlobj.h>
|
||||
@@ -64,6 +67,22 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver {
|
||||
render_frame()->GetWebFrame(), context);
|
||||
}
|
||||
|
||||
bool OnMessageReceived(const IPC::Message& message) {
|
||||
bool handled = true;
|
||||
IPC_BEGIN_MESSAGE_MAP(AtomRenderFrameObserver, message)
|
||||
IPC_MESSAGE_HANDLER(AtomViewMsg_SetZoomLevel, OnSetZoomLevel)
|
||||
IPC_MESSAGE_UNHANDLED(handled = false)
|
||||
IPC_END_MESSAGE_MAP()
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
void OnSetZoomLevel(double level) {
|
||||
auto view = render_frame()->GetWebFrame()->view();
|
||||
if (view)
|
||||
view->setZoomLevel(level);
|
||||
}
|
||||
|
||||
private:
|
||||
AtomRendererClient* renderer_client_;
|
||||
|
||||
@@ -215,8 +234,6 @@ void AtomRendererClient::EnableWebRuntimeFeatures() {
|
||||
blink::WebRuntimeFeatures::enableExperimentalFeatures(b);
|
||||
if (IsSwitchEnabled(command_line, switches::kExperimentalCanvasFeatures, &b))
|
||||
blink::WebRuntimeFeatures::enableExperimentalCanvasFeatures(b);
|
||||
if (IsSwitchEnabled(command_line, switches::kSubpixelFontScaling, &b))
|
||||
blink::WebRuntimeFeatures::enableSubpixelFontScaling(b);
|
||||
if (IsSwitchEnabled(command_line, switches::kOverlayScrollbars, &b))
|
||||
blink::WebRuntimeFeatures::enableOverlayScrollbars(b);
|
||||
if (IsSwitchEnabled(command_line, switches::kOverlayFullscreenVideo, &b))
|
||||
|
||||
86
chromium_src/chrome/browser/chrome_process_finder_win.cc
Normal file
86
chromium_src/chrome/browser/chrome_process_finder_win.cc
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright 2013 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 "chrome/browser/chrome_process_finder_win.h"
|
||||
|
||||
#include <shellapi.h>
|
||||
#include <string>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/process/process.h"
|
||||
#include "base/process/process_info.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/win/message_window.h"
|
||||
#include "base/win/scoped_handle.h"
|
||||
#include "base/win/win_util.h"
|
||||
#include "base/win/windows_version.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
int timeout_in_milliseconds = 20 * 1000;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace chrome {
|
||||
|
||||
HWND FindRunningChromeWindow(const base::FilePath& user_data_dir) {
|
||||
return base::win::MessageWindow::FindWindow(user_data_dir.value());
|
||||
}
|
||||
|
||||
NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window,
|
||||
bool fast_start) {
|
||||
DCHECK(remote_window);
|
||||
DWORD process_id = 0;
|
||||
DWORD thread_id = GetWindowThreadProcessId(remote_window, &process_id);
|
||||
if (!thread_id || !process_id)
|
||||
return NOTIFY_FAILED;
|
||||
|
||||
// Send the command line to the remote chrome window.
|
||||
// Format is "START\0<<<current directory>>>\0<<<commandline>>>".
|
||||
std::wstring to_send(L"START\0", 6); // want the NULL in the string.
|
||||
base::FilePath cur_dir;
|
||||
if (!base::GetCurrentDirectory(&cur_dir))
|
||||
return NOTIFY_FAILED;
|
||||
to_send.append(cur_dir.value());
|
||||
to_send.append(L"\0", 1); // Null separator.
|
||||
to_send.append(::GetCommandLineW());
|
||||
to_send.append(L"\0", 1); // Null separator.
|
||||
|
||||
// Allow the current running browser window to make itself the foreground
|
||||
// window (otherwise it will just flash in the taskbar).
|
||||
::AllowSetForegroundWindow(process_id);
|
||||
|
||||
COPYDATASTRUCT cds;
|
||||
cds.dwData = 0;
|
||||
cds.cbData = static_cast<DWORD>((to_send.length() + 1) * sizeof(wchar_t));
|
||||
cds.lpData = const_cast<wchar_t*>(to_send.c_str());
|
||||
DWORD_PTR result = 0;
|
||||
if (::SendMessageTimeout(remote_window, WM_COPYDATA, NULL,
|
||||
reinterpret_cast<LPARAM>(&cds), SMTO_ABORTIFHUNG,
|
||||
timeout_in_milliseconds, &result)) {
|
||||
return result ? NOTIFY_SUCCESS : NOTIFY_FAILED;
|
||||
}
|
||||
|
||||
// It is possible that the process owning this window may have died by now.
|
||||
if (!::IsWindow(remote_window))
|
||||
return NOTIFY_FAILED;
|
||||
|
||||
// If the window couldn't be notified but still exists, assume it is hung.
|
||||
return NOTIFY_WINDOW_HUNG;
|
||||
}
|
||||
|
||||
base::TimeDelta SetNotificationTimeoutForTesting(base::TimeDelta new_timeout) {
|
||||
base::TimeDelta old_timeout =
|
||||
base::TimeDelta::FromMilliseconds(timeout_in_milliseconds);
|
||||
timeout_in_milliseconds = new_timeout.InMilliseconds();
|
||||
return old_timeout;
|
||||
}
|
||||
|
||||
} // namespace chrome
|
||||
39
chromium_src/chrome/browser/chrome_process_finder_win.h
Normal file
39
chromium_src/chrome/browser/chrome_process_finder_win.h
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright 2013 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 CHROME_BROWSER_CHROME_PROCESS_FINDER_WIN_H_
|
||||
#define CHROME_BROWSER_CHROME_PROCESS_FINDER_WIN_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "base/time/time.h"
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
namespace chrome {
|
||||
|
||||
enum NotifyChromeResult {
|
||||
NOTIFY_SUCCESS,
|
||||
NOTIFY_FAILED,
|
||||
NOTIFY_WINDOW_HUNG,
|
||||
};
|
||||
|
||||
// Finds an already running Chrome window if it exists.
|
||||
HWND FindRunningChromeWindow(const base::FilePath& user_data_dir);
|
||||
|
||||
// Attempts to send the current command line to an already running instance of
|
||||
// Chrome via a WM_COPYDATA message.
|
||||
// Returns true if a running Chrome is found and successfully notified.
|
||||
// |fast_start| is true when this is being called on the window fast start path.
|
||||
NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window,
|
||||
bool fast_start);
|
||||
|
||||
// Changes the notification timeout to |new_timeout|, returns the old timeout.
|
||||
base::TimeDelta SetNotificationTimeoutForTesting(base::TimeDelta new_timeout);
|
||||
|
||||
} // namespace chrome
|
||||
|
||||
#endif // CHROME_BROWSER_CHROME_PROCESS_FINDER_WIN_H_
|
||||
182
chromium_src/chrome/browser/process_singleton.h
Normal file
182
chromium_src/chrome/browser/process_singleton.h
Normal file
@@ -0,0 +1,182 @@
|
||||
// Copyright (c) 2012 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 CHROME_BROWSER_PROCESS_SINGLETON_H_
|
||||
#define CHROME_BROWSER_PROCESS_SINGLETON_H_
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/process/process.h"
|
||||
#include "base/threading/non_thread_safe.h"
|
||||
#include "ui/gfx/native_widget_types.h"
|
||||
|
||||
#if defined(OS_POSIX) && !defined(OS_ANDROID)
|
||||
#include "base/files/scoped_temp_dir.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/win/message_window.h"
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
namespace base {
|
||||
class CommandLine;
|
||||
}
|
||||
|
||||
// ProcessSingleton ----------------------------------------------------------
|
||||
//
|
||||
// This class allows different browser processes to communicate with
|
||||
// each other. It is named according to the user data directory, so
|
||||
// we can be sure that no more than one copy of the application can be
|
||||
// running at once with a given data directory.
|
||||
//
|
||||
// Implementation notes:
|
||||
// - the Windows implementation uses an invisible global message window;
|
||||
// - the Linux implementation uses a Unix domain socket in the user data dir.
|
||||
|
||||
class ProcessSingleton : public base::NonThreadSafe {
|
||||
public:
|
||||
enum NotifyResult {
|
||||
PROCESS_NONE,
|
||||
PROCESS_NOTIFIED,
|
||||
PROFILE_IN_USE,
|
||||
LOCK_ERROR,
|
||||
};
|
||||
|
||||
// Implement this callback to handle notifications from other processes. The
|
||||
// callback will receive the command line and directory with which the other
|
||||
// Chrome process was launched. Return true if the command line will be
|
||||
// handled within the current browser instance or false if the remote process
|
||||
// should handle it (i.e., because the current process is shutting down).
|
||||
using NotificationCallback =
|
||||
base::Callback<bool(const base::CommandLine::StringVector& command_line,
|
||||
const base::FilePath& current_directory)>;
|
||||
|
||||
ProcessSingleton(const base::FilePath& user_data_dir,
|
||||
const NotificationCallback& notification_callback);
|
||||
~ProcessSingleton();
|
||||
|
||||
// Notify another process, if available. Otherwise sets ourselves as the
|
||||
// singleton instance. Returns PROCESS_NONE if we became the singleton
|
||||
// instance. Callers are guaranteed to either have notified an existing
|
||||
// process or have grabbed the singleton (unless the profile is locked by an
|
||||
// unreachable process).
|
||||
// TODO(brettw): Make the implementation of this method non-platform-specific
|
||||
// by making Linux re-use the Windows implementation.
|
||||
NotifyResult NotifyOtherProcessOrCreate();
|
||||
|
||||
// Sets ourself up as the singleton instance. Returns true on success. If
|
||||
// false is returned, we are not the singleton instance and the caller must
|
||||
// exit.
|
||||
// NOTE: Most callers should generally prefer NotifyOtherProcessOrCreate() to
|
||||
// this method, only callers for whom failure is preferred to notifying
|
||||
// another process should call this directly.
|
||||
bool Create();
|
||||
|
||||
// Clear any lock state during shutdown.
|
||||
void Cleanup();
|
||||
|
||||
#if defined(OS_POSIX) && !defined(OS_ANDROID)
|
||||
static void DisablePromptForTesting();
|
||||
#endif
|
||||
#if defined(OS_WIN)
|
||||
// Called to query whether to kill a hung browser process that has visible
|
||||
// windows. Return true to allow killing the hung process.
|
||||
using ShouldKillRemoteProcessCallback = base::Callback<bool()>;
|
||||
void OverrideShouldKillRemoteProcessCallbackForTesting(
|
||||
const ShouldKillRemoteProcessCallback& display_dialog_callback);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Notify another process, if available.
|
||||
// Returns true if another process was found and notified, false if we should
|
||||
// continue with the current process.
|
||||
// On Windows, Create() has to be called before this.
|
||||
NotifyResult NotifyOtherProcess();
|
||||
|
||||
#if defined(OS_POSIX) && !defined(OS_ANDROID)
|
||||
// Exposed for testing. We use a timeout on Linux, and in tests we want
|
||||
// this timeout to be short.
|
||||
NotifyResult NotifyOtherProcessWithTimeout(
|
||||
const base::CommandLine& command_line,
|
||||
int retry_attempts,
|
||||
const base::TimeDelta& timeout,
|
||||
bool kill_unresponsive);
|
||||
NotifyResult NotifyOtherProcessWithTimeoutOrCreate(
|
||||
const base::CommandLine& command_line,
|
||||
int retry_attempts,
|
||||
const base::TimeDelta& timeout);
|
||||
void OverrideCurrentPidForTesting(base::ProcessId pid);
|
||||
void OverrideKillCallbackForTesting(
|
||||
const base::Callback<void(int)>& callback);
|
||||
#endif
|
||||
|
||||
private:
|
||||
NotificationCallback notification_callback_; // Handler for notifications.
|
||||
|
||||
#if defined(OS_WIN)
|
||||
HWND remote_window_; // The HWND_MESSAGE of another browser.
|
||||
base::win::MessageWindow window_; // The message-only window.
|
||||
bool is_virtualized_; // Stuck inside Microsoft Softricity VM environment.
|
||||
HANDLE lock_file_;
|
||||
base::FilePath user_data_dir_;
|
||||
ShouldKillRemoteProcessCallback should_kill_remote_process_callback_;
|
||||
#elif defined(OS_POSIX) && !defined(OS_ANDROID)
|
||||
// Start listening to the socket.
|
||||
void StartListening(int sock);
|
||||
|
||||
// Return true if the given pid is one of our child processes.
|
||||
// Assumes that the current pid is the root of all pids of the current
|
||||
// instance.
|
||||
bool IsSameChromeInstance(pid_t pid);
|
||||
|
||||
// Extract the process's pid from a symbol link path and if it is on
|
||||
// the same host, kill the process, unlink the lock file and return true.
|
||||
// If the process is part of the same chrome instance, unlink the lock file
|
||||
// and return true without killing it.
|
||||
// If the process is on a different host, return false.
|
||||
bool KillProcessByLockPath();
|
||||
|
||||
// Default function to kill a process, overridable by tests.
|
||||
void KillProcess(int pid);
|
||||
|
||||
// Allow overriding for tests.
|
||||
base::ProcessId current_pid_;
|
||||
|
||||
// Function to call when the other process is hung and needs to be killed.
|
||||
// Allows overriding for tests.
|
||||
base::Callback<void(int)> kill_callback_;
|
||||
|
||||
// Path in file system to the socket.
|
||||
base::FilePath socket_path_;
|
||||
|
||||
// Path in file system to the lock.
|
||||
base::FilePath lock_path_;
|
||||
|
||||
// Path in file system to the cookie file.
|
||||
base::FilePath cookie_path_;
|
||||
|
||||
// Temporary directory to hold the socket.
|
||||
base::ScopedTempDir socket_dir_;
|
||||
|
||||
// Helper class for linux specific messages. LinuxWatcher is ref counted
|
||||
// because it posts messages between threads.
|
||||
class LinuxWatcher;
|
||||
scoped_refptr<LinuxWatcher> watcher_;
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ProcessSingleton);
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_PROCESS_SINGLETON_H_
|
||||
1061
chromium_src/chrome/browser/process_singleton_posix.cc
Normal file
1061
chromium_src/chrome/browser/process_singleton_posix.cc
Normal file
File diff suppressed because it is too large
Load Diff
328
chromium_src/chrome/browser/process_singleton_win.cc
Normal file
328
chromium_src/chrome/browser/process_singleton_win.cc
Normal file
@@ -0,0 +1,328 @@
|
||||
// Copyright (c) 2012 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 "chrome/browser/process_singleton.h"
|
||||
|
||||
#include <shellapi.h>
|
||||
|
||||
#include "base/base_paths.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/process/process.h"
|
||||
#include "base/process/process_info.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/win/metro.h"
|
||||
#include "base/win/registry.h"
|
||||
#include "base/win/scoped_handle.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "chrome/browser/chrome_process_finder_win.h"
|
||||
#include "content/public/common/result_codes.h"
|
||||
#include "net/base/escape.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/gfx/win/hwnd_util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const char kLockfile[] = "lockfile";
|
||||
|
||||
// A helper class that acquires the given |mutex| while the AutoLockMutex is in
|
||||
// scope.
|
||||
class AutoLockMutex {
|
||||
public:
|
||||
explicit AutoLockMutex(HANDLE mutex) : mutex_(mutex) {
|
||||
DWORD result = ::WaitForSingleObject(mutex_, INFINITE);
|
||||
DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result;
|
||||
}
|
||||
|
||||
~AutoLockMutex() {
|
||||
BOOL released = ::ReleaseMutex(mutex_);
|
||||
DPCHECK(released);
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE mutex_;
|
||||
DISALLOW_COPY_AND_ASSIGN(AutoLockMutex);
|
||||
};
|
||||
|
||||
// A helper class that releases the given |mutex| while the AutoUnlockMutex is
|
||||
// in scope and immediately re-acquires it when going out of scope.
|
||||
class AutoUnlockMutex {
|
||||
public:
|
||||
explicit AutoUnlockMutex(HANDLE mutex) : mutex_(mutex) {
|
||||
BOOL released = ::ReleaseMutex(mutex_);
|
||||
DPCHECK(released);
|
||||
}
|
||||
|
||||
~AutoUnlockMutex() {
|
||||
DWORD result = ::WaitForSingleObject(mutex_, INFINITE);
|
||||
DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result;
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE mutex_;
|
||||
DISALLOW_COPY_AND_ASSIGN(AutoUnlockMutex);
|
||||
};
|
||||
|
||||
// Checks the visibility of the enumerated window and signals once a visible
|
||||
// window has been found.
|
||||
BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) {
|
||||
bool* result = reinterpret_cast<bool*>(param);
|
||||
*result = ::IsWindowVisible(window) != 0;
|
||||
// Stops enumeration if a visible window has been found.
|
||||
return !*result;
|
||||
}
|
||||
|
||||
// Convert Command line string to argv.
|
||||
base::CommandLine::StringVector CommandLineStringToArgv(
|
||||
const std::wstring& command_line_string) {
|
||||
int num_args = 0;
|
||||
wchar_t** args = NULL;
|
||||
args = ::CommandLineToArgvW(command_line_string.c_str(), &num_args);
|
||||
base::CommandLine::StringVector argv;
|
||||
for (int i = 0; i < num_args; ++i)
|
||||
argv.push_back(std::wstring(args[i]));
|
||||
LocalFree(args);
|
||||
return argv;
|
||||
}
|
||||
|
||||
bool ParseCommandLine(const COPYDATASTRUCT* cds,
|
||||
base::CommandLine::StringVector* parsed_command_line,
|
||||
base::FilePath* current_directory) {
|
||||
// We should have enough room for the shortest command (min_message_size)
|
||||
// and also be a multiple of wchar_t bytes. The shortest command
|
||||
// possible is L"START\0\0" (empty current directory and command line).
|
||||
static const int min_message_size = 7;
|
||||
if (cds->cbData < min_message_size * sizeof(wchar_t) ||
|
||||
cds->cbData % sizeof(wchar_t) != 0) {
|
||||
LOG(WARNING) << "Invalid WM_COPYDATA, length = " << cds->cbData;
|
||||
return false;
|
||||
}
|
||||
|
||||
// We split the string into 4 parts on NULLs.
|
||||
DCHECK(cds->lpData);
|
||||
const std::wstring msg(static_cast<wchar_t*>(cds->lpData),
|
||||
cds->cbData / sizeof(wchar_t));
|
||||
const std::wstring::size_type first_null = msg.find_first_of(L'\0');
|
||||
if (first_null == 0 || first_null == std::wstring::npos) {
|
||||
// no NULL byte, don't know what to do
|
||||
LOG(WARNING) << "Invalid WM_COPYDATA, length = " << msg.length() <<
|
||||
", first null = " << first_null;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decode the command, which is everything until the first NULL.
|
||||
if (msg.substr(0, first_null) == L"START") {
|
||||
// Another instance is starting parse the command line & do what it would
|
||||
// have done.
|
||||
VLOG(1) << "Handling STARTUP request from another process";
|
||||
const std::wstring::size_type second_null =
|
||||
msg.find_first_of(L'\0', first_null + 1);
|
||||
if (second_null == std::wstring::npos ||
|
||||
first_null == msg.length() - 1 || second_null == msg.length()) {
|
||||
LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
|
||||
"parts separated by NULLs";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get current directory.
|
||||
*current_directory = base::FilePath(msg.substr(first_null + 1,
|
||||
second_null - first_null));
|
||||
|
||||
const std::wstring::size_type third_null =
|
||||
msg.find_first_of(L'\0', second_null + 1);
|
||||
if (third_null == std::wstring::npos ||
|
||||
third_null == msg.length()) {
|
||||
LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
|
||||
"parts separated by NULLs";
|
||||
}
|
||||
|
||||
// Get command line.
|
||||
const std::wstring cmd_line =
|
||||
msg.substr(second_null + 1, third_null - second_null);
|
||||
*parsed_command_line = CommandLineStringToArgv(cmd_line);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProcessLaunchNotification(
|
||||
const ProcessSingleton::NotificationCallback& notification_callback,
|
||||
UINT message,
|
||||
WPARAM wparam,
|
||||
LPARAM lparam,
|
||||
LRESULT* result) {
|
||||
if (message != WM_COPYDATA)
|
||||
return false;
|
||||
|
||||
// Handle the WM_COPYDATA message from another process.
|
||||
const COPYDATASTRUCT* cds = reinterpret_cast<COPYDATASTRUCT*>(lparam);
|
||||
|
||||
base::CommandLine::StringVector parsed_command_line;
|
||||
base::FilePath current_directory;
|
||||
if (!ParseCommandLine(cds, &parsed_command_line, ¤t_directory)) {
|
||||
*result = TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
*result = notification_callback.Run(parsed_command_line, current_directory) ?
|
||||
TRUE : FALSE;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TerminateAppWithError() {
|
||||
// TODO: This is called when the secondary process can't ping the primary
|
||||
// process. Need to find out what to do here.
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ProcessSingleton::ProcessSingleton(
|
||||
const base::FilePath& user_data_dir,
|
||||
const NotificationCallback& notification_callback)
|
||||
: notification_callback_(notification_callback),
|
||||
is_virtualized_(false),
|
||||
lock_file_(INVALID_HANDLE_VALUE),
|
||||
user_data_dir_(user_data_dir),
|
||||
should_kill_remote_process_callback_(
|
||||
base::Bind(&TerminateAppWithError)) {
|
||||
}
|
||||
|
||||
ProcessSingleton::~ProcessSingleton() {
|
||||
if (lock_file_ != INVALID_HANDLE_VALUE)
|
||||
::CloseHandle(lock_file_);
|
||||
}
|
||||
|
||||
// Code roughly based on Mozilla.
|
||||
ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
|
||||
if (is_virtualized_)
|
||||
return PROCESS_NOTIFIED; // We already spawned the process in this case.
|
||||
if (lock_file_ == INVALID_HANDLE_VALUE && !remote_window_) {
|
||||
return LOCK_ERROR;
|
||||
} else if (!remote_window_) {
|
||||
return PROCESS_NONE;
|
||||
}
|
||||
|
||||
switch (chrome::AttemptToNotifyRunningChrome(remote_window_, false)) {
|
||||
case chrome::NOTIFY_SUCCESS:
|
||||
return PROCESS_NOTIFIED;
|
||||
case chrome::NOTIFY_FAILED:
|
||||
remote_window_ = NULL;
|
||||
return PROCESS_NONE;
|
||||
case chrome::NOTIFY_WINDOW_HUNG:
|
||||
// Fall through and potentially terminate the hung browser.
|
||||
break;
|
||||
}
|
||||
|
||||
DWORD process_id = 0;
|
||||
DWORD thread_id = ::GetWindowThreadProcessId(remote_window_, &process_id);
|
||||
if (!thread_id || !process_id) {
|
||||
remote_window_ = NULL;
|
||||
return PROCESS_NONE;
|
||||
}
|
||||
base::Process process = base::Process::Open(process_id);
|
||||
|
||||
// The window is hung. Scan for every window to find a visible one.
|
||||
bool visible_window = false;
|
||||
::EnumThreadWindows(thread_id,
|
||||
&BrowserWindowEnumeration,
|
||||
reinterpret_cast<LPARAM>(&visible_window));
|
||||
|
||||
// If there is a visible browser window, ask the user before killing it.
|
||||
if (visible_window && !should_kill_remote_process_callback_.Run()) {
|
||||
// The user denied. Quit silently.
|
||||
return PROCESS_NOTIFIED;
|
||||
}
|
||||
|
||||
// Time to take action. Kill the browser process.
|
||||
process.Terminate(content::RESULT_CODE_HUNG, true);
|
||||
remote_window_ = NULL;
|
||||
return PROCESS_NONE;
|
||||
}
|
||||
|
||||
ProcessSingleton::NotifyResult
|
||||
ProcessSingleton::NotifyOtherProcessOrCreate() {
|
||||
ProcessSingleton::NotifyResult result = PROCESS_NONE;
|
||||
if (!Create()) {
|
||||
result = NotifyOtherProcess();
|
||||
if (result == PROCESS_NONE)
|
||||
result = PROFILE_IN_USE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Look for a Chrome instance that uses the same profile directory. If there
|
||||
// isn't one, create a message window with its title set to the profile
|
||||
// directory path.
|
||||
bool ProcessSingleton::Create() {
|
||||
static const wchar_t kMutexName[] = L"Local\\AtomProcessSingletonStartup!";
|
||||
|
||||
remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
|
||||
if (!remote_window_) {
|
||||
// Make sure we will be the one and only process creating the window.
|
||||
// We use a named Mutex since we are protecting against multi-process
|
||||
// access. As documented, it's clearer to NOT request ownership on creation
|
||||
// since it isn't guaranteed we will get it. It is better to create it
|
||||
// without ownership and explicitly get the ownership afterward.
|
||||
base::win::ScopedHandle only_me(::CreateMutex(NULL, FALSE, kMutexName));
|
||||
if (!only_me.IsValid()) {
|
||||
DPLOG(FATAL) << "CreateMutex failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoLockMutex auto_lock_only_me(only_me.Get());
|
||||
|
||||
// We now own the mutex so we are the only process that can create the
|
||||
// window at this time, but we must still check if someone created it
|
||||
// between the time where we looked for it above and the time the mutex
|
||||
// was given to us.
|
||||
remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
|
||||
if (!remote_window_) {
|
||||
// We have to make sure there is no Chrome instance running on another
|
||||
// machine that uses the same profile.
|
||||
base::FilePath lock_file_path = user_data_dir_.AppendASCII(kLockfile);
|
||||
lock_file_ = ::CreateFile(lock_file_path.value().c_str(),
|
||||
GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL |
|
||||
FILE_FLAG_DELETE_ON_CLOSE,
|
||||
NULL);
|
||||
DWORD error = ::GetLastError();
|
||||
LOG_IF(WARNING, lock_file_ != INVALID_HANDLE_VALUE &&
|
||||
error == ERROR_ALREADY_EXISTS) << "Lock file exists but is writable.";
|
||||
LOG_IF(ERROR, lock_file_ == INVALID_HANDLE_VALUE)
|
||||
<< "Lock file can not be created! Error code: " << error;
|
||||
|
||||
if (lock_file_ != INVALID_HANDLE_VALUE) {
|
||||
// Set the window's title to the path of our user data directory so
|
||||
// other Chrome instances can decide if they should forward to us.
|
||||
bool result = window_.CreateNamed(
|
||||
base::Bind(&ProcessLaunchNotification, notification_callback_),
|
||||
user_data_dir_.value());
|
||||
|
||||
// NB: Ensure that if the primary app gets started as elevated
|
||||
// admin inadvertently, secondary windows running not as elevated
|
||||
// will still be able to send messages
|
||||
::ChangeWindowMessageFilterEx(window_.hwnd(), WM_COPYDATA, MSGFLT_ALLOW, NULL);
|
||||
CHECK(result && window_.hwnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return window_.hwnd() != NULL;
|
||||
}
|
||||
|
||||
void ProcessSingleton::Cleanup() {
|
||||
}
|
||||
|
||||
void ProcessSingleton::OverrideShouldKillRemoteProcessCallbackForTesting(
|
||||
const ShouldKillRemoteProcessCallback& display_dialog_callback) {
|
||||
should_kill_remote_process_callback_ = display_dialog_callback;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright 2014 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 "extensions/browser/app_window/size_constraints.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "ui/gfx/geometry/insets.h"
|
||||
|
||||
namespace extensions {
|
||||
|
||||
SizeConstraints::SizeConstraints()
|
||||
: maximum_size_(kUnboundedSize, kUnboundedSize) {}
|
||||
|
||||
SizeConstraints::SizeConstraints(const gfx::Size& min_size,
|
||||
const gfx::Size& max_size)
|
||||
: minimum_size_(min_size), maximum_size_(max_size) {}
|
||||
|
||||
SizeConstraints::~SizeConstraints() {}
|
||||
|
||||
// static
|
||||
gfx::Size SizeConstraints::AddFrameToConstraints(
|
||||
const gfx::Size& size_constraints,
|
||||
const gfx::Insets& frame_insets) {
|
||||
return gfx::Size(
|
||||
size_constraints.width() == kUnboundedSize
|
||||
? kUnboundedSize
|
||||
: size_constraints.width() + frame_insets.width(),
|
||||
size_constraints.height() == kUnboundedSize
|
||||
? kUnboundedSize
|
||||
: size_constraints.height() + frame_insets.height());
|
||||
}
|
||||
|
||||
gfx::Size SizeConstraints::ClampSize(gfx::Size size) const {
|
||||
const gfx::Size max_size = GetMaximumSize();
|
||||
if (max_size.width() != kUnboundedSize)
|
||||
size.set_width(std::min(size.width(), max_size.width()));
|
||||
if (max_size.height() != kUnboundedSize)
|
||||
size.set_height(std::min(size.height(), max_size.height()));
|
||||
size.SetToMax(GetMinimumSize());
|
||||
return size;
|
||||
}
|
||||
|
||||
bool SizeConstraints::HasMinimumSize() const {
|
||||
const gfx::Size min_size = GetMinimumSize();
|
||||
return min_size.width() != kUnboundedSize ||
|
||||
min_size.height() != kUnboundedSize;
|
||||
}
|
||||
|
||||
bool SizeConstraints::HasMaximumSize() const {
|
||||
const gfx::Size max_size = GetMaximumSize();
|
||||
return max_size.width() != kUnboundedSize ||
|
||||
max_size.height() != kUnboundedSize;
|
||||
}
|
||||
|
||||
bool SizeConstraints::HasFixedSize() const {
|
||||
return !GetMinimumSize().IsEmpty() && GetMinimumSize() == GetMaximumSize();
|
||||
}
|
||||
|
||||
gfx::Size SizeConstraints::GetMinimumSize() const {
|
||||
return minimum_size_;
|
||||
}
|
||||
|
||||
gfx::Size SizeConstraints::GetMaximumSize() const {
|
||||
return gfx::Size(
|
||||
maximum_size_.width() == kUnboundedSize
|
||||
? kUnboundedSize
|
||||
: std::max(maximum_size_.width(), minimum_size_.width()),
|
||||
maximum_size_.height() == kUnboundedSize
|
||||
? kUnboundedSize
|
||||
: std::max(maximum_size_.height(), minimum_size_.height()));
|
||||
}
|
||||
|
||||
void SizeConstraints::set_minimum_size(const gfx::Size& min_size) {
|
||||
minimum_size_ = min_size;
|
||||
}
|
||||
|
||||
void SizeConstraints::set_maximum_size(const gfx::Size& max_size) {
|
||||
maximum_size_ = max_size;
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright 2014 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 EXTENSIONS_BROWSER_APP_WINDOW_SIZE_CONSTRAINTS_H_
|
||||
#define EXTENSIONS_BROWSER_APP_WINDOW_SIZE_CONSTRAINTS_H_
|
||||
|
||||
#include "ui/gfx/geometry/size.h"
|
||||
|
||||
namespace gfx {
|
||||
class Insets;
|
||||
}
|
||||
|
||||
namespace extensions {
|
||||
|
||||
class SizeConstraints {
|
||||
public:
|
||||
// The value SizeConstraints uses to represent an unbounded width or height.
|
||||
// This is an enum so that it can be declared inline here.
|
||||
enum { kUnboundedSize = 0 };
|
||||
|
||||
SizeConstraints();
|
||||
SizeConstraints(const gfx::Size& min_size, const gfx::Size& max_size);
|
||||
~SizeConstraints();
|
||||
|
||||
// Adds frame insets to a size constraint.
|
||||
static gfx::Size AddFrameToConstraints(const gfx::Size& size_constraints,
|
||||
const gfx::Insets& frame_insets);
|
||||
|
||||
// Returns the bounds with its size clamped to the min/max size.
|
||||
gfx::Size ClampSize(gfx::Size size) const;
|
||||
|
||||
// When gfx::Size is used as a min/max size, a zero represents an unbounded
|
||||
// component. This method checks whether either component is specified.
|
||||
// Note we can't use gfx::Size::IsEmpty as it returns true if either width
|
||||
// or height is zero.
|
||||
bool HasMinimumSize() const;
|
||||
bool HasMaximumSize() const;
|
||||
|
||||
// This returns true if all components are specified, and min and max are
|
||||
// equal.
|
||||
bool HasFixedSize() const;
|
||||
|
||||
gfx::Size GetMaximumSize() const;
|
||||
gfx::Size GetMinimumSize() const;
|
||||
|
||||
void set_minimum_size(const gfx::Size& min_size);
|
||||
void set_maximum_size(const gfx::Size& max_size);
|
||||
|
||||
private:
|
||||
gfx::Size minimum_size_;
|
||||
gfx::Size maximum_size_;
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
|
||||
#endif // EXTENSIONS_BROWSER_APP_WINDOW_SIZE_CONSTRAINTS_H_
|
||||
@@ -1,32 +1,33 @@
|
||||
## Guías
|
||||
|
||||
* [Distribución de aplicaciones](tutorial/application-distribution.md)
|
||||
* [Empaquetamiento de aplicaciones](tutorial/application-packaging.md)
|
||||
* [Utilizando módulos nativos](tutorial/using-native-node-modules.md)
|
||||
* [Depurando el proceso principal](tutorial/debugging-main-process.md)
|
||||
* [Plataformas Soportadas](tutorial/supported-platforms.md)
|
||||
* [Distribución de la Aplicación](tutorial/application-distribution.md)
|
||||
* [Empaquetamiento de la Aplicación](tutorial/application-packaging.md)
|
||||
* [Utilizando Módulos Node Nativos](tutorial/using-native-node-modules.md)
|
||||
* [Depurando el Proceso Principal](tutorial/debugging-main-process.md)
|
||||
* [Utilizando Selenium y WebDriver](tutorial/using-selenium-and-webdriver.md)
|
||||
* [Extensión DevTools](tutorial/devtools-extension.md)
|
||||
* [Utilizando el plugin pepper flash](tutorial/using-pepper-flash-plugin.md)
|
||||
* [Utilizando el plugin Pepper Flash](tutorial/using-pepper-flash-plugin.md)
|
||||
|
||||
## Tutoriales
|
||||
|
||||
* [Introducción](../../docs/tutorial/quick-start.md)
|
||||
* [Integración con el entorno de escritorio](../../docs/tutorial/desktop-environment-integration.md)
|
||||
* [Detección del evento en línea/fuera de línea](../../docs/tutorial/online-offline-events.md)
|
||||
* [Introducción](tutorial/quick-start.md)
|
||||
* [Integración con el entorno de escritorio](tutorial/desktop-environment-integration.md)
|
||||
* [Detección del evento en línea/fuera de línea](tutorial/online-offline-events.md)
|
||||
|
||||
## API
|
||||
## Referencias a la API
|
||||
|
||||
* [Sinopsis](../../docs/api/synopsis.md)
|
||||
* [Proceso](../../docs/api/process.md)
|
||||
* [Parámetros CLI soportados (Chrome)](../../docs/api/chrome-command-line-switches.md)
|
||||
* [Sinopsis](api/synopsis.md)
|
||||
* [Proceso](api/process.md)
|
||||
* [Parámetros CLI soportados (Chrome)](api/chrome-command-line-switches.md)
|
||||
|
||||
Elementos DOM customizados:
|
||||
### Elementos DOM personalizados:
|
||||
|
||||
* [Objeto `File`](../../docs/api/file-object.md)
|
||||
* [Etiqueta `<webview>`](../../docs/api/web-view-tag.md)
|
||||
* [Función `window.open`](../../docs/api/window-open.md)
|
||||
|
||||
Módulos del proceso principal:
|
||||
### Módulos del Proceso Principal:
|
||||
|
||||
* [app](../../docs/api/app.md)
|
||||
* [auto-updater](../../docs/api/auto-updater.md)
|
||||
@@ -34,21 +35,23 @@ Módulos del proceso principal:
|
||||
* [content-tracing](../../docs/api/content-tracing.md)
|
||||
* [dialog](../../docs/api/dialog.md)
|
||||
* [global-shortcut](../../docs/api/global-shortcut.md)
|
||||
* [ipc (main process)](../../docs/api/ipc-main-process.md)
|
||||
* [ipc (proceso principal)](../../docs/api/ipc-main-process.md)
|
||||
* [menu](../../docs/api/menu.md)
|
||||
* [menu-item](../../docs/api/menu-item.md)
|
||||
* [power-monitor](../../docs/api/power-monitor.md)
|
||||
* [power-save-blocker](../../docs/api/power-save-blocker.md)
|
||||
* [protocol](../../docs/api/protocol.md)
|
||||
* [session](../../docs/api/session.md)
|
||||
* [web-contents](../../docs/api/web-contents.md)
|
||||
* [tray](../../docs/api/tray.md)
|
||||
|
||||
Módulos del renderer (página web):
|
||||
### Módulos del proceso de renderizado (Página Web):
|
||||
|
||||
* [ipc (renderer)](../../docs/api/ipc-renderer.md)
|
||||
* [ipc (renderizador)](../../docs/api/ipc-renderer.md)
|
||||
* [remote](../../docs/api/remote.md)
|
||||
* [web-frame](../../docs/api/web-frame.md)
|
||||
|
||||
Módulos de ambos procesos:
|
||||
### Módulos de Ambos Procesos:
|
||||
|
||||
* [clipboard](../../docs/api/clipboard.md)
|
||||
* [crash-reporter](../../docs/api/crash-reporter.md)
|
||||
@@ -58,11 +61,11 @@ Módulos de ambos procesos:
|
||||
|
||||
## Desarrollo
|
||||
|
||||
* [Guía de estilo](../../docs/development/coding-style.md)
|
||||
* [Estructura de directorio](../../docs/development/source-code-directory-structure.md)
|
||||
* [Diferencias técnicas con NW.js (anteriormente conocido como node-webkit)](../../docs/development/atom-shell-vs-node-webkit.md)
|
||||
* [Sistema de compilación](../../docs/development/build-system-overview.md)
|
||||
* [Instrucciones de compilación (Mac)](../../docs/development/build-instructions-osx.md)
|
||||
* [Instrucciones de compilación (Windows)](../../docs/development/build-instructions-windows.md)
|
||||
* [Instrucciones de compilación (Linux)](../../docs/development/build-instructions-linux.md)
|
||||
* [Configurando un servidor de símbolos en el depurador](../../docs/development/setting-up-symbol-server.md)
|
||||
* [Guía de Estilo](development/coding-style.md)
|
||||
* [Estructura de los directorios del Código Fuente](../../development/source-code-directory-structure.md)
|
||||
* [Diferencias Técnicas con NW.js (anteriormente conocido como node-webkit)](../../development/atom-shell-vs-node-webkit.md)
|
||||
* [Repaso del Sistema de Compilación](../../development/build-system-overview.md)
|
||||
* [Instrucciones de Compilación (Mac)](../../development/build-instructions-osx.md)
|
||||
* [Instrucciones de Compilación (Windows)](../../development/build-instructions-windows.md)
|
||||
* [Instrucciones de Compilación (Linux)](../../development/build-instructions-linux.md)
|
||||
* [Configurando un Servidor de Símbolos en el depurador](../../development/setting-up-symbol-server.md)
|
||||
|
||||
119
docs-translations/es/api/chrome-command-line-switches.md
Normal file
119
docs-translations/es/api/chrome-command-line-switches.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# Parámetros CLI soportados (Chrome)
|
||||
|
||||
Esta página lista las líneas de comandos usadas por el navegador Chrome que también son
|
||||
soportadas por Electron. Puedes usar [app.commandLine.appendSwitch][append-switch] para
|
||||
anexarlas en el script principal de tu aplicación antes de que el evento [ready][ready] del
|
||||
módulo [app][app] sea emitido:
|
||||
|
||||
```javascript
|
||||
var app = require('app');
|
||||
app.commandLine.appendSwitch('remote-debugging-port', '8315');
|
||||
app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1');
|
||||
|
||||
app.on('ready', function() {
|
||||
// Your code here
|
||||
});
|
||||
```
|
||||
|
||||
## --client-certificate=`path`
|
||||
|
||||
Establece el `path` del archivo de certificado del cliente.
|
||||
|
||||
## --ignore-connections-limit=`domains`
|
||||
|
||||
Ignora el límite de conexiones para la lista de `domains` separados por `,`.
|
||||
|
||||
## --disable-http-cache
|
||||
|
||||
Deshabilita la caché del disco para las peticiones HTTP.
|
||||
|
||||
## --remote-debugging-port=`port`
|
||||
|
||||
Habilita la depuración remota a través de HTTP en el puerto especificado.
|
||||
|
||||
## --proxy-server=`address:port`
|
||||
|
||||
Usa un servidor proxy especificado, que sobreescribe la configuración del sistema.
|
||||
Este cambio solo afecta peticiones HTTP y HTTPS.
|
||||
|
||||
## --proxy-pac-url=`url`
|
||||
|
||||
Utiliza el script PAC en la `url` especificada.
|
||||
|
||||
## --no-proxy-server
|
||||
|
||||
No usa un servidor proxy y siempre establece conexiones directas. Anula cualquier
|
||||
otra bandera de servidor proxy bandera que se pase.
|
||||
|
||||
## --host-rules=`rules`
|
||||
|
||||
Una lista separada por comas de `rules` (reglas) que controlan cómo se asignan los
|
||||
nombres de host.
|
||||
|
||||
Por ejemplo:
|
||||
|
||||
* `MAP * 127.0.0.1` Obliga a todos los nombres de host a ser asignados a 127.0.0.1
|
||||
* `MAP *.google.com proxy` Obliga todos los subdominios google.com a resolverse con
|
||||
"proxy".
|
||||
* `MAP test.com [::1]:77` Obliga a resolver "test.com" con un bucle invertido de IPv6.
|
||||
También obligará a que el puerto de la dirección respuesta sea 77.
|
||||
* `MAP * baz, EXCLUDE www.google.com` Reasigna todo a "baz", excepto a "www.google.com".
|
||||
|
||||
Estas asignaciones especifican el host final en una petición de red (Anfitrión de la conexión TCP
|
||||
y de resolución de conexión directa, y el `CONNECT` en una conexión proxy HTTP, y el host final de
|
||||
la conexión proxy `SOCKS`).
|
||||
|
||||
## --host-resolver-rules=`rules`
|
||||
|
||||
Como `--host-rules` pero estas `rules` solo se aplican al solucionador.
|
||||
|
||||
[app]: app.md
|
||||
[append-switch]: app.md#appcommandlineappendswitchswitch-value
|
||||
[ready]: app.md#event-ready
|
||||
|
||||
## --ignore-certificate-errors
|
||||
|
||||
Ignora errores de certificado relacionados.
|
||||
|
||||
## --ppapi-flash-path=`path`
|
||||
|
||||
Asigna la ruta `path` del pepper flash plugin.
|
||||
|
||||
## --ppapi-flash-version=`version`
|
||||
|
||||
Asigna la versión `version` del pepper flash plugin.
|
||||
|
||||
## --log-net-log=`path`
|
||||
|
||||
Permite guardar y escribir eventos de registros de red en `path`.
|
||||
|
||||
## --ssl-version-fallback-min=`version`
|
||||
|
||||
Establece la versión mínima de SSL/TLS ("tls1", "tls1.1" o "tls1.2") que
|
||||
el repliegue de TLC aceptará.
|
||||
|
||||
## --enable-logging
|
||||
|
||||
Imprime el registro de Chromium en consola.
|
||||
|
||||
Este cambio no puede ser usado en `app.commandLine.appendSwitch` ya que se analiza antes de que la
|
||||
aplicación del usuario esté cargada.
|
||||
|
||||
## --v=`log_level`
|
||||
|
||||
Da el máximo nivel activo de V-logging por defecto; 0 es el predeterminado. Valores positivos
|
||||
son normalmente usados para los niveles de V-logging.
|
||||
|
||||
Este modificador sólo funciona cuando también se pasa `--enable-logging`.
|
||||
|
||||
## --vmodule=`pattern`
|
||||
|
||||
Da los niveles máximos de V-logging por módulo para sobreescribir el valor dado por
|
||||
`--v`. Ej. `my_module=2,foo*=3` cambiaría el nivel de registro para todo el código,
|
||||
los archivos de origen `my_module.*` y `foo*.*`.
|
||||
|
||||
Cualquier patrón que contiene un slash o un slash invertido será probado contra toda la ruta
|
||||
y no sólo con el módulo. Ej. `*/foo/bar/*=2` cambiaría el nivel de registro para todo el código
|
||||
en los archivos origen bajo un directorio `foo/bar`.
|
||||
|
||||
Este modificador sólo funciona cuando también se pasa `--enable-logging`.
|
||||
47
docs-translations/es/api/process.md
Normal file
47
docs-translations/es/api/process.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# process
|
||||
|
||||
El objeto `process` en Electron tiene las siguientes diferencias con respecto
|
||||
al node convencional:
|
||||
|
||||
* `process.type` String - El tipo del proceso puede ser `browser` (ej. proceso
|
||||
principal) o `renderer`.
|
||||
* `process.versions['electron']` String - Versión de Electron.
|
||||
* `process.versions['chrome']` String - Versión de Chromium.
|
||||
* `process.resourcesPath` String - Ruta al código fuente JavaScript.
|
||||
|
||||
## Events
|
||||
|
||||
### Event: 'loaded'
|
||||
|
||||
Se emite cuando Electron ha cargado su script de inicialización interna y
|
||||
está comenzando a cargar la página web o el script principal.
|
||||
|
||||
Puede ser usado por el script precargado para añadir de nuevo los símbolos globales
|
||||
de Node eliminados, al alcance global cuando la integración de Node está apagada:
|
||||
|
||||
```js
|
||||
// preload.js
|
||||
var _setImmediate = setImmediate;
|
||||
var _clearImmediate = clearImmediate;
|
||||
process.once('loaded', function() {
|
||||
global.setImmediate = _setImmediate;
|
||||
global.clearImmediate = _clearImmediate;
|
||||
});
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
El objeto `process` tiene los siguientes métodos:
|
||||
|
||||
### `process.hang`
|
||||
|
||||
Interrumpe el hilo principal del proceso actual.
|
||||
|
||||
|
||||
### process.setFdLimit(maxDescriptors) _OS X_ _Linux_
|
||||
|
||||
* `maxDescriptors` Integer
|
||||
|
||||
Establece el límite dinámico del descriptor del archivo en `maxDescriptors`
|
||||
o en el límite estricto del Sistema Operativo, el que sea menor para el
|
||||
proceso actual.
|
||||
47
docs-translations/es/api/synopsis.md
Normal file
47
docs-translations/es/api/synopsis.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Synopsis
|
||||
|
||||
Todos los [Módulos integrados de Node.js](http://nodejs.org/api/) se encuentran
|
||||
disponibles en Electron y módulos de terceros son támbien totalmente compatibles
|
||||
(incluyendo los [módulos nativos](../tutorial/using-native-node-modules.md)).
|
||||
|
||||
Electron también provee algunos módulos integrados adicionales para desarrollar
|
||||
aplicaciones nativas de escritorio. Algunos módulos sólo se encuentran disponibles
|
||||
en el proceso principal, algunos sólo en el proceso renderer (página web), y
|
||||
algunos pueden ser usados en ambos procesos.
|
||||
|
||||
La regla básica es: Si un módulo es
|
||||
[GUI](https://es.wikipedia.org/wiki/Interfaz_gráfica_de_usuario) o de bajo nivel,
|
||||
entonces solo estará disponible en el proceso principal. Necesitas familiarizarte
|
||||
con el concepto de [scripts para proceso principal vs scripts para proceso renderer]
|
||||
(../tutorial/quick-start.md#the-main-process) para ser capaz de usar esos módulos.
|
||||
|
||||
El script del proceso principal es como un script normal de Node.js:
|
||||
|
||||
```javascript
|
||||
var app = require('app');
|
||||
var BrowserWindow = require('browser-window');
|
||||
|
||||
var window = null;
|
||||
|
||||
app.on('ready', function() {
|
||||
window = new BrowserWindow({width: 800, height: 600});
|
||||
window.loadUrl('https://github.com');
|
||||
});
|
||||
```
|
||||
|
||||
El proceso renderer no es diferente de una página web normal, excepto por la
|
||||
capacidad extra de utilizar módulos de node:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
var remote = require('remote');
|
||||
console.log(remote.require('app').getVersion());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Para ejecutar tu aplicación, lee [Ejecutar la aplicación](../tutorial/quick-start.md#run-your-app).
|
||||
100
docs-translations/es/styleguide.md
Normal file
100
docs-translations/es/styleguide.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# Gúia de estilo de Electron
|
||||
|
||||
Encuentra el apartado correcto para cada tarea: [leer la documentación de Electron](#reading-electron-documentation)
|
||||
o [escribir documentación para Electron](#writing-electron-documentation).
|
||||
|
||||
## Escribir Documentación para Electron
|
||||
|
||||
Estas son las maneras en las que construimos la documentación de Electron.
|
||||
|
||||
- Máximo un título `h1` por página.
|
||||
- Utilizar `bash` en lugar de `cmd` en los bloques de código (por el resaltado
|
||||
de sintaxis).
|
||||
- Los títulos `h1` en el documento deben corresponder al nombre del objeto
|
||||
(ej. `browser-window` → `BrowserWindow`).
|
||||
- Archivos separados por guiones, mas sin embargo, es correcto.
|
||||
- No subtítulos seguidos por otros subtítulos, añadir por lo menos un enunciado
|
||||
de descripción.
|
||||
- Métodos de cabecera son delimitados con apóstrofes: `código`.
|
||||
- Cabeceras de Eventos son delimitados con 'comillas' simples.
|
||||
- No generar listas de mas de dos niveles (debido al renderizador de Markdown
|
||||
desafortunadamente).
|
||||
- Agregar títulos de sección: Eventos, Métodos de Clases y Métodos de Instancia.
|
||||
- Utilizar 'deberá' en lugar de 'debería' al describir resultados.
|
||||
- Eventos y Métodos son cabeceras `h3`.
|
||||
- Argumentos opcionales escritos como `function (required[, optional])`.
|
||||
- Argumentos opcionales son denotados cuando se llaman en listas.
|
||||
- Delimitador de línea de 80-columnas.
|
||||
- Métodos específicos de Plataformas son denotados en itálicas seguidas por la cabecera del método.
|
||||
- ```### `method(foo, bar)` _OS X_```
|
||||
- Preferir 'en el ___ proceso' en lugar de 'sobre el'
|
||||
|
||||
### Traducciones de la Documentación
|
||||
|
||||
Traducciones de documentos de Electron se encuentran dentro del folder
|
||||
`docs-translations`.
|
||||
|
||||
Para agregar otro set (o un set parcial):
|
||||
|
||||
- Crear un subdirectorio nombrado igual a la abreviación del lenguaje.
|
||||
- Dentro de ese subdirectorio, duplicar el directorio de `docs`, manteniendo los
|
||||
mismos nombres de directorios y archivos.
|
||||
- Traducir los archivos.
|
||||
- Actualizar el `README.md` dentro del subdirectorio del lenguaje apuntando a
|
||||
los archivos que has traducido.
|
||||
- Agregar un enlace al folder de tu traducción en la sección principal Electron
|
||||
[README](https://github.com/atom/electron#documentation-translations).
|
||||
|
||||
## Leyendo la Documentación de Electron
|
||||
|
||||
Estos son algunos consejos para entender la sintaxis de la documentación de
|
||||
Electron.
|
||||
|
||||
### Métodos
|
||||
|
||||
Un ejemplo de la documentación del [método](https://developer.mozilla.org/en-US/docs/Glossary/Method):
|
||||
|
||||
---
|
||||
|
||||
`methodName(required[, optional]))`
|
||||
|
||||
* `require` String, **required**
|
||||
* `optional` Integer
|
||||
|
||||
---
|
||||
|
||||
El nombre del método es seguido por los argumentos que recibe. Argumentos
|
||||
opcionales son denotados por corchetes rodeados por el argumento opcional y la
|
||||
coma requerida si el argumento opcional fuera seguido por otro argumento.
|
||||
|
||||
Debajo del método se encuentra más información detallada de cada uno de los
|
||||
argumentos. El tipo de argumento es denotado por los tipos comúnes:
|
||||
[`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String),
|
||||
[`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number),
|
||||
[`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object),
|
||||
[`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
|
||||
o un tipo personalizado como el [`webContent`](api/web-content.md) de Electron.
|
||||
|
||||
### Eventos
|
||||
|
||||
Un ejemplo de documentación del [evento](https://developer.mozilla.org/en-US/docs/Web/API/Event):
|
||||
|
||||
---
|
||||
|
||||
Event: 'wake-up'
|
||||
|
||||
Returns:
|
||||
|
||||
* `time` String
|
||||
|
||||
---
|
||||
|
||||
El evento es una cadena que es utilizada luego de un método observador `.on`. Si
|
||||
regresa un valor, él y su tipo son denotados abajo. Si se estaba a la escucha y
|
||||
respondió a este evento se debería ver así:
|
||||
|
||||
```javascript
|
||||
Alarm.on('wake-up', function(time) {
|
||||
console.log(time)
|
||||
})
|
||||
```
|
||||
@@ -1,10 +1,11 @@
|
||||
# Distribución de aplicaciones
|
||||
# Distribución de la Aplicación
|
||||
|
||||
Para distribuir tu aplicación con Electron, debes nombrar al directorio de tu aplicación
|
||||
como `app`, y ponerlo bajo el directorio de recursos de Electron (en OSX es `Electron.app/Contents/Resources/`,
|
||||
en Linux y Windows es `resources/`):
|
||||
Para distribuir tu aplicación con Electron, el directorio que contiene la
|
||||
aplicación deberá llamarse `app`, y ser colocado debajo del directorio de
|
||||
recursos de Electron (en OSX es `Electron.app/Contents/Resources/`, en Linux y
|
||||
Windows es `resources/`), de esta forma:
|
||||
|
||||
En OSX:
|
||||
En OS X:
|
||||
|
||||
```text
|
||||
electron/Electron.app/Contents/Resources/app/
|
||||
@@ -22,18 +23,19 @@ electron/resources/app
|
||||
└── index.html
|
||||
```
|
||||
|
||||
Posteriormente ejecutas `Electron.app` (o `electron` en Linux, `electron.exe` en Windows),
|
||||
y Electron iniciará la aplicación. El directorio `electron` será la distribución que recibirán los usuarios finales.
|
||||
Luego ejecutar `Electron.app` (o `electron` en Linux, `electron.exe` en Windows),
|
||||
y Electron será iniciado como tu aplicación. El directorio `electron` será
|
||||
entonces tu distribución que recibirán los usuarios finales.
|
||||
|
||||
## Empaquetando tu aplicación como un archivo
|
||||
## Empaquetando tu aplicación en un archivo
|
||||
|
||||
Además de copiar todos tus archivos fuente para la distribución, también puedes
|
||||
empaquetar tu aplicación como un archivo [asar](https://github.com/atom/asar)
|
||||
y de esta forma evitar la exposición del código fuente de tu aplicación a los usuarios.
|
||||
Además de distribuir tu aplicación al copiar todos los archivos de código fuente,
|
||||
también puedes empaquetar tu aplicación como un archivo [asar](https://github.com/atom/asar)
|
||||
y de esta forma evitar exponer del código fuente de tu aplicación a los usuarios.
|
||||
|
||||
Para usar un archivo `asar` en reemplazo de la carpeta `app`, debes renombrar
|
||||
el archivo a `app.asar`, y ponerlo bajo el directorio de recursos de Electron (como arriba),
|
||||
Electron intentará leer el archivo y ejecutar la aplicación desde él.
|
||||
Para utilizar un archivo `asar` en reemplazo del directorio `app`, debes de
|
||||
renombrar el archivo a `app.asar`, y colocarlo por debajo el directorio de recursos
|
||||
de Electron (ver en seguida), Electron intentará leer el archivo y arrancar desde el.
|
||||
|
||||
En OS X:
|
||||
|
||||
@@ -49,30 +51,33 @@ electron/resources/
|
||||
└── app.asar
|
||||
```
|
||||
|
||||
Más detalles en [Empaquetamiento de aplicaciones](application-packaging-es.md).
|
||||
Más detalles en [Empaquetado de Aplicaciones](application-packaging.md).
|
||||
|
||||
## Rebranding con binarios descargados
|
||||
## Redefinición con Binarios Descargados
|
||||
|
||||
Luego de empaquetar tu aplicación con Electron, podría ser útil agregar tu marca
|
||||
antes de realizar la distribución.
|
||||
Luego de empaquetar tu aplicación en Electron, querrás redefinir Electron antes
|
||||
de distribuirlo a los usuarios.
|
||||
|
||||
### Windows
|
||||
|
||||
Puedes renombrar `electron.exe` a cualquier nombre que desees, y editar su ícono y otras informaciones
|
||||
con herramientas como [rcedit](https://github.com/atom/rcedit) o [ResEdit](http://www.resedit.net).
|
||||
Puedes renombrar `electron.exe` a cualquier nombre que desees, y editar su ícono
|
||||
y otra información con herramientas como [rcedit](https://github.com/atom/rcedit)
|
||||
o [ResEdit](http://www.resedit.net).
|
||||
|
||||
### OS X
|
||||
### OSX
|
||||
|
||||
Puedes renombrar `Electron.app` a cualquier nombre que desees. También debes modificar los campos
|
||||
`CFBundleDisplayName`, `CFBundleIdentifier` y `CFBundleName` en los siguientes archivos:
|
||||
Puedes renombrar `Electron.app` a cualquier nombre que desees, y tendrás que
|
||||
renombrar los campos `CFBundleDisplayName`, `CFBundleIdentifier` y `CFBundleName`
|
||||
en los siguientes archivos:
|
||||
|
||||
* `Electron.app/Contents/Info.plist`
|
||||
* `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist`
|
||||
|
||||
También puedes renombrar el helper de la aplicación para evitar que aparezca como `Electron Helper`
|
||||
en el Monitor de Actividades.
|
||||
También puedes renombrar el helper de la aplicación para evitar que aparezca
|
||||
como `Electron Helper` en el Monitor de Actividades. Pero asegurate de renombrar
|
||||
el nombre de archivo del ejecutable.
|
||||
|
||||
La estructura de una aplicación renombrada sería así:
|
||||
La estructura de una aplicación renombrada será:
|
||||
|
||||
```
|
||||
MyApp.app/Contents
|
||||
@@ -98,17 +103,19 @@ MyApp.app/Contents
|
||||
|
||||
Puedes renombrar el ejectuable `electron` a cualquier nombre que desees.
|
||||
|
||||
## Rebranding desde el código fuente de Electron
|
||||
## Redefinición mediante la recompilación de Electron desde el código fuente
|
||||
|
||||
También es posible agregar tu marca a Electron mediante un build personalizado.
|
||||
Para realizar esto debes modificar el archivo `atom.gyp`.
|
||||
También es posible redefinir Electron cambiando el nombre del producto y
|
||||
compilandolo desde sus fuentes. Para realizar esto necesitas modificar el
|
||||
archivo `atom.gyp` y realizar una compilación desde cero.
|
||||
|
||||
### grunt-build-atom-shell
|
||||
|
||||
La modificación del código de Electron para agregar tu marca puede resultar complicada, una tarea Grunt
|
||||
se ha creado para manejar esto de forma automatizada:
|
||||
|
||||
La modificación a mano del código de Electron y su compilación puede resultar
|
||||
complicada, por lo cual se ha generado una tarea Grunt para manejar esto de
|
||||
forma automaticamente:
|
||||
[grunt-build-atom-shell](https://github.com/paulcbetts/grunt-build-atom-shell).
|
||||
|
||||
Esta tarea se encargará de modificar el archivo `.gyp`, compilar el código
|
||||
y reconstruir los módulos nativos de la aplicación para que coincidan con el nuevo nombre.
|
||||
Esta tarea se encargará de modificar el archivo `.gyp`, compilar el código desde
|
||||
las fuentes, y luego reconstruir los módulos nativos de la aplicación para que
|
||||
coincidan con el nuevo nombre del ejecutable.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user