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