summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa/hung_renderer_controller.mm
diff options
context:
space:
mode:
authorrohitrao@chromium.org <rohitrao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-24 16:18:02 +0000
committerrohitrao@chromium.org <rohitrao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-24 16:18:02 +0000
commitb89d4cdd649ad1e70d5bad3e18f6f721761861d5 (patch)
tree461b6977d53f8f9a3bd92e45bba66bd1069d75ba /chrome/browser/cocoa/hung_renderer_controller.mm
parent734d9be68c10a2d85336baaf3f21d21520ea9f5c (diff)
downloadchromium_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.mm143
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];
+}