diff options
author | rohitrao@chromium.org <rohitrao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-24 16:18:02 +0000 |
---|---|---|
committer | rohitrao@chromium.org <rohitrao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-24 16:18:02 +0000 |
commit | b89d4cdd649ad1e70d5bad3e18f6f721761861d5 (patch) | |
tree | 461b6977d53f8f9a3bd92e45bba66bd1069d75ba /chrome/browser/cocoa/hung_renderer_controller.mm | |
parent | 734d9be68c10a2d85336baaf3f21d21520ea9f5c (diff) | |
download | chromium_src-b89d4cdd649ad1e70d5bad3e18f6f721761861d5.zip chromium_src-b89d4cdd649ad1e70d5bad3e18f6f721761861d5.tar.gz chromium_src-b89d4cdd649ad1e70d5bad3e18f6f721761861d5.tar.bz2 |
Initial implementation of the hung renderer dialog on Mac.
BUG=http://crbug.com/13152
TEST=Navigate to about:hang in a tab, verify that the dialog comes up.
Review URL: http://codereview.chromium.org/146012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19125 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa/hung_renderer_controller.mm')
-rw-r--r-- | chrome/browser/cocoa/hung_renderer_controller.mm | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/chrome/browser/cocoa/hung_renderer_controller.mm b/chrome/browser/cocoa/hung_renderer_controller.mm new file mode 100644 index 0000000..a9ec7ea --- /dev/null +++ b/chrome/browser/cocoa/hung_renderer_controller.mm @@ -0,0 +1,143 @@ +// 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 <Cocoa/Cocoa.h> + +#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); + [[self window] performClose:nil]; +} + +- (IBAction)wait:(id)sender { + if (hungContents_ && hungContents_->render_view_host()) + hungContents_->render_view_host()->RestartHangMonitorTimeout(); + [[self window] performClose:nil]; +} + +- (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()) { + // If you switch tabs with the dialog open, + // HungRendererDialog::EndForTabContents() is called after the + // RWHV is hidden. performClose: runs a nested message loop, + // during which the RWHV is drawn at least once, failing a DCHECK + // that ensures it is never drawn while hidden. The workaround + // here is to call close, which closes the window immediately with + // no nested message loop. + [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]; +} |