Browse Source

Move closing logic to api::BrowserWindow

Closing a BrowserWindow is essentially closing a WebContents, the logic
should not be in NativeWindow.
Cheng Zhao 7 years ago
parent
commit
aa3eafcea1

+ 79 - 17
atom/browser/api/atom_api_browser_window.cc

@@ -9,7 +9,9 @@
 #include "atom/browser/api/atom_api_web_contents.h"
 #include "atom/browser/browser.h"
 #include "atom/browser/native_window.h"
+#include "atom/browser/unresponsive_suppressor.h"
 #include "atom/browser/web_contents_preferences.h"
+#include "atom/browser/window_list.h"
 #include "atom/common/api/api_messages.h"
 #include "atom/common/native_mate_converters/callback.h"
 #include "atom/common/native_mate_converters/file_path_converter.h"
@@ -174,7 +176,7 @@ void BrowserWindow::Init(v8::Isolate* isolate,
 
 BrowserWindow::~BrowserWindow() {
   if (!window_->IsClosed())
-    window_->CloseContents(nullptr);
+    window_->CloseImmediately();
 
   api_web_contents_->RemoveObserver(this);
 
@@ -214,6 +216,23 @@ void BrowserWindow::DidFirstVisuallyNonEmptyPaint() {
       }, GetWeakPtr()));
 }
 
+void BrowserWindow::BeforeUnloadDialogCancelled() {
+  WindowList::WindowCloseCancelled(window_.get());
+  // Cancel unresponsive event when window close is cancelled.
+  window_unresposive_closure_.Cancel();
+}
+
+void BrowserWindow::OnRendererUnresponsive(content::RenderWidgetHost*) {
+  // Schedule the unresponsive shortly later, since we may receive the
+  // responsive event soon. This could happen after the whole application had
+  // blocked for a while.
+  // Also notice that when closing this event would be ignored because we have
+  // explicitly started a close timeout counter. This is on purpose because we
+  // don't want the unresponsive event to be sent too early when user is closing
+  // the window.
+  ScheduleUnresponsiveEvent(50);
+}
+
 bool BrowserWindow::OnMessageReceived(const IPC::Message& message,
                                       content::RenderFrameHost* rfh) {
   bool handled = true;
@@ -225,14 +244,11 @@ bool BrowserWindow::OnMessageReceived(const IPC::Message& message,
   return handled;
 }
 
-void BrowserWindow::OnRendererResponsive() {
-}
-
-void BrowserWindow::WillCloseWindow(bool* prevent_default) {
-  *prevent_default = Emit("close");
-}
+void BrowserWindow::OnCloseContents() {
+  if (!web_contents())
+    return;
+  Observe(nullptr);
 
-void BrowserWindow::WillDestroyNativeObject() {
   // Close all child windows before closing current window.
   v8::Locker locker(isolate());
   v8::HandleScope handle_scope(isolate());
@@ -241,6 +257,25 @@ void BrowserWindow::WillDestroyNativeObject() {
     if (mate::ConvertFromV8(isolate(), value, &child) && !child.IsEmpty())
       child->window_->CloseImmediately();
   }
+
+  // When the web contents is gone, close the window immediately, but the
+  // memory will not be freed until you call delete.
+  // In this way, it would be safe to manage windows via smart pointers. If you
+  // want to free memory when the window is closed, you can do deleting by
+  // overriding the OnWindowClosed method in the observer.
+  window_->CloseImmediately();
+
+  // Do not sent "unresponsive" event after window is closed.
+  window_unresposive_closure_.Cancel();
+}
+
+void BrowserWindow::OnRendererResponsive() {
+  window_unresposive_closure_.Cancel();
+  Emit("responsive");
+}
+
+void BrowserWindow::WillCloseWindow(bool* prevent_default) {
+  *prevent_default = Emit("close");
 }
 
 void BrowserWindow::OnCloseButtonClicked(bool* prevent_default) {
@@ -248,7 +283,22 @@ void BrowserWindow::OnCloseButtonClicked(bool* prevent_default) {
   // not close the window immediately, instead we try to close the web page
   // first, and when the web page is closed the window will also be closed.
   *prevent_default = true;
-  window_->RequestToClosePage();
+
+  // Assume the window is not responding if it doesn't cancel the close and is
+  // not closed in 5s, in this way we can quickly show the unresponsive
+  // dialog when the window is busy executing some script withouth waiting for
+  // the unresponsive timeout.
+  if (window_unresposive_closure_.IsCancelled())
+    ScheduleUnresponsiveEvent(5000);
+
+  if (!web_contents())
+    // Already closed by renderer
+    return;
+
+  if (web_contents()->NeedToFireBeforeUnload())
+    web_contents()->DispatchBeforeUnload();
+  else
+    web_contents()->Close();
 }
 
 void BrowserWindow::OnWindowClosed() {
@@ -360,14 +410,6 @@ void BrowserWindow::OnWindowLeaveHtmlFullScreen() {
   Emit("leave-html-full-screen");
 }
 
-void BrowserWindow::OnWindowUnresponsive() {
-  Emit("unresponsive");
-}
-
-void BrowserWindow::OnWindowResponsive() {
-  Emit("responsive");
-}
-
 void BrowserWindow::OnExecuteWindowsCommand(const std::string& command_name) {
   Emit("app-command", command_name);
 }
@@ -1071,6 +1113,26 @@ void BrowserWindow::UpdateDraggableRegions(
   window_->UpdateDraggableRegions(regions);
 }
 
+void BrowserWindow::ScheduleUnresponsiveEvent(int ms) {
+  if (!window_unresposive_closure_.IsCancelled())
+    return;
+
+  window_unresposive_closure_.Reset(
+      base::Bind(&BrowserWindow::NotifyWindowUnresponsive, GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      window_unresposive_closure_.callback(),
+      base::TimeDelta::FromMilliseconds(ms));
+}
+
+void BrowserWindow::NotifyWindowUnresponsive() {
+  window_unresposive_closure_.Cancel();
+  if (!window_->IsClosed() && window_->IsEnabled() &&
+      !IsUnresponsiveEventSuppressed()) {
+    Emit("unresponsive");
+  }
+}
+
 // static
 void BrowserWindow::BuildPrototype(v8::Isolate* isolate,
                                    v8::Local<v8::FunctionTemplate> prototype) {

+ 14 - 3
atom/browser/api/atom_api_browser_window.h

@@ -15,6 +15,7 @@
 #include "atom/browser/native_window_observer.h"
 #include "atom/common/api/atom_api_native_image.h"
 #include "atom/common/key_weak_map.h"
+#include "base/cancelable_callback.h"
 #include "base/memory/weak_ptr.h"
 #include "native_mate/persistent_dictionary.h"
 
@@ -62,15 +63,17 @@ class BrowserWindow : public mate::TrackableObject<BrowserWindow>,
   // content::WebContentsObserver:
   void RenderViewCreated(content::RenderViewHost* render_view_host) override;
   void DidFirstVisuallyNonEmptyPaint() override;
+  void BeforeUnloadDialogCancelled() override;
+  void OnRendererUnresponsive(content::RenderWidgetHost*) override;
   bool OnMessageReceived(const IPC::Message& message,
                          content::RenderFrameHost* rfh) override;
 
   // ExtendedWebContentsObserver:
+  void OnCloseContents() override;
   void OnRendererResponsive() override;
 
   // NativeWindowObserver:
   void WillCloseWindow(bool* prevent_default) override;
-  void WillDestroyNativeObject() override;
   void OnCloseButtonClicked(bool* prevent_default) override;
   void OnWindowClosed() override;
   void OnWindowEndSession() override;
@@ -95,8 +98,6 @@ class BrowserWindow : public mate::TrackableObject<BrowserWindow>,
   void OnWindowLeaveFullScreen() override;
   void OnWindowEnterHtmlFullScreen() override;
   void OnWindowLeaveHtmlFullScreen() override;
-  void OnWindowUnresponsive() override;
-  void OnWindowResponsive() override;
   void OnExecuteWindowsCommand(const std::string& command_name) override;
   void OnTouchBarItemResult(const std::string& item_id,
                             const base::DictionaryValue& details) override;
@@ -253,11 +254,21 @@ class BrowserWindow : public mate::TrackableObject<BrowserWindow>,
       content::RenderFrameHost* rfh,
       const std::vector<DraggableRegion>& regions);
 
+  // Schedule a notification unresponsive event.
+  void ScheduleUnresponsiveEvent(int ms);
+
+  // Dispatch unresponsive event to observers.
+  void NotifyWindowUnresponsive();
+
 #if defined(OS_WIN)
   typedef std::map<UINT, MessageCallback> MessageCallbackMap;
   MessageCallbackMap messages_callback_map_;
 #endif
 
+  // 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_;
+
   v8::Global<v8::Value> browser_view_;
   v8::Global<v8::Value> web_contents_;
   v8::Global<v8::Value> menu_;

+ 8 - 6
atom/browser/api/atom_api_web_contents.cc

@@ -446,6 +446,8 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
 WebContents::~WebContents() {
   // The destroy() is called.
   if (managed_web_contents()) {
+    managed_web_contents()->GetView()->SetDelegate(nullptr);
+
     // For webview we need to tell content module to do some cleanup work before
     // destroying it.
     if (type_ == WEB_VIEW)
@@ -457,7 +459,8 @@ WebContents::~WebContents() {
       DestroyWebContents(false /* async */);
     } else {
       if (type_ == BROWSER_WINDOW && owner_window()) {
-        owner_window()->CloseContents(nullptr);
+        for (ExtendedWebContentsObserver& observer : observers_)
+          observer.OnCloseContents();
       } else {
         DestroyWebContents(true /* async */);
       }
@@ -565,9 +568,10 @@ void WebContents::MoveContents(content::WebContents* source,
 
 void WebContents::CloseContents(content::WebContents* source) {
   Emit("close");
-
-  if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window())
-    owner_window()->CloseContents(source);
+  if (managed_web_contents())
+    managed_web_contents()->GetView()->SetDelegate(nullptr);
+  for (ExtendedWebContentsObserver& observer : observers_)
+    observer.OnCloseContents();
 }
 
 void WebContents::ActivateContents(content::WebContents* source) {
@@ -640,8 +644,6 @@ void WebContents::RendererUnresponsive(
 
 void WebContents::RendererResponsive(content::WebContents* source) {
   Emit("responsive");
-  if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window())
-    owner_window()->RendererResponsive(source);
   for (ExtendedWebContentsObserver& observer : observers_)
     observer.OnRendererResponsive();
 }

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

@@ -54,6 +54,7 @@ namespace api {
 // dispatch those events.
 class ExtendedWebContentsObserver {
  public:
+  virtual void OnCloseContents() {}
   virtual void OnRendererResponsive() {}
 };
 

+ 0 - 87
atom/browser/native_window.cc

@@ -11,7 +11,6 @@
 #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/draggable_region.h"
 #include "atom/common/native_mate_converters/file_path_converter.h"
@@ -426,52 +425,6 @@ void NativeWindow::PreviewFile(const std::string& path,
 void NativeWindow::CloseFilePreview() {
 }
 
-void NativeWindow::RequestToClosePage() {
-  // Assume the window is not responding if it doesn't cancel the close and is
-  // not closed in 5s, in this way we can quickly show the unresponsive
-  // dialog when the window is busy executing some script withouth waiting for
-  // the unresponsive timeout.
-  if (window_unresposive_closure_.IsCancelled())
-    ScheduleUnresponsiveEvent(5000);
-
-  if (!web_contents())
-    // Already closed by renderer
-    return;
-
-  if (web_contents()->NeedToFireBeforeUnload())
-    web_contents()->DispatchBeforeUnload();
-  else
-    web_contents()->Close();
-}
-
-void NativeWindow::CloseContents(content::WebContents* source) {
-  if (!inspectable_web_contents_)
-    return;
-
-  inspectable_web_contents_->GetView()->SetDelegate(nullptr);
-  inspectable_web_contents_ = nullptr;
-  Observe(nullptr);
-
-  for (NativeWindowObserver& observer : observers_)
-    observer.WillDestroyNativeObject();
-
-  // When the web contents is gone, close the window immediately, but the
-  // memory will not be freed until you call delete.
-  // In this way, it would be safe to manage windows via smart pointers. If you
-  // want to free memory when the window is closed, you can do deleting by
-  // overriding the OnWindowClosed method in the observer.
-  CloseImmediately();
-
-  // Do not sent "unresponsive" event after window is closed.
-  window_unresposive_closure_.Cancel();
-}
-
-void NativeWindow::RendererResponsive(content::WebContents* source) {
-  window_unresposive_closure_.Cancel();
-  for (NativeWindowObserver& observer : observers_)
-    observer.OnWindowResponsive();
-}
-
 void NativeWindow::NotifyWindowCloseButtonClicked() {
   // First ask the observers whether we want to close.
   bool prevent_default = false;
@@ -652,44 +605,4 @@ std::unique_ptr<SkRegion> NativeWindow::DraggableRegionsToSkRegion(
   return sk_region;
 }
 
-void NativeWindow::BeforeUnloadDialogCancelled() {
-  WindowList::WindowCloseCancelled(this);
-
-  // Cancel unresponsive event when window close is cancelled.
-  window_unresposive_closure_.Cancel();
-}
-
-void NativeWindow::OnRendererUnresponsive(content::RenderWidgetHost*) {
-  // Schedule the unresponsive shortly later, since we may receive the
-  // responsive event soon. This could happen after the whole application had
-  // blocked for a while.
-  // Also notice that when closing this event would be ignored because we have
-  // explicitly started a close timeout counter. This is on purpose because we
-  // don't want the unresponsive event to be sent too early when user is closing
-  // the window.
-  ScheduleUnresponsiveEvent(50);
-}
-
-void NativeWindow::ScheduleUnresponsiveEvent(int ms) {
-  if (!window_unresposive_closure_.IsCancelled())
-    return;
-
-  window_unresposive_closure_.Reset(
-      base::Bind(&NativeWindow::NotifyWindowUnresponsive,
-                 weak_factory_.GetWeakPtr()));
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE,
-      window_unresposive_closure_.callback(),
-      base::TimeDelta::FromMilliseconds(ms));
-}
-
-void NativeWindow::NotifyWindowUnresponsive() {
-  window_unresposive_closure_.Cancel();
-
-  if (!is_closed_ && !IsUnresponsiveEventSuppressed() && IsEnabled()) {
-    for (NativeWindowObserver& observer : observers_)
-      observer.OnWindowUnresponsive();
-  }
-}
-
 }  // namespace atom

+ 0 - 20
atom/browser/native_window.h

@@ -13,7 +13,6 @@
 #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/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/supports_user_data.h"
@@ -230,12 +229,7 @@ class NativeWindow : public base::SupportsUserData,
     return weak_factory_.GetWeakPtr();
   }
 
-  // Requests the WebContents to close, can be cancelled by the page.
-  virtual void RequestToClosePage();
-
   // Methods called by the WebContents.
-  virtual void CloseContents(content::WebContents* source);
-  virtual void RendererResponsive(content::WebContents* source);
   virtual void HandleKeyboardEvent(
       content::WebContents*,
       const content::NativeWebKeyboardEvent& event) {}
@@ -315,17 +309,7 @@ class NativeWindow : public base::SupportsUserData,
   std::unique_ptr<SkRegion> DraggableRegionsToSkRegion(
       const std::vector<DraggableRegion>& regions);
 
-  // content::WebContentsObserver:
-  void BeforeUnloadDialogCancelled() override;
-  void OnRendererUnresponsive(content::RenderWidgetHost*) override;
-
  private:
-  // Schedule a notification unresponsive event.
-  void ScheduleUnresponsiveEvent(int ms);
-
-  // Dispatch unresponsive event to observers.
-  void NotifyWindowUnresponsive();
-
   // Whether window has standard frame.
   bool has_frame_;
 
@@ -341,10 +325,6 @@ class NativeWindow : public base::SupportsUserData,
   // The windows has been closed.
   bool is_closed_;
 
-  // 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_;
-
   // Used to display sheets at the appropriate horizontal and vertical offsets
   // on macOS.
   double sheet_offset_x_;

+ 0 - 9
atom/browser/native_window_observer.h

@@ -34,9 +34,6 @@ class NativeWindowObserver {
   // Called when the window is gonna closed.
   virtual void WillCloseWindow(bool* prevent_default) {}
 
-  // Called before the native window object is going to be destroyed.
-  virtual void WillDestroyNativeObject() {}
-
   // Called when closed button is clicked.
   virtual void OnCloseButtonClicked(bool* prevent_default) {}
 
@@ -85,12 +82,6 @@ class NativeWindowObserver {
   virtual void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) {}
   #endif
 
-  // Called when renderer is hung.
-  virtual void OnWindowUnresponsive() {}
-
-  // Called when renderer recovers.
-  virtual void OnWindowResponsive() {}
-
   // Called on Windows when App Commands arrive (WM_APPCOMMAND)
   virtual void OnExecuteWindowsCommand(const std::string& command_name) {}
 };

+ 1 - 1
atom/browser/window_list.cc

@@ -93,7 +93,7 @@ void WindowList::CloseAllWindows() {
 void WindowList::DestroyAllWindows() {
   WindowVector windows = GetInstance()->windows_;
   for (const auto& window : windows)
-    window->CloseContents(nullptr);  // e.g. Destroy()
+    window->CloseImmediately();  // e.g. Destroy()
 }
 
 WindowList::WindowList() {