Compare commits

..

2 Commits

Author SHA1 Message Date
Cheng Zhao
cb5273731f Bump v0.34.4 2015-11-24 18:19:10 +08:00
Cheng Zhao
aa40c6c260 Update libchromiumcontent
Backport https://codereview.chromium.org/1324513002.
2015-11-24 18:14:02 +08:00
3121 changed files with 82890 additions and 287098 deletions

View File

@@ -1 +0,0 @@
config-staging

View File

@@ -1,79 +0,0 @@
version: 2.1
# Required for dynamic configuration
setup: true
# Orbs
orbs:
path-filtering: circleci/path-filtering@0.1.0
continuation: circleci/continuation@0.2.0
# All input parameters to pass to build config
parameters:
run-docs-only:
type: boolean
default: false
upload-to-storage:
type: string
default: '1'
run-build-linux:
type: boolean
default: false
run-build-mac:
type: boolean
default: false
run-linux-publish:
type: boolean
default: false
linux-publish-arch-limit:
type: enum
default: all
enum: ["all", "arm", "arm64", "x64", "ia32"]
run-macos-publish:
type: boolean
default: false
macos-publish-arch-limit:
type: enum
default: all
enum: ["all", "osx-x64", "osx-arm64", "mas-x64", "mas-arm64"]
jobs:
generate-config:
docker:
- image: cimg/node:16.14
steps:
- checkout
- path-filtering/set-parameters:
base-revision: main
mapping: |
^((?!docs/).)*$ run-build-mac true
^((?!docs/).)*$ run-build-linux true
docs/.* run-docs-only true
^((?!docs/).)*$ run-docs-only false
- run:
command: |
cd .circleci/config
yarn
export CIRCLECI_BINARY="$HOME/circleci"
curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/main/install.sh | DESTDIR=$CIRCLECI_BINARY bash
node build.js
name: Pack config.yml
- run:
name: Set params
command: node .circleci/config/params.js
- continuation/continue:
configuration_path: .circleci/config-staging/built.yml
parameters: /tmp/pipeline-parameters.json
# Initial setup workflow
workflows:
setup:
jobs:
- generate-config

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +0,0 @@
const cp = require('child_process');
const fs = require('fs-extra');
const path = require('path');
const yaml = require('js-yaml');
const STAGING_DIR = path.resolve(__dirname, '..', 'config-staging');
function copyAndExpand(dir = './') {
const absDir = path.resolve(__dirname, dir);
const targetDir = path.resolve(STAGING_DIR, dir);
if (!fs.existsSync(targetDir)) {
fs.mkdirSync(targetDir);
}
for (const file of fs.readdirSync(absDir)) {
if (!file.endsWith('.yml')) {
if (fs.statSync(path.resolve(absDir, file)).isDirectory()) {
copyAndExpand(path.join(dir, file));
}
continue;
}
fs.writeFileSync(path.resolve(targetDir, file), yaml.dump(yaml.load(fs.readFileSync(path.resolve(absDir, file), 'utf8')), {
noRefs: true,
}));
}
}
if (fs.pathExists(STAGING_DIR)) fs.removeSync(STAGING_DIR);
copyAndExpand();
const output = cp.spawnSync(process.env.CIRCLECI_BINARY || 'circleci', ['config', 'pack', STAGING_DIR]);
fs.writeFileSync(path.resolve(STAGING_DIR, 'built.yml'), output.stdout.toString());

View File

@@ -1,51 +0,0 @@
executor:
name: linux-docker
size: medium
steps:
- checkout:
path: src/electron
- run:
name: Setup third_party Depot Tools
command: |
# "depot_tools" has to be checkout into "//third_party/depot_tools" so pylint.py can a "pylintrc" file.
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git src/third_party/depot_tools
echo 'export PATH="$PATH:'"$PWD"'/src/third_party/depot_tools"' >> $BASH_ENV
- run:
name: Download GN Binary
command: |
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
gn_version="$(curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/DEPS?format=TEXT" | base64 -d | grep gn_version | head -n1 | cut -d\' -f4)"
cipd ensure -ensure-file - -root . \<<-CIPD
\$ServiceURL https://chrome-infra-packages.appspot.com/
@Subdir src/buildtools/linux64
gn/gn/linux-amd64 $gn_version
CIPD
echo 'export CHROMIUM_BUILDTOOLS_PATH="'"$PWD"'/src/buildtools"' >> $BASH_ENV
- run:
name: Download clang-format Binary
command: |
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
sha1_path='buildtools/linux64/clang-format.sha1'
curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/${sha1_path}?format=TEXT" | base64 -d > "src/${sha1_path}"
download_from_google_storage.py --no_resume --no_auth --bucket chromium-clang-format -s "src/${sha1_path}"
- run:
name: Run Lint
command: |
# gn.py tries to find a gclient root folder starting from the current dir.
# When it fails and returns "None" path, the whole script fails. Let's "fix" it.
touch .gclient
# Another option would be to checkout "buildtools" inside the Electron checkout,
# but then we would lint its contents (at least gn format), and it doesn't pass it.
cd src/electron
node script/yarn install --frozen-lockfile
node script/yarn lint
- run:
name: Run Script Typechecker
command: |
cd src/electron
node script/yarn tsc -p tsconfig.script.json

View File

@@ -1,10 +0,0 @@
{
"name": "@electron/circleci-config",
"version": "0.0.0",
"private": true,
"license": "MIT",
"dependencies": {
"fs-extra": "^10.1.0",
"js-yaml": "^4.1.0"
}
}

View File

@@ -1,12 +0,0 @@
const fs = require('fs');
const PARAMS_PATH = '/tmp/pipeline-parameters.json';
const content = JSON.parse(fs.readFileSync(PARAMS_PATH, 'utf-8'));
// Choose resource class for linux hosts
const currentBranch = process.env.CIRCLE_BRANCH || '';
content['large-linux-executor'] = /^pull\/[0-9-]+$/.test(currentBranch) ? '2xlarge' : 'electronjs/aks-linux-large';
content['medium-linux-executor'] = /^pull\/[0-9-]+$/.test(currentBranch) ? 'medium' : 'electronjs/aks-linux-medium';
fs.writeFileSync(PARAMS_PATH, JSON.stringify(content));

View File

@@ -1,43 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
fs-extra@^10.1.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^2.0.0"
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
version "4.2.10"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"
jsonfile@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
dependencies:
universalify "^2.0.0"
optionalDependencies:
graceful-fs "^4.1.6"
universalify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==

View File

@@ -1,8 +0,0 @@
#!/bin/bash
set -e
mkdir -p ~/.ssh
echo "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=" >> ~/.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,4 +0,0 @@
---
Checks: '-modernize-use-nullptr'
InheritParentConfig: true
...

View File

@@ -1,58 +0,0 @@
# Electron Dev on Codespaces
Welcome to the Codespaces Electron Developer Environment.
## Quick Start
Upon creation of your codespace you should have [build tools](https://github.com/electron/build-tools) installed and an initialized gclient checkout of Electron. In order to build electron you'll need to run the following command.
```bash
e build
```
The initial build will take ~8 minutes. Incremental builds are substantially quicker. If you pull changes from upstream that touch either the `patches` folder or the `DEPS` folder you will have to run `e sync` in order to keep your checkout up to date.
## Directory Structure
Codespaces doesn't lean very well into gclient based checkouts, the directory structure is slightly strange. There are two locations for the `electron` checkout that both map to the same files under the hood.
```graphql
# Primary gclient checkout container
/workspaces/gclient/*
src/* - # Chromium checkout
electron - # Electron checkout
# Symlinked Electron checkout (identical to the above)
/workspaces/electron
```
## Goma
If you are a maintainer [with Goma access](../docs/development/goma.md) it should be automatically configured and authenticated when you spin up a new codespaces instance. You can validate this by checking `e d goma_auth info` or by checking that your build-tools configuration has a goma mode of `cluster`.
## Running Electron
You can run Electron in a few ways. If you just want to see if it launches:
```bash
# Enter an interactive JS prompt headlessly
xvfb-run e start -i
```
But if you want to actually see Electron you will need to use the built-in VNC capability. If you click "Ports" in codespaces and then open the `VNC web client` forwarded port you should see a web based VNC portal in your browser. When you are asked for a password use `builduser`.
Once in the VNC UI you can open `Applications -> System -> XTerm` which will open a VNC based terminal app and then you can run `e start` like normal and Electron will open in your VNC session.
## Running Tests
You run tests via build-tools and `xvfb`.
```bash
# Run all tests
xvfb-run e test
# Run the main process tests
xvfb-run e test --runners=main
# Run the old remote tests
xvfb-run e test --runners=remote
```

View File

@@ -1,66 +0,0 @@
{
"dockerComposeFile": "docker-compose.yml",
"service": "buildtools",
"onCreateCommand": ".devcontainer/on-create-command.sh",
"updateContentCommand": ".devcontainer/update-content-command.sh",
"workspaceFolder": "/workspaces/gclient/src/electron",
"forwardPorts": [8088, 6080, 5901],
"portsAttributes": {
"8088": {
"label": "Goma Control Panel",
"onAutoForward": "silent"
},
"6080": {
"label": "VNC web client (noVNC)",
"onAutoForward": "silent"
},
"5901": {
"label": "VNC TCP port",
"onAutoForward": "silent"
}
},
"hostRequirements": {
"storage": "128gb",
"cpus": 16
},
"remoteUser": "builduser",
"customizations": {
"codespaces": {
"openFiles": [
".devcontainer/README.md"
]
},
"vscode": {
"extensions": ["joeleinbinder.mojom-language",
"rafaelmaiolla.diff",
"surajbarkale.ninja",
"ms-vscode.cpptools",
"mutantdino.resourcemonitor",
"dbaeumer.vscode-eslint",
"shakram02.bash-beautify",
"marshallofsound.gnls-electron",
"CircleCI.circleci"
],
"settings": {
"editor.tabSize": 2,
"bashBeautify.tabSize": 2,
"typescript.tsdk": "node_modules/typescript/lib",
"[gn]": {
"editor.formatOnSave": true
},
"[javascript]": {
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
},
"[typescript]": {
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
},
"javascript.preferences.quoteStyle": "single",
"typescript.preferences.quoteStyle": "single"
}
}
}
}

View File

@@ -1,19 +0,0 @@
version: '3'
services:
buildtools:
image: ghcr.io/electron/devcontainer:3d8d44d0f15b05bef6149e448f9cc522111847e9
volumes:
- ..:/workspaces/gclient/src/electron:cached
- /var/run/docker.sock:/var/run/docker.sock
command: /bin/sh -c "while sleep 1000; do :; done"
user: builduser
cap_add:
- SYS_PTRACE
security_opt:
- seccomp:unconfined

View File

@@ -1,82 +0,0 @@
#!/bin/bash
set -eo pipefail
buildtools=$HOME/.electron_build_tools
gclient_root=/workspaces/gclient
buildtools_configs=/workspaces/buildtools-configs
export PATH="$PATH:$buildtools/src"
# Create the persisted buildtools config folder
mkdir -p $buildtools_configs
mkdir -p $gclient_root/.git-cache
rm -f $buildtools/configs
ln -s $buildtools_configs $buildtools/configs
# Write the gclient config if it does not already exist
if [ ! -f $gclient_root/.gclient ]; then
echo "Creating gclient config"
echo "solutions = [
{ \"name\" : \"src/electron\",
\"url\" : \"https://github.com/electron/electron\",
\"deps_file\" : \"DEPS\",
\"managed\" : False,
\"custom_deps\" : {
},
\"custom_vars\": {},
},
]
" >$gclient_root/.gclient
fi
# Write the default buildtools config file if it does
# not already exist
if [ ! -f $buildtools/configs/evm.testing.json ]; then
echo "Creating build-tools testing config"
write_config() {
echo "
{
\"goma\": \"$1\",
\"root\": \"/workspaces/gclient\",
\"remotes\": {
\"electron\": {
\"origin\": \"https://github.com/electron/electron.git\"
}
},
\"gen\": {
\"args\": [
\"import(\\\"//electron/build/args/testing.gn\\\")\",
\"import(\\\"/home/builduser/.electron_build_tools/third_party/goma.gn\\\")\"
],
\"out\": \"Testing\"
},
\"env\": {
\"CHROMIUM_BUILDTOOLS_PATH\": \"/workspaces/gclient/src/buildtools\",
\"GIT_CACHE_PATH\": \"/workspaces/gclient/.git-cache\"
},
\"\$schema\": \"file:///home/builduser/.electron_build_tools/evm-config.schema.json\"
}
" >$buildtools/configs/evm.testing.json
}
# Start out as cache only
write_config cache-only
e use testing
# Attempt to auth to the goma service via codespaces tokens
# if it works we can use the goma cluster
export NOTGOMA_CODESPACES_TOKEN=$GITHUB_TOKEN
if e d goma_auth login; then
echo "$GITHUB_USER has GOMA access - switching to cluster mode"
write_config cluster
fi
else
echo "build-tools testing config already exists"
# Re-auth with the goma cluster regardless.
NOTGOMA_CODESPACES_TOKEN=$GITHUB_TOKEN e d goma_auth login || true
fi

View File

@@ -1,10 +0,0 @@
#!/bin/bash
set -eo pipefail
buildtools=$HOME/.electron_build_tools
export PATH="$PATH:$buildtools/src"
# Sync latest
e d gclient sync --with_branch_heads --with_tags

View File

@@ -1,2 +0,0 @@
*
!tools/xvfb-init.sh

View File

@@ -1,6 +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=

View File

@@ -1,46 +0,0 @@
{
"root": true,
"extends": "standard",
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"env": {
"browser": true
},
"rules": {
"semi": ["error", "always"],
"no-var": "error",
"no-unused-vars": "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"
},
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
},
"overrides": [
{
"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"
}
}
]
}

View File

@@ -1,5 +0,0 @@
# Atom --> Electron rename
d9321f4df751fa32813fab1b6387bbd61bd681d0
34c4c8d5088fa183f56baea28809de6f2a427e02
# Enable JS Semicolons
5d657dece4102e5e5304d42e8004b6ad64c0fcda

30
.gitattributes vendored
View File

@@ -1,30 +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.
*.c text eol=lf
*.cc text eol=lf
*.cpp text eol=lf
*.csv text eol=lf
*.grd text eol=lf
*.grdp text eol=lf
*.gn text eol=lf
*.gni text eol=lf
*.h text eol=lf
*.html text eol=lf
*.idl text eol=lf
*.in text eol=lf
*.js text eol=lf
*.json text eol=lf
*.json5 text eol=lf
*.md text eol=lf
*.mm text eol=lf
*.mojom text eol=lf
*.proto text eol=lf
*.py text eol=lf
*.ps1 text eol=lf
*.sh text eol=lf
*.ts text eol=lf
*.txt text eol=lf

19
.github/CODEOWNERS vendored
View File

@@ -1,19 +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/patch-owners
DEPS @electron/wg-upgrades
# Releases WG
/docs/breaking-changes.md @electron/wg-releases
/npm/ @electron/wg-releases
/script/release @electron/wg-releases
# Security WG
/lib/browser/devtools.ts @electron/wg-security
/lib/browser/guest-view-manager.ts @electron/wg-security
/lib/browser/rpc-server.ts @electron/wg-security
/lib/renderer/security-warnings.ts @electron/wg-security

