Merge pull request #1 from atom/master

Merge with forked
This commit is contained in:
Max Graey 2015-04-21 04:39:54 +07:00
commit 916fa4b9a8
14 changed files with 88 additions and 307 deletions

View file

@ -1,5 +1,7 @@
# Electron [![Build Status](https://travis-ci.org/atom/electron.svg?branch=master)](https://travis-ci.org/atom/electron)
:zap: *formerly known as Atom Shell* :zap:
The Electron framework lets you write cross-platform desktop applications
using JavaScript, HTML and CSS. It is based on [io.js](http://iojs.org) and
[Chromium](http://www.chromium.org) and is used in the [Atom
@ -10,6 +12,17 @@ editor](https://github.com/atom/atom).
Prebuilt binaries and debug symbols of Electron for Linux, Windows and Mac can
be found on the [releases](https://github.com/atom/electron/releases) page.
You can also use [`npm`](https://docs.npmjs.com/) to install prebuilt electron
binaries:
```
# Install the `electron` command globally in your $PATH
npm install electron-prebuilt -g
# Install as a development dependency
npm install electron-prebuilt --save-dev
```
### Mirrors
- [China](https://npm.taobao.org/mirrors/atom-shell)
@ -22,5 +35,5 @@ contains documents describing how to build and contribute to Electron.
## Community
There is an [`atom-shell` category on the Atom forums](http://discuss.atom.io/category/atom-shell)
There is an [`electron` category on the Atom forums](http://discuss.atom.io/category/electron)
as well as an `#atom-shell` channel on Freenode.

View file

@ -26,7 +26,19 @@ int NodeMain(int argc, char *argv[]) {
JavascriptEnvironment gin_env;
node::Environment* env = node::CreateEnvironment(
gin_env.isolate(), gin_env.context(), argc, argv, exec_argc, exec_argv);
gin_env.isolate(), uv_default_loop(), gin_env.context(), argc, argv,
exec_argc, exec_argv);
// Start debugger.
node::node_isolate = gin_env.isolate();
if (node::use_debug_agent)
node::StartDebug(env, node::debug_wait_connect);
node::LoadEnvironment(env);
// Enable debugger.
if (node::use_debug_agent)
node::EnableDebug(env);
bool more;
do {

View file

@ -4,6 +4,7 @@
#include "atom/browser/api/atom_api_power_monitor.h"
#include "atom/browser/browser.h"
#include "base/power_monitor/power_monitor.h"
#include "base/power_monitor/power_monitor_device_source.h"
#include "native_mate/dictionary.h"
@ -38,8 +39,14 @@ void PowerMonitor::OnResume() {
}
// static
mate::Handle<PowerMonitor> PowerMonitor::Create(v8::Isolate* isolate) {
return CreateHandle(isolate, new PowerMonitor);
v8::Handle<v8::Value> PowerMonitor::Create(v8::Isolate* isolate) {
if (!Browser::Get()->is_ready()) {
node::ThrowError("Cannot initialize \"power-monitor\" module"
"before app is ready");
return v8::Null(isolate);
}
return CreateHandle(isolate, new PowerMonitor).ToV8();
}
} // namespace api
@ -57,9 +64,8 @@ void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
using atom::api::PowerMonitor;
v8::Isolate* isolate = context->GetIsolate();
mate::Handle<PowerMonitor> power_monitor = PowerMonitor::Create(isolate);
mate::Dictionary dict(isolate, exports);
dict.Set("powerMonitor", power_monitor);
dict.Set("powerMonitor", PowerMonitor::Create(isolate));
}
} // namespace

View file

@ -17,7 +17,7 @@ namespace api {
class PowerMonitor : public mate::EventEmitter,
public base::PowerObserver {
public:
static mate::Handle<PowerMonitor> Create(v8::Isolate* isolate);
static v8::Handle<v8::Value> Create(v8::Isolate* isolate);
protected:
PowerMonitor();

View file

@ -8,7 +8,6 @@
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/browser.h"
#include "atom/browser/javascript_environment.h"
#include "atom/browser/node_debugger.h"
#include "atom/common/api/atom_bindings.h"
#include "atom/common/node_bindings.h"
#include "base/command_line.h"
@ -60,16 +59,9 @@ void AtomBrowserMainParts::PostEarlyInitialization() {
node_bindings_->Initialize();
// Support the "--debug" switch.
node_debugger_.reset(new NodeDebugger(js_env_->isolate()));
// Create the global environment.
global_env = node_bindings_->CreateEnvironment(js_env_->context());
// Make sure node can get correct environment when debugging.
if (node_debugger_->IsRunning())
global_env->AssignToContext(v8::Debug::GetDebugContext());
// Add atom-shell extended APIs.
atom_bindings_->BindTo(js_env_->isolate(), global_env->process_object());

View file

@ -14,7 +14,6 @@ class AtomBindings;
class Browser;
class JavascriptEnvironment;
class NodeBindings;
class NodeDebugger;
class AtomBrowserMainParts : public brightray::BrowserMainParts {
public:
@ -46,7 +45,6 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
scoped_ptr<JavascriptEnvironment> js_env_;
scoped_ptr<NodeBindings> node_bindings_;
scoped_ptr<AtomBindings> atom_bindings_;
scoped_ptr<NodeDebugger> node_debugger_;
base::Timer gc_timer_;

View file

@ -1,202 +0,0 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/node_debugger.h"
#include <string>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "net/socket/tcp_listen_socket.h"
#include "atom/common/node_includes.h"
namespace atom {
namespace {
// NodeDebugger is stored in Isolate's data, slots 0, 1, 3 have already been
// taken by gin, blink and node, using 2 is a safe option for now.
const int kIsolateSlot = 2;
const char* kContentLength = "Content-Length";
} // namespace
NodeDebugger::NodeDebugger(v8::Isolate* isolate)
: isolate_(isolate),
thread_("NodeDebugger"),
content_length_(-1),
weak_factory_(this) {
bool use_debug_agent = false;
int port = 5858;
bool wait_for_connection = false;
std::string port_str;
base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
if (cmd->HasSwitch("debug")) {
use_debug_agent = true;
port_str = cmd->GetSwitchValueASCII("debug");
}
if (cmd->HasSwitch("debug-brk")) {
use_debug_agent = true;
wait_for_connection = true;
port_str = cmd->GetSwitchValueASCII("debug-brk");
}
if (use_debug_agent) {
if (!port_str.empty())
base::StringToInt(port_str, &port);
isolate_->SetData(kIsolateSlot, this);
v8::Debug::SetMessageHandler(DebugMessageHandler);
if (wait_for_connection)
v8::Debug::DebugBreak(isolate_);
// Start a new IO thread.
base::Thread::Options options;
options.message_loop_type = base::MessageLoop::TYPE_IO;
if (!thread_.StartWithOptions(options)) {
LOG(ERROR) << "Unable to start debugger thread";
return;
}
// Start the server in new IO thread.
thread_.message_loop()->PostTask(
FROM_HERE,
base::Bind(&NodeDebugger::StartServer, weak_factory_.GetWeakPtr(),
port));
}
}
NodeDebugger::~NodeDebugger() {
thread_.Stop();
}
bool NodeDebugger::IsRunning() const {
return thread_.IsRunning();
}
void NodeDebugger::StartServer(int port) {
server_ = net::TCPListenSocket::CreateAndListen("127.0.0.1", port, this);
if (!server_) {
LOG(ERROR) << "Cannot start debugger server";
return;
}
}
void NodeDebugger::CloseSession() {
accepted_socket_.reset();
}
void NodeDebugger::OnMessage(const std::string& message) {
if (message.find("\"type\":\"request\",\"command\":\"disconnect\"}") !=
std::string::npos)
CloseSession();
base::string16 message16 = base::UTF8ToUTF16(message);
v8::Debug::SendCommand(
isolate_,
reinterpret_cast<const uint16_t*>(message16.data()), message16.size());
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(&v8::Debug::ProcessDebugMessages));
}
void NodeDebugger::SendMessage(const std::string& message) {
if (accepted_socket_) {
std::string header = base::StringPrintf(
"%s: %d\r\n\r\n", kContentLength, static_cast<int>(message.size()));
accepted_socket_->Send(header);
accepted_socket_->Send(message);
}
}
void NodeDebugger::SendConnectMessage() {
accepted_socket_->Send(base::StringPrintf(
"Type: connect\r\n"
"V8-Version: %s\r\n"
"Protocol-Version: 1\r\n"
"Embedding-Host: %s\r\n"
"%s: 0\r\n",
v8::V8::GetVersion(), ATOM_PRODUCT_NAME, kContentLength), true);
}
// static
void NodeDebugger::DebugMessageHandler(const v8::Debug::Message& message) {
NodeDebugger* self = static_cast<NodeDebugger*>(
message.GetIsolate()->GetData(kIsolateSlot));
if (self) {
std::string message8(*v8::String::Utf8Value(message.GetJSON()));
self->thread_.message_loop()->PostTask(
FROM_HERE,
base::Bind(&NodeDebugger::SendMessage, self->weak_factory_.GetWeakPtr(),
message8));
}
}
void NodeDebugger::DidAccept(net::StreamListenSocket* server,
scoped_ptr<net::StreamListenSocket> socket) {
// Only accept one session.
if (accepted_socket_) {
socket->Send(std::string("Remote debugging session already active"), true);
return;
}
accepted_socket_ = socket.Pass();
SendConnectMessage();
}
void NodeDebugger::DidRead(net::StreamListenSocket* socket,
const char* data,
int len) {
buffer_.append(data, len);
do {
if (buffer_.size() == 0)
return;
// Read the "Content-Length" header.
if (content_length_ < 0) {
size_t pos = buffer_.find("\r\n\r\n");
if (pos == std::string::npos)
return;
// We can be sure that the header is "Content-Length: xxx\r\n".
std::string content_length = buffer_.substr(16, pos - 16);
if (!base::StringToInt(content_length, &content_length_)) {
DidClose(accepted_socket_.get());
return;
}
// Strip header from buffer.
buffer_ = buffer_.substr(pos + 4);
}
// Read the message.
if (buffer_.size() >= static_cast<size_t>(content_length_)) {
std::string message = buffer_.substr(0, content_length_);
buffer_ = buffer_.substr(content_length_);
OnMessage(message);
// Get ready for next message.
content_length_ = -1;
}
} while (true);
}
void NodeDebugger::DidClose(net::StreamListenSocket* socket) {
// If we lost the connection, then simulate a disconnect msg:
OnMessage("{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}");
}
} // namespace atom

View file

@ -1,59 +0,0 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_NODE_DEBUGGER_H_
#define ATOM_BROWSER_NODE_DEBUGGER_H_
#include <string>
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "net/socket/stream_listen_socket.h"
#include "v8/include/v8-debug.h"
namespace atom {
// Add support for node's "--debug" switch.
class NodeDebugger : public net::StreamListenSocket::Delegate {
public:
explicit NodeDebugger(v8::Isolate* isolate);
virtual ~NodeDebugger();
bool IsRunning() const;
private:
void StartServer(int port);
void CloseSession();
void OnMessage(const std::string& message);
void SendMessage(const std::string& message);
void SendConnectMessage();
static void DebugMessageHandler(const v8::Debug::Message& message);
// net::StreamListenSocket::Delegate:
void DidAccept(net::StreamListenSocket* server,
scoped_ptr<net::StreamListenSocket> socket) override;
void DidRead(net::StreamListenSocket* socket,
const char* data,
int len) override;
void DidClose(net::StreamListenSocket* socket) override;
v8::Isolate* isolate_;
base::Thread thread_;
scoped_ptr<net::StreamListenSocket> server_;
scoped_ptr<net::StreamListenSocket> accepted_socket_;
std::string buffer_;
int content_length_;
base::WeakPtrFactory<NodeDebugger> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(NodeDebugger);
};
} // namespace atom
#endif // ATOM_BROWSER_NODE_DEBUGGER_H_

View file

@ -128,9 +128,13 @@ void NodeBindings::Initialize() {
node::g_standalone_mode = is_browser_;
node::g_upstream_node_mode = false;
// Parse the debug args.
auto args = AtomCommandLine::argv();
for (const std::string& arg : args)
node::ParseDebugOpt(arg.c_str());
// Init node.
// (we assume it would not node::Init would not modify the parameters under
// embedded mode).
// (we assume node::Init would not modify the parameters under embedded mode).
node::Init(nullptr, nullptr, nullptr, nullptr);
}
@ -166,7 +170,14 @@ node::Environment* NodeBindings::CreateEnvironment(
}
void NodeBindings::LoadEnvironment(node::Environment* env) {
node::node_isolate = env->isolate();
if (node::use_debug_agent)
node::StartDebug(env, node::debug_wait_connect);
node::LoadEnvironment(env);
if (node::use_debug_agent)
node::EnableDebug(env);
}
void NodeBindings::PrepareMessageLoop() {

View file

@ -1,13 +1,18 @@
# power-monitor
The `power-monitor` module is used to monitor the power state change. You can
only use it on the main process.
only use it on the main process. You should not use this module until the `ready`
event of `app` module gets emitted.
An example is:
```javascript
require('power-monitor').on('suspend', function() {
console.log('The system is going to sleep');
var app = require('app');
app.on('ready', function() {
require('power-monitor').on('suspend', function() {
console.log('The system is going to sleep');
});
});
```
@ -18,3 +23,11 @@ Emitted when the system is suspending.
## Event: resume
Emitted when system is resuming.
## Event: on-ac
Emitted when the system changes to AC power.
## Event: on-battery
Emitted when system changes to battery power.

View file

@ -2,31 +2,31 @@
## Introduction
Generally, atom-shell enables you to create desktop applications with pure
Generally, Electron enables you to create desktop applications with pure
JavaScript by providing a runtime with rich native APIs. You could see it as
a variant of the io.js runtime which is focused on desktop applications
instead of web servers.
It doesn't mean atom-shell is a JavaScript binding to GUI libraries. Instead,
atom-shell uses web pages as its GUI, so you could also see it as a minimal
It doesn't mean Electron is a JavaScript binding to GUI libraries. Instead,
Electron uses web pages as its GUI, so you could also see it as a minimal
Chromium browser, controlled by JavaScript.
### The main process
In atom-shell the process that runs `package.json`'s `main` script is called
In Electron the process that runs `package.json`'s `main` script is called
__the main process__. The script runs in the main process can display GUI by
creating web pages.
### The renderer process
Since atom-shell uses Chromium for displaying web pages, Chromium's
multi-processes architecture is also used. Each web page in atom-shell runs in
Since Electron uses Chromium for displaying web pages, Chromium's
multi-processes architecture is also used. Each web page in Electron runs in
its own process, which is called __the renderer process__.
In normal browsers web pages are usually running in sandboxed environment and
not allowed to access native resources. In atom-shell users are given the power
to use io.js APIs in web pages, so it would be possible to interactive with
low level operating system in web pages with JavaScript.
In normal browsers web pages usually run in a sandboxed environment and are not
allowed access to native resources. In Electron users have the power to use
io.js APIs in web pages and it is therefore possible to interact with low level
operating system features.
### Differences between main process and renderer process
@ -44,14 +44,13 @@ native GUI resources in web pages is very dangerous and easy to leak resources.
If you want to do GUI operations in web pages, you have to communicate with
the main process to do it there.
In atom-shell, we have provided the [ipc](../api/ipc-renderer.md) module for
In Electron, we have provided the [ipc](../api/ipc-renderer.md) module for
communication between main process and renderer process. And there is also a
[remote](../api/remote.md) module for RPC style communication.
## Write your first atom-shell app
## Write your first Electron app
Generally, an atom-shell app would be structured like this (see the
[hello-atom](https://github.com/dougnukem/hello-atom) repo for reference):
Generally, an Electron app would be structured like this:
```text
your-app/
@ -93,7 +92,7 @@ app.on('window-all-closed', function() {
app.quit();
});
// This method will be called when atom-shell has done everything
// This method will be called when Electron has done everything
// initialization and ready for creating browser windows.
app.on('ready', function() {
// Create the browser window.
@ -123,7 +122,7 @@ Finally the `index.html` is the web page you want to show:
<body>
<h1>Hello World!</h1>
We are using node.js <script>document.write(process.version)</script>
and atom-shell <script>document.write(process.versions['electron'])</script>.
and Electron <script>document.write(process.versions['electron'])</script>.
</body>
</html>
```
@ -133,18 +132,18 @@ Finally the `index.html` is the web page you want to show:
After you're done writing your app, you can create a distribution by
following the [Application distribution](./application-distribution.md) guide
and then execute the packaged app. You can also just use the downloaded
atom-shell binary to execute your app directly.
Electron binary to execute your app directly.
On Windows:
```cmd
$ .\atom-shell\atom.exe your-app\
$ .\electron\electron.exe your-app\
```
On Linux:
```bash
$ ./atom-shell/atom your-app/
$ ./electron/electron your-app/
```
On OS X:
@ -153,5 +152,5 @@ On OS X:
$ ./Electron.app/Contents/MacOS/Atom your-app/
```
`Electron.app` here is part of the atom-shell's release package, you can download
`Electron.app` here is part of the Electron's release package, you can download
it from [here](https://github.com/atom/electron/releases).

View file

@ -148,8 +148,6 @@
'atom/browser/net/url_request_string_job.h',
'atom/browser/net/url_request_buffer_job.cc',
'atom/browser/net/url_request_buffer_job.h',
'atom/browser/node_debugger.cc',
'atom/browser/node_debugger.h',
'atom/browser/ui/accelerator_util.cc',
'atom/browser/ui/accelerator_util.h',
'atom/browser/ui/accelerator_util_mac.mm',

2
vendor/brightray vendored

@ -1 +1 @@
Subproject commit ec0a660b0b70e6ea5a4ee760a753b8fac31a5de2
Subproject commit e2539f3550ddc58f1f4e826b5ff9691485003d39

2
vendor/node vendored

@ -1 +1 @@
Subproject commit 9f7ab575d78fa4c50cc5529f15646c8a37eb3258
Subproject commit a7e75da3cae48cf6e55fa7c9f13d689f11021795