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