View File

@@ -1,80 +0,0 @@
name: Bug Report
description: Report an Electron bug
title: "[Bug]: "
labels: "bug :beetle:"
body:
- type: checkboxes
attributes:
label: Preflight Checklist
description: Please ensure you've completed all of the following.
options:
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
required: true
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
required: true
- label: I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a bug report that matches the one I want to file, without success.
required: true
- type: input
attributes:
label: Electron Version
description: |
What version of Electron are you using?
Note: Please only report issues for [currently supported versions of Electron](https://www.electronjs.org/docs/latest/tutorial/support#currently-supported-versions).
placeholder: 17.0.0
validations:
required: true
- type: dropdown
attributes:
label: What operating system are you using?
options:
- Windows
- macOS
- Ubuntu
- Other Linux
- Other (specify below)
validations:
required: true
- type: input
attributes:
label: Operating System Version
description: What operating system version are you using? On Windows, click Start button > Settings > System > About. On macOS, click the Apple Menu > About This Mac. On Linux, use lsb_release or uname -a.
placeholder: "e.g. Windows 10 version 1909, macOS Catalina 10.15.7, or Ubuntu 20.04"
validations:
required: true
- type: dropdown
attributes:
label: What arch are you using?
options:
- x64
- ia32
- arm64 (including Apple Silicon)
- Other (specify below)
validations:
required: true
- type: input
attributes:
label: Last Known Working Electron version
description: What is the last version of Electron this worked in, if applicable?
placeholder: 16.0.0
- type: textarea
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Actual Behavior
description: A clear description of what actually happens.
validations:
required: true
- type: input
attributes:
label: Testcase Gist URL
description: If you can reproduce the issue in a standalone test case, please use [Electron Fiddle](https://github.com/electron/fiddle) to create one and to publish it as a [GitHub gist](https://gist.github.com) and put the gist URL here. This is **the best way** to ensure this issue is triaged quickly.
placeholder: https://gist.github.com/...
- type: textarea
attributes:
label: Additional Information
description: If your problem needs further explanation, or if the issue you're seeing cannot be reproduced in a gist, please add more information here.

View File

@@ -1,40 +0,0 @@
name: Feature Request
description: Suggest an idea for Electron
title: "[Feature Request]: "
labels: "enhancement :sparkles:"
body:
- type: checkboxes
attributes:
label: Preflight Checklist
description: Please ensure you've completed all of the following.
options:
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
required: true
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
required: true
- label: I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a feature request that matches the one I want to file, without success.
required: true
- type: textarea
attributes:
label: Problem Description
description: Please add a clear and concise description of the problem you are seeking to solve with this feature request.
validations:
required: true
- type: textarea
attributes:
label: Proposed Solution
description: Describe the solution you'd like in a clear and concise manner.
validations:
required: true
- type: textarea
attributes:
label: Alternatives Considered
description: A clear and concise description of any alternative solutions or features you've considered.
validations:
required: true
- type: textarea
attributes:
label: Additional Information
description: Add any other context about the problem here.
validations:
required: false

View File

@@ -1,30 +0,0 @@
name: Report Mac App Store Private API Rejection
description: Your app was rejected from the Mac App Store for using private API's
title: "[MAS Rejection]: "
body:
- type: checkboxes
attributes:
label: Preflight Checklist
description: Please ensure you've completed all of the following.
options:
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
required: true
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
required: true
- type: input
attributes:
label: Electron Version
description: What version of Electron are you using?
placeholder: 12.0.0
validations:
required: true
- type: textarea
attributes:
label: Rejection Email
description: Paste the contents of your rejection email here, censoring any private information such as app names.
validations:
required: true
- type: textarea
attributes:
label: Additional Information
description: Add any other context about the problem here.

View File

@@ -1,21 +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/main/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/main/docs/development/testing.md)
- [ ] relevant documentation, tutorials, templates and examples are changed or added
- [ ] [PR release notes](https://github.com/electron/clerk/blob/main/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/main/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/main/README.md#examples -->

27
.github/config.yml vendored
View File

@@ -1,27 +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/main/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/main/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/main/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! 🎉🎉🎉

View File

@@ -1,92 +0,0 @@
name: Branch Created
on:
create:
permissions: {}
jobs:
release-branch-created:
name: Release Branch Created
if: ${{ github.event.ref_type == 'branch' && endsWith(github.event.ref, '-x-y') }}
permissions:
contents: read
pull-requests: write
repository-projects: write # Required for labels
runs-on: ubuntu-latest
steps:
- name: Determine Major Version
id: check-major-version
run: |
if [[ ${{ github.event.ref }} =~ ^([0-9]+)-x-y$ ]]; then
echo "MAJOR=${BASH_REMATCH[1]}" >> "$GITHUB_OUTPUT"
else
echo "Not a release branch: ${{ github.event.ref }}"
fi
- name: New Release Branch Tasks
if: ${{ steps.check-major-version.outputs.MAJOR }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: electron/electron
MAJOR: ${{ steps.check-major-version.outputs.MAJOR }}
NUM_SUPPORTED_VERSIONS: 3
run: |
PREVIOUS_MAJOR=$((MAJOR - 1))
UNSUPPORTED_MAJOR=$((MAJOR - NUM_SUPPORTED_VERSIONS - 1))
# Create new labels
gh label create $MAJOR-x-y --color 8d9ee8 || true
gh label create target/$MAJOR-x-y --color ad244f --description "PR should also be added to the \"${MAJOR}-x-y\" branch." || true
gh label create merged/$MAJOR-x-y --color 61a3c6 --description "PR was merged to the \"${MAJOR}-x-y\" branch." || true
gh label create in-flight/$MAJOR-x-y --color db69a6 || true
gh label create needs-manual-bp/$MAJOR-x-y --color 8b5dba || true
# Change color of old labels
gh label edit $UNSUPPORTED_MAJOR-x-y --color ededed || true
gh label edit target/$UNSUPPORTED_MAJOR-x-y --color ededed || true
gh label edit merged/$UNSUPPORTED_MAJOR-x-y --color ededed || true
gh label edit in-flight/$UNSUPPORTED_MAJOR-x-y --color ededed || true
gh label edit needs-manual-bp/$UNSUPPORTED_MAJOR-x-y --color ededed || true
# Add the new target label to any PRs which:
# * target the previous major
# * are in-flight for the previous major
# * need manual backport for the previous major
for PREVIOUS_MAJOR_LABEL in target/$PREVIOUS_MAJOR-x-y in-flight/$PREVIOUS_MAJOR-x-y needs-manual-bp/$PREVIOUS_MAJOR-x-y; do
PULL_REQUESTS=$(gh pr list --label $PREVIOUS_MAJOR_LABEL --jq .[].number --json number --limit 500)
if [[ $PULL_REQUESTS ]]; then
echo $PULL_REQUESTS | xargs -n 1 gh pr edit --add-label target/$MAJOR-x-y || true
fi
done
- name: Generate GitHub App token
if: ${{ steps.check-major-version.outputs.MAJOR }}
uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1
id: generate-token
with:
creds: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }}
org: electron
- name: Generate Release Project Board Metadata
if: ${{ steps.check-major-version.outputs.MAJOR }}
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1
id: generate-project-metadata
with:
script: |
const major = ${{ steps.check-major-version.outputs.MAJOR }}
core.setOutput("template-view", JSON.stringify({
major,
"next-major": major + 1,
"prev-major": major - 1,
}))
core.setOutput("title", `${major}-x-y`)
- name: Create Release Project Board
if: ${{ steps.check-major-version.outputs.MAJOR }}
uses: dsanders11/project-actions/copy-project@a24415515fa60a22f71f9d9d00e36ca82660cde9 # v1.0.1
with:
drafts: true
project-number: 64
# TODO - Set to public once GitHub fixes their GraphQL bug
# public: true
template-view: ${{ steps.generate-project-metadata.outputs.template-view }}
title: ${{ steps.generate-project-metadata.outputs.title}}
token: ${{ steps.generate-token.outputs.token }}

View File

@@ -1,26 +0,0 @@
name: Issue Commented
on:
issue_comment:
types:
- created
permissions: {}
jobs:
issue-commented:
name: Remove blocked/need-repro on comment
if: ${{ contains(github.event.issue.labels.*.name, 'blocked/need-repro') && !contains(fromJSON('["MEMBER", "OWNER"]'), github.event.comment.author_association) && github.event.comment.user.type != 'Bot' }}
runs-on: ubuntu-latest
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@cc6751b3b5e4edc5b9a4ad0a021ac455653b6dc8 # v1.0.0
id: generate-token
with:
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
- name: Remove label
env:
GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}
ISSUE_URL: ${{ github.event.issue.html_url }}
run: |
gh issue edit $ISSUE_URL --remove-label 'blocked/need-repro'

View File

@@ -1,68 +0,0 @@
name: Issue Labeled
on:
issues:
types: [labeled]
permissions: # added using https://github.com/step-security/secure-workflows
contents: read
jobs:
issue-labeled-blocked:
name: blocked/* label added
if: startsWith(github.event.label.name, 'blocked/')
runs-on: ubuntu-latest
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@cc6751b3b5e4edc5b9a4ad0a021ac455653b6dc8 # v1.0.0
id: generate-token
with:
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
org: electron
- name: Set status
uses: dsanders11/project-actions/edit-item@a24415515fa60a22f71f9d9d00e36ca82660cde9 # v1.0.1
with:
token: ${{ steps.generate-token.outputs.token }}
project-number: 90
field: Status
field-value: 🛑 Blocked
issue-labeled-blocked-need-repro:
name: blocked/need-repro label added
if: github.event.label.name == 'blocked/need-repro'
permissions:
issues: write # for actions-cool/issues-helper to update issues
runs-on: ubuntu-latest
steps:
- name: Check if comment needed
id: check-for-comment
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: electron/electron
run: |
set -eo pipefail
COMMENT_COUNT=$(gh issue view ${{ github.event.issue.number }} --comments --json comments | jq '[ .comments[] | select(.author.login == "electron-issue-triage" or .authorAssociation == "OWNER" or .authorAssociation == "MEMBER") | select(.body | startswith("<!-- blocked/need-repro -->")) ] | length')
if [[ $COMMENT_COUNT -eq 0 ]]; then
echo "SHOULD_COMMENT=1" >> "$GITHUB_OUTPUT"
fi
- name: Generate GitHub App token
if: ${{ steps.check-for-comment.outputs.SHOULD_COMMENT }}
uses: electron/github-app-auth-action@cc6751b3b5e4edc5b9a4ad0a021ac455653b6dc8 # v1.0.0
id: generate-token
with:
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
- name: Create comment
if: ${{ steps.check-for-comment.outputs.SHOULD_COMMENT }}
uses: actions-cool/issues-helper@275328970dbc3bfc3bc43f5fe741bf3638300c0a # v3.3.3
with:
actions: 'create-comment'
token: ${{ steps.generate-token.outputs.token }}
body: |
<!-- blocked/need-repro -->
Hello @${{ github.event.issue.user.login }}. Thanks for reporting this and helping to make Electron better!
Would it be possible for you to make a standalone testcase with only the code necessary to reproduce the issue? For example, [Electron Fiddle](https://www.electronjs.org/fiddle) is a great tool for making small test cases and makes it easy to publish your test case to a [gist](https://gist.github.com) that Electron maintainers can use.
Stand-alone test cases make fixing issues go more smoothly: it ensure everyone's looking at the same issue, it removes all unnecessary variables from the equation, and it can also provide the basis for automated regression tests.
Now adding the https://github.com/electron/electron/labels/blocked%2Fneed-repro label for this reason. After you make a test case, please link to it in a followup comment. This issue will be closed in 10 days if the above is not addressed.

View File

@@ -1,27 +0,0 @@
name: Issue Opened
on:
issues:
types:
- opened
permissions: {}
jobs:
add-to-issue-triage:
if: ${{ contains(github.event.issue.labels.*.name, 'bug :beetle:') }}
runs-on: ubuntu-latest
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1
id: generate-token
with:
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
org: electron
- name: Add to Issue Triage
uses: dsanders11/project-actions/add-item@a24415515fa60a22f71f9d9d00e36ca82660cde9 # v1.0.1
with:
field: Reporter
field-value: ${{ github.event.issue.user.login }}
project-number: 90
token: ${{ steps.generate-token.outputs.token }}

View File

@@ -1,38 +0,0 @@
name: Issue Unlabeled
on:
issues:
types: [unlabeled]
permissions:
contents: read
jobs:
issue-unlabeled-blocked:
name: All blocked/* labels removed
if: startsWith(github.event.label.name, 'blocked/') && github.event.issue.state == 'open'
runs-on: ubuntu-latest
steps:
- name: Check for any blocked labels
id: check-for-blocked-labels
run: |
set -eo pipefail
BLOCKED_LABEL_COUNT=$(echo '${{ toJSON(github.event.issue.labels.*.name) }}' | jq '[ .[] | select(startswith("blocked/")) ] | length')
if [[ $BLOCKED_LABEL_COUNT -eq 0 ]]; then
echo "NOT_BLOCKED=1" >> "$GITHUB_OUTPUT"
fi
- name: Generate GitHub App token
if: ${{ steps.check-for-blocked-labels.outputs.NOT_BLOCKED }}
uses: electron/github-app-auth-action@cc6751b3b5e4edc5b9a4ad0a021ac455653b6dc8 # v1.0.0
id: generate-token
with:
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
org: electron
- name: Set status
if: ${{ steps.check-for-blocked-labels.outputs.NOT_BLOCKED }}
uses: dsanders11/project-actions/edit-item@a24415515fa60a22f71f9d9d00e36ca82660cde9 # v1.0.1
with:
token: ${{ steps.generate-token.outputs.token }}
project-number: 90
field: Status
field-value: 📥 Was Blocked

View File

@@ -1,28 +0,0 @@
name: Pull Request Labeled
on:
pull_request:
types: [labeled]
permissions:
contents: read
jobs:
pull-request-labeled-deprecation-review-complete:
name: deprecation-review/complete label added
if: github.event.label.name == 'deprecation-review/complete ✅'
runs-on: ubuntu-latest
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@cc6751b3b5e4edc5b9a4ad0a021ac455653b6dc8 # v1.0.0
id: generate-token
with:
creds: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }}
org: electron
- name: Set status
uses: dsanders11/project-actions/edit-item@a24415515fa60a22f71f9d9d00e36ca82660cde9 # v1.0.1
with:
token: ${{ steps.generate-token.outputs.token }}
project-number: 94
field: Status
field-value: ✅ Reviewed

View File

@@ -1,54 +0,0 @@
name: Scorecards supply-chain security
on:
# Only the default branch is supported.
branch_protection_rule:
schedule:
- cron: '44 17 * * 0'
push:
branches: [ "main" ]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecards analysis
runs-on: ubuntu-latest
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Used to receive a badge.
id-token: write
steps:
- name: "Checkout code"
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3.1.0
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # tag=v2.1.2
with:
results_file: results.sarif
results_format: sarif
# Publish the results for public repositories to enable scorecard badges. For more details, see
# https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories, `publish_results` will automatically be set to `false`, regardless
# of the value entered here.
publish_results: true
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # tag=v3.1.2
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # tag=v2.1.27
with:
sarif_file: results.sarif

View File

@@ -1,26 +0,0 @@
name: "Check Semantic Commit"
on:
pull_request:
types:
- opened
- edited
- synchronize
permissions:
contents: read
jobs:
main:
permissions:
pull-requests: read # for amannn/action-semantic-pull-request to analyze PRs
statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR
name: Validate PR Title
runs-on: ubuntu-latest
steps:
- name: semantic-pull-request
uses: amannn/action-semantic-pull-request@01d5fd8a8ebb9aafe902c40c53f0f4744f7381eb # tag: v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
validateSingleCommit: false

View File

@@ -1,35 +0,0 @@
name: Check Stable Prep Items
on:
schedule:
- cron: '0 */12 * * *'
workflow_dispatch:
permissions: {}
jobs:
check-stable-prep-items:
name: Check Stable Prep Items
runs-on: ubuntu-latest
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1
id: generate-token
with:
creds: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }}
org: electron
- name: Find Newest Release Project Board
id: find-project-number
env:
GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}
run: |
set -eo pipefail
PROJECT_NUMBER=$(gh project list --owner electron --format json | jq -r '.projects | map(select(.title | test("^[0-9]+-x-y$"))) | max_by(.number) | .number')
echo "PROJECT_NUMBER=$PROJECT_NUMBER" >> "$GITHUB_OUTPUT"
- name: Update Completed Stable Prep Items
uses: dsanders11/project-actions/completed-by@a24415515fa60a22f71f9d9d00e36ca82660cde9 # v1.0.1
with:
field: Prep Status
field-value: ✅ Complete
project-number: ${{ steps.find-project-number.outputs.PROJECT_NUMBER }}
token: ${{ steps.generate-token.outputs.token }}

