Merge remote-tracking branch 'refs/remotes/atom/master'
This commit is contained in:
commit
50083017bc
110 changed files with 3432 additions and 647 deletions
|
@ -47,9 +47,13 @@ Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법도 문
|
|||
- [중국어 간체](https://github.com/atom/electron/tree/master/docs-translations/zh-CN)
|
||||
- [중국어 번체](https://github.com/atom/electron/tree/master/docs-translations/zh-TW)
|
||||
|
||||
## 시작하기
|
||||
|
||||
[`atom/electron-quick-start`](https://github.com/atom/electron-quick-start) 저장소를 클론하여 Electron을 간단히 접해볼 수 있습니다.
|
||||
|
||||
## 커뮤니티
|
||||
|
||||
다음 링크를 통해 커뮤니티에 질문을 올리거나 토론을 나누실 수 있습니다:
|
||||
다음 링크를 통해 커뮤니티에 질문을 올리거나 토론을 나눌 수 있습니다:
|
||||
|
||||
- Atom 포럼의 [`electron`](http://discuss.atom.io/category/electron) 카테고리
|
||||
- Freenode 채팅의 `#atom-shell` 채널
|
||||
|
|
|
@ -53,6 +53,11 @@ contains documents describing how to build and contribute to Electron.
|
|||
- [Simplified Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-CN)
|
||||
- [Traditional Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-TW)
|
||||
|
||||
## Quick Start
|
||||
|
||||
Clone and run the [`atom/electron-quick-start`](https://github.com/atom/electron-quick-start)
|
||||
repository to see a minimal Electron app in action.
|
||||
|
||||
## Community
|
||||
|
||||
You can ask questions and interact with the community in the following
|
||||
|
|
2
atom.gyp
2
atom.gyp
|
@ -4,7 +4,7 @@
|
|||
'product_name%': 'Electron',
|
||||
'company_name%': 'GitHub, Inc',
|
||||
'company_abbr%': 'github',
|
||||
'version%': '0.34.0',
|
||||
'version%': '0.34.1',
|
||||
},
|
||||
'includes': [
|
||||
'filenames.gypi',
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "base/at_exit.h"
|
||||
#include "base/i18n/icu_util.h"
|
||||
#include "base/mac/bundle_locations.h"
|
||||
#include "base/mac/scoped_nsautorelease_pool.h"
|
||||
#include "brightray/common/mac/main_application_bundle.h"
|
||||
#include "content/public/app/content_main.h"
|
||||
|
||||
|
@ -25,6 +26,7 @@ int AtomMain(int argc, const char* argv[]) {
|
|||
|
||||
int AtomInitializeICUandStartNode(int argc, char *argv[]) {
|
||||
base::AtExitManager atexit_manager;
|
||||
base::mac::ScopedNSAutoreleasePool pool;
|
||||
base::mac::SetOverrideFrameworkBundlePath(
|
||||
brightray::MainApplicationBundlePath()
|
||||
.Append("Contents")
|
||||
|
|
|
@ -59,7 +59,9 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
|||
#endif // !defined(OS_WIN)
|
||||
|
||||
// Only enable logging when --enable-logging is specified.
|
||||
if (!command_line->HasSwitch(switches::kEnableLogging)) {
|
||||
scoped_ptr<base::Environment> env(base::Environment::Create());
|
||||
if (!command_line->HasSwitch(switches::kEnableLogging) &&
|
||||
!env->HasVar("ELECTRON_ENABLE_LOGGING")) {
|
||||
settings.logging_dest = logging::LOG_NONE;
|
||||
logging::SetMinLogLevel(logging::LOG_NUM_SEVERITIES);
|
||||
}
|
||||
|
@ -69,10 +71,13 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
|||
// Logging with pid and timestamp.
|
||||
logging::SetLogItems(true, false, true, false);
|
||||
|
||||
#if defined(DEBUG) && defined(OS_LINUX)
|
||||
// Enable convient stack printing.
|
||||
base::debug::EnableInProcessStackDumping();
|
||||
bool enable_stack_dumping = env->HasVar("ELECTRON_ENABLE_STACK_DUMPING");
|
||||
#if defined(DEBUG) && defined(OS_LINUX)
|
||||
enable_stack_dumping = true;
|
||||
#endif
|
||||
if (enable_stack_dumping)
|
||||
base::debug::EnableInProcessStackDumping();
|
||||
|
||||
return brightray::MainDelegate::BasicStartupComplete(exit_code);
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
#include "atom/app/uv_task_runner.h"
|
||||
#include "atom/browser/javascript_environment.h"
|
||||
#include "atom/browser/node_debugger.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "base/command_line.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "base/thread_task_runner_handle.h"
|
||||
#include "gin/array_buffer.h"
|
||||
#include "gin/public/isolate_holder.h"
|
||||
|
@ -19,25 +19,22 @@ namespace atom {
|
|||
int NodeMain(int argc, char *argv[]) {
|
||||
base::CommandLine::Init(argc, argv);
|
||||
|
||||
argv = uv_setup_args(argc, argv);
|
||||
int exec_argc;
|
||||
const char** exec_argv;
|
||||
node::Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);
|
||||
|
||||
int exit_code = 1;
|
||||
{
|
||||
// Feed gin::PerIsolateData with a task runner.
|
||||
argv = uv_setup_args(argc, argv);
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
scoped_refptr<UvTaskRunner> uv_task_runner(new UvTaskRunner(loop));
|
||||
base::ThreadTaskRunnerHandle handle(uv_task_runner);
|
||||
|
||||
gin::V8Initializer::LoadV8Snapshot();
|
||||
gin::V8Initializer::LoadV8Natives();
|
||||
gin::IsolateHolder::Initialize(
|
||||
gin::IsolateHolder::kNonStrictMode,
|
||||
gin::ArrayBufferAllocator::SharedInstance());
|
||||
|
||||
JavascriptEnvironment gin_env;
|
||||
|
||||
int exec_argc;
|
||||
const char** exec_argv;
|
||||
node::Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);
|
||||
|
||||
node::Environment* env = node::CreateEnvironment(
|
||||
gin_env.isolate(), loop, gin_env.context(), argc, argv,
|
||||
exec_argc, exec_argv);
|
||||
|
|
|
@ -48,8 +48,13 @@ void UvTaskRunner::OnTimeout(uv_timer_t* timer) {
|
|||
|
||||
self->tasks_[timer].Run();
|
||||
self->tasks_.erase(timer);
|
||||
uv_unref(reinterpret_cast<uv_handle_t*>(timer));
|
||||
delete timer;
|
||||
uv_timer_stop(timer);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(timer), UvTaskRunner::OnClose);
|
||||
}
|
||||
|
||||
// static
|
||||
void UvTaskRunner::OnClose(uv_handle_t* handle) {
|
||||
delete reinterpret_cast<uv_timer_t*>(handle);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -31,6 +31,7 @@ class UvTaskRunner : public base::SingleThreadTaskRunner {
|
|||
|
||||
private:
|
||||
static void OnTimeout(uv_timer_t* timer);
|
||||
static void OnClose(uv_handle_t* handle);
|
||||
|
||||
uv_loop_t* loop_;
|
||||
|
||||
|
|
|
@ -111,6 +111,23 @@ int GetPathConstant(const std::string& name) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
bool NotificationCallbackWrapper(
|
||||
const ProcessSingleton::NotificationCallback& callback,
|
||||
const base::CommandLine::StringVector& cmd,
|
||||
const base::FilePath& cwd) {
|
||||
// Make sure the callback is called after app gets ready.
|
||||
if (Browser::Get()->is_ready()) {
|
||||
callback.Run(cmd, cwd);
|
||||
} else {
|
||||
scoped_refptr<base::SingleThreadTaskRunner> task_runner(
|
||||
base::ThreadTaskRunnerHandle::Get());
|
||||
task_runner->PostTask(
|
||||
FROM_HERE, base::Bind(base::IgnoreResult(callback), cmd, cwd));
|
||||
}
|
||||
// ProcessSingleton needs to know whether current process is quiting.
|
||||
return !Browser::Get()->is_shutting_down();
|
||||
}
|
||||
|
||||
void OnClientCertificateSelected(
|
||||
v8::Isolate* isolate,
|
||||
std::shared_ptr<content::ClientCertificateDelegate> delegate,
|
||||
|
@ -160,6 +177,11 @@ void App::OnWindowAllClosed() {
|
|||
|
||||
void App::OnQuit() {
|
||||
Emit("quit");
|
||||
|
||||
if (process_singleton_.get()) {
|
||||
process_singleton_->Cleanup();
|
||||
process_singleton_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void App::OnOpenFile(bool* prevent_default, const std::string& file_path) {
|
||||
|
@ -251,6 +273,12 @@ void App::SetAppUserModelId(const std::string& app_id) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void App::AllowNTLMCredentialsForAllDomains(bool should_allow) {
|
||||
auto browser_context = static_cast<AtomBrowserContext*>(
|
||||
AtomBrowserMainParts::Get()->browser_context());
|
||||
browser_context->AllowNTLMCredentialsForAllDomains(should_allow);
|
||||
}
|
||||
|
||||
std::string App::GetLocale() {
|
||||
return l10n_util::GetApplicationLocale("");
|
||||
}
|
||||
|
@ -262,6 +290,28 @@ v8::Local<v8::Value> App::DefaultSession(v8::Isolate* isolate) {
|
|||
return v8::Local<v8::Value>::New(isolate, default_session_);
|
||||
}
|
||||
|
||||
bool App::MakeSingleInstance(
|
||||
const ProcessSingleton::NotificationCallback& callback) {
|
||||
if (process_singleton_.get())
|
||||
return false;
|
||||
|
||||
base::FilePath user_dir;
|
||||
PathService::Get(brightray::DIR_USER_DATA, &user_dir);
|
||||
process_singleton_.reset(new ProcessSingleton(
|
||||
user_dir, base::Bind(NotificationCallbackWrapper, callback)));
|
||||
|
||||
switch (process_singleton_->NotifyOtherProcessOrCreate()) {
|
||||
case ProcessSingleton::NotifyResult::LOCK_ERROR:
|
||||
case ProcessSingleton::NotifyResult::PROFILE_IN_USE:
|
||||
case ProcessSingleton::NotifyResult::PROCESS_NOTIFIED:
|
||||
process_singleton_.reset();
|
||||
return true;
|
||||
case ProcessSingleton::NotifyResult::PROCESS_NONE:
|
||||
default: // Shouldn't be needed, but VS warns if it is not there.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
auto browser = base::Unretained(Browser::Get());
|
||||
|
@ -285,7 +335,10 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
|
|||
.SetMethod("getPath", &App::GetPath)
|
||||
.SetMethod("setDesktopName", &App::SetDesktopName)
|
||||
.SetMethod("setAppUserModelId", &App::SetAppUserModelId)
|
||||
.SetMethod("allowNTLMCredentialsForAllDomains",
|
||||
&App::AllowNTLMCredentialsForAllDomains)
|
||||
.SetMethod("getLocale", &App::GetLocale)
|
||||
.SetMethod("makeSingleInstance", &App::MakeSingleInstance)
|
||||
.SetProperty("defaultSession", &App::DefaultSession);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "atom/browser/browser_observer.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "chrome/browser/process_singleton.h"
|
||||
#include "content/public/browser/gpu_data_manager_observer.h"
|
||||
#include "native_mate/handle.h"
|
||||
|
||||
|
@ -65,11 +67,16 @@ class App : public mate::EventEmitter,
|
|||
|
||||
void SetDesktopName(const std::string& desktop_name);
|
||||
void SetAppUserModelId(const std::string& app_id);
|
||||
void AllowNTLMCredentialsForAllDomains(bool should_allow);
|
||||
bool MakeSingleInstance(
|
||||
const ProcessSingleton::NotificationCallback& callback);
|
||||
std::string GetLocale();
|
||||
v8::Local<v8::Value> DefaultSession(v8::Isolate* isolate);
|
||||
|
||||
v8::Global<v8::Value> default_session_;
|
||||
|
||||
scoped_ptr<ProcessSingleton> process_singleton_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(App);
|
||||
};
|
||||
|
||||
|
|
|
@ -5,12 +5,31 @@
|
|||
#include "atom/browser/api/atom_api_auto_updater.h"
|
||||
|
||||
#include "base/time/time.h"
|
||||
#include "atom/browser/auto_updater.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<base::Time> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const base::Time& val) {
|
||||
v8::MaybeLocal<v8::Value> date = v8::Date::New(
|
||||
isolate->GetCurrentContext(), val.ToJsTime());
|
||||
if (date.IsEmpty())
|
||||
return v8::Null(isolate);
|
||||
else
|
||||
return date.ToLocalChecked();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
@ -20,11 +39,18 @@ AutoUpdater::AutoUpdater() {
|
|||
}
|
||||
|
||||
AutoUpdater::~AutoUpdater() {
|
||||
auto_updater::AutoUpdater::SetDelegate(NULL);
|
||||
auto_updater::AutoUpdater::SetDelegate(nullptr);
|
||||
}
|
||||
|
||||
void AutoUpdater::OnError(const std::string& error) {
|
||||
Emit("error", error);
|
||||
void AutoUpdater::OnError(const std::string& message) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
auto error = v8::Exception::Error(mate::StringToV8(isolate(), message));
|
||||
EmitCustomEvent(
|
||||
"error",
|
||||
error->ToObject(isolate()->GetCurrentContext()).ToLocalChecked(),
|
||||
// Message is also emitted to keep compatibility with old code.
|
||||
message);
|
||||
}
|
||||
|
||||
void AutoUpdater::OnCheckingForUpdate() {
|
||||
|
@ -42,11 +68,14 @@ void AutoUpdater::OnUpdateNotAvailable() {
|
|||
void AutoUpdater::OnUpdateDownloaded(const std::string& release_notes,
|
||||
const std::string& release_name,
|
||||
const base::Time& release_date,
|
||||
const std::string& update_url,
|
||||
const base::Closure& quit_and_install) {
|
||||
quit_and_install_ = quit_and_install;
|
||||
Emit("update-downloaded-raw", release_notes, release_name,
|
||||
release_date.ToJsTime(), update_url);
|
||||
const std::string& url) {
|
||||
Emit("update-downloaded", release_notes, release_name, release_date, url,
|
||||
// Keep compatibility with old APIs.
|
||||
base::Bind(&AutoUpdater::QuitAndInstall, base::Unretained(this)));
|
||||
}
|
||||
|
||||
void AutoUpdater::OnWindowAllClosed() {
|
||||
QuitAndInstall();
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder(
|
||||
|
@ -54,14 +83,21 @@ mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder(
|
|||
return mate::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("setFeedUrl", &auto_updater::AutoUpdater::SetFeedURL)
|
||||
.SetMethod("checkForUpdates", &auto_updater::AutoUpdater::CheckForUpdates)
|
||||
.SetMethod("_quitAndInstall", &AutoUpdater::QuitAndInstall);
|
||||
.SetMethod("quitAndInstall", &AutoUpdater::QuitAndInstall);
|
||||
}
|
||||
|
||||
void AutoUpdater::QuitAndInstall() {
|
||||
if (quit_and_install_.is_null())
|
||||
Browser::Get()->Shutdown();
|
||||
else
|
||||
quit_and_install_.Run();
|
||||
// If we don't have any window then quitAndInstall immediately.
|
||||
WindowList* window_list = WindowList::GetInstance();
|
||||
if (window_list->size() == 0) {
|
||||
auto_updater::AutoUpdater::QuitAndInstall();
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise do the restart after all windows have been closed.
|
||||
window_list->AddObserver(this);
|
||||
for (NativeWindow* window : *window_list)
|
||||
window->Close();
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "atom/browser/auto_updater_delegate.h"
|
||||
#include "atom/browser/auto_updater.h"
|
||||
#include "atom/browser/window_list_observer.h"
|
||||
#include "native_mate/handle.h"
|
||||
|
||||
namespace atom {
|
||||
|
@ -17,7 +17,8 @@ namespace atom {
|
|||
namespace api {
|
||||
|
||||
class AutoUpdater : public mate::EventEmitter,
|
||||
public auto_updater::AutoUpdaterDelegate {
|
||||
public auto_updater::Delegate,
|
||||
public WindowListObserver {
|
||||
public:
|
||||
static mate::Handle<AutoUpdater> Create(v8::Isolate* isolate);
|
||||
|
||||
|
@ -25,17 +26,18 @@ class AutoUpdater : public mate::EventEmitter,
|
|||
AutoUpdater();
|
||||
virtual ~AutoUpdater();
|
||||
|
||||
// AutoUpdaterDelegate implementations.
|
||||
// Delegate implementations.
|
||||
void OnError(const std::string& error) override;
|
||||
void OnCheckingForUpdate() override;
|
||||
void OnUpdateAvailable() override;
|
||||
void OnUpdateNotAvailable() override;
|
||||
void OnUpdateDownloaded(
|
||||
const std::string& release_notes,
|
||||
void OnUpdateDownloaded(const std::string& release_notes,
|
||||
const std::string& release_name,
|
||||
const base::Time& release_date,
|
||||
const std::string& update_url,
|
||||
const base::Closure& quit_and_install) override;
|
||||
const std::string& update_url) override;
|
||||
|
||||
// WindowListObserver:
|
||||
void OnWindowAllClosed() override;
|
||||
|
||||
// mate::Wrappable implementations:
|
||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
|
@ -44,8 +46,6 @@ class AutoUpdater : public mate::EventEmitter,
|
|||
private:
|
||||
void QuitAndInstall();
|
||||
|
||||
base::Closure quit_and_install_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AutoUpdater);
|
||||
};
|
||||
|
||||
|
|
|
@ -105,6 +105,24 @@ struct Converter<ClearStorageDataOptions> {
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<net::ProxyConfig> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
net::ProxyConfig* out) {
|
||||
std::string proxy;
|
||||
if (!ConvertFromV8(isolate, val, &proxy))
|
||||
return false;
|
||||
auto pac_url = GURL(proxy);
|
||||
if (pac_url.is_valid()) {
|
||||
out->set_pac_url(pac_url);
|
||||
} else {
|
||||
out->proxy_rules().ParseFromString(proxy);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace atom {
|
||||
|
@ -209,12 +227,12 @@ void ClearHttpCacheInIO(
|
|||
}
|
||||
|
||||
void SetProxyInIO(net::URLRequestContextGetter* getter,
|
||||
const std::string& proxy,
|
||||
const net::ProxyConfig& config,
|
||||
const base::Closure& callback) {
|
||||
net::ProxyConfig config;
|
||||
config.proxy_rules().ParseFromString(proxy);
|
||||
auto proxy_service = getter->GetURLRequestContext()->proxy_service();
|
||||
proxy_service->ResetConfigService(new net::ProxyConfigServiceFixed(config));
|
||||
// Refetches and applies the new pac script if provided.
|
||||
proxy_service->ForceReloadProxyConfig();
|
||||
RunCallbackInUI(callback);
|
||||
}
|
||||
|
||||
|
@ -287,11 +305,11 @@ void Session::ClearStorageData(mate::Arguments* args) {
|
|||
base::Time(), base::Time::Max(), callback);
|
||||
}
|
||||
|
||||
void Session::SetProxy(const std::string& proxy,
|
||||
void Session::SetProxy(const net::ProxyConfig& config,
|
||||
const base::Closure& callback) {
|
||||
auto getter = browser_context_->GetRequestContext();
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&SetProxyInIO, base::Unretained(getter), proxy, callback));
|
||||
base::Bind(&SetProxyInIO, base::Unretained(getter), config, callback));
|
||||
}
|
||||
|
||||
void Session::SetDownloadPath(const base::FilePath& path) {
|
||||
|
|
|
@ -23,6 +23,10 @@ class Arguments;
|
|||
class Dictionary;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
class ProxyConfig;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomBrowserContext;
|
||||
|
@ -64,7 +68,7 @@ class Session: public mate::TrackableObject<Session>,
|
|||
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
|
||||
void ClearCache(const net::CompletionCallback& callback);
|
||||
void ClearStorageData(mate::Arguments* args);
|
||||
void SetProxy(const std::string& proxy, const base::Closure& callback);
|
||||
void SetProxy(const net::ProxyConfig& config, const base::Closure& callback);
|
||||
void SetDownloadPath(const base::FilePath& path);
|
||||
void EnableNetworkEmulation(const mate::Dictionary& options);
|
||||
void DisableNetworkEmulation();
|
||||
|
|
|
@ -618,6 +618,10 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
|
|||
if (options.Get("userAgent", &user_agent))
|
||||
SetUserAgent(user_agent);
|
||||
|
||||
std::string extra_headers;
|
||||
if (options.Get("extraHeaders", &extra_headers))
|
||||
params.extra_headers = extra_headers;
|
||||
|
||||
params.transition_type = ui::PAGE_TRANSITION_TYPED;
|
||||
params.should_clear_history_list = true;
|
||||
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
|
||||
|
|
|
@ -189,6 +189,14 @@ void Window::OnExecuteWindowsCommand(const std::string& command_name) {
|
|||
Emit("app-command", command_name);
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
void Window::OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) {
|
||||
if (IsWindowMessageHooked(message)) {
|
||||
messages_callback_map_[message].Run(w_param, l_param);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// static
|
||||
mate::Wrappable* Window::New(v8::Isolate* isolate,
|
||||
const mate::Dictionary& options) {
|
||||
|
@ -385,6 +393,10 @@ bool Window::IsKiosk() {
|
|||
return window_->IsKiosk();
|
||||
}
|
||||
|
||||
void Window::SetBackgroundColor(const std::string& color_name) {
|
||||
window_->SetBackgroundColor(color_name);
|
||||
}
|
||||
|
||||
void Window::FocusOnWebView() {
|
||||
window_->FocusOnWebView();
|
||||
}
|
||||
|
@ -488,6 +500,29 @@ bool Window::IsMenuBarVisible() {
|
|||
return window_->IsMenuBarVisible();
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
bool Window::HookWindowMessage(UINT message,
|
||||
const MessageCallback& callback) {
|
||||
messages_callback_map_[message] = callback;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Window::UnhookWindowMessage(UINT message) {
|
||||
if (!ContainsKey(messages_callback_map_, message))
|
||||
return;
|
||||
|
||||
messages_callback_map_.erase(message);
|
||||
}
|
||||
|
||||
bool Window::IsWindowMessageHooked(UINT message) {
|
||||
return ContainsKey(messages_callback_map_, message);
|
||||
}
|
||||
|
||||
void Window::UnhookAllWindowMessages() {
|
||||
messages_callback_map_.clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
void Window::ShowDefinitionForSelection() {
|
||||
window_->ShowDefinitionForSelection();
|
||||
|
@ -564,6 +599,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("setSkipTaskbar", &Window::SetSkipTaskbar)
|
||||
.SetMethod("setKiosk", &Window::SetKiosk)
|
||||
.SetMethod("isKiosk", &Window::IsKiosk)
|
||||
.SetMethod("setBackgroundColor", &Window::SetBackgroundColor)
|
||||
.SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename)
|
||||
.SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename)
|
||||
.SetMethod("setDocumentEdited", &Window::SetDocumentEdited)
|
||||
|
@ -585,6 +621,12 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
|||
&Window::SetVisibleOnAllWorkspaces)
|
||||
.SetMethod("isVisibleOnAllWorkspaces",
|
||||
&Window::IsVisibleOnAllWorkspaces)
|
||||
#if defined(OS_WIN)
|
||||
.SetMethod("hookWindowMessage", &Window::HookWindowMessage)
|
||||
.SetMethod("isWindowMessageHooked", &Window::IsWindowMessageHooked)
|
||||
.SetMethod("unhookWindowMessage", &Window::UnhookWindowMessage)
|
||||
.SetMethod("unhookAllWindowMessages", &Window::UnhookAllWindowMessages)
|
||||
#endif
|
||||
#if defined(OS_MACOSX)
|
||||
.SetMethod("showDefinitionForSelection",
|
||||
&Window::ShowDefinitionForSelection)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#ifndef ATOM_BROWSER_API_ATOM_API_WINDOW_H_
|
||||
#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -75,6 +76,11 @@ class Window : public mate::TrackableObject<Window>,
|
|||
void OnRendererResponsive() override;
|
||||
void OnExecuteWindowsCommand(const std::string& command_name) override;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
void OnWindowMessage(UINT message, WPARAM w_param,
|
||||
LPARAM l_param) override;
|
||||
#endif
|
||||
|
||||
// mate::Wrappable:
|
||||
bool IsDestroyed() const override;
|
||||
|
||||
|
@ -122,6 +128,7 @@ class Window : public mate::TrackableObject<Window>,
|
|||
void SetSkipTaskbar(bool skip);
|
||||
void SetKiosk(bool kiosk);
|
||||
bool IsKiosk();
|
||||
void SetBackgroundColor(const std::string& color_name);
|
||||
void FocusOnWebView();
|
||||
void BlurWebView();
|
||||
bool IsWebViewFocused();
|
||||
|
@ -142,6 +149,18 @@ class Window : public mate::TrackableObject<Window>,
|
|||
bool IsMenuBarVisible();
|
||||
void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
typedef base::Callback<void(WPARAM, LPARAM)> MessageCallback;
|
||||
typedef std::map<UINT, MessageCallback> MessageCallbackMap;
|
||||
MessageCallbackMap messages_callback_map_;
|
||||
|
||||
bool HookWindowMessage(UINT message,
|
||||
const MessageCallback& callback);
|
||||
bool IsWindowMessageHooked(UINT message);
|
||||
void UnhookWindowMessage(UINT message);
|
||||
void UnhookAllWindowMessages();
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
void ShowDefinitionForSelection();
|
||||
#endif
|
||||
|
|
|
@ -1,24 +1,7 @@
|
|||
autoUpdater = process.atomBinding('auto_updater').autoUpdater
|
||||
EventEmitter = require('events').EventEmitter
|
||||
|
||||
autoUpdater.__proto__ = EventEmitter.prototype
|
||||
|
||||
autoUpdater.on 'update-downloaded-raw', (args...) ->
|
||||
args[3] = new Date(args[3]) # releaseDate
|
||||
@emit 'update-downloaded', args..., => @quitAndInstall()
|
||||
|
||||
autoUpdater.quitAndInstall = ->
|
||||
# If we don't have any window then quitAndInstall immediately.
|
||||
BrowserWindow = require 'browser-window'
|
||||
windows = BrowserWindow.getAllWindows()
|
||||
if windows.length is 0
|
||||
@_quitAndInstall()
|
||||
return
|
||||
|
||||
# Do the restart after all windows have been closed.
|
||||
app = require 'app'
|
||||
app.removeAllListeners 'window-all-closed'
|
||||
app.once 'window-all-closed', @_quitAndInstall.bind(this)
|
||||
win.close() for win in windows
|
||||
|
||||
module.exports = autoUpdater
|
||||
switch process.platform
|
||||
when 'win32'
|
||||
module.exports = require './auto-updater/auto-updater-win'
|
||||
when 'darwin'
|
||||
module.exports = require './auto-updater/auto-updater-mac'
|
||||
else
|
||||
throw new Error('auto-updater is not implemented on this platform')
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{EventEmitter} = require 'events'
|
||||
{autoUpdater} = process.atomBinding 'auto_updater'
|
||||
|
||||
autoUpdater.__proto__ = EventEmitter.prototype
|
||||
|
||||
module.exports = autoUpdater
|
42
atom/browser/api/lib/auto-updater/auto-updater-win.coffee
Normal file
42
atom/browser/api/lib/auto-updater/auto-updater-win.coffee
Normal file
|
@ -0,0 +1,42 @@
|
|||
app = require 'app'
|
||||
url = require 'url'
|
||||
{EventEmitter} = require 'events'
|
||||
|
||||
squirrelUpdate = require './squirrel-update-win'
|
||||
|
||||
class AutoUpdater extends EventEmitter
|
||||
quitAndInstall: ->
|
||||
squirrelUpdate.processStart()
|
||||
app.quit()
|
||||
|
||||
setFeedUrl: (updateUrl) ->
|
||||
@updateUrl = updateUrl
|
||||
|
||||
checkForUpdates: ->
|
||||
return @emitError 'Update URL is not set' unless @updateUrl
|
||||
return @emitError 'Can not find Squirrel' unless squirrelUpdate.supported()
|
||||
|
||||
@emit 'checking-for-update'
|
||||
|
||||
squirrelUpdate.download @updateUrl, (error, update) =>
|
||||
return @emitError error if error?
|
||||
return @emit 'update-not-available' unless update?
|
||||
|
||||
@emit 'update-available'
|
||||
|
||||
squirrelUpdate.update @updateUrl, (error) =>
|
||||
return @emitError error if error?
|
||||
|
||||
{releaseNotes, version} = update
|
||||
# Following information is not available on Windows, so fake them.
|
||||
date = new Date
|
||||
url = @updateUrl
|
||||
|
||||
@emit 'update-downloaded', {}, releaseNotes, version, date, url, => @quitAndInstall()
|
||||
|
||||
# Private: Emit both error object and message, this is to keep compatibility
|
||||
# with Old APIs.
|
||||
emitError: (message) ->
|
||||
@emit 'error', new Error(message), message
|
||||
|
||||
module.exports = new AutoUpdater
|
67
atom/browser/api/lib/auto-updater/squirrel-update-win.coffee
Normal file
67
atom/browser/api/lib/auto-updater/squirrel-update-win.coffee
Normal file
|
@ -0,0 +1,67 @@
|
|||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
{spawn} = require 'child_process'
|
||||
|
||||
appFolder = path.dirname process.execPath # i.e. my-app/app-0.1.13/
|
||||
updateExe = path.resolve appFolder, '..', 'Update.exe' # i.e. my-app/Update.exe
|
||||
exeName = path.basename process.execPath
|
||||
|
||||
# Spawn a command and invoke the callback when it completes with an error
|
||||
# and the output from standard out.
|
||||
spawnUpdate = (args, detached, callback) ->
|
||||
try
|
||||
spawnedProcess = spawn updateExe, args, {detached}
|
||||
catch error
|
||||
# Shouldn't happen, but still guard it.
|
||||
process.nextTick -> callback error
|
||||
return
|
||||
|
||||
stdout = ''
|
||||
stderr = ''
|
||||
spawnedProcess.stdout.on 'data', (data) -> stdout += data
|
||||
spawnedProcess.stderr.on 'data', (data) -> stderr += data
|
||||
|
||||
errorEmitted = false
|
||||
spawnedProcess.on 'error', (error) ->
|
||||
errorEmitted = true
|
||||
callback error
|
||||
spawnedProcess.on 'exit', (code, signal) ->
|
||||
# We may have already emitted an error.
|
||||
return if errorEmitted
|
||||
|
||||
# Process terminated with error.
|
||||
if code isnt 0
|
||||
return callback "Command failed: #{signal ? code}\n#{stderr}"
|
||||
|
||||
# Success.
|
||||
callback null, stdout
|
||||
|
||||
# Start an instance of the installed app.
|
||||
exports.processStart = (callback) ->
|
||||
spawnUpdate ['--processStart', exeName], true, ->
|
||||
|
||||
# Download the releases specified by the URL and write new results to stdout.
|
||||
exports.download = (updateUrl, callback) ->
|
||||
spawnUpdate ['--download', updateUrl], false, (error, stdout) ->
|
||||
return callback(error) if error?
|
||||
|
||||
try
|
||||
# Last line of output is the JSON details about the releases
|
||||
json = stdout.trim().split('\n').pop()
|
||||
update = JSON.parse(json)?.releasesToApply?.pop?()
|
||||
catch
|
||||
return callback "Invalid result:\n#{stdout}"
|
||||
|
||||
callback null, update
|
||||
|
||||
# Update the application to the latest remote version specified by URL.
|
||||
exports.update = (updateUrl, callback) ->
|
||||
spawnUpdate ['--update', updateUrl], false, callback
|
||||
|
||||
# Is the Update.exe installed with the current application?
|
||||
exports.supported = ->
|
||||
try
|
||||
fs.accessSync updateExe, fs.R_OK
|
||||
return true
|
||||
catch
|
||||
return false
|
|
@ -36,8 +36,13 @@ bool SavePageHandler::Handle(const base::FilePath& full_path,
|
|||
auto download_manager = content::BrowserContext::GetDownloadManager(
|
||||
web_contents_->GetBrowserContext());
|
||||
download_manager->AddObserver(this);
|
||||
// Chromium will create a 'foo_files' directory under the directory of saving
|
||||
// page 'foo.html' for holding other resource files of 'foo.html'.
|
||||
base::FilePath saved_main_directory_path = full_path.DirName().Append(
|
||||
full_path.RemoveExtension().BaseName().value() +
|
||||
FILE_PATH_LITERAL("_files"));
|
||||
bool result = web_contents_->SavePage(full_path,
|
||||
full_path.DirName(),
|
||||
saved_main_directory_path,
|
||||
save_type);
|
||||
download_manager->RemoveObserver(this);
|
||||
// If initialization fails which means fail to create |DownloadItem|, we need
|
||||
|
|
|
@ -60,7 +60,8 @@ std::string RemoveWhitespace(const std::string& str) {
|
|||
AtomBrowserContext::AtomBrowserContext(const std::string& partition,
|
||||
bool in_memory)
|
||||
: brightray::BrowserContext(partition, in_memory),
|
||||
job_factory_(new AtomURLRequestJobFactory) {
|
||||
job_factory_(new AtomURLRequestJobFactory),
|
||||
allow_ntlm_everywhere_(false) {
|
||||
}
|
||||
|
||||
AtomBrowserContext::~AtomBrowserContext() {
|
||||
|
@ -168,6 +169,16 @@ void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
|
|||
base::FilePath());
|
||||
}
|
||||
|
||||
bool AtomBrowserContext::AllowNTLMCredentialsForDomain(const GURL& origin) {
|
||||
if (allow_ntlm_everywhere_)
|
||||
return true;
|
||||
return Delegate::AllowNTLMCredentialsForDomain(origin);
|
||||
}
|
||||
|
||||
void AtomBrowserContext::AllowNTLMCredentialsForAllDomains(bool should_allow) {
|
||||
allow_ntlm_everywhere_ = should_allow;
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
namespace brightray {
|
||||
|
|
|
@ -28,6 +28,7 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
|||
net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory(
|
||||
const base::FilePath& base_path) override;
|
||||
net::SSLConfigService* CreateSSLConfigService() override;
|
||||
bool AllowNTLMCredentialsForDomain(const GURL& auth_origin) override;
|
||||
|
||||
// content::BrowserContext:
|
||||
content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
|
||||
|
@ -36,6 +37,8 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
|||
// brightray::BrowserContext:
|
||||
void RegisterPrefs(PrefRegistrySimple* pref_registry) override;
|
||||
|
||||
void AllowNTLMCredentialsForAllDomains(bool should_allow);
|
||||
|
||||
AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
|
||||
|
||||
private:
|
||||
|
@ -45,6 +48,8 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
|||
// Managed by brightray::BrowserContext.
|
||||
AtomURLRequestJobFactory* job_factory_;
|
||||
|
||||
bool allow_ntlm_everywhere_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext);
|
||||
};
|
||||
|
||||
|
|
|
@ -62,7 +62,6 @@ void AtomBrowserMainParts::PreEarlyInitialization() {
|
|||
void AtomBrowserMainParts::PostEarlyInitialization() {
|
||||
brightray::BrowserMainParts::PostEarlyInitialization();
|
||||
|
||||
{
|
||||
// Temporary set the bridge_task_runner_ as current thread's task runner,
|
||||
// so we can fool gin::PerIsolateData to use it as its task runner, instead
|
||||
// of getting current message loop's task runner, which is null for now.
|
||||
|
@ -72,7 +71,6 @@ void AtomBrowserMainParts::PostEarlyInitialization() {
|
|||
// The ProxyResolverV8 has setup a complete V8 environment, in order to
|
||||
// avoid conflicts we only initialize our V8 environment after that.
|
||||
js_env_.reset(new JavascriptEnvironment);
|
||||
}
|
||||
|
||||
node_bindings_->Initialize();
|
||||
|
||||
|
@ -107,6 +105,7 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
|
|||
1000));
|
||||
|
||||
brightray::BrowserMainParts::PreMainMessageLoopRun();
|
||||
BridgeTaskRunner::MessageLoopIsReady();
|
||||
|
||||
#if defined(USE_X11)
|
||||
libgtk2ui::GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess());
|
||||
|
|
|
@ -5,11 +5,14 @@
|
|||
#include "atom/browser/atom_ssl_config_service.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/socket/ssl_client_socket.h"
|
||||
#include "net/ssl/ssl_cipher_suite_names.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
|
@ -26,6 +29,23 @@ uint16 GetSSLProtocolVersion(const std::string& version_string) {
|
|||
return version;
|
||||
}
|
||||
|
||||
std::vector<uint16> ParseCipherSuites(
|
||||
const std::vector<std::string>& cipher_strings) {
|
||||
std::vector<uint16> cipher_suites;
|
||||
cipher_suites.reserve(cipher_strings.size());
|
||||
|
||||
for (auto& cipher_string : cipher_strings) {
|
||||
uint16 cipher_suite = 0;
|
||||
if (!net::ParseSSLCipherString(cipher_string, &cipher_suite)) {
|
||||
LOG(ERROR) << "Ignoring unrecognised cipher suite : "
|
||||
<< cipher_string;
|
||||
continue;
|
||||
}
|
||||
cipher_suites.push_back(cipher_suite);
|
||||
}
|
||||
return cipher_suites;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AtomSSLConfigService::AtomSSLConfigService() {
|
||||
|
@ -35,6 +55,13 @@ AtomSSLConfigService::AtomSSLConfigService() {
|
|||
cmd_line->GetSwitchValueASCII(switches::kSSLVersionFallbackMin);
|
||||
config_.version_fallback_min = GetSSLProtocolVersion(version_string);
|
||||
}
|
||||
|
||||
if (cmd_line->HasSwitch(switches::kCipherSuiteBlacklist)) {
|
||||
auto cipher_strings = base::SplitString(
|
||||
cmd_line->GetSwitchValueASCII(switches::kCipherSuiteBlacklist),
|
||||
",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
||||
config_.disabled_cipher_suites = ParseCipherSuites(cipher_strings);
|
||||
}
|
||||
}
|
||||
|
||||
AtomSSLConfigService::~AtomSSLConfigService() {
|
||||
|
|
|
@ -6,22 +6,25 @@
|
|||
|
||||
namespace auto_updater {
|
||||
|
||||
AutoUpdaterDelegate* AutoUpdater::delegate_ = NULL;
|
||||
Delegate* AutoUpdater::delegate_ = nullptr;
|
||||
|
||||
AutoUpdaterDelegate* AutoUpdater::GetDelegate() {
|
||||
Delegate* AutoUpdater::GetDelegate() {
|
||||
return delegate_;
|
||||
}
|
||||
|
||||
void AutoUpdater::SetDelegate(AutoUpdaterDelegate* delegate) {
|
||||
void AutoUpdater::SetDelegate(Delegate* delegate) {
|
||||
delegate_ = delegate;
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX) && defined(MAS_BUILD)
|
||||
#if !defined(OS_MACOSX) || defined(MAS_BUILD)
|
||||
void AutoUpdater::SetFeedURL(const std::string& url) {
|
||||
}
|
||||
|
||||
void AutoUpdater::CheckForUpdates() {
|
||||
}
|
||||
|
||||
void AutoUpdater::QuitAndInstall() {
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace auto_updater
|
||||
|
|
|
@ -9,21 +9,48 @@
|
|||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace base {
|
||||
class Time;
|
||||
}
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
class AutoUpdaterDelegate;
|
||||
class Delegate {
|
||||
public:
|
||||
// An error happened.
|
||||
virtual void OnError(const std::string& error) {}
|
||||
|
||||
// Checking to see if there is an update
|
||||
virtual void OnCheckingForUpdate() {}
|
||||
|
||||
// There is an update available and it is being downloaded
|
||||
virtual void OnUpdateAvailable() {}
|
||||
|
||||
// There is no available update.
|
||||
virtual void OnUpdateNotAvailable() {}
|
||||
|
||||
// There is a new update which has been downloaded.
|
||||
virtual void OnUpdateDownloaded(const std::string& release_notes,
|
||||
const std::string& release_name,
|
||||
const base::Time& release_date,
|
||||
const std::string& update_url) {}
|
||||
|
||||
protected:
|
||||
virtual ~Delegate() {}
|
||||
};
|
||||
|
||||
class AutoUpdater {
|
||||
public:
|
||||
// Gets/Sets the delegate.
|
||||
static AutoUpdaterDelegate* GetDelegate();
|
||||
static void SetDelegate(AutoUpdaterDelegate* delegate);
|
||||
static Delegate* GetDelegate();
|
||||
static void SetDelegate(Delegate* delegate);
|
||||
|
||||
static void SetFeedURL(const std::string& url);
|
||||
static void CheckForUpdates();
|
||||
static void QuitAndInstall();
|
||||
|
||||
private:
|
||||
static AutoUpdaterDelegate* delegate_;
|
||||
static Delegate* delegate_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(AutoUpdater);
|
||||
};
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_
|
||||
#define ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/callback_forward.h"
|
||||
|
||||
namespace base {
|
||||
class Time;
|
||||
}
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
class AutoUpdaterDelegate {
|
||||
public:
|
||||
// An error happened.
|
||||
virtual void OnError(const std::string& error) {}
|
||||
|
||||
// Checking to see if there is an update
|
||||
virtual void OnCheckingForUpdate() {}
|
||||
|
||||
// There is an update available and it is being downloaded
|
||||
virtual void OnUpdateAvailable() {}
|
||||
|
||||
// There is no available update.
|
||||
virtual void OnUpdateNotAvailable() {}
|
||||
|
||||
// There is a new update which has been downloaded.
|
||||
virtual void OnUpdateDownloaded(const std::string& release_notes,
|
||||
const std::string& release_name,
|
||||
const base::Time& release_date,
|
||||
const std::string& update_url,
|
||||
const base::Closure& quit_and_install) {}
|
||||
|
||||
protected:
|
||||
virtual ~AutoUpdaterDelegate() {}
|
||||
};
|
||||
|
||||
} // namespace auto_updater
|
||||
|
||||
#endif // ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_
|
|
@ -1,17 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/auto_updater.h"
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
// static
|
||||
void AutoUpdater::SetFeedURL(const std::string& url) {
|
||||
}
|
||||
|
||||
// static
|
||||
void AutoUpdater::CheckForUpdates() {
|
||||
}
|
||||
|
||||
} // namespace auto_updater
|
|
@ -12,9 +12,6 @@
|
|||
#include "base/bind.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "atom/browser/auto_updater_delegate.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
|
@ -23,20 +20,12 @@ namespace {
|
|||
// The gloal SQRLUpdater object.
|
||||
SQRLUpdater* g_updater = nil;
|
||||
|
||||
void RelaunchToInstallUpdate() {
|
||||
[[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) {
|
||||
AutoUpdaterDelegate* delegate = AutoUpdater::GetDelegate();
|
||||
if (delegate)
|
||||
delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription));
|
||||
}];
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
void AutoUpdater::SetFeedURL(const std::string& feed) {
|
||||
if (g_updater == nil) {
|
||||
AutoUpdaterDelegate* delegate = GetDelegate();
|
||||
Delegate* delegate = GetDelegate();
|
||||
if (!delegate)
|
||||
return;
|
||||
|
||||
|
@ -67,7 +56,7 @@ void AutoUpdater::SetFeedURL(const std::string& feed) {
|
|||
|
||||
// static
|
||||
void AutoUpdater::CheckForUpdates() {
|
||||
AutoUpdaterDelegate* delegate = GetDelegate();
|
||||
Delegate* delegate = GetDelegate();
|
||||
if (!delegate)
|
||||
return;
|
||||
|
||||
|
@ -86,8 +75,7 @@ void AutoUpdater::CheckForUpdates() {
|
|||
base::SysNSStringToUTF8(update.releaseNotes),
|
||||
base::SysNSStringToUTF8(update.releaseName),
|
||||
base::Time::FromDoubleT(update.releaseDate.timeIntervalSince1970),
|
||||
base::SysNSStringToUTF8(update.updateURL.absoluteString),
|
||||
base::Bind(RelaunchToInstallUpdate));
|
||||
base::SysNSStringToUTF8(update.updateURL.absoluteString));
|
||||
} else {
|
||||
// When the completed event is sent with no update, then we know there
|
||||
// is no update available.
|
||||
|
@ -100,4 +88,12 @@ void AutoUpdater::CheckForUpdates() {
|
|||
}];
|
||||
}
|
||||
|
||||
void AutoUpdater::QuitAndInstall() {
|
||||
[[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) {
|
||||
Delegate* delegate = AutoUpdater::GetDelegate();
|
||||
if (delegate)
|
||||
delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription));
|
||||
}];
|
||||
}
|
||||
|
||||
} // namespace auto_updater
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/auto_updater.h"
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
// static
|
||||
void AutoUpdater::SetFeedURL(const std::string& url) {
|
||||
}
|
||||
|
||||
// static
|
||||
void AutoUpdater::CheckForUpdates() {
|
||||
}
|
||||
|
||||
} // namespace auto_updater
|
|
@ -8,13 +8,33 @@
|
|||
|
||||
namespace atom {
|
||||
|
||||
// static
|
||||
std::vector<BridgeTaskRunner::TaskPair> BridgeTaskRunner::tasks_;
|
||||
std::vector<BridgeTaskRunner::TaskPair> BridgeTaskRunner::non_nestable_tasks_;
|
||||
|
||||
// static
|
||||
void BridgeTaskRunner::MessageLoopIsReady() {
|
||||
auto message_loop = base::MessageLoop::current();
|
||||
CHECK(message_loop);
|
||||
for (const TaskPair& task : tasks_) {
|
||||
message_loop->task_runner()->PostDelayedTask(
|
||||
base::get<0>(task), base::get<1>(task), base::get<2>(task));
|
||||
}
|
||||
for (const TaskPair& task : non_nestable_tasks_) {
|
||||
message_loop->task_runner()->PostNonNestableDelayedTask(
|
||||
base::get<0>(task), base::get<1>(task), base::get<2>(task));
|
||||
}
|
||||
}
|
||||
|
||||
bool BridgeTaskRunner::PostDelayedTask(
|
||||
const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::TimeDelta delay) {
|
||||
auto message_loop = base::MessageLoop::current();
|
||||
if (!message_loop)
|
||||
return false;
|
||||
if (!message_loop) {
|
||||
tasks_.push_back(base::MakeTuple(from_here, task, delay));
|
||||
return true;
|
||||
}
|
||||
|
||||
return message_loop->task_runner()->PostDelayedTask(from_here, task, delay);
|
||||
}
|
||||
|
@ -22,7 +42,7 @@ bool BridgeTaskRunner::PostDelayedTask(
|
|||
bool BridgeTaskRunner::RunsTasksOnCurrentThread() const {
|
||||
auto message_loop = base::MessageLoop::current();
|
||||
if (!message_loop)
|
||||
return false;
|
||||
return true;
|
||||
|
||||
return message_loop->task_runner()->RunsTasksOnCurrentThread();
|
||||
}
|
||||
|
@ -32,8 +52,10 @@ bool BridgeTaskRunner::PostNonNestableDelayedTask(
|
|||
const base::Closure& task,
|
||||
base::TimeDelta delay) {
|
||||
auto message_loop = base::MessageLoop::current();
|
||||
if (!message_loop)
|
||||
return false;
|
||||
if (!message_loop) {
|
||||
non_nestable_tasks_.push_back(base::MakeTuple(from_here, task, delay));
|
||||
return true;
|
||||
}
|
||||
|
||||
return message_loop->task_runner()->PostNonNestableDelayedTask(
|
||||
from_here, task, delay);
|
||||
|
|
|
@ -5,17 +5,23 @@
|
|||
#ifndef ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
|
||||
#define ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/single_thread_task_runner.h"
|
||||
#include "base/tuple.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Post all tasks to the current message loop's task runner if available,
|
||||
// otherwise fail silently.
|
||||
// otherwise delay the work until message loop is ready.
|
||||
class BridgeTaskRunner : public base::SingleThreadTaskRunner {
|
||||
public:
|
||||
BridgeTaskRunner() {}
|
||||
~BridgeTaskRunner() override {}
|
||||
|
||||
// Called when message loop is ready.
|
||||
static void MessageLoopIsReady();
|
||||
|
||||
// base::SingleThreadTaskRunner:
|
||||
bool PostDelayedTask(const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
|
@ -27,6 +33,11 @@ class BridgeTaskRunner : public base::SingleThreadTaskRunner {
|
|||
base::TimeDelta delay) override;
|
||||
|
||||
private:
|
||||
using TaskPair = base::Tuple<
|
||||
tracked_objects::Location, base::Closure, base::TimeDelta>;
|
||||
static std::vector<TaskPair> tasks_;
|
||||
static std::vector<TaskPair> non_nestable_tasks_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BridgeTaskRunner);
|
||||
};
|
||||
|
||||
|
|
|
@ -53,8 +53,14 @@ void Browser::Shutdown() {
|
|||
is_quiting_ = true;
|
||||
|
||||
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnQuit());
|
||||
|
||||
if (base::MessageLoop::current()) {
|
||||
base::MessageLoop::current()->PostTask(
|
||||
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
|
||||
} else {
|
||||
// There is no message loop available so we are in early stage.
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Browser::GetVersion() const {
|
||||
|
|
|
@ -130,6 +130,7 @@ class Browser : public WindowListObserver {
|
|||
observers_.RemoveObserver(obs);
|
||||
}
|
||||
|
||||
bool is_shutting_down() const { return is_shutdown_; }
|
||||
bool is_quiting() const { return is_quiting_; }
|
||||
bool is_ready() const { return is_ready_; }
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "atom/browser/javascript_environment.h"
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "gin/array_buffer.h"
|
||||
#include "gin/v8_initializer.h"
|
||||
|
||||
|
@ -20,7 +21,12 @@ JavascriptEnvironment::JavascriptEnvironment()
|
|||
}
|
||||
|
||||
bool JavascriptEnvironment::Initialize() {
|
||||
gin::V8Initializer::LoadV8Snapshot();
|
||||
auto cmd = base::CommandLine::ForCurrentProcess();
|
||||
if (cmd->HasSwitch("debug-brk")) {
|
||||
// Need to be called before v8::Initialize().
|
||||
const char expose_debug_as[] = "--expose_debug_as=v8debug";
|
||||
v8::V8::SetFlagsFromString(expose_debug_as, sizeof(expose_debug_as) - 1);
|
||||
}
|
||||
gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode,
|
||||
gin::ArrayBufferAllocator::SharedInstance());
|
||||
return true;
|
||||
|
|
|
@ -10,6 +10,8 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
|||
meta.type = 'buffer' if Buffer.isBuffer value
|
||||
meta.type = 'value' if value is null
|
||||
meta.type = 'array' if Array.isArray value
|
||||
meta.type = 'error' if value instanceof Error
|
||||
meta.type = 'date' if value instanceof Date
|
||||
meta.type = 'promise' if value? and value.constructor.name is 'Promise'
|
||||
|
||||
# Treat simple objects as value.
|
||||
|
@ -36,6 +38,10 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
|||
meta.value = Array::slice.call value, 0
|
||||
else if meta.type is 'promise'
|
||||
meta.then = valueToMeta(sender, value.then.bind(value))
|
||||
else if meta.type is 'error'
|
||||
meta.message = value.message
|
||||
else if meta.type is 'date'
|
||||
meta.value = value.getTime()
|
||||
else
|
||||
meta.type = 'value'
|
||||
meta.value = value
|
||||
|
@ -43,8 +49,8 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
|||
meta
|
||||
|
||||
# Convert Error into meta data.
|
||||
errorToMeta = (error) ->
|
||||
type: 'error', message: error.message, stack: (error.stack || error)
|
||||
exceptionToMeta = (error) ->
|
||||
type: 'exception', message: error.message, stack: (error.stack || error)
|
||||
|
||||
# Convert array of meta data from renderer into array of real values.
|
||||
unwrapArgs = (sender, args) ->
|
||||
|
@ -100,19 +106,19 @@ ipc.on 'ATOM_BROWSER_REQUIRE', (event, module) ->
|
|||
try
|
||||
event.returnValue = valueToMeta event.sender, process.mainModule.require(module)
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_GLOBAL', (event, name) ->
|
||||
try
|
||||
event.returnValue = valueToMeta event.sender, global[name]
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event) ->
|
||||
try
|
||||
event.returnValue = valueToMeta event.sender, event.sender.getOwnerBrowserWindow()
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_CURRENT_WEB_CONTENTS', (event) ->
|
||||
event.returnValue = valueToMeta event.sender, event.sender
|
||||
|
@ -126,7 +132,7 @@ ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, id, args) ->
|
|||
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
||||
event.returnValue = valueToMeta event.sender, obj
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, id, args) ->
|
||||
try
|
||||
|
@ -134,7 +140,7 @@ ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, id, args) ->
|
|||
func = objectsRegistry.get id
|
||||
callFunction event, func, global, args
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) ->
|
||||
try
|
||||
|
@ -144,7 +150,7 @@ ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) ->
|
|||
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
||||
event.returnValue = valueToMeta event.sender, obj
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, id, method, args) ->
|
||||
try
|
||||
|
@ -152,7 +158,7 @@ ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, id, method, args) ->
|
|||
obj = objectsRegistry.get id
|
||||
callFunction event, obj[method], obj, args
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, id, name, value) ->
|
||||
try
|
||||
|
@ -160,14 +166,14 @@ ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, id, name, value) ->
|
|||
obj[name] = value
|
||||
event.returnValue = null
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, id, name) ->
|
||||
try
|
||||
obj = objectsRegistry.get id
|
||||
event.returnValue = valueToMeta event.sender, obj[name]
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_DEREFERENCE', (event, id) ->
|
||||
objectsRegistry.remove event.sender.getId(), id
|
||||
|
@ -177,4 +183,4 @@ ipc.on 'ATOM_BROWSER_GUEST_WEB_CONTENTS', (event, guestInstanceId) ->
|
|||
guestViewManager = require './guest-view-manager'
|
||||
event.returnValue = valueToMeta event.sender, guestViewManager.getGuest(guestInstanceId)
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
|
|
@ -43,26 +43,6 @@ DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::NativeWindowRelay);
|
|||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// Convert draggable regions in raw format to SkRegion format. Caller is
|
||||
// responsible for deleting the returned SkRegion instance.
|
||||
scoped_ptr<SkRegion> DraggableRegionsToSkRegion(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
scoped_ptr<SkRegion> sk_region(new SkRegion);
|
||||
for (const DraggableRegion& region : regions) {
|
||||
sk_region->op(
|
||||
region.bounds.x(),
|
||||
region.bounds.y(),
|
||||
region.bounds.right(),
|
||||
region.bounds.bottom(),
|
||||
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
|
||||
}
|
||||
return sk_region.Pass();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NativeWindow::NativeWindow(
|
||||
brightray::InspectableWebContents* inspectable_web_contents,
|
||||
const mate::Dictionary& options)
|
||||
|
@ -159,6 +139,10 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
|
|||
if (options.Get(switches::kKiosk, &kiosk) && kiosk) {
|
||||
SetKiosk(kiosk);
|
||||
}
|
||||
std::string color;
|
||||
if (options.Get(switches::kBackgroundColor, &color)) {
|
||||
SetBackgroundColor(color);
|
||||
}
|
||||
std::string title("Electron");
|
||||
options.Get(switches::kTitle, &title);
|
||||
SetTitle(title);
|
||||
|
@ -480,6 +464,28 @@ void NativeWindow::NotifyWindowExecuteWindowsCommand(
|
|||
OnExecuteWindowsCommand(command));
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
void NativeWindow::NotifyWindowMessage(UINT message, WPARAM w_param,
|
||||
LPARAM l_param) {
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
|
||||
OnWindowMessage(message, w_param, l_param));
|
||||
}
|
||||
#endif
|
||||
|
||||
scoped_ptr<SkRegion> NativeWindow::DraggableRegionsToSkRegion(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
scoped_ptr<SkRegion> sk_region(new SkRegion);
|
||||
for (const DraggableRegion& region : regions) {
|
||||
sk_region->op(
|
||||
region.bounds.x(),
|
||||
region.bounds.y(),
|
||||
region.bounds.right(),
|
||||
region.bounds.bottom(),
|
||||
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
|
||||
}
|
||||
return sk_region.Pass();
|
||||
}
|
||||
|
||||
void NativeWindow::RenderViewCreated(
|
||||
content::RenderViewHost* render_view_host) {
|
||||
if (!transparent_)
|
||||
|
|
|
@ -134,6 +134,7 @@ class NativeWindow : public base::SupportsUserData,
|
|||
virtual void SetSkipTaskbar(bool skip) = 0;
|
||||
virtual void SetKiosk(bool kiosk) = 0;
|
||||
virtual bool IsKiosk() = 0;
|
||||
virtual void SetBackgroundColor(const std::string& color_name) = 0;
|
||||
virtual void SetRepresentedFilename(const std::string& filename);
|
||||
virtual std::string GetRepresentedFilename();
|
||||
virtual void SetDocumentEdited(bool edited);
|
||||
|
@ -209,6 +210,10 @@ class NativeWindow : public base::SupportsUserData,
|
|||
void NotifyWindowLeaveHtmlFullScreen();
|
||||
void NotifyWindowExecuteWindowsCommand(const std::string& command);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
void NotifyWindowMessage(UINT message, WPARAM w_param, LPARAM l_param);
|
||||
#endif
|
||||
|
||||
void AddObserver(NativeWindowObserver* obs) {
|
||||
observers_.AddObserver(obs);
|
||||
}
|
||||
|
@ -241,10 +246,19 @@ class NativeWindow : public base::SupportsUserData,
|
|||
NativeWindow(brightray::InspectableWebContents* inspectable_web_contents,
|
||||
const mate::Dictionary& options);
|
||||
|
||||
// Convert draggable regions in raw format to SkRegion format. Caller is
|
||||
// responsible for deleting the returned SkRegion instance.
|
||||
scoped_ptr<SkRegion> DraggableRegionsToSkRegion(
|
||||
const std::vector<DraggableRegion>& regions);
|
||||
|
||||
// Converts between content size to window size.
|
||||
virtual gfx::Size ContentSizeToWindowSize(const gfx::Size& size) = 0;
|
||||
virtual gfx::Size WindowSizeToContentSize(const gfx::Size& size) = 0;
|
||||
|
||||
// Called when the window needs to update its draggable region.
|
||||
virtual void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions);
|
||||
|
||||
// content::WebContentsObserver:
|
||||
void RenderViewCreated(content::RenderViewHost* render_view_host) override;
|
||||
void BeforeUnloadDialogCancelled() override;
|
||||
|
@ -252,10 +266,6 @@ class NativeWindow : public base::SupportsUserData,
|
|||
bool OnMessageReceived(const IPC::Message& message) override;
|
||||
|
||||
private:
|
||||
// Called when the window needs to update its draggable region.
|
||||
void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions);
|
||||
|
||||
// Schedule a notification unresponsive event.
|
||||
void ScheduleUnresponsiveEvent(int ms);
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ class NativeWindowMac : public NativeWindow {
|
|||
void SetSkipTaskbar(bool skip) override;
|
||||
void SetKiosk(bool kiosk) override;
|
||||
bool IsKiosk() override;
|
||||
void SetBackgroundColor(const std::string& color_name) override;
|
||||
void SetRepresentedFilename(const std::string& filename) override;
|
||||
std::string GetRepresentedFilename() override;
|
||||
void SetDocumentEdited(bool edited) override;
|
||||
|
@ -71,12 +72,10 @@ class NativeWindowMac : public NativeWindow {
|
|||
void SetVisibleOnAllWorkspaces(bool visible) override;
|
||||
bool IsVisibleOnAllWorkspaces() override;
|
||||
|
||||
// Returns true if |point| in local Cocoa coordinate system falls within
|
||||
// the draggable region.
|
||||
bool IsWithinDraggableRegion(NSPoint point) const;
|
||||
|
||||
// Called to handle a mouse event.
|
||||
void HandleMouseEvent(NSEvent* event);
|
||||
// Refresh the DraggableRegion views.
|
||||
void UpdateDraggableRegionViews() {
|
||||
UpdateDraggableRegionViews(draggable_regions_);
|
||||
}
|
||||
|
||||
protected:
|
||||
// NativeWindow:
|
||||
|
@ -84,17 +83,24 @@ class NativeWindowMac : public NativeWindow {
|
|||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent&) override;
|
||||
|
||||
// Return a vector of non-draggable regions that fill a window of size
|
||||
// |width| by |height|, but leave gaps where the window should be draggable.
|
||||
std::vector<gfx::Rect> CalculateNonDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions, int width, int height);
|
||||
|
||||
private:
|
||||
// NativeWindow:
|
||||
gfx::Size ContentSizeToWindowSize(const gfx::Size& size) override;
|
||||
gfx::Size WindowSizeToContentSize(const gfx::Size& size) override;
|
||||
void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) override;
|
||||
|
||||
void InstallView();
|
||||
void UninstallView();
|
||||
|
||||
// Install the drag view, which will cover the whole window and decides
|
||||
// whehter we can drag.
|
||||
void InstallDraggableRegionView();
|
||||
void UpdateDraggableRegionViews(const std::vector<DraggableRegion>& regions);
|
||||
|
||||
base::scoped_nsobject<AtomNSWindow> window_;
|
||||
base::scoped_nsobject<AtomNSWindowDelegate> window_delegate_;
|
||||
|
@ -102,6 +108,8 @@ class NativeWindowMac : public NativeWindow {
|
|||
// The view that will fill the whole frameless window.
|
||||
base::scoped_nsobject<FullSizeContentView> content_view_;
|
||||
|
||||
std::vector<DraggableRegion> draggable_regions_;
|
||||
|
||||
bool is_kiosk_;
|
||||
|
||||
NSInteger attention_request_id_; // identifier from requestUserAttention
|
||||
|
@ -109,10 +117,6 @@ class NativeWindowMac : public NativeWindow {
|
|||
// The presentation options before entering kiosk mode.
|
||||
NSApplicationPresentationOptions kiosk_options_;
|
||||
|
||||
// Mouse location since the last mouse event, in screen coordinates. This is
|
||||
// used in custom drag to compute the window movement.
|
||||
NSPoint last_mouse_offset_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowMac);
|
||||
};
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/gfx/skia_util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -146,6 +147,7 @@ bool ScopedDisableResize::disable_resize_ = false;
|
|||
}
|
||||
|
||||
- (void)windowDidResize:(NSNotification*)notification {
|
||||
shell_->UpdateDraggableRegionViews();
|
||||
shell_->NotifyWindowResize();
|
||||
}
|
||||
|
||||
|
@ -257,43 +259,23 @@ bool ScopedDisableResize::disable_resize_ = false;
|
|||
|
||||
@end
|
||||
|
||||
@interface ControlRegionView : NSView {
|
||||
@private
|
||||
atom::NativeWindowMac* shellWindow_; // Weak; owns self.
|
||||
}
|
||||
@interface ControlRegionView : NSView
|
||||
@end
|
||||
|
||||
@implementation ControlRegionView
|
||||
|
||||
- (id)initWithShellWindow:(atom::NativeWindowMac*)shellWindow {
|
||||
if ((self = [super init]))
|
||||
shellWindow_ = shellWindow;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)mouseDownCanMoveWindow {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSView*)hitTest:(NSPoint)aPoint {
|
||||
if (!shellWindow_->IsWithinDraggableRegion(aPoint)) {
|
||||
return nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent*)event {
|
||||
shellWindow_->HandleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(NSEvent*)event {
|
||||
shellWindow_->HandleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstMouse:(NSEvent*)event {
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface NSView (WebContentsView)
|
||||
- (void)setMouseDownCanMoveWindow:(BOOL)can_move;
|
||||
@end
|
||||
|
||||
@interface AtomProgressBar : NSProgressIndicator
|
||||
|
@ -439,11 +421,6 @@ NativeWindowMac::NativeWindowMac(
|
|||
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
||||
|
||||
InstallView();
|
||||
|
||||
// Install the DraggableRegionView if it is forced to use draggable regions
|
||||
// for normal window.
|
||||
if (has_frame() && force_using_draggable_region())
|
||||
InstallDraggableRegionView();
|
||||
}
|
||||
|
||||
NativeWindowMac::~NativeWindowMac() {
|
||||
|
@ -658,6 +635,9 @@ bool NativeWindowMac::IsKiosk() {
|
|||
return is_kiosk_;
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetBackgroundColor(const std::string& color_name) {
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetRepresentedFilename(const std::string& filename) {
|
||||
[window_ setRepresentedFilename:base::SysUTF8ToNSString(filename)];
|
||||
}
|
||||
|
@ -746,36 +726,6 @@ bool NativeWindowMac::IsVisibleOnAllWorkspaces() {
|
|||
return collectionBehavior & NSWindowCollectionBehaviorCanJoinAllSpaces;
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
|
||||
if (!draggable_region())
|
||||
return false;
|
||||
if (!web_contents())
|
||||
return false;
|
||||
NSView* webView = web_contents()->GetNativeView();
|
||||
NSInteger webViewHeight = NSHeight([webView bounds]);
|
||||
// |draggable_region_| is stored in local platform-indepdent coordiate system
|
||||
// while |point| is in local Cocoa coordinate system. Do the conversion
|
||||
// to match these two.
|
||||
return draggable_region()->contains(point.x, webViewHeight - point.y);
|
||||
}
|
||||
|
||||
void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
|
||||
NSPoint eventLoc = [event locationInWindow];
|
||||
NSRect mouseRect = [window_ convertRectToScreen:NSMakeRect(eventLoc.x, eventLoc.y, 0, 0)];
|
||||
NSPoint current_mouse_location = mouseRect.origin;
|
||||
|
||||
if ([event type] == NSLeftMouseDown) {
|
||||
NSPoint frame_origin = [window_ frame].origin;
|
||||
last_mouse_offset_ = NSMakePoint(
|
||||
frame_origin.x - current_mouse_location.x,
|
||||
frame_origin.y - current_mouse_location.y);
|
||||
} else if ([event type] == NSLeftMouseDragged) {
|
||||
[window_ setFrameOrigin:NSMakePoint(
|
||||
current_mouse_location.x + last_mouse_offset_.x,
|
||||
current_mouse_location.y + last_mouse_offset_.y)];
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
|
@ -800,6 +750,23 @@ void NativeWindowMac::HandleKeyboardEvent(
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<gfx::Rect> NativeWindowMac::CalculateNonDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions, int width, int height) {
|
||||
std::vector<gfx::Rect> result;
|
||||
if (regions.empty()) {
|
||||
result.push_back(gfx::Rect(0, 0, width, height));
|
||||
} else {
|
||||
scoped_ptr<SkRegion> draggable(DraggableRegionsToSkRegion(regions));
|
||||
scoped_ptr<SkRegion> non_draggable(new SkRegion);
|
||||
non_draggable->op(0, 0, width, height, SkRegion::kUnion_Op);
|
||||
non_draggable->op(*draggable, SkRegion::kDifference_Op);
|
||||
for (SkRegion::Iterator it(*non_draggable); !it.done(); it.next()) {
|
||||
result.push_back(gfx::SkIRectToRect(it.rect()));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowMac::ContentSizeToWindowSize(const gfx::Size& size) {
|
||||
if (!has_frame())
|
||||
return size;
|
||||
|
@ -818,6 +785,13 @@ gfx::Size NativeWindowMac::WindowSizeToContentSize(const gfx::Size& size) {
|
|||
return gfx::Size(content.size);
|
||||
}
|
||||
|
||||
void NativeWindowMac::UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
NativeWindow::UpdateDraggableRegions(regions);
|
||||
draggable_regions_ = regions;
|
||||
UpdateDraggableRegionViews(regions);
|
||||
}
|
||||
|
||||
void NativeWindowMac::InstallView() {
|
||||
// Make sure the bottom corner is rounded: http://crbug.com/396264.
|
||||
[[window_ contentView] setWantsLayer:YES];
|
||||
|
@ -840,8 +814,6 @@ void NativeWindowMac::InstallView() {
|
|||
[view setFrame:[content_view_ bounds]];
|
||||
[content_view_ addSubview:view];
|
||||
|
||||
InstallDraggableRegionView();
|
||||
|
||||
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES];
|
||||
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
|
||||
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES];
|
||||
|
@ -858,14 +830,55 @@ void NativeWindowMac::UninstallView() {
|
|||
[view removeFromSuperview];
|
||||
}
|
||||
|
||||
void NativeWindowMac::InstallDraggableRegionView() {
|
||||
void NativeWindowMac::UpdateDraggableRegionViews(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
if (has_frame() && !force_using_draggable_region())
|
||||
return;
|
||||
|
||||
// All ControlRegionViews should be added as children of the WebContentsView,
|
||||
// because WebContentsView will be removed and re-added when entering and
|
||||
// leaving fullscreen mode.
|
||||
NSView* webView = web_contents()->GetNativeView();
|
||||
NSInteger webViewWidth = NSWidth([webView bounds]);
|
||||
NSInteger webViewHeight = NSHeight([webView bounds]);
|
||||
|
||||
[webView setMouseDownCanMoveWindow:YES];
|
||||
|
||||
// Remove all ControlRegionViews that are added last time.
|
||||
// Note that [webView subviews] returns the view's mutable internal array and
|
||||
// it should be copied to avoid mutating the original array while enumerating
|
||||
// it.
|
||||
base::scoped_nsobject<NSArray> subviews([[webView subviews] copy]);
|
||||
for (NSView* subview in subviews.get())
|
||||
if ([subview isKindOfClass:[ControlRegionView class]])
|
||||
[subview removeFromSuperview];
|
||||
|
||||
// Draggable regions is implemented by having the whole web view draggable
|
||||
// (mouseDownCanMoveWindow) and overlaying regions that are not draggable.
|
||||
std::vector<gfx::Rect> system_drag_exclude_areas =
|
||||
CalculateNonDraggableRegions(regions, webViewWidth, webViewHeight);
|
||||
|
||||
// Create and add a ControlRegionView for each region that needs to be
|
||||
// excluded from the dragging.
|
||||
for (std::vector<gfx::Rect>::const_iterator iter =
|
||||
system_drag_exclude_areas.begin();
|
||||
iter != system_drag_exclude_areas.end();
|
||||
++iter) {
|
||||
base::scoped_nsobject<NSView> controlRegion(
|
||||
[[ControlRegionView alloc] initWithShellWindow:this]);
|
||||
[controlRegion setFrame:NSMakeRect(0, 0,
|
||||
NSWidth([webView bounds]),
|
||||
NSHeight([webView bounds]))];
|
||||
[[ControlRegionView alloc] initWithFrame:NSZeroRect]);
|
||||
[controlRegion setFrame:NSMakeRect(iter->x(),
|
||||
webViewHeight - iter->bottom(),
|
||||
iter->width(),
|
||||
iter->height())];
|
||||
[webView addSubview:controlRegion];
|
||||
}
|
||||
|
||||
// AppKit will not update its cache of mouseDownCanMoveWindow unless something
|
||||
// changes. Previously we tried adding an NSView and removing it, but for some
|
||||
// reason it required reposting the mouse-down event, and didn't always work.
|
||||
// Calling the below seems to be an effective solution.
|
||||
[window_ setMovableByWindowBackground:NO];
|
||||
[window_ setMovableByWindowBackground:YES];
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
#include "ui/base/window_open_disposition.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeWindowObserver {
|
||||
|
@ -55,6 +59,11 @@ class NativeWindowObserver {
|
|||
virtual void OnWindowEnterHtmlFullScreen() {}
|
||||
virtual void OnWindowLeaveHtmlFullScreen() {}
|
||||
|
||||
// Called when window message received
|
||||
#if defined(OS_WIN)
|
||||
virtual void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) {}
|
||||
#endif
|
||||
|
||||
// Called when renderer is hung.
|
||||
virtual void OnRendererUnresponsive() {}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#elif defined(OS_WIN)
|
||||
#include "atom/browser/ui/views/win_frame_view.h"
|
||||
#include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h"
|
||||
#include "skia/ext/skia_utils_win.h"
|
||||
#include "ui/base/win/shell.h"
|
||||
#include "ui/gfx/win/dpi.h"
|
||||
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
|
||||
|
@ -77,6 +78,29 @@ bool IsAltModifier(const content::NativeWebKeyboardEvent& event) {
|
|||
(modifiers == (Modifiers::AltKey | Modifiers::IsRight));
|
||||
}
|
||||
|
||||
SkColor ParseHexColor(const std::string& name) {
|
||||
SkColor result = 0xFF000000;
|
||||
unsigned value = 0;
|
||||
auto color = name.substr(1);
|
||||
unsigned length = color.size();
|
||||
if (length != 3 && length != 6)
|
||||
return result;
|
||||
for (unsigned i = 0; i < length; ++i) {
|
||||
if (!base::IsHexDigit(color[i]))
|
||||
return result;
|
||||
value <<= 4;
|
||||
value |= (color[i] < 'A' ? color[i] - '0' : (color[i] - 'A' + 10) & 0xF);
|
||||
}
|
||||
if (length == 6) {
|
||||
result |= value;
|
||||
return result;
|
||||
}
|
||||
result |= (value & 0xF00) << 12 | (value & 0xF00) << 8
|
||||
| (value & 0xF0) << 8 | (value & 0xF0) << 4
|
||||
| (value & 0xF) << 4 | (value & 0xF);
|
||||
return result;
|
||||
}
|
||||
|
||||
class NativeWindowClientView : public views::ClientView {
|
||||
public:
|
||||
NativeWindowClientView(views::Widget* widget,
|
||||
|
@ -205,7 +229,7 @@ NativeWindowViews::NativeWindowViews(
|
|||
|
||||
// Add web view.
|
||||
SetLayoutManager(new MenuLayout(this, kMenuBarHeight));
|
||||
set_background(views::Background::CreateStandardPanelBackground());
|
||||
|
||||
AddChildView(web_view_);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
@ -496,6 +520,21 @@ bool NativeWindowViews::IsKiosk() {
|
|||
return IsFullscreen();
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetBackgroundColor(const std::string& color_name) {
|
||||
// web views' background color.
|
||||
SkColor background_color = ParseHexColor(color_name);
|
||||
set_background(views::Background::CreateSolidBackground(background_color));
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Set the background color of native window.
|
||||
HBRUSH brush = CreateSolidBrush(skia::SkColorToCOLORREF(background_color));
|
||||
ULONG_PTR previous_brush = SetClassLongPtr(
|
||||
GetAcceleratedWidget(), GCLP_HBRBACKGROUND, (LONG)brush);
|
||||
if (previous_brush)
|
||||
DeleteObject((HBRUSH)previous_brush);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
|
||||
if (menu_model == nullptr) {
|
||||
// Remove accelerators
|
||||
|
|
|
@ -77,6 +77,7 @@ class NativeWindowViews : public NativeWindow,
|
|||
void SetSkipTaskbar(bool skip) override;
|
||||
void SetKiosk(bool kiosk) override;
|
||||
bool IsKiosk() override;
|
||||
void SetBackgroundColor(const std::string& color_name) override;
|
||||
void SetMenu(ui::MenuModel* menu_model) override;
|
||||
gfx::NativeWindow GetNativeWindow() override;
|
||||
void SetOverlayIcon(const gfx::Image& overlay,
|
||||
|
|
|
@ -80,6 +80,8 @@ bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
|
|||
|
||||
bool NativeWindowViews::PreHandleMSG(
|
||||
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) {
|
||||
NotifyWindowMessage(message, w_param, l_param);
|
||||
|
||||
switch (message) {
|
||||
case WM_COMMAND:
|
||||
// Handle thumbar button click message.
|
||||
|
|
|
@ -35,17 +35,14 @@ NodeDebugger::NodeDebugger(v8::Isolate* isolate)
|
|||
weak_factory_(this) {
|
||||
bool use_debug_agent = false;
|
||||
int port = 5858;
|
||||
bool wait_for_connection = false;
|
||||
|
||||
std::string port_str;
|
||||
base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
|
||||
if (cmd->HasSwitch("debug")) {
|
||||
use_debug_agent = true;
|
||||
port_str = cmd->GetSwitchValueASCII("debug");
|
||||
}
|
||||
if (cmd->HasSwitch("debug-brk")) {
|
||||
} else if (cmd->HasSwitch("debug-brk")) {
|
||||
use_debug_agent = true;
|
||||
wait_for_connection = true;
|
||||
port_str = cmd->GetSwitchValueASCII("debug-brk");
|
||||
}
|
||||
|
||||
|
@ -56,9 +53,6 @@ NodeDebugger::NodeDebugger(v8::Isolate* isolate)
|
|||
isolate_->SetData(kIsolateSlot, this);
|
||||
v8::Debug::SetMessageHandler(DebugMessageHandler);
|
||||
|
||||
if (wait_for_connection)
|
||||
v8::Debug::DebugBreak(isolate_);
|
||||
|
||||
uv_async_init(uv_default_loop(), &weak_up_ui_handle_, ProcessMessageInUI);
|
||||
|
||||
// Start a new IO thread.
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<key>CFBundleIconFile</key>
|
||||
<string>atom.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.34.0</string>
|
||||
<string>0.34.1</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.34.0</string>
|
||||
<string>0.34.1</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.developer-tools</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
|
|
@ -56,8 +56,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,34,0,0
|
||||
PRODUCTVERSION 0,34,0,0
|
||||
FILEVERSION 0,34,1,0
|
||||
PRODUCTVERSION 0,34,1,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -74,12 +74,12 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "0.34.0"
|
||||
VALUE "FileVersion", "0.34.1"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "0.34.0"
|
||||
VALUE "ProductVersion", "0.34.1"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
|
|
@ -79,8 +79,25 @@ class FileDialog {
|
|||
if (!title.empty())
|
||||
GetPtr()->SetTitle(base::UTF8ToUTF16(title).c_str());
|
||||
|
||||
if (!filterspec.empty())
|
||||
GetPtr()->SetDefaultExtension(filterspec.front().pszSpec);
|
||||
// By default, *.* will be added to the file name if file type is "*.*". In
|
||||
// Electron, we disable it to make a better experience.
|
||||
//
|
||||
// From MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/
|
||||
// bb775970(v=vs.85).aspx
|
||||
//
|
||||
// If SetDefaultExtension is not called, the dialog will not update
|
||||
// automatically when user choose a new file type in the file dialog.
|
||||
//
|
||||
// We set file extension to the first none-wildcard extension to make
|
||||
// sure the dialog will update file extension automatically.
|
||||
for (size_t i = 0; i < filterspec.size(); ++i) {
|
||||
if (std::wstring(filterspec[i].pszSpec) != L"*.*") {
|
||||
// SetFileTypeIndex is regarded as one-based index.
|
||||
GetPtr()->SetFileTypeIndex(i+1);
|
||||
GetPtr()->SetDefaultExtension(filterspec[i].pszSpec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SetDefaultFolder(default_path);
|
||||
}
|
||||
|
@ -255,7 +272,8 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
|||
|
||||
bool matched = false;
|
||||
for (size_t i = 0; i < filter.second.size(); ++i) {
|
||||
if (base::EndsWith(file_name, filter.second[i], false)) {
|
||||
if (filter.second[i] == "*" ||
|
||||
base::EndsWith(file_name, filter.second[i], false)) {
|
||||
matched = true;
|
||||
break;;
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ void TrayIcon::NotifyRightClicked(const gfx::Rect& bounds, int modifiers) {
|
|||
OnRightClicked(bounds, modifiers));
|
||||
}
|
||||
|
||||
void TrayIcon::NotfiyDropFiles(const std::vector<std::string>& files) {
|
||||
void TrayIcon::NotifyDropFiles(const std::vector<std::string>& files) {
|
||||
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDropFiles(files));
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ class TrayIcon {
|
|||
void NotifyBalloonClosed();
|
||||
void NotifyRightClicked(const gfx::Rect& bounds = gfx::Rect(),
|
||||
int modifiers = 0);
|
||||
void NotfiyDropFiles(const std::vector<std::string>& files);
|
||||
void NotifyDropFiles(const std::vector<std::string>& files);
|
||||
|
||||
protected:
|
||||
TrayIcon();
|
||||
|
|
|
@ -265,7 +265,7 @@ const CGFloat kVerticalTitleMargin = 2;
|
|||
NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
|
||||
for (NSString* file in files)
|
||||
dropFiles.push_back(base::SysNSStringToUTF8(file));
|
||||
trayIcon_->NotfiyDropFiles(dropFiles);
|
||||
trayIcon_->NotifyDropFiles(dropFiles);
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
|
|
|
@ -41,7 +41,7 @@ void FatalErrorCallback(const char* location, const char* message) {
|
|||
}
|
||||
|
||||
void Log(const base::string16& message) {
|
||||
std::cout << message;
|
||||
std::cout << message << std::flush;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
module.exports = process.atomBinding 'shell'
|
||||
|
||||
if process.platform is 'win32' and process.type is 'renderer'
|
||||
module.exports.showItemInFolder = require('remote').process.atomBinding('shell').showItemInFolder
|
||||
module.exports.showItemInFolder = (item) ->
|
||||
require('remote').require('shell').showItemInFolder item
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#define ATOM_MAJOR_VERSION 0
|
||||
#define ATOM_MINOR_VERSION 34
|
||||
#define ATOM_PATCH_VERSION 0
|
||||
#define ATOM_PATCH_VERSION 1
|
||||
|
||||
#define ATOM_VERSION_IS_RELEASE 1
|
||||
|
||||
|
|
|
@ -263,7 +263,9 @@ exports.wrapFsWithAsar = (fs) ->
|
|||
|
||||
info = archive.getFileInfo filePath
|
||||
notFoundError asarPath, filePath unless info
|
||||
return new Buffer(0) if info.size is 0
|
||||
|
||||
if info.size is 0
|
||||
return if options then '' else new Buffer(0)
|
||||
|
||||
if info.unpacked
|
||||
realPath = archive.copyFileOut filePath
|
||||
|
|
|
@ -70,10 +70,13 @@ struct V8FunctionInvoker<ReturnType(ArgTypes...)> {
|
|||
v8::Local<v8::Function> holder = function->NewHandle();
|
||||
v8::Local<v8::Context> context = holder->CreationContext();
|
||||
v8::Context::Scope context_scope(context);
|
||||
ReturnType ret;
|
||||
ReturnType ret = ReturnType();
|
||||
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
|
||||
v8::Local<v8::Value> val(holder->Call(holder, args.size(), &args.front()));
|
||||
Converter<ReturnType>::FromV8(isolate, val, &ret);
|
||||
v8::Local<v8::Value> result;
|
||||
auto maybe_result =
|
||||
holder->Call(context, holder, args.size(), &args.front());
|
||||
if (maybe_result.ToLocal(&result))
|
||||
Converter<ReturnType>::FromV8(isolate, result, &ret);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -93,6 +93,9 @@ const char kDisableAutoHideCursor[] = "disable-auto-hide-cursor";
|
|||
// Use the OS X's standard window instead of the textured window.
|
||||
const char kStandardWindow[] = "standard-window";
|
||||
|
||||
// Default browser window background color.
|
||||
const char kBackgroundColor[] = "background-color";
|
||||
|
||||
// Path to client certificate.
|
||||
const char kClientCertificate[] = "client-certificate";
|
||||
|
||||
|
@ -116,6 +119,9 @@ const char kRegisterStandardSchemes[] = "register-standard-schemes";
|
|||
// TLS fallback will accept.
|
||||
const char kSSLVersionFallbackMin[] = "ssl-version-fallback-min";
|
||||
|
||||
// Comma-separated list of SSL cipher suites to disable.
|
||||
const char kCipherSuiteBlacklist[] = "cipher-suite-blacklist";
|
||||
|
||||
// The browser process app model ID
|
||||
const char kAppUserModelId[] = "app-user-model-id";
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ extern const char kTransparent[];
|
|||
extern const char kType[];
|
||||
extern const char kDisableAutoHideCursor[];
|
||||
extern const char kStandardWindow[];
|
||||
extern const char kBackgroundColor[];
|
||||
extern const char kClientCertificate[];
|
||||
|
||||
extern const char kExperimentalFeatures[];
|
||||
|
@ -59,6 +60,7 @@ extern const char kPageVisibility[];
|
|||
extern const char kDisableHttpCache[];
|
||||
extern const char kRegisterStandardSchemes[];
|
||||
extern const char kSSLVersionFallbackMin[];
|
||||
extern const char kCipherSuiteBlacklist[];
|
||||
|
||||
extern const char kAppUserModelId[];
|
||||
|
||||
|
|
|
@ -46,7 +46,9 @@ metaToValue = (meta) ->
|
|||
when 'array' then (metaToValue(el) for el in meta.members)
|
||||
when 'buffer' then new Buffer(meta.value)
|
||||
when 'promise' then Promise.resolve(then: metaToValue(meta.then))
|
||||
when 'error'
|
||||
when 'error' then new Error(meta.message)
|
||||
when 'date' then new Date(meta.value)
|
||||
when 'exception'
|
||||
throw new Error("#{meta.message}\n#{meta.stack}")
|
||||
else
|
||||
if meta.type is 'function'
|
||||
|
|
86
chromium_src/chrome/browser/chrome_process_finder_win.cc
Normal file
86
chromium_src/chrome/browser/chrome_process_finder_win.cc
Normal file
|
@ -0,0 +1,86 @@
|
|||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/chrome_process_finder_win.h"
|
||||
|
||||
#include <shellapi.h>
|
||||
#include <string>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/process/process.h"
|
||||
#include "base/process/process_info.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/win/message_window.h"
|
||||
#include "base/win/scoped_handle.h"
|
||||
#include "base/win/win_util.h"
|
||||
#include "base/win/windows_version.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
int timeout_in_milliseconds = 20 * 1000;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace chrome {
|
||||
|
||||
HWND FindRunningChromeWindow(const base::FilePath& user_data_dir) {
|
||||
return base::win::MessageWindow::FindWindow(user_data_dir.value());
|
||||
}
|
||||
|
||||
NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window,
|
||||
bool fast_start) {
|
||||
DCHECK(remote_window);
|
||||
DWORD process_id = 0;
|
||||
DWORD thread_id = GetWindowThreadProcessId(remote_window, &process_id);
|
||||
if (!thread_id || !process_id)
|
||||
return NOTIFY_FAILED;
|
||||
|
||||
// Send the command line to the remote chrome window.
|
||||
// Format is "START\0<<<current directory>>>\0<<<commandline>>>".
|
||||
std::wstring to_send(L"START\0", 6); // want the NULL in the string.
|
||||
base::FilePath cur_dir;
|
||||
if (!base::GetCurrentDirectory(&cur_dir))
|
||||
return NOTIFY_FAILED;
|
||||
to_send.append(cur_dir.value());
|
||||
to_send.append(L"\0", 1); // Null separator.
|
||||
to_send.append(::GetCommandLineW());
|
||||
to_send.append(L"\0", 1); // Null separator.
|
||||
|
||||
// Allow the current running browser window to make itself the foreground
|
||||
// window (otherwise it will just flash in the taskbar).
|
||||
::AllowSetForegroundWindow(process_id);
|
||||
|
||||
COPYDATASTRUCT cds;
|
||||
cds.dwData = 0;
|
||||
cds.cbData = static_cast<DWORD>((to_send.length() + 1) * sizeof(wchar_t));
|
||||
cds.lpData = const_cast<wchar_t*>(to_send.c_str());
|
||||
DWORD_PTR result = 0;
|
||||
if (::SendMessageTimeout(remote_window, WM_COPYDATA, NULL,
|
||||
reinterpret_cast<LPARAM>(&cds), SMTO_ABORTIFHUNG,
|
||||
timeout_in_milliseconds, &result)) {
|
||||
return result ? NOTIFY_SUCCESS : NOTIFY_FAILED;
|
||||
}
|
||||
|
||||
// It is possible that the process owning this window may have died by now.
|
||||
if (!::IsWindow(remote_window))
|
||||
return NOTIFY_FAILED;
|
||||
|
||||
// If the window couldn't be notified but still exists, assume it is hung.
|
||||
return NOTIFY_WINDOW_HUNG;
|
||||
}
|
||||
|
||||
base::TimeDelta SetNotificationTimeoutForTesting(base::TimeDelta new_timeout) {
|
||||
base::TimeDelta old_timeout =
|
||||
base::TimeDelta::FromMilliseconds(timeout_in_milliseconds);
|
||||
timeout_in_milliseconds = new_timeout.InMilliseconds();
|
||||
return old_timeout;
|
||||
}
|
||||
|
||||
} // namespace chrome
|
39
chromium_src/chrome/browser/chrome_process_finder_win.h
Normal file
39
chromium_src/chrome/browser/chrome_process_finder_win.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_CHROME_PROCESS_FINDER_WIN_H_
|
||||
#define CHROME_BROWSER_CHROME_PROCESS_FINDER_WIN_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "base/time/time.h"
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
namespace chrome {
|
||||
|
||||
enum NotifyChromeResult {
|
||||
NOTIFY_SUCCESS,
|
||||
NOTIFY_FAILED,
|
||||
NOTIFY_WINDOW_HUNG,
|
||||
};
|
||||
|
||||
// Finds an already running Chrome window if it exists.
|
||||
HWND FindRunningChromeWindow(const base::FilePath& user_data_dir);
|
||||
|
||||
// Attempts to send the current command line to an already running instance of
|
||||
// Chrome via a WM_COPYDATA message.
|
||||
// Returns true if a running Chrome is found and successfully notified.
|
||||
// |fast_start| is true when this is being called on the window fast start path.
|
||||
NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window,
|
||||
bool fast_start);
|
||||
|
||||
// Changes the notification timeout to |new_timeout|, returns the old timeout.
|
||||
base::TimeDelta SetNotificationTimeoutForTesting(base::TimeDelta new_timeout);
|
||||
|
||||
} // namespace chrome
|
||||
|
||||
#endif // CHROME_BROWSER_CHROME_PROCESS_FINDER_WIN_H_
|
182
chromium_src/chrome/browser/process_singleton.h
Normal file
182
chromium_src/chrome/browser/process_singleton.h
Normal file
|
@ -0,0 +1,182 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_PROCESS_SINGLETON_H_
|
||||
#define CHROME_BROWSER_PROCESS_SINGLETON_H_
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/process/process.h"
|
||||
#include "base/threading/non_thread_safe.h"
|
||||
#include "ui/gfx/native_widget_types.h"
|
||||
|
||||
#if defined(OS_POSIX) && !defined(OS_ANDROID)
|
||||
#include "base/files/scoped_temp_dir.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/win/message_window.h"
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
namespace base {
|
||||
class CommandLine;
|
||||
}
|
||||
|
||||
// ProcessSingleton ----------------------------------------------------------
|
||||
//
|
||||
// This class allows different browser processes to communicate with
|
||||
// each other. It is named according to the user data directory, so
|
||||
// we can be sure that no more than one copy of the application can be
|
||||
// running at once with a given data directory.
|
||||
//
|
||||
// Implementation notes:
|
||||
// - the Windows implementation uses an invisible global message window;
|
||||
// - the Linux implementation uses a Unix domain socket in the user data dir.
|
||||
|
||||
class ProcessSingleton : public base::NonThreadSafe {
|
||||
public:
|
||||
enum NotifyResult {
|
||||
PROCESS_NONE,
|
||||
PROCESS_NOTIFIED,
|
||||
PROFILE_IN_USE,
|
||||
LOCK_ERROR,
|
||||
};
|
||||
|
||||
// Implement this callback to handle notifications from other processes. The
|
||||
// callback will receive the command line and directory with which the other
|
||||
// Chrome process was launched. Return true if the command line will be
|
||||
// handled within the current browser instance or false if the remote process
|
||||
// should handle it (i.e., because the current process is shutting down).
|
||||
using NotificationCallback =
|
||||
base::Callback<bool(const base::CommandLine::StringVector& command_line,
|
||||
const base::FilePath& current_directory)>;
|
||||
|
||||
ProcessSingleton(const base::FilePath& user_data_dir,
|
||||
const NotificationCallback& notification_callback);
|
||||
~ProcessSingleton();
|
||||
|
||||
// Notify another process, if available. Otherwise sets ourselves as the
|
||||
// singleton instance. Returns PROCESS_NONE if we became the singleton
|
||||
// instance. Callers are guaranteed to either have notified an existing
|
||||
// process or have grabbed the singleton (unless the profile is locked by an
|
||||
// unreachable process).
|
||||
// TODO(brettw): Make the implementation of this method non-platform-specific
|
||||
// by making Linux re-use the Windows implementation.
|
||||
NotifyResult NotifyOtherProcessOrCreate();
|
||||
|
||||
// Sets ourself up as the singleton instance. Returns true on success. If
|
||||
// false is returned, we are not the singleton instance and the caller must
|
||||
// exit.
|
||||
// NOTE: Most callers should generally prefer NotifyOtherProcessOrCreate() to
|
||||
// this method, only callers for whom failure is preferred to notifying
|
||||
// another process should call this directly.
|
||||
bool Create();
|
||||
|
||||
// Clear any lock state during shutdown.
|
||||
void Cleanup();
|
||||
|
||||
#if defined(OS_POSIX) && !defined(OS_ANDROID)
|
||||
static void DisablePromptForTesting();
|
||||
#endif
|
||||
#if defined(OS_WIN)
|
||||
// Called to query whether to kill a hung browser process that has visible
|
||||
// windows. Return true to allow killing the hung process.
|
||||
using ShouldKillRemoteProcessCallback = base::Callback<bool()>;
|
||||
void OverrideShouldKillRemoteProcessCallbackForTesting(
|
||||
const ShouldKillRemoteProcessCallback& display_dialog_callback);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Notify another process, if available.
|
||||
// Returns true if another process was found and notified, false if we should
|
||||
// continue with the current process.
|
||||
// On Windows, Create() has to be called before this.
|
||||
NotifyResult NotifyOtherProcess();
|
||||
|
||||
#if defined(OS_POSIX) && !defined(OS_ANDROID)
|
||||
// Exposed for testing. We use a timeout on Linux, and in tests we want
|
||||
// this timeout to be short.
|
||||
NotifyResult NotifyOtherProcessWithTimeout(
|
||||
const base::CommandLine& command_line,
|
||||
int retry_attempts,
|
||||
const base::TimeDelta& timeout,
|
||||
bool kill_unresponsive);
|
||||
NotifyResult NotifyOtherProcessWithTimeoutOrCreate(
|
||||
const base::CommandLine& command_line,
|
||||
int retry_attempts,
|
||||
const base::TimeDelta& timeout);
|
||||
void OverrideCurrentPidForTesting(base::ProcessId pid);
|
||||
void OverrideKillCallbackForTesting(
|
||||
const base::Callback<void(int)>& callback);
|
||||
#endif
|
||||
|
||||
private:
|
||||
NotificationCallback notification_callback_; // Handler for notifications.
|
||||
|
||||
#if defined(OS_WIN)
|
||||
HWND remote_window_; // The HWND_MESSAGE of another browser.
|
||||
base::win::MessageWindow window_; // The message-only window.
|
||||
bool is_virtualized_; // Stuck inside Microsoft Softricity VM environment.
|
||||
HANDLE lock_file_;
|
||||
base::FilePath user_data_dir_;
|
||||
ShouldKillRemoteProcessCallback should_kill_remote_process_callback_;
|
||||
#elif defined(OS_POSIX) && !defined(OS_ANDROID)
|
||||
// Start listening to the socket.
|
||||
void StartListening(int sock);
|
||||
|
||||
// Return true if the given pid is one of our child processes.
|
||||
// Assumes that the current pid is the root of all pids of the current
|
||||
// instance.
|
||||
bool IsSameChromeInstance(pid_t pid);
|
||||
|
||||
// Extract the process's pid from a symbol link path and if it is on
|
||||
// the same host, kill the process, unlink the lock file and return true.
|
||||
// If the process is part of the same chrome instance, unlink the lock file
|
||||
// and return true without killing it.
|
||||
// If the process is on a different host, return false.
|
||||
bool KillProcessByLockPath();
|
||||
|
||||
// Default function to kill a process, overridable by tests.
|
||||
void KillProcess(int pid);
|
||||
|
||||
// Allow overriding for tests.
|
||||
base::ProcessId current_pid_;
|
||||
|
||||
// Function to call when the other process is hung and needs to be killed.
|
||||
// Allows overriding for tests.
|
||||
base::Callback<void(int)> kill_callback_;
|
||||
|
||||
// Path in file system to the socket.
|
||||
base::FilePath socket_path_;
|
||||
|
||||
// Path in file system to the lock.
|
||||
base::FilePath lock_path_;
|
||||
|
||||
// Path in file system to the cookie file.
|
||||
base::FilePath cookie_path_;
|
||||
|
||||
// Temporary directory to hold the socket.
|
||||
base::ScopedTempDir socket_dir_;
|
||||
|
||||
// Helper class for linux specific messages. LinuxWatcher is ref counted
|
||||
// because it posts messages between threads.
|
||||
class LinuxWatcher;
|
||||
scoped_refptr<LinuxWatcher> watcher_;
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ProcessSingleton);
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_PROCESS_SINGLETON_H_
|
1061
chromium_src/chrome/browser/process_singleton_posix.cc
Normal file
1061
chromium_src/chrome/browser/process_singleton_posix.cc
Normal file
File diff suppressed because it is too large
Load diff
328
chromium_src/chrome/browser/process_singleton_win.cc
Normal file
328
chromium_src/chrome/browser/process_singleton_win.cc
Normal file
|
@ -0,0 +1,328 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/process_singleton.h"
|
||||
|
||||
#include <shellapi.h>
|
||||
|
||||
#include "base/base_paths.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/process/process.h"
|
||||
#include "base/process/process_info.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/win/metro.h"
|
||||
#include "base/win/registry.h"
|
||||
#include "base/win/scoped_handle.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "chrome/browser/chrome_process_finder_win.h"
|
||||
#include "content/public/common/result_codes.h"
|
||||
#include "net/base/escape.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/gfx/win/hwnd_util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const char kLockfile[] = "lockfile";
|
||||
|
||||
// A helper class that acquires the given |mutex| while the AutoLockMutex is in
|
||||
// scope.
|
||||
class AutoLockMutex {
|
||||
public:
|
||||
explicit AutoLockMutex(HANDLE mutex) : mutex_(mutex) {
|
||||
DWORD result = ::WaitForSingleObject(mutex_, INFINITE);
|
||||
DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result;
|
||||
}
|
||||
|
||||
~AutoLockMutex() {
|
||||
BOOL released = ::ReleaseMutex(mutex_);
|
||||
DPCHECK(released);
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE mutex_;
|
||||
DISALLOW_COPY_AND_ASSIGN(AutoLockMutex);
|
||||
};
|
||||
|
||||
// A helper class that releases the given |mutex| while the AutoUnlockMutex is
|
||||
// in scope and immediately re-acquires it when going out of scope.
|
||||
class AutoUnlockMutex {
|
||||
public:
|
||||
explicit AutoUnlockMutex(HANDLE mutex) : mutex_(mutex) {
|
||||
BOOL released = ::ReleaseMutex(mutex_);
|
||||
DPCHECK(released);
|
||||
}
|
||||
|
||||
~AutoUnlockMutex() {
|
||||
DWORD result = ::WaitForSingleObject(mutex_, INFINITE);
|
||||
DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result;
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE mutex_;
|
||||
DISALLOW_COPY_AND_ASSIGN(AutoUnlockMutex);
|
||||
};
|
||||
|
||||
// Checks the visibility of the enumerated window and signals once a visible
|
||||
// window has been found.
|
||||
BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) {
|
||||
bool* result = reinterpret_cast<bool*>(param);
|
||||
*result = ::IsWindowVisible(window) != 0;
|
||||
// Stops enumeration if a visible window has been found.
|
||||
return !*result;
|
||||
}
|
||||
|
||||
// Convert Command line string to argv.
|
||||
base::CommandLine::StringVector CommandLineStringToArgv(
|
||||
const std::wstring& command_line_string) {
|
||||
int num_args = 0;
|
||||
wchar_t** args = NULL;
|
||||
args = ::CommandLineToArgvW(command_line_string.c_str(), &num_args);
|
||||
base::CommandLine::StringVector argv;
|
||||
for (int i = 0; i < num_args; ++i)
|
||||
argv.push_back(std::wstring(args[i]));
|
||||
LocalFree(args);
|
||||
return argv;
|
||||
}
|
||||
|
||||
bool ParseCommandLine(const COPYDATASTRUCT* cds,
|
||||
base::CommandLine::StringVector* parsed_command_line,
|
||||
base::FilePath* current_directory) {
|
||||
// We should have enough room for the shortest command (min_message_size)
|
||||
// and also be a multiple of wchar_t bytes. The shortest command
|
||||
// possible is L"START\0\0" (empty current directory and command line).
|
||||
static const int min_message_size = 7;
|
||||
if (cds->cbData < min_message_size * sizeof(wchar_t) ||
|
||||
cds->cbData % sizeof(wchar_t) != 0) {
|
||||
LOG(WARNING) << "Invalid WM_COPYDATA, length = " << cds->cbData;
|
||||
return false;
|
||||
}
|
||||
|
||||
// We split the string into 4 parts on NULLs.
|
||||
DCHECK(cds->lpData);
|
||||
const std::wstring msg(static_cast<wchar_t*>(cds->lpData),
|
||||
cds->cbData / sizeof(wchar_t));
|
||||
const std::wstring::size_type first_null = msg.find_first_of(L'\0');
|
||||
if (first_null == 0 || first_null == std::wstring::npos) {
|
||||
// no NULL byte, don't know what to do
|
||||
LOG(WARNING) << "Invalid WM_COPYDATA, length = " << msg.length() <<
|
||||
", first null = " << first_null;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decode the command, which is everything until the first NULL.
|
||||
if (msg.substr(0, first_null) == L"START") {
|
||||
// Another instance is starting parse the command line & do what it would
|
||||
// have done.
|
||||
VLOG(1) << "Handling STARTUP request from another process";
|
||||
const std::wstring::size_type second_null =
|
||||
msg.find_first_of(L'\0', first_null + 1);
|
||||
if (second_null == std::wstring::npos ||
|
||||
first_null == msg.length() - 1 || second_null == msg.length()) {
|
||||
LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
|
||||
"parts separated by NULLs";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get current directory.
|
||||
*current_directory = base::FilePath(msg.substr(first_null + 1,
|
||||
second_null - first_null));
|
||||
|
||||
const std::wstring::size_type third_null =
|
||||
msg.find_first_of(L'\0', second_null + 1);
|
||||
if (third_null == std::wstring::npos ||
|
||||
third_null == msg.length()) {
|
||||
LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
|
||||
"parts separated by NULLs";
|
||||
}
|
||||
|
||||
// Get command line.
|
||||
const std::wstring cmd_line =
|
||||
msg.substr(second_null + 1, third_null - second_null);
|
||||
*parsed_command_line = CommandLineStringToArgv(cmd_line);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProcessLaunchNotification(
|
||||
const ProcessSingleton::NotificationCallback& notification_callback,
|
||||
UINT message,
|
||||
WPARAM wparam,
|
||||
LPARAM lparam,
|
||||
LRESULT* result) {
|
||||
if (message != WM_COPYDATA)
|
||||
return false;
|
||||
|
||||
// Handle the WM_COPYDATA message from another process.
|
||||
const COPYDATASTRUCT* cds = reinterpret_cast<COPYDATASTRUCT*>(lparam);
|
||||
|
||||
base::CommandLine::StringVector parsed_command_line;
|
||||
base::FilePath current_directory;
|
||||
if (!ParseCommandLine(cds, &parsed_command_line, ¤t_directory)) {
|
||||
*result = TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
*result = notification_callback.Run(parsed_command_line, current_directory) ?
|
||||
TRUE : FALSE;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TerminateAppWithError() {
|
||||
// TODO: This is called when the secondary process can't ping the primary
|
||||
// process. Need to find out what to do here.
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ProcessSingleton::ProcessSingleton(
|
||||
const base::FilePath& user_data_dir,
|
||||
const NotificationCallback& notification_callback)
|
||||
: notification_callback_(notification_callback),
|
||||
is_virtualized_(false),
|
||||
lock_file_(INVALID_HANDLE_VALUE),
|
||||
user_data_dir_(user_data_dir),
|
||||
should_kill_remote_process_callback_(
|
||||
base::Bind(&TerminateAppWithError)) {
|
||||
}
|
||||
|
||||
ProcessSingleton::~ProcessSingleton() {
|
||||
if (lock_file_ != INVALID_HANDLE_VALUE)
|
||||
::CloseHandle(lock_file_);
|
||||
}
|
||||
|
||||
// Code roughly based on Mozilla.
|
||||
ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
|
||||
if (is_virtualized_)
|
||||
return PROCESS_NOTIFIED; // We already spawned the process in this case.
|
||||
if (lock_file_ == INVALID_HANDLE_VALUE && !remote_window_) {
|
||||
return LOCK_ERROR;
|
||||
} else if (!remote_window_) {
|
||||
return PROCESS_NONE;
|
||||
}
|
||||
|
||||
switch (chrome::AttemptToNotifyRunningChrome(remote_window_, false)) {
|
||||
case chrome::NOTIFY_SUCCESS:
|
||||
return PROCESS_NOTIFIED;
|
||||
case chrome::NOTIFY_FAILED:
|
||||
remote_window_ = NULL;
|
||||
return PROCESS_NONE;
|
||||
case chrome::NOTIFY_WINDOW_HUNG:
|
||||
// Fall through and potentially terminate the hung browser.
|
||||
break;
|
||||
}
|
||||
|
||||
DWORD process_id = 0;
|
||||
DWORD thread_id = ::GetWindowThreadProcessId(remote_window_, &process_id);
|
||||
if (!thread_id || !process_id) {
|
||||
remote_window_ = NULL;
|
||||
return PROCESS_NONE;
|
||||
}
|
||||
base::Process process = base::Process::Open(process_id);
|
||||
|
||||
// The window is hung. Scan for every window to find a visible one.
|
||||
bool visible_window = false;
|
||||
::EnumThreadWindows(thread_id,
|
||||
&BrowserWindowEnumeration,
|
||||
reinterpret_cast<LPARAM>(&visible_window));
|
||||
|
||||
// If there is a visible browser window, ask the user before killing it.
|
||||
if (visible_window && !should_kill_remote_process_callback_.Run()) {
|
||||
// The user denied. Quit silently.
|
||||
return PROCESS_NOTIFIED;
|
||||
}
|
||||
|
||||
// Time to take action. Kill the browser process.
|
||||
process.Terminate(content::RESULT_CODE_HUNG, true);
|
||||
remote_window_ = NULL;
|
||||
return PROCESS_NONE;
|
||||
}
|
||||
|
||||
ProcessSingleton::NotifyResult
|
||||
ProcessSingleton::NotifyOtherProcessOrCreate() {
|
||||
ProcessSingleton::NotifyResult result = PROCESS_NONE;
|
||||
if (!Create()) {
|
||||
result = NotifyOtherProcess();
|
||||
if (result == PROCESS_NONE)
|
||||
result = PROFILE_IN_USE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Look for a Chrome instance that uses the same profile directory. If there
|
||||
// isn't one, create a message window with its title set to the profile
|
||||
// directory path.
|
||||
bool ProcessSingleton::Create() {
|
||||
static const wchar_t kMutexName[] = L"Local\\AtomProcessSingletonStartup!";
|
||||
|
||||
remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
|
||||
if (!remote_window_) {
|
||||
// Make sure we will be the one and only process creating the window.
|
||||
// We use a named Mutex since we are protecting against multi-process
|
||||
// access. As documented, it's clearer to NOT request ownership on creation
|
||||
// since it isn't guaranteed we will get it. It is better to create it
|
||||
// without ownership and explicitly get the ownership afterward.
|
||||
base::win::ScopedHandle only_me(::CreateMutex(NULL, FALSE, kMutexName));
|
||||
if (!only_me.IsValid()) {
|
||||
DPLOG(FATAL) << "CreateMutex failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoLockMutex auto_lock_only_me(only_me.Get());
|
||||
|
||||
// We now own the mutex so we are the only process that can create the
|
||||
// window at this time, but we must still check if someone created it
|
||||
// between the time where we looked for it above and the time the mutex
|
||||
// was given to us.
|
||||
remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
|
||||
if (!remote_window_) {
|
||||
// We have to make sure there is no Chrome instance running on another
|
||||
// machine that uses the same profile.
|
||||
base::FilePath lock_file_path = user_data_dir_.AppendASCII(kLockfile);
|
||||
lock_file_ = ::CreateFile(lock_file_path.value().c_str(),
|
||||
GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL |
|
||||
FILE_FLAG_DELETE_ON_CLOSE,
|
||||
NULL);
|
||||
DWORD error = ::GetLastError();
|
||||
LOG_IF(WARNING, lock_file_ != INVALID_HANDLE_VALUE &&
|
||||
error == ERROR_ALREADY_EXISTS) << "Lock file exists but is writable.";
|
||||
LOG_IF(ERROR, lock_file_ == INVALID_HANDLE_VALUE)
|
||||
<< "Lock file can not be created! Error code: " << error;
|
||||
|
||||
if (lock_file_ != INVALID_HANDLE_VALUE) {
|
||||
// Set the window's title to the path of our user data directory so
|
||||
// other Chrome instances can decide if they should forward to us.
|
||||
bool result = window_.CreateNamed(
|
||||
base::Bind(&ProcessLaunchNotification, notification_callback_),
|
||||
user_data_dir_.value());
|
||||
|
||||
// NB: Ensure that if the primary app gets started as elevated
|
||||
// admin inadvertently, secondary windows running not as elevated
|
||||
// will still be able to send messages
|
||||
::ChangeWindowMessageFilterEx(window_.hwnd(), WM_COPYDATA, MSGFLT_ALLOW, NULL);
|
||||
CHECK(result && window_.hwnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return window_.hwnd() != NULL;
|
||||
}
|
||||
|
||||
void ProcessSingleton::Cleanup() {
|
||||
}
|
||||
|
||||
void ProcessSingleton::OverrideShouldKillRemoteProcessCallbackForTesting(
|
||||
const ShouldKillRemoteProcessCallback& display_dialog_callback) {
|
||||
should_kill_remote_process_callback_ = display_dialog_callback;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
## Guías
|
||||
|
||||
* [Platfaformas Soportadas](tutorial/supported-platforms.md)
|
||||
* [Distribución de la Aplicacion](tutorial/application-distribution.md)
|
||||
* [Empaquetamiento de la Aplicacion](tutorial/application-packaging.md)
|
||||
* [Plataformas Soportadas](tutorial/supported-platforms.md)
|
||||
* [Distribución de la Aplicación](tutorial/application-distribution.md)
|
||||
* [Empaquetamiento de la Aplicación](tutorial/application-packaging.md)
|
||||
* [Utilizando Módulos Node Nativos](tutorial/using-native-node-modules.md)
|
||||
* [Depurando el Proceso Principal](tutorial/debugging-main-process.md)
|
||||
* [Utilizando Selenium y WebDriver](tutorial/using-selenium-and-webdriver.md)
|
||||
|
@ -62,7 +62,7 @@
|
|||
## Desarrollo
|
||||
|
||||
* [Guía de Estilo](development/coding-style.md)
|
||||
* [Estructura de los directorios del Código Fuente](../../development/source-code-directory-structure.md)
|
||||
* [Estructura de los directorios del Código Fuente](development/source-code-directory-structure.md)
|
||||
* [Diferencias Técnicas con NW.js (anteriormente conocido como node-webkit)](../../development/atom-shell-vs-node-webkit.md)
|
||||
* [Repaso del Sistema de Compilación](../../development/build-system-overview.md)
|
||||
* [Instrucciones de Compilación (Mac)](../../development/build-instructions-osx.md)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Esta página lista las líneas de comandos usadas por el navegador Chrome que también son
|
||||
soportadas por Electron. Puedes usar [app.commandLine.appendSwitch][append-switch] para
|
||||
anexarlas en el script principal de tu aplicación antes de que el evento [ready][ready] del
|
||||
modulo [app][app] sea emitido:
|
||||
módulo [app][app] sea emitido:
|
||||
|
||||
```javascript
|
||||
var app = require('app');
|
||||
|
@ -25,7 +25,7 @@ Ignora el límite de conexiones para la lista de `domains` separados por `,`.
|
|||
|
||||
## --disable-http-cache
|
||||
|
||||
Deshabilita la cacheé del disco para las peticiones HTTP.
|
||||
Deshabilita la caché del disco para las peticiones HTTP.
|
||||
|
||||
## --remote-debugging-port=`port`
|
||||
|
||||
|
@ -97,11 +97,11 @@ el repliegue de TLC aceptará.
|
|||
Imprime el registro de Chromium en consola.
|
||||
|
||||
Este cambio no puede ser usado en `app.commandLine.appendSwitch` ya que se analiza antes de que la
|
||||
aplicación del usuario este cargada.
|
||||
aplicación del usuario esté cargada.
|
||||
|
||||
## --v=`log_level`
|
||||
|
||||
Da el maximo nivel activo de V-logging por defecto; 0 es el predeterminado. Valores positivos
|
||||
Da el máximo nivel activo de V-logging por defecto; 0 es el predeterminado. Valores positivos
|
||||
son normalmente usados para los niveles de V-logging.
|
||||
|
||||
Este modificador sólo funciona cuando también se pasa `--enable-logging`.
|
||||
|
@ -109,10 +109,10 @@ Este modificador sólo funciona cuando también se pasa `--enable-logging`.
|
|||
## --vmodule=`pattern`
|
||||
|
||||
Da los niveles máximos de V-logging por módulo para sobreescribir el valor dado por
|
||||
`--v`. Ej. `my_module=2,foo*=3` cambiaria el nivel de registro para todo el código
|
||||
el archivos de origen `my_module.*` y `foo*.*`.
|
||||
`--v`. Ej. `my_module=2,foo*=3` cambiaría el nivel de registro para todo el código,
|
||||
los archivos de origen `my_module.*` y `foo*.*`.
|
||||
|
||||
Cualquier patron que contiene un slash o un slash invertido será probado contra toda la ruta
|
||||
Cualquier patrón que contiene un slash o un slash invertido será probado contra toda la ruta
|
||||
y no sólo con el módulo. Ej. `*/foo/bar/*=2` cambiaría el nivel de registro para todo el código
|
||||
en los archivos origen bajo un directorio `foo/bar`.
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ disponibles en Electron y módulos de terceros son támbien totalmente compatibl
|
|||
|
||||
Electron también provee algunos módulos integrados adicionales para desarrollar
|
||||
aplicaciones nativas de escritorio. Algunos módulos sólo se encuentran disponibles
|
||||
en el proceso principal, algunos sólo en el proceso renderer (pagina web), y
|
||||
en el proceso principal, algunos sólo en el proceso renderer (página web), y
|
||||
algunos pueden ser usados en ambos procesos.
|
||||
|
||||
La regla básica es: Si un módulo es
|
||||
|
|
37
docs-translations/es/development/coding-style.md
Normal file
37
docs-translations/es/development/coding-style.md
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Guía de estilo de código
|
||||
|
||||
Esta es la guía de estilo de código para Electron.
|
||||
|
||||
## C++ y Python
|
||||
|
||||
Para C++ y Python, nosotros seguimos la [guía de estilo](http://www.chromium.org/developers/coding-style) de Chromium.
|
||||
Además hay un script `script/cpplint.py` para verificar si todos los archivos
|
||||
siguen el estilo.
|
||||
|
||||
La versión de Python que estamos usando ahora es Python 2.7.
|
||||
|
||||
El código C++ usa muchas abstracciones y tipos de Chromium, por eso
|
||||
se recomienda familiarizarse con ellos. Un buen lugar para iniciar es
|
||||
el documento de Chromium sobre [Abstracciones importantes y estructras de datos](https://www.chromium.org/developers/coding-style/important-abstractions-and-data-structures). El documento menciona algunos tipos especiales, tipos por alcance (que
|
||||
automaticamente liberan su memoria cuando salen de su alcance), mecanismos de
|
||||
registro de eventos, etcétera.
|
||||
|
||||
## CoffeeScript
|
||||
|
||||
Para CoffeeScript, nosotros seguimos la [guía de estilo](https://github.com/styleguide/javascript) de Github y también las
|
||||
siguientes reglas:
|
||||
|
||||
* Los archivos **NO** deberían terminar con una nueva línea, por que se busca
|
||||
seguir los estilos que usa Google.
|
||||
* Los nombres de los archivos debén estar concatenados con `-` en vez de `_`,
|
||||
por ejemplo `nombre-de-archivo.coffee` en vez de `nombre_de_archivo.coffee`,
|
||||
esto es por que en [github/atom](https://github.com/github/atom)
|
||||
los nombres de los módulos usualmente estan en la forma `nombre-de-modulo`.
|
||||
Esta regla aplica únicamente a los archivos `.coffee`.
|
||||
|
||||
## Nombres de las API
|
||||
|
||||
Al crear una nueva API, nosotros deberíamos preferir usar metodos `get` y `set`
|
||||
en vez de usar el estilo de jQuery que utiliza una sola función. Por ejemplo,
|
||||
se prefiere `.getText()` y `.setText()` por sobre `.text([text])`. Hay una
|
||||
[discusión](https://github.com/atom/electron/issues/46) sobre esto.
|
|
@ -0,0 +1,62 @@
|
|||
# Estructura de los directorios del código fuente
|
||||
|
||||
El código fuente de electron es separado en pocas partes, en su mayoría
|
||||
siguiendo las especificaciones para separar archivos que usa Chromium.
|
||||
|
||||
Quizá necesites familiarizarte con la [arquitectura multiprocesos](http://dev.chromium.org/developers/design-documents/multi-process-architecture) de Chromium para comprender mejor el código fuente.
|
||||
|
||||
## Estructura del código fuente
|
||||
|
||||
```
|
||||
Electron
|
||||
├──atom - Código fuente de Electron.
|
||||
| ├── app - Código de arranque.
|
||||
| ├── browser - La interfaz incluyendo la ventana principal, UI,
|
||||
| | y todas las cosas del proceso principal. Este le habla al renderizador
|
||||
| | para manejar las páginas web.
|
||||
| | ├── lib - Código Javascript para inicializar el proceso principal.
|
||||
| | ├── ui - Implementaciones de UI para distintas plataformas.
|
||||
| | | ├── cocoa - Código fuente específico para Cocoa.
|
||||
| | | ├── gtk - Código fuente específico para GTK+.
|
||||
| | | └── win - Código fuente específico para Windows GUI.
|
||||
| | ├── default_app - La página por defecto para mostrar cuando Electron
|
||||
| | | es iniciado sin proveer una app.
|
||||
| | ├── api - La implementación de las APIs para el proceso principal.
|
||||
| | | └── lib - Código Javascript parte de la implementación de la API.
|
||||
| | ├── net - Código relacionado a la red.
|
||||
| | ├── mac - Código fuente de Objective-C específico para Mac.
|
||||
| | └── resources - Iconos, archivos específicos de plataforma, etc.
|
||||
| ├── renderer - Código que se ejecuta en el proceso de renderizado.
|
||||
| | ├── lib - Código Javascript del proceso de inicio del renderizador.
|
||||
| | └── api - La implementación de las APIs para el proceso de renderizado.
|
||||
| | └── lib - Código Javascript parte de la implementación de la API.
|
||||
| └── common - Código que se utiliza en ambos procesos, el principal y el de
|
||||
| renderizado. Incluye algunas funciones de utilidad y código para integrar
|
||||
| el ciclo de mensajes de Node en el ciclo de mensajes de Chromium.
|
||||
| ├── lib - Código Javascript común para la inicialización.
|
||||
| └── api - La implementación de APIs comunes, y los fundamentos de
|
||||
| los módulos integrados de Electron.
|
||||
| └── lib - Código Javascript parte de la implementación de la API.
|
||||
├── chromium_src - Código fuente copiado de Chromium.
|
||||
├── docs - Documentación.
|
||||
├── spec - Pruebas automaticas.
|
||||
├── atom.gyp - Reglas de compilado de Electron.
|
||||
└── common.gypi - Configuración específica para compilar y reglas
|
||||
de empaquetado para otros componentes como `node` y `breakpad`.
|
||||
```
|
||||
|
||||
## Estructura de otros directorios
|
||||
|
||||
* **script** - Scripts usados para propositos de desarrollo
|
||||
como compilar, empaquetar, realizar pruebas, etc.
|
||||
* **tools** - Scripts de ayuda usados por los archivos gyp, contrario a la
|
||||
carpeta `scripts`, estos scripts nunca deberían ser llamados por los usuarios.
|
||||
* **vendor** - Código fuente de dependencias externas, no usamos `third_party`
|
||||
como nombre por que se podría confundir con el mismo directorio
|
||||
en las carpetas del código fuente de Chromium.
|
||||
* **node_modules** - Módulos de node usados para la compilación.
|
||||
* **out** - Directorio temporal de salida usado por `ninja`.
|
||||
* **dist** - Directorio temporal creado por `script/create-dist.py` cuando
|
||||
se esta creando una distribución.
|
||||
* **external_binaries** - Binarios descargados de frameworks externos que no
|
||||
soportan la compilación con `gyp`.
|
|
@ -15,7 +15,7 @@ Estas son las maneras en las que construimos la documentación de Electron.
|
|||
- Archivos separados por guiones, mas sin embargo, es correcto.
|
||||
- No subtítulos seguidos por otros subtítulos, añadir por lo menos un enunciado
|
||||
de descripción.
|
||||
- Métodos de cabecera son delimitados con apóstrofes: `codigo`.
|
||||
- Métodos de cabecera son delimitados con apóstrofes: `código`.
|
||||
- Cabeceras de Eventos son delimitados con 'comillas' simples.
|
||||
- No generar listas de mas de dos niveles (debido al renderizador de Markdown
|
||||
desafortunadamente).
|
||||
|
@ -25,7 +25,7 @@ Estas son las maneras en las que construimos la documentación de Electron.
|
|||
- Argumentos opcionales escritos como `function (required[, optional])`.
|
||||
- Argumentos opcionales son denotados cuando se llaman en listas.
|
||||
- Delimitador de línea de 80-columnas.
|
||||
- Métodos específicos de Plataformas son denotados en italicas seguidas por la cabecera del método.
|
||||
- Métodos específicos de Plataformas son denotados en itálicas seguidas por la cabecera del método.
|
||||
- ```### `method(foo, bar)` _OS X_```
|
||||
- Preferir 'en el ___ proceso' en lugar de 'sobre el'
|
||||
|
||||
|
@ -47,7 +47,7 @@ Para agregar otro set (o un set parcial):
|
|||
|
||||
## Leyendo la Documentación de Electron
|
||||
|
||||
Estos son algunos consejos para entender la syntaxis de la documentación de
|
||||
Estos son algunos consejos para entender la sintaxis de la documentación de
|
||||
Electron.
|
||||
|
||||
### Métodos
|
||||
|
@ -67,7 +67,7 @@ El nombre del método es seguido por los argumentos que recibe. Argumentos
|
|||
opcionales son denotados por corchetes rodeados por el argumento opcional y la
|
||||
coma requerida si el argumento opcional fuera seguido por otro argumento.
|
||||
|
||||
Debajo del método se encuentra mas información detallada de cada uno de los
|
||||
Debajo del método se encuentra más información detallada de cada uno de los
|
||||
argumentos. El tipo de argumento es denotado por los tipos comúnes:
|
||||
[`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String),
|
||||
[`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number),
|
||||
|
@ -90,7 +90,7 @@ Returns:
|
|||
---
|
||||
|
||||
El evento es una cadena que es utilizada luego de un método observador `.on`. Si
|
||||
regresa un valor, el y su tipo son denotados abajo. Si se estaba a la escucha y
|
||||
regresa un valor, él y su tipo son denotados abajo. Si se estaba a la escucha y
|
||||
respondió a este evento se debería ver así:
|
||||
|
||||
```javascript
|
||||
|
|
|
@ -65,7 +65,6 @@ a ser ejecutado por el proceso principal. Un ejemplo de `package.json` podría v
|
|||
```
|
||||
|
||||
El `main.js` debería crear las ventanas y gestionar los eventos del sistema, un ejemplo típico sería:
|
||||
example being:
|
||||
|
||||
```javascript
|
||||
var app = require('app'); // Módulo para controlar el ciclo de vida de la aplicación.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
* [지원하는 플랫폼](tutorial/supported-platforms.md)
|
||||
* [어플리케이션 배포](tutorial/application-distribution.md)
|
||||
* [맥 앱스토어 제출 가이드 (0% 번역됨)](tutorial/mac-app-store-submission-guide.md)
|
||||
* [어플리케이션 패키징](tutorial/application-packaging.md)
|
||||
* [네이티브 Node 모듈 사용하기](tutorial/using-native-node-modules.md)
|
||||
* [메인 프로세스 디버깅하기](tutorial/debugging-main-process.md)
|
||||
|
@ -19,7 +20,7 @@
|
|||
|
||||
* [개요](api/synopsis.md)
|
||||
* [Process 객체](api/process.md)
|
||||
* [크롬 Command Line 스위치 지원](api/chrome-command-line-switches.md)
|
||||
* [크롬 명령줄 스위치 지원](api/chrome-command-line-switches.md)
|
||||
|
||||
### 커스텀 DOM elements:
|
||||
|
||||
|
@ -29,7 +30,7 @@
|
|||
|
||||
### 메인 프로세스에서 사용할 수 있는 모듈:
|
||||
|
||||
* [app (0% 번역됨)](api/app.md)
|
||||
* [app](api/app.md)
|
||||
* [auto-updater](api/auto-updater.md)
|
||||
* [browser-window (0% 번역됨)](api/browser-window.md)
|
||||
* [content-tracing](api/content-tracing.md)
|
||||
|
@ -65,7 +66,7 @@
|
|||
* [소스 코드 디렉터리 구조](development/source-code-directory-structure.md)
|
||||
* [NW.js(node-webkit)와 기술적으로 다른점](development/atom-shell-vs-node-webkit.md)
|
||||
* [빌드 시스템 개요](development/build-system-overview.md)
|
||||
* [빌드 설명서 (Mac)](development/build-instructions-osx.md)
|
||||
* [빌드 설명서 (OS X)](development/build-instructions-osx.md)
|
||||
* [빌드 설명서 (Windows)](development/build-instructions-windows.md)
|
||||
* [빌드 설명서 (Linux)](development/build-instructions-linux.md)
|
||||
* [디버거에서 디버그 심볼 서버 설정](development/setting-up-symbol-server.md)
|
||||
|
|
392
docs-translations/ko-KR/api/app.md
Normal file
392
docs-translations/ko-KR/api/app.md
Normal file
|
@ -0,0 +1,392 @@
|
|||
# app
|
||||
|
||||
`app` 모듈은 어플리케이션의 생명주기 제어를 책임집니다.
|
||||
|
||||
밑의 예제는 마지막 윈도우창가 종료되었을 때, 어플리케이션을 종료시키는 예제입니다:
|
||||
|
||||
```javascript
|
||||
var app = require('app');
|
||||
app.on('window-all-closed', function() {
|
||||
app.quit();
|
||||
});
|
||||
```
|
||||
|
||||
## Events
|
||||
|
||||
`app` 객체는 다음과 같은 이벤트를 가지고 있습니다:
|
||||
|
||||
### Event: 'will-finish-launching'
|
||||
|
||||
어플리케이션이 기본적인 시작 준비를 마치면 발생하는 이벤트입니다.
|
||||
Windows, Linux 운영체제에서의 `will-finish-launching` 이벤트는 `ready` 이벤트와 동일합니다.
|
||||
OS X에서의 이벤트는 `NSApplication`의 `applicationWillFinishLaunching`에 대한 알림으로 표현됩니다.
|
||||
대개 이곳에서 `open-file`과 `open-url` 이벤트 리스너를 설정하고 crash reporter와 auto updater를 시작합니다.
|
||||
|
||||
대부분의 경우, 모든 것을 `ready` 이벤트 핸들러로 해결해야 합니다.
|
||||
|
||||
### Event: 'ready'
|
||||
|
||||
Electron이 초기화를 끝냈을 때 발생하는 이벤트입니다.
|
||||
|
||||
### Event: 'window-all-closed'
|
||||
|
||||
모든 윈도우창이 종료되었을 때 발생하는 이벤트입니다.
|
||||
|
||||
이 이벤트는 어플리케이션이 완전히 종료되지 않았을 때만 발생합니다.
|
||||
만약 사용자가 `Cmd + Q`를 입력했거나 개발자가 `app.quit()`를 호출했다면,
|
||||
Electron은 먼저 모든 윈도우창의 종료를 시도하고 `will-quit` 이벤트를 발생시킵니다.
|
||||
그리고 `will-quit` 이벤트가 발생했을 땐 `window-all-closed` 이벤트가 발생하지 않습니다.
|
||||
|
||||
**역주:** 이 이벤트는 말 그대로 현재 어플리케이션에서 윈도우창만 완전히 종료됬을 때 발생하는 이벤트 입니다.
|
||||
따라서 어플리케이션을 완전히 종료하려면 이 이벤트에서 `app.quit()`를 호출해 주어야 합니다.
|
||||
|
||||
### Event: 'before-quit'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
|
||||
어플리케이션 윈도우창들이 닫히기 시작할 때 발생하는 이벤트입니다.
|
||||
`event.preventDefault()` 호출은 이벤트의 기본 동작을 방지하기 때문에
|
||||
이를 통해 어플리케이션의 종료를 방지할 수 있습니다.
|
||||
|
||||
### Event: 'will-quit'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
|
||||
모든 윈도우창들이 종료되고 어플리케이션이 종료되기 시작할 때 발생하는 이벤트 입니다.
|
||||
`event.preventDefault()` 호출을 통해 어플리케이션의 종료를 방지할 수 있습니다.
|
||||
|
||||
`will-quit` 와 `window-all-closed` 이벤트의 차이점을 확인하려면 `window-all-close` 이벤트의 설명을 참고하세요.
|
||||
|
||||
### Event: 'quit'
|
||||
|
||||
어플리케이션이 종료될 때 발생하는 이벤트입니다.
|
||||
|
||||
### Event: 'open-file'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `path` String
|
||||
|
||||
사용자가 어플리케이션을 통해 파일을 열고자 할 때 발생하는 이벤트입니다.
|
||||
|
||||
`open-file` 이벤트는 보통 어플리케이션이 열려 있을 때 OS가 파일을 열기 위해 어플리케이션을 재사용할 때 발생합니다.
|
||||
이 이벤트는 파일을 dock에 떨어트릴 때, 어플리케이션이 실행되기 전에도 발생합니다.
|
||||
따라서 이 이벤트를 제대로 처리하려면 `open-file` 이벤트 핸들러를 어플리케이션이 시작하기 전에 등록해 놓았는지 확실히 확인해야 합니다. (`ready` 이벤트가 발생하기 전에)
|
||||
|
||||
이 이벤트를 처리할 땐 반드시 `event.preventDefault()`를 호출해야 합니다.
|
||||
|
||||
### Event: 'open-url'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `url` String
|
||||
|
||||
유저가 어플리케이션을 통해 URL을 열고자 할 때 발생하는 이벤트입니다.
|
||||
|
||||
어플리케이션에서 URL을 열기 위해 반드시 URL 스킴이 등록되어 있어야 합니다.
|
||||
|
||||
이 이벤트를 처리할 땐 반드시 `event.preventDefault()`를 호출해야 합니다.
|
||||
|
||||
### Event: 'activate' _OS X_
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `hasVisibleWindows` Boolean
|
||||
|
||||
어플리케이션이 활성화 되었을 때 발생하는 이벤트 입니다.
|
||||
이 이벤트는 어플리케이션의 dock 아이콘을 클릭했을 때 주로 발생합니다.
|
||||
|
||||
### Event: 'browser-window-blur'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `window` BrowserWindow
|
||||
|
||||
[browserWindow](browser-window.md)에 대한 포커스가 사라졌을 때 발생하는 이벤트 입니다.
|
||||
|
||||
### Event: 'browser-window-focus'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `window` BrowserWindow
|
||||
|
||||
[browserWindow](browser-window.md)에 대한 포커스가 발생했을 때 발생하는 이벤트 입니다.
|
||||
|
||||
**역주:** _포커스_는 창을 클릭해서 활성화 시켰을 때를 말합니다.
|
||||
|
||||
### Event: 'browser-window-created'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `window` BrowserWindow
|
||||
|
||||
새로운 [browserWindow](browser-window.md)가 생성되었을 때 발생하는 이벤트 입니다.
|
||||
|
||||
### Event: 'select-certificate'
|
||||
|
||||
사용자 인증이 요청되었을 때 발생하는 이벤트 입니다.
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `webContents` [WebContents](browser-window.md#class-webcontents)
|
||||
* `url` String
|
||||
* `certificateList` [Objects]
|
||||
* `data` PEM으로 인코딩된 데이터
|
||||
* `issuerName` 발급자의 공통 이름
|
||||
* `callback` Function
|
||||
|
||||
```javascript
|
||||
app.on('select-certificate', function(event, host, url, list, callback) {
|
||||
event.preventDefault();
|
||||
callback(list[0]);
|
||||
})
|
||||
```
|
||||
|
||||
`url`에 대한
|
||||
|
||||
`url`은 클라이언트 인증서를 요청하는 탐색 항목에 해당합니다.
|
||||
그리고 `callback`은 목록에서 필터링된 항목과 함께 호출될 필요가 있습니다.
|
||||
|
||||
이 이벤트에서의 `event.preventDefault()` 호출은 초기 인증에 사용한 저장된 데이터를 사용하는 것을 막습니다.
|
||||
|
||||
### Event: 'gpu-process-crashed'
|
||||
|
||||
GPU가 작동하던 중 크래시가 일어났을 때 발생하는 이벤트입니다.
|
||||
|
||||
## Methods
|
||||
|
||||
`app` 객체는 다음과 같은 메서드를 가지고 있습니다:
|
||||
|
||||
**참고:** 몇몇 메서드는 특정 플랫폼에서만 작동합니다.
|
||||
|
||||
### `app.quit()`
|
||||
|
||||
모든 윈도우창 종료를 시도합니다. `before-quit` 이벤트가 먼저 발생합니다.
|
||||
모든 윈도우창이 성공적으로 종료되면 `will-quit` 이벤트가 발생하고 기본 동작에 따라 어플리케이션이 종료됩니다.
|
||||
|
||||
이 함수는 모든 `beforeunload`와 `unload` 이벤트 핸들러가 제대로 실행됨을 보장합니다.
|
||||
`beforeunload` 이벤트 핸들러에서 `false`를 반환했을 때 윈도우창 종료가 취소 될 수 있습니다.
|
||||
|
||||
### `app.getAppPath()`
|
||||
|
||||
현재 어플리케이션의 디렉터리를 반환합니다.
|
||||
|
||||
### `app.getPath(name)`
|
||||
|
||||
* `name` String
|
||||
|
||||
`name`에 관련한 특정 디렉터리 또는 파일의 경로를 반환합니다.
|
||||
경로를 가져오는 데 실패할 경우 `Error`를 반환합니다.
|
||||
|
||||
**역주:** 이 메서드는 운영체제에서 지정한 특수 디렉터리를 가져오는데 사용할 수 있습니다.
|
||||
|
||||
`name`은 다음 목록에 있는 경로 중 하나를 선택해 사용할 수 있습니다:
|
||||
|
||||
* `home` - 사용자의 홈 디렉터리.
|
||||
* `appData` - 각 사용자의 어플리케이션 데이터 디렉터리. 기본 경로는 다음과 같습니다:
|
||||
* `%APPDATA%` - Windows
|
||||
* `$XDG_CONFIG_HOME` 또는 `~/.config` - Linux
|
||||
* `~/Library/Application Support` - OS X
|
||||
* `userData` - 어플리케이션의 설정을 저장하는 디렉터리.
|
||||
이 디렉터리는 기본적으로 `appData`에 어플리케이션 이름으로 생성된 폴더가 지정됩니다.
|
||||
* `temp` - 임시 폴더 디렉터리.
|
||||
* `userDesktop` - 현재 사용자의 데스트탑 디렉터리.
|
||||
* `exe` - 현재 실행중인 Electron 바이너리 파일.
|
||||
* `module` - `libchromiumcontent` 라이브러리.
|
||||
|
||||
### `app.setPath(name, path)`
|
||||
|
||||
* `name` String
|
||||
* `path` String
|
||||
|
||||
`name`에 대한 특정 디렉터리나 파일의 경로인 `path`를 재정의합니다.
|
||||
만약 지정한 디렉터리의 경로가 존재하지 않으면 디렉터리가 이 메서드를 통해 새로 생성됩니다.
|
||||
재정의에 실패했을 땐 `Error`를 반환합니다.
|
||||
|
||||
이 메서드는 `app.getPath`에 정의되어 있는 `name`의 경로만 재정의할 수 있습니다.
|
||||
|
||||
기본적으로, 웹 페이지의 쿠키와 캐시는 `userData` 디렉터리에 저장됩니다.
|
||||
만약 이 위치를 변경하고자 한다면, 반드시 `app` 모듈의 `ready` 이벤트가 발생하기 전에 `userData` 경로를 재정의해야 합니다.
|
||||
|
||||
### `app.getVersion()`
|
||||
|
||||
로드된 어플리케이션의 버전을 반환합니다.
|
||||
|
||||
만약 `package.json` 파일에서 어플리케이션의 버전을 찾을 수 없는 경우, 현재 번들 또는 실행 파일의 버전을 반환합니다.
|
||||
|
||||
### `app.getName()`
|
||||
|
||||
`package.json`에서 기술된 현재 어플리케이션의 이름을 반환합니다.
|
||||
|
||||
npm 모듈 규칙에 따라 대부분의 경우 `package.json`의 `name` 필드는 소문자 이름을 사용합니다.
|
||||
하지만 Electron은 `name`대신 `productName` 필드를 주로 사용하기 때문에 반드시 이 필드도 같이 지정해야 합니다.
|
||||
이 필드는 맨 앞글자가 대문자인 어플리케이션 전체 이름을 지정해야 합니다.
|
||||
|
||||
### `app.getLocale()`
|
||||
|
||||
현재 어플리케이션의 [로케일](https://ko.wikipedia.org/wiki/%EB%A1%9C%EC%BC%80%EC%9D%BC)을 반환합니다.
|
||||
|
||||
### `app.resolveProxy(url, callback)`
|
||||
|
||||
* `url` URL
|
||||
* `callback` Function
|
||||
|
||||
`url`의 프록시 정보를 해석합니다.
|
||||
`callback`은 요청이 수행되었을 때 `callback(proxy)` 형태로 호출됩니다.
|
||||
|
||||
### `app.addRecentDocument(path)` _OS X_ _Windows_
|
||||
|
||||
* `path` String
|
||||
|
||||
최근 문서 목록에 `path`를 추가합니다.
|
||||
|
||||
이 목록은 OS에 의해 관리됩니다.
|
||||
최근 문서 목록은 Windows의 경우 작업 표시줄에서 찾을 수 있고, OS X의 경우 dock 메뉴에서 찾을 수 있습니다.
|
||||
|
||||
### `app.clearRecentDocuments()` _OS X_ _Windows_
|
||||
|
||||
최근 문서 목록을 모두 비웁니다.
|
||||
|
||||
### `app.setUserTasks(tasks)` _Windows_
|
||||
|
||||
* `tasks` Array - `Task` 객체의 배열
|
||||
|
||||
Windows에서 사용할 수 있는 JumpList의 [Tasks][tasks] 카테고리에 `task`를 추가합니다.
|
||||
|
||||
`tasks`는 다음과 같은 구조를 가지는 `Task` 객체의 배열입니다:
|
||||
|
||||
`Task` Object
|
||||
* `program` String - 실행할 프로그램의 경로.
|
||||
보통 현재 작동중인 어플리케이션의 경로인 `process.execPath`를 지정합니다.
|
||||
* `arguments` String - `program`이 실행될 때 사용될 명령줄 인자.
|
||||
* `title` String - JumpList에 표시할 문자열.
|
||||
* `description` String - 이 작업에 대한 설명.
|
||||
* `iconPath` String - JumpList에 표시될 아이콘의 절대 경로.
|
||||
아이콘을 포함하고 있는 임의의 리소스 파일을 사용할 수 있습니다.
|
||||
보통 어플리케이션의 아이콘을 그대로 사용하기 위해 `process.execPath`를 지정합니다.
|
||||
* `iconIndex` Integer - 아이콘 파일의 인덱스. 만약 아이콘 파일이 두 개 이상의 아이콘을 가지고 있을 경우,
|
||||
사용할 아이콘의 인덱스를 이 옵션으로 지정해 주어야 합니다. 단, 아이콘을 하나만 포함하고 있는 경우 0을 지정하면 됩니다.
|
||||
|
||||
### `app.allowNTLMCredentialsForAllDomains(allow)`
|
||||
|
||||
* `allow` Boolean
|
||||
|
||||
항상 동적으로 HTTP NTLM 또는 Negotiate 인증에 자격 증명을 보낼 것인지 설정합니다.
|
||||
|
||||
기본적으로 Electron은 "로컬 인터넷" 사이트 URL에서 NTLM/Kerberos 자격 증명만을 보냅니다. (같은 도메인 내에서)
|
||||
그러나 기업 네트워크가 잘못 구성된 경우 종종 작업에 실패할 수 있습니다.
|
||||
이때 이 메서드를 통해 모든 URL을 허용할 수 있습니다.
|
||||
|
||||
### `app.makeSingleInstance(callback)`
|
||||
|
||||
* `callback` Function
|
||||
|
||||
현재 어플리케이션을 **Single Instance Application**으로 만들어줍니다.
|
||||
이 메서드는 어플리케이션이 여러 번 실행됐을 때 다중 인스턴스가 생성되는 대신 한 개의 주 인스턴스만 유지되도록 만들 수 있습니다.
|
||||
이때 중복 생성된 인스턴스는 주 인스턴스에 신호를 보내고 종료됩니다.
|
||||
|
||||
`callback`은 주 인스턴스가 생성된 이후 또 다른 인스턴스가 생성됐을 때 `callback(argv, workingDirectory)` 형식으로 호출됩니다.
|
||||
`argv`는 두 번째 인스턴스의 명령줄 인수이며 `workingDirectory`는 현재 작업중인 디렉터리입니다.
|
||||
보통 대부분의 어플리케이션은 이러한 콜백이 호출될 때 주 윈도우창을 포커스하고 최소화되어있으면 창 복구를 실행합니다.
|
||||
|
||||
`callback`은 `app`의 `ready` 이벤트가 발생한 후 실행됨을 보장합니다.
|
||||
|
||||
이 메서드는 현재 실행된 어플리케이션이 주 인스턴스인 경우 `false`를 반환하고 어플리케이션의 로드가 계속 진행 되도록 합니다.
|
||||
그리고 두 번째 중복된 인스턴스 생성인 경우 `true`를 반환합니다. (다른 인스턴스에 인수가 전달됬을 때)
|
||||
이 불리언 값을 통해 중복 생성된 인스턴스는 즉시 종료시켜야 합니다.
|
||||
|
||||
OS X에선 사용자가 Finder에서 어플리케이션의 두 번째 인스턴스를 열려고 했을 때 자동으로 **Single Instance**화 하고 `open-file`과 `open-url` 이벤트를 발생시킵니다.
|
||||
그러나 사용자가 어플리케이션을 CLI 터미널에서 실행하면 운영체제 시스템의 싱글 인스턴스 메커니즘이 무시되며 그대로 중복 실행됩니다.
|
||||
따라서 OS X에서도 이 메서드를 통해 확실히 중복 실행을 방지하는 것이 좋습니다.
|
||||
|
||||
다음 예제는 두 번째 인스턴스가 생성되었을 때 중복된 인스턴스를 종료하고 주 어플리케이션 인스턴스의 윈도우창을 활성화 시키는 예제입니다:
|
||||
|
||||
```javascript
|
||||
var myWindow = null;
|
||||
|
||||
var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
|
||||
// 어플리케이션을 중복 실행했습니다. 주 어플리케이션 인스턴스를 활성화 합니다.
|
||||
if (myWindow) {
|
||||
if (myWindow.isMinimized()) myWindow.restore();
|
||||
myWindow.focus();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (shouldQuit) {
|
||||
app.quit();
|
||||
return;
|
||||
}
|
||||
|
||||
// 윈도우창을 생성하고 각종 리소스를 로드하고 작업합니다..
|
||||
app.on('ready', function() {
|
||||
});
|
||||
```
|
||||
|
||||
### `app.commandLine.appendSwitch(switch[, value])`
|
||||
|
||||
Chrominum의 명령줄에 스위치를 추가합니다. `value`는 추가적인 값을 뜻하며 옵션입니다.
|
||||
|
||||
**참고:** 이 메서드는 `process.argv`에 영향을 주지 않습니다.
|
||||
개발자들은 보통 Chrominum의 로우 레벨 수준의 동작을 제어하기 위해 주로 사용합니다.
|
||||
|
||||
### `app.commandLine.appendArgument(value)`
|
||||
|
||||
Chrominum의 명령줄에 인수를 추가합니다. 인수는 올바르게 인용됩니다.
|
||||
|
||||
**참고:** 이 메서드는 `process.argv`에 영향을 주지 않습니다.
|
||||
|
||||
### `app.dock.bounce([type])` _OS X_
|
||||
|
||||
* `type` String (optional) - `critical` 또는 `informational`을 지정할 수 있습니다. 기본값은 `informational` 입니다.
|
||||
|
||||
`critical`이 전달되면 dock 아이콘이 어플리케이션이 활성화되거나 요청이 중지되기 전까지 통통 튑니다.
|
||||
|
||||
`informational`이 전달되면 dock 아이콘이 1초만 통통 튑니다.
|
||||
하지만 어플리케이션이 활성화되거나 요청이 중지되기 전까지 요청은 계속 활성화로 유지 됩니다.
|
||||
|
||||
또한 요청을 취소할 때 사용할 수 있는 ID를 반환합니다.
|
||||
|
||||
### `app.dock.cancelBounce(id)` _OS X_
|
||||
|
||||
* `id` Integer
|
||||
|
||||
`app.dock.bounce([type])` 메서드에서 반환한 `id`의 통통 튀는 효과를 취소합니다.
|
||||
|
||||
### `app.dock.setBadge(text)` _OS X_
|
||||
|
||||
* `text` String
|
||||
|
||||
dock의 badge에 표시할 문자열을 설정합니다.
|
||||
|
||||
### `app.dock.getBadge()` _OS X_
|
||||
|
||||
dock의 badge에 설정된 문자열을 반환합니다.
|
||||
|
||||
### `app.dock.hide()` _OS X_
|
||||
|
||||
dock 아이콘을 숨깁니다.
|
||||
|
||||
### `app.dock.show()` _OS X_
|
||||
|
||||
dock 아이콘을 표시합니다.
|
||||
|
||||
### `app.dock.setMenu(menu)` _OS X_
|
||||
|
||||
* `menu` Menu
|
||||
|
||||
어플리케이션의 [dock menu][dock-menu]를 설정합니다.
|
||||
|
||||
[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103
|
||||
[tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks
|
|
@ -1,86 +1,28 @@
|
|||
# autoUpdater
|
||||
|
||||
**이 모듈은 현재 OS X에서만 사용할 수 있습니다.**
|
||||
이 모듈은 `Squirrel` 자동 업데이트 프레임워크의 인터페이스를 제공합니다.
|
||||
|
||||
Windows 인스톨러를 생성하려면 [atom/grunt-electron-installer](https://github.com/atom/grunt-electron-installer)를 참고하세요.
|
||||
## 플랫폼별 참고 사항
|
||||
|
||||
`auto-updater` 모듈은 [Squirrel.Mac](https://github.com/Squirrel/Squirrel.Mac) 프레임워크의 간단한 wrapper 입니다.
|
||||
`autoUpdater`는 기본적으로 모든 플랫폼에 대해 같은 API를 제공하지만, 여전히 플랫폼별로 약간씩 다른 점이 있습니다.
|
||||
|
||||
Squirrel.Mac은 업데이트 설치를 위해 `.app` 폴더에
|
||||
[codesign](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/codesign.1.html)
|
||||
툴을 사용한 서명을 요구합니다.
|
||||
### OS X
|
||||
|
||||
## Squirrel
|
||||
OS X에선 `auto-updater` 모듈이 [Squirrel.Mac][squirrel-mac]를 기반으로 작동합니다.
|
||||
따라서 이 모듈을 작동시키기 위해 특별히 준비해야 할 작업은 없습니다.
|
||||
서버 사이드 요구 사항은 [서버 지원][server-support]을 참고하세요.
|
||||
|
||||
Squirrel은 어플리케이션이 **안전하고 투명한 업데이트**를 제공할 수 있도록 하는데 초점이 맞춰진 OS X 프레임워크입니다.
|
||||
### Windows
|
||||
|
||||
Squirrel은 사용자에게 어플리케이션의 업데이트를 알릴 필요 없이 자동으로 서버가 지시하는 버전을 받아 어플리케이션을 업데이트합니다.
|
||||
지능적으로 클라이언트 어플리케이션을 업데이트 할 수 있습니다.
|
||||
Windows에선 `auto-updater` 모듈을 사용하기 전에 어플리케이션을 사용자의 장치에 설치해야 합니다.
|
||||
[grunt-electron-installer][installer]를 사용하여 어플리케이션 셋업을 만드는 것을 권장합니다.
|
||||
|
||||
업데이트 요청은 커스텀 헤더 또는 요청 본문에 인증 정보를 포함시킬 수 있습니다.
|
||||
이에 따라 서버에선 이러한 요청을 분석 처리하여 사용자에게 적당한 업데이트를 제공할 수 있습니다.
|
||||
서버 사이드 요구 사항 또한 OS X와 다르게 적용됩니다. 자세한 내용은 [Squirrel.Windows][squirrel-windows]를 참고하세요.
|
||||
|
||||
Squirrel JSON 업데이트 요청시 처리는 반드시 어떤 업데이트가 필요한지 요청의 기준에 맞춰 동적으로 생성되어야 합니다.
|
||||
Squirrel은 사용해야 하는 업데이트 선택하는 과정을 서버에 의존합니다. [서버 지원](#서버-지원)을 참고하세요.
|
||||
### Linux
|
||||
|
||||
Squirrel의 인스톨러는 오류에 관대하게 설계되었습니다. 그리고 업데이트가 유효한지 확인합니다.
|
||||
|
||||
## 업데이트 요청
|
||||
|
||||
Squirrel은 클라이언트 어플리케이션이 업데이트 확인을 위해 제공하는 요청을 무시합니다.
|
||||
Squirrel이 응답을 분석할 수 있어야하기 때문에 요청 헤더에 `Accept: application/json` 헤더가 추가됩니다.
|
||||
|
||||
업데이트 응답과 본문 포맷에 대한 요구 사항은 [서버 지원](#서버-지원)를 참고하세요.
|
||||
|
||||
업데이트 요청에는 서버가 해당 어플리케이션이 어떤 버전을 사용해야 하는지 판단하기 위해 *반드시* 버전 식별자를 포함시켜야 합니다.
|
||||
추가로 OS 버전, 사용자 이름 같은 다른 식별 기준을 포함하여 서버에서 적합한 어플리케이션을 제공할 수 있도록 할 수 있습니다.
|
||||
|
||||
버전 식별자와 다른 기준을 특정하는 업데이트 요청 폼을 서버로 전달하기 위한 공통적인 방법으로 쿼리 인자를 사용하는 방법이 있습니다:
|
||||
|
||||
```javascript
|
||||
// In the main process
|
||||
var app = require('app');
|
||||
var autoUpdater = require('auto-updater');
|
||||
autoUpdater.setFeedUrl('http://mycompany.com/myapp/latest?version=' + app.getVersion());
|
||||
```
|
||||
|
||||
## 서버 지원
|
||||
|
||||
업데이트를 제공하는 서버는 반드시 클라이언트로부터 받은 [업데이트 요청](#업데이트-요청)을 기반으로 업데이트를 처리할 수 있어야 합니다.
|
||||
|
||||
만약 업데이트 요청이 들어오면 서버는 반드시 [200 OK](http://tools.ietf.org/html/rfc2616#section-10.2.1) 상태 코드를 포함한
|
||||
[업데이트 JSON](#update-json-format)을 본문으로 보내야 합니다.
|
||||
이 응답을 받으면 Squirrel은 이 업데이트를 다운로드할 것입니다. 참고로 현재 설치된 버전과 서버에서 받아온 새로운 버전이 같아도 상관하지 않고 무조건 받습니다.
|
||||
업데이트시 버전 중복을 피하려면 서버에서 클라이언트 업데이트 요청에 대해 통보하지 않으면 됩니다.
|
||||
|
||||
만약 따로 업데이트가 없다면 [204 No Content](http://tools.ietf.org/html/rfc2616#section-10.2.5) 상태 코드를 반환해야 합니다.
|
||||
Squirrel은 지정한 시간이 지난 후 다시 업데이트를 확인합니다.
|
||||
|
||||
## JSON 포맷 업데이트
|
||||
|
||||
업데이트가 사용 가능한 경우 Squirrel은 다음과 같은 구조의 json 데이터를 응답으로 받습니다:
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "http://mycompany.com/myapp/releases/myrelease",
|
||||
"name": "My Release Name",
|
||||
"notes": "Theses are some release notes innit",
|
||||
"pub_date": "2013-09-18T12:29:53+01:00"
|
||||
}
|
||||
```
|
||||
|
||||
응답 json 데이터에서 "url" 키는 필수적으로 포함해야 하고 다른 키들은 옵션입니다.
|
||||
|
||||
Squirrel은 "url"로 `Accept: application/zip` 헤더와 함께 업데이트 zip 파일을 요청합니다.
|
||||
향후 업데이트 포맷에 대해 서버에서 적절한 포맷을 반환할 수 있도록 MIME 타입을 `Accept` 헤더에 담아 요청합니다.
|
||||
|
||||
`pub_date`은 ISO 8601 표준에 따라 포맷된 날짜입니다.
|
||||
|
||||
## 업데이트 서버 구현
|
||||
|
||||
[Nuts](https://github.com/GitbookIO/nuts)는 위에서 설명한 업데이트 서버의 오픈 소스 구현입니다.
|
||||
이 구현은 Github 릴리즈와 완벽하게 통합되어 있습니다. Nuts는 `Squirrel.Mac`과 `Squirrel.Windows`를 지원하고 다운로드와 업데이트를 관리합니다.
|
||||
이 구현을 사용하면 cross-platform 지원을 신경 쓸 필요가 없습니다.
|
||||
Linux는 따로 `auto-updater`를 지원하지 않습니다.
|
||||
각 배포판의 패키지 관리자를 통해 어플리케이션 업데이트를 제공하는 것을 권장합니다.
|
||||
|
||||
## Events
|
||||
|
||||
|
@ -88,10 +30,11 @@ Squirrel은 "url"로 `Accept: application/zip` 헤더와 함께 업데이트 zip
|
|||
|
||||
### Event: 'error'
|
||||
|
||||
* `event` Event
|
||||
* `message` String
|
||||
Returns:
|
||||
|
||||
업데이트시 에러가 나면 발생하는 이벤트입니다.
|
||||
* `error` Error
|
||||
|
||||
업데이트에 문제가 생기면 발생하는 이벤트입니다.
|
||||
|
||||
### Event: 'checking-for-update'
|
||||
|
||||
|
@ -107,14 +50,15 @@ Squirrel은 "url"로 `Accept: application/zip` 헤더와 함께 업데이트 zip
|
|||
|
||||
### Event: 'update-downloaded'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `releaseNotes` String
|
||||
* `releaseName` String
|
||||
* `releaseDate` Date
|
||||
* `updateUrl` String
|
||||
* `quitAndUpdate` Function
|
||||
|
||||
업데이트의 다운로드가 완료되었을 때 발생하는 이벤트입니다. `quitAndUpdate()`를 호출하면 어플리케이션을 종료하고 업데이트를 설치합니다.
|
||||
업데이트의 다운로드가 완료되었을 때 발생하는 이벤트입니다.
|
||||
|
||||
## Methods
|
||||
|
||||
|
@ -129,3 +73,13 @@ Squirrel은 "url"로 `Accept: application/zip` 헤더와 함께 업데이트 zip
|
|||
### `autoUpdater.checkForUpdates()`
|
||||
|
||||
서버에 새로운 업데이트가 있는지 요청을 보내 확인합니다. API를 사용하기 전에 `setFeedUrl`를 호출해야 합니다.
|
||||
|
||||
### `autoUpdater.quitAndUpdate()`
|
||||
|
||||
어플리케이션을 다시 시작하고 다운로드된 업데이트를 설치합니다.
|
||||
이 메서드는 `update-downloaded` 이벤트가 발생한 이후에만 사용할 수 있습니다.
|
||||
|
||||
[squirrel-mac]: https://github.com/Squirrel/Squirrel.Mac
|
||||
[server-support]: https://github.com/Squirrel/Squirrel.Mac#server-support
|
||||
[squirrel-windows]: https://github.com/Squirrel/Squirrel.Windows
|
||||
[installer]: https://github.com/atom/grunt-electron-installer
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# 크롬 Command-Line 스위치 지원
|
||||
# 크롬 명령줄 스위치 지원
|
||||
|
||||
크롬 Command-Line 스위치는 크롬 브라우저에서 제공되는 추가 옵션이며 Electron에서도 지원합니다.
|
||||
크롬 명령줄(Command-Line) 스위치는 크롬 브라우저에서 제공되는 추가 옵션이며 Electron에서도 지원합니다.
|
||||
[app][app]의 [ready][ready]이벤트가 작동하기 전에 [app.commandLine.appendSwitch][append-switch] API를 사용하면
|
||||
어플리케이션 내부에서 스위치들을 추가할 수 있습니다:
|
||||
|
||||
|
@ -44,7 +44,7 @@ HTTP 요청 캐시를 비활성화 합니다.
|
|||
|
||||
## --host-rules=`rules`
|
||||
|
||||
Hostname 맵핑 규칙을 설정합니다. (`,`로 분리)
|
||||
Hostname 맵핑 규칙을 설정합니다. (`,`로 구분)
|
||||
|
||||
예시:
|
||||
|
||||
|
@ -86,11 +86,16 @@ Net log 이벤트를 활성화하고 `path`에 로그를 기록합니다.
|
|||
|
||||
TLS fallback에서 사용할 SSL/TLS 최소 버전을 지정합니다. ("tls1", "tls1.1", "tls1.2")
|
||||
|
||||
## --cipher-suite-blacklist=`cipher_suites`
|
||||
|
||||
SSL 암호화를 비활성화할 대상 목록을 지정합니다. (`,`로 구분)
|
||||
|
||||
## --enable-logging
|
||||
|
||||
Chromium의 로그를 콘솔에 출력합니다.
|
||||
|
||||
이 스위치는 어플리케이션이 로드되기 전에 파싱 되므로 `app.commandLine.appendSwitch`에서 사용할 수 없습니다.
|
||||
이 스위치는 어플리케이션이 로드되기 전에 분석 되므로 `app.commandLine.appendSwitch` 메서드에선 사용할 수 없습니다.
|
||||
하지만 `ELECTRON_ENABLE_LOGGING` 환경 변수를 설정하면 본 스위치를 지정한 것과 같은 효과를 낼 수 있습니다.
|
||||
|
||||
## --v=`log_level`
|
||||
|
||||
|
|
|
@ -54,11 +54,10 @@ crashReporter.start({
|
|||
|
||||
Crash Reporter는 다음과 같은 데이터를 `submitUrl`에 `POST` 방식으로 전송합니다:
|
||||
|
||||
* `rept` String - 예시 'electron-crash-service'
|
||||
* `ver` String - Electron의 버전
|
||||
* `platform` String - 예시 'win32'
|
||||
* `process_type` String - 예시 'renderer'
|
||||
* `ptime` Number
|
||||
* `guid` String - e.g. '5e1286fc-da97-479e-918b-6bfb0c3d1c72'
|
||||
* `_version` String - `package.json`내의 `version` 필드
|
||||
* `_productName` String - Crash Reporter의 `options` 객체에서 정의한 제품명.
|
||||
* `prod` String - 기본 제품의 이름. 이 경우 Electron으로 표시됩니다.
|
||||
|
|
|
@ -13,7 +13,7 @@ var BrowserWindow = require('browser-window');
|
|||
var win = new BrowserWindow({ width: 800, height: 600, frame: false });
|
||||
```
|
||||
|
||||
### 최신 Mac에서 사용할 수 있는 대안
|
||||
### 최신 OS X에서 사용할 수 있는 대안
|
||||
|
||||
OS X 10.10 Yosemite 이후의 최신 버전부터는 테두리가 없는 창을 만들 때 새로운 방법을 사용할 수 있습니다.
|
||||
`frame` 옵션을 `false`로 지정하여 제목과 창 구성 요소를 모두 비활성화하는 대신 새로운 `title-bar-style`
|
||||
|
|
|
@ -5,7 +5,8 @@ Electron의 `process` 객체는 기존의 node와는 달리 약간의 차이점
|
|||
* `process.type` String - 프로세스의 타입, `browser` (메인 프로세스) 또는 `renderer`가 됩니다.
|
||||
* `process.versions['electron']` String - Electron의 버전.
|
||||
* `process.versions['chrome']` String - Chromium의 버전.
|
||||
* `process.resourcesPath` String - JavaScript 소스코드의 경로.
|
||||
* `process.resourcesPath` String - JavaScript 소스 코드의 경로.
|
||||
* `process.mas` Boolean - Mac 앱 스토어용 빌드일 때 `true`로 지정됩니다. 다른 빌드일 땐 `undefined`로 지정됩니다.
|
||||
|
||||
## Events
|
||||
|
||||
|
@ -37,4 +38,4 @@ process.once('loaded', function() {
|
|||
|
||||
* `maxDescriptors` Integer
|
||||
|
||||
`maxDescriptors`에 file descriptor 소프트 리미트를 설정하거나 OS 하드 리미트를 설정합니다. 값은 현재 프로세스에 대해 낮은 값이어야 합니다.
|
||||
현재 프로세스의 파일 기술자의 제한 값을 소프트 제한 `maxDescriptors`의 값이나 OS 하드 제한 중 낮은 값으로 설정합니다.
|
||||
|
|
|
@ -147,6 +147,8 @@ win.webContents.on('did-finish-load', function() {
|
|||
|
||||
세션에 사용할 프록시 `config`를 분석하고 프록시를 적용합니다.
|
||||
|
||||
세션에 사용할 프록시는 `config`가 PAC 주소일 경우 그대로 적용하고, 다른 형식일 경우 다음 규칙에 따라 적용합니다.
|
||||
|
||||
```
|
||||
config = scheme-proxies[";"<scheme-proxies>]
|
||||
scheme-proxies = [<url-scheme>"="]<proxy-uri-list>
|
||||
|
|
|
@ -118,7 +118,7 @@ __주의:__ `bounds`는 OS X 와 Windows에서만 작동합니다.
|
|||
|
||||
`Tray` 모듈은 다음과 같은 메서드를 가지고 있습니다:
|
||||
|
||||
**참고:** 몇가지 메서드는 특정한 플랫폼에서만 작동합니다.
|
||||
**참고:** 몇몇 메서드는 특정 플랫폼에서만 작동합니다.
|
||||
|
||||
### `Tray.destroy()`
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# 데스크톱 환경 통합
|
||||
|
||||
어플리케이션을 배포할 서로 다른 운영체제 시스템의 환경과 기능에 맞춰 사용 환경을 통합할 수 있습니다.
|
||||
예를 들어 Windows에선 태스크바의 JumpList에 바로가기를 추가할 수 있고 Mac(OS X)에선 dock menu에 커스텀 메뉴를 추가할 수 있습니다.
|
||||
어플리케이션 배포의 대상이 되는 서로 다른 운영체제 시스템의 환경에 맞춰 어플리케이션의 기능을 통합할 수 있습니다.
|
||||
예를 들어 Windows에선 태스크바의 JumpList에 바로가기를 추가할 수 있고 Mac(OS X)에선 dock 메뉴에 커스텀 메뉴를 추가할 수 있습니다.
|
||||
|
||||
이 가이드는 Electron API를 이용하여 각 운영체제 시스템의 기능을 활용하는 방법을 설명합니다.
|
||||
|
||||
|
@ -194,10 +194,10 @@ var window = new BrowserWindow({...});
|
|||
window.setProgressBar(0.5);
|
||||
```
|
||||
|
||||
## 윈도우 대표 파일 제시 (OS X)
|
||||
## 대표 파일 제시 (OS X)
|
||||
|
||||
OS X는 윈도우에서 대표 파일을 설정할 수 있습니다. 쉽게 말해 타이틀바에서 파일 아이콘을 볼 수 있을 때 사용자가 Command-Click 또는 Control-Click 할 경우 파일 경로 팝업이 보여집니다.
|
||||
또한 윈도우의 상태도 지정할 수 있습니다. 쉽게 말해 로드된 문서의 수정여부를 타이틀바 파일 아이콘에 표시할 수 있습니다.
|
||||
OS X는 창에서 대표 파일을 설정할 수 있습니다. 타이틀바에서 파일 아이콘이 있고, 사용자가 Command-Click 또는 Control-Click 키를 누를 경우 파일 경로 팝업이 보여집니다.
|
||||
또한 창의 상태도 지정할 수 있습니다. 쉽게 말해 로드된 문서의 수정여부를 타이틀바 파일 아이콘에 표시할 수 있습니다.
|
||||
|
||||
__대표 파일 팝업 메뉴:__
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ var BrowserWindow = require('browser-window'); // 네이티브 브라우저 창
|
|||
require('crash-reporter').start();
|
||||
|
||||
// 윈도우 객체를 전역에 유지합니다. 만약 이렇게 하지 않으면
|
||||
// 자바스크립트 GC가 일어날 때 창이 자동으로 닫혀버립니다.
|
||||
// 자바스크립트 GC가 일어날 때 창이 멋대로 닫혀버립니다.
|
||||
var mainWindow = null;
|
||||
|
||||
// 모든 창이 닫히면 어플리케이션 종료.
|
||||
|
@ -93,7 +93,7 @@ app.on('ready', function() {
|
|||
mainWindow.loadUrl('file://' + __dirname + '/index.html');
|
||||
|
||||
// 개발자 콘솔을 엽니다.
|
||||
mainWindow.openDevTools();
|
||||
mainWindow.webContents.openDevTools();
|
||||
|
||||
// 창이 닫히면 호출됩니다.
|
||||
mainWindow.on('closed', function() {
|
||||
|
@ -116,7 +116,8 @@ app.on('ready', function() {
|
|||
</head>
|
||||
<body>
|
||||
<h1>헬로 월드!</h1>
|
||||
이 어플리케이션은 Node.js <script>document.write(process.version)</script> 과
|
||||
이 어플리케이션은 node <script>document.write(process.version)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
Electron <script>document.write(process.versions['electron'])</script>을 사용합니다.
|
||||
</body>
|
||||
</html>
|
||||
|
@ -174,6 +175,23 @@ $ ./Electron.app/Contents/MacOS/Electron your-app/
|
|||
어플리케이션 실행파일은 `Electron`의 release 패키지에 포함되어 있습니다.
|
||||
[여기](https://github.com/atom/electron/releases)에서 다운로드 받을 수 있습니다.
|
||||
|
||||
### 배포용 파일 만들기
|
||||
### 배포용 실행 파일 만들기
|
||||
|
||||
어플리케이션 작성을 완료했다면 [어플리케이션 배포](application-distribution.md) 가이드를 통해 제작한 앱을 본격적으로 배포할 수 있습니다.
|
||||
어플리케이션 작성을 모두 끝냈다면 [어플리케이션 배포](application-distribution.md) 가이드를 통해 제작한 앱을 패키징하고 배포할 수 있습니다.
|
||||
|
||||
### 미리 작성된 앱 실행하기
|
||||
|
||||
[`atom/electron-quick-start`](https://github.com/atom/electron-quick-start) 저장소를 클론하면 이 가이드에서 작성한 예제 앱을 바로 실행해 볼 수 있습니다.
|
||||
|
||||
**참고**: 이 예제를 실행시키려면 [Git](https://git-scm.com)과 [Node.js](https://nodejs.org/en/download/)가 필요합니다. (CLI에서 실행 가능한 [npm](https://npmjs.org)이 있어야 합니다)
|
||||
|
||||
**역주**: `npm`은 보통 Node.js를 설치하면 자동으로 같이 설치됩니다.
|
||||
|
||||
```bash
|
||||
# 저장소를 클론합니다
|
||||
$ git clone https://github.com/atom/electron-quick-start
|
||||
# 저장소 안으로 들어갑니다
|
||||
$ cd electron-quick-start
|
||||
# 어플리케이션의 종속성 모듈을 설치한 후 실행합니다
|
||||
$ npm install && npm start
|
||||
```
|
|
@ -28,7 +28,7 @@ Electron도 이 모듈을 통해 포팅된 네이티브 모듈을 사용할 수
|
|||
npm install --save-dev electron-rebuild
|
||||
|
||||
# 필요한 네이티브 모듈을 `npm install`로 설치한 후 다음 명령을 실행하세요:
|
||||
node ./node_modules/.bin/electron-rebuild
|
||||
./node_modules/.bin/electron-rebuild
|
||||
```
|
||||
|
||||
### `npm`을 이용한 방법
|
||||
|
|
73
docs-translations/th-TH/README.md
Normal file
73
docs-translations/th-TH/README.md
Normal file
|
@ -0,0 +1,73 @@
|
|||
## คู่มือ
|
||||
|
||||
* [แพลตฟอร์มที่รองรับ](tutorial/supported-platforms.md)
|
||||
* [การเผยแพร่แอปพลิเคชัน](tutorial/application-distribution.md)
|
||||
* [แนวทางการส่งแอปเข้า Mac App Store](tutorial/mac-app-store-submission-guide.md)
|
||||
* [การบรรจุแอปพลิเคชัน](tutorial/application-packaging.md)
|
||||
* [การใช้โมดูลของ Node](tutorial/using-native-node-modules.md)
|
||||
* [การหาข้อผิดพลาดในกระบวนการหลัก](tutorial/debugging-main-process.md)
|
||||
* [การใช้งาน Selenium และ WebDriver](tutorial/using-selenium-and-webdriver.md)
|
||||
* [ส่วนเสริมของ DevTools](tutorial/devtools-extension.md)
|
||||
* [การใช้งานส่วนเสริม Pepper Flash](tutorial/using-pepper-flash-plugin.md)
|
||||
|
||||
## แนะนำ
|
||||
|
||||
* [เริ่มต้นอย่างคราวๆ](tutorial/quick-start.md)
|
||||
* [การร่วมกันของสภาพแวดล้อมบนเดสทอป](tutorial/desktop-environment-integration.md)
|
||||
* [การตรวจจับเหตุการณ์ออนไลน์หรือออฟไลน์](tutorial/online-offline-events.md)
|
||||
|
||||
## แหล่งอ้างอิงของ API
|
||||
|
||||
* [สรุปความ](api/synopsis.md)
|
||||
* [โปรเซสออบเจค](api/process.md)
|
||||
* [คำสั่งสำหรับเปลี่ยนแปลงค่าของ Chrome ที่รองรับ](api/chrome-command-line-switches.md)
|
||||
|
||||
### การปรับแต่ง DOM:
|
||||
|
||||
* [วัตถุ `File`](api/file-object.md)
|
||||
* [แท็ก `<webview>`](api/web-view-tag.md)
|
||||
* [ฟังก์ชัน `window.open`](api/window-open.md)
|
||||
|
||||
### โมดูลสำหรับกระบวนการหลัก :
|
||||
|
||||
* [app](api/app.md)
|
||||
* [auto-updater](api/auto-updater.md)
|
||||
* [browser-window](api/browser-window.md)
|
||||
* [content-tracing](api/content-tracing.md)
|
||||
* [dialog](api/dialog.md)
|
||||
* [global-shortcut](api/global-shortcut.md)
|
||||
* [ipc (main process)](api/ipc-main-process.md)
|
||||
* [menu](api/menu.md)
|
||||
* [menu-item](api/menu-item.md)
|
||||
* [power-monitor](api/power-monitor.md)
|
||||
* [power-save-blocker](api/power-save-blocker.md)
|
||||
* [protocol](api/protocol.md)
|
||||
* [session](api/session.md)
|
||||
* [web-contents](api/web-contents.md)
|
||||
* [tray](api/tray.md)
|
||||
|
||||
### โมดูลสำหรับกระบวนการ Renderer (เว็บเพจ):
|
||||
|
||||
* [ipc (renderer)](api/ipc-renderer.md)
|
||||
* [remote](api/remote.md)
|
||||
* [web-frame](api/web-frame.md)
|
||||
|
||||
### Modules for Both Processes:
|
||||
|
||||
* [clipboard](api/clipboard.md)
|
||||
* [crash-reporter](api/crash-reporter.md)
|
||||
* [native-image](api/native-image.md)
|
||||
* [screen](api/screen.md)
|
||||
* [shell](api/shell.md)
|
||||
|
||||
## การพัฒนา
|
||||
|
||||
* [ลักษณะการเขียนโค้ด](development/coding-style.md)
|
||||
* [โครงสร้างไดเรคทอรี่ของซอร์สโค้ด](development/source-code-directory-structure.md)
|
||||
* [ความแตกต่างทางเทคนิคจาก NW.js (หรือ node-webkit)](development/atom-shell-vs-node-webkit.md)
|
||||
* [ภาพรวมการสร้างระบบ](development/build-system-overview.md)
|
||||
* [ขั้นตอนการสร้าง (OS X)](development/build-instructions-osx.md)
|
||||
* [ขั้นตอนการสร้าง (Windows)](development/build-instructions-windows.md)
|
||||
* [ขั้นตอนการสร้าง (Linux)](development/build-instructions-linux.md)
|
||||
* [Setting Up Symbol Server in debugger](development/setting-up-symbol-server.md)
|
||||
* [การติดตั้งเซิร์ฟเวอร์ Symbol Server ใน debugger](development/setting-up-symbol-server.md)
|
|
@ -1,7 +1,9 @@
|
|||
## 導引
|
||||
|
||||
* [支援平台](tutorial/supported-platforms.md)
|
||||
* [應用程式發布](tutorial/application-distribution.md)
|
||||
* [應用程式打包](tutorial/application-packaging.md)
|
||||
* [Mac App Store 上架指引](tutorial/mac-app-store-submission-guide.md)
|
||||
* [使用原生 node 模組](tutorial/using-native-node-modules.md)
|
||||
* [主行程 Debug](tutorial/debugging-main-process.md)
|
||||
* [使用 Selenium 和 WebDriver](tutorial/using-selenium-and-webdriver.md)
|
||||
|
@ -64,7 +66,7 @@
|
|||
* [源碼目錄結構](development/source-code-directory-structure.md)
|
||||
* [與 NW.js (原名node-webkit) 在技術上的差異](development/atom-shell-vs-node-webkit.md)
|
||||
* [構建系統概況](development/build-system-overview.md)
|
||||
* [構建步驟 (Mac)](development/build-instructions-mac.md)
|
||||
* [構建步驟 (OS X)](development/build-instructions-osx.md)
|
||||
* [構建步驟 (Windows)](development/build-instructions-windows.md)
|
||||
* [構建步驟 (Linux)](development/build-instructions-linux.md)
|
||||
* [在 debugger 中使用 symbol server](development/setting-up-symbol-server.md)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
## 簡介
|
||||
|
||||
Electron 可以讓你使用純 JavaScript 提供豐富的原生的 APIs 來創造桌面應用程式。
|
||||
你可以把它視為一個 io.js 的變體,專注於桌面應用程式而不是 web 伺服器。
|
||||
你可以把它視為一個 Node.js 的變體,專注於桌面應用程式而不是 web 伺服器。
|
||||
|
||||
這不表示 Electron 是一個用 JavaScript 去綁定 GUI 函式庫。取而代之的,Electron 是使用網頁介面來作為它的 GUI ,
|
||||
所以你可以把它看作是一個被 JavaScript 所控制且精簡化的 Chromium 瀏覽器。
|
||||
|
@ -19,7 +19,7 @@ Electron 可以讓你使用純 JavaScript 提供豐富的原生的 APIs 來創
|
|||
每一個網頁在 Electron 裏執行各自的行程,被稱為 __渲染行程__。
|
||||
|
||||
在一般瀏覽器中,網頁通常會在沙盒環境下運行,並且不允許存取原生資源。然而,
|
||||
Electron 的用戶擁有在網頁中呼叫 io.js APIs 的能力,允許低級別操作與作業系統的交互作用。
|
||||
Electron 的用戶擁有在網頁中呼叫 Node.js APIs 的能力,允許低級別操作與作業系統的交互作用。
|
||||
|
||||
## 主行程與渲染行程的區別
|
||||
|
||||
|
@ -30,7 +30,7 @@ Electron 的用戶擁有在網頁中呼叫 io.js APIs 的能力,允許低級
|
|||
在網頁中,是不允許呼叫原生 GUI 相關 APIs 因為管理原生 GUI 資源在網頁上是非常危險而且容易造成資源洩露。
|
||||
如果你想要在網頁中呼叫 GUI 相關的 APIs 的操作,網頁的渲染行程必須與主行程進行通訊,請求主行程進行相關的操作。
|
||||
|
||||
在 Electron ,我們提供用於在主行程與渲染行程之間通訊的 [ipc][1] 模組。並且也有一個遠端模使用 RPC 通訊方式 [remote][2]。
|
||||
在 Electron,我們提供用於在主行程與渲染行程之間通訊的 [ipc](../api/ipc-renderer.md) 模組。並且也有一個遠端模組使用 RPC 通訊方式 [remote](../api/remote.md)。
|
||||
|
||||
# 打造你第一個 Electron 應用
|
||||
|
||||
|
@ -43,7 +43,7 @@ your-app/
|
|||
└── index.html
|
||||
```
|
||||
|
||||
`package.json ` 的格式與 Node 的模組完全一樣,並且有個腳本被指定為 `main` 是用來啟動你的應用程式,它運行在主行程上。
|
||||
`package.json` 的格式與 Node 的模組完全一樣,並且有個腳本被指定為 `main` 是用來啟動你的應用程式,它運行在主行程上。
|
||||
你應用裡的 一個範例在你的 `package.json` 看起來可能像這樣:
|
||||
|
||||
```json
|
||||
|
@ -88,7 +88,7 @@ app.on('ready', function() {
|
|||
mainWindow.loadUrl('file://' + __dirname + '/index.html');
|
||||
|
||||
// 打開開發者工具
|
||||
mainWindow.openDevTools();
|
||||
mainWindow.webContents.openDevTools();
|
||||
|
||||
// 當window 被關閉,這個事件會被觸發
|
||||
mainWindow.on('closed', function() {
|
||||
|
@ -110,8 +110,9 @@ app.on('ready', function() {
|
|||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
We are using io.js <script>document.write(process.version)</script>
|
||||
and Electron <script>document.write(process.versions['electron'])</script>.
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
@ -160,6 +161,17 @@ $ ./Electron.app/Contents/MacOS/Electron your-app/
|
|||
# 作為版本發行
|
||||
在你完成了你的應用程式後,你可以依照 [應用部署](https://github.com/atom/electron/blob/master/docs/tutorial/application-distribution.md) 指南發布一個版本,並且運行已經打包好的應用程式。
|
||||
|
||||
[1]: https://github.com/atom/electron/blob/master/docs/api/ipc-renderer.md
|
||||
# 試試這個範例
|
||||
|
||||
[2]: https://github.com/atom/electron/blob/master/docs/api/remote.md
|
||||
Clone 與執行本篇教學的程式碼,它們都放在 [`atom/electron-quick-start`](https://github.com/atom/electron-quick-start) 這個 repository。
|
||||
|
||||
**Note**: 執行這個範例需要 [Git](https://git-scm.com) 以及 [Node.js](https://nodejs.org/en/download/) (其中包括 [npm](https://npmjs.org)) 在你的作業系統。
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
$ git clone https://github.com/atom/electron-quick-start
|
||||
# Go into the repository
|
||||
$ cd electron-quick-start
|
||||
# Install dependencies and run the app
|
||||
$ npm install && npm start
|
||||
```
|
|
@ -66,7 +66,7 @@
|
|||
* [Source Code Directory Structure](development/source-code-directory-structure.md)
|
||||
* [Technical Differences to NW.js (formerly node-webkit)](development/atom-shell-vs-node-webkit.md)
|
||||
* [Build System Overview](development/build-system-overview.md)
|
||||
* [Build Instructions (Mac)](development/build-instructions-osx.md)
|
||||
* [Build Instructions (OS X)](development/build-instructions-osx.md)
|
||||
* [Build Instructions (Windows)](development/build-instructions-windows.md)
|
||||
* [Build Instructions (Linux)](development/build-instructions-linux.md)
|
||||
* [Setting Up Symbol Server in debugger](development/setting-up-symbol-server.md)
|
||||
|
|
|
@ -99,7 +99,7 @@ You should call `event.preventDefault()` if you want to handle this event.
|
|||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `hasVisibleWindows` Bool
|
||||
* `hasVisibleWindows` Boolean
|
||||
|
||||
Emitted when the application is activated, which usually happens when clicks on
|
||||
the applications's dock icon.
|
||||
|
@ -169,7 +169,7 @@ The `app` object has the following methods:
|
|||
|
||||
### `app.quit()`
|
||||
|
||||
Try to close all windows. The `before-quit` event will emitted first. If all
|
||||
Try to close all windows. The `before-quit` event will be emitted first. If all
|
||||
windows are successfully closed, the `will-quit` event will be emitted and by
|
||||
default the application will terminate.
|
||||
|
||||
|
@ -213,7 +213,7 @@ created by this method. On failure an `Error` is thrown.
|
|||
|
||||
You can only override paths of a `name` defined in `app.getPath`.
|
||||
|
||||
By default, web pages's cookies and caches will be stored under the `userData`
|
||||
By default, web pages' cookies and caches will be stored under the `userData`
|
||||
directory. If you want to change this location, you have to override the
|
||||
`userData` path before the `ready` event of the `app` module is emitted.
|
||||
|
||||
|
@ -245,7 +245,7 @@ Returns the current application locale.
|
|||
Resolves the proxy information for `url`. The `callback` will be called with
|
||||
`callback(proxy)` when the request is performed.
|
||||
|
||||
### `app.addRecentDocument(path)`
|
||||
### `app.addRecentDocument(path)` _OS X_ _Windows_
|
||||
|
||||
* `path` String
|
||||
|
||||
|
@ -254,7 +254,7 @@ Adds `path` to the recent documents list.
|
|||
This list is managed by the OS. On Windows you can visit the list from the task
|
||||
bar, and on OS X you can visit it from dock menu.
|
||||
|
||||
### `app.clearRecentDocuments()`
|
||||
### `app.clearRecentDocuments()` _OS X_ _Windows_
|
||||
|
||||
Clears the recent documents list.
|
||||
|
||||
|
@ -264,7 +264,7 @@ Clears the recent documents list.
|
|||
|
||||
Adds `tasks` to the [Tasks][tasks] category of the JumpList on Windows.
|
||||
|
||||
`tasks` is an array of `Task` objects in following format:
|
||||
`tasks` is an array of `Task` objects in the following format:
|
||||
|
||||
`Task` Object
|
||||
* `program` String - Path of the program to execute, usually you should
|
||||
|
@ -280,6 +280,70 @@ Adds `tasks` to the [Tasks][tasks] category of the JumpList on Windows.
|
|||
consists of two or more icons, set this value to identify the icon. If an
|
||||
icon file consists of one icon, this value is 0.
|
||||
|
||||
### `app.allowNTLMCredentialsForAllDomains(allow)`
|
||||
|
||||
* `allow` Boolean
|
||||
|
||||
Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate
|
||||
authentication - normally, Electron will only send NTLM/Kerberos credentials for
|
||||
URLs that fall under "Local Intranet" sites (i.e. are in the same domain as you).
|
||||
However, this detection often fails when corporate networks are badly configured,
|
||||
so this lets you co-opt this behavior and enable it for all URLs.
|
||||
|
||||
### `app.makeSingleInstance(callback)`
|
||||
|
||||
* `callback` Function
|
||||
|
||||
This method makes your application a Single Instance Application - instead of
|
||||
allowing multiple instances of your app to run, this will ensure that only a
|
||||
single instance of your app is running, and other instances signal this
|
||||
instance and exit.
|
||||
|
||||
`callback` will be called with `callback(argv, workingDirectory)` when a second
|
||||
instance has been executed. `argv` is an Array of the second instance's command
|
||||
line arguments, and `workingDirectory` is its current working directory. Usually
|
||||
applications respond to this by making their primary window focused and
|
||||
non-minimized.
|
||||
|
||||
The `callback` is guaranteed to be executed after the `ready` event of `app`
|
||||
gets emitted.
|
||||
|
||||
This method returns `false` if your process is the primary instance of the
|
||||
application and your app should continue loading. And returns `true` if your
|
||||
process has sent its parameters to another instance, and you should immediately
|
||||
quit.
|
||||
|
||||
On OS X the system enforces single instance automatically when users try to open
|
||||
a second instance of your app in Finder, and the `open-file` and `open-url`
|
||||
events will be emitted for that. However when users start your app in command
|
||||
line the system's single instance machanism will be bypassed and you have to
|
||||
use this method to ensure single instance.
|
||||
|
||||
An example of activating the window of primary instance when a second instance
|
||||
starts:
|
||||
|
||||
```js
|
||||
var myWindow = null;
|
||||
|
||||
var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
|
||||
// Someone tried to run a second instance, we should focus our window
|
||||
if (myWindow) {
|
||||
if (myWindow.isMinimized()) myWindow.restore();
|
||||
myWindow.focus();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (shouldQuit) {
|
||||
app.quit();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create myWindow, load the rest of the app, etc...
|
||||
app.on('ready', function() {
|
||||
});
|
||||
```
|
||||
|
||||
### `app.commandLine.appendSwitch(switch[, value])`
|
||||
|
||||
Append a switch (with optional `value`) to Chromium's command line.
|
||||
|
|
|
@ -1,106 +1,31 @@
|
|||
# autoUpdater
|
||||
|
||||
**This module has only been implemented for OS X.**
|
||||
This module provides an interface for the `Squirrel` auto-updater framework.
|
||||
|
||||
Check out [atom/grunt-electron-installer](https://github.com/atom/grunt-electron-installer)
|
||||
to build a Windows installer for your app.
|
||||
## Platform notices
|
||||
|
||||
The `auto-updater` module is a simple wrapper around the
|
||||
[Squirrel.Mac](https://github.com/Squirrel/Squirrel.Mac) framework.
|
||||
Though `autoUpdater` provides an uniform API for different platforms, there are
|
||||
still some subtle differences on each platform.
|
||||
|
||||
Squirrel.Mac requires that your `.app` folder is signed using the
|
||||
[codesign](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/codesign.1.html)
|
||||
utility for updates to be installed.
|
||||
### OS X
|
||||
|
||||
## Squirrel
|
||||
On OS X the `autoUpdater` module is built upon [Squirrel.Mac][squirrel-mac], you
|
||||
don't need any special setup to make it work. For server-side requirements, you
|
||||
can read [Server Support][server-support].
|
||||
|
||||
Squirrel is an OS X framework focused on making application updates **as safe
|
||||
and transparent as updates to a website**.
|
||||
### Windows
|
||||
|
||||
Instead of publishing a feed of versions from which your app must select,
|
||||
Squirrel updates to the version your server tells it to. This allows you to
|
||||
intelligently update your clients based on the request you give to Squirrel.
|
||||
On Windows you have to install your app into user's machine before you can use
|
||||
the auto-updater, it is recommended to use [grunt-electron-installer][installer]
|
||||
module to generate a Windows installer.
|
||||
|
||||
Your request can include authentication details, custom headers or a request
|
||||
body so that your server has the context it needs in order to supply the most
|
||||
suitable update.
|
||||
The server-side setup is also different from OS X, you can read the documents of
|
||||
[Squirrel.Windows][squirrel-windows] to get more details.
|
||||
|
||||
The update JSON Squirrel requests should be dynamically generated based on
|
||||
criteria in the request and whether an update is required. Squirrel relies
|
||||
on server-side support to determine whether an update is required. See
|
||||
[Server Support](#server-support).
|
||||
### Linux
|
||||
|
||||
Squirrel's installer is designed to be fault tolerant and ensures that any
|
||||
updates installed are valid.
|
||||
|
||||
## Update Requests
|
||||
|
||||
Squirrel is indifferent to the request the client application provides for
|
||||
update checking. `Accept: application/json` is added to the request headers
|
||||
because Squirrel is responsible for parsing the response.
|
||||
|
||||
For the requirements imposed on the responses and the body format of an update
|
||||
response, see [Server Support](#server-support).
|
||||
|
||||
Your update request must *at least* include a version identifier so that the
|
||||
server can determine whether an update for this specific version is required. It
|
||||
may also include other identifying criteria, such as operating system version or
|
||||
username, to allow the server to deliver as fine grained an update as you
|
||||
would like.
|
||||
|
||||
How you include the version identifier or other criteria is specific to the
|
||||
server that you are requesting updates from. A common approach is to use query
|
||||
parameters, like this:
|
||||
|
||||
```javascript
|
||||
// In the main process
|
||||
var app = require('app');
|
||||
var autoUpdater = require('auto-updater');
|
||||
autoUpdater.setFeedUrl('http://mycompany.com/myapp/latest?version=' + app.getVersion());
|
||||
```
|
||||
|
||||
## Server Support
|
||||
|
||||
Your server should determine whether an update is required based on the
|
||||
[Update Request](#update-requests) your client issues.
|
||||
|
||||
If an update is required, your server should respond with a status code of
|
||||
[200 OK](http://tools.ietf.org/html/rfc2616#section-10.2.1) and include the
|
||||
[update JSON](#update-json-format) in the body. Squirrel **will** download and
|
||||
install this update, even if the version of the update is the same as the
|
||||
currently running version. To save redundantly downloading the same version
|
||||
multiple times your server must not inform the client to update.
|
||||
|
||||
If no update is required your server must respond with a status code of
|
||||
[204 No Content](http://tools.ietf.org/html/rfc2616#section-10.2.5). Squirrel
|
||||
will check for an update again at the interval you specify.
|
||||
|
||||
## Update JSON Format
|
||||
|
||||
When an update is available, Squirrel expects the following schema in response
|
||||
to the update request provided:
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "http://mycompany.com/myapp/releases/myrelease",
|
||||
"name": "My Release Name",
|
||||
"notes": "Theses are some release notes innit",
|
||||
"pub_date": "2013-09-18T12:29:53+01:00"
|
||||
}
|
||||
```
|
||||
|
||||
The only required key is "url"; the others are optional.
|
||||
|
||||
Squirrel will request "url" with `Accept: application/zip` and only supports
|
||||
installing ZIP updates. If future update formats are supported their MIME type
|
||||
will be added to the `Accept` header so that your server can return the
|
||||
appropriate format.
|
||||
|
||||
`pub_date` (if present) must be formatted according to ISO 8601.
|
||||
|
||||
## Update server implementations
|
||||
|
||||
[Nuts](https://github.com/GitbookIO/nuts) is an open source implementation of the update server described above, it integrates beautifully with GitHub releases. Nuts manages downloads and updates, it’s compatible with `Squirrel.Mac` and `Squirrel.Windows` so you get cross-platform support out of the box.
|
||||
There is not built-in support for auto-updater on Linux, it is recommended to
|
||||
use the distribution's package manager to update your app.
|
||||
|
||||
## Events
|
||||
|
||||
|
@ -110,8 +35,7 @@ The `autoUpdater` object emits the following events:
|
|||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `message` String
|
||||
* `error` Error
|
||||
|
||||
Emitted when there is an error while updating.
|
||||
|
||||
|
@ -137,10 +61,10 @@ Returns:
|
|||
* `releaseName` String
|
||||
* `releaseDate` Date
|
||||
* `updateUrl` String
|
||||
* `quitAndUpdate` Function
|
||||
|
||||
Emitted when an update has been downloaded. Calling `quitAndUpdate()` will
|
||||
restart the application and install the update.
|
||||
Emitted when an update has been downloaded.
|
||||
|
||||
On Windows only `releaseName` is available.
|
||||
|
||||
## Methods
|
||||
|
||||
|
@ -150,10 +74,20 @@ The `autoUpdater` object has the following methods:
|
|||
|
||||
* `url` String
|
||||
|
||||
Set the `url` and initialize the auto updater. The `url` cannot be changed
|
||||
Sets the `url` and initialize the auto updater. The `url` cannot be changed
|
||||
once it is set.
|
||||
|
||||
### `autoUpdater.checkForUpdates()`
|
||||
|
||||
Ask the server whether there is an update. You must call `setFeedUrl` before
|
||||
Asks the server whether there is an update. You must call `setFeedUrl` before
|
||||
using this API.
|
||||
|
||||
### `autoUpdater.quitAndUpdate()`
|
||||
|
||||
Restarts the app and install the update after it has been downloaded. It should
|
||||
only be called after `update-downloaded` has been emitted.
|
||||
|
||||
[squirrel-mac]: https://github.com/Squirrel/Squirrel.Mac
|
||||
[server-support]: https://github.com/Squirrel/Squirrel.Mac#server-support
|
||||
[squirrel-windows]: https://github.com/Squirrel/Squirrel.Windows
|
||||
[installer]: https://github.com/atom/grunt-electron-installer
|
||||
|
|
|
@ -61,6 +61,8 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
|||
key is pressed.
|
||||
* `enable-larger-than-screen` Boolean - Enable the window to be resized larger
|
||||
than screen.
|
||||
* `background-color` String - Window's background color as Hexadecimal value,
|
||||
like `#66CD00` or `#FFF`. This is only implemented on Linux and Windows.
|
||||
* `dark-theme` Boolean - Forces using dark theme for the window, only works on
|
||||
some GTK+3 desktop environments.
|
||||
* `transparent` Boolean - Makes the window [transparent](frameless-window.md).
|
||||
|
@ -550,6 +552,30 @@ Enters or leaves the kiosk mode.
|
|||
|
||||
Returns whether the window is in kiosk mode.
|
||||
|
||||
### `win.hookWindowMessage(message, callback)` _WINDOWS_
|
||||
|
||||
* `message` Integer
|
||||
* `callback` Function
|
||||
|
||||
Hooks a windows message. The `callback` is called when
|
||||
the message is received in the WndProc.
|
||||
|
||||
### `win.isWindowMessageHooked(message)` _WINDOWS_
|
||||
|
||||
* `message` Integer
|
||||
|
||||
Returns `true` or `false` depending on whether the message is hooked.
|
||||
|
||||
### `win.unhookWindowMessage(message)` _WINDOWS_
|
||||
|
||||
* `message` Integer
|
||||
|
||||
Unhook the window message.
|
||||
|
||||
### `win.unhookAllWindowMessages()` _WINDOWS_
|
||||
|
||||
Unhooks all of the window messages.
|
||||
|
||||
### `win.setRepresentedFilename(filename)` _OS X_
|
||||
|
||||
* `filename` String
|
||||
|
|
|
@ -92,11 +92,17 @@ Enables net log events to be saved and writes them to `path`.
|
|||
Sets the minimum SSL/TLS version ("tls1", "tls1.1" or "tls1.2") that TLS
|
||||
fallback will accept.
|
||||
|
||||
## --cipher-suite-blacklist=`cipher_suites`
|
||||
|
||||
Specify comma-separated list of SSL cipher suites to disable.
|
||||
|
||||
## --enable-logging
|
||||
|
||||
Prints Chromium's logging into console.
|
||||
|
||||
This switch can not be used in `app.commandLine.appendSwitch` since it is parsed earlier than user's app is loaded.
|
||||
This switch can not be used in `app.commandLine.appendSwitch` since it is parsed
|
||||
earlier than user's app is loaded, but you can set the `ELECTRON_ENABLE_LOGGING`
|
||||
environment variable to achieve the same effect.
|
||||
|
||||
## --v=`log_level`
|
||||
|
||||
|
|
|
@ -59,11 +59,10 @@ ID.
|
|||
|
||||
The crash reporter will send the following data to the `submitUrl` as `POST`:
|
||||
|
||||
* `rept` String - e.g. 'electron-crash-service'.
|
||||
* `ver` String - The version of Electron.
|
||||
* `platform` String - e.g. 'win32'.
|
||||
* `process_type` String - e.g. 'renderer'.
|
||||
* `ptime` Number
|
||||
* `guid` String - e.g. '5e1286fc-da97-479e-918b-6bfb0c3d1c72'
|
||||
* `_version` String - The version in `package.json`.
|
||||
* `_productName` String - The product name in the `crashReporter` `options`
|
||||
object.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Frameless Window
|
||||
|
||||
A frameless window is a window that has no [chrome](https://developer.mozilla.org/en-US/docs/Glossary/Chrome), the parts of the window, like toolbars, that are not a part of the webp page. These are options on the [`BrowserWindow`](browser-window.md) class.
|
||||
A frameless window is a window that has no [chrome](https://developer.mozilla.org/en-US/docs/Glossary/Chrome), the parts of the window, like toolbars, that are not a part of the web page. These are options on the [`BrowserWindow`](browser-window.md) class.
|
||||
|
||||
## Create a frameless window
|
||||
|
||||
|
@ -13,7 +13,7 @@ var BrowserWindow = require('browser-window');
|
|||
var win = new BrowserWindow({ width: 800, height: 600, frame: false });
|
||||
```
|
||||
|
||||
### Alternatives on Mac
|
||||
### Alternatives on OS X
|
||||
|
||||
On Mac OS X 10.10 Yosemite and newer, there's an alternative way to specify
|
||||
a chromeless window. Instead of setting `frame` to `false` which disables
|
||||
|
|
|
@ -154,7 +154,9 @@ Clears the data of web storages.
|
|||
* `config` String
|
||||
* `callback` Function - Called when operation is done.
|
||||
|
||||
Parses the `config` indicating which proxies to use for the session.
|
||||
If `config` is a PAC url, it is used directly otherwise
|
||||
`config` is parsed based on the following rules indicating which
|
||||
proxies to use for the session.
|
||||
|
||||
```
|
||||
config = scheme-proxies[";"<scheme-proxies>]
|
||||
|
|
|
@ -36,6 +36,7 @@ Returns:
|
|||
|
||||
This event is like `did-finish-load` but emitted when the load failed or was
|
||||
cancelled, e.g. `window.stop()` is invoked.
|
||||
The full list of error codes and their meaning is available [here](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h).
|
||||
|
||||
### Event: 'did-frame-finish-load'
|
||||
|
||||
|
@ -182,6 +183,7 @@ See [session documentation](session.md) for this object's methods.
|
|||
* `options` Object (optional), properties:
|
||||
* `httpReferrer` String - A HTTP Referrer url.
|
||||
* `userAgent` String - A user agent originating the request.
|
||||
* `extraHeaders` String - Extra headers separated by "\n"
|
||||
|
||||
Loads the `url` in the window, the `url` must contain the protocol prefix,
|
||||
e.g. the `http://` or `file://`.
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
# Mac App Store Submission Guide
|
||||
|
||||
Since v0.34.0, Electron allows submitting packaged apps to Mac App Store (MAS),
|
||||
this guide provides information on how to submit your app, and the limitations
|
||||
of the MAS build.
|
||||
Since v0.34.0, Electron allows submitting packaged apps to the Mac App Store
|
||||
(MAS). This guide provides information on: how to submit your app and the
|
||||
limitations of the MAS build.
|
||||
|
||||
## How to submit your app
|
||||
## How to Submit Your App
|
||||
|
||||
Following steps introduces a simple way to submit your app to Mac App Store, but
|
||||
it doesn't make sure your app gets approved by Apple, you still have to read
|
||||
apple's [Submitting Your App][submitting-your-app] guide on how to meet Mac
|
||||
App Store's requirements.
|
||||
The following steps introduce a simple way to submit your app to Mac App Store.
|
||||
However, these steps do not ensure sure your app will be approved by Apple; you
|
||||
still need to read Apple's [Submitting Your App][submitting-your-app] guide on
|
||||
how to meet the Mac App Store requirements.
|
||||
|
||||
### Get certificate
|
||||
### Get Certificate
|
||||
|
||||
To submit your app to Mac App Store, you have to get a certificate from Apple
|
||||
first, you can follow [existing guides][nwjs-guide] on web.
|
||||
To submit your app to the Mac App Store, you first must get a certificate from
|
||||
Apple. You can follow these [existing guides][nwjs-guide] on web.
|
||||
|
||||
### Sign your app
|
||||
### Sign Your App
|
||||
|
||||
After getting the certificate, you can package your app by following
|
||||
[Application Distribution](application-distribution.md), and then sign your app.
|
||||
The step is basically the same with other programs, the key is to sign every
|
||||
dependency of Electron one by one.
|
||||
After getting the certificate from Apple, you can package your app by following
|
||||
[Application Distribution](application-distribution.md), and then proceed to
|
||||
signing your app. This step is basically the same with other programs, but the
|
||||
key is to sign every dependency of Electron one by one.
|
||||
|
||||
First you need to prepare two entitlements files.
|
||||
First, you need to prepare two entitlements files.
|
||||
|
||||
`child.plist`:
|
||||
|
||||
|
@ -53,7 +53,7 @@ First you need to prepare two entitlements files.
|
|||
</plist>
|
||||
```
|
||||
|
||||
And then sign your app with following script:
|
||||
And then sign your app with the following script:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
@ -80,32 +80,33 @@ codesign -fs "$APP_KEY" --entitlements parent.plist "$APP_PATH"
|
|||
productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$APP_PATH"
|
||||
```
|
||||
|
||||
If you are new to app sandboxing of OS X, you should also go through Apple's
|
||||
[Enabling App Sandbox][enable-app-sandbox] to have a basic idea, and add keys
|
||||
for the permissions needed by your app to the entitlements files.
|
||||
If you are new to app sandboxing under OS X, you should also read through
|
||||
Apple's [Enabling App Sandbox][enable-app-sandbox] to have a basic idea, then
|
||||
add keys for the permissions needed by your app to the entitlements files.
|
||||
|
||||
### Upload your app and submit for review
|
||||
### Upload Your App and Submit for Review
|
||||
|
||||
After signing your app you can use Application Loader to upload it to iTunes
|
||||
Connect for processing, make sure you have [created a record][create-record]
|
||||
After signing your app, you can use Application Loader to upload it to iTunes
|
||||
Connect for processing, making sure you have [created a record][create-record]
|
||||
before uploading. Then you can [submit your app for review][submit-for-review].
|
||||
|
||||
## Limitations of MAS build
|
||||
## Limitations of MAS Build
|
||||
|
||||
In order to satisfy requirements for app sandboxing, following modules have been
|
||||
disabled in MAS build:
|
||||
In order to satisfy all requirements for app sandboxing, the following modules
|
||||
have been disabled in the MAS build:
|
||||
|
||||
* `crash-reporter`
|
||||
* `auto-updater`
|
||||
|
||||
and following behaviors have been changed:
|
||||
and the following behaviors have been changed:
|
||||
|
||||
* Video capture may not work for some machines.
|
||||
* Certain accessibility features may not work.
|
||||
* Apps will not be aware of DNS changes.
|
||||
|
||||
Also due to the usage of app sandboxing, the resources can be accessed by the
|
||||
app is strictly limited, you can read [App Sandboxing][app-sandboxing] for more.
|
||||
Also, due to the usage of app sandboxing, the resources which can be accessed by
|
||||
the app are strictly limited; you can read [App Sandboxing][app-sandboxing] for
|
||||
more information.
|
||||
|
||||
[submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html
|
||||
[nwjs-guide]: https://github.com/nwjs/nw.js/wiki/Mac-App-Store-%28MAS%29-Submission-Guideline#first-steps
|
||||
|
|
|
@ -107,7 +107,7 @@ app.on('ready', function() {
|
|||
mainWindow.loadUrl('file://' + __dirname + '/index.html');
|
||||
|
||||
// Open the DevTools.
|
||||
mainWindow.openDevTools();
|
||||
mainWindow.webContents.openDevTools();
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function() {
|
||||
|
@ -130,8 +130,9 @@ Finally the `index.html` is the web page you want to show:
|
|||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
We are using Node.js <script>document.write(process.version)</script>
|
||||
and Electron <script>document.write(process.versions['electron'])</script>.
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
@ -188,3 +189,19 @@ it from [here](https://github.com/atom/electron/releases).
|
|||
After you're done writing your app, you can create a distribution by
|
||||
following the [Application Distribution](./application-distribution.md) guide
|
||||
and then executing the packaged app.
|
||||
|
||||
### Try this Example
|
||||
|
||||
Clone and run the code in this tutorial by using the [`atom/electron-quick-start`](https://github.com/atom/electron-quick-start)
|
||||
repository.
|
||||
|
||||
**Note**: Running this requires [Git](https://git-scm.com) and [Node.js](https://nodejs.org/en/download/) (which includes [npm](https://npmjs.org)) on your system.
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
$ git clone https://github.com/atom/electron-quick-start
|
||||
# Go into the repository
|
||||
$ cd electron-quick-start
|
||||
# Install dependencies and run the app
|
||||
$ npm install && npm start
|
||||
```
|
||||
|
|
|
@ -31,8 +31,8 @@ which handles the manual steps of downloading headers and building native module
|
|||
```sh
|
||||
npm install --save-dev electron-rebuild
|
||||
|
||||
# Every time you run npm install, run this
|
||||
node ./node_modules/.bin/electron-rebuild
|
||||
# Every time you run "npm install", run this
|
||||
./node_modules/.bin/electron-rebuild
|
||||
```
|
||||
|
||||
### The npm Way
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue