Merge remote-tracking branch 'refs/remotes/atom/master'

This commit is contained in:
Plusb Preco 2015-10-16 22:36:01 +09:00
commit c0ee8f4e60
36 changed files with 728 additions and 45 deletions

View file

@ -4,7 +4,7 @@
'product_name%': 'Electron',
'company_name%': 'GitHub, Inc',
'company_abbr%': 'github',
'version%': '0.33.8',
'version%': '0.34.0',
},
'includes': [
'filenames.gypi',

View file

@ -21,6 +21,15 @@
namespace atom {
namespace {
bool IsBrowserProcess(base::CommandLine* cmd) {
std::string process_type = cmd->GetSwitchValueASCII(switches::kProcessType);
return process_type.empty();
}
} // namespace
AtomMainDelegate::AtomMainDelegate() {
}
@ -28,11 +37,14 @@ 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.
std::wcout << std::endl;
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;
@ -47,7 +59,6 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
#endif // !defined(OS_WIN)
// Only enable logging when --enable-logging is specified.
auto command_line = base::CommandLine::ForCurrentProcess();
if (!command_line->HasSwitch(switches::kEnableLogging)) {
settings.logging_dest = logging::LOG_NONE;
logging::SetMinLogLevel(logging::LOG_NUM_SEVERITIES);
@ -83,7 +94,7 @@ void AtomMainDelegate::PreSandboxStartup() {
}
// Only append arguments for browser process.
if (!process_type.empty())
if (!IsBrowserProcess(command_line))
return;
#if defined(OS_WIN)

View file

@ -11,6 +11,7 @@
#include "atom/browser/api/atom_api_download_item.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/api/save_page_handler.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"
@ -237,6 +238,8 @@ Session::~Session() {
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),

View file

@ -162,6 +162,26 @@ struct Converter<net::HttpResponseHeaders*> {
}
};
template<>
struct Converter<content::SavePageType> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
content::SavePageType* out) {
std::string save_type;
if (!ConvertFromV8(isolate, val, &save_type))
return false;
if (save_type == "HTMLOnly") {
*out = content::SAVE_PAGE_TYPE_AS_ONLY_HTML;
} else if (save_type == "HTMLComplete") {
*out = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML;
} else if (save_type == "MHTML") {
*out = content::SAVE_PAGE_TYPE_AS_MHTML;
} else {
return false;
}
return true;
}
};
} // namespace mate
@ -665,6 +685,13 @@ void WebContents::InsertCSS(const std::string& css) {
web_contents()->InsertCSS(css);
}
bool WebContents::SavePage(const base::FilePath& full_file_path,
const content::SavePageType& save_type,
const SavePageHandler::SavePageCallback& callback) {
auto handler = new SavePageHandler(web_contents(), callback);
return handler->Handle(full_file_path, save_type);
}
void WebContents::ExecuteJavaScript(const base::string16& code,
bool has_user_gesture) {
Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture));
@ -976,6 +1003,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
.SetMethod("setUserAgent", &WebContents::SetUserAgent)
.SetMethod("getUserAgent", &WebContents::GetUserAgent)
.SetMethod("insertCSS", &WebContents::InsertCSS)
.SetMethod("savePage", &WebContents::SavePage)
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
.SetMethod("openDevTools", &WebContents::OpenDevTools)
.SetMethod("closeDevTools", &WebContents::CloseDevTools)

View file

@ -9,6 +9,7 @@
#include <vector>
#include "atom/browser/api/frame_subscriber.h"
#include "atom/browser/api/save_page_handler.h"
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/common_web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
@ -73,6 +74,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
void SetUserAgent(const std::string& user_agent);
std::string GetUserAgent();
void InsertCSS(const std::string& css);
bool SavePage(const base::FilePath& full_file_path,
const content::SavePageType& save_type,
const SavePageHandler::SavePageCallback& callback);
void ExecuteJavaScript(const base::string16& code,
bool has_user_gesture);
void OpenDevTools(mate::Arguments* args);

View file