View File

@@ -1,52 +0,0 @@
name: 'Close stale issues'
on:
workflow_dispatch:
schedule:
# 1:30am every day
- cron: '30 1 * * *'
permissions: {}
jobs:
stale:
runs-on: ubuntu-latest
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@cc6751b3b5e4edc5b9a4ad0a021ac455653b6dc8 # v1.0.0
id: generate-token
with:
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
- uses: actions/stale@5ebf00ea0e4c1561e9b43a292ed34424fb1d4578 # tag: v6.0.1
with:
repo-token: ${{ steps.generate-token.outputs.token }}
days-before-stale: 90
days-before-close: 30
stale-issue-label: stale
operations-per-run: 1750
stale-issue-message: >
This issue has been automatically marked as stale. **If this issue is still affecting you, please leave any comment** (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the [latest version of Electron](https://www.electronjs.org/releases/stable) or in the [beta](https://www.electronjs.org/releases/beta)—please include it with your comment!
close-issue-message: >
This issue has been closed due to inactivity, and will not be monitored. If this is a bug and you can reproduce this issue on a [supported version of Electron](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#timeline) please open a new issue and include instructions for reproducing the issue.
exempt-issue-labels: "discussion,security \U0001F512,enhancement :sparkles:,status/confirmed"
only-pr-labels: not-a-real-label
pending-repro:
runs-on: ubuntu-latest
if: ${{ always() }}
needs: stale
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@cc6751b3b5e4edc5b9a4ad0a021ac455653b6dc8 # v1.0.0
id: generate-token
with:
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
- uses: actions/stale@5ebf00ea0e4c1561e9b43a292ed34424fb1d4578 # tag: v6.0.1
with:
repo-token: ${{ steps.generate-token.outputs.token }}
days-before-stale: -1
days-before-close: 10
remove-stale-when-updated: false
stale-issue-label: blocked/need-repro
stale-pr-label: not-a-real-label
operations-per-run: 1750
close-issue-message: >
Unfortunately, without a way to reproduce this issue, we're unable to continue investigation. This issue has been closed and will not be monitored further. If you're able to provide a minimal test case that reproduces this issue on a [supported version of Electron](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#timeline) please open a new issue and include instructions for reproducing the issue.

View File

@@ -1,74 +0,0 @@
name: Update AppVeyor Image
# Run chron daily Mon-Fri
on:
workflow_dispatch:
schedule:
- cron: '0 8 * * 1-5' # runs 8:00 every business day (see https://crontab.guru)
permissions:
contents: write
pull-requests: write
jobs:
bake-appveyor-image:
name: Bake AppVeyor Image
permissions:
contents: write
pull-requests: write # to create a new PR with updated Appveyor images
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0
with:
fetch-depth: 0
- name: Yarn install
run: |
node script/yarn.js install --frozen-lockfile
- name: Set Repo for Commit
run: git config --global --add safe.directory $GITHUB_WORKSPACE
- name: Check AppVeyor Image
env:
APPVEYOR_TOKEN: ${{ secrets.APPVEYOR_TOKEN }}
run: |
node ./script/prepare-appveyor
if [ -f ./image_version.txt ]; then
echo "APPVEYOR_IMAGE_VERSION="$(cat image_version.txt)"" >> $GITHUB_ENV
rm image_version.txt
fi
- name: (Optionally) Update Appveyor Image
if: ${{ env.APPVEYOR_IMAGE_VERSION }}
uses: mikefarah/yq@1c7dc0e88aad311c89889bc5ce5d8f96931a1bd0 # v4.27.2
with:
cmd: |
yq '.image = "${{ env.APPVEYOR_IMAGE_VERSION }}"' "appveyor.yml" > "appveyor2.yml"
yq '.image = "${{ env.APPVEYOR_IMAGE_VERSION }}"' "appveyor-woa.yml" > "appveyor-woa2.yml"
- name: (Optionally) Generate Commit Diff
if: ${{ env.APPVEYOR_IMAGE_VERSION }}
run: |
diff -w -B appveyor.yml appveyor2.yml > appveyor.diff || true
patch -f appveyor.yml < appveyor.diff
rm appveyor2.yml appveyor.diff
- name: (Optionally) Generate Commit Diff for WOA
if: ${{ env.APPVEYOR_IMAGE_VERSION }}
run: |
diff -w -B appveyor-woa.yml appveyor-woa2.yml > appveyor-woa.diff || true
patch -f appveyor-woa.yml < appveyor-woa.diff
rm appveyor-woa2.yml appveyor-woa.diff
- name: (Optionally) Commit and Pull Request
if: ${{ env.APPVEYOR_IMAGE_VERSION }}
uses: peter-evans/create-pull-request@2b011faafdcbc9ceb11414d64d0573f37c774b04 # v4.2.3
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: 'build: update appveyor image to latest version'
committer: GitHub <noreply@github.com>
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
signoff: false
branch: bump-appveyor-image
delete-branch: true
reviewers: electron/wg-releases
title: 'build: update appveyor image to latest version'
labels: semver/none,no-backport
body: |
This PR updates appveyor.yml to the latest baked image, ${{ env.APPVEYOR_IMAGE_VERSION }}.
Notes: none

68
.gitignore vendored
View File

@@ -1,56 +1,20 @@
.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/brightray/vendor/download/
/vendor/debian_wheezy_arm-sysroot/
/vendor/debian_wheezy_i386-sysroot/
/vendor/python_26/
/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
/npm/checksums.json
.npmrc
# Generated API definitions
electron-api.json
electron.d.ts
# Spec hash calculation
spec/.hash
# Eslint Cache
.eslintcache*
# Generated native addon files
/spec/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
spec/fixtures/logo.png
*.xcodeproj
*.swp
*.pyc
debug.log
npm-debug.log

24
.gitmodules vendored Normal file
View File

@@ -0,0 +1,24 @@
[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
[submodule "vendor/boto"]
path = vendor/boto
url = https://github.com/boto/boto.git

View File

@@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run precommit

View File

@@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run prepack

View File

@@ -1,6 +0,0 @@
{
"default": false,
"no-trailing-spaces": {
"br_spaces": 0
}
}

View File

@@ -1,3 +0,0 @@
{
"extends": "@electron/lint-roller/configs/markdownlint.json"
}

1
.nvmrc
View File

@@ -1 +0,0 @@
16

View File

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

29
.travis.yml Normal file
View File

@@ -0,0 +1,29 @@
git:
depth: 10
notifications:
email: false
language: cpp
compiler: clang
os:
- linux
- osx
env:
- TARGET_ARCH=x64
osx_image: xcode7
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

1591
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,73 +2,74 @@
:+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).
See the [Documentation Styleguide](/docs/styleguide.md).
* Use short, present tense commit messages. See [Commit Message Styleguide](#git-commit-messages).
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 8 weeks. (For more information on Electron's release cadence, see [this blog post](https://electronjs.org/blog/8-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/main/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)
### Dependencies Upgrades Policy
Dependencies in Electron's `package.json` or `yarn.lock` files should only be altered by maintainers. For security reasons, we will not accept PRs that alter our `package.json` or `yarn.lock` files. We invite contributors to make requests updating these files in our issue tracker. If the change is significantly complicated, draft PRs are welcome, with the understanding that these PRs will be closed in favor of a duplicate PR submitted by an Electron maintainer.
## 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

161
DEPS
View File

@@ -1,161 +0,0 @@
gclient_gn_args_from = 'src'
vars = {
'chromium_version':
'120.0.6099.276',
'node_version':
'v18.18.2',
'nan_version':
'e14bdcd1f72d62bca1d541b66da43130384ec213',
'squirrel.mac_version':
'0e5d146ba13101a1302d59ea6e6e0b3cace4ae38',
'reactiveobjc_version':
'74ab5baccc6f7202c8ac69a8d1e152c29dc1ea76',
'mantle_version':
'78d3966b3c331292ea29ec38661b25df0a245948',
'pyyaml_version': '3.12',
'chromium_git': 'https://chromium.googlesource.com',
'electron_git': 'https://github.com/electron',
'nodejs_git': 'https://github.com/nodejs',
'yaml_git': 'https://github.com/yaml',
'squirrel_git': 'https://github.com/Squirrel',
'reactiveobjc_git': 'https://github.com/ReactiveCocoa',
'mantle_git': 'https://github.com/Mantle',
# The path of the sysroots.json file.
'sysroots_json_path': 'electron/script/sysroots.json',
# 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,
'use_rts': False,
'mac_xcode_version': 'default',
'generate_location_tags': False,
# To allow running hooks without parsing the DEPS tree
'process_deps': 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/third_party/pyyaml': {
'url': (Var("yaml_git")) + '/pyyaml.git@' + (Var("pyyaml_version")),
'condition': 'checkout_pyyaml 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': Var("reactiveobjc_git") + '/ReactiveObjC.git@' + Var("reactiveobjc_version"),
'condition': 'process_deps'
},
'src/third_party/squirrel.mac/vendor/Mantle': {
'url': Var("mantle_git") + '/Mantle.git@' + Var("mantle_version"),
'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_npm_deps',
'pattern': 'src/electron/package.json',
'action': [
'python3',
'-c',
'import os, subprocess; os.chdir(os.path.join("src", "electron")); subprocess.check_call(["python3", "script/lib/npx.py", "yarn@' + (Var("yarn_version")) + '", "install", "--frozen-lockfile"]);',
],
},
]
recursedeps = [
'src',
]

View File

@@ -1,5 +1,4 @@
Copyright (c) Electron contributors
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

62
README-ko.md Normal file
View File

@@ -0,0 +1,62 @@
[![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에서 Electron으로 변경되었습니다* :zap:
Electron 프레임워크는 JavaScript, HTML 그리고 CSS를 사용하여 Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주는 프레임워크입니다. 이 프레임워크는 [Node.js](https://nodejs.org) 와
[Chromium](http://www.chromium.org)을 기반으로 만들어 졌으며 [Atom Editor](https://github.com/atom/atom)에 사용되고 있습니다.
Electron에 대한 중요한 알림을 받고 싶다면 Twitter에서 [@ElectronJS](https://twitter.com/electronjs)를 팔로우 하세요.
이 프로젝트는 기여자 규약 1.2를 준수합니다. 이 프로젝트에 참여할 때 코드를 유지해야 합니다. 받아들일 수 없는 행동은 atom@github.com로 보고 하십시오.
## 다운로드
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
# 개발 의존성 모듈 형태로 설치합니다.
npm install electron-prebuilt --save-dev
```
### 미러
- [China](https://npm.taobao.org/mirrors/electron)
## 참조 문서
[Docs](https://github.com/atom/electron/tree/master/docs/README.md)에 개발 가이드와 API 레퍼런스가 있습니다.
Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법도 문서에 포함되어 있으니 참고하시기 바랍니다.
## 참조 문서 (번역)
- [브라질 포르투칼어](https://github.com/atom/electron/tree/master/docs-translations/pt-BR)
- [한국어](https://github.com/atom/electron/tree/master/docs-translations/ko-KR)
- [일본어](https://github.com/atom/electron/tree/master/docs-translations/jp)
- [스페인어](https://github.com/atom/electron/tree/master/docs-translations/es)
- [중국어 간체](https://github.com/atom/electron/tree/master/docs-translations/zh-CN)
- [중국어 번체](https://github.com/atom/electron/tree/master/docs-translations/zh-TW)
## 시작하기
[`atom/electron-quick-start`](https://github.com/atom/electron-quick-start) 저장소를 클론하여 Electron을 간단히 접해볼 수 있습니다.
## 커뮤니티
다음 링크를 통해 커뮤니티에 질문을 올리거나 토론을 나눌 수 있습니다:
- Atom 포럼의 [`electron`](http://discuss.atom.io/category/electron) 카테고리
- Freenode 채팅의 `#atom-shell` 채널
- Slack의 [`Atom`](http://atom-slack.herokuapp.com/) 채널
[awesome-electron](https://github.com/sindresorhus/awesome-electron) 프로젝트엔 커뮤니티가 운영중인 유용한 예제 어플리케이션과 도구, 리소스가 있으니 한번 참고해 보시기 바랍니다.

134
README.md
View File

@@ -1,115 +1,71 @@
[![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/)
[![CircleCI Build Status](https://circleci.com/gh/electron/electron/tree/main.svg?style=shield)](https://circleci.com/gh/electron/electron/tree/main)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/4lggi9dpjc1qob7k/branch/main?svg=true)](https://ci.appveyor.com/project/electron-bot/electron-ljo26/branch/main)
[![Electron Discord Invite](https://img.shields.io/discord/745037351163527189?color=%237289DA&label=chat&logo=discord&logoColor=white)](https://discord.gg/electronjs)
[![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/)
:memo: Available Translations: 🇨🇳 🇧🇷 🇪🇸 🇯🇵 🇷🇺 🇫🇷 🇺🇸 🇩🇪.
View these docs in other languages on our [Crowdin](https://crowdin.com/project/electron) project.
: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).
[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
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/main/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 OS X 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
```
# Install the `electron` command globally in your $PATH
npm install electron-prebuilt -g
For more installation options and troubleshooting tips, see
[installation](docs/tutorial/installation.md). For info on how to manage Electron versions in your apps, see
[Electron versioning](docs/tutorial/electron-versioning.md).
## Platform support
Each Electron release provides binaries for macOS, Windows, and Linux.
* macOS (Catalina and up): Electron provides 64-bit Intel and ARM binaries for macOS. Apple Silicon support was added in Electron 11.
* Windows (Windows 10 and up): Electron provides `ia32` (`x86`), `x64` (`amd64`), and `arm64` binaries for Windows. Windows on ARM support was added in Electron 5.0.8. Support for Windows 7, 8 and 8.1 was [removed in Electron 23, in line with Chromium's Windows deprecation policy](https://www.electronjs.org/blog/windows-7-to-8-1-deprecation-notice).
* Linux: The prebuilt binaries of Electron are built on Ubuntu 20.04. They have also been verified to work on:
* Ubuntu 14.04 and newer
* Fedora 24 and newer
* Debian 8 and newer
## 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
## 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('node: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://npmmirror.com/mirrors/electron/)
- [China](https://npm.taobao.org/mirrors/electron)
See the [Advanced Installation Instructions](https://www.electronjs.org/docs/latest/tutorial/installation#mirror) to learn how to use a custom mirror.
## Documentation
## Documentation translations
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.
We crowdsource translations for our documentation via [Crowdin](https://crowdin.com/project/electron).
We currently accept translations for Chinese (Simplified), French, German, Japanese, Portuguese,
Russian, and Spanish.
## Documentation Translations
## Contributing
- [Brazilian Portuguese](https://github.com/atom/electron/tree/master/docs-translations/pt-BR)
- [Korean](https://github.com/atom/electron/tree/master/docs-translations/ko-KR)
- [Japanese](https://github.com/atom/electron/tree/master/docs-translations/jp)
- [Spanish](https://github.com/atom/electron/tree/master/docs-translations/es)
- [Simplified Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-CN)
- [Traditional Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-TW)
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.
## Quick Start
Clone and run the [`atom/electron-quick-start`](https://github.com/atom/electron-quick-start)
repository to see a minimal Electron app in action.
## Community
Info on reporting bugs, getting help, finding third-party tools and sample apps,
and more can be found on the [Community page](https://www.electronjs.org/community).
You can ask questions and interact with the community in the following
locations:
- [`electron`](http://discuss.atom.io/c/electron) category on the Atom
forums
- `#atom-shell` channel on Freenode
- [`Atom`](http://atom-slack.herokuapp.com/) channel on Slack
## License
[MIT](https://github.com/electron/electron/blob/main/LICENSE)
When using Electron logos, make sure to follow [OpenJS Foundation Trademark Policy](https://openjsf.org/wp-content/uploads/sites/84/2021/01/OpenJS-Foundation-Trademark-Policy-2021-01-12.docx.pdf).
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,17 +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, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/electron/electron/security/advisories/new) tab.
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/main/wg-security/membership-and-notifications.md#notifications) section of the Security WG's [Membership and Notifications](https://github.com/electron/governance/blob/main/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,108 +0,0 @@
# The config is used to bake appveyor images, not for running CI jobs.
# The config expects the following environment variables to be set:
# - "APPVEYOR_BAKE_IMAGE" e.g. 'electron-99.0.4767.0'. Name of the image to be baked.
# Typically named after the Chromium version on which the image is built.
# This can be set dynamically in the prepare-appveyor script.
version: 1.0.{build}
build_cloud: electronhq-16-core
image: base-bake-image
environment:
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
ELECTRON_OUT_DIR: Default
ELECTRON_ENABLE_STACK_DUMPING: 1
MOCHA_REPORTER: mocha-multi-reporters
MOCHA_MULTI_REPORTERS: mocha-appveyor-reporter, tap
GOMA_FALLBACK_ON_AUTH_FAILURE: true
DEPOT_TOOLS_WIN_TOOLCHAIN: 0
PYTHONIOENCODING: UTF-8
# The following lines are needed when baking from a completely new image (eg MicrosoftWindowsServer:WindowsServer:2019-Datacenter:latest via image: base-windows-server2019)
# init:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
# - appveyor version
# - ps: $ErrorActionPreference = 'Stop'
# - ps: 'Write-Host "OS Build: $((Get-CimInstance Win32_OperatingSystem).BuildNumber)"'
# clone_folder: '%USERPROFILE%\image-bake-scripts'
# clone_script:
# - ps: Invoke-WebRequest "https://github.com/appveyor/build-images/archive/1f90d94e74c8243c909a09b994e527584dfcb838.zip" -OutFile "$env:temp\scripts.zip"
# - ps: Expand-Archive -Path "$env:temp\scripts.zip" -DestinationPath "$env:temp\scripts" -Force
# - ps: Copy-Item -Path "$env:temp\scripts\build-images-1f90d94e74c8243c909a09b994e527584dfcb838\scripts\Windows\*" -Destination $env:APPVEYOR_BUILD_FOLDER -Recurse
build_script:
# The following lines are needed when baking from a completely new image (eg MicrosoftWindowsServer:WindowsServer:2019-Datacenter:latest via image: base-windows-server2019)
# - ps: .\init_server.ps1
# - ps: .\extend_system_volume.ps1
# # Restart VM
# - ps: Start-Sleep -s 5; Restart-Computer
# - ps: Start-Sleep -s 5
# - appveyor version
# - ps: .\install_path_utils.ps1
# - ps: .\install_powershell_core.ps1
# - ps: .\install_powershell_get.ps1
# - ps: .\install_7zip.ps1
# - ps: .\install_chocolatey.ps1
# - ps: .\install_webpi.ps1
# - ps: .\install_nuget.ps1
# - ps: .\install_pstools.ps1
# - ps: .\install_git.ps1
# - ps: .\install_git_lfs.ps1
# # Restart VM
# - ps: Start-Sleep -s 5; Restart-Computer
# - ps: Start-Sleep -s 5
# END LINES FOR COMPLETELY NEW IMAGE
- git config --global core.longpaths true
- ps: >-
if (-not (Test-Path -Path C:\projects\src)) {
New-Item -Path C:\projects\src -ItemType Directory
}
- cd C:\projects\
- git clone -q --branch=%APPVEYOR_REPO_BRANCH% https://github.com/electron/electron.git C:\projects\src\electron
- git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
- ps: $env:PATH="$pwd\depot_tools;$env:PATH"
- update_depot_tools.bat
# Uncomment the following line if windows deps change
# - src\electron\script\setup-win-for-dev.bat
- >-
gclient config
--name "src\electron"
--unmanaged
%GCLIENT_EXTRA_ARGS%
"https://github.com/electron/electron"
- ps: cd src\electron
- ps: node script\generate-deps-hash.js
- ps: $depshash = Get-Content .\.depshash -Raw
- ps: Copy-Item -path .\.depshash -destination ..\.depshash
- ps: cd ..\..
- gclient sync --with_branch_heads --with_tags --nohooks
- ps: regsvr32 /s "C:\Program Files\Microsoft Visual Studio\2022\Community\DIA SDK\bin\amd64\msdia140.dll"
- ps: set vs2022_install="C:\Program Files\Microsoft Visual Studio\2022\Community"
# The following lines are needed when baking from a completely new image (eg MicrosoftWindowsServer:WindowsServer:2019-Datacenter:latest via image: base-windows-server2019)
# # Restart VM
# - ps: Start-Sleep -s 5; Restart-Computer
# - ps: Start-Sleep -s 5
# - cd %USERPROFILE%\image-bake-scripts
# - appveyor version
# - ps: .\optimize_dotnet_runtime.ps1
# - ps: .\disable_windows_background_services.ps1
# - ps: .\enforce_windows_firewall.ps1
# - ps: .\cleanup_windows.ps1
# END LINES FOR COMPLETELY NEW IMAGE
on_image_bake:
- ps: >-
echo "Baking image: $env:APPVEYOR_BAKE_IMAGE at dir $PWD"
- ps: Remove-Item -Recurse -Force C:\projects\depot_tools
- ps: Remove-Item -Recurse -Force C:\projects\src\electron
# Uncomment these lines and set APPVEYOR_RDP_PASSWORD in project settings to enable RDP after bake is done
# # on_finish:
# - ps: >-
# $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

View File

@@ -1,327 +0,0 @@
# NOTE IF CHANGING THIS FILE, ALSO APPLY THE CHANGE TO appveyor.yml
# IF APPLICABLE!!!!
#
#
# 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/+/main/docs/reference.md#var_target_cpu
# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordingly
# 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'}.
# 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_STORAGE" Set it to '1' upload a release to the Azure 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
version: 1.0.{build}
build_cloud: electronhq-16-core
image: e-120.0.6099.0
environment:
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
ELECTRON_OUT_DIR: Default
ELECTRON_ENABLE_STACK_DUMPING: 1
ELECTRON_ALSO_LOG_TO_STDERR: 1
MOCHA_REPORTER: mocha-multi-reporters
MOCHA_MULTI_REPORTERS: "@marshallofsound/mocha-appveyor-reporter, tap"
GOMA_FALLBACK_ON_AUTH_FAILURE: true
DEPOT_TOOLS_WIN_TOOLCHAIN: 1
DEPOT_TOOLS_WIN_TOOLCHAIN_BASE_URL: "https://dev-cdn.electronjs.org/windows-toolchains/_"
GYP_MSVS_HASH_27370823e7: 28622d16b1
PYTHONIOENCODING: UTF-8
matrix:
- job_name: Build Arm on X64 Windows
- job_name: Test On Windows On Arm Hardware
job_depends_on: Build Arm on X64 Windows
APPVEYOR_BUILD_WORKER_IMAGE: base-woa
APPVEYOR_BUILD_WORKER_CLOUD: electronhq-woa
clone_script:
- ps: git clone -q $("--branch=" + $Env:APPVEYOR_REPO_BRANCH) $("https://github.com/" + $Env:APPVEYOR_REPO_NAME + ".git") $Env:APPVEYOR_BUILD_FOLDER
- ps: if (!$Env:APPVEYOR_PULL_REQUEST_NUMBER) {$("git checkout -qf " + $Env:APPVEYOR_REPO_COMMIT)}
- ps: if ($Env:APPVEYOR_PULL_REQUEST_NUMBER) {git fetch -q origin +refs/pull/$($Env:APPVEYOR_PULL_REQUEST_NUMBER)/head; git checkout -qf FETCH_HEAD}
clone_folder: C:\projects\src\electron
skip_branch_with_pr: true
# the first failed job cancels other jobs and fails entire build
matrix:
fast_finish: true
for:
- matrix:
only:
- job_name: Build Arm on X64 Windows
build_script:
- ps: |
node script/yarn.js install --frozen-lockfile
node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER
$env:SHOULD_SKIP_ARTIFACT_VALIDATION = "false"
if ($LASTEXITCODE -eq 0) {
Write-warning "Skipping build for doc-only change"
$env:SHOULD_SKIP_ARTIFACT_VALIDATION = "true"
Exit-AppveyorBuild
} else {
$global:LASTEXITCODE = 0
}
- cd ..
- ps: Write-Host "Building $env:GN_CONFIG build"
- git config --global core.longpaths true
- ps: >-
if (Test-Path -Path "$pwd\depot_tools") {
Remove-Item -Recurse -Force $pwd\depot_tools
}
- ps: >-
if (Test-Path -Path "$pwd\build-tools") {
Remove-Item -Recurse -Force $pwd\build-tools
}
- git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
- ps: New-Item -Name depot_tools\.disable_auto_update -ItemType File
- depot_tools\bootstrap\win_tools.bat
- ps: $env:PATH="$pwd\depot_tools;$env:PATH"
- ps: >-
if (Test-Path -Path "$pwd\src\electron") {
Remove-Item -Recurse -Force $pwd\src\electron
}
- 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
- ps: >-
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
- 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
- ps: >-
if (Test-Path 'env:RAW_GOMA_AUTH') {
$goma_login = python3 $env:LOCAL_GOMA_DIR\goma_auth.py info
if ($goma_login -eq 'Login as Fermi Planck') {
Write-warning "Goma authentication is correct";
} else {
Write-warning "WARNING!!!!!! Goma authentication is incorrect; please update Goma auth token.";
$host.SetShouldExit(1)
}
}
- ps: $env:CHROMIUM_BUILDTOOLS_PATH="$pwd\src\buildtools"
- ps: >-
if ($env:GN_CONFIG -ne 'release') {
$env:NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] "
}
- gclient config --name "src\electron" --unmanaged %GCLIENT_EXTRA_ARGS% "https://github.com/electron/electron"
# Patches are applied in the image bake. Check depshash to see if patches have changed.
- ps: $env:RUN_GCLIENT_SYNC="false"
- ps: $depshash_baked = Get-Content .\src\.depshash -Raw
- ps: cd src\electron
- ps: node script\generate-deps-hash.js
- ps: $depshash = Get-Content .\.depshash -Raw
- ps: cd ..\..
- ps: >-
if ($depshash_baked -ne $depshash) {
$env:RUN_GCLIENT_SYNC="true"
}
- if "%RUN_GCLIENT_SYNC%"=="true" ( gclient sync --with_branch_heads --with_tags ) else ( gclient runhooks )
- cd src
- ps: $env:PATH="$pwd\third_party\ninja;$env:PATH"
- 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/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/default_mksnapshot_args
# Remove unused args from mksnapshot_args
- ps: >-
Get-Content out/Default/default_mksnapshot_args | Where-Object { -not $_.Contains('--turbo-profiling-input') -And -not $_.Contains('builtins-pgo') -And -not $_.Contains('The gn arg use_goma=true') } | Set-Content 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 electron:node_headers
- python3 %LOCAL_GOMA_DIR%\goma_ctl.py stat
- ps: >-
Get-CimInstance -Namespace root\cimv2 -Class Win32_product | Select vendor, description, @{l='install_location';e='InstallLocation'}, @{l='install_date';e='InstallDate'}, @{l='install_date_2';e='InstallDate2'}, caption, version, name, @{l='sku_number';e='SKUNumber'} | ConvertTo-Json | Out-File -Encoding utf8 -FilePath .\installed_software.json
- python3 electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json
- 7z a node_headers.zip out\Default\gen\node_headers
- 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') {
python3 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
}
- ps: |
$manifest_file = "electron/script/zip_manifests/dist_zip.win.$env:TARGET_ARCH.manifest"
python3 electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip $manifest_file
if ($LASTEXITCODE -ne 0) {
throw "Zip contains files not listed in the manifest $manifest_file"
}
- ps: |
cd C:\projects\src
$missing_artifacts = $false
if ($env:SHOULD_SKIP_ARTIFACT_VALIDATION -eq 'true') {
Write-warning "Skipping artifact validation for doc-only $env:APPVEYOR_PROJECT_NAME"
} else {
$artifacts_to_validate = 'dist.zip','windows_toolchain_profile.json','shell_browser_ui_unittests.exe','chromedriver.zip','ffmpeg.zip','node_headers.zip','mksnapshot.zip','electron.lib','hunspell_dictionaries.zip'
foreach($artifact_name in $artifacts_to_validate) {
if ($artifact_name -eq 'ffmpeg.zip') {
$artifact_file = "out\ffmpeg\ffmpeg.zip"
} elseif (
$artifact_name -eq 'node_headers.zip') {
$artifact_file = $artifact_name
} else {
$artifact_file = "out\Default\$artifact_name"
}
if (-not(Test-Path $artifact_file)) {
Write-warning "$artifact_name is missing and cannot be added to artifacts"
$missing_artifacts = $true
}
}
}
if ($missing_artifacts) {
throw "Build failed due to missing artifacts"
}
deploy_script:
- cd electron
- ps: >-
if (Test-Path Env:\ELECTRON_RELEASE) {
if (Test-Path Env:\UPLOAD_TO_STORAGE) {
Write-Output "Uploading Electron release distribution to azure"
& python3 script\release\uploaders\upload.py --verbose --upload_to_storage
} else {
Write-Output "Uploading Electron release distribution to github releases"
& python3 script\release\uploaders\upload.py --verbose
}
}
on_finish:
# Uncomment this lines to enable RDP
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
- cd C:\projects\src
- if exist out\Default\windows_toolchain_profile.json ( appveyor-retry appveyor PushArtifact out\Default\windows_toolchain_profile.json )
- if exist out\Default\dist.zip (appveyor-retry appveyor PushArtifact out\Default\dist.zip)
- if exist out\Default\shell_browser_ui_unittests.exe (appveyor-retry appveyor PushArtifact out\Default\shell_browser_ui_unittests.exe)
- if exist out\Default\chromedriver.zip (appveyor-retry appveyor PushArtifact out\Default\chromedriver.zip)
- if exist out\ffmpeg\ffmpeg.zip (appveyor-retry appveyor PushArtifact out\ffmpeg\ffmpeg.zip)
- if exist node_headers.zip (appveyor-retry appveyor PushArtifact node_headers.zip)
- if exist out\Default\mksnapshot.zip (appveyor-retry appveyor PushArtifact out\Default\mksnapshot.zip)
- if exist out\Default\hunspell_dictionaries.zip (appveyor-retry appveyor PushArtifact out\Default\hunspell_dictionaries.zip)
- if exist out\Default\electron.lib (appveyor-retry appveyor PushArtifact out\Default\electron.lib)
- ps: >-
if ((Test-Path "pdb.zip") -And ($env:GN_CONFIG -ne 'release')) {
appveyor-retry appveyor PushArtifact pdb.zip
}
- matrix:
only:
- job_name: Test On Windows On Arm Hardware
environment:
IGNORE_YARN_INSTALL_ERROR: 1
ELECTRON_TEST_RESULTS_DIR: junit
MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap'
MOCHA_REPORTER: mocha-multi-reporters
ELECTRON_SKIP_NATIVE_MODULE_TESTS: true
build_script:
- ps: |
node script/yarn.js install --frozen-lockfile
node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER
if ($LASTEXITCODE -eq 0) {
Write-warning "Skipping build for doc only change"
Exit-AppveyorBuild
} else {
$global:LASTEXITCODE = 0
}
- cd ..
- mkdir out\Default
- cd ..
- ps: |
# Download build artifacts
$apiUrl = 'https://ci.appveyor.com/api'
$build_info = Invoke-RestMethod -Method Get -Uri "$apiUrl/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/builds/$env:APPVEYOR_BUILD_ID"
$artifacts_to_download = @('dist.zip','ffmpeg.zip','node_headers.zip','electron.lib')
foreach ($job in $build_info.build.jobs) {
if ($job.name -eq "Build Arm on X64 Windows") {
$jobId = $job.jobId
foreach($artifact_name in $artifacts_to_download) {
if ($artifact_name -eq 'shell_browser_ui_unittests.exe' -Or $artifact_name -eq 'electron.lib') {
$outfile = "src\out\Default\$artifact_name"
} else {
$outfile = $artifact_name
}
Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/$artifact_name" -OutFile $outfile
}
# Uncomment the following lines to download the pdb.zip to show real stacktraces when crashes happen during testing
# Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/pdb.zip" -OutFile pdb.zip
# 7z x -y -osrc pdb.zip
}
}
- ps: |
$out_default_zips = @('dist.zip')
foreach($zip_name in $out_default_zips) {
7z x -y -osrc\out\Default $zip_name
}
- ps: 7z x -y -osrc\out\ffmpeg ffmpeg.zip
- ps: 7z x -y -osrc node_headers.zip
test_script:
# Workaround for https://github.com/appveyor/ci/issues/2420
- set "PATH=%PATH%;C:\Program Files\Git\mingw64\libexec\git-core"
- ps: |
cd src
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
- set npm_config_nodedir=%cd%\out\Default\gen\node_headers
- set npm_config_arch=arm64
- cd electron
# Explicitly set npm_config_arch because the .env doesn't persist
- ps: >-
if ($env:TARGET_ARCH -eq 'ia32') {
$env:npm_config_arch = "ia32"
}
- echo Running main test suite & node script/yarn test --runners=main --enable-logging --disable-features=CalculateNativeWinOcclusion
- cd ..
- echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg
on_finish:
# Uncomment these lines to enable RDP
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
- if exist electron\electron.log ( appveyor-retry appveyor PushArtifact electron\electron.log )

View File

@@ -1,327 +0,0 @@
# NOTE IF CHANGING THIS FILE, ALSO APPLY THE CHANGE TO appveyor-woa.yml
# IF APPLICABLE!!!!
#
#
# 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/+/main/docs/reference.md#var_target_cpu
# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordingly
# 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'}.
# 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_STORAGE" Set it to '1' upload a release to the Azure 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
version: 1.0.{build}
build_cloud: electronhq-16-core
image: e-120.0.6099.0
environment:
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
ELECTRON_OUT_DIR: Default
ELECTRON_ENABLE_STACK_DUMPING: 1
ELECTRON_ALSO_LOG_TO_STDERR: 1
MOCHA_REPORTER: mocha-multi-reporters
MOCHA_MULTI_REPORTERS: "@marshallofsound/mocha-appveyor-reporter, tap"
GOMA_FALLBACK_ON_AUTH_FAILURE: true
DEPOT_TOOLS_WIN_TOOLCHAIN: 1
DEPOT_TOOLS_WIN_TOOLCHAIN_BASE_URL: "https://dev-cdn.electronjs.org/windows-toolchains/_"
GYP_MSVS_HASH_27370823e7: 28622d16b1
PYTHONIOENCODING: UTF-8
matrix:
- job_name: Build
- job_name: Test
job_depends_on: Build
clone_script:
- ps: git clone -q $("--branch=" + $Env:APPVEYOR_REPO_BRANCH) $("https://github.com/" + $Env:APPVEYOR_REPO_NAME + ".git") $Env:APPVEYOR_BUILD_FOLDER
- ps: if (!$Env:APPVEYOR_PULL_REQUEST_NUMBER) {$("git checkout -qf " + $Env:APPVEYOR_REPO_COMMIT)}
- ps: if ($Env:APPVEYOR_PULL_REQUEST_NUMBER) {git fetch -q origin +refs/pull/$($Env:APPVEYOR_PULL_REQUEST_NUMBER)/head; git checkout -qf FETCH_HEAD}
clone_folder: C:\projects\src\electron
skip_branch_with_pr: true
# the first failed job cancels other jobs and fails entire build
matrix:
fast_finish: true
for:
- matrix:
only:
- job_name: Build
build_script:
- ps: |
node script/yarn.js install --frozen-lockfile
node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER
$env:SHOULD_SKIP_ARTIFACT_VALIDATION = "false"
if ($LASTEXITCODE -eq 0) {
Write-warning "Skipping build for doc-only change"
$env:SHOULD_SKIP_ARTIFACT_VALIDATION = "true"
Exit-AppveyorBuild
} else {
$global:LASTEXITCODE = 0
}
- cd ..
- ps: Write-Host "Building $env:GN_CONFIG build"
- git config --global core.longpaths true
- ps: >-
if (Test-Path -Path "$pwd\depot_tools") {
Remove-Item -Recurse -Force $pwd\depot_tools
}
- ps: >-
if (Test-Path -Path "$pwd\build-tools") {
Remove-Item -Recurse -Force $pwd\build-tools
}
- git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
- ps: New-Item -Name depot_tools\.disable_auto_update -ItemType File
- depot_tools\bootstrap\win_tools.bat
- ps: $env:PATH="$pwd\depot_tools;$env:PATH"
- ps: >-
if (Test-Path -Path "$pwd\src\electron") {
Remove-Item -Recurse -Force $pwd\src\electron
}
- 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
- ps: >-
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
- 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
- ps: >-
if (Test-Path 'env:RAW_GOMA_AUTH') {
$goma_login = python3 $env:LOCAL_GOMA_DIR\goma_auth.py info
if ($goma_login -eq 'Login as Fermi Planck') {
Write-warning "Goma authentication is correct";
} else {
Write-warning "WARNING!!!!!! Goma authentication is incorrect; please update Goma auth token.";
$host.SetShouldExit(1)
}
}
- ps: $env:CHROMIUM_BUILDTOOLS_PATH="$pwd\src\buildtools"
- ps: >-
if ($env:GN_CONFIG -ne 'release') {
$env:NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] "
}
- gclient config --name "src\electron" --unmanaged %GCLIENT_EXTRA_ARGS% "https://github.com/electron/electron"
# Patches are applied in the image bake. Check depshash to see if patches have changed.
- ps: $env:RUN_GCLIENT_SYNC="false"
- ps: $depshash_baked = Get-Content .\src\.depshash -Raw
- ps: cd src\electron
- ps: node script\generate-deps-hash.js
- ps: $depshash = Get-Content .\.depshash -Raw
- ps: cd ..\..
- ps: >-
if ($depshash_baked -ne $depshash) {
$env:RUN_GCLIENT_SYNC="true"
}
- if "%RUN_GCLIENT_SYNC%"=="true" ( gclient sync --with_branch_heads --with_tags ) else ( gclient runhooks )
- cd src
- ps: $env:PATH="$pwd\third_party\ninja;$env:PATH"
- 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/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/default_mksnapshot_args
# Remove unused args from mksnapshot_args
- ps: >-
Get-Content out/Default/default_mksnapshot_args | Where-Object { -not $_.Contains('--turbo-profiling-input') -And -not $_.Contains('builtins-pgo') -And -not $_.Contains('The gn arg use_goma=true') } | Set-Content 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 electron:node_headers
- python3 %LOCAL_GOMA_DIR%\goma_ctl.py stat
- ps: >-
Get-CimInstance -Namespace root\cimv2 -Class Win32_product | Select vendor, description, @{l='install_location';e='InstallLocation'}, @{l='install_date';e='InstallDate'}, @{l='install_date_2';e='InstallDate2'}, caption, version, name, @{l='sku_number';e='SKUNumber'} | ConvertTo-Json | Out-File -Encoding utf8 -FilePath .\installed_software.json
- python3 electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json
- 7z a node_headers.zip out\Default\gen\node_headers
- 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') {
python3 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
}
- ps: |
$manifest_file = "electron/script/zip_manifests/dist_zip.win.$env:TARGET_ARCH.manifest"
python3 electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip $manifest_file
if ($LASTEXITCODE -ne 0) {
throw "Zip contains files not listed in the manifest $manifest_file"
}
- ps: |
cd C:\projects\src
$missing_artifacts = $false
if ($env:SHOULD_SKIP_ARTIFACT_VALIDATION -eq 'true') {
Write-warning "Skipping artifact validation for doc-only $env:APPVEYOR_PROJECT_NAME"
} else {
$artifacts_to_validate = 'dist.zip','windows_toolchain_profile.json','shell_browser_ui_unittests.exe','chromedriver.zip','ffmpeg.zip','node_headers.zip','mksnapshot.zip','electron.lib','hunspell_dictionaries.zip'
foreach($artifact_name in $artifacts_to_validate) {
if ($artifact_name -eq 'ffmpeg.zip') {
$artifact_file = "out\ffmpeg\ffmpeg.zip"
} elseif (
$artifact_name -eq 'node_headers.zip') {
$artifact_file = $artifact_name
} else {
$artifact_file = "out\Default\$artifact_name"
}
if (-not(Test-Path $artifact_file)) {
Write-warning "$artifact_name is missing and cannot be added to artifacts"
$missing_artifacts = $true
}
}
}
if ($missing_artifacts) {
throw "Build failed due to missing artifacts"
}
deploy_script:
- cd electron
- ps: >-
if (Test-Path Env:\ELECTRON_RELEASE) {
if (Test-Path Env:\UPLOAD_TO_STORAGE) {
Write-Output "Uploading Electron release distribution to azure"
& python3 script\release\uploaders\upload.py --verbose --upload_to_storage
} else {
Write-Output "Uploading Electron release distribution to github releases"
& python3 script\release\uploaders\upload.py --verbose
}
}
on_finish:
# Uncomment this lines to enable RDP
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
- cd C:\projects\src
- if exist out\Default\windows_toolchain_profile.json ( appveyor-retry appveyor PushArtifact out\Default\windows_toolchain_profile.json )
- if exist out\Default\dist.zip (appveyor-retry appveyor PushArtifact out\Default\dist.zip)
- if exist out\Default\shell_browser_ui_unittests.exe (appveyor-retry appveyor PushArtifact out\Default\shell_browser_ui_unittests.exe)
- if exist out\Default\chromedriver.zip (appveyor-retry appveyor PushArtifact out\Default\chromedriver.zip)
- if exist out\ffmpeg\ffmpeg.zip (appveyor-retry appveyor PushArtifact out\ffmpeg\ffmpeg.zip)
- if exist node_headers.zip (appveyor-retry appveyor PushArtifact node_headers.zip)
- if exist out\Default\mksnapshot.zip (appveyor-retry appveyor PushArtifact out\Default\mksnapshot.zip)
- if exist out\Default\hunspell_dictionaries.zip (appveyor-retry appveyor PushArtifact out\Default\hunspell_dictionaries.zip)
- if exist out\Default\electron.lib (appveyor-retry appveyor PushArtifact out\Default\electron.lib)
- ps: >-
if ((Test-Path "pdb.zip") -And ($env:GN_CONFIG -ne 'release')) {
appveyor-retry appveyor PushArtifact pdb.zip
}
- matrix:
only:
- job_name: Test
init:
- ps: |
if ($env:RUN_TESTS -ne 'true') {
Write-warning "Skipping tests for $env:APPVEYOR_PROJECT_NAME"; Exit-AppveyorBuild
}
build_script:
- ps: |
node script/yarn.js install --frozen-lockfile
node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER
if ($LASTEXITCODE -eq 0) {
Write-warning "Skipping build for doc only change"
Exit-AppveyorBuild
} else {
$global:LASTEXITCODE = 0
}
- cd ..
- mkdir out\Default
- cd ..
- ps: |
# Download build artifacts
$apiUrl = 'https://ci.appveyor.com/api'
$build_info = Invoke-RestMethod -Method Get -Uri "$apiUrl/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/builds/$env:APPVEYOR_BUILD_ID"
$artifacts_to_download = @('dist.zip','shell_browser_ui_unittests.exe','chromedriver.zip','ffmpeg.zip','node_headers.zip','mksnapshot.zip','electron.lib')
foreach ($job in $build_info.build.jobs) {
if ($job.name -eq "Build") {
$jobId = $job.jobId
foreach($artifact_name in $artifacts_to_download) {
if ($artifact_name -eq 'shell_browser_ui_unittests.exe' -Or $artifact_name -eq 'electron.lib') {
$outfile = "src\out\Default\$artifact_name"
} else {
$outfile = $artifact_name
}
Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/$artifact_name" -OutFile $outfile
}
# Uncomment the following lines to download the pdb.zip to show real stacktraces when crashes happen during testing
# Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/pdb.zip" -OutFile pdb.zip
# 7z x -y -osrc pdb.zip
}
}
- ps: |
$out_default_zips = @('dist.zip','chromedriver.zip','mksnapshot.zip')
foreach($zip_name in $out_default_zips) {
7z x -y -osrc\out\Default $zip_name
}
- ps: 7z x -y -osrc\out\ffmpeg ffmpeg.zip
- ps: 7z x -y -osrc node_headers.zip
test_script:
# Workaround for https://github.com/appveyor/ci/issues/2420
- set "PATH=%PATH%;C:\Program Files\Git\mingw64\libexec\git-core"
- ps: |
cd src
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
- cd electron
# Explicitly set npm_config_arch because the .env doesn't persist
- ps: >-
if ($env:TARGET_ARCH -eq 'ia32') {
$env:npm_config_arch = "ia32"
}
- echo Running main test suite & node script/yarn test -- --trace-uncaught --runners=main --enable-logging=file --log-file=%cd%\electron.log
- echo Running native test suite & node script/yarn test -- --trace-uncaught --runners=native --enable-logging=file --log-file=%cd%\electron.log
- cd ..
- 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"
- echo Verifying mksnapshot & python electron\script\verify-mksnapshot.py --build-dir out\Default --source-root %cd%
- echo "Done verifying mksnapshot"
- echo Verifying chromedriver & python electron\script\verify-chromedriver.py --build-dir out\Default --source-root %cd%
- echo "Done verifying chromedriver"
on_finish:
# Uncomment these lines to enable RDP
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
- if exist electron\electron.log ( appveyor-retry appveyor PushArtifact electron\electron.log )

567
atom.gyp Normal file
View File

@@ -0,0 +1,567 @@
{
'variables': {
'project_name%': 'electron',
'product_name%': 'Electron',
'company_name%': 'GitHub, Inc',
'company_abbr%': 'github',
'version%': '0.34.4',
},
'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',
],
},
{
'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)',
],
},
],
'conditions': [
['mas_build==0', {
'copies': [
{
'destination': '<(PRODUCT_DIR)/<(product_name).app/Contents/Frameworks',
'files': [
'external_binaries/Squirrel.framework',
'external_binaries/ReactiveCocoa.framework',
'external_binaries/Mantle.framework',
],
},
],
}],
],
}, { # OS=="mac"
'dependencies': [
'make_locale_paks',
],
}], # 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)/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)/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',
],
'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" and mas_build==0', {
'dependencies': [
'vendor/crashpad/client/client.gyp:crashpad_client',
'vendor/crashpad/handler/handler.gyp:crashpad_handler',
],
'link_settings': {
# Do not link with QTKit for mas build.
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/QTKit.framework',
],
},
}], # OS=="mac" and mas_build==0
['OS=="mac" and mas_build==1', {
'defines': [
'MAS_BUILD',
],
'sources!': [
'atom/browser/auto_updater_mac.mm',
'atom/common/crash_reporter/crash_reporter_mac.h',
'atom/common/crash_reporter/crash_reporter_mac.mm',
],
}], # OS=="mac" and mas_build==1
['OS=="linux"', {
'link_settings': {
'ldflags': [
# 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',
],
},
'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)',
],
},
],
'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': 'Fix path of ffmpeg',
'action': [
'install_name_tool',
'-change',
'@loader_path/libffmpeg.dylib',
'@rpath/libffmpeg.dylib',
'${BUILT_PRODUCTS_DIR}/<(product_name) Framework.framework/Versions/A/<(product_name) Framework',
],
},
{
'postbuild_name': 'Add symlinks for framework subdirectories',
'action': [
'tools/mac/create-framework-subdir-symlinks.sh',
'<(product_name) Framework',
'Libraries',
],
},
],
'conditions': [
['mas_build==0', {
'link_settings': {
'libraries': [
'external_binaries/Squirrel.framework',
'external_binaries/ReactiveCocoa.framework',
'external_binaries/Mantle.framework',
],
},
'copies': [
{
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Resources',
'files': [
'<(PRODUCT_DIR)/crashpad_handler',
],
},
],
}],
],
}, # target framework
{
'target_name': '<(project_name)_helper',
'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,114 @@
// 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/atom_version.h"
#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 "content/public/common/user_agent.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;
}
std::string AtomContentClient::GetUserAgent() const {
return content::BuildUserAgentFromProduct(
"Chrome/" CHROME_VERSION_STRING " "
ATOM_PRODUCT_NAME "/" ATOM_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->GetSwitchValuePath(
switches::kPpapiFlashPath);
if (flash_path.empty())
return;
auto flash_version = command_line->GetSwitchValueASCII(
switches::kPpapiFlashVersion);
plugins->push_back(
CreatePepperFlashInfo(flash_path, flash_version));
}
} // namespace atom

View File

@@ -0,0 +1,36 @@
// 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;
std::string GetUserAgent() 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,38 @@
// 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 "base/mac/scoped_nsautorelease_pool.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::ScopedNSAutoreleasePool pool;
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

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

@@ -0,0 +1,193 @@
// 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/at_exit.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::AtExitManager atexit_manager;
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();
base::AtExitManager atexit_manager;
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,149 @@
// 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 <iostream>
#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 {
namespace {
bool IsBrowserProcess(base::CommandLine* cmd) {
std::string process_type = cmd->GetSwitchValueASCII(switches::kProcessType);
return process_type.empty();
}
} // namespace
AtomMainDelegate::AtomMainDelegate() {
}
AtomMainDelegate::~AtomMainDelegate() {
}
bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
auto command_line = base::CommandLine::ForCurrentProcess();
logging::LoggingSettings settings;
#if defined(OS_WIN)
// On Windows the terminal returns immediately, so we add a new line to
// prevent output in the same line as the prompt.
if (IsBrowserProcess(command_line))
std::wcout << std::endl;
#if defined(DEBUG)
// Print logging to debug.log on Windows
settings.logging_dest = logging::LOG_TO_ALL;
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)
#else // defined(OS_WIN)
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
#endif // !defined(OS_WIN)
// Only enable logging when --enable-logging is specified.
scoped_ptr<base::Environment> env(base::Environment::Create());
if (!command_line->HasSwitch(switches::kEnableLogging) &&
!env->HasVar("ELECTRON_ENABLE_LOGGING")) {
settings.logging_dest = logging::LOG_NONE;
logging::SetMinLogLevel(logging::LOG_NUM_SEVERITIES);
}
logging::InitLogging(settings);
// Logging with pid and timestamp.
logging::SetLogItems(true, false, true, false);
// Enable convient stack printing.
bool enable_stack_dumping = env->HasVar("ELECTRON_ENABLE_STACK_DUMPING");
#if defined(DEBUG) && defined(OS_LINUX)
enable_stack_dumping = true;
#endif
if (enable_stack_dumping)
base::debug::EnableInProcessStackDumping();
return brightray::MainDelegate::BasicStartupComplete(exit_code);
}
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 (!IsBrowserProcess(command_line))
return;
// 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

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

@@ -0,0 +1,74 @@
// 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/app/uv_task_runner.h"
#include "atom/browser/javascript_environment.h"
#include "atom/browser/node_debugger.h"
#include "base/command_line.h"
#include "atom/common/node_includes.h"
#include "base/thread_task_runner_handle.h"
#include "gin/array_buffer.h"
#include "gin/public/isolate_holder.h"
#include "gin/v8_initializer.h"
namespace atom {
int NodeMain(int argc, char *argv[]) {
base::CommandLine::Init(argc, argv);
int exit_code = 1;
{
// Feed gin::PerIsolateData with a task runner.
argv = uv_setup_args(argc, argv);
uv_loop_t* loop = uv_default_loop();
scoped_refptr<UvTaskRunner> uv_task_runner(new UvTaskRunner(loop));
base::ThreadTaskRunnerHandle handle(uv_task_runner);
gin::V8Initializer::LoadV8Snapshot();
gin::V8Initializer::LoadV8Natives();
JavascriptEnvironment gin_env;
int exec_argc;
const char** exec_argv;
node::Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);
node::Environment* env = node::CreateEnvironment(
gin_env.isolate(), loop, gin_env.context(), argc, argv,
exec_argc, exec_argv);
// Start our custom debugger implementation.
NodeDebugger node_debugger(gin_env.isolate());
if (node_debugger.IsRunning())
env->AssignToContext(v8::Debug::GetDebugContext());
node::LoadEnvironment(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,60 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/app/uv_task_runner.h"
#include "base/stl_util.h"
namespace atom {
UvTaskRunner::UvTaskRunner(uv_loop_t* loop) : loop_(loop) {
}
UvTaskRunner::~UvTaskRunner() {
for (auto& iter : tasks_) {
uv_unref(reinterpret_cast<uv_handle_t*>(iter.first));
delete iter.first;
}
}
bool UvTaskRunner::PostDelayedTask(const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) {
uv_timer_t* timer = new uv_timer_t;
timer->data = this;
uv_timer_init(loop_, timer);
uv_timer_start(timer, UvTaskRunner::OnTimeout, delay.InMilliseconds(), 0);
tasks_[timer] = task;
return true;
}
bool UvTaskRunner::RunsTasksOnCurrentThread() const {
return true;
}
bool UvTaskRunner::PostNonNestableDelayedTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) {
return PostDelayedTask(from_here, task, delay);;
}
// static
void UvTaskRunner::OnTimeout(uv_timer_t* timer) {
UvTaskRunner* self = static_cast<UvTaskRunner*>(timer->data);
if (!ContainsKey(self->tasks_, timer))
return;
self->tasks_[timer].Run();
self->tasks_.erase(timer);
uv_timer_stop(timer);
uv_close(reinterpret_cast<uv_handle_t*>(timer), UvTaskRunner::OnClose);
}
// static
void UvTaskRunner::OnClose(uv_handle_t* handle) {
delete reinterpret_cast<uv_timer_t*>(handle);
}
} // namespace atom

45
atom/app/uv_task_runner.h Normal file
View File

@@ -0,0 +1,45 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_APP_UV_TASK_RUNNER_H_
#define ATOM_APP_UV_TASK_RUNNER_H_
#include <map>
#include "base/callback.h"
#include "base/single_thread_task_runner.h"
#include "vendor/node/deps/uv/include/uv.h"
namespace atom {
// TaskRunner implementation that posts tasks into libuv's default loop.
class UvTaskRunner : public base::SingleThreadTaskRunner {
public:
explicit UvTaskRunner(uv_loop_t* loop);
~UvTaskRunner() override;
// base::SingleThreadTaskRunner:
bool PostDelayedTask(const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) override;
bool RunsTasksOnCurrentThread() const override;
bool PostNonNestableDelayedTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) override;
private:
static void OnTimeout(uv_timer_t* timer);
static void OnClose(uv_handle_t* handle);
uv_loop_t* loop_;
std::map<uv_timer_t*, base::Closure> tasks_;
DISALLOW_COPY_AND_ASSIGN(UvTaskRunner);
};
} // namespace atom
#endif // ATOM_APP_UV_TASK_RUNNER_H_

View File

@@ -0,0 +1,443 @@
// 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>
#include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/api/atom_api_session.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/browser.h"
#include "atom/browser/login_handler.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/net_converter.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/node_includes.h"
#include "atom/common/options_switches.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 "content/public/common/content_switches.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "ui/base/l10n/l10n_util.h"
#if defined(OS_WIN)
#include "base/strings/utf_string_conversions.h"
#endif
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;
}
bool NotificationCallbackWrapper(
const ProcessSingleton::NotificationCallback& callback,
const base::CommandLine::StringVector& cmd,
const base::FilePath& cwd) {
// Make sure the callback is called after app gets ready.
if (Browser::Get()->is_ready()) {
callback.Run(cmd, cwd);
} else {
scoped_refptr<base::SingleThreadTaskRunner> task_runner(
base::ThreadTaskRunnerHandle::Get());
task_runner->PostTask(
FROM_HERE, base::Bind(base::IgnoreResult(callback), cmd, cwd));
}
// ProcessSingleton needs to know whether current process is quiting.
return !Browser::Get()->is_shutting_down();
}
void OnClientCertificateSelected(
v8::Isolate* isolate,
std::shared_ptr<content::ClientCertificateDelegate> delegate,
mate::Arguments* args) {
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());
}
void PassLoginInformation(scoped_refptr<LoginHandler> login_handler,
mate::Arguments* args) {
base::string16 username, password;
if (args->GetNext(&username) && args->GetNext(&password))
login_handler->Login(username, password);
else
login_handler->CancelAuth();
}
} // namespace
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");
if (process_singleton_.get()) {
process_singleton_->Cleanup();
process_singleton_.reset();
}
}
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::OnActivate(bool has_visible_windows) {
Emit("activate", has_visible_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::OnLogin(LoginHandler* login_handler) {
// Convert the args explicitly since they will be passed for twice.
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto web_contents =
WebContents::CreateFrom(isolate(), login_handler->GetWebContents());
auto request = mate::ConvertToV8(isolate(), login_handler->request());
auto auth_info = mate::ConvertToV8(isolate(), login_handler->auth_info());
auto callback = mate::ConvertToV8(
isolate(),
base::Bind(&PassLoginInformation, make_scoped_refptr(login_handler)));
bool prevent_default =
Emit("login", web_contents, request, auth_info, callback);
// Also pass it to WebContents.
if (!prevent_default)
prevent_default =
web_contents->Emit("login", request, auth_info, callback);
// Default behavior is to always cancel the auth.
if (!prevent_default)
login_handler->CancelAuth();
}
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::AllowNTLMCredentialsForAllDomains(bool should_allow) {
auto browser_context = static_cast<AtomBrowserContext*>(
AtomBrowserMainParts::Get()->browser_context());
browser_context->AllowNTLMCredentialsForAllDomains(should_allow);
}
std::string App::GetLocale() {
return l10n_util::GetApplicationLocale("");
}
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_);
}
bool App::MakeSingleInstance(
const ProcessSingleton::NotificationCallback& callback) {
if (process_singleton_.get())
return false;
base::FilePath user_dir;
PathService::Get(brightray::DIR_USER_DATA, &user_dir);
process_singleton_.reset(new ProcessSingleton(
user_dir, base::Bind(NotificationCallbackWrapper, callback)));
switch (process_singleton_->NotifyOtherProcessOrCreate()) {
case ProcessSingleton::NotifyResult::LOCK_ERROR:
case ProcessSingleton::NotifyResult::PROFILE_IN_USE:
case ProcessSingleton::NotifyResult::PROCESS_NOTIFIED:
process_singleton_.reset();
return true;
case ProcessSingleton::NotifyResult::PROCESS_NONE:
default: // Shouldn't be needed, but VS warns if it is not there.
return false;
}
}
mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
auto browser = base::Unretained(Browser::Get());
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("quit", base::Bind(&Browser::Quit, browser))
.SetMethod("exit", base::Bind(&Browser::Exit, 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))
.SetMethod("setAppUserModelId",
base::Bind(&Browser::SetAppUserModelID, 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("allowNTLMCredentialsForAllDomains",
&App::AllowNTLMCredentialsForAllDomains)
.SetMethod("getLocale", &App::GetLocale)
.SetMethod("makeSingleInstance", &App::MakeSingleInstance)
.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();
if (switch_string == atom::switches::kPpapiFlashPath ||
switch_string == atom::switches::kClientCertificate ||
switch_string == switches::kLogNetLog) {
base::FilePath path;
args->GetNext(&path);
command_line->AppendSwitchPath(switch_string, path);
return;
}
std::string value;
if (args->GetNext(&value))
command_line->AppendSwitchASCII(switch_string, value);
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,87 @@
// 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 "atom/common/native_mate_converters/callback.h"
#include "chrome/browser/process_singleton.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "native_mate/handle.h"
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 OnActivate(bool has_visible_windows) override;
void OnWillFinishLaunching() override;
void OnFinishLaunching() override;
void OnSelectCertificate(
content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) override;
void OnLogin(LoginHandler* login_handler) 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 AllowNTLMCredentialsForAllDomains(bool should_allow);
bool MakeSingleInstance(
const ProcessSingleton::NotificationCallback& callback);
std::string GetLocale();
v8::Local<v8::Value> DefaultSession(v8::Isolate* isolate);
v8::Global<v8::Value> default_session_;
scoped_ptr<ProcessSingleton> process_singleton_;
DISALLOW_COPY_AND_ASSIGN(App);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_APP_H_

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.
#include "atom/browser/api/atom_api_auto_updater.h"
#include "base/time/time.h"
#include "atom/browser/browser.h"
#include "atom/browser/native_window.h"
#include "atom/browser/window_list.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/node_includes.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
namespace mate {
template<>
struct Converter<base::Time> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const base::Time& val) {
v8::MaybeLocal<v8::Value> date = v8::Date::New(
isolate->GetCurrentContext(), val.ToJsTime());
if (date.IsEmpty())
return v8::Null(isolate);
else
return date.ToLocalChecked();
}
};
} // namespace mate
namespace atom {
namespace api {
AutoUpdater::AutoUpdater() {
auto_updater::AutoUpdater::SetDelegate(this);
}
AutoUpdater::~AutoUpdater() {
auto_updater::AutoUpdater::SetDelegate(nullptr);
}
void AutoUpdater::OnError(const std::string& message) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto error = v8::Exception::Error(mate::StringToV8(isolate(), message));
EmitCustomEvent(
"error",
error->ToObject(isolate()->GetCurrentContext()).ToLocalChecked(),
// Message is also emitted to keep compatibility with old code.
message);
}
void AutoUpdater::OnCheckingForUpdate() {
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& url) {
Emit("update-downloaded", release_notes, release_name, release_date, url,
// Keep compatibility with old APIs.
base::Bind(&AutoUpdater::QuitAndInstall, base::Unretained(this)));
}
void AutoUpdater::OnWindowAllClosed() {
QuitAndInstall();
}
mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder(
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 we don't have any window then quitAndInstall immediately.
WindowList* window_list = WindowList::GetInstance();
if (window_list->size() == 0) {
auto_updater::AutoUpdater::QuitAndInstall();
return;
}
// Otherwise do the restart after all windows have been closed.
window_list->AddObserver(this);
for (NativeWindow* window : *window_list)
window->Close();
}
// static
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 "atom/browser/api/event_emitter.h"
#include "atom/browser/auto_updater.h"
#include "atom/browser/window_list_observer.h"
#include "native_mate/handle.h"
namespace atom {
namespace api {
class AutoUpdater : public mate::EventEmitter,
public auto_updater::Delegate,
public WindowListObserver {
public:
static mate::Handle<AutoUpdater> Create(v8::Isolate* isolate);
protected:
AutoUpdater();
virtual ~AutoUpdater();
// Delegate implementations.
void OnError(const std::string& error) override;
void OnCheckingForUpdate() override;
void OnUpdateAvailable() override;
void OnUpdateNotAvailable() override;
void OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url) override;
// WindowListObserver:
void OnWindowAllClosed() override;
// mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
private:
void QuitAndInstall();
DISALLOW_COPY_AND_ASSIGN(AutoUpdater);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_AUTO_UPDATER_H_

View File

@@ -0,0 +1,90 @@
// 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 "atom/common/node_includes.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "content/public/browser/tracing_controller.h"
#include "native_mate/dictionary.h"
using content::TracingController;
namespace mate {
template<>
struct Converter<base::trace_event::TraceConfig> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
base::trace_event::TraceConfig* out) {
Dictionary options;
if (!ConvertFromV8(isolate, val, &options))
return false;
std::string category_filter, trace_options;
if (!options.Get("categoryFilter", &category_filter) ||
!options.Get("traceOptions", &trace_options))
return false;
*out = base::trace_event::TraceConfig(category_filter, trace_options);
return true;
}
};
} // 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,346 @@
// 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"
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();
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,205 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_download_item.h"
#include <map>
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/node_includes.h"
#include "base/memory/linked_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "native_mate/dictionary.h"
#include "net/base/filename_util.h"
namespace mate {
template<>
struct Converter<content::DownloadItem::DownloadState> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
content::DownloadItem::DownloadState state) {
std::string download_state;
switch (state) {
case content::DownloadItem::COMPLETE:
download_state = "completed";
break;
case content::DownloadItem::CANCELLED:
download_state = "cancelled";
break;
case content::DownloadItem::INTERRUPTED:
download_state = "interrupted";
break;
default:
break;
}
return ConvertToV8(isolate, download_state);
}
};
} // namespace mate
namespace atom {
namespace api {
namespace {
// The wrapDownloadItem funtion which is implemented in JavaScript
using WrapDownloadItemCallback = base::Callback<void(v8::Local<v8::Value>)>;
WrapDownloadItemCallback g_wrap_download_item;
char kDownloadItemSavePathKey[] = "DownloadItemSavePathKey";
std::map<uint32, linked_ptr<v8::Global<v8::Value>>> g_download_item_objects;
} // namespace
DownloadItem::SavePathData::SavePathData(const base::FilePath& path) :
path_(path) {
}
const base::FilePath& DownloadItem::SavePathData::path() {
return path_;
}
DownloadItem::DownloadItem(content::DownloadItem* download_item) :
download_item_(download_item) {
download_item_->AddObserver(this);
}
DownloadItem::~DownloadItem() {
Destroy();
}
void DownloadItem::Destroy() {
if (download_item_) {
download_item_->RemoveObserver(this);
auto iter = g_download_item_objects.find(download_item_->GetId());
if (iter != g_download_item_objects.end())
g_download_item_objects.erase(iter);
download_item_ = nullptr;
}
}
bool DownloadItem::IsDestroyed() const {
return download_item_ == nullptr;
}
void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) {
download_item_->IsDone() ? Emit("done", item->GetState()) : Emit("updated");
}
void DownloadItem::OnDownloadDestroyed(content::DownloadItem* download) {
Destroy();
}
int64 DownloadItem::GetReceivedBytes() {
return download_item_->GetReceivedBytes();
}
int64 DownloadItem::GetTotalBytes() {
return download_item_->GetTotalBytes();
}
const GURL& DownloadItem::GetUrl() {
return download_item_->GetURL();
}
std::string DownloadItem::GetMimeType() {
return download_item_->GetMimeType();
}
bool DownloadItem::HasUserGesture() {
return download_item_->HasUserGesture();
}
std::string DownloadItem::GetFilename() {
return base::UTF16ToUTF8(net::GenerateFileName(GetUrl(),
GetContentDisposition(),
std::string(),
download_item_->GetSuggestedFilename(),
GetMimeType(),
std::string()).LossyDisplayName());
}
std::string DownloadItem::GetContentDisposition() {
return download_item_->GetContentDisposition();
}
void DownloadItem::SetSavePath(const base::FilePath& path) {
download_item_->SetUserData(UserDataKey(), new SavePathData(path));
}
void DownloadItem::Pause() {
download_item_->Pause();
}
void DownloadItem::Resume() {
download_item_->Resume();
}
void DownloadItem::Cancel() {
download_item_->Cancel(true);
}
mate::ObjectTemplateBuilder DownloadItem::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("pause", &DownloadItem::Pause)
.SetMethod("resume", &DownloadItem::Resume)
.SetMethod("cancel", &DownloadItem::Cancel)
.SetMethod("getReceivedBytes", &DownloadItem::GetReceivedBytes)
.SetMethod("getTotalBytes", &DownloadItem::GetTotalBytes)
.SetMethod("getUrl", &DownloadItem::GetUrl)
.SetMethod("getMimeType", &DownloadItem::GetMimeType)
.SetMethod("hasUserGesture", &DownloadItem::HasUserGesture)
.SetMethod("getFilename", &DownloadItem::GetFilename)
.SetMethod("getContentDisposition", &DownloadItem::GetContentDisposition)
.SetMethod("setSavePath", &DownloadItem::SetSavePath);
}
// static
mate::Handle<DownloadItem> DownloadItem::Create(
v8::Isolate* isolate, content::DownloadItem* item) {
auto handle = mate::CreateHandle(isolate, new DownloadItem(item));
g_wrap_download_item.Run(handle.ToV8());
g_download_item_objects[item->GetId()] = make_linked_ptr(
new v8::Global<v8::Value>(isolate, handle.ToV8()));
return handle;
}
// static
void* DownloadItem::UserDataKey() {
return &kDownloadItemSavePathKey;
}
void ClearWrapDownloadItem() {
g_wrap_download_item.Reset();
}
void SetWrapDownloadItem(const WrapDownloadItemCallback& callback) {
g_wrap_download_item = callback;
// Cleanup the wrapper on exit.
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
base::Bind(ClearWrapDownloadItem));
}
} // namespace api
} // namespace atom
namespace {
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
v8::Isolate* isolate = context->GetIsolate();
mate::Dictionary dict(isolate, exports);
dict.SetMethod("_setWrapDownloadItem", &atom::api::SetWrapDownloadItem);
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_download_item, Initialize);

