Closing a window requires closing web contents now.
authorCheng Zhao <zcbenz@gmail.com>
Wed, 1 May 2013 07:42:30 +0000 (15:42 +0800)
committerCheng Zhao <zcbenz@gmail.com>
Wed, 1 May 2013 07:42:30 +0000 (15:42 +0800)
In this way, we can prevent the close of window by using beforeunload
handler.

browser/native_window.cc
browser/native_window.h
browser/native_window_mac.mm
common/platform_util.h

index fe7befb..8640401 100644 (file)
@@ -20,6 +20,7 @@
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
 #include "common/api/api_messages.h"
 #include "common/options_switches.h"
 #include "ipc/ipc_message_macros.h"
@@ -38,7 +39,9 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
                            base::DictionaryValue* options)
     : content::WebContentsObserver(web_contents),
       inspectable_web_contents_(
-          brightray::InspectableWebContents::Create(web_contents)) {
+          brightray::InspectableWebContents::Create(web_contents)),
+      window_going_to_destroy_(false),
+      can_destroy_window_(false) {
   web_contents->SetDelegate(this);
 
   windows_.push_back(this);
@@ -132,6 +135,26 @@ void NativeWindow::CloseDevTools() {
   inspectable_web_contents()->GetView()->CloseDevTools();
 }
 
+void NativeWindow::RequestToDestroyWindow() {
+  if (window_going_to_destroy_)
+    return;
+
+  window_going_to_destroy_ = true;
+
+  content::WebContents* web_contents(GetWebContents());
+
+  web_contents->OnCloseStarted();
+
+  if (web_contents->NeedToFireBeforeUnload())
+    web_contents->GetRenderViewHost()->FirePageBeforeUnload(false);
+  else
+    web_contents->Close();
+}
+
+bool NativeWindow::CanClose() {
+  return !GetWebContents()->NeedToFireBeforeUnload() || can_destroy_window_;
+}
+
 content::WebContents* NativeWindow::GetWebContents() const {
   return inspectable_web_contents_->GetWebContents();
 }
@@ -161,6 +184,26 @@ content::JavaScriptDialogManager* NativeWindow::GetJavaScriptDialogManager() {
   return dialog_manager_.get();
 }
 
+void NativeWindow::BeforeUnloadFired(content::WebContents* source,
+                                     bool proceed,
+                                     bool* proceed_to_fire_unload) {
+  *proceed_to_fire_unload = proceed;
+
+  if (proceed && window_going_to_destroy_) {
+    can_destroy_window_ = true;
+  } else {
+    window_going_to_destroy_ = false;
+    can_destroy_window_ = false;
+  }
+}
+
+void NativeWindow::CloseContents(content::WebContents* source) {
+  // When the web contents is gone, close the window immediately, but the
+  // wrapper itself will not get destroyed until you call delete.
+  // In this way, it would be safe to manage windows via smart pointers.
+  Close();
+}
+
 bool NativeWindow::OnMessageReceived(const IPC::Message& message) {
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(NativeWindow, message)
index 296c136..6b20e0d 100644 (file)
@@ -90,9 +90,18 @@ class NativeWindow : public content::WebContentsDelegate,
   virtual void FlashFrame(bool flash) = 0;
   virtual void SetKiosk(bool kiosk) = 0;
   virtual bool IsKiosk() = 0;
+
   virtual void ShowDevTools();
   virtual void CloseDevTools();
 
+  // Close the web page in this window and then desctruct.
+  virtual void RequestToDestroyWindow();
+
+  // Used by platform dependent code to determine whether the window can be
+  // closed. A window can only be closed when the beforeunload handler
+  // doesn't prevent it.
+  bool CanClose();
+
   content::WebContents* GetWebContents() const;
 
   void AddObserver(NativeWindowObserver* obs) {
@@ -119,6 +128,10 @@ class NativeWindow : public content::WebContentsDelegate,
                                   content::WebContents* new_contents) OVERRIDE;
   virtual content::JavaScriptDialogManager*
       GetJavaScriptDialogManager() OVERRIDE;
+  virtual void CloseContents(content::WebContents* source) OVERRIDE;
+  virtual void BeforeUnloadFired(content::WebContents* source,
+                                 bool proceed,
+                                 bool* proceed_to_fire_unload) OVERRIDE;
 
   // Implementations of content::WebContentsObserver.
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
@@ -149,6 +162,9 @@ class NativeWindow : public content::WebContentsDelegate,
 
   scoped_ptr<brightray::InspectableWebContents> inspectable_web_contents_;
 
+  bool window_going_to_destroy_;
+  bool can_destroy_window_;
+
   DISALLOW_COPY_AND_ASSIGN(NativeWindow);
 };
 
index f22989b..83effce 100644 (file)
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 
+@interface AtomNSWindowDelegate : NSObject<NSWindowDelegate> {
+ @private
+  atom::NativeWindowMac* shell_;
+}
+- (id)initWithShell:(atom::NativeWindowMac*)shell;
+@end
+
+@implementation AtomNSWindowDelegate
+
+- (id)initWithShell:(atom::NativeWindowMac*)shell {
+  if ((self = [super init]))
+    shell_ = shell;
+  return self;
+}
+
+- (BOOL)windowShouldClose:(id)window {
+  if (!shell_->CanClose()) {
+    shell_->RequestToDestroyWindow();
+    return NO;
+  }
+
+  [self release];
+
+  return YES;
+}
+
+@end
+
 @interface AtomNSWindow : AtomEventProcessingWindow {
  @private
   atom::NativeWindowMac* shell_;
@@ -70,6 +98,8 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
   [atom_window setShell:this];
 
   window_ = atom_window;
+  [window() setReleasedWhenClosed:NO];
+  [window() setDelegate:[[AtomNSWindowDelegate alloc] initWithShell:this]];
 
   // Disable fullscreen button when 'fullscreen' is specified to false.
   bool fullscreen;
@@ -84,7 +114,6 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
 }
 
 NativeWindowMac::~NativeWindowMac() {
-  Close();
   [window() release];
 }
 
index c8652d2..8442510 100644 (file)
@@ -30,6 +30,6 @@ void MoveItemToTrash(const base::FilePath& full_path);
 
 void Beep();
 
-}  // platform_util
+}  // namespace platform_util
 
 #endif  // ATOM_COMMON_PLATFORM_UTIL_H_