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

This commit is contained in:
Eran Tiktin 2015-11-20 18:44:51 +02:00
commit 50083017bc
110 changed files with 3432 additions and 647 deletions

View file

@ -47,9 +47,13 @@ Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법도 문
- [중국어 간체](https://github.com/atom/electron/tree/master/docs-translations/zh-CN)
- [중국어 번체](https://github.com/atom/electron/tree/master/docs-translations/zh-TW)
## 시작하기
[`atom/electron-quick-start`](https://github.com/atom/electron-quick-start) 저장소를 클론하여 Electron을 간단히 접해볼 수 있습니다.
## 커뮤니티
다음 링크를 통해 커뮤니티에 질문을 올리거나 토론을 나누실 수 있습니다:
다음 링크를 통해 커뮤니티에 질문을 올리거나 토론을 나 수 있습니다:
- Atom 포럼의 [`electron`](http://discuss.atom.io/category/electron) 카테고리
- Freenode 채팅의 `#atom-shell` 채널

View file

@ -53,6 +53,11 @@ contains documents describing how to build and contribute to Electron.
- [Simplified Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-CN)
- [Traditional Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-TW)
## Quick Start
Clone and run the [`atom/electron-quick-start`](https://github.com/atom/electron-quick-start)
repository to see a minimal Electron app in action.
## Community
You can ask questions and interact with the community in the following

View file

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

View file

@ -10,6 +10,7 @@
#include "base/at_exit.h"
#include "base/i18n/icu_util.h"
#include "base/mac/bundle_locations.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "brightray/common/mac/main_application_bundle.h"
#include "content/public/app/content_main.h"
@ -25,6 +26,7 @@ int AtomMain(int argc, const char* argv[]) {
int AtomInitializeICUandStartNode(int argc, char *argv[]) {
base::AtExitManager atexit_manager;
base::mac::ScopedNSAutoreleasePool pool;
base::mac::SetOverrideFrameworkBundlePath(
brightray::MainApplicationBundlePath()
.Append("Contents")

View file

@ -59,7 +59,9 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
#endif // !defined(OS_WIN)
// Only enable logging when --enable-logging is specified.
if (!command_line->HasSwitch(switches::kEnableLogging)) {
scoped_ptr<base::Environment> env(base::Environment::Create());
if (!command_line->HasSwitch(switches::kEnableLogging) &&
!env->HasVar("ELECTRON_ENABLE_LOGGING")) {
settings.logging_dest = logging::LOG_NONE;
logging::SetMinLogLevel(logging::LOG_NUM_SEVERITIES);
}
@ -69,10 +71,13 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
// Logging with pid and timestamp.
logging::SetLogItems(true, false, true, false);
#if defined(DEBUG) && defined(OS_LINUX)
// Enable convient stack printing.
base::debug::EnableInProcessStackDumping();
bool enable_stack_dumping = env->HasVar("ELECTRON_ENABLE_STACK_DUMPING");
#if defined(DEBUG) && defined(OS_LINUX)
enable_stack_dumping = true;
#endif
if (enable_stack_dumping)
base::debug::EnableInProcessStackDumping();
return brightray::MainDelegate::BasicStartupComplete(exit_code);
}

View file

@ -7,8 +7,8 @@
#include "atom/app/uv_task_runner.h"
#include "atom/browser/javascript_environment.h"
#include "atom/browser/node_debugger.h"
#include "atom/common/node_includes.h"
#include "base/command_line.h"
#include "atom/common/node_includes.h"
#include "base/thread_task_runner_handle.h"
#include "gin/array_buffer.h"
#include "gin/public/isolate_holder.h"
@ -19,25 +19,22 @@ namespace atom {
int NodeMain(int argc, char *argv[]) {
base::CommandLine::Init(argc, argv);
argv = uv_setup_args(argc, argv);
int exec_argc;
const char** exec_argv;
node::Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);
int exit_code = 1;
{
// Feed gin::PerIsolateData with a task runner.
argv = uv_setup_args(argc, argv);
uv_loop_t* loop = uv_default_loop();
scoped_refptr<UvTaskRunner> uv_task_runner(new UvTaskRunner(loop));
base::ThreadTaskRunnerHandle handle(uv_task_runner);
gin::V8Initializer::LoadV8Snapshot();
gin::V8Initializer::LoadV8Natives();
gin::IsolateHolder::Initialize(
gin::IsolateHolder::kNonStrictMode,
gin::ArrayBufferAllocator::SharedInstance());
JavascriptEnvironment gin_env;
int exec_argc;
const char** exec_argv;
node::Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);
node::Environment* env = node::CreateEnvironment(
gin_env.isolate(), loop, gin_env.context(), argc, argv,
exec_argc, exec_argv);

View file

@ -48,8 +48,13 @@ void UvTaskRunner::OnTimeout(uv_timer_t* timer) {
self->tasks_[timer].Run();
self->tasks_.erase(timer);
uv_unref(reinterpret_cast<uv_handle_t*>(timer));
delete timer;
uv_timer_stop(timer);
uv_close(reinterpret_cast<uv_handle_t*>(timer), UvTaskRunner::OnClose);
}
// static
void UvTaskRunner::OnClose(uv_handle_t* handle) {
delete reinterpret_cast<uv_timer_t*>(handle);
}
} // namespace atom

View file

@ -31,6 +31,7 @@ class UvTaskRunner : public base::SingleThreadTaskRunner {
private:
static void OnTimeout(uv_timer_t* timer);
static void OnClose(uv_handle_t* handle);
uv_loop_t* loop_;

View file

@ -111,6 +111,23 @@ int GetPathConstant(const std::string& name) {
return -1;
}
bool NotificationCallbackWrapper(
const ProcessSingleton::NotificationCallback& callback,
const base::CommandLine::StringVector& cmd,
const base::FilePath& cwd) {
// Make sure the callback is called after app gets ready.
if (Browser::Get()->is_ready()) {
callback.Run(cmd, cwd);
} else {
scoped_refptr<base::SingleThreadTaskRunner> task_runner(
base::ThreadTaskRunnerHandle::Get());
task_runner->PostTask(
FROM_HERE, base::Bind(base::IgnoreResult(callback), cmd, cwd));
}
// ProcessSingleton needs to know whether current process is quiting.
return !Browser::Get()->is_shutting_down();
}
void OnClientCertificateSelected(
v8::Isolate* isolate,
std::shared_ptr<content::ClientCertificateDelegate> delegate,
@ -160,6 +177,11 @@ void App::OnWindowAllClosed() {
void App::OnQuit() {
Emit("quit");
if (process_singleton_.get()) {
process_singleton_->Cleanup();
process_singleton_.reset();
}
}
void App::OnOpenFile(bool* prevent_default, const std::string& file_path) {
@ -251,6 +273,12 @@ void App::SetAppUserModelId(const std::string& app_id) {
#endif
}
void App::AllowNTLMCredentialsForAllDomains(bool should_allow) {
auto browser_context = static_cast<AtomBrowserContext*>(
AtomBrowserMainParts::Get()->browser_context());
browser_context->AllowNTLMCredentialsForAllDomains(should_allow);
}
std::string App::GetLocale() {
return l10n_util::GetApplicationLocale("");
}
@ -262,6 +290,28 @@ v8::Local<v8::Value> App::DefaultSession(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, default_session_);
}
bool App::MakeSingleInstance(
const ProcessSingleton::NotificationCallback& callback) {
if (process_singleton_.get())
return false;
base::FilePath user_dir;
PathService::Get(brightray::DIR_USER_DATA, &user_dir);
process_singleton_.reset(new ProcessSingleton(
user_dir, base::Bind(NotificationCallbackWrapper, callback)));
switch (process_singleton_->NotifyOtherProcessOrCreate()) {
case ProcessSingleton::NotifyResult::LOCK_ERROR:
case ProcessSingleton::NotifyResult::PROFILE_IN_USE:
case ProcessSingleton::NotifyResult::PROCESS_NOTIFIED:
process_singleton_.reset();
return true;
case ProcessSingleton::NotifyResult::PROCESS_NONE:
default: // Shouldn't be needed, but VS warns if it is not there.
return false;
}
}
mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
auto browser = base::Unretained(Browser::Get());
@ -285,7 +335,10 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
.SetMethod("getPath", &App::GetPath)
.SetMethod("setDesktopName", &App::SetDesktopName)
.SetMethod("setAppUserModelId", &App::SetAppUserModelId)
.SetMethod("allowNTLMCredentialsForAllDomains",
&App::AllowNTLMCredentialsForAllDomains)
.SetMethod("getLocale", &App::GetLocale)
.SetMethod("makeSingleInstance", &App::MakeSingleInstance)
.SetProperty("defaultSession", &App::DefaultSession);
}

View file

@ -9,6 +9,8 @@
#include "atom/browser/api/event_emitter.h"
#include "atom/browser/browser_observer.h"
#include "atom/common/native_mate_converters/callback.h"
#include "chrome/browser/process_singleton.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "native_mate/handle.h"
@ -65,11 +67,16 @@ class App : public mate::EventEmitter,
void SetDesktopName(const std::string& desktop_name);
void SetAppUserModelId(const std::string& app_id);
void AllowNTLMCredentialsForAllDomains(bool should_allow);
bool MakeSingleInstance(
const ProcessSingleton::NotificationCallback& callback);
std::string GetLocale();
v8::Local<v8::Value> DefaultSession(v8::Isolate* isolate);
v8::Global<v8::Value> default_session_;
scoped_ptr<ProcessSingleton> process_singleton_;
DISALLOW_COPY_AND_ASSIGN(App);
};

View file

@ -5,12 +5,31 @@
#include "atom/browser/api/atom_api_auto_updater.h"
#include "base/time/time.h"
#include "atom/browser/auto_updater.h"
#include "atom/browser/browser.h"
#include "atom/browser/native_window.h"
#include "atom/browser/window_list.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/node_includes.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
namespace mate {
template<>
struct Converter<base::Time> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const base::Time& val) {
v8::MaybeLocal<v8::Value> date = v8::Date::New(
isolate->GetCurrentContext(), val.ToJsTime());
if (date.IsEmpty())
return v8::Null(isolate);
else
return date.ToLocalChecked();
}
};
} // namespace mate
namespace atom {
namespace api {
@ -20,11 +39,18 @@ AutoUpdater::AutoUpdater() {
}
AutoUpdater::~AutoUpdater() {
auto_updater::AutoUpdater::SetDelegate(NULL);
auto_updater::AutoUpdater::SetDelegate(nullptr);
}
void AutoUpdater::OnError(const std::string& error) {
Emit("error", error);
void AutoUpdater::OnError(const std::string& message) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto error = v8::Exception::Error(mate::StringToV8(isolate(), message));
EmitCustomEvent(
"error",
error->ToObject(isolate()->GetCurrentContext()).ToLocalChecked(),
// Message is also emitted to keep compatibility with old code.
message);
}
void AutoUpdater::OnCheckingForUpdate() {
@ -42,11 +68,14 @@ void AutoUpdater::OnUpdateNotAvailable() {
void AutoUpdater::OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url,
const base::Closure& quit_and_install) {
quit_and_install_ = quit_and_install;
Emit("update-downloaded-raw", release_notes, release_name,
release_date.ToJsTime(), update_url);
const std::string& url) {
Emit("update-downloaded", release_notes, release_name, release_date, url,
// Keep compatibility with old APIs.
base::Bind(&AutoUpdater::QuitAndInstall, base::Unretained(this)));
}
void AutoUpdater::OnWindowAllClosed() {
QuitAndInstall();
}
mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder(
@ -54,14 +83,21 @@ mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder(
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("setFeedUrl", &auto_updater::AutoUpdater::SetFeedURL)
.SetMethod("checkForUpdates", &auto_updater::AutoUpdater::CheckForUpdates)
.SetMethod("_quitAndInstall", &AutoUpdater::QuitAndInstall);
.SetMethod("quitAndInstall", &AutoUpdater::QuitAndInstall);
}
void AutoUpdater::QuitAndInstall() {
if (quit_and_install_.is_null())
Browser::Get()->Shutdown();
else
quit_and_install_.Run();
// If we don't have any window then quitAndInstall immediately.
WindowList* window_list = WindowList::GetInstance();
if (window_list->size() == 0) {
auto_updater::AutoUpdater::QuitAndInstall();
return;
}
// Otherwise do the restart after all windows have been closed.
window_list->AddObserver(this);
for (NativeWindow* window : *window_list)
window->Close();
}
// static

View file

@ -7,9 +7,9 @@
#include <string>
#include "base/callback.h"
#include "atom/browser/api/event_emitter.h"
#include "atom/browser/auto_updater_delegate.h"
#include "atom/browser/auto_updater.h"
#include "atom/browser/window_list_observer.h"
#include "native_mate/handle.h"
namespace atom {
@ -17,7 +17,8 @@ namespace atom {
namespace api {
class AutoUpdater : public mate::EventEmitter,
public auto_updater::AutoUpdaterDelegate {
public auto_updater::Delegate,
public WindowListObserver {
public:
static mate::Handle<AutoUpdater> Create(v8::Isolate* isolate);
@ -25,17 +26,18 @@ class AutoUpdater : public mate::EventEmitter,
AutoUpdater();
virtual ~AutoUpdater();
// AutoUpdaterDelegate implementations.
// Delegate implementations.
void OnError(const std::string& error) override;
void OnCheckingForUpdate() override;
void OnUpdateAvailable() override;
void OnUpdateNotAvailable() override;
void OnUpdateDownloaded(
const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url,
const base::Closure& quit_and_install) override;
void OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url) override;
// WindowListObserver:
void OnWindowAllClosed() override;
// mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
@ -44,8 +46,6 @@ class AutoUpdater : public mate::EventEmitter,
private:
void QuitAndInstall();
base::Closure quit_and_install_;
DISALLOW_COPY_AND_ASSIGN(AutoUpdater);
};

View file

@ -105,6 +105,24 @@ struct Converter<ClearStorageDataOptions> {
}
};
template<>
struct Converter<net::ProxyConfig> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
net::ProxyConfig* out) {
std::string proxy;
if (!ConvertFromV8(isolate, val, &proxy))
return false;
auto pac_url = GURL(proxy);
if (pac_url.is_valid()) {
out->set_pac_url(pac_url);
} else {
out->proxy_rules().ParseFromString(proxy);
}
return true;
}
};
} // namespace mate
namespace atom {
@ -209,12 +227,12 @@ void ClearHttpCacheInIO(
}
void SetProxyInIO(net::URLRequestContextGetter* getter,
const std::string& proxy,
const net::ProxyConfig& config,
const base::Closure& callback) {
net::ProxyConfig config;
config.proxy_rules().ParseFromString(proxy);
auto proxy_service = getter->GetURLRequestContext()->proxy_service();
proxy_service->ResetConfigService(new net::ProxyConfigServiceFixed(config));
// Refetches and applies the new pac script if provided.
proxy_service->ForceReloadProxyConfig();
RunCallbackInUI(callback);
}
@ -287,11 +305,11 @@ void Session::ClearStorageData(mate::Arguments* args) {
base::Time(), base::Time::Max(), callback);
}
void Session::SetProxy(const std::string& proxy,
void Session::SetProxy(const net::ProxyConfig& config,
const base::Closure& callback) {
auto getter = browser_context_->GetRequestContext();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&SetProxyInIO, base::Unretained(getter), proxy, callback));
base::Bind(&SetProxyInIO, base::Unretained(getter), config, callback));
}
void Session::SetDownloadPath(const base::FilePath& path) {

View file

@ -23,6 +23,10 @@ class Arguments;
class Dictionary;
}
namespace net {
class ProxyConfig;
}
namespace atom {
class AtomBrowserContext;
@ -64,7 +68,7 @@ class Session: public mate::TrackableObject<Session>,
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
void ClearCache(const net::CompletionCallback& callback);
void ClearStorageData(mate::Arguments* args);
void SetProxy(const std::string& proxy, const base::Closure& callback);
void SetProxy(const net::ProxyConfig& config, const base::Closure& callback);
void SetDownloadPath(const base::FilePath& path);
void EnableNetworkEmulation(const mate::Dictionary& options);
void DisableNetworkEmulation();

View file

@ -618,6 +618,10 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
if (options.Get("userAgent", &user_agent))
SetUserAgent(user_agent);
std::string extra_headers;
if (options.Get("extraHeaders", &extra_headers))
params.extra_headers = extra_headers;
params.transition_type = ui::PAGE_TRANSITION_TYPED;
params.should_clear_history_list = true;
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;

View file

@ -189,6 +189,14 @@ void Window::OnExecuteWindowsCommand(const std::string& command_name) {
Emit("app-command", command_name);
}
#if defined(OS_WIN)
void Window::OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) {
if (IsWindowMessageHooked(message)) {
messages_callback_map_[message].Run(w_param, l_param);
}
}
#endif
// static
mate::Wrappable* Window::New(v8::Isolate* isolate,
const mate::Dictionary& options) {
@ -385,6 +393,10 @@ bool Window::IsKiosk() {
return window_->IsKiosk();
}
void Window::SetBackgroundColor(const std::string& color_name) {
window_->SetBackgroundColor(color_name);
}
void Window::FocusOnWebView() {
window_->FocusOnWebView();
}
@ -488,6 +500,29 @@ bool Window::IsMenuBarVisible() {
return window_->IsMenuBarVisible();
}
#if defined(OS_WIN)
bool Window::HookWindowMessage(UINT message,
const MessageCallback& callback) {
messages_callback_map_[message] = callback;
return true;
}
void Window::UnhookWindowMessage(UINT message) {
if (!ContainsKey(messages_callback_map_, message))
return;
messages_callback_map_.erase(message);
}
bool Window::IsWindowMessageHooked(UINT message) {
return ContainsKey(messages_callback_map_, message);
}
void Window::UnhookAllWindowMessages() {
messages_callback_map_.clear();
}
#endif
#if defined(OS_MACOSX)
void Window::ShowDefinitionForSelection() {
window_->ShowDefinitionForSelection();
@ -564,6 +599,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setSkipTaskbar", &Window::SetSkipTaskbar)
.SetMethod("setKiosk", &Window::SetKiosk)
.SetMethod("isKiosk", &Window::IsKiosk)
.SetMethod("setBackgroundColor", &Window::SetBackgroundColor)
.SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename)
.SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename)
.SetMethod("setDocumentEdited", &Window::SetDocumentEdited)
@ -585,6 +621,12 @@ void Window::BuildPrototype(v8::Isolate* isolate,
&Window::SetVisibleOnAllWorkspaces)
.SetMethod("isVisibleOnAllWorkspaces",
&Window::IsVisibleOnAllWorkspaces)
#if defined(OS_WIN)
.SetMethod("hookWindowMessage", &Window::HookWindowMessage)
.SetMethod("isWindowMessageHooked", &Window::IsWindowMessageHooked)
.SetMethod("unhookWindowMessage", &Window::UnhookWindowMessage)
.SetMethod("unhookAllWindowMessages", &Window::UnhookAllWindowMessages)
#endif
#if defined(OS_MACOSX)
.SetMethod("showDefinitionForSelection",
&Window::ShowDefinitionForSelection)

View file

@ -5,6 +5,7 @@
#ifndef ATOM_BROWSER_API_ATOM_API_WINDOW_H_
#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_
#include <map>
#include <string>
#include <vector>
@ -75,6 +76,11 @@ class Window : public mate::TrackableObject<Window>,
void OnRendererResponsive() override;
void OnExecuteWindowsCommand(const std::string& command_name) override;
#if defined(OS_WIN)
void OnWindowMessage(UINT message, WPARAM w_param,
LPARAM l_param) override;
#endif
// mate::Wrappable:
bool IsDestroyed() const override;
@ -122,6 +128,7 @@ class Window : public mate::TrackableObject<Window>,
void SetSkipTaskbar(bool skip);
void SetKiosk(bool kiosk);
bool IsKiosk();
void SetBackgroundColor(const std::string& color_name);
void FocusOnWebView();
void BlurWebView();
bool IsWebViewFocused();
@ -142,6 +149,18 @@ class Window : public mate::TrackableObject<Window>,
bool IsMenuBarVisible();
void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
#if defined(OS_WIN)
typedef base::Callback<void(WPARAM, LPARAM)> MessageCallback;
typedef std::map<UINT, MessageCallback> MessageCallbackMap;
MessageCallbackMap messages_callback_map_;
bool HookWindowMessage(UINT message,
const MessageCallback& callback);
bool IsWindowMessageHooked(UINT message);
void UnhookWindowMessage(UINT message);
void UnhookAllWindowMessages();
#endif
#if defined(OS_MACOSX)
void ShowDefinitionForSelection();
#endif

View file

@ -1,24 +1,7 @@
autoUpdater = process.atomBinding('auto_updater').autoUpdater
EventEmitter = require('events').EventEmitter
autoUpdater.__proto__ = EventEmitter.prototype
autoUpdater.on 'update-downloaded-raw', (args...) ->
args[3] = new Date(args[3]) # releaseDate
@emit 'update-downloaded', args..., => @quitAndInstall()
autoUpdater.quitAndInstall = ->
# If we don't have any window then quitAndInstall immediately.
BrowserWindow = require 'browser-window'
windows = BrowserWindow.getAllWindows()
if windows.length is 0
@_quitAndInstall()
return
# Do the restart after all windows have been closed.
app = require 'app'
app.removeAllListeners 'window-all-closed'
app.once 'window-all-closed', @_quitAndInstall.bind(this)
win.close() for win in windows
module.exports = autoUpdater
switch process.platform
when 'win32'
module.exports = require './auto-updater/auto-updater-win'
when 'darwin'
module.exports = require './auto-updater/auto-updater-mac'
else
throw new Error('auto-updater is not implemented on this platform')

View file

@ -0,0 +1,6 @@
{EventEmitter} = require 'events'
{autoUpdater} = process.atomBinding 'auto_updater'
autoUpdater.__proto__ = EventEmitter.prototype
module.exports = autoUpdater

View file

@ -0,0 +1,42 @@
app = require 'app'
url = require 'url'
{EventEmitter} = require 'events'
squirrelUpdate = require './squirrel-update-win'
class AutoUpdater extends EventEmitter
quitAndInstall: ->
squirrelUpdate.processStart()
app.quit()
setFeedUrl: (updateUrl) ->
@updateUrl = updateUrl
checkForUpdates: ->
return @emitError 'Update URL is not set' unless @updateUrl
return @emitError 'Can not find Squirrel' unless squirrelUpdate.supported()
@emit 'checking-for-update'
squirrelUpdate.download @updateUrl, (error, update) =>
return @emitError error if error?
return @emit 'update-not-available' unless update?
@emit 'update-available'
squirrelUpdate.update @updateUrl, (error) =>
return @emitError error if error?
{releaseNotes, version} = update
# Following information is not available on Windows, so fake them.
date = new Date
url = @updateUrl
@emit 'update-downloaded', {}, releaseNotes, version, date, url, => @quitAndInstall()
# Private: Emit both error object and message, this is to keep compatibility
# with Old APIs.
emitError: (message) ->
@emit 'error', new Error(message), message
module.exports = new AutoUpdater

View file

@ -0,0 +1,67 @@
fs = require 'fs'
path = require 'path'
{spawn} = require 'child_process'
appFolder = path.dirname process.execPath # i.e. my-app/app-0.1.13/
updateExe = path.resolve appFolder, '..', 'Update.exe' # i.e. my-app/Update.exe
exeName = path.basename process.execPath
# Spawn a command and invoke the callback when it completes with an error
# and the output from standard out.
spawnUpdate = (args, detached, callback) ->
try
spawnedProcess = spawn updateExe, args, {detached}
catch error
# Shouldn't happen, but still guard it.
process.nextTick -> callback error
return
stdout = ''
stderr = ''
spawnedProcess.stdout.on 'data', (data) -> stdout += data
spawnedProcess.stderr.on 'data', (data) -> stderr += data
errorEmitted = false
spawnedProcess.on 'error', (error) ->
errorEmitted = true
callback error
spawnedProcess.on 'exit', (code, signal) ->
# We may have already emitted an error.
return if errorEmitted
# Process terminated with error.
if code isnt 0
return callback "Command failed: #{signal ? code}\n#{stderr}"
# Success.
callback null, stdout
# Start an instance of the installed app.
exports.processStart = (callback) ->
spawnUpdate ['--processStart', exeName], true, ->
# Download the releases specified by the URL and write new results to stdout.
exports.download = (updateUrl, callback) ->
spawnUpdate ['--download', updateUrl], false, (error, stdout) ->
return callback(error) if error?
try
# Last line of output is the JSON details about the releases
json = stdout.trim().split('\n').pop()
update = JSON.parse(json)?.releasesToApply?.pop?()
catch
return callback "Invalid result:\n#{stdout}"
callback null, update
# Update the application to the latest remote version specified by URL.
exports.update = (updateUrl, callback) ->
spawnUpdate ['--update', updateUrl], false, callback
# Is the Update.exe installed with the current application?
exports.supported = ->
try
fs.accessSync updateExe, fs.R_OK
return true
catch
return false

View file

@ -36,8 +36,13 @@ bool SavePageHandler::Handle(const base::FilePath& full_path,
auto download_manager = content::BrowserContext::GetDownloadManager(
web_contents_->GetBrowserContext());
download_manager->AddObserver(this);
// Chromium will create a 'foo_files' directory under the directory of saving
// page 'foo.html' for holding other resource files of 'foo.html'.
base::FilePath saved_main_directory_path = full_path.DirName().Append(
full_path.RemoveExtension().BaseName().value() +
FILE_PATH_LITERAL("_files"));
bool result = web_contents_->SavePage(full_path,
full_path.DirName(),
saved_main_directory_path,
save_type);
download_manager->RemoveObserver(this);
// If initialization fails which means fail to create |DownloadItem|, we need

View file

@ -60,7 +60,8 @@ std::string RemoveWhitespace(const std::string& str) {
AtomBrowserContext::AtomBrowserContext(const std::string& partition,
bool in_memory)
: brightray::BrowserContext(partition, in_memory),
job_factory_(new AtomURLRequestJobFactory) {
job_factory_(new AtomURLRequestJobFactory),
allow_ntlm_everywhere_(false) {
}
AtomBrowserContext::~AtomBrowserContext() {
@ -168,6 +169,16 @@ void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
base::FilePath());
}
bool AtomBrowserContext::AllowNTLMCredentialsForDomain(const GURL& origin) {
if (allow_ntlm_everywhere_)
return true;
return Delegate::AllowNTLMCredentialsForDomain(origin);
}
void AtomBrowserContext::AllowNTLMCredentialsForAllDomains(bool should_allow) {
allow_ntlm_everywhere_ = should_allow;
}
} // namespace atom
namespace brightray {

View file

@ -28,6 +28,7 @@ class AtomBrowserContext : public brightray::BrowserContext {
net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory(
const base::FilePath& base_path) override;
net::SSLConfigService* CreateSSLConfigService() override;
bool AllowNTLMCredentialsForDomain(const GURL& auth_origin) override;
// content::BrowserContext:
content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
@ -36,6 +37,8 @@ class AtomBrowserContext : public brightray::BrowserContext {
// brightray::BrowserContext:
void RegisterPrefs(PrefRegistrySimple* pref_registry) override;
void AllowNTLMCredentialsForAllDomains(bool should_allow);
AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
private:
@ -45,6 +48,8 @@ class AtomBrowserContext : public brightray::BrowserContext {
// Managed by brightray::BrowserContext.
AtomURLRequestJobFactory* job_factory_;
bool allow_ntlm_everywhere_;
DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext);
};

View file

@ -62,17 +62,15 @@ void AtomBrowserMainParts::PreEarlyInitialization() {
void AtomBrowserMainParts::PostEarlyInitialization() {
brightray::BrowserMainParts::PostEarlyInitialization();
{
// Temporary set the bridge_task_runner_ as current thread's task runner,
// so we can fool gin::PerIsolateData to use it as its task runner, instead
// of getting current message loop's task runner, which is null for now.
bridge_task_runner_ = new BridgeTaskRunner;
base::ThreadTaskRunnerHandle handle(bridge_task_runner_);
// Temporary set the bridge_task_runner_ as current thread's task runner,
// so we can fool gin::PerIsolateData to use it as its task runner, instead
// of getting current message loop's task runner, which is null for now.
bridge_task_runner_ = new BridgeTaskRunner;
base::ThreadTaskRunnerHandle handle(bridge_task_runner_);
// The ProxyResolverV8 has setup a complete V8 environment, in order to
// avoid conflicts we only initialize our V8 environment after that.
js_env_.reset(new JavascriptEnvironment);
}
// The ProxyResolverV8 has setup a complete V8 environment, in order to
// avoid conflicts we only initialize our V8 environment after that.
js_env_.reset(new JavascriptEnvironment);
node_bindings_->Initialize();
@ -107,6 +105,7 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
1000));
brightray::BrowserMainParts::PreMainMessageLoopRun();
BridgeTaskRunner::MessageLoopIsReady();
#if defined(USE_X11)
libgtk2ui::GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess());

View file

@ -5,11 +5,14 @@
#include "atom/browser/atom_ssl_config_service.h"
#include <string>
#include <vector>
#include "base/command_line.h"
#include "base/strings/string_split.h"
#include "atom/common/options_switches.h"
#include "content/public/browser/browser_thread.h"
#include "net/socket/ssl_client_socket.h"
#include "net/ssl/ssl_cipher_suite_names.h"
namespace atom {
@ -26,6 +29,23 @@ uint16 GetSSLProtocolVersion(const std::string& version_string) {
return version;
}
std::vector<uint16> ParseCipherSuites(
const std::vector<std::string>& cipher_strings) {
std::vector<uint16> cipher_suites;
cipher_suites.reserve(cipher_strings.size());
for (auto& cipher_string : cipher_strings) {
uint16 cipher_suite = 0;
if (!net::ParseSSLCipherString(cipher_string, &cipher_suite)) {
LOG(ERROR) << "Ignoring unrecognised cipher suite : "
<< cipher_string;
continue;
}
cipher_suites.push_back(cipher_suite);
}
return cipher_suites;
}
} // namespace
AtomSSLConfigService::AtomSSLConfigService() {
@ -35,6 +55,13 @@ AtomSSLConfigService::AtomSSLConfigService() {
cmd_line->GetSwitchValueASCII(switches::kSSLVersionFallbackMin);
config_.version_fallback_min = GetSSLProtocolVersion(version_string);
}
if (cmd_line->HasSwitch(switches::kCipherSuiteBlacklist)) {
auto cipher_strings = base::SplitString(
cmd_line->GetSwitchValueASCII(switches::kCipherSuiteBlacklist),
",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
config_.disabled_cipher_suites = ParseCipherSuites(cipher_strings);
}
}
AtomSSLConfigService::~AtomSSLConfigService() {

View file

@ -6,22 +6,25 @@
namespace auto_updater {
AutoUpdaterDelegate* AutoUpdater::delegate_ = NULL;
Delegate* AutoUpdater::delegate_ = nullptr;
AutoUpdaterDelegate* AutoUpdater::GetDelegate() {
Delegate* AutoUpdater::GetDelegate() {
return delegate_;
}
void AutoUpdater::SetDelegate(AutoUpdaterDelegate* delegate) {
void AutoUpdater::SetDelegate(Delegate* delegate) {
delegate_ = delegate;
}
#if defined(OS_MACOSX) && defined(MAS_BUILD)
#if !defined(OS_MACOSX) || defined(MAS_BUILD)
void AutoUpdater::SetFeedURL(const std::string& url) {
}
void AutoUpdater::CheckForUpdates() {
}
void AutoUpdater::QuitAndInstall() {
}
#endif
} // namespace auto_updater

View file

@ -9,21 +9,48 @@
#include "base/basictypes.h"
namespace base {
class Time;
}
namespace auto_updater {
class AutoUpdaterDelegate;
class Delegate {
public:
// An error happened.
virtual void OnError(const std::string& error) {}
// Checking to see if there is an update
virtual void OnCheckingForUpdate() {}
// There is an update available and it is being downloaded
virtual void OnUpdateAvailable() {}
// There is no available update.
virtual void OnUpdateNotAvailable() {}
// There is a new update which has been downloaded.
virtual void OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url) {}
protected:
virtual ~Delegate() {}
};
class AutoUpdater {
public:
// Gets/Sets the delegate.
static AutoUpdaterDelegate* GetDelegate();
static void SetDelegate(AutoUpdaterDelegate* delegate);
static Delegate* GetDelegate();
static void SetDelegate(Delegate* delegate);
static void SetFeedURL(const std::string& url);
static void CheckForUpdates();
static void QuitAndInstall();
private:
static AutoUpdaterDelegate* delegate_;
static Delegate* delegate_;
DISALLOW_IMPLICIT_CONSTRUCTORS(AutoUpdater);
};

View file

@ -1,45 +0,0 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_
#define ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_
#include <string>
#include "base/callback_forward.h"
namespace base {
class Time;
}
namespace auto_updater {
class AutoUpdaterDelegate {
public:
// An error happened.
virtual void OnError(const std::string& error) {}
// Checking to see if there is an update
virtual void OnCheckingForUpdate() {}
// There is an update available and it is being downloaded
virtual void OnUpdateAvailable() {}
// There is no available update.
virtual void OnUpdateNotAvailable() {}
// There is a new update which has been downloaded.
virtual void OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url,
const base::Closure& quit_and_install) {}
protected:
virtual ~AutoUpdaterDelegate() {}
};
} // namespace auto_updater
#endif // ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_

View file

@ -1,17 +0,0 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/auto_updater.h"
namespace auto_updater {
// static
void AutoUpdater::SetFeedURL(const std::string& url) {
}
// static
void AutoUpdater::CheckForUpdates() {
}
} // namespace auto_updater

View file

@ -12,9 +12,6 @@
#include "base/bind.h"
#include "base/time/time.h"
#include "base/strings/sys_string_conversions.h"
#include "atom/browser/auto_updater_delegate.h"
#include <iostream>
namespace auto_updater {
@ -23,20 +20,12 @@ namespace {
// The gloal SQRLUpdater object.
SQRLUpdater* g_updater = nil;
void RelaunchToInstallUpdate() {
[[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) {
AutoUpdaterDelegate* delegate = AutoUpdater::GetDelegate();
if (delegate)
delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription));
}];
}
} // namespace
// static
void AutoUpdater::SetFeedURL(const std::string& feed) {
if (g_updater == nil) {
AutoUpdaterDelegate* delegate = GetDelegate();
Delegate* delegate = GetDelegate();
if (!delegate)
return;
@ -67,7 +56,7 @@ void AutoUpdater::SetFeedURL(const std::string& feed) {
// static
void AutoUpdater::CheckForUpdates() {
AutoUpdaterDelegate* delegate = GetDelegate();
Delegate* delegate = GetDelegate();
if (!delegate)
return;
@ -86,8 +75,7 @@ void AutoUpdater::CheckForUpdates() {
base::SysNSStringToUTF8(update.releaseNotes),
base::SysNSStringToUTF8(update.releaseName),
base::Time::FromDoubleT(update.releaseDate.timeIntervalSince1970),
base::SysNSStringToUTF8(update.updateURL.absoluteString),
base::Bind(RelaunchToInstallUpdate));
base::SysNSStringToUTF8(update.updateURL.absoluteString));
} else {
// When the completed event is sent with no update, then we know there
// is no update available.
@ -100,4 +88,12 @@ void AutoUpdater::CheckForUpdates() {
}];
}
void AutoUpdater::QuitAndInstall() {
[[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) {
Delegate* delegate = AutoUpdater::GetDelegate();
if (delegate)
delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription));
}];
}
} // namespace auto_updater

View file

@ -1,17 +0,0 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/auto_updater.h"
namespace auto_updater {
// static
void AutoUpdater::SetFeedURL(const std::string& url) {
}
// static
void AutoUpdater::CheckForUpdates() {
}
} // namespace auto_updater

View file

@ -8,13 +8,33 @@
namespace atom {
// static
std::vector<BridgeTaskRunner::TaskPair> BridgeTaskRunner::tasks_;
std::vector<BridgeTaskRunner::TaskPair> BridgeTaskRunner::non_nestable_tasks_;
// static
void BridgeTaskRunner::MessageLoopIsReady() {
auto message_loop = base::MessageLoop::current();
CHECK(message_loop);
for (const TaskPair& task : tasks_) {
message_loop->task_runner()->PostDelayedTask(
base::get<0>(task), base::get<1>(task), base::get<2>(task));
}
for (const TaskPair& task : non_nestable_tasks_) {
message_loop->task_runner()->PostNonNestableDelayedTask(
base::get<0>(task), base::get<1>(task), base::get<2>(task));
}
}
bool BridgeTaskRunner::PostDelayedTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) {
auto message_loop = base::MessageLoop::current();
if (!message_loop)
return false;
if (!message_loop) {
tasks_.push_back(base::MakeTuple(from_here, task, delay));
return true;
}
return message_loop->task_runner()->PostDelayedTask(from_here, task, delay);
}
@ -22,7 +42,7 @@ bool BridgeTaskRunner::PostDelayedTask(
bool BridgeTaskRunner::RunsTasksOnCurrentThread() const {
auto message_loop = base::MessageLoop::current();
if (!message_loop)
return false;
return true;
return message_loop->task_runner()->RunsTasksOnCurrentThread();
}
@ -32,8 +52,10 @@ bool BridgeTaskRunner::PostNonNestableDelayedTask(
const base::Closure& task,
base::TimeDelta delay) {
auto message_loop = base::MessageLoop::current();
if (!message_loop)
return false;
if (!message_loop) {
non_nestable_tasks_.push_back(base::MakeTuple(from_here, task, delay));
return true;
}
return message_loop->task_runner()->PostNonNestableDelayedTask(
from_here, task, delay);

View file

@ -5,17 +5,23 @@
#ifndef ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
#define ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
#include <vector>
#include "base/single_thread_task_runner.h"
#include "base/tuple.h"
namespace atom {
// Post all tasks to the current message loop's task runner if available,
// otherwise fail silently.
// otherwise delay the work until message loop is ready.
class BridgeTaskRunner : public base::SingleThreadTaskRunner {
public:
BridgeTaskRunner() {}
~BridgeTaskRunner() override {}
// Called when message loop is ready.
static void MessageLoopIsReady();
// base::SingleThreadTaskRunner:
bool PostDelayedTask(const tracked_objects::Location& from_here,
const base::Closure& task,
@ -27,6 +33,11 @@ class BridgeTaskRunner : public base::SingleThreadTaskRunner {
base::TimeDelta delay) override;
private:
using TaskPair = base::Tuple<
tracked_objects::Location, base::Closure, base::TimeDelta>;
static std::vector<TaskPair> tasks_;
static std::vector<TaskPair> non_nestable_tasks_;
DISALLOW_COPY_AND_ASSIGN(BridgeTaskRunner);
};

View file

@ -53,8 +53,14 @@ void Browser::Shutdown() {
is_quiting_ = true;
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnQuit());
base::MessageLoop::current()->PostTask(
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
if (base::MessageLoop::current()) {
base::MessageLoop::current()->PostTask(
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
} else {
// There is no message loop available so we are in early stage.
exit(0);
}
}
std::string Browser::GetVersion() const {

View file

@ -130,6 +130,7 @@ class Browser : public WindowListObserver {
observers_.RemoveObserver(obs);
}
bool is_shutting_down() const { return is_shutdown_; }
bool is_quiting() const { return is_quiting_; }
bool is_ready() const { return is_ready_; }

View file

@ -4,6 +4,7 @@
#include "atom/browser/javascript_environment.h"
#include "base/command_line.h"
#include "gin/array_buffer.h"
#include "gin/v8_initializer.h"
@ -20,7 +21,12 @@ JavascriptEnvironment::JavascriptEnvironment()
}
bool JavascriptEnvironment::Initialize() {
gin::V8Initializer::LoadV8Snapshot();
auto cmd = base::CommandLine::ForCurrentProcess();
if (cmd->HasSwitch("debug-brk")) {
// Need to be called before v8::Initialize().
const char expose_debug_as[] = "--expose_debug_as=v8debug";
v8::V8::SetFlagsFromString(expose_debug_as, sizeof(expose_debug_as) - 1);
}
gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode,
gin::ArrayBufferAllocator::SharedInstance());
return true;

View file

@ -10,6 +10,8 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
meta.type = 'buffer' if Buffer.isBuffer value
meta.type = 'value' if value is null
meta.type = 'array' if Array.isArray value
meta.type = 'error' if value instanceof Error
meta.type = 'date' if value instanceof Date
meta.type = 'promise' if value? and value.constructor.name is 'Promise'
# Treat simple objects as value.
@ -36,6 +38,10 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
meta.value = Array::slice.call value, 0
else if meta.type is 'promise'
meta.then = valueToMeta(sender, value.then.bind(value))
else if meta.type is 'error'
meta.message = value.message
else if meta.type is 'date'
meta.value = value.getTime()
else
meta.type = 'value'
meta.value = value
@ -43,8 +49,8 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
meta
# Convert Error into meta data.
errorToMeta = (error) ->
type: 'error', message: error.message, stack: (error.stack || error)
exceptionToMeta = (error) ->
type: 'exception', message: error.message, stack: (error.stack || error)
# Convert array of meta data from renderer into array of real values.
unwrapArgs = (sender, args) ->
@ -100,19 +106,19 @@ ipc.on 'ATOM_BROWSER_REQUIRE', (event, module) ->
try
event.returnValue = valueToMeta event.sender, process.mainModule.require(module)
catch e
event.returnValue = errorToMeta e
event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_GLOBAL', (event, name) ->
try
event.returnValue = valueToMeta event.sender, global[name]
catch e
event.returnValue = errorToMeta e
event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event) ->
try
event.returnValue = valueToMeta event.sender, event.sender.getOwnerBrowserWindow()
catch e
event.returnValue = errorToMeta e
event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_CURRENT_WEB_CONTENTS', (event) ->
event.returnValue = valueToMeta event.sender, event.sender
@ -126,7 +132,7 @@ ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, id, args) ->
obj = new (Function::bind.apply(constructor, [null].concat(args)))
event.returnValue = valueToMeta event.sender, obj
catch e
event.returnValue = errorToMeta e
event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, id, args) ->
try
@ -134,7 +140,7 @@ ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, id, args) ->
func = objectsRegistry.get id
callFunction event, func, global, args
catch e
event.returnValue = errorToMeta e
event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) ->
try
@ -144,7 +150,7 @@ ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) ->
obj = new (Function::bind.apply(constructor, [null].concat(args)))
event.returnValue = valueToMeta event.sender, obj
catch e
event.returnValue = errorToMeta e
event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, id, method, args) ->
try
@ -152,7 +158,7 @@ ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, id, method, args) ->
obj = objectsRegistry.get id
callFunction event, obj[method], obj, args
catch e
event.returnValue = errorToMeta e
event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, id, name, value) ->
try
@ -160,14 +166,14 @@ ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, id, name, value) ->
obj[name] = value
event.returnValue = null
catch e
event.returnValue = errorToMeta e
event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, id, name) ->
try
obj = objectsRegistry.get id
event.returnValue = valueToMeta event.sender, obj[name]
catch e
event.returnValue = errorToMeta e
event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_DEREFERENCE', (event, id) ->
objectsRegistry.remove event.sender.getId(), id
@ -177,4 +183,4 @@ ipc.on 'ATOM_BROWSER_GUEST_WEB_CONTENTS', (event, guestInstanceId) ->
guestViewManager = require './guest-view-manager'
event.returnValue = valueToMeta event.sender, guestViewManager.getGuest(guestInstanceId)
catch e
event.returnValue = errorToMeta e
event.returnValue = exceptionToMeta e

View file

@ -43,26 +43,6 @@ DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::NativeWindowRelay);
namespace atom {
namespace {
// Convert draggable regions in raw format to SkRegion format. Caller is
// responsible for deleting the returned SkRegion instance.
scoped_ptr<SkRegion> DraggableRegionsToSkRegion(
const std::vector<DraggableRegion>& regions) {
scoped_ptr<SkRegion> sk_region(new SkRegion);
for (const DraggableRegion& region : regions) {
sk_region->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
return sk_region.Pass();
}
} // namespace
NativeWindow::NativeWindow(
brightray::InspectableWebContents* inspectable_web_contents,
const mate::Dictionary& options)
@ -159,6 +139,10 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
if (options.Get(switches::kKiosk, &kiosk) && kiosk) {
SetKiosk(kiosk);
}
std::string color;
if (options.Get(switches::kBackgroundColor, &color)) {
SetBackgroundColor(color);
}
std::string title("Electron");
options.Get(switches::kTitle, &title);
SetTitle(title);
@ -480,6 +464,28 @@ void NativeWindow::NotifyWindowExecuteWindowsCommand(
OnExecuteWindowsCommand(command));
}
#if defined(OS_WIN)
void NativeWindow::NotifyWindowMessage(UINT message, WPARAM w_param,
LPARAM l_param) {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
OnWindowMessage(message, w_param, l_param));
}
#endif
scoped_ptr<SkRegion> NativeWindow::DraggableRegionsToSkRegion(
const std::vector<DraggableRegion>& regions) {
scoped_ptr<SkRegion> sk_region(new SkRegion);
for (const DraggableRegion& region : regions) {
sk_region->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
return sk_region.Pass();
}
void NativeWindow::RenderViewCreated(
content::RenderViewHost* render_view_host) {
if (!transparent_)

View file

@ -134,6 +134,7 @@ class NativeWindow : public base::SupportsUserData,
virtual void SetSkipTaskbar(bool skip) = 0;
virtual void SetKiosk(bool kiosk) = 0;
virtual bool IsKiosk() = 0;
virtual void SetBackgroundColor(const std::string& color_name) = 0;
virtual void SetRepresentedFilename(const std::string& filename);
virtual std::string GetRepresentedFilename();
virtual void SetDocumentEdited(bool edited);
@ -209,6 +210,10 @@ class NativeWindow : public base::SupportsUserData,
void NotifyWindowLeaveHtmlFullScreen();
void NotifyWindowExecuteWindowsCommand(const std::string& command);
#if defined(OS_WIN)
void NotifyWindowMessage(UINT message, WPARAM w_param, LPARAM l_param);
#endif
void AddObserver(NativeWindowObserver* obs) {
observers_.AddObserver(obs);
}
@ -241,10 +246,19 @@ class NativeWindow : public base::SupportsUserData,
NativeWindow(brightray::InspectableWebContents* inspectable_web_contents,
const mate::Dictionary& options);
// Convert draggable regions in raw format to SkRegion format. Caller is
// responsible for deleting the returned SkRegion instance.
scoped_ptr<SkRegion> DraggableRegionsToSkRegion(
const std::vector<DraggableRegion>& regions);
// Converts between content size to window size.
virtual gfx::Size ContentSizeToWindowSize(const gfx::Size& size) = 0;
virtual gfx::Size WindowSizeToContentSize(const gfx::Size& size) = 0;
// Called when the window needs to update its draggable region.
virtual void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions);
// content::WebContentsObserver:
void RenderViewCreated(content::RenderViewHost* render_view_host) override;
void BeforeUnloadDialogCancelled() override;
@ -252,10 +266,6 @@ class NativeWindow : public base::SupportsUserData,
bool OnMessageReceived(const IPC::Message& message) override;
private:
// Called when the window needs to update its draggable region.
void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions);
// Schedule a notification unresponsive event.
void ScheduleUnresponsiveEvent(int ms);

View file

@ -57,6 +57,7 @@ class NativeWindowMac : public NativeWindow {
void SetSkipTaskbar(bool skip) override;
void SetKiosk(bool kiosk) override;
bool IsKiosk() override;
void SetBackgroundColor(const std::string& color_name) override;
void SetRepresentedFilename(const std::string& filename) override;
std::string GetRepresentedFilename() override;
void SetDocumentEdited(bool edited) override;
@ -71,12 +72,10 @@ class NativeWindowMac : public NativeWindow {
void SetVisibleOnAllWorkspaces(bool visible) override;
bool IsVisibleOnAllWorkspaces() override;
// Returns true if |point| in local Cocoa coordinate system falls within
// the draggable region.
bool IsWithinDraggableRegion(NSPoint point) const;
// Called to handle a mouse event.
void HandleMouseEvent(NSEvent* event);
// Refresh the DraggableRegion views.
void UpdateDraggableRegionViews() {
UpdateDraggableRegionViews(draggable_regions_);
}
protected:
// NativeWindow:
@ -84,17 +83,24 @@ class NativeWindowMac : public NativeWindow {
content::WebContents*,
const content::NativeWebKeyboardEvent&) override;
// Return a vector of non-draggable regions that fill a window of size
// |width| by |height|, but leave gaps where the window should be draggable.
std::vector<gfx::Rect> CalculateNonDraggableRegions(
const std::vector<DraggableRegion>& regions, int width, int height);
private:
// NativeWindow:
gfx::Size ContentSizeToWindowSize(const gfx::Size& size) override;
gfx::Size WindowSizeToContentSize(const gfx::Size& size) override;
void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) override;
void InstallView();
void UninstallView();
// Install the drag view, which will cover the whole window and decides
// whehter we can drag.
void InstallDraggableRegionView();
void UpdateDraggableRegionViews(const std::vector<DraggableRegion>& regions);
base::scoped_nsobject<AtomNSWindow> window_;
base::scoped_nsobject<AtomNSWindowDelegate> window_delegate_;
@ -102,6 +108,8 @@ class NativeWindowMac : public NativeWindow {
// The view that will fill the whole frameless window.
base::scoped_nsobject<FullSizeContentView> content_view_;
std::vector<DraggableRegion> draggable_regions_;
bool is_kiosk_;
NSInteger attention_request_id_; // identifier from requestUserAttention
@ -109,10 +117,6 @@ class NativeWindowMac : public NativeWindow {
// The presentation options before entering kiosk mode.
NSApplicationPresentationOptions kiosk_options_;
// Mouse location since the last mouse event, in screen coordinates. This is
// used in custom drag to compute the window movement.
NSPoint last_mouse_offset_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowMac);
};

View file

@ -19,6 +19,7 @@
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "native_mate/dictionary.h"
#include "ui/gfx/skia_util.h"
namespace {
@ -146,6 +147,7 @@ bool ScopedDisableResize::disable_resize_ = false;
}
- (void)windowDidResize:(NSNotification*)notification {
shell_->UpdateDraggableRegionViews();
shell_->NotifyWindowResize();
}
@ -257,43 +259,23 @@ bool ScopedDisableResize::disable_resize_ = false;
@end
@interface ControlRegionView : NSView {
@private
atom::NativeWindowMac* shellWindow_; // Weak; owns self.
}
@interface ControlRegionView : NSView
@end
@implementation ControlRegionView
- (id)initWithShellWindow:(atom::NativeWindowMac*)shellWindow {
if ((self = [super init]))
shellWindow_ = shellWindow;
return self;
}
- (BOOL)mouseDownCanMoveWindow {
return NO;
}
- (NSView*)hitTest:(NSPoint)aPoint {
if (!shellWindow_->IsWithinDraggableRegion(aPoint)) {
return nil;
}
return self;
return nil;
}
- (void)mouseDown:(NSEvent*)event {
shellWindow_->HandleMouseEvent(event);
}
- (void)mouseDragged:(NSEvent*)event {
shellWindow_->HandleMouseEvent(event);
}
- (BOOL)acceptsFirstMouse:(NSEvent*)event {
return YES;
}
@end
@interface NSView (WebContentsView)
- (void)setMouseDownCanMoveWindow:(BOOL)can_move;
@end
@interface AtomProgressBar : NSProgressIndicator
@ -439,11 +421,6 @@ NativeWindowMac::NativeWindowMac(
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
InstallView();
// Install the DraggableRegionView if it is forced to use draggable regions
// for normal window.
if (has_frame() && force_using_draggable_region())
InstallDraggableRegionView();
}
NativeWindowMac::~NativeWindowMac() {
@ -658,6 +635,9 @@ bool NativeWindowMac::IsKiosk() {
return is_kiosk_;
}
void NativeWindowMac::SetBackgroundColor(const std::string& color_name) {
}
void NativeWindowMac::SetRepresentedFilename(const std::string& filename) {
[window_ setRepresentedFilename:base::SysUTF8ToNSString(filename)];
}
@ -746,36 +726,6 @@ bool NativeWindowMac::IsVisibleOnAllWorkspaces() {
return collectionBehavior & NSWindowCollectionBehaviorCanJoinAllSpaces;
}
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
if (!draggable_region())
return false;
if (!web_contents())
return false;
NSView* webView = web_contents()->GetNativeView();
NSInteger webViewHeight = NSHeight([webView bounds]);
// |draggable_region_| is stored in local platform-indepdent coordiate system
// while |point| is in local Cocoa coordinate system. Do the conversion
// to match these two.
return draggable_region()->contains(point.x, webViewHeight - point.y);
}
void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
NSPoint eventLoc = [event locationInWindow];
NSRect mouseRect = [window_ convertRectToScreen:NSMakeRect(eventLoc.x, eventLoc.y, 0, 0)];
NSPoint current_mouse_location = mouseRect.origin;
if ([event type] == NSLeftMouseDown) {
NSPoint frame_origin = [window_ frame].origin;
last_mouse_offset_ = NSMakePoint(
frame_origin.x - current_mouse_location.x,
frame_origin.y - current_mouse_location.y);
} else if ([event type] == NSLeftMouseDragged) {
[window_ setFrameOrigin:NSMakePoint(
current_mouse_location.x + last_mouse_offset_.x,
current_mouse_location.y + last_mouse_offset_.y)];
}
}
void NativeWindowMac::HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent& event) {
@ -800,6 +750,23 @@ void NativeWindowMac::HandleKeyboardEvent(
}
}
std::vector<gfx::Rect> NativeWindowMac::CalculateNonDraggableRegions(
const std::vector<DraggableRegion>& regions, int width, int height) {
std::vector<gfx::Rect> result;
if (regions.empty()) {
result.push_back(gfx::Rect(0, 0, width, height));
} else {
scoped_ptr<SkRegion> draggable(DraggableRegionsToSkRegion(regions));
scoped_ptr<SkRegion> non_draggable(new SkRegion);
non_draggable->op(0, 0, width, height, SkRegion::kUnion_Op);
non_draggable->op(*draggable, SkRegion::kDifference_Op);
for (SkRegion::Iterator it(*non_draggable); !it.done(); it.next()) {
result.push_back(gfx::SkIRectToRect(it.rect()));
}
}
return result;
}
gfx::Size NativeWindowMac::ContentSizeToWindowSize(const gfx::Size& size) {
if (!has_frame())
return size;
@ -818,6 +785,13 @@ gfx::Size NativeWindowMac::WindowSizeToContentSize(const gfx::Size& size) {
return gfx::Size(content.size);
}
void NativeWindowMac::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
NativeWindow::UpdateDraggableRegions(regions);
draggable_regions_ = regions;
UpdateDraggableRegionViews(regions);
}
void NativeWindowMac::InstallView() {
// Make sure the bottom corner is rounded: http://crbug.com/396264.
[[window_ contentView] setWantsLayer:YES];
@ -840,8 +814,6 @@ void NativeWindowMac::InstallView() {
[view setFrame:[content_view_ bounds]];
[content_view_ addSubview:view];
InstallDraggableRegionView();
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES];
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES];
@ -858,14 +830,55 @@ void NativeWindowMac::UninstallView() {
[view removeFromSuperview];
}
void NativeWindowMac::InstallDraggableRegionView() {
void NativeWindowMac::UpdateDraggableRegionViews(
const std::vector<DraggableRegion>& regions) {
if (has_frame() && !force_using_draggable_region())
return;
// All ControlRegionViews should be added as children of the WebContentsView,
// because WebContentsView will be removed and re-added when entering and
// leaving fullscreen mode.
NSView* webView = web_contents()->GetNativeView();
base::scoped_nsobject<NSView> controlRegion(
[[ControlRegionView alloc] initWithShellWindow:this]);
[controlRegion setFrame:NSMakeRect(0, 0,
NSWidth([webView bounds]),
NSHeight([webView bounds]))];
[webView addSubview:controlRegion];
NSInteger webViewWidth = NSWidth([webView bounds]);
NSInteger webViewHeight = NSHeight([webView bounds]);
[webView setMouseDownCanMoveWindow:YES];
// Remove all ControlRegionViews that are added last time.
// Note that [webView subviews] returns the view's mutable internal array and
// it should be copied to avoid mutating the original array while enumerating
// it.
base::scoped_nsobject<NSArray> subviews([[webView subviews] copy]);
for (NSView* subview in subviews.get())
if ([subview isKindOfClass:[ControlRegionView class]])
[subview removeFromSuperview];
// Draggable regions is implemented by having the whole web view draggable
// (mouseDownCanMoveWindow) and overlaying regions that are not draggable.
std::vector<gfx::Rect> system_drag_exclude_areas =
CalculateNonDraggableRegions(regions, webViewWidth, webViewHeight);
// Create and add a ControlRegionView for each region that needs to be
// excluded from the dragging.
for (std::vector<gfx::Rect>::const_iterator iter =
system_drag_exclude_areas.begin();
iter != system_drag_exclude_areas.end();
++iter) {
base::scoped_nsobject<NSView> controlRegion(
[[ControlRegionView alloc] initWithFrame:NSZeroRect]);
[controlRegion setFrame:NSMakeRect(iter->x(),
webViewHeight - iter->bottom(),
iter->width(),
iter->height())];
[webView addSubview:controlRegion];
}
// AppKit will not update its cache of mouseDownCanMoveWindow unless something
// changes. Previously we tried adding an NSView and removing it, but for some
// reason it required reposting the mouse-down event, and didn't always work.
// Calling the below seems to be an effective solution.
[window_ setMovableByWindowBackground:NO];
[window_ setMovableByWindowBackground:YES];
}
// static

View file

@ -11,6 +11,10 @@
#include "ui/base/window_open_disposition.h"
#include "url/gurl.h"
#if defined(OS_WIN)
#include <windows.h>
#endif
namespace atom {
class NativeWindowObserver {
@ -55,6 +59,11 @@ class NativeWindowObserver {
virtual void OnWindowEnterHtmlFullScreen() {}
virtual void OnWindowLeaveHtmlFullScreen() {}
// Called when window message received
#if defined(OS_WIN)
virtual void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) {}
#endif
// Called when renderer is hung.
virtual void OnRendererUnresponsive() {}

View file

@ -42,6 +42,7 @@
#elif defined(OS_WIN)
#include "atom/browser/ui/views/win_frame_view.h"
#include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h"
#include "skia/ext/skia_utils_win.h"
#include "ui/base/win/shell.h"
#include "ui/gfx/win/dpi.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
@ -77,6 +78,29 @@ bool IsAltModifier(const content::NativeWebKeyboardEvent& event) {
(modifiers == (Modifiers::AltKey | Modifiers::IsRight));
}
SkColor ParseHexColor(const std::string& name) {
SkColor result = 0xFF000000;
unsigned value = 0;
auto color = name.substr(1);
unsigned length = color.size();
if (length != 3 && length != 6)
return result;
for (unsigned i = 0; i < length; ++i) {
if (!base::IsHexDigit(color[i]))
return result;
value <<= 4;
value |= (color[i] < 'A' ? color[i] - '0' : (color[i] - 'A' + 10) & 0xF);
}
if (length == 6) {
result |= value;
return result;
}
result |= (value & 0xF00) << 12 | (value & 0xF00) << 8
| (value & 0xF0) << 8 | (value & 0xF0) << 4
| (value & 0xF) << 4 | (value & 0xF);
return result;
}
class NativeWindowClientView : public views::ClientView {
public:
NativeWindowClientView(views::Widget* widget,
@ -205,7 +229,7 @@ NativeWindowViews::NativeWindowViews(
// Add web view.
SetLayoutManager(new MenuLayout(this, kMenuBarHeight));
set_background(views::Background::CreateStandardPanelBackground());
AddChildView(web_view_);
#if defined(OS_WIN)
@ -496,6 +520,21 @@ bool NativeWindowViews::IsKiosk() {
return IsFullscreen();
}
void NativeWindowViews::SetBackgroundColor(const std::string& color_name) {
// web views' background color.
SkColor background_color = ParseHexColor(color_name);
set_background(views::Background::CreateSolidBackground(background_color));
#if defined(OS_WIN)
// Set the background color of native window.
HBRUSH brush = CreateSolidBrush(skia::SkColorToCOLORREF(background_color));
ULONG_PTR previous_brush = SetClassLongPtr(
GetAcceleratedWidget(), GCLP_HBRBACKGROUND, (LONG)brush);
if (previous_brush)
DeleteObject((HBRUSH)previous_brush);
#endif
}
void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
if (menu_model == nullptr) {
// Remove accelerators

View file

@ -77,6 +77,7 @@ class NativeWindowViews : public NativeWindow,
void SetSkipTaskbar(bool skip) override;
void SetKiosk(bool kiosk) override;
bool IsKiosk() override;
void SetBackgroundColor(const std::string& color_name) override;
void SetMenu(ui::MenuModel* menu_model) override;
gfx::NativeWindow GetNativeWindow() override;
void SetOverlayIcon(const gfx::Image& overlay,

View file

@ -80,6 +80,8 @@ bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
bool NativeWindowViews::PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) {
NotifyWindowMessage(message, w_param, l_param);
switch (message) {
case WM_COMMAND:
// Handle thumbar button click message.

View file

@ -35,17 +35,14 @@ NodeDebugger::NodeDebugger(v8::Isolate* isolate)
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")) {
} else if (cmd->HasSwitch("debug-brk")) {
use_debug_agent = true;
wait_for_connection = true;
port_str = cmd->GetSwitchValueASCII("debug-brk");
}
@ -56,9 +53,6 @@ NodeDebugger::NodeDebugger(v8::Isolate* isolate)
isolate_->SetData(kIsolateSlot, this);
v8::Debug::SetMessageHandler(DebugMessageHandler);
if (wait_for_connection)
v8::Debug::DebugBreak(isolate_);
uv_async_init(uv_default_loop(), &weak_up_ui_handle_, ProcessMessageInUI);
// Start a new IO thread.

View file

@ -17,9 +17,9 @@
<key>CFBundleIconFile</key>
<string>atom.icns</string>
<key>CFBundleVersion</key>
<string>0.34.0</string>
<string>0.34.1</string>
<key>CFBundleShortVersionString</key>
<string>0.34.0</string>
<string>0.34.1</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,34,0,0
PRODUCTVERSION 0,34,0,0
FILEVERSION 0,34,1,0
PRODUCTVERSION 0,34,1,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -74,12 +74,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
VALUE "FileVersion", "0.34.0"
VALUE "FileVersion", "0.34.1"
VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron"
VALUE "ProductVersion", "0.34.0"
VALUE "ProductVersion", "0.34.1"
VALUE "SquirrelAwareVersion", "1"
END
END

View file

@ -79,8 +79,25 @@ class FileDialog {
if (!title.empty())
GetPtr()->SetTitle(base::UTF8ToUTF16(title).c_str());
if (!filterspec.empty())
GetPtr()->SetDefaultExtension(filterspec.front().pszSpec);
// By default, *.* will be added to the file name if file type is "*.*". In
// Electron, we disable it to make a better experience.
//
// From MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/
// bb775970(v=vs.85).aspx
//
// If SetDefaultExtension is not called, the dialog will not update
// automatically when user choose a new file type in the file dialog.
//
// We set file extension to the first none-wildcard extension to make
// sure the dialog will update file extension automatically.
for (size_t i = 0; i < filterspec.size(); ++i) {
if (std::wstring(filterspec[i].pszSpec) != L"*.*") {
// SetFileTypeIndex is regarded as one-based index.
GetPtr()->SetFileTypeIndex(i+1);
GetPtr()->SetDefaultExtension(filterspec[i].pszSpec);
break;
}
}
SetDefaultFolder(default_path);
}
@ -255,7 +272,8 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
bool matched = false;
for (size_t i = 0; i < filter.second.size(); ++i) {
if (base::EndsWith(file_name, filter.second[i], false)) {
if (filter.second[i] == "*" ||
base::EndsWith(file_name, filter.second[i], false)) {
matched = true;
break;;
}

View file

@ -55,7 +55,7 @@ void TrayIcon::NotifyRightClicked(const gfx::Rect& bounds, int modifiers) {
OnRightClicked(bounds, modifiers));
}
void TrayIcon::NotfiyDropFiles(const std::vector<std::string>& files) {
void TrayIcon::NotifyDropFiles(const std::vector<std::string>& files) {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDropFiles(files));
}

View file

@ -61,7 +61,7 @@ class TrayIcon {
void NotifyBalloonClosed();
void NotifyRightClicked(const gfx::Rect& bounds = gfx::Rect(),
int modifiers = 0);
void NotfiyDropFiles(const std::vector<std::string>& files);
void NotifyDropFiles(const std::vector<std::string>& files);
protected:
TrayIcon();

View file

@ -265,7 +265,7 @@ const CGFloat kVerticalTitleMargin = 2;
NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
for (NSString* file in files)
dropFiles.push_back(base::SysNSStringToUTF8(file));
trayIcon_->NotfiyDropFiles(dropFiles);
trayIcon_->NotifyDropFiles(dropFiles);
return YES;
}
return NO;

View file

@ -41,7 +41,7 @@ void FatalErrorCallback(const char* location, const char* message) {
}
void Log(const base::string16& message) {
std::cout << message;
std::cout << message << std::flush;
}
} // namespace

View file

@ -1,4 +1,5 @@
module.exports = process.atomBinding 'shell'
if process.platform is 'win32' and process.type is 'renderer'
module.exports.showItemInFolder = require('remote').process.atomBinding('shell').showItemInFolder
module.exports.showItemInFolder = (item) ->
require('remote').require('shell').showItemInFolder item

View file

@ -7,7 +7,7 @@
#define ATOM_MAJOR_VERSION 0
#define ATOM_MINOR_VERSION 34
#define ATOM_PATCH_VERSION 0
#define ATOM_PATCH_VERSION 1
#define ATOM_VERSION_IS_RELEASE 1

View file

@ -263,7 +263,9 @@ exports.wrapFsWithAsar = (fs) ->
info = archive.getFileInfo filePath
notFoundError asarPath, filePath unless info
return new Buffer(0) if info.size is 0
if info.size is 0
return if options then '' else new Buffer(0)
if info.unpacked
realPath = archive.copyFileOut filePath

View file

@ -70,10 +70,13 @@ struct V8FunctionInvoker<ReturnType(ArgTypes...)> {
v8::Local<v8::Function> holder = function->NewHandle();
v8::Local<v8::Context> context = holder->CreationContext();
v8::Context::Scope context_scope(context);
ReturnType ret;
ReturnType ret = ReturnType();
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
v8::Local<v8::Value> val(holder->Call(holder, args.size(), &args.front()));
Converter<ReturnType>::FromV8(isolate, val, &ret);
v8::Local<v8::Value> result;
auto maybe_result =
holder->Call(context, holder, args.size(), &args.front());
if (maybe_result.ToLocal(&result))
Converter<ReturnType>::FromV8(isolate, result, &ret);
return ret;
}
};

View file

@ -93,6 +93,9 @@ const char kDisableAutoHideCursor[] = "disable-auto-hide-cursor";
// Use the OS X's standard window instead of the textured window.
const char kStandardWindow[] = "standard-window";
// Default browser window background color.
const char kBackgroundColor[] = "background-color";
// Path to client certificate.
const char kClientCertificate[] = "client-certificate";
@ -116,6 +119,9 @@ const char kRegisterStandardSchemes[] = "register-standard-schemes";
// TLS fallback will accept.
const char kSSLVersionFallbackMin[] = "ssl-version-fallback-min";
// Comma-separated list of SSL cipher suites to disable.
const char kCipherSuiteBlacklist[] = "cipher-suite-blacklist";
// The browser process app model ID
const char kAppUserModelId[] = "app-user-model-id";

View file

@ -47,6 +47,7 @@ extern const char kTransparent[];
extern const char kType[];
extern const char kDisableAutoHideCursor[];
extern const char kStandardWindow[];
extern const char kBackgroundColor[];
extern const char kClientCertificate[];
extern const char kExperimentalFeatures[];
@ -59,6 +60,7 @@ extern const char kPageVisibility[];
extern const char kDisableHttpCache[];
extern const char kRegisterStandardSchemes[];
extern const char kSSLVersionFallbackMin[];
extern const char kCipherSuiteBlacklist[];
extern const char kAppUserModelId[];

View file

@ -46,7 +46,9 @@ metaToValue = (meta) ->
when 'array' then (metaToValue(el) for el in meta.members)
when 'buffer' then new Buffer(meta.value)
when 'promise' then Promise.resolve(then: metaToValue(meta.then))
when 'error'
when 'error' then new Error(meta.message)
when 'date' then new Date(meta.value)
when 'exception'
throw new Error("#{meta.message}\n#{meta.stack}")
else
if meta.type is 'function'

View file

@ -0,0 +1,86 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chrome_process_finder_win.h"
#include <shellapi.h>
#include <string>
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/process/process.h"
#include "base/process/process_info.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/message_window.h"
#include "base/win/scoped_handle.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
namespace {
int timeout_in_milliseconds = 20 * 1000;
} // namespace
namespace chrome {
HWND FindRunningChromeWindow(const base::FilePath& user_data_dir) {
return base::win::MessageWindow::FindWindow(user_data_dir.value());
}
NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window,
bool fast_start) {
DCHECK(remote_window);
DWORD process_id = 0;
DWORD thread_id = GetWindowThreadProcessId(remote_window, &process_id);
if (!thread_id || !process_id)
return NOTIFY_FAILED;
// Send the command line to the remote chrome window.
// Format is "START\0<<<current directory>>>\0<<<commandline>>>".
std::wstring to_send(L"START\0", 6); // want the NULL in the string.
base::FilePath cur_dir;
if (!base::GetCurrentDirectory(&cur_dir))
return NOTIFY_FAILED;
to_send.append(cur_dir.value());
to_send.append(L"\0", 1); // Null separator.
to_send.append(::GetCommandLineW());
to_send.append(L"\0", 1); // Null separator.
// Allow the current running browser window to make itself the foreground
// window (otherwise it will just flash in the taskbar).
::AllowSetForegroundWindow(process_id);
COPYDATASTRUCT cds;
cds.dwData = 0;
cds.cbData = static_cast<DWORD>((to_send.length() + 1) * sizeof(wchar_t));
cds.lpData = const_cast<wchar_t*>(to_send.c_str());
DWORD_PTR result = 0;
if (::SendMessageTimeout(remote_window, WM_COPYDATA, NULL,
reinterpret_cast<LPARAM>(&cds), SMTO_ABORTIFHUNG,
timeout_in_milliseconds, &result)) {
return result ? NOTIFY_SUCCESS : NOTIFY_FAILED;
}
// It is possible that the process owning this window may have died by now.
if (!::IsWindow(remote_window))
return NOTIFY_FAILED;
// If the window couldn't be notified but still exists, assume it is hung.
return NOTIFY_WINDOW_HUNG;
}
base::TimeDelta SetNotificationTimeoutForTesting(base::TimeDelta new_timeout) {
base::TimeDelta old_timeout =
base::TimeDelta::FromMilliseconds(timeout_in_milliseconds);
timeout_in_milliseconds = new_timeout.InMilliseconds();
return old_timeout;
}
} // namespace chrome

View file

@ -0,0 +1,39 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROME_PROCESS_FINDER_WIN_H_
#define CHROME_BROWSER_CHROME_PROCESS_FINDER_WIN_H_
#include <windows.h>
#include "base/time/time.h"
namespace base {
class FilePath;
}
namespace chrome {
enum NotifyChromeResult {
NOTIFY_SUCCESS,
NOTIFY_FAILED,
NOTIFY_WINDOW_HUNG,
};
// Finds an already running Chrome window if it exists.
HWND FindRunningChromeWindow(const base::FilePath& user_data_dir);
// Attempts to send the current command line to an already running instance of
// Chrome via a WM_COPYDATA message.
// Returns true if a running Chrome is found and successfully notified.
// |fast_start| is true when this is being called on the window fast start path.
NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window,
bool fast_start);
// Changes the notification timeout to |new_timeout|, returns the old timeout.
base::TimeDelta SetNotificationTimeoutForTesting(base::TimeDelta new_timeout);
} // namespace chrome
#endif // CHROME_BROWSER_CHROME_PROCESS_FINDER_WIN_H_

View file

@ -0,0 +1,182 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PROCESS_SINGLETON_H_
#define CHROME_BROWSER_PROCESS_SINGLETON_H_
#if defined(OS_WIN)
#include <windows.h>
#endif // defined(OS_WIN)
#include <set>
#include <vector>
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/process/process.h"
#include "base/threading/non_thread_safe.h"
#include "ui/gfx/native_widget_types.h"
#if defined(OS_POSIX) && !defined(OS_ANDROID)
#include "base/files/scoped_temp_dir.h"
#endif
#if defined(OS_WIN)
#include "base/win/message_window.h"
#endif // defined(OS_WIN)
namespace base {
class CommandLine;
}
// ProcessSingleton ----------------------------------------------------------
//
// This class allows different browser processes to communicate with
// each other. It is named according to the user data directory, so
// we can be sure that no more than one copy of the application can be
// running at once with a given data directory.
//
// Implementation notes:
// - the Windows implementation uses an invisible global message window;
// - the Linux implementation uses a Unix domain socket in the user data dir.
class ProcessSingleton : public base::NonThreadSafe {
public:
enum NotifyResult {
PROCESS_NONE,
PROCESS_NOTIFIED,
PROFILE_IN_USE,
LOCK_ERROR,
};
// Implement this callback to handle notifications from other processes. The
// callback will receive the command line and directory with which the other
// Chrome process was launched. Return true if the command line will be
// handled within the current browser instance or false if the remote process
// should handle it (i.e., because the current process is shutting down).
using NotificationCallback =
base::Callback<bool(const base::CommandLine::StringVector& command_line,
const base::FilePath& current_directory)>;
ProcessSingleton(const base::FilePath& user_data_dir,
const NotificationCallback& notification_callback);
~ProcessSingleton();
// Notify another process, if available. Otherwise sets ourselves as the
// singleton instance. Returns PROCESS_NONE if we became the singleton
// instance. Callers are guaranteed to either have notified an existing
// process or have grabbed the singleton (unless the profile is locked by an
// unreachable process).
// TODO(brettw): Make the implementation of this method non-platform-specific
// by making Linux re-use the Windows implementation.
NotifyResult NotifyOtherProcessOrCreate();
// Sets ourself up as the singleton instance. Returns true on success. If
// false is returned, we are not the singleton instance and the caller must
// exit.
// NOTE: Most callers should generally prefer NotifyOtherProcessOrCreate() to
// this method, only callers for whom failure is preferred to notifying
// another process should call this directly.
bool Create();
// Clear any lock state during shutdown.
void Cleanup();
#if defined(OS_POSIX) && !defined(OS_ANDROID)
static void DisablePromptForTesting();
#endif
#if defined(OS_WIN)
// Called to query whether to kill a hung browser process that has visible
// windows. Return true to allow killing the hung process.
using ShouldKillRemoteProcessCallback = base::Callback<bool()>;
void OverrideShouldKillRemoteProcessCallbackForTesting(
const ShouldKillRemoteProcessCallback& display_dialog_callback);
#endif
protected:
// Notify another process, if available.
// Returns true if another process was found and notified, false if we should
// continue with the current process.
// On Windows, Create() has to be called before this.
NotifyResult NotifyOtherProcess();
#if defined(OS_POSIX) && !defined(OS_ANDROID)
// Exposed for testing. We use a timeout on Linux, and in tests we want
// this timeout to be short.
NotifyResult NotifyOtherProcessWithTimeout(
const base::CommandLine& command_line,
int retry_attempts,
const base::TimeDelta& timeout,
bool kill_unresponsive);
NotifyResult NotifyOtherProcessWithTimeoutOrCreate(
const base::CommandLine& command_line,
int retry_attempts,
const base::TimeDelta& timeout);
void OverrideCurrentPidForTesting(base::ProcessId pid);
void OverrideKillCallbackForTesting(
const base::Callback<void(int)>& callback);
#endif
private:
NotificationCallback notification_callback_; // Handler for notifications.
#if defined(OS_WIN)
HWND remote_window_; // The HWND_MESSAGE of another browser.
base::win::MessageWindow window_; // The message-only window.
bool is_virtualized_; // Stuck inside Microsoft Softricity VM environment.
HANDLE lock_file_;
base::FilePath user_data_dir_;
ShouldKillRemoteProcessCallback should_kill_remote_process_callback_;
#elif defined(OS_POSIX) && !defined(OS_ANDROID)
// Start listening to the socket.
void StartListening(int sock);
// Return true if the given pid is one of our child processes.
// Assumes that the current pid is the root of all pids of the current
// instance.
bool IsSameChromeInstance(pid_t pid);
// Extract the process's pid from a symbol link path and if it is on
// the same host, kill the process, unlink the lock file and return true.
// If the process is part of the same chrome instance, unlink the lock file
// and return true without killing it.
// If the process is on a different host, return false.
bool KillProcessByLockPath();
// Default function to kill a process, overridable by tests.
void KillProcess(int pid);
// Allow overriding for tests.
base::ProcessId current_pid_;
// Function to call when the other process is hung and needs to be killed.
// Allows overriding for tests.
base::Callback<void(int)> kill_callback_;
// Path in file system to the socket.
base::FilePath socket_path_;
// Path in file system to the lock.
base::FilePath lock_path_;
// Path in file system to the cookie file.
base::FilePath cookie_path_;
// Temporary directory to hold the socket.
base::ScopedTempDir socket_dir_;
// Helper class for linux specific messages. LinuxWatcher is ref counted
// because it posts messages between threads.
class LinuxWatcher;
scoped_refptr<LinuxWatcher> watcher_;
#endif
DISALLOW_COPY_AND_ASSIGN(ProcessSingleton);
};
#endif // CHROME_BROWSER_PROCESS_SINGLETON_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,328 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/process_singleton.h"
#include <shellapi.h>
#include "base/base_paths.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/process/process.h"
#include "base/process/process_info.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/win/metro.h"
#include "base/win/registry.h"
#include "base/win/scoped_handle.h"
#include "base/win/windows_version.h"
#include "chrome/browser/chrome_process_finder_win.h"
#include "content/public/common/result_codes.h"
#include "net/base/escape.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/win/hwnd_util.h"
namespace {
const char kLockfile[] = "lockfile";
// A helper class that acquires the given |mutex| while the AutoLockMutex is in
// scope.
class AutoLockMutex {
public:
explicit AutoLockMutex(HANDLE mutex) : mutex_(mutex) {
DWORD result = ::WaitForSingleObject(mutex_, INFINITE);
DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result;
}
~AutoLockMutex() {
BOOL released = ::ReleaseMutex(mutex_);
DPCHECK(released);
}
private:
HANDLE mutex_;
DISALLOW_COPY_AND_ASSIGN(AutoLockMutex);
};
// A helper class that releases the given |mutex| while the AutoUnlockMutex is
// in scope and immediately re-acquires it when going out of scope.
class AutoUnlockMutex {
public:
explicit AutoUnlockMutex(HANDLE mutex) : mutex_(mutex) {
BOOL released = ::ReleaseMutex(mutex_);
DPCHECK(released);
}
~AutoUnlockMutex() {
DWORD result = ::WaitForSingleObject(mutex_, INFINITE);
DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result;
}
private:
HANDLE mutex_;
DISALLOW_COPY_AND_ASSIGN(AutoUnlockMutex);
};
// Checks the visibility of the enumerated window and signals once a visible
// window has been found.
BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) {
bool* result = reinterpret_cast<bool*>(param);
*result = ::IsWindowVisible(window) != 0;
// Stops enumeration if a visible window has been found.
return !*result;
}
// Convert Command line string to argv.
base::CommandLine::StringVector CommandLineStringToArgv(
const std::wstring& command_line_string) {
int num_args = 0;
wchar_t** args = NULL;
args = ::CommandLineToArgvW(command_line_string.c_str(), &num_args);
base::CommandLine::StringVector argv;
for (int i = 0; i < num_args; ++i)
argv.push_back(std::wstring(args[i]));
LocalFree(args);
return argv;
}
bool ParseCommandLine(const COPYDATASTRUCT* cds,
base::CommandLine::StringVector* parsed_command_line,
base::FilePath* current_directory) {
// We should have enough room for the shortest command (min_message_size)
// and also be a multiple of wchar_t bytes. The shortest command
// possible is L"START\0\0" (empty current directory and command line).
static const int min_message_size = 7;
if (cds->cbData < min_message_size * sizeof(wchar_t) ||
cds->cbData % sizeof(wchar_t) != 0) {
LOG(WARNING) << "Invalid WM_COPYDATA, length = " << cds->cbData;
return false;
}
// We split the string into 4 parts on NULLs.
DCHECK(cds->lpData);
const std::wstring msg(static_cast<wchar_t*>(cds->lpData),
cds->cbData / sizeof(wchar_t));
const std::wstring::size_type first_null = msg.find_first_of(L'\0');
if (first_null == 0 || first_null == std::wstring::npos) {
// no NULL byte, don't know what to do
LOG(WARNING) << "Invalid WM_COPYDATA, length = " << msg.length() <<
", first null = " << first_null;
return false;
}
// Decode the command, which is everything until the first NULL.
if (msg.substr(0, first_null) == L"START") {
// Another instance is starting parse the command line & do what it would
// have done.
VLOG(1) << "Handling STARTUP request from another process";
const std::wstring::size_type second_null =
msg.find_first_of(L'\0', first_null + 1);
if (second_null == std::wstring::npos ||
first_null == msg.length() - 1 || second_null == msg.length()) {
LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
"parts separated by NULLs";
return false;
}
// Get current directory.
*current_directory = base::FilePath(msg.substr(first_null + 1,
second_null - first_null));
const std::wstring::size_type third_null =
msg.find_first_of(L'\0', second_null + 1);
if (third_null == std::wstring::npos ||
third_null == msg.length()) {
LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
"parts separated by NULLs";
}
// Get command line.
const std::wstring cmd_line =
msg.substr(second_null + 1, third_null - second_null);
*parsed_command_line = CommandLineStringToArgv(cmd_line);
return true;
}
return false;
}
bool ProcessLaunchNotification(
const ProcessSingleton::NotificationCallback& notification_callback,
UINT message,
WPARAM wparam,
LPARAM lparam,
LRESULT* result) {
if (message != WM_COPYDATA)
return false;
// Handle the WM_COPYDATA message from another process.
const COPYDATASTRUCT* cds = reinterpret_cast<COPYDATASTRUCT*>(lparam);
base::CommandLine::StringVector parsed_command_line;
base::FilePath current_directory;
if (!ParseCommandLine(cds, &parsed_command_line, &current_directory)) {
*result = TRUE;
return true;
}
*result = notification_callback.Run(parsed_command_line, current_directory) ?
TRUE : FALSE;
return true;
}
bool TerminateAppWithError() {
// TODO: This is called when the secondary process can't ping the primary
// process. Need to find out what to do here.
return false;
}
} // namespace
ProcessSingleton::ProcessSingleton(
const base::FilePath& user_data_dir,
const NotificationCallback& notification_callback)
: notification_callback_(notification_callback),
is_virtualized_(false),
lock_file_(INVALID_HANDLE_VALUE),
user_data_dir_(user_data_dir),
should_kill_remote_process_callback_(
base::Bind(&TerminateAppWithError)) {
}
ProcessSingleton::~ProcessSingleton() {
if (lock_file_ != INVALID_HANDLE_VALUE)
::CloseHandle(lock_file_);
}
// Code roughly based on Mozilla.
ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
if (is_virtualized_)
return PROCESS_NOTIFIED; // We already spawned the process in this case.
if (lock_file_ == INVALID_HANDLE_VALUE && !remote_window_) {
return LOCK_ERROR;
} else if (!remote_window_) {
return PROCESS_NONE;
}
switch (chrome::AttemptToNotifyRunningChrome(remote_window_, false)) {
case chrome::NOTIFY_SUCCESS:
return PROCESS_NOTIFIED;
case chrome::NOTIFY_FAILED:
remote_window_ = NULL;
return PROCESS_NONE;
case chrome::NOTIFY_WINDOW_HUNG:
// Fall through and potentially terminate the hung browser.
break;
}
DWORD process_id = 0;
DWORD thread_id = ::GetWindowThreadProcessId(remote_window_, &process_id);
if (!thread_id || !process_id) {
remote_window_ = NULL;
return PROCESS_NONE;
}
base::Process process = base::Process::Open(process_id);
// The window is hung. Scan for every window to find a visible one.
bool visible_window = false;
::EnumThreadWindows(thread_id,
&BrowserWindowEnumeration,
reinterpret_cast<LPARAM>(&visible_window));
// If there is a visible browser window, ask the user before killing it.
if (visible_window && !should_kill_remote_process_callback_.Run()) {
// The user denied. Quit silently.
return PROCESS_NOTIFIED;
}
// Time to take action. Kill the browser process.
process.Terminate(content::RESULT_CODE_HUNG, true);
remote_window_ = NULL;
return PROCESS_NONE;
}
ProcessSingleton::NotifyResult
ProcessSingleton::NotifyOtherProcessOrCreate() {
ProcessSingleton::NotifyResult result = PROCESS_NONE;
if (!Create()) {
result = NotifyOtherProcess();
if (result == PROCESS_NONE)
result = PROFILE_IN_USE;
}
return result;
}
// Look for a Chrome instance that uses the same profile directory. If there
// isn't one, create a message window with its title set to the profile
// directory path.
bool ProcessSingleton::Create() {
static const wchar_t kMutexName[] = L"Local\\AtomProcessSingletonStartup!";
remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
if (!remote_window_) {
// Make sure we will be the one and only process creating the window.
// We use a named Mutex since we are protecting against multi-process
// access. As documented, it's clearer to NOT request ownership on creation
// since it isn't guaranteed we will get it. It is better to create it
// without ownership and explicitly get the ownership afterward.
base::win::ScopedHandle only_me(::CreateMutex(NULL, FALSE, kMutexName));
if (!only_me.IsValid()) {
DPLOG(FATAL) << "CreateMutex failed";
return false;
}
AutoLockMutex auto_lock_only_me(only_me.Get());
// We now own the mutex so we are the only process that can create the
// window at this time, but we must still check if someone created it
// between the time where we looked for it above and the time the mutex
// was given to us.
remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
if (!remote_window_) {
// We have to make sure there is no Chrome instance running on another
// machine that uses the same profile.
base::FilePath lock_file_path = user_data_dir_.AppendASCII(kLockfile);
lock_file_ = ::CreateFile(lock_file_path.value().c_str(),
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_DELETE_ON_CLOSE,
NULL);
DWORD error = ::GetLastError();
LOG_IF(WARNING, lock_file_ != INVALID_HANDLE_VALUE &&
error == ERROR_ALREADY_EXISTS) << "Lock file exists but is writable.";
LOG_IF(ERROR, lock_file_ == INVALID_HANDLE_VALUE)
<< "Lock file can not be created! Error code: " << error;
if (lock_file_ != INVALID_HANDLE_VALUE) {
// Set the window's title to the path of our user data directory so
// other Chrome instances can decide if they should forward to us.
bool result = window_.CreateNamed(
base::Bind(&ProcessLaunchNotification, notification_callback_),
user_data_dir_.value());
// NB: Ensure that if the primary app gets started as elevated
// admin inadvertently, secondary windows running not as elevated
// will still be able to send messages
::ChangeWindowMessageFilterEx(window_.hwnd(), WM_COPYDATA, MSGFLT_ALLOW, NULL);
CHECK(result && window_.hwnd());
}
}
}
return window_.hwnd() != NULL;
}
void ProcessSingleton::Cleanup() {
}
void ProcessSingleton::OverrideShouldKillRemoteProcessCallbackForTesting(
const ShouldKillRemoteProcessCallback& display_dialog_callback) {
should_kill_remote_process_callback_ = display_dialog_callback;
}

View file

@ -1,8 +1,8 @@
## Guías
* [Platfaformas Soportadas](tutorial/supported-platforms.md)
* [Distribución de la Aplicacion](tutorial/application-distribution.md)
* [Empaquetamiento de la Aplicacion](tutorial/application-packaging.md)
* [Plataformas Soportadas](tutorial/supported-platforms.md)
* [Distribución de la Aplicación](tutorial/application-distribution.md)
* [Empaquetamiento de la Aplicación](tutorial/application-packaging.md)
* [Utilizando Módulos Node Nativos](tutorial/using-native-node-modules.md)
* [Depurando el Proceso Principal](tutorial/debugging-main-process.md)
* [Utilizando Selenium y WebDriver](tutorial/using-selenium-and-webdriver.md)
@ -62,7 +62,7 @@
## Desarrollo
* [Guía de Estilo](development/coding-style.md)
* [Estructura de los directorios del Código Fuente](../../development/source-code-directory-structure.md)
* [Estructura de los directorios del Código Fuente](development/source-code-directory-structure.md)
* [Diferencias Técnicas con NW.js (anteriormente conocido como node-webkit)](../../development/atom-shell-vs-node-webkit.md)
* [Repaso del Sistema de Compilación](../../development/build-system-overview.md)
* [Instrucciones de Compilación (Mac)](../../development/build-instructions-osx.md)

View file

@ -1,9 +1,9 @@
# Parámetros CLI soportados (Chrome)
Esta página lista las líneas de comandos usadas por el navegador Chrome que también son
Esta página lista las líneas de comandos usadas por el navegador Chrome que también son
soportadas por Electron. Puedes usar [app.commandLine.appendSwitch][append-switch] para
anexarlas en el script principal de tu aplicación antes de que el evento [ready][ready] del
modulo [app][app] sea emitido:
módulo [app][app] sea emitido:
```javascript
var app = require('app');
@ -25,7 +25,7 @@ Ignora el límite de conexiones para la lista de `domains` separados por `,`.
## --disable-http-cache
Deshabilita la cacheé del disco para las peticiones HTTP.
Deshabilita la caché del disco para las peticiones HTTP.
## --remote-debugging-port=`port`
@ -42,7 +42,7 @@ Utiliza el script PAC en la `url` especificada.
## --no-proxy-server
No usa un servidor proxy y siempre establece conexiones directas. Anula cualquier
No usa un servidor proxy y siempre establece conexiones directas. Anula cualquier
otra bandera de servidor proxy bandera que se pase.
## --host-rules=`rules`
@ -55,12 +55,12 @@ Por ejemplo:
* `MAP * 127.0.0.1` Obliga a todos los nombres de host a ser asignados a 127.0.0.1
* `MAP *.google.com proxy` Obliga todos los subdominios google.com a resolverse con
"proxy".
* `MAP test.com [::1]:77` Obliga a resolver "test.com" con un bucle invertido de IPv6.
* `MAP test.com [::1]:77` Obliga a resolver "test.com" con un bucle invertido de IPv6.
También obligará a que el puerto de la dirección respuesta sea 77.
* `MAP * baz, EXCLUDE www.google.com` Reasigna todo a "baz", excepto a "www.google.com".
Estas asignaciones especifican el host final en una petición de red (Anfitrión de la conexión TCP
y de resolución de conexión directa, y el `CONNECT` en una conexión proxy HTTP, y el host final de
y de resolución de conexión directa, y el `CONNECT` en una conexión proxy HTTP, y el host final de
la conexión proxy `SOCKS`).
## --host-resolver-rules=`rules`
@ -89,30 +89,30 @@ Permite guardar y escribir eventos de registros de red en `path`.
## --ssl-version-fallback-min=`version`
Establece la versión mínima de SSL/TLS ("tls1", "tls1.1" o "tls1.2") que
Establece la versión mínima de SSL/TLS ("tls1", "tls1.1" o "tls1.2") que
el repliegue de TLC aceptará.
## --enable-logging
Imprime el registro de Chromium en consola.
Este cambio no puede ser usado en `app.commandLine.appendSwitch` ya que se analiza antes de que la
aplicación del usuario este cargada.
Este cambio no puede ser usado en `app.commandLine.appendSwitch` ya que se analiza antes de que la
aplicación del usuario esté cargada.
## --v=`log_level`
Da el maximo nivel activo de V-logging por defecto; 0 es el predeterminado. Valores positivos
Da el máximo nivel activo de V-logging por defecto; 0 es el predeterminado. Valores positivos
son normalmente usados para los niveles de V-logging.
Este modificador sólo funciona cuando también se pasa `--enable-logging`.
## --vmodule=`pattern`
Da los niveles máximos de V-logging por módulo para sobreescribir el valor dado por
`--v`. Ej. `my_module=2,foo*=3` cambiaria el nivel de registro para todo el código
el archivos de origen `my_module.*` y `foo*.*`.
Da los niveles máximos de V-logging por módulo para sobreescribir el valor dado por
`--v`. Ej. `my_module=2,foo*=3` cambiaría el nivel de registro para todo el código,
los archivos de origen `my_module.*` y `foo*.*`.
Cualquier patron que contiene un slash o un slash invertido será probado contra toda la ruta
Cualquier patrón que contiene un slash o un slash invertido será probado contra toda la ruta
y no sólo con el módulo. Ej. `*/foo/bar/*=2` cambiaría el nivel de registro para todo el código
en los archivos origen bajo un directorio `foo/bar`.

View file

@ -1,7 +1,7 @@
# process
El objeto `process` en Electron tiene las siguientes diferencias con respecto
al node convencional:
El objeto `process` en Electron tiene las siguientes diferencias con respecto
al node convencional:
* `process.type` String - El tipo del proceso puede ser `browser` (ej. proceso
principal) o `renderer`.
@ -16,7 +16,7 @@ al node convencional:
Se emite cuando Electron ha cargado su script de inicialización interna y
está comenzando a cargar la página web o el script principal.
Puede ser usado por el script precargado para añadir de nuevo los símbolos globales
Puede ser usado por el script precargado para añadir de nuevo los símbolos globales
de Node eliminados, al alcance global cuando la integración de Node está apagada:
```js
@ -43,5 +43,5 @@ Interrumpe el hilo principal del proceso actual.
* `maxDescriptors` Integer
Establece el límite dinámico del descriptor del archivo en `maxDescriptors`
o en el límite estricto del Sistema Operativo, el que sea menor para el
o en el límite estricto del Sistema Operativo, el que sea menor para el
proceso actual.

View file

@ -4,14 +4,14 @@ Todos los [Módulos integrados de Node.js](http://nodejs.org/api/) se encuentran
disponibles en Electron y módulos de terceros son támbien totalmente compatibles
(incluyendo los [módulos nativos](../tutorial/using-native-node-modules.md)).
Electron también provee algunos módulos integrados adicionales para desarrollar
Electron también provee algunos módulos integrados adicionales para desarrollar
aplicaciones nativas de escritorio. Algunos módulos sólo se encuentran disponibles
en el proceso principal, algunos sólo en el proceso renderer (pagina web), y
en el proceso principal, algunos sólo en el proceso renderer (página web), y
algunos pueden ser usados en ambos procesos.
La regla básica es: Si un módulo es
[GUI](https://es.wikipedia.org/wiki/Interfaz_gráfica_de_usuario) o de bajo nivel,
entonces solo estará disponible en el proceso principal. Necesitas familiarizarte
La regla básica es: Si un módulo es
[GUI](https://es.wikipedia.org/wiki/Interfaz_gráfica_de_usuario) o de bajo nivel,
entonces solo estará disponible en el proceso principal. Necesitas familiarizarte
con el concepto de [scripts para proceso principal vs scripts para proceso renderer]
(../tutorial/quick-start.md#the-main-process) para ser capaz de usar esos módulos.
@ -29,7 +29,7 @@ app.on('ready', function() {
});
```
El proceso renderer no es diferente de una página web normal, excepto por la
El proceso renderer no es diferente de una página web normal, excepto por la
capacidad extra de utilizar módulos de node:
```html
@ -44,4 +44,4 @@ capacidad extra de utilizar módulos de node:
</html>
```
Para ejecutar tu aplicación, lee [Ejecutar la aplicación](../tutorial/quick-start.md#run-your-app).
Para ejecutar tu aplicación, lee [Ejecutar la aplicación](../tutorial/quick-start.md#run-your-app).

View file

@ -0,0 +1,37 @@
# Guía de estilo de código
Esta es la guía de estilo de código para Electron.
## C++ y Python
Para C++ y Python, nosotros seguimos la [guía de estilo](http://www.chromium.org/developers/coding-style) de Chromium.
Además hay un script `script/cpplint.py` para verificar si todos los archivos
siguen el estilo.
La versión de Python que estamos usando ahora es Python 2.7.
El código C++ usa muchas abstracciones y tipos de Chromium, por eso
se recomienda familiarizarse con ellos. Un buen lugar para iniciar es
el documento de Chromium sobre [Abstracciones importantes y estructras de datos](https://www.chromium.org/developers/coding-style/important-abstractions-and-data-structures). El documento menciona algunos tipos especiales, tipos por alcance (que
automaticamente liberan su memoria cuando salen de su alcance), mecanismos de
registro de eventos, etcétera.
## CoffeeScript
Para CoffeeScript, nosotros seguimos la [guía de estilo](https://github.com/styleguide/javascript) de Github y también las
siguientes reglas:
* Los archivos **NO** deberían terminar con una nueva línea, por que se busca
seguir los estilos que usa Google.
* Los nombres de los archivos debén estar concatenados con `-` en vez de `_`,
por ejemplo `nombre-de-archivo.coffee` en vez de `nombre_de_archivo.coffee`,
esto es por que en [github/atom](https://github.com/github/atom)
los nombres de los módulos usualmente estan en la forma `nombre-de-modulo`.
Esta regla aplica únicamente a los archivos `.coffee`.
## Nombres de las API
Al crear una nueva API, nosotros deberíamos preferir usar metodos `get` y `set`
en vez de usar el estilo de jQuery que utiliza una sola función. Por ejemplo,
se prefiere `.getText()` y `.setText()` por sobre `.text([text])`. Hay una
[discusión](https://github.com/atom/electron/issues/46) sobre esto.

View file

@ -0,0 +1,62 @@
# Estructura de los directorios del código fuente
El código fuente de electron es separado en pocas partes, en su mayoría
siguiendo las especificaciones para separar archivos que usa Chromium.
Quizá necesites familiarizarte con la [arquitectura multiprocesos](http://dev.chromium.org/developers/design-documents/multi-process-architecture) de Chromium para comprender mejor el código fuente.
## Estructura del código fuente
```
Electron
├──atom - Código fuente de Electron.
| ├── app - Código de arranque.
| ├── browser - La interfaz incluyendo la ventana principal, UI,
| | y todas las cosas del proceso principal. Este le habla al renderizador
| | para manejar las páginas web.
| | ├── lib - Código Javascript para inicializar el proceso principal.
| | ├── ui - Implementaciones de UI para distintas plataformas.
| | | ├── cocoa - Código fuente específico para Cocoa.
| | | ├── gtk - Código fuente específico para GTK+.
| | | └── win - Código fuente específico para Windows GUI.
| | ├── default_app - La página por defecto para mostrar cuando Electron
| | | es iniciado sin proveer una app.
| | ├── api - La implementación de las APIs para el proceso principal.
| | | └── lib - Código Javascript parte de la implementación de la API.
| | ├── net - Código relacionado a la red.
| | ├── mac - Código fuente de Objective-C específico para Mac.
| | └── resources - Iconos, archivos específicos de plataforma, etc.
| ├── renderer - Código que se ejecuta en el proceso de renderizado.
| | ├── lib - Código Javascript del proceso de inicio del renderizador.
| | └── api - La implementación de las APIs para el proceso de renderizado.
| | └── lib - Código Javascript parte de la implementación de la API.
| └── common - Código que se utiliza en ambos procesos, el principal y el de
| renderizado. Incluye algunas funciones de utilidad y código para integrar
| el ciclo de mensajes de Node en el ciclo de mensajes de Chromium.
| ├── lib - Código Javascript común para la inicialización.
| └── api - La implementación de APIs comunes, y los fundamentos de
| los módulos integrados de Electron.
| └── lib - Código Javascript parte de la implementación de la API.
├── chromium_src - Código fuente copiado de Chromium.
├── docs - Documentación.
├── spec - Pruebas automaticas.
├── atom.gyp - Reglas de compilado de Electron.
└── common.gypi - Configuración específica para compilar y reglas
de empaquetado para otros componentes como `node` y `breakpad`.
```
## Estructura de otros directorios
* **script** - Scripts usados para propositos de desarrollo
como compilar, empaquetar, realizar pruebas, etc.
* **tools** - Scripts de ayuda usados por los archivos gyp, contrario a la
carpeta `scripts`, estos scripts nunca deberían ser llamados por los usuarios.
* **vendor** - Código fuente de dependencias externas, no usamos `third_party`
como nombre por que se podría confundir con el mismo directorio
en las carpetas del código fuente de Chromium.
* **node_modules** - Módulos de node usados para la compilación.
* **out** - Directorio temporal de salida usado por `ninja`.
* **dist** - Directorio temporal creado por `script/create-dist.py` cuando
se esta creando una distribución.
* **external_binaries** - Binarios descargados de frameworks externos que no
soportan la compilación con `gyp`.

View file

@ -15,7 +15,7 @@ Estas son las maneras en las que construimos la documentación de Electron.
- Archivos separados por guiones, mas sin embargo, es correcto.
- No subtítulos seguidos por otros subtítulos, añadir por lo menos un enunciado
de descripción.
- Métodos de cabecera son delimitados con apóstrofes: `codigo`.
- Métodos de cabecera son delimitados con apóstrofes: `código`.
- Cabeceras de Eventos son delimitados con 'comillas' simples.
- No generar listas de mas de dos niveles (debido al renderizador de Markdown
desafortunadamente).
@ -25,7 +25,7 @@ Estas son las maneras en las que construimos la documentación de Electron.
- Argumentos opcionales escritos como `function (required[, optional])`.
- Argumentos opcionales son denotados cuando se llaman en listas.
- Delimitador de línea de 80-columnas.
- Métodos específicos de Plataformas son denotados en italicas seguidas por la cabecera del método.
- Métodos específicos de Plataformas son denotados en itálicas seguidas por la cabecera del método.
- ```### `method(foo, bar)` _OS X_```
- Preferir 'en el ___ proceso' en lugar de 'sobre el'
@ -47,7 +47,7 @@ Para agregar otro set (o un set parcial):
## Leyendo la Documentación de Electron
Estos son algunos consejos para entender la syntaxis de la documentación de
Estos son algunos consejos para entender la sintaxis de la documentación de
Electron.
### Métodos
@ -67,7 +67,7 @@ El nombre del método es seguido por los argumentos que recibe. Argumentos
opcionales son denotados por corchetes rodeados por el argumento opcional y la
coma requerida si el argumento opcional fuera seguido por otro argumento.
Debajo del método se encuentra mas información detallada de cada uno de los
Debajo del método se encuentra más información detallada de cada uno de los
argumentos. El tipo de argumento es denotado por los tipos comúnes:
[`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String),
[`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number),
@ -90,7 +90,7 @@ Returns:
---
El evento es una cadena que es utilizada luego de un método observador `.on`. Si
regresa un valor, el y su tipo son denotados abajo. Si se estaba a la escucha y
regresa un valor, él y su tipo son denotados abajo. Si se estaba a la escucha y
respondió a este evento se debería ver así:
```javascript

View file

@ -65,7 +65,6 @@ a ser ejecutado por el proceso principal. Un ejemplo de `package.json` podría v
```
El `main.js` debería crear las ventanas y gestionar los eventos del sistema, un ejemplo típico sería:
example being:
```javascript
var app = require('app'); // Módulo para controlar el ciclo de vida de la aplicación.

View file

@ -2,6 +2,7 @@
* [지원하는 플랫폼](tutorial/supported-platforms.md)
* [어플리케이션 배포](tutorial/application-distribution.md)
* [맥 앱스토어 제출 가이드 (0% 번역됨)](tutorial/mac-app-store-submission-guide.md)
* [어플리케이션 패키징](tutorial/application-packaging.md)
* [네이티브 Node 모듈 사용하기](tutorial/using-native-node-modules.md)
* [메인 프로세스 디버깅하기](tutorial/debugging-main-process.md)
@ -19,7 +20,7 @@
* [개요](api/synopsis.md)
* [Process 객체](api/process.md)
* [크롬 Command Line 스위치 지원](api/chrome-command-line-switches.md)
* [크롬 명령줄 스위치 지원](api/chrome-command-line-switches.md)
### 커스텀 DOM elements:
@ -29,7 +30,7 @@
### 메인 프로세스에서 사용할 수 있는 모듈:
* [app (0% 번역됨)](api/app.md)
* [app](api/app.md)
* [auto-updater](api/auto-updater.md)
* [browser-window (0% 번역됨)](api/browser-window.md)
* [content-tracing](api/content-tracing.md)
@ -65,7 +66,7 @@
* [소스 코드 디렉터리 구조](development/source-code-directory-structure.md)
* [NW.js(node-webkit)와 기술적으로 다른점](development/atom-shell-vs-node-webkit.md)
* [빌드 시스템 개요](development/build-system-overview.md)
* [빌드 설명서 (Mac)](development/build-instructions-osx.md)
* [빌드 설명서 (OS X)](development/build-instructions-osx.md)
* [빌드 설명서 (Windows)](development/build-instructions-windows.md)
* [빌드 설명서 (Linux)](development/build-instructions-linux.md)
* [디버거에서 디버그 심볼 서버 설정](development/setting-up-symbol-server.md)

View file

@ -0,0 +1,392 @@
# app
`app` 모듈은 어플리케이션의 생명주기 제어를 책임집니다.
밑의 예제는 마지막 윈도우창가 종료되었을 때, 어플리케이션을 종료시키는 예제입니다:
```javascript
var app = require('app');
app.on('window-all-closed', function() {
app.quit();
});
```
## Events
`app` 객체는 다음과 같은 이벤트를 가지고 있습니다:
### Event: 'will-finish-launching'
어플리케이션이 기본적인 시작 준비를 마치면 발생하는 이벤트입니다.
Windows, Linux 운영체제에서의 `will-finish-launching` 이벤트는 `ready` 이벤트와 동일합니다.
OS X에서의 이벤트는 `NSApplication``applicationWillFinishLaunching`에 대한 알림으로 표현됩니다.
대개 이곳에서 `open-file``open-url` 이벤트 리스너를 설정하고 crash reporter와 auto updater를 시작합니다.
대부분의 경우, 모든 것을 `ready` 이벤트 핸들러로 해결해야 합니다.
### Event: 'ready'
Electron이 초기화를 끝냈을 때 발생하는 이벤트입니다.
### Event: 'window-all-closed'
모든 윈도우창이 종료되었을 때 발생하는 이벤트입니다.
이 이벤트는 어플리케이션이 완전히 종료되지 않았을 때만 발생합니다.
만약 사용자가 `Cmd + Q`를 입력했거나 개발자가 `app.quit()`를 호출했다면,
Electron은 먼저 모든 윈도우창의 종료를 시도하고 `will-quit` 이벤트를 발생시킵니다.
그리고 `will-quit` 이벤트가 발생했을 땐 `window-all-closed` 이벤트가 발생하지 않습니다.
**역주:** 이 이벤트는 말 그대로 현재 어플리케이션에서 윈도우창만 완전히 종료됬을 때 발생하는 이벤트 입니다.
따라서 어플리케이션을 완전히 종료하려면 이 이벤트에서 `app.quit()`를 호출해 주어야 합니다.
### Event: 'before-quit'
Returns:
* `event` Event
어플리케이션 윈도우창들이 닫히기 시작할 때 발생하는 이벤트입니다.
`event.preventDefault()` 호출은 이벤트의 기본 동작을 방지하기 때문에
이를 통해 어플리케이션의 종료를 방지할 수 있습니다.
### Event: 'will-quit'
Returns:
* `event` Event
모든 윈도우창들이 종료되고 어플리케이션이 종료되기 시작할 때 발생하는 이벤트 입니다.
`event.preventDefault()` 호출을 통해 어플리케이션의 종료를 방지할 수 있습니다.
`will-quit``window-all-closed` 이벤트의 차이점을 확인하려면 `window-all-close` 이벤트의 설명을 참고하세요.
### Event: 'quit'
어플리케이션이 종료될 때 발생하는 이벤트입니다.
### Event: 'open-file'
Returns:
* `event` Event
* `path` String
사용자가 어플리케이션을 통해 파일을 열고자 할 때 발생하는 이벤트입니다.
`open-file` 이벤트는 보통 어플리케이션이 열려 있을 때 OS가 파일을 열기 위해 어플리케이션을 재사용할 때 발생합니다.
이 이벤트는 파일을 dock에 떨어트릴 때, 어플리케이션이 실행되기 전에도 발생합니다.
따라서 이 이벤트를 제대로 처리하려면 `open-file` 이벤트 핸들러를 어플리케이션이 시작하기 전에 등록해 놓았는지 확실히 확인해야 합니다. (`ready` 이벤트가 발생하기 전에)
이 이벤트를 처리할 땐 반드시 `event.preventDefault()`를 호출해야 합니다.
### Event: 'open-url'
Returns:
* `event` Event
* `url` String
유저가 어플리케이션을 통해 URL을 열고자 할 때 발생하는 이벤트입니다.
어플리케이션에서 URL을 열기 위해 반드시 URL 스킴이 등록되어 있어야 합니다.
이 이벤트를 처리할 땐 반드시 `event.preventDefault()`를 호출해야 합니다.
### Event: 'activate' _OS X_
Returns:
* `event` Event
* `hasVisibleWindows` Boolean
어플리케이션이 활성화 되었을 때 발생하는 이벤트 입니다.
이 이벤트는 어플리케이션의 dock 아이콘을 클릭했을 때 주로 발생합니다.
### Event: 'browser-window-blur'
Returns:
* `event` Event
* `window` BrowserWindow
[browserWindow](browser-window.md)에 대한 포커스가 사라졌을 때 발생하는 이벤트 입니다.
### Event: 'browser-window-focus'
Returns:
* `event` Event
* `window` BrowserWindow
[browserWindow](browser-window.md)에 대한 포커스가 발생했을 때 발생하는 이벤트 입니다.
**역주:** _포커스_는 창을 클릭해서 활성화 시켰을 때를 말합니다.
### Event: 'browser-window-created'
Returns:
* `event` Event
* `window` BrowserWindow
새로운 [browserWindow](browser-window.md)가 생성되었을 때 발생하는 이벤트 입니다.
### Event: 'select-certificate'
사용자 인증이 요청되었을 때 발생하는 이벤트 입니다.
Returns:
* `event` Event
* `webContents` [WebContents](browser-window.md#class-webcontents)
* `url` String
* `certificateList` [Objects]
* `data` PEM으로 인코딩된 데이터
* `issuerName` 발급자의 공통 이름
* `callback` Function
```javascript
app.on('select-certificate', function(event, host, url, list, callback) {
event.preventDefault();
callback(list[0]);
})
```
`url`에 대한
`url`은 클라이언트 인증서를 요청하는 탐색 항목에 해당합니다.
그리고 `callback`은 목록에서 필터링된 항목과 함께 호출될 필요가 있습니다.
이 이벤트에서의 `event.preventDefault()` 호출은 초기 인증에 사용한 저장된 데이터를 사용하는 것을 막습니다.
### Event: 'gpu-process-crashed'
GPU가 작동하던 중 크래시가 일어났을 때 발생하는 이벤트입니다.
## Methods
`app` 객체는 다음과 같은 메서드를 가지고 있습니다:
**참고:** 몇몇 메서드는 특정 플랫폼에서만 작동합니다.
### `app.quit()`
모든 윈도우창 종료를 시도합니다. `before-quit` 이벤트가 먼저 발생합니다.
모든 윈도우창이 성공적으로 종료되면 `will-quit` 이벤트가 발생하고 기본 동작에 따라 어플리케이션이 종료됩니다.
이 함수는 모든 `beforeunload``unload` 이벤트 핸들러가 제대로 실행됨을 보장합니다.
`beforeunload` 이벤트 핸들러에서 `false`를 반환했을 때 윈도우창 종료가 취소 될 수 있습니다.
### `app.getAppPath()`
현재 어플리케이션의 디렉터리를 반환합니다.
### `app.getPath(name)`
* `name` String
`name`에 관련한 특정 디렉터리 또는 파일의 경로를 반환합니다.
경로를 가져오는 데 실패할 경우 `Error`를 반환합니다.
**역주:** 이 메서드는 운영체제에서 지정한 특수 디렉터리를 가져오는데 사용할 수 있습니다.
`name`은 다음 목록에 있는 경로 중 하나를 선택해 사용할 수 있습니다:
* `home` - 사용자의 홈 디렉터리.
* `appData` - 각 사용자의 어플리케이션 데이터 디렉터리. 기본 경로는 다음과 같습니다:
* `%APPDATA%` - Windows
* `$XDG_CONFIG_HOME` 또는 `~/.config` - Linux
* `~/Library/Application Support` - OS X
* `userData` - 어플리케이션의 설정을 저장하는 디렉터리.
이 디렉터리는 기본적으로 `appData`에 어플리케이션 이름으로 생성된 폴더가 지정됩니다.
* `temp` - 임시 폴더 디렉터리.
* `userDesktop` - 현재 사용자의 데스트탑 디렉터리.
* `exe` - 현재 실행중인 Electron 바이너리 파일.
* `module` - `libchromiumcontent` 라이브러리.
### `app.setPath(name, path)`
* `name` String
* `path` String
`name`에 대한 특정 디렉터리나 파일의 경로인 `path`를 재정의합니다.
만약 지정한 디렉터리의 경로가 존재하지 않으면 디렉터리가 이 메서드를 통해 새로 생성됩니다.
재정의에 실패했을 땐 `Error`를 반환합니다.
이 메서드는 `app.getPath`에 정의되어 있는 `name`의 경로만 재정의할 수 있습니다.
기본적으로, 웹 페이지의 쿠키와 캐시는 `userData` 디렉터리에 저장됩니다.
만약 이 위치를 변경하고자 한다면, 반드시 `app` 모듈의 `ready` 이벤트가 발생하기 전에 `userData` 경로를 재정의해야 합니다.
### `app.getVersion()`
로드된 어플리케이션의 버전을 반환합니다.
만약 `package.json` 파일에서 어플리케이션의 버전을 찾을 수 없는 경우, 현재 번들 또는 실행 파일의 버전을 반환합니다.
### `app.getName()`
`package.json`에서 기술된 현재 어플리케이션의 이름을 반환합니다.
npm 모듈 규칙에 따라 대부분의 경우 `package.json``name` 필드는 소문자 이름을 사용합니다.
하지만 Electron은 `name`대신 `productName` 필드를 주로 사용하기 때문에 반드시 이 필드도 같이 지정해야 합니다.
이 필드는 맨 앞글자가 대문자인 어플리케이션 전체 이름을 지정해야 합니다.
### `app.getLocale()`
현재 어플리케이션의 [로케일](https://ko.wikipedia.org/wiki/%EB%A1%9C%EC%BC%80%EC%9D%BC)을 반환합니다.
### `app.resolveProxy(url, callback)`
* `url` URL
* `callback` Function
`url`의 프록시 정보를 해석합니다.
`callback`은 요청이 수행되었을 때 `callback(proxy)` 형태로 호출됩니다.
### `app.addRecentDocument(path)` _OS X_ _Windows_
* `path` String
최근 문서 목록에 `path`를 추가합니다.
이 목록은 OS에 의해 관리됩니다.
최근 문서 목록은 Windows의 경우 작업 표시줄에서 찾을 수 있고, OS X의 경우 dock 메뉴에서 찾을 수 있습니다.
### `app.clearRecentDocuments()` _OS X_ _Windows_
최근 문서 목록을 모두 비웁니다.
### `app.setUserTasks(tasks)` _Windows_
* `tasks` Array - `Task` 객체의 배열
Windows에서 사용할 수 있는 JumpList의 [Tasks][tasks] 카테고리에 `task`를 추가합니다.
`tasks`는 다음과 같은 구조를 가지는 `Task` 객체의 배열입니다:
`Task` Object
* `program` String - 실행할 프로그램의 경로.
보통 현재 작동중인 어플리케이션의 경로인 `process.execPath`를 지정합니다.
* `arguments` String - `program`이 실행될 때 사용될 명령줄 인자.
* `title` String - JumpList에 표시할 문자열.
* `description` String - 이 작업에 대한 설명.
* `iconPath` String - JumpList에 표시될 아이콘의 절대 경로.
아이콘을 포함하고 있는 임의의 리소스 파일을 사용할 수 있습니다.
보통 어플리케이션의 아이콘을 그대로 사용하기 위해 `process.execPath`를 지정합니다.
* `iconIndex` Integer - 아이콘 파일의 인덱스. 만약 아이콘 파일이 두 개 이상의 아이콘을 가지고 있을 경우,
사용할 아이콘의 인덱스를 이 옵션으로 지정해 주어야 합니다. 단, 아이콘을 하나만 포함하고 있는 경우 0을 지정하면 됩니다.
### `app.allowNTLMCredentialsForAllDomains(allow)`
* `allow` Boolean
항상 동적으로 HTTP NTLM 또는 Negotiate 인증에 자격 증명을 보낼 것인지 설정합니다.
기본적으로 Electron은 "로컬 인터넷" 사이트 URL에서 NTLM/Kerberos 자격 증명만을 보냅니다. (같은 도메인 내에서)
그러나 기업 네트워크가 잘못 구성된 경우 종종 작업에 실패할 수 있습니다.
이때 이 메서드를 통해 모든 URL을 허용할 수 있습니다.
### `app.makeSingleInstance(callback)`
* `callback` Function
현재 어플리케이션을 **Single Instance Application**으로 만들어줍니다.
이 메서드는 어플리케이션이 여러 번 실행됐을 때 다중 인스턴스가 생성되는 대신 한 개의 주 인스턴스만 유지되도록 만들 수 있습니다.
이때 중복 생성된 인스턴스는 주 인스턴스에 신호를 보내고 종료됩니다.
`callback`은 주 인스턴스가 생성된 이후 또 다른 인스턴스가 생성됐을 때 `callback(argv, workingDirectory)` 형식으로 호출됩니다.
`argv`는 두 번째 인스턴스의 명령줄 인수이며 `workingDirectory`는 현재 작업중인 디렉터리입니다.
보통 대부분의 어플리케이션은 이러한 콜백이 호출될 때 주 윈도우창을 포커스하고 최소화되어있으면 창 복구를 실행합니다.
`callback``app``ready` 이벤트가 발생한 후 실행됨을 보장합니다.
이 메서드는 현재 실행된 어플리케이션이 주 인스턴스인 경우 `false`를 반환하고 어플리케이션의 로드가 계속 진행 되도록 합니다.
그리고 두 번째 중복된 인스턴스 생성인 경우 `true`를 반환합니다. (다른 인스턴스에 인수가 전달됬을 때)
이 불리언 값을 통해 중복 생성된 인스턴스는 즉시 종료시켜야 합니다.
OS X에선 사용자가 Finder에서 어플리케이션의 두 번째 인스턴스를 열려고 했을 때 자동으로 **Single Instance**화 하고 `open-file``open-url` 이벤트를 발생시킵니다.
그러나 사용자가 어플리케이션을 CLI 터미널에서 실행하면 운영체제 시스템의 싱글 인스턴스 메커니즘이 무시되며 그대로 중복 실행됩니다.
따라서 OS X에서도 이 메서드를 통해 확실히 중복 실행을 방지하는 것이 좋습니다.
다음 예제는 두 번째 인스턴스가 생성되었을 때 중복된 인스턴스를 종료하고 주 어플리케이션 인스턴스의 윈도우창을 활성화 시키는 예제입니다:
```javascript
var myWindow = null;
var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
// 어플리케이션을 중복 실행했습니다. 주 어플리케이션 인스턴스를 활성화 합니다.
if (myWindow) {
if (myWindow.isMinimized()) myWindow.restore();
myWindow.focus();
}
return true;
});
if (shouldQuit) {
app.quit();
return;
}
// 윈도우창을 생성하고 각종 리소스를 로드하고 작업합니다..
app.on('ready', function() {
});
```
### `app.commandLine.appendSwitch(switch[, value])`
Chrominum의 명령줄에 스위치를 추가합니다. `value`는 추가적인 값을 뜻하며 옵션입니다.
**참고:** 이 메서드는 `process.argv`에 영향을 주지 않습니다.
개발자들은 보통 Chrominum의 로우 레벨 수준의 동작을 제어하기 위해 주로 사용합니다.
### `app.commandLine.appendArgument(value)`
Chrominum의 명령줄에 인수를 추가합니다. 인수는 올바르게 인용됩니다.
**참고:** 이 메서드는 `process.argv`에 영향을 주지 않습니다.
### `app.dock.bounce([type])` _OS X_
* `type` String (optional) - `critical` 또는 `informational`을 지정할 수 있습니다. 기본값은 `informational` 입니다.
`critical`이 전달되면 dock 아이콘이 어플리케이션이 활성화되거나 요청이 중지되기 전까지 통통 튑니다.
`informational`이 전달되면 dock 아이콘이 1초만 통통 튑니다.
하지만 어플리케이션이 활성화되거나 요청이 중지되기 전까지 요청은 계속 활성화로 유지 됩니다.
또한 요청을 취소할 때 사용할 수 있는 ID를 반환합니다.
### `app.dock.cancelBounce(id)` _OS X_
* `id` Integer
`app.dock.bounce([type])` 메서드에서 반환한 `id`의 통통 튀는 효과를 취소합니다.
### `app.dock.setBadge(text)` _OS X_
* `text` String
dock의 badge에 표시할 문자열을 설정합니다.
### `app.dock.getBadge()` _OS X_
dock의 badge에 설정된 문자열을 반환합니다.
### `app.dock.hide()` _OS X_
dock 아이콘을 숨깁니다.
### `app.dock.show()` _OS X_
dock 아이콘을 표시합니다.
### `app.dock.setMenu(menu)` _OS X_
* `menu` Menu
어플리케이션의 [dock menu][dock-menu]를 설정합니다.
[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103
[tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks

View file

@ -1,86 +1,28 @@
# autoUpdater
**이 모듈은 현재 OS X에서만 사용할 수 있습니다.**
이 모듈은 `Squirrel` 자동 업데이트 프레임워크의 인터페이스를 제공합니다.
Windows 인스톨러를 생성하려면 [atom/grunt-electron-installer](https://github.com/atom/grunt-electron-installer)를 참고하세요.
## 플랫폼별 참고 사항
`auto-updater` 모듈은 [Squirrel.Mac](https://github.com/Squirrel/Squirrel.Mac) 프레임워크의 간단한 wrapper 입니다.
`autoUpdater`는 기본적으로 모든 플랫폼에 대해 같은 API를 제공하지만, 여전히 플랫폼별로 약간씩 다른 점이 있습니다.
Squirrel.Mac은 업데이트 설치를 위해 `.app` 폴더에
[codesign](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/codesign.1.html)
툴을 사용한 서명을 요구합니다.
### OS X
## Squirrel
OS X에선 `auto-updater` 모듈이 [Squirrel.Mac][squirrel-mac]를 기반으로 작동합니다.
따라서 이 모듈을 작동시키기 위해 특별히 준비해야 할 작업은 없습니다.
서버 사이드 요구 사항은 [서버 지원][server-support]을 참고하세요.
Squirrel은 어플리케이션이 **안전하고 투명한 업데이트**를 제공할 수 있도록 하는데 초점이 맞춰진 OS X 프레임워크입니다.
### Windows
Squirrel은 사용자에게 어플리케이션의 업데이트를 알릴 필요 없이 자동으로 서버가 지시하는 버전을 받아 어플리케이션을 업데이트합니다.
지능적으로 클라이언트 어플리케이션을 업데이트 할 수 있습니다.
Windows에선 `auto-updater` 모듈을 사용하기 전에 어플리케이션을 사용자의 장치에 설치해야 합니다.
[grunt-electron-installer][installer]를 사용하여 어플리케이션 셋업을 만드는 것을 권장합니다.
업데이트 요청은 커스텀 헤더 또는 요청 본문에 인증 정보를 포함시킬 수 있습니다.
이에 따라 서버에선 이러한 요청을 분석 처리하여 사용자에게 적당한 업데이트를 제공할 수 있습니다.
서버 사이드 요구 사항 또한 OS X와 다르게 적용됩니다. 자세한 내용은 [Squirrel.Windows][squirrel-windows]를 참고하세요.
Squirrel JSON 업데이트 요청시 처리는 반드시 어떤 업데이트가 필요한지 요청의 기준에 맞춰 동적으로 생성되어야 합니다.
Squirrel은 사용해야 하는 업데이트 선택하는 과정을 서버에 의존합니다. [서버 지원](#서버-지원)을 참고하세요.
### Linux
Squirrel의 인스톨러는 오류에 관대하게 설계되었습니다. 그리고 업데이트가 유효한지 확인합니다.
## 업데이트 요청
Squirrel은 클라이언트 어플리케이션이 업데이트 확인을 위해 제공하는 요청을 무시합니다.
Squirrel이 응답을 분석할 수 있어야하기 때문에 요청 헤더에 `Accept: application/json` 헤더가 추가됩니다.
업데이트 응답과 본문 포맷에 대한 요구 사항은 [서버 지원](#서버-지원)를 참고하세요.
업데이트 요청에는 서버가 해당 어플리케이션이 어떤 버전을 사용해야 하는지 판단하기 위해 *반드시* 버전 식별자를 포함시켜야 합니다.
추가로 OS 버전, 사용자 이름 같은 다른 식별 기준을 포함하여 서버에서 적합한 어플리케이션을 제공할 수 있도록 할 수 있습니다.
버전 식별자와 다른 기준을 특정하는 업데이트 요청 폼을 서버로 전달하기 위한 공통적인 방법으로 쿼리 인자를 사용하는 방법이 있습니다:
```javascript
// In the main process
var app = require('app');
var autoUpdater = require('auto-updater');
autoUpdater.setFeedUrl('http://mycompany.com/myapp/latest?version=' + app.getVersion());
```
## 서버 지원
업데이트를 제공하는 서버는 반드시 클라이언트로부터 받은 [업데이트 요청](#업데이트-요청)을 기반으로 업데이트를 처리할 수 있어야 합니다.
만약 업데이트 요청이 들어오면 서버는 반드시 [200 OK](http://tools.ietf.org/html/rfc2616#section-10.2.1) 상태 코드를 포함한
[업데이트 JSON](#update-json-format)을 본문으로 보내야 합니다.
이 응답을 받으면 Squirrel은 이 업데이트를 다운로드할 것입니다. 참고로 현재 설치된 버전과 서버에서 받아온 새로운 버전이 같아도 상관하지 않고 무조건 받습니다.
업데이트시 버전 중복을 피하려면 서버에서 클라이언트 업데이트 요청에 대해 통보하지 않으면 됩니다.
만약 따로 업데이트가 없다면 [204 No Content](http://tools.ietf.org/html/rfc2616#section-10.2.5) 상태 코드를 반환해야 합니다.
Squirrel은 지정한 시간이 지난 후 다시 업데이트를 확인합니다.
## JSON 포맷 업데이트
업데이트가 사용 가능한 경우 Squirrel은 다음과 같은 구조의 json 데이터를 응답으로 받습니다:
```json
{
"url": "http://mycompany.com/myapp/releases/myrelease",
"name": "My Release Name",
"notes": "Theses are some release notes innit",
"pub_date": "2013-09-18T12:29:53+01:00"
}
```
응답 json 데이터에서 "url" 키는 필수적으로 포함해야 하고 다른 키들은 옵션입니다.
Squirrel은 "url"로 `Accept: application/zip` 헤더와 함께 업데이트 zip 파일을 요청합니다.
향후 업데이트 포맷에 대해 서버에서 적절한 포맷을 반환할 수 있도록 MIME 타입을 `Accept` 헤더에 담아 요청합니다.
`pub_date`은 ISO 8601 표준에 따라 포맷된 날짜입니다.
## 업데이트 서버 구현
[Nuts](https://github.com/GitbookIO/nuts)는 위에서 설명한 업데이트 서버의 오픈 소스 구현입니다.
이 구현은 Github 릴리즈와 완벽하게 통합되어 있습니다. Nuts는 `Squirrel.Mac``Squirrel.Windows`를 지원하고 다운로드와 업데이트를 관리합니다.
이 구현을 사용하면 cross-platform 지원을 신경 쓸 필요가 없습니다.
Linux는 따로 `auto-updater`를 지원하지 않습니다.
각 배포판의 패키지 관리자를 통해 어플리케이션 업데이트를 제공하는 것을 권장합니다.
## Events
@ -88,10 +30,11 @@ Squirrel은 "url"로 `Accept: application/zip` 헤더와 함께 업데이트 zip
### Event: 'error'
* `event` Event
* `message` String
Returns:
업데이트시 에러가 나면 발생하는 이벤트입니다.
* `error` Error
업데이트에 문제가 생기면 발생하는 이벤트입니다.
### Event: 'checking-for-update'
@ -107,14 +50,15 @@ Squirrel은 "url"로 `Accept: application/zip` 헤더와 함께 업데이트 zip
### Event: 'update-downloaded'
Returns:
* `event` Event
* `releaseNotes` String
* `releaseName` String
* `releaseDate` Date
* `updateUrl` String
* `quitAndUpdate` Function
업데이트의 다운로드가 완료되었을 때 발생하는 이벤트입니다. `quitAndUpdate()`를 호출하면 어플리케이션을 종료하고 업데이트를 설치합니다.
업데이트의 다운로드가 완료되었을 때 발생하는 이벤트입니다.
## Methods
@ -129,3 +73,13 @@ Squirrel은 "url"로 `Accept: application/zip` 헤더와 함께 업데이트 zip
### `autoUpdater.checkForUpdates()`
서버에 새로운 업데이트가 있는지 요청을 보내 확인합니다. API를 사용하기 전에 `setFeedUrl`를 호출해야 합니다.
### `autoUpdater.quitAndUpdate()`
어플리케이션을 다시 시작하고 다운로드된 업데이트를 설치합니다.
이 메서드는 `update-downloaded` 이벤트가 발생한 이후에만 사용할 수 있습니다.
[squirrel-mac]: https://github.com/Squirrel/Squirrel.Mac
[server-support]: https://github.com/Squirrel/Squirrel.Mac#server-support
[squirrel-windows]: https://github.com/Squirrel/Squirrel.Windows
[installer]: https://github.com/atom/grunt-electron-installer

View file

@ -1,6 +1,6 @@
# 크롬 Command-Line 스위치 지원
# 크롬 명령줄 스위치 지원
크롬 Command-Line 스위치는 크롬 브라우저에서 제공되는 추가 옵션이며 Electron에서도 지원합니다.
크롬 명령줄(Command-Line) 스위치는 크롬 브라우저에서 제공되는 추가 옵션이며 Electron에서도 지원합니다.
[app][app]의 [ready][ready]이벤트가 작동하기 전에 [app.commandLine.appendSwitch][append-switch] API를 사용하면
어플리케이션 내부에서 스위치들을 추가할 수 있습니다:
@ -44,7 +44,7 @@ HTTP 요청 캐시를 비활성화 합니다.
## --host-rules=`rules`
Hostname 맵핑 규칙을 설정합니다. (`,`로 분)
Hostname 맵핑 규칙을 설정합니다. (`,`로 분)
예시:
@ -86,11 +86,16 @@ Net log 이벤트를 활성화하고 `path`에 로그를 기록합니다.
TLS fallback에서 사용할 SSL/TLS 최소 버전을 지정합니다. ("tls1", "tls1.1", "tls1.2")
## --cipher-suite-blacklist=`cipher_suites`
SSL 암호화를 비활성화할 대상 목록을 지정합니다. (`,`로 구분)
## --enable-logging
Chromium의 로그를 콘솔에 출력합니다.
이 스위치는 어플리케이션이 로드되기 전에 파싱 되므로 `app.commandLine.appendSwitch`에서 사용할 수 없습니다.
이 스위치는 어플리케이션이 로드되기 전에 분석 되므로 `app.commandLine.appendSwitch` 메서드에선 사용할 수 없습니다.
하지만 `ELECTRON_ENABLE_LOGGING` 환경 변수를 설정하면 본 스위치를 지정한 것과 같은 효과를 낼 수 있습니다.
## --v=`log_level`

View file

@ -54,11 +54,10 @@ crashReporter.start({
Crash Reporter는 다음과 같은 데이터를 `submitUrl``POST` 방식으로 전송합니다:
* `rept` String - 예시 'electron-crash-service'
* `ver` String - Electron의 버전
* `platform` String - 예시 'win32'
* `process_type` String - 예시 'renderer'
* `ptime` Number
* `guid` String - e.g. '5e1286fc-da97-479e-918b-6bfb0c3d1c72'
* `_version` String - `package.json`내의 `version` 필드
* `_productName` String - Crash Reporter의 `options` 객체에서 정의한 제품명.
* `prod` String - 기본 제품의 이름. 이 경우 Electron으로 표시됩니다.

View file

@ -13,7 +13,7 @@ var BrowserWindow = require('browser-window');
var win = new BrowserWindow({ width: 800, height: 600, frame: false });
```
### 최신 Mac에서 사용할 수 있는 대안
### 최신 OS X에서 사용할 수 있는 대안
OS X 10.10 Yosemite 이후의 최신 버전부터는 테두리가 없는 창을 만들 때 새로운 방법을 사용할 수 있습니다.
`frame` 옵션을 `false`로 지정하여 제목과 창 구성 요소를 모두 비활성화하는 대신 새로운 `title-bar-style`

View file

@ -5,7 +5,8 @@ Electron의 `process` 객체는 기존의 node와는 달리 약간의 차이점
* `process.type` String - 프로세스의 타입, `browser` (메인 프로세스) 또는 `renderer`가 됩니다.
* `process.versions['electron']` String - Electron의 버전.
* `process.versions['chrome']` String - Chromium의 버전.
* `process.resourcesPath` String - JavaScript 소스코드의 경로.
* `process.resourcesPath` String - JavaScript 소스 코드의 경로.
* `process.mas` Boolean - Mac 앱 스토어용 빌드일 때 `true`로 지정됩니다. 다른 빌드일 땐 `undefined`로 지정됩니다.
## Events
@ -37,4 +38,4 @@ process.once('loaded', function() {
* `maxDescriptors` Integer
`maxDescriptors`에 file descriptor 소프트 리미트를 설정하거나 OS 하드 리미트를 설정합니다. 값은 현재 프로세스에 대해 낮은 값이어야 합니다.
현재 프로세스의 파일 기술자의 제한 값을 소프트 제한 `maxDescriptors`의 값이나 OS 하드 제한 중 낮은 값으로 설정합니다.

View file

@ -147,6 +147,8 @@ win.webContents.on('did-finish-load', function() {
세션에 사용할 프록시 `config`를 분석하고 프록시를 적용합니다.
세션에 사용할 프록시는 `config`가 PAC 주소일 경우 그대로 적용하고, 다른 형식일 경우 다음 규칙에 따라 적용합니다.
```
config = scheme-proxies[";"<scheme-proxies>]
scheme-proxies = [<url-scheme>"="]<proxy-uri-list>

View file

@ -118,7 +118,7 @@ __주의:__ `bounds`는 OS X 와 Windows에서만 작동합니다.
`Tray` 모듈은 다음과 같은 메서드를 가지고 있습니다:
**참고:** 몇가지 메서드는 특정한 플랫폼에서만 작동합니다.
**참고:** 몇몇 메서드는 특정 플랫폼에서만 작동합니다.
### `Tray.destroy()`

View file

@ -1,7 +1,7 @@
# 데스크톱 환경 통합
어플리케이션을 배포할 서로 다른 운영체제 시스템의 환경과 기능에 맞춰 사용 환경을 통합할 수 있습니다.
예를 들어 Windows에선 태스크바의 JumpList에 바로가기를 추가할 수 있고 Mac(OS X)에선 dock menu에 커스텀 메뉴를 추가할 수 있습니다.
어플리케이션 배포의 대상이 되는 서로 다른 운영체제 시스템의 환경에 맞춰 어플리케이션의 기능을 통합할 수 있습니다.
예를 들어 Windows에선 태스크바의 JumpList에 바로가기를 추가할 수 있고 Mac(OS X)에선 dock 메뉴에 커스텀 메뉴를 추가할 수 있습니다.
이 가이드는 Electron API를 이용하여 각 운영체제 시스템의 기능을 활용하는 방법을 설명합니다.
@ -194,10 +194,10 @@ var window = new BrowserWindow({...});
window.setProgressBar(0.5);
```
## 윈도우 대표 파일 제시 (OS X)
## 대표 파일 제시 (OS X)
OS X는 윈도우에서 대표 파일을 설정할 수 있습니다. 쉽게 말해 타이틀바에서 파일 아이콘을 볼 수 있을 때 사용자가 Command-Click 또는 Control-Click 할 경우 파일 경로 팝업이 보여집니다.
또한 윈도우의 상태도 지정할 수 있습니다. 쉽게 말해 로드된 문서의 수정여부를 타이틀바 파일 아이콘에 표시할 수 있습니다.
OS X는 창에서 대표 파일을 설정할 수 있습니다. 타이틀바에서 파일 아이콘이 있고, 사용자가 Command-Click 또는 Control-Click 키를 누를 경우 파일 경로 팝업이 보여집니다.
또한 의 상태도 지정할 수 있습니다. 쉽게 말해 로드된 문서의 수정여부를 타이틀바 파일 아이콘에 표시할 수 있습니다.
__대표 파일 팝업 메뉴:__

View file

@ -71,7 +71,7 @@ var BrowserWindow = require('browser-window'); // 네이티브 브라우저 창
require('crash-reporter').start();
// 윈도우 객체를 전역에 유지합니다. 만약 이렇게 하지 않으면
// 자바스크립트 GC가 일어날 때 창이 자동으로 닫혀버립니다.
// 자바스크립트 GC가 일어날 때 창이 멋대로 닫혀버립니다.
var mainWindow = null;
// 모든 창이 닫히면 어플리케이션 종료.
@ -93,7 +93,7 @@ app.on('ready', function() {
mainWindow.loadUrl('file://' + __dirname + '/index.html');
// 개발자 콘솔을 엽니다.
mainWindow.openDevTools();
mainWindow.webContents.openDevTools();
// 창이 닫히면 호출됩니다.
mainWindow.on('closed', function() {
@ -116,7 +116,8 @@ app.on('ready', function() {
</head>
<body>
<h1>헬로 월드!</h1>
이 어플리케이션은 Node.js <script>document.write(process.version)</script>
이 어플리케이션은 node <script>document.write(process.version)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
Electron <script>document.write(process.versions['electron'])</script>을 사용합니다.
</body>
</html>
@ -174,6 +175,23 @@ $ ./Electron.app/Contents/MacOS/Electron your-app/
어플리케이션 실행파일은 `Electron`의 release 패키지에 포함되어 있습니다.
[여기](https://github.com/atom/electron/releases)에서 다운로드 받을 수 있습니다.
### 배포용 파일 만들기
### 배포용 실행 파일 만들기
어플리케이션 작성을 완료했다면 [어플리케이션 배포](application-distribution.md) 가이드를 통해 제작한 앱을 본격적으로 배포할 수 있습니다.
어플리케이션 작성을 모두 끝냈다면 [어플리케이션 배포](application-distribution.md) 가이드를 통해 제작한 앱을 패키징하고 배포할 수 있습니다.
### 미리 작성된 앱 실행하기
[`atom/electron-quick-start`](https://github.com/atom/electron-quick-start) 저장소를 클론하면 이 가이드에서 작성한 예제 앱을 바로 실행해 볼 수 있습니다.
**참고**: 이 예제를 실행시키려면 [Git](https://git-scm.com)과 [Node.js](https://nodejs.org/en/download/)가 필요합니다. (CLI에서 실행 가능한 [npm](https://npmjs.org)이 있어야 합니다)
**역주**: `npm`은 보통 Node.js를 설치하면 자동으로 같이 설치됩니다.
```bash
# 저장소를 클론합니다
$ git clone https://github.com/atom/electron-quick-start
# 저장소 안으로 들어갑니다
$ cd electron-quick-start
# 어플리케이션의 종속성 모듈을 설치한 후 실행합니다
$ npm install && npm start
```

View file

@ -28,7 +28,7 @@ Electron도 이 모듈을 통해 포팅된 네이티브 모듈을 사용할 수
npm install --save-dev electron-rebuild
# 필요한 네이티브 모듈을 `npm install`로 설치한 후 다음 명령을 실행하세요:
node ./node_modules/.bin/electron-rebuild
./node_modules/.bin/electron-rebuild
```
### `npm`을 이용한 방법

View file

@ -0,0 +1,73 @@
## คู่มือ
* [แพลตฟอร์มที่รองรับ](tutorial/supported-platforms.md)
* [การเผยแพร่แอปพลิเคชัน](tutorial/application-distribution.md)
* [แนวทางการส่งแอปเข้า Mac App Store](tutorial/mac-app-store-submission-guide.md)
* [การบรรจุแอปพลิเคชัน](tutorial/application-packaging.md)
* [การใช้โมดูลของ Node](tutorial/using-native-node-modules.md)
* [การหาข้อผิดพลาดในกระบวนการหลัก](tutorial/debugging-main-process.md)
* [การใช้งาน Selenium และ WebDriver](tutorial/using-selenium-and-webdriver.md)
* [ส่วนเสริมของ DevTools](tutorial/devtools-extension.md)
* [การใช้งานส่วนเสริม Pepper Flash](tutorial/using-pepper-flash-plugin.md)
## แนะนำ
* [เริ่มต้นอย่างคราวๆ](tutorial/quick-start.md)
* [การร่วมกันของสภาพแวดล้อมบนเดสทอป](tutorial/desktop-environment-integration.md)
* [การตรวจจับเหตุการณ์ออนไลน์หรือออฟไลน์](tutorial/online-offline-events.md)
## แหล่งอ้างอิงของ API
* [สรุปความ](api/synopsis.md)
* [โปรเซสออบเจค](api/process.md)
* [คำสั่งสำหรับเปลี่ยนแปลงค่าของ Chrome ที่รองรับ](api/chrome-command-line-switches.md)
### การปรับแต่ง DOM:
* [วัตถุ `File`](api/file-object.md)
* [แท็ก `<webview>`](api/web-view-tag.md)
* [ฟังก์ชัน `window.open`](api/window-open.md)
### โมดูลสำหรับกระบวนการหลัก :
* [app](api/app.md)
* [auto-updater](api/auto-updater.md)
* [browser-window](api/browser-window.md)
* [content-tracing](api/content-tracing.md)
* [dialog](api/dialog.md)
* [global-shortcut](api/global-shortcut.md)
* [ipc (main process)](api/ipc-main-process.md)
* [menu](api/menu.md)
* [menu-item](api/menu-item.md)
* [power-monitor](api/power-monitor.md)
* [power-save-blocker](api/power-save-blocker.md)
* [protocol](api/protocol.md)
* [session](api/session.md)
* [web-contents](api/web-contents.md)
* [tray](api/tray.md)
### โมดูลสำหรับกระบวนการ Renderer (เว็บเพจ):
* [ipc (renderer)](api/ipc-renderer.md)
* [remote](api/remote.md)
* [web-frame](api/web-frame.md)
### Modules for Both Processes:
* [clipboard](api/clipboard.md)
* [crash-reporter](api/crash-reporter.md)
* [native-image](api/native-image.md)
* [screen](api/screen.md)
* [shell](api/shell.md)
## การพัฒนา
* [ลักษณะการเขียนโค้ด](development/coding-style.md)
* [โครงสร้างไดเรคทอรี่ของซอร์สโค้ด](development/source-code-directory-structure.md)
* [ความแตกต่างทางเทคนิคจาก NW.js (หรือ node-webkit)](development/atom-shell-vs-node-webkit.md)
* [ภาพรวมการสร้างระบบ](development/build-system-overview.md)
* [ขั้นตอนการสร้าง (OS X)](development/build-instructions-osx.md)
* [ขั้นตอนการสร้าง (Windows)](development/build-instructions-windows.md)
* [ขั้นตอนการสร้าง (Linux)](development/build-instructions-linux.md)
* [Setting Up Symbol Server in debugger](development/setting-up-symbol-server.md)
* [การติดตั้งเซิร์ฟเวอร์ Symbol Server ใน debugger](development/setting-up-symbol-server.md)

View file

@ -1,7 +1,9 @@
## 導引
* [支援平台](tutorial/supported-platforms.md)
* [應用程式發布](tutorial/application-distribution.md)
* [應用程式打包](tutorial/application-packaging.md)
* [Mac App Store 上架指引](tutorial/mac-app-store-submission-guide.md)
* [使用原生 node 模組](tutorial/using-native-node-modules.md)
* [主行程 Debug](tutorial/debugging-main-process.md)
* [使用 Selenium 和 WebDriver](tutorial/using-selenium-and-webdriver.md)
@ -64,7 +66,7 @@
* [源碼目錄結構](development/source-code-directory-structure.md)
* [與 NW.js (原名node-webkit) 在技術上的差異](development/atom-shell-vs-node-webkit.md)
* [構建系統概況](development/build-system-overview.md)
* [構建步驟 (Mac)](development/build-instructions-mac.md)
* [構建步驟 (OS X)](development/build-instructions-osx.md)
* [構建步驟 (Windows)](development/build-instructions-windows.md)
* [構建步驟 (Linux)](development/build-instructions-linux.md)
* [在 debugger 中使用 symbol server](development/setting-up-symbol-server.md)

View file

@ -3,7 +3,7 @@
## 簡介
Electron 可以讓你使用純 JavaScript 提供豐富的原生的 APIs 來創造桌面應用程式。
你可以把它視為一個 io.js 的變體,專注於桌面應用程式而不是 web 伺服器。
你可以把它視為一個 Node.js 的變體,專注於桌面應用程式而不是 web 伺服器。
這不表示 Electron 是一個用 JavaScript 去綁定 GUI 函式庫。取而代之的Electron 是使用網頁介面來作為它的 GUI
所以你可以把它看作是一個被 JavaScript 所控制且精簡化的 Chromium 瀏覽器。
@ -19,7 +19,7 @@ Electron 可以讓你使用純 JavaScript 提供豐富的原生的 APIs 來創
每一個網頁在 Electron 裏執行各自的行程,被稱為 __渲染行程__
在一般瀏覽器中,網頁通常會在沙盒環境下運行,並且不允許存取原生資源。然而,
Electron 的用戶擁有在網頁中呼叫 io.js APIs 的能力,允許低級別操作與作業系統的交互作用。
Electron 的用戶擁有在網頁中呼叫 Node.js APIs 的能力,允許低級別操作與作業系統的交互作用。
## 主行程與渲染行程的區別
@ -30,7 +30,7 @@ Electron 的用戶擁有在網頁中呼叫 io.js APIs 的能力,允許低級
在網頁中,是不允許呼叫原生 GUI 相關 APIs 因為管理原生 GUI 資源在網頁上是非常危險而且容易造成資源洩露。
如果你想要在網頁中呼叫 GUI 相關的 APIs 的操作,網頁的渲染行程必須與主行程進行通訊,請求主行程進行相關的操作。
在 Electron ,我們提供用於在主行程與渲染行程之間通訊的 [ipc][1] 模組。並且也有一個遠端模使用 RPC 通訊方式 [remote][2]
在 Electron我們提供用於在主行程與渲染行程之間通訊的 [ipc](../api/ipc-renderer.md) 模組。並且也有一個遠端模組使用 RPC 通訊方式 [remote](../api/remote.md)
# 打造你第一個 Electron 應用
@ -43,7 +43,7 @@ your-app/
└── index.html
```
`package.json ` 的格式與 Node 的模組完全一樣,並且有個腳本被指定為 `main` 是用來啟動你的應用程式,它運行在主行程上。
`package.json` 的格式與 Node 的模組完全一樣,並且有個腳本被指定為 `main` 是用來啟動你的應用程式,它運行在主行程上。
你應用裡的 一個範例在你的 `package.json` 看起來可能像這樣:
```json
@ -88,7 +88,7 @@ app.on('ready', function() {
  mainWindow.loadUrl('file://' + __dirname + '/index.html');
  // 打開開發者工具
  mainWindow.openDevTools();
  mainWindow.webContents.openDevTools();
  // 當window 被關閉,這個事件會被觸發
  mainWindow.on('closed', function() {
@ -110,8 +110,9 @@ app.on('ready', function() {
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using io.js <script>document.write(process.version)</script>
    and Electron <script>document.write(process.versions['electron'])</script>.
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
  </body>
</html>
```
@ -160,6 +161,17 @@ $ ./Electron.app/Contents/MacOS/Electron your-app/
# 作為版本發行
在你完成了你的應用程式後,你可以依照 [應用部署](https://github.com/atom/electron/blob/master/docs/tutorial/application-distribution.md) 指南發布一個版本,並且運行已經打包好的應用程式。
[1]: https://github.com/atom/electron/blob/master/docs/api/ipc-renderer.md
# 試試這個範例
[2]: https://github.com/atom/electron/blob/master/docs/api/remote.md
Clone 與執行本篇教學的程式碼,它們都放在 [`atom/electron-quick-start`](https://github.com/atom/electron-quick-start) 這個 repository。
**Note**: 執行這個範例需要 [Git](https://git-scm.com) 以及 [Node.js](https://nodejs.org/en/download/) (其中包括 [npm](https://npmjs.org)) 在你的作業系統。
```bash
# Clone the repository
$ git clone https://github.com/atom/electron-quick-start
# Go into the repository
$ cd electron-quick-start
# Install dependencies and run the app
$ npm install && npm start
```

View file

@ -66,7 +66,7 @@
* [Source Code Directory Structure](development/source-code-directory-structure.md)
* [Technical Differences to NW.js (formerly node-webkit)](development/atom-shell-vs-node-webkit.md)
* [Build System Overview](development/build-system-overview.md)
* [Build Instructions (Mac)](development/build-instructions-osx.md)
* [Build Instructions (OS X)](development/build-instructions-osx.md)
* [Build Instructions (Windows)](development/build-instructions-windows.md)
* [Build Instructions (Linux)](development/build-instructions-linux.md)
* [Setting Up Symbol Server in debugger](development/setting-up-symbol-server.md)

View file

@ -99,7 +99,7 @@ You should call `event.preventDefault()` if you want to handle this event.
Returns:
* `event` Event
* `hasVisibleWindows` Bool
* `hasVisibleWindows` Boolean
Emitted when the application is activated, which usually happens when clicks on
the applications's dock icon.
@ -169,7 +169,7 @@ The `app` object has the following methods:
### `app.quit()`
Try to close all windows. The `before-quit` event will emitted first. If all
Try to close all windows. The `before-quit` event will be emitted first. If all
windows are successfully closed, the `will-quit` event will be emitted and by
default the application will terminate.
@ -213,7 +213,7 @@ created by this method. On failure an `Error` is thrown.
You can only override paths of a `name` defined in `app.getPath`.
By default, web pages's cookies and caches will be stored under the `userData`
By default, web pages' cookies and caches will be stored under the `userData`
directory. If you want to change this location, you have to override the
`userData` path before the `ready` event of the `app` module is emitted.
@ -245,7 +245,7 @@ Returns the current application locale.
Resolves the proxy information for `url`. The `callback` will be called with
`callback(proxy)` when the request is performed.
### `app.addRecentDocument(path)`
### `app.addRecentDocument(path)` _OS X_ _Windows_
* `path` String
@ -254,7 +254,7 @@ Adds `path` to the recent documents list.
This list is managed by the OS. On Windows you can visit the list from the task
bar, and on OS X you can visit it from dock menu.
### `app.clearRecentDocuments()`
### `app.clearRecentDocuments()` _OS X_ _Windows_
Clears the recent documents list.
@ -264,7 +264,7 @@ Clears the recent documents list.
Adds `tasks` to the [Tasks][tasks] category of the JumpList on Windows.
`tasks` is an array of `Task` objects in following format:
`tasks` is an array of `Task` objects in the following format:
`Task` Object
* `program` String - Path of the program to execute, usually you should
@ -280,6 +280,70 @@ Adds `tasks` to the [Tasks][tasks] category of the JumpList on Windows.
consists of two or more icons, set this value to identify the icon. If an
icon file consists of one icon, this value is 0.
### `app.allowNTLMCredentialsForAllDomains(allow)`
* `allow` Boolean
Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate
authentication - normally, Electron will only send NTLM/Kerberos credentials for
URLs that fall under "Local Intranet" sites (i.e. are in the same domain as you).
However, this detection often fails when corporate networks are badly configured,
so this lets you co-opt this behavior and enable it for all URLs.
### `app.makeSingleInstance(callback)`
* `callback` Function
This method makes your application a Single Instance Application - instead of
allowing multiple instances of your app to run, this will ensure that only a
single instance of your app is running, and other instances signal this
instance and exit.
`callback` will be called with `callback(argv, workingDirectory)` when a second
instance has been executed. `argv` is an Array of the second instance's command
line arguments, and `workingDirectory` is its current working directory. Usually
applications respond to this by making their primary window focused and
non-minimized.
The `callback` is guaranteed to be executed after the `ready` event of `app`
gets emitted.
This method returns `false` if your process is the primary instance of the
application and your app should continue loading. And returns `true` if your
process has sent its parameters to another instance, and you should immediately
quit.
On OS X the system enforces single instance automatically when users try to open
a second instance of your app in Finder, and the `open-file` and `open-url`
events will be emitted for that. However when users start your app in command
line the system's single instance machanism will be bypassed and you have to
use this method to ensure single instance.
An example of activating the window of primary instance when a second instance
starts:
```js
var myWindow = null;
var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
// Someone tried to run a second instance, we should focus our window
if (myWindow) {
if (myWindow.isMinimized()) myWindow.restore();
myWindow.focus();
}
return true;
});
if (shouldQuit) {
app.quit();
return;
}
// Create myWindow, load the rest of the app, etc...
app.on('ready', function() {
});
```
### `app.commandLine.appendSwitch(switch[, value])`
Append a switch (with optional `value`) to Chromium's command line.

View file

@ -1,106 +1,31 @@
# autoUpdater
**This module has only been implemented for OS X.**
This module provides an interface for the `Squirrel` auto-updater framework.
Check out [atom/grunt-electron-installer](https://github.com/atom/grunt-electron-installer)
to build a Windows installer for your app.
## Platform notices
The `auto-updater` module is a simple wrapper around the
[Squirrel.Mac](https://github.com/Squirrel/Squirrel.Mac) framework.
Though `autoUpdater` provides an uniform API for different platforms, there are
still some subtle differences on each platform.
Squirrel.Mac requires that your `.app` folder is signed using the
[codesign](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/codesign.1.html)
utility for updates to be installed.
### OS X
## Squirrel
On OS X the `autoUpdater` module is built upon [Squirrel.Mac][squirrel-mac], you
don't need any special setup to make it work. For server-side requirements, you
can read [Server Support][server-support].
Squirrel is an OS X framework focused on making application updates **as safe
and transparent as updates to a website**.
### Windows
Instead of publishing a feed of versions from which your app must select,
Squirrel updates to the version your server tells it to. This allows you to
intelligently update your clients based on the request you give to Squirrel.
On Windows you have to install your app into user's machine before you can use
the auto-updater, it is recommended to use [grunt-electron-installer][installer]
module to generate a Windows installer.
Your request can include authentication details, custom headers or a request
body so that your server has the context it needs in order to supply the most
suitable update.
The server-side setup is also different from OS X, you can read the documents of
[Squirrel.Windows][squirrel-windows] to get more details.
The update JSON Squirrel requests should be dynamically generated based on
criteria in the request and whether an update is required. Squirrel relies
on server-side support to determine whether an update is required. See
[Server Support](#server-support).
### Linux
Squirrel's installer is designed to be fault tolerant and ensures that any
updates installed are valid.
## Update Requests
Squirrel is indifferent to the request the client application provides for
update checking. `Accept: application/json` is added to the request headers
because Squirrel is responsible for parsing the response.
For the requirements imposed on the responses and the body format of an update
response, see [Server Support](#server-support).
Your update request must *at least* include a version identifier so that the
server can determine whether an update for this specific version is required. It
may also include other identifying criteria, such as operating system version or
username, to allow the server to deliver as fine grained an update as you
would like.
How you include the version identifier or other criteria is specific to the
server that you are requesting updates from. A common approach is to use query
parameters, like this:
```javascript
// In the main process
var app = require('app');
var autoUpdater = require('auto-updater');
autoUpdater.setFeedUrl('http://mycompany.com/myapp/latest?version=' + app.getVersion());
```
## Server Support
Your server should determine whether an update is required based on the
[Update Request](#update-requests) your client issues.
If an update is required, your server should respond with a status code of
[200 OK](http://tools.ietf.org/html/rfc2616#section-10.2.1) and include the
[update JSON](#update-json-format) in the body. Squirrel **will** download and
install this update, even if the version of the update is the same as the
currently running version. To save redundantly downloading the same version
multiple times your server must not inform the client to update.
If no update is required your server must respond with a status code of
[204 No Content](http://tools.ietf.org/html/rfc2616#section-10.2.5). Squirrel
will check for an update again at the interval you specify.
## Update JSON Format
When an update is available, Squirrel expects the following schema in response
to the update request provided:
```json
{
"url": "http://mycompany.com/myapp/releases/myrelease",
"name": "My Release Name",
"notes": "Theses are some release notes innit",
"pub_date": "2013-09-18T12:29:53+01:00"
}
```
The only required key is "url"; the others are optional.
Squirrel will request "url" with `Accept: application/zip` and only supports
installing ZIP updates. If future update formats are supported their MIME type
will be added to the `Accept` header so that your server can return the
appropriate format.
`pub_date` (if present) must be formatted according to ISO 8601.
## Update server implementations
[Nuts](https://github.com/GitbookIO/nuts) is an open source implementation of the update server described above, it integrates beautifully with GitHub releases. Nuts manages downloads and updates, its compatible with `Squirrel.Mac` and `Squirrel.Windows` so you get cross-platform support out of the box.
There is not built-in support for auto-updater on Linux, it is recommended to
use the distribution's package manager to update your app.
## Events
@ -110,8 +35,7 @@ The `autoUpdater` object emits the following events:
Returns:
* `event` Event
* `message` String
* `error` Error
Emitted when there is an error while updating.
@ -137,10 +61,10 @@ Returns:
* `releaseName` String
* `releaseDate` Date
* `updateUrl` String
* `quitAndUpdate` Function
Emitted when an update has been downloaded. Calling `quitAndUpdate()` will
restart the application and install the update.
Emitted when an update has been downloaded.
On Windows only `releaseName` is available.
## Methods
@ -150,10 +74,20 @@ The `autoUpdater` object has the following methods:
* `url` String
Set the `url` and initialize the auto updater. The `url` cannot be changed
Sets the `url` and initialize the auto updater. The `url` cannot be changed
once it is set.
### `autoUpdater.checkForUpdates()`
Ask the server whether there is an update. You must call `setFeedUrl` before
Asks the server whether there is an update. You must call `setFeedUrl` before
using this API.
### `autoUpdater.quitAndUpdate()`
Restarts the app and install the update after it has been downloaded. It should
only be called after `update-downloaded` has been emitted.
[squirrel-mac]: https://github.com/Squirrel/Squirrel.Mac
[server-support]: https://github.com/Squirrel/Squirrel.Mac#server-support
[squirrel-windows]: https://github.com/Squirrel/Squirrel.Windows
[installer]: https://github.com/atom/grunt-electron-installer

View file

@ -61,6 +61,8 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
key is pressed.
* `enable-larger-than-screen` Boolean - Enable the window to be resized larger
than screen.
* `background-color` String - Window's background color as Hexadecimal value,
like `#66CD00` or `#FFF`. This is only implemented on Linux and Windows.
* `dark-theme` Boolean - Forces using dark theme for the window, only works on
some GTK+3 desktop environments.
* `transparent` Boolean - Makes the window [transparent](frameless-window.md).
@ -550,6 +552,30 @@ Enters or leaves the kiosk mode.
Returns whether the window is in kiosk mode.
### `win.hookWindowMessage(message, callback)` _WINDOWS_
* `message` Integer
* `callback` Function
Hooks a windows message. The `callback` is called when
the message is received in the WndProc.
### `win.isWindowMessageHooked(message)` _WINDOWS_
* `message` Integer
Returns `true` or `false` depending on whether the message is hooked.
### `win.unhookWindowMessage(message)` _WINDOWS_
* `message` Integer
Unhook the window message.
### `win.unhookAllWindowMessages()` _WINDOWS_
Unhooks all of the window messages.
### `win.setRepresentedFilename(filename)` _OS X_
* `filename` String

View file

@ -92,11 +92,17 @@ Enables net log events to be saved and writes them to `path`.
Sets the minimum SSL/TLS version ("tls1", "tls1.1" or "tls1.2") that TLS
fallback will accept.
## --cipher-suite-blacklist=`cipher_suites`
Specify comma-separated list of SSL cipher suites to disable.
## --enable-logging
Prints Chromium's logging into console.
This switch can not be used in `app.commandLine.appendSwitch` since it is parsed earlier than user's app is loaded.
This switch can not be used in `app.commandLine.appendSwitch` since it is parsed
earlier than user's app is loaded, but you can set the `ELECTRON_ENABLE_LOGGING`
environment variable to achieve the same effect.
## --v=`log_level`

View file

@ -59,11 +59,10 @@ ID.
The crash reporter will send the following data to the `submitUrl` as `POST`:
* `rept` String - e.g. 'electron-crash-service'.
* `ver` String - The version of Electron.
* `platform` String - e.g. 'win32'.
* `process_type` String - e.g. 'renderer'.
* `ptime` Number
* `guid` String - e.g. '5e1286fc-da97-479e-918b-6bfb0c3d1c72'
* `_version` String - The version in `package.json`.
* `_productName` String - The product name in the `crashReporter` `options`
object.

View file

@ -1,6 +1,6 @@
# Frameless Window
A frameless window is a window that has no [chrome](https://developer.mozilla.org/en-US/docs/Glossary/Chrome), the parts of the window, like toolbars, that are not a part of the webp page. These are options on the [`BrowserWindow`](browser-window.md) class.
A frameless window is a window that has no [chrome](https://developer.mozilla.org/en-US/docs/Glossary/Chrome), the parts of the window, like toolbars, that are not a part of the web page. These are options on the [`BrowserWindow`](browser-window.md) class.
## Create a frameless window
@ -13,7 +13,7 @@ var BrowserWindow = require('browser-window');
var win = new BrowserWindow({ width: 800, height: 600, frame: false });
```
### Alternatives on Mac
### Alternatives on OS X
On Mac OS X 10.10 Yosemite and newer, there's an alternative way to specify
a chromeless window. Instead of setting `frame` to `false` which disables

View file

@ -154,7 +154,9 @@ Clears the data of web storages.
* `config` String
* `callback` Function - Called when operation is done.
Parses the `config` indicating which proxies to use for the session.
If `config` is a PAC url, it is used directly otherwise
`config` is parsed based on the following rules indicating which
proxies to use for the session.
```
config = scheme-proxies[";"<scheme-proxies>]

View file

@ -36,6 +36,7 @@ Returns:
This event is like `did-finish-load` but emitted when the load failed or was
cancelled, e.g. `window.stop()` is invoked.
The full list of error codes and their meaning is available [here](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h).
### Event: 'did-frame-finish-load'
@ -182,6 +183,7 @@ See [session documentation](session.md) for this object's methods.
* `options` Object (optional), properties:
* `httpReferrer` String - A HTTP Referrer url.
* `userAgent` String - A user agent originating the request.
* `extraHeaders` String - Extra headers separated by "\n"
Loads the `url` in the window, the `url` must contain the protocol prefix,
e.g. the `http://` or `file://`.

View file

@ -1,29 +1,29 @@
# 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.
Since v0.34.0, Electron allows submitting packaged apps to the 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
## 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.
The following steps introduce a simple way to submit your app to Mac App Store.
However, these steps do not ensure sure your app will be approved by Apple; you
still need to read Apple's [Submitting Your App][submitting-your-app] guide on
how to meet the Mac App Store requirements.
### Get certificate
### 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.
To submit your app to the Mac App Store, you first must get a certificate from
Apple. You can follow these [existing guides][nwjs-guide] on web.
### Sign your app
### 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.
After getting the certificate from Apple, you can package your app by following
[Application Distribution](application-distribution.md), and then proceed to
signing your app. This step is basically the same with other programs, but the
key is to sign every dependency of Electron one by one.
First you need to prepare two entitlements files.
First, you need to prepare two entitlements files.
`child.plist`:
@ -53,7 +53,7 @@ First you need to prepare two entitlements files.
</plist>
```
And then sign your app with following script:
And then sign your app with the following script:
```bash
#!/bin/bash
@ -80,32 +80,33 @@ 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.
If you are new to app sandboxing under OS X, you should also read through
Apple's [Enabling App Sandbox][enable-app-sandbox] to have a basic idea, then
add keys for the permissions needed by your app to the entitlements files.
### Upload your app and submit for review
### 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]
After signing your app, you can use Application Loader to upload it to iTunes
Connect for processing, making 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
## Limitations of MAS Build
In order to satisfy requirements for app sandboxing, following modules have been
disabled in MAS build:
In order to satisfy all requirements for app sandboxing, the following modules
have been disabled in the MAS build:
* `crash-reporter`
* `auto-updater`
and following behaviors have been changed:
and the 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.
Also, due to the usage of app sandboxing, the resources which can be accessed by
the app are strictly limited; you can read [App Sandboxing][app-sandboxing] for
more information.
[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

View file

@ -107,7 +107,7 @@ app.on('ready', function() {
mainWindow.loadUrl('file://' + __dirname + '/index.html');
// Open the DevTools.
mainWindow.openDevTools();
mainWindow.webContents.openDevTools();
// Emitted when the window is closed.
mainWindow.on('closed', function() {
@ -130,8 +130,9 @@ Finally the `index.html` is the web page you want to show:
</head>
<body>
<h1>Hello World!</h1>
We are using Node.js <script>document.write(process.version)</script>
and Electron <script>document.write(process.versions['electron'])</script>.
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</body>
</html>
```
@ -188,3 +189,19 @@ it from [here](https://github.com/atom/electron/releases).
After you're done writing your app, you can create a distribution by
following the [Application Distribution](./application-distribution.md) guide
and then executing the packaged app.
### Try this Example
Clone and run the code in this tutorial by using the [`atom/electron-quick-start`](https://github.com/atom/electron-quick-start)
repository.
**Note**: Running this requires [Git](https://git-scm.com) and [Node.js](https://nodejs.org/en/download/) (which includes [npm](https://npmjs.org)) on your system.
```bash
# Clone the repository
$ git clone https://github.com/atom/electron-quick-start
# Go into the repository
$ cd electron-quick-start
# Install dependencies and run the app
$ npm install && npm start
```

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