diff options
author | thakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-09 22:37:55 +0000 |
---|---|---|
committer | thakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-09 22:37:55 +0000 |
commit | d546029a268e19c244bcbfba57e4bd2d39d44a83 (patch) | |
tree | 82090113ed3095ac5db6fe5610a908846b7cf0ec | |
parent | 8717745b839efbe446902f3449a3a348f687a42f (diff) | |
download | chromium_src-d546029a268e19c244bcbfba57e4bd2d39d44a83.zip chromium_src-d546029a268e19c244bcbfba57e4bd2d39d44a83.tar.gz chromium_src-d546029a268e19c244bcbfba57e4bd2d39d44a83.tar.bz2 |
Several theming fixes for the Mac. Sorry for the extensive change, but they
were all sort of intertwined.
Fixes up patterns in general so that they are all in phase.
Moves the window widget buttons down by two pixels.
Draws overlays correctly.
Fixes up some accessibility issues with the default window widgets.
Gets rid of some out of date files (tab_cell).
BUG=18438, 18547, 19851, 20295, 22213, 23651, 24338
TEST=Launch Chrome. Switch to "dots" theme from the Google themes. Create a couple of tabs. Check to make sure that the background pattern line up with the tabs. Move the tabs around. Check that the hightlight colors and text colors look correct for all of the tabs. Make sure the patterns stay lined up. Resize the window, make sure none of the patterns move around. Create new windows by dragging the tabs out of the windows and make sure a new window is created with the correct pattern. Show the "find" bar. Make sure its pattern lines up correctly with the tabbar. Switch to default theme. Make sure it looks correct and draws properly. Switch to Zen theme and make sure that the overlay at the top draws correctly. Create a new window. make sure that the rollovers in the window widgets work correctly in both the active and inactive window. Mouse down on the zoom button in the inactive window and notice that the window context changes. Move off of the zoom button and mouse up. Mouse down on the miniaturize button on the inactive window and notice that the window context does not change. Move off of the miniaturize button and mouse up. Do the same thing you did for the miniaturize button for the close button. Start up Accessibility Inspector from the developer tools. Make sure that the window widgets report their accessibility information correctly.
Review URL: http://codereview.chromium.org/260009
Patch from dmaclach@chromium.org.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28613 0039d316-1c4b-4281-b951-d872f2087c98
27 files changed, 839 insertions, 346 deletions
@@ -118,7 +118,7 @@ deps_os = { }, "mac": { "src/third_party/GTM": - "http://google-toolbox-for-mac.googlecode.com/svn/trunk@223", + "http://google-toolbox-for-mac.googlecode.com/svn/trunk@230", "src/third_party/pdfsqueeze": "http://pdfsqueeze.googlecode.com/svn/trunk@2", "src/third_party/WebKit/WebKit/mac": diff --git a/chrome/browser/cocoa/background_gradient_view.h b/chrome/browser/cocoa/background_gradient_view.h index 9c04b4d..547a08d 100644 --- a/chrome/browser/cocoa/background_gradient_view.h +++ b/chrome/browser/cocoa/background_gradient_view.h @@ -10,7 +10,6 @@ // A custom view that draws a 'standard' background gradient. // Base class for other Chromium views. - @interface BackgroundGradientView : NSView { @private BOOL showsDivider_; @@ -19,6 +18,10 @@ // The color used for the bottom stroke. Public so subclasses can use. - (NSColor *)strokeColor; +// Draws the background for this view. Make sure that your patternphase +// is set up correctly in your graphics context before calling. +- (void)drawBackground; + // Controls whether the bar draws a dividing line at the bottom. @property(assign) BOOL showsDivider; @end diff --git a/chrome/browser/cocoa/background_gradient_view.mm b/chrome/browser/cocoa/background_gradient_view.mm index de35705..96e3773 100644 --- a/chrome/browser/cocoa/background_gradient_view.mm +++ b/chrome/browser/cocoa/background_gradient_view.mm @@ -27,44 +27,31 @@ [self setNeedsDisplay:YES]; } -// The offset of this pattern to make it line up with the top of the window. -- (NSPoint)patternPhase { - NSPoint phase = NSZeroPoint; - phase.y += NSHeight([[self window] frame]) - kToolbarTopOffset; - return phase; -} - -- (void)drawRect:(NSRect)rect { +- (void)drawBackground { BOOL isKey = [[self window] isKeyWindow]; - - GTMTheme *theme = [self gtm_theme]; - - NSImage *backgroundImage = [theme backgroundImageForStyle:GTMThemeStyleToolBar - state:GTMThemeStateActiveWindow]; + GTMTheme* theme = [self gtm_theme]; + NSImage* backgroundImage = + [theme backgroundImageForStyle:GTMThemeStyleToolBar + state:GTMThemeStateActiveWindow]; if (backgroundImage) { - NSPoint phase = [self patternPhase]; - [[NSGraphicsContext currentContext] setPatternPhase:phase]; - - NSColor *color = [NSColor colorWithPatternImage:backgroundImage]; + NSColor* color = [NSColor colorWithPatternImage:backgroundImage]; [color set]; NSRectFill([self bounds]); } else { CGFloat winHeight = NSHeight([[self window] frame]); - NSGradient *gradient = [theme gradientForStyle:GTMThemeStyleToolBar + NSGradient* gradient = [theme gradientForStyle:GTMThemeStyleToolBar state:isKey]; NSPoint startPoint = [self convertPoint:NSMakePoint(0, winHeight - kToolbarTopOffset) fromView:nil]; NSPoint endPoint = - [self convertPoint:NSMakePoint(0, winHeight - - kToolbarTopOffset - - kToolbarMaxHeight) - fromView:nil]; + NSMakePoint(0, winHeight - kToolbarTopOffset - kToolbarMaxHeight); + endPoint = [self convertPoint:endPoint fromView:nil]; [gradient drawFromPoint:startPoint toPoint:endPoint - options:NSGradientDrawsBeforeStartingLocation | - NSGradientDrawsAfterEndingLocation]; + options:(NSGradientDrawsBeforeStartingLocation | + NSGradientDrawsAfterEndingLocation)]; } if (showsDivider_) { diff --git a/chrome/browser/cocoa/background_gradient_view_unittest.mm b/chrome/browser/cocoa/background_gradient_view_unittest.mm index 7b5e0c0..20ff6be 100644 --- a/chrome/browser/cocoa/background_gradient_view_unittest.mm +++ b/chrome/browser/cocoa/background_gradient_view_unittest.mm @@ -10,18 +10,29 @@ #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" +// Since BackgroundGradientView doesn't do any drawing by default, we +// create a subclass to call its draw method for us. +@interface BackgroundGradientSubClassTest : BackgroundGradientView +@end + +@implementation BackgroundGradientSubClassTest +- (void)drawRect:(NSRect)rect { + [self drawBackground]; +} +@end + namespace { class BackgroundGradientViewTest : public PlatformTest { public: BackgroundGradientViewTest() { NSRect frame = NSMakeRect(0, 0, 100, 30); - view_.reset([[BackgroundGradientView alloc] initWithFrame:frame]); + view_.reset([[BackgroundGradientSubClassTest alloc] initWithFrame:frame]); [cocoa_helper_.contentView() addSubview:view_.get()]; } CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc... - scoped_nsobject<BackgroundGradientView> view_; + scoped_nsobject<BackgroundGradientSubClassTest> view_; }; // Test adding/removing from the view hierarchy, mostly to ensure nothing diff --git a/chrome/browser/cocoa/browser_frame_view.h b/chrome/browser/cocoa/browser_frame_view.h new file mode 100644 index 0000000..277a96b --- /dev/null +++ b/chrome/browser/cocoa/browser_frame_view.h @@ -0,0 +1,52 @@ +// 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. + +#import <Cocoa/Cocoa.h> + +// BrowserFrameView is a class whose methods we swizzle into NSGrayFrame +// (an AppKit framework class) so that we can support custom frame drawing, and +// have the ability to move our window widgets (close, zoom, miniaturize) where +// we want them. +// This class is never to be instantiated on its own. +// We explored a variety of ways to support custom frame drawing and custom +// window widgets. +// Our requirements were: +// a) that we could fall back on standard system drawing at any time for the +// "default theme" +// b) We needed to be able to draw both a background pattern, and an overlay +// graphic, and we need to be able to set the pattern phase of our background +// window. +// c) We had to be able to support "transparent" themes, so that you could see +// through to the underlying windows in places without the system theme +// getting in the way. +// d) We had to support having the custom window controls moved down by a couple +// of pixels and rollovers, accessibility, etc. all had to work. +// +// Since we want "A" we couldn't just do a transparent borderless window. At +// least I couldn't find the right combination of HITheme calls to make it draw +// nicely, and I don't trust that the HITheme calls are going to exist in future +// system versions. +// "C" precluded us from inserting a view between the system frame and the +// the content frame in Z order. To get the transparency we actually need to +// replace the drawing of the system frame. +// "D" required us to override _mouseInGroup to get our custom widget rollovers +// drawing correctly. The widgets call _mouseInGroup on their superview to +// decide whether they should draw in highlight mode or not. +// "B" precluded us from just setting a background color on the window. +// +// Originally we tried overriding the private API +frameViewForStyleMask: to +// add our own subclass of NSGrayView to our window. Turns out that if you +// subclass NSGrayView it does not draw correctly when you call NSGrayView's +// drawRect. It appears that NSGrayView's drawRect: method (and that of its +// superclasses) do lots of "isMemberOfClass/isKindOfClass" calls, and if your +// class is NOT an instance of NSGrayView (as opposed to a subclass of +// NSGrayView) then the system drawing will not work correctly. +// +// Given all of the above, we found swizzling drawRect, and adding an +// implementation of _mouseInGroup and updateTrackingAreas, in _load to be the +// easiest and safest method of achieving our goals. We do the best we can to +// check that everything is safe, and attempt to fallback gracefully if it is +// not. +@interface BrowserFrameView : NSView +@end diff --git a/chrome/browser/cocoa/browser_frame_view.mm b/chrome/browser/cocoa/browser_frame_view.mm new file mode 100644 index 0000000..8ccc01e --- /dev/null +++ b/chrome/browser/cocoa/browser_frame_view.mm @@ -0,0 +1,176 @@ +// 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. + +#import "chrome/browser/cocoa/browser_frame_view.h" + +#import <objc/runtime.h> +#import <Carbon/Carbon.h> + +#include "base/logging.h" +#include "base/scoped_nsobject.h" +#import "chrome/browser/cocoa/chrome_browser_window.h" +#import "third_party/GTM/AppKit/GTMTheme.h" + +// To line up our background pattern with the patterns in the tabs we need +// to move our background patterns in the window frame up by two pixels. +// 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 NSInteger kBrowserFrameViewPatternPhaseOffset = 2; + +@interface NSView (Swizzles) +- (void)drawRectOriginal:(NSRect)rect; +- (BOOL)_mouseInGroup:(NSButton*)widget; +- (void)updateTrackingAreas; +@end + +@implementation BrowserFrameView + ++ (void)load { + // This is where we swizzle drawRect, and add in two methods that we + // need. If any of these fail it shouldn't affect the functionality of the + // others. If they all fail, we will lose window frame theming and + // roll overs for our close widgets, but things should still function + // correctly. + scoped_nsobject<NSAutoreleasePool> pool([[NSAutoreleasePool alloc] init]); + Class grayFrameClass = NSClassFromString(@"NSGrayFrame"); + DCHECK(grayFrameClass); + if (!grayFrameClass) return; + + // Exchange draw rect + Method m0 = class_getInstanceMethod([self class], @selector(drawRect:)); + DCHECK(m0); + if (m0) { + BOOL didAdd = class_addMethod(grayFrameClass, + @selector(drawRectOriginal:), + method_getImplementation(m0), + method_getTypeEncoding(m0)); + DCHECK(didAdd); + if (didAdd) { + Method m1 = class_getInstanceMethod(grayFrameClass, @selector(drawRect:)); + Method m2 = class_getInstanceMethod(grayFrameClass, + @selector(drawRectOriginal:)); + DCHECK(m1 && m2); + if (m1 && m2) { + method_exchangeImplementations(m1, m2); + } + } + } + + // Add _mouseInGroup + m0 = class_getInstanceMethod([self class], @selector(_mouseInGroup:)); + DCHECK(m0); + if (m0) { + BOOL didAdd = class_addMethod(grayFrameClass, + @selector(_mouseInGroup:), + method_getImplementation(m0), + method_getTypeEncoding(m0)); + DCHECK(didAdd); + } + // Add updateTrackingArea + m0 = class_getInstanceMethod([self class], @selector(updateTrackingAreas)); + DCHECK(m0); + if (m0) { + BOOL didAdd = class_addMethod(grayFrameClass, + @selector(updateTrackingAreas), + method_getImplementation(m0), + method_getTypeEncoding(m0)); + DCHECK(didAdd); + } +} + +- (id)initWithFrame:(NSRect)frame { + // This class is not for instantiating. + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (id)initWithCoder:(NSCoder*)coder { + // This class is not for instantiating. + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +// Here is our custom drawing for our frame. +- (void)drawRect:(NSRect)rect { + // If this isn't the window class we expect, then pass it on to the + // original implementation. + if (![[self window] isKindOfClass:[ChromeBrowserWindow class]]) { + [self drawRectOriginal:rect]; + return; + } + + // Clear out everything + [[NSColor clearColor] set]; + NSRectFillUsingOperation(rect, NSCompositeSourceOver); + + // Set up our clip + NSWindow* window = [self window]; + NSRect windowRect = [window frame]; + windowRect.origin = NSMakePoint(0, 0); + [[NSBezierPath bezierPathWithRoundedRect:windowRect + xRadius:4 + yRadius:4] addClip]; + [[NSBezierPath bezierPathWithRect:rect] addClip]; + + // Draw our background color if we have one, otherwise fall back on + // system drawing. + GTMTheme* theme = [self gtm_theme]; + GTMThemeState state = [window isMainWindow] ? GTMThemeStateActiveWindow + : GTMThemeStateInactiveWindow; + NSColor* color = [theme backgroundPatternColorForStyle:GTMThemeStyleWindow + state:state]; + if (color) { + // If we have a theme pattern, draw it here. + NSPoint phase = NSMakePoint(0, (NSHeight(windowRect) + + kBrowserFrameViewPatternPhaseOffset)); + [[NSGraphicsContext currentContext] setPatternPhase:phase]; + [color set]; + NSRectFill(rect); + } else { + [self drawRectOriginal:rect]; + } + + // Check to see if we have an overlay image. + NSImage* overlayImage = [theme valueForAttribute:@"overlay" + style:GTMThemeStyleWindow + state:state]; + if (overlayImage) { + NSSize overlaySize = [overlayImage size]; + NSRect windowFrame = NSMakeRect(0, + NSHeight(windowRect) - overlaySize.height, + NSWidth(windowRect), + overlaySize.height); + NSRect imageFrame = NSMakeRect(0, 0, overlaySize.width, overlaySize.height); + [overlayImage drawInRect:windowFrame + fromRect:imageFrame + operation:NSCompositeSourceOver + fraction:1.0]; + } +} + +// Check to see if the mouse is currently in one of our window widgets. +- (BOOL)_mouseInGroup:(NSButton*)widget { + BOOL mouseInGroup = NO; + if ([[self window] isKindOfClass:[ChromeBrowserWindow class]]) { + ChromeBrowserWindow* window = + static_cast<ChromeBrowserWindow*>([self window]); + mouseInGroup = [window mouseInGroup:widget]; + } else { + mouseInGroup = [super _mouseInGroup:widget]; + } + return mouseInGroup; +} + +// Let our window handle updating the window widget tracking area. +- (void)updateTrackingAreas { + [super updateTrackingAreas]; + if ([[self window] isKindOfClass:[ChromeBrowserWindow class]]) { + ChromeBrowserWindow* window = + static_cast<ChromeBrowserWindow*>([self window]); + [window updateTrackingAreas]; + } +} + +@end diff --git a/chrome/browser/cocoa/browser_frame_view_unittest.mm b/chrome/browser/cocoa/browser_frame_view_unittest.mm new file mode 100644 index 0000000..90d51c7 --- /dev/null +++ b/chrome/browser/cocoa/browser_frame_view_unittest.mm @@ -0,0 +1,48 @@ +// 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. + +#import <Cocoa/Cocoa.h> +#include <objc/runtime.h> + +#include "base/scoped_nsobject.h" +#import "chrome/browser/cocoa/browser_frame_view.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" + +class BrowserFrameViewTest : public PlatformTest { + public: + BrowserFrameViewTest() { + NSRect frame = NSMakeRect(0, 0, 50, 50); + // We create NSGrayFrame instead of BrowserFrameView because + // we are swizzling into NSGrayFrame. + Class browserFrameClass = NSClassFromString(@"NSGrayFrame"); + view_.reset([[browserFrameClass alloc] initWithFrame:frame]); + } + + scoped_nsobject<NSView> view_; +}; + +// Test to make sure our class modifications were successful. +TEST_F(BrowserFrameViewTest, SuccessfulClassModifications) { + unsigned int count; + BOOL foundMouseInGroup = NO; + BOOL foundDrawRectOriginal = NO; + BOOL foundUpdateTrackingAreas = NO; + + Method* methods = class_copyMethodList([view_ class], &count); + for (unsigned int i = 0; i < count; ++i) { + SEL selector = method_getName(methods[i]); + if (selector == @selector(_mouseInGroup:)) { + foundMouseInGroup = YES; + } else if (selector == @selector(drawRectOriginal:)) { + foundDrawRectOriginal = YES; + } else if (selector == @selector(updateTrackingAreas)) { + foundUpdateTrackingAreas = YES; + } + } + EXPECT_TRUE(foundMouseInGroup); + EXPECT_TRUE(foundDrawRectOriginal); + EXPECT_TRUE(foundUpdateTrackingAreas); + free(methods); +} diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm index b9562fa..7c37bbb 100644 --- a/chrome/browser/cocoa/browser_window_controller.mm +++ b/chrome/browser/cocoa/browser_window_controller.mm @@ -51,8 +51,8 @@ const int kWindowGradientHeight = 24; } @interface GTMTheme (BrowserThemeProviderInitialization) -+ (GTMTheme *)themeWithBrowserThemeProvider:(BrowserThemeProvider*)provider - isOffTheRecord:(BOOL)offTheRecord; ++ (GTMTheme*)themeWithBrowserThemeProvider:(BrowserThemeProvider*)provider + isOffTheRecord:(BOOL)offTheRecord; @end @interface NSWindow (NSPrivateApis) @@ -72,12 +72,6 @@ const int kWindowGradientHeight = 24; @interface BrowserWindowController(Private) -// Leopard's gradient heuristic gets confused by our tabs and makes the title -// gradient jump when creating a tab that is less than a tab width from the -// right side of the screen. This function disables Leopard's gradient -// heuristic. -- (void)fixWindowGradient; - // Saves the window's position in the local state preferences. - (void)saveWindowPositionIfNeeded; @@ -93,9 +87,6 @@ willPositionSheet:(NSWindow*)sheet // Assign a theme to the window. - (void)setTheme; -// Theme up the window. -- (void)applyTheme; - // Repositions the windows subviews. - (void)layoutSubviews; @@ -226,8 +217,6 @@ willPositionSheet:(NSWindow*)sheet [extensionShelfController_ wasInsertedIntoWindow]; } - [self fixWindowGradient]; - // Force a relayout of all the various bars. [self layoutSubviews]; @@ -338,11 +327,16 @@ willPositionSheet:(NSWindow*)sheet - (void)windowDidBecomeMain:(NSNotification*)notification { BrowserList::SetLastActive(browser_.get()); [self saveWindowPositionIfNeeded]; - [self applyTheme]; + + // 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]; } - (void)windowDidResignMain:(NSNotification*)notification { - [self applyTheme]; + // 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]; } // Called when we are activated (when we gain focus). @@ -534,7 +528,7 @@ willPositionSheet:(NSWindow*)sheet EncodingMenuController encoding_controller; if (encoding_controller.DoesCommandBelongToEncodingMenu(tag)) { DCHECK(browser_.get()); - Profile *profile = browser_->profile(); + Profile* profile = browser_->profile(); DCHECK(profile); TabContents* current_tab = browser_->GetSelectedTabContents(); if (!current_tab) { @@ -753,7 +747,7 @@ willPositionSheet:(NSWindow*)sheet return [tabStripController_ selectedTabView]; } -- (TabStripController *)tabStripController { +- (TabStripController*)tabStripController { return tabStripController_; } @@ -1022,13 +1016,35 @@ willPositionSheet:(NSWindow*)sheet - (void)userChangedTheme { [self setTheme]; - [self applyTheme]; + NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter postNotificationName:kGTMThemeDidChangeNotification + object:theme_]; + // 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]; } -- (GTMTheme *)gtm_themeForWindow:(NSWindow*)window { +- (GTMTheme*)gtm_themeForWindow:(NSWindow*)window { return theme_ ? theme_ : [GTMTheme defaultTheme]; } +- (NSPoint)gtm_themePatternPhaseForWindow:(NSWindow*)window { + // Our patterns want to be drawn from the upper left hand corner of the view. + // Cocoa wants to do it from the lower left of the window. + // Rephase our pattern to fit this view. Some other views (Tabs, Toolbar etc.) + // will phase their patterns relative to this so all the views look right. + NSView* tabStripView = [self tabStripView]; + NSRect tabStripViewWindowBounds = [tabStripView bounds]; + NSView* windowChromeView = [[window contentView] superview]; + tabStripViewWindowBounds = + [tabStripView convertRect:tabStripViewWindowBounds + toView:windowChromeView]; + NSPoint phase = NSMakePoint(NSMinX(tabStripViewWindowBounds), + NSMinY(tabStripViewWindowBounds) + + [TabStripController defaultTabHeight]); + return phase; +} + - (NSPoint)topLeftForBubble { NSRect rect = [toolbarController_ starButtonInWindowCoordinates]; NSPoint p = NSMakePoint(NSMinX(rect), NSMinY(rect)); // bottom left @@ -1134,17 +1150,6 @@ willPositionSheet:(NSWindow*)sheet [[[[self window] contentView] superview] addSubview:incognitoView.get()]; } -- (void)fixWindowGradient { - NSWindow* win = [self window]; - if ([win respondsToSelector:@selector( - setAutorecalculatesContentBorderThickness:forEdge:)] && - [win respondsToSelector:@selector( - setContentBorderThickness:forEdge:)]) { - [win setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge]; - [win setContentBorderThickness:kWindowGradientHeight forEdge:NSMaxYEdge]; - } -} - - (void)saveWindowPositionIfNeeded { if (browser_ != BrowserList::GetLastActive()) return; @@ -1215,22 +1220,17 @@ willPositionSheet:(NSWindow*)sheet - (void)setTheme { ThemeProvider* theme_provider = browser_->profile()->GetThemeProvider(); - if (theme_provider) { - GTMTheme *theme = [GTMTheme themeWithBrowserThemeProvider: - (BrowserThemeProvider *)theme_provider - isOffTheRecord:browser_->profile()->IsOffTheRecord()]; + 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)applyTheme { - NSColor* color = - [theme_ backgroundPatternColorForStyle:GTMThemeStyleWindow - state:[[self window] isMainWindow]]; - [[self window] setBackgroundColor:color]; - [tabStripController_ applyTheme]; -} - // Private method to layout browser window subviews. Positions the toolbar and // the infobar above the tab content area. Positions the download shelf below // the tab content area. If the toolbar is not a child of the contentview, this @@ -1349,8 +1349,8 @@ willPositionSheet:(NSWindow*)sheet @end @implementation GTMTheme (BrowserThemeProviderInitialization) -+ (GTMTheme *)themeWithBrowserThemeProvider:(BrowserThemeProvider*)provider - isOffTheRecord:(BOOL)isOffTheRecord { ++ (GTMTheme*)themeWithBrowserThemeProvider:(BrowserThemeProvider*)provider + isOffTheRecord:(BOOL)isOffTheRecord { // First check if it's in the cache. // TODO(pinkerton): This might be a good candidate for a singleton. typedef std::pair<std::string, BOOL> ThemeKey; @@ -1375,7 +1375,7 @@ willPositionSheet:(NSWindow*)sheet [theme setBackgroundColor:incognitoColor]; [theme setValue:[NSColor blackColor] forAttribute:@"textColor" - style:GTMThemeStyleToolBar + style:GTMThemeStyleTabBarSelected state:GTMThemeStateActiveWindow]; [theme setValue:[NSColor blackColor] forAttribute:@"textColor" @@ -1401,7 +1401,7 @@ willPositionSheet:(NSWindow*)sheet provider->GetNSColor(BrowserThemeProvider::COLOR_TAB_TEXT); [theme setValue:tabTextColor forAttribute:@"textColor" - style:GTMThemeStyleToolBar + style:GTMThemeStyleTabBarSelected state:GTMThemeStateActiveWindow]; NSColor* tabInactiveTextColor = @@ -1480,7 +1480,24 @@ willPositionSheet:(NSWindow*)sheet style:GTMThemeStyleToolBar state:GTMThemeStateActiveWindow]; + NSImage* frameOverlayImage = + provider->GetNSImageNamed(IDR_THEME_FRAME_OVERLAY); + if (frameOverlayImage) { + [theme setValue:frameOverlayImage + forAttribute:@"overlay" + style:GTMThemeStyleWindow + state:GTMThemeStateActiveWindow]; + } + + NSImage* frameOverlayInactiveImage = + provider->GetNSImageNamed(IDR_THEME_FRAME_OVERLAY_INACTIVE); + if (frameOverlayInactiveImage) { + [theme setValue:frameOverlayInactiveImage + forAttribute:@"overlay" + style:GTMThemeStyleWindow + state:GTMThemeStateInactiveWindow]; + } + return theme; } @end - diff --git a/chrome/browser/cocoa/bubble_view.mm b/chrome/browser/cocoa/bubble_view.mm index 012e930..32159001 100644 --- a/chrome/browser/cocoa/bubble_view.mm +++ b/chrome/browser/cocoa/bubble_view.mm @@ -102,7 +102,7 @@ const float kWindowEdge = 0.7f; [border stroke]; // Text - NSColor* textColor = [theme textColorForStyle:GTMThemeStyleToolBar + NSColor* textColor = [theme textColorForStyle:GTMThemeStyleTabBarSelected state:GTMThemeStateActiveWindow]; NSFont* textFont = [self font]; scoped_nsobject<NSShadow> textShadow([[NSShadow alloc] init]); diff --git a/chrome/browser/cocoa/chrome_browser_window.h b/chrome/browser/cocoa/chrome_browser_window.h index 9130616..c25b489 100644 --- a/chrome/browser/cocoa/chrome_browser_window.h +++ b/chrome/browser/cocoa/chrome_browser_window.h @@ -7,12 +7,31 @@ #import <Cocoa/Cocoa.h> +#include "base/scoped_nsobject.h" + +// Offset from the top of the window frame to the top of the window controls +// (zoom, close, miniaturize). +const NSInteger kChromeWindowButtonsOffsetFromTop = 7; + +// Offset from the left of the window frame to the top of the window controls +// (zoom, close, miniaturize). +const NSInteger kChromeWindowButtonsOffsetFromLeft = 8; + +// Offset between the window controls (zoom, close, miniaturize). +const NSInteger kChromeWindowButtonsInterButtonSpacing = 7; + // Cocoa class representing a Chrome browser window. // We need to override NSWindow with our own class since we need access to all // unhandled keyboard events and subclassing NSWindow is the only method to do -// this. +// this. We also handle our own window controls and custom window frame drawing. @interface ChromeBrowserWindow : NSWindow { + @private BOOL shouldHideTitle_; + NSButton* closeButton_; + NSButton* miniaturizeButton_; + NSButton* zoomButton_; + BOOL entered_; + scoped_nsobject<NSTrackingArea> widgetTrackingArea_; } // See global_keyboard_shortcuts_mac.h for details on the next two functions. @@ -31,6 +50,12 @@ // Tells the window to suppress title drawing. - (void)setShouldHideTitle:(BOOL)flag; +// Return true if the mouse is currently in our tracking area for our window +// widgets. +- (BOOL)mouseInGroup:(NSButton*)widget; + +// Update the tracking areas for our window widgets as appropriate. +- (void)updateTrackingAreas; @end @interface ChromeBrowserWindow (UndocumentedAPI) diff --git a/chrome/browser/cocoa/chrome_browser_window.mm b/chrome/browser/cocoa/chrome_browser_window.mm index a6df8d5..6786cda 100644 --- a/chrome/browser/cocoa/chrome_browser_window.mm +++ b/chrome/browser/cocoa/chrome_browser_window.mm @@ -6,12 +6,261 @@ #include "base/logging.h" #import "chrome/browser/cocoa/browser_window_controller.h" +#import "chrome/browser/cocoa/browser_frame_view.h" +#import "chrome/browser/cocoa/tab_strip_controller.h" #import "chrome/browser/renderer_host/render_widget_host_view_mac.h" #include "chrome/browser/global_keyboard_shortcuts_mac.h" +// Our browser window does some interesting things to get the behaviors that +// we want. We replace the standard window controls (zoom, close, miniaturize) +// with our own versions, so that we can position them slightly differently than +// the default window has them. To do this, we hide the ones that Apple provides +// us with, and create our own. This requires us to handle tracking for the +// buttons (so that they highlight and activate correctly) as well as implement +// the private method _mouseInGroup in our frame view class which is required +// to get the rollover highlight drawing to draw correctly. +@interface ChromeBrowserWindow(ChromeBrowserWindowPrivateMethods) +// Return the view that does the "frame" drawing. +- (NSView*)frameView; +@end + typedef int (*KeyToCommandMapper)(bool, bool, bool, int); @implementation ChromeBrowserWindow +- (id)initWithContentRect:(NSRect)contentRect + styleMask:(NSUInteger)aStyle + backing:(NSBackingStoreType)bufferingType + defer:(BOOL)flag { + if ((self = [super initWithContentRect:contentRect + styleMask:aStyle + backing:bufferingType + defer:flag])) { + NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter addObserver:self + selector:@selector(themeDidChangeNotification:) + name:kGTMThemeDidChangeNotification + object:nil]; + + // Hook ourselves up to get notified if the user changes the system + // theme on us. + NSDistributedNotificationCenter* distCenter = + [NSDistributedNotificationCenter defaultCenter]; + [distCenter addObserver:self + selector:@selector(systemThemeDidChangeNotification:) + name:@"AppleAquaColorVariantChanged" + object:nil]; + [self setOpaque:NO]; + // Set up our buttons how we like them. + NSView* frameView = [self frameView]; + NSRect frameViewBounds = [frameView bounds]; + + // Find all the "original" buttons, and hide them. We can't use the original + // buttons because the OS likes to move them around when we resize windows + // and will put them back in what it considers to be their "preferred" + // locations. + NSButton* oldButton = [self standardWindowButton:NSWindowCloseButton]; + [oldButton setHidden:YES]; + oldButton = [self standardWindowButton:NSWindowMiniaturizeButton]; + [oldButton setHidden:YES]; + oldButton = [self standardWindowButton:NSWindowZoomButton]; + [oldButton setHidden:YES]; + + // Create and position our new buttons. + closeButton_ = [NSWindow standardWindowButton:NSWindowCloseButton + forStyleMask:aStyle]; + NSRect closeButtonFrame = [closeButton_ frame]; + closeButtonFrame.origin = + NSMakePoint(kChromeWindowButtonsOffsetFromLeft, + (NSHeight(frameViewBounds) - + NSHeight(closeButtonFrame) - + kChromeWindowButtonsOffsetFromTop)); + [closeButton_ setFrame:closeButtonFrame]; + [closeButton_ setTarget:self]; + [closeButton_ setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; + [frameView addSubview:closeButton_]; + + miniaturizeButton_ = + [NSWindow standardWindowButton:NSWindowMiniaturizeButton + forStyleMask:aStyle]; + NSRect miniaturizeButtonFrame = [miniaturizeButton_ frame]; + miniaturizeButtonFrame.origin = + NSMakePoint((NSMaxX(closeButtonFrame) + + kChromeWindowButtonsInterButtonSpacing), + NSMinY(closeButtonFrame)); + [miniaturizeButton_ setFrame:miniaturizeButtonFrame]; + [miniaturizeButton_ setTarget:self]; + [miniaturizeButton_ setAutoresizingMask:(NSViewMaxXMargin | + NSViewMinYMargin)]; + [frameView addSubview:miniaturizeButton_]; + + zoomButton_ = [NSWindow standardWindowButton:NSWindowZoomButton + forStyleMask:aStyle]; + NSRect zoomButtonFrame = [zoomButton_ frame]; + zoomButtonFrame.origin = + NSMakePoint((NSMaxX(miniaturizeButtonFrame) + + kChromeWindowButtonsInterButtonSpacing), + NSMinY(miniaturizeButtonFrame)); + [zoomButton_ setFrame:zoomButtonFrame]; + [zoomButton_ setTarget:self]; + [zoomButton_ setAutoresizingMask:(NSViewMaxXMargin | + NSViewMinYMargin)]; + + [frameView addSubview:zoomButton_]; + [self updateTrackingAreas]; + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; + [super dealloc]; +} + +- (NSView*)frameView { + return [[self contentView] superview]; +} + +// The tab strip view covers our window buttons. So we add hit testing here +// to find them properly and return them to the accessibility system. +- (id)accessibilityHitTest:(NSPoint)point { + NSPoint windowPoint = [self convertScreenToBase:point]; + NSControl* controls[] = { closeButton_, zoomButton_, miniaturizeButton_ }; + id value = nil; + for (size_t i = 0; i < sizeof(controls) / sizeof(controls[0]); ++i) { + if (NSPointInRect(windowPoint, [controls[i] frame])) { + value = [controls[i] accessibilityHitTest:point]; + break; + } + } + if (!value) { + value = [super accessibilityHitTest:point]; + } + return value; +} + +// Map our custom buttons into the accessibility hierarchy correctly. +- (id)accessibilityAttributeValue:(NSString*)attribute { + id value = nil; + struct { + NSString* attribute_; + id value_; + } attributeMap[] = { + { NSAccessibilityCloseButtonAttribute, [closeButton_ cell]}, + { NSAccessibilityZoomButtonAttribute, [zoomButton_ cell]}, + { NSAccessibilityMinimizeButtonAttribute, [miniaturizeButton_ cell]}, + }; + + for (size_t i = 0; i < sizeof(attributeMap) / sizeof(attributeMap[0]); ++i) { + if ([attributeMap[i].attribute_ isEqualToString:attribute]) { + value = attributeMap[i].value_; + break; + } + } + if (!value) { + value = [super accessibilityAttributeValue:attribute]; + } + return value; +} + +- (void)updateTrackingAreas { + NSView* frameView = [self frameView]; + if (widgetTrackingArea_) { + [frameView removeTrackingArea:widgetTrackingArea_]; + } + NSRect trackingRect = [closeButton_ frame]; + trackingRect.size.width = NSMaxX([zoomButton_ frame]) - NSMinX(trackingRect); + widgetTrackingArea_.reset( + [[NSTrackingArea alloc] initWithRect:trackingRect + options:(NSTrackingMouseEnteredAndExited | + NSTrackingActiveAlways) + owner:self + userInfo:nil]); + [frameView addTrackingArea:widgetTrackingArea_]; +} + +- (void)windowMainStatusChanged { + [closeButton_ setNeedsDisplay]; + [zoomButton_ setNeedsDisplay]; + [miniaturizeButton_ setNeedsDisplay]; + NSView* frameView = [self frameView]; + NSView* contentView = [self contentView]; + NSRect updateRect = [frameView frame]; + NSRect contentRect = [contentView frame]; + CGFloat tabStripHeight = [TabStripController defaultTabHeight]; + updateRect.size.height -= NSHeight(contentRect) - tabStripHeight; + updateRect.origin.y = NSMaxY(contentRect) - tabStripHeight; + [[self frameView] setNeedsDisplayInRect:updateRect]; +} + +- (void)becomeMainWindow { + [self windowMainStatusChanged]; + [super becomeMainWindow]; +} + +- (void)resignMainWindow { + [self windowMainStatusChanged]; + [super resignMainWindow]; +} + +- (void)themeDidChangeNotification:(NSNotification*)aNotification { + GTMTheme* theme = [aNotification object]; + if ([theme isEqual:[self gtm_theme]]) { + [[self frameView] setNeedsDisplay:YES]; + } +} + +- (void)systemThemeDidChangeNotification:(NSNotification*)aNotification { + [closeButton_ setNeedsDisplay]; + [zoomButton_ setNeedsDisplay]; + [miniaturizeButton_ setNeedsDisplay]; +} + +- (void)sendEvent:(NSEvent*)event { + // For cocoa windows, clicking on the close and the miniaturize (but not the + // zoom buttons) while a window is in the background does NOT bring that + // window to the front. We don't get that behavior for free, so we handle + // it here. Zoom buttons do bring the window to the front. Note that + // Finder windows (in Leopard) behave differently in this regard in that + // zoom buttons don't bring the window to the foreground. + BOOL eventHandled = NO; + if (![self isMainWindow]) { + if ([event type] == NSLeftMouseDown) { + NSView* frameView = [self frameView]; + NSPoint mouse = [frameView convertPointFromBase:[event locationInWindow]]; + if (NSPointInRect(mouse, [closeButton_ frame])) { + [closeButton_ mouseDown:event]; + eventHandled = YES; + } else if (NSPointInRect(mouse, [miniaturizeButton_ frame])) { + [miniaturizeButton_ mouseDown:event]; + eventHandled = YES; + } + } + } + if (!eventHandled) { + [super sendEvent:event]; + } +} + +// Update our buttons so that they highlight correctly. +- (void)mouseEntered:(NSEvent*)event { + entered_ = YES; + [closeButton_ setNeedsDisplay]; + [zoomButton_ setNeedsDisplay]; + [miniaturizeButton_ setNeedsDisplay]; +} + +// Update our buttons so that they highlight correctly. +- (void)mouseExited:(NSEvent*)event { + entered_ = NO; + [closeButton_ setNeedsDisplay]; + [zoomButton_ setNeedsDisplay]; + [miniaturizeButton_ setNeedsDisplay]; +} + +- (BOOL)mouseInGroup:(NSButton*)widget { + return entered_; +} - (BOOL)handleExtraKeyboardShortcut:(NSEvent*)event fromTable: (KeyToCommandMapper)commandForKeyboardShortcut { diff --git a/chrome/browser/cocoa/chrome_browser_window_unittest.mm b/chrome/browser/cocoa/chrome_browser_window_unittest.mm index e531e43..77986df 100644 --- a/chrome/browser/cocoa/chrome_browser_window_unittest.mm +++ b/chrome/browser/cocoa/chrome_browser_window_unittest.mm @@ -8,6 +8,7 @@ #include "chrome/app/chrome_dll_resource.h" #import "chrome/browser/cocoa/chrome_browser_window.h" #import "chrome/browser/cocoa/browser_window_controller.h" +#import "chrome/browser/cocoa/browser_frame_view.h" #import "chrome/browser/cocoa/cocoa_test_helper.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -73,7 +74,7 @@ TEST_F(ChromeBrowserWindowTest, ShowAndClose) { // forwards it to [delegate executeCommand:]. Assume that other // CommandForKeyboardShortcut() will work the same for the rest. TEST_F(ChromeBrowserWindowTest, PerformKeyEquivalentForwardToExecuteCommand) { - NSEvent *event = KeyEvent(NSCommandKeyMask, kVK_ANSI_1); + NSEvent* event = KeyEvent(NSCommandKeyMask, kVK_ANSI_1); id delegate = [OCMockObject mockForClass:[BrowserWindowController class]]; // -stub to satisfy the DCHECK. @@ -95,7 +96,7 @@ TEST_F(ChromeBrowserWindowTest, PerformKeyEquivalentForwardToExecuteCommand) { // TODO(shess) Think of a way to test that it is sent to the // superclass. TEST_F(ChromeBrowserWindowTest, PerformKeyEquivalentNoForward) { - NSEvent *event = KeyEvent(0, 0); + NSEvent* event = KeyEvent(0, 0); id delegate = [OCMockObject mockForClass:[BrowserWindowController class]]; // -stub to satisfy the DCHECK. @@ -142,4 +143,50 @@ TEST_F(ChromeBrowserWindowTest, DoesHideTitle) { EXPECT_TRUE([emptyTitleData isEqualToData:hiddenTitleData]); } +// Test to make sure that our window widgets are in the right place. +TEST_F(ChromeBrowserWindowTest, WindowWidgetLocation) { + NSCell* closeBoxCell = [window_ accessibilityAttributeValue: + NSAccessibilityCloseButtonAttribute]; + NSView* closeBoxControl = [closeBoxCell controlView]; + EXPECT_TRUE(closeBoxControl); + NSRect closeBoxFrame = [closeBoxControl frame]; + NSRect windowBounds = [window_ frame]; + windowBounds.origin = NSZeroPoint; + EXPECT_EQ(NSMaxY(closeBoxFrame), + NSMaxY(windowBounds) - kChromeWindowButtonsOffsetFromTop); + EXPECT_EQ(NSMinX(closeBoxFrame), kChromeWindowButtonsOffsetFromLeft); + + NSCell* miniaturizeCell = [window_ accessibilityAttributeValue: + NSAccessibilityMinimizeButtonAttribute]; + NSView* miniaturizeControl = [miniaturizeCell controlView]; + EXPECT_TRUE(miniaturizeControl); + NSRect miniaturizeFrame = [miniaturizeControl frame]; + EXPECT_EQ(NSMaxY(miniaturizeFrame), + NSMaxY(windowBounds) - kChromeWindowButtonsOffsetFromTop); + EXPECT_EQ(NSMinX(miniaturizeFrame), + NSMaxX(closeBoxFrame) + kChromeWindowButtonsInterButtonSpacing); +} + +// Test that we actually have a tracking area in place. +TEST_F(ChromeBrowserWindowTest, WindowWidgetTrackingArea) { + NSCell* closeBoxCell = [window_ accessibilityAttributeValue: + NSAccessibilityCloseButtonAttribute]; + NSView* closeBoxControl = [closeBoxCell controlView]; + NSView* frameView = [[window_ contentView] superview]; + NSArray* trackingAreas = [frameView trackingAreas]; + NSPoint point = [closeBoxControl frame].origin; + point.x += 1; + point.y += 1; + BOOL foundArea = NO; + for (NSTrackingArea* area in trackingAreas) { + NSRect rect = [area rect]; + foundArea = NSPointInRect(point, rect); + if (foundArea) { + EXPECT_TRUE([[area owner] isEqual:window_]); + break; + } + } + EXPECT_TRUE(foundArea); +} + } // namespace diff --git a/chrome/browser/cocoa/download_shelf_view.mm b/chrome/browser/cocoa/download_shelf_view.mm index 4d12529..1dcc562 100644 --- a/chrome/browser/cocoa/download_shelf_view.mm +++ b/chrome/browser/cocoa/download_shelf_view.mm @@ -17,17 +17,20 @@ - (void)drawRect:(NSRect)rect { BOOL isKey = [[self window] isKeyWindow]; - GTMTheme *theme = [self gtm_theme]; + GTMTheme* theme = [self gtm_theme]; - NSImage *backgroundImage = [theme backgroundImageForStyle:GTMThemeStyleToolBar + NSImage* backgroundImage = [theme backgroundImageForStyle:GTMThemeStyleToolBar state:GTMThemeStateActiveWindow]; if (backgroundImage) { - [[NSGraphicsContext currentContext] setPatternPhase:NSZeroPoint]; - NSColor *color = [NSColor colorWithPatternImage:backgroundImage]; + // We want our backgrounds for the shelf to be phased from the upper + // left hand corner of the view. + NSPoint phase = NSMakePoint(0, NSHeight([self bounds])); + [[NSGraphicsContext currentContext] setPatternPhase:phase]; + NSColor* color = [NSColor colorWithPatternImage:backgroundImage]; [color set]; NSRectFill([self bounds]); } else { - NSGradient *gradient = [theme gradientForStyle:GTMThemeStyleToolBar + NSGradient* gradient = [theme gradientForStyle:GTMThemeStyleToolBar state:isKey]; NSPoint startPoint = [self convertPointFromBase:NSMakePoint(0, 0)]; NSPoint endPoint = [self convertPointFromBase: diff --git a/chrome/browser/cocoa/find_bar_view.mm b/chrome/browser/cocoa/find_bar_view.mm index 238884d..259d59d 100644 --- a/chrome/browser/cocoa/find_bar_view.mm +++ b/chrome/browser/cocoa/find_bar_view.mm @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/cocoa/find_bar_view.h" +#import "chrome/browser/cocoa/find_bar_view.h" @implementation FindBarView @@ -27,7 +27,7 @@ NSPoint bottomRight = NSMakePoint(NSMaxX(rect) - (2 * curveSize), NSMinY(rect)); - NSBezierPath *path = [NSBezierPath bezierPath]; + NSBezierPath* path = [NSBezierPath bezierPath]; [path moveToPoint:topLeft]; [path curveToPoint:midLeft1 controlPoint1:NSMakePoint(midLeft1.x, topLeft.y) @@ -45,11 +45,16 @@ [path curveToPoint:topRight controlPoint1:NSMakePoint(midRight2.x, topLeft.y) controlPoint2:NSMakePoint(midRight2.x, topLeft.y)]; - - [NSGraphicsContext saveGraphicsState]; + NSGraphicsContext* context = [NSGraphicsContext currentContext]; + [context saveGraphicsState]; [path addClip]; - [super drawRect:rect]; - [NSGraphicsContext restoreGraphicsState]; + + // Set the pattern phase + NSPoint phase = [self gtm_themePatternPhase]; + + [context setPatternPhase:phase]; + [super drawBackground]; + [context restoreGraphicsState]; [[self strokeColor] set]; [path stroke]; diff --git a/chrome/browser/cocoa/status_bubble_mac_unittest.mm b/chrome/browser/cocoa/status_bubble_mac_unittest.mm index d462f0d..8d5681b 100644 --- a/chrome/browser/cocoa/status_bubble_mac_unittest.mm +++ b/chrome/browser/cocoa/status_bubble_mac_unittest.mm @@ -16,9 +16,13 @@ @interface StatusBubbleMacTestWindowDelegate : NSObject <GTMThemeDelegate>; @end @implementation StatusBubbleMacTestWindowDelegate -- (GTMTheme *)gtm_themeForWindow:(NSWindow *)window { +- (GTMTheme*)gtm_themeForWindow:(NSWindow*)window { return [[[GTMTheme alloc] init] autorelease]; } + +- (NSPoint)gtm_themePatternPhaseForWindow:(NSWindow*)window { + return NSZeroPoint; +} @end class StatusBubbleMacTest : public PlatformTest { diff --git a/chrome/browser/cocoa/tab_cell.h b/chrome/browser/cocoa/tab_cell.h index 0f0ff0f..e69de29 100644 --- a/chrome/browser/cocoa/tab_cell.h +++ b/chrome/browser/cocoa/tab_cell.h @@ -1,20 +0,0 @@ -// 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. - -#ifndef CHROME_BROWSER_COCOA_TAB_CELL_H_ -#define CHROME_BROWSER_COCOA_TAB_CELL_H_ - -#import <Cocoa/Cocoa.h> - -// A button cell that handles drawing/highlighting of tabs in the tab bar. Text -// drawing leaves room for an icon view on the left of the tab and a close -// button on the right. Technically, though, it doesn't know anything about what -// it's leaving space for, so they could be reversed or even replaced by views -// for other purposes. - -@interface TabCell : NSButtonCell { -} -@end - -#endif // CHROME_BROWSER_COCOA_TAB_CELL_H_ diff --git a/chrome/browser/cocoa/tab_cell.mm b/chrome/browser/cocoa/tab_cell.mm index 6e2c22c..e69de29 100644 --- a/chrome/browser/cocoa/tab_cell.mm +++ b/chrome/browser/cocoa/tab_cell.mm @@ -1,76 +0,0 @@ -// 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. - -#import "base/scoped_nsobject.h" -#import "chrome/browser/cocoa/tab_cell.h" -#import "third_party/GTM/AppKit/GTMTheme.h" -#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h" - - -@implementation TabCell - -- (id)initTextCell:(NSString *)aString { - self = [super initTextCell:aString]; - if (self != nil) { - // nothing for now... - } - return self; -} - -- (NSBackgroundStyle)interiorBackgroundStyle { - return [[[self controlView] gtm_theme] - interiorBackgroundStyleForStyle:GTMThemeStyleToolBar - state:GTMThemeStateActiveWindow]; -} - -// Override drawing the button so that it looks like a Chromium tab instead -// of just a normal MacOS button. -- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { - // Inset where the text is drawn to keep it away from the sloping edges of the - // tab, the close box, and the icon view. These constants are derived - // empirically as the cell doesn't know about the surrounding view objects. - // TODO(pinkerton/alcor): Fix this somehow? - const int kIconXOffset = 28; - const int kCloseBoxXOffset = 21; - NSRect frame = NSOffsetRect(cellFrame, kIconXOffset, 0); - frame.size.width -= kCloseBoxXOffset + kIconXOffset; - [self drawInteriorWithFrame:frame - inView:controlView]; -} - -- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { - GTMTheme* theme = [[self controlView] gtm_theme]; - NSColor* textColor = [theme textColorForStyle:GTMThemeStyleToolBar - state:[self isHighlighted]]; - - scoped_nsobject<NSShadow> textShadow([[NSShadow alloc] init]); - [textShadow setShadowBlurRadius:0.0f]; - [textShadow.get() setShadowColor:[textColor gtm_legibleTextColor]]; - [textShadow.get() setShadowOffset:NSMakeSize(0.0f, -1.0f)]; - - NSDictionary* attributes = - [NSDictionary dictionaryWithObjectsAndKeys: - [self font], NSFontAttributeName, - textColor, NSForegroundColorAttributeName, - textShadow.get(), NSShadowAttributeName, - nil]; - - [[self title] drawInRect:[self titleRectForBounds:cellFrame] - withAttributes:attributes]; - - NSRect imageBounds = NSZeroRect; - imageBounds.size = [[self image] size]; - [[self image] drawInRect:[self imageRectForBounds:cellFrame] - fromRect:imageBounds - operation:NSCompositeSourceOver - fraction:1.0]; -} - -- (void)highlight:(BOOL)flag - withFrame:(NSRect)cellFrame - inView:(NSView *)controlView { - // Don't do normal highlighting -} - -@end diff --git a/chrome/browser/cocoa/tab_cell_unittest.mm b/chrome/browser/cocoa/tab_cell_unittest.mm index 9eb29fc..e69de29 100644 --- a/chrome/browser/cocoa/tab_cell_unittest.mm +++ b/chrome/browser/cocoa/tab_cell_unittest.mm @@ -1,42 +0,0 @@ -// 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. - -#import <Cocoa/Cocoa.h> - -#include "base/scoped_nsobject.h" -#import "chrome/browser/cocoa/tab_cell.h" -#import "chrome/browser/cocoa/cocoa_test_helper.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -namespace { - -class TabCellTest : public PlatformTest { - public: - TabCellTest() { - NSRect frame = NSMakeRect(0, 0, 50, 30); - view_.reset([[NSButton alloc] initWithFrame:frame]); - scoped_nsobject<TabCell> cell([[TabCell alloc] initTextCell:@"Testing"]); - [view_ setCell:cell.get()]; - [cocoa_helper_.contentView() addSubview:view_.get()]; - } - - CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc... - scoped_nsobject<NSButton> view_; -}; - -// Test adding/removing from the view hierarchy, mostly to ensure nothing -// leaks or crashes. -TEST_F(TabCellTest, AddRemove) { - EXPECT_EQ(cocoa_helper_.contentView(), [view_ superview]); - [view_.get() removeFromSuperview]; - EXPECT_FALSE([view_ superview]); -} - -// Test drawing, mostly to ensure nothing leaks or crashes. -TEST_F(TabCellTest, Display) { - [view_ display]; -} - -} // namespace diff --git a/chrome/browser/cocoa/tab_controller.h b/chrome/browser/cocoa/tab_controller.h index 7d44751..1bc9300 100644 --- a/chrome/browser/cocoa/tab_controller.h +++ b/chrome/browser/cocoa/tab_controller.h @@ -64,7 +64,7 @@ enum TabLoadingState { + (float)minSelectedTabWidth; // The view associated with this controller, pre-casted as a TabView -- (TabView *)tabView; +- (TabView*)tabView; // Closes the associated TabView by relaying the message to |target_| to // perform the close. @@ -78,18 +78,17 @@ enum TabLoadingState { - (void)setIconView:(NSView*)iconView; - (NSView*)iconView; -// (Re)apply the current theme. -- (void)applyTheme; - // Called by the tabs to determine whether we are in rapid (tab) closure mode. // In this mode, we handle clicks slightly differently due to animation. // Ideally, tabs would know about their own animation and wouldn't need this. - (BOOL)inRapidClosureMode; +// Update the title color to match the tabs current state. +- (void)updateTitleColor; @end @interface TabController(TestingAPI) -- (NSString *)toolTip; +- (NSString*)toolTip; - (int)iconCapacity; - (BOOL)shouldShowIcon; - (BOOL)shouldShowCloseButton; diff --git a/chrome/browser/cocoa/tab_controller.mm b/chrome/browser/cocoa/tab_controller.mm index 64207f9..94de7cfc 100644 --- a/chrome/browser/cocoa/tab_controller.mm +++ b/chrome/browser/cocoa/tab_controller.mm @@ -33,11 +33,15 @@ self = [super initWithNibName:@"TabView" bundle:mac_util::MainAppBundle()]; if (self != nil) { isIconShowing_ = YES; - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(viewResized:) - name:NSViewFrameDidChangeNotification - object:[self view]]; + NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter addObserver:self + selector:@selector(viewResized:) + name:NSViewFrameDidChangeNotification + object:[self view]]; + [defaultCenter addObserver:self + selector:@selector(themeChangedNotification:) + name:kGTMThemeDidChangeNotification + object:nil]; } return self; } @@ -52,9 +56,10 @@ // mark ourselves as needing a redraw. - (void)internalSetSelected:(BOOL)selected { selected_ = selected; - [(TabView *)[self view] setState:selected]; + TabView* tabView = static_cast<TabView*>([self view]); + [tabView setState:selected]; [self updateVisibility]; - [self applyTheme]; + [self updateTitleColor]; } // Called when the tab's nib is done loading and all outlets are hooked up. @@ -71,9 +76,6 @@ iconTitleXOffset_ = NSMinX(titleFrame) - NSMinX(originalIconFrame_); titleCloseWidthOffset_ = NSMaxX([closeButton_ frame]) - NSMaxX(titleFrame); - // Ensure we don't show favicon if the tab is already too small to begin with. - [self updateVisibility]; - [self internalSetSelected:selected_]; } @@ -100,7 +102,7 @@ return [[self target] isCommandEnabled:command forController:self]; } -- (void)setTitle:(NSString *)title { +- (void)setTitle:(NSString*)title { [[self view] setToolTip:title]; [super setTitle:title]; } @@ -131,7 +133,7 @@ return iconView_; } -- (NSString *)toolTip { +- (NSString*)toolTip { return [[self view] toolTip]; } @@ -212,6 +214,21 @@ [titleView_ setFrame:titleFrame]; } +- (void)updateTitleColor { + NSColor* titleColor = nil; + GTMTheme* theme = [[self view] gtm_theme]; + if (![self selected]) { + titleColor = [theme textColorForStyle:GTMThemeStyleTabBarDeselected + state:GTMThemeStateActiveWindow]; + } + // Default to the selected text color unless told otherwise. + if (!titleColor) { + titleColor = [theme textColorForStyle:GTMThemeStyleTabBarSelected + state:GTMThemeStateActiveWindow]; + } + [titleView_ setTextColor:titleColor ? titleColor : [NSColor textColor]]; +} + // Called when our view is resized. If it gets too small, start by hiding // the close button and only show it if tab is selected. Eventually, hide the // icon as well. We know that this is for our view because we only registered @@ -220,21 +237,12 @@ [self updateVisibility]; } -- (void)applyTheme { - GTMTheme* theme = [[self view] gtm_theme]; - NSColor* color = nil; - if (!selected_) { - color = [theme textColorForStyle:GTMThemeStyleTabBarDeselected - state:GTMThemeStateActiveWindow]; +- (void)themeChangedNotification:(NSNotification*)notification { + GTMTheme* theme = [notification object]; + NSView* view = [self view]; + if ([theme isEqual:[view gtm_theme]]) { + [self updateTitleColor]; } - // Default to the selected text color unless told otherwise. - if (!color) { - color = [theme textColorForStyle:GTMThemeStyleToolBar - state:GTMThemeStateActiveWindow]; - } - - [titleView_ setTextColor:color ? color : [NSColor textColor]]; - [[self view] setNeedsDisplay:YES]; } // Called by the tabs to determine whether we are in rapid (tab) closure mode. diff --git a/chrome/browser/cocoa/tab_strip_controller.h b/chrome/browser/cocoa/tab_strip_controller.h index e9f0625..2c37f64 100644 --- a/chrome/browser/cocoa/tab_strip_controller.h +++ b/chrome/browser/cocoa/tab_strip_controller.h @@ -94,7 +94,7 @@ class ToolbarModel; browser:(Browser*)browser; // Return the view for the currently selected tab. -- (NSView *)selectedTabView; +- (NSView*)selectedTabView; // Set the frame of the selected tab, also updates the internal frame dict. - (void)setFrameOfSelectedTab:(NSRect)frame; @@ -133,9 +133,6 @@ class ToolbarModel; // Force the tabs to rearrange themselves to reflect the current model. - (void)layoutTabs; -// The user changed the theme, or theme state changed. -- (void)applyTheme; - // Are we in rapid (tab) closure mode? I.e., is a full layout deferred (while // the user closes tabs)? Needed to overcome missing clicks during rapid tab // closure. diff --git a/chrome/browser/cocoa/tab_strip_controller.mm b/chrome/browser/cocoa/tab_strip_controller.mm index 2f10f27..e72eb19 100644 --- a/chrome/browser/cocoa/tab_strip_controller.mm +++ b/chrome/browser/cocoa/tab_strip_controller.mm @@ -18,7 +18,6 @@ #import "chrome/browser/cocoa/browser_window_controller.h" #import "chrome/browser/cocoa/constrained_window_mac.h" #import "chrome/browser/cocoa/tab_strip_view.h" -#import "chrome/browser/cocoa/tab_cell.h" #import "chrome/browser/cocoa/tab_contents_controller.h" #import "chrome/browser/cocoa/tab_controller.h" #import "chrome/browser/cocoa/tab_strip_model_observer_bridge.h" @@ -426,7 +425,7 @@ static const float kIndentLeavingSpaceForControls = 64.0; [NSAnimationContext endGrouping]; // Store the frame by identifier to aviod redundant calls to animator. - NSValue *identifier = [NSValue valueWithPointer:[tab view]]; + NSValue* identifier = [NSValue valueWithPointer:[tab view]]; [targetFrames_ setObject:[NSValue valueWithRect:tabFrame] forKey:identifier]; continue; @@ -455,8 +454,8 @@ static const float kIndentLeavingSpaceForControls = 64.0; // Check the frame by identifier to avoid redundant calls to animator. id frameTarget = visible && animate ? [[tab view] animator] : [tab view]; - NSValue *identifier = [NSValue valueWithPointer:[tab view]]; - NSValue *oldTargetValue = [targetFrames_ objectForKey:identifier]; + NSValue* identifier = [NSValue valueWithPointer:[tab view]]; + NSValue* oldTargetValue = [targetFrames_ objectForKey:identifier]; if (!oldTargetValue || !NSEqualRects([oldTargetValue rectValue], tabFrame)) { [frameTarget setFrame:tabFrame]; @@ -641,7 +640,7 @@ static const float kIndentLeavingSpaceForControls = 64.0; hoveredTab_ = nil; } - NSValue *identifier = [NSValue valueWithPointer:tab]; + NSValue* identifier = [NSValue valueWithPointer:tab]; [targetFrames_ removeObjectForKey:identifier]; // Once we're totally done with the tab, delete its controller @@ -782,14 +781,14 @@ static const float kIndentLeavingSpaceForControls = 64.0; } - (void)setFrameOfSelectedTab:(NSRect)frame { - NSView *view = [self selectedTabView]; - NSValue *identifier = [NSValue valueWithPointer:view]; + NSView* view = [self selectedTabView]; + NSValue* identifier = [NSValue valueWithPointer:view]; [targetFrames_ setObject:[NSValue valueWithRect:frame] forKey:identifier]; [view setFrame:frame]; } -- (NSView *)selectedTabView { +- (NSView*)selectedTabView { int selectedIndex = tabModel_->selected_index(); return [self viewAtIndex:selectedIndex]; } @@ -837,12 +836,6 @@ static const float kIndentLeavingSpaceForControls = 64.0; tabModel_->InsertTabContentsAt(index, contents, true, false); } -- (void)applyTheme { - for (TabController* tab in tabArray_.get()) { - [tab applyTheme]; - } -} - // Called when the tab strip view changes size. As we only registered for // changes on our view, we know it's only for our view. Layout w/out // animations since they are blocked by the resize nested runloop. We need @@ -856,7 +849,7 @@ static const float kIndentLeavingSpaceForControls = 64.0; return availableResizeWidth_ != kUseFullAvailableWidth; } -- (void)mouseMoved:(NSEvent *)event { +- (void)mouseMoved:(NSEvent*)event { // Use hit test to figure out what view we are hovering over. TabView* targetView = (TabView*)[tabView_ hitTest:[event locationInWindow]]; if (![targetView isKindOfClass:[TabView class]]) { diff --git a/chrome/browser/cocoa/tab_view.mm b/chrome/browser/cocoa/tab_view.mm index fd6a2a4..fd1be74 100644 --- a/chrome/browser/cocoa/tab_view.mm +++ b/chrome/browser/cocoa/tab_view.mm @@ -59,7 +59,7 @@ static const NSTimeInterval kAnimationHideDuration = 0.4; // Overridden so that mouse clicks come to this view (the parent of the // hierarchy) first. We want to handle clicks and drags in this class and // leave the background button for display purposes only. -- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent { +- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent { return YES; } @@ -88,7 +88,7 @@ static const NSTimeInterval kAnimationHideDuration = 0.4; [self setNeedsDisplay:YES]; } -- (void)mouseEntered:(NSEvent *)theEvent { +- (void)mouseEntered:(NSEvent*)theEvent { if ([theEvent trackingArea] == closeTrackingArea_) { [closeButton_ setImage:nsimage_cache::ImageNamed(@"close_bar_h.pdf")]; } else { @@ -99,13 +99,13 @@ static const NSTimeInterval kAnimationHideDuration = 0.4; } } -- (void)mouseMoved:(NSEvent *)theEvent { +- (void)mouseMoved:(NSEvent*)theEvent { hoverPoint_ = [self convertPoint:[theEvent locationInWindow] fromView:nil]; [self setNeedsDisplay:YES]; } -- (void)mouseExited:(NSEvent *)theEvent { +- (void)mouseExited:(NSEvent*)theEvent { if ([theEvent trackingArea] == closeTrackingArea_) { [closeButton_ setImage:nsimage_cache::ImageNamed(@"close_bar.pdf")]; } else { @@ -118,7 +118,7 @@ static const NSTimeInterval kAnimationHideDuration = 0.4; // Determines which view a click in our frame actually hit. It's either this // view or our child close button. -- (NSView *)hitTest:(NSPoint)aPoint { +- (NSView*)hitTest:(NSPoint)aPoint { NSPoint viewPoint = [self convertPoint:aPoint fromView:[self superview]]; NSRect frame = [self frame]; @@ -136,7 +136,7 @@ static const NSTimeInterval kAnimationHideDuration = 0.4; // Returns |YES| if this tab can be torn away into a new window. - (BOOL)canBeDragged { - NSWindowController *controller = [sourceWindow_ windowController]; + NSWindowController* controller = [sourceWindow_ windowController]; if ([controller isKindOfClass:[TabWindowController class]]) { TabWindowController* realController = static_cast<TabWindowController*>(controller); @@ -154,7 +154,7 @@ static const NSTimeInterval kAnimationHideDuration = 0.4; for (NSWindow* window in [NSApp windows]) { if (window == dragWindow) continue; if (![window isVisible]) continue; - NSWindowController *controller = [window windowController]; + NSWindowController* controller = [window windowController]; if ([controller isKindOfClass:[TabWindowController class]]) { TabWindowController* realController = static_cast<TabWindowController*>(controller); @@ -189,7 +189,7 @@ static const NSTimeInterval kTearDuration = 0.333; // has moved less than the threshold, we want to close the tab. static const CGFloat kRapidCloseDist = 2.5; -- (void)mouseDown:(NSEvent *)theEvent { +- (void)mouseDown:(NSEvent*)theEvent { NSPoint downLocation = [theEvent locationInWindow]; // During the tab closure animation (in particular, during rapid tab closure), @@ -284,7 +284,7 @@ static const CGFloat kRapidCloseDist = 2.5; } } -- (void)mouseDragged:(NSEvent *)theEvent { +- (void)mouseDragged:(NSEvent*)theEvent { // Special-case this to keep the logic below simpler. if (moveWindowOnDrag_) { NSPoint thisPoint = [NSEvent mouseLocation]; @@ -452,7 +452,7 @@ static const CGFloat kRapidCloseDist = 2.5; // Compute where placeholder should go and insert it into the // destination tab strip. NSRect dropTabFrame = [[targetController_ tabStripView] frame]; - TabView *draggedTabView = (TabView *)[draggedController_ selectedTabView]; + TabView* draggedTabView = (TabView*)[draggedController_ selectedTabView]; NSRect tabFrame = [draggedTabView frame]; tabFrame.origin = [dragWindow_ convertBaseToScreen:tabFrame.origin]; tabFrame.origin = [[targetController_ window] @@ -490,7 +490,7 @@ static const CGFloat kRapidCloseDist = 2.5; } } -- (void)mouseUp:(NSEvent *)theEvent { +- (void)mouseUp:(NSEvent*)theEvent { // The drag/click is done. If the user dragged the mouse, finalize the drag // and clean up. @@ -549,19 +549,12 @@ static const CGFloat kRapidCloseDist = 2.5; } } -- (NSPoint)patternPhase { - NSPoint phase = NSZeroPoint; - phase.x -= [self convertRect:[self bounds] toView:nil].origin.x; - // offset to start pattern in upper left corner - phase.y += NSHeight([self bounds]) - 1; - return phase; -} - - (void)drawRect:(NSRect)rect { - [[NSGraphicsContext currentContext] saveGraphicsState]; + NSGraphicsContext* context = [NSGraphicsContext currentContext]; + [context saveGraphicsState]; rect = [self bounds]; BOOL active = [[self window] isKeyWindow] || [[self window] isMainWindow]; - BOOL selected = [(NSButton *)self state]; + BOOL selected = [(NSButton*)self state]; // Inset by 0.5 in order to draw on pixels rather than on borders (which would // cause blurry pixels). Decrease height by 1 in order to move away from the @@ -583,7 +576,7 @@ static const CGFloat kRapidCloseDist = 2.5; // Outset many of these values by 1 to cause the fill to bleed outside the // clip area. - NSBezierPath *path = [NSBezierPath bezierPath]; + NSBezierPath* path = [NSBezierPath bezierPath]; [path moveToPoint:NSMakePoint(bottomLeft.x - 1, bottomLeft.y - 2)]; [path lineToPoint:NSMakePoint(bottomLeft.x - 1, bottomLeft.y)]; [path lineToPoint:bottomLeft]; @@ -601,52 +594,51 @@ static const CGFloat kRapidCloseDist = 2.5; [path lineToPoint:NSMakePoint(bottomRight.x + 1, bottomRight.y)]; [path lineToPoint:NSMakePoint(bottomRight.x + 1, bottomRight.y - 2)]; - GTMTheme *theme = [self gtm_theme]; + GTMTheme* theme = [self gtm_theme]; + + // Setting the pattern phase + NSPoint phase = [self gtm_themePatternPhase]; + [context setPatternPhase:phase]; if (!selected) { - NSColor *windowColor = + NSColor* windowColor = [theme backgroundPatternColorForStyle:GTMThemeStyleWindow state:GTMThemeStateActiveWindow]; if (windowColor) { [windowColor set]; - - [[NSGraphicsContext currentContext] setPatternPhase:[self patternPhase]]; } else { - NSPoint phase = [self patternPhase]; - phase.y += 1; - [[NSGraphicsContext currentContext] setPatternPhase:phase]; [[NSColor windowBackgroundColor] set]; } [path fill]; - NSColor *tabColor = + NSColor* tabColor = [theme backgroundPatternColorForStyle:GTMThemeStyleTabBarDeselected state:GTMThemeStateActiveWindow]; if (tabColor) { [tabColor set]; - [[NSGraphicsContext currentContext] setPatternPhase:[self patternPhase]]; } else { [[NSColor colorWithCalibratedWhite:1.0 alpha:0.3] set]; } [path fill]; - } - [[NSGraphicsContext currentContext] saveGraphicsState]; + [context saveGraphicsState]; [path addClip]; if (selected || hoverAlpha_ > 0) { // Draw the background. CGFloat backgroundAlpha = hoverAlpha_ * 0.5; - [[NSGraphicsContext currentContext] saveGraphicsState]; - CGContextRef context = - (CGContextRef)([[NSGraphicsContext currentContext] graphicsPort]); - CGContextBeginTransparencyLayer(context, 0); + [context saveGraphicsState]; + CGContextRef cgContext = + (CGContextRef)([context graphicsPort]); + CGContextBeginTransparencyLayer(cgContext, 0); if (!selected) - CGContextSetAlpha(context, backgroundAlpha); + CGContextSetAlpha(cgContext, backgroundAlpha); [path addClip]; - [super drawRect:rect]; + [context saveGraphicsState]; + [super drawBackground]; + [context restoreGraphicsState]; // Draw a mouse hover gradient for the default themes if (!selected) { @@ -671,8 +663,8 @@ static const CGFloat kRapidCloseDist = 2.5; } } - CGContextEndTransparencyLayer(context); - [[NSGraphicsContext currentContext] restoreGraphicsState]; + CGContextEndTransparencyLayer(cgContext); + [context restoreGraphicsState]; } // Draw the top inner highlight. @@ -684,10 +676,10 @@ static const CGFloat kRapidCloseDist = 2.5; setStroke]; [highlightPath stroke]; - [[NSGraphicsContext currentContext] restoreGraphicsState]; + [context restoreGraphicsState]; // Draw the top stroke. - [[NSGraphicsContext currentContext] saveGraphicsState]; + [context saveGraphicsState]; if (selected) { [[NSColor colorWithDeviceWhite:0.0 alpha:active ? 0.3 : 0.15] set]; } else { @@ -696,7 +688,7 @@ static const CGFloat kRapidCloseDist = 2.5; } [path setLineWidth:1.0]; [path stroke]; - [[NSGraphicsContext currentContext] restoreGraphicsState]; + [context restoreGraphicsState]; // Draw the bottom border. if (!selected) { @@ -706,7 +698,7 @@ static const CGFloat kRapidCloseDist = 2.5; [[NSColor colorWithDeviceWhite:0.0 alpha:active ? 0.3 : 0.15] set]; NSRectFillUsingOperation(borderRect, NSCompositeSourceOver); } - [[NSGraphicsContext currentContext] restoreGraphicsState]; + [context restoreGraphicsState]; } // Called when the user hits the right mouse button (or control-clicks) to @@ -715,4 +707,11 @@ static const CGFloat kRapidCloseDist = 2.5; [NSMenu popUpContextMenu:[self menu] withEvent:theEvent forView:self]; } +- (void)viewDidMoveToWindow { + [super viewDidMoveToWindow]; + if ([self window]) { + [controller_ updateTitleColor]; + } +} + @end diff --git a/chrome/browser/cocoa/tab_window_controller.mm b/chrome/browser/cocoa/tab_window_controller.mm index 2d02e70..20267c8 100644 --- a/chrome/browser/cocoa/tab_window_controller.mm +++ b/chrome/browser/cocoa/tab_window_controller.mm @@ -15,7 +15,7 @@ @synthesize tabStripView = tabStripView_; @synthesize tabContentArea = tabContentArea_; -- (id)initWithWindow:(NSWindow *)window { +- (id)initWithWindow:(NSWindow*)window { if ((self = [super initWithWindow:window]) != nil) { lockedTabs_.reset([[NSMutableSet alloc] initWithCapacity:10]); } @@ -77,6 +77,7 @@ } else { [[[[self window] contentView] superview] addSubview:[self tabStripView]]; [[self window] setContentView:cachedContentView_]; + [[[[self window] contentView] superview] updateTrackingAreas]; } } @@ -89,9 +90,10 @@ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(removeOverlay) object:nil]; + NSWindow* window = [self window]; if (useOverlay && !overlayWindow_) { DCHECK(!cachedContentView_); - overlayWindow_ = [[NSPanel alloc] initWithContentRect:[[self window] frame] + overlayWindow_ = [[NSPanel alloc] initWithContentRect:[window frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES]; @@ -99,17 +101,17 @@ [overlayWindow_ setBackgroundColor:[NSColor clearColor]]; [overlayWindow_ setOpaque:NO]; [overlayWindow_ setDelegate:self]; - cachedContentView_ = [[self window] contentView]; + cachedContentView_ = [window contentView]; [self moveViewsBetweenWindowAndOverlay:useOverlay]; - [[self window] addChildWindow:overlayWindow_ ordered:NSWindowAbove]; + [window addChildWindow:overlayWindow_ ordered:NSWindowAbove]; [overlayWindow_ orderFront:nil]; } else if (!useOverlay && overlayWindow_) { DCHECK(cachedContentView_); - [[self window] setContentView:cachedContentView_]; + [window setContentView:cachedContentView_]; [self moveViewsBetweenWindowAndOverlay:useOverlay]; - [[self window] makeFirstResponder:cachedContentView_]; - [[self window] display]; - [[self window] removeChildWindow:overlayWindow_]; + [window makeFirstResponder:cachedContentView_]; + [window display]; + [window removeChildWindow:overlayWindow_]; [overlayWindow_ orderOut:nil]; [overlayWindow_ release]; overlayWindow_ = nil; @@ -134,7 +136,7 @@ NOTIMPLEMENTED(); } -- (NSView *)selectedTabView { +- (NSView*)selectedTabView { NOTIMPLEMENTED(); return nil; } diff --git a/chrome/browser/cocoa/toolbar_controller.mm b/chrome/browser/cocoa/toolbar_controller.mm index 5f591db..e85f3a1 100644 --- a/chrome/browser/cocoa/toolbar_controller.mm +++ b/chrome/browser/cocoa/toolbar_controller.mm @@ -179,9 +179,7 @@ class PrefObserverBridge : public NotificationObserver { EncodingMenuControllerDelegate::BuildEncodingMenu(profile_, encodingMenu_); } -- (void)removeFromSuperview { - NSLog(@"remove"); -} + - (void)mouseExited:(NSEvent*)theEvent { [[hoveredButton_ cell] setMouseInside:NO animate:YES]; [hoveredButton_ release]; @@ -189,8 +187,8 @@ class PrefObserverBridge : public NotificationObserver { } - (NSButton*)hoverButtonForEvent:(NSEvent*)theEvent { - NSButton* targetView = (NSButton *)[[self view] - hitTest:[theEvent locationInWindow]]; + NSButton* targetView = (NSButton*)[[self view] + hitTest:[theEvent locationInWindow]]; // Only interpret the view as a hoverButton_ if it's both button and has a // button cell that cares. GradientButtonCell derived cells care. @@ -434,10 +432,10 @@ class PrefObserverBridge : public NotificationObserver { [resizeDelegate_ resizeView:[self view] newHeight:newToolbarHeight]; } -- (NSString *)view:(NSView *)view - stringForToolTip:(NSToolTipTag)tag - point:(NSPoint)point - userData:(void *)userData { +- (NSString*)view:(NSView*)view + stringForToolTip:(NSToolTipTag)tag + point:(NSPoint)point + userData:(void*)userData { DCHECK(view == goButton_); // Following chrome/browser/views/go_button.cc: GoButton::GetTooltipText() diff --git a/chrome/browser/cocoa/toolbar_view.mm b/chrome/browser/cocoa/toolbar_view.mm index 17278aa..e8111d0 100644 --- a/chrome/browser/cocoa/toolbar_view.mm +++ b/chrome/browser/cocoa/toolbar_view.mm @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/cocoa/toolbar_view.h" +#import "chrome/browser/cocoa/toolbar_view.h" @implementation ToolbarView @@ -11,4 +11,12 @@ return NO; } +- (void)drawRect:(NSRect)rect { + // The toolbar's background pattern is phased relative to the + // tab strip view's background pattern. + NSPoint phase = [self gtm_themePatternPhase]; + [[NSGraphicsContext currentContext] setPatternPhase:phase]; + [self drawBackground]; +} + @end diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 0120dc2..9f4827d 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -1011,6 +1011,8 @@ 'browser/cocoa/bookmark_name_folder_controller.h', 'browser/cocoa/bookmark_name_folder_controller.mm', 'browser/cocoa/browser_test_helper.h', + 'browser/cocoa/browser_frame_view.h', + 'browser/cocoa/browser_frame_view.mm', 'browser/cocoa/browser_window_cocoa.h', 'browser/cocoa/browser_window_cocoa.mm', 'browser/cocoa/browser_window_controller.h', @@ -1125,8 +1127,6 @@ 'browser/cocoa/shell_dialogs_mac.mm', 'browser/cocoa/status_bubble_mac.h', 'browser/cocoa/status_bubble_mac.mm', - 'browser/cocoa/tab_cell.h', - 'browser/cocoa/tab_cell.mm', 'browser/cocoa/tab_contents_controller.h', 'browser/cocoa/tab_contents_controller.mm', 'browser/cocoa/tab_controller.h', @@ -4183,6 +4183,7 @@ 'browser/cocoa/bookmark_menu_bridge_unittest.mm', 'browser/cocoa/bookmark_menu_cocoa_controller_unittest.mm', 'browser/cocoa/bookmark_name_folder_controller_unittest.mm', + 'browser/cocoa/browser_frame_view_unittest.mm', 'browser/cocoa/browser_window_cocoa_unittest.mm', 'browser/cocoa/browser_window_controller_unittest.mm', 'browser/cocoa/bubble_view_unittest.mm', @@ -4226,7 +4227,6 @@ 'browser/cocoa/sad_tab_view_unittest.mm', 'browser/cocoa/search_engine_list_model_unittest.mm', 'browser/cocoa/status_bubble_mac_unittest.mm', - 'browser/cocoa/tab_cell_unittest.mm', 'browser/cocoa/tab_controller_unittest.mm', 'browser/cocoa/tab_strip_controller_unittest.mm', 'browser/cocoa/tab_strip_view_unittest.mm', |