Browse Source

Merge remote-tracking branch 'origin/master' into chrome58

Kevin Sawicki 8 years ago
parent
commit
fb85b26767
49 changed files with 721 additions and 208 deletions
  1. 2 1
      README.md
  2. 55 2
      atom/browser/api/atom_api_app.cc
  3. 4 0
      atom/browser/api/atom_api_app.h
  4. 1 1
      atom/browser/api/atom_api_dialog.cc
  5. 9 0
      atom/browser/api/atom_api_web_contents.cc
  6. 1 0
      atom/browser/api/atom_api_web_contents.h
  7. 2 2
      atom/browser/resources/mac/Info.plist
  8. 4 4
      atom/browser/resources/win/atom.rc
  9. 98 0
      atom/browser/ui/certificate_trust_win.cc
  10. 10 0
      atom/browser/ui/cocoa/atom_touch_bar.mm
  11. 82 46
      atom/common/api/atom_bindings.cc
  12. 9 0
      atom/common/api/atom_bindings.h
  13. 1 1
      atom/common/atom_version.h
  14. 3 0
      atom/renderer/atom_sandboxed_renderer_client.cc
  15. 6 6
      docs-translations/es/project/README.md
  16. 1 1
      docs-translations/ko-KR/project/README.md
  17. 1 1
      docs-translations/pt-BR/project/README.md
  18. 1 1
      docs-translations/tr-TR/project/README.md
  19. 1 1
      docs-translations/zh-CN/project/README.md
  20. 2 2
      docs-translations/zh-TW/project/README.md
  21. 1 0
      docs/README.md
  22. 4 0
      docs/api/app.md
  23. 11 5
      docs/api/dialog.md
  24. 2 2
      docs/api/ipc-main.md
  25. 75 72
      docs/api/locales.md
  26. 12 0
      docs/api/process.md
  27. 6 0
      docs/api/structures/cpu-usage.md
  28. 8 0
      docs/api/structures/io-counters.md
  29. 12 0
      docs/api/structures/memory-info.md
  30. 4 0
      docs/api/structures/process-memory-info.md
  31. 8 3
      docs/api/touch-bar-segmented-control.md
  32. 1 1
      docs/glossary.md
  33. 2 48
      docs/tutorial/desktop-environment-integration.md
  34. 85 0
      docs/tutorial/notifications.md
  35. 4 4
      docs/tutorial/quick-start.md
  36. 1 1
      electron.gyp
  37. 1 0
      filenames.gypi
  38. 3 2
      lib/browser/api/touch-bar.js
  39. 3 0
      lib/sandboxed_renderer/init.js
  40. 2 1
      package.json
  41. 1 0
      script/cibuild
  42. 10 0
      script/create-dist.py
  43. 1 0
      script/upload.py
  44. 13 0
      spec/api-app-spec.js
  45. 77 0
      spec/api-browser-window-spec.js
  46. 26 0
      spec/api-process-spec.js
  47. 11 0
      spec/fixtures/api/allocate-memory.html
  48. 17 0
      spec/fixtures/api/beforeunload-false-prevent3.html
  49. 27 0
      spec/fixtures/api/sandbox.html

+ 2 - 1
README.md

@@ -72,10 +72,11 @@ locations:
 forums
 - `#atom-shell` channel on Freenode
 - [`Atom`](http://atom-slack.herokuapp.com/) channel on Slack
+- [`electron-ru`](https://telegram.me/electron_ru) *(Russian)*
 - [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)*
 - [`electron-kr`](http://www.meetup.com/electron-kr/) *(Korean)*
 - [`electron-jp`](https://electron-jp.slack.com) *(Japanese)*
-- [`electron-tr`](https://electron-tr.slack.com) *(Turkish)*
+- [`electron-tr`](http://electron-tr.herokuapp.com) *(Turkish)*
 - [`electron-id`](https://electron-id.slack.com) *(Indonesia)*
 
 Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron)

+ 55 - 2
atom/browser/api/atom_api_app.cc

@@ -34,12 +34,12 @@
 #include "chrome/browser/icon_manager.h"
 #include "chrome/common/chrome_paths.h"
 #include "content/public/browser/browser_accessibility_state.h"
+#include "content/public/browser/browser_child_process_host.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"
 #include "content/public/common/content_switches.h"
 #include "media/audio/audio_manager.h"
-#include "native_mate/dictionary.h"
 #include "native_mate/object_template_builder.h"
 #include "net/ssl/ssl_cert_request_info.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -337,6 +337,17 @@ namespace api {
 
 namespace {
 
+class AppIdProcessIterator : public base::ProcessIterator {
+ public:
+  AppIdProcessIterator() : base::ProcessIterator(nullptr) {}
+
+ protected:
+  bool IncludeEntry() override {
+    return (entry().parent_pid() == base::GetCurrentProcId() ||
+            entry().pid() == base::GetCurrentProcId());
+  }
+};
+
 IconLoader::IconSize GetIconSizeByString(const std::string& size) {
   if (size == "small") {
     return IconLoader::IconSize::SMALL;
@@ -912,6 +923,47 @@ void App::GetFileIcon(const base::FilePath& path,
   }
 }
 
+std::vector<mate::Dictionary> App::GetAppMemoryInfo(v8::Isolate* isolate) {
+  AppIdProcessIterator process_iterator;
+  auto process_entry = process_iterator.NextProcessEntry();
+  std::vector<mate::Dictionary> result;
+
+  while (process_entry != nullptr) {
+    int64_t pid = process_entry->pid();
+    auto process = base::Process::OpenWithExtraPrivileges(pid);
+
+#if defined(OS_MACOSX)
+    std::unique_ptr<base::ProcessMetrics> metrics(
+      base::ProcessMetrics::CreateProcessMetrics(
+        process.Handle(), content::BrowserChildProcessHost::GetPortProvider()));
+#else
+    std::unique_ptr<base::ProcessMetrics> metrics(
+      base::ProcessMetrics::CreateProcessMetrics(process.Handle()));
+#endif
+
+    mate::Dictionary pid_dict = mate::Dictionary::CreateEmpty(isolate);
+    mate::Dictionary memory_dict = mate::Dictionary::CreateEmpty(isolate);
+
+    memory_dict.Set("workingSetSize",
+            static_cast<double>(metrics->GetWorkingSetSize() >> 10));
+    memory_dict.Set("peakWorkingSetSize",
+            static_cast<double>(metrics->GetPeakWorkingSetSize() >> 10));
+
+    size_t private_bytes, shared_bytes;
+    if (metrics->GetMemoryBytes(&private_bytes, &shared_bytes)) {
+      memory_dict.Set("privateBytes", static_cast<double>(private_bytes >> 10));
+      memory_dict.Set("sharedBytes", static_cast<double>(shared_bytes >> 10));
+    }
+
+    pid_dict.Set("memory", memory_dict);
+    pid_dict.Set("pid", pid);
+    result.push_back(pid_dict);
+    process_entry = process_iterator.NextProcessEntry();
+  }
+
+  return result;
+}
+
 // static
 mate::Handle<App> App::Create(v8::Isolate* isolate) {
   return mate::CreateHandle(isolate, new App(isolate));
@@ -983,7 +1035,8 @@ void App::BuildPrototype(
                  &App::IsAccessibilitySupportEnabled)
       .SetMethod("disableHardwareAcceleration",
                  &App::DisableHardwareAcceleration)
-      .SetMethod("getFileIcon", &App::GetFileIcon);
+      .SetMethod("getFileIcon", &App::GetFileIcon)
+      .SetMethod("getAppMemoryInfo", &App::GetAppMemoryInfo);
 }
 
 }  // namespace api

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

@@ -13,10 +13,12 @@
 #include "atom/browser/browser.h"
 #include "atom/browser/browser_observer.h"
 #include "atom/common/native_mate_converters/callback.h"
+#include "base/process/process_iterator.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "chrome/browser/icon_manager.h"
 #include "chrome/browser/process_singleton.h"
 #include "content/public/browser/gpu_data_manager_observer.h"
+#include "native_mate/dictionary.h"
 #include "native_mate/handle.h"
 #include "net/base/completion_callback.h"
 
@@ -141,6 +143,8 @@ class App : public AtomBrowserClient::Delegate,
   void GetFileIcon(const base::FilePath& path,
                    mate::Arguments* args);
 
+  std::vector<mate::Dictionary> GetAppMemoryInfo(v8::Isolate* isolate);
+
 #if defined(OS_WIN)
   // Get the current Jump List settings.
   v8::Local<v8::Value> GetJumpListSettings();

+ 1 - 1
atom/browser/api/atom_api_dialog.cc

@@ -129,7 +129,7 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
   dict.SetMethod("showErrorBox", &atom::ShowErrorBox);
   dict.SetMethod("showOpenDialog", &ShowOpenDialog);
   dict.SetMethod("showSaveDialog", &ShowSaveDialog);
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) || defined(OS_WIN)
   dict.SetMethod("showCertificateTrustDialog",
                  &certificate_trust::ShowCertificateTrust);
 #endif

+ 9 - 0
atom/browser/api/atom_api_web_contents.cc

@@ -873,6 +873,15 @@ void WebContents::Observe(int type,
   }
 }
 
+void WebContents::BeforeUnloadDialogCancelled() {
+  if (deferred_load_url_.id) {
+    auto& controller = web_contents()->GetController();
+    if (!controller.GetPendingEntry()) {
+      deferred_load_url_.id = 0;
+    }
+  }
+}
+
 void WebContents::DevToolsReloadPage() {
   Emit("devtools-reload-page");
 }

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

@@ -340,6 +340,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
   void Observe(int type,
                const content::NotificationSource& source,
                const content::NotificationDetails& details) override;
+  void BeforeUnloadDialogCancelled() override;
 
   // brightray::InspectableWebContentsDelegate:
   void DevToolsReloadPage() override;

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

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

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

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

+ 98 - 0
atom/browser/ui/certificate_trust_win.cc

@@ -0,0 +1,98 @@
+// Copyright (c) 2017 GitHub, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#include "atom/browser/ui/certificate_trust.h"
+
+#include <wincrypt.h>
+#include <windows.h>
+
+#include "base/callback.h"
+#include "net/cert/cert_database.h"
+
+namespace certificate_trust {
+
+// Add the provided certificate to the Trusted Root Certificate Authorities
+// store for the current user.
+//
+// This requires prompting the user to confirm they trust the certificate.
+BOOL AddToTrustedRootStore(const PCCERT_CONTEXT cert_context,
+                           const scoped_refptr<net::X509Certificate>& cert) {
+  auto root_cert_store = CertOpenStore(
+      CERT_STORE_PROV_SYSTEM,
+      0,
+      NULL,
+      CERT_SYSTEM_STORE_CURRENT_USER,
+      L"Root");
+
+  if (root_cert_store == NULL) {
+    return false;
+  }
+
+  auto result = CertAddCertificateContextToStore(
+    root_cert_store,
+    cert_context,
+    CERT_STORE_ADD_REPLACE_EXISTING,
+    NULL);
+
+  if (result) {
+    // force Chromium to reload it's database for this certificate
+    auto cert_db = net::CertDatabase::GetInstance();
+    cert_db->NotifyObserversCertDBChanged(cert.get());
+  }
+
+  CertCloseStore(root_cert_store, CERT_CLOSE_STORE_FORCE_FLAG);
+
+  return result;
+}
+
+CERT_CHAIN_PARA GetCertificateChainParameters() {
+  CERT_ENHKEY_USAGE enhkey_usage;
+  enhkey_usage.cUsageIdentifier = 0;
+  enhkey_usage.rgpszUsageIdentifier = NULL;
+
+  CERT_USAGE_MATCH cert_usage;
+  // ensure the rules are applied to the entire chain
+  cert_usage.dwType = USAGE_MATCH_TYPE_AND;
+  cert_usage.Usage = enhkey_usage;
+
+  CERT_CHAIN_PARA params = { sizeof(CERT_CHAIN_PARA) };
+  params.RequestedUsage = cert_usage;
+
+  return params;
+}
+
+void ShowCertificateTrust(atom::NativeWindow* parent_window,
+                          const scoped_refptr<net::X509Certificate>& cert,
+                          const std::string& message,
+                          const ShowTrustCallback& callback) {
+  PCCERT_CHAIN_CONTEXT chain_context;
+
+  auto cert_context = cert->CreateOSCertChainForCert();
+
+  auto params = GetCertificateChainParameters();
+
+  if (CertGetCertificateChain(NULL,
+                              cert_context,
+                              NULL,
+                              NULL,
+                              &params,
+                              NULL,
+                              NULL,
+                              &chain_context)) {
+    auto error_status = chain_context->TrustStatus.dwErrorStatus;
+    if (error_status == CERT_TRUST_IS_SELF_SIGNED ||
+        error_status == CERT_TRUST_IS_UNTRUSTED_ROOT) {
+      // these are the only scenarios we're interested in supporting
+      AddToTrustedRootStore(cert_context, cert);
+    }
+
+    CertFreeCertificateChain(chain_context);
+  }
+
+  CertFreeCertificateContext(cert_context);
+
+  callback.Run();
+}
+
+}  // namespace certificate_trust

+ 10 - 0
atom/browser/ui/cocoa/atom_touch_bar.mm

@@ -224,6 +224,7 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item";
   NSString* item_id = [NSString stringWithFormat:@"%ld", ((NSSegmentedControl*)sender).tag];
   base::DictionaryValue details;
   details.SetInteger("selectedIndex", ((NSSegmentedControl*)sender).selectedSegment);
+  details.SetBoolean("isSelected", [((NSSegmentedControl*)sender) isSelectedForSegment:((NSSegmentedControl*)sender).selectedSegment]);
   window_->NotifyTouchBarItemInteraction([item_id UTF8String],
                                          details);
 }
@@ -520,6 +521,15 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item";
   else
     control.segmentStyle = NSSegmentStyleAutomatic;
 
+  std::string segmentMode;
+  settings.Get("mode", &segmentMode);
+  if (segmentMode == "multiple")
+    control.trackingMode = NSSegmentSwitchTrackingSelectAny;
+  else if (segmentMode == "buttons")
+    control.trackingMode = NSSegmentSwitchTrackingMomentary;
+  else
+    control.trackingMode = NSSegmentSwitchTrackingSelectOne;
+
   std::vector<mate::Dictionary> segments;
   settings.Get("segments", &segments);
 

+ 82 - 46
atom/common/api/atom_bindings.cc

@@ -13,7 +13,7 @@
 #include "atom/common/native_mate_converters/string16_converter.h"
 #include "atom/common/node_includes.h"
 #include "base/logging.h"
-#include "base/process/process_metrics.h"
+#include "base/sys_info.h"
 #include "native_mate/dictionary.h"
 
 namespace atom {
@@ -23,51 +23,6 @@ namespace {
 // Dummy class type that used for crashing the program.
 struct DummyClass { bool crash; };
 
-void Hang() {
-  for (;;)
-    base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
-}
-
-v8::Local<v8::Value> GetProcessMemoryInfo(v8::Isolate* isolate) {
-  std::unique_ptr<base::ProcessMetrics> metrics(
-      base::ProcessMetrics::CreateCurrentProcessMetrics());
-
-  mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
-  dict.Set("workingSetSize",
-           static_cast<double>(metrics->GetWorkingSetSize() >> 10));
-  dict.Set("peakWorkingSetSize",
-           static_cast<double>(metrics->GetPeakWorkingSetSize() >> 10));
-
-  size_t private_bytes, shared_bytes;
-  if (metrics->GetMemoryBytes(&private_bytes, &shared_bytes)) {
-    dict.Set("privateBytes", static_cast<double>(private_bytes >> 10));
-    dict.Set("sharedBytes", static_cast<double>(shared_bytes >> 10));
-  }
-
-  return dict.GetHandle();
-}
-
-v8::Local<v8::Value> GetSystemMemoryInfo(v8::Isolate* isolate,
-                                         mate::Arguments* args) {
-  base::SystemMemoryInfoKB mem_info;
-  if (!base::GetSystemMemoryInfo(&mem_info)) {
-    args->ThrowError("Unable to retrieve system memory information");
-    return v8::Undefined(isolate);
-  }
-
-  mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
-  dict.Set("total", mem_info.total);
-  dict.Set("free", mem_info.free);
-
-  // NB: These return bogus values on macOS
-#if !defined(OS_MACOSX)
-  dict.Set("swapTotal", mem_info.swap_total);
-  dict.Set("swapFree", mem_info.swap_free);
-#endif
-
-  return dict.GetHandle();
-}
-
 // Called when there is a fatal error in V8, we just crash the process here so
 // we can get the stack trace.
 void FatalErrorCallback(const char* location, const char* message) {
@@ -81,6 +36,7 @@ void FatalErrorCallback(const char* location, const char* message) {
 AtomBindings::AtomBindings(uv_loop_t* loop) {
   uv_async_init(loop, &call_next_tick_async_, OnCallNextTick);
   call_next_tick_async_.data = this;
+  metrics_ = base::ProcessMetrics::CreateCurrentProcessMetrics();
 }
 
 AtomBindings::~AtomBindings() {
@@ -97,6 +53,9 @@ void AtomBindings::BindTo(v8::Isolate* isolate,
   dict.SetMethod("log", &Log);
   dict.SetMethod("getProcessMemoryInfo", &GetProcessMemoryInfo);
   dict.SetMethod("getSystemMemoryInfo", &GetSystemMemoryInfo);
+  dict.SetMethod("getCPUUsage",
+      base::Bind(&AtomBindings::GetCPUUsage, base::Unretained(this)));
+  dict.SetMethod("getIOCounters", &GetIOCounters);
 #if defined(OS_POSIX)
   dict.SetMethod("setFdLimit", &base::SetFdLimit);
 #endif
@@ -168,4 +127,81 @@ void AtomBindings::Crash() {
   static_cast<DummyClass*>(nullptr)->crash = true;
 }
 
+// static
+void AtomBindings::Hang() {
+  for (;;)
+    base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
+}
+
+// static
+v8::Local<v8::Value> AtomBindings::GetProcessMemoryInfo(v8::Isolate* isolate) {
+  std::unique_ptr<base::ProcessMetrics> metrics(
+      base::ProcessMetrics::CreateCurrentProcessMetrics());
+
+  mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
+  dict.Set("workingSetSize",
+           static_cast<double>(metrics->GetWorkingSetSize() >> 10));
+  dict.Set("peakWorkingSetSize",
+           static_cast<double>(metrics->GetPeakWorkingSetSize() >> 10));
+
+  size_t private_bytes, shared_bytes;
+  if (metrics->GetMemoryBytes(&private_bytes, &shared_bytes)) {
+    dict.Set("privateBytes", static_cast<double>(private_bytes >> 10));
+    dict.Set("sharedBytes", static_cast<double>(shared_bytes >> 10));
+  }
+
+  return dict.GetHandle();
+}
+
+// static
+v8::Local<v8::Value> AtomBindings::GetSystemMemoryInfo(v8::Isolate* isolate,
+    mate::Arguments* args) {
+  base::SystemMemoryInfoKB mem_info;
+  if (!base::GetSystemMemoryInfo(&mem_info)) {
+    args->ThrowError("Unable to retrieve system memory information");
+    return v8::Undefined(isolate);
+  }
+
+  mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
+  dict.Set("total", mem_info.total);
+  dict.Set("free", mem_info.free);
+
+  // NB: These return bogus values on macOS
+#if !defined(OS_MACOSX)
+  dict.Set("swapTotal", mem_info.swap_total);
+  dict.Set("swapFree", mem_info.swap_free);
+#endif
+
+  return dict.GetHandle();
+}
+
+v8::Local<v8::Value> AtomBindings::GetCPUUsage(v8::Isolate* isolate) {
+  mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
+  int processor_count = base::SysInfo::NumberOfProcessors();
+  dict.Set("percentCPUUsage",
+           metrics_->GetPlatformIndependentCPUUsage() / processor_count);
+  dict.Set("idleWakeupsPerSecond", metrics_->GetIdleWakeupsPerSecond());
+
+  return dict.GetHandle();
+}
+
+// static
+v8::Local<v8::Value> AtomBindings::GetIOCounters(v8::Isolate* isolate) {
+  std::unique_ptr<base::ProcessMetrics> metrics(
+      base::ProcessMetrics::CreateCurrentProcessMetrics());
+  base::IoCounters io_counters;
+  mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
+
+  if (metrics->GetIOCounters(&io_counters)) {
+    dict.Set("readOperationCount", io_counters.ReadOperationCount);
+    dict.Set("writeOperationCount", io_counters.WriteOperationCount);
+    dict.Set("otherOperationCount", io_counters.OtherOperationCount);
+    dict.Set("readTransferCount", io_counters.ReadTransferCount);
+    dict.Set("writeTransferCount", io_counters.WriteTransferCount);
+    dict.Set("otherTransferCount", io_counters.OtherTransferCount);
+  }
+
+  return dict.GetHandle();
+}
+
 }  // namespace atom

+ 9 - 0
atom/common/api/atom_bindings.h

@@ -8,7 +8,9 @@
 #include <list>
 
 #include "base/macros.h"
+#include "base/process/process_metrics.h"
 #include "base/strings/string16.h"
+#include "native_mate/arguments.h"
 #include "v8/include/v8.h"
 #include "vendor/node/deps/uv/include/uv.h"
 
@@ -32,6 +34,12 @@ class AtomBindings {
 
   static void Log(const base::string16& message);
   static void Crash();
+  static void Hang();
+  static v8::Local<v8::Value> GetProcessMemoryInfo(v8::Isolate* isolate);
+  static v8::Local<v8::Value> GetSystemMemoryInfo(v8::Isolate* isolate,
+      mate::Arguments* args);
+  v8::Local<v8::Value> GetCPUUsage(v8::Isolate* isolate);
+  static v8::Local<v8::Value> GetIOCounters(v8::Isolate* isolate);
 
  private:
   void ActivateUVLoop(v8::Isolate* isolate);
@@ -40,6 +48,7 @@ class AtomBindings {
 
   uv_async_t call_next_tick_async_;
   std::list<node::Environment*> pending_next_ticks_;
+  std::unique_ptr<base::ProcessMetrics> metrics_;
 
   DISALLOW_COPY_AND_ASSIGN(AtomBindings);
 };

+ 1 - 1
atom/common/atom_version.h

@@ -7,7 +7,7 @@
 
 #define ATOM_MAJOR_VERSION 1
 #define ATOM_MINOR_VERSION 6
-#define ATOM_PATCH_VERSION 8
+#define ATOM_PATCH_VERSION 9
 
 #define ATOM_VERSION_IS_RELEASE 1
 

+ 3 - 0
atom/renderer/atom_sandboxed_renderer_client.cc

@@ -86,6 +86,9 @@ void InitializeBindings(v8::Local<v8::Object> binding,
   mate::Dictionary b(isolate, binding);
   b.SetMethod("get", GetBinding);
   b.SetMethod("crash", AtomBindings::Crash);
+  b.SetMethod("hang", AtomBindings::Hang);
+  b.SetMethod("getProcessMemoryInfo", &AtomBindings::GetProcessMemoryInfo);
+  b.SetMethod("getSystemMemoryInfo", &AtomBindings::GetSystemMemoryInfo);
 }
 
 class AtomSandboxedRenderViewObserver : public AtomRenderViewObserver {

+ 6 - 6
docs-translations/es/project/README.md

@@ -7,12 +7,12 @@
 
 :memo: Traducciones disponibles: [Koreano](https://github.com/electron/electron/tree/master/docs-translations/ko-KR/project/README.md) | [Chino Simplificado](https://github.com/electron/electron/tree/master/docs-translations/zh-CN/project/README.md) | [Portugués Brasileño](https://github.com/electron/electron/tree/master/docs-translations/pt-BR/project/README.md) | [Chino Tradicional](https://github.com/electron/electron/tree/master/docs-translations/zh-TW/project/README.md)
 
-Electron es un framework que permite escribir aplicaciones de escritorio multiplataforma 
-usando JavaScript, HTML y CSS. Está basado en [Node.js](https://nodejs.org/) con 
+Electron es un framework que permite escribir aplicaciones de escritorio multiplataforma
+usando JavaScript, HTML y CSS. Está basado en [Node.js](https://nodejs.org/) con
 [Chromium](http://www.chromium.org). Es usado por [Atom
 editor](https://github.com/atom/atom) y muchas otras [aplicaciones](https://electron.atom.io/apps).
 
-Sigue a [@ElectronJS](https://twitter.com/electronjs) en Twitter para estar informado de anuncios 
+Sigue a [@ElectronJS](https://twitter.com/electronjs) en Twitter para estar informado de anuncios
 importantes.
 
 Este proyecto se adhiere al [Código de Conducta convenido para Colaboradores](CODE_OF_CONDUCT.md).
@@ -41,7 +41,7 @@ los prebuilt binaries, debug symbols, y más.
 
 ## Documentación
 
-Las guías y API de referencia están disponibles en el directorio 
+Las guías y API de referencia están disponibles en el directorio
 [docs](https://github.com/electron/electron/tree/master/docs). Ahí también
 puedes encontrar documentos que describen cómo construir y contribuir en Electron.
 
@@ -67,14 +67,14 @@ para ver una aplicación mínima en acción.
 ## Comunidad
 
 Puedes preguntar y interactuar con la comunidad en los siguientes lugares:
-- [`electron`](http://discuss.atom.io/c/electron) Categoría en los Foros de 
+- [`electron`](http://discuss.atom.io/c/electron) Categoría en los Foros de
 Atom.
 - `#atom-shell` canal de IRC en Freenode
 - [`Atom`](http://atom-slack.herokuapp.com/) canales en Slack
 - [`electron-br`](https://electron-br.slack.com) *(Portugués Brasileño)*
 - [`electron-kr`](http://www.meetup.com/electron-kr/) *(Koreano)*
 - [`electron-jp`](https://electron-jp.slack.com) *(Japonés)*
-- [`electron-tr`](http://www.meetup.com/Electron-JS-Istanbul/) *(Turco)*
+- [`electron-tr`](http://electron-tr.herokuapp.com) *(Turco)*
 - [`electron-id`](https://electron-id.slack.com) *(Indonés*
 
 Mira [awesome-electron](https://github.com/sindresorhus/awesome-electron)

+ 1 - 1
docs-translations/ko-KR/project/README.md

@@ -73,7 +73,7 @@ npm install electron --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/) *(터키)* 커뮤니티
+- [`electron-tr`](http://electron-tr.herokuapp.com) *(터키)* 커뮤니티
 - [`electron-id`](https://electron-id.slack.com) *(인도네시아)* 커뮤니티
 
 [awesome-electron](https://github.com/sindresorhus/awesome-electron) 프로젝트에

+ 1 - 1
docs-translations/pt-BR/project/README.md

@@ -61,7 +61,7 @@ Você pode fazer perguntas e interagir com a comunidade nos seguintes locais:
 - [`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-tr`](http://electron-tr.herokuapp.com) *(Turkish)*
 - [`electron-id`](https://electron-id.slack.com) *(Indonesia)*
 
 Confira [awesome-electron](https://github.com/sindresorhus/awesome-electron) para uma lista mantida pela comunidade de exemplos de aplicativos úteis, ferramentas e recursos.

+ 1 - 1
docs-translations/tr-TR/project/README.md

@@ -72,7 +72,7 @@ Asağıdaki sayfalardan sorular sorabilir ve topluluk ile etkileşime geçebilir
 - [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)*
 - [`electron-kr`](http://www.meetup.com/electron-kr/) *(Korean)*
 - [`electron-jp`](https://electron-jp.slack.com) *(Japanese)*
-- [`electron-tr`](http://www.meetup.com/Electron-JS-Istanbul/) *(Turkish)*
+- [`electron-tr`](http://electron-tr.herokuapp.com) *(Turkish)*
 - [`electron-id`](https://electron-id.slack.com) *(Indonesia)*
 
 Topluluk tarafından sağlanan örnek uygulamaları, aracları ve kaynaklara ulaşmak için

+ 1 - 1
docs-translations/zh-CN/project/README.md

@@ -73,7 +73,7 @@ ELECTRON_MIRROR=http://npm.taobao.org/mirrors/electron/ npm install electron -g
 - [`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/) *(土耳其)*
+- [`electron-tr`](http://electron-tr.herokuapp.com) *(土耳其)*
 - [`electron-id`](https://electron-id.slack.com) *(印度尼西亚)*
 
 查看 [awesome-electron](https://github.com/sindresorhus/awesome-electron)

+ 2 - 2
docs-translations/zh-TW/project/README.md

@@ -66,12 +66,12 @@ Clone 並使用 [`electron/electron-quick-start`](https://github.com/electron/el
 - [`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/) *(土耳其)*
+- [`electron-tr`](http://electron-tr.herokuapp.com) *(土耳其)*
 - [`electron-id`](https://electron-id.slack.com) *(印度尼西亞)*
 
 在 [awesome-electron](https://github.com/sindresorhus/awesome-electron)
 查看由社群維護的清單,包括實用的應用程式、工具以及資源。
 
-## 憑證
+## 授權條款
 
 MIT © 2016 Github

+ 1 - 0
docs/README.md

@@ -40,6 +40,7 @@ an issue:
 * [Desktop Environment Integration](tutorial/desktop-environment-integration.md)
 * [Online/Offline Event Detection](tutorial/online-offline-events.md)
 * [REPL](tutorial/repl.md)
+* [Native Notifications](tutorial/notifications.md)
 
 ## API References
 

+ 4 - 0
docs/api/app.md

@@ -760,6 +760,10 @@ Disables hardware acceleration for current app.
 
 This method can only be called before app is ready.
 
+### `app.getAppMemoryInfo()`
+
+Returns [ProcessMemoryInfo[]](structures/process-memory-info.md):  Array of `ProcessMemoryInfo` objects that correspond to memory usage statistics of all the processes associated with the app.
+
 ### `app.setBadgeCount(count)` _Linux_ _macOS_
 
 * `count` Integer

+ 11 - 5
docs/api/dialog.md

@@ -176,7 +176,7 @@ it is usually used to report errors in early stage of startup.  If called
 before the app `ready`event on Linux, the message will be emitted to stderr,
 and no GUI dialog will appear.
 
-### `dialog.showCertificateTrustDialog([browserWindow, ]options, callback)` _macOS_
+### `dialog.showCertificateTrustDialog([browserWindow, ]options, callback)` _macOS_ _Windows_
 
 * `browserWindow` BrowserWindow (optional)
 * `options` Object
@@ -184,11 +184,17 @@ and no GUI dialog will appear.
   * `message` String - The message to display to the user.
 * `callback` Function
 
-Displays a modal dialog that shows a message and certificate information, and
-gives the user the option of trusting/importing the certificate.
+On macOS, this displays a modal dialog that shows a message and certificate
+information, and gives the user the option of trusting/importing the
+certificate. If you provide a `browserWindow` argument the dialog will be
+attached to the parent window, making it modal.
 
-The `browserWindow` argument allows the dialog to attach itself to a parent
-window, making it modal.
+On Windows the options are more limited, due to the Win32 APIs used:
+
+ - The `message` argument is not used, as the OS provides its own confirmation
+   dialog.
+ - The `browserWindow` argument is ignored since it is not possible to make
+   this confirmation dialog modal.
 
 ## Sheets
 

+ 2 - 2
docs/api/ipc-main.md

@@ -16,8 +16,8 @@ It is also possible to send messages from the main process to the renderer
 process, see [webContents.send][web-contents-send] for more information.
 
 * When sending a message, the event name is the `channel`.
-* To reply a synchronous message, you need to set `event.returnValue`.
-* To send an asynchronous back to the sender, you can use
+* To reply to a synchronous message, you need to set `event.returnValue`.
+* To send an asynchronous message back to the sender, you can use
   `event.sender.send(...)`.
 
 An example of sending and handling messages between the render and main

+ 75 - 72
docs/api/locales.md

@@ -8,132 +8,135 @@ values are listed below:
 | Language Code | Language Name |
 |---------------|---------------|
 | af | Afrikaans |
-| an | Aragonese |
-| ar-AE | Arabic (U.A.E.) |
-| ar-IQ | Arabic (Iraq) |
-| ar | Arabic (Standard) |
-| ar-BH | Arabic (Bahrain) |
-| ar-DZ | Arabic (Algeria) |
-| ar-EG | Arabic (Egypt) |
-| ar-JO | Arabic (Jordan) |
-| ar-KW | Arabic (Kuwait) |
-| ar-LB | Arabic (Lebanon) |
-| ar-LY | Arabic (Libya) |
-| ar-MA | Arabic (Morocco) |
-| ar-OM | Arabic (Oman) |
-| ar-QA | Arabic (Qatar) |
-| ar-SA | Arabic (Saudi Arabia) |
-| ar-SY | Arabic (Syria) |
-| ar-TN | Arabic (Tunisia) |
-| ar-YE | Arabic (Yemen) |
-| as | Assamese |
-| ast | Asturian |
+| am | Amharic |
+| ar | Arabic |
 | az | Azerbaijani |
 | be | Belarusian |
 | bg | Bulgarian |
-| bg | Bulgarian |
+| bh | Bihari |
 | bn | Bengali |
 | br | Breton |
 | bs | Bosnian |
 | ca | Catalan |
-| ce | Chechen |
-| ch | Chamorro |
 | co | Corsican |
-| cr | Cree |
 | cs | Czech |
-| cv | Chuvash |
+| cy | Welsh |
 | da | Danish |
-| de | German (Standard) |
+| de | German |
 | de-AT | German (Austria) |
 | de-CH | German (Switzerland) |
 | de-DE | German (Germany) |
-| de-LI | German (Liechtenstein) |
-| de-LU | German (Luxembourg) |
 | el | Greek |
-| en-AU | English (Australia) |
-| en-BZ | English (Belize) |
 | en | English |
+| en-AU | English (Australia) |
 | en-CA | English (Canada) |
-| en-GB | English (United Kingdom) |
-| en-IE | English (Ireland) |
-| en-JM | English (Jamaica) |
+| en-GB | English (UK) |
 | en-NZ | English (New Zealand) |
-| en-PH | English (Philippines) |
-| en-TT | English (Trinidad & Tobago) |
-| en-US | English (United States) |
+| en-US | English (US) |
 | en-ZA | English (South Africa) |
-| en-ZW | English (Zimbabwe) |
 | eo | Esperanto |
+| es | Spanish |
+| es-419 | Spanish (Latin America) |
 | et | Estonian |
 | eu | Basque |
 | fa | Persian |
-| fa | Farsi |
-| fa-IR | Persian/Iran |
 | fi | Finnish |
-| fj | Fijian |
-| fo | Faeroese |
+| fil | Filipino |
+| fo | Faroese |
+| fr | French |
+| fr-CA | French (Canada) |
 | fr-CH | French (Switzerland) |
 | fr-FR | French (France) |
-| fr-LU | French (Luxembourg) |
-| fr-MC | French (Monaco) |
-| fr | French (Standard) |
-| fr-BE | French (Belgium) |
-| fr-CA | French (Canada) |
-| fur | Friulian |
 | fy | Frisian |
 | ga | Irish |
-| gd-IE | Gaelic (Irish) |
-| gd | Gaelic (Scots) |
-| gl | Galacian |
-| gu | Gujurati |
+| gd | Scots Gaelic |
+| gl | Galician |
+| gn | Guarani |
+| gu | Gujarati |
+| ha | Hausa |
+| haw | Hawaiian |
 | he | Hebrew |
 | hi | Hindi |
 | hr | Croatian |
-| ht | Haitian |
 | hu | Hungarian |
 | hy | Armenian |
+| ia | Interlingua |
 | id | Indonesian |
 | is | Icelandic |
+| it | Italian |
 | it-CH | Italian (Switzerland) |
-| it | Italian (Standard) |
-| iu | Inuktitut |
+| it-IT | Italian (Italy) |
 | ja | Japanese |
+| jw | Javanese |
 | ka | Georgian |
 | kk | Kazakh |
-| km | Khmer |
+| km | Cambodian |
 | kn | Kannada |
 | ko | Korean |
-| ko-KP | Korean (North Korea) |
-| ko-KR | Korean (South Korea) |
-| ks | Kashmiri |
-| ky | Kirghiz |
+| ku | Kurdish |
+| ky | Kyrgyz |
 | la | Latin |
-| lb | Luxembourgish |
+| ln | Lingala |
+| lo | Laothian |
 | lt | Lithuanian |
 | lv | Latvian |
-| mi | Maori |
-| mk | FYRO Macedonian |
+| mk | Macedonian |
 | ml | Malayalam |
+| mn | Mongolian |
 | mo | Moldavian |
 | mr | Marathi |
 | ms | Malay |
 | mt | Maltese |
-| my | Burmese |
 | nb | Norwegian (Bokmal) |
 | ne | Nepali |
-| ng | Ndonga |
-| nl | Dutch (Standard) |
-| nl-BE | Dutch (Belgian) |
+| nl | Dutch |
 | nn | Norwegian (Nynorsk) |
 | no | Norwegian |
-| nv | Navajo |
 | oc | Occitan |
 | om | Oromo |
 | or | Oriya |
+| pa | Punjabi |
+| pl | Polish |
+| ps | Pashto |
+| pt | Portuguese |
+| pt-BR | Portuguese (Brazil) |
+| pt-PT | Portuguese (Portugal) |
+| qu | Quechua |
+| rm | Romansh |
+| ro | Romanian |
+| ru | Russian |
+| sd | Sindhi |
+| sh | Serbo-Croatian |
+| si | Sinhalese |
+| sk | Slovak |
+| sl | Slovenian |
+| sn | Shona |
+| so | Somali |
 | sq | Albanian |
-| tlh | Klingon |
-| zh-TW | Chinese (Taiwan) |
+| sr | Serbian |
+| st | Sesotho |
+| su | Sundanese |
+| sv | Swedish |
+| sw | Swahili |
+| ta | Tamil |
+| te | Telugu |
+| tg | Tajik |
+| th | Thai |
+| ti | Tigrinya |
+| tk | Turkmen |
+| to | Tonga |
+| tr | Turkish |
+| tt | Tatar |
+| tw | Twi |
+| ug | Uighur |
+| uk | Ukrainian |
+| ur | Urdu |
+| uz | Uzbek |
+| vi | Vietnamese |
+| xh | Xhosa |
+| yi | Yiddish |
+| yo | Yoruba |
 | zh | Chinese |
-| zh-CN | Chinese (PRC) |
-| zh-HK | Chinese (Hong Kong) |
-| zh-SG | Chinese (Singapore) |
+| zh-CN | Chinese (Simplified) |
+| zh-TW | Chinese (Traditional) |
+| zu | Zulu |

+ 12 - 0
docs/api/process.md

@@ -116,3 +116,15 @@ Returns `Object`:
 
 Returns an object giving memory usage statistics about the entire system. Note
 that all statistics are reported in Kilobytes.
+
+### `process.getCPUUsage()`
+
+Returns:
+
+* `CPUUsage` [CPUUsage](structures/cpu-usage.md)
+
+### `process.getIOCounters()` _Windows_ _Linux_
+
+Returns:
+
+* `IOCounters` [IOCounters](structures/io-counters.md)

+ 6 - 0
docs/api/structures/cpu-usage.md

@@ -0,0 +1,6 @@
+# CPUUsage Object
+
+* `percentCPUUsage` Number - Percentage of CPU used since the last call to getCPUUsage.
+  First call returns 0.
+* `idleWakeupsPerSecond` Number - The number of average idle cpu wakeups per second
+  since the last call to getCPUUsage. First call returns 0.

+ 8 - 0
docs/api/structures/io-counters.md

@@ -0,0 +1,8 @@
+# IOCounters Object
+
+* `readOperationCount` Number - The number of I/O read operations.
+* `writeOperationCount` Number - The number of I/O write operations.
+* `otherOperationCount` Number - Then number of I/O other operations.
+* `readTransferCount` Number - The number of I/O read transfers.
+* `writeTransferCount` Number - The number of I/O write transfers.
+* `otherTransferCount` Number - Then number of I/O other transfers.

+ 12 - 0
docs/api/structures/memory-info.md

@@ -0,0 +1,12 @@
+# MemoryInfo Object
+
+* `workingSetSize` Integer - Process id of the process.
+* `workingSetSize` Integer - The amount of memory currently pinned to actual physical RAM.
+* `peakWorkingSetSize` Integer - The maximum amount of memory that has ever been pinned
+  to actual physical RAM.
+* `privateBytes` Integer - The amount of memory not shared by other processes, such as
+  JS heap or HTML content.
+* `sharedBytes` Integer - The amount of memory shared between processes, typically
+  memory consumed by the Electron code itself
+
+Note that all statistics are reported in Kilobytes.

+ 4 - 0
docs/api/structures/process-memory-info.md

@@ -0,0 +1,4 @@
+# ProcessMemoryInfo Object
+
+* `pid` Integer - Process id of the process.
+* `memory` [MemoryInfo](memory-info.md) - Memory information of the process.

+ 8 - 3
docs/api/touch-bar-segmented-control.md

@@ -21,10 +21,15 @@ Process: [Main](../tutorial/quick-start.md#main-process)
     * `small-square` - The control is displayed using the small square style.
     * `separated` - The segments in the control are displayed very close to each
       other but not touching.
-  * `segments` [SegmentedControlSegment[]](structures/segmented-control-segment.md) - An array of segments to place in this control
-  * `selectedIndex` Integer (Optional) - The index of the currently selected segment, will update automatically with user interaction
+  * `mode` String - (Optional) The selection mode of the control:
+    * `single` - Default. One item selected at a time, selecting one deselects the previously selected item.
+    * `multiple` - Multiple items can be selected at a time.
+    * `buttons` - Make the segments act as buttons, each segment can be pressed and released but never marked as active.
+  * `segments` [SegmentedControlSegment[]](structures/segmented-control-segment.md) - An array of segments to place in this control.
+  * `selectedIndex` Integer (Optional) - The index of the currently selected segment, will update automatically with user interaction.  When the mode is multiple it will be the last selected item.
   * `change` Function - Called when the user selects a new segment
-    * `selectedIndex` Integer - The index of the segment the user selected
+    * `selectedIndex` Integer - The index of the segment the user selected.
+    * `isSelected` Boolean - Whether as a result of user selection the segment is selected or not.
 
 ### Instance Properties
 

+ 1 - 1
docs/glossary.md

@@ -127,7 +127,7 @@ available in "core".
 ### V8
 
 V8 is Google's open source JavaScript engine. It is written in C++ and is
-used in Google Chrome, the open source browser from Google. V8 can run
+used in Google Chrome. V8 can run
 standalone, or can be embedded into any C++ application.
 
 ### webview

+ 2 - 48
docs/tutorial/desktop-environment-integration.md

@@ -8,55 +8,9 @@ applications can put a custom menu in the dock menu.
 This guide explains how to integrate your application into those desktop
 environments with Electron APIs.
 
-## Notifications (Windows, Linux, macOS)
+## Notifications
 
-All three operating systems provide means for applications to send notifications
-to the user. Electron conveniently allows developers to send notifications with
-the [HTML5 Notification API](https://notifications.spec.whatwg.org/), using
-the currently running operating system's native notification APIs to display it.
-
-**Note:** Since this is an HTML5 API it is only available in the renderer process.
-
-```javascript
-let myNotification = new Notification('Title', {
-  body: 'Lorem Ipsum Dolor Sit Amet'
-})
-
-myNotification.onclick = () => {
-  console.log('Notification clicked')
-}
-```
-
-While code and user experience across operating systems are similar, there
-are fine differences.
-
-### Windows
-
-* On Windows 10, notifications "just work".
-* On Windows 8.1 and Windows 8, a shortcut to your app, with a [Application User
-Model ID][app-user-model-id], must be installed to the Start screen. Note,
-however, that it does not need to be pinned to the Start screen.
-* On Windows 7, notifications work via a custom implemetation which visually
-resembles the native one on newer systems.
-
-Furthermore, the maximum length for the notification body is 250 characters,
-with the Windows team recommending that notifications should be kept to 200
-characters.
-
-### Linux
-
-Notifications are sent using `libnotify`, it can show notifications on any
-desktop environment that follows [Desktop Notifications
-Specification][notification-spec], including Cinnamon, Enlightenment, Unity,
-GNOME, KDE.
-
-### macOS
-
-Notifications are straight-forward on macOS, you should however be aware of
-[Apple's Human Interface guidelines regarding notifications](https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/NotificationCenter.html).
-
-Note that notifications are limited to 256 bytes in size - and will be truncated
-if you exceed that limit.
+See [Notifications](notifications.md)
 
 ## Recent documents (Windows & macOS)
 

+ 85 - 0
docs/tutorial/notifications.md

@@ -0,0 +1,85 @@
+# Notifications (Windows, Linux, macOS)
+
+All three operating systems provide means for applications to send notifications
+to the user. Electron conveniently allows developers to send notifications with
+the [HTML5 Notification API](https://notifications.spec.whatwg.org/), using
+the currently running operating system's native notification APIs to display it.
+
+**Note:** Since this is an HTML5 API it is only available in the renderer process.
+
+```javascript
+let myNotification = new Notification('Title', {
+  body: 'Lorem Ipsum Dolor Sit Amet'
+})
+
+myNotification.onclick = () => {
+  console.log('Notification clicked')
+}
+```
+
+While code and user experience across operating systems are similar, there
+are subtle differences.
+
+## Windows
+
+* On Windows 10, notifications "just work".
+* On Windows 8.1 and Windows 8, a shortcut to your app, with an [Application User
+Model ID][app-user-model-id], must be installed to the Start screen. Note,
+however, that it does not need to be pinned to the Start screen.
+* On Windows 7, notifications work via a custom implementation which visually
+ resembles the native one on newer systems.
+
+Furthermore, in Windows 8, the maximum length for the notification body is 250
+characters, with the Windows team recommending that notifications should be kept
+to 200 characters. That said, that limitation has been removed in Windows 10, with
+the Windows team asking developers to be reasonable. Attempting to send gigantic
+amounts of text to the API (thousands of characters) might result in instability.
+
+### Advanced Notifications
+
+Later versions of Windows allow for advanced notifications, with custom templates,
+images, and other flexible elements. To send those notifications (from either the
+main process or the renderer process), use the userland module
+[electron-windows-notifications](https://github.com/felixrieseberg/electron-windows-notifications),
+which uses native Node addons to send `ToastNotification` and `TileNotification` objects.
+
+While notifications including buttons work with just `electron-windows-notifications`,
+handling replies requires the use of [`electron-windows-interactive-notifications`](https://github.com/felixrieseberg/electron-windows-interactive-notifications), which
+helps with registering the required COM components and calling your Electron app with
+the entered user data.
+
+### Quiet Hours / Presentation Mode
+
+To detect whether or not you're allowed to send a notification, use the userland module
+[electron-notification-state](https://github.com/felixrieseberg/electron-notification-state).
+
+This allows you to determine ahead of time whether or not Windows will silently throw
+the notification away.
+
+## macOS
+
+Notifications are straight-forward on macOS, but you should be aware of
+[Apple's Human Interface guidelines regarding notifications](https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/NotificationCenter.html).
+
+Note that notifications are limited to 256 bytes in size and will be truncated
+if you exceed that limit.
+
+### Advanced Notifications
+
+Later versions of macOS allow for notifications with an input field, allowing the user
+to quickly reply to a notification. In order to send notifications with an input field,
+use the userland module [node-mac-notifier](https://github.com/CharlieHess/node-mac-notifier).
+
+### Do not disturb / Session State
+
+To detect whether or not you're allowed to send a notification, use the userland module
+[electron-notification-state](https://github.com/felixrieseberg/electron-notification-state).
+
+This will allow you to detect ahead of time whether or not the notification will be displayed.
+
+## Linux
+
+Notifications are sent using `libnotify` which can show notifications on any
+desktop environment that follows [Desktop Notifications
+Specification][notification-spec], including Cinnamon, Enlightenment, Unity,
+GNOME, KDE.

+ 4 - 4
docs/tutorial/quick-start.md

@@ -192,10 +192,10 @@ $ .\node_modules\.bin\electron .
 If you downloaded Electron manually, you can also use the included
 binary to execute your app directly.
 
-#### Windows
+#### macOS
 
 ```bash
-$ .\electron\electron.exe your-app\
+$ ./Electron.app/Contents/MacOS/Electron your-app/
 ```
 
 #### Linux
@@ -204,10 +204,10 @@ $ .\electron\electron.exe your-app\
 $ ./electron/electron your-app/
 ```
 
-#### macOS
+#### Windows
 
 ```bash
-$ ./Electron.app/Contents/MacOS/Electron your-app/
+$ .\electron\electron.exe your-app\
 ```
 
 `Electron.app` here is part of the Electron's release package, you can download

+ 1 - 1
electron.gyp

@@ -4,7 +4,7 @@
     'product_name%': 'Electron',
     'company_name%': 'GitHub, Inc',
     'company_abbr%': 'github',
-    'version%': '1.6.8',
+    'version%': '1.6.9',
     'js2c_input_dir': '<(SHARED_INTERMEDIATE_DIR)/js2c',
   },
   'includes': [

+ 1 - 0
filenames.gypi

@@ -291,6 +291,7 @@
       'atom/browser/ui/atom_menu_model.h',
       'atom/browser/ui/certificate_trust.h',
       'atom/browser/ui/certificate_trust_mac.mm',
+      'atom/browser/ui/certificate_trust_win.cc',
       'atom/browser/ui/cocoa/atom_menu_controller.h',
       'atom/browser/ui/cocoa/atom_menu_controller.mm',
       'atom/browser/ui/cocoa/atom_touch_bar.h',

+ 3 - 2
lib/browser/api/touch-bar.js

@@ -264,16 +264,17 @@ TouchBar.TouchBarSegmentedControl = class TouchBarSegmentedControl extends Touch
   constructor (config) {
     super()
     if (config == null) config = {}
-    const {segmentStyle, segments, selectedIndex, change} = config
+    const {segmentStyle, segments, selectedIndex, change, mode} = config
     this.type = 'segmented_control'
     this._addLiveProperty('segmentStyle', segmentStyle)
     this._addLiveProperty('segments', segments || [])
     this._addLiveProperty('selectedIndex', selectedIndex)
+    this._addLiveProperty('mode', mode)
 
     if (typeof change === 'function') {
       this.onInteraction = (details) => {
         this._selectedIndex = details.selectedIndex
-        change(details.selectedIndex)
+        change(details.selectedIndex, details.isSelected)
       }
     }
   }

+ 3 - 0
lib/sandboxed_renderer/init.js

@@ -38,6 +38,9 @@ const preloadSrc = fs.readFileSync(preloadPath).toString()
 // access to things like `process.atomBinding`).
 const preloadProcess = new events.EventEmitter()
 preloadProcess.crash = () => binding.crash()
+preloadProcess.hang = () => binding.hang()
+preloadProcess.getProcessMemoryInfo = () => binding.getProcessMemoryInfo()
+preloadProcess.getSystemMemoryInfo = () => binding.getSystemMemoryInfo()
 process.platform = preloadProcess.platform = electron.remote.process.platform
 process.execPath = preloadProcess.execPath = electron.remote.process.execPath
 process.on('exit', () => preloadProcess.emit('exit'))

+ 2 - 1
package.json

@@ -1,11 +1,12 @@
 {
   "name": "electron",
-  "version": "1.6.8",
+  "version": "1.6.9",
   "devDependencies": {
     "asar": "^0.11.0",
     "browserify": "^13.1.0",
     "electabul": "~0.0.4",
     "electron-docs-linter": "^2.1.0",
+    "electron-typescript-definitions": "^1.2.0",
     "request": "*",
     "standard": "^8.4.0",
     "standard-markdown": "^2.1.1"

+ 1 - 0
script/cibuild

@@ -81,6 +81,7 @@ def main():
     sys.stderr.write('\nRunning `npm run lint`\n')
     sys.stderr.flush()
     execute([npm, 'run', 'lint'])
+
   if is_release:
     run_script('build.py', ['-c', 'R'])
     run_script('create-dist.py')

+ 10 - 0
script/create-dist.py

@@ -91,6 +91,7 @@ def main():
 
   if PLATFORM != 'win32' and not args.no_api_docs:
     create_api_json_schema()
+    create_typescript_definitions()
 
   if PLATFORM == 'linux':
     strip_binaries()
@@ -143,6 +144,15 @@ def create_api_json_schema():
            '--version={}'.format(ELECTRON_VERSION.replace('v', ''))],
           env=env)
 
+def create_typescript_definitions():
+  node_bin_dir = os.path.join(SOURCE_ROOT, 'node_modules', '.bin')
+  env = os.environ.copy()
+  env['PATH'] = os.path.pathsep.join([node_bin_dir, env['PATH']])
+  infile = os.path.relpath(os.path.join(DIST_DIR, 'electron-api.json'))
+  outfile = os.path.relpath(os.path.join(DIST_DIR, 'electron.d.ts'))
+  execute(['electron-typescript-definitions', '--in={0}'.format(infile),
+           '--out={0}'.format(outfile)], env=env)
+
 def strip_binaries():
   for binary in TARGET_BINARIES[PLATFORM]:
     if binary.endswith('.so') or '.' not in binary:

+ 1 - 0
script/upload.py

@@ -81,6 +81,7 @@ def main():
   if PLATFORM == 'darwin':
     upload_electron(github, release, os.path.join(DIST_DIR,
                     'electron-api.json'))
+    upload_electron(github, release, os.path.join(DIST_DIR, 'electron.d.ts'))
     upload_electron(github, release, os.path.join(DIST_DIR, DSYM_NAME))
   elif PLATFORM == 'win32':
     upload_electron(github, release, os.path.join(DIST_DIR, PDB_NAME))

+ 13 - 0
spec/api-app-spec.js

@@ -533,4 +533,17 @@ describe('app module', function () {
       })
     })
   })
+
+  describe('getAppMemoryInfo() API', function () {
+    it('returns the process memory of all running electron processes', function () {
+      const appMemoryInfo = app.getAppMemoryInfo()
+      assert.ok(appMemoryInfo.length > 0, 'App memory info object is not > 0')
+      for (const {memory, pid} of appMemoryInfo) {
+        assert.ok(memory.workingSetSize > 0, 'working set size is not > 0')
+        assert.ok(memory.privateBytes > 0, 'private bytes is not > 0')
+        assert.ok(memory.sharedBytes > 0, 'shared bytes is not > 0')
+        assert.ok(pid > 0, 'pid is not > 0')
+      }
+    })
+  })
 })

+ 77 - 0
spec/api-browser-window-spec.js

@@ -1150,6 +1150,29 @@ describe('BrowserWindow module', function () {
         })
         w.loadURL('file://' + path.join(fixtures, 'pages', 'window-open.html'))
       })
+
+      it('releases memory after popup is closed', (done) => {
+        w.destroy()
+        w = new BrowserWindow({
+          show: false,
+          webPreferences: {
+            preload: preload,
+            sandbox: true
+          }
+        })
+        w.loadURL('file://' + path.join(fixtures, 'api', 'sandbox.html?allocate-memory'))
+        w.webContents.openDevTools({mode: 'detach'})
+        ipcMain.once('answer', function (event, {bytesBeforeOpen, bytesAfterOpen, bytesAfterClose}) {
+          const memoryIncreaseByOpen = bytesAfterOpen - bytesBeforeOpen
+          const memoryDecreaseByClose = bytesAfterOpen - bytesAfterClose
+          // decreased memory should be less than increased due to factors we
+          // can't control, but given the amount of memory allocated in the
+          // fixture, we can reasonably expect decrease to be at least 70% of
+          // increase
+          assert(memoryDecreaseByClose > memoryIncreaseByOpen * 0.7)
+          done()
+        })
+      })
     })
   })
 
@@ -1174,6 +1197,60 @@ describe('BrowserWindow module', function () {
       })
       w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-empty-string.html'))
     })
+
+    it('emits for each close attempt', function (done) {
+      var beforeUnloadCount = 0
+      w.on('onbeforeunload', function () {
+        beforeUnloadCount++
+        if (beforeUnloadCount < 3) {
+          w.close()
+        } else if (beforeUnloadCount === 3) {
+          done()
+        }
+      })
+      w.webContents.once('did-finish-load', function () {
+        w.close()
+      })
+      w.loadURL('file://' + path.join(fixtures, 'api', 'beforeunload-false-prevent3.html'))
+    })
+
+    it('emits for each reload attempt', function (done) {
+      var beforeUnloadCount = 0
+      w.on('onbeforeunload', function () {
+        beforeUnloadCount++
+        if (beforeUnloadCount < 3) {
+          w.reload()
+        } else if (beforeUnloadCount === 3) {
+          done()
+        }
+      })
+      w.webContents.once('did-finish-load', function () {
+        w.webContents.once('did-finish-load', function () {
+          assert.fail('Reload was not prevented')
+        })
+        w.reload()
+      })
+      w.loadURL('file://' + path.join(fixtures, 'api', 'beforeunload-false-prevent3.html'))
+    })
+
+    it('emits for each navigation attempt', function (done) {
+      var beforeUnloadCount = 0
+      w.on('onbeforeunload', function () {
+        beforeUnloadCount++
+        if (beforeUnloadCount < 3) {
+          w.loadURL('about:blank')
+        } else if (beforeUnloadCount === 3) {
+          done()
+        }
+      })
+      w.webContents.once('did-finish-load', function () {
+        w.webContents.once('did-finish-load', function () {
+          assert.fail('Navigation was not prevented')
+        })
+        w.loadURL('about:blank')
+      })
+      w.loadURL('file://' + path.join(fixtures, 'api', 'beforeunload-false-prevent3.html'))
+    })
   })
 
   describe('new-window event', function () {

+ 26 - 0
spec/api-process-spec.js

@@ -0,0 +1,26 @@
+const assert = require('assert')
+
+describe('process module', function () {
+  describe('process.getCPUUsage()', function () {
+    it('returns a cpu usage object', function () {
+      const cpuUsage = process.getCPUUsage()
+      assert.equal(typeof cpuUsage.percentCPUUsage, 'number')
+      assert.equal(typeof cpuUsage.idleWakeupsPerSecond, 'number')
+    })
+  })
+
+  describe('process.getIOCounters()', function () {
+    it('returns an io counters object', function () {
+      if (process.platform === 'darwin') {
+        return
+      }
+      const ioCounters = process.getIOCounters()
+      assert.equal(typeof ioCounters.readOperationCount, 'number')
+      assert.equal(typeof ioCounters.writeOperationCount, 'number')
+      assert.equal(typeof ioCounters.otherOperationCount, 'number')
+      assert.equal(typeof ioCounters.readTransferCount, 'number')
+      assert.equal(typeof ioCounters.writeTransferCount, 'number')
+      assert.equal(typeof ioCounters.otherTransferCount, 'number')
+    })
+  })
+})

+ 11 - 0
spec/fixtures/api/allocate-memory.html

@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <head>
+  </head>
+  <body>
+  <script>
+    window.bigBuffer = new Uint8Array(1024 * 1024 * 64)
+    window.bigBuffer.fill(5, 50, 1024 * 1024)
+   </script>
+  </body>
+</html>

+ 17 - 0
spec/fixtures/api/beforeunload-false-prevent3.html

@@ -0,0 +1,17 @@
+<html>
+<body>
+<script type="text/javascript" charset="utf-8">
+  // Only prevent unload on the first three window closes
+  var unloadPreventedCount = 0;
+  window.onbeforeunload = function() {
+    setTimeout(function() {
+      require('electron').remote.getCurrentWindow().emit('onbeforeunload');
+    }, 0);
+    if (unloadPreventedCount < 3) {
+      unloadPreventedCount++;
+      return false;
+    }
+  }
+</script>
+</body>
+</html>

+ 27 - 0
spec/fixtures/api/sandbox.html

@@ -1,5 +1,18 @@
 <html>
 <script type="text/javascript" charset="utf-8">
+  function timeout(ms) {
+    return new Promise((resolve) => {
+      setTimeout(resolve, ms)
+    })
+  }
+  async function invokeGc () {
+    // it seems calling window.gc once does not guarantee garbage will be
+    // collected, so we repeat 10 times with interval of 100 ms
+    for (let i = 0; i < 10; i++) {
+      window.gc()
+      await timeout(100)
+    }
+  }
   if (window.opener) {
     window.callback = () => {
       opener.require('electron').ipcRenderer.send('answer', document.body.innerHTML)
@@ -7,6 +20,20 @@
   } else {
     const {ipcRenderer} = require('electron')
     const tests = {
+      'allocate-memory': async () => {
+        await invokeGc()
+        const {privateBytes: bytesBeforeOpen} = process.getProcessMemoryInfo()
+        let w = open('./allocate-memory.html')
+        await invokeGc()
+        const {privateBytes: bytesAfterOpen} = process.getProcessMemoryInfo()
+        w.close()
+        w = null
+        await invokeGc()
+        const {privateBytes: bytesAfterClose} = process.getProcessMemoryInfo()
+        ipcRenderer.send('answer', {
+          bytesBeforeOpen, bytesAfterOpen, bytesAfterClose
+        })
+      },
       'window-events': () => {
         document.title = 'changed'
       },