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