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