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