View File

@@ -0,0 +1,72 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_
#define ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_
#include <string>
#include "atom/browser/api/trackable_object.h"
#include "base/files/file_path.h"
#include "content/public/browser/download_item.h"
#include "native_mate/handle.h"
#include "url/gurl.h"
namespace atom {
namespace api {
class DownloadItem : public mate::EventEmitter,
public content::DownloadItem::Observer {
public:
class SavePathData : public base::SupportsUserData::Data {
public:
explicit SavePathData(const base::FilePath& path);
const base::FilePath& path();
private:
base::FilePath path_;
};
static mate::Handle<DownloadItem> Create(v8::Isolate* isolate,
content::DownloadItem* item);
static void* UserDataKey();
protected:
explicit DownloadItem(content::DownloadItem* download_item);
~DownloadItem();
// Override content::DownloadItem::Observer methods
void OnDownloadUpdated(content::DownloadItem* download) override;
void OnDownloadDestroyed(content::DownloadItem* download) override;
void Pause();
void Resume();
void Cancel();
int64 GetReceivedBytes();
int64 GetTotalBytes();
std::string GetMimeType();
bool HasUserGesture();
std::string GetFilename();
std::string GetContentDisposition();
const GURL& GetUrl();
void SetSavePath(const base::FilePath& path);
private:
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
void Destroy();
content::DownloadItem* download_item_;
DISALLOW_COPY_AND_ASSIGN(DownloadItem);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_

View File

@@ -0,0 +1,101 @@
// 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() {
}
void GlobalShortcut::Destroy() {
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,58 @@
// 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 "atom/browser/api/trackable_object.h"
#include "base/callback.h"
#include "chrome/browser/extensions/global_shortcut_listener.h"
#include "native_mate/handle.h"
#include "ui/base/accelerators/accelerator.h"
namespace atom {
namespace api {
class GlobalShortcut : public extensions::GlobalShortcutListener::Observer,
public mate::TrackableObject<GlobalShortcut> {
public:
static mate::Handle<GlobalShortcut> Create(v8::Isolate* isolate);
protected:
GlobalShortcut();
~GlobalShortcut() override;
// mate::TrackableObject:
void Destroy() override;
// 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,207 @@
// 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::Destroy() {
model_.reset();
}
bool Menu::IsDestroyed() const {
return !model_;
}
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::SetRole(int index, const base::string16& role) {
model_->SetRole(index, role);
}
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("setRole", &Menu::SetRole)
.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,129 @@
// 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/api/trackable_object.h"
#include "atom/browser/ui/atom_menu_model.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
namespace atom {
namespace api {
class Menu : public mate::TrackableObject<Menu>,
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();
~Menu() override;
// mate::TrackableObject:
void Destroy() override;
// mate::Wrappable:
bool IsDestroyed() const override;
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 SetRole(int index, const base::string16& role);
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,40 @@
// 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 Destroy() override;
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,101 @@
// 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::Destroy() {
menu_controller_.reset();
Menu::Destroy();
}
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,76 @@
// 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 "atom/common/node_includes.h"
#include "base/power_monitor/power_monitor.h"
#include "base/power_monitor/power_monitor_device_source.h"
#include "native_mate/dictionary.h"
namespace atom {
namespace api {
PowerMonitor::PowerMonitor() {
base::PowerMonitor::Get()->AddObserver(this);
}
PowerMonitor::~PowerMonitor() {
}
void PowerMonitor::Destroy() {
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()) {
isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
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,42 @@
// 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/trackable_object.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::TrackableObject<PowerMonitor>,
public base::PowerObserver {
public:
static v8::Local<v8::Value> Create(v8::Isolate* isolate);
protected:
PowerMonitor();
~PowerMonitor() override;
// mate::TrackableObject:
void Destroy() override;
// 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,133 @@
// 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 "atom/common/node_includes.h"
#include "content/public/browser/power_save_blocker.h"
#include "native_mate/dictionary.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::Destroy() {
power_save_blocker_types_.clear();
power_save_blocker_.reset();
}
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,61 @@
// 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 "atom/browser/api/trackable_object.h"
#include "base/memory/scoped_ptr.h"
#include "content/public/browser/power_save_blocker.h"
#include "native_mate/handle.h"
namespace mate {
class Dictionary;
}
namespace atom {
namespace api {
class PowerSaveBlocker : public mate::TrackableObject<PowerSaveBlocker> {
public:
static mate::Handle<PowerSaveBlocker> Create(v8::Isolate* isolate);
protected:
PowerSaveBlocker();
~PowerSaveBlocker() override;
// mate::TrackableObject:
void Destroy() override;
// 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,166 @@
// 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/net/url_request_async_asar_job.h"
#include "atom/browser/net/url_request_buffer_job.h"
#include "atom/browser/net/url_request_fetch_job.h"
#include "atom/browser/net/url_request_string_job.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/net_converter.h"
#include "atom/common/node_includes.h"
#include "native_mate/dictionary.h"
using content::BrowserThread;
namespace atom {
namespace api {
Protocol::Protocol(AtomBrowserContext* browser_context)
: request_context_getter_(browser_context->GetRequestContext()),
job_factory_(browser_context->job_factory()) {
CHECK(job_factory_);
}
mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("registerStandardSchemes", &Protocol::RegisterStandardSchemes)
.SetMethod("registerStringProtocol",
&Protocol::RegisterProtocol<URLRequestStringJob>)
.SetMethod("registerBufferProtocol",
&Protocol::RegisterProtocol<URLRequestBufferJob>)
.SetMethod("registerFileProtocol",
&Protocol::RegisterProtocol<UrlRequestAsyncAsarJob>)
.SetMethod("registerHttpProtocol",
&Protocol::RegisterProtocol<URLRequestFetchJob>)
.SetMethod("unregisterProtocol", &Protocol::UnregisterProtocol)
.SetMethod("isProtocolHandled", &Protocol::IsProtocolHandled)
.SetMethod("interceptStringProtocol",
&Protocol::InterceptProtocol<URLRequestStringJob>)
.SetMethod("interceptBufferProtocol",
&Protocol::InterceptProtocol<URLRequestBufferJob>)
.SetMethod("interceptFileProtocol",
&Protocol::InterceptProtocol<UrlRequestAsyncAsarJob>)
.SetMethod("interceptHttpProtocol",
&Protocol::InterceptProtocol<URLRequestFetchJob>)
.SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol);
}
void Protocol::RegisterStandardSchemes(
const std::vector<std::string>& schemes) {
atom::AtomBrowserClient::SetCustomSchemes(schemes);
}
void Protocol::UnregisterProtocol(
const std::string& scheme, mate::Arguments* args) {
CompletionCallback callback;
args->GetNext(&callback);
content::BrowserThread::PostTaskAndReplyWithResult(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&Protocol::UnregisterProtocolInIO,
base::Unretained(this), scheme),
base::Bind(&Protocol::OnIOCompleted,
base::Unretained(this), callback));
}
Protocol::ProtocolError Protocol::UnregisterProtocolInIO(
const std::string& scheme) {
if (!job_factory_->HasProtocolHandler(scheme))
return PROTOCOL_NOT_REGISTERED;
job_factory_->SetProtocolHandler(scheme, nullptr);
return PROTOCOL_OK;
}
void Protocol::IsProtocolHandled(const std::string& scheme,
const BooleanCallback& callback) {
content::BrowserThread::PostTaskAndReplyWithResult(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&Protocol::IsProtocolHandledInIO,
base::Unretained(this), scheme),
callback);
}
bool Protocol::IsProtocolHandledInIO(const std::string& scheme) {
return job_factory_->IsHandledProtocol(scheme);
}
void Protocol::UninterceptProtocol(
const std::string& scheme, mate::Arguments* args) {
CompletionCallback callback;
args->GetNext(&callback);
content::BrowserThread::PostTaskAndReplyWithResult(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&Protocol::UninterceptProtocolInIO,
base::Unretained(this), scheme),
base::Bind(&Protocol::OnIOCompleted,
base::Unretained(this), callback));
}
Protocol::ProtocolError Protocol::UninterceptProtocolInIO(
const std::string& scheme) {
if (!original_protocols_.contains(scheme))
return PROTOCOL_NOT_INTERCEPTED;
job_factory_->ReplaceProtocol(scheme,
original_protocols_.take_and_erase(scheme));
return PROTOCOL_OK;
}
void Protocol::OnIOCompleted(
const CompletionCallback& callback, ProtocolError error) {
// The completion callback is optional.
if (callback.is_null())
return;
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
if (error == PROTOCOL_OK) {
callback.Run(v8::Null(isolate()));
} else {
std::string str = ErrorCodeToString(error);
callback.Run(v8::Exception::Error(mate::StringToV8(isolate(), str)));
}
}
std::string Protocol::ErrorCodeToString(ProtocolError error) {
switch (error) {
case PROTOCOL_FAIL: return "Failed to manipulate protocol factory";
case PROTOCOL_REGISTERED: return "The scheme has been registred";
case PROTOCOL_NOT_REGISTERED: return "The scheme has not been registred";
case PROTOCOL_INTERCEPTED: return "The scheme has been intercepted";
case PROTOCOL_NOT_INTERCEPTED: return "The scheme has not been intercepted";
default: return "Unexpected error";
}
}
// 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,192 @@
// 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/net/atom_url_request_job_factory.h"
#include "base/callback.h"
#include "base/containers/scoped_ptr_hash_map.h"
#include "content/public/browser/browser_thread.h"
#include "native_mate/arguments.h"
#include "native_mate/dictionary.h"
#include "native_mate/handle.h"
#include "native_mate/wrappable.h"
namespace net {
class URLRequest;
class URLRequestContextGetter;
}
namespace atom {
class AtomBrowserContext;
class AtomURLRequestJobFactory;
namespace api {
class Protocol : public mate::Wrappable {
public:
using Handler =
base::Callback<void(const net::URLRequest*, v8::Local<v8::Value>)>;
using CompletionCallback = base::Callback<void(v8::Local<v8::Value>)>;
using BooleanCallback = base::Callback<void(bool)>;
static mate::Handle<Protocol> Create(
v8::Isolate* isolate, AtomBrowserContext* browser_context);
protected:
explicit Protocol(AtomBrowserContext* browser_context);
// mate::Wrappable implementations:
virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate);
private:
// Possible errors.
enum ProtocolError {
PROTOCOL_OK, // no error
PROTOCOL_FAIL, // operation failed, should never occur
PROTOCOL_REGISTERED,
PROTOCOL_NOT_REGISTERED,
PROTOCOL_INTERCEPTED,
PROTOCOL_NOT_INTERCEPTED,
};
// The protocol handler that will create a protocol handler for certain
// request job.
template<typename RequestJob>
class CustomProtocolHandler
: public net::URLRequestJobFactory::ProtocolHandler {
public:
CustomProtocolHandler(
v8::Isolate* isolate,
net::URLRequestContextGetter* request_context,
const Handler& handler)
: isolate_(isolate),
request_context_(request_context),
handler_(handler) {}
~CustomProtocolHandler() override {}
net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const override {
RequestJob* request_job = new RequestJob(request, network_delegate);
request_job->SetHandlerInfo(isolate_, request_context_, handler_);
return request_job;
}
private:
v8::Isolate* isolate_;
net::URLRequestContextGetter* request_context_;
Protocol::Handler handler_;
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
};
// Register schemes to standard scheme list.
void RegisterStandardSchemes(const std::vector<std::string>& schemes);
// Register the protocol with certain request job.
template<typename RequestJob>
void RegisterProtocol(const std::string& scheme,
const Handler& handler,
mate::Arguments* args) {
CompletionCallback callback;
args->GetNext(&callback);
content::BrowserThread::PostTaskAndReplyWithResult(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&Protocol::RegisterProtocolInIO<RequestJob>,
base::Unretained(this), scheme, handler),
base::Bind(&Protocol::OnIOCompleted,
base::Unretained(this), callback));
}
template<typename RequestJob>
ProtocolError RegisterProtocolInIO(const std::string& scheme,
const Handler& handler) {
if (job_factory_->IsHandledProtocol(scheme))
return PROTOCOL_REGISTERED;
scoped_ptr<CustomProtocolHandler<RequestJob>> protocol_handler(
new CustomProtocolHandler<RequestJob>(
isolate(), request_context_getter_, handler));
if (job_factory_->SetProtocolHandler(scheme, protocol_handler.Pass()))
return PROTOCOL_OK;
else
return PROTOCOL_FAIL;
}
// Unregister the protocol handler that handles |scheme|.
void UnregisterProtocol(const std::string& scheme, mate::Arguments* args);
ProtocolError UnregisterProtocolInIO(const std::string& scheme);
// Whether the protocol has handler registered.
void IsProtocolHandled(const std::string& scheme,
const BooleanCallback& callback);
bool IsProtocolHandledInIO(const std::string& scheme);
// Replace the protocol handler with a new one.
template<typename RequestJob>
void InterceptProtocol(const std::string& scheme,
const Handler& handler,
mate::Arguments* args) {
CompletionCallback callback;
args->GetNext(&callback);
content::BrowserThread::PostTaskAndReplyWithResult(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&Protocol::InterceptProtocolInIO<RequestJob>,
base::Unretained(this), scheme, handler),
base::Bind(&Protocol::OnIOCompleted,
base::Unretained(this), callback));
}
template<typename RequestJob>
ProtocolError InterceptProtocolInIO(const std::string& scheme,
const Handler& handler) {
if (!job_factory_->IsHandledProtocol(scheme))
return PROTOCOL_NOT_REGISTERED;
// It is possible a protocol is handled but can not be intercepted.
if (!job_factory_->HasProtocolHandler(scheme))
return PROTOCOL_FAIL;
if (ContainsKey(original_protocols_, scheme))
return PROTOCOL_INTERCEPTED;
scoped_ptr<CustomProtocolHandler<RequestJob>> protocol_handler(
new CustomProtocolHandler<RequestJob>(
isolate(), request_context_getter_, handler));
original_protocols_.set(
scheme,
job_factory_->ReplaceProtocol(scheme, protocol_handler.Pass()));
return PROTOCOL_OK;
}
// Restore the |scheme| to its original protocol handler.
void UninterceptProtocol(const std::string& scheme, mate::Arguments* args);
ProtocolError UninterceptProtocolInIO(const std::string& scheme);
// Convert error code to JS exception and call the callback.
void OnIOCompleted(const CompletionCallback& callback, ProtocolError error);
// Convert error code to string.
std::string ErrorCodeToString(ProtocolError error);
net::URLRequestContextGetter* request_context_getter_;
// Map that stores the original protocols of schemes.
using OriginalProtocolsMap = base::ScopedPtrHashMap<
std::string,
scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>>;
OriginalProtocolsMap original_protocols_;
AtomURLRequestJobFactory* job_factory_; // weak ref
DISALLOW_COPY_AND_ASSIGN(Protocol);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_

View File

@@ -0,0 +1,146 @@
// 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()) {
isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
isolate,
"Cannot initialize \"screen\" module before app is ready")));
return v8::Null(isolate);
}
gfx::Screen* screen = gfx::Screen::GetNativeScreen();
if (!screen) {
isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
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,427 @@
// 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/api/atom_api_download_item.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/api/save_page_handler.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/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 "atom/common/node_includes.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 "brightray/browser/net/devtools_network_conditions.h"
#include "brightray/browser/net/devtools_network_controller.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"
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;
}
};
template<>
struct Converter<net::ProxyConfig> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
net::ProxyConfig* out) {
std::string proxy;
if (!ConvertFromV8(isolate, val, &proxy))
return false;
auto pac_url = GURL(proxy);
if (pac_url.is_valid()) {
out->set_pac_url(pac_url);
} else {
out->proxy_rules().ParseFromString(proxy);
}
return true;
}
};
} // namespace mate
namespace atom {
namespace api {
namespace {
// The wrapSession funtion which is implemented in JavaScript
using WrapSessionCallback = base::Callback<void(v8::Local<v8::Value>)>;
WrapSessionCallback g_wrap_session;
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 net::ProxyConfig& config,
const base::Closure& callback) {
auto proxy_service = getter->GetURLRequestContext()->proxy_service();
proxy_service->ResetConfigService(new net::ProxyConfigServiceFixed(config));
// Refetches and applies the new pac script if provided.
proxy_service->ForceReloadProxyConfig();
RunCallbackInUI(callback);
}
} // namespace
Session::Session(AtomBrowserContext* browser_context)
: browser_context_(browser_context) {
AttachAsUserData(browser_context);
// Observe DownloadManger to get download notifications.
content::BrowserContext::GetDownloadManager(browser_context)->
AddObserver(this);
}
Session::~Session() {
content::BrowserContext::GetDownloadManager(browser_context())->
RemoveObserver(this);
Destroy();
}
void Session::OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) {
auto web_contents = item->GetWebContents();
if (SavePageHandler::IsSavePageTypes(item->GetMimeType()))
return;
bool prevent_default = Emit(
"will-download",
DownloadItem::Create(isolate(), item),
api::WebContents::CreateFrom(isolate(), web_contents));
if (prevent_default) {
item->Cancel(true);
item->Remove();
}
}
bool Session::IsDestroyed() const {
return !browser_context_;
}
void Session::Destroy() {
browser_context_ = nullptr;
}
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 net::ProxyConfig& config,
const base::Closure& callback) {
auto getter = browser_context_->GetRequestContext();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&SetProxyInIO, base::Unretained(getter), config, callback));
}
void Session::SetDownloadPath(const base::FilePath& path) {
browser_context_->prefs()->SetFilePath(
prefs::kDownloadDefaultDirectory, path);
}
void Session::EnableNetworkEmulation(const mate::Dictionary& options) {
scoped_ptr<brightray::DevToolsNetworkConditions> conditions;
bool offline = false;
double latency, download_throughput, upload_throughput;
if (options.Get("offline", &offline) && offline) {
conditions.reset(new brightray::DevToolsNetworkConditions(offline));
} else {
options.Get("latency", &latency);
options.Get("downloadThroughput", &download_throughput);
options.Get("uploadThroughput", &upload_throughput);
conditions.reset(
new brightray::DevToolsNetworkConditions(false,
latency,
download_throughput,
upload_throughput));
}
auto controller = browser_context_->GetDevToolsNetworkController();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&brightray::DevToolsNetworkController::SetNetworkState,
base::Unretained(controller),
std::string(),
base::Passed(&conditions)));
}
void Session::DisableNetworkEmulation() {
scoped_ptr<brightray::DevToolsNetworkConditions> conditions(
new brightray::DevToolsNetworkConditions(false));
auto controller = browser_context_->GetDevToolsNetworkController();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&brightray::DevToolsNetworkController::SetNetworkState,
base::Unretained(controller),
std::string(),
base::Passed(&conditions)));
}
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)
.SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
.SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
.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));
auto handle = mate::CreateHandle(isolate, new Session(browser_context));
g_wrap_session.Run(handle.ToV8());
return handle;
}
// static
mate::Handle<Session> Session::FromPartition(
v8::Isolate* isolate, const std::string& partition, bool in_memory) {
auto browser_context = brightray::BrowserContext::From(partition, in_memory);
return CreateFrom(isolate,
static_cast<AtomBrowserContext*>(browser_context.get()));
}
void ClearWrapSession() {
g_wrap_session.Reset();
}
void SetWrapSession(const WrapSessionCallback& callback) {
g_wrap_session = callback;
// Cleanup the wrapper on exit.
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
base::Bind(ClearWrapSession));
}
} // namespace api
} // namespace atom
namespace {
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
v8::Isolate* isolate = context->GetIsolate();
mate::Dictionary dict(isolate, exports);
dict.SetMethod("fromPartition", &atom::api::Session::FromPartition);
dict.SetMethod("_setWrapSession", &atom::api::SetWrapSession);
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_session, Initialize)

