Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / browser_window_cocoa.mm
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
65 using content::NativeWebKeyboardEvent;
66 using content::SSLStatus;
67 using content::WebContents;
68
69 namespace {
70
71 NSPoint 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
87 BrowserWindowCocoa::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
102 BrowserWindowCocoa::~BrowserWindowCocoa() {
103   browser_->search_model()->RemoveObserver(this);
104 }
105
106 void 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
154 void BrowserWindowCocoa::ShowInactive() {
155   [window() orderFront:controller_];
156 }
157
158 void BrowserWindowCocoa::Hide() {
159   // Not implemented.
160 }
161
162 void 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.
180 void 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
216 void BrowserWindowCocoa::Activate() {
217   [controller_ activate];
218 }
219
220 void BrowserWindowCocoa::Deactivate() {
221   // TODO(jcivelli): http://crbug.com/51364 Implement me.
222   NOTIMPLEMENTED();
223 }
224
225 void 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
234 bool BrowserWindowCocoa::IsAlwaysOnTop() const {
235   return false;
236 }
237
238 void BrowserWindowCocoa::SetAlwaysOnTop(bool always_on_top) {
239   // Not implemented for browser windows.
240   NOTIMPLEMENTED();
241 }
242
243 bool BrowserWindowCocoa::IsActive() const {
244   return [window() isKeyWindow];
245 }
246
247 gfx::NativeWindow BrowserWindowCocoa::GetNativeWindow() {
248   return window();
249 }
250
251 BrowserWindowTesting* BrowserWindowCocoa::GetBrowserWindowTesting() {
252   return NULL;
253 }
254
255 StatusBubble* BrowserWindowCocoa::GetStatusBubble() {
256   return [controller_ statusBubble];
257 }
258
259 void 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
269 void BrowserWindowCocoa::BookmarkBarStateChanged(
270     BookmarkBar::AnimateChangeType change_type) {
271   [[controller_ bookmarkBarController]
272       updateState:browser_->bookmark_bar_state()
273        changeType:change_type];
274 }
275
276 void BrowserWindowCocoa::UpdateDevTools() {
277   [controller_ updateDevToolsForContents:
278       browser_->tab_strip_model()->GetActiveWebContents()];
279 }
280
281 void BrowserWindowCocoa::UpdateLoadingAnimations(bool should_animate) {
282   // Do nothing on Mac.
283 }
284
285 void BrowserWindowCocoa::SetStarredState(bool is_starred) {
286   [controller_ setStarredState:is_starred];
287 }
288
289 void BrowserWindowCocoa::SetTranslateIconToggled(bool is_lit) {
290   [controller_ setCurrentPageIsTranslated:is_lit];
291 }
292
293 void 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
304 void BrowserWindowCocoa::ZoomChangedForActiveTab(bool can_show_bubble) {
305   [controller_ zoomChangedForActiveTab:can_show_bubble ? YES : NO];
306 }
307
308 gfx::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
317 ui::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
325 gfx::Rect BrowserWindowCocoa::GetBounds() const {
326   return GetRestoredBounds();
327 }
328
329 bool BrowserWindowCocoa::IsMaximized() const {
330   return [window() isZoomed];
331 }
332
333 bool BrowserWindowCocoa::IsMinimized() const {
334   return [window() isMiniaturized];
335 }
336
337 void BrowserWindowCocoa::Maximize() {
338   // Zoom toggles so only call if not already maximized.
339   if (!IsMaximized())
340     [window() zoom:controller_];
341 }
342
343 void BrowserWindowCocoa::Minimize() {
344   [window() miniaturize:controller_];
345 }
346
347 void 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.
356 void 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
370 void BrowserWindowCocoa::ExitFullscreen() {
371   [controller_ exitAnyFullscreen];
372 }
373
374 void BrowserWindowCocoa::UpdateFullscreenExitBubbleContent(
375       const GURL& url,
376       FullscreenExitBubbleType bubble_type) {
377   [controller_ updateFullscreenExitBubbleURL:url bubbleType:bubble_type];
378 }
379
380 bool BrowserWindowCocoa::ShouldHideUIForFullscreen() const {
381   // On Mac, fullscreen mode has most normal things (in a slide-down panel).
382   return false;
383 }
384
385 bool BrowserWindowCocoa::IsFullscreen() const {
386   return [controller_ isInAnyFullscreenMode];
387 }
388
389 bool BrowserWindowCocoa::IsFullscreenBubbleVisible() const {
390   return false;
391 }
392
393 void 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
408 LocationBar* BrowserWindowCocoa::GetLocationBar() const {
409   return [controller_ locationBarBridge];
410 }
411
412 void BrowserWindowCocoa::SetFocusToLocationBar(bool select_all) {
413   [controller_ focusLocationBar:select_all ? YES : NO];
414 }
415
416 void BrowserWindowCocoa::UpdateReloadStopState(bool is_loading, bool force) {
417   [controller_ setIsLoading:is_loading force:force];
418 }
419
420 void BrowserWindowCocoa::UpdateToolbar(content::WebContents* contents) {
421   [controller_ updateToolbarWithContents:contents];
422 }
423
424 void BrowserWindowCocoa::FocusToolbar() {
425   // Not needed on the Mac.
426 }
427
428 void BrowserWindowCocoa::FocusAppMenu() {
429   // Chrome uses the standard Mac OS X menu bar, so this isn't needed.
430 }
431
432 void BrowserWindowCocoa::RotatePaneFocus(bool forwards) {
433   // Not needed on the Mac.
434 }
435
436 void BrowserWindowCocoa::FocusBookmarksToolbar() {
437   // Not needed on the Mac.
438 }
439
440 void BrowserWindowCocoa::FocusInfobars() {
441   // Not needed on the Mac.
442 }
443
444 bool BrowserWindowCocoa::IsBookmarkBarVisible() const {
445   return browser_->profile()->GetPrefs()->GetBoolean(
446       bookmarks::prefs::kShowBookmarkBar);
447 }
448
449 bool BrowserWindowCocoa::IsBookmarkBarAnimating() const {
450   return [controller_ isBookmarkBarAnimating];
451 }
452
453 bool BrowserWindowCocoa::IsTabStripEditable() const {
454   return ![controller_ isDragSessionActive];
455 }
456
457 bool BrowserWindowCocoa::IsToolbarVisible() const {
458   return browser_->SupportsWindowFeature(Browser::FEATURE_TOOLBAR) ||
459          browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR);
460 }
461
462 gfx::Rect BrowserWindowCocoa::GetRootWindowResizerRect() const {
463   if (IsDownloadShelfVisible())
464     return gfx::Rect();
465   NSRect tabRect = [controller_ selectedTabGrowBoxRect];
466   return gfx::Rect(NSRectToCGRect(tabRect));
467 }
468
469 void BrowserWindowCocoa::AddFindBar(
470     FindBarCocoaController* find_bar_cocoa_controller) {
471   [controller_ addFindBar:find_bar_cocoa_controller];
472 }
473
474 void BrowserWindowCocoa::ShowUpdateChromeDialog() {
475   restart_browser::RequestRestart(window());
476 }
477
478 void BrowserWindowCocoa::ShowBookmarkBubble(const GURL& url,
479                                             bool already_bookmarked) {
480   [controller_ showBookmarkBubbleForURL:url
481                       alreadyBookmarked:(already_bookmarked ? YES : NO)];
482 }
483
484 void BrowserWindowCocoa::ShowBookmarkAppBubble(
485     const WebApplicationInfo& web_app_info,
486     const std::string& extension_id) {
487   NOTIMPLEMENTED();
488 }
489
490 void 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)
507 void 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
530 bool BrowserWindowCocoa::IsDownloadShelfVisible() const {
531   return [controller_ isDownloadShelfVisible] != NO;
532 }
533
534 DownloadShelf* 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:].
542 void 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
550 void BrowserWindowCocoa::UserChangedTheme() {
551   [controller_ userChangedTheme];
552 }
553
554 int BrowserWindowCocoa::GetExtraRenderViewHeight() const {
555   // Currently this is only used on linux.
556   return 0;
557 }
558
559 void BrowserWindowCocoa::WebContentsFocused(WebContents* contents) {
560   NOTIMPLEMENTED();
561 }
562
563 void 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
571 void BrowserWindowCocoa::ShowAppMenu() {
572   // No-op. Mac doesn't support showing the menus via alt keys.
573 }
574
575 bool 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
600 void BrowserWindowCocoa::HandleKeyboardEvent(
601     const NativeWebKeyboardEvent& event) {
602   if ([BrowserWindowUtils shouldHandleKeyboardEvent:event])
603     [BrowserWindowUtils handleKeyboardEvent:event.os_event inWindow:window()];
604 }
605
606 void BrowserWindowCocoa::Cut() {
607   [NSApp sendAction:@selector(cut:) to:nil from:nil];
608 }
609
610 void BrowserWindowCocoa::Copy() {
611   [NSApp sendAction:@selector(copy:) to:nil from:nil];
612 }
613
614 void BrowserWindowCocoa::Paste() {
615   [NSApp sendAction:@selector(paste:) to:nil from:nil];
616 }
617
618 void BrowserWindowCocoa::EnterFullscreenWithChrome() {
619   CHECK(chrome::mac::SupportsSystemFullscreen());
620   [controller_ enterFullscreenWithChrome];
621 }
622
623 bool BrowserWindowCocoa::IsFullscreenWithChrome() {
624   return IsFullscreen() && ![controller_ inPresentationMode];
625 }
626
627 bool BrowserWindowCocoa::IsFullscreenWithoutChrome() {
628   return IsFullscreen() && [controller_ inPresentationMode];
629 }
630
631 WindowOpenDisposition BrowserWindowCocoa::GetDispositionForPopupBounds(
632     const gfx::Rect& bounds) {
633   // When using Cocoa's System Fullscreen mode, convert popups into tabs.
634   if ([controller_ isInAppKitFullscreen])
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     AvatarBubbleMode mode,
694     const signin::ManageAccountsParams& manage_accounts_params) {
695   AvatarBaseController* controller = [controller_ avatarButtonController];
696   NSView* anchor = [controller buttonView];
697   if ([anchor isHiddenOrHasHiddenAncestor])
698     anchor = [[controller_ toolbarController] wrenchButton];
699   [controller showAvatarBubbleAnchoredAt:anchor
700                                 withMode:mode
701                          withServiceType:manage_accounts_params.service_type];
702 }
703
704 int
705 BrowserWindowCocoa::GetRenderViewHeightInsetWithDetachedBookmarkBar() {
706   if (browser_->bookmark_bar_state() != BookmarkBar::DETACHED)
707     return 0;
708   return 40;
709 }
710
711 void BrowserWindowCocoa::ExecuteExtensionCommand(
712     const extensions::Extension* extension,
713     const extensions::Command& command) {
714   [cocoa_controller() executeExtensionCommand:extension->id() command:command];
715 }