Bug 303110 - Add Unified Toolbar machinery to Cocoa widgets. r=joshmoz, r=bz, sr=roc.

This commit is contained in:
cbarrett@mozilla.com 2007-10-29 21:03:42 -07:00
Родитель 456558695a
Коммит 878ccd501c
8 изменённых файлов: 414 добавлений и 14 удалений

Просмотреть файл

@ -838,6 +838,7 @@ GK_ATOM(thead, "thead")
GK_ATOM(thumb, "thumb")
GK_ATOM(title, "title")
GK_ATOM(titlebar, "titlebar")
GK_ATOM(titlebarcolor, "titlebarcolor")
GK_ATOM(titletip, "titletip")
GK_ATOM(toggled, "toggled")
GK_ATOM(token, "token")

Просмотреть файл

@ -63,6 +63,7 @@
#include "nsIPrivateDOMEvent.h"
#include "nsHashtable.h"
#include "nsIAtom.h"
#include "nsIBaseWindow.h"
#include "nsIDOMAttr.h"
#include "nsIDOMDocument.h"
#include "nsIDOMElement.h"
@ -1055,8 +1056,20 @@ nsXULElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
HideWindowChrome(aValue && NS_LITERAL_STRING("true").Equals(*aValue));
}
// handle :read-only/:read-write
// titlebarcolor is settable on any root node (windows, dialogs, etc)
nsIDocument *document = GetCurrentDoc();
if (aName == nsGkAtoms::titlebarcolor &&
document && document->GetRootContent() == this) {
nscolor color = NS_RGBA(0, 0, 0, 0);
nsAttrValue attrValue;
attrValue.ParseColor(*aValue, document);
attrValue.GetColorValue(color);
SetTitlebarColor(color);
}
// handle :read-only/:read-write
if (aName == nsGkAtoms::readonly && document) {
mozAutoDocUpdate upd(document, UPDATE_CONTENT_STATE, PR_TRUE);
document->ContentStatesChanged(this, nsnull,
@ -1298,6 +1311,12 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify)
HideWindowChrome(PR_FALSE);
}
if (aName == nsGkAtoms::titlebarcolor &&
doc && doc->GetRootContent() == this) {
// Use 0, 0, 0, 0 as the "none" color.
SetTitlebarColor(NS_RGBA(0, 0, 0, 0));
}
// If the accesskey attribute is removed, unregister it here
// Also see nsAreaFrame, nsBoxFrame and nsTextBoxFrame's AttributeChanged
if (aName == nsGkAtoms::accesskey || aName == nsGkAtoms::control) {
@ -2291,6 +2310,28 @@ nsXULElement::HideWindowChrome(PRBool aShouldHide)
return NS_OK;
}
void
nsXULElement::SetTitlebarColor(nscolor aColor)
{
nsIDocument* doc = GetCurrentDoc();
if (!doc || doc->GetRootContent() != this) {
return;
}
// only top level chrome documents can set the titlebar color
if (!doc->GetParentDocument()) {
nsCOMPtr<nsISupports> container = doc->GetContainer();
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
if (baseWindow) {
nsCOMPtr<nsIWidget> mainWidget;
baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
if (mainWidget) {
mainWidget->SetWindowTitlebarColor(aColor);
}
}
}
}
PRBool
nsXULElement::BoolAttrIsTrue(nsIAtom* aName)
{

Просмотреть файл

@ -713,6 +713,8 @@ protected:
nsresult HideWindowChrome(PRBool aShouldHide);
void SetTitlebarColor(nscolor aColor);
const nsAttrName* InternalGetExistingAttrNameFromQName(const nsAString& aStr) const;
protected:

Просмотреть файл

@ -95,11 +95,11 @@ typedef nsEventStatus (*PR_CALLBACK EVENT_CALLBACK)(nsGUIEvent *event);
#define NS_NATIVE_PLUGIN_PORT_CG 101
#endif
// 15800FBD-650A-4F67-81FB-186E73F45BE1
// d9d02313-6a10-4b6d-9f15-18177e94047a
#define NS_IWIDGET_IID \
{ 0x15800FBD, 0x650A, 0x4F67, \
{ 0x81, 0xFB, 0x18, 0x6E, 0x73, 0xF4, 0x5B, 0xE1 } }
{ 0xd9d02313, 0x6a10, 0x4b6d, \
{ 0x9f, 0x15, 0x18, 0x17, 0x7e, 0x94, 0x04, 0x7a } }
// Hide the native window systems real window type so as to avoid
// including native window system types and api's. This is necessary
@ -1030,11 +1030,27 @@ class nsIWidget : public nsISupports {
*/
NS_IMETHOD EndSecureKeyboardInput() = 0;
/**
* Set the background color of the window titlebar for this widget. On Mac,
* for example, this will remove the grey gradient and bottom border and
* instead show a single, solid color.
*
* Ignored on any platform that does not support it. Ignored by widgets that
* do not represent windows.
*
* @param aColor The color to set the title bar background to. Alpha values
* other than fully transparent (0) are respected if possible
* on the platform. An alpha of 0 will cause the window to
* draw with the default style for the platform.
*/
NS_IMETHOD SetWindowTitlebarColor(nscolor aColor) = 0;
/**
* Get the Thebes surface associated with this widget.
*/
virtual gfxASurface *GetThebesSurface() = 0;
protected:
// keep the list of children. We also keep track of our siblings.
// The ownership model is as follows: parent holds a strong ref to

Просмотреть файл

@ -21,6 +21,7 @@
*
* Contributor(s):
* Josh Aas <josh@mozilla.com>
* Colin Barrett <cbarrett@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -70,6 +71,11 @@ class nsChildView;
// original value.
- (void)_setWindowNumber:(int)aNumber;
// If we set the window's stylemask to be textured, the corners on the bottom of
// the window are rounded by default. We use this private method to make
// the corners square again, a la Safari.
- (void)setBottomCornerRounded:(BOOL)rounded;
@end
@ -107,10 +113,42 @@ class nsChildView;
- (nsCocoaWindow*)geckoWidget;
@end
// Class that allows us to show the toolbar pill button
// NSColor subclass that allows us to draw separate colors both in the titlebar
// and for background of the window.
@interface TitlebarAndBackgroundColor : NSColor
{
NSColor *mTitlebarColor;
NSColor *mBackgroundColor;
NSWindow *mWindow; // [WEAK] (we are owned by the window)
float mTitlebarHeight;
}
- (id)initWithTitlebarColor:(NSColor*)aTitlebarColor
andBackgroundColor:(NSColor*)aBackgroundColor
forWindow:(NSWindow*)aWindow;
// Pass nil here to get the default appearance.
- (void)setTitlebarColor:(NSColor*)aColor;
- (NSColor*)titlebarColor;
- (void)setBackgroundColor:(NSColor*)aColor;
- (NSColor*)backgroundColor;
- (NSWindow*)window;
- (float)titlebarHeight;
@end
// NSWindow subclass for handling windows with toolbars.
@interface ToolbarWindow : NSWindow
{
TitlebarAndBackgroundColor *mColor;
}
- (void)setTitlebarColor:(NSColor*)aColor;
- (NSColor*)titlebarColor;
// This method is also available on NSWindows (via a category), and is the
// preferred way to check the background color of a window.
- (NSColor*)windowBackgroundColor;
@end
class nsCocoaWindow : public nsBaseWidget, public nsPIWidgetCocoa
@ -199,6 +237,7 @@ public:
NS_IMETHOD DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus) ;
NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener, PRBool aDoCapture, PRBool aConsumeRollupEvent);
NS_IMETHOD GetAttention(PRInt32 aCycleCount);
NS_IMETHOD SetWindowTitlebarColor(nscolor aColor);
virtual gfxASurface* GetThebesSurface();

