Merge pull request #133 from atom/sheet-unresponsive

Do not send "unresponsive" message if window is showing a modal dialog.
This commit is contained in:
Cheng Zhao 2013-12-04 06:11:38 -08:00
commit 170ef2362f
7 changed files with 62 additions and 22 deletions

View file

@ -4,6 +4,7 @@
#include "browser/api/atom_api_window.h" #include "browser/api/atom_api_window.h"
#include "base/process_util.h"
#include "base/values.h" #include "base/values.h"
#include "browser/native_window.h" #include "browser/native_window.h"
#include "common/v8_conversions.h" #include "common/v8_conversions.h"
@ -126,8 +127,15 @@ v8::Handle<v8::Value> Window::New(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::Destroy(const v8::Arguments &args) { v8::Handle<v8::Value> Window::Destroy(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK; UNWRAP_WINDOW_AND_CHECK;
base::ProcessHandle handle = self->window_->GetRenderProcessHandle();
delete self; delete self;
// Check if the render process is terminated, it could happen that the render
// became a zombie.
if (!base::WaitForSingleProcess(handle,
base::TimeDelta::FromMilliseconds(500)))
base::KillProcess(handle, 0, true);
return v8::Undefined(); return v8::Undefined();
} }

View file

@ -44,7 +44,6 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
: content::WebContentsObserver(web_contents), : content::WebContentsObserver(web_contents),
has_frame_(true), has_frame_(true),
is_closed_(false), is_closed_(false),
not_responding_(false),
weak_factory_(this), weak_factory_(this),
inspectable_web_contents_( inspectable_web_contents_(
brightray::InspectableWebContents::Create(web_contents)) { brightray::InspectableWebContents::Create(web_contents)) {
@ -200,6 +199,10 @@ bool NativeWindow::SetIcon(const std::string& str_path) {
return true; return true;
} }
base::ProcessHandle NativeWindow::GetRenderProcessHandle() {
return GetWebContents()->GetRenderProcessHost()->GetHandle();
}
void NativeWindow::CapturePage(const gfx::Rect& rect, void NativeWindow::CapturePage(const gfx::Rect& rect,
const CapturePageCallback& callback) { const CapturePageCallback& callback) {
GetWebContents()->GetRenderViewHost()->CopyFromBackingStore( GetWebContents()->GetRenderViewHost()->CopyFromBackingStore(
@ -226,7 +229,16 @@ void NativeWindow::CloseWebContents() {
// not closed in 500ms, in this way we can quickly show the unresponsive // not closed in 500ms, in this way we can quickly show the unresponsive
// dialog when the window is busy executing some script withouth waiting for // dialog when the window is busy executing some script withouth waiting for
// the unresponsive timeout. // the unresponsive timeout.
RendererUnresponsive(web_contents); if (window_unresposive_closure_.IsCancelled()) {
window_unresposive_closure_.Reset(
base::Bind(&NativeWindow::RendererUnresponsive,
weak_factory_.GetWeakPtr(),
web_contents));
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
window_unresposive_closure_.callback(),
base::TimeDelta::FromMilliseconds(500));
}
if (web_contents->NeedToFireBeforeUnload()) if (web_contents->NeedToFireBeforeUnload())
web_contents->GetRenderViewHost()->FirePageBeforeUnload(false); web_contents->GetRenderViewHost()->FirePageBeforeUnload(false);
@ -286,7 +298,7 @@ void NativeWindow::BeforeUnloadFired(content::WebContents* tab,
WindowList::WindowCloseCancelled(this); WindowList::WindowCloseCancelled(this);
// When the "beforeunload" callback is fired the window is certainly live. // When the "beforeunload" callback is fired the window is certainly live.
not_responding_ = false; window_unresposive_closure_.Cancel();
} }
void NativeWindow::RequestToLockMouse(content::WebContents* web_contents, void NativeWindow::RequestToLockMouse(content::WebContents* web_contents,
@ -331,7 +343,7 @@ void NativeWindow::CloseContents(content::WebContents* source) {
NotifyWindowClosed(); NotifyWindowClosed();
// Do not sent "unresponsive" event after window is closed. // Do not sent "unresponsive" event after window is closed.
not_responding_ = false; window_unresposive_closure_.Cancel();
} }
bool NativeWindow::IsPopupOrPanel(const content::WebContents* source) const { bool NativeWindow::IsPopupOrPanel(const content::WebContents* source) const {
@ -340,16 +352,16 @@ bool NativeWindow::IsPopupOrPanel(const content::WebContents* source) const {
} }
void NativeWindow::RendererUnresponsive(content::WebContents* source) { void NativeWindow::RendererUnresponsive(content::WebContents* source) {
not_responding_ = true; window_unresposive_closure_.Cancel();
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE, if (!HasModalDialog())
base::Bind(&NativeWindow::RendererUnresponsiveDelayed, FOR_EACH_OBSERVER(NativeWindowObserver,
weak_factory_.GetWeakPtr()), observers_,
base::TimeDelta::FromMilliseconds(500)); OnRendererUnresponsive());
} }
void NativeWindow::RendererResponsive(content::WebContents* source) { void NativeWindow::RendererResponsive(content::WebContents* source) {
not_responding_ = false; window_unresposive_closure_.Cancel();
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererResponsive()); FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererResponsive());
} }
@ -371,13 +383,6 @@ void NativeWindow::RenderViewGone(base::TerminationStatus status) {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererCrashed()); FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererCrashed());
} }
void NativeWindow::RendererUnresponsiveDelayed() {
if (not_responding_)
FOR_EACH_OBSERVER(NativeWindowObserver,
observers_,
OnRendererUnresponsive());
}
void NativeWindow::Observe(int type, void NativeWindow::Observe(int type,
const content::NotificationSource& source, const content::NotificationSource& source,
const content::NotificationDetails& details) { const content::NotificationDetails& details) {

View file

@ -6,6 +6,7 @@
#define ATOM_BROWSER_NATIVE_WINDOW_H_ #define ATOM_BROWSER_NATIVE_WINDOW_H_
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/cancelable_callback.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
@ -99,6 +100,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual void FlashFrame(bool flash) = 0; virtual void FlashFrame(bool flash) = 0;
virtual void SetKiosk(bool kiosk) = 0; virtual void SetKiosk(bool kiosk) = 0;
virtual bool IsKiosk() = 0; virtual bool IsKiosk() = 0;
virtual bool HasModalDialog() = 0;
virtual gfx::NativeWindow GetNativeWindow() = 0; virtual gfx::NativeWindow GetNativeWindow() = 0;
virtual bool IsClosed() const { return is_closed_; } virtual bool IsClosed() const { return is_closed_; }
@ -112,6 +114,10 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual void RestartHangMonitorTimeout(); virtual void RestartHangMonitorTimeout();
virtual bool SetIcon(const std::string& path); virtual bool SetIcon(const std::string& path);
// Returns the process handle of render process, useful for killing the
// render process manually
virtual base::ProcessHandle GetRenderProcessHandle();
// Captures the page with |rect|, |callback| would be called when capturing is // Captures the page with |rect|, |callback| would be called when capturing is
// done. // done.
virtual void CapturePage(const gfx::Rect& rect, virtual void CapturePage(const gfx::Rect& rect,
@ -191,8 +197,6 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
gfx::Image icon_; gfx::Image icon_;
private: private:
void RendererUnresponsiveDelayed();
// Called when CapturePage has done. // Called when CapturePage has done.
void OnCapturePageDone(const CapturePageCallback& callback, void OnCapturePageDone(const CapturePageCallback& callback,
bool succeed, bool succeed,
@ -214,8 +218,9 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
// The windows has been closed. // The windows has been closed.
bool is_closed_; bool is_closed_;
// The window is not responding. // Closure that would be called when window is unresponsive when closing,
bool not_responding_; // it should be cancelled when we can prove that the window is responsive.
base::CancelableClosure window_unresposive_closure_;
base::WeakPtrFactory<NativeWindow> weak_factory_; base::WeakPtrFactory<NativeWindow> weak_factory_;

View file

@ -53,6 +53,7 @@ class NativeWindowMac : public NativeWindow {
virtual void FlashFrame(bool flash) OVERRIDE; virtual void FlashFrame(bool flash) OVERRIDE;
virtual void SetKiosk(bool kiosk) OVERRIDE; virtual void SetKiosk(bool kiosk) OVERRIDE;
virtual bool IsKiosk() OVERRIDE; virtual bool IsKiosk() OVERRIDE;
virtual bool HasModalDialog() OVERRIDE;
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE; virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
void NotifyWindowBlur() { NativeWindow::NotifyWindowBlur(); } void NotifyWindowBlur() { NativeWindow::NotifyWindowBlur(); }

View file

@ -387,6 +387,10 @@ bool NativeWindowMac::IsKiosk() {
return is_kiosk_; return is_kiosk_;
} }
bool NativeWindowMac::HasModalDialog() {
return [window() attachedSheet] != nil;
}
gfx::NativeWindow NativeWindowMac::GetNativeWindow() { gfx::NativeWindow NativeWindowMac::GetNativeWindow() {
return window(); return window();
} }

View file

@ -194,6 +194,17 @@ class NativeWindowFramelessView : public views::NonClientFrameView {
DISALLOW_COPY_AND_ASSIGN(NativeWindowFramelessView); DISALLOW_COPY_AND_ASSIGN(NativeWindowFramelessView);
}; };
bool WindowHasModalDialog(HWND parent, HWND except, HWND after = NULL) {
HWND hwnd = ::FindWindowEx(parent, after, NULL, NULL);
if (hwnd != except &&
(::GetWindowLong(hwnd, GWL_STYLE) & (WS_VISIBLE | WS_POPUP)))
return true;
else if (hwnd == NULL)
return false;
else
return WindowHasModalDialog(parent, except, hwnd);
}
} // namespace } // namespace
NativeWindowWin::NativeWindowWin(content::WebContents* web_contents, NativeWindowWin::NativeWindowWin(content::WebContents* web_contents,
@ -359,6 +370,11 @@ bool NativeWindowWin::IsKiosk() {
return IsFullscreen(); return IsFullscreen();
} }
bool NativeWindowWin::HasModalDialog() {
return WindowHasModalDialog(GetNativeWindow(),
GetWebContents()->GetView()->GetNativeView());
}
gfx::NativeWindow NativeWindowWin::GetNativeWindow() { gfx::NativeWindow NativeWindowWin::GetNativeWindow() {
return window_->GetNativeView(); return window_->GetNativeView();
} }

View file

@ -65,6 +65,7 @@ class NativeWindowWin : public NativeWindow,
virtual void FlashFrame(bool flash) OVERRIDE; virtual void FlashFrame(bool flash) OVERRIDE;
virtual void SetKiosk(bool kiosk) OVERRIDE; virtual void SetKiosk(bool kiosk) OVERRIDE;
virtual bool IsKiosk() OVERRIDE; virtual bool IsKiosk() OVERRIDE;
virtual bool HasModalDialog() OVERRIDE;
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE; virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
void OnMenuCommand(int position, HMENU menu); void OnMenuCommand(int position, HMENU menu);