@ -0,0 +1,78 @@
// 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/save_page_handler.h"
#include <string>
#include "atom/browser/atom_browser_context.h"
#include "base/callback.h"
#include "base/files/file_path.h"
#include "content/public/browser/web_contents.h"
namespace atom {
namespace api {
SavePageHandler::SavePageHandler(content::WebContents* web_contents,
const SavePageCallback& callback)
: web_contents_(web_contents),
callback_(callback) {
}
SavePageHandler::~SavePageHandler() {
}
void SavePageHandler::OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) {
// OnDownloadCreated is invoked during WebContents::SavePage, so the |item|
// here is the one stated by WebContents::SavePage.
item->AddObserver(this);
}
bool SavePageHandler::Handle(const base::FilePath& full_path,
const content::SavePageType& save_type) {
auto download_manager = content::BrowserContext::GetDownloadManager(
web_contents_->GetBrowserContext());
download_manager->AddObserver(this);
bool result = web_contents_->SavePage(full_path,
full_path.DirName(),
save_type);
download_manager->RemoveObserver(this);
// If initialization fails which means fail to create |DownloadItem|, we need
// to delete the |SavePageHandler| instance to avoid memory-leak.
if (!result)
delete this;
return result;
}
void SavePageHandler::OnDownloadUpdated(content::DownloadItem* item) {
if (item->IsDone()) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
if (item->GetState() == content::DownloadItem::COMPLETE) {
callback_.Run(v8::Null(isolate));
} else {
v8::Local<v8::String> error_message = v8::String::NewFromUtf8(
isolate, "Fail to save page");
callback_.Run(v8::Exception::Error(error_message));
}
Destroy(item);
}
}
void SavePageHandler::Destroy(content::DownloadItem* item) {
item->RemoveObserver(this);
delete this;
}
// static
bool SavePageHandler::IsSavePageTypes(const std::string& type) {
return type == "multipart/related" || type == "text/html";
}
} // namespace api
} // namespace atom

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_SAVE_PAGE_HANDLER_H_
#define ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_
#include <string>
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/save_page_type.h"
#include "v8/include/v8.h"
namespace base {
class FilePath;
}
namespace content {
class WebContents;
}
namespace atom {
namespace api {
// A self-destroyed class for handling save page request.
class SavePageHandler : public content::DownloadManager::Observer,
public content::DownloadItem::Observer {
public:
using SavePageCallback = base::Callback<void(v8::Local<v8::Value>)>;
SavePageHandler(content::WebContents* web_contents,
const SavePageCallback& callback);
~SavePageHandler();
bool Handle(const base::FilePath& full_path,
const content::SavePageType& save_type);
static bool IsSavePageTypes(const std::string& type);
private:
void Destroy(content::DownloadItem* item);
// content::DownloadManager::Observer:
void OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) override;
// content::DownloadItem::Observer:
void OnDownloadUpdated(content::DownloadItem* item) override;
content::WebContents* web_contents_; // weak
SavePageCallback callback_;
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_

View file

@ -18,6 +18,25 @@ require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')
globalPaths = Module.globalPaths
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
if process.platform is 'win32'
# Redirect node's console to use our own implementations, since node can not
# handle console output when running as GUI program.
consoleLog = (args...) ->
process.log util.format(args...) + "\n"
streamWrite = (chunk, encoding, callback) ->
chunk = chunk.toString(encoding) if Buffer.isBuffer chunk
process.log chunk
callback() if callback
true
console.log = console.error = console.warn = consoleLog
process.stdout.write = process.stderr.write = streamWrite
# Always returns EOF for stdin stream.
Readable = require('stream').Readable
stdin = new Readable
stdin.push null
process.__defineGetter__ 'stdin', -> stdin
# Don't quit on fatal error.
process.on 'uncaughtException', (error) ->
# Do nothing if the user has a custom uncaught exception handler.

View file

@ -69,7 +69,9 @@ unwrapArgs = (sender, args) ->
rendererReleased = true
ret = ->
throw new Error('Calling a callback of released renderer view') if rendererReleased
if rendererReleased
throw new Error("Attempting to call a function in a renderer window
that has been closed or released. Function provided here: #{meta.id}.")
sender.send 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, arguments)
v8Util.setDestructor ret, ->
return if rendererReleased

View file

@ -116,7 +116,8 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
} else if (options.Get(switches::kCenter, &center) && center) {
Center();
}
extensions::SizeConstraints size_constraints;
// On Linux and Window we may already have maximum size defined.
extensions::SizeConstraints size_constraints(GetContentSizeConstraints());
int min_height = 0, min_width = 0;
if (options.Get(switches::kMinHeight, &min_height) |
options.Get(switches::kMinWidth, &min_width)) {

View file

@ -390,7 +390,10 @@ gfx::Size NativeWindowViews::GetContentSize() {
void NativeWindowViews::SetContentSizeConstraints(
const extensions::SizeConstraints& size_constraints) {
NativeWindow::SetContentSizeConstraints(size_constraints);
window_->OnSizeConstraintsChanged();
// widget_delegate() is only available after Init() is called, we make use of
// this to determine whether native widget has initialized.
if (window_ && window_->widget_delegate())
window_->OnSizeConstraintsChanged();
#if defined(USE_X11)
if (resizable_)
old_size_constraints_ = size_constraints;

View file

@ -17,9 +17,9 @@
<key>CFBundleIconFile</key>
<string>atom.icns</string>
<key>CFBundleVersion</key>
<string>0.33.8</string>
<string>0.34.0</string>
<key>CFBundleShortVersionString</key>
<string>0.33.8</string>
<string>0.34.0</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key>

View file

@ -56,8 +56,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,33,8,0
PRODUCTVERSION 0,33,8,0
FILEVERSION 0,34,0,0
PRODUCTVERSION 0,34,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -74,12 +74,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
VALUE "FileVersion", "0.33.8"
VALUE "FileVersion", "0.34.0"
VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron"
VALUE "ProductVersion", "0.33.8"
VALUE "ProductVersion", "0.34.0"
VALUE "SquirrelAwareVersion", "1"
END
END

View file

@ -26,7 +26,6 @@ namespace {
const char* kWebRuntimeFeatures[] = {
switches::kExperimentalFeatures,
switches::kExperimentalCanvasFeatures,
switches::kSubpixelFontScaling,
switches::kOverlayScrollbars,
switches::kOverlayFullscreenVideo,
switches::kSharedWorker,

View file

@ -1,16 +1,25 @@
savedGlobal = global # the "global.global" might be deleted later
module.exports =
class CallbacksRegistry
constructor: ->
@emptyFunc = -> throw new Error "Browser trying to call a non-exist callback
in renderer, this usually happens when renderer code forgot to release
a callback installed on objects in browser when renderer was going to be
unloaded or released."
@nextId = 0
@callbacks = {}
add: (callback) ->
id = Math.random().toString()
id = ++@nextId
# Capture the location of the function and put it in the ID string,
# so that release errors can be tracked down easily.
regexp = /at (.*)/gi
stackString = (new Error).stack
while (match = regexp.exec(stackString)) isnt null
[x, location] = match
continue if location.indexOf('(native)') isnt -1
continue if location.indexOf('atom.asar') isnt -1
[x, filenameAndLine] = /([^/^\)]*)\)?$/gi.exec(location)
id = "#{filenameAndLine} (#{id})"
break
@callbacks[id] = callback
id
@ -18,10 +27,10 @@ class CallbacksRegistry
@callbacks[id] ? ->
call: (id, args...) ->
@get(id).call savedGlobal, args...
@get(id).call global, args...
apply: (id, args...) ->
@get(id).apply savedGlobal, args...
@get(id).apply global, args...
remove: (id) ->
delete @callbacks[id]

View file

@ -6,8 +6,8 @@
#define ATOM_VERSION_H
#define ATOM_MAJOR_VERSION 0
#define ATOM_MINOR_VERSION 33
#define ATOM_PATCH_VERSION 8
#define ATOM_MINOR_VERSION 34
#define ATOM_PATCH_VERSION 0
#define ATOM_VERSION_IS_RELEASE 1

View file

@ -11,6 +11,25 @@
#include "base/memory/singleton.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/common/result_codes.h"
#include "gin/public/debug.h"
#include "sandbox/win/src/nt_internals.h"
#pragma intrinsic(_AddressOfReturnAddress)
#pragma intrinsic(_ReturnAddress)
#ifdef _WIN64
// See http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
typedef struct _UNWIND_INFO {
unsigned char Version : 3;
unsigned char Flags : 5;
unsigned char SizeOfProlog;
unsigned char CountOfCodes;
unsigned char FrameRegister : 4;
unsigned char FrameOffset : 4;
ULONG ExceptionHandler;
} UNWIND_INFO, *PUNWIND_INFO;
#endif
namespace crash_reporter {
@ -24,6 +43,94 @@ const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent";
const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service";
typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle,
NTSTATUS ExitStatus);
char* g_real_terminate_process_stub = NULL;
void TerminateProcessWithoutDump() {
// Patched stub exists based on conditions (See InitCrashReporter).
// As a side note this function also gets called from
// WindowProcExceptionFilter.
if (g_real_terminate_process_stub == NULL) {
::TerminateProcess(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
} else {
NtTerminateProcessPtr real_terminate_proc =
reinterpret_cast<NtTerminateProcessPtr>(
static_cast<char*>(g_real_terminate_process_stub));
real_terminate_proc(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
}
}
#ifdef _WIN64
int CrashForExceptionInNonABICompliantCodeRange(
PEXCEPTION_RECORD ExceptionRecord,
ULONG64 EstablisherFrame,
PCONTEXT ContextRecord,
PDISPATCHER_CONTEXT DispatcherContext) {
EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord };
if (!CrashReporter::GetInstance())
return EXCEPTION_CONTINUE_SEARCH;
return static_cast<CrashReporterWin*>(CrashReporter::GetInstance())->
CrashForException(&info);
}
struct ExceptionHandlerRecord {
RUNTIME_FUNCTION runtime_function;
UNWIND_INFO unwind_info;
unsigned char thunk[12];
};
void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
ExceptionHandlerRecord* record =
reinterpret_cast<ExceptionHandlerRecord*>(start);
// We assume that the first page of the code range is executable and
// committed and reserved for breakpad. What could possibly go wrong?
// All addresses are 32bit relative offsets to start.
record->runtime_function.BeginAddress = 0;
record->runtime_function.EndAddress =
base::checked_cast<DWORD>(size_in_bytes);
record->runtime_function.UnwindData =
offsetof(ExceptionHandlerRecord, unwind_info);
// Create unwind info that only specifies an exception handler.
record->unwind_info.Version = 1;
record->unwind_info.Flags = UNW_FLAG_EHANDLER;
record->unwind_info.SizeOfProlog = 0;
record->unwind_info.CountOfCodes = 0;
record->unwind_info.FrameRegister = 0;
record->unwind_info.FrameOffset = 0;
record->unwind_info.ExceptionHandler =
offsetof(ExceptionHandlerRecord, thunk);
// Hardcoded thunk.
// mov imm64, rax
record->thunk[0] = 0x48;
record->thunk[1] = 0xb8;
void* handler = &CrashForExceptionInNonABICompliantCodeRange;
memcpy(&record->thunk[2], &handler, 8);
// jmp rax
record->thunk[10] = 0xff;
record->thunk[11] = 0xe0;
// Protect reserved page against modifications.
DWORD old_protect;
CHECK(VirtualProtect(
start, sizeof(ExceptionHandlerRecord), PAGE_EXECUTE_READ, &old_protect));
CHECK(RtlAddFunctionTable(
&record->runtime_function, 1, reinterpret_cast<DWORD64>(start)));
}
void UnregisterNonABICompliantCodeRange(void* start) {
ExceptionHandlerRecord* record =
reinterpret_cast<ExceptionHandlerRecord*>(start);
CHECK(RtlDeleteFunctionTable(&record->runtime_function));
}
#endif // _WIN64
} // namespace
CrashReporterWin::CrashReporterWin() {
@ -63,26 +170,46 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
// to allow any previous handler to detach in the correct order.
breakpad_.reset();
int handler_types = google_breakpad::ExceptionHandler::HANDLER_EXCEPTION |
google_breakpad::ExceptionHandler::HANDLER_PURECALL;
breakpad_.reset(new google_breakpad::ExceptionHandler(
temp_dir.value(),
FilterCallback,
MinidumpCallback,
this,
handler_types,
google_breakpad::ExceptionHandler::HANDLER_ALL,
kSmallDumpType,
pipe_name.c_str(),
GetCustomInfo(product_name, version, company_name)));
if (!breakpad_->IsOutOfProcess())
LOG(ERROR) << "Cannot initialize out-of-process crash handler";
#ifdef _WIN64
// Hook up V8 to breakpad.
{
// gin::Debug::SetCodeRangeCreatedCallback only runs the callback when
// Isolate is just created, so we have to manually run following code here.
void* code_range = nullptr;
size_t size = 0;
v8::Isolate::GetCurrent()->GetCodeRange(&code_range, &size);
if (code_range && size)
RegisterNonABICompliantCodeRange(code_range, size);
}
gin::Debug::SetCodeRangeDeletedCallback(UnregisterNonABICompliantCodeRange);
#endif
}
void CrashReporterWin::SetUploadParameters() {
upload_parameters_["platform"] = "win32";
}
int CrashReporterWin::CrashForException(EXCEPTION_POINTERS* info) {
if (breakpad_) {
breakpad_->WriteMinidumpForException(info);
TerminateProcessWithoutDump();
}
return EXCEPTION_CONTINUE_SEARCH;
}
// static
bool CrashReporterWin::FilterCallback(void* context,
EXCEPTION_POINTERS* exinfo,

View file

@ -29,6 +29,9 @@ class CrashReporterWin : public CrashReporter {
bool skip_system_crash_handler) override;
void SetUploadParameters() override;
// Crashes the process after generating a dump for the provided exception.
int CrashForException(EXCEPTION_POINTERS* info);
private:
friend struct DefaultSingletonTraits<CrashReporterWin>;

View file

@ -311,7 +311,7 @@ bool CrashService::Initialize(const base::string16& application_name,
// service is initialized.
base::string16 wait_name = ReplaceStringPlaceholders(
kWaitEventFormat, application_name, NULL);
HANDLE wait_event = ::CreateEventW(NULL, TRUE, FALSE, wait_name.c_str());
HANDLE wait_event = ::CreateEventW(NULL, TRUE, TRUE, wait_name.c_str());
::SetEvent(wait_event);
return true;

View file

@ -99,7 +99,6 @@ const char kClientCertificate[] = "client-certificate";
// Web runtime features.
const char kExperimentalFeatures[] = "experimental-features";
const char kExperimentalCanvasFeatures[] = "experimental-canvas-features";
const char kSubpixelFontScaling[] = "subpixel-font-scaling";
const char kOverlayScrollbars[] = "overlay-scrollbars";
const char kOverlayFullscreenVideo[] = "overlay-fullscreen-video";
const char kSharedWorker[] = "shared-worker";

View file

@ -51,7 +51,6 @@ extern const char kClientCertificate[];
extern const char kExperimentalFeatures[];
extern const char kExperimentalCanvasFeatures[];
extern const char kSubpixelFontScaling[];
extern const char kOverlayScrollbars[];
extern const char kOverlayFullscreenVideo[];
extern const char kSharedWorker[];

View file

@ -234,8 +234,6 @@ void AtomRendererClient::EnableWebRuntimeFeatures() {
blink::WebRuntimeFeatures::enableExperimentalFeatures(b);
if (IsSwitchEnabled(command_line, switches::kExperimentalCanvasFeatures, &b))
blink::WebRuntimeFeatures::enableExperimentalCanvasFeatures(b);
if (IsSwitchEnabled(command_line, switches::kSubpixelFontScaling, &b))
blink::WebRuntimeFeatures::enableSubpixelFontScaling(b);
if (IsSwitchEnabled(command_line, switches::kOverlayScrollbars, &b))
blink::WebRuntimeFeatures::enableOverlayScrollbars(b);
if (IsSwitchEnabled(command_line, switches::kOverlayFullscreenVideo, &b))

View file

@ -1,12 +1,12 @@
## Guias
* [Distribuir Aplicação](tutorial/application-distribution.md)
* [Distribuição de Aplicações](tutorial/application-distribution.md)
* [Empacotamento da aplicação](tutorial/application-packaging.md)
* [Usando módulos nativos](../../docs/tutorial/using-native-node-modules.md)
* [Depuração do processo principal](../../docs/tutorial/debugging-main-process.md)
* [Usando módulos nativos](tutorial/using-native-node-modules.md)
* [Depuração do processo principal](tutorial/debugging-main-process.md)
* [Usando Selenium e WebDriver](../../docs/tutorial/using-selenium-and-webdriver.md)
* [Extensão DevTools](../../docs/tutorial/devtools-extension.md)
* [Usando o plugin papper flash](../../docs/tutorial/using-pepper-flash-plugin.md)
* [Usando o plugin papper flash](tutorial/using-pepper-flash-plugin.md)
## Tutoriais

View file

@ -0,0 +1,53 @@
# Depurando o Processo Principal
A janela do navegador, DevTools, pode somente depurar o processo de renderização
de scripts (por exemplo, as páginas da web). Para providenciar um modo de
depurar os scripts através do processo principal, o Electron criou as opções
`--debug` e `--debug-brk`.
## Opções da Linha de Comando
Use a seguinte opção na linha de comando para depurar o processo principal do
Electron:
### `--debug=[porta]`
Quando este comando é usado, o Electron irá executar o protocolo de depuração
V8 mandando as mensagens na `porta`. A `porta` padrão é `5858`.
### `--debug-brk=[porta]`
Semelhante ao `--debug`, porém pausa o script na primeira linha.
## Usando node-inspector para depurar
__Nota:__ O Electron usa a versão v0.11.13 do Node, a qual, atualmenta não
funciona muito bem com node-inspector, e o processo principal irá quebrar se
você inspecionar o objeto `process` pelo console do node-inspector.
### 1. Inicie o servidor [node-inspector][node-inspector]
```bash
$ node-inspector
```
### 2. Habilite o modo de depuração para o Electron
Você pode também iniciar o Electron com um ponto de depuração, desta maneira:
```bash
$ electron --debug=5858 sua/aplicacao
```
ou para pausar o script na primeira linha:
```bash
$ electron --debug-brk=5858 sua/aplicacao
```
### 3. Carregue o debugger UI
Abra este endereço http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858
usando o Chrome.
[node-inspector]: https://github.com/node-inspector/node-inspector

View file

@ -0,0 +1,68 @@
# Usando Módulos Nativos do Node
Os módulos nativos do Node são suportados pelo Electron, desde que o Electron
esteja usando uma versão diferente da oficial V8 do Node, você tem de
especificar manualmente a localização das headers do Electron quando compilar os
módulos nativos.
## Compatibilidade de Módulos Nativos do Node
Módulos nativos podem quebrar quando utilizar a nova versão do Node, V8.
Para ter certeza que o módulo que você está interessado em trabalhar com o
Electron, você deve checar se a versão do Node utilizada é compatível com a
usada pelo Electron.
Você pode verificar qual versão do Node foi utilizada no Electron olhando na
página [releases](https://github.com/atom/electron/releases) ou usando
`process.version` (veja [Quick Start](https://github.com/atom/electron/blob/master/docs/tutorial/quick-start.md)
por exemplo).
Considere usar [NAN](https://github.com/nodejs/nan/) para seus próprios
módulos, caso isso facilite o suporte da múltiplas versões do Node. Isso é
também de grande ajuda para fazer a portabilidade dos módulos antigos para as
versões mais novas do Node, assim podendo trabalhar com o Electron.
## Como Instalar os Módulos Nativos
Existem três maneiras de instalar os módulos nativos:
### O Modo Fácil
O modo mais direto para recompilar os módulos é pelo pacote
[`electron-rebuild`](https://github.com/paulcbetts/electron-rebuild),
o que lida com passos manuais para baixar as headers e construir os módulos
nativos:
```sh
npm install --save-dev electron-rebuild
# Sempre que rodar npm install, execute também:
node ./node_modules/.bin/electron-rebuild
```
### Via npm
Você pode usar também `npm` para instalar os módulos. Os passos são exatamente
os mesmos com os módulos Node, exceto que você precisa configurar algumas
variáveis da ambiente:
```bash
export npm_config_disturl=https://atom.io/download/atom-shell
export npm_config_target=0.33.1
export npm_config_arch=x64
export npm_config_runtime=electron
HOME=~/.electron-gyp npm install module-name
```
### O modo node-gyp
Para compilar os módulos do Node com as headers do Electron, você precisa dizer
ao `node-gyp` onde baixar as headers e qual versão usar:
```bash
$ cd /path-to-module/
$ HOME=~/.electron-gyp node-gyp rebuild --target=0.29.1 --arch=x64 --dist-url=https://atom.io/download/atom-shell
```
A tag `HOME=~/.electron-gyp` altera onde encontrar as headers de desenvolvimento.
A tag `--target=0.29.1` é a versão do Electron. A tag `--dist-url=...` especifica
onde baixar as headers. A tag `--arch=x64` diz ao módulo que é feito em 64bit.

View file

@ -0,0 +1,68 @@
# Usando o Plugin Pepper Flash
Electron atualmente suporta o plugin Pepper Flash. Para usá-lo no Electron,
você deve especificar manualmente a localização do plugin e então ele será
habilitado em sua aplicação.
## Prepare uma cópia do plugin Flash
Tanto no OS X como no Linux, os detalhes do plugin Pepper Flash podem ser
encontrados navegando por `chrome://plugins` no navegador Chrome. Essa
localização e versão são úteis para o suporte do plugin Electron's Pepper Flash.
Você pode também copiar para outra localização.
## Adicionando a opçao Electron
Você pode adicionar diretamente `--ppapi-flash-path` e `ppapi-flash-version`
para a linha de comando do Electron ou usando o método
`app.commandLine.appendSwitch` após o evento pronto. Também, adicione a opção
`plugins` em `browser-window`.
Por exemplo:
```javascript
var app = require('app');
var BrowserWindow = require('browser-window');
// Informa os erros ao ao servidor.
require('crash-reporter').start();
// Mantém uma referência global da janela, se não manter, a janela irá fechar
// automaticamente quando o objeto javascript for GCed.
var mainWindow = null;
// Sai assim que todas as janelas forem fechadas.
app.on('window-all-closed', function() {
if (process.platform != 'darwin') {
app.quit();
}
});
// Epecifica o caminho do flash.
// No Windows, deve ser /path/to/pepflashplayer.dll
// No Mac, /path/to/PepperFlashPlayer.plugin
// No Linux, /path/to/libpepflashplayer.so
app.commandLine.appendSwitch('ppapi-flash-path', '/path/to/libpepflashplayer.so');
// Especifica a versão do flash, por exemplo, v17.0.0.169
app.commandLine.appendSwitch('ppapi-flash-version', '17.0.0.169');
app.on('ready', function() {
mainWindow = new BrowserWindow({
'width': 800,
'height': 600,
'web-preferences': {
'plugins': true
}
});
mainWindow.loadUrl('file://' + __dirname + '/index.html');
// Algo mais
});
```
## Ative o plugin Flash na tag `<webview>`
Adicione o atributo `plugins` na tag `<webview>`.
```html
<webview src="http://www.adobe.com/software/flash/about/" plugins></webview>
```

View file

@ -2,6 +2,7 @@
* [Supported Platforms](tutorial/supported-platforms.md)
* [Application Distribution](tutorial/application-distribution.md)
* [Mac App Store Submission Guide](tutorial/mac-app-store-submission-guide.md)
* [Application Packaging](tutorial/application-packaging.md)
* [Using Native Node Modules](tutorial/using-native-node-modules.md)
* [Debugging Main Process](tutorial/debugging-main-process.md)

View file

@ -111,7 +111,6 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
* `plugins` Boolean - Whether plugins should be enabled.
* `experimental-features` Boolean
* `experimental-canvas-features` Boolean
* `subpixel-font-scaling` Boolean
* `overlay-scrollbars` Boolean
* `overlay-fullscreen-video` Boolean
* `shared-worker` Boolean

View file

@ -8,6 +8,8 @@ upstream node:
* `process.versions['electron']` String - Version of Electron.
* `process.versions['chrome']` String - Version of Chromium.
* `process.resourcesPath` String - Path to JavaScript source code.
* `process.mas` Boolean - For Mac App Store build, this value is `true`, for
other builds it is `undefined`.
## Events
@ -37,7 +39,7 @@ The `process` object has the following method:
Causes the main thread of the current process hang.
### process.setFdLimit(maxDescriptors) _OS X_ _Linux_
### `process.setFdLimit(maxDescriptors)` _OS X_ _Linux_
* `maxDescriptors` Integer

View file

@ -631,3 +631,26 @@ Get the `WebContents` of DevTools for this `WebContents`.
**Note:** Users should never store this object because it may become `null`
when the DevTools has been closed.
### `webContents.savePage(fullPath, saveType, callback)`
* `fullPath` String - The full file path.
* `saveType` String - Specify the save type.
* `HTMLOnly` - Save only the HTML of the page.
* `HTMLComplete` - Save complete-html page.
* `MHTML` - Save complete-html page as MHTML.
* `callback` Function - `function(error) {}`.
* `error` Error
Returns true if the process of saving page has been initiated successfully.
```javascript
win.loadUrl('https://github.com');
win.webContents.on('did-finish-load', function() {
win.webContents.savePage('/tmp/test.html', 'HTMLComplete', function(error) {
if (!error)
console.log("Save page successfully");
});
});
```

View file

@ -0,0 +1,115 @@
# Mac App Store Submission Guide
Since v0.34.0, Electron allows submitting packaged apps to Mac App Store (MAS),
this guide provides information on how to submit your app, and the limitations
of the MAS build.
## How to submit your app
Following steps introduces a simple way to submit your app to Mac App Store, but
it doesn't make sure your app gets approved by Apple, you still have to read
apple's [Submitting Your App][submitting-your-app] guide on how to meet Mac
App Store's requirements.
### Get certificate
To submit your app to Mac App Store, you have to get a certificate from Apple
first, you can follow [existing guides][nwjs-guide] on web.
### Sign your app
After getting the certificate, you can package your app by following
[Application Distribution](application-distribution.md), and then sign your app.
The step is basically the same with other programs, the key is to sign every
dependency of Electron one by one.
First you need to prepare two entitlements files.
`child.plist`:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>
```
`parent.plist`:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
</dict>
</plist>
```
And then sign your app with following script:
```bash
#!/bin/bash
# Name of your app.
APP="YourApp"
# The path of you app to sign.
APP_PATH="/path/to/YouApp.app"
# The path to the location you want to put the signed package.
RESULT_PATH="~/Desktop/$APP.pkg"
# The name of certificates you requested.
APP_KEY="3rd Party Mac Developer Application: Company Name (APPIDENTITY)"
INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)"
FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Libraries/libnode.dylib"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Electron Framework"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/"
codesign -fs "$APP_KEY" --entitlements parent.plist "$APP_PATH"
productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$APP_PATH"
```
If you are new to app sandboxing of OS X, you should also go through Apple's
[Enabling App Sandbox][enable-app-sandbox] to have a basic idea, and add keys
for the permissions needed by your app to the entitlements files.
### Upload your app and submit for review
After signing your app you can use Application Loader to upload it to iTunes
Connect for processing, make sure you have [created a record][create-record]
before uploading. Then you can [submit your app for review][submit-for-review].
## Limitations of MAS build
In order to satisfy requirements for app sandboxing, following modules have been
disabled in MAS build:
* `crash-reporter`
* `auto-updater`
and following behaviors have been changed:
* Video capture may not work for some machines.
* Certain accessibility features may not work.
* Apps will not be aware of DNS changes.
Also due to the usage of app sandboxing, the resources can be accessed by the
app is strictly limited, you can read [App Sandboxing][app-sandboxing] for more.
[submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html
[nwjs-guide]: https://github.com/nwjs/nw.js/wiki/Mac-App-Store-%28MAS%29-Submission-Guideline#first-steps
[enable-app-sandbox]: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html
[create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html
[submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html
[app-sandboxing]: https://developer.apple.com/app-sandboxing/

View file

@ -108,6 +108,8 @@
'atom/browser/api/trackable_object.h',
'atom/browser/api/frame_subscriber.cc',
'atom/browser/api/frame_subscriber.h',
'atom/browser/api/save_page_handler.cc',
'atom/browser/api/save_page_handler.h',
'atom/browser/auto_updater.cc',
'atom/browser/auto_updater.h',
'atom/browser/auto_updater_delegate.h',

View file

@ -7,8 +7,8 @@ import sys
BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \
'http://github-janky-artifacts.s3.amazonaws.com/libchromiumcontent'
LIBCHROMIUMCONTENT_COMMIT = '04523758cda2a96d2454f9056fb1fb9a1c1f95f1'
'http://gh-contractor-zcbenz.s3.amazonaws.com/libchromiumcontent'
LIBCHROMIUMCONTENT_COMMIT = '78e54bc39a04b758ed5167cd980cc4d9951bd629'
PLATFORM = {
'cygwin': 'win32',

View file

@ -301,3 +301,15 @@ describe 'browser-window module', ->
assert.notEqual data.length, 0
w.webContents.endFrameSubscription()
done()
describe 'save page', ->
savePagePath = path.join fixtures, 'save_page.html'
it 'should save page', (done) ->
w.webContents.on 'did-finish-load', ->
w.webContents.savePage savePagePath, 'HTMLComplete', (error) ->
assert.equal error, null
assert fs.existsSync savePagePath
fs.unlinkSync savePagePath
done()
w.loadUrl "file://#{fixtures}/api/blank.html"

View file

@ -15,9 +15,6 @@ describe 'crash-reporter module', ->
beforeEach -> w = new BrowserWindow(show: false)
afterEach -> w.destroy()
# It is not working on 64bit Windows.
return if process.platform is 'win32' and process.arch is 'x64'
# It is not working for mas build.
return if process.mas

View file

@ -450,10 +450,10 @@ describe 'asar package', ->
w = new BrowserWindow(show: false, width: 400, height: 400)
p = path.resolve fixtures, 'asar', 'web.asar', 'index.html'
u = url.format protocol: 'file', slashed: true, pathname: p
w.loadUrl u
ipc.once 'dirname', (event, dirname) ->
assert.equal dirname, path.dirname(p)
done()
w.loadUrl u
it 'loads script tag in html', (done) ->
after ->