Draw native scrollbars using nsITheme on Mac OS X. Don't use a cocoa control. Fixes a whole host of clipping and visibility bugs and bugs 339447, 369293, 370439. r=josh sr=roc
git-svn-id: svn://10.0.0.236/trunk@224386 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -1377,6 +1377,7 @@ GK_ATOM(positionedInlineFrame, "PositionedInlineFrame")
|
||||
GK_ATOM(canvasFrame, "CanvasFrame")
|
||||
GK_ATOM(rootFrame, "RootFrame")
|
||||
GK_ATOM(scrollFrame, "ScrollFrame")
|
||||
GK_ATOM(scrollbarFrame, "ScrollbarFrame")
|
||||
GK_ATOM(sequenceFrame, "SequenceFrame")
|
||||
GK_ATOM(tableCaptionFrame, "TableCaptionFrame")
|
||||
GK_ATOM(tableCellFrame, "TableCellFrame")
|
||||
|
||||
@@ -112,6 +112,12 @@ nsScrollbarFrame::IsContainingBlock() const
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
nsScrollbarFrame::GetType() const
|
||||
{
|
||||
return nsGkAtoms::scrollbarFrame;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScrollbarFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
|
||||
@@ -99,6 +99,8 @@ public:
|
||||
|
||||
virtual PRBool IsContainingBlock() const;
|
||||
|
||||
virtual nsIAtom* GetType() const;
|
||||
|
||||
// nsIScrollbarFrame
|
||||
virtual void SetScrollbarMediatorContent(nsIContent* aMediator);
|
||||
virtual nsIScrollbarMediator* GetScrollbarMediator();
|
||||
|
||||
@@ -47,15 +47,54 @@
|
||||
|
||||
scrollbar {
|
||||
-moz-appearance: scrollbar;
|
||||
-moz-binding: url(chrome://global/content/bindings/nativescrollbar.xml#scrollbar);
|
||||
min-width: 16px;
|
||||
-moz-binding: url(chrome://global/content/bindings/scrollbar.xml#scrollbar);
|
||||
cursor: default;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
html|select[size]:not([size="0"]):not([size="1"]) > scrollbar,
|
||||
html|select[multiple] > scrollbar {
|
||||
-moz-appearance: scrollbar-small;
|
||||
min-width: 11px;
|
||||
}
|
||||
|
||||
/* ..... track ..... */
|
||||
|
||||
slider {
|
||||
-moz-appearance: scrollbartrack-vertical;
|
||||
}
|
||||
|
||||
slider[orient="horizontal"] {
|
||||
-moz-appearance: scrollbartrack-horizontal;
|
||||
}
|
||||
|
||||
/* ..... thumb ..... */
|
||||
|
||||
thumb {
|
||||
-moz-appearance: scrollbarthumb-vertical;
|
||||
}
|
||||
|
||||
thumb[orient="horizontal"] {
|
||||
-moz-appearance: scrollbarthumb-horizontal;
|
||||
}
|
||||
|
||||
/* ..... increment ..... */
|
||||
|
||||
scrollbarbutton[type="increment"] {
|
||||
-moz-appearance: scrollbarbutton-right;
|
||||
}
|
||||
|
||||
scrollbar[orient="vertical"] > scrollbarbutton[type="increment"] {
|
||||
-moz-appearance: scrollbarbutton-down;
|
||||
}
|
||||
|
||||
/* ..... decrement ..... */
|
||||
|
||||
scrollbarbutton[type="decrement"] {
|
||||
-moz-appearance: scrollbarbutton-left;
|
||||
}
|
||||
|
||||
scrollbar[orient="vertical"] > scrollbarbutton[type="decrement"] {
|
||||
-moz-appearance: scrollbarbutton-up;
|
||||
}
|
||||
|
||||
/* ::::: square at the corner of two scrollbars ::::: */
|
||||
@@ -63,7 +102,6 @@ html|select[multiple] > scrollbar {
|
||||
scrollcorner {
|
||||
/* XXX -moz-appearance: scrollcorner; */
|
||||
-moz-binding: url(chrome://global/content/bindings/scrollbar.xml#scrollbar-base);
|
||||
width: 16px;
|
||||
cursor: default;
|
||||
background-color: white;
|
||||
}
|
||||
@@ -74,8 +112,7 @@ scrollcorner {
|
||||
@media print {
|
||||
html|div scrollbar {
|
||||
-moz-appearance: scrollbar;
|
||||
-moz-binding: url(chrome://global/content/bindings/nativescrollbar.xml#scrollbar);
|
||||
min-width: 16px;
|
||||
-moz-binding: url(chrome://global/content/bindings/scrollbar.xml#scrollbar);
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,7 @@
|
||||
|
||||
scrollbar {
|
||||
-moz-appearance: scrollbar;
|
||||
-moz-binding: url(chrome://global/content/bindings/nativescrollbar.xml#scrollbar);
|
||||
min-width: 16px;
|
||||
-moz-binding: url(chrome://global/content/bindings/scrollbar.xml#scrollbar);
|
||||
cursor: default;
|
||||
background-color: white;
|
||||
}
|
||||
@@ -56,7 +55,46 @@ scrollbar {
|
||||
html|select[size]:not([size="0"]):not([size="1"]) > scrollbar,
|
||||
html|select[multiple] > scrollbar {
|
||||
-moz-appearance: scrollbar-small;
|
||||
min-width: 11px;
|
||||
}
|
||||
|
||||
/* ..... track ..... */
|
||||
|
||||
slider {
|
||||
-moz-appearance: scrollbartrack-vertical;
|
||||
}
|
||||
|
||||
slider[orient="horizontal"] {
|
||||
-moz-appearance: scrollbartrack-horizontal;
|
||||
}
|
||||
|
||||
/* ..... thumb ..... */
|
||||
|
||||
thumb {
|
||||
-moz-appearance: scrollbarthumb-vertical;
|
||||
}
|
||||
|
||||
thumb[orient="horizontal"] {
|
||||
-moz-appearance: scrollbarthumb-horizontal;
|
||||
}
|
||||
|
||||
/* ..... increment ..... */
|
||||
|
||||
scrollbarbutton[type="increment"] {
|
||||
-moz-appearance: scrollbarbutton-right;
|
||||
}
|
||||
|
||||
scrollbar[orient="vertical"] > scrollbarbutton[type="increment"] {
|
||||
-moz-appearance: scrollbarbutton-down;
|
||||
}
|
||||
|
||||
/* ..... decrement ..... */
|
||||
|
||||
scrollbarbutton[type="decrement"] {
|
||||
-moz-appearance: scrollbarbutton-left;
|
||||
}
|
||||
|
||||
scrollbar[orient="vertical"] > scrollbarbutton[type="decrement"] {
|
||||
-moz-appearance: scrollbarbutton-up;
|
||||
}
|
||||
|
||||
/* ::::: square at the corner of two scrollbars ::::: */
|
||||
@@ -75,16 +113,7 @@ scrollcorner {
|
||||
@media print {
|
||||
html|div scrollbar {
|
||||
-moz-appearance: scrollbar;
|
||||
-moz-binding: url(chrome://global/content/bindings/nativescrollbar.xml#scrollbar);
|
||||
min-width: 16px;
|
||||
-moz-binding: url(chrome://global/content/bindings/scrollbar.xml#scrollbar);
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
/* ::::: slider ::::: */
|
||||
|
||||
thumb {
|
||||
background: url("chrome://global/skin/icons/thumb.png") transparent center no-repeat;
|
||||
min-width: 15px;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,6 @@ CMMSRCS = \
|
||||
nsChildView.mm \
|
||||
nsWindowMap.mm \
|
||||
nsWidgetFactory.mm \
|
||||
nsNativeScrollbar.mm \
|
||||
nsCursorManager.mm \
|
||||
nsMacCursor.mm \
|
||||
nsScreenCocoa.mm \
|
||||
|
||||
@@ -50,6 +50,9 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
// Apple hasn't defined a constant for scollbars with two arrows on each end, so we'll use this one.
|
||||
static const int kThemeScrollBarArrowsBoth = 2;
|
||||
|
||||
typedef enum {
|
||||
//theme accent variation colours on Mac OS,
|
||||
//offsets into Platinum theme variation colour table
|
||||
|
||||
@@ -524,6 +524,11 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(const nsMetricID aID, PRInt32 & aMetric)
|
||||
case kThemeScrollBarArrowsSingle:
|
||||
aMetric = eMetric_ScrollArrowStyleSingle;
|
||||
break;
|
||||
// This constant isn't selectable in System Preferences like the other two (don't know why)
|
||||
// `defaults write -g AppleScrollBarVariant DoubleBoth` to enable it.
|
||||
case kThemeScrollBarArrowsBoth:
|
||||
aMetric = eMetric_ScrollArrowStyleBothAtEachEnd;
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("Not handling all possible ThemeScrollBarArrowStyle values");
|
||||
// fall through so we default to BothAtBottom
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* 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
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsNativeScrollbar_h_
|
||||
#define nsNativeScrollbar_h_
|
||||
|
||||
#import <Carbon/Carbon.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "mozView.h"
|
||||
#include "nsChildView.h"
|
||||
|
||||
#include "nsINativeScrollbar.h"
|
||||
#include "nsIContent.h"
|
||||
|
||||
class nsIScrollbarMediator;
|
||||
|
||||
@class NativeScrollbarView;
|
||||
|
||||
//
|
||||
// nsNativeScrollbar
|
||||
//
|
||||
// A wrapper around a MacOS native scrollbar that knows how to work
|
||||
// with a stub gecko frame to scroll in the GFXScrollFrame mechanism
|
||||
//
|
||||
|
||||
class nsNativeScrollbar : public nsChildView, public nsINativeScrollbar
|
||||
{
|
||||
private:
|
||||
typedef nsChildView Inherited;
|
||||
|
||||
public:
|
||||
nsNativeScrollbar();
|
||||
virtual ~nsNativeScrollbar();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSINATIVESCROLLBAR
|
||||
|
||||
// called from the NativeScrollbarView when someone hits a part
|
||||
// of the scrollbar.
|
||||
void DoScroll(NSScrollerPart inPart);
|
||||
|
||||
protected:
|
||||
|
||||
// nsWindow Interface
|
||||
virtual PRBool DispatchMouseEvent(nsMouseEvent &aEvent);
|
||||
NS_IMETHOD Enable(PRBool aState);
|
||||
NS_IMETHOD IsEnabled(PRBool* outState);
|
||||
|
||||
NSScroller* GetControl() { return (NSScroller*)mView; }
|
||||
|
||||
void UpdateContentPosition(PRUint32 inNewPos);
|
||||
|
||||
void RecreateHorizontalScrollbar();
|
||||
|
||||
virtual NSView* CreateCocoaView(NSRect inFrame);
|
||||
|
||||
void UpdateScroller();
|
||||
|
||||
NativeScrollbarView* ScrollbarView() const { return (NativeScrollbarView*)mView; }
|
||||
|
||||
// DATA
|
||||
private:
|
||||
|
||||
nsIContent* mContent; // the content node that affects the scrollbar's value
|
||||
nsIScrollbarMediator* mMediator; // for scrolling with outliners
|
||||
nsISupports* mScrollbar; // for calling into the mediator
|
||||
|
||||
PRUint32 mValue;
|
||||
PRUint32 mMaxValue;
|
||||
PRUint32 mVisibleImageSize;
|
||||
PRUint32 mLineIncrement;
|
||||
PRBool mIsEnabled;
|
||||
};
|
||||
|
||||
|
||||
@interface NativeScrollbarView : NSScroller<mozView>
|
||||
{
|
||||
// Our window [WEAK]
|
||||
NSWindow* mWindow;
|
||||
|
||||
// the nsNativeScrollbar that created this view. It retains this NSView, so
|
||||
// the link back to it must be weak. [WEAK]
|
||||
nsNativeScrollbar* mGeckoChild;
|
||||
|
||||
// YES when we're in a tracking loop
|
||||
BOOL mInTracking;
|
||||
|
||||
// rects that were invalidated during a draw, so have pending drawing
|
||||
NSMutableArray* mPendingDirtyRects;
|
||||
BOOL mPendingFullDisplay;
|
||||
}
|
||||
|
||||
// default initializer
|
||||
- (id)initWithFrame:(NSRect)frameRect geckoChild:(nsNativeScrollbar*)inChild;
|
||||
// overridden parent class initializer
|
||||
- (id)initWithFrame:(NSRect)frameRect;
|
||||
|
||||
- (IBAction)scroll:(NSScroller*)sender;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#endif // nsNativeScrollbar_h_
|
||||
@@ -1,775 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Mark Mentovai <mark@moxienet.com>
|
||||
* Stuart Morgan <stuart.morgan@alumni.case.edu>
|
||||
* Josh Aas <josh@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
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsNativeScrollbar.h"
|
||||
#include "nsIDeviceContext.h"
|
||||
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsWidgetAtoms.h"
|
||||
#include "nsINameSpaceManager.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIScrollbarMediator.h"
|
||||
#include "nsIRollupListener.h"
|
||||
|
||||
// category of NSScroller methods to quiet warnings
|
||||
|
||||
@interface NSScroller(NativeScrollViewExtensions)
|
||||
- (void)trackPagingArea:(id)aEvent;
|
||||
@end
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(nsNativeScrollbar, nsChildView, nsINativeScrollbar)
|
||||
|
||||
static const float kHorizScrollbarInitW = 100;
|
||||
static const float kHorizScrollbarInitH = 16;
|
||||
|
||||
extern nsIRollupListener * gRollupListener;
|
||||
extern nsIWidget * gRollupWidget;
|
||||
|
||||
inline void BoundsCheck(PRInt32 low, PRUint32& value, PRUint32 high)
|
||||
{
|
||||
if ((PRInt32) value < low)
|
||||
value = low;
|
||||
if (value > high)
|
||||
value = high;
|
||||
}
|
||||
|
||||
nsNativeScrollbar::nsNativeScrollbar()
|
||||
: nsChildView()
|
||||
, mContent(nsnull)
|
||||
, mMediator(nsnull)
|
||||
, mScrollbar(nsnull)
|
||||
, mValue(0)
|
||||
, mMaxValue(0)
|
||||
, mVisibleImageSize(0)
|
||||
, mLineIncrement(0)
|
||||
, mIsEnabled(PR_TRUE)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
nsNativeScrollbar::~nsNativeScrollbar()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// CreateCocoaView
|
||||
//
|
||||
// Create a NativeScrollbarView for insertion into the cocoa view hierarchy.
|
||||
// Cocoa sets the orientation of a scrollbar at creation time by looking
|
||||
// at its frame and taking the longer side to be the orientation. Since
|
||||
// chances are good at this point gecko just wants us to be 1x1, assume
|
||||
// we're going to be vertical. If later when we get a content node assigned
|
||||
// we find we're horizontal, we can update then.
|
||||
//
|
||||
NSView*
|
||||
nsNativeScrollbar::CreateCocoaView(NSRect inFrame)
|
||||
{
|
||||
return [[[NativeScrollbarView alloc] initWithFrame:inFrame geckoChild:this] autorelease];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// DoScroll
|
||||
//
|
||||
// Called from the action proc of the scrollbar, adjust the control's
|
||||
// value as well as the value in the content node which communicates
|
||||
// to gecko that the document is scrolling.
|
||||
//
|
||||
void
|
||||
nsNativeScrollbar::DoScroll(NSScrollerPart inPart)
|
||||
{
|
||||
PRUint32 oldPos, newPos;
|
||||
PRUint32 incr;
|
||||
PRUint32 visibleImageSize;
|
||||
GetPosition(&oldPos);
|
||||
GetLineIncrement(&incr);
|
||||
GetViewSize(&visibleImageSize);
|
||||
switch ( inPart ) {
|
||||
|
||||
//
|
||||
// For the up/down buttons, scroll up or down by the line height and
|
||||
// update the attributes on the content node (the scroll frame listens
|
||||
// for these attributes and will scroll accordingly). However,
|
||||
// if we have a mediator, we're in an outliner and we have to scroll by
|
||||
// lines. Outliner ignores the params to ScrollbarButtonPressed() except
|
||||
// to check if one is greater than the other to indicate direction.
|
||||
//
|
||||
|
||||
case NSScrollerDecrementLine: // scroll up/left
|
||||
newPos = oldPos - (mLineIncrement ? mLineIncrement : 1);
|
||||
if ( mMediator ) {
|
||||
BoundsCheck(0, newPos, mMaxValue);
|
||||
mMediator->ScrollbarButtonPressed(mScrollbar, oldPos, newPos);
|
||||
} else {
|
||||
UpdateContentPosition(newPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case NSScrollerIncrementLine: // scroll down/right
|
||||
newPos = oldPos + (mLineIncrement ? mLineIncrement : 1);
|
||||
if ( mMediator ) {
|
||||
BoundsCheck(0, newPos, mMaxValue);
|
||||
mMediator->ScrollbarButtonPressed(mScrollbar, oldPos, newPos);
|
||||
} else {
|
||||
UpdateContentPosition(newPos);
|
||||
}
|
||||
break;
|
||||
|
||||
//
|
||||
// For page up/down, scroll by the page height and update the attributes
|
||||
// on the content node (as above). If we have a mediator, we're in an
|
||||
// outliner so tell it directly that the position has changed. Note that
|
||||
// outliner takes signed values, so we have to convert our unsigned to
|
||||
// signed values first.
|
||||
//
|
||||
|
||||
case NSScrollerDecrementPage: // scroll up a page
|
||||
newPos = oldPos - visibleImageSize;
|
||||
UpdateContentPosition(newPos);
|
||||
if ( mMediator ) {
|
||||
PRInt32 op = oldPos, np = mValue;
|
||||
if ( np < 0 )
|
||||
np = 0;
|
||||
mMediator->PositionChanged(mScrollbar, op, np);
|
||||
}
|
||||
break;
|
||||
|
||||
case NSScrollerIncrementPage: // scroll down a page
|
||||
newPos = oldPos + visibleImageSize;
|
||||
UpdateContentPosition(newPos);
|
||||
if ( mMediator ) {
|
||||
PRInt32 op = oldPos, np = mValue;
|
||||
if ( np < 0 )
|
||||
np = 0;
|
||||
mMediator->PositionChanged(mScrollbar, op, np);
|
||||
}
|
||||
break;
|
||||
|
||||
//
|
||||
// The scroller handles changing the value on the thumb for
|
||||
// us, so read it, convert it back to the range gecko is expecting,
|
||||
// and tell the content.
|
||||
//
|
||||
case NSScrollerKnob:
|
||||
case NSScrollerKnobSlot:
|
||||
newPos = (int) ([ScrollbarView() floatValue] * mMaxValue);
|
||||
UpdateContentPosition(newPos);
|
||||
if ( mMediator ) {
|
||||
PRInt32 op = oldPos, np = mValue;
|
||||
if ( np < 0 )
|
||||
np = 0;
|
||||
mMediator->PositionChanged(mScrollbar, op, np);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
; // do nothing
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// UpdateContentPosition
|
||||
//
|
||||
// Tell the content node that the scrollbar has changed value and
|
||||
// then update the scrollbar's position
|
||||
//
|
||||
void
|
||||
nsNativeScrollbar::UpdateContentPosition(PRUint32 inNewPos)
|
||||
{
|
||||
if ( inNewPos == mValue || !mContent ) // break any possible recursion
|
||||
return;
|
||||
|
||||
// guarantee |inNewPos| is in the range of [0, mMaxValue] so it's correctly unsigned
|
||||
BoundsCheck(0, inNewPos, mMaxValue);
|
||||
|
||||
// convert the int to a string
|
||||
nsAutoString buffer;
|
||||
buffer.AppendInt(inNewPos);
|
||||
|
||||
mContent->SetAttr(kNameSpaceID_None, nsWidgetAtoms::curpos, buffer, PR_TRUE);
|
||||
SetPosition(inNewPos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// DispatchMouseEvent
|
||||
//
|
||||
// We don't need to do much here, cocoa will handle tracking the mouse for us. Returning
|
||||
// true means that the event is handled.
|
||||
//
|
||||
PRBool
|
||||
nsNativeScrollbar::DispatchMouseEvent(nsMouseEvent &aEvent)
|
||||
{
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// SetMaxRange
|
||||
//
|
||||
// Set the maximum range of a scroll bar. This should be set to the
|
||||
// full scrollable area minus the visible area.
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsNativeScrollbar::SetMaxRange(PRUint32 aEndRange)
|
||||
{
|
||||
if ((PRInt32)aEndRange < 0)
|
||||
aEndRange = 0;
|
||||
|
||||
mMaxValue = aEndRange;
|
||||
UpdateScroller();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// GetMaxRange
|
||||
//
|
||||
// Get the maximum range of a scroll bar
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsNativeScrollbar::GetMaxRange(PRUint32* aMaxRange)
|
||||
{
|
||||
*aMaxRange = mMaxValue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// SetPosition
|
||||
//
|
||||
// Set the current position of the slider and redraw the scrollbar. We have
|
||||
// to convert between the integer values gecko uses (0,mMaxValue) to the float
|
||||
// values that cocoa uses (0,1).
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsNativeScrollbar::SetPosition(PRUint32 aPos)
|
||||
{
|
||||
NativeScrollbarView* scrollbarView = ScrollbarView();
|
||||
|
||||
if ((PRInt32)aPos < 0)
|
||||
aPos = 0;
|
||||
|
||||
// while we _should_ be ensuring that we don't set our value higher
|
||||
// than our max value, the gfx scrollview code plays fast and loose
|
||||
// with the rules while going back/forward and adjusts the value to the
|
||||
// previous value long before it sets the max. As a result, we would
|
||||
// lose the given value (since max would most likely be 0). The only
|
||||
// way around that is to relax our restrictions a little bit. (bug 135191)
|
||||
// mValue = ((PRInt32)aPos) > mMaxValue ? mMaxValue : ((int)aPos);
|
||||
mValue = aPos;
|
||||
if ( mMaxValue )
|
||||
[scrollbarView setFloatValue:(mValue / (float)mMaxValue)];
|
||||
else
|
||||
[scrollbarView setFloatValue:0.0];
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// GetPosition
|
||||
//
|
||||
// Get the current position of the slider
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsNativeScrollbar::GetPosition(PRUint32* aPos)
|
||||
{
|
||||
*aPos = mValue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// SetViewSize
|
||||
//
|
||||
// Change the knob proportion to be the ratio of the size of the visible image (given in |aSize|)
|
||||
// to the total area (visible + max). Recall that the max size is the total minus the
|
||||
// visible area.
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsNativeScrollbar::SetViewSize(PRUint32 aSize)
|
||||
{
|
||||
if ((PRInt32)aSize < 0)
|
||||
aSize = 0;
|
||||
|
||||
mVisibleImageSize = aSize;
|
||||
|
||||
UpdateScroller();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// GetViewSize
|
||||
//
|
||||
// Get the height of the visible view area.
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsNativeScrollbar::GetViewSize(PRUint32* aSize)
|
||||
{
|
||||
*aSize = mVisibleImageSize;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// SetLineIncrement
|
||||
//
|
||||
// Set the line increment of the scroll bar
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsNativeScrollbar::SetLineIncrement(PRUint32 aLineIncrement)
|
||||
{
|
||||
mLineIncrement = (((int)aLineIncrement) > 0 ? aLineIncrement : 1);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// GetLineIncrement
|
||||
//
|
||||
// Get the line increment of the scroll bar
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsNativeScrollbar::GetLineIncrement(PRUint32* aLineIncrement)
|
||||
{
|
||||
*aLineIncrement = mLineIncrement;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// GetNarrowSize
|
||||
//
|
||||
// Ask the appearance manager for the dimensions of the narrow axis
|
||||
// of the scrollbar. We cheat and assume the width of a vertical scrollbar
|
||||
// is the same as the height of a horizontal scrollbar. *shrug*. Shoot me.
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsNativeScrollbar::GetNarrowSize(PRInt32* outSize)
|
||||
{
|
||||
if ( *outSize )
|
||||
return NS_ERROR_FAILURE;
|
||||
SInt32 width = 0;
|
||||
::GetThemeMetric(kThemeMetricScrollBarWidth, &width);
|
||||
*outSize = width;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// SetContent
|
||||
//
|
||||
// Hook up this native scrollbar to the rest of gecko. We care about
|
||||
// the content so we can set attributes on it to affect the scrollview. We
|
||||
// care about the mediator for <outliner> so we can do row-based scrolling.
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsNativeScrollbar::SetContent(nsIContent* inContent, nsISupports* inScrollbar,
|
||||
nsIScrollbarMediator* inMediator)
|
||||
{
|
||||
mContent = inContent;
|
||||
mMediator = inMediator;
|
||||
mScrollbar = inScrollbar;
|
||||
|
||||
if ( mContent ) {
|
||||
// we may have to re-create the scrollbar view as horizontal. Check the
|
||||
// 'orient' attribute and rebuild the view with all the settings
|
||||
// present in the current view
|
||||
if (mContent->AttrValueIs(kNameSpaceID_None, nsWidgetAtoms::orient,
|
||||
nsWidgetAtoms::horizontal, eCaseMatters))
|
||||
RecreateHorizontalScrollbar();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// RecreateHorizontalScrollbar
|
||||
//
|
||||
// Replace the vertical scroller we created earlier with a horizontal scroller
|
||||
// of the same dimensions and values
|
||||
//
|
||||
void
|
||||
nsNativeScrollbar::RecreateHorizontalScrollbar()
|
||||
{
|
||||
// Use a horizontal frame so that Cocoa thinks it's a horizontal scroller.
|
||||
NSRect orientation = NSMakeRect(0, 0,
|
||||
kHorizScrollbarInitW, kHorizScrollbarInitH);
|
||||
|
||||
NativeScrollbarView* oldScrollbarView = ScrollbarView();
|
||||
|
||||
// Create the new horizontal scroller, init it, and reset the old values.
|
||||
mView = [[NativeScrollbarView alloc] initWithFrame:orientation
|
||||
geckoChild:this];
|
||||
|
||||
NativeScrollbarView* newScrollbarView = ScrollbarView();
|
||||
|
||||
[newScrollbarView setNativeWindow:[oldScrollbarView nativeWindow]];
|
||||
[newScrollbarView setFrame:[oldScrollbarView bounds]];
|
||||
|
||||
[newScrollbarView setHidden:[oldScrollbarView isHidden]];
|
||||
[newScrollbarView setEnabled:[oldScrollbarView isEnabled]];
|
||||
[newScrollbarView setFloatValue:[oldScrollbarView floatValue]
|
||||
knobProportion:[oldScrollbarView knobProportion]];
|
||||
|
||||
// Hook up the new view and get rid of the previous one.
|
||||
[mParentView replaceSubview:oldScrollbarView with:newScrollbarView];
|
||||
[oldScrollbarView release];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Enable
|
||||
//
|
||||
// Enable/disable this scrollbar
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsNativeScrollbar::Enable(PRBool aState)
|
||||
{
|
||||
if (aState != mVisible) {
|
||||
mIsEnabled = aState;
|
||||
UpdateScroller();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNativeScrollbar::IsEnabled(PRBool* outState)
|
||||
{
|
||||
if (outState)
|
||||
*outState = mIsEnabled;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsNativeScrollbar::UpdateScroller()
|
||||
{
|
||||
NativeScrollbarView* scrollbarView = ScrollbarView();
|
||||
|
||||
// Update the current value based on the new range. We need to recompute the
|
||||
// float value in case we had to set the value to 0 because gecko cheated
|
||||
// and set the position before it set the max value.
|
||||
float knobProp = 1.0f;
|
||||
if ((mVisibleImageSize + mMaxValue) > 0)
|
||||
knobProp = (float)mVisibleImageSize / (float)(mVisibleImageSize + mMaxValue);
|
||||
[scrollbarView setFloatValue:(mValue / (float)mMaxValue) knobProportion:knobProp];
|
||||
|
||||
BOOL enableScrollbar = (mIsEnabled && (mMaxValue > 0));
|
||||
[scrollbarView setEnabled:enableScrollbar];
|
||||
|
||||
Invalidate(FALSE);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface NativeScrollbarView(Private)
|
||||
|
||||
- (void)processPendingRedraws;
|
||||
|
||||
@end
|
||||
|
||||
@implementation NativeScrollbarView
|
||||
|
||||
//
|
||||
// -initWithFrame:geckoChild
|
||||
// Designated Initializer
|
||||
//
|
||||
// Init our superclass and make the connection to the gecko nsIWidget we're
|
||||
// mirroring
|
||||
//
|
||||
- (id)initWithFrame:(NSRect)frameRect geckoChild:(nsNativeScrollbar*)inChild
|
||||
{
|
||||
if ((self = [super initWithFrame:frameRect]))
|
||||
{
|
||||
NS_ASSERTION(inChild, "Need to provide a tether between this and a nsChildView class");
|
||||
mGeckoChild = inChild;
|
||||
|
||||
// make ourselves the target of the scroll and set the action message
|
||||
[self setTarget:self];
|
||||
[self setAction:@selector(scroll:)];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// -initWithFrame
|
||||
//
|
||||
// overridden parent class initializer
|
||||
//
|
||||
- (id)initWithFrame:(NSRect)frameRect
|
||||
{
|
||||
NS_WARNING("You're calling the wrong initializer. You really want -initWithFrame:geckoChild");
|
||||
if ((self = [self initWithFrame:frameRect geckoChild:nsnull]))
|
||||
{
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)setFrame:(NSRect)frameRect
|
||||
{
|
||||
// maybe make this a small scrollbar
|
||||
SInt32 smallScrollbarWidth = 0;
|
||||
::GetThemeMetric(kThemeMetricSmallScrollBarWidth, &smallScrollbarWidth);
|
||||
if ((SInt32)frameRect.size.width == smallScrollbarWidth ||
|
||||
(SInt32)frameRect.size.height == smallScrollbarWidth) {
|
||||
[self setControlSize:NSSmallControlSize];
|
||||
}
|
||||
else {
|
||||
[self setControlSize:NSRegularControlSize];
|
||||
}
|
||||
|
||||
[super setFrame:frameRect];
|
||||
}
|
||||
|
||||
|
||||
- (NSWindow*)nativeWindow
|
||||
{
|
||||
NSWindow* currWin = [self window];
|
||||
if (currWin)
|
||||
return currWin;
|
||||
else
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
- (void) setNativeWindow: (NSWindow*)aWindow
|
||||
{
|
||||
mWindow = aWindow;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)isFlipped
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// -widget
|
||||
//
|
||||
// return our gecko child view widget. Note this does not AddRef.
|
||||
//
|
||||
- (nsIWidget*) widget
|
||||
{
|
||||
return NS_STATIC_CAST(nsIWidget*, mGeckoChild);
|
||||
}
|
||||
|
||||
- (void)setNeedsPendingDisplay
|
||||
{
|
||||
mPendingFullDisplay = YES;
|
||||
[self performSelector:@selector(processPendingRedraws) withObject:nil afterDelay:0];
|
||||
}
|
||||
|
||||
- (void)setNeedsPendingDisplayInRect:(NSRect)invalidRect
|
||||
{
|
||||
if (!mPendingDirtyRects)
|
||||
mPendingDirtyRects = [[NSMutableArray alloc] initWithCapacity:1];
|
||||
[mPendingDirtyRects addObject:[NSValue valueWithRect:invalidRect]];
|
||||
[self performSelector:@selector(processPendingRedraws) withObject:nil afterDelay:0];
|
||||
}
|
||||
|
||||
//
|
||||
// -processPendingRedraws
|
||||
//
|
||||
// Clears the queue of any pending invalides
|
||||
//
|
||||
- (void)processPendingRedraws
|
||||
{
|
||||
if (mPendingFullDisplay) {
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
else {
|
||||
unsigned int count = [mPendingDirtyRects count];
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
[self setNeedsDisplayInRect:[[mPendingDirtyRects objectAtIndex:i] rectValue]];
|
||||
}
|
||||
}
|
||||
mPendingFullDisplay = NO;
|
||||
[mPendingDirtyRects release];
|
||||
mPendingDirtyRects = nil;
|
||||
}
|
||||
|
||||
- (void)scrollRect:(NSRect)aRect by:(NSSize)offset
|
||||
{
|
||||
// Update any pending dirty rects to reflect the new scroll position
|
||||
if (mPendingDirtyRects) {
|
||||
unsigned int count = [mPendingDirtyRects count];
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
NSRect oldRect = [[mPendingDirtyRects objectAtIndex:i] rectValue];
|
||||
NSRect newRect = NSOffsetRect(oldRect, offset.width, offset.height);
|
||||
[mPendingDirtyRects replaceObjectAtIndex:i
|
||||
withObject:[NSValue valueWithRect:newRect]];
|
||||
}
|
||||
}
|
||||
[super scrollRect:aRect by:offset];
|
||||
}
|
||||
|
||||
//
|
||||
// -mouseMoved
|
||||
//
|
||||
// our parent view will try to forward this message down to us. The
|
||||
// default behavior for NSResponder is to forward it up the chain. Can you
|
||||
// say "infinite recursion"? I thought so. Just stub out the action to
|
||||
// break the cycle of madness.
|
||||
//
|
||||
- (void)mouseMoved:(NSEvent*)theEvent
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
//
|
||||
// -widgetDestroyed
|
||||
//
|
||||
// the gecko nsNativeScrollbar is being destroyed.
|
||||
//
|
||||
- (void)widgetDestroyed
|
||||
{
|
||||
mGeckoChild = nsnull;
|
||||
|
||||
if (mInTracking)
|
||||
{
|
||||
// To get out of the NSScroller tracking loop, we post a fake mouseup event.
|
||||
// We have to do this here, before we are ripped out of the view hierarchy.
|
||||
[NSApp postEvent:[NSEvent mouseEventWithType:NSLeftMouseUp
|
||||
location:[NSEvent mouseLocation]
|
||||
modifierFlags:0
|
||||
timestamp:[[NSApp currentEvent] timestamp]
|
||||
windowNumber:[[self window] windowNumber]
|
||||
context:NULL
|
||||
eventNumber:0
|
||||
clickCount:0
|
||||
pressure:1.0]
|
||||
atStart:YES];
|
||||
|
||||
mInTracking = NO;
|
||||
}
|
||||
}
|
||||
|
||||
// contextMenu, from mozView protocol
|
||||
- (NSMenu*)contextMenu
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
//
|
||||
// -scroll
|
||||
//
|
||||
// the action message we've set up to be called when the scrollbar needs
|
||||
// to adjust its value. Feed back into the owning widget to process
|
||||
// how much to scroll and adjust the correct attributes.
|
||||
//
|
||||
- (IBAction)scroll:(NSScroller*)sender
|
||||
{
|
||||
// roll up popup windows if there are any
|
||||
if (gRollupListener && gRollupWidget &&
|
||||
gRollupWidget->GetNativeData(NS_NATIVE_WINDOW) != [self nativeWindow]) {
|
||||
gRollupListener->Rollup();
|
||||
}
|
||||
|
||||
if (mGeckoChild)
|
||||
mGeckoChild->DoScroll([sender hitPart]);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// -trackKnob:
|
||||
//
|
||||
// overridden to toggle mInTracking on and off
|
||||
//
|
||||
- (void)trackKnob:(NSEvent *)theEvent
|
||||
{
|
||||
mInTracking = YES;
|
||||
NS_DURING // be sure we always turn mInTracking off.
|
||||
[super trackKnob:theEvent];
|
||||
NS_HANDLER
|
||||
NS_ENDHANDLER
|
||||
mInTracking = NO;
|
||||
}
|
||||
|
||||
//
|
||||
// -trackScrollButtons:
|
||||
//
|
||||
// overridden to toggle mInTracking on and off
|
||||
//
|
||||
- (void)trackScrollButtons:(NSEvent *)theEvent
|
||||
{
|
||||
mInTracking = YES;
|
||||
NS_DURING // be sure we always turn mInTracking off.
|
||||
[super trackScrollButtons:theEvent];
|
||||
NS_HANDLER
|
||||
NS_ENDHANDLER
|
||||
mInTracking = NO;
|
||||
}
|
||||
|
||||
//
|
||||
// -trackPagingArea:
|
||||
//
|
||||
// this method is not documented, but was seen in sampling. We have
|
||||
// to override it to toggle mInTracking.
|
||||
//
|
||||
- (void)trackPagingArea:(id)theEvent
|
||||
{
|
||||
mInTracking = YES;
|
||||
NS_DURING // be sure we always turn mInTracking off.
|
||||
[super trackPagingArea:theEvent];
|
||||
NS_HANDLER
|
||||
NS_ENDHANDLER
|
||||
mInTracking = NO;
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
// XXXhakan: need to find out what needs to be done here to make these scrollbars accessible.
|
||||
- (BOOL)accessibilityIsIgnored
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@@ -92,7 +92,7 @@ protected:
|
||||
static const int kAquaMinButtonWidth = 68;
|
||||
static const int kAquaDropdownLeftEndcap = 9;
|
||||
static const int kAquaDropwdonRightEndcap = 20; // wider on right to encompass the button
|
||||
|
||||
|
||||
nsresult GetSystemColor(PRUint8 aWidgetType, nsILookAndFeel::nsColorID& aColorID);
|
||||
nsresult GetSystemFont(PRUint8 aWidgetType, nsSystemFontID& aFont);
|
||||
|
||||
@@ -125,6 +125,12 @@ protected:
|
||||
void DrawCheckboxRadio (CGContextRef context, ThemeButtonKind inKind,
|
||||
const HIRect& inBoxRect, PRBool inChecked,
|
||||
PRBool inDisabled, PRInt32 inState);
|
||||
// Scrollbars
|
||||
void DrawScrollbar(CGContextRef aCGContext, const HIRect& aBoxRect, nsIFrame *aFrame);
|
||||
void GetScrollbarPressStates (nsIFrame *aFrame, PRInt32 aButtonStates[]);
|
||||
void GetScrollbarDrawInfo (HIThemeTrackDrawInfo& aTdi, nsIFrame *aFrame,
|
||||
const HIRect& aRect, PRBool aShouldGetButtonStates);
|
||||
nsIFrame* GetParentScrollbarFrame(nsIFrame *aFrame);
|
||||
};
|
||||
|
||||
#endif // nsNativeThemeCocoa_h_
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com> (HITheme rewrite)
|
||||
* Josh Aas <josh@mozilla.com>
|
||||
* Colin Barrett <cbarrett@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
@@ -58,11 +59,16 @@
|
||||
#include "gfxQuartzSurface.h"
|
||||
|
||||
#define DRAW_IN_FRAME_DEBUG 0
|
||||
#define SCROLLBARS_VISUAL_DEBUG 0
|
||||
|
||||
extern "C" {
|
||||
CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
|
||||
}
|
||||
|
||||
// Copied from nsLookAndFeel.h
|
||||
// Apple hasn't defined a constant for scollbars with two arrows on each end, so we'll use this one.
|
||||
static const int kThemeScrollBarArrowsBoth = 2;
|
||||
|
||||
#define HITHEME_ORIENTATION kHIThemeOrientationNormal
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsNativeThemeCocoa, nsITheme)
|
||||
@@ -105,6 +111,7 @@ nsNativeThemeCocoa::DrawCheckboxRadio(CGContextRef cgContext, ThemeButtonKind in
|
||||
HIThemeDrawButton(&inBoxRect, &bdi, cgContext, HITHEME_ORIENTATION, NULL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsNativeThemeCocoa::DrawButton(CGContextRef cgContext, ThemeButtonKind inKind,
|
||||
const HIRect& inBoxRect, PRBool inIsDefault, PRBool inDisabled,
|
||||
@@ -154,6 +161,7 @@ nsNativeThemeCocoa::DrawButton(CGContextRef cgContext, ThemeButtonKind inKind,
|
||||
HIThemeDrawButton(&drawRect, &bdi, cgContext, HITHEME_ORIENTATION, NULL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsNativeThemeCocoa::DrawSpinButtons(CGContextRef cgContext, ThemeButtonKind inKind,
|
||||
const HIRect& inBoxRect, PRBool inDisabled,
|
||||
@@ -174,6 +182,7 @@ nsNativeThemeCocoa::DrawSpinButtons(CGContextRef cgContext, ThemeButtonKind inKi
|
||||
HIThemeDrawButton(&inBoxRect, &bdi, cgContext, HITHEME_ORIENTATION, NULL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsNativeThemeCocoa::DrawFrame(CGContextRef cgContext, HIThemeFrameKind inKind,
|
||||
const HIRect& inBoxRect, PRBool inIsDisabled, PRInt32 inState)
|
||||
@@ -208,6 +217,7 @@ nsNativeThemeCocoa::DrawFrame(CGContextRef cgContext, HIThemeFrameKind inKind,
|
||||
HIThemeDrawFrame(&drawRect, &fdi, cgContext, HITHEME_ORIENTATION);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsNativeThemeCocoa::DrawProgress(CGContextRef cgContext,
|
||||
const HIRect& inBoxRect, PRBool inIsIndeterminate,
|
||||
@@ -306,6 +316,114 @@ nsNativeThemeCocoa::DrawTab(CGContextRef cgContext, const HIRect& inBoxRect,
|
||||
HIThemeDrawTab(&inBoxRect, &tdi, cgContext, HITHEME_ORIENTATION, NULL);
|
||||
}
|
||||
|
||||
|
||||
static UInt8
|
||||
ConvertToPressState(PRInt32 aButtonState, UInt8 aPressState)
|
||||
{
|
||||
// If the button is pressed, return the press state passed in. Otherwise, return 0.
|
||||
return ((aButtonState & NS_EVENT_STATE_ACTIVE) && (aButtonState & NS_EVENT_STATE_HOVER)) ? aPressState : 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsNativeThemeCocoa::GetScrollbarPressStates(nsIFrame *aFrame, PRInt32 aButtonStates[])
|
||||
{
|
||||
static nsIContent::AttrValuesArray attributeValues[] = {
|
||||
&nsWidgetAtoms::scrollbarUpTop,
|
||||
&nsWidgetAtoms::scrollbarDownTop,
|
||||
&nsWidgetAtoms::scrollbarUpBottom,
|
||||
&nsWidgetAtoms::scrollbarDownBottom,
|
||||
nsnull
|
||||
};
|
||||
|
||||
// Get the state of any scrollbar buttons in our child frames
|
||||
for (nsIFrame *childFrame = aFrame->GetFirstChild(nsnull);
|
||||
childFrame;
|
||||
childFrame = childFrame->GetNextSibling()) {
|
||||
|
||||
nsIContent *childContent = childFrame->GetContent();
|
||||
if (!childContent) continue;
|
||||
PRInt32 attrIndex = childContent->FindAttrValueIn(kNameSpaceID_None, nsWidgetAtoms::sbattr,
|
||||
attributeValues, eCaseMatters);
|
||||
if (attrIndex < 0) continue;
|
||||
|
||||
PRInt32 currentState = GetContentState(childFrame, NS_THEME_BUTTON);
|
||||
aButtonStates[attrIndex] = currentState;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsNativeThemeCocoa::GetScrollbarDrawInfo(HIThemeTrackDrawInfo& aTdi, nsIFrame *aFrame,
|
||||
const HIRect& aRect, PRBool aShouldGetButtonStates)
|
||||
{
|
||||
PRInt32 curpos = CheckIntAttr(aFrame, nsWidgetAtoms::curpos);
|
||||
PRInt32 minpos = CheckIntAttr(aFrame, nsWidgetAtoms::minpos);
|
||||
PRInt32 maxpos = CheckIntAttr(aFrame, nsWidgetAtoms::maxpos);
|
||||
|
||||
PRBool isHorizontal = aFrame->GetContent()->AttrValueIs(kNameSpaceID_None, nsWidgetAtoms::orient,
|
||||
nsWidgetAtoms::horizontal, eCaseMatters);
|
||||
PRBool isSmall = aFrame->GetStyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL;
|
||||
|
||||
aTdi.version = 0;
|
||||
aTdi.kind = isSmall ? kThemeSmallScrollBar : kThemeMediumScrollBar;
|
||||
aTdi.bounds = aRect;
|
||||
aTdi.min = minpos;
|
||||
aTdi.max = maxpos;
|
||||
aTdi.value = curpos;
|
||||
aTdi.attributes = kThemeTrackShowThumb;
|
||||
if (isHorizontal)
|
||||
aTdi.attributes |= kThemeTrackHorizontal;
|
||||
|
||||
aTdi.trackInfo.scrollbar.viewsize = (SInt32)(isHorizontal ? (aRect.size.width) : (aRect.size.height));
|
||||
|
||||
// Only go get these scrollbar button states if we need it. For example, there's no reaon to look up scrollbar button
|
||||
// states when we're only creating a TrackDrawInfo to determine the size of the thumb.
|
||||
if (aShouldGetButtonStates) {
|
||||
PRInt32 buttonStates[] = {0, 0, 0, 0};
|
||||
GetScrollbarPressStates(aFrame, buttonStates);
|
||||
ThemeScrollBarArrowStyle arrowStyle;
|
||||
::GetThemeScrollBarArrowStyle(&arrowStyle);
|
||||
// If all four buttons are visible
|
||||
if (arrowStyle == kThemeScrollBarArrowsBoth) {
|
||||
aTdi.trackInfo.scrollbar.pressState = ConvertToPressState(buttonStates[0], kThemeTopOutsideArrowPressed) |
|
||||
ConvertToPressState(buttonStates[1], kThemeTopInsideArrowPressed) |
|
||||
ConvertToPressState(buttonStates[2], kThemeBottomInsideArrowPressed) |
|
||||
ConvertToPressState(buttonStates[3], kThemeBottomOutsideArrowPressed);
|
||||
} else {
|
||||
// It seems that unless all four buttons are showing, kThemeTopOutsideArrowPressed is the correct constant for
|
||||
// the up scrollbar button.
|
||||
aTdi.trackInfo.scrollbar.pressState = ConvertToPressState(buttonStates[0], kThemeTopOutsideArrowPressed) |
|
||||
ConvertToPressState(buttonStates[2], kThemeTopOutsideArrowPressed) |
|
||||
ConvertToPressState(buttonStates[3], kThemeBottomOutsideArrowPressed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsNativeThemeCocoa::DrawScrollbar(CGContextRef aCGContext, const HIRect& aBoxRect, nsIFrame *aFrame)
|
||||
{
|
||||
HIThemeTrackDrawInfo tdi;
|
||||
GetScrollbarDrawInfo(tdi, aFrame, aBoxRect, PR_TRUE); //True means we want the press states
|
||||
::HIThemeDrawTrack(&tdi, NULL, aCGContext, HITHEME_ORIENTATION);
|
||||
}
|
||||
|
||||
|
||||
nsIFrame*
|
||||
nsNativeThemeCocoa::GetParentScrollbarFrame(nsIFrame *aFrame)
|
||||
{
|
||||
// Walk our parents to find a scrollbar frame
|
||||
nsIFrame *scrollbarFrame = aFrame;
|
||||
do {
|
||||
if (scrollbarFrame->GetType() == nsWidgetAtoms::scrollbarFrame) break;
|
||||
} while ((scrollbarFrame = scrollbarFrame->GetParent()));
|
||||
|
||||
// We return null if we can't find a parent scrollbar frame
|
||||
return scrollbarFrame;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNativeThemeCocoa::DrawWidgetBackground(nsIRenderingContext* aContext, nsIFrame* aFrame,
|
||||
PRUint8 aWidgetType, const nsRect& aRect,
|
||||
@@ -627,18 +745,35 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsIRenderingContext* aContext, nsIFrame
|
||||
// do nothing, drawn by scale
|
||||
break;
|
||||
|
||||
case NS_THEME_SCROLLBAR_GRIPPER_HORIZONTAL:
|
||||
case NS_THEME_SCROLLBAR_GRIPPER_VERTICAL:
|
||||
case NS_THEME_SCROLLBAR_SMALL:
|
||||
case NS_THEME_SCROLLBAR: {
|
||||
DrawScrollbar(cgContext, macRect, aFrame);
|
||||
}
|
||||
break;
|
||||
case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
|
||||
case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
|
||||
#if SCROLLBARS_VISUAL_DEBUG
|
||||
CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 0, 0.6);
|
||||
CGContextFillRect(cgContext, macRect);
|
||||
break;
|
||||
#endif
|
||||
case NS_THEME_SCROLLBAR_BUTTON_UP:
|
||||
case NS_THEME_SCROLLBAR_BUTTON_LEFT:
|
||||
#if SCROLLBARS_VISUAL_DEBUG
|
||||
CGContextSetRGBFillColor(cgContext, 1.0, 0, 0, 0.6);
|
||||
CGContextFillRect(cgContext, macRect);
|
||||
break;
|
||||
#endif
|
||||
case NS_THEME_SCROLLBAR_BUTTON_DOWN:
|
||||
case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
|
||||
#if SCROLLBARS_VISUAL_DEBUG
|
||||
CGContextSetRGBFillColor(cgContext, 0, 1.0, 0, 0.6);
|
||||
CGContextFillRect(cgContext, macRect);
|
||||
break;
|
||||
#endif
|
||||
case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
|
||||
case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
|
||||
case NS_THEME_SCROLLBAR_BUTTON_LEFT:
|
||||
case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
|
||||
// Scrollbars are now native on mac, via nsNativeScrollbarFrame.
|
||||
// So, this should never be called.
|
||||
// do nothing, drawn by scrollbar
|
||||
break;
|
||||
|
||||
case NS_THEME_LISTBOX:
|
||||
@@ -706,11 +841,36 @@ nsNativeThemeCocoa::GetWidgetBorder(nsIDeviceContext* aContext,
|
||||
aResult->SizeTo(frameOutset, frameOutset, frameOutset, frameOutset);
|
||||
}
|
||||
break;
|
||||
case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
|
||||
case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
|
||||
{
|
||||
// There's only an endcap to worry about when both arrows are on the bottom
|
||||
ThemeScrollBarArrowStyle arrowStyle;
|
||||
::GetThemeScrollBarArrowStyle(&arrowStyle);
|
||||
if (arrowStyle == kThemeScrollBarArrowsLowerRight) {
|
||||
PRBool isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL);
|
||||
|
||||
nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
|
||||
if (!scrollbarFrame) return NS_ERROR_FAILURE;
|
||||
PRBool isSmall = (scrollbarFrame->GetStyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL);
|
||||
|
||||
// There isn't a metric for this, so just hardcode a best guess at the value.
|
||||
// This value is even less exact due to the fact that the endcap is partially concave.
|
||||
PRInt32 endcapSize = isSmall ? 5 : 6;
|
||||
|
||||
if (isHorizontal)
|
||||
aResult->SizeTo(endcapSize, 0, 0, 0);
|
||||
else
|
||||
aResult->SizeTo(0, endcapSize, 0, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// return false here to indicate that CSS padding values should be used
|
||||
PRBool
|
||||
nsNativeThemeCocoa::GetWidgetPadding(nsIDeviceContext* aContext,
|
||||
@@ -746,6 +906,7 @@ nsNativeThemeCocoa::GetWidgetPadding(nsIDeviceContext* aContext,
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
nsNativeThemeCocoa::GetWidgetOverflow(nsIDeviceContext* aContext, nsIFrame* aFrame,
|
||||
PRUint8 aWidgetType, nsRect* aResult)
|
||||
@@ -780,6 +941,7 @@ nsNativeThemeCocoa::GetWidgetOverflow(nsIDeviceContext* aContext, nsIFrame* aFra
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNativeThemeCocoa::GetMinimumWidgetSize(nsIRenderingContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
@@ -934,16 +1096,46 @@ nsNativeThemeCocoa::GetMinimumWidgetSize(nsIRenderingContext* aContext,
|
||||
*aIsOverridable = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
case NS_THEME_SCROLLBAR:
|
||||
case NS_THEME_SCROLLBAR_BUTTON_UP:
|
||||
case NS_THEME_SCROLLBAR_BUTTON_DOWN:
|
||||
case NS_THEME_SCROLLBAR_BUTTON_LEFT:
|
||||
case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
|
||||
|
||||
// Get the rect of the thumb from HITheme, so we can return it to Gecko, which has different ideas about
|
||||
// how big the thumb should be. This is kind of a hack.
|
||||
case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
|
||||
case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
|
||||
case NS_THEME_SCROLLBAR_GRIPPER_HORIZONTAL:
|
||||
case NS_THEME_SCROLLBAR_GRIPPER_VERTICAL:
|
||||
{
|
||||
// Find our parent scrollbar frame. If we can't, abort.
|
||||
nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
|
||||
if (!scrollbarFrame) return NS_ERROR_FAILURE;
|
||||
|
||||
// We need to get the device context to convert from app units :(
|
||||
nsRect scrollbarRect = scrollbarFrame->GetRect();
|
||||
nsCOMPtr<nsIDeviceContext> dctx;
|
||||
aContext->GetDeviceContext(*getter_AddRefs(dctx));
|
||||
PRInt32 p2a = dctx->AppUnitsPerDevPixel();
|
||||
CGRect macRect = CGRectMake(NSAppUnitsToIntPixels(scrollbarRect.x, p2a),
|
||||
NSAppUnitsToIntPixels(scrollbarRect.y, p2a),
|
||||
NSAppUnitsToIntPixels(scrollbarRect.width, p2a),
|
||||
NSAppUnitsToIntPixels(scrollbarRect.height, p2a));
|
||||
|
||||
// False here means not to get scrollbar button state information.
|
||||
HIThemeTrackDrawInfo tdi;
|
||||
GetScrollbarDrawInfo(tdi, scrollbarFrame, macRect, PR_FALSE);
|
||||
|
||||
HIRect thumbRect;
|
||||
::HIThemeGetTrackPartBounds(&tdi, kControlIndicatorPart, &thumbRect);
|
||||
|
||||
// HITheme is just lying to us, I guess...
|
||||
PRInt32 thumbAdjust = ((scrollbarFrame->GetStyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL) ?
|
||||
2 : 4);
|
||||
|
||||
if (aWidgetType == NS_THEME_SCROLLBAR_THUMB_VERTICAL)
|
||||
aResult->SizeTo(nscoord(thumbRect.size.width), nscoord(thumbRect.size.height - thumbAdjust));
|
||||
else
|
||||
aResult->SizeTo(nscoord(thumbRect.size.width - thumbAdjust), nscoord(thumbRect.size.height));
|
||||
*aIsOverridable = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
case NS_THEME_SCROLLBAR:
|
||||
case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
|
||||
case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
|
||||
{
|
||||
@@ -951,12 +1143,44 @@ nsNativeThemeCocoa::GetMinimumWidgetSize(nsIRenderingContext* aContext,
|
||||
// really doesn't matter if the scrollbar is vertical or horizontal
|
||||
// and the width metric is a really good metric for every piece
|
||||
// of the scrollbar.
|
||||
|
||||
nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
|
||||
if (!scrollbarFrame) return NS_ERROR_FAILURE;
|
||||
|
||||
PRInt32 themeMetric = (scrollbarFrame->GetStyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL) ?
|
||||
kThemeMetricSmallScrollBarWidth :
|
||||
kThemeMetricScrollBarWidth;
|
||||
SInt32 scrollbarWidth = 0;
|
||||
::GetThemeMetric(kThemeMetricScrollBarWidth, &scrollbarWidth);
|
||||
::GetThemeMetric(themeMetric, &scrollbarWidth);
|
||||
aResult->SizeTo(scrollbarWidth, scrollbarWidth);
|
||||
*aIsOverridable = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
case NS_THEME_SCROLLBAR_BUTTON_UP:
|
||||
case NS_THEME_SCROLLBAR_BUTTON_DOWN:
|
||||
case NS_THEME_SCROLLBAR_BUTTON_LEFT:
|
||||
case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
|
||||
{
|
||||
nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
|
||||
if (!scrollbarFrame) return NS_ERROR_FAILURE;
|
||||
|
||||
// Since there is no NS_THEME_SCROLLBAR_BUTTON_UP_SMALL we need to ask the parent what appearance style it has.
|
||||
PRInt32 themeMetric = (scrollbarFrame->GetStyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL) ?
|
||||
kThemeMetricSmallScrollBarWidth :
|
||||
kThemeMetricScrollBarWidth;
|
||||
SInt32 scrollbarWidth = 0;
|
||||
::GetThemeMetric(themeMetric, &scrollbarWidth);
|
||||
|
||||
// It seems that for both sizes of scrollbar, the buttons are one pixel "longer".
|
||||
if (aWidgetType == NS_THEME_SCROLLBAR_BUTTON_LEFT || aWidgetType == NS_THEME_SCROLLBAR_BUTTON_RIGHT)
|
||||
aResult->SizeTo(scrollbarWidth+1, scrollbarWidth);
|
||||
else
|
||||
aResult->SizeTo(scrollbarWidth, scrollbarWidth+1);
|
||||
|
||||
*aIsOverridable = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@@ -1092,8 +1316,6 @@ nsNativeThemeCocoa::ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* a
|
||||
case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
|
||||
case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
|
||||
case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
|
||||
case NS_THEME_SCROLLBAR_GRIPPER_HORIZONTAL:
|
||||
case NS_THEME_SCROLLBAR_GRIPPER_VERTICAL:
|
||||
case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
|
||||
case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
|
||||
retVal = PR_TRUE;
|
||||
|
||||
@@ -64,7 +64,6 @@
|
||||
#include "nsSound.h"
|
||||
#include "nsIdleServiceX.h"
|
||||
|
||||
#include "nsNativeScrollbar.h"
|
||||
#include "nsScreenManagerCocoa.h"
|
||||
#include "nsDeviceContextSpecX.h"
|
||||
#include "nsPrintOptionsX.h"
|
||||
@@ -78,7 +77,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsLookAndFeel)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMenuBarX)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMenuX)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMenuItemX)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsNativeScrollbar)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsTransferable)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter)
|
||||
@@ -167,10 +165,6 @@ static const nsModuleComponentInfo gComponents[] =
|
||||
NS_BIDIKEYBOARD_CID,
|
||||
"@mozilla.org/widget/bidikeyboard;1",
|
||||
nsBidiKeyboardConstructor },
|
||||
{ "Native Scrollbar",
|
||||
NS_NATIVESCROLLBAR_CID,
|
||||
"@mozilla.org/widget/nativescrollbar;1",
|
||||
nsNativeScrollbarConstructor },
|
||||
{ "Native Theme Renderer",
|
||||
NS_THEMERENDERER_CID,
|
||||
"@mozilla.org/chrome/chrome-native-theme;1",
|
||||
|
||||
@@ -100,6 +100,12 @@ WIDGET_ATOM(orient, "orient")
|
||||
WIDGET_ATOM(radio, "radio")
|
||||
WIDGET_ATOM(readonly, "readonly")
|
||||
WIDGET_ATOM(Reload, "Reload")
|
||||
WIDGET_ATOM(sbattr, "sbattr")
|
||||
WIDGET_ATOM(scrollbarFrame, "ScrollbarFrame")
|
||||
WIDGET_ATOM(scrollbarDownBottom, "scrollbar-down-bottom")
|
||||
WIDGET_ATOM(scrollbarDownTop, "scrollbar-down-top")
|
||||
WIDGET_ATOM(scrollbarUpBottom, "scrollbar-up-bottom")
|
||||
WIDGET_ATOM(scrollbarUpTop, "scrollbar-up-top")
|
||||
WIDGET_ATOM(Search, "Search")
|
||||
WIDGET_ATOM(selected, "selected")
|
||||
WIDGET_ATOM(sortdirection, "sortDirection")
|
||||
|
||||
Reference in New Issue
Block a user