Commit de11bd62 authored by ananta@chromium.org's avatar ananta@chromium.org

Add support for invoking the Windows 8 metro style hung renderer dialog box. This functionality is

provided by the newly added class HungRendererDialogMetro. 

The actual dialog box is displayed by the metro driver.dll and the functionality to create and display
this is invoked via the exported functions ShowDialogBox and DismissDialogBox. The handlers to be run when
the user clicks on the kill process/wait buttons are passed into the ShowDialogBox function.

Factored out the platform specific portion of the kill process functionality in the static function
HungRendererDialogView::KillRendererProcess which is conditionally compiled for the platform.

BUG=125672
R=sky
Review URL: https://chromiumcodereview.appspot.com/10806079

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@148258 0039d316-1c4b-4281-b951-d872f2087c98
parent 634350c1
......@@ -39,9 +39,20 @@
#include "ui/aura/window.h"
#endif
#if defined(OS_WIN)
#include "chrome/browser/hang_monitor/hang_crash_dump_win.h"
#endif
// These functions allow certain chrome platforms to override the default hung
// renderer dialog. For e.g. Chrome on Windows 8 metro
bool PlatformShowCustomHungRendererDialog(WebContents* contents);
bool PlatformHideCustomHungRendererDialog(WebContents* contents);
#if !defined(OS_WIN)
bool PlatformShowCustomHungRendererDialog(WebContents* contents) {
return false;
}
bool PlatformHideCustomHungRendererDialog(WebContents* contents) {
return false;
}
#endif // OS_WIN
HungRendererDialogView* HungRendererDialogView::g_instance_ = NULL;
......@@ -173,8 +184,6 @@ static const int kTableViewHeight = 100;
///////////////////////////////////////////////////////////////////////////////
// HungRendererDialogView, public:
#if !defined(OS_WIN)
// static
HungRendererDialogView* HungRendererDialogView::Create() {
if (!g_instance_) {
......@@ -183,13 +192,28 @@ HungRendererDialogView* HungRendererDialogView::Create() {
}
return g_instance_;
}
#endif // defined(OS_WIN)
// static
HungRendererDialogView* HungRendererDialogView::GetInstance() {
return g_instance_;
}
// static
bool HungRendererDialogView::IsFrameActive(WebContents* contents) {
gfx::NativeView frame_view =
platform_util::GetTopLevel(contents->GetNativeView());
return platform_util::IsWindowActive(frame_view);
}
#if !defined(OS_WIN)
// static
void HungRendererDialogView::KillRendererProcess(
base::ProcessHandle process_handle) {
base::KillProcess(process_handle, content::RESULT_CODE_HUNG, false);
}
#endif // OS_WIN
HungRendererDialogView::HungRendererDialogView()
: hung_pages_table_(NULL),
kill_button_(NULL),
......@@ -208,7 +232,8 @@ void HungRendererDialogView::ShowForWebContents(WebContents* contents) {
// Don't show the warning unless the foreground window is the frame, or this
// window (but still invisible). If the user has another window or
// application selected, activating ourselves is rude.
if (!IsFrameActive(contents))
if (!IsFrameActive(contents) &&
!platform_util::IsWindowActive(GetWidget()->GetNativeWindow()))
return;
if (!GetWidget()->IsActive()) {
......@@ -306,13 +331,7 @@ void HungRendererDialogView::ButtonPressed(
base::ProcessHandle process_handle =
hung_pages_table_model_->GetRenderProcessHost()->GetHandle();
#if defined(OS_WIN)
// Try to generate a crash report for the hung process.
CrashDumpAndTerminateHungChildProcess(process_handle);
#else
// Kill the process.
base::KillProcess(process_handle, content::RESULT_CODE_HUNG, false);
#endif
KillRendererProcess(process_handle);
}
}
......@@ -333,16 +352,6 @@ void HungRendererDialogView::ViewHierarchyChanged(bool is_add,
Init();
}
bool HungRendererDialogView::IsFrameActive(WebContents* contents) {
gfx::NativeView frame_view =
platform_util::GetTopLevel(contents->GetNativeView());
if (!platform_util::IsWindowActive(frame_view) &&
!platform_util::IsWindowActive(GetWidget()->GetNativeWindow())) {
return false;
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
// HungRendererDialogView, private:
......@@ -452,7 +461,8 @@ void HungRendererDialogView::InitClass() {
namespace chrome {
void ShowHungRendererDialog(WebContents* contents) {
if (!logging::DialogsAreSuppressed()) {
if (!logging::DialogsAreSuppressed() &&
!PlatformShowCustomHungRendererDialog(contents)) {
HungRendererDialogView* view = HungRendererDialogView::Create();
view->ShowForWebContents(contents);
}
......@@ -460,6 +470,7 @@ void ShowHungRendererDialog(WebContents* contents) {
void HideHungRendererDialog(WebContents* contents) {
if (!logging::DialogsAreSuppressed() &&
!PlatformHideCustomHungRendererDialog(contents) &&
HungRendererDialogView::GetInstance())
HungRendererDialogView::GetInstance()->EndForWebContents(contents);
}
......
......@@ -99,9 +99,17 @@ class HungRendererDialogView : public views::DialogDelegateView,
// Factory function for creating an instance of the HungRendererDialogView
// class. At any given point only one instance can be active.
static HungRendererDialogView* Create();
// Returns a pointer to the singleton instance if any.
static HungRendererDialogView* GetInstance();
// Platform specific function to kill the renderer process identified by the
// handle passed in.
static void KillRendererProcess(base::ProcessHandle process_handle);
// Returns true if the frame is in the foreground.
static bool IsFrameActive(WebContents* contents);
virtual void ShowForWebContents(WebContents* contents);
virtual void EndForWebContents(WebContents* contents);
......@@ -130,9 +138,6 @@ class HungRendererDialogView : public views::DialogDelegateView,
views::View* parent,
views::View* child) OVERRIDE;
// Returns true if the frame is in the foreground.
bool IsFrameActive(WebContents* contents);
static HungRendererDialogView* g_instance_;
private:
......
......@@ -4,17 +4,167 @@
#include "chrome/browser/ui/views/hung_renderer_view_win.h"
#include "base/win/metro.h"
#include "chrome/browser/hang_monitor/hang_crash_dump_win.h"
#include "chrome/browser/ui/views/hung_renderer_view.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
// Metro functions for displaying and dismissing a dialog box.
typedef void (*MetroShowDialogBox)(
const wchar_t* title,
const wchar_t* content,
const wchar_t* button1_label,
const wchar_t* button2_label,
base::win::MetroDialogButtonPressedHandler button1_handler,
base::win::MetroDialogButtonPressedHandler button2_handler);
typedef void (*MetroDismissDialogBox)();
using content::BrowserThread;
using content::WebContents;
HungRendererDialogMetro* HungRendererDialogMetro::g_instance_ = NULL;
bool PlatformShowCustomHungRendererDialog(WebContents* contents) {
if (!base::win::IsMetroProcess())
return false;
HungRendererDialogMetro::Create()->Show(contents);
return true;
}
bool PlatformHideCustomHungRendererDialog(WebContents* contents) {
if (!base::win::IsMetroProcess())
return false;
if (HungRendererDialogMetro::GetInstance())
HungRendererDialogMetro::GetInstance()->Hide(contents);
return true;
}
// static
void HungRendererDialogView::KillRendererProcess(
base::ProcessHandle process_handle) {
// Try to generate a crash report for the hung process.
CrashDumpAndTerminateHungChildProcess(process_handle);
}
// static
HungRendererDialogMetro* HungRendererDialogMetro::Create() {
if (!GetInstance())
g_instance_ = new HungRendererDialogMetro;
return g_instance_;
}
// static
HungRendererDialogView* HungRendererDialogView::Create() {
if (!g_instance_)
g_instance_ = new HungRendererDialogViewWin();
HungRendererDialogMetro* HungRendererDialogMetro::GetInstance() {
return g_instance_;
}
void HungRendererDialogViewWin::ShowForWebContents(WebContents* contents) {
HungRendererDialogView::ShowForWebContents(contents);
HungRendererDialogMetro::HungRendererDialogMetro()
: contents_(NULL),
metro_dialog_displayed_(false) {
}
HungRendererDialogMetro::~HungRendererDialogMetro() {
g_instance_ = NULL;
}
void HungRendererDialogViewWin::EndForWebContents(WebContents* contents) {
HungRendererDialogView::EndForWebContents(contents);
void HungRendererDialogMetro::Show(WebContents* contents) {
if (!metro_dialog_displayed_ &&
HungRendererDialogView::IsFrameActive(contents)) {
HMODULE metro_dll = base::win::GetMetroModule();
DCHECK(metro_dll);
if (metro_dll) {
MetroShowDialogBox show_dialog_box = reinterpret_cast<MetroShowDialogBox>
(::GetProcAddress(metro_dll, "ShowDialogBox"));
DCHECK(show_dialog_box);
if (show_dialog_box) {
string16 dialog_box_title =
l10n_util::GetStringUTF16(IDS_BROWSER_HANGMONITOR_RENDERER_TITLE);
string16 kill_button_label =
l10n_util::GetStringUTF16(IDS_BROWSER_HANGMONITOR_RENDERER_END);
string16 wait_button_label =
l10n_util::GetStringUTF16(IDS_BROWSER_HANGMONITOR_RENDERER_WAIT);
contents_ = contents;
metro_dialog_displayed_ = true;
(*show_dialog_box)(dialog_box_title.c_str(),
contents->GetTitle().c_str(),
kill_button_label.c_str(),
wait_button_label.c_str(),
HungRendererDialogMetro::OnMetroKillProcess,
HungRendererDialogMetro::OnMetroWait);
}
}
}
}
void HungRendererDialogMetro::Hide(WebContents* contents) {
HMODULE metro_dll = base::win::GetMetroModule();
DCHECK(metro_dll);
if (metro_dll) {
MetroDismissDialogBox dismiss_dialog_box =
reinterpret_cast<MetroDismissDialogBox>
(::GetProcAddress(metro_dll, "DismissDialogBox"));
DCHECK(dismiss_dialog_box);
if (dismiss_dialog_box) {
(*dismiss_dialog_box)();
ResetMetroState();
}
}
}
void HungRendererDialogMetro::ResetMetroState() {
metro_dialog_displayed_ = false;
contents_ = NULL;
delete g_instance_;
}
// static
void HungRendererDialogMetro::OnMetroKillProcess() {
// Metro chrome will invoke these handlers on the metro thread. Ensure that
// we switch to the UI thread.
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(HungRendererDialogMetro::OnMetroKillProcess));
return;
}
// Its possible that we got deleted in the meantime.
if (!GetInstance())
return;
DCHECK(GetInstance()->contents_);
HungRendererDialogView::KillRendererProcess(
GetInstance()->contents_->GetRenderProcessHost()->GetHandle());
// The metro dialog box is dismissed when the button handlers are invoked.
GetInstance()->ResetMetroState();
}
// static
void HungRendererDialogMetro::OnMetroWait() {
// Metro chrome will invoke these handlers on the metro thread. Ensure that
// we switch to the UI thread.
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(HungRendererDialogMetro::OnMetroWait));
return;
}
// Its possible that we got deleted in the meantime.
if (!GetInstance())
return;
GetInstance()->ResetMetroState();
}
......@@ -5,16 +5,45 @@
#ifndef CHROME_BROWSER_UI_VIEWS_HUNG_RENDERER_VIEW_WIN_H_
#define CHROME_BROWSER_UI_VIEWS_HUNG_RENDERER_VIEW_WIN_H_
#include "chrome/browser/ui/views/hung_renderer_view.h"
#include "base/basictypes.h"
#include "chrome/browser/ui/tab_contents/tab_contents.h"
#include "content/public/browser/web_contents.h"
class HungRendererDialogViewWin : public HungRendererDialogView {
// This class provides functionality to display a Windows 8 metro style hung
// renderer dialog.
class HungRendererDialogMetro {
public:
HungRendererDialogViewWin() {}
virtual ~HungRendererDialogViewWin() {}
// Creates or returns the global instance of the HungRendererDialogMetro
// class
static HungRendererDialogMetro* Create();
static HungRendererDialogMetro* GetInstance();
// HungRendererDialogView overrides.
virtual void ShowForWebContents(WebContents* contents) OVERRIDE;
virtual void EndForWebContents(WebContents* contents) OVERRIDE;
void Show(content::WebContents* contents);
void Hide(content::WebContents* contents);
private:
HungRendererDialogMetro();
~HungRendererDialogMetro();
// Handlers for the hang monitor dialog displayed in Windows 8 metro.
static void OnMetroKillProcess();
static void OnMetroWait();
// Resets Windows 8 metro specific state like whether the dialog was
// displayed, etc.
void ResetMetroState();
content::WebContents* contents_;
// Set to true if the metro version of the hang dialog is displayed.
// Helps ensure that only one instance of the dialog is displayed at any
// given time.
bool metro_dialog_displayed_;
// Pointer to the global instance of the HungRendererDialogMetro class.
static HungRendererDialogMetro* g_instance_;
DISALLOW_COPY_AND_ASSIGN(HungRendererDialogMetro);
};
#endif // CHROME_BROWSER_UI_VIEWS_HUNG_RENDERER_VIEW_WIN_H_
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment