Home | History | Annotate | Download | only in cocoa
      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.
      4 
      5 #include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "base/logging.h"
     10 #include "base/mac/mac_util.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/prefs/pref_service.h"
     13 #include "base/strings/sys_string_conversions.h"
     14 #include "chrome/app/chrome_command_ids.h"
     15 #include "chrome/browser/chrome_notification_types.h"
     16 #include "chrome/browser/download/download_shelf.h"
     17 #include "chrome/browser/extensions/tab_helper.h"
     18 #include "chrome/browser/fullscreen.h"
     19 #include "chrome/browser/password_manager/password_manager.h"
     20 #include "chrome/browser/profiles/profile.h"
     21 #include "chrome/browser/shell_integration.h"
     22 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
     23 #include "chrome/browser/ui/browser.h"
     24 #include "chrome/browser/ui/browser_command_controller.h"
     25 #include "chrome/browser/ui/browser_commands.h"
     26 #include "chrome/browser/ui/browser_list.h"
     27 #include "chrome/browser/ui/browser_window_state.h"
     28 #import "chrome/browser/ui/cocoa/browser/avatar_button_controller.h"
     29 #import "chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.h"
     30 #import "chrome/browser/ui/cocoa/browser/edit_search_engine_cocoa_controller.h"
     31 #import "chrome/browser/ui/cocoa/browser/password_generation_bubble_controller.h"
     32 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
     33 #import "chrome/browser/ui/cocoa/browser_window_utils.h"
     34 #import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
     35 #import "chrome/browser/ui/cocoa/download/download_shelf_controller.h"
     36 #include "chrome/browser/ui/cocoa/find_bar/find_bar_bridge.h"
     37 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
     38 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
     39 #import "chrome/browser/ui/cocoa/nsmenuitem_additions.h"
     40 #include "chrome/browser/ui/cocoa/restart_browser.h"
     41 #include "chrome/browser/ui/cocoa/status_bubble_mac.h"
     42 #include "chrome/browser/ui/cocoa/task_manager_mac.h"
     43 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
     44 #import "chrome/browser/ui/cocoa/web_dialog_window_controller.h"
     45 #import "chrome/browser/ui/cocoa/website_settings_bubble_controller.h"
     46 #include "chrome/browser/ui/search/search_model.h"
     47 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     48 #include "chrome/browser/ui/web_applications/web_app_ui.h"
     49 #include "chrome/browser/web_applications/web_app.h"
     50 #include "chrome/common/chrome_switches.h"
     51 #include "chrome/common/pref_names.h"
     52 #include "content/public/browser/native_web_keyboard_event.h"
     53 #include "content/public/browser/notification_details.h"
     54 #include "content/public/browser/notification_source.h"
     55 #include "content/public/browser/web_contents.h"
     56 #include "content/public/browser/web_contents_view.h"
     57 #include "content/public/common/password_form.h"
     58 #include "grit/chromium_strings.h"
     59 #include "grit/generated_resources.h"
     60 #include "ui/base/l10n/l10n_util_mac.h"
     61 #include "ui/gfx/rect.h"
     62 
     63 #if defined(ENABLE_ONE_CLICK_SIGNIN)
     64 #import "chrome/browser/ui/cocoa/one_click_signin_bubble_controller.h"
     65 #import "chrome/browser/ui/cocoa/one_click_signin_dialog_controller.h"
     66 #endif
     67 
     68 using content::NativeWebKeyboardEvent;
     69 using content::SSLStatus;
     70 using content::WebContents;
     71 
     72 // Replicate specific 10.7 SDK declarations for building with prior SDKs.
     73 #if !defined(MAC_OS_X_VERSION_10_7) || \
     74     MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
     75 
     76 enum {
     77   NSWindowAnimationBehaviorDefault = 0,
     78   NSWindowAnimationBehaviorNone = 2,
     79   NSWindowAnimationBehaviorDocumentWindow = 3,
     80   NSWindowAnimationBehaviorUtilityWindow = 4,
     81   NSWindowAnimationBehaviorAlertPanel = 5
     82 };
     83 typedef NSInteger NSWindowAnimationBehavior;
     84 
     85 @interface NSWindow (LionSDKDeclarations)
     86 - (NSWindowAnimationBehavior)animationBehavior;
     87 - (void)setAnimationBehavior:(NSWindowAnimationBehavior)newAnimationBehavior;
     88 @end
     89 
     90 #endif  // MAC_OS_X_VERSION_10_7
     91 
     92 namespace {
     93 
     94 NSPoint GetPointForBubble(content::WebContents* web_contents,
     95                           int x_offset,
     96                           int y_offset) {
     97   NSView* view = web_contents->GetView()->GetNativeView();
     98   NSRect bounds = [view bounds];
     99   NSPoint point;
    100   point.x = NSMinX(bounds) + x_offset;
    101   // The view's origin is at the bottom but |rect|'s origin is at the top.
    102   point.y = NSMaxY(bounds) - y_offset;
    103   point = [view convertPoint:point toView:nil];
    104   point = [[view window] convertBaseToScreen:point];
    105   return point;
    106 }
    107 
    108 void CreateShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) {
    109   // creation_locations will be ignored by CreatePlatformShortcuts on Mac.
    110   ShellIntegration::ShortcutLocations creation_locations;
    111   web_app::CreateShortcuts(shortcut_info, creation_locations,
    112                            web_app::SHORTCUT_CREATION_BY_USER);
    113 }
    114 
    115 }  // namespace
    116 
    117 BrowserWindowCocoa::BrowserWindowCocoa(Browser* browser,
    118                                        BrowserWindowController* controller)
    119   : browser_(browser),
    120     controller_(controller),
    121     confirm_close_factory_(browser),
    122     initial_show_state_(ui::SHOW_STATE_DEFAULT),
    123     attention_request_id_(0) {
    124 
    125   gfx::Rect bounds;
    126   chrome::GetSavedWindowBoundsAndShowState(browser_,
    127                                            &bounds,
    128                                            &initial_show_state_);
    129 
    130   browser_->search_model()->AddObserver(this);
    131 }
    132 
    133 BrowserWindowCocoa::~BrowserWindowCocoa() {
    134   browser_->search_model()->RemoveObserver(this);
    135 }
    136 
    137 void BrowserWindowCocoa::Show() {
    138   // The Browser associated with this browser window must become the active
    139   // browser at the time |Show()| is called. This is the natural behaviour under
    140   // Windows, but |-makeKeyAndOrderFront:| won't send |-windowDidBecomeMain:|
    141   // until we return to the runloop. Therefore any calls to
    142   // |chrome::FindLastActiveWithHostDesktopType| will return the previous
    143   // browser instead if we don't explicitly set it here.
    144   BrowserList::SetLastActive(browser_);
    145 
    146   bool is_session_restore = browser_->is_session_restore();
    147   NSWindowAnimationBehavior saved_animation_behavior =
    148       NSWindowAnimationBehaviorDefault;
    149   bool did_save_animation_behavior = false;
    150   // Turn off swishing when restoring windows.
    151   if (is_session_restore &&
    152       [window() respondsToSelector:@selector(animationBehavior)] &&
    153       [window() respondsToSelector:@selector(setAnimationBehavior:)]) {
    154     did_save_animation_behavior = true;
    155     saved_animation_behavior = [window() animationBehavior];
    156     [window() setAnimationBehavior:NSWindowAnimationBehaviorNone];
    157   }
    158 
    159   [window() makeKeyAndOrderFront:controller_];
    160 
    161   // When creating windows from nibs it is necessary to |makeKeyAndOrderFront:|
    162   // prior to |orderOut:| then |miniaturize:| when restoring windows in the
    163   // minimized state.
    164   if (initial_show_state_ == ui::SHOW_STATE_MINIMIZED) {
    165     [window() orderOut:controller_];
    166     [window() miniaturize:controller_];
    167   } else if (initial_show_state_ == ui::SHOW_STATE_FULLSCREEN) {
    168     chrome::ToggleFullscreenMode(browser_);
    169   }
    170   initial_show_state_ = ui::SHOW_STATE_DEFAULT;
    171 
    172   // Restore window animation behavior.
    173   if (did_save_animation_behavior)
    174     [window() setAnimationBehavior:saved_animation_behavior];
    175 
    176   browser_->OnWindowDidShow();
    177 }
    178 
    179 void BrowserWindowCocoa::ShowInactive() {
    180   [window() orderFront:controller_];
    181 }
    182 
    183 void BrowserWindowCocoa::Hide() {
    184   // Not implemented.
    185 }
    186 
    187 void BrowserWindowCocoa::SetBounds(const gfx::Rect& bounds) {
    188   gfx::Rect real_bounds = [controller_ enforceMinWindowSize:bounds];
    189 
    190   ExitFullscreen();
    191   NSRect cocoa_bounds = NSMakeRect(real_bounds.x(), 0,
    192                                    real_bounds.width(),
    193                                    real_bounds.height());
    194   // Flip coordinates based on the primary screen.
    195   NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
    196   cocoa_bounds.origin.y =
    197       NSHeight([screen frame]) - real_bounds.height() - real_bounds.y();
    198 
    199   [window() setFrame:cocoa_bounds display:YES];
    200 }
    201 
    202 // Callers assume that this doesn't immediately delete the Browser object.
    203 // The controller implementing the window delegate methods called from
    204 // |-performClose:| must take precautions to ensure that.
    205 void BrowserWindowCocoa::Close() {
    206   // If there is an overlay window, we contain a tab being dragged between
    207   // windows. Don't hide the window as it makes the UI extra confused. We can
    208   // still close the window, as that will happen when the drag completes.
    209   if ([controller_ overlayWindow]) {
    210     [controller_ deferPerformClose];
    211   } else {
    212     // Using |-performClose:| can prevent the window from actually closing if
    213     // a JavaScript beforeunload handler opens an alert during shutdown, as
    214     // documented at <http://crbug.com/118424>. Re-implement
    215     // -[NSWindow performClose:] as closely as possible to how Apple documents
    216     // it.
    217     //
    218     // Before calling |-close|, hide the window immediately. |-performClose:|
    219     // would do something similar, and this ensures that the window is removed
    220     // from AppKit's display list. Not doing so can lead to crashes like
    221     // <http://crbug.com/156101>.
    222     id<NSWindowDelegate> delegate = [window() delegate];
    223     SEL window_should_close = @selector(windowShouldClose:);
    224     if ([delegate respondsToSelector:window_should_close]) {
    225       if ([delegate windowShouldClose:window()]) {
    226         [window() orderOut:nil];
    227         [window() close];
    228       }
    229     } else if ([window() respondsToSelector:window_should_close]) {
    230       if ([window() performSelector:window_should_close withObject:window()]) {
    231         [window() orderOut:nil];
    232         [window() close];
    233       }
    234     } else {
    235       [window() orderOut:nil];
    236       [window() close];
    237     }
    238   }
    239 }
    240 
    241 void BrowserWindowCocoa::Activate() {
    242   [controller_ activate];
    243 }
    244 
    245 void BrowserWindowCocoa::Deactivate() {
    246   // TODO(jcivelli): http://crbug.com/51364 Implement me.
    247   NOTIMPLEMENTED();
    248 }
    249 
    250 void BrowserWindowCocoa::FlashFrame(bool flash) {
    251   if (flash) {
    252     attention_request_id_ = [NSApp requestUserAttention:NSInformationalRequest];
    253   } else {
    254     [NSApp cancelUserAttentionRequest:attention_request_id_];
    255     attention_request_id_ = 0;
    256   }
    257 }
    258 
    259 bool BrowserWindowCocoa::IsAlwaysOnTop() const {
    260   return false;
    261 }
    262 
    263 bool BrowserWindowCocoa::IsActive() const {
    264   return [window() isKeyWindow];
    265 }
    266 
    267 gfx::NativeWindow BrowserWindowCocoa::GetNativeWindow() {
    268   return window();
    269 }
    270 
    271 BrowserWindowTesting* BrowserWindowCocoa::GetBrowserWindowTesting() {
    272   return NULL;
    273 }
    274 
    275 StatusBubble* BrowserWindowCocoa::GetStatusBubble() {
    276   return [controller_ statusBubble];
    277 }
    278 
    279 void BrowserWindowCocoa::UpdateTitleBar() {
    280   NSString* newTitle =
    281       base::SysUTF16ToNSString(browser_->GetWindowTitleForCurrentTab());
    282 
    283   pending_window_title_.reset(
    284       [BrowserWindowUtils scheduleReplaceOldTitle:pending_window_title_.get()
    285                                      withNewTitle:newTitle
    286                                         forWindow:window()]);
    287 }
    288 
    289 void BrowserWindowCocoa::BookmarkBarStateChanged(
    290     BookmarkBar::AnimateChangeType change_type) {
    291   [[controller_ bookmarkBarController]
    292       updateState:browser_->bookmark_bar_state()
    293        changeType:change_type];
    294 }
    295 
    296 void BrowserWindowCocoa::UpdateDevTools() {
    297   [controller_ updateDevToolsForContents:
    298       browser_->tab_strip_model()->GetActiveWebContents()];
    299 }
    300 
    301 void BrowserWindowCocoa::UpdateLoadingAnimations(bool should_animate) {
    302   // Do nothing on Mac.
    303 }
    304 
    305 void BrowserWindowCocoa::SetStarredState(bool is_starred) {
    306   [controller_ setStarredState:is_starred ? YES : NO];
    307 }
    308 
    309 void BrowserWindowCocoa::ZoomChangedForActiveTab(bool can_show_bubble) {
    310   [controller_ zoomChangedForActiveTab:can_show_bubble ? YES : NO];
    311 }
    312 
    313 gfx::Rect BrowserWindowCocoa::GetRestoredBounds() const {
    314   // Flip coordinates based on the primary screen.
    315   NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
    316   NSRect frame = [controller_ regularWindowFrame];
    317   gfx::Rect bounds(frame.origin.x, 0, NSWidth(frame), NSHeight(frame));
    318   bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame));
    319   return bounds;
    320 }
    321 
    322 ui::WindowShowState BrowserWindowCocoa::GetRestoredState() const {
    323   if (IsMaximized())
    324     return ui::SHOW_STATE_MAXIMIZED;
    325   if (IsMinimized())
    326     return ui::SHOW_STATE_MINIMIZED;
    327   return ui::SHOW_STATE_NORMAL;
    328 }
    329 
    330 gfx::Rect BrowserWindowCocoa::GetBounds() const {
    331   return GetRestoredBounds();
    332 }
    333 
    334 bool BrowserWindowCocoa::IsMaximized() const {
    335   return [window() isZoomed];
    336 }
    337 
    338 bool BrowserWindowCocoa::IsMinimized() const {
    339   return [window() isMiniaturized];
    340 }
    341 
    342 void BrowserWindowCocoa::Maximize() {
    343   // Zoom toggles so only call if not already maximized.
    344   if (!IsMaximized())
    345     [window() zoom:controller_];
    346 }
    347 
    348 void BrowserWindowCocoa::Minimize() {
    349   [window() miniaturize:controller_];
    350 }
    351 
    352 void BrowserWindowCocoa::Restore() {
    353   if (IsMaximized())
    354     [window() zoom:controller_];  // Toggles zoom mode.
    355   else if (IsMinimized())
    356     [window() deminiaturize:controller_];
    357 }
    358 
    359 void BrowserWindowCocoa::EnterFullscreen(
    360       const GURL& url, FullscreenExitBubbleType bubble_type) {
    361   // When simplified fullscreen is enabled, always enter normal fullscreen.
    362   const CommandLine* command_line = CommandLine::ForCurrentProcess();
    363   if (command_line->HasSwitch(switches::kEnableSimplifiedFullscreen)) {
    364     if (url.is_empty())
    365       [controller_ enterFullscreen];
    366     else
    367       [controller_ enterFullscreenForURL:url bubbleType:bubble_type];
    368     return;
    369   }
    370 
    371   [controller_ enterPresentationModeForURL:url
    372                                 bubbleType:bubble_type];
    373 }
    374 
    375 void BrowserWindowCocoa::ExitFullscreen() {
    376   [controller_ exitFullscreen];
    377 }
    378 
    379 void BrowserWindowCocoa::UpdateFullscreenExitBubbleContent(
    380       const GURL& url,
    381       FullscreenExitBubbleType bubble_type) {
    382   [controller_ updateFullscreenExitBubbleURL:url bubbleType:bubble_type];
    383 }
    384 
    385 bool BrowserWindowCocoa::ShouldHideUIForFullscreen() const {
    386   // On Mac, fullscreen mode has most normal things (in a slide-down panel).
    387   return false;
    388 }
    389 
    390 bool BrowserWindowCocoa::IsFullscreen() const {
    391   if ([controller_ inPresentationMode])
    392     CHECK([controller_ isFullscreen]);  // Presentation mode must be fullscreen.
    393   return [controller_ isFullscreen];
    394 }
    395 
    396 bool BrowserWindowCocoa::IsFullscreenBubbleVisible() const {
    397   return false;
    398 }
    399 
    400 void BrowserWindowCocoa::ConfirmAddSearchProvider(
    401     TemplateURL* template_url,
    402     Profile* profile) {
    403   // The controller will release itself when the window closes.
    404   EditSearchEngineCocoaController* editor =
    405       [[EditSearchEngineCocoaController alloc] initWithProfile:profile
    406                                                       delegate:NULL
    407                                                    templateURL:template_url];
    408   [NSApp beginSheet:[editor window]
    409      modalForWindow:window()
    410       modalDelegate:controller_
    411      didEndSelector:@selector(sheetDidEnd:returnCode:context:)
    412         contextInfo:NULL];
    413 }
    414 
    415 LocationBar* BrowserWindowCocoa::GetLocationBar() const {
    416   return [controller_ locationBarBridge];
    417 }
    418 
    419 void BrowserWindowCocoa::SetFocusToLocationBar(bool select_all) {
    420   [controller_ focusLocationBar:select_all ? YES : NO];
    421 }
    422 
    423 void BrowserWindowCocoa::UpdateReloadStopState(bool is_loading, bool force) {
    424   [controller_ setIsLoading:is_loading force:force];
    425 }
    426 
    427 void BrowserWindowCocoa::UpdateToolbar(content::WebContents* contents,
    428                                        bool should_restore_state) {
    429   [controller_ updateToolbarWithContents:contents
    430                       shouldRestoreState:should_restore_state ? YES : NO];
    431 }
    432 
    433 void BrowserWindowCocoa::FocusToolbar() {
    434   // Not needed on the Mac.
    435 }
    436 
    437 void BrowserWindowCocoa::FocusAppMenu() {
    438   // Chrome uses the standard Mac OS X menu bar, so this isn't needed.
    439 }
    440 
    441 void BrowserWindowCocoa::RotatePaneFocus(bool forwards) {
    442   // Not needed on the Mac.
    443 }
    444 
    445 void BrowserWindowCocoa::FocusBookmarksToolbar() {
    446   // Not needed on the Mac.
    447 }
    448 
    449 void BrowserWindowCocoa::FocusInfobars() {
    450   // Not needed on the Mac.
    451 }
    452 
    453 bool BrowserWindowCocoa::IsBookmarkBarVisible() const {
    454   return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
    455 }
    456 
    457 bool BrowserWindowCocoa::IsBookmarkBarAnimating() const {
    458   return [controller_ isBookmarkBarAnimating];
    459 }
    460 
    461 bool BrowserWindowCocoa::IsTabStripEditable() const {
    462   return ![controller_ isDragSessionActive];
    463 }
    464 
    465 bool BrowserWindowCocoa::IsToolbarVisible() const {
    466   return browser_->SupportsWindowFeature(Browser::FEATURE_TOOLBAR) ||
    467          browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR);
    468 }
    469 
    470 gfx::Rect BrowserWindowCocoa::GetRootWindowResizerRect() const {
    471   if (IsDownloadShelfVisible())
    472     return gfx::Rect();
    473   NSRect tabRect = [controller_ selectedTabGrowBoxRect];
    474   return gfx::Rect(NSRectToCGRect(tabRect));
    475 }
    476 
    477 // This is called from Browser, which in turn is called directly from
    478 // a menu option.  All we do here is set a preference.  The act of
    479 // setting the preference sends notifications to all windows who then
    480 // know what to do.
    481 void BrowserWindowCocoa::ToggleBookmarkBar() {
    482   chrome::ToggleBookmarkBarWhenVisible(browser_->profile());
    483 }
    484 
    485 void BrowserWindowCocoa::AddFindBar(
    486     FindBarCocoaController* find_bar_cocoa_controller) {
    487   [controller_ addFindBar:find_bar_cocoa_controller];
    488 }
    489 
    490 void BrowserWindowCocoa::ShowUpdateChromeDialog() {
    491   restart_browser::RequestRestart(window());
    492 }
    493 
    494 void BrowserWindowCocoa::ShowBookmarkBubble(const GURL& url,
    495                                             bool already_bookmarked) {
    496   [controller_ showBookmarkBubbleForURL:url
    497                       alreadyBookmarked:(already_bookmarked ? YES : NO)];
    498 }
    499 
    500 #if defined(ENABLE_ONE_CLICK_SIGNIN)
    501 void BrowserWindowCocoa::ShowOneClickSigninBubble(
    502     OneClickSigninBubbleType type,
    503     const string16& email,
    504     const string16& error_message,
    505     const StartSyncCallback& start_sync_callback) {
    506   WebContents* web_contents =
    507         browser_->tab_strip_model()->GetActiveWebContents();
    508   if (type == ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE) {
    509     base::scoped_nsobject<OneClickSigninBubbleController> bubble_controller([
    510             [OneClickSigninBubbleController alloc]
    511         initWithBrowserWindowController:cocoa_controller()
    512                             webContents:web_contents
    513                            errorMessage:base::SysUTF16ToNSString(error_message)
    514                                callback:start_sync_callback]);
    515     [bubble_controller showWindow:nil];
    516   } else {
    517     // Deletes itself when the dialog closes.
    518     new OneClickSigninDialogController(
    519         web_contents, start_sync_callback, email);
    520   }
    521 }
    522 #endif
    523 
    524 bool BrowserWindowCocoa::IsDownloadShelfVisible() const {
    525   return [controller_ isDownloadShelfVisible] != NO;
    526 }
    527 
    528 DownloadShelf* BrowserWindowCocoa::GetDownloadShelf() {
    529   DownloadShelfController* shelfController = [controller_ downloadShelf];
    530   return [shelfController bridge];
    531 }
    532 
    533 // We allow closing the window here since the real quit decision on Mac is made
    534 // in [AppController quit:].
    535 void BrowserWindowCocoa::ConfirmBrowserCloseWithPendingDownloads() {
    536   // Call InProgressDownloadResponse asynchronously to avoid a crash when the
    537   // browser window is closed here (http://crbug.com/44454).
    538   base::MessageLoop::current()->PostTask(FROM_HERE,
    539       base::Bind(&Browser::InProgressDownloadResponse,
    540                  confirm_close_factory_.GetWeakPtr(), true));
    541 }
    542 
    543 void BrowserWindowCocoa::UserChangedTheme() {
    544   [controller_ userChangedTheme];
    545 }
    546 
    547 int BrowserWindowCocoa::GetExtraRenderViewHeight() const {
    548   // Currently this is only used on linux.
    549   return 0;
    550 }
    551 
    552 void BrowserWindowCocoa::WebContentsFocused(WebContents* contents) {
    553   NOTIMPLEMENTED();
    554 }
    555 
    556 void BrowserWindowCocoa::ShowWebsiteSettings(
    557     Profile* profile,
    558     content::WebContents* web_contents,
    559     const GURL& url,
    560     const content::SSLStatus& ssl) {
    561   WebsiteSettingsUIBridge::Show(window(), profile, web_contents, url, ssl);
    562 }
    563 
    564 void BrowserWindowCocoa::ShowAppMenu() {
    565   // No-op. Mac doesn't support showing the menus via alt keys.
    566 }
    567 
    568 bool BrowserWindowCocoa::PreHandleKeyboardEvent(
    569     const NativeWebKeyboardEvent& event, bool* is_keyboard_shortcut) {
    570   if (![BrowserWindowUtils shouldHandleKeyboardEvent:event])
    571     return false;
    572 
    573   if (event.type == WebKit::WebInputEvent::RawKeyDown &&
    574       [controller_ handledByExtensionCommand:event.os_event])
    575     return true;
    576 
    577   int id = [BrowserWindowUtils getCommandId:event];
    578   if (id == -1)
    579     return false;
    580 
    581   if (browser_->command_controller()->IsReservedCommandOrKey(id, event)) {
    582       return [BrowserWindowUtils handleKeyboardEvent:event.os_event
    583                                             inWindow:window()];
    584   }
    585 
    586   DCHECK(is_keyboard_shortcut);
    587   *is_keyboard_shortcut = true;
    588   return false;
    589 }
    590 
    591 void BrowserWindowCocoa::HandleKeyboardEvent(
    592     const NativeWebKeyboardEvent& event) {
    593   if ([BrowserWindowUtils shouldHandleKeyboardEvent:event])
    594     [BrowserWindowUtils handleKeyboardEvent:event.os_event inWindow:window()];
    595 }
    596 
    597 void BrowserWindowCocoa::ShowCreateChromeAppShortcutsDialog(
    598     Profile* profile, const extensions::Extension* app) {
    599   // Normally we would show a dialog, but since we always create the app
    600   // shortcut in /Applications there are no options for the user to choose.
    601   web_app::UpdateShortcutInfoAndIconForApp(*app, profile,
    602                                            base::Bind(&CreateShortcuts));
    603 }
    604 
    605 void BrowserWindowCocoa::Cut() {
    606   [NSApp sendAction:@selector(cut:) to:nil from:nil];
    607 }
    608 
    609 void BrowserWindowCocoa::Copy() {
    610   [NSApp sendAction:@selector(copy:) to:nil from:nil];
    611 }
    612 
    613 void BrowserWindowCocoa::Paste() {
    614   [NSApp sendAction:@selector(paste:) to:nil from:nil];
    615 }
    616 
    617 void BrowserWindowCocoa::OpenTabpose() {
    618   [controller_ openTabpose];
    619 }
    620 
    621 void BrowserWindowCocoa::EnterFullscreenWithChrome() {
    622   // This method cannot be called if simplified fullscreen is enabled.
    623   const CommandLine* command_line = CommandLine::ForCurrentProcess();
    624   DCHECK(!command_line->HasSwitch(switches::kEnableSimplifiedFullscreen));
    625 
    626   CHECK(chrome::mac::SupportsSystemFullscreen());
    627   if ([controller_ inPresentationMode])
    628     [controller_ exitPresentationMode];
    629   else
    630     [controller_ enterFullscreen];
    631 }
    632 
    633 bool BrowserWindowCocoa::IsFullscreenWithChrome() {
    634   // The WithChrome mode does not exist when simplified fullscreen is enabled.
    635   const CommandLine* command_line = CommandLine::ForCurrentProcess();
    636   if (command_line->HasSwitch(switches::kEnableSimplifiedFullscreen))
    637     return false;
    638   return IsFullscreen() && ![controller_ inPresentationMode];
    639 }
    640 
    641 bool BrowserWindowCocoa::IsFullscreenWithoutChrome() {
    642   // Presentation mode does not exist if simplified fullscreen is enabled.  The
    643   // WithoutChrome mode simply maps to whether or not the window is fullscreen.
    644   const CommandLine* command_line = CommandLine::ForCurrentProcess();
    645   if (command_line->HasSwitch(switches::kEnableSimplifiedFullscreen))
    646     return IsFullscreen();
    647 
    648   return IsFullscreen() && [controller_ inPresentationMode];
    649 }
    650 
    651 WindowOpenDisposition BrowserWindowCocoa::GetDispositionForPopupBounds(
    652     const gfx::Rect& bounds) {
    653   // In Lion fullscreen mode, convert popups into tabs.
    654   if (chrome::mac::SupportsSystemFullscreen() && IsFullscreen())
    655     return NEW_FOREGROUND_TAB;
    656   return NEW_POPUP;
    657 }
    658 
    659 FindBar* BrowserWindowCocoa::CreateFindBar() {
    660   // We could push the AddFindBar() call into the FindBarBridge
    661   // constructor or the FindBarCocoaController init, but that makes
    662   // unit testing difficult, since we would also require a
    663   // BrowserWindow object.
    664   FindBarBridge* bridge = new FindBarBridge(browser_);
    665   AddFindBar(bridge->find_bar_cocoa_controller());
    666   return bridge;
    667 }
    668 
    669 web_modal::WebContentsModalDialogHost*
    670     BrowserWindowCocoa::GetWebContentsModalDialogHost() {
    671   return NULL;
    672 }
    673 
    674 extensions::ActiveTabPermissionGranter*
    675     BrowserWindowCocoa::GetActiveTabPermissionGranter() {
    676   WebContents* web_contents =
    677       browser_->tab_strip_model()->GetActiveWebContents();
    678   if (!web_contents)
    679     return NULL;
    680   extensions::TabHelper* tab_helper =
    681       extensions::TabHelper::FromWebContents(web_contents);
    682   return tab_helper ? tab_helper->active_tab_permission_granter() : NULL;
    683 }
    684 
    685 void BrowserWindowCocoa::ModelChanged(const SearchModel::State& old_state,
    686                                       const SearchModel::State& new_state) {
    687 }
    688 
    689 void BrowserWindowCocoa::DestroyBrowser() {
    690   [controller_ destroyBrowser];
    691 
    692   // at this point the controller is dead (autoreleased), so
    693   // make sure we don't try to reference it any more.
    694 }
    695 
    696 NSWindow* BrowserWindowCocoa::window() const {
    697   return [controller_ window];
    698 }
    699 
    700 void BrowserWindowCocoa::ShowAvatarBubble(WebContents* web_contents,
    701                                           const gfx::Rect& rect) {
    702   NSPoint point = GetPointForBubble(web_contents, rect.right(), rect.bottom());
    703 
    704   // |menu| will automatically release itself on close.
    705   AvatarMenuBubbleController* menu =
    706       [[AvatarMenuBubbleController alloc] initWithBrowser:browser_
    707                                                anchoredAt:point];
    708   [[menu bubble] setAlignment:info_bubble::kAlignEdgeToAnchorEdge];
    709   [menu showWindow:nil];
    710 }
    711 
    712 void BrowserWindowCocoa::ShowAvatarBubbleFromAvatarButton() {
    713   AvatarButtonController* controller = [controller_ avatarButtonController];
    714   [controller showAvatarBubble:[controller buttonView]];
    715 }
    716 
    717 void BrowserWindowCocoa::ShowPasswordGenerationBubble(
    718     const gfx::Rect& rect,
    719     const content::PasswordForm& form,
    720     autofill::PasswordGenerator* password_generator) {
    721   WebContents* web_contents =
    722       browser_->tab_strip_model()->GetActiveWebContents();
    723   // We want to point to the middle of the rect instead of the right side.
    724   NSPoint point = GetPointForBubble(web_contents,
    725                                     rect.x() + rect.width()/2,
    726                                     rect.bottom());
    727 
    728   PasswordGenerationBubbleController* controller =
    729       [[PasswordGenerationBubbleController alloc]
    730         initWithWindow:browser_->window()->GetNativeWindow()
    731             anchoredAt:point
    732         renderViewHost:web_contents->GetRenderViewHost()
    733         passwordManager:PasswordManager::FromWebContents(web_contents)
    734         usingGenerator:password_generator
    735                forForm:form];
    736   [controller showWindow:nil];
    737 }
    738