Compare commits

..

8 Commits

Author SHA1 Message Date
Cheng Zhao
037e5d7f59 Bump v0.30.8 2015-09-26 21:34:28 +08:00
Josh Abernathy
cdfb492e4f Use 0.8.0.
This picks up the fix for https://github.com/atom/atom/issues/7061.
2015-09-26 21:33:30 +08:00
Kevin Sawicki
8075600055 Touch README 2015-09-16 09:59:21 -07:00
Cheng Zhao
0824f7235b Bump v0.30.7 2015-09-24 14:01:04 +08:00
Cheng Zhao
9fca3f1973 win: Fix leaking of fd when reading file in asar 2015-09-24 14:00:53 +08:00
Indrek Ardel
83a2772a57 Fix a typo 2015-09-24 11:37:17 +08:00
Cheng Zhao
4bebfc4421 Bump v0.30.6 2015-08-26 15:46:53 +08:00
Cheng Zhao
ffa408755f mac: Do not set rounded corner by adding layer 2015-08-26 15:45:38 +08:00
2619 changed files with 65595 additions and 234359 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +0,0 @@
#!/bin/bash
set -e
mkdir -p ~/.ssh
echo "|1|B3r+7aO0/x90IdefihIjxIoJrrk=|OJddGDfhbuLFc1bUyy84hhIw57M= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|1|rGlEvW55DtzNZp+pzw9gvyOyKi4=|LLWr+7qlkAlw3YGGVfLHHxB/kR0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" >> ~/.ssh/known_hosts

View File

@@ -1,35 +0,0 @@
# Defines the Chromium style for automatic reformatting.
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
BasedOnStyle: Chromium
# This defaults to 'Auto'. Explicitly set it for a while, so that
# 'vector<vector<int> >' in existing files gets formatted to
# 'vector<vector<int>>'. ('Auto' means that clang-format will only use
# 'int>>' if the file already contains at least one such instance.)
Standard: Cpp11
# Make sure code like:
# IPC_BEGIN_MESSAGE_MAP()
# IPC_MESSAGE_HANDLER(WidgetHostViewHost_Update, OnUpdate)
# IPC_END_MESSAGE_MAP()
# gets correctly indented.
MacroBlockBegin: "^\
BEGIN_MSG_MAP|\
BEGIN_MSG_MAP_EX|\
BEGIN_SAFE_MSG_MAP_EX|\
CR_BEGIN_MSG_MAP_EX|\
IPC_BEGIN_MESSAGE_MAP|\
IPC_BEGIN_MESSAGE_MAP_WITH_PARAM|\
IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN|\
IPC_STRUCT_BEGIN|\
IPC_STRUCT_BEGIN_WITH_PARENT|\
IPC_STRUCT_TRAITS_BEGIN|\
POLPARAMS_BEGIN|\
PPAPI_BEGIN_MESSAGE_MAP$"
MacroBlockEnd: "^\
CR_END_MSG_MAP|\
END_MSG_MAP|\
IPC_END_MESSAGE_MAP|\
IPC_PROTOBUF_MESSAGE_TRAITS_END|\
IPC_STRUCT_END|\
IPC_STRUCT_TRAITS_END|\
POLPARAMS_END|\
PPAPI_END_MESSAGE_MAP$"

View File

@@ -1,3 +0,0 @@
*
!tools/xvfb-init.sh
!build/install-build-deps.sh

View File

@@ -1,7 +0,0 @@
# These env vars are only necessary for creating Electron releases.
# See docs/development/releasing.md
APPVEYOR_CLOUD_TOKEN=
CIRCLE_TOKEN=
ELECTRON_GITHUB_TOKEN=
VSTS_TOKEN=

View File

@@ -1,53 +0,0 @@
{
"extends": "standard",
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"env": {
"browser": true
},
"rules": {
"semi": ["error", "always"],
"no-var": "error",
"no-unused-vars": "off",
"no-global-assign": "off",
"guard-for-in": "error",
"@typescript-eslint/no-unused-vars": ["error", {
"vars": "all",
"args": "after-used",
"ignoreRestSiblings": true
}],
"prefer-const": ["error", {
"destructuring": "all"
}],
"standard/no-callback-literal": "off",
"node/no-deprecated-api": "off"
},
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
},
"overrides": [
{
"files": "*.js",
"rules": {
"@typescript-eslint/no-unused-vars": "off"
}
},
{
"files": "*.ts",
"rules": {
"no-undef": "off",
"no-redeclare": "off",
"@typescript-eslint/no-redeclare": ["error"],
"no-use-before-define": "off"
}
},
{
"files": "*.d.ts",
"rules": {
"no-useless-constructor": "off",
"@typescript-eslint/no-unused-vars": "off"
}
}
]
}

14
.gitattributes vendored
View File

@@ -1,14 +0,0 @@
# `git apply` and friends don't understand CRLF, even on windows. Force those
# files to be checked out with LF endings even if core.autocrlf is true.
*.patch text eol=lf
patches/**/.patches merge=union
# Source code and markdown files should always use LF as line ending.
*.cc text eol=lf
*.mm text eol=lf
*.h text eol=lf
*.js text eol=lf
*.ts text eol=lf
*.py text eol=lf
*.ps1 text eol=lf
*.md text eol=lf

21
.github/CODEOWNERS vendored
View File

@@ -1,21 +0,0 @@
# Order is important. The LAST matching pattern has the MOST precedence.
# gitignore style patterns are used, not globs.
# https://help.github.com/articles/about-codeowners
# https://git-scm.com/docs/gitignore
# Upgrades WG
/patches/ @electron/wg-upgrades
DEPS @electron/wg-upgrades
# Releases WG
/npm/ @electron/wg-releases
/script/release @electron/wg-releases
# Security WG
/lib/browser/rpc-server.ts @electron/wg-security
# Remote Change Disliker
/lib/browser/remote/ @nornagon
/lib/renderer/remote/ @nornagon
/lib/renderer/api/remote.ts @nornagon
/docs/api/remote.md @nornagon

View File

