diff options
author | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-12 16:50:25 +0000 |
---|---|---|
committer | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-12 16:50:25 +0000 |
commit | 390886f24eb629a8d05ab21cef4764b2cc76c452 (patch) | |
tree | 69bf0d43baf91b82bf078b3bec65f43c46526d9a /chrome/browser/cocoa/browser_window_controller_private.mm | |
parent | a26e44e1c8e376e800368dbf5628885e1509e8fb (diff) | |
download | chromium_src-390886f24eb629a8d05ab21cef4764b2cc76c452.zip chromium_src-390886f24eb629a8d05ab21cef4764b2cc76c452.tar.gz chromium_src-390886f24eb629a8d05ab21cef4764b2cc76c452.tar.bz2 |
Mac: Part 1 of browser_window_controller.* re-organization.
BUG=35543
TEST=everything still builds and works
Review URL: http://codereview.chromium.org/606002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38899 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa/browser_window_controller_private.mm')
-rw-r--r-- | chrome/browser/cocoa/browser_window_controller_private.mm | 440 |
1 files changed, 440 insertions, 0 deletions
diff --git a/chrome/browser/cocoa/browser_window_controller_private.mm b/chrome/browser/cocoa/browser_window_controller_private.mm new file mode 100644 index 0000000..45da0bf --- /dev/null +++ b/chrome/browser/cocoa/browser_window_controller_private.mm @@ -0,0 +1,440 @@ +// Copyright (c) 2010 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. + +#import "chrome/browser/cocoa/browser_window_controller_private.h" + +#include "base/mac_util.h" +#import "base/scoped_nsobject.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_theme_provider.h" +#import "chrome/browser/cocoa/browser_theme_provider_init.h" +#import "chrome/browser/cocoa/chrome_browser_window.h" +#import "chrome/browser/cocoa/fast_resize_view.h" +#import "chrome/browser/cocoa/find_bar_cocoa_controller.h" +#import "chrome/browser/cocoa/floating_bar_backing_view.h" +#import "chrome/browser/cocoa/fullscreen_controller.h" +#import "chrome/browser/cocoa/tab_strip_controller.h" +#import "chrome/browser/cocoa/tab_strip_view.h" +#import "chrome/browser/cocoa/toolbar_controller.h" +#include "chrome/browser/renderer_host/render_widget_host_view.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tab_contents/tab_contents_view.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" + + +namespace { + +// Insets for the location bar, used when the full toolbar is hidden. +// TODO(viettrungluu): We can argue about the "correct" insetting; I like the +// following best, though arguably 0 inset is better/more correct. +const CGFloat kLocBarLeftRightInset = 1; +const CGFloat kLocBarTopInset = 0; +const CGFloat kLocBarBottomInset = 1; + +// The amount by which the floating bar is offset downwards (to avoid the menu) +// in fullscreen mode. +const CGFloat kFullscreenVerticalBarOffset = 14; + +} // end namespace + + +@implementation BrowserWindowController(Private) + +- (void)saveWindowPositionIfNeeded { + if (browser_ != BrowserList::GetLastActive()) + return; + + if (!g_browser_process || !g_browser_process->local_state() || + !browser_->ShouldSaveWindowPlacement()) + return; + + [self saveWindowPositionToPrefs:g_browser_process->local_state()]; +} + +- (void)saveWindowPositionToPrefs:(PrefService*)prefs { + // If we're in fullscreen mode, save the position of the regular window + // instead. + NSWindow* window = [self isFullscreen] ? savedRegularWindow_ : [self window]; + + // Window positions are stored relative to the origin of the primary monitor. + NSRect monitorFrame = [[[NSScreen screens] objectAtIndex:0] frame]; + + // Start with the window's frame, which is in virtual coordinates. + // Do some y twiddling to flip the coordinate system. + gfx::Rect bounds(NSRectToCGRect([window frame])); + bounds.set_y(monitorFrame.size.height - bounds.y() - bounds.height()); + + // We also need to save the current work area, in flipped coordinates. + gfx::Rect workArea(NSRectToCGRect([[window screen] visibleFrame])); + workArea.set_y(monitorFrame.size.height - workArea.y() - workArea.height()); + + DictionaryValue* windowPreferences = prefs->GetMutableDictionary( + browser_->GetWindowPlacementKey().c_str()); + windowPreferences->SetInteger(L"left", bounds.x()); + windowPreferences->SetInteger(L"top", bounds.y()); + windowPreferences->SetInteger(L"right", bounds.right()); + windowPreferences->SetInteger(L"bottom", bounds.bottom()); + windowPreferences->SetBoolean(L"maximized", false); + windowPreferences->SetBoolean(L"always_on_top", false); + windowPreferences->SetInteger(L"work_area_left", workArea.x()); + windowPreferences->SetInteger(L"work_area_top", workArea.y()); + windowPreferences->SetInteger(L"work_area_right", workArea.right()); + windowPreferences->SetInteger(L"work_area_bottom", workArea.bottom()); +} + +- (NSRect)window:(NSWindow*)window +willPositionSheet:(NSWindow*)sheet + usingRect:(NSRect)defaultSheetRect { + // Position the sheet as follows: + // - If the bookmark bar is hidden or shown as a bubble (on the NTP when the + // bookmark bar is disabled), position the sheet immediately below the + // normal toolbar. + // - If the bookmark bar is shown (attached to the normal toolbar), position + // the sheet below the bookmark bar. + // - If the bookmark bar is currently animating, position the sheet according + // to where the bar will be when the animation ends. + switch ([bookmarkBarController_ visualState]) { + case bookmarks::kShowingState: { + NSRect bookmarkBarFrame = [[bookmarkBarController_ view] frame]; + defaultSheetRect.origin.y = bookmarkBarFrame.origin.y; + break; + } + case bookmarks::kHiddenState: + case bookmarks::kDetachedState: { + NSRect toolbarFrame = [[toolbarController_ view] frame]; + defaultSheetRect.origin.y = toolbarFrame.origin.y; + break; + } + case bookmarks::kInvalidState: + default: + NOTREACHED(); + } + return defaultSheetRect; +} + +- (void)setTheme { + ThemeProvider* theme_provider = browser_->profile()->GetThemeProvider(); + BrowserThemeProvider* browser_theme_provider = + static_cast<BrowserThemeProvider*>(theme_provider); + if (browser_theme_provider) { + bool offtheRecord = browser_->profile()->IsOffTheRecord(); + GTMTheme* theme = + [GTMTheme themeWithBrowserThemeProvider:browser_theme_provider + isOffTheRecord:offtheRecord]; + theme_.reset([theme retain]); + } +} + +- (void)layoutSubviews { + // With the exception of the tab strip, the subviews which we lay out are + // subviews of the content view, so we mainly work in the content view's + // coordinate system. Note, however, that the content view's coordinate system + // and the window's base coordinate system should coincide. + NSWindow* window = [self window]; + NSView* contentView = [window contentView]; + NSRect contentBounds = [contentView bounds]; + CGFloat minY = NSMinY(contentBounds); + CGFloat width = NSWidth(contentBounds); + + // Suppress title drawing if necessary. + if ([window respondsToSelector:@selector(setShouldHideTitle:)]) + [(id)window setShouldHideTitle:![self hasTitleBar]]; + + BOOL isFullscreen = [self isFullscreen]; + CGFloat floatingBarHeight = [self floatingBarHeight]; + CGFloat yOffset = floor( + isFullscreen ? (1 - floatingBarShownFraction_) * floatingBarHeight : 0); + CGFloat maxY = NSMaxY(contentBounds) + yOffset; + CGFloat startMaxY = maxY; + + if ([self hasTabStrip]) { + // If we need to lay out the tab strip, replace |maxY| and |startMaxY| with + // higher values, and then lay out the tab strip. + startMaxY = maxY = NSHeight([window frame]) + yOffset; + maxY = [self layoutTabStripAtMaxY:maxY width:width fullscreen:isFullscreen]; + } + + // Sanity-check |maxY|. + DCHECK_GE(maxY, minY); + DCHECK_LE(maxY, NSMaxY(contentBounds) + yOffset); + + // Place the toolbar at the top of the reserved area. + maxY = [self layoutToolbarAtMaxY:maxY width:width]; + + // If we're not displaying the bookmark bar below the infobar, then it goes + // immediately below the toolbar. + BOOL placeBookmarkBarBelowInfoBar = [self placeBookmarkBarBelowInfoBar]; + if (!placeBookmarkBarBelowInfoBar) + maxY = [self layoutBookmarkBarAtMaxY:maxY width:width]; + + // The floating bar backing view doesn't actually add any height. + [self layoutFloatingBarBackingViewAtY:maxY + width:width + height:floatingBarHeight + fullscreen:isFullscreen]; + + [fullscreenController_ overlayFrameChanged:[floatingBarBackingView_ frame]]; + + // Place the find bar immediately below the toolbar/attached bookmark bar. In + // fullscreen mode, it hangs off the top of the screen when the bar is hidden. + [findBarCocoaController_ positionFindBarViewAtMaxY:maxY maxWidth:width]; + + // If in fullscreen mode, reset |maxY| to top of screen, so that the floating + // bar slides over the things which appear to be in the content area. + if (isFullscreen) + maxY = NSMaxY(contentBounds); + + // Also place the infobar container immediate below the toolbar, except in + // fullscreen mode in which case it's at the top of the visual content area. + maxY = [self layoutInfoBarAtMaxY:maxY width:width]; + + // If the bookmark bar is detached, place it next in the visual content area. + if (placeBookmarkBarBelowInfoBar) + maxY = [self layoutBookmarkBarAtMaxY:maxY width:width]; + + // Place the download shelf, if any, at the bottom of the view. + minY = [self layoutDownloadShelfAtMinY:minY width:width]; + + // Finally, the content area takes up all of the remaining space. + [self layoutTabContentAreaAtMinY:minY maxY:maxY width:width]; + + // Place the status bubble at the bottom of the content area. + verticalOffsetForStatusBubble_ = minY; + + // Normally, we don't need to tell the toolbar whether or not to show the + // divider, but things break down during animation. + [toolbarController_ + setDividerOpacity:[bookmarkBarController_ toolbarDividerOpacity]]; +} + +- (CGFloat)floatingBarHeight { + if (![self isFullscreen]) + return 0; + + CGFloat totalHeight = kFullscreenVerticalBarOffset; + + if ([self hasTabStrip]) + totalHeight += NSHeight([[self tabStripView] frame]); + + if ([self hasToolbar]) { + totalHeight += NSHeight([[toolbarController_ view] frame]); + } else if ([self hasLocationBar]) { + totalHeight += NSHeight([[toolbarController_ view] frame]) + + kLocBarTopInset + kLocBarBottomInset; + } + + if (![self placeBookmarkBarBelowInfoBar]) + totalHeight += NSHeight([[bookmarkBarController_ view] frame]); + + return totalHeight; +} + +- (CGFloat)layoutTabStripAtMaxY:(CGFloat)maxY + width:(CGFloat)width + fullscreen:(BOOL)fullscreen { + // Nothing to do if no tab strip. + if (![self hasTabStrip]) + return maxY; + + NSView* tabStripView = [self tabStripView]; + CGFloat tabStripHeight = NSHeight([tabStripView frame]); + // In fullscreen mode, push the tab strip down so that the main menu (which + // also slides down) doesn't run it over. + if (fullscreen) + maxY -= kFullscreenVerticalBarOffset; + maxY -= tabStripHeight; + [tabStripView setFrame:NSMakeRect(0, maxY, width, tabStripHeight)]; + + // Set indentation. + [tabStripController_ setIndentForControls:(fullscreen ? 0 : + [[tabStripController_ class] defaultIndentForControls])]; + + // TODO(viettrungluu): Seems kind of bad -- shouldn't |-layoutSubviews| do + // this? Moreover, |-layoutTabs| will try to animate.... + [tabStripController_ layoutTabs]; + + return maxY; +} + +- (CGFloat)layoutToolbarAtMaxY:(CGFloat)maxY width:(CGFloat)width { + NSView* toolbarView = [toolbarController_ view]; + NSRect toolbarFrame = [toolbarView frame]; + if ([self hasToolbar]) { + // The toolbar is present in the window, so we make room for it. + DCHECK(![toolbarView isHidden]); + toolbarFrame.origin.x = 0; + toolbarFrame.origin.y = maxY - NSHeight(toolbarFrame); + toolbarFrame.size.width = width; + maxY -= NSHeight(toolbarFrame); + } else { + if ([self hasLocationBar]) { + // Location bar is present with no toolbar. Put a border of + // |kLocBar...Inset| pixels around the location bar. + // TODO(viettrungluu): This is moderately ridiculous. The toolbar should + // really be aware of what its height should be (the way the toolbar + // compression stuff is currently set up messes things up). + DCHECK(![toolbarView isHidden]); + toolbarFrame.origin.x = kLocBarLeftRightInset; + toolbarFrame.origin.y = maxY - NSHeight(toolbarFrame) - kLocBarTopInset; + toolbarFrame.size.width = width - 2 * kLocBarLeftRightInset; + maxY -= kLocBarTopInset + NSHeight(toolbarFrame) + kLocBarBottomInset; + } else { + DCHECK([toolbarView isHidden]); + } + } + [toolbarView setFrame:toolbarFrame]; + return maxY; +} + +- (BOOL)placeBookmarkBarBelowInfoBar { + // If we are currently displaying the NTP detached bookmark bar or animating + // to/from it (from/to anything else), we display the bookmark bar below the + // infobar. + return [bookmarkBarController_ isInState:bookmarks::kDetachedState] || + [bookmarkBarController_ isAnimatingToState:bookmarks::kDetachedState] || + [bookmarkBarController_ isAnimatingFromState:bookmarks::kDetachedState]; +} + +- (CGFloat)layoutBookmarkBarAtMaxY:(CGFloat)maxY width:(CGFloat)width { + NSView* bookmarkBarView = [bookmarkBarController_ view]; + NSRect bookmarkBarFrame = [bookmarkBarView frame]; + BOOL oldHidden = [bookmarkBarView isHidden]; + BOOL newHidden = ![self isBookmarkBarVisible]; + if (oldHidden != newHidden) + [bookmarkBarView setHidden:newHidden]; + bookmarkBarFrame.origin.y = maxY - NSHeight(bookmarkBarFrame); + bookmarkBarFrame.size.width = width; + [bookmarkBarView setFrame:bookmarkBarFrame]; + maxY -= NSHeight(bookmarkBarFrame); + + // TODO(viettrungluu): Does this really belong here? Calling it shouldn't be + // necessary in the non-NTP case. + [bookmarkBarController_ layoutSubviews]; + + return maxY; +} + +- (void)layoutFloatingBarBackingViewAtY:(CGFloat)y + width:(CGFloat)width + height:(CGFloat)height + fullscreen:(BOOL)fullscreen { + // Only display when in fullscreen mode. + if (fullscreen) { + DCHECK(floatingBarBackingView_.get()); + BOOL aboveBookmarkBar = [self placeBookmarkBarBelowInfoBar]; + + // Insert it into the view hierarchy if necessary. + if (![floatingBarBackingView_ superview] || + aboveBookmarkBar != floatingBarAboveBookmarkBar_) { + NSView* contentView = [[self window] contentView]; + // z-order gets messed up unless we explicitly remove the floatingbar view + // and re-add it. + [floatingBarBackingView_ removeFromSuperview]; + [contentView addSubview:floatingBarBackingView_ + positioned:(aboveBookmarkBar ? + NSWindowAbove : NSWindowBelow) + relativeTo:[bookmarkBarController_ view]]; + floatingBarAboveBookmarkBar_ = aboveBookmarkBar; + } + + // Set its frame. + [floatingBarBackingView_ setFrame:NSMakeRect(0, y, width, height)]; + } else { + // Okay to call even if |floatingBarBackingView_| is nil. + if ([floatingBarBackingView_ superview]) + [floatingBarBackingView_ removeFromSuperview]; + } +} + +- (CGFloat)layoutInfoBarAtMaxY:(CGFloat)maxY width:(CGFloat)width { + NSView* infoBarView = [infoBarContainerController_ view]; + NSRect infoBarFrame = [infoBarView frame]; + infoBarFrame.origin.y = maxY - NSHeight(infoBarFrame); + infoBarFrame.size.width = width; + [infoBarView setFrame:infoBarFrame]; + maxY -= NSHeight(infoBarFrame); + return maxY; +} + +- (CGFloat)layoutDownloadShelfAtMinY:(CGFloat)minY width:(CGFloat)width { + if (downloadShelfController_.get()) { + NSView* downloadView = [downloadShelfController_ view]; + NSRect downloadFrame = [downloadView frame]; + downloadFrame.origin.y = minY; + downloadFrame.size.width = width; + [downloadView setFrame:downloadFrame]; + minY += NSHeight(downloadFrame); + } + return minY; +} + +- (void)layoutTabContentAreaAtMinY:(CGFloat)minY + maxY:(CGFloat)maxY + width:(CGFloat)width { + NSView* tabContentView = [self tabContentArea]; + NSRect tabContentFrame = [tabContentView frame]; + + bool contentShifted = NSMaxY(tabContentFrame) != maxY; + + tabContentFrame.origin.y = minY; + tabContentFrame.size.height = maxY - minY; + tabContentFrame.size.width = width; + [tabContentView setFrame:tabContentFrame]; + + // If the relayout shifts the content area up or down, let the renderer know. + if (contentShifted) { + if (TabContents* contents = browser_->GetSelectedTabContents()) { + if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView()) + rwhv->WindowFrameChanged(); + } + } +} + +- (BOOL)shouldShowBookmarkBar { + DCHECK(browser_.get()); + return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar) ? + YES : NO; +} + +- (BOOL)shouldShowDetachedBookmarkBar { + DCHECK(browser_.get()); + TabContents* contents = browser_->GetSelectedTabContents(); + return (contents && contents->ShouldShowBookmarkBar()) ? YES : NO; +} + +- (void)adjustToolbarAndBookmarkBarForCompression:(CGFloat)compression { + CGFloat newHeight = + [toolbarController_ desiredHeightForCompression:compression]; + NSRect toolbarFrame = [[toolbarController_ view] frame]; + CGFloat deltaH = newHeight - toolbarFrame.size.height; + + if (deltaH == 0) + return; + + toolbarFrame.size.height = newHeight; + NSRect bookmarkFrame = [[bookmarkBarController_ view] frame]; + bookmarkFrame.size.height = bookmarkFrame.size.height - deltaH; + [[toolbarController_ view] setFrame:toolbarFrame]; + [[bookmarkBarController_ view] setFrame:bookmarkFrame]; + [self layoutSubviews]; +} + +- (void)adjustUIForFullscreen:(BOOL)fullscreen { + if (fullscreen) { + mac_util::RequestFullScreen(); + + // Create the floating bar backing view if necessary. + if (!floatingBarBackingView_.get()) { + floatingBarBackingView_.reset( + [[FloatingBarBackingView alloc] initWithFrame:NSZeroRect]); + } + } else { + mac_util::ReleaseFullScreen(); + } +} + +@end // @implementation BrowserWindowController(Private) |