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