Просмотреть файл

@ -21,6 +21,7 @@
*
* Contributor(s):
* Josh Aas <josh@mozilla.com>
* Colin Barrett <cbarrett@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -317,11 +318,12 @@ nsresult nsCocoaWindow::StandardCreate(nsIWidget *aParent,
// NSLog(@"Top-level window being created at Cocoa rect: %f, %f, %f, %f\n",
// rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
// Create the window
Class windowClass = [NSWindow class];
// If we're a top level window, we want to be able to have the toolbar
// pill button, so use the special ToolbarWindow class.
if (mWindowType == eWindowType_toplevel)
// If we have a titlebar, we want to be able to control the titlebar color
// (for unified), so use the special ToolbarWindow class. Note that we need
// to check the window type because we mark sheets sheets as having titlebars.
if ((mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog) &&
(features & NSTitledWindowMask))
windowClass = [ToolbarWindow class];
// If we're a popup window we need to use the PopupWindow class.
else if (mWindowType == eWindowType_popup)
@ -330,6 +332,8 @@ nsresult nsCocoaWindow::StandardCreate(nsIWidget *aParent,
// BorderlessWindow class.
else if (features == NSBorderlessWindowMask)
windowClass = [BorderlessWindow class];
// Create the window
mWindow = [[windowClass alloc] initWithContentRect:rect styleMask:features
backing:NSBackingStoreBuffered defer:NO];
@ -358,7 +362,7 @@ nsresult nsCocoaWindow::StandardCreate(nsIWidget *aParent,
[mWindow setBackgroundColor:[NSColor whiteColor]];
[mWindow setContentMinSize:NSMakeSize(60, 60)];
[mWindow setReleasedWhenClosed:NO];
// setup our notification delegate. Note that setDelegate: does NOT retain.
mDelegate = [[WindowDelegate alloc] initWithGeckoWindow:this];
[mWindow setDelegate:mDelegate];
@ -1079,6 +1083,27 @@ NS_IMETHODIMP nsCocoaWindow::GetAttention(PRInt32 aCycleCount)
}
NS_IMETHODIMP nsCocoaWindow::SetWindowTitlebarColor(nscolor aColor)
{
if (![mWindow isKindOfClass:[ToolbarWindow class]]) {
NS_WARNING("Calling SetWindowTitlebarColor on window that isn't of the ToolbarWindow class.");
return NS_ERROR_FAILURE;
}
// If they pass a color with a complete transparent alpha component, use the
// native titlebar appearance.
if (NS_GET_A(aColor) == 0) {
[(ToolbarWindow*)mWindow setTitlebarColor:nil];
} else {
[(ToolbarWindow*)mWindow setTitlebarColor:[NSColor colorWithDeviceRed:NS_GET_R(aColor)/255.0
green:NS_GET_G(aColor)/255.0
blue:NS_GET_B(aColor)/255.0
alpha:NS_GET_A(aColor)/255.0]];
}
return NS_OK;
}
gfxASurface* nsCocoaWindow::GetThebesSurface()
{
if (mPopupContentView)
@ -1294,18 +1319,96 @@ NS_IMETHODIMP nsCocoaWindow::EndSecureKeyboardInput()
@end
// Category on NSWindow so callers can use the same method on both ToolbarWindows
// and NSWindows for accessing the background color.
@implementation NSWindow(ToolbarWindowCompat)
- (NSColor*)windowBackgroundColor
{
return [self backgroundColor];
}
@end
// This class allows us to have a "unified toolbar" style window. It works like this:
// 1) We set the window's style to textured.
// 2) Because of this, the background color applies to the entire window, including
// the titlebar area. For normal textured windows, the default pattern is a
// "brushed metal" image.
// 3) We set the background color to a custom NSColor subclass that knows how tall the window is.
// When -set is called on it, it sets a pattern (with a draw callback) as the fill. In that callback,
// it paints the the titlebar and background colrs in the correct areas of the context its given,
// which will fill the entire window (CG will tile it horizontally for us).
//
// This class also provides us with a pill button to show/hide the toolbar.
@implementation ToolbarWindow
// The carbon widget code was saying we want a toolbar for all top level
// windows, and since we're only using this class for top level windows, we
// always want to return yes from here.
- (id)initWithContentRect:(NSRect)aContentRect styleMask:(unsigned int)aStyle backing:(NSBackingStoreType)aBufferingType defer:(BOOL)aFlag
{
aStyle = aStyle | NSTexturedBackgroundWindowMask;
if ((self = [super initWithContentRect:aContentRect styleMask:aStyle backing:aBufferingType defer:aFlag])) {
mColor = [[TitlebarAndBackgroundColor alloc] initWithTitlebarColor:nil
andBackgroundColor:[NSColor whiteColor]
forWindow:self];
// Call the superclass's implementation, to avoid our guard method below.
[super setBackgroundColor:mColor];
// setBottomCornerRounded: is a private API call, so we check to make sure
// we respond to it just in case.
if ([self respondsToSelector:@selector(setBottomCornerRounded:)])
[self setBottomCornerRounded:NO];
}
return self;
}
- (void)dealloc
{
[mColor release];
[super dealloc];
}
// We don't provide our own implementation of -backgroundColor because NSWindow
// looks at it, apparently. This is here to keep someone from messing with our
// custom NSColor subclass.
- (void)setBackgroundColor:(NSColor*)aColor
{
[mColor setBackgroundColor:aColor];
}
// If you need to get at the background color of the window (in the traditional
// sense) use this method instead.
- (NSColor*)windowBackgroundColor
{
return [mColor backgroundColor];
}
// Pass nil here to get the default appearance.
- (void)setTitlebarColor:(NSColor*)aColor
{
[mColor setTitlebarColor:aColor];
}
- (NSColor*)titlebarColor
{
return [mColor titlebarColor];
}
// Always show the toolbar pill button.
- (BOOL)_hasToolbar
{
return YES;
}
// Dispatch a toolbar pill button clicked message to Gecko
// Dispatch a toolbar pill button clicked message to Gecko.
- (void)_toolbarPillButtonClicked:(id)sender
{
nsCocoaWindow *geckoWindow = [[self delegate] geckoWidget];
@ -1329,6 +1432,196 @@ NS_IMETHODIMP nsCocoaWindow::EndSecureKeyboardInput()
@end
// Custom NSColor subclass where most of the work takes place for drawing in
// the titlebar area.
@implementation TitlebarAndBackgroundColor
- (id)initWithTitlebarColor:(NSColor*)aTitlebarColor
andBackgroundColor:(NSColor*)aBackgroundColor
forWindow:(NSWindow*)aWindow
{
if ((self = [super init])) {
mTitlebarColor = [aTitlebarColor retain];
mBackgroundColor = [aBackgroundColor retain];
mWindow = aWindow; // weak ref
NSRect frameRect = [aWindow frame];
mTitlebarHeight = frameRect.size.height - [aWindow contentRectForFrameRect:frameRect].size.height;
}
return self;
}
- (void)dealloc
{
[mTitlebarColor release];
[mBackgroundColor release];
[super dealloc];
}
// Our pattern width is 1 pixel. CoreGraphics can cache and tile for us.
static const float sPatternWidth = 1.0f;
// These are the start and end greys for the default titlebar gradient.
static const float sHeaderStartGrey = 196/255.0f;
static const float sHeaderEndGrey = 149/255.0f;
// This is the grey for the border at the bottom of the titlebar.
static const float sTitlebarBorderGrey = 64/255.0f;
// Callback used by the default titlebar shading.
static void headerShading(void* aInfo, const float* aIn, float* aOut)
{
float result = (*aIn) * sHeaderStartGrey + (1.0f - *aIn) * sHeaderEndGrey;
aOut[0] = result;
aOut[1] = result;
aOut[2] = result;
aOut[3] = 1.0f;
}
// Callback where all of the drawing for this color takes place.
void patternDraw(void* aInfo, CGContextRef aContext)
{
TitlebarAndBackgroundColor *color = (TitlebarAndBackgroundColor*)aInfo;
NSColor *titlebarColor = [color titlebarColor];
NSColor *backgroundColor = [color backgroundColor];
NSWindow *window = [color window];
// Remember: this context is NOT flipped, so the origin is in the bottom left.
float titlebarHeight = [color titlebarHeight];
float titlebarOrigin = [window frame].size.height - titlebarHeight;
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:aContext flipped:NO]];
// If the titlebar color is nil, draw the default titlebar shading.
if (!titlebarColor) {
//Create and draw a CGShading that uses headerShading() as its callback.
CGFunctionCallbacks callbacks = {0, headerShading, NULL};
CGFunctionRef function = CGFunctionCreate(NULL, 1, NULL, 4, NULL, &callbacks);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGShadingRef shading = CGShadingCreateAxial(colorSpace, CGPointMake(0.0f, titlebarOrigin),
CGPointMake(0.0f, titlebarOrigin + titlebarHeight),
function, NO, NO);
CGColorSpaceRelease(colorSpace);
CGFunctionRelease(function);
CGContextDrawShading(aContext, shading);
// Draw the one pixel border at the bottom of the titlebar.
[[NSColor colorWithDeviceWhite:sTitlebarBorderGrey alpha:1.0f] set];
NSRectFill(NSMakeRect(0.0f, titlebarOrigin, sPatternWidth, 1.0f));
} else {
// if the titlebar color is not nil, just set and draw it normally.
[titlebarColor set];
NSRectFill(NSMakeRect(0.0f, titlebarOrigin, sPatternWidth, titlebarHeight));
}
// Draw the background color of the window everywhere but where the titlebar is.
[backgroundColor set];
NSRectFill(NSMakeRect(0.0f, 0.0f, 1.0f, titlebarOrigin));
[NSGraphicsContext restoreGraphicsState];
}
- (void)setFill
{
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
// Set up the pattern to be as tall as our window, and one pixel wide.
// CoreGraphics can cache and tile us quickly.
CGPatternCallbacks callbacks = {0, &patternDraw, NULL};
CGPatternRef pattern = CGPatternCreate(self, CGRectMake(0.0f, 0.0f, sPatternWidth, [mWindow frame].size.height),
CGAffineTransformIdentity, 1, [mWindow frame].size.height,
kCGPatternTilingConstantSpacing, true, &callbacks);
// Set the pattern as the fill, which is what we were asked to do. All our
// drawing will take place in the patternDraw callback.
CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
CGContextSetFillColorSpace(context, patternSpace);
CGColorSpaceRelease(patternSpace);
float component = 1.0f;
CGContextSetFillPattern(context, pattern, &component);
CGPatternRelease(pattern);
}
// Pass nil here to get the default appearance.
- (void)setTitlebarColor:(NSColor*)aColor
{
[mTitlebarColor autorelease];
mTitlebarColor = [aColor retain];
}
- (NSColor*)titlebarColor
{
return mTitlebarColor;
}
- (void)setBackgroundColor:(NSColor*)aColor
{
[mBackgroundColor autorelease];
mBackgroundColor = [aColor retain];
}
- (NSColor*)backgroundColor
{
return mBackgroundColor;
}
- (NSWindow*)window
{
return mWindow;
}
- (NSString*)colorSpaceName
{
return NSDeviceRGBColorSpace;
}
- (void)set
{
[self setFill];
}
- (float)titlebarHeight
{
return mTitlebarHeight;
}
@end
// This is an internal Apple class, which we need to work around a bug in. It is
// the class responsible for drawing the titlebar for metal windows. It actually
// is a few levels deep in the inhertiance graph, but we don't need to know about
// all its superclasses.
@interface NSGrayFrame : NSObject
+ (void)drawBevel:(NSRect)bevel inFrame:(NSRect)frame topCornerRounded:(BOOL)top;
+ (void)drawBevel:(NSRect)bevel inFrame:(NSRect)frame topCornerRounded:(BOOL)top bottomCornerRounded:(BOOL)bottom;
@end
@implementation NSGrayFrame(DrawingBugWorkaround)
// Work around a bug in this method -- it draws a strange 1px border on the left and
// right edges of a window. We don't want that, so call the similar method defined
// in the superclass.
+ (void)drawBevel:(NSRect)bevel inFrame:(NSRect)frame topCornerRounded:(BOOL)top bottomCornerRounded:(BOOL)bottom
{
if ([self respondsToSelector:@selector(drawBevel:inFrame:topCornerRounded:)])
[self drawBevel:bevel inFrame:frame topCornerRounded:top];
}
@end
@implementation PopupWindow
// The OS treats our custom popup windows very strangely -- many mouse events

Просмотреть файл

@ -858,6 +858,13 @@ nsBaseWidget::EndSecureKeyboardInput()
return NS_OK;
}
NS_IMETHODIMP
nsBaseWidget::SetWindowTitlebarColor(nscolor aColor)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/**
* Modifies aFile to point at an icon file with the given name and suffix. The
* suffix may correspond to a file extension with leading '.' if appropriate.

Просмотреть файл

@ -133,6 +133,7 @@ public:
NS_IMETHOD SetIcon(const nsAString &anIconSpec);
NS_IMETHOD BeginSecureKeyboardInput();
NS_IMETHOD EndSecureKeyboardInput();
NS_IMETHOD SetWindowTitlebarColor(nscolor aColor);
virtual void ConvertToDeviceCoordinates(nscoord &aX,nscoord &aY) {}
virtual void FreeNativeData(void * data, PRUint32 aDataType) {}