Merge pull request #5 from atom/master

Update from original
This commit is contained in:
Eran Tiktin 2015-09-27 21:33:37 +03:00
commit fd9eadd1fa
55 changed files with 779 additions and 192 deletions

View file

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

View file

@ -0,0 +1,201 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_download_item.h"
#include <map>
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/node_includes.h"
#include "base/memory/linked_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "native_mate/dictionary.h"
#include "net/base/filename_util.h"
namespace mate {
template<>
struct Converter<content::DownloadItem::DownloadState> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
content::DownloadItem::DownloadState state) {
std::string download_state;
switch (state) {
case content::DownloadItem::COMPLETE:
download_state = "completed";
break;
case content::DownloadItem::CANCELLED:
download_state = "cancelled";
break;
case content::DownloadItem::INTERRUPTED:
download_state = "interrupted";
break;
default:
break;
}
return ConvertToV8(isolate, download_state);
}
};
} // namespace mate
namespace atom {
namespace api {
namespace {
// The wrapDownloadItem funtion which is implemented in JavaScript
using WrapDownloadItemCallback = base::Callback<void(v8::Local<v8::Value>)>;
WrapDownloadItemCallback g_wrap_download_item;
char kDownloadItemSavePathKey[] = "DownloadItemSavePathKey";
std::map<uint32, linked_ptr<v8::Global<v8::Value>>> g_download_item_objects;
} // namespace
DownloadItem::SavePathData::SavePathData(const base::FilePath& path) :
path_(path) {
}
const base::FilePath& DownloadItem::SavePathData::path() {
return path_;
}
DownloadItem::DownloadItem(content::DownloadItem* download_item) :
download_item_(download_item) {
download_item_->AddObserver(this);
}
DownloadItem::~DownloadItem() {
Destroy();
}
void DownloadItem::Destroy() {
if (download_item_) {
download_item_->RemoveObserver(this);
auto iter = g_download_item_objects.find(download_item_->GetId());
if (iter != g_download_item_objects.end())
g_download_item_objects.erase(iter);
download_item_ = nullptr;
}
}
bool DownloadItem::IsDestroyed() const {
return download_item_ == nullptr;
}
void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) {
download_item_->IsDone() ? Emit("done", item->GetState()) : Emit("updated");
}
void DownloadItem::OnDownloadDestroyed(content::DownloadItem* download) {
Destroy();
}
int64 DownloadItem::GetReceivedBytes() {
return download_item_->GetReceivedBytes();
}
int64 DownloadItem::GetTotalBytes() {
return download_item_->GetTotalBytes();
}
const GURL& DownloadItem::GetUrl() {
return download_item_->GetURL();
}
std::string DownloadItem::GetMimeType() {
return download_item_->GetMimeType();
}
bool DownloadItem::HasUserGesture() {
return download_item_->HasUserGesture();
}
std::string DownloadItem::GetFilename() {
return base::UTF16ToUTF8(net::GenerateFileName(GetUrl(),
GetContentDisposition(),
std::string(),
download_item_->GetSuggestedFilename(),
GetMimeType(),
std::string()).LossyDisplayName());
}
std::string DownloadItem::GetContentDisposition() {
return download_item_->GetContentDisposition();
}
void DownloadItem::SetSavePath(const base::FilePath& path) {
download_item_->SetUserData(UserDataKey(), new SavePathData(path));
}
void DownloadItem::Pause() {
download_item_->Pause();
}
void DownloadItem::Resume() {
download_item_->Resume();
}
void DownloadItem::Cancel() {
download_item_->Cancel(true);
}
mate::ObjectTemplateBuilder DownloadItem::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("pause", &DownloadItem::Pause)
.SetMethod("resume", &DownloadItem::Resume)
.SetMethod("cancel", &DownloadItem::Cancel)
.SetMethod("getReceivedBytes", &DownloadItem::GetReceivedBytes)
.SetMethod("getTotalBytes", &DownloadItem::GetTotalBytes)
.SetMethod("getUrl", &DownloadItem::GetUrl)
.SetMethod("getMimeType", &DownloadItem::GetMimeType)
.SetMethod("hasUserGesture", &DownloadItem::HasUserGesture)
.SetMethod("getFilename", &DownloadItem::GetFilename)
.SetMethod("getContentDisposition", &DownloadItem::GetContentDisposition)
.SetMethod("setSavePath", &DownloadItem::SetSavePath);
}
void SetWrapDownloadItem(const WrapDownloadItemCallback& callback) {
g_wrap_download_item = callback;
}
void ClearWrapDownloadItem() {
g_wrap_download_item.Reset();
}
// static
mate::Handle<DownloadItem> DownloadItem::Create(
v8::Isolate* isolate, content::DownloadItem* item) {
auto handle = mate::CreateHandle(isolate, new DownloadItem(item));
g_wrap_download_item.Run(handle.ToV8());
g_download_item_objects[item->GetId()] = make_linked_ptr(
new v8::Global<v8::Value>(isolate, handle.ToV8()));
return handle;
}
// static
void* DownloadItem::UserDataKey() {
return &kDownloadItemSavePathKey;
}
} // namespace api
} // namespace atom
namespace {
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
v8::Isolate* isolate = context->GetIsolate();
mate::Dictionary dict(isolate, exports);
dict.SetMethod("_setWrapDownloadItem", &atom::api::SetWrapDownloadItem);
dict.SetMethod("_clearWrapDownloadItem", &atom::api::ClearWrapDownloadItem);
}
} // namespace
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_download_item, Initialize);

View file

@ -0,0 +1,72 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_
#define ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_
#include <string>
#include "atom/browser/api/trackable_object.h"
#include "base/files/file_path.h"
#include "content/public/browser/download_item.h"
#include "native_mate/handle.h"
#include "url/gurl.h"
namespace atom {
namespace api {
class DownloadItem : public mate::EventEmitter,
public content::DownloadItem::Observer {
public:
class SavePathData : public base::SupportsUserData::Data {
public:
explicit SavePathData(const base::FilePath& path);
const base::FilePath& path();
private:
base::FilePath path_;
};
static mate::Handle<DownloadItem> Create(v8::Isolate* isolate,
content::DownloadItem* item);
static void* UserDataKey();
protected:
explicit DownloadItem(content::DownloadItem* download_item);
~DownloadItem();
// Override content::DownloadItem::Observer methods
void OnDownloadUpdated(content::DownloadItem* download) override;
void OnDownloadDestroyed(content::DownloadItem* download) override;
void Pause();
void Resume();
void Cancel();
int64 GetReceivedBytes();
int64 GetTotalBytes();
std::string GetMimeType();
bool HasUserGesture();
std::string GetFilename();
std::string GetContentDisposition();
const GURL& GetUrl();
void SetSavePath(const base::FilePath& path);
private:
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
void Destroy();
content::DownloadItem* download_item_;
DISALLOW_COPY_AND_ASSIGN(DownloadItem);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_

View file

@ -8,6 +8,7 @@
#include <vector>
#include "atom/browser/api/atom_api_cookies.h"
#include "atom/browser/api/atom_api_download_item.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/common/native_mate_converters/callback.h"
@ -101,19 +102,6 @@ struct Converter<ClearStorageDataOptions> {
}
};
template<>
struct Converter<content::DownloadItem*> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
content::DownloadItem* val) {
mate::Dictionary dict(isolate, v8::Object::New(isolate));
dict.Set("url", val->GetURL());
dict.Set("filename", val->GetSuggestedFilename());
dict.Set("mimeType", val->GetMimeType());
dict.Set("hasUserGesture", val->HasUserGesture());
return dict.GetHandle();
}
};
} // namespace mate
namespace atom {
@ -245,11 +233,12 @@ Session::~Session() {
}
void Session::OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) {
content::DownloadItem* item) {
auto web_contents = item->GetWebContents();
bool prevent_default = Emit("will-download", item,
api::WebContents::CreateFrom(isolate(),
web_contents));
bool prevent_default = Emit(
"will-download",
DownloadItem::Create(isolate(), item),
api::WebContents::CreateFrom(isolate(), web_contents));
if (prevent_default) {
item->Cancel(true);
item->Remove();

View file

@ -2,6 +2,7 @@ EventEmitter = require('events').EventEmitter
bindings = process.atomBinding 'app'
sessionBindings = process.atomBinding 'session'
downloadItemBindings = process.atomBinding 'download_item'
app = bindings.app
app.__proto__ = EventEmitter.prototype
@ -10,6 +11,15 @@ wrapSession = (session) ->
# session is an Event Emitter.
session.__proto__ = EventEmitter.prototype
wrapDownloadItem = (download_item) ->
# download_item is an Event Emitter.
download_item.__proto__ = EventEmitter.prototype
# Be compatible with old APIs.
download_item.url = download_item.getUrl()
download_item.filename = download_item.getFilename()
download_item.mimeType = download_item.getMimeType()
download_item.hasUserGesture = download_item.hasUserGesture()
app.setApplicationMenu = (menu) ->
require('menu').setApplicationMenu menu
@ -51,5 +61,8 @@ app.on 'activate', (event, hasVisibleWindows) -> @emit 'activate-with-no-open-wi
sessionBindings._setWrapSession wrapSession
process.once 'exit', sessionBindings._clearWrapSession
downloadItemBindings._setWrapDownloadItem wrapDownloadItem
process.once 'exit', downloadItemBindings._clearWrapDownloadItem
# Only one App object pemitted.
module.exports = app

View file

@ -6,6 +6,7 @@
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/atom_download_manager_delegate.h"
#include "atom/browser/atom_ssl_config_service.h"
#include "atom/browser/browser.h"
#include "atom/browser/net/atom_url_request_job_factory.h"
#include "atom/browser/net/asar/asar_protocol_handler.h"
@ -156,6 +157,10 @@ content::BrowserPluginGuestManager* AtomBrowserContext::GetGuestManager() {
return guest_manager_.get();
}
net::SSLConfigService* AtomBrowserContext::CreateSSLConfigService() {
return new AtomSSLConfigService;
}
void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
pref_registry->RegisterFilePathPref(prefs::kSelectFileLastDirectory,
base::FilePath());

View file

@ -27,6 +27,7 @@ class AtomBrowserContext : public brightray::BrowserContext {
content::URLRequestInterceptorScopedVector* interceptors) override;
net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory(
const base::FilePath& base_path) override;
net::SSLConfigService* CreateSSLConfigService() override;
// content::BrowserContext:
content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;

View file

@ -6,6 +6,7 @@
#include <string>
#include "atom/browser/api/atom_api_download_item.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/native_window.h"
#include "atom/browser/ui/file_dialog.h"
@ -73,18 +74,19 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
if (relay)
window = relay->window.get();
file_dialog::Filters filters;
base::FilePath path;
if (!file_dialog::ShowSaveDialog(window, item->GetURL().spec(), default_path,
filters, &path)) {
return;
if (file_dialog::ShowSaveDialog(window, item->GetURL().spec(), default_path,
file_dialog::Filters(), &path)) {
// Remember the last selected download directory.
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
download_manager_->GetBrowserContext());
browser_context->prefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
path.DirName());
}
// Remeber the last selected download directory.
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
download_manager_->GetBrowserContext());
browser_context->prefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
path.DirName());
// Running the DownloadTargetCallback with an empty FilePath signals that the
// download should be cancelled.
// If user cancels the file save dialog, run the callback with empty FilePath.
callback.Run(path,
content::DownloadItem::TARGET_DISPOSITION_PROMPT,
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path);
@ -100,6 +102,25 @@ bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
const content::DownloadTargetCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!download->GetForcedFilePath().empty()) {
callback.Run(download->GetForcedFilePath(),
content::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
download->GetForcedFilePath());
return true;
}
base::SupportsUserData::Data* save_path = download->GetUserData(
atom::api::DownloadItem::UserDataKey());
if (save_path) {
const base::FilePath& default_download_path =
static_cast<api::DownloadItem::SavePathData*>(save_path)->path();
callback.Run(default_download_path,
content::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
default_download_path);
return true;
}
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
download_manager_->GetBrowserContext());
base::FilePath default_download_path = browser_context->prefs()->GetFilePath(
@ -110,14 +131,6 @@ bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
default_download_path = path.Append(FILE_PATH_LITERAL("Downloads"));
}
if (!download->GetForcedFilePath().empty()) {
callback.Run(download->GetForcedFilePath(),
content::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
download->GetForcedFilePath());
return true;
}
CreateDownloadPathCallback download_path_callback =
base::Bind(&AtomDownloadManagerDelegate::OnDownloadPathGenerated,
weak_ptr_factory_.GetWeakPtr(),

View file

@ -0,0 +1,47 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/atom_ssl_config_service.h"
#include <string>
#include "base/command_line.h"
#include "atom/common/options_switches.h"
#include "content/public/browser/browser_thread.h"
#include "net/socket/ssl_client_socket.h"
namespace atom {
namespace {
uint16 GetSSLProtocolVersion(const std::string& version_string) {
uint16 version = 0; // Invalid
if (version_string == "tls1")
version = net::SSL_PROTOCOL_VERSION_TLS1;
else if (version_string == "tls1.1")
version = net::SSL_PROTOCOL_VERSION_TLS1_1;
else if (version_string == "tls1.2")
version = net::SSL_PROTOCOL_VERSION_TLS1_2;
return version;
}
} // namespace
AtomSSLConfigService::AtomSSLConfigService() {
auto cmd_line = base::CommandLine::ForCurrentProcess();
if (cmd_line->HasSwitch(switches::kSSLVersionFallbackMin)) {
auto version_string =
cmd_line->GetSwitchValueASCII(switches::kSSLVersionFallbackMin);
config_.version_fallback_min = GetSSLProtocolVersion(version_string);
}
}
AtomSSLConfigService::~AtomSSLConfigService() {
}
void AtomSSLConfigService::GetSSLConfig(net::SSLConfig* config) {
*config = config_;
}
} // namespace atom

View file

@ -0,0 +1,28 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_ATOM_SSL_CONFIG_SERVICE_H_
#define ATOM_BROWSER_ATOM_SSL_CONFIG_SERVICE_H_
#include "net/ssl/ssl_config_service.h"
namespace atom {
class AtomSSLConfigService : public net::SSLConfigService {
public:
AtomSSLConfigService();
~AtomSSLConfigService() override;
// net::SSLConfigService:
void GetSSLConfig(net::SSLConfig* config) override;
private:
net::SSLConfig config_;
DISALLOW_COPY_AND_ASSIGN(AtomSSLConfigService);
};
} // namespace atom
#endif // ATOM_BROWSER_ATOM_SSL_CONFIG_SERVICE_H_

View file

@ -13,8 +13,8 @@ app.on('window-all-closed', function() {
// Parse command line options.
var argv = process.argv.slice(1);
var option = { file: null, help: null, version: null, webdriver: null };
for (var i in argv) {
var option = { file: null, help: null, version: null, webdriver: null, modules: [] };
for (var i = 0; i < argv.length; i++) {
if (argv[i] == '--version' || argv[i] == '-v') {
option.version = true;
break;
@ -23,6 +23,9 @@ for (var i in argv) {
break;
} else if (argv[i] == '--test-type=webdriver') {
option.webdriver = true;
} else if (argv[i] == '--require' || argv[i] == '-r') {
option.modules.push(argv[++i]);
continue;
} else if (argv[i][0] == '-') {
continue;
} else {
@ -212,6 +215,10 @@ app.once('ready', function() {
Menu.setApplicationMenu(menu);
});
if (option.modules.length > 0) {
require('module')._preloadModules(option.modules);
}
// Start the specified app if there is one specified in command line, otherwise
// start the default app.
if (option.file && !option.webdriver) {
@ -253,6 +260,7 @@ if (option.file && !option.webdriver) {
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 += " -r, --require Module to preload (option can be repeated)";
helpMessage += " -h, --help Print this usage message.\n";
helpMessage += " -v, --version Print the version.";
console.log(helpMessage);

View file

@ -68,6 +68,7 @@ NativeWindow::NativeWindow(
const mate::Dictionary& options)
: content::WebContentsObserver(inspectable_web_contents->GetWebContents()),
has_frame_(true),
force_using_draggable_region_(false),
transparent_(false),
enable_larger_than_screen_(false),
is_closed_(false),
@ -159,8 +160,13 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
// Then show it.
bool show = true;
options.Get(switches::kShow, &show);
if (show)
if (show) {
Show();
} else {
// When RenderView is created it sets to visible, this is to prevent
// breaking the visibility API.
web_contents()->WasHidden();
}
}
void NativeWindow::SetSize(const gfx::Size& size) {
@ -468,7 +474,7 @@ bool NativeWindow::OnMessageReceived(const IPC::Message& message) {
void NativeWindow::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
// Draggable region is not supported for non-frameless window.
if (has_frame_)
if (has_frame_ && !force_using_draggable_region_)
return;
draggable_region_ = DraggableRegionsToSkRegion(regions);
}

View file

@ -219,6 +219,13 @@ class NativeWindow : public content::WebContentsObserver,
bool enable_larger_than_screen() const { return enable_larger_than_screen_; }
gfx::ImageSkia icon() const { return icon_; }
bool force_using_draggable_region() const {
return force_using_draggable_region_;
}
void set_force_using_draggable_region(bool force) {
force_using_draggable_region_ = true;
}
void set_has_dialog_attached(bool has_dialog_attached) {
has_dialog_attached_ = has_dialog_attached;
}
@ -257,6 +264,9 @@ class NativeWindow : public content::WebContentsObserver,
// Whether window has standard frame.
bool has_frame_;
// Force the window to be aware of draggable regions.
bool force_using_draggable_region_;
// Whether window is transparent.
bool transparent_;

View file

@ -351,21 +351,19 @@ NativeWindowMac::NativeWindowMac(
bool useStandardWindow = true;
options.Get(switches::kStandardWindow, &useStandardWindow);
// New title bar styles are available in Yosemite or newer
std::string titleBarStyle;
if (base::mac::IsOSYosemiteOrLater())
options.Get(switches::kTitleBarStyle, &titleBarStyle);
NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask;
if (!useStandardWindow || transparent() || !has_frame()) {
styleMask |= NSTexturedBackgroundWindowMask;
}
std::string titleBarStyle = "default";
options.Get(switches::kTitleBarStyle, &titleBarStyle);
if (base::mac::IsOSYosemiteOrLater()) {
// New title bar styles are available in Yosemite or newer
if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) {
styleMask |= NSFullSizeContentViewWindowMask;
styleMask |= NSUnifiedTitleAndToolbarWindowMask;
}
if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) {
styleMask |= NSFullSizeContentViewWindowMask;
styleMask |= NSUnifiedTitleAndToolbarWindowMask;
}
window_.reset([[AtomNSWindow alloc]
@ -393,18 +391,18 @@ NativeWindowMac::NativeWindowMac(
// We will manage window's lifetime ourselves.
[window_ setReleasedWhenClosed:NO];
// Configure title bar look on Yosemite or newer
if (base::mac::IsOSYosemiteOrLater()) {
if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) {
[window_ setTitlebarAppearsTransparent:YES];
[window_ setTitleVisibility:NSWindowTitleHidden];
if (titleBarStyle == "hidden-inset") {
NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"];
toolbar.showsBaselineSeparator = NO;
[window_ setToolbar:toolbar];
[toolbar release];
}
// Hide the title bar.
if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) {
[window_ setTitlebarAppearsTransparent:YES];
[window_ setTitleVisibility:NSWindowTitleHidden];
if (titleBarStyle == "hidden-inset") {
base::scoped_nsobject<NSToolbar> toolbar(
[[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]);
[toolbar setShowsBaselineSeparator:NO];
[window_ setToolbar:toolbar];
}
// We should be aware of draggable regions when using hidden titlebar.
set_force_using_draggable_region(true);
}
// On OS X the initial window size doesn't include window frame.
@ -436,6 +434,11 @@ NativeWindowMac::NativeWindowMac(
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
InstallView();
// Install the DraggableRegionView if it is forced to use draggable regions
// for normal window.
if (has_frame() && force_using_draggable_region())
InstallDraggableRegionView();
}
NativeWindowMac::~NativeWindowMac() {
@ -467,6 +470,8 @@ bool NativeWindowMac::IsFocused() {
}
void NativeWindowMac::Show() {
web_contents()->WasShown();
// This method is supposed to put focus on window, however if the app does not
// have focus then "makeKeyAndOrderFront" will only show the window.
[NSApp activateIgnoringOtherApps:YES];
@ -475,11 +480,13 @@ void NativeWindowMac::Show() {
}
void NativeWindowMac::ShowInactive() {
web_contents()->WasShown();
[window_ orderFrontRegardless];
}
void NativeWindowMac::Hide() {
[window_ orderOut:nil];
web_contents()->WasHidden();
}
bool NativeWindowMac::IsVisible() {

View file

@ -338,15 +338,18 @@ bool NativeWindowViews::IsFocused() {
}
void NativeWindowViews::Show() {
web_contents()->WasShown();
window_->native_widget_private()->ShowWithWindowState(GetRestoredState());
}
void NativeWindowViews::ShowInactive() {
web_contents()->WasShown();
window_->ShowInactive();
}
void NativeWindowViews::Hide() {
window_->Hide();
web_contents()->WasHidden();
}
bool NativeWindowViews::IsVisible() {

View file

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

View file

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

View file

@ -4,10 +4,7 @@
#include "atom/browser/ui/win/notify_icon.h"
#include <shobjidl.h>
#include "atom/browser/ui/win/notify_icon_host.h"
#include "base/md5.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/windows_version.h"
@ -28,31 +25,7 @@ NotifyIcon::NotifyIcon(NotifyIconHost* host,
icon_id_(id),
window_(window),
message_id_(message),
menu_model_(NULL),
has_tray_app_id_hash_(false) {
// NB: If we have an App Model ID, we should propagate that to the tray.
// Doing this prevents duplicate items from showing up in the notification
// preferences (i.e. "Always Show / Show notifications only / etc")
PWSTR explicit_app_id;
if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(&explicit_app_id))) {
// GUIDs and MD5 hashes are the same length. So convenient!
base::MD5Sum(explicit_app_id,
sizeof(wchar_t) * wcslen(explicit_app_id),
reinterpret_cast<base::MD5Digest*>(&tray_app_id_hash_));
// Set the GUID to version 4 as described in RFC 4122, section 4.4.
// The format of GUID version 4 must be like
// xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, where y is one of [8, 9, A, B].
tray_app_id_hash_.Data3 &= 0x0fff;
tray_app_id_hash_.Data3 |= 0x4000;
// Set y to one of [8, 9, A, B].
tray_app_id_hash_.Data4[0] = 1;
has_tray_app_id_hash_ = true;
CoTaskMemFree(explicit_app_id);
}
menu_model_(NULL) {
NOTIFYICONDATA icon_data;
InitIconData(&icon_data);
icon_data.uFlags |= NIF_MESSAGE;
@ -81,10 +54,6 @@ void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos,
icon_id.uID = icon_id_;
icon_id.hWnd = window_;
icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER);
if (has_tray_app_id_hash_)
memcpy(reinterpret_cast<void*>(&icon_id.guidItem),
&tray_app_id_hash_,
sizeof(GUID));
RECT rect = { 0 };
Shell_NotifyIconGetRect(&icon_id, &rect);
@ -202,13 +171,6 @@ void NotifyIcon::InitIconData(NOTIFYICONDATA* icon_data) {
icon_data->cbSize = sizeof(NOTIFYICONDATA);
icon_data->hWnd = window_;
icon_data->uID = icon_id_;
if (has_tray_app_id_hash_) {
icon_data->uFlags |= NIF_GUID;
memcpy(reinterpret_cast<void*>(&icon_data->guidItem),
&tray_app_id_hash_,
sizeof(GUID));
}
}
} // namespace atom

View file

@ -79,10 +79,6 @@ class NotifyIcon : public TrayIcon {
// The context menu.
ui::SimpleMenuModel* menu_model_;
// A hash of the app model ID
GUID tray_app_id_hash_;
bool has_tray_app_id_hash_;
DISALLOW_COPY_AND_ASSIGN(NotifyIcon);
};

View file

@ -115,6 +115,14 @@ bool FillFileInfoWithNode(Archive::FileInfo* info,
Archive::Archive(const base::FilePath& path)
: path_(path),
file_(path_, base::File::FLAG_OPEN | base::File::FLAG_READ),
#if defined(OS_WIN)
fd_(_open_osfhandle(
reinterpret_cast<intptr_t>(file_.GetPlatformFile()), 0)),
#elif defined(OS_POSIX)
fd_(file_.GetPlatformFile()),
#else
fd_(-1),
#endif
header_size_(0) {
}
@ -271,17 +279,7 @@ bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) {
}
int Archive::GetFD() const {
if (!file_.IsValid())
return -1;
#if defined(OS_WIN)
return
_open_osfhandle(reinterpret_cast<intptr_t>(file_.GetPlatformFile()), 0);
#elif defined(OS_POSIX)
return file_.GetPlatformFile();
#else
return -1;
#endif
return fd_;
}
} // namespace asar

View file

@ -69,6 +69,7 @@ class Archive {
private:
base::FilePath path_;
base::File file_;
int fd_;
uint32 header_size_;
scoped_ptr<base::DictionaryValue> header_;

View file

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

View file

@ -34,6 +34,7 @@ REFERENCE_MODULE(atom_browser_app);
REFERENCE_MODULE(atom_browser_auto_updater);
REFERENCE_MODULE(atom_browser_content_tracing);
REFERENCE_MODULE(atom_browser_dialog);
REFERENCE_MODULE(atom_browser_download_item);
REFERENCE_MODULE(atom_browser_menu);
REFERENCE_MODULE(atom_browser_power_monitor);
REFERENCE_MODULE(atom_browser_power_save_blocker);

View file

@ -113,6 +113,10 @@ const char kDisableHttpCache[] = "disable-http-cache";
// Register schemes to standard.
const char kRegisterStandardSchemes[] = "register-standard-schemes";
// The minimum SSL/TLS version ("tls1", "tls1.1", or "tls1.2") that
// TLS fallback will accept.
const char kSSLVersionFallbackMin[] = "ssl-version-fallback-min";
// The browser process app model ID
const char kAppUserModelId[] = "app-user-model-id";

View file

@ -59,6 +59,7 @@ extern const char kPageVisibility[];
extern const char kDisableHttpCache[];
extern const char kRegisterStandardSchemes[];
extern const char kSSLVersionFallbackMin[];
extern const char kAppUserModelId[];

View file

@ -26,7 +26,7 @@
* [`<webview>` 태그](api/web-view-tag.md)
* [`window.open` 함수](api/window-open.md)
### 메인 프로세스를 위한 모듈들:
### 메인 프로세스에서 사용할 수 있는 모듈:
* [app (0% 번역됨)](api/app.md)
* [auto-updater](api/auto-updater.md)
@ -44,13 +44,13 @@
* [web-contents (0% 번역됨)](api/web-contents.md)
* [tray](api/tray.md)
### 랜더러 프로세스를 위한 모듈들 (웹 페이지):
### 랜더러 프로세스에서 사용할 수 있는 모듈 (웹 페이지):
* [ipc (renderer)](api/ipc-renderer.md)
* [remote](api/remote.md)
* [web-frame](api/web-frame.md)
### 두 프로세스에서 모두 사용 가능한 모듈들:
### 두 프로세스 모두 사용할 수 있는 모듈:
* [clipboard](api/clipboard.md)
* [crash-reporter](api/crash-reporter.md)

View file

@ -1,6 +1,6 @@
# 크롬 Command-Line 스위치 지원
다음 Command-Line 스위치들은 크롬 브라우저에서 제공되는 추가 옵션이며 Electron에서도 지원합니다.
크롬 Command-Line 스위치는 크롬 브라우저에서 제공되는 추가 옵션이며 Electron에서도 지원합니다.
[app][app]의 [ready][ready]이벤트가 작동하기 전에 [app.commandLine.appendSwitch][append-switch] API를 사용하면
어플리케이션 내부에서 스위치들을 추가할 수 있습니다:
@ -80,7 +80,11 @@ Pepper 플래시 플러그인의 버전을 설정합니다.
## --log-net-log=`path`
Net log 이벤트를 지정한 `path`에 로그로 기록합니다.
Net log 이벤트를 활성화하고 `path`에 로그를 기록합니다.
## --ssl-version-fallback-min=`version`
Fallback SSL/TLS 최소 버전을 지정합니다. ("tls1", "tls1.1", "tls1.2")
## --v=`log_level`
@ -93,7 +97,7 @@ Net log 이벤트를 지정한 `path`에 로그로 기록합니다.
`--v` 옵션에 전달된 값을 덮어쓰고 모듈당 최대 V-logging 레벨을 지정합니다.
예를 들어 `my_module=2,foo*=3``my_module.*`, `foo*.*`와 같은 파일 이름 패턴을 가진 모든 소스 코드들의 로깅 레벨을 각각 2와 3으로 설정합니다.
슬래시(`/`), 백슬래시(`\`)를 포함하는 모든 패턴은 모듈뿐만 아니라 모든 경로명에 대해서도 테스트 됩니다.
또한 슬래시(`/`) 또는 백슬래시(`\`)를 포함하는 패턴은 지정한 경로에 대해 패턴을 테스트 합니다.
예를 들어 `*/foo/bar/*=2` 표현식은 `foo/bar` 디렉터리 안의 모든 소스 코드의 로깅 레벨을 2로 지정합니다.
모든 크로미움과 관련된 로그를 비활성화하고 어플리케이션의 로그만 활성화 하려면 다음과 같이 코드를 작성하면 됩니다:

View file

@ -6,7 +6,7 @@
`screen`은 [EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter)를 상속 받았습니다.
**참고:** 랜더러 / DevTools에선 이미 DOM 속성이 `window.screen`을 가지고 있으므로 `screen = require('screen')` 형식으로 모듈을 사용할 수 없습니다.
밑의 예제와 같이 `atomScreen` 같은 이름으로 모듈 이름을 대체하여 사용해야 합니다.
밑의 예제와 같이 `electronScreen` 같은 이름으로 모듈 이름을 대체하여 사용해야 합니다.
다음 예제는 화면 전체를 채우는 윈도우 창을 생성합니다:
@ -17,8 +17,8 @@ var BrowserWindow = require('browser-window');
var mainWindow;
app.on('ready', function() {
var atomScreen = require('screen');
var size = atomScreen.getPrimaryDisplay().workAreaSize;
var electronScreen = require('screen');
var size = electronScreen.getPrimaryDisplay().workAreaSize;
mainWindow = new BrowserWindow({ width: size.width, height: size.height });
});
```
@ -32,8 +32,8 @@ var BrowserWindow = require('browser-window');
var mainWindow;
app.on('ready', function() {
var atomScreen = require('screen');
var displays = atomScreen.getAllDisplays();
var electronScreen = require('screen');
var displays = electronScreen.getAllDisplays();
var externalDisplay = null;
for (var i in displays) {
if (displays[i].bounds.x > 0 || displays[i].bounds.y > 0) {

View file

@ -17,11 +17,7 @@ var session = win.webContents.session
### Event: 'will-download'
* `event` Event
* `item` Object
* `url` String
* `filename` String
* `mimeType` String
* `hasUserGesture` Boolean
* `item` [DownloadItem](download-item.md)
* `webContents` [WebContents](web-contents.md)
Electron의 `webContents`에서 `item`을 다운로드할 때 발생하는 이벤트입니다.
@ -31,7 +27,7 @@ Electron의 `webContents`에서 `item`을 다운로드할 때 발생하는 이
```javascript
session.on('will-download', function(event, item, webContents) {
event.preventDefault();
require('request')(item.url, function(data) {
require('request')(item.getUrl(), function(data) {
require('fs').writeFileSync('/somewhere', data);
});
});

View file

@ -135,6 +135,14 @@
즉. 작동중인 랜더러 프로세스의 세션은 변경할 수 없습니다.
이후 이 값을 바꾸려고 시도하면 DOM 예외를 발생시킵니다.
### `allowpopups`
```html
<webview src="https://www.github.com/" allowpopups></webview>
```
"on"으로 지정하면 페이지에서 새로운 창을 열 수 있도록 허용합니다.
## Methods
`webview` 태그는 다음과 같은 메서드를 가지고 있습니다:
@ -467,8 +475,8 @@ Returns:
* `url` String
* `frameName` String
* `disposition` String - Can be `default`, `foreground-tab`, `background-tab`,
`new-window` and `other`
* `disposition` String - `default`, `foreground-tab`, `background-tab`, `new-window`, `other`를 사용할 수 있습니다.
* `options` Object - 새로운 `BrowserWindow`를 만들 때 사용되어야 하는 옵션.
페이지가 새로운 브라우저 창을 생성할 때 발생하는 이벤트입니다.

View file

@ -6,6 +6,8 @@
프록시 객체는 브라우저의 웹 페이지 창과 호환될 수 있도록 일부 제한된 표준 기능만 가지고 있습니다.
창의 모든 컨트롤 권한을 가지려면 `BrowserWindow`를 직접 생성해서 사용해야 합니다.
새롭게 생성된 `BrowserWindow`는 기본적으로 부모 창의 옵션을 상속합니다. 이 옵션을 변경하려면 새 창을 열 때 `features` 인자를 지정해야 합니다.
### `window.open(url[, frameName][, features])`
* `url` String
@ -14,6 +16,8 @@
`BrowserWindowProxy` 클래스의 객체를 반환하는 새로운 윈도우를 생성합니다.
`features` 문자열은 표준 브라우저의 포맷을 따르고 있지만, 각 기능은 `BrowserWindow`의 옵션이어야 합니다.
### `window.opener.postMessage(message, targetOrigin)`
* `message` String

View file

@ -111,6 +111,7 @@ app.on('ready', function() {
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>헬로 월드!</title>
</head>
<body>

View file

@ -29,7 +29,20 @@ npm install --save-dev electron-rebuild
node ./node_modules/.bin/electron-rebuild
```
### node-gyp을 이용한 방법
### `npm`을 이용한 방법
또한 `npm`을 통해 설치할 수도 있습니다.
환경변수가 필요한 것을 제외하고 일반 Node 모듈을 설치하는 방법과 완전히 똑같습니다:
```bash
export npm_config_disturl=https://atom.io/download/atom-shell
export npm_config_target=0.33.1
export npm_config_arch=x64
export npm_config_runtime=electron
HOME=~/.electron-gyp npm install module-name
```
### `node-gyp`를 이용한 방법
Node 모듈을 `node-gyp`를 사용하여 Electron을 타겟으로 빌드할 때는 `node-gyp`에 헤더 다운로드 주소와 버전을 알려주어야 합니다:
@ -40,15 +53,3 @@ $ HOME=~/.electron-gyp node-gyp rebuild --target=0.29.1 --arch=x64 --dist-url=ht
`HOME=~/.electron-gyp`은 변경할 헤더의 위치를 찾습니다. `--target=0.29.1`은 Electron의 버전입니다.
`--dist-url=...`은 헤더를 다운로드 하는 주소입니다. `--arch=x64`는 64비트 시스템을 타겟으로 빌드 한다는 것을 `node-gyp`에게 알려줍니다.
### npm을 이용한 방법
또한 `npm`을 통해 설치할 수도 있습니다.
환경변수가 필요한 것을 제외하고 일반 Node 모듈을 설치하는 방법과 완전히 똑같습니다:
```bash
export npm_config_disturl=https://atom.io/download/atom-shell
export npm_config_target=0.29.1
export npm_config_arch=x64
HOME=~/.electron-gyp npm install module-name
```

View file

@ -665,7 +665,7 @@ Same as `webContents.loadUrl(url[, options])`.
Same as `webContents.reload`.
### `win.setMenu(menu)` _OS X_
### `win.setMenu(menu)` _Linux_ _Windows_
* `menu` Menu

View file

@ -87,6 +87,11 @@ Sets the `version` of the pepper flash plugin.
Enables net log events to be saved and writes them to `path`.
## --ssl-version-fallback-min=`version`
Set the minimum SSL/TLS version ("tls1", "tls1.1" or "tls1.2") that TLS
fallback will accept.
## --v=`log_level`
Gives the default maximal active V-logging level; 0 is the default. Normally

101
docs/api/download-item.md Normal file
View file

@ -0,0 +1,101 @@
# DownloadItem
`DownloadItem` is an EventEmitter represents a download item in Electron. It
is used in `will-download` event of `Session` module, and allows users to
control the download item.
```javascript
// In the main process.
win.webContents.session.on('will-download', function(event, item, webContents) {
// Set the save path, making Electron not to prompt a save dialog.
item.setSavePath('/tmp/save.pdf');
console.log(item.getMimeType());
console.log(item.getFilename());
console.log(item.getTotalBytes());
item.on('updated', function() {
console.log('Received bytes: ' + item.getReceivedBytes());
});
item.on('done', function(e, state) {
if (state == "completed") {
console.log("Download successfully");
} else {
console.log("Download is cancelled or interrupted that can't be resumed");
}
});
```
## Events
### Event: 'updated'
Emits when the `downloadItem` gets updated.
### Event: 'done'
* `event` Event
* `state` String
* `completed` - The download completed successfully.
* `cancelled` - The download has been cancelled.
* `interrupted` - An error broke the connection with the file server.
Emits when the download is in a terminal state. This includes a completed
download, a cancelled download(via `downloadItem.cancel()`), and interrupted
download that can't be resumed.
## Methods
The `downloadItem` object has the following methods:
### `downloadItem.setSavePath(path)`
* `path` String - Set the save file path of the download item.
The API is only available in session's `will-download` callback function.
If user doesn't set the save path via the API, Electron will use the original
routine to determine the save path(Usually prompts a save dialog).
### `downloadItem.pause()`
Pauses the download.
### `downloadItem.resume()`
Resumes the download that has been paused.
### `downloadItem.cancel()`
Cancels the download operation.
### `downloadItem.getUrl()`
Returns a `String` represents the origin url where the item is downloaded from.
### `downloadItem.getMimeType()`
Returns a `String` represents the mime type.
### `downloadItem.hasUserGesture()`
Returns a `Boolean` indicates whether the download has user gesture.
### `downloadItem.getFilename()`
Returns a `String` represents the file name of the download item.
**Note:** The file name is not always the same as the actual one saved in local
disk. If user changes the file name in a prompted download saving dialog, the
actual name of saved file will be different.
### `downloadItem.getTotalBytes()`
Returns a `Integer` represents the total size in bytes of the download item.
If the size is unknown, it returns 0.
### `downloadItem.getReceivedBytes()`
Returns a `Integer` represents the received bytes of the download item.
### `downloadItem.getContentDisposition()`
Returns a `String` represents the Content-Disposition field from the response
header.

View file

@ -8,7 +8,7 @@ position, etc. You should not use this module until the `ready` event of the
**Note:** In the renderer / DevTools, `window.screen` is a reserved
DOM property, so writing `var screen = require('screen')` will not work. In our
examples below, we use `atomScreen` as the variable name instead.
examples below, we use `electronScreen` as the variable name instead.
An example of creating a window that fills the whole screen:
@ -19,8 +19,8 @@ var BrowserWindow = require('browser-window');
var mainWindow;
app.on('ready', function() {
var atomScreen = require('screen');
var size = atomScreen.getPrimaryDisplay().workAreaSize;
var electronScreen = require('screen');
var size = electronScreen.getPrimaryDisplay().workAreaSize;
mainWindow = new BrowserWindow({ width: size.width, height: size.height });
});
```
@ -34,8 +34,8 @@ var BrowserWindow = require('browser-window');
var mainWindow;
app.on('ready', function() {
var atomScreen = require('screen');
var displays = atomScreen.getAllDisplays();
var electronScreen = require('screen');
var displays = electronScreen.getAllDisplays();
var externalDisplay = null;
for (var i in displays) {
if (displays[i].bounds.x > 0 || displays[i].bounds.y > 0) {

View file

@ -18,11 +18,7 @@ var session = win.webContents.session
### Event: 'will-download'
* `event` Event
* `item` Object
* `url` String
* `filename` String
* `mimeType` String
* `hasUserGesture` Boolean
* `item` [DownloadItem](download-item.md)
* `webContents` [WebContents](web-contents.md)
Fired when Electron is about to download `item` in `webContents`.
@ -32,7 +28,7 @@ Calling `event.preventDefault()` will cancel the download.
```javascript
session.on('will-download', function(event, item, webContents) {
event.preventDefault();
require('request')(item.url, function(data) {
require('request')(item.getUrl(), function(data) {
require('fs').writeFileSync('/somewhere', data);
});
});

View file

@ -124,6 +124,7 @@ Finally the `index.html` is the web page you want to show:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>

View file

@ -34,6 +34,19 @@ npm install --save-dev electron-rebuild
node ./node_modules/.bin/electron-rebuild
```
### The npm Way
You can also use `npm` to install modules. The steps are exactly the same with
Node modules, except that you need to setup some environment variables:
```bash
export npm_config_disturl=https://atom.io/download/atom-shell
export npm_config_target=0.33.1
export npm_config_arch=x64
export npm_config_runtime=electron
HOME=~/.electron-gyp npm install module-name
```
### The node-gyp Way
To build Node modules with headers of Electron, you need to tell `node-gyp`
@ -48,15 +61,3 @@ The `HOME=~/.electron-gyp` changes where to find development headers. The
`--target=0.29.1` is version of Electron. The `--dist-url=...` specifies
where to download the headers. The `--arch=x64` says the module is built for
64bit system.
### The npm Way
You can also use `npm` to install modules. The steps are exactly the same with
Node modules, except that you need to setup some environment variables:
```bash
export npm_config_disturl=https://atom.io/download/atom-shell
export npm_config_target=0.29.1
export npm_config_arch=x64
HOME=~/.electron-gyp npm install module-name
```

View file

@ -71,6 +71,8 @@
'atom/browser/api/atom_api_content_tracing.cc',
'atom/browser/api/atom_api_cookies.cc',
'atom/browser/api/atom_api_cookies.h',
'atom/browser/api/atom_api_download_item.cc',
'atom/browser/api/atom_api_download_item.h',
'atom/browser/api/atom_api_dialog.cc',
'atom/browser/api/atom_api_global_shortcut.cc',
'atom/browser/api/atom_api_global_shortcut.h',
@ -129,6 +131,8 @@
'atom/browser/atom_quota_permission_context.h',
'atom/browser/atom_speech_recognition_manager_delegate.cc',
'atom/browser/atom_speech_recognition_manager_delegate.h',
'atom/browser/atom_ssl_config_service.cc',
'atom/browser/atom_ssl_config_service.h',
'atom/browser/bridge_task_runner.cc',
'atom/browser/bridge_task_runner.h',
'atom/browser/browser.cc',

View file

@ -1,11 +1,11 @@
{
"name": "electron",
"devDependencies": {
"asar": "0.8.x",
"asar": "^0.8.0",
"coffee-script": "^1.9.2",
"coffeelint": "^1.9.4",
"request": "*",
"runas": "3.x"
"runas": "^3.0.0"
},
"private": true,
"scripts": {

View file

@ -8,7 +8,7 @@ import sys
BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \
'http://github-janky-artifacts.s3.amazonaws.com/libchromiumcontent'
LIBCHROMIUMCONTENT_COMMIT = '8482fe555913dea3bde8a74f754524e2cfb02bc5'
LIBCHROMIUMCONTENT_COMMIT = '04523758cda2a96d2454f9056fb1fb9a1c1f95f1'
PLATFORM = {
'cygwin': 'win32',

View file

@ -8,7 +8,7 @@ from lib.config import get_target_arch
from lib.util import safe_mkdir, rm_rf, extract_zip, tempdir, download
VERSION = 'v0.7.0'
VERSION = 'v0.8.0'
SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
FRAMEWORKS_URL = 'http://github.com/atom/atom-shell-frameworks/releases' \
'/download/' + VERSION

View file

@ -294,16 +294,6 @@ describe 'browser-window module', ->
w.show()
w.minimize()
describe 'will-navigate event', ->
@timeout 10000
it 'emits when user starts a navigation', (done) ->
url = "file://#{fixtures}/pages/will-navigate.html"
w.webContents.on 'will-navigate', (event, u) ->
event.preventDefault()
assert.equal u, url
done()
w.loadUrl url
xdescribe 'beginFrameSubscription method', ->
it 'subscribes frame updates', (done) ->
w.loadUrl "file://#{fixtures}/api/blank.html"

View file

@ -2,6 +2,7 @@ assert = require 'assert'
remote = require 'remote'
http = require 'http'
path = require 'path'
fs = require 'fs'
app = remote.require 'app'
BrowserWindow = remote.require 'browser-window'
@ -72,3 +73,51 @@ describe 'session module', ->
quotas: ['persistent'],
w.webContents.session.clearStorageData options, ->
w.webContents.send 'getcount'
describe 'DownloadItem', ->
# A 5 MB mock pdf.
mockPDF = new Buffer 1024 * 1024 * 5
contentDisposition = 'inline; filename="mock.pdf"'
ipc = require 'ipc'
downloadFilePath = path.join fixtures, 'mock.pdf'
downloadServer = http.createServer (req, res) ->
res.writeHead 200, {
'Content-Length': mockPDF.length,
'Content-Type': 'application/pdf',
'Content-Disposition': contentDisposition
}
res.end mockPDF
downloadServer.close()
it 'can download successfully', (done) ->
downloadServer.listen 0, '127.0.0.1', ->
{port} = downloadServer.address()
ipc.sendSync 'set-download-option', false
w.loadUrl "#{url}:#{port}"
ipc.once 'download-done', (state, url, mimeType, receivedBytes,
totalBytes, disposition, filename) ->
assert.equal state, 'completed'
assert.equal filename, 'mock.pdf'
assert.equal url, "http://127.0.0.1:#{port}/"
assert.equal mimeType, 'application/pdf'
assert.equal receivedBytes, mockPDF.length
assert.equal totalBytes, mockPDF.length
assert.equal disposition, contentDisposition
assert fs.existsSync downloadFilePath
fs.unlinkSync downloadFilePath
done()
it 'can cancel download', (done) ->
downloadServer.listen 0, '127.0.0.1', ->
{port} = downloadServer.address()
ipc.sendSync 'set-download-option', true
w.loadUrl "#{url}:#{port}/"
ipc.once 'download-done', (state, url, mimeType, receivedBytes,
totalBytes, disposition, filename) ->
assert.equal state, 'cancelled'
assert.equal filename, 'mock.pdf'
assert.equal mimeType, 'application/pdf'
assert.equal receivedBytes, 0
assert.equal totalBytes, mockPDF.length
assert.equal disposition, contentDisposition
done()

View file

@ -8,6 +8,10 @@ describe 'asar package', ->
describe 'node api', ->
describe 'fs.readFileSync', ->
it 'does not leak fd', ->
for i in [1..10000]
fs.readFileSync(path.join(process.resourcesPath, 'atom.asar', 'renderer', 'api', 'lib', 'ipc.js'))
it 'reads a normal file', ->
file1 = path.join fixtures, 'asar', 'a.asar', 'file1'
assert.equal fs.readFileSync(file1).toString().trim(), 'file1'

View file

@ -23,6 +23,23 @@ describe 'chromium feature', ->
{port} = server.address()
$.get "http://127.0.0.1:#{port}"
describe 'document.hidden', ->
BrowserWindow = remote.require 'browser-window'
ipc = remote.require 'ipc'
url = "file://#{fixtures}/pages/document-hidden.html"
w = null
afterEach ->
w?.destroy()
ipc.removeAllListeners 'hidden'
it 'is set correctly when window is not shown', (done) ->
ipc.once 'hidden', (event, hidden) ->
assert hidden
done()
w = new BrowserWindow(show:false)
w.loadUrl url
describe 'navigator.webkitGetUserMedia', ->
it 'calls its callbacks', (done) ->
@timeout 5000

View file

@ -0,0 +1,7 @@
<html>
<body>
<script type="text/javascript" charset="utf-8">
require('ipc').send('hidden', document.hidden);
</script>
</body>
</html>

View file

@ -22,6 +22,12 @@ describe 'third-party module', ->
assert.equal msg, 'ok'
done()
describe 'ffi', ->
it 'does not crash', ->
ffi = require 'ffi'
libm = ffi.Library('libm', ceil: [ 'double', [ 'double' ] ])
assert.equal libm.ceil(1.5), 2
describe 'q', ->
Q = require 'q'

View file

@ -65,6 +65,7 @@ describe 'node feature', ->
describe 'contexts', ->
describe 'setTimeout in fs callback', ->
return if process.env.TRAVIS is 'true'
it 'does not crash', (done) ->
fs.readFile __filename, ->
setTimeout done, 0

View file

@ -5,6 +5,7 @@
"version": "0.1.0",
"devDependencies": {
"basic-auth": "^1.0.0",
"ffi": "2.0.0",
"formidable": "1.0.16",
"graceful-fs": "3.0.5",
"mocha": "2.1.0",

View file

@ -1,6 +1,7 @@
var app = require('app');
var ipc = require('ipc');
var dialog = require('dialog');
var path = require('path');
var BrowserWindow = require('browser-window');
var window = null;
@ -73,4 +74,27 @@ app.on('ready', function() {
});
if (chosen == 0) window.destroy();
});
// For session's download test, listen 'will-download' event in browser, and
// reply the result to renderer for verifying
var downloadFilePath = path.join(__dirname, '..', 'fixtures', 'mock.pdf');
require('ipc').on('set-download-option', function(event, need_cancel) {
window.webContents.session.once('will-download',
function(e, item, webContents) {
item.setSavePath(downloadFilePath);
item.on('done', function(e, state) {
window.webContents.send('download-done',
state,
item.getUrl(),
item.getMimeType(),
item.getReceivedBytes(),
item.getTotalBytes(),
item.getContentDisposition(),
item.getFilename());
});
if (need_cancel)
item.cancel();
});
event.returnValue = "done";
});
});

2
vendor/brightray vendored

@ -1 +1 @@
Subproject commit 25f3a9d0a5b73ec170a65f4e2e4c9ad91e23fc8c
Subproject commit 8e443520e695674fd26585cfa24a0ec0b6140c27

2
vendor/node vendored

@ -1 +1 @@
Subproject commit fa54694af4350bf1720ff47e97a07c7c09325ee2
Subproject commit ac25693ad1d4c248e69a89147fd3995c3bf6c946