commit
7d788cfa7a
68 changed files with 686 additions and 318 deletions
|
@ -1 +1 @@
|
||||||
v5.1.1
|
v5.10.0
|
||||||
|
|
|
@ -98,10 +98,6 @@ void AtomMainDelegate::PreSandboxStartup() {
|
||||||
std::string process_type = command_line->GetSwitchValueASCII(
|
std::string process_type = command_line->GetSwitchValueASCII(
|
||||||
switches::kProcessType);
|
switches::kProcessType);
|
||||||
|
|
||||||
if (process_type == switches::kUtilityProcess) {
|
|
||||||
AtomContentUtilityClient::PreSandboxStartup();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only append arguments for browser process.
|
// Only append arguments for browser process.
|
||||||
if (!IsBrowserProcess(command_line))
|
if (!IsBrowserProcess(command_line))
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -13,12 +13,15 @@
|
||||||
#include "atom/browser/atom_browser_client.h"
|
#include "atom/browser/atom_browser_client.h"
|
||||||
#include "atom/browser/atom_browser_context.h"
|
#include "atom/browser/atom_browser_context.h"
|
||||||
#include "atom/browser/atom_browser_main_parts.h"
|
#include "atom/browser/atom_browser_main_parts.h"
|
||||||
|
#include "atom/browser/atom_security_state_model_client.h"
|
||||||
#include "atom/browser/native_window.h"
|
#include "atom/browser/native_window.h"
|
||||||
|
#include "atom/browser/net/atom_network_delegate.h"
|
||||||
#include "atom/browser/web_contents_permission_helper.h"
|
#include "atom/browser/web_contents_permission_helper.h"
|
||||||
#include "atom/browser/web_contents_preferences.h"
|
#include "atom/browser/web_contents_preferences.h"
|
||||||
#include "atom/browser/web_view_guest_delegate.h"
|
#include "atom/browser/web_view_guest_delegate.h"
|
||||||
#include "atom/common/api/api_messages.h"
|
#include "atom/common/api/api_messages.h"
|
||||||
#include "atom/common/api/event_emitter_caller.h"
|
#include "atom/common/api/event_emitter_caller.h"
|
||||||
|
#include "atom/common/color_util.h"
|
||||||
#include "atom/common/mouse_util.h"
|
#include "atom/common/mouse_util.h"
|
||||||
#include "atom/common/native_mate_converters/blink_converter.h"
|
#include "atom/common/native_mate_converters/blink_converter.h"
|
||||||
#include "atom/common/native_mate_converters/callback.h"
|
#include "atom/common/native_mate_converters/callback.h"
|
||||||
|
@ -276,6 +279,8 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||||
|
|
||||||
// Intialize permission helper.
|
// Intialize permission helper.
|
||||||
WebContentsPermissionHelper::CreateForWebContents(web_contents);
|
WebContentsPermissionHelper::CreateForWebContents(web_contents);
|
||||||
|
// Intialize security state client.
|
||||||
|
AtomSecurityStateModelClient::CreateForWebContents(web_contents);
|
||||||
|
|
||||||
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
|
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
|
||||||
|
|
||||||
|
@ -546,28 +551,21 @@ void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host,
|
||||||
void WebContents::DidFailProvisionalLoad(
|
void WebContents::DidFailProvisionalLoad(
|
||||||
content::RenderFrameHost* render_frame_host,
|
content::RenderFrameHost* render_frame_host,
|
||||||
const GURL& url,
|
const GURL& url,
|
||||||
int error_code,
|
int code,
|
||||||
const base::string16& error_description,
|
const base::string16& description,
|
||||||
bool was_ignored_by_handler) {
|
bool was_ignored_by_handler) {
|
||||||
bool is_main_frame = !render_frame_host->GetParent();
|
bool is_main_frame = !render_frame_host->GetParent();
|
||||||
Emit("did-fail-provisional-load",
|
Emit("did-fail-provisional-load", code, description, url, is_main_frame);
|
||||||
error_code,
|
Emit("did-fail-load", code, description, url, is_main_frame);
|
||||||
error_description,
|
|
||||||
url,
|
|
||||||
is_main_frame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host,
|
void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host,
|
||||||
const GURL& validated_url,
|
const GURL& url,
|
||||||
int error_code,
|
int error_code,
|
||||||
const base::string16& error_description,
|
const base::string16& error_description,
|
||||||
bool was_ignored_by_handler) {
|
bool was_ignored_by_handler) {
|
||||||
bool is_main_frame = !render_frame_host->GetParent();
|
bool is_main_frame = !render_frame_host->GetParent();
|
||||||
Emit("did-fail-load",
|
Emit("did-fail-load", error_code, error_description, url, is_main_frame);
|
||||||
error_code,
|
|
||||||
error_description,
|
|
||||||
validated_url,
|
|
||||||
is_main_frame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::DidStartLoading() {
|
void WebContents::DidStartLoading() {
|
||||||
|
@ -587,7 +585,8 @@ void WebContents::DidGetResourceResponseStart(
|
||||||
details.http_response_code,
|
details.http_response_code,
|
||||||
details.method,
|
details.method,
|
||||||
details.referrer,
|
details.referrer,
|
||||||
details.headers.get());
|
details.headers.get(),
|
||||||
|
ResourceTypeToString(details.resource_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::DidGetRedirectForResourceRequest(
|
void WebContents::DidGetRedirectForResourceRequest(
|
||||||
|
@ -633,6 +632,10 @@ void WebContents::DidUpdateFaviconURL(
|
||||||
Emit("page-favicon-updated", unique_urls);
|
Emit("page-favicon-updated", unique_urls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebContents::DevToolsReloadPage() {
|
||||||
|
Emit("devtools-reload-page");
|
||||||
|
}
|
||||||
|
|
||||||
void WebContents::DevToolsFocused() {
|
void WebContents::DevToolsFocused() {
|
||||||
Emit("devtools-focused");
|
Emit("devtools-focused");
|
||||||
}
|
}
|
||||||
|
@ -748,12 +751,19 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
|
||||||
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
|
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
|
||||||
web_contents()->GetController().LoadURLWithParams(params);
|
web_contents()->GetController().LoadURLWithParams(params);
|
||||||
|
|
||||||
// Set the background color of RenderViewHost to transparent so it doesn't
|
// Set the background color of RenderWidgetHostView.
|
||||||
// override the background color set by the user.
|
|
||||||
// We have to call it right after LoadURL because the RenderViewHost is only
|
// We have to call it right after LoadURL because the RenderViewHost is only
|
||||||
// created after loading a page.
|
// created after loading a page.
|
||||||
const auto view = web_contents()->GetRenderWidgetHostView();
|
const auto view = web_contents()->GetRenderWidgetHostView();
|
||||||
view->SetBackgroundColor(SK_ColorTRANSPARENT);
|
WebContentsPreferences* web_preferences =
|
||||||
|
WebContentsPreferences::FromWebContents(web_contents());
|
||||||
|
std::string color_name;
|
||||||
|
if (web_preferences->web_preferences()->GetString(options::kBackgroundColor,
|
||||||
|
&color_name)) {
|
||||||
|
view->SetBackgroundColor(ParseHexColor(color_name));
|
||||||
|
} else {
|
||||||
|
view->SetBackgroundColor(SK_ColorTRANSPARENT);
|
||||||
|
}
|
||||||
|
|
||||||
// For the same reason we can only disable hidden here.
|
// For the same reason we can only disable hidden here.
|
||||||
const auto host = static_cast<content::RenderWidgetHostImpl*>(
|
const auto host = static_cast<content::RenderWidgetHostImpl*>(
|
||||||
|
|
|
@ -251,6 +251,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
void MediaStoppedPlaying(const MediaPlayerId& id) override;
|
void MediaStoppedPlaying(const MediaPlayerId& id) override;
|
||||||
void DidChangeThemeColor(SkColor theme_color) override;
|
void DidChangeThemeColor(SkColor theme_color) override;
|
||||||
|
|
||||||
|
// brightray::InspectableWebContentsDelegate:
|
||||||
|
void DevToolsReloadPage() override;
|
||||||
|
|
||||||
// brightray::InspectableWebContentsViewDelegate:
|
// brightray::InspectableWebContentsViewDelegate:
|
||||||
void DevToolsFocused() override;
|
void DevToolsFocused() override;
|
||||||
void DevToolsOpened() override;
|
void DevToolsOpened() override;
|
||||||
|
|
|
@ -136,9 +136,8 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
|
||||||
// Start idle gc.
|
// Start idle gc.
|
||||||
gc_timer_.Start(
|
gc_timer_.Start(
|
||||||
FROM_HERE, base::TimeDelta::FromMinutes(1),
|
FROM_HERE, base::TimeDelta::FromMinutes(1),
|
||||||
base::Bind(base::IgnoreResult(&v8::Isolate::IdleNotification),
|
base::Bind(&v8::Isolate::LowMemoryNotification,
|
||||||
base::Unretained(js_env_->isolate()),
|
base::Unretained(js_env_->isolate())));
|
||||||
1000));
|
|
||||||
|
|
||||||
brightray::BrowserMainParts::PreMainMessageLoopRun();
|
brightray::BrowserMainParts::PreMainMessageLoopRun();
|
||||||
bridge_task_runner_->MessageLoopIsReady();
|
bridge_task_runner_->MessageLoopIsReady();
|
||||||
|
|
105
atom/browser/atom_security_state_model_client.cc
Normal file
105
atom/browser/atom_security_state_model_client.cc
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
// Copyright (c) 2016 GitHub, Inc.
|
||||||
|
// Use of this source code is governed by the MIT license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "atom/browser/atom_security_state_model_client.h"
|
||||||
|
|
||||||
|
#include "content/public/browser/cert_store.h"
|
||||||
|
#include "content/public/browser/navigation_entry.h"
|
||||||
|
#include "content/public/browser/web_contents.h"
|
||||||
|
#include "content/public/common/origin_util.h"
|
||||||
|
#include "content/public/common/ssl_status.h"
|
||||||
|
#include "net/cert/x509_certificate.h"
|
||||||
|
|
||||||
|
DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::AtomSecurityStateModelClient);
|
||||||
|
|
||||||
|
using security_state::SecurityStateModel;
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
SecurityStateModel::SecurityLevel GetSecurityLevelForSecurityStyle(
|
||||||
|
content::SecurityStyle style) {
|
||||||
|
switch (style) {
|
||||||
|
case content::SECURITY_STYLE_UNKNOWN:
|
||||||
|
return SecurityStateModel::NONE;
|
||||||
|
case content::SECURITY_STYLE_UNAUTHENTICATED:
|
||||||
|
return SecurityStateModel::NONE;
|
||||||
|
case content::SECURITY_STYLE_AUTHENTICATION_BROKEN:
|
||||||
|
return SecurityStateModel::SECURITY_ERROR;
|
||||||
|
case content::SECURITY_STYLE_WARNING:
|
||||||
|
return SecurityStateModel::SECURITY_WARNING;
|
||||||
|
case content::SECURITY_STYLE_AUTHENTICATED:
|
||||||
|
return SecurityStateModel::SECURE;
|
||||||
|
}
|
||||||
|
return SecurityStateModel::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
AtomSecurityStateModelClient::AtomSecurityStateModelClient(
|
||||||
|
content::WebContents* web_contents)
|
||||||
|
: web_contents_(web_contents),
|
||||||
|
security_state_model_(new SecurityStateModel()) {
|
||||||
|
security_state_model_->SetClient(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
AtomSecurityStateModelClient::~AtomSecurityStateModelClient() {
|
||||||
|
}
|
||||||
|
|
||||||
|
const SecurityStateModel::SecurityInfo&
|
||||||
|
AtomSecurityStateModelClient::GetSecurityInfo() const {
|
||||||
|
return security_state_model_->GetSecurityInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AtomSecurityStateModelClient::RetrieveCert(
|
||||||
|
scoped_refptr<net::X509Certificate>* cert) {
|
||||||
|
content::NavigationEntry* entry =
|
||||||
|
web_contents_->GetController().GetVisibleEntry();
|
||||||
|
if (!entry)
|
||||||
|
return false;
|
||||||
|
return content::CertStore::GetInstance()->RetrieveCert(
|
||||||
|
entry->GetSSL().cert_id, cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AtomSecurityStateModelClient::UsedPolicyInstalledCertificate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AtomSecurityStateModelClient::IsOriginSecure(const GURL& url) {
|
||||||
|
return content::IsOriginSecure(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AtomSecurityStateModelClient::GetVisibleSecurityState(
|
||||||
|
SecurityStateModel::VisibleSecurityState* state) {
|
||||||
|
content::NavigationEntry* entry =
|
||||||
|
web_contents_->GetController().GetVisibleEntry();
|
||||||
|
if (!entry ||
|
||||||
|
entry->GetSSL().security_style == content::SECURITY_STYLE_UNKNOWN) {
|
||||||
|
*state = SecurityStateModel::VisibleSecurityState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->initialized = true;
|
||||||
|
state->url = entry->GetURL();
|
||||||
|
const content::SSLStatus& ssl = entry->GetSSL();
|
||||||
|
state->initial_security_level =
|
||||||
|
GetSecurityLevelForSecurityStyle(ssl.security_style);
|
||||||
|
state->cert_id = ssl.cert_id;
|
||||||
|
state->cert_status = ssl.cert_status;
|
||||||
|
state->connection_status = ssl.connection_status;
|
||||||
|
state->security_bits = ssl.security_bits;
|
||||||
|
state->sct_verify_statuses.clear();
|
||||||
|
for (const auto& sct : ssl.signed_certificate_timestamp_ids)
|
||||||
|
state->sct_verify_statuses.push_back(sct.status);
|
||||||
|
state->displayed_mixed_content =
|
||||||
|
(ssl.content_status & content::SSLStatus::DISPLAYED_INSECURE_CONTENT)
|
||||||
|
? true
|
||||||
|
: false;
|
||||||
|
state->ran_mixed_content =
|
||||||
|
(ssl.content_status & content::SSLStatus::RAN_INSECURE_CONTENT) ? true
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace atom
|
42
atom/browser/atom_security_state_model_client.h
Normal file
42
atom/browser/atom_security_state_model_client.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright (c) 2016 GitHub, Inc.
|
||||||
|
// Use of this source code is governed by the MIT license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef ATOM_BROWSER_ATOM_SECURITY_STATE_MODEL_CLIENT_H_
|
||||||
|
#define ATOM_BROWSER_ATOM_SECURITY_STATE_MODEL_CLIENT_H_
|
||||||
|
|
||||||
|
#include "components/security_state/security_state_model.h"
|
||||||
|
#include "components/security_state/security_state_model_client.h"
|
||||||
|
#include "content/public/browser/web_contents_user_data.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
class AtomSecurityStateModelClient
|
||||||
|
: public security_state::SecurityStateModelClient,
|
||||||
|
public content::WebContentsUserData<AtomSecurityStateModelClient> {
|
||||||
|
public:
|
||||||
|
~AtomSecurityStateModelClient() override;
|
||||||
|
|
||||||
|
const security_state::SecurityStateModel::SecurityInfo&
|
||||||
|
GetSecurityInfo() const;
|
||||||
|
|
||||||
|
// security_state::SecurityStateModelClient:
|
||||||
|
void GetVisibleSecurityState(
|
||||||
|
security_state::SecurityStateModel::VisibleSecurityState* state) override;
|
||||||
|
bool RetrieveCert(scoped_refptr<net::X509Certificate>* cert) override;
|
||||||
|
bool UsedPolicyInstalledCertificate() override;
|
||||||
|
bool IsOriginSecure(const GURL& url) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit AtomSecurityStateModelClient(content::WebContents* web_contents);
|
||||||
|
friend class content::WebContentsUserData<AtomSecurityStateModelClient>;
|
||||||
|
|
||||||
|
content::WebContents* web_contents_;
|
||||||
|
scoped_ptr<security_state::SecurityStateModel> security_state_model_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(AtomSecurityStateModelClient);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
#endif // ATOM_BROWSER_ATOM_SECURITY_STATE_MODEL_CLIENT_H_
|
|
@ -10,9 +10,11 @@
|
||||||
|
|
||||||
#include "atom/browser/atom_browser_context.h"
|
#include "atom/browser/atom_browser_context.h"
|
||||||
#include "atom/browser/atom_javascript_dialog_manager.h"
|
#include "atom/browser/atom_javascript_dialog_manager.h"
|
||||||
|
#include "atom/browser/atom_security_state_model_client.h"
|
||||||
#include "atom/browser/native_window.h"
|
#include "atom/browser/native_window.h"
|
||||||
#include "atom/browser/ui/file_dialog.h"
|
#include "atom/browser/ui/file_dialog.h"
|
||||||
#include "atom/browser/web_dialog_helper.h"
|
#include "atom/browser/web_dialog_helper.h"
|
||||||
|
#include "atom/common/atom_constants.h"
|
||||||
#include "base/files/file_util.h"
|
#include "base/files/file_util.h"
|
||||||
#include "base/prefs/pref_service.h"
|
#include "base/prefs/pref_service.h"
|
||||||
#include "base/prefs/scoped_user_pref_update.h"
|
#include "base/prefs/scoped_user_pref_update.h"
|
||||||
|
@ -25,6 +27,8 @@
|
||||||
#include "content/public/browser/render_process_host.h"
|
#include "content/public/browser/render_process_host.h"
|
||||||
#include "content/public/browser/render_view_host.h"
|
#include "content/public/browser/render_view_host.h"
|
||||||
#include "content/public/browser/render_widget_host.h"
|
#include "content/public/browser/render_widget_host.h"
|
||||||
|
#include "content/public/browser/security_style_explanation.h"
|
||||||
|
#include "content/public/browser/security_style_explanations.h"
|
||||||
#include "storage/browser/fileapi/isolated_context.h"
|
#include "storage/browser/fileapi/isolated_context.h"
|
||||||
|
|
||||||
#if defined(TOOLKIT_VIEWS)
|
#if defined(TOOLKIT_VIEWS)
|
||||||
|
@ -36,6 +40,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using content::BrowserThread;
|
using content::BrowserThread;
|
||||||
|
using security_state::SecurityStateModel;
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
|
@ -140,6 +145,24 @@ std::set<std::string> GetAddedFileSystemPaths(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
content::SecurityStyle SecurityLevelToSecurityStyle(
|
||||||
|
SecurityStateModel::SecurityLevel security_level) {
|
||||||
|
switch (security_level) {
|
||||||
|
case SecurityStateModel::NONE:
|
||||||
|
return content::SECURITY_STYLE_UNAUTHENTICATED;
|
||||||
|
case SecurityStateModel::SECURITY_WARNING:
|
||||||
|
case SecurityStateModel::SECURITY_POLICY_WARNING:
|
||||||
|
return content::SECURITY_STYLE_WARNING;
|
||||||
|
case SecurityStateModel::EV_SECURE:
|
||||||
|
case SecurityStateModel::SECURE:
|
||||||
|
return content::SECURITY_STYLE_AUTHENTICATED;
|
||||||
|
case SecurityStateModel::SECURITY_ERROR:
|
||||||
|
return content::SECURITY_STYLE_AUTHENTICATION_BROKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return content::SECURITY_STYLE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
CommonWebContentsDelegate::CommonWebContentsDelegate()
|
CommonWebContentsDelegate::CommonWebContentsDelegate()
|
||||||
|
@ -265,6 +288,90 @@ bool CommonWebContentsDelegate::IsFullscreenForTabOrPending(
|
||||||
return html_fullscreen_;
|
return html_fullscreen_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
content::SecurityStyle CommonWebContentsDelegate::GetSecurityStyle(
|
||||||
|
content::WebContents* web_contents,
|
||||||
|
content::SecurityStyleExplanations* explanations) {
|
||||||
|
auto model_client =
|
||||||
|
AtomSecurityStateModelClient::FromWebContents(web_contents);
|
||||||
|
|
||||||
|
const SecurityStateModel::SecurityInfo& security_info =
|
||||||
|
model_client->GetSecurityInfo();
|
||||||
|
|
||||||
|
const content::SecurityStyle security_style =
|
||||||
|
SecurityLevelToSecurityStyle(security_info.security_level);
|
||||||
|
|
||||||
|
explanations->ran_insecure_content_style =
|
||||||
|
SecurityLevelToSecurityStyle(
|
||||||
|
SecurityStateModel::kRanInsecureContentLevel);
|
||||||
|
explanations->displayed_insecure_content_style =
|
||||||
|
SecurityLevelToSecurityStyle(
|
||||||
|
SecurityStateModel::kDisplayedInsecureContentLevel);
|
||||||
|
|
||||||
|
explanations->scheme_is_cryptographic = security_info.scheme_is_cryptographic;
|
||||||
|
if (!security_info.scheme_is_cryptographic)
|
||||||
|
return security_style;
|
||||||
|
|
||||||
|
if (security_info.sha1_deprecation_status ==
|
||||||
|
SecurityStateModel::DEPRECATED_SHA1_MAJOR) {
|
||||||
|
explanations->broken_explanations.push_back(
|
||||||
|
content::SecurityStyleExplanation(
|
||||||
|
kSHA1Certificate,
|
||||||
|
kSHA1MajorDescription,
|
||||||
|
security_info.cert_id));
|
||||||
|
} else if (security_info.sha1_deprecation_status ==
|
||||||
|
SecurityStateModel::DEPRECATED_SHA1_MINOR) {
|
||||||
|
explanations->unauthenticated_explanations.push_back(
|
||||||
|
content::SecurityStyleExplanation(
|
||||||
|
kSHA1Certificate,
|
||||||
|
kSHA1MinorDescription,
|
||||||
|
security_info.cert_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
explanations->ran_insecure_content =
|
||||||
|
security_info.mixed_content_status ==
|
||||||
|
SecurityStateModel::RAN_MIXED_CONTENT ||
|
||||||
|
security_info.mixed_content_status ==
|
||||||
|
SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT;
|
||||||
|
explanations->displayed_insecure_content =
|
||||||
|
security_info.mixed_content_status ==
|
||||||
|
SecurityStateModel::DISPLAYED_MIXED_CONTENT ||
|
||||||
|
security_info.mixed_content_status ==
|
||||||
|
SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT;
|
||||||
|
|
||||||
|
if (net::IsCertStatusError(security_info.cert_status)) {
|
||||||
|
std::string error_string = net::ErrorToString(
|
||||||
|
net::MapCertStatusToNetError(security_info.cert_status));
|
||||||
|
|
||||||
|
content::SecurityStyleExplanation explanation(
|
||||||
|
kCertificateError,
|
||||||
|
"There are issues with the site's certificate chain " + error_string,
|
||||||
|
security_info.cert_id);
|
||||||
|
|
||||||
|
if (net::IsCertStatusMinorError(security_info.cert_status))
|
||||||
|
explanations->unauthenticated_explanations.push_back(explanation);
|
||||||
|
else
|
||||||
|
explanations->broken_explanations.push_back(explanation);
|
||||||
|
} else {
|
||||||
|
if (security_info.sha1_deprecation_status ==
|
||||||
|
SecurityStateModel::NO_DEPRECATED_SHA1) {
|
||||||
|
explanations->secure_explanations.push_back(
|
||||||
|
content::SecurityStyleExplanation(
|
||||||
|
kValidCertificate,
|
||||||
|
kValidCertificateDescription,
|
||||||
|
security_info.cert_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (security_info.is_secure_protocol_and_ciphersuite) {
|
||||||
|
explanations->secure_explanations.push_back(
|
||||||
|
content::SecurityStyleExplanation(
|
||||||
|
kSecureProtocol,
|
||||||
|
kSecureProtocolDescription));
|
||||||
|
}
|
||||||
|
|
||||||
|
return security_style;
|
||||||
|
}
|
||||||
|
|
||||||
void CommonWebContentsDelegate::DevToolsSaveToFile(
|
void CommonWebContentsDelegate::DevToolsSaveToFile(
|
||||||
const std::string& url, const std::string& content, bool save_as) {
|
const std::string& url, const std::string& content, bool save_as) {
|
||||||
base::FilePath path;
|
base::FilePath path;
|
||||||
|
|
|
@ -76,6 +76,9 @@ class CommonWebContentsDelegate
|
||||||
void ExitFullscreenModeForTab(content::WebContents* source) override;
|
void ExitFullscreenModeForTab(content::WebContents* source) override;
|
||||||
bool IsFullscreenForTabOrPending(
|
bool IsFullscreenForTabOrPending(
|
||||||
const content::WebContents* source) const override;
|
const content::WebContents* source) const override;
|
||||||
|
content::SecurityStyle GetSecurityStyle(
|
||||||
|
content::WebContents* web_contents,
|
||||||
|
content::SecurityStyleExplanations* explanations) override;
|
||||||
|
|
||||||
// brightray::InspectableWebContentsDelegate:
|
// brightray::InspectableWebContentsDelegate:
|
||||||
void DevToolsSaveToFile(const std::string& url,
|
void DevToolsSaveToFile(const std::string& url,
|
||||||
|
|
|
@ -162,8 +162,8 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
|
||||||
std::string color;
|
std::string color;
|
||||||
if (options.Get(options::kBackgroundColor, &color)) {
|
if (options.Get(options::kBackgroundColor, &color)) {
|
||||||
SetBackgroundColor(color);
|
SetBackgroundColor(color);
|
||||||
} else if (has_frame()) {
|
} else if (!transparent()) {
|
||||||
// For window with frame, use white as default background.
|
// For normal window, use white as default background.
|
||||||
SetBackgroundColor("#FFFF");
|
SetBackgroundColor("#FFFF");
|
||||||
}
|
}
|
||||||
std::string title("Electron");
|
std::string title("Electron");
|
||||||
|
|
|
@ -807,9 +807,14 @@ bool NativeWindowMac::IsKiosk() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeWindowMac::SetBackgroundColor(const std::string& color_name) {
|
void NativeWindowMac::SetBackgroundColor(const std::string& color_name) {
|
||||||
base::ScopedCFTypeRef<CGColorRef> color =
|
SkColor color = ParseHexColor(color_name);
|
||||||
skia::CGColorCreateFromSkColor(ParseHexColor(color_name));
|
base::ScopedCFTypeRef<CGColorRef> cgcolor =
|
||||||
[[[window_ contentView] layer] setBackgroundColor:color];
|
skia::CGColorCreateFromSkColor(color);
|
||||||
|
[[[window_ contentView] layer] setBackgroundColor:cgcolor];
|
||||||
|
|
||||||
|
const auto view = web_contents()->GetRenderWidgetHostView();
|
||||||
|
if (view)
|
||||||
|
view->SetBackgroundColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeWindowMac::SetHasShadow(bool has_shadow) {
|
void NativeWindowMac::SetHasShadow(bool has_shadow) {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "brightray/browser/inspectable_web_contents.h"
|
#include "brightray/browser/inspectable_web_contents.h"
|
||||||
#include "brightray/browser/inspectable_web_contents_view.h"
|
#include "brightray/browser/inspectable_web_contents_view.h"
|
||||||
|
#include "content/public/browser/browser_thread.h"
|
||||||
#include "content/public/browser/native_web_keyboard_event.h"
|
#include "content/public/browser/native_web_keyboard_event.h"
|
||||||
#include "native_mate/dictionary.h"
|
#include "native_mate/dictionary.h"
|
||||||
#include "ui/aura/window_tree_host.h"
|
#include "ui/aura/window_tree_host.h"
|
||||||
|
@ -780,10 +781,12 @@ void NativeWindowViews::OnWidgetActivationChanged(
|
||||||
if (widget != window_.get())
|
if (widget != window_.get())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (active)
|
// Post the notification to next tick.
|
||||||
NotifyWindowFocus();
|
content::BrowserThread::PostTask(
|
||||||
else
|
content::BrowserThread::UI, FROM_HERE,
|
||||||
NotifyWindowBlur();
|
base::Bind(active ? &NativeWindow::NotifyWindowFocus :
|
||||||
|
&NativeWindow::NotifyWindowBlur,
|
||||||
|
GetWeakPtr()));
|
||||||
|
|
||||||
if (active && inspectable_web_contents() &&
|
if (active && inspectable_web_contents() &&
|
||||||
!inspectable_web_contents()->IsDevToolsViewShowing())
|
!inspectable_web_contents()->IsDevToolsViewShowing())
|
||||||
|
|
|
@ -5,20 +5,18 @@
|
||||||
#include "atom/browser/net/atom_network_delegate.h"
|
#include "atom/browser/net/atom_network_delegate.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "atom/common/native_mate_converters/net_converter.h"
|
#include "atom/common/native_mate_converters/net_converter.h"
|
||||||
#include "base/stl_util.h"
|
#include "base/stl_util.h"
|
||||||
#include "base/strings/string_util.h"
|
#include "base/strings/string_util.h"
|
||||||
#include "content/public/browser/browser_thread.h"
|
#include "content/public/browser/browser_thread.h"
|
||||||
#include "content/public/browser/resource_request_info.h"
|
|
||||||
#include "net/url_request/url_request.h"
|
#include "net/url_request/url_request.h"
|
||||||
|
|
||||||
using content::BrowserThread;
|
using content::BrowserThread;
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
const char* ResourceTypeToString(content::ResourceType type) {
|
const char* ResourceTypeToString(content::ResourceType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case content::RESOURCE_TYPE_MAIN_FRAME:
|
case content::RESOURCE_TYPE_MAIN_FRAME:
|
||||||
|
@ -40,6 +38,11 @@ const char* ResourceTypeToString(content::ResourceType type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using ResponseHeadersContainer =
|
||||||
|
std::pair<scoped_refptr<net::HttpResponseHeaders>*, const std::string&>;
|
||||||
|
|
||||||
void RunSimpleListener(const AtomNetworkDelegate::SimpleListener& listener,
|
void RunSimpleListener(const AtomNetworkDelegate::SimpleListener& listener,
|
||||||
scoped_ptr<base::DictionaryValue> details) {
|
scoped_ptr<base::DictionaryValue> details) {
|
||||||
return listener.Run(*(details.get()));
|
return listener.Run(*(details.get()));
|
||||||
|
@ -170,10 +173,15 @@ void ReadFromResponseObject(const base::DictionaryValue& response,
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadFromResponseObject(const base::DictionaryValue& response,
|
void ReadFromResponseObject(const base::DictionaryValue& response,
|
||||||
scoped_refptr<net::HttpResponseHeaders>* headers) {
|
const ResponseHeadersContainer& container) {
|
||||||
const base::DictionaryValue* dict;
|
const base::DictionaryValue* dict;
|
||||||
|
std::string status_line;
|
||||||
|
if (!response.GetString("statusLine", &status_line))
|
||||||
|
status_line = container.second;
|
||||||
if (response.GetDictionary("responseHeaders", &dict)) {
|
if (response.GetDictionary("responseHeaders", &dict)) {
|
||||||
|
auto headers = container.first;
|
||||||
*headers = new net::HttpResponseHeaders("");
|
*headers = new net::HttpResponseHeaders("");
|
||||||
|
(*headers)->ReplaceStatusLine(status_line);
|
||||||
for (base::DictionaryValue::Iterator it(*dict);
|
for (base::DictionaryValue::Iterator it(*dict);
|
||||||
!it.IsAtEnd();
|
!it.IsAtEnd();
|
||||||
it.Advance()) {
|
it.Advance()) {
|
||||||
|
@ -263,7 +271,8 @@ int AtomNetworkDelegate::OnHeadersReceived(
|
||||||
request, callback, original, override, allowed);
|
request, callback, original, override, allowed);
|
||||||
|
|
||||||
return HandleResponseEvent(
|
return HandleResponseEvent(
|
||||||
kOnHeadersReceived, request, callback, override, original);
|
kOnHeadersReceived, request, callback,
|
||||||
|
std::make_pair(override, original->GetStatusLine()), original);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtomNetworkDelegate::OnBeforeRedirect(net::URLRequest* request,
|
void AtomNetworkDelegate::OnBeforeRedirect(net::URLRequest* request,
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "net/base/net_errors.h"
|
#include "net/base/net_errors.h"
|
||||||
#include "net/http/http_request_headers.h"
|
#include "net/http/http_request_headers.h"
|
||||||
#include "net/http/http_response_headers.h"
|
#include "net/http/http_response_headers.h"
|
||||||
|
#include "content/public/browser/resource_request_info.h"
|
||||||
|
|
||||||
namespace extensions {
|
namespace extensions {
|
||||||
class URLPattern;
|
class URLPattern;
|
||||||
|
@ -24,6 +25,8 @@ namespace atom {
|
||||||
|
|
||||||
using URLPatterns = std::set<extensions::URLPattern>;
|
using URLPatterns = std::set<extensions::URLPattern>;
|
||||||
|
|
||||||
|
const char* ResourceTypeToString(content::ResourceType type);
|
||||||
|
|
||||||
class AtomNetworkDelegate : public brightray::NetworkDelegate {
|
class AtomNetworkDelegate : public brightray::NetworkDelegate {
|
||||||
public:
|
public:
|
||||||
using ResponseCallback = base::Callback<void(const base::DictionaryValue&)>;
|
using ResponseCallback = base::Callback<void(const base::DictionaryValue&)>;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "atom/browser/native_window.h"
|
||||||
#include "atom/common/native_mate_converters/value_converter.h"
|
#include "atom/common/native_mate_converters/value_converter.h"
|
||||||
#include "atom/common/options_switches.h"
|
#include "atom/common/options_switches.h"
|
||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
|
@ -131,20 +132,28 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches(
|
||||||
// --guest-instance-id, which is used to identify guest WebContents.
|
// --guest-instance-id, which is used to identify guest WebContents.
|
||||||
int guest_instance_id;
|
int guest_instance_id;
|
||||||
if (web_preferences.GetInteger(options::kGuestInstanceID, &guest_instance_id))
|
if (web_preferences.GetInteger(options::kGuestInstanceID, &guest_instance_id))
|
||||||
command_line->AppendSwitchASCII(switches::kGuestInstanceID,
|
command_line->AppendSwitchASCII(switches::kGuestInstanceID,
|
||||||
base::IntToString(guest_instance_id));
|
base::IntToString(guest_instance_id));
|
||||||
|
|
||||||
// Pass the opener's window id.
|
// Pass the opener's window id.
|
||||||
int opener_id;
|
int opener_id;
|
||||||
if (web_preferences.GetInteger(options::kOpenerID, &opener_id))
|
if (web_preferences.GetInteger(options::kOpenerID, &opener_id))
|
||||||
command_line->AppendSwitchASCII(switches::kOpenerID,
|
command_line->AppendSwitchASCII(switches::kOpenerID,
|
||||||
base::IntToString(opener_id));
|
base::IntToString(opener_id));
|
||||||
|
|
||||||
// Enable blink features.
|
// Enable blink features.
|
||||||
std::string blink_features;
|
std::string blink_features;
|
||||||
if (web_preferences.GetString(options::kBlinkFeatures, &blink_features))
|
if (web_preferences.GetString(options::kBlinkFeatures, &blink_features))
|
||||||
command_line->AppendSwitchASCII(::switches::kEnableBlinkFeatures,
|
command_line->AppendSwitchASCII(::switches::kEnableBlinkFeatures,
|
||||||
blink_features);
|
blink_features);
|
||||||
|
|
||||||
|
// The initial visibility state.
|
||||||
|
NativeWindow* window = NativeWindow::FromWebContents(web_contents);
|
||||||
|
if (window) {
|
||||||
|
bool visible = window->IsVisible() && !window->IsMinimized();
|
||||||
|
if (!visible) // Default state is visible.
|
||||||
|
command_line->AppendSwitch("hidden-page");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|
|
@ -6,6 +6,22 @@
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
const char* kCORSHeader = "Access-Control-Allow-Origin: *";
|
const char kCORSHeader[] = "Access-Control-Allow-Origin: *";
|
||||||
|
|
||||||
|
const char kSHA1Certificate[] = "SHA-1 Certificate";
|
||||||
|
const char kSHA1MajorDescription[] =
|
||||||
|
"The certificate for this site expires in 2017 or later, "
|
||||||
|
"and the certificate chain contains a certificate signed using SHA-1.";
|
||||||
|
const char kSHA1MinorDescription[] =
|
||||||
|
"The certificate for this site expires in 2016, "
|
||||||
|
"and the certificate chain contains a certificate signed using SHA-1.";
|
||||||
|
const char kCertificateError[] = "Certificate Error";
|
||||||
|
const char kValidCertificate[] = "Valid Certificate";
|
||||||
|
const char kValidCertificateDescription[] =
|
||||||
|
"The connection to this site is using a valid, trusted server certificate.";
|
||||||
|
const char kSecureProtocol[] = "Secure TLS connection";
|
||||||
|
const char kSecureProtocolDescription[] =
|
||||||
|
"The connection to this site is using a strong protocol version "
|
||||||
|
"and cipher suite.";
|
||||||
|
|
||||||
} // namespace atom
|
} // namespace atom
|
||||||
|
|
|
@ -8,7 +8,17 @@
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
// Header to ignore CORS.
|
// Header to ignore CORS.
|
||||||
extern const char* kCORSHeader;
|
extern const char kCORSHeader[];
|
||||||
|
|
||||||
|
// Strings describing Chrome security policy for DevTools security panel.
|
||||||
|
extern const char kSHA1Certificate[];
|
||||||
|
extern const char kSHA1MajorDescription[];
|
||||||
|
extern const char kSHA1MinorDescription[];
|
||||||
|
extern const char kCertificateError[];
|
||||||
|
extern const char kValidCertificate[];
|
||||||
|
extern const char kValidCertificateDescription[];
|
||||||
|
extern const char kSecureProtocol[];
|
||||||
|
extern const char kSecureProtocolDescription[];
|
||||||
|
|
||||||
} // namespace atom
|
} // namespace atom
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,9 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool XDGUtil(const std::string& util, const std::string& arg) {
|
bool XDGUtil(const std::string& util,
|
||||||
|
const std::string& arg,
|
||||||
|
const bool wait_for_exit) {
|
||||||
std::vector<std::string> argv;
|
std::vector<std::string> argv;
|
||||||
argv.push_back(util);
|
argv.push_back(util);
|
||||||
argv.push_back(arg);
|
argv.push_back(arg);
|
||||||
|
@ -30,6 +32,11 @@ bool XDGUtil(const std::string& util, const std::string& arg) {
|
||||||
if (!process.IsValid())
|
if (!process.IsValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!wait_for_exit) {
|
||||||
|
base::EnsureProcessGetsReaped(process.Pid());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int exit_code = -1;
|
int exit_code = -1;
|
||||||
if (!process.WaitForExit(&exit_code))
|
if (!process.WaitForExit(&exit_code))
|
||||||
return false;
|
return false;
|
||||||
|
@ -37,12 +44,12 @@ bool XDGUtil(const std::string& util, const std::string& arg) {
|
||||||
return (exit_code == 0);
|
return (exit_code == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XDGOpen(const std::string& path) {
|
bool XDGOpen(const std::string& path, const bool wait_for_exit) {
|
||||||
return XDGUtil("xdg-open", path);
|
return XDGUtil("xdg-open", path, wait_for_exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XDGEmail(const std::string& email) {
|
bool XDGEmail(const std::string& email, const bool wait_for_exit) {
|
||||||
return XDGUtil("xdg-email", email);
|
return XDGUtil("xdg-email", email, wait_for_exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -57,22 +64,24 @@ void ShowItemInFolder(const base::FilePath& full_path) {
|
||||||
if (!base::DirectoryExists(dir))
|
if (!base::DirectoryExists(dir))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
XDGOpen(dir.value());
|
XDGOpen(dir.value(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenItem(const base::FilePath& full_path) {
|
void OpenItem(const base::FilePath& full_path) {
|
||||||
XDGOpen(full_path.value());
|
XDGOpen(full_path.value(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenExternal(const GURL& url, bool activate) {
|
bool OpenExternal(const GURL& url, bool activate) {
|
||||||
|
// Don't wait for exit, since we don't want to wait for the browser/email
|
||||||
|
// client window to close before returning
|
||||||
if (url.SchemeIs("mailto"))
|
if (url.SchemeIs("mailto"))
|
||||||
return XDGEmail(url.spec());
|
return XDGEmail(url.spec(), false);
|
||||||
else
|
else
|
||||||
return XDGOpen(url.spec());
|
return XDGOpen(url.spec(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MoveItemToTrash(const base::FilePath& full_path) {
|
bool MoveItemToTrash(const base::FilePath& full_path) {
|
||||||
return XDGUtil("gvfs-trash", full_path.value());
|
return XDGUtil("gvfs-trash", full_path.value(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Beep() {
|
void Beep() {
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "third_party/WebKit/public/web/WebFrame.h"
|
#include "third_party/WebKit/public/web/WebFrame.h"
|
||||||
#include "third_party/WebKit/public/web/WebLocalFrame.h"
|
#include "third_party/WebKit/public/web/WebLocalFrame.h"
|
||||||
#include "third_party/WebKit/public/web/WebKit.h"
|
#include "third_party/WebKit/public/web/WebKit.h"
|
||||||
|
#include "third_party/WebKit/public/web/WebScriptSource.h"
|
||||||
#include "third_party/WebKit/public/web/WebView.h"
|
#include "third_party/WebKit/public/web/WebView.h"
|
||||||
#include "ui/base/resource/resource_bundle.h"
|
#include "ui/base/resource/resource_bundle.h"
|
||||||
#include "native_mate/dictionary.h"
|
#include "native_mate/dictionary.h"
|
||||||
|
@ -88,6 +89,9 @@ void AtomRenderViewObserver::DidCreateDocumentElement(
|
||||||
blink::WebLocalFrame* frame) {
|
blink::WebLocalFrame* frame) {
|
||||||
document_created_ = true;
|
document_created_ = true;
|
||||||
|
|
||||||
|
// Make sure every page will get a script context created.
|
||||||
|
frame->executeScript(blink::WebScriptSource("void 0"));
|
||||||
|
|
||||||
// Read --zoom-factor from command line.
|
// Read --zoom-factor from command line.
|
||||||
std::string zoom_factor_str = base::CommandLine::ForCurrentProcess()->
|
std::string zoom_factor_str = base::CommandLine::ForCurrentProcess()->
|
||||||
GetSwitchValueASCII(switches::kZoomFactor);
|
GetSwitchValueASCII(switches::kZoomFactor);
|
||||||
|
|
|
@ -37,7 +37,7 @@ int64_t AtomContentUtilityClient::max_ipc_message_size_ =
|
||||||
AtomContentUtilityClient::AtomContentUtilityClient()
|
AtomContentUtilityClient::AtomContentUtilityClient()
|
||||||
: filter_messages_(false) {
|
: filter_messages_(false) {
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
handlers_.push_back(new PrintingHandlerWin());
|
handlers_.push_back(new printing::PrintingHandlerWin());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,11 +71,4 @@ void AtomContentUtilityClient::OnStartupPing() {
|
||||||
// Don't release the process, we assume further messages are on the way.
|
// Don't release the process, we assume further messages are on the way.
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
|
||||||
void AtomContentUtilityClient::PreSandboxStartup() {
|
|
||||||
#if defined(OS_WIN)
|
|
||||||
PrintingHandlerWin::PreSandboxStartup();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace atom
|
} // namespace atom
|
||||||
|
|
|
@ -31,8 +31,6 @@ class AtomContentUtilityClient : public content::ContentUtilityClient {
|
||||||
void UtilityThreadStarted() override;
|
void UtilityThreadStarted() override;
|
||||||
bool OnMessageReceived(const IPC::Message& message) override;
|
bool OnMessageReceived(const IPC::Message& message) override;
|
||||||
|
|
||||||
static void PreSandboxStartup();
|
|
||||||
|
|
||||||
static void set_max_ipc_message_size_for_test(int64_t max_message_size) {
|
static void set_max_ipc_message_size_for_test(int64_t max_message_size) {
|
||||||
max_ipc_message_size_ = max_message_size;
|
max_ipc_message_size_ = max_message_size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,14 @@
|
||||||
#include "base/scoped_native_library.h"
|
#include "base/scoped_native_library.h"
|
||||||
#include "chrome/common/print_messages.h"
|
#include "chrome/common/print_messages.h"
|
||||||
#include "content/public/utility/utility_thread.h"
|
#include "content/public/utility/utility_thread.h"
|
||||||
|
#include "pdf/pdf.h"
|
||||||
#include "printing/emf_win.h"
|
#include "printing/emf_win.h"
|
||||||
#include "printing/page_range.h"
|
#include "printing/page_range.h"
|
||||||
#include "printing/pdf_render_settings.h"
|
#include "printing/pdf_render_settings.h"
|
||||||
#include "ui/gfx/gdi_util.h"
|
#include "ui/gfx/gdi_util.h"
|
||||||
|
|
||||||
|
namespace printing {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool Send(IPC::Message* message) {
|
bool Send(IPC::Message* message) {
|
||||||
|
@ -25,114 +28,12 @@ void ReleaseProcessIfNeeded() {
|
||||||
content::UtilityThread::Get()->ReleaseProcessIfNeeded();
|
content::UtilityThread::Get()->ReleaseProcessIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
class PdfFunctions {
|
|
||||||
public:
|
|
||||||
PdfFunctions() : get_pdf_doc_info_func_(NULL),
|
|
||||||
render_pdf_to_dc_func_(NULL) {}
|
|
||||||
|
|
||||||
bool Init() {
|
|
||||||
base::FilePath module_path;
|
|
||||||
if (!PathService::Get(base::DIR_MODULE, &module_path))
|
|
||||||
return false;
|
|
||||||
base::FilePath::StringType name(FILE_PATH_LITERAL("pdf.dll"));
|
|
||||||
pdf_lib_.Reset(base::LoadNativeLibrary(module_path.Append(name), NULL));
|
|
||||||
if (!pdf_lib_.is_valid()) {
|
|
||||||
LOG(WARNING) << "Couldn't load PDF plugin";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
get_pdf_doc_info_func_ =
|
|
||||||
reinterpret_cast<GetPDFDocInfoProc>(
|
|
||||||
pdf_lib_.GetFunctionPointer("GetPDFDocInfo"));
|
|
||||||
LOG_IF(WARNING, !get_pdf_doc_info_func_) << "Missing GetPDFDocInfo";
|
|
||||||
|
|
||||||
render_pdf_to_dc_func_ =
|
|
||||||
reinterpret_cast<RenderPDFPageToDCProc>(
|
|
||||||
pdf_lib_.GetFunctionPointer("RenderPDFPageToDC"));
|
|
||||||
LOG_IF(WARNING, !render_pdf_to_dc_func_) << "Missing RenderPDFPageToDC";
|
|
||||||
|
|
||||||
if (!get_pdf_doc_info_func_ || !render_pdf_to_dc_func_) {
|
|
||||||
Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
return IsValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsValid() const {
|
|
||||||
return pdf_lib_.is_valid();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() {
|
|
||||||
pdf_lib_.Reset(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetPDFDocInfo(const void* pdf_buffer,
|
|
||||||
int buffer_size,
|
|
||||||
int* page_count,
|
|
||||||
double* max_page_width) {
|
|
||||||
if (!get_pdf_doc_info_func_)
|
|
||||||
return false;
|
|
||||||
return get_pdf_doc_info_func_(pdf_buffer, buffer_size, page_count,
|
|
||||||
max_page_width);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RenderPDFPageToDC(const void* pdf_buffer,
|
|
||||||
int buffer_size,
|
|
||||||
int page_number,
|
|
||||||
HDC dc,
|
|
||||||
int dpi,
|
|
||||||
int bounds_origin_x,
|
|
||||||
int bounds_origin_y,
|
|
||||||
int bounds_width,
|
|
||||||
int bounds_height,
|
|
||||||
bool fit_to_bounds,
|
|
||||||
bool stretch_to_bounds,
|
|
||||||
bool keep_aspect_ratio,
|
|
||||||
bool center_in_bounds,
|
|
||||||
bool autorotate) {
|
|
||||||
if (!render_pdf_to_dc_func_)
|
|
||||||
return false;
|
|
||||||
return render_pdf_to_dc_func_(pdf_buffer, buffer_size, page_number,
|
|
||||||
dc, dpi, bounds_origin_x,
|
|
||||||
bounds_origin_y, bounds_width, bounds_height,
|
|
||||||
fit_to_bounds, stretch_to_bounds,
|
|
||||||
keep_aspect_ratio, center_in_bounds,
|
|
||||||
autorotate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Exported by PDF plugin.
|
|
||||||
typedef bool (*GetPDFDocInfoProc)(const void* pdf_buffer,
|
|
||||||
int buffer_size, int* page_count,
|
|
||||||
double* max_page_width);
|
|
||||||
typedef bool (*RenderPDFPageToDCProc)(
|
|
||||||
const void* pdf_buffer, int buffer_size, int page_number, HDC dc,
|
|
||||||
int dpi, int bounds_origin_x, int bounds_origin_y,
|
|
||||||
int bounds_width, int bounds_height, bool fit_to_bounds,
|
|
||||||
bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds,
|
|
||||||
bool autorotate);
|
|
||||||
|
|
||||||
RenderPDFPageToDCProc render_pdf_to_dc_func_;
|
|
||||||
GetPDFDocInfoProc get_pdf_doc_info_func_;
|
|
||||||
|
|
||||||
base::ScopedNativeLibrary pdf_lib_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(PdfFunctions);
|
|
||||||
};
|
|
||||||
|
|
||||||
base::LazyInstance<PdfFunctions> g_pdf_lib = LAZY_INSTANCE_INITIALIZER;
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
PrintingHandlerWin::PrintingHandlerWin() {}
|
PrintingHandlerWin::PrintingHandlerWin() {}
|
||||||
|
|
||||||
PrintingHandlerWin::~PrintingHandlerWin() {}
|
PrintingHandlerWin::~PrintingHandlerWin() {}
|
||||||
|
|
||||||
// static
|
|
||||||
void PrintingHandlerWin::PreSandboxStartup() {
|
|
||||||
g_pdf_lib.Get().Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PrintingHandlerWin::OnMessageReceived(const IPC::Message& message) {
|
bool PrintingHandlerWin::OnMessageReceived(const IPC::Message& message) {
|
||||||
bool handled = true;
|
bool handled = true;
|
||||||
IPC_BEGIN_MESSAGE_MAP(PrintingHandlerWin, message)
|
IPC_BEGIN_MESSAGE_MAP(PrintingHandlerWin, message)
|
||||||
|
@ -149,7 +50,7 @@ bool PrintingHandlerWin::OnMessageReceived(const IPC::Message& message) {
|
||||||
|
|
||||||
void PrintingHandlerWin::OnRenderPDFPagesToMetafile(
|
void PrintingHandlerWin::OnRenderPDFPagesToMetafile(
|
||||||
IPC::PlatformFileForTransit pdf_transit,
|
IPC::PlatformFileForTransit pdf_transit,
|
||||||
const printing::PdfRenderSettings& settings) {
|
const PdfRenderSettings& settings) {
|
||||||
pdf_rendering_settings_ = settings;
|
pdf_rendering_settings_ = settings;
|
||||||
base::File pdf_file = IPC::PlatformFileForTransitToFile(pdf_transit);
|
base::File pdf_file = IPC::PlatformFileForTransitToFile(pdf_transit);
|
||||||
int page_count = LoadPDF(pdf_file.Pass());
|
int page_count = LoadPDF(pdf_file.Pass());
|
||||||
|
@ -174,9 +75,6 @@ void PrintingHandlerWin::OnRenderPDFPagesToMetafileStop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int PrintingHandlerWin::LoadPDF(base::File pdf_file) {
|
int PrintingHandlerWin::LoadPDF(base::File pdf_file) {
|
||||||
if (!g_pdf_lib.Get().IsValid())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
int64_t length64 = pdf_file.GetLength();
|
int64_t length64 = pdf_file.GetLength();
|
||||||
if (length64 <= 0 || length64 > std::numeric_limits<int>::max())
|
if (length64 <= 0 || length64 > std::numeric_limits<int>::max())
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -187,8 +85,8 @@ int PrintingHandlerWin::LoadPDF(base::File pdf_file) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
int total_page_count = 0;
|
int total_page_count = 0;
|
||||||
if (!g_pdf_lib.Get().GetPDFDocInfo(
|
if (!chrome_pdf::GetPDFDocInfo(&pdf_data_.front(), pdf_data_.size(),
|
||||||
&pdf_data_.front(), pdf_data_.size(), &total_page_count, NULL)) {
|
&total_page_count, nullptr)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return total_page_count;
|
return total_page_count;
|
||||||
|
@ -197,7 +95,7 @@ int PrintingHandlerWin::LoadPDF(base::File pdf_file) {
|
||||||
bool PrintingHandlerWin::RenderPdfPageToMetafile(int page_number,
|
bool PrintingHandlerWin::RenderPdfPageToMetafile(int page_number,
|
||||||
base::File output_file,
|
base::File output_file,
|
||||||
float* scale_factor) {
|
float* scale_factor) {
|
||||||
printing::Emf metafile;
|
Emf metafile;
|
||||||
metafile.Init();
|
metafile.Init();
|
||||||
|
|
||||||
// We need to scale down DC to fit an entire page into DC available area.
|
// We need to scale down DC to fit an entire page into DC available area.
|
||||||
|
@ -216,7 +114,7 @@ bool PrintingHandlerWin::RenderPdfPageToMetafile(int page_number,
|
||||||
// The underlying metafile is of type Emf and ignores the arguments passed
|
// The underlying metafile is of type Emf and ignores the arguments passed
|
||||||
// to StartPage.
|
// to StartPage.
|
||||||
metafile.StartPage(gfx::Size(), gfx::Rect(), 1);
|
metafile.StartPage(gfx::Size(), gfx::Rect(), 1);
|
||||||
if (!g_pdf_lib.Get().RenderPDFPageToDC(
|
if (!chrome_pdf::RenderPDFPageToDC(
|
||||||
&pdf_data_.front(),
|
&pdf_data_.front(),
|
||||||
pdf_data_.size(),
|
pdf_data_.size(),
|
||||||
page_number,
|
page_number,
|
||||||
|
@ -237,3 +135,5 @@ bool PrintingHandlerWin::RenderPdfPageToMetafile(int page_number,
|
||||||
metafile.FinishDocument();
|
metafile.FinishDocument();
|
||||||
return metafile.SaveTo(&output_file);
|
return metafile.SaveTo(&output_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // printing
|
||||||
|
|
|
@ -12,10 +12,10 @@
|
||||||
#include "printing/pdf_render_settings.h"
|
#include "printing/pdf_render_settings.h"
|
||||||
|
|
||||||
namespace printing {
|
namespace printing {
|
||||||
|
|
||||||
class PdfRenderSettings;
|
class PdfRenderSettings;
|
||||||
struct PwgRasterSettings;
|
struct PwgRasterSettings;
|
||||||
struct PageRange;
|
struct PageRange;
|
||||||
}
|
|
||||||
|
|
||||||
// Dispatches IPCs for printing.
|
// Dispatches IPCs for printing.
|
||||||
class PrintingHandlerWin : public UtilityMessageHandler {
|
class PrintingHandlerWin : public UtilityMessageHandler {
|
||||||
|
@ -26,12 +26,10 @@ class PrintingHandlerWin : public UtilityMessageHandler {
|
||||||
// IPC::Listener:
|
// IPC::Listener:
|
||||||
bool OnMessageReceived(const IPC::Message& message) override;
|
bool OnMessageReceived(const IPC::Message& message) override;
|
||||||
|
|
||||||
static void PrintingHandlerWin::PreSandboxStartup();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// IPC message handlers.
|
// IPC message handlers.
|
||||||
void OnRenderPDFPagesToMetafile(IPC::PlatformFileForTransit pdf_transit,
|
void OnRenderPDFPagesToMetafile(IPC::PlatformFileForTransit pdf_transit,
|
||||||
const printing::PdfRenderSettings& settings);
|
const PdfRenderSettings& settings);
|
||||||
void OnRenderPDFPagesToMetafileGetPage(
|
void OnRenderPDFPagesToMetafileGetPage(
|
||||||
int page_number,
|
int page_number,
|
||||||
IPC::PlatformFileForTransit output_file);
|
IPC::PlatformFileForTransit output_file);
|
||||||
|
@ -43,9 +41,11 @@ class PrintingHandlerWin : public UtilityMessageHandler {
|
||||||
float* scale_factor);
|
float* scale_factor);
|
||||||
|
|
||||||
std::vector<char> pdf_data_;
|
std::vector<char> pdf_data_;
|
||||||
printing::PdfRenderSettings pdf_rendering_settings_;
|
PdfRenderSettings pdf_rendering_settings_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(PrintingHandlerWin);
|
DISALLOW_COPY_AND_ASSIGN(PrintingHandlerWin);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace printing
|
||||||
|
|
||||||
#endif // CHROME_UTILITY_PRINTING_HANDLER_WIN_H_
|
#endif // CHROME_UTILITY_PRINTING_HANDLER_WIN_H_
|
||||||
|
|
|
@ -2,8 +2,14 @@
|
||||||
|
|
||||||
이 모듈은 `Squirrel` 자동 업데이트 프레임워크의 인터페이스를 제공합니다.
|
이 모듈은 `Squirrel` 자동 업데이트 프레임워크의 인터페이스를 제공합니다.
|
||||||
|
|
||||||
[electron-release-server](https://github.com/ArekSredzki/electron-release-server)를
|
다음 프로젝트 중 하나를 택하여 사용하면, 어플리케이션을 배포하기 위한 멀티 플랫폼
|
||||||
포크하면 어플리케이션을 배포하기 위한 멀티 플랫폼 릴리즈 서버를 손쉽게 구축할 수 있습니다.
|
릴리즈 서버를 손쉽게 구축할 수 있습니다:
|
||||||
|
|
||||||
|
- [electron-release-server][electron-release-server]: *완벽하게 모든 기능을
|
||||||
|
지원하는 electron 어플리케이션을 위한 자가 호스트 릴리즈 서버입니다. auto-updater와
|
||||||
|
호환됩니다*
|
||||||
|
- [squirrel-updates-server][squirrel-updates-server]: *GitHub 릴리즈를 사용하는
|
||||||
|
Squirrel.Mac 와 Squirrel.Windows를 위한 간단한 node.js 기반 서버입니다*
|
||||||
|
|
||||||
## 플랫폼별 참고 사항
|
## 플랫폼별 참고 사항
|
||||||
|
|
||||||
|
@ -16,6 +22,9 @@ OS X에선 `auto-updater` 모듈이 [Squirrel.Mac][squirrel-mac]를 기반으로
|
||||||
따라서 이 모듈을 작동시키기 위해 특별히 준비해야 할 작업은 없습니다.
|
따라서 이 모듈을 작동시키기 위해 특별히 준비해야 할 작업은 없습니다.
|
||||||
서버 사이드 요구 사항은 [서버 지원][server-support]을 참고하세요.
|
서버 사이드 요구 사항은 [서버 지원][server-support]을 참고하세요.
|
||||||
|
|
||||||
|
**참고:** Mac OS X에서 자동 업데이트를 지원하려면 반드시 사인이 되어있어야 합니다.
|
||||||
|
이것은 `Squirrel.Mac`의 요구사항입니다.
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
Windows에선 `auto-updater` 모듈을 사용하기 전에 어플리케이션을 사용자의 장치에
|
Windows에선 `auto-updater` 모듈을 사용하기 전에 어플리케이션을 사용자의 장치에
|
||||||
|
@ -95,5 +104,7 @@ Returns:
|
||||||
[squirrel-mac]: https://github.com/Squirrel/Squirrel.Mac
|
[squirrel-mac]: https://github.com/Squirrel/Squirrel.Mac
|
||||||
[server-support]: https://github.com/Squirrel/Squirrel.Mac#server-support
|
[server-support]: https://github.com/Squirrel/Squirrel.Mac#server-support
|
||||||
[squirrel-windows]: https://github.com/Squirrel/Squirrel.Windows
|
[squirrel-windows]: https://github.com/Squirrel/Squirrel.Windows
|
||||||
[installer]: https://github.com/atom/grunt-electron-installer
|
[installer]: https://github.com/electron/grunt-electron-installer
|
||||||
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx
|
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx
|
||||||
|
[electron-release-server]: https://github.com/ArekSredzki/electron-release-server
|
||||||
|
[squirrel-updates-server]: https://github.com/Aluxian/squirrel-updates-server
|
||||||
|
|
|
@ -173,6 +173,8 @@ win.show();
|
||||||
* `defaultMonospaceFontSize` Integer - 기본값 `13`.
|
* `defaultMonospaceFontSize` Integer - 기본값 `13`.
|
||||||
* `minimumFontSize` Integer - 기본값 `0`.
|
* `minimumFontSize` Integer - 기본값 `0`.
|
||||||
* `defaultEncoding` String - 기본값 `ISO-8859-1`.
|
* `defaultEncoding` String - 기본값 `ISO-8859-1`.
|
||||||
|
* `backgroundThrottling` Boolean - 페이지가 백그라운드 상태에 진입할 때 애니메이션과
|
||||||
|
타이머에 스로틀을 적용할지 여부입니다. 기본값은 `true`입니다.
|
||||||
|
|
||||||
## Events
|
## Events
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ crashReporter.start({
|
||||||
있습니다:
|
있습니다:
|
||||||
|
|
||||||
* [socorro](https://github.com/mozilla/socorro)
|
* [socorro](https://github.com/mozilla/socorro)
|
||||||
* [mini-breakpad-server](https://github.com/atom/mini-breakpad-server)
|
* [mini-breakpad-server](https://github.com/electron/mini-breakpad-server)
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ crashReporter.start({
|
||||||
**참고:** OS X에선 Windows와 Linux의 `breakpad`와 달리 새로운 `crashpad`
|
**참고:** OS X에선 Windows와 Linux의 `breakpad`와 달리 새로운 `crashpad`
|
||||||
클라이언트를 사용합니다. 오류 수집 기능을 활성화 시키려면 오류를 수집하고 싶은 메인
|
클라이언트를 사용합니다. 오류 수집 기능을 활성화 시키려면 오류를 수집하고 싶은 메인
|
||||||
프로세스나 랜더러 프로세스에서 `crashReporter.start` 메서드를 호출하여 `crashpad`를
|
프로세스나 랜더러 프로세스에서 `crashReporter.start` 메서드를 호출하여 `crashpad`를
|
||||||
초기화 해야합니다.
|
초기화해야 합니다.
|
||||||
|
|
||||||
### `crashReporter.getLastCrashReport()`
|
### `crashReporter.getLastCrashReport()`
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Frameless Window
|
# Frameless Window
|
||||||
|
|
||||||
Frameless Window는 [창 테두리](https://developer.mozilla.org/en-US/docs/Glossary/Chrome)가
|
Frameless Window는 [창 테두리](https://developer.mozilla.org/ko/docs/Glossary/Chrome)가
|
||||||
없는 윈도우를 말합니다. 이 기능은 윈도우의 일부분인 툴바와 같이 웹 페이지의 일부분이
|
없는 윈도우를 말합니다. 이 기능은 윈도우의 일부분인 툴바와 같이 웹 페이지의 일부분이
|
||||||
아닌 부분을 보이지 않도록 합니다. [`BrowserWindow`](browser-window.md) 클래스의
|
아닌 부분을 보이지 않도록 합니다. [`BrowserWindow`](browser-window.md) 클래스의
|
||||||
옵션에서 설정할 수 있습니다.
|
옵션에서 설정할 수 있습니다.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Menu
|
# Menu
|
||||||
|
|
||||||
`menu` 클래스는 어플리케이션 메뉴와 [컨텍스트 메뉴](https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/PopupGuide/ContextMenus)를
|
`menu` 클래스는 어플리케이션 메뉴와 [컨텍스트 메뉴](https://developer.mozilla.org/ko/docs/Mozilla/Tech/XUL/PopupGuide/ContextMenus)를
|
||||||
만들 때 사용됩니다. 이 모듈은 메인 프로세스용 모듈이지만 `remote` 모듈을 통해 랜더러
|
만들 때 사용됩니다. 이 모듈은 메인 프로세스용 모듈이지만 `remote` 모듈을 통해 랜더러
|
||||||
프로세스에서도 사용할 수 있습니다.
|
프로세스에서도 사용할 수 있습니다.
|
||||||
|
|
||||||
|
@ -382,4 +382,4 @@ OS X에선 지정한 어플리케이션 메뉴에 상관없이 메뉴의 첫번
|
||||||
```
|
```
|
||||||
|
|
||||||
[AboutInformationPropertyListFiles]: https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html
|
[AboutInformationPropertyListFiles]: https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html
|
||||||
[setMenu]: https://github.com/electron/electron/blob/master/docs-translations/ko-KR/api/browser-window.md#winsetmenumenu-linux-windows
|
[setMenu]: ./browser-window.md#winsetmenumenu-linux-windows
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
Electron의 메인 프로세스에선 GUI와 관련 있는(`dialog`, `menu`등) 모듈만 사용할 수
|
Electron의 메인 프로세스에선 GUI와 관련 있는(`dialog`, `menu`등) 모듈만 사용할 수
|
||||||
있습니다. 랜더러 프로세스에서 이러한 모듈들을 사용하려면 `ipc` 모듈을 통해 메인
|
있습니다. 랜더러 프로세스에서 이러한 모듈들을 사용하려면 `ipc` 모듈을 통해 메인
|
||||||
프로세스와 inter-process 통신을 해야합니다. 또한, `remote` 모듈을 사용하면
|
프로세스와 inter-process 통신을 해야 합니다. 또한, `remote` 모듈을 사용하면
|
||||||
inter-process 통신을 하지 않고도 간단한 API를 통해 직접 메인 프로세스의 모듈과
|
inter-process 통신을 하지 않고도 간단한 API를 통해 직접 메인 프로세스의 모듈과
|
||||||
메서드를 사용할 수 있습니다. 이 개념은 Java의 [RMI][rmi]와 비슷합니다.
|
메서드를 사용할 수 있습니다. 이 개념은 Java의 [RMI][rmi]와 비슷합니다.
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ win.loadURL('https://github.com');
|
||||||
않습니다. 대신에 이 `BrowserWindow` 객체는 메인 프로세스에서 생성되며 랜더러
|
않습니다. 대신에 이 `BrowserWindow` 객체는 메인 프로세스에서 생성되며 랜더러
|
||||||
프로세스에 `win` 객체와 같이 이에 대응하는 remote 객체를 반환합니다.
|
프로세스에 `win` 객체와 같이 이에 대응하는 remote 객체를 반환합니다.
|
||||||
|
|
||||||
참고로 remote를 통해선 [enumerable 속성](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties)을
|
참고로 remote를 통해선 [enumerable 속성](https://developer.mozilla.org/ko/docs/Web/JavaScript/Enumerability_and_ownership_of_properties)을
|
||||||
가진 프로퍼티에만 접근할 수 있습니다.
|
가진 프로퍼티에만 접근할 수 있습니다.
|
||||||
|
|
||||||
## Remote 객체의 생명 주기
|
## Remote 객체의 생명 주기
|
||||||
|
|
|
@ -78,5 +78,5 @@ require('electron').hideInternalModules()
|
||||||
```
|
```
|
||||||
|
|
||||||
[gui]: https://en.wikipedia.org/wiki/Graphical_user_interface
|
[gui]: https://en.wikipedia.org/wiki/Graphical_user_interface
|
||||||
[destructuring-assignment]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
|
[destructuring-assignment]: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
|
||||||
[issue-387]: https://github.com/electron/electron/issues/387
|
[issue-387]: https://github.com/electron/electron/issues/387
|
||||||
|
|
|
@ -11,7 +11,7 @@ const Tray = electron.Tray;
|
||||||
|
|
||||||
var appIcon = null;
|
var appIcon = null;
|
||||||
app.on('ready', function(){
|
app.on('ready', function(){
|
||||||
appIcon = new Tray('/path/to/my/icon'); // 현재 어플리케이션 디렉터리를 기준으로 하려면 `__dirname + '/images/tray.png'` 형식으로 입력해야합니다.
|
appIcon = new Tray('/path/to/my/icon'); // 현재 어플리케이션 디렉터리를 기준으로 하려면 `__dirname + '/images/tray.png'` 형식으로 입력해야 합니다.
|
||||||
var contextMenu = Menu.buildFromTemplate([
|
var contextMenu = Menu.buildFromTemplate([
|
||||||
{ label: 'Item1', type: 'radio' },
|
{ label: 'Item1', type: 'radio' },
|
||||||
{ label: 'Item2', type: 'radio' },
|
{ label: 'Item2', type: 'radio' },
|
||||||
|
|
|
@ -67,6 +67,7 @@ Returns:
|
||||||
* `requestMethod` String
|
* `requestMethod` String
|
||||||
* `referrer` String
|
* `referrer` String
|
||||||
* `headers` Object
|
* `headers` Object
|
||||||
|
* `resourceType` String
|
||||||
|
|
||||||
요청한 리소스에 관련된 자세한 정보를 사용할 수 있을 때 발생하는 이벤트입니다.
|
요청한 리소스에 관련된 자세한 정보를 사용할 수 있을 때 발생하는 이벤트입니다.
|
||||||
`status`는 리소스를 다운로드하기 위한 소켓 연결을 나타냅니다.
|
`status`는 리소스를 다운로드하기 위한 소켓 연결을 나타냅니다.
|
||||||
|
|
|
@ -17,9 +17,15 @@
|
||||||
수 있습니다:
|
수 있습니다:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<webview id="foo" src="https://www.github.com/" style="display:inline-block; width:640px; height:480px"></webview>
|
<webview id="foo" src="https://www.github.com/" style="display:inline-flex; width:640px; height:480px"></webview>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
주의할 점은 `webview` 태그의 스타일은 전통적인 flexbox 레이아웃을 사용했을 때 자식
|
||||||
|
`object` 요소가 해당 `webview` 컨테이너의 전체 높이와 넓이를 확실히 채우도록
|
||||||
|
내부적으로 `display:flex;`를 사용합니다. (v0.36.11 부터) 따라서 인라인 레이아웃을
|
||||||
|
위해 `display:inline-flex;`를 쓰지 않는 한, 기본 `display:flex;` CSS 속성을
|
||||||
|
덮어쓰지 않도록 주의해야 합니다.
|
||||||
|
|
||||||
게스트 컨텐츠를 조작하기 위해 자바스크립트로 `webview` 태그의 이벤트를 리스닝 하여
|
게스트 컨텐츠를 조작하기 위해 자바스크립트로 `webview` 태그의 이벤트를 리스닝 하여
|
||||||
응답을 받을 수 있습니다. 다음 예제를 참고하세요: 첫번째 리스너는 페이지 로딩 시작시의
|
응답을 받을 수 있습니다. 다음 예제를 참고하세요: 첫번째 리스너는 페이지 로딩 시작시의
|
||||||
이벤트를 확인하고 두번째 리스너는 페이지의 로딩이 끝난시점을 확인합니다. 그리고
|
이벤트를 확인하고 두번째 리스너는 페이지의 로딩이 끝난시점을 확인합니다. 그리고
|
||||||
|
@ -495,6 +501,7 @@ Returns:
|
||||||
* `requestMethod` String
|
* `requestMethod` String
|
||||||
* `referrer` String
|
* `referrer` String
|
||||||
* `headers` Object
|
* `headers` Object
|
||||||
|
* `resourceType` String
|
||||||
|
|
||||||
요청한 리소스에 관해 자세한 내용을 알 수 있을 때 발생하는 이벤트입니다.
|
요청한 리소스에 관해 자세한 내용을 알 수 있을 때 발생하는 이벤트입니다.
|
||||||
`status`는 리소스를 다운로드할 소켓 커낵션을 나타냅니다.
|
`status`는 리소스를 다운로드할 소켓 커낵션을 나타냅니다.
|
||||||
|
|
|
@ -16,7 +16,7 @@ main 필드에 메인 웹 페이지(index.html) URL을 지정하면 어플리케
|
||||||
|
|
||||||
Electron에선 JavaScript를 엔트리 포인트로 사용합니다. URL을 직접 제공하는 대신 API를
|
Electron에선 JavaScript를 엔트리 포인트로 사용합니다. URL을 직접 제공하는 대신 API를
|
||||||
사용하여 직접 브라우저 창과 HTML 파일을 로드할 수 있습니다. 또한 윈도우의 종료시기를
|
사용하여 직접 브라우저 창과 HTML 파일을 로드할 수 있습니다. 또한 윈도우의 종료시기를
|
||||||
결정하는 이벤트를 리스닝해야합니다.
|
결정하는 이벤트를 리스닝해야 합니다.
|
||||||
|
|
||||||
Electron은 Node.js 런타임과 비슷하게 작동합니다. Electron의 API는 저수준이기에
|
Electron은 Node.js 런타임과 비슷하게 작동합니다. Electron의 API는 저수준이기에
|
||||||
브라우저 테스팅을 위해 [PhantomJS](http://phantomjs.org/)를 사용할 수도 있습니다.
|
브라우저 테스팅을 위해 [PhantomJS](http://phantomjs.org/)를 사용할 수도 있습니다.
|
||||||
|
|
|
@ -26,17 +26,17 @@ C++ 코드는 많은 Chromium의 추상화와 타입을 사용합니다. 따라
|
||||||
* [표준](http://npm.im/standard) JavaScript 코딩 스타일을 사용합니다.
|
* [표준](http://npm.im/standard) JavaScript 코딩 스타일을 사용합니다.
|
||||||
* Google의 코딩 스타일에도 맞추기 위해 파일의 끝에는 **절대** 개행을 삽입해선 안됩니다.
|
* Google의 코딩 스타일에도 맞추기 위해 파일의 끝에는 **절대** 개행을 삽입해선 안됩니다.
|
||||||
* 파일 이름의 공백은 `_`대신에 `-`을 사용하여야 합니다. 예를 들어
|
* 파일 이름의 공백은 `_`대신에 `-`을 사용하여야 합니다. 예를 들어
|
||||||
`file_name.js`를 `file-name.js`로 고쳐야합니다. 왜냐하면
|
`file_name.js`를 `file-name.js`로 고쳐야 합니다. 왜냐하면
|
||||||
[github/atom](https://github.com/github/atom)에서 사용되는 모듈의 이름은 보통
|
[github/atom](https://github.com/github/atom)에서 사용되는 모듈의 이름은 보통
|
||||||
`module-name` 형식이기 때문입니다. 이 규칙은 '.js' 파일에만 적용됩니다.
|
`module-name` 형식이기 때문입니다. 이 규칙은 '.js' 파일에만 적용됩니다.
|
||||||
* 적절한 곳에 새로운 ES6/ES2015 문법을 사용해도 됩니다.
|
* 적절한 곳에 새로운 ES6/ES2015 문법을 사용해도 됩니다.
|
||||||
* [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const)
|
* [`const`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/const)
|
||||||
는 requires와 다른 상수에 사용합니다
|
는 requires와 다른 상수에 사용합니다
|
||||||
* [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let)
|
* [`let`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/let)
|
||||||
은 변수를 정의할 때 사용합니다
|
은 변수를 정의할 때 사용합니다
|
||||||
* [Arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
|
* [Arrow functions](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
|
||||||
는 `function () { }` 표현 대신에 사용합니다
|
는 `function () { }` 표현 대신에 사용합니다
|
||||||
* [Template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals)
|
* [Template literals](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Template_literals)
|
||||||
는 `+`로 문자열을 합치는 대신 사용합니다.
|
는 `+`로 문자열을 합치는 대신 사용합니다.
|
||||||
|
|
||||||
## API 이름
|
## API 이름
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
공식적인 Electron의 심볼 서버의 URL은
|
공식적인 Electron의 심볼 서버의 URL은
|
||||||
http://54.249.141.255:8086/atom-shell/symbols 입니다. 일단 이 URL에 직접적으로
|
http://54.249.141.255:8086/atom-shell/symbols 입니다. 일단 이 URL에 직접적으로
|
||||||
접근할 수는 없습니다: 디버깅 툴에 심볼의 경로를 추가해야합니다. 아래의 예제를 참고하면
|
접근할 수는 없습니다: 디버깅 툴에 심볼의 경로를 추가해야 합니다. 아래의 예제를 참고하면
|
||||||
로컬 캐시 디렉터리는 서버로부터 중복되지 않게 PDB를 가져오는데 사용됩니다.
|
로컬 캐시 디렉터리는 서버로부터 중복되지 않게 PDB를 가져오는데 사용됩니다.
|
||||||
`c:\code\symbols` 캐시 디렉터리를 사용중인 OS에 맞춰 적당한 경로로 변경하세요.
|
`c:\code\symbols` 캐시 디렉터리를 사용중인 OS에 맞춰 적당한 경로로 변경하세요.
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ SRV*c:\code\symbols\*http://54.249.141.255:8086/atom-shell/symbols
|
||||||
|
|
||||||
Windbg 메뉴 또는 `.sympath` 커맨드를 이용하여 환경에 `_NT_SYMBOL_PATH` 문자열을
|
Windbg 메뉴 또는 `.sympath` 커맨드를 이용하여 환경에 `_NT_SYMBOL_PATH` 문자열을
|
||||||
설정합니다. 만약 Microsoft의 심볼서버로부터 심볼을 받아오려면 다음과 같이 리스팅을
|
설정합니다. 만약 Microsoft의 심볼서버로부터 심볼을 받아오려면 다음과 같이 리스팅을
|
||||||
먼저 해야합니다:
|
먼저해야 합니다:
|
||||||
|
|
||||||
```
|
```
|
||||||
SRV*c:\code\symbols\*http://msdl.microsoft.com/download/symbols;SRV*c:\code\symbols\*http://54.249.141.255:8086/atom-shell/symbols
|
SRV*c:\code\symbols\*http://msdl.microsoft.com/download/symbols;SRV*c:\code\symbols\*http://54.249.141.255:8086/atom-shell/symbols
|
||||||
|
|
|
@ -147,7 +147,7 @@ npm uninstall -g electron
|
||||||
[memory-management]: https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management
|
[memory-management]: https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management
|
||||||
[variable-scope]: https://msdn.microsoft.com/library/bzt2dkta(v=vs.94).aspx
|
[variable-scope]: https://msdn.microsoft.com/library/bzt2dkta(v=vs.94).aspx
|
||||||
[electron-module]: https://www.npmjs.com/package/electron
|
[electron-module]: https://www.npmjs.com/package/electron
|
||||||
[storage]: https://developer.mozilla.org/en-US/docs/Web/API/Storage
|
[storage]: https://developer.mozilla.org/ko/docs/Web/API/Storage
|
||||||
[local-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
|
[local-storage]: https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage
|
||||||
[session-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage
|
[session-storage]: https://developer.mozilla.org/ko/docs/Web/API/Window/sessionStorage
|
||||||
[indexed-db]: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API
|
[indexed-db]: https://developer.mozilla.org/ko/docs/Web/API/IndexedDB_API
|
||||||
|
|
|
@ -50,7 +50,7 @@ Electron 문서 구조를 이해하는 데 참고할 수 있는 유용한 도움
|
||||||
|
|
||||||
### Methods
|
### Methods
|
||||||
|
|
||||||
[Method](https://developer.mozilla.org/en-US/docs/Glossary/Method) 문서의
|
[Method](https://developer.mozilla.org/ko/docs/Glossary/Method) 문서의
|
||||||
예제입니다:
|
예제입니다:
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -66,16 +66,16 @@ Electron 문서 구조를 이해하는 데 참고할 수 있는 유용한 도움
|
||||||
묶어 이 인수가 다른 인수뒤에서 선택적으로 사용될 수 있다는 것을 표시합니다.
|
묶어 이 인수가 다른 인수뒤에서 선택적으로 사용될 수 있다는 것을 표시합니다.
|
||||||
|
|
||||||
메서드 이름 하단에선 각 인수에 대해 자세한 설명을 합니다. 인수의 타입은:
|
메서드 이름 하단에선 각 인수에 대해 자세한 설명을 합니다. 인수의 타입은:
|
||||||
[`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String),
|
[`String`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String),
|
||||||
[`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number),
|
[`Number`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Number),
|
||||||
[`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object),
|
[`Object`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object),
|
||||||
[`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
|
[`Array`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array)
|
||||||
와 같은 일반적으로 쓰이는 타입 중 하나를 받거나 Electron의 [`webContent`](api/web-content.md)
|
와 같은 일반적으로 쓰이는 타입 중 하나를 받거나 Electron의 [`webContent`](api/web-content.md)
|
||||||
같은 커스텀 타입을 받습니다.
|
같은 커스텀 타입을 받습니다.
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
[Event](https://developer.mozilla.org/en-US/docs/Web/API/Event) 문서의 예제입니다:
|
[Event](https://developer.mozilla.org/ko/docs/Web/API/Event) 문서의 예제입니다:
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ electron/resources/app
|
||||||
|
|
||||||
## asar로 앱 패키징 하기
|
## asar로 앱 패키징 하기
|
||||||
|
|
||||||
소스파일 전체를 복사해서 배포하는 것과는 별개로 [asar](https://github.com/atom/asar)
|
소스파일 전체를 복사해서 배포하는 것과는 별개로 [asar](https://github.com/electron/asar)
|
||||||
아카이브를 통해 어플리케이션의 소스코드가 사용자에게 노출되는 것을 방지할 수 있습니다.
|
아카이브를 통해 어플리케이션의 소스코드가 사용자에게 노출되는 것을 방지할 수 있습니다.
|
||||||
|
|
||||||
`asar` 아카이브를 사용할 땐 단순히 `app` 폴더 대신에 어플리케이션을 패키징한
|
`asar` 아카이브를 사용할 땐 단순히 `app` 폴더 대신에 어플리케이션을 패키징한
|
||||||
|
|
|
@ -179,4 +179,4 @@ $ asar pack app app.asar --unpack *.node
|
||||||
포함되어 있습니다. 사용자에게 어플리케이션을 배포할 때 반드시 해당 폴더도 같이 배포해야
|
포함되어 있습니다. 사용자에게 어플리케이션을 배포할 때 반드시 해당 폴더도 같이 배포해야
|
||||||
합니다.
|
합니다.
|
||||||
|
|
||||||
[asar]: https://github.com/atom/asar
|
[asar]: https://github.com/electron/asar
|
||||||
|
|
|
@ -17,7 +17,7 @@ Electron은 v0.34.0 버전부터 앱 패키지를 Mac App Store(MAS)에 제출
|
||||||
다음 몇 가지 간단한 절차에 따라 앱 스토어에 어플리케이션을 등록하는 방법을 알아봅니다.
|
다음 몇 가지 간단한 절차에 따라 앱 스토어에 어플리케이션을 등록하는 방법을 알아봅니다.
|
||||||
한가지, 이 절차는 제출한 앱이 Apple로부터 승인되는 것을 보장하지 않습니다. 따라서
|
한가지, 이 절차는 제출한 앱이 Apple로부터 승인되는 것을 보장하지 않습니다. 따라서
|
||||||
여전히 Apple의 [Submitting Your App][submitting-your-app] 가이드를 숙지하고 있어야
|
여전히 Apple의 [Submitting Your App][submitting-your-app] 가이드를 숙지하고 있어야
|
||||||
하며 앱 스토어 제출 요구 사항을 확실히 인지하고 있어야합니다.
|
하며 앱 스토어 제출 요구 사항을 확실히 인지하고 있어야 합니다.
|
||||||
|
|
||||||
### 인증서 취득
|
### 인증서 취득
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ Electron의 V8 버전에 맞춰 네이티브 모듈을 다시 빌드하고 헤
|
||||||
node.js의 버전을 확인할 필요가 있습니다. Electron에서 사용하는 node 버전은
|
node.js의 버전을 확인할 필요가 있습니다. Electron에서 사용하는 node 버전은
|
||||||
[releases](https://github.com/electron/electron/releases)에서 확인할 수 있으며
|
[releases](https://github.com/electron/electron/releases)에서 확인할 수 있으며
|
||||||
`process.version`을 출력하여 버전을 확인할 수도 있습니다.
|
`process.version`을 출력하여 버전을 확인할 수도 있습니다.
|
||||||
([시작하기](https://github.com/electron/electron/blob/master/docs/tutorial/quick-start.md)의
|
([시작하기](./quick-start.md)의
|
||||||
예제를 참고하세요)
|
예제를 참고하세요)
|
||||||
|
|
||||||
혹시 직접 만든 네이티브 모듈이 있다면 [NAN](https://github.com/nodejs/nan/) 모듈을
|
혹시 직접 만든 네이티브 모듈이 있다면 [NAN](https://github.com/nodejs/nan/) 모듈을
|
||||||
|
|
|
@ -13,7 +13,7 @@ Pepper 플래시 플러그인을 사용하려면 Pepper 플래시 플러그인
|
||||||
|
|
||||||
플러그인을 사용하려면 Electron 커맨드 라인에 `--ppapi-flash-path` 와
|
플러그인을 사용하려면 Electron 커맨드 라인에 `--ppapi-flash-path` 와
|
||||||
`ppapi-flash-version` 플래그를 app의 ready 이벤트가 호출되기 전에 추가해야 합니다.
|
`ppapi-flash-version` 플래그를 app의 ready 이벤트가 호출되기 전에 추가해야 합니다.
|
||||||
그리고 `browser-window`에 `plugins` 스위치도 추가해야합니다.
|
그리고 `browser-window`에 `plugins` 스위치도 추가해야 합니다.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// 플래시 플러그인의 위치를 설정합니다.
|
// 플래시 플러그인의 위치를 설정합니다.
|
||||||
|
|
|
@ -31,7 +31,7 @@ process.once('loaded', function() {
|
||||||
|
|
||||||
### `process.noAsar`
|
### `process.noAsar`
|
||||||
|
|
||||||
设置它为 `true` 可以使 `asar` 文件在node的内置模块中实效.
|
设置它为 `true` 可以使 `asar` 文件在node的内置模块中失效.
|
||||||
|
|
||||||
## 方法
|
## 方法
|
||||||
|
|
||||||
|
@ -45,4 +45,4 @@ process.once('loaded', function() {
|
||||||
|
|
||||||
* `maxDescriptors` Integer
|
* `maxDescriptors` Integer
|
||||||
|
|
||||||
设置文件描述符软限制于 `maxDescriptors` 或硬限制与os, 无论它是否低于当前进程.
|
设置文件描述符软限制于 `maxDescriptors` 或硬限制与os, 无论它是否低于当前进程.
|
||||||
|
|
|
@ -63,6 +63,7 @@ var webContents = win.webContents;
|
||||||
* `requestMethod` String
|
* `requestMethod` String
|
||||||
* `referrer` String
|
* `referrer` String
|
||||||
* `headers` Object
|
* `headers` Object
|
||||||
|
* `resourceType` String
|
||||||
|
|
||||||
当有关请求资源的详细信息可用的时候发出事件.
|
当有关请求资源的详细信息可用的时候发出事件.
|
||||||
`status` 标识了 socket链接来下载资源.
|
`status` 标识了 socket链接来下载资源.
|
||||||
|
|
|
@ -457,6 +457,7 @@ Returns:
|
||||||
* `requestMethod` String
|
* `requestMethod` String
|
||||||
* `referrer` String
|
* `referrer` String
|
||||||
* `headers` Object
|
* `headers` Object
|
||||||
|
* `resourceType` String
|
||||||
|
|
||||||
当获得返回详情的时候触发.
|
当获得返回详情的时候触发.
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ electron/resources/app
|
||||||
|
|
||||||
## 将你的应用程序打包成一个文件
|
## 将你的应用程序打包成一个文件
|
||||||
|
|
||||||
除了通过拷贝所有的资源文件来分发你的应用程序之外,你可以可以通过打包你的应用程序为一个 [asar](https://github.com/atom/asar) 库文件以避免暴露你的源代码。
|
除了通过拷贝所有的资源文件来分发你的应用程序之外,你可以通过打包你的应用程序为一个 [asar](https://github.com/atom/asar) 库文件以避免暴露你的源代码。
|
||||||
|
|
||||||
为了使用一个 `asar` 库文件代替 `app` 文件夹,你需要修改这个库文件的名字为 `app.asar` ,
|
为了使用一个 `asar` 库文件代替 `app` 文件夹,你需要修改这个库文件的名字为 `app.asar` ,
|
||||||
然后将其放到 Electron 的资源文件夹下,然后 Electron 就会试图读取这个库文件并从中启动。
|
然后将其放到 Electron 的资源文件夹下,然后 Electron 就会试图读取这个库文件并从中启动。
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
|
|
||||||
*main.js*
|
*main.js*
|
||||||
```javascript
|
```javascript
|
||||||
var app = require('app');
|
const electron = require('electron');
|
||||||
var BrowserWindow = require('browser-window');
|
const app = electron.app;
|
||||||
var onlineStatusWindow;
|
const BrowserWindow = electron.BrowserWindow;
|
||||||
|
|
||||||
|
var onlineStatusWindow;
|
||||||
app.on('ready', function() {
|
app.on('ready', function() {
|
||||||
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false });
|
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false });
|
||||||
onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html');
|
onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html');
|
||||||
|
@ -36,17 +37,18 @@ app.on('ready', function() {
|
||||||
|
|
||||||
*main.js*
|
*main.js*
|
||||||
```javascript
|
```javascript
|
||||||
var app = require('app');
|
const electron = require('electron');
|
||||||
var ipc = require('ipc');
|
const app = electron.app;
|
||||||
var BrowserWindow = require('browser-window');
|
const ipcMain = electron.ipcMain;
|
||||||
var onlineStatusWindow;
|
const BrowserWindow = electron.BrowserWindow;
|
||||||
|
|
||||||
|
var onlineStatusWindow;
|
||||||
app.on('ready', function() {
|
app.on('ready', function() {
|
||||||
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false });
|
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false });
|
||||||
onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html');
|
onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html');
|
||||||
});
|
});
|
||||||
|
|
||||||
ipc.on('online-status-changed', function(event, status) {
|
ipcMain.on('online-status-changed', function(event, status) {
|
||||||
console.log(status);
|
console.log(status);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
@ -57,9 +59,9 @@ ipc.on('online-status-changed', function(event, status) {
|
||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
var ipc = require('ipc');
|
const ipcRenderer = require('electron').ipcRenderer;
|
||||||
var updateOnlineStatus = function() {
|
var updateOnlineStatus = function() {
|
||||||
ipc.send('online-status-changed', navigator.onLine ? 'online' : 'offline');
|
ipcRenderer.send('online-status-changed', navigator.onLine ? 'online' : 'offline');
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener('online', updateOnlineStatus);
|
window.addEventListener('online', updateOnlineStatus);
|
||||||
|
|
|
@ -40,7 +40,7 @@ your-app/
|
||||||
```
|
```
|
||||||
**注意**:如果 `main` 字段没有在 `package.json` 声明,Electron会优先加载 `index.js`。
|
**注意**:如果 `main` 字段没有在 `package.json` 声明,Electron会优先加载 `index.js`。
|
||||||
|
|
||||||
`main.js` 应该用于创建窗口和处理系统时间,一个典型的例子如下:
|
`main.js` 应该用于创建窗口和处理系统事件,一个典型的例子如下:
|
||||||
```javascript
|
```javascript
|
||||||
var app = require('app'); // 控制应用生命周期的模块。
|
var app = require('app'); // 控制应用生命周期的模块。
|
||||||
var BrowserWindow = require('browser-window'); // 创建原生浏览器窗口的模块
|
var BrowserWindow = require('browser-window'); // 创建原生浏览器窗口的模块
|
||||||
|
|
|
@ -446,6 +446,8 @@ The `callback` has to be called with an `response` object:
|
||||||
* `cancel` Boolean
|
* `cancel` Boolean
|
||||||
* `responseHeaders` Object (optional) - When provided, the server is assumed
|
* `responseHeaders` Object (optional) - When provided, the server is assumed
|
||||||
to have responded with these headers.
|
to have responded with these headers.
|
||||||
|
* `statusLine` String (optional) - Should be provided when overriding `responseHeaders`
|
||||||
|
to change header status otherwise original response header's status will be used.
|
||||||
|
|
||||||
#### `ses.webRequest.onResponseStarted([filter, ]listener)`
|
#### `ses.webRequest.onResponseStarted([filter, ]listener)`
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ Returns:
|
||||||
* `requestMethod` String
|
* `requestMethod` String
|
||||||
* `referrer` String
|
* `referrer` String
|
||||||
* `headers` Object
|
* `headers` Object
|
||||||
|
* `resourceType` String
|
||||||
|
|
||||||
Emitted when details regarding a requested resource are available.
|
Emitted when details regarding a requested resource are available.
|
||||||
`status` indicates the socket connection to download the resource.
|
`status` indicates the socket connection to download the resource.
|
||||||
|
|
|
@ -510,6 +510,7 @@ Returns:
|
||||||
* `requestMethod` String
|
* `requestMethod` String
|
||||||
* `referrer` String
|
* `referrer` String
|
||||||
* `headers` Object
|
* `headers` Object
|
||||||
|
* `resourceType` String
|
||||||
|
|
||||||
Fired when details regarding a requested resource is available.
|
Fired when details regarding a requested resource is available.
|
||||||
`status` indicates socket connection to download the resource.
|
`status` indicates socket connection to download the resource.
|
||||||
|
|
|
@ -39,9 +39,16 @@ etc.
|
||||||
* [Template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals)
|
* [Template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals)
|
||||||
instead of string concatenation using `+`
|
instead of string concatenation using `+`
|
||||||
|
|
||||||
## API Names
|
## Naming Things
|
||||||
|
|
||||||
When creating a new API, we should prefer getters and setters instead of
|
Electron APIs uses the same capitalization scheme as Node.js:
|
||||||
|
|
||||||
|
- When the module itself is a class like `BrowserWindow`, use `CamelCase`.
|
||||||
|
- When the module is a set of APIs, like `globalShortcut`, use `mixedCase`.
|
||||||
|
- When the API is a property of object, and it is complex enough to be in a separate chapter like `win.webContents`, use `mixedCase`.
|
||||||
|
- For other non-module APIs, use natural titles, like `<webview> Tag` or `Process Object`.
|
||||||
|
|
||||||
|
When creating a new API, it is preferred to use getters and setters instead of
|
||||||
jQuery's one-function style. For example, `.getText()` and `.setText(text)`
|
jQuery's one-function style. For example, `.getText()` and `.setText(text)`
|
||||||
are preferred to `.text([text])`. There is a
|
are preferred to `.text([text])`. There is a
|
||||||
[discussion](https://github.com/electron/electron/issues/46) on this.
|
[discussion](https://github.com/electron/electron/issues/46) on this.
|
||||||
|
|
|
@ -157,6 +157,8 @@
|
||||||
'atom/browser/atom_quota_permission_context.h',
|
'atom/browser/atom_quota_permission_context.h',
|
||||||
'atom/browser/atom_resource_dispatcher_host_delegate.cc',
|
'atom/browser/atom_resource_dispatcher_host_delegate.cc',
|
||||||
'atom/browser/atom_resource_dispatcher_host_delegate.h',
|
'atom/browser/atom_resource_dispatcher_host_delegate.h',
|
||||||
|
'atom/browser/atom_security_state_model_client.cc',
|
||||||
|
'atom/browser/atom_security_state_model_client.h',
|
||||||
'atom/browser/atom_speech_recognition_manager_delegate.cc',
|
'atom/browser/atom_speech_recognition_manager_delegate.cc',
|
||||||
'atom/browser/atom_speech_recognition_manager_delegate.h',
|
'atom/browser/atom_speech_recognition_manager_delegate.h',
|
||||||
'atom/browser/bridge_task_runner.cc',
|
'atom/browser/bridge_task_runner.cc',
|
||||||
|
|
|
@ -78,19 +78,20 @@ BrowserWindow.prototype._init = function () {
|
||||||
app.emit('browser-window-focus', event, this)
|
app.emit('browser-window-focus', event, this)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Evented visibilityState changes
|
// Subscribe to visibilityState changes and pass to renderer process.
|
||||||
this.on('show', () => {
|
let isVisible = this.isVisible() && !this.isMinimized()
|
||||||
this.webContents.send('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', this.isVisible(), this.isMinimized())
|
let visibilityChanged = () => {
|
||||||
})
|
let newState = this.isVisible() && !this.isMinimized()
|
||||||
this.on('hide', () => {
|
if (isVisible !== newState) {
|
||||||
this.webContents.send('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', this.isVisible(), this.isMinimized())
|
isVisible = newState
|
||||||
})
|
this.webContents.send('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', isVisible ? 'visible' : 'hidden')
|
||||||
this.on('minimize', () => {
|
}
|
||||||
this.webContents.send('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', this.isVisible(), this.isMinimized())
|
}
|
||||||
})
|
this.on('show', visibilityChanged)
|
||||||
this.on('restore', () => {
|
this.on('hide', visibilityChanged)
|
||||||
this.webContents.send('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', this.isVisible(), this.isMinimized())
|
this.on('minimize', visibilityChanged)
|
||||||
})
|
this.on('restore', visibilityChanged)
|
||||||
|
this.on('maximize', visibilityChanged)
|
||||||
|
|
||||||
// Notify the creation of the window.
|
// Notify the creation of the window.
|
||||||
app.emit('browser-window-created', {}, this)
|
app.emit('browser-window-created', {}, this)
|
||||||
|
@ -105,6 +106,7 @@ BrowserWindow.prototype._init = function () {
|
||||||
this.webContents.on('devtools-closed', () => {
|
this.webContents.on('devtools-closed', () => {
|
||||||
this.emit('devtools-closed')
|
this.emit('devtools-closed')
|
||||||
})
|
})
|
||||||
|
|
||||||
Object.defineProperty(this, 'devToolsWebContents', {
|
Object.defineProperty(this, 'devToolsWebContents', {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: false,
|
configurable: false,
|
||||||
|
@ -195,37 +197,21 @@ BrowserWindow.prototype.inspectServiceWorker = function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated.
|
// Deprecated.
|
||||||
|
|
||||||
deprecate.member(BrowserWindow, 'undo', 'webContents')
|
deprecate.member(BrowserWindow, 'undo', 'webContents')
|
||||||
|
|
||||||
deprecate.member(BrowserWindow, 'redo', 'webContents')
|
deprecate.member(BrowserWindow, 'redo', 'webContents')
|
||||||
|
|
||||||
deprecate.member(BrowserWindow, 'cut', 'webContents')
|
deprecate.member(BrowserWindow, 'cut', 'webContents')
|
||||||
|
|
||||||
deprecate.member(BrowserWindow, 'copy', 'webContents')
|
deprecate.member(BrowserWindow, 'copy', 'webContents')
|
||||||
|
|
||||||
deprecate.member(BrowserWindow, 'paste', 'webContents')
|
deprecate.member(BrowserWindow, 'paste', 'webContents')
|
||||||
|
|
||||||
deprecate.member(BrowserWindow, 'selectAll', 'webContents')
|
deprecate.member(BrowserWindow, 'selectAll', 'webContents')
|
||||||
|
|
||||||
deprecate.member(BrowserWindow, 'reloadIgnoringCache', 'webContents')
|
deprecate.member(BrowserWindow, 'reloadIgnoringCache', 'webContents')
|
||||||
|
|
||||||
deprecate.member(BrowserWindow, 'isLoading', 'webContents')
|
deprecate.member(BrowserWindow, 'isLoading', 'webContents')
|
||||||
|
|
||||||
deprecate.member(BrowserWindow, 'isWaitingForResponse', 'webContents')
|
deprecate.member(BrowserWindow, 'isWaitingForResponse', 'webContents')
|
||||||
|
|
||||||
deprecate.member(BrowserWindow, 'stop', 'webContents')
|
deprecate.member(BrowserWindow, 'stop', 'webContents')
|
||||||
|
|
||||||
deprecate.member(BrowserWindow, 'isCrashed', 'webContents')
|
deprecate.member(BrowserWindow, 'isCrashed', 'webContents')
|
||||||
|
|
||||||
deprecate.member(BrowserWindow, 'print', 'webContents')
|
deprecate.member(BrowserWindow, 'print', 'webContents')
|
||||||
|
|
||||||
deprecate.member(BrowserWindow, 'printToPDF', 'webContents')
|
deprecate.member(BrowserWindow, 'printToPDF', 'webContents')
|
||||||
|
|
||||||
deprecate.rename(BrowserWindow, 'restart', 'reload')
|
deprecate.rename(BrowserWindow, 'restart', 'reload')
|
||||||
|
|
||||||
deprecate.rename(BrowserWindow, 'loadUrl', 'loadURL')
|
deprecate.rename(BrowserWindow, 'loadUrl', 'loadURL')
|
||||||
|
|
||||||
deprecate.rename(BrowserWindow, 'getUrl', 'getURL')
|
deprecate.rename(BrowserWindow, 'getUrl', 'getURL')
|
||||||
|
|
||||||
BrowserWindow.prototype.executeJavaScriptInDevTools = deprecate('executeJavaScriptInDevTools', 'devToolsWebContents.executeJavaScript', function (code) {
|
BrowserWindow.prototype.executeJavaScriptInDevTools = deprecate('executeJavaScriptInDevTools', 'devToolsWebContents.executeJavaScript', function (code) {
|
||||||
|
|
|
@ -146,13 +146,9 @@ let wrapWebContents = function (webContents) {
|
||||||
return menu.popup(params.x, params.y)
|
return menu.popup(params.x, params.y)
|
||||||
})
|
})
|
||||||
|
|
||||||
// This error occurs when host could not be found.
|
// The devtools requests the webContents to reload.
|
||||||
webContents.on('did-fail-provisional-load', function (...args) {
|
webContents.on('devtools-reload-page', function () {
|
||||||
// Calling loadURL during this event might cause crash, so delay the event
|
webContents.reload()
|
||||||
// until next tick.
|
|
||||||
setImmediate(() => {
|
|
||||||
this.emit.apply(this, ['did-fail-load'].concat(args))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Delays the page-title-updated event to next tick.
|
// Delays the page-title-updated event to next tick.
|
||||||
|
@ -168,6 +164,7 @@ let wrapWebContents = function (webContents) {
|
||||||
deprecate.event(webContents, 'page-title-set', 'page-title-updated', function (...args) {
|
deprecate.event(webContents, 'page-title-set', 'page-title-updated', function (...args) {
|
||||||
return this.emit.apply(this, ['page-title-set'].concat(args))
|
return this.emit.apply(this, ['page-title-set'].concat(args))
|
||||||
})
|
})
|
||||||
|
|
||||||
webContents.printToPDF = function (options, callback) {
|
webContents.printToPDF = function (options, callback) {
|
||||||
var printingSetting
|
var printingSetting
|
||||||
printingSetting = {
|
printingSetting = {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
;(function () {
|
;(function () {
|
||||||
return function (process, require, asarSource) {
|
return function (process, require, asarSource) {
|
||||||
// Make asar.coffee accessible via "require".
|
// Make asar.coffee accessible via "require".
|
||||||
process.binding('natives').ATOM_SHELL_ASAR = asarSource
|
process.binding('natives').ELECTRON_ASAR = asarSource
|
||||||
|
|
||||||
// Monkey-patch the fs module.
|
// Monkey-patch the fs module.
|
||||||
require('ATOM_SHELL_ASAR').wrapFsWithAsar(require('fs'))
|
require('ELECTRON_ASAR').wrapFsWithAsar(require('fs'))
|
||||||
|
|
||||||
// Make graceful-fs work with asar.
|
// Make graceful-fs work with asar.
|
||||||
var source = process.binding('natives')
|
var source = process.binding('natives')
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
var nativeModule = new process.NativeModule('original-fs')
|
var nativeModule = new process.NativeModule('original-fs')
|
||||||
nativeModule.cache()
|
nativeModule.cache()
|
||||||
nativeModule.compile()
|
nativeModule.compile()
|
||||||
var asar = require('ATOM_SHELL_ASAR')
|
var asar = require('ELECTRON_ASAR')
|
||||||
asar.wrapFsWithAsar(nativeModule.exports)
|
asar.wrapFsWithAsar(nativeModule.exports)
|
||||||
module.exports = nativeModule.exports`
|
module.exports = nativeModule.exports`
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,11 +47,7 @@ electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', (ev
|
||||||
// Process command line arguments.
|
// Process command line arguments.
|
||||||
var nodeIntegration = 'false'
|
var nodeIntegration = 'false'
|
||||||
var preloadScript = null
|
var preloadScript = null
|
||||||
|
for (let arg of process.argv) {
|
||||||
var ref = process.argv
|
|
||||||
var i, len, arg
|
|
||||||
for (i = 0, len = ref.length; i < len; i++) {
|
|
||||||
arg = ref[i]
|
|
||||||
if (arg.indexOf('--guest-instance-id=') === 0) {
|
if (arg.indexOf('--guest-instance-id=') === 0) {
|
||||||
// This is a guest web view.
|
// This is a guest web view.
|
||||||
process.guestInstanceId = parseInt(arg.substr(arg.indexOf('=') + 1))
|
process.guestInstanceId = parseInt(arg.substr(arg.indexOf('=') + 1))
|
||||||
|
|
|
@ -3,20 +3,8 @@
|
||||||
const ipcRenderer = require('electron').ipcRenderer
|
const ipcRenderer = require('electron').ipcRenderer
|
||||||
const remote = require('electron').remote
|
const remote = require('electron').remote
|
||||||
|
|
||||||
// Cache browser window visibility
|
|
||||||
var _isVisible = true
|
|
||||||
var _isMinimized = false
|
|
||||||
var initWindow = function initWindow () {
|
|
||||||
var currentWindow
|
|
||||||
currentWindow = remote.getCurrentWindow()
|
|
||||||
_isVisible = currentWindow.isVisible()
|
|
||||||
_isMinimized = currentWindow.isMinimized()
|
|
||||||
}
|
|
||||||
initWindow()
|
|
||||||
|
|
||||||
// Helper function to resolve relative url.
|
// Helper function to resolve relative url.
|
||||||
var a = window.top.document.createElement('a')
|
var a = window.top.document.createElement('a')
|
||||||
|
|
||||||
var resolveURL = function (url) {
|
var resolveURL = function (url) {
|
||||||
a.href = url
|
a.href = url
|
||||||
return a.href
|
return a.href
|
||||||
|
@ -171,8 +159,6 @@ window.alert = function (message, title) {
|
||||||
title: title,
|
title: title,
|
||||||
buttons: buttons
|
buttons: buttons
|
||||||
})
|
})
|
||||||
|
|
||||||
// Alert should always return undefined.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// And the confirm().
|
// And the confirm().
|
||||||
|
@ -200,17 +186,6 @@ if (process.openerId != null) {
|
||||||
window.opener = BrowserWindowProxy.getOrCreate(process.openerId)
|
window.opener = BrowserWindowProxy.getOrCreate(process.openerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcRenderer.on('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', function (event, isVisible, isMinimized) {
|
|
||||||
var hasChanged = _isVisible !== isVisible || _isMinimized !== isMinimized
|
|
||||||
|
|
||||||
if (hasChanged) {
|
|
||||||
_isVisible = isVisible
|
|
||||||
_isMinimized = isMinimized
|
|
||||||
|
|
||||||
document.dispatchEvent(new Event('visibilitychange'))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcRenderer.on('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (event, sourceId, message, sourceOrigin) {
|
ipcRenderer.on('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (event, sourceId, message, sourceOrigin) {
|
||||||
// Manually dispatch event instead of using postMessage because we also need to
|
// Manually dispatch event instead of using postMessage because we also need to
|
||||||
// set event.source.
|
// set event.source.
|
||||||
|
@ -249,19 +224,26 @@ Object.defineProperty(window.history, 'length', {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// The initial visibilityState.
|
||||||
|
let cachedVisibilityState = process.argv.includes('--hidden-page') ? 'hidden' : 'visible'
|
||||||
|
|
||||||
|
// Subscribe to visibilityState changes.
|
||||||
|
ipcRenderer.on('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', function (event, visibilityState) {
|
||||||
|
if (cachedVisibilityState !== visibilityState) {
|
||||||
|
cachedVisibilityState = visibilityState
|
||||||
|
document.dispatchEvent(new Event('visibilitychange'))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Make document.hidden and document.visibilityState return the correct value.
|
// Make document.hidden and document.visibilityState return the correct value.
|
||||||
Object.defineProperty(document, 'hidden', {
|
Object.defineProperty(document, 'hidden', {
|
||||||
get: function () {
|
get: function () {
|
||||||
return _isMinimized || !_isVisible
|
return cachedVisibilityState !== 'visible'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
Object.defineProperty(document, 'visibilityState', {
|
Object.defineProperty(document, 'visibilityState', {
|
||||||
get: function () {
|
get: function () {
|
||||||
if (_isVisible && !_isMinimized) {
|
return cachedVisibilityState
|
||||||
return 'visible'
|
|
||||||
} else {
|
|
||||||
return 'hidden'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -12,7 +12,7 @@ var WEB_VIEW_EVENTS = {
|
||||||
'did-frame-finish-load': ['isMainFrame'],
|
'did-frame-finish-load': ['isMainFrame'],
|
||||||
'did-start-loading': [],
|
'did-start-loading': [],
|
||||||
'did-stop-loading': [],
|
'did-stop-loading': [],
|
||||||
'did-get-response-details': ['status', 'newURL', 'originalURL', 'httpResponseCode', 'requestMethod', 'referrer', 'headers'],
|
'did-get-response-details': ['status', 'newURL', 'originalURL', 'httpResponseCode', 'requestMethod', 'referrer', 'headers', 'resourceType'],
|
||||||
'did-get-redirect-request': ['oldURL', 'newURL', 'isMainFrame'],
|
'did-get-redirect-request': ['oldURL', 'newURL', 'isMainFrame'],
|
||||||
'dom-ready': [],
|
'dom-ready': [],
|
||||||
'console-message': ['level', 'message', 'line', 'sourceId'],
|
'console-message': ['level', 'message', 'line', 'sourceId'],
|
||||||
|
|
|
@ -8,7 +8,7 @@ import sys
|
||||||
|
|
||||||
BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \
|
BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \
|
||||||
'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent'
|
'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent'
|
||||||
LIBCHROMIUMCONTENT_COMMIT = '4e506867ad95907e0a9cbec4ab3ee0f84214de94'
|
LIBCHROMIUMCONTENT_COMMIT = '1a4c5e51a670633ff3ecd4448ad01ba21b440542'
|
||||||
|
|
||||||
PLATFORM = {
|
PLATFORM = {
|
||||||
'cygwin': 'win32',
|
'cygwin': 'win32',
|
||||||
|
|
|
@ -101,6 +101,32 @@ describe('browser-window module', function () {
|
||||||
w.loadURL('about:blank')
|
w.loadURL('about:blank')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should emit did-get-response-details event', function (done) {
|
||||||
|
// expected {fileName: resourceType} pairs
|
||||||
|
var expectedResources = {
|
||||||
|
'did-get-response-details.html': 'mainFrame',
|
||||||
|
'logo.png': 'image'
|
||||||
|
}
|
||||||
|
var responses = 0;
|
||||||
|
w.webContents.on('did-get-response-details', function (event, status, newUrl, oldUrl, responseCode, method, referrer, headers, resourceType) {
|
||||||
|
responses++
|
||||||
|
var fileName = newUrl.slice(newUrl.lastIndexOf('/') + 1)
|
||||||
|
var expectedType = expectedResources[fileName]
|
||||||
|
assert(!!expectedType, `Unexpected response details for ${newUrl}`)
|
||||||
|
assert(typeof status === 'boolean', 'status should be boolean')
|
||||||
|
assert.equal(responseCode, 200)
|
||||||
|
assert.equal(method, 'GET')
|
||||||
|
assert(typeof referrer === 'string', 'referrer should be string')
|
||||||
|
assert(!!headers, 'headers should be present')
|
||||||
|
assert(typeof headers === 'object', 'headers should be object')
|
||||||
|
assert.equal(resourceType, expectedType, 'Incorrect resourceType')
|
||||||
|
if (responses === Object.keys(expectedResources).length) {
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
w.loadURL('file://' + path.join(fixtures, 'pages', 'did-get-response-details.html'))
|
||||||
|
})
|
||||||
|
|
||||||
it('should emit did-fail-load event for files that do not exist', function (done) {
|
it('should emit did-fail-load event for files that do not exist', function (done) {
|
||||||
w.webContents.on('did-fail-load', function (event, code, desc, url, isMainFrame) {
|
w.webContents.on('did-fail-load', function (event, code, desc, url, isMainFrame) {
|
||||||
assert.equal(code, -6)
|
assert.equal(code, -6)
|
||||||
|
@ -127,6 +153,14 @@ describe('browser-window module', function () {
|
||||||
})
|
})
|
||||||
w.loadURL('file://' + path.join(fixtures, 'api', 'did-fail-load-iframe.html'))
|
w.loadURL('file://' + path.join(fixtures, 'api', 'did-fail-load-iframe.html'))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('does not crash in did-fail-provisional-load handler', function (done) {
|
||||||
|
w.webContents.once('did-fail-provisional-load', function () {
|
||||||
|
w.loadURL('http://localhost:11111')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadURL('http://localhost:11111')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('BrowserWindow.show()', function () {
|
describe('BrowserWindow.show()', function () {
|
||||||
|
|
|
@ -7,12 +7,18 @@ const session = remote.session
|
||||||
describe('webRequest module', function () {
|
describe('webRequest module', function () {
|
||||||
var ses = session.defaultSession
|
var ses = session.defaultSession
|
||||||
var server = http.createServer(function (req, res) {
|
var server = http.createServer(function (req, res) {
|
||||||
res.setHeader('Custom', ['Header'])
|
if (req.url == '/serverRedirect') {
|
||||||
var content = req.url
|
res.statusCode = 301
|
||||||
if (req.headers.accept === '*/*;test/header') {
|
res.setHeader('Location', 'http://' + req.rawHeaders[1])
|
||||||
content += 'header/received'
|
res.end()
|
||||||
|
} else {
|
||||||
|
res.setHeader('Custom', ['Header'])
|
||||||
|
var content = req.url
|
||||||
|
if (req.headers.accept === '*/*;test/header') {
|
||||||
|
content += 'header/received'
|
||||||
|
}
|
||||||
|
res.end(content)
|
||||||
}
|
}
|
||||||
res.end(content)
|
|
||||||
})
|
})
|
||||||
var defaultURL = null
|
var defaultURL = null
|
||||||
|
|
||||||
|
@ -297,6 +303,44 @@ describe('webRequest module', function () {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('follows server redirect', function (done) {
|
||||||
|
ses.webRequest.onHeadersReceived(function (details, callback) {
|
||||||
|
var responseHeaders = details.responseHeaders
|
||||||
|
callback({
|
||||||
|
responseHeaders: responseHeaders,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
$.ajax({
|
||||||
|
url: defaultURL + 'serverRedirect',
|
||||||
|
success: function (data, status, xhr) {
|
||||||
|
assert.equal(xhr.getResponseHeader('Custom'), 'Header')
|
||||||
|
done()
|
||||||
|
},
|
||||||
|
error: function (xhr, errorType) {
|
||||||
|
done(errorType)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can change the header status', function (done) {
|
||||||
|
ses.webRequest.onHeadersReceived(function (details, callback) {
|
||||||
|
var responseHeaders = details.responseHeaders
|
||||||
|
callback({
|
||||||
|
responseHeaders: responseHeaders,
|
||||||
|
statusLine: "HTTP/1.1 404 Not Found"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
$.ajax({
|
||||||
|
url: defaultURL,
|
||||||
|
success: function (data, status, xhr) {
|
||||||
|
},
|
||||||
|
error: function (xhr, errorType) {
|
||||||
|
assert.equal(xhr.getResponseHeader('Custom'), 'Header')
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('webRequest.onResponseStarted', function () {
|
describe('webRequest.onResponseStarted', function () {
|
||||||
|
|
5
spec/fixtures/pages/did-get-response-details.html
vendored
Normal file
5
spec/fixtures/pages/did-get-response-details.html
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<img src="../assets/logo.png" />
|
||||||
|
</body>
|
||||||
|
</html>
|
7
spec/fixtures/pages/ping.html
vendored
Normal file
7
spec/fixtures/pages/ping.html
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript" charset="utf-8">
|
||||||
|
require('electron').ipcRenderer.send('pong')
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
5
spec/fixtures/pages/webview-no-script.html
vendored
Normal file
5
spec/fixtures/pages/webview-no-script.html
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<webview nodeintegration src="ping.html"/>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -2,7 +2,7 @@ const assert = require('assert')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const http = require('http')
|
const http = require('http')
|
||||||
const url = require('url')
|
const url = require('url')
|
||||||
const {app, session} = require('electron').remote
|
const {app, session, ipcMain, BrowserWindow} = require('electron').remote
|
||||||
|
|
||||||
describe('<webview> tag', function () {
|
describe('<webview> tag', function () {
|
||||||
this.timeout(10000)
|
this.timeout(10000)
|
||||||
|
@ -20,6 +20,15 @@ describe('<webview> tag', function () {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('works without script tag in page', function (done) {
|
||||||
|
let w = new BrowserWindow({show: false})
|
||||||
|
ipcMain.once('pong', function () {
|
||||||
|
w.destroy()
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadURL('file://' + fixtures + '/pages/webview-no-script.html')
|
||||||
|
})
|
||||||
|
|
||||||
describe('src attribute', function () {
|
describe('src attribute', function () {
|
||||||
it('specifies the page to load', function (done) {
|
it('specifies the page to load', function (done) {
|
||||||
webview.addEventListener('console-message', function (e) {
|
webview.addEventListener('console-message', function (e) {
|
||||||
|
@ -155,6 +164,18 @@ describe('<webview> tag', function () {
|
||||||
webview.src = 'file://' + fixtures + '/pages/e.html'
|
webview.src = 'file://' + fixtures + '/pages/e.html'
|
||||||
document.body.appendChild(webview)
|
document.body.appendChild(webview)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('works without script tag in page', function (done) {
|
||||||
|
var listener = function (e) {
|
||||||
|
assert.equal(e.message, 'function object object')
|
||||||
|
webview.removeEventListener('console-message', listener)
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
webview.addEventListener('console-message', listener)
|
||||||
|
webview.setAttribute('preload', fixtures + '/module/preload.js')
|
||||||
|
webview.src = 'file://' + fixtures + '/pages/base-page.html'
|
||||||
|
document.body.appendChild(webview)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('httpreferrer attribute', function () {
|
describe('httpreferrer attribute', function () {
|
||||||
|
@ -763,4 +784,33 @@ describe('<webview> tag', function () {
|
||||||
document.body.appendChild(webview)
|
document.body.appendChild(webview)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('did-get-response-details event', function () {
|
||||||
|
it('emits for the page and its resources', function (done) {
|
||||||
|
// expected {fileName: resourceType} pairs
|
||||||
|
var expectedResources = {
|
||||||
|
'did-get-response-details.html': 'mainFrame',
|
||||||
|
'logo.png': 'image'
|
||||||
|
}
|
||||||
|
var responses = 0;
|
||||||
|
webview.addEventListener('did-get-response-details', function (event) {
|
||||||
|
responses++
|
||||||
|
var fileName = event.newURL.slice(event.newURL.lastIndexOf('/') + 1)
|
||||||
|
var expectedType = expectedResources[fileName]
|
||||||
|
assert(!!expectedType, `Unexpected response details for ${event.newURL}`)
|
||||||
|
assert(typeof event.status === 'boolean', 'status should be boolean')
|
||||||
|
assert.equal(event.httpResponseCode, 200)
|
||||||
|
assert.equal(event.requestMethod, 'GET')
|
||||||
|
assert(typeof event.referrer === 'string', 'referrer should be string')
|
||||||
|
assert(!!event.headers, 'headers should be present')
|
||||||
|
assert(typeof event.headers === 'object', 'headers should be object')
|
||||||
|
assert.equal(event.resourceType, expectedType, 'Incorrect resourceType')
|
||||||
|
if (responses === Object.keys(expectedResources).length) {
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
webview.src = 'file://' + path.join(fixtures, 'pages', 'did-get-response-details.html')
|
||||||
|
document.body.appendChild(webview)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
2
vendor/brightray
vendored
2
vendor/brightray
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 242feb1c817565de6592e9e672c136635bfff453
|
Subproject commit 7b037805e0dbb5976bdca5808f0ef4c937db1f6e
|
Loading…
Add table
Reference in a new issue