commit
e22cb0ca9f
809 changed files with 55169 additions and 18812 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,6 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.tags*
|
||||||
|
/.idea/
|
||||||
/build/
|
/build/
|
||||||
/dist/
|
/dist/
|
||||||
/external_binaries/
|
/external_binaries/
|
||||||
|
|
|
@ -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
24
CODE_OF_CONDUCT.md
Normal 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
80
CONTRIBUTING-ko.md
Normal 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(코드 검사기)의 경고를 제거했을 때
|
|
@ -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
|
||||||
|
@ -29,7 +30,8 @@ possible with your report. If you can, please include:
|
||||||
* Include screenshots and animated GIFs in your pull request whenever possible.
|
* Include screenshots and animated GIFs in your pull request whenever possible.
|
||||||
* Follow the CoffeeScript, JavaScript, C++ and Python [coding style defined in docs](/docs/development/coding-style.md).
|
* Follow the CoffeeScript, JavaScript, C++ and Python [coding style defined in docs](/docs/development/coding-style.md).
|
||||||
* Write documentation in [Markdown](https://daringfireball.net/projects/markdown).
|
* Write documentation in [Markdown](https://daringfireball.net/projects/markdown).
|
||||||
* Use short, present tense commit messages. See [Commit Message Styleguide](#git-commit-messages-styleguide).
|
See the [Documentation Styleguide](/docs/styleguide.md).
|
||||||
|
* Use short, present tense commit messages. See [Commit Message Styleguide](#git-commit-messages).
|
||||||
|
|
||||||
## Styleguides
|
## Styleguides
|
||||||
|
|
||||||
|
@ -56,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
|
||||||
|
|
63
README-ko.md
63
README-ko.md
|
@ -1,29 +1,39 @@
|
||||||
[![Electron Logo](http://electron.atom.io/images/electron-logo.svg)](http://electron.atom.io/)
|
[![Electron Logo](http://electron.atom.io/images/electron-logo.svg)](http://electron.atom.io/)
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/atom/electron.svg?branch=master)](https://travis-ci.org/atom/electron)
|
[![Build Status](https://travis-ci.org/atom/electron.svg?branch=master)](https://travis-ci.org/atom/electron)
|
||||||
[![devDependency Status](https://david-dm.org/atom/electron/dev-status.svg)](https://david-dm.org/atom/electron#info=devDependencies)
|
[![devDependency Status](https://david-dm.org/atom/electron/dev-status.svg)](https://david-dm.org/atom/electron#info=devDependencies)
|
||||||
|
[![Join the Electron Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/)
|
||||||
|
|
||||||
### [Electron](https://github.com/atom/electron/) 한국어 참조문서
|
### [Electron](https://github.com/atom/electron/) 한국어 참조문서
|
||||||
|
|
||||||
:zap: *이전까지 Atom Shell로 알려져 있었습니다* :zap:
|
:zap: *프레임워크 이름이 Atom Shell에서 Electron으로 변경되었습니다* :zap:
|
||||||
|
|
||||||
|
Electron 프레임워크는 JavaScript, HTML 그리고 CSS를 사용하여
|
||||||
|
Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주는 프레임워크입니다.
|
||||||
|
[Node.js](https://nodejs.org/)와 [Chromium](http://www.chromium.org)을 기반으로
|
||||||
|
만들어졌으며 [Atom Editor](https://github.com/atom/atom)에 사용되고 있습니다.
|
||||||
|
|
||||||
Electron은 JavaScript, HTML 그리고 CSS를 이용하여 Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주는 프레임워크입니다. 이 프레임워크는 [io.js](http://iojs.org) 와
|
Electron에 대한 중요한 알림을 받고 싶다면 Twitter에서
|
||||||
[Chromium](http://www.chromium.org) 을 기반으로 만들어 졌으며 [Atom Editor](https://github.com/atom/atom) 에 사용되고 있습니다.
|
[@ElectronJS](https://twitter.com/electronjs)를 팔로우 하세요.
|
||||||
|
|
||||||
Electron에 대한 중요한 알림을 받으려면 Twitter에서 [@ElectronJS](https://twitter.com/electronjs)를 Follow하세요.
|
이 프로젝트는 기여자 규약 [행동강령](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` 커맨드를 등록하고 전역에 설치합니다.
|
||||||
npm install electron-prebuilt -g
|
npm install electron-prebuilt -g
|
||||||
|
|
||||||
# 개발용 dependency로 설치합니다.
|
# 개발 의존성 모듈 형태로 설치합니다.
|
||||||
npm install electron-prebuilt --save-dev
|
npm install electron-prebuilt --save-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -31,13 +41,38 @@ npm install electron-prebuilt --save-dev
|
||||||
|
|
||||||
- [China](https://npm.taobao.org/mirrors/electron)
|
- [China](https://npm.taobao.org/mirrors/electron)
|
||||||
|
|
||||||
## 참조문서
|
## 참조 문서
|
||||||
|
|
||||||
[docs](https://github.com/atom/electron/tree/master/docs/README-ko.md) 에 프레임워크 사용 가이드와 API 레퍼런스가 있습니다.
|
[Docs](https://github.com/atom/electron/tree/master/docs/README.md)에 개발 지침과
|
||||||
추가적으로 Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법도 문서에 포함되어 있으니 참고하기 바랍니다.
|
API 레퍼런스가 있습니다. Electron을 빌드 하는 방법과 프로젝트에 기여하는법 또한 문서에
|
||||||
|
포함되어 있으니 참고하시기 바랍니다.
|
||||||
|
|
||||||
|
## 참조 문서 (번역)
|
||||||
|
|
||||||
|
- [브라질 포르투갈어](https://github.com/atom/electron/tree/master/docs-translations/pt-BR)
|
||||||
|
- [한국어](https://github.com/atom/electron/tree/master/docs-translations/ko-KR)
|
||||||
|
- [일본어](https://github.com/atom/electron/tree/master/docs-translations/jp)
|
||||||
|
- [스페인어](https://github.com/atom/electron/tree/master/docs-translations/es)
|
||||||
|
- [중국어 간체](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/uk-UA)
|
||||||
|
- [러시아어](https://github.com/atom/electron/tree/master/docs-translations/ru-RU)
|
||||||
|
|
||||||
|
## 시작하기
|
||||||
|
|
||||||
|
[`atom/electron-quick-start`](https://github.com/atom/electron-quick-start)
|
||||||
|
저장소를 클론하여 Electron을 간단히 접해볼 수 있습니다.
|
||||||
|
|
||||||
## 커뮤니티
|
## 커뮤니티
|
||||||
|
|
||||||
[Atom 포럼내의 `electron` 카테고리](http://discuss.atom.io/category/electron) 와 Freenode `#atom-shell` 채팅채널이 있습니다.
|
다음 링크를 통해 커뮤니티에 질문을 올리거나 토론을 나눌 수 있습니다:
|
||||||
|
|
||||||
[awesome-electron](https://github.com/sindresorhus/awesome-electron) 에 커뮤니티가 운영중인 유용한 예제 앱과 툴, 리소스가 있으니 한번 탐색해 보시기 바랍니다.
|
- Atom 포럼의 [`electron`](http://discuss.atom.io/c/electron) 카테고리
|
||||||
|
- Freenode 채팅의 `#atom-shell` 채널
|
||||||
|
- Slack의 [`Atom`](http://atom-slack.herokuapp.com/) 채널
|
||||||
|
- [`electron-br`](https://electron-br.slack.com) *(브라질 포르투갈어)* 커뮤니티
|
||||||
|
- [`electron-kr`](http://www.meetup.com/electron-kr/) *(한국어)* 커뮤니티
|
||||||
|
|
||||||
|
[awesome-electron](https://github.com/sindresorhus/awesome-electron) 프로젝트에
|
||||||
|
커뮤니티가 운영중인 유용한 예제 어플리케이션과 도구, 리소스가 있으니 한번 참고해 보시기
|
||||||
|
바랍니다.
|
||||||
|
|
40
README.md
40
README.md
|
@ -4,22 +4,23 @@
|
||||||
[![devDependency Status](https://david-dm.org/atom/electron/dev-status.svg)](https://david-dm.org/atom/electron#info=devDependencies)
|
[![devDependency Status](https://david-dm.org/atom/electron/dev-status.svg)](https://david-dm.org/atom/electron#info=devDependencies)
|
||||||
[![Join the Electron Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/)
|
[![Join the Electron Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/)
|
||||||
|
|
||||||
: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 unacceptable behavior to atom@github.com.
|
By participating, you are expected to uphold this code. Please report unacceptable
|
||||||
|
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
|
||||||
|
@ -43,9 +44,32 @@ Guides and the API reference are located in the
|
||||||
[docs](https://github.com/atom/electron/tree/master/docs) directory. It also
|
[docs](https://github.com/atom/electron/tree/master/docs) directory. It also
|
||||||
contains documents describing how to build and contribute to Electron.
|
contains documents describing how to build and contribute to Electron.
|
||||||
|
|
||||||
|
## Documentation Translations
|
||||||
|
|
||||||
|
- [Brazilian Portuguese](https://github.com/atom/electron/tree/master/docs-translations/pt-BR)
|
||||||
|
- [Korean](https://github.com/atom/electron/tree/master/docs-translations/ko-KR)
|
||||||
|
- [Japanese](https://github.com/atom/electron/tree/master/docs-translations/jp)
|
||||||
|
- [Spanish](https://github.com/atom/electron/tree/master/docs-translations/es)
|
||||||
|
- [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)
|
||||||
|
- [Ukrainian](https://github.com/atom/electron/tree/master/docs-translations/uk-UA)
|
||||||
|
- [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
|
||||||
|
|
||||||
There is an [`electron` category on the Atom forums](http://discuss.atom.io/category/electron)
|
You can ask questions and interact with the community in the following
|
||||||
as well as an `#atom-shell` channel on Freenode.
|
locations:
|
||||||
|
- [`electron`](http://discuss.atom.io/c/electron) category on the Atom
|
||||||
|
forums
|
||||||
|
- `#atom-shell` channel on Freenode
|
||||||
|
- [`Atom`](http://atom-slack.herokuapp.com/) channel on Slack
|
||||||
|
- [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)*
|
||||||
|
- [`electron-kr`](http://www.meetup.com/electron-kr/) *(Korean)*
|
||||||
|
|
||||||
Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron) for a community maintained list of useful example apps, tools and resources.
|
Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron)
|
||||||
|
for a community maintained list of useful example apps, tools and resources.
|
||||||
|
|
23
appveyor.yml
Normal file
23
appveyor.yml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# appveyor file
|
||||||
|
# http://www.appveyor.com/docs/appveyor-yml
|
||||||
|
version: "{build}"
|
||||||
|
|
||||||
|
init:
|
||||||
|
- git config --global core.autocrlf input
|
||||||
|
|
||||||
|
platform:
|
||||||
|
- x86
|
||||||
|
- x64
|
||||||
|
|
||||||
|
install:
|
||||||
|
- cmd: SET PATH=C:\Program Files (x86)\MSBuild\12.0\bin\;%PATH%
|
||||||
|
- cmd: SET PATH=C:\python27;%PATH%
|
||||||
|
- cmd: python script/cibuild
|
||||||
|
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
|
||||||
|
# disable build and test pahses
|
||||||
|
build: off
|
||||||
|
test: off
|
156
atom.gyp
156
atom.gyp
|
@ -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.30.4',
|
'version%': '0.36.6',
|
||||||
},
|
},
|
||||||
'includes': [
|
'includes': [
|
||||||
'filenames.gypi',
|
'filenames.gypi',
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
'target_name': '<(project_name)',
|
'target_name': '<(project_name)',
|
||||||
'type': 'executable',
|
'type': 'executable',
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
'compile_coffee',
|
'js2asar',
|
||||||
'<(project_name)_lib',
|
'<(project_name)_lib',
|
||||||
],
|
],
|
||||||
'sources': [
|
'sources': [
|
||||||
|
@ -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,10 +106,20 @@
|
||||||
'<@(locale_dirs)',
|
'<@(locale_dirs)',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
}, { # OS=="mac"
|
'conditions': [
|
||||||
'dependencies': [
|
['mas_build==0', {
|
||||||
'make_locale_paks',
|
'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"
|
||||||
['OS=="win"', {
|
['OS=="win"', {
|
||||||
|
@ -144,7 +151,7 @@
|
||||||
'destination': '<(PRODUCT_DIR)',
|
'destination': '<(PRODUCT_DIR)',
|
||||||
'files': [
|
'files': [
|
||||||
'<@(copied_libraries)',
|
'<@(copied_libraries)',
|
||||||
'<(libchromiumcontent_dir)/ffmpegsumo.dll',
|
'<(libchromiumcontent_dir)/locales',
|
||||||
'<(libchromiumcontent_dir)/libEGL.dll',
|
'<(libchromiumcontent_dir)/libEGL.dll',
|
||||||
'<(libchromiumcontent_dir)/libGLESv2.dll',
|
'<(libchromiumcontent_dir)/libGLESv2.dll',
|
||||||
'<(libchromiumcontent_dir)/icudtl.dat',
|
'<(libchromiumcontent_dir)/icudtl.dat',
|
||||||
|
@ -193,7 +200,7 @@
|
||||||
'destination': '<(PRODUCT_DIR)',
|
'destination': '<(PRODUCT_DIR)',
|
||||||
'files': [
|
'files': [
|
||||||
'<@(copied_libraries)',
|
'<@(copied_libraries)',
|
||||||
'<(libchromiumcontent_dir)/libffmpegsumo.so',
|
'<(libchromiumcontent_dir)/locales',
|
||||||
'<(libchromiumcontent_dir)/icudtl.dat',
|
'<(libchromiumcontent_dir)/icudtl.dat',
|
||||||
'<(libchromiumcontent_dir)/content_shell.pak',
|
'<(libchromiumcontent_dir)/content_shell.pak',
|
||||||
'<(libchromiumcontent_dir)/natives_blob.bin',
|
'<(libchromiumcontent_dir)/natives_blob.bin',
|
||||||
|
@ -214,7 +221,7 @@
|
||||||
'target_name': '<(project_name)_lib',
|
'target_name': '<(project_name)_lib',
|
||||||
'type': 'static_library',
|
'type': 'static_library',
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
'atom_coffee2c',
|
'atom_js2c',
|
||||||
'vendor/brightray/brightray.gyp:brightray',
|
'vendor/brightray/brightray.gyp:brightray',
|
||||||
'vendor/node/node.gyp:node',
|
'vendor/node/node.gyp:node',
|
||||||
],
|
],
|
||||||
|
@ -226,8 +233,8 @@
|
||||||
# Defined in Chromium but not exposed in its gyp file.
|
# Defined in Chromium but not exposed in its gyp file.
|
||||||
'V8_USE_EXTERNAL_STARTUP_DATA',
|
'V8_USE_EXTERNAL_STARTUP_DATA',
|
||||||
'ENABLE_PLUGINS',
|
'ENABLE_PLUGINS',
|
||||||
# Needed by Node.
|
'ENABLE_PEPPER_CDMS',
|
||||||
'NODE_WANT_INTERNALS=1',
|
'USE_PROPRIETARY_CODECS',
|
||||||
],
|
],
|
||||||
'sources': [
|
'sources': [
|
||||||
'<@(lib_sources)',
|
'<@(lib_sources)',
|
||||||
|
@ -249,6 +256,12 @@
|
||||||
'vendor/node/deps/cares/include',
|
'vendor/node/deps/cares/include',
|
||||||
# The `third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h` is using `platform/PlatformExport.h`.
|
# The `third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h` is using `platform/PlatformExport.h`.
|
||||||
'<(libchromiumcontent_src_dir)/third_party/WebKit/Source',
|
'<(libchromiumcontent_src_dir)/third_party/WebKit/Source',
|
||||||
|
# The 'third_party/libyuv/include/libyuv/scale_argb.h' is using 'libyuv/basic_types.h'.
|
||||||
|
'<(libchromiumcontent_src_dir)/third_party/libyuv/include',
|
||||||
|
# The 'third_party/webrtc/modules/desktop_capture/desktop_frame.h' is using 'webrtc/base/scoped_ptr.h'.
|
||||||
|
'<(libchromiumcontent_src_dir)/third_party/',
|
||||||
|
'<(libchromiumcontent_src_dir)/components/cdm',
|
||||||
|
'<(libchromiumcontent_src_dir)/third_party/widevine',
|
||||||
],
|
],
|
||||||
'direct_dependent_settings': {
|
'direct_dependent_settings': {
|
||||||
'include_dirs': [
|
'include_dirs': [
|
||||||
|
@ -275,6 +288,7 @@
|
||||||
'-lcomctl32.lib',
|
'-lcomctl32.lib',
|
||||||
'-lcomdlg32.lib',
|
'-lcomdlg32.lib',
|
||||||
'-lwininet.lib',
|
'-lwininet.lib',
|
||||||
|
'-lwinmm.lib',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
|
@ -289,12 +303,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': [
|
||||||
|
@ -321,11 +351,11 @@
|
||||||
],
|
],
|
||||||
}, # target <(product_name)_lib
|
}, # target <(product_name)_lib
|
||||||
{
|
{
|
||||||
'target_name': 'compile_coffee',
|
'target_name': 'js2asar',
|
||||||
'type': 'none',
|
'type': 'none',
|
||||||
'actions': [
|
'actions': [
|
||||||
{
|
{
|
||||||
'action_name': 'compile_coffee',
|
'action_name': 'js2asar',
|
||||||
'variables': {
|
'variables': {
|
||||||
'conditions': [
|
'conditions': [
|
||||||
['OS=="mac"', {
|
['OS=="mac"', {
|
||||||
|
@ -336,41 +366,41 @@
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'inputs': [
|
'inputs': [
|
||||||
'<@(coffee_sources)',
|
'<@(js_sources)',
|
||||||
],
|
],
|
||||||
'outputs': [
|
'outputs': [
|
||||||
'<(resources_path)/atom.asar',
|
'<(resources_path)/atom.asar',
|
||||||
],
|
],
|
||||||
'action': [
|
'action': [
|
||||||
'python',
|
'python',
|
||||||
'tools/coffee2asar.py',
|
'tools/js2asar.py',
|
||||||
'<@(_outputs)',
|
'<@(_outputs)',
|
||||||
'<@(_inputs)',
|
'<@(_inputs)',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
}, # target compile_coffee
|
}, # target js2asar
|
||||||
{
|
{
|
||||||
'target_name': 'atom_coffee2c',
|
'target_name': 'atom_js2c',
|
||||||
'type': 'none',
|
'type': 'none',
|
||||||
'actions': [
|
'actions': [
|
||||||
{
|
{
|
||||||
'action_name': 'atom_coffee2c',
|
'action_name': 'atom_js2c',
|
||||||
'inputs': [
|
'inputs': [
|
||||||
'<@(coffee2c_sources)',
|
'<@(js2c_sources)',
|
||||||
],
|
],
|
||||||
'outputs': [
|
'outputs': [
|
||||||
'<(SHARED_INTERMEDIATE_DIR)/atom_natives.h',
|
'<(SHARED_INTERMEDIATE_DIR)/atom_natives.h',
|
||||||
],
|
],
|
||||||
'action': [
|
'action': [
|
||||||
'python',
|
'python',
|
||||||
'tools/coffee2c.py',
|
'tools/js2c.py',
|
||||||
'<@(_outputs)',
|
'<@(_outputs)',
|
||||||
'<@(_inputs)',
|
'<@(_inputs)',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
}, # target atom_coffee2c
|
}, # target atom_js2c
|
||||||
],
|
],
|
||||||
'conditions': [
|
'conditions': [
|
||||||
['OS=="mac"', {
|
['OS=="mac"', {
|
||||||
|
@ -397,9 +427,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,
|
||||||
|
@ -441,13 +468,6 @@
|
||||||
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Libraries',
|
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Libraries',
|
||||||
'files': [
|
'files': [
|
||||||
'<@(copied_libraries)',
|
'<@(copied_libraries)',
|
||||||
'<(libchromiumcontent_dir)/ffmpegsumo.so',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Resources',
|
|
||||||
'files': [
|
|
||||||
'<(PRODUCT_DIR)/crashpad_handler',
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -462,6 +482,16 @@
|
||||||
'${BUILT_PRODUCTS_DIR}/<(product_name) Framework.framework/Versions/A/<(product_name) Framework',
|
'${BUILT_PRODUCTS_DIR}/<(product_name) Framework.framework/Versions/A/<(product_name) Framework',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'postbuild_name': 'Fix path of ffmpeg',
|
||||||
|
'action': [
|
||||||
|
'install_name_tool',
|
||||||
|
'-change',
|
||||||
|
'@loader_path/libffmpeg.dylib',
|
||||||
|
'@rpath/libffmpeg.dylib',
|
||||||
|
'${BUILT_PRODUCTS_DIR}/<(product_name) Framework.framework/Versions/A/<(product_name) Framework',
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'postbuild_name': 'Add symlinks for framework subdirectories',
|
'postbuild_name': 'Add symlinks for framework subdirectories',
|
||||||
'action': [
|
'action': [
|
||||||
|
@ -470,6 +500,35 @@
|
||||||
'Libraries',
|
'Libraries',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'postbuild_name': 'Copy locales',
|
||||||
|
'action': [
|
||||||
|
'tools/mac/copy-locales.py',
|
||||||
|
'-d',
|
||||||
|
'<(libchromiumcontent_dir)/locales',
|
||||||
|
'${BUILT_PRODUCTS_DIR}/<(product_name) Framework.framework/Resources',
|
||||||
|
'<@(locales)',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'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
|
||||||
{
|
{
|
||||||
|
@ -495,31 +554,6 @@
|
||||||
},
|
},
|
||||||
}, # target helper
|
}, # target helper
|
||||||
],
|
],
|
||||||
}, { # OS=="mac"
|
|
||||||
'targets': [
|
|
||||||
{
|
|
||||||
'target_name': 'make_locale_paks',
|
|
||||||
'type': 'none',
|
|
||||||
'actions': [
|
|
||||||
{
|
|
||||||
'action_name': 'Make Empty Paks',
|
|
||||||
'inputs': [
|
|
||||||
'tools/make_locale_paks.py',
|
|
||||||
],
|
|
||||||
'outputs': [
|
|
||||||
'<(PRODUCT_DIR)/locales'
|
|
||||||
],
|
|
||||||
'action': [
|
|
||||||
'python',
|
|
||||||
'tools/make_locale_paks.py',
|
|
||||||
'<(PRODUCT_DIR)',
|
|
||||||
'<@(locales)',
|
|
||||||
],
|
|
||||||
'msvs_cygwin_shell': 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}], # OS!="mac"
|
}], # OS!="mac"
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,25 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "atom/common/atom_version.h"
|
||||||
#include "atom/common/chrome_version.h"
|
#include "atom/common/chrome_version.h"
|
||||||
#include "atom/common/options_switches.h"
|
#include "atom/common/options_switches.h"
|
||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
|
#include "base/files/file_util.h"
|
||||||
#include "base/strings/string_split.h"
|
#include "base/strings/string_split.h"
|
||||||
#include "base/strings/string_util.h"
|
#include "base/strings/string_util.h"
|
||||||
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "content/public/common/content_constants.h"
|
#include "content/public/common/content_constants.h"
|
||||||
#include "content/public/common/pepper_plugin_info.h"
|
#include "content/public/common/pepper_plugin_info.h"
|
||||||
|
#include "content/public/common/user_agent.h"
|
||||||
#include "ppapi/shared_impl/ppapi_permissions.h"
|
#include "ppapi/shared_impl/ppapi_permissions.h"
|
||||||
|
#include "third_party/widevine/cdm/stub/widevine_cdm_version.h"
|
||||||
|
#include "ui/base/l10n/l10n_util.h"
|
||||||
|
#include "url/url_constants.h"
|
||||||
|
|
||||||
|
#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS)
|
||||||
|
#include "chrome/common/widevine_cdm_constants.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
|
@ -29,8 +40,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. :(
|
||||||
|
@ -45,7 +56,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,
|
||||||
|
@ -60,35 +71,59 @@ content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path,
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS)
|
||||||
|
content::PepperPluginInfo CreateWidevineCdmInfo(const base::FilePath& path,
|
||||||
|
const std::string& version) {
|
||||||
|
content::PepperPluginInfo widevine_cdm;
|
||||||
|
widevine_cdm.is_out_of_process = true;
|
||||||
|
widevine_cdm.path = path;
|
||||||
|
widevine_cdm.name = kWidevineCdmDisplayName;
|
||||||
|
widevine_cdm.description = kWidevineCdmDescription +
|
||||||
|
std::string(" (version: ") +
|
||||||
|
version + ")";
|
||||||
|
widevine_cdm.version = version;
|
||||||
|
content::WebPluginMimeType widevine_cdm_mime_type(
|
||||||
|
kWidevineCdmPluginMimeType,
|
||||||
|
kWidevineCdmPluginExtension,
|
||||||
|
kWidevineCdmPluginMimeTypeDescription);
|
||||||
|
|
||||||
|
// Add the supported codecs as if they came from the component manifest.
|
||||||
|
std::vector<std::string> codecs;
|
||||||
|
codecs.push_back(kCdmSupportedCodecVorbis);
|
||||||
|
codecs.push_back(kCdmSupportedCodecVp8);
|
||||||
|
codecs.push_back(kCdmSupportedCodecVp9);
|
||||||
|
#if defined(USE_PROPRIETARY_CODECS)
|
||||||
|
codecs.push_back(kCdmSupportedCodecAac);
|
||||||
|
codecs.push_back(kCdmSupportedCodecAvc1);
|
||||||
|
#endif // defined(USE_PROPRIETARY_CODECS)
|
||||||
|
std::string codec_string = base::JoinString(
|
||||||
|
codecs, std::string(1, kCdmSupportedCodecsValueDelimiter));
|
||||||
|
widevine_cdm_mime_type.additional_param_names.push_back(
|
||||||
|
base::ASCIIToUTF16(kCdmSupportedCodecsParamName));
|
||||||
|
widevine_cdm_mime_type.additional_param_values.push_back(
|
||||||
|
base::ASCIIToUTF16(codec_string));
|
||||||
|
|
||||||
|
widevine_cdm.mime_types.push_back(widevine_cdm_mime_type);
|
||||||
|
widevine_cdm.permissions = kWidevineCdmPluginPermissions;
|
||||||
|
|
||||||
|
return widevine_cdm;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void ConvertStringWithSeparatorToVector(std::vector<std::string>* vec,
|
||||||
|
const char* separator,
|
||||||
|
const char* cmd_switch) {
|
||||||
|
auto command_line = base::CommandLine::ForCurrentProcess();
|
||||||
|
auto string_with_separator = command_line->GetSwitchValueASCII(cmd_switch);
|
||||||
|
if (!string_with_separator.empty())
|
||||||
|
*vec = base::SplitString(string_with_separator, separator,
|
||||||
|
base::TRIM_WHITESPACE,
|
||||||
|
base::SPLIT_WANT_NONEMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
AtomContentClient::AtomContentClient() {
|
void AddPepperFlashFromCommandLine(
|
||||||
}
|
|
||||||
|
|
||||||
AtomContentClient::~AtomContentClient() {
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string AtomContentClient::GetProduct() const {
|
|
||||||
return "Chrome/" CHROME_VERSION_STRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AtomContentClient::AddAdditionalSchemes(
|
|
||||||
std::vector<std::string>* standard_schemes,
|
|
||||||
std::vector<std::string>* savable_schemes) {
|
|
||||||
auto command_line = base::CommandLine::ForCurrentProcess();
|
|
||||||
auto custom_schemes = command_line->GetSwitchValueASCII(
|
|
||||||
switches::kRegisterStandardSchemes);
|
|
||||||
if (!custom_schemes.empty()) {
|
|
||||||
std::vector<std::string> schemes;
|
|
||||||
base::SplitString(custom_schemes, ',', &schemes);
|
|
||||||
standard_schemes->insert(standard_schemes->end(),
|
|
||||||
schemes.begin(),
|
|
||||||
schemes.end());
|
|
||||||
}
|
|
||||||
standard_schemes->push_back("chrome-extension");
|
|
||||||
}
|
|
||||||
|
|
||||||
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->GetSwitchValueNative(
|
||||||
|
@ -103,4 +138,79 @@ void AtomContentClient::AddPepperPlugins(
|
||||||
CreatePepperFlashInfo(base::FilePath(flash_path), flash_version));
|
CreatePepperFlashInfo(base::FilePath(flash_path), flash_version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS)
|
||||||
|
void AddWidevineCdmFromCommandLine(
|
||||||
|
std::vector<content::PepperPluginInfo>* plugins) {
|
||||||
|
auto command_line = base::CommandLine::ForCurrentProcess();
|
||||||
|
auto widevine_cdm_path = command_line->GetSwitchValueNative(
|
||||||
|
switches::kWidevineCdmPath);
|
||||||
|
if (widevine_cdm_path.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!base::PathExists(base::FilePath(widevine_cdm_path)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto widevine_cdm_version = command_line->GetSwitchValueASCII(
|
||||||
|
switches::kWidevineCdmVersion);
|
||||||
|
if (widevine_cdm_version.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
plugins->push_back(CreateWidevineCdmInfo(base::FilePath(widevine_cdm_path),
|
||||||
|
widevine_cdm_version));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
AtomContentClient::AtomContentClient() {
|
||||||
|
}
|
||||||
|
|
||||||
|
AtomContentClient::~AtomContentClient() {
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AtomContentClient::GetProduct() const {
|
||||||
|
return "Chrome/" CHROME_VERSION_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AtomContentClient::GetUserAgent() const {
|
||||||
|
return content::BuildUserAgentFromProduct(
|
||||||
|
"Chrome/" CHROME_VERSION_STRING " "
|
||||||
|
ATOM_PRODUCT_NAME "/" ATOM_VERSION_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
base::string16 AtomContentClient::GetLocalizedString(int message_id) const {
|
||||||
|
return l10n_util::GetStringUTF16(message_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AtomContentClient::AddAdditionalSchemes(
|
||||||
|
std::vector<url::SchemeWithType>* standard_schemes,
|
||||||
|
std::vector<std::string>* savable_schemes) {
|
||||||
|
std::vector<std::string> schemes;
|
||||||
|
ConvertStringWithSeparatorToVector(&schemes, ",",
|
||||||
|
switches::kRegisterStandardSchemes);
|
||||||
|
if (!schemes.empty()) {
|
||||||
|
for (const std::string& scheme : schemes)
|
||||||
|
standard_schemes->push_back({scheme.c_str(), url::SCHEME_WITHOUT_PORT});
|
||||||
|
}
|
||||||
|
standard_schemes->push_back({"chrome-extension", url::SCHEME_WITHOUT_PORT});
|
||||||
|
}
|
||||||
|
|
||||||
|
void AtomContentClient::AddPepperPlugins(
|
||||||
|
std::vector<content::PepperPluginInfo>* plugins) {
|
||||||
|
AddPepperFlashFromCommandLine(plugins);
|
||||||
|
#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS)
|
||||||
|
AddWidevineCdmFromCommandLine(plugins);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void AtomContentClient::AddServiceWorkerSchemes(
|
||||||
|
std::set<std::string>* service_worker_schemes) {
|
||||||
|
std::vector<std::string> schemes;
|
||||||
|
ConvertStringWithSeparatorToVector(&schemes, ",",
|
||||||
|
switches::kRegisterServiceWorkerSchemes);
|
||||||
|
if (!schemes.empty()) {
|
||||||
|
for (const std::string& scheme : schemes)
|
||||||
|
service_worker_schemes->insert(scheme);
|
||||||
|
}
|
||||||
|
service_worker_schemes->insert(url::kFileScheme);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace atom
|
} // namespace atom
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#ifndef ATOM_APP_ATOM_CONTENT_CLIENT_H_
|
#ifndef ATOM_APP_ATOM_CONTENT_CLIENT_H_
|
||||||
#define ATOM_APP_ATOM_CONTENT_CLIENT_H_
|
#define ATOM_APP_ATOM_CONTENT_CLIENT_H_
|
||||||
|
|
||||||
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -20,11 +21,15 @@ class AtomContentClient : public brightray::ContentClient {
|
||||||
protected:
|
protected:
|
||||||
// content::ContentClient:
|
// content::ContentClient:
|
||||||
std::string GetProduct() const override;
|
std::string GetProduct() const override;
|
||||||
|
std::string GetUserAgent() const override;
|
||||||
|
base::string16 GetLocalizedString(int message_id) 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;
|
||||||
|
void AddServiceWorkerSchemes(
|
||||||
|
std::set<std::string>* service_worker_schemes) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_COPY_AND_ASSIGN(AtomContentClient);
|
DISALLOW_COPY_AND_ASSIGN(AtomContentClient);
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -5,13 +5,8 @@
|
||||||
#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 <io.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <shellscalingapi.h>
|
#include <shellscalingapi.h>
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
|
@ -33,12 +28,30 @@
|
||||||
|
|
||||||
#include "atom/app/node_main.h"
|
#include "atom/app/node_main.h"
|
||||||
#include "atom/common/atom_command_line.h"
|
#include "atom/common/atom_command_line.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)
|
||||||
// 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);
|
||||||
|
@ -76,24 +89,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 (!IsEnvSet("TERM") && !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
|
||||||
|
@ -130,15 +141,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::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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,9 +170,9 @@ 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;
|
||||||
return atom::NodeMain(argc, const_cast<char**>(argv));
|
return atom::NodeMain(argc, const_cast<char**>(argv));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,8 +187,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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,22 @@
|
||||||
#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/l10n/l10n_util.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 +39,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;
|
||||||
|
@ -38,16 +56,32 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||||
#else
|
#else
|
||||||
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
|
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
|
||||||
#endif // defined(DEBUG)
|
#endif // defined(DEBUG)
|
||||||
#endif // defined(OS_WIN)
|
#else // defined(OS_WIN)
|
||||||
|
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
|
||||||
|
#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);
|
||||||
}
|
}
|
||||||
|
@ -69,16 +103,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);
|
||||||
|
|
||||||
|
@ -111,16 +138,4 @@ scoped_ptr<brightray::ContentClient> AtomMainDelegate::CreateContentClient() {
|
||||||
return scoped_ptr<brightray::ContentClient>(new AtomContentClient).Pass();
|
return scoped_ptr<brightray::ContentClient>(new AtomContentClient).Pass();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtomMainDelegate::AddDataPackFromPath(
|
|
||||||
ui::ResourceBundle* bundle, const base::FilePath& pak_dir) {
|
|
||||||
#if defined(OS_WIN)
|
|
||||||
bundle->AddDataPackFromPath(
|
|
||||||
pak_dir.Append(FILE_PATH_LITERAL("ui_resources_200_percent.pak")),
|
|
||||||
ui::SCALE_FACTOR_200P);
|
|
||||||
bundle->AddDataPackFromPath(
|
|
||||||
pak_dir.Append(FILE_PATH_LITERAL("content_resources_200_percent.pak")),
|
|
||||||
ui::SCALE_FACTOR_200P);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace atom
|
} // namespace atom
|
||||||
|
|
|
@ -25,8 +25,6 @@ class AtomMainDelegate : public brightray::MainDelegate {
|
||||||
|
|
||||||
// brightray::MainDelegate:
|
// brightray::MainDelegate:
|
||||||
scoped_ptr<brightray::ContentClient> CreateContentClient() override;
|
scoped_ptr<brightray::ContentClient> CreateContentClient() override;
|
||||||
void AddDataPackFromPath(
|
|
||||||
ui::ResourceBundle* bundle, const base::FilePath& pak_dir) override;
|
|
||||||
#if defined(OS_MACOSX)
|
#if defined(OS_MACOSX)
|
||||||
void OverrideChildProcessPath() override;
|
void OverrideChildProcessPath() override;
|
||||||
void OverrideFrameworkBundlePath() override;
|
void OverrideFrameworkBundlePath() override;
|
||||||
|
|
|
@ -4,42 +4,48 @@
|
||||||
|
|
||||||
#include "atom/app/node_main.h"
|
#include "atom/app/node_main.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 "base/command_line.h"
|
||||||
#include "atom/common/node_includes.h"
|
#include "atom/common/node_includes.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"
|
||||||
|
#include "gin/v8_initializer.h"
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
int NodeMain(int argc, char *argv[]) {
|
int NodeMain(int argc, char *argv[]) {
|
||||||
argv = uv_setup_args(argc, argv);
|
base::CommandLine::Init(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;
|
||||||
{
|
{
|
||||||
gin::IsolateHolder::LoadV8Snapshot();
|
// Feed gin::PerIsolateData with a task runner.
|
||||||
gin::IsolateHolder::Initialize(
|
argv = uv_setup_args(argc, argv);
|
||||||
gin::IsolateHolder::kNonStrictMode,
|
uv_loop_t* loop = uv_default_loop();
|
||||||
gin::ArrayBufferAllocator::SharedInstance());
|
scoped_refptr<UvTaskRunner> uv_task_runner(new UvTaskRunner(loop));
|
||||||
|
base::ThreadTaskRunnerHandle handle(uv_task_runner);
|
||||||
|
|
||||||
|
gin::V8Initializer::LoadV8Snapshot();
|
||||||
|
gin::V8Initializer::LoadV8Natives();
|
||||||
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(), uv_default_loop(), gin_env.context(), argc, argv,
|
gin_env.isolate(), loop, gin_env.context(), argc, argv,
|
||||||
exec_argc, exec_argv);
|
exec_argc, exec_argv);
|
||||||
|
|
||||||
// Start debugger.
|
// Start our custom debugger implementation.
|
||||||
node::node_isolate = gin_env.isolate();
|
NodeDebugger node_debugger(gin_env.isolate());
|
||||||
if (node::use_debug_agent)
|
if (node_debugger.IsRunning())
|
||||||
node::StartDebug(env, node::debug_wait_connect);
|
env->AssignToContext(v8::Debug::GetDebugContext());
|
||||||
|
|
||||||
node::LoadEnvironment(env);
|
node::LoadEnvironment(env);
|
||||||
|
|
||||||
// Enable debugger.
|
|
||||||
if (node::use_debug_agent)
|
|
||||||
node::EnableDebug(env);
|
|
||||||
|
|
||||||
bool more;
|
bool more;
|
||||||
do {
|
do {
|
||||||
more = uv_run(env->event_loop(), UV_RUN_ONCE);
|
more = uv_run(env->event_loop(), UV_RUN_ONCE);
|
||||||
|
|
60
atom/app/uv_task_runner.cc
Normal file
60
atom/app/uv_task_runner.cc
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright (c) 2015 GitHub, Inc.
|
||||||
|
// Use of this source code is governed by the MIT license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "atom/app/uv_task_runner.h"
|
||||||
|
|
||||||
|
#include "base/stl_util.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
UvTaskRunner::UvTaskRunner(uv_loop_t* loop) : loop_(loop) {
|
||||||
|
}
|
||||||
|
|
||||||
|
UvTaskRunner::~UvTaskRunner() {
|
||||||
|
for (auto& iter : tasks_) {
|
||||||
|
uv_unref(reinterpret_cast<uv_handle_t*>(iter.first));
|
||||||
|
delete iter.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UvTaskRunner::PostDelayedTask(const tracked_objects::Location& from_here,
|
||||||
|
const base::Closure& task,
|
||||||
|
base::TimeDelta delay) {
|
||||||
|
uv_timer_t* timer = new uv_timer_t;
|
||||||
|
timer->data = this;
|
||||||
|
uv_timer_init(loop_, timer);
|
||||||
|
uv_timer_start(timer, UvTaskRunner::OnTimeout, delay.InMilliseconds(), 0);
|
||||||
|
tasks_[timer] = task;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UvTaskRunner::RunsTasksOnCurrentThread() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UvTaskRunner::PostNonNestableDelayedTask(
|
||||||
|
const tracked_objects::Location& from_here,
|
||||||
|
const base::Closure& task,
|
||||||
|
base::TimeDelta delay) {
|
||||||
|
return PostDelayedTask(from_here, task, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void UvTaskRunner::OnTimeout(uv_timer_t* timer) {
|
||||||
|
UvTaskRunner* self = static_cast<UvTaskRunner*>(timer->data);
|
||||||
|
if (!ContainsKey(self->tasks_, timer))
|
||||||
|
return;
|
||||||
|
|
||||||
|
self->tasks_[timer].Run();
|
||||||
|
self->tasks_.erase(timer);
|
||||||
|
uv_timer_stop(timer);
|
||||||
|
uv_close(reinterpret_cast<uv_handle_t*>(timer), UvTaskRunner::OnClose);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void UvTaskRunner::OnClose(uv_handle_t* handle) {
|
||||||
|
delete reinterpret_cast<uv_timer_t*>(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace atom
|
45
atom/app/uv_task_runner.h
Normal file
45
atom/app/uv_task_runner.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// 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_APP_UV_TASK_RUNNER_H_
|
||||||
|
#define ATOM_APP_UV_TASK_RUNNER_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "base/callback.h"
|
||||||
|
#include "base/single_thread_task_runner.h"
|
||||||
|
#include "vendor/node/deps/uv/include/uv.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
// TaskRunner implementation that posts tasks into libuv's default loop.
|
||||||
|
class UvTaskRunner : public base::SingleThreadTaskRunner {
|
||||||
|
public:
|
||||||
|
explicit UvTaskRunner(uv_loop_t* loop);
|
||||||
|
~UvTaskRunner() override;
|
||||||
|
|
||||||
|
// base::SingleThreadTaskRunner:
|
||||||
|
bool PostDelayedTask(const tracked_objects::Location& from_here,
|
||||||
|
const base::Closure& task,
|
||||||
|
base::TimeDelta delay) override;
|
||||||
|
bool RunsTasksOnCurrentThread() const override;
|
||||||
|
bool PostNonNestableDelayedTask(
|
||||||
|
const tracked_objects::Location& from_here,
|
||||||
|
const base::Closure& task,
|
||||||
|
base::TimeDelta delay) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void OnTimeout(uv_timer_t* timer);
|
||||||
|
static void OnClose(uv_handle_t* handle);
|
||||||
|
|
||||||
|
uv_loop_t* loop_;
|
||||||
|
|
||||||
|
std::map<uv_timer_t*, base::Closure> tasks_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(UvTaskRunner);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
#endif // ATOM_APP_UV_TASK_RUNNER_H_
|
|
@ -7,35 +7,41 @@
|
||||||
#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/native_mate_converters/image_converter.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"
|
||||||
|
#include "ui/base/l10n/l10n_util.h"
|
||||||
|
#include "ui/gfx/image/image.h"
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
|
#include "ui/base/win/shell.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "atom/common/node_includes.h"
|
|
||||||
|
|
||||||
using atom::Browser;
|
using atom::Browser;
|
||||||
|
|
||||||
namespace mate {
|
namespace mate {
|
||||||
|
@ -61,21 +67,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 +90,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 +144,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);
|
||||||
}
|
}
|
||||||
|
@ -157,7 +184,13 @@ void App::OnWindowAllClosed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::OnQuit() {
|
void App::OnQuit() {
|
||||||
Emit("quit");
|
int exitCode = AtomBrowserMainParts::Get()->GetExitCode();
|
||||||
|
Emit("quit", exitCode);
|
||||||
|
|
||||||
|
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) {
|
||||||
|
@ -168,8 +201,8 @@ void App::OnOpenURL(const std::string& url) {
|
||||||
Emit("open-url", url);
|
Emit("open-url", url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::OnActivateWithNoOpenWindows() {
|
void App::OnActivate(bool has_visible_windows) {
|
||||||
Emit("activate-with-no-open-windows");
|
Emit("activate", has_visible_windows);
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::OnWillFinishLaunching() {
|
void App::OnWillFinishLaunching() {
|
||||||
|
@ -177,26 +210,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,18 +311,42 @@ 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v8::Local<v8::Value> App::DefaultSession(v8::Isolate* isolate) {
|
std::string App::GetLocale() {
|
||||||
if (default_session_.IsEmpty())
|
return l10n_util::GetApplicationLocale("");
|
||||||
return v8::Null(isolate);
|
}
|
||||||
else
|
|
||||||
return v8::Local<v8::Value>::New(isolate, default_session_);
|
#if defined(OS_WIN)
|
||||||
|
bool App::IsAeroGlassEnabled() {
|
||||||
|
return ui::win::IsAeroGlassEnabled();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool App::MakeSingleInstance(
|
||||||
|
const ProcessSingleton::NotificationCallback& callback) {
|
||||||
|
if (process_singleton_.get())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
base::FilePath user_dir;
|
||||||
|
PathService::Get(brightray::DIR_USER_DATA, &user_dir);
|
||||||
|
process_singleton_.reset(new ProcessSingleton(
|
||||||
|
user_dir, base::Bind(NotificationCallbackWrapper, callback)));
|
||||||
|
|
||||||
|
switch (process_singleton_->NotifyOtherProcessOrCreate()) {
|
||||||
|
case ProcessSingleton::NotifyResult::LOCK_ERROR:
|
||||||
|
case ProcessSingleton::NotifyResult::PROFILE_IN_USE:
|
||||||
|
case ProcessSingleton::NotifyResult::PROCESS_NOTIFIED:
|
||||||
|
process_singleton_.reset();
|
||||||
|
return true;
|
||||||
|
case ProcessSingleton::NotifyResult::PROCESS_NONE:
|
||||||
|
default: // Shouldn't be needed, but VS warns if it is not there.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
|
mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
|
||||||
|
@ -261,6 +354,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))
|
||||||
|
@ -271,15 +365,20 @@ 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))
|
||||||
|
.SetMethod("isAeroGlassEnabled", &App::IsAeroGlassEnabled)
|
||||||
#endif
|
#endif
|
||||||
.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",
|
||||||
.SetProperty("defaultSession", &App::DefaultSession);
|
&App::AllowNTLMCredentialsForAllDomains)
|
||||||
|
.SetMethod("getLocale", &App::GetLocale)
|
||||||
|
.SetMethod("makeSingleInstance", &App::MakeSingleInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
@ -296,6 +395,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);
|
||||||
|
@ -341,6 +450,7 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||||
dict.SetMethod("dockHide", base::Bind(&Browser::DockHide, browser));
|
dict.SetMethod("dockHide", base::Bind(&Browser::DockHide, browser));
|
||||||
dict.SetMethod("dockShow", base::Bind(&Browser::DockShow, browser));
|
dict.SetMethod("dockShow", base::Bind(&Browser::DockShow, browser));
|
||||||
dict.SetMethod("dockSetMenu", &DockSetMenu);
|
dict.SetMethod("dockSetMenu", &DockSetMenu);
|
||||||
|
dict.SetMethod("dockSetIcon", base::Bind(&Browser::DockSetIcon, browser));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
@ -41,10 +45,25 @@ class App : public mate::EventEmitter,
|
||||||
void OnQuit() override;
|
void OnQuit() override;
|
||||||
void OnOpenFile(bool* prevent_default, const std::string& file_path) override;
|
void OnOpenFile(bool* prevent_default, const std::string& file_path) override;
|
||||||
void OnOpenURL(const std::string& url) override;
|
void OnOpenURL(const std::string& url) override;
|
||||||
void OnActivateWithNoOpenWindows() 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,10 +83,16 @@ 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);
|
||||||
v8::Local<v8::Value> DefaultSession(v8::Isolate* isolate);
|
bool MakeSingleInstance(
|
||||||
|
const ProcessSingleton::NotificationCallback& callback);
|
||||||
|
std::string GetLocale();
|
||||||
|
|
||||||
v8::Global<v8::Value> default_session_;
|
#if defined(OS_WIN)
|
||||||
|
bool IsAeroGlassEnabled();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
scoped_ptr<ProcessSingleton> process_singleton_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(App);
|
DISALLOW_COPY_AND_ASSIGN(App);
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,12 +5,30 @@
|
||||||
#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 "native_mate/dictionary.h"
|
#include "native_mate/dictionary.h"
|
||||||
#include "native_mate/object_template_builder.h"
|
#include "native_mate/object_template_builder.h"
|
||||||
|
|
||||||
#include "atom/common/node_includes.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 {
|
||||||
|
|
||||||
|
@ -21,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() {
|
||||||
|
@ -43,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
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,39 +7,30 @@
|
||||||
|
|
||||||
#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/node_includes.h"
|
||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
#include "base/files/file_util.h"
|
#include "base/files/file_util.h"
|
||||||
#include "content/public/browser/tracing_controller.h"
|
#include "content/public/browser/tracing_controller.h"
|
||||||
#include "native_mate/dictionary.h"
|
#include "native_mate/dictionary.h"
|
||||||
|
|
||||||
#include "atom/common/node_includes.h"
|
|
||||||
|
|
||||||
using content::TracingController;
|
using content::TracingController;
|
||||||
|
|
||||||
namespace mate {
|
namespace mate {
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct Converter<base::trace_event::CategoryFilter> {
|
struct Converter<base::trace_event::TraceConfig> {
|
||||||
static bool FromV8(v8::Isolate* isolate,
|
static bool FromV8(v8::Isolate* isolate,
|
||||||
v8::Local<v8::Value> val,
|
v8::Local<v8::Value> val,
|
||||||
base::trace_event::CategoryFilter* out) {
|
base::trace_event::TraceConfig* out) {
|
||||||
std::string filter;
|
Dictionary options;
|
||||||
if (!ConvertFromV8(isolate, val, &filter))
|
|
||||||
return false;
|
|
||||||
*out = base::trace_event::CategoryFilter(filter);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct Converter<base::trace_event::TraceOptions> {
|
|
||||||
static bool FromV8(v8::Isolate* isolate,
|
|
||||||
v8::Local<v8::Value> val,
|
|
||||||
base::trace_event::TraceOptions* out) {
|
|
||||||
std::string options;
|
|
||||||
if (!ConvertFromV8(isolate, val, &options))
|
if (!ConvertFromV8(isolate, val, &options))
|
||||||
return false;
|
return false;
|
||||||
return out->SetFromString(options);
|
std::string category_filter, trace_options;
|
||||||
|
if (!options.Get("categoryFilter", &category_filter) ||
|
||||||
|
!options.Get("traceOptions", &trace_options))
|
||||||
|
return false;
|
||||||
|
*out = base::trace_event::TraceConfig(category_filter, trace_options);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#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/value_converter.h"
|
#include "atom/common/native_mate_converters/value_converter.h"
|
||||||
#include "base/bind.h"
|
|
||||||
#include "base/time/time.h"
|
#include "base/time/time.h"
|
||||||
#include "base/values.h"
|
#include "base/values.h"
|
||||||
#include "content/public/browser/browser_context.h"
|
#include "content/public/browser/browser_context.h"
|
||||||
|
@ -20,141 +19,21 @@
|
||||||
#include "net/url_request/url_request_context.h"
|
#include "net/url_request/url_request_context.h"
|
||||||
#include "net/url_request/url_request_context_getter.h"
|
#include "net/url_request/url_request_context_getter.h"
|
||||||
|
|
||||||
#include "atom/common/node_includes.h"
|
|
||||||
|
|
||||||
using atom::api::Cookies;
|
|
||||||
using content::BrowserThread;
|
using content::BrowserThread;
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
bool GetCookieListFromStore(
|
|
||||||
net::CookieStore* cookie_store,
|
|
||||||
const std::string& url,
|
|
||||||
const net::CookieMonster::GetCookieListCallback& callback) {
|
|
||||||
DCHECK(cookie_store);
|
|
||||||
GURL gurl(url);
|
|
||||||
net::CookieMonster* monster = cookie_store->GetCookieMonster();
|
|
||||||
// Empty url will match all url cookies.
|
|
||||||
if (url.empty()) {
|
|
||||||
monster->GetAllCookiesAsync(callback);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gurl.is_valid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
monster->GetAllCookiesForURLAsync(gurl, callback);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunGetCookiesCallbackOnUIThread(v8::Isolate* isolate,
|
|
||||||
const std::string& error_message,
|
|
||||||
const net::CookieList& cookie_list,
|
|
||||||
const Cookies::CookiesCallback& callback) {
|
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
||||||
|
|
||||||
v8::Locker locker(isolate);
|
|
||||||
v8::HandleScope handle_scope(isolate);
|
|
||||||
|
|
||||||
if (!error_message.empty()) {
|
|
||||||
v8::Local<v8::Value> error = mate::ConvertToV8(isolate, error_message);
|
|
||||||
callback.Run(error, v8::Null(isolate));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback.Run(v8::Null(isolate), mate::ConvertToV8(isolate, cookie_list));
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunRemoveCookiesCallbackOnUIThread(
|
|
||||||
v8::Isolate* isolate,
|
|
||||||
const std::string& error_message,
|
|
||||||
const Cookies::CookiesCallback& callback) {
|
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
||||||
|
|
||||||
v8::Locker locker(isolate);
|
|
||||||
v8::HandleScope handle_scope(isolate);
|
|
||||||
|
|
||||||
if (!error_message.empty()) {
|
|
||||||
v8::Local<v8::Value> error = mate::ConvertToV8(isolate, error_message);
|
|
||||||
callback.Run(error, v8::Null(isolate));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback.Run(v8::Null(isolate), v8::Null(isolate));
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunSetCookiesCallbackOnUIThread(v8::Isolate* isolate,
|
|
||||||
const std::string& error_message,
|
|
||||||
bool set_success,
|
|
||||||
const Cookies::CookiesCallback& callback) {
|
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
||||||
|
|
||||||
v8::Locker locker(isolate);
|
|
||||||
v8::HandleScope handle_scope(isolate);
|
|
||||||
|
|
||||||
if (!error_message.empty()) {
|
|
||||||
v8::Local<v8::Value> error = mate::ConvertToV8(isolate, error_message);
|
|
||||||
callback.Run(error, v8::Null(isolate));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!set_success) {
|
|
||||||
v8::Local<v8::Value> error = mate::ConvertToV8(
|
|
||||||
isolate, "Failed to set cookies");
|
|
||||||
callback.Run(error, v8::Null(isolate));
|
|
||||||
}
|
|
||||||
|
|
||||||
callback.Run(v8::Null(isolate), v8::Null(isolate));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MatchesDomain(const base::DictionaryValue* filter,
|
|
||||||
const std::string& cookie_domain) {
|
|
||||||
std::string filter_domain;
|
|
||||||
if (!filter->GetString("domain", &filter_domain))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Add a leading '.' character to the filter domain if it doesn't exist.
|
|
||||||
if (net::cookie_util::DomainIsHostOnly(filter_domain))
|
|
||||||
filter_domain.insert(0, ".");
|
|
||||||
|
|
||||||
std::string sub_domain(cookie_domain);
|
|
||||||
// Strip any leading '.' character from the input cookie domain.
|
|
||||||
if (!net::cookie_util::DomainIsHostOnly(sub_domain))
|
|
||||||
sub_domain = sub_domain.substr(1);
|
|
||||||
|
|
||||||
// Now check whether the domain argument is a subdomain of the filter domain.
|
|
||||||
for (sub_domain.insert(0, ".");
|
|
||||||
sub_domain.length() >= filter_domain.length();) {
|
|
||||||
if (sub_domain == filter_domain) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const size_t next_dot = sub_domain.find('.', 1); // Skip over leading dot.
|
|
||||||
sub_domain.erase(0, next_dot);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MatchesCookie(const base::DictionaryValue* filter,
|
|
||||||
const net::CanonicalCookie& cookie) {
|
|
||||||
std::string name, domain, path;
|
|
||||||
bool is_secure, session;
|
|
||||||
if (filter->GetString("name", &name) && name != cookie.Name())
|
|
||||||
return false;
|
|
||||||
if (filter->GetString("path", &path) && path != cookie.Path())
|
|
||||||
return false;
|
|
||||||
if (!MatchesDomain(filter, cookie.Domain()))
|
|
||||||
return false;
|
|
||||||
if (filter->GetBoolean("secure", &is_secure) &&
|
|
||||||
is_secure != cookie.IsSecure())
|
|
||||||
return false;
|
|
||||||
if (filter->GetBoolean("session", &session) &&
|
|
||||||
session != cookie.IsPersistent())
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace mate {
|
namespace mate {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Converter<atom::api::Cookies::Error> {
|
||||||
|
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||||
|
atom::api::Cookies::Error val) {
|
||||||
|
if (val == atom::api::Cookies::SUCCESS)
|
||||||
|
return v8::Null(isolate);
|
||||||
|
else
|
||||||
|
return v8::Exception::Error(StringToV8(isolate, "failed"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct Converter<net::CanonicalCookie> {
|
struct Converter<net::CanonicalCookie> {
|
||||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||||
|
@ -163,11 +42,11 @@ struct Converter<net::CanonicalCookie> {
|
||||||
dict.Set("name", val.Name());
|
dict.Set("name", val.Name());
|
||||||
dict.Set("value", val.Value());
|
dict.Set("value", val.Value());
|
||||||
dict.Set("domain", val.Domain());
|
dict.Set("domain", val.Domain());
|
||||||
dict.Set("host_only", net::cookie_util::DomainIsHostOnly(val.Domain()));
|
dict.Set("hostOnly", net::cookie_util::DomainIsHostOnly(val.Domain()));
|
||||||
dict.Set("path", val.Path());
|
dict.Set("path", val.Path());
|
||||||
dict.Set("secure", val.IsSecure());
|
dict.Set("secure", val.IsSecure());
|
||||||
dict.Set("http_only", val.IsHttpOnly());
|
dict.Set("httpOnly", val.IsHttpOnly());
|
||||||
dict.Set("session", val.IsPersistent());
|
dict.Set("session", !val.IsPersistent());
|
||||||
if (!val.IsPersistent())
|
if (!val.IsPersistent())
|
||||||
dict.Set("expirationDate", val.ExpiryDate().ToDoubleT());
|
dict.Set("expirationDate", val.ExpiryDate().ToDoubleT());
|
||||||
return dict.GetHandle();
|
return dict.GetHandle();
|
||||||
|
@ -180,121 +59,117 @@ namespace atom {
|
||||||
|
|
||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
Cookies::Cookies(content::BrowserContext* browser_context)
|
namespace {
|
||||||
: request_context_getter_(browser_context->GetRequestContext()) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Cookies::~Cookies() {
|
// Returns whether |domain| matches |filter|.
|
||||||
}
|
bool MatchesDomain(std::string filter, const std::string& domain) {
|
||||||
|
// Add a leading '.' character to the filter domain if it doesn't exist.
|
||||||
|
if (net::cookie_util::DomainIsHostOnly(filter))
|
||||||
|
filter.insert(0, ".");
|
||||||
|
|
||||||
void Cookies::Get(const base::DictionaryValue& options,
|
std::string sub_domain(domain);
|
||||||
const CookiesCallback& callback) {
|
// Strip any leading '.' character from the input cookie domain.
|
||||||
scoped_ptr<base::DictionaryValue> filter(
|
if (!net::cookie_util::DomainIsHostOnly(sub_domain))
|
||||||
options.DeepCopyWithoutEmptyChildren());
|
sub_domain = sub_domain.substr(1);
|
||||||
|
|
||||||
content::BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
// Now check whether the domain argument is a subdomain of the filter domain.
|
||||||
base::Bind(&Cookies::GetCookiesOnIOThread, base::Unretained(this),
|
for (sub_domain.insert(0, "."); sub_domain.length() >= filter.length();) {
|
||||||
Passed(&filter), callback));
|
if (sub_domain == filter)
|
||||||
}
|
return true;
|
||||||
|
const size_t next_dot = sub_domain.find('.', 1); // Skip over leading dot.
|
||||||
void Cookies::GetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> filter,
|
sub_domain.erase(0, next_dot);
|
||||||
const CookiesCallback& callback) {
|
|
||||||
std::string url;
|
|
||||||
filter->GetString("url", &url);
|
|
||||||
if (!GetCookieListFromStore(GetCookieStore(), url,
|
|
||||||
base::Bind(&Cookies::OnGetCookies, base::Unretained(this),
|
|
||||||
Passed(&filter), callback))) {
|
|
||||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
|
||||||
base::Bind(&RunGetCookiesCallbackOnUIThread, isolate(),
|
|
||||||
"Url is not valid", net::CookieList(), callback));
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cookies::OnGetCookies(scoped_ptr<base::DictionaryValue> filter,
|
// Returns whether |cookie| matches |filter|.
|
||||||
const CookiesCallback& callback,
|
bool MatchesCookie(const base::DictionaryValue* filter,
|
||||||
const net::CookieList& cookie_list) {
|
const net::CanonicalCookie& cookie) {
|
||||||
|
std::string str;
|
||||||
|
bool b;
|
||||||
|
if (filter->GetString("name", &str) && str != cookie.Name())
|
||||||
|
return false;
|
||||||
|
if (filter->GetString("path", &str) && str != cookie.Path())
|
||||||
|
return false;
|
||||||
|
if (filter->GetString("domain", &str) && !MatchesDomain(str, cookie.Domain()))
|
||||||
|
return false;
|
||||||
|
if (filter->GetBoolean("secure", &b) && b != cookie.IsSecure())
|
||||||
|
return false;
|
||||||
|
if (filter->GetBoolean("session", &b) && b != !cookie.IsPersistent())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to returns the CookieStore.
|
||||||
|
inline net::CookieStore* GetCookieStore(
|
||||||
|
scoped_refptr<net::URLRequestContextGetter> getter) {
|
||||||
|
return getter->GetURLRequestContext()->cookie_store();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run |callback| on UI thread.
|
||||||
|
void RunCallbackInUI(const base::Closure& callback) {
|
||||||
|
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove cookies from |list| not matching |filter|, and pass it to |callback|.
|
||||||
|
void FilterCookies(scoped_ptr<base::DictionaryValue> filter,
|
||||||
|
const Cookies::GetCallback& callback,
|
||||||
|
const net::CookieList& list) {
|
||||||
net::CookieList result;
|
net::CookieList result;
|
||||||
for (const auto& cookie : cookie_list) {
|
for (const auto& cookie : list) {
|
||||||
if (MatchesCookie(filter.get(), cookie))
|
if (MatchesCookie(filter.get(), cookie))
|
||||||
result.push_back(cookie);
|
result.push_back(cookie);
|
||||||
}
|
}
|
||||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
|
RunCallbackInUI(base::Bind(callback, Cookies::SUCCESS, result));
|
||||||
&RunGetCookiesCallbackOnUIThread, isolate(), "", result, callback));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cookies::Remove(const mate::Dictionary& details,
|
// Receives cookies matching |filter| in IO thread.
|
||||||
const CookiesCallback& callback) {
|
void GetCookiesOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||||
GURL url;
|
scoped_ptr<base::DictionaryValue> filter,
|
||||||
std::string name;
|
const Cookies::GetCallback& callback) {
|
||||||
std::string error_message;
|
|
||||||
if (!details.Get("url", &url) || !details.Get("name", &name)) {
|
|
||||||
error_message = "Details(url, name) of removing cookie are required.";
|
|
||||||
}
|
|
||||||
if (error_message.empty() && !url.is_valid()) {
|
|
||||||
error_message = "Url is not valid.";
|
|
||||||
}
|
|
||||||
if (!error_message.empty()) {
|
|
||||||
RunRemoveCookiesCallbackOnUIThread(isolate(), error_message, callback);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
content::BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
|
||||||
base::Bind(&Cookies::RemoveCookiesOnIOThread, base::Unretained(this),
|
|
||||||
url, name, callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cookies::RemoveCookiesOnIOThread(const GURL& url, const std::string& name,
|
|
||||||
const CookiesCallback& callback) {
|
|
||||||
GetCookieStore()->DeleteCookieAsync(url, name,
|
|
||||||
base::Bind(&Cookies::OnRemoveCookies, base::Unretained(this), callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cookies::OnRemoveCookies(const CookiesCallback& callback) {
|
|
||||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
|
||||||
base::Bind(&RunRemoveCookiesCallbackOnUIThread, isolate(), "", callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cookies::Set(const base::DictionaryValue& options,
|
|
||||||
const CookiesCallback& callback) {
|
|
||||||
std::string url;
|
std::string url;
|
||||||
std::string error_message;
|
filter->GetString("url", &url);
|
||||||
if (!options.GetString("url", &url)) {
|
|
||||||
error_message = "The url field is required.";
|
|
||||||
}
|
|
||||||
|
|
||||||
GURL gurl(url);
|
auto filtered_callback =
|
||||||
if (error_message.empty() && !gurl.is_valid()) {
|
base::Bind(FilterCookies, base::Passed(&filter), callback);
|
||||||
error_message = "Url is not valid.";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!error_message.empty()) {
|
net::CookieMonster* monster = GetCookieStore(getter)->GetCookieMonster();
|
||||||
RunSetCookiesCallbackOnUIThread(isolate(), error_message, false, callback);
|
// Empty url will match all url cookies.
|
||||||
return;
|
if (url.empty())
|
||||||
}
|
monster->GetAllCookiesAsync(filtered_callback);
|
||||||
|
else
|
||||||
scoped_ptr<base::DictionaryValue> details(
|
monster->GetAllCookiesForURLAsync(GURL(url), filtered_callback);
|
||||||
options.DeepCopyWithoutEmptyChildren());
|
|
||||||
|
|
||||||
content::BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
|
||||||
base::Bind(&Cookies::SetCookiesOnIOThread, base::Unretained(this),
|
|
||||||
Passed(&details), gurl, callback));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cookies::SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
|
// Removes cookie with |url| and |name| in IO thread.
|
||||||
const GURL& url,
|
void RemoveCookieOnIOThread(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||||
const CookiesCallback& callback) {
|
const GURL& url, const std::string& name,
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
const base::Closure& callback) {
|
||||||
|
GetCookieStore(getter)->DeleteCookieAsync(
|
||||||
|
url, name, base::Bind(RunCallbackInUI, callback));
|
||||||
|
}
|
||||||
|
|
||||||
std::string name, value, domain, path;
|
// Callback of SetCookie.
|
||||||
|
void OnSetCookie(const Cookies::SetCallback& callback, bool success) {
|
||||||
|
RunCallbackInUI(
|
||||||
|
base::Bind(callback, success ? Cookies::SUCCESS : Cookies::FAILED));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets cookie with |details| in IO thread.
|
||||||
|
void SetCookieOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||||
|
scoped_ptr<base::DictionaryValue> details,
|
||||||
|
const Cookies::SetCallback& callback) {
|
||||||
|
std::string url, name, value, domain, path;
|
||||||
bool secure = false;
|
bool secure = false;
|
||||||
bool http_only = false;
|
bool http_only = false;
|
||||||
double expiration_date;
|
double expiration_date;
|
||||||
|
details->GetString("url", &url);
|
||||||
details->GetString("name", &name);
|
details->GetString("name", &name);
|
||||||
details->GetString("value", &value);
|
details->GetString("value", &value);
|
||||||
details->GetString("domain", &domain);
|
details->GetString("domain", &domain);
|
||||||
details->GetString("path", &path);
|
details->GetString("path", &path);
|
||||||
details->GetBoolean("secure", &secure);
|
details->GetBoolean("secure", &secure);
|
||||||
details->GetBoolean("http_only", &http_only);
|
details->GetBoolean("httpOnly", &http_only);
|
||||||
|
|
||||||
base::Time expiration_time;
|
base::Time expiration_time;
|
||||||
if (details->GetDouble("expirationDate", &expiration_date)) {
|
if (details->GetDouble("expirationDate", &expiration_date)) {
|
||||||
|
@ -303,37 +178,44 @@ void Cookies::SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
|
||||||
base::Time::FromDoubleT(expiration_date);
|
base::Time::FromDoubleT(expiration_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
GetCookieStore()->GetCookieMonster()->SetCookieWithDetailsAsync(
|
GetCookieStore(getter)->GetCookieMonster()->SetCookieWithDetailsAsync(
|
||||||
url,
|
GURL(url), name, value, domain, path, expiration_time, secure, http_only,
|
||||||
name,
|
false, net::COOKIE_PRIORITY_DEFAULT, base::Bind(OnSetCookie, callback));
|
||||||
value,
|
|
||||||
domain,
|
|
||||||
path,
|
|
||||||
expiration_time,
|
|
||||||
secure,
|
|
||||||
http_only,
|
|
||||||
false,
|
|
||||||
net::COOKIE_PRIORITY_DEFAULT,
|
|
||||||
base::Bind(&Cookies::OnSetCookies, base::Unretained(this), callback));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cookies::OnSetCookies(const CookiesCallback& callback,
|
} // namespace
|
||||||
bool set_success) {
|
|
||||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
Cookies::Cookies(content::BrowserContext* browser_context)
|
||||||
base::Bind(&RunSetCookiesCallbackOnUIThread, isolate(), "", set_success,
|
: request_context_getter_(browser_context->GetRequestContext()) {
|
||||||
callback));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mate::ObjectTemplateBuilder Cookies::GetObjectTemplateBuilder(
|
Cookies::~Cookies() {
|
||||||
v8::Isolate* isolate) {
|
|
||||||
return mate::ObjectTemplateBuilder(isolate)
|
|
||||||
.SetMethod("get", &Cookies::Get)
|
|
||||||
.SetMethod("remove", &Cookies::Remove)
|
|
||||||
.SetMethod("set", &Cookies::Set);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
net::CookieStore* Cookies::GetCookieStore() {
|
void Cookies::Get(const base::DictionaryValue& filter,
|
||||||
return request_context_getter_->GetURLRequestContext()->cookie_store();
|
const GetCallback& callback) {
|
||||||
|
scoped_ptr<base::DictionaryValue> copied(filter.CreateDeepCopy());
|
||||||
|
auto getter = make_scoped_refptr(request_context_getter_);
|
||||||
|
content::BrowserThread::PostTask(
|
||||||
|
BrowserThread::IO, FROM_HERE,
|
||||||
|
base::Bind(GetCookiesOnIO, getter, Passed(&copied), callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cookies::Remove(const GURL& url, const std::string& name,
|
||||||
|
const base::Closure& callback) {
|
||||||
|
auto getter = make_scoped_refptr(request_context_getter_);
|
||||||
|
content::BrowserThread::PostTask(
|
||||||
|
BrowserThread::IO, FROM_HERE,
|
||||||
|
base::Bind(RemoveCookieOnIOThread, getter, url, name, callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cookies::Set(const base::DictionaryValue& details,
|
||||||
|
const SetCallback& callback) {
|
||||||
|
scoped_ptr<base::DictionaryValue> copied(details.CreateDeepCopy());
|
||||||
|
auto getter = make_scoped_refptr(request_context_getter_);
|
||||||
|
content::BrowserThread::PostTask(
|
||||||
|
BrowserThread::IO, FROM_HERE,
|
||||||
|
base::Bind(SetCookieOnIO, getter, Passed(&copied), callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
@ -343,6 +225,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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
@ -20,12 +20,7 @@ namespace content {
|
||||||
class BrowserContext;
|
class BrowserContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace mate {
|
|
||||||
class Dictionary;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace net {
|
namespace net {
|
||||||
class CookieStore;
|
|
||||||
class URLRequestContextGetter;
|
class URLRequestContextGetter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,52 +28,34 @@ 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)
|
enum Error {
|
||||||
typedef base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>
|
SUCCESS,
|
||||||
CookiesCallback;
|
FAILED,
|
||||||
|
};
|
||||||
|
|
||||||
|
using GetCallback = base::Callback<void(Error, const net::CookieList&)>;
|
||||||
|
using SetCallback = base::Callback<void(Error)>;
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
void Get(const base::DictionaryValue& options,
|
void Get(const base::DictionaryValue& filter, const GetCallback& callback);
|
||||||
const CookiesCallback& callback);
|
void Remove(const GURL& url, const std::string& name,
|
||||||
void Remove(const mate::Dictionary& details,
|
const base::Closure& callback);
|
||||||
const CookiesCallback& callback);
|
void Set(const base::DictionaryValue& details, const SetCallback& callback);
|
||||||
void Set(const base::DictionaryValue& details,
|
|
||||||
const CookiesCallback& callback);
|
|
||||||
|
|
||||||
void GetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> filter,
|
|
||||||
const CookiesCallback& callback);
|
|
||||||
void OnGetCookies(scoped_ptr<base::DictionaryValue> filter,
|
|
||||||
const CookiesCallback& callback,
|
|
||||||
const net::CookieList& cookie_list);
|
|
||||||
|
|
||||||
void RemoveCookiesOnIOThread(const GURL& url,
|
|
||||||
const std::string& name,
|
|
||||||
const CookiesCallback& callback);
|
|
||||||
void OnRemoveCookies(const CookiesCallback& callback);
|
|
||||||
|
|
||||||
void SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
|
|
||||||
const GURL& url,
|
|
||||||
const CookiesCallback& callback);
|
|
||||||
void OnSetCookies(const CookiesCallback& callback,
|
|
||||||
bool set_success);
|
|
||||||
|
|
||||||
// mate::Wrappable:
|
|
||||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
|
||||||
v8::Isolate* isolate) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Must be called on IO thread.
|
net::URLRequestContextGetter* request_context_getter_;
|
||||||
net::CookieStore* GetCookieStore();
|
|
||||||
|
|
||||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Cookies);
|
DISALLOW_COPY_AND_ASSIGN(Cookies);
|
||||||
};
|
};
|
||||||
|
|
195
atom/browser/api/atom_api_debugger.cc
Normal file
195
atom/browser/api/atom_api_debugger.cc
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
// Copyright (c) 2016 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/atom_api_debugger.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "atom/browser/atom_browser_main_parts.h"
|
||||||
|
#include "atom/common/native_mate_converters/callback.h"
|
||||||
|
#include "atom/common/native_mate_converters/value_converter.h"
|
||||||
|
#include "atom/common/node_includes.h"
|
||||||
|
#include "base/json/json_reader.h"
|
||||||
|
#include "base/json/json_writer.h"
|
||||||
|
#include "content/public/browser/devtools_agent_host.h"
|
||||||
|
#include "content/public/browser/web_contents.h"
|
||||||
|
#include "native_mate/dictionary.h"
|
||||||
|
#include "native_mate/object_template_builder.h"
|
||||||
|
|
||||||
|
using content::DevToolsAgentHost;
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// The wrapDebugger funtion which is implemented in JavaScript.
|
||||||
|
using WrapDebuggerCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||||
|
WrapDebuggerCallback g_wrap_debugger;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Debugger::Debugger(content::WebContents* web_contents)
|
||||||
|
: web_contents_(web_contents),
|
||||||
|
previous_request_id_(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Debugger::~Debugger() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Debugger::AgentHostClosed(DevToolsAgentHost* agent_host,
|
||||||
|
bool replaced_with_another_client) {
|
||||||
|
std::string detach_reason = "target closed";
|
||||||
|
if (replaced_with_another_client)
|
||||||
|
detach_reason = "replaced with devtools";
|
||||||
|
Emit("detach", detach_reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Debugger::DispatchProtocolMessage(DevToolsAgentHost* agent_host,
|
||||||
|
const std::string& message) {
|
||||||
|
DCHECK(agent_host == agent_host_.get());
|
||||||
|
|
||||||
|
scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
|
||||||
|
if (!parsed_message->IsType(base::Value::TYPE_DICTIONARY))
|
||||||
|
return;
|
||||||
|
|
||||||
|
base::DictionaryValue* dict =
|
||||||
|
static_cast<base::DictionaryValue*>(parsed_message.get());
|
||||||
|
int id;
|
||||||
|
if (!dict->GetInteger("id", &id)) {
|
||||||
|
std::string method;
|
||||||
|
if (!dict->GetString("method", &method))
|
||||||
|
return;
|
||||||
|
base::DictionaryValue* params_value = nullptr;
|
||||||
|
base::DictionaryValue params;
|
||||||
|
if (dict->GetDictionary("params", ¶ms_value))
|
||||||
|
params.Swap(params_value);
|
||||||
|
Emit("message", method, params);
|
||||||
|
} else {
|
||||||
|
auto send_command_callback = pending_requests_[id];
|
||||||
|
pending_requests_.erase(id);
|
||||||
|
if (send_command_callback.is_null())
|
||||||
|
return;
|
||||||
|
base::DictionaryValue* error_body = nullptr;
|
||||||
|
base::DictionaryValue error;
|
||||||
|
if (dict->GetDictionary("error", &error_body))
|
||||||
|
error.Swap(error_body);
|
||||||
|
|
||||||
|
base::DictionaryValue* result_body = nullptr;
|
||||||
|
base::DictionaryValue result;
|
||||||
|
if (dict->GetDictionary("result", &result_body))
|
||||||
|
result.Swap(result_body);
|
||||||
|
send_command_callback.Run(error, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Debugger::Attach(mate::Arguments* args) {
|
||||||
|
std::string protocol_version;
|
||||||
|
args->GetNext(&protocol_version);
|
||||||
|
|
||||||
|
if (!protocol_version.empty() &&
|
||||||
|
!DevToolsAgentHost::IsSupportedProtocolVersion(protocol_version)) {
|
||||||
|
args->ThrowError("Requested protocol version is not supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
agent_host_ = DevToolsAgentHost::GetOrCreateFor(web_contents_);
|
||||||
|
if (!agent_host_.get()) {
|
||||||
|
args->ThrowError("No target available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (agent_host_->IsAttached()) {
|
||||||
|
args->ThrowError("Another debugger is already attached to this target");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
agent_host_->AttachClient(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Debugger::IsAttached() {
|
||||||
|
return agent_host_.get() ? agent_host_->IsAttached() : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Debugger::Detach() {
|
||||||
|
if (!agent_host_.get())
|
||||||
|
return;
|
||||||
|
agent_host_->DetachClient();
|
||||||
|
AgentHostClosed(agent_host_.get(), false);
|
||||||
|
agent_host_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Debugger::SendCommand(mate::Arguments* args) {
|
||||||
|
if (!agent_host_.get())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string method;
|
||||||
|
if (!args->GetNext(&method)) {
|
||||||
|
args->ThrowError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
base::DictionaryValue command_params;
|
||||||
|
args->GetNext(&command_params);
|
||||||
|
SendCommandCallback callback;
|
||||||
|
args->GetNext(&callback);
|
||||||
|
|
||||||
|
base::DictionaryValue request;
|
||||||
|
int request_id = ++previous_request_id_;
|
||||||
|
pending_requests_[request_id] = callback;
|
||||||
|
request.SetInteger("id", request_id);
|
||||||
|
request.SetString("method", method);
|
||||||
|
if (!command_params.empty())
|
||||||
|
request.Set("params", command_params.DeepCopy());
|
||||||
|
|
||||||
|
std::string json_args;
|
||||||
|
base::JSONWriter::Write(request, &json_args);
|
||||||
|
agent_host_->DispatchProtocolMessage(json_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
mate::Handle<Debugger> Debugger::Create(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
content::WebContents* web_contents) {
|
||||||
|
auto handle = mate::CreateHandle(isolate, new Debugger(web_contents));
|
||||||
|
g_wrap_debugger.Run(handle.ToV8());
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Debugger::BuildPrototype(v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::ObjectTemplate> prototype) {
|
||||||
|
mate::ObjectTemplateBuilder(isolate, prototype)
|
||||||
|
.SetMethod("attach", &Debugger::Attach)
|
||||||
|
.SetMethod("isAttached", &Debugger::IsAttached)
|
||||||
|
.SetMethod("detach", &Debugger::Detach)
|
||||||
|
.SetMethod("sendCommand", &Debugger::SendCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearWrapDebugger() {
|
||||||
|
g_wrap_debugger.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetWrapDebugger(const WrapDebuggerCallback& callback) {
|
||||||
|
g_wrap_debugger = callback;
|
||||||
|
|
||||||
|
// Cleanup the wrapper on exit.
|
||||||
|
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
|
||||||
|
base::Bind(ClearWrapDebugger));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||||
|
v8::Local<v8::Context> context, void* priv) {
|
||||||
|
v8::Isolate* isolate = context->GetIsolate();
|
||||||
|
mate::Dictionary dict(isolate, exports);
|
||||||
|
dict.SetMethod("_setWrapDebugger", &atom::api::SetWrapDebugger);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_debugger, Initialize);
|
75
atom/browser/api/atom_api_debugger.h
Normal file
75
atom/browser/api/atom_api_debugger.h
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
// Copyright (c) 2016 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_ATOM_API_DEBUGGER_H_
|
||||||
|
#define ATOM_BROWSER_API_ATOM_API_DEBUGGER_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "atom/browser/api/trackable_object.h"
|
||||||
|
#include "base/callback.h"
|
||||||
|
#include "base/values.h"
|
||||||
|
#include "content/public/browser/devtools_agent_host_client.h"
|
||||||
|
#include "native_mate/handle.h"
|
||||||
|
|
||||||
|
namespace content {
|
||||||
|
class DevToolsAgentHost;
|
||||||
|
class WebContents;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace mate {
|
||||||
|
class Arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
class Debugger: public mate::TrackableObject<Debugger>,
|
||||||
|
public content::DevToolsAgentHostClient {
|
||||||
|
public:
|
||||||
|
using SendCommandCallback =
|
||||||
|
base::Callback<void(const base::DictionaryValue&,
|
||||||
|
const base::DictionaryValue&)>;
|
||||||
|
|
||||||
|
static mate::Handle<Debugger> Create(
|
||||||
|
v8::Isolate* isolate, content::WebContents* web_contents);
|
||||||
|
|
||||||
|
// mate::TrackableObject:
|
||||||
|
static void BuildPrototype(v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::ObjectTemplate> prototype);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit Debugger(content::WebContents* web_contents);
|
||||||
|
~Debugger();
|
||||||
|
|
||||||
|
// content::DevToolsAgentHostClient:
|
||||||
|
void AgentHostClosed(content::DevToolsAgentHost* agent_host,
|
||||||
|
bool replaced_with_another_client) override;
|
||||||
|
void DispatchProtocolMessage(content::DevToolsAgentHost* agent_host,
|
||||||
|
const std::string& message) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using PendingRequestMap = std::map<int, SendCommandCallback>;
|
||||||
|
|
||||||
|
void Attach(mate::Arguments* args);
|
||||||
|
bool IsAttached();
|
||||||
|
void Detach();
|
||||||
|
void SendCommand(mate::Arguments* args);
|
||||||
|
|
||||||
|
content::WebContents* web_contents_; // Weak Reference.
|
||||||
|
scoped_refptr<content::DevToolsAgentHost> agent_host_;
|
||||||
|
|
||||||
|
PendingRequestMap pending_requests_;
|
||||||
|
int previous_request_id_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(Debugger);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
#endif // ATOM_BROWSER_API_ATOM_API_DEBUGGER_H_
|
120
atom/browser/api/atom_api_desktop_capturer.cc
Normal file
120
atom/browser/api/atom_api_desktop_capturer.cc
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
// 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/atom_api_desktop_capturer.h"
|
||||||
|
|
||||||
|
#include "atom/common/api/atom_api_native_image.h"
|
||||||
|
#include "atom/common/node_includes.h"
|
||||||
|
#include "atom/common/native_mate_converters/gfx_converter.h"
|
||||||
|
#include "base/strings/utf_string_conversions.h"
|
||||||
|
#include "chrome/browser/media/desktop_media_list.h"
|
||||||
|
#include "native_mate/dictionary.h"
|
||||||
|
#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
|
||||||
|
#include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
|
||||||
|
#include "third_party/webrtc/modules/desktop_capture/window_capturer.h"
|
||||||
|
|
||||||
|
namespace mate {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Converter<DesktopMediaList::Source> {
|
||||||
|
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||||
|
const DesktopMediaList::Source& source) {
|
||||||
|
mate::Dictionary dict(isolate, v8::Object::New(isolate));
|
||||||
|
content::DesktopMediaID id = source.id;
|
||||||
|
dict.Set("name", base::UTF16ToUTF8(source.name));
|
||||||
|
dict.Set("id", id.ToString());
|
||||||
|
dict.Set(
|
||||||
|
"thumbnail",
|
||||||
|
atom::api::NativeImage::Create(isolate, gfx::Image(source.thumbnail)));
|
||||||
|
return ConvertToV8(isolate, dict);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mate
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
DesktopCapturer::DesktopCapturer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
DesktopCapturer::~DesktopCapturer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopCapturer::StartHandling(bool capture_window,
|
||||||
|
bool capture_screen,
|
||||||
|
const gfx::Size& thumbnail_size) {
|
||||||
|
webrtc::DesktopCaptureOptions options =
|
||||||
|
webrtc::DesktopCaptureOptions::CreateDefault();
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
// On windows, desktop effects (e.g. Aero) will be disabled when the Desktop
|
||||||
|
// capture API is active by default.
|
||||||
|
// We keep the desktop effects in most times. Howerver, the screen still
|
||||||
|
// fickers when the API is capturing the window due to limitation of current
|
||||||
|
// implemetation. This is a known and wontFix issue in webrtc (see:
|
||||||
|
// http://code.google.com/p/webrtc/issues/detail?id=3373)
|
||||||
|
options.set_disable_effects(false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
scoped_ptr<webrtc::ScreenCapturer> screen_capturer(
|
||||||
|
capture_screen ? webrtc::ScreenCapturer::Create(options) : nullptr);
|
||||||
|
scoped_ptr<webrtc::WindowCapturer> window_capturer(
|
||||||
|
capture_window ? webrtc::WindowCapturer::Create(options) : nullptr);
|
||||||
|
media_list_.reset(new NativeDesktopMediaList(screen_capturer.Pass(),
|
||||||
|
window_capturer.Pass()));
|
||||||
|
|
||||||
|
media_list_->SetThumbnailSize(thumbnail_size);
|
||||||
|
media_list_->StartUpdating(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopCapturer::OnSourceAdded(int index) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopCapturer::OnSourceRemoved(int index) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopCapturer::OnSourceMoved(int old_index, int new_index) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopCapturer::OnSourceNameChanged(int index) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopCapturer::OnSourceThumbnailChanged(int index) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopCapturer::OnRefreshFinished() {
|
||||||
|
Emit("finished", media_list_->GetSources());
|
||||||
|
media_list_.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mate::ObjectTemplateBuilder DesktopCapturer::GetObjectTemplateBuilder(
|
||||||
|
v8::Isolate* isolate) {
|
||||||
|
return mate::ObjectTemplateBuilder(isolate)
|
||||||
|
.SetMethod("startHandling", &DesktopCapturer::StartHandling);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
mate::Handle<DesktopCapturer> DesktopCapturer::Create(v8::Isolate* isolate) {
|
||||||
|
return mate::CreateHandle(isolate, new DesktopCapturer);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||||
|
v8::Local<v8::Context> context, void* priv) {
|
||||||
|
v8::Isolate* isolate = context->GetIsolate();
|
||||||
|
mate::Dictionary dict(isolate, exports);
|
||||||
|
dict.Set("desktopCapturer", atom::api::DesktopCapturer::Create(isolate));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_desktop_capturer, Initialize);
|
52
atom/browser/api/atom_api_desktop_capturer.h
Normal file
52
atom/browser/api/atom_api_desktop_capturer.h
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
// 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_ATOM_API_DESKTOP_CAPTURER_H_
|
||||||
|
#define ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_H_
|
||||||
|
|
||||||
|
#include "atom/browser/api/event_emitter.h"
|
||||||
|
#include "chrome/browser/media/desktop_media_list_observer.h"
|
||||||
|
#include "chrome/browser/media/native_desktop_media_list.h"
|
||||||
|
#include "native_mate/handle.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
class DesktopCapturer: public mate::EventEmitter,
|
||||||
|
public DesktopMediaListObserver {
|
||||||
|
public:
|
||||||
|
static mate::Handle<DesktopCapturer> Create(v8::Isolate* isolate);
|
||||||
|
|
||||||
|
void StartHandling(bool capture_window,
|
||||||
|
bool capture_screen,
|
||||||
|
const gfx::Size& thumbnail_size);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
DesktopCapturer();
|
||||||
|
~DesktopCapturer();
|
||||||
|
|
||||||
|
// DesktopMediaListObserver overrides.
|
||||||
|
void OnSourceAdded(int index) override;
|
||||||
|
void OnSourceRemoved(int index) override;
|
||||||
|
void OnSourceMoved(int old_index, int new_index) override;
|
||||||
|
void OnSourceNameChanged(int index) override;
|
||||||
|
void OnSourceThumbnailChanged(int index) override;
|
||||||
|
bool OnRefreshFinished() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// mate::Wrappable:
|
||||||
|
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||||
|
v8::Isolate* isolate) override;
|
||||||
|
|
||||||
|
scoped_ptr<DesktopMediaList> media_list_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(DesktopCapturer);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
#endif // ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_H_
|
|
@ -41,6 +41,7 @@ namespace {
|
||||||
|
|
||||||
void ShowMessageBox(int type,
|
void ShowMessageBox(int type,
|
||||||
const std::vector<std::string>& buttons,
|
const std::vector<std::string>& buttons,
|
||||||
|
int default_id,
|
||||||
int cancel_id,
|
int cancel_id,
|
||||||
int options,
|
int options,
|
||||||
const std::string& title,
|
const std::string& title,
|
||||||
|
@ -54,12 +55,13 @@ void ShowMessageBox(int type,
|
||||||
if (mate::Converter<atom::MessageBoxCallback>::FromV8(args->isolate(),
|
if (mate::Converter<atom::MessageBoxCallback>::FromV8(args->isolate(),
|
||||||
peek,
|
peek,
|
||||||
&callback)) {
|
&callback)) {
|
||||||
atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, cancel_id,
|
atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons,
|
||||||
options, title, message, detail, icon, callback);
|
default_id, cancel_id, options, title,
|
||||||
|
message, detail, icon, callback);
|
||||||
} else {
|
} else {
|
||||||
int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type,
|
int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type,
|
||||||
buttons, cancel_id, options, title,
|
buttons, default_id, cancel_id,
|
||||||
message, detail, icon);
|
options, title, message, detail, icon);
|
||||||
args->Return(chosen);
|
args->Return(chosen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
198
atom/browser/api/atom_api_download_item.cc
Normal file
198
atom/browser/api/atom_api_download_item.cc
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
// 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/atom_api_download_item.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "atom/browser/atom_browser_main_parts.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/gurl_converter.h"
|
||||||
|
#include "atom/common/node_includes.h"
|
||||||
|
#include "base/memory/linked_ptr.h"
|
||||||
|
#include "base/strings/utf_string_conversions.h"
|
||||||
|
#include "native_mate/dictionary.h"
|
||||||
|
#include "net/base/filename_util.h"
|
||||||
|
|
||||||
|
namespace mate {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Converter<content::DownloadItem::DownloadState> {
|
||||||
|
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||||
|
content::DownloadItem::DownloadState state) {
|
||||||
|
std::string download_state;
|
||||||
|
switch (state) {
|
||||||
|
case content::DownloadItem::COMPLETE:
|
||||||
|
download_state = "completed";
|
||||||
|
break;
|
||||||
|
case content::DownloadItem::CANCELLED:
|
||||||
|
download_state = "cancelled";
|
||||||
|
break;
|
||||||
|
case content::DownloadItem::INTERRUPTED:
|
||||||
|
download_state = "interrupted";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ConvertToV8(isolate, download_state);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mate
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// The wrapDownloadItem funtion which is implemented in JavaScript
|
||||||
|
using WrapDownloadItemCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||||
|
WrapDownloadItemCallback g_wrap_download_item;
|
||||||
|
|
||||||
|
char kDownloadItemSavePathKey[] = "DownloadItemSavePathKey";
|
||||||
|
|
||||||
|
std::map<uint32, linked_ptr<v8::Global<v8::Value>>> g_download_item_objects;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
DownloadItem::SavePathData::SavePathData(const base::FilePath& path) :
|
||||||
|
path_(path) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const base::FilePath& DownloadItem::SavePathData::path() {
|
||||||
|
return path_;
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadItem::DownloadItem(content::DownloadItem* download_item) :
|
||||||
|
download_item_(download_item) {
|
||||||
|
download_item_->AddObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadItem::~DownloadItem() {
|
||||||
|
if (download_item_)
|
||||||
|
OnDownloadDestroyed(download_item_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) {
|
||||||
|
download_item_->IsDone() ? Emit("done", item->GetState()) : Emit("updated");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::OnDownloadDestroyed(content::DownloadItem* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 DownloadItem::GetReceivedBytes() {
|
||||||
|
return download_item_->GetReceivedBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 DownloadItem::GetTotalBytes() {
|
||||||
|
return download_item_->GetTotalBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
const GURL& DownloadItem::GetURL() {
|
||||||
|
return download_item_->GetURL();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DownloadItem::GetMimeType() {
|
||||||
|
return download_item_->GetMimeType();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DownloadItem::HasUserGesture() {
|
||||||
|
return download_item_->HasUserGesture();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DownloadItem::GetFilename() {
|
||||||
|
return base::UTF16ToUTF8(net::GenerateFileName(GetURL(),
|
||||||
|
GetContentDisposition(),
|
||||||
|
std::string(),
|
||||||
|
download_item_->GetSuggestedFilename(),
|
||||||
|
GetMimeType(),
|
||||||
|
std::string()).LossyDisplayName());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DownloadItem::GetContentDisposition() {
|
||||||
|
return download_item_->GetContentDisposition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::SetSavePath(const base::FilePath& path) {
|
||||||
|
download_item_->SetUserData(UserDataKey(), new SavePathData(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::Pause() {
|
||||||
|
download_item_->Pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::Resume() {
|
||||||
|
download_item_->Resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloadItem::Cancel() {
|
||||||
|
download_item_->Cancel(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void DownloadItem::BuildPrototype(v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::ObjectTemplate> prototype) {
|
||||||
|
mate::ObjectTemplateBuilder(isolate, prototype)
|
||||||
|
.MakeDestroyable()
|
||||||
|
.SetMethod("pause", &DownloadItem::Pause)
|
||||||
|
.SetMethod("resume", &DownloadItem::Resume)
|
||||||
|
.SetMethod("cancel", &DownloadItem::Cancel)
|
||||||
|
.SetMethod("getReceivedBytes", &DownloadItem::GetReceivedBytes)
|
||||||
|
.SetMethod("getTotalBytes", &DownloadItem::GetTotalBytes)
|
||||||
|
.SetMethod("getURL", &DownloadItem::GetURL)
|
||||||
|
.SetMethod("getMimeType", &DownloadItem::GetMimeType)
|
||||||
|
.SetMethod("hasUserGesture", &DownloadItem::HasUserGesture)
|
||||||
|
.SetMethod("getFilename", &DownloadItem::GetFilename)
|
||||||
|
.SetMethod("getContentDisposition", &DownloadItem::GetContentDisposition)
|
||||||
|
.SetMethod("setSavePath", &DownloadItem::SetSavePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
mate::Handle<DownloadItem> DownloadItem::Create(
|
||||||
|
v8::Isolate* isolate, content::DownloadItem* item) {
|
||||||
|
auto handle = mate::CreateHandle(isolate, new DownloadItem(item));
|
||||||
|
g_wrap_download_item.Run(handle.ToV8());
|
||||||
|
g_download_item_objects[item->GetId()] = make_linked_ptr(
|
||||||
|
new v8::Global<v8::Value>(isolate, handle.ToV8()));
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void* DownloadItem::UserDataKey() {
|
||||||
|
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 atom
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||||
|
v8::Local<v8::Context> context, void* priv) {
|
||||||
|
v8::Isolate* isolate = context->GetIsolate();
|
||||||
|
mate::Dictionary dict(isolate, exports);
|
||||||
|
dict.SetMethod("_setWrapDownloadItem", &atom::api::SetWrapDownloadItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_download_item, Initialize);
|
69
atom/browser/api/atom_api_download_item.h
Normal file
69
atom/browser/api/atom_api_download_item.h
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
// 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_ATOM_API_DOWNLOAD_ITEM_H_
|
||||||
|
#define ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "atom/browser/api/trackable_object.h"
|
||||||
|
#include "base/files/file_path.h"
|
||||||
|
#include "content/public/browser/download_item.h"
|
||||||
|
#include "native_mate/handle.h"
|
||||||
|
#include "url/gurl.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
class DownloadItem : public mate::TrackableObject<DownloadItem>,
|
||||||
|
public content::DownloadItem::Observer {
|
||||||
|
public:
|
||||||
|
class SavePathData : public base::SupportsUserData::Data {
|
||||||
|
public:
|
||||||
|
explicit SavePathData(const base::FilePath& path);
|
||||||
|
const base::FilePath& path();
|
||||||
|
private:
|
||||||
|
base::FilePath path_;
|
||||||
|
};
|
||||||
|
|
||||||
|
static mate::Handle<DownloadItem> Create(v8::Isolate* isolate,
|
||||||
|
content::DownloadItem* item);
|
||||||
|
static void* UserDataKey();
|
||||||
|
|
||||||
|
// mate::TrackableObject:
|
||||||
|
static void BuildPrototype(v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::ObjectTemplate> prototype);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit DownloadItem(content::DownloadItem* download_item);
|
||||||
|
~DownloadItem();
|
||||||
|
|
||||||
|
// Override content::DownloadItem::Observer methods
|
||||||
|
void OnDownloadUpdated(content::DownloadItem* download) override;
|
||||||
|
void OnDownloadDestroyed(content::DownloadItem* download) override;
|
||||||
|
|
||||||
|
void Pause();
|
||||||
|
void Resume();
|
||||||
|
void Cancel();
|
||||||
|
int64 GetReceivedBytes();
|
||||||
|
int64 GetTotalBytes();
|
||||||
|
std::string GetMimeType();
|
||||||
|
bool HasUserGesture();
|
||||||
|
std::string GetFilename();
|
||||||
|
std::string GetContentDisposition();
|
||||||
|
const GURL& GetURL();
|
||||||
|
void SetSavePath(const base::FilePath& path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
content::DownloadItem* download_item_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(DownloadItem);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
#endif // ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_
|
|
@ -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(
|
||||||
|
|
|
@ -107,6 +107,10 @@ void Menu::SetSublabel(int index, const base::string16& sublabel) {
|
||||||
model_->SetSublabel(index, sublabel);
|
model_->SetSublabel(index, sublabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Menu::SetRole(int index, const base::string16& role) {
|
||||||
|
model_->SetRole(index, role);
|
||||||
|
}
|
||||||
|
|
||||||
void Menu::Clear() {
|
void Menu::Clear() {
|
||||||
model_->Clear();
|
model_->Clear();
|
||||||
}
|
}
|
||||||
|
@ -147,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)
|
||||||
|
@ -154,6 +159,7 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
|
||||||
.SetMethod("insertSubMenu", &Menu::InsertSubMenuAt)
|
.SetMethod("insertSubMenu", &Menu::InsertSubMenuAt)
|
||||||
.SetMethod("setIcon", &Menu::SetIcon)
|
.SetMethod("setIcon", &Menu::SetIcon)
|
||||||
.SetMethod("setSublabel", &Menu::SetSublabel)
|
.SetMethod("setSublabel", &Menu::SetSublabel)
|
||||||
|
.SetMethod("setRole", &Menu::SetRole)
|
||||||
.SetMethod("clear", &Menu::Clear)
|
.SetMethod("clear", &Menu::Clear)
|
||||||
.SetMethod("getIndexOfCommandId", &Menu::GetIndexOfCommandId)
|
.SetMethod("getIndexOfCommandId", &Menu::GetIndexOfCommandId)
|
||||||
.SetMethod("getItemCount", &Menu::GetItemCount)
|
.SetMethod("getItemCount", &Menu::GetItemCount)
|
||||||
|
@ -163,8 +169,7 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
|
||||||
.SetMethod("isItemCheckedAt", &Menu::IsItemCheckedAt)
|
.SetMethod("isItemCheckedAt", &Menu::IsItemCheckedAt)
|
||||||
.SetMethod("isEnabledAt", &Menu::IsEnabledAt)
|
.SetMethod("isEnabledAt", &Menu::IsEnabledAt)
|
||||||
.SetMethod("isVisibleAt", &Menu::IsVisibleAt)
|
.SetMethod("isVisibleAt", &Menu::IsVisibleAt)
|
||||||
.SetMethod("_popup", &Menu::Popup)
|
.SetMethod("popupAt", &Menu::PopupAt);
|
||||||
.SetMethod("_popupAt", &Menu::PopupAt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace api
|
} // namespace api
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -51,8 +51,9 @@ class Menu : public mate::Wrappable,
|
||||||
void ExecuteCommand(int command_id, int event_flags) override;
|
void ExecuteCommand(int command_id, int event_flags) override;
|
||||||
void MenuWillShow(ui::SimpleMenuModel* source) override;
|
void MenuWillShow(ui::SimpleMenuModel* source) override;
|
||||||
|
|
||||||
virtual void Popup(Window* window) = 0;
|
virtual void PopupAt(Window* window,
|
||||||
virtual void PopupAt(Window* window, int x, int y) = 0;
|
int x = -1, int y = -1,
|
||||||
|
int positioning_item = 0) = 0;
|
||||||
|
|
||||||
scoped_ptr<AtomMenuModel> model_;
|
scoped_ptr<AtomMenuModel> model_;
|
||||||
Menu* parent_;
|
Menu* parent_;
|
||||||
|
@ -73,6 +74,7 @@ class Menu : public mate::Wrappable,
|
||||||
Menu* menu);
|
Menu* menu);
|
||||||
void SetIcon(int index, const gfx::Image& image);
|
void SetIcon(int index, const gfx::Image& image);
|
||||||
void SetSublabel(int index, const base::string16& sublabel);
|
void SetSublabel(int index, const base::string16& sublabel);
|
||||||
|
void SetRole(int index, const base::string16& role);
|
||||||
void Clear();
|
void Clear();
|
||||||
int GetIndexOfCommandId(int command_id);
|
int GetIndexOfCommandId(int command_id);
|
||||||
int GetItemCount() const;
|
int GetItemCount() const;
|
||||||
|
|
|
@ -19,8 +19,7 @@ class MenuMac : public Menu {
|
||||||
protected:
|
protected:
|
||||||
MenuMac();
|
MenuMac();
|
||||||
|
|
||||||
void Popup(Window* window) override;
|
void PopupAt(Window* window, int x, int y, int positioning_item = 0) override;
|
||||||
void PopupAt(Window* window, int x, int y) override;
|
|
||||||
|
|
||||||
base::scoped_nsobject<AtomMenuController> menu_controller_;
|
base::scoped_nsobject<AtomMenuController> menu_controller_;
|
||||||
|
|
||||||
|
|
|
@ -18,39 +18,7 @@ namespace api {
|
||||||
MenuMac::MenuMac() {
|
MenuMac::MenuMac() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuMac::Popup(Window* window) {
|
void MenuMac::PopupAt(Window* window, int x, int y, int positioning_item) {
|
||||||
NativeWindow* native_window = window->window();
|
|
||||||
if (!native_window)
|
|
||||||
return;
|
|
||||||
content::WebContents* web_contents = native_window->web_contents();
|
|
||||||
if (!web_contents)
|
|
||||||
return;
|
|
||||||
|
|
||||||
NSWindow* nswindow = native_window->GetNativeWindow();
|
|
||||||
base::scoped_nsobject<AtomMenuController> menu_controller(
|
|
||||||
[[AtomMenuController alloc] initWithModel:model_.get()]);
|
|
||||||
|
|
||||||
// Fake out a context menu event.
|
|
||||||
NSEvent* currentEvent = [NSApp currentEvent];
|
|
||||||
NSPoint position = [nswindow mouseLocationOutsideOfEventStream];
|
|
||||||
NSTimeInterval eventTime = [currentEvent timestamp];
|
|
||||||
NSEvent* clickEvent = [NSEvent mouseEventWithType:NSRightMouseDown
|
|
||||||
location:position
|
|
||||||
modifierFlags:NSRightMouseDownMask
|
|
||||||
timestamp:eventTime
|
|
||||||
windowNumber:[nswindow windowNumber]
|
|
||||||
context:nil
|
|
||||||
eventNumber:0
|
|
||||||
clickCount:1
|
|
||||||
pressure:1.0];
|
|
||||||
|
|
||||||
// Show the menu.
|
|
||||||
[NSMenu popUpContextMenu:[menu_controller menu]
|
|
||||||
withEvent:clickEvent
|
|
||||||
forView:web_contents->GetContentNativeView()];
|
|
||||||
}
|
|
||||||
|
|
||||||
void MenuMac::PopupAt(Window* window, int x, int y) {
|
|
||||||
NativeWindow* native_window = window->window();
|
NativeWindow* native_window = window->window();
|
||||||
if (!native_window)
|
if (!native_window)
|
||||||
return;
|
return;
|
||||||
|
@ -63,10 +31,23 @@ void MenuMac::PopupAt(Window* window, int x, int y) {
|
||||||
NSMenu* menu = [menu_controller menu];
|
NSMenu* menu = [menu_controller menu];
|
||||||
NSView* view = web_contents->GetContentNativeView();
|
NSView* view = web_contents->GetContentNativeView();
|
||||||
|
|
||||||
|
// Which menu item to show.
|
||||||
|
NSMenuItem* item = nil;
|
||||||
|
if (positioning_item < [menu numberOfItems] && positioning_item >= 0)
|
||||||
|
item = [menu itemAtIndex:positioning_item];
|
||||||
|
|
||||||
|
// (-1, -1) means showing on mouse location.
|
||||||
|
NSPoint position;
|
||||||
|
if (x == -1 || y == -1) {
|
||||||
|
NSWindow* nswindow = native_window->GetNativeWindow();
|
||||||
|
position = [view convertPoint:[nswindow mouseLocationOutsideOfEventStream]
|
||||||
|
fromView:nil];
|
||||||
|
} else {
|
||||||
|
position = NSMakePoint(x, [view frame].size.height - y);
|
||||||
|
}
|
||||||
|
|
||||||
// Show the menu.
|
// Show the menu.
|
||||||
[menu popUpMenuPositioningItem:[menu itemAtIndex:0]
|
[menu popUpMenuPositioningItem:item atLocation:position inView:view];
|
||||||
atLocation:NSMakePoint(x, [view frame].size.height - y)
|
|
||||||
inView:view];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|
|
@ -16,11 +16,7 @@ namespace api {
|
||||||
MenuViews::MenuViews() {
|
MenuViews::MenuViews() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuViews::Popup(Window* window) {
|
void MenuViews::PopupAt(Window* window, int x, int y, int positioning_item) {
|
||||||
PopupAtPoint(window, gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MenuViews::PopupAt(Window* window, int x, int y) {
|
|
||||||
NativeWindow* native_window = static_cast<NativeWindow*>(window->window());
|
NativeWindow* native_window = static_cast<NativeWindow*>(window->window());
|
||||||
if (!native_window)
|
if (!native_window)
|
||||||
return;
|
return;
|
||||||
|
@ -31,18 +27,23 @@ void MenuViews::PopupAt(Window* window, int x, int y) {
|
||||||
if (!view)
|
if (!view)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gfx::Point origin = view->GetViewBounds().origin();
|
// (-1, -1) means showing on mouse location.
|
||||||
PopupAtPoint(window, gfx::Point(origin.x() + x, origin.y() + y));
|
gfx::Point location;
|
||||||
}
|
if (x == -1 || y == -1) {
|
||||||
|
location = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
|
||||||
|
} else {
|
||||||
|
gfx::Point origin = view->GetViewBounds().origin();
|
||||||
|
location = gfx::Point(origin.x() + x, origin.y() + y);
|
||||||
|
}
|
||||||
|
|
||||||
void MenuViews::PopupAtPoint(Window* window, const gfx::Point& point) {
|
// Show the menu.
|
||||||
views::MenuRunner menu_runner(
|
views::MenuRunner menu_runner(
|
||||||
model(),
|
model(),
|
||||||
views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS);
|
views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS);
|
||||||
ignore_result(menu_runner.RunMenuAt(
|
ignore_result(menu_runner.RunMenuAt(
|
||||||
static_cast<NativeWindowViews*>(window->window())->widget(),
|
static_cast<NativeWindowViews*>(window->window())->widget(),
|
||||||
NULL,
|
NULL,
|
||||||
gfx::Rect(point, gfx::Size()),
|
gfx::Rect(location, gfx::Size()),
|
||||||
views::MENU_ANCHOR_TOPLEFT,
|
views::MENU_ANCHOR_TOPLEFT,
|
||||||
ui::MENU_SOURCE_MOUSE));
|
ui::MENU_SOURCE_MOUSE));
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,9 @@ class MenuViews : public Menu {
|
||||||
MenuViews();
|
MenuViews();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Popup(Window* window) override;
|
void PopupAt(Window* window, int x, int y, int positioning_item = 0) override;
|
||||||
void PopupAt(Window* window, int x, int y) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void PopupAtPoint(Window* window, const gfx::Point& point);
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(MenuViews);
|
DISALLOW_COPY_AND_ASSIGN(MenuViews);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,11 @@
|
||||||
#include "atom/browser/api/atom_api_power_monitor.h"
|
#include "atom/browser/api/atom_api_power_monitor.h"
|
||||||
|
|
||||||
#include "atom/browser/browser.h"
|
#include "atom/browser/browser.h"
|
||||||
|
#include "atom/common/node_includes.h"
|
||||||
#include "base/power_monitor/power_monitor.h"
|
#include "base/power_monitor/power_monitor.h"
|
||||||
#include "base/power_monitor/power_monitor_device_source.h"
|
#include "base/power_monitor/power_monitor_device_source.h"
|
||||||
#include "native_mate/dictionary.h"
|
#include "native_mate/dictionary.h"
|
||||||
|
|
||||||
#include "atom/common/node_includes.h"
|
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
namespace api {
|
namespace api {
|
||||||
|
@ -41,9 +40,9 @@ void PowerMonitor::OnResume() {
|
||||||
// static
|
// static
|
||||||
v8::Local<v8::Value> PowerMonitor::Create(v8::Isolate* isolate) {
|
v8::Local<v8::Value> PowerMonitor::Create(v8::Isolate* isolate) {
|
||||||
if (!Browser::Get()->is_ready()) {
|
if (!Browser::Get()->is_ready()) {
|
||||||
node::ThrowError(
|
isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
|
||||||
isolate,
|
isolate,
|
||||||
"Cannot initialize \"power-monitor\" module before app is ready");
|
"Cannot initialize \"power-monitor\" module before app is ready")));
|
||||||
return v8::Null(isolate);
|
return v8::Null(isolate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "atom/common/node_includes.h"
|
||||||
#include "content/public/browser/power_save_blocker.h"
|
#include "content/public/browser/power_save_blocker.h"
|
||||||
#include "native_mate/dictionary.h"
|
#include "native_mate/dictionary.h"
|
||||||
#include "atom/common/node_includes.h"
|
|
||||||
|
|
||||||
namespace mate {
|
namespace mate {
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,264 +7,52 @@
|
||||||
#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"
|
||||||
#include "atom/browser/api/atom_api_session.h"
|
#include "atom/browser/net/url_request_async_asar_job.h"
|
||||||
#include "atom/browser/net/adapter_request_job.h"
|
#include "atom/browser/net/url_request_buffer_job.h"
|
||||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
#include "atom/browser/net/url_request_fetch_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/file_path_converter.h"
|
#include "atom/common/native_mate_converters/net_converter.h"
|
||||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
|
||||||
#include "content/public/browser/browser_thread.h"
|
|
||||||
#include "native_mate/dictionary.h"
|
|
||||||
#include "net/url_request/url_request_context.h"
|
|
||||||
|
|
||||||
#include "atom/common/node_includes.h"
|
#include "atom/common/node_includes.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 {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
|
|
||||||
|
|
||||||
scoped_refptr<base::RefCountedBytes> BufferToRefCountedBytes(
|
|
||||||
v8::Local<v8::Value> buf) {
|
|
||||||
scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes);
|
|
||||||
auto start = reinterpret_cast<const unsigned char*>(node::Buffer::Data(buf));
|
|
||||||
data->data().assign(start, start + node::Buffer::Length(buf));
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
class CustomProtocolRequestJob : public AdapterRequestJob {
|
|
||||||
public:
|
|
||||||
CustomProtocolRequestJob(Protocol* registry,
|
|
||||||
ProtocolHandler* protocol_handler,
|
|
||||||
net::URLRequest* request,
|
|
||||||
net::NetworkDelegate* network_delegate)
|
|
||||||
: AdapterRequestJob(protocol_handler, request, network_delegate),
|
|
||||||
registry_(registry) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetJobTypeInUI(const Protocol::JsProtocolHandler& callback) {
|
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
||||||
|
|
||||||
v8::Locker locker(registry_->isolate());
|
|
||||||
v8::HandleScope handle_scope(registry_->isolate());
|
|
||||||
|
|
||||||
// Call the JS handler.
|
|
||||||
v8::Local<v8::Value> result = callback.Run(request());
|
|
||||||
|
|
||||||
// Determine the type of the job we are going to create.
|
|
||||||
if (result->IsString()) {
|
|
||||||
std::string data = mate::V8ToString(result);
|
|
||||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
|
||||||
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
|
|
||||||
GetWeakPtr(), "text/plain", "UTF-8", data));
|
|
||||||
return;
|
|
||||||
} else if (result->IsObject()) {
|
|
||||||
v8::Local<v8::Object> obj = result->ToObject();
|
|
||||||
mate::Dictionary dict(registry_->isolate(), obj);
|
|
||||||
std::string name = mate::V8ToString(obj->GetConstructorName());
|
|
||||||
if (name == "RequestStringJob") {
|
|
||||||
std::string mime_type, charset, data;
|
|
||||||
dict.Get("mimeType", &mime_type);
|
|
||||||
dict.Get("charset", &charset);
|
|
||||||
dict.Get("data", &data);
|
|
||||||
|
|
||||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
|
||||||
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
|
|
||||||
GetWeakPtr(), mime_type, charset, data));
|
|
||||||
return;
|
|
||||||
} else if (name == "RequestBufferJob") {
|
|
||||||
std::string mime_type, encoding;
|
|
||||||
v8::Local<v8::Value> buffer;
|
|
||||||
dict.Get("mimeType", &mime_type);
|
|
||||||
dict.Get("encoding", &encoding);
|
|
||||||
dict.Get("data", &buffer);
|
|
||||||
|
|
||||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
|
||||||
base::Bind(&AdapterRequestJob::CreateBufferJobAndStart,
|
|
||||||
GetWeakPtr(), mime_type, encoding,
|
|
||||||
BufferToRefCountedBytes(buffer)));
|
|
||||||
return;
|
|
||||||
} else if (name == "RequestFileJob") {
|
|
||||||
base::FilePath path;
|
|
||||||
dict.Get("path", &path);
|
|
||||||
|
|
||||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
|
||||||
base::Bind(&AdapterRequestJob::CreateFileJobAndStart,
|
|
||||||
GetWeakPtr(), path));
|
|
||||||
return;
|
|
||||||
} else if (name == "RequestErrorJob") {
|
|
||||||
int error = net::ERR_NOT_IMPLEMENTED;
|
|
||||||
dict.Get("error", &error);
|
|
||||||
|
|
||||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
|
||||||
base::Bind(&AdapterRequestJob::CreateErrorJobAndStart,
|
|
||||||
GetWeakPtr(), error));
|
|
||||||
return;
|
|
||||||
} else if (name == "RequestHttpJob") {
|
|
||||||
GURL url;
|
|
||||||
std::string method, referrer;
|
|
||||||
dict.Get("url", &url);
|
|
||||||
dict.Get("method", &method);
|
|
||||||
dict.Get("referrer", &referrer);
|
|
||||||
|
|
||||||
v8::Local<v8::Value> value;
|
|
||||||
mate::Handle<Session> session;
|
|
||||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter;
|
|
||||||
// "session" null -> pass nullptr;
|
|
||||||
// "session" a Session object -> use passed session.
|
|
||||||
// "session" undefined -> use current session;
|
|
||||||
if (dict.Get("session", &session))
|
|
||||||
request_context_getter =
|
|
||||||
session->browser_context()->GetRequestContext();
|
|
||||||
else if (dict.Get("session", &value) && value->IsNull())
|
|
||||||
request_context_getter = nullptr;
|
|
||||||
else
|
|
||||||
request_context_getter = registry_->request_context_getter();
|
|
||||||
|
|
||||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
|
||||||
base::Bind(&AdapterRequestJob::CreateHttpJobAndStart, GetWeakPtr(),
|
|
||||||
request_context_getter, url, method, referrer));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try the default protocol handler if we have.
|
|
||||||
if (default_protocol_handler()) {
|
|
||||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
|
||||||
base::Bind(&AdapterRequestJob::CreateJobFromProtocolHandlerAndStart,
|
|
||||||
GetWeakPtr()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to the not implemented error.
|
|
||||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
|
||||||
base::Bind(&AdapterRequestJob::CreateErrorJobAndStart,
|
|
||||||
GetWeakPtr(), net::ERR_NOT_IMPLEMENTED));
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdapterRequestJob:
|
|
||||||
void GetJobType() override {
|
|
||||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
|
||||||
base::Bind(&CustomProtocolRequestJob::GetJobTypeInUI,
|
|
||||||
base::Unretained(this),
|
|
||||||
registry_->GetProtocolHandler(request()->url().scheme())));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Protocol* registry_; // Weak, the Protocol class is expected to live forever.
|
|
||||||
};
|
|
||||||
|
|
||||||
// Always return the same CustomProtocolRequestJob for all requests, because
|
|
||||||
// the content API needs the ProtocolHandler to return a job immediately, and
|
|
||||||
// getting the real job from the JS requires asynchronous calls, so we have
|
|
||||||
// to create an adapter job first.
|
|
||||||
// Users can also pass an extra ProtocolHandler as the fallback one when
|
|
||||||
// registered handler doesn't want to deal with the request.
|
|
||||||
class CustomProtocolHandler : public ProtocolHandler {
|
|
||||||
public:
|
|
||||||
CustomProtocolHandler(api::Protocol* registry,
|
|
||||||
ProtocolHandler* protocol_handler = NULL)
|
|
||||||
: registry_(registry), protocol_handler_(protocol_handler) {
|
|
||||||
}
|
|
||||||
|
|
||||||
net::URLRequestJob* MaybeCreateJob(
|
|
||||||
net::URLRequest* request,
|
|
||||||
net::NetworkDelegate* network_delegate) const override {
|
|
||||||
return new CustomProtocolRequestJob(registry_, protocol_handler_.get(),
|
|
||||||
request, network_delegate);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtocolHandler* ReleaseDefaultProtocolHandler() {
|
|
||||||
return protocol_handler_.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtocolHandler* original_handler() { return protocol_handler_.get(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Protocol* registry_; // Weak, the Protocol class is expected to live forever.
|
|
||||||
scoped_ptr<ProtocolHandler> protocol_handler_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string ConvertErrorCode(int error_code) {
|
|
||||||
switch (error_code) {
|
|
||||||
case Protocol::ERR_SCHEME_REGISTERED:
|
|
||||||
return "The Scheme is already registered";
|
|
||||||
case Protocol::ERR_SCHEME_UNREGISTERED:
|
|
||||||
return "The Scheme has not been registered";
|
|
||||||
case Protocol::ERR_SCHEME_INTERCEPTED:
|
|
||||||
return "There is no protocol handler to intercept";
|
|
||||||
case Protocol::ERR_SCHEME_UNINTERCEPTED:
|
|
||||||
return "The protocol is not intercepted";
|
|
||||||
case Protocol::ERR_NO_SCHEME:
|
|
||||||
return "The Scheme does not exist.";
|
|
||||||
case Protocol::ERR_SCHEME:
|
|
||||||
return "Cannot intercept custom protocols";
|
|
||||||
default:
|
|
||||||
NOTREACHED();
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
Protocol::Protocol(AtomBrowserContext* browser_context)
|
Protocol::Protocol(AtomBrowserContext* browser_context)
|
||||||
: request_context_getter_(browser_context->GetRequestContext()),
|
: request_context_getter_(browser_context->GetRequestContext()),
|
||||||
job_factory_(browser_context->job_factory()) {
|
job_factory_(browser_context->job_factory()) {
|
||||||
CHECK(job_factory_);
|
CHECK(job_factory_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Protocol::JsProtocolHandler Protocol::GetProtocolHandler(
|
|
||||||
const std::string& scheme) {
|
|
||||||
return protocol_handlers_[scheme];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Protocol::OnIOActionCompleted(const JsCompletionCallback& callback,
|
|
||||||
int error) {
|
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
||||||
v8::Locker locker(isolate());
|
|
||||||
v8::HandleScope handle_scope(isolate());
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
callback.Run(v8::Exception::Error(
|
|
||||||
mate::StringToV8(isolate(), ConvertErrorCode(error))));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback.Run(v8::Null(isolate()));
|
|
||||||
}
|
|
||||||
|
|
||||||
mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
|
mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
|
||||||
v8::Isolate* isolate) {
|
v8::Isolate* isolate) {
|
||||||
return mate::ObjectTemplateBuilder(isolate)
|
return mate::ObjectTemplateBuilder(isolate)
|
||||||
.SetMethod("registerStandardSchemes", &Protocol::RegisterStandardSchemes)
|
.SetMethod("registerStandardSchemes", &Protocol::RegisterStandardSchemes)
|
||||||
.SetMethod("isHandledProtocol", &Protocol::IsHandledProtocol)
|
.SetMethod("registerServiceWorkerSchemes",
|
||||||
.SetMethod("_registerProtocol", &Protocol::RegisterProtocol)
|
&Protocol::RegisterServiceWorkerSchemes)
|
||||||
.SetMethod("_unregisterProtocol", &Protocol::UnregisterProtocol)
|
.SetMethod("registerStringProtocol",
|
||||||
.SetMethod("_interceptProtocol", &Protocol::InterceptProtocol)
|
&Protocol::RegisterProtocol<URLRequestStringJob>)
|
||||||
.SetMethod("_uninterceptProtocol", &Protocol::UninterceptProtocol);
|
.SetMethod("registerBufferProtocol",
|
||||||
|
&Protocol::RegisterProtocol<URLRequestBufferJob>)
|
||||||
|
.SetMethod("registerFileProtocol",
|
||||||
|
&Protocol::RegisterProtocol<URLRequestAsyncAsarJob>)
|
||||||
|
.SetMethod("registerHttpProtocol",
|
||||||
|
&Protocol::RegisterProtocol<URLRequestFetchJob>)
|
||||||
|
.SetMethod("unregisterProtocol", &Protocol::UnregisterProtocol)
|
||||||
|
.SetMethod("isProtocolHandled", &Protocol::IsProtocolHandled)
|
||||||
|
.SetMethod("interceptStringProtocol",
|
||||||
|
&Protocol::InterceptProtocol<URLRequestStringJob>)
|
||||||
|
.SetMethod("interceptBufferProtocol",
|
||||||
|
&Protocol::InterceptProtocol<URLRequestBufferJob>)
|
||||||
|
.SetMethod("interceptFileProtocol",
|
||||||
|
&Protocol::InterceptProtocol<URLRequestAsyncAsarJob>)
|
||||||
|
.SetMethod("interceptHttpProtocol",
|
||||||
|
&Protocol::InterceptProtocol<URLRequestFetchJob>)
|
||||||
|
.SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Protocol::RegisterStandardSchemes(
|
void Protocol::RegisterStandardSchemes(
|
||||||
|
@ -272,131 +60,91 @@ void Protocol::RegisterStandardSchemes(
|
||||||
atom::AtomBrowserClient::SetCustomSchemes(schemes);
|
atom::AtomBrowserClient::SetCustomSchemes(schemes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Protocol::IsHandledProtocol(const std::string& scheme,
|
void Protocol::RegisterServiceWorkerSchemes(
|
||||||
const net::CompletionCallback& callback) {
|
const std::vector<std::string>& schemes) {
|
||||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
atom::AtomBrowserClient::SetCustomServiceWorkerSchemes(schemes);
|
||||||
base::Bind(&AtomURLRequestJobFactory::IsHandledProtocol,
|
}
|
||||||
base::Unretained(job_factory_), scheme),
|
|
||||||
|
void Protocol::UnregisterProtocol(
|
||||||
|
const std::string& scheme, mate::Arguments* args) {
|
||||||
|
CompletionCallback callback;
|
||||||
|
args->GetNext(&callback);
|
||||||
|
content::BrowserThread::PostTaskAndReplyWithResult(
|
||||||
|
content::BrowserThread::IO, FROM_HERE,
|
||||||
|
base::Bind(&Protocol::UnregisterProtocolInIO,
|
||||||
|
base::Unretained(this), scheme),
|
||||||
|
base::Bind(&Protocol::OnIOCompleted,
|
||||||
|
base::Unretained(this), callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
Protocol::ProtocolError Protocol::UnregisterProtocolInIO(
|
||||||
|
const std::string& scheme) {
|
||||||
|
if (!job_factory_->HasProtocolHandler(scheme))
|
||||||
|
return PROTOCOL_NOT_REGISTERED;
|
||||||
|
job_factory_->SetProtocolHandler(scheme, nullptr);
|
||||||
|
return PROTOCOL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Protocol::IsProtocolHandled(const std::string& scheme,
|
||||||
|
const BooleanCallback& callback) {
|
||||||
|
content::BrowserThread::PostTaskAndReplyWithResult(
|
||||||
|
content::BrowserThread::IO, FROM_HERE,
|
||||||
|
base::Bind(&Protocol::IsProtocolHandledInIO,
|
||||||
|
base::Unretained(this), scheme),
|
||||||
callback);
|
callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Protocol::RegisterProtocol(v8::Isolate* isolate,
|
bool Protocol::IsProtocolHandledInIO(const std::string& scheme) {
|
||||||
const std::string& scheme,
|
return job_factory_->IsHandledProtocol(scheme);
|
||||||
const JsProtocolHandler& handler,
|
|
||||||
const JsCompletionCallback& callback) {
|
|
||||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
|
||||||
base::Bind(&Protocol::RegisterProtocolInIO,
|
|
||||||
base::Unretained(this), scheme, handler),
|
|
||||||
base::Bind(&Protocol::OnIOActionCompleted,
|
|
||||||
base::Unretained(this), callback));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Protocol::UnregisterProtocol(v8::Isolate* isolate,
|
void Protocol::UninterceptProtocol(
|
||||||
const std::string& scheme,
|
const std::string& scheme, mate::Arguments* args) {
|
||||||
const JsCompletionCallback& callback) {
|
CompletionCallback callback;
|
||||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
args->GetNext(&callback);
|
||||||
base::Bind(&Protocol::UnregisterProtocolInIO,
|
content::BrowserThread::PostTaskAndReplyWithResult(
|
||||||
base::Unretained(this), scheme),
|
content::BrowserThread::IO, FROM_HERE,
|
||||||
base::Bind(&Protocol::OnIOActionCompleted,
|
|
||||||
base::Unretained(this), callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Protocol::InterceptProtocol(v8::Isolate* isolate,
|
|
||||||
const std::string& scheme,
|
|
||||||
const JsProtocolHandler& handler,
|
|
||||||
const JsCompletionCallback& callback) {
|
|
||||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
|
||||||
base::Bind(&Protocol::InterceptProtocolInIO,
|
|
||||||
base::Unretained(this), scheme, handler),
|
|
||||||
base::Bind(&Protocol::OnIOActionCompleted,
|
|
||||||
base::Unretained(this), callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Protocol::UninterceptProtocol(v8::Isolate* isolate,
|
|
||||||
const std::string& scheme,
|
|
||||||
const JsCompletionCallback& callback) {
|
|
||||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
|
||||||
base::Bind(&Protocol::UninterceptProtocolInIO,
|
base::Bind(&Protocol::UninterceptProtocolInIO,
|
||||||
base::Unretained(this), scheme),
|
base::Unretained(this), scheme),
|
||||||
base::Bind(&Protocol::OnIOActionCompleted,
|
base::Bind(&Protocol::OnIOCompleted,
|
||||||
base::Unretained(this), callback));
|
base::Unretained(this), callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
int Protocol::RegisterProtocolInIO(const std::string& scheme,
|
Protocol::ProtocolError Protocol::UninterceptProtocolInIO(
|
||||||
const JsProtocolHandler& handler) {
|
const std::string& scheme) {
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
if (!original_protocols_.contains(scheme))
|
||||||
|
return PROTOCOL_NOT_INTERCEPTED;
|
||||||
if (ContainsKey(protocol_handlers_, scheme) ||
|
job_factory_->ReplaceProtocol(scheme,
|
||||||
job_factory_->IsHandledProtocol(scheme)) {
|
original_protocols_.take_and_erase(scheme));
|
||||||
return ERR_SCHEME_REGISTERED;
|
return PROTOCOL_OK;
|
||||||
}
|
|
||||||
|
|
||||||
protocol_handlers_[scheme] = handler;
|
|
||||||
job_factory_->SetProtocolHandler(scheme, new CustomProtocolHandler(this));
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Protocol::UnregisterProtocolInIO(const std::string& scheme) {
|
void Protocol::OnIOCompleted(
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
const CompletionCallback& callback, ProtocolError error) {
|
||||||
|
// The completion callback is optional.
|
||||||
|
if (callback.is_null())
|
||||||
|
return;
|
||||||
|
|
||||||
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
|
v8::Locker locker(isolate());
|
||||||
if (it == protocol_handlers_.end()) {
|
v8::HandleScope handle_scope(isolate());
|
||||||
return ERR_SCHEME_UNREGISTERED;
|
|
||||||
|
if (error == PROTOCOL_OK) {
|
||||||
|
callback.Run(v8::Null(isolate()));
|
||||||
|
} else {
|
||||||
|
std::string str = ErrorCodeToString(error);
|
||||||
|
callback.Run(v8::Exception::Error(mate::StringToV8(isolate(), str)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol_handlers_.erase(it);
|
|
||||||
job_factory_->SetProtocolHandler(scheme, NULL);
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Protocol::InterceptProtocolInIO(const std::string& scheme,
|
std::string Protocol::ErrorCodeToString(ProtocolError error) {
|
||||||
const JsProtocolHandler& handler) {
|
switch (error) {
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
case PROTOCOL_FAIL: return "Failed to manipulate protocol factory";
|
||||||
|
case PROTOCOL_REGISTERED: return "The scheme has been registred";
|
||||||
// Force the request context to initialize, otherwise we might have nothing
|
case PROTOCOL_NOT_REGISTERED: return "The scheme has not been registred";
|
||||||
// to intercept.
|
case PROTOCOL_INTERCEPTED: return "The scheme has been intercepted";
|
||||||
request_context_getter_->GetURLRequestContext();
|
case PROTOCOL_NOT_INTERCEPTED: return "The scheme has not been intercepted";
|
||||||
|
default: return "Unexpected error";
|
||||||
if (!job_factory_->HasProtocolHandler(scheme))
|
|
||||||
return ERR_NO_SCHEME;
|
|
||||||
|
|
||||||
if (ContainsKey(protocol_handlers_, scheme))
|
|
||||||
return ERR_SCHEME;
|
|
||||||
|
|
||||||
protocol_handlers_[scheme] = handler;
|
|
||||||
ProtocolHandler* original_handler = job_factory_->GetProtocolHandler(scheme);
|
|
||||||
if (original_handler == nullptr) {
|
|
||||||
return ERR_SCHEME_INTERCEPTED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
job_factory_->ReplaceProtocol(
|
|
||||||
scheme, new CustomProtocolHandler(this, original_handler));
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Protocol::UninterceptProtocolInIO(const std::string& scheme) {
|
|
||||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
||||||
|
|
||||||
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
|
|
||||||
if (it == protocol_handlers_.end())
|
|
||||||
return ERR_SCHEME_UNREGISTERED;
|
|
||||||
|
|
||||||
protocol_handlers_.erase(it);
|
|
||||||
CustomProtocolHandler* handler = static_cast<CustomProtocolHandler*>(
|
|
||||||
job_factory_->GetProtocolHandler(scheme));
|
|
||||||
if (handler->original_handler() == nullptr) {
|
|
||||||
return ERR_SCHEME_UNINTERCEPTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the protocol handler to the orignal one and delete current protocol
|
|
||||||
// handler.
|
|
||||||
ProtocolHandler* original_handler = handler->ReleaseDefaultProtocolHandler();
|
|
||||||
delete job_factory_->ReplaceProtocol(scheme, original_handler);
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|
|
@ -9,10 +9,14 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "atom/browser/api/event_emitter.h"
|
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||||
#include "base/callback.h"
|
#include "base/callback.h"
|
||||||
|
#include "base/containers/scoped_ptr_hash_map.h"
|
||||||
|
#include "content/public/browser/browser_thread.h"
|
||||||
|
#include "native_mate/arguments.h"
|
||||||
|
#include "native_mate/dictionary.h"
|
||||||
#include "native_mate/handle.h"
|
#include "native_mate/handle.h"
|
||||||
#include "net/base/completion_callback.h"
|
#include "native_mate/wrappable.h"
|
||||||
|
|
||||||
namespace net {
|
namespace net {
|
||||||
class URLRequest;
|
class URLRequest;
|
||||||
|
@ -26,31 +30,16 @@ class AtomURLRequestJobFactory;
|
||||||
|
|
||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
class Protocol : public mate::EventEmitter {
|
class Protocol : public mate::Wrappable {
|
||||||
public:
|
public:
|
||||||
using JsProtocolHandler =
|
using Handler =
|
||||||
base::Callback<v8::Local<v8::Value>(const net::URLRequest*)>;
|
base::Callback<void(const net::URLRequest*, v8::Local<v8::Value>)>;
|
||||||
using JsCompletionCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
using CompletionCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||||
|
using BooleanCallback = base::Callback<void(bool)>;
|
||||||
enum {
|
|
||||||
OK = 0,
|
|
||||||
ERR_SCHEME_REGISTERED,
|
|
||||||
ERR_SCHEME_UNREGISTERED,
|
|
||||||
ERR_SCHEME_INTERCEPTED,
|
|
||||||
ERR_SCHEME_UNINTERCEPTED,
|
|
||||||
ERR_NO_SCHEME,
|
|
||||||
ERR_SCHEME
|
|
||||||
};
|
|
||||||
|
|
||||||
static mate::Handle<Protocol> Create(
|
static mate::Handle<Protocol> Create(
|
||||||
v8::Isolate* isolate, AtomBrowserContext* browser_context);
|
v8::Isolate* isolate, AtomBrowserContext* browser_context);
|
||||||
|
|
||||||
JsProtocolHandler GetProtocolHandler(const std::string& scheme);
|
|
||||||
|
|
||||||
net::URLRequestContextGetter* request_context_getter() {
|
|
||||||
return request_context_getter_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit Protocol(AtomBrowserContext* browser_context);
|
explicit Protocol(AtomBrowserContext* browser_context);
|
||||||
|
|
||||||
|
@ -59,48 +48,142 @@ class Protocol : public mate::EventEmitter {
|
||||||
v8::Isolate* isolate);
|
v8::Isolate* isolate);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::map<std::string, JsProtocolHandler> ProtocolHandlersMap;
|
// Possible errors.
|
||||||
|
enum ProtocolError {
|
||||||
|
PROTOCOL_OK, // no error
|
||||||
|
PROTOCOL_FAIL, // operation failed, should never occur
|
||||||
|
PROTOCOL_REGISTERED,
|
||||||
|
PROTOCOL_NOT_REGISTERED,
|
||||||
|
PROTOCOL_INTERCEPTED,
|
||||||
|
PROTOCOL_NOT_INTERCEPTED,
|
||||||
|
};
|
||||||
|
|
||||||
// Callback called after performing action on IO thread.
|
// The protocol handler that will create a protocol handler for certain
|
||||||
void OnIOActionCompleted(const JsCompletionCallback& callback,
|
// request job.
|
||||||
int error);
|
template<typename RequestJob>
|
||||||
|
class CustomProtocolHandler
|
||||||
|
: public net::URLRequestJobFactory::ProtocolHandler {
|
||||||
|
public:
|
||||||
|
CustomProtocolHandler(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
net::URLRequestContextGetter* request_context,
|
||||||
|
const Handler& handler)
|
||||||
|
: isolate_(isolate),
|
||||||
|
request_context_(request_context),
|
||||||
|
handler_(handler) {}
|
||||||
|
~CustomProtocolHandler() override {}
|
||||||
|
|
||||||
|
net::URLRequestJob* MaybeCreateJob(
|
||||||
|
net::URLRequest* request,
|
||||||
|
net::NetworkDelegate* network_delegate) const override {
|
||||||
|
RequestJob* request_job = new RequestJob(request, network_delegate);
|
||||||
|
request_job->SetHandlerInfo(isolate_, request_context_, handler_);
|
||||||
|
return request_job;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
v8::Isolate* isolate_;
|
||||||
|
net::URLRequestContextGetter* request_context_;
|
||||||
|
Protocol::Handler handler_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
|
||||||
|
};
|
||||||
|
|
||||||
// Register schemes to standard scheme list.
|
// Register schemes to standard scheme list.
|
||||||
void RegisterStandardSchemes(const std::vector<std::string>& schemes);
|
void RegisterStandardSchemes(const std::vector<std::string>& schemes);
|
||||||
|
|
||||||
// Returns whether a scheme has been registered.
|
// Register schemes that can handle service worker.
|
||||||
void IsHandledProtocol(const std::string& scheme,
|
void RegisterServiceWorkerSchemes(const std::vector<std::string>& schemes);
|
||||||
const net::CompletionCallback& callback);
|
|
||||||
|
|
||||||
// Register/unregister an networking |scheme| which would be handled by
|
// Register the protocol with certain request job.
|
||||||
// |callback|.
|
template<typename RequestJob>
|
||||||
void RegisterProtocol(v8::Isolate* isolate,
|
void RegisterProtocol(const std::string& scheme,
|
||||||
const std::string& scheme,
|
const Handler& handler,
|
||||||
const JsProtocolHandler& handler,
|
mate::Arguments* args) {
|
||||||
const JsCompletionCallback& callback);
|
CompletionCallback callback;
|
||||||
void UnregisterProtocol(v8::Isolate* isolate, const std::string& scheme,
|
args->GetNext(&callback);
|
||||||
const JsCompletionCallback& callback);
|
content::BrowserThread::PostTaskAndReplyWithResult(
|
||||||
|
content::BrowserThread::IO, FROM_HERE,
|
||||||
|
base::Bind(&Protocol::RegisterProtocolInIO<RequestJob>,
|
||||||
|
base::Unretained(this), scheme, handler),
|
||||||
|
base::Bind(&Protocol::OnIOCompleted,
|
||||||
|
base::Unretained(this), callback));
|
||||||
|
}
|
||||||
|
template<typename RequestJob>
|
||||||
|
ProtocolError RegisterProtocolInIO(const std::string& scheme,
|
||||||
|
const Handler& handler) {
|
||||||
|
if (job_factory_->IsHandledProtocol(scheme))
|
||||||
|
return PROTOCOL_REGISTERED;
|
||||||
|
scoped_ptr<CustomProtocolHandler<RequestJob>> protocol_handler(
|
||||||
|
new CustomProtocolHandler<RequestJob>(
|
||||||
|
isolate(), request_context_getter_, handler));
|
||||||
|
if (job_factory_->SetProtocolHandler(scheme, protocol_handler.Pass()))
|
||||||
|
return PROTOCOL_OK;
|
||||||
|
else
|
||||||
|
return PROTOCOL_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
// Intercept/unintercept an existing protocol handler.
|
// Unregister the protocol handler that handles |scheme|.
|
||||||
void InterceptProtocol(v8::Isolate* isolate,
|
void UnregisterProtocol(const std::string& scheme, mate::Arguments* args);
|
||||||
const std::string& scheme,
|
ProtocolError UnregisterProtocolInIO(const std::string& scheme);
|
||||||
const JsProtocolHandler& handler,
|
|
||||||
const JsCompletionCallback& callback);
|
|
||||||
void UninterceptProtocol(v8::Isolate* isolate, const std::string& scheme,
|
|
||||||
const JsCompletionCallback& callback);
|
|
||||||
|
|
||||||
// The networking related operations have to be done in IO thread.
|
// Whether the protocol has handler registered.
|
||||||
int RegisterProtocolInIO(const std::string& scheme,
|
void IsProtocolHandled(const std::string& scheme,
|
||||||
const JsProtocolHandler& handler);
|
const BooleanCallback& callback);
|
||||||
int UnregisterProtocolInIO(const std::string& scheme);
|
bool IsProtocolHandledInIO(const std::string& scheme);
|
||||||
int InterceptProtocolInIO(const std::string& scheme,
|
|
||||||
const JsProtocolHandler& handler);
|
|
||||||
int UninterceptProtocolInIO(const std::string& scheme);
|
|
||||||
|
|
||||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
|
// Replace the protocol handler with a new one.
|
||||||
|
template<typename RequestJob>
|
||||||
|
void InterceptProtocol(const std::string& scheme,
|
||||||
|
const Handler& handler,
|
||||||
|
mate::Arguments* args) {
|
||||||
|
CompletionCallback callback;
|
||||||
|
args->GetNext(&callback);
|
||||||
|
content::BrowserThread::PostTaskAndReplyWithResult(
|
||||||
|
content::BrowserThread::IO, FROM_HERE,
|
||||||
|
base::Bind(&Protocol::InterceptProtocolInIO<RequestJob>,
|
||||||
|
base::Unretained(this), scheme, handler),
|
||||||
|
base::Bind(&Protocol::OnIOCompleted,
|
||||||
|
base::Unretained(this), callback));
|
||||||
|
}
|
||||||
|
template<typename RequestJob>
|
||||||
|
ProtocolError InterceptProtocolInIO(const std::string& scheme,
|
||||||
|
const Handler& handler) {
|
||||||
|
if (!job_factory_->IsHandledProtocol(scheme))
|
||||||
|
return PROTOCOL_NOT_REGISTERED;
|
||||||
|
// It is possible a protocol is handled but can not be intercepted.
|
||||||
|
if (!job_factory_->HasProtocolHandler(scheme))
|
||||||
|
return PROTOCOL_FAIL;
|
||||||
|
if (ContainsKey(original_protocols_, scheme))
|
||||||
|
return PROTOCOL_INTERCEPTED;
|
||||||
|
scoped_ptr<CustomProtocolHandler<RequestJob>> protocol_handler(
|
||||||
|
new CustomProtocolHandler<RequestJob>(
|
||||||
|
isolate(), request_context_getter_, handler));
|
||||||
|
original_protocols_.set(
|
||||||
|
scheme,
|
||||||
|
job_factory_->ReplaceProtocol(scheme, protocol_handler.Pass()));
|
||||||
|
return PROTOCOL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
AtomURLRequestJobFactory* job_factory_;
|
// Restore the |scheme| to its original protocol handler.
|
||||||
ProtocolHandlersMap protocol_handlers_;
|
void UninterceptProtocol(const std::string& scheme, mate::Arguments* args);
|
||||||
|
ProtocolError UninterceptProtocolInIO(const std::string& scheme);
|
||||||
|
|
||||||
|
// Convert error code to JS exception and call the callback.
|
||||||
|
void OnIOCompleted(const CompletionCallback& callback, ProtocolError error);
|
||||||
|
|
||||||
|
// Convert error code to string.
|
||||||
|
std::string ErrorCodeToString(ProtocolError error);
|
||||||
|
|
||||||
|
net::URLRequestContextGetter* request_context_getter_;
|
||||||
|
|
||||||
|
// Map that stores the original protocols of schemes.
|
||||||
|
using OriginalProtocolsMap = base::ScopedPtrHashMap<
|
||||||
|
std::string,
|
||||||
|
scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>>;
|
||||||
|
OriginalProtocolsMap original_protocols_;
|
||||||
|
|
||||||
|
AtomURLRequestJobFactory* job_factory_; // weak ref
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Protocol);
|
DISALLOW_COPY_AND_ASSIGN(Protocol);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,14 +113,16 @@ mate::ObjectTemplateBuilder Screen::GetObjectTemplateBuilder(
|
||||||
// static
|
// static
|
||||||
v8::Local<v8::Value> Screen::Create(v8::Isolate* isolate) {
|
v8::Local<v8::Value> Screen::Create(v8::Isolate* isolate) {
|
||||||
if (!Browser::Get()->is_ready()) {
|
if (!Browser::Get()->is_ready()) {
|
||||||
node::ThrowError(isolate,
|
isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
|
||||||
"Cannot initialize \"screen\" module before app is ready");
|
isolate,
|
||||||
|
"Cannot initialize \"screen\" module before app is ready")));
|
||||||
return v8::Null(isolate);
|
return v8::Null(isolate);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Screen* screen = gfx::Screen::GetNativeScreen();
|
gfx::Screen* screen = gfx::Screen::GetNativeScreen();
|
||||||
if (!screen) {
|
if (!screen) {
|
||||||
node::ThrowError(isolate, "Failed to get screen information");
|
isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
|
||||||
|
isolate, "Failed to get screen information")));
|
||||||
return v8::Null(isolate);
|
return v8::Null(isolate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,14 +8,25 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#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_web_contents.h"
|
||||||
|
#include "atom/browser/api/atom_api_web_request.h"
|
||||||
|
#include "atom/browser/api/save_page_handler.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/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 "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_number_conversions.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"
|
||||||
|
@ -28,8 +39,6 @@
|
||||||
#include "net/url_request/url_request_context.h"
|
#include "net/url_request/url_request_context.h"
|
||||||
#include "net/url_request/url_request_context_getter.h"
|
#include "net/url_request/url_request_context_getter.h"
|
||||||
|
|
||||||
#include "atom/common/node_includes.h"
|
|
||||||
|
|
||||||
using content::BrowserThread;
|
using content::BrowserThread;
|
||||||
using content::StoragePartition;
|
using content::StoragePartition;
|
||||||
|
|
||||||
|
@ -44,7 +53,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")
|
||||||
|
@ -68,7 +77,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")
|
||||||
|
@ -101,6 +110,35 @@ 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_rules;
|
||||||
|
GURL pac_url;
|
||||||
|
mate::Dictionary options;
|
||||||
|
// Fallback to previous API when passed String.
|
||||||
|
// https://git.io/vuhjj
|
||||||
|
if (ConvertFromV8(isolate, val, &proxy_rules)) {
|
||||||
|
pac_url = GURL(proxy_rules); // Assume it is PAC script if it is URL.
|
||||||
|
} else if (ConvertFromV8(isolate, val, &options)) {
|
||||||
|
options.Get("pacScript", &pac_url);
|
||||||
|
options.Get("proxyRules", &proxy_rules);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pacScript takes precedence over proxyRules.
|
||||||
|
if (!pac_url.is_empty() && pac_url.is_valid()) {
|
||||||
|
out->set_pac_url(pac_url);
|
||||||
|
} else {
|
||||||
|
out->proxy_rules().ParseFromString(proxy_rules);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace mate
|
} // namespace mate
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
@ -109,6 +147,10 @@ namespace api {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// The wrapSession funtion which is implemented in JavaScript
|
||||||
|
using WrapSessionCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||||
|
WrapSessionCallback g_wrap_session;
|
||||||
|
|
||||||
class ResolveProxyHelper {
|
class ResolveProxyHelper {
|
||||||
public:
|
public:
|
||||||
ResolveProxyHelper(AtomBrowserContext* browser_context,
|
ResolveProxyHelper(AtomBrowserContext* browser_context,
|
||||||
|
@ -163,7 +205,7 @@ class ResolveProxyHelper {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Runs the callback in UI thread.
|
// Runs the callback in UI thread.
|
||||||
template <typename ...T>
|
template<typename ...T>
|
||||||
void RunCallbackInUI(const base::Callback<void(T...)>& callback, T... result) {
|
void RunCallbackInUI(const base::Callback<void(T...)>& callback, T... result) {
|
||||||
BrowserThread::PostTask(
|
BrowserThread::PostTask(
|
||||||
BrowserThread::UI, FROM_HERE, base::Bind(callback, result...));
|
BrowserThread::UI, FROM_HERE, base::Bind(callback, result...));
|
||||||
|
@ -171,19 +213,35 @@ void RunCallbackInUI(const base::Callback<void(T...)>& callback, T... result) {
|
||||||
|
|
||||||
// Callback of HttpCache::GetBackend.
|
// Callback of HttpCache::GetBackend.
|
||||||
void OnGetBackend(disk_cache::Backend** backend_ptr,
|
void OnGetBackend(disk_cache::Backend** backend_ptr,
|
||||||
|
Session::CacheAction action,
|
||||||
const net::CompletionCallback& callback,
|
const net::CompletionCallback& callback,
|
||||||
int result) {
|
int result) {
|
||||||
if (result != net::OK) {
|
if (result != net::OK) {
|
||||||
RunCallbackInUI(callback, result);
|
RunCallbackInUI(callback, result);
|
||||||
} else if (backend_ptr && *backend_ptr) {
|
} else if (backend_ptr && *backend_ptr) {
|
||||||
(*backend_ptr)->DoomAllEntries(base::Bind(&RunCallbackInUI<int>, callback));
|
if (action == Session::CacheAction::CLEAR) {
|
||||||
|
(*backend_ptr)->DoomAllEntries(base::Bind(&RunCallbackInUI<int>,
|
||||||
|
callback));
|
||||||
|
} else if (action == Session::CacheAction::STATS) {
|
||||||
|
base::StringPairs stats;
|
||||||
|
(*backend_ptr)->GetStats(&stats);
|
||||||
|
for (size_t i = 0; i < stats.size(); ++i) {
|
||||||
|
if (stats[i].first == "Current size") {
|
||||||
|
int current_size;
|
||||||
|
base::StringToInt(stats[i].second, ¤t_size);
|
||||||
|
RunCallbackInUI(callback, current_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
RunCallbackInUI<int>(callback, net::ERR_FAILED);
|
RunCallbackInUI<int>(callback, net::ERR_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearHttpCacheInIO(
|
void DoCacheActionInIO(
|
||||||
const scoped_refptr<net::URLRequestContextGetter>& context_getter,
|
const scoped_refptr<net::URLRequestContextGetter>& context_getter,
|
||||||
|
Session::CacheAction action,
|
||||||
const net::CompletionCallback& callback) {
|
const net::CompletionCallback& callback) {
|
||||||
auto request_context = context_getter->GetURLRequestContext();
|
auto request_context = context_getter->GetURLRequestContext();
|
||||||
auto http_cache = request_context->http_transaction_factory()->GetCache();
|
auto http_cache = request_context->http_transaction_factory()->GetCache();
|
||||||
|
@ -194,19 +252,20 @@ void ClearHttpCacheInIO(
|
||||||
using BackendPtr = disk_cache::Backend*;
|
using BackendPtr = disk_cache::Backend*;
|
||||||
BackendPtr* backend_ptr = new BackendPtr(nullptr);
|
BackendPtr* backend_ptr = new BackendPtr(nullptr);
|
||||||
net::CompletionCallback on_get_backend =
|
net::CompletionCallback on_get_backend =
|
||||||
base::Bind(&OnGetBackend, base::Owned(backend_ptr), callback);
|
base::Bind(&OnGetBackend, base::Owned(backend_ptr), action, callback);
|
||||||
int rv = http_cache->GetBackend(backend_ptr, on_get_backend);
|
int rv = http_cache->GetBackend(backend_ptr, on_get_backend);
|
||||||
if (rv != net::ERR_IO_PENDING)
|
if (rv != net::ERR_IO_PENDING)
|
||||||
on_get_backend.Run(net::OK);
|
on_get_backend.Run(net::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,19 +274,42 @@ void SetProxyInIO(net::URLRequestContextGetter* getter,
|
||||||
Session::Session(AtomBrowserContext* browser_context)
|
Session::Session(AtomBrowserContext* browser_context)
|
||||||
: browser_context_(browser_context) {
|
: browser_context_(browser_context) {
|
||||||
AttachAsUserData(browser_context);
|
AttachAsUserData(browser_context);
|
||||||
|
|
||||||
|
// Observe DownloadManger to get download notifications.
|
||||||
|
content::BrowserContext::GetDownloadManager(browser_context)->
|
||||||
|
AddObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Session::~Session() {
|
Session::~Session() {
|
||||||
|
content::BrowserContext::GetDownloadManager(browser_context())->
|
||||||
|
RemoveObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::OnDownloadCreated(content::DownloadManager* manager,
|
||||||
|
content::DownloadItem* item) {
|
||||||
|
auto web_contents = item->GetWebContents();
|
||||||
|
if (SavePageHandler::IsSavePageTypes(item->GetMimeType()))
|
||||||
|
return;
|
||||||
|
bool prevent_default = Emit(
|
||||||
|
"will-download",
|
||||||
|
DownloadItem::Create(isolate(), item),
|
||||||
|
api::WebContents::CreateFrom(isolate(), web_contents));
|
||||||
|
if (prevent_default) {
|
||||||
|
item->Cancel(true);
|
||||||
|
item->Remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::ClearCache(const net::CompletionCallback& callback) {
|
template<Session::CacheAction action>
|
||||||
|
void Session::DoCacheAction(const net::CompletionCallback& callback) {
|
||||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||||
base::Bind(&ClearHttpCacheInIO,
|
base::Bind(&DoCacheActionInIO,
|
||||||
make_scoped_refptr(browser_context_->GetRequestContext()),
|
make_scoped_refptr(browser_context_->GetRequestContext()),
|
||||||
|
action,
|
||||||
callback));
|
callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,18 +324,24 @@ void Session::ClearStorageData(mate::Arguments* args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto storage_partition =
|
auto storage_partition =
|
||||||
content::BrowserContext::GetStoragePartition(browser_context_, nullptr);
|
content::BrowserContext::GetStoragePartition(browser_context(), nullptr);
|
||||||
storage_partition->ClearData(
|
storage_partition->ClearData(
|
||||||
options.storage_types, options.quota_types, options.origin,
|
options.storage_types, options.quota_types, options.origin,
|
||||||
content::StoragePartition::OriginMatcherFunction(),
|
content::StoragePartition::OriginMatcherFunction(),
|
||||||
base::Time(), base::Time::Max(), callback);
|
base::Time(), base::Time::Max(), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::SetProxy(const std::string& proxy,
|
void Session::FlushStorageData() {
|
||||||
|
auto storage_partition =
|
||||||
|
content::BrowserContext::GetStoragePartition(browser_context(), nullptr);
|
||||||
|
storage_partition->Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
@ -261,36 +349,135 @@ 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());
|
||||||
cookies_.Reset(isolate, handle.ToV8());
|
cookies_.Reset(isolate, handle.ToV8());
|
||||||
}
|
}
|
||||||
return v8::Local<v8::Value>::New(isolate, cookies_);
|
return v8::Local<v8::Value>::New(isolate, cookies_);
|
||||||
}
|
}
|
||||||
|
|
||||||
mate::ObjectTemplateBuilder Session::GetObjectTemplateBuilder(
|
v8::Local<v8::Value> Session::WebRequest(v8::Isolate* isolate) {
|
||||||
v8::Isolate* isolate) {
|
if (web_request_.IsEmpty()) {
|
||||||
return mate::ObjectTemplateBuilder(isolate)
|
auto handle = atom::api::WebRequest::Create(isolate, browser_context());
|
||||||
.SetMethod("resolveProxy", &Session::ResolveProxy)
|
web_request_.Reset(isolate, handle.ToV8());
|
||||||
.SetMethod("clearCache", &Session::ClearCache)
|
}
|
||||||
.SetMethod("clearStorageData", &Session::ClearStorageData)
|
return v8::Local<v8::Value>::New(isolate, web_request_);
|
||||||
.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,
|
v8::Isolate* isolate, AtomBrowserContext* browser_context) {
|
||||||
AtomBrowserContext* browser_context) {
|
|
||||||
auto existing = TrackableObject::FromWrappedClass(isolate, browser_context);
|
auto existing = TrackableObject::FromWrappedClass(isolate, browser_context);
|
||||||
if (existing)
|
if (existing)
|
||||||
return mate::CreateHandle(isolate, static_cast<Session*>(existing));
|
return mate::CreateHandle(isolate, static_cast<Session*>(existing));
|
||||||
|
|
||||||
return mate::CreateHandle(isolate, new Session(browser_context));
|
auto handle = mate::CreateHandle(isolate, new Session(browser_context));
|
||||||
|
g_wrap_session.Run(handle.ToV8());
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
mate::Handle<Session> Session::FromPartition(
|
||||||
|
v8::Isolate* isolate, const std::string& partition, bool in_memory) {
|
||||||
|
auto browser_context = brightray::BrowserContext::From(partition, in_memory);
|
||||||
|
return CreateFrom(isolate,
|
||||||
|
static_cast<AtomBrowserContext*>(browser_context.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Session::BuildPrototype(v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::ObjectTemplate> prototype) {
|
||||||
|
mate::ObjectTemplateBuilder(isolate, prototype)
|
||||||
|
.MakeDestroyable()
|
||||||
|
.SetMethod("resolveProxy", &Session::ResolveProxy)
|
||||||
|
.SetMethod("getCacheSize", &Session::DoCacheAction<CacheAction::STATS>)
|
||||||
|
.SetMethod("clearCache", &Session::DoCacheAction<CacheAction::CLEAR>)
|
||||||
|
.SetMethod("clearStorageData", &Session::ClearStorageData)
|
||||||
|
.SetMethod("flushStorageData", &Session::FlushStorageData)
|
||||||
|
.SetMethod("setProxy", &Session::SetProxy)
|
||||||
|
.SetMethod("setDownloadPath", &Session::SetDownloadPath)
|
||||||
|
.SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
|
||||||
|
.SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
|
||||||
|
.SetMethod("setCertificateVerifyProc", &Session::SetCertVerifyProc)
|
||||||
|
.SetProperty("cookies", &Session::Cookies)
|
||||||
|
.SetProperty("webRequest", &Session::WebRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearWrapSession() {
|
||||||
|
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
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||||
|
v8::Local<v8::Context> context, void* priv) {
|
||||||
|
v8::Isolate* isolate = context->GetIsolate();
|
||||||
|
mate::Dictionary dict(isolate, exports);
|
||||||
|
dict.SetMethod("fromPartition", &atom::api::Session::FromPartition);
|
||||||
|
dict.SetMethod("_setWrapSession", &atom::api::SetWrapSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_session, Initialize)
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "atom/browser/api/trackable_object.h"
|
#include "atom/browser/api/trackable_object.h"
|
||||||
|
#include "content/public/browser/download_manager.h"
|
||||||
#include "native_mate/handle.h"
|
#include "native_mate/handle.h"
|
||||||
#include "net/base/completion_callback.h"
|
#include "net/base/completion_callback.h"
|
||||||
|
|
||||||
|
@ -19,6 +20,11 @@ class FilePath;
|
||||||
|
|
||||||
namespace mate {
|
namespace mate {
|
||||||
class Arguments;
|
class Arguments;
|
||||||
|
class Dictionary;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace net {
|
||||||
|
class ProxyConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
@ -27,35 +33,57 @@ class AtomBrowserContext;
|
||||||
|
|
||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
class Session: public mate::TrackableObject<Session> {
|
class Session: public mate::TrackableObject<Session>,
|
||||||
|
public content::DownloadManager::Observer {
|
||||||
public:
|
public:
|
||||||
using ResolveProxyCallback = base::Callback<void(std::string)>;
|
using ResolveProxyCallback = base::Callback<void(std::string)>;
|
||||||
|
|
||||||
|
enum class CacheAction {
|
||||||
|
CLEAR,
|
||||||
|
STATS,
|
||||||
|
};
|
||||||
|
|
||||||
// Gets or creates Session from the |browser_context|.
|
// Gets or creates Session from the |browser_context|.
|
||||||
static mate::Handle<Session> CreateFrom(
|
static mate::Handle<Session> CreateFrom(
|
||||||
v8::Isolate* isolate, AtomBrowserContext* browser_context);
|
v8::Isolate* isolate, AtomBrowserContext* browser_context);
|
||||||
|
|
||||||
AtomBrowserContext* browser_context() const { return browser_context_; }
|
// Gets the Session of |partition| and |in_memory|.
|
||||||
|
static mate::Handle<Session> FromPartition(
|
||||||
|
v8::Isolate* isolate, const std::string& partition, bool in_memory);
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
// mate::Wrappable implementations:
|
// content::DownloadManager::Observer:
|
||||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
void OnDownloadCreated(content::DownloadManager* manager,
|
||||||
v8::Isolate* isolate) override;
|
content::DownloadItem* item) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
|
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
|
||||||
void ClearCache(const net::CompletionCallback& callback);
|
template<CacheAction action>
|
||||||
|
void DoCacheAction(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 FlushStorageData();
|
||||||
|
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);
|
||||||
|
v8::Local<v8::Value> WebRequest(v8::Isolate* isolate);
|
||||||
|
|
||||||
|
// Cached object.
|
||||||
v8::Global<v8::Value> cookies_;
|
v8::Global<v8::Value> cookies_;
|
||||||
|
v8::Global<v8::Value> web_request_;
|
||||||
|
|
||||||
AtomBrowserContext* browser_context_; // weak ref
|
scoped_refptr<AtomBrowserContext> browser_context_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Session);
|
DISALLOW_COPY_AND_ASSIGN(Session);
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,13 +12,12 @@
|
||||||
#include "atom/common/native_mate_converters/gfx_converter.h"
|
#include "atom/common/native_mate_converters/gfx_converter.h"
|
||||||
#include "atom/common/native_mate_converters/image_converter.h"
|
#include "atom/common/native_mate_converters/image_converter.h"
|
||||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||||
|
#include "atom/common/node_includes.h"
|
||||||
#include "native_mate/constructor.h"
|
#include "native_mate/constructor.h"
|
||||||
#include "native_mate/dictionary.h"
|
#include "native_mate/dictionary.h"
|
||||||
#include "ui/events/event_constants.h"
|
#include "ui/events/event_constants.h"
|
||||||
#include "ui/gfx/image/image.h"
|
#include "ui/gfx/image/image.h"
|
||||||
|
|
||||||
#include "atom/common/node_includes.h"
|
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
namespace api {
|
namespace api {
|
||||||
|
@ -35,7 +34,8 @@ Tray::~Tray() {
|
||||||
// static
|
// static
|
||||||
mate::Wrappable* Tray::New(v8::Isolate* isolate, const gfx::Image& image) {
|
mate::Wrappable* Tray::New(v8::Isolate* isolate, const gfx::Image& image) {
|
||||||
if (!Browser::Get()->is_ready()) {
|
if (!Browser::Get()->is_ready()) {
|
||||||
node::ThrowError(isolate, "Cannot create Tray before app is ready");
|
isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
|
||||||
|
isolate, "Cannot create Tray before app is ready")));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return new Tray(image);
|
return new Tray(image);
|
||||||
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -5,16 +5,22 @@
|
||||||
#include "atom/browser/api/atom_api_web_contents.h"
|
#include "atom/browser/api/atom_api_web_contents.h"
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "atom/browser/api/atom_api_debugger.h"
|
||||||
#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"
|
||||||
#include "atom/browser/native_window.h"
|
#include "atom/browser/native_window.h"
|
||||||
|
#include "atom/browser/web_contents_preferences.h"
|
||||||
#include "atom/browser/web_view_guest_delegate.h"
|
#include "atom/browser/web_view_guest_delegate.h"
|
||||||
#include "atom/common/api/api_messages.h"
|
#include "atom/common/api/api_messages.h"
|
||||||
#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/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"
|
||||||
|
@ -24,25 +30,32 @@
|
||||||
#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/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/navigation_details.h"
|
#include "content/public/browser/navigation_details.h"
|
||||||
#include "content/public/browser/navigation_entry.h"
|
#include "content/public/browser/navigation_entry.h"
|
||||||
#include "content/public/browser/plugin_service.h"
|
#include "content/public/browser/plugin_service.h"
|
||||||
#include "content/public/browser/render_frame_host.h"
|
#include "content/public/browser/render_frame_host.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/render_widget_host_view.h"
|
||||||
#include "content/public/browser/resource_request_details.h"
|
#include "content/public/browser/resource_request_details.h"
|
||||||
#include "content/public/browser/service_worker_context.h"
|
#include "content/public/browser/service_worker_context.h"
|
||||||
#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 "ui/base/l10n/l10n_util.h"
|
||||||
|
|
||||||
#include "atom/common/node_includes.h"
|
#include "atom/common/node_includes.h"
|
||||||
|
|
||||||
|
@ -54,9 +67,12 @@ 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -114,6 +130,53 @@ struct Converter<WindowOpenDisposition> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Converter<net::HttpResponseHeaders*> {
|
||||||
|
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||||
|
net::HttpResponseHeaders* headers) {
|
||||||
|
base::DictionaryValue response_headers;
|
||||||
|
if (headers) {
|
||||||
|
void* iter = nullptr;
|
||||||
|
std::string key;
|
||||||
|
std::string value;
|
||||||
|
while (headers->EnumerateHeaderLines(&iter, &key, &value)) {
|
||||||
|
key = base::ToLowerASCII(key);
|
||||||
|
if (response_headers.HasKey(key)) {
|
||||||
|
base::ListValue* values = nullptr;
|
||||||
|
if (response_headers.GetList(key, &values))
|
||||||
|
values->AppendString(value);
|
||||||
|
} else {
|
||||||
|
scoped_ptr<base::ListValue> values(new base::ListValue());
|
||||||
|
values->AppendString(value);
|
||||||
|
response_headers.Set(key, values.Pass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ConvertToV8(isolate, response_headers);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
@ -123,9 +186,7 @@ namespace api {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
v8::Persistent<v8::ObjectTemplate> template_;
|
// The wrapWebContents function which is implemented in JavaScript
|
||||||
|
|
||||||
// The wrapWebContents funtion 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;
|
||||||
|
|
||||||
|
@ -153,23 +214,42 @@ WebContents::WebContents(content::WebContents* web_contents)
|
||||||
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
|
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
|
||||||
}
|
}
|
||||||
|
|
||||||
WebContents::WebContents(const mate::Dictionary& options) {
|
WebContents::WebContents(v8::Isolate* isolate,
|
||||||
|
const mate::Dictionary& options)
|
||||||
|
: request_id_(0) {
|
||||||
|
// Whether it is a guest WebContents.
|
||||||
bool is_guest = false;
|
bool is_guest = false;
|
||||||
options.Get("isGuest", &is_guest);
|
options.Get("isGuest", &is_guest);
|
||||||
|
|
||||||
type_ = is_guest ? WEB_VIEW : BROWSER_WINDOW;
|
type_ = is_guest ? WEB_VIEW : BROWSER_WINDOW;
|
||||||
|
|
||||||
auto browser_context = AtomBrowserMainParts::Get()->browser_context();
|
// Obtain the session.
|
||||||
|
std::string partition;
|
||||||
|
mate::Handle<api::Session> session;
|
||||||
|
if (options.Get("session", &session)) {
|
||||||
|
} else if (options.Get("partition", &partition) && !partition.empty()) {
|
||||||
|
bool in_memory = true;
|
||||||
|
if (base::StartsWith(partition, "persist:", base::CompareCase::SENSITIVE)) {
|
||||||
|
in_memory = false;
|
||||||
|
partition = partition.substr(8);
|
||||||
|
}
|
||||||
|
session = Session::FromPartition(isolate, partition, in_memory);
|
||||||
|
} else {
|
||||||
|
// Use the default session if not specified.
|
||||||
|
session = Session::FromPartition(isolate, "", false);
|
||||||
|
}
|
||||||
|
session_.Reset(isolate, session.ToV8());
|
||||||
|
|
||||||
content::WebContents* web_contents;
|
content::WebContents* web_contents;
|
||||||
if (is_guest) {
|
if (is_guest) {
|
||||||
content::SiteInstance* site_instance = content::SiteInstance::CreateForURL(
|
content::SiteInstance* site_instance = content::SiteInstance::CreateForURL(
|
||||||
browser_context, GURL("chrome-guest://fake-host"));
|
session->browser_context(), GURL("chrome-guest://fake-host"));
|
||||||
content::WebContents::CreateParams params(browser_context, site_instance);
|
content::WebContents::CreateParams params(
|
||||||
|
session->browser_context(), site_instance);
|
||||||
guest_delegate_.reset(new WebViewGuestDelegate);
|
guest_delegate_.reset(new WebViewGuestDelegate);
|
||||||
params.guest_delegate = guest_delegate_.get();
|
params.guest_delegate = guest_delegate_.get();
|
||||||
web_contents = content::WebContents::Create(params);
|
web_contents = content::WebContents::Create(params);
|
||||||
} else {
|
} else {
|
||||||
content::WebContents::CreateParams params(browser_context);
|
content::WebContents::CreateParams params(session->browser_context());
|
||||||
web_contents = content::WebContents::Create(params);
|
web_contents = content::WebContents::Create(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +257,11 @@ WebContents::WebContents(const mate::Dictionary& options) {
|
||||||
AttachAsUserData(web_contents);
|
AttachAsUserData(web_contents);
|
||||||
InitWithWebContents(web_contents);
|
InitWithWebContents(web_contents);
|
||||||
|
|
||||||
|
managed_web_contents()->GetView()->SetDelegate(this);
|
||||||
|
|
||||||
|
// Save the preferences in C++.
|
||||||
|
new WebContentsPreferences(web_contents, options);
|
||||||
|
|
||||||
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
|
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
|
||||||
|
|
||||||
if (is_guest) {
|
if (is_guest) {
|
||||||
|
@ -196,7 +281,18 @@ WebContents::WebContents(const mate::Dictionary& options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
WebContents::~WebContents() {
|
WebContents::~WebContents() {
|
||||||
Destroy();
|
// The destroy() is called.
|
||||||
|
if (managed_web_contents()) {
|
||||||
|
// For webview we need to tell content module to do some cleanup work before
|
||||||
|
// destroying it.
|
||||||
|
if (type_ == WEB_VIEW)
|
||||||
|
guest_delegate_->Destroy();
|
||||||
|
|
||||||
|
// The WebContentsDestroyed will not be called automatically because we
|
||||||
|
// unsubscribe from webContents before destroying it. So we have to manually
|
||||||
|
// call it here to make sure "destroyed" event is emitted.
|
||||||
|
WebContentsDestroyed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebContents::AddMessageToConsole(content::WebContents* source,
|
bool WebContents::AddMessageToConsole(content::WebContents* source,
|
||||||
|
@ -217,7 +313,7 @@ bool WebContents::ShouldCreateWebContents(
|
||||||
int route_id,
|
int route_id,
|
||||||
int main_frame_route_id,
|
int main_frame_route_id,
|
||||||
WindowContainerType window_container_type,
|
WindowContainerType window_container_type,
|
||||||
const base::string16& frame_name,
|
const std::string& frame_name,
|
||||||
const GURL& target_url,
|
const GURL& target_url,
|
||||||
const std::string& partition_id,
|
const std::string& partition_id,
|
||||||
content::SessionStorageNamespace* session_storage_namespace) {
|
content::SessionStorageNamespace* session_storage_namespace) {
|
||||||
|
@ -277,7 +373,10 @@ bool WebContents::IsPopupOrPanel(const content::WebContents* source) const {
|
||||||
void WebContents::HandleKeyboardEvent(
|
void WebContents::HandleKeyboardEvent(
|
||||||
content::WebContents* source,
|
content::WebContents* source,
|
||||||
const content::NativeWebKeyboardEvent& event) {
|
const content::NativeWebKeyboardEvent& event) {
|
||||||
if (type_ == BROWSER_WINDOW) {
|
if (event.windowsKeyCode == ui::VKEY_ESCAPE && is_html_fullscreen()) {
|
||||||
|
// Escape exits tabbed fullscreen mode.
|
||||||
|
ExitFullscreenModeForTab(source);
|
||||||
|
} else if (type_ == BROWSER_WINDOW) {
|
||||||
owner_window()->HandleKeyboardEvent(source, event);
|
owner_window()->HandleKeyboardEvent(source, event);
|
||||||
} else if (type_ == WEB_VIEW && guest_delegate_) {
|
} else if (type_ == WEB_VIEW && guest_delegate_) {
|
||||||
// Send the unhandled keyboard events back to the embedder.
|
// Send the unhandled keyboard events back to the embedder.
|
||||||
|
@ -308,6 +407,43 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebContents::OnGoToEntryOffset(int offset) {
|
||||||
|
GoToOffset(offset);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebContents::FindReply(content::WebContents* web_contents,
|
||||||
|
int request_id,
|
||||||
|
int number_of_matches,
|
||||||
|
const gfx::Rect& selection_rect,
|
||||||
|
int active_match_ordinal,
|
||||||
|
bool final_update) {
|
||||||
|
v8::Locker locker(isolate());
|
||||||
|
v8::HandleScope handle_scope(isolate());
|
||||||
|
|
||||||
|
mate::Dictionary result = mate::Dictionary::CreateEmpty(isolate());
|
||||||
|
if (number_of_matches == -1) {
|
||||||
|
result.Set("requestId", request_id);
|
||||||
|
result.Set("selectionArea", selection_rect);
|
||||||
|
result.Set("finalUpdate", final_update);
|
||||||
|
Emit("found-in-page", result);
|
||||||
|
} else if (final_update) {
|
||||||
|
result.Set("requestId", request_id);
|
||||||
|
result.Set("matches", number_of_matches);
|
||||||
|
result.Set("finalUpdate", final_update);
|
||||||
|
Emit("found-in-page", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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.
|
||||||
|
@ -339,6 +475,22 @@ void WebContents::PluginCrashed(const base::FilePath& plugin_path,
|
||||||
Emit("plugin-crashed", info.name, info.version);
|
Emit("plugin-crashed", info.name, info.version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebContents::MediaStartedPlaying() {
|
||||||
|
Emit("media-started-playing");
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebContents::MediaPaused() {
|
||||||
|
Emit("media-paused");
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebContents::DidChangeThemeColor(SkColor theme_color) {
|
||||||
|
std::string hex_theme_color = base::StringPrintf("#%02X%02X%02X",
|
||||||
|
SkColorGetR(theme_color),
|
||||||
|
SkColorGetG(theme_color),
|
||||||
|
SkColorGetB(theme_color));
|
||||||
|
Emit("did-change-theme-color", hex_theme_color);
|
||||||
|
}
|
||||||
|
|
||||||
void WebContents::DocumentLoadedInFrame(
|
void WebContents::DocumentLoadedInFrame(
|
||||||
content::RenderFrameHost* render_frame_host) {
|
content::RenderFrameHost* render_frame_host) {
|
||||||
if (!render_frame_host->GetParent())
|
if (!render_frame_host->GetParent())
|
||||||
|
@ -354,20 +506,21 @@ 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,
|
||||||
Emit("did-fail-load", error_code, error_description);
|
bool was_ignored_by_handler) {
|
||||||
|
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,
|
||||||
const GURL& validated_url,
|
const GURL& validated_url,
|
||||||
int error_code,
|
int error_code,
|
||||||
const base::string16& error_description) {
|
const base::string16& error_description,
|
||||||
Emit("did-fail-load", error_code, error_description);
|
bool was_ignored_by_handler) {
|
||||||
|
Emit("did-fail-load", error_code, error_description, validated_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::DidStartLoading() {
|
void WebContents::DidStartLoading() {
|
||||||
|
@ -380,30 +533,6 @@ void WebContents::DidStopLoading() {
|
||||||
|
|
||||||
void WebContents::DidGetResourceResponseStart(
|
void WebContents::DidGetResourceResponseStart(
|
||||||
const content::ResourceRequestDetails& details) {
|
const content::ResourceRequestDetails& details) {
|
||||||
v8::Locker locker(isolate());
|
|
||||||
v8::HandleScope handle_scope(isolate());
|
|
||||||
base::DictionaryValue response_headers;
|
|
||||||
|
|
||||||
net::HttpResponseHeaders* headers = details.headers.get();
|
|
||||||
if (!headers)
|
|
||||||
return;
|
|
||||||
void* iter = nullptr;
|
|
||||||
std::string key;
|
|
||||||
std::string value;
|
|
||||||
while (headers->EnumerateHeaderLines(&iter, &key, &value)) {
|
|
||||||
key = base::StringToLowerASCII(key);
|
|
||||||
value = base::StringToLowerASCII(value);
|
|
||||||
if (response_headers.HasKey(key)) {
|
|
||||||
base::ListValue* values = nullptr;
|
|
||||||
if (response_headers.GetList(key, &values))
|
|
||||||
values->AppendString(value);
|
|
||||||
} else {
|
|
||||||
scoped_ptr<base::ListValue> values(new base::ListValue());
|
|
||||||
values->AppendString(value);
|
|
||||||
response_headers.Set(key, values.Pass());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Emit("did-get-response-details",
|
Emit("did-get-response-details",
|
||||||
details.socket_address.IsEmpty(),
|
details.socket_address.IsEmpty(),
|
||||||
details.url,
|
details.url,
|
||||||
|
@ -411,7 +540,7 @@ void WebContents::DidGetResourceResponseStart(
|
||||||
details.http_response_code,
|
details.http_response_code,
|
||||||
details.method,
|
details.method,
|
||||||
details.referrer,
|
details.referrer,
|
||||||
response_headers);
|
details.headers.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::DidGetRedirectForResourceRequest(
|
void WebContents::DidGetRedirectForResourceRequest(
|
||||||
|
@ -420,21 +549,28 @@ void WebContents::DidGetRedirectForResourceRequest(
|
||||||
Emit("did-get-redirect-request",
|
Emit("did-get-redirect-request",
|
||||||
details.url,
|
details.url,
|
||||||
details.new_url,
|
details.new_url,
|
||||||
(details.resource_type == content::RESOURCE_TYPE_MAIN_FRAME));
|
(details.resource_type == content::RESOURCE_TYPE_MAIN_FRAME),
|
||||||
|
details.http_response_code,
|
||||||
|
details.method,
|
||||||
|
details.referrer,
|
||||||
|
details.headers.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::DidNavigateMainFrame(
|
void WebContents::DidNavigateMainFrame(
|
||||||
const content::LoadCommittedDetails& details,
|
const content::LoadCommittedDetails& details,
|
||||||
const content::FrameNavigateParams& params) {
|
const content::FrameNavigateParams& params) {
|
||||||
if (details.is_navigation_to_different_page())
|
if (details.is_navigation_to_different_page())
|
||||||
Emit("did-navigate-to-different-page");
|
Emit("did-navigate", params.url);
|
||||||
|
else if (details.is_in_page)
|
||||||
|
Emit("did-navigate-in-page", params.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
||||||
|
@ -450,6 +586,33 @@ 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)
|
||||||
|
@ -462,11 +625,37 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// There are three ways of destroying a webContents:
|
||||||
|
// 1. call webContents.destory();
|
||||||
|
// 2. garbage collection;
|
||||||
|
// 3. user closes the window of webContents;
|
||||||
|
// For webview only #1 will happen, for BrowserWindow both #1 and #3 may
|
||||||
|
// happen. The #2 should never happen for webContents, because webview is
|
||||||
|
// managed by GuestViewManager, and BrowserWindow's webContents is managed
|
||||||
|
// by api::Window.
|
||||||
|
// For #1, the destructor will do the cleanup work and we only need to make
|
||||||
|
// sure "destroyed" event is emitted. For #3, the content::WebContents will
|
||||||
|
// be destroyed on close, and WebContentsDestroyed would be called for it, so
|
||||||
|
// we need to make sure the api::WebContents is also deleted.
|
||||||
void WebContents::WebContentsDestroyed() {
|
void WebContents::WebContentsDestroyed() {
|
||||||
// The RenderViewDeleted was not called when the WebContents is destroyed.
|
// The RenderViewDeleted was not called when the WebContents is destroyed.
|
||||||
RenderViewDeleted(web_contents()->GetRenderViewHost());
|
RenderViewDeleted(web_contents()->GetRenderViewHost());
|
||||||
Emit("destroyed");
|
|
||||||
|
// This event is only for internal use, which is emitted when WebContents is
|
||||||
|
// being destroyed.
|
||||||
|
Emit("will-destroy");
|
||||||
|
|
||||||
|
// Cleanup relationships with other parts.
|
||||||
RemoveFromWeakMap();
|
RemoveFromWeakMap();
|
||||||
|
|
||||||
|
// 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("destroyed");
|
||||||
|
|
||||||
|
// Destroy the native class in next tick.
|
||||||
|
base::MessageLoop::current()->PostTask(FROM_HERE, GetDestroyClosure());
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::NavigationEntryCommitted(
|
void WebContents::NavigationEntryCommitted(
|
||||||
|
@ -475,22 +664,6 @@ void WebContents::NavigationEntryCommitted(
|
||||||
details.is_in_page, details.did_replace_entry);
|
details.is_in_page, details.did_replace_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void 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::IsAlive() const {
|
|
||||||
return web_contents() != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WebContents::GetID() const {
|
int WebContents::GetID() const {
|
||||||
return web_contents()->GetRenderProcessHost()->GetID();
|
return web_contents()->GetRenderProcessHost()->GetID();
|
||||||
}
|
}
|
||||||
|
@ -511,12 +684,29 @@ 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 {
|
||||||
|
return web_contents()->GetURL();
|
||||||
|
}
|
||||||
|
|
||||||
base::string16 WebContents::GetTitle() const {
|
base::string16 WebContents::GetTitle() const {
|
||||||
return web_contents()->GetTitle();
|
return web_contents()->GetTitle();
|
||||||
}
|
}
|
||||||
|
@ -533,10 +723,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();
|
||||||
|
@ -560,8 +746,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() {
|
||||||
|
@ -572,9 +760,11 @@ void WebContents::InsertCSS(const std::string& css) {
|
||||||
web_contents()->InsertCSS(css);
|
web_contents()->InsertCSS(css);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::ExecuteJavaScript(const base::string16& code,
|
bool WebContents::SavePage(const base::FilePath& full_file_path,
|
||||||
bool has_user_gesture) {
|
const content::SavePageType& save_type,
|
||||||
Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture));
|
const SavePageHandler::SavePageCallback& callback) {
|
||||||
|
auto handler = new SavePageHandler(web_contents(), callback);
|
||||||
|
return handler->Handle(full_file_path, save_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::OpenDevTools(mate::Arguments* args) {
|
void WebContents::OpenDevTools(mate::Arguments* args) {
|
||||||
|
@ -606,6 +796,28 @@ bool WebContents::IsDevToolsOpened() {
|
||||||
return managed_web_contents()->IsDevToolsViewShowing();
|
return managed_web_contents()->IsDevToolsViewShowing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WebContents::IsDevToolsFocused() {
|
||||||
|
if (type_ == REMOTE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return managed_web_contents()->GetView()->IsDevToolsViewFocused();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebContents::EnableDeviceEmulation(
|
||||||
|
const blink::WebDeviceEmulationParams& params) {
|
||||||
|
if (type_ == REMOTE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Send(new ViewMsg_EnableDeviceEmulation(routing_id(), params));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebContents::DisableDeviceEmulation() {
|
||||||
|
if (type_ == REMOTE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Send(new ViewMsg_DisableDeviceEmulation(routing_id()));
|
||||||
|
}
|
||||||
|
|
||||||
void WebContents::ToggleDevTools() {
|
void WebContents::ToggleDevTools() {
|
||||||
if (IsDevToolsOpened())
|
if (IsDevToolsOpened())
|
||||||
CloseDevTools();
|
CloseDevTools();
|
||||||
|
@ -637,14 +849,6 @@ void WebContents::InspectServiceWorker() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
|
|
||||||
if (session_.IsEmpty()) {
|
|
||||||
auto handle = Session::CreateFrom(isolate, GetBrowserContext());
|
|
||||||
session_.Reset(isolate, handle.ToV8());
|
|
||||||
}
|
|
||||||
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());
|
||||||
|
@ -691,17 +895,19 @@ void WebContents::PrintToPDF(const base::DictionaryValue& setting,
|
||||||
PrintToPDF(setting, callback);
|
PrintToPDF(setting, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::AddWorkSpace(const base::FilePath& path) {
|
void WebContents::AddWorkSpace(mate::Arguments* args,
|
||||||
|
const base::FilePath& path) {
|
||||||
if (path.empty()) {
|
if (path.empty()) {
|
||||||
node::ThrowError(isolate(), "path cannot be empty");
|
args->ThrowError("path cannot be empty");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DevToolsAddFileSystem(path);
|
DevToolsAddFileSystem(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::RemoveWorkSpace(const base::FilePath& path) {
|
void WebContents::RemoveWorkSpace(mate::Arguments* args,
|
||||||
|
const base::FilePath& path) {
|
||||||
if (path.empty()) {
|
if (path.empty()) {
|
||||||
node::ThrowError(isolate(), "path cannot be empty");
|
args->ThrowError("path cannot be empty");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DevToolsRemoveFileSystem(path);
|
DevToolsRemoveFileSystem(path);
|
||||||
|
@ -751,6 +957,25 @@ void WebContents::ReplaceMisspelling(const base::string16& word) {
|
||||||
web_contents()->ReplaceMisspelling(word);
|
web_contents()->ReplaceMisspelling(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32 WebContents::FindInPage(mate::Arguments* args) {
|
||||||
|
uint32 request_id = GetNextRequestId();
|
||||||
|
base::string16 search_text;
|
||||||
|
blink::WebFindOptions options;
|
||||||
|
if (!args->GetNext(&search_text) || search_text.empty()) {
|
||||||
|
args->ThrowError("Must provide a non-empty search content");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
args->GetNext(&options);
|
||||||
|
|
||||||
|
web_contents()->Find(request_id, search_text, options);
|
||||||
|
return request_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebContents::StopFindInPage(content::StopFindAction action) {
|
||||||
|
web_contents()->StopFinding(action);
|
||||||
|
}
|
||||||
|
|
||||||
void WebContents::Focus() {
|
void WebContents::Focus() {
|
||||||
web_contents()->Focus();
|
web_contents()->Focus();
|
||||||
}
|
}
|
||||||
|
@ -764,6 +989,56 @@ bool WebContents::SendIPCMessage(const base::string16& channel,
|
||||||
return Send(new AtomViewMsg_Message(routing_id(), channel, args));
|
return Send(new AtomViewMsg_Message(routing_id(), channel, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebContents::SendInputEvent(v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::Value> input_event) {
|
||||||
|
const auto view = web_contents()->GetRenderWidgetHostView();
|
||||||
|
if (!view)
|
||||||
|
return;
|
||||||
|
const auto host = view->GetRenderWidgetHost();
|
||||||
|
if (!host)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int type = mate::GetWebInputEventType(isolate, input_event);
|
||||||
|
if (blink::WebInputEvent::isMouseEventType(type)) {
|
||||||
|
blink::WebMouseEvent mouse_event;
|
||||||
|
if (mate::ConvertFromV8(isolate, input_event, &mouse_event)) {
|
||||||
|
host->ForwardMouseEvent(mouse_event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (blink::WebInputEvent::isKeyboardEventType(type)) {
|
||||||
|
content::NativeWebKeyboardEvent keyboard_event;
|
||||||
|
if (mate::ConvertFromV8(isolate, input_event, &keyboard_event)) {
|
||||||
|
host->ForwardKeyboardEvent(keyboard_event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (type == blink::WebInputEvent::MouseWheel) {
|
||||||
|
blink::WebMouseWheelEvent mouse_wheel_event;
|
||||||
|
if (mate::ConvertFromV8(isolate, input_event, &mouse_wheel_event)) {
|
||||||
|
host->ForwardWheelEvent(mouse_wheel_event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
|
||||||
|
isolate, "Invalid event object")));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebContents::BeginFrameSubscription(
|
||||||
|
const FrameSubscriber::FrameCaptureCallback& callback) {
|
||||||
|
const auto view = web_contents()->GetRenderWidgetHostView();
|
||||||
|
if (view) {
|
||||||
|
scoped_ptr<FrameSubscriber> frame_subscriber(new FrameSubscriber(
|
||||||
|
isolate(), view->GetVisibleViewportSize(), callback));
|
||||||
|
view->BeginFrameSubscription(frame_subscriber.Pass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebContents::EndFrameSubscription() {
|
||||||
|
const auto view = web_contents()->GetRenderWidgetHostView();
|
||||||
|
if (view)
|
||||||
|
view->EndFrameSubscription();
|
||||||
|
}
|
||||||
|
|
||||||
void WebContents::SetSize(const SetSizeParams& params) {
|
void WebContents::SetSize(const SetSizeParams& params) {
|
||||||
if (guest_delegate_)
|
if (guest_delegate_)
|
||||||
guest_delegate_->SetSize(params);
|
guest_delegate_->SetSize(params);
|
||||||
|
@ -778,69 +1053,108 @@ bool WebContents::IsGuest() const {
|
||||||
return type_ == WEB_VIEW;
|
return type_ == WEB_VIEW;
|
||||||
}
|
}
|
||||||
|
|
||||||
mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
v8::Local<v8::Value> WebContents::GetWebPreferences(v8::Isolate* isolate) {
|
||||||
v8::Isolate* isolate) {
|
WebContentsPreferences* web_preferences =
|
||||||
if (template_.IsEmpty())
|
WebContentsPreferences::FromWebContents(web_contents());
|
||||||
template_.Reset(isolate, mate::ObjectTemplateBuilder(isolate)
|
return mate::ConvertToV8(isolate, *web_preferences->web_preferences());
|
||||||
.SetMethod("destroy", &WebContents::Destroy, true)
|
|
||||||
.SetMethod("isAlive", &WebContents::IsAlive, true)
|
|
||||||
.SetMethod("getId", &WebContents::GetID)
|
|
||||||
.SetMethod("equal", &WebContents::Equal)
|
|
||||||
.SetMethod("_loadUrl", &WebContents::LoadURL)
|
|
||||||
.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("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("setSize", &WebContents::SetSize)
|
|
||||||
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
|
|
||||||
.SetMethod("isGuest", &WebContents::IsGuest)
|
|
||||||
.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::GetOwnerBrowserWindow() {
|
||||||
return !IsAlive();
|
if (owner_window())
|
||||||
|
return Window::From(isolate(), owner_window());
|
||||||
|
else
|
||||||
|
return v8::Null(isolate());
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
|
||||||
|
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_);
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> WebContents::Debugger(v8::Isolate* isolate) {
|
||||||
|
if (debugger_.IsEmpty()) {
|
||||||
|
auto handle = atom::api::Debugger::Create(isolate, web_contents());
|
||||||
|
debugger_.Reset(isolate, handle.ToV8());
|
||||||
|
}
|
||||||
|
return v8::Local<v8::Value>::New(isolate, debugger_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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("openDevTools", &WebContents::OpenDevTools)
|
||||||
|
.SetMethod("closeDevTools", &WebContents::CloseDevTools)
|
||||||
|
.SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened)
|
||||||
|
.SetMethod("isDevToolsFocused", &WebContents::IsDevToolsFocused)
|
||||||
|
.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("findInPage", &WebContents::FindInPage)
|
||||||
|
.SetMethod("stopFindInPage", &WebContents::StopFindInPage)
|
||||||
|
.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)
|
||||||
|
.SetProperty("debugger", &WebContents::Debugger);
|
||||||
}
|
}
|
||||||
|
|
||||||
AtomBrowserContext* WebContents::GetBrowserContext() const {
|
AtomBrowserContext* WebContents::GetBrowserContext() const {
|
||||||
|
@ -877,19 +1191,23 @@ mate::Handle<WebContents> WebContents::CreateFrom(
|
||||||
// static
|
// static
|
||||||
mate::Handle<WebContents> WebContents::Create(
|
mate::Handle<WebContents> WebContents::Create(
|
||||||
v8::Isolate* isolate, const mate::Dictionary& options) {
|
v8::Isolate* isolate, const mate::Dictionary& options) {
|
||||||
auto handle = mate::CreateHandle(isolate, new WebContents(options));
|
auto handle = mate::CreateHandle(isolate, new WebContents(isolate, options));
|
||||||
g_wrap_web_contents.Run(handle.ToV8());
|
g_wrap_web_contents.Run(handle.ToV8());
|
||||||
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
|
||||||
|
@ -903,7 +1221,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
|
||||||
|
|
|
@ -8,13 +8,19 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "atom/browser/api/frame_subscriber.h"
|
||||||
|
#include "atom/browser/api/save_page_handler.h"
|
||||||
#include "atom/browser/api/trackable_object.h"
|
#include "atom/browser/api/trackable_object.h"
|
||||||
#include "atom/browser/common_web_contents_delegate.h"
|
#include "atom/browser/common_web_contents_delegate.h"
|
||||||
#include "content/public/common/favicon_url.h"
|
|
||||||
#include "content/public/browser/web_contents_observer.h"
|
#include "content/public/browser/web_contents_observer.h"
|
||||||
|
#include "content/public/common/favicon_url.h"
|
||||||
#include "native_mate/handle.h"
|
#include "native_mate/handle.h"
|
||||||
#include "ui/gfx/image/image.h"
|
#include "ui/gfx/image/image.h"
|
||||||
|
|
||||||
|
namespace blink {
|
||||||
|
struct WebDeviceEmulationParams;
|
||||||
|
}
|
||||||
|
|
||||||
namespace brightray {
|
namespace brightray {
|
||||||
class InspectableWebContents;
|
class InspectableWebContents;
|
||||||
}
|
}
|
||||||
|
@ -48,11 +54,11 @@ 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);
|
||||||
|
|
||||||
void Destroy();
|
|
||||||
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;
|
||||||
base::string16 GetTitle() const;
|
base::string16 GetTitle() const;
|
||||||
bool IsLoading() const;
|
bool IsLoading() const;
|
||||||
bool IsWaitingForResponse() const;
|
bool IsWaitingForResponse() const;
|
||||||
|
@ -65,15 +71,18 @@ 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);
|
||||||
void ExecuteJavaScript(const base::string16& code,
|
bool SavePage(const base::FilePath& full_file_path,
|
||||||
bool has_user_gesture);
|
const content::SavePageType& save_type,
|
||||||
|
const SavePageHandler::SavePageCallback& callback);
|
||||||
void OpenDevTools(mate::Arguments* args);
|
void OpenDevTools(mate::Arguments* args);
|
||||||
void CloseDevTools();
|
void CloseDevTools();
|
||||||
bool IsDevToolsOpened();
|
bool IsDevToolsOpened();
|
||||||
|
bool IsDevToolsFocused();
|
||||||
void ToggleDevTools();
|
void ToggleDevTools();
|
||||||
|
void EnableDeviceEmulation(const blink::WebDeviceEmulationParams& params);
|
||||||
|
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);
|
||||||
|
@ -85,8 +94,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
const PrintToPDFCallback& callback);
|
const PrintToPDFCallback& callback);
|
||||||
|
|
||||||
// DevTools workspace api.
|
// DevTools workspace api.
|
||||||
void AddWorkSpace(const base::FilePath& path);
|
void AddWorkSpace(mate::Arguments* args, const base::FilePath& path);
|
||||||
void RemoveWorkSpace(const base::FilePath& path);
|
void RemoveWorkSpace(mate::Arguments* args, const base::FilePath& path);
|
||||||
|
|
||||||
// Editing commands.
|
// Editing commands.
|
||||||
void Undo();
|
void Undo();
|
||||||
|
@ -100,30 +109,50 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
void Unselect();
|
void Unselect();
|
||||||
void Replace(const base::string16& word);
|
void Replace(const base::string16& word);
|
||||||
void ReplaceMisspelling(const base::string16& word);
|
void ReplaceMisspelling(const base::string16& word);
|
||||||
|
uint32 FindInPage(mate::Arguments* args);
|
||||||
|
void StopFindInPage(content::StopFindAction action);
|
||||||
|
|
||||||
// Focus.
|
// Focus.
|
||||||
void Focus();
|
void Focus();
|
||||||
void TabTraverse(bool reverse);
|
void TabTraverse(bool reverse);
|
||||||
|
|
||||||
// Sending messages to browser.
|
// Send messages to browser.
|
||||||
bool SendIPCMessage(const base::string16& channel,
|
bool SendIPCMessage(const base::string16& channel,
|
||||||
const base::ListValue& args);
|
const base::ListValue& args);
|
||||||
|
|
||||||
|
// Send WebInputEvent to the page.
|
||||||
|
void SendInputEvent(v8::Isolate* isolate, v8::Local<v8::Value> input_event);
|
||||||
|
|
||||||
|
// Subscribe to the frame updates.
|
||||||
|
void BeginFrameSubscription(
|
||||||
|
const FrameSubscriber::FrameCaptureCallback& callback);
|
||||||
|
void EndFrameSubscription();
|
||||||
|
|
||||||
// Methods for creating <webview>.
|
// Methods for creating <webview>.
|
||||||
void SetSize(const SetSizeParams& params);
|
void SetSize(const SetSizeParams& params);
|
||||||
void SetAllowTransparency(bool allow);
|
void SetAllowTransparency(bool allow);
|
||||||
bool IsGuest() const;
|
bool IsGuest() const;
|
||||||
|
|
||||||
|
// Returns the web preferences of current WebContents.
|
||||||
|
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);
|
||||||
|
v8::Local<v8::Value> Debugger(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);
|
||||||
explicit WebContents(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,
|
||||||
|
@ -135,7 +164,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
int route_id,
|
int route_id,
|
||||||
int main_frame_route_id,
|
int main_frame_route_id,
|
||||||
WindowContainerType window_container_type,
|
WindowContainerType window_container_type,
|
||||||
const base::string16& frame_name,
|
const std::string& frame_name,
|
||||||
const GURL& target_url,
|
const GURL& target_url,
|
||||||
const std::string& partition_id,
|
const std::string& partition_id,
|
||||||
content::SessionStorageNamespace* session_storage_namespace) override;
|
content::SessionStorageNamespace* session_storage_namespace) override;
|
||||||
|
@ -158,6 +187,14 @@ 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;
|
||||||
|
bool OnGoToEntryOffset(int offset) override;
|
||||||
|
void FindReply(content::WebContents* web_contents,
|
||||||
|
int request_id,
|
||||||
|
int number_of_matches,
|
||||||
|
const gfx::Rect& selection_rect,
|
||||||
|
int active_match_ordinal,
|
||||||
|
bool final_update) override;
|
||||||
|
|
||||||
// content::WebContentsObserver:
|
// content::WebContentsObserver:
|
||||||
void BeforeUnloadFired(const base::TimeTicks& proceed_time) override;
|
void BeforeUnloadFired(const base::TimeTicks& proceed_time) override;
|
||||||
|
@ -170,11 +207,13 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
void DidFailLoad(content::RenderFrameHost* render_frame_host,
|
void DidFailLoad(content::RenderFrameHost* render_frame_host,
|
||||||
const GURL& validated_url,
|
const GURL& validated_url,
|
||||||
int error_code,
|
int error_code,
|
||||||
const base::string16& error_description) override;
|
const base::string16& error_description,
|
||||||
|
bool was_ignored_by_handler) override;
|
||||||
void DidFailProvisionalLoad(content::RenderFrameHost* render_frame_host,
|
void DidFailProvisionalLoad(content::RenderFrameHost* render_frame_host,
|
||||||
const GURL& validated_url,
|
const GURL& validated_url,
|
||||||
int error_code,
|
int error_code,
|
||||||
const base::string16& error_description) override;
|
const base::string16& error_description,
|
||||||
|
bool was_ignored_by_handler) override;
|
||||||
void DidStartLoading() override;
|
void DidStartLoading() override;
|
||||||
void DidStopLoading() override;
|
void DidStopLoading() override;
|
||||||
void DidGetResourceResponseStart(
|
void DidGetResourceResponseStart(
|
||||||
|
@ -194,6 +233,14 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
const std::vector<content::FaviconURL>& urls) override;
|
const std::vector<content::FaviconURL>& urls) override;
|
||||||
void PluginCrashed(const base::FilePath& plugin_path,
|
void PluginCrashed(const base::FilePath& plugin_path,
|
||||||
base::ProcessId plugin_pid) override;
|
base::ProcessId plugin_pid) override;
|
||||||
|
void MediaStartedPlaying() override;
|
||||||
|
void MediaPaused() override;
|
||||||
|
void DidChangeThemeColor(SkColor theme_color) override;
|
||||||
|
|
||||||
|
// brightray::InspectableWebContentsViewDelegate:
|
||||||
|
void DevToolsFocused() override;
|
||||||
|
void DevToolsOpened() override;
|
||||||
|
void DevToolsClosed() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum Type {
|
enum Type {
|
||||||
|
@ -204,6 +251,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
|
|
||||||
AtomBrowserContext* GetBrowserContext() const;
|
AtomBrowserContext* GetBrowserContext() const;
|
||||||
|
|
||||||
|
uint32 GetNextRequestId() {
|
||||||
|
return ++request_id_;
|
||||||
|
}
|
||||||
|
|
||||||
// Called when received a message from renderer.
|
// Called when received a message from renderer.
|
||||||
void OnRendererMessage(const base::string16& channel,
|
void OnRendererMessage(const base::string16& channel,
|
||||||
const base::ListValue& args);
|
const base::ListValue& args);
|
||||||
|
@ -214,12 +265,17 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
IPC::Message* message);
|
IPC::Message* message);
|
||||||
|
|
||||||
v8::Global<v8::Value> session_;
|
v8::Global<v8::Value> session_;
|
||||||
|
v8::Global<v8::Value> devtools_web_contents_;
|
||||||
|
v8::Global<v8::Value> debugger_;
|
||||||
|
|
||||||
scoped_ptr<WebViewGuestDelegate> guest_delegate_;
|
scoped_ptr<WebViewGuestDelegate> guest_delegate_;
|
||||||
|
|
||||||
// The type of current WebContents.
|
// The type of current WebContents.
|
||||||
Type type_;
|
Type type_;
|
||||||
|
|
||||||
|
// Request id used for findInPage request.
|
||||||
|
uint32 request_id_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(WebContents);
|
DISALLOW_COPY_AND_ASSIGN(WebContents);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
119
atom/browser/api/atom_api_web_request.cc
Normal file
119
atom/browser/api/atom_api_web_request.cc
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
// 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/atom_api_web_request.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "atom/browser/atom_browser_context.h"
|
||||||
|
#include "atom/browser/net/atom_network_delegate.h"
|
||||||
|
#include "atom/common/native_mate_converters/callback.h"
|
||||||
|
#include "atom/common/native_mate_converters/net_converter.h"
|
||||||
|
#include "atom/common/native_mate_converters/value_converter.h"
|
||||||
|
#include "content/public/browser/browser_thread.h"
|
||||||
|
#include "native_mate/dictionary.h"
|
||||||
|
#include "native_mate/object_template_builder.h"
|
||||||
|
|
||||||
|
using content::BrowserThread;
|
||||||
|
|
||||||
|
namespace mate {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Converter<extensions::URLPattern> {
|
||||||
|
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
|
||||||
|
extensions::URLPattern* out) {
|
||||||
|
std::string pattern;
|
||||||
|
if (!ConvertFromV8(isolate, val, &pattern))
|
||||||
|
return false;
|
||||||
|
return out->Parse(pattern) == extensions::URLPattern::PARSE_SUCCESS;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mate
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
WebRequest::WebRequest(AtomBrowserContext* browser_context)
|
||||||
|
: browser_context_(browser_context) {
|
||||||
|
}
|
||||||
|
|
||||||
|
WebRequest::~WebRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
template<AtomNetworkDelegate::SimpleEvent type>
|
||||||
|
void WebRequest::SetSimpleListener(mate::Arguments* args) {
|
||||||
|
SetListener<AtomNetworkDelegate::SimpleListener>(
|
||||||
|
&AtomNetworkDelegate::SetSimpleListenerInIO, type, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<AtomNetworkDelegate::ResponseEvent type>
|
||||||
|
void WebRequest::SetResponseListener(mate::Arguments* args) {
|
||||||
|
SetListener<AtomNetworkDelegate::ResponseListener>(
|
||||||
|
&AtomNetworkDelegate::SetResponseListenerInIO, type, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Listener, typename Method, typename Event>
|
||||||
|
void WebRequest::SetListener(Method method, Event type, mate::Arguments* args) {
|
||||||
|
// { urls }.
|
||||||
|
URLPatterns patterns;
|
||||||
|
mate::Dictionary dict;
|
||||||
|
args->GetNext(&dict) && dict.Get("urls", &patterns);
|
||||||
|
|
||||||
|
// Function or null.
|
||||||
|
v8::Local<v8::Value> value;
|
||||||
|
Listener listener;
|
||||||
|
if (!args->GetNext(&listener) &&
|
||||||
|
!(args->GetNext(&value) && value->IsNull())) {
|
||||||
|
args->ThrowError("Must pass null or a Function");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto delegate = browser_context_->network_delegate();
|
||||||
|
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||||
|
base::Bind(method, base::Unretained(delegate), type,
|
||||||
|
patterns, listener));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
mate::Handle<WebRequest> WebRequest::Create(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
AtomBrowserContext* browser_context) {
|
||||||
|
return mate::CreateHandle(isolate, new WebRequest(browser_context));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void WebRequest::BuildPrototype(v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::ObjectTemplate> prototype) {
|
||||||
|
mate::ObjectTemplateBuilder(isolate, prototype)
|
||||||
|
.SetMethod("onBeforeRequest",
|
||||||
|
&WebRequest::SetResponseListener<
|
||||||
|
AtomNetworkDelegate::kOnBeforeRequest>)
|
||||||
|
.SetMethod("onBeforeSendHeaders",
|
||||||
|
&WebRequest::SetResponseListener<
|
||||||
|
AtomNetworkDelegate::kOnBeforeSendHeaders>)
|
||||||
|
.SetMethod("onHeadersReceived",
|
||||||
|
&WebRequest::SetResponseListener<
|
||||||
|
AtomNetworkDelegate::kOnHeadersReceived>)
|
||||||
|
.SetMethod("onSendHeaders",
|
||||||
|
&WebRequest::SetSimpleListener<
|
||||||
|
AtomNetworkDelegate::kOnSendHeaders>)
|
||||||
|
.SetMethod("onBeforeRedirect",
|
||||||
|
&WebRequest::SetSimpleListener<
|
||||||
|
AtomNetworkDelegate::kOnBeforeRedirect>)
|
||||||
|
.SetMethod("onResponseStarted",
|
||||||
|
&WebRequest::SetSimpleListener<
|
||||||
|
AtomNetworkDelegate::kOnResponseStarted>)
|
||||||
|
.SetMethod("onCompleted",
|
||||||
|
&WebRequest::SetSimpleListener<
|
||||||
|
AtomNetworkDelegate::kOnCompleted>)
|
||||||
|
.SetMethod("onErrorOccurred",
|
||||||
|
&WebRequest::SetSimpleListener<
|
||||||
|
AtomNetworkDelegate::kOnErrorOccurred>);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
|
||||||
|
} // namespace atom
|
50
atom/browser/api/atom_api_web_request.h
Normal file
50
atom/browser/api/atom_api_web_request.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
// 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_ATOM_API_WEB_REQUEST_H_
|
||||||
|
#define ATOM_BROWSER_API_ATOM_API_WEB_REQUEST_H_
|
||||||
|
|
||||||
|
#include "atom/browser/api/trackable_object.h"
|
||||||
|
#include "atom/browser/net/atom_network_delegate.h"
|
||||||
|
#include "native_mate/arguments.h"
|
||||||
|
#include "native_mate/handle.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
class AtomBrowserContext;
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
class WebRequest : public mate::TrackableObject<WebRequest> {
|
||||||
|
public:
|
||||||
|
static mate::Handle<WebRequest> Create(v8::Isolate* isolate,
|
||||||
|
AtomBrowserContext* browser_context);
|
||||||
|
|
||||||
|
// mate::TrackableObject:
|
||||||
|
static void BuildPrototype(v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::ObjectTemplate> prototype);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit WebRequest(AtomBrowserContext* browser_context);
|
||||||
|
~WebRequest();
|
||||||
|
|
||||||
|
// C++ can not distinguish overloaded member function.
|
||||||
|
template<AtomNetworkDelegate::SimpleEvent type>
|
||||||
|
void SetSimpleListener(mate::Arguments* args);
|
||||||
|
template<AtomNetworkDelegate::ResponseEvent type>
|
||||||
|
void SetResponseListener(mate::Arguments* args);
|
||||||
|
template<typename Listener, typename Method, typename Event>
|
||||||
|
void SetListener(Method method, Event type, mate::Arguments* args);
|
||||||
|
|
||||||
|
private:
|
||||||
|
scoped_refptr<AtomBrowserContext> browser_context_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(WebRequest);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
#endif // ATOM_BROWSER_API_ATOM_API_WEB_REQUEST_H_
|
|
@ -3,13 +3,14 @@
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
#include "atom/browser/api/atom_api_web_contents.h"
|
#include "atom/browser/api/atom_api_web_contents.h"
|
||||||
|
#include "atom/browser/web_contents_preferences.h"
|
||||||
#include "atom/browser/web_view_manager.h"
|
#include "atom/browser/web_view_manager.h"
|
||||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
#include "atom/common/native_mate_converters/value_converter.h"
|
||||||
|
#include "atom/common/node_includes.h"
|
||||||
#include "content/public/browser/browser_context.h"
|
#include "content/public/browser/browser_context.h"
|
||||||
#include "native_mate/dictionary.h"
|
#include "native_mate/dictionary.h"
|
||||||
#include "net/base/filename_util.h"
|
|
||||||
|
|
||||||
#include "atom/common/node_includes.h"
|
using atom::WebContentsPreferences;
|
||||||
|
|
||||||
namespace mate {
|
namespace mate {
|
||||||
|
|
||||||
|
@ -25,28 +26,6 @@ struct Converter<content::WebContents*> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
|
||||||
struct Converter<atom::WebViewManager::WebViewInfo> {
|
|
||||||
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
|
|
||||||
atom::WebViewManager::WebViewInfo* out) {
|
|
||||||
Dictionary options;
|
|
||||||
if (!ConvertFromV8(isolate, val, &options))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
GURL preload_url;
|
|
||||||
if (!options.Get("preloadUrl", &preload_url))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!preload_url.is_empty() &&
|
|
||||||
!net::FileURLToFilePath(preload_url, &(out->preload_script)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return options.Get("nodeIntegration", &(out->node_integration)) &&
|
|
||||||
options.Get("plugins", &(out->plugins)) &&
|
|
||||||
options.Get("disableWebSecurity", &(out->disable_web_security));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace mate
|
} // namespace mate
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -65,14 +44,13 @@ void AddGuest(int guest_instance_id,
|
||||||
int element_instance_id,
|
int element_instance_id,
|
||||||
content::WebContents* embedder,
|
content::WebContents* embedder,
|
||||||
content::WebContents* guest_web_contents,
|
content::WebContents* guest_web_contents,
|
||||||
atom::WebViewManager::WebViewInfo info) {
|
const base::DictionaryValue& options) {
|
||||||
auto manager = GetWebViewManager(embedder);
|
auto manager = GetWebViewManager(embedder);
|
||||||
if (manager) {
|
if (manager)
|
||||||
info.guest_instance_id = guest_instance_id;
|
|
||||||
info.embedder = embedder;
|
|
||||||
manager->AddGuest(guest_instance_id, element_instance_id, embedder,
|
manager->AddGuest(guest_instance_id, element_instance_id, embedder,
|
||||||
guest_web_contents, info);
|
guest_web_contents);
|
||||||
}
|
|
||||||
|
WebContentsPreferences::FromWebContents(guest_web_contents)->Merge(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveGuest(content::WebContents* embedder, int guest_instance_id) {
|
void RemoveGuest(content::WebContents* embedder, int guest_instance_id) {
|
||||||
|
|
|
@ -3,32 +3,29 @@
|
||||||
// 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"
|
||||||
#include "atom/browser/browser.h"
|
#include "atom/browser/browser.h"
|
||||||
#include "atom/browser/native_window.h"
|
#include "atom/browser/native_window.h"
|
||||||
#include "atom/common/node_includes.h"
|
|
||||||
#include "atom/common/options_switches.h"
|
|
||||||
#include "atom/common/event_types.h"
|
|
||||||
#include "atom/common/native_mate_converters/callback.h"
|
#include "atom/common/native_mate_converters/callback.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"
|
||||||
#include "atom/common/native_mate_converters/image_converter.h"
|
#include "atom/common/native_mate_converters/image_converter.h"
|
||||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||||
|
#include "atom/common/node_includes.h"
|
||||||
|
#include "atom/common/options_switches.h"
|
||||||
#include "content/public/browser/render_process_host.h"
|
#include "content/public/browser/render_process_host.h"
|
||||||
#include "native_mate/constructor.h"
|
#include "native_mate/constructor.h"
|
||||||
#include "native_mate/dictionary.h"
|
#include "native_mate/dictionary.h"
|
||||||
#include "ui/gfx/geometry/rect.h"
|
#include "ui/gfx/geometry/rect.h"
|
||||||
#include "v8/include/v8.h"
|
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
#include "atom/browser/native_window_views.h"
|
#include "atom/browser/native_window_views.h"
|
||||||
#include "atom/browser/ui/win/taskbar_host.h"
|
#include "atom/browser/ui/win/taskbar_host.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "atom/common/node_includes.h"
|
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
namespace mate {
|
namespace mate {
|
||||||
|
|
||||||
|
@ -64,58 +61,126 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
|
Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
|
||||||
|
// 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);
|
||||||
|
options.Get(options::kWebPreferences, &web_preferences);
|
||||||
|
|
||||||
|
// Be compatible with old options which are now in web_preferences.
|
||||||
|
v8::Local<v8::Value> value;
|
||||||
|
if (options.Get(options::kNodeIntegration, &value))
|
||||||
|
web_preferences.Set(options::kNodeIntegration, value);
|
||||||
|
if (options.Get(options::kPreloadScript, &value))
|
||||||
|
web_preferences.Set(options::kPreloadScript, value);
|
||||||
|
if (options.Get(options::kZoomFactor, &value))
|
||||||
|
web_preferences.Set(options::kZoomFactor, value);
|
||||||
|
|
||||||
// Creates the WebContents used by BrowserWindow.
|
// Creates the WebContents used by BrowserWindow.
|
||||||
mate::Dictionary web_contents_options(isolate, v8::Object::New(isolate));
|
auto web_contents = WebContents::Create(isolate, web_preferences);
|
||||||
auto web_contents = WebContents::Create(isolate, web_contents_options);
|
|
||||||
web_contents_.Reset(isolate, web_contents.ToV8());
|
web_contents_.Reset(isolate, web_contents.ToV8());
|
||||||
api_web_contents_ = web_contents.get();
|
api_web_contents_ = web_contents.get();
|
||||||
|
|
||||||
|
// Keep a copy of the options for later use.
|
||||||
|
mate::Dictionary(isolate, web_contents->GetWrapper(isolate)).Set(
|
||||||
|
"browserWindowOptions", options);
|
||||||
|
|
||||||
// Creates BrowserWindow.
|
// Creates BrowserWindow.
|
||||||
window_.reset(NativeWindow::Create(web_contents->managed_web_contents(),
|
window_.reset(NativeWindow::Create(web_contents->managed_web_contents(),
|
||||||
options));
|
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) {
|
||||||
*prevent_default = Emit("close");
|
*prevent_default = Emit("close");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::OnFrameRendered(scoped_ptr<uint8[]> rgb, const int size) {
|
|
||||||
v8::Locker locker(isolate());
|
|
||||||
v8::HandleScope handle_scope(isolate());
|
|
||||||
|
|
||||||
auto data = node::Buffer::New(isolate(), reinterpret_cast<const char*>(rgb.get()), static_cast<size_t>(size));
|
|
||||||
|
|
||||||
Emit("frame-rendered", data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
||||||
|
|
||||||
|
// Destroy the native class when window is closed.
|
||||||
|
base::MessageLoop::current()->PostTask(FROM_HERE, GetDestroyClosure());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::OnWindowBlur() {
|
void Window::OnWindowBlur() {
|
||||||
|
@ -162,6 +227,14 @@ void Window::OnWindowLeaveFullScreen() {
|
||||||
Emit("leave-full-screen");
|
Emit("leave-full-screen");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::OnWindowScrollTouchBegin() {
|
||||||
|
Emit("scroll-touch-begin");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::OnWindowScrollTouchEnd() {
|
||||||
|
Emit("scroll-touch-end");
|
||||||
|
}
|
||||||
|
|
||||||
void Window::OnWindowEnterHtmlFullScreen() {
|
void Window::OnWindowEnterHtmlFullScreen() {
|
||||||
Emit("enter-html-full-screen");
|
Emit("enter-html-full-screen");
|
||||||
}
|
}
|
||||||
|
@ -178,59 +251,45 @@ void Window::OnRendererResponsive() {
|
||||||
Emit("responsive");
|
Emit("responsive");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::OnDevToolsFocus() {
|
|
||||||
Emit("devtools-focused");
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::OnDevToolsOpened() {
|
|
||||||
Emit("devtools-opened");
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::OnDevToolsClosed() {
|
|
||||||
Emit("devtools-closed");
|
|
||||||
|
|
||||||
v8::Locker locker(isolate());
|
|
||||||
v8::HandleScope handle_scope(isolate());
|
|
||||||
devtools_web_contents_.Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
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()) {
|
||||||
node::ThrowError(isolate,
|
isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
|
||||||
"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() {
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -287,16 +346,20 @@ bool Window::IsFullscreen() {
|
||||||
return window_->IsFullscreen();
|
return window_->IsFullscreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::SetBounds(const gfx::Rect& bounds) {
|
void Window::SetBounds(const gfx::Rect& bounds, mate::Arguments* args) {
|
||||||
window_->SetBounds(bounds);
|
bool animate = false;
|
||||||
|
args->GetNext(&animate);
|
||||||
|
window_->SetBounds(bounds, animate);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Rect Window::GetBounds() {
|
gfx::Rect Window::GetBounds() {
|
||||||
return window_->GetBounds();
|
return window_->GetBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::SetSize(int width, int height) {
|
void Window::SetSize(int width, int height, mate::Arguments* args) {
|
||||||
window_->SetSize(gfx::Size(width, height));
|
bool animate = false;
|
||||||
|
args->GetNext(&animate);
|
||||||
|
window_->SetSize(gfx::Size(width, height), animate);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> Window::GetSize() {
|
std::vector<int> Window::GetSize() {
|
||||||
|
@ -307,8 +370,10 @@ std::vector<int> Window::GetSize() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::SetContentSize(int width, int height) {
|
void Window::SetContentSize(int width, int height, mate::Arguments* args) {
|
||||||
window_->SetContentSize(gfx::Size(width, height));
|
bool animate = false;
|
||||||
|
args->GetNext(&animate);
|
||||||
|
window_->SetContentSize(gfx::Size(width, height), animate);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> Window::GetContentSize() {
|
std::vector<int> Window::GetContentSize() {
|
||||||
|
@ -351,6 +416,46 @@ bool Window::IsResizable() {
|
||||||
return window_->IsResizable();
|
return window_->IsResizable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::SetMovable(bool movable) {
|
||||||
|
window_->SetMovable(movable);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Window::IsMovable() {
|
||||||
|
return window_->IsMovable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::SetMinimizable(bool minimizable) {
|
||||||
|
window_->SetMinimizable(minimizable);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Window::IsMinimizable() {
|
||||||
|
return window_->IsMinimizable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::SetMaximizable(bool maximizable) {
|
||||||
|
window_->SetMaximizable(maximizable);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Window::IsMaximizable() {
|
||||||
|
return window_->IsMaximizable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::SetFullScreenable(bool fullscreenable) {
|
||||||
|
window_->SetFullScreenable(fullscreenable);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Window::IsFullScreenable() {
|
||||||
|
return window_->IsFullScreenable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::SetClosable(bool closable) {
|
||||||
|
window_->SetClosable(closable);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Window::IsClosable() {
|
||||||
|
return window_->IsClosable();
|
||||||
|
}
|
||||||
|
|
||||||
void Window::SetAlwaysOnTop(bool top) {
|
void Window::SetAlwaysOnTop(bool top) {
|
||||||
window_->SetAlwaysOnTop(top);
|
window_->SetAlwaysOnTop(top);
|
||||||
}
|
}
|
||||||
|
@ -363,8 +468,10 @@ void Window::Center() {
|
||||||
window_->Center();
|
window_->Center();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::SetPosition(int x, int y) {
|
void Window::SetPosition(int x, int y, mate::Arguments* args) {
|
||||||
window_->SetPosition(gfx::Point(x, y));
|
bool animate = false;
|
||||||
|
args->GetNext(&animate);
|
||||||
|
window_->SetPosition(gfx::Point(x, y), animate);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> Window::GetPosition() {
|
std::vector<int> Window::GetPosition() {
|
||||||
|
@ -399,6 +506,18 @@ bool Window::IsKiosk() {
|
||||||
return window_->IsKiosk();
|
return window_->IsKiosk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::SetBackgroundColor(const std::string& color_name) {
|
||||||
|
window_->SetBackgroundColor(color_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::SetHasShadow(bool has_shadow) {
|
||||||
|
window_->SetHasShadow(has_shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Window::HasShadow() {
|
||||||
|
return window_->HasShadow();
|
||||||
|
}
|
||||||
|
|
||||||
void Window::FocusOnWebView() {
|
void Window::FocusOnWebView() {
|
||||||
window_->FocusOnWebView();
|
window_->FocusOnWebView();
|
||||||
}
|
}
|
||||||
|
@ -427,6 +546,10 @@ bool Window::IsDocumentEdited() {
|
||||||
return window_->IsDocumentEdited();
|
return window_->IsDocumentEdited();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::SetIgnoreMouseEvents(bool ignore) {
|
||||||
|
return window_->SetIgnoreMouseEvents(ignore);
|
||||||
|
}
|
||||||
|
|
||||||
void Window::CapturePage(mate::Arguments* args) {
|
void Window::CapturePage(mate::Arguments* args) {
|
||||||
gfx::Rect rect;
|
gfx::Rect rect;
|
||||||
base::Callback<void(const gfx::Image&)> callback;
|
base::Callback<void(const gfx::Image&)> callback;
|
||||||
|
@ -442,14 +565,6 @@ void Window::CapturePage(mate::Arguments* args) {
|
||||||
rect, base::Bind(&OnCapturePageDone, args->isolate(), callback));
|
rect, base::Bind(&OnCapturePageDone, args->isolate(), callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::BeginFrameSubscription() {
|
|
||||||
window_->SetFrameSubscription(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::EndFrameSubscription() {
|
|
||||||
window_->SetFrameSubscription(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::SetProgressBar(double progress) {
|
void Window::SetProgressBar(double progress) {
|
||||||
window_->SetProgressBar(progress);
|
window_->SetProgressBar(progress);
|
||||||
}
|
}
|
||||||
|
@ -506,6 +621,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();
|
||||||
|
@ -518,6 +656,12 @@ void Window::SetAspectRatio(double aspect_ratio, mate::Arguments* args) {
|
||||||
window_->SetAspectRatio(aspect_ratio, extra_size);
|
window_->SetAspectRatio(aspect_ratio, extra_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> Window::GetNativeWindowHandle() {
|
||||||
|
gfx::AcceleratedWidget handle = window_->GetAcceleratedWidget();
|
||||||
|
return ToBuffer(
|
||||||
|
isolate(), static_cast<void*>(&handle), sizeof(gfx::AcceleratedWidget));
|
||||||
|
}
|
||||||
|
|
||||||
void Window::SetVisibleOnAllWorkspaces(bool visible) {
|
void Window::SetVisibleOnAllWorkspaces(bool visible) {
|
||||||
return window_->SetVisibleOnAllWorkspaces(visible);
|
return window_->SetVisibleOnAllWorkspaces(visible);
|
||||||
}
|
}
|
||||||
|
@ -526,127 +670,6 @@ bool Window::IsVisibleOnAllWorkspaces() {
|
||||||
return window_->IsVisibleOnAllWorkspaces();
|
return window_->IsVisibleOnAllWorkspaces();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::SendKeyboardEvent(v8::Isolate* isolate, const mate::Dictionary& data){
|
|
||||||
auto type = blink::WebInputEvent::Type::Char;
|
|
||||||
int modifiers = 0;
|
|
||||||
int keycode = 0;
|
|
||||||
int native = 0;
|
|
||||||
std::string type_str = "";
|
|
||||||
mate::Dictionary modifier_list = mate::Dictionary::CreateEmpty(isolate);
|
|
||||||
|
|
||||||
data.Get(switches::kEventType, &type_str);
|
|
||||||
data.Get(switches::kModifiers, &modifier_list);
|
|
||||||
data.Get(switches::kKeyCode, &keycode);
|
|
||||||
data.Get(switches::kNativeKeyCode, &native);
|
|
||||||
|
|
||||||
if(type_str.compare(event_types::kKeyDown) == 0){
|
|
||||||
type = blink::WebInputEvent::Type::KeyDown;
|
|
||||||
}else if(type_str.compare(event_types::kKeyUp) == 0){
|
|
||||||
type = blink::WebInputEvent::Type::KeyUp;
|
|
||||||
}else if(type_str.compare(event_types::kChar) == 0){
|
|
||||||
type = blink::WebInputEvent::Type::Char;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<std::string, bool> modifier_types;
|
|
||||||
modifier_types[event_types::kModifierIsKeyPad] = false;
|
|
||||||
modifier_types[event_types::kModifierIsAutoRepeat] = false;
|
|
||||||
modifier_types[event_types::kModifierIsLeft] = false;
|
|
||||||
modifier_types[event_types::kModifierIsRight] = false;
|
|
||||||
modifier_types[event_types::kModifierShiftKey] = false;
|
|
||||||
modifier_types[event_types::kModifierControlKey] = false;
|
|
||||||
modifier_types[event_types::kModifierAltKey] = false;
|
|
||||||
modifier_types[event_types::kModifierMetaKey] = false;
|
|
||||||
modifier_types[event_types::kModifierCapsLockOn] = false;
|
|
||||||
modifier_types[event_types::kModifierNumLockOn] = false;
|
|
||||||
|
|
||||||
for(std::map<std::string, bool>::iterator it = modifier_types.begin(); it != modifier_types.end(); ++it){
|
|
||||||
modifier_list.Get(it->first,&(it->second));
|
|
||||||
|
|
||||||
if(it->second) modifiers = modifiers & event_types::modifierStrToWebModifier(it->first);
|
|
||||||
}
|
|
||||||
|
|
||||||
window_->SendKeyboardEvent(type, modifiers, keycode, native);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::SendMouseEvent(v8::Isolate* isolate, const mate::Dictionary& data){
|
|
||||||
int x, y, movementX, movementY, clickCount;
|
|
||||||
std::string type_str = "";
|
|
||||||
std::string button_str = "";
|
|
||||||
mate::Dictionary modifier_list = mate::Dictionary::CreateEmpty(isolate);
|
|
||||||
|
|
||||||
blink::WebInputEvent::Type type = blink::WebInputEvent::Type::MouseMove;
|
|
||||||
blink::WebMouseEvent::Button button = blink::WebMouseEvent::Button::ButtonNone;
|
|
||||||
int modifiers = 0;
|
|
||||||
|
|
||||||
data.Get(switches::kEventType, &type_str);
|
|
||||||
data.Get(switches::kMouseEventButton, &button_str);
|
|
||||||
data.Get(switches::kModifiers, &modifier_list);
|
|
||||||
|
|
||||||
if(type_str.compare(event_types::kMouseDown) == 0){
|
|
||||||
type = blink::WebInputEvent::Type::MouseDown;
|
|
||||||
}else if(type_str.compare(event_types::kMouseUp) == 0){
|
|
||||||
type = blink::WebInputEvent::Type::MouseUp;
|
|
||||||
}else if(type_str.compare(event_types::kMouseMove) == 0){
|
|
||||||
type = blink::WebInputEvent::Type::MouseMove;
|
|
||||||
}else if(type_str.compare(event_types::kMouseEnter) == 0){
|
|
||||||
type = blink::WebInputEvent::Type::MouseEnter;
|
|
||||||
}else if(type_str.compare(event_types::kMouseLeave) == 0){
|
|
||||||
type = blink::WebInputEvent::Type::MouseLeave;
|
|
||||||
}else if(type_str.compare(event_types::kContextMenu) == 0){
|
|
||||||
type = blink::WebInputEvent::Type::ContextMenu;
|
|
||||||
}else if(type_str.compare(event_types::kMouseWheel) == 0){
|
|
||||||
type = blink::WebInputEvent::Type::MouseWheel;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<std::string, bool> modifier_types;
|
|
||||||
modifier_types[event_types::kMouseLeftButton] = false;
|
|
||||||
modifier_types[event_types::kMouseRightButton] = false;
|
|
||||||
modifier_types[event_types::kMouseMiddleButton] = false;
|
|
||||||
modifier_types[event_types::kModifierLeftButtonDown] = false;
|
|
||||||
modifier_types[event_types::kModifierMiddleButtonDown] = false;
|
|
||||||
modifier_types[event_types::kModifierRightButtonDown] = false;
|
|
||||||
modifier_types[event_types::kModifierShiftKey] = false;
|
|
||||||
modifier_types[event_types::kModifierControlKey] = false;
|
|
||||||
modifier_types[event_types::kModifierAltKey] = false;
|
|
||||||
modifier_types[event_types::kModifierMetaKey] = false;
|
|
||||||
modifier_types[event_types::kModifierCapsLockOn] = false;
|
|
||||||
modifier_types[event_types::kModifierNumLockOn] = false;
|
|
||||||
|
|
||||||
for(std::map<std::string, bool>::iterator it = modifier_types.begin(); it != modifier_types.end(); ++it){
|
|
||||||
modifier_list.Get(it->first,&(it->second));
|
|
||||||
|
|
||||||
if(it->second) modifiers = modifiers & event_types::modifierStrToWebModifier(it->first);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(type == blink::WebInputEvent::Type::MouseWheel){
|
|
||||||
bool precise = true;
|
|
||||||
|
|
||||||
x = 0;
|
|
||||||
y = 0;
|
|
||||||
data.Get(switches::kX, &x);
|
|
||||||
data.Get(switches::kY, &y);
|
|
||||||
data.Get(switches::kMouseWheelPrecise, &precise);
|
|
||||||
|
|
||||||
window_->SendMouseWheelEvent(modifiers, x, y, precise);
|
|
||||||
}else{
|
|
||||||
if (data.Get(switches::kX, &x) && data.Get(switches::kY, &y)) {
|
|
||||||
if(!data.Get(switches::kMovementX, &movementX)){
|
|
||||||
movementX = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!data.Get(switches::kMovementY, &movementY)){
|
|
||||||
movementY = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!data.Get(switches::kClickCount, &clickCount)){
|
|
||||||
clickCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
window_->SendMouseEvent(type, modifiers, button, x, y, movementX, movementY, clickCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t Window::ID() const {
|
int32_t Window::ID() const {
|
||||||
return weak_map_id();
|
return weak_map_id();
|
||||||
}
|
}
|
||||||
|
@ -658,20 +681,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)
|
||||||
|
@ -687,6 +702,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||||
.SetMethod("setFullScreen", &Window::SetFullScreen)
|
.SetMethod("setFullScreen", &Window::SetFullScreen)
|
||||||
.SetMethod("isFullScreen", &Window::IsFullscreen)
|
.SetMethod("isFullScreen", &Window::IsFullscreen)
|
||||||
.SetMethod("setAspectRatio", &Window::SetAspectRatio)
|
.SetMethod("setAspectRatio", &Window::SetAspectRatio)
|
||||||
|
.SetMethod("getNativeWindowHandle", &Window::GetNativeWindowHandle)
|
||||||
.SetMethod("getBounds", &Window::GetBounds)
|
.SetMethod("getBounds", &Window::GetBounds)
|
||||||
.SetMethod("setBounds", &Window::SetBounds)
|
.SetMethod("setBounds", &Window::SetBounds)
|
||||||
.SetMethod("getSize", &Window::GetSize)
|
.SetMethod("getSize", &Window::GetSize)
|
||||||
|
@ -699,6 +715,16 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||||
.SetMethod("getMaximumSize", &Window::GetMaximumSize)
|
.SetMethod("getMaximumSize", &Window::GetMaximumSize)
|
||||||
.SetMethod("setResizable", &Window::SetResizable)
|
.SetMethod("setResizable", &Window::SetResizable)
|
||||||
.SetMethod("isResizable", &Window::IsResizable)
|
.SetMethod("isResizable", &Window::IsResizable)
|
||||||
|
.SetMethod("setMovable", &Window::SetMovable)
|
||||||
|
.SetMethod("isMovable", &Window::IsMovable)
|
||||||
|
.SetMethod("setMinimizable", &Window::SetMinimizable)
|
||||||
|
.SetMethod("isMinimizable", &Window::IsMinimizable)
|
||||||
|
.SetMethod("setMaximizable", &Window::SetMaximizable)
|
||||||
|
.SetMethod("isMaximizable", &Window::IsMaximizable)
|
||||||
|
.SetMethod("setFullScreenable", &Window::SetFullScreenable)
|
||||||
|
.SetMethod("isFullScreenable", &Window::IsFullScreenable)
|
||||||
|
.SetMethod("setClosable", &Window::SetClosable)
|
||||||
|
.SetMethod("isClosable", &Window::IsClosable)
|
||||||
.SetMethod("setAlwaysOnTop", &Window::SetAlwaysOnTop)
|
.SetMethod("setAlwaysOnTop", &Window::SetAlwaysOnTop)
|
||||||
.SetMethod("isAlwaysOnTop", &Window::IsAlwaysOnTop)
|
.SetMethod("isAlwaysOnTop", &Window::IsAlwaysOnTop)
|
||||||
.SetMethod("center", &Window::Center)
|
.SetMethod("center", &Window::Center)
|
||||||
|
@ -710,10 +736,14 @@ 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("setHasShadow", &Window::SetHasShadow)
|
||||||
|
.SetMethod("hasShadow", &Window::HasShadow)
|
||||||
.SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename)
|
.SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename)
|
||||||
.SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename)
|
.SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename)
|
||||||
.SetMethod("setDocumentEdited", &Window::SetDocumentEdited)
|
.SetMethod("setDocumentEdited", &Window::SetDocumentEdited)
|
||||||
.SetMethod("isDocumentEdited", &Window::IsDocumentEdited)
|
.SetMethod("isDocumentEdited", &Window::IsDocumentEdited)
|
||||||
|
.SetMethod("setIgnoreMouseEvents", &Window::SetIgnoreMouseEvents)
|
||||||
.SetMethod("focusOnWebView", &Window::FocusOnWebView)
|
.SetMethod("focusOnWebView", &Window::FocusOnWebView)
|
||||||
.SetMethod("blurWebView", &Window::BlurWebView)
|
.SetMethod("blurWebView", &Window::BlurWebView)
|
||||||
.SetMethod("isWebViewFocused", &Window::IsWebViewFocused)
|
.SetMethod("isWebViewFocused", &Window::IsWebViewFocused)
|
||||||
|
@ -730,17 +760,28 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||||
&Window::SetVisibleOnAllWorkspaces)
|
&Window::SetVisibleOnAllWorkspaces)
|
||||||
.SetMethod("isVisibleOnAllWorkspaces",
|
.SetMethod("isVisibleOnAllWorkspaces",
|
||||||
&Window::IsVisibleOnAllWorkspaces)
|
&Window::IsVisibleOnAllWorkspaces)
|
||||||
.SetMethod("sendMouseEvent", &Window::SendMouseEvent)
|
#if defined(OS_WIN)
|
||||||
.SetMethod("sendKeyboardEvent", &Window::SendKeyboardEvent)
|
.SetMethod("hookWindowMessage", &Window::HookWindowMessage)
|
||||||
.SetMethod("beginFrameSubscription", &Window::BeginFrameSubscription)
|
.SetMethod("isWindowMessageHooked", &Window::IsWindowMessageHooked)
|
||||||
.SetMethod("endFrameSubscription", &Window::EndFrameSubscription)
|
.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
|
||||||
|
|
|
@ -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,10 +54,7 @@ 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 OnFrameRendered(scoped_ptr<uint8[]> rgb, const int size) override;
|
|
||||||
void OnWindowClosed() override;
|
void OnWindowClosed() override;
|
||||||
void OnWindowBlur() override;
|
void OnWindowBlur() override;
|
||||||
void OnWindowFocus() override;
|
void OnWindowFocus() override;
|
||||||
|
@ -64,25 +65,23 @@ class Window : public mate::TrackableObject<Window>,
|
||||||
void OnWindowResize() override;
|
void OnWindowResize() override;
|
||||||
void OnWindowMove() override;
|
void OnWindowMove() override;
|
||||||
void OnWindowMoved() override;
|
void OnWindowMoved() override;
|
||||||
|
void OnWindowScrollTouchBegin() override;
|
||||||
|
void OnWindowScrollTouchEnd() override;
|
||||||
void OnWindowEnterFullScreen() override;
|
void OnWindowEnterFullScreen() override;
|
||||||
void OnWindowLeaveFullScreen() override;
|
void OnWindowLeaveFullScreen() override;
|
||||||
void OnWindowEnterHtmlFullScreen() override;
|
void OnWindowEnterHtmlFullScreen() override;
|
||||||
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:
|
||||||
// APIs for NativeWindow.
|
// APIs for NativeWindow.
|
||||||
void Destroy();
|
|
||||||
void Close();
|
void Close();
|
||||||
bool IsClosed();
|
|
||||||
void Focus();
|
void Focus();
|
||||||
bool IsFocused();
|
bool IsFocused();
|
||||||
void Show();
|
void Show();
|
||||||
|
@ -97,11 +96,11 @@ class Window : public mate::TrackableObject<Window>,
|
||||||
bool IsMinimized();
|
bool IsMinimized();
|
||||||
void SetFullScreen(bool fullscreen);
|
void SetFullScreen(bool fullscreen);
|
||||||
bool IsFullscreen();
|
bool IsFullscreen();
|
||||||
void SetBounds(const gfx::Rect& bounds);
|
void SetBounds(const gfx::Rect& bounds, mate::Arguments* args);
|
||||||
gfx::Rect GetBounds();
|
gfx::Rect GetBounds();
|
||||||
void SetSize(int width, int height);
|
void SetSize(int width, int height, mate::Arguments* args);
|
||||||
std::vector<int> GetSize();
|
std::vector<int> GetSize();
|
||||||
void SetContentSize(int width, int height);
|
void SetContentSize(int width, int height, mate::Arguments* args);
|
||||||
std::vector<int> GetContentSize();
|
std::vector<int> GetContentSize();
|
||||||
void SetMinimumSize(int width, int height);
|
void SetMinimumSize(int width, int height);
|
||||||
std::vector<int> GetMinimumSize();
|
std::vector<int> GetMinimumSize();
|
||||||
|
@ -109,10 +108,20 @@ class Window : public mate::TrackableObject<Window>,
|
||||||
std::vector<int> GetMaximumSize();
|
std::vector<int> GetMaximumSize();
|
||||||
void SetResizable(bool resizable);
|
void SetResizable(bool resizable);
|
||||||
bool IsResizable();
|
bool IsResizable();
|
||||||
|
void SetMovable(bool movable);
|
||||||
|
bool IsMovable();
|
||||||
|
void SetMinimizable(bool minimizable);
|
||||||
|
bool IsMinimizable();
|
||||||
|
void SetMaximizable(bool maximizable);
|
||||||
|
bool IsMaximizable();
|
||||||
|
void SetFullScreenable(bool fullscreenable);
|
||||||
|
bool IsFullScreenable();
|
||||||
|
void SetClosable(bool closable);
|
||||||
|
bool IsClosable();
|
||||||
void SetAlwaysOnTop(bool top);
|
void SetAlwaysOnTop(bool top);
|
||||||
bool IsAlwaysOnTop();
|
bool IsAlwaysOnTop();
|
||||||
void Center();
|
void Center();
|
||||||
void SetPosition(int x, int y);
|
void SetPosition(int x, int y, mate::Arguments* args);
|
||||||
std::vector<int> GetPosition();
|
std::vector<int> GetPosition();
|
||||||
void SetTitle(const std::string& title);
|
void SetTitle(const std::string& title);
|
||||||
std::string GetTitle();
|
std::string GetTitle();
|
||||||
|
@ -120,6 +129,9 @@ 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 SetHasShadow(bool has_shadow);
|
||||||
|
bool HasShadow();
|
||||||
void FocusOnWebView();
|
void FocusOnWebView();
|
||||||
void BlurWebView();
|
void BlurWebView();
|
||||||
bool IsWebViewFocused();
|
bool IsWebViewFocused();
|
||||||
|
@ -127,6 +139,7 @@ class Window : public mate::TrackableObject<Window>,
|
||||||
std::string GetRepresentedFilename();
|
std::string GetRepresentedFilename();
|
||||||
void SetDocumentEdited(bool edited);
|
void SetDocumentEdited(bool edited);
|
||||||
bool IsDocumentEdited();
|
bool IsDocumentEdited();
|
||||||
|
void SetIgnoreMouseEvents(bool ignore);
|
||||||
void CapturePage(mate::Arguments* args);
|
void CapturePage(mate::Arguments* args);
|
||||||
void SetProgressBar(double progress);
|
void SetProgressBar(double progress);
|
||||||
void SetOverlayIcon(const gfx::Image& overlay,
|
void SetOverlayIcon(const gfx::Image& overlay,
|
||||||
|
@ -138,11 +151,17 @@ class Window : public mate::TrackableObject<Window>,
|
||||||
void SetMenuBarVisibility(bool visible);
|
void SetMenuBarVisibility(bool visible);
|
||||||
bool IsMenuBarVisible();
|
bool IsMenuBarVisible();
|
||||||
void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
|
void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
|
||||||
|
v8::Local<v8::Value> GetNativeWindowHandle();
|
||||||
|
|
||||||
void SendKeyboardEvent(v8::Isolate* isolate, const mate::Dictionary& data);
|
#if defined(OS_WIN)
|
||||||
void SendMouseEvent(v8::Isolate* isolate, const mate::Dictionary& data);
|
typedef base::Callback<void(v8::Local<v8::Value>,
|
||||||
void BeginFrameSubscription();
|
v8::Local<v8::Value>)> MessageCallback;
|
||||||
void EndFrameSubscription();
|
|
||||||
|
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();
|
||||||
|
@ -153,10 +172,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_;
|
||||||
|
|
|
@ -56,7 +56,7 @@ v8::Local<v8::Object> EventEmitter::CreateJSEvent(
|
||||||
v8::Local<v8::Object> EventEmitter::CreateCustomEvent(
|
v8::Local<v8::Object> EventEmitter::CreateCustomEvent(
|
||||||
v8::Isolate* isolate, v8::Local<v8::Object> custom_event) {
|
v8::Isolate* isolate, v8::Local<v8::Object> custom_event) {
|
||||||
v8::Local<v8::Object> event = CreateEventObject(isolate);
|
v8::Local<v8::Object> event = CreateEventObject(isolate);
|
||||||
event->SetPrototype(custom_event->CreationContext(), custom_event);
|
(void)event->SetPrototype(custom_event->CreationContext(), custom_event);
|
||||||
mate::Dictionary(isolate, event).Set("sender", GetWrapper(isolate));
|
mate::Dictionary(isolate, event).Set("sender", GetWrapper(isolate));
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,8 @@ class EventEmitter : public Wrappable {
|
||||||
content::WebContents* sender,
|
content::WebContents* sender,
|
||||||
IPC::Message* message,
|
IPC::Message* message,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
|
v8::Locker locker(isolate());
|
||||||
|
v8::HandleScope handle_scope(isolate());
|
||||||
v8::Local<v8::Object> event = CreateJSEvent(isolate(), sender, message);
|
v8::Local<v8::Object> event = CreateJSEvent(isolate(), sender, message);
|
||||||
return EmitWithEvent(name, event, args...);
|
return EmitWithEvent(name, event, args...);
|
||||||
}
|
}
|
||||||
|
|
66
atom/browser/api/frame_subscriber.cc
Normal file
66
atom/browser/api/frame_subscriber.cc
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
// 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/frame_subscriber.h"
|
||||||
|
|
||||||
|
#include "atom/common/node_includes.h"
|
||||||
|
#include "base/bind.h"
|
||||||
|
#include "media/base/video_frame.h"
|
||||||
|
#include "media/base/yuv_convert.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
FrameSubscriber::FrameSubscriber(v8::Isolate* isolate,
|
||||||
|
const gfx::Size& size,
|
||||||
|
const FrameCaptureCallback& callback)
|
||||||
|
: isolate_(isolate), size_(size), callback_(callback) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FrameSubscriber::ShouldCaptureFrame(
|
||||||
|
const gfx::Rect& damage_rect,
|
||||||
|
base::TimeTicks present_time,
|
||||||
|
scoped_refptr<media::VideoFrame>* storage,
|
||||||
|
DeliverFrameCallback* callback) {
|
||||||
|
*storage = media::VideoFrame::CreateFrame(
|
||||||
|
media::PIXEL_FORMAT_YV12,
|
||||||
|
size_, gfx::Rect(size_), size_, base::TimeDelta());
|
||||||
|
*callback = base::Bind(&FrameSubscriber::OnFrameDelivered,
|
||||||
|
base::Unretained(this), *storage);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSubscriber::OnFrameDelivered(
|
||||||
|
scoped_refptr<media::VideoFrame> frame, base::TimeTicks, bool result) {
|
||||||
|
if (!result)
|
||||||
|
return;
|
||||||
|
|
||||||
|
v8::Locker locker(isolate_);
|
||||||
|
v8::HandleScope handle_scope(isolate_);
|
||||||
|
|
||||||
|
gfx::Rect rect = frame->visible_rect();
|
||||||
|
size_t rgb_arr_size = rect.width() * rect.height() * 4;
|
||||||
|
v8::MaybeLocal<v8::Object> buffer = node::Buffer::New(isolate_, rgb_arr_size);
|
||||||
|
if (buffer.IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Convert a frame of YUV to 32 bit ARGB.
|
||||||
|
media::ConvertYUVToRGB32(frame->data(media::VideoFrame::kYPlane),
|
||||||
|
frame->data(media::VideoFrame::kUPlane),
|
||||||
|
frame->data(media::VideoFrame::kVPlane),
|
||||||
|
reinterpret_cast<uint8*>(
|
||||||
|
node::Buffer::Data(buffer.ToLocalChecked())),
|
||||||
|
rect.width(), rect.height(),
|
||||||
|
frame->stride(media::VideoFrame::kYPlane),
|
||||||
|
frame->stride(media::VideoFrame::kUVPlane),
|
||||||
|
rect.width() * 4,
|
||||||
|
media::YV12);
|
||||||
|
|
||||||
|
callback_.Run(buffer.ToLocalChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
|
||||||
|
} // namespace atom
|
45
atom/browser/api/frame_subscriber.h
Normal file
45
atom/browser/api/frame_subscriber.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// 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_FRAME_SUBSCRIBER_H_
|
||||||
|
#define ATOM_BROWSER_API_FRAME_SUBSCRIBER_H_
|
||||||
|
|
||||||
|
#include "base/callback.h"
|
||||||
|
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
|
||||||
|
#include "ui/gfx/geometry/size.h"
|
||||||
|
#include "v8/include/v8.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
class FrameSubscriber : public content::RenderWidgetHostViewFrameSubscriber {
|
||||||
|
public:
|
||||||
|
using FrameCaptureCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||||
|
|
||||||
|
FrameSubscriber(v8::Isolate* isolate,
|
||||||
|
const gfx::Size& size,
|
||||||
|
const FrameCaptureCallback& callback);
|
||||||
|
|
||||||
|
bool ShouldCaptureFrame(const gfx::Rect& damage_rect,
|
||||||
|
base::TimeTicks present_time,
|
||||||
|
scoped_refptr<media::VideoFrame>* storage,
|
||||||
|
DeliverFrameCallback* callback) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void OnFrameDelivered(
|
||||||
|
scoped_refptr<media::VideoFrame> frame, base::TimeTicks, bool);
|
||||||
|
|
||||||
|
v8::Isolate* isolate_;
|
||||||
|
gfx::Size size_;
|
||||||
|
FrameCaptureCallback callback_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(FrameSubscriber);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
#endif // ATOM_BROWSER_API_FRAME_SUBSCRIBER_H_
|
|
@ -1,45 +0,0 @@
|
||||||
EventEmitter = require('events').EventEmitter
|
|
||||||
|
|
||||||
bindings = process.atomBinding 'app'
|
|
||||||
|
|
||||||
app = bindings.app
|
|
||||||
app.__proto__ = EventEmitter.prototype
|
|
||||||
|
|
||||||
app.setApplicationMenu = (menu) ->
|
|
||||||
require('menu').setApplicationMenu menu
|
|
||||||
|
|
||||||
app.getApplicationMenu = ->
|
|
||||||
require('menu').getApplicationMenu()
|
|
||||||
|
|
||||||
app.commandLine =
|
|
||||||
appendSwitch: bindings.appendSwitch,
|
|
||||||
appendArgument: bindings.appendArgument
|
|
||||||
|
|
||||||
if process.platform is 'darwin'
|
|
||||||
app.dock =
|
|
||||||
bounce: (type='informational') -> bindings.dockBounce type
|
|
||||||
cancelBounce: bindings.dockCancelBounce
|
|
||||||
setBadge: bindings.dockSetBadgeText
|
|
||||||
getBadge: bindings.dockGetBadgeText
|
|
||||||
hide: bindings.dockHide
|
|
||||||
show: bindings.dockShow
|
|
||||||
setMenu: bindings.dockSetMenu
|
|
||||||
|
|
||||||
appPath = null
|
|
||||||
app.setAppPath = (path) ->
|
|
||||||
appPath = path
|
|
||||||
|
|
||||||
app.getAppPath = ->
|
|
||||||
appPath
|
|
||||||
|
|
||||||
# Be compatible with old API.
|
|
||||||
app.once 'ready', -> @emit 'finish-launching'
|
|
||||||
app.terminate = app.quit
|
|
||||||
app.exit = process.exit
|
|
||||||
app.getHomeDir = -> @getPath 'home'
|
|
||||||
app.getDataPath = -> @getPath 'userData'
|
|
||||||
app.setDataPath = (path) -> @setPath 'userData', path
|
|
||||||
app.resolveProxy = -> @defaultSession.resolveProxy.apply @defaultSession, arguments
|
|
||||||
|
|
||||||
# Only one App object pemitted.
|
|
||||||
module.exports = app
|
|
123
atom/browser/api/lib/app.js
Normal file
123
atom/browser/api/lib/app.js
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
const deprecate = require('electron').deprecate;
|
||||||
|
const session = require('electron').session;
|
||||||
|
const Menu = require('electron').Menu;
|
||||||
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
|
const bindings = process.atomBinding('app');
|
||||||
|
const downloadItemBindings = process.atomBinding('download_item');
|
||||||
|
const app = bindings.app;
|
||||||
|
|
||||||
|
var slice = [].slice;
|
||||||
|
|
||||||
|
app.__proto__ = EventEmitter.prototype;
|
||||||
|
|
||||||
|
app.setApplicationMenu = function(menu) {
|
||||||
|
return Menu.setApplicationMenu(menu);
|
||||||
|
};
|
||||||
|
|
||||||
|
app.getApplicationMenu = function() {
|
||||||
|
return Menu.getApplicationMenu();
|
||||||
|
};
|
||||||
|
|
||||||
|
app.commandLine = {
|
||||||
|
appendSwitch: bindings.appendSwitch,
|
||||||
|
appendArgument: bindings.appendArgument
|
||||||
|
};
|
||||||
|
|
||||||
|
if (process.platform === 'darwin') {
|
||||||
|
app.dock = {
|
||||||
|
bounce: function(type) {
|
||||||
|
if (type == null) {
|
||||||
|
type = 'informational';
|
||||||
|
}
|
||||||
|
return bindings.dockBounce(type);
|
||||||
|
},
|
||||||
|
cancelBounce: bindings.dockCancelBounce,
|
||||||
|
setBadge: bindings.dockSetBadgeText,
|
||||||
|
getBadge: bindings.dockGetBadgeText,
|
||||||
|
hide: bindings.dockHide,
|
||||||
|
show: bindings.dockShow,
|
||||||
|
setMenu: bindings.dockSetMenu,
|
||||||
|
setIcon: bindings.dockSetIcon
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var appPath = null;
|
||||||
|
|
||||||
|
app.setAppPath = function(path) {
|
||||||
|
return appPath = path;
|
||||||
|
};
|
||||||
|
|
||||||
|
app.getAppPath = function() {
|
||||||
|
return appPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Routes the events to webContents.
|
||||||
|
var ref1 = ['login', 'certificate-error', 'select-client-certificate'];
|
||||||
|
var fn = function(name) {
|
||||||
|
return app.on(name, function() {
|
||||||
|
var args, event, webContents;
|
||||||
|
event = arguments[0], webContents = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : [];
|
||||||
|
return webContents.emit.apply(webContents, [name, event].concat(slice.call(args)));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var i, len;
|
||||||
|
for (i = 0, len = ref1.length; i < len; i++) {
|
||||||
|
fn(ref1[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated.
|
||||||
|
|
||||||
|
app.getHomeDir = deprecate('app.getHomeDir', 'app.getPath', function() {
|
||||||
|
return this.getPath('home');
|
||||||
|
});
|
||||||
|
|
||||||
|
app.getDataPath = deprecate('app.getDataPath', 'app.getPath', function() {
|
||||||
|
return this.getPath('userData');
|
||||||
|
});
|
||||||
|
|
||||||
|
app.setDataPath = deprecate('app.setDataPath', 'app.setPath', function(path) {
|
||||||
|
return this.setPath('userData', path);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.resolveProxy = deprecate('app.resolveProxy', 'session.defaultSession.resolveProxy', function(url, callback) {
|
||||||
|
return session.defaultSession.resolveProxy(url, callback);
|
||||||
|
});
|
||||||
|
|
||||||
|
deprecate.rename(app, 'terminate', 'quit');
|
||||||
|
|
||||||
|
deprecate.event(app, 'finish-launching', 'ready', function() {
|
||||||
|
|
||||||
|
// give default app a chance to setup default menu.
|
||||||
|
return setImmediate((function(_this) {
|
||||||
|
return function() {
|
||||||
|
return _this.emit('finish-launching');
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
});
|
||||||
|
|
||||||
|
deprecate.event(app, 'activate-with-no-open-windows', 'activate', function(event, hasVisibleWindows) {
|
||||||
|
if (!hasVisibleWindows) {
|
||||||
|
return this.emit('activate-with-no-open-windows', event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
deprecate.event(app, 'select-certificate', 'select-client-certificate');
|
||||||
|
|
||||||
|
// Wrappers for native classes.
|
||||||
|
var wrapDownloadItem = function(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');
|
||||||
|
return deprecate.rename(downloadItem, 'getUrl', 'getURL');
|
||||||
|
};
|
||||||
|
|
||||||
|
downloadItemBindings._setWrapDownloadItem(wrapDownloadItem);
|
||||||
|
|
||||||
|
// Only one App object pemitted.
|
||||||
|
module.exports = app;
|
|
@ -1,6 +0,0 @@
|
||||||
module.exports =
|
|
||||||
browserMainParts:
|
|
||||||
preMainMessageLoopRun: ->
|
|
||||||
|
|
||||||
setImmediate ->
|
|
||||||
module.exports.browserMainParts.preMainMessageLoopRun()
|
|
|
@ -1,24 +0,0 @@
|
||||||
autoUpdater = process.atomBinding('auto_updater').autoUpdater
|
|
||||||
EventEmitter = require('events').EventEmitter
|
|
||||||
|
|
||||||
autoUpdater.__proto__ = EventEmitter.prototype
|
|
||||||
|
|
||||||
autoUpdater.on 'update-downloaded-raw', (args...) ->
|
|
||||||
args[3] = new Date(args[3]) # releaseDate
|
|
||||||
@emit 'update-downloaded', args..., => @quitAndInstall()
|
|
||||||
|
|
||||||
autoUpdater.quitAndInstall = ->
|
|
||||||
# If we don't have any window then quitAndInstall immediately.
|
|
||||||
BrowserWindow = require 'browser-window'
|
|
||||||
windows = BrowserWindow.getAllWindows()
|
|
||||||
if windows.length is 0
|
|
||||||
@_quitAndInstall()
|
|
||||||
return
|
|
||||||
|
|
||||||
# Do the restart after all windows have been closed.
|
|
||||||
app = require 'app'
|
|
||||||
app.removeAllListeners 'window-all-closed'
|
|
||||||
app.once 'window-all-closed', @_quitAndInstall.bind(this)
|
|
||||||
win.close() for win in windows
|
|
||||||
|
|
||||||
module.exports = autoUpdater
|
|
7
atom/browser/api/lib/auto-updater.js
Normal file
7
atom/browser/api/lib/auto-updater.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
const deprecate = require('electron').deprecate;
|
||||||
|
const autoUpdater = process.platform === 'win32' ? require('./auto-updater/auto-updater-win') : require('./auto-updater/auto-updater-native');
|
||||||
|
|
||||||
|
// Deprecated.
|
||||||
|
deprecate.rename(autoUpdater, 'setFeedUrl', 'setFeedURL');
|
||||||
|
|
||||||
|
module.exports = autoUpdater;
|
6
atom/browser/api/lib/auto-updater/auto-updater-native.js
Normal file
6
atom/browser/api/lib/auto-updater/auto-updater-native.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
const autoUpdater = process.atomBinding('auto_updater').autoUpdater;
|
||||||
|
|
||||||
|
autoUpdater.__proto__ = EventEmitter.prototype;
|
||||||
|
|
||||||
|
module.exports = autoUpdater;
|
62
atom/browser/api/lib/auto-updater/auto-updater-win.js
Normal file
62
atom/browser/api/lib/auto-updater/auto-updater-win.js
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const app = require('electron').app;
|
||||||
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
const squirrelUpdate = require('./squirrel-update-win');
|
||||||
|
|
||||||
|
class AutoUpdater extends EventEmitter {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
quitAndInstall() {
|
||||||
|
squirrelUpdate.processStart();
|
||||||
|
return app.quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
setFeedURL(updateURL) {
|
||||||
|
return this.updateURL = updateURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkForUpdates() {
|
||||||
|
if (!this.updateURL) {
|
||||||
|
return this.emitError('Update URL is not set');
|
||||||
|
}
|
||||||
|
if (!squirrelUpdate.supported()) {
|
||||||
|
return this.emitError('Can not find Squirrel');
|
||||||
|
}
|
||||||
|
this.emit('checking-for-update');
|
||||||
|
return squirrelUpdate.download(this.updateURL, (function(_this) {
|
||||||
|
return function(error, update) {
|
||||||
|
if (error != null) {
|
||||||
|
return _this.emitError(error);
|
||||||
|
}
|
||||||
|
if (update == null) {
|
||||||
|
return _this.emit('update-not-available');
|
||||||
|
}
|
||||||
|
_this.emit('update-available');
|
||||||
|
return squirrelUpdate.update(_this.updateURL, function(error) {
|
||||||
|
var date, releaseNotes, version;
|
||||||
|
if (error != null) {
|
||||||
|
return _this.emitError(error);
|
||||||
|
}
|
||||||
|
releaseNotes = update.releaseNotes, version = update.version;
|
||||||
|
|
||||||
|
// Following information is not available on Windows, so fake them.
|
||||||
|
date = new Date;
|
||||||
|
return _this.emit('update-downloaded', {}, releaseNotes, version, date, _this.updateURL, function() {
|
||||||
|
return _this.quitAndInstall();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private: Emit both error object and message, this is to keep compatibility
|
||||||
|
// with Old APIs.
|
||||||
|
emitError(message) {
|
||||||
|
return this.emit('error', new Error(message), message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new AutoUpdater;
|
98
atom/browser/api/lib/auto-updater/squirrel-update-win.js
Normal file
98
atom/browser/api/lib/auto-updater/squirrel-update-win.js
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const spawn = require('child_process').spawn;
|
||||||
|
|
||||||
|
// i.e. my-app/app-0.1.13/
|
||||||
|
const appFolder = path.dirname(process.execPath);
|
||||||
|
|
||||||
|
// i.e. my-app/Update.exe
|
||||||
|
const updateExe = path.resolve(appFolder, '..', 'Update.exe');
|
||||||
|
|
||||||
|
const exeName = path.basename(process.execPath);
|
||||||
|
|
||||||
|
// Spawn a command and invoke the callback when it completes with an error
|
||||||
|
// and the output from standard out.
|
||||||
|
var spawnUpdate = function(args, detached, callback) {
|
||||||
|
var error, errorEmitted, spawnedProcess, stderr, stdout;
|
||||||
|
try {
|
||||||
|
spawnedProcess = spawn(updateExe, args, {
|
||||||
|
detached: detached
|
||||||
|
});
|
||||||
|
} catch (error1) {
|
||||||
|
error = error1;
|
||||||
|
|
||||||
|
// Shouldn't happen, but still guard it.
|
||||||
|
process.nextTick(function() {
|
||||||
|
return callback(error);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stdout = '';
|
||||||
|
stderr = '';
|
||||||
|
spawnedProcess.stdout.on('data', function(data) {
|
||||||
|
return stdout += data;
|
||||||
|
});
|
||||||
|
spawnedProcess.stderr.on('data', function(data) {
|
||||||
|
return stderr += data;
|
||||||
|
});
|
||||||
|
errorEmitted = false;
|
||||||
|
spawnedProcess.on('error', function(error) {
|
||||||
|
errorEmitted = true;
|
||||||
|
return callback(error);
|
||||||
|
});
|
||||||
|
return spawnedProcess.on('exit', function(code, signal) {
|
||||||
|
|
||||||
|
// We may have already emitted an error.
|
||||||
|
if (errorEmitted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process terminated with error.
|
||||||
|
if (code !== 0) {
|
||||||
|
return callback("Command failed: " + (signal != null ? signal : code) + "\n" + stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success.
|
||||||
|
return callback(null, stdout);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start an instance of the installed app.
|
||||||
|
exports.processStart = function() {
|
||||||
|
return spawnUpdate(['--processStart', exeName], true, function() {});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Download the releases specified by the URL and write new results to stdout.
|
||||||
|
exports.download = function(updateURL, callback) {
|
||||||
|
return spawnUpdate(['--download', updateURL], false, function(error, stdout) {
|
||||||
|
var json, ref, ref1, update;
|
||||||
|
if (error != null) {
|
||||||
|
return callback(error);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// Last line of output is the JSON details about the releases
|
||||||
|
json = stdout.trim().split('\n').pop();
|
||||||
|
update = (ref = JSON.parse(json)) != null ? (ref1 = ref.releasesToApply) != null ? typeof ref1.pop === "function" ? ref1.pop() : void 0 : void 0 : void 0;
|
||||||
|
} catch (jsonError) {
|
||||||
|
return callback("Invalid result:\n" + stdout);
|
||||||
|
}
|
||||||
|
return callback(null, update);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Update the application to the latest remote version specified by URL.
|
||||||
|
exports.update = function(updateURL, callback) {
|
||||||
|
return spawnUpdate(['--update', updateURL], false, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Is the Update.exe installed with the current application?
|
||||||
|
exports.supported = function() {
|
||||||
|
try {
|
||||||
|
fs.accessSync(updateExe, fs.R_OK);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,84 +0,0 @@
|
||||||
EventEmitter = require('events').EventEmitter
|
|
||||||
app = require 'app'
|
|
||||||
ipc = require 'ipc'
|
|
||||||
|
|
||||||
BrowserWindow = process.atomBinding('window').BrowserWindow
|
|
||||||
BrowserWindow::__proto__ = EventEmitter.prototype
|
|
||||||
|
|
||||||
BrowserWindow::_init = ->
|
|
||||||
# Simulate the application menu on platforms other than OS X.
|
|
||||||
if process.platform isnt 'darwin'
|
|
||||||
menu = app.getApplicationMenu()
|
|
||||||
@setMenu menu if menu?
|
|
||||||
|
|
||||||
# Make new windows requested by links behave like "window.open"
|
|
||||||
@webContents.on '-new-window', (event, url, frameName) ->
|
|
||||||
options = show: true, width: 800, height: 600
|
|
||||||
ipc.emit 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options
|
|
||||||
|
|
||||||
# window.resizeTo(...)
|
|
||||||
# window.moveTo(...)
|
|
||||||
@webContents.on 'move', (event, size) =>
|
|
||||||
@setBounds size
|
|
||||||
|
|
||||||
# Hide the auto-hide menu when webContents is focused.
|
|
||||||
@webContents.on 'activate', =>
|
|
||||||
if process.platform isnt 'darwin' and @isMenuBarAutoHide() and @isMenuBarVisible()
|
|
||||||
@setMenuBarVisibility false
|
|
||||||
|
|
||||||
# Forward the crashed event.
|
|
||||||
@webContents.on 'crashed', =>
|
|
||||||
@emit 'crashed'
|
|
||||||
|
|
||||||
# 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
|
|
||||||
# when we first start to load URL, if we do it earlier it won't have effect,
|
|
||||||
# if we do it later we might move focus in the page.
|
|
||||||
# Though this hack is only needed on OS X when the app is launched from
|
|
||||||
# Finder, we still do it on all platforms in case of other bugs we don't know.
|
|
||||||
@webContents.once 'load-url', ->
|
|
||||||
@focus()
|
|
||||||
|
|
||||||
# Redirect focus/blur event to app instance too.
|
|
||||||
@on 'blur', (event) =>
|
|
||||||
app.emit 'browser-window-blur', event, this
|
|
||||||
@on 'focus', (event) =>
|
|
||||||
app.emit 'browser-window-focus', event, this
|
|
||||||
|
|
||||||
BrowserWindow.getFocusedWindow = ->
|
|
||||||
windows = BrowserWindow.getAllWindows()
|
|
||||||
return window for window in windows when window.isFocused()
|
|
||||||
|
|
||||||
BrowserWindow.fromWebContents = (webContents) ->
|
|
||||||
windows = BrowserWindow.getAllWindows()
|
|
||||||
return window for window in windows when window.webContents?.equal webContents
|
|
||||||
|
|
||||||
BrowserWindow.fromDevToolsWebContents = (webContents) ->
|
|
||||||
windows = BrowserWindow.getAllWindows()
|
|
||||||
return window for window in windows when window.devToolsWebContents?.equal webContents
|
|
||||||
|
|
||||||
# Helpers.
|
|
||||||
BrowserWindow::loadUrl = -> @webContents.loadUrl.apply @webContents, arguments
|
|
||||||
BrowserWindow::send = -> @webContents.send.apply @webContents, arguments
|
|
||||||
|
|
||||||
# Be compatible with old API.
|
|
||||||
BrowserWindow::restart = -> @webContents.reload()
|
|
||||||
BrowserWindow::getUrl = -> @webContents.getUrl()
|
|
||||||
BrowserWindow::reload = -> @webContents.reload.apply @webContents, arguments
|
|
||||||
BrowserWindow::reloadIgnoringCache = -> @webContents.reloadIgnoringCache.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::closeDevTools = -> @webContents.closeDevTools()
|
|
||||||
BrowserWindow::isDevToolsOpened = -> @webContents.isDevToolsOpened()
|
|
||||||
BrowserWindow::toggleDevTools = -> @webContents.toggleDevTools()
|
|
||||||
BrowserWindow::inspectElement = -> @webContents.inspectElement.apply @webContents, arguments
|
|
||||||
BrowserWindow::inspectServiceWorker = -> @webContents.inspectServiceWorker()
|
|
||||||
BrowserWindow::print = -> @webContents.print.apply @webContents, arguments
|
|
||||||
BrowserWindow::printToPDF = -> @webContents.printToPDF.apply @webContents, arguments
|
|
||||||
|
|
||||||
module.exports = BrowserWindow
|
|
241
atom/browser/api/lib/browser-window.js
Normal file
241
atom/browser/api/lib/browser-window.js
Normal file
|
@ -0,0 +1,241 @@
|
||||||
|
const ipcMain = require('electron').ipcMain;
|
||||||
|
const deprecate = require('electron').deprecate;
|
||||||
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
const BrowserWindow = process.atomBinding('window').BrowserWindow;
|
||||||
|
|
||||||
|
BrowserWindow.prototype.__proto__ = EventEmitter.prototype;
|
||||||
|
|
||||||
|
BrowserWindow.prototype._init = function() {
|
||||||
|
|
||||||
|
// avoid recursive require.
|
||||||
|
var app, menu;
|
||||||
|
app = require('electron').app;
|
||||||
|
|
||||||
|
// Simulate the application menu on platforms other than OS X.
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
menu = app.getApplicationMenu();
|
||||||
|
if (menu != null) {
|
||||||
|
this.setMenu(menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make new windows requested by links behave like "window.open"
|
||||||
|
this.webContents.on('-new-window', function(event, url, frameName) {
|
||||||
|
var options;
|
||||||
|
options = {
|
||||||
|
show: true,
|
||||||
|
width: 800,
|
||||||
|
height: 600
|
||||||
|
};
|
||||||
|
return ipcMain.emit('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options);
|
||||||
|
});
|
||||||
|
|
||||||
|
// window.resizeTo(...)
|
||||||
|
// window.moveTo(...)
|
||||||
|
this.webContents.on('move', (function(_this) {
|
||||||
|
return function(event, size) {
|
||||||
|
return _this.setBounds(size);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
|
||||||
|
// Hide the auto-hide menu when webContents is focused.
|
||||||
|
this.webContents.on('activate', (function(_this) {
|
||||||
|
return function() {
|
||||||
|
if (process.platform !== 'darwin' && _this.isMenuBarAutoHide() && _this.isMenuBarVisible()) {
|
||||||
|
return _this.setMenuBarVisibility(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
|
||||||
|
// Forward the crashed event.
|
||||||
|
this.webContents.on('crashed', (function(_this) {
|
||||||
|
return function() {
|
||||||
|
return _this.emit('crashed');
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
|
||||||
|
// Change window title to page title.
|
||||||
|
this.webContents.on('page-title-updated', (function(_this) {
|
||||||
|
return function(event, title) {
|
||||||
|
_this.emit('page-title-updated', event, title);
|
||||||
|
if (!event.defaultPrevented) {
|
||||||
|
return _this.setTitle(title);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// when we first start to load URL, if we do it earlier it won't have effect,
|
||||||
|
// if we do it later we might move focus in the page.
|
||||||
|
// Though this hack is only needed on OS X when the app is launched from
|
||||||
|
// Finder, we still do it on all platforms in case of other bugs we don't know.
|
||||||
|
this.webContents.once('load-url', function() {
|
||||||
|
return this.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Redirect focus/blur event to app instance too.
|
||||||
|
this.on('blur', (function(_this) {
|
||||||
|
return function(event) {
|
||||||
|
return app.emit('browser-window-blur', event, _this);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
this.on('focus', (function(_this) {
|
||||||
|
return function(event) {
|
||||||
|
return app.emit('browser-window-focus', event, _this);
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
|
||||||
|
// Notify the creation of the window.
|
||||||
|
app.emit('browser-window-created', {}, this);
|
||||||
|
|
||||||
|
// Be compatible with old APIs.
|
||||||
|
this.webContents.on('devtools-focused', (function(_this) {
|
||||||
|
return function() {
|
||||||
|
return _this.emit('devtools-focused');
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
this.webContents.on('devtools-opened', (function(_this) {
|
||||||
|
return function() {
|
||||||
|
return _this.emit('devtools-opened');
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
this.webContents.on('devtools-closed', (function(_this) {
|
||||||
|
return function() {
|
||||||
|
return _this.emit('devtools-closed');
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
return Object.defineProperty(this, 'devToolsWebContents', {
|
||||||
|
enumerable: true,
|
||||||
|
configurable: false,
|
||||||
|
get: function() {
|
||||||
|
return this.webContents.devToolsWebContents;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserWindow.getFocusedWindow = function() {
|
||||||
|
var i, len, window, windows;
|
||||||
|
windows = BrowserWindow.getAllWindows();
|
||||||
|
for (i = 0, len = windows.length; i < len; i++) {
|
||||||
|
window = windows[i];
|
||||||
|
if (window.isFocused()) {
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserWindow.fromWebContents = function(webContents) {
|
||||||
|
var i, len, ref1, window, windows;
|
||||||
|
windows = BrowserWindow.getAllWindows();
|
||||||
|
for (i = 0, len = windows.length; i < len; i++) {
|
||||||
|
window = windows[i];
|
||||||
|
if ((ref1 = window.webContents) != null ? ref1.equal(webContents) : void 0) {
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserWindow.fromDevToolsWebContents = function(webContents) {
|
||||||
|
var i, len, ref1, window, windows;
|
||||||
|
windows = BrowserWindow.getAllWindows();
|
||||||
|
for (i = 0, len = windows.length; i < len; i++) {
|
||||||
|
window = windows[i];
|
||||||
|
if ((ref1 = window.devToolsWebContents) != null ? ref1.equal(webContents) : void 0) {
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helpers.
|
||||||
|
|
||||||
|
BrowserWindow.prototype.loadURL = function() {
|
||||||
|
return this.webContents.loadURL.apply(this.webContents, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserWindow.prototype.getURL = function() {
|
||||||
|
return this.webContents.getURL();
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserWindow.prototype.reload = function() {
|
||||||
|
return this.webContents.reload.apply(this.webContents, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserWindow.prototype.send = function() {
|
||||||
|
return this.webContents.send.apply(this.webContents, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserWindow.prototype.openDevTools = function() {
|
||||||
|
return this.webContents.openDevTools.apply(this.webContents, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserWindow.prototype.closeDevTools = function() {
|
||||||
|
return this.webContents.closeDevTools();
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserWindow.prototype.isDevToolsOpened = function() {
|
||||||
|
return this.webContents.isDevToolsOpened();
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserWindow.prototype.isDevToolsFocused = function() {
|
||||||
|
return this.webContents.isDevToolsFocused();
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserWindow.prototype.toggleDevTools = function() {
|
||||||
|
return this.webContents.toggleDevTools();
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserWindow.prototype.inspectElement = function() {
|
||||||
|
return this.webContents.inspectElement.apply(this.webContents, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserWindow.prototype.inspectServiceWorker = function() {
|
||||||
|
return this.webContents.inspectServiceWorker();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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.prototype.executeJavaScriptInDevTools = deprecate('executeJavaScriptInDevTools', 'devToolsWebContents.executeJavaScript', function(code) {
|
||||||
|
var ref1;
|
||||||
|
return (ref1 = this.devToolsWebContents) != null ? ref1.executeJavaScript(code) : void 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
BrowserWindow.prototype.getPageTitle = deprecate('getPageTitle', 'webContents.getTitle', function() {
|
||||||
|
var ref1;
|
||||||
|
return (ref1 = this.webContents) != null ? ref1.getTitle() : void 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = BrowserWindow;
|
|
@ -1 +0,0 @@
|
||||||
module.exports = process.atomBinding 'content_tracing'
|
|
1
atom/browser/api/lib/content-tracing.js
Normal file
1
atom/browser/api/lib/content-tracing.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
module.exports = process.atomBinding('content_tracing');
|
|
@ -1,125 +0,0 @@
|
||||||
binding = process.atomBinding 'dialog'
|
|
||||||
v8Util = process.atomBinding 'v8_util'
|
|
||||||
app = require 'app'
|
|
||||||
BrowserWindow = require 'browser-window'
|
|
||||||
|
|
||||||
fileDialogProperties =
|
|
||||||
openFile: 1 << 0
|
|
||||||
openDirectory: 1 << 1
|
|
||||||
multiSelections: 1 << 2
|
|
||||||
createDirectory: 1 << 3
|
|
||||||
|
|
||||||
messageBoxTypes = ['none', 'info', 'warning', 'error', 'question']
|
|
||||||
|
|
||||||
messageBoxOptions =
|
|
||||||
noLink: 1 << 0
|
|
||||||
|
|
||||||
parseArgs = (window, options, callback) ->
|
|
||||||
unless window is null or window?.constructor is BrowserWindow
|
|
||||||
# Shift.
|
|
||||||
callback = options
|
|
||||||
options = window
|
|
||||||
window = null
|
|
||||||
if not callback? and typeof options is 'function'
|
|
||||||
# Shift.
|
|
||||||
callback = options
|
|
||||||
options = null
|
|
||||||
[window, options, callback]
|
|
||||||
|
|
||||||
checkAppInitialized = ->
|
|
||||||
throw new Error('dialog module can only be used after app is ready') unless app.isReady()
|
|
||||||
|
|
||||||
module.exports =
|
|
||||||
showOpenDialog: (args...) ->
|
|
||||||
checkAppInitialized()
|
|
||||||
[window, options, callback] = parseArgs args...
|
|
||||||
|
|
||||||
options ?= title: 'Open', properties: ['openFile']
|
|
||||||
options.properties ?= ['openFile']
|
|
||||||
throw new TypeError('Properties need to be array') unless Array.isArray options.properties
|
|
||||||
|
|
||||||
properties = 0
|
|
||||||
for prop, value of fileDialogProperties
|
|
||||||
properties |= value if prop in options.properties
|
|
||||||
|
|
||||||
options.title ?= ''
|
|
||||||
options.defaultPath ?= ''
|
|
||||||
options.filters ?= []
|
|
||||||
|
|
||||||
wrappedCallback =
|
|
||||||
if typeof callback is 'function'
|
|
||||||
(success, result) -> callback(if success then result)
|
|
||||||
else
|
|
||||||
null
|
|
||||||
|
|
||||||
binding.showOpenDialog String(options.title),
|
|
||||||
String(options.defaultPath),
|
|
||||||
options.filters
|
|
||||||
properties,
|
|
||||||
window,
|
|
||||||
wrappedCallback
|
|
||||||
|
|
||||||
showSaveDialog: (args...) ->
|
|
||||||
checkAppInitialized()
|
|
||||||
[window, options, callback] = parseArgs args...
|
|
||||||
|
|
||||||
options ?= title: 'Save'
|
|
||||||
options.title ?= ''
|
|
||||||
options.defaultPath ?= ''
|
|
||||||
options.filters ?= []
|
|
||||||
|
|
||||||
wrappedCallback =
|
|
||||||
if typeof callback is 'function'
|
|
||||||
(success, result) -> callback(if success then result)
|
|
||||||
else
|
|
||||||
null
|
|
||||||
|
|
||||||
binding.showSaveDialog String(options.title),
|
|
||||||
String(options.defaultPath),
|
|
||||||
options.filters
|
|
||||||
window,
|
|
||||||
wrappedCallback
|
|
||||||
|
|
||||||
showMessageBox: (args...) ->
|
|
||||||
checkAppInitialized()
|
|
||||||
[window, options, callback] = parseArgs args...
|
|
||||||
|
|
||||||
options ?= type: 'none'
|
|
||||||
options.type ?= 'none'
|
|
||||||
messageBoxType = messageBoxTypes.indexOf options.type
|
|
||||||
throw new TypeError('Invalid message box type') unless messageBoxType > -1
|
|
||||||
|
|
||||||
throw new TypeError('Buttons need to be array') unless Array.isArray options.buttons
|
|
||||||
|
|
||||||
options.title ?= ''
|
|
||||||
options.message ?= ''
|
|
||||||
options.detail ?= ''
|
|
||||||
options.icon ?= null
|
|
||||||
|
|
||||||
# Choose a default button to get selected when dialog is cancelled.
|
|
||||||
unless options.cancelId?
|
|
||||||
options.cancelId = 0
|
|
||||||
for text, i in options.buttons
|
|
||||||
if text.toLowerCase() in ['cancel', 'no']
|
|
||||||
options.cancelId = i
|
|
||||||
break
|
|
||||||
|
|
||||||
flags = if options.noLink then messageBoxOptions.noLink else 0
|
|
||||||
|
|
||||||
binding.showMessageBox messageBoxType,
|
|
||||||
options.buttons,
|
|
||||||
options.cancelId,
|
|
||||||
flags,
|
|
||||||
options.title,
|
|
||||||
options.message,
|
|
||||||
options.detail,
|
|
||||||
options.icon,
|
|
||||||
window,
|
|
||||||
callback
|
|
||||||
|
|
||||||
showErrorBox: (args...) ->
|
|
||||||
binding.showErrorBox args...
|
|
||||||
|
|
||||||
# Mark standard asynchronous functions.
|
|
||||||
for api in ['showMessageBox', 'showOpenDialog', 'showSaveDialog']
|
|
||||||
v8Util.setHiddenValue module.exports[api], 'asynchronous', true
|
|
170
atom/browser/api/lib/dialog.js
Normal file
170
atom/browser/api/lib/dialog.js
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
const app = require('electron').app;
|
||||||
|
const BrowserWindow = require('electron').BrowserWindow;
|
||||||
|
const binding = process.atomBinding('dialog');
|
||||||
|
const v8Util = process.atomBinding('v8_util');
|
||||||
|
|
||||||
|
var slice = [].slice;
|
||||||
|
var includes = [].includes;
|
||||||
|
|
||||||
|
var fileDialogProperties = {
|
||||||
|
openFile: 1 << 0,
|
||||||
|
openDirectory: 1 << 1,
|
||||||
|
multiSelections: 1 << 2,
|
||||||
|
createDirectory: 1 << 3
|
||||||
|
};
|
||||||
|
|
||||||
|
var messageBoxTypes = ['none', 'info', 'warning', 'error', 'question'];
|
||||||
|
|
||||||
|
var messageBoxOptions = {
|
||||||
|
noLink: 1 << 0
|
||||||
|
};
|
||||||
|
|
||||||
|
var parseArgs = function(window, options, callback) {
|
||||||
|
if (!(window === null || (window != null ? window.constructor : void 0) === BrowserWindow)) {
|
||||||
|
// Shift.
|
||||||
|
callback = options;
|
||||||
|
options = window;
|
||||||
|
window = null;
|
||||||
|
}
|
||||||
|
if ((callback == null) && typeof options === 'function') {
|
||||||
|
// Shift.
|
||||||
|
callback = options;
|
||||||
|
options = null;
|
||||||
|
}
|
||||||
|
return [window, options, callback];
|
||||||
|
};
|
||||||
|
|
||||||
|
var checkAppInitialized = function() {
|
||||||
|
if (!app.isReady()) {
|
||||||
|
throw new Error('dialog module can only be used after app is ready');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
showOpenDialog: function() {
|
||||||
|
var args, callback, options, prop, properties, ref1, value, window, wrappedCallback;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
checkAppInitialized();
|
||||||
|
ref1 = parseArgs.apply(null, args), window = ref1[0], options = ref1[1], callback = ref1[2];
|
||||||
|
if (options == null) {
|
||||||
|
options = {
|
||||||
|
title: 'Open',
|
||||||
|
properties: ['openFile']
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (options.properties == null) {
|
||||||
|
options.properties = ['openFile'];
|
||||||
|
}
|
||||||
|
if (!Array.isArray(options.properties)) {
|
||||||
|
throw new TypeError('Properties need to be array');
|
||||||
|
}
|
||||||
|
properties = 0;
|
||||||
|
for (prop in fileDialogProperties) {
|
||||||
|
value = fileDialogProperties[prop];
|
||||||
|
if (includes.call(options.properties, prop)) {
|
||||||
|
properties |= value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (options.title == null) {
|
||||||
|
options.title = '';
|
||||||
|
}
|
||||||
|
if (options.defaultPath == null) {
|
||||||
|
options.defaultPath = '';
|
||||||
|
}
|
||||||
|
if (options.filters == null) {
|
||||||
|
options.filters = [];
|
||||||
|
}
|
||||||
|
wrappedCallback = typeof callback === 'function' ? function(success, result) {
|
||||||
|
return callback(success ? result : void 0);
|
||||||
|
} : null;
|
||||||
|
return binding.showOpenDialog(String(options.title), String(options.defaultPath), options.filters, properties, window, wrappedCallback);
|
||||||
|
},
|
||||||
|
showSaveDialog: function() {
|
||||||
|
var args, callback, options, ref1, window, wrappedCallback;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
checkAppInitialized();
|
||||||
|
ref1 = parseArgs.apply(null, args), window = ref1[0], options = ref1[1], callback = ref1[2];
|
||||||
|
if (options == null) {
|
||||||
|
options = {
|
||||||
|
title: 'Save'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (options.title == null) {
|
||||||
|
options.title = '';
|
||||||
|
}
|
||||||
|
if (options.defaultPath == null) {
|
||||||
|
options.defaultPath = '';
|
||||||
|
}
|
||||||
|
if (options.filters == null) {
|
||||||
|
options.filters = [];
|
||||||
|
}
|
||||||
|
wrappedCallback = typeof callback === 'function' ? function(success, result) {
|
||||||
|
return callback(success ? result : void 0);
|
||||||
|
} : null;
|
||||||
|
return binding.showSaveDialog(String(options.title), String(options.defaultPath), options.filters, window, wrappedCallback);
|
||||||
|
},
|
||||||
|
showMessageBox: function() {
|
||||||
|
var args, callback, flags, i, j, len, messageBoxType, options, ref1, ref2, ref3, text, window;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
checkAppInitialized();
|
||||||
|
ref1 = parseArgs.apply(null, args), window = ref1[0], options = ref1[1], callback = ref1[2];
|
||||||
|
if (options == null) {
|
||||||
|
options = {
|
||||||
|
type: 'none'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (options.type == null) {
|
||||||
|
options.type = 'none';
|
||||||
|
}
|
||||||
|
messageBoxType = messageBoxTypes.indexOf(options.type);
|
||||||
|
if (!(messageBoxType > -1)) {
|
||||||
|
throw new TypeError('Invalid message box type');
|
||||||
|
}
|
||||||
|
if (!Array.isArray(options.buttons)) {
|
||||||
|
throw new TypeError('Buttons need to be array');
|
||||||
|
}
|
||||||
|
if (options.title == null) {
|
||||||
|
options.title = '';
|
||||||
|
}
|
||||||
|
if (options.message == null) {
|
||||||
|
options.message = '';
|
||||||
|
}
|
||||||
|
if (options.detail == null) {
|
||||||
|
options.detail = '';
|
||||||
|
}
|
||||||
|
if (options.icon == null) {
|
||||||
|
options.icon = null;
|
||||||
|
}
|
||||||
|
if (options.defaultId == null) {
|
||||||
|
options.defaultId = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Choose a default button to get selected when dialog is cancelled.
|
||||||
|
if (options.cancelId == null) {
|
||||||
|
options.cancelId = 0;
|
||||||
|
ref2 = options.buttons;
|
||||||
|
for (i = j = 0, len = ref2.length; j < len; i = ++j) {
|
||||||
|
text = ref2[i];
|
||||||
|
if ((ref3 = text.toLowerCase()) === 'cancel' || ref3 === 'no') {
|
||||||
|
options.cancelId = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flags = options.noLink ? messageBoxOptions.noLink : 0;
|
||||||
|
return binding.showMessageBox(messageBoxType, options.buttons, options.defaultId, options.cancelId, flags, options.title, options.message, options.detail, options.icon, window, callback);
|
||||||
|
},
|
||||||
|
showErrorBox: function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return binding.showErrorBox.apply(binding, args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mark standard asynchronous functions.
|
||||||
|
var ref1 = ['showMessageBox', 'showOpenDialog', 'showSaveDialog'];
|
||||||
|
var j, len, api;
|
||||||
|
for (j = 0, len = ref1.length; j < len; j++) {
|
||||||
|
api = ref1[j];
|
||||||
|
v8Util.setHiddenValue(module.exports[api], 'asynchronous', true);
|
||||||
|
}
|
112
atom/browser/api/lib/exports/electron.js
Normal file
112
atom/browser/api/lib/exports/electron.js
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
const common = require('../../../../common/api/lib/exports/electron');
|
||||||
|
|
||||||
|
|
||||||
|
// Import common modules.
|
||||||
|
common.defineProperties(exports);
|
||||||
|
|
||||||
|
Object.defineProperties(exports, {
|
||||||
|
|
||||||
|
// Browser side modules, please sort with alphabet order.
|
||||||
|
app: {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return require('../app');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
autoUpdater: {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return require('../auto-updater');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
BrowserWindow: {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return require('../browser-window');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contentTracing: {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return require('../content-tracing');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dialog: {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return require('../dialog');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ipcMain: {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return require('../ipc-main');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
globalShortcut: {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return require('../global-shortcut');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Menu: {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return require('../menu');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MenuItem: {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return require('../menu-item');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
powerMonitor: {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return require('../power-monitor');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
powerSaveBlocker: {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return require('../power-save-blocker');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
protocol: {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return require('../protocol');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
screen: {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return require('../screen');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
session: {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return require('../session');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Tray: {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return require('../tray');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// The internal modules, invisible unless you know their names.
|
||||||
|
NavigationController: {
|
||||||
|
get: function() {
|
||||||
|
return require('../navigation-controller');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
webContents: {
|
||||||
|
get: function() {
|
||||||
|
return require('../web-contents');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,5 +0,0 @@
|
||||||
bindings = process.atomBinding 'global_shortcut'
|
|
||||||
|
|
||||||
globalShortcut = bindings.globalShortcut
|
|
||||||
|
|
||||||
module.exports = globalShortcut
|
|
5
atom/browser/api/lib/global-shortcut.js
Normal file
5
atom/browser/api/lib/global-shortcut.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
var globalShortcut;
|
||||||
|
|
||||||
|
globalShortcut = process.atomBinding('global_shortcut').globalShortcut;
|
||||||
|
|
||||||
|
module.exports = globalShortcut;
|
3
atom/browser/api/lib/ipc-main.js
Normal file
3
atom/browser/api/lib/ipc-main.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
|
module.exports = new EventEmitter;
|
|
@ -1,3 +0,0 @@
|
||||||
EventEmitter = require('events').EventEmitter
|
|
||||||
|
|
||||||
module.exports = new EventEmitter
|
|
7
atom/browser/api/lib/ipc.js
Normal file
7
atom/browser/api/lib/ipc.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
const deprecate = require('electron').deprecate;
|
||||||
|
const ipcMain = require('electron').ipcMain;
|
||||||
|
|
||||||
|
// This module is deprecated, we mirror everything from ipcMain.
|
||||||
|
deprecate.warn('ipc module', 'require("electron").ipcMain');
|
||||||
|
|
||||||
|
module.exports = ipcMain;
|
|
@ -1,49 +0,0 @@
|
||||||
BrowserWindow = require 'browser-window'
|
|
||||||
v8Util = process.atomBinding 'v8_util'
|
|
||||||
|
|
||||||
nextCommandId = 0
|
|
||||||
|
|
||||||
class MenuItem
|
|
||||||
@types = ['normal', 'separator', 'submenu', 'checkbox', 'radio']
|
|
||||||
|
|
||||||
constructor: (options) ->
|
|
||||||
Menu = require 'menu'
|
|
||||||
|
|
||||||
{click, @selector, @type, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked, @submenu} = options
|
|
||||||
|
|
||||||
@type = 'submenu' if not @type? and @submenu?
|
|
||||||
throw new Error('Invalid submenu') if @type is 'submenu' and @submenu?.constructor isnt Menu
|
|
||||||
|
|
||||||
@overrideReadOnlyProperty 'type', 'normal'
|
|
||||||
@overrideReadOnlyProperty 'accelerator'
|
|
||||||
@overrideReadOnlyProperty 'icon'
|
|
||||||
@overrideReadOnlyProperty 'submenu'
|
|
||||||
@overrideProperty 'label', ''
|
|
||||||
@overrideProperty 'sublabel', ''
|
|
||||||
@overrideProperty 'enabled', true
|
|
||||||
@overrideProperty 'visible', true
|
|
||||||
@overrideProperty 'checked', false
|
|
||||||
|
|
||||||
throw new Error("Unknown menu type #{@type}") if MenuItem.types.indexOf(@type) is -1
|
|
||||||
|
|
||||||
@commandId = ++nextCommandId
|
|
||||||
@click = =>
|
|
||||||
# Manually flip the checked flags when clicked.
|
|
||||||
@checked = !@checked if @type in ['checkbox', 'radio']
|
|
||||||
|
|
||||||
if typeof click is 'function'
|
|
||||||
click this, BrowserWindow.getFocusedWindow()
|
|
||||||
else if typeof @selector is 'string'
|
|
||||||
Menu.sendActionToFirstResponder @selector
|
|
||||||
|
|
||||||
overrideProperty: (name, defaultValue=null) ->
|
|
||||||
this[name] ?= defaultValue
|
|
||||||
|
|
||||||
overrideReadOnlyProperty: (name, defaultValue=null) ->
|
|
||||||
this[name] ?= defaultValue
|
|
||||||
Object.defineProperty this, name,
|
|
||||||
enumerable: true
|
|
||||||
writable: false
|
|
||||||
value: this[name]
|
|
||||||
|
|
||||||
module.exports = MenuItem
|
|
102
atom/browser/api/lib/menu-item.js
Normal file
102
atom/browser/api/lib/menu-item.js
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
var MenuItem, methodInBrowserWindow, nextCommandId, rolesMap;
|
||||||
|
|
||||||
|
nextCommandId = 0;
|
||||||
|
|
||||||
|
// Maps role to methods of webContents
|
||||||
|
rolesMap = {
|
||||||
|
undo: 'undo',
|
||||||
|
redo: 'redo',
|
||||||
|
cut: 'cut',
|
||||||
|
copy: 'copy',
|
||||||
|
paste: 'paste',
|
||||||
|
selectall: 'selectAll',
|
||||||
|
minimize: 'minimize',
|
||||||
|
close: 'close'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Maps methods that should be called directly on the BrowserWindow instance
|
||||||
|
methodInBrowserWindow = {
|
||||||
|
minimize: true,
|
||||||
|
close: true
|
||||||
|
};
|
||||||
|
|
||||||
|
MenuItem = (function() {
|
||||||
|
MenuItem.types = ['normal', 'separator', 'submenu', 'checkbox', 'radio'];
|
||||||
|
|
||||||
|
function MenuItem(options) {
|
||||||
|
var click, ref;
|
||||||
|
const Menu = require('electron').Menu;
|
||||||
|
click = options.click, this.selector = options.selector, this.type = options.type, this.role = options.role, this.label = options.label, this.sublabel = options.sublabel, this.accelerator = options.accelerator, this.icon = options.icon, this.enabled = options.enabled, this.visible = options.visible, this.checked = options.checked, this.submenu = options.submenu;
|
||||||
|
if ((this.submenu != null) && this.submenu.constructor !== Menu) {
|
||||||
|
this.submenu = Menu.buildFromTemplate(this.submenu);
|
||||||
|
}
|
||||||
|
if ((this.type == null) && (this.submenu != null)) {
|
||||||
|
this.type = 'submenu';
|
||||||
|
}
|
||||||
|
if (this.type === 'submenu' && ((ref = this.submenu) != null ? ref.constructor : void 0) !== Menu) {
|
||||||
|
throw new Error('Invalid submenu');
|
||||||
|
}
|
||||||
|
this.overrideReadOnlyProperty('type', 'normal');
|
||||||
|
this.overrideReadOnlyProperty('role');
|
||||||
|
this.overrideReadOnlyProperty('accelerator');
|
||||||
|
this.overrideReadOnlyProperty('icon');
|
||||||
|
this.overrideReadOnlyProperty('submenu');
|
||||||
|
this.overrideProperty('label', '');
|
||||||
|
this.overrideProperty('sublabel', '');
|
||||||
|
this.overrideProperty('enabled', true);
|
||||||
|
this.overrideProperty('visible', true);
|
||||||
|
this.overrideProperty('checked', false);
|
||||||
|
if (MenuItem.types.indexOf(this.type) === -1) {
|
||||||
|
throw new Error("Unknown menu type " + this.type);
|
||||||
|
}
|
||||||
|
this.commandId = ++nextCommandId;
|
||||||
|
this.click = (function(_this) {
|
||||||
|
return function(focusedWindow) {
|
||||||
|
|
||||||
|
// Manually flip the checked flags when clicked.
|
||||||
|
var methodName, ref1, ref2;
|
||||||
|
if ((ref1 = _this.type) === 'checkbox' || ref1 === 'radio') {
|
||||||
|
_this.checked = !_this.checked;
|
||||||
|
}
|
||||||
|
if (_this.role && rolesMap[_this.role] && process.platform !== 'darwin' && (focusedWindow != null)) {
|
||||||
|
methodName = rolesMap[_this.role];
|
||||||
|
if (methodInBrowserWindow[methodName]) {
|
||||||
|
return focusedWindow[methodName]();
|
||||||
|
} else {
|
||||||
|
return (ref2 = focusedWindow.webContents) != null ? ref2[methodName]() : void 0;
|
||||||
|
}
|
||||||
|
} else if (typeof click === 'function') {
|
||||||
|
return click(_this, focusedWindow);
|
||||||
|
} else if (typeof _this.selector === 'string') {
|
||||||
|
return Menu.sendActionToFirstResponder(_this.selector);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem.prototype.overrideProperty = function(name, defaultValue) {
|
||||||
|
if (defaultValue == null) {
|
||||||
|
defaultValue = null;
|
||||||
|
}
|
||||||
|
return this[name] != null ? this[name] : this[name] = defaultValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
MenuItem.prototype.overrideReadOnlyProperty = function(name, defaultValue) {
|
||||||
|
if (defaultValue == null) {
|
||||||
|
defaultValue = null;
|
||||||
|
}
|
||||||
|
if (this[name] == null) {
|
||||||
|
this[name] = defaultValue;
|
||||||
|
}
|
||||||
|
return Object.defineProperty(this, name, {
|
||||||
|
enumerable: true,
|
||||||
|
writable: false,
|
||||||
|
value: this[name]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return MenuItem;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = MenuItem;
|
|
@ -1,174 +0,0 @@
|
||||||
BrowserWindow = require 'browser-window'
|
|
||||||
EventEmitter = require('events').EventEmitter
|
|
||||||
MenuItem = require 'menu-item'
|
|
||||||
v8Util = process.atomBinding 'v8_util'
|
|
||||||
|
|
||||||
bindings = process.atomBinding 'menu'
|
|
||||||
|
|
||||||
# Automatically generated radio menu item's group id.
|
|
||||||
nextGroupId = 0
|
|
||||||
|
|
||||||
# Search between seperators to find a radio menu item and return its group id,
|
|
||||||
# otherwise generate a group id.
|
|
||||||
generateGroupId = (items, pos) ->
|
|
||||||
if pos > 0
|
|
||||||
for i in [pos - 1..0]
|
|
||||||
item = items[i]
|
|
||||||
return item.groupId if item.type is 'radio'
|
|
||||||
break if item.type is 'separator'
|
|
||||||
else if pos < items.length
|
|
||||||
for i in [pos..items.length - 1]
|
|
||||||
item = items[i]
|
|
||||||
return item.groupId if item.type is 'radio'
|
|
||||||
break if item.type is 'separator'
|
|
||||||
++nextGroupId
|
|
||||||
|
|
||||||
# Returns the index of item according to |id|.
|
|
||||||
indexOfItemById = (items, id) ->
|
|
||||||
return i for item, i in items when item.id is id
|
|
||||||
-1
|
|
||||||
|
|
||||||
# Returns the index of where to insert the item according to |position|.
|
|
||||||
indexToInsertByPosition = (items, position) ->
|
|
||||||
return items.length unless position
|
|
||||||
|
|
||||||
[query, id] = position.split '='
|
|
||||||
insertIndex = indexOfItemById items, id
|
|
||||||
if insertIndex is -1 and query isnt 'endof'
|
|
||||||
console.warn "Item with id '#{id}' is not found"
|
|
||||||
return items.length
|
|
||||||
|
|
||||||
switch query
|
|
||||||
when 'after'
|
|
||||||
insertIndex++
|
|
||||||
when 'endof'
|
|
||||||
# If the |id| doesn't exist, then create a new group with the |id|.
|
|
||||||
if insertIndex is -1
|
|
||||||
items.push id: id, type: 'separator'
|
|
||||||
insertIndex = items.length - 1
|
|
||||||
|
|
||||||
# Find the end of the group.
|
|
||||||
insertIndex++
|
|
||||||
while insertIndex < items.length and items[insertIndex].type isnt 'separator'
|
|
||||||
insertIndex++
|
|
||||||
|
|
||||||
insertIndex
|
|
||||||
|
|
||||||
Menu = bindings.Menu
|
|
||||||
Menu::__proto__ = EventEmitter.prototype
|
|
||||||
|
|
||||||
Menu::_init = ->
|
|
||||||
@commandsMap = {}
|
|
||||||
@groupsMap = {}
|
|
||||||
@items = []
|
|
||||||
@delegate =
|
|
||||||
isCommandIdChecked: (commandId) => @commandsMap[commandId]?.checked
|
|
||||||
isCommandIdEnabled: (commandId) => @commandsMap[commandId]?.enabled
|
|
||||||
isCommandIdVisible: (commandId) => @commandsMap[commandId]?.visible
|
|
||||||
getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator
|
|
||||||
getIconForCommandId: (commandId) => @commandsMap[commandId]?.icon
|
|
||||||
executeCommand: (commandId) => @commandsMap[commandId]?.click()
|
|
||||||
menuWillShow: =>
|
|
||||||
# Make sure radio groups have at least one menu item seleted.
|
|
||||||
for id, group of @groupsMap
|
|
||||||
checked = false
|
|
||||||
for radioItem in group when radioItem.checked
|
|
||||||
checked = true
|
|
||||||
break
|
|
||||||
v8Util.setHiddenValue group[0], 'checked', true unless checked
|
|
||||||
|
|
||||||
Menu::popup = (window, x, y) ->
|
|
||||||
throw new TypeError('Invalid window') unless window?.constructor is BrowserWindow
|
|
||||||
if x? and y?
|
|
||||||
@_popupAt(window, x, y)
|
|
||||||
else
|
|
||||||
@_popup window
|
|
||||||
|
|
||||||
Menu::append = (item) ->
|
|
||||||
@insert @getItemCount(), item
|
|
||||||
|
|
||||||
Menu::insert = (pos, item) ->
|
|
||||||
throw new TypeError('Invalid item') unless item?.constructor is MenuItem
|
|
||||||
|
|
||||||
switch item.type
|
|
||||||
when 'normal' then @insertItem pos, item.commandId, item.label
|
|
||||||
when 'checkbox' then @insertCheckItem pos, item.commandId, item.label
|
|
||||||
when 'separator' then @insertSeparator pos
|
|
||||||
when 'submenu' then @insertSubMenu pos, item.commandId, item.label, item.submenu
|
|
||||||
when 'radio'
|
|
||||||
# Grouping radio menu items.
|
|
||||||
item.overrideReadOnlyProperty 'groupId', generateGroupId(@items, pos)
|
|
||||||
@groupsMap[item.groupId] ?= []
|
|
||||||
@groupsMap[item.groupId].push item
|
|
||||||
|
|
||||||
# Setting a radio menu item should flip other items in the group.
|
|
||||||
v8Util.setHiddenValue item, 'checked', item.checked
|
|
||||||
Object.defineProperty item, 'checked',
|
|
||||||
enumerable: true
|
|
||||||
get: -> v8Util.getHiddenValue item, 'checked'
|
|
||||||
set: (val) =>
|
|
||||||
for otherItem in @groupsMap[item.groupId] when otherItem isnt item
|
|
||||||
v8Util.setHiddenValue otherItem, 'checked', false
|
|
||||||
v8Util.setHiddenValue item, 'checked', true
|
|
||||||
|
|
||||||
@insertRadioItem pos, item.commandId, item.label, item.groupId
|
|
||||||
|
|
||||||
@setSublabel pos, item.sublabel if item.sublabel?
|
|
||||||
@setIcon pos, item.icon if item.icon?
|
|
||||||
|
|
||||||
# Make menu accessable to items.
|
|
||||||
item.overrideReadOnlyProperty 'menu', this
|
|
||||||
|
|
||||||
# Remember the items.
|
|
||||||
@items.splice pos, 0, item
|
|
||||||
@commandsMap[item.commandId] = item
|
|
||||||
|
|
||||||
# Force menuWillShow to be called
|
|
||||||
Menu::_callMenuWillShow = ->
|
|
||||||
@delegate?.menuWillShow()
|
|
||||||
item.submenu._callMenuWillShow() for item in @items when item.submenu?
|
|
||||||
|
|
||||||
applicationMenu = null
|
|
||||||
Menu.setApplicationMenu = (menu) ->
|
|
||||||
throw new TypeError('Invalid menu') unless menu is null or menu.constructor is Menu
|
|
||||||
applicationMenu = menu # Keep a reference.
|
|
||||||
|
|
||||||
if process.platform is 'darwin'
|
|
||||||
return if menu is null
|
|
||||||
menu._callMenuWillShow()
|
|
||||||
bindings.setApplicationMenu menu
|
|
||||||
else
|
|
||||||
windows = BrowserWindow.getAllWindows()
|
|
||||||
w.setMenu menu for w in windows
|
|
||||||
|
|
||||||
Menu.getApplicationMenu = -> applicationMenu
|
|
||||||
|
|
||||||
Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder
|
|
||||||
|
|
||||||
Menu.buildFromTemplate = (template) ->
|
|
||||||
throw new TypeError('Invalid template for Menu') unless Array.isArray template
|
|
||||||
|
|
||||||
positionedTemplate = []
|
|
||||||
insertIndex = 0
|
|
||||||
|
|
||||||
for item in template
|
|
||||||
if item.position
|
|
||||||
insertIndex = indexToInsertByPosition positionedTemplate, item.position
|
|
||||||
else
|
|
||||||
# If no |position| is specified, insert after last item.
|
|
||||||
insertIndex++
|
|
||||||
positionedTemplate.splice insertIndex, 0, item
|
|
||||||
|
|
||||||
menu = new Menu
|
|
||||||
|
|
||||||
for item in positionedTemplate
|
|
||||||
throw new TypeError('Invalid template for MenuItem') unless typeof item is 'object'
|
|
||||||
|
|
||||||
item.submenu = Menu.buildFromTemplate item.submenu if item.submenu?
|
|
||||||
menuItem = new MenuItem(item)
|
|
||||||
menuItem[key] = value for key, value of item when not menuItem[key]?
|
|
||||||
menu.append menuItem
|
|
||||||
|
|
||||||
menu
|
|
||||||
|
|
||||||
module.exports = Menu
|
|
335
atom/browser/api/lib/menu.js
Normal file
335
atom/browser/api/lib/menu.js
Normal file
|
@ -0,0 +1,335 @@
|
||||||
|
const BrowserWindow = require('electron').BrowserWindow;
|
||||||
|
const MenuItem = require('electron').MenuItem;
|
||||||
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
const v8Util = process.atomBinding('v8_util');
|
||||||
|
const bindings = process.atomBinding('menu');
|
||||||
|
|
||||||
|
// Automatically generated radio menu item's group id.
|
||||||
|
var nextGroupId = 0;
|
||||||
|
|
||||||
|
// Search between seperators to find a radio menu item and return its group id,
|
||||||
|
// otherwise generate a group id.
|
||||||
|
var generateGroupId = function(items, pos) {
|
||||||
|
var i, item, j, k, ref1, ref2, ref3;
|
||||||
|
if (pos > 0) {
|
||||||
|
for (i = j = ref1 = pos - 1; ref1 <= 0 ? j <= 0 : j >= 0; i = ref1 <= 0 ? ++j : --j) {
|
||||||
|
item = items[i];
|
||||||
|
if (item.type === 'radio') {
|
||||||
|
return item.groupId;
|
||||||
|
}
|
||||||
|
if (item.type === 'separator') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (pos < items.length) {
|
||||||
|
for (i = k = ref2 = pos, ref3 = items.length - 1; ref2 <= ref3 ? k <= ref3 : k >= ref3; i = ref2 <= ref3 ? ++k : --k) {
|
||||||
|
item = items[i];
|
||||||
|
if (item.type === 'radio') {
|
||||||
|
return item.groupId;
|
||||||
|
}
|
||||||
|
if (item.type === 'separator') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ++nextGroupId;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns the index of item according to |id|.
|
||||||
|
var indexOfItemById = function(items, id) {
|
||||||
|
var i, item, j, len;
|
||||||
|
for (i = j = 0, len = items.length; j < len; i = ++j) {
|
||||||
|
item = items[i];
|
||||||
|
if (item.id === id) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns the index of where to insert the item according to |position|.
|
||||||
|
var indexToInsertByPosition = function(items, position) {
|
||||||
|
var id, insertIndex, query, ref1;
|
||||||
|
if (!position) {
|
||||||
|
return items.length;
|
||||||
|
}
|
||||||
|
ref1 = position.split('='), query = ref1[0], id = ref1[1];
|
||||||
|
insertIndex = indexOfItemById(items, id);
|
||||||
|
if (insertIndex === -1 && query !== 'endof') {
|
||||||
|
console.warn("Item with id '" + id + "' is not found");
|
||||||
|
return items.length;
|
||||||
|
}
|
||||||
|
switch (query) {
|
||||||
|
case 'after':
|
||||||
|
insertIndex++;
|
||||||
|
break;
|
||||||
|
case 'endof':
|
||||||
|
|
||||||
|
// If the |id| doesn't exist, then create a new group with the |id|.
|
||||||
|
if (insertIndex === -1) {
|
||||||
|
items.push({
|
||||||
|
id: id,
|
||||||
|
type: 'separator'
|
||||||
|
});
|
||||||
|
insertIndex = items.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the end of the group.
|
||||||
|
insertIndex++;
|
||||||
|
while (insertIndex < items.length && items[insertIndex].type !== 'separator') {
|
||||||
|
insertIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return insertIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Menu = bindings.Menu;
|
||||||
|
|
||||||
|
Menu.prototype.__proto__ = EventEmitter.prototype;
|
||||||
|
|
||||||
|
Menu.prototype._init = function() {
|
||||||
|
this.commandsMap = {};
|
||||||
|
this.groupsMap = {};
|
||||||
|
this.items = [];
|
||||||
|
return this.delegate = {
|
||||||
|
isCommandIdChecked: (function(_this) {
|
||||||
|
return function(commandId) {
|
||||||
|
var ref1;
|
||||||
|
return (ref1 = _this.commandsMap[commandId]) != null ? ref1.checked : void 0;
|
||||||
|
};
|
||||||
|
})(this),
|
||||||
|
isCommandIdEnabled: (function(_this) {
|
||||||
|
return function(commandId) {
|
||||||
|
var ref1;
|
||||||
|
return (ref1 = _this.commandsMap[commandId]) != null ? ref1.enabled : void 0;
|
||||||
|
};
|
||||||
|
})(this),
|
||||||
|
isCommandIdVisible: (function(_this) {
|
||||||
|
return function(commandId) {
|
||||||
|
var ref1;
|
||||||
|
return (ref1 = _this.commandsMap[commandId]) != null ? ref1.visible : void 0;
|
||||||
|
};
|
||||||
|
})(this),
|
||||||
|
getAcceleratorForCommandId: (function(_this) {
|
||||||
|
return function(commandId) {
|
||||||
|
var ref1;
|
||||||
|
return (ref1 = _this.commandsMap[commandId]) != null ? ref1.accelerator : void 0;
|
||||||
|
};
|
||||||
|
})(this),
|
||||||
|
getIconForCommandId: (function(_this) {
|
||||||
|
return function(commandId) {
|
||||||
|
var ref1;
|
||||||
|
return (ref1 = _this.commandsMap[commandId]) != null ? ref1.icon : void 0;
|
||||||
|
};
|
||||||
|
})(this),
|
||||||
|
executeCommand: (function(_this) {
|
||||||
|
return function(commandId) {
|
||||||
|
var ref1;
|
||||||
|
return (ref1 = _this.commandsMap[commandId]) != null ? ref1.click(BrowserWindow.getFocusedWindow()) : void 0;
|
||||||
|
};
|
||||||
|
})(this),
|
||||||
|
menuWillShow: (function(_this) {
|
||||||
|
return function() {
|
||||||
|
|
||||||
|
// Make sure radio groups have at least one menu item seleted.
|
||||||
|
var checked, group, id, j, len, radioItem, ref1, results;
|
||||||
|
ref1 = _this.groupsMap;
|
||||||
|
results = [];
|
||||||
|
for (id in ref1) {
|
||||||
|
group = ref1[id];
|
||||||
|
checked = false;
|
||||||
|
for (j = 0, len = group.length; j < len; j++) {
|
||||||
|
radioItem = group[j];
|
||||||
|
if (!radioItem.checked) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
checked = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!checked) {
|
||||||
|
results.push(v8Util.setHiddenValue(group[0], 'checked', true));
|
||||||
|
} else {
|
||||||
|
results.push(void 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
})(this)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Menu.prototype.popup = function(window, x, y, positioningItem) {
|
||||||
|
if (typeof window != 'object' || window.constructor !== BrowserWindow) {
|
||||||
|
// Shift.
|
||||||
|
positioningItem = y;
|
||||||
|
y = x;
|
||||||
|
x = window;
|
||||||
|
window = BrowserWindow.getFocusedWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default parameters.
|
||||||
|
if (typeof x !== 'number') x = -1;
|
||||||
|
if (typeof y !== 'number') y = -1;
|
||||||
|
if (typeof positioningItem !== 'number') positioningItem = 0;
|
||||||
|
|
||||||
|
this.popupAt(window, x, y, positioningItem);
|
||||||
|
};
|
||||||
|
|
||||||
|
Menu.prototype.append = function(item) {
|
||||||
|
return this.insert(this.getItemCount(), item);
|
||||||
|
};
|
||||||
|
|
||||||
|
Menu.prototype.insert = function(pos, item) {
|
||||||
|
var base, name;
|
||||||
|
if ((item != null ? item.constructor : void 0) !== MenuItem) {
|
||||||
|
throw new TypeError('Invalid item');
|
||||||
|
}
|
||||||
|
switch (item.type) {
|
||||||
|
case 'normal':
|
||||||
|
this.insertItem(pos, item.commandId, item.label);
|
||||||
|
break;
|
||||||
|
case 'checkbox':
|
||||||
|
this.insertCheckItem(pos, item.commandId, item.label);
|
||||||
|
break;
|
||||||
|
case 'separator':
|
||||||
|
this.insertSeparator(pos);
|
||||||
|
break;
|
||||||
|
case 'submenu':
|
||||||
|
this.insertSubMenu(pos, item.commandId, item.label, item.submenu);
|
||||||
|
break;
|
||||||
|
case 'radio':
|
||||||
|
// Grouping radio menu items.
|
||||||
|
item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos));
|
||||||
|
if ((base = this.groupsMap)[name = item.groupId] == null) {
|
||||||
|
base[name] = [];
|
||||||
|
}
|
||||||
|
this.groupsMap[item.groupId].push(item);
|
||||||
|
|
||||||
|
// Setting a radio menu item should flip other items in the group.
|
||||||
|
v8Util.setHiddenValue(item, 'checked', item.checked);
|
||||||
|
Object.defineProperty(item, 'checked', {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return v8Util.getHiddenValue(item, 'checked');
|
||||||
|
},
|
||||||
|
set: (function(_this) {
|
||||||
|
return function() {
|
||||||
|
var j, len, otherItem, ref1;
|
||||||
|
ref1 = _this.groupsMap[item.groupId];
|
||||||
|
for (j = 0, len = ref1.length; j < len; j++) {
|
||||||
|
otherItem = ref1[j];
|
||||||
|
if (otherItem !== item) {
|
||||||
|
v8Util.setHiddenValue(otherItem, 'checked', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v8Util.setHiddenValue(item, 'checked', true);
|
||||||
|
};
|
||||||
|
})(this)
|
||||||
|
});
|
||||||
|
this.insertRadioItem(pos, item.commandId, item.label, item.groupId);
|
||||||
|
}
|
||||||
|
if (item.sublabel != null) {
|
||||||
|
this.setSublabel(pos, item.sublabel);
|
||||||
|
}
|
||||||
|
if (item.icon != null) {
|
||||||
|
this.setIcon(pos, item.icon);
|
||||||
|
}
|
||||||
|
if (item.role != null) {
|
||||||
|
this.setRole(pos, item.role);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make menu accessable to items.
|
||||||
|
item.overrideReadOnlyProperty('menu', this);
|
||||||
|
|
||||||
|
// Remember the items.
|
||||||
|
this.items.splice(pos, 0, item);
|
||||||
|
return this.commandsMap[item.commandId] = item;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Force menuWillShow to be called
|
||||||
|
Menu.prototype._callMenuWillShow = function() {
|
||||||
|
var item, j, len, ref1, ref2, results;
|
||||||
|
if ((ref1 = this.delegate) != null) {
|
||||||
|
ref1.menuWillShow();
|
||||||
|
}
|
||||||
|
ref2 = this.items;
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = ref2.length; j < len; j++) {
|
||||||
|
item = ref2[j];
|
||||||
|
if (item.submenu != null) {
|
||||||
|
results.push(item.submenu._callMenuWillShow());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
var applicationMenu = null;
|
||||||
|
|
||||||
|
Menu.setApplicationMenu = function(menu) {
|
||||||
|
var j, len, results, w, windows;
|
||||||
|
if (!(menu === null || menu.constructor === Menu)) {
|
||||||
|
throw new TypeError('Invalid menu');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep a reference.
|
||||||
|
applicationMenu = menu;
|
||||||
|
if (process.platform === 'darwin') {
|
||||||
|
if (menu === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
menu._callMenuWillShow();
|
||||||
|
return bindings.setApplicationMenu(menu);
|
||||||
|
} else {
|
||||||
|
windows = BrowserWindow.getAllWindows();
|
||||||
|
results = [];
|
||||||
|
for (j = 0, len = windows.length; j < len; j++) {
|
||||||
|
w = windows[j];
|
||||||
|
results.push(w.setMenu(menu));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Menu.getApplicationMenu = function() {
|
||||||
|
return applicationMenu;
|
||||||
|
};
|
||||||
|
|
||||||
|
Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder;
|
||||||
|
|
||||||
|
Menu.buildFromTemplate = function(template) {
|
||||||
|
var insertIndex, item, j, k, key, len, len1, menu, menuItem, positionedTemplate, value;
|
||||||
|
if (!Array.isArray(template)) {
|
||||||
|
throw new TypeError('Invalid template for Menu');
|
||||||
|
}
|
||||||
|
positionedTemplate = [];
|
||||||
|
insertIndex = 0;
|
||||||
|
for (j = 0, len = template.length; j < len; j++) {
|
||||||
|
item = template[j];
|
||||||
|
if (item.position) {
|
||||||
|
insertIndex = indexToInsertByPosition(positionedTemplate, item.position);
|
||||||
|
} else {
|
||||||
|
// If no |position| is specified, insert after last item.
|
||||||
|
insertIndex++;
|
||||||
|
}
|
||||||
|
positionedTemplate.splice(insertIndex, 0, item);
|
||||||
|
}
|
||||||
|
menu = new Menu;
|
||||||
|
for (k = 0, len1 = positionedTemplate.length; k < len1; k++) {
|
||||||
|
item = positionedTemplate[k];
|
||||||
|
if (typeof item !== 'object') {
|
||||||
|
throw new TypeError('Invalid template for MenuItem');
|
||||||
|
}
|
||||||
|
menuItem = new MenuItem(item);
|
||||||
|
for (key in item) {
|
||||||
|
value = item[key];
|
||||||
|
if (menuItem[key] == null) {
|
||||||
|
menuItem[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menu.append(menuItem);
|
||||||
|
}
|
||||||
|
return menu;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Menu;
|
|
@ -1,117 +0,0 @@
|
||||||
ipc = require 'ipc'
|
|
||||||
|
|
||||||
# The history operation in renderer is redirected to browser.
|
|
||||||
ipc.on 'ATOM_SHELL_NAVIGATION_CONTROLLER', (event, method, args...) ->
|
|
||||||
event.sender[method] args...
|
|
||||||
|
|
||||||
ipc.on 'ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', (event, method, args...) ->
|
|
||||||
event.returnValue = event.sender[method] args...
|
|
||||||
|
|
||||||
# JavaScript implementation of Chromium's NavigationController.
|
|
||||||
# Instead of relying on Chromium for history control, we compeletely do history
|
|
||||||
# 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
|
|
||||||
# process is restarted everytime.
|
|
||||||
class NavigationController
|
|
||||||
constructor: (@webContents) ->
|
|
||||||
@clearHistory()
|
|
||||||
|
|
||||||
@webContents.on 'navigation-entry-commited', (event, url, inPage, replaceEntry) =>
|
|
||||||
if @inPageIndex > -1 and not inPage
|
|
||||||
# Navigated to a new page, clear in-page mark.
|
|
||||||
@inPageIndex = -1
|
|
||||||
else if @inPageIndex is -1 and inPage
|
|
||||||
# Started in-page navigations.
|
|
||||||
@inPageIndex = @currentIndex
|
|
||||||
|
|
||||||
if @pendingIndex >= 0 # Go to index.
|
|
||||||
@currentIndex = @pendingIndex
|
|
||||||
@pendingIndex = -1
|
|
||||||
@history[@currentIndex] = url
|
|
||||||
else if replaceEntry # Non-user initialized navigation.
|
|
||||||
@history[@currentIndex] = url
|
|
||||||
else # Normal navigation.
|
|
||||||
@history = @history.slice 0, @currentIndex + 1 # Clear history.
|
|
||||||
currentEntry = @history[@currentIndex]
|
|
||||||
if currentEntry?.url isnt url
|
|
||||||
@currentIndex++
|
|
||||||
@history.push url
|
|
||||||
|
|
||||||
loadUrl: (url, options={}) ->
|
|
||||||
@pendingIndex = -1
|
|
||||||
@webContents._loadUrl url, options
|
|
||||||
@webContents.emit 'load-url', url, options
|
|
||||||
|
|
||||||
getUrl: ->
|
|
||||||
if @currentIndex is -1
|
|
||||||
''
|
|
||||||
else
|
|
||||||
@history[@currentIndex]
|
|
||||||
|
|
||||||
stop: ->
|
|
||||||
@pendingIndex = -1
|
|
||||||
@webContents._stop()
|
|
||||||
|
|
||||||
reload: ->
|
|
||||||
@pendingIndex = @currentIndex
|
|
||||||
@webContents._loadUrl @getUrl(), {}
|
|
||||||
|
|
||||||
reloadIgnoringCache: ->
|
|
||||||
@webContents._reloadIgnoringCache() # Rely on WebContents to clear cache.
|
|
||||||
@reload()
|
|
||||||
|
|
||||||
canGoBack: ->
|
|
||||||
@getActiveIndex() > 0
|
|
||||||
|
|
||||||
canGoForward: ->
|
|
||||||
@getActiveIndex() < @history.length - 1
|
|
||||||
|
|
||||||
canGoToIndex: (index) ->
|
|
||||||
index >=0 and index < @history.length
|
|
||||||
|
|
||||||
canGoToOffset: (offset) ->
|
|
||||||
@canGoToIndex @currentIndex + offset
|
|
||||||
|
|
||||||
clearHistory: ->
|
|
||||||
@history = []
|
|
||||||
@currentIndex = -1
|
|
||||||
@pendingIndex = -1
|
|
||||||
@inPageIndex = -1
|
|
||||||
|
|
||||||
goBack: ->
|
|
||||||
return unless @canGoBack()
|
|
||||||
@pendingIndex = @getActiveIndex() - 1
|
|
||||||
if @inPageIndex > -1 and @pendingIndex >= @inPageIndex
|
|
||||||
@webContents._goBack()
|
|
||||||
else
|
|
||||||
@webContents._loadUrl @history[@pendingIndex], {}
|
|
||||||
|
|
||||||
goForward: ->
|
|
||||||
return unless @canGoForward()
|
|
||||||
@pendingIndex = @getActiveIndex() + 1
|
|
||||||
if @inPageIndex > -1 and @pendingIndex >= @inPageIndex
|
|
||||||
@webContents._goForward()
|
|
||||||
else
|
|
||||||
@webContents._loadUrl @history[@pendingIndex], {}
|
|
||||||
|
|
||||||
goToIndex: (index) ->
|
|
||||||
return unless @canGoToIndex index
|
|
||||||
@pendingIndex = index
|
|
||||||
@webContents._loadUrl @history[@pendingIndex], {}
|
|
||||||
|
|
||||||
goToOffset: (offset) ->
|
|
||||||
return unless @canGoToOffset offset
|
|
||||||
pendingIndex = @currentIndex + offset
|
|
||||||
if @inPageIndex > -1 and pendingIndex >= @inPageIndex
|
|
||||||
@pendingIndex = pendingIndex
|
|
||||||
@webContents._goToOffset offset
|
|
||||||
else
|
|
||||||
@goToIndex pendingIndex
|
|
||||||
|
|
||||||
getActiveIndex: ->
|
|
||||||
if @pendingIndex is -1 then @currentIndex else @pendingIndex
|
|
||||||
|
|
||||||
length: ->
|
|
||||||
@history.length
|
|
||||||
|
|
||||||
module.exports = NavigationController
|
|
188
atom/browser/api/lib/navigation-controller.js
Normal file
188
atom/browser/api/lib/navigation-controller.js
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
const ipcMain = require('electron').ipcMain;
|
||||||
|
|
||||||
|
var slice = [].slice;
|
||||||
|
|
||||||
|
// The history operation in renderer is redirected to browser.
|
||||||
|
ipcMain.on('ATOM_SHELL_NAVIGATION_CONTROLLER', function() {
|
||||||
|
var args, event, method, ref;
|
||||||
|
event = arguments[0], method = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : [];
|
||||||
|
return (ref = event.sender)[method].apply(ref, args);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', function() {
|
||||||
|
var args, event, method, ref;
|
||||||
|
event = arguments[0], method = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : [];
|
||||||
|
return event.returnValue = (ref = event.sender)[method].apply(ref, args);
|
||||||
|
});
|
||||||
|
|
||||||
|
// JavaScript implementation of Chromium's NavigationController.
|
||||||
|
// Instead of relying on Chromium for history control, we compeletely do history
|
||||||
|
// 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
|
||||||
|
// process is restarted everytime.
|
||||||
|
var NavigationController = (function() {
|
||||||
|
function NavigationController(webContents) {
|
||||||
|
this.webContents = webContents;
|
||||||
|
this.clearHistory();
|
||||||
|
|
||||||
|
// webContents may have already navigated to a page.
|
||||||
|
if (this.webContents._getURL()) {
|
||||||
|
this.currentIndex++;
|
||||||
|
this.history.push(this.webContents._getURL());
|
||||||
|
}
|
||||||
|
this.webContents.on('navigation-entry-commited', (function(_this) {
|
||||||
|
return function(event, url, inPage, replaceEntry) {
|
||||||
|
var currentEntry;
|
||||||
|
if (_this.inPageIndex > -1 && !inPage) {
|
||||||
|
|
||||||
|
// Navigated to a new page, clear in-page mark.
|
||||||
|
_this.inPageIndex = -1;
|
||||||
|
} else if (_this.inPageIndex === -1 && inPage) {
|
||||||
|
|
||||||
|
// Started in-page navigations.
|
||||||
|
_this.inPageIndex = _this.currentIndex;
|
||||||
|
}
|
||||||
|
if (_this.pendingIndex >= 0) {
|
||||||
|
|
||||||
|
// Go to index.
|
||||||
|
_this.currentIndex = _this.pendingIndex;
|
||||||
|
_this.pendingIndex = -1;
|
||||||
|
return _this.history[_this.currentIndex] = url;
|
||||||
|
} else if (replaceEntry) {
|
||||||
|
|
||||||
|
// Non-user initialized navigation.
|
||||||
|
return _this.history[_this.currentIndex] = url;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Normal navigation. Clear history.
|
||||||
|
_this.history = _this.history.slice(0, _this.currentIndex + 1);
|
||||||
|
currentEntry = _this.history[_this.currentIndex];
|
||||||
|
if ((currentEntry != null ? currentEntry.url : void 0) !== url) {
|
||||||
|
_this.currentIndex++;
|
||||||
|
return _this.history.push(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigationController.prototype.loadURL = function(url, options) {
|
||||||
|
if (options == null) {
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
this.pendingIndex = -1;
|
||||||
|
this.webContents._loadURL(url, options);
|
||||||
|
return this.webContents.emit('load-url', url, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
NavigationController.prototype.getURL = function() {
|
||||||
|
if (this.currentIndex === -1) {
|
||||||
|
return '';
|
||||||
|
} else {
|
||||||
|
return this.history[this.currentIndex];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NavigationController.prototype.stop = function() {
|
||||||
|
this.pendingIndex = -1;
|
||||||
|
return this.webContents._stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
NavigationController.prototype.reload = function() {
|
||||||
|
this.pendingIndex = this.currentIndex;
|
||||||
|
return this.webContents._loadURL(this.getURL(), {});
|
||||||
|
};
|
||||||
|
|
||||||
|
NavigationController.prototype.reloadIgnoringCache = function() {
|
||||||
|
this.pendingIndex = this.currentIndex;
|
||||||
|
return this.webContents._loadURL(this.getURL(), {
|
||||||
|
extraHeaders: "pragma: no-cache\n"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
NavigationController.prototype.canGoBack = function() {
|
||||||
|
return this.getActiveIndex() > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
NavigationController.prototype.canGoForward = function() {
|
||||||
|
return this.getActiveIndex() < this.history.length - 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
NavigationController.prototype.canGoToIndex = function(index) {
|
||||||
|
return index >= 0 && index < this.history.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
NavigationController.prototype.canGoToOffset = function(offset) {
|
||||||
|
return this.canGoToIndex(this.currentIndex + offset);
|
||||||
|
};
|
||||||
|
|
||||||
|
NavigationController.prototype.clearHistory = function() {
|
||||||
|
this.history = [];
|
||||||
|
this.currentIndex = -1;
|
||||||
|
this.pendingIndex = -1;
|
||||||
|
return this.inPageIndex = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
NavigationController.prototype.goBack = function() {
|
||||||
|
if (!this.canGoBack()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.pendingIndex = this.getActiveIndex() - 1;
|
||||||
|
if (this.inPageIndex > -1 && this.pendingIndex >= this.inPageIndex) {
|
||||||
|
return this.webContents._goBack();
|
||||||
|
} else {
|
||||||
|
return this.webContents._loadURL(this.history[this.pendingIndex], {});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NavigationController.prototype.goForward = function() {
|
||||||
|
if (!this.canGoForward()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.pendingIndex = this.getActiveIndex() + 1;
|
||||||
|
if (this.inPageIndex > -1 && this.pendingIndex >= this.inPageIndex) {
|
||||||
|
return this.webContents._goForward();
|
||||||
|
} else {
|
||||||
|
return this.webContents._loadURL(this.history[this.pendingIndex], {});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NavigationController.prototype.goToIndex = function(index) {
|
||||||
|
if (!this.canGoToIndex(index)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.pendingIndex = index;
|
||||||
|
return this.webContents._loadURL(this.history[this.pendingIndex], {});
|
||||||
|
};
|
||||||
|
|
||||||
|
NavigationController.prototype.goToOffset = function(offset) {
|
||||||
|
var pendingIndex;
|
||||||
|
if (!this.canGoToOffset(offset)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pendingIndex = this.currentIndex + offset;
|
||||||
|
if (this.inPageIndex > -1 && pendingIndex >= this.inPageIndex) {
|
||||||
|
this.pendingIndex = pendingIndex;
|
||||||
|
return this.webContents._goToOffset(offset);
|
||||||
|
} else {
|
||||||
|
return this.goToIndex(pendingIndex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NavigationController.prototype.getActiveIndex = function() {
|
||||||
|
if (this.pendingIndex === -1) {
|
||||||
|
return this.currentIndex;
|
||||||
|
} else {
|
||||||
|
return this.pendingIndex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NavigationController.prototype.length = function() {
|
||||||
|
return this.history.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
return NavigationController;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = NavigationController;
|
|
@ -1,6 +0,0 @@
|
||||||
powerMonitor = process.atomBinding('power_monitor').powerMonitor
|
|
||||||
EventEmitter = require('events').EventEmitter
|
|
||||||
|
|
||||||
powerMonitor.__proto__ = EventEmitter.prototype
|
|
||||||
|
|
||||||
module.exports = powerMonitor
|
|
6
atom/browser/api/lib/power-monitor.js
Normal file
6
atom/browser/api/lib/power-monitor.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
const powerMonitor = process.atomBinding('power_monitor').powerMonitor;
|
||||||
|
|
||||||
|
powerMonitor.__proto__ = EventEmitter.prototype;
|
||||||
|
|
||||||
|
module.exports = powerMonitor;
|
|
@ -1,3 +0,0 @@
|
||||||
bindings = process.atomBinding 'power_save_blocker'
|
|
||||||
|
|
||||||
module.exports = bindings.powerSaveBlocker
|
|
5
atom/browser/api/lib/power-save-blocker.js
Normal file
5
atom/browser/api/lib/power-save-blocker.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
var powerSaveBlocker;
|
||||||
|
|
||||||
|
powerSaveBlocker = process.atomBinding('power_save_blocker').powerSaveBlocker;
|
||||||
|
|
||||||
|
module.exports = powerSaveBlocker;
|
|
@ -1,64 +0,0 @@
|
||||||
app = require 'app'
|
|
||||||
throw new Error('Can not initialize protocol module before app is ready') unless app.isReady()
|
|
||||||
|
|
||||||
protocol = process.atomBinding('protocol').protocol
|
|
||||||
EventEmitter = require('events').EventEmitter
|
|
||||||
|
|
||||||
protocol.__proto__ = EventEmitter.prototype
|
|
||||||
|
|
||||||
GetWrappedCallback = (scheme, callback, notification) ->
|
|
||||||
wrappedCallback = (error) ->
|
|
||||||
if not callback?
|
|
||||||
if error
|
|
||||||
throw error
|
|
||||||
else
|
|
||||||
protocol.emit notification, scheme
|
|
||||||
else
|
|
||||||
callback error, scheme
|
|
||||||
|
|
||||||
# Compatibility with old api.
|
|
||||||
protocol.registerProtocol = (scheme, handler, callback) ->
|
|
||||||
protocol._registerProtocol scheme, handler, GetWrappedCallback(scheme, callback, 'registered')
|
|
||||||
|
|
||||||
protocol.unregisterProtocol = (scheme, callback) ->
|
|
||||||
protocol._unregisterProtocol scheme, GetWrappedCallback(scheme, callback, 'unregistered')
|
|
||||||
|
|
||||||
protocol.interceptProtocol = (scheme, handler, callback) ->
|
|
||||||
protocol._interceptProtocol scheme, handler, GetWrappedCallback(scheme, callback, 'intercepted')
|
|
||||||
|
|
||||||
protocol.uninterceptProtocol = (scheme, callback) ->
|
|
||||||
protocol._uninterceptProtocol scheme, GetWrappedCallback(scheme, callback, 'unintercepted')
|
|
||||||
|
|
||||||
protocol.RequestStringJob =
|
|
||||||
class RequestStringJob
|
|
||||||
constructor: ({mimeType, charset, data}) ->
|
|
||||||
if typeof data isnt 'string' and not data instanceof Buffer
|
|
||||||
throw new TypeError('Data should be string or Buffer')
|
|
||||||
|
|
||||||
@mimeType = mimeType ? 'text/plain'
|
|
||||||
@charset = charset ? 'UTF-8'
|
|
||||||
@data = String data
|
|
||||||
|
|
||||||
protocol.RequestBufferJob =
|
|
||||||
class RequestBufferJob
|
|
||||||
constructor: ({mimeType, encoding, data}) ->
|
|
||||||
if not data instanceof Buffer
|
|
||||||
throw new TypeError('Data should be Buffer')
|
|
||||||
|
|
||||||
@mimeType = mimeType ? 'application/octet-stream'
|
|
||||||
@encoding = encoding ? 'utf8'
|
|
||||||
@data = new Buffer(data)
|
|
||||||
|
|
||||||
protocol.RequestFileJob =
|
|
||||||
class RequestFileJob
|
|
||||||
constructor: (@path) ->
|
|
||||||
|
|
||||||
protocol.RequestErrorJob =
|
|
||||||
class RequestErrorJob
|
|
||||||
constructor: (@error) ->
|
|
||||||
|
|
||||||
protocol.RequestHttpJob =
|
|
||||||
class RequestHttpJob
|
|
||||||
constructor: ({@session, @url, @method, @referrer}) ->
|
|
||||||
|
|
||||||
module.exports = protocol
|
|
31
atom/browser/api/lib/protocol.js
Normal file
31
atom/browser/api/lib/protocol.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
const app = require('electron').app;
|
||||||
|
|
||||||
|
if (!app.isReady()) {
|
||||||
|
throw new Error('Can not initialize protocol module before app is ready');
|
||||||
|
}
|
||||||
|
|
||||||
|
const protocol = process.atomBinding('protocol').protocol;
|
||||||
|
|
||||||
|
// Warn about removed APIs.
|
||||||
|
var logAndThrow = function(callback, message) {
|
||||||
|
console.error(message);
|
||||||
|
if (callback) {
|
||||||
|
return callback(new Error(message));
|
||||||
|
} else {
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
protocol.registerProtocol = function(scheme, handler, callback) {
|
||||||
|
return logAndThrow(callback, 'registerProtocol API has been replaced by the register[File/Http/Buffer/String]Protocol API family, please switch to the new APIs.');
|
||||||
|
};
|
||||||
|
|
||||||
|
protocol.isHandledProtocol = function(scheme, callback) {
|
||||||
|
return logAndThrow(callback, 'isHandledProtocol API has been replaced by isProtocolHandled.');
|
||||||
|
};
|
||||||
|
|
||||||
|
protocol.interceptProtocol = function(scheme, handler, callback) {
|
||||||
|
return logAndThrow(callback, 'interceptProtocol API has been replaced by the intercept[File/Http/Buffer/String]Protocol API family, please switch to the new APIs.');
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = protocol;
|
|
@ -1,6 +0,0 @@
|
||||||
EventEmitter = require('events').EventEmitter
|
|
||||||
|
|
||||||
screen = process.atomBinding('screen').screen
|
|
||||||
screen.__proto__ = EventEmitter.prototype
|
|
||||||
|
|
||||||
module.exports = screen
|
|
6
atom/browser/api/lib/screen.js
Normal file
6
atom/browser/api/lib/screen.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
const screen = process.atomBinding('screen').screen;
|
||||||
|
|
||||||
|
screen.__proto__ = EventEmitter.prototype;
|
||||||
|
|
||||||
|
module.exports = screen;
|
33
atom/browser/api/lib/session.js
Normal file
33
atom/browser/api/lib/session.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
const bindings = process.atomBinding('session');
|
||||||
|
const PERSIST_PERFIX = 'persist:';
|
||||||
|
|
||||||
|
// Returns the Session from |partition| string.
|
||||||
|
exports.fromPartition = function(partition) {
|
||||||
|
if (partition == null) {
|
||||||
|
partition = '';
|
||||||
|
}
|
||||||
|
if (partition === '') {
|
||||||
|
return exports.defaultSession;
|
||||||
|
}
|
||||||
|
if (partition.startsWith(PERSIST_PERFIX)) {
|
||||||
|
return bindings.fromPartition(partition.substr(PERSIST_PERFIX.length), false);
|
||||||
|
} else {
|
||||||
|
return bindings.fromPartition(partition, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns the default session.
|
||||||
|
Object.defineProperty(exports, 'defaultSession', {
|
||||||
|
enumerable: true,
|
||||||
|
get: function() {
|
||||||
|
return bindings.fromPartition('', false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var wrapSession = function(session) {
|
||||||
|
// session is an EventEmitter.
|
||||||
|
return session.__proto__ = EventEmitter.prototype;
|
||||||
|
};
|
||||||
|
|
||||||
|
bindings._setWrapSession(wrapSession);
|
|
@ -1,14 +0,0 @@
|
||||||
EventEmitter = require('events').EventEmitter
|
|
||||||
bindings = process.atomBinding 'tray'
|
|
||||||
|
|
||||||
Tray = bindings.Tray
|
|
||||||
Tray::__proto__ = EventEmitter.prototype
|
|
||||||
|
|
||||||
Tray::setContextMenu = (menu) ->
|
|
||||||
@_setContextMenu menu
|
|
||||||
@menu = menu # Keep a strong reference of menu.
|
|
||||||
|
|
||||||
# Keep compatibility with old APIs.
|
|
||||||
Tray::popContextMenu = Tray::popUpContextMenu
|
|
||||||
|
|
||||||
module.exports = Tray
|
|
23
atom/browser/api/lib/tray.js
Normal file
23
atom/browser/api/lib/tray.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
const deprecate = require('electron').deprecate;
|
||||||
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
const Tray = process.atomBinding('tray').Tray;
|
||||||
|
|
||||||
|
Tray.prototype.__proto__ = EventEmitter.prototype;
|
||||||
|
|
||||||
|
Tray.prototype._init = function() {
|
||||||
|
// 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');
|
||||||
|
return deprecate.event(this, 'balloon-clicked', 'balloon-click');
|
||||||
|
};
|
||||||
|
|
||||||
|
Tray.prototype.setContextMenu = function(menu) {
|
||||||
|
this._setContextMenu(menu);
|
||||||
|
|
||||||
|
// Keep a strong reference of menu.
|
||||||
|
return this.menu = menu;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Tray;
|
|
@ -1,114 +0,0 @@
|
||||||
EventEmitter = require('events').EventEmitter
|
|
||||||
NavigationController = require './navigation-controller'
|
|
||||||
binding = process.atomBinding 'web_contents'
|
|
||||||
ipc = require 'ipc'
|
|
||||||
|
|
||||||
nextId = 0
|
|
||||||
getNextId = -> ++nextId
|
|
||||||
|
|
||||||
PDFPageSize =
|
|
||||||
A4:
|
|
||||||
custom_display_name: "A4"
|
|
||||||
height_microns: 297000
|
|
||||||
name: "ISO_A4"
|
|
||||||
is_default: "true"
|
|
||||||
width_microns: 210000
|
|
||||||
A3:
|
|
||||||
custom_display_name: "A3"
|
|
||||||
height_microns: 420000
|
|
||||||
name: "ISO_A3"
|
|
||||||
width_microns: 297000
|
|
||||||
Legal:
|
|
||||||
custom_display_name: "Legal"
|
|
||||||
height_microns: 355600
|
|
||||||
name: "NA_LEGAL"
|
|
||||||
width_microns: 215900
|
|
||||||
Letter:
|
|
||||||
custom_display_name: "Letter"
|
|
||||||
height_microns: 279400
|
|
||||||
name: "NA_LETTER"
|
|
||||||
width_microns: 215900
|
|
||||||
Tabloid:
|
|
||||||
height_microns: 431800
|
|
||||||
name: "NA_LEDGER"
|
|
||||||
width_microns: 279400
|
|
||||||
custom_display_name: "Tabloid"
|
|
||||||
|
|
||||||
wrapWebContents = (webContents) ->
|
|
||||||
# webContents is an EventEmitter.
|
|
||||||
webContents.__proto__ = EventEmitter.prototype
|
|
||||||
|
|
||||||
# WebContents::send(channel, args..)
|
|
||||||
webContents.send = (channel, args...) ->
|
|
||||||
@_send channel, [args...]
|
|
||||||
|
|
||||||
# Make sure webContents.executeJavaScript would run the code only when the
|
|
||||||
# web contents has been loaded.
|
|
||||||
webContents.loaded = false
|
|
||||||
webContents.once 'did-finish-load', -> @loaded = true
|
|
||||||
webContents.executeJavaScript = (code, hasUserGesture=false) ->
|
|
||||||
if @loaded
|
|
||||||
@_executeJavaScript code, hasUserGesture
|
|
||||||
else
|
|
||||||
webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code, hasUserGesture)
|
|
||||||
|
|
||||||
# The navigation controller.
|
|
||||||
controller = new NavigationController(webContents)
|
|
||||||
for name, method of NavigationController.prototype when method instanceof Function
|
|
||||||
do (name, method) ->
|
|
||||||
webContents[name] = -> method.apply controller, arguments
|
|
||||||
|
|
||||||
# Dispatch IPC messages to the ipc module.
|
|
||||||
webContents.on 'ipc-message', (event, packed) ->
|
|
||||||
[channel, args...] = packed
|
|
||||||
ipc.emit channel, event, args...
|
|
||||||
webContents.on 'ipc-message-sync', (event, packed) ->
|
|
||||||
[channel, args...] = packed
|
|
||||||
Object.defineProperty event, 'returnValue', set: (value) -> event.sendReply JSON.stringify(value)
|
|
||||||
ipc.emit channel, event, args...
|
|
||||||
|
|
||||||
webContents.printToPDF = (options, callback) ->
|
|
||||||
printingSetting =
|
|
||||||
pageRage: []
|
|
||||||
mediaSize: {}
|
|
||||||
landscape: false
|
|
||||||
color: 2
|
|
||||||
headerFooterEnabled: false
|
|
||||||
marginsType: 0
|
|
||||||
isFirstRequest: false
|
|
||||||
requestID: getNextId()
|
|
||||||
previewModifiable: true
|
|
||||||
printToPDF: true
|
|
||||||
printWithCloudPrint: false
|
|
||||||
printWithPrivet: false
|
|
||||||
printWithExtension: false
|
|
||||||
deviceName: "Save as PDF"
|
|
||||||
generateDraftData: true
|
|
||||||
fitToPageEnabled: false
|
|
||||||
duplex: 0
|
|
||||||
copies: 1
|
|
||||||
collate: true
|
|
||||||
shouldPrintBackgrounds: false
|
|
||||||
shouldPrintSelectionOnly: false
|
|
||||||
|
|
||||||
if options.landscape
|
|
||||||
printingSetting.landscape = options.landscape
|
|
||||||
if options.marginsType
|
|
||||||
printingSetting.marginsType = options.marginsType
|
|
||||||
if options.printSelectionOnly
|
|
||||||
printingSetting.shouldPrintSelectionOnly = options.printSelectionOnly
|
|
||||||
if options.printBackgrounds
|
|
||||||
printingSetting.shouldPrintBackgrounds = options.printBackground
|
|
||||||
|
|
||||||
if options.pageSize and PDFPageSize[options.pageSize]
|
|
||||||
printingSetting.mediaSize = PDFPageSize[options.pageSize]
|
|
||||||
else
|
|
||||||
printingSetting.mediaSize = PDFPageSize['A4']
|
|
||||||
|
|
||||||
@_printToPDF printingSetting, callback
|
|
||||||
|
|
||||||
binding._setWrapWebContents wrapWebContents
|
|
||||||
process.once 'exit', binding._clearWrapWebContents
|
|
||||||
|
|
||||||
module.exports.create = (options={}) ->
|
|
||||||
binding.create(options)
|
|
233
atom/browser/api/lib/web-contents.js
Normal file
233
atom/browser/api/lib/web-contents.js
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
const deprecate = require('electron').deprecate;
|
||||||
|
const ipcMain = require('electron').ipcMain;
|
||||||
|
const NavigationController = require('electron').NavigationController;
|
||||||
|
const Menu = require('electron').Menu;
|
||||||
|
|
||||||
|
const binding = process.atomBinding('web_contents');
|
||||||
|
const debuggerBinding = process.atomBinding('debugger');
|
||||||
|
|
||||||
|
let slice = [].slice;
|
||||||
|
let nextId = 0;
|
||||||
|
|
||||||
|
let getNextId = function() {
|
||||||
|
return ++nextId;
|
||||||
|
};
|
||||||
|
|
||||||
|
let PDFPageSize = {
|
||||||
|
A5: {
|
||||||
|
custom_display_name: "A5",
|
||||||
|
height_microns: 210000,
|
||||||
|
name: "ISO_A5",
|
||||||
|
width_microns: 148000
|
||||||
|
},
|
||||||
|
A4: {
|
||||||
|
custom_display_name: "A4",
|
||||||
|
height_microns: 297000,
|
||||||
|
name: "ISO_A4",
|
||||||
|
is_default: "true",
|
||||||
|
width_microns: 210000
|
||||||
|
},
|
||||||
|
A3: {
|
||||||
|
custom_display_name: "A3",
|
||||||
|
height_microns: 420000,
|
||||||
|
name: "ISO_A3",
|
||||||
|
width_microns: 297000
|
||||||
|
},
|
||||||
|
Legal: {
|
||||||
|
custom_display_name: "Legal",
|
||||||
|
height_microns: 355600,
|
||||||
|
name: "NA_LEGAL",
|
||||||
|
width_microns: 215900
|
||||||
|
},
|
||||||
|
Letter: {
|
||||||
|
custom_display_name: "Letter",
|
||||||
|
height_microns: 279400,
|
||||||
|
name: "NA_LETTER",
|
||||||
|
width_microns: 215900
|
||||||
|
},
|
||||||
|
Tabloid: {
|
||||||
|
height_microns: 431800,
|
||||||
|
name: "NA_LEDGER",
|
||||||
|
width_microns: 279400,
|
||||||
|
custom_display_name: "Tabloid"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Following methods are mapped to webFrame.
|
||||||
|
const webFrameMethods = [
|
||||||
|
'executeJavaScript',
|
||||||
|
'insertText',
|
||||||
|
'setZoomFactor',
|
||||||
|
'setZoomLevel',
|
||||||
|
'setZoomLevelLimits'
|
||||||
|
];
|
||||||
|
|
||||||
|
let wrapWebContents = function(webContents) {
|
||||||
|
// webContents is an EventEmitter.
|
||||||
|
var controller, method, name, ref1;
|
||||||
|
webContents.__proto__ = EventEmitter.prototype;
|
||||||
|
|
||||||
|
// Every remote callback from renderer process would add a listenter to the
|
||||||
|
// render-view-deleted event, so ignore the listenters warning.
|
||||||
|
webContents.setMaxListeners(0);
|
||||||
|
|
||||||
|
// WebContents::send(channel, args..)
|
||||||
|
webContents.send = function() {
|
||||||
|
var args, channel;
|
||||||
|
channel = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
|
||||||
|
return this._send(channel, slice.call(args));
|
||||||
|
};
|
||||||
|
|
||||||
|
// The navigation controller.
|
||||||
|
controller = new NavigationController(webContents);
|
||||||
|
ref1 = NavigationController.prototype;
|
||||||
|
for (name in ref1) {
|
||||||
|
method = ref1[name];
|
||||||
|
if (method instanceof Function) {
|
||||||
|
(function(name, method) {
|
||||||
|
return webContents[name] = function() {
|
||||||
|
return method.apply(controller, arguments);
|
||||||
|
};
|
||||||
|
})(name, method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mapping webFrame methods.
|
||||||
|
for (let method of webFrameMethods) {
|
||||||
|
webContents[method] = function() {
|
||||||
|
let args = Array.prototype.slice.call(arguments);
|
||||||
|
this.send('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', method, args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure webContents.executeJavaScript would run the code only when the
|
||||||
|
// webContents has been loaded.
|
||||||
|
const executeJavaScript = webContents.executeJavaScript;
|
||||||
|
webContents.executeJavaScript = function(code, hasUserGesture) {
|
||||||
|
if (this.getURL() && !this.isLoading())
|
||||||
|
return executeJavaScript.call(this, code, hasUserGesture);
|
||||||
|
else
|
||||||
|
return this.once('did-finish-load', executeJavaScript.bind(this, code, hasUserGesture));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Dispatch IPC messages to the ipc module.
|
||||||
|
webContents.on('ipc-message', function(event, packed) {
|
||||||
|
var args, channel;
|
||||||
|
channel = packed[0], args = 2 <= packed.length ? slice.call(packed, 1) : [];
|
||||||
|
return ipcMain.emit.apply(ipcMain, [channel, event].concat(slice.call(args)));
|
||||||
|
});
|
||||||
|
webContents.on('ipc-message-sync', function(event, packed) {
|
||||||
|
var args, channel;
|
||||||
|
channel = packed[0], args = 2 <= packed.length ? slice.call(packed, 1) : [];
|
||||||
|
Object.defineProperty(event, 'returnValue', {
|
||||||
|
set: function(value) {
|
||||||
|
return event.sendReply(JSON.stringify(value));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ipcMain.emit.apply(ipcMain, [channel, event].concat(slice.call(args)));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle context menu action request from pepper plugin.
|
||||||
|
webContents.on('pepper-context-menu', function(event, params) {
|
||||||
|
var menu;
|
||||||
|
menu = Menu.buildFromTemplate(params.menu);
|
||||||
|
return menu.popup(params.x, params.y);
|
||||||
|
});
|
||||||
|
|
||||||
|
// This error occurs when host could not be found.
|
||||||
|
webContents.on('did-fail-provisional-load', function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
|
||||||
|
// Calling loadURL during this event might cause crash, so delay the event
|
||||||
|
// until next tick.
|
||||||
|
return setImmediate((function(_this) {
|
||||||
|
return function() {
|
||||||
|
return _this.emit.apply(_this, ['did-fail-load'].concat(slice.call(args)));
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Delays the page-title-updated event to next tick.
|
||||||
|
webContents.on('-page-title-updated', function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return setImmediate((function(_this) {
|
||||||
|
return function() {
|
||||||
|
return _this.emit.apply(_this, ['page-title-updated'].concat(slice.call(args)));
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Deprecated.
|
||||||
|
deprecate.rename(webContents, 'loadUrl', 'loadURL');
|
||||||
|
deprecate.rename(webContents, 'getUrl', 'getURL');
|
||||||
|
deprecate.event(webContents, 'page-title-set', 'page-title-updated', function() {
|
||||||
|
var args;
|
||||||
|
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
||||||
|
return this.emit.apply(this, ['page-title-set'].concat(slice.call(args)));
|
||||||
|
});
|
||||||
|
return webContents.printToPDF = function(options, callback) {
|
||||||
|
var printingSetting;
|
||||||
|
printingSetting = {
|
||||||
|
pageRage: [],
|
||||||
|
mediaSize: {},
|
||||||
|
landscape: false,
|
||||||
|
color: 2,
|
||||||
|
headerFooterEnabled: false,
|
||||||
|
marginsType: 0,
|
||||||
|
isFirstRequest: false,
|
||||||
|
requestID: getNextId(),
|
||||||
|
previewModifiable: true,
|
||||||
|
printToPDF: true,
|
||||||
|
printWithCloudPrint: false,
|
||||||
|
printWithPrivet: false,
|
||||||
|
printWithExtension: false,
|
||||||
|
deviceName: "Save as PDF",
|
||||||
|
generateDraftData: true,
|
||||||
|
fitToPageEnabled: false,
|
||||||
|
duplex: 0,
|
||||||
|
copies: 1,
|
||||||
|
collate: true,
|
||||||
|
shouldPrintBackgrounds: false,
|
||||||
|
shouldPrintSelectionOnly: false
|
||||||
|
};
|
||||||
|
if (options.landscape) {
|
||||||
|
printingSetting.landscape = options.landscape;
|
||||||
|
}
|
||||||
|
if (options.marginsType) {
|
||||||
|
printingSetting.marginsType = options.marginsType;
|
||||||
|
}
|
||||||
|
if (options.printSelectionOnly) {
|
||||||
|
printingSetting.shouldPrintSelectionOnly = options.printSelectionOnly;
|
||||||
|
}
|
||||||
|
if (options.printBackground) {
|
||||||
|
printingSetting.shouldPrintBackgrounds = options.printBackground;
|
||||||
|
}
|
||||||
|
if (options.pageSize && PDFPageSize[options.pageSize]) {
|
||||||
|
printingSetting.mediaSize = PDFPageSize[options.pageSize];
|
||||||
|
} else {
|
||||||
|
printingSetting.mediaSize = PDFPageSize['A4'];
|
||||||
|
}
|
||||||
|
return this._printToPDF(printingSetting, callback);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wrapper for native class.
|
||||||
|
let wrapDebugger = function(webContentsDebugger) {
|
||||||
|
// debugger is an EventEmitter.
|
||||||
|
webContentsDebugger.__proto__ = EventEmitter.prototype;
|
||||||
|
};
|
||||||
|
|
||||||
|
binding._setWrapWebContents(wrapWebContents);
|
||||||
|
debuggerBinding._setWrapDebugger(wrapDebugger);
|
||||||
|
|
||||||
|
module.exports.create = function(options) {
|
||||||
|
if (options == null) {
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
return binding.create(options);
|
||||||
|
};
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue