Browse Source

Merge pull request #13 from electron/master

update as upstream
Heilig Benedek 8 years ago
parent
commit
015516497c
100 changed files with 1255 additions and 593 deletions
  1. 1 1
      .node-version
  2. 1 0
      README-ko.md
  3. 2 0
      README.md
  4. 0 1
      atom/app/atom_main.cc
  5. 4 3
      atom/app/node_main.cc
  6. 1 1
      atom/app/uv_task_runner.cc
  7. 50 4
      atom/browser/api/atom_api_app.cc
  8. 2 0
      atom/browser/api/atom_api_app.h
  9. 1 0
      atom/browser/api/atom_api_auto_updater.cc
  10. 1 0
      atom/browser/api/atom_api_auto_updater.h
  11. 5 4
      atom/browser/api/atom_api_cookies.cc
  12. 4 6
      atom/browser/api/atom_api_cookies.h
  13. 11 6
      atom/browser/api/atom_api_menu.cc
  14. 7 5
      atom/browser/api/atom_api_menu.h
  15. 8 2
      atom/browser/api/atom_api_menu_mac.mm
  16. 6 2
      atom/browser/api/atom_api_menu_views.cc
  17. 1 1
      atom/browser/api/atom_api_menu_views.h
  18. 1 1
      atom/browser/api/atom_api_power_save_blocker.h
  19. 27 3
      atom/browser/api/atom_api_protocol.cc
  20. 1 0
      atom/browser/api/atom_api_protocol.h
  21. 16 14
      atom/browser/api/atom_api_screen.cc
  22. 14 13
      atom/browser/api/atom_api_screen.h
  23. 92 21
      atom/browser/api/atom_api_session.cc
  24. 16 11
      atom/browser/api/atom_api_session.h
  25. 4 0
      atom/browser/api/atom_api_system_preferences.cc
  26. 13 5
      atom/browser/api/atom_api_system_preferences.h
  27. 43 18
      atom/browser/api/atom_api_system_preferences_mac.mm
  28. 54 25
      atom/browser/api/atom_api_tray.cc
  29. 5 4
      atom/browser/api/atom_api_tray.h
  30. 136 55
      atom/browser/api/atom_api_web_contents.cc
  31. 15 9
      atom/browser/api/atom_api_web_contents.h
  32. 32 0
      atom/browser/api/atom_api_web_contents_mac.mm
  33. 16 28
      atom/browser/api/atom_api_window.cc
  34. 2 1
      atom/browser/api/atom_api_window.h
  35. 7 7
      atom/browser/api/event.cc
  36. 10 0
      atom/browser/api/event_emitter.cc
  37. 11 0
      atom/browser/api/event_emitter.h
  38. 10 6
      atom/browser/api/frame_subscriber.cc
  39. 4 3
      atom/browser/api/frame_subscriber.h
  40. 0 1
      atom/browser/api/trackable_object.h
  41. 22 8
      atom/browser/atom_access_token_store.cc
  42. 6 3
      atom/browser/atom_access_token_store.h
  43. 6 5
      atom/browser/atom_browser_client.cc
  44. 1 1
      atom/browser/atom_browser_client.h
  45. 45 31
      atom/browser/atom_browser_context.cc
  46. 15 5
      atom/browser/atom_browser_context.h
  47. 6 2
      atom/browser/atom_browser_main_parts.cc
  48. 5 5
      atom/browser/atom_browser_main_parts_posix.cc
  49. 8 0
      atom/browser/atom_download_manager_delegate.cc
  50. 8 1
      atom/browser/atom_resource_dispatcher_host_delegate.cc
  51. 8 2
      atom/browser/atom_security_state_model_client.cc
  52. 0 5
      atom/browser/atom_speech_recognition_manager_delegate.cc
  53. 0 2
      atom/browser/atom_speech_recognition_manager_delegate.h
  54. 4 0
      atom/browser/auto_updater.cc
  55. 1 0
      atom/browser/auto_updater.h
  56. 7 0
      atom/browser/auto_updater_mac.mm
  57. 10 0
      atom/browser/browser.cc
  58. 27 6
      atom/browser/browser.h
  59. 22 0
      atom/browser/browser_linux.cc
  60. 26 1
      atom/browser/browser_mac.mm
  61. 3 0
      atom/browser/browser_observer.h
  62. 37 1
      atom/browser/browser_win.cc
  63. 7 8
      atom/browser/common_web_contents_delegate.cc
  64. 7 1
      atom/browser/common_web_contents_delegate_mac.mm
  65. 9 0
      atom/browser/javascript_environment.cc
  66. 3 0
      atom/browser/javascript_environment.h
  67. 2 0
      atom/browser/mac/atom_application.mm
  68. 1 3
      atom/browser/mac/atom_application_delegate.h
  69. 7 9
      atom/browser/mac/atom_application_delegate.mm
  70. 2 2
      atom/browser/mac/dict_util.h
  71. 24 49
      atom/browser/native_window.cc
  72. 5 46
      atom/browser/native_window.h
  73. 1 1
      atom/browser/native_window_mac.h
  74. 53 34
      atom/browser/native_window_mac.mm
  75. 97 29
      atom/browser/native_window_views.cc
  76. 10 3
      atom/browser/native_window_views.h
  77. 9 4
      atom/browser/native_window_views_win.cc
  78. 1 1
      atom/browser/net/asar/asar_protocol_handler.cc
  79. 5 5
      atom/browser/net/asar/url_request_asar_job.cc
  80. 1 1
      atom/browser/net/asar/url_request_asar_job.h
  81. 2 9
      atom/browser/net/atom_cert_verifier.cc
  82. 1 3
      atom/browser/net/atom_cert_verifier.h
  83. 8 4
      atom/browser/net/atom_url_request_job_factory.cc
  84. 3 0
      atom/browser/net/atom_url_request_job_factory.h
  85. 1 1
      atom/browser/net/url_request_async_asar_job.cc
  86. 1 1
      atom/browser/net/url_request_buffer_job.cc
  87. 2 1
      atom/browser/net/url_request_fetch_job.cc
  88. 1 1
      atom/browser/net/url_request_string_job.cc
  89. 1 1
      atom/browser/node_debugger.h
  90. 10 0
      atom/browser/relauncher_linux.cc
  91. 10 2
      atom/browser/relauncher_mac.cc
  92. 2 2
      atom/browser/resources/mac/Info.plist
  93. BIN
      atom/browser/resources/win/atom.ico
  94. 4 4
      atom/browser/resources/win/atom.rc
  95. 8 8
      atom/browser/ui/accelerator_util.cc
  96. 4 6
      atom/browser/ui/accelerator_util.h
  97. 4 0
      atom/browser/ui/accelerator_util_mac.mm
  98. 21 3
      atom/browser/ui/atom_menu_model.cc
  99. 20 1
      atom/browser/ui/atom_menu_model.h
  100. 7 11
      atom/browser/ui/cocoa/atom_menu_controller.h

+ 1 - 1
.node-version

@@ -1 +1 @@
-v6.1.0
+v6.3.0

+ 1 - 0
README-ko.md

@@ -75,6 +75,7 @@ npm install electron-prebuilt --save-dev
 - [`electron-br`](https://electron-br.slack.com) *(브라질)* 커뮤니티
 - [`electron-kr`](http://www.meetup.com/electron-kr/) *(한국)* 커뮤니티
 - [`electron-jp`](https://electron-jp-slackin.herokuapp.com/) *(일본)* 커뮤니티
+- [`electron-tr`](http://www.meetup.com/Electron-JS-Istanbul/) *(터키)* 커뮤니티
 
 [awesome-electron](https://github.com/sindresorhus/awesome-electron) 프로젝트에
 커뮤니티가 운영중인 유용한 예시 애플리케이션과 도구, 리소스가 있으니 참고하기 바랍니다.

+ 2 - 0
README.md

@@ -72,6 +72,8 @@ forums
 - [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)*
 - [`electron-kr`](http://www.meetup.com/electron-kr/) *(Korean)*
 - [`electron-jp`](https://electron-jp-slackin.herokuapp.com/) *(Japanese)*
+- [`electron-tr`](http://www.meetup.com/Electron-JS-Istanbul/) *(Turkish)*
+- [`electron-id`](https://electron-id.slack.com) *(Indonesia)*
 
 Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron)
 for a community maintained list of useful example apps, tools and resources.

+ 0 - 1
atom/app/atom_main.cc

@@ -19,7 +19,6 @@
 #include "base/win/windows_version.h"
 #include "content/public/app/sandbox_helper_win.h"
 #include "sandbox/win/src/sandbox_types.h"
-#include "ui/gfx/win/dpi.h"
 #elif defined(OS_LINUX)  // defined(OS_WIN)
 #include "atom/app/atom_main_delegate.h"  // NOLINT
 #include "content/public/app/content_main.h"

+ 4 - 3
atom/app/node_main.cc

@@ -7,14 +7,15 @@
 #include "atom/app/uv_task_runner.h"
 #include "atom/browser/javascript_environment.h"
 #include "atom/browser/node_debugger.h"
-#include "atom/common/node_includes.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
-#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "gin/array_buffer.h"
 #include "gin/public/isolate_holder.h"
 #include "gin/v8_initializer.h"
 
+#include "atom/common/node_includes.h"
+
 namespace atom {
 
 int NodeMain(int argc, char *argv[]) {
@@ -69,7 +70,7 @@ int NodeMain(int argc, char *argv[]) {
     exit_code = node::EmitExit(env);
     node::RunAtExit(env);
 
-    env->Dispose();
+    node::FreeEnvironment(env);
   }
 
   v8::V8::Dispose();

+ 1 - 1
atom/app/uv_task_runner.cc

@@ -21,7 +21,7 @@ UvTaskRunner::~UvTaskRunner() {
 bool UvTaskRunner::PostDelayedTask(const tracked_objects::Location& from_here,
                                    const base::Closure& task,
                                    base::TimeDelta delay) {
-  uv_timer_t* timer = new uv_timer_t;
+  auto* timer = new uv_timer_t;
   timer->data = this;
   uv_timer_init(loop_, timer);
   uv_timer_start(timer, UvTaskRunner::OnTimeout, delay.InMilliseconds(), 0);

+ 50 - 4
atom/browser/api/atom_api_app.cc

@@ -32,6 +32,7 @@
 #include "base/strings/string_util.h"
 #include "brightray/browser/brightray_paths.h"
 #include "chrome/common/chrome_paths.h"
+#include "content/public/browser/browser_accessibility_state.h"
 #include "content/public/browser/client_certificate_delegate.h"
 #include "content/public/browser/gpu_data_manager.h"
 #include "content/public/browser/render_frame_host.h"
@@ -71,6 +72,30 @@ struct Converter<Browser::UserTask> {
 };
 #endif
 
+template<>
+struct Converter<Browser::LoginItemSettings> {
+  static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
+                     Browser::LoginItemSettings* out) {
+    mate::Dictionary dict;
+    if (!ConvertFromV8(isolate, val, &dict))
+      return false;
+
+    dict.Get("openAtLogin", &(out->open_at_login));
+    dict.Get("openAsHidden", &(out->open_as_hidden));
+    return true;
+  }
+
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                   Browser::LoginItemSettings val) {
+    mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
+    dict.Set("openAtLogin", val.open_at_login);
+    dict.Set("openAsHidden", val.open_as_hidden);
+    dict.Set("restoreState", val.restore_state);
+    dict.Set("wasOpenedAtLogin", val.opened_at_login);
+    dict.Set("wasOpenedAsHidden", val.opened_as_hidden);
+    return dict.GetHandle();
+  }
+};
 }  // namespace mate
 
 
@@ -254,6 +279,10 @@ void App::OnFinishLaunching() {
   Emit("ready");
 }
 
+void App::OnAccessibilitySupportChanged() {
+  Emit("accessibility-support-changed", IsAccessibilitySupportEnabled());
+}
+
 #if defined(OS_MACOSX)
 void App::OnContinueUserActivity(
     bool* prevent_default,
@@ -459,14 +488,20 @@ void App::DisableHardwareAcceleration(mate::Arguments* args) {
   content::GpuDataManager::GetInstance()->DisableHardwareAcceleration();
 }
 
+bool App::IsAccessibilitySupportEnabled() {
+  auto ax_state = content::BrowserAccessibilityState::GetInstance();
+  return ax_state->IsAccessibleBrowser();
+}
+
 #if defined(USE_NSS_CERTS)
 void App::ImportCertificate(
     const base::DictionaryValue& options,
     const net::CompletionCallback& callback) {
-  auto browser_context = AtomBrowserMainParts::Get()->browser_context();
+  auto browser_context = AtomBrowserContext::From("", false);
   if (!certificate_manager_model_) {
     std::unique_ptr<base::DictionaryValue> copy = options.CreateDeepCopy();
-    CertificateManagerModel::Create(browser_context,
+    CertificateManagerModel::Create(
+        browser_context.get(),
         base::Bind(&App::OnCertificateManagerModelCreated,
                    base::Unretained(this),
                    base::Passed(&copy),
@@ -519,6 +554,12 @@ void App::BuildPrototype(
                  base::Bind(&Browser::SetAsDefaultProtocolClient, browser))
       .SetMethod("removeAsDefaultProtocolClient",
                  base::Bind(&Browser::RemoveAsDefaultProtocolClient, browser))
+      .SetMethod("setBadgeCount", base::Bind(&Browser::SetBadgeCount, browser))
+      .SetMethod("getBadgeCount", base::Bind(&Browser::GetBadgeCount, browser))
+      .SetMethod("getLoginItemSettings",
+                 base::Bind(&Browser::GetLoginItemSettings, browser))
+      .SetMethod("setLoginItemSettings",
+                 base::Bind(&Browser::SetLoginItemSettings, browser))
 #if defined(OS_MACOSX)
       .SetMethod("hide", base::Bind(&Browser::Hide, browser))
       .SetMethod("show", base::Bind(&Browser::Show, browser))
@@ -528,8 +569,11 @@ void App::BuildPrototype(
                  base::Bind(&Browser::GetCurrentActivityType, browser))
 #endif
 #if defined(OS_WIN)
-      .SetMethod("setUserTasks",
-                 base::Bind(&Browser::SetUserTasks, browser))
+      .SetMethod("setUserTasks", base::Bind(&Browser::SetUserTasks, browser))
+#endif
+#if defined(OS_LINUX)
+      .SetMethod("isUnityRunning",
+                 base::Bind(&Browser::IsUnityRunning, browser))
 #endif
       .SetMethod("setPath", &App::SetPath)
       .SetMethod("getPath", &App::GetPath)
@@ -541,6 +585,8 @@ void App::BuildPrototype(
       .SetMethod("makeSingleInstance", &App::MakeSingleInstance)
       .SetMethod("releaseSingleInstance", &App::ReleaseSingleInstance)
       .SetMethod("relaunch", &App::Relaunch)
+      .SetMethod("isAccessibilitySupportEnabled",
+                 &App::IsAccessibilitySupportEnabled)
       .SetMethod("disableHardwareAcceleration",
                  &App::DisableHardwareAcceleration);
 }

+ 2 - 0
atom/browser/api/atom_api_app.h

@@ -72,6 +72,7 @@ class App : public AtomBrowserClient::Delegate,
   void OnFinishLaunching() override;
   void OnLogin(LoginHandler* login_handler,
                const base::DictionaryValue& request_details) override;
+  void OnAccessibilitySupportChanged() override;
 #if defined(OS_MACOSX)
   void OnContinueUserActivity(
       bool* prevent_default,
@@ -113,6 +114,7 @@ class App : public AtomBrowserClient::Delegate,
   void ReleaseSingleInstance();
   bool Relaunch(mate::Arguments* args);
   void DisableHardwareAcceleration(mate::Arguments* args);
+  bool IsAccessibilitySupportEnabled();
 #if defined(USE_NSS_CERTS)
   void ImportCertificate(const base::DictionaryValue& options,
                          const net::CompletionCallback& callback);

+ 1 - 0
atom/browser/api/atom_api_auto_updater.cc

@@ -109,6 +109,7 @@ void AutoUpdater::BuildPrototype(
     v8::Isolate* isolate, v8::Local<v8::ObjectTemplate> prototype) {
   mate::ObjectTemplateBuilder(isolate, prototype)
       .SetMethod("checkForUpdates", &auto_updater::AutoUpdater::CheckForUpdates)
+      .SetMethod("getFeedURL", &auto_updater::AutoUpdater::GetFeedURL)
       .SetMethod("setFeedURL", &AutoUpdater::SetFeedURL)
       .SetMethod("quitAndInstall", &AutoUpdater::QuitAndInstall);
 }

+ 1 - 0
atom/browser/api/atom_api_auto_updater.h

@@ -44,6 +44,7 @@ class AutoUpdater : public mate::EventEmitter<AutoUpdater>,
   void OnWindowAllClosed() override;
 
  private:
+  std::string GetFeedURL();
   void SetFeedURL(const std::string& url, mate::Arguments* args);
   void QuitAndInstall();
 

+ 5 - 4
atom/browser/api/atom_api_cookies.cc

@@ -4,6 +4,7 @@
 
 #include "atom/browser/api/atom_api_cookies.h"
 
+#include "atom/browser/atom_browser_context.h"
 #include "atom/common/native_mate_converters/callback.h"
 #include "atom/common/native_mate_converters/gurl_converter.h"
 #include "atom/common/native_mate_converters/value_converter.h"
@@ -30,7 +31,7 @@ struct Converter<atom::api::Cookies::Error> {
     if (val == atom::api::Cookies::SUCCESS)
       return v8::Null(isolate);
     else
-      return v8::Exception::Error(StringToV8(isolate, "failed"));
+      return v8::Exception::Error(StringToV8(isolate, "Setting cookie failed"));
   }
 };
 
@@ -204,8 +205,8 @@ void SetCookieOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
 }  // namespace
 
 Cookies::Cookies(v8::Isolate* isolate,
-                 content::BrowserContext* browser_context)
-      : request_context_getter_(browser_context->GetRequestContext()) {
+                 AtomBrowserContext* browser_context)
+      : request_context_getter_(browser_context->url_request_context_getter()) {
   Init(isolate);
 }
 
@@ -241,7 +242,7 @@ void Cookies::Set(const base::DictionaryValue& details,
 // static
 mate::Handle<Cookies> Cookies::Create(
     v8::Isolate* isolate,
-    content::BrowserContext* browser_context) {
+    AtomBrowserContext* browser_context) {
   return mate::CreateHandle(isolate, new Cookies(isolate, browser_context));
 }
 

+ 4 - 6
atom/browser/api/atom_api_cookies.h

@@ -16,16 +16,14 @@ namespace base {
 class DictionaryValue;
 }
 
-namespace content {
-class BrowserContext;
-}
-
 namespace net {
 class URLRequestContextGetter;
 }
 
 namespace atom {
 
+class AtomBrowserContext;
+
 namespace api {
 
 class Cookies : public mate::TrackableObject<Cookies> {
@@ -39,14 +37,14 @@ class Cookies : public mate::TrackableObject<Cookies> {
   using SetCallback = base::Callback<void(Error)>;
 
   static mate::Handle<Cookies> Create(v8::Isolate* isolate,
-                                      content::BrowserContext* browser_context);
+                                      AtomBrowserContext* browser_context);
 
   // mate::TrackableObject:
   static void BuildPrototype(v8::Isolate* isolate,
                              v8::Local<v8::ObjectTemplate> prototype);
 
  protected:
-  Cookies(v8::Isolate* isolate, content::BrowserContext* browser_context);
+  Cookies(v8::Isolate* isolate, AtomBrowserContext* browser_context);
   ~Cookies() override;
 
   void Get(const base::DictionaryValue& filter, const GetCallback& callback);

+ 11 - 6
atom/browser/api/atom_api_menu.cc

@@ -21,7 +21,7 @@ namespace api {
 
 Menu::Menu(v8::Isolate* isolate)
     : model_(new AtomMenuModel(this)),
-      parent_(NULL) {
+      parent_(nullptr) {
 }
 
 Menu::~Menu() {
@@ -53,16 +53,21 @@ bool Menu::IsCommandIdVisible(int command_id) const {
   return is_visible_.Run(command_id);
 }
 
-bool Menu::GetAcceleratorForCommandId(int command_id,
-                                      ui::Accelerator* accelerator) {
+bool Menu::GetAcceleratorForCommandIdWithParams(
+    int command_id,
+    bool use_default_accelerator,
+    ui::Accelerator* accelerator) const {
   v8::Locker locker(isolate());
   v8::HandleScope handle_scope(isolate());
-  v8::Local<v8::Value> val = get_accelerator_.Run(command_id);
+  v8::Local<v8::Value> val = get_accelerator_.Run(
+      command_id, use_default_accelerator);
   return mate::ConvertFromV8(isolate(), val, accelerator);
 }
 
-void Menu::ExecuteCommand(int command_id, int event_flags) {
-  execute_command_.Run(command_id);
+void Menu::ExecuteCommand(int command_id, int flags) {
+  execute_command_.Run(
+      mate::internal::CreateEventFromFlags(isolate(), flags),
+      command_id);
 }
 
 void Menu::MenuWillShow(ui::SimpleMenuModel* source) {

+ 7 - 5
atom/browser/api/atom_api_menu.h

@@ -5,13 +5,13 @@
 #ifndef ATOM_BROWSER_API_ATOM_API_MENU_H_
 #define ATOM_BROWSER_API_ATOM_API_MENU_H_
 
+#include <memory>
 #include <string>
 
 #include "atom/browser/api/atom_api_window.h"
 #include "atom/browser/api/trackable_object.h"
 #include "atom/browser/ui/atom_menu_model.h"
 #include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
 
 namespace atom {
 
@@ -46,8 +46,10 @@ class Menu : public mate::TrackableObject<Menu>,
   bool IsCommandIdChecked(int command_id) const override;
   bool IsCommandIdEnabled(int command_id) const override;
   bool IsCommandIdVisible(int command_id) const override;
-  bool GetAcceleratorForCommandId(int command_id,
-                                  ui::Accelerator* accelerator) override;
+  bool GetAcceleratorForCommandIdWithParams(
+      int command_id,
+      bool use_default_accelerator,
+      ui::Accelerator* accelerator) const override;
   void ExecuteCommand(int command_id, int event_flags) override;
   void MenuWillShow(ui::SimpleMenuModel* source) override;
 
@@ -89,8 +91,8 @@ class Menu : public mate::TrackableObject<Menu>,
   base::Callback<bool(int)> is_checked_;
   base::Callback<bool(int)> is_enabled_;
   base::Callback<bool(int)> is_visible_;
-  base::Callback<v8::Local<v8::Value>(int)> get_accelerator_;
-  base::Callback<void(int)> execute_command_;
+  base::Callback<v8::Local<v8::Value>(int, bool)> get_accelerator_;
+  base::Callback<void(v8::Local<v8::Value>, int)> execute_command_;
   base::Callback<void()> menu_will_show_;
 
   DISALLOW_COPY_AND_ASSIGN(Menu);

+ 8 - 2
atom/browser/api/atom_api_menu_mac.mm

@@ -5,6 +5,7 @@
 #import "atom/browser/api/atom_api_menu_mac.h"
 
 #include "atom/browser/native_window.h"
+#include "atom/browser/unresponsive_suppressor.h"
 #include "base/message_loop/message_loop.h"
 #include "base/strings/sys_string_conversions.h"
 #include "brightray/browser/inspectable_web_contents.h"
@@ -30,7 +31,8 @@ void MenuMac::PopupAt(Window* window, int x, int y, int positioning_item) {
     return;
 
   base::scoped_nsobject<AtomMenuController> menu_controller(
-      [[AtomMenuController alloc] initWithModel:model_.get()]);
+      [[AtomMenuController alloc] initWithModel:model_.get()
+                          useDefaultAccelerator:NO]);
   NSMenu* menu = [menu_controller menu];
   NSView* view = web_contents->GetView()->GetNativeView();
 
@@ -66,6 +68,9 @@ void MenuMac::PopupAt(Window* window, int x, int y, int positioning_item) {
   if (rightmostMenuPoint > screenRight)
     position.x = position.x - [menu size].width;
 
+  // Don't emit unresponsive event when showing menu.
+  atom::UnresponsiveSuppressor suppressor;
+
   // Show the menu.
   [menu popUpMenuPositioningItem:item atLocation:position inView:view];
 }
@@ -74,7 +79,8 @@ void MenuMac::PopupAt(Window* window, int x, int y, int positioning_item) {
 void Menu::SetApplicationMenu(Menu* base_menu) {
   MenuMac* menu = static_cast<MenuMac*>(base_menu);
   base::scoped_nsobject<AtomMenuController> menu_controller(
-      [[AtomMenuController alloc] initWithModel:menu->model_.get()]);
+      [[AtomMenuController alloc] initWithModel:menu->model_.get()
+                          useDefaultAccelerator:YES]);
   [NSApp setMainMenu:[menu_controller menu]];
 
   // Ensure the menu_controller_ is destroyed after main menu is set.

+ 6 - 2
atom/browser/api/atom_api_menu_views.cc

@@ -5,8 +5,9 @@
 #include "atom/browser/api/atom_api_menu_views.h"
 
 #include "atom/browser/native_window_views.h"
+#include "atom/browser/unresponsive_suppressor.h"
 #include "content/public/browser/render_widget_host_view.h"
-#include "ui/gfx/screen.h"
+#include "ui/display/screen.h"
 #include "ui/views/controls/menu/menu_runner.h"
 
 namespace atom {
@@ -30,12 +31,15 @@ void MenuViews::PopupAt(Window* window, int x, int y, int positioning_item) {
   // (-1, -1) means showing on mouse location.
   gfx::Point location;
   if (x == -1 || y == -1) {
-    location = gfx::Screen::GetScreen()->GetCursorScreenPoint();
+    location = display::Screen::GetScreen()->GetCursorScreenPoint();
   } else {
     gfx::Point origin = view->GetViewBounds().origin();
     location = gfx::Point(origin.x() + x, origin.y() + y);
   }
 
+  // Don't emit unresponsive event when showing menu.
+  atom::UnresponsiveSuppressor suppressor;
+
   // Show the menu.
   views::MenuRunner menu_runner(
       model(),

+ 1 - 1
atom/browser/api/atom_api_menu_views.h

@@ -6,7 +6,7 @@
 #define ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_
 
 #include "atom/browser/api/atom_api_menu.h"
-#include "ui/gfx/screen.h"
+#include "ui/display/screen.h"
 
 namespace atom {
 

+ 1 - 1
atom/browser/api/atom_api_power_save_blocker.h

@@ -6,9 +6,9 @@
 #define ATOM_BROWSER_API_ATOM_API_POWER_SAVE_BLOCKER_H_
 
 #include <map>
+#include <memory>
 
 #include "atom/browser/api/trackable_object.h"
-#include "base/memory/scoped_ptr.h"
 #include "content/public/browser/power_save_blocker.h"
 #include "native_mate/handle.h"
 

+ 27 - 3
atom/browser/api/atom_api_protocol.cc

@@ -6,6 +6,7 @@
 
 #include "atom/browser/atom_browser_client.h"
 #include "atom/browser/atom_browser_main_parts.h"
+#include "atom/browser/browser.h"
 #include "atom/browser/net/url_request_async_asar_job.h"
 #include "atom/browser/net/url_request_buffer_job.h"
 #include "atom/browser/net/url_request_fetch_job.h"
@@ -26,13 +27,30 @@ namespace atom {
 
 namespace api {
 
+namespace {
+
+// Clear protocol handlers in IO thread.
+void ClearJobFactoryInIO(
+    scoped_refptr<brightray::URLRequestContextGetter> request_context_getter) {
+  auto job_factory = static_cast<AtomURLRequestJobFactory*>(
+      request_context_getter->job_factory());
+  job_factory->Clear();
+}
+
+}  // namespace
+
 Protocol::Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context)
-    : request_context_getter_(static_cast<brightray::URLRequestContextGetter*>(
-          browser_context->GetRequestContext())),
+    : request_context_getter_(browser_context->GetRequestContext()),
       weak_factory_(this) {
   Init(isolate);
 }
 
+Protocol::~Protocol() {
+  content::BrowserThread::PostTask(
+      content::BrowserThread::IO, FROM_HERE,
+      base::Bind(ClearJobFactoryInIO, request_context_getter_));
+}
+
 void Protocol::RegisterServiceWorkerSchemes(
     const std::vector<std::string>& schemes) {
   atom::AtomBrowserClient::SetCustomServiceWorkerSchemes(schemes);
@@ -174,7 +192,13 @@ void Protocol::BuildPrototype(
 namespace {
 
 void RegisterStandardSchemes(
-    const std::vector<std::string>& schemes) {
+    const std::vector<std::string>& schemes, mate::Arguments* args) {
+  if (atom::Browser::Get()->is_ready()) {
+    args->ThrowError("protocol.registerStandardSchemes should be called before "
+                     "app is ready");
+    return;
+  }
+
   auto policy = content::ChildProcessSecurityPolicy::GetInstance();
   for (const auto& scheme : schemes) {
     url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT);

+ 1 - 0
atom/browser/api/atom_api_protocol.h

@@ -43,6 +43,7 @@ class Protocol : public mate::TrackableObject<Protocol> {
 
  protected:
   Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context);
+  ~Protocol();
 
  private:
   // Possible errors.

+ 16 - 14
atom/browser/api/atom_api_screen.cc

@@ -12,7 +12,9 @@
 #include "base/bind.h"
 #include "native_mate/dictionary.h"
 #include "native_mate/object_template_builder.h"
-#include "ui/gfx/screen.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/gfx/geometry/point.h"
 
 #include "atom/common/node_includes.h"
 
@@ -34,20 +36,20 @@ typename T::iterator FindById(T* container, int id) {
 // Convert the changed_metrics bitmask to string array.
 std::vector<std::string> MetricsToArray(uint32_t metrics) {
   std::vector<std::string> array;
-  if (metrics & gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS)
+  if (metrics & display::DisplayObserver::DISPLAY_METRIC_BOUNDS)
     array.push_back("bounds");
-  if (metrics & gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA)
+  if (metrics & display::DisplayObserver::DISPLAY_METRIC_WORK_AREA)
     array.push_back("workArea");
-  if (metrics & gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR)
+  if (metrics & display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR)
     array.push_back("scaleFactor");
-  if (metrics & gfx::DisplayObserver::DISPLAY_METRIC_ROTATION)
+  if (metrics & display::DisplayObserver::DISPLAY_METRIC_ROTATION)
     array.push_back("rotation");
   return array;
 }
 
 }  // namespace
 
-Screen::Screen(v8::Isolate* isolate, gfx::Screen* screen)
+Screen::Screen(v8::Isolate* isolate, display::Screen* screen)
     : screen_(screen) {
   screen_->AddObserver(this);
   Init(isolate);
@@ -61,31 +63,31 @@ gfx::Point Screen::GetCursorScreenPoint() {
   return screen_->GetCursorScreenPoint();
 }
 
-gfx::Display Screen::GetPrimaryDisplay() {
+display::Display Screen::GetPrimaryDisplay() {
   return screen_->GetPrimaryDisplay();
 }
 
-std::vector<gfx::Display> Screen::GetAllDisplays() {
+std::vector<display::Display> Screen::GetAllDisplays() {
   return screen_->GetAllDisplays();
 }
 
-gfx::Display Screen::GetDisplayNearestPoint(const gfx::Point& point) {
+display::Display Screen::GetDisplayNearestPoint(const gfx::Point& point) {
   return screen_->GetDisplayNearestPoint(point);
 }
 
-gfx::Display Screen::GetDisplayMatching(const gfx::Rect& match_rect) {
+display::Display Screen::GetDisplayMatching(const gfx::Rect& match_rect) {
   return screen_->GetDisplayMatching(match_rect);
 }
 
-void Screen::OnDisplayAdded(const gfx::Display& new_display) {
+void Screen::OnDisplayAdded(const display::Display& new_display) {
   Emit("display-added", new_display);
 }
 
-void Screen::OnDisplayRemoved(const gfx::Display& old_display) {
+void Screen::OnDisplayRemoved(const display::Display& old_display) {
   Emit("display-removed", old_display);
 }
 
-void Screen::OnDisplayMetricsChanged(const gfx::Display& display,
+void Screen::OnDisplayMetricsChanged(const display::Display& display,
                                      uint32_t changed_metrics) {
   Emit("display-metrics-changed", display, MetricsToArray(changed_metrics));
 }
@@ -99,7 +101,7 @@ v8::Local<v8::Value> Screen::Create(v8::Isolate* isolate) {
     return v8::Null(isolate);
   }
 
-  gfx::Screen* screen = gfx::Screen::GetScreen();
+  display::Screen* screen = display::Screen::GetScreen();
   if (!screen) {
     isolate->ThrowException(v8::Exception::Error(mate::StringToV8(
         isolate, "Failed to get screen information")));

+ 14 - 13
atom/browser/api/atom_api_screen.h

@@ -9,7 +9,8 @@
 
 #include "atom/browser/api/event_emitter.h"
 #include "native_mate/handle.h"
-#include "ui/gfx/display_observer.h"
+#include "ui/display/display_observer.h"
+#include "ui/display/screen.h"
 
 namespace gfx {
 class Point;
@@ -22,7 +23,7 @@ namespace atom {
 namespace api {
 
 class Screen : public mate::EventEmitter<Screen>,
-               public gfx::DisplayObserver {
+               public display::DisplayObserver {
  public:
   static v8::Local<v8::Value> Create(v8::Isolate* isolate);
 
@@ -30,23 +31,23 @@ class Screen : public mate::EventEmitter<Screen>,
                              v8::Local<v8::ObjectTemplate> prototype);
 
  protected:
-  Screen(v8::Isolate* isolate, gfx::Screen* screen);
+  Screen(v8::Isolate* isolate, display::Screen* screen);
   ~Screen() override;
 
   gfx::Point GetCursorScreenPoint();
-  gfx::Display GetPrimaryDisplay();
-  std::vector<gfx::Display> GetAllDisplays();
-  gfx::Display GetDisplayNearestPoint(const gfx::Point& point);
-  gfx::Display GetDisplayMatching(const gfx::Rect& match_rect);
-
-  // gfx::DisplayObserver:
-  void OnDisplayAdded(const gfx::Display& new_display) override;
-  void OnDisplayRemoved(const gfx::Display& old_display) override;
-  void OnDisplayMetricsChanged(const gfx::Display& display,
+  display::Display GetPrimaryDisplay();
+  std::vector<display::Display> GetAllDisplays();
+  display::Display GetDisplayNearestPoint(const gfx::Point& point);
+  display::Display GetDisplayMatching(const gfx::Rect& match_rect);
+
+  // display::DisplayObserver:
+  void OnDisplayAdded(const display::Display& new_display) override;
+  void OnDisplayRemoved(const display::Display& old_display) override;
+  void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t changed_metrics) override;
 
  private:
-  gfx::Screen* screen_;
+  display::Screen* screen_;
 
   DISALLOW_COPY_AND_ASSIGN(Screen);
 };

+ 92 - 21
atom/browser/api/atom_api_session.cc

@@ -11,6 +11,7 @@
 #include "atom/browser/api/atom_api_download_item.h"
 #include "atom/browser/api/atom_api_protocol.h"
 #include "atom/browser/api/atom_api_web_request.h"
+#include "atom/browser/browser.h"
 #include "atom/browser/atom_browser_context.h"
 #include "atom/browser/atom_browser_main_parts.h"
 #include "atom/browser/atom_permission_manager.h"
@@ -20,13 +21,14 @@
 #include "atom/common/native_mate_converters/gurl_converter.h"
 #include "atom/common/native_mate_converters/file_path_converter.h"
 #include "atom/common/native_mate_converters/net_converter.h"
+#include "atom/common/native_mate_converters/value_converter.h"
 #include "atom/common/node_includes.h"
 #include "base/files/file_path.h"
 #include "base/guid.h"
 #include "components/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
-#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "brightray/browser/net/devtools_network_conditions.h"
 #include "brightray/browser/net/devtools_network_controller_handle.h"
 #include "chrome/common/pref_names.h"
@@ -41,8 +43,10 @@
 #include "net/http/http_auth_preferences.h"
 #include "net/proxy/proxy_service.h"
 #include "net/proxy/proxy_config_service_fixed.h"
+#include "net/url_request/static_http_user_agent_settings.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "ui/base/l10n/l10n_util.h"
 
 using content::BrowserThread;
 using content::StoragePartition;
@@ -93,6 +97,15 @@ uint32_t GetQuotaMask(const std::vector<std::string>& quota_types) {
   return quota_mask;
 }
 
+void SetUserAgentInIO(scoped_refptr<net::URLRequestContextGetter> getter,
+                      const std::string& accept_lang,
+                      const std::string& user_agent) {
+  getter->GetURLRequestContext()->set_http_user_agent_settings(
+      new net::StaticHttpUserAgentSettings(
+          net::HttpUtil::GenerateAcceptLanguageHeader(accept_lang),
+          user_agent));
+}
+
 }  // namespace
 
 namespace mate {
@@ -120,7 +133,7 @@ struct Converter<net::ProxyConfig> {
   static bool FromV8(v8::Isolate* isolate,
                      v8::Local<v8::Value> val,
                      net::ProxyConfig* out) {
-    std::string proxy_rules;
+    std::string proxy_rules, proxy_bypass_rules;
     GURL pac_url;
     mate::Dictionary options;
     // Fallback to previous API when passed String.
@@ -130,6 +143,7 @@ struct Converter<net::ProxyConfig> {
     } else if (ConvertFromV8(isolate, val, &options)) {
       options.Get("pacScript", &pac_url);
       options.Get("proxyRules", &proxy_rules);
+      options.Get("proxyBypassRules", &proxy_bypass_rules);
     } else {
       return false;
     }
@@ -139,6 +153,7 @@ struct Converter<net::ProxyConfig> {
       out->set_pac_url(pac_url);
     } else {
       out->proxy_rules().ParseFromString(proxy_rules);
+      out->proxy_rules().bypass_rules.ParseFromString(proxy_bypass_rules);
     }
     return true;
   }
@@ -152,6 +167,8 @@ namespace api {
 
 namespace {
 
+const char kPersistPrefix[] = "persist:";
+
 // The wrapSession funtion which is implemented in JavaScript
 using WrapSessionCallback = base::Callback<void(v8::Local<v8::Value>)>;
 WrapSessionCallback g_wrap_session;
@@ -164,7 +181,7 @@ class ResolveProxyHelper {
       : callback_(callback),
         original_thread_(base::ThreadTaskRunnerHandle::Get()) {
     scoped_refptr<net::URLRequestContextGetter> context_getter =
-        browser_context->GetRequestContext();
+        browser_context->url_request_context_getter();
     context_getter->GetNetworkTaskRunner()->PostTask(
         FROM_HERE,
         base::Bind(&ResolveProxyHelper::ResolveProxy,
@@ -230,10 +247,10 @@ void OnGetBackend(disk_cache::Backend** backend_ptr,
     } else if (action == Session::CacheAction::STATS) {
       base::StringPairs stats;
       (*backend_ptr)->GetStats(&stats);
-      for (size_t i = 0; i < stats.size(); ++i) {
-        if (stats[i].first == "Current size") {
+      for (const auto& stat : stats) {
+        if (stat.first == "Current size") {
           int current_size;
-          base::StringToInt(stats[i].second, &current_size);
+          base::StringToInt(stat.second, &current_size);
           RunCallbackInUI(callback, current_size);
           break;
         }
@@ -255,7 +272,7 @@ void DoCacheActionInIO(
 
   // Call GetBackend and make the backend's ptr accessable in OnGetBackend.
   using BackendPtr = disk_cache::Backend*;
-  BackendPtr* backend_ptr = new BackendPtr(nullptr);
+  auto* backend_ptr = new BackendPtr(nullptr);
   net::CompletionCallback on_get_backend =
       base::Bind(&OnGetBackend, base::Owned(backend_ptr), action, callback);
   int rv = http_cache->GetBackend(backend_ptr, on_get_backend);
@@ -267,13 +284,21 @@ void SetProxyInIO(net::URLRequestContextGetter* getter,
                   const net::ProxyConfig& config,
                   const base::Closure& callback) {
   auto proxy_service = getter->GetURLRequestContext()->proxy_service();
-  proxy_service->ResetConfigService(make_scoped_ptr(
+  proxy_service->ResetConfigService(base::WrapUnique(
       new net::ProxyConfigServiceFixed(config)));
   // Refetches and applies the new pac script if provided.
   proxy_service->ForceReloadProxyConfig();
   RunCallbackInUI(callback);
 }
 
+void SetCertVerifyProcInIO(
+    const scoped_refptr<net::URLRequestContextGetter>& context_getter,
+    const AtomCertVerifier::VerifyProc& proc) {
+  auto request_context = context_getter->GetURLRequestContext();
+  static_cast<AtomCertVerifier*>(request_context->cert_verifier())->
+      SetVerifyProc(proc);
+}
+
 void ClearHostResolverCacheInIO(
     const scoped_refptr<net::URLRequestContextGetter>& context_getter,
     const base::Closure& callback) {
@@ -300,6 +325,11 @@ void AllowNTLMCredentialsForDomainsInIO(
   }
 }
 
+void OnClearStorageDataDone(const base::Closure& callback) {
+  if (!callback.is_null())
+    callback.Run();
+}
+
 }  // namespace
 
 Session::Session(v8::Isolate* isolate, AtomBrowserContext* browser_context)
@@ -349,21 +379,19 @@ void Session::DoCacheAction(const net::CompletionCallback& callback) {
 }
 
 void Session::ClearStorageData(mate::Arguments* args) {
-  // clearStorageData([options, ]callback)
+  // clearStorageData([options, callback])
   ClearStorageDataOptions options;
-  args->GetNext(&options);
   base::Closure callback;
-  if (!args->GetNext(&callback)) {
-    args->ThrowError();
-    return;
-  }
+  args->GetNext(&options);
+  args->GetNext(&callback);
 
   auto storage_partition =
       content::BrowserContext::GetStoragePartition(browser_context(), nullptr);
   storage_partition->ClearData(
       options.storage_types, options.quota_types, options.origin,
       content::StoragePartition::OriginMatcherFunction(),
-      base::Time(), base::Time::Max(), callback);
+      base::Time(), base::Time::Max(),
+      base::Bind(&OnClearStorageDataDone, callback));
 }
 
 void Session::FlushStorageData() {
@@ -423,7 +451,10 @@ void Session::SetCertVerifyProc(v8::Local<v8::Value> val,
     return;
   }
 
-  browser_context_->cert_verifier()->SetVerifyProc(proc);
+  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+      base::Bind(&SetCertVerifyProcInIO,
+                 make_scoped_refptr(browser_context_->GetRequestContext()),
+                 proc));
 }
 
 void Session::SetPermissionRequestHandler(v8::Local<v8::Value> val,
@@ -455,6 +486,23 @@ void Session::AllowNTLMCredentialsForDomains(const std::string& domains) {
                  domains));
 }
 
+void Session::SetUserAgent(const std::string& user_agent,
+                           mate::Arguments* args) {
+  browser_context_->SetUserAgent(user_agent);
+
+  std::string accept_lang = l10n_util::GetApplicationLocale("");
+  args->GetNext(&accept_lang);
+
+  auto getter = browser_context_->GetRequestContext();
+  getter->GetNetworkTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&SetUserAgentInIO, getter, accept_lang, user_agent));
+}
+
+std::string Session::GetUserAgent() {
+  return browser_context_->GetUserAgent();
+}
+
 v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
   if (cookies_.IsEmpty()) {
     auto handle = atom::api::Cookies::Create(isolate, browser_context());
@@ -494,10 +542,19 @@ mate::Handle<Session> Session::CreateFrom(
 
 // static
 mate::Handle<Session> Session::FromPartition(
-    v8::Isolate* isolate, const std::string& partition, bool in_memory) {
-  auto browser_context = brightray::BrowserContext::From(partition, in_memory);
-  return CreateFrom(isolate,
-                    static_cast<AtomBrowserContext*>(browser_context.get()));
+    v8::Isolate* isolate, const std::string& partition,
+    const base::DictionaryValue& options) {
+  scoped_refptr<AtomBrowserContext> browser_context;
+  if (partition.empty()) {
+    browser_context = AtomBrowserContext::From("", false, options);
+  } else if (base::StartsWith(partition, kPersistPrefix,
+                              base::CompareCase::SENSITIVE)) {
+    std::string name = partition.substr(8);
+    browser_context = AtomBrowserContext::From(name, false, options);
+  } else {
+    browser_context = AtomBrowserContext::From(partition, true, options);
+  }
+  return CreateFrom(isolate, browser_context.get());
 }
 
 // static
@@ -520,6 +577,8 @@ void Session::BuildPrototype(v8::Isolate* isolate,
       .SetMethod("clearHostResolverCache", &Session::ClearHostResolverCache)
       .SetMethod("allowNTLMCredentialsForDomains",
                  &Session::AllowNTLMCredentialsForDomains)
+      .SetMethod("setUserAgent", &Session::SetUserAgent)
+      .SetMethod("getUserAgent", &Session::GetUserAgent)
       .SetProperty("cookies", &Session::Cookies)
       .SetProperty("protocol", &Session::Protocol)
       .SetProperty("webRequest", &Session::WebRequest);
@@ -535,11 +594,23 @@ void SetWrapSession(const WrapSessionCallback& callback) {
 
 namespace {
 
+v8::Local<v8::Value> FromPartition(
+    const std::string& partition, mate::Arguments* args) {
+  if (!atom::Browser::Get()->is_ready()) {
+    args->ThrowError("Session can only be received when app is ready");
+    return v8::Null(args->isolate());
+  }
+  base::DictionaryValue options;
+  args->GetNext(&options);
+  return atom::api::Session::FromPartition(
+      args->isolate(), partition, options).ToV8();
+}
+
 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("fromPartition", &atom::api::Session::FromPartition);
+  dict.SetMethod("fromPartition", &FromPartition);
   dict.SetMethod("_setWrapSession", &atom::api::SetWrapSession);
 }
 

+ 16 - 11
atom/browser/api/atom_api_session.h

@@ -8,6 +8,7 @@
 #include <string>
 
 #include "atom/browser/api/trackable_object.h"
+#include "base/values.h"
 #include "content/public/browser/download_manager.h"
 #include "native_mate/handle.h"
 #include "net/base/completion_callback.h"
@@ -47,9 +48,10 @@ class Session: public mate::TrackableObject<Session>,
   static mate::Handle<Session> CreateFrom(
       v8::Isolate* isolate, AtomBrowserContext* browser_context);
 
-  // Gets the Session of |partition| and |in_memory|.
+  // Gets the Session of |partition|.
   static mate::Handle<Session> FromPartition(
-      v8::Isolate* isolate, const std::string& partition, bool in_memory);
+      v8::Isolate* isolate, const std::string& partition,
+      const base::DictionaryValue& options = base::DictionaryValue());
 
   AtomBrowserContext* browser_context() const { return browser_context_.get(); }
 
@@ -57,15 +59,7 @@ class Session: public mate::TrackableObject<Session>,
   static void BuildPrototype(v8::Isolate* isolate,
                              v8::Local<v8::ObjectTemplate> prototype);
 
- protected:
-  Session(v8::Isolate* isolate, AtomBrowserContext* browser_context);
-  ~Session();
-
-  // content::DownloadManager::Observer:
-  void OnDownloadCreated(content::DownloadManager* manager,
-                         content::DownloadItem* item) override;
-
- private:
+  // Methods.
   void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
   template<CacheAction action>
   void DoCacheAction(const net::CompletionCallback& callback);
@@ -80,10 +74,21 @@ class Session: public mate::TrackableObject<Session>,
                                    mate::Arguments* args);
   void ClearHostResolverCache(mate::Arguments* args);
   void AllowNTLMCredentialsForDomains(const std::string& domains);
+  void SetUserAgent(const std::string& user_agent, mate::Arguments* args);
+  std::string GetUserAgent();
   v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
   v8::Local<v8::Value> Protocol(v8::Isolate* isolate);
   v8::Local<v8::Value> WebRequest(v8::Isolate* isolate);
 
+ protected:
+  Session(v8::Isolate* isolate, AtomBrowserContext* browser_context);
+  ~Session();
+
+  // content::DownloadManager::Observer:
+  void OnDownloadCreated(content::DownloadManager* manager,
+                         content::DownloadItem* item) override;
+
+ private:
   // Cached object.
   v8::Global<v8::Value> cookies_;
   v8::Global<v8::Value> protocol_;

+ 4 - 0
atom/browser/api/atom_api_system_preferences.cc

@@ -53,6 +53,10 @@ void SystemPreferences::BuildPrototype(
                  &SystemPreferences::SubscribeNotification)
       .SetMethod("unsubscribeNotification",
                  &SystemPreferences::UnsubscribeNotification)
+      .SetMethod("subscribeLocalNotification",
+                 &SystemPreferences::SubscribeLocalNotification)
+      .SetMethod("unsubscribeLocalNotification",
+                 &SystemPreferences::UnsubscribeLocalNotification)
       .SetMethod("getUserDefault", &SystemPreferences::GetUserDefault)
 #endif
       .SetMethod("isDarkMode", &SystemPreferences::IsDarkMode);

+ 13 - 5
atom/browser/api/atom_api_system_preferences.h

@@ -26,17 +26,18 @@ class SystemPreferences : public mate::EventEmitter<SystemPreferences> {
   static void BuildPrototype(v8::Isolate* isolate,
                              v8::Local<v8::ObjectTemplate> prototype);
 
-#if defined(OS_MACOSX)
-  using NotificationCallback = base::Callback<
-      void(const std::string&, const base::DictionaryValue&)>;
-#endif
-
 #if defined(OS_WIN)
   bool IsAeroGlassEnabled();
 #elif defined(OS_MACOSX)
+  using NotificationCallback = base::Callback<
+    void(const std::string&, const base::DictionaryValue&)>;
+
   int SubscribeNotification(const std::string& name,
                             const NotificationCallback& callback);
   void UnsubscribeNotification(int id);
+  int SubscribeLocalNotification(const std::string& name,
+                                 const NotificationCallback& callback);
+  void UnsubscribeLocalNotification(int request_id);
   v8::Local<v8::Value> GetUserDefault(const std::string& name,
                                       const std::string& type);
 #endif
@@ -46,6 +47,13 @@ class SystemPreferences : public mate::EventEmitter<SystemPreferences> {
   explicit SystemPreferences(v8::Isolate* isolate);
   ~SystemPreferences() override;
 
+#if defined(OS_MACOSX)
+  int DoSubscribeNotification(const std::string& name,
+                              const NotificationCallback& callback,
+                              bool is_local);
+  void DoUnsubscribeNotification(int request_id, bool is_local);
+#endif
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SystemPreferences);
 };

+ 43 - 18
atom/browser/api/atom_api_system_preferences_mac.mm

@@ -30,34 +30,59 @@ std::map<int, id> g_id_map;
 
 int SystemPreferences::SubscribeNotification(
     const std::string& name, const NotificationCallback& callback) {
+  return DoSubscribeNotification(name, callback, false);
+}
+
+void SystemPreferences::UnsubscribeNotification(int request_id) {
+  DoUnsubscribeNotification(request_id, false);
+}
+
+int SystemPreferences::SubscribeLocalNotification(
+    const std::string& name, const NotificationCallback& callback) {
+  return DoSubscribeNotification(name, callback, true);
+}
+
+void SystemPreferences::UnsubscribeLocalNotification(int request_id) {
+  DoUnsubscribeNotification(request_id, true);
+}
+
+int SystemPreferences::DoSubscribeNotification(const std::string& name,
+  const NotificationCallback& callback, bool is_local) {
   int request_id = g_next_id++;
   __block NotificationCallback copied_callback = callback;
-  g_id_map[request_id] = [[NSDistributedNotificationCenter defaultCenter]
-      addObserverForName:base::SysUTF8ToNSString(name)
-      object:nil
-      queue:nil
-      usingBlock:^(NSNotification* notification) {
-        std::unique_ptr<base::DictionaryValue> user_info =
-            NSDictionaryToDictionaryValue(notification.userInfo);
-        if (user_info) {
-          copied_callback.Run(
-              base::SysNSStringToUTF8(notification.name),
-              *user_info);
-        } else {
-          copied_callback.Run(
-              base::SysNSStringToUTF8(notification.name),
-              base::DictionaryValue());
-        }
+  NSNotificationCenter* center = is_local ?
+    [NSNotificationCenter defaultCenter] :
+    [NSDistributedNotificationCenter defaultCenter];
+
+  g_id_map[request_id] = [center
+    addObserverForName:base::SysUTF8ToNSString(name)
+    object:nil
+    queue:nil
+    usingBlock:^(NSNotification* notification) {
+      std::unique_ptr<base::DictionaryValue> user_info =
+        NSDictionaryToDictionaryValue(notification.userInfo);
+      if (user_info) {
+        copied_callback.Run(
+          base::SysNSStringToUTF8(notification.name),
+          *user_info);
+      } else {
+        copied_callback.Run(
+          base::SysNSStringToUTF8(notification.name),
+          base::DictionaryValue());
       }
+    }
   ];
   return request_id;
 }
 
-void SystemPreferences::UnsubscribeNotification(int request_id) {
+void SystemPreferences::DoUnsubscribeNotification(int request_id, bool is_local) {
   auto iter = g_id_map.find(request_id);
   if (iter != g_id_map.end()) {
     id observer = iter->second;
-    [[NSDistributedNotificationCenter defaultCenter] removeObserver:observer];
+    NSNotificationCenter* center = is_local ?
+      [NSNotificationCenter defaultCenter] :
+      [NSDistributedNotificationCenter defaultCenter];
+    [center removeObserver:observer];
     g_id_map.erase(iter);
   }
 }

+ 54 - 25
atom/browser/api/atom_api_tray.cc

@@ -8,7 +8,6 @@
 
 #include "atom/browser/api/atom_api_menu.h"
 #include "atom/browser/browser.h"
-#include "atom/browser/ui/tray_icon.h"
 #include "atom/common/api/atom_api_native_image.h"
 #include "atom/common/native_mate_converters/gfx_converter.h"
 #include "atom/common/native_mate_converters/image_converter.h"
@@ -16,9 +15,47 @@
 #include "atom/common/node_includes.h"
 #include "native_mate/constructor.h"
 #include "native_mate/dictionary.h"
-#include "ui/events/event_constants.h"
 #include "ui/gfx/image/image.h"
 
+namespace mate {
+
+template<>
+struct Converter<atom::TrayIcon::HighlightMode> {
+  static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
+                     atom::TrayIcon::HighlightMode* out) {
+    std::string mode;
+    if (ConvertFromV8(isolate, val, &mode)) {
+      if (mode == "always") {
+        *out = atom::TrayIcon::HighlightMode::ALWAYS;
+        return true;
+      }
+      if (mode == "selection") {
+        *out = atom::TrayIcon::HighlightMode::SELECTION;
+        return true;
+      }
+      if (mode == "never") {
+        *out = atom::TrayIcon::HighlightMode::NEVER;
+        return true;
+      }
+    }
+
+    // Support old boolean parameter
+    // TODO(kevinsawicki): Remove in 2.0, deprecate before then with warnings
+    bool highlight;
+    if (ConvertFromV8(isolate, val, &highlight)) {
+      if (highlight)
+        *out = atom::TrayIcon::HighlightMode::SELECTION;
+      else
+        *out = atom::TrayIcon::HighlightMode::NEVER;
+      return true;
+    }
+
+    return false;
+  }
+};
+}  // namespace mate
+
+
 namespace atom {
 
 namespace api {
@@ -30,6 +67,8 @@ Tray::Tray(v8::Isolate* isolate, mate::Handle<NativeImage> image)
 }
 
 Tray::~Tray() {
+  // Destroy the native tray in next tick.
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, tray_icon_.release());
 }
 
 // static
@@ -44,24 +83,15 @@ mate::WrappableBase* Tray::New(v8::Isolate* isolate,
 }
 
 void Tray::OnClicked(const gfx::Rect& bounds, int modifiers) {
-  v8::Locker locker(isolate());
-  v8::HandleScope handle_scope(isolate());
-  EmitCustomEvent("click",
-                  ModifiersToObject(isolate(), modifiers), bounds);
+  EmitWithFlags("click", modifiers, bounds);
 }
 
 void Tray::OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {
-  v8::Locker locker(isolate());
-  v8::HandleScope handle_scope(isolate());
-  EmitCustomEvent("double-click",
-                  ModifiersToObject(isolate(), modifiers), bounds);
+  EmitWithFlags("double-click", modifiers, bounds);
 }
 
 void Tray::OnRightClicked(const gfx::Rect& bounds, int modifiers) {
-  v8::Locker locker(isolate());
-  v8::HandleScope handle_scope(isolate());
-  EmitCustomEvent("right-click",
-                  ModifiersToObject(isolate(), modifiers), bounds);
+  EmitWithFlags("right-click", modifiers, bounds);
 }
 
 void Tray::OnBalloonShow() {
@@ -84,6 +114,10 @@ void Tray::OnDropFiles(const std::vector<std::string>& files) {
   Emit("drop-files", files);
 }
 
+void Tray::OnDropText(const std::string& text) {
+  Emit("drop-text", text);
+}
+
 void Tray::OnDragEntered() {
   Emit("drag-enter");
 }
@@ -121,8 +155,8 @@ void Tray::SetTitle(const std::string& title) {
   tray_icon_->SetTitle(title);
 }
 
-void Tray::SetHighlightMode(bool highlight) {
-  tray_icon_->SetHighlightMode(highlight);
+void Tray::SetHighlightMode(TrayIcon::HighlightMode mode) {
+  tray_icon_->SetHighlightMode(mode);
 }
 
 void Tray::DisplayBalloon(mate::Arguments* args,
@@ -159,14 +193,8 @@ void Tray::SetContextMenu(v8::Isolate* isolate, mate::Handle<Menu> menu) {
   tray_icon_->SetContextMenu(menu->model());
 }
 
-v8::Local<v8::Object> Tray::ModifiersToObject(v8::Isolate* isolate,
-                                              int modifiers) {
-  mate::Dictionary obj(isolate, v8::Object::New(isolate));
-  obj.Set("shiftKey", static_cast<bool>(modifiers & ui::EF_SHIFT_DOWN));
-  obj.Set("ctrlKey", static_cast<bool>(modifiers & ui::EF_CONTROL_DOWN));
-  obj.Set("altKey", static_cast<bool>(modifiers & ui::EF_ALT_DOWN));
-  obj.Set("metaKey", static_cast<bool>(modifiers & ui::EF_COMMAND_DOWN));
-  return obj.GetHandle();
+gfx::Rect Tray::GetBounds() {
+  return tray_icon_->GetBounds();
 }
 
 // static
@@ -181,7 +209,8 @@ void Tray::BuildPrototype(v8::Isolate* isolate,
       .SetMethod("setHighlightMode", &Tray::SetHighlightMode)
       .SetMethod("displayBalloon", &Tray::DisplayBalloon)
       .SetMethod("popUpContextMenu", &Tray::PopUpContextMenu)
-      .SetMethod("setContextMenu", &Tray::SetContextMenu);
+      .SetMethod("setContextMenu", &Tray::SetContextMenu)
+      .SetMethod("getBounds", &Tray::GetBounds);
 }
 
 }  // namespace api

+ 5 - 4
atom/browser/api/atom_api_tray.h

@@ -5,12 +5,13 @@
 #ifndef ATOM_BROWSER_API_ATOM_API_TRAY_H_
 #define ATOM_BROWSER_API_ATOM_API_TRAY_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "atom/browser/api/trackable_object.h"
+#include "atom/browser/ui/tray_icon.h"
 #include "atom/browser/ui/tray_icon_observer.h"
-#include "base/memory/scoped_ptr.h"
 #include "native_mate/handle.h"
 
 namespace gfx {
@@ -53,6 +54,7 @@ class Tray : public mate::TrackableObject<Tray>,
   void OnBalloonClosed() override;
   void OnDrop() override;
   void OnDropFiles(const std::vector<std::string>& files) override;
+  void OnDropText(const std::string& text) override;
   void OnDragEntered() override;
   void OnDragExited() override;
   void OnDragEnded() override;
@@ -61,14 +63,13 @@ class Tray : public mate::TrackableObject<Tray>,
   void SetPressedImage(v8::Isolate* isolate, mate::Handle<NativeImage> image);
   void SetToolTip(const std::string& tool_tip);
   void SetTitle(const std::string& title);
-  void SetHighlightMode(bool highlight);
+  void SetHighlightMode(TrayIcon::HighlightMode mode);
   void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options);
   void PopUpContextMenu(mate::Arguments* args);
   void SetContextMenu(v8::Isolate* isolate, mate::Handle<Menu> menu);
+  gfx::Rect GetBounds();
 
  private:
-  v8::Local<v8::Object> ModifiersToObject(v8::Isolate* isolate, int modifiers);
-
   v8::Global<v8::Object> menu_;
   std::unique_ptr<TrayIcon> tray_icon_;
 

+ 136 - 55
atom/browser/api/atom_api_web_contents.cc

@@ -17,6 +17,7 @@
 #include "atom/browser/lib/bluetooth_chooser.h"
 #include "atom/browser/native_window.h"
 #include "atom/browser/net/atom_network_delegate.h"
+#include "atom/browser/ui/drag_util.h"
 #include "atom/browser/web_contents_permission_helper.h"
 #include "atom/browser/web_contents_preferences.h"
 #include "atom/browser/web_view_guest_delegate.h"
@@ -46,6 +47,7 @@
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/plugin_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
@@ -61,11 +63,10 @@
 #include "native_mate/dictionary.h"
 #include "native_mate/object_template_builder.h"
 #include "net/http/http_response_headers.h"
-#include "net/url_request/static_http_user_agent_settings.h"
 #include "net/url_request/url_request_context.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "third_party/WebKit/public/web/WebFindOptions.h"
-#include "ui/base/l10n/l10n_util.h"
+#include "ui/display/screen.h"
 
 #include "atom/common/node_includes.h"
 
@@ -76,15 +77,6 @@ struct PrintSettings {
   bool print_background;
 };
 
-void SetUserAgentInIO(scoped_refptr<net::URLRequestContextGetter> getter,
-                      std::string accept_lang,
-                      std::string user_agent) {
-  getter->GetURLRequestContext()->set_http_user_agent_settings(
-      new net::StaticHttpUserAgentSettings(
-          net::HttpUtil::GenerateAcceptLanguageHeader(accept_lang),
-          user_agent));
-}
-
 }  // namespace
 
 namespace mate {
@@ -248,6 +240,13 @@ content::ServiceWorkerContext* GetServiceWorkerContext(
   return storage_partition->GetServiceWorkerContext();
 }
 
+// Called when CapturePage is done.
+void OnCapturePageDone(base::Callback<void(const gfx::Image&)> callback,
+                       const SkBitmap& bitmap,
+                       content::ReadbackResponse response) {
+  callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap));
+}
+
 }  // namespace
 
 WebContents::WebContents(v8::Isolate* isolate,
@@ -287,16 +286,11 @@ WebContents::WebContents(v8::Isolate* isolate,
   std::string partition;
   mate::Handle<api::Session> session;
   if (options.Get("session", &session)) {
-  } else if (options.Get("partition", &partition) && !partition.empty()) {
-    bool in_memory = true;
-    if (base::StartsWith(partition, "persist:", base::CompareCase::SENSITIVE)) {
-      in_memory = false;
-      partition = partition.substr(8);
-    }
-    session = Session::FromPartition(isolate, partition, in_memory);
+  } else if (options.Get("partition", &partition)) {
+    session = Session::FromPartition(isolate, partition);
   } else {
     // Use the default session if not specified.
-    session = Session::FromPartition(isolate, "", false);
+    session = Session::FromPartition(isolate, "");
   }
   session_.Reset(isolate, session.ToV8());
 
@@ -610,17 +604,6 @@ void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host,
     Emit("did-finish-load");
 }
 
-void WebContents::DidFailProvisionalLoad(
-    content::RenderFrameHost* render_frame_host,
-    const GURL& url,
-    int code,
-    const base::string16& description,
-    bool was_ignored_by_handler) {
-  bool is_main_frame = !render_frame_host->GetParent();
-  Emit("did-fail-provisional-load", code, description, url, is_main_frame);
-  Emit("did-fail-load", code, description, url, is_main_frame);
-}
-
 void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host,
                               const GURL& url,
                               int error_code,
@@ -664,13 +647,27 @@ void WebContents::DidGetRedirectForResourceRequest(
        details.headers.get());
 }
 
-void WebContents::DidNavigateMainFrame(
-    const content::LoadCommittedDetails& details,
-    const content::FrameNavigateParams& params) {
-  if (details.is_navigation_to_different_page())
-    Emit("did-navigate", params.url);
-  else if (details.is_in_page)
-    Emit("did-navigate-in-page", params.url);
+void WebContents::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  bool is_main_frame = navigation_handle->IsInMainFrame();
+  if (navigation_handle->HasCommitted() && !navigation_handle->IsErrorPage()) {
+    auto url = navigation_handle->GetURL();
+    bool is_in_page = navigation_handle->IsSamePage();
+    if (is_main_frame && !is_in_page) {
+      Emit("did-navigate", url);
+    } else if (is_in_page) {
+      Emit("did-navigate-in-page", url);
+    }
+  } else {
+    auto url = navigation_handle->GetURL();
+    int code = navigation_handle->GetNetErrorCode();
+    auto description = net::ErrorToShortString(code);
+    Emit("did-fail-provisional-load", code, description, url, is_main_frame);
+
+    // Do not emit "did-fail-load" for canceled requests.
+    if (code != net::ERR_ABORTED)
+      Emit("did-fail-load", code, description, url, is_main_frame);
+  }
 }
 
 void WebContents::TitleWasSet(content::NavigationEntry* entry,
@@ -684,10 +681,10 @@ void WebContents::TitleWasSet(content::NavigationEntry* entry,
 void WebContents::DidUpdateFaviconURL(
     const std::vector<content::FaviconURL>& urls) {
   std::set<GURL> unique_urls;
-  for (auto iter = urls.begin(); iter != urls.end(); ++iter) {
-    if (iter->icon_type != content::FaviconURL::FAVICON)
+  for (const auto& iter : urls) {
+    if (iter.icon_type != content::FaviconURL::FAVICON)
       continue;
-    const GURL& url = iter->icon_url;
+    const GURL& url = iter.icon_url;
     if (url.is_valid())
       unique_urls.insert(url);
   }
@@ -736,6 +733,7 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
     IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
     IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
                                     OnRendererMessageSync)
+    IPC_MESSAGE_HANDLER(AtomViewHostMsg_DidCommitCompositorFrame, OnViewPainted)
     IPC_MESSAGE_HANDLER_CODE(ViewHostMsg_SetCursor, OnCursorChange,
       handled = false)
     IPC_MESSAGE_UNHANDLED(handled = false)
@@ -745,7 +743,7 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
 }
 
 // There are three ways of destroying a webContents:
-// 1. call webContents.destory();
+// 1. call webContents.destroy();
 // 2. garbage collection;
 // 3. user closes the window of webContents;
 // For webview only #1 will happen, for BrowserWindow both #1 and #3 may
@@ -788,6 +786,13 @@ WebContents::Type WebContents::GetType() const {
   return type_;
 }
 
+#if !defined(OS_MACOSX)
+bool WebContents::IsFocused() const {
+  auto view = web_contents()->GetRenderWidgetHostView();
+  return view && view->HasFocus();
+}
+#endif
+
 bool WebContents::Equal(const WebContents* web_contents) const {
   return GetID() == web_contents->GetID();
 }
@@ -811,7 +816,7 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
 
   std::string user_agent;
   if (options.Get("userAgent", &user_agent))
-    SetUserAgent(user_agent);
+    web_contents()->SetUserAgentOverride(user_agent);
 
   std::string extra_headers;
   if (options.Get("extraHeaders", &extra_headers))
@@ -898,14 +903,9 @@ bool WebContents::IsCrashed() const {
   return web_contents()->IsCrashed();
 }
 
-void WebContents::SetUserAgent(const std::string& user_agent) {
+void WebContents::SetUserAgent(const std::string& user_agent,
+                               mate::Arguments* args) {
   web_contents()->SetUserAgentOverride(user_agent);
-  scoped_refptr<net::URLRequestContextGetter> getter =
-      web_contents()->GetBrowserContext()->GetRequestContext();
-
-  auto accept_lang = l10n_util::GetApplicationLocale("");
-  getter->GetNetworkTaskRunner()->PostTask(FROM_HERE,
-      base::Bind(&SetUserAgentInIO, getter, accept_lang, user_agent));
 }
 
 std::string WebContents::GetUserAgent() {
@@ -1146,6 +1146,12 @@ void WebContents::ShowDefinitionForSelection() {
 #endif
 }
 
+void WebContents::CopyImageAt(int x, int y) {
+  const auto host = web_contents()->GetRenderViewHost();
+  if (host)
+    host->CopyImageAt(x, y);
+}
+
 void WebContents::Focus() {
   web_contents()->Focus();
 }
@@ -1194,15 +1200,14 @@ void WebContents::SendInputEvent(v8::Isolate* isolate,
       isolate, "Invalid event object")));
 }
 
-void WebContents::BeginFrameSubscription(
-  mate::Arguments* args) {
-  FrameSubscriber::FrameCaptureCallback callback;
+void WebContents::BeginFrameSubscription(mate::Arguments* args) {
   bool only_dirty = false;
+  FrameSubscriber::FrameCaptureCallback callback;
 
+  args->GetNext(&only_dirty);
   if (!args->GetNext(&callback)) {
-    args->GetNext(&only_dirty);
-    if (!args->GetNext(&callback))
-      args->ThrowTypeError("'callback' must be defined");
+    args->ThrowError();
+    return;
   }
 
   const auto view = web_contents()->GetRenderWidgetHostView();
@@ -1219,6 +1224,74 @@ void WebContents::EndFrameSubscription() {
     view->EndFrameSubscription();
 }
 
+void WebContents::StartDrag(const mate::Dictionary& item,
+                            mate::Arguments* args) {
+  base::FilePath file;
+  std::vector<base::FilePath> files;
+  if (!item.Get("files", &files) && item.Get("file", &file)) {
+    files.push_back(file);
+  }
+
+  mate::Handle<NativeImage> icon;
+  if (!item.Get("icon", &icon) && !file.empty()) {
+    // TODO(zcbenz): Set default icon from file.
+  }
+
+  // Error checking.
+  if (icon.IsEmpty()) {
+    args->ThrowError("icon must be set");
+    return;
+  }
+
+  // Start dragging.
+  if (!files.empty()) {
+    base::MessageLoop::ScopedNestableTaskAllower allow(
+        base::MessageLoop::current());
+    DragFileItems(files, icon->image(), web_contents()->GetNativeView());
+  } else {
+    args->ThrowError("There is nothing to drag");
+  }
+}
+
+void WebContents::CapturePage(mate::Arguments* args) {
+  gfx::Rect rect;
+  base::Callback<void(const gfx::Image&)> callback;
+
+  if (!(args->Length() == 1 && args->GetNext(&callback)) &&
+      !(args->Length() == 2 && args->GetNext(&rect)
+                            && args->GetNext(&callback))) {
+    args->ThrowError();
+    return;
+  }
+
+  const auto view = web_contents()->GetRenderWidgetHostView();
+  const auto host = view ? view->GetRenderWidgetHost() : nullptr;
+  if (!view || !host) {
+    callback.Run(gfx::Image());
+    return;
+  }
+
+  // Capture full page if user doesn't specify a |rect|.
+  const gfx::Size view_size = rect.IsEmpty() ? view->GetViewBounds().size() :
+                                               rect.size();
+
+  // By default, the requested bitmap size is the view size in screen
+  // coordinates.  However, if there's more pixel detail available on the
+  // current system, increase the requested bitmap size to capture it all.
+  gfx::Size bitmap_size = view_size;
+  const gfx::NativeView native_view = view->GetNativeView();
+  const float scale =
+      display::Screen::GetScreen()->GetDisplayNearestWindow(native_view)
+      .device_scale_factor();
+  if (scale > 1.0f)
+    bitmap_size = gfx::ScaleToCeiledSize(view_size, scale);
+
+  host->CopyFromBackingStore(gfx::Rect(rect.origin(), view_size),
+                             bitmap_size,
+                             base::Bind(&OnCapturePageDone, callback),
+                             kBGRA_8888_SkColorType);
+}
+
 void WebContents::OnCursorChange(const content::WebCursor& cursor) {
   content::WebCursor::CursorInfo info;
   cursor.GetCursorInfo(&info);
@@ -1232,6 +1305,10 @@ void WebContents::OnCursorChange(const content::WebCursor& cursor) {
   }
 }
 
+void WebContents::OnViewPainted() {
+  Emit("view-painted");
+}
+
 void WebContents::SetSize(const SetSizeParams& params) {
   if (guest_delegate_)
     guest_delegate_->SetSize(params);
@@ -1338,6 +1415,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
       .SetMethod("beginFrameSubscription",
                  &WebContents::BeginFrameSubscription)
       .SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
+      .SetMethod("startDrag", &WebContents::StartDrag)
       .SetMethod("setSize", &WebContents::SetSize)
       .SetMethod("isGuest", &WebContents::IsGuest)
       .SetMethod("getType", &WebContents::GetType)
@@ -1353,6 +1431,9 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
       .SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
       .SetMethod("showDefinitionForSelection",
                  &WebContents::ShowDefinitionForSelection)
+      .SetMethod("copyImageAt", &WebContents::CopyImageAt)
+      .SetMethod("capturePage", &WebContents::CapturePage)
+      .SetMethod("isFocused", &WebContents::IsFocused)
       .SetProperty("id", &WebContents::ID)
       .SetProperty("session", &WebContents::Session)
       .SetProperty("hostWebContents", &WebContents::HostWebContents)

+ 15 - 9
atom/browser/api/atom_api_web_contents.h

@@ -67,6 +67,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
 
   int GetID() const;
   Type GetType() const;
+  bool IsFocused() const;
   bool Equal(const WebContents* web_contents) const;
   void LoadURL(const GURL& url, const mate::Dictionary& options);
   void DownloadURL(const GURL& url);
@@ -81,7 +82,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
   void GoForward();
   void GoToOffset(int offset);
   bool IsCrashed() const;
-  void SetUserAgent(const std::string& user_agent);
+  void SetUserAgent(const std::string& user_agent, mate::Arguments* args);
   std::string GetUserAgent();
   void InsertCSS(const std::string& css);
   bool SavePage(const base::FilePath& full_file_path,
@@ -125,6 +126,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
   uint32_t FindInPage(mate::Arguments* args);
   void StopFindInPage(content::StopFindAction action);
   void ShowDefinitionForSelection();
+  void CopyImageAt(int x, int y);
 
   // Focus.
   void Focus();
@@ -142,6 +144,13 @@ class WebContents : public mate::TrackableObject<WebContents>,
   void BeginFrameSubscription(mate::Arguments* args);
   void EndFrameSubscription();
 
+  // Dragging native items.
+  void StartDrag(const mate::Dictionary& item, mate::Arguments* args);
+
+  // Captures the page with |rect|, |callback| would be called when capturing is
+  // done.
+  void CapturePage(mate::Arguments* args);
+
   // Methods for creating <webview>.
   void SetSize(const SetSizeParams& params);
   bool IsGuest() const;
@@ -237,11 +246,6 @@ class WebContents : public mate::TrackableObject<WebContents>,
                    int error_code,
                    const base::string16& error_description,
                    bool was_ignored_by_handler) override;
-  void DidFailProvisionalLoad(content::RenderFrameHost* render_frame_host,
-                              const GURL& validated_url,
-                              int error_code,
-                              const base::string16& error_description,
-                              bool was_ignored_by_handler) override;
   void DidStartLoading() override;
   void DidStopLoading() override;
   void DidGetResourceResponseStart(
@@ -249,9 +253,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
   void DidGetRedirectForResourceRequest(
       content::RenderFrameHost* render_frame_host,
       const content::ResourceRedirectDetails& details) override;
-  void DidNavigateMainFrame(
-      const content::LoadCommittedDetails& details,
-      const content::FrameNavigateParams& params) override;
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
   bool OnMessageReceived(const IPC::Message& message) override;
   void WebContentsDestroyed() override;
   void NavigationEntryCommitted(
@@ -292,6 +295,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
                              const base::ListValue& args,
                              IPC::Message* message);
 
+  // Called when the hosted view gets graphical updates.
+  void OnViewPainted();
+
   v8::Global<v8::Value> session_;
   v8::Global<v8::Value> devtools_web_contents_;
   v8::Global<v8::Value> debugger_;

+ 32 - 0
atom/browser/api/atom_api_web_contents_mac.mm

@@ -0,0 +1,32 @@
+// Copyright (c) 2016 GitHub, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#include "atom/browser/api/atom_api_web_contents.h"
+
+@interface NSWindow
+- (BOOL)isKeyWindow;
+@end
+
+namespace atom {
+
+namespace api {
+
+bool WebContents::IsFocused() const {
+  auto view = web_contents()->GetRenderWidgetHostView();
+  if (!view) return false;
+
+  if (GetType() != BACKGROUND_PAGE) {
+    auto window = web_contents()->GetTopLevelNativeWindow();
+    // On Mac the render widget host view does not lose focus when the window
+    // loses focus so check if the top level window is the key window.
+    if (window && ![window isKeyWindow])
+      return false;
+  }
+
+  return view->HasFocus();
+}
+
+}  // namespace api
+
+}  // namespace atom

+ 16 - 28
atom/browser/api/atom_api_window.cc

@@ -55,15 +55,6 @@ namespace api {
 
 namespace {
 
-void OnCapturePageDone(
-    v8::Isolate* isolate,
-    const base::Callback<void(const gfx::Image&)>& callback,
-    const SkBitmap& bitmap) {
-  v8::Locker locker(isolate);
-  v8::HandleScope handle_scope(isolate);
-  callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap));
-}
-
 // Converts binary data to Buffer.
 v8::Local<v8::Value> ToBuffer(v8::Isolate* isolate, void* val, int size) {
   auto buffer = node::Buffer::Copy(isolate, static_cast<char*>(val), size);
@@ -106,9 +97,6 @@ Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
       options,
       parent.IsEmpty() ? nullptr : parent->window_.get()));
   web_contents->SetOwnerWindow(window_.get());
-  window_->InitFromOptions(options);
-  window_->AddObserver(this);
-  AttachAsUserData(window_.get());
 
 #if defined(TOOLKIT_VIEWS)
   // Sets the window icon.
@@ -116,6 +104,10 @@ Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
   if (options.Get(options::kIcon, &icon))
     SetIcon(icon);
 #endif
+
+  window_->InitFromOptions(options);
+  window_->AddObserver(this);
+  AttachAsUserData(window_.get());
 }
 
 Window::~Window() {
@@ -572,23 +564,12 @@ void Window::SetIgnoreMouseEvents(bool ignore) {
   return window_->SetIgnoreMouseEvents(ignore);
 }
 
-void Window::SetFocusable(bool focusable) {
-  return window_->SetFocusable(focusable);
+void Window::SetContentProtection(bool enable) {
+  return window_->SetContentProtection(enable);
 }
 
-void Window::CapturePage(mate::Arguments* args) {
-  gfx::Rect rect;
-  base::Callback<void(const gfx::Image&)> callback;
-
-  if (!(args->Length() == 1 && args->GetNext(&callback)) &&
-      !(args->Length() == 2 && args->GetNext(&rect)
-                            && args->GetNext(&callback))) {
-    args->ThrowError();
-    return;
-  }
-
-  window_->CapturePage(
-      rect, base::Bind(&OnCapturePageDone, args->isolate(), callback));
+void Window::SetFocusable(bool focusable) {
+  return window_->SetFocusable(focusable);
 }
 
 void Window::SetProgressBar(double progress) {
@@ -668,6 +649,12 @@ bool Window::IsWindowMessageHooked(UINT message) {
 void Window::UnhookAllWindowMessages() {
   messages_callback_map_.clear();
 }
+
+bool Window::SetThumbnailClip(const gfx::Rect& region) {
+  auto window = static_cast<NativeWindowViews*>(window_.get());
+  return window->taskbar_host().SetThumbnailClip(
+      window_->GetAcceleratedWidget(), region);
+}
 #endif
 
 #if defined(TOOLKIT_VIEWS)
@@ -833,11 +820,11 @@ void Window::BuildPrototype(v8::Isolate* isolate,
       .SetMethod("setDocumentEdited", &Window::SetDocumentEdited)
       .SetMethod("isDocumentEdited", &Window::IsDocumentEdited)
       .SetMethod("setIgnoreMouseEvents", &Window::SetIgnoreMouseEvents)
+      .SetMethod("setContentProtection", &Window::SetContentProtection)
       .SetMethod("setFocusable", &Window::SetFocusable)
       .SetMethod("focusOnWebView", &Window::FocusOnWebView)
       .SetMethod("blurWebView", &Window::BlurWebView)
       .SetMethod("isWebViewFocused", &Window::IsWebViewFocused)
-      .SetMethod("capturePage", &Window::CapturePage)
       .SetMethod("setProgressBar", &Window::SetProgressBar)
       .SetMethod("setOverlayIcon", &Window::SetOverlayIcon)
       .SetMethod("setThumbarButtons", &Window::SetThumbarButtons)
@@ -855,6 +842,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
       .SetMethod("isWindowMessageHooked", &Window::IsWindowMessageHooked)
       .SetMethod("unhookWindowMessage", &Window::UnhookWindowMessage)
       .SetMethod("unhookAllWindowMessages", &Window::UnhookAllWindowMessages)
+      .SetMethod("setThumbnailClip", &Window::SetThumbnailClip)
 #endif
 #if defined(TOOLKIT_VIEWS)
       .SetMethod("setIcon", &Window::SetIcon)

+ 2 - 1
atom/browser/api/atom_api_window.h

@@ -153,8 +153,8 @@ class Window : public mate::TrackableObject<Window>,
   void SetDocumentEdited(bool edited);
   bool IsDocumentEdited();
   void SetIgnoreMouseEvents(bool ignore);
+  void SetContentProtection(bool enable);
   void SetFocusable(bool focusable);
-  void CapturePage(mate::Arguments* args);
   void SetProgressBar(double progress);
   void SetOverlayIcon(const gfx::Image& overlay,
                       const std::string& description);
@@ -179,6 +179,7 @@ class Window : public mate::TrackableObject<Window>,
   bool IsWindowMessageHooked(UINT message);
   void UnhookWindowMessage(UINT message);
   void UnhookAllWindowMessages();
+  bool SetThumbnailClip(const gfx::Rect& region);
 #endif
 
 #if defined(TOOLKIT_VIEWS)

+ 7 - 7
atom/browser/api/event.cc

@@ -12,8 +12,8 @@
 namespace mate {
 
 Event::Event(v8::Isolate* isolate)
-    : sender_(NULL),
-      message_(NULL) {
+    : sender_(nullptr),
+      message_(nullptr) {
   Init(isolate);
 }
 
@@ -31,8 +31,8 @@ void Event::SetSenderAndMessage(content::WebContents* sender,
 }
 
 void Event::WebContentsDestroyed() {
-  sender_ = NULL;
-  message_ = NULL;
+  sender_ = nullptr;
+  message_ = nullptr;
 }
 
 void Event::PreventDefault(v8::Isolate* isolate) {
@@ -41,13 +41,13 @@ void Event::PreventDefault(v8::Isolate* isolate) {
 }
 
 bool Event::SendReply(const base::string16& json) {
-  if (message_ == NULL || sender_ == NULL)
+  if (message_ == nullptr || sender_ == nullptr)
     return false;
 
   AtomViewHostMsg_Message_Sync::WriteReplyParams(message_, json);
   bool success = sender_->Send(message_);
-  message_ = NULL;
-  sender_ = NULL;
+  message_ = nullptr;
+  sender_ = nullptr;
   return success;
 }
 

+ 10 - 0
atom/browser/api/event_emitter.cc

@@ -8,6 +8,7 @@
 #include "native_mate/arguments.h"
 #include "native_mate/dictionary.h"
 #include "native_mate/object_template_builder.h"
+#include "ui/events/event_constants.h"
 
 namespace mate {
 
@@ -65,6 +66,15 @@ v8::Local<v8::Object> CreateCustomEvent(
   return event;
 }
 
+v8::Local<v8::Object> CreateEventFromFlags(v8::Isolate* isolate, int flags) {
+  mate::Dictionary obj = mate::Dictionary::CreateEmpty(isolate);
+  obj.Set("shiftKey", static_cast<bool>(flags & ui::EF_SHIFT_DOWN));
+  obj.Set("ctrlKey", static_cast<bool>(flags & ui::EF_CONTROL_DOWN));
+  obj.Set("altKey", static_cast<bool>(flags & ui::EF_ALT_DOWN));
+  obj.Set("metaKey", static_cast<bool>(flags & ui::EF_COMMAND_DOWN));
+  return obj.GetHandle();
+}
+
 }  // namespace internal
 
 }  // namespace mate

+ 11 - 0
atom/browser/api/event_emitter.h

@@ -30,6 +30,7 @@ v8::Local<v8::Object> CreateCustomEvent(
     v8::Isolate* isolate,
     v8::Local<v8::Object> object,
     v8::Local<v8::Object> event);
+v8::Local<v8::Object> CreateEventFromFlags(v8::Isolate* isolate, int flags);
 
 }  // namespace internal
 
@@ -54,6 +55,16 @@ class EventEmitter : public Wrappable<T> {
         internal::CreateCustomEvent(isolate(), GetWrapper(), event), args...);
   }
 
+  // this.emit(name, new Event(flags), args...);
+  template<typename... Args>
+  bool EmitWithFlags(const base::StringPiece& name,
+                     int flags,
+                     const Args&... args) {
+    return EmitCustomEvent(
+        name,
+        internal::CreateEventFromFlags(isolate(), flags), args...);
+  }
+
   // this.emit(name, new Event(), args...);
   template<typename... Args>
   bool Emit(const base::StringPiece& name, const Args&... args) {

+ 10 - 6
atom/browser/api/frame_subscriber.cc

@@ -5,8 +5,8 @@
 #include "atom/browser/api/frame_subscriber.h"
 
 #include "base/bind.h"
-#include "atom/common/node_includes.h"
 #include "atom/common/native_mate_converters/gfx_converter.h"
+#include "atom/common/node_includes.h"
 #include "content/public/browser/render_widget_host.h"
 
 namespace atom {
@@ -17,8 +17,11 @@ FrameSubscriber::FrameSubscriber(v8::Isolate* isolate,
                                  content::RenderWidgetHostView* view,
                                  const FrameCaptureCallback& callback,
                                  bool only_dirty)
-    : isolate_(isolate), view_(view), callback_(callback),
-      only_dirty_(only_dirty), weak_factory_(this) {
+    : isolate_(isolate),
+      view_(view),
+      callback_(callback),
+      only_dirty_(only_dirty),
+      weak_factory_(this) {
 }
 
 bool FrameSubscriber::ShouldCaptureFrame(
@@ -48,8 +51,9 @@ bool FrameSubscriber::ShouldCaptureFrame(
 }
 
 void FrameSubscriber::OnFrameDelivered(const FrameCaptureCallback& callback,
-  const gfx::Rect& damage_rect, const SkBitmap& bitmap,
-  content::ReadbackResponse response) {
+                                       const gfx::Rect& damage_rect,
+                                       const SkBitmap& bitmap,
+                                       content::ReadbackResponse response) {
   if (response != content::ReadbackResponse::READBACK_SUCCESS)
     return;
 
@@ -67,7 +71,7 @@ void FrameSubscriber::OnFrameDelivered(const FrameCaptureCallback& callback,
     rgb_arr_size);
 
   v8::Local<v8::Value> damage =
-    mate::Converter<gfx::Rect>::ToV8(isolate_, damage_rect);
+      mate::Converter<gfx::Rect>::ToV8(isolate_, damage_rect);
 
   callback_.Run(buffer.ToLocalChecked(), damage);
 }

+ 4 - 3
atom/browser/api/frame_subscriber.h

@@ -21,7 +21,7 @@ namespace api {
 class FrameSubscriber : public content::RenderWidgetHostViewFrameSubscriber {
  public:
   using FrameCaptureCallback =
-    base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>;
+      base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>;
 
   FrameSubscriber(v8::Isolate* isolate,
                   content::RenderWidgetHostView* view,
@@ -35,8 +35,9 @@ class FrameSubscriber : public content::RenderWidgetHostViewFrameSubscriber {
 
  private:
   void OnFrameDelivered(const FrameCaptureCallback& callback,
-    const gfx::Rect& damage_rect, const SkBitmap& bitmap,
-    content::ReadbackResponse response);
+                        const gfx::Rect& damage_rect,
+                        const SkBitmap& bitmap,
+                        content::ReadbackResponse response);
 
   v8::Isolate* isolate_;
   content::RenderWidgetHostView* view_;

+ 0 - 1
atom/browser/api/trackable_object.h

@@ -10,7 +10,6 @@
 #include "atom/browser/api/event_emitter.h"
 #include "atom/common/key_weak_map.h"
 #include "base/bind.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "native_mate/object_template_builder.h"
 

+ 22 - 8
atom/browser/atom_access_token_store.cc

@@ -7,8 +7,8 @@
 #include <utility>
 
 #include "atom/browser/atom_browser_context.h"
-#include "atom/browser/atom_browser_main_parts.h"
 #include "atom/common/google_api_key.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/geolocation_provider.h"
 
 namespace atom {
@@ -33,21 +33,35 @@ AtomAccessTokenStore::~AtomAccessTokenStore() {
 
 void AtomAccessTokenStore::LoadAccessTokens(
     const LoadAccessTokensCallback& callback) {
-  AccessTokenMap access_token_map;
+  content::BrowserThread::PostTaskAndReply(
+      content::BrowserThread::UI,
+      FROM_HERE,
+      base::Bind(&AtomAccessTokenStore::GetRequestContextOnUIThread, this),
+      base::Bind(&AtomAccessTokenStore::RespondOnOriginatingThread,
+                 this, callback));
+}
+
+void AtomAccessTokenStore::SaveAccessToken(const GURL& server_url,
+                                           const base::string16& access_token) {
+}
+
+void AtomAccessTokenStore::GetRequestContextOnUIThread() {
+  auto browser_context = AtomBrowserContext::From("", false);
+  request_context_getter_ = browser_context->GetRequestContext();
+}
 
+void AtomAccessTokenStore::RespondOnOriginatingThread(
+    const LoadAccessTokensCallback& callback) {
   // Equivelent to access_token_map[kGeolocationProviderURL].
   // Somehow base::string16 is causing compilation errors when used in a pair
   // of std::map on Linux, this can work around it.
+  AccessTokenMap access_token_map;
   std::pair<GURL, base::string16> token_pair;
   token_pair.first = GURL(kGeolocationProviderURL);
   access_token_map.insert(token_pair);
 
-  auto browser_context = AtomBrowserMainParts::Get()->browser_context();
-  callback.Run(access_token_map, browser_context->url_request_context_getter());
-}
-
-void AtomAccessTokenStore::SaveAccessToken(const GURL& server_url,
-                                           const base::string16& access_token) {
+  callback.Run(access_token_map, request_context_getter_.get());
+  request_context_getter_ = nullptr;
 }
 
 }  // namespace atom

+ 6 - 3
atom/browser/atom_access_token_store.h

@@ -9,12 +9,10 @@
 
 namespace atom {
 
-class AtomBrowserContext;
-
 class AtomAccessTokenStore : public content::AccessTokenStore {
  public:
   AtomAccessTokenStore();
-  virtual ~AtomAccessTokenStore();
+  ~AtomAccessTokenStore();
 
   // content::AccessTokenStore:
   void LoadAccessTokens(
@@ -23,6 +21,11 @@ class AtomAccessTokenStore : public content::AccessTokenStore {
                        const base::string16& access_token) override;
 
  private:
+  void GetRequestContextOnUIThread();
+  void RespondOnOriginatingThread(const LoadAccessTokensCallback& callback);
+
+  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+
   DISALLOW_COPY_AND_ASSIGN(AtomAccessTokenStore);
 };
 

+ 6 - 5
atom/browser/atom_browser_client.cc

@@ -202,7 +202,7 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
 void AtomBrowserClient::DidCreatePpapiPlugin(
     content::BrowserPpapiHost* host) {
   host->GetPpapiHost()->AddHostFactoryFilter(
-      make_scoped_ptr(new chrome::ChromeBrowserPepperHostFactory(host)));
+      base::WrapUnique(new chrome::ChromeBrowserPepperHostFactory(host)));
 }
 
 content::QuotaPermissionContext*
@@ -287,20 +287,21 @@ brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts(
 
 void AtomBrowserClient::WebNotificationAllowed(
     int render_process_id,
-    const base::Callback<void(bool)>& callback) {
+    const base::Callback<void(bool, bool)>& callback) {
   content::WebContents* web_contents =
       WebContentsPreferences::GetWebContentsFromProcessID(render_process_id);
   if (!web_contents) {
-    callback.Run(false);
+    callback.Run(false, false);
     return;
   }
   auto permission_helper =
       WebContentsPermissionHelper::FromWebContents(web_contents);
   if (!permission_helper) {
-    callback.Run(false);
+    callback.Run(false, false);
     return;
   }
-  permission_helper->RequestWebNotificationPermission(callback);
+  permission_helper->RequestWebNotificationPermission(
+      base::Bind(callback, web_contents->IsAudioMuted()));
 }
 
 void AtomBrowserClient::RenderProcessHostDestroyed(

+ 1 - 1
atom/browser/atom_browser_client.h

@@ -100,7 +100,7 @@ class AtomBrowserClient : public brightray::BrowserClient,
       const content::MainFunctionParams&) override;
   void WebNotificationAllowed(
       int render_process_id,
-      const base::Callback<void(bool)>& callback) override;
+      const base::Callback<void(bool, bool)>& callback) override;
 
   // content::RenderProcessHostObserver:
   void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;

+ 45 - 31
atom/browser/atom_browser_context.cc

@@ -63,21 +63,12 @@ std::string RemoveWhitespace(const std::string& str) {
 
 }  // namespace
 
-AtomBrowserContext::AtomBrowserContext(const std::string& partition,
-                                       bool in_memory)
+AtomBrowserContext::AtomBrowserContext(
+    const std::string& partition, bool in_memory,
+    const base::DictionaryValue& options)
     : brightray::BrowserContext(partition, in_memory),
-      cert_verifier_(new AtomCertVerifier),
       network_delegate_(new AtomNetworkDelegate) {
-}
-
-AtomBrowserContext::~AtomBrowserContext() {
-}
-
-net::NetworkDelegate* AtomBrowserContext::CreateNetworkDelegate() {
-  return network_delegate_;
-}
-
-std::string AtomBrowserContext::GetUserAgent() {
+  // Construct user agent string.
   Browser* browser = Browser::Get();
   std::string name = RemoveWhitespace(browser->GetName());
   std::string user_agent;
@@ -91,7 +82,29 @@ std::string AtomBrowserContext::GetUserAgent() {
         browser->GetVersion().c_str(),
         CHROME_VERSION_STRING);
   }
-  return content::BuildUserAgentFromProduct(user_agent);
+  user_agent_ = content::BuildUserAgentFromProduct(user_agent);
+
+  // Read options.
+  use_cache_ = true;
+  options.GetBoolean("cache", &use_cache_);
+
+  // Initialize Pref Registry in brightray.
+  InitPrefs();
+}
+
+AtomBrowserContext::~AtomBrowserContext() {
+}
+
+void AtomBrowserContext::SetUserAgent(const std::string& user_agent) {
+  user_agent_ = user_agent;
+}
+
+net::NetworkDelegate* AtomBrowserContext::CreateNetworkDelegate() {
+  return network_delegate_;
+}
+
+std::string AtomBrowserContext::GetUserAgent() {
+  return user_agent_;
 }
 
 std::unique_ptr<net::URLRequestJobFactory>
@@ -107,29 +120,29 @@ AtomBrowserContext::CreateURLRequestJobFactory(
   protocol_handlers->clear();
 
   job_factory->SetProtocolHandler(
-      url::kDataScheme, make_scoped_ptr(new net::DataProtocolHandler));
+      url::kDataScheme, base::WrapUnique(new net::DataProtocolHandler));
   job_factory->SetProtocolHandler(
-      url::kFileScheme, make_scoped_ptr(new asar::AsarProtocolHandler(
+      url::kFileScheme, base::WrapUnique(new asar::AsarProtocolHandler(
           BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
               base::SequencedWorkerPool::SKIP_ON_SHUTDOWN))));
   job_factory->SetProtocolHandler(
       url::kHttpScheme,
-      make_scoped_ptr(new HttpProtocolHandler(url::kHttpScheme)));
+      base::WrapUnique(new HttpProtocolHandler(url::kHttpScheme)));
   job_factory->SetProtocolHandler(
       url::kHttpsScheme,
-      make_scoped_ptr(new HttpProtocolHandler(url::kHttpsScheme)));
+      base::WrapUnique(new HttpProtocolHandler(url::kHttpsScheme)));
   job_factory->SetProtocolHandler(
       url::kWsScheme,
-      make_scoped_ptr(new HttpProtocolHandler(url::kWsScheme)));
+      base::WrapUnique(new HttpProtocolHandler(url::kWsScheme)));
   job_factory->SetProtocolHandler(
       url::kWssScheme,
-      make_scoped_ptr(new HttpProtocolHandler(url::kWssScheme)));
+      base::WrapUnique(new HttpProtocolHandler(url::kWssScheme)));
 
   auto host_resolver =
       url_request_context_getter()->GetURLRequestContext()->host_resolver();
   job_factory->SetProtocolHandler(
       url::kFtpScheme,
-      make_scoped_ptr(new net::FtpProtocolHandler(
+      base::WrapUnique(new net::FtpProtocolHandler(
           new net::FtpNetworkLayer(host_resolver))));
 
   return std::move(job_factory);
@@ -139,7 +152,7 @@ net::HttpCache::BackendFactory*
 AtomBrowserContext::CreateHttpCacheBackendFactory(
     const base::FilePath& base_path) {
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kDisableHttpCache))
+  if (!use_cache_ || command_line->HasSwitch(switches::kDisableHttpCache))
     return new NoCacheBackend;
   else
     return brightray::BrowserContext::CreateHttpCacheBackendFactory(base_path);
@@ -168,7 +181,7 @@ content::PermissionManager* AtomBrowserContext::GetPermissionManager() {
 }
 
 std::unique_ptr<net::CertVerifier> AtomBrowserContext::CreateCertVerifier() {
-  return make_scoped_ptr(cert_verifier_);
+  return base::WrapUnique(new AtomCertVerifier);
 }
 
 net::SSLConfigService* AtomBrowserContext::CreateSSLConfigService() {
@@ -185,14 +198,15 @@ void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
   pref_registry->RegisterDictionaryPref(prefs::kDevToolsFileSystemPaths);
 }
 
-}  // namespace atom
-
-namespace brightray {
-
 // static
-scoped_refptr<BrowserContext> BrowserContext::Create(
-    const std::string& partition, bool in_memory) {
-  return make_scoped_refptr(new atom::AtomBrowserContext(partition, in_memory));
+scoped_refptr<AtomBrowserContext> AtomBrowserContext::From(
+    const std::string& partition, bool in_memory,
+    const base::DictionaryValue& options) {
+  auto browser_context = brightray::BrowserContext::Get(partition, in_memory);
+  if (browser_context)
+    return static_cast<AtomBrowserContext*>(browser_context.get());
+
+  return new AtomBrowserContext(partition, in_memory, options);
 }
 
-}  // namespace brightray
+}  // namespace atom

+ 15 - 5
atom/browser/atom_browser_context.h

@@ -12,15 +12,20 @@
 namespace atom {
 
 class AtomDownloadManagerDelegate;
-class AtomCertVerifier;
 class AtomNetworkDelegate;
 class AtomPermissionManager;
 class WebViewManager;
 
 class AtomBrowserContext : public brightray::BrowserContext {
  public:
-  AtomBrowserContext(const std::string& partition, bool in_memory);
-  ~AtomBrowserContext() override;
+  // Get or create the BrowserContext according to its |partition| and
+  // |in_memory|. The |options| will be passed to constructor when there is no
+  // existing BrowserContext.
+  static scoped_refptr<AtomBrowserContext> From(
+      const std::string& partition, bool in_memory,
+      const base::DictionaryValue& options = base::DictionaryValue());
+
+  void SetUserAgent(const std::string& user_agent);
 
   // brightray::URLRequestContextGetter::Delegate:
   net::NetworkDelegate* CreateNetworkDelegate() override;
@@ -40,16 +45,21 @@ class AtomBrowserContext : public brightray::BrowserContext {
   // brightray::BrowserContext:
   void RegisterPrefs(PrefRegistrySimple* pref_registry) override;
 
-  AtomCertVerifier* cert_verifier() const { return cert_verifier_; }
   AtomNetworkDelegate* network_delegate() const { return network_delegate_; }
 
+ protected:
+  AtomBrowserContext(const std::string& partition, bool in_memory,
+                     const base::DictionaryValue& options);
+  ~AtomBrowserContext() override;
+
  private:
   std::unique_ptr<AtomDownloadManagerDelegate> download_manager_delegate_;
   std::unique_ptr<WebViewManager> guest_manager_;
   std::unique_ptr<AtomPermissionManager> permission_manager_;
+  std::string user_agent_;
+  bool use_cache_;
 
   // Managed by brightray::BrowserContext.
-  AtomCertVerifier* cert_verifier_;
   AtomNetworkDelegate* network_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext);

+ 6 - 2
atom/browser/atom_browser_main_parts.cc

@@ -15,7 +15,7 @@
 #include "atom/common/node_bindings.h"
 #include "atom/common/node_includes.h"
 #include "base/command_line.h"
-#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
 #include "v8/include/v8-debug.h"
 
@@ -32,7 +32,7 @@ void Erase(T* container, typename T::iterator iter) {
 }
 
 // static
-AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
+AtomBrowserMainParts* AtomBrowserMainParts::self_ = nullptr;
 
 AtomBrowserMainParts::AtomBrowserMainParts()
     : fake_browser_process_(new BrowserProcess),
@@ -124,6 +124,8 @@ void AtomBrowserMainParts::PostEarlyInitialization() {
 }
 
 void AtomBrowserMainParts::PreMainMessageLoopRun() {
+  js_env_->OnMessageLoopCreated();
+
   // Run user's main script before most things get initialized, so we can have
   // a chance to setup everything.
   node_bindings_->PrepareMessageLoop();
@@ -169,6 +171,8 @@ void AtomBrowserMainParts::PostMainMessageLoopStart() {
 void AtomBrowserMainParts::PostMainMessageLoopRun() {
   brightray::BrowserMainParts::PostMainMessageLoopRun();
 
+  js_env_->OnMessageLoopDestroying();
+
 #if defined(OS_MACOSX)
   FreeAppDelegate();
 #endif

+ 5 - 5
atom/browser/atom_browser_main_parts_posix.cc

@@ -43,7 +43,7 @@ void GracefulShutdownHandler(int signal) {
   struct sigaction action;
   memset(&action, 0, sizeof(action));
   action.sa_handler = SIG_DFL;
-  RAW_CHECK(sigaction(signal, &action, NULL) == 0);
+  RAW_CHECK(sigaction(signal, &action, nullptr) == 0);
 
   RAW_CHECK(g_pipe_pid == getpid());
   RAW_CHECK(g_shutdown_pipe_write_fd != -1);
@@ -171,7 +171,7 @@ void AtomBrowserMainParts::HandleSIGCHLD() {
   struct sigaction action;
   memset(&action, 0, sizeof(action));
   action.sa_handler = SIGCHLDHandler;
-  CHECK_EQ(sigaction(SIGCHLD, &action, NULL), 0);
+  CHECK_EQ(sigaction(SIGCHLD, &action, nullptr), 0);
 }
 
 void AtomBrowserMainParts::HandleShutdownSignals() {
@@ -211,15 +211,15 @@ void AtomBrowserMainParts::HandleShutdownSignals() {
   struct sigaction action;
   memset(&action, 0, sizeof(action));
   action.sa_handler = SIGTERMHandler;
-  CHECK_EQ(sigaction(SIGTERM, &action, NULL), 0);
+  CHECK_EQ(sigaction(SIGTERM, &action, nullptr), 0);
   // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If
   // the browser process is being debugged, GDB will catch the SIGINT first.
   action.sa_handler = SIGINTHandler;
-  CHECK_EQ(sigaction(SIGINT, &action, NULL), 0);
+  CHECK_EQ(sigaction(SIGINT, &action, nullptr), 0);
   // And SIGHUP, for when the terminal disappears. On shutdown, many Linux
   // distros send SIGHUP, SIGTERM, and then SIGKILL.
   action.sa_handler = SIGHUPHandler;
-  CHECK_EQ(sigaction(SIGHUP, &action, NULL), 0);
+  CHECK_EQ(sigaction(SIGHUP, &action, nullptr), 0);
 }
 
 }  // namespace atom

+ 8 - 0
atom/browser/atom_download_manager_delegate.cc

@@ -85,6 +85,14 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
         download_manager_->GetBrowserContext());
     browser_context->prefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
                                           path.DirName());
+
+    v8::Isolate* isolate = v8::Isolate::GetCurrent();
+    v8::Locker locker(isolate);
+    v8::HandleScope handle_scope(isolate);
+    api::DownloadItem* download_item = api::DownloadItem::FromWrappedClass(
+        isolate, item);
+    if (download_item)
+      download_item->SetSavePath(path);
   }
 
   // Running the DownloadTargetCallback with an empty FilePath signals that the

+ 8 - 1
atom/browser/atom_resource_dispatcher_host_delegate.cc

@@ -7,6 +7,7 @@
 #include "atom/browser/login_handler.h"
 #include "atom/browser/web_contents_permission_helper.h"
 #include "atom/common/platform_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/escape.h"
 #include "url/gurl.h"
@@ -20,7 +21,13 @@ namespace {
 void OnOpenExternal(const GURL& escaped_url,
                     bool allowed) {
   if (allowed)
-    platform_util::OpenExternal(escaped_url, true);
+    platform_util::OpenExternal(
+#if defined(OS_WIN)
+        base::UTF8ToUTF16(escaped_url.spec()),
+#else
+        escaped_url,
+#endif
+        true);
 }
 
 void HandleExternalProtocolInUI(

+ 8 - 2
atom/browser/atom_security_state_model_client.cc

@@ -91,8 +91,14 @@ void AtomSecurityStateModelClient::GetVisibleSecurityState(
   state->connection_status = ssl.connection_status;
   state->security_bits = ssl.security_bits;
   state->sct_verify_statuses.clear();
-  for (const auto& sct : ssl.signed_certificate_timestamp_ids)
-    state->sct_verify_statuses.push_back(sct.status);
+  state->sct_verify_statuses.insert(state->sct_verify_statuses.end(),
+                                    ssl.num_unknown_scts,
+                                    net::ct::SCT_STATUS_LOG_UNKNOWN);
+  state->sct_verify_statuses.insert(state->sct_verify_statuses.end(),
+                                    ssl.num_invalid_scts,
+                                    net::ct::SCT_STATUS_INVALID);
+  state->sct_verify_statuses.insert(state->sct_verify_statuses.end(),
+                                    ssl.num_valid_scts, net::ct::SCT_STATUS_OK);
   state->displayed_mixed_content =
       (ssl.content_status & content::SSLStatus::DISPLAYED_INSECURE_CONTENT)
           ? true

+ 0 - 5
atom/browser/atom_speech_recognition_manager_delegate.cc

@@ -50,11 +50,6 @@ void AtomSpeechRecognitionManagerDelegate::OnAudioLevelsChange(
     int session_id, float volume, float noise_volume) {
 }
 
-void AtomSpeechRecognitionManagerDelegate::GetDiagnosticInformation(
-    bool* can_report_metrics, std::string* hardware_info) {
-  *can_report_metrics = false;
-}
-
 void AtomSpeechRecognitionManagerDelegate::CheckRecognitionIsAllowed(
     int session_id,
     base::Callback<void(bool ask_user, bool is_allowed)> callback) {

+ 0 - 2
atom/browser/atom_speech_recognition_manager_delegate.h

@@ -36,8 +36,6 @@ class AtomSpeechRecognitionManagerDelegate
                            float noise_volume) override;
 
   // content::SpeechRecognitionManagerDelegate:
-  void GetDiagnosticInformation(bool* can_report_metrics,
-                                std::string* hardware_info) override;
   void CheckRecognitionIsAllowed(
       int session_id,
       base::Callback<void(bool ask_user, bool is_allowed)> callback) override;

+ 4 - 0
atom/browser/auto_updater.cc

@@ -17,6 +17,10 @@ void AutoUpdater::SetDelegate(Delegate* delegate) {
 }
 
 #if !defined(OS_MACOSX) || defined(MAS_BUILD)
+std::string AutoUpdater::GetFeedURL() {
+  return "";
+}
+
 void AutoUpdater::SetFeedURL(const std::string& url,
                              const HeaderMap& requestHeaders) {
 }

+ 1 - 0
atom/browser/auto_updater.h

@@ -49,6 +49,7 @@ class AutoUpdater {
   static Delegate* GetDelegate();
   static void SetDelegate(Delegate* delegate);
 
+  static std::string GetFeedURL();
   static void SetFeedURL(const std::string& url,
                          const HeaderMap& requestHeaders);
   static void CheckForUpdates();

+ 7 - 0
atom/browser/auto_updater_mac.mm

@@ -25,9 +25,14 @@ SQRLUpdater* g_updater = nil;
 namespace {
 
 bool g_update_available = false;
+std::string update_url_ = "";
 
 }
 
+std::string AutoUpdater::GetFeedURL() {
+  return update_url_;
+}
+
 // static
 void AutoUpdater::SetFeedURL(const std::string& feed,
                              const HeaderMap& requestHeaders) {
@@ -35,6 +40,8 @@ void AutoUpdater::SetFeedURL(const std::string& feed,
   if (!delegate)
     return;
 
+  update_url_ = feed;
+
   NSURL* url = [NSURL URLWithString:base::SysUTF8ToNSString(feed)];
   NSMutableURLRequest* urlRequest = [NSMutableURLRequest requestWithURL:url];
 

+ 10 - 0
atom/browser/browser.cc

@@ -118,6 +118,10 @@ void Browser::SetName(const std::string& name) {
   name_override_ = name;
 }
 
+int Browser::GetBadgeCount() {
+  return badge_count_;
+}
+
 bool Browser::OpenFile(const std::string& file_path) {
   bool prevent_default = false;
   FOR_EACH_OBSERVER(BrowserObserver,
@@ -151,6 +155,12 @@ void Browser::DidFinishLaunching() {
   FOR_EACH_OBSERVER(BrowserObserver, observers_, OnFinishLaunching());
 }
 
+void Browser::OnAccessibilitySupportChanged() {
+  FOR_EACH_OBSERVER(BrowserObserver,
+                    observers_,
+                    OnAccessibilitySupportChanged());
+}
+
 void Browser::RequestLogin(
     LoginHandler* login_handler,
     std::unique_ptr<base::DictionaryValue> request_details) {

+ 27 - 6
atom/browser/browser.h

@@ -25,16 +25,13 @@ class DictionaryValue;
 class FilePath;
 }
 
-namespace ui {
-class MenuModel;
-}
-
 namespace gfx {
 class Image;
 }
 
 namespace atom {
 
+class AtomMenuModel;
 class LoginHandler;
 
 // This class is used for control application-wide operations.
@@ -87,6 +84,21 @@ class Browser : public WindowListObserver {
   // Query the current state of default handler for a protocol.
   bool IsDefaultProtocolClient(const std::string& protocol);
 
+  // Set/Get the badge count.
+  bool SetBadgeCount(int count);
+  int GetBadgeCount();
+
+  // Set/Get the login item settings of the app
+  struct LoginItemSettings {
+    bool open_at_login = false;
+    bool open_as_hidden = false;
+    bool restore_state = false;
+    bool opened_at_login = false;
+    bool opened_as_hidden = false;
+  };
+  void SetLoginItemSettings(LoginItemSettings settings);
+  LoginItemSettings GetLoginItemSettings();
+
 #if defined(OS_MACOSX)
   // Hide the application.
   void Hide();
@@ -126,7 +138,7 @@ class Browser : public WindowListObserver {
   void DockShow();
 
   // Set docks' menu.
-  void DockSetMenu(ui::MenuModel* model);
+  void DockSetMenu(AtomMenuModel* model);
 
   // Set docks' icon.
   void DockSetIcon(const gfx::Image& image);
@@ -149,7 +161,12 @@ class Browser : public WindowListObserver {
   // one from app's name.
   // The returned string managed by Browser, and should not be modified.
   PCWSTR GetAppUserModelID();
-#endif
+#endif  // defined(OS_WIN)
+
+#if defined(OS_LINUX)
+  // Whether Unity launcher is running.
+  bool IsUnityRunning();
+#endif  // defined(OS_LINUX)
 
   // Tell the application to open a file.
   bool OpenFile(const std::string& file_path);
@@ -165,6 +182,8 @@ class Browser : public WindowListObserver {
   void WillFinishLaunching();
   void DidFinishLaunching();
 
+  void OnAccessibilitySupportChanged();
+
   // Request basic auth login.
   void RequestLogin(LoginHandler* login_handler,
                     std::unique_ptr<base::DictionaryValue> request_details);
@@ -216,6 +235,8 @@ class Browser : public WindowListObserver {
   std::string version_override_;
   std::string name_override_;
 
+  int badge_count_ = 0;
+
 #if defined(OS_WIN)
   base::string16 app_user_model_id_;
 #endif

+ 22 - 0
atom/browser/browser_linux.cc

@@ -10,6 +10,7 @@
 #include "atom/browser/window_list.h"
 #include "atom/common/atom_version.h"
 #include "brightray/common/application_info.h"
+#include "chrome/browser/ui/libgtk2ui/unity_service.h"
 
 namespace atom {
 
@@ -46,6 +47,23 @@ bool Browser::IsDefaultProtocolClient(const std::string& protocol) {
   return false;
 }
 
+bool Browser::SetBadgeCount(int count) {
+  if (IsUnityRunning()) {
+    unity::SetDownloadCount(count);
+    badge_count_ = count;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+void Browser::SetLoginItemSettings(LoginItemSettings settings) {
+}
+
+Browser::LoginItemSettings Browser::GetLoginItemSettings() {
+  return LoginItemSettings();
+}
+
 std::string Browser::GetExecutableFileVersion() const {
   return brightray::GetApplicationVersion();
 }
@@ -54,4 +72,8 @@ std::string Browser::GetExecutableFileProductName() const {
   return brightray::GetApplicationName();
 }
 
+bool Browser::IsUnityRunning() {
+  return unity::IsRunning();
+}
+
 }  // namespace atom

+ 26 - 1
atom/browser/browser_mac.mm

@@ -11,6 +11,8 @@
 #include "atom/browser/window_list.h"
 #include "base/mac/bundle_locations.h"
 #include "base/mac/foundation_util.h"
+#include "base/mac/mac_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/sys_string_conversions.h"
 #include "brightray/common/application_info.h"
 #include "net/base/mac/url_conversions.h"
@@ -114,6 +116,12 @@ bool Browser::IsDefaultProtocolClient(const std::string& protocol) {
 void Browser::SetAppUserModelID(const base::string16& name) {
 }
 
+bool Browser::SetBadgeCount(int count) {
+  DockSetBadgeText(count != 0 ? base::IntToString(count) : "");
+  badge_count_ = count;
+  return true;
+}
+
 void Browser::SetUserActivity(const std::string& type,
                               const base::DictionaryValue& user_info,
                               mate::Arguments* args) {
@@ -141,6 +149,23 @@ bool Browser::ContinueUserActivity(const std::string& type,
   return prevent_default;
 }
 
+Browser::LoginItemSettings Browser::GetLoginItemSettings() {
+  LoginItemSettings settings;
+  settings.open_at_login = base::mac::CheckLoginItemStatus(
+      &settings.open_as_hidden);
+  settings.restore_state = base::mac::WasLaunchedAsLoginItemRestoreState();
+  settings.opened_at_login = base::mac::WasLaunchedAsLoginOrResumeItem();
+  settings.opened_as_hidden = base::mac::WasLaunchedAsHiddenLoginItem();
+  return settings;
+}
+
+void Browser::SetLoginItemSettings(LoginItemSettings settings) {
+  if (settings.open_at_login)
+    base::mac::AddToLoginItems(settings.open_as_hidden);
+  else
+    base::mac::RemoveFromLoginItems();
+}
+
 std::string Browser::GetExecutableFileVersion() const {
   return brightray::GetApplicationVersion();
 }
@@ -209,7 +234,7 @@ void Browser::DockShow() {
   }
 }
 
-void Browser::DockSetMenu(ui::MenuModel* model) {
+void Browser::DockSetMenu(AtomMenuModel* model) {
   AtomApplicationDelegate* delegate = (AtomApplicationDelegate*)[NSApp delegate];
   [delegate setApplicationDockMenu:model];
 }

+ 3 - 0
atom/browser/browser_observer.h

@@ -52,6 +52,9 @@ class BrowserObserver {
   virtual void OnLogin(LoginHandler* login_handler,
                        const base::DictionaryValue& request_details) {}
 
+  // The browser's accessibility suppport has changed.
+  virtual void OnAccessibilitySupportChanged() {}
+
 #if defined(OS_MACOSX)
   // The browser wants to resume a user activity via handoff. (macOS only)
   virtual void OnContinueUserActivity(

+ 37 - 1
atom/browser/browser_win.cc

@@ -13,7 +13,6 @@
 #include "base/base_paths.h"
 #include "base/file_version_info.h"
 #include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -269,6 +268,43 @@ bool Browser::IsDefaultProtocolClient(const std::string& protocol) {
   }
 }
 
+bool Browser::SetBadgeCount(int count) {
+  return false;
+}
+
+void Browser::SetLoginItemSettings(LoginItemSettings settings) {
+  std::wstring keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
+  base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS);
+
+  if (settings.open_at_login) {
+    base::FilePath path;
+    if (PathService::Get(base::FILE_EXE, &path)) {
+      std::wstring exePath(path.value());
+      key.WriteValue(GetAppUserModelID(), exePath.c_str());
+    }
+  } else {
+    key.DeleteValue(GetAppUserModelID());
+  }
+}
+
+Browser::LoginItemSettings Browser::GetLoginItemSettings() {
+  LoginItemSettings settings;
+  std::wstring keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
+  base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS);
+  std::wstring keyVal;
+
+  if (!FAILED(key.ReadValue(GetAppUserModelID(), &keyVal))) {
+    base::FilePath path;
+    if (PathService::Get(base::FILE_EXE, &path)) {
+      std::wstring exePath(path.value());
+      settings.open_at_login = keyVal == exePath;
+    }
+  }
+
+  return settings;
+}
+
+
 PCWSTR Browser::GetAppUserModelID() {
   if (app_user_model_id_.empty()) {
     SetAppUserModelID(base::ReplaceStringPlaceholders(

+ 7 - 8
atom/browser/common_web_contents_delegate.cc

@@ -94,7 +94,7 @@ FileSystem CreateFileSystemStruct(
 }
 
 base::DictionaryValue* CreateFileSystemValue(const FileSystem& file_system) {
-  base::DictionaryValue* file_system_value = new base::DictionaryValue();
+  auto* file_system_value = new base::DictionaryValue();
   file_system_value->SetString("fileSystemName", file_system.file_system_name);
   file_system_value->SetString("rootURL", file_system.root_url);
   file_system_value->SetString("fileSystemPath", file_system.file_system_path);
@@ -377,7 +377,7 @@ content::SecurityStyle CommonWebContentsDelegate::GetSecurityStyle(
 void CommonWebContentsDelegate::DevToolsSaveToFile(
     const std::string& url, const std::string& content, bool save_as) {
   base::FilePath path;
-  PathsMap::iterator it = saved_files_.find(url);
+  auto it = saved_files_.find(url);
   if (it != saved_files_.end() && !save_as) {
     path = it->second;
   } else {
@@ -402,7 +402,7 @@ void CommonWebContentsDelegate::DevToolsSaveToFile(
 
 void CommonWebContentsDelegate::DevToolsAppendToFile(
     const std::string& url, const std::string& content) {
-  PathsMap::iterator it = saved_files_.find(url);
+  auto it = saved_files_.find(url);
   if (it == saved_files_.end())
     return;
 
@@ -435,8 +435,8 @@ void CommonWebContentsDelegate::DevToolsRequestFileSystems() {
   }
 
   base::ListValue file_system_value;
-  for (size_t i = 0; i < file_systems.size(); ++i)
-    file_system_value.Append(CreateFileSystemValue(file_systems[i]));
+  for (const auto& file_system : file_systems)
+    file_system_value.Append(CreateFileSystemValue(file_system));
   web_contents_->CallClientFunction("DevToolsAPI.fileSystemsLoaded",
                                     &file_system_value, nullptr, nullptr);
 }
@@ -610,9 +610,8 @@ void CommonWebContentsDelegate::OnDevToolsSearchCompleted(
     const std::string& file_system_path,
     const std::vector<std::string>& file_paths) {
   base::ListValue file_paths_value;
-  for (std::vector<std::string>::const_iterator it(file_paths.begin());
-       it != file_paths.end(); ++it) {
-    file_paths_value.AppendString(*it);
+  for (const auto& file_path : file_paths) {
+    file_paths_value.AppendString(file_path);
   }
   base::FundamentalValue request_id_value(request_id);
   base::StringValue file_system_path_value(file_system_path);

+ 7 - 1
atom/browser/common_web_contents_delegate_mac.mm

@@ -27,7 +27,13 @@ void CommonWebContentsDelegate::HandleKeyboardEvent(
   if (event.windowsKeyCode == ui::VKEY_ESCAPE && is_html_fullscreen())
     ExitFullscreenModeForTab(source);
 
-  if (event.os_event.window)
+  // Send the event to the menu before sending it to the window
+  if (event.os_event.type == NSKeyDown &&
+      [[NSApp mainMenu] performKeyEquivalent:event.os_event])
+    return;
+
+  if (event.os_event.window &&
+      [event.os_event.window isKindOfClass:[EventDispatchingWindow class]])
     [event.os_event.window redispatchKeyEvent:event.os_event];
 }
 

+ 9 - 0
atom/browser/javascript_environment.cc

@@ -7,6 +7,7 @@
 #include <string>
 
 #include "base/command_line.h"
+#include "base/message_loop/message_loop.h"
 #include "content/public/common/content_switches.h"
 #include "gin/array_buffer.h"
 #include "gin/v8_initializer.h"
@@ -23,6 +24,14 @@ JavascriptEnvironment::JavascriptEnvironment()
       context_scope_(v8::Local<v8::Context>::New(isolate_, context_)) {
 }
 
+void JavascriptEnvironment::OnMessageLoopCreated() {
+  isolate_holder_.AddRunMicrotasksObserver();
+}
+
+void JavascriptEnvironment::OnMessageLoopDestroying() {
+  isolate_holder_.RemoveRunMicrotasksObserver();
+}
+
 bool JavascriptEnvironment::Initialize() {
   auto cmd = base::CommandLine::ForCurrentProcess();
   if (cmd->HasSwitch("debug-brk")) {

+ 3 - 0
atom/browser/javascript_environment.h

@@ -14,6 +14,9 @@ class JavascriptEnvironment {
  public:
   JavascriptEnvironment();
 
+  void OnMessageLoopCreated();
+  void OnMessageLoopDestroying();
+
   v8::Isolate* isolate() const { return isolate_; }
   v8::Local<v8::Context> context() const {
     return v8::Local<v8::Context>::New(isolate_, context_);

+ 2 - 0
atom/browser/mac/atom_application.mm

@@ -83,6 +83,8 @@
   } else {
     ax_state->DisableAccessibility();
   }
+
+  atom::Browser::Get()->OnAccessibilitySupportChanged();
 }
 
 @end

+ 1 - 3
atom/browser/mac/atom_application_delegate.h

@@ -11,9 +11,7 @@
   base::scoped_nsobject<AtomMenuController> menu_controller_;
 }
 
-- (id)init;
-
 // Sets the menu that will be returned in "applicationDockMenu:".
-- (void)setApplicationDockMenu:(ui::MenuModel*)model;
+- (void)setApplicationDockMenu:(atom::AtomMenuModel*)model;
 
 @end

+ 7 - 9
atom/browser/mac/atom_application_delegate.mm

@@ -12,14 +12,9 @@
 
 @implementation AtomApplicationDelegate
 
-- (id)init {
-  self = [super init];
-  menu_controller_.reset([[AtomMenuController alloc] init]);
-  return self;
-}
-
-- (void)setApplicationDockMenu:(ui::MenuModel*)model {
-  [menu_controller_ populateWithModel:model];
+- (void)setApplicationDockMenu:(atom::AtomMenuModel*)model {
+  menu_controller_.reset([[AtomMenuController alloc] initWithModel:model
+                                             useDefaultAccelerator:NO]);
 }
 
 - (void)applicationWillFinishLaunching:(NSNotification*)notify {
@@ -34,7 +29,10 @@
 }
 
 - (NSMenu*)applicationDockMenu:(NSApplication*)sender {
-  return [menu_controller_ menu];
+  if (menu_controller_)
+    return [menu_controller_ menu];
+  else
+    return nil;
 }
 
 - (BOOL)application:(NSApplication*)sender

+ 2 - 2
atom/browser/mac/dict_util.h

@@ -5,9 +5,9 @@
 #ifndef ATOM_BROWSER_MAC_DICT_UTIL_H_
 #define ATOM_BROWSER_MAC_DICT_UTIL_H_
 
-#import <Foundation/Foundation.h>
+#include <memory>
 
-#include "base/memory/scoped_ptr.h"
+#import <Foundation/Foundation.h>
 
 namespace base {
 class ListValue;

+ 24 - 49
atom/browser/native_window.cc

@@ -11,6 +11,7 @@
 #include "atom/browser/atom_browser_context.h"
 #include "atom/browser/atom_browser_main_parts.h"
 #include "atom/browser/browser.h"
+#include "atom/browser/unresponsive_suppressor.h"
 #include "atom/browser/window_list.h"
 #include "atom/common/api/api_messages.h"
 #include "atom/common/native_mate_converters/file_path_converter.h"
@@ -37,9 +38,13 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/screen.h"
 #include "ui/gl/gpu_switching_manager.h"
 
+#if defined(OS_LINUX) || defined(OS_WIN)
+#include "content/public/common/renderer_preferences.h"
+#include "ui/gfx/font_render_params.h"
+#endif
+
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::NativeWindowRelay);
 
 namespace atom {
@@ -53,7 +58,6 @@ NativeWindow::NativeWindow(
       transparent_(false),
       enable_larger_than_screen_(false),
       is_closed_(false),
-      has_dialog_attached_(false),
       sheet_offset_x_(0.0),
       sheet_offset_y_(0.0),
       aspect_ratio_(0.0),
@@ -68,6 +72,20 @@ NativeWindow::NativeWindow(
   if (parent)
     options.Get("modal", &is_modal_);
 
+#if defined(OS_LINUX) || defined(OS_WIN)
+  auto* prefs = web_contents()->GetMutableRendererPrefs();
+
+  // Update font settings.
+  CR_DEFINE_STATIC_LOCAL(const gfx::FontRenderParams, params,
+      (gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr)));
+  prefs->should_antialias_text = params.antialiasing;
+  prefs->use_subpixel_positioning = params.subpixel_positioning;
+  prefs->hinting = params.hinting;
+  prefs->use_autohinter = params.autohinter;
+  prefs->use_bitmaps = params.use_bitmaps;
+  prefs->subpixel_rendering = params.subpixel_rendering;
+#endif
+
   // Tell the content module to initialize renderer widget with transparent
   // mode.
   ui::GpuSwitchingManager::SetTransparent(transparent_);
@@ -210,7 +228,7 @@ gfx::Size NativeWindow::GetContentSize() {
 
 void NativeWindow::SetSizeConstraints(
     const extensions::SizeConstraints& window_constraints) {
-  extensions::SizeConstraints content_constraints;
+  extensions::SizeConstraints content_constraints(GetContentSizeConstraints());
   if (window_constraints.HasMaximumSize())
     content_constraints.set_maximum_size(
         WindowSizeToContentSize(window_constraints.GetMaximumSize()));
@@ -291,11 +309,7 @@ bool NativeWindow::IsDocumentEdited() {
 void NativeWindow::SetFocusable(bool focusable) {
 }
 
-void NativeWindow::SetMenu(ui::MenuModel* menu) {
-}
-
-bool NativeWindow::HasModalDialog() {
-  return has_dialog_attached_;
+void NativeWindow::SetMenu(AtomMenuModel* menu) {
 }
 
 void NativeWindow::SetParentWindow(NativeWindow* parent) {
@@ -315,39 +329,6 @@ bool NativeWindow::IsWebViewFocused() {
   return host_view && host_view->HasFocus();
 }
 
-void NativeWindow::CapturePage(const gfx::Rect& rect,
-                               const CapturePageCallback& callback) {
-  const auto view = web_contents()->GetRenderWidgetHostView();
-  const auto host = view ? view->GetRenderWidgetHost() : nullptr;
-  if (!view || !host) {
-    callback.Run(SkBitmap());
-    return;
-  }
-
-  // Capture full page if user doesn't specify a |rect|.
-  const gfx::Size view_size = rect.IsEmpty() ? view->GetViewBounds().size() :
-                                               rect.size();
-
-  // By default, the requested bitmap size is the view size in screen
-  // coordinates.  However, if there's more pixel detail available on the
-  // current system, increase the requested bitmap size to capture it all.
-  gfx::Size bitmap_size = view_size;
-  const gfx::NativeView native_view = view->GetNativeView();
-  const float scale =
-      gfx::Screen::GetScreen()->GetDisplayNearestWindow(native_view)
-      .device_scale_factor();
-  if (scale > 1.0f)
-    bitmap_size = gfx::ScaleToCeiledSize(view_size, scale);
-
-  host->CopyFromBackingStore(
-      gfx::Rect(rect.origin(), view_size),
-      bitmap_size,
-      base::Bind(&NativeWindow::OnCapturePageDone,
-                 weak_factory_.GetWeakPtr(),
-                 callback),
-      kBGRA_8888_SkColorType);
-}
-
 void NativeWindow::SetAutoHideMenuBar(bool auto_hide) {
 }
 
@@ -394,7 +375,7 @@ void NativeWindow::RequestToClosePage() {
     ScheduleUnresponsiveEvent(5000);
 
   if (web_contents()->NeedToFireBeforeUnload())
-    web_contents()->DispatchBeforeUnload(false);
+    web_contents()->DispatchBeforeUnload();
   else
     web_contents()->Close();
 }
@@ -624,7 +605,7 @@ void NativeWindow::ScheduleUnresponsiveEvent(int ms) {
 void NativeWindow::NotifyWindowUnresponsive() {
   window_unresposive_closure_.Cancel();
 
-  if (!is_closed_ && !HasModalDialog() && IsEnabled())
+  if (!is_closed_ && !IsUnresponsiveEventSuppressed() && IsEnabled())
     FOR_EACH_OBSERVER(NativeWindowObserver,
                       observers_,
                       OnRendererUnresponsive());
@@ -634,10 +615,4 @@ void NativeWindow::NotifyReadyToShow() {
   FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnReadyToShow());
 }
 
-void NativeWindow::OnCapturePageDone(const CapturePageCallback& callback,
-                                     const SkBitmap& bitmap,
-                                     content::ReadbackResponse response) {
-  callback.Run(bitmap);
-}
-
 }  // namespace atom

+ 5 - 46
atom/browser/native_window.h

@@ -6,13 +6,14 @@
 #define ATOM_BROWSER_NATIVE_WINDOW_H_
 
 #include <map>
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "atom/browser/native_window_observer.h"
 #include "atom/browser/ui/accelerator_util.h"
+#include "atom/browser/ui/atom_menu_model.h"
 #include "base/cancelable_callback.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/supports_user_data.h"
@@ -43,10 +44,6 @@ namespace mate {
 class Dictionary;
 }
 
-namespace ui {
-class MenuModel;
-}
-
 namespace atom {
 
 struct DraggableRegion;
@@ -54,28 +51,7 @@ struct DraggableRegion;
 class NativeWindow : public base::SupportsUserData,
                      public content::WebContentsObserver {
  public:
-  using CapturePageCallback = base::Callback<void(const SkBitmap& bitmap)>;
-
-  class DialogScope {
-   public:
-    explicit DialogScope(NativeWindow* window)
-        : window_(window) {
-      if (window_ != NULL)
-        window_->set_has_dialog_attached(true);
-    }
-
-    ~DialogScope() {
-      if (window_ != NULL)
-        window_->set_has_dialog_attached(false);
-    }
-
-   private:
-    NativeWindow* window_;
-
-    DISALLOW_COPY_AND_ASSIGN(DialogScope);
-  };
-
-  virtual ~NativeWindow();
+  ~NativeWindow() override;
 
   // Create window with existing WebContents, the caller is responsible for
   // managing the window's live.
@@ -157,9 +133,9 @@ class NativeWindow : public base::SupportsUserData,
   virtual void SetDocumentEdited(bool edited);
   virtual bool IsDocumentEdited();
   virtual void SetIgnoreMouseEvents(bool ignore) = 0;
+  virtual void SetContentProtection(bool enable) = 0;
   virtual void SetFocusable(bool focusable);
-  virtual void SetMenu(ui::MenuModel* menu);
-  virtual bool HasModalDialog();
+  virtual void SetMenu(AtomMenuModel* menu);
   virtual void SetParentWindow(NativeWindow* parent);
   virtual gfx::NativeWindow GetNativeWindow() = 0;
   virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0;
@@ -178,11 +154,6 @@ class NativeWindow : public base::SupportsUserData,
   virtual void BlurWebView();
   virtual bool IsWebViewFocused();
 
-  // Captures the page with |rect|, |callback| would be called when capturing is
-  // done.
-  virtual void CapturePage(const gfx::Rect& rect,
-                           const CapturePageCallback& callback);
-
   // Toggle the menu bar.
   virtual void SetAutoHideMenuBar(bool auto_hide);
   virtual bool IsMenuBarAutoHide();
@@ -254,10 +225,6 @@ class NativeWindow : public base::SupportsUserData,
   SkRegion* draggable_region() const { return draggable_region_.get(); }
   bool enable_larger_than_screen() const { return enable_larger_than_screen_; }
 
-  void set_has_dialog_attached(bool has_dialog_attached) {
-    has_dialog_attached_ = has_dialog_attached;
-  }
-
   NativeWindow* parent() const { return parent_; }
   bool is_modal() const { return is_modal_; }
 
@@ -295,11 +262,6 @@ class NativeWindow : public base::SupportsUserData,
   // Dispatch ReadyToShow event to observers.
   void NotifyReadyToShow();
 
-  // Called when CapturePage has done.
-  void OnCapturePageDone(const CapturePageCallback& callback,
-                         const SkBitmap& bitmap,
-                         content::ReadbackResponse response);
-
   // Whether window has standard frame.
   bool has_frame_;
 
@@ -319,9 +281,6 @@ class NativeWindow : public base::SupportsUserData,
   // The windows has been closed.
   bool is_closed_;
 
-  // There is a dialog that has been attached to window.
-  bool has_dialog_attached_;
-
   // Closure that would be called when window is unresponsive when closing,
   // it should be cancelled when we can prove that the window is responsive.
   base::CancelableClosure window_unresposive_closure_;

+ 1 - 1
atom/browser/native_window_mac.h

@@ -79,7 +79,7 @@ class NativeWindowMac : public NativeWindow {
   void SetDocumentEdited(bool edited) override;
   bool IsDocumentEdited() override;
   void SetIgnoreMouseEvents(bool ignore) override;
-  bool HasModalDialog() override;
+  void SetContentProtection(bool enable) override;
   void SetParentWindow(NativeWindow* parent) override;
   gfx::NativeWindow GetNativeWindow() override;
   gfx::AcceleratedWidget GetAcceleratedWidget() override;

+ 53 - 34
atom/browser/native_window_mac.mm

@@ -70,6 +70,7 @@ bool ScopedDisableResize::disable_resize_ = false;
 @interface AtomNSWindowDelegate : NSObject<NSWindowDelegate> {
  @private
   atom::NativeWindowMac* shell_;
+  bool is_zooming_;
 }
 - (id)initWithShell:(atom::NativeWindowMac*)shell;
 @end
@@ -79,6 +80,7 @@ bool ScopedDisableResize::disable_resize_ = false;
 - (id)initWithShell:(atom::NativeWindowMac*)shell {
   if ((self = [super init])) {
     shell_ = shell;
+    is_zooming_ = false;
   }
   return self;
 }
@@ -172,16 +174,20 @@ bool ScopedDisableResize::disable_resize_ = false;
 }
 
 - (BOOL)windowShouldZoom:(NSWindow*)window toFrame:(NSRect)newFrame {
-  // Cocoa doen't have concept of maximize/unmaximize, so wee need to emulate
-  // them by calculating size change when zooming.
-  if (newFrame.size.width < [window frame].size.width ||
-      newFrame.size.height < [window frame].size.height)
-    shell_->NotifyWindowUnmaximize();
-  else
-    shell_->NotifyWindowMaximize();
+  is_zooming_ = true;
   return YES;
 }
 
+- (void)windowDidEndLiveResize:(NSNotification*)notification {
+  if (is_zooming_) {
+    if (shell_->IsMaximized())
+      shell_->NotifyWindowMaximize();
+    else
+      shell_->NotifyWindowUnmaximize();
+    is_zooming_ = false;
+  }
+}
+
 - (void)windowWillEnterFullScreen:(NSNotification*)notification {
   // Hide the native toolbar before entering fullscreen, so there is no visual
   // artifacts.
@@ -199,6 +205,7 @@ bool ScopedDisableResize::disable_resize_ = false;
   // have to set one, because title bar is visible here.
   NSWindow* window = shell_->GetNativeWindow();
   if ((shell_->transparent() || !shell_->has_frame()) &&
+      base::mac::IsOSYosemiteOrLater() &&
       // FIXME(zcbenz): Showing titlebar for hiddenInset window is weird under
       // fullscreen mode.
       shell_->title_bar_style() != atom::NativeWindowMac::HIDDEN_INSET) {
@@ -223,6 +230,7 @@ bool ScopedDisableResize::disable_resize_ = false;
   // Restore the titlebar visibility.
   NSWindow* window = shell_->GetNativeWindow();
   if ((shell_->transparent() || !shell_->has_frame()) &&
+      base::mac::IsOSYosemiteOrLater() &&
       shell_->title_bar_style() != atom::NativeWindowMac::HIDDEN_INSET) {
     [window setTitleVisibility:NSWindowTitleHidden];
   }
@@ -233,13 +241,6 @@ bool ScopedDisableResize::disable_resize_ = false;
 }
 
 - (void)windowDidExitFullScreen:(NSNotification*)notification {
-  // For certain versions of macOS the fullscreen button will automatically show
-  // after exiting fullscreen mode.
-  if (!shell_->has_frame()) {
-    NSWindow* window = shell_->GetNativeWindow();
-    [[window standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
-  }
-
   shell_->NotifyWindowLeaveFullScreen();
 }
 
@@ -526,8 +527,10 @@ NativeWindowMac::NativeWindowMac(
     [window_ setDisableKeyOrMainWindow:YES];
 
   if (transparent() || !has_frame()) {
-    // Don't show title bar.
-    [window_ setTitleVisibility:NSWindowTitleHidden];
+    if (base::mac::IsOSYosemiteOrLater()) {
+      // Don't show title bar.
+      [window_ setTitleVisibility:NSWindowTitleHidden];
+    }
     // Remove non-transparent corners, see http://git.io/vfonD.
     [window_ setOpaque:NO];
   }
@@ -714,11 +717,6 @@ void NativeWindowMac::SetFullScreen(bool fullscreen) {
   if (fullscreen == IsFullscreen())
     return;
 
-  if (!base::mac::IsOSLionOrLater()) {
-    LOG(ERROR) << "Fullscreen mode is only supported above Lion";
-    return;
-  }
-
   [window_ toggleFullScreen:nil];
 }
 
@@ -727,13 +725,22 @@ bool NativeWindowMac::IsFullscreen() const {
 }
 
 void NativeWindowMac::SetBounds(const gfx::Rect& bounds, bool animate) {
-  NSRect cocoa_bounds = NSMakeRect(bounds.x(), 0,
-                                   bounds.width(),
-                                   bounds.height());
+  // Do nothing if in fullscreen mode.
+  if (IsFullscreen())
+    return;
+
+  // Check size constraints since setFrame does not check it.
+  gfx::Size size = bounds.size();
+  size.SetToMax(GetMinimumSize());
+  gfx::Size max_size = GetMaximumSize();
+  if (!max_size.IsEmpty())
+    size.SetToMin(max_size);
+
+  NSRect cocoa_bounds = NSMakeRect(bounds.x(), 0, size.width(), size.height());
   // Flip coordinates based on the primary screen.
   NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
   cocoa_bounds.origin.y =
-      NSHeight([screen frame]) - bounds.height() - bounds.y();
+      NSHeight([screen frame]) - size.height() - bounds.y();
 
   [window_ setFrame:cocoa_bounds display:YES animate:animate];
 }
@@ -785,13 +792,13 @@ bool NativeWindowMac::IsResizable() {
 
 void NativeWindowMac::SetAspectRatio(double aspect_ratio,
                                      const gfx::Size& extra_size) {
-    NativeWindow::SetAspectRatio(aspect_ratio, extra_size);
+  NativeWindow::SetAspectRatio(aspect_ratio, extra_size);
 
-    // Reset the behaviour to default if aspect_ratio is set to 0 or less.
-    if (aspect_ratio > 0.0)
-      [window_ setAspectRatio:NSMakeSize(aspect_ratio, 1.0)];
-    else
-      [window_ setResizeIncrements:NSMakeSize(1.0, 1.0)];
+  // Reset the behaviour to default if aspect_ratio is set to 0 or less.
+  if (aspect_ratio > 0.0)
+    [window_ setAspectRatio:NSMakeSize(aspect_ratio, 1.0)];
+  else
+    [window_ setResizeIncrements:NSMakeSize(1.0, 1.0)];
 }
 
 void NativeWindowMac::SetMovable(bool movable) {
@@ -852,6 +859,11 @@ void NativeWindowMac::Center() {
 }
 
 void NativeWindowMac::SetTitle(const std::string& title) {
+  // For macOS <= 10.9, the setTitleVisibility API is not available, we have
+  // to avoid calling setTitle for frameless window.
+  if (!base::mac::IsOSYosemiteOrLater() && (transparent() || !has_frame()))
+    return;
+
   [window_ setTitle:base::SysUTF8ToNSString(title)];
 }
 
@@ -935,8 +947,9 @@ void NativeWindowMac::SetIgnoreMouseEvents(bool ignore) {
   [window_ setIgnoresMouseEvents:ignore];
 }
 
-bool NativeWindowMac::HasModalDialog() {
-  return [window_ attachedSheet] != nil;
+void NativeWindowMac::SetContentProtection(bool enable) {
+  [window_ setSharingType:enable ? NSWindowSharingNone
+                                 : NSWindowSharingReadOnly];
 }
 
 void NativeWindowMac::SetParentWindow(NativeWindow* parent) {
@@ -1057,7 +1070,10 @@ void NativeWindowMac::UpdateDraggableRegions(
 
 void NativeWindowMac::InstallView() {
   // Make sure the bottom corner is rounded: http://crbug.com/396264.
-  [[window_ contentView] setWantsLayer:YES];
+  // But do not enable it on OS X 10.9 for transparent window, otherwise a
+  // semi-transparent frame would show.
+  if (!(transparent() && base::mac::IsOSMavericks()))
+    [[window_ contentView] setWantsLayer:YES];
 
   NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
   if (has_frame()) {
@@ -1077,6 +1093,9 @@ void NativeWindowMac::InstallView() {
     [view setFrame:[content_view_ bounds]];
     [content_view_ addSubview:view];
 
+    // The fullscreen button should always be hidden for frameless window.
+    [[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
+
     if (title_bar_style_ != NORMAL)
       return;
 

+ 97 - 29
atom/browser/native_window_views.cc

@@ -51,7 +51,9 @@
 #include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h"
 #include "skia/ext/skia_utils_win.h"
 #include "ui/base/win/shell.h"
-#include "ui/gfx/win/dpi.h"
+#include "ui/display/win/screen_win.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
 #endif
 
@@ -135,6 +137,10 @@ NativeWindowViews::NativeWindowViews(
       menu_bar_autohide_(false),
       menu_bar_visible_(false),
       menu_bar_alt_pressed_(false),
+#if defined(OS_WIN)
+      enabled_a11y_support_(false),
+      thick_frame_(true),
+#endif
       keyboard_event_handler_(new views::UnhandledKeyboardEventHandler),
       disable_count_(0),
       use_content_size_(false),
@@ -152,6 +158,11 @@ NativeWindowViews::NativeWindowViews(
   options.Get(options::kResizable, &resizable_);
   options.Get(options::kMinimizable, &minimizable_);
   options.Get(options::kMaximizable, &maximizable_);
+
+  // Transparent window must not have thick frame.
+  options.Get("thickFrame", &thick_frame_);
+  if (transparent())
+    thick_frame_ = false;
 #endif
 
   if (enable_larger_than_screen())
@@ -214,6 +225,9 @@ NativeWindowViews::NativeWindowViews(
   bool fullscreen = false;
   options.Get(options::kFullscreen, &fullscreen);
 
+  std::string window_type;
+  options.Get(options::kType, &window_type);
+
 #if defined(USE_X11)
   // Start monitoring window states.
   window_state_watcher_.reset(new WindowStateWatcher(this));
@@ -243,9 +257,6 @@ NativeWindowViews::NativeWindowViews(
     state_atom_list.push_back(GetAtom("_NET_WM_STATE_FULLSCREEN"));
   }
 
-  std::string window_type;
-  options.Get(options::kType, &window_type);
-
   if (parent) {
     SetParentWindow(parent);
     // Force using dialog type for child window.
@@ -269,13 +280,6 @@ NativeWindowViews::NativeWindowViews(
   AddChildView(web_view_);
 
 #if defined(OS_WIN)
-  // Save initial window state.
-  if (fullscreen)
-    last_window_state_ = ui::SHOW_STATE_FULLSCREEN;
-  else
-    last_window_state_ = ui::SHOW_STATE_NORMAL;
-  last_normal_size_ = gfx::Size(widget_size_);
-
   if (!has_frame()) {
     // Set Window style so that we get a minimize and maximize animation when
     // frameless.
@@ -287,17 +291,18 @@ NativeWindowViews::NativeWindowViews(
     if (maximizable_)
       frame_style |= WS_MAXIMIZEBOX;
     // We should not show a frame for transparent window.
-    if (transparent())
+    if (!thick_frame_)
       frame_style &= ~(WS_THICKFRAME | WS_CAPTION);
     ::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, frame_style);
   }
 
-  if (transparent()) {
-    // Transparent window on Windows has to have WS_EX_COMPOSITED style.
-    LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
+  LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
+  // Window without thick frame has to have WS_EX_COMPOSITED style.
+  if (!thick_frame_)
     ex_style |= WS_EX_COMPOSITED;
-    ::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style);
-  }
+  if (window_type == "toolbar")
+    ex_style |= WS_EX_TOOLWINDOW;
+  ::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style);
 #endif
 
   // TODO(zcbenz): This was used to force using native frame on Windows 2003, we
@@ -315,6 +320,15 @@ NativeWindowViews::NativeWindowViews(
 
   window_->CenterWindow(size);
   Layout();
+
+#if defined(OS_WIN)
+  // Save initial window state.
+  if (fullscreen)
+    last_window_state_ = ui::SHOW_STATE_FULLSCREEN;
+  else
+    last_window_state_ = ui::SHOW_STATE_NORMAL;
+  last_normal_bounds_ = GetBounds();
+#endif
 }
 
 NativeWindowViews::~NativeWindowViews() {
@@ -335,6 +349,10 @@ void NativeWindowViews::CloseImmediately() {
 }
 
 void NativeWindowViews::Focus(bool focus) {
+  // For hidden window focus() should do nothing.
+  if (!IsVisible())
+    return;
+
   if (focus) {
 #if defined(OS_WIN)
     window_->Activate();
@@ -406,6 +424,17 @@ bool NativeWindowViews::IsEnabled() {
 }
 
 void NativeWindowViews::Maximize() {
+#if defined(OS_WIN)
+  // For window without WS_THICKFRAME style, we can not call Maximize().
+  if (!thick_frame_) {
+    restore_bounds_ = GetBounds();
+    auto display =
+        display::Screen::GetScreen()->GetDisplayNearestPoint(GetPosition());
+    SetBounds(display.work_area(), false);
+    return;
+  }
+#endif
+
   if (IsVisible())
     window_->Maximize();
   else
@@ -414,6 +443,13 @@ void NativeWindowViews::Maximize() {
 }
 
 void NativeWindowViews::Unmaximize() {
+#if defined(OS_WIN)
+  if (!thick_frame_) {
+    SetBounds(restore_bounds_, false);
+    return;
+  }
+#endif
+
   window_->Restore();
 }
 
@@ -450,6 +486,20 @@ void NativeWindowViews::SetFullScreen(bool fullscreen) {
     last_window_state_ = ui::SHOW_STATE_NORMAL;
     NotifyWindowLeaveFullScreen();
   }
+
+  // For window without WS_THICKFRAME style, we can not call SetFullscreen().
+  if (!thick_frame_) {
+    if (fullscreen) {
+      restore_bounds_ = GetBounds();
+      auto display =
+          display::Screen::GetScreen()->GetDisplayNearestPoint(GetPosition());
+      SetBounds(display.bounds(), false);
+    } else {
+      SetBounds(restore_bounds_, false);
+    }
+    return;
+  }
+
   // We set the new value after notifying, so we can handle the size event
   // correctly.
   window_->SetFullscreen(fullscreen);
@@ -459,6 +509,12 @@ void NativeWindowViews::SetFullScreen(bool fullscreen) {
   else
     window_->native_widget_private()->ShowWithWindowState(
         ui::SHOW_STATE_FULLSCREEN);
+
+  // Auto-hide menubar when in fullscreen.
+  if (fullscreen)
+    SetMenuBarVisibility(false);
+  else
+    SetMenuBarVisibility(!menu_bar_autohide_);
 #endif
 }
 
@@ -466,8 +522,7 @@ bool NativeWindowViews::IsFullscreen() const {
   return window_->IsFullscreen();
 }
 
-void NativeWindowViews::SetBounds(const gfx::Rect& bounds,
-    bool animate = false) {
+void NativeWindowViews::SetBounds(const gfx::Rect& bounds, bool animate) {
 #if defined(USE_X11)
   // On Linux the minimum and maximum size should be updated with window size
   // when window is not resizable.
@@ -513,7 +568,7 @@ void NativeWindowViews::SetContentSizeConstraints(
 
 void NativeWindowViews::SetResizable(bool resizable) {
 #if defined(OS_WIN)
-  if (!transparent())
+  if (thick_frame_)
     FlipWindowStyle(GetAcceleratedWidget(), resizable, WS_THICKFRAME);
 #elif defined(USE_X11)
   if (resizable != resizable_) {
@@ -536,7 +591,11 @@ void NativeWindowViews::SetResizable(bool resizable) {
 
 bool NativeWindowViews::IsResizable() {
 #if defined(OS_WIN)
-  return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME;
+  if (thick_frame_) {
+    return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME;
+  } else {
+    return CanResize();
+  }
 #else
   return CanResize();
 #endif
@@ -728,6 +787,13 @@ void NativeWindowViews::SetIgnoreMouseEvents(bool ignore) {
 #endif
 }
 
+void NativeWindowViews::SetContentProtection(bool enable) {
+#if defined(OS_WIN)
+  DWORD affinity = enable ? WDA_MONITOR : WDA_NONE;
+  ::SetWindowDisplayAffinity(GetAcceleratedWidget(), affinity);
+#endif
+}
+
 void NativeWindowViews::SetFocusable(bool focusable) {
 #if defined(OS_WIN)
   LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
@@ -741,7 +807,7 @@ void NativeWindowViews::SetFocusable(bool focusable) {
 #endif
 }
 
-void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
+void NativeWindowViews::SetMenu(AtomMenuModel* menu_model) {
   if (menu_model == nullptr) {
     // Remove accelerators
     accelerator_table_.clear();
@@ -1086,9 +1152,11 @@ gfx::Size NativeWindowViews::ContentSizeToWindowSize(const gfx::Size& size) {
 
   gfx::Size window_size(size);
 #if defined(OS_WIN)
-  gfx::Rect dpi_bounds =
-      gfx::Rect(gfx::Point(), gfx::win::DIPToScreenSize(size));
-  gfx::Rect window_bounds = gfx::win::ScreenToDIPRect(
+  HWND hwnd = GetAcceleratedWidget();
+  gfx::Rect dpi_bounds = gfx::Rect(
+      gfx::Point(), display::win::ScreenWin::DIPToScreenSize(hwnd, size));
+  gfx::Rect window_bounds = display::win::ScreenWin::ScreenToDIPRect(
+      hwnd,
       window_->non_client_view()->GetWindowBoundsForClientBounds(dpi_bounds));
   window_size = window_bounds.size();
 #endif
@@ -1104,16 +1172,16 @@ gfx::Size NativeWindowViews::WindowSizeToContentSize(const gfx::Size& size) {
 
   gfx::Size content_size(size);
 #if defined(OS_WIN)
-  content_size = gfx::win::DIPToScreenSize(content_size);
+  HWND hwnd = GetAcceleratedWidget();
+  content_size = display::win::ScreenWin::DIPToScreenSize(hwnd, content_size);
   RECT rect;
   SetRectEmpty(&rect);
-  HWND hwnd = GetAcceleratedWidget();
   DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
   DWORD ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
   AdjustWindowRectEx(&rect, style, FALSE, ex_style);
   content_size.set_width(content_size.width() - (rect.right - rect.left));
   content_size.set_height(content_size.height() - (rect.bottom - rect.top));
-  content_size = gfx::win::ScreenToDIPSize(content_size);
+  content_size = display::win::ScreenWin::ScreenToDIPSize(hwnd, content_size);
 #endif
 
   if (menu_bar_ && menu_bar_visible_)
@@ -1175,7 +1243,7 @@ bool NativeWindowViews::AcceleratorPressed(const ui::Accelerator& accelerator) {
       &accelerator_table_, accelerator);
 }
 
-void NativeWindowViews::RegisterAccelerators(ui::MenuModel* menu_model) {
+void NativeWindowViews::RegisterAccelerators(AtomMenuModel* menu_model) {
   // Clear previous accelerators.
   views::FocusManager* focus_manager = GetFocusManager();
   accelerator_table_.clear();

+ 10 - 3
atom/browser/native_window_views.h

@@ -96,8 +96,9 @@ class NativeWindowViews : public NativeWindow,
   void SetHasShadow(bool has_shadow) override;
   bool HasShadow() override;
   void SetIgnoreMouseEvents(bool ignore) override;
+  void SetContentProtection(bool enable) override;
   void SetFocusable(bool focusable) override;
-  void SetMenu(ui::MenuModel* menu_model) override;
+  void SetMenu(AtomMenuModel* menu_model) override;
   void SetParentWindow(NativeWindow* parent) override;
   gfx::NativeWindow GetNativeWindow() override;
   void SetOverlayIcon(const gfx::Image& overlay,
@@ -175,7 +176,7 @@ class NativeWindowViews : public NativeWindow,
   bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
 
   // Register accelerators supported by the menu model.
-  void RegisterAccelerators(ui::MenuModel* menu_model);
+  void RegisterAccelerators(AtomMenuModel* menu_model);
 
   // Returns the restore state for the window.
   ui::WindowShowState GetRestoredState();
@@ -211,7 +212,7 @@ class NativeWindowViews : public NativeWindow,
   // to receive the wrong size (#2498). To circumvent that, we keep tabs on the
   // size of the window while in the normal state (not maximized, minimized or
   // fullscreen), so we restore it correctly.
-  gfx::Size last_normal_size_;
+  gfx::Rect last_normal_bounds_;
 
   // In charge of running taskbar related APIs.
   TaskbarHost taskbar_host_;
@@ -219,6 +220,12 @@ class NativeWindowViews : public NativeWindow,
   // If true we have enabled a11y
   bool enabled_a11y_support_;
 
+  // Whether to show the WS_THICKFRAME style.
+  bool thick_frame_;
+
+  // The bounds of window before maximize/fullscreen.
+  gfx::Rect restore_bounds_;
+
   // The icons of window and taskbar.
   base::win::ScopedHICON window_icon_;
   base::win::ScopedHICON app_icon_;

+ 9 - 4
atom/browser/native_window_views_win.cc

@@ -2,6 +2,7 @@
 // Use of this source code is governed by the MIT license that can be
 // found in the LICENSE file.
 
+#include "atom/browser/browser.h"
 #include "atom/browser/native_window_views.h"
 #include "content/public/browser/browser_accessibility_state.h"
 
@@ -98,6 +99,7 @@ bool NativeWindowViews::PreHandleMSG(
         if (axState && !axState->IsAccessibleBrowser()) {
           axState->OnScreenReaderDetected();
           enabled_a11y_support_ = true;
+          Browser::Get()->OnAccessibilitySupportChanged();
         }
       }
 
@@ -119,7 +121,10 @@ bool NativeWindowViews::PreHandleMSG(
         ::GetWindowRect(GetAcceleratedWidget(), (LPRECT)l_param);
       return false;
     }
-
+    case WM_MOVE: {
+      last_normal_bounds_ = GetBounds();
+      return false;
+    }
     default:
       return false;
   }
@@ -140,7 +145,7 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
     case SIZE_RESTORED:
       if (last_window_state_ == ui::SHOW_STATE_NORMAL) {
         // Window was resized so we save it's new size.
-        last_normal_size_ = GetSize();
+        last_normal_bounds_ = GetBounds();
       } else {
         switch (last_window_state_) {
           case ui::SHOW_STATE_MAXIMIZED:
@@ -148,7 +153,7 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
 
             // When the window is restored we resize it to the previous known
             // normal size.
-            NativeWindow::SetSize(last_normal_size_);
+            SetBounds(last_normal_bounds_, false);
 
             NotifyWindowUnmaximize();
             break;
@@ -161,7 +166,7 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
 
               // When the window is restored we resize it to the previous known
               // normal size.
-              NativeWindow::SetSize(last_normal_size_);
+              SetBounds(last_normal_bounds_, false);
 
               NotifyWindowRestore();
             }

+ 1 - 1
atom/browser/net/asar/asar_protocol_handler.cc

@@ -22,7 +22,7 @@ net::URLRequestJob* AsarProtocolHandler::MaybeCreateJob(
     net::NetworkDelegate* network_delegate) const {
   base::FilePath full_path;
   net::FileURLToFilePath(request->url(), &full_path);
-  URLRequestAsarJob* job = new URLRequestAsarJob(request, network_delegate);
+  auto* job = new URLRequestAsarJob(request, network_delegate);
   job->Initialize(file_task_runner_, full_path);
   return job;
 }

+ 5 - 5
atom/browser/net/asar/url_request_asar_job.cc

@@ -111,7 +111,7 @@ void URLRequestAsarJob::Start() {
     if (rv != net::ERR_IO_PENDING)
       DidOpen(rv);
   } else if (type_ == TYPE_FILE) {
-    FileMetaInfo* meta_info = new FileMetaInfo();
+    auto* meta_info = new FileMetaInfo();
     file_task_runner_->PostTaskAndReply(
         FROM_HERE,
         base::Bind(&URLRequestAsarJob::FetchMetaInfo, file_path_,
@@ -180,10 +180,10 @@ bool URLRequestAsarJob::IsRedirectResponse(GURL* location,
 #endif
 }
 
-net::Filter* URLRequestAsarJob::SetupFilter() const {
+std::unique_ptr<net::Filter> URLRequestAsarJob::SetupFilter() const {
   // Bug 9936 - .svgz files needs to be decompressed.
   return base::LowerCaseEqualsASCII(file_path_.Extension(), ".svgz")
-      ? net::Filter::GZipFactory() : NULL;
+      ? net::Filter::GZipFactory() : nullptr;
 }
 
 bool URLRequestAsarJob::GetMimeType(std::string* mime_type) const {
@@ -224,7 +224,7 @@ int URLRequestAsarJob::GetResponseCode() const {
 
 void URLRequestAsarJob::GetResponseInfo(net::HttpResponseInfo* info) {
   std::string status("HTTP/1.1 200 OK");
-  net::HttpResponseHeaders* headers = new net::HttpResponseHeaders(status);
+  auto* headers = new net::HttpResponseHeaders(status);
 
   headers->AddHeader(atom::kCORSHeader);
   info->headers = headers;
@@ -338,7 +338,7 @@ void URLRequestAsarJob::DidRead(scoped_refptr<net::IOBuffer> buf, int result) {
     DCHECK_GE(remaining_bytes_, 0);
   }
 
-  buf = NULL;
+  buf = nullptr;
 
   ReadRawDataComplete(result);
 }

+ 1 - 1
atom/browser/net/asar/url_request_asar_job.h

@@ -56,7 +56,7 @@ class URLRequestAsarJob : public net::URLRequestJob {
   void Kill() override;
   int ReadRawData(net::IOBuffer* buf, int buf_size) override;
   bool IsRedirectResponse(GURL* location, int* http_status_code) override;
-  net::Filter* SetupFilter() const override;
+  std::unique_ptr<net::Filter> SetupFilter() const override;
   bool GetMimeType(std::string* mime_type) const override;
   void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
   int GetResponseCode() const override;

+ 2 - 9
atom/browser/net/atom_cert_verifier.cc

@@ -36,7 +36,6 @@ AtomCertVerifier::~AtomCertVerifier() {
 }
 
 void AtomCertVerifier::SetVerifyProc(const VerifyProc& proc) {
-  base::AutoLock auto_lock(lock_);
   verify_proc_ = proc;
 }
 
@@ -52,20 +51,14 @@ int AtomCertVerifier::Verify(
     const net::BoundNetLog& net_log) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  VerifyProc proc;
-  {
-    base::AutoLock auto_lock(lock_);
-    proc = verify_proc_;
-  }
-
-  if (proc.is_null())
+  if (verify_proc_.is_null())
     return default_cert_verifier_->Verify(
         cert, hostname, ocsp_response, flags, crl_set, verify_result, callback,
         out_req, net_log);
 
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(proc, hostname, make_scoped_refptr(cert),
+      base::Bind(verify_proc_, hostname, make_scoped_refptr(cert),
                  base::Bind(OnResult, verify_result, callback)));
   return net::ERR_IO_PENDING;
 }

+ 1 - 3
atom/browser/net/atom_cert_verifier.h

@@ -5,10 +5,9 @@
 #ifndef ATOM_BROWSER_NET_ATOM_CERT_VERIFIER_H_
 #define ATOM_BROWSER_NET_ATOM_CERT_VERIFIER_H_
 
+#include <memory>
 #include <string>
 
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
 #include "net/cert/cert_verifier.h"
 
 namespace atom {
@@ -39,7 +38,6 @@ class AtomCertVerifier : public net::CertVerifier {
   bool SupportsOCSPStapling() override;
 
  private:
-  base::Lock lock_;
   VerifyProc verify_proc_;
   std::unique_ptr<net::CertVerifier> default_cert_verifier_;
 

+ 8 - 4
atom/browser/net/atom_url_request_job_factory.cc

@@ -20,14 +20,14 @@ typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
 AtomURLRequestJobFactory::AtomURLRequestJobFactory() {}
 
 AtomURLRequestJobFactory::~AtomURLRequestJobFactory() {
-  STLDeleteValues(&protocol_handler_map_);
+  Clear();
 }
 
 bool AtomURLRequestJobFactory::SetProtocolHandler(
     const std::string& scheme,
     std::unique_ptr<ProtocolHandler> protocol_handler) {
   if (!protocol_handler) {
-    ProtocolHandlerMap::iterator it = protocol_handler_map_.find(scheme);
+    auto it = protocol_handler_map_.find(scheme);
     if (it == protocol_handler_map_.end())
       return false;
 
@@ -66,7 +66,7 @@ ProtocolHandler* AtomURLRequestJobFactory::GetProtocolHandler(
     const std::string& scheme) const {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  ProtocolHandlerMap::const_iterator it = protocol_handler_map_.find(scheme);
+  auto it = protocol_handler_map_.find(scheme);
   if (it == protocol_handler_map_.end())
     return nullptr;
   return it->second;
@@ -77,13 +77,17 @@ bool AtomURLRequestJobFactory::HasProtocolHandler(
   return ContainsKey(protocol_handler_map_, scheme);
 }
 
+void AtomURLRequestJobFactory::Clear() {
+  STLDeleteValues(&protocol_handler_map_);
+}
+
 net::URLRequestJob* AtomURLRequestJobFactory::MaybeCreateJobWithProtocolHandler(
     const std::string& scheme,
     net::URLRequest* request,
     net::NetworkDelegate* network_delegate) const {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  ProtocolHandlerMap::const_iterator it = protocol_handler_map_.find(scheme);
+  auto it = protocol_handler_map_.find(scheme);
   if (it == protocol_handler_map_.end())
     return nullptr;
   return it->second->MaybeCreateJob(request, network_delegate);

+ 3 - 0
atom/browser/net/atom_url_request_job_factory.h

@@ -39,6 +39,9 @@ class AtomURLRequestJobFactory : public net::URLRequestJobFactory {
   // Whether the protocol handler is registered by the job factory.
   bool HasProtocolHandler(const std::string& scheme) const;
 
+  // Clear all protocol handlers.
+  void Clear();
+
   // URLRequestJobFactory implementation
   net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
       const std::string& scheme,

+ 1 - 1
atom/browser/net/url_request_async_asar_job.cc

@@ -40,7 +40,7 @@ void URLRequestAsyncAsarJob::StartAsync(std::unique_ptr<base::Value> options) {
 
 void URLRequestAsyncAsarJob::GetResponseInfo(net::HttpResponseInfo* info) {
   std::string status("HTTP/1.1 200 OK");
-  net::HttpResponseHeaders* headers = new net::HttpResponseHeaders(status);
+  auto* headers = new net::HttpResponseHeaders(status);
 
   headers->AddHeader(kCORSHeader);
   info->headers = headers;

+ 1 - 1
atom/browser/net/url_request_buffer_job.cc

@@ -72,7 +72,7 @@ void URLRequestBufferJob::GetResponseInfo(net::HttpResponseInfo* info) {
   status.append(" ");
   status.append(net::GetHttpReasonPhrase(status_code_));
   status.append("\0\0", 2);
-  net::HttpResponseHeaders* headers = new net::HttpResponseHeaders(status);
+  auto* headers = new net::HttpResponseHeaders(status);
 
   headers->AddHeader(kCORSHeader);
 

+ 2 - 1
atom/browser/net/url_request_fetch_job.cc

@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <string>
 
+#include "base/memory/ptr_util.h"
 #include "base/strings/string_util.h"
 #include "native_mate/dictionary.h"
 #include "net/base/io_buffer.h"
@@ -132,7 +133,7 @@ void URLRequestFetchJob::StartAsync(std::unique_ptr<base::Value> options) {
     request_type = GetRequestType(method);
 
   fetcher_ = net::URLFetcher::Create(formated_url, request_type, this);
-  fetcher_->SaveResponseWithWriter(make_scoped_ptr(new ResponsePiper(this)));
+  fetcher_->SaveResponseWithWriter(base::WrapUnique(new ResponsePiper(this)));
 
   // A request context getter is passed by the user.
   if (url_request_context_getter_)

+ 1 - 1
atom/browser/net/url_request_string_job.cc

@@ -31,7 +31,7 @@ void URLRequestStringJob::StartAsync(std::unique_ptr<base::Value> options) {
 
 void URLRequestStringJob::GetResponseInfo(net::HttpResponseInfo* info) {
   std::string status("HTTP/1.1 200 OK");
-  net::HttpResponseHeaders* headers = new net::HttpResponseHeaders(status);
+  auto* headers = new net::HttpResponseHeaders(status);
 
   headers->AddHeader(kCORSHeader);
 

+ 1 - 1
atom/browser/node_debugger.h

@@ -5,9 +5,9 @@
 #ifndef ATOM_BROWSER_NODE_DEBUGGER_H_
 #define ATOM_BROWSER_NODE_DEBUGGER_H_
 
+#include <memory>
 #include <string>
 
-#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread.h"
 #include "net/test/embedded_test_server/stream_listen_socket.h"

+ 10 - 0
atom/browser/relauncher_linux.cc

@@ -4,11 +4,13 @@
 
 #include "atom/browser/relauncher.h"
 
+#include <fcntl.h>
 #include <signal.h>
 #include <sys/prctl.h>
 #include <sys/signalfd.h>
 
 #include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
 #include "base/logging.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/process/launch.h"
@@ -55,9 +57,17 @@ void RelauncherSynchronizeWithParent() {
 
 int LaunchProgram(const StringVector& relauncher_args,
                   const StringVector& argv) {
+  // Redirect the stdout of child process to /dev/null, otherwise after
+  // relaunch the child process will raise exception when writing to stdout.
+  base::ScopedFD devnull(HANDLE_EINTR(open("/dev/null", O_WRONLY)));
+  base::FileHandleMappingVector no_stdout;
+  no_stdout.push_back(std::make_pair(devnull.get(), STDERR_FILENO));
+  no_stdout.push_back(std::make_pair(devnull.get(), STDOUT_FILENO));
+
   base::LaunchOptions options;
   options.allow_new_privs = true;
   options.new_process_group = true;  // detach
+  options.fds_to_remap = &no_stdout;
   base::Process process = base::LaunchProcess(argv, options);
   return process.IsValid() ? 0 : 1;
 }

+ 10 - 2
atom/browser/relauncher_mac.cc

@@ -43,7 +43,7 @@ void RelauncherSynchronizeWithParent() {
 
   struct kevent change = { 0 };
   EV_SET(&change, parent_pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
-  if (kevent(kq.get(), &change, 1, NULL, 0, NULL) == -1) {
+  if (kevent(kq.get(), &change, 1, nullptr, 0, nullptr) == -1) {
     PLOG(ERROR) << "kevent (add)";
     return;
   }
@@ -58,7 +58,7 @@ void RelauncherSynchronizeWithParent() {
   // write above to complete. The parent process is now free to exit. Wait for
   // that to happen.
   struct kevent event;
-  int events = kevent(kq.get(), NULL, 0, &event, 1, NULL);
+  int events = kevent(kq.get(), nullptr, 0, &event, 1, nullptr);
   if (events != 1) {
     if (events < 0) {
       PLOG(ERROR) << "kevent (monitor)";
@@ -79,8 +79,16 @@ void RelauncherSynchronizeWithParent() {
 
 int LaunchProgram(const StringVector& relauncher_args,
                   const StringVector& argv) {
+  // Redirect the stdout of child process to /dev/null, otherwise after
+  // relaunch the child process will raise exception when writing to stdout.
+  base::ScopedFD devnull(HANDLE_EINTR(open("/dev/null", O_WRONLY)));
+  base::FileHandleMappingVector no_stdout;
+  no_stdout.push_back(std::make_pair(devnull.get(), STDERR_FILENO));
+  no_stdout.push_back(std::make_pair(devnull.get(), STDOUT_FILENO));
+
   base::LaunchOptions options;
   options.new_process_group = true;  // detach
+  options.fds_to_remap = &no_stdout;
   base::Process process = base::LaunchProcess(argv, options);
   return process.IsValid() ? 0 : 1;
 }

+ 2 - 2
atom/browser/resources/mac/Info.plist

@@ -17,9 +17,9 @@
   <key>CFBundleIconFile</key>
   <string>electron.icns</string>
   <key>CFBundleVersion</key>
-  <string>1.2.3</string>
+  <string>1.3.1</string>
   <key>CFBundleShortVersionString</key>
-  <string>1.2.3</string>
+  <string>1.3.1</string>
   <key>LSApplicationCategoryType</key>
   <string>public.app-category.developer-tools</string>
   <key>LSMinimumSystemVersion</key>

BIN
atom/browser/resources/win/atom.ico


+ 4 - 4
atom/browser/resources/win/atom.rc

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

+ 8 - 8
atom/browser/ui/accelerator_util.cc

@@ -14,7 +14,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
-#include "ui/base/models/simple_menu_model.h"
 
 namespace accelerator_util {
 
@@ -31,9 +30,9 @@ bool StringToAccelerator(const std::string& shortcut,
   // Now, parse it into an accelerator.
   int modifiers = ui::EF_NONE;
   ui::KeyboardCode key = ui::VKEY_UNKNOWN;
-  for (size_t i = 0; i < tokens.size(); i++) {
+  for (const auto& token : tokens) {
     bool shifted = false;
-    ui::KeyboardCode code = atom::KeyboardCodeFromStr(tokens[i], &shifted);
+    ui::KeyboardCode code = atom::KeyboardCodeFromStr(token, &shifted);
     if (shifted)
       modifiers |= ui::EF_SHIFT_DOWN;
     switch (code) {
@@ -69,16 +68,17 @@ bool StringToAccelerator(const std::string& shortcut,
   return true;
 }
 
-void GenerateAcceleratorTable(AcceleratorTable* table, ui::MenuModel* model) {
+void GenerateAcceleratorTable(AcceleratorTable* table,
+                              atom::AtomMenuModel* model) {
   int count = model->GetItemCount();
   for (int i = 0; i < count; ++i) {
-    ui::MenuModel::ItemType type = model->GetTypeAt(i);
-    if (type == ui::MenuModel::TYPE_SUBMENU) {
-      ui::MenuModel* submodel = model->GetSubmenuModelAt(i);
+    atom::AtomMenuModel::ItemType type = model->GetTypeAt(i);
+    if (type == atom::AtomMenuModel::TYPE_SUBMENU) {
+      auto submodel = model->GetSubmenuModelAt(i);
       GenerateAcceleratorTable(table, submodel);
     } else {
       ui::Accelerator accelerator;
-      if (model->GetAcceleratorAt(i, &accelerator)) {
+      if (model->GetAcceleratorAtWithParams(i, true, &accelerator)) {
         MenuItem item = { i, model };
         (*table)[accelerator] = item;
       }

+ 4 - 6
atom/browser/ui/accelerator_util.h

@@ -8,15 +8,12 @@
 #include <map>
 #include <string>
 
+#include "atom/browser/ui/atom_menu_model.h"
 #include "ui/base/accelerators/accelerator.h"
 
-namespace ui {
-class MenuModel;
-}
-
 namespace accelerator_util {
 
-typedef struct { int position; ui::MenuModel* model; } MenuItem;
+typedef struct { int position; atom::AtomMenuModel* model; } MenuItem;
 typedef std::map<ui::Accelerator, MenuItem> AcceleratorTable;
 
 // Parse a string as an accelerator.
@@ -27,7 +24,8 @@ bool StringToAccelerator(const std::string& description,
 void SetPlatformAccelerator(ui::Accelerator* accelerator);
 
 // Generate a table that contains memu model's accelerators and command ids.
-void GenerateAcceleratorTable(AcceleratorTable* table, ui::MenuModel* model);
+void GenerateAcceleratorTable(AcceleratorTable* table,
+                              atom::AtomMenuModel* model);
 
 // Trigger command from the accelerators table.
 bool TriggerAcceleratorTableCommand(AcceleratorTable* table,

+ 4 - 0
atom/browser/ui/accelerator_util_mac.mm

@@ -29,6 +29,10 @@ void SetPlatformAccelerator(ui::Accelerator* accelerator) {
     modifiers ^= NSShiftKeyMask;
   }
 
+  if (character == NSDeleteFunctionKey) {
+    character = NSDeleteCharacter;
+  }
+
   NSString* characters =
       [[[NSString alloc] initWithCharacters:&character length:1] autorelease];
 

+ 21 - 3
atom/browser/ui/atom_menu_model.cc

@@ -17,19 +17,37 @@ AtomMenuModel::~AtomMenuModel() {
 }
 
 void AtomMenuModel::SetRole(int index, const base::string16& role) {
-  roles_[index] = role;
+  int command_id = GetCommandIdAt(index);
+  roles_[command_id] = role;
 }
 
 base::string16 AtomMenuModel::GetRoleAt(int index) {
-  if (ContainsKey(roles_, index))
-    return roles_[index];
+  int command_id = GetCommandIdAt(index);
+  if (ContainsKey(roles_, command_id))
+    return roles_[command_id];
   else
     return base::string16();
 }
 
+bool AtomMenuModel::GetAcceleratorAtWithParams(
+    int index,
+    bool use_default_accelerator,
+    ui::Accelerator* accelerator) const {
+  if (delegate_) {
+    return delegate_->GetAcceleratorForCommandIdWithParams(
+        GetCommandIdAt(index), use_default_accelerator, accelerator);
+  }
+  return false;
+}
+
 void AtomMenuModel::MenuClosed() {
   ui::SimpleMenuModel::MenuClosed();
   FOR_EACH_OBSERVER(Observer, observers_, MenuClosed());
 }
 
+AtomMenuModel* AtomMenuModel::GetSubmenuModelAt(int index) {
+  return static_cast<AtomMenuModel*>(
+      ui::SimpleMenuModel::GetSubmenuModelAt(index));
+}
+
 }  // namespace atom

+ 20 - 1
atom/browser/ui/atom_menu_model.h

@@ -17,6 +17,19 @@ class AtomMenuModel : public ui::SimpleMenuModel {
   class Delegate : public ui::SimpleMenuModel::Delegate {
    public:
     virtual ~Delegate() {}
+
+    virtual bool GetAcceleratorForCommandIdWithParams(
+        int command_id,
+        bool use_default_accelerator,
+        ui::Accelerator* accelerator) const = 0;
+
+   private:
+    // ui::SimpleMenuModel::Delegate:
+    bool GetAcceleratorForCommandId(int command_id,
+                                    ui::Accelerator* accelerator) {
+      return GetAcceleratorForCommandIdWithParams(
+          command_id, false, accelerator);
+    }
   };
 
   class Observer {
@@ -35,14 +48,20 @@ class AtomMenuModel : public ui::SimpleMenuModel {
 
   void SetRole(int index, const base::string16& role);
   base::string16 GetRoleAt(int index);
+  bool GetAcceleratorAtWithParams(int index,
+                                  bool use_default_accelerator,
+                                  ui::Accelerator* accelerator) const;
 
   // ui::SimpleMenuModel:
   void MenuClosed() override;
 
+  using SimpleMenuModel::GetSubmenuModelAt;
+  AtomMenuModel* GetSubmenuModelAt(int index);
+
  private:
   Delegate* delegate_;  // weak ref.
 
-  std::map<int, base::string16> roles_;
+  std::map<int, base::string16> roles_;  // command id -> role
   base::ObserverList<Observer> observers_;
 
   DISALLOW_COPY_AND_ASSIGN(AtomMenuModel);

+ 7 - 11
atom/browser/ui/cocoa/atom_menu_controller.h

@@ -11,8 +11,8 @@
 #include "base/mac/scoped_nsobject.h"
 #include "base/strings/string16.h"
 
-namespace ui {
-class MenuModel;
+namespace atom {
+class AtomMenuModel;
 }
 
 // A controller for the cross-platform menu model. The menu that's created
@@ -23,24 +23,20 @@ class MenuModel;
 // as it only maintains weak references.
 @interface AtomMenuController : NSObject<NSMenuDelegate> {
  @protected
-  ui::MenuModel* model_;  // weak
+  atom::AtomMenuModel* model_;  // weak
   base::scoped_nsobject<NSMenu> menu_;
   BOOL isMenuOpen_;
+  BOOL useDefaultAccelerator_;
 }
 
-@property(nonatomic, assign) ui::MenuModel* model;
-
-// NIB-based initializer. This does not create a menu. Clients can set the
-// properties of the object and the menu will be created upon the first call to
-// |-menu|. Note that the menu will be immutable after creation.
-- (id)init;
+@property(nonatomic, assign) atom::AtomMenuModel* model;
 
 // Builds a NSMenu from the pre-built model (must not be nil). Changes made
 // to the contents of the model after calling this will not be noticed.
-- (id)initWithModel:(ui::MenuModel*)model;
+- (id)initWithModel:(atom::AtomMenuModel*)model useDefaultAccelerator:(BOOL)use;
 
 // Populate current NSMenu with |model|.
-- (void)populateWithModel:(ui::MenuModel*)model;
+- (void)populateWithModel:(atom::AtomMenuModel*)model;
 
 // Programmatically close the constructed menu.
 - (void)cancel;

Some files were not shown because too many files changed in this diff