View File

@@ -0,0 +1,89 @@
// 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 "content/public/browser/download_manager.h"
#include "native_mate/handle.h"
#include "net/base/completion_callback.h"
class GURL;
namespace base {
class FilePath;
}
namespace mate {
class Arguments;
class Dictionary;
}
namespace net {
class ProxyConfig;
}
namespace atom {
class AtomBrowserContext;
namespace api {
class Session: public mate::TrackableObject<Session>,
public content::DownloadManager::Observer {
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);
// Gets the Session of |partition| and |in_memory|.
static mate::Handle<Session> FromPartition(
v8::Isolate* isolate, const std::string& partition, bool in_memory);
AtomBrowserContext* browser_context() const { return browser_context_.get(); }
protected:
explicit Session(AtomBrowserContext* browser_context);
~Session();
// content::DownloadManager::Observer:
void OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) override;
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
private:
// mate::TrackableObject:
void Destroy() override;
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
void ClearCache(const net::CompletionCallback& callback);
void ClearStorageData(mate::Arguments* args);
void SetProxy(const net::ProxyConfig& config, const base::Closure& callback);
void SetDownloadPath(const base::FilePath& path);
void EnableNetworkEmulation(const mate::Dictionary& options);
void DisableNetworkEmulation();
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
// Cached object for cookies API.
v8::Global<v8::Value> cookies_;
scoped_refptr<AtomBrowserContext> browser_context_;
DISALLOW_COPY_AND_ASSIGN(Session);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_SESSION_H_

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