// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #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" #include "win8/util/win8_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 (!win8::IsSingleWindowMetroMode()) return false; HungRendererDialogMetro::Create()->Show(contents); return true; } bool PlatformHideCustomHungRendererDialog(WebContents* contents) { if (!win8::IsSingleWindowMetroMode()) 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 HungRendererDialogMetro* HungRendererDialogMetro::GetInstance() { return g_instance_; } HungRendererDialogMetro::HungRendererDialogMetro() : contents_(NULL), metro_dialog_displayed_(false) { } HungRendererDialogMetro::~HungRendererDialogMetro() { g_instance_ = NULL; } 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 (::GetProcAddress(metro_dll, "ShowDialogBox")); DCHECK(show_dialog_box); if (show_dialog_box) { base::string16 dialog_box_title = l10n_util::GetStringUTF16(IDS_BROWSER_HANGMONITOR_RENDERER_TITLE); base::string16 kill_button_label = l10n_util::GetStringUTF16(IDS_BROWSER_HANGMONITOR_RENDERER_END); base::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 (::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(); }