Merge pull request #2 from atom/master

Update from original
This commit is contained in:
Eran Tiktin 2015-09-04 21:27:32 +03:00
commit 090c817ac9
179 changed files with 5024 additions and 2968 deletions

View file

@ -6,7 +6,7 @@
### [Electron](https://github.com/atom/electron/) 한국어 참조문서
:zap: *이전까지 Atom Shell로 알려져 있었습니다* :zap:
:zap: *프레임워크 이름이 Atom Shell에서 Electron으로 바뀌었습니다* :zap:
Electron 프레임워크는 JavaScript, HTML 그리고 CSS를 사용하여 Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주는 프레임워크입니다. 이 프레임워크는 [io.js](http://iojs.org) 와
[Chromium](http://www.chromium.org)을 기반으로 만들어 졌으며 [Atom Editor](https://github.com/atom/atom)에 사용되고 있습니다.
@ -36,7 +36,7 @@ npm install electron-prebuilt --save-dev
[Docs](https://github.com/atom/electron/tree/master/docs/README.md)에 개발 가이드와 API 레퍼런스가 있습니다.
Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법도 문서에 포함되어 있으니 참고하시기 바랍니다.
## 참조 문서(번역)
## 참조 문서 (번역)
- [한국어](https://github.com/atom/electron/tree/master/docs-translations/ko)
- [일본어](https://github.com/atom/electron/tree/master/docs-translations/jp)

View file

@ -48,6 +48,8 @@ contains documents describing how to build and contribute to Electron.
- [Korean](https://github.com/atom/electron/tree/master/docs-translations/ko)
- [Japanese](https://github.com/atom/electron/tree/master/docs-translations/jp)
- [Spanish](https://github.com/atom/electron/tree/master/docs-translations/es)
- [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)
## Community

View file

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

View file

@ -33,6 +33,7 @@
#include "atom/app/node_main.h"
#include "atom/common/atom_command_line.h"
#include "base/at_exit.h"
#include "base/i18n/icu_util.h"
#if defined(OS_WIN)
@ -134,6 +135,7 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
if (env->GetVar("ATOM_SHELL_INTERNAL_RUN_AS_NODE", &node_indicator) &&
node_indicator == "1") {
// Now that argv conversion is done, we can finally start.
base::AtExitManager atexit_manager;
base::i18n::InitializeICU();
return atom::NodeMain(argc, argv);
} else if (env->GetVar("ATOM_SHELL_INTERNAL_CRASH_SERVICE",
@ -165,6 +167,7 @@ int main(int argc, const char* argv[]) {
char* node_indicator = getenv("ATOM_SHELL_INTERNAL_RUN_AS_NODE");
if (node_indicator != NULL && strcmp(node_indicator, "1") == 0) {
base::i18n::InitializeICU();
base::AtExitManager atexit_manager;
return atom::NodeMain(argc, const_cast<char**>(argv));
}

View file

@ -4,10 +4,12 @@
#include "atom/app/node_main.h"
#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 "base/thread_task_runner_handle.h"
#include "gin/array_buffer.h"
#include "gin/public/isolate_holder.h"
#include "gin/v8_initializer.h"
@ -24,14 +26,20 @@ int NodeMain(int argc, char *argv[]) {
int exit_code = 1;
{
// Feed gin::PerIsolateData with a task runner.
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;
node::Environment* env = node::CreateEnvironment(
gin_env.isolate(), uv_default_loop(), gin_env.context(), argc, argv,
gin_env.isolate(), loop, gin_env.context(), argc, argv,
exec_argc, exec_argv);
// Start our custom debugger implementation.

View file

@ -0,0 +1,55 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/app/uv_task_runner.h"
#include "base/stl_util.h"
namespace atom {
UvTaskRunner::UvTaskRunner(uv_loop_t* loop) : loop_(loop) {
}
UvTaskRunner::~UvTaskRunner() {
for (auto& iter : tasks_) {
uv_unref(reinterpret_cast<uv_handle_t*>(iter.first));
delete iter.first;
}
}
bool UvTaskRunner::PostDelayedTask(const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) {
uv_timer_t* timer = new uv_timer_t;
timer->data = this;
uv_timer_init(loop_, timer);
uv_timer_start(timer, UvTaskRunner::OnTimeout, delay.InMilliseconds(), 0);
tasks_[timer] = task;
return true;
}
bool UvTaskRunner::RunsTasksOnCurrentThread() const {
return true;
}
bool UvTaskRunner::PostNonNestableDelayedTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) {
return PostDelayedTask(from_here, task, delay);;
}
// static
void UvTaskRunner::OnTimeout(uv_timer_t* timer) {
UvTaskRunner* self = static_cast<UvTaskRunner*>(timer->data);
if (!ContainsKey(self->tasks_, timer))
return;
self->tasks_[timer].Run();
self->tasks_.erase(timer);
uv_unref(reinterpret_cast<uv_handle_t*>(timer));
delete timer;
}
} // namespace atom

44
atom/app/uv_task_runner.h Normal file
View file

@ -0,0 +1,44 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_APP_UV_TASK_RUNNER_H_
#define ATOM_APP_UV_TASK_RUNNER_H_
#include <map>
#include "base/callback.h"
#include "base/single_thread_task_runner.h"
#include "vendor/node/deps/uv/include/uv.h"
namespace atom {
// TaskRunner implementation that posts tasks into libuv's default loop.
class UvTaskRunner : public base::SingleThreadTaskRunner {
public:
explicit UvTaskRunner(uv_loop_t* loop);
~UvTaskRunner() override;
// base::SingleThreadTaskRunner:
bool PostDelayedTask(const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) override;
bool RunsTasksOnCurrentThread() const override;
bool PostNonNestableDelayedTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) override;
private:
static void OnTimeout(uv_timer_t* timer);
uv_loop_t* loop_;
std::map<uv_timer_t*, base::Closure> tasks_;
DISALLOW_COPY_AND_ASSIGN(UvTaskRunner);
};
} // namespace atom
#endif // ATOM_APP_UV_TASK_RUNNER_H_

View file

@ -19,27 +19,19 @@ using content::TracingController;
namespace mate {
template<>
struct Converter<base::trace_event::CategoryFilter> {
struct Converter<base::trace_event::TraceConfig> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
base::trace_event::CategoryFilter* out) {
std::string filter;
if (!ConvertFromV8(isolate, val, &filter))
return false;
*out = base::trace_event::CategoryFilter(filter);
return true;
}
};
template<>
struct Converter<base::trace_event::TraceOptions> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
base::trace_event::TraceOptions* out) {
std::string options;
base::trace_event::TraceConfig* out) {
Dictionary options;
if (!ConvertFromV8(isolate, val, &options))
return false;
return out->SetFromString(options);
std::string category_filter, trace_options;
if (!options.Get("categoryFilter", &category_filter) ||
!options.Get("traceOptions", &trace_options))
return false;
*out = base::trace_event::TraceConfig(category_filter, trace_options);
return true;
}
};

View file

@ -107,6 +107,10 @@ void Menu::SetSublabel(int index, const base::string16& sublabel) {
model_->SetSublabel(index, sublabel);
}
void Menu::SetRole(int index, const base::string16& role) {
model_->SetRole(index, role);
}
void Menu::Clear() {
model_->Clear();
}
@ -154,6 +158,7 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
.SetMethod("insertSubMenu", &Menu::InsertSubMenuAt)
.SetMethod("setIcon", &Menu::SetIcon)
.SetMethod("setSublabel", &Menu::SetSublabel)
.SetMethod("setRole", &Menu::SetRole)
.SetMethod("clear", &Menu::Clear)
.SetMethod("getIndexOfCommandId", &Menu::GetIndexOfCommandId)
.SetMethod("getItemCount", &Menu::GetItemCount)

View file

@ -73,6 +73,7 @@ class Menu : public mate::Wrappable,
Menu* menu);
void SetIcon(int index, const gfx::Image& image);
void SetSublabel(int index, const base::string16& sublabel);
void SetRole(int index, const base::string16& role);
void Clear();
int GetIndexOfCommandId(int command_id);
int GetItemCount() const;

View file

@ -9,6 +9,7 @@
#include "atom/browser/api/atom_api_cookies.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
@ -101,6 +102,19 @@ struct Converter<ClearStorageDataOptions> {
}
};
template<>
struct Converter<content::DownloadItem*> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
content::DownloadItem* val) {
mate::Dictionary dict(isolate, v8::Object::New(isolate));
dict.Set("url", val->GetURL());
dict.Set("filename", val->GetSuggestedFilename());
dict.Set("mimeType", val->GetMimeType());
dict.Set("hasUserGesture", val->HasUserGesture());
return dict.GetHandle();
}
};
} // namespace mate
namespace atom {
@ -109,6 +123,10 @@ namespace api {
namespace {
// The wrapSession funtion which is implemented in JavaScript
using WrapSessionCallback = base::Callback<void(v8::Local<v8::Value>)>;
WrapSessionCallback g_wrap_session;
class ResolveProxyHelper {
public:
ResolveProxyHelper(AtomBrowserContext* browser_context,
@ -215,9 +233,28 @@ void SetProxyInIO(net::URLRequestContextGetter* getter,
Session::Session(AtomBrowserContext* browser_context)
: browser_context_(browser_context) {
AttachAsUserData(browser_context);
// Observe DownloadManger to get download notifications.
auto download_manager =
content::BrowserContext::GetDownloadManager(browser_context);
download_manager->AddObserver(this);
}
Session::~Session() {
auto download_manager =
content::BrowserContext::GetDownloadManager(browser_context_);
download_manager->RemoveObserver(this);
}
void Session::OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) {
auto web_contents = item->GetWebContents();
bool prevent_default = Emit("will-download", item,
api::WebContents::CreateFrom(isolate(),
web_contents));
if (prevent_default) {
item->Cancel(true);
item->Remove();
}
}
void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) {
@ -288,9 +325,33 @@ mate::Handle<Session> Session::CreateFrom(
if (existing)
return mate::CreateHandle(isolate, static_cast<Session*>(existing));
return mate::CreateHandle(isolate, new Session(browser_context));
auto handle = mate::CreateHandle(isolate, new Session(browser_context));
g_wrap_session.Run(handle.ToV8());
return handle;
}
void SetWrapSession(const WrapSessionCallback& callback) {
g_wrap_session = callback;
}
void ClearWrapSession() {
g_wrap_session.Reset();
}
} // namespace api
} // namespace atom
namespace {
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
v8::Isolate* isolate = context->GetIsolate();
mate::Dictionary dict(isolate, exports);
dict.SetMethod("_setWrapSession", &atom::api::SetWrapSession);
dict.SetMethod("_clearWrapSession", &atom::api::ClearWrapSession);
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_session, Initialize)

View file

@ -8,6 +8,7 @@
#include <string>
#include "atom/browser/api/trackable_object.h"
#include "content/public/browser/download_manager.h"
#include "native_mate/handle.h"
#include "net/base/completion_callback.h"
@ -27,7 +28,8 @@ class AtomBrowserContext;
namespace api {
class Session: public mate::TrackableObject<Session> {
class Session: public mate::TrackableObject<Session>,
public content::DownloadManager::Observer {
public:
using ResolveProxyCallback = base::Callback<void(std::string)>;
@ -41,6 +43,10 @@ class Session: public mate::TrackableObject<Session> {
explicit Session(AtomBrowserContext* browser_context);
~Session();
// content::DownloadManager::Observer:
void OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) override;
// mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;

View file

@ -159,11 +159,19 @@ WebContents::WebContents(const mate::Dictionary& options) {
type_ = is_guest ? WEB_VIEW : BROWSER_WINDOW;
auto browser_context = AtomBrowserMainParts::Get()->browser_context();
content::BrowserContext* browser_context =
AtomBrowserMainParts::Get()->browser_context();
content::WebContents* web_contents;
if (is_guest) {
content::SiteInstance* site_instance = content::SiteInstance::CreateForURL(
browser_context, GURL("chrome-guest://fake-host"));
GURL guest_site;
options.Get("partition", &guest_site);
// use hosts' browser_context when no partition is specified.
if (!guest_site.query().empty()) {
browser_context = AtomBrowserMainParts::Get()
->GetBrowserContextForPartition(guest_site);
}
auto site_instance =
content::SiteInstance::CreateForURL(browser_context, guest_site);
content::WebContents::CreateParams params(browser_context, site_instance);
guest_delegate_.reset(new WebViewGuestDelegate);
params.guest_delegate = guest_delegate_.get();
@ -217,7 +225,7 @@ bool WebContents::ShouldCreateWebContents(
int route_id,
int main_frame_route_id,
WindowContainerType window_container_type,
const base::string16& frame_name,
const std::string& frame_name,
const GURL& target_url,
const std::string& partition_id,
content::SessionStorageNamespace* session_storage_namespace) {
@ -362,14 +370,16 @@ void WebContents::DidFailProvisionalLoad(
content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
const base::string16& error_description) {
const base::string16& error_description,
bool was_ignored_by_handler) {
Emit("did-fail-load", error_code, error_description);
}
void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
const base::string16& error_description) {
const base::string16& error_description,
bool was_ignored_by_handler) {
Emit("did-fail-load", error_code, error_description);
}

View file

@ -10,8 +10,8 @@
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/common_web_contents_delegate.h"
#include "content/public/common/favicon_url.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/favicon_url.h"
#include "native_mate/handle.h"
#include "ui/gfx/image/image.h"
@ -135,7 +135,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
int route_id,
int main_frame_route_id,
WindowContainerType window_container_type,
const base::string16& frame_name,
const std::string& frame_name,
const GURL& target_url,
const std::string& partition_id,
content::SessionStorageNamespace* session_storage_namespace) override;
@ -170,11 +170,13 @@ class WebContents : public mate::TrackableObject<WebContents>,
void DidFailLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
const base::string16& error_description) override;
const base::string16& error_description,
bool was_ignored_by_handler) override;
void DidFailProvisionalLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
const base::string16& error_description) override;
const base::string16& error_description,
bool was_ignored_by_handler) override;
void DidStartLoading() override;
void DidStopLoading() override;
void DidGetResourceResponseStart(

View file

@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/web_view_constants.h"
#include "atom/browser/web_view_manager.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "content/public/browser/browser_context.h"
@ -34,16 +35,19 @@ struct Converter<atom::WebViewManager::WebViewInfo> {
return false;
GURL preload_url;
if (!options.Get("preloadUrl", &preload_url))
if (!options.Get(atom::web_view::kPreloadUrl, &preload_url))
return false;
if (!preload_url.is_empty() &&
!net::FileURLToFilePath(preload_url, &(out->preload_script)))
return false;
return options.Get("nodeIntegration", &(out->node_integration)) &&
options.Get("plugins", &(out->plugins)) &&
options.Get("disableWebSecurity", &(out->disable_web_security));
return options.Get(atom::web_view::kNodeIntegration,
&(out->node_integration)) &&
options.Get(atom::web_view::kPlugins, &(out->plugins)) &&
options.Get(atom::web_view::kPartitionId, &(out->partition_id)) &&
options.Get(atom::web_view::kDisableWebSecurity,
&(out->disable_web_security));
}
};
@ -67,12 +71,15 @@ void AddGuest(int guest_instance_id,
content::WebContents* guest_web_contents,
atom::WebViewManager::WebViewInfo info) {
auto manager = GetWebViewManager(embedder);
if (manager) {
info.guest_instance_id = guest_instance_id;
info.embedder = embedder;
if (manager)
manager->AddGuest(guest_instance_id, element_instance_id, embedder,
guest_web_contents, info);
}
guest_web_contents);
info.guest_instance_id = guest_instance_id;
info.embedder = embedder;
auto data = new atom::WebViewManager::WebViewInfoUserData(info);
guest_web_contents->SetUserData(
atom::web_view::kWebViewInfoKeyName, data);
}
void RemoveGuest(content::WebContents* embedder, int guest_instance_id) {

View file

@ -1,10 +1,15 @@
EventEmitter = require('events').EventEmitter
bindings = process.atomBinding 'app'
sessionBindings = process.atomBinding 'session'
app = bindings.app
app.__proto__ = EventEmitter.prototype
wrapSession = (session) ->
# session is an Event Emitter.
session.__proto__ = EventEmitter.prototype
app.setApplicationMenu = (menu) ->
require('menu').setApplicationMenu menu
@ -41,5 +46,9 @@ app.getDataPath = -> @getPath 'userData'
app.setDataPath = (path) -> @setPath 'userData', path
app.resolveProxy = -> @defaultSession.resolveProxy.apply @defaultSession, arguments
# Session wrapper.
sessionBindings._setWrapSession wrapSession
process.once 'exit', sessionBindings._clearWrapSession
# Only one App object pemitted.
module.exports = app

View file

@ -62,6 +62,12 @@ BrowserWindow::loadUrl = -> @webContents.loadUrl.apply @webContents, arguments
BrowserWindow::send = -> @webContents.send.apply @webContents, arguments
# Be compatible with old API.
BrowserWindow::undo = -> @webContents.undo()
BrowserWindow::redo = -> @webContents.redo()
BrowserWindow::cut = -> @webContents.cut()
BrowserWindow::copy = -> @webContents.copy()
BrowserWindow::paste = -> @webContents.paste()
BrowserWindow::selectAll = -> @webContents.selectAll()
BrowserWindow::restart = -> @webContents.reload()
BrowserWindow::getUrl = -> @webContents.getUrl()
BrowserWindow::reload = -> @webContents.reload.apply @webContents, arguments

View file

@ -3,18 +3,30 @@ v8Util = process.atomBinding 'v8_util'
nextCommandId = 0
# Maps role to methods of webContents
rolesMap =
undo: 'undo'
redo: 'redo'
cut: 'cut'
copy: 'copy'
paste: 'paste'
selectall: 'selectAll'
minimize: 'minimize'
close: 'close'
class MenuItem
@types = ['normal', 'separator', 'submenu', 'checkbox', 'radio']
constructor: (options) ->
Menu = require 'menu'
{click, @selector, @type, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked, @submenu} = options
{click, @selector, @type, @role, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked, @submenu} = options
@type = 'submenu' if not @type? and @submenu?
throw new Error('Invalid submenu') if @type is 'submenu' and @submenu?.constructor isnt Menu
@overrideReadOnlyProperty 'type', 'normal'
@overrideReadOnlyProperty 'role'
@overrideReadOnlyProperty 'accelerator'
@overrideReadOnlyProperty 'icon'
@overrideReadOnlyProperty 'submenu'
@ -27,12 +39,14 @@ class MenuItem
throw new Error("Unknown menu type #{@type}") if MenuItem.types.indexOf(@type) is -1
@commandId = ++nextCommandId
@click = =>
@click = (focusedWindow) =>
# Manually flip the checked flags when clicked.
@checked = !@checked if @type in ['checkbox', 'radio']
if typeof click is 'function'
click this, BrowserWindow.getFocusedWindow()
if @role and rolesMap[@role] and process.platform isnt 'darwin'
focusedWindow?[rolesMap[@role]]()
else if typeof click is 'function'
click this, focusedWindow
else if typeof @selector is 'string'
Menu.sendActionToFirstResponder @selector

View file

@ -67,7 +67,8 @@ Menu::_init = ->
isCommandIdVisible: (commandId) => @commandsMap[commandId]?.visible
getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator
getIconForCommandId: (commandId) => @commandsMap[commandId]?.icon
executeCommand: (commandId) => @commandsMap[commandId]?.click()
executeCommand: (commandId) =>
@commandsMap[commandId]?.click BrowserWindow.getFocusedWindow()
menuWillShow: =>
# Make sure radio groups have at least one menu item seleted.
for id, group of @groupsMap
@ -115,6 +116,7 @@ Menu::insert = (pos, item) ->
@setSublabel pos, item.sublabel if item.sublabel?
@setIcon pos, item.icon if item.icon?
@setRole pos, item.role if item.role?
# Make menu accessable to items.
item.overrideReadOnlyProperty 'menu', this

View file

@ -16,6 +16,7 @@
#include "atom/browser/browser.h"
#include "atom/browser/native_window.h"
#include "atom/browser/web_view_manager.h"
#include "atom/browser/web_view_constants.h"
#include "atom/browser/window_list.h"
#include "atom/common/options_switches.h"
#include "base/command_line.h"
@ -74,8 +75,12 @@ ProcessOwner GetProcessOwner(int process_id,
return OWNER_NATIVE_WINDOW;
// Then search for guest WebContents.
if (WebViewManager::GetInfoForWebContents(web_contents, info))
auto data = static_cast<WebViewManager::WebViewInfoUserData*>(
web_contents->GetUserData(web_view::kWebViewInfoKeyName));
if (data) {
*info = data->web_view_info();
return OWNER_GUEST_WEB_CONTENTS;
}
return OWNER_NONE;
}
@ -155,9 +160,10 @@ void AtomBrowserClient::OverrideWebkitPrefs(
// Custom preferences of guest page.
auto web_contents = content::WebContents::FromRenderViewHost(host);
WebViewManager::WebViewInfo info;
if (WebViewManager::GetInfoForWebContents(web_contents, &info)) {
prefs->web_security_enabled = !info.disable_web_security;
auto info = static_cast<WebViewManager::WebViewInfoUserData*>(
web_contents->GetUserData(web_view::kWebViewInfoKeyName));
if (info) {
prefs->web_security_enabled = !info->web_view_info().disable_web_security;
return;
}

View file

@ -7,12 +7,14 @@
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/atom_browser_client.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/bridge_task_runner.h"
#include "atom/browser/browser.h"
#include "atom/browser/javascript_environment.h"
#include "atom/browser/node_debugger.h"
#include "atom/common/api/atom_bindings.h"
#include "atom/common/node_bindings.h"
#include "base/command_line.h"
#include "base/thread_task_runner_handle.h"
#include "chrome/browser/browser_process.h"
#include "v8/include/v8-debug.h"
@ -24,6 +26,23 @@
namespace atom {
namespace {
const base::FilePath::CharType kStoragePartitionDirname[] = "Partitions";
void GetStoragePartitionConfig(const GURL& partition,
base::FilePath* partition_path,
bool* in_memory,
std::string* id) {
*in_memory = (partition.path() != "/persist");
net::UnescapeRule::Type flags =
net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS;
*id = net::UnescapeURLComponent(partition.query(), flags);
*partition_path = base::FilePath(kStoragePartitionDirname).AppendASCII(*id);
}
} // namespace
// static
AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
@ -48,6 +67,21 @@ AtomBrowserMainParts* AtomBrowserMainParts::Get() {
return self_;
}
content::BrowserContext* AtomBrowserMainParts::GetBrowserContextForPartition(
const GURL& partition) {
std::string id;
bool in_memory;
base::FilePath partition_path;
GetStoragePartitionConfig(partition, &partition_path, &in_memory, &id);
if (browser_context_map_.contains(id))
return browser_context_map_.get(id);
scoped_ptr<brightray::BrowserContext> browser_context(CreateBrowserContext());
browser_context->Initialize(partition_path.value(), in_memory);
browser_context_map_.set(id, browser_context.Pass());
return browser_context_map_.get(id);
}
void AtomBrowserMainParts::RegisterDestructionCallback(
const base::Closure& callback) {
destruction_callbacks_.push_back(callback);
@ -64,9 +98,17 @@ void AtomBrowserMainParts::PostEarlyInitialization() {
SetDPIFromGSettings();
#endif
// 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);
{
// 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);
}
node_bindings_->Initialize();

View file

@ -6,10 +6,14 @@
#define ATOM_BROWSER_ATOM_BROWSER_MAIN_PARTS_H_
#include <list>
#include <map>
#include <string>
#include "base/callback.h"
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/timer/timer.h"
#include "brightray/browser/browser_main_parts.h"
#include "content/public/browser/browser_context.h"
class BrowserProcess;
@ -20,6 +24,7 @@ class Browser;
class JavascriptEnvironment;
class NodeBindings;
class NodeDebugger;
class BridgeTaskRunner;
class AtomBrowserMainParts : public brightray::BrowserMainParts {
public:
@ -28,6 +33,10 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
static AtomBrowserMainParts* Get();
// Returns the BrowserContext associated with the partition.
content::BrowserContext* GetBrowserContextForPartition(
const GURL& partition);
// Register a callback that should be destroyed before JavaScript environment
// gets destroyed.
void RegisterDestructionCallback(const base::Closure& callback);
@ -54,6 +63,10 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
// A fake BrowserProcess object that used to feed the source code from chrome.
scoped_ptr<BrowserProcess> fake_browser_process_;
// The gin::PerIsolateData requires a task runner to create, so we feed it
// with a task runner that will post all work to main loop.
scoped_refptr<BridgeTaskRunner> bridge_task_runner_;
scoped_ptr<Browser> browser_;
scoped_ptr<JavascriptEnvironment> js_env_;
scoped_ptr<NodeBindings> node_bindings_;
@ -65,6 +78,10 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
// List of callbacks should be executed before destroying JS env.
std::list<base::Closure> destruction_callbacks_;
// partition_id => browser_context
base::ScopedPtrHashMap<std::string, scoped_ptr<brightray::BrowserContext>>
browser_context_map_;
static AtomBrowserMainParts* self_;
DISALLOW_COPY_AND_ASSIGN(AtomBrowserMainParts);

View file

@ -0,0 +1,42 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/bridge_task_runner.h"
#include "base/message_loop/message_loop.h"
namespace atom {
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;
return message_loop->task_runner()->PostDelayedTask(from_here, task, delay);
}
bool BridgeTaskRunner::RunsTasksOnCurrentThread() const {
auto message_loop = base::MessageLoop::current();
if (!message_loop)
return false;
return message_loop->task_runner()->RunsTasksOnCurrentThread();
}
bool BridgeTaskRunner::PostNonNestableDelayedTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) {
auto message_loop = base::MessageLoop::current();
if (!message_loop)
return false;
return message_loop->task_runner()->PostNonNestableDelayedTask(
from_here, task, delay);
}
} // namespace atom

View file

@ -0,0 +1,35 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
#define ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
#include "base/single_thread_task_runner.h"
namespace atom {
// Post all tasks to the current message loop's task runner if available,
// otherwise fail silently.
class BridgeTaskRunner : public base::SingleThreadTaskRunner {
public:
BridgeTaskRunner() {}
~BridgeTaskRunner() override {}
// base::SingleThreadTaskRunner:
bool PostDelayedTask(const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) override;
bool RunsTasksOnCurrentThread() const override;
bool PostNonNestableDelayedTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) override;
private:
DISALLOW_COPY_AND_ASSIGN(BridgeTaskRunner);
};
} // namespace atom
#endif // ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_

View file

@ -153,7 +153,7 @@ class Browser : public WindowListObserver {
void OnWindowAllClosed() override;
// Observers of the browser.
ObserverList<BrowserObserver> observers_;
base::ObserverList<BrowserObserver> observers_;
// Whether "ready" event has been emitted.
bool is_ready_;

View file

@ -36,238 +36,176 @@ app.once('ready', function() {
if (Menu.getApplicationMenu())
return;
var template;
var template = [
{
label: 'Edit',
submenu: [
{
label: 'Undo',
accelerator: 'CmdOrCtrl+Z',
role: 'undo'
},
{
label: 'Redo',
accelerator: 'Shift+CmdOrCtrl+Z',
role: 'redo'
},
{
type: 'separator'
},
{
label: 'Cut',
accelerator: 'CmdOrCtrl+X',
role: 'cut'
},
{
label: 'Copy',
accelerator: 'CmdOrCtrl+C',
role: 'copy'
},
{
label: 'Paste',
accelerator: 'CmdOrCtrl+V',
role: 'paste'
},
{
label: 'Select All',
accelerator: 'CmdOrCtrl+A',
role: 'selectall'
},
]
},
{
label: 'View',
submenu: [
{
label: 'Reload',
accelerator: 'CmdOrCtrl+R',
click: function(item, focusedWindow) {
if (focusedWindow)
focusedWindow.reload();
}
},
{
label: 'Toggle Full Screen',
accelerator: (function() {
if (process.platform == 'darwin')
return 'Ctrl+Command+F';
else
return 'F11';
})(),
click: function(item, focusedWindow) {
if (focusedWindow)
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
}
},
{
label: 'Toggle Developer Tools',
accelerator: (function() {
if (process.platform == 'darwin')
return 'Alt+Command+I';
else
return 'Ctrl+Shift+I';
})(),
click: function(item, focusedWindow) {
if (focusedWindow)
focusedWindow.toggleDevTools();
}
},
]
},
{
label: 'Window',
role: 'window',
submenu: [
{
label: 'Minimize',
accelerator: 'CmdOrCtrl+M',
role: 'minimize'
},
{
label: 'Close',
accelerator: 'CmdOrCtrl+W',
role: 'close'
},
]
},
{
label: 'Help',
role: 'help',
submenu: [
{
label: 'Learn More',
click: function() { require('shell').openExternal('http://electron.atom.io') }
},
{
label: 'Documentation',
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
},
{
label: 'Community Discussions',
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
},
{
label: 'Search Issues',
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
}
]
},
];
if (process.platform == 'darwin') {
template = [
template.unshift({
label: 'Electron',
submenu: [
{
label: 'About Electron',
role: 'about'
},
{
type: 'separator'
},
{
label: 'Services',
role: 'services',
submenu: []
},
{
type: 'separator'
},
{
label: 'Hide Electron',
accelerator: 'Command+H',
role: 'hide'
},
{
label: 'Hide Others',
accelerator: 'Command+Shift+H',
role: 'hideothers:'
},
{
label: 'Show All',
role: 'unhide:'
},
{
type: 'separator'
},
{
label: 'Quit',
accelerator: 'Command+Q',
click: function() { app.quit(); }
},
]
});
template[3].submenu.push(
{
label: 'Electron',
submenu: [
{
label: 'About Electron',
selector: 'orderFrontStandardAboutPanel:'
},
{
type: 'separator'
},
{
label: 'Services',
submenu: []
},
{
type: 'separator'
},
{
label: 'Hide Electron',
accelerator: 'Command+H',
selector: 'hide:'
},
{
label: 'Hide Others',
accelerator: 'Command+Shift+H',
selector: 'hideOtherApplications:'
},
{
label: 'Show All',
selector: 'unhideAllApplications:'
},
{
type: 'separator'
},
{
label: 'Quit',
accelerator: 'Command+Q',
click: function() { app.quit(); }
},
]
type: 'separator'
},
{
label: 'Edit',
submenu: [
{
label: 'Undo',
accelerator: 'Command+Z',
selector: 'undo:'
},
{
label: 'Redo',
accelerator: 'Shift+Command+Z',
selector: 'redo:'
},
{
type: 'separator'
},
{
label: 'Cut',
accelerator: 'Command+X',
selector: 'cut:'
},
{
label: 'Copy',
accelerator: 'Command+C',
selector: 'copy:'
},
{
label: 'Paste',
accelerator: 'Command+V',
selector: 'paste:'
},
{
label: 'Select All',
accelerator: 'Command+A',
selector: 'selectAll:'
},
]
},
{
label: 'View',
submenu: [
{
label: 'Reload',
accelerator: 'Command+R',
click: function() {
var focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow)
focusedWindow.reload();
}
},
{
label: 'Toggle Full Screen',
accelerator: 'Ctrl+Command+F',
click: function() {
var focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow)
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
}
},
{
label: 'Toggle Developer Tools',
accelerator: 'Alt+Command+I',
click: function() {
var focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow)
focusedWindow.toggleDevTools();
}
},
]
},
{
label: 'Window',
submenu: [
{
label: 'Minimize',
accelerator: 'Command+M',
selector: 'performMiniaturize:'
},
{
label: 'Close',
accelerator: 'Command+W',
selector: 'performClose:'
},
{
type: 'separator'
},
{
label: 'Bring All to Front',
selector: 'arrangeInFront:'
},
]
},
{
label: 'Help',
submenu: [
{
label: 'Learn More',
click: function() { require('shell').openExternal('http://electron.atom.io') }
},
{
label: 'Documentation',
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
},
{
label: 'Community Discussions',
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
},
{
label: 'Search Issues',
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
}
]
label: 'Bring All to Front',
role: 'front'
}
];
} else {
template = [
{
label: '&File',
submenu: [
{
label: '&Open',
accelerator: 'Ctrl+O',
},
{
label: '&Close',
accelerator: 'Ctrl+W',
click: function() {
var focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow)
focusedWindow.close();
}
},
]
},
{
label: '&View',
submenu: [
{
label: '&Reload',
accelerator: 'Ctrl+R',
click: function() {
var focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow)
focusedWindow.reload();
}
},
{
label: 'Toggle &Full Screen',
accelerator: 'F11',
click: function() {
var focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow)
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
}
},
{
label: 'Toggle &Developer Tools',
accelerator: 'Shift+Ctrl+I',
click: function() {
var focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow)
focusedWindow.toggleDevTools();
}
},
]
},
{
label: 'Help',
submenu: [
{
label: 'Learn More',
click: function() { require('shell').openExternal('http://electron.atom.io') }
},
{
label: 'Documentation',
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
},
{
label: 'Community Discussions',
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
},
{
label: 'Search Issues',
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
}
]
}
];
);
}
var menu = Menu.buildFromTemplate(template);

View file

@ -38,12 +38,29 @@ moveLastToFirst = (list) ->
getNextInstanceId = (webContents) ->
++nextInstanceId
# Generate URL encoded partition id.
getPartitionId = (partition) ->
# Guest site url will be chrome-guest://fake-host/{persist}?{partitionId}
partitionId = "chrome-guest://fake-host/"
if partition
persist = partition.startsWith('persist:')
if persist
partition = partition.substring('persist:'.length)
partitionId += 'persist?'
else
# Just to differentiate from same persistant ID
partition += "_temp"
partitionId += '?'
partitionId += encodeURIComponent(partition)
return partitionId
# Create a new guest instance.
createGuest = (embedder, params) ->
webViewManager ?= process.atomBinding 'web_view_manager'
id = getNextInstanceId embedder
guest = webContents.create {isGuest: true, embedder}
partitionId = getPartitionId params.partition
guest = webContents.create {isGuest: true, partition: partitionId, embedder}
guestInstances[id] = {guest, embedder}
# Destroy guest when the embedder is gone or navigated.
@ -120,6 +137,7 @@ attachGuest = (embedder, elementInstanceId, guestInstanceId, params) ->
plugins: params.plugins
disableWebSecurity: params.disablewebsecurity
preloadUrl: params.preload ? ''
partitionId: getPartitionId(params.partition)
guest.attachParams = params
embedderElementsMap[key] = guestInstanceId

View file

@ -57,13 +57,19 @@ ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', (event, guestId, me
if guestContents?.getUrl().indexOf(targetOrigin) is 0 or targetOrigin is '*'
guestContents.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', message, targetOrigin
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', (event, message, targetOrigin) ->
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', (event, guestId, message, targetOrigin, sourceOrigin) ->
embedder = v8Util.getHiddenValue event.sender, 'embedder'
if embedder?.getUrl().indexOf(targetOrigin) is 0 or targetOrigin is '*'
embedder.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', message, targetOrigin
embedder.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', guestId, message, sourceOrigin
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', (event, guestId, method, args...) ->
BrowserWindow.fromId(guestId)?.webContents?[method] args...
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_IS_GUEST_WINDOW', (event) ->
event.returnValue = v8Util.getHiddenValue(event.sender, 'embedder') isnt undefined
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_GET_GUEST_ID', (event) ->
embedder = v8Util.getHiddenValue event.sender, 'embedder'
if embedder?
guest = BrowserWindow.fromWebContents event.sender
if guest?
event.returnValue = guest.id
return
event.returnValue = null

View file

@ -310,7 +310,7 @@ class NativeWindow : public content::WebContentsObserver,
brightray::InspectableWebContents* inspectable_web_contents_;
// Observers of this window.
ObserverList<NativeWindowObserver> observers_;
base::ObserverList<NativeWindowObserver> observers_;
base::WeakPtrFactory<NativeWindow> weak_factory_;

View file

@ -172,7 +172,7 @@ bool URLRequestAsarJob::IsRedirectResponse(GURL* location,
#if defined(OS_WIN)
// Follow a Windows shortcut.
// We just resolve .lnk file, ignore others.
if (!LowerCaseEqualsASCII(file_path_.Extension(), ".lnk"))
if (!base::LowerCaseEqualsASCII(file_path_.Extension(), ".lnk"))
return false;
base::FilePath new_path = file_path_;
@ -193,7 +193,7 @@ bool URLRequestAsarJob::IsRedirectResponse(GURL* location,
net::Filter* URLRequestAsarJob::SetupFilter() const {
// Bug 9936 - .svgz files needs to be decompressed.
return LowerCaseEqualsASCII(file_path_.Extension(), ".svgz")
return base::LowerCaseEqualsASCII(file_path_.Extension(), ".svgz")
? net::Filter::GZipFactory() : NULL;
}
@ -265,8 +265,7 @@ void URLRequestAsarJob::DidOpen(int result) {
}
if (type_ == TYPE_ASAR) {
int rv = stream_->Seek(base::File::FROM_BEGIN,
file_info_.offset,
int rv = stream_->Seek(file_info_.offset,
base::Bind(&URLRequestAsarJob::DidSeek,
weak_ptr_factory_.GetWeakPtr()));
if (rv != net::ERR_IO_PENDING) {
@ -285,8 +284,7 @@ void URLRequestAsarJob::DidOpen(int result) {
byte_range_.first_byte_position() + 1;
if (remaining_bytes_ > 0 && byte_range_.first_byte_position() != 0) {
int rv = stream_->Seek(base::File::FROM_BEGIN,
byte_range_.first_byte_position(),
int rv = stream_->Seek(byte_range_.first_byte_position(),
base::Bind(&URLRequestAsarJob::DidSeek,
weak_ptr_factory_.GetWeakPtr()));
if (rv != net::ERR_IO_PENDING) {

View file

@ -23,7 +23,7 @@ namespace {
// Convert string to RequestType.
net::URLFetcher::RequestType GetRequestType(const std::string& raw) {
std::string method = StringToUpperASCII(raw);
std::string method = base::StringToUpperASCII(raw);
if (method.empty() || method == "GET")
return net::URLFetcher::GET;
else if (method == "POST")

View file

@ -17,7 +17,7 @@
<key>CFBundleIconFile</key>
<string>atom.icns</string>
<key>CFBundleVersion</key>
<string>0.31.0</string>
<string>0.31.2</string>
<key>LSMinimumSystemVersion</key>
<string>10.8.0</string>
<key>NSMainNibFile</key>

View file

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

View file

@ -4,6 +4,8 @@
#include "atom/browser/ui/atom_menu_model.h"
#include "base/stl_util.h"
namespace atom {
AtomMenuModel::AtomMenuModel(Delegate* delegate)
@ -14,6 +16,17 @@ AtomMenuModel::AtomMenuModel(Delegate* delegate)
AtomMenuModel::~AtomMenuModel() {
}
void AtomMenuModel::SetRole(int index, const base::string16& role) {
roles_[index] = role;
}
base::string16 AtomMenuModel::GetRoleAt(int index) {
if (ContainsKey(roles_, index))
return roles_[index];
else
return base::string16();
}
void AtomMenuModel::MenuClosed() {
ui::SimpleMenuModel::MenuClosed();
FOR_EACH_OBSERVER(Observer, observers_, MenuClosed());

View file

@ -5,6 +5,8 @@
#ifndef ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_
#define ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_
#include <map>
#include "base/observer_list.h"
#include "ui/base/models/simple_menu_model.h"
@ -31,13 +33,17 @@ class AtomMenuModel : public ui::SimpleMenuModel {
void AddObserver(Observer* obs) { observers_.AddObserver(obs); }
void RemoveObserver(Observer* obs) { observers_.RemoveObserver(obs); }
void SetRole(int index, const base::string16& role);
base::string16 GetRoleAt(int index);
// ui::SimpleMenuModel:
void MenuClosed() override;
private:
Delegate* delegate_; // weak ref.
ObserverList<Observer> observers_;
std::map<int, base::string16> roles_;
base::ObserverList<Observer> observers_;
DISALLOW_COPY_AND_ASSIGN(AtomMenuModel);
};

View file

@ -59,17 +59,4 @@ class MenuModel;
@end
// Exposed only for unit testing, do not call directly.
@interface AtomMenuController (PrivateExposedForTesting)
- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item;
@end
// Protected methods that subclassers can override.
@interface AtomMenuController (Protected)
- (void)addItemToMenu:(NSMenu*)menu
atIndex:(NSInteger)index
fromModel:(ui::MenuModel*)model;
- (NSMenu*)menuFromModel:(ui::MenuModel*)model;
@end
#endif // ATOM_BROWSER_UI_COCOA_ATOM_MENU_CONTROLLER_H_

View file

@ -8,16 +8,36 @@
#include "atom/browser/ui/atom_menu_model.h"
#include "base/logging.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/accelerators/platform_accelerator_cocoa.h"
#include "ui/base/l10n/l10n_util_mac.h"
#include "ui/events/cocoa/cocoa_event_utils.h"
#include "ui/gfx/image/image.h"
@interface AtomMenuController (Private)
- (void)addSeparatorToMenu:(NSMenu*)menu
atIndex:(int)index;
@end
namespace {
struct Role {
SEL selector;
const char* role;
};
Role kRolesMap[] = {
{ @selector(orderFrontStandardAboutPanel:), "about" },
{ @selector(hide:), "hide" },
{ @selector(hideOtherApplications:), "hideothers" },
{ @selector(unhideAllApplications:), "unhide" },
{ @selector(arrangeInFront:), "front" },
{ @selector(undo:), "undo" },
{ @selector(redo:), "redo" },
{ @selector(cut:), "cut" },
{ @selector(copy:), "copy" },
{ @selector(paste:), "paste" },
{ @selector(selectAll:), "selectall" },
{ @selector(performMiniaturize:), "minimize" },
{ @selector(performClose:), "close" },
};
} // namespace
@implementation AtomMenuController
@ -101,7 +121,9 @@
// associated with the entry in the model identified by |modelIndex|.
- (void)addItemToMenu:(NSMenu*)menu
atIndex:(NSInteger)index
fromModel:(ui::MenuModel*)model {
fromModel:(ui::MenuModel*)ui_model {
atom::AtomMenuModel* model = static_cast<atom::AtomMenuModel*>(ui_model);
base::string16 label16 = model->GetLabelAt(index);
NSString* label = l10n_util::FixUpWindowsStyleLabel(label16);
base::scoped_nsobject<NSMenuItem> item(
@ -124,13 +146,13 @@
[submenu setTitle:[item title]];
[item setSubmenu:submenu];
// Hack to set window and help menu.
if ([[item title] isEqualToString:@"Window"] && [submenu numberOfItems] > 0)
// Set submenu's role.
base::string16 role = model->GetRoleAt(index);
if (role == base::ASCIIToUTF16("window"))
[NSApp setWindowsMenu:submenu];
else if ([[item title] isEqualToString:@"Help"])
else if (role == base::ASCIIToUTF16("help"))
[NSApp setHelpMenu:submenu];
if ([[item title] isEqualToString:@"Services"] &&
[submenu numberOfItems] == 0)
if (role == base::ASCIIToUTF16("services"))
[NSApp setServicesMenu:submenu];
} else {
// The MenuModel works on indexes so we can't just set the command id as the
@ -139,7 +161,6 @@
// model. Setting the target to |self| allows this class to participate
// in validation of the menu items.
[item setTag:index];
[item setTarget:self];
NSValue* modelObject = [NSValue valueWithPointer:model];
[item setRepresentedObject:modelObject]; // Retains |modelObject|.
ui::Accelerator accelerator;
@ -153,6 +174,19 @@
platformAccelerator->modifier_mask()];
}
}
// Set menu item's role.
base::string16 role = model->GetRoleAt(index);
if (role.empty()) {
[item setTarget:self];
} else {
for (const Role& pair : kRolesMap) {
if (role == base::ASCIIToUTF16(pair.role)) {
[item setAction:pair.selector];
break;
}
}
}
}
[menu insertItem:item atIndex:index];
}

View file

@ -22,7 +22,7 @@ gboolean FileFilterCaseInsensitive(const GtkFileFilterInfo* file_info,
// Makes .* file extension matches all file types.
if (*file_extension == ".*")
return true;
return EndsWith(file_info->filename, *file_extension, false);
return base::EndsWith(file_info->filename, *file_extension, false);
}
// Deletes |data| when gtk_file_filter_add_custom() is done with it.

View file

@ -252,7 +252,7 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
bool matched = false;
for (size_t i = 0; i < filter.second.size(); ++i) {
if (EndsWith(file_name, filter.second[i], false)) {
if (base::EndsWith(file_name, filter.second[i], false)) {
matched = true;
break;;
}

View file

@ -67,7 +67,7 @@ class TrayIcon {
TrayIcon();
private:
ObserverList<TrayIconObserver> observers_;
base::ObserverList<TrayIconObserver> observers_;
DISALLOW_COPY_AND_ASSIGN(TrayIcon);
};

View file

@ -41,7 +41,7 @@ void SetWindowType(::Window xwindow, const std::string& type) {
XDisplay* xdisplay = gfx::GetXDisplay();
std::string type_prefix = "_NET_WM_WINDOW_TYPE_";
::Atom window_type = XInternAtom(
xdisplay, (type_prefix + StringToUpperASCII(type)).c_str(), False);
xdisplay, (type_prefix + base::StringToUpperASCII(type)).c_str(), False);
XChangeProperty(xdisplay, xwindow,
XInternAtom(xdisplay, "_NET_WM_WINDOW_TYPE", False),
XA_ATOM,

View file

@ -0,0 +1,24 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/web_view_constants.h"
namespace atom {
namespace web_view {
const char kPreloadUrl[] = "preloadUrl";
const char kNodeIntegration[] = "nodeIntegration";
const char kPlugins[] = "plugins";
const char kDisableWebSecurity[] = "disableWebSecurity";
const char kPartitionId[] = "partitionId";
const int kDefaultWidth = 300;
const int kDefaultHeight = 300;
const char kWebViewInfoKeyName[] = "web_view_info";
} // namespace web_view
} // namespace atom

View file

@ -0,0 +1,27 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_WEB_VIEW_CONSTANTS_H_
#define ATOM_BROWSER_WEB_VIEW_CONSTANTS_H_
namespace atom {
namespace web_view {
extern const char kPreloadUrl[];
extern const char kNodeIntegration[];
extern const char kPlugins[];
extern const char kDisableWebSecurity[];
extern const char kPartitionId[];
extern const int kDefaultWidth;
extern const int kDefaultHeight;
extern const char kWebViewInfoKeyName[];
} // namespace web_view
} // namespace atom
#endif // ATOM_BROWSER_WEB_VIEW_CONSTANTS_H_

View file

@ -5,6 +5,7 @@
#include "atom/browser/web_view_guest_delegate.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/web_view_constants.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "content/public/browser/guest_host.h"
#include "content/public/browser/render_frame_host.h"
@ -13,13 +14,6 @@
namespace atom {
namespace {
const int kDefaultWidth = 300;
const int kDefaultHeight = 300;
} // namespace
WebViewGuestDelegate::WebViewGuestDelegate()
: guest_opaque_(true),
guest_host_(nullptr),
@ -178,7 +172,7 @@ gfx::Size WebViewGuestDelegate::GetDefaultSize() const {
return embedder_web_contents_->GetRenderWidgetHostView()
->GetVisibleViewportSize();
} else {
return gfx::Size(kDefaultWidth, kDefaultHeight);
return gfx::Size(web_view::kDefaultWidth, web_view::kDefaultHeight);
}
}

View file

@ -5,37 +5,12 @@
#include "atom/browser/web_view_manager.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
namespace atom {
namespace {
WebViewManager* GetManagerFromWebContents(
const content::WebContents* web_contents) {
auto context = web_contents->GetBrowserContext();
if (!context)
return nullptr;
return static_cast<WebViewManager*>(context->GetGuestManager());
}
} // namespace
// static
bool WebViewManager::GetInfoForWebContents(
const content::WebContents* web_contents, WebViewInfo* info) {
auto manager = GetManagerFromWebContents(web_contents);
if (!manager)
return false;
base::AutoLock auto_lock(manager->lock_);
auto iter = manager->webview_info_map_.find(web_contents);
if (iter == manager->webview_info_map_.end())
return false;
*info = iter->second;
return true;
}
WebViewManager::WebViewManager(content::BrowserContext* context) {
}
@ -45,11 +20,9 @@ WebViewManager::~WebViewManager() {
void WebViewManager::AddGuest(int guest_instance_id,
int element_instance_id,
content::WebContents* embedder,
content::WebContents* web_contents,
const WebViewInfo& info) {
content::WebContents* web_contents) {
base::AutoLock auto_lock(lock_);
web_contents_embdder_map_[guest_instance_id] = { web_contents, embedder };
webview_info_map_[web_contents] = info;
web_contents_embedder_map_[guest_instance_id] = { web_contents, embedder };
// Map the element in embedder to guest.
int owner_process_id = embedder->GetRenderProcessHost()->GetID();
@ -59,12 +32,10 @@ void WebViewManager::AddGuest(int guest_instance_id,
void WebViewManager::RemoveGuest(int guest_instance_id) {
base::AutoLock auto_lock(lock_);
if (!ContainsKey(web_contents_embdder_map_, guest_instance_id))
if (!ContainsKey(web_contents_embedder_map_, guest_instance_id))
return;
auto web_contents = web_contents_embdder_map_[guest_instance_id].web_contents;
web_contents_embdder_map_.erase(guest_instance_id);
webview_info_map_.erase(web_contents);
web_contents_embedder_map_.erase(guest_instance_id);
// Remove the record of element in embedder too.
for (const auto& element : element_instance_id_to_guest_map_)
@ -82,15 +53,15 @@ content::WebContents* WebViewManager::GetGuestByInstanceID(
return nullptr;
int guest_instance_id = element_instance_id_to_guest_map_[key];
if (ContainsKey(web_contents_embdder_map_, guest_instance_id))
return web_contents_embdder_map_[guest_instance_id].web_contents;
if (ContainsKey(web_contents_embedder_map_, guest_instance_id))
return web_contents_embedder_map_[guest_instance_id].web_contents;
else
return nullptr;
}
bool WebViewManager::ForEachGuest(content::WebContents* embedder_web_contents,
const GuestCallback& callback) {
for (auto& item : web_contents_embdder_map_)
for (auto& item : web_contents_embedder_map_)
if (item.second.embedder == embedder_web_contents &&
callback.Run(item.second.web_contents))
return true;

View file

@ -8,8 +8,10 @@
#include <map>
#include "base/files/file_path.h"
#include "base/supports_user_data.h"
#include "base/synchronization/lock.h"
#include "content/public/browser/browser_plugin_guest_manager.h"
#include "content/public/browser/site_instance.h"
namespace content {
class BrowserContext;
@ -27,12 +29,20 @@ class WebViewManager : public content::BrowserPluginGuestManager {
bool plugins;
bool disable_web_security;
base::FilePath preload_script;
GURL partition_id;
};
// Finds the WebViewManager attached with |web_contents| and returns the
// WebViewInfo of it.
static bool GetInfoForWebContents(const content::WebContents* web_contents,
WebViewInfo* info);
class WebViewInfoUserData : public base::SupportsUserData::Data {
public:
explicit WebViewInfoUserData(WebViewInfo info)
: web_view_info_(info) {}
~WebViewInfoUserData() override {}
WebViewInfo& web_view_info() { return web_view_info_; }
private:
WebViewInfo web_view_info_;
};
explicit WebViewManager(content::BrowserContext* context);
virtual ~WebViewManager();
@ -40,8 +50,7 @@ class WebViewManager : public content::BrowserPluginGuestManager {
void AddGuest(int guest_instance_id,
int element_instance_id,
content::WebContents* embedder,
content::WebContents* web_contents,
const WebViewInfo& info);
content::WebContents* web_contents);
void RemoveGuest(int guest_instance_id);
protected:
@ -57,7 +66,7 @@ class WebViewManager : public content::BrowserPluginGuestManager {
content::WebContents* embedder;
};
// guest_instance_id => (web_contents, embedder)
std::map<int, WebContentsWithEmbedder> web_contents_embdder_map_;
std::map<int, WebContentsWithEmbedder> web_contents_embedder_map_;
struct ElementInstanceKey {
int embedder_process_id;
@ -81,10 +90,6 @@ class WebViewManager : public content::BrowserPluginGuestManager {
// (embedder_process_id, element_instance_id) => guest_instance_id
std::map<ElementInstanceKey, int> element_instance_id_to_guest_map_;
typedef std::map<const content::WebContents*, WebViewInfo> WebViewInfoMap;
// web_contents => (guest_instance_id, embedder, ...)
WebViewInfoMap webview_info_map_;
base::Lock lock_;
DISALLOW_COPY_AND_ASSIGN(WebViewManager);

View file

@ -13,7 +13,7 @@
namespace atom {
// static
base::LazyInstance<ObserverList<WindowListObserver>>::Leaky
base::LazyInstance<base::ObserverList<WindowListObserver>>::Leaky
WindowList::observers_ = LAZY_INSTANCE_INITIALIZER;
// static

View file

@ -60,7 +60,8 @@ class WindowList {
// A list of observers which will be notified of every window addition and
// removal across all WindowLists.
static base::LazyInstance<ObserverList<WindowListObserver>>::Leaky observers_;
static base::LazyInstance<base::ObserverList<WindowListObserver>>::Leaky
observers_;
static WindowList* instance_;

View file

@ -14,6 +14,7 @@
#include "atom/common/node_includes.h"
#include "base/base64.h"
#include "base/strings/string_util.h"
#include "base/strings/pattern.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "net/base/data_url.h"
@ -62,7 +63,7 @@ float GetScaleFactorFromPath(const base::FilePath& path) {
// We don't try to convert string to float here because it is very very
// expensive.
for (unsigned i = 0; i < arraysize(kScaleFactorPairs); ++i) {
if (EndsWith(filename, kScaleFactorPairs[i].name, true))
if (base::EndsWith(filename, kScaleFactorPairs[i].name, true))
return kScaleFactorPairs[i].scale;
}
@ -104,7 +105,7 @@ bool PopulateImageSkiaRepsFromPath(gfx::ImageSkia* image,
const base::FilePath& path) {
bool succeed = false;
std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe());
if (MatchPattern(filename, "*@*x"))
if (base::MatchPattern(filename, "*@*x"))
// Don't search for other representations if the DPI has been specified.
return AddImageSkiaRep(image, path, GetScaleFactorFromPath(path));
else
@ -119,8 +120,8 @@ bool PopulateImageSkiaRepsFromPath(gfx::ImageSkia* image,
#if defined(OS_MACOSX)
bool IsTemplateFilename(const base::FilePath& path) {
return (MatchPattern(path.value(), "*Template.*") ||
MatchPattern(path.value(), "*Template@*x.*"));
return (base::MatchPattern(path.value(), "*Template.*") ||
base::MatchPattern(path.value(), "*Template@*x.*"));
}
#endif

View file

@ -11,6 +11,7 @@
#include "atom/common/chrome_version.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "base/logging.h"
#include "base/process/process_metrics.h"
#include "native_mate/dictionary.h"
#include "atom/common/node_includes.h"
@ -61,6 +62,9 @@ void AtomBindings::BindTo(v8::Isolate* isolate,
dict.SetMethod("crash", &Crash);
dict.SetMethod("hang", &Hang);
dict.SetMethod("log", &Log);
#if defined(OS_POSIX)
dict.SetMethod("setFdLimit", &base::SetFdLimit);
#endif
dict.SetMethod("activateUvLoop",
base::Bind(&AtomBindings::ActivateUVLoop, base::Unretained(this)));

View file

@ -136,7 +136,8 @@ bool Archive::Init() {
}
uint32 size;
if (!PickleIterator(Pickle(buf.data(), buf.size())).ReadUInt32(&size)) {
if (!base::PickleIterator(base::Pickle(buf.data(), buf.size())).ReadUInt32(
&size)) {
LOG(ERROR) << "Failed to parse header size from " << path_.value();
return false;
}
@ -149,7 +150,8 @@ bool Archive::Init() {
}
std::string header;
if (!PickleIterator(Pickle(buf.data(), buf.size())).ReadString(&header)) {
if (!base::PickleIterator(base::Pickle(buf.data(), buf.size())).ReadString(
&header)) {
LOG(ERROR) << "Failed to parse header from " << path_.value();
return false;
}

View file

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

View file

@ -8,7 +8,7 @@
#ifndef ATOM_COMMON_CHROME_VERSION_H_
#define ATOM_COMMON_CHROME_VERSION_H_
#define CHROME_VERSION_STRING "44.0.2403.125"
#define CHROME_VERSION_STRING "45.0.2454.85"
#define CHROME_VERSION "v" CHROME_VERSION_STRING
#endif // ATOM_COMMON_CHROME_VERSION_H_

View file

@ -40,6 +40,7 @@ REFERENCE_MODULE(atom_browser_power_monitor);
REFERENCE_MODULE(atom_browser_power_save_blocker);
REFERENCE_MODULE(atom_browser_protocol);
REFERENCE_MODULE(atom_browser_global_shortcut);
REFERENCE_MODULE(atom_browser_session);
REFERENCE_MODULE(atom_browser_tray);
REFERENCE_MODULE(atom_browser_web_contents);
REFERENCE_MODULE(atom_browser_web_view_manager);

View file

@ -27,7 +27,6 @@
#include "third_party/WebKit/public/web/WebPluginParams.h"
#include "third_party/WebKit/public/web/WebKit.h"
#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
#include "third_party/WebKit/Source/wtf/ArrayBufferContents.h"
#include "atom/common/node_includes.h"
@ -52,10 +51,6 @@ bool IsSwitchEnabled(base::CommandLine* command_line,
return true;
}
bool IsGuestFrame(blink::WebFrame* frame) {
return frame->uniqueName().utf8() == "ATOM_SHELL_GUEST_WEB_VIEW";
}
// global.Uint8Array;
v8::Local<v8::Function> GetUint8ArrayConstructor(
v8::Isolate* isolate, v8::Local<v8::Context> context) {
@ -113,8 +108,7 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver {
AtomRendererClient::AtomRendererClient()
: node_bindings_(NodeBindings::Create(false)),
atom_bindings_(new AtomBindings),
main_frame_(nullptr) {
atom_bindings_(new AtomBindings) {
}
AtomRendererClient::~AtomRendererClient() {
@ -189,14 +183,9 @@ bool AtomRendererClient::OverrideCreatePlugin(
void AtomRendererClient::DidCreateScriptContext(
blink::WebFrame* frame,
v8::Handle<v8::Context> context) {
// Only attach node bindings in main frame or guest frame.
if (!IsGuestFrame(frame)) {
if (main_frame_)
return;
// The first web frame is the main frame.
main_frame_ = frame;
}
// Only insert node integration for the main frame.
if (frame->parent())
return;
// Give the node loop a run to make sure everything is ready.
node_bindings_->RunMessageLoop();
@ -215,20 +204,17 @@ void AtomRendererClient::DidCreateScriptContext(
node_bindings_->LoadEnvironment(env);
}
bool AtomRendererClient::ShouldFork(blink::WebFrame* frame,
bool AtomRendererClient::ShouldFork(blink::WebLocalFrame* frame,
const GURL& url,
const std::string& http_method,
bool is_initial_navigation,
bool is_server_redirect,
bool* send_referrer) {
// Never fork renderer process for guests.
if (IsGuestFrame(frame))
return false;
// Handle all the navigations and reloads in browser.
// FIXME We only support GET here because http method will be ignored when
// the OpenURLFromTab is triggered, which means form posting would not work,
// we should solve this by patching Chromium in future.
*send_referrer = true;
return http_method == "GET";
}

View file

@ -45,7 +45,7 @@ class AtomRendererClient : public content::ContentRendererClient,
blink::WebLocalFrame* frame,
const blink::WebPluginParams& params,
blink::WebPlugin** plugin) override;
bool ShouldFork(blink::WebFrame* frame,
bool ShouldFork(blink::WebLocalFrame* frame,
const GURL& url,
const std::string& http_method,
bool is_initial_navigation,
@ -64,9 +64,6 @@ class AtomRendererClient : public content::ContentRendererClient,
scoped_ptr<NodeBindings> node_bindings_;
scoped_ptr<AtomBindings> atom_bindings_;
// The main frame.
blink::WebFrame* main_frame_;
DISALLOW_COPY_AND_ASSIGN(AtomRendererClient);
};

View file

@ -6,7 +6,9 @@
#include <map>
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
#include "ui/gfx/geometry/size.h"
namespace atom {
@ -20,7 +22,8 @@ static base::LazyInstance<GuestViewContainerMap> g_guest_view_container_map =
} // namespace
GuestViewContainer::GuestViewContainer(content::RenderFrame* render_frame)
: render_frame_(render_frame) {
: render_frame_(render_frame),
weak_ptr_factory_(this) {
}
GuestViewContainer::~GuestViewContainer() {
@ -55,4 +58,8 @@ void GuestViewContainer::DidResizeElement(const gfx::Size& new_size) {
FROM_HERE, base::Bind(element_resize_callback_, new_size));
}
base::WeakPtr<content::BrowserPluginDelegate> GuestViewContainer::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
} // namespace atom

View file

@ -28,6 +28,7 @@ class GuestViewContainer : public content::BrowserPluginDelegate {
// content::BrowserPluginDelegate:
void SetElementInstanceID(int element_instance_id) final;
void DidResizeElement(const gfx::Size& new_size) final;
base::WeakPtr<BrowserPluginDelegate> GetWeakPtr() final;
private:
int element_instance_id_;
@ -35,6 +36,8 @@ class GuestViewContainer : public content::BrowserPluginDelegate {
ResizeCallback element_resize_callback_;
base::WeakPtrFactory<GuestViewContainer> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(GuestViewContainer);
};

View file

@ -29,8 +29,6 @@ for arg in process.argv
if arg.indexOf('--guest-instance-id=') == 0
# This is a guest web view.
process.guestInstanceId = parseInt arg.substr(arg.indexOf('=') + 1)
# Set the frame name to make AtomRendererClient recognize this guest.
require('web-frame').setName 'ATOM_SHELL_GUEST_WEB_VIEW'
else if arg.indexOf('--node-integration=') == 0
nodeIntegration = arg.substr arg.indexOf('=') + 1
else if arg.indexOf('--preload=') == 0

View file

@ -1,11 +1,9 @@
window.onload = ->
inspectorFrame = document.getElementById('inspector-app-iframe').contentWindow
# Use menu API to show context menu.
inspectorFrame.eval 'InspectorFrontendHost.showContextMenuAtPoint = parent.createMenu'
InspectorFrontendHost.showContextMenuAtPoint = createMenu
# Use dialog API to override file chooser dialog.
inspectorFrame.eval 'WebInspector.createFileSelectorElement = parent.createFileSelectorElement'
WebInspector.createFileSelectorElement = createFileSelectorElement
convertToMenuTemplate = (items) ->
template = []
@ -60,7 +58,3 @@ createFileSelectorElement = (callback) ->
fileSelectorElement.style.display = 'none'
fileSelectorElement.click = showFileChooserDialog.bind this, callback
return fileSelectorElement
# Exposed for iframe.
window.createMenu = createMenu
window.createFileSelectorElement = createFileSelectorElement

View file

@ -94,14 +94,22 @@ window.confirm = (message, title='') ->
window.prompt = ->
throw new Error('prompt() is and will not be supported.')
# Simple implementation of postMessage.
if ipc.sendSync 'ATOM_SHELL_GUEST_WINDOW_MANAGER_IS_GUEST_WINDOW'
# Implement window.postMessage if current window is a guest window.
guestId = ipc.sendSync 'ATOM_SHELL_GUEST_WINDOW_MANAGER_GET_GUEST_ID'
if guestId?
window.opener =
postMessage: (message, targetOrigin='*') ->
ipc.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', message, targetOrigin
ipc.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', guestId, message, targetOrigin, location.origin
ipc.on 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', (message, targetOrigin) ->
window.postMessage message, targetOrigin
ipc.on 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', (guestId, message, sourceOrigin) ->
# Manually dispatch event instead of using postMessage because we also need to
# set event.source.
event = document.createEvent 'Event'
event.initEvent 'message', false, false
event.data = message
event.origin = sourceOrigin
event.source = new BrowserWindowProxy(guestId)
window.dispatchEvent event
# Forward history operations to browser.
sendHistoryOperation = (args...) ->

View file

@ -296,8 +296,7 @@ void PdfToEmfUtilityProcessHostClient::Start(
// generate when sent to a metafile DC.
utility_process_host_ =
content::UtilityProcessHost::Create(
this, base::MessageLoop::current()->message_loop_proxy())
->AsWeakPtr();
this, base::MessageLoop::current()->task_runner())->AsWeakPtr();
if (!utility_process_host_)
return OnFailed();
// Should reply with OnProcessStarted().

View file

@ -220,64 +220,6 @@ PrintedDocument* PrintJob::document() const {
return document_.get();
}
void PrintJob::UpdatePrintedDocument(PrintedDocument* new_document) {
if (document_.get() == new_document)
return;
document_ = new_document;
if (document_.get()) {
settings_ = document_->settings();
}
if (worker_) {
DCHECK(!is_job_pending_);
// Sync the document with the worker.
worker_->PostTask(FROM_HERE,
base::Bind(&HoldRefCallback,
make_scoped_refptr(this),
base::Bind(&PrintJobWorker::OnDocumentChanged,
base::Unretained(worker_.get()),
document_)));
}
}
void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) {
switch (event_details.type()) {
case JobEventDetails::FAILED: {
settings_.Clear();
// No need to cancel since the worker already canceled itself.
Stop();
break;
}
case JobEventDetails::USER_INIT_DONE:
case JobEventDetails::DEFAULT_INIT_DONE:
case JobEventDetails::USER_INIT_CANCELED: {
DCHECK_EQ(event_details.document(), document_.get());
break;
}
case JobEventDetails::NEW_DOC:
case JobEventDetails::NEW_PAGE:
case JobEventDetails::JOB_DONE:
case JobEventDetails::ALL_PAGES_REQUESTED: {
// Don't care.
break;
}
case JobEventDetails::DOC_DONE: {
// This will call Stop() and broadcast a JOB_DONE message.
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(&PrintJob::OnDocumentDone, this));
break;
}
case JobEventDetails::PAGE_DONE:
break;
default: {
NOTREACHED();
break;
}
}
}
#if defined(OS_WIN)
class PrintJob::PdfToEmfState {
@ -375,6 +317,68 @@ void PrintJob::OnPdfToEmfPageConverted(int page_number,
#endif // OS_WIN
void PrintJob::UpdatePrintedDocument(PrintedDocument* new_document) {
if (document_.get() == new_document)
return;
document_ = new_document;
if (document_.get()) {
settings_ = document_->settings();
}
if (worker_) {
DCHECK(!is_job_pending_);
// Sync the document with the worker.
worker_->PostTask(FROM_HERE,
base::Bind(&HoldRefCallback,
make_scoped_refptr(this),
base::Bind(&PrintJobWorker::OnDocumentChanged,
base::Unretained(worker_.get()),
document_)));
}
}
void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) {
switch (event_details.type()) {
case JobEventDetails::FAILED: {
settings_.Clear();
// No need to cancel since the worker already canceled itself.
Stop();
break;
}
case JobEventDetails::USER_INIT_DONE:
case JobEventDetails::DEFAULT_INIT_DONE:
case JobEventDetails::USER_INIT_CANCELED: {
DCHECK_EQ(event_details.document(), document_.get());
break;
}
case JobEventDetails::NEW_DOC:
case JobEventDetails::NEW_PAGE:
case JobEventDetails::JOB_DONE:
case JobEventDetails::ALL_PAGES_REQUESTED: {
// Don't care.
break;
}
case JobEventDetails::DOC_DONE: {
// This will call Stop() and broadcast a JOB_DONE message.
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(&PrintJob::OnDocumentDone, this));
break;
}
case JobEventDetails::PAGE_DONE:
#if defined(OS_WIN)
ptd_to_emf_state_->OnPageProcessed(
base::Bind(&PrintJob::OnPdfToEmfPageConverted, this));
#endif // OS_WIN
break;
default: {
NOTREACHED();
break;
}
}
}
void PrintJob::OnDocumentDone() {
// Be sure to live long enough. The instance could be destroyed by the
// JOB_DONE broadcast.

View file

@ -46,7 +46,8 @@ ui::ClipboardType ConvertClipboardType(uint32_t type) {
// assume all data that is placed on the clipboard is UTF16 and pepper allows
// arbitrary data so this change would require some reworking of the chrome
// clipboard interface for custom data.
bool JumpToFormatInPickle(const base::string16& format, PickleIterator* iter) {
bool JumpToFormatInPickle(const base::string16& format,
base::PickleIterator* iter) {
size_t size = 0;
if (!iter->ReadSizeT(&size))
return false;
@ -66,22 +67,22 @@ bool JumpToFormatInPickle(const base::string16& format, PickleIterator* iter) {
}
bool IsFormatAvailableInPickle(const base::string16& format,
const Pickle& pickle) {
PickleIterator iter(pickle);
const base::Pickle& pickle) {
base::PickleIterator iter(pickle);
return JumpToFormatInPickle(format, &iter);
}
std::string ReadDataFromPickle(const base::string16& format,
const Pickle& pickle) {
const base::Pickle& pickle) {
std::string result;
PickleIterator iter(pickle);
base::PickleIterator iter(pickle);
if (!JumpToFormatInPickle(format, &iter) || !iter.ReadString(&result))
return std::string();
return result;
}
bool WriteDataToPickle(const std::map<base::string16, std::string>& data,
Pickle* pickle) {
base::Pickle* pickle) {
pickle->WriteSizeT(data.size());
for (std::map<base::string16, std::string>::const_iterator it = data.begin();
it != data.end();
@ -187,7 +188,7 @@ int32_t PepperFlashClipboardMessageFilter::OnMsgIsFormatAvailable(
std::string clipboard_data;
clipboard->ReadData(ui::Clipboard::GetPepperCustomDataFormatType(),
&clipboard_data);
Pickle pickle(clipboard_data.data(), clipboard_data.size());
base::Pickle pickle(clipboard_data.data(), clipboard_data.size());
available =
IsFormatAvailableInPickle(base::UTF8ToUTF16(format_name), pickle);
}
@ -265,7 +266,7 @@ int32_t PepperFlashClipboardMessageFilter::OnMsgReadData(
std::string clipboard_data;
clipboard->ReadData(ui::Clipboard::GetPepperCustomDataFormatType(),
&clipboard_data);
Pickle pickle(clipboard_data.data(), clipboard_data.size());
base::Pickle pickle(clipboard_data.data(), clipboard_data.size());
if (IsFormatAvailableInPickle(format_name, pickle)) {
result = PP_OK;
clipboard_string = ReadDataFromPickle(format_name, pickle);
@ -340,7 +341,7 @@ int32_t PepperFlashClipboardMessageFilter::OnMsgWriteData(
}
if (custom_data_map.size() > 0) {
Pickle pickle;
base::Pickle pickle;
if (WriteDataToPickle(custom_data_map, &pickle)) {
scw.WritePickledData(pickle,
ui::Clipboard::GetPepperCustomDataFormatType());

View file

@ -27,7 +27,7 @@
#if defined(OS_WIN)
// A vector of filters, each being a Tuple containing a display string (i.e.
// "Text Files") and a filter pattern (i.e. "*.txt").
typedef std::vector<Tuple<base::string16, base::string16>>
typedef std::vector<base::Tuple<base::string16, base::string16>>
GetOpenFileNameFilter;
#endif // OS_WIN

View file

@ -56,17 +56,9 @@ void PepperSharedMemoryMessageFilter::OnHostMsgCreateSharedMemory(
->GetVarTracker()
->TrackSharedMemoryHandle(instance, host_shm_handle, size);
base::PlatformFile host_handle =
#if defined(OS_WIN)
host_shm_handle;
#elif defined(OS_POSIX)
host_shm_handle.fd;
#else
#error Not implemented.
#endif
// We set auto_close to false since we need our file descriptor to
// actually be duplicated on linux. The shared memory destructor will
// close the original handle for us.
plugin_handle->set_shmem(host_->ShareHandleWithRemote(host_handle, false),
size);
plugin_handle->set_shmem(
host_->ShareSharedMemoryHandleWithRemote(host_shm_handle), size);
}

View file

@ -427,9 +427,10 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient,
// blink::WebFrameClient override:
virtual blink::WebFrame* createChildFrame(
blink::WebLocalFrame* parent,
blink::WebTreeScopeType scope,
const blink::WebString& name,
blink::WebSandboxFlags sandboxFlags);
virtual void frameDetached(blink::WebFrame* frame);
virtual void frameDetached(blink::WebFrame* frame, DetachType type);
private:
void CallOnReady();
@ -548,7 +549,8 @@ void PrepareFrameAndViewForPrint::CopySelection(
blink::WebView* web_view = blink::WebView::create(this);
owns_web_view_ = true;
content::RenderView::ApplyWebPreferences(prefs, web_view);
web_view->setMainFrame(blink::WebLocalFrame::create(this));
web_view->setMainFrame(
blink::WebLocalFrame::create(blink::WebTreeScopeType::Document, this));
frame_.Reset(web_view->mainFrame()->toWebLocalFrame());
node_to_print_.reset();
@ -573,14 +575,17 @@ void PrepareFrameAndViewForPrint::didStopLoading() {
blink::WebFrame* PrepareFrameAndViewForPrint::createChildFrame(
blink::WebLocalFrame* parent,
blink::WebTreeScopeType scope,
const blink::WebString& name,
blink::WebSandboxFlags sandboxFlags) {
blink::WebFrame* frame = blink::WebLocalFrame::create(this);
blink::WebFrame* frame = blink::WebLocalFrame::create(scope, this);
parent->appendChild(frame);
return frame;
}
void PrepareFrameAndViewForPrint::frameDetached(blink::WebFrame* frame) {
void PrepareFrameAndViewForPrint::frameDetached(blink::WebFrame* frame,
DetachType type) {
DCHECK(type == DetachType::Remove);
if (frame->parent())
frame->parent()->removeChild(frame);
frame->close();

View file

@ -85,6 +85,7 @@
'-Wno-deprecated-declarations',
'-Wno-return-type',
'-Wno-gnu-folding-constant',
'-Wno-shift-negative-value',
],
},
'conditions': [
@ -99,6 +100,7 @@
'-Wno-unused-value',
'-Wno-deprecated-declarations',
'-Wno-return-type',
'-Wno-shift-negative-value',
# Required when building as shared library.
'-fPIC',
],

View file

@ -62,7 +62,7 @@ Módulos de ambos procesos:
* [Estructura de directorio](development/source-code-directory-structure.md)
* [Diferencias técnicas con NW.js (anteriormente conocido como node-webkit)](development/atom-shell-vs-node-webkit.md)
* [Sistema de compilación](development/build-system-overview.md)
* [Instrucciones de compilación (Mac)](development/build-instructions-mac.md)
* [Instrucciones de compilación (Mac)](development/build-instructions-osx.md)
* [Instrucciones de compilación (Windows)](development/build-instructions-windows.md)
* [Instrucciones de compilación (Linux)](development/build-instructions-linux.md)
* [Configurando un servidor de símbolos en el depurador](development/setting-up-symbol-server.md)

View file

@ -14,17 +14,17 @@ Electronでは、`package.json` の `main`で実行されるプロセスを __
Electronはウェブページを表示させるためにChromiumを使用しているので、Chromiumのマルチプロセスアーキテクチャが使用されることになります。Electronで実行されるウェブページはそれぞれ自身のプロセスで実行されます。それを __レンダラープロセス__ と呼びます。
通常、ブラウザのウェブページはサンドボックス環境で実行されネイティブなリソースへのアクセスができません。Electronではウェブページからio.jsのAPIを使って、ネイティブリソースへの権限が与えられます。そのおかげでウェブページの中からJavaScriptを使って低レベルなオペレーティングシステムとのインタラクションが可能になります。
通常、ブラウザのウェブページはサンドボックス環境で実行されネイティブなリソースへのアクセスができません。Electronではウェブページからio.jsのAPIを使って、ネイティブリソースへの権限が与えられます。そのおかげでウェブページの中からJavaScriptを使って低レベルなオペレーティングシステムとのインタラクションが可能になります。
### メインプロセスとレンダラープロセスの違い
### メインプロセスとレンダラープロセスの違い
メインプロセスは `BrowserWindow` インスタンスを作ることによってウェブページをつくります。それぞれの `BrowserWindow` インスタンスはそれ自身の レンダラープロセス上でウェブページを実行します。`BrowserWindow` インスタンスが破棄されると、対応するレンダラープロセスも終了されます。
メインプロセスは `BrowserWindow` インスタンスを作ることによってウェブページをつくります。それぞれの `BrowserWindow` インスタンスはそれ自身の レンダラープロセス上でウェブページを実行します。`BrowserWindow` インスタンスが破棄されると、対応するレンダラープロセスも終了されます。
メインプロセスはすべてのウェブページとそれに対応するレンダラープロセスを管理しています。それぞれのレンダラープロセスは分離しているのでウェブページで実行されていることだけを気に留めておいてください。
メインプロセスはすべてのウェブページとそれに対応するレンダラープロセスを管理しています。それぞれのレンダラープロセスは分離しているのでウェブページで実行されていることだけを気に留めておいてください。
ウェブページでは、GUI関連のAPIを呼ぶことはできません。なぜならば、ウェブページで管理しているネイティブのGUIリソースは非常に危険で簡単にリークしてしまうからです。もしウェブページ内でGUIを操作したい場合には、メインプロセスと通信をする必要があります。
Electronでは、メインプロセスとレンダラープロセスとのコミュニケーションをするために[ipc](../api/ipc-renderer.md)モジュールを提供しています。またそれと、RPC形式の通信を行う[remote](../api/remote.md)モジュールもあります。
Electronでは、メインプロセスとレンダラープロセスとのコミュニケーションをするために[ipc](../api/ipc-renderer.md)モジュールを提供しています。またそれと、RPC形式の通信を行う[remote](../api/remote.md)モジュールもあります。
## Electronアプリを作成する

View file

@ -17,14 +17,14 @@
## API 레퍼런스
* [개요](api/synopsis.md)
* [프로세스 객체](api/process.md)
* [process](api/process.md)
* [크롬 Command-Line 스위치 지원](api/chrome-command-line-switches.md)
커스텀 DOM Element:
커스텀 DOM elements:
* [`File` 객체](api/file-object.md)
* [`<webview>` 태그](api/web-view-tag.md)
* [`window.open` 함수](api/window-open.md)
* [`window.open` 메서드](api/window-open.md)
메인 프로세스를 위한 모듈들:
@ -40,6 +40,8 @@
* [power-monitor](api/power-monitor.md)
* [power-save-blocker](api/power-save-blocker.md)
* [protocol](api/protocol.md)
* [session](api/session.md)
* [webContents](api/web-contents.md)
* [tray](api/tray.md)
랜더러 프로세스를 위한 모듈들 (웹 페이지):
@ -60,9 +62,9 @@
* [코딩 스타일](development/coding-style.md)
* [소스 코드 디렉터리 구조](development/source-code-directory-structure.md)
* [NW.js와 기술적으로 다른점 (이전 node-webkit)](development/atom-shell-vs-node-webkit.md)
* [NW.js(node-webkit)와 기술적으로 다른점](development/atom-shell-vs-node-webkit.md)
* [빌드 시스템 개요](development/build-system-overview.md)
* [빌드 설명서 (Mac)](development/build-instructions-mac.md)
* [빌드 설명서 (Mac)](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

@ -17,7 +17,7 @@ Squirrel은 어플리케이션이 **안전하고 투명한 업데이트**를 제
Squirrel은 사용자에게 어플리케이션의 업데이트를 알릴 필요 없이 서버가 지시하는 버전을 받아온 후 자동으로 업데이트합니다.
이 기능을 사용하면 Squirrel을 통해 클라이언트의 어플리케이션을 지능적으로 업데이트 할 수 있습니다.
요청시 커스텀 헤더 또는 요청 본문에 인증 정보를 포함시킬 수 있습니다.
또한 요청시 커스텀 헤더 또는 요청 본문에 인증 정보를 포함시킬 수 있습니다.
서버에선 이러한 요청을 분류 처리하여 적당한 업데이트를 제공할 수 있습니다.
Squirrel JSON 업데이트 요청시 처리는 반드시 어떤 업데이트가 필요한지 요청의 기준에 맞춰 동적으로 생성되어야 합니다.
@ -76,6 +76,12 @@ Squirrel은 "url"로 `Accept: application/zip` 헤더와 함께 업데이트 zip
`pub_date`은 ISO 8601 표준에 따라 포맷된 날짜입니다.
## 업데이트 서버 구현
[Nuts](https://github.com/GitbookIO/nuts)는 위에서 설명한 업데이트 서버의 오픈 소스 구현입니다.
이 구현은 Github 릴리즈와 완벽하게 통합되어 있습니다. Nuts는 `Squirrel.Mac``Squirrel.Windows`를 지원하고 다운로드와 업데이트를 관리합니다.
이 구현을 사용하면 cross-platform 지원을 신경 쓸 필요가 없습니다.
## Events
`autoUpdater` 객체는 다음과 같은 이벤트를 발생시킵니다:

View file

@ -1,6 +1,6 @@
# clipboard
`clipboard` 복사/붙여넣기 작업을 수행하는 방법을 제공합니다. 다음 예제는 클립보드에 문자열을 씁니다:
`clipboard` 모듈은 복사/붙여넣기 작업을 수행하는 방법을 제공합니다. 다음 예제는 클립보드에 문자열을 씁니다:
```javascript
var clipboard = require('clipboard');
@ -15,59 +15,65 @@ clipboard.writeText('Example String', 'selection');
console.log(clipboard.readText('selection'));
```
## clipboard.readText([type])
## Methods
* `type` String
`clipboard` 모듈은 다음과 같은 메서드를 가지고 있습니다:
**참고:** Experimental 마크가 붙은 API는 실험적인 기능이며 차후 최신 버전에서 제거될 수 있습니다.
### `clipboard.readText([type])`
* `type` String (optional)
클립보드 컨텐츠를 `plain text`로 반환합니다.
## clipboard.writeText(text[, type])
### `clipboard.writeText(text[, type])`
* `text` String
* `type` String
* `type` String (optional)
클립보드에 `plain text`로 문자열을 씁니다.
## clipboard.readHtml([type])
### `clipboard.readHtml([type])`
* `type` String
* `type` String (optional)
클립보드 컨텐츠를 `markup`으로 반환합니다.
## clipboard.writeHtml(markup[, type])
### `clipboard.writeHtml(markup[, type])`
* `markup` String
* `type` String
* `type` String (optional)
클립보드에 `markup`으로 씁니다.
## clipboard.readImage([type])
### `clipboard.readImage([type])`
* `type` String
* `type` String (optional)
클립보드로부터 [NativeImage](native-image.md)로 이미지를 읽어들입니다.
## clipboard.writeImage(image[, type])
### `clipboard.writeImage(image[, type])`
* `image` [NativeImage](native-image.md)
* `type` String
* `type` String (optional)
클립보드에 `image`를 씁니다.
## clipboard.clear([type])
### `clipboard.clear([type])`
* `type` String
* `type` String (optional)
클립보드에 저장된 모든 컨텐츠를 삭제합니다.
## clipboard.availableFormats([type])
### clipboard.availableFormats([type])
클립보드의 `type`에 해당하는 지원하는 `format`을 문자열로 반환합니다.
## clipboard.has(data[, type])
### `clipboard.has(data[, type])`
* `data` String
* `type` String
* `type` String (optional)
클립보드가 지정한 `data`의 형식을 지원하는지 확인합니다.
@ -76,24 +82,20 @@ var clipboard = require('clipboard');
console.log(clipboard.has('<p>selection</p>'));
```
**알림:** 이 API는 실험적인 기능이며 차후 최신버전에서 제외될 수 있습니다.
## clipboard.read(data[, type])
### `clipboard.read(data[, type])` _Experimental_
* `data` String
* `type` String
* `type` String (optional)
클립보드로부터 `data`를 읽어들입니다.
**알림:** 이 API는 실험적인 기능이며 차후 최신버전에서 제외될 수 있습니다.
## clipboard.write(data[, type])
### `clipboard.write(data[, type])` _Experimental_
* `data` Object
* `text` String
* `html` String
* `image` [NativeImage](native-image.md)
* `type` String
* `type` String (optional)
```javascript
var clipboard = require('clipboard');

View file

@ -1,30 +1,35 @@
# content-tracing
# contentTracing
`content-trace` 모듈은 Chromium 컨텐츠 모듈단에서 생성된 데이터를 수집하고 추적하는데 사용됩니다.
`content-tracing` 모듈은 Chromium 컨텐츠 모듈단에서 생성된 데이터를 수집하고 추적하는데 사용됩니다.
이 모듈은 웹 인터페이스를 포함하고 있지 않으며 크롬 브라우저에서 `chrome://tracing/` 페이지를 열어 생성된 파일을 로드하면 결과를 볼 수 있습니다.
```javascript
var tracing = require('content-tracing');
tracing.startRecording('*', tracing.DEFAULT_OPTIONS, function() {
var contentTracing = require('content-tracing');
contentTracing.startRecording('*', contentTracing.DEFAULT_OPTIONS, function() {
console.log('Tracing started');
setTimeout(function() {
tracing.stopRecording('', function(path) {
contentTracing.stopRecording('', function(path) {
console.log('Tracing data recorded to ' + path);
});
}, 5000);
});
```
``
## tracing.getCategories(callback)
## Methods
`content-tracing` 모듈은 다음과 같은 메서드를 가지고 있습니다:
### `contentTracing.getCategories(callback)`
* `callback` Function
카테고리 그룹 세트를 가져옵니다. 카테고리 그룹은 도달된 코드 경로를 변경할 수 있습니다.
모든 child 프로세스가 `getCategories` 요청을 받으면 `callback` 호출되며 인자에 카테고리 그룹의 배열이 전달됩니다.
모든 child 프로세스가 `getCategories` 요청을 승인하면 `callback`이 한 번 호출되며 인자에 카테고리 그룹의 배열이 전달됩니다.
## tracing.startRecording(categoryFilter, traceOptions, callback)
### `contentTracing.startRecording(categoryFilter, traceOptions, callback)`
* `categoryFilter` String
* `traceOptions` String
@ -33,7 +38,7 @@ tracing.startRecording('*', tracing.DEFAULT_OPTIONS, function() {
모든 프로세스에서 레코딩을 시작합니다.
레코딩은 지역적으로 즉시 실행됩니다. 그리고 비동기로 child 프로세스는 곧 EnableRecording 요청을 받게 됩니다.
모든 child 프로세스가 `startRecording` 요청을 받으면 `callback` 호출됩니다.
모든 child 프로세스가 `startRecording` 요청을 승인하면 `callback`이 한 번 호출됩니다.
`categoryFilter`는 어떤 카테고리 그룹이 트레이싱 되어야 하는지 필터링할 수 있습니다.
필터는 `-` 접두사를 통해 특정 카테고리 그룹을 제외할 수 있습니다.
@ -63,7 +68,7 @@ tracing.startRecording('*', tracing.DEFAULT_OPTIONS, function() {
`record-until-full`이 기본 모드, `enable-sampling``enable-systrace`옵션은 포함되지 않음
## tracing.stopRecording(resultFilePath, callback)
## `contentTracing.stopRecording(resultFilePath, callback)`
* `resultFilePath` String
* `callback` Function
@ -75,12 +80,12 @@ Child 프로세스는 일반적으로 추적 데이터와 희귀한 플러시
우리는 추적에 의한 런타임 오버헤드를 피하고자 합니다.
그래서 추적이 끝나면 모든 child 프로세스에 보류된 추적 데이터를 플러시 할 것인지 물어봅니다.
모든 child 프로세스가 `stopRecording` 요청을 받으면 `callback`에 추적 데이터를 포함한 파일을 전달됩니다.
모든 child 프로세스가 `stopRecording` 요청을 승인하면 `callback`에 추적 데이터 파일을 포함하여 한 번 호출됩니다.
추적 데이터는 `resultFilePath` 해당 경로가 비어있는 경우에 한 해 해당 경로에 작성되거나 임시 파일에 작성됩니다.
실제 파일 경로는 null이 아닌 이상 `callback`을 통해 전달됩니다.
## tracing.startMonitoring(categoryFilter, traceOptions, callback)
### `contentTracing.startMonitoring(categoryFilter, traceOptions, callback)`
* `categoryFilter` String
* `traceOptions` String
@ -90,17 +95,17 @@ Child 프로세스는 일반적으로 추적 데이터와 희귀한 플러시
모니터링은 지역적으로 즉시 시작됩니다. 그리고 이내 자식 프로세스들이 `startMonitoring` 비동기 요청을 받습니다.
모든 자식 프로세스가 `startMonitoring` 요청을 받으면 `callback` 호출됩니다.
모든 자식 프로세스가 `startMonitoring` 요청을 승인하면 `callback`이 한 번 호출됩니다.
## tracing.stopMonitoring(callback);
### `contentTracing.stopMonitoring(callback)`
* `callback` Function
모든 프로세스에서 모니터링을 중단합니다.
모든 자식 프로세스가 `stopMonitoring` 요청을 받으면 `callback` 호출됩니다.
모든 자식 프로세스가 `stopMonitoring` 요청을 승인하면 `callback`이 한 번 호출됩니다.
## tracing.captureMonitoringSnapshot(resultFilePath, callback)
### `contentTracing.captureMonitoringSnapshot(resultFilePath, callback)`
* `resultFilePath` String
* `callback` Function
@ -112,15 +117,15 @@ Child 프로세스는 일반적으로 추적 데이터와 희귀한 플러시
그리고 우리는 추적시 발생하는 불필요한 런타임 오버헤드를 피하고자 합니다.
그래서 추적이 끝나면 반드시 비동기로 자식 프로세스들의 보류된 추적 데이터를 플러시 할 것인지 물어봅니다.
모든 자식 프로세스가 `captureMonitoringSnapshot` 요청을 받으면 추적 데이터 파일을 포함하는 `callback`이 호출됩니다.
모든 자식 프로세스가 `captureMonitoringSnapshot` 요청을 승인하면 추적 데이터 파일을 포함하는 `callback` 한 번 호출됩니다.
## tracing.getTraceBufferUsage(callback)
### `contentTracing.getTraceBufferUsage(callback)`
* `callback` Function
추적 버퍼 % 전체 상태의 프로세스간 최대치를 가져옵니다. TraceBufferUsage 값이 결정되면 `callback`이 호출됩니다.
추적 버퍼 % 전체 상태의 프로세스간 최대치를 가져옵니다. TraceBufferUsage 값이 결정되면 `callback` 한 번 호출됩니다.
## tracing.setWatchEvent(categoryName, eventName, callback)
### `contentTracing.setWatchEvent(categoryName, eventName, callback)`
* `categoryName` String
* `eventName` String
@ -128,6 +133,6 @@ Child 프로세스는 일반적으로 추적 데이터와 희귀한 플러시
`callback`은 지정된 이벤트가 어떤 작업을 발생시킬 때마다 호출됩니다.
## tracing.cancelWatchEvent()
### `contentTracing.cancelWatchEvent()`
Watch 이벤트를 중단합니다. 만약 추적이 활성화되어 있다면 이 함수는 watch 이벤트 콜백과 race가 일어날 것입니다.
Watch 이벤트를 중단합니다. 만약 추적이 활성화되어 있다면 이 메서드는 watch 이벤트 콜백과 race가 일어날 것입니다.

View file

@ -1,9 +1,12 @@
# crash-reporter
# crashReporter
다음 예제는 윈격 서버에 어플리케이션 오류 정보를 자동으로 보고하는 예제입니다:
`crash-reporter` 모듈은 어플리케이션의 크래시 정보를 자동으로 원격 서버에 업로드하는데 사용합니다.
다음 예제는 윈격 서버에 어플리케이션 크래시 정보를 자동으로 보고하는 예제입니다:
```javascript
crashReporter = require('crash-reporter');
var crashReporter = require('crash-reporter');
crashReporter.start({
productName: 'YourName',
companyName: 'YourCompany',
@ -12,38 +15,42 @@ crashReporter.start({
});
```
## crashReporter.start(options)
## Methods
* `options` Object
* `productName` String, 기본값: Electron
* `companyName` String, 기본값: GitHub, Inc
* `submitUrl` String, 기본값: http://54.249.141.255:1127/post
* Crash Reporter는 POST 방식으로 해당 URL에 전송됩니다.
* `autoSubmit` Boolean, 기본값: true
* true로 지정할 경우 유저의 승인 없이 자동으로 오류를 보고합니다.
* `ignoreSystemCrashHandler` Boolean, 기본값: false
* `extra` Object
* 오류보고 시 같이 보낼 추가 정보를 지정하는 객체입니다.
* 문자열로 된 속성만 정상적으로 보내집니다.
* 중첩 객체는 지원되지 않습니다. (Nested objects are not supported)
`crash-reporter` 모듈은 다음과 같은 메서드를 가지고 있습니다:
### `crashReporter.start(options)`
* `options` Object, properties:
* `productName` String, 기본값: Electron
* `companyName` String, 기본값: GitHub, Inc
* `submitUrl` String, 기본값: http://54.249.141.255:1127/post
* 크래시 리포트는 POST 방식으로 이 URL로 전송됩니다.
* `autoSubmit` Boolean, 기본값: true
* true로 지정할 경우 유저의 승인 없이 자동으로 오류를 보고합니다.
* `ignoreSystemCrashHandler` Boolean, 기본값: false
* `extra` Object
* 크래시 리포트 시 같이 보낼 추가 정보를 지정하는 객체입니다.
* 문자열로 된 속성만 정상적으로 보내집니다.
* 중첩 객체는 지원되지 않습니다. (Nested objects are not supported)
다른 crashReporter API들을 사용하기 전에 이 함수를 먼저 호출해야 합니다.
다른 crashReporter API를 사용하기 전에 이 메서드를 먼저 호출해야 합니다.
**알림:** OS X에선 Windows와 Linux의 `breakpad`와 달리 새로운 `crashpad` 클라이언트를 사용합니다.
**참고:** OS X에선 Windows와 Linux의 `breakpad`와 달리 새로운 `crashpad` 클라이언트를 사용합니다.
오류 수집 기능을 활성화 시키려면 오류를 수집하고 싶은 메인 프로세스나 랜더러 프로세스에서
`crashReporter.start` 함수를 호출하여 `crashpad`를 초기화 해야합니다.
`crashReporter.start` 메서드를 호출하여 `crashpad`를 초기화 해야합니다.
## crashReporter.getLastCrashReport()
### `crashReporter.getLastCrashReport()`
마지막 오류보고의 날짜와 ID를 반환합니다.
이전 오류보고가 없거나 Crash Reporter가 시작되지 않았을 경우 `null`이 반환됩니다.
마지막 크래시 리포트의 날짜와 ID를 반환합니다.
이전 크래시 리포트가 없거나 Crash Reporter가 시작되지 않았을 경우 `null`이 반환됩니다.
## crashReporter.getUploadedReports()
### `crashReporter.getUploadedReports()`
모든 업로드된 오류보고를 반환합니다. 각 보고는 날짜와 업로드 ID를 포함하고 있습니다.
모든 업로드된 크래시 리포트를 반환합니다. 각 보고는 날짜와 업로드 ID를 포함하고 있습니다.
# crash-reporter 오류보고 형식
## crash-reporter 업로드 형식
Crash Reporter는 다음과 같은 데이터를 `submitUrl``POST` 방식으로 전송합니다:
@ -56,5 +63,5 @@ Crash Reporter는 다음과 같은 데이터를 `submitUrl`에 `POST` 방식으
* `_productName` String - Crash Reporter의 `options` 객체에서 정의한 제품명.
* `prod` String - 기본 제품의 이름. 이 경우 Electron으로 표시됩니다.
* `_companyName` String - Crash Reporter의 `options` 객체에서 정의한 회사명.
* `upload_file_minidump` File - 오류보고 파일
* `upload_file_minidump` File - 크래시 리포트 파일
* Crash Reporter의 `options` 객체에서 정의한 `extra` 객체의 속성들.

View file

@ -1,34 +1,39 @@
# dialog
`dialog` 모듈은 네이티브 시스템의 대화 상자를 조작할 때 사용할 수 있는 API입니다.
웹 어플리케이션에서 일반 네이티브 어플리케이션과 같은 사용자 경험을 제공할 수 있습니다.
`dialog` 모듈은 파일 열기, 알림과 같은 네이티브 시스템의 대화 상자를 조작할 때 사용할 수 있는 모듈입니다.
이 모듈을 사용하면 웹 어플리케이션에서 일반 네이티브 어플리케이션과 비슷한 사용자 경험을 제공할 수 있습니다.
다음 예제는 파일과 디렉터리를 다중으로 선택하는 대화 상자를 표시하는 예제입니다:
```javascript
var win = ...; // 대화 상자를 사용할 객체
var win = ...; // 대화 상자를 사용할 BrowserWindow 객체
var dialog = require('dialog');
console.log(dialog.showOpenDialog({ properties: [ 'openFile', 'openDirectory', 'multiSelections' ]}));
```
**OS X 주의**: 대화 상자를 시트처럼 보여지게 하려면 `browserWindow` 인자에 `BrowserWindow` 객체의 참조를 제공하면 됩니다.
**OS X 알림**: 대화 상자를 시트처럼 보여지게 하려면 `browserWindow` 인자에 `BrowserWindow` 객체의 참조를 제공하면 됩니다.
## dialog.showOpenDialog([browserWindow], [options], [callback])
## Methods
* `browserWindow` BrowserWindow
* `options` Object
`dialog` 모듈은 다음과 같은 메서드를 가지고 있습니다:
### `dialog.showOpenDialog([browserWindow][, options][, callback])`
* `browserWindow` BrowserWindow (optional)
* `options` Object (optional)
* `title` String
* `defaultPath` String
* `filters` Array
* `properties` Array - 대화 상자가 사용할 기능(모드)이 담긴 배열입니다.
다음을 포함할 수 있습니다: `openFile`, `openDirectory`, `multiSelections`, `createDirectory`
* `callback` Function
* `callback` Function (optional)
사용할 대화 상자의 기능이 담긴 배열입니다. 다음을 포함할 수 있습니다: `openFile`, `openDirectory`, `multiSelections`, `createDirectory`
작업에 성공하면 유저가 선택한 파일의 경로를 포함한 배열을 반환합니다. 그 외의 경우`undefined`를 반환합니다.
작업에 성공하면 콜백으로 유저가 선택한 파일의 경로를 포함한 배열을 반환합니다. 그 외엔 `undefined`를 반환합니다.
`filters`를 지정하면 유저가 선택 가능한 파일 형식을 지정할 수 있습니다. 예제는 다음과 같습니다:
`filters`를 지정하면 유저가 선택 가능한 파일 형식을 지정할 수 있습니다.
유저가 선택할 수 있는 타입에 제한을 두려면 다음과 같이 할 수 있습니다:
```javascript
{
@ -42,32 +47,30 @@ console.log(dialog.showOpenDialog({ properties: [ 'openFile', 'openDirectory', '
```
`extensions` 배열은 반드시 와일드카드와 마침표를 제외한 파일 확장자를 포함시켜야 합니다.
예를 들어 `'png'`는 가능하지만 `'.png'``'*.png'`는 안됩니다.
(예를 들어 `'png'`는 가능하지만 `'.png'``'*.png'`는 안됩니다)
모든 파일을 보여주려면 `'*'`와 같은 와일드카드를 사용하면 됩니다. (다른 와일드카드는 지원하지 않습니다)
`callback`이 전달되면 메소드가 비동기로 작동되며 결과는 `callback(filenames)`을 통해 전달됩니다.
Windows와 Linux에선 파일 선택 모드, 디렉터리 선택 모드를 동시에 사용할 수 없습니다.
그래서 이 두 플랫폼에선 `properties``['openFile', 'openDirectory']`로 설정하면 디렉터리 선택 대화 상자가 표시됩니다.
**참고:** Windows와 Linux에선 파일 선택 모드, 디렉터리 선택 모드를 동시에 사용할 수 없습니다.
이러한 이유로 `properties``['openFile', 'openDirectory']`로 설정하면 디렉터리 선택 대화 상자가 표시됩니다.
## dialog.showSaveDialog([browserWindow], [options], [callback])
### `dialog.showSaveDialog([browserWindow][, options][, callback])`
* `browserWindow` BrowserWindow
* `options` Object
* `browserWindow` BrowserWindow (optional)
* `options` Object (optional)
* `title` String
* `defaultPath` String
* `filters` Array
* `callback` Function
* `callback` Function (optional)
작업에 성공하면
작업에 성공하면 유저가 선택한 파일의 경로를 포함한 배열을 반환합니다. 그 외의 경우엔 `undefined`를 반환합니다.
작업에 성공하면 콜백으로 유저가 선택한 파일의 경로를 포함한 배열을 반환합니다. 그 외엔 `undefined`를 반환합니다.
`filters`를 지정하면 유저가 저장 가능한 파일 형식을 지정할 수 있습니다. 사용 방법은 `dialog.showOpenDialog``filters` 속성과 같습니다.
`callback`이 전달되면 메소드가 비동기로 작동되며 결과는 `callback(filename)`을 통해 전달됩니다.
## dialog.showMessageBox([browserWindow], options, [callback])
### `dialog.showMessageBox([browserWindow][, options][, callback])`
* `browserWindow` BrowserWindow
* `options` Object
@ -78,26 +81,26 @@ Windows와 Linux에선 파일 선택 모드, 디렉터리 선택 모드를 동
* `message` String - 대화 상자의 본문 내용입니다.
* `detail` String - 메시지의 추가 정보입니다.
* `icon` [NativeImage](native-image.md)
* `cancelId` Integer - 유저가 대화 상자의 버튼을 클릭하지 않고 대화 상자를 취소했을 때 반환되는 버튼의 index입니다.
기본적으로 버튼 리스트가 "cancel" 또는 "no" 라벨을 가지고 있을 때 해당 버튼의 index를 반환합니다. 따로 두 라벨이 지정되지 않은 경우 0을 반환합니다.
* `cancelId` Integer - 유저가 대화 상자의 버튼을 클릭하지 않고 대화 상자를 취소했을 때 반환되는 버튼의 인덱스입니다.
기본적으로 버튼 리스트가 "cancel" 또는 "no" 라벨을 가지고 있을 때 해당 버튼의 인덱스를 반환합니다. 따로 두 라벨이 지정되지 않은 경우 0을 반환합니다.
OS X와 Windows에선 `cancelId` 지정 여부에 상관없이 "Cancel" 버튼이 언제나 `cancelId`로 지정됩니다.
* `noLink` Boolean - Windows Electron은 "Cancel"이나 "Yes"와 같은 흔히 사용되는 버튼을 찾으려고 시도하고
대화 상자 내에서 해당 버튼을 커맨드 링크처럼 만듭니다. 이 기능으로 앱을 좀 더 Modern Windows 앱처럼 만들 수 있습니다.
이 기능을 원하지 않으면 `noLink`를 true로 지정하면 됩니다.
* `callback` Function
대화 상자를 표시합니다. `browserWindow`를 지정하면 대화 상자가 완전히 닫힐 때까지 창을 사용할 수 없습니다.
완료시 유저가 선택한 버튼의 index를 반환합니다.
대화 상자를 표시합니다. `browserWindow`를 지정하면 대화 상자가 완전히 닫힐 때까지 지정한 창을 사용할 수 없습니다.
완료 시 유저가 선택한 버튼의 인덱스를 반환합니다.
역주: 부정을 표현하는 "아니오", "취소"와 같은 한글 단어는 지원되지 않습니다.
만약 OS X 또는 Windows에서 "확인", "취소"와 같은 순서로 버튼을 지정하게 될 때 Alt + f4로 해당 대화 상자를 끄게 되면 "확인"을 누른로 판단되어 버립니다.
만약 OS X 또는 Windows에서 "확인", "취소"와 같은 순서로 버튼을 지정하게 될 때 Alt + f4로 해당 대화 상자를 끄게 되면 "확인"을 누른 것으로 판단되어 버립니다.
이를 해결하려면 "Cancel"을 대신 사용하거나 BrowserWindow API를 사용하여 대화 상자를 직접 구현해야합니다.
`callback`이 전달되면 메소드가 비동기로 작동되며 결과는 `callback(response)`을 통해 전달됩니다.
## dialog.showErrorBox(title, content)
### `dialog.showErrorBox(title, content)`
에러 메시지를 보여주는 모달 대화 상자를 표시합니다.
에러 메시지를 보여주는 대화 상자를 표시합니다.
이 API는 `app` 모듈의 `ready` 이벤트가 발생하기 전에 사용할 수 있습니다.
이 메소드는 보통 어플리케이션이 시작되기 전에 특정한 에러를 표시하기 위해 사용됩니다.

View file

@ -1,9 +1,10 @@
# `File` 객체
DOM의 File 인터페이스는 네이티브 파일을 추상화 합니다. 유저가 직접적으로 HTML5 File API를 사용하여 작업할 때 파일의 경로를
알 수 있도록 Electron은 파일시스템의 실제 파일 경로를 담은 `path` 속성을 File 인터페이스에 추가하였습니다.
DOM의 File 인터페이스는 네이티브 파일을 추상화 합니다.
유저가 직접 HTML5 File API를 이용하여 작업할 때 선택된 파일의 경로를 알 수 있도록
Electron은 파일의 실제 경로를 담은 `path` 속성을 File 인터페이스에 추가하였습니다.
다음 예제는 drag n drop한 파일의 실제 경로를 가져옵니다:
다음 예제는 앱으로 드래그 앤 드롭한 파일의 실제 경로를 가져옵니다:
```html
<div id="holder">

View file

@ -1,10 +1,12 @@
# Frameless 윈도우
# Frameless Window
Frameless 윈도우는 테두리가 없는 윈도우 창을 말합니다.
Frameless Window는 [테두리](https://developer.mozilla.org/en-US/docs/Glossary/Chrome)가 없는 창입니다.
이 기능은 윈도우 창의 일부분인 툴바와 같이 웹 페이지의 일부분이 아닌 부분을 보이지 않도록 합니다.
[`BrowserWindow`](browser-window.md) 클래스의 옵션에서 설정할 수 있습니다.
## Frameless 윈도우 만들기
## Frameless Window 만들기
Frameless 윈도우를 만드려면 [BrowserWindow](browser-window.md) 객체의 `options`에서 `frame` 옵션을 `false`로 지정하기만 하면됩니다:
Frameless Window를 만드려면 [BrowserWindow](browser-window.md) 객체의 `options`에서 `frame` 옵션을 `false`로 지정하면 됩니다:
```javascript
var BrowserWindow = require('browser-window');
@ -13,7 +15,7 @@ var win = new BrowserWindow({ width: 800, height: 600, frame: false });
## 투명한 창 만들기
Frameless 윈도우의 창의 배경을 투명하게 만들고 싶다면 `transparent` 옵션을 `true`로 바꿔주기만 하면됩니다:
Frameless Window의 창의 배경을 투명하게 만들고 싶다면 `transparent` 옵션을 `true`로 바꿔주기만 하면됩니다:
```javascript
var win = new BrowserWindow({ transparent: true, frame: false });
@ -21,22 +23,20 @@ var win = new BrowserWindow({ transparent: true, frame: false });
### API의 한계
* 투명한 영역을 통과하여 클릭할 수 없습니다. 우리는 이 문제를 해결하기 위해 API를 제공할 예정이지만 현재로써는
* 투명한 영역을 통과하여 클릭할 수 없습니다. 우리는 이 문제를 해결하기 위해 API를 제공할 예정이었지만 현재로써는
[upstream 버그](https://code.google.com/p/chromium/issues/detail?id=387234)로 인해 중단된 상태입니다.
* 투명한 창은 크기를 조절할 수 없습니다. `resizable` 속성을 `true`로 할 경우 몇몇 플랫폼에선 윈도우 크래시가 일어납니다.
* `blur` 필터는 웹 페이지에서만 적용됩니다. 윈도우 아래 컨텐츠에는 블러 효과를 적용할 방법이 없습니다.
* Windows에선 DWM(데스크톱 창 관리자)가 비활성화되어 있을 경우 작동하지 않습니다.
* Linux를 사용할 경우 [alpha channel doesn't work on some NVidia drivers](https://code.google.com/p/chromium/issues/detail?id=369209)
upstream 버그가 있으므로 CLI 옵션에 `--enable-transparent-visuals --disable-gpu`을 추가해야 합니다.
* 투명한 창은 크기를 조절할 수 없습니다. `resizable` 속성을 `true`로 할 경우 몇몇 플랫폼에선 크래시가 일어납니다.
* `blur` 필터는 웹 페이지에서만 적용됩니다. 윈도우 아래 컨텐츠에는 블러 효과를 적용할 방법이 없습니다. (예시: 유저의 시스템에 열린 다른 어플리케이션)
* Windows에선 DWM(데스크톱 창 관리자)가 비활성화되어 있을 경우 투명한 창이 작동하지 않습니다.
* Linux를 사용할 경우 [alpha channel doesn't work on some NVidia drivers](https://code.google.com/p/chromium/issues/detail?id=369209)
upstream 버그가 있는 관계로 투명한 창 기능을 사용하려면 CLI 옵션에 `--enable-transparent-visuals --disable-gpu`을 추가해야 합니다.
이 옵션은 GPU의 사용을 중단하고 윈도우를 생성하는데 ARGB를 사용할 수 있도록 해줍니다.
* OS X(Mac)에선 네이티브 윈도우의 그림자가 투명한 창에선 보이지 않습니다.
* OS X(Mac)에선 네이티브 창에서 보여지는 그림자가 투명한 창에선 보이지 않습니다.
## 드래그 가능 위치 지정
기본적으로 Frameless 윈도우는 드래그 할 수 없습니다.
어플리케이션의 CSS에서 특정 범위를 `-webkit-app-region: drag`로 지정하면 OS의 기본 타이틀바 처럼 드래그 되도록 할 수 있습니다.
기본적으로 Frameless Window는 드래그 할 수 없습니다.
어플리케이션의 CSS에서 특정 범위를 `-webkit-app-region: drag`로 지정하면 OS의 기본 타이틀 바 처럼 드래그 되도록 할 수 있습니다.
그리고 `-webkit-app-region: no-drag`를 지정해서 드래그 불가능 영역을 만들 수도 있습니다. 현재 사각형 형태의 범위만 지원합니다.
창 전체를 드래그 가능하게 만드려면 `-webkit-app-region: drag``body`의 스타일에 지정하면 됩니다:
@ -54,13 +54,13 @@ button {
}
```
또한 커스텀 타이틀바를 만들어 사용할 때 타이틀바 내부의 버튼도 드래그 불가능 영역으로 지정해야 합니다.
따로 커스텀 타이틀 바를 만들어 사용할 때는 타이틀 바 내부의 모든 버튼을 드래그 불가능 영역으로 지정해야 합니다.
## 텍스트 선택
한가지, Frameless 윈도우에서 텍스트가 선택되는 드래그 동작은 혼란을 야기할 수 있습니다.
예를 들어 타이틀바를 드래그 할 때 타이틀바의 텍스트를 실수로 선택할 수 있습니다.
이를 방지하기 위해 다음과 같이 드래그 영역의 텍스트 선택 동작을 비활성화해야 할 필요가 있습니다:
Frameless Window에서 텍스트가 선택되는 드래그 동작은 혼란을 야기할 수 있습니다.
예를 들어 타이틀 바를 드래그 할 때 타이틀 바의 텍스트를 실수로 선택할 수 있습니다.
이를 방지하기 위해 다음과 같이 드래그 영역의 텍스트 선택 기능을 비활성화해야 할 필요가 있습니다:
```css
.titlebar {
@ -71,5 +71,5 @@ button {
## 컨텍스트 메뉴
몇몇 플랫폼에선 드래그 가능 영역이 non-client 프레임으로 처리됩니다. 그래서 이 영역에서 오른쪽 클릭 할 경우 시스템 메뉴가 팝업 됩니다.
그래서 컨텍스트 메뉴 지정이 모든 플랫폼에서 정상적으로 작동하게 하려면 커스텀 컨텍스트 메뉴를 드래그 영역 내에 만들어선 안됩니다.
몇몇 플랫폼에선 드래그 가능 영역이 non-client 프레임으로 처리됩니다. 이러한 플랫폼에선 드래그 가능 영역에서 오른쪽 클릭 할 경우 시스템 메뉴가 팝업 됩니다.
이러한 이유로 컨텍스트 메뉴 지정 시 모든 플랫폼에서 정상적으로 작동하게 하려면 커스텀 컨텍스트 메뉴를 드래그 영역 내에 만들어선 안됩니다.

View file

@ -1,8 +1,9 @@
# global-shortcut
`global-shortcut` 모듈은 운영체제의 전역 키보드 단축키를 설정 등록/해제 하는 방법을 제공합니다.
이 모듈을 사용하여 사용자가 다양한 단축키 작업을 할 수 있도록 단축키를 정의 할 수 있습니다.
참고로 설정된 단축키는 어플리케이션이 백그라운드로 작동(창이 포커스 되지 않음) 할 때도 여전히 계속 작동합니다.
`global-shortcut` 모듈은 운영체제의 전역 키보드 단축키를 등록/해제 하는 방법을 제공합니다.
이 모듈을 사용하여 사용자가 다양한 작업을 편하게 할 수 있도록 단축키를 정의 할 수 있습니다.
**참고:** 등록된 단축키는 어플리케이션이 백그라운드로 작동(창이 포커스 되지 않음) 할 때도 계속해서 작동합니다.
이 모듈은 `app` 모듈의 `ready` 이벤트 이전에 사용할 수 없습니다.
```javascript
@ -30,25 +31,29 @@ app.on('will-quit', function() {
});
```
## globalShortcut.register(accelerator, callback)
## Methods
`global-shortcut` 모듈은 다음과 같은 메서드를 가지고 있습니다:
### `globalShortcut.register(accelerator, callback)`
* `accelerator` [Accelerator](accelerator.md)
* `callback` Function
`accelerator`로 표현된 전역 단축키를 등록합니다. 유저로부터 등록된 단축키가 눌렸을 경우 `callback` 함수가 호출됩니다.
## globalShortcut.isRegistered(accelerator)
### `globalShortcut.isRegistered(accelerator)`
* `accelerator` [Accelerator](accelerator.md)
지정된 `accelerator` 단축키가 등록되었는지 여부를 확인합니다. 반환값은 boolean(true, false) 입니다.
## globalShortcut.unregister(accelerator)
### `globalShortcut.unregister(accelerator)`
* `accelerator` [Accelerator](accelerator.md)
`키코드`에 해당하는 전역 단축키를 등록 해제합니다.
`accelerator`에 해당하는 전역 단축키를 등록 해제합니다.
## globalShortcut.unregisterAll()
### `globalShortcut.unregisterAll()`
모든 전역 단축키 등록을 해제합니다.

View file

@ -1,17 +1,21 @@
# ipc (main process)
랜더러 프로세스(웹 페이지)로 부터 동기 또는 비동기로 메시지를 받아 처리합니다.
`ipc` (main process) 모듈은 메인 프로세스에서 사용할 때 랜더러 프로세스(웹 페이지)에서 전달된 동기 또는 비동기 메시지를 보내고 받는 방법을 제공합니다.
랜더러 프로세스에서 메시지를 전달하면 이 모듈을 통해 메시지를 받을 수 있습니다.
랜더러로부터 발신된 메시지들은 모두 이 모듈에서 `channel` 이라는 특정 이벤트 이름을 통해 수신할 수 있습니다.
동기 메시지는 `event.returnValue`를 이용하여 반환값(답장)을 설정할 수 있습니다. 비동기 메시지라면 `event.sender.send(...)`를 사용하면 됩니다.
## 메시지 전송
또한 메인 프로세스에서 랜더러 프로세스로 메시지를 보내는 것도 가능합니다.
자세한 내용은 [WebContents.send](browser-window.md#webcontentssendchannel-args)를 참고 하세요.
물론 메인 프로세스에서 랜더러 프로세스로 메시지를 보내는 것도 가능합니다.
자세한 내용은 [WebContents.send](browser-window.md#webcontentssendchannel-args)를 참고하세요.
보내진 메시지들을 처리하는 예제입니다:
- 메시지를 전송할 때 이벤트 이름은 `channel`이 됩니다.
- 메시지에 동기로 응답할 땐 반드시 `event.returnValue`를 설정해야 합니다.
- 메시지를 비동기로 응답할 땐 `event.sender.send(...)` 메서드를 사용할 수 있습니다.
랜더러 프로세스와 메인 프로세스간에 메시지를 전달하고 받는 예제입니다:
```javascript
// 메인 프로세스에서 처리.
// 메인 프로세스
var ipc = require('ipc');
ipc.on('asynchronous-message', function(event, arg) {
console.log(arg); // prints "ping"
@ -25,7 +29,7 @@ ipc.on('synchronous-message', function(event, arg) {
```
```javascript
// 랜더러 프로세스에서의 처리 (web page).
// 랜더러 프로세스 (web page)
var ipc = require('ipc');
console.log(ipc.sendSync('synchronous-message', 'ping')); // prints "pong"
@ -35,12 +39,33 @@ ipc.on('asynchronous-reply', function(arg) {
ipc.send('asynchronous-message', 'ping');
```
## Class: Event
## 메시지 리스닝
### Event.returnValue
`ipc` 모듈은 다음과 같은 이벤트 메서드를 가지고 있습니다:
동기 메시지를 설정합니다.
### `ipc.on(channel, callback)`
### Event.sender
* `channel` String - 이벤트 이름
* `callback` Function
메시지를 보내온 sender `WebContents` 객체입니다.
이벤트가 발생하면 `callback``event` 객체와 `arg` 메시지가 포함되어 호출됩니다.
## IPC Events
`callback`에서 전달된 `event` 객체는 다음과 같은 메서드와 속성을 가지고 있습니다:
### `Event.returnValue`
이 메시지를 지정하면 동기 메시지를 전달합니다.
### `Event.sender`
메시지를 보낸 `WebContents` 객체를 반환합니다.
### `Event.sender.send(channel[, arg1][, arg2][, ...])`
* `channel` String - The event name.
* `arg` (optional)
랜더러 프로세스로 비동기 메시지를 전달합니다.
옵션으로 `arg`에 한 개 또는 여러 개의 메시지를 포함할 수 있습니다. 모든 타입을 사용할 수 있습니다.

View file

@ -1,25 +1,45 @@
# ipc (renderer)
`ipc` 모듈은 메인 프로세스로 메시지를 동기 또는 비동기로 보내고 받을 수 있는 몇 가지 방법을 제공합니다.
만약 랜더러 프로세스에서 메인 프로세스의 모듈을 직접적으로 사용하고 싶다면 [remote](remote.md) 모듈을 사용하는 것을 고려해보는 것이 좋습니다.
`ipc` (renderer) 모듈은 메인 프로세스로 동기 또는 비동기 메시지를 보내고 받는 방법을 제공합니다.
물론 메인 프로세스로부터 받은 메시지에 응답할 수도 있습니다.
[ipc (main process)](ipc-main-process.md)에서 예제를 볼 수 있습니다.
**참고:** 만약 랜더러 프로세스에서 메인 프로세스의 모듈을 직접적 사용하고 싶다면 [remote](remote.md) 모듈을 사용하는 것을 고려해보는 것이 좋습니다.
## ipc.send(channel[, args...])
[ipc (main process)](ipc-main-process.md)에서 예제를 확인 할 수 있습니다.
지정한 `channel`을 통해 `args..`를 비동기로 메시지를 보냅니다. 메인 프로세스는 `ipc` 모듈의 `channel` 이벤트를 통해 메시지를 받을 수 있습니다.
## Methods
## ipc.sendSync(channel[, args...])
`ipc` 모듈은 다음과 같은 메서드를 가지고 있습니다:
지정한 `channel`을 통해 `args..`를 동기로 메시지를 보냅니다. 그리고 메인 프로세스에서 보낸 결과를 반환합니다.
메인 프로세스는 `ipc` 모듈의 `channel` 이벤트를 통해 메시지를 받을 수 있습니다. 그리고 `event.returnValue`를 통해 반환값을 설정할 수 있습니다.
**참고:** 이 메소드들을 사용하여 `message`를 보낼 땐 반드시 메인 프로세스의
[`ipc (main process)`](ipc-main-process.md) 모듈에서도 이벤트 리스너를 등록해 두어야 합니다.
역자 주: `channel`은 이벤트 이름입니다.
### `ipc.send(channel[, arg1][, arg2][, ...])`
**알림:** 보통 개발자들은 해당 API를 사용하려 하지 않습니다. 동기 ipc 작업은 랜더러 프로세스의 모든 작업을 중단시킵니다.
* `channel` String - 이벤트 이름
* `arg` (optional)
## ipc.sendToHost(channel[, args...])
`channel`을 통해 메인 프로세스에 비동기 메시지를 보냅니다.
옵션으로 `arg`에 한 개 또는 여러 개의 메시지를 포함할 수 있습니다. 모든 타입을 사용할 수 있습니다.
메인 프로세스는 `ipc`를 통해 `channel` 이벤트를 리스닝 할 수 있습니다.
`ipc.send`와 비슷하지만 메시지를 메인 프로세스 대신 호스트 페이지로 보냅니다.
### `ipc.sendSync(channel[, arg1][, arg2][, ...])`
이 메소드는 보통 `<webview>`와 호스트 페이지 간의 통신에 사용됩니다.
* `channel` String - 이벤트 이름
* `arg` (optional)
`channel`을 통해 메인 프로세스에 동기 메시지를 보냅니다.
옵션으로 `arg`에 한 개 또는 여러 개의 메시지를 포함할 수 있습니다. 모든 타입을 사용할 수 있습니다.
메인 프로세스는 `ipc`를 통해 `channel` 이벤트를 리스닝 할 수 있습니다.
메인 프로세스에선 `ipc` 모듈의 `channel` 이벤트를 통해 받은 `event.returnValue`로 회신 할 수 있습니다.
**참고:** 동기 메시징은 모든 랜더러 프로세스의 작업을 일시 중단시킵니다. 이 메서드를 사용하는 것을 권장하지 않습니다.
### `ipc.sendToHost(channel[, arg1][, arg2][, ...])`
* `channel` String - 이벤트 이름
* `arg` (optional)
`ipc.send`와 비슷하지만 이벤트를 메인 프로세스 대신 호스트 페이지내의 `<webview>`로 보냅니다.
옵션으로 `arg`에 한 개 또는 여러 개의 메시지를 포함할 수 있습니다. 모든 타입을 사용할 수 있습니다.

View file

@ -1,12 +1,18 @@
# menu-item
# MenuItem
`menu-item` 모듈은 어플리케이션 또는 컨텐츠 [`menu`](menu.md)에 아이템을 추가할 수 있도록 관련 클래스를 제공합니다.
[`menu`](menu.md)에서 예제를 확인할 수 있습니다.
## Class: MenuItem
`MenuItem` 인스턴스 객체에서 사용할 수 있는 메서드입니다:
### new MenuItem(options)
* `options` Object
* `click` Function - 메뉴 아이템이 클릭될 때 호출되는 콜백함수
* `selector` String - First Responder가 클릭될 때 호출 되는 선택자 (OS X 전용)
* `click` Function - 메뉴 아이템이 클릭될 때 `click(menuItem, browserWindow)` 형태로 호출 되는 콜백 함수
* `role` String - 메뉴 아이템의 액션을 정의합니다. 이 속성을 지정하면 `click` 속성이 무시됩니다.
* `type` String - `MenuItem`의 타입 `normal`, `separator`, `submenu`, `checkbox` 또는 `radio` 사용가능
* `label` String
* `sublabel` String
@ -18,3 +24,29 @@
* `submenu` Menu - 보조메뉴를 설정합니다. `type``submenu`일 경우 반드시 설정해야합니다. 일반 메뉴 아이템일 경우 생략할 수 있습니다.
* `id` String - 현재 메뉴 아이템에 대해 유일키를 지정합니다. 이 키는 이후 `position` 옵션에서 사용할 수 있습니다.
* `position` String - 미리 지정한 `id`를 이용하여 메뉴 아이템의 위치를 세밀하게 조정합니다.
When creating menu items, it is recommended to specify `role` instead of
manually implementing the behavior if there is matching action, so menu can have
best native experience.
The `role` property can have following values:
* `undo`
* `redo`
* `cut`
* `copy`
* `paste`
* `selectall`
* `minimize` - Minimize current window
* `close` - Close current window
On OS X `role` can also have following additional values:
* `about` - Map to the `orderFrontStandardAboutPanel` action
* `hide` - Map to the `hide` action
* `hideothers` - Map to the `hideOtherApplications` action
* `unhide` - Map to the `unhideAllApplications` action
* `front` - Map to the `arrangeInFront` action
* `window` - The submenu is a "Window" menu
* `help` - The submenu is a "Help" menu
* `services` - The submenu is a "Services" menu

View file

@ -1,11 +1,12 @@
# menu
# Menu
`Menu` 클래스는 어플리케이션 메뉴와 컨텍스트 메뉴를 만들 때 사용됩니다.
메뉴는 여러 개의 메뉴 아이템으로 구성되고 서브 메뉴를 가질 수도 있습니다.
`menu` 클래스는 어플리케이션 메뉴와 [컨텍스트 메뉴](https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/PopupGuide/ContextMenus)를 만들 때 사용됩니다.
이 모듈은 메인 프로세스용 모듈이지만 `remote` 모듈을 통해 랜더러 프로세스에서도 사용할 수 있습니다.
각 메뉴는 여러 개의 [메뉴 아이템](menu-item.md)으로 구성되고 서브 메뉴를 가질 수도 있습니다.
다음 예제는 웹 페이지 내에서 [remote](remote.md) 모듈을 활용하여 동적으로 메뉴를 생성하는 예제입니다.
이 예제에서 만들어진 메뉴는 유저가 페이지에서 오른쪽 클릭을 할 때 마우스 위치에 팝업 형태로 표시됩니다:
그리고 유저가 페이지에서 오른쪽 클릭을 할 때마다 마우스 위치에 팝업 형태로 메뉴를 표시합니다:
```html
<!-- index.html -->
@ -26,69 +27,22 @@ window.addEventListener('contextmenu', function (e) {
</script>
```
다음 예제는 template API를 활용하여 어플리케이션 메뉴를 만드는 간단한 예제입니다:
또 하나의 예를 들자면 다음 예제는 랜더러 프로세스에서 template API를 사용하여 어플리케이션 메뉴를 만듭니다:
**Windows 와 Linux 유저 주의:** 각 메뉴 아이템의 `selector` 멤버는 Mac 운영체제 전용입니다. [Accelerator 옵션](accelerator.md)
```html
<!-- index.html -->
<script>
var remote = require('remote');
var Menu = remote.require('menu');
```javascript
var template = [
{
label: 'Electron',
submenu: [
{
label: 'About Electron',
selector: 'orderFrontStandardAboutPanel:'
},
{
type: 'separator'
},
{
label: 'Services',
submenu: []
},
{
type: 'separator'
},
{
label: 'Hide Electron',
accelerator: 'CmdOrCtrl+H',
selector: 'hide:'
},
{
label: 'Hide Others',
accelerator: 'CmdOrCtrl+Shift+H',
selector: 'hideOtherApplications:'
},
{
label: 'Show All',
selector: 'unhideAllApplications:'
},
{
type: 'separator'
},
{
label: 'Quit',
accelerator: 'CmdOrCtrl+Q',
selector: 'terminate:'
},
]
},
{
label: 'Edit',
submenu: [
{
label: 'Undo',
accelerator: 'CmdOrCtrl+Z',
selector: 'undo:'
role: 'undo'
},
{
label: 'Redo',
accelerator: 'Shift+CmdOrCtrl+Z',
selector: 'redo:'
role: 'redo'
},
{
type: 'separator'
@ -96,23 +50,23 @@ var template = [
{
label: 'Cut',
accelerator: 'CmdOrCtrl+X',
selector: 'cut:'
role: 'cut'
},
{
label: 'Copy',
accelerator: 'CmdOrCtrl+C',
selector: 'copy:'
role: 'copy'
},
{
label: 'Paste',
accelerator: 'CmdOrCtrl+V',
selector: 'paste:'
role: 'paste'
},
{
label: 'Select All',
accelerator: 'CmdOrCtrl+A',
selector: 'selectAll:'
}
role: 'selectall'
},
]
},
{
@ -121,71 +75,153 @@ var template = [
{
label: 'Reload',
accelerator: 'CmdOrCtrl+R',
click: function() { remote.getCurrentWindow().reload(); }
click: function(item, focusedWindow) {
if (focusedWindow)
focusedWindow.reload();
}
},
{
label: 'Toggle DevTools',
accelerator: 'Alt+CmdOrCtrl+I',
click: function() { remote.getCurrentWindow().toggleDevTools(); }
label: 'Toggle Full Screen',
accelerator: (function() {
if (process.platform == 'darwin')
return 'Ctrl+Command+F';
else
return 'F11';
})(),
click: function(item, focusedWindow) {
if (focusedWindow)
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
}
},
{
label: 'Toggle Developer Tools',
accelerator: (function() {
if (process.platform == 'darwin')
return 'Alt+Command+I';
else
return 'Ctrl+Shift+I';
})(),
click: function(item, focusedWindow) {
if (focusedWindow)
focusedWindow.toggleDevTools();
}
},
]
},
{
label: 'Window',
role: 'window',
submenu: [
{
label: 'Minimize',
accelerator: 'CmdOrCtrl+M',
selector: 'performMiniaturize:'
role: 'minimize'
},
{
label: 'Close',
accelerator: 'CmdOrCtrl+W',
selector: 'performClose:'
role: 'close'
},
]
},
{
label: 'Help',
role: 'help',
submenu: [
{
label: 'Learn More',
click: function() { require('shell').openExternal('http://electron.atom.io') }
},
]
},
];
if (process.platform == 'darwin') {
var name = require('app').getName();
template.unshift({
label: name,
submenu: [
{
label: 'About ' + name,
role: 'about'
},
{
type: 'separator'
},
{
label: 'Bring All to Front',
selector: 'arrangeInFront:'
}
label: 'Services',
role: 'services',
submenu: []
},
{
type: 'separator'
},
{
label: 'Hide ' + name,
accelerator: 'Command+H',
role: 'hide'
},
{
label: 'Hide Others',
accelerator: 'Command+Shift+H',
role: 'hideothers:'
},
{
label: 'Show All',
role: 'unhide:'
},
{
type: 'separator'
},
{
label: 'Quit',
accelerator: 'Command+Q',
click: function() { app.quit(); }
},
]
},
{
label: 'Help',
submenu: []
}
];
});
// Window menu.
template[3].submenu.push(
{
type: 'separator'
},
{
label: 'Bring All to Front',
role: 'front'
}
);
}
menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
</script>
```
## Class: Menu
### new Menu()
### `new Menu()`
새로운 메뉴를 생성합니다.
### Class Method: Menu.setApplicationMenu(menu)
### Methods
`menu` 클래스는 다음과 같은 메서드를 가지고 있습니다:
### `Menu.setApplicationMenu(menu)`
* `menu` Menu
지정한 `menu`를 이용하여 어플리케이션 메뉴를 만듭니다. OS X에선 상단바에 표시되며 Windows와 Linux에선 각 창의 상단에 표시됩니다.
지정한 `menu`어플리케이션 메뉴로 만듭니다. OS X에선 상단바에 표시되며 Windows와 Linux에선 각 창의 상단에 표시됩니다.
### Class Method: Menu.sendActionToFirstResponder(action)
### `Menu.sendActionToFirstResponder(action)` _OS X_
* `action` String
`action`을 어플리케이션의 first responder에 전달합니다.
함수는 Cocoa 메뉴 동작을 에뮬레이트 하는데 사용되며 보통 `MenuItem``selector` 속성에 사용됩니다.
메서드는 Cocoa 메뉴 동작을 에뮬레이트 하는데 사용되며 보통 `MenuItem``selector` 속성에 사용됩니다.
**알림:** 이 함수는 OS X에서만 사용할 수 있습니다.
**참고:** 이 메서드는 OS X에서만 사용할 수 있습니다.
### Class Method: Menu.buildFromTemplate(template)
### `Menu.buildFromTemplate(template)`
* `template` Array
@ -193,57 +229,58 @@ Menu.setApplicationMenu(menu);
또한 `template`에는 다른 속성도 추가할 수 있으며 메뉴가 만들어질 때 해당 메뉴 아이템의 프로퍼티로 변환됩니다.
### Menu.popup(browserWindow, [x, y])
### `Menu.popup(browserWindow[, x, y])`
* `browserWindow` BrowserWindow
* `x` Number
* `y` Number
* `x` Number (optional)
* `y` Number (만약 `x`를 지정했을 경우 `y`도 필수로 지정해야 합니다)
메뉴를 `browserWindow` 안에서 팝업으로 표시합니다.
옵션으로 메뉴를 표시할 `(x,y)` 좌표를 임의로 지정할 수 있습니다. 따로 지정하지 않은 경우 마우스 커서 위치에 표시됩니다.
메뉴를 `browserWindow` 내부 팝업으로 표시합니다.
옵션으로 메뉴를 표시할 `(x,y)` 좌표를 지정할 수 있습니다.
따로 좌표를 지정하지 않은 경우 마우스 커서 위치에 표시됩니다.
### Menu.append(menuItem)
### `Menu.append(menuItem)`
* `menuItem` MenuItem
메뉴의 리스트 끝에 `menuItem`을 삽입합니다.
### Menu.insert(pos, menuItem)
### `Menu.insert(pos, menuItem)`
* `pos` Integer
* `menuItem` MenuItem
`pos` 위치에 `menuItem`을 삽입합니다.
### Menu.items
### `Menu.items()`
메뉴가 가지고 있는 메뉴 아이템들의 배열입니다.
## OS X 어플리케이션 메뉴에 대해 알아 둬야 할 것들
OS X에선 Windows, Linux와 달리 완전히 다른 어플리케이션 메뉴 스타일을 가지고 있습니다.
어플리케이션을 네이티브처럼 작동할 수 있도록 하기 위해 다음 몇 가지 유의 사항을 숙지해야 합니다.
그래서 어플리케이션을 네이티브처럼 작동할 수 있도록 하기 위해 다음 몇 가지 유의 사항을 숙지해야 합니다.
### 기본 메뉴
OS X엔 `Services``Windows`와 같은 많은 시스템 지정 기본 메뉴가 있습니다.
기본 메뉴를 만들려면 다음 중 하나를 메뉴의 라벨로 지정하기만 하면 됩니다.
기본 메뉴를 만들려면 반드시 다음 리스트 중 한 가지를 선택하여 메뉴의 `role`로 지정해야 합니다.
그러면 Electron이 자동으로 인식하여 해당 메뉴를 기본 메뉴로 만듭니다:
* `Window`
* `Help`
* `Services`
* `window`
* `help`
* `services`
### 기본 메뉴 아이템 동작
### 메뉴 아이템 기본 동작
OS X는 몇몇의 메뉴 아이템에 대해 `About xxx`, `Hide xxx`, `Hide Others`와 같은 기본 동작을 제공하고 있습니다. (`selector`라고 불립니다)
메뉴 아이템의 기본 동작을 지정하려면 메뉴 아이템의 `selector` 속성을 사용하면 됩니다.
OS X는 몇가지 메뉴 아이템에 대해 `About xxx`, `Hide xxx`, `Hide Others`와 같은 기본 동작을 제공하고 있습니다.
메뉴 아이템의 기본 동작을 지정하려면 반드시 메뉴 아이템의 `role` 속성을 지정해야 합니다.
### 메인 메뉴의 이름
OS X에선 지정한 어플리케이션 메뉴에 상관없이 메뉴의 첫번째 라벨은 언제나 어플리케이션의 이름이 됩니다.
어플리케이션 이름을 변경하려면 앱 번들내의 `Info.plist` 파일을 수정해야합니다.
자세한 내용은 [About Information Property List Files](https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html)을 참고하세요.
자세한 내용은 [About Information Property List Files][AboutInformationPropertyListFiles] 문서를 참고하세요.
## 메뉴 아이템 위치
@ -257,7 +294,7 @@ OS X에선 지정한 어플리케이션 메뉴에 상관없이 메뉴의 첫번
* `endof` - 이 아이템을 id의 논리 그룹에 맞춰서 각 그룹의 항목 뒤에 삽입합니다. (그룹은 분리자 아이템에 의해 만들어집니다)
만약 참조된 아이템의 분리자 그룹이 존재하지 않을 경우 지정된 id로 새로운 분리자 그룹을 만든 후 해당 그룹의 뒤에 삽입됩니다.
위치를 지정한 아이템의 뒤에 위치가 지정되지 않은 아이템이 있을 경우 해당 아이템의 위치가 지정되기 전까지 이전에 위치가 지정된 아이템의 위치 지정을 따릅니다.
위치를 지정한 아이템의 뒤에 위치가 지정되지 않은 아이템이 있을 경우 각 아이템의 위치가 지정되기 전까지 모든 아이템이 위치가 지정된 아이템의 뒤에 삽입됩니다.
이에 따라 위치를 이동하고 싶은 특정 그룹의 아이템들이 있을 경우 해당 그룹의 맨 첫번째 메뉴 아이템의 위치만을 지정하면 됩니다.
### 예제
@ -309,3 +346,5 @@ OS X에선 지정한 어플리케이션 메뉴에 상관없이 메뉴의 첫번
- 2
- 3
```
[AboutInformationPropertyListFiles]: https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html

View file

@ -1,15 +1,16 @@
# NativeImage
Electron은 파일 경로나 `NativeImage` 인스턴스를 전달하여 사용하는 이미지 API를 가지고 있습니다. `null`을 전달할 경우 빈 이미지가 사용됩니다.
Electron은 파일 경로 또는 `NativeImage` 인스턴스를 통해 이미지를 사용할 수 있는 API를 가지고 있습니다.
`null`을 전달할 경우 빈 이미지가 생성됩니다.
예를 들어 트레이 메뉴를 만들거나 윈도우의 아이콘을 설정할 때 다음과 같이 `문자열`파일 경로를 전달할 수 있습니다:
예를 들어 트레이 메뉴를 만들거나 윈도우의 아이콘을 설정할 때 다음과 같이 파일 경로를 전달하여 이미지를 사용할 수 있습니다:
```javascript
var appIcon = new Tray('/Users/somebody/images/icon.png');
var window = new BrowserWindow({icon: '/Users/somebody/images/window.png'});
```
또는 클립보드로부터 이미지를 읽어올 수 있습니다:
이 예제는 클립보드로부터 가져온 `NativeImage`로 트레이 메뉴를 생성합니다:
```javascript
var clipboard = require('clipboard');
@ -19,7 +20,8 @@ var appIcon = new Tray(image);
## 지원하는 포맷
현재 `PNG``JPEG` 포맷을 지원하고 있습니다. 손실 없는 이미지 압축과 투명도 지원을 위해 `PNG` 사용을 권장합니다.
현재 `PNG``JPEG` 이미지 포맷을 지원하고 있습니다.
손실 없는 이미지 압축과 투명도 지원을 위해 `PNG` 사용을 권장합니다.
그리고 Windows에서는 `ICO` 포맷도 사용할 수 있습니다.
@ -27,9 +29,9 @@ var appIcon = new Tray(image);
플랫폼이 high-DPI를 지원하는 경우 `@2x`와 같이 이미지의 파일명 뒤에 접미사를 추가하여 고해상도 이미지로 지정할 수 있습니다.
예를 들어 `icon.png` 라는 기본 해상도의 이미지를 기준으로 크기를 두 배로 늘린 이미지를 `icon@2x.png`와 같이 이름을 지정하면 고해상도 이미지로 처리됩니다.
예를 들어 `icon.png` 라는 기본 해상도의 이미지를 기준으로 크기를 두 배로 늘린 이미지를 `icon@2x.png` 처럼 지정하면 고해상도 이미지로 처리됩니다.
서로 다른 해상도(DPI)의 이미지를 지원하고 싶다면 다중 해상도의 이미지를 접미사를 붙여 한 폴더에 넣으면 됩니다. 이 이미지를 사용(로드)할 땐 접미사를 붙이지 않습니다:
서로 다른 해상도(DPI)의 이미지를 같이 지원하고 싶다면 다중 해상도의 이미지를 접미사를 붙여 한 폴더에 같이 넣으면 됩니다. 이 이미지를 사용(로드)할 땐 따로 접미사를 붙이지 않습니다:
```text
images/
@ -64,69 +66,79 @@ var appIcon = new Tray('/Users/somebody/images/icon.png');
가장 일반적으로 템플릿 이미지는 밝고 어두운 테마 색상으로 변경할 수 있는 메뉴 바 아이콘 등에 사용되고 있습니다.
템플릿 이미지는 Mac 운영체제만 지원합니다.
**참고:** 템플릿 이미지는 OS X 운영체제만 지원합니다.
템플릿 이미지를 지정하려면 다음 예제와 같이 파일명에 `Template` 문자열을 추가해야 합니다:
* `xxxTemplate.png`
* `xxxTemplate@2x.png`
## nativeImage.createEmpty()
## Methods
`NativeImage` 클래스는 다음과 같은 메서드를 가지고 있습니다:
### `NativeImage.createEmpty()`
`NativeImage` 인스턴스를 만듭니다.
## nativeImage.createFromPath(path)
### `NativeImage.createFromPath(path)`
* `path` String
`path`로부터 이미지를 로드하여 새로운 `NativeImage` 인스턴스를 만듭니다.
## nativeImage.createFromBuffer(buffer[, scaleFactor])
### `NativeImage.createFromBuffer(buffer[, scaleFactor])`
* `buffer` [Buffer][buffer]
* `scaleFactor` Double
* `scaleFactor` Double (optional)
`buffer`로부터 이미지를 로드하여 새로운 `NativeImage` 인스턴스를 만듭니다. `scaleFactor`는 1.0이 기본입니다.
## nativeImage.createFromDataUrl(dataUrl)
### `NativeImage.createFromDataUrl(dataUrl)`
* `dataUrl` String
`dataUrl`로부터 이미지를 로드하여 새로운 `NativeImage` 인스턴스를 만듭니다.
## Class: NativeImage
## Instance Methods
이미지를 표현한 클래스입니다.
`nativeImage` 인스턴스 객체에서 사용할 수 있는 메서드 입니다:
### NativeImage.toPng()
```javascript
var NativeImage = require('native-image');
var image = NativeImage.createFromPath('/Users/somebody/images/icon.png');
```
### `image.toPng()`
`PNG` 이미지를 인코딩한 데이터를 [Buffer][buffer]로 반환합니다.
### NativeImage.toJpeg(quality)
### `image.toJpeg(quality)`
* `quality` Integer (0 - 100 사이의 값)
* `quality` Integer 0 - 100 사이의 값 (**required**)
`JPEG` 이미지를 인코딩한 데이터를 [Buffer][buffer]로 반환합니다.
### NativeImage.toDataUrl()
### `image.toDataUrl()`
이미지의 data URL을 반환합니다.
이미지를 data URL로 반환합니다.
### NativeImage.isEmpty()
### `image.isEmpty()`
이미지가 비었는지를 체크합니다.
이미지가 비었는지 확인합니다.
### NativeImage.getSize()
### `image.getSize()`
이미지의 사이즈를 반환합니다.
### NativeImage.setTemplateImage(option)
### `image.setTemplateImage(option)`
* `option` Boolean
해당 이미지를 템플릿 이미지로 설정합니다.
### NativeImage.isTemplateImage()
### `image.isTemplateImage()`
이미지가 템플릿 이미지인지 확인합니다.

View file

@ -16,18 +16,22 @@ app.on('ready', function() {
});
```
## Event: suspend
## Events
`power-monitor` 모듈은 다음과 같은 이벤트를 가지고 있습니다:
## Event: `suspend`
시스템이 절전모드로 진입할 때 발생하는 이벤트입니다.
## Event: resume
## Event: `resume`
시스템의 절전모드가 해제될 때 발생하는 이벤트입니다.
## Event: on-ac
## Event: `on-ac`
시스템이 AC 어뎁터 충전기를 사용하기 시작할 때 발생하는 이벤트입니다.
## Event: on-battery
## Event: `on-battery`
시스템이 배터리를 사용하기 시작할 때 발생하는 이벤트입니다.

View file

@ -1,6 +1,6 @@
# power-save-blocker
# powerSaveBlocker
`power-save-blocker` 모듈은 시스템이 저전력 모드(슬립)로 진입하는 것을 막고 앱 및 화면이 항상 활성화되어 있는 상태를 만들 수 있도록 해줍니다.
`power-save-blocker` 모듈은 시스템이 저전력(슬립) 모드로 진입하는 것을 막고 앱 시스템과 화면이 항상 활성화 상태를 유지할 수 있도록 하는 몇가지 유틸리티를 제공하는 모듈입니다.
예제:
@ -13,31 +13,34 @@ console.log(powerSaveBlocker.isStarted(id));
powerSaveBlocker.stop(id);
```
## powerSaveBlocker.start(type)
## Methods
`powerSaveBlocker` 모듈은 다음과 같은 메서드를 가지고 있습니다:
### `powerSaveBlocker.start(type)`
* `type` String - Power save blocker 종류
* `prevent-app-suspension` - 저전력 모드 등으로 인한 어플리케이션 작동 중단을 방지합니다.
시스템을 항시 활성화 상태로 만듭니다, 하지만 화면은 자동으로 꺼질 수 있습니다. 사용 예시: 파일 다운로드, 음악 재생 등.
시스템을 항시 활성화 상태로 만듭니다. 하지만 화면은 자동으로 꺼질 수 있습니다. 사용 예시: 파일 다운로드, 음악 재생 등.
* `prevent-display-sleep`- 슬립 모드 등으로 인한 어플리케이션의 작동 중단을 방지합니다.
시스템을 항시 활성화 상태로 만들고 슬립 모드(화면 꺼짐)를 방지합니다. 사용 예시: 비디오 재생 등.
Power save blocker를 시작하고 시스템이 저전력 모드(슬립)로 진입하는 것을 막니다. 정수로 된 식별 ID를 반환합니다.
시스템이 저전력 모드(슬립)로 진입하는 것을 막기 시작합니다. 정수로 된 식별 ID를 반환합니다.
**알림:**
`prevent-display-sleep` 모드는 `prevent-app-suspension` 보다 우선순위가 높습니다.
가장 높은 우선순위의 모드만 작동합니다. 다시 말해 `prevent-display-sleep` 모드는 언제나 `prevent-app-suspension` 모드의 효과를 덮어씌웁니다.
**참고:** `prevent-display-sleep` 모드는 `prevent-app-suspension` 보다 우선 순위가 높습니다.
두 모드 중 가장 높은 우선 순위의 모드만 작동합니다. 다시 말해 `prevent-display-sleep` 모드는 언제나 `prevent-app-suspension` 모드의 효과를 덮어씌웁니다.
예를 들어 A-요청이 `prevent-app-suspension` 모드를 사용하고 B-요청이 `prevent-display-sleep`를 사용하는 API 호출이 있었다 치면
`prevent-display-sleep` 모드를 사용하는 B의 작동이 중단(stop)되기 전까지 작동하다 B가 중단되면 `prevent-app-suspension` 모드를 사용하는 A가 작동하기 시작합니다.
## powerSaveBlocker.stop(id)
### `powerSaveBlocker.stop(id)`
* `id` Integer - `powerSaveBlocker.start`로 부터 반환되는 power save blocker 식별 ID.
설정한 power save blocker를 중지합니다.
## powerSaveBlocker.isStarted(id)
### `powerSaveBlocker.isStarted(id)`
* `id` Integer - `powerSaveBlocker.start`로 부터 반환되는 power save blocker 식별 ID.
해당하는 id의 `powerSaveBlocker`가 실행중인지 확인합니다.
지정한 id의 `powerSaveBlocker`가 실행 중인지 확인합니다.

View file

@ -1,4 +1,4 @@
# 프로세스 객체
# process
Electron의 `process` 객체는 기존의 node와는 달리 약간의 차이점이 있습니다:
@ -7,6 +7,16 @@ Electron의 `process` 객체는 기존의 node와는 달리 약간의 차이점
* `process.versions['chrome']` String - Chromium의 버전.
* `process.resourcesPath` String - JavaScript 소스코드의 경로.
## process.hang
## Methods
`process` 객체는 다음과 같은 메서드를 가지고 있습니다:
### `process.hang()`
현재 프로세스의 주 스레드를 중단시킵니다.
### `process.setFdLimit(maxDescriptors)` _OS X_ _Linux_
* `maxDescriptors` Integer
`maxDescriptors`에 file descriptor 소프트 리미트를 설정하거나 OS 하드 리미트를 설정합니다. 값은 현재 프로세스에 대해 낮은 값이어야 합니다.

View file

@ -2,7 +2,7 @@
`protocol` 모듈은 이미 있는 프로토콜의 동작을 가로채거나 새로운 프로토콜을 만들 수 있는 기능을 제공합니다.
다음 예제는 `file://` 프로토콜과 같은 일을 하는 커스텀 프로토콜을 설정합니다:
다음 예제는 `file://` 프로토콜과 비슷한 일을 하는 커스텀 프로토콜을 설정합니다:
```javascript
var app = require('app');
@ -20,24 +20,28 @@ app.on('ready', function() {
});
```
**알림:** 이 모듈은 `ready` 이벤트가 호출된 이후에만 사용할 수 있습니다.
**참고:** 이 모듈은 `app` 모듈의 `ready` 이벤트가 발생한 이후에만 사용할 수 있습니다.
## protocol.registerStandardSchemes(schemes)
## Methods
`protocol` 모듈은 다음과 같은 메서드를 가지고 있습니다:
### `protocol.registerStandardSchemes(schemes)`
* `schemes` Array - 표준 스킴으로 등록할 커스텀 스킴 리스트
표준 스킴의 형식은 RFC 3986 [일반 URI 구문](https://tools.ietf.org/html/rfc3986#section-3) 표준을 따릅니다.
표준 `scheme`의 형식은 RFC 3986 [일반 URI 구문](https://tools.ietf.org/html/rfc3986#section-3) 표준을 따릅니다.
이 형식은 `file:``filesystem:`을 포함합니다.
## protocol.registerFileProtocol(scheme, handler[, completion])
### `protocol.registerFileProtocol(scheme, handler[, completion])`
* `scheme` String
* `handler` Function
* `completion` Function
* `completion` Function (optional)
`scheme`에 파일을 응답으로 보내는 프로토콜을 등록합니다.
`handler``request`가 `scheme`와 함께 생성될 때 `handler(request, callback)` 형식으로 호출됩니다.
`completion``scheme`가 성공적으로 등록되었을 때 `completion(null)` 형식으로 호출되고
`handler``scheme`와 함께 `request` 생성될 때 `handler(request, callback)` 형식으로 호출됩니다.
`completion` 콜백`scheme`가 성공적으로 등록되었을 때 `completion(null)` 형식으로 호출되고
등록에 실패했을 땐 `completion(error)` 형식으로 에러 내용을 담아 호출됩니다.
`request`를 처리할 때 반드시 파일 경로 또는 `path` 속성을 포함하는 객체를 인자에 포함하여 `callback`을 호출해야 합니다.
@ -45,16 +49,16 @@ app.on('ready', function() {
만약 `callback`이 아무 인자도 없이 호출되거나 숫자나 `error` 프로퍼티를 가진 객체가 인자로 전달될 경우
`request`는 지정한 `error` 코드(숫자)를 출력합니다.
사용할 수 있는 에러 코드는 다음 링크에서 확인할 수 있습니다: https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h
사용할 수 있는 에러 코드는 [네트워크 에러 목록](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h)에서 확인할 수 있습니다.
기본적으로 스킴`http:`와 같이 처리됩니다. `file:`과 같이 "일반적인 URI 문법"과는 다르게 인식되는 프로토콜은
기본적으로 `scheme``http:`와 같이 처리됩니다. `file:`과 같이 "일반적인 URI 문법"과는 다르게 인식되는 프로토콜은
`protocol.registerStandardSchemes`을 사용하여 표준 스킴으로 처리되도록 할 수 있습니다.
## protocol.registerBufferProtocol(scheme, handler[, completion])
### `protocol.registerBufferProtocol(scheme, handler[, completion])`
* `scheme` String
* `handler` Function
* `completion` Function
* `completion` Function (optional)
`scheme``Buffer`를 응답으로 보내는 프로토콜을 등록합니다.
반드시 `Buffer` 또는 `data`, `mimeType`, `chart` 속성을 포함한 객체 중 하나를 인자에 포함하여 `callback`을 호출해야 합니다.
@ -70,76 +74,75 @@ protocol.registerBufferProtocol('atom', function(request, callback) {
});
```
## protocol.registerStringProtocol(scheme, handler[, completion])
### `protocol.registerStringProtocol(scheme, handler[, completion])`
* `scheme` String
* `handler` Function
* `completion` Function
* `completion` Function (optional)
`scheme``문자열` 응답으로 보내는 프로토콜을 등록합니다.
`scheme``문자열` 응답으로 보내는 프로토콜을 등록합니다.
반드시 `문자열` 또는 `data`, `mimeType`, `chart` 속성을 포함한 객체 중 하나를 인자에 포함하여 `callback`을 호출해야 합니다.
## protocol.registerHttpProtocol(scheme, handler[, completion])
### `protocol.registerHttpProtocol(scheme, handler[, completion])`
* `scheme` String
* `handler` Function
* `completion` Function
* `completion` Function (optional)
`scheme`에 HTTP 요청을 응답으로 보내는 프로토콜을 등록합니다.
반드시 `url`, `method`, `referer`, `session` 속성을 포함하는 객체를 인자에 포함하여 `callback`을 호출해야 합니다.
기본적으로 HTTP 요청은 현재 세션을 재사용합니다. 만약 서로 다른 세션에 요청을 보내고 싶으면 `session``null`로 지정해야 합니다.
## protocol.unregisterProtocol(scheme[, completion])
### `protocol.unregisterProtocol(scheme[, completion])`
* `scheme` String
* `completion` Function
* `completion` Function (optional)
`scheme`의 커스텀 프로토콜 등록을 해제합니다.
## protocol.isProtocolHandled(scheme, callback)
### `protocol.isProtocolHandled(scheme, callback)`
* `scheme` String
* `callback` Function
`scheme`에 동작(handler)이 등록되어 있는지 여부를 확인합니다. `callback`으로 결과(boolean)가 반환됩니다.
## protocol.interceptFileProtocol(scheme, handler[, completion])
### `protocol.interceptFileProtocol(scheme, handler[, completion])`
* `scheme` String
* `handler` Function
* `completion` Function
* `completion` Function (optional)
`scheme` 프로토콜을 가로채고 `handler`를 파일 전송에 대한 새로운 동작으로 사용합니다.
## protocol.interceptStringProtocol(scheme, handler[, completion])
### `protocol.interceptStringProtocol(scheme, handler[, completion])`
* `scheme` String
* `handler` Function
* `completion` Function
* `completion` Function (optional)
`scheme` 프로토콜을 가로채고 `handler`를 문자열 전송에 대한 새로운 동작으로 사용합니다.
## protocol.interceptBufferProtocol(scheme, handler[, completion])
### `protocol.interceptBufferProtocol(scheme, handler[, completion])`
* `scheme` String
* `handler` Function
* `completion` Function
* `completion` Function (optional)
`scheme` 프로토콜을 가로채고 `handler``Buffer` 전송에 대한 새로운 동작으로 사용합니다.
## protocol.interceptHttpProtocol(scheme, handler[, completion])
### `protocol.interceptHttpProtocol(scheme, handler[, completion])`
* `scheme` String
* `handler` Function
* `completion` Function
* `completion` Function (optional)
`scheme` 프로토콜을 가로채고 `handler`를 HTTP 프로토콜의 요청에 대한 새로운 동작으로 사용합니다.
## protocol.uninterceptProtocol(scheme[, completion])
### `protocol.uninterceptProtocol(scheme[, completion])`
* `scheme` String
* `completion` Function
* `completion` Function (optional)
가로챈 `scheme`를 삭제하고 기본 핸들러로 복구합니다.

View file

@ -1,10 +1,10 @@
# remote
`remote` 모듈은 메인 프로세스와 랜더러 프로세스 사이에 inter-process 통신을 간단하게 추상화 한 모듈입니다.
`remote` 모듈은 메인 프로세스와 랜더러 프로세스(웹 페이지) 사이의 inter-process (IPC) 통신을 간단하게 추상화 한 모듈입니다.
Electron의 랜더러 프로세스에선 GUI와 관련 없는 모듈만 사용할 수 있습니다.
기본적으로 랜더러 프로세스에서 메인 프로세스의 API를 사용하려면 inter-process 통신을 사용해야 합니다.
하지만 `remote` 모듈을 사용하면 따로 inter-process 통신을 사용하지 않고 직접 명시적으로 사용할 수 있습니다.
기본적으로 랜더러 프로세스에서 메인 프로세스의 API를 사용하려면 메인 프로세스와 inter-process 통신을 해야 합니다.
하지만 `remote` 모듈을 사용하면 따로 inter-process 통신을 하지 않고 직접 명시적으로 모듈을 사용할 수 있습니다.
Java의 [RMI](http://en.wikipedia.org/wiki/Java_remote_method_invocation)와 개념이 비슷합니다.
다음 예제는 랜더러 프로세스에서 브라우저 창을 만드는 예제입니다:
@ -12,21 +12,22 @@ Java의 [RMI](http://en.wikipedia.org/wiki/Java_remote_method_invocation)와 개
```javascript
var remote = require('remote');
var BrowserWindow = remote.require('browser-window');
var win = new BrowserWindow({ width: 800, height: 600 });
win.loadUrl('https://github.com');
```
알림: 반대로 하려면(메인 프로세스에서 랜더러 프로세스에 접근) [webContents.executeJavascript](browser-window.md#webcontents-executejavascript-code) API를 사용하면 됩니다.
**참고:** 반대로 메인 프로세스에서 랜더러 프로세스에 접근 하려면 [webContents.executeJavascript](browser-window.md#webcontents-executejavascript-code) 메서드를 사용하면 됩니다.
## Remote 객체
`remote` 모듈로부터 반환된 각 객체(함수 포함)는 메인 프로세스의 객체를 추상화 한 객체입니다. (우리는 그것을 remote 객체 또는 remote 함수라고 부릅니다)
Remote 모듈의 함수를 호출하거나, 객체에 접근하거나, 생성자로 객체를 생성하는 등의 작업은 실질적으로 동기형 inter-process 메시지를 보냅니다.
`remote` 모듈로부터 반환된 각 객체(메서드 포함)는 메인 프로세스의 객체를 추상화 한 객체입니다. (우리는 그것을 remote 객체 또는 remote 함수라고 부릅니다)
Remote 모듈의 메서드를 호출하거나, 객체에 접근하거나, 생성자로 객체를 생성하는 등의 작업은 실질적으로 동기형 inter-process 메시지를 보냅니다.
위의 예제에서 사용한 두 `BrowserWindow``win`은 remote 객체입니다. 그리고 `new BrowserWindow`이 생성하는 `BrowserWindow` 객체는 랜더러 프로세스에서 생성되지 않습니다.
대신에 이 `BrowserWindow` 객체는 메인 프로세스에서 생성되며 랜더러 프로세스에 `win` 객체와 같이 이에 대응하는 remote 객체를 반환합니다.
## Remote 객체의
## Remote 객체의 생명 주기
Electron은 랜더러 프로세스의 remote 객체가 살아있는 한(다시 말해서 GC(garbage collection)가 일어나지 않습니다) 대응하는 메인 프로세스의 객체는 릴리즈되지 않습니다.
Remote 객체가 GC 되려면 대응하는 메인 프로세스 내부 객체의 참조가 해제되어야만 합니다.
@ -38,50 +39,89 @@ Remote 객체가 GC 되려면 대응하는 메인 프로세스 내부 객체의
## 메인 프로세스로 콜백 넘기기
몇몇 메인 프로세스의 API는 콜백 함수를 사용합니다. 그리고 보통 remote 함수를 호출할 때 콜백 함수를 넘길 것입니다.
`remote` 모듈은 이를 지원합니다. 하지만 반드시 주의해서 사용해야 합니다.
메인 프로세스의 코드는 `remote` 모듈을 통해 랜더러 프로세스가 전달하는 콜백 함수를 받을 수 있습니다.
하지만 이 작업은 반드시 주의를 기울여 사용해야 합니다.
첫째, 데드락을 피하기 위해 메인 프로세스로 전달된 콜백들은 비동기로 호출됩니다.
그래서 전달된 콜백들이 언제나 값을 반환할 것이라고 기대하면 안 됩니다.
이러한 이유로 메인 프로세스로 전달된 콜백들의 반환 값을 내부 함수에서 언제나 정상적으로 받을 것이라고 예측해선 안됩니다.
둘째, 콜백들은 메인 프로세스로 전송되고 호출된 후에도 자동으로 참조가 릴리즈 되지 않습니다.
참조는 메인 프로세스에서 GC가 일어나기 전까지 계속 남아있게 됩니다.
예를 들어 메인 프로세스에서 `Array.map` 같은 메서드를 사용할 때 랜더러 프로세스에서 전달된 함수를 사용해선 안됩니다:
다음 코드를 보면 느낌이 팟 하고 올 것입니다. 이 예제는 remote 객체에 `close` 이벤트 콜백을 설치합니다:
```javascript
// mapNumbers.js 메인 프로세스
exports.withRendererCallback = function(mapper) {
return [1,2,3].map(mapper);
}
exports.withLocalCallback = function() {
return exports.mapNumbers(function(x) {
return x + 1;
});
}
```
```javascript
// 랜더러 프로세스
var mapNumbers = require("remote").require("mapNumbers");
var withRendererCb = mapNumbers.withRendererCallback(function(x) {
return x + 1;
})
var withLocalCb = mapNumbers.withLocalCallback()
console.log(withRendererCb, withLocalCb) // [true, true, true], [2, 3, 4]
```
보다시피 랜더러 콜백의 동기 반환 값은 예상되지 않은 처리입니다.
그리고 메인 프로세스에서 처리한 함수의 반환 값과 일치하지 않습니다.
둘째, 콜백들은 메인 프로세스로 전달, 호출된 이후에도 자동으로 함수의 참조가 릴리즈 되지 않습니다.
함수 참조는 메인 프로세스에서 GC가 일어나기 전까지 계속 프로세스에 남아있게 됩니다.
다음 코드를 보면 느낌이 올 것입니다. 이 예제는 remote 객체에 `close` 이벤트 콜백을 설치합니다:
```javascript
var remote = require('remote');
remote.getCurrentWindow().on('close', function() {
// blabla...
});
```
문제는 이 이벤트는 명시적으로 제거하지 않는 이상 계속해서 메인 프로세스에 남아있게 된다는 것입니다.
그래서 매 창을 새로고침 할 때마다 콜백이 새롭게 설치되며 이전 콜백은 떨궈져 누수가 됩니다.
설상가상으로 이전에 설치한 콜백의 콘텍스트가 릴리즈 되고 나서 `close` 이벤트가 발생하면 예외가 발생하고 메인 프로세스가 작동 중지됩니다.
하지만 이 코드 처럼 이벤트를 명시적으로 제거하지 않는 이상 콜백 함수의 참조가 계속해서 메인 프로세스에 남아있게 됩니다.
만약 명시적으로 콜백을 제거하지 않으면 매 번 창을 새로고침 할 때마다 콜백을 새로 설치합니다.
게다가 이전 콜백이 제거되지 않고 계속해서 쌓이면서 메모리 누수가 발생합니다.
일반적으로 정확히 무엇을 할 것인지 잘 알고 있지 않는 이상 웬만하면 메인 프로세스로 콜백 함수를 넘기는 건 자제하는 게 좋습니다.
설상가상으로 이전에 설치된 콜백의 콘텍스트가 릴리즈 되고 난 후(예: 페이지 새로고침) `close` 이벤트가 발생하면 예외가 발생하고 메인 프로세스가 작동 중지됩니다.
## remote.require(module)
이러한 문제를 피하려면 랜더러 프로세스에서 메인 프로세스로 넘긴 함수의 참조를 사용 후 확실하게 제거해야 합니다.
작업 후 이벤트 콜백을 포함하여 책임 있게 함수의 참조를 제거하거나 메인 프로세스에서 랜더러 프로세스가 종료될 때 내부적으로 함수 참조를 제거하도록 설계해야 합니다.
## Methods
`remote` 모듈은 다음과 같은 메서드를 가지고 있습니다:
### `remote.require(module)`
* `module` String
메인 프로세스의 `require(module)` API를 실행한 후 결과 객체를 반환합니다.
## remote.getCurrentWindow()
### `remote.getCurrentWindow()`
현재 웹 페이지가 들어있는 [BrowserWindow](browser-window.md) 객체를 반환합니다.
현재 웹 페이지가 들어있는 [`BrowserWindow`](browser-window.md) 객체를 반환합니다.
## remote.getCurrentWebContents()
### `remote.getCurrentWebContents()`
현재 웹 페이지의 WebContents 객체를 반환합니다.
현재 웹 페이지의 [`WebContents`](web-contents.md) 객체를 반환합니다.
## remote.getGlobal(name)
### `remote.getGlobal(name)`
* `name` String
메인 프로세스의 전역 변수(`name`)를 가져옵니다. (예시: `global[name]`)
## remote.process
### `remote.process`
메인 프로세스의 `process` 객체를 반환합니다. `remote.getGlobal('process')`와 같습니다. 하지만 캐시 됩니다.

View file

@ -5,8 +5,8 @@
`screen`은 [EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter)를 상속 받았습니다.
한가지 주의할 점은 랜더러 / DevTools에선 이 모듈의 이름인 `screen`은 이미 DOM 속성에 `window.screen`로 존재 하므로 `screen = require('screen')`
사용할 수 없습니다. 밑의 예제와 같이 `atomScreen`등의 이름으로 변수 이름을 대체하여 사용해야 합니다.
**참고:** 랜더러 / DevTools에선 이미 DOM 속성이 `window.screen`을 가지고 있으므로 `screen = require('screen')` 형식으로 모듈을 사용할 수 없습니다.
밑의 예제와 같이 `atomScreen` 같은 이름으로 모듈 이름을 대체하여 사용해야 합니다.
다음 예제는 화면 전체를 채우는 윈도우 창을 생성합니다:
@ -51,43 +51,57 @@ app.on('ready', function() {
});
```
## Event: display-added
## Events
`screen` 모듈은 다음과 같은 이벤트를 가지고 있습니다:
### Event: 'display-added'
Returns:
* `event` Event
* `newDisplay` Object
새로운 디스플레이가 추가되면 발생하는 이벤트입니다.
## Event: display-removed
### Event: 'display-removed'
Returns:
* `event` Event
* `oldDisplay` Object
기존의 디스플레이가 제거되면 발생하는 이벤트입니다.
## Event: display-metrics-changed
### Event: 'display-metrics-changed'
Returns:
* `event` Event
* `display` Object
* `changedMetrics` Array
`display` 하나 또는 다수의 매트릭스가 변경될 때 발생하는 이벤트입니다.
`display`에서 하나 또는 다수의 매트릭스가 변경될 때 발생하는 이벤트입니다.
`changedMetrics`는 변경에 대한 정보를 담은 문자열의 배열입니다.
`bounds`, `workArea`, `scaleFactor`, `rotation`등이 변경될 수 있습니다.
## screen.getCursorScreenPoint()
## Methods
`screen` 모듈은 다음과 같은 메서드를 가지고 있습니다:
### `screen.getCursorScreenPoint()`
현재 마우스 포인터의 절대 위치를 반환합니다.
## screen.getPrimaryDisplay()
### `screen.getPrimaryDisplay()`
기본 디스플레이를 반환합니다.
## screen.getAllDisplays()
### `screen.getAllDisplays()`
사용 가능한 모든 디스플레이를 배열로 반환합니다.
## screen.getDisplayNearestPoint(point)
### `screen.getDisplayNearestPoint(point)`
* `point` Object
* `x` Integer
@ -95,7 +109,7 @@ app.on('ready', function() {
지정한 좌표에 가까운 디스플레이를 반환합니다.
## screen.getDisplayMatching(rect)
### `screen.getDisplayMatching(rect)`
* `rect` Object
* `x` Integer

View file

@ -1,34 +1,39 @@
# shell
`shell` 모듈은 데스크톱 환경 통합에 관련하여 제공되는 모듈입니다.
`shell` 모듈은 데스크톱 환경 통합에 관련한 유틸리티를 제공하는 모듈입니다.
다음 예제는 기본 브라우저로 설정된 URL을 엽니다:
다음 예제는 설정된 URL을 유저의 기본 브라우저로 엽니다:
```javascript
var shell = require('shell');
shell.openExternal('https://github.com');
```
## shell.showItemInFolder(fullPath)
## Methods
`shell` 모듈은 다음과 같은 메서드를 가지고 있습니다:
### `shell.showItemInFolder(fullPath)`
* `fullPath` String
지정한 파일을 탐색기에서 보여줍니다. 가능한 경우 탐색기 내에서 파일을 선택합니다.
## shell.openItem(fullPath)
### `shell.openItem(fullPath)`
* `fullPath` String
지정한 파일을 데스크톱 기본 프로그램으로 엽니다.
## shell.openExternal(url)
### `shell.openExternal(url)`
* `url` String
제공된 외부 프로토콜 URL을 기반으로 데스크톱의 기본 프로그램으로 엽니다. (예를 들어 mailto: URL은 해당 URL을 기본 메일 에이전트로 엽니다.)
제공된 외부 프로토콜 URL을 기반으로 데스크톱의 기본 프로그램으로 엽니다. (예를 들어 mailto: URL은 유저의 기본 이메일 에이전트로 URL을 엽니다.)
역주: 폴더는 'file:\\\\C:\\'와 같이 지정하여 열 수 있습니다. (`\\`로 경로를 표현한 이유는 Escape 문자열을 참고하세요.)
## shell.moveItemToTrash(fullPath)
### `shell.moveItemToTrash(fullPath)`
* `fullPath` String
@ -36,6 +41,6 @@ Move the given file to trash and returns boolean status for the operation.
지정한 파일을 휴지통으로 이동합니다. 작업의 성공여부를 boolean 형으로 리턴합니다.
## shell.beep()
### `shell.beep()`
비프음을 재생합니다.

View file

@ -1,14 +1,15 @@
# 개요
Electron은 모든 [node.js's built-in 모듈](http://nodejs.org/api/)과 third-party node 모듈을 완벽하게 지원합니다. ([네이티브 모듈](../tutorial/using-native-node-modules.md) 포함해서)
Electron은 모든 [Node.js의 built-in 모듈](http://nodejs.org/api/)과 third-party node 모듈을 완벽하게 지원합니다. ([네이티브 모듈](../tutorial/using-native-node-modules.md) 포함)
Electron은 네이티브 데스크톱 어플리케이션을 개발 할 수 있도록 추가적인 built-in 모듈을 제공합니다.
몇몇 모듈은 메인 프로세스에서만 사용할 수 있고 어떤 모듈은 랜더러 프로세스에서만 사용할 수 있습니다. 또한 두 프로세스 모두 사용할 수 있는 모듈도 있습니다.
기본적인 규칙은 다음과 같습니다: GUI와 저 수준 시스템에 관련된 모듈은 오직 메인 프로세스에서만 사용할 수 있습니다.
[메인 프로세스 vs. 랜더러 프로세스](../tutorial/quick-start.md#메인 프로세스) 컨셉에 익숙해야 이 모듈들을 사용하기 쉬우므로 해당 문서를 정독하는 것을 권장합니다.
몇몇 모듈은 메인 프로세스에서만 사용할 수 있고 어떤 모듈은 랜더러 프로세스(웹 페이지)에서만 사용할 수 있습니다.
또한 두 프로세스 모두 사용할 수 있는 모듈도 있습니다.
기본적인 규칙으로 [GUI](https://en.wikipedia.org/wiki/Graphical_user_interface)와 저 수준 시스템에 관련된 모듈들은 오직 메인 프로세스에서만 사용할 수 있습니다.
[메인 프로세스 vs. 랜더러 프로세스](../tutorial/quick-start.md#메인 프로세스) 컨셉에 익숙해야 이 모듈들을 사용하기 쉬우므로 관련 문서를 읽어 보는 것을 권장합니다.
메인 프로세스 스크립트는 일반 `node.js` 스크립트와 같습니다:
메인 프로세스 스크립트는 일반 Node.js 스크립트와 비슷합니다:
```javascript
var app = require('app');
@ -22,7 +23,7 @@ app.on('ready', function() {
});
```
웹 페이지 역시 예외적인 node module을 사용할 수 있다는 점을 제외하면 일반 웹 페이지와 다를게 없습니다:
랜더러 프로세스도 예외적인 node module들을 사용할 수 있다는 점을 제외하면 일반 웹 페이지와 크게 다를게 없습니다:
```html
<!DOCTYPE html>

View file

@ -1,6 +1,6 @@
# Tray
`Tray`는 OS의 알림영역에 아이콘을 표시합니다. 보통 컨텍스트 메뉴(context menu)를 같이 사용합니다.
`Tray`는 OS의 알림 영역에 아이콘을 표시합니다. 보통 컨텍스트 메뉴(context menu)를 같이 사용합니다.
```javascript
var app = require('app');
@ -29,19 +29,25 @@ __플랫폼별 한계:__
* 앱 알림 표시기는 컨텍스트 메뉴를 가지고 있을 때만 보입니다.
* Linux에서 앱 알림 표시기가 사용될 경우, `clicked` 이벤트는 무시됩니다.
이러한 이유로 만약 Tray API가 모든 플랫폼에서 똑같이 작동하게 하고 싶다면, 설계시 `clicked` 이벤트에 의존하지 말아야합니다.
그리고 언제나 컨텍스트 메뉴를 포함해서 사용해야 합니다.
이러한 이유로 Tray API가 모든 플랫폼에서 똑같이 작동하게 하고 싶다면 `clicked` 이벤트에 의존해선 안됩니다.
그리고 언제나 컨텍스트 메뉴를 포함해야 합니다.
## Class: Tray
`Tray`는 [EventEmitter][event-emitter]를 상속 받았습니다.
### new Tray(image)
### `new Tray(image)`
* `image` [NativeImage](native-image.md)
전달된 `image`를 이용하여 트레이 아이콘을 만듭니다.
## Events
`Tray` 모듈은 다음과 같은 이벤트를 가지고 있습니다:
**참고:** 몇가지 이벤트는 특정한 플랫폼에서만 작동합니다.
### Event: 'clicked'
* `event` Event
@ -57,9 +63,9 @@ __플랫폼별 한계:__
트레이 아이콘이 클릭될 때 발생하는 이벤트입니다.
__주의:__ `bounds`는 OS X 와 Windows 7 이후 버전에서만 작동합니다.
__주의:__ `bounds`는 OS X 와 Windows에서만 작동합니다.
### Event: 'right-clicked'
### Event: 'right-clicked' _OS X_ _Windows_
* `event` Event
* `altKey` Boolean
@ -74,9 +80,7 @@ __주의:__ `bounds`는 OS X 와 Windows 7 이후 버전에서만 작동합니
트레이 아이콘을 오른쪽 클릭될 때 호출 됩니다.
__주의:__ 이 기능은 OS X 와 Windows 운영체제에서만 작동합니다.
### Event: 'double-clicked'
### Event: 'double-clicked' _OS X_ _Windows_
* `event` Event
* `altKey` Boolean
@ -91,76 +95,66 @@ __주의:__ 이 기능은 OS X 와 Windows 운영체제에서만 작동합니다
트레이 아이콘이 더블 클릭될 때 발생하는 이벤트입니다.
__주의:__ 이 기능은 OS X 와 Windows 운영체제에서만 작동합니다.
### Event: 'balloon-show'
### Event: 'balloon-show' _Windows_
알림풍선이 보여질 때 발생하는 이벤트입니다.
__주의:__ 이 기능은 Windows에서만 작동합니다.
### Event: 'balloon-clicked'
### Event: 'balloon-clicked' _Windows_
알림풍선이 클릭될 때 발생하는 이벤트입니다.
__주의:__ 이 기능은 Windows에서만 작동합니다.
### Event: 'balloon-closed'
### Event: 'balloon-closed' _Windows_
알림풍선이 시간이 지나 사라지거나 유저가 클릭하여 닫을 때 발생하는 이벤트입니다.
__주의:__ 이 기능은 Windows에서만 작동합니다.
### Event: 'drop-files'
### Event: 'drop-files' _OS X_
* `event`
* `files` Array - 드롭된 파일의 경로
트레이 아이콘에 파일이 드롭되면 발생하는 이벤트입니다.
__주의:__ 이 기능은 OS X에서만 작동합니다.
## Methods
### Tray.destroy()
`Tray` 모듈은 다음과 같은 메서드를 가지고 있습니다:
**참고:** 몇가지 메서드는 특정한 플랫폼에서만 작동합니다.
### `Tray.destroy()`
트레이 아이콘을 즉시 삭제시킵니다.
### Tray.setImage(image)
### `Tray.setImage(image)`
* `image` [NativeImage](native-image.md)
`image`를 사용하여 트레이 아이콘의 이미지를 설정합니다.
### Tray.setPressedImage(image)
### `Tray.setPressedImage(image)` _OS X_
* `image` [NativeImage](native-image.md)
`image`를 사용하여 트레이 아이콘이 눌렸을 때의 이미지를 설정합니다.
__주의:__ 이 기능은 OS X에서만 작동합니다.
### Tray.setToolTip(toolTip)
### `Tray.setToolTip(toolTip)`
* `toolTip` String
트레이 아이콘의 툴팁 텍스트를 설정합니다.
### Tray.setTitle(title)
### `Tray.setTitle(title)` _OS X_
* `title` String
상태바에서 트레이 아이콘 옆에 표시되는 제목 텍스트를 설정합니다.
__주의:__ 이 기능은 OS X에서만 작동합니다.
### Tray.setHighlightMode(highlight)
### `Tray.setHighlightMode(highlight)` _OS X_
* `highlight` Boolean
트레이 아이콘을 클릭했을 때 하이라이트 될지 설정합니다.
__주의:__ 이 기능은 OS X에서만 작동합니다.
### Tray.displayBalloon(options)
### `Tray.displayBalloon(options)` _Windows_
* `options` Object
* `icon` [NativeImage](native-image.md)
@ -169,19 +163,15 @@ __주의:__ 이 기능은 OS X에서만 작동합니다.
트레이에 알림풍선을 생성합니다.
__알림:__ 이 기능은 Windows에서만 작동합니다.
### `Tray.popContextMenu([position])` _OS X_ _Windows_
### Tray.popContextMenu([position])
* `position` Object - 팝 메뉴 위치
* `position` Object (optional) - 팝업 메뉴 위치
* `x` Integer
* `y` Integer
`position`은 Windows에서만 사용할 수 있으며 기본값은 (0, 0)입니다.
__주의:__ 이 기능은 Windows 와 OS X에서만 작동합니다.
### Tray.setContextMenu(menu)
### `Tray.setContextMenu(menu)`
* `menu` Menu

View file

@ -1,8 +1,8 @@
# web-frame
`web-frame` 모듈은 현재 웹 페이지의 랜더링 상태를 설정 할 수 있도록 해줍니다.
`web-frame` 모듈은 현재 웹 페이지의 랜더링 상태를 설정 할 수 있도록 관련 유틸리티를 제공하는 모듈입니다.
다음 예제는 현재 페이지를 200% 줌 합니다.
다음 예제는 현재 페이지를 200% 줌 합니다:
```javascript
var webFrame = require('web-frame');
@ -30,6 +30,13 @@ webFrame.setZoomFactor(2);
현재 줌 레벨을 반환합니다.
## webFrame.setZoomLevelLimits(minimumLevel, maximumLevel)
* `minimumLevel` Number
* `maximumLevel` Number
줌 레벨의 최대, 최소치를 지정합니다.
## webFrame.setSpellCheckProvider(language, autoCorrectWord, provider)
* `language` String

View file

@ -1,9 +1,9 @@
# `window.open` 함수
# `window.open` 메서드
`window.open` 함수가 호출되면 새 창에서 새로운 페이지를 불러옵니다.
이 창은 `url`로 부터 만들어진 `BrowserWindow`의 새 인스턴스이며 본 객체 대신 페이지의 컨트롤이 제한된 프록시 객체를 반환합니다.
`window.open` 메서드가 호출되면 새 창을 생성하고 `url` 페이지를 불러옵니다.
이 창은 지정한 `url`을 로드하여 만들어진 `BrowserWindow`의 새 인스턴스이며 본래 창 객체 대신 페이지의 컨트롤이 제한된 프록시 객체를 반환합니다.
프록시 객체는 기존의 웹 페이지와 호환될 수 있도록 일부 제한된 표준 기능만 가지고 있습니다.
프록시 객체는 브라우저의 웹 페이지 창과 호환될 수 있도록 일부 제한된 표준 기능만 가지고 있습니다.
창의 모든 컨트롤을 가지려면 `BrowserWindow`를 직접 생성하여 작업해야 합니다.
## window.open(url, [frameName[, features]])
@ -19,7 +19,7 @@
* `message` String
* `targetOrigin` String
부모 윈도우에 메시지를 보냅니다. 특정한 origin을 지정할 수도 있으며 `*`를 지정하면 따로 origin 설정을 사용하지 않습니다.
부모 윈도우에 메시지를 보냅니다. origin을 특정할 수 있으며 `*`를 지정하면 따로 origin 설정을 사용하지 않습니다.
## Class: BrowserWindowProxy
@ -52,6 +52,6 @@ Forcefully closes the child window without calling its unload event.
* `message` String
* `targetOrigin` String
자식 윈도우에 메시지를 보냅니다. 특정한 origin을 지정할 수도 있으며 `*`를 지정하면 따로 origin 설정을 사용하지 않습니다.
자식 윈도우에 메시지를 보냅니다. origin을 특정할 수 있으며 `*`를 지정하면 따로 origin 설정을 사용하지 않습니다.
참고로 자식 윈도우의 `window.opener` 객체에는 다른 속성 없이 이 함수 하나만 구현되어 있습니다.
참고로 자식 윈도우의 `window.opener` 객체에는 다른 속성 없이 이 메서드 한 개만 구현되어 있습니다.

View file

@ -1,6 +1,6 @@
# NW.js와 기술적으로 다른점 (이전 node-webkit)
__알림: Electron은 이전까지 Atom Shell로 불려졌습니다.__
__주의: Electron은 Atom Shell의 새로운 이름입니다.__
NW.js 처럼 Electron은 JavaScript와 HTML 그리고 Node 통합환경을 제공함으로써 웹 페이지에서 저수준 시스템에 접근할 수 있는 웹 기반 데스크탑 어플리케이션을 작성할 수 있도록 합니다.

View file

@ -4,12 +4,12 @@
* Python 2.7.x. 몇몇 CentOS와 같은 배포판들은 아직도 Python 2.6.x 버전을 사용합니다. 그래서 `python -V`를 통해 버전을 확인해 줄 필요가 있습니다.
* Node.js v0.12.x. Node를 설치하는 방법은 여러가지가 있습니다. 그중 하나는 [Node.js](http://nodejs.org) 사이트에서 소스코드를 받아 빌드하는 방법입니다.
이렇게 하면 Node를 일반 유저로 홈 디렉터리에 설치할 수 있습니다. 또는 [NodeSource](https://nodesource.com/blog/nodejs-v012-iojs-and-the-nodesource-linux-repositories) 에서 받아올 수 있습니다.
이렇게 하면 Node를 일반 유저로 홈 디렉터리에 설치할 수 있습니다. 또는 [NodeSource](https://nodesource.com/blog/nodejs-v012-iojs-and-the-nodesource-linux-repositories)에서 소스 파일을 받아올 수 있습니다.
자세한 내용은 [Node.js 설치 방법](https://github.com/joyent/node/wiki/Installation) 을 참고하세요.
* Clang 3.4 또는 최신 버전
* GTK+ 와 libnotify의 개발용 헤더
Ubuntu를 사용하고 있다면 다음 커맨드로 설치하면 합니다:
Ubuntu를 사용하고 있다면 다음과 같이 라이브러리를 설치해야 합니다:
```bash
$ sudo apt-get install build-essential clang libdbus-1-dev libgtk2.0-dev \
@ -18,7 +18,15 @@ $ sudo apt-get install build-essential clang libdbus-1-dev libgtk2.0-dev \
libxss1 libnss3-dev gcc-multilib g++-multilib
```
다른 배포판의 경우 yum과 같은 패키지 매니저를 통해 패키지를 설치 할 수 있습니다. 패키지의 이름은 대부분 비슷할 것입니다.
Fedora를 사용하고 있다면 다음과 같이 라이브러리를 설치해야 합니다:
```bash
$ sudo yum install clang dbus-devel gtk2-devel libnotify-devel libgnome-keyring-devel \
xorg-x11-server-utils libcap-devel cups-devel libXtst-devel \
alsa-lib-devel libXrandr-devel GConf2-devel nss-devel
```
다른 배포판의 경우 pacman 같은 패키지 매니저를 통해 패키지를 설치 할 수 있습니다. 패키지의 이름은 대부분 위 예시와 비슷할 것입니다.
또는 소스코드를 내려받아 직접 빌드하는 방법도 있습니다.
## 가상머신을 사용하여 빌드 하는 경우
@ -78,7 +86,7 @@ $ ./script/create-dist.py
이 스크립트는 매우 작은 배포판을 `dist` 디렉터리에 생성합니다.
create-dist.py 스크립트를 실행한 이후 1.3GB를 초과하는 공간을 차지하는 out/R 폴더의 실행파일 바이너리는 삭제해도 됩니다.
`Debug` 타겟만 빌드 할 수 있습니다:
또는 `Debug` 타겟만 빌드 할 수 있습니다:
```bash
$ ./script/build.py -c D

View file

@ -34,7 +34,7 @@ $ ./script/bootstrap.py -v
$ ./script/build.py
```
`Debug` 타겟만 빌드 할 수 있습니다:
또는 `Debug` 타겟만 빌드 할 수 있습니다:
```bash
$ ./script/build.py -c D

View file

@ -9,7 +9,7 @@
* [git](http://git-scm.com)
현재 Windows를 설치하지 않았다면 [modern.ie](https://www.modern.ie/en-us/virtualization-tools#downloads)에서
사용기한이 정해져있는 무료 가상머신 버전의 Windows를 받아 Electron을 빌드할 수도 있습니다.
사용 기한이 정해져있는 무료 가상머신 버전의 Windows를 받아 Electron을 빌드하는 방법도 있습니다.
Electron은 전적으로 command-line 스크립트를 사용하여 빌드합니다. 그렇기에 Electron을 개발하는데 아무런 에디터나 사용할 수 있습니다.
하지만 이 말은 Visual Studio를 개발을 위해 사용할 수 없다는 말이 됩니다. 나중에 Visual Studio를 이용한 빌드 방법도 제공할 예정입니다.
@ -40,7 +40,7 @@ python script\bootstrap.py -v
python script\build.py
```
`Debug` 타겟만 빌드 할 수 있습니다:
또는 `Debug` 타겟만 빌드 할 수 있습니다:
```powershell
python script\build.py -c D
@ -72,6 +72,15 @@ python script\cpplint.py
python script\test.py
```
테스트 실행시 `runas`와 같은 네이티브 모듈을 포함하는데 이 모듈은 디버그 빌드에서 같이 사용할 수 없습니다.
하지만 여전히 릴리즈 빌드에선 사용할 수 있습니다.
릴리즈 빌드로 테스트를 실행하려면 다음 커맨드를 사용하면 됩니다:
```powershell
python script\test.py -R
```
## 문제 해결
### Command xxxx not found

View file

@ -1,6 +1,6 @@
# 디버거에서 디버그 심볼 서버 설정
디버그 심볼은 디버깅 세션을 더 좋게 개선해 줍니다. 디버그 심볼은 실행 파일과 동적 링크 라이브러리에서 함수에 대한 정보를 담고 있으며 명료한 함수 호출 스텍 정보를 제공합니다.
디버그 심볼은 디버깅 세션을 더 좋게 개선해 줍니다. 디버그 심볼은 실행 파일과 동적 링크 라이브러리에서 메서드에 대한 정보를 담고 있으며 명료한 함수 호출 스텍 정보를 제공합니다.
심볼 서버는 유저가 크기가 큰 디버깅용 파일을 필수적으로 다운로드 받지 않고도 디버거가 알맞은 심볼, 바이너리 그리고 소스를 자동적으로 로드할 수 있도록 해줍니다.
서버 사용법은 [Microsoft의 심볼 서버](http://support.microsoft.com/kb/311503)와 비슷합니다. 이 문서를 참조하세요.

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