mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
94 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4608f5e9cd | ||
|
|
9300859983 | ||
|
|
52240750a1 | ||
|
|
d76bd4a103 | ||
|
|
bfac7f7a17 | ||
|
|
36d2512ff8 | ||
|
|
ca7e2c4d96 | ||
|
|
817dfbdc27 | ||
|
|
5fa7ae7d72 | ||
|
|
c54eca8dff | ||
|
|
72f5381c31 | ||
|
|
7ca2363d78 | ||
|
|
dec7c40fd8 | ||
|
|
a8846e0432 | ||
|
|
8c5f171a93 | ||
|
|
ea74e825c9 | ||
|
|
2b3ef714bd | ||
|
|
23afffa46d | ||
|
|
129cdb7680 | ||
|
|
8d3404d26c | ||
|
|
05e0564426 | ||
|
|
d8be645d5a | ||
|
|
3f499f69ff | ||
|
|
75b24c7d76 | ||
|
|
c6cf91d11f | ||
|
|
3a50c9e48c | ||
|
|
7c2b1468c8 | ||
|
|
fb6c80d12e | ||
|
|
d826e1e5fb | ||
|
|
04a0aaa35f | ||
|
|
f5fbd52dbd | ||
|
|
5575d17d0e | ||
|
|
0e7970fec5 | ||
|
|
fdfd8807a0 | ||
|
|
da07e72f20 | ||
|
|
f4a27f699a | ||
|
|
e3c21424de | ||
|
|
b5aa2a31a1 | ||
|
|
05ae1960d1 | ||
|
|
dde791d475 | ||
|
|
16b2f08cd3 | ||
|
|
0143a45488 | ||
|
|
2f1683445b | ||
|
|
4c78f98da6 | ||
|
|
3ff2959f0c | ||
|
|
36c4b1705d | ||
|
|
d8adbc0875 | ||
|
|
b527846ee4 | ||
|
|
ee45f0e8bc | ||
|
|
ca5ee0fc81 | ||
|
|
ecf29f72bc | ||
|
|
c811beb1e2 | ||
|
|
0c091428d3 | ||
|
|
858198a2bd | ||
|
|
1649d8f900 | ||
|
|
eb42fdbbc6 | ||
|
|
6cc571bdfe | ||
|
|
da648511b3 | ||
|
|
18b3dfa350 | ||
|
|
05be71e9bc | ||
|
|
36819e2638 | ||
|
|
9b585458c1 | ||
|
|
c424d0e9f3 | ||
|
|
81783b255e | ||
|
|
80c8ab4c39 | ||
|
|
826a4e0e48 | ||
|
|
7917748b21 | ||
|
|
b7f974f469 | ||
|
|
5c5fd377f7 | ||
|
|
0a995c3731 | ||
|
|
47b754e914 | ||
|
|
00ef99826d | ||
|
|
45943302ee | ||
|
|
2157f898bb | ||
|
|
132c7aba2d | ||
|
|
1ae88f0f0f | ||
|
|
c0f0fcba7b | ||
|
|
cdb1711fe1 | ||
|
|
20b4cae980 | ||
|
|
67bc4afe88 | ||
|
|
fb78169396 | ||
|
|
ba7e26539f | ||
|
|
500d15f53a | ||
|
|
fad977e27d | ||
|
|
4983ef77bd | ||
|
|
4a6066c69e | ||
|
|
1690df9bcf | ||
|
|
5c94f7ccd4 | ||
|
|
494c3f3255 | ||
|
|
ec4d596189 | ||
|
|
bc04e951cf | ||
|
|
916fa4b9a8 | ||
|
|
0d3cc8aaa7 | ||
|
|
51cadc6e90 |
10
README.md
10
README.md
@@ -1,4 +1,7 @@
|
||||
# Electron [](https://travis-ci.org/atom/electron)
|
||||
[](http://electron.atom.io/)
|
||||
|
||||
[](https://travis-ci.org/atom/electron)
|
||||
[](https://david-dm.org/atom/electron#info=devDependencies)
|
||||
|
||||
:zap: *formerly known as Atom Shell* :zap:
|
||||
|
||||
@@ -7,6 +10,9 @@ using JavaScript, HTML and CSS. It is based on [io.js](http://iojs.org) and
|
||||
[Chromium](http://www.chromium.org) and is used in the [Atom
|
||||
editor](https://github.com/atom/atom).
|
||||
|
||||
Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important
|
||||
announcements.
|
||||
|
||||
## Downloads
|
||||
|
||||
Prebuilt binaries and debug symbols of Electron for Linux, Windows and Mac can
|
||||
@@ -15,7 +21,7 @@ be found on the [releases](https://github.com/atom/electron/releases) page.
|
||||
You can also use [`npm`](https://docs.npmjs.com/) to install prebuilt electron
|
||||
binaries:
|
||||
|
||||
```
|
||||
```sh
|
||||
# Install the `electron` command globally in your $PATH
|
||||
npm install electron-prebuilt -g
|
||||
|
||||
|
||||
2
atom.gyp
2
atom.gyp
@@ -4,7 +4,7 @@
|
||||
'product_name%': 'Electron',
|
||||
'company_name%': 'GitHub, Inc',
|
||||
'company_abbr%': 'github',
|
||||
'version%': '0.25.0',
|
||||
'version%': '0.25.2',
|
||||
|
||||
'atom_source_root': '<!(["python", "tools/atom_source_root.py"])',
|
||||
},
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <shlobj.h>
|
||||
#endif
|
||||
|
||||
#include "atom/browser/api/atom_api_menu.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/browser.h"
|
||||
@@ -25,6 +29,10 @@
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#endif
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
using atom::Browser;
|
||||
@@ -200,6 +208,13 @@ void App::SetDesktopName(const std::string& desktop_name) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void App::SetAppUserModelId(const std::string& app_id) {
|
||||
#if defined(OS_WIN)
|
||||
base::string16 app_id_utf16 = base::UTF8ToUTF16(app_id);
|
||||
SetCurrentProcessExplicitAppUserModelID(app_id_utf16.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
auto browser = base::Unretained(Browser::Get());
|
||||
@@ -222,7 +237,8 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
|
||||
.SetMethod("setPath", &App::SetPath)
|
||||
.SetMethod("getPath", &App::GetPath)
|
||||
.SetMethod("resolveProxy", &App::ResolveProxy)
|
||||
.SetMethod("setDesktopName", &App::SetDesktopName);
|
||||
.SetMethod("setDesktopName", &App::SetDesktopName)
|
||||
.SetMethod("setAppUserModelId", &App::SetAppUserModelId);
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -61,6 +61,7 @@ class App : public mate::EventEmitter,
|
||||
|
||||
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
|
||||
void SetDesktopName(const std::string& desktop_name);
|
||||
void SetAppUserModelId(const std::string& app_id);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(App);
|
||||
};
|
||||
|
||||
@@ -17,20 +17,6 @@ using content::TracingController;
|
||||
|
||||
namespace mate {
|
||||
|
||||
template<typename T>
|
||||
struct Converter<std::set<T> > {
|
||||
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const std::set<T>& val) {
|
||||
v8::Handle<v8::Array> result = v8::Array::New(
|
||||
isolate, static_cast<int>(val.size()));
|
||||
typename std::set<T>::const_iterator it;
|
||||
int i;
|
||||
for (i = 0, it = val.begin(); it != val.end(); ++it, ++i)
|
||||
result->Set(i, Converter<T>::ToV8(isolate, *it));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<base::trace_event::CategoryFilter> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
|
||||
@@ -4,17 +4,23 @@
|
||||
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_javascript_dialog_manager.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/web_dialog_helper.h"
|
||||
#include "atom/browser/web_view_manager.h"
|
||||
#include "atom/common/api/api_messages.h"
|
||||
#include "atom/common/native_mate_converters/gfx_converter.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "brightray/browser/inspectable_web_contents.h"
|
||||
#include "brightray/browser/media/media_stream_devices_controller.h"
|
||||
#include "content/public/browser/favicon_status.h"
|
||||
#include "content/public/browser/navigation_details.h"
|
||||
#include "content/public/browser/navigation_entry.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
@@ -22,11 +28,13 @@
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "content/public/browser/resource_request_details.h"
|
||||
#include "content/public/browser/service_worker_context.h"
|
||||
#include "content/public/browser/storage_partition.h"
|
||||
#include "content/public/browser/site_instance.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
#include "vendor/brightray/browser/media/media_stream_devices_controller.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
@@ -49,6 +57,22 @@ NativeWindow* GetWindowFromGuest(const content::WebContents* guest) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
content::ServiceWorkerContext* GetServiceWorkerContext(
|
||||
const content::WebContents* web_contents) {
|
||||
auto context = web_contents->GetBrowserContext();
|
||||
auto site_instance = web_contents->GetSiteInstance();
|
||||
if (!context || !site_instance)
|
||||
return nullptr;
|
||||
|
||||
content::StoragePartition* storage_partition =
|
||||
content::BrowserContext::GetStoragePartition(
|
||||
context, site_instance);
|
||||
|
||||
DCHECK(storage_partition);
|
||||
|
||||
return storage_partition->GetServiceWorkerContext();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
WebContents::WebContents(content::WebContents* web_contents)
|
||||
@@ -136,11 +160,20 @@ content::WebContents* WebContents::OpenURLFromTab(
|
||||
load_url_params.is_renderer_initiated = params.is_renderer_initiated;
|
||||
load_url_params.transferred_global_request_id =
|
||||
params.transferred_global_request_id;
|
||||
load_url_params.should_clear_history_list = true;
|
||||
|
||||
web_contents()->GetController().LoadURLWithParams(load_url_params);
|
||||
return web_contents();
|
||||
}
|
||||
|
||||
content::JavaScriptDialogManager* WebContents::GetJavaScriptDialogManager(
|
||||
content::WebContents* source) {
|
||||
if (!dialog_manager_)
|
||||
dialog_manager_.reset(new AtomJavaScriptDialogManager);
|
||||
|
||||
return dialog_manager_.get();
|
||||
}
|
||||
|
||||
void WebContents::RunFileChooser(content::WebContents* guest,
|
||||
const content::FileChooserParams& params) {
|
||||
if (!web_dialog_helper_)
|
||||
@@ -191,6 +224,12 @@ void WebContents::RenderProcessGone(base::TerminationStatus status) {
|
||||
Emit("crashed");
|
||||
}
|
||||
|
||||
void WebContents::DocumentLoadedInFrame(
|
||||
content::RenderFrameHost* render_frame_host) {
|
||||
if (!render_frame_host->GetParent())
|
||||
Emit("dom-ready");
|
||||
}
|
||||
|
||||
void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host,
|
||||
const GURL& validated_url) {
|
||||
bool is_main_frame = !render_frame_host->GetParent();
|
||||
@@ -253,7 +292,22 @@ void WebContents::DidNavigateMainFrame(
|
||||
|
||||
void WebContents::TitleWasSet(content::NavigationEntry* entry,
|
||||
bool explicit_set) {
|
||||
Emit("page-title-set", entry->GetTitle(), explicit_set);
|
||||
// Back/Forward navigation may have pruned entries.
|
||||
if (entry)
|
||||
Emit("page-title-set", entry->GetTitle(), explicit_set);
|
||||
}
|
||||
|
||||
void WebContents::DidUpdateFaviconURL(
|
||||
const std::vector<content::FaviconURL>& urls) {
|
||||
std::set<GURL> unique_urls;
|
||||
for (auto iter = urls.begin(); iter != urls.end(); ++iter) {
|
||||
if (iter->icon_type != content::FaviconURL::FAVICON)
|
||||
continue;
|
||||
const GURL& url = iter->icon_url;
|
||||
if (url.is_valid())
|
||||
unique_urls.insert(url);
|
||||
}
|
||||
Emit("page-favicon-updated", unique_urls);
|
||||
}
|
||||
|
||||
bool WebContents::OnMessageReceived(const IPC::Message& message) {
|
||||
@@ -295,8 +349,7 @@ void WebContents::WebContentsDestroyed() {
|
||||
|
||||
void WebContents::NavigationEntryCommitted(
|
||||
const content::LoadCommittedDetails& load_details) {
|
||||
auto entry = web_contents()->GetController().GetLastCommittedEntry();
|
||||
entry->SetVirtualURL(load_details.entry->GetOriginalRequestURL());
|
||||
Emit("navigation-entry-commited", load_details.entry->GetURL());
|
||||
}
|
||||
|
||||
void WebContents::DidAttach(int guest_proxy_routing_id) {
|
||||
@@ -364,21 +417,22 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
|
||||
blink::WebReferrerPolicyDefault);
|
||||
|
||||
params.transition_type = ui::PAGE_TRANSITION_TYPED;
|
||||
params.should_clear_history_list = true;
|
||||
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
|
||||
web_contents()->GetController().LoadURLWithParams(params);
|
||||
}
|
||||
|
||||
GURL WebContents::GetURL() const {
|
||||
auto entry = web_contents()->GetController().GetLastCommittedEntry();
|
||||
if (!entry)
|
||||
return GURL::EmptyGURL();
|
||||
return entry->GetVirtualURL();
|
||||
}
|
||||
|
||||
base::string16 WebContents::GetTitle() const {
|
||||
return web_contents()->GetTitle();
|
||||
}
|
||||
|
||||
gfx::Image WebContents::GetFavicon() const {
|
||||
auto entry = web_contents()->GetController().GetLastCommittedEntry();
|
||||
if (!entry)
|
||||
return gfx::Image();
|
||||
return entry->GetFavicon().image;
|
||||
}
|
||||
|
||||
bool WebContents::IsLoading() const {
|
||||
return web_contents()->IsLoading();
|
||||
}
|
||||
@@ -391,46 +445,8 @@ void WebContents::Stop() {
|
||||
web_contents()->Stop();
|
||||
}
|
||||
|
||||
void WebContents::Reload(const mate::Dictionary& options) {
|
||||
// Navigating to a URL would always restart the renderer process, we want this
|
||||
// because normal reloading will break our node integration.
|
||||
// This is done by AtomBrowserClient::ShouldSwapProcessesForNavigation.
|
||||
LoadURL(GetURL(), options);
|
||||
}
|
||||
|
||||
void WebContents::ReloadIgnoringCache(const mate::Dictionary& options) {
|
||||
// Hack to remove pending entries that ignores cache and treated as a fresh
|
||||
// load.
|
||||
void WebContents::ReloadIgnoringCache() {
|
||||
web_contents()->GetController().ReloadIgnoringCache(false);
|
||||
Reload(options);
|
||||
}
|
||||
|
||||
bool WebContents::CanGoBack() const {
|
||||
return web_contents()->GetController().CanGoBack();
|
||||
}
|
||||
|
||||
bool WebContents::CanGoForward() const {
|
||||
return web_contents()->GetController().CanGoForward();
|
||||
}
|
||||
|
||||
bool WebContents::CanGoToOffset(int offset) const {
|
||||
return web_contents()->GetController().CanGoToOffset(offset);
|
||||
}
|
||||
|
||||
void WebContents::GoBack() {
|
||||
web_contents()->GetController().GoBack();
|
||||
}
|
||||
|
||||
void WebContents::GoForward() {
|
||||
web_contents()->GetController().GoForward();
|
||||
}
|
||||
|
||||
void WebContents::GoToIndex(int index) {
|
||||
web_contents()->GetController().GoToIndex(index);
|
||||
}
|
||||
|
||||
void WebContents::GoToOffset(int offset) {
|
||||
web_contents()->GetController().GoToOffset(offset);
|
||||
}
|
||||
|
||||
int WebContents::GetRoutingID() const {
|
||||
@@ -470,6 +486,13 @@ bool WebContents::IsDevToolsOpened() {
|
||||
return storage_->IsDevToolsViewShowing();
|
||||
}
|
||||
|
||||
void WebContents::InspectElement(int x, int y) {
|
||||
OpenDevTools();
|
||||
scoped_refptr<content::DevToolsAgentHost> agent(
|
||||
content::DevToolsAgentHost::GetOrCreateFor(storage_->GetWebContents()));
|
||||
agent->InspectElement(x, y);
|
||||
}
|
||||
|
||||
void WebContents::Undo() {
|
||||
web_contents()->Undo();
|
||||
}
|
||||
@@ -561,6 +584,27 @@ void WebContents::SetAllowTransparency(bool allow) {
|
||||
}
|
||||
}
|
||||
|
||||
void WebContents::HasServiceWorker(
|
||||
const base::Callback<void(bool)>& callback) {
|
||||
auto context = GetServiceWorkerContext(web_contents());
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
context->CheckHasServiceWorker(web_contents()->GetLastCommittedURL(),
|
||||
GURL::EmptyGURL(),
|
||||
callback);
|
||||
}
|
||||
|
||||
void WebContents::UnregisterServiceWorker(
|
||||
const base::Callback<void(bool)>& callback) {
|
||||
auto context = GetServiceWorkerContext(web_contents());
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
context->UnregisterServiceWorker(web_contents()->GetLastCommittedURL(),
|
||||
callback);
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
if (template_.IsEmpty())
|
||||
@@ -568,20 +612,12 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
||||
.SetMethod("destroy", &WebContents::Destroy)
|
||||
.SetMethod("isAlive", &WebContents::IsAlive)
|
||||
.SetMethod("_loadUrl", &WebContents::LoadURL)
|
||||
.SetMethod("getUrl", &WebContents::GetURL)
|
||||
.SetMethod("getTitle", &WebContents::GetTitle)
|
||||
.SetMethod("getFavicon", &WebContents::GetFavicon)
|
||||
.SetMethod("isLoading", &WebContents::IsLoading)
|
||||
.SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse)
|
||||
.SetMethod("stop", &WebContents::Stop)
|
||||
.SetMethod("_reload", &WebContents::Reload)
|
||||
.SetMethod("_stop", &WebContents::Stop)
|
||||
.SetMethod("_reloadIgnoringCache", &WebContents::ReloadIgnoringCache)
|
||||
.SetMethod("canGoBack", &WebContents::CanGoBack)
|
||||
.SetMethod("canGoForward", &WebContents::CanGoForward)
|
||||
.SetMethod("canGoToOffset", &WebContents::CanGoToOffset)
|
||||
.SetMethod("goBack", &WebContents::GoBack)
|
||||
.SetMethod("goForward", &WebContents::GoForward)
|
||||
.SetMethod("goToIndex", &WebContents::GoToIndex)
|
||||
.SetMethod("goToOffset", &WebContents::GoToOffset)
|
||||
.SetMethod("getRoutingId", &WebContents::GetRoutingID)
|
||||
.SetMethod("getProcessId", &WebContents::GetProcessID)
|
||||
.SetMethod("isCrashed", &WebContents::IsCrashed)
|
||||
@@ -591,6 +627,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
||||
.SetMethod("openDevTools", &WebContents::OpenDevTools)
|
||||
.SetMethod("closeDevTools", &WebContents::CloseDevTools)
|
||||
.SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened)
|
||||
.SetMethod("inspectElement", &WebContents::InspectElement)
|
||||
.SetMethod("undo", &WebContents::Undo)
|
||||
.SetMethod("redo", &WebContents::Redo)
|
||||
.SetMethod("cut", &WebContents::Cut)
|
||||
@@ -605,6 +642,9 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
||||
.SetMethod("setAutoSize", &WebContents::SetAutoSize)
|
||||
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
|
||||
.SetMethod("isGuest", &WebContents::is_guest)
|
||||
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
|
||||
.SetMethod("unregisterServiceWorker",
|
||||
&WebContents::UnregisterServiceWorker)
|
||||
.Build());
|
||||
|
||||
return mate::ObjectTemplateBuilder(
|
||||
|
||||
@@ -6,13 +6,16 @@
|
||||
#define ATOM_BROWSER_API_ATOM_API_WEB_CONTENTS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "brightray/browser/default_web_contents_delegate.h"
|
||||
#include "content/public/browser/browser_plugin_guest_delegate.h"
|
||||
#include "content/public/common/favicon_url.h"
|
||||
#include "content/public/browser/web_contents_delegate.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
||||
namespace brightray {
|
||||
class InspectableWebContents;
|
||||
@@ -24,6 +27,7 @@ class Dictionary;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomJavaScriptDialogManager;
|
||||
class WebDialogHelper;
|
||||
|
||||
namespace api {
|
||||
@@ -44,20 +48,12 @@ class WebContents : public mate::EventEmitter,
|
||||
void Destroy();
|
||||
bool IsAlive() const;
|
||||
void LoadURL(const GURL& url, const mate::Dictionary& options);
|
||||
GURL GetURL() const;
|
||||
base::string16 GetTitle() const;
|
||||
gfx::Image GetFavicon() const;
|
||||
bool IsLoading() const;
|
||||
bool IsWaitingForResponse() const;
|
||||
void Stop();
|
||||
void Reload(const mate::Dictionary& options);
|
||||
void ReloadIgnoringCache(const mate::Dictionary& options);
|
||||
bool CanGoBack() const;
|
||||
bool CanGoForward() const;
|
||||
bool CanGoToOffset(int offset) const;
|
||||
void GoBack();
|
||||
void GoForward();
|
||||
void GoToIndex(int index);
|
||||
void GoToOffset(int offset);
|
||||
void ReloadIgnoringCache();
|
||||
int GetRoutingID() const;
|
||||
int GetProcessID() const;
|
||||
bool IsCrashed() const;
|
||||
@@ -67,6 +63,9 @@ class WebContents : public mate::EventEmitter,
|
||||
void OpenDevTools();
|
||||
void CloseDevTools();
|
||||
bool IsDevToolsOpened();
|
||||
void InspectElement(int x, int y);
|
||||
void HasServiceWorker(const base::Callback<void(bool)>&);
|
||||
void UnregisterServiceWorker(const base::Callback<void(bool)>&);
|
||||
|
||||
// Editing commands.
|
||||
void Undo();
|
||||
@@ -130,6 +129,8 @@ class WebContents : public mate::EventEmitter,
|
||||
content::WebContents* OpenURLFromTab(
|
||||
content::WebContents* source,
|
||||
const content::OpenURLParams& params) override;
|
||||
content::JavaScriptDialogManager* GetJavaScriptDialogManager(
|
||||
content::WebContents* source) override;
|
||||
void RunFileChooser(content::WebContents* web_contents,
|
||||
const content::FileChooserParams& params) override;
|
||||
void EnumerateDirectory(content::WebContents* web_contents,
|
||||
@@ -149,6 +150,8 @@ class WebContents : public mate::EventEmitter,
|
||||
// content::WebContentsObserver:
|
||||
void RenderViewDeleted(content::RenderViewHost*) override;
|
||||
void RenderProcessGone(base::TerminationStatus status) override;
|
||||
void DocumentLoadedInFrame(
|
||||
content::RenderFrameHost* render_frame_host) override;
|
||||
void DidFinishLoad(content::RenderFrameHost* render_frame_host,
|
||||
const GURL& validated_url) override;
|
||||
void DidFailLoad(content::RenderFrameHost* render_frame_host,
|
||||
@@ -175,6 +178,8 @@ class WebContents : public mate::EventEmitter,
|
||||
void NavigationEntryCommitted(
|
||||
const content::LoadCommittedDetails& load_details) override;
|
||||
void TitleWasSet(content::NavigationEntry* entry, bool explicit_set) override;
|
||||
void DidUpdateFaviconURL(
|
||||
const std::vector<content::FaviconURL>& urls) override;
|
||||
|
||||
// content::BrowserPluginGuestDelegate:
|
||||
void DidAttach(int guest_proxy_routing_id) final;
|
||||
@@ -201,6 +206,7 @@ class WebContents : public mate::EventEmitter,
|
||||
const gfx::Size& new_size);
|
||||
|
||||
scoped_ptr<WebDialogHelper> web_dialog_helper_;
|
||||
scoped_ptr<AtomJavaScriptDialogManager> dialog_manager_;
|
||||
|
||||
// Unique ID for a guest WebContents.
|
||||
int guest_instance_id_;
|
||||
|
||||
79
atom/browser/api/lib/navigation-controller.coffee
Normal file
79
atom/browser/api/lib/navigation-controller.coffee
Normal file
@@ -0,0 +1,79 @@
|
||||
# JavaScript implementation of Chromium's NavigationController.
|
||||
# Instead of relying on Chromium for history control, we compeletely do history
|
||||
# control on user land, and only rely on WebContents.loadUrl for navigation.
|
||||
# This helps us avoid Chromium's various optimizations so we can ensure renderer
|
||||
# process is restarted everytime.
|
||||
class NavigationController
|
||||
constructor: (@webContents) ->
|
||||
@history = []
|
||||
@currentIndex = -1
|
||||
@pendingIndex = -1
|
||||
|
||||
@webContents.on 'navigation-entry-commited', (event, url) =>
|
||||
if @pendingIndex is -1 # Normal navigation.
|
||||
@history = @history.slice 0, @currentIndex + 1 # Clear history.
|
||||
if @history[@currentIndex] isnt url
|
||||
@currentIndex++
|
||||
@history.push url
|
||||
else # Go to index.
|
||||
@currentIndex = @pendingIndex
|
||||
@pendingIndex = -1
|
||||
@history[@currentIndex] = url
|
||||
|
||||
loadUrl: (url, options={}) ->
|
||||
@pendingIndex = -1
|
||||
@webContents._loadUrl url, options
|
||||
|
||||
getUrl: ->
|
||||
if @currentIndex is -1
|
||||
''
|
||||
else
|
||||
@history[@currentIndex]
|
||||
|
||||
stop: ->
|
||||
@pendingIndex = -1
|
||||
@webContents._stop()
|
||||
|
||||
reload: ->
|
||||
@pendingIndex = @currentIndex
|
||||
@webContents._loadUrl @getUrl(), {}
|
||||
|
||||
reloadIgnoringCache: ->
|
||||
@webContents._reloadIgnoringCache() # Rely on WebContents to clear cache.
|
||||
@reload()
|
||||
|
||||
canGoBack: ->
|
||||
@getActiveIndex() > 0
|
||||
|
||||
canGoForward: ->
|
||||
@getActiveIndex() < @history.length - 1
|
||||
|
||||
canGoToIndex: (index) ->
|
||||
index >=0 and index < @history.length
|
||||
|
||||
canGoToOffset: (offset) ->
|
||||
@canGoToIndex @currentIndex + offset
|
||||
|
||||
goBack: ->
|
||||
return unless @canGoBack()
|
||||
@pendingIndex = @getActiveIndex() - 1
|
||||
@webContents._loadUrl @history[@pendingIndex], {}
|
||||
|
||||
goForward: ->
|
||||
return unless @canGoForward()
|
||||
@pendingIndex = @getActiveIndex() + 1
|
||||
@webContents._loadUrl @history[@pendingIndex], {}
|
||||
|
||||
goToIndex: (index) ->
|
||||
return unless @canGoToIndex index
|
||||
@pendingIndex = index
|
||||
@webContents._loadUrl @history[@pendingIndex], {}
|
||||
|
||||
goToOffset: (offset) ->
|
||||
return unless @canGoToOffset offset
|
||||
@goToIndex @currentIndex + offset
|
||||
|
||||
getActiveIndex: ->
|
||||
if @pendingIndex is -1 then @currentIndex else @pendingIndex
|
||||
|
||||
module.exports = NavigationController
|
||||
@@ -1,4 +1,5 @@
|
||||
EventEmitter = require('events').EventEmitter
|
||||
NavigationController = require './navigation-controller'
|
||||
binding = process.atomBinding 'web_contents'
|
||||
ipc = require 'ipc'
|
||||
|
||||
@@ -26,10 +27,12 @@ module.exports.wrap = (webContents) ->
|
||||
webContents.getId = -> "#{@getProcessId()}-#{@getRoutingId()}"
|
||||
webContents.equal = (other) -> @getId() is other.getId()
|
||||
|
||||
# Provide a default parameter for |urlOptions|.
|
||||
webContents.loadUrl = (url, urlOptions={}) -> @_loadUrl url, urlOptions
|
||||
webContents.reload = (urlOptions={}) -> @_reload urlOptions
|
||||
webContents.reloadIgnoringCache = (urlOptions={}) -> @_reloadIgnoringCache urlOptions
|
||||
# The navigation controller.
|
||||
controller = new NavigationController(webContents)
|
||||
webContents.controller = controller
|
||||
for name, method of NavigationController.prototype when method instanceof Function
|
||||
do (name, method) ->
|
||||
webContents[name] = -> method.apply controller, arguments
|
||||
|
||||
# Translate |disposition| to string for 'new-window' event.
|
||||
webContents.on '-new-window', (args..., disposition) ->
|
||||
|
||||
@@ -49,7 +49,7 @@ struct FindByProcessId {
|
||||
} // namespace
|
||||
|
||||
AtomBrowserClient::AtomBrowserClient()
|
||||
: dying_render_process_(NULL) {
|
||||
: dying_render_process_(nullptr) {
|
||||
}
|
||||
|
||||
AtomBrowserClient::~AtomBrowserClient() {
|
||||
@@ -119,27 +119,31 @@ void AtomBrowserClient::OverrideWebkitPrefs(
|
||||
window->OverrideWebkitPrefs(prefs);
|
||||
}
|
||||
|
||||
bool AtomBrowserClient::ShouldSwapBrowsingInstancesForNavigation(
|
||||
content::SiteInstance* site_instance,
|
||||
const GURL& current_url,
|
||||
const GURL& new_url) {
|
||||
if (site_instance->HasProcess())
|
||||
dying_render_process_ = site_instance->GetProcess();
|
||||
|
||||
// Restart renderer process for all navigations, this relies on a patch to
|
||||
// Chromium: http://git.io/_PaNyg.
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string AtomBrowserClient::GetApplicationLocale() {
|
||||
return l10n_util::GetApplicationLocale("");
|
||||
}
|
||||
|
||||
void AtomBrowserClient::OverrideSiteInstanceForNavigation(
|
||||
content::BrowserContext* browser_context,
|
||||
content::SiteInstance* current_instance,
|
||||
const GURL& url,
|
||||
content::SiteInstance** new_instance) {
|
||||
if (current_instance->HasProcess())
|
||||
dying_render_process_ = current_instance->GetProcess();
|
||||
|
||||
// Restart renderer process for all navigations.
|
||||
*new_instance = content::SiteInstance::CreateForURL(browser_context, url);
|
||||
}
|
||||
|
||||
void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
||||
base::CommandLine* command_line,
|
||||
int child_process_id) {
|
||||
std::string process_type = command_line->GetSwitchValueASCII("type");
|
||||
if (process_type != "renderer")
|
||||
return;
|
||||
|
||||
WindowList* list = WindowList::GetInstance();
|
||||
NativeWindow* window = NULL;
|
||||
NativeWindow* window = nullptr;
|
||||
|
||||
// Find the owner of this child process.
|
||||
WindowList::const_iterator iter = std::find_if(
|
||||
@@ -150,15 +154,25 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
||||
// If the render process is a newly started one, which means the window still
|
||||
// uses the old going-to-be-swapped render process, then we try to find the
|
||||
// window from the swapped render process.
|
||||
if (window == NULL && dying_render_process_ != NULL) {
|
||||
child_process_id = dying_render_process_->GetID();
|
||||
if (!window && dying_render_process_) {
|
||||
int dying_process_id = dying_render_process_->GetID();
|
||||
WindowList::const_iterator iter = std::find_if(
|
||||
list->begin(), list->end(), FindByProcessId(child_process_id));
|
||||
if (iter != list->end())
|
||||
list->begin(), list->end(), FindByProcessId(dying_process_id));
|
||||
if (iter != list->end()) {
|
||||
window = *iter;
|
||||
child_process_id = dying_process_id;
|
||||
} else {
|
||||
// It appears that the dying process doesn't belong to a BrowserWindow,
|
||||
// then it might be a guest process, if it is we should update its
|
||||
// process ID in the WebViewManager.
|
||||
auto child_process = content::RenderProcessHost::FromID(child_process_id);
|
||||
// Update the process ID in webview guests.
|
||||
WebViewManager::UpdateGuestProcessID(dying_render_process_,
|
||||
child_process);
|
||||
}
|
||||
}
|
||||
|
||||
if (window != NULL) {
|
||||
if (window) {
|
||||
window->AppendExtraCommandLineSwitches(command_line, child_process_id);
|
||||
} else {
|
||||
// Append commnad line arguments for guest web view.
|
||||
@@ -180,7 +194,7 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
||||
}
|
||||
}
|
||||
|
||||
dying_render_process_ = NULL;
|
||||
dying_render_process_ = nullptr;
|
||||
}
|
||||
|
||||
brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts(
|
||||
|
||||
@@ -27,11 +27,12 @@ class AtomBrowserClient : public brightray::BrowserClient {
|
||||
void ResourceDispatcherHostCreated() override;
|
||||
void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,
|
||||
content::WebPreferences* prefs) override;
|
||||
bool ShouldSwapBrowsingInstancesForNavigation(
|
||||
content::SiteInstance* site_instance,
|
||||
const GURL& current_url,
|
||||
const GURL& new_url) override;
|
||||
std::string GetApplicationLocale() override;
|
||||
void OverrideSiteInstanceForNavigation(
|
||||
content::BrowserContext* browser_context,
|
||||
content::SiteInstance* current_instance,
|
||||
const GURL& dest_url,
|
||||
content::SiteInstance** new_instance);
|
||||
void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
|
||||
int child_process_id) override;
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ void AtomJavaScriptDialogManager::RunBeforeUnloadDialog(
|
||||
const base::string16& message_text,
|
||||
bool is_reload,
|
||||
const DialogClosedCallback& callback) {
|
||||
|
||||
bool prevent_reload = message_text.empty() ||
|
||||
message_text == base::ASCIIToUTF16("false");
|
||||
callback.Run(!prevent_reload, message_text);
|
||||
|
||||
@@ -112,11 +112,12 @@ app.on('ready', function() {
|
||||
click: function() { mainWindow.restart(); }
|
||||
},
|
||||
{
|
||||
label: 'Enter Fullscreen',
|
||||
click: function() { mainWindow.setFullScreen(true); }
|
||||
label: 'Toggle Full Screen',
|
||||
accelerator: 'Ctrl+Command+F',
|
||||
click: function() { mainWindow.setFullScreen(!mainWindow.isFullScreen()); }
|
||||
},
|
||||
{
|
||||
label: 'Toggle DevTools',
|
||||
label: 'Toggle Developer Tools',
|
||||
accelerator: 'Alt+Command+I',
|
||||
click: function() { mainWindow.toggleDevTools(); }
|
||||
},
|
||||
@@ -144,6 +145,27 @@ app.on('ready', function() {
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Learn More',
|
||||
click: function() { require('shell').openExternal('http://electron.atom.io') }
|
||||
},
|
||||
{
|
||||
label: 'Documentation',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
|
||||
},
|
||||
{
|
||||
label: 'Community Discussions',
|
||||
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
|
||||
},
|
||||
{
|
||||
label: 'Search Issues',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
menu = Menu.buildFromTemplate(template);
|
||||
@@ -173,16 +195,38 @@ app.on('ready', function() {
|
||||
click: function() { mainWindow.restart(); }
|
||||
},
|
||||
{
|
||||
label: '&Enter Fullscreen',
|
||||
click: function() { mainWindow.setFullScreen(true); }
|
||||
label: 'Toggle &Full Screen',
|
||||
accelerator: 'F11',
|
||||
click: function() { mainWindow.setFullScreen(!mainWindow.isFullScreen()); }
|
||||
},
|
||||
{
|
||||
label: '&Toggle DevTools',
|
||||
label: 'Toggle &Developer Tools',
|
||||
accelerator: 'Alt+Ctrl+I',
|
||||
click: function() { mainWindow.toggleDevTools(); }
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Learn More',
|
||||
click: function() { require('shell').openExternal('http://electron.atom.io') }
|
||||
},
|
||||
{
|
||||
label: 'Documentation',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
|
||||
},
|
||||
{
|
||||
label: 'Community Discussions',
|
||||
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
|
||||
},
|
||||
{
|
||||
label: 'Search Issues',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
menu = Menu.buildFromTemplate(template);
|
||||
|
||||
@@ -11,11 +11,14 @@ app.on('window-all-closed', function() {
|
||||
|
||||
// Parse command line options.
|
||||
var argv = process.argv.slice(1);
|
||||
var option = { file: null, version: null, webdriver: null };
|
||||
var option = { file: null, help: null, version: null, webdriver: null };
|
||||
for (var i in argv) {
|
||||
if (argv[i] == '--version' || argv[i] == '-v') {
|
||||
option.version = true;
|
||||
break;
|
||||
} else if (argv[i] == '--help' || argv[i] == '-h') {
|
||||
option.help = true;
|
||||
break;
|
||||
} else if (argv[i] == '--test-type=webdriver') {
|
||||
option.webdriver = true;
|
||||
} else if (argv[i][0] == '-') {
|
||||
@@ -58,7 +61,17 @@ if (option.file && !option.webdriver) {
|
||||
}
|
||||
}
|
||||
} else if (option.version) {
|
||||
console.log('v' + process.versions['electron']);
|
||||
console.log('v' + process.versions.electron);
|
||||
process.exit(0);
|
||||
} else if (option.help) {
|
||||
var helpMessage = "Electron v" + process.versions.electron + " - Cross Platform Desktop Application Shell\n\n";
|
||||
helpMessage += "Usage: electron [options] [path]\n\n";
|
||||
helpMessage += "A path to an Electron application may be specified. The path must be to \n";
|
||||
helpMessage += "an index.js file or to a folder containing a package.json or index.js file.\n\n";
|
||||
helpMessage += "Options:\n";
|
||||
helpMessage += " -h, --help Print this usage message.\n";
|
||||
helpMessage += " -v, --version Print the version.";
|
||||
console.log(helpMessage);
|
||||
process.exit(0);
|
||||
} else {
|
||||
require('./default_app.js');
|
||||
|
||||
@@ -10,12 +10,14 @@ supportedWebViewEvents = [
|
||||
'did-stop-loading'
|
||||
'did-get-response-details'
|
||||
'did-get-redirect-request'
|
||||
'dom-ready'
|
||||
'console-message'
|
||||
'new-window'
|
||||
'close'
|
||||
'crashed'
|
||||
'destroyed'
|
||||
'page-title-set'
|
||||
'page-favicon-updated'
|
||||
]
|
||||
|
||||
nextInstanceId = 0
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
module = require 'module'
|
||||
util = require 'util'
|
||||
Module = require 'module'
|
||||
|
||||
# We modified the original process.argv to let node.js load the atom.js,
|
||||
# we need to restore it here.
|
||||
process.argv.splice 1, 1
|
||||
|
||||
# Add browser/api/lib to require's search paths,
|
||||
# which contains javascript part of Atom's built-in libraries.
|
||||
globalPaths = module.globalPaths
|
||||
# Add browser/api/lib to module search paths, which contains javascript part of
|
||||
# Electron's built-in libraries.
|
||||
globalPaths = Module.globalPaths
|
||||
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
|
||||
|
||||
# Import common settings.
|
||||
@@ -89,4 +89,4 @@ app.setPath 'userCache', path.join(app.getPath('cache'), app.getName())
|
||||
require './chrome-extension'
|
||||
|
||||
# Finally load app's main.js and transfer control to C++.
|
||||
module._load path.join(packagePath, packageJson.main), module, true
|
||||
Module._load path.join(packagePath, packageJson.main), Module, true
|
||||
|
||||
@@ -18,6 +18,4 @@
|
||||
// CrAppControlProtocol:
|
||||
- (void)setHandlingSendEvent:(BOOL)handlingSendEvent;
|
||||
|
||||
- (IBAction)closeAllWindows:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
@@ -36,10 +36,6 @@
|
||||
andEventID:kAEGetURL];
|
||||
}
|
||||
|
||||
- (IBAction)closeAllWindows:(id)sender {
|
||||
atom::Browser::Get()->Quit();
|
||||
}
|
||||
|
||||
- (void)handleURLEvent:(NSAppleEventDescriptor*)event
|
||||
withReplyEvent:(NSAppleEventDescriptor*)replyEvent {
|
||||
NSString* url = [
|
||||
|
||||
@@ -565,6 +565,7 @@ content::WebContents* NativeWindow::OpenURLFromTab(
|
||||
load_url_params.is_renderer_initiated = params.is_renderer_initiated;
|
||||
load_url_params.transferred_global_request_id =
|
||||
params.transferred_global_request_id;
|
||||
load_url_params.should_clear_history_list = true;
|
||||
|
||||
source->GetController().LoadURLWithParams(load_url_params);
|
||||
return source;
|
||||
@@ -685,6 +686,20 @@ void NativeWindow::RendererResponsive(content::WebContents* source) {
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererResponsive());
|
||||
}
|
||||
|
||||
void NativeWindow::EnterFullscreenModeForTab(content::WebContents* source,
|
||||
const GURL& origin) {
|
||||
SetFullScreen(true);
|
||||
}
|
||||
|
||||
void NativeWindow::ExitFullscreenModeForTab(content::WebContents* source) {
|
||||
SetFullScreen(false);
|
||||
}
|
||||
|
||||
bool NativeWindow::IsFullscreenForTabOrPending(
|
||||
const content::WebContents* source) const {
|
||||
return IsFullscreen();
|
||||
}
|
||||
|
||||
void NativeWindow::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
|
||||
// Do nothing, we override this method just to avoid compilation error since
|
||||
// there are two virtual functions named BeforeUnloadFired.
|
||||
|
||||
@@ -112,7 +112,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
virtual void Restore() = 0;
|
||||
virtual bool IsMinimized() = 0;
|
||||
virtual void SetFullScreen(bool fullscreen) = 0;
|
||||
virtual bool IsFullscreen() = 0;
|
||||
virtual bool IsFullscreen() const = 0;
|
||||
virtual void SetSize(const gfx::Size& size) = 0;
|
||||
virtual gfx::Size GetSize() = 0;
|
||||
virtual void SetContentSize(const gfx::Size& size) = 0;
|
||||
@@ -273,6 +273,11 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
const content::WebContents* source) const override;
|
||||
void RendererUnresponsive(content::WebContents* source) override;
|
||||
void RendererResponsive(content::WebContents* source) override;
|
||||
void EnterFullscreenModeForTab(content::WebContents* source,
|
||||
const GURL& origin) override;
|
||||
void ExitFullscreenModeForTab(content::WebContents* source) override;
|
||||
bool IsFullscreenForTabOrPending(
|
||||
const content::WebContents* source) const override;
|
||||
|
||||
// Implementations of content::WebContentsObserver.
|
||||
void RenderViewCreated(content::RenderViewHost* render_view_host) override;
|
||||
|
||||
@@ -44,7 +44,7 @@ class NativeWindowMac : public NativeWindow {
|
||||
void Restore() override;
|
||||
bool IsMinimized() override;
|
||||
void SetFullScreen(bool fullscreen) override;
|
||||
bool IsFullscreen() override;
|
||||
bool IsFullscreen() const override;
|
||||
void SetSize(const gfx::Size& size) override;
|
||||
gfx::Size GetSize() override;
|
||||
void SetContentSize(const gfx::Size& size) override;
|
||||
|
||||
@@ -54,10 +54,8 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
@interface AtomNSWindowDelegate : NSObject<NSWindowDelegate> {
|
||||
@private
|
||||
atom::NativeWindowMac* shell_;
|
||||
BOOL acceptsFirstMouse_;
|
||||
}
|
||||
- (id)initWithShell:(atom::NativeWindowMac*)shell;
|
||||
- (void)setAcceptsFirstMouse:(BOOL)accept;
|
||||
@end
|
||||
|
||||
@implementation AtomNSWindowDelegate
|
||||
@@ -65,15 +63,10 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
- (id)initWithShell:(atom::NativeWindowMac*)shell {
|
||||
if ((self = [super init])) {
|
||||
shell_ = shell;
|
||||
acceptsFirstMouse_ = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setAcceptsFirstMouse:(BOOL)accept {
|
||||
acceptsFirstMouse_ = accept;
|
||||
}
|
||||
|
||||
- (void)windowDidBecomeMain:(NSNotification*)notification {
|
||||
content::WebContents* web_contents = shell_->GetWebContents();
|
||||
if (!web_contents)
|
||||
@@ -151,10 +144,6 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstMouse:(NSEvent*)event {
|
||||
return acceptsFirstMouse_;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface AtomNSWindow : EventProcessingWindow {
|
||||
@@ -162,6 +151,8 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
atom::NativeWindowMac* shell_;
|
||||
bool enable_larger_than_screen_;
|
||||
}
|
||||
@property BOOL acceptsFirstMouse;
|
||||
@property BOOL disableAutoHideCursor;
|
||||
- (void)setShell:(atom::NativeWindowMac*)shell;
|
||||
- (void)setEnableLargerThanScreen:(bool)enable;
|
||||
@end
|
||||
@@ -184,16 +175,6 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
return [super constrainFrameRect:frameRect toScreen:screen];
|
||||
}
|
||||
|
||||
- (IBAction)reload:(id)sender {
|
||||
content::WebContents* web_contents = shell_->GetWebContents();
|
||||
content::NavigationController::LoadURLParams params(web_contents->GetURL());
|
||||
web_contents->GetController().LoadURLWithParams(params);
|
||||
}
|
||||
|
||||
- (IBAction)showDevTools:(id)sender {
|
||||
shell_->OpenDevTools(true);
|
||||
}
|
||||
|
||||
- (id)accessibilityAttributeValue:(NSString*)attribute {
|
||||
if (![attribute isEqualToString:@"AXChildren"])
|
||||
return [super accessibilityAttributeValue:attribute];
|
||||
@@ -349,6 +330,10 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
[window_ setBackgroundColor:[NSColor clearColor]];
|
||||
}
|
||||
|
||||
// Remove non-transparent corners, see http://git.io/vfonD.
|
||||
if (!has_frame_)
|
||||
[window_ setOpaque:NO];
|
||||
|
||||
// We will manage window's lifetime ourselves.
|
||||
[window_ setReleasedWhenClosed:NO];
|
||||
|
||||
@@ -361,7 +346,12 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
// Enable the NSView to accept first mouse event.
|
||||
bool acceptsFirstMouse = false;
|
||||
options.Get(switches::kAcceptFirstMouse, &acceptsFirstMouse);
|
||||
[window_delegate_ setAcceptsFirstMouse:acceptsFirstMouse];
|
||||
[window_ setAcceptsFirstMouse:acceptsFirstMouse];
|
||||
|
||||
// Disable auto-hiding cursor.
|
||||
bool disableAutoHideCursor = false;
|
||||
options.Get(switches::kDisableAutoHideCursor, &disableAutoHideCursor);
|
||||
[window_ setDisableAutoHideCursor:disableAutoHideCursor];
|
||||
|
||||
// Disable fullscreen button when 'fullscreen' is specified to false.
|
||||
bool fullscreen;
|
||||
@@ -476,7 +466,7 @@ void NativeWindowMac::SetFullScreen(bool fullscreen) {
|
||||
[window_ toggleFullScreen:nil];
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsFullscreen() {
|
||||
bool NativeWindowMac::IsFullscreen() const {
|
||||
return [window_ styleMask] & NSFullScreenWindowMask;
|
||||
}
|
||||
|
||||
|
||||
@@ -369,7 +369,7 @@ void NativeWindowViews::SetFullScreen(bool fullscreen) {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsFullscreen() {
|
||||
bool NativeWindowViews::IsFullscreen() const {
|
||||
return window_->IsFullscreen();
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ class NativeWindowViews : public NativeWindow,
|
||||
void Restore() override;
|
||||
bool IsMinimized() override;
|
||||
void SetFullScreen(bool fullscreen) override;
|
||||
bool IsFullscreen() override;
|
||||
bool IsFullscreen() const override;
|
||||
void SetSize(const gfx::Size& size) override;
|
||||
gfx::Size GetSize() override;
|
||||
void SetContentSize(const gfx::Size& size) override;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>atom.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.25.0</string>
|
||||
<string>0.25.2</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.8.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
|
||||
@@ -50,8 +50,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,25,0,0
|
||||
PRODUCTVERSION 0,25,0,0
|
||||
FILEVERSION 0,25,2,0
|
||||
PRODUCTVERSION 0,25,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -68,12 +68,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "0.25.0"
|
||||
VALUE "FileVersion", "0.25.2"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "0.25.0"
|
||||
VALUE "ProductVersion", "0.25.2"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
||||
@@ -10,18 +10,42 @@
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
WebViewManager* GetManagerFromProcess(content::RenderProcessHost* process) {
|
||||
if (!process)
|
||||
return nullptr;
|
||||
auto context = process->GetBrowserContext();
|
||||
if (!context)
|
||||
return nullptr;
|
||||
return static_cast<WebViewManager*>(context->GetGuestManager());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
bool WebViewManager::GetInfoForProcess(content::RenderProcessHost* process,
|
||||
WebViewInfo* info) {
|
||||
if (!process)
|
||||
return false;
|
||||
auto context = process->GetBrowserContext();
|
||||
if (!context)
|
||||
return false;
|
||||
auto manager = context->GetGuestManager();
|
||||
auto manager = GetManagerFromProcess(process);
|
||||
if (!manager)
|
||||
return false;
|
||||
return static_cast<WebViewManager*>(manager)->GetInfo(process->GetID(), info);
|
||||
return manager->GetInfo(process->GetID(), info);
|
||||
}
|
||||
|
||||
// static
|
||||
void WebViewManager::UpdateGuestProcessID(
|
||||
content::RenderProcessHost* old_process,
|
||||
content::RenderProcessHost* new_process) {
|
||||
auto manager = GetManagerFromProcess(old_process);
|
||||
if (manager) {
|
||||
base::AutoLock auto_lock(manager->lock_);
|
||||
int old_id = old_process->GetID();
|
||||
int new_id = new_process->GetID();
|
||||
if (!ContainsKey(manager->webview_info_map_, old_id))
|
||||
return;
|
||||
manager->webview_info_map_[new_id] = manager->webview_info_map_[old_id];
|
||||
manager->webview_info_map_.erase(old_id);
|
||||
}
|
||||
}
|
||||
|
||||
WebViewManager::WebViewManager(content::BrowserContext* context) {
|
||||
|
||||
@@ -34,6 +34,10 @@ class WebViewManager : public content::BrowserPluginGuestManager {
|
||||
static bool GetInfoForProcess(content::RenderProcessHost* process,
|
||||
WebViewInfo* info);
|
||||
|
||||
// Updates the guest process ID.
|
||||
static void UpdateGuestProcessID(content::RenderProcessHost* old_process,
|
||||
content::RenderProcessHost* new_process);
|
||||
|
||||
explicit WebViewManager(content::BrowserContext* context);
|
||||
virtual ~WebViewManager();
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#define ATOM_MAJOR_VERSION 0
|
||||
#define ATOM_MINOR_VERSION 25
|
||||
#define ATOM_PATCH_VERSION 0
|
||||
#define ATOM_PATCH_VERSION 2
|
||||
|
||||
#define ATOM_VERSION_IS_RELEASE 1
|
||||
|
||||
|
||||
@@ -53,11 +53,20 @@ asarStatsToFsStats = (stats) ->
|
||||
}
|
||||
|
||||
# Create a ENOENT error.
|
||||
createNotFoundError = (asarPath, filePath) ->
|
||||
notFoundError = (asarPath, filePath, callback) ->
|
||||
error = new Error("ENOENT, #{filePath} not found in #{asarPath}")
|
||||
error.code = "ENOENT"
|
||||
error.errno = -2
|
||||
error
|
||||
unless typeof callback is 'function'
|
||||
throw error
|
||||
process.nextTick -> callback error
|
||||
|
||||
# Create invalid archive error.
|
||||
invalidArchiveError = (asarPath, callback) ->
|
||||
error = new Error("Invalid package #{asarPath}")
|
||||
unless typeof callback is 'function'
|
||||
throw error
|
||||
process.nextTick -> callback error
|
||||
|
||||
# Override APIs that rely on passing file path instead of content to C++.
|
||||
overrideAPISync = (module, name, arg = 0) ->
|
||||
@@ -68,10 +77,10 @@ overrideAPISync = (module, name, arg = 0) ->
|
||||
return old.apply this, arguments unless isAsar
|
||||
|
||||
archive = getOrCreateArchive asarPath
|
||||
throw new Error("Invalid package #{asarPath}") unless archive
|
||||
invalidArchiveError asarPath unless archive
|
||||
|
||||
newPath = archive.copyFileOut filePath
|
||||
throw createNotFoundError(asarPath, filePath) unless newPath
|
||||
notFoundError asarPath, filePath unless newPath
|
||||
|
||||
arguments[arg] = newPath
|
||||
old.apply this, arguments
|
||||
@@ -87,10 +96,10 @@ overrideAPI = (module, name, arg = 0) ->
|
||||
return overrideAPISync module, name, arg unless typeof callback is 'function'
|
||||
|
||||
archive = getOrCreateArchive asarPath
|
||||
return callback new Error("Invalid package #{asarPath}") unless archive
|
||||
return invalidArchiveError asarPath, callback unless archive
|
||||
|
||||
newPath = archive.copyFileOut filePath
|
||||
return callback createNotFoundError(asarPath, filePath) unless newPath
|
||||
return notFoundError asarPath, filePath, callback unless newPath
|
||||
|
||||
arguments[arg] = newPath
|
||||
old.apply this, arguments
|
||||
@@ -103,10 +112,10 @@ exports.wrapFsWithAsar = (fs) ->
|
||||
return lstatSync p unless isAsar
|
||||
|
||||
archive = getOrCreateArchive asarPath
|
||||
throw new Error("Invalid package #{asarPath}") unless archive
|
||||
invalidArchiveError asarPath unless archive
|
||||
|
||||
stats = archive.stat filePath
|
||||
throw createNotFoundError(asarPath, filePath) unless stats
|
||||
notFoundError asarPath, filePath unless stats
|
||||
|
||||
asarStatsToFsStats stats
|
||||
|
||||
@@ -116,10 +125,10 @@ exports.wrapFsWithAsar = (fs) ->
|
||||
return lstat p, callback unless isAsar
|
||||
|
||||
archive = getOrCreateArchive asarPath
|
||||
return callback new Error("Invalid package #{asarPath}") unless archive
|
||||
return invalidArchiveError asarPath, callback unless archive
|
||||
|
||||
stats = getOrCreateArchive(asarPath).stat filePath
|
||||
return callback createNotFoundError(asarPath, filePath) unless stats
|
||||
return notFoundError asarPath, filePath, callback unless stats
|
||||
|
||||
process.nextTick -> callback null, asarStatsToFsStats stats
|
||||
|
||||
@@ -156,10 +165,10 @@ exports.wrapFsWithAsar = (fs) ->
|
||||
return realpathSync.apply this, arguments unless isAsar
|
||||
|
||||
archive = getOrCreateArchive asarPath
|
||||
throw new Error("Invalid package #{asarPath}") unless archive
|
||||
invalidArchiveError asarPath unless archive
|
||||
|
||||
real = archive.realpath filePath
|
||||
throw createNotFoundError(asarPath, filePath) if real is false
|
||||
notFoundError asarPath, filePath if real is false
|
||||
|
||||
path.join realpathSync(asarPath), real
|
||||
|
||||
@@ -173,10 +182,11 @@ exports.wrapFsWithAsar = (fs) ->
|
||||
cache = undefined
|
||||
|
||||
archive = getOrCreateArchive asarPath
|
||||
return callback new Error("Invalid package #{asarPath}") unless archive
|
||||
return invalidArchiveError asarPath, callback unless archive
|
||||
|
||||
real = archive.realpath filePath
|
||||
return callback createNotFoundError(asarPath, filePath) if real is false
|
||||
if real is false
|
||||
return notFoundError asarPath, filePath, callback
|
||||
|
||||
realpath asarPath, (err, p) ->
|
||||
return callback err if err
|
||||
@@ -188,7 +198,7 @@ exports.wrapFsWithAsar = (fs) ->
|
||||
return exists p, callback unless isAsar
|
||||
|
||||
archive = getOrCreateArchive asarPath
|
||||
return callback new Error("Invalid package #{asarPath}") unless archive
|
||||
return invalidArchiveError asarPath, callback unless archive
|
||||
|
||||
process.nextTick -> callback archive.stat(filePath) isnt false
|
||||
|
||||
@@ -213,11 +223,13 @@ exports.wrapFsWithAsar = (fs) ->
|
||||
options = undefined
|
||||
|
||||
archive = getOrCreateArchive asarPath
|
||||
return callback new Error("Invalid package #{asarPath}") unless archive
|
||||
return invalidArchiveError asarPath, callback unless archive
|
||||
|
||||
info = archive.getFileInfo filePath
|
||||
return callback createNotFoundError(asarPath, filePath) unless info
|
||||
return callback null, new Buffer(0) if info.size is 0
|
||||
return notFoundError asarPath, filePath, callback unless info
|
||||
|
||||
if info.size is 0
|
||||
return process.nextTick -> callback null, new Buffer(0)
|
||||
|
||||
if info.unpacked
|
||||
realPath = archive.copyFileOut filePath
|
||||
@@ -247,10 +259,10 @@ exports.wrapFsWithAsar = (fs) ->
|
||||
return readFileSync.apply this, arguments unless isAsar
|
||||
|
||||
archive = getOrCreateArchive asarPath
|
||||
throw new Error("Invalid package #{asarPath}") unless archive
|
||||
invalidArchiveError asarPath unless archive
|
||||
|
||||
info = archive.getFileInfo filePath
|
||||
throw createNotFoundError(asarPath, filePath) unless info
|
||||
notFoundError asarPath, filePath unless info
|
||||
return new Buffer(0) if info.size is 0
|
||||
|
||||
if info.unpacked
|
||||
@@ -283,10 +295,10 @@ exports.wrapFsWithAsar = (fs) ->
|
||||
return readdir.apply this, arguments unless isAsar
|
||||
|
||||
archive = getOrCreateArchive asarPath
|
||||
return callback new Error("Invalid package #{asarPath}") unless archive
|
||||
return invalidArchiveError asarPath, callback unless archive
|
||||
|
||||
files = archive.readdir filePath
|
||||
return callback createNotFoundError(asarPath, filePath) unless files
|
||||
return notFoundError asarPath, filePath, callback unless files
|
||||
|
||||
process.nextTick -> callback null, files
|
||||
|
||||
@@ -296,10 +308,10 @@ exports.wrapFsWithAsar = (fs) ->
|
||||
return readdirSync.apply this, arguments unless isAsar
|
||||
|
||||
archive = getOrCreateArchive asarPath
|
||||
throw new Error("Invalid package #{asarPath}") unless archive
|
||||
invalidArchiveError asarPath unless archive
|
||||
|
||||
files = archive.readdir filePath
|
||||
throw createNotFoundError(asarPath, filePath) unless files
|
||||
notFoundError asarPath, filePath unless files
|
||||
|
||||
files
|
||||
|
||||
|
||||
@@ -10,8 +10,20 @@ process.atomBinding = (name) ->
|
||||
catch e
|
||||
process.binding "atom_common_#{name}" if /No such module/.test e.message
|
||||
|
||||
# Add common/api/lib to module search paths.
|
||||
# Global module search paths.
|
||||
globalPaths = Module.globalPaths
|
||||
|
||||
# Don't lookup modules in user-defined search paths, see http://git.io/vf8sF.
|
||||
homeDir =
|
||||
if process.platform is 'win32'
|
||||
process.env.USERPROFILE
|
||||
else
|
||||
process.env.HOME
|
||||
if homeDir # Node only add user-defined search paths when $HOME is defined.
|
||||
userModulePath = path.resolve homeDir, '.node_modules'
|
||||
globalPaths.splice globalPaths.indexOf(userModulePath), 2
|
||||
|
||||
# Add common/api/lib to module search paths.
|
||||
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
|
||||
|
||||
# setImmediate and process.nextTick makes use of uv_check and uv_prepare to
|
||||
|
||||
@@ -75,6 +75,9 @@ const char kTransparent[] = "transparent";
|
||||
// Window type hint.
|
||||
const char kType[] = "type";
|
||||
|
||||
// Disable auto-hiding cursor.
|
||||
const char kDisableAutoHideCursor[] = "disable-auto-hide-cursor";
|
||||
|
||||
// Web runtime features.
|
||||
const char kExperimentalFeatures[] = "experimental-features";
|
||||
const char kExperimentalCanvasFeatures[] = "experimental-canvas-features";
|
||||
|
||||
@@ -41,6 +41,7 @@ extern const char kGuestInstanceID[];
|
||||
extern const char kPreloadScript[];
|
||||
extern const char kTransparent[];
|
||||
extern const char kType[];
|
||||
extern const char kDisableAutoHideCursor[];
|
||||
|
||||
extern const char kExperimentalFeatures[];
|
||||
extern const char kExperimentalCanvasFeatures[];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,12 +12,14 @@ WEB_VIEW_EVENTS =
|
||||
'did-get-response-details': ['status', 'newUrl', 'originalUrl',
|
||||
'httpResponseCode', 'requestMethod', 'referrer']
|
||||
'did-get-redirect-request': ['oldUrl', 'newUrl', 'isMainFrame']
|
||||
'dom-ready': []
|
||||
'console-message': ['level', 'message', 'line', 'sourceId']
|
||||
'new-window': ['url', 'frameName', 'disposition']
|
||||
'close': []
|
||||
'crashed': []
|
||||
'destroyed': []
|
||||
'page-title-set': ['title', 'explicitSet']
|
||||
'page-favicon-updated': ['favicons']
|
||||
|
||||
dispatchEvent = (webView, event, args...) ->
|
||||
throw new Error("Unkown event #{event}") unless WEB_VIEW_EVENTS[event]?
|
||||
|
||||
@@ -138,10 +138,7 @@ class SrcAttribute extends WebViewAttribute
|
||||
setupMutationObserver: ->
|
||||
@observer = new MutationObserver (mutations) =>
|
||||
for mutation in mutations
|
||||
oldValue = mutation.oldValue
|
||||
newValue = @getValue()
|
||||
return if oldValue isnt newValue
|
||||
@handleMutation oldValue, newValue
|
||||
@handleMutation mutation.oldValue, @getValue()
|
||||
params =
|
||||
attributes: true,
|
||||
attributeOldValue: true,
|
||||
|
||||
@@ -255,6 +255,7 @@ registerWebViewElement = ->
|
||||
"openDevTools"
|
||||
"closeDevTools"
|
||||
"isDevToolsOpened"
|
||||
"inspectElement"
|
||||
"undo"
|
||||
"redo"
|
||||
"cut"
|
||||
@@ -276,6 +277,13 @@ registerWebViewElement = ->
|
||||
remote.getGuestWebContents(internal.guestInstanceId)[m] args...
|
||||
proto[m] = createHandler m for m in methods
|
||||
|
||||
# Return dataUrl instead of nativeImage.
|
||||
proto.getFavicon = (args...) ->
|
||||
internal = v8Util.getHiddenValue this, 'internal'
|
||||
return unless internal
|
||||
favicon = remote.getGuestWebContents(internal.guestInstanceId)['getFavicon'] args...
|
||||
favicon.toDataUrl()
|
||||
|
||||
window.WebView = webFrame.registerEmbedderCustomElement 'webview',
|
||||
prototype: proto
|
||||
|
||||
|
||||
@@ -54,9 +54,10 @@ You can also create a window without chrome by using
|
||||
* `frame` Boolean - Specify `false` to create a
|
||||
[Frameless Window](frameless-window.md)
|
||||
* `node-integration` Boolean - Whether node integration is enabled, default
|
||||
is `true`
|
||||
is `true`
|
||||
* `accept-first-mouse` Boolean - Whether the web view accepts a single
|
||||
mouse-down event that simultaneously activates the window
|
||||
mouse-down event that simultaneously activates the window
|
||||
* `disable-auto-hide-cursor` Boolean - Do not hide cursor when typing
|
||||
* `auto-hide-menu-bar` Boolean - Auto hide the menu bar unless the `Alt`
|
||||
key is pressed.
|
||||
* `enable-larger-than-screen` Boolean - Enable the window to be resized larger
|
||||
@@ -662,6 +663,19 @@ Emitted when details regarding a requested resource is available.
|
||||
|
||||
Emitted when a redirect was received while requesting a resource.
|
||||
|
||||
### Event: 'dom-ready'
|
||||
|
||||
* `event` Event
|
||||
|
||||
Emitted when document in the given frame is loaded.
|
||||
|
||||
### Event: 'page-favicon-updated'
|
||||
|
||||
* `event` Event
|
||||
* `favicons` Array - Array of Urls
|
||||
|
||||
Emitted when page receives favicon urls.
|
||||
|
||||
### Event: 'new-window'
|
||||
|
||||
* `event` Event
|
||||
@@ -713,6 +727,10 @@ Returns URL of current web page.
|
||||
|
||||
Returns the title of web page.
|
||||
|
||||
### WebContents.getFavicon()
|
||||
|
||||
Returns the favicon of web page as [NativeImage](native-image.md).
|
||||
|
||||
### WebContents.isLoading()
|
||||
|
||||
Returns whether web page is still loading resources.
|
||||
@@ -834,6 +852,21 @@ Executes editing command `replace` in page.
|
||||
|
||||
Executes editing command `replaceMisspelling` in page.
|
||||
|
||||
### WebContents.hasServiceWorker(callback)
|
||||
|
||||
* `callback` Function
|
||||
|
||||
Checks if any serviceworker is registered and returns boolean as
|
||||
response to `callback`.
|
||||
|
||||
### WebContents.unregisterServiceWorker(callback)
|
||||
|
||||
* `callback` Function
|
||||
|
||||
Unregisters any serviceworker if present and returns boolean as
|
||||
response to `callback` when the JS promise is fullfilled or false
|
||||
when the JS promise is rejected.
|
||||
|
||||
### WebContents.send(channel[, args...])
|
||||
|
||||
* `channel` String
|
||||
|
||||
@@ -130,6 +130,10 @@ Returns URL of guest page.
|
||||
|
||||
Returns the title of guest page.
|
||||
|
||||
### `<webview>`.getFavicon()
|
||||
|
||||
Returns the favicon of guest page as dataUrl.
|
||||
|
||||
### `<webview>`.isLoading()
|
||||
|
||||
Returns whether guest page is still loading resources.
|
||||
@@ -219,6 +223,13 @@ Closes the devtools window of guest page.
|
||||
|
||||
Returns whether guest page has a devtools window attached.
|
||||
|
||||
### `<webview>`.inspectElement(x, y)
|
||||
|
||||
* `x` Integer
|
||||
* `y` Integer
|
||||
|
||||
Starts inspecting element at position (`x`, `y`) of guest page.
|
||||
|
||||
### `<webview>`.undo()
|
||||
|
||||
Executes editing command `undo` in page.
|
||||
@@ -322,6 +333,10 @@ Fired when details regarding a requested resource is available.
|
||||
|
||||
Fired when a redirect was received while requesting a resource.
|
||||
|
||||
### dom-ready
|
||||
|
||||
Fired when document in the given frame is loaded.
|
||||
|
||||
### page-title-set
|
||||
|
||||
* `title` String
|
||||
@@ -330,6 +345,12 @@ Fired when a redirect was received while requesting a resource.
|
||||
Fired when page title is set during navigation. `explicitSet` is false when title is synthesised from file
|
||||
url.
|
||||
|
||||
### page-favicon-updated
|
||||
|
||||
* `favicons` Array - Array of Urls
|
||||
|
||||
Fired when page receives favicon urls.
|
||||
|
||||
### console-message
|
||||
|
||||
* `level` Integer
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
__Note: Electron was previously named Atom Shell.__
|
||||
|
||||
Like NW.js, Electron provides a platform to write desktop applications
|
||||
with JavaScript and HTML, and has Node integration to grant access to low level
|
||||
with JavaScript and HTML and has Node integration to grant access to low level
|
||||
system in web pages.
|
||||
|
||||
But there are also fundamental differences between the two projects that make
|
||||
@@ -11,39 +11,38 @@ Electron a completely separate product from NW.js:
|
||||
|
||||
__1. Entry of application__
|
||||
|
||||
In NW.js, the main entry of an application is a web page, you specify a
|
||||
main page in the `package.json` and it would be opened in a browser window as
|
||||
In NW.js, the main entry of an application is a web page. You specify a
|
||||
main page in the `package.json` and it is opened in a browser window as
|
||||
the application's main window.
|
||||
|
||||
While in Electron, the entry point is a JavaScript script, instead of
|
||||
providing a URL directly, you need to manually create a browser window and load
|
||||
html file in it with corresponding API. You also need to listen to window events
|
||||
In Electron, the entry point is a JavaScript script. Instead of
|
||||
providing a URL directly, you manually create a browser window and load
|
||||
an HTML file using the API. You also need to listen to window events
|
||||
to decide when to quit the application.
|
||||
|
||||
So Electron works more like the Node.js runtime, and APIs are more low level,
|
||||
you can also use Electron for web testing purpose like
|
||||
[phantomjs](http://phantomjs.org/).
|
||||
Electron works more like the Node.js runtime. Electron's APIs are lower level
|
||||
so you can use it for browser testing in place of [PhantomJS](http://phantomjs.org/).
|
||||
|
||||
__2. Build system__
|
||||
|
||||
In order to avoid the complexity of building the whole Chromium, Electron uses
|
||||
[libchromiumcontent](https://github.com/brightray/libchromiumcontent) to access
|
||||
Chromium's Content API, libchromiumcontent is a single, shared library that
|
||||
includes the Chromium Content module and all its dependencies. So users don't
|
||||
Chromium's Content API. libchromiumcontent is a single, shared library that
|
||||
includes the Chromium Content module and all its dependencies. Users don't
|
||||
need a powerful machine to build Electron.
|
||||
|
||||
__3. Node integration__
|
||||
|
||||
In NW.js, the Node integration in web pages requires patching Chromium to
|
||||
work, while in Electron we chose a different way to integrate libuv loop to
|
||||
each platform's message loop to avoid hacking Chromium, see the
|
||||
work, while in Electron we chose a different way to integrate libuv loop with
|
||||
each platform's message loop to avoid hacking Chromium. See the
|
||||
[`node_bindings`](../../atom/common/) code for how that was done.
|
||||
|
||||
__4. Multi-context__
|
||||
|
||||
If you are an experienced NW.js user, you should be familiar with the
|
||||
concept of Node context and web context, these concepts were invented because
|
||||
of how the NW.js was implemented.
|
||||
concept of Node context and web context. These concepts were invented because
|
||||
of how NW.js was implemented.
|
||||
|
||||
By using the [multi-context](http://strongloop.com/strongblog/whats-new-node-js-v0-12-multiple-context-execution/)
|
||||
feature of Node, Electron doesn't introduce a new JavaScript context in web
|
||||
|
||||
@@ -18,7 +18,7 @@ Guide](https://github.com/styleguide/javascript), and also following rules:
|
||||
* File names should be concatenated with `-` instead of `_`, e.g.
|
||||
`file-name.coffee` rather than `file_name.coffee`, because in
|
||||
[github/atom](https://github.com/github/atom) module names are usually in
|
||||
the `module-name` form, this rule only apply to `.coffee` files.
|
||||
the `module-name` form, this rule only applies to `.coffee` files.
|
||||
|
||||
## API Names
|
||||
|
||||
|
||||
@@ -118,8 +118,8 @@ app.setUserTasks([
|
||||
arguments: '--new-window',
|
||||
iconPath: process.execPath,
|
||||
iconIndex: 0,
|
||||
title: 'New Window'
|
||||
description: 'Create a new winodw',
|
||||
title: 'New Window',
|
||||
description: 'Create a new window',
|
||||
}
|
||||
]);
|
||||
```
|
||||
|
||||
@@ -2,41 +2,35 @@
|
||||
|
||||
## Introduction
|
||||
|
||||
Generally, Electron enables you to create desktop applications with pure
|
||||
JavaScript by providing a runtime with rich native APIs. You could see it as
|
||||
a variant of the io.js runtime which is focused on desktop applications
|
||||
instead of web servers.
|
||||
Electron enables you to create desktop applications with pure JavaScript by providing a runtime with rich native APIs. You could see it as a variant of the io.js runtime which is focused on desktop applications instead of web servers.
|
||||
|
||||
It doesn't mean Electron is a JavaScript binding to GUI libraries. Instead,
|
||||
Electron uses web pages as its GUI, so you could also see it as a minimal
|
||||
Chromium browser, controlled by JavaScript.
|
||||
|
||||
### The main process
|
||||
### Main process
|
||||
|
||||
In Electron the process that runs `package.json`'s `main` script is called
|
||||
__the main process__. The script runs in the main process can display GUI by
|
||||
In Electron, the process that runs `package.json`'s `main` script is called
|
||||
__the main process__. The script that runs in the main process, can display GUI by
|
||||
creating web pages.
|
||||
|
||||
### The renderer process
|
||||
### Renderer process
|
||||
|
||||
Since Electron uses Chromium for displaying web pages, Chromium's
|
||||
multi-processes architecture is also used. Each web page in Electron runs in
|
||||
its own process, which is called __the renderer process__.
|
||||
|
||||
In normal browsers web pages usually run in a sandboxed environment and are not
|
||||
allowed access to native resources. In Electron users have the power to use
|
||||
io.js APIs in web pages and it is therefore possible to interact with low level
|
||||
operating system features.
|
||||
allowed access to native resources. Electron users however, have the power to use
|
||||
io.js APIs in web pages allowing lower level operating system interactions.
|
||||
|
||||
### Differences between main process and renderer process
|
||||
|
||||
The main process creates web pages by creating `BrowserWindow` instances, and
|
||||
each `BrowserWindow` instance runs the web page in its own renderer process,
|
||||
when a `BrowserWindow` instance is destroyed, the corresponding renderer process
|
||||
The main process creates web pages by creating `BrowserWindow` instances. Each `BrowserWindow` instance runs the web page in its own renderer process. When a `BrowserWindow` instance is destroyed, the corresponding renderer process
|
||||
would also be terminated.
|
||||
|
||||
So the main process manages all web pages and their corresponding renderer
|
||||
processes, and each renderer process is separated from each other and only care
|
||||
The main process manages all web pages and their corresponding renderer
|
||||
processes, each renderer process is isolated and only cares
|
||||
about the web page running in it.
|
||||
|
||||
In web pages, it is not allowed to call native GUI related APIs because managing
|
||||
@@ -121,7 +115,7 @@ Finally the `index.html` is the web page you want to show:
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
We are using node.js <script>document.write(process.version)</script>
|
||||
We are using io.js <script>document.write(process.version)</script>
|
||||
and Electron <script>document.write(process.versions['electron'])</script>.
|
||||
</body>
|
||||
</html>
|
||||
@@ -149,7 +143,7 @@ $ ./electron/electron your-app/
|
||||
On OS X:
|
||||
|
||||
```bash
|
||||
$ ./Electron.app/Contents/MacOS/Atom your-app/
|
||||
$ ./Electron.app/Contents/MacOS/Electron your-app/
|
||||
```
|
||||
|
||||
`Electron.app` here is part of the Electron's release package, you can download
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
'atom/browser/api/lib/ipc.coffee',
|
||||
'atom/browser/api/lib/menu.coffee',
|
||||
'atom/browser/api/lib/menu-item.coffee',
|
||||
'atom/browser/api/lib/navigation-controller.coffee',
|
||||
'atom/browser/api/lib/power-monitor.coffee',
|
||||
'atom/browser/api/lib/protocol.coffee',
|
||||
'atom/browser/api/lib/screen.coffee',
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"devDependencies": {
|
||||
"asar": "0.2.2",
|
||||
"coffee-script": "~1.7.1",
|
||||
"coffeelint": "~1.3.0",
|
||||
"asar": "0.5.0",
|
||||
"coffee-script": "^1.9.2",
|
||||
"coffeelint": "^1.9.4",
|
||||
"request": "*",
|
||||
"runas": "^2.0.0"
|
||||
},
|
||||
|
||||
@@ -114,7 +114,6 @@ def update_info_plist(version):
|
||||
|
||||
def tag_version(version):
|
||||
execute(['git', 'commit', '-a', '-m', 'Bump v{0}'.format(version)])
|
||||
execute(['git', 'tag', 'v{0}'.format(version)])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -7,7 +7,7 @@ import sys
|
||||
|
||||
|
||||
BASE_URL = 'http://gh-contractor-zcbenz.s3.amazonaws.com/libchromiumcontent'
|
||||
LIBCHROMIUMCONTENT_COMMIT = '0529dc17ca2f950b671cf12f82260cc397b4cebb'
|
||||
LIBCHROMIUMCONTENT_COMMIT = '0fb4fbe55f5a967b960644f0fdc2013668d5a46a'
|
||||
|
||||
PLATFORM = {
|
||||
'cygwin': 'win32',
|
||||
|
||||
@@ -39,8 +39,11 @@ def parse_args():
|
||||
def get_files_list(version):
|
||||
return [
|
||||
'node-{0}.tar.gz'.format(version),
|
||||
'iojs-{0}.tar.gz'.format(version),
|
||||
'node.lib',
|
||||
'x64/node.lib',
|
||||
'win-x86/iojs.lib',
|
||||
'win-x64/iojs.lib',
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -38,10 +38,13 @@ def main():
|
||||
safe_mkdir(DIST_DIR)
|
||||
|
||||
args = parse_args()
|
||||
dist_headers_dir = os.path.join(DIST_DIR, 'node-{0}'.format(args.version))
|
||||
node_headers_dir = os.path.join(DIST_DIR, 'node-{0}'.format(args.version))
|
||||
iojs_headers_dir = os.path.join(DIST_DIR, 'iojs-{0}'.format(args.version))
|
||||
|
||||
copy_headers(dist_headers_dir)
|
||||
create_header_tarball(dist_headers_dir)
|
||||
copy_headers(node_headers_dir)
|
||||
create_header_tarball(node_headers_dir)
|
||||
copy_headers(iojs_headers_dir)
|
||||
create_header_tarball(iojs_headers_dir)
|
||||
|
||||
# Upload node's headers to S3.
|
||||
bucket, access_key, secret_key = s3_config()
|
||||
@@ -103,22 +106,32 @@ def upload_node(bucket, access_key, secret_key, version):
|
||||
with scoped_cwd(DIST_DIR):
|
||||
s3put(bucket, access_key, secret_key, DIST_DIR,
|
||||
'atom-shell/dist/{0}'.format(version), glob.glob('node-*.tar.gz'))
|
||||
s3put(bucket, access_key, secret_key, DIST_DIR,
|
||||
'atom-shell/dist/{0}'.format(version), glob.glob('iojs-*.tar.gz'))
|
||||
|
||||
if PLATFORM == 'win32':
|
||||
if get_target_arch() == 'ia32':
|
||||
node_lib = os.path.join(DIST_DIR, 'node.lib')
|
||||
iojs_lib = os.path.join(DIST_DIR, 'win-x86', 'iojs.lib')
|
||||
else:
|
||||
node_lib = os.path.join(DIST_DIR, 'x64', 'node.lib')
|
||||
safe_mkdir(os.path.dirname(node_lib))
|
||||
iojs_lib = os.path.join(DIST_DIR, 'win-x64', 'iojs.lib')
|
||||
safe_mkdir(os.path.dirname(node_lib))
|
||||
safe_mkdir(os.path.dirname(iojs_lib))
|
||||
|
||||
# Copy atom.lib to node.lib
|
||||
# Copy atom.lib to node.lib and iojs.lib.
|
||||
atom_lib = os.path.join(OUT_DIR, 'node.dll.lib')
|
||||
shutil.copy2(atom_lib, node_lib)
|
||||
shutil.copy2(atom_lib, iojs_lib)
|
||||
|
||||
# Upload the node.lib.
|
||||
s3put(bucket, access_key, secret_key, DIST_DIR,
|
||||
'atom-shell/dist/{0}'.format(version), [node_lib])
|
||||
|
||||
# Upload the iojs.lib.
|
||||
s3put(bucket, access_key, secret_key, DIST_DIR,
|
||||
'atom-shell/dist/{0}'.format(version), [iojs_lib])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
||||
@@ -2,6 +2,8 @@ assert = require 'assert'
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
remote = require 'remote'
|
||||
http = require 'http'
|
||||
url = require 'url'
|
||||
|
||||
BrowserWindow = remote.require 'browser-window'
|
||||
|
||||
@@ -216,8 +218,28 @@ describe 'browser-window module', ->
|
||||
|
||||
describe 'will-navigate event', ->
|
||||
it 'emits when user starts a navigation', (done) ->
|
||||
@timeout 10000
|
||||
w.webContents.on 'will-navigate', (event, url) ->
|
||||
event.preventDefault()
|
||||
assert.equal url, 'https://www.github.com/'
|
||||
done()
|
||||
w.loadUrl "file://#{fixtures}/pages/will-navigate.html"
|
||||
|
||||
describe 'dom-ready event', ->
|
||||
it 'emits when document is loaded', (done) ->
|
||||
server = http.createServer (req, res) ->
|
||||
action = url.parse(req.url, true).pathname
|
||||
if action == '/logo.png'
|
||||
img = fs.readFileSync(path.join(fixtures, 'assets', 'logo.png'))
|
||||
res.writeHead(200, {'Content-Type': 'image/png'})
|
||||
setTimeout ->
|
||||
res.end(img, 'binary')
|
||||
, 2000
|
||||
server.close()
|
||||
server.listen 62542, '127.0.0.1'
|
||||
remote.require('ipc').on 'dom-ready', (e, state) ->
|
||||
assert.equal state, 'interactive'
|
||||
done()
|
||||
w.webContents.on 'did-finish-load', ->
|
||||
w.close()
|
||||
w.loadUrl "file://#{fixtures}/pages/f.html"
|
||||
|
||||
@@ -66,6 +66,7 @@ describe 'ipc module', ->
|
||||
assert.equal msg, 'test'
|
||||
|
||||
it 'does not crash when reply is not sent and browser is destroyed', (done) ->
|
||||
@timeout 10000
|
||||
w = new BrowserWindow(show: false)
|
||||
remote.require('ipc').once 'send-sync-message', (event) ->
|
||||
event.returnValue = null
|
||||
|
||||
@@ -36,6 +36,14 @@ describe 'asar package', ->
|
||||
throws = -> fs.readFileSync p
|
||||
assert.throws throws, /ENOENT/
|
||||
|
||||
it 'passes ENOENT error to callback when can not find file', ->
|
||||
p = path.join fixtures, 'asar', 'a.asar', 'not-exist'
|
||||
async = false
|
||||
fs.readFile p, (e) ->
|
||||
assert async
|
||||
assert /ENOENT/.test e
|
||||
async = true
|
||||
|
||||
describe 'fs.readFile', ->
|
||||
it 'reads a normal file', (done) ->
|
||||
p = path.join fixtures, 'asar', 'a.asar', 'file1'
|
||||
|
||||
2
spec/fixtures/pages/a.html
vendored
2
spec/fixtures/pages/a.html
vendored
@@ -1,4 +1,6 @@
|
||||
<html>
|
||||
<link rel="icon" type="image/png" href="/favicon.png"/>
|
||||
<link rel="icon" type="image/png" href="http://test.com/favicon.png"/>
|
||||
<body>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
console.log('a');
|
||||
|
||||
13
spec/fixtures/pages/beforeunload-false.html
vendored
Normal file
13
spec/fixtures/pages/beforeunload-false.html
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<html>
|
||||
<body>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
window.onbeforeunload = function() {
|
||||
setTimeout(function() {
|
||||
var ipc = require('ipc');
|
||||
ipc.sendToHost('onbeforeunload');
|
||||
}, 0);
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
11
spec/fixtures/pages/f.html
vendored
Normal file
11
spec/fixtures/pages/f.html
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<html>
|
||||
<body>
|
||||
<img src='http://127.0.0.1:62542/logo.png' />
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
var remote = require('remote')
|
||||
remote.getCurrentWindow().webContents.on('dom-ready', function() {
|
||||
require('ipc').send('dom-ready', document.readyState);
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
9
spec/fixtures/pages/native-module.html
vendored
Normal file
9
spec/fixtures/pages/native-module.html
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<body>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
var path = require('path');
|
||||
console.log(typeof require(path.join(__dirname, '..', '..', 'node_modules', 'runas')));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -47,6 +47,19 @@ describe '<webview> tag', ->
|
||||
webview.src = "file://#{fixtures}/pages/d.html"
|
||||
document.body.appendChild webview
|
||||
|
||||
it 'loads native modules when navigation happens', (done) ->
|
||||
listener = (e) ->
|
||||
webview.removeEventListener 'did-finish-load', listener
|
||||
listener2 = (e) ->
|
||||
assert.equal e.message, 'function'
|
||||
done()
|
||||
webview.addEventListener 'console-message', listener2
|
||||
webview.src = "file://#{fixtures}/pages/native-module.html"
|
||||
webview.addEventListener 'did-finish-load', listener
|
||||
webview.setAttribute 'nodeintegration', 'on'
|
||||
webview.src = "file://#{fixtures}/pages/native-module.html"
|
||||
document.body.appendChild webview
|
||||
|
||||
describe 'preload attribute', ->
|
||||
it 'loads the script before other scripts in window', (done) ->
|
||||
listener = (e) ->
|
||||
@@ -151,3 +164,32 @@ describe '<webview> tag', ->
|
||||
done()
|
||||
webview.src = "file://#{fixtures}/pages/a.html"
|
||||
document.body.appendChild webview
|
||||
|
||||
describe 'page-favicon-updated event', ->
|
||||
it 'emits when favicon urls are received', (done) ->
|
||||
webview.addEventListener 'page-favicon-updated', (e) ->
|
||||
assert.equal e.favicons.length, 2
|
||||
url =
|
||||
if process.platform is 'win32'
|
||||
'file:///C:/favicon.png'
|
||||
else
|
||||
'file:///favicon.png'
|
||||
assert.equal e.favicons[0], url
|
||||
done()
|
||||
webview.src = "file://#{fixtures}/pages/a.html"
|
||||
document.body.appendChild webview
|
||||
|
||||
describe '<webview>.reload()', ->
|
||||
it 'should emit beforeunload handler', (done) ->
|
||||
webview.addEventListener 'did-finish-load', (e) ->
|
||||
webview.reload()
|
||||
listener = (e) ->
|
||||
assert.equal e.channel, 'onbeforeunload'
|
||||
webview.removeEventListener 'ipc-message', listener
|
||||
done()
|
||||
webview.addEventListener 'console-message', (e) ->
|
||||
console.log(e)
|
||||
webview.addEventListener 'ipc-message', listener
|
||||
webview.setAttribute 'nodeintegration', 'on'
|
||||
webview.src = "file://#{fixtures}/pages/beforeunload-false.html"
|
||||
document.body.appendChild webview
|
||||
|
||||
2
vendor/brightray
vendored
2
vendor/brightray
vendored
Submodule vendor/brightray updated: 1ed1eb2709...32ba91f830
2
vendor/native_mate
vendored
2
vendor/native_mate
vendored
Submodule vendor/native_mate updated: 40da835cbb...047a8de934
2
vendor/node
vendored
2
vendor/node
vendored
Submodule vendor/node updated: a7e75da3ca...e5aaa1ad33
Reference in New Issue
Block a user