summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/cocoa/bookmark_bar_controller.h8
-rw-r--r--chrome/browser/cocoa/browser_window_controller.h25
-rw-r--r--chrome/browser/cocoa/browser_window_controller.mm370
-rw-r--r--chrome/browser/cocoa/browser_window_controller_unittest.mm37
-rw-r--r--chrome/browser/cocoa/floating_bar_backing_view.h14
-rw-r--r--chrome/browser/cocoa/floating_bar_backing_view.mm65
-rw-r--r--chrome/browser/cocoa/floating_bar_backing_view_unittest.mm26
-rw-r--r--chrome/browser/cocoa/fullscreen_controller.h71
-rw-r--r--chrome/browser/cocoa/fullscreen_controller.mm346
-rw-r--r--chrome/browser/cocoa/location_bar_view_mac.h7
-rw-r--r--chrome/browser/cocoa/location_bar_view_mac.mm21
-rwxr-xr-xchrome/chrome_browser.gypi4
-rwxr-xr-xchrome/chrome_tests.gypi1
13 files changed, 887 insertions, 108 deletions
diff --git a/chrome/browser/cocoa/bookmark_bar_controller.h b/chrome/browser/cocoa/bookmark_bar_controller.h
index 8ab0e8c..b68b19f 100644
--- a/chrome/browser/cocoa/bookmark_bar_controller.h
+++ b/chrome/browser/cocoa/bookmark_bar_controller.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -150,9 +150,9 @@ willAnimateFromState:(bookmarks::VisualState)oldState
// Update the visible state of the bookmark bar.
- (void)updateVisibility;
-// Turn on or off the bookmark bar and prevent or reallow its
-// appearance. On disable, toggle off if shown. On enable, show only
-// if needed. For fullscreen mode.
+// Turn on or off the bookmark bar and prevent or reallow its appearance. On
+// disable, toggle off if shown. On enable, show only if needed. App and popup
+// windows do not show a bookmark bar.
- (void)setBookmarkBarEnabled:(BOOL)enabled;
// Returns the amount by which the toolbar above should be compressed.
diff --git a/chrome/browser/cocoa/browser_window_controller.h b/chrome/browser/cocoa/browser_window_controller.h
index 9a15e39..4044e5f 100644
--- a/chrome/browser/cocoa/browser_window_controller.h
+++ b/chrome/browser/cocoa/browser_window_controller.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -30,6 +30,7 @@ class BrowserWindowCocoa;
class ConstrainedWindowMac;
@class DownloadShelfController;
@class FindBarCocoaController;
+@class FullscreenController;
@class GTMWindowSheetController;
@class InfoBarContainerController;
class LocationBar;
@@ -63,6 +64,7 @@ class TabStripModelObserverBridge;
scoped_nsobject<InfoBarContainerController> infoBarContainerController_;
scoped_nsobject<DownloadShelfController> downloadShelfController_;
scoped_nsobject<BookmarkBarController> bookmarkBarController_;
+ scoped_nsobject<FullscreenController> fullscreenController_;
// Strong. StatusBubble is a special case of a strong reference that
// we don't wrap in a scoped_ptr because it is acting the same
@@ -92,6 +94,17 @@ class TabStripModelObserverBridge;
// an in-progress pinch gesture.
CGFloat totalMagnifyGestureAmount_;
NSInteger currentZoomStepDelta_;
+
+ // Lazily created view which draws the background for the floating set of bars
+ // in fullscreen mode.
+ scoped_nsobject<NSView> floatingBarBackingView_;
+
+ // Tracks whether the floating bar is above or below the bookmark bar, in
+ // terms of z-order.
+ BOOL floatingBarAboveBookmarkBar_;
+
+ // The proportion of the floating bar which is shown (in fullscreen mode).
+ CGFloat floatingBarShownFraction_;
}
// Load the browser window nib and do any Cocoa-specific initialization.
@@ -189,6 +202,14 @@ class TabStripModelObserverBridge;
// Returns fullscreen state.
- (BOOL)isFullscreen;
+// Gets or sets the fraction of the floating bar (fullscreen overlay) that is
+// shown. 0 is completely hidden, 1 is fully shown.
+- (CGFloat)floatingBarShownFraction;
+- (void)setFloatingBarShownFraction:(CGFloat)fraction;
+
+// Returns YES if any of the views in the floating bar currently has focus.
+- (BOOL)floatingBarHasFocus;
+
// The user changed the theme.
- (void)userChangedTheme;
@@ -240,7 +261,7 @@ class TabStripModelObserverBridge;
- (void)adjustWindowHeightBy:(CGFloat)deltaH;
// Return an autoreleased NSWindow suitable for fullscreen use.
-- (NSWindow*)fullscreenWindow;
+- (NSWindow*)createFullscreenWindow;
// Return a point suitable for the topLeft for a bookmark bubble.
- (NSPoint)topLeftForBubble;
diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm
index aeb5cb6..6dda638 100644
--- a/chrome/browser/cocoa/browser_window_controller.mm
+++ b/chrome/browser/cocoa/browser_window_controller.mm
@@ -1,7 +1,9 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.h"
+
#include <Carbon/Carbon.h>
#include "app/l10n_util_mac.h"
@@ -24,17 +26,20 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/tabs/tab_strip_model.h"
+#import "chrome/browser/cocoa/autocomplete_text_field_editor.h"
#import "chrome/browser/cocoa/background_gradient_view.h"
#import "chrome/browser/cocoa/bookmark_bar_controller.h"
#import "chrome/browser/cocoa/bookmark_editor_controller.h"
#import "chrome/browser/cocoa/browser_window_cocoa.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
#import "chrome/browser/cocoa/chrome_browser_window.h"
#import "chrome/browser/cocoa/download_shelf_controller.h"
#import "chrome/browser/cocoa/event_utils.h"
#import "chrome/browser/cocoa/fast_resize_view.h"
#import "chrome/browser/cocoa/find_bar_cocoa_controller.h"
#include "chrome/browser/cocoa/find_bar_bridge.h"
+#import "chrome/browser/cocoa/floating_bar_backing_view.h"
+#import "chrome/browser/cocoa/focus_tracker.h"
+#import "chrome/browser/cocoa/fullscreen_controller.h"
#import "chrome/browser/cocoa/fullscreen_window.h"
#import "chrome/browser/cocoa/infobar_container_controller.h"
#import "chrome/browser/cocoa/sad_tab_controller.h"
@@ -114,6 +119,15 @@
// longer indicate that the window is shrinking from an apparent zoomed state)
// and if it's set we continue to constrain the resize.
+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;
+} // end namespace
+
@interface GTMTheme (BrowserThemeProviderInitialization)
+ (GTMTheme*)themeWithBrowserThemeProvider:(BrowserThemeProvider*)provider
isOffTheRecord:(BOOL)offTheRecord;
@@ -129,7 +143,6 @@
@end
-
@interface BrowserWindowController(Private)
// Saves the window's position in the local state preferences.
@@ -152,11 +165,26 @@ willPositionSheet:(NSWindow*)sheet
// content area, download shelf (if any).
- (void)layoutSubviews;
+// Find the total height of the floating bar (in fullscreen mode). Safe to call
+// even when not in fullscreen mode.
+- (CGFloat)floatingBarHeight;
+
+// Lays out the tab strip at the given maximum y-coordinate, with the given
+// width, possibly for fullscreen mode; returns the new maximum y (below the tab
+// strip). This is safe to call even when there is no tab strip.
+- (CGFloat)layoutTabStripAtMaxY:(CGFloat)maxY
+ width:(CGFloat)width
+ fullscreen:(BOOL)fullscreen;
+
// Lays out the toolbar (or just location bar for popups) at the given maximum
// y-coordinate, with the given width; returns the new maximum y (below the
// toolbar).
- (CGFloat)layoutToolbarAtMaxY:(CGFloat)maxY width:(CGFloat)width;
+// Returns YES if the bookmark bar should be placed below the infobar, NO
+// otherwise.
+- (BOOL)placeBookmarkBarBelowInfoBar;
+
// Lays out the bookmark bar at the given maximum y-coordinate, with the given
// width; returns the new maximum y (below the bookmark bar). Note that one must
// call it with the appropriate |maxY| which depends on whether or not the
@@ -164,14 +192,19 @@ willPositionSheet:(NSWindow*)sheet
// |-placeBookmarkBarBelowInfoBar|).
- (CGFloat)layoutBookmarkBarAtMaxY:(CGFloat)maxY width:(CGFloat)width;
+// Lay out the view which draws the background for the floating bar when in
+// fullscreen mode, with the given (minimum) y-coordinate, width, height, and
+// fullscreen-mode-status. Should be called even when not in fullscreen mode to
+// hide the backing view.
+- (void)layoutFloatingBarBackingViewAtY:(CGFloat)y
+ width:(CGFloat)width
+ height:(CGFloat)height
+ fullscreen:(BOOL)fullscreen;
+
// Lays out the infobar at the given maximum y-coordinate, with the given width;
// returns the new maximum y (below the infobar).
- (CGFloat)layoutInfoBarAtMaxY:(CGFloat)maxY width:(CGFloat)width;
-// Returns YES if the bookmark bar should be placed below the infobar, NO
-// otherwise.
-- (BOOL)placeBookmarkBarBelowInfoBar;
-
// Lays out the download shelf, if there is one, at the given minimum
// y-coordinate, with the given width; returns the new minimum y (above the
// download shelf). This is safe to call even if there is no download shelf.
@@ -195,6 +228,9 @@ willPositionSheet:(NSWindow*)sheet
// keep the total height of the two views constant.
- (void)adjustToolbarAndBookmarkBarForCompression:(CGFloat)compression;
+// Adjust the UI when entering or leaving fullscreen mode.
+- (void)adjustUIForFullscreen:(BOOL)fullscreen;
+
@end
// IncognitoImageView subclasses NSImageView to allow mouse events to pass
@@ -267,6 +303,7 @@ willPositionSheet:(NSWindow*)sheet
// Puts the incognito badge on the window frame, if necessary. Do this
// before creating the tab strip to avoid redundant tab layout.
+ // TODO(viettrungluu): fullscreen mode
[self installIncognitoBadge];
// Create a controller for the tab strip, giving it the model object for
@@ -453,12 +490,20 @@ willPositionSheet:(NSWindow*)sheet
// TODO(dmaclach): Instead of redrawing the whole window, views that care
// about the active window state should be registering for notifications.
[[self window] setViewsNeedDisplay:YES];
+
+ // TODO(viettrungluu): For some reason, the above doesn't suffice.
+ if ([self isFullscreen])
+ [floatingBarBackingView_ setNeedsDisplay:YES];
}
- (void)windowDidResignMain:(NSNotification*)notification {
// TODO(dmaclach): Instead of redrawing the whole window, views that care
// about the active window state should be registering for notifications.
[[self window] setViewsNeedDisplay:YES];
+
+ // TODO(viettrungluu): For some reason, the above doesn't suffice.
+ if ([self isFullscreen])
+ [floatingBarBackingView_ setNeedsDisplay:YES];
}
// Called when we are activated (when we gain focus).
@@ -841,9 +886,6 @@ willPositionSheet:(NSWindow*)sheet
}
- (BOOL)supportsFullscreen {
- // Fullscreen mode disabled for Mstone-4 / ReleaseBlock-Beta.
- return NO;
-
// TODO(avi, thakis): GTMWindowSheetController has no api to move
// tabsheets between windows. Until then, we have to prevent having to
// move a tabsheet between windows, e.g. no fullscreen toggling
@@ -1197,6 +1239,14 @@ willPositionSheet:(NSWindow*)sheet
return [tabStripController_ tabDraggingAllowed];
}
+- (BOOL)tabTearingAllowed {
+ return ![self isFullscreen];
+}
+
+- (BOOL)windowMovementAllowed {
+ return ![self isFullscreen];
+}
+
- (BOOL)isTabFullyVisible:(TabView*)tab {
return [tabStripController_ isTabFullyVisible:tab];
}
@@ -1244,75 +1294,98 @@ willPositionSheet:(NSWindow*)sheet
positionFindBarView:[infoBarContainerController_ view]];
}
-// Adjust the UI for fullscreen mode. E.g. when going fullscreen,
-// remove the toolbar. When stopping fullscreen, add it back in.
-- (void)adjustUIForFullscreen:(BOOL)fullscreen {
- if (fullscreen) {
- // Disable showing of the bookmark bar. This does not toggle the
- // preference.
- [bookmarkBarController_ setBookmarkBarEnabled:NO];
- // Make room for more content area.
- [[toolbarController_ view] removeFromSuperview];
- // Hide the menubar, and allow it to un-hide when moving the mouse
- // to the top of the screen. Does this eliminate the need for an
- // info bubble describing how to exit fullscreen mode?
- mac_util::RequestFullScreen();
- } else {
- mac_util::ReleaseFullScreen();
- [[[self window] contentView] addSubview:[toolbarController_ view]];
- [bookmarkBarController_ setBookmarkBarEnabled:[self supportsBookmarkBar]];
- }
-
- // Force a relayout.
- [self layoutSubviews];
-}
-
-- (NSWindow*)fullscreenWindow {
+- (NSWindow*)createFullscreenWindow {
return [[[FullscreenWindow alloc] initForScreen:[[self window] screen]]
autorelease];
}
- (void)setFullscreen:(BOOL)fullscreen {
+ // The logic in this function is a bit complicated and very carefully
+ // arranged. See the below comments for more details.
+
+ if (fullscreen == [self isFullscreen])
+ return;
+
if (![self supportsFullscreen])
- return;
+ return;
+ // Save the current first responder so we can restore after views are moved.
NSWindow* window = [self window];
+ scoped_nsobject<FocusTracker> focusTracker(
+ [[FocusTracker alloc] initWithWindow:window]);
+ BOOL showDropdown = [self floatingBarHasFocus];
- // Retain the contentView while we remove it from its superview.
- scoped_nsobject<NSView> content([[window contentView] retain]);
+ // If we're entering fullscreen, create the fullscreen controller. If we're
+ // exiting fullscreen, kill the controller.
+ if (fullscreen) {
+ fullscreenController_.reset([[FullscreenController alloc]
+ initWithBrowserController:self]);
+ } else {
+ [fullscreenController_ exitFullscreen];
+ fullscreenController_.reset(nil);
+ }
+
+ // Retain the tab strip view while we remove it from its superview.
+ scoped_nsobject<NSView> tabStripView;
+ if ([self hasTabStrip]) {
+ tabStripView.reset([[self tabStripView] retain]);
+ [tabStripView removeFromSuperview];
+ }
- // Disable autoresizing of subviews while we move views around. This
- // prevents spurious renderer resizes.
- [content setAutoresizesSubviews:NO];
- [content removeFromSuperview];
+ // Ditto for the content view.
+ scoped_nsobject<NSView> contentView([[window contentView] retain]);
+ // Disable autoresizing of subviews while we move views around. This prevents
+ // spurious renderer resizes.
+ [contentView setAutoresizesSubviews:NO];
+ [contentView removeFromSuperview];
- NSWindow* dstWindow = nil;
+ NSWindow* destWindow = nil;
if (fullscreen) {
DCHECK(!savedRegularWindow_);
savedRegularWindow_ = [window retain];
- dstWindow = [self fullscreenWindow];
+ destWindow = [self createFullscreenWindow];
} else {
DCHECK(savedRegularWindow_);
- dstWindow = [savedRegularWindow_ autorelease];
+ destWindow = [savedRegularWindow_ autorelease];
savedRegularWindow_ = nil;
}
+ DCHECK(destWindow);
- // With this call, valgrind yells at me about "Conditional jump or
- // move depends on uninitialised value(s)". The error happens in
- // -[NSThemeFrame drawOverlayRect:]. I'm pretty convinced this is
- // an Apple bug, but there is no visual impact. I have been
- // unable to tickle it away with other window or view manipulation
- // Cocoa calls. Stack added to suppressions_mac.txt.
- [content setAutoresizesSubviews:YES];
- [dstWindow setContentView:content];
- [window setWindowController:nil];
+ // Have to do this here, otherwise later calls can crash because the window
+ // has no delegate.
[window setDelegate:nil];
- [self setWindow:dstWindow];
- [dstWindow setWindowController:self];
- [dstWindow setDelegate:self];
+ [destWindow setDelegate:self];
+
+ // With this call, valgrind complains that a "Conditional jump or move depends
+ // on uninitialised value(s)". The error happens in -[NSThemeFrame
+ // drawOverlayRect:]. I'm pretty convinced this is an Apple bug, but there is
+ // no visual impact. I have been unable to tickle it away with other window
+ // or view manipulation Cocoa calls. Stack added to suppressions_mac.txt.
+ [contentView setAutoresizesSubviews:YES];
+ [destWindow setContentView:contentView];
+
+ // Add the tabstrip after setting the content view, so that the tab strip will
+ // be on top (in the z-order).
+ if ([self hasTabStrip])
+ [[[destWindow contentView] superview] addSubview:tabStripView];
+
+ [window setWindowController:nil];
+ [self setWindow:destWindow];
+ [destWindow setWindowController:self];
[self adjustUIForFullscreen:fullscreen];
- [dstWindow makeKeyAndOrderFront:self];
+ // When entering fullscreen mode, the controller forces a layout for us. When
+ // exiting, we need to call layoutSubviews manually.
+ if (fullscreen) {
+ [fullscreenController_ enterFullscreenForContentView:contentView
+ showDropdown:showDropdown];
+ } else {
+ [self layoutSubviews];
+ }
+
+ // The window needs to be onscreen before we can set its first responder.
+ [destWindow makeKeyAndOrderFront:self];
+ [focusTracker restoreFocusInWindow:destWindow];
[window orderOut:self];
}
@@ -1320,6 +1393,20 @@ willPositionSheet:(NSWindow*)sheet
return savedRegularWindow_ != nil;
}
+- (CGFloat)floatingBarShownFraction {
+ return floatingBarShownFraction_;
+}
+
+- (void)setFloatingBarShownFraction:(CGFloat)fraction {
+ floatingBarShownFraction_ = fraction;
+ [self layoutSubviews];
+}
+
+- (BOOL)floatingBarHasFocus {
+ NSResponder* focused = [[self window] firstResponder];
+ return [focused isKindOfClass:[AutocompleteTextFieldEditor class]];
+}
+
- (NSInteger)numberOfTabs {
return browser_->tabstrip_model()->count();
}
@@ -1372,6 +1459,8 @@ willPositionSheet:(NSWindow*)sheet
windowShim_->UpdateTitleBar();
// Update the bookmark bar.
+ // TODO(viettrungluu): perhaps update to not terminate running animations (if
+ // applicable)?
[self updateBookmarkBarVisibilityWithAnimation:NO];
}
@@ -1701,16 +1790,20 @@ willAnimateFromState:(bookmarks::VisualState)oldState
}
- (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([[self window] frame]));
+ 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([[[self window] screen] visibleFrame]));
+ gfx::Rect workArea(NSRectToCGRect([[window screen] visibleFrame]));
workArea.set_y(monitorFrame.size.height - workArea.y() - workArea.height());
DictionaryValue* windowPreferences = prefs->GetMutableDictionary(
@@ -1771,20 +1864,38 @@ willPositionSheet:(NSWindow*)sheet
}
- (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 contentFrame = [contentView frame];
- CGFloat maxY = NSMaxY(contentFrame);
- CGFloat minY = NSMinY(contentFrame);
- CGFloat width = NSWidth(contentFrame);
- if ([self hasTabStrip])
- maxY = NSMinY([[self tabStripView] frame]);
- DCHECK_GE(maxY, minY);
+ 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];
@@ -1794,6 +1905,19 @@ willPositionSheet:(NSWindow*)sheet
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]];
+
+ // 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);
+
// Place the infobar container in place below the toolbar.
maxY = [self layoutInfoBarAtMaxY:maxY width:width];
@@ -1820,6 +1944,51 @@ willPositionSheet:(NSWindow*)sheet
setDividerOpacity:[bookmarkBarController_ toolbarDividerOpacity]];
}
+- (CGFloat)floatingBarHeight {
+ if (![self isFullscreen])
+ return 0;
+
+ CGFloat totalHeight = 0;
+
+ 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]);
+ 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];
@@ -1838,11 +2007,6 @@ willPositionSheet:(NSWindow*)sheet
// 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]);
- // 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;
toolbarFrame.origin.x = kLocBarLeftRightInset;
toolbarFrame.origin.y = maxY - NSHeight(toolbarFrame) - kLocBarTopInset;
toolbarFrame.size.width = width - 2 * kLocBarLeftRightInset;
@@ -1855,6 +2019,15 @@ willPositionSheet:(NSWindow*)sheet
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];
@@ -1874,6 +2047,38 @@ willPositionSheet:(NSWindow*)sheet
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];
@@ -1884,15 +2089,6 @@ willPositionSheet:(NSWindow*)sheet
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)layoutDownloadShelfAtMinY:(CGFloat)minY width:(CGFloat)width {
if (downloadShelfController_.get()) {
NSView* downloadView = [downloadShelfController_ view];
@@ -1945,6 +2141,20 @@ willPositionSheet:(NSWindow*)sheet
[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)
@implementation GTMTheme (BrowserThemeProviderInitialization)
diff --git a/chrome/browser/cocoa/browser_window_controller_unittest.mm b/chrome/browser/cocoa/browser_window_controller_unittest.mm
index 75c7e0e..e1318d1 100644
--- a/chrome/browser/cocoa/browser_window_controller_unittest.mm
+++ b/chrome/browser/cocoa/browser_window_controller_unittest.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -91,9 +91,9 @@ TEST_F(BrowserWindowControllerTest, TestSaveWindowPosition) {
}
TEST_F(BrowserWindowControllerTest, TestFullScreenWindow) {
- // Confirm the fullscreen command doesn't return nil.
+ // Confirm that |-createFullscreenWindow| doesn't return nil.
// See BrowserWindowFullScreenControllerTest for more fullscreen tests.
- EXPECT_TRUE([controller_ fullscreenWindow]);
+ EXPECT_TRUE([controller_ createFullscreenWindow]);
}
TEST_F(BrowserWindowControllerTest, TestNormal) {
@@ -166,9 +166,10 @@ TEST_F(BrowserWindowControllerTest, TestIncognitoWidthSpace) {
namespace {
// Verifies that the toolbar, infobar, tab content area, and download shelf
-// completely fill their window's contentView.
+// completely fill the area under the tabstrip.
void CheckViewPositions(BrowserWindowController* controller) {
NSRect contentView = [[[controller window] contentView] bounds];
+ NSRect tabstrip = [[controller tabStripView] frame];
NSRect toolbar = [[controller toolbarView] frame];
NSRect infobar = [[controller infoBarContainerView] frame];
NSRect contentArea = [[controller tabContentArea] frame];
@@ -189,7 +190,9 @@ void CheckViewPositions(BrowserWindowController* controller) {
EXPECT_TRUE([[controller bookmarkView] isHidden]);
}
- EXPECT_EQ(NSMaxY(contentView), NSMaxY(toolbar));
+ // Toolbar should start immediately under the tabstrip, but the tabstrip is
+ // not necessarily fixed with respect to the content view.
+ EXPECT_EQ(NSMinY(tabstrip), NSMaxY(toolbar));
}
} // end namespace
@@ -582,13 +585,7 @@ class BrowserWindowFullScreenControllerTest : public CocoaTest {
- (BOOL)supportsFullscreen;
@end
-// Fullscreen mode disabled for Mstone-4 / ReleaseBlock-Beta.
-// Confirm we don't accidentally turn it back on.
-TEST_F(BrowserWindowFullScreenControllerTest, ConfirmFullscreenDisabled) {
- EXPECT_FALSE([controller_ supportsFullscreen]);
-}
-
-TEST_F(BrowserWindowFullScreenControllerTest, DISABLED_TestFullscreen) {
+TEST_F(BrowserWindowFullScreenControllerTest, TestFullscreen) {
EXPECT_FALSE([controller_ isFullscreen]);
[controller_ setFullscreen:YES];
EXPECT_TRUE([controller_ isFullscreen]);
@@ -596,7 +593,7 @@ TEST_F(BrowserWindowFullScreenControllerTest, DISABLED_TestFullscreen) {
EXPECT_FALSE([controller_ isFullscreen]);
}
-TEST_F(BrowserWindowFullScreenControllerTest, DISABLED_TestActivate) {
+TEST_F(BrowserWindowFullScreenControllerTest, TestActivate) {
EXPECT_FALSE([controller_ isFullscreen]);
[controller_ activate];
@@ -606,19 +603,19 @@ TEST_F(BrowserWindowFullScreenControllerTest, DISABLED_TestActivate) {
[controller_ setFullscreen:YES];
[controller_ activate];
frontmostWindow = [[NSApp orderedWindows] objectAtIndex:0];
- EXPECT_EQ(frontmostWindow, [controller_ fullscreenWindow]);
+ EXPECT_EQ(frontmostWindow, [controller_ createFullscreenWindow]);
// We have to cleanup after ourselves by unfullscreening.
[controller_ setFullscreen:NO];
}
@implementation BrowserWindowControllerFakeFullscreen
-// Override fullscreenWindow to return a dummy window. This isn't needed to
-// pass the test, but because the dummy window is only 100x100, it prevents the
-// real fullscreen window from flashing up and taking over the whole screen..
-// We have to return an actual window because layoutSubviews: looks at the
-// window's frame.
-- (NSWindow*)fullscreenWindow {
+// Override |-createFullscreenWindow| to return a dummy window. This isn't
+// needed to pass the test, but because the dummy window is only 100x100, it
+// prevents the real fullscreen window from flashing up and taking over the
+// whole screen. We have to return an actual window because |-layoutSubviews|
+// looks at the window's frame.
+- (NSWindow*)createFullscreenWindow {
if (fullscreenWindow_.get())
return fullscreenWindow_.get();
diff --git a/chrome/browser/cocoa/floating_bar_backing_view.h b/chrome/browser/cocoa/floating_bar_backing_view.h
new file mode 100644
index 0000000..66ee53f
--- /dev/null
+++ b/chrome/browser/cocoa/floating_bar_backing_view.h
@@ -0,0 +1,14 @@
+// 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.
+
+#ifndef CHROME_BROWSER_COCOA_FLOATING_BAR_BACKING_VIEW_H_
+#define CHROME_BROWSER_COCOA_FLOATING_BAR_BACKING_VIEW_H_
+
+#import <Cocoa/Cocoa.h>
+
+// A custom view that draws the tab strip background for fullscreen windows.
+@interface FloatingBarBackingView : NSView
+@end
+
+#endif // CHROME_BROWSER_COCOA_FLOATING_BAR_BACKING_VIEW_H_
diff --git a/chrome/browser/cocoa/floating_bar_backing_view.mm b/chrome/browser/cocoa/floating_bar_backing_view.mm
new file mode 100644
index 0000000..b44c244
--- /dev/null
+++ b/chrome/browser/cocoa/floating_bar_backing_view.mm
@@ -0,0 +1,65 @@
+// 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.
+
+#include "chrome/browser/cocoa/floating_bar_backing_view.h"
+#import "third_party/GTM/AppKit/GTMTheme.h"
+
+@implementation FloatingBarBackingView
+
+- (void)drawRect:(NSRect)rect {
+ NSWindow* window = [self window];
+ BOOL isMainWindow = [window isMainWindow];
+
+ if (isMainWindow)
+ [[NSColor windowFrameColor] set];
+ else
+ [[NSColor windowBackgroundColor] set];
+ NSRectFill(rect);
+
+ // Code basically clipped from browser_frame_view.mm, with modifications to
+ // not use window rect and not draw rounded corners.
+ NSRect bounds = [self bounds];
+
+ // Draw our background color if we have one, otherwise fall back on
+ // system drawing.
+ GTMTheme* theme = [self gtm_theme];
+ GTMThemeState state = isMainWindow ? GTMThemeStateActiveWindow
+ : GTMThemeStateInactiveWindow;
+ NSColor* color = [theme backgroundPatternColorForStyle:GTMThemeStyleWindow
+ state:state];
+ if (color) {
+ // If there is a theme pattern, draw it here.
+
+ // To line up the background pattern with the patterns in the tabs the
+ // background pattern in the window frame need to be moved up by two
+ // pixels and left by 5.
+ // This will make the themes look slightly different than in Windows/Linux
+ // because of the differing heights between window top and tab top, but this
+ // has been approved by UI.
+ static const NSPoint kBrowserFrameViewPatternPhaseOffset = { -5, 2 };
+ NSPoint phase = kBrowserFrameViewPatternPhaseOffset;
+ phase.y += NSHeight(bounds);
+ phase = [self gtm_themePatternPhase];
+ [[NSGraphicsContext currentContext] setPatternPhase:phase];
+ [color set];
+ NSRectFill(rect);
+ }
+
+ // Check to see if we have an overlay image.
+ NSImage* overlayImage = [theme valueForAttribute:@"overlay"
+ style:GTMThemeStyleWindow
+ state:state];
+ if (overlayImage) {
+ // Anchor to top-left and don't scale.
+ NSSize overlaySize = [overlayImage size];
+ NSRect imageFrame = NSMakeRect(0, 0, overlaySize.width, overlaySize.height);
+ [overlayImage drawAtPoint:NSMakePoint(0, NSHeight(bounds) -
+ overlaySize.height)
+ fromRect:imageFrame
+ operation:NSCompositeSourceOver
+ fraction:1.0];
+ }
+}
+
+@end // @implementation FloatingBarBackingView
diff --git a/chrome/browser/cocoa/floating_bar_backing_view_unittest.mm b/chrome/browser/cocoa/floating_bar_backing_view_unittest.mm
new file mode 100644
index 0000000..94d395f
--- /dev/null
+++ b/chrome/browser/cocoa/floating_bar_backing_view_unittest.mm
@@ -0,0 +1,26 @@
+// 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/cocoa_test_helper.h"
+#import "chrome/browser/cocoa/floating_bar_backing_view.h"
+
+namespace {
+
+class FloatingBarBackingViewTest : public CocoaTest {
+ public:
+ FloatingBarBackingViewTest() {
+ NSRect content_frame = [[test_window() contentView] frame];
+ scoped_nsobject<FloatingBarBackingView> view(
+ [[FloatingBarBackingView alloc] initWithFrame:content_frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ FloatingBarBackingView* view_; // Weak. Owned by the view hierarchy.
+};
+
+// Tests display, add/remove.
+TEST_VIEW(FloatingBarBackingViewTest, view_);
+
+} // namespace
diff --git a/chrome/browser/cocoa/fullscreen_controller.h b/chrome/browser/cocoa/fullscreen_controller.h
new file mode 100644
index 0000000..06f1d42
--- /dev/null
+++ b/chrome/browser/cocoa/fullscreen_controller.h
@@ -0,0 +1,71 @@
+// 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.
+
+#ifndef CHROME_BROWSER_COCOA_FULLSCREEN_CONTROLLER_H_
+#define CHROME_BROWSER_COCOA_FULLSCREEN_CONTROLLER_H_
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/cocoa_protocols_mac.h"
+#include "chrome/browser/cocoa/location_bar_view_mac.h"
+
+@class BrowserWindowController;
+
+// Provides a controller to manage fullscreen mode for a single browser window.
+// This class handles running animations, showing and hiding the floating
+// dropdown bar, and managing the tracking area associated with the dropdown.
+// This class does not directly manage any views -- the BrowserWindowController
+// is responsible for positioning and z-ordering views.
+//
+// Tracking areas are disabled while animations are running. If
+// |overlayFrameChanged:| is called while an animation is running, the
+// controller saves the new frame and installs the appropriate tracking area
+// when the animation finishes. This is largely done for ease of
+// implementation; it is easier to check the mouse location at each animation
+// step than it is to manage a constantly-changing tracking area.
+@interface FullscreenController : NSObject<NSAnimationDelegate> {
+ // Our parent controller.
+ BrowserWindowController* browserController_; // weak
+
+ // The content view for the fullscreen window. This is nil when not in
+ // fullscreen mode.
+ NSView* contentView_; // weak
+
+ // Whether or not we are in fullscreen mode.
+ BOOL isFullscreen_;
+
+ // The tracking area associated with the floating dropdown bar. This tracking
+ // area is attached to |contentView_|, because when the dropdown is completely
+ // hidden, we still need to keep a 1px tall tracking area visible. Attaching
+ // to the content view allows us to do this. |trackingArea_| can be nil if
+ // not in fullscreen mode or during animations.
+ scoped_nsobject<NSTrackingArea> trackingArea_;
+
+ // Pointer to the currently running animation. Is nil if no animation is
+ // running.
+ scoped_nsobject<NSAnimation> currentAnimation_;
+
+ // Holds the current bounds of |trackingArea_|, even if |trackingArea_| is
+ // currently nil. Used to restore the tracking area when an animation
+ // completes.
+ NSRect trackingAreaBounds_;
+}
+
+// Designated initializer.
+- (id)initWithBrowserController:(BrowserWindowController*)controller;
+
+// Informs the controller that the browser has entered or exited fullscreen
+// mode. enterFullscreenForContentView:showDropdown: should be called after the
+// fullscreen window is setup, just before it is shown. exitFullscreen should
+// be called before any views are moved back to the non-fullscreen window.
+- (void)enterFullscreenForContentView:(NSView*)contentView
+ showDropdown:(BOOL)showDropdown;
+- (void)exitFullscreen;
+
+// Informs the controller that the overlay's frame has changed. The controller
+// uses this information to update its tracking areas.
+- (void)overlayFrameChanged:(NSRect)frame;
+@end
+
+#endif // CHROME_BROWSER_COCOA_FULLSCREEN_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/fullscreen_controller.mm b/chrome/browser/cocoa/fullscreen_controller.mm
new file mode 100644
index 0000000..ee7bc5c
--- /dev/null
+++ b/chrome/browser/cocoa/fullscreen_controller.mm
@@ -0,0 +1,346 @@
+// 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/fullscreen_controller.h"
+
+#import "chrome/browser/cocoa/browser_window_controller.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+
+
+namespace {
+const CGFloat kDropdownAnimationDuration = 0.12;
+const CGFloat kDropdownShowDelay = 0.2;
+const CGFloat kDropdownHideDelay = 0.2;
+} // end namespace
+
+
+// Helper class to manage animations for the fullscreen dropdown bar. Calls
+// back to [BrowserWindowController setFloatingBarShownFraction] once per
+// animation step.
+@interface DropdownAnimation : NSAnimation {
+ BrowserWindowController* controller_;
+ CGFloat startFraction_;
+ CGFloat endFraction_;
+}
+// Designated initializer. Asks |controller| for the current shown fraction, so
+// if the bar is already partially shown or partially hidden, the animation
+// duration may be less than |fullDuration|.
+- (id)initWithFraction:(CGFloat)fromFraction
+ fullDuration:(CGFloat)fullDuration
+ animationCurve:(NSInteger)animationCurve
+ controller:(BrowserWindowController*)controller;
+@end
+
+@implementation DropdownAnimation
+- (id)initWithFraction:(CGFloat)toFraction
+ fullDuration:(CGFloat)fullDuration
+ animationCurve:(NSInteger)animationCurve
+ controller:(BrowserWindowController*)controller {
+ // Calculate the effective duration, based on the current shown fraction.
+ DCHECK(controller);
+ CGFloat fromFraction = [controller floatingBarShownFraction];
+ CGFloat effectiveDuration = fabs(fullDuration * (fromFraction - toFraction));
+
+ if ((self = [super gtm_initWithDuration:effectiveDuration
+ animationCurve:animationCurve])) {
+ startFraction_ = fromFraction;
+ endFraction_ = toFraction;
+ controller_ = controller;
+ }
+ return self;
+}
+
+// Called once per animation step. Overridden to change the floating bar's
+// position based on the animation's progress.
+- (void)setCurrentProgress:(NSAnimationProgress)progress {
+ CGFloat fraction =
+ startFraction_ + (progress * (endFraction_ - startFraction_));
+ [controller_ setFloatingBarShownFraction:fraction];
+}
+@end
+
+
+@interface FullscreenController (PrivateMethods)
+// Shows or hides the overlay, with animation. The overlay cannot be hidden if
+// any of its "subviews" currently has focus or if the mouse is currently over
+// the overlay.
+- (void)showOverlay;
+- (void)hideOverlayIfPossible;
+
+// Stops any running animations, removes tracking areas, etc. Common cleanup
+// code shared by exitFullscreen: and dealloc:.
+- (void)cleanup;
+@end
+
+
+@implementation FullscreenController
+
+- (id)initWithBrowserController:(BrowserWindowController*)controller {
+ if ((self == [super init])) {
+ browserController_ = controller;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ // Perform all the exit fullscreen steps, including stopping any running
+ // animations and cleaning up tracking areas.
+ [self cleanup];
+ [super dealloc];
+}
+
+- (void)enterFullscreenForContentView:(NSView*)contentView
+ showDropdown:(BOOL)showDropdown {
+ DCHECK(!isFullscreen_);
+ isFullscreen_ = YES;
+ contentView_ = contentView;
+ [browserController_ setFloatingBarShownFraction:(showDropdown ? 1 : 0)];
+
+ // Since there is no way to get a pointer to the correct LocationBarViewMac to
+ // pass as the |object| parameter, we register for all location bar focus
+ // notifications and filter for those from the same window once the
+ // notification is received.
+ NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+ [nc addObserver:self
+ selector:@selector(gainedFocus:)
+ name:kLocationBarGainedFocusNotification
+ object:nil];
+ [nc addObserver:self
+ selector:@selector(lostFocus:)
+ name:kLocationBarLostFocusNotification
+ object:nil];
+}
+
+- (void)exitFullscreen {
+ DCHECK(isFullscreen_);
+ [self cleanup];
+ isFullscreen_ = NO;
+}
+
+- (void)overlayFrameChanged:(NSRect)frame {
+ if (!isFullscreen_)
+ return;
+
+ if (!NSIntersectsRect(frame, [contentView_ bounds])) {
+ // Reset the tracking area to be a single pixel high at the top border of
+ // the content view.
+ frame = [contentView_ bounds];
+ frame.origin.y = NSMaxY(frame) - 1;
+ frame.size.height = 1;
+ }
+
+ // If an animation is currently running, do not set up a tracking area.
+ // Instead, save the bounds and we will create it in animationDidEnd:.
+ if (currentAnimation_.get()) {
+ trackingAreaBounds_ = frame;
+ return;
+ }
+
+ NSWindow* window = [browserController_ window];
+ NSPoint mouseLoc =
+ [contentView_ convertPointFromBase:
+ [window mouseLocationOutsideOfEventStream]];
+
+ if (trackingArea_.get()) {
+ // If the tracking rectangle is already |rect|, quit early.
+ NSRect oldRect = [trackingArea_ rect];
+ if (NSEqualRects(frame, oldRect))
+ return;
+
+ // Otherwise, remove it.
+ [contentView_ removeTrackingArea:trackingArea_.get()];
+ }
+
+ // Create and add a new tracking area for |frame|.
+ trackingArea_.reset(
+ [[NSTrackingArea alloc] initWithRect:frame
+ options:NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveInKeyWindow
+ owner:self
+ userInfo:nil]);
+ [contentView_ addTrackingArea:trackingArea_.get()];
+}
+
+- (void)gainedFocus:(NSNotification*)notification {
+ LocationBarViewMac* bar =
+ static_cast<LocationBarViewMac*>([[notification object] pointerValue]);
+ if ([bar->location_entry()->GetNativeView() window] ==
+ [browserController_ window]) {
+ [self showOverlay];
+ }
+}
+
+- (void)lostFocus:(NSNotification*)notification {
+ LocationBarViewMac* bar =
+ static_cast<LocationBarViewMac*>([[notification object] pointerValue]);
+ if ([bar->location_entry()->GetNativeView() window] ==
+ [browserController_ window]) {
+ [self hideOverlayIfPossible];
+ }
+}
+
+// Used to activate the floating bar in fullscreen mode.
+- (void)mouseEntered:(NSEvent*)event {
+ DCHECK(isFullscreen_);
+
+ NSTrackingArea* trackingArea = [event trackingArea];
+ if (trackingArea == trackingArea_.get()) {
+ // Cancel any pending hides and set the bar to show after a delay.
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+ if (currentAnimation_.get()) {
+ [self showOverlay];
+ } else {
+ [self performSelector:@selector(showOverlay)
+ withObject:nil
+ afterDelay:kDropdownShowDelay];
+ }
+ }
+}
+
+// Used to deactivate the floating bar in fullscreen mode.
+- (void)mouseExited:(NSEvent*)event {
+ DCHECK(isFullscreen_);
+
+ NSTrackingArea* trackingArea = [event trackingArea];
+ if (trackingArea == trackingArea_.get()) {
+ // We can get a false mouse exit when the menu slides down, so if the mouse
+ // is where the menu would be, ignore the mouse exit.
+ CGFloat mainMenuHeight = [[NSApp mainMenu] menuBarHeight];
+ NSWindow* window = [browserController_ window];
+ NSPoint mouseLoc = [window mouseLocationOutsideOfEventStream];
+ if (mouseLoc.y >= NSHeight([window frame]) - mainMenuHeight)
+ return;
+
+ // Cancel any pending shows and set the bar to hide after a delay.
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+ if (currentAnimation_.get()) {
+ [self hideOverlayIfPossible];
+ } else {
+ [self performSelector:@selector(hideOverlayIfPossible)
+ withObject:nil
+ afterDelay:kDropdownHideDelay];
+ }
+ }
+}
+
+- (void)animationDidEnd:(NSAnimation*)animation {
+ // Reset the |currentAnimation_| pointer now that the animation is finished.
+ currentAnimation_.reset(nil);
+
+ // Invariant says that the tracking area is not installed while animations are
+ // in progress. Check to make sure this is true.
+ DCHECK(!trackingArea_.get());
+ if (trackingArea_.get())
+ [contentView_ removeTrackingArea:trackingArea_.get()];
+
+ // |trackingAreaBounds_| contains the correct tracking area bounds, including
+ // |any updates that may have come while the animation was running. Install a
+ // |new tracking area with these bounds.
+ trackingArea_.reset(
+ [[NSTrackingArea alloc] initWithRect:trackingAreaBounds_
+ options:NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveInKeyWindow
+ owner:self
+ userInfo:nil]);
+ [contentView_ addTrackingArea:trackingArea_.get()];
+}
+
+@end
+
+
+@implementation FullscreenController (PrivateMethods)
+
+- (void)showOverlay {
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+
+ // This method can be called by LocationBarViewMac even when we're not in
+ // fullscreen mode. Do nothing in that case.
+ if (!isFullscreen_)
+ return;
+
+ // Show the overlay with animation, first stopping any running animations.
+ if (currentAnimation_.get())
+ [currentAnimation_ stopAnimation];
+ currentAnimation_.reset(
+ [[DropdownAnimation alloc] initWithFraction:1
+ fullDuration:kDropdownAnimationDuration
+ animationCurve:NSAnimationEaseIn
+ controller:browserController_]);
+ [currentAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
+ [currentAnimation_ setDelegate:self];
+
+ // If there is an existing tracking area, remove it. We do not track mouse
+ // movements during animations (see class comment in the .h file).
+ if (currentAnimation_ && trackingArea_.get()) {
+ [contentView_ removeTrackingArea:trackingArea_.get()];
+ trackingArea_.reset(nil);
+ }
+ [currentAnimation_ startAnimation];
+}
+
+- (void)hideOverlayIfPossible {
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+
+ if (!isFullscreen_)
+ return;
+
+ NSWindow* window = [browserController_ window];
+
+ // If the floating bar currently has focus, do not hide the overlay.
+ if ([browserController_ floatingBarHasFocus])
+ return;
+
+ // We can get a false mouse exit when the menu slides down, so if the mouse is
+ // where the menu would be, ignore the mouse exit.
+ // TODO(rohitrao): Set a timer to check where the mouse is later, to make
+ // sure the floating bar doesn't get stuck.
+ CGFloat mainMenuHeight = [[NSApp mainMenu] menuBarHeight];
+ NSPoint mouseLoc = [window mouseLocationOutsideOfEventStream];
+ if (mouseLoc.y >= NSHeight([window frame]) - mainMenuHeight)
+ return;
+
+ // Do not hide the bar if the mouse is currently over the dropdown view. We
+ // use the current tracking area as a proxy for the dropdown's location. If
+ // there is no current tracking area (possible because we currently do not
+ // always open the dropdown when the omnibox gets focus), then go ahead and
+ // close the dropdown.
+ if (trackingArea_.get() &&
+ NSMouseInRect([contentView_ convertPointFromBase:mouseLoc],
+ [trackingArea_ rect],
+ [contentView_ isFlipped])) {
+ return;
+ }
+
+ // Hide the overlay with animation, first stopping any running animations.
+ if (currentAnimation_.get())
+ [currentAnimation_ stopAnimation];
+ currentAnimation_.reset(
+ [[DropdownAnimation alloc] initWithFraction:0
+ fullDuration:kDropdownAnimationDuration
+ animationCurve:NSAnimationEaseOut
+ controller:browserController_]);
+ [currentAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
+ [currentAnimation_ setDelegate:self];
+
+ // If there is an existing tracking area, remove it. We do not track mouse
+ // movements during animations.
+ if (currentAnimation_ && trackingArea_.get()) {
+ [contentView_ removeTrackingArea:trackingArea_.get()];
+ trackingArea_.reset(nil);
+ }
+
+ [currentAnimation_ startAnimation];
+}
+
+- (void)cleanup {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+ [currentAnimation_ stopAnimation];
+ [contentView_ removeTrackingArea:trackingArea_.get()];
+ contentView_ = nil;
+ currentAnimation_.reset(nil);
+ trackingArea_.reset(nil);
+}
+
+@end
diff --git a/chrome/browser/cocoa/location_bar_view_mac.h b/chrome/browser/cocoa/location_bar_view_mac.h
index 363188c..567a9a2 100644
--- a/chrome/browser/cocoa/location_bar_view_mac.h
+++ b/chrome/browser/cocoa/location_bar_view_mac.h
@@ -27,6 +27,10 @@ class CommandUpdater;
class Profile;
class ToolbarModel;
+// Notifications sent when this location bar gains or loses focus.
+extern const NSString* kLocationBarGainedFocusNotification;
+extern const NSString* kLocationBarLostFocusNotification;
+
// A C++ bridge class that represents the location bar UI element to
// the portable code. Wires up an AutocompleteEditViewMac instance to
// the location bar text field, which handles most of the work.
@@ -327,6 +331,9 @@ class LocationBarViewMac : public AutocompleteEditController,
// Sets the label for the SSL icon.
void SetSecurityIconLabel();
+ // Posts |notification| to the default notification center.
+ void PostNotification(const NSString* notification);
+
scoped_ptr<AutocompleteEditViewMac> edit_view_;
CommandUpdater* command_updater_; // Weak, owned by Browser.
diff --git a/chrome/browser/cocoa/location_bar_view_mac.mm b/chrome/browser/cocoa/location_bar_view_mac.mm
index 3fd0da4..6d30820 100644
--- a/chrome/browser/cocoa/location_bar_view_mac.mm
+++ b/chrome/browser/cocoa/location_bar_view_mac.mm
@@ -34,6 +34,13 @@
#include "grit/theme_resources.h"
#include "skia/ext/skia_utils_mac.h"
+
+const NSString* kLocationBarGainedFocusNotification =
+ @"kLocationBarGainedFocusNotification_Chrome";
+const NSString* kLocationBarLostFocusNotification =
+ @"kLocationBarLostFocusNotification_Chrome";
+
+
// TODO(shess): This code is mostly copied from the gtk
// implementation. Make sure it's all appropriate and flesh it out.
@@ -139,10 +146,12 @@ void LocationBarViewMac::AcceptInputWithDisposition(
}
void LocationBarViewMac::FocusLocation() {
+ PostNotification(kLocationBarGainedFocusNotification);
edit_view_->FocusLocation();
}
void LocationBarViewMac::FocusSearch() {
+ PostNotification(kLocationBarGainedFocusNotification);
edit_view_->SetForcedQuery();
// TODO(pkasting): Focus the edit a la Linux/Win
}
@@ -299,10 +308,12 @@ void LocationBarViewMac::OnInputInProgress(bool in_progress) {
Update(NULL, false);
}
-void LocationBarViewMac::OnKillFocus() {
+void LocationBarViewMac::OnSetFocus() {
+ PostNotification(kLocationBarGainedFocusNotification);
}
-void LocationBarViewMac::OnSetFocus() {
+void LocationBarViewMac::OnKillFocus() {
+ PostNotification(kLocationBarLostFocusNotification);
}
SkBitmap LocationBarViewMac::GetFavIcon() const {
@@ -317,6 +328,7 @@ std::wstring LocationBarViewMac::GetTitle() const {
void LocationBarViewMac::Revert() {
edit_view_->RevertAll();
+ PostNotification(kLocationBarLostFocusNotification);
}
// TODO(pamg): Change all these, here and for other platforms, to size_t.
@@ -473,6 +485,11 @@ void LocationBarViewMac::Observe(NotificationType type,
}
}
+void LocationBarViewMac::PostNotification(const NSString* notification) {
+ [[NSNotificationCenter defaultCenter] postNotificationName:notification
+ object:[NSValue valueWithPointer:this]];
+}
+
// LocationBarImageView---------------------------------------------------------
void LocationBarViewMac::LocationBarImageView::SetImage(NSImage* image) {
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index a85e57d..c181704e 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -496,10 +496,14 @@
'browser/cocoa/find_pasteboard.mm',
'browser/cocoa/first_run_dialog.h',
'browser/cocoa/first_run_dialog.mm',
+ 'browser/cocoa/floating_bar_backing_view.h',
+ 'browser/cocoa/floating_bar_backing_view.mm',
'browser/cocoa/focus_tracker.h',
'browser/cocoa/focus_tracker.mm',
'browser/cocoa/font_language_settings_controller.h',
'browser/cocoa/font_language_settings_controller.mm',
+ 'browser/cocoa/fullscreen_controller.h',
+ 'browser/cocoa/fullscreen_controller.mm',
'browser/cocoa/fullscreen_window.h',
'browser/cocoa/fullscreen_window.mm',
'browser/cocoa/gradient_button_cell.h',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index d7d338f..066f627 100755
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -616,6 +616,7 @@
'browser/cocoa/find_bar_text_field_cell_unittest.mm',
'browser/cocoa/find_bar_view_unittest.mm',
'browser/cocoa/find_pasteboard_unittest.mm',
+ 'browser/cocoa/floating_bar_backing_view_unittest.mm',
'browser/cocoa/focus_tracker_unittest.mm',
'browser/cocoa/font_language_settings_controller_unittest.mm',
'browser/cocoa/fullscreen_window_unittest.mm',