// Copyright (c) 2009 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. #import #include "app/l10n_util.h" #include "base/mac_util.h" #include "base/process_util.h" #include "base/sys_string_conversions.h" #include "grit/generated_resources.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/hung_renderer_dialog.h" #import "chrome/browser/cocoa/hung_renderer_controller.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/logging_chrome.h" #include "chrome/common/result_codes.h" #include "grit/chromium_strings.h" namespace { // We only support showing one of these at a time per app. The // controller owns itself and is released when its window is closed. HungRendererController* g_instance = NULL; } // end namespace @implementation HungRendererController - (id)initWithWindowNibName:(NSString*)nibName { NSString* nibpath = [mac_util::MainAppBundle() pathForResource:nibName ofType:@"nib"]; self = [super initWithWindowNibPath:nibpath owner:self]; if (self) { [tableView_ setDataSource:self]; } return self; } - (void)dealloc { DCHECK(!g_instance); [super dealloc]; } - (void)awakeFromNib { // This is easier than creating a localizer, since we only have one // string to modify. std::wstring productString = l10n_util::GetString(IDS_PRODUCT_NAME); [[self window] setTitle:base::SysWideToNSString(productString)]; } - (IBAction)kill:(id)sender { if (hungContents_) base::KillProcess(hungContents_->process()->process().handle(), ResultCodes::HUNG, false); // Cannot call performClose:, because the close button is disabled. [self close]; } - (IBAction)wait:(id)sender { if (hungContents_ && hungContents_->render_view_host()) hungContents_->render_view_host()->RestartHangMonitorTimeout(); // Cannot call performClose:, because the close button is disabled. [self close]; } - (int)numberOfRowsInTableView:(NSTableView *)aTableView { return hungRenderers_.size(); } - (id)tableView:(NSTableView*)aTableView objectValueForTableColumn:(NSTableColumn*)column row:(int)rowIndex { // TODO(rohitrao): Add favicons. TabContents* contents = hungRenderers_[rowIndex]; string16 title = contents->GetTitle(); if (title.empty()) title = l10n_util::GetStringUTF16(IDS_TAB_UNTITLED_TITLE); return base::SysUTF16ToNSString(title); } - (void)windowWillClose:(NSNotification*)notification { // We have to reset g_instance before autoreleasing the window, // because we want to avoid reusing the same dialog if someone calls // HungRendererDialog::ShowForTabContents() between the autorelease // call and the actual dealloc. g_instance = nil; [self autorelease]; } - (void)showForTabContents:(TabContents*)contents { DCHECK(contents); hungContents_ = contents; hungRenderers_.clear(); for (TabContentsIterator it; !it.done(); ++it) { if (it->process() == hungContents_->process()) hungRenderers_.push_back(*it); } [tableView_ reloadData]; [[self window] center]; [self showWindow:self]; } - (void)endForTabContents:(TabContents*)contents { DCHECK(contents); DCHECK(hungContents_); if (hungContents_ && hungContents_->process() == contents->process()) { // Cannot call performClose:, because the close button is disabled. [self close]; } } @end @implementation HungRendererController (JustForTesting) - (NSButton*)killButton { return killButton_; } - (NSButton*)waitButton { return waitButton_; } @end // static void HungRendererDialog::ShowForTabContents(TabContents* contents) { if (!logging::DialogsAreSuppressed()) { if (!g_instance) g_instance = [[HungRendererController alloc] initWithWindowNibName:@"HungRendererDialog"]; [g_instance showForTabContents:contents]; } } // static void HungRendererDialog::HideForTabContents(TabContents* contents) { if (!logging::DialogsAreSuppressed() && g_instance) [g_instance endForTabContents:contents]; }