diff --git a/README.md b/README.md index 7b582e6201c..643de8cb050 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/atom/app/node_main.cc b/atom/app/node_main.cc index 66cf9dcf12e..7446a0a7110 100644 --- a/atom/app/node_main.cc +++ b/atom/app/node_main.cc @@ -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 { diff --git a/atom/browser/api/atom_api_power_monitor.cc b/atom/browser/api/atom_api_power_monitor.cc index 905f61f590e..8f87eec0728 100644 --- a/atom/browser/api/atom_api_power_monitor.cc +++ b/atom/browser/api/atom_api_power_monitor.cc @@ -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::Create(v8::Isolate* isolate) { - return CreateHandle(isolate, new PowerMonitor); +v8::Handle 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 exports, v8::Handle unused, using atom::api::PowerMonitor; v8::Isolate* isolate = context->GetIsolate(); - mate::Handle power_monitor = PowerMonitor::Create(isolate); mate::Dictionary dict(isolate, exports); - dict.Set("powerMonitor", power_monitor); + dict.Set("powerMonitor", PowerMonitor::Create(isolate)); } } // namespace diff --git a/atom/browser/api/atom_api_power_monitor.h b/atom/browser/api/atom_api_power_monitor.h index 2fccc7fd311..cdd14ff6e85 100644 --- a/atom/browser/api/atom_api_power_monitor.h +++ b/atom/browser/api/atom_api_power_monitor.h @@ -17,7 +17,7 @@ namespace api { class PowerMonitor : public mate::EventEmitter, public base::PowerObserver { public: - static mate::Handle Create(v8::Isolate* isolate); + static v8::Handle Create(v8::Isolate* isolate); protected: PowerMonitor(); diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index bcf685e6e3a..aaf68836d0c 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -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()); diff --git a/atom/browser/atom_browser_main_parts.h b/atom/browser/atom_browser_main_parts.h index a825862ff9b..6ca0686655b 100644 --- a/atom/browser/atom_browser_main_parts.h +++ b/atom/browser/atom_browser_main_parts.h @@ -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 js_env_; scoped_ptr node_bindings_; scoped_ptr atom_bindings_; - scoped_ptr node_debugger_; base::Timer gc_timer_; diff --git a/atom/browser/node_debugger.cc b/atom/browser/node_debugger.cc deleted file mode 100644 index 4e2302763c7..00000000000 --- a/atom/browser/node_debugger.cc +++ /dev/null @@ -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 - -#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(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(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( - 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 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(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 diff --git a/atom/browser/node_debugger.h b/atom/browser/node_debugger.h deleted file mode 100644 index 6ee5b1e2068..00000000000 --- a/atom/browser/node_debugger.h +++ /dev/null @@ -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 - -#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 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 server_; - scoped_ptr accepted_socket_; - - std::string buffer_; - int content_length_; - - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(NodeDebugger); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NODE_DEBUGGER_H_ diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index 01df48fdc66..10ab8f4929a 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -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() { diff --git a/docs/api/power-monitor.md b/docs/api/power-monitor.md index 5ead769aa34..4643110f35b 100644 --- a/docs/api/power-monitor.md +++ b/docs/api/power-monitor.md @@ -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. diff --git a/docs/tutorial/quick-start.md b/docs/tutorial/quick-start.md index 0e643d9422a..adbe0a912a3 100644 --- a/docs/tutorial/quick-start.md +++ b/docs/tutorial/quick-start.md @@ -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:

Hello World!

We are using node.js - and atom-shell . + and Electron . ``` @@ -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). diff --git a/filenames.gypi b/filenames.gypi index d14c935ab72..586d67c1772 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -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', diff --git a/vendor/brightray b/vendor/brightray index ec0a660b0b7..e2539f3550d 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit ec0a660b0b70e6ea5a4ee760a753b8fac31a5de2 +Subproject commit e2539f3550ddc58f1f4e826b5ff9691485003d39 diff --git a/vendor/node b/vendor/node index 9f7ab575d78..a7e75da3cae 160000 --- a/vendor/node +++ b/vendor/node @@ -1 +1 @@ -Subproject commit 9f7ab575d78fa4c50cc5529f15646c8a37eb3258 +Subproject commit a7e75da3cae48cf6e55fa7c9f13d689f11021795