@@ -1,58 +0,0 @@
---
name: Bug report
about: Create a report to help us improve Electron
---
<!-- As an open source project with a dedicated but small maintainer team, it can sometimes take a long time for issues to be addressed so please be patient and we will get back to you as soon as we can.
-->
### Preflight Checklist
<!-- Please ensure you've completed the following steps by replacing [ ] with [x]-->
* [ ] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project.
* [ ] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to.
* [ ] I have searched the issue tracker for an issue that matches the one I want to file, without success.
### Issue Details
* **Electron Version:**
* <!-- (output of `node_modules/.bin/electron --version`) e.g. 4.0.3 -->
* **Operating System:**
* <!-- (Platform and Version) e.g. macOS 10.13.6 / Windows 10 (1803) / Ubuntu 18.04 x64 -->
* **Last Known Working Electron version:**
* <!-- (if applicable) e.g. 3.1.0 -->
### Expected Behavior
<!-- A clear and concise description of what you expected to happen. -->
### Actual Behavior
<!-- A clear and concise description of what actually happened. -->
### To Reproduce
<!--
Your best chance of getting this bug looked at quickly is to provide an example.
-->
<!--
For bugs that can be encapsulated in a small experiment, you can use Electron Fiddle (https://github.com/electron/fiddle) to publish your example to a GitHub Gist and link it your bug report.
-->
<!--
If Fiddle is insufficient to produce an example, please provide an example REPOSITORY that can be cloned and run. You can fork electron-quick-start (https://github.com/electron/electron-quick-start) and include a link to the branch with your changes.
-->
<!--
If you provide a URL, please list the commands required to clone/setup/run your repo e.g.
```sh
$ git clone $YOUR_URL -b $BRANCH
$ npm install
$ npm start || electron .
```
-->
### Screenshots
<!-- If applicable, add screenshots to help explain your problem. -->
### Additional Information
<!-- Add any other context about the problem here. -->

View File

@@ -1,27 +0,0 @@
---
name: Feature request
about: Suggest an idea for Electron
---
<!-- As an open source project with a dedicated but small maintainer team, it can sometimes take a long time for issues to be addressed so please be patient and we will get back to you as soon as we can.
-->
### Preflight Checklist
<!-- Please ensure you've completed the following steps by replacing [ ] with [x]-->
* [ ] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project.
* [ ] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to.
* [ ] I have searched the issue tracker for a feature request that matches the one I want to file, without success.
### Problem Description
<!-- Is your feature request related to a problem? Please add a clear and concise description of what the problem is. -->
### Proposed Solution
<!-- Describe the solution you'd like in a clear and concise manner -->
### Alternatives Considered
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
### Additional Information
<!-- Add any other context about the problem here. -->

View File

@@ -1,25 +0,0 @@
---
name: Mac App Store Private API Rejection
about: Your app was rejected from the Mac App Store for using private API's
---
<!-- As an open source project with a dedicated but small maintainer team, it can sometimes take a long time for issues to be addressed so please be patient and we will get back to you as soon as we can.
-->
### Preflight Checklist
<!-- Please ensure you've completed the following steps by replacing [ ] with [x]-->
* [ ] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project.
* [ ] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to.
### Issue Details
* **Electron Version:**
* <!-- (output of `node_modules/.bin/electron --version`) e.g. 4.0.3 -->
### Rejection Email
<!-- Paste the contents of your rejection email here, censoring any private information such as app names.-->
### Additional Information
<!-- Add any other context about the problem here. -->

View File

@@ -1,20 +0,0 @@
#### Description of Change
<!--
Thank you for your Pull Request. Please provide a description above and review
the requirements below.
Contributors guide: https://github.com/electron/electron/blob/master/CONTRIBUTING.md
-->
#### Checklist
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->
- [ ] PR description included and stakeholders cc'd
- [ ] `npm test` passes
- [ ] tests are [changed or added](https://github.com/electron/electron/blob/master/docs/development/testing.md)
- [ ] relevant documentation is changed or added
- [ ] [PR release notes](https://github.com/electron/clerk/blob/master/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/master/README.md#examples).
#### Release Notes
Notes: <!-- Please add a one-line description for app developers to read in the release notes, or 'none' if no notes relevant to app developers. Examples and help on special cases: https://github.com/electron/clerk/blob/master/README.md#examples -->

40
.github/config.yml vendored
View File

@@ -1,40 +0,0 @@
# Comment to be posted to on PRs from first time contributors in your repository
newPRWelcomeComment: |
💖 Thanks for opening this pull request! 💖
We use [semantic commit messages](https://github.com/electron/electron/blob/master/docs/development/pull-requests.md#commit-message-guidelines) to streamline the release process. Before your pull request can be merged, you should **update your pull request title** to start with a semantic prefix.
Examples of commit messages with semantic prefixes:
- `fix: don't overwrite prevent_default if default wasn't prevented`
- `feat: add app.isPackaged() method`
- `docs: app.isDefaultProtocolClient is now available on Linux`
Things that will help get your PR across the finish line:
- Follow the JavaScript, C++, and Python [coding style](https://github.com/electron/electron/blob/master/docs/development/coding-style.md).
- Run `npm run lint` locally to catch formatting errors earlier.
- Document any user-facing changes you've made following the [documentation styleguide](https://github.com/electron/electron/blob/master/docs/styleguide.md).
- Include tests when adding/changing behavior.
- Include screenshots and animated GIFs whenever possible.
We get a lot of pull requests on this repo, so please be patient and we will get back to you as soon as we can.
# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge
# Comment to be posted to on pull requests merged by a first time user
firstPRMergeComment: >
Congrats on merging your first pull request! 🎉🎉🎉
# Users authorized to run manual trop backports
authorizedUsers:
- alexeykuzmin
- ckerr
- codebytere
- deepak1556
- jkleinsc
- loc
- MarshallOfSound
- miniak
- nornagon
- zcbenz

78
.gitignore vendored
View File

@@ -1,71 +1,19 @@
.DS_Store
.env
.gclient_done
**/.npmrc
.tags*
.vs/
.vscode/
*.log
*.pyc
*.sln
*.swp
*.VC.db
*.VC.VC.opendb
*.vcxproj
*.vcxproj.filters
*.vcxproj.user
*.xcodeproj
/.idea/
/build/
/dist/
/external_binaries/
/out/
/vendor/.gclient
/vendor/debian_jessie_mips64-sysroot/
/vendor/debian_stretch_amd64-sysroot/
/vendor/debian_stretch_arm-sysroot/
/vendor/debian_stretch_arm64-sysroot/
/vendor/debian_stretch_i386-sysroot/
/vendor/gcc-4.8.3-d197-n64-loongson/
/vendor/readme-gcc483-loongson.txt
/vendor/download/
/vendor/llvm-build/
/vendor/llvm/
/vendor/npm/
/vendor/brightray/vendor/download/
/vendor/debian_wheezy_arm-sysroot/
/vendor/debian_wheezy_i386-sysroot/
/vendor/python_26/
/vendor/native_mksnapshot
/vendor/LICENSES.chromium.html
/vendor/pyyaml
/vendor/npm/
/vendor/llvm/
/vendor/llvm-build/
/vendor/.gclient
node_modules/
SHASUMS256.txt
**/package-lock.json
compile_commands.json
.envrc
# npm package
/npm/dist
/npm/path.txt
.npmrc
# Generated API definitions
electron-api.json
electron.d.ts
# Spec hash calculation
spec/.hash
# Eslint Cache
.eslintcache
# Generated native addon files
/spec-main/fixtures/native-addon/echo/build/
# If someone runs tsc this is where stuff will end up
ts-gen
# Used to accelerate CI builds
.depshash
.depshash-target
# Used to accelerate builds after sync
patches/mtime-cache.json
*.xcodeproj
*.swp
*.pyc
debug.log
npm-debug.log

18
.gitmodules vendored
View File

@@ -1,3 +1,21 @@
[submodule "vendor/brightray"]
path = vendor/brightray
url = https://github.com/atom/brightray.git
[submodule "vendor/node"]
path = vendor/node
url = https://github.com/atom/node.git
[submodule "vendor/depot_tools"]
path = vendor/depot_tools
url = https://chromium.googlesource.com/chromium/tools/depot_tools.git
[submodule "vendor/breakpad"]
path = vendor/breakpad
url = https://github.com/atom/chromium-breakpad.git
[submodule "vendor/native_mate"]
path = vendor/native_mate
url = https://github.com/zcbenz/native-mate.git
[submodule "vendor/crashpad"]
path = vendor/crashpad
url = https://github.com/atom/crashpad.git
[submodule "vendor/requests"]
path = vendor/requests
url = https://github.com/kennethreitz/requests

View File

@@ -1,6 +0,0 @@
{
"plugins": [
["remark-lint-code-block-style", "fenced"],
["remark-lint-fenced-code-flag"]
]
}

28
.travis.yml Normal file
View File

@@ -0,0 +1,28 @@
git:
depth: 10
notifications:
email: false
language: cpp
compiler: clang
os:
- linux
- osx
env:
- TARGET_ARCH=x64
matrix:
include:
- os: linux
env: TARGET_ARCH=arm
- os: linux
env: TARGET_ARCH=ia32
allow_failures:
- env: TARGET_ARCH=arm
- env: TARGET_ARCH=ia32
script: './script/cibuild'
branches:
only:
- master

1385
BUILD.gn

File diff suppressed because it is too large Load Diff

View File

@@ -1,135 +0,0 @@
# Code of Conduct
As a member project of the OpenJS Foundation, Electron uses [Contributor Covenant v2.0](https://contributor-covenant.org/version/2/0/code_of_conduct) as their code of conduct. The full text is included [below](#contributor-covenant-code-of-conduct) in English, and translations are available from the Contributor Covenant organisation:
- [contributor-covenant.org/translations](https://www.contributor-covenant.org/translations)
- [github.com/ContributorCovenant](https://github.com/ContributorCovenant/contributor_covenant/tree/release/content/version/2/0)
## Contributor Covenant Code of Conduct
### Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
### Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
### Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders 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, and will communicate reasons for moderation
decisions when appropriate.
### Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
### Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[coc@electronjs.org](mailto:coc@electronjs.org).
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
### Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
#### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
#### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
#### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
#### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
### Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@@ -2,69 +2,73 @@
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
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 coc@electronjs.org.
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0).
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.
These are just guidelines, not rules, use your best judgment and feel free to
propose changes to this document in a pull request.
## [Issues](https://electronjs.org/docs/development/issues)
## Submitting Issues
Issues are created [here](https://github.com/electron/electron/issues/new).
* You can create an issue [here](https://github.com/atom/electron/issues/new),
but before doing that please read the notes below and include as many details as
possible with your report. If you can, please include:
* The version of Electron you are using
* The operating system you are using
* If applicable, what you were doing when the issue arose and what you
expected to happen
* Other things that will help resolve your issue:
* Screenshots and animated GIFs
* Error output that appears in your terminal, dev tools or as an alert
* Perform a [cursory search](https://github.com/atom/electron/issues?utf8=✓&q=is%3Aissue+)
to see if a similar issue has already been submitted
* [How to Contribute in Issues](https://electronjs.org/docs/development/issues#how-to-contribute-in-issues)
* [Asking for General Help](https://electronjs.org/docs/development/issues#asking-for-general-help)
* [Submitting a Bug Report](https://electronjs.org/docs/development/issues#submitting-a-bug-report)
* [Triaging a Bug Report](https://electronjs.org/docs/development/issues#triaging-a-bug-report)
* [Resolving a Bug Report](https://electronjs.org/docs/development/issues#resolving-a-bug-report)
## Submitting Pull Requests
### Issue Closure
* 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).
* Write documentation in [Markdown](https://daringfireball.net/projects/markdown).
* Use short, present tense commit messages. See [Commit Message Styleguide](#git-commit-messages-styleguide).
Bug reports will be closed if the issue has been inactive and the latest affected version no longer receives support. At the moment, Electron maintains its three latest major versions, with a new major version being released every 12 weeks. (For more information on Electron's release cadence, see [this blog post](https://electronjs.org/blog/12-week-cadence).)
## Styleguides
_If an issue has been closed and you still feel it's relevant, feel free to ping a maintainer or add a comment!_
### General Code
### Languages
* End files with a newline.
* Place requires in the following order:
* Built in Node Modules (such as `path`)
* Built in Electron Modules (such as `ipc`, `app`)
* Local Modules (using relative paths)
* Place class properties in the following order:
* Class methods and properties (methods starting with a `@`)
* Instance methods and properties
* Avoid platform-dependent code:
* Use `path.join()` to concatenate filenames.
* Use `os.tmpdir()` rather than `/tmp` when you need to reference the
temporary directory.
* Using a plain `return` when returning explicitly at the end of a function.
* Not `return null`, `return undefined`, `null`, or `undefined`
We accept issues in *any* language.
When an issue is posted in a language besides English, it is acceptable and encouraged to post an English-translated copy as a reply.
Anyone may post the translated reply.
In most cases, a quick pass through translation software is sufficient.
Having the original text _as well as_ the translation can help mitigate translation errors.
### Git Commit Messages
Responses to posted issues may or may not be in the original language.
**Please note** that using non-English as an attempt to circumvent our [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) will be an immediate, and possibly indefinite, ban from the project.
## [Pull Requests](https://electronjs.org/docs/development/pull-requests)
Pull Requests are the way concrete changes are made to the code, documentation,
dependencies, and tools contained in the `electron/electron` repository.
* [Setting up your local environment](https://electronjs.org/docs/development/pull-requests#setting-up-your-local-environment)
* [Step 1: Fork](https://electronjs.org/docs/development/pull-requests#step-1-fork)
* [Step 2: Build](https://electronjs.org/docs/development/pull-requests#step-2-build)
* [Step 3: Branch](https://electronjs.org/docs/development/pull-requests#step-3-branch)
* [Making Changes](https://electronjs.org/docs/development/pull-requests#making-changes)
* [Step 4: Code](https://electronjs.org/docs/development/pull-requests#step-4-code)
* [Step 5: Commit](https://electronjs.org/docs/development/pull-requests#step-5-commit)
* [Commit message guidelines](https://electronjs.org/docs/development/pull-requests#commit-message-guidelines)
* [Step 6: Rebase](https://electronjs.org/docs/development/pull-requests#step-6-rebase)
* [Step 7: Test](https://electronjs.org/docs/development/pull-requests#step-7-test)
* [Step 8: Push](https://electronjs.org/docs/development/pull-requests#step-8-push)
* [Step 9: Opening the Pull Request](https://electronjs.org/docs/development/pull-requests#step-9-opening-the-pull-request)
* [Step 10: Discuss and Update](https://electronjs.org/docs/development/pull-requests#step-10-discuss-and-update)
* [Approval and Request Changes Workflow](https://electronjs.org/docs/development/pull-requests#approval-and-request-changes-workflow)
* [Step 11: Landing](https://electronjs.org/docs/development/pull-requests#step-11-landing)
* [Continuous Integration Testing](https://electronjs.org/docs/development/pull-requests#continuous-integration-testing)
## Style Guides
See [Coding Style](https://electronjs.org/docs/development/coding-style) for information about which standards Electron adheres to in different parts of its codebase.
## Further Reading
For more in-depth guides on developing Electron, see
[/docs/development](/docs/development/README.md)
* Use the present tense ("Add feature" not "Added feature")
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
* Limit the first line to 72 characters or less
* Reference issues and pull requests liberally
* Consider starting the commit message with an applicable emoji:
* :art: `:art:` when improving the format/structure of the code
* :racehorse: `:racehorse:` when improving performance
* :non-potable_water: `:non-potable_water:` when plugging memory leaks
* :memo: `:memo:` when writing docs
* :penguin: `:penguin:` when fixing something on Linux
* :apple: `:apple:` when fixing something on Mac OS
* :checkered_flag: `:checkered_flag:` when fixing something on Windows
* :bug: `:bug:` when fixing a bug
* :fire: `:fire:` when removing code or files
* :green_heart: `:green_heart:` when fixing the CI build
* :white_check_mark: `:white_check_mark:` when adding tests
* :lock: `:lock:` when dealing with security
* :arrow_up: `:arrow_up:` when upgrading dependencies
* :arrow_down: `:arrow_down:` when downgrading dependencies
* :shirt: `:shirt:` when removing linter warnings

193
DEPS
View File

@@ -1,193 +0,0 @@
gclient_gn_args_file = 'src/build/config/gclient_args.gni'
gclient_gn_args = [
'build_with_chromium',
'checkout_android',
'checkout_android_native_support',
'checkout_libaom',
'checkout_nacl',
'checkout_pgo_profiles',
'checkout_oculus_sdk',
'checkout_openxr',
'checkout_google_benchmark',
'mac_xcode_version',
]
vars = {
'chromium_version':
'2a55c4f55b99b2191ea59cba1e2f6da4dbb7dee0',
'node_version':
'v14.15.0',
'nan_version':
'2c4ee8a32a299eada3cd6e468bbd0a473bfea96d',
'squirrel.mac_version':
'a3a5b3f03b824441c014893b18f99a103b2603e9',
'pyyaml_version': '3.12',
'requests_version': 'e4d59bedfd3c7f4f254f4f5d036587bcd8152458',
'chromium_git': 'https://chromium.googlesource.com',
'electron_git': 'https://github.com/electron',
'nodejs_git': 'https://github.com/nodejs',
'requests_git': 'https://github.com/kennethreitz',
'yaml_git': 'https://github.com/yaml',
'squirrel_git': 'https://github.com/Squirrel',
# KEEP IN SYNC WITH utils.js FILE
'yarn_version': '1.15.2',
# To be able to build clean Chromium from sources.
'apply_patches': True,
# To use an mtime cache for patched files to speed up builds.
'use_mtime_cache': True,
# To allow in-house builds to checkout those manually.
'checkout_chromium': True,
'checkout_node': True,
'checkout_nan': True,
'checkout_pgo_profiles': True,
# It's only needed to parse the native tests configurations.
'checkout_pyyaml': False,
# Python "requests" module is used for releases only.
'checkout_requests': False,
'mac_xcode_version': 'default',
# To allow running hooks without parsing the DEPS tree
'process_deps': True,
# It is always needed for normal Electron builds,
# but might be impossible for custom in-house builds.
'download_external_binaries': True,
'checkout_nacl':
False,
'checkout_libaom':
True,
'checkout_oculus_sdk':
False,
'checkout_openxr':
False,
'build_with_chromium':
True,
'checkout_android':
False,
'checkout_android_native_support':
False,
'checkout_google_benchmark':
False,
'checkout_clang_tidy':
True,
}
deps = {
'src': {
'url': (Var("chromium_git")) + '/chromium/src.git@' + (Var("chromium_version")),
'condition': 'checkout_chromium and process_deps',
},
'src/third_party/nan': {
'url': (Var("nodejs_git")) + '/nan.git@' + (Var("nan_version")),
'condition': 'checkout_nan and process_deps',
},
'src/third_party/electron_node': {
'url': (Var("nodejs_git")) + '/node.git@' + (Var("node_version")),
'condition': 'checkout_node and process_deps',
},
'src/electron/vendor/pyyaml': {
'url': (Var("yaml_git")) + '/pyyaml.git@' + (Var("pyyaml_version")),
'condition': 'checkout_pyyaml and process_deps',
},
'src/electron/vendor/requests': {
'url': Var('requests_git') + '/requests.git' + '@' + Var('requests_version'),
'condition': 'checkout_requests and process_deps',
},
'src/third_party/squirrel.mac': {
'url': Var("squirrel_git") + '/Squirrel.Mac.git@' + Var("squirrel.mac_version"),
'condition': 'process_deps',
},
'src/third_party/squirrel.mac/vendor/ReactiveObjC': {
'url': 'https://github.com/ReactiveCocoa/ReactiveObjC.git@74ab5baccc6f7202c8ac69a8d1e152c29dc1ea76',
'condition': 'process_deps'
},
'src/third_party/squirrel.mac/vendor/Mantle': {
'url': 'https://github.com/Mantle/Mantle.git@78d3966b3c331292ea29ec38661b25df0a245948',
'condition': 'process_deps',
}
}
pre_deps_hooks = [
{
'name': 'generate_mtime_cache',
'condition': '(checkout_chromium and apply_patches and use_mtime_cache) and process_deps',
'pattern': 'src/electron',
'action': [
'python3',
'src/electron/script/patches-mtime-cache.py',
'generate',
'--cache-file',
'src/electron/patches/mtime-cache.json',
'--patches-config',
'src/electron/patches/config.json',
],
},
]
hooks = [
{
'name': 'patch_chromium',
'condition': '(checkout_chromium and apply_patches) and process_deps',
'pattern': 'src/electron',
'action': [
'python3',
'src/electron/script/apply_all_patches.py',
'src/electron/patches/config.json',
],
},
{
'name': 'apply_mtime_cache',
'condition': '(checkout_chromium and apply_patches and use_mtime_cache) and process_deps',
'pattern': 'src/electron',
'action': [
'python3',
'src/electron/script/patches-mtime-cache.py',
'apply',
'--cache-file',
'src/electron/patches/mtime-cache.json',
],
},
{
'name': 'electron_external_binaries',
'pattern': 'src/electron/script/update-external-binaries.py',
'condition': 'download_external_binaries',
'action': [
'python3',
'src/electron/script/update-external-binaries.py',
],
},
{
'name': 'electron_npm_deps',
'pattern': 'src/electron/package.json',
'action': [
'python3',
'-c',
'import os, subprocess; os.chdir(os.path.join("src", "electron")); subprocess.check_call(["python", "script/lib/npx.py", "yarn@' + (Var("yarn_version")) + '", "install", "--frozen-lockfile"]);',
],
},
{
'name': 'setup_requests',
'pattern': 'src/electron',
'condition': 'checkout_requests and process_deps',
'action': [
'python3',
'-c',
'import os, subprocess; os.chdir(os.path.join("src", "electron", "vendor", "requests")); subprocess.check_call(["python", "setup.py", "build"]);',
],
},
]
recursedeps = [
'src',
'src/third_party/squirrel.mac',
]

View File

@@ -1 +0,0 @@
12.0.0-nightly.20201110

View File

@@ -1,4 +1,4 @@
Copyright (c) 2013-2020 GitHub Inc.
Copyright (c) 2014 GitHub Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

44
README-ko.md Normal file
View File

@@ -0,0 +1,44 @@
[![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)
[![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/) 한국어 참조문서
:zap: *이전까지 Atom Shell로 알려져 있었습니다* :zap:
Electron은 JavaScript, HTML 그리고 CSS를 이용하여 Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주는 프레임워크입니다. 이 프레임워크는 [io.js](http://iojs.org) 와
[Chromium](http://www.chromium.org) 을 기반으로 만들어 졌으며 [Atom Editor](https://github.com/atom/atom) 에 사용되고 있습니다.
Electron에 대한 중요한 알림을 받으려면 Twitter에서 [@ElectronJS](https://twitter.com/electronjs)를 Follow하세요.
## 다운로드
Linux, Windows, Mac용으로 미리 빌드된 Electron 바이너리와 디버그 심볼이 준비되어 있습니다. [releases](https://github.com/atom/electron/releases) 페이지에서 받아 볼 수 있습니다.
또한 [`npm`](https://docs.npmjs.com/)을 이용하여 미리 빌드된 Electron 바이너리를 받을 수 있습니다:
```sh
# $PATH에 `electron`을 등록하고 전역에 설치합니다.
npm install electron-prebuilt -g
# 개발용 dependency로 설치합니다.
npm install electron-prebuilt --save-dev
```
### 미러
- [China](https://npm.taobao.org/mirrors/electron)
## 참조문서
[docs](https://github.com/atom/electron/tree/master/docs/README-ko.md) 에 프레임워크 사용 가이드와 API 레퍼런스가 있습니다.
추가적으로 Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법이 문서에 포함되어 있으니 참고하시기 바랍니다.
## 커뮤니티
[Atom 포럼내의 `electron` 카테고리](http://discuss.atom.io/category/electron) 와 Freenode `#atom-shell` 채팅채널이 있습니다.
[awesome-electron](https://github.com/sindresorhus/awesome-electron) 에 커뮤니티가 운영중인 유용한 예제 앱과 툴, 리소스가 있으니 한번 탐색해 보시기 바랍니다.

112
README.md
View File

@@ -1,108 +1,52 @@
[![Electron Logo](https://electronjs.org/images/electron-logo.svg)](https://electronjs.org)
[![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)
[![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/)
[![CircleCI Build Status](https://circleci.com/gh/electron/electron/tree/master.svg?style=shield)](https://circleci.com/gh/electron/electron/tree/master)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/4lggi9dpjc1qob7k/branch/master?svg=true)](https://ci.appveyor.com/project/electron-bot/electron-ljo26/branch/master)
[![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron?type=dev)
[![Electron Discord Invite](https://img.shields.io/discord/745037351163527189?color=%237289DA&label=chat&logo=discord&logoColor=white)](https://discord.com/invite/electron)
:memo: Available Translations: 🇨🇳 🇹🇼 🇧🇷 🇪🇸 🇰🇷 🇯🇵 🇷🇺 🇫🇷 🇹🇭 🇳🇱 🇹🇷 🇮🇩 🇺🇦 🇨🇿 🇮🇹 🇵🇱.
View these docs in other languages at [electron/i18n](https://github.com/electron/i18n/tree/master/content/).
:zap: *formerly known as Atom Shell* :zap:
The Electron framework lets you write cross-platform desktop applications
using JavaScript, HTML and CSS. It is based on [Node.js](https://nodejs.org/) and
[Chromium](https://www.chromium.org) and is used by the [Atom
editor](https://github.com/atom/atom) and many other [apps](https://electronjs.org/apps).
using JavaScript, HTML and CSS. It is based on [io.js](http://iojs.org) and
[Chromium](http://www.chromium.org) and is used in the [Atom
editor](https://github.com/atom/atom).
Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important
announcements.
This project adheres to the Contributor Covenant
[code of conduct](https://github.com/electron/electron/tree/master/CODE_OF_CONDUCT.md).
By participating, you are expected to uphold this code. Please report unacceptable
behavior to [coc@electronjs.org](mailto:coc@electronjs.org).
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0).
By participating, you are expected to uphold this code. Please report unacceptable behavior to atom@github.com.
## Installation
## Downloads
To install prebuilt Electron binaries, use [`npm`](https://docs.npmjs.com/).
The preferred method is to install Electron as a development dependency in your
app:
Prebuilt binaries and debug symbols of Electron for Linux, Windows and Mac can
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
binaries:
```sh
npm install electron --save-dev [--save-exact]
```
# Install the `electron` command globally in your $PATH
npm install electron-prebuilt -g
The `--save-exact` flag is recommended for Electron prior to version 2, as it does not follow semantic
versioning. As of version 2.0.0, Electron follows semver, so you don't need `--save-exact` flag. For info on how to manage Electron versions in your apps, see
[Electron versioning](docs/tutorial/electron-versioning.md).
For more installation options and troubleshooting tips, see
[installation](docs/tutorial/installation.md).
## Quick start & Electron Fiddle
Use [`Electron Fiddle`](https://github.com/electron/fiddle)
to build, run, and package small Electron experiments, to see code examples for all of Electron's APIs, and
to try out different versions of Electron. It's designed to make the start of your journey with
Electron easier.
Alternatively, clone and run the
[electron/electron-quick-start](https://github.com/electron/electron-quick-start)
repository to see a minimal Electron app in action:
```sh
git clone https://github.com/electron/electron-quick-start
cd electron-quick-start
npm install
npm start
```
## Resources for learning Electron
- [electronjs.org/docs](https://electronjs.org/docs) - All of Electron's documentation
- [electron/fiddle](https://github.com/electron/fiddle) - A tool to build, run, and package small Electron experiments
- [electron/electron-quick-start](https://github.com/electron/electron-quick-start) - A very basic starter Electron app
- [electronjs.org/community#boilerplates](https://electronjs.org/community#boilerplates) - Sample starter apps created by the community
- [electron/simple-samples](https://github.com/electron/simple-samples) - Small applications with ideas for taking them further
- [electron/electron-api-demos](https://github.com/electron/electron-api-demos) - An Electron app that teaches you how to use Electron
- [hokein/electron-sample-apps](https://github.com/hokein/electron-sample-apps) - Small demo apps for the various Electron APIs
## Programmatic usage
Most people use Electron from the command line, but if you require `electron` inside
your **Node app** (not your Electron app) it will return the file path to the
binary. Use this to spawn Electron from Node scripts:
```javascript
const electron = require('electron')
const proc = require('child_process')
// will print something similar to /Users/maf/.../Electron
console.log(electron)
// spawn Electron
const child = proc.spawn(electron)
# Install as a development dependency
npm install electron-prebuilt --save-dev
```
### Mirrors
- [China](https://npm.taobao.org/mirrors/electron)
## Documentation Translations
## Documentation
Find documentation translations in [electron/i18n](https://github.com/electron/i18n).
## Contributing
If you are interested in reporting/fixing issues and contributing directly to the code base, please see [CONTRIBUTING.md](CONTRIBUTING.md) for more information on what we're looking for and how to get started.
Guides and the API reference are located in the
[docs](https://github.com/atom/electron/tree/master/docs) directory. It also
contains documents describing how to build and contribute to Electron.
## Community
Info on reporting bugs, getting help, finding third-party tools and sample apps,
and more can be found in the [support document](docs/tutorial/support.md#finding-support).
There is an [`electron` category on the Atom forums](http://discuss.atom.io/category/electron)
as well as an `#atom-shell` channel on Freenode.
## License
[MIT](https://github.com/electron/electron/blob/master/LICENSE)
When using the Electron or other GitHub logos, be sure to follow the [GitHub logo guidelines](https://github.com/logos).
Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron)
for a community maintained list of useful example apps, tools and resources.

View File

@@ -1,16 +0,0 @@
# Reporting Security Issues
The Electron team and community take security bugs in Electron seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
To report a security issue, email [security@electronjs.org](mailto:security@electronjs.org) and include the word "SECURITY" in the subject line.
The Electron team will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.
Report security bugs in third-party modules to the person or team maintaining the module. You can also report a vulnerability through the [npm contact form](https://www.npmjs.com/support) by selecting "I'm reporting a security vulnerability".
## The Electron Security Notification Process
For context on Electron's security notification process, please see the [Notifications](https://github.com/electron/governance/blob/master/wg-security/membership-and-notifications.md#notifications) section of the Security WG's [Membership and Notifications](https://github.com/electron/governance/blob/master/wg-security/membership-and-notifications.md) Governance document.
## Learning More About Security
To learn more about securing an Electron application, please see the [security tutorial](docs/tutorial/security.md).

View File

@@ -1,236 +0,0 @@
# The config expects the following environment variables to be set:
# - "GN_CONFIG" Build type. One of {'testing', 'release'}.
# - "GN_EXTRA_ARGS" Additional gn arguments for a build config,
# e.g. 'target_cpu="x86"' to build for a 32bit platform.
# https://gn.googlesource.com/gn/+/master/docs/reference.md#target_cpu
# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordningly
# if you pass a custom value for 'target_cpu'.
# - "ELECTRON_RELEASE" Set it to '1' upload binaries on success.
# - "NPM_CONFIG_ARCH" E.g. 'x86'. Is used to build native Node.js modules.
# Must match 'target_cpu' passed to "GN_EXTRA_ARGS" and "TARGET_ARCH" value.
# - "TARGET_ARCH" Choose from {'ia32', 'x64', 'arm', 'arm64', 'mips64el'}.
# Is used in some publishing scripts, but does NOT affect the Electron binary.
# Must match 'target_cpu' passed to "GN_EXTRA_ARGS" and "NPM_CONFIG_ARCH" value.
# - "UPLOAD_TO_S3" Set it to '1' upload a release to the S3 bucket.
# Otherwise the release will be uploaded to the Github Releases.
# (The value is only checked if "ELECTRON_RELEASE" is defined.)
#
# The publishing scripts expect access tokens to be defined as env vars,
# but those are not covered here.
#
# AppVeyor docs on variables:
# https://www.appveyor.com/docs/environment-variables/
# https://www.appveyor.com/docs/build-configuration/#secure-variables
# https://www.appveyor.com/docs/build-configuration/#custom-environment-variables
# Uncomment these lines to enable RDP
#on_finish:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
version: 1.0.{build}
build_cloud: electron-16-core
image: vs2019bt-16.6.2
environment:
GIT_CACHE_PATH: C:\Users\electron\libcc_cache
ELECTRON_OUT_DIR: Default
ELECTRON_ENABLE_STACK_DUMPING: 1
MOCHA_REPORTER: mocha-multi-reporters
MOCHA_MULTI_REPORTERS: mocha-appveyor-reporter, tap
notifications:
- provider: Webhook
url: https://electron-mission-control.herokuapp.com/rest/appveyor-hook
method: POST
headers:
x-mission-control-secret:
secure: 90BLVPcqhJPG7d24v0q/RRray6W3wDQ8uVQlQjOHaBWkw1i8FoA1lsjr2C/v1dVok+tS2Pi6KxDctPUkwIb4T27u4RhvmcPzQhVpfwVJAG9oNtq+yKN7vzHfg7k/pojEzVdJpQLzeJGcSrZu7VY39Q==
on_build_success: false
on_build_failure: true
on_build_status_changed: false
build_script:
- ps: >-
if(($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME -split "/")[0] -eq ($env:APPVEYOR_REPO_NAME -split "/")[0]) {
Write-warning "Skipping PR build for branch"; Exit-AppveyorBuild
} else {
node script/yarn.js install --frozen-lockfile
$result = node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH
Write-Output $result
if ($result.ExitCode -eq 0) {
Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild
}
}
- echo "Building $env:GN_CONFIG build"
- git config --global core.longpaths true
- cd ..
- mkdir src
- update_depot_tools.bat
- ps: Move-Item $env:APPVEYOR_BUILD_FOLDER -Destination src\electron
- ps: $env:CHROMIUM_BUILDTOOLS_PATH="$pwd\src\buildtools"
- ps: >-
if ($env:GN_CONFIG -eq 'release') {
$env:GCLIENT_EXTRA_ARGS="$env:GCLIENT_EXTRA_ARGS --custom-var=checkout_requests=True"
} else {
$env:NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] "
}
- >-
gclient config
--name "src\electron"
--unmanaged
%GCLIENT_EXTRA_ARGS%
"https://github.com/electron/electron"
- ps: >-
if ($env:GN_CONFIG -eq 'release') {
$env:RUN_GCLIENT_SYNC="true"
} else {
cd src\electron
node script\generate-deps-hash.js
$depshash = Get-Content .\.depshash -Raw
$zipfile = "Z:\$depshash.7z"
cd ..\..
if (Test-Path -Path $zipfile) {
# file exists, unzip and then gclient sync
7z x -y $zipfile -mmt=30 -aoa
if (-not (Test-Path -Path "src\buildtools")) {
# the zip file must be corrupt - resync
$env:RUN_GCLIENT_SYNC="true"
if ($env:TARGET_ARCH -ne 'ia32') {
# only save on x64/woa to avoid contention saving
$env:SAVE_GCLIENT_SRC="true"
}
} else {
# update external binaries
python src/electron/script/update-external-binaries.py
# update angle
cd src\third_party\angle
git remote set-url origin https://chromium.googlesource.com/angle/angle.git
git fetch
cd ..\..\..
}
} else {
# file does not exist, gclient sync, then zip
$env:RUN_GCLIENT_SYNC="true"
if ($env:TARGET_ARCH -ne 'ia32') {
# only save on x64/woa to avoid contention saving
$env:SAVE_GCLIENT_SRC="true"
}
}
}
- if "%RUN_GCLIENT_SYNC%"=="true" ( gclient sync --with_branch_heads --with_tags --ignore_locks)
- ps: >-
if ($env:SAVE_GCLIENT_SRC -eq 'true') {
# archive current source for future use
# only run on x64/woa to avoid contention saving
$(7z a $zipfile src -xr!android_webview -xr!electron -xr'!*\.git' -xr!third_party\WebKit\LayoutTests! -xr!third_party\blink\web_tests -xr!third_party\blink\perf_tests -slp -t7z -mmt=30)
if ($LASTEXITCODE -ne 0) {
Write-warning "Could not save source to shared drive; continuing anyway"
}
# build time generation of file gen/angle/angle_commit.h depends on
# third_party/angle/.git
# https://chromium-review.googlesource.com/c/angle/angle/+/2074924
$(7z a $zipfile src\third_party\angle\.git)
if ($LASTEXITCODE -ne 0) {
Write-warning "Failed to add third_party\angle\.git; continuing anyway"
}
}
- ps: >-
if (Test-Path 'env:RAW_GOMA_AUTH') {
$env:GOMA_OAUTH2_CONFIG_FILE = "$pwd\.goma_oauth2_config"
$env:RAW_GOMA_AUTH | Set-Content $env:GOMA_OAUTH2_CONFIG_FILE
}
- git clone https://github.com/electron/build-tools.git
- cd build-tools
- npm install
- mkdir third_party
- node -e "require('./src/utils/goma.js').downloadAndPrepare()"
- ps: $env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)"
- ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)"
- cd ..
- ps: .\src\electron\script\start-goma.ps1 -gomaDir $env:LOCAL_GOMA_DIR
- cd src
- set BUILD_CONFIG_PATH=//electron/build/args/%GN_CONFIG%.gn
- gn gen out/Default "--args=import(\"%BUILD_CONFIG_PATH%\") import(\"%GN_GOMA_FILE%\") %GN_EXTRA_ARGS% "
- gn check out/Default //electron:electron_lib
- gn check out/Default //electron:electron_app
- gn check out/Default //electron:manifests
- gn check out/Default //electron/shell/common/api:mojo
- if DEFINED GN_GOMA_FILE (ninja -j 300 -C out/Default electron:electron_app) else (ninja -C out/Default electron:electron_app)
- if "%GN_CONFIG%"=="testing" ( python C:\depot_tools\post_build_ninja_summary.py -C out\Default )
- gn gen out/ffmpeg "--args=import(\"//electron/build/args/ffmpeg.gn\") %GN_EXTRA_ARGS%"
- ninja -C out/ffmpeg electron:electron_ffmpeg_zip
- ninja -C out/Default electron:electron_dist_zip
- ninja -C out/Default shell_browser_ui_unittests
- gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args
- ninja -C out/Default electron:electron_mksnapshot_zip
- cd out\Default
- 7z a mksnapshot.zip mksnapshot_args gen\v8\embedded.S
- cd ..\..
- ninja -C out/Default electron:hunspell_dictionaries_zip
- ninja -C out/Default electron:electron_chromedriver_zip
- ninja -C out/Default third_party/electron_node:headers
- python %LOCAL_GOMA_DIR%\goma_ctl.py stat
- python electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json
- appveyor PushArtifact out/Default/windows_toolchain_profile.json
- appveyor PushArtifact out/Default/dist.zip
- appveyor PushArtifact out/Default/shell_browser_ui_unittests.exe
- appveyor PushArtifact out/Default/chromedriver.zip
- appveyor PushArtifact out/ffmpeg/ffmpeg.zip
- 7z a node_headers.zip out\Default\gen\node_headers
- appveyor PushArtifact node_headers.zip
- appveyor PushArtifact out/Default/mksnapshot.zip
- appveyor PushArtifact out/Default/hunspell_dictionaries.zip
- appveyor PushArtifact out/Default/electron.lib
- ps: >-
if ($env:GN_CONFIG -eq 'release') {
# Needed for msdia140.dll on 64-bit windows
$env:Path += ";$pwd\third_party\llvm-build\Release+Asserts\bin"
ninja -C out/Default electron:electron_symbols
}
- ps: >-
if ($env:GN_CONFIG -eq 'release') {
python electron\script\zip-symbols.py
appveyor-retry appveyor PushArtifact out/Default/symbols.zip
} else {
# It's useful to have pdb files when debugging testing builds that are
# built on CI.
7z a pdb.zip out\Default\*.pdb
appveyor-retry appveyor PushArtifact pdb.zip
}
- python electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.win.%TARGET_ARCH%.manifest
test_script:
# Workaround for https://github.com/appveyor/ci/issues/2420
- set "PATH=%PATH%;C:\Program Files\Git\mingw64\libexec\git-core"
- ps: >-
if ((-Not (Test-Path Env:\TEST_WOA)) -And (-Not (Test-Path Env:\ELECTRON_RELEASE)) -And ($env:GN_CONFIG -in "testing", "release")) {
$env:RUN_TESTS="true"
}
- ps: >-
if ($env:RUN_TESTS -eq 'true') {
New-Item .\out\Default\gen\node_headers\Release -Type directory
Copy-Item -path .\out\Default\electron.lib -destination .\out\Default\gen\node_headers\Release\node.lib
} else {
echo "Skipping tests for $env:GN_CONFIG build"
}
- cd electron
# CalculateNativeWinOcclusion is disabled due to https://bugs.chromium.org/p/chromium/issues/detail?id=1139022
- if "%RUN_TESTS%"=="true" ( echo Running test suite & node script/yarn test -- --trace-uncaught --enable-logging --disable-features=CalculateNativeWinOcclusion )
- cd ..
- if "%RUN_TESTS%"=="true" ( echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg )
- echo "About to verify mksnapshot"
- if "%RUN_TESTS%"=="true" ( echo Verifying mksnapshot & python electron\script\verify-mksnapshot.py --build-dir out\Default --source-root %cd% )
- echo "Done verifying mksnapshot"
- if "%RUN_TESTS%"=="true" ( echo Verifying chromedriver & python electron\script\verify-chromedriver.py --build-dir out\Default --source-root %cd% )
- echo "Done verifying chromedriver"
deploy_script:
- cd electron
- ps: >-
if (Test-Path Env:\ELECTRON_RELEASE) {
if (Test-Path Env:\UPLOAD_TO_S3) {
Write-Output "Uploading Electron release distribution to s3"
& python script\release\uploaders\upload.py --verbose --upload_to_s3
} else {
Write-Output "Uploading Electron release distribution to github releases"
& python script\release\uploaders\upload.py --verbose
}
} elseif (Test-Path Env:\TEST_WOA) {
node script/release/ci-release-build.js --job=electron-woa-testing --ci=VSTS --armTest --appveyorJobId=$env:APPVEYOR_JOB_ID $env:APPVEYOR_REPO_BRANCH
}

525
atom.gyp Normal file
View File

@@ -0,0 +1,525 @@
{
'variables': {
'project_name%': 'electron',
'product_name%': 'Electron',
'company_name%': 'GitHub, Inc',
'company_abbr%': 'github',
'version%': '0.30.8',
},
'includes': [
'filenames.gypi',
'vendor/native_mate/native_mate_files.gypi',
],
'target_defaults': {
'defines': [
'ATOM_PRODUCT_NAME="<(product_name)"',
'ATOM_PROJECT_NAME="<(project_name)"',
],
'conditions': [
['OS=="mac"', {
'mac_framework_dirs': [
'<(source_root)/external_binaries',
],
}],
],
},
'targets': [
{
'target_name': '<(project_name)',
'type': 'executable',
'dependencies': [
'compile_coffee',
'<(project_name)_lib',
],
'sources': [
'<@(app_sources)',
],
'include_dirs': [
'.',
],
'conditions': [
['OS=="mac"', {
'product_name': '<(product_name)',
'mac_bundle': 1,
'dependencies!': [
'<(project_name)_lib',
],
'dependencies': [
'<(project_name)_framework',
'<(project_name)_helper',
],
'xcode_settings': {
'ATOM_BUNDLE_ID': 'com.<(company_abbr).<(project_name)',
'INFOPLIST_FILE': 'atom/browser/resources/mac/Info.plist',
'LD_RUNPATH_SEARCH_PATHS': [
'@executable_path/../Frameworks',
],
},
'mac_bundle_resources': [
'<@(bundle_sources)',
],
'copies': [
{
'destination': '<(PRODUCT_DIR)/<(product_name).app/Contents/Frameworks',
'files': [
'<(PRODUCT_DIR)/<(product_name) Helper.app',
'<(PRODUCT_DIR)/<(product_name) Framework.framework',
'external_binaries/Squirrel.framework',
'external_binaries/ReactiveCocoa.framework',
'external_binaries/Mantle.framework',
],
},
{
'destination': '<(PRODUCT_DIR)/<(product_name).app/Contents/Resources',
'files': [
'atom/browser/default_app',
],
},
],
'postbuilds': [
{
# This postbuid step is responsible for creating the following
# helpers:
#
# <(product_name) EH.app and <(product_name) NP.app are created
# from <(product_name).app.
#
# The EH helper is marked for an executable heap. The NP helper
# is marked for no PIE (ASLR).
'postbuild_name': 'Make More Helpers',
'action': [
'vendor/brightray/tools/mac/make_more_helpers.sh',
'Frameworks',
'<(product_name)',
],
},
# The application doesn't have real localizations, it just has
# empty .lproj directories, which is enough to convince Cocoa
# atom-shell supports those languages.
{
'postbuild_name': 'Make Empty Localizations',
'variables': {
'apply_locales_cmd': ['python', 'tools/mac/apply_locales.py'],
'locale_dirs': [
'>!@(<(apply_locales_cmd) -d ZZLOCALE.lproj <(locales))',
],
},
'action': [
'tools/mac/make_locale_dirs.sh',
'<@(locale_dirs)',
],
},
]
}, { # OS=="mac"
'dependencies': [
'make_locale_paks',
],
}], # OS!="mac"
['OS=="win"', {
'include_dirs': [
'<(libchromiumcontent_dir)/gen/ui/resources',
],
'msvs_settings': {
'VCManifestTool': {
'EmbedManifest': 'true',
'AdditionalManifestFiles': 'atom/browser/resources/win/atom.manifest',
}
},
'copies': [
{
'variables': {
'conditions': [
['libchromiumcontent_component', {
'copied_libraries': [
'<@(libchromiumcontent_shared_libraries)',
'<@(libchromiumcontent_shared_v8_libraries)',
],
}, {
'copied_libraries': [
'<(libchromiumcontent_dir)/pdf.dll',
],
}],
],
},
'destination': '<(PRODUCT_DIR)',
'files': [
'<@(copied_libraries)',
'<(libchromiumcontent_dir)/ffmpegsumo.dll',
'<(libchromiumcontent_dir)/libEGL.dll',
'<(libchromiumcontent_dir)/libGLESv2.dll',
'<(libchromiumcontent_dir)/icudtl.dat',
'<(libchromiumcontent_dir)/content_resources_200_percent.pak',
'<(libchromiumcontent_dir)/content_shell.pak',
'<(libchromiumcontent_dir)/ui_resources_200_percent.pak',
'<(libchromiumcontent_dir)/natives_blob.bin',
'<(libchromiumcontent_dir)/snapshot_blob.bin',
'external_binaries/d3dcompiler_47.dll',
'external_binaries/xinput1_3.dll',
'external_binaries/msvcp120.dll',
'external_binaries/msvcr120.dll',
'external_binaries/vccorlib120.dll',
],
},
{
'destination': '<(PRODUCT_DIR)/resources',
'files': [
'atom/browser/default_app',
]
},
],
}, {
'dependencies': [
'vendor/breakpad/breakpad.gyp:dump_syms#host',
],
}], # OS=="win"
['OS=="linux"', {
'copies': [
{
'variables': {
'conditions': [
['libchromiumcontent_component', {
'copied_libraries': [
'<(PRODUCT_DIR)/lib/libnode.so',
'<@(libchromiumcontent_shared_libraries)',
'<@(libchromiumcontent_shared_v8_libraries)',
],
}, {
'copied_libraries': [
'<(PRODUCT_DIR)/lib/libnode.so',
],
}],
],
},
'destination': '<(PRODUCT_DIR)',
'files': [
'<@(copied_libraries)',
'<(libchromiumcontent_dir)/libffmpegsumo.so',
'<(libchromiumcontent_dir)/icudtl.dat',
'<(libchromiumcontent_dir)/content_shell.pak',
'<(libchromiumcontent_dir)/natives_blob.bin',
'<(libchromiumcontent_dir)/snapshot_blob.bin',
],
},
{
'destination': '<(PRODUCT_DIR)/resources',
'files': [
'atom/browser/default_app',
]
},
],
}], # OS=="linux"
],
}, # target <(project_name)
{
'target_name': '<(project_name)_lib',
'type': 'static_library',
'dependencies': [
'atom_coffee2c',
'vendor/brightray/brightray.gyp:brightray',
'vendor/node/node.gyp:node',
],
'defines': [
# This is defined in skia/skia_common.gypi.
'SK_SUPPORT_LEGACY_GETTOPDEVICE',
# Disable warnings for g_settings_list_schemas.
'GLIB_DISABLE_DEPRECATION_WARNINGS',
# Defined in Chromium but not exposed in its gyp file.
'V8_USE_EXTERNAL_STARTUP_DATA',
'ENABLE_PLUGINS',
# Needed by Node.
'NODE_WANT_INTERNALS=1',
],
'sources': [
'<@(lib_sources)',
],
'include_dirs': [
'.',
'chromium_src',
'vendor/brightray',
'vendor/native_mate',
# Include atom_natives.h.
'<(SHARED_INTERMEDIATE_DIR)',
# Include directories for uv and node.
'vendor/node/src',
'vendor/node/deps/http_parser',
'vendor/node/deps/uv/include',
# The `node.h` is using `#include"v8.h"`.
'<(libchromiumcontent_src_dir)/v8/include',
# The `node.h` is using `#include"ares.h"`.
'vendor/node/deps/cares/include',
# The `third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h` is using `platform/PlatformExport.h`.
'<(libchromiumcontent_src_dir)/third_party/WebKit/Source',
],
'direct_dependent_settings': {
'include_dirs': [
'.',
],
},
'export_dependent_settings': [
'vendor/brightray/brightray.gyp:brightray',
],
'conditions': [
['libchromiumcontent_component', {
'link_settings': {
'libraries': [ '<@(libchromiumcontent_v8_libraries)' ],
},
}],
['OS=="win"', {
'sources': [
'<@(lib_sources_win)',
],
'link_settings': {
'libraries': [
'-limm32.lib',
'-loleacc.lib',
'-lcomctl32.lib',
'-lcomdlg32.lib',
'-lwininet.lib',
],
},
'dependencies': [
# Node is built as static_library on Windows, so we also need to
# include its dependencies here.
'vendor/node/deps/cares/cares.gyp:cares',
'vendor/node/deps/http_parser/http_parser.gyp:http_parser',
'vendor/node/deps/uv/uv.gyp:libuv',
'vendor/node/deps/zlib/zlib.gyp:zlib',
# Build with breakpad support.
'vendor/breakpad/breakpad.gyp:breakpad_handler',
'vendor/breakpad/breakpad.gyp:breakpad_sender',
],
}], # OS=="win"
['OS=="mac"', {
'dependencies': [
'vendor/crashpad/client/client.gyp:crashpad_client',
'vendor/crashpad/handler/handler.gyp:crashpad_handler',
],
}], # OS=="mac"
['OS=="linux"', {
'link_settings': {
'ldflags': [
# Make binary search for libraries under current directory, so we
# don't have to manually set $LD_LIBRARY_PATH:
# http://serverfault.com/questions/279068/cant-find-so-in-the-same-directory-as-the-executable
'-rpath \$$ORIGIN',
# Make native module dynamic loading work.
'-rdynamic',
],
},
# Required settings of using breakpad.
'cflags_cc': [
'-Wno-empty-body',
'-Wno-reserved-user-defined-literal',
],
'include_dirs': [
'vendor/breakpad/src',
],
'dependencies': [
'vendor/breakpad/breakpad.gyp:breakpad_client',
],
}], # OS=="linux"
],
}, # target <(product_name)_lib
{
'target_name': 'compile_coffee',
'type': 'none',
'actions': [
{
'action_name': 'compile_coffee',
'variables': {
'conditions': [
['OS=="mac"', {
'resources_path': '<(PRODUCT_DIR)/<(product_name).app/Contents/Resources',
},{
'resources_path': '<(PRODUCT_DIR)/resources',
}],
],
},
'inputs': [
'<@(coffee_sources)',
],
'outputs': [
'<(resources_path)/atom.asar',
],
'action': [
'python',
'tools/coffee2asar.py',
'<@(_outputs)',
'<@(_inputs)',
],
}
],
}, # target compile_coffee
{
'target_name': 'atom_coffee2c',
'type': 'none',
'actions': [
{
'action_name': 'atom_coffee2c',
'inputs': [
'<@(coffee2c_sources)',
],
'outputs': [
'<(SHARED_INTERMEDIATE_DIR)/atom_natives.h',
],
'action': [
'python',
'tools/coffee2c.py',
'<@(_outputs)',
'<@(_inputs)',
],
}
],
}, # target atom_coffee2c
],
'conditions': [
['OS=="mac"', {
'targets': [
{
'target_name': '<(project_name)_framework',
'product_name': '<(product_name) Framework',
'type': 'shared_library',
'dependencies': [
'<(project_name)_lib',
],
'sources': [
'<@(framework_sources)',
],
'include_dirs': [
'.',
'vendor',
'<(libchromiumcontent_src_dir)',
],
'export_dependent_settings': [
'<(project_name)_lib',
],
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/Carbon.framework',
'$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework',
'external_binaries/Squirrel.framework',
'external_binaries/ReactiveCocoa.framework',
'external_binaries/Mantle.framework',
],
},
'mac_bundle': 1,
'mac_bundle_resources': [
'atom/common/resources/mac/MainMenu.xib',
'<(libchromiumcontent_dir)/content_shell.pak',
'<(libchromiumcontent_dir)/icudtl.dat',
'<(libchromiumcontent_dir)/natives_blob.bin',
'<(libchromiumcontent_dir)/snapshot_blob.bin',
],
'xcode_settings': {
'ATOM_BUNDLE_ID': 'com.<(company_abbr).<(project_name).framework',
'INFOPLIST_FILE': 'atom/common/resources/mac/Info.plist',
'LD_DYLIB_INSTALL_NAME': '@rpath/<(product_name) Framework.framework/<(product_name) Framework',
'LD_RUNPATH_SEARCH_PATHS': [
'@loader_path/Libraries',
],
'OTHER_LDFLAGS': [
'-ObjC',
],
},
'copies': [
{
'variables': {
'conditions': [
['libchromiumcontent_component', {
'copied_libraries': [
'<(PRODUCT_DIR)/libnode.dylib',
'<@(libchromiumcontent_shared_libraries)',
'<@(libchromiumcontent_shared_v8_libraries)',
],
}, {
'copied_libraries': [
'<(PRODUCT_DIR)/libnode.dylib',
],
}],
],
},
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Libraries',
'files': [
'<@(copied_libraries)',
'<(libchromiumcontent_dir)/ffmpegsumo.so',
],
},
{
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Resources',
'files': [
'<(PRODUCT_DIR)/crashpad_handler',
],
},
],
'postbuilds': [
{
'postbuild_name': 'Fix path of libnode',
'action': [
'install_name_tool',
'-change',
'/usr/local/lib/libnode.dylib',
'@rpath/libnode.dylib',
'${BUILT_PRODUCTS_DIR}/<(product_name) Framework.framework/Versions/A/<(product_name) Framework',
],
},
{
'postbuild_name': 'Add symlinks for framework subdirectories',
'action': [
'tools/mac/create-framework-subdir-symlinks.sh',
'<(product_name) Framework',
'Libraries',
],
},
],
}, # target framework
{
'target_name': '<(project_name)_helper',
'product_name': '<(product_name) Helper',
'type': 'executable',
'dependencies': [
'<(project_name)_framework',
],
'sources': [
'<@(app_sources)',
],
'include_dirs': [
'.',
],
'mac_bundle': 1,
'xcode_settings': {
'ATOM_BUNDLE_ID': 'com.<(company_abbr).<(project_name).helper',
'INFOPLIST_FILE': 'atom/renderer/resources/mac/Info.plist',
'LD_RUNPATH_SEARCH_PATHS': [
'@executable_path/../../..',
],
},
}, # 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"
],
}

View File

@@ -0,0 +1,106 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/app/atom_content_client.h"
#include <string>
#include <vector>
#include "atom/common/chrome_version.h"
#include "atom/common/options_switches.h"
#include "base/command_line.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/pepper_plugin_info.h"
#include "ppapi/shared_impl/ppapi_permissions.h"
namespace atom {
namespace {
content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path,
const std::string& version) {
content::PepperPluginInfo plugin;
plugin.is_out_of_process = true;
plugin.name = content::kFlashPluginName;
plugin.path = path;
plugin.permissions = ppapi::PERMISSION_ALL_BITS;
std::vector<std::string> flash_version_numbers;
base::SplitString(version, '.', &flash_version_numbers);
if (flash_version_numbers.size() < 1)
flash_version_numbers.push_back("11");
// |SplitString()| puts in an empty string given an empty string. :(
else if (flash_version_numbers[0].empty())
flash_version_numbers[0] = "11";
if (flash_version_numbers.size() < 2)
flash_version_numbers.push_back("2");
if (flash_version_numbers.size() < 3)
flash_version_numbers.push_back("999");
if (flash_version_numbers.size() < 4)
flash_version_numbers.push_back("999");
// E.g., "Shockwave Flash 10.2 r154":
plugin.description = plugin.name + " " + flash_version_numbers[0] + "." +
flash_version_numbers[1] + " r" + flash_version_numbers[2];
plugin.version = JoinString(flash_version_numbers, '.');
content::WebPluginMimeType swf_mime_type(
content::kFlashPluginSwfMimeType,
content::kFlashPluginSwfExtension,
content::kFlashPluginSwfDescription);
plugin.mime_types.push_back(swf_mime_type);
content::WebPluginMimeType spl_mime_type(
content::kFlashPluginSplMimeType,
content::kFlashPluginSplExtension,
content::kFlashPluginSplDescription);
plugin.mime_types.push_back(spl_mime_type);
return plugin;
}
} // namespace
AtomContentClient::AtomContentClient() {
}
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) {
auto command_line = base::CommandLine::ForCurrentProcess();
auto flash_path = command_line->GetSwitchValueNative(
switches::kPpapiFlashPath);
if (flash_path.empty())
return;
auto flash_version = command_line->GetSwitchValueASCII(
switches::kPpapiFlashVersion);
plugins->push_back(
CreatePepperFlashInfo(base::FilePath(flash_path), flash_version));
}
} // namespace atom

View File

@@ -0,0 +1,35 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_APP_ATOM_CONTENT_CLIENT_H_
#define ATOM_APP_ATOM_CONTENT_CLIENT_H_
#include <string>
#include <vector>
#include "brightray/common/content_client.h"
namespace atom {
class AtomContentClient : public brightray::ContentClient {
public:
AtomContentClient();
virtual ~AtomContentClient();
protected:
// content::ContentClient:
std::string GetProduct() const override;
void AddAdditionalSchemes(
std::vector<std::string>* standard_schemes,
std::vector<std::string>* savable_schemes) override;
void AddPepperPlugins(
std::vector<content::PepperPluginInfo>* plugins) override;
private:
DISALLOW_COPY_AND_ASSIGN(AtomContentClient);
};
} // namespace atom
#endif // ATOM_APP_ATOM_CONTENT_CLIENT_H_

View File

@@ -0,0 +1,20 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_APP_ATOM_LIBRARY_MAIN_H_
#define ATOM_APP_ATOM_LIBRARY_MAIN_H_
#include "base/basictypes.h"
#if defined(OS_MACOSX)
extern "C" {
__attribute__((visibility("default")))
int AtomMain(int argc, const char* argv[]);
__attribute__((visibility("default")))
int AtomInitializeICUandStartNode(int argc, char *argv[]);
}
#endif // OS_MACOSX
#endif // ATOM_APP_ATOM_LIBRARY_MAIN_H_

View File

@@ -0,0 +1,36 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/app/atom_library_main.h"
#include "atom/app/atom_main_delegate.h"
#include "atom/app/node_main.h"
#include "atom/common/atom_command_line.h"
#include "base/at_exit.h"
#include "base/i18n/icu_util.h"
#include "base/mac/bundle_locations.h"
#include "brightray/common/mac/main_application_bundle.h"
#include "content/public/app/content_main.h"
#if defined(OS_MACOSX)
int AtomMain(int argc, const char* argv[]) {
atom::AtomMainDelegate delegate;
content::ContentMainParams params(&delegate);
params.argc = argc;
params.argv = argv;
atom::AtomCommandLine::Init(argc, argv);
return content::ContentMain(params);
}
int AtomInitializeICUandStartNode(int argc, char *argv[]) {
base::AtExitManager atexit_manager;
base::mac::SetOverrideFrameworkBundlePath(
brightray::MainApplicationBundlePath()
.Append("Contents")
.Append("Frameworks")
.Append(ATOM_PRODUCT_NAME " Framework.framework"));
base::i18n::InitializeICU();
return atom::NodeMain(argc, argv);
}
#endif // OS_MACOSX

190
atom/app/atom_main.cc Normal file
View File

@@ -0,0 +1,190 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/app/atom_main.h"
#include <stdlib.h>
#include <string.h>
#if defined(OS_WIN)
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <windows.h>
#include <shellscalingapi.h>
#include <tchar.h>
#include <shellapi.h>
#include "atom/app/atom_main_delegate.h"
#include "atom/common/crash_reporter/win/crash_service_main.h"
#include "base/environment.h"
#include "base/win/windows_version.h"
#include "content/public/app/startup_helper_win.h"
#include "sandbox/win/src/sandbox_types.h"
#include "ui/gfx/win/dpi.h"
#elif defined(OS_LINUX) // defined(OS_WIN)
#include "atom/app/atom_main_delegate.h" // NOLINT
#include "content/public/app/content_main.h"
#else // defined(OS_LINUX)
#include "atom/app/atom_library_main.h"
#endif // defined(OS_MACOSX)
#include "atom/app/node_main.h"
#include "atom/common/atom_command_line.h"
#include "base/i18n/icu_util.h"
#if defined(OS_WIN)
namespace {
// Win8.1 supports monitor-specific DPI scaling.
bool SetProcessDpiAwarenessWrapper(PROCESS_DPI_AWARENESS value) {
typedef HRESULT(WINAPI *SetProcessDpiAwarenessPtr)(PROCESS_DPI_AWARENESS);
SetProcessDpiAwarenessPtr set_process_dpi_awareness_func =
reinterpret_cast<SetProcessDpiAwarenessPtr>(
GetProcAddress(GetModuleHandleA("user32.dll"),
"SetProcessDpiAwarenessInternal"));
if (set_process_dpi_awareness_func) {
HRESULT hr = set_process_dpi_awareness_func(value);
if (SUCCEEDED(hr)) {
VLOG(1) << "SetProcessDpiAwareness succeeded.";
return true;
} else if (hr == E_ACCESSDENIED) {
LOG(ERROR) << "Access denied error from SetProcessDpiAwareness. "
"Function called twice, or manifest was used.";
}
}
return false;
}
// This function works for Windows Vista through Win8. Win8.1 must use
// SetProcessDpiAwareness[Wrapper].
BOOL SetProcessDPIAwareWrapper() {
typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID);
SetProcessDPIAwarePtr set_process_dpi_aware_func =
reinterpret_cast<SetProcessDPIAwarePtr>(
GetProcAddress(GetModuleHandleA("user32.dll"),
"SetProcessDPIAware"));
return set_process_dpi_aware_func &&
set_process_dpi_aware_func();
}
void EnableHighDPISupport() {
if (!SetProcessDpiAwarenessWrapper(PROCESS_SYSTEM_DPI_AWARE)) {
SetProcessDPIAwareWrapper();
}
}
} // namespace
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
int argc = 0;
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.
std::string os;
if (env->GetVar("OS", &os) && os != "cygwin") {
AttachConsole(ATTACH_PARENT_PROCESS);
FILE* dontcare;
freopen_s(&dontcare, "CON", "w", stdout);
freopen_s(&dontcare, "CON", "w", stderr);
freopen_s(&dontcare, "CON", "r", stdin);
}
// Convert argv to to UTF8
char** argv = new char*[argc];
for (int i = 0; i < argc; i++) {
// Compute the size of the required buffer
DWORD size = WideCharToMultiByte(CP_UTF8,
0,
wargv[i],
-1,
NULL,
0,
NULL,
NULL);
if (size == 0) {
// This should never happen.
fprintf(stderr, "Could not convert arguments to utf8.");
exit(1);
}
// Do the actual conversion
argv[i] = new char[size];
DWORD result = WideCharToMultiByte(CP_UTF8,
0,
wargv[i],
-1,
argv[i],
size,
NULL,
NULL);
if (result == 0) {
// This should never happen.
fprintf(stderr, "Could not convert arguments to utf8.");
exit(1);
}
}
std::string node_indicator, crash_service_indicator;
if (env->GetVar("ATOM_SHELL_INTERNAL_RUN_AS_NODE", &node_indicator) &&
node_indicator == "1") {
// Now that argv conversion is done, we can finally start.
base::i18n::InitializeICU();
return atom::NodeMain(argc, argv);
} else if (env->GetVar("ATOM_SHELL_INTERNAL_CRASH_SERVICE",
&crash_service_indicator) &&
crash_service_indicator == "1") {
return crash_service::Main(cmd);
}
sandbox::SandboxInterfaceInfo sandbox_info = {0};
content::InitializeSandboxInfo(&sandbox_info);
atom::AtomMainDelegate delegate;
// We don't want to set DPI awareness on pre-Win7 because we don't support
// DirectWrite there. GDI fonts are kerned very badly, so better to leave
// DPI-unaware and at effective 1.0. See also ShouldUseDirectWrite().
if (base::win::GetVersion() >= base::win::VERSION_WIN7)
EnableHighDPISupport();
content::ContentMainParams params(&delegate);
params.instance = instance;
params.sandbox_info = &sandbox_info;
atom::AtomCommandLine::Init(argc, argv);
return content::ContentMain(params);
}
#elif defined(OS_LINUX) // defined(OS_WIN)
int main(int argc, const char* argv[]) {
char* node_indicator = getenv("ATOM_SHELL_INTERNAL_RUN_AS_NODE");
if (node_indicator != NULL && strcmp(node_indicator, "1") == 0) {
base::i18n::InitializeICU();
return atom::NodeMain(argc, const_cast<char**>(argv));
}
atom::AtomMainDelegate delegate;
content::ContentMainParams params(&delegate);
params.argc = argc;
params.argv = argv;
atom::AtomCommandLine::Init(argc, argv);
return content::ContentMain(params);
}
#else // defined(OS_LINUX)
int main(int argc, const char* argv[]) {
char* node_indicator = getenv("ATOM_SHELL_INTERNAL_RUN_AS_NODE");
if (node_indicator != NULL && strcmp(node_indicator, "1") == 0) {
return AtomInitializeICUandStartNode(argc, const_cast<char**>(argv));
}
return AtomMain(argc, argv);
}
#endif // defined(OS_MACOSX)

10
atom/app/atom_main.h Normal file
View File

@@ -0,0 +1,10 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_APP_ATOM_MAIN_H_
#define ATOM_APP_ATOM_MAIN_H_
#include "content/public/app/content_main.h"
#endif // ATOM_APP_ATOM_MAIN_H_

View File

@@ -0,0 +1,126 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/app/atom_main_delegate.h"
#include <string>
#include "atom/app/atom_content_client.h"
#include "atom/browser/atom_browser_client.h"
#include "atom/common/google_api_key.h"
#include "atom/renderer/atom_renderer_client.h"
#include "atom/utility/atom_content_utility_client.h"
#include "base/command_line.h"
#include "base/debug/stack_trace.h"
#include "base/environment.h"
#include "base/logging.h"
#include "content/public/common/content_switches.h"
#include "ui/base/resource/resource_bundle.h"
namespace atom {
AtomMainDelegate::AtomMainDelegate() {
}
AtomMainDelegate::~AtomMainDelegate() {
}
bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
// Disable logging out to debug.log on Windows
logging::LoggingSettings settings;
#if defined(OS_WIN)
#if defined(DEBUG)
settings.logging_dest = logging::LOG_TO_ALL;
settings.log_file = L"debug.log";
settings.lock_log = logging::LOCK_LOG_FILE;
settings.delete_old = logging::DELETE_OLD_LOG_FILE;
#else
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
#endif // defined(DEBUG)
#endif // defined(OS_WIN)
logging::InitLogging(settings);
// Logging with pid and timestamp.
logging::SetLogItems(true, false, true, false);
#if defined(DEBUG) && defined(OS_LINUX)
// Enable convient stack printing.
base::debug::EnableInProcessStackDumping();
#endif
return brightray::MainDelegate::BasicStartupComplete(exit_code);
}
void AtomMainDelegate::PreSandboxStartup() {
brightray::MainDelegate::PreSandboxStartup();
// Set google API key.
scoped_ptr<base::Environment> env(base::Environment::Create());
if (!env->HasVar("GOOGLE_API_KEY"))
env->SetVar("GOOGLE_API_KEY", GOOGLEAPIS_API_KEY);
auto command_line = base::CommandLine::ForCurrentProcess();
std::string process_type = command_line->GetSwitchValueASCII(
switches::kProcessType);
if (process_type == switches::kUtilityProcess) {
AtomContentUtilityClient::PreSandboxStartup();
}
// Only append arguments for browser process.
if (!process_type.empty())
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.
command_line->AppendSwitch(switches::kNoSandbox);
// Allow file:// URIs to read other file:// URIs by default.
command_line->AppendSwitch(switches::kAllowFileAccessFromFiles);
#if defined(OS_MACOSX)
// Enable AVFoundation.
command_line->AppendSwitch("enable-avfoundation");
#endif
}
content::ContentBrowserClient* AtomMainDelegate::CreateContentBrowserClient() {
browser_client_.reset(new AtomBrowserClient);
return browser_client_.get();
}
content::ContentRendererClient*
AtomMainDelegate::CreateContentRendererClient() {
renderer_client_.reset(new AtomRendererClient);
return renderer_client_.get();
}
content::ContentUtilityClient* AtomMainDelegate::CreateContentUtilityClient() {
utility_client_.reset(new AtomContentUtilityClient);
return utility_client_.get();
}
scoped_ptr<brightray::ContentClient> AtomMainDelegate::CreateContentClient() {
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

View File

@@ -0,0 +1,46 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_APP_ATOM_MAIN_DELEGATE_H_
#define ATOM_APP_ATOM_MAIN_DELEGATE_H_
#include "brightray/common/main_delegate.h"
#include "brightray/common/content_client.h"
namespace atom {
class AtomMainDelegate : public brightray::MainDelegate {
public:
AtomMainDelegate();
~AtomMainDelegate();
protected:
// content::ContentMainDelegate:
bool BasicStartupComplete(int* exit_code) override;
void PreSandboxStartup() override;
content::ContentBrowserClient* CreateContentBrowserClient() override;
content::ContentRendererClient* CreateContentRendererClient() override;
content::ContentUtilityClient* CreateContentUtilityClient() override;
// brightray::MainDelegate:
scoped_ptr<brightray::ContentClient> CreateContentClient() override;
void AddDataPackFromPath(
ui::ResourceBundle* bundle, const base::FilePath& pak_dir) override;
#if defined(OS_MACOSX)
void OverrideChildProcessPath() override;
void OverrideFrameworkBundlePath() override;
#endif
private:
brightray::ContentClient content_client_;
scoped_ptr<content::ContentBrowserClient> browser_client_;
scoped_ptr<content::ContentRendererClient> renderer_client_;
scoped_ptr<content::ContentUtilityClient> utility_client_;
DISALLOW_COPY_AND_ASSIGN(AtomMainDelegate);
};
} // namespace atom
#endif // ATOM_APP_ATOM_MAIN_DELEGATE_H_

View File

@@ -0,0 +1,51 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/app/atom_main_delegate.h"
#include "base/mac/bundle_locations.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "brightray/common/application_info.h"
#include "brightray/common/mac/main_application_bundle.h"
#include "content/public/common/content_paths.h"
namespace atom {
namespace {
base::FilePath GetFrameworksPath() {
return brightray::MainApplicationBundlePath().Append("Contents")
.Append("Frameworks");
}
base::FilePath GetHelperAppPath(const base::FilePath& frameworks_path,
const std::string& name) {
return frameworks_path.Append(name + " Helper.app")
.Append("Contents")
.Append("MacOS")
.Append(name + " Helper");
}
} // namespace
void AtomMainDelegate::OverrideFrameworkBundlePath() {
base::mac::SetOverrideFrameworkBundlePath(
GetFrameworksPath().Append(ATOM_PRODUCT_NAME " Framework.framework"));
}
void AtomMainDelegate::OverrideChildProcessPath() {
base::FilePath frameworks_path = GetFrameworksPath();
base::FilePath helper_path = GetHelperAppPath(frameworks_path,
ATOM_PRODUCT_NAME);
if (!base::PathExists(helper_path))
helper_path = GetHelperAppPath(frameworks_path,
brightray::GetApplicationName());
if (!base::PathExists(helper_path))
LOG(FATAL) << "Unable to find helper app";
PathService::Override(content::CHILD_PROCESS_EXE, helper_path);
}
} // namespace atom

68
atom/app/node_main.cc Normal file
View File

@@ -0,0 +1,68 @@
// 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/node_main.h"
#include "atom/browser/javascript_environment.h"
#include "atom/common/node_includes.h"
#include "gin/array_buffer.h"
#include "gin/public/isolate_holder.h"
namespace atom {
int NodeMain(int argc, char *argv[]) {
argv = uv_setup_args(argc, argv);
int exec_argc;
const char** exec_argv;
node::Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);
int exit_code = 1;
{
gin::IsolateHolder::LoadV8Snapshot();
gin::IsolateHolder::Initialize(
gin::IsolateHolder::kNonStrictMode,
gin::ArrayBufferAllocator::SharedInstance());
JavascriptEnvironment gin_env;
node::Environment* env = node::CreateEnvironment(
gin_env.isolate(), uv_default_loop(), gin_env.context(), argc, argv,
exec_argc, exec_argv);
// Start debugger.
node::node_isolate = gin_env.isolate();
if (node::use_debug_agent)
node::StartDebug(env, node::debug_wait_connect);
node::LoadEnvironment(env);
// Enable debugger.
if (node::use_debug_agent)
node::EnableDebug(env);
bool more;
do {
more = uv_run(env->event_loop(), UV_RUN_ONCE);
if (more == false) {
node::EmitBeforeExit(env);
// Emit `beforeExit` if the loop became alive either after emitting
// event, or after running some callbacks.
more = uv_loop_alive(env->event_loop());
if (uv_run(env->event_loop(), UV_RUN_NOWAIT) != 0)
more = true;
}
} while (more == true);
exit_code = node::EmitExit(env);
node::RunAtExit(env);
env->Dispose();
}
v8::V8::Dispose();
return exit_code;
}
} // namespace atom

14
atom/app/node_main.h Normal file
View File

@@ -0,0 +1,14 @@
// 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_NODE_MAIN_H_
#define ATOM_APP_NODE_MAIN_H_
namespace atom {
int NodeMain(int argc, char *argv[]);
} // namespace atom
#endif // ATOM_APP_NODE_MAIN_H_

View File

@@ -0,0 +1,349 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_app.h"
#include <string>
#include <vector>
#if defined(OS_WIN)
#include <shlobj.h>
#endif
#include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/api/atom_api_session.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/browser.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "brightray/browser/brightray_paths.h"
#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/gpu_data_manager.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "net/ssl/ssl_cert_request_info.h"
#if defined(OS_WIN)
#include "base/strings/utf_string_conversions.h"
#endif
#include "atom/common/node_includes.h"
using atom::Browser;
namespace mate {
#if defined(OS_WIN)
template<>
struct Converter<Browser::UserTask> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
Browser::UserTask* out) {
mate::Dictionary dict;
if (!ConvertFromV8(isolate, val, &dict))
return false;
if (!dict.Get("program", &(out->program)) ||
!dict.Get("title", &(out->title)))
return false;
if (dict.Get("iconPath", &(out->icon_path)) &&
!dict.Get("iconIndex", &(out->icon_index)))
return false;
dict.Get("arguments", &(out->arguments));
dict.Get("description", &(out->description));
return true;
}
};
#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 atom {
namespace api {
namespace {
// Return the path constant from string.
int GetPathConstant(const std::string& name) {
if (name == "appData")
return brightray::DIR_APP_DATA;
else if (name == "userData")
return brightray::DIR_USER_DATA;
else if (name == "cache")
return brightray::DIR_CACHE;
else if (name == "userCache")
return brightray::DIR_USER_CACHE;
else if (name == "home")
return base::DIR_HOME;
else if (name == "temp")
return base::DIR_TEMP;
else if (name == "userDesktop")
return base::DIR_USER_DESKTOP;
else if (name == "exe")
return base::FILE_EXE;
else if (name == "module")
return base::FILE_MODULE;
else
return -1;
}
void OnClientCertificateSelected(
v8::Isolate* isolate,
std::shared_ptr<content::ClientCertificateDelegate> delegate,
mate::Arguments* args) {
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
mate::Dictionary cert_data;
if (!(args->Length() == 1 && args->GetNext(&cert_data))) {
args->ThrowError();
return;
}
std::string encoded_data;
cert_data.Get("data", &encoded_data);
auto certs =
net::X509Certificate::CreateCertificateListFromBytes(
encoded_data.data(), encoded_data.size(),
net::X509Certificate::FORMAT_AUTO);
delegate->ContinueWithCertificate(certs[0].get());
}
} // namespace
App::App() {
Browser::Get()->AddObserver(this);
content::GpuDataManager::GetInstance()->AddObserver(this);
}
App::~App() {
Browser::Get()->RemoveObserver(this);
content::GpuDataManager::GetInstance()->RemoveObserver(this);
}
void App::OnBeforeQuit(bool* prevent_default) {
*prevent_default = Emit("before-quit");
}
void App::OnWillQuit(bool* prevent_default) {
*prevent_default = Emit("will-quit");
}
void App::OnWindowAllClosed() {
Emit("window-all-closed");
}
void App::OnQuit() {
Emit("quit");
}
void App::OnOpenFile(bool* prevent_default, const std::string& file_path) {
*prevent_default = Emit("open-file", file_path);
}
void App::OnOpenURL(const std::string& url) {
Emit("open-url", url);
}
void App::OnActivateWithNoOpenWindows() {
Emit("activate-with-no-open-windows");
}
void App::OnWillFinishLaunching() {
Emit("will-finish-launching");
}
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");
}
void App::OnSelectCertificate(
content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) {
std::shared_ptr<content::ClientCertificateDelegate>
shared_delegate(delegate.release());
bool prevent_default =
Emit("select-certificate",
api::WebContents::CreateFrom(isolate(), web_contents),
cert_request_info->host_and_port.ToString(),
cert_request_info->client_certs,
base::Bind(&OnClientCertificateSelected,
isolate(),
shared_delegate));
// Default to first certificate from the platform store.
if (!prevent_default)
shared_delegate->ContinueWithCertificate(
cert_request_info->client_certs[0].get());
}
void App::OnGpuProcessCrashed(base::TerminationStatus exit_code) {
Emit("gpu-process-crashed");
}
base::FilePath App::GetPath(mate::Arguments* args, const std::string& name) {
bool succeed = false;
base::FilePath path;
int key = GetPathConstant(name);
if (key >= 0)
succeed = PathService::Get(key, &path);
if (!succeed)
args->ThrowError("Failed to get path");
return path;
}
void App::SetPath(mate::Arguments* args,
const std::string& name,
const base::FilePath& path) {
bool succeed = false;
int key = GetPathConstant(name);
if (key >= 0)
succeed = PathService::Override(key, path);
if (!succeed)
args->ThrowError("Failed to set path");
}
void App::SetDesktopName(const std::string& desktop_name) {
#if defined(OS_LINUX)
scoped_ptr<base::Environment> env(base::Environment::Create());
env->SetVar("CHROME_DESKTOP", desktop_name);
#endif
}
void App::SetAppUserModelId(const std::string& app_id) {
#if defined(OS_WIN)
base::string16 app_id_utf16 = base::UTF8ToUTF16(app_id);
SetCurrentProcessExplicitAppUserModelID(app_id_utf16.c_str());
#endif
}
v8::Local<v8::Value> App::DefaultSession(v8::Isolate* isolate) {
if (default_session_.IsEmpty())
return v8::Null(isolate);
else
return v8::Local<v8::Value>::New(isolate, default_session_);
}
mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
auto browser = base::Unretained(Browser::Get());
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("quit", base::Bind(&Browser::Quit, browser))
.SetMethod("focus", base::Bind(&Browser::Focus, browser))
.SetMethod("getVersion", base::Bind(&Browser::GetVersion, browser))
.SetMethod("setVersion", base::Bind(&Browser::SetVersion, browser))
.SetMethod("getName", base::Bind(&Browser::GetName, browser))
.SetMethod("setName", base::Bind(&Browser::SetName, browser))
.SetMethod("isReady", base::Bind(&Browser::is_ready, browser))
.SetMethod("addRecentDocument",
base::Bind(&Browser::AddRecentDocument, browser))
.SetMethod("clearRecentDocuments",
base::Bind(&Browser::ClearRecentDocuments, browser))
#if defined(OS_WIN)
.SetMethod("setUserTasks",
base::Bind(&Browser::SetUserTasks, browser))
#endif
.SetMethod("setPath", &App::SetPath)
.SetMethod("getPath", &App::GetPath)
.SetMethod("setDesktopName", &App::SetDesktopName)
.SetMethod("setAppUserModelId", &App::SetAppUserModelId)
.SetProperty("defaultSession", &App::DefaultSession);
}
// static
mate::Handle<App> App::Create(v8::Isolate* isolate) {
return CreateHandle(isolate, new App);
}
} // namespace api
} // namespace atom
namespace {
void AppendSwitch(const std::string& switch_string, mate::Arguments* args) {
auto command_line = base::CommandLine::ForCurrentProcess();
std::string value;
if (args->GetNext(&value))
command_line->AppendSwitchASCII(switch_string, value);
else
command_line->AppendSwitch(switch_string);
}
#if defined(OS_MACOSX)
int DockBounce(const std::string& type) {
int request_id = -1;
if (type == "critical")
request_id = Browser::Get()->DockBounce(Browser::BOUNCE_CRITICAL);
else if (type == "informational")
request_id = Browser::Get()->DockBounce(Browser::BOUNCE_INFORMATIONAL);
return request_id;
}
void DockSetMenu(atom::api::Menu* menu) {
Browser::Get()->DockSetMenu(menu->model());
}
#endif
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
v8::Isolate* isolate = context->GetIsolate();
auto command_line = base::CommandLine::ForCurrentProcess();
mate::Dictionary dict(isolate, exports);
dict.Set("app", atom::api::App::Create(isolate));
dict.SetMethod("appendSwitch", &AppendSwitch);
dict.SetMethod("appendArgument",
base::Bind(&base::CommandLine::AppendArg,
base::Unretained(command_line)));
#if defined(OS_MACOSX)
auto browser = base::Unretained(Browser::Get());
dict.SetMethod("dockBounce", &DockBounce);
dict.SetMethod("dockCancelBounce",
base::Bind(&Browser::DockCancelBounce, browser));
dict.SetMethod("dockSetBadgeText",
base::Bind(&Browser::DockSetBadgeText, browser));
dict.SetMethod("dockGetBadgeText",
base::Bind(&Browser::DockGetBadgeText, browser));
dict.SetMethod("dockHide", base::Bind(&Browser::DockHide, browser));
dict.SetMethod("dockShow", base::Bind(&Browser::DockShow, browser));
dict.SetMethod("dockSetMenu", &DockSetMenu);
#endif
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_app, Initialize)

View File

@@ -0,0 +1,79 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_API_APP_H_
#define ATOM_BROWSER_API_ATOM_API_APP_H_
#include <string>
#include "atom/browser/api/event_emitter.h"
#include "atom/browser/browser_observer.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "native_mate/handle.h"
namespace base {
class FilePath;
}
namespace mate {
class Arguments;
}
namespace atom {
namespace api {
class App : public mate::EventEmitter,
public BrowserObserver,
public content::GpuDataManagerObserver {
public:
static mate::Handle<App> Create(v8::Isolate* isolate);
protected:
App();
virtual ~App();
// BrowserObserver:
void OnBeforeQuit(bool* prevent_default) override;
void OnWillQuit(bool* prevent_default) override;
void OnWindowAllClosed() override;
void OnQuit() override;
void OnOpenFile(bool* prevent_default, const std::string& file_path) override;
void OnOpenURL(const std::string& url) override;
void OnActivateWithNoOpenWindows() override;
void OnWillFinishLaunching() override;
void OnFinishLaunching() override;
void OnSelectCertificate(
content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) override;
// content::GpuDataManagerObserver:
void OnGpuProcessCrashed(base::TerminationStatus exit_code) override;
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
private:
// Get/Set the pre-defined path in PathService.
base::FilePath GetPath(mate::Arguments* args, const std::string& name);
void SetPath(mate::Arguments* args,
const std::string& name,
const base::FilePath& path);
void SetDesktopName(const std::string& desktop_name);
void SetAppUserModelId(const std::string& app_id);
v8::Local<v8::Value> DefaultSession(v8::Isolate* isolate);
v8::Global<v8::Value> default_session_;
DISALLOW_COPY_AND_ASSIGN(App);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_APP_H_

View File

@@ -0,0 +1,89 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_auto_updater.h"
#include "base/time/time.h"
#include "atom/browser/auto_updater.h"
#include "atom/browser/browser.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "atom/common/node_includes.h"
namespace atom {
namespace api {
AutoUpdater::AutoUpdater() {
auto_updater::AutoUpdater::SetDelegate(this);
}
AutoUpdater::~AutoUpdater() {
auto_updater::AutoUpdater::SetDelegate(NULL);
}
void AutoUpdater::OnError(const std::string& error) {
Emit("error", error);
}
void AutoUpdater::OnCheckingForUpdate() {
Emit("checking-for-update");
}
void AutoUpdater::OnUpdateAvailable() {
Emit("update-available");
}
void AutoUpdater::OnUpdateNotAvailable() {
Emit("update-not-available");
}
void AutoUpdater::OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url,
const base::Closure& quit_and_install) {
quit_and_install_ = quit_and_install;
Emit("update-downloaded-raw", release_notes, release_name,
release_date.ToJsTime(), update_url);
}
mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("setFeedUrl", &auto_updater::AutoUpdater::SetFeedURL)
.SetMethod("checkForUpdates", &auto_updater::AutoUpdater::CheckForUpdates)
.SetMethod("_quitAndInstall", &AutoUpdater::QuitAndInstall);
}
void AutoUpdater::QuitAndInstall() {
if (quit_and_install_.is_null())
Browser::Get()->Shutdown();
else
quit_and_install_.Run();
}
// static
mate::Handle<AutoUpdater> AutoUpdater::Create(v8::Isolate* isolate) {
return CreateHandle(isolate, new AutoUpdater);
}
} // 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("autoUpdater", atom::api::AutoUpdater::Create(isolate));
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_auto_updater, Initialize)

View File

@@ -0,0 +1,56 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_API_AUTO_UPDATER_H_
#define ATOM_BROWSER_API_ATOM_API_AUTO_UPDATER_H_
#include <string>
#include "base/callback.h"
#include "atom/browser/api/event_emitter.h"
#include "atom/browser/auto_updater_delegate.h"
#include "native_mate/handle.h"
namespace atom {
namespace api {
class AutoUpdater : public mate::EventEmitter,
public auto_updater::AutoUpdaterDelegate {
public:
static mate::Handle<AutoUpdater> Create(v8::Isolate* isolate);
protected:
AutoUpdater();
virtual ~AutoUpdater();
// AutoUpdaterDelegate implementations.
void OnError(const std::string& error) override;
void OnCheckingForUpdate() override;
void OnUpdateAvailable() override;
void OnUpdateNotAvailable() override;
void OnUpdateDownloaded(
const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url,
const base::Closure& quit_and_install) override;
// mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
private:
void QuitAndInstall();
base::Closure quit_and_install_;
DISALLOW_COPY_AND_ASSIGN(AutoUpdater);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_AUTO_UPDATER_H_

View File

@@ -0,0 +1,99 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include <set>
#include <string>
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "content/public/browser/tracing_controller.h"
#include "native_mate/dictionary.h"
#include "atom/common/node_includes.h"
using content::TracingController;
namespace mate {
template<>
struct Converter<base::trace_event::CategoryFilter> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
base::trace_event::CategoryFilter* out) {
std::string filter;
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))
return false;
return out->SetFromString(options);
}
};
} // namespace mate
namespace {
using CompletionCallback = base::Callback<void(const base::FilePath&)>;
scoped_refptr<TracingController::TraceDataSink> GetTraceDataSink(
const base::FilePath& path, const CompletionCallback& callback) {
base::FilePath result_file_path = path;
if (result_file_path.empty() && !base::CreateTemporaryFile(&result_file_path))
LOG(ERROR) << "Creating temporary file failed";
return TracingController::CreateFileSink(result_file_path,
base::Bind(callback,
result_file_path));
}
void StopRecording(const base::FilePath& path,
const CompletionCallback& callback) {
TracingController::GetInstance()->DisableRecording(
GetTraceDataSink(path, callback));
}
void CaptureMonitoringSnapshot(const base::FilePath& path,
const CompletionCallback& callback) {
TracingController::GetInstance()->CaptureMonitoringSnapshot(
GetTraceDataSink(path, callback));
}
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
auto controller = base::Unretained(TracingController::GetInstance());
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("getCategories", base::Bind(
&TracingController::GetCategories, controller));
dict.SetMethod("startRecording", base::Bind(
&TracingController::EnableRecording, controller));
dict.SetMethod("stopRecording", &StopRecording);
dict.SetMethod("startMonitoring", base::Bind(
&TracingController::EnableMonitoring, controller));
dict.SetMethod("stopMonitoring", base::Bind(
&TracingController::DisableMonitoring, controller));
dict.SetMethod("captureMonitoringSnapshot", &CaptureMonitoringSnapshot);
dict.SetMethod("getTraceBufferUsage", base::Bind(
&TracingController::GetTraceBufferUsage, controller));
dict.SetMethod("setWatchEvent", base::Bind(
&TracingController::SetWatchEvent, controller));
dict.SetMethod("cancelWatchEvent", base::Bind(
&TracingController::CancelWatchEvent, controller));
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_content_tracing, Initialize)

View File

@@ -0,0 +1,348 @@
// 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_cookies.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "base/bind.h"
#include "base/time/time.h"
#include "base/values.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_store.h"
#include "net/cookies/cookie_util.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "atom/common/node_includes.h"
using atom::api::Cookies;
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 {
template<>
struct Converter<net::CanonicalCookie> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const net::CanonicalCookie& val) {
mate::Dictionary dict(isolate, v8::Object::New(isolate));
dict.Set("name", val.Name());
dict.Set("value", val.Value());
dict.Set("domain", val.Domain());
dict.Set("host_only", net::cookie_util::DomainIsHostOnly(val.Domain()));
dict.Set("path", val.Path());
dict.Set("secure", val.IsSecure());
dict.Set("http_only", val.IsHttpOnly());
dict.Set("session", val.IsPersistent());
if (!val.IsPersistent())
dict.Set("expirationDate", val.ExpiryDate().ToDoubleT());
return dict.GetHandle();
}
};
} // namespace mate
namespace atom {
namespace api {
Cookies::Cookies(content::BrowserContext* browser_context)
: request_context_getter_(browser_context->GetRequestContext()) {
}
Cookies::~Cookies() {
}
void Cookies::Get(const base::DictionaryValue& options,
const CookiesCallback& callback) {
scoped_ptr<base::DictionaryValue> filter(
options.DeepCopyWithoutEmptyChildren());
content::BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&Cookies::GetCookiesOnIOThread, base::Unretained(this),
Passed(&filter), callback));
}
void Cookies::GetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> filter,
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));
}
}
void Cookies::OnGetCookies(scoped_ptr<base::DictionaryValue> filter,
const CookiesCallback& callback,
const net::CookieList& cookie_list) {
net::CookieList result;
for (const auto& cookie : cookie_list) {
if (MatchesCookie(filter.get(), cookie))
result.push_back(cookie);
}
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
&RunGetCookiesCallbackOnUIThread, isolate(), "", result, callback));
}
void Cookies::Remove(const mate::Dictionary& details,
const CookiesCallback& callback) {
GURL url;
std::string name;
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 error_message;
if (!options.GetString("url", &url)) {
error_message = "The url field is required.";
}
GURL gurl(url);
if (error_message.empty() && !gurl.is_valid()) {
error_message = "Url is not valid.";
}
if (!error_message.empty()) {
RunSetCookiesCallbackOnUIThread(isolate(), error_message, false, callback);
return;
}
scoped_ptr<base::DictionaryValue> details(
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,
const GURL& url,
const CookiesCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
std::string name, value, domain, path;
bool secure = false;
bool http_only = false;
double expiration_date;
details->GetString("name", &name);
details->GetString("value", &value);
details->GetString("domain", &domain);
details->GetString("path", &path);
details->GetBoolean("secure", &secure);
details->GetBoolean("http_only", &http_only);
base::Time expiration_time;
if (details->GetDouble("expirationDate", &expiration_date)) {
expiration_time = (expiration_date == 0) ?
base::Time::UnixEpoch() :
base::Time::FromDoubleT(expiration_date);
}
GetCookieStore()->GetCookieMonster()->SetCookieWithDetailsAsync(
url,
name,
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,
bool set_success) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&RunSetCookiesCallbackOnUIThread, isolate(), "", set_success,
callback));
}
mate::ObjectTemplateBuilder Cookies::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("get", &Cookies::Get)
.SetMethod("remove", &Cookies::Remove)
.SetMethod("set", &Cookies::Set);
}
net::CookieStore* Cookies::GetCookieStore() {
return request_context_getter_->GetURLRequestContext()->cookie_store();
}
// static
mate::Handle<Cookies> Cookies::Create(
v8::Isolate* isolate,
content::BrowserContext* browser_context) {
return mate::CreateHandle(isolate, new Cookies(browser_context));
}
} // namespace api
} // namespace atom

View File

@@ -0,0 +1,90 @@
// 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_COOKIES_H_
#define ATOM_BROWSER_API_ATOM_API_COOKIES_H_
#include <string>
#include "base/callback.h"
#include "native_mate/wrappable.h"
#include "native_mate/handle.h"
#include "net/cookies/canonical_cookie.h"
namespace base {
class DictionaryValue;
}
namespace content {
class BrowserContext;
}
namespace mate {
class Dictionary;
}
namespace net {
class CookieStore;
class URLRequestContextGetter;
}
namespace atom {
namespace api {
class Cookies : public mate::Wrappable {
public:
// node.js style callback function(error, result)
typedef base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>
CookiesCallback;
static mate::Handle<Cookies> Create(v8::Isolate* isolate,
content::BrowserContext* browser_context);
protected:
explicit Cookies(content::BrowserContext* browser_context);
~Cookies();
void Get(const base::DictionaryValue& options,
const CookiesCallback& callback);
void Remove(const mate::Dictionary& details,
const CookiesCallback& 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:
// Must be called on IO thread.
net::CookieStore* GetCookieStore();
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
DISALLOW_COPY_AND_ASSIGN(Cookies);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_COOKIES_H_

View File

@@ -0,0 +1,118 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include <string>
#include <utility>
#include <vector>
#include "atom/browser/api/atom_api_window.h"
#include "atom/browser/native_window.h"
#include "atom/browser/ui/file_dialog.h"
#include "atom/browser/ui/message_box.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/image_converter.h"
#include "native_mate/dictionary.h"
#include "atom/common/node_includes.h"
namespace mate {
template<>
struct Converter<file_dialog::Filter> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
file_dialog::Filter* out) {
mate::Dictionary dict;
if (!ConvertFromV8(isolate, val, &dict))
return false;
if (!dict.Get("name", &(out->first)))
return false;
if (!dict.Get("extensions", &(out->second)))
return false;
return true;
}
};
} // namespace mate
namespace {
void ShowMessageBox(int type,
const std::vector<std::string>& buttons,
int cancel_id,
int options,
const std::string& title,
const std::string& message,
const std::string& detail,
const gfx::ImageSkia& icon,
atom::NativeWindow* window,
mate::Arguments* args) {
v8::Local<v8::Value> peek = args->PeekNext();
atom::MessageBoxCallback callback;
if (mate::Converter<atom::MessageBoxCallback>::FromV8(args->isolate(),
peek,
&callback)) {
atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, cancel_id,
options, title, message, detail, icon, callback);
} else {
int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type,
buttons, cancel_id, options, title,
message, detail, icon);
args->Return(chosen);
}
}
void ShowOpenDialog(const std::string& title,
const base::FilePath& default_path,
const file_dialog::Filters& filters,
int properties,
atom::NativeWindow* window,
mate::Arguments* args) {
v8::Local<v8::Value> peek = args->PeekNext();
file_dialog::OpenDialogCallback callback;
if (mate::Converter<file_dialog::OpenDialogCallback>::FromV8(args->isolate(),
peek,
&callback)) {
file_dialog::ShowOpenDialog(window, title, default_path, filters,
properties, callback);
} else {
std::vector<base::FilePath> paths;
if (file_dialog::ShowOpenDialog(window, title, default_path, filters,
properties, &paths))
args->Return(paths);
}
}
void ShowSaveDialog(const std::string& title,
const base::FilePath& default_path,
const file_dialog::Filters& filters,
atom::NativeWindow* window,
mate::Arguments* args) {
v8::Local<v8::Value> peek = args->PeekNext();
file_dialog::SaveDialogCallback callback;
if (mate::Converter<file_dialog::SaveDialogCallback>::FromV8(args->isolate(),
peek,
&callback)) {
file_dialog::ShowSaveDialog(window, title, default_path, filters, callback);
} else {
base::FilePath path;
if (file_dialog::ShowSaveDialog(window, title, default_path, filters,
&path))
args->Return(path);
}
}
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("showMessageBox", &ShowMessageBox);
dict.SetMethod("showErrorBox", &atom::ShowErrorBox);
dict.SetMethod("showOpenDialog", &ShowOpenDialog);
dict.SetMethod("showSaveDialog", &ShowSaveDialog);
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_dialog, Initialize)

View File

@@ -0,0 +1,98 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_global_shortcut.h"
#include <string>
#include "atom/common/native_mate_converters/accelerator_converter.h"
#include "atom/common/native_mate_converters/callback.h"
#include "base/stl_util.h"
#include "native_mate/dictionary.h"
#include "atom/common/node_includes.h"
using extensions::GlobalShortcutListener;
namespace atom {
namespace api {
GlobalShortcut::GlobalShortcut() {
}
GlobalShortcut::~GlobalShortcut() {
UnregisterAll();
}
void GlobalShortcut::OnKeyPressed(const ui::Accelerator& accelerator) {
if (accelerator_callback_map_.find(accelerator) ==
accelerator_callback_map_.end()) {
// This should never occur, because if it does, GlobalGlobalShortcutListener
// notifes us with wrong accelerator.
NOTREACHED();
return;
}
accelerator_callback_map_[accelerator].Run();
}
bool GlobalShortcut::Register(const ui::Accelerator& accelerator,
const base::Closure& callback) {
if (!GlobalShortcutListener::GetInstance()->RegisterAccelerator(
accelerator, this)) {
return false;
}
accelerator_callback_map_[accelerator] = callback;
return true;
}
void GlobalShortcut::Unregister(const ui::Accelerator& accelerator) {
if (!ContainsKey(accelerator_callback_map_, accelerator))
return;
accelerator_callback_map_.erase(accelerator);
GlobalShortcutListener::GetInstance()->UnregisterAccelerator(
accelerator, this);
}
bool GlobalShortcut::IsRegistered(const ui::Accelerator& accelerator) {
return ContainsKey(accelerator_callback_map_, accelerator);
}
void GlobalShortcut::UnregisterAll() {
accelerator_callback_map_.clear();
GlobalShortcutListener::GetInstance()->UnregisterAccelerators(this);
}
mate::ObjectTemplateBuilder GlobalShortcut::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("register", &GlobalShortcut::Register)
.SetMethod("isRegistered", &GlobalShortcut::IsRegistered)
.SetMethod("unregister", &GlobalShortcut::Unregister)
.SetMethod("unregisterAll", &GlobalShortcut::UnregisterAll);
}
// static
mate::Handle<GlobalShortcut> GlobalShortcut::Create(v8::Isolate* isolate) {
return CreateHandle(isolate, new GlobalShortcut);
}
} // 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("globalShortcut", atom::api::GlobalShortcut::Create(isolate));
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_global_shortcut, Initialize)

View File

@@ -0,0 +1,55 @@
// Copyright (c) 2014 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_GLOBAL_SHORTCUT_H_
#define ATOM_BROWSER_API_ATOM_API_GLOBAL_SHORTCUT_H_
#include <map>
#include <string>
#include "base/callback.h"
#include "chrome/browser/extensions/global_shortcut_listener.h"
#include "native_mate/wrappable.h"
#include "native_mate/handle.h"
#include "ui/base/accelerators/accelerator.h"
namespace atom {
namespace api {
class GlobalShortcut : public extensions::GlobalShortcutListener::Observer,
public mate::Wrappable {
public:
static mate::Handle<GlobalShortcut> Create(v8::Isolate* isolate);
protected:
GlobalShortcut();
virtual ~GlobalShortcut();
// mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
private:
typedef std::map<ui::Accelerator, base::Closure> AcceleratorCallbackMap;
bool Register(const ui::Accelerator& accelerator,
const base::Closure& callback);
bool IsRegistered(const ui::Accelerator& accelerator);
void Unregister(const ui::Accelerator& accelerator);
void UnregisterAll();
// GlobalShortcutListener::Observer implementation.
void OnKeyPressed(const ui::Accelerator& accelerator) override;
AcceleratorCallbackMap accelerator_callback_map_;
DISALLOW_COPY_AND_ASSIGN(GlobalShortcut);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_GLOBAL_SHORTCUT_H_

View File

@@ -0,0 +1,194 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/native_window.h"
#include "atom/common/native_mate_converters/accelerator_converter.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/image_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "native_mate/constructor.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "atom/common/node_includes.h"
namespace atom {
namespace api {
Menu::Menu()
: model_(new AtomMenuModel(this)),
parent_(NULL) {
}
Menu::~Menu() {
}
void Menu::AfterInit(v8::Isolate* isolate) {
mate::Dictionary wrappable(isolate, GetWrapper(isolate));
mate::Dictionary delegate;
if (!wrappable.Get("delegate", &delegate))
return;
delegate.Get("isCommandIdChecked", &is_checked_);
delegate.Get("isCommandIdEnabled", &is_enabled_);
delegate.Get("isCommandIdVisible", &is_visible_);
delegate.Get("getAcceleratorForCommandId", &get_accelerator_);
delegate.Get("executeCommand", &execute_command_);
delegate.Get("menuWillShow", &menu_will_show_);
}
bool Menu::IsCommandIdChecked(int command_id) const {
return is_checked_.Run(command_id);
}
bool Menu::IsCommandIdEnabled(int command_id) const {
return is_enabled_.Run(command_id);
}
bool Menu::IsCommandIdVisible(int command_id) const {
return is_visible_.Run(command_id);
}
bool Menu::GetAcceleratorForCommandId(int command_id,
ui::Accelerator* accelerator) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
v8::Local<v8::Value> val = get_accelerator_.Run(command_id);
return mate::ConvertFromV8(isolate(), val, accelerator);
}
void Menu::ExecuteCommand(int command_id, int event_flags) {
execute_command_.Run(command_id);
}
void Menu::MenuWillShow(ui::SimpleMenuModel* source) {
menu_will_show_.Run();
}
void Menu::InsertItemAt(
int index, int command_id, const base::string16& label) {
model_->InsertItemAt(index, command_id, label);
}
void Menu::InsertSeparatorAt(int index) {
model_->InsertSeparatorAt(index, ui::NORMAL_SEPARATOR);
}
void Menu::InsertCheckItemAt(int index,
int command_id,
const base::string16& label) {
model_->InsertCheckItemAt(index, command_id, label);
}
void Menu::InsertRadioItemAt(int index,
int command_id,
const base::string16& label,
int group_id) {
model_->InsertRadioItemAt(index, command_id, label, group_id);
}
void Menu::InsertSubMenuAt(int index,
int command_id,
const base::string16& label,
Menu* menu) {
menu->parent_ = this;
model_->InsertSubMenuAt(index, command_id, label, menu->model_.get());
}
void Menu::SetIcon(int index, const gfx::Image& image) {
model_->SetIcon(index, image);
}
void Menu::SetSublabel(int index, const base::string16& sublabel) {
model_->SetSublabel(index, sublabel);
}
void Menu::Clear() {
model_->Clear();
}
int Menu::GetIndexOfCommandId(int command_id) {
return model_->GetIndexOfCommandId(command_id);
}
int Menu::GetItemCount() const {
return model_->GetItemCount();
}
int Menu::GetCommandIdAt(int index) const {
return model_->GetCommandIdAt(index);
}
base::string16 Menu::GetLabelAt(int index) const {
return model_->GetLabelAt(index);
}
base::string16 Menu::GetSublabelAt(int index) const {
return model_->GetSublabelAt(index);
}
bool Menu::IsItemCheckedAt(int index) const {
return model_->IsItemCheckedAt(index);
}
bool Menu::IsEnabledAt(int index) const {
return model_->IsEnabledAt(index);
}
bool Menu::IsVisibleAt(int index) const {
return model_->IsVisibleAt(index);
}
// static
void Menu::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("insertItem", &Menu::InsertItemAt)
.SetMethod("insertCheckItem", &Menu::InsertCheckItemAt)
.SetMethod("insertRadioItem", &Menu::InsertRadioItemAt)
.SetMethod("insertSeparator", &Menu::InsertSeparatorAt)
.SetMethod("insertSubMenu", &Menu::InsertSubMenuAt)
.SetMethod("setIcon", &Menu::SetIcon)
.SetMethod("setSublabel", &Menu::SetSublabel)
.SetMethod("clear", &Menu::Clear)
.SetMethod("getIndexOfCommandId", &Menu::GetIndexOfCommandId)
.SetMethod("getItemCount", &Menu::GetItemCount)
.SetMethod("getCommandIdAt", &Menu::GetCommandIdAt)
.SetMethod("getLabelAt", &Menu::GetLabelAt)
.SetMethod("getSublabelAt", &Menu::GetSublabelAt)
.SetMethod("isItemCheckedAt", &Menu::IsItemCheckedAt)
.SetMethod("isEnabledAt", &Menu::IsEnabledAt)
.SetMethod("isVisibleAt", &Menu::IsVisibleAt)
.SetMethod("_popup", &Menu::Popup)
.SetMethod("_popupAt", &Menu::PopupAt);
}
} // namespace api
} // namespace atom
namespace {
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
using atom::api::Menu;
v8::Isolate* isolate = context->GetIsolate();
v8::Local<v8::Function> constructor = mate::CreateConstructor<Menu>(
isolate, "Menu", base::Bind(&Menu::Create));
mate::Dictionary dict(isolate, exports);
dict.Set("Menu", static_cast<v8::Local<v8::Value>>(constructor));
#if defined(OS_MACOSX)
dict.SetMethod("setApplicationMenu", &Menu::SetApplicationMenu);
dict.SetMethod("sendActionToFirstResponder",
&Menu::SendActionToFirstResponder);
#endif
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_menu, Initialize)

View File

@@ -0,0 +1,124 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_API_MENU_H_
#define ATOM_BROWSER_API_ATOM_API_MENU_H_
#include <string>
#include "atom/browser/api/atom_api_window.h"
#include "atom/browser/ui/atom_menu_model.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "native_mate/wrappable.h"
namespace atom {
namespace api {
class Menu : public mate::Wrappable,
public AtomMenuModel::Delegate {
public:
static mate::Wrappable* Create();
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
#if defined(OS_MACOSX)
// Set the global menubar.
static void SetApplicationMenu(Menu* menu);
// Fake sending an action from the application menu.
static void SendActionToFirstResponder(const std::string& action);
#endif
AtomMenuModel* model() const { return model_.get(); }
protected:
Menu();
virtual ~Menu();
// mate::Wrappable:
void AfterInit(v8::Isolate* isolate) override;
// ui::SimpleMenuModel::Delegate:
bool IsCommandIdChecked(int command_id) const override;
bool IsCommandIdEnabled(int command_id) const override;
bool IsCommandIdVisible(int command_id) const override;
bool GetAcceleratorForCommandId(int command_id,
ui::Accelerator* accelerator) override;
void ExecuteCommand(int command_id, int event_flags) override;
void MenuWillShow(ui::SimpleMenuModel* source) override;
virtual void Popup(Window* window) = 0;
virtual void PopupAt(Window* window, int x, int y) = 0;
scoped_ptr<AtomMenuModel> model_;
Menu* parent_;
private:
void InsertItemAt(int index, int command_id, const base::string16& label);
void InsertSeparatorAt(int index);
void InsertCheckItemAt(int index,
int command_id,
const base::string16& label);
void InsertRadioItemAt(int index,
int command_id,
const base::string16& label,
int group_id);
void InsertSubMenuAt(int index,
int command_id,
const base::string16& label,
Menu* menu);
void SetIcon(int index, const gfx::Image& image);
void SetSublabel(int index, const base::string16& sublabel);
void Clear();
int GetIndexOfCommandId(int command_id);
int GetItemCount() const;
int GetCommandIdAt(int index) const;
base::string16 GetLabelAt(int index) const;
base::string16 GetSublabelAt(int index) const;
bool IsItemCheckedAt(int index) const;
bool IsEnabledAt(int index) const;
bool IsVisibleAt(int index) const;
// Stored delegate methods.
base::Callback<bool(int)> is_checked_;
base::Callback<bool(int)> is_enabled_;
base::Callback<bool(int)> is_visible_;
base::Callback<v8::Local<v8::Value>(int)> get_accelerator_;
base::Callback<void(int)> execute_command_;
base::Callback<void()> menu_will_show_;
DISALLOW_COPY_AND_ASSIGN(Menu);
};
} // namespace api
} // namespace atom
namespace mate {
template<>
struct Converter<atom::AtomMenuModel*> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
atom::AtomMenuModel** out) {
// null would be tranfered to NULL.
if (val->IsNull()) {
*out = nullptr;
return true;
}
atom::api::Menu* menu;
if (!Converter<atom::api::Menu*>::FromV8(isolate, val, &menu))
return false;
*out = menu->model();
return true;
}
};
} // namespace mate
#endif // ATOM_BROWSER_API_ATOM_API_MENU_H_

View File

@@ -0,0 +1,39 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_API_MENU_MAC_H_
#define ATOM_BROWSER_API_ATOM_API_MENU_MAC_H_
#include "atom/browser/api/atom_api_menu.h"
#include <string>
#import "atom/browser/ui/cocoa/atom_menu_controller.h"
namespace atom {
namespace api {
class MenuMac : public Menu {
protected:
MenuMac();
void Popup(Window* window) override;
void PopupAt(Window* window, int x, int y) override;
base::scoped_nsobject<AtomMenuController> menu_controller_;
private:
friend class Menu;
static void SendActionToFirstResponder(const std::string& action);
DISALLOW_COPY_AND_ASSIGN(MenuMac);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_MENU_MAC_H_

View File

@@ -0,0 +1,96 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#import "atom/browser/api/atom_api_menu_mac.h"
#include "atom/browser/native_window.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/sys_string_conversions.h"
#include "content/public/browser/web_contents.h"
#include "atom/common/node_includes.h"
namespace atom {
namespace api {
MenuMac::MenuMac() {
}
void MenuMac::Popup(Window* window) {
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();
if (!native_window)
return;
content::WebContents* web_contents = native_window->web_contents();
if (!web_contents)
return;
base::scoped_nsobject<AtomMenuController> menu_controller(
[[AtomMenuController alloc] initWithModel:model_.get()]);
NSMenu* menu = [menu_controller menu];
NSView* view = web_contents->GetContentNativeView();
// Show the menu.
[menu popUpMenuPositioningItem:[menu itemAtIndex:0]
atLocation:NSMakePoint(x, [view frame].size.height - y)
inView:view];
}
// static
void Menu::SetApplicationMenu(Menu* base_menu) {
MenuMac* menu = static_cast<MenuMac*>(base_menu);
base::scoped_nsobject<AtomMenuController> menu_controller(
[[AtomMenuController alloc] initWithModel:menu->model_.get()]);
[NSApp setMainMenu:[menu_controller menu]];
// Ensure the menu_controller_ is destroyed after main menu is set.
menu_controller.swap(menu->menu_controller_);
}
// static
void Menu::SendActionToFirstResponder(const std::string& action) {
SEL selector = NSSelectorFromString(base::SysUTF8ToNSString(action));
[NSApp sendAction:selector to:nil from:[NSApp mainMenu]];
}
// static
mate::Wrappable* Menu::Create() {
return new MenuMac();
}
} // namespace api
} // namespace atom

View File

@@ -0,0 +1,57 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_menu_views.h"
#include "atom/browser/native_window_views.h"
#include "content/public/browser/render_widget_host_view.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/menu/menu_runner.h"
namespace atom {
namespace api {
MenuViews::MenuViews() {
}
void MenuViews::Popup(Window* window) {
PopupAtPoint(window, gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
}
void MenuViews::PopupAt(Window* window, int x, int y) {
NativeWindow* native_window = static_cast<NativeWindow*>(window->window());
if (!native_window)
return;
content::WebContents* web_contents = native_window->web_contents();
if (!web_contents)
return;
content::RenderWidgetHostView* view = web_contents->GetRenderWidgetHostView();
if (!view)
return;
gfx::Point origin = view->GetViewBounds().origin();
PopupAtPoint(window, gfx::Point(origin.x() + x, origin.y() + y));
}
void MenuViews::PopupAtPoint(Window* window, const gfx::Point& point) {
views::MenuRunner menu_runner(
model(),
views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS);
ignore_result(menu_runner.RunMenuAt(
static_cast<NativeWindowViews*>(window->window())->widget(),
NULL,
gfx::Rect(point, gfx::Size()),
views::MENU_ANCHOR_TOPLEFT,
ui::MENU_SOURCE_MOUSE));
}
// static
mate::Wrappable* Menu::Create() {
return new MenuViews();
}
} // namespace api
} // namespace atom

View File

@@ -0,0 +1,33 @@
// Copyright (c) 2014 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_MENU_VIEWS_H_
#define ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_
#include "atom/browser/api/atom_api_menu.h"
#include "ui/gfx/screen.h"
namespace atom {
namespace api {
class MenuViews : public Menu {
public:
MenuViews();
protected:
void Popup(Window* window) override;
void PopupAt(Window* window, int x, int y) override;
private:
void PopupAtPoint(Window* window, const gfx::Point& point);
DISALLOW_COPY_AND_ASSIGN(MenuViews);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_

View File

@@ -0,0 +1,74 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_power_monitor.h"
#include "atom/browser/browser.h"
#include "base/power_monitor/power_monitor.h"
#include "base/power_monitor/power_monitor_device_source.h"
#include "native_mate/dictionary.h"
#include "atom/common/node_includes.h"
namespace atom {
namespace api {
PowerMonitor::PowerMonitor() {
base::PowerMonitor::Get()->AddObserver(this);
}
PowerMonitor::~PowerMonitor() {
base::PowerMonitor::Get()->RemoveObserver(this);
}
void PowerMonitor::OnPowerStateChange(bool on_battery_power) {
if (on_battery_power)
Emit("on-battery");
else
Emit("on-ac");
}
void PowerMonitor::OnSuspend() {
Emit("suspend");
}
void PowerMonitor::OnResume() {
Emit("resume");
}
// static
v8::Local<v8::Value> PowerMonitor::Create(v8::Isolate* isolate) {
if (!Browser::Get()->is_ready()) {
node::ThrowError(
isolate,
"Cannot initialize \"power-monitor\" module before app is ready");
return v8::Null(isolate);
}
return CreateHandle(isolate, new PowerMonitor).ToV8();
}
} // namespace api
} // namespace atom
namespace {
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
#if defined(OS_MACOSX)
base::PowerMonitorDeviceSource::AllocateSystemIOPorts();
#endif
using atom::api::PowerMonitor;
v8::Isolate* isolate = context->GetIsolate();
mate::Dictionary dict(isolate, exports);
dict.Set("powerMonitor", PowerMonitor::Create(isolate));
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_power_monitor, Initialize)

View File

@@ -0,0 +1,39 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_
#define ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_
#include "atom/browser/api/event_emitter.h"
#include "base/compiler_specific.h"
#include "base/power_monitor/power_observer.h"
#include "native_mate/handle.h"
namespace atom {
namespace api {
class PowerMonitor : public mate::EventEmitter,
public base::PowerObserver {
public:
static v8::Local<v8::Value> Create(v8::Isolate* isolate);
protected:
PowerMonitor();
virtual ~PowerMonitor();
// base::PowerObserver implementations:
void OnPowerStateChange(bool on_battery_power) override;
void OnSuspend() override;
void OnResume() override;
private:
DISALLOW_COPY_AND_ASSIGN(PowerMonitor);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_

View File

@@ -0,0 +1,128 @@
// 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_power_save_blocker.h"
#include <string>
#include "content/public/browser/power_save_blocker.h"
#include "native_mate/dictionary.h"
#include "atom/common/node_includes.h"
namespace mate {
template<>
struct Converter<content::PowerSaveBlocker::PowerSaveBlockerType> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
content::PowerSaveBlocker::PowerSaveBlockerType* out) {
using content::PowerSaveBlocker;
std::string type;
if (!ConvertFromV8(isolate, val, &type))
return false;
if (type == "prevent-app-suspension")
*out = PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension;
else if (type == "prevent-display-sleep")
*out = PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
else
return false;
return true;
}
};
} // namespace mate
namespace atom {
namespace api {
PowerSaveBlocker::PowerSaveBlocker()
: current_blocker_type_(
content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension) {
}
PowerSaveBlocker::~PowerSaveBlocker() {
}
void PowerSaveBlocker::UpdatePowerSaveBlocker() {
if (power_save_blocker_types_.empty()) {
power_save_blocker_.reset();
return;
}
// |kPowerSaveBlockPreventAppSuspension| keeps system active, but allows
// screen to be turned off.
// |kPowerSaveBlockPreventDisplaySleep| keeps system and screen active, has a
// higher precedence level than |kPowerSaveBlockPreventAppSuspension|.
//
// Only the highest-precedence blocker type takes effect.
content::PowerSaveBlocker::PowerSaveBlockerType new_blocker_type =
content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension;
for (const auto& element : power_save_blocker_types_) {
if (element.second ==
content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep) {
new_blocker_type =
content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
break;
}
}
if (!power_save_blocker_ || new_blocker_type != current_blocker_type_) {
scoped_ptr<content::PowerSaveBlocker> new_blocker =
content::PowerSaveBlocker::Create(
new_blocker_type,
content::PowerSaveBlocker::kReasonOther,
ATOM_PRODUCT_NAME);
power_save_blocker_.swap(new_blocker);
current_blocker_type_ = new_blocker_type;
}
}
int PowerSaveBlocker::Start(
content::PowerSaveBlocker::PowerSaveBlockerType type) {
static int count = 0;
power_save_blocker_types_[count] = type;
UpdatePowerSaveBlocker();
return count++;
}
bool PowerSaveBlocker::Stop(int id) {
bool success = power_save_blocker_types_.erase(id) > 0;
UpdatePowerSaveBlocker();
return success;
}
bool PowerSaveBlocker::IsStarted(int id) {
return power_save_blocker_types_.find(id) != power_save_blocker_types_.end();
}
mate::ObjectTemplateBuilder PowerSaveBlocker::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("start", &PowerSaveBlocker::Start)
.SetMethod("stop", &PowerSaveBlocker::Stop)
.SetMethod("isStarted", &PowerSaveBlocker::IsStarted);
}
// static
mate::Handle<PowerSaveBlocker> PowerSaveBlocker::Create(v8::Isolate* isolate) {
return CreateHandle(isolate, new PowerSaveBlocker);
}
} // 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("powerSaveBlocker", atom::api::PowerSaveBlocker::Create(isolate));
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_power_save_blocker, Initialize);

View File

@@ -0,0 +1,59 @@
// 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_POWER_SAVE_BLOCKER_H_
#define ATOM_BROWSER_API_ATOM_API_POWER_SAVE_BLOCKER_H_
#include <map>
#include "base/memory/scoped_ptr.h"
#include "content/public/browser/power_save_blocker.h"
#include "native_mate/handle.h"
#include "native_mate/wrappable.h"
namespace mate {
class Dictionary;
}
namespace atom {
namespace api {
class PowerSaveBlocker : public mate::Wrappable {
public:
static mate::Handle<PowerSaveBlocker> Create(v8::Isolate* isolate);
protected:
PowerSaveBlocker();
virtual ~PowerSaveBlocker();
// mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
private:
void UpdatePowerSaveBlocker();
int Start(content::PowerSaveBlocker::PowerSaveBlockerType type);
bool Stop(int id);
bool IsStarted(int id);
scoped_ptr<content::PowerSaveBlocker> power_save_blocker_;
// Currnet blocker type used by |power_save_blocker_|
content::PowerSaveBlocker::PowerSaveBlockerType current_blocker_type_;
// Map from id to the corresponding blocker type for each request.
using PowerSaveBlockerTypeMap =
std::map<int, content::PowerSaveBlocker::PowerSaveBlockerType>;
PowerSaveBlockerTypeMap power_save_blocker_types_;
DISALLOW_COPY_AND_ASSIGN(PowerSaveBlocker);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_POWER_SAVE_BLOCKER_H_

View File

@@ -0,0 +1,425 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_protocol.h"
#include "atom/browser/atom_browser_client.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/api/atom_api_session.h"
#include "atom/browser/net/adapter_request_job.h"
#include "atom/browser/net/atom_url_request_job_factory.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 "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"
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 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)
: request_context_getter_(browser_context->GetRequestContext()),
job_factory_(browser_context->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(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("registerStandardSchemes", &Protocol::RegisterStandardSchemes)
.SetMethod("isHandledProtocol", &Protocol::IsHandledProtocol)
.SetMethod("_registerProtocol", &Protocol::RegisterProtocol)
.SetMethod("_unregisterProtocol", &Protocol::UnregisterProtocol)
.SetMethod("_interceptProtocol", &Protocol::InterceptProtocol)
.SetMethod("_uninterceptProtocol", &Protocol::UninterceptProtocol);
}
void Protocol::RegisterStandardSchemes(
const std::vector<std::string>& schemes) {
atom::AtomBrowserClient::SetCustomSchemes(schemes);
}
void Protocol::IsHandledProtocol(const std::string& scheme,
const net::CompletionCallback& callback) {
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
base::Bind(&AtomURLRequestJobFactory::IsHandledProtocol,
base::Unretained(job_factory_), scheme),
callback);
}
void Protocol::RegisterProtocol(v8::Isolate* isolate,
const std::string& 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,
const std::string& scheme,
const JsCompletionCallback& callback) {
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
base::Bind(&Protocol::UnregisterProtocolInIO,
base::Unretained(this), scheme),
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::Unretained(this), scheme),
base::Bind(&Protocol::OnIOActionCompleted,
base::Unretained(this), callback));
}
int Protocol::RegisterProtocolInIO(const std::string& scheme,
const JsProtocolHandler& handler) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (ContainsKey(protocol_handlers_, scheme) ||
job_factory_->IsHandledProtocol(scheme)) {
return ERR_SCHEME_REGISTERED;
}
protocol_handlers_[scheme] = handler;
job_factory_->SetProtocolHandler(scheme, new CustomProtocolHandler(this));
return OK;
}
int Protocol::UnregisterProtocolInIO(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);
job_factory_->SetProtocolHandler(scheme, NULL);
return OK;
}
int Protocol::InterceptProtocolInIO(const std::string& scheme,
const JsProtocolHandler& handler) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Force the request context to initialize, otherwise we might have nothing
// to intercept.
request_context_getter_->GetURLRequestContext();
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
mate::Handle<Protocol> Protocol::Create(
v8::Isolate* isolate, AtomBrowserContext* browser_context) {
return mate::CreateHandle(isolate, new Protocol(browser_context));
}
} // 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);
auto browser_context = static_cast<atom::AtomBrowserContext*>(
atom::AtomBrowserMainParts::Get()->browser_context());
dict.Set("protocol", atom::api::Protocol::Create(isolate, browser_context));
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_protocol, Initialize)

View File

@@ -0,0 +1,112 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_
#define ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_
#include <string>
#include <map>
#include <vector>
#include "atom/browser/api/event_emitter.h"
#include "base/callback.h"
#include "native_mate/handle.h"
#include "net/base/completion_callback.h"
namespace net {
class URLRequest;
class URLRequestContextGetter;
}
namespace atom {
class AtomBrowserContext;
class AtomURLRequestJobFactory;
namespace api {
class Protocol : public mate::EventEmitter {
public:
using JsProtocolHandler =
base::Callback<v8::Local<v8::Value>(const net::URLRequest*)>;
using JsCompletionCallback = base::Callback<void(v8::Local<v8::Value>)>;
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(
v8::Isolate* isolate, AtomBrowserContext* browser_context);
JsProtocolHandler GetProtocolHandler(const std::string& scheme);
net::URLRequestContextGetter* request_context_getter() {
return request_context_getter_.get();
}
protected:
explicit Protocol(AtomBrowserContext* browser_context);
// mate::Wrappable implementations:
virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate);
private:
typedef std::map<std::string, JsProtocolHandler> ProtocolHandlersMap;
// Callback called after performing action on IO thread.
void OnIOActionCompleted(const JsCompletionCallback& callback,
int error);
// Register schemes to standard scheme list.
void RegisterStandardSchemes(const std::vector<std::string>& schemes);
// Returns whether a scheme has been registered.
void IsHandledProtocol(const std::string& scheme,
const net::CompletionCallback& callback);
// Register/unregister an networking |scheme| which would be handled by
// |callback|.
void RegisterProtocol(v8::Isolate* isolate,
const std::string& scheme,
const JsProtocolHandler& handler,
const JsCompletionCallback& callback);
void UnregisterProtocol(v8::Isolate* isolate, const std::string& scheme,
const JsCompletionCallback& callback);
// Intercept/unintercept an existing protocol handler.
void InterceptProtocol(v8::Isolate* isolate,
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.
int RegisterProtocolInIO(const std::string& scheme,
const JsProtocolHandler& handler);
int UnregisterProtocolInIO(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_;
AtomURLRequestJobFactory* job_factory_;
ProtocolHandlersMap protocol_handlers_;
DISALLOW_COPY_AND_ASSIGN(Protocol);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_

View File

@@ -0,0 +1,144 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_screen.h"
#include <algorithm>
#include <string>
#include "atom/browser/browser.h"
#include "atom/common/native_mate_converters/gfx_converter.h"
#include "base/bind.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "ui/gfx/screen.h"
#include "atom/common/node_includes.h"
namespace atom {
namespace api {
namespace {
// Find an item in container according to its ID.
template<class T>
typename T::iterator FindById(T* container, int id) {
auto predicate = [id] (const typename T::value_type& item) -> bool {
return item.id() == id;
};
return std::find_if(container->begin(), container->end(), predicate);
}
// Convert the changed_metrics bitmask to string array.
std::vector<std::string> MetricsToArray(uint32_t metrics) {
std::vector<std::string> array;
if (metrics & gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS)
array.push_back("bounds");
if (metrics & gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA)
array.push_back("workArea");
if (metrics & gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR)
array.push_back("scaleFactor");
if (metrics & gfx::DisplayObserver::DISPLAY_METRIC_ROTATION)
array.push_back("rotaion");
return array;
}
} // namespace
Screen::Screen(gfx::Screen* screen) : screen_(screen) {
displays_ = screen_->GetAllDisplays();
screen_->AddObserver(this);
}
Screen::~Screen() {
screen_->RemoveObserver(this);
}
gfx::Point Screen::GetCursorScreenPoint() {
return screen_->GetCursorScreenPoint();
}
gfx::Display Screen::GetPrimaryDisplay() {
return screen_->GetPrimaryDisplay();
}
std::vector<gfx::Display> Screen::GetAllDisplays() {
return displays_;
}
gfx::Display Screen::GetDisplayNearestPoint(const gfx::Point& point) {
return screen_->GetDisplayNearestPoint(point);
}
gfx::Display Screen::GetDisplayMatching(const gfx::Rect& match_rect) {
return screen_->GetDisplayMatching(match_rect);
}
void Screen::OnDisplayAdded(const gfx::Display& new_display) {
displays_.push_back(new_display);
Emit("display-added", new_display);
}
void Screen::OnDisplayRemoved(const gfx::Display& old_display) {
auto iter = FindById(&displays_, old_display.id());
if (iter == displays_.end())
return;
displays_.erase(iter);
Emit("display-removed", old_display);
}
void Screen::OnDisplayMetricsChanged(const gfx::Display& display,
uint32_t changed_metrics) {
auto iter = FindById(&displays_, display.id());
if (iter == displays_.end())
return;
*iter = display;
Emit("display-metrics-changed", display, MetricsToArray(changed_metrics));
}
mate::ObjectTemplateBuilder Screen::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("getCursorScreenPoint", &Screen::GetCursorScreenPoint)
.SetMethod("getPrimaryDisplay", &Screen::GetPrimaryDisplay)
.SetMethod("getAllDisplays", &Screen::GetAllDisplays)
.SetMethod("getDisplayNearestPoint", &Screen::GetDisplayNearestPoint)
.SetMethod("getDisplayMatching", &Screen::GetDisplayMatching);
}
// static
v8::Local<v8::Value> Screen::Create(v8::Isolate* isolate) {
if (!Browser::Get()->is_ready()) {
node::ThrowError(isolate,
"Cannot initialize \"screen\" module before app is ready");
return v8::Null(isolate);
}
gfx::Screen* screen = gfx::Screen::GetNativeScreen();
if (!screen) {
node::ThrowError(isolate, "Failed to get screen information");
return v8::Null(isolate);
}
return mate::CreateHandle(isolate, new Screen(screen)).ToV8();
}
} // namespace api
} // namespace atom
namespace {
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
dict.Set("screen", atom::api::Screen::Create(context->GetIsolate()));
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_screen, Initialize)

View File

@@ -0,0 +1,60 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_API_SCREEN_H_
#define ATOM_BROWSER_API_ATOM_API_SCREEN_H_
#include <vector>
#include "atom/browser/api/event_emitter.h"
#include "native_mate/handle.h"
#include "ui/gfx/display_observer.h"
namespace gfx {
class Point;
class Rect;
class Screen;
}
namespace atom {
namespace api {
class Screen : public mate::EventEmitter,
public gfx::DisplayObserver {
public:
static v8::Local<v8::Value> Create(v8::Isolate* isolate);
protected:
explicit Screen(gfx::Screen* screen);
virtual ~Screen();
gfx::Point GetCursorScreenPoint();
gfx::Display GetPrimaryDisplay();
std::vector<gfx::Display> GetAllDisplays();
gfx::Display GetDisplayNearestPoint(const gfx::Point& point);
gfx::Display GetDisplayMatching(const gfx::Rect& match_rect);
// gfx::DisplayObserver:
void OnDisplayAdded(const gfx::Display& new_display) override;
void OnDisplayRemoved(const gfx::Display& old_display) override;
void OnDisplayMetricsChanged(const gfx::Display& display,
uint32_t changed_metrics) override;
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
private:
gfx::Screen* screen_;
std::vector<gfx::Display> displays_;
DISALLOW_COPY_AND_ASSIGN(Screen);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_SCREEN_H_

View File

@@ -0,0 +1,296 @@
// 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_session.h"
#include <string>
#include <vector>
#include "atom/browser/api/atom_api_cookies.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "base/files/file_path.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_util.h"
#include "base/thread_task_runner_handle.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "net/base/load_flags.h"
#include "net/disk_cache/disk_cache.h"
#include "net/proxy/proxy_service.h"
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "atom/common/node_includes.h"
using content::BrowserThread;
using content::StoragePartition;
namespace {
struct ClearStorageDataOptions {
GURL origin;
uint32 storage_types = StoragePartition::REMOVE_DATA_MASK_ALL;
uint32 quota_types = StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL;
};
uint32 GetStorageMask(const std::vector<std::string>& storage_types) {
uint32 storage_mask = 0;
for (const auto& it : storage_types) {
auto type = base::StringToLowerASCII(it);
if (type == "appcache")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_APPCACHE;
else if (type == "cookies")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_COOKIES;
else if (type == "filesystem")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS;
else if (type == "indexdb")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_INDEXEDDB;
else if (type == "localstorage")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE;
else if (type == "shadercache")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE;
else if (type == "websql")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_WEBSQL;
else if (type == "serviceworkers")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS;
}
return storage_mask;
}
uint32 GetQuotaMask(const std::vector<std::string>& quota_types) {
uint32 quota_mask = 0;
for (const auto& it : quota_types) {
auto type = base::StringToLowerASCII(it);
if (type == "temporary")
quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY;
else if (type == "persistent")
quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_PERSISTENT;
else if (type == "syncable")
quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_SYNCABLE;
}
return quota_mask;
}
} // namespace
namespace mate {
template<>
struct Converter<ClearStorageDataOptions> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
ClearStorageDataOptions* out) {
mate::Dictionary options;
if (!ConvertFromV8(isolate, val, &options))
return false;
options.Get("origin", &out->origin);
std::vector<std::string> types;
if (options.Get("storages", &types))
out->storage_types = GetStorageMask(types);
if (options.Get("quotas", &types))
out->quota_types = GetQuotaMask(types);
return true;
}
};
} // namespace mate
namespace atom {
namespace api {
namespace {
class ResolveProxyHelper {
public:
ResolveProxyHelper(AtomBrowserContext* browser_context,
const GURL& url,
Session::ResolveProxyCallback callback)
: callback_(callback),
original_thread_(base::ThreadTaskRunnerHandle::Get()) {
scoped_refptr<net::URLRequestContextGetter> context_getter =
browser_context->GetRequestContext();
context_getter->GetNetworkTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ResolveProxyHelper::ResolveProxy,
base::Unretained(this), context_getter, url));
}
void OnResolveProxyCompleted(int result) {
std::string proxy;
if (result == net::OK)
proxy = proxy_info_.ToPacString();
original_thread_->PostTask(FROM_HERE,
base::Bind(callback_, proxy));
delete this;
}
private:
void ResolveProxy(scoped_refptr<net::URLRequestContextGetter> context_getter,
const GURL& url) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
net::ProxyService* proxy_service =
context_getter->GetURLRequestContext()->proxy_service();
net::CompletionCallback completion_callback =
base::Bind(&ResolveProxyHelper::OnResolveProxyCompleted,
base::Unretained(this));
// Start the request.
int result = proxy_service->ResolveProxy(
url, net::LOAD_NORMAL, &proxy_info_, completion_callback,
&pac_req_, nullptr, net::BoundNetLog());
// Completed synchronously.
if (result != net::ERR_IO_PENDING)
completion_callback.Run(result);
}
Session::ResolveProxyCallback callback_;
net::ProxyInfo proxy_info_;
net::ProxyService::PacRequest* pac_req_;
scoped_refptr<base::SingleThreadTaskRunner> original_thread_;
DISALLOW_COPY_AND_ASSIGN(ResolveProxyHelper);
};
// Runs the callback in UI thread.
template <typename ...T>
void RunCallbackInUI(const base::Callback<void(T...)>& callback, T... result) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, base::Bind(callback, result...));
}
// Callback of HttpCache::GetBackend.
void OnGetBackend(disk_cache::Backend** backend_ptr,
const net::CompletionCallback& callback,
int result) {
if (result != net::OK) {
RunCallbackInUI(callback, result);
} else if (backend_ptr && *backend_ptr) {
(*backend_ptr)->DoomAllEntries(base::Bind(&RunCallbackInUI<int>, callback));
} else {
RunCallbackInUI<int>(callback, net::ERR_FAILED);
}
}
void ClearHttpCacheInIO(
const scoped_refptr<net::URLRequestContextGetter>& context_getter,
const net::CompletionCallback& callback) {
auto request_context = context_getter->GetURLRequestContext();
auto http_cache = request_context->http_transaction_factory()->GetCache();
if (!http_cache)
RunCallbackInUI<int>(callback, net::ERR_FAILED);
// Call GetBackend and make the backend's ptr accessable in OnGetBackend.
using BackendPtr = disk_cache::Backend*;
BackendPtr* backend_ptr = new BackendPtr(nullptr);
net::CompletionCallback on_get_backend =
base::Bind(&OnGetBackend, base::Owned(backend_ptr), callback);
int rv = http_cache->GetBackend(backend_ptr, on_get_backend);
if (rv != net::ERR_IO_PENDING)
on_get_backend.Run(net::OK);
}
void SetProxyInIO(net::URLRequestContextGetter* getter,
const std::string& proxy,
const base::Closure& callback) {
net::ProxyConfig config;
config.proxy_rules().ParseFromString(proxy);
auto proxy_service = getter->GetURLRequestContext()->proxy_service();
proxy_service->ResetConfigService(new net::ProxyConfigServiceFixed(config));
RunCallbackInUI(callback);
}
} // namespace
Session::Session(AtomBrowserContext* browser_context)
: browser_context_(browser_context) {
AttachAsUserData(browser_context);
}
Session::~Session() {
}
void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) {
new ResolveProxyHelper(browser_context_, url, callback);
}
void Session::ClearCache(const net::CompletionCallback& callback) {
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&ClearHttpCacheInIO,
make_scoped_refptr(browser_context_->GetRequestContext()),
callback));
}
void Session::ClearStorageData(mate::Arguments* args) {
// clearStorageData([options, ]callback)
ClearStorageDataOptions options;
args->GetNext(&options);
base::Closure callback;
if (!args->GetNext(&callback)) {
args->ThrowError();
return;
}
auto storage_partition =
content::BrowserContext::GetStoragePartition(browser_context_, nullptr);
storage_partition->ClearData(
options.storage_types, options.quota_types, options.origin,
content::StoragePartition::OriginMatcherFunction(),
base::Time(), base::Time::Max(), callback);
}
void Session::SetProxy(const std::string& proxy,
const base::Closure& callback) {
auto getter = browser_context_->GetRequestContext();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&SetProxyInIO, base::Unretained(getter), proxy, callback));
}
void Session::SetDownloadPath(const base::FilePath& path) {
browser_context_->prefs()->SetFilePath(
prefs::kDownloadDefaultDirectory, path);
}
v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
if (cookies_.IsEmpty()) {
auto handle = atom::api::Cookies::Create(isolate, browser_context_);
cookies_.Reset(isolate, handle.ToV8());
}
return v8::Local<v8::Value>::New(isolate, cookies_);
}
mate::ObjectTemplateBuilder Session::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("resolveProxy", &Session::ResolveProxy)
.SetMethod("clearCache", &Session::ClearCache)
.SetMethod("clearStorageData", &Session::ClearStorageData)
.SetMethod("setProxy", &Session::SetProxy)
.SetMethod("setDownloadPath", &Session::SetDownloadPath)
.SetProperty("cookies", &Session::Cookies);
}
// static
mate::Handle<Session> Session::CreateFrom(
v8::Isolate* isolate,
AtomBrowserContext* browser_context) {
auto existing = TrackableObject::FromWrappedClass(isolate, browser_context);
if (existing)
return mate::CreateHandle(isolate, static_cast<Session*>(existing));
return mate::CreateHandle(isolate, new Session(browser_context));
}
} // namespace api
} // namespace atom

View File

@@ -0,0 +1,67 @@
// 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_SESSION_H_
#define ATOM_BROWSER_API_ATOM_API_SESSION_H_
#include <string>
#include "atom/browser/api/trackable_object.h"
#include "native_mate/handle.h"
#include "net/base/completion_callback.h"
class GURL;
namespace base {
class FilePath;
}
namespace mate {
class Arguments;
}
namespace atom {
class AtomBrowserContext;
namespace api {
class Session: public mate::TrackableObject<Session> {
public:
using ResolveProxyCallback = base::Callback<void(std::string)>;
// Gets or creates Session from the |browser_context|.
static mate::Handle<Session> CreateFrom(
v8::Isolate* isolate, AtomBrowserContext* browser_context);
AtomBrowserContext* browser_context() const { return browser_context_; }
protected:
explicit Session(AtomBrowserContext* browser_context);
~Session();
// mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
private:
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
void ClearCache(const net::CompletionCallback& callback);
void ClearStorageData(mate::Arguments* args);
void SetProxy(const std::string& proxy, const base::Closure& callback);
void SetDownloadPath(const base::FilePath& path);
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
v8::Global<v8::Value> cookies_;
AtomBrowserContext* browser_context_; // weak ref
DISALLOW_COPY_AND_ASSIGN(Session);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_SESSION_H_

View File

@@ -0,0 +1,177 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_tray.h"
#include <string>
#include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/browser.h"
#include "atom/browser/ui/tray_icon.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/string16_converter.h"
#include "native_mate/constructor.h"
#include "native_mate/dictionary.h"
#include "ui/events/event_constants.h"
#include "ui/gfx/image/image.h"
#include "atom/common/node_includes.h"
namespace atom {
namespace api {
Tray::Tray(const gfx::Image& image)
: tray_icon_(TrayIcon::Create()) {
tray_icon_->SetImage(image);
tray_icon_->AddObserver(this);
}
Tray::~Tray() {
}
// static
mate::Wrappable* Tray::New(v8::Isolate* isolate, const gfx::Image& image) {
if (!Browser::Get()->is_ready()) {
node::ThrowError(isolate, "Cannot create Tray before app is ready");
return nullptr;
}
return new Tray(image);
}
void Tray::OnClicked(const gfx::Rect& bounds, int modifiers) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
EmitCustomEvent("clicked",
ModifiersToObject(isolate(), modifiers), bounds);
}
void Tray::OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
EmitCustomEvent("double-clicked",
ModifiersToObject(isolate(), modifiers), bounds);
}
void Tray::OnRightClicked(const gfx::Rect& bounds, int modifiers) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
EmitCustomEvent("right-clicked",
ModifiersToObject(isolate(), modifiers), bounds);
}
void Tray::OnBalloonShow() {
Emit("balloon-show");
}
void Tray::OnBalloonClicked() {
Emit("balloon-clicked");
}
void Tray::OnBalloonClosed() {
Emit("balloon-closed");
}
void Tray::OnDropFiles(const std::vector<std::string>& files) {
Emit("drop-files", files);
}
bool Tray::IsDestroyed() const {
return !tray_icon_;
}
void Tray::Destroy() {
tray_icon_.reset();
}
void Tray::SetImage(mate::Arguments* args, const gfx::Image& image) {
tray_icon_->SetImage(image);
}
void Tray::SetPressedImage(mate::Arguments* args, const gfx::Image& image) {
tray_icon_->SetPressedImage(image);
}
void Tray::SetToolTip(mate::Arguments* args, const std::string& tool_tip) {
tray_icon_->SetToolTip(tool_tip);
}
void Tray::SetTitle(mate::Arguments* args, const std::string& title) {
tray_icon_->SetTitle(title);
}
void Tray::SetHighlightMode(mate::Arguments* args, bool highlight) {
tray_icon_->SetHighlightMode(highlight);
}
void Tray::DisplayBalloon(mate::Arguments* args,
const mate::Dictionary& options) {
gfx::Image icon;
options.Get("icon", &icon);
base::string16 title, content;
if (!options.Get("title", &title) ||
!options.Get("content", &content)) {
args->ThrowError("'title' and 'content' must be defined");
return;
}
tray_icon_->DisplayBalloon(icon, title, content);
}
void Tray::PopUpContextMenu(mate::Arguments* args) {
gfx::Point pos;
args->GetNext(&pos);
tray_icon_->PopUpContextMenu(pos);
}
void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) {
tray_icon_->SetContextMenu(menu->model());
}
v8::Local<v8::Object> Tray::ModifiersToObject(v8::Isolate* isolate,
int modifiers) {
mate::Dictionary obj(isolate, v8::Object::New(isolate));
obj.Set("shiftKey", static_cast<bool>(modifiers & ui::EF_SHIFT_DOWN));
obj.Set("ctrlKey", static_cast<bool>(modifiers & ui::EF_CONTROL_DOWN));
obj.Set("altKey", static_cast<bool>(modifiers & ui::EF_ALT_DOWN));
obj.Set("metaKey", static_cast<bool>(modifiers & ui::EF_COMMAND_DOWN));
return obj.GetHandle();
}
// static
void Tray::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("destroy", &Tray::Destroy, true)
.SetMethod("setImage", &Tray::SetImage)
.SetMethod("setPressedImage", &Tray::SetPressedImage)
.SetMethod("setToolTip", &Tray::SetToolTip)
.SetMethod("setTitle", &Tray::SetTitle)
.SetMethod("setHighlightMode", &Tray::SetHighlightMode)
.SetMethod("displayBalloon", &Tray::DisplayBalloon)
.SetMethod("popUpContextMenu", &Tray::PopUpContextMenu)
.SetMethod("_setContextMenu", &Tray::SetContextMenu);
}
} // namespace api
} // namespace atom
namespace {
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
using atom::api::Tray;
v8::Isolate* isolate = context->GetIsolate();
v8::Local<v8::Function> constructor = mate::CreateConstructor<Tray>(
isolate, "Tray", base::Bind(&Tray::New));
mate::Dictionary dict(isolate, exports);
dict.Set("Tray", static_cast<v8::Local<v8::Value>>(constructor));
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_tray, Initialize)

View File

@@ -0,0 +1,78 @@
// Copyright (c) 2014 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_TRAY_H_
#define ATOM_BROWSER_API_ATOM_API_TRAY_H_
#include <string>
#include <vector>
#include "atom/browser/api/event_emitter.h"
#include "atom/browser/ui/tray_icon_observer.h"
#include "base/memory/scoped_ptr.h"
namespace gfx {
class Image;
}
namespace mate {
class Arguments;
class Dictionary;
}
namespace atom {
class TrayIcon;
namespace api {
class Menu;
class Tray : public mate::EventEmitter,
public TrayIconObserver {
public:
static mate::Wrappable* New(v8::Isolate* isolate, const gfx::Image& image);
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
protected:
explicit Tray(const gfx::Image& image);
virtual ~Tray();
// TrayIconObserver:
void OnClicked(const gfx::Rect& bounds, int modifiers) override;
void OnDoubleClicked(const gfx::Rect& bounds, int modifiers) override;
void OnRightClicked(const gfx::Rect& bounds, int modifiers) override;
void OnBalloonShow() override;
void OnBalloonClicked() override;
void OnBalloonClosed() override;
void OnDropFiles(const std::vector<std::string>& files) override;
// mate::Wrappable:
bool IsDestroyed() const override;
void Destroy();
void SetImage(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 SetTitle(mate::Arguments* args, const std::string& title);
void SetHighlightMode(mate::Arguments* args, bool highlight);
void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options);
void PopUpContextMenu(mate::Arguments* args);
void SetContextMenu(mate::Arguments* args, Menu* menu);
private:
v8::Local<v8::Object> ModifiersToObject(v8::Isolate* isolate, int modifiers);
scoped_ptr<TrayIcon> tray_icon_;
DISALLOW_COPY_AND_ASSIGN(Tray);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_TRAY_H_

View File

@@ -0,0 +1,911 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_web_contents.h"
#include <set>
#include "atom/browser/api/atom_api_session.h"
#include "atom/browser/atom_browser_client.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/native_window.h"
#include "atom/browser/web_view_guest_delegate.h"
#include "atom/common/api/api_messages.h"
#include "atom/common/api/event_emitter_caller.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/gfx_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/string16_converter.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "chrome/browser/printing/print_view_manager_basic.h"
#include "chrome/browser/printing/print_preview_message_handler.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/resource_request_details.h"
#include "content/public/browser/service_worker_context.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/static_http_user_agent_settings.h"
#include "net/url_request/url_request_context.h"
#include "atom/common/node_includes.h"
namespace {
struct PrintSettings {
bool silent;
bool print_background;
};
void SetUserAgentInIO(scoped_refptr<net::URLRequestContextGetter> getter,
std::string user_agent) {
getter->GetURLRequestContext()->set_http_user_agent_settings(
new net::StaticHttpUserAgentSettings("en-us,en", user_agent));
}
} // namespace
namespace mate {
template<>
struct Converter<atom::SetSizeParams> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
atom::SetSizeParams* out) {
mate::Dictionary params;
if (!ConvertFromV8(isolate, val, &params))
return false;
bool autosize;
if (params.Get("enableAutoSize", &autosize))
out->enable_auto_size.reset(new bool(true));
gfx::Size size;
if (params.Get("min", &size))
out->min_size.reset(new gfx::Size(size));
if (params.Get("max", &size))
out->max_size.reset(new gfx::Size(size));
if (params.Get("normal", &size))
out->normal_size.reset(new gfx::Size(size));
return true;
}
};
template<>
struct Converter<PrintSettings> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
PrintSettings* out) {
mate::Dictionary dict;
if (!ConvertFromV8(isolate, val, &dict))
return false;
dict.Get("silent", &(out->silent));
dict.Get("printBackground", &(out->print_background));
return true;
}
};
template<>
struct Converter<WindowOpenDisposition> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
WindowOpenDisposition val) {
std::string disposition = "other";
switch (val) {
case CURRENT_TAB: disposition = "default"; break;
case NEW_FOREGROUND_TAB: disposition = "foreground-tab"; break;
case NEW_BACKGROUND_TAB: disposition = "background-tab"; break;
case NEW_POPUP: case NEW_WINDOW: disposition = "new-window"; break;
default: break;
}
return mate::ConvertToV8(isolate, disposition);
}
};
} // namespace mate
namespace atom {
namespace api {
namespace {
v8::Persistent<v8::ObjectTemplate> template_;
// The wrapWebContents funtion which is implemented in JavaScript
using WrapWebContentsCallback = base::Callback<void(v8::Local<v8::Value>)>;
WrapWebContentsCallback g_wrap_web_contents;
content::ServiceWorkerContext* GetServiceWorkerContext(
const content::WebContents* web_contents) {
auto context = web_contents->GetBrowserContext();
auto site_instance = web_contents->GetSiteInstance();
if (!context || !site_instance)
return nullptr;
auto storage_partition =
content::BrowserContext::GetStoragePartition(context, site_instance);
if (!storage_partition)
return nullptr;
return storage_partition->GetServiceWorkerContext();
}
} // namespace
WebContents::WebContents(content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
type_(REMOTE) {
AttachAsUserData(web_contents);
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
}
WebContents::WebContents(const mate::Dictionary& options) {
bool is_guest = false;
options.Get("isGuest", &is_guest);
type_ = is_guest ? WEB_VIEW : BROWSER_WINDOW;
auto browser_context = AtomBrowserMainParts::Get()->browser_context();
content::WebContents* web_contents;
if (is_guest) {
content::SiteInstance* site_instance = content::SiteInstance::CreateForURL(
browser_context, GURL("chrome-guest://fake-host"));
content::WebContents::CreateParams params(browser_context, site_instance);
guest_delegate_.reset(new WebViewGuestDelegate);
params.guest_delegate = guest_delegate_.get();
web_contents = content::WebContents::Create(params);
} else {
content::WebContents::CreateParams params(browser_context);
web_contents = content::WebContents::Create(params);
}
Observe(web_contents);
AttachAsUserData(web_contents);
InitWithWebContents(web_contents);
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
if (is_guest) {
guest_delegate_->Initialize(this);
NativeWindow* owner_window = nullptr;
WebContents* embedder = nullptr;
if (options.Get("embedder", &embedder) && embedder) {
// New WebContents's owner_window is the embedder's owner_window.
auto relay = NativeWindowRelay::FromWebContents(embedder->web_contents());
if (relay)
owner_window = relay->window.get();
}
if (owner_window)
SetOwnerWindow(owner_window);
}
}
WebContents::~WebContents() {
Destroy();
}
bool WebContents::AddMessageToConsole(content::WebContents* source,
int32 level,
const base::string16& message,
int32 line_no,
const base::string16& source_id) {
if (type_ == BROWSER_WINDOW) {
return false;
} else {
Emit("console-message", level, message, line_no, source_id);
return true;
}
}
bool WebContents::ShouldCreateWebContents(
content::WebContents* web_contents,
int route_id,
int main_frame_route_id,
WindowContainerType window_container_type,
const base::string16& frame_name,
const GURL& target_url,
const std::string& partition_id,
content::SessionStorageNamespace* session_storage_namespace) {
if (type_ == BROWSER_WINDOW)
Emit("-new-window", target_url, frame_name, NEW_FOREGROUND_TAB);
else
Emit("new-window", target_url, frame_name, NEW_FOREGROUND_TAB);
return false;
}
content::WebContents* WebContents::OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params) {
if (params.disposition != CURRENT_TAB) {
if (type_ == BROWSER_WINDOW)
Emit("-new-window", params.url, "", params.disposition);
else
Emit("new-window", params.url, "", params.disposition);
return nullptr;
}
// Give user a chance to cancel navigation.
if (Emit("will-navigate", params.url))
return nullptr;
return CommonWebContentsDelegate::OpenURLFromTab(source, params);
}
void WebContents::BeforeUnloadFired(content::WebContents* tab,
bool proceed,
bool* proceed_to_fire_unload) {
if (type_ == BROWSER_WINDOW)
*proceed_to_fire_unload = proceed;
else
*proceed_to_fire_unload = true;
}
void WebContents::MoveContents(content::WebContents* source,
const gfx::Rect& pos) {
Emit("move", pos);
}
void WebContents::CloseContents(content::WebContents* source) {
Emit("close");
if (type_ == BROWSER_WINDOW)
owner_window()->CloseContents(source);
}
void WebContents::ActivateContents(content::WebContents* source) {
Emit("activate");
}
bool WebContents::IsPopupOrPanel(const content::WebContents* source) const {
return type_ == BROWSER_WINDOW;
}
void WebContents::HandleKeyboardEvent(
content::WebContents* source,
const content::NativeWebKeyboardEvent& event) {
if (type_ == BROWSER_WINDOW) {
owner_window()->HandleKeyboardEvent(source, event);
} else if (type_ == WEB_VIEW && guest_delegate_) {
// Send the unhandled keyboard events back to the embedder.
guest_delegate_->HandleKeyboardEvent(source, event);
}
}
void WebContents::EnterFullscreenModeForTab(content::WebContents* source,
const GURL& origin) {
CommonWebContentsDelegate::EnterFullscreenModeForTab(source, origin);
Emit("enter-html-full-screen");
}
void WebContents::ExitFullscreenModeForTab(content::WebContents* source) {
CommonWebContentsDelegate::ExitFullscreenModeForTab(source);
Emit("leave-html-full-screen");
}
void WebContents::RendererUnresponsive(content::WebContents* source) {
Emit("unresponsive");
if (type_ == BROWSER_WINDOW)
owner_window()->RendererUnresponsive(source);
}
void WebContents::RendererResponsive(content::WebContents* source) {
Emit("responsive");
if (type_ == BROWSER_WINDOW)
owner_window()->RendererResponsive(source);
}
void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
// Do nothing, we override this method just to avoid compilation error since
// there are two virtual functions named BeforeUnloadFired.
}
void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
int process_id = render_view_host->GetProcess()->GetID();
Emit("render-view-deleted", process_id);
// process.emit('ATOM_BROWSER_RELEASE_RENDER_VIEW', processId);
// Tell the rpc server that a render view has been deleted and we need to
// release all objects owned by it.
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
node::Environment* env = node::Environment::GetCurrent(isolate());
mate::EmitEvent(isolate(), env->process_object(),
"ATOM_BROWSER_RELEASE_RENDER_VIEW", process_id);
}
void WebContents::RenderProcessGone(base::TerminationStatus status) {
Emit("crashed");
}
void WebContents::PluginCrashed(const base::FilePath& plugin_path,
base::ProcessId plugin_pid) {
content::WebPluginInfo info;
auto plugin_service = content::PluginService::GetInstance();
plugin_service->GetPluginInfoByPath(plugin_path, &info);
Emit("plugin-crashed", info.name, info.version);
}
void WebContents::DocumentLoadedInFrame(
content::RenderFrameHost* render_frame_host) {
if (!render_frame_host->GetParent())
Emit("dom-ready");
}
void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url) {
bool is_main_frame = !render_frame_host->GetParent();
Emit("did-frame-finish-load", is_main_frame);
if (is_main_frame)
Emit("did-finish-load");
}
// this error occurs when host could not be found
void WebContents::DidFailProvisionalLoad(
content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
const base::string16& error_description) {
Emit("did-fail-load", error_code, error_description);
}
void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
const base::string16& error_description) {
Emit("did-fail-load", error_code, error_description);
}
void WebContents::DidStartLoading() {
Emit("did-start-loading");
}
void WebContents::DidStopLoading() {
Emit("did-stop-loading");
}
void WebContents::DidGetResourceResponseStart(
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",
details.socket_address.IsEmpty(),
details.url,
details.original_url,
details.http_response_code,
details.method,
details.referrer,
response_headers);
}
void WebContents::DidGetRedirectForResourceRequest(
content::RenderFrameHost* render_frame_host,
const content::ResourceRedirectDetails& details) {
Emit("did-get-redirect-request",
details.url,
details.new_url,
(details.resource_type == content::RESOURCE_TYPE_MAIN_FRAME));
}
void WebContents::DidNavigateMainFrame(
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) {
if (details.is_navigation_to_different_page())
Emit("did-navigate-to-different-page");
}
void WebContents::TitleWasSet(content::NavigationEntry* entry,
bool explicit_set) {
// Back/Forward navigation may have pruned entries.
if (entry)
Emit("page-title-set", entry->GetTitle(), explicit_set);
}
void WebContents::DidUpdateFaviconURL(
const std::vector<content::FaviconURL>& urls) {
std::set<GURL> unique_urls;
for (auto iter = urls.begin(); iter != urls.end(); ++iter) {
if (iter->icon_type != content::FaviconURL::FAVICON)
continue;
const GURL& url = iter->icon_url;
if (url.is_valid())
unique_urls.insert(url);
}
Emit("page-favicon-updated", unique_urls);
}
bool WebContents::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(WebContents, message)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
OnRendererMessageSync)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void WebContents::WebContentsDestroyed() {
// The RenderViewDeleted was not called when the WebContents is destroyed.
RenderViewDeleted(web_contents()->GetRenderViewHost());
Emit("destroyed");
RemoveFromWeakMap();
}
void WebContents::NavigationEntryCommitted(
const content::LoadCommittedDetails& details) {
Emit("navigation-entry-commited", details.entry->GetURL(),
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 {
return web_contents()->GetRenderProcessHost()->GetID();
}
bool WebContents::Equal(const WebContents* web_contents) const {
return GetID() == web_contents->GetID();
}
void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
content::NavigationController::LoadURLParams params(url);
GURL http_referrer;
if (options.Get("httpReferrer", &http_referrer))
params.referrer = content::Referrer(http_referrer.GetAsReferrer(),
blink::WebReferrerPolicyDefault);
std::string user_agent;
if (options.Get("userAgent", &user_agent))
SetUserAgent(user_agent);
params.transition_type = ui::PAGE_TRANSITION_TYPED;
params.should_clear_history_list = true;
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
web_contents()->GetController().LoadURLWithParams(params);
}
base::string16 WebContents::GetTitle() const {
return web_contents()->GetTitle();
}
bool WebContents::IsLoading() const {
return web_contents()->IsLoading();
}
bool WebContents::IsWaitingForResponse() const {
return web_contents()->IsWaitingForResponse();
}
void WebContents::Stop() {
web_contents()->Stop();
}
void WebContents::ReloadIgnoringCache() {
web_contents()->GetController().ReloadIgnoringCache(false);
}
void WebContents::GoBack() {
atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
web_contents()->GetController().GoBack();
}
void WebContents::GoForward() {
atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
web_contents()->GetController().GoForward();
}
void WebContents::GoToOffset(int offset) {
atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
web_contents()->GetController().GoToOffset(offset);
}
bool WebContents::IsCrashed() const {
return web_contents()->IsCrashed();
}
void WebContents::SetUserAgent(const std::string& user_agent) {
web_contents()->SetUserAgentOverride(user_agent);
scoped_refptr<net::URLRequestContextGetter> getter =
web_contents()->GetBrowserContext()->GetRequestContext();
getter->GetNetworkTaskRunner()->PostTask(FROM_HERE,
base::Bind(&SetUserAgentInIO, getter, user_agent));
}
std::string WebContents::GetUserAgent() {
return web_contents()->GetUserAgentOverride();
}
void WebContents::InsertCSS(const std::string& css) {
web_contents()->InsertCSS(css);
}
void WebContents::ExecuteJavaScript(const base::string16& code,
bool has_user_gesture) {
Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture));
}
void WebContents::OpenDevTools(mate::Arguments* args) {
if (type_ == REMOTE)
return;
bool detach = false;
if (type_ == WEB_VIEW) {
detach = true;
} else if (args && args->Length() == 1) {
mate::Dictionary options;
args->GetNext(&options) && options.Get("detach", &detach);
}
managed_web_contents()->SetCanDock(!detach);
managed_web_contents()->ShowDevTools();
}
void WebContents::CloseDevTools() {
if (type_ == REMOTE)
return;
managed_web_contents()->CloseDevTools();
}
bool WebContents::IsDevToolsOpened() {
if (type_ == REMOTE)
return false;
return managed_web_contents()->IsDevToolsViewShowing();
}
void WebContents::ToggleDevTools() {
if (IsDevToolsOpened())
CloseDevTools();
else
OpenDevTools(nullptr);
}
void WebContents::InspectElement(int x, int y) {
if (type_ == REMOTE)
return;
OpenDevTools(nullptr);
scoped_refptr<content::DevToolsAgentHost> agent(
content::DevToolsAgentHost::GetOrCreateFor(web_contents()));
agent->InspectElement(x, y);
}
void WebContents::InspectServiceWorker() {
if (type_ == REMOTE)
return;
for (const auto& agent_host : content::DevToolsAgentHost::GetOrCreateAll()) {
if (agent_host->GetType() ==
content::DevToolsAgentHost::TYPE_SERVICE_WORKER) {
OpenDevTools(nullptr);
managed_web_contents()->AttachTo(agent_host);
break;
}
}
}
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(
const base::Callback<void(bool)>& callback) {
auto context = GetServiceWorkerContext(web_contents());
if (!context)
return;
context->CheckHasServiceWorker(web_contents()->GetLastCommittedURL(),
GURL::EmptyGURL(),
callback);
}
void WebContents::UnregisterServiceWorker(
const base::Callback<void(bool)>& callback) {
auto context = GetServiceWorkerContext(web_contents());
if (!context)
return;
context->UnregisterServiceWorker(web_contents()->GetLastCommittedURL(),
callback);
}
void WebContents::SetAudioMuted(bool muted) {
web_contents()->SetAudioMuted(muted);
}
bool WebContents::IsAudioMuted() {
return web_contents()->IsAudioMuted();
}
void WebContents::Print(mate::Arguments* args) {
PrintSettings settings = { false, false };
if (args->Length() == 1 && !args->GetNext(&settings)) {
args->ThrowError();
return;
}
printing::PrintViewManagerBasic::FromWebContents(web_contents())->
PrintNow(settings.silent, settings.print_background);
}
void WebContents::PrintToPDF(const base::DictionaryValue& setting,
const PrintToPDFCallback& callback) {
printing::PrintPreviewMessageHandler::FromWebContents(web_contents())->
PrintToPDF(setting, callback);
}
void WebContents::AddWorkSpace(const base::FilePath& path) {
if (path.empty()) {
node::ThrowError(isolate(), "path cannot be empty");
return;
}
DevToolsAddFileSystem(path);
}
void WebContents::RemoveWorkSpace(const base::FilePath& path) {
if (path.empty()) {
node::ThrowError(isolate(), "path cannot be empty");
return;
}
DevToolsRemoveFileSystem(path);
}
void WebContents::Undo() {
web_contents()->Undo();
}
void WebContents::Redo() {
web_contents()->Redo();
}
void WebContents::Cut() {
web_contents()->Cut();
}
void WebContents::Copy() {
web_contents()->Copy();
}
void WebContents::Paste() {
web_contents()->Paste();
}
void WebContents::PasteAndMatchStyle() {
web_contents()->PasteAndMatchStyle();
}
void WebContents::Delete() {
web_contents()->Delete();
}
void WebContents::SelectAll() {
web_contents()->SelectAll();
}
void WebContents::Unselect() {
web_contents()->Unselect();
}
void WebContents::Replace(const base::string16& word) {
web_contents()->Replace(word);
}
void WebContents::ReplaceMisspelling(const base::string16& word) {
web_contents()->ReplaceMisspelling(word);
}
void WebContents::Focus() {
web_contents()->Focus();
}
void WebContents::TabTraverse(bool reverse) {
web_contents()->FocusThroughTabTraversal(reverse);
}
bool WebContents::SendIPCMessage(const base::string16& channel,
const base::ListValue& args) {
return Send(new AtomViewMsg_Message(routing_id(), channel, args));
}
void WebContents::SetSize(const SetSizeParams& params) {
if (guest_delegate_)
guest_delegate_->SetSize(params);
}
void WebContents::SetAllowTransparency(bool allow) {
if (guest_delegate_)
guest_delegate_->SetAllowTransparency(allow);
}
bool WebContents::IsGuest() const {
return type_ == WEB_VIEW;
}
mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
if (template_.IsEmpty())
template_.Reset(isolate, mate::ObjectTemplateBuilder(isolate)
.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 {
return !IsAlive();
}
AtomBrowserContext* WebContents::GetBrowserContext() const {
return static_cast<AtomBrowserContext*>(web_contents()->GetBrowserContext());
}
void WebContents::OnRendererMessage(const base::string16& channel,
const base::ListValue& args) {
// webContents.emit(channel, new Event(), args...);
Emit(base::UTF16ToUTF8(channel), args);
}
void WebContents::OnRendererMessageSync(const base::string16& channel,
const base::ListValue& args,
IPC::Message* message) {
// webContents.emit(channel, new Event(sender, message), args...);
EmitWithSender(base::UTF16ToUTF8(channel), web_contents(), message, args);
}
// static
mate::Handle<WebContents> WebContents::CreateFrom(
v8::Isolate* isolate, content::WebContents* web_contents) {
// We have an existing WebContents object in JS.
auto existing = TrackableObject::FromWrappedClass(isolate, web_contents);
if (existing)
return mate::CreateHandle(isolate, static_cast<WebContents*>(existing));
// Otherwise create a new WebContents wrapper object.
auto handle = mate::CreateHandle(isolate, new WebContents(web_contents));
g_wrap_web_contents.Run(handle.ToV8());
return handle;
}
// static
mate::Handle<WebContents> WebContents::Create(
v8::Isolate* isolate, const mate::Dictionary& options) {
auto handle = mate::CreateHandle(isolate, new WebContents(options));
g_wrap_web_contents.Run(handle.ToV8());
return handle;
}
void SetWrapWebContents(const WrapWebContentsCallback& callback) {
g_wrap_web_contents = callback;
}
void ClearWrapWebContents() {
g_wrap_web_contents.Reset();
}
} // 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("create", &atom::api::WebContents::Create);
dict.SetMethod("_setWrapWebContents", &atom::api::SetWrapWebContents);
dict.SetMethod("_clearWrapWebContents", &atom::api::ClearWrapWebContents);
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_web_contents, Initialize)

View File

@@ -0,0 +1,230 @@
// Copyright (c) 2014 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_CONTENTS_H_
#define ATOM_BROWSER_API_ATOM_API_WEB_CONTENTS_H_
#include <string>
#include <vector>
#include "atom/browser/api/trackable_object.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 "native_mate/handle.h"
#include "ui/gfx/image/image.h"
namespace brightray {
class InspectableWebContents;
}
namespace mate {
class Arguments;
class Dictionary;
}
namespace atom {
struct SetSizeParams;
class AtomBrowserContext;
class WebViewGuestDelegate;
namespace api {
class WebContents : public mate::TrackableObject<WebContents>,
public CommonWebContentsDelegate,
public content::WebContentsObserver {
public:
// For node.js callback function type: function(error, buffer)
using PrintToPDFCallback =
base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>;
// Create from an existing WebContents.
static mate::Handle<WebContents> CreateFrom(
v8::Isolate* isolate, content::WebContents* web_contents);
// Create a new WebContents.
static mate::Handle<WebContents> Create(
v8::Isolate* isolate, const mate::Dictionary& options);
void Destroy();
bool IsAlive() const;
int GetID() const;
bool Equal(const WebContents* web_contents) const;
void LoadURL(const GURL& url, const mate::Dictionary& options);
base::string16 GetTitle() const;
bool IsLoading() const;
bool IsWaitingForResponse() const;
void Stop();
void ReloadIgnoringCache();
void GoBack();
void GoForward();
void GoToOffset(int offset);
bool IsCrashed() const;
void SetUserAgent(const std::string& user_agent);
std::string GetUserAgent();
void InsertCSS(const std::string& css);
void ExecuteJavaScript(const base::string16& code,
bool has_user_gesture);
void OpenDevTools(mate::Arguments* args);
void CloseDevTools();
bool IsDevToolsOpened();
void ToggleDevTools();
void InspectElement(int x, int y);
void InspectServiceWorker();
v8::Local<v8::Value> Session(v8::Isolate* isolate);
void HasServiceWorker(const base::Callback<void(bool)>&);
void UnregisterServiceWorker(const base::Callback<void(bool)>&);
void SetAudioMuted(bool muted);
bool IsAudioMuted();
void Print(mate::Arguments* args);
// Print current page as PDF.
void PrintToPDF(const base::DictionaryValue& setting,
const PrintToPDFCallback& callback);
// DevTools workspace api.
void AddWorkSpace(const base::FilePath& path);
void RemoveWorkSpace(const base::FilePath& path);
// Editing commands.
void Undo();
void Redo();
void Cut();
void Copy();
void Paste();
void PasteAndMatchStyle();
void Delete();
void SelectAll();
void Unselect();
void Replace(const base::string16& word);
void ReplaceMisspelling(const base::string16& word);
// Focus.
void Focus();
void TabTraverse(bool reverse);
// Sending messages to browser.
bool SendIPCMessage(const base::string16& channel,
const base::ListValue& args);
// Methods for creating <webview>.
void SetSize(const SetSizeParams& params);
void SetAllowTransparency(bool allow);
bool IsGuest() const;
protected:
explicit WebContents(content::WebContents* web_contents);
explicit WebContents(const mate::Dictionary& options);
~WebContents();
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
// content::WebContentsDelegate:
bool AddMessageToConsole(content::WebContents* source,
int32 level,
const base::string16& message,
int32 line_no,
const base::string16& source_id) override;
bool ShouldCreateWebContents(
content::WebContents* web_contents,
int route_id,
int main_frame_route_id,
WindowContainerType window_container_type,
const base::string16& frame_name,
const GURL& target_url,
const std::string& partition_id,
content::SessionStorageNamespace* session_storage_namespace) override;
content::WebContents* OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params) override;
void BeforeUnloadFired(content::WebContents* tab,
bool proceed,
bool* proceed_to_fire_unload) override;
void MoveContents(content::WebContents* source,
const gfx::Rect& pos) override;
void CloseContents(content::WebContents* source) override;
void ActivateContents(content::WebContents* contents) override;
bool IsPopupOrPanel(const content::WebContents* source) const override;
void HandleKeyboardEvent(
content::WebContents* source,
const content::NativeWebKeyboardEvent& event) override;
void EnterFullscreenModeForTab(content::WebContents* source,
const GURL& origin) override;
void ExitFullscreenModeForTab(content::WebContents* source) override;
void RendererUnresponsive(content::WebContents* source) override;
void RendererResponsive(content::WebContents* source) override;
// content::WebContentsObserver:
void BeforeUnloadFired(const base::TimeTicks& proceed_time) override;
void RenderViewDeleted(content::RenderViewHost*) override;
void RenderProcessGone(base::TerminationStatus status) override;
void DocumentLoadedInFrame(
content::RenderFrameHost* render_frame_host) override;
void DidFinishLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url) override;
void DidFailLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
const base::string16& error_description) override;
void DidFailProvisionalLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
const base::string16& error_description) override;
void DidStartLoading() override;
void DidStopLoading() override;
void DidGetResourceResponseStart(
const content::ResourceRequestDetails& details) override;
void DidGetRedirectForResourceRequest(
content::RenderFrameHost* render_frame_host,
const content::ResourceRedirectDetails& details) override;
void DidNavigateMainFrame(
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) override;
bool OnMessageReceived(const IPC::Message& message) override;
void WebContentsDestroyed() override;
void NavigationEntryCommitted(
const content::LoadCommittedDetails& load_details) override;
void TitleWasSet(content::NavigationEntry* entry, bool explicit_set) override;
void DidUpdateFaviconURL(
const std::vector<content::FaviconURL>& urls) override;
void PluginCrashed(const base::FilePath& plugin_path,
base::ProcessId plugin_pid) override;
private:
enum Type {
BROWSER_WINDOW, // Used by BrowserWindow.
WEB_VIEW, // Used by <webview>.
REMOTE, // Thin wrap around an existing WebContents.
};
AtomBrowserContext* GetBrowserContext() const;
// Called when received a message from renderer.
void OnRendererMessage(const base::string16& channel,
const base::ListValue& args);
// Called when received a synchronous message from renderer.
void OnRendererMessageSync(const base::string16& channel,
const base::ListValue& args,
IPC::Message* message);
v8::Global<v8::Value> session_;
scoped_ptr<WebViewGuestDelegate> guest_delegate_;
// The type of current WebContents.
Type type_;
DISALLOW_COPY_AND_ASSIGN(WebContents);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_WEB_CONTENTS_H_

View File

@@ -0,0 +1,93 @@
// 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_contents.h"
#include "atom/browser/web_view_manager.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "content/public/browser/browser_context.h"
#include "native_mate/dictionary.h"
#include "net/base/filename_util.h"
#include "atom/common/node_includes.h"
namespace mate {
template<>
struct Converter<content::WebContents*> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
content::WebContents** out) {
atom::api::WebContents* contents;
if (!Converter<atom::api::WebContents*>::FromV8(isolate, val, &contents))
return false;
*out = contents->web_contents();
return true;
}
};
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 {
atom::WebViewManager* GetWebViewManager(content::WebContents* web_contents) {
auto context = web_contents->GetBrowserContext();
if (context) {
auto manager = context->GetGuestManager();
return static_cast<atom::WebViewManager*>(manager);
} else {
return nullptr;
}
}
void AddGuest(int guest_instance_id,
int element_instance_id,
content::WebContents* embedder,
content::WebContents* guest_web_contents,
atom::WebViewManager::WebViewInfo info) {
auto manager = GetWebViewManager(embedder);
if (manager) {
info.guest_instance_id = guest_instance_id;
info.embedder = embedder;
manager->AddGuest(guest_instance_id, element_instance_id, embedder,
guest_web_contents, info);
}
}
void RemoveGuest(content::WebContents* embedder, int guest_instance_id) {
auto manager = GetWebViewManager(embedder);
if (manager)
manager->RemoveGuest(guest_instance_id);
}
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("addGuest", &AddGuest);
dict.SetMethod("removeGuest", &RemoveGuest);
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_web_view_manager, Initialize)

View File

@@ -0,0 +1,626 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_window.h"
#include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/browser.h"
#include "atom/browser/native_window.h"
#include "atom/common/native_mate_converters/callback.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/image_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "content/public/browser/render_process_host.h"
#include "native_mate/constructor.h"
#include "native_mate/dictionary.h"
#include "ui/gfx/geometry/rect.h"
#if defined(OS_WIN)
#include "atom/browser/native_window_views.h"
#include "atom/browser/ui/win/taskbar_host.h"
#endif
#include "atom/common/node_includes.h"
#if defined(OS_WIN)
namespace mate {
template<>
struct Converter<atom::TaskbarHost::ThumbarButton> {
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val,
atom::TaskbarHost::ThumbarButton* out) {
mate::Dictionary dict;
if (!ConvertFromV8(isolate, val, &dict))
return false;
dict.Get("click", &(out->clicked_callback));
dict.Get("tooltip", &(out->tooltip));
dict.Get("flags", &out->flags);
return dict.Get("icon", &(out->icon));
}
};
} // namespace mate
#endif
namespace atom {
namespace api {
namespace {
void OnCapturePageDone(
v8::Isolate* isolate,
const base::Callback<void(const gfx::Image&)>& callback,
const SkBitmap& bitmap) {
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap));
}
} // namespace
Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
// Creates the WebContents used by BrowserWindow.
mate::Dictionary web_contents_options(isolate, v8::Object::New(isolate));
auto web_contents = WebContents::Create(isolate, web_contents_options);
web_contents_.Reset(isolate, web_contents.ToV8());
api_web_contents_ = web_contents.get();
// Creates BrowserWindow.
window_.reset(NativeWindow::Create(web_contents->managed_web_contents(),
options));
web_contents->SetOwnerWindow(window_.get());
window_->InitFromOptions(options);
window_->AddObserver(this);
}
Window::~Window() {
if (window_)
Destroy();
}
void Window::OnPageTitleUpdated(bool* prevent_default,
const std::string& title) {
*prevent_default = Emit("page-title-updated", title);
}
void Window::WillCloseWindow(bool* prevent_default) {
*prevent_default = Emit("close");
}
void Window::OnWindowClosed() {
if (api_web_contents_) {
api_web_contents_->DestroyWebContents();
api_web_contents_ = nullptr;
web_contents_.Reset();
}
RemoveFromWeakMap();
window_->RemoveObserver(this);
Emit("closed");
}
void Window::OnWindowBlur() {
Emit("blur");
}
void Window::OnWindowFocus() {
Emit("focus");
}
void Window::OnWindowMaximize() {
Emit("maximize");
}
void Window::OnWindowUnmaximize() {
Emit("unmaximize");
}
void Window::OnWindowMinimize() {
Emit("minimize");
}
void Window::OnWindowRestore() {
Emit("restore");
}
void Window::OnWindowResize() {
Emit("resize");
}
void Window::OnWindowMove() {
Emit("move");
}
void Window::OnWindowMoved() {
Emit("moved");
}
void Window::OnWindowEnterFullScreen() {
Emit("enter-full-screen");
}
void Window::OnWindowLeaveFullScreen() {
Emit("leave-full-screen");
}
void Window::OnWindowEnterHtmlFullScreen() {
Emit("enter-html-full-screen");
}
void Window::OnWindowLeaveHtmlFullScreen() {
Emit("leave-html-full-screen");
}
void Window::OnRendererUnresponsive() {
Emit("unresponsive");
}
void Window::OnRendererResponsive() {
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) {
Emit("app-command", command_name);
}
// static
mate::Wrappable* Window::New(v8::Isolate* isolate,
const mate::Dictionary& options) {
if (!Browser::Get()->is_ready()) {
node::ThrowError(isolate,
"Cannot create BrowserWindow before app is ready");
return nullptr;
}
return new Window(isolate, options);
}
bool Window::IsDestroyed() const {
return !window_ || window_->IsClosed();
}
void Window::Destroy() {
window_->CloseContents(nullptr);
}
void Window::Close() {
window_->Close();
}
bool Window::IsClosed() {
return window_->IsClosed();
}
void Window::Focus() {
window_->Focus(true);
}
bool Window::IsFocused() {
return window_->IsFocused();
}
void Window::Show() {
window_->Show();
}
void Window::ShowInactive() {
window_->ShowInactive();
}
void Window::Hide() {
window_->Hide();
}
bool Window::IsVisible() {
return window_->IsVisible();
}
void Window::Maximize() {
window_->Maximize();
}
void Window::Unmaximize() {
window_->Unmaximize();
}
bool Window::IsMaximized() {
return window_->IsMaximized();
}
void Window::Minimize() {
window_->Minimize();
}
void Window::Restore() {
window_->Restore();
}
bool Window::IsMinimized() {
return window_->IsMinimized();
}
void Window::SetFullScreen(bool fullscreen) {
window_->SetFullScreen(fullscreen);
}
bool Window::IsFullscreen() {
return window_->IsFullscreen();
}
void Window::SetBounds(const gfx::Rect& bounds) {
window_->SetBounds(bounds);
}
gfx::Rect Window::GetBounds() {
return window_->GetBounds();
}
void Window::SetSize(int width, int height) {
window_->SetSize(gfx::Size(width, height));
}
std::vector<int> Window::GetSize() {
std::vector<int> result(2);
gfx::Size size = window_->GetSize();
result[0] = size.width();
result[1] = size.height();
return result;
}
void Window::SetContentSize(int width, int height) {
window_->SetContentSize(gfx::Size(width, height));
}
std::vector<int> Window::GetContentSize() {
std::vector<int> result(2);
gfx::Size size = window_->GetContentSize();
result[0] = size.width();
result[1] = size.height();
return result;
}
void Window::SetMinimumSize(int width, int height) {
window_->SetMinimumSize(gfx::Size(width, height));
}
std::vector<int> Window::GetMinimumSize() {
std::vector<int> result(2);
gfx::Size size = window_->GetMinimumSize();
result[0] = size.width();
result[1] = size.height();
return result;
}
void Window::SetMaximumSize(int width, int height) {
window_->SetMaximumSize(gfx::Size(width, height));
}
std::vector<int> Window::GetMaximumSize() {
std::vector<int> result(2);
gfx::Size size = window_->GetMaximumSize();
result[0] = size.width();
result[1] = size.height();
return result;
}
void Window::SetResizable(bool resizable) {
window_->SetResizable(resizable);
}
bool Window::IsResizable() {
return window_->IsResizable();
}
void Window::SetAlwaysOnTop(bool top) {
window_->SetAlwaysOnTop(top);
}
bool Window::IsAlwaysOnTop() {
return window_->IsAlwaysOnTop();
}
void Window::Center() {
window_->Center();
}
void Window::SetPosition(int x, int y) {
window_->SetPosition(gfx::Point(x, y));
}
std::vector<int> Window::GetPosition() {
std::vector<int> result(2);
gfx::Point pos = window_->GetPosition();
result[0] = pos.x();
result[1] = pos.y();
return result;
}
void Window::SetTitle(const std::string& title) {
window_->SetTitle(title);
}
std::string Window::GetTitle() {
return window_->GetTitle();
}
void Window::FlashFrame(bool flash) {
window_->FlashFrame(flash);
}
void Window::SetSkipTaskbar(bool skip) {
window_->SetSkipTaskbar(skip);
}
void Window::SetKiosk(bool kiosk) {
window_->SetKiosk(kiosk);
}
bool Window::IsKiosk() {
return window_->IsKiosk();
}
void Window::FocusOnWebView() {
window_->FocusOnWebView();
}
void Window::BlurWebView() {
window_->BlurWebView();
}
bool Window::IsWebViewFocused() {
return window_->IsWebViewFocused();
}
void Window::SetRepresentedFilename(const std::string& filename) {
window_->SetRepresentedFilename(filename);
}
std::string Window::GetRepresentedFilename() {
return window_->GetRepresentedFilename();
}
void Window::SetDocumentEdited(bool edited) {
window_->SetDocumentEdited(edited);
}
bool Window::IsDocumentEdited() {
return window_->IsDocumentEdited();
}
void Window::CapturePage(mate::Arguments* args) {
gfx::Rect rect;
base::Callback<void(const gfx::Image&)> callback;
if (!(args->Length() == 1 && args->GetNext(&callback)) &&
!(args->Length() == 2 && args->GetNext(&rect)
&& args->GetNext(&callback))) {
args->ThrowError();
return;
}
window_->CapturePage(
rect, base::Bind(&OnCapturePageDone, args->isolate(), callback));
}
void Window::SetProgressBar(double progress) {
window_->SetProgressBar(progress);
}
void Window::SetOverlayIcon(const gfx::Image& overlay,
const std::string& description) {
window_->SetOverlayIcon(overlay, description);
}
bool Window::SetThumbarButtons(mate::Arguments* args) {
#if defined(OS_WIN)
std::vector<TaskbarHost::ThumbarButton> buttons;
if (!args->GetNext(&buttons)) {
args->ThrowError();
return false;
}
auto window = static_cast<NativeWindowViews*>(window_.get());
return window->taskbar_host().SetThumbarButtons(
window->GetAcceleratedWidget(), buttons);
#else
return false;
#endif
}
void Window::SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> value) {
mate::Handle<Menu> menu;
if (value->IsObject() &&
mate::V8ToString(value->ToObject()->GetConstructorName()) == "Menu" &&
mate::ConvertFromV8(isolate, value, &menu)) {
menu_.Reset(isolate, menu.ToV8());
window_->SetMenu(menu->model());
} else if (value->IsNull()) {
menu_.Reset();
window_->SetMenu(nullptr);
} else {
isolate->ThrowException(v8::Exception::TypeError(
mate::StringToV8(isolate, "Invalid Menu")));
}
}
void Window::SetAutoHideMenuBar(bool auto_hide) {
window_->SetAutoHideMenuBar(auto_hide);
}
bool Window::IsMenuBarAutoHide() {
return window_->IsMenuBarAutoHide();
}
void Window::SetMenuBarVisibility(bool visible) {
window_->SetMenuBarVisibility(visible);
}
bool Window::IsMenuBarVisible() {
return window_->IsMenuBarVisible();
}
#if defined(OS_MACOSX)
void Window::ShowDefinitionForSelection() {
window_->ShowDefinitionForSelection();
}
#endif
void Window::SetAspectRatio(double aspect_ratio, mate::Arguments* args) {
gfx::Size extra_size;
args->GetNext(&extra_size);
window_->SetAspectRatio(aspect_ratio, extra_size);
}
void Window::SetVisibleOnAllWorkspaces(bool visible) {
return window_->SetVisibleOnAllWorkspaces(visible);
}
bool Window::IsVisibleOnAllWorkspaces() {
return window_->IsVisibleOnAllWorkspaces();
}
int32_t Window::ID() const {
return weak_map_id();
}
v8::Local<v8::Value> Window::WebContents(v8::Isolate* isolate) {
if (web_contents_.IsEmpty())
return v8::Null(isolate);
else
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
void Window::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("destroy", &Window::Destroy, true)
.SetMethod("close", &Window::Close)
.SetMethod("isClosed", &Window::IsClosed)
.SetMethod("focus", &Window::Focus)
.SetMethod("isFocused", &Window::IsFocused)
.SetMethod("show", &Window::Show)
.SetMethod("showInactive", &Window::ShowInactive)
.SetMethod("hide", &Window::Hide)
.SetMethod("isVisible", &Window::IsVisible)
.SetMethod("maximize", &Window::Maximize)
.SetMethod("unmaximize", &Window::Unmaximize)
.SetMethod("isMaximized", &Window::IsMaximized)
.SetMethod("minimize", &Window::Minimize)
.SetMethod("restore", &Window::Restore)
.SetMethod("isMinimized", &Window::IsMinimized)
.SetMethod("setFullScreen", &Window::SetFullScreen)
.SetMethod("isFullScreen", &Window::IsFullscreen)
.SetMethod("setAspectRatio", &Window::SetAspectRatio)
.SetMethod("getBounds", &Window::GetBounds)
.SetMethod("setBounds", &Window::SetBounds)
.SetMethod("getSize", &Window::GetSize)
.SetMethod("setSize", &Window::SetSize)
.SetMethod("getContentSize", &Window::GetContentSize)
.SetMethod("setContentSize", &Window::SetContentSize)
.SetMethod("setMinimumSize", &Window::SetMinimumSize)
.SetMethod("getMinimumSize", &Window::GetMinimumSize)
.SetMethod("setMaximumSize", &Window::SetMaximumSize)
.SetMethod("getMaximumSize", &Window::GetMaximumSize)
.SetMethod("setResizable", &Window::SetResizable)
.SetMethod("isResizable", &Window::IsResizable)
.SetMethod("setAlwaysOnTop", &Window::SetAlwaysOnTop)
.SetMethod("isAlwaysOnTop", &Window::IsAlwaysOnTop)
.SetMethod("center", &Window::Center)
.SetMethod("setPosition", &Window::SetPosition)
.SetMethod("getPosition", &Window::GetPosition)
.SetMethod("setTitle", &Window::SetTitle)
.SetMethod("getTitle", &Window::GetTitle)
.SetMethod("flashFrame", &Window::FlashFrame)
.SetMethod("setSkipTaskbar", &Window::SetSkipTaskbar)
.SetMethod("setKiosk", &Window::SetKiosk)
.SetMethod("isKiosk", &Window::IsKiosk)
.SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename)
.SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename)
.SetMethod("setDocumentEdited", &Window::SetDocumentEdited)
.SetMethod("isDocumentEdited", &Window::IsDocumentEdited)
.SetMethod("focusOnWebView", &Window::FocusOnWebView)
.SetMethod("blurWebView", &Window::BlurWebView)
.SetMethod("isWebViewFocused", &Window::IsWebViewFocused)
.SetMethod("capturePage", &Window::CapturePage)
.SetMethod("setProgressBar", &Window::SetProgressBar)
.SetMethod("setOverlayIcon", &Window::SetOverlayIcon)
.SetMethod("setThumbarButtons", &Window::SetThumbarButtons)
.SetMethod("setMenu", &Window::SetMenu)
.SetMethod("setAutoHideMenuBar", &Window::SetAutoHideMenuBar)
.SetMethod("isMenuBarAutoHide", &Window::IsMenuBarAutoHide)
.SetMethod("setMenuBarVisibility", &Window::SetMenuBarVisibility)
.SetMethod("isMenuBarVisible", &Window::IsMenuBarVisible)
.SetMethod("setVisibleOnAllWorkspaces",
&Window::SetVisibleOnAllWorkspaces)
.SetMethod("isVisibleOnAllWorkspaces",
&Window::IsVisibleOnAllWorkspaces)
#if defined(OS_MACOSX)
.SetMethod("showDefinitionForSelection",
&Window::ShowDefinitionForSelection)
#endif
.SetProperty("id", &Window::ID, true)
.SetProperty("webContents", &Window::WebContents, true)
.SetProperty("devToolsWebContents", &Window::DevToolsWebContents, true);
}
} // namespace api
} // namespace atom
namespace {
using atom::api::Window;
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
v8::Isolate* isolate = context->GetIsolate();
v8::Local<v8::Function> constructor = mate::CreateConstructor<Window>(
isolate, "BrowserWindow", base::Bind(&Window::New));
mate::Dictionary browser_window(isolate, constructor);
browser_window.SetMethod("fromId",
&mate::TrackableObject<Window>::FromWeakMapID);
browser_window.SetMethod("getAllWindows",
&mate::TrackableObject<Window>::GetAll);
mate::Dictionary dict(isolate, exports);
dict.Set("BrowserWindow", browser_window);
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_window, Initialize)

View File

@@ -0,0 +1,190 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_API_WINDOW_H_
#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_
#include <string>
#include <vector>
#include "base/memory/scoped_ptr.h"
#include "ui/gfx/image/image.h"
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/native_window.h"
#include "atom/browser/native_window_observer.h"
#include "native_mate/handle.h"
class GURL;
namespace gfx {
class Rect;
}
namespace mate {
class Arguments;
class Dictionary;
}
namespace atom {
class NativeWindow;
namespace api {
class WebContents;
class Window : public mate::TrackableObject<Window>,
public NativeWindowObserver {
public:
static mate::Wrappable* New(v8::Isolate* isolate,
const mate::Dictionary& options);
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
NativeWindow* window() const { return window_.get(); }
protected:
Window(v8::Isolate* isolate, const mate::Dictionary& options);
virtual ~Window();
// NativeWindowObserver:
void OnPageTitleUpdated(bool* prevent_default,
const std::string& title) override;
void WillCloseWindow(bool* prevent_default) override;
void OnWindowClosed() override;
void OnWindowBlur() override;
void OnWindowFocus() override;
void OnWindowMaximize() override;
void OnWindowUnmaximize() override;
void OnWindowMinimize() override;
void OnWindowRestore() override;
void OnWindowResize() override;
void OnWindowMove() override;
void OnWindowMoved() override;
void OnWindowEnterFullScreen() override;
void OnWindowLeaveFullScreen() override;
void OnWindowEnterHtmlFullScreen() override;
void OnWindowLeaveHtmlFullScreen() override;
void OnRendererUnresponsive() override;
void OnRendererResponsive() override;
void OnDevToolsFocus() override;
void OnDevToolsOpened() override;
void OnDevToolsClosed() override;
void OnExecuteWindowsCommand(const std::string& command_name) override;
// mate::Wrappable:
bool IsDestroyed() const override;
private:
// APIs for NativeWindow.
void Destroy();
void Close();
bool IsClosed();
void Focus();
bool IsFocused();
void Show();
void ShowInactive();
void Hide();
bool IsVisible();
void Maximize();
void Unmaximize();
bool IsMaximized();
void Minimize();
void Restore();
bool IsMinimized();
void SetFullScreen(bool fullscreen);
bool IsFullscreen();
void SetBounds(const gfx::Rect& bounds);
gfx::Rect GetBounds();
void SetSize(int width, int height);
std::vector<int> GetSize();
void SetContentSize(int width, int height);
std::vector<int> GetContentSize();
void SetMinimumSize(int width, int height);
std::vector<int> GetMinimumSize();
void SetMaximumSize(int width, int height);
std::vector<int> GetMaximumSize();
void SetResizable(bool resizable);
bool IsResizable();
void SetAlwaysOnTop(bool top);
bool IsAlwaysOnTop();
void Center();
void SetPosition(int x, int y);
std::vector<int> GetPosition();
void SetTitle(const std::string& title);
std::string GetTitle();
void FlashFrame(bool flash);
void SetSkipTaskbar(bool skip);
void SetKiosk(bool kiosk);
bool IsKiosk();
void FocusOnWebView();
void BlurWebView();
bool IsWebViewFocused();
void SetRepresentedFilename(const std::string& filename);
std::string GetRepresentedFilename();
void SetDocumentEdited(bool edited);
bool IsDocumentEdited();
void CapturePage(mate::Arguments* args);
void SetProgressBar(double progress);
void SetOverlayIcon(const gfx::Image& overlay,
const std::string& description);
bool SetThumbarButtons(mate::Arguments* args);
void SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> menu);
void SetAutoHideMenuBar(bool auto_hide);
bool IsMenuBarAutoHide();
void SetMenuBarVisibility(bool visible);
bool IsMenuBarVisible();
void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
#if defined(OS_MACOSX)
void ShowDefinitionForSelection();
#endif
void SetVisibleOnAllWorkspaces(bool visible);
bool IsVisibleOnAllWorkspaces();
int32_t ID() const;
v8::Local<v8::Value> WebContents(v8::Isolate* isolate);
v8::Local<v8::Value> DevToolsWebContents(v8::Isolate* isolate);
v8::Global<v8::Value> web_contents_;
v8::Global<v8::Value> devtools_web_contents_;
v8::Global<v8::Value> menu_;
api::WebContents* api_web_contents_;
scoped_ptr<NativeWindow> window_;
DISALLOW_COPY_AND_ASSIGN(Window);
};
} // namespace api
} // namespace atom
namespace mate {
template<>
struct Converter<atom::NativeWindow*> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
atom::NativeWindow** out) {
// null would be tranfered to NULL.
if (val->IsNull()) {
*out = NULL;
return true;
}
atom::api::Window* window;
if (!Converter<atom::api::Window*>::FromV8(isolate, val, &window))
return false;
*out = window->window();
return true;
}
};
} // namespace mate
#endif // ATOM_BROWSER_API_ATOM_API_WINDOW_H_

72
atom/browser/api/event.cc Normal file
View File

@@ -0,0 +1,72 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/event.h"
#include "atom/common/api/api_messages.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "content/public/browser/web_contents.h"
#include "native_mate/object_template_builder.h"
namespace mate {
namespace {
v8::Persistent<v8::ObjectTemplate> template_;
} // namespace
Event::Event()
: sender_(NULL),
message_(NULL) {
}
Event::~Event() {
}
ObjectTemplateBuilder Event::GetObjectTemplateBuilder(v8::Isolate* isolate) {
if (template_.IsEmpty())
template_.Reset(isolate, ObjectTemplateBuilder(isolate)
.SetMethod("preventDefault", &Event::PreventDefault)
.SetMethod("sendReply", &Event::SendReply)
.Build());
return ObjectTemplateBuilder(
isolate, v8::Local<v8::ObjectTemplate>::New(isolate, template_));
}
void Event::SetSenderAndMessage(content::WebContents* sender,
IPC::Message* message) {
DCHECK(!sender_);
DCHECK(!message_);
sender_ = sender;
message_ = message;
Observe(sender);
}
void Event::WebContentsDestroyed() {
sender_ = NULL;
message_ = NULL;
}
void Event::PreventDefault(v8::Isolate* isolate) {
GetWrapper(isolate)->Set(StringToV8(isolate, "defaultPrevented"),
v8::True(isolate));
}
bool Event::SendReply(const base::string16& json) {
if (message_ == NULL || sender_ == NULL)
return false;
AtomViewHostMsg_Message_Sync::WriteReplyParams(message_, json);
return sender_->Send(message_);
}
// static
Handle<Event> Event::Create(v8::Isolate* isolate) {
return CreateHandle(isolate, new Event);
}
} // namespace mate

52
atom/browser/api/event.h Normal file
View File

@@ -0,0 +1,52 @@
// Copyright (c) 2014 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_EVENT_H_
#define ATOM_BROWSER_API_EVENT_H_
#include "content/public/browser/web_contents_observer.h"
#include "native_mate/wrappable.h"
#include "native_mate/handle.h"
namespace IPC {
class Message;
}
namespace mate {
class Event : public Wrappable,
public content::WebContentsObserver {
public:
static Handle<Event> Create(v8::Isolate* isolate);
// Pass the sender and message to be replied.
void SetSenderAndMessage(content::WebContents* sender, IPC::Message* message);
// event.PreventDefault().
void PreventDefault(v8::Isolate* isolate);
// event.sendReply(json), used for replying synchronous message.
bool SendReply(const base::string16& json);
protected:
Event();
virtual ~Event();
// Wrappable implementations:
ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) override;
// content::WebContentsObserver implementations:
void WebContentsDestroyed() override;
private:
// Replyer for the synchronous messages.
content::WebContents* sender_;
IPC::Message* message_;
DISALLOW_COPY_AND_ASSIGN(Event);
};
} // namespace mate
#endif // ATOM_BROWSER_API_EVENT_H_

View File

@@ -0,0 +1,64 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/event_emitter.h"
#include "atom/browser/api/event.h"
#include "native_mate/arguments.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
namespace mate {
namespace {
v8::Persistent<v8::ObjectTemplate> event_template;
void PreventDefault(mate::Arguments* args) {
mate::Dictionary self(args->isolate(), args->GetThis());
self.Set("defaultPrevented", true);
}
// Create a pure JavaScript Event object.
v8::Local<v8::Object> CreateEventObject(v8::Isolate* isolate) {
if (event_template.IsEmpty()) {
event_template.Reset(isolate, ObjectTemplateBuilder(isolate)
.SetMethod("preventDefault", &PreventDefault)
.Build());
}
return v8::Local<v8::ObjectTemplate>::New(
isolate, event_template)->NewInstance();
}
} // namespace
EventEmitter::EventEmitter() {
}
v8::Local<v8::Object> EventEmitter::CreateJSEvent(
v8::Isolate* isolate, content::WebContents* sender, IPC::Message* message) {
v8::Local<v8::Object> event;
bool use_native_event = sender && message;
if (use_native_event) {
mate::Handle<mate::Event> native_event = mate::Event::Create(isolate);
native_event->SetSenderAndMessage(sender, message);
event = v8::Local<v8::Object>::Cast(native_event.ToV8());
} else {
event = CreateEventObject(isolate);
}
mate::Dictionary(isolate, event).Set("sender", GetWrapper(isolate));
return event;
}
v8::Local<v8::Object> EventEmitter::CreateCustomEvent(
v8::Isolate* isolate, v8::Local<v8::Object> custom_event) {
v8::Local<v8::Object> event = CreateEventObject(isolate);
event->SetPrototype(custom_event->CreationContext(), custom_event);
mate::Dictionary(isolate, event).Set("sender", GetWrapper(isolate));
return event;
}
} // namespace mate

View File

@@ -0,0 +1,79 @@
// Copyright (c) 2014 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_EVENT_EMITTER_H_
#define ATOM_BROWSER_API_EVENT_EMITTER_H_
#include <vector>
#include "atom/common/api/event_emitter_caller.h"
#include "native_mate/wrappable.h"
namespace content {
class WebContents;
}
namespace IPC {
class Message;
}
namespace mate {
// Provide helperers to emit event in JavaScript.
class EventEmitter : public Wrappable {
public:
typedef std::vector<v8::Local<v8::Value>> ValueArray;
// this.emit(name, event, args...);
template<typename... Args>
bool EmitCustomEvent(const base::StringPiece& name,
v8::Local<v8::Object> event,
const Args&... args) {
return EmitWithEvent(name, CreateCustomEvent(isolate(), event), args...);
}
// this.emit(name, new Event(), args...);
template<typename... Args>
bool Emit(const base::StringPiece& name, const Args&... args) {
return EmitWithSender(name, nullptr, nullptr, args...);
}
// this.emit(name, new Event(sender, message), args...);
template<typename... Args>
bool EmitWithSender(const base::StringPiece& name,
content::WebContents* sender,
IPC::Message* message,
const Args&... args) {
v8::Local<v8::Object> event = CreateJSEvent(isolate(), sender, message);
return EmitWithEvent(name, event, args...);
}
protected:
EventEmitter();
private:
// this.emit(name, event, args...);
template<typename... Args>
bool EmitWithEvent(const base::StringPiece& name,
v8::Local<v8::Object> event,
const Args&... args) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
EmitEvent(isolate(), GetWrapper(isolate()), name, event, args...);
return event->Get(
StringToV8(isolate(), "defaultPrevented"))->BooleanValue();
}
v8::Local<v8::Object> CreateJSEvent(v8::Isolate* isolate,
content::WebContents* sender,
IPC::Message* message);
v8::Local<v8::Object> CreateCustomEvent(
v8::Isolate* isolate, v8::Local<v8::Object> event);
DISALLOW_COPY_AND_ASSIGN(EventEmitter);
};
} // namespace mate
#endif // ATOM_BROWSER_API_EVENT_EMITTER_H_

View File

@@ -0,0 +1,45 @@
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

View File

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

View File

@@ -0,0 +1,24 @@
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

View File

@@ -0,0 +1,84 @@
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

View File

@@ -0,0 +1 @@
module.exports = process.atomBinding 'content_tracing'

View File

@@ -0,0 +1,125 @@
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

View File

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

View File

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

View File

@@ -0,0 +1,49 @@
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

View File

@@ -0,0 +1,174 @@
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

View File

@@ -0,0 +1,117 @@
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

View File

@@ -0,0 +1,6 @@
powerMonitor = process.atomBinding('power_monitor').powerMonitor
EventEmitter = require('events').EventEmitter
powerMonitor.__proto__ = EventEmitter.prototype
module.exports = powerMonitor

View File

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

View File

@@ -0,0 +1,64 @@
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

View File

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

View File

@@ -0,0 +1,14 @@
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

View File

@@ -0,0 +1,114 @@
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.printBackground
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)

View File

@@ -0,0 +1,68 @@
// 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/trackable_object.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "base/bind.h"
#include "base/supports_user_data.h"
namespace mate {
namespace {
const char* kTrackedObjectKey = "TrackedObjectKey";
class IDUserData : public base::SupportsUserData::Data {
public:
explicit IDUserData(int32_t id) : id_(id) {}
operator int32_t() const { return id_; }
private:
int32_t id_;
DISALLOW_COPY_AND_ASSIGN(IDUserData);
};
} // namespace
TrackableObjectBase::TrackableObjectBase()
: weak_map_id_(0), wrapped_(nullptr) {
}
TrackableObjectBase::~TrackableObjectBase() {
}
void TrackableObjectBase::AfterInit(v8::Isolate* isolate) {
if (wrapped_)
AttachAsUserData(wrapped_);
}
void TrackableObjectBase::AttachAsUserData(base::SupportsUserData* wrapped) {
if (weak_map_id_ != 0) {
wrapped->SetUserData(kTrackedObjectKey, new IDUserData(weak_map_id_));
wrapped_ = nullptr;
} else {
// If the TrackableObjectBase is not ready yet then delay SetUserData until
// AfterInit is called.
wrapped_ = wrapped;
}
}
// static
int32_t TrackableObjectBase::GetIDFromWrappedClass(base::SupportsUserData* w) {
auto id = static_cast<IDUserData*>(w->GetUserData(kTrackedObjectKey));
if (id)
return *id;
else
return 0;
}
// static
void TrackableObjectBase::RegisterDestructionCallback(void (*c)()) {
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(base::Bind(c));
}
} // namespace mate

View File

@@ -0,0 +1,125 @@
// 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_TRACKABLE_OBJECT_H_
#define ATOM_BROWSER_API_TRACKABLE_OBJECT_H_
#include <vector>
#include "atom/browser/api/event_emitter.h"
#include "atom/common/id_weak_map.h"
#include "base/memory/scoped_ptr.h"
namespace base {
class SupportsUserData;
}
namespace mate {
// Users should use TrackableObject instead.
class TrackableObjectBase : public mate::EventEmitter {
public:
TrackableObjectBase();
// The ID in weak map.
int32_t weak_map_id() const { return weak_map_id_; }
// Wrap TrackableObject into a class that SupportsUserData.
void AttachAsUserData(base::SupportsUserData* wrapped);
protected:
~TrackableObjectBase() override;
// mate::Wrappable:
void AfterInit(v8::Isolate* isolate) override;
// Get the weak_map_id from SupportsUserData.
static int32_t GetIDFromWrappedClass(base::SupportsUserData* wrapped);
// Register a callback that should be destroyed before JavaScript environment
// gets destroyed.
static void RegisterDestructionCallback(void (*callback)());
int32_t weak_map_id_;
base::SupportsUserData* wrapped_;
private:
DISALLOW_COPY_AND_ASSIGN(TrackableObjectBase);
};
// All instances of TrackableObject will be kept in a weak map and can be got
// from its ID.
template<typename T>
class TrackableObject : public TrackableObjectBase {
public:
// Finds out the TrackableObject from its ID in weak map.
static T* FromWeakMapID(v8::Isolate* isolate, int32_t id) {
if (!weak_map_)
return nullptr;
v8::MaybeLocal<v8::Object> object = weak_map_->Get(isolate, id);
if (object.IsEmpty())
return nullptr;
T* self = nullptr;
mate::ConvertFromV8(isolate, object.ToLocalChecked(), &self);
return self;
}
// Finds out the TrackableObject from the class it wraps.
static T* FromWrappedClass(v8::Isolate* isolate,
base::SupportsUserData* wrapped) {
int32_t id = GetIDFromWrappedClass(wrapped);
if (!id)
return nullptr;
return FromWeakMapID(isolate, id);
}
// Returns all objects in this class's weak map.
static std::vector<v8::Local<v8::Object>> GetAll(v8::Isolate* isolate) {
if (weak_map_)
return weak_map_->Values(isolate);
else
return std::vector<v8::Local<v8::Object>>();
}
TrackableObject() {
RegisterDestructionCallback(&TrackableObject<T>::ReleaseAllWeakReferences);
}
// Removes this instance from the weak map.
void RemoveFromWeakMap() {
if (weak_map_ && weak_map_->Has(weak_map_id()))
weak_map_->Remove(weak_map_id());
}
protected:
~TrackableObject() override {
RemoveFromWeakMap();
}
void AfterInit(v8::Isolate* isolate) override {
if (!weak_map_)
weak_map_.reset(new atom::IDWeakMap);
weak_map_id_ = weak_map_->Add(isolate, GetWrapper(isolate));
TrackableObjectBase::AfterInit(isolate);
}
private:
// Releases all weak references in weak map, called when app is terminating.
static void ReleaseAllWeakReferences() {
weak_map_.reset();
}
static scoped_ptr<atom::IDWeakMap> weak_map_;
DISALLOW_COPY_AND_ASSIGN(TrackableObject);
};
template<typename T>
scoped_ptr<atom::IDWeakMap> TrackableObject<T>::weak_map_;
} // namespace mate
#endif // ATOM_BROWSER_API_TRACKABLE_OBJECT_H_

View File

@@ -0,0 +1,51 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/atom_access_token_store.h"
#include <utility>
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/common/google_api_key.h"
namespace atom {
namespace {
// Notice that we just combined the api key with the url together here, because
// if we use the standard {url: key} format Chromium would override our key with
// the predefined one in common.gypi of libchromiumcontent, which is empty.
const char* kGeolocationProviderUrl =
"https://www.googleapis.com/geolocation/v1/geolocate?key="
GOOGLEAPIS_API_KEY;
} // namespace
AtomAccessTokenStore::AtomAccessTokenStore() {
}
AtomAccessTokenStore::~AtomAccessTokenStore() {
}
void AtomAccessTokenStore::LoadAccessTokens(
const LoadAccessTokensCallbackType& callback) {
AccessTokenSet access_token_set;
// Equivelent to access_token_set[kGeolocationProviderUrl].
// Somehow base::string16 is causing compilation errors when used in a pair
// of std::map on Linux, this can work around it.
std::pair<GURL, base::string16> token_pair;
token_pair.first = GURL(kGeolocationProviderUrl);
access_token_set.insert(token_pair);
auto browser_context = AtomBrowserMainParts::Get()->browser_context();
callback.Run(access_token_set, browser_context->url_request_context_getter());
}
void AtomAccessTokenStore::SaveAccessToken(const GURL& server_url,
const base::string16& access_token) {
}
} // namespace atom

View File

@@ -0,0 +1,31 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_ATOM_ACCESS_TOKEN_STORE_H_
#define ATOM_BROWSER_ATOM_ACCESS_TOKEN_STORE_H_
#include "content/public/browser/access_token_store.h"
namespace atom {
class AtomBrowserContext;
class AtomAccessTokenStore : public content::AccessTokenStore {
public:
AtomAccessTokenStore();
virtual ~AtomAccessTokenStore();
// content::AccessTokenStore:
void LoadAccessTokens(
const LoadAccessTokensCallbackType& callback) override;
void SaveAccessToken(const GURL& server_url,
const base::string16& access_token) override;
private:
DISALLOW_COPY_AND_ASSIGN(AtomAccessTokenStore);
};
} // namespace atom
#endif // ATOM_BROWSER_ATOM_ACCESS_TOKEN_STORE_H_

View File

@@ -0,0 +1,267 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/atom_browser_client.h"
#if defined(OS_WIN)
#include <shlobj.h>
#endif
#include "atom/browser/atom_access_token_store.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/atom_quota_permission_context.h"
#include "atom/browser/atom_speech_recognition_manager_delegate.h"
#include "atom/browser/browser.h"
#include "atom/browser/native_window.h"
#include "atom/browser/web_view_manager.h"
#include "atom/browser/window_list.h"
#include "atom/common/options_switches.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/strings/string_util.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/printing/printing_message_filter.h"
#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
#include "chrome/browser/speech/tts_message_filter.h"
#include "content/public/browser/browser_ppapi_host.h"
#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/web_preferences.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "ppapi/host/ppapi_host.h"
#include "ui/base/l10n/l10n_util.h"
namespace atom {
namespace {
// The default routing id of WebContents.
// In Electron each RenderProcessHost only has one WebContents, so this ID is
// same for every WebContents.
int kDefaultRoutingID = 2;
// Next navigation should not restart renderer process.
bool g_suppress_renderer_process_restart = false;
// Custom schemes to be registered to standard.
std::string g_custom_schemes = "";
// Find out the owner of the child process according to |process_id|.
enum ProcessOwner {
OWNER_NATIVE_WINDOW,
OWNER_GUEST_WEB_CONTENTS,
OWNER_NONE, // it might be devtools though.
};
ProcessOwner GetProcessOwner(int process_id,
NativeWindow** window,
WebViewManager::WebViewInfo* info) {
auto web_contents = content::WebContents::FromRenderViewHost(
content::RenderViewHost::FromID(process_id, kDefaultRoutingID));
if (!web_contents)
return OWNER_NONE;
// First search for NativeWindow.
for (auto native_window : *WindowList::GetInstance())
if (web_contents == native_window->web_contents()) {
*window = native_window;
return OWNER_NATIVE_WINDOW;
}
// Then search for guest WebContents.
if (WebViewManager::GetInfoForWebContents(web_contents, info))
return OWNER_GUEST_WEB_CONTENTS;
return OWNER_NONE;
}
scoped_refptr<net::X509Certificate> ImportCertFromFile(
const base::FilePath& path) {
if (path.empty())
return nullptr;
std::string cert_data;
if (!base::ReadFileToString(path, &cert_data))
return nullptr;
net::CertificateList certs =
net::X509Certificate::CreateCertificateListFromBytes(
cert_data.data(), cert_data.size(),
net::X509Certificate::FORMAT_AUTO);
if (certs.empty())
return nullptr;
return certs[0];
}
} // namespace
// static
void AtomBrowserClient::SuppressRendererProcessRestartForOnce() {
g_suppress_renderer_process_restart = true;
}
void AtomBrowserClient::SetCustomSchemes(
const std::vector<std::string>& schemes) {
g_custom_schemes = JoinString(schemes, ',');
}
AtomBrowserClient::AtomBrowserClient() {
}
AtomBrowserClient::~AtomBrowserClient() {
}
void AtomBrowserClient::RenderProcessWillLaunch(
content::RenderProcessHost* host) {
int process_id = host->GetID();
host->AddFilter(new printing::PrintingMessageFilter(process_id));
host->AddFilter(new TtsMessageFilter(process_id, host->GetBrowserContext()));
}
content::SpeechRecognitionManagerDelegate*
AtomBrowserClient::CreateSpeechRecognitionManagerDelegate() {
return new AtomSpeechRecognitionManagerDelegate;
}
content::AccessTokenStore* AtomBrowserClient::CreateAccessTokenStore() {
return new AtomAccessTokenStore;
}
void AtomBrowserClient::OverrideWebkitPrefs(
content::RenderViewHost* host, content::WebPreferences* prefs) {
prefs->javascript_enabled = true;
prefs->web_security_enabled = true;
prefs->javascript_can_open_windows_automatically = true;
prefs->plugins_enabled = true;
prefs->dom_paste_enabled = true;
prefs->java_enabled = false;
prefs->allow_scripts_to_close_windows = true;
prefs->javascript_can_access_clipboard = true;
prefs->local_storage_enabled = true;
prefs->databases_enabled = true;
prefs->application_cache_enabled = true;
prefs->allow_universal_access_from_file_urls = true;
prefs->allow_file_access_from_file_urls = true;
prefs->experimental_webgl_enabled = true;
prefs->allow_displaying_insecure_content = false;
prefs->allow_running_insecure_content = false;
// Custom preferences of guest page.
auto web_contents = content::WebContents::FromRenderViewHost(host);
WebViewManager::WebViewInfo info;
if (WebViewManager::GetInfoForWebContents(web_contents, &info)) {
prefs->web_security_enabled = !info.disable_web_security;
return;
}
NativeWindow* window = NativeWindow::FromWebContents(web_contents);
if (window)
window->OverrideWebkitPrefs(prefs);
}
std::string AtomBrowserClient::GetApplicationLocale() {
return l10n_util::GetApplicationLocale("");
}
void AtomBrowserClient::OverrideSiteInstanceForNavigation(
content::BrowserContext* browser_context,
content::SiteInstance* current_instance,
const GURL& url,
content::SiteInstance** new_instance) {
if (g_suppress_renderer_process_restart) {
g_suppress_renderer_process_restart = false;
return;
}
// Restart renderer process for all navigations except "javacript:" scheme.
if (url.SchemeIs(url::kJavaScriptScheme))
return;
*new_instance = content::SiteInstance::CreateForURL(browser_context, url);
}
void AtomBrowserClient::AppendExtraCommandLineSwitches(
base::CommandLine* command_line,
int process_id) {
std::string process_type = command_line->GetSwitchValueASCII("type");
if (process_type != "renderer")
return;
// The registered standard schemes.
if (!g_custom_schemes.empty())
command_line->AppendSwitchASCII(switches::kRegisterStandardSchemes,
g_custom_schemes);
#if defined(OS_WIN)
// Append --app-user-model-id.
PWSTR current_app_id;
if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(&current_app_id))) {
command_line->AppendSwitchNative(switches::kAppUserModelId, current_app_id);
CoTaskMemFree(current_app_id);
}
#endif
NativeWindow* window;
WebViewManager::WebViewInfo info;
ProcessOwner owner = GetProcessOwner(process_id, &window, &info);
if (owner == OWNER_NATIVE_WINDOW) {
window->AppendExtraCommandLineSwitches(command_line);
} else if (owner == OWNER_GUEST_WEB_CONTENTS) {
command_line->AppendSwitchASCII(
switches::kGuestInstanceID, base::IntToString(info.guest_instance_id));
command_line->AppendSwitchASCII(
switches::kNodeIntegration, info.node_integration ? "true" : "false");
if (info.plugins)
command_line->AppendSwitch(switches::kEnablePlugins);
if (!info.preload_script.empty())
command_line->AppendSwitchPath(
switches::kPreloadScript, info.preload_script);
}
}
void AtomBrowserClient::DidCreatePpapiPlugin(
content::BrowserPpapiHost* host) {
host->GetPpapiHost()->AddHostFactoryFilter(
make_scoped_ptr(new chrome::ChromeBrowserPepperHostFactory(host)));
}
content::QuotaPermissionContext*
AtomBrowserClient::CreateQuotaPermissionContext() {
return new AtomQuotaPermissionContext;
}
void AtomBrowserClient::SelectClientCertificate(
content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) {
// --client-certificate=`path`
auto cmd = base::CommandLine::ForCurrentProcess();
if (cmd->HasSwitch(switches::kClientCertificate)) {
auto cert_path = cmd->GetSwitchValuePath(switches::kClientCertificate);
auto certificate = ImportCertFromFile(cert_path);
if (certificate.get())
delegate->ContinueWithCertificate(certificate.get());
return;
}
if (!cert_request_info->client_certs.empty())
Browser::Get()->ClientCertificateSelector(web_contents,
cert_request_info,
delegate.Pass());
}
brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts(
const content::MainFunctionParams&) {
v8::V8::Initialize(); // Init V8 before creating main parts.
return new AtomBrowserMainParts;
}
} // namespace atom

View File

@@ -0,0 +1,66 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_ATOM_BROWSER_CLIENT_H_
#define ATOM_BROWSER_ATOM_BROWSER_CLIENT_H_
#include <string>
#include <vector>
#include "brightray/browser/browser_client.h"
namespace content {
class QuotaPermissionContext;
class ClientCertificateDelegate;
}
namespace net {
class SSLCertRequestInfo;
}
namespace atom {
class AtomBrowserClient : public brightray::BrowserClient {
public:
AtomBrowserClient();
virtual ~AtomBrowserClient();
// Don't force renderer process to restart for once.
static void SuppressRendererProcessRestartForOnce();
// Custom schemes to be registered to standard.
static void SetCustomSchemes(const std::vector<std::string>& schemes);
protected:
// content::ContentBrowserClient:
void RenderProcessWillLaunch(content::RenderProcessHost* host) override;
content::SpeechRecognitionManagerDelegate*
CreateSpeechRecognitionManagerDelegate() override;
content::AccessTokenStore* CreateAccessTokenStore() override;
void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,
content::WebPreferences* prefs) override;
std::string GetApplicationLocale() override;
void OverrideSiteInstanceForNavigation(
content::BrowserContext* browser_context,
content::SiteInstance* current_instance,
const GURL& dest_url,
content::SiteInstance** new_instance) override;
void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
int child_process_id) override;
void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override;
content::QuotaPermissionContext* CreateQuotaPermissionContext() override;
void SelectClientCertificate(
content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) override;
private:
brightray::BrowserMainParts* OverrideCreateBrowserMainParts(
const content::MainFunctionParams&) override;
DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient);
};
} // namespace atom
#endif // ATOM_BROWSER_ATOM_BROWSER_CLIENT_H_

View File

@@ -0,0 +1,159 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/atom_download_manager_delegate.h"
#include "atom/browser/browser.h"
#include "atom/browser/net/atom_url_request_job_factory.h"
#include "atom/browser/net/asar/asar_protocol_handler.h"
#include "atom/browser/net/http_protocol_handler.h"
#include "atom/browser/web_view_manager.h"
#include "atom/common/atom_version.h"
#include "atom/common/chrome_version.h"
#include "atom/common/options_switches.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/worker_pool.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/user_agent.h"
#include "net/ftp/ftp_network_layer.h"
#include "net/url_request/data_protocol_handler.h"
#include "net/url_request/ftp_protocol_handler.h"
#include "net/url_request/url_request_intercepting_job_factory.h"
#include "net/url_request/url_request_context.h"
#include "url/url_constants.h"
using content::BrowserThread;
namespace atom {
namespace {
class NoCacheBackend : public net::HttpCache::BackendFactory {
int CreateBackend(net::NetLog* net_log,
scoped_ptr<disk_cache::Backend>* backend,
const net::CompletionCallback& callback) override {
return net::ERR_FAILED;
}
};
std::string RemoveWhitespace(const std::string& str) {
std::string trimmed;
if (base::RemoveChars(str, " ", &trimmed))
return trimmed;
else
return str;
}
} // namespace
AtomBrowserContext::AtomBrowserContext()
: job_factory_(new AtomURLRequestJobFactory) {
}
AtomBrowserContext::~AtomBrowserContext() {
}
std::string AtomBrowserContext::GetUserAgent() {
Browser* browser = Browser::Get();
std::string name = RemoveWhitespace(browser->GetName());
std::string user_agent;
if (name == ATOM_PRODUCT_NAME) {
user_agent = "Chrome/" CHROME_VERSION_STRING " "
ATOM_PRODUCT_NAME "/" ATOM_VERSION_STRING;
} else {
user_agent = base::StringPrintf(
"%s/%s Chrome/%s " ATOM_PRODUCT_NAME "/" ATOM_VERSION_STRING,
name.c_str(),
browser->GetVersion().c_str(),
CHROME_VERSION_STRING);
}
return content::BuildUserAgentFromProduct(user_agent);
}
net::URLRequestJobFactory* AtomBrowserContext::CreateURLRequestJobFactory(
content::ProtocolHandlerMap* handlers,
content::URLRequestInterceptorScopedVector* interceptors) {
scoped_ptr<AtomURLRequestJobFactory> job_factory(job_factory_);
for (content::ProtocolHandlerMap::iterator it = handlers->begin();
it != handlers->end(); ++it)
job_factory->SetProtocolHandler(it->first, it->second.release());
handlers->clear();
job_factory->SetProtocolHandler(
url::kDataScheme, new net::DataProtocolHandler);
job_factory->SetProtocolHandler(
url::kFileScheme, new asar::AsarProtocolHandler(
BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
job_factory->SetProtocolHandler(
url::kHttpScheme, new HttpProtocolHandler(url::kHttpScheme));
job_factory->SetProtocolHandler(
url::kHttpsScheme, new HttpProtocolHandler(url::kHttpsScheme));
job_factory->SetProtocolHandler(
url::kWsScheme, new HttpProtocolHandler(url::kWsScheme));
job_factory->SetProtocolHandler(
url::kWssScheme, new HttpProtocolHandler(url::kWssScheme));
auto host_resolver = url_request_context_getter()
->GetURLRequestContext()
->host_resolver();
job_factory->SetProtocolHandler(
url::kFtpScheme, new net::FtpProtocolHandler(
new net::FtpNetworkLayer(host_resolver)));
// Set up interceptors in the reverse order.
scoped_ptr<net::URLRequestJobFactory> top_job_factory = job_factory.Pass();
content::URLRequestInterceptorScopedVector::reverse_iterator it;
for (it = interceptors->rbegin(); it != interceptors->rend(); ++it)
top_job_factory.reset(new net::URLRequestInterceptingJobFactory(
top_job_factory.Pass(), make_scoped_ptr(*it)));
interceptors->weak_clear();
return top_job_factory.release();
}
net::HttpCache::BackendFactory*
AtomBrowserContext::CreateHttpCacheBackendFactory(
const base::FilePath& base_path) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kDisableHttpCache))
return new NoCacheBackend;
else
return brightray::BrowserContext::CreateHttpCacheBackendFactory(base_path);
}
content::DownloadManagerDelegate*
AtomBrowserContext::GetDownloadManagerDelegate() {
if (!download_manager_delegate_.get()) {
auto download_manager = content::BrowserContext::GetDownloadManager(this);
download_manager_delegate_.reset(
new AtomDownloadManagerDelegate(download_manager));
}
return download_manager_delegate_.get();
}
content::BrowserPluginGuestManager* AtomBrowserContext::GetGuestManager() {
if (!guest_manager_)
guest_manager_.reset(new WebViewManager(this));
return guest_manager_.get();
}
void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
pref_registry->RegisterFilePathPref(prefs::kSelectFileLastDirectory,
base::FilePath());
pref_registry->RegisterFilePathPref(prefs::kDownloadDefaultDirectory,
base::FilePath());
}
} // namespace atom

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