diff --git a/atom.gyp b/atom.gyp index 3a46f242a23..42069ea8462 100644 --- a/atom.gyp +++ b/atom.gyp @@ -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', diff --git a/atom/browser/api/atom_api_download_item.cc b/atom/browser/api/atom_api_download_item.cc new file mode 100644 index 00000000000..ec4dcd84b28 --- /dev/null +++ b/atom/browser/api/atom_api_download_item.cc @@ -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 + +#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 { + static v8::Local 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)>; +WrapDownloadItemCallback g_wrap_download_item; + +char kDownloadItemSavePathKey[] = "DownloadItemSavePathKey"; + +std::map>> 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::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(isolate, handle.ToV8())); + return handle; +} + +// static +void* DownloadItem::UserDataKey() { + return &kDownloadItemSavePathKey; +} + +} // namespace api + +} // namespace atom + +namespace { + +void Initialize(v8::Local exports, v8::Local unused, + v8::Local 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); diff --git a/atom/browser/api/atom_api_download_item.h b/atom/browser/api/atom_api_download_item.h new file mode 100644 index 00000000000..14074a4bed0 --- /dev/null +++ b/atom/browser/api/atom_api_download_item.h @@ -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 + +#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 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_ diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index f07ab8b7804..7d5f75cac09 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -8,6 +8,7 @@ #include #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 { } }; -template<> -struct Converter { - static v8::Local 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(); diff --git a/atom/browser/api/lib/app.coffee b/atom/browser/api/lib/app.coffee index f5b137eb0bb..18c80dc2b1f 100644 --- a/atom/browser/api/lib/app.coffee +++ b/atom/browser/api/lib/app.coffee @@ -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 diff --git a/atom/browser/atom_browser_context.cc b/atom/browser/atom_browser_context.cc index d1ef09e70ff..6823fbaee90 100644 --- a/atom/browser/atom_browser_context.cc +++ b/atom/browser/atom_browser_context.cc @@ -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()); diff --git a/atom/browser/atom_browser_context.h b/atom/browser/atom_browser_context.h index c99461ad9a8..839359c1ef5 100644 --- a/atom/browser/atom_browser_context.h +++ b/atom/browser/atom_browser_context.h @@ -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; diff --git a/atom/browser/atom_download_manager_delegate.cc b/atom/browser/atom_download_manager_delegate.cc index b573a396332..b6b65668255 100644 --- a/atom/browser/atom_download_manager_delegate.cc +++ b/atom/browser/atom_download_manager_delegate.cc @@ -6,6 +6,7 @@ #include +#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( + download_manager_->GetBrowserContext()); + browser_context->prefs()->SetFilePath(prefs::kDownloadDefaultDirectory, + path.DirName()); } - // Remeber the last selected download directory. - AtomBrowserContext* browser_context = static_cast( - 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(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( 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(), diff --git a/atom/browser/atom_ssl_config_service.cc b/atom/browser/atom_ssl_config_service.cc new file mode 100644 index 00000000000..f19dbacf7dd --- /dev/null +++ b/atom/browser/atom_ssl_config_service.cc @@ -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 + +#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 diff --git a/atom/browser/atom_ssl_config_service.h b/atom/browser/atom_ssl_config_service.h new file mode 100644 index 00000000000..3fa91c62c43 --- /dev/null +++ b/atom/browser/atom_ssl_config_service.h @@ -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_ diff --git a/atom/browser/default_app/main.js b/atom/browser/default_app/main.js index 4d854dc35cb..1b92685d13a 100644 --- a/atom/browser/default_app/main.js +++ b/atom/browser/default_app/main.js @@ -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); diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 4d5f273340a..c3620bba705 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -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& 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); } diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index e9a2b9433d1..5c8d8c73b0f 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -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_; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 9555914c899..f0a685e4d95 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -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 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() { diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 45697c96683..70707219f3f 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -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() { diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist index 6260173b825..eb39cb35f94 100644 --- a/atom/browser/resources/mac/Info.plist +++ b/atom/browser/resources/mac/Info.plist @@ -17,7 +17,7 @@ CFBundleIconFile atom.icns CFBundleVersion - 0.33.1 + 0.33.3 LSMinimumSystemVersion 10.8.0 NSMainNibFile diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc index 0583c2df3be..6fba6cf8067 100644 --- a/atom/browser/resources/win/atom.rc +++ b/atom/browser/resources/win/atom.rc @@ -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 diff --git a/atom/browser/ui/win/notify_icon.cc b/atom/browser/ui/win/notify_icon.cc index 4026d9ec4a6..c88d4c810ef 100644 --- a/atom/browser/ui/win/notify_icon.cc +++ b/atom/browser/ui/win/notify_icon.cc @@ -4,10 +4,7 @@ #include "atom/browser/ui/win/notify_icon.h" -#include - #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(&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(&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(&icon_data->guidItem), - &tray_app_id_hash_, - sizeof(GUID)); - } } } // namespace atom diff --git a/atom/browser/ui/win/notify_icon.h b/atom/browser/ui/win/notify_icon.h index 136186b689b..d368dec7132 100644 --- a/atom/browser/ui/win/notify_icon.h +++ b/atom/browser/ui/win/notify_icon.h @@ -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); }; diff --git a/atom/common/asar/archive.cc b/atom/common/asar/archive.cc index 0b2f59ae0f1..969f958956c 100644 --- a/atom/common/asar/archive.cc +++ b/atom/common/asar/archive.cc @@ -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(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(file_.GetPlatformFile()), 0); -#elif defined(OS_POSIX) - return file_.GetPlatformFile(); -#else - return -1; -#endif + return fd_; } } // namespace asar diff --git a/atom/common/asar/archive.h b/atom/common/asar/archive.h index dda7aa78e0c..f2ff2f76d67 100644 --- a/atom/common/asar/archive.h +++ b/atom/common/asar/archive.h @@ -69,6 +69,7 @@ class Archive { private: base::FilePath path_; base::File file_; + int fd_; uint32 header_size_; scoped_ptr header_; diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h index 5f9d0f3ca0b..4f240347540 100644 --- a/atom/common/atom_version.h +++ b/atom/common/atom_version.h @@ -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 diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index 5aec200550a..2da68854ad1 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -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); diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index c70e1ba4afa..46687becf84 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -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"; diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index e62f3116661..16046d19c82 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -59,6 +59,7 @@ extern const char kPageVisibility[]; extern const char kDisableHttpCache[]; extern const char kRegisterStandardSchemes[]; +extern const char kSSLVersionFallbackMin[]; extern const char kAppUserModelId[]; diff --git a/docs-translations/ko-KR/README.md b/docs-translations/ko-KR/README.md index 2fb242fae90..1e0ba63e7b6 100644 --- a/docs-translations/ko-KR/README.md +++ b/docs-translations/ko-KR/README.md @@ -26,7 +26,7 @@ * [`` 태그](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) diff --git a/docs-translations/ko-KR/api/chrome-command-line-switches.md b/docs-translations/ko-KR/api/chrome-command-line-switches.md index 5b9bf472204..2d9158fcc2f 100644 --- a/docs-translations/ko-KR/api/chrome-command-line-switches.md +++ b/docs-translations/ko-KR/api/chrome-command-line-switches.md @@ -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로 지정합니다. 모든 크로미움과 관련된 로그를 비활성화하고 어플리케이션의 로그만 활성화 하려면 다음과 같이 코드를 작성하면 됩니다: diff --git a/docs-translations/ko-KR/api/screen.md b/docs-translations/ko-KR/api/screen.md index 26975cbb1e2..5e0805749f3 100644 --- a/docs-translations/ko-KR/api/screen.md +++ b/docs-translations/ko-KR/api/screen.md @@ -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) { diff --git a/docs-translations/ko-KR/api/session.md b/docs-translations/ko-KR/api/session.md index cb912aabb10..4c6ead1647f 100644 --- a/docs-translations/ko-KR/api/session.md +++ b/docs-translations/ko-KR/api/session.md @@ -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); }); }); diff --git a/docs-translations/ko-KR/api/web-view-tag.md b/docs-translations/ko-KR/api/web-view-tag.md index b3f05de7f33..69b94465aed 100644 --- a/docs-translations/ko-KR/api/web-view-tag.md +++ b/docs-translations/ko-KR/api/web-view-tag.md @@ -135,6 +135,14 @@ 즉. 작동중인 랜더러 프로세스의 세션은 변경할 수 없습니다. 이후 이 값을 바꾸려고 시도하면 DOM 예외를 발생시킵니다. +### `allowpopups` + +```html + +``` + +"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`를 만들 때 사용되어야 하는 옵션. 페이지가 새로운 브라우저 창을 생성할 때 발생하는 이벤트입니다. diff --git a/docs-translations/ko-KR/api/window-open.md b/docs-translations/ko-KR/api/window-open.md index a4cf3bce5c9..828c46e679e 100644 --- a/docs-translations/ko-KR/api/window-open.md +++ b/docs-translations/ko-KR/api/window-open.md @@ -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 diff --git a/docs-translations/ko-KR/tutorial/quick-start.md b/docs-translations/ko-KR/tutorial/quick-start.md index 8c2e043061e..4a6ce6d2252 100644 --- a/docs-translations/ko-KR/tutorial/quick-start.md +++ b/docs-translations/ko-KR/tutorial/quick-start.md @@ -111,6 +111,7 @@ app.on('ready', function() { + 헬로 월드! diff --git a/docs-translations/ko-KR/tutorial/using-native-node-modules.md b/docs-translations/ko-KR/tutorial/using-native-node-modules.md index 913c300be88..ed64abb492f 100644 --- a/docs-translations/ko-KR/tutorial/using-native-node-modules.md +++ b/docs-translations/ko-KR/tutorial/using-native-node-modules.md @@ -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 -``` diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index f1705c29175..a1870bc66af 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -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 diff --git a/docs/api/chrome-command-line-switches.md b/docs/api/chrome-command-line-switches.md index 2f995c99b21..cd633fc0460 100644 --- a/docs/api/chrome-command-line-switches.md +++ b/docs/api/chrome-command-line-switches.md @@ -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 diff --git a/docs/api/download-item.md b/docs/api/download-item.md new file mode 100644 index 00000000000..53cd56cca9e --- /dev/null +++ b/docs/api/download-item.md @@ -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. diff --git a/docs/api/screen.md b/docs/api/screen.md index 934e3eaf5a7..da15c7326f1 100644 --- a/docs/api/screen.md +++ b/docs/api/screen.md @@ -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) { diff --git a/docs/api/session.md b/docs/api/session.md index 439cf8514e9..64991ab7530 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -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); }); }); diff --git a/docs/tutorial/quick-start.md b/docs/tutorial/quick-start.md index 93cd0ebc5bd..4ce65a1dc1a 100644 --- a/docs/tutorial/quick-start.md +++ b/docs/tutorial/quick-start.md @@ -124,6 +124,7 @@ Finally the `index.html` is the web page you want to show: + Hello World! diff --git a/docs/tutorial/using-native-node-modules.md b/docs/tutorial/using-native-node-modules.md index c338494cde2..0e6477fc4c0 100644 --- a/docs/tutorial/using-native-node-modules.md +++ b/docs/tutorial/using-native-node-modules.md @@ -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 -``` diff --git a/filenames.gypi b/filenames.gypi index 99d6bc6d50d..cb6a2273eae 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -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', diff --git a/package.json b/package.json index 101fdeee257..a125d13b68e 100644 --- a/package.json +++ b/package.json @@ -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": { diff --git a/script/lib/config.py b/script/lib/config.py index 0df68bd773b..68f216785d6 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -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', diff --git a/script/update-external-binaries.py b/script/update-external-binaries.py index 49e73435ab5..fae268ea8cb 100755 --- a/script/update-external-binaries.py +++ b/script/update-external-binaries.py @@ -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 diff --git a/spec/api-browser-window-spec.coffee b/spec/api-browser-window-spec.coffee index de713a6545c..2e4a66b92b9 100644 --- a/spec/api-browser-window-spec.coffee +++ b/spec/api-browser-window-spec.coffee @@ -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" diff --git a/spec/api-session-spec.coffee b/spec/api-session-spec.coffee index 34a08ee50f0..9e083d27c0f 100644 --- a/spec/api-session-spec.coffee +++ b/spec/api-session-spec.coffee @@ -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() diff --git a/spec/asar-spec.coffee b/spec/asar-spec.coffee index 4ef9337f3ab..1e6ee691036 100644 --- a/spec/asar-spec.coffee +++ b/spec/asar-spec.coffee @@ -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' diff --git a/spec/chromium-spec.coffee b/spec/chromium-spec.coffee index 4dd39aff5fd..a782079026a 100644 --- a/spec/chromium-spec.coffee +++ b/spec/chromium-spec.coffee @@ -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 diff --git a/spec/fixtures/pages/document-hidden.html b/spec/fixtures/pages/document-hidden.html new file mode 100644 index 00000000000..17920bff079 --- /dev/null +++ b/spec/fixtures/pages/document-hidden.html @@ -0,0 +1,7 @@ + + + + + diff --git a/spec/modules-spec.coffee b/spec/modules-spec.coffee index e7bdac36b3e..1cdc6cf0ea5 100644 --- a/spec/modules-spec.coffee +++ b/spec/modules-spec.coffee @@ -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' diff --git a/spec/node-spec.coffee b/spec/node-spec.coffee index c8d569e01ad..969fc76f41f 100644 --- a/spec/node-spec.coffee +++ b/spec/node-spec.coffee @@ -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 diff --git a/spec/package.json b/spec/package.json index a3b0d590eff..8f43b711f19 100644 --- a/spec/package.json +++ b/spec/package.json @@ -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", diff --git a/spec/static/main.js b/spec/static/main.js index 38ba7cc089d..5b10bb6d43d 100644 --- a/spec/static/main.js +++ b/spec/static/main.js @@ -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"; + }); }); diff --git a/vendor/brightray b/vendor/brightray index 25f3a9d0a5b..8e443520e69 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 25f3a9d0a5b73ec170a65f4e2e4c9ad91e23fc8c +Subproject commit 8e443520e695674fd26585cfa24a0ec0b6140c27 diff --git a/vendor/node b/vendor/node index fa54694af43..ac25693ad1d 160000 --- a/vendor/node +++ b/vendor/node @@ -1 +1 @@ -Subproject commit fa54694af4350bf1720ff47e97a07c7c09325ee2 +Subproject commit ac25693ad1d4c248e69a89147fd3995c3bf6c946