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) # 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 The Electron framework lets you write cross-platform desktop applications
using JavaScript, HTML and CSS. It is based on [io.js](http://iojs.org) and using JavaScript, HTML and CSS. It is based on [io.js](http://iojs.org) and
[Chromium](http://www.chromium.org) and is used in the [Atom [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 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. 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 ### Mirrors
- [China](https://npm.taobao.org/mirrors/atom-shell) - [China](https://npm.taobao.org/mirrors/atom-shell)
@ -22,5 +35,5 @@ contains documents describing how to build and contribute to Electron.
## Community ## 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. as well as an `#atom-shell` channel on Freenode.

View file

@ -26,7 +26,19 @@ int NodeMain(int argc, char *argv[]) {
JavascriptEnvironment gin_env; JavascriptEnvironment gin_env;
node::Environment* env = node::CreateEnvironment( 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; bool more;
do { do {

View file

@ -4,6 +4,7 @@
#include "atom/browser/api/atom_api_power_monitor.h" #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.h"
#include "base/power_monitor/power_monitor_device_source.h" #include "base/power_monitor/power_monitor_device_source.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
@ -38,8 +39,14 @@ void PowerMonitor::OnResume() {
} }
// static // static
mate::Handle<PowerMonitor> PowerMonitor::Create(v8::Isolate* isolate) { v8::Handle<v8::Value> PowerMonitor::Create(v8::Isolate* isolate) {
return CreateHandle(isolate, new PowerMonitor); 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 } // namespace api
@ -57,9 +64,8 @@ void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
using atom::api::PowerMonitor; using atom::api::PowerMonitor;
v8::Isolate* isolate = context->GetIsolate(); v8::Isolate* isolate = context->GetIsolate();
mate::Handle<PowerMonitor> power_monitor = PowerMonitor::Create(isolate);
mate::Dictionary dict(isolate, exports); mate::Dictionary dict(isolate, exports);
dict.Set("powerMonitor", power_monitor); dict.Set("powerMonitor", PowerMonitor::Create(isolate));
} }
} // namespace } // namespace

View file

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

View file

@ -8,7 +8,6 @@
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/javascript_environment.h" #include "atom/browser/javascript_environment.h"
#include "atom/browser/node_debugger.h"
#include "atom/common/api/atom_bindings.h" #include "atom/common/api/atom_bindings.h"
#include "atom/common/node_bindings.h" #include "atom/common/node_bindings.h"
#include "base/command_line.h" #include "base/command_line.h"
@ -60,16 +59,9 @@ void AtomBrowserMainParts::PostEarlyInitialization() {
node_bindings_->Initialize(); node_bindings_->Initialize();
// Support the "--debug" switch.
node_debugger_.reset(new NodeDebugger(js_env_->isolate()));
// Create the global environment. // Create the global environment.
global_env = node_bindings_->CreateEnvironment(js_env_->context()); 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. // Add atom-shell extended APIs.
atom_bindings_->BindTo(js_env_->isolate(), global_env->process_object()); atom_bindings_->BindTo(js_env_->isolate(), global_env->process_object());

View file

@ -14,7 +14,6 @@ class AtomBindings;
class Browser; class Browser;
class JavascriptEnvironment; class JavascriptEnvironment;
class NodeBindings; class NodeBindings;
class NodeDebugger;
class AtomBrowserMainParts : public brightray::BrowserMainParts { class AtomBrowserMainParts : public brightray::BrowserMainParts {
public: public:
@ -46,7 +45,6 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
scoped_ptr<JavascriptEnvironment> js_env_; scoped_ptr<JavascriptEnvironment> js_env_;
scoped_ptr<NodeBindings> node_bindings_; scoped_ptr<NodeBindings> node_bindings_;
scoped_ptr<AtomBindings> atom_bindings_; scoped_ptr<AtomBindings> atom_bindings_;
scoped_ptr<NodeDebugger> node_debugger_;
base::Timer gc_timer_; 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_standalone_mode = is_browser_;
node::g_upstream_node_mode = false; 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. // Init node.
// (we assume it would not node::Init would not modify the parameters under // (we assume node::Init would not modify the parameters under embedded mode).
// embedded mode).
node::Init(nullptr, nullptr, nullptr, nullptr); node::Init(nullptr, nullptr, nullptr, nullptr);
} }
@ -166,7 +170,14 @@ node::Environment* NodeBindings::CreateEnvironment(
} }
void NodeBindings::LoadEnvironment(node::Environment* env) { 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); node::LoadEnvironment(env);
if (node::use_debug_agent)
node::EnableDebug(env);
} }
void NodeBindings::PrepareMessageLoop() { void NodeBindings::PrepareMessageLoop() {

View file

@ -1,14 +1,19 @@
# power-monitor # power-monitor
The `power-monitor` module is used to monitor the power state change. You can 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: An example is:
```javascript ```javascript
var app = require('app');
app.on('ready', function() {
require('power-monitor').on('suspend', function() { require('power-monitor').on('suspend', function() {
console.log('The system is going to sleep'); console.log('The system is going to sleep');
}); });
});
``` ```
## Event: suspend ## Event: suspend
@ -18,3 +23,11 @@ Emitted when the system is suspending.
## Event: resume ## Event: resume
Emitted when system is resuming. 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 ## 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 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 a variant of the io.js runtime which is focused on desktop applications
instead of web servers. instead of web servers.
It doesn't mean atom-shell is a JavaScript binding to GUI libraries. Instead, It doesn't mean Electron 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 Electron uses web pages as its GUI, so you could also see it as a minimal
Chromium browser, controlled by JavaScript. Chromium browser, controlled by JavaScript.
### The main process ### 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 __the main process__. The script runs in the main process can display GUI by
creating web pages. creating web pages.
### The renderer process ### The renderer process
Since atom-shell uses Chromium for displaying web pages, Chromium's Since Electron uses Chromium for displaying web pages, Chromium's
multi-processes architecture is also used. Each web page in atom-shell runs in multi-processes architecture is also used. Each web page in Electron runs in
its own process, which is called __the renderer process__. its own process, which is called __the renderer process__.
In normal browsers web pages are usually running in sandboxed environment and In normal browsers web pages usually run in a sandboxed environment and are not
not allowed to access native resources. In atom-shell users are given the power allowed access to native resources. In Electron users have the power to use
to use io.js APIs in web pages, so it would be possible to interactive with io.js APIs in web pages and it is therefore possible to interact with low level
low level operating system in web pages with JavaScript. operating system features.
### Differences between main process and renderer process ### 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 If you want to do GUI operations in web pages, you have to communicate with
the main process to do it there. 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 communication between main process and renderer process. And there is also a
[remote](../api/remote.md) module for RPC style communication. [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 Generally, an Electron app would be structured like this:
[hello-atom](https://github.com/dougnukem/hello-atom) repo for reference):
```text ```text
your-app/ your-app/
@ -93,7 +92,7 @@ app.on('window-all-closed', function() {
app.quit(); 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. // initialization and ready for creating browser windows.
app.on('ready', function() { app.on('ready', function() {
// Create the browser window. // Create the browser window.
@ -123,7 +122,7 @@ Finally the `index.html` is the web page you want to show:
<body> <body>
<h1>Hello World!</h1> <h1>Hello World!</h1>
We are using node.js <script>document.write(process.version)</script> 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> </body>
</html> </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 After you're done writing your app, you can create a distribution by
following the [Application distribution](./application-distribution.md) guide following the [Application distribution](./application-distribution.md) guide
and then execute the packaged app. You can also just use the downloaded 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: On Windows:
```cmd ```cmd
$ .\atom-shell\atom.exe your-app\ $ .\electron\electron.exe your-app\
``` ```
On Linux: On Linux:
```bash ```bash
$ ./atom-shell/atom your-app/ $ ./electron/electron your-app/
``` ```
On OS X: On OS X:
@ -153,5 +152,5 @@ On OS X:
$ ./Electron.app/Contents/MacOS/Atom your-app/ $ ./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). 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_string_job.h',
'atom/browser/net/url_request_buffer_job.cc', 'atom/browser/net/url_request_buffer_job.cc',
'atom/browser/net/url_request_buffer_job.h', '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.cc',
'atom/browser/ui/accelerator_util.h', 'atom/browser/ui/accelerator_util.h',
'atom/browser/ui/accelerator_util_mac.mm', '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