BookmarkManager: Fix 'new folder text field size changes on clicking it' issue.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / browser_window_cocoa.mm
blob75abbe914eb89c1620a16cd69c04b6b9776856c7
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 #include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #import "base/mac/sdk_forward_declarations.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/sys_string_conversions.h"
15 #include "chrome/app/chrome_command_ids.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/download/download_shelf.h"
18 #include "chrome/browser/extensions/extension_util.h"
19 #include "chrome/browser/extensions/tab_helper.h"
20 #include "chrome/browser/fullscreen.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/shell_integration.h"
23 #include "chrome/browser/signin/chrome_signin_helper.h"
24 #include "chrome/browser/translate/chrome_translate_client.h"
25 #include "chrome/browser/ui/browser.h"
26 #include "chrome/browser/ui/browser_command_controller.h"
27 #include "chrome/browser/ui/browser_commands_mac.h"
28 #include "chrome/browser/ui/browser_list.h"
29 #include "chrome/browser/ui/browser_window_state.h"
30 #import "chrome/browser/ui/cocoa/browser/edit_search_engine_cocoa_controller.h"
31 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
32 #import "chrome/browser/ui/cocoa/browser_window_utils.h"
33 #import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
34 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h"
35 #import "chrome/browser/ui/cocoa/download/download_shelf_controller.h"
36 #import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h"
37 #include "chrome/browser/ui/cocoa/find_bar/find_bar_bridge.h"
38 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
39 #include "chrome/browser/ui/cocoa/key_equivalent_constants.h"
40 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
41 #import "chrome/browser/ui/cocoa/nsmenuitem_additions.h"
42 #import "chrome/browser/ui/cocoa/profiles/avatar_base_controller.h"
43 #import "chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.h"
44 #include "chrome/browser/ui/cocoa/restart_browser.h"
45 #include "chrome/browser/ui/cocoa/status_bubble_mac.h"
46 #include "chrome/browser/ui/cocoa/task_manager_mac.h"
47 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
48 #import "chrome/browser/ui/cocoa/web_dialog_window_controller.h"
49 #import "chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.h"
50 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
51 #include "chrome/browser/ui/search/search_model.h"
52 #include "chrome/browser/ui/tabs/tab_strip_model.h"
53 #include "chrome/browser/web_applications/web_app.h"
54 #include "chrome/common/chrome_switches.h"
55 #include "chrome/common/pref_names.h"
56 #include "chrome/grit/generated_resources.h"
57 #include "components/translate/core/browser/language_state.h"
58 #include "content/public/browser/native_web_keyboard_event.h"
59 #include "content/public/browser/notification_details.h"
60 #include "content/public/browser/notification_service.h"
61 #include "content/public/browser/notification_source.h"
62 #include "content/public/browser/web_contents.h"
63 #include "extensions/browser/extension_registry.h"
64 #include "extensions/browser/extension_system.h"
65 #include "extensions/common/constants.h"
66 #include "ui/base/l10n/l10n_util_mac.h"
67 #include "ui/events/keycodes/keyboard_codes.h"
68 #include "ui/gfx/geometry/rect.h"
70 #if defined(ENABLE_ONE_CLICK_SIGNIN)
71 #import "chrome/browser/ui/cocoa/one_click_signin_bubble_controller.h"
72 #import "chrome/browser/ui/cocoa/one_click_signin_dialog_controller.h"
73 #endif
75 using content::NativeWebKeyboardEvent;
76 using content::WebContents;
78 namespace {
80 // These UI constants are used in BrowserWindowCocoa::ShowBookmarkAppBubble.
81 // Used for defining the layout of the NSAlert and NSTextField within the
82 // accessory view.
83 const int kAppTextFieldVerticalSpacing = 2;
84 const int kAppTextFieldWidth = 200;
85 const int kAppTextFieldHeight = 22;
86 const int kBookmarkAppBubbleViewWidth = 200;
87 const int kBookmarkAppBubbleViewHeight = 46;
89 const int kIconPreviewTargetSize = 128;
91 base::string16 TrimText(NSString* controlText) {
92   base::string16 text = base::SysNSStringToUTF16(controlText);
93   base::TrimWhitespace(text, base::TRIM_ALL, &text);
94   return text;
97 }  // namespace
99 @interface TextRequiringDelegate : NSObject<NSTextFieldDelegate> {
100  @private
101   // Disable |control_| when text changes to just whitespace or empty string.
102   NSControl* control_;
104 - (id)initWithControl:(NSControl*)control text:(NSString*)text;
105 - (void)controlTextDidChange:(NSNotification*)notification;
106 @end
108 @interface TextRequiringDelegate ()
109 - (void)validateText:(NSString*)text;
110 @end
112 @implementation TextRequiringDelegate
113 - (id)initWithControl:(NSControl*)control text:(NSString*)text {
114   if ((self = [super init])) {
115     control_ = control;
116     [self validateText:text];
117   }
118   return self;
121 - (void)controlTextDidChange:(NSNotification*)notification {
122   [self validateText:[[notification object] stringValue]];
125 - (void)validateText:(NSString*)text {
126   [control_ setEnabled:TrimText(text).empty() ? NO : YES];
128 @end
130 BrowserWindowCocoa::BrowserWindowCocoa(Browser* browser,
131                                        BrowserWindowController* controller)
132   : browser_(browser),
133     controller_(controller),
134     initial_show_state_(ui::SHOW_STATE_DEFAULT),
135     attention_request_id_(0) {
137   gfx::Rect bounds;
138   chrome::GetSavedWindowBoundsAndShowState(browser_,
139                                            &bounds,
140                                            &initial_show_state_);
142   browser_->search_model()->AddObserver(this);
145 BrowserWindowCocoa::~BrowserWindowCocoa() {
146   browser_->search_model()->RemoveObserver(this);
149 void BrowserWindowCocoa::Show() {
150   // The Browser associated with this browser window must become the active
151   // browser at the time |Show()| is called. This is the natural behaviour under
152   // Windows, but |-makeKeyAndOrderFront:| won't send |-windowDidBecomeMain:|
153   // until we return to the runloop. Therefore any calls to
154   // |chrome::FindLastActiveWithHostDesktopType| will return the previous
155   // browser instead if we don't explicitly set it here.
156   BrowserList::SetLastActive(browser_);
158   bool is_session_restore = browser_->is_session_restore();
159   NSWindowAnimationBehavior saved_animation_behavior =
160       NSWindowAnimationBehaviorDefault;
161   bool did_save_animation_behavior = false;
162   // Turn off swishing when restoring windows or showing an app.
163   if ((is_session_restore || browser_->is_app()) &&
164       [window() respondsToSelector:@selector(animationBehavior)] &&
165       [window() respondsToSelector:@selector(setAnimationBehavior:)]) {
166     did_save_animation_behavior = true;
167     saved_animation_behavior = [window() animationBehavior];
168     [window() setAnimationBehavior:NSWindowAnimationBehaviorNone];
169   }
171   {
172     TRACE_EVENT0("ui", "BrowserWindowCocoa::Show makeKeyAndOrderFront");
173     // This call takes up a substantial part of startup time, and an even more
174     // substantial part of startup time when any CALayers are part of the
175     // window's NSView heirarchy.
176     [window() makeKeyAndOrderFront:controller_];
177   }
179   // When creating windows from nibs it is necessary to |makeKeyAndOrderFront:|
180   // prior to |orderOut:| then |miniaturize:| when restoring windows in the
181   // minimized state.
182   if (initial_show_state_ == ui::SHOW_STATE_MINIMIZED) {
183     [window() orderOut:controller_];
184     [window() miniaturize:controller_];
185   } else if (initial_show_state_ == ui::SHOW_STATE_FULLSCREEN) {
186     chrome::ToggleFullscreenWithToolbarOrFallback(browser_);
187   }
188   initial_show_state_ = ui::SHOW_STATE_DEFAULT;
190   // Restore window animation behavior.
191   if (did_save_animation_behavior)
192     [window() setAnimationBehavior:saved_animation_behavior];
194   browser_->OnWindowDidShow();
197 void BrowserWindowCocoa::ShowInactive() {
198   [window() orderFront:controller_];
201 void BrowserWindowCocoa::Hide() {
202   [window() orderOut:controller_];
205 void BrowserWindowCocoa::SetBounds(const gfx::Rect& bounds) {
206   gfx::Rect real_bounds = [controller_ enforceMinWindowSize:bounds];
208   ExitFullscreen();
209   NSRect cocoa_bounds = NSMakeRect(real_bounds.x(), 0,
210                                    real_bounds.width(),
211                                    real_bounds.height());
212   // Flip coordinates based on the primary screen.
213   NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
214   cocoa_bounds.origin.y =
215       NSHeight([screen frame]) - real_bounds.height() - real_bounds.y();
217   [window() setFrame:cocoa_bounds display:YES];
220 // Callers assume that this doesn't immediately delete the Browser object.
221 // The controller implementing the window delegate methods called from
222 // |-performClose:| must take precautions to ensure that.
223 void BrowserWindowCocoa::Close() {
224   // If there is an overlay window, we contain a tab being dragged between
225   // windows. Don't hide the window as it makes the UI extra confused. We can
226   // still close the window, as that will happen when the drag completes.
227   if ([controller_ overlayWindow]) {
228     [controller_ deferPerformClose];
229   } else {
230     // Using |-performClose:| can prevent the window from actually closing if
231     // a JavaScript beforeunload handler opens an alert during shutdown, as
232     // documented at <http://crbug.com/118424>. Re-implement
233     // -[NSWindow performClose:] as closely as possible to how Apple documents
234     // it.
235     //
236     // Before calling |-close|, hide the window immediately. |-performClose:|
237     // would do something similar, and this ensures that the window is removed
238     // from AppKit's display list. Not doing so can lead to crashes like
239     // <http://crbug.com/156101>.
240     id<NSWindowDelegate> delegate = [window() delegate];
241     SEL window_should_close = @selector(windowShouldClose:);
242     if ([delegate respondsToSelector:window_should_close]) {
243       if ([delegate windowShouldClose:window()]) {
244         [window() orderOut:nil];
245         [window() close];
246       }
247     } else if ([window() respondsToSelector:window_should_close]) {
248       if ([window() performSelector:window_should_close withObject:window()]) {
249         [window() orderOut:nil];
250         [window() close];
251       }
252     } else {
253       [window() orderOut:nil];
254       [window() close];
255     }
256   }
259 void BrowserWindowCocoa::Activate() {
260   [controller_ activate];
263 void BrowserWindowCocoa::Deactivate() {
264   // TODO(jcivelli): http://crbug.com/51364 Implement me.
265   NOTIMPLEMENTED();
268 void BrowserWindowCocoa::FlashFrame(bool flash) {
269   if (flash) {
270     attention_request_id_ = [NSApp requestUserAttention:NSInformationalRequest];
271   } else {
272     [NSApp cancelUserAttentionRequest:attention_request_id_];
273     attention_request_id_ = 0;
274   }
277 bool BrowserWindowCocoa::IsAlwaysOnTop() const {
278   return false;
281 void BrowserWindowCocoa::SetAlwaysOnTop(bool always_on_top) {
282   // Not implemented for browser windows.
283   NOTIMPLEMENTED();
286 bool BrowserWindowCocoa::IsActive() const {
287   return [window() isKeyWindow];
290 gfx::NativeWindow BrowserWindowCocoa::GetNativeWindow() const {
291   return window();
294 StatusBubble* BrowserWindowCocoa::GetStatusBubble() {
295   return [controller_ statusBubble];
298 void BrowserWindowCocoa::UpdateTitleBar() {
299   NSString* newTitle =
300       base::SysUTF16ToNSString(browser_->GetWindowTitleForCurrentTab());
302   pending_window_title_.reset(
303       [BrowserWindowUtils scheduleReplaceOldTitle:pending_window_title_.get()
304                                      withNewTitle:newTitle
305                                         forWindow:window()]);
308 void BrowserWindowCocoa::BookmarkBarStateChanged(
309     BookmarkBar::AnimateChangeType change_type) {
310   [[controller_ bookmarkBarController]
311       updateState:browser_->bookmark_bar_state()
312        changeType:change_type];
315 void BrowserWindowCocoa::UpdateDevTools() {
316   [controller_ updateDevToolsForContents:
317       browser_->tab_strip_model()->GetActiveWebContents()];
320 void BrowserWindowCocoa::UpdateLoadingAnimations(bool should_animate) {
321   // Do nothing on Mac.
324 void BrowserWindowCocoa::SetStarredState(bool is_starred) {
325   [controller_ setStarredState:is_starred];
328 void BrowserWindowCocoa::SetTranslateIconToggled(bool is_lit) {
329   [controller_ setCurrentPageIsTranslated:is_lit];
332 void BrowserWindowCocoa::OnActiveTabChanged(content::WebContents* old_contents,
333                                             content::WebContents* new_contents,
334                                             int index,
335                                             int reason) {
336   [controller_ onActiveTabChanged:old_contents to:new_contents];
337   // TODO(pkasting): Perhaps the code in
338   // TabStripController::activateTabWithContents should move here?  Or this
339   // should call that (instead of TabStripModelObserverBridge doing so)?  It's
340   // not obvious to me why Mac doesn't handle tab changes in BrowserWindow the
341   // way views and GTK do.
342   // See http://crbug.com/340720 for discussion.
345 void BrowserWindowCocoa::ZoomChangedForActiveTab(bool can_show_bubble) {
346   [controller_ zoomChangedForActiveTab:can_show_bubble ? YES : NO];
349 gfx::Rect BrowserWindowCocoa::GetRestoredBounds() const {
350   // Flip coordinates based on the primary screen.
351   NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
352   NSRect frame = [controller_ regularWindowFrame];
353   gfx::Rect bounds(frame.origin.x, 0, NSWidth(frame), NSHeight(frame));
354   bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame));
355   return bounds;
358 ui::WindowShowState BrowserWindowCocoa::GetRestoredState() const {
359   if (IsMaximized())
360     return ui::SHOW_STATE_MAXIMIZED;
361   if (IsMinimized())
362     return ui::SHOW_STATE_MINIMIZED;
363   return ui::SHOW_STATE_NORMAL;
366 gfx::Rect BrowserWindowCocoa::GetBounds() const {
367   return GetRestoredBounds();
370 bool BrowserWindowCocoa::IsMaximized() const {
371   // -isZoomed returns YES if the window's frame equals the rect returned by
372   // -windowWillUseStandardFrame:defaultFrame:, even if the window is in the
373   // dock, so have to explicitly check for miniaturization state first.
374   return ![window() isMiniaturized] && [window() isZoomed];
377 bool BrowserWindowCocoa::IsMinimized() const {
378   return [window() isMiniaturized];
381 void BrowserWindowCocoa::Maximize() {
382   // Zoom toggles so only call if not already maximized.
383   if (!IsMaximized())
384     [window() zoom:controller_];
387 void BrowserWindowCocoa::Minimize() {
388   [window() miniaturize:controller_];
391 void BrowserWindowCocoa::Restore() {
392   if (IsMaximized())
393     [window() zoom:controller_];  // Toggles zoom mode.
394   else if (IsMinimized())
395     [window() deminiaturize:controller_];
398 // See browser_window_controller.h for a detailed explanation of the logic in
399 // this method.
400 void BrowserWindowCocoa::EnterFullscreen(const GURL& url,
401                                          ExclusiveAccessBubbleType bubble_type,
402                                          bool with_toolbar) {
403   if (browser_->exclusive_access_manager()
404           ->fullscreen_controller()
405           ->IsWindowFullscreenForTabOrPending())
406     [controller_ enterWebContentFullscreenForURL:url bubbleType:bubble_type];
407   else if (!url.is_empty())
408     [controller_ enterExtensionFullscreenForURL:url bubbleType:bubble_type];
409   else
410     [controller_ enterBrowserFullscreenWithToolbar:with_toolbar];
413 void BrowserWindowCocoa::ExitFullscreen() {
414   [controller_ exitAnyFullscreen];
417 void BrowserWindowCocoa::UpdateExclusiveAccessExitBubbleContent(
418     const GURL& url,
419     ExclusiveAccessBubbleType bubble_type) {
420   [controller_ updateFullscreenExitBubbleURL:url bubbleType:bubble_type];
423 bool BrowserWindowCocoa::ShouldHideUIForFullscreen() const {
424   // On Mac, fullscreen mode has most normal things (in a slide-down panel).
425   return false;
428 bool BrowserWindowCocoa::IsFullscreen() const {
429   return [controller_ isInAnyFullscreenMode];
432 bool BrowserWindowCocoa::IsFullscreenBubbleVisible() const {
433   return false;
436 bool BrowserWindowCocoa::SupportsFullscreenWithToolbar() const {
437   return chrome::mac::SupportsSystemFullscreen();
440 void BrowserWindowCocoa::UpdateFullscreenWithToolbar(bool with_toolbar) {
441   [controller_ updateFullscreenWithToolbar:with_toolbar];
444 bool BrowserWindowCocoa::IsFullscreenWithToolbar() const {
445   return IsFullscreen() && ![controller_ inPresentationMode];
448 void BrowserWindowCocoa::ConfirmAddSearchProvider(
449     TemplateURL* template_url,
450     Profile* profile) {
451   // The controller will release itself when the window closes.
452   EditSearchEngineCocoaController* editor =
453       [[EditSearchEngineCocoaController alloc] initWithProfile:profile
454                                                       delegate:NULL
455                                                    templateURL:template_url];
456   [NSApp beginSheet:[editor window]
457      modalForWindow:window()
458       modalDelegate:controller_
459      didEndSelector:@selector(sheetDidEnd:returnCode:context:)
460         contextInfo:NULL];
463 LocationBar* BrowserWindowCocoa::GetLocationBar() const {
464   return [controller_ locationBarBridge];
467 void BrowserWindowCocoa::SetFocusToLocationBar(bool select_all) {
468   [controller_ focusLocationBar:select_all ? YES : NO];
471 void BrowserWindowCocoa::UpdateReloadStopState(bool is_loading, bool force) {
472   [controller_ setIsLoading:is_loading force:force];
475 void BrowserWindowCocoa::UpdateToolbar(content::WebContents* contents) {
476   [controller_ updateToolbarWithContents:contents];
479 void BrowserWindowCocoa::ResetToolbarTabState(content::WebContents* contents) {
480   [controller_ resetTabState:contents];
483 void BrowserWindowCocoa::FocusToolbar() {
484   // Not needed on the Mac.
487 ToolbarActionsBar* BrowserWindowCocoa::GetToolbarActionsBar() {
488   if ([controller_ hasToolbar])
489     return [[[controller_ toolbarController] browserActionsController]
490                toolbarActionsBar];
491   return nullptr;
494 void BrowserWindowCocoa::ToolbarSizeChanged(bool is_animating) {
495   // Not needed on the Mac.
498 void BrowserWindowCocoa::FocusAppMenu() {
499   // Chrome uses the standard Mac OS X menu bar, so this isn't needed.
502 void BrowserWindowCocoa::RotatePaneFocus(bool forwards) {
503   // Not needed on the Mac.
506 void BrowserWindowCocoa::FocusBookmarksToolbar() {
507   // Not needed on the Mac.
510 void BrowserWindowCocoa::FocusInfobars() {
511   // Not needed on the Mac.
514 bool BrowserWindowCocoa::IsBookmarkBarVisible() const {
515   return browser_->profile()->GetPrefs()->GetBoolean(
516       bookmarks::prefs::kShowBookmarkBar);
519 bool BrowserWindowCocoa::IsBookmarkBarAnimating() const {
520   return [controller_ isBookmarkBarAnimating];
523 bool BrowserWindowCocoa::IsTabStripEditable() const {
524   return ![controller_ isDragSessionActive];
527 bool BrowserWindowCocoa::IsToolbarVisible() const {
528   return browser_->SupportsWindowFeature(Browser::FEATURE_TOOLBAR) ||
529          browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR);
532 gfx::Rect BrowserWindowCocoa::GetRootWindowResizerRect() const {
533   if (IsDownloadShelfVisible())
534     return gfx::Rect();
535   NSRect tabRect = [controller_ selectedTabGrowBoxRect];
536   return gfx::Rect(NSRectToCGRect(tabRect));
539 void BrowserWindowCocoa::AddFindBar(
540     FindBarCocoaController* find_bar_cocoa_controller) {
541   [controller_ addFindBar:find_bar_cocoa_controller];
544 void BrowserWindowCocoa::ShowUpdateChromeDialog() {
545   restart_browser::RequestRestart(window());
548 void BrowserWindowCocoa::ShowBookmarkBubble(const GURL& url,
549                                             bool already_bookmarked) {
550   [controller_ showBookmarkBubbleForURL:url
551                       alreadyBookmarked:(already_bookmarked ? YES : NO)];
554 void BrowserWindowCocoa::ShowBookmarkAppBubble(
555     const WebApplicationInfo& web_app_info,
556     const ShowBookmarkAppBubbleCallback& callback) {
557   base::scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]);
558   [alert setMessageText:l10n_util::GetNSString(
559       IDS_ADD_TO_APPLICATIONS_BUBBLE_TITLE)];
560   [alert setAlertStyle:NSInformationalAlertStyle];
562   NSButton* continue_button =
563       [alert addButtonWithTitle:l10n_util::GetNSString(IDS_OK)];
564   [continue_button setKeyEquivalent:kKeyEquivalentReturn];
565   NSButton* cancel_button =
566       [alert addButtonWithTitle:l10n_util::GetNSString(IDS_CANCEL)];
567   [cancel_button setKeyEquivalent:kKeyEquivalentEscape];
569   base::scoped_nsobject<NSButton> open_as_window_checkbox(
570       [[NSButton alloc] initWithFrame:NSZeroRect]);
571   [open_as_window_checkbox setButtonType:NSSwitchButton];
572   [open_as_window_checkbox
573       setTitle:l10n_util::GetNSString(IDS_BOOKMARK_APP_BUBBLE_OPEN_AS_WINDOW)];
574   [open_as_window_checkbox setState:web_app_info.open_as_window];
575   [open_as_window_checkbox sizeToFit];
577   base::scoped_nsobject<NSTextField> app_title([[NSTextField alloc]
578       initWithFrame:NSMakeRect(0, kAppTextFieldHeight +
579                                       kAppTextFieldVerticalSpacing,
580                                kAppTextFieldWidth, kAppTextFieldHeight)]);
581   NSString* original_title = SysUTF16ToNSString(web_app_info.title);
582   [[app_title cell] setWraps:NO];
583   [[app_title cell] setScrollable:YES];
584   [app_title setStringValue:original_title];
585   base::scoped_nsobject<TextRequiringDelegate> delegate(
586       [[TextRequiringDelegate alloc] initWithControl:continue_button
587                                                 text:[app_title stringValue]]);
588   [app_title setDelegate:delegate];
590   base::scoped_nsobject<NSView> view([[NSView alloc]
591       initWithFrame:NSMakeRect(0, 0, kBookmarkAppBubbleViewWidth,
592                                kBookmarkAppBubbleViewHeight)]);
594   // When CanHostedAppsOpenInWindows() returns false, do not show the open as
595   // window checkbox to avoid confusing users.
596   if (extensions::util::CanHostedAppsOpenInWindows())
597     [view addSubview:open_as_window_checkbox];
598   [view addSubview:app_title];
599   [alert setAccessoryView:view];
601   // Find the image with target size.
602   // Assumes that the icons are sorted in ascending order of size.
603   if (!web_app_info.icons.empty()) {
604     for (const WebApplicationInfo::IconInfo& info : web_app_info.icons) {
605       if (info.width == kIconPreviewTargetSize &&
606           info.height == kIconPreviewTargetSize) {
607         gfx::Image icon_image = gfx::Image::CreateFrom1xBitmap(info.data);
608         [alert setIcon:icon_image.ToNSImage()];
609         break;
610       }
611     }
612   }
614   NSInteger response = [alert runModal];
616   // Prevent |app_title| from accessing |delegate| after it's destroyed.
617   [app_title setDelegate:nil];
619   if (response == NSAlertFirstButtonReturn) {
620     WebApplicationInfo updated_info = web_app_info;
621     updated_info.open_as_window = [open_as_window_checkbox state] == NSOnState;
622     updated_info.title = TrimText([app_title stringValue]);
624     callback.Run(true, updated_info);
625     return;
626   }
628   callback.Run(false, web_app_info);
631 void BrowserWindowCocoa::ShowTranslateBubble(
632     content::WebContents* contents,
633     translate::TranslateStep step,
634     translate::TranslateErrors::Type error_type,
635     bool is_user_gesture) {
636   ChromeTranslateClient* chrome_translate_client =
637       ChromeTranslateClient::FromWebContents(contents);
638   translate::LanguageState& language_state =
639       chrome_translate_client->GetLanguageState();
640   language_state.SetTranslateEnabled(true);
642   [controller_ showTranslateBubbleForWebContents:contents
643                                             step:step
644                                        errorType:error_type];
647 bool BrowserWindowCocoa::ShowSessionCrashedBubble() {
648   return false;
651 bool BrowserWindowCocoa::IsProfileResetBubbleSupported() const {
652   return false;
655 GlobalErrorBubbleViewBase* BrowserWindowCocoa::ShowProfileResetBubble(
656     const base::WeakPtr<ProfileResetGlobalError>& global_error) {
657   NOTREACHED();
658   return nullptr;
661 #if defined(ENABLE_ONE_CLICK_SIGNIN)
662 void BrowserWindowCocoa::ShowOneClickSigninBubble(
663     OneClickSigninBubbleType type,
664     const base::string16& email,
665     const base::string16& error_message,
666     const StartSyncCallback& start_sync_callback) {
667   WebContents* web_contents =
668         browser_->tab_strip_model()->GetActiveWebContents();
669   if (type == ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE) {
670     base::scoped_nsobject<OneClickSigninBubbleController> bubble_controller([
671             [OneClickSigninBubbleController alloc]
672         initWithBrowserWindowController:cocoa_controller()
673                             webContents:web_contents
674                            errorMessage:base::SysUTF16ToNSString(error_message)
675                                callback:start_sync_callback]);
676     [bubble_controller showWindow:nil];
677   } else {
678     // Deletes itself when the dialog closes.
679     new OneClickSigninDialogController(
680         web_contents, start_sync_callback, email);
681   }
683 #endif
685 bool BrowserWindowCocoa::IsDownloadShelfVisible() const {
686   return [controller_ isDownloadShelfVisible] != NO;
689 DownloadShelf* BrowserWindowCocoa::GetDownloadShelf() {
690   [controller_ createAndAddDownloadShelf];
691   DownloadShelfController* shelfController = [controller_ downloadShelf];
692   return [shelfController bridge];
695 // We allow closing the window here since the real quit decision on Mac is made
696 // in [AppController quit:].
697 void BrowserWindowCocoa::ConfirmBrowserCloseWithPendingDownloads(
698       int download_count,
699       Browser::DownloadClosePreventionType dialog_type,
700       bool app_modal,
701       const base::Callback<void(bool)>& callback) {
702   callback.Run(true);
705 void BrowserWindowCocoa::UserChangedTheme() {
706   [controller_ userChangedTheme];
709 void BrowserWindowCocoa::ShowWebsiteSettings(
710     Profile* profile,
711     content::WebContents* web_contents,
712     const GURL& url,
713     const SecurityStateModel::SecurityInfo& security_info) {
714   WebsiteSettingsUIBridge::Show(window(), profile, web_contents, url,
715                                 security_info);
718 void BrowserWindowCocoa::ShowAppMenu() {
719   // No-op. Mac doesn't support showing the menus via alt keys.
722 bool BrowserWindowCocoa::PreHandleKeyboardEvent(
723     const NativeWebKeyboardEvent& event, bool* is_keyboard_shortcut) {
724   // Handle ESC to dismiss permission bubbles, but still forward it
725   // to the window afterwards.
726   if (event.windowsKeyCode == ui::VKEY_ESCAPE)
727     [controller_ dismissPermissionBubble];
729   if (![BrowserWindowUtils shouldHandleKeyboardEvent:event])
730     return false;
732   if (event.type == blink::WebInputEvent::RawKeyDown &&
733       [controller_
734           handledByExtensionCommand:event.os_event
735                            priority:ui::AcceleratorManager::kHighPriority])
736     return true;
738   int id = [BrowserWindowUtils getCommandId:event];
739   if (id == -1)
740     return false;
742   if (browser_->command_controller()->IsReservedCommandOrKey(id, event)) {
743       return [BrowserWindowUtils handleKeyboardEvent:event.os_event
744                                             inWindow:window()];
745   }
747   DCHECK(is_keyboard_shortcut);
748   *is_keyboard_shortcut = true;
749   return false;
752 void BrowserWindowCocoa::HandleKeyboardEvent(
753     const NativeWebKeyboardEvent& event) {
754   if ([BrowserWindowUtils shouldHandleKeyboardEvent:event])
755     [BrowserWindowUtils handleKeyboardEvent:event.os_event inWindow:window()];
758 void BrowserWindowCocoa::CutCopyPaste(int command_id) {
759   if (command_id == IDC_CUT)
760     [NSApp sendAction:@selector(cut:) to:nil from:nil];
761   else if (command_id == IDC_COPY)
762     [NSApp sendAction:@selector(copy:) to:nil from:nil];
763   else
764     [NSApp sendAction:@selector(paste:) to:nil from:nil];
767 WindowOpenDisposition BrowserWindowCocoa::GetDispositionForPopupBounds(
768     const gfx::Rect& bounds) {
769   // When using Cocoa's System Fullscreen mode, convert popups into tabs.
770   if ([controller_ isInAppKitFullscreen])
771     return NEW_FOREGROUND_TAB;
772   return NEW_POPUP;
775 FindBar* BrowserWindowCocoa::CreateFindBar() {
776   // We could push the AddFindBar() call into the FindBarBridge
777   // constructor or the FindBarCocoaController init, but that makes
778   // unit testing difficult, since we would also require a
779   // BrowserWindow object.
780   FindBarBridge* bridge = new FindBarBridge(browser_);
781   AddFindBar(bridge->find_bar_cocoa_controller());
782   return bridge;
785 web_modal::WebContentsModalDialogHost*
786     BrowserWindowCocoa::GetWebContentsModalDialogHost() {
787   DCHECK([controller_ window]);
788   ConstrainedWindowSheetController* sheet_controller =
789       [ConstrainedWindowSheetController
790           controllerForParentWindow:[controller_ window]];
791   DCHECK(sheet_controller);
792   return [sheet_controller dialogHost];
795 extensions::ActiveTabPermissionGranter*
796     BrowserWindowCocoa::GetActiveTabPermissionGranter() {
797   WebContents* web_contents =
798       browser_->tab_strip_model()->GetActiveWebContents();
799   if (!web_contents)
800     return NULL;
801   extensions::TabHelper* tab_helper =
802       extensions::TabHelper::FromWebContents(web_contents);
803   return tab_helper ? tab_helper->active_tab_permission_granter() : NULL;
806 void BrowserWindowCocoa::ModelChanged(const SearchModel::State& old_state,
807                                       const SearchModel::State& new_state) {
810 void BrowserWindowCocoa::DestroyBrowser() {
811   [controller_ destroyBrowser];
813   // at this point the controller is dead (autoreleased), so
814   // make sure we don't try to reference it any more.
817 NSWindow* BrowserWindowCocoa::window() const {
818   return [controller_ window];
821 void BrowserWindowCocoa::ShowAvatarBubbleFromAvatarButton(
822     AvatarBubbleMode mode,
823     const signin::ManageAccountsParams& manage_accounts_params) {
824   AvatarBaseController* controller = [controller_ avatarButtonController];
825   NSView* anchor = [controller buttonView];
826   if ([anchor isHiddenOrHasHiddenAncestor])
827     anchor = [[controller_ toolbarController] wrenchButton];
828   [controller showAvatarBubbleAnchoredAt:anchor
829                                 withMode:mode
830                          withServiceType:manage_accounts_params.service_type];
834 BrowserWindowCocoa::GetRenderViewHeightInsetWithDetachedBookmarkBar() {
835   if (browser_->bookmark_bar_state() != BookmarkBar::DETACHED)
836     return 0;
837   return 40;
840 void BrowserWindowCocoa::ExecuteExtensionCommand(
841     const extensions::Extension* extension,
842     const extensions::Command& command) {
843   [cocoa_controller() executeExtensionCommand:extension->id() command:command];
846 ExclusiveAccessContext* BrowserWindowCocoa::GetExclusiveAccessContext() {
847   return this;
850 Profile* BrowserWindowCocoa::GetProfile() {
851   return browser_->profile();
854 WebContents* BrowserWindowCocoa::GetActiveWebContents() {
855   return browser_->tab_strip_model()->GetActiveWebContents();
858 void BrowserWindowCocoa::UnhideDownloadShelf() {
859   GetDownloadShelf()->Unhide();
862 void BrowserWindowCocoa::HideDownloadShelf() {
863   GetDownloadShelf()->Hide();
864   StatusBubble* statusBubble = GetStatusBubble();
865   if (statusBubble)
866     statusBubble->Hide();