Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / hung_renderer_controller.mm
bloba72eecaccb30edfbea1d486fab0293deeaff8fb6
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "chrome/browser/ui/cocoa/hung_renderer_controller.h"
7 #import <Cocoa/Cocoa.h>
9 #include "base/mac/bundle_locations.h"
10 #include "base/process/process.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "chrome/browser/favicon/favicon_tab_helper.h"
13 #import "chrome/browser/ui/cocoa/multi_key_equivalent_button.h"
14 #import "chrome/browser/ui/cocoa/tab_contents/favicon_util_mac.h"
15 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
16 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
17 #include "chrome/common/logging_chrome.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/common/result_codes.h"
22 #include "grit/theme_resources.h"
23 #include "skia/ext/skia_utils_mac.h"
24 #include "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
25 #include "ui/base/l10n/l10n_util_mac.h"
26 #include "ui/base/resource/resource_bundle.h"
27 #include "ui/gfx/image/image.h"
29 using content::WebContents;
31 namespace {
32 // We only support showing one of these at a time per app.  The
33 // controller owns itself and is released when its window is closed.
34 HungRendererController* g_instance = NULL;
35 }  // namespace
37 class HungRendererWebContentsObserverBridge
38     : public content::WebContentsObserver {
39  public:
40   HungRendererWebContentsObserverBridge(WebContents* web_contents,
41                                         HungRendererController* controller)
42     : content::WebContentsObserver(web_contents),
43       controller_(controller) {
44   }
46  protected:
47   // WebContentsObserver overrides:
48   void RenderProcessGone(base::TerminationStatus status) override {
49     [controller_ renderProcessGone];
50   }
51   void WebContentsDestroyed() override { [controller_ renderProcessGone]; }
53  private:
54   HungRendererController* controller_;  // weak
56   DISALLOW_COPY_AND_ASSIGN(HungRendererWebContentsObserverBridge);
59 @implementation HungRendererController
61 - (id)initWithWindowNibName:(NSString*)nibName {
62   NSString* nibpath = [base::mac::FrameworkBundle() pathForResource:nibName
63                                                              ofType:@"nib"];
64   self = [super initWithWindowNibPath:nibpath owner:self];
65   if (self) {
66     [tableView_ setDataSource:self];
67   }
68   return self;
71 - (void)dealloc {
72   DCHECK(!g_instance);
73   [tableView_ setDataSource:nil];
74   [tableView_ setDelegate:nil];
75   [killButton_ setTarget:nil];
76   [waitButton_ setTarget:nil];
77   [super dealloc];
80 - (void)awakeFromNib {
81   // Load in the image
82   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
83   NSImage* backgroundImage =
84       rb.GetNativeImageNamed(IDR_FROZEN_TAB_ICON).ToNSImage();
85   [imageView_ setImage:backgroundImage];
87   // Make the message fit.
88   CGFloat messageShift =
89     [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:messageView_];
91   // Move the graphic up to be top even with the message.
92   NSRect graphicFrame = [imageView_ frame];
93   graphicFrame.origin.y += messageShift;
94   [imageView_ setFrame:graphicFrame];
96   // Make the window taller to fit everything.
97   NSSize windowDelta = NSMakeSize(0, messageShift);
98   [GTMUILocalizerAndLayoutTweaker
99       resizeWindowWithoutAutoResizingSubViews:[self window]
100                                         delta:windowDelta];
102   // Make the "wait" button respond to additional keys.  By setting this to
103   // @"\e", it will respond to both Esc and Command-. (period).
104   KeyEquivalentAndModifierMask key;
105   key.charCode = @"\e";
106   [waitButton_ addKeyEquivalent:key];
109 + (void)showForWebContents:(content::WebContents*)contents {
110   if (!logging::DialogsAreSuppressed()) {
111     if (!g_instance)
112       g_instance = [[HungRendererController alloc]
113           initWithWindowNibName:@"HungRendererDialog"];
114     [g_instance showForWebContents:contents];
115   }
118 + (void)endForWebContents:(content::WebContents*)contents {
119   if (!logging::DialogsAreSuppressed() && g_instance)
120     [g_instance endForWebContents:contents];
123 - (IBAction)kill:(id)sender {
124   if (hungContents_) {
125     base::Process process = base::Process::DeprecatedGetProcessFromHandle(
126         hungContents_->GetRenderProcessHost()->GetHandle());
127     process.Terminate(content::RESULT_CODE_HUNG, false);
128   }
129   // Cannot call performClose:, because the close button is disabled.
130   [self close];
133 - (IBAction)wait:(id)sender {
134   if (hungContents_ && hungContents_->GetRenderViewHost())
135     hungContents_->GetRenderViewHost()->RestartHangMonitorTimeout();
136   // Cannot call performClose:, because the close button is disabled.
137   [self close];
140 - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView {
141   return [hungTitles_ count];
144 - (id)tableView:(NSTableView*)aTableView
145       objectValueForTableColumn:(NSTableColumn*)column
146             row:(NSInteger)rowIndex {
147   return [NSNumber numberWithInt:NSOffState];
150 - (NSCell*)tableView:(NSTableView*)tableView
151     dataCellForTableColumn:(NSTableColumn*)tableColumn
152                        row:(NSInteger)rowIndex {
153   NSCell* cell = [tableColumn dataCellForRow:rowIndex];
155   if ([[tableColumn identifier] isEqualToString:@"title"]) {
156     DCHECK([cell isKindOfClass:[NSButtonCell class]]);
157     NSButtonCell* buttonCell = static_cast<NSButtonCell*>(cell);
158     [buttonCell setTitle:[hungTitles_ objectAtIndex:rowIndex]];
159     [buttonCell setImage:[hungFavicons_ objectAtIndex:rowIndex]];
160     [buttonCell setRefusesFirstResponder:YES];  // Don't push in like a button.
161     [buttonCell setHighlightsBy:NSNoCellMask];
162   }
163   return cell;
166 - (void)windowWillClose:(NSNotification*)notification {
167   // We have to reset g_instance before autoreleasing the window,
168   // because we want to avoid reusing the same dialog if someone calls
169   // chrome::ShowHungRendererDialog() between the autorelease call and the
170   // actual dealloc.
171   g_instance = nil;
173   // Prevent kills from happening after close if the user had the
174   // button depressed just when new activity was detected.
175   hungContents_ = NULL;
177   [self autorelease];
180 // TODO(shess): This could observe all of the tabs referenced in the
181 // loop, updating the dialog and keeping it up so long as any remain.
182 // Tabs closed by their renderer will close the dialog (that's
183 // activity!), so it would not add much value.  Also, the views
184 // implementation only monitors the initiating tab.
185 - (void)showForWebContents:(WebContents*)contents {
186   DCHECK(contents);
187   hungContents_ = contents;
188   hungContentsObserver_.reset(
189       new HungRendererWebContentsObserverBridge(contents, self));
190   base::scoped_nsobject<NSMutableArray> titles([[NSMutableArray alloc] init]);
191   base::scoped_nsobject<NSMutableArray> favicons([[NSMutableArray alloc] init]);
192   for (TabContentsIterator it; !it.done(); it.Next()) {
193     if (it->GetRenderProcessHost() == hungContents_->GetRenderProcessHost()) {
194       base::string16 title = it->GetTitle();
195       if (title.empty())
196         title = CoreTabHelper::GetDefaultTitle();
197       [titles addObject:base::SysUTF16ToNSString(title)];
198       [favicons addObject:mac::FaviconForWebContents(*it)];
199     }
200   }
201   hungTitles_.reset([titles copy]);
202   hungFavicons_.reset([favicons copy]);
203   [tableView_ reloadData];
205   [[self window] center];
206   [self showWindow:self];
209 - (void)endForWebContents:(WebContents*)contents {
210   DCHECK(contents);
211   DCHECK(hungContents_);
212   if (hungContents_ && hungContents_->GetRenderProcessHost() ==
213       contents->GetRenderProcessHost()) {
214     // Cannot call performClose:, because the close button is disabled.
215     [self close];
216   }
219 - (void)renderProcessGone {
220   // Cannot call performClose:, because the close button is disabled.
221   [self close];
224 @end
226 @implementation HungRendererController (JustForTesting)
227 - (NSButton*)killButton {
228   return killButton_;
231 - (MultiKeyEquivalentButton*)waitButton {
232   return waitButton_;
234 @end