diff --git a/browser/native_window.cc b/browser/native_window.cc index fe7befb65a2..86404014e7a 100644 --- a/browser/native_window.cc +++ b/browser/native_window.cc @@ -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) diff --git a/browser/native_window.h b/browser/native_window.h index 296c136c207..6b20e0d5915 100644 --- a/browser/native_window.h +++ b/browser/native_window.h @@ -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 inspectable_web_contents_; + bool window_going_to_destroy_; + bool can_destroy_window_; + DISALLOW_COPY_AND_ASSIGN(NativeWindow); }; diff --git a/browser/native_window_mac.mm b/browser/native_window_mac.mm index f22989bd01c..83effce4cc8 100644 --- a/browser/native_window_mac.mm +++ b/browser/native_window_mac.mm @@ -21,6 +21,34 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_view.h" +@interface AtomNSWindowDelegate : NSObject { + @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]; } diff --git a/common/platform_util.h b/common/platform_util.h index c8652d2f603..8442510fbe5 100644 --- a/common/platform_util.h +++ b/common/platform_util.h @@ -30,6 +30,6 @@ void MoveItemToTrash(const base::FilePath& full_path); void Beep(); -} // platform_util +} // namespace platform_util #endif // ATOM_COMMON_PLATFORM_UTIL_H_