Newer
Older

pinkerton@google.com
committed
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/gfx/rect.h"

pinkerton@chromium.org
committed
#include "base/logging.h"

avi@google.com
committed
#include "base/sys_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/cocoa/browser_window_cocoa.h"

pinkerton@chromium.org
committed
#import "chrome/browser/cocoa/browser_window_controller.h"
#import "chrome/browser/cocoa/bug_report_window_controller.h"

pinkerton@chromium.org
committed
#import "chrome/browser/cocoa/clear_browsing_data_controller.h"
#import "chrome/browser/cocoa/download_shelf_controller.h"
#import "chrome/browser/cocoa/html_dialog_window_controller.h"
#import "chrome/browser/cocoa/keyword_editor_cocoa_controller.h"
#import "chrome/browser/cocoa/nsmenuitem_additions.h"
#include "chrome/browser/cocoa/page_info_window_mac.h"
#include "chrome/browser/cocoa/repost_form_warning_mac.h"
#include "chrome/browser/cocoa/status_bubble_mac.h"
#include "chrome/browser/cocoa/task_manager_mac.h"
#import "chrome/browser/cocoa/theme_install_bubble_view.h"

thakis@chromium.org
committed
#include "chrome/browser/download/download_shelf.h"
#include "chrome/browser/global_keyboard_shortcuts_mac.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"

thakis@chromium.org
committed
#include "chrome/common/temp_scaffolding_stubs.h"
#include "chrome/browser/profile.h"

pinkerton@google.com
committed
BrowserWindowCocoa::BrowserWindowCocoa(Browser* browser,
BrowserWindowController* controller,

pinkerton@google.com
committed
NSWindow* window)

thakis@chromium.org
committed
: window_(window),
browser_(browser),
// This pref applies to all windows, so all must watch for it.
registrar_.Add(this, NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
NotificationService::AllSources());

pinkerton@google.com
committed
}
BrowserWindowCocoa::~BrowserWindowCocoa() {
}
void BrowserWindowCocoa::Show() {
[window_ makeKeyAndOrderFront:controller_];
}
void BrowserWindowCocoa::SetBounds(const gfx::Rect& bounds) {
NSRect cocoa_bounds = NSMakeRect(bounds.x(), 0, bounds.width(),
bounds.height());
// Flip coordinates based on the primary screen.
NSScreen* screen = [[NSScreen screens] objectAtIndex:0];

pinkerton@google.com
committed
[screen frame].size.height - bounds.height() - bounds.y();

pinkerton@chromium.org
committed
[window_ setFrame:cocoa_bounds display:YES];

pinkerton@google.com
committed
}

pinkerton@chromium.org
committed
// Callers assume that this doesn't immediately delete the Browser object.
// The controller implementing the window delegate methods called from
// |-performClose:| must take precautions to ensure that.

pinkerton@google.com
committed
void BrowserWindowCocoa::Close() {

pinkerton@chromium.org
committed
// If there is an overlay window, we contain a tab being dragged between
// windows. Don't hide the window as it makes the UI extra confused. We can
// still close the window, as that will happen when the drag completes.
if ([controller_ overlayWindow])
[controller_ deferPerformClose];

pinkerton@chromium.org
committed
else {
// Make sure we hide the window immediately. Even though performClose:
// calls orderOut: eventually, it leaves the window on-screen long enough
// that we start to see tabs shutting down. http://crbug.com/23959
[window_ orderOut:controller_];

pinkerton@chromium.org
committed
[window_ performClose:controller_];

pinkerton@chromium.org
committed
}

pinkerton@google.com
committed
}
void BrowserWindowCocoa::Activate() {
[controller_ activate];

pinkerton@google.com
committed
}
void BrowserWindowCocoa::FlashFrame() {
[NSApp requestUserAttention:NSInformationalRequest];

pinkerton@google.com
committed
}
bool BrowserWindowCocoa::IsActive() const {
return [window_ isKeyWindow];
}
gfx::NativeWindow BrowserWindowCocoa::GetNativeHandle() {

pinkerton@google.com
committed
return [controller_ window];
}

ben@chromium.org
committed
BrowserWindowTesting* BrowserWindowCocoa::GetBrowserWindowTesting() {
return NULL;
}

pinkerton@google.com
committed
StatusBubble* BrowserWindowCocoa::GetStatusBubble() {

pinkerton@chromium.org
committed
return [controller_ statusBubble];

pinkerton@google.com
committed
}
void BrowserWindowCocoa::SelectedTabToolbarSizeChanged(bool is_animating) {
// According to beng, this is an ugly method that comes from the days when the
// download shelf was a ChromeView attached to the TabContents, and as its
// size changed via animation it notified through TCD/etc to the browser view
// to relayout for each tick of the animation. We don't need anything of the
// sort on Mac.

pinkerton@google.com
committed
}

finnur@chromium.org
committed
void BrowserWindowCocoa::SelectedTabExtensionShelfSizeChanged() {
NOTIMPLEMENTED();
}

pinkerton@google.com
committed
void BrowserWindowCocoa::UpdateTitleBar() {

avi@google.com
committed
NSString* newTitle =
base::SysUTF16ToNSString(browser_->GetWindowTitleForCurrentTab());

avi@google.com
committed

pinkerton@google.com
committed
}
void BrowserWindowCocoa::ShelfVisibilityChanged() {
// Mac doesn't yet support showing the bookmark bar at a different size on
// the new tab page. When it does, this method should attempt to relayout the
// bookmark bar/extension shelf as their preferred height may have changed.
NOTIMPLEMENTED();
}
void BrowserWindowCocoa::UpdateDevTools() {
NOTIMPLEMENTED();
}
void BrowserWindowCocoa::FocusDevTools() {
NOTIMPLEMENTED();
}

pinkerton@google.com
committed
void BrowserWindowCocoa::UpdateLoadingAnimations(bool should_animate) {
// Do nothing on Mac.

pinkerton@google.com
committed
}

ben@chromium.org
committed
void BrowserWindowCocoa::SetStarredState(bool is_starred) {
[controller_ setStarredState:is_starred ? YES : NO];

ben@chromium.org
committed
}
gfx::Rect BrowserWindowCocoa::GetRestoredBounds() const {

pinkerton@google.com
committed
// TODO(pinkerton): not sure if we can get the non-zoomed bounds, or if it
// really matters. We may want to let Cocoa handle all this for us.
// Flip coordinates based on the primary screen.
NSScreen* screen = [[NSScreen screens] objectAtIndex:0];

pinkerton@google.com
committed
NSRect frame = [window_ frame];
gfx::Rect bounds(frame.origin.x, 0, frame.size.width, frame.size.height);
bounds.set_y([screen frame].size.height - frame.origin.y - frame.size.height);

pinkerton@google.com
committed
return bounds;
}

mad@chromium.org
committed
bool BrowserWindowCocoa::IsMaximized() const {

pinkerton@google.com
committed
return [window_ isZoomed];
}
void BrowserWindowCocoa::SetFullscreen(bool fullscreen) {
[controller_ setFullscreen:fullscreen];
}
bool BrowserWindowCocoa::IsFullscreen() const {
return !![controller_ isFullscreen];

mad@chromium.org
committed
gfx::Rect BrowserWindowCocoa::GetRootWindowResizerRect() const {

pinkerton@chromium.org
committed
NSRect tabRect = [controller_ selectedTabGrowBoxRect];

pinkerton@chromium.org
committed
return gfx::Rect(NSRectToCGRect(tabRect));

mad@chromium.org
committed
}

ben@chromium.org
committed
void BrowserWindowCocoa::ConfirmAddSearchProvider(
const TemplateURL* template_url,
Profile* profile) {
NOTIMPLEMENTED();
}
LocationBar* BrowserWindowCocoa::GetLocationBar() const {

pinkerton@chromium.org
committed
return [controller_ locationBar];

pinkerton@google.com
committed
}
void BrowserWindowCocoa::SetFocusToLocationBar() {

pinkerton@chromium.org
committed
[controller_ focusLocationBar];
}

pkasting@chromium.org
committed
void BrowserWindowCocoa::UpdateStopGoState(bool is_loading, bool force) {

pinkerton@chromium.org
committed
[controller_ setIsLoading:is_loading ? YES : NO];

pinkerton@google.com
committed
}
void BrowserWindowCocoa::UpdateToolbar(TabContents* contents,
bool should_restore_state) {
[controller_ updateToolbarWithContents:contents

pinkerton@chromium.org
committed
shouldRestoreState:should_restore_state ? YES : NO];

pinkerton@google.com
committed
}
void BrowserWindowCocoa::FocusToolbar() {

pinkerton@chromium.org
committed
NOTIMPLEMENTED();

pinkerton@google.com
committed
}
bool BrowserWindowCocoa::IsBookmarkBarVisible() const {
return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);

pinkerton@google.com
committed
}
// This is called from Browser, which in turn is called directly from
// a menu option. All we do here is set a preference. The act of
// setting the preference sends notifications to all windows who then
// know what to do.

pinkerton@google.com
committed
void BrowserWindowCocoa::ToggleBookmarkBar() {
bookmark_utils::ToggleWhenVisible(browser_->profile());

pinkerton@google.com
committed
}

finnur@chromium.org
committed
void BrowserWindowCocoa::ToggleExtensionShelf() {
NOTIMPLEMENTED();
}
void BrowserWindowCocoa::AddFindBar(
FindBarCocoaController* find_bar_cocoa_controller) {
return [controller_ addFindBar:find_bar_cocoa_controller];

finnur@google.com
committed
}

pinkerton@google.com
committed
void BrowserWindowCocoa::ShowAboutChromeDialog() {

pinkerton@chromium.org
committed
NOTIMPLEMENTED();

pinkerton@google.com
committed
}
void BrowserWindowCocoa::ShowTaskManager() {

pinkerton@google.com
committed
void BrowserWindowCocoa::ShowBookmarkManager() {

pinkerton@chromium.org
committed
NOTIMPLEMENTED();

pinkerton@google.com
committed
}

ben@chromium.org
committed
void BrowserWindowCocoa::ShowBookmarkBubble(const GURL& url,
bool already_bookmarked) {
[controller_ showBookmarkBubbleForURL:url
alreadyBookmarked:(already_bookmarked ? YES : NO)];

ben@chromium.org
committed
}

thakis@chromium.org
committed
bool BrowserWindowCocoa::IsDownloadShelfVisible() const {
return [controller_ isDownloadShelfVisible] != NO;

thakis@chromium.org
committed
}
DownloadShelf* BrowserWindowCocoa::GetDownloadShelf() {
DownloadShelfController* shelfController = [controller_ downloadShelf];
return [shelfController bridge];

thakis@chromium.org
committed
}

pinkerton@google.com
committed
void BrowserWindowCocoa::ShowReportBugDialog() {
TabContents* current_tab = browser_->GetSelectedTabContents();
if (current_tab && current_tab->controller().GetActiveEntry()) {
BugReportWindowController* controller =
[[BugReportWindowController alloc]
initWithTabContents:current_tab
profile:browser_->profile()];
[controller runModalDialog];
}

pinkerton@google.com
committed
}
void BrowserWindowCocoa::ShowClearBrowsingDataDialog() {

pinkerton@chromium.org
committed
scoped_nsobject<ClearBrowsingDataController> controller(
[[ClearBrowsingDataController alloc]
initWithProfile:browser_->profile()]);
[controller runModalDialog];

pinkerton@google.com
committed
}
void BrowserWindowCocoa::ShowImportDialog() {

pinkerton@chromium.org
committed
NOTIMPLEMENTED();

pinkerton@google.com
committed
}
void BrowserWindowCocoa::ShowSearchEnginesDialog() {
[KeywordEditorCocoaController showKeywordEditor:browser_->profile()];

pinkerton@google.com
committed
}
void BrowserWindowCocoa::ShowPasswordManager() {

pinkerton@chromium.org
committed
NOTIMPLEMENTED();

pinkerton@google.com
committed
}

pinkerton@chromium.org
committed
NOTIMPLEMENTED();
}
void BrowserWindowCocoa::ShowNewProfileDialog() {

pinkerton@chromium.org
committed
NOTIMPLEMENTED();
void BrowserWindowCocoa::ShowRepostFormWarningDialog(
TabContents* tab_contents) {
new RepostFormWarningMac(GetNativeHandle(), &tab_contents->controller());
void BrowserWindowCocoa::ShowProfileErrorDialog(int message_id) {
NOTIMPLEMENTED();
}
void BrowserWindowCocoa::ShowThemeInstallBubble() {
ThemeInstallBubbleView::Show(window_);
}

paul@chromium.org
committed
// We allow closing the window here since the real quit decision on Mac is made
// in [AppController quit:].

jcampan@chromium.org
committed
void BrowserWindowCocoa::ConfirmBrowserCloseWithPendingDownloads() {

paul@chromium.org
committed
browser_->InProgressDownloadResponse(true);

jcampan@chromium.org
committed
}

brettw@chromium.org
committed
void BrowserWindowCocoa::ShowHTMLDialog(HtmlDialogUIDelegate* delegate,

brettw@chromium.org
committed
gfx::NativeWindow parent_window) {
if (!parent_window) {
parent_window = GetNativeHandle();
}
[HtmlDialogWindowController showHtmlDialog:delegate
parentWindow:parent_window
browser:browser_];

pinkerton@google.com
committed
}
void BrowserWindowCocoa::UserChangedTheme() {
[controller_ userChangedTheme];

estade@chromium.org
committed
int BrowserWindowCocoa::GetExtraRenderViewHeight() const {
// Currently this is only used on linux.
return 0;
}
void BrowserWindowCocoa::TabContentsFocused(TabContents* tab_contents) {
NOTIMPLEMENTED();
}
void BrowserWindowCocoa::ShowPageInfo(Profile* profile,
const GURL& url,
const NavigationEntry::SSLStatus& ssl,
bool show_history) {
PageInfoWindowMac::ShowPageInfo(profile, url, ssl, show_history);
}
void BrowserWindowCocoa::ShowPageMenu() {
// No-op. Mac doesn't support showing the menus via alt keys.
}
void BrowserWindowCocoa::ShowAppMenu() {
// No-op. Mac doesn't support showing the menus via alt keys.
}
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
@interface MenuWalker : NSObject
+ (NSMenuItem*)itemForKeyEquivalent:(NSEvent*)key
menu:(NSMenu*)menu;
@end
@implementation MenuWalker
+ (NSMenuItem*)itemForKeyEquivalent:(NSEvent*)key
menu:(NSMenu*)menu {
NSMenuItem* result = nil;
for (NSMenuItem *item in [menu itemArray]) {
NSMenu* submenu = [item submenu];
if (submenu) {
if (submenu != [NSApp servicesMenu])
result = [self itemForKeyEquivalent:key
menu:submenu];
} else if ([item cr_firesForKeyEvent:key]) {
result = item;
}
if (result)
break;
}
return result;
}
@end

jam@chromium.org
committed
int BrowserWindowCocoa::GetCommandId(const NativeWebKeyboardEvent& event) {
if ([event.os_event type] != NSKeyDown)
return -1;
// Look in menu.
NSMenuItem* item = [MenuWalker itemForKeyEquivalent:event.os_event
menu:[NSApp mainMenu]];
if (item && [item action] == @selector(commandDispatch:) && [item tag] > 0)
return [item tag];
// "Close window" doesn't use the |commandDispatch:| mechanism. Menu items
// that do not correspond to IDC_ constants need no special treatment however,
// as they can't be blacklisted in |Browser::IsReservedAccelerator()| anyhow.
if (item && [item action] == @selector(performClose:))
return IDC_CLOSE_WINDOW;
// Look in secondary keyboard shortcuts.
NSUInteger modifiers = [event.os_event modifierFlags];
const bool cmdKey = (modifiers & NSCommandKeyMask) != 0;
const bool shiftKey = (modifiers & NSShiftKeyMask) != 0;
const bool cntrlKey = (modifiers & NSControlKeyMask) != 0;
const bool optKey = (modifiers & NSAlternateKeyMask) != 0;
const int keyCode = [event.os_event keyCode];
int cmdNum = CommandForWindowKeyboardShortcut(
cmdKey, shiftKey, cntrlKey, optKey, keyCode);
if (cmdNum != -1)
return cmdNum;
cmdNum = CommandForBrowserKeyboardShortcut(
cmdKey, shiftKey, cntrlKey, optKey, keyCode);
if (cmdNum != -1)
return cmdNum;

jam@chromium.org
committed
return -1;
}
void BrowserWindowCocoa::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
switch (type.value) {
// Only the key window gets a direct toggle from the menu.
// Other windows hear about it from the notification.
case NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED:
[controller_ updateBookmarkBarVisibility];
break;
default:
NOTREACHED(); // we don't ask for anything else!
break;
}
}

pinkerton@google.com
committed
void BrowserWindowCocoa::DestroyBrowser() {
[controller_ destroyBrowser];
// at this point the controller is dead (autoreleased), so
// make sure we don't try to reference it any more.
}