From dd6cf51b951780c11a1d7a064bf4a359a77eeade Mon Sep 17 00:00:00 2001 From: Neil Deakin Date: Wed, 14 Jan 2009 13:21:58 -0500 Subject: [PATCH] Bug 472090, change scale to use a listener instead of mutation events, r=smaug,sr=neil --- layout/xul/base/public/Makefile.in | 1 + .../nsISliderListener.idl} | 46 ++++------ layout/xul/base/src/nsSliderFrame.cpp | 70 ++++++++++++---- layout/xul/base/src/nsSliderFrame.h | 10 +-- toolkit/content/widgets/scale.xml | 83 ++++++++++++------- 5 files changed, 130 insertions(+), 80 deletions(-) rename layout/xul/base/{src/nsIScrollbarListener.h => public/nsISliderListener.idl} (62%) diff --git a/layout/xul/base/public/Makefile.in b/layout/xul/base/public/Makefile.in index 56793820011a..f2630a95175e 100644 --- a/layout/xul/base/public/Makefile.in +++ b/layout/xul/base/public/Makefile.in @@ -63,6 +63,7 @@ XPIDLSRCS= nsIBoxObject.idl \ nsIEditorBoxObject.idl \ nsIContainerBoxObject.idl \ nsIListBoxObject.idl \ + nsISliderListener.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/layout/xul/base/src/nsIScrollbarListener.h b/layout/xul/base/public/nsISliderListener.idl similarity index 62% rename from layout/xul/base/src/nsIScrollbarListener.h rename to layout/xul/base/public/nsISliderListener.idl index 4bc3406b20e3..5f9380722d79 100644 --- a/layout/xul/base/src/nsIScrollbarListener.h +++ b/layout/xul/base/public/nsISliderListener.idl @@ -12,15 +12,13 @@ * for the specific language governing rights and limitations under the * License. * - * The Original Code is Mozilla Communicator client code. + * 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) 1998 + * The Initial Developer of the Original Code is Neil Deakin + * Portions created by the Initial Developer are Copyright (C) 2009 * the Initial Developer. All Rights Reserved. * * Contributor(s): - * Original Author: David W. Hyatt (hyatt@netscape.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"), @@ -36,29 +34,19 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef nsIScrollbarListener_h___ -#define nsIScrollbarListener_h___ +#include "nsISupports.idl" -// {A0ADBD81-2911-11d3-97FA-00400553EEF0} -#define NS_ISCROLLBARLISTENER_IID \ -{ 0xa0adbd81, 0x2911, 0x11d3, { 0x97, 0xfa, 0x0, 0x40, 0x5, 0x53, 0xee, 0xf0 } } - -static NS_DEFINE_IID(kIScrollbarListenerIID, NS_ISCROLLBARLISTENER_IID); - -class nsPresContext; - -class nsIScrollbarListener : public nsISupports { - -public: - - NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCROLLBARLISTENER_IID) - - NS_IMETHOD PositionChanged(nsPresContext* aPresContext, PRInt32 aOldIndex, PRInt32& aNewIndex) = 0; - - NS_IMETHOD PagedUpDown() = 0; +/** + * Used for to listen to slider changes to avoid mutation listeners + */ +[scriptable, uuid(CD380CB5-E9F6-4B7D-A19F-B1FD7B31C532)] +interface nsISliderListener : nsISupports +{ + /** + * Called when the current, minimum or maximum value has been changed to + * newValue. The which parameter will either be 'curpos', 'minpos' or 'maxpos'. + * If userChanged is true, then the user changed ths slider, otherwise it + * was changed via some other means. + */ + void valueChanged(in AString which, in long newValue, in boolean userChanged); }; - -NS_DEFINE_STATIC_IID_ACCESSOR(nsIScrollbarListener, NS_ISCROLLBARLISTENER_IID) - -#endif - diff --git a/layout/xul/base/src/nsSliderFrame.cpp b/layout/xul/base/src/nsSliderFrame.cpp index a1557d67189a..16dd12567d2e 100644 --- a/layout/xul/base/src/nsSliderFrame.cpp +++ b/layout/xul/base/src/nsSliderFrame.cpp @@ -59,7 +59,7 @@ #include "nsIDOMMouseEvent.h" #include "nsIDocument.h" #include "nsScrollbarButtonFrame.h" -#include "nsIScrollbarListener.h" +#include "nsISliderListener.h" #include "nsIScrollbarMediator.h" #include "nsIScrollbarFrame.h" #include "nsILookAndFeel.h" @@ -115,8 +115,8 @@ NS_NewSliderFrame (nsIPresShell* aPresShell, nsStyleContext* aContext) nsSliderFrame::nsSliderFrame(nsIPresShell* aPresShell, nsStyleContext* aContext): nsBoxFrame(aPresShell, aContext), mCurPos(0), - mScrollbarListener(nsnull), - mChange(0) + mChange(0), + mUserChanged(PR_FALSE) { } @@ -228,6 +228,30 @@ nsSliderFrame::GetIntegerAttribute(nsIContent* content, nsIAtom* atom, PRInt32 d return defaultValue; } +class nsValueChangedRunnable : public nsRunnable +{ +public: + nsValueChangedRunnable(nsISliderListener* aListener, + nsIAtom* aWhich, + PRInt32 aValue, + PRBool aUserChanged) + : mListener(aListener), mWhich(aWhich), + mValue(aValue), mUserChanged(aUserChanged) + {} + + NS_IMETHODIMP Run() + { + nsAutoString which; + mWhich->ToString(atom); + return mListener->ValueChanged(which, mValue, mUserChanged); + } + + nsCOMPtr mListener; + nsCOMPtr mWhich; + PRInt32 mValue; + PRBool mUserChanged; +}; + NS_IMETHODIMP nsSliderFrame::AttributeChanged(PRInt32 aNameSpaceID, nsIAtom* aAttribute, @@ -251,6 +275,18 @@ nsSliderFrame::AttributeChanged(PRInt32 aNameSpaceID, PRInt32 current = GetCurrentPosition(scrollbar); PRInt32 min = GetMinPosition(scrollbar); PRInt32 max = GetMaxPosition(scrollbar); + + // inform the parent that the minimum or maximum changed + nsIFrame* parent = GetParent(); + if (parent) { + nsCOMPtr sliderListener = do_QueryInterface(parent->GetContent()); + if (sliderListener) { + nsContentUtils::AddScriptRunner( + new nsValueChangedRunnable(sliderListener, aAttribute, + aAttribute == nsGkAtoms::minpos ? min : max, PR_FALSE)); + } + } + if (current < min || current > max) { if (current < min || max < min) @@ -610,9 +646,6 @@ nsSliderFrame::PageUpDown(nscoord change) nsGkAtoms::reverse, eCaseMatters)) change = -change; - if (mScrollbarListener) - mScrollbarListener->PagedUpDown(); // Let the listener decide our increment. - nscoord pageIncrement = GetPageIncrement(scrollbar); PRInt32 curpos = GetCurrentPosition(scrollbar); PRInt32 minpos = GetMinPosition(scrollbar); @@ -685,11 +718,18 @@ nsSliderFrame::CurrentPositionChanged(nsPresContext* aPresContext, // Redraw the scrollbar InvalidateWithFlags(clientRect, aImmediateRedraw ? INVALIDATE_IMMEDIATE : 0); - if (mScrollbarListener) - mScrollbarListener->PositionChanged(aPresContext, mCurPos, curpospx); - mCurPos = curpospx; + // inform the parent if it exists that the value changed + nsIFrame* parent = GetParent(); + if (parent) { + nsCOMPtr sliderListener = do_QueryInterface(parent->GetContent()); + if (sliderListener) { + nsContentUtils::AddScriptRunner( + new nsValueChangedRunnable(sliderListener, nsGkAtoms::curpos, mCurPos, mUserChanged)); + } + } + return NS_OK; } @@ -766,6 +806,9 @@ nsSliderFrame::SetCurrentPositionInternal(nsIContent* aScrollbar, PRInt32 aNewPo { nsCOMPtr scrollbar = aScrollbar; nsIBox* scrollbarBox = GetScrollbar(); + + mUserChanged = PR_TRUE; + nsIScrollbarFrame* scrollbarFrame = do_QueryFrame(scrollbarBox); if (scrollbarFrame) { // See if we have a mediator. @@ -784,11 +827,13 @@ nsSliderFrame::SetCurrentPositionInternal(nsIContent* aScrollbar, PRInt32 aNewPo CurrentPositionChanged(frame->PresContext(), aImmediateRedraw); } } + mUserChanged = PR_FALSE; return; } } UpdateAttribute(scrollbar, aNewPos, PR_TRUE, aIsSmooth); + mUserChanged = PR_FALSE; #ifdef DEBUG_SLIDER printf("Current Pos=%d\n",aNewPos); @@ -1091,13 +1136,6 @@ nsSliderFrame::EnsureOrient() } -void -nsSliderFrame::SetScrollbarListener(nsIScrollbarListener* aListener) -{ - // Don't addref/release this, since it's actually a frame. - mScrollbarListener = aListener; -} - void nsSliderFrame::Notify(void) { PRBool stop = PR_FALSE; diff --git a/layout/xul/base/src/nsSliderFrame.h b/layout/xul/base/src/nsSliderFrame.h index 604bab0e2e5d..4aa56e8454c3 100644 --- a/layout/xul/base/src/nsSliderFrame.h +++ b/layout/xul/base/src/nsSliderFrame.h @@ -47,7 +47,6 @@ #include "nsIDOMMouseListener.h" class nsString; -class nsIScrollbarListener; class nsISupportsArray; class nsITimer; class nsSliderFrame; @@ -186,8 +185,6 @@ public: static PRInt32 GetIntegerAttribute(nsIContent* content, nsIAtom* atom, PRInt32 defaultValue); void EnsureOrient(); - void SetScrollbarListener(nsIScrollbarListener* aListener); - virtual nsIView* GetMouseCapturer() const { return GetView(); } NS_IMETHOD HandlePress(nsPresContext* aPresContext, @@ -242,12 +239,15 @@ private: PRInt32 mCurPos; - nsIScrollbarListener* mScrollbarListener; - nscoord mChange; nsPoint mDestinationPoint; nsRefPtr mMediator; + // true if an attribute change has been caused by the user manipulating the + // slider. This allows notifications to tell how a slider's current position + // was changed. + PRBool mUserChanged; + static PRBool gMiddlePref; static PRInt32 gSnapMultiplier; }; // class nsSliderFrame diff --git a/toolkit/content/widgets/scale.xml b/toolkit/content/widgets/scale.xml index 82540ec48056..0a762e82948c 100644 --- a/toolkit/content/widgets/scale.xml +++ b/toolkit/content/widgets/scale.xml @@ -39,7 +39,7 @@ - + return Components.interfaces.nsIAccessibleProvider.XULScale; @@ -57,6 +57,7 @@ + false @@ -148,55 +149,77 @@ + + + + + + + + + - - if (event.originalTarget != this._slider) - return; - - switch (event.attrName) { - case "curpos": - this.setAttribute("value", event.newValue); - - var changeEvent = document.createEvent("Events"); - changeEvent.initEvent("change", true, true); - this.dispatchEvent(changeEvent); - break; - - case "minpos": - this.setAttribute("min", event.newValue); - break; - - case "maxpos": - this.setAttribute("max", event.newValue); - break; - } - - - return (this.dir == "reverse") ? this.increase() : this.decrease(); + this._userChanged = true; + (this.dir == "reverse") ? this.increase() : this.decrease(); + this._userChanged = false; - return (this.dir == "reverse") ? this.increase() : this.decrease(); + this._userChanged = true; + (this.dir == "reverse") ? this.increase() : this.decrease(); + this._userChanged = false; - return (this.dir == "reverse") ? this.decrease() : this.increase(); + this._userChanged = true; + (this.dir == "reverse") ? this.decrease() : this.increase(); + this._userChanged = false; - return (this.dir == "reverse") ? this.decrease() : this.increase(); + this._userChanged = true; + (this.dir == "reverse") ? this.decrease() : this.increase(); + this._userChanged = false; - return (this.dir == "reverse") ? this.increasePage() : this.decreasePage(); + this._userChanged = true; + (this.dir == "reverse") ? this.increasePage() : this.decreasePage(); + this._userChanged = false; - return (this.dir == "reverse") ? this.decreasePage() : this.increasePage(); + this._userChanged = true; + (this.dir == "reverse") ? this.decreasePage() : this.increasePage(); + this._userChanged = false; + this._userChanged = true; this.value = (this.dir == "reverse") ? this.max : this.min; + this._userChanged = false; + this._userChanged = true; this.value = (this.dir == "reverse") ? this.min : this.max; + this._userChanged = false;