Merge branch 'master' into desktop-capture-api

This commit is contained in:
Cheng Zhao 2015-12-08 12:43:44 +08:00
commit 04f7ceab73
464 changed files with 18563 additions and 4629 deletions

2
.gitignore vendored
View file

@ -1,4 +1,6 @@
.DS_Store .DS_Store
.tags*
/.idea/
/build/ /build/
/dist/ /dist/
/external_binaries/ /external_binaries/

View file

@ -10,6 +10,7 @@ os:
- osx - osx
env: env:
- TARGET_ARCH=x64 - TARGET_ARCH=x64
osx_image: xcode7
matrix: matrix:
include: include:

24
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,24 @@
# Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery
- Personal attacks
- Trolling or insulting/derogatory comments
- Public or private harassment
- Publishing other's private information, such as physical or electronic addresses, without explicit permission
- Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at [atom@github.com](mailto:atom@github.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident.
This Code of Conduct is adapted from the Contributor Covenant, version 1.3.0, available from http://contributor-covenant.org/version/1/3/0/

80
CONTRIBUTING-ko.md Normal file
View file

@ -0,0 +1,80 @@
# Electron에 기여하기
:+1::tada: 먼저, 이 프로젝트에 기여해주셔서 감사합니다! :tada::+1:
이 프로젝트는 기여자 규약 [행동강령](CODE_OF_CONDUCT.md)을 준수합니다. 따라서 이
프로젝트의 개발에 참여하려면 이 규약을 지켜야 합니다. 받아들일 수 없는 행위를 발견했을
경우 atom@github.com로 보고 하십시오.
다음 항목들은 Electron에 기여하는 가이드라인을 제시합니다.
참고로 이 항목들은 그저 가이드라인에 불과하며 규칙이 아닙니다. 따라서 스스로의 적절한
판단에 따라 이 문서의 변경을 제안할 수 있으며 변경시 pull request를 넣으면 됩니다.
## 이슈 제출
* [여기](https://github.com/atom/electron/issues/new)에서 새로운 이슈를 만들 수
있습니다. 하지만 이슈를 작성하기 전에 아래의 항목들을 숙지하고 가능한한 이슈 보고에
대해 최대한 많은 정보와 자세한 설명을 포함해야 합니다. 가능하다면 다음 항목을 포함해야
합니다:
* 사용하고 있는 Electron의 버전
* 현재 사용중인 운영체제
* 가능하다면 무엇을 하려고 했고, 어떤 결과를 예측했으며, 어떤 것이 예측된대로
작동하지 않았는지에 대해 서술해야 합니다.
* 추가로 다음 사항을 준수하면 이슈를 해결하는데 큰 도움이 됩니다:
* 스크린샷 또는 GIF 애니메이션 이미지들
* 터미널에 출력된 에러의 내용 또는 개발자 도구, 알림창에 뜬 내용
* [Cursory search](https://github.com/atom/electron/issues?utf8=✓&q=is%3Aissue+)를
통해 이미 비슷한 내용의 이슈가 등록되어있는지 확인
## Pull Request 하기
* 가능한한 스크린샷과 GIF 애니메이션 이미지를 pull request에 추가
* CoffeeScript, JavaScript, C++과 Python등
[참조문서에 정의된 코딩스타일](/docs-translations/ko-KR/development/coding-style.md)을
준수
* [문서 스타일 가이드](/docs-translations/ko-KR/styleguide.md)에 따라 문서를
[Markdown](https://daringfireball.net/projects/markdown) 형식으로 작성.
* 짧은, 현재 시제 커밋 메시지 사용. [커밋 메시지 스타일 가이드](#Git-커밋-메시지)를
참고하세요
## 스타일 가이드
### 공통 코드
* 파일 마지막에 공백 라인(newline) 추가
* 다음 순서에 맞춰서 require 코드 작성:
* Node 빌트인 모듈 (`path` 같은)
* Electron 모듈 (`ipc`, `app` 같은)
* 로컬 모듈 (상대 경로상에 있는)
* 다음 순서에 맞춰서 클래스 속성 지정:
* 클래스 메서드와 속성 (메서드는 `@`로 시작)
* 인스턴스 메서드와 속성
* 플랫폼 종속적인 코드 자제:
* 파일 이름 결합시 `path.join()`을 사용.
* 임시 디렉터리가 필요할 땐 `/tmp` 대신 `os.tmpdir()`을 통해 접근.
* 명시적인 함수 종료가 필요할 땐 `return` 만 사용.
* `return null`, `return undefined`, `null`, 또는 `undefined` 사용 X
### Git 커밋 메시지
* 현재 시제 사용 ("Added feature" 대신 "Add feature" 사용)
* 필수적 분위기(imperative mood) 사용 ("Moves cursor to..." 대신 "Move cursor to..." 사용)
* 첫 줄은 72자에 맞추거나 그 보다 적게 제한
* 자유롭게 필요에 따라 이슈나 PR링크를 참조
* 단순한 문서 변경일 경우 `[ci skip]`을 커밋 메시지에 추가
* 커밋 메시지의 도입부에 의미있는 이모티콘 사용:
* :art: `:art:` 코드의 포맷이나 구조를 개선(추가)했을 때
* :racehorse: `:racehorse:` 성능을 개선했을 때
* :non-potable_water: `:non-potable_water:` 메모리 누수를 연결했을 때
* :memo: `:memo:` 문서를 작성했을 때
* :penguin: `:penguin:` Linux에 대한 패치를 했을 때
* :apple: `:apple:` Mac OS에 대한 패치를 했을 때
* :checkered_flag: `:checkered_flag:` Windows에 대한 패치를 했을 때
* :bug: `:bug:` 버그를 고쳤을 때
* :fire: `:fire:` 코드 또는 파일을 삭제했을 때
* :green_heart: `:green_heart:` CI 빌드를 고쳤을 때
* :white_check_mark: `:white_check_mark:` 테스트를 추가했을 때
* :lock: `:lock:` 보안 문제를 해결했을 때
* :arrow_up: `:arrow_up:` 종속성 라이브러리를 업데이트 했을 때
* :arrow_down: `:arrow_down:` 종속성 라이브러리를 다운그레이드 했을 때
* :shirt: `:shirt:` linter(코드 검사기)의 경고를 제거했을 때

View file

@ -2,8 +2,9 @@
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1: :+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0). This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md).
By participating, you are expected to uphold this code. Please report unacceptable behavior to atom@github.com. By participating, you are expected to uphold this code. Please report unacceptable
behavior to atom@github.com.
The following is a set of guidelines for contributing to Electron. The following is a set of guidelines for contributing to Electron.
These are just guidelines, not rules, use your best judgment and feel free to These are just guidelines, not rules, use your best judgment and feel free to
@ -57,6 +58,7 @@ possible with your report. If you can, please include:
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...") * Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
* Limit the first line to 72 characters or less * Limit the first line to 72 characters or less
* Reference issues and pull requests liberally * Reference issues and pull requests liberally
* When only changing documentation, include `[ci skip]` in the commit description
* Consider starting the commit message with an applicable emoji: * Consider starting the commit message with an applicable emoji:
* :art: `:art:` when improving the format/structure of the code * :art: `:art:` when improving the format/structure of the code
* :racehorse: `:racehorse:` when improving performance * :racehorse: `:racehorse:` when improving performance

View file

@ -8,18 +8,26 @@
:zap: *프레임워크 이름이 Atom Shell에서 Electron으로 변경되었습니다* :zap: :zap: *프레임워크 이름이 Atom Shell에서 Electron으로 변경되었습니다* :zap:
Electron 프레임워크는 JavaScript, HTML 그리고 CSS를 사용하여 Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주는 프레임워크입니다. 이 프레임워크는 [io.js](http://iojs.org) 와 Electron 프레임워크는 JavaScript, HTML 그리고 CSS를 사용하여
[Chromium](http://www.chromium.org)을 기반으로 만들어 졌으며 [Atom Editor](https://github.com/atom/atom)에 사용되고 있습니다. 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)를 팔로우 하세요. Electron에 대한 중요한 알림을 받고 싶다면 Twitter에서
[@ElectronJS](https://twitter.com/electronjs)를 팔로우 하세요.
이 프로젝트는 기여자 규약 1.2를 준수합니다. 이 프로젝트에 참여할 때 코드를 유지해야 합니다. 받아들일 수 없는 행동은 atom@github.com로 보고 하십시오. 이 프로젝트는 기여자 규약 [행동강령](CODE_OF_CONDUCT.md)을 준수합니다. 따라서 이
프로젝트의 개발에 참여하려면 이 규약을 지켜야 합니다. 받아들일 수 없는 행위를 발견했을
경우 atom@github.com로 보고 하십시오.
## 다운로드 ## 다운로드
Linux, Windows, Mac용으로 미리 빌드된 Electron 바이너리와 디버그 심볼이 준비되어 있습니다. [releases](https://github.com/atom/electron/releases) 페이지에서 받아 볼 수 있습니다. Linux, Windows, OS X 용으로 미리 빌드된 Electron 바이너리와 디버그 심볼이 준비되어
있습니다. [releases](https://github.com/atom/electron/releases) 페이지에서 받아 볼
수 있습니다.
또한 [`npm`](https://docs.npmjs.com/)을 통해 미리 빌드된 Electron 바이너리를 받을 수도 있습니다: 또한 [`npm`](https://docs.npmjs.com/)을 통해 미리 빌드된 Electron 바이너리를 설치할
수도 있습니다:
```sh ```sh
# $PATH에 `electron` 커맨드를 등록하고 전역에 설치합니다. # $PATH에 `electron` 커맨드를 등록하고 전역에 설치합니다.
@ -35,8 +43,9 @@ npm install electron-prebuilt --save-dev
## 참조 문서 ## 참조 문서
[Docs](https://github.com/atom/electron/tree/master/docs/README.md)에 개발 가이드와 API 레퍼런스가 있습니다. [Docs](https://github.com/atom/electron/tree/master/docs/README.md)에 개발 지침과
Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법도 문서에 포함되어 있으니 참고하시기 바랍니다. API 레퍼런스가 있습니다. Electron을 빌드 하는 방법과 프로젝트에 기여하는법 또한 문서에
포함되어 있으니 참고하시기 바랍니다.
## 참조 문서 (번역) ## 참조 문서 (번역)
@ -47,12 +56,19 @@ Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법도 문
- [중국어 간체](https://github.com/atom/electron/tree/master/docs-translations/zh-CN) - [중국어 간체](https://github.com/atom/electron/tree/master/docs-translations/zh-CN)
- [중국어 번체](https://github.com/atom/electron/tree/master/docs-translations/zh-TW) - [중국어 번체](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) 카테고리 - Atom 포럼의 [`electron`](http://discuss.atom.io/c/electron) 카테고리
- Freenode 채팅의 `#atom-shell` 채널 - Freenode 채팅의 `#atom-shell` 채널
- Slack의 [`Atom`](http://atom-slack.herokuapp.com/) 채널 - Slack의 [`Atom`](http://atom-slack.herokuapp.com/) 채널
[awesome-electron](https://github.com/sindresorhus/awesome-electron) 프로젝트엔 커뮤니티가 운영중인 유용한 예제 어플리케이션과 도구, 리소스가 있으니 한번 참고해 보시기 바랍니다. [awesome-electron](https://github.com/sindresorhus/awesome-electron) 프로젝트에
커뮤니티가 운영중인 유용한 예제 어플리케이션과 도구, 리소스가 있으니 한번 참고해 보시기
바랍니다.

View file

@ -7,20 +7,20 @@
:zap: *Formerly known as Atom Shell* :zap: :zap: *Formerly known as Atom Shell* :zap:
The Electron framework lets you write cross-platform desktop applications 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 [Chromium](http://www.chromium.org) and is used in the [Atom
editor](https://github.com/atom/atom). editor](https://github.com/atom/atom).
Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important
announcements. announcements.
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0). This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md).
By participating, you are expected to uphold this code. Please report By participating, you are expected to uphold this code. Please report unacceptable
unacceptable behavior to atom@github.com. behavior to atom@github.com.
## Downloads ## Downloads
Prebuilt binaries and debug symbols of Electron for Linux, Windows and Mac can Prebuilt binaries and debug symbols of Electron for Linux, Windows and OS X can
be found on the [releases](https://github.com/atom/electron/releases) page. be found on the [releases](https://github.com/atom/electron/releases) page.
You can also use [`npm`](https://docs.npmjs.com/) to install prebuilt electron You can also use [`npm`](https://docs.npmjs.com/) to install prebuilt electron
@ -52,15 +52,22 @@ contains documents describing how to build and contribute to Electron.
- [Spanish](https://github.com/atom/electron/tree/master/docs-translations/es) - [Spanish](https://github.com/atom/electron/tree/master/docs-translations/es)
- [Simplified Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-CN) - [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) - [Traditional Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-TW)
- [Russian](https://github.com/atom/electron/tree/master/docs-translations/ru-RU)
## 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 ## Community
You can ask questions and interact with the community in the following You can ask questions and interact with the community in the following
locations: locations:
- [`electron`](http://discuss.atom.io/category/electron) category on the Atom - [`electron`](http://discuss.atom.io/c/electron) category on the Atom
forums forums
- `#atom-shell` channel on Freenode - `#atom-shell` channel on Freenode
- [`Atom`](http://atom-slack.herokuapp.com/) channel on Slack - [`Atom`](http://atom-slack.herokuapp.com/) channel on Slack
- [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)*
Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron) Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron)
for a community maintained list of useful example apps, tools and resources. for a community maintained list of useful example apps, tools and resources.

View file

@ -4,7 +4,7 @@
'product_name%': 'Electron', 'product_name%': 'Electron',
'company_name%': 'GitHub, Inc', 'company_name%': 'GitHub, Inc',
'company_abbr%': 'github', 'company_abbr%': 'github',
'version%': '0.33.1', 'version%': '0.36.0',
}, },
'includes': [ 'includes': [
'filenames.gypi', 'filenames.gypi',
@ -64,9 +64,6 @@
'files': [ 'files': [
'<(PRODUCT_DIR)/<(product_name) Helper.app', '<(PRODUCT_DIR)/<(product_name) Helper.app',
'<(PRODUCT_DIR)/<(product_name) Framework.framework', '<(PRODUCT_DIR)/<(product_name) Framework.framework',
'external_binaries/Squirrel.framework',
'external_binaries/ReactiveCocoa.framework',
'external_binaries/Mantle.framework',
], ],
}, },
{ {
@ -109,7 +106,21 @@
'<@(locale_dirs)', '<@(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" }, { # OS=="mac"
'dependencies': [ 'dependencies': [
'make_locale_paks', 'make_locale_paks',
@ -290,12 +301,28 @@
'vendor/breakpad/breakpad.gyp:breakpad_sender', 'vendor/breakpad/breakpad.gyp:breakpad_sender',
], ],
}], # OS=="win" }], # OS=="win"
['OS=="mac"', { ['OS=="mac" and mas_build==0', {
'dependencies': [ 'dependencies': [
'vendor/crashpad/client/client.gyp:crashpad_client', 'vendor/crashpad/client/client.gyp:crashpad_client',
'vendor/crashpad/handler/handler.gyp:crashpad_handler', '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"', { ['OS=="linux"', {
'link_settings': { 'link_settings': {
'ldflags': [ 'ldflags': [
@ -398,9 +425,6 @@
'libraries': [ 'libraries': [
'$(SDKROOT)/System/Library/Frameworks/Carbon.framework', '$(SDKROOT)/System/Library/Frameworks/Carbon.framework',
'$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework', '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework',
'external_binaries/Squirrel.framework',
'external_binaries/ReactiveCocoa.framework',
'external_binaries/Mantle.framework',
], ],
}, },
'mac_bundle': 1, 'mac_bundle': 1,
@ -444,12 +468,6 @@
'<@(copied_libraries)', '<@(copied_libraries)',
], ],
}, },
{
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Resources',
'files': [
'<(PRODUCT_DIR)/crashpad_handler',
],
},
], ],
'postbuilds': [ 'postbuilds': [
{ {
@ -481,6 +499,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 framework
{ {
'target_name': '<(project_name)_helper', 'target_name': '<(project_name)_helper',

View file

@ -31,8 +31,8 @@ content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path,
plugin.path = path; plugin.path = path;
plugin.permissions = ppapi::PERMISSION_ALL_BITS; plugin.permissions = ppapi::PERMISSION_ALL_BITS;
std::vector<std::string> flash_version_numbers; std::vector<std::string> flash_version_numbers = base::SplitString(
base::SplitString(version, '.', &flash_version_numbers); version, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (flash_version_numbers.size() < 1) if (flash_version_numbers.size() < 1)
flash_version_numbers.push_back("11"); flash_version_numbers.push_back("11");
// |SplitString()| puts in an empty string given an empty string. :( // |SplitString()| puts in an empty string given an empty string. :(
@ -47,7 +47,7 @@ content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path,
// E.g., "Shockwave Flash 10.2 r154": // E.g., "Shockwave Flash 10.2 r154":
plugin.description = plugin.name + " " + flash_version_numbers[0] + "." + plugin.description = plugin.name + " " + flash_version_numbers[0] + "." +
flash_version_numbers[1] + " r" + flash_version_numbers[2]; flash_version_numbers[1] + " r" + flash_version_numbers[2];
plugin.version = JoinString(flash_version_numbers, '.'); plugin.version = base::JoinString(flash_version_numbers, ".");
content::WebPluginMimeType swf_mime_type( content::WebPluginMimeType swf_mime_type(
content::kFlashPluginSwfMimeType, content::kFlashPluginSwfMimeType,
content::kFlashPluginSwfExtension, content::kFlashPluginSwfExtension,
@ -81,25 +81,24 @@ std::string AtomContentClient::GetUserAgent() const {
} }
void AtomContentClient::AddAdditionalSchemes( void AtomContentClient::AddAdditionalSchemes(
std::vector<std::string>* standard_schemes, std::vector<url::SchemeWithType>* standard_schemes,
std::vector<std::string>* savable_schemes) { std::vector<std::string>* savable_schemes) {
auto command_line = base::CommandLine::ForCurrentProcess(); auto command_line = base::CommandLine::ForCurrentProcess();
auto custom_schemes = command_line->GetSwitchValueASCII( auto custom_schemes = command_line->GetSwitchValueASCII(
switches::kRegisterStandardSchemes); switches::kRegisterStandardSchemes);
if (!custom_schemes.empty()) { if (!custom_schemes.empty()) {
std::vector<std::string> schemes; std::vector<std::string> schemes = base::SplitString(
base::SplitString(custom_schemes, ',', &schemes); custom_schemes, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
standard_schemes->insert(standard_schemes->end(), for (const std::string& scheme : schemes)
schemes.begin(), standard_schemes->push_back({scheme.c_str(), url::SCHEME_WITHOUT_PORT});
schemes.end());
} }
standard_schemes->push_back("chrome-extension"); standard_schemes->push_back({"chrome-extension", url::SCHEME_WITHOUT_PORT});
} }
void AtomContentClient::AddPepperPlugins( void AtomContentClient::AddPepperPlugins(
std::vector<content::PepperPluginInfo>* plugins) { std::vector<content::PepperPluginInfo>* plugins) {
auto command_line = base::CommandLine::ForCurrentProcess(); auto command_line = base::CommandLine::ForCurrentProcess();
auto flash_path = command_line->GetSwitchValueNative( auto flash_path = command_line->GetSwitchValuePath(
switches::kPpapiFlashPath); switches::kPpapiFlashPath);
if (flash_path.empty()) if (flash_path.empty())
return; return;
@ -108,7 +107,7 @@ void AtomContentClient::AddPepperPlugins(
switches::kPpapiFlashVersion); switches::kPpapiFlashVersion);
plugins->push_back( plugins->push_back(
CreatePepperFlashInfo(base::FilePath(flash_path), flash_version)); CreatePepperFlashInfo(flash_path, flash_version));
} }
} // namespace atom } // namespace atom

View file

@ -22,7 +22,7 @@ class AtomContentClient : public brightray::ContentClient {
std::string GetProduct() const override; std::string GetProduct() const override;
std::string GetUserAgent() const override; std::string GetUserAgent() const override;
void AddAdditionalSchemes( void AddAdditionalSchemes(
std::vector<std::string>* standard_schemes, std::vector<url::SchemeWithType>* standard_schemes,
std::vector<std::string>* savable_schemes) override; std::vector<std::string>* savable_schemes) override;
void AddPepperPlugins( void AddPepperPlugins(
std::vector<content::PepperPluginInfo>* plugins) override; std::vector<content::PepperPluginInfo>* plugins) override;

View file

@ -10,6 +10,7 @@
#include "base/at_exit.h" #include "base/at_exit.h"
#include "base/i18n/icu_util.h" #include "base/i18n/icu_util.h"
#include "base/mac/bundle_locations.h" #include "base/mac/bundle_locations.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "brightray/common/mac/main_application_bundle.h" #include "brightray/common/mac/main_application_bundle.h"
#include "content/public/app/content_main.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[]) { int AtomInitializeICUandStartNode(int argc, char *argv[]) {
base::AtExitManager atexit_manager; base::AtExitManager atexit_manager;
base::mac::ScopedNSAutoreleasePool pool;
base::mac::SetOverrideFrameworkBundlePath( base::mac::SetOverrideFrameworkBundlePath(
brightray::MainApplicationBundlePath() brightray::MainApplicationBundlePath()
.Append("Contents") .Append("Contents")

View file

@ -5,7 +5,6 @@
#include "atom/app/atom_main.h" #include "atom/app/atom_main.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#if defined(OS_WIN) #if defined(OS_WIN)
#include <stdio.h> #include <stdio.h>
@ -36,10 +35,33 @@
#include "base/at_exit.h" #include "base/at_exit.h"
#include "base/i18n/icu_util.h" #include "base/i18n/icu_util.h"
#if defined(OS_WIN)
namespace { namespace {
const char* kRunAsNode = "ELECTRON_RUN_AS_NODE";
const char* kOldRunAsNode = "ATOM_SHELL_INTERNAL_RUN_AS_NODE";
bool IsEnvSet(const char* name) {
#if defined(OS_WIN)
size_t required_size;
getenv_s(&required_size, nullptr, 0, name);
return required_size != 0;
#else
char* indicator = getenv(name);
return indicator && indicator[0] != '\0';
#endif
}
bool IsRunAsNode() {
return IsEnvSet(kRunAsNode) || IsEnvSet(kOldRunAsNode);
}
#if defined(OS_WIN)
bool IsCygwin() {
std::string os;
scoped_ptr<base::Environment> env(base::Environment::Create());
return env->GetVar("OS", &os) && os == "cygwin";
}
// Win8.1 supports monitor-specific DPI scaling. // Win8.1 supports monitor-specific DPI scaling.
bool SetProcessDpiAwarenessWrapper(PROCESS_DPI_AWARENESS value) { bool SetProcessDpiAwarenessWrapper(PROCESS_DPI_AWARENESS value) {
typedef HRESULT(WINAPI *SetProcessDpiAwarenessPtr)(PROCESS_DPI_AWARENESS); typedef HRESULT(WINAPI *SetProcessDpiAwarenessPtr)(PROCESS_DPI_AWARENESS);
@ -77,24 +99,22 @@ void EnableHighDPISupport() {
SetProcessDPIAwareWrapper(); SetProcessDPIAwareWrapper();
} }
} }
#endif
} // namespace } // namespace
#if defined(OS_WIN)
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) { int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
int argc = 0; int argc = 0;
wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
scoped_ptr<base::Environment> env(base::Environment::Create());
// Make output work in console if we are not in cygiwn. // Make output work in console if we are not in cygiwn.
std::string os; if (!IsCygwin() && !IsEnvSet("ELECTRON_NO_ATTACH_CONSOLE")) {
if (env->GetVar("OS", &os) && os != "cygwin") {
AttachConsole(ATTACH_PARENT_PROCESS); AttachConsole(ATTACH_PARENT_PROCESS);
FILE* dontcare; FILE* dontcare;
freopen_s(&dontcare, "CON", "w", stdout); freopen_s(&dontcare, "CON", "w", stdout);
freopen_s(&dontcare, "CON", "w", stderr); freopen_s(&dontcare, "CON", "w", stderr);
freopen_s(&dontcare, "CON", "r", stdin);
} }
// Convert argv to to UTF8 // Convert argv to to UTF8
@ -131,16 +151,12 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
} }
} }
std::string node_indicator, crash_service_indicator; if (IsRunAsNode()) {
if (env->GetVar("ATOM_SHELL_INTERNAL_RUN_AS_NODE", &node_indicator) &&
node_indicator == "1") {
// Now that argv conversion is done, we can finally start. // Now that argv conversion is done, we can finally start.
base::AtExitManager atexit_manager; base::AtExitManager atexit_manager;
base::i18n::InitializeICU(); base::i18n::InitializeICU();
return atom::NodeMain(argc, argv); return atom::NodeMain(argc, argv);
} else if (env->GetVar("ATOM_SHELL_INTERNAL_CRASH_SERVICE", } else if (IsEnvSet("ATOM_SHELL_INTERNAL_CRASH_SERVICE")) {
&crash_service_indicator) &&
crash_service_indicator == "1") {
return crash_service::Main(cmd); return crash_service::Main(cmd);
} }
@ -164,8 +180,7 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
#elif defined(OS_LINUX) // defined(OS_WIN) #elif defined(OS_LINUX) // defined(OS_WIN)
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
char* node_indicator = getenv("ATOM_SHELL_INTERNAL_RUN_AS_NODE"); if (IsRunAsNode()) {
if (node_indicator != NULL && strcmp(node_indicator, "1") == 0) {
base::i18n::InitializeICU(); base::i18n::InitializeICU();
base::AtExitManager atexit_manager; base::AtExitManager atexit_manager;
return atom::NodeMain(argc, const_cast<char**>(argv)); return atom::NodeMain(argc, const_cast<char**>(argv));
@ -182,8 +197,7 @@ int main(int argc, const char* argv[]) {
#else // defined(OS_LINUX) #else // defined(OS_LINUX)
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
char* node_indicator = getenv("ATOM_SHELL_INTERNAL_RUN_AS_NODE"); if (IsRunAsNode()) {
if (node_indicator != NULL && strcmp(node_indicator, "1") == 0) {
return AtomInitializeICUandStartNode(argc, const_cast<char**>(argv)); return AtomInitializeICUandStartNode(argc, const_cast<char**>(argv));
} }

View file

@ -5,6 +5,7 @@
#include "atom/app/atom_main_delegate.h" #include "atom/app/atom_main_delegate.h"
#include <string> #include <string>
#include <iostream>
#include "atom/app/atom_content_client.h" #include "atom/app/atom_content_client.h"
#include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_client.h"
@ -15,11 +16,21 @@
#include "base/debug/stack_trace.h" #include "base/debug/stack_trace.h"
#include "base/environment.h" #include "base/environment.h"
#include "base/logging.h" #include "base/logging.h"
#include "chrome/common/chrome_paths.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_bundle.h"
namespace atom { namespace atom {
namespace {
bool IsBrowserProcess(base::CommandLine* cmd) {
std::string process_type = cmd->GetSwitchValueASCII(switches::kProcessType);
return process_type.empty();
}
} // namespace
AtomMainDelegate::AtomMainDelegate() { AtomMainDelegate::AtomMainDelegate() {
} }
@ -27,10 +38,16 @@ AtomMainDelegate::~AtomMainDelegate() {
} }
bool AtomMainDelegate::BasicStartupComplete(int* exit_code) { bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
// Disable logging out to debug.log on Windows auto command_line = base::CommandLine::ForCurrentProcess();
logging::LoggingSettings settings; logging::LoggingSettings settings;
#if defined(OS_WIN) #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) #if defined(DEBUG)
// Print logging to debug.log on Windows
settings.logging_dest = logging::LOG_TO_ALL; settings.logging_dest = logging::LOG_TO_ALL;
settings.log_file = L"debug.log"; settings.log_file = L"debug.log";
settings.lock_log = logging::LOCK_LOG_FILE; settings.lock_log = logging::LOCK_LOG_FILE;
@ -41,15 +58,29 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
#else // defined(OS_WIN) #else // defined(OS_WIN)
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
#endif // !defined(OS_WIN) #endif // !defined(OS_WIN)
// Only enable logging when --enable-logging is specified.
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::InitLogging(settings);
// Logging with pid and timestamp. // Logging with pid and timestamp.
logging::SetLogItems(true, false, true, false); logging::SetLogItems(true, false, true, false);
#if defined(DEBUG) && defined(OS_LINUX)
// Enable convient stack printing. // 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 #endif
if (enable_stack_dumping)
base::debug::EnableInProcessStackDumping();
chrome::RegisterPathProvider();
return brightray::MainDelegate::BasicStartupComplete(exit_code); return brightray::MainDelegate::BasicStartupComplete(exit_code);
} }
@ -71,16 +102,9 @@ void AtomMainDelegate::PreSandboxStartup() {
} }
// Only append arguments for browser process. // Only append arguments for browser process.
if (!process_type.empty()) if (!IsBrowserProcess(command_line))
return; return;
#if defined(OS_WIN)
// Disable the LegacyRenderWidgetHostHWND, it made frameless windows unable
// to move and resize. We may consider enabling it again after upgraded to
// Chrome 38, which should have fixed the problem.
command_line->AppendSwitch(switches::kDisableLegacyIntermediateWindow);
#endif
// Disable renderer sandbox for most of node's functions. // Disable renderer sandbox for most of node's functions.
command_line->AppendSwitch(switches::kNoSandbox); command_line->AppendSwitch(switches::kNoSandbox);

View file

@ -7,8 +7,8 @@
#include "atom/app/uv_task_runner.h" #include "atom/app/uv_task_runner.h"
#include "atom/browser/javascript_environment.h" #include "atom/browser/javascript_environment.h"
#include "atom/browser/node_debugger.h" #include "atom/browser/node_debugger.h"
#include "atom/common/node_includes.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "atom/common/node_includes.h"
#include "base/thread_task_runner_handle.h" #include "base/thread_task_runner_handle.h"
#include "gin/array_buffer.h" #include "gin/array_buffer.h"
#include "gin/public/isolate_holder.h" #include "gin/public/isolate_holder.h"
@ -19,25 +19,22 @@ namespace atom {
int NodeMain(int argc, char *argv[]) { int NodeMain(int argc, char *argv[]) {
base::CommandLine::Init(argc, 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; int exit_code = 1;
{ {
// Feed gin::PerIsolateData with a task runner. // Feed gin::PerIsolateData with a task runner.
argv = uv_setup_args(argc, argv);
uv_loop_t* loop = uv_default_loop(); uv_loop_t* loop = uv_default_loop();
scoped_refptr<UvTaskRunner> uv_task_runner(new UvTaskRunner(loop)); scoped_refptr<UvTaskRunner> uv_task_runner(new UvTaskRunner(loop));
base::ThreadTaskRunnerHandle handle(uv_task_runner); base::ThreadTaskRunnerHandle handle(uv_task_runner);
gin::V8Initializer::LoadV8Snapshot(); gin::V8Initializer::LoadV8Snapshot();
gin::V8Initializer::LoadV8Natives(); gin::V8Initializer::LoadV8Natives();
gin::IsolateHolder::Initialize(
gin::IsolateHolder::kNonStrictMode,
gin::ArrayBufferAllocator::SharedInstance());
JavascriptEnvironment gin_env; 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( node::Environment* env = node::CreateEnvironment(
gin_env.isolate(), loop, gin_env.context(), argc, argv, gin_env.isolate(), loop, gin_env.context(), argc, argv,
exec_argc, exec_argv); exec_argc, exec_argv);

View file

@ -48,8 +48,13 @@ void UvTaskRunner::OnTimeout(uv_timer_t* timer) {
self->tasks_[timer].Run(); self->tasks_[timer].Run();
self->tasks_.erase(timer); self->tasks_.erase(timer);
uv_unref(reinterpret_cast<uv_handle_t*>(timer)); uv_timer_stop(timer);
delete 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 } // namespace atom

View file

@ -31,6 +31,7 @@ class UvTaskRunner : public base::SingleThreadTaskRunner {
private: private:
static void OnTimeout(uv_timer_t* timer); static void OnTimeout(uv_timer_t* timer);
static void OnClose(uv_handle_t* handle);
uv_loop_t* loop_; uv_loop_t* loop_;

View file

@ -7,26 +7,29 @@
#include <string> #include <string>
#include <vector> #include <vector>
#if defined(OS_WIN)
#include <shlobj.h>
#endif
#include "atom/browser/api/atom_api_menu.h" #include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/api/atom_api_session.h" #include "atom/browser/api/atom_api_session.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/login_handler.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/net_converter.h"
#include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
#include "atom/common/options_switches.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/environment.h" #include "base/environment.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "brightray/browser/brightray_paths.h" #include "brightray/browser/brightray_paths.h"
#include "chrome/common/chrome_paths.h"
#include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/gpu_data_manager.h" #include "content/public/browser/gpu_data_manager.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/content_switches.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h" #include "native_mate/object_template_builder.h"
#include "net/ssl/ssl_cert_request_info.h" #include "net/ssl/ssl_cert_request_info.h"
@ -61,21 +64,6 @@ struct Converter<Browser::UserTask> {
}; };
#endif #endif
template<>
struct Converter<scoped_refptr<net::X509Certificate>> {
static v8::Local<v8::Value> ToV8(
v8::Isolate* isolate,
const scoped_refptr<net::X509Certificate>& val) {
mate::Dictionary dict(isolate, v8::Object::New(isolate));
std::string encoded_data;
net::X509Certificate::GetPEMEncoded(
val->os_cert_handle(), &encoded_data);
dict.Set("data", encoded_data);
dict.Set("issuerName", val->issuer().GetDisplayName());
return dict.GetHandle();
}
};
} // namespace mate } // namespace mate
@ -99,22 +87,47 @@ int GetPathConstant(const std::string& name) {
return base::DIR_HOME; return base::DIR_HOME;
else if (name == "temp") else if (name == "temp")
return base::DIR_TEMP; return base::DIR_TEMP;
else if (name == "userDesktop") else if (name == "userDesktop" || name == "desktop")
return base::DIR_USER_DESKTOP; return base::DIR_USER_DESKTOP;
else if (name == "exe") else if (name == "exe")
return base::FILE_EXE; return base::FILE_EXE;
else if (name == "module") else if (name == "module")
return base::FILE_MODULE; return base::FILE_MODULE;
else if (name == "documents")
return chrome::DIR_USER_DOCUMENTS;
else if (name == "downloads")
return chrome::DIR_DEFAULT_DOWNLOADS;
else if (name == "music")
return chrome::DIR_USER_MUSIC;
else if (name == "pictures")
return chrome::DIR_USER_PICTURES;
else if (name == "videos")
return chrome::DIR_USER_VIDEOS;
else else
return -1; 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( void OnClientCertificateSelected(
v8::Isolate* isolate, v8::Isolate* isolate,
std::shared_ptr<content::ClientCertificateDelegate> delegate, std::shared_ptr<content::ClientCertificateDelegate> delegate,
mate::Arguments* args) { mate::Arguments* args) {
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
mate::Dictionary cert_data; mate::Dictionary cert_data;
if (!(args->Length() == 1 && args->GetNext(&cert_data))) { if (!(args->Length() == 1 && args->GetNext(&cert_data))) {
args->ThrowError(); args->ThrowError();
@ -128,18 +141,29 @@ void OnClientCertificateSelected(
net::X509Certificate::CreateCertificateListFromBytes( net::X509Certificate::CreateCertificateListFromBytes(
encoded_data.data(), encoded_data.size(), encoded_data.data(), encoded_data.size(),
net::X509Certificate::FORMAT_AUTO); net::X509Certificate::FORMAT_AUTO);
delegate->ContinueWithCertificate(certs[0].get()); delegate->ContinueWithCertificate(certs[0].get());
} }
void PassLoginInformation(scoped_refptr<LoginHandler> login_handler,
mate::Arguments* args) {
base::string16 username, password;
if (args->GetNext(&username) && args->GetNext(&password))
login_handler->Login(username, password);
else
login_handler->CancelAuth();
}
} // namespace } // namespace
App::App() { App::App() {
static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())->set_delegate(this);
Browser::Get()->AddObserver(this); Browser::Get()->AddObserver(this);
content::GpuDataManager::GetInstance()->AddObserver(this); content::GpuDataManager::GetInstance()->AddObserver(this);
} }
App::~App() { App::~App() {
static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())->set_delegate(
nullptr);
Browser::Get()->RemoveObserver(this); Browser::Get()->RemoveObserver(this);
content::GpuDataManager::GetInstance()->RemoveObserver(this); content::GpuDataManager::GetInstance()->RemoveObserver(this);
} }
@ -158,6 +182,11 @@ void App::OnWindowAllClosed() {
void App::OnQuit() { void App::OnQuit() {
Emit("quit"); Emit("quit");
if (process_singleton_.get()) {
process_singleton_->Cleanup();
process_singleton_.reset();
}
} }
void App::OnOpenFile(bool* prevent_default, const std::string& file_path) { void App::OnOpenFile(bool* prevent_default, const std::string& file_path) {
@ -177,26 +206,62 @@ void App::OnWillFinishLaunching() {
} }
void App::OnFinishLaunching() { void App::OnFinishLaunching() {
// Create the defaultSession.
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto browser_context = static_cast<AtomBrowserContext*>(
AtomBrowserMainParts::Get()->browser_context());
auto handle = Session::CreateFrom(isolate(), browser_context);
default_session_.Reset(isolate(), handle.ToV8());
Emit("ready"); Emit("ready");
} }
void App::OnSelectCertificate( void App::OnLogin(LoginHandler* login_handler) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
bool prevent_default = Emit(
"login",
WebContents::CreateFrom(isolate(), login_handler->GetWebContents()),
login_handler->request(),
login_handler->auth_info(),
base::Bind(&PassLoginInformation, make_scoped_refptr(login_handler)));
// Default behavior is to always cancel the auth.
if (!prevent_default)
login_handler->CancelAuth();
}
void App::AllowCertificateError(
int pid,
int fid,
int cert_error,
const net::SSLInfo& ssl_info,
const GURL& request_url,
content::ResourceType resource_type,
bool overridable,
bool strict_enforcement,
bool expired_previous_decision,
const base::Callback<void(bool)>& callback,
content::CertificateRequestResultType* request) {
auto rfh = content::RenderFrameHost::FromID(pid, fid);
auto web_contents = content::WebContents::FromRenderFrameHost(rfh);
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
bool prevent_default = Emit("certificate-error",
WebContents::CreateFrom(isolate(), web_contents),
request_url,
net::ErrorToString(cert_error),
ssl_info.cert,
callback);
// Deny the certificate by default.
if (!prevent_default)
*request = content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY;
}
void App::SelectClientCertificate(
content::WebContents* web_contents, content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info, net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) { scoped_ptr<content::ClientCertificateDelegate> delegate) {
std::shared_ptr<content::ClientCertificateDelegate> std::shared_ptr<content::ClientCertificateDelegate>
shared_delegate(delegate.release()); shared_delegate(delegate.release());
bool prevent_default = bool prevent_default =
Emit("select-certificate", Emit("select-client-certificate",
api::WebContents::CreateFrom(isolate(), web_contents), WebContents::CreateFrom(isolate(), web_contents),
cert_request_info->host_and_port.ToString(), cert_request_info->host_and_port.ToString(),
cert_request_info->client_certs, cert_request_info->client_certs,
base::Bind(&OnClientCertificateSelected, base::Bind(&OnClientCertificateSelected,
@ -242,22 +307,36 @@ void App::SetDesktopName(const std::string& desktop_name) {
#endif #endif
} }
void App::SetAppUserModelId(const std::string& app_id) { void App::AllowNTLMCredentialsForAllDomains(bool should_allow) {
#if defined(OS_WIN) auto browser_context = static_cast<AtomBrowserContext*>(
base::string16 app_id_utf16 = base::UTF8ToUTF16(app_id); AtomBrowserMainParts::Get()->browser_context());
SetCurrentProcessExplicitAppUserModelID(app_id_utf16.c_str()); browser_context->AllowNTLMCredentialsForAllDomains(should_allow);
#endif
} }
std::string App::GetLocale() { std::string App::GetLocale() {
return l10n_util::GetApplicationLocale(""); return l10n_util::GetApplicationLocale("");
} }
v8::Local<v8::Value> App::DefaultSession(v8::Isolate* isolate) { bool App::MakeSingleInstance(
if (default_session_.IsEmpty()) const ProcessSingleton::NotificationCallback& callback) {
return v8::Null(isolate); if (process_singleton_.get())
else return false;
return v8::Local<v8::Value>::New(isolate, default_session_);
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( mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
@ -265,6 +344,7 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
auto browser = base::Unretained(Browser::Get()); auto browser = base::Unretained(Browser::Get());
return mate::ObjectTemplateBuilder(isolate) return mate::ObjectTemplateBuilder(isolate)
.SetMethod("quit", base::Bind(&Browser::Quit, browser)) .SetMethod("quit", base::Bind(&Browser::Quit, browser))
.SetMethod("exit", base::Bind(&Browser::Exit, browser))
.SetMethod("focus", base::Bind(&Browser::Focus, browser)) .SetMethod("focus", base::Bind(&Browser::Focus, browser))
.SetMethod("getVersion", base::Bind(&Browser::GetVersion, browser)) .SetMethod("getVersion", base::Bind(&Browser::GetVersion, browser))
.SetMethod("setVersion", base::Bind(&Browser::SetVersion, browser)) .SetMethod("setVersion", base::Bind(&Browser::SetVersion, browser))
@ -275,6 +355,8 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
base::Bind(&Browser::AddRecentDocument, browser)) base::Bind(&Browser::AddRecentDocument, browser))
.SetMethod("clearRecentDocuments", .SetMethod("clearRecentDocuments",
base::Bind(&Browser::ClearRecentDocuments, browser)) base::Bind(&Browser::ClearRecentDocuments, browser))
.SetMethod("setAppUserModelId",
base::Bind(&Browser::SetAppUserModelID, browser))
#if defined(OS_WIN) #if defined(OS_WIN)
.SetMethod("setUserTasks", .SetMethod("setUserTasks",
base::Bind(&Browser::SetUserTasks, browser)) base::Bind(&Browser::SetUserTasks, browser))
@ -282,9 +364,10 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
.SetMethod("setPath", &App::SetPath) .SetMethod("setPath", &App::SetPath)
.SetMethod("getPath", &App::GetPath) .SetMethod("getPath", &App::GetPath)
.SetMethod("setDesktopName", &App::SetDesktopName) .SetMethod("setDesktopName", &App::SetDesktopName)
.SetMethod("setAppUserModelId", &App::SetAppUserModelId) .SetMethod("allowNTLMCredentialsForAllDomains",
&App::AllowNTLMCredentialsForAllDomains)
.SetMethod("getLocale", &App::GetLocale) .SetMethod("getLocale", &App::GetLocale)
.SetProperty("defaultSession", &App::DefaultSession); .SetMethod("makeSingleInstance", &App::MakeSingleInstance);
} }
// static // static
@ -301,6 +384,16 @@ namespace {
void AppendSwitch(const std::string& switch_string, mate::Arguments* args) { void AppendSwitch(const std::string& switch_string, mate::Arguments* args) {
auto command_line = base::CommandLine::ForCurrentProcess(); 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; std::string value;
if (args->GetNext(&value)) if (args->GetNext(&value))
command_line->AppendSwitchASCII(switch_string, value); command_line->AppendSwitchASCII(switch_string, value);

View file

@ -8,7 +8,10 @@
#include <string> #include <string>
#include "atom/browser/api/event_emitter.h" #include "atom/browser/api/event_emitter.h"
#include "atom/browser/atom_browser_client.h"
#include "atom/browser/browser_observer.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 "content/public/browser/gpu_data_manager_observer.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
@ -24,7 +27,8 @@ namespace atom {
namespace api { namespace api {
class App : public mate::EventEmitter, class App : public AtomBrowserClient::Delegate,
public mate::EventEmitter,
public BrowserObserver, public BrowserObserver,
public content::GpuDataManagerObserver { public content::GpuDataManagerObserver {
public: public:
@ -44,7 +48,22 @@ class App : public mate::EventEmitter,
void OnActivate(bool has_visible_windows) override; void OnActivate(bool has_visible_windows) override;
void OnWillFinishLaunching() override; void OnWillFinishLaunching() override;
void OnFinishLaunching() override; void OnFinishLaunching() override;
void OnSelectCertificate( void OnLogin(LoginHandler* login_handler) override;
// content::ContentBrowserClient:
void AllowCertificateError(
int render_process_id,
int render_frame_id,
int cert_error,
const net::SSLInfo& ssl_info,
const GURL& request_url,
content::ResourceType resource_type,
bool overridable,
bool strict_enforcement,
bool expired_previous_decision,
const base::Callback<void(bool)>& callback,
content::CertificateRequestResultType* request) override;
void SelectClientCertificate(
content::WebContents* web_contents, content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info, net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) override; scoped_ptr<content::ClientCertificateDelegate> delegate) override;
@ -64,11 +83,12 @@ class App : public mate::EventEmitter,
const base::FilePath& path); const base::FilePath& path);
void SetDesktopName(const std::string& desktop_name); 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(); 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); DISALLOW_COPY_AND_ASSIGN(App);
}; };

View file

@ -5,12 +5,31 @@
#include "atom/browser/api/atom_api_auto_updater.h" #include "atom/browser/api/atom_api_auto_updater.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "atom/browser/auto_updater.h"
#include "atom/browser/browser.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 "atom/common/node_includes.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.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 atom {
namespace api { namespace api {
@ -20,11 +39,18 @@ AutoUpdater::AutoUpdater() {
} }
AutoUpdater::~AutoUpdater() { AutoUpdater::~AutoUpdater() {
auto_updater::AutoUpdater::SetDelegate(NULL); auto_updater::AutoUpdater::SetDelegate(nullptr);
} }
void AutoUpdater::OnError(const std::string& error) { void AutoUpdater::OnError(const std::string& message) {
Emit("error", error); 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() { void AutoUpdater::OnCheckingForUpdate() {
@ -42,26 +68,36 @@ void AutoUpdater::OnUpdateNotAvailable() {
void AutoUpdater::OnUpdateDownloaded(const std::string& release_notes, void AutoUpdater::OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_name, const std::string& release_name,
const base::Time& release_date, const base::Time& release_date,
const std::string& update_url, const std::string& url) {
const base::Closure& quit_and_install) { Emit("update-downloaded", release_notes, release_name, release_date, url,
quit_and_install_ = quit_and_install; // Keep compatibility with old APIs.
Emit("update-downloaded-raw", release_notes, release_name, base::Bind(&AutoUpdater::QuitAndInstall, base::Unretained(this)));
release_date.ToJsTime(), update_url); }
void AutoUpdater::OnWindowAllClosed() {
QuitAndInstall();
} }
mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder( mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder(
v8::Isolate* isolate) { v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate) return mate::ObjectTemplateBuilder(isolate)
.SetMethod("setFeedUrl", &auto_updater::AutoUpdater::SetFeedURL) .SetMethod("setFeedURL", &auto_updater::AutoUpdater::SetFeedURL)
.SetMethod("checkForUpdates", &auto_updater::AutoUpdater::CheckForUpdates) .SetMethod("checkForUpdates", &auto_updater::AutoUpdater::CheckForUpdates)
.SetMethod("_quitAndInstall", &AutoUpdater::QuitAndInstall); .SetMethod("quitAndInstall", &AutoUpdater::QuitAndInstall);
} }
void AutoUpdater::QuitAndInstall() { void AutoUpdater::QuitAndInstall() {
if (quit_and_install_.is_null()) // If we don't have any window then quitAndInstall immediately.
Browser::Get()->Shutdown(); WindowList* window_list = WindowList::GetInstance();
else if (window_list->size() == 0) {
quit_and_install_.Run(); 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 // static

View file

@ -7,9 +7,9 @@
#include <string> #include <string>
#include "base/callback.h"
#include "atom/browser/api/event_emitter.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" #include "native_mate/handle.h"
namespace atom { namespace atom {
@ -17,7 +17,8 @@ namespace atom {
namespace api { namespace api {
class AutoUpdater : public mate::EventEmitter, class AutoUpdater : public mate::EventEmitter,
public auto_updater::AutoUpdaterDelegate { public auto_updater::Delegate,
public WindowListObserver {
public: public:
static mate::Handle<AutoUpdater> Create(v8::Isolate* isolate); static mate::Handle<AutoUpdater> Create(v8::Isolate* isolate);
@ -25,17 +26,18 @@ class AutoUpdater : public mate::EventEmitter,
AutoUpdater(); AutoUpdater();
virtual ~AutoUpdater(); virtual ~AutoUpdater();
// AutoUpdaterDelegate implementations. // Delegate implementations.
void OnError(const std::string& error) override; void OnError(const std::string& error) override;
void OnCheckingForUpdate() override; void OnCheckingForUpdate() override;
void OnUpdateAvailable() override; void OnUpdateAvailable() override;
void OnUpdateNotAvailable() override; void OnUpdateNotAvailable() override;
void OnUpdateDownloaded( void OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_notes, const std::string& release_name,
const std::string& release_name, const base::Time& release_date,
const base::Time& release_date, const std::string& update_url) override;
const std::string& update_url,
const base::Closure& quit_and_install) override; // WindowListObserver:
void OnWindowAllClosed() override;
// mate::Wrappable implementations: // mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder( mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
@ -44,8 +46,6 @@ class AutoUpdater : public mate::EventEmitter,
private: private:
void QuitAndInstall(); void QuitAndInstall();
base::Closure quit_and_install_;
DISALLOW_COPY_AND_ASSIGN(AutoUpdater); DISALLOW_COPY_AND_ASSIGN(AutoUpdater);
}; };

View file

@ -204,7 +204,7 @@ void Cookies::GetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> filter,
Passed(&filter), callback))) { Passed(&filter), callback))) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&RunGetCookiesCallbackOnUIThread, isolate(), base::Bind(&RunGetCookiesCallbackOnUIThread, isolate(),
"Url is not valid", net::CookieList(), callback)); "URL is not valid", net::CookieList(), callback));
} }
} }
@ -229,7 +229,7 @@ void Cookies::Remove(const mate::Dictionary& details,
error_message = "Details(url, name) of removing cookie are required."; error_message = "Details(url, name) of removing cookie are required.";
} }
if (error_message.empty() && !url.is_valid()) { if (error_message.empty() && !url.is_valid()) {
error_message = "Url is not valid."; error_message = "URL is not valid.";
} }
if (!error_message.empty()) { if (!error_message.empty()) {
RunRemoveCookiesCallbackOnUIThread(isolate(), error_message, callback); RunRemoveCookiesCallbackOnUIThread(isolate(), error_message, callback);
@ -261,7 +261,7 @@ void Cookies::Set(const base::DictionaryValue& options,
GURL gurl(url); GURL gurl(url);
if (error_message.empty() && !gurl.is_valid()) { if (error_message.empty() && !gurl.is_valid()) {
error_message = "Url is not valid."; error_message = "URL is not valid.";
} }
if (!error_message.empty()) { if (!error_message.empty()) {
@ -322,14 +322,6 @@ void Cookies::OnSetCookies(const CookiesCallback& callback,
callback)); callback));
} }
mate::ObjectTemplateBuilder Cookies::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("get", &Cookies::Get)
.SetMethod("remove", &Cookies::Remove)
.SetMethod("set", &Cookies::Set);
}
net::CookieStore* Cookies::GetCookieStore() { net::CookieStore* Cookies::GetCookieStore() {
return request_context_getter_->GetURLRequestContext()->cookie_store(); return request_context_getter_->GetURLRequestContext()->cookie_store();
} }
@ -341,6 +333,15 @@ mate::Handle<Cookies> Cookies::Create(
return mate::CreateHandle(isolate, new Cookies(browser_context)); return mate::CreateHandle(isolate, new Cookies(browser_context));
} }
// static
void Cookies::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("get", &Cookies::Get)
.SetMethod("remove", &Cookies::Remove)
.SetMethod("set", &Cookies::Set);
}
} // namespace api } // namespace api
} // namespace atom } // namespace atom

View file

@ -7,8 +7,8 @@
#include <string> #include <string>
#include "atom/browser/api/trackable_object.h"
#include "base/callback.h" #include "base/callback.h"
#include "native_mate/wrappable.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
#include "net/cookies/canonical_cookie.h" #include "net/cookies/canonical_cookie.h"
@ -33,7 +33,7 @@ namespace atom {
namespace api { namespace api {
class Cookies : public mate::Wrappable { class Cookies : public mate::TrackableObject<Cookies> {
public: public:
// node.js style callback function(error, result) // node.js style callback function(error, result)
typedef base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)> typedef base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>
@ -42,6 +42,10 @@ class Cookies : public mate::Wrappable {
static mate::Handle<Cookies> Create(v8::Isolate* isolate, static mate::Handle<Cookies> Create(v8::Isolate* isolate,
content::BrowserContext* browser_context); content::BrowserContext* browser_context);
// mate::TrackableObject:
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
protected: protected:
explicit Cookies(content::BrowserContext* browser_context); explicit Cookies(content::BrowserContext* browser_context);
~Cookies(); ~Cookies();
@ -70,10 +74,6 @@ class Cookies : public mate::Wrappable {
void OnSetCookies(const CookiesCallback& callback, void OnSetCookies(const CookiesCallback& callback,
bool set_success); bool set_success);
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
private: private:
// Must be called on IO thread. // Must be called on IO thread.
net::CookieStore* GetCookieStore(); net::CookieStore* GetCookieStore();

View file

@ -6,6 +6,7 @@
#include <map> #include <map>
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h"
@ -30,7 +31,7 @@ struct Converter<content::DownloadItem::DownloadState> {
download_state = "cancelled"; download_state = "cancelled";
break; break;
case content::DownloadItem::INTERRUPTED: case content::DownloadItem::INTERRUPTED:
download_state = "interrputed"; download_state = "interrupted";
break; break;
default: default:
break; break;
@ -69,29 +70,20 @@ DownloadItem::DownloadItem(content::DownloadItem* download_item) :
} }
DownloadItem::~DownloadItem() { DownloadItem::~DownloadItem() {
Destroy(); if (download_item_)
} OnDownloadDestroyed(download_item_);
void DownloadItem::Destroy() {
if (download_item_) {
download_item_->RemoveObserver(this);
auto iter = g_download_item_objects.find(download_item_->GetId());
if (iter != g_download_item_objects.end())
g_download_item_objects.erase(iter);
download_item_ = nullptr;
}
}
bool DownloadItem::IsDestroyed() const {
return download_item_ == nullptr;
} }
void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) { void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) {
download_item_->IsDone() ? Emit("done", item->GetState()) : Emit("updated"); download_item_->IsDone() ? Emit("done", item->GetState()) : Emit("updated");
} }
void DownloadItem::OnDownloadDestroyed(content::DownloadItem* download) { void DownloadItem::OnDownloadDestroyed(content::DownloadItem* download_item) {
Destroy(); download_item_->RemoveObserver(this);
auto iter = g_download_item_objects.find(download_item_->GetId());
if (iter != g_download_item_objects.end())
g_download_item_objects.erase(iter);
download_item_ = nullptr;
} }
int64 DownloadItem::GetReceivedBytes() { int64 DownloadItem::GetReceivedBytes() {
@ -102,7 +94,7 @@ int64 DownloadItem::GetTotalBytes() {
return download_item_->GetTotalBytes(); return download_item_->GetTotalBytes();
} }
const GURL& DownloadItem::GetUrl() { const GURL& DownloadItem::GetURL() {
return download_item_->GetURL(); return download_item_->GetURL();
} }
@ -115,7 +107,7 @@ bool DownloadItem::HasUserGesture() {
} }
std::string DownloadItem::GetFilename() { std::string DownloadItem::GetFilename() {
return base::UTF16ToUTF8(net::GenerateFileName(GetUrl(), return base::UTF16ToUTF8(net::GenerateFileName(GetURL(),
GetContentDisposition(), GetContentDisposition(),
std::string(), std::string(),
download_item_->GetSuggestedFilename(), download_item_->GetSuggestedFilename(),
@ -143,15 +135,17 @@ void DownloadItem::Cancel() {
download_item_->Cancel(true); download_item_->Cancel(true);
} }
mate::ObjectTemplateBuilder DownloadItem::GetObjectTemplateBuilder( // static
v8::Isolate* isolate) { void DownloadItem::BuildPrototype(v8::Isolate* isolate,
return mate::ObjectTemplateBuilder(isolate) v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.MakeDestroyable()
.SetMethod("pause", &DownloadItem::Pause) .SetMethod("pause", &DownloadItem::Pause)
.SetMethod("resume", &DownloadItem::Resume) .SetMethod("resume", &DownloadItem::Resume)
.SetMethod("cancel", &DownloadItem::Cancel) .SetMethod("cancel", &DownloadItem::Cancel)
.SetMethod("getReceivedBytes", &DownloadItem::GetReceivedBytes) .SetMethod("getReceivedBytes", &DownloadItem::GetReceivedBytes)
.SetMethod("getTotalBytes", &DownloadItem::GetTotalBytes) .SetMethod("getTotalBytes", &DownloadItem::GetTotalBytes)
.SetMethod("getUrl", &DownloadItem::GetUrl) .SetMethod("getURL", &DownloadItem::GetURL)
.SetMethod("getMimeType", &DownloadItem::GetMimeType) .SetMethod("getMimeType", &DownloadItem::GetMimeType)
.SetMethod("hasUserGesture", &DownloadItem::HasUserGesture) .SetMethod("hasUserGesture", &DownloadItem::HasUserGesture)
.SetMethod("getFilename", &DownloadItem::GetFilename) .SetMethod("getFilename", &DownloadItem::GetFilename)
@ -159,14 +153,6 @@ mate::ObjectTemplateBuilder DownloadItem::GetObjectTemplateBuilder(
.SetMethod("setSavePath", &DownloadItem::SetSavePath); .SetMethod("setSavePath", &DownloadItem::SetSavePath);
} }
void SetWrapDownloadItem(const WrapDownloadItemCallback& callback) {
g_wrap_download_item = callback;
}
void ClearWrapDownloadItem() {
g_wrap_download_item.Reset();
}
// static // static
mate::Handle<DownloadItem> DownloadItem::Create( mate::Handle<DownloadItem> DownloadItem::Create(
v8::Isolate* isolate, content::DownloadItem* item) { v8::Isolate* isolate, content::DownloadItem* item) {
@ -182,6 +168,18 @@ void* DownloadItem::UserDataKey() {
return &kDownloadItemSavePathKey; return &kDownloadItemSavePathKey;
} }
void ClearWrapDownloadItem() {
g_wrap_download_item.Reset();
}
void SetWrapDownloadItem(const WrapDownloadItemCallback& callback) {
g_wrap_download_item = callback;
// Cleanup the wrapper on exit.
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
base::Bind(ClearWrapDownloadItem));
}
} // namespace api } // namespace api
} // namespace atom } // namespace atom
@ -193,7 +191,6 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Isolate* isolate = context->GetIsolate(); v8::Isolate* isolate = context->GetIsolate();
mate::Dictionary dict(isolate, exports); mate::Dictionary dict(isolate, exports);
dict.SetMethod("_setWrapDownloadItem", &atom::api::SetWrapDownloadItem); dict.SetMethod("_setWrapDownloadItem", &atom::api::SetWrapDownloadItem);
dict.SetMethod("_clearWrapDownloadItem", &atom::api::ClearWrapDownloadItem);
} }
} // namespace } // namespace

View file

@ -17,7 +17,7 @@ namespace atom {
namespace api { namespace api {
class DownloadItem : public mate::EventEmitter, class DownloadItem : public mate::TrackableObject<DownloadItem>,
public content::DownloadItem::Observer { public content::DownloadItem::Observer {
public: public:
class SavePathData : public base::SupportsUserData::Data { class SavePathData : public base::SupportsUserData::Data {
@ -32,6 +32,10 @@ class DownloadItem : public mate::EventEmitter,
content::DownloadItem* item); content::DownloadItem* item);
static void* UserDataKey(); static void* UserDataKey();
// mate::TrackableObject:
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
protected: protected:
explicit DownloadItem(content::DownloadItem* download_item); explicit DownloadItem(content::DownloadItem* download_item);
~DownloadItem(); ~DownloadItem();
@ -49,17 +53,10 @@ class DownloadItem : public mate::EventEmitter,
bool HasUserGesture(); bool HasUserGesture();
std::string GetFilename(); std::string GetFilename();
std::string GetContentDisposition(); std::string GetContentDisposition();
const GURL& GetUrl(); const GURL& GetURL();
void SetSavePath(const base::FilePath& path); void SetSavePath(const base::FilePath& path);
private: private:
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
void Destroy();
content::DownloadItem* download_item_; content::DownloadItem* download_item_;
DISALLOW_COPY_AND_ASSIGN(DownloadItem); DISALLOW_COPY_AND_ASSIGN(DownloadItem);

View file

@ -8,9 +8,9 @@
#include <map> #include <map>
#include <string> #include <string>
#include "atom/browser/api/trackable_object.h"
#include "base/callback.h" #include "base/callback.h"
#include "chrome/browser/extensions/global_shortcut_listener.h" #include "chrome/browser/extensions/global_shortcut_listener.h"
#include "native_mate/wrappable.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
#include "ui/base/accelerators/accelerator.h" #include "ui/base/accelerators/accelerator.h"
@ -19,13 +19,13 @@ namespace atom {
namespace api { namespace api {
class GlobalShortcut : public extensions::GlobalShortcutListener::Observer, class GlobalShortcut : public extensions::GlobalShortcutListener::Observer,
public mate::Wrappable { public mate::TrackableObject<GlobalShortcut> {
public: public:
static mate::Handle<GlobalShortcut> Create(v8::Isolate* isolate); static mate::Handle<GlobalShortcut> Create(v8::Isolate* isolate);
protected: protected:
GlobalShortcut(); GlobalShortcut();
virtual ~GlobalShortcut(); ~GlobalShortcut() override;
// mate::Wrappable implementations: // mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder( mate::ObjectTemplateBuilder GetObjectTemplateBuilder(

View file

@ -151,6 +151,7 @@ bool Menu::IsVisibleAt(int index) const {
void Menu::BuildPrototype(v8::Isolate* isolate, void Menu::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) { v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype) mate::ObjectTemplateBuilder(isolate, prototype)
.MakeDestroyable()
.SetMethod("insertItem", &Menu::InsertItemAt) .SetMethod("insertItem", &Menu::InsertItemAt)
.SetMethod("insertCheckItem", &Menu::InsertCheckItemAt) .SetMethod("insertCheckItem", &Menu::InsertCheckItemAt)
.SetMethod("insertRadioItem", &Menu::InsertRadioItemAt) .SetMethod("insertRadioItem", &Menu::InsertRadioItemAt)

View file

@ -8,16 +8,16 @@
#include <string> #include <string>
#include "atom/browser/api/atom_api_window.h" #include "atom/browser/api/atom_api_window.h"
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/ui/atom_menu_model.h" #include "atom/browser/ui/atom_menu_model.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "native_mate/wrappable.h"
namespace atom { namespace atom {
namespace api { namespace api {
class Menu : public mate::Wrappable, class Menu : public mate::TrackableObject<Menu>,
public AtomMenuModel::Delegate { public AtomMenuModel::Delegate {
public: public:
static mate::Wrappable* Create(); static mate::Wrappable* Create();
@ -37,7 +37,7 @@ class Menu : public mate::Wrappable,
protected: protected:
Menu(); Menu();
virtual ~Menu(); ~Menu() override;
// mate::Wrappable: // mate::Wrappable:
void AfterInit(v8::Isolate* isolate) override; void AfterInit(v8::Isolate* isolate) override;

View file

@ -5,7 +5,7 @@
#ifndef ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_ #ifndef ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_
#define ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_ #define ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_
#include "atom/browser/api/event_emitter.h" #include "atom/browser/api/trackable_object.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/power_monitor/power_observer.h" #include "base/power_monitor/power_observer.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
@ -14,14 +14,14 @@ namespace atom {
namespace api { namespace api {
class PowerMonitor : public mate::EventEmitter, class PowerMonitor : public mate::TrackableObject<PowerMonitor>,
public base::PowerObserver { public base::PowerObserver {
public: public:
static v8::Local<v8::Value> Create(v8::Isolate* isolate); static v8::Local<v8::Value> Create(v8::Isolate* isolate);
protected: protected:
PowerMonitor(); PowerMonitor();
virtual ~PowerMonitor(); ~PowerMonitor() override;
// base::PowerObserver implementations: // base::PowerObserver implementations:
void OnPowerStateChange(bool on_battery_power) override; void OnPowerStateChange(bool on_battery_power) override;

View file

@ -7,10 +7,10 @@
#include <map> #include <map>
#include "atom/browser/api/trackable_object.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "content/public/browser/power_save_blocker.h" #include "content/public/browser/power_save_blocker.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
#include "native_mate/wrappable.h"
namespace mate { namespace mate {
class Dictionary; class Dictionary;
@ -20,13 +20,13 @@ namespace atom {
namespace api { namespace api {
class PowerSaveBlocker : public mate::Wrappable { class PowerSaveBlocker : public mate::TrackableObject<PowerSaveBlocker> {
public: public:
static mate::Handle<PowerSaveBlocker> Create(v8::Isolate* isolate); static mate::Handle<PowerSaveBlocker> Create(v8::Isolate* isolate);
protected: protected:
PowerSaveBlocker(); PowerSaveBlocker();
virtual ~PowerSaveBlocker(); ~PowerSaveBlocker() override;
// mate::Wrappable implementations: // mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder( mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
@ -48,7 +48,6 @@ class PowerSaveBlocker : public mate::Wrappable {
std::map<int, content::PowerSaveBlocker::PowerSaveBlockerType>; std::map<int, content::PowerSaveBlocker::PowerSaveBlockerType>;
PowerSaveBlockerTypeMap power_save_blocker_types_; PowerSaveBlockerTypeMap power_save_blocker_types_;
DISALLOW_COPY_AND_ASSIGN(PowerSaveBlocker); DISALLOW_COPY_AND_ASSIGN(PowerSaveBlocker);
}; };

View file

@ -12,27 +12,12 @@
#include "atom/browser/net/url_request_fetch_job.h" #include "atom/browser/net/url_request_fetch_job.h"
#include "atom/browser/net/url_request_string_job.h" #include "atom/browser/net/url_request_string_job.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/net_converter.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
using content::BrowserThread; using content::BrowserThread;
namespace mate {
template<>
struct Converter<const net::URLRequest*> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const net::URLRequest* val) {
return mate::ObjectTemplateBuilder(isolate)
.SetValue("method", val->method())
.SetValue("url", val->url().spec())
.SetValue("referrer", val->referrer())
.Build()->NewInstance();
}
};
} // namespace mate
namespace atom { namespace atom {
namespace api { namespace api {
@ -52,7 +37,7 @@ mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
.SetMethod("registerBufferProtocol", .SetMethod("registerBufferProtocol",
&Protocol::RegisterProtocol<URLRequestBufferJob>) &Protocol::RegisterProtocol<URLRequestBufferJob>)
.SetMethod("registerFileProtocol", .SetMethod("registerFileProtocol",
&Protocol::RegisterProtocol<UrlRequestAsyncAsarJob>) &Protocol::RegisterProtocol<URLRequestAsyncAsarJob>)
.SetMethod("registerHttpProtocol", .SetMethod("registerHttpProtocol",
&Protocol::RegisterProtocol<URLRequestFetchJob>) &Protocol::RegisterProtocol<URLRequestFetchJob>)
.SetMethod("unregisterProtocol", &Protocol::UnregisterProtocol) .SetMethod("unregisterProtocol", &Protocol::UnregisterProtocol)
@ -62,7 +47,7 @@ mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
.SetMethod("interceptBufferProtocol", .SetMethod("interceptBufferProtocol",
&Protocol::InterceptProtocol<URLRequestBufferJob>) &Protocol::InterceptProtocol<URLRequestBufferJob>)
.SetMethod("interceptFileProtocol", .SetMethod("interceptFileProtocol",
&Protocol::InterceptProtocol<UrlRequestAsyncAsarJob>) &Protocol::InterceptProtocol<URLRequestAsyncAsarJob>)
.SetMethod("interceptHttpProtocol", .SetMethod("interceptHttpProtocol",
&Protocol::InterceptProtocol<URLRequestFetchJob>) &Protocol::InterceptProtocol<URLRequestFetchJob>)
.SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol); .SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol);

View file

@ -41,7 +41,7 @@ std::vector<std::string> MetricsToArray(uint32_t metrics) {
if (metrics & gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR) if (metrics & gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR)
array.push_back("scaleFactor"); array.push_back("scaleFactor");
if (metrics & gfx::DisplayObserver::DISPLAY_METRIC_ROTATION) if (metrics & gfx::DisplayObserver::DISPLAY_METRIC_ROTATION)
array.push_back("rotaion"); array.push_back("rotation");
return array; return array;
} }

View file

@ -9,16 +9,22 @@
#include "atom/browser/api/atom_api_cookies.h" #include "atom/browser/api/atom_api_cookies.h"
#include "atom/browser/api/atom_api_download_item.h" #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/atom_api_web_contents.h"
#include "atom/browser/api/save_page_handler.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/net/atom_cert_verifier.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/net_converter.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/prefs/pref_service.h" #include "base/prefs/pref_service.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/thread_task_runner_handle.h" #include "base/thread_task_runner_handle.h"
#include "brightray/browser/net/devtools_network_conditions.h"
#include "brightray/browser/net/devtools_network_controller.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_partition.h"
@ -45,7 +51,7 @@ struct ClearStorageDataOptions {
uint32 GetStorageMask(const std::vector<std::string>& storage_types) { uint32 GetStorageMask(const std::vector<std::string>& storage_types) {
uint32 storage_mask = 0; uint32 storage_mask = 0;
for (const auto& it : storage_types) { for (const auto& it : storage_types) {
auto type = base::StringToLowerASCII(it); auto type = base::ToLowerASCII(it);
if (type == "appcache") if (type == "appcache")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_APPCACHE; storage_mask |= StoragePartition::REMOVE_DATA_MASK_APPCACHE;
else if (type == "cookies") else if (type == "cookies")
@ -69,7 +75,7 @@ uint32 GetStorageMask(const std::vector<std::string>& storage_types) {
uint32 GetQuotaMask(const std::vector<std::string>& quota_types) { uint32 GetQuotaMask(const std::vector<std::string>& quota_types) {
uint32 quota_mask = 0; uint32 quota_mask = 0;
for (const auto& it : quota_types) { for (const auto& it : quota_types) {
auto type = base::StringToLowerASCII(it); auto type = base::ToLowerASCII(it);
if (type == "temporary") if (type == "temporary")
quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY; quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY;
else if (type == "persistent") else if (type == "persistent")
@ -102,6 +108,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 mate
namespace atom { namespace atom {
@ -206,12 +230,13 @@ void ClearHttpCacheInIO(
} }
void SetProxyInIO(net::URLRequestContextGetter* getter, void SetProxyInIO(net::URLRequestContextGetter* getter,
const std::string& proxy, const net::ProxyConfig& config,
const base::Closure& callback) { const base::Closure& callback) {
net::ProxyConfig config;
config.proxy_rules().ParseFromString(proxy);
auto proxy_service = getter->GetURLRequestContext()->proxy_service(); auto proxy_service = getter->GetURLRequestContext()->proxy_service();
proxy_service->ResetConfigService(new net::ProxyConfigServiceFixed(config)); proxy_service->ResetConfigService(make_scoped_ptr(
new net::ProxyConfigServiceFixed(config)));
// Refetches and applies the new pac script if provided.
proxy_service->ForceReloadProxyConfig();
RunCallbackInUI(callback); RunCallbackInUI(callback);
} }
@ -229,12 +254,13 @@ Session::Session(AtomBrowserContext* browser_context)
Session::~Session() { Session::~Session() {
content::BrowserContext::GetDownloadManager(browser_context())-> content::BrowserContext::GetDownloadManager(browser_context())->
RemoveObserver(this); RemoveObserver(this);
Destroy();
} }
void Session::OnDownloadCreated(content::DownloadManager* manager, void Session::OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) { content::DownloadItem* item) {
auto web_contents = item->GetWebContents(); auto web_contents = item->GetWebContents();
if (SavePageHandler::IsSavePageTypes(item->GetMimeType()))
return;
bool prevent_default = Emit( bool prevent_default = Emit(
"will-download", "will-download",
DownloadItem::Create(isolate(), item), DownloadItem::Create(isolate(), item),
@ -245,14 +271,6 @@ void Session::OnDownloadCreated(content::DownloadManager* manager,
} }
} }
bool Session::IsDestroyed() const {
return !browser_context_;
}
void Session::Destroy() {
browser_context_ = nullptr;
}
void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) { void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) {
new ResolveProxyHelper(browser_context(), url, callback); new ResolveProxyHelper(browser_context(), url, callback);
} }
@ -282,11 +300,11 @@ void Session::ClearStorageData(mate::Arguments* args) {
base::Time(), base::Time::Max(), callback); base::Time(), base::Time::Max(), callback);
} }
void Session::SetProxy(const std::string& proxy, void Session::SetProxy(const net::ProxyConfig& config,
const base::Closure& callback) { const base::Closure& callback) {
auto getter = browser_context_->GetRequestContext(); auto getter = browser_context_->GetRequestContext();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 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) { void Session::SetDownloadPath(const base::FilePath& path) {
@ -294,6 +312,54 @@ void Session::SetDownloadPath(const base::FilePath& path) {
prefs::kDownloadDefaultDirectory, path); prefs::kDownloadDefaultDirectory, path);
} }
void Session::EnableNetworkEmulation(const mate::Dictionary& options) {
scoped_ptr<brightray::DevToolsNetworkConditions> conditions;
bool offline = false;
double latency, download_throughput, upload_throughput;
if (options.Get("offline", &offline) && offline) {
conditions.reset(new brightray::DevToolsNetworkConditions(offline));
} else {
options.Get("latency", &latency);
options.Get("downloadThroughput", &download_throughput);
options.Get("uploadThroughput", &upload_throughput);
conditions.reset(
new brightray::DevToolsNetworkConditions(false,
latency,
download_throughput,
upload_throughput));
}
auto controller = browser_context_->GetDevToolsNetworkController();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&brightray::DevToolsNetworkController::SetNetworkState,
base::Unretained(controller),
std::string(),
base::Passed(&conditions)));
}
void Session::DisableNetworkEmulation() {
scoped_ptr<brightray::DevToolsNetworkConditions> conditions(
new brightray::DevToolsNetworkConditions(false));
auto controller = browser_context_->GetDevToolsNetworkController();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&brightray::DevToolsNetworkController::SetNetworkState,
base::Unretained(controller),
std::string(),
base::Passed(&conditions)));
}
void Session::SetCertVerifyProc(v8::Local<v8::Value> val,
mate::Arguments* args) {
AtomCertVerifier::VerifyProc proc;
if (!(val->IsNull() || mate::ConvertFromV8(args->isolate(), val, &proc))) {
args->ThrowError("Must pass null or function");
return;
}
browser_context_->cert_verifier()->SetVerifyProc(proc);
}
v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) { v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
if (cookies_.IsEmpty()) { if (cookies_.IsEmpty()) {
auto handle = atom::api::Cookies::Create(isolate, browser_context()); auto handle = atom::api::Cookies::Create(isolate, browser_context());
@ -302,17 +368,6 @@ v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, cookies_); return v8::Local<v8::Value>::New(isolate, cookies_);
} }
mate::ObjectTemplateBuilder Session::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("resolveProxy", &Session::ResolveProxy)
.SetMethod("clearCache", &Session::ClearCache)
.SetMethod("clearStorageData", &Session::ClearStorageData)
.SetMethod("setProxy", &Session::SetProxy)
.SetMethod("setDownloadPath", &Session::SetDownloadPath)
.SetProperty("cookies", &Session::Cookies);
}
// static // static
mate::Handle<Session> Session::CreateFrom( mate::Handle<Session> Session::CreateFrom(
v8::Isolate* isolate, AtomBrowserContext* browser_context) { v8::Isolate* isolate, AtomBrowserContext* browser_context) {
@ -333,14 +388,34 @@ mate::Handle<Session> Session::FromPartition(
static_cast<AtomBrowserContext*>(browser_context.get())); static_cast<AtomBrowserContext*>(browser_context.get()));
} }
void SetWrapSession(const WrapSessionCallback& callback) { // static
g_wrap_session = callback; void Session::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.MakeDestroyable()
.SetMethod("resolveProxy", &Session::ResolveProxy)
.SetMethod("clearCache", &Session::ClearCache)
.SetMethod("clearStorageData", &Session::ClearStorageData)
.SetMethod("setProxy", &Session::SetProxy)
.SetMethod("setDownloadPath", &Session::SetDownloadPath)
.SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
.SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
.SetMethod("setCertificateVerifyProc", &Session::SetCertVerifyProc)
.SetProperty("cookies", &Session::Cookies);
} }
void ClearWrapSession() { void ClearWrapSession() {
g_wrap_session.Reset(); g_wrap_session.Reset();
} }
void SetWrapSession(const WrapSessionCallback& callback) {
g_wrap_session = callback;
// Cleanup the wrapper on exit.
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
base::Bind(ClearWrapSession));
}
} // namespace api } // namespace api
} // namespace atom } // namespace atom
@ -353,7 +428,6 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
mate::Dictionary dict(isolate, exports); mate::Dictionary dict(isolate, exports);
dict.SetMethod("fromPartition", &atom::api::Session::FromPartition); dict.SetMethod("fromPartition", &atom::api::Session::FromPartition);
dict.SetMethod("_setWrapSession", &atom::api::SetWrapSession); dict.SetMethod("_setWrapSession", &atom::api::SetWrapSession);
dict.SetMethod("_clearWrapSession", &atom::api::ClearWrapSession);
} }
} // namespace } // namespace

View file

@ -20,6 +20,11 @@ class FilePath;
namespace mate { namespace mate {
class Arguments; class Arguments;
class Dictionary;
}
namespace net {
class ProxyConfig;
} }
namespace atom { namespace atom {
@ -43,6 +48,10 @@ class Session: public mate::TrackableObject<Session>,
AtomBrowserContext* browser_context() const { return browser_context_.get(); } AtomBrowserContext* browser_context() const { return browser_context_.get(); }
// mate::TrackableObject:
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
protected: protected:
explicit Session(AtomBrowserContext* browser_context); explicit Session(AtomBrowserContext* browser_context);
~Session(); ~Session();
@ -51,20 +60,15 @@ class Session: public mate::TrackableObject<Session>,
void OnDownloadCreated(content::DownloadManager* manager, void OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) override; content::DownloadItem* item) override;
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
private: private:
// mate::TrackableObject:
void Destroy() override;
void ResolveProxy(const GURL& url, ResolveProxyCallback callback); void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
void ClearCache(const net::CompletionCallback& callback); void ClearCache(const net::CompletionCallback& callback);
void ClearStorageData(mate::Arguments* args); 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 SetDownloadPath(const base::FilePath& path);
void EnableNetworkEmulation(const mate::Dictionary& options);
void DisableNetworkEmulation();
void SetCertVerifyProc(v8::Local<v8::Value> proc, mate::Arguments* args);
v8::Local<v8::Value> Cookies(v8::Isolate* isolate); v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
// Cached object for cookies API. // Cached object for cookies API.

View file

@ -44,21 +44,21 @@ mate::Wrappable* Tray::New(v8::Isolate* isolate, const gfx::Image& image) {
void Tray::OnClicked(const gfx::Rect& bounds, int modifiers) { void Tray::OnClicked(const gfx::Rect& bounds, int modifiers) {
v8::Locker locker(isolate()); v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate()); v8::HandleScope handle_scope(isolate());
EmitCustomEvent("clicked", EmitCustomEvent("click",
ModifiersToObject(isolate(), modifiers), bounds); ModifiersToObject(isolate(), modifiers), bounds);
} }
void Tray::OnDoubleClicked(const gfx::Rect& bounds, int modifiers) { void Tray::OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {
v8::Locker locker(isolate()); v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate()); v8::HandleScope handle_scope(isolate());
EmitCustomEvent("double-clicked", EmitCustomEvent("double-click",
ModifiersToObject(isolate(), modifiers), bounds); ModifiersToObject(isolate(), modifiers), bounds);
} }
void Tray::OnRightClicked(const gfx::Rect& bounds, int modifiers) { void Tray::OnRightClicked(const gfx::Rect& bounds, int modifiers) {
v8::Locker locker(isolate()); v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate()); v8::HandleScope handle_scope(isolate());
EmitCustomEvent("right-clicked", EmitCustomEvent("right-click",
ModifiersToObject(isolate(), modifiers), bounds); ModifiersToObject(isolate(), modifiers), bounds);
} }
@ -67,23 +67,31 @@ void Tray::OnBalloonShow() {
} }
void Tray::OnBalloonClicked() { void Tray::OnBalloonClicked() {
Emit("balloon-clicked"); Emit("balloon-click");
} }
void Tray::OnBalloonClosed() { void Tray::OnBalloonClosed() {
Emit("balloon-closed"); Emit("balloon-closed");
} }
void Tray::OnDrop() {
Emit("drop");
}
void Tray::OnDropFiles(const std::vector<std::string>& files) { void Tray::OnDropFiles(const std::vector<std::string>& files) {
Emit("drop-files", files); Emit("drop-files", files);
} }
bool Tray::IsDestroyed() const { void Tray::OnDragEntered() {
return !tray_icon_; Emit("drag-enter");
} }
void Tray::Destroy() { void Tray::OnDragExited() {
tray_icon_.reset(); Emit("drag-leave");
}
void Tray::OnDragEnded() {
Emit("drag-end");
} }
void Tray::SetImage(mate::Arguments* args, const gfx::Image& image) { void Tray::SetImage(mate::Arguments* args, const gfx::Image& image) {
@ -121,9 +129,11 @@ void Tray::DisplayBalloon(mate::Arguments* args,
} }
void Tray::PopUpContextMenu(mate::Arguments* args) { void Tray::PopUpContextMenu(mate::Arguments* args) {
mate::Handle<Menu> menu;
args->GetNext(&menu);
gfx::Point pos; gfx::Point pos;
args->GetNext(&pos); args->GetNext(&pos);
tray_icon_->PopUpContextMenu(pos); tray_icon_->PopUpContextMenu(pos, menu.IsEmpty() ? nullptr : menu->model());
} }
void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) { void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) {
@ -144,7 +154,7 @@ v8::Local<v8::Object> Tray::ModifiersToObject(v8::Isolate* isolate,
void Tray::BuildPrototype(v8::Isolate* isolate, void Tray::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) { v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype) mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("destroy", &Tray::Destroy, true) .MakeDestroyable()
.SetMethod("setImage", &Tray::SetImage) .SetMethod("setImage", &Tray::SetImage)
.SetMethod("setPressedImage", &Tray::SetPressedImage) .SetMethod("setPressedImage", &Tray::SetPressedImage)
.SetMethod("setToolTip", &Tray::SetToolTip) .SetMethod("setToolTip", &Tray::SetToolTip)

View file

@ -8,7 +8,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "atom/browser/api/event_emitter.h" #include "atom/browser/api/trackable_object.h"
#include "atom/browser/ui/tray_icon_observer.h" #include "atom/browser/ui/tray_icon_observer.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
@ -29,7 +29,7 @@ namespace api {
class Menu; class Menu;
class Tray : public mate::EventEmitter, class Tray : public mate::TrackableObject<Tray>,
public TrayIconObserver { public TrayIconObserver {
public: public:
static mate::Wrappable* New(v8::Isolate* isolate, const gfx::Image& image); static mate::Wrappable* New(v8::Isolate* isolate, const gfx::Image& image);
@ -39,7 +39,7 @@ class Tray : public mate::EventEmitter,
protected: protected:
explicit Tray(const gfx::Image& image); explicit Tray(const gfx::Image& image);
virtual ~Tray(); ~Tray() override;
// TrayIconObserver: // TrayIconObserver:
void OnClicked(const gfx::Rect& bounds, int modifiers) override; void OnClicked(const gfx::Rect& bounds, int modifiers) override;
@ -48,12 +48,12 @@ class Tray : public mate::EventEmitter,
void OnBalloonShow() override; void OnBalloonShow() override;
void OnBalloonClicked() override; void OnBalloonClicked() override;
void OnBalloonClosed() override; void OnBalloonClosed() override;
void OnDrop() override;
void OnDropFiles(const std::vector<std::string>& files) override; void OnDropFiles(const std::vector<std::string>& files) override;
void OnDragEntered() override;
void OnDragExited() override;
void OnDragEnded() override;
// mate::Wrappable:
bool IsDestroyed() const override;
void Destroy();
void SetImage(mate::Arguments* args, const gfx::Image& image); void SetImage(mate::Arguments* args, const gfx::Image& image);
void SetPressedImage(mate::Arguments* args, const gfx::Image& image); void SetPressedImage(mate::Arguments* args, const gfx::Image& image);
void SetToolTip(mate::Arguments* args, const std::string& tool_tip); void SetToolTip(mate::Arguments* args, const std::string& tool_tip);

View file

@ -7,6 +7,7 @@
#include <set> #include <set>
#include "atom/browser/api/atom_api_session.h" #include "atom/browser/api/atom_api_session.h"
#include "atom/browser/api/atom_api_window.h"
#include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_client.h"
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
@ -17,6 +18,7 @@
#include "atom/common/api/event_emitter_caller.h" #include "atom/common/api/event_emitter_caller.h"
#include "atom/common/native_mate_converters/blink_converter.h" #include "atom/common/native_mate_converters/blink_converter.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/content_converter.h"
#include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/gfx_converter.h" #include "atom/common/native_mate_converters/gfx_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h"
@ -26,9 +28,11 @@
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "brightray/browser/inspectable_web_contents.h" #include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "chrome/browser/printing/print_view_manager_basic.h" #include "chrome/browser/printing/print_view_manager_basic.h"
#include "chrome/browser/printing/print_preview_message_handler.h" #include "chrome/browser/printing/print_preview_message_handler.h"
#include "content/common/view_messages.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/favicon_status.h"
#include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_details.h"
@ -43,12 +47,14 @@
#include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_partition.h"
#include "content/public/browser/site_instance.h" #include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/common/context_menu_params.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h" #include "native_mate/object_template_builder.h"
#include "net/http/http_response_headers.h" #include "net/http/http_response_headers.h"
#include "net/url_request/static_http_user_agent_settings.h" #include "net/url_request/static_http_user_agent_settings.h"
#include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context.h"
#include "third_party/WebKit/public/web/WebInputEvent.h" #include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/base/l10n/l10n_util.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
@ -60,9 +66,21 @@ struct PrintSettings {
}; };
void SetUserAgentInIO(scoped_refptr<net::URLRequestContextGetter> getter, void SetUserAgentInIO(scoped_refptr<net::URLRequestContextGetter> getter,
std::string accept_lang,
std::string user_agent) { std::string user_agent) {
getter->GetURLRequestContext()->set_http_user_agent_settings( 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 } // namespace
@ -130,8 +148,7 @@ struct Converter<net::HttpResponseHeaders*> {
std::string key; std::string key;
std::string value; std::string value;
while (headers->EnumerateHeaderLines(&iter, &key, &value)) { while (headers->EnumerateHeaderLines(&iter, &key, &value)) {
key = base::StringToLowerASCII(key); key = base::ToLowerASCII(key);
value = base::StringToLowerASCII(value);
if (response_headers.HasKey(key)) { if (response_headers.HasKey(key)) {
base::ListValue* values = nullptr; base::ListValue* values = nullptr;
if (response_headers.GetList(key, &values)) if (response_headers.GetList(key, &values))
@ -147,6 +164,27 @@ 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;
save_type = base::ToLowerASCII(save_type);
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 } // namespace mate
@ -156,8 +194,6 @@ namespace api {
namespace { namespace {
v8::Persistent<v8::ObjectTemplate> template_;
// The wrapWebContents function which is implemented in JavaScript // The wrapWebContents function which is implemented in JavaScript
using WrapWebContentsCallback = base::Callback<void(v8::Local<v8::Value>)>; using WrapWebContentsCallback = base::Callback<void(v8::Local<v8::Value>)>;
WrapWebContentsCallback g_wrap_web_contents; WrapWebContentsCallback g_wrap_web_contents;
@ -228,10 +264,10 @@ WebContents::WebContents(v8::Isolate* isolate,
AttachAsUserData(web_contents); AttachAsUserData(web_contents);
InitWithWebContents(web_contents); InitWithWebContents(web_contents);
managed_web_contents()->GetView()->SetDelegate(this);
// Save the preferences in C++. // Save the preferences in C++.
base::DictionaryValue web_preferences; new WebContentsPreferences(web_contents, options);
mate::ConvertFromV8(isolate, options.GetHandle(), &web_preferences);
new WebContentsPreferences(web_contents, &web_preferences);
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent()); web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
@ -252,7 +288,15 @@ WebContents::WebContents(v8::Isolate* isolate,
} }
WebContents::~WebContents() { WebContents::~WebContents() {
Destroy(); if (type_ == WEB_VIEW && managed_web_contents()) {
// When force destroying the "destroyed" event is not emitted.
WebContentsDestroyed();
guest_delegate_->Destroy();
Observe(nullptr);
DestroyWebContents();
}
} }
bool WebContents::AddMessageToConsole(content::WebContents* source, bool WebContents::AddMessageToConsole(content::WebContents* source,
@ -367,6 +411,15 @@ void WebContents::RendererResponsive(content::WebContents* source) {
owner_window()->RendererResponsive(source); owner_window()->RendererResponsive(source);
} }
bool WebContents::HandleContextMenu(const content::ContextMenuParams& params) {
if (!params.custom_context.is_pepper_menu)
return false;
Emit("pepper-context-menu", std::make_pair(params, web_contents()));
web_contents()->NotifyContextMenuClosed(params.custom_context);
return true;
}
void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) { void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
// Do nothing, we override this method just to avoid compilation error since // Do nothing, we override this method just to avoid compilation error since
// there are two virtual functions named BeforeUnloadFired. // there are two virtual functions named BeforeUnloadFired.
@ -413,14 +466,13 @@ void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host,
Emit("did-finish-load"); Emit("did-finish-load");
} }
// this error occurs when host could not be found
void WebContents::DidFailProvisionalLoad( void WebContents::DidFailProvisionalLoad(
content::RenderFrameHost* render_frame_host, content::RenderFrameHost* render_frame_host,
const GURL& validated_url, const GURL& url,
int error_code, int error_code,
const base::string16& error_description, const base::string16& error_description,
bool was_ignored_by_handler) { bool was_ignored_by_handler) {
Emit("did-fail-load", error_code, error_description, validated_url); Emit("did-fail-provisional-load", error_code, error_description, url);
} }
void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host, void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host,
@ -473,9 +525,10 @@ void WebContents::DidNavigateMainFrame(
void WebContents::TitleWasSet(content::NavigationEntry* entry, void WebContents::TitleWasSet(content::NavigationEntry* entry,
bool explicit_set) { bool explicit_set) {
// Back/Forward navigation may have pruned entries.
if (entry) if (entry)
Emit("page-title-set", entry->GetTitle(), explicit_set); Emit("-page-title-updated", entry->GetTitle(), explicit_set);
else
Emit("-page-title-updated", "", explicit_set);
} }
void WebContents::DidUpdateFaviconURL( void WebContents::DidUpdateFaviconURL(
@ -491,12 +544,40 @@ void WebContents::DidUpdateFaviconURL(
Emit("page-favicon-updated", unique_urls); Emit("page-favicon-updated", unique_urls);
} }
void WebContents::DevToolsFocused() {
Emit("devtools-focused");
}
void WebContents::DevToolsOpened() {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto handle = WebContents::CreateFrom(
isolate(), managed_web_contents()->GetDevToolsWebContents());
devtools_web_contents_.Reset(isolate(), handle.ToV8());
// Inherit owner window in devtools.
if (owner_window())
handle->SetOwnerWindow(managed_web_contents()->GetDevToolsWebContents(),
owner_window());
Emit("devtools-opened");
}
void WebContents::DevToolsClosed() {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
devtools_web_contents_.Reset();
Emit("devtools-closed");
}
bool WebContents::OnMessageReceived(const IPC::Message& message) { bool WebContents::OnMessageReceived(const IPC::Message& message) {
bool handled = true; bool handled = true;
IPC_BEGIN_MESSAGE_MAP(WebContents, message) IPC_BEGIN_MESSAGE_MAP(WebContents, message)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage) IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync, IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
OnRendererMessageSync) OnRendererMessageSync)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_ZoomLevelChanged, OnZoomLevelChanged)
IPC_MESSAGE_UNHANDLED(handled = false) IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP() IPC_END_MESSAGE_MAP()
@ -516,23 +597,6 @@ void WebContents::NavigationEntryCommitted(
details.is_in_page, details.did_replace_entry); details.is_in_page, details.did_replace_entry);
} }
void WebContents::Destroy() {
session_.Reset();
if (type_ == WEB_VIEW && managed_web_contents()) {
// When force destroying the "destroyed" event is not emitted.
WebContentsDestroyed();
guest_delegate_->Destroy();
Observe(nullptr);
DestroyWebContents();
}
}
bool WebContents::IsAlive() const {
return web_contents() != NULL;
}
int WebContents::GetID() const { int WebContents::GetID() const {
return web_contents()->GetRenderProcessHost()->GetID(); return web_contents()->GetRenderProcessHost()->GetID();
} }
@ -553,12 +617,25 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
if (options.Get("userAgent", &user_agent)) if (options.Get("userAgent", &user_agent))
SetUserAgent(user_agent); SetUserAgent(user_agent);
std::string extra_headers;
if (options.Get("extraHeaders", &extra_headers))
params.extra_headers = extra_headers;
params.transition_type = ui::PAGE_TRANSITION_TYPED; params.transition_type = ui::PAGE_TRANSITION_TYPED;
params.should_clear_history_list = true; params.should_clear_history_list = true;
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE; params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
web_contents()->GetController().LoadURLWithParams(params); web_contents()->GetController().LoadURLWithParams(params);
} }
void WebContents::DownloadURL(const GURL& url) {
auto browser_context = web_contents()->GetBrowserContext();
auto download_manager =
content::BrowserContext::GetDownloadManager(browser_context);
download_manager->DownloadUrl(
content::DownloadUrlParameters::FromWebContents(web_contents(), url));
}
GURL WebContents::GetURL() const { GURL WebContents::GetURL() const {
return web_contents()->GetURL(); return web_contents()->GetURL();
} }
@ -579,10 +656,6 @@ void WebContents::Stop() {
web_contents()->Stop(); web_contents()->Stop();
} }
void WebContents::ReloadIgnoringCache() {
web_contents()->GetController().ReloadIgnoringCache(false);
}
void WebContents::GoBack() { void WebContents::GoBack() {
atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce(); atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
web_contents()->GetController().GoBack(); web_contents()->GetController().GoBack();
@ -606,8 +679,10 @@ void WebContents::SetUserAgent(const std::string& user_agent) {
web_contents()->SetUserAgentOverride(user_agent); web_contents()->SetUserAgentOverride(user_agent);
scoped_refptr<net::URLRequestContextGetter> getter = scoped_refptr<net::URLRequestContextGetter> getter =
web_contents()->GetBrowserContext()->GetRequestContext(); web_contents()->GetBrowserContext()->GetRequestContext();
auto accept_lang = l10n_util::GetApplicationLocale("");
getter->GetNetworkTaskRunner()->PostTask(FROM_HERE, getter->GetNetworkTaskRunner()->PostTask(FROM_HERE,
base::Bind(&SetUserAgentInIO, getter, user_agent)); base::Bind(&SetUserAgentInIO, getter, accept_lang, user_agent));
} }
std::string WebContents::GetUserAgent() { std::string WebContents::GetUserAgent() {
@ -618,6 +693,13 @@ void WebContents::InsertCSS(const std::string& css) {
web_contents()->InsertCSS(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, void WebContents::ExecuteJavaScript(const base::string16& code,
bool has_user_gesture) { bool has_user_gesture) {
Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture)); Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture));
@ -698,10 +780,6 @@ void WebContents::InspectServiceWorker() {
} }
} }
v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, session_);
}
void WebContents::HasServiceWorker( void WebContents::HasServiceWorker(
const base::Callback<void(bool)>& callback) { const base::Callback<void(bool)>& callback) {
auto context = GetServiceWorkerContext(web_contents()); auto context = GetServiceWorkerContext(web_contents());
@ -893,79 +971,91 @@ v8::Local<v8::Value> WebContents::GetWebPreferences(v8::Isolate* isolate) {
return mate::ConvertToV8(isolate, *web_preferences->web_preferences()); return mate::ConvertToV8(isolate, *web_preferences->web_preferences());
} }
mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder( v8::Local<v8::Value> WebContents::GetOwnerBrowserWindow() {
v8::Isolate* isolate) { if (owner_window())
if (template_.IsEmpty()) return Window::From(isolate(), owner_window());
template_.Reset(isolate, mate::ObjectTemplateBuilder(isolate) else
.SetMethod("destroy", &WebContents::Destroy, true) return v8::Null(isolate());
.SetMethod("isAlive", &WebContents::IsAlive, true)
.SetMethod("getId", &WebContents::GetID)
.SetMethod("equal", &WebContents::Equal)
.SetMethod("_loadUrl", &WebContents::LoadURL)
.SetMethod("_getUrl", &WebContents::GetURL)
.SetMethod("getTitle", &WebContents::GetTitle)
.SetMethod("isLoading", &WebContents::IsLoading)
.SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse)
.SetMethod("_stop", &WebContents::Stop)
.SetMethod("_reloadIgnoringCache", &WebContents::ReloadIgnoringCache)
.SetMethod("_goBack", &WebContents::GoBack)
.SetMethod("_goForward", &WebContents::GoForward)
.SetMethod("_goToOffset", &WebContents::GoToOffset)
.SetMethod("isCrashed", &WebContents::IsCrashed)
.SetMethod("setUserAgent", &WebContents::SetUserAgent)
.SetMethod("getUserAgent", &WebContents::GetUserAgent)
.SetMethod("insertCSS", &WebContents::InsertCSS)
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
.SetMethod("openDevTools", &WebContents::OpenDevTools)
.SetMethod("closeDevTools", &WebContents::CloseDevTools)
.SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened)
.SetMethod("enableDeviceEmulation",
&WebContents::EnableDeviceEmulation)
.SetMethod("disableDeviceEmulation",
&WebContents::DisableDeviceEmulation)
.SetMethod("toggleDevTools", &WebContents::ToggleDevTools)
.SetMethod("inspectElement", &WebContents::InspectElement)
.SetMethod("setAudioMuted", &WebContents::SetAudioMuted)
.SetMethod("isAudioMuted", &WebContents::IsAudioMuted)
.SetMethod("undo", &WebContents::Undo)
.SetMethod("redo", &WebContents::Redo)
.SetMethod("cut", &WebContents::Cut)
.SetMethod("copy", &WebContents::Copy)
.SetMethod("paste", &WebContents::Paste)
.SetMethod("pasteAndMatchStyle", &WebContents::PasteAndMatchStyle)
.SetMethod("delete", &WebContents::Delete)
.SetMethod("selectAll", &WebContents::SelectAll)
.SetMethod("unselect", &WebContents::Unselect)
.SetMethod("replace", &WebContents::Replace)
.SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling)
.SetMethod("focus", &WebContents::Focus)
.SetMethod("tabTraverse", &WebContents::TabTraverse)
.SetMethod("_send", &WebContents::SendIPCMessage, true)
.SetMethod("sendInputEvent", &WebContents::SendInputEvent)
.SetMethod("beginFrameSubscription",
&WebContents::BeginFrameSubscription)
.SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
.SetMethod("setSize", &WebContents::SetSize)
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
.SetMethod("isGuest", &WebContents::IsGuest)
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
.SetMethod("unregisterServiceWorker",
&WebContents::UnregisterServiceWorker)
.SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
.SetMethod("print", &WebContents::Print)
.SetMethod("_printToPDF", &WebContents::PrintToPDF)
.SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
.SetProperty("session", &WebContents::Session)
.Build());
return mate::ObjectTemplateBuilder(
isolate, v8::Local<v8::ObjectTemplate>::New(isolate, template_));
} }
bool WebContents::IsDestroyed() const { v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
return !IsAlive(); return v8::Local<v8::Value>::New(isolate, session_);
}
v8::Local<v8::Value> WebContents::DevToolsWebContents(v8::Isolate* isolate) {
if (devtools_web_contents_.IsEmpty())
return v8::Null(isolate);
else
return v8::Local<v8::Value>::New(isolate, devtools_web_contents_);
}
// static
void WebContents::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.MakeDestroyable()
.SetMethod("getId", &WebContents::GetID)
.SetMethod("equal", &WebContents::Equal)
.SetMethod("_loadURL", &WebContents::LoadURL)
.SetMethod("downloadURL", &WebContents::DownloadURL)
.SetMethod("_getURL", &WebContents::GetURL)
.SetMethod("getTitle", &WebContents::GetTitle)
.SetMethod("isLoading", &WebContents::IsLoading)
.SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse)
.SetMethod("_stop", &WebContents::Stop)
.SetMethod("_goBack", &WebContents::GoBack)
.SetMethod("_goForward", &WebContents::GoForward)
.SetMethod("_goToOffset", &WebContents::GoToOffset)
.SetMethod("isCrashed", &WebContents::IsCrashed)
.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)
.SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened)
.SetMethod("enableDeviceEmulation",
&WebContents::EnableDeviceEmulation)
.SetMethod("disableDeviceEmulation",
&WebContents::DisableDeviceEmulation)
.SetMethod("toggleDevTools", &WebContents::ToggleDevTools)
.SetMethod("inspectElement", &WebContents::InspectElement)
.SetMethod("setAudioMuted", &WebContents::SetAudioMuted)
.SetMethod("isAudioMuted", &WebContents::IsAudioMuted)
.SetMethod("undo", &WebContents::Undo)
.SetMethod("redo", &WebContents::Redo)
.SetMethod("cut", &WebContents::Cut)
.SetMethod("copy", &WebContents::Copy)
.SetMethod("paste", &WebContents::Paste)
.SetMethod("pasteAndMatchStyle", &WebContents::PasteAndMatchStyle)
.SetMethod("delete", &WebContents::Delete)
.SetMethod("selectAll", &WebContents::SelectAll)
.SetMethod("unselect", &WebContents::Unselect)
.SetMethod("replace", &WebContents::Replace)
.SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling)
.SetMethod("focus", &WebContents::Focus)
.SetMethod("tabTraverse", &WebContents::TabTraverse)
.SetMethod("_send", &WebContents::SendIPCMessage)
.SetMethod("sendInputEvent", &WebContents::SendInputEvent)
.SetMethod("beginFrameSubscription",
&WebContents::BeginFrameSubscription)
.SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
.SetMethod("setSize", &WebContents::SetSize)
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
.SetMethod("isGuest", &WebContents::IsGuest)
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
.SetMethod("unregisterServiceWorker",
&WebContents::UnregisterServiceWorker)
.SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
.SetMethod("print", &WebContents::Print)
.SetMethod("_printToPDF", &WebContents::PrintToPDF)
.SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
.SetProperty("session", &WebContents::Session)
.SetProperty("devToolsWebContents", &WebContents::DevToolsWebContents);
} }
AtomBrowserContext* WebContents::GetBrowserContext() const { AtomBrowserContext* WebContents::GetBrowserContext() const {
@ -985,6 +1075,15 @@ void WebContents::OnRendererMessageSync(const base::string16& channel,
EmitWithSender(base::UTF16ToUTF8(channel), web_contents(), message, args); 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 // static
mate::Handle<WebContents> WebContents::CreateFrom( mate::Handle<WebContents> WebContents::CreateFrom(
v8::Isolate* isolate, content::WebContents* web_contents) { v8::Isolate* isolate, content::WebContents* web_contents) {
@ -1007,14 +1106,18 @@ mate::Handle<WebContents> WebContents::Create(
return handle; return handle;
} }
void SetWrapWebContents(const WrapWebContentsCallback& callback) {
g_wrap_web_contents = callback;
}
void ClearWrapWebContents() { void ClearWrapWebContents() {
g_wrap_web_contents.Reset(); g_wrap_web_contents.Reset();
} }
void SetWrapWebContents(const WrapWebContentsCallback& callback) {
g_wrap_web_contents = callback;
// Cleanup the wrapper on exit.
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
base::Bind(ClearWrapWebContents));
}
} // namespace api } // namespace api
} // namespace atom } // namespace atom
@ -1028,7 +1131,6 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
mate::Dictionary dict(isolate, exports); mate::Dictionary dict(isolate, exports);
dict.SetMethod("create", &atom::api::WebContents::Create); dict.SetMethod("create", &atom::api::WebContents::Create);
dict.SetMethod("_setWrapWebContents", &atom::api::SetWrapWebContents); dict.SetMethod("_setWrapWebContents", &atom::api::SetWrapWebContents);
dict.SetMethod("_clearWrapWebContents", &atom::api::ClearWrapWebContents);
} }
} // namespace } // namespace

View file

@ -9,6 +9,7 @@
#include <vector> #include <vector>
#include "atom/browser/api/frame_subscriber.h" #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/api/trackable_object.h"
#include "atom/browser/common_web_contents_delegate.h" #include "atom/browser/common_web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
@ -53,13 +54,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
static mate::Handle<WebContents> Create( static mate::Handle<WebContents> Create(
v8::Isolate* isolate, const mate::Dictionary& options); v8::Isolate* isolate, const mate::Dictionary& options);
// mate::TrackableObject:
void Destroy() override;
bool IsAlive() const;
int GetID() const; int GetID() const;
bool Equal(const WebContents* web_contents) const; bool Equal(const WebContents* web_contents) const;
void LoadURL(const GURL& url, const mate::Dictionary& options); void LoadURL(const GURL& url, const mate::Dictionary& options);
void DownloadURL(const GURL& url);
GURL GetURL() const; GURL GetURL() const;
base::string16 GetTitle() const; base::string16 GetTitle() const;
bool IsLoading() const; bool IsLoading() const;
@ -73,6 +71,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
void SetUserAgent(const std::string& user_agent); void SetUserAgent(const std::string& user_agent);
std::string GetUserAgent(); std::string GetUserAgent();
void InsertCSS(const std::string& css); 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, void ExecuteJavaScript(const base::string16& code,
bool has_user_gesture); bool has_user_gesture);
void OpenDevTools(mate::Arguments* args); void OpenDevTools(mate::Arguments* args);
@ -83,7 +84,6 @@ class WebContents : public mate::TrackableObject<WebContents>,
void DisableDeviceEmulation(); void DisableDeviceEmulation();
void InspectElement(int x, int y); void InspectElement(int x, int y);
void InspectServiceWorker(); void InspectServiceWorker();
v8::Local<v8::Value> Session(v8::Isolate* isolate);
void HasServiceWorker(const base::Callback<void(bool)>&); void HasServiceWorker(const base::Callback<void(bool)>&);
void UnregisterServiceWorker(const base::Callback<void(bool)>&); void UnregisterServiceWorker(const base::Callback<void(bool)>&);
void SetAudioMuted(bool muted); void SetAudioMuted(bool muted);
@ -135,16 +135,22 @@ class WebContents : public mate::TrackableObject<WebContents>,
// Returns the web preferences of current WebContents. // Returns the web preferences of current WebContents.
v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate); v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate);
// Returns the owner window.
v8::Local<v8::Value> GetOwnerBrowserWindow();
// Properties.
v8::Local<v8::Value> Session(v8::Isolate* isolate);
v8::Local<v8::Value> DevToolsWebContents(v8::Isolate* isolate);
// mate::TrackableObject:
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
protected: protected:
explicit WebContents(content::WebContents* web_contents); explicit WebContents(content::WebContents* web_contents);
WebContents(v8::Isolate* isolate, const mate::Dictionary& options); WebContents(v8::Isolate* isolate, const mate::Dictionary& options);
~WebContents(); ~WebContents();
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
// content::WebContentsDelegate: // content::WebContentsDelegate:
bool AddMessageToConsole(content::WebContents* source, bool AddMessageToConsole(content::WebContents* source,
int32 level, int32 level,
@ -179,6 +185,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
void ExitFullscreenModeForTab(content::WebContents* source) override; void ExitFullscreenModeForTab(content::WebContents* source) override;
void RendererUnresponsive(content::WebContents* source) override; void RendererUnresponsive(content::WebContents* source) override;
void RendererResponsive(content::WebContents* source) override; void RendererResponsive(content::WebContents* source) override;
bool HandleContextMenu(const content::ContextMenuParams& params) override;
// content::WebContentsObserver: // content::WebContentsObserver:
void BeforeUnloadFired(const base::TimeTicks& proceed_time) override; void BeforeUnloadFired(const base::TimeTicks& proceed_time) override;
@ -218,6 +225,11 @@ class WebContents : public mate::TrackableObject<WebContents>,
void PluginCrashed(const base::FilePath& plugin_path, void PluginCrashed(const base::FilePath& plugin_path,
base::ProcessId plugin_pid) override; base::ProcessId plugin_pid) override;
// brightray::InspectableWebContentsViewDelegate:
void DevToolsFocused() override;
void DevToolsOpened() override;
void DevToolsClosed() override;
private: private:
enum Type { enum Type {
BROWSER_WINDOW, // Used by BrowserWindow. BROWSER_WINDOW, // Used by BrowserWindow.
@ -236,7 +248,12 @@ class WebContents : public mate::TrackableObject<WebContents>,
const base::ListValue& args, const base::ListValue& args,
IPC::Message* message); 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> session_;
v8::Global<v8::Value> devtools_web_contents_;
scoped_ptr<WebViewGuestDelegate> guest_delegate_; scoped_ptr<WebViewGuestDelegate> guest_delegate_;

View file

@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "atom/browser/api/atom_api_window.h" #include "atom/browser/api/atom_api_window.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/browser/api/atom_api_menu.h" #include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/api/atom_api_web_contents.h"
@ -60,22 +61,82 @@ void OnCapturePageDone(
callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap)); callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap));
} }
// Converts min-width to minWidth, returns false if no conversion is needed.
bool TranslateOldKey(const std::string& key, std::string* new_key) {
if (key.find('-') == std::string::npos)
return false;
new_key->reserve(key.size());
bool next_upper_case = false;
for (char c : key) {
if (c == '-') {
next_upper_case = true;
} else if (next_upper_case) {
new_key->push_back(base::ToUpperASCII(c));
next_upper_case = false;
} else {
new_key->push_back(c);
}
}
return true;
}
// Converts min-width to minWidth recursively in the dictionary.
void TranslateOldOptions(v8::Isolate* isolate, v8::Local<v8::Object> options) {
auto context = isolate->GetCurrentContext();
auto maybe_keys = options->GetOwnPropertyNames(context);
if (maybe_keys.IsEmpty())
return;
std::vector<std::string> keys;
if (!mate::ConvertFromV8(isolate, maybe_keys.ToLocalChecked(), &keys))
return;
mate::Dictionary dict(isolate, options);
for (const auto& key : keys) {
v8::Local<v8::Value> value;
if (!dict.Get(key, &value)) // Shouldn't happen, but guard it anyway.
continue;
// Go recursively.
v8::Local<v8::Object> sub_options;
if (mate::ConvertFromV8(isolate, value, &sub_options))
TranslateOldOptions(isolate, sub_options);
// Translate key.
std::string new_key;
if (TranslateOldKey(key, &new_key)) {
dict.Set(new_key, value);
dict.Delete(key);
}
}
}
#if defined(OS_WIN)
// Converts binary data to Buffer.
v8::Local<v8::Value> ToBuffer(v8::Isolate* isolate, void* val, int size) {
auto buffer = node::Buffer::New(isolate, static_cast<char*>(val), size);
if (buffer.IsEmpty())
return v8::Null(isolate);
else
return buffer.ToLocalChecked();
}
#endif
} // namespace } // namespace
Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) { Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
// Use options['web-preferences'] to create WebContents. // Be compatible with old style field names like min-width.
TranslateOldOptions(isolate, options.GetHandle());
// Use options.webPreferences to create WebContents.
mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate); mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate);
options.Get(switches::kWebPreferences, &web_preferences); options.Get(options::kWebPreferences, &web_preferences);
// Be compatible with old options which are now in web_preferences. // Be compatible with old options which are now in web_preferences.
v8::Local<v8::Value> value; v8::Local<v8::Value> value;
if (options.Get(switches::kNodeIntegration, &value)) if (options.Get(options::kNodeIntegration, &value))
web_preferences.Set(switches::kNodeIntegration, value); web_preferences.Set(options::kNodeIntegration, value);
if (options.Get(switches::kPreloadScript, &value)) if (options.Get(options::kPreloadScript, &value))
web_preferences.Set(switches::kPreloadScript, value); web_preferences.Set(options::kPreloadScript, value);
if (options.Get(switches::kZoomFactor, &value)) if (options.Get(options::kZoomFactor, &value))
web_preferences.Set(switches::kZoomFactor, value); web_preferences.Set(options::kZoomFactor, value);
// Creates the WebContents used by BrowserWindow. // Creates the WebContents used by BrowserWindow.
auto web_contents = WebContents::Create(isolate, web_preferences); auto web_contents = WebContents::Create(isolate, web_preferences);
@ -92,16 +153,16 @@ Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
web_contents->SetOwnerWindow(window_.get()); web_contents->SetOwnerWindow(window_.get());
window_->InitFromOptions(options); window_->InitFromOptions(options);
window_->AddObserver(this); window_->AddObserver(this);
AttachAsUserData(window_.get());
} }
Window::~Window() { Window::~Window() {
if (window_) if (!window_->IsClosed())
Destroy(); window_->CloseContents(nullptr);
}
void Window::OnPageTitleUpdated(bool* prevent_default, // Destroy the native window in next tick because the native code might be
const std::string& title) { // iterating all windows.
*prevent_default = Emit("page-title-updated", title); base::MessageLoop::current()->DeleteSoon(FROM_HERE, window_.release());
} }
void Window::WillCloseWindow(bool* prevent_default) { void Window::WillCloseWindow(bool* prevent_default) {
@ -109,19 +170,19 @@ void Window::WillCloseWindow(bool* prevent_default) {
} }
void Window::OnWindowClosed() { void Window::OnWindowClosed() {
if (api_web_contents_) { api_web_contents_->DestroyWebContents();
api_web_contents_->DestroyWebContents();
api_web_contents_ = nullptr;
web_contents_.Reset();
}
RemoveFromWeakMap(); RemoveFromWeakMap();
window_->RemoveObserver(this); window_->RemoveObserver(this);
// We can not call Destroy here because we need to call Emit first, but we
// also do not want any method to be used, so just mark as destroyed here.
MarkDestroyed();
Emit("closed"); Emit("closed");
// Clean up the resources after window has been closed. // Destroy the native class when window is closed.
base::MessageLoop::current()->DeleteSoon(FROM_HERE, window_.release()); base::MessageLoop::current()->PostTask(FROM_HERE, GetDestroyClosure());
} }
void Window::OnWindowBlur() { void Window::OnWindowBlur() {
@ -184,60 +245,45 @@ void Window::OnRendererResponsive() {
Emit("responsive"); Emit("responsive");
} }
void Window::OnDevToolsFocus() {
Emit("devtools-focused");
}
void Window::OnDevToolsOpened() {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto handle = WebContents::CreateFrom(
isolate(), api_web_contents_->GetDevToolsWebContents());
devtools_web_contents_.Reset(isolate(), handle.ToV8());
Emit("devtools-opened");
}
void Window::OnDevToolsClosed() {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
devtools_web_contents_.Reset();
Emit("devtools-closed");
}
void Window::OnExecuteWindowsCommand(const std::string& command_name) { void Window::OnExecuteWindowsCommand(const std::string& command_name) {
Emit("app-command", command_name); Emit("app-command", command_name);
} }
#if defined(OS_WIN)
void Window::OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) {
if (IsWindowMessageHooked(message)) {
messages_callback_map_[message].Run(
ToBuffer(isolate(), static_cast<void*>(&w_param), sizeof(WPARAM)),
ToBuffer(isolate(), static_cast<void*>(&l_param), sizeof(LPARAM)));
}
}
#endif
// static // static
mate::Wrappable* Window::New(v8::Isolate* isolate, mate::Wrappable* Window::New(v8::Isolate* isolate, mate::Arguments* args) {
const mate::Dictionary& options) {
if (!Browser::Get()->is_ready()) { if (!Browser::Get()->is_ready()) {
isolate->ThrowException(v8::Exception::Error(mate::StringToV8( isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
isolate, "Cannot create BrowserWindow before app is ready"))); isolate, "Cannot create BrowserWindow before app is ready")));
return nullptr; return nullptr;
} }
if (args->Length() > 1) {
args->ThrowError();
return nullptr;
}
mate::Dictionary options;
if (!(args->Length() == 1 && args->GetNext(&options))) {
options = mate::Dictionary::CreateEmpty(isolate);
}
return new Window(isolate, options); return new Window(isolate, options);
} }
bool Window::IsDestroyed() const {
return !window_ || window_->IsClosed();
}
void Window::Destroy() {
if (window_)
window_->CloseContents(nullptr);
}
void Window::Close() { void Window::Close() {
window_->Close(); window_->Close();
} }
bool Window::IsClosed() {
return window_->IsClosed();
}
void Window::Focus() { void Window::Focus() {
window_->Focus(true); window_->Focus(true);
} }
@ -406,6 +452,10 @@ bool Window::IsKiosk() {
return window_->IsKiosk(); return window_->IsKiosk();
} }
void Window::SetBackgroundColor(const std::string& color_name) {
window_->SetBackgroundColor(color_name);
}
void Window::FocusOnWebView() { void Window::FocusOnWebView() {
window_->FocusOnWebView(); window_->FocusOnWebView();
} }
@ -509,6 +559,29 @@ bool Window::IsMenuBarVisible() {
return window_->IsMenuBarVisible(); return window_->IsMenuBarVisible();
} }
#if defined(OS_WIN)
bool Window::HookWindowMessage(UINT message,
const MessageCallback& callback) {
messages_callback_map_[message] = callback;
return true;
}
void Window::UnhookWindowMessage(UINT message) {
if (!ContainsKey(messages_callback_map_, message))
return;
messages_callback_map_.erase(message);
}
bool Window::IsWindowMessageHooked(UINT message) {
return ContainsKey(messages_callback_map_, message);
}
void Window::UnhookAllWindowMessages() {
messages_callback_map_.clear();
}
#endif
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
void Window::ShowDefinitionForSelection() { void Window::ShowDefinitionForSelection() {
window_->ShowDefinitionForSelection(); window_->ShowDefinitionForSelection();
@ -540,20 +613,12 @@ v8::Local<v8::Value> Window::WebContents(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, web_contents_); return v8::Local<v8::Value>::New(isolate, web_contents_);
} }
v8::Local<v8::Value> Window::DevToolsWebContents(v8::Isolate* isolate) {
if (devtools_web_contents_.IsEmpty())
return v8::Null(isolate);
else
return v8::Local<v8::Value>::New(isolate, devtools_web_contents_);
}
// static // static
void Window::BuildPrototype(v8::Isolate* isolate, void Window::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) { v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype) mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("destroy", &Window::Destroy, true) .MakeDestroyable()
.SetMethod("close", &Window::Close) .SetMethod("close", &Window::Close)
.SetMethod("isClosed", &Window::IsClosed)
.SetMethod("focus", &Window::Focus) .SetMethod("focus", &Window::Focus)
.SetMethod("isFocused", &Window::IsFocused) .SetMethod("isFocused", &Window::IsFocused)
.SetMethod("show", &Window::Show) .SetMethod("show", &Window::Show)
@ -592,6 +657,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setSkipTaskbar", &Window::SetSkipTaskbar) .SetMethod("setSkipTaskbar", &Window::SetSkipTaskbar)
.SetMethod("setKiosk", &Window::SetKiosk) .SetMethod("setKiosk", &Window::SetKiosk)
.SetMethod("isKiosk", &Window::IsKiosk) .SetMethod("isKiosk", &Window::IsKiosk)
.SetMethod("setBackgroundColor", &Window::SetBackgroundColor)
.SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename) .SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename)
.SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename) .SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename)
.SetMethod("setDocumentEdited", &Window::SetDocumentEdited) .SetMethod("setDocumentEdited", &Window::SetDocumentEdited)
@ -613,13 +679,28 @@ void Window::BuildPrototype(v8::Isolate* isolate,
&Window::SetVisibleOnAllWorkspaces) &Window::SetVisibleOnAllWorkspaces)
.SetMethod("isVisibleOnAllWorkspaces", .SetMethod("isVisibleOnAllWorkspaces",
&Window::IsVisibleOnAllWorkspaces) &Window::IsVisibleOnAllWorkspaces)
#if defined(OS_WIN)
.SetMethod("hookWindowMessage", &Window::HookWindowMessage)
.SetMethod("isWindowMessageHooked", &Window::IsWindowMessageHooked)
.SetMethod("unhookWindowMessage", &Window::UnhookWindowMessage)
.SetMethod("unhookAllWindowMessages", &Window::UnhookAllWindowMessages)
#endif
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
.SetMethod("showDefinitionForSelection", .SetMethod("showDefinitionForSelection",
&Window::ShowDefinitionForSelection) &Window::ShowDefinitionForSelection)
#endif #endif
.SetProperty("id", &Window::ID, true) .SetProperty("id", &Window::ID)
.SetProperty("webContents", &Window::WebContents, true) .SetProperty("webContents", &Window::WebContents);
.SetProperty("devToolsWebContents", &Window::DevToolsWebContents, true); }
// static
v8::Local<v8::Value> Window::From(v8::Isolate* isolate,
NativeWindow* native_window) {
auto existing = TrackableObject::FromWrappedClass(isolate, native_window);
if (existing)
return existing->GetWrapper(isolate);
else
return v8::Null(isolate);
} }
} // namespace api } // namespace api

View file

@ -5,6 +5,7 @@
#ifndef ATOM_BROWSER_API_ATOM_API_WINDOW_H_ #ifndef ATOM_BROWSER_API_ATOM_API_WINDOW_H_
#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_ #define ATOM_BROWSER_API_ATOM_API_WINDOW_H_
#include <map>
#include <string> #include <string>
#include <vector> #include <vector>
@ -37,12 +38,15 @@ class WebContents;
class Window : public mate::TrackableObject<Window>, class Window : public mate::TrackableObject<Window>,
public NativeWindowObserver { public NativeWindowObserver {
public: public:
static mate::Wrappable* New(v8::Isolate* isolate, static mate::Wrappable* New(v8::Isolate* isolate, mate::Arguments* args);
const mate::Dictionary& options);
static void BuildPrototype(v8::Isolate* isolate, static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype); v8::Local<v8::ObjectTemplate> prototype);
// Returns the BrowserWindow object from |native_window|.
static v8::Local<v8::Value> From(v8::Isolate* isolate,
NativeWindow* native_window);
NativeWindow* window() const { return window_.get(); } NativeWindow* window() const { return window_.get(); }
protected: protected:
@ -50,8 +54,6 @@ class Window : public mate::TrackableObject<Window>,
virtual ~Window(); virtual ~Window();
// NativeWindowObserver: // NativeWindowObserver:
void OnPageTitleUpdated(bool* prevent_default,
const std::string& title) override;
void WillCloseWindow(bool* prevent_default) override; void WillCloseWindow(bool* prevent_default) override;
void OnWindowClosed() override; void OnWindowClosed() override;
void OnWindowBlur() override; void OnWindowBlur() override;
@ -69,21 +71,15 @@ class Window : public mate::TrackableObject<Window>,
void OnWindowLeaveHtmlFullScreen() override; void OnWindowLeaveHtmlFullScreen() override;
void OnRendererUnresponsive() override; void OnRendererUnresponsive() override;
void OnRendererResponsive() override; void OnRendererResponsive() override;
void OnDevToolsFocus() override;
void OnDevToolsOpened() override;
void OnDevToolsClosed() override;
void OnExecuteWindowsCommand(const std::string& command_name) override; void OnExecuteWindowsCommand(const std::string& command_name) override;
// mate::Wrappable: #if defined(OS_WIN)
bool IsDestroyed() const override; void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) override;
#endif
private: private:
// mate::TrackableObject:
void Destroy() override;
// APIs for NativeWindow. // APIs for NativeWindow.
void Close(); void Close();
bool IsClosed();
void Focus(); void Focus();
bool IsFocused(); bool IsFocused();
void Show(); void Show();
@ -121,6 +117,7 @@ class Window : public mate::TrackableObject<Window>,
void SetSkipTaskbar(bool skip); void SetSkipTaskbar(bool skip);
void SetKiosk(bool kiosk); void SetKiosk(bool kiosk);
bool IsKiosk(); bool IsKiosk();
void SetBackgroundColor(const std::string& color_name);
void FocusOnWebView(); void FocusOnWebView();
void BlurWebView(); void BlurWebView();
bool IsWebViewFocused(); bool IsWebViewFocused();
@ -141,6 +138,16 @@ class Window : public mate::TrackableObject<Window>,
bool IsMenuBarVisible(); bool IsMenuBarVisible();
void SetAspectRatio(double aspect_ratio, mate::Arguments* args); void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
#if defined(OS_WIN)
typedef base::Callback<void(v8::Local<v8::Value>,
v8::Local<v8::Value>)> MessageCallback;
bool HookWindowMessage(UINT message, const MessageCallback& callback);
bool IsWindowMessageHooked(UINT message);
void UnhookWindowMessage(UINT message);
void UnhookAllWindowMessages();
#endif
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
void ShowDefinitionForSelection(); void ShowDefinitionForSelection();
#endif #endif
@ -150,10 +157,13 @@ class Window : public mate::TrackableObject<Window>,
int32_t ID() const; int32_t ID() const;
v8::Local<v8::Value> WebContents(v8::Isolate* isolate); v8::Local<v8::Value> WebContents(v8::Isolate* isolate);
v8::Local<v8::Value> DevToolsWebContents(v8::Isolate* isolate);
#if defined(OS_WIN)
typedef std::map<UINT, MessageCallback> MessageCallbackMap;
MessageCallbackMap messages_callback_map_;
#endif
v8::Global<v8::Value> web_contents_; v8::Global<v8::Value> web_contents_;
v8::Global<v8::Value> devtools_web_contents_;
v8::Global<v8::Value> menu_; v8::Global<v8::Value> menu_;
api::WebContents* api_web_contents_; api::WebContents* api_web_contents_;

View file

@ -24,12 +24,11 @@ bool FrameSubscriber::ShouldCaptureFrame(
base::TimeTicks present_time, base::TimeTicks present_time,
scoped_refptr<media::VideoFrame>* storage, scoped_refptr<media::VideoFrame>* storage,
DeliverFrameCallback* callback) { DeliverFrameCallback* callback) {
*storage = media::VideoFrame::CreateFrame(media::VideoFrame::YV12, size_, *storage = media::VideoFrame::CreateFrame(
gfx::Rect(size_), size_, media::PIXEL_FORMAT_YV12,
base::TimeDelta()); size_, gfx::Rect(size_), size_, base::TimeDelta());
*callback = base::Bind(&FrameSubscriber::OnFrameDelivered, *callback = base::Bind(&FrameSubscriber::OnFrameDelivered,
base::Unretained(this), base::Unretained(this), *storage);
*storage);
return true; return true;
} }
@ -38,6 +37,9 @@ void FrameSubscriber::OnFrameDelivered(
if (!result) if (!result)
return; return;
v8::Locker locker(isolate_);
v8::HandleScope handle_scope(isolate_);
gfx::Rect rect = frame->visible_rect(); gfx::Rect rect = frame->visible_rect();
size_t rgb_arr_size = rect.width() * rect.height() * 4; size_t rgb_arr_size = rect.width() * rect.height() * 4;
v8::MaybeLocal<v8::Object> buffer = node::Buffer::New(isolate_, rgb_arr_size); v8::MaybeLocal<v8::Object> buffer = node::Buffer::New(isolate_, rgb_arr_size);
@ -56,8 +58,6 @@ void FrameSubscriber::OnFrameDelivered(
rect.width() * 4, rect.width() * 4,
media::YV12); media::YV12);
v8::Locker locker(isolate_);
v8::HandleScope handle_scope(isolate_);
callback_.Run(buffer.ToLocalChecked()); callback_.Run(buffer.ToLocalChecked());
} }

View file

@ -1,30 +1,17 @@
EventEmitter = require('events').EventEmitter {deprecate, session, Menu} = require 'electron'
{EventEmitter} = require 'events'
bindings = process.atomBinding 'app' bindings = process.atomBinding 'app'
sessionBindings = process.atomBinding 'session'
downloadItemBindings = process.atomBinding 'download_item' downloadItemBindings = process.atomBinding 'download_item'
app = bindings.app app = bindings.app
app.__proto__ = EventEmitter.prototype app.__proto__ = EventEmitter.prototype
wrapSession = (session) ->
# session is an Event Emitter.
session.__proto__ = EventEmitter.prototype
wrapDownloadItem = (download_item) ->
# download_item is an Event Emitter.
download_item.__proto__ = EventEmitter.prototype
# Be compatible with old APIs.
download_item.url = download_item.getUrl()
download_item.filename = download_item.getFilename()
download_item.mimeType = download_item.getMimeType()
download_item.hasUserGesture = download_item.hasUserGesture()
app.setApplicationMenu = (menu) -> app.setApplicationMenu = (menu) ->
require('menu').setApplicationMenu menu Menu.setApplicationMenu menu
app.getApplicationMenu = -> app.getApplicationMenu = ->
require('menu').getApplicationMenu() Menu.getApplicationMenu()
app.commandLine = app.commandLine =
appendSwitch: bindings.appendSwitch, appendSwitch: bindings.appendSwitch,
@ -47,22 +34,39 @@ app.setAppPath = (path) ->
app.getAppPath = -> app.getAppPath = ->
appPath appPath
# Be compatible with old API. # Routes the events to webContents.
app.once 'ready', -> @emit 'finish-launching' for name in ['login', 'certificate-error', 'select-client-certificate']
app.terminate = app.quit do (name) ->
app.exit = process.exit app.on name, (event, webContents, args...) ->
app.getHomeDir = -> @getPath 'home' webContents.emit name, event, args...
app.getDataPath = -> @getPath 'userData'
app.setDataPath = (path) -> @setPath 'userData', path
app.resolveProxy = -> @defaultSession.resolveProxy.apply @defaultSession, arguments
app.on 'activate', (event, hasVisibleWindows) -> @emit 'activate-with-no-open-windows' if not hasVisibleWindows
# Session wrapper. # Deprecated.
sessionBindings._setWrapSession wrapSession app.getHomeDir = deprecate 'app.getHomeDir', 'app.getPath', ->
process.once 'exit', sessionBindings._clearWrapSession @getPath 'home'
app.getDataPath = deprecate 'app.getDataPath', 'app.getPath', ->
@getPath 'userData'
app.setDataPath = deprecate 'app.setDataPath', 'app.setPath', (path) ->
@setPath 'userData', path
app.resolveProxy = deprecate 'app.resolveProxy', 'session.defaultSession.resolveProxy', (url, callback) ->
session.defaultSession.resolveProxy url, callback
deprecate.rename app, 'terminate', 'quit'
deprecate.event app, 'finish-launching', 'ready', ->
setImmediate => # give default app a chance to setup default menu.
@emit 'finish-launching'
deprecate.event app, 'activate-with-no-open-windows', 'activate', (event, hasVisibleWindows) ->
@emit 'activate-with-no-open-windows', event if not hasVisibleWindows
deprecate.event app, 'select-certificate', 'select-client-certificate'
# Wrappers for native classes.
wrapDownloadItem = (downloadItem) ->
# downloadItem is an EventEmitter.
downloadItem.__proto__ = EventEmitter.prototype
# Deprecated.
deprecate.property downloadItem, 'url', 'getURL'
deprecate.property downloadItem, 'filename', 'getFilename'
deprecate.property downloadItem, 'mimeType', 'getMimeType'
deprecate.rename downloadItem, 'getUrl', 'getURL'
downloadItemBindings._setWrapDownloadItem wrapDownloadItem downloadItemBindings._setWrapDownloadItem wrapDownloadItem
process.once 'exit', downloadItemBindings._clearWrapDownloadItem
# Only one App object pemitted. # Only one App object pemitted.
module.exports = app module.exports = app

View file

@ -1,6 +0,0 @@
module.exports =
browserMainParts:
preMainMessageLoopRun: ->
setImmediate ->
module.exports.browserMainParts.preMainMessageLoopRun()

View file

@ -1,24 +1,12 @@
autoUpdater = process.atomBinding('auto_updater').autoUpdater {deprecate} = require 'electron'
EventEmitter = require('events').EventEmitter
autoUpdater.__proto__ = EventEmitter.prototype autoUpdater =
if process.platform is 'win32'
require './auto-updater/auto-updater-win'
else
require './auto-updater/auto-updater-native'
autoUpdater.on 'update-downloaded-raw', (args...) -> # Deprecated.
args[3] = new Date(args[3]) # releaseDate deprecate.rename autoUpdater, 'setFeedUrl', 'setFeedURL'
@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 module.exports = autoUpdater

View file

@ -0,0 +1,6 @@
{EventEmitter} = require 'events'
{autoUpdater} = process.atomBinding 'auto_updater'
autoUpdater.__proto__ = EventEmitter.prototype
module.exports = autoUpdater

View file

@ -0,0 +1,42 @@
{app} = require 'electron'
{EventEmitter} = require 'events'
url = require 'url'
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

View 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

View file

@ -1,11 +1,12 @@
EventEmitter = require('events').EventEmitter {ipcMain, deprecate} = require 'electron'
app = require 'app' {EventEmitter} = require 'events'
ipc = require 'ipc'
BrowserWindow = process.atomBinding('window').BrowserWindow {BrowserWindow} = process.atomBinding 'window'
BrowserWindow::__proto__ = EventEmitter.prototype BrowserWindow::__proto__ = EventEmitter.prototype
BrowserWindow::_init = -> BrowserWindow::_init = ->
{app} = require 'electron' # avoid recursive require.
# Simulate the application menu on platforms other than OS X. # Simulate the application menu on platforms other than OS X.
if process.platform isnt 'darwin' if process.platform isnt 'darwin'
menu = app.getApplicationMenu() menu = app.getApplicationMenu()
@ -14,7 +15,7 @@ BrowserWindow::_init = ->
# Make new windows requested by links behave like "window.open" # Make new windows requested by links behave like "window.open"
@webContents.on '-new-window', (event, url, frameName) -> @webContents.on '-new-window', (event, url, frameName) ->
options = show: true, width: 800, height: 600 options = show: true, width: 800, height: 600
ipc.emit 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options ipcMain.emit 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options
# window.resizeTo(...) # window.resizeTo(...)
# window.moveTo(...) # window.moveTo(...)
@ -30,6 +31,11 @@ BrowserWindow::_init = ->
@webContents.on 'crashed', => @webContents.on 'crashed', =>
@emit 'crashed' @emit 'crashed'
# Change window title to page title.
@webContents.on 'page-title-updated', (event, title, explicitSet) =>
@emit 'page-title-updated', event, title
@setTitle title unless event.defaultPrevented
# Sometimes the webContents doesn't get focus when window is shown, so we have # Sometimes the webContents doesn't get focus when window is shown, so we have
# to force focusing on webContents in this case. The safest way is to focus it # to force focusing on webContents in this case. The safest way is to focus it
# when we first start to load URL, if we do it earlier it won't have effect, # when we first start to load URL, if we do it earlier it won't have effect,
@ -48,6 +54,15 @@ BrowserWindow::_init = ->
# Notify the creation of the window. # Notify the creation of the window.
app.emit 'browser-window-created', {}, this app.emit 'browser-window-created', {}, this
# Be compatible with old APIs.
@webContents.on 'devtools-focused', => @emit 'devtools-focused'
@webContents.on 'devtools-opened', => @emit 'devtools-opened'
@webContents.on 'devtools-closed', => @emit 'devtools-closed'
Object.defineProperty this, 'devToolsWebContents',
enumerable: true,
configurable: false,
get: -> @webContents.devToolsWebContents
BrowserWindow.getFocusedWindow = -> BrowserWindow.getFocusedWindow = ->
windows = BrowserWindow.getAllWindows() windows = BrowserWindow.getAllWindows()
return window for window in windows when window.isFocused() return window for window in windows when window.isFocused()
@ -61,33 +76,37 @@ BrowserWindow.fromDevToolsWebContents = (webContents) ->
return window for window in windows when window.devToolsWebContents?.equal webContents return window for window in windows when window.devToolsWebContents?.equal webContents
# Helpers. # Helpers.
BrowserWindow::loadUrl = -> @webContents.loadUrl.apply @webContents, arguments BrowserWindow::loadURL = -> @webContents.loadURL.apply @webContents, arguments
BrowserWindow::send = -> @webContents.send.apply @webContents, arguments BrowserWindow::getURL = -> @webContents.getURL()
# Be compatible with old API.
BrowserWindow::undo = -> @webContents.undo()
BrowserWindow::redo = -> @webContents.redo()
BrowserWindow::cut = -> @webContents.cut()
BrowserWindow::copy = -> @webContents.copy()
BrowserWindow::paste = -> @webContents.paste()
BrowserWindow::selectAll = -> @webContents.selectAll()
BrowserWindow::restart = -> @webContents.reload()
BrowserWindow::getUrl = -> @webContents.getUrl()
BrowserWindow::reload = -> @webContents.reload.apply @webContents, arguments BrowserWindow::reload = -> @webContents.reload.apply @webContents, arguments
BrowserWindow::reloadIgnoringCache = -> @webContents.reloadIgnoringCache.apply @webContents, arguments BrowserWindow::send = -> @webContents.send.apply @webContents, arguments
BrowserWindow::getPageTitle = -> @webContents.getTitle()
BrowserWindow::isLoading = -> @webContents.isLoading()
BrowserWindow::isWaitingForResponse = -> @webContents.isWaitingForResponse()
BrowserWindow::stop = -> @webContents.stop()
BrowserWindow::isCrashed = -> @webContents.isCrashed()
BrowserWindow::executeJavaScriptInDevTools = (code) -> @devToolsWebContents?.executeJavaScript code
BrowserWindow::openDevTools = -> @webContents.openDevTools.apply @webContents, arguments BrowserWindow::openDevTools = -> @webContents.openDevTools.apply @webContents, arguments
BrowserWindow::closeDevTools = -> @webContents.closeDevTools() BrowserWindow::closeDevTools = -> @webContents.closeDevTools()
BrowserWindow::isDevToolsOpened = -> @webContents.isDevToolsOpened() BrowserWindow::isDevToolsOpened = -> @webContents.isDevToolsOpened()
BrowserWindow::toggleDevTools = -> @webContents.toggleDevTools() BrowserWindow::toggleDevTools = -> @webContents.toggleDevTools()
BrowserWindow::inspectElement = -> @webContents.inspectElement.apply @webContents, arguments BrowserWindow::inspectElement = -> @webContents.inspectElement.apply @webContents, arguments
BrowserWindow::inspectServiceWorker = -> @webContents.inspectServiceWorker() BrowserWindow::inspectServiceWorker = -> @webContents.inspectServiceWorker()
BrowserWindow::print = -> @webContents.print.apply @webContents, arguments
BrowserWindow::printToPDF = -> @webContents.printToPDF.apply @webContents, arguments # Deprecated.
deprecate.member BrowserWindow, 'undo', 'webContents'
deprecate.member BrowserWindow, 'redo', 'webContents'
deprecate.member BrowserWindow, 'cut', 'webContents'
deprecate.member BrowserWindow, 'copy', 'webContents'
deprecate.member BrowserWindow, 'paste', 'webContents'
deprecate.member BrowserWindow, 'selectAll', 'webContents'
deprecate.member BrowserWindow, 'reloadIgnoringCache', 'webContents'
deprecate.member BrowserWindow, 'isLoading', 'webContents'
deprecate.member BrowserWindow, 'isWaitingForResponse', 'webContents'
deprecate.member BrowserWindow, 'stop', 'webContents'
deprecate.member BrowserWindow, 'isCrashed', 'webContents'
deprecate.member BrowserWindow, 'print', 'webContents'
deprecate.member BrowserWindow, 'printToPDF', 'webContents'
deprecate.rename BrowserWindow, 'restart', 'reload'
deprecate.rename BrowserWindow, 'loadUrl', 'loadURL'
deprecate.rename BrowserWindow, 'getUrl', 'getURL'
BrowserWindow::executeJavaScriptInDevTools = deprecate 'executeJavaScriptInDevTools', 'devToolsWebContents.executeJavaScript', (code) ->
@devToolsWebContents?.executeJavaScript code
BrowserWindow::getPageTitle = deprecate 'getPageTitle', 'webContents.getTitle', ->
@webContents?.getTitle()
module.exports = BrowserWindow module.exports = BrowserWindow

View file

@ -1,7 +1,7 @@
{app, BrowserWindow} = require 'electron'
binding = process.atomBinding 'dialog' binding = process.atomBinding 'dialog'
v8Util = process.atomBinding 'v8_util' v8Util = process.atomBinding 'v8_util'
app = require 'app'
BrowserWindow = require 'browser-window'
fileDialogProperties = fileDialogProperties =
openFile: 1 << 0 openFile: 1 << 0

View file

@ -0,0 +1,55 @@
# Import common modules.
module.exports = require '../../../../common/api/lib/exports/electron'
Object.defineProperties module.exports,
# Browser side modules, please sort with alphabet order.
app:
enumerable: true
get: -> require '../app'
autoUpdater:
enumerable: true
get: -> require '../auto-updater'
BrowserWindow:
enumerable: true
get: -> require '../browser-window'
contentTracing:
enumerable: true
get: -> require '../content-tracing'
dialog:
enumerable: true
get: -> require '../dialog'
ipcMain:
enumerable: true
get: -> require '../ipc-main'
globalShortcut:
enumerable: true
get: -> require '../global-shortcut'
Menu:
enumerable: true
get: -> require '../menu'
MenuItem:
enumerable: true
get: -> require '../menu-item'
powerMonitor:
enumerable: true
get: -> require '../power-monitor'
powerSaveBlocker:
enumerable: true
get: -> require '../power-save-blocker'
protocol:
enumerable: true
get: -> require '../protocol'
screen:
enumerable: true
get: -> require '../screen'
session:
enumerable: true
get: -> require '../session'
Tray:
enumerable: true
get: -> require '../tray'
# The internal modules, invisible unless you know their names.
NavigationController:
get: -> require '../navigation-controller'
webContents:
get: -> require '../web-contents'

View file

@ -1,5 +1,3 @@
bindings = process.atomBinding 'global_shortcut' {globalShortcut} = process.atomBinding 'global_shortcut'
globalShortcut = bindings.globalShortcut
module.exports = globalShortcut module.exports = globalShortcut

View file

@ -0,0 +1,3 @@
{EventEmitter} = require 'events'
module.exports = new EventEmitter

View file

@ -1,3 +1,6 @@
EventEmitter = require('events').EventEmitter {deprecate, ipcMain} = require 'electron'
module.exports = new EventEmitter # This module is deprecated, we mirror everything from ipcMain.
deprecate.warn 'ipc module', 'require("electron").ipcMain'
module.exports = ipcMain

View file

@ -1,4 +1,3 @@
BrowserWindow = require 'browser-window'
v8Util = process.atomBinding 'v8_util' v8Util = process.atomBinding 'v8_util'
nextCommandId = 0 nextCommandId = 0
@ -14,11 +13,16 @@ rolesMap =
minimize: 'minimize' minimize: 'minimize'
close: 'close' close: 'close'
# Maps methods that should be called directly on the BrowserWindow instance
methodInBrowserWindow =
minimize: true
close: true
class MenuItem class MenuItem
@types = ['normal', 'separator', 'submenu', 'checkbox', 'radio'] @types = ['normal', 'separator', 'submenu', 'checkbox', 'radio']
constructor: (options) -> constructor: (options) ->
Menu = require 'menu' {Menu} = require 'electron'
{click, @selector, @type, @role, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked, @submenu} = options {click, @selector, @type, @role, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked, @submenu} = options
@ -43,8 +47,12 @@ class MenuItem
# Manually flip the checked flags when clicked. # Manually flip the checked flags when clicked.
@checked = !@checked if @type in ['checkbox', 'radio'] @checked = !@checked if @type in ['checkbox', 'radio']
if @role and rolesMap[@role] and process.platform isnt 'darwin' if @role and rolesMap[@role] and process.platform isnt 'darwin' and focusedWindow?
focusedWindow?[rolesMap[@role]]() methodName = rolesMap[@role]
if methodInBrowserWindow[methodName]
focusedWindow[methodName]()
else
focusedWindow.webContents?[methodName]()
else if typeof click is 'function' else if typeof click is 'function'
click this, focusedWindow click this, focusedWindow
else if typeof @selector is 'string' else if typeof @selector is 'string'

View file

@ -1,8 +1,7 @@
BrowserWindow = require 'browser-window' {BrowserWindow, MenuItem} = require 'electron'
EventEmitter = require('events').EventEmitter {EventEmitter} = require 'events'
MenuItem = require 'menu-item'
v8Util = process.atomBinding 'v8_util'
v8Util = process.atomBinding 'v8_util'
bindings = process.atomBinding 'menu' bindings = process.atomBinding 'menu'
# Automatically generated radio menu item's group id. # Automatically generated radio menu item's group id.
@ -79,7 +78,11 @@ Menu::_init = ->
v8Util.setHiddenValue group[0], 'checked', true unless checked v8Util.setHiddenValue group[0], 'checked', true unless checked
Menu::popup = (window, x, y) -> Menu::popup = (window, x, y) ->
throw new TypeError('Invalid window') unless window?.constructor is BrowserWindow unless window?.constructor is BrowserWindow
# Shift.
y = x
x = window
window = BrowserWindow.getFocusedWindow()
if x? and y? if x? and y?
@_popupAt(window, x, y) @_popupAt(window, x, y)
else else

View file

@ -1,15 +1,15 @@
ipc = require 'ipc' {ipcMain} = require 'electron'
# The history operation in renderer is redirected to browser. # The history operation in renderer is redirected to browser.
ipc.on 'ATOM_SHELL_NAVIGATION_CONTROLLER', (event, method, args...) -> ipcMain.on 'ATOM_SHELL_NAVIGATION_CONTROLLER', (event, method, args...) ->
event.sender[method] args... event.sender[method] args...
ipc.on 'ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', (event, method, args...) -> ipcMain.on 'ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', (event, method, args...) ->
event.returnValue = event.sender[method] args... event.returnValue = event.sender[method] args...
# JavaScript implementation of Chromium's NavigationController. # JavaScript implementation of Chromium's NavigationController.
# Instead of relying on Chromium for history control, we compeletely do history # Instead of relying on Chromium for history control, we compeletely do history
# control on user land, and only rely on WebContents.loadUrl for navigation. # control on user land, and only rely on WebContents.loadURL for navigation.
# This helps us avoid Chromium's various optimizations so we can ensure renderer # This helps us avoid Chromium's various optimizations so we can ensure renderer
# process is restarted everytime. # process is restarted everytime.
class NavigationController class NavigationController
@ -17,9 +17,9 @@ class NavigationController
@clearHistory() @clearHistory()
# webContents may have already navigated to a page. # webContents may have already navigated to a page.
if @webContents._getUrl() if @webContents._getURL()
@currentIndex++ @currentIndex++
@history.push @webContents._getUrl() @history.push @webContents._getURL()
@webContents.on 'navigation-entry-commited', (event, url, inPage, replaceEntry) => @webContents.on 'navigation-entry-commited', (event, url, inPage, replaceEntry) =>
if @inPageIndex > -1 and not inPage if @inPageIndex > -1 and not inPage
@ -42,12 +42,12 @@ class NavigationController
@currentIndex++ @currentIndex++
@history.push url @history.push url
loadUrl: (url, options={}) -> loadURL: (url, options={}) ->
@pendingIndex = -1 @pendingIndex = -1
@webContents._loadUrl url, options @webContents._loadURL url, options
@webContents.emit 'load-url', url, options @webContents.emit 'load-url', url, options
getUrl: -> getURL: ->
if @currentIndex is -1 if @currentIndex is -1
'' ''
else else
@ -59,11 +59,11 @@ class NavigationController
reload: -> reload: ->
@pendingIndex = @currentIndex @pendingIndex = @currentIndex
@webContents._loadUrl @getUrl(), {} @webContents._loadURL @getURL(), {}
reloadIgnoringCache: -> reloadIgnoringCache: ->
@webContents._reloadIgnoringCache() # Rely on WebContents to clear cache. @pendingIndex = @currentIndex
@reload() @webContents._loadURL @getURL(), {extraHeaders: "pragma: no-cache\n"}
canGoBack: -> canGoBack: ->
@getActiveIndex() > 0 @getActiveIndex() > 0
@ -89,7 +89,7 @@ class NavigationController
if @inPageIndex > -1 and @pendingIndex >= @inPageIndex if @inPageIndex > -1 and @pendingIndex >= @inPageIndex
@webContents._goBack() @webContents._goBack()
else else
@webContents._loadUrl @history[@pendingIndex], {} @webContents._loadURL @history[@pendingIndex], {}
goForward: -> goForward: ->
return unless @canGoForward() return unless @canGoForward()
@ -97,12 +97,12 @@ class NavigationController
if @inPageIndex > -1 and @pendingIndex >= @inPageIndex if @inPageIndex > -1 and @pendingIndex >= @inPageIndex
@webContents._goForward() @webContents._goForward()
else else
@webContents._loadUrl @history[@pendingIndex], {} @webContents._loadURL @history[@pendingIndex], {}
goToIndex: (index) -> goToIndex: (index) ->
return unless @canGoToIndex index return unless @canGoToIndex index
@pendingIndex = index @pendingIndex = index
@webContents._loadUrl @history[@pendingIndex], {} @webContents._loadURL @history[@pendingIndex], {}
goToOffset: (offset) -> goToOffset: (offset) ->
return unless @canGoToOffset offset return unless @canGoToOffset offset

View file

@ -1,5 +1,6 @@
powerMonitor = process.atomBinding('power_monitor').powerMonitor {EventEmitter} = require 'events'
EventEmitter = require('events').EventEmitter
{powerMonitor} = process.atomBinding 'power_monitor'
powerMonitor.__proto__ = EventEmitter.prototype powerMonitor.__proto__ = EventEmitter.prototype

View file

@ -1,3 +1,3 @@
bindings = process.atomBinding 'power_save_blocker' {powerSaveBlocker} = process.atomBinding 'power_save_blocker'
module.exports = bindings.powerSaveBlocker module.exports = powerSaveBlocker

View file

@ -1,7 +1,8 @@
app = require 'app' {app} = require 'electron'
throw new Error('Can not initialize protocol module before app is ready') unless app.isReady() throw new Error('Can not initialize protocol module before app is ready') unless app.isReady()
protocol = process.atomBinding('protocol').protocol {protocol} = process.atomBinding 'protocol'
# Warn about removed APIs. # Warn about removed APIs.
logAndThrow = (callback, message) -> logAndThrow = (callback, message) ->

View file

@ -1,6 +1,6 @@
EventEmitter = require('events').EventEmitter {EventEmitter} = require 'events'
{screen} = process.atomBinding 'screen'
screen = process.atomBinding('screen').screen
screen.__proto__ = EventEmitter.prototype screen.__proto__ = EventEmitter.prototype
module.exports = screen module.exports = screen

View file

@ -0,0 +1,23 @@
{EventEmitter} = require 'events'
bindings = process.atomBinding 'session'
PERSIST_PERFIX = 'persist:'
# Returns the Session from |partition| string.
exports.fromPartition = (partition='') ->
if partition.startsWith PERSIST_PERFIX
bindings.fromPartition partition.substr(PERSIST_PERFIX.length), false
else
bindings.fromPartition partition, true
# Returns the default session.
Object.defineProperty exports, 'defaultSession',
enumerable: true
get: -> exports.fromPartition ''
wrapSession = (session) ->
# session is an EventEmitter.
session.__proto__ = EventEmitter.prototype
bindings._setWrapSession wrapSession

View file

@ -1,14 +1,19 @@
EventEmitter = require('events').EventEmitter {deprecate} = require 'electron'
bindings = process.atomBinding 'tray' {EventEmitter} = require 'events'
Tray = bindings.Tray {Tray} = process.atomBinding 'tray'
Tray::__proto__ = EventEmitter.prototype Tray::__proto__ = EventEmitter.prototype
Tray::_init = ->
# Deprecated.
deprecate.rename this, 'popContextMenu', 'popUpContextMenu'
deprecate.event this, 'clicked', 'click'
deprecate.event this, 'double-clicked', 'double-click'
deprecate.event this, 'right-clicked', 'right-click'
deprecate.event this, 'balloon-clicked', 'balloon-click'
Tray::setContextMenu = (menu) -> Tray::setContextMenu = (menu) ->
@_setContextMenu menu @_setContextMenu menu
@menu = menu # Keep a strong reference of menu. @menu = menu # Keep a strong reference of menu.
# Keep compatibility with old APIs.
Tray::popContextMenu = Tray::popUpContextMenu
module.exports = Tray module.exports = Tray

View file

@ -1,7 +1,7 @@
EventEmitter = require('events').EventEmitter {EventEmitter} = require 'events'
NavigationController = require './navigation-controller' {deprecate, ipcMain, session, NavigationController, Menu} = require 'electron'
binding = process.atomBinding 'web_contents' binding = process.atomBinding 'web_contents'
ipc = require 'ipc'
nextId = 0 nextId = 0
getNextId = -> ++nextId getNextId = -> ++nextId
@ -45,7 +45,7 @@ wrapWebContents = (webContents) ->
# Make sure webContents.executeJavaScript would run the code only when the # Make sure webContents.executeJavaScript would run the code only when the
# web contents has been loaded. # web contents has been loaded.
webContents.executeJavaScript = (code, hasUserGesture=false) -> webContents.executeJavaScript = (code, hasUserGesture=false) ->
if @getUrl() and not @isLoading() if @getURL() and not @isLoading()
@_executeJavaScript code, hasUserGesture @_executeJavaScript code, hasUserGesture
else else
webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code, hasUserGesture) webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code, hasUserGesture)
@ -59,11 +59,32 @@ wrapWebContents = (webContents) ->
# Dispatch IPC messages to the ipc module. # Dispatch IPC messages to the ipc module.
webContents.on 'ipc-message', (event, packed) -> webContents.on 'ipc-message', (event, packed) ->
[channel, args...] = packed [channel, args...] = packed
ipc.emit channel, event, args... ipcMain.emit channel, event, args...
webContents.on 'ipc-message-sync', (event, packed) -> webContents.on 'ipc-message-sync', (event, packed) ->
[channel, args...] = packed [channel, args...] = packed
Object.defineProperty event, 'returnValue', set: (value) -> event.sendReply JSON.stringify(value) Object.defineProperty event, 'returnValue', set: (value) -> event.sendReply JSON.stringify(value)
ipc.emit channel, event, args... ipcMain.emit channel, event, args...
# Handle context menu action request from pepper plugin.
webContents.on 'pepper-context-menu', (event, params) ->
menu = Menu.buildFromTemplate params.menu
menu.popup params.x, params.y
# This error occurs when host could not be found.
webContents.on 'did-fail-provisional-load', (args...) ->
# Calling loadURL during this event might cause crash, so delay the event
# until next tick.
setImmediate => @emit 'did-fail-load', args...
# Delays the page-title-updated event to next tick.
webContents.on '-page-title-updated', (args...) ->
setImmediate => @emit 'page-title-updated', args...
# Deprecated.
deprecate.rename webContents, 'loadUrl', 'loadURL'
deprecate.rename webContents, 'getUrl', 'getURL'
deprecate.event webContents, 'page-title-set', 'page-title-updated', (args...) ->
@emit 'page-title-set', args...
webContents.printToPDF = (options, callback) -> webContents.printToPDF = (options, callback) ->
printingSetting = printingSetting =
@ -106,7 +127,6 @@ wrapWebContents = (webContents) ->
@_printToPDF printingSetting, callback @_printToPDF printingSetting, callback
binding._setWrapWebContents wrapWebContents binding._setWrapWebContents wrapWebContents
process.once 'exit', binding._clearWrapWebContents
module.exports.create = (options={}) -> module.exports.create = (options={}) ->
binding.create(options) binding.create(options)

View 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

View 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_

View file

@ -30,11 +30,11 @@ class IDUserData : public base::SupportsUserData::Data {
TrackableObjectBase::TrackableObjectBase() TrackableObjectBase::TrackableObjectBase()
: weak_map_id_(0), wrapped_(nullptr), weak_factory_(this) { : weak_map_id_(0), wrapped_(nullptr), weak_factory_(this) {
RegisterDestructionCallback( cleanup_ = RegisterDestructionCallback(GetDestroyClosure());
base::Bind(&TrackableObjectBase::Destroy, weak_factory_.GetWeakPtr()));
} }
TrackableObjectBase::~TrackableObjectBase() { TrackableObjectBase::~TrackableObjectBase() {
cleanup_.Run();
} }
void TrackableObjectBase::AfterInit(v8::Isolate* isolate) { void TrackableObjectBase::AfterInit(v8::Isolate* isolate) {
@ -42,6 +42,18 @@ void TrackableObjectBase::AfterInit(v8::Isolate* isolate) {
AttachAsUserData(wrapped_); AttachAsUserData(wrapped_);
} }
void TrackableObjectBase::MarkDestroyed() {
GetWrapper(isolate())->SetAlignedPointerInInternalField(0, nullptr);
}
base::Closure TrackableObjectBase::GetDestroyClosure() {
return base::Bind(&TrackableObjectBase::Destroy, weak_factory_.GetWeakPtr());
}
void TrackableObjectBase::Destroy() {
delete this;
}
void TrackableObjectBase::AttachAsUserData(base::SupportsUserData* wrapped) { void TrackableObjectBase::AttachAsUserData(base::SupportsUserData* wrapped) {
if (weak_map_id_ != 0) { if (weak_map_id_ != 0) {
wrapped->SetUserData(kTrackedObjectKey, new IDUserData(weak_map_id_)); wrapped->SetUserData(kTrackedObjectKey, new IDUserData(weak_map_id_));
@ -63,9 +75,9 @@ int32_t TrackableObjectBase::GetIDFromWrappedClass(base::SupportsUserData* w) {
} }
// static // static
void TrackableObjectBase::RegisterDestructionCallback( base::Closure TrackableObjectBase::RegisterDestructionCallback(
const base::Closure& closure) { const base::Closure& c) {
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(closure); return atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(c);
} }
} // namespace mate } // namespace mate

View file

@ -12,6 +12,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "native_mate/object_template_builder.h"
namespace base { namespace base {
class SupportsUserData; class SupportsUserData;
@ -30,26 +31,32 @@ class TrackableObjectBase : public mate::EventEmitter {
// Wrap TrackableObject into a class that SupportsUserData. // Wrap TrackableObject into a class that SupportsUserData.
void AttachAsUserData(base::SupportsUserData* wrapped); void AttachAsUserData(base::SupportsUserData* wrapped);
// Subclasses should implement this to destroy their native types.
virtual void Destroy() = 0;
protected: protected:
~TrackableObjectBase() override; ~TrackableObjectBase() override;
// mate::Wrappable: // mate::Wrappable:
void AfterInit(v8::Isolate* isolate) override; void AfterInit(v8::Isolate* isolate) override;
// Mark the JS object as destroyed.
void MarkDestroyed();
// Returns a closure that can destroy the native class.
base::Closure GetDestroyClosure();
// Get the weak_map_id from SupportsUserData. // Get the weak_map_id from SupportsUserData.
static int32_t GetIDFromWrappedClass(base::SupportsUserData* wrapped); static int32_t GetIDFromWrappedClass(base::SupportsUserData* wrapped);
// Register a callback that should be destroyed before JavaScript environment // Register a callback that should be destroyed before JavaScript environment
// gets destroyed. // gets destroyed.
static void RegisterDestructionCallback(const base::Closure& closure); static base::Closure RegisterDestructionCallback(const base::Closure& c);
int32_t weak_map_id_; int32_t weak_map_id_;
base::SupportsUserData* wrapped_; base::SupportsUserData* wrapped_;
private: private:
void Destroy();
base::Closure cleanup_;
base::WeakPtrFactory<TrackableObjectBase> weak_factory_; base::WeakPtrFactory<TrackableObjectBase> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(TrackableObjectBase); DISALLOW_COPY_AND_ASSIGN(TrackableObjectBase);
@ -91,11 +98,6 @@ class TrackableObject : public TrackableObjectBase {
return std::vector<v8::Local<v8::Object>>(); return std::vector<v8::Local<v8::Object>>();
} }
TrackableObject() {
RegisterDestructionCallback(
base::Bind(&TrackableObject<T>::ReleaseAllWeakReferences));
}
// Removes this instance from the weak map. // Removes this instance from the weak map.
void RemoveFromWeakMap() { void RemoveFromWeakMap() {
if (weak_map_ && weak_map_->Has(weak_map_id())) if (weak_map_ && weak_map_->Has(weak_map_id()))
@ -103,28 +105,49 @@ class TrackableObject : public TrackableObjectBase {
} }
protected: protected:
TrackableObject() {}
~TrackableObject() override { ~TrackableObject() override {
RemoveFromWeakMap(); RemoveFromWeakMap();
} }
void AfterInit(v8::Isolate* isolate) override { void AfterInit(v8::Isolate* isolate) override {
if (!weak_map_) if (!weak_map_) {
weak_map_.reset(new atom::IDWeakMap); weak_map_.reset(new atom::IDWeakMap);
RegisterDestructionCallback(
base::Bind(&TrackableObject<T>::ReleaseAllWeakReferences));
}
weak_map_id_ = weak_map_->Add(isolate, GetWrapper(isolate)); weak_map_id_ = weak_map_->Add(isolate, GetWrapper(isolate));
TrackableObjectBase::AfterInit(isolate); TrackableObjectBase::AfterInit(isolate);
} }
private: private:
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override {
if (template_.IsEmpty()) {
auto templ = v8::ObjectTemplate::New(isolate);
T::BuildPrototype(isolate, templ);
template_.Reset(isolate, templ);
}
return ObjectTemplateBuilder(
isolate, v8::Local<v8::ObjectTemplate>::New(isolate, template_));
}
// Releases all weak references in weak map, called when app is terminating. // Releases all weak references in weak map, called when app is terminating.
static void ReleaseAllWeakReferences() { static void ReleaseAllWeakReferences() {
weak_map_.reset(); weak_map_.reset();
} }
static v8::Persistent<v8::ObjectTemplate> template_;
static scoped_ptr<atom::IDWeakMap> weak_map_; static scoped_ptr<atom::IDWeakMap> weak_map_;
DISALLOW_COPY_AND_ASSIGN(TrackableObject); DISALLOW_COPY_AND_ASSIGN(TrackableObject);
}; };
template<typename T>
v8::Persistent<v8::ObjectTemplate> TrackableObject<T>::template_;
template<typename T> template<typename T>
scoped_ptr<atom::IDWeakMap> TrackableObject<T>::weak_map_; scoped_ptr<atom::IDWeakMap> TrackableObject<T>::weak_map_;

View file

@ -18,7 +18,7 @@ namespace {
// Notice that we just combined the api key with the url together here, because // Notice that we just combined the api key with the url together here, because
// if we use the standard {url: key} format Chromium would override our key with // if we use the standard {url: key} format Chromium would override our key with
// the predefined one in common.gypi of libchromiumcontent, which is empty. // the predefined one in common.gypi of libchromiumcontent, which is empty.
const char* kGeolocationProviderUrl = const char* kGeolocationProviderURL =
"https://www.googleapis.com/geolocation/v1/geolocate?key=" "https://www.googleapis.com/geolocation/v1/geolocate?key="
GOOGLEAPIS_API_KEY; GOOGLEAPIS_API_KEY;
@ -35,11 +35,11 @@ void AtomAccessTokenStore::LoadAccessTokens(
const LoadAccessTokensCallbackType& callback) { const LoadAccessTokensCallbackType& callback) {
AccessTokenSet access_token_set; AccessTokenSet access_token_set;
// Equivelent to access_token_set[kGeolocationProviderUrl]. // Equivelent to access_token_set[kGeolocationProviderURL].
// Somehow base::string16 is causing compilation errors when used in a pair // Somehow base::string16 is causing compilation errors when used in a pair
// of std::map on Linux, this can work around it. // of std::map on Linux, this can work around it.
std::pair<GURL, base::string16> token_pair; std::pair<GURL, base::string16> token_pair;
token_pair.first = GURL(kGeolocationProviderUrl); token_pair.first = GURL(kGeolocationProviderURL);
access_token_set.insert(token_pair); access_token_set.insert(token_pair);
auto browser_context = AtomBrowserMainParts::Get()->browser_context(); auto browser_context = AtomBrowserMainParts::Get()->browser_context();

View file

@ -12,8 +12,8 @@
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/atom_quota_permission_context.h" #include "atom/browser/atom_quota_permission_context.h"
#include "atom/browser/atom_resource_dispatcher_host_delegate.h"
#include "atom/browser/atom_speech_recognition_manager_delegate.h" #include "atom/browser/atom_speech_recognition_manager_delegate.h"
#include "atom/browser/browser.h"
#include "atom/browser/native_window.h" #include "atom/browser/native_window.h"
#include "atom/browser/web_contents_preferences.h" #include "atom/browser/web_contents_preferences.h"
#include "atom/browser/window_list.h" #include "atom/browser/window_list.h"
@ -30,6 +30,7 @@
#include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/site_instance.h" #include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/common/web_preferences.h" #include "content/public/common/web_preferences.h"
@ -83,10 +84,10 @@ void AtomBrowserClient::SuppressRendererProcessRestartForOnce() {
void AtomBrowserClient::SetCustomSchemes( void AtomBrowserClient::SetCustomSchemes(
const std::vector<std::string>& schemes) { const std::vector<std::string>& schemes) {
g_custom_schemes = JoinString(schemes, ','); g_custom_schemes = base::JoinString(schemes, ",");
} }
AtomBrowserClient::AtomBrowserClient() { AtomBrowserClient::AtomBrowserClient() : delegate_(nullptr) {
} }
AtomBrowserClient::~AtomBrowserClient() { AtomBrowserClient::~AtomBrowserClient() {
@ -115,7 +116,6 @@ void AtomBrowserClient::OverrideWebkitPrefs(
prefs->javascript_can_open_windows_automatically = true; prefs->javascript_can_open_windows_automatically = true;
prefs->plugins_enabled = true; prefs->plugins_enabled = true;
prefs->dom_paste_enabled = true; prefs->dom_paste_enabled = true;
prefs->java_enabled = false;
prefs->allow_scripts_to_close_windows = true; prefs->allow_scripts_to_close_windows = true;
prefs->javascript_can_access_clipboard = true; prefs->javascript_can_access_clipboard = true;
prefs->local_storage_enabled = true; prefs->local_storage_enabled = true;
@ -206,6 +206,26 @@ content::QuotaPermissionContext*
return new AtomQuotaPermissionContext; return new AtomQuotaPermissionContext;
} }
void AtomBrowserClient::AllowCertificateError(
int render_process_id,
int render_frame_id,
int cert_error,
const net::SSLInfo& ssl_info,
const GURL& request_url,
content::ResourceType resource_type,
bool overridable,
bool strict_enforcement,
bool expired_previous_decision,
const base::Callback<void(bool)>& callback,
content::CertificateRequestResultType* request) {
if (delegate_) {
delegate_->AllowCertificateError(
render_process_id, render_frame_id, cert_error, ssl_info, request_url,
resource_type, overridable, strict_enforcement,
expired_previous_decision, callback, request);
}
}
void AtomBrowserClient::SelectClientCertificate( void AtomBrowserClient::SelectClientCertificate(
content::WebContents* web_contents, content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info, net::SSLCertRequestInfo* cert_request_info,
@ -220,10 +240,17 @@ void AtomBrowserClient::SelectClientCertificate(
return; return;
} }
if (!cert_request_info->client_certs.empty()) if (!cert_request_info->client_certs.empty() && delegate_) {
Browser::Get()->ClientCertificateSelector(web_contents, delegate_->SelectClientCertificate(
cert_request_info, web_contents, cert_request_info, delegate.Pass());
delegate.Pass()); }
}
void AtomBrowserClient::ResourceDispatcherHostCreated() {
resource_dispatcher_host_delegate_.reset(
new AtomResourceDispatcherHostDelegate);
content::ResourceDispatcherHost::Get()->SetDelegate(
resource_dispatcher_host_delegate_.get());
} }
brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts( brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts(

View file

@ -23,12 +23,17 @@ class SSLCertRequestInfo;
namespace atom { namespace atom {
class AtomResourceDispatcherHostDelegate;
class AtomBrowserClient : public brightray::BrowserClient, class AtomBrowserClient : public brightray::BrowserClient,
public content::RenderProcessHostObserver { public content::RenderProcessHostObserver {
public: public:
AtomBrowserClient(); AtomBrowserClient();
virtual ~AtomBrowserClient(); virtual ~AtomBrowserClient();
using Delegate = content::ContentBrowserClient;
void set_delegate(Delegate* delegate) { delegate_ = delegate; }
// Don't force renderer process to restart for once. // Don't force renderer process to restart for once.
static void SuppressRendererProcessRestartForOnce(); static void SuppressRendererProcessRestartForOnce();
// Custom schemes to be registered to standard. // Custom schemes to be registered to standard.
@ -52,10 +57,23 @@ class AtomBrowserClient : public brightray::BrowserClient,
int child_process_id) override; int child_process_id) override;
void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override; void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override;
content::QuotaPermissionContext* CreateQuotaPermissionContext() override; content::QuotaPermissionContext* CreateQuotaPermissionContext() override;
void AllowCertificateError(
int render_process_id,
int render_frame_id,
int cert_error,
const net::SSLInfo& ssl_info,
const GURL& request_url,
content::ResourceType resource_type,
bool overridable,
bool strict_enforcement,
bool expired_previous_decision,
const base::Callback<void(bool)>& callback,
content::CertificateRequestResultType* request) override;
void SelectClientCertificate( void SelectClientCertificate(
content::WebContents* web_contents, content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info, net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) override; scoped_ptr<content::ClientCertificateDelegate> delegate) override;
void ResourceDispatcherHostCreated() override;
// brightray::BrowserClient: // brightray::BrowserClient:
brightray::BrowserMainParts* OverrideCreateBrowserMainParts( brightray::BrowserMainParts* OverrideCreateBrowserMainParts(
@ -68,6 +86,11 @@ class AtomBrowserClient : public brightray::BrowserClient,
// pending_render_process => current_render_process. // pending_render_process => current_render_process.
std::map<int, int> pending_processes_; std::map<int, int> pending_processes_;
scoped_ptr<AtomResourceDispatcherHostDelegate>
resource_dispatcher_host_delegate_;
Delegate* delegate_;
DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient); DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient);
}; };

View file

@ -6,8 +6,9 @@
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/atom_download_manager_delegate.h" #include "atom/browser/atom_download_manager_delegate.h"
#include "atom/browser/atom_ssl_config_service.h"
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/net/atom_cert_verifier.h"
#include "atom/browser/net/atom_ssl_config_service.h"
#include "atom/browser/net/atom_url_request_job_factory.h" #include "atom/browser/net/atom_url_request_job_factory.h"
#include "atom/browser/net/asar/asar_protocol_handler.h" #include "atom/browser/net/asar/asar_protocol_handler.h"
#include "atom/browser/net/http_protocol_handler.h" #include "atom/browser/net/http_protocol_handler.h"
@ -60,7 +61,9 @@ std::string RemoveWhitespace(const std::string& str) {
AtomBrowserContext::AtomBrowserContext(const std::string& partition, AtomBrowserContext::AtomBrowserContext(const std::string& partition,
bool in_memory) bool in_memory)
: brightray::BrowserContext(partition, in_memory), : brightray::BrowserContext(partition, in_memory),
job_factory_(new AtomURLRequestJobFactory) { cert_verifier_(nullptr),
job_factory_(new AtomURLRequestJobFactory),
allow_ntlm_everywhere_(false) {
} }
AtomBrowserContext::~AtomBrowserContext() { AtomBrowserContext::~AtomBrowserContext() {
@ -83,7 +86,8 @@ std::string AtomBrowserContext::GetUserAgent() {
return content::BuildUserAgentFromProduct(user_agent); return content::BuildUserAgentFromProduct(user_agent);
} }
net::URLRequestJobFactory* AtomBrowserContext::CreateURLRequestJobFactory( scoped_ptr<net::URLRequestJobFactory>
AtomBrowserContext::CreateURLRequestJobFactory(
content::ProtocolHandlerMap* handlers, content::ProtocolHandlerMap* handlers,
content::URLRequestInterceptorScopedVector* interceptors) { content::URLRequestInterceptorScopedVector* interceptors) {
scoped_ptr<AtomURLRequestJobFactory> job_factory(job_factory_); scoped_ptr<AtomURLRequestJobFactory> job_factory(job_factory_);
@ -128,7 +132,7 @@ net::URLRequestJobFactory* AtomBrowserContext::CreateURLRequestJobFactory(
top_job_factory.Pass(), make_scoped_ptr(*it))); top_job_factory.Pass(), make_scoped_ptr(*it)));
interceptors->weak_clear(); interceptors->weak_clear();
return top_job_factory.release(); return top_job_factory.Pass();
} }
net::HttpCache::BackendFactory* net::HttpCache::BackendFactory*
@ -157,6 +161,12 @@ content::BrowserPluginGuestManager* AtomBrowserContext::GetGuestManager() {
return guest_manager_.get(); return guest_manager_.get();
} }
scoped_ptr<net::CertVerifier> AtomBrowserContext::CreateCertVerifier() {
DCHECK(!cert_verifier_);
cert_verifier_ = new AtomCertVerifier;
return make_scoped_ptr(cert_verifier_);
}
net::SSLConfigService* AtomBrowserContext::CreateSSLConfigService() { net::SSLConfigService* AtomBrowserContext::CreateSSLConfigService() {
return new AtomSSLConfigService; return new AtomSSLConfigService;
} }
@ -168,6 +178,16 @@ void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
base::FilePath()); 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 atom
namespace brightray { namespace brightray {

View file

@ -12,6 +12,7 @@
namespace atom { namespace atom {
class AtomDownloadManagerDelegate; class AtomDownloadManagerDelegate;
class AtomCertVerifier;
class AtomURLRequestJobFactory; class AtomURLRequestJobFactory;
class WebViewManager; class WebViewManager;
@ -22,12 +23,14 @@ class AtomBrowserContext : public brightray::BrowserContext {
// brightray::URLRequestContextGetter::Delegate: // brightray::URLRequestContextGetter::Delegate:
std::string GetUserAgent() override; std::string GetUserAgent() override;
net::URLRequestJobFactory* CreateURLRequestJobFactory( scoped_ptr<net::URLRequestJobFactory> CreateURLRequestJobFactory(
content::ProtocolHandlerMap* handlers, content::ProtocolHandlerMap* handlers,
content::URLRequestInterceptorScopedVector* interceptors) override; content::URLRequestInterceptorScopedVector* interceptors) override;
net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory( net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory(
const base::FilePath& base_path) override; const base::FilePath& base_path) override;
scoped_ptr<net::CertVerifier> CreateCertVerifier() override;
net::SSLConfigService* CreateSSLConfigService() override; net::SSLConfigService* CreateSSLConfigService() override;
bool AllowNTLMCredentialsForDomain(const GURL& auth_origin) override;
// content::BrowserContext: // content::BrowserContext:
content::DownloadManagerDelegate* GetDownloadManagerDelegate() override; content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
@ -36,6 +39,10 @@ class AtomBrowserContext : public brightray::BrowserContext {
// brightray::BrowserContext: // brightray::BrowserContext:
void RegisterPrefs(PrefRegistrySimple* pref_registry) override; void RegisterPrefs(PrefRegistrySimple* pref_registry) override;
void AllowNTLMCredentialsForAllDomains(bool should_allow);
AtomCertVerifier* cert_verifier() const { return cert_verifier_; }
AtomURLRequestJobFactory* job_factory() const { return job_factory_; } AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
private: private:
@ -43,8 +50,11 @@ class AtomBrowserContext : public brightray::BrowserContext {
scoped_ptr<WebViewManager> guest_manager_; scoped_ptr<WebViewManager> guest_manager_;
// Managed by brightray::BrowserContext. // Managed by brightray::BrowserContext.
AtomCertVerifier* cert_verifier_;
AtomURLRequestJobFactory* job_factory_; AtomURLRequestJobFactory* job_factory_;
bool allow_ntlm_everywhere_;
DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext); DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext);
}; };

View file

@ -25,11 +25,17 @@
namespace atom { namespace atom {
template<typename T>
void Erase(T* container, typename T::iterator iter) {
container->erase(iter);
}
// static // static
AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL; AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
AtomBrowserMainParts::AtomBrowserMainParts() AtomBrowserMainParts::AtomBrowserMainParts()
: fake_browser_process_(new BrowserProcess), : fake_browser_process_(new BrowserProcess),
exit_code_(nullptr),
browser_(new Browser), browser_(new Browser),
node_bindings_(NodeBindings::Create(true)), node_bindings_(NodeBindings::Create(true)),
atom_bindings_(new AtomBindings), atom_bindings_(new AtomBindings),
@ -47,29 +53,39 @@ AtomBrowserMainParts* AtomBrowserMainParts::Get() {
return self_; return self_;
} }
void AtomBrowserMainParts::RegisterDestructionCallback( bool AtomBrowserMainParts::SetExitCode(int code) {
if (!exit_code_)
return false;
*exit_code_ = code;
return true;
}
base::Closure AtomBrowserMainParts::RegisterDestructionCallback(
const base::Closure& callback) { const base::Closure& callback) {
destruction_callbacks_.push_back(callback); auto iter = destructors_.insert(destructors_.end(), callback);
return base::Bind(&Erase<std::list<base::Closure>>, &destructors_, iter);
}
void AtomBrowserMainParts::PreEarlyInitialization() {
brightray::BrowserMainParts::PreEarlyInitialization();
#if defined(OS_POSIX)
HandleSIGCHLD();
#endif
} }
void AtomBrowserMainParts::PostEarlyInitialization() { void AtomBrowserMainParts::PostEarlyInitialization() {
brightray::BrowserMainParts::PostEarlyInitialization(); brightray::BrowserMainParts::PostEarlyInitialization();
#if defined(USE_X11) // Temporary set the bridge_task_runner_ as current thread's task runner,
SetDPIFromGSettings(); // so we can fool gin::PerIsolateData to use it as its task runner, instead
#endif // 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
// Temporary set the bridge_task_runner_ as current thread's task runner, // avoid conflicts we only initialize our V8 environment after that.
// so we can fool gin::PerIsolateData to use it as its task runner, instead js_env_.reset(new JavascriptEnvironment);
// 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);
}
node_bindings_->Initialize(); node_bindings_->Initialize();
@ -104,6 +120,8 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
1000)); 1000));
brightray::BrowserMainParts::PreMainMessageLoopRun(); brightray::BrowserMainParts::PreMainMessageLoopRun();
bridge_task_runner_->MessageLoopIsReady();
bridge_task_runner_ = nullptr;
#if defined(USE_X11) #if defined(USE_X11)
libgtk2ui::GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess()); libgtk2ui::GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess());
@ -116,14 +134,43 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
#endif #endif
} }
bool AtomBrowserMainParts::MainMessageLoopRun(int* result_code) {
exit_code_ = result_code;
return brightray::BrowserMainParts::MainMessageLoopRun(result_code);
}
void AtomBrowserMainParts::PostMainMessageLoopStart() {
brightray::BrowserMainParts::PostMainMessageLoopStart();
#if defined(OS_POSIX)
HandleShutdownSignals();
#endif
}
void AtomBrowserMainParts::PostMainMessageLoopRun() { void AtomBrowserMainParts::PostMainMessageLoopRun() {
brightray::BrowserMainParts::PostMainMessageLoopRun(); brightray::BrowserMainParts::PostMainMessageLoopRun();
#if defined(OS_MACOSX)
FreeAppDelegate();
#endif
// Make sure destruction callbacks are called before message loop is // Make sure destruction callbacks are called before message loop is
// destroyed, otherwise some objects that need to be deleted on IO thread // destroyed, otherwise some objects that need to be deleted on IO thread
// won't be freed. // won't be freed.
for (const auto& callback : destruction_callbacks_) // We don't use ranged for loop because iterators are getting invalided when
// the callback runs.
for (auto iter = destructors_.begin(); iter != destructors_.end();) {
base::Closure& callback = *iter;
++iter;
callback.Run(); callback.Run();
}
// Destroy JavaScript environment immediately after running destruction
// callbacks.
gc_timer_.Stop();
node_debugger_.reset();
atom_bindings_.reset();
node_bindings_.reset();
js_env_.reset();
} }
} // namespace atom } // namespace atom

View file

@ -31,25 +31,37 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
static AtomBrowserMainParts* Get(); static AtomBrowserMainParts* Get();
// Sets the exit code, will fail if the the message loop is not ready.
bool SetExitCode(int code);
// Register a callback that should be destroyed before JavaScript environment // Register a callback that should be destroyed before JavaScript environment
// gets destroyed. // gets destroyed.
void RegisterDestructionCallback(const base::Closure& callback); // Returns a closure that can be used to remove |callback| from the list.
base::Closure RegisterDestructionCallback(const base::Closure& callback);
Browser* browser() { return browser_.get(); } Browser* browser() { return browser_.get(); }
protected: protected:
// content::BrowserMainParts: // content::BrowserMainParts:
void PreEarlyInitialization() override;
void PostEarlyInitialization() override; void PostEarlyInitialization() override;
void PreMainMessageLoopRun() override; void PreMainMessageLoopRun() override;
bool MainMessageLoopRun(int* result_code) override;
void PostMainMessageLoopStart() override;
void PostMainMessageLoopRun() override; void PostMainMessageLoopRun() override;
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
void PreMainMessageLoopStart() override; void PreMainMessageLoopStart() override;
void PostDestroyThreads() override;
#endif #endif
private: private:
#if defined(USE_X11) #if defined(OS_POSIX)
void SetDPIFromGSettings(); // Set signal handlers.
void HandleSIGCHLD();
void HandleShutdownSignals();
#endif
#if defined(OS_MACOSX)
void FreeAppDelegate();
#endif #endif
// A fake BrowserProcess object that used to feed the source code from chrome. // A fake BrowserProcess object that used to feed the source code from chrome.
@ -59,6 +71,9 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
// with a task runner that will post all work to main loop. // with a task runner that will post all work to main loop.
scoped_refptr<BridgeTaskRunner> bridge_task_runner_; scoped_refptr<BridgeTaskRunner> bridge_task_runner_;
// Pointer to exit code.
int* exit_code_;
scoped_ptr<Browser> browser_; scoped_ptr<Browser> browser_;
scoped_ptr<JavascriptEnvironment> js_env_; scoped_ptr<JavascriptEnvironment> js_env_;
scoped_ptr<NodeBindings> node_bindings_; scoped_ptr<NodeBindings> node_bindings_;
@ -68,7 +83,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
base::Timer gc_timer_; base::Timer gc_timer_;
// List of callbacks should be executed before destroying JS env. // List of callbacks should be executed before destroying JS env.
std::list<base::Closure> destruction_callbacks_; std::list<base::Closure> destructors_;
static AtomBrowserMainParts* self_; static AtomBrowserMainParts* self_;

View file

@ -1,73 +0,0 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/atom_browser_main_parts.h"
#include <gio/gio.h>
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "ui/gfx/switches.h"
namespace atom {
namespace {
const char* kInterfaceSchema = "org.gnome.desktop.interface";
const char* kScaleFactor = "scaling-factor";
bool SchemaExists(const char* schema_name) {
const gchar* const* schemas = g_settings_list_schemas();
while (*schemas) {
if (strcmp(schema_name, static_cast<const char*>(*schemas)) == 0)
return true;
schemas++;
}
return false;
}
bool KeyExists(GSettings* client, const char* key) {
gchar** keys = g_settings_list_keys(client);
if (!keys)
return false;
gchar** iter = keys;
while (*iter) {
if (strcmp(*iter, key) == 0)
break;
iter++;
}
bool exists = *iter != NULL;
g_strfreev(keys);
return exists;
}
void GetDPIFromGSettings(guint* scale_factor) {
GSettings* client = nullptr;
if (!SchemaExists(kInterfaceSchema) ||
!(client = g_settings_new(kInterfaceSchema))) {
VLOG(1) << "Cannot create gsettings client.";
return;
}
if (KeyExists(client, kScaleFactor))
*scale_factor = g_settings_get_uint(client, kScaleFactor);
g_object_unref(client);
}
} // namespace
void AtomBrowserMainParts::SetDPIFromGSettings() {
guint scale_factor = 1;
GetDPIFromGSettings(&scale_factor);
if (scale_factor == 0)
scale_factor = 1;
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kForceDeviceScaleFactor, base::UintToString(scale_factor));
}
} // namespace atom

View file

@ -34,7 +34,7 @@ void AtomBrowserMainParts::PreMainMessageLoopStart() {
setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"]; setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"];
} }
void AtomBrowserMainParts::PostDestroyThreads() { void AtomBrowserMainParts::FreeAppDelegate() {
[[NSApp delegate] release]; [[NSApp delegate] release];
[NSApp setDelegate:nil]; [NSApp setDelegate:nil];
} }

View file

@ -0,0 +1,225 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
// Most code came from: chrome/browser/chrome_browser_main_posix.cc.
#include "atom/browser/atom_browser_main_parts.h"
#include <errno.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <sys/resource.h>
#include <unistd.h>
#include "atom/browser/browser.h"
#include "base/posix/eintr_wrapper.h"
#include "content/public/browser/browser_thread.h"
using content::BrowserThread;
namespace atom {
namespace {
// See comment in |PreEarlyInitialization()|, where sigaction is called.
void SIGCHLDHandler(int signal) {
}
// The OSX fork() implementation can crash in the child process before
// fork() returns. In that case, the shutdown pipe will still be
// shared with the parent process. To prevent child crashes from
// causing parent shutdowns, |g_pipe_pid| is the pid for the process
// which registered |g_shutdown_pipe_write_fd|.
// See <http://crbug.com/175341>.
pid_t g_pipe_pid = -1;
int g_shutdown_pipe_write_fd = -1;
int g_shutdown_pipe_read_fd = -1;
// Common code between SIG{HUP, INT, TERM}Handler.
void GracefulShutdownHandler(int signal) {
// Reinstall the default handler. We had one shot at graceful shutdown.
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = SIG_DFL;
RAW_CHECK(sigaction(signal, &action, NULL) == 0);
RAW_CHECK(g_pipe_pid == getpid());
RAW_CHECK(g_shutdown_pipe_write_fd != -1);
RAW_CHECK(g_shutdown_pipe_read_fd != -1);
size_t bytes_written = 0;
do {
int rv = HANDLE_EINTR(
write(g_shutdown_pipe_write_fd,
reinterpret_cast<const char*>(&signal) + bytes_written,
sizeof(signal) - bytes_written));
RAW_CHECK(rv >= 0);
bytes_written += rv;
} while (bytes_written < sizeof(signal));
}
// See comment in |PostMainMessageLoopStart()|, where sigaction is called.
void SIGHUPHandler(int signal) {
RAW_CHECK(signal == SIGHUP);
GracefulShutdownHandler(signal);
}
// See comment in |PostMainMessageLoopStart()|, where sigaction is called.
void SIGINTHandler(int signal) {
RAW_CHECK(signal == SIGINT);
GracefulShutdownHandler(signal);
}
// See comment in |PostMainMessageLoopStart()|, where sigaction is called.
void SIGTERMHandler(int signal) {
RAW_CHECK(signal == SIGTERM);
GracefulShutdownHandler(signal);
}
class ShutdownDetector : public base::PlatformThread::Delegate {
public:
explicit ShutdownDetector(int shutdown_fd);
void ThreadMain() override;
private:
const int shutdown_fd_;
DISALLOW_COPY_AND_ASSIGN(ShutdownDetector);
};
ShutdownDetector::ShutdownDetector(int shutdown_fd)
: shutdown_fd_(shutdown_fd) {
CHECK_NE(shutdown_fd_, -1);
}
// These functions are used to help us diagnose crash dumps that happen
// during the shutdown process.
NOINLINE void ShutdownFDReadError() {
// Ensure function isn't optimized away.
asm("");
sleep(UINT_MAX);
}
NOINLINE void ShutdownFDClosedError() {
// Ensure function isn't optimized away.
asm("");
sleep(UINT_MAX);
}
NOINLINE void ExitPosted() {
// Ensure function isn't optimized away.
asm("");
sleep(UINT_MAX);
}
void ShutdownDetector::ThreadMain() {
base::PlatformThread::SetName("CrShutdownDetector");
int signal;
size_t bytes_read = 0;
ssize_t ret;
do {
ret = HANDLE_EINTR(
read(shutdown_fd_,
reinterpret_cast<char*>(&signal) + bytes_read,
sizeof(signal) - bytes_read));
if (ret < 0) {
NOTREACHED() << "Unexpected error: " << strerror(errno);
ShutdownFDReadError();
break;
} else if (ret == 0) {
NOTREACHED() << "Unexpected closure of shutdown pipe.";
ShutdownFDClosedError();
break;
}
bytes_read += ret;
} while (bytes_read < sizeof(signal));
VLOG(1) << "Handling shutdown for signal " << signal << ".";
base::Closure task =
base::Bind(&Browser::Quit, base::Unretained(Browser::Get()));
if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task)) {
// Without a UI thread to post the exit task to, there aren't many
// options. Raise the signal again. The default handler will pick it up
// and cause an ungraceful exit.
RAW_LOG(WARNING, "No UI thread, exiting ungracefully.");
kill(getpid(), signal);
// The signal may be handled on another thread. Give that a chance to
// happen.
sleep(3);
// We really should be dead by now. For whatever reason, we're not. Exit
// immediately, with the exit status set to the signal number with bit 8
// set. On the systems that we care about, this exit status is what is
// normally used to indicate an exit by this signal's default handler.
// This mechanism isn't a de jure standard, but even in the worst case, it
// should at least result in an immediate exit.
RAW_LOG(WARNING, "Still here, exiting really ungracefully.");
_exit(signal | (1 << 7));
}
ExitPosted();
}
} // namespace
void AtomBrowserMainParts::HandleSIGCHLD() {
// We need to accept SIGCHLD, even though our handler is a no-op because
// otherwise we cannot wait on children. (According to POSIX 2001.)
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = SIGCHLDHandler;
CHECK_EQ(sigaction(SIGCHLD, &action, NULL), 0);
}
void AtomBrowserMainParts::HandleShutdownSignals() {
int pipefd[2];
int ret = pipe(pipefd);
if (ret < 0) {
PLOG(DFATAL) << "Failed to create pipe";
} else {
g_pipe_pid = getpid();
g_shutdown_pipe_read_fd = pipefd[0];
g_shutdown_pipe_write_fd = pipefd[1];
#if !defined(ADDRESS_SANITIZER) && !defined(KEEP_SHADOW_STACKS)
const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 2;
#else
// ASan instrumentation and -finstrument-functions (used for keeping the
// shadow stacks) bloat the stack frames, so we need to increase the stack
// size to avoid hitting the guard page.
const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 4;
#endif
// TODO(viettrungluu,willchan): crbug.com/29675 - This currently leaks, so
// if you change this, you'll probably need to change the suppression.
if (!base::PlatformThread::CreateNonJoinable(
kShutdownDetectorThreadStackSize,
new ShutdownDetector(g_shutdown_pipe_read_fd))) {
LOG(DFATAL) << "Failed to create shutdown detector task.";
}
}
// Setup signal handlers for shutdown AFTER shutdown pipe is setup because
// it may be called right away after handler is set.
// If adding to this list of signal handlers, note the new signal probably
// needs to be reset in child processes. See
// base/process_util_posix.cc:LaunchProcess.
// We need to handle SIGTERM, because that is how many POSIX-based distros ask
// processes to quit gracefully at shutdown time.
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = SIGTERMHandler;
CHECK_EQ(sigaction(SIGTERM, &action, NULL), 0);
// Also handle SIGINT - when the user terminates the browser via Ctrl+C. If
// the browser process is being debugged, GDB will catch the SIGINT first.
action.sa_handler = SIGINTHandler;
CHECK_EQ(sigaction(SIGINT, &action, NULL), 0);
// And SIGHUP, for when the terminal disappears. On shutdown, many Linux
// distros send SIGHUP, SIGTERM, and then SIGKILL.
action.sa_handler = SIGHUPHandler;
CHECK_EQ(sigaction(SIGHUP, &action, NULL), 0);
}
} // namespace atom

View file

@ -0,0 +1,40 @@
// 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/atom_resource_dispatcher_host_delegate.h"
#include "atom/browser/login_handler.h"
#include "atom/common/platform_util.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/escape.h"
#include "url/gurl.h"
using content::BrowserThread;
namespace atom {
AtomResourceDispatcherHostDelegate::AtomResourceDispatcherHostDelegate() {
}
bool AtomResourceDispatcherHostDelegate::HandleExternalProtocol(
const GURL& url,
int render_process_id,
int render_view_id,
bool is_main_frame,
ui::PageTransition transition,
bool has_user_gesture) {
GURL escaped_url(net::EscapeExternalHandlerValue(url.spec()));
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(base::IgnoreResult(platform_util::OpenExternal), escaped_url));
return true;
}
content::ResourceDispatcherHostLoginDelegate*
AtomResourceDispatcherHostDelegate::CreateLoginDelegate(
net::AuthChallengeInfo* auth_info,
net::URLRequest* request) {
return new LoginHandler(auth_info, request);
}
} // namespace atom

View file

@ -0,0 +1,31 @@
// 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_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
#define ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
#include "content/public/browser/resource_dispatcher_host_delegate.h"
namespace atom {
class AtomResourceDispatcherHostDelegate
: public content::ResourceDispatcherHostDelegate {
public:
AtomResourceDispatcherHostDelegate();
// content::ResourceDispatcherHostDelegate:
bool HandleExternalProtocol(const GURL& url,
int render_process_id,
int render_view_id,
bool is_main_frame,
ui::PageTransition transition,
bool has_user_gesture) override;
content::ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
net::AuthChallengeInfo* auth_info,
net::URLRequest* request) override;
};
} // namespace atom
#endif // ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_

View file

@ -6,14 +6,25 @@
namespace auto_updater { namespace auto_updater {
AutoUpdaterDelegate* AutoUpdater::delegate_ = NULL; Delegate* AutoUpdater::delegate_ = nullptr;
AutoUpdaterDelegate* AutoUpdater::GetDelegate() { Delegate* AutoUpdater::GetDelegate() {
return delegate_; return delegate_;
} }
void AutoUpdater::SetDelegate(AutoUpdaterDelegate* delegate) { void AutoUpdater::SetDelegate(Delegate* delegate) {
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 } // namespace auto_updater

View file

@ -9,21 +9,48 @@
#include "base/basictypes.h" #include "base/basictypes.h"
namespace base {
class Time;
}
namespace auto_updater { 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 { class AutoUpdater {
public: public:
// Gets/Sets the delegate. // Gets/Sets the delegate.
static AutoUpdaterDelegate* GetDelegate(); static Delegate* GetDelegate();
static void SetDelegate(AutoUpdaterDelegate* delegate); static void SetDelegate(Delegate* delegate);
static void SetFeedURL(const std::string& url); static void SetFeedURL(const std::string& url);
static void CheckForUpdates(); static void CheckForUpdates();
static void QuitAndInstall();
private: private:
static AutoUpdaterDelegate* delegate_; static Delegate* delegate_;
DISALLOW_IMPLICIT_CONSTRUCTORS(AutoUpdater); DISALLOW_IMPLICIT_CONSTRUCTORS(AutoUpdater);
}; };

View file

@ -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_

View file

@ -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

View file

@ -12,9 +12,6 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "atom/browser/auto_updater_delegate.h"
#include <iostream>
namespace auto_updater { namespace auto_updater {
@ -23,20 +20,12 @@ namespace {
// The gloal SQRLUpdater object. // The gloal SQRLUpdater object.
SQRLUpdater* g_updater = nil; 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 } // namespace
// static // static
void AutoUpdater::SetFeedURL(const std::string& feed) { void AutoUpdater::SetFeedURL(const std::string& feed) {
if (g_updater == nil) { if (g_updater == nil) {
AutoUpdaterDelegate* delegate = GetDelegate(); Delegate* delegate = GetDelegate();
if (!delegate) if (!delegate)
return; return;
@ -67,7 +56,7 @@ void AutoUpdater::SetFeedURL(const std::string& feed) {
// static // static
void AutoUpdater::CheckForUpdates() { void AutoUpdater::CheckForUpdates() {
AutoUpdaterDelegate* delegate = GetDelegate(); Delegate* delegate = GetDelegate();
if (!delegate) if (!delegate)
return; return;
@ -86,8 +75,7 @@ void AutoUpdater::CheckForUpdates() {
base::SysNSStringToUTF8(update.releaseNotes), base::SysNSStringToUTF8(update.releaseNotes),
base::SysNSStringToUTF8(update.releaseName), base::SysNSStringToUTF8(update.releaseName),
base::Time::FromDoubleT(update.releaseDate.timeIntervalSince1970), base::Time::FromDoubleT(update.releaseDate.timeIntervalSince1970),
base::SysNSStringToUTF8(update.updateURL.absoluteString), base::SysNSStringToUTF8(update.updateURL.absoluteString));
base::Bind(RelaunchToInstallUpdate));
} else { } else {
// When the completed event is sent with no update, then we know there // When the completed event is sent with no update, then we know there
// is no update available. // 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 } // namespace auto_updater

View file

@ -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

View file

@ -8,13 +8,28 @@
namespace atom { namespace atom {
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( bool BridgeTaskRunner::PostDelayedTask(
const tracked_objects::Location& from_here, const tracked_objects::Location& from_here,
const base::Closure& task, const base::Closure& task,
base::TimeDelta delay) { base::TimeDelta delay) {
auto message_loop = base::MessageLoop::current(); auto message_loop = base::MessageLoop::current();
if (!message_loop) if (!message_loop) {
return false; tasks_.push_back(base::MakeTuple(from_here, task, delay));
return true;
}
return message_loop->task_runner()->PostDelayedTask(from_here, task, delay); return message_loop->task_runner()->PostDelayedTask(from_here, task, delay);
} }
@ -22,7 +37,7 @@ bool BridgeTaskRunner::PostDelayedTask(
bool BridgeTaskRunner::RunsTasksOnCurrentThread() const { bool BridgeTaskRunner::RunsTasksOnCurrentThread() const {
auto message_loop = base::MessageLoop::current(); auto message_loop = base::MessageLoop::current();
if (!message_loop) if (!message_loop)
return false; return true;
return message_loop->task_runner()->RunsTasksOnCurrentThread(); return message_loop->task_runner()->RunsTasksOnCurrentThread();
} }
@ -32,8 +47,10 @@ bool BridgeTaskRunner::PostNonNestableDelayedTask(
const base::Closure& task, const base::Closure& task,
base::TimeDelta delay) { base::TimeDelta delay) {
auto message_loop = base::MessageLoop::current(); auto message_loop = base::MessageLoop::current();
if (!message_loop) if (!message_loop) {
return false; non_nestable_tasks_.push_back(base::MakeTuple(from_here, task, delay));
return true;
}
return message_loop->task_runner()->PostNonNestableDelayedTask( return message_loop->task_runner()->PostNonNestableDelayedTask(
from_here, task, delay); from_here, task, delay);

View file

@ -5,17 +5,23 @@
#ifndef ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_ #ifndef ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
#define ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_ #define ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
#include <vector>
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/tuple.h"
namespace atom { namespace atom {
// Post all tasks to the current message loop's task runner if available, // 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 { class BridgeTaskRunner : public base::SingleThreadTaskRunner {
public: public:
BridgeTaskRunner() {} BridgeTaskRunner() {}
~BridgeTaskRunner() override {} ~BridgeTaskRunner() override {}
// Called when message loop is ready.
void MessageLoopIsReady();
// base::SingleThreadTaskRunner: // base::SingleThreadTaskRunner:
bool PostDelayedTask(const tracked_objects::Location& from_here, bool PostDelayedTask(const tracked_objects::Location& from_here,
const base::Closure& task, const base::Closure& task,
@ -27,6 +33,11 @@ class BridgeTaskRunner : public base::SingleThreadTaskRunner {
base::TimeDelta delay) override; base::TimeDelta delay) override;
private: private:
using TaskPair = base::Tuple<
tracked_objects::Location, base::Closure, base::TimeDelta>;
std::vector<TaskPair> tasks_;
std::vector<TaskPair> non_nestable_tasks_;
DISALLOW_COPY_AND_ASSIGN(BridgeTaskRunner); DISALLOW_COPY_AND_ASSIGN(BridgeTaskRunner);
}; };

View file

@ -7,16 +7,16 @@
#include <string> #include <string>
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/native_window.h"
#include "atom/browser/window_list.h" #include "atom/browser/window_list.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "content/public/browser/client_certificate_delegate.h"
#include "net/ssl/ssl_cert_request_info.h"
namespace atom { namespace atom {
Browser::Browser() Browser::Browser()
: is_quiting_(false), : is_quiting_(false),
is_ready_(false) { is_ready_(false),
is_shutdown_(false) {
WindowList::AddObserver(this); WindowList::AddObserver(this);
} }
@ -30,6 +30,9 @@ Browser* Browser::Get() {
} }
void Browser::Quit() { void Browser::Quit() {
if (is_quiting_)
return;
is_quiting_ = HandleBeforeQuit(); is_quiting_ = HandleBeforeQuit();
if (!is_quiting_) if (!is_quiting_)
return; return;
@ -41,12 +44,43 @@ void Browser::Quit() {
window_list->CloseAllWindows(); window_list->CloseAllWindows();
} }
void Browser::Exit(int code) {
if (!AtomBrowserMainParts::Get()->SetExitCode(code)) {
// Message loop is not ready, quit directly.
exit(code);
} else {
// Prepare to quit when all windows have been closed..
is_quiting_ = true;
// Must destroy windows before quitting, otherwise bad things can happen.
atom::WindowList* window_list = atom::WindowList::GetInstance();
if (window_list->size() == 0) {
NotifyAndShutdown();
} else {
// Unlike Quit(), we do not ask to close window, but destroy the window
// without asking.
for (NativeWindow* window : *window_list)
window->CloseContents(nullptr); // e.g. Destroy()
}
}
}
void Browser::Shutdown() { void Browser::Shutdown() {
if (is_shutdown_)
return;
is_shutdown_ = true;
is_quiting_ = true;
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnQuit()); FOR_EACH_OBSERVER(BrowserObserver, observers_, OnQuit());
is_quiting_ = true; if (base::MessageLoop::current()) {
base::MessageLoop::current()->PostTask( base::MessageLoop::current()->PostTask(
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); 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 { std::string Browser::GetVersion() const {
@ -75,10 +109,6 @@ std::string Browser::GetName() const {
void Browser::SetName(const std::string& name) { void Browser::SetName(const std::string& name) {
name_override_ = name; name_override_ = name;
#if defined(OS_WIN)
SetAppUserModelID(name);
#endif
} }
bool Browser::OpenFile(const std::string& file_path) { bool Browser::OpenFile(const std::string& file_path) {
@ -109,18 +139,14 @@ void Browser::DidFinishLaunching() {
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnFinishLaunching()); FOR_EACH_OBSERVER(BrowserObserver, observers_, OnFinishLaunching());
} }
void Browser::ClientCertificateSelector( void Browser::RequestLogin(LoginHandler* login_handler) {
content::WebContents* web_contents, FOR_EACH_OBSERVER(BrowserObserver, observers_, OnLogin(login_handler));
net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) {
FOR_EACH_OBSERVER(BrowserObserver,
observers_,
OnSelectCertificate(web_contents,
cert_request_info,
delegate.Pass()));
} }
void Browser::NotifyAndShutdown() { void Browser::NotifyAndShutdown() {
if (is_shutdown_)
return;
bool prevent_default = false; bool prevent_default = false;
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillQuit(&prevent_default)); FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillQuit(&prevent_default));

View file

@ -11,12 +11,12 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "base/strings/string16.h"
#include "atom/browser/browser_observer.h" #include "atom/browser/browser_observer.h"
#include "atom/browser/window_list_observer.h" #include "atom/browser/window_list_observer.h"
#if defined(OS_WIN) #if defined(OS_WIN)
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/strings/string16.h"
#endif #endif
namespace base { namespace base {
@ -29,6 +29,8 @@ class MenuModel;
namespace atom { namespace atom {
class LoginHandler;
// This class is used for control application-wide operations. // This class is used for control application-wide operations.
class Browser : public WindowListObserver { class Browser : public WindowListObserver {
public: public:
@ -40,6 +42,9 @@ class Browser : public WindowListObserver {
// Try to close all windows and quit the application. // Try to close all windows and quit the application.
void Quit(); void Quit();
// Exit the application immediately and set exit code.
void Exit(int code);
// Cleanup everything and shutdown the application gracefully. // Cleanup everything and shutdown the application gracefully.
void Shutdown(); void Shutdown();
@ -64,6 +69,9 @@ class Browser : public WindowListObserver {
// Clear the recent documents list. // Clear the recent documents list.
void ClearRecentDocuments(); void ClearRecentDocuments();
// Set the application user model ID.
void SetAppUserModelID(const base::string16& name);
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
// Bounce the dock icon. // Bounce the dock icon.
enum BounceType { enum BounceType {
@ -98,8 +106,10 @@ class Browser : public WindowListObserver {
// Add a custom task to jump list. // Add a custom task to jump list.
void SetUserTasks(const std::vector<UserTask>& tasks); void SetUserTasks(const std::vector<UserTask>& tasks);
// Set the application user model ID, called when "SetName" is called. // Returns the application user model ID, if there isn't one, then create
void SetAppUserModelID(const std::string& name); // one from app's name.
// The returned string managed by Browser, and should not be modified.
PCWSTR GetAppUserModelID();
#endif #endif
// Tell the application to open a file. // Tell the application to open a file.
@ -116,11 +126,8 @@ class Browser : public WindowListObserver {
void WillFinishLaunching(); void WillFinishLaunching();
void DidFinishLaunching(); void DidFinishLaunching();
// Called when client certificate is required. // Request basic auth login.
void ClientCertificateSelector( void RequestLogin(LoginHandler* login_handler);
content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate);
void AddObserver(BrowserObserver* obs) { void AddObserver(BrowserObserver* obs) {
observers_.AddObserver(obs); observers_.AddObserver(obs);
@ -130,6 +137,7 @@ class Browser : public WindowListObserver {
observers_.RemoveObserver(obs); observers_.RemoveObserver(obs);
} }
bool is_shutting_down() const { return is_shutdown_; }
bool is_quiting() const { return is_quiting_; } bool is_quiting() const { return is_quiting_; }
bool is_ready() const { return is_ready_; } bool is_ready() const { return is_ready_; }
@ -159,6 +167,9 @@ class Browser : public WindowListObserver {
// Whether "ready" event has been emitted. // Whether "ready" event has been emitted.
bool is_ready_; bool is_ready_;
// The browse is being shutdown.
bool is_shutdown_;
std::string version_override_; std::string version_override_;
std::string name_override_; std::string name_override_;

View file

@ -31,6 +31,9 @@ void Browser::AddRecentDocument(const base::FilePath& path) {
void Browser::ClearRecentDocuments() { void Browser::ClearRecentDocuments() {
} }
void Browser::SetAppUserModelID(const base::string16& name) {
}
std::string Browser::GetExecutableFileVersion() const { std::string Browser::GetExecutableFileVersion() const {
return brightray::GetApplicationVersion(); return brightray::GetApplicationVersion();
} }

View file

@ -26,6 +26,9 @@ void Browser::AddRecentDocument(const base::FilePath& path) {
void Browser::ClearRecentDocuments() { void Browser::ClearRecentDocuments() {
} }
void Browser::SetAppUserModelID(const base::string16& name) {
}
std::string Browser::GetExecutableFileVersion() const { std::string Browser::GetExecutableFileVersion() const {
return brightray::GetApplicationVersion(); return brightray::GetApplicationVersion();
} }

View file

@ -7,19 +7,10 @@
#include <string> #include <string>
#include "base/memory/scoped_ptr.h"
#include "content/public/browser/client_certificate_delegate.h"
namespace content {
class WebContents;
}
namespace net {
class SSLCertRequestInfo;
}
namespace atom { namespace atom {
class LoginHandler;
class BrowserObserver { class BrowserObserver {
public: public:
// The browser is about to close all windows. // The browser is about to close all windows.
@ -51,11 +42,8 @@ class BrowserObserver {
virtual void OnWillFinishLaunching() {} virtual void OnWillFinishLaunching() {}
virtual void OnFinishLaunching() {} virtual void OnFinishLaunching() {}
// The browser requires client certificate. // The browser requests HTTP login.
virtual void OnSelectCertificate( virtual void OnLogin(LoginHandler* login_handler) {}
content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) {}
protected: protected:
virtual ~BrowserObserver() {} virtual ~BrowserObserver() {}

View file

@ -15,6 +15,7 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/win/win_util.h" #include "base/win/win_util.h"
@ -25,6 +26,8 @@ namespace atom {
namespace { namespace {
const wchar_t kAppUserModelIDFormat[] = L"electron.app.$1";
BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) { BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) {
DWORD target_process_id = *reinterpret_cast<DWORD*>(param); DWORD target_process_id = *reinterpret_cast<DWORD*>(param);
DWORD process_id = 0; DWORD process_id = 0;
@ -56,7 +59,7 @@ void Browser::AddRecentDocument(const base::FilePath& path) {
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
SHARDAPPIDINFO info; SHARDAPPIDINFO info;
info.psi = item; info.psi = item;
info.pszAppID = app_user_model_id_.c_str(); info.pszAppID = GetAppUserModelID();
SHAddToRecentDocs(SHARD_APPIDINFO, &info); SHAddToRecentDocs(SHARD_APPIDINFO, &info);
} }
} }
@ -66,16 +69,21 @@ void Browser::ClearRecentDocuments() {
if (FAILED(destinations.CoCreateInstance(CLSID_ApplicationDestinations, if (FAILED(destinations.CoCreateInstance(CLSID_ApplicationDestinations,
NULL, CLSCTX_INPROC_SERVER))) NULL, CLSCTX_INPROC_SERVER)))
return; return;
if (FAILED(destinations->SetAppID(app_user_model_id_.c_str()))) if (FAILED(destinations->SetAppID(GetAppUserModelID())))
return; return;
destinations->RemoveAllDestinations(); destinations->RemoveAllDestinations();
} }
void Browser::SetAppUserModelID(const base::string16& name) {
app_user_model_id_ = name;
SetCurrentProcessExplicitAppUserModelID(app_user_model_id_.c_str());
}
void Browser::SetUserTasks(const std::vector<UserTask>& tasks) { void Browser::SetUserTasks(const std::vector<UserTask>& tasks) {
CComPtr<ICustomDestinationList> destinations; CComPtr<ICustomDestinationList> destinations;
if (FAILED(destinations.CoCreateInstance(CLSID_DestinationList))) if (FAILED(destinations.CoCreateInstance(CLSID_DestinationList)))
return; return;
if (FAILED(destinations->SetAppID(app_user_model_id_.c_str()))) if (FAILED(destinations->SetAppID(GetAppUserModelID())))
return; return;
// Start a transaction that updates the JumpList of this application. // Start a transaction that updates the JumpList of this application.
@ -117,10 +125,13 @@ void Browser::SetUserTasks(const std::vector<UserTask>& tasks) {
destinations->CommitList(); destinations->CommitList();
} }
void Browser::SetAppUserModelID(const std::string& name) { PCWSTR Browser::GetAppUserModelID() {
app_user_model_id_ = base::string16(L"electron.app."); if (app_user_model_id_.empty()) {
app_user_model_id_ += base::UTF8ToUTF16(name); SetAppUserModelID(base::ReplaceStringPlaceholders(
SetCurrentProcessExplicitAppUserModelID(app_user_model_id_.c_str()); kAppUserModelIDFormat, base::UTF8ToUTF16(GetName()), nullptr));
}
return app_user_model_id_.c_str();
} }
std::string Browser::GetExecutableFileVersion() const { std::string Browser::GetExecutableFileVersion() const {

View file

@ -21,6 +21,14 @@
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "storage/browser/fileapi/isolated_context.h" #include "storage/browser/fileapi/isolated_context.h"
#if defined(TOOLKIT_VIEWS)
#include "atom/browser/native_window_views.h"
#endif
#if defined(USE_X11)
#include "atom/browser/browser.h"
#endif
using content::BrowserThread; using content::BrowserThread;
namespace atom { namespace atom {
@ -128,7 +136,11 @@ void CommonWebContentsDelegate::InitWithWebContents(
} }
void CommonWebContentsDelegate::SetOwnerWindow(NativeWindow* owner_window) { void CommonWebContentsDelegate::SetOwnerWindow(NativeWindow* owner_window) {
content::WebContents* web_contents = GetWebContents(); SetOwnerWindow(GetWebContents(), owner_window);
}
void CommonWebContentsDelegate::SetOwnerWindow(
content::WebContents* web_contents, NativeWindow* owner_window) {
owner_window_ = owner_window->GetWeakPtr(); owner_window_ = owner_window->GetWeakPtr();
NativeWindowRelay* relay = new NativeWindowRelay(owner_window_); NativeWindowRelay* relay = new NativeWindowRelay(owner_window_);
web_contents->SetUserData(relay->key, relay); web_contents->SetUserData(relay->key, relay);
@ -355,6 +367,23 @@ void CommonWebContentsDelegate::OnDevToolsAppendToFile(
"DevToolsAPI.appendedToURL", &url_value, nullptr, nullptr); "DevToolsAPI.appendedToURL", &url_value, nullptr, nullptr);
} }
#if defined(TOOLKIT_VIEWS)
gfx::ImageSkia CommonWebContentsDelegate::GetDevToolsWindowIcon() {
if (!owner_window())
return gfx::ImageSkia();
return static_cast<views::WidgetDelegate*>(static_cast<NativeWindowViews*>(
owner_window()))->GetWindowAppIcon();
}
#endif
#if defined(USE_X11)
void CommonWebContentsDelegate::GetDevToolsWindowWMClass(
std::string* name, std::string* class_name) {
*class_name = Browser::Get()->GetName();
*name = base::ToLowerASCII(*class_name);
}
#endif
void CommonWebContentsDelegate::SetHtmlApiFullscreen(bool enter_fullscreen) { void CommonWebContentsDelegate::SetHtmlApiFullscreen(bool enter_fullscreen) {
// Window is already in fullscreen mode, save the state. // Window is already in fullscreen mode, save the state.
if (enter_fullscreen && owner_window_->IsFullscreen()) { if (enter_fullscreen && owner_window_->IsFullscreen()) {

View file

@ -12,6 +12,7 @@
#include "brightray/browser/default_web_contents_delegate.h" #include "brightray/browser/default_web_contents_delegate.h"
#include "brightray/browser/inspectable_web_contents_impl.h" #include "brightray/browser/inspectable_web_contents_impl.h"
#include "brightray/browser/inspectable_web_contents_delegate.h" #include "brightray/browser/inspectable_web_contents_delegate.h"
#include "brightray/browser/inspectable_web_contents_view_delegate.h"
namespace atom { namespace atom {
@ -21,7 +22,8 @@ class WebDialogHelper;
class CommonWebContentsDelegate class CommonWebContentsDelegate
: public brightray::DefaultWebContentsDelegate, : public brightray::DefaultWebContentsDelegate,
public brightray::InspectableWebContentsDelegate { public brightray::InspectableWebContentsDelegate,
public brightray::InspectableWebContentsViewDelegate {
public: public:
CommonWebContentsDelegate(); CommonWebContentsDelegate();
virtual ~CommonWebContentsDelegate(); virtual ~CommonWebContentsDelegate();
@ -32,6 +34,8 @@ class CommonWebContentsDelegate
// Set the window as owner window. // Set the window as owner window.
void SetOwnerWindow(NativeWindow* owner_window); void SetOwnerWindow(NativeWindow* owner_window);
void SetOwnerWindow(content::WebContents* web_contents,
NativeWindow* owner_window);
// Destroy the managed InspectableWebContents object. // Destroy the managed InspectableWebContents object.
void DestroyWebContents(); void DestroyWebContents();
@ -86,6 +90,15 @@ class CommonWebContentsDelegate
void DevToolsRemoveFileSystem( void DevToolsRemoveFileSystem(
const base::FilePath& file_system_path) override; const base::FilePath& file_system_path) override;
// brightray::InspectableWebContentsViewDelegate:
#if defined(TOOLKIT_VIEWS)
gfx::ImageSkia GetDevToolsWindowIcon() override;
#endif
#if defined(USE_X11)
void GetDevToolsWindowWMClass(
std::string* name, std::string* class_name) override;
#endif
private: private:
// Callback for when DevToolsSaveToFile has completed. // Callback for when DevToolsSaveToFile has completed.
void OnDevToolsSaveToFile(const std::string& url); void OnDevToolsSaveToFile(const std::string& url);

View file

@ -1,5 +1,6 @@
var app = require('app'); const electron = require('electron');
var BrowserWindow = require('browser-window'); const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
var mainWindow = null; var mainWindow = null;
@ -12,9 +13,9 @@ app.on('ready', function() {
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
width: 800, width: 800,
height: 600, height: 600,
'auto-hide-menu-bar': true, autoHideMenuBar: true,
'use-content-size': true, useContentSize: true,
}); });
mainWindow.loadUrl('file://' + __dirname + '/index.html'); mainWindow.loadURL('file://' + __dirname + '/index.html');
mainWindow.focus(); mainWindow.focus();
}); });

View file

@ -57,13 +57,17 @@
</head> </head>
<body> <body>
<script> <script>
var execPath = require('remote').process.execPath; const electron = require('electron');
const remote = electron.remote;
const shell = electron.shell;
var execPath = remote.process.execPath;
var command = execPath + ' path-to-your-app'; var command = execPath + ' path-to-your-app';
document.onclick = function(e) { document.onclick = function(e) {
e.preventDefault(); e.preventDefault();
if (e.target.tagName == 'A') if (e.target.tagName == 'A')
require('shell').openExternal(e.target.href); shell.openExternal(e.target.href);
return false; return false;
}; };
document.ondragover = document.ondrop = function(e) { document.ondragover = document.ondrop = function(e) {
@ -72,7 +76,11 @@
}; };
</script> </script>
<h2 style="-webkit-app-region: drag">Welcome to Electron</h2> <h2>
<script>
document.write(`Welcome to Electron (v${process.versions.electron})`)
</script>
</h2>
<p> <p>
To run your app with Electron, execute the following command under your To run your app with Electron, execute the following command under your
@ -83,8 +91,18 @@
<p> <p>
The <code>path-to-your-app</code> should be the path to your own Electron The <code>path-to-your-app</code> should be the path to your own Electron
app, you can read the <a href='https://github.com/atom/electron/blob/master/docs/tutorial/quick-start.md'>quick start</a> app, you can read the
guide in Electron's <a href='https://github.com/atom/electron/blob/master/docs'>docs</a> <script>
document.write(
`<a href='https://github.com/atom/electron/blob/v${process.versions.electron}/docs/tutorial/quick-start.md'>quick start</a>`
);
</script>
guide in Electron's
<script>
document.write(
`<a href='https://github.com/atom/electron/tree/v${process.versions.electron}/docs#readme'>docs</a>`
);
</script>
on how to write one. on how to write one.
</p> </p>

View file

@ -1,9 +1,11 @@
var app = require('app'); const electron = require('electron');
var dialog = require('dialog'); const app = electron.app;
const dialog = electron.dialog;
const shell = electron.shell;
const Menu = electron.Menu;
var fs = require('fs'); var fs = require('fs');
var path = require('path'); var path = require('path');
var Menu = require('menu');
var BrowserWindow = require('browser-window');
// Quit when all windows are closed and no other one is listening to this. // Quit when all windows are closed and no other one is listening to this.
app.on('window-all-closed', function() { app.on('window-all-closed', function() {
@ -13,16 +15,22 @@ app.on('window-all-closed', function() {
// Parse command line options. // Parse command line options.
var argv = process.argv.slice(1); var argv = process.argv.slice(1);
var option = { file: null, help: null, version: null, webdriver: null }; var option = { file: null, help: null, version: null, webdriver: null, modules: [] };
for (var i in argv) { for (var i = 0; i < argv.length; i++) {
if (argv[i] == '--version' || argv[i] == '-v') { if (argv[i] == '--version' || argv[i] == '-v') {
option.version = true; option.version = true;
break; break;
} else if (argv[i].match(/^--app=/)) {
option.file = argv[i].split('=')[1];
break;
} else if (argv[i] == '--help' || argv[i] == '-h') { } else if (argv[i] == '--help' || argv[i] == '-h') {
option.help = true; option.help = true;
break; break;
} else if (argv[i] == '--test-type=webdriver') { } else if (argv[i] == '--test-type=webdriver') {
option.webdriver = true; option.webdriver = true;
} else if (argv[i] == '--require' || argv[i] == '-r') {
option.modules.push(argv[++i]);
continue;
} else if (argv[i][0] == '-') { } else if (argv[i][0] == '-') {
continue; continue;
} else { } else {
@ -136,19 +144,23 @@ app.once('ready', function() {
submenu: [ submenu: [
{ {
label: 'Learn More', label: 'Learn More',
click: function() { require('shell').openExternal('http://electron.atom.io') } click: function() { shell.openExternal('http://electron.atom.io') }
}, },
{ {
label: 'Documentation', label: 'Documentation',
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') } click: function() {
shell.openExternal(
`https://github.com/atom/electron/tree/v${process.versions.electron}/docs#readme`
)
}
}, },
{ {
label: 'Community Discussions', label: 'Community Discussions',
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') } click: function() { shell.openExternal('https://discuss.atom.io/c/electron') }
}, },
{ {
label: 'Search Issues', label: 'Search Issues',
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') } click: function() { shell.openExternal('https://github.com/atom/electron/issues') }
} }
] ]
}, },
@ -181,11 +193,11 @@ app.once('ready', function() {
{ {
label: 'Hide Others', label: 'Hide Others',
accelerator: 'Command+Shift+H', accelerator: 'Command+Shift+H',
role: 'hideothers:' role: 'hideothers'
}, },
{ {
label: 'Show All', label: 'Show All',
role: 'unhide:' role: 'unhide'
}, },
{ {
type: 'separator' type: 'separator'
@ -212,6 +224,10 @@ app.once('ready', function() {
Menu.setApplicationMenu(menu); Menu.setApplicationMenu(menu);
}); });
if (option.modules.length > 0) {
require('module')._preloadModules(option.modules);
}
// Start the specified app if there is one specified in command line, otherwise // Start the specified app if there is one specified in command line, otherwise
// start the default app. // start the default app.
if (option.file && !option.webdriver) { if (option.file && !option.webdriver) {
@ -237,7 +253,11 @@ if (option.file && !option.webdriver) {
} catch(e) { } catch(e) {
if (e.code == 'MODULE_NOT_FOUND') { if (e.code == 'MODULE_NOT_FOUND') {
app.focus(); app.focus();
dialog.showErrorBox('Error opening app', 'The app provided is not a valid electron app, please read the docs on how to write one:\nhttps://github.com/atom/electron/tree/master/docs\n\n' + e.toString()); dialog.showErrorBox(
'Error opening app',
'The app provided is not a valid Electron app, please read the docs on how to write one:\n' +
`https://github.com/atom/electron/tree/v${process.versions.electron}/docs\n\n${e.toString()}`
);
process.exit(1); process.exit(1);
} else { } else {
console.error('App threw an error when running', e); console.error('App threw an error when running', e);
@ -253,10 +273,11 @@ if (option.file && !option.webdriver) {
helpMessage += "A path to an Electron application may be specified. The path must be to \n"; 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 += "an index.js file or to a folder containing a package.json or index.js file.\n\n";
helpMessage += "Options:\n"; helpMessage += "Options:\n";
helpMessage += " -r, --require Module to preload (option can be repeated)\n";
helpMessage += " -h, --help Print this usage message.\n"; helpMessage += " -h, --help Print this usage message.\n";
helpMessage += " -v, --version Print the version."; helpMessage += " -v, --version Print the version.";
console.log(helpMessage); console.log(helpMessage);
process.exit(0); process.exit(0);
} else { } else {
require('./default_app.js'); require('./default_app');
} }

View file

@ -4,6 +4,10 @@
#include "atom/browser/javascript_environment.h" #include "atom/browser/javascript_environment.h"
#include <string>
#include "base/command_line.h"
#include "content/public/common/content_switches.h"
#include "gin/array_buffer.h" #include "gin/array_buffer.h"
#include "gin/v8_initializer.h" #include "gin/v8_initializer.h"
@ -20,7 +24,18 @@ JavascriptEnvironment::JavascriptEnvironment()
} }
bool JavascriptEnvironment::Initialize() { 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);
}
// --js-flags.
std::string js_flags = cmd->GetSwitchValueASCII(switches::kJavaScriptFlags);
if (!js_flags.empty())
v8::V8::SetFlagsFromString(js_flags.c_str(), js_flags.size());
gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode, gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode,
gin::ArrayBufferAllocator::SharedInstance()); gin::ArrayBufferAllocator::SharedInstance());
return true; return true;

View file

@ -1,4 +1,4 @@
app = require 'app' electron = require 'electron'
fs = require 'fs' fs = require 'fs'
path = require 'path' path = require 'path'
url = require 'url' url = require 'url'
@ -40,6 +40,7 @@ loadedExtensions = null
loadedExtensionsPath = null loadedExtensionsPath = null
# Persistent loaded extensions. # Persistent loaded extensions.
{app} = electron
app.on 'will-quit', -> app.on 'will-quit', ->
try try
loadedExtensions = Object.keys(extensionInfoMap).map (key) -> extensionInfoMap[key].srcDirectory loadedExtensions = Object.keys(extensionInfoMap).map (key) -> extensionInfoMap[key].srcDirectory
@ -51,11 +52,10 @@ app.on 'will-quit', ->
# We can not use protocol or BrowserWindow until app is ready. # We can not use protocol or BrowserWindow until app is ready.
app.once 'ready', -> app.once 'ready', ->
protocol = require 'protocol' {protocol, BrowserWindow} = electron
BrowserWindow = require 'browser-window'
# Load persistented extensions. # Load persistented extensions.
loadedExtensionsPath = path.join app.getDataPath(), 'DevTools Extensions' loadedExtensionsPath = path.join app.getPath('userData'), 'DevTools Extensions'
try try
loadedExtensions = JSON.parse fs.readFileSync(loadedExtensionsPath) loadedExtensions = JSON.parse fs.readFileSync(loadedExtensionsPath)

View file

@ -1,5 +1,5 @@
ipc = require 'ipc' {ipcMain, webContents} = require 'electron'
webContents = require 'web-contents'
webViewManager = null # Doesn't exist in early initialization. webViewManager = null # Doesn't exist in early initialization.
supportedWebViewEvents = [ supportedWebViewEvents = [
@ -19,7 +19,7 @@ supportedWebViewEvents = [
'gpu-crashed' 'gpu-crashed'
'plugin-crashed' 'plugin-crashed'
'destroyed' 'destroyed'
'page-title-set' 'page-title-updated'
'page-favicon-updated' 'page-favicon-updated'
'enter-html-full-screen' 'enter-html-full-screen'
'leave-html-full-screen' 'leave-html-full-screen'
@ -79,7 +79,7 @@ createGuest = (embedder, params) ->
opts = {} opts = {}
opts.httpReferrer = params.httpreferrer if params.httpreferrer opts.httpReferrer = params.httpreferrer if params.httpreferrer
opts.userAgent = params.useragent if params.useragent opts.userAgent = params.useragent if params.useragent
@loadUrl params.src, opts @loadURL params.src, opts
if params.allowtransparency? if params.allowtransparency?
@setAllowTransparency params.allowtransparency @setAllowTransparency params.allowtransparency
@ -118,11 +118,11 @@ attachGuest = (embedder, elementInstanceId, guestInstanceId, params) ->
destroyGuest embedder, oldGuestInstanceId destroyGuest embedder, oldGuestInstanceId
webPreferences = webPreferences =
'guest-instance-id': guestInstanceId guestInstanceId: guestInstanceId
'node-integration': params.nodeintegration ? false nodeIntegration: params.nodeintegration ? false
'plugins': params.plugins plugins: params.plugins
'web-security': !params.disablewebsecurity webSecurity: !params.disablewebsecurity
webPreferences['preload-url'] = params.preload if params.preload webPreferences.preloadURL = params.preload if params.preload
webViewManager.addGuest guestInstanceId, elementInstanceId, embedder, guest, webPreferences webViewManager.addGuest guestInstanceId, elementInstanceId, embedder, guest, webPreferences
guest.attachParams = params guest.attachParams = params
@ -140,19 +140,19 @@ destroyGuest = (embedder, id) ->
delete reverseEmbedderElementsMap[id] delete reverseEmbedderElementsMap[id]
delete embedderElementsMap[key] delete embedderElementsMap[key]
ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', (event, params, requestId) -> ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', (event, params, requestId) ->
event.sender.send "ATOM_SHELL_RESPONSE_#{requestId}", createGuest(event.sender, params) event.sender.send "ATOM_SHELL_RESPONSE_#{requestId}", createGuest(event.sender, params)
ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', (event, elementInstanceId, guestInstanceId, params) -> ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', (event, elementInstanceId, guestInstanceId, params) ->
attachGuest event.sender, elementInstanceId, guestInstanceId, params attachGuest event.sender, elementInstanceId, guestInstanceId, params
ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_DESTROY_GUEST', (event, id) -> ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_DESTROY_GUEST', (event, id) ->
destroyGuest event.sender, id destroyGuest event.sender, id
ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_SIZE', (event, id, params) -> ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_SIZE', (event, id, params) ->
guestInstances[id]?.guest.setSize params guestInstances[id]?.guest.setSize params
ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_ALLOW_TRANSPARENCY', (event, id, allowtransparency) -> ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_ALLOW_TRANSPARENCY', (event, id, allowtransparency) ->
guestInstances[id]?.guest.setAllowTransparency allowtransparency guestInstances[id]?.guest.setAllowTransparency allowtransparency
# Returns WebContents from its guest id. # Returns WebContents from its guest id.

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