Back to index

lightning-sunbird  0.9+nobinonly
nsNativeScrollbar.mm
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License
00006  * Version 1.1 (the "License"); you may not use this file except in
00007  * compliance with the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is 
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Stuart Morgan <stuart.morgan@alumni.case.edu>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or 
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the NPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsNativeScrollbar.h"
00040 #include "nsIDeviceContext.h"
00041 
00042 #include "nsReadableUtils.h"
00043 #include "nsWidgetAtoms.h"
00044 #include "nsINameSpaceManager.h"
00045 #include "nsIDOMElement.h"
00046 #include "nsIScrollbarMediator.h"
00047 
00048 NS_IMPL_ISUPPORTS_INHERITED1(nsNativeScrollbar, nsChildView, nsINativeScrollbar)
00049 
00050 inline void BoundsCheck(PRInt32 low, PRUint32& value, PRUint32 high)
00051 {
00052   if ((PRInt32) value < low)
00053     value = low;
00054   if (value > high)
00055     value = high;
00056 }
00057 
00058 nsNativeScrollbar::nsNativeScrollbar()
00059   : nsChildView()
00060   , mContent(nsnull)
00061   , mMediator(nsnull)
00062   , mScrollbar(nsnull)
00063   , mValue(0)
00064   , mMaxValue(0)
00065   , mVisibleImageSize(0)
00066   , mLineIncrement(0)
00067   , mIsEnabled(PR_TRUE)
00068 {
00069 }
00070 
00071 
00072 nsNativeScrollbar::~nsNativeScrollbar()
00073 {
00074 }
00075 
00076 //
00077 // CreateCocoaView
00078 //
00079 // Create a NativeScrollbarView for insertion into the cocoa view hierarchy.
00080 // Cocoa sets the orientation of a scrollbar at creation time by looking
00081 // at its frame and taking the longer side to be the orientation. Since
00082 // chances are good at this point gecko just wants us to be 1x1, assume
00083 // we're going to be vertical. If later when we get a content node assigned
00084 // we find we're horizontal, we can update then.
00085 //
00086 NSView*
00087 nsNativeScrollbar::CreateCocoaView(NSRect inFrame)
00088 {
00089   return [[[NativeScrollbarView alloc] initWithFrame:inFrame geckoChild:this] autorelease];
00090 }
00091 
00092 
00093 GrafPtr
00094 nsNativeScrollbar::GetQuickDrawPort ( )
00095 {
00096   // pray we're always a child of a NSQuickDrawView
00097   if ( [mParentView isKindOfClass: [ChildView class]] ) {
00098     NSQuickDrawView* parent = NS_STATIC_CAST(NSQuickDrawView*, mParentView);
00099     return (GrafPtr)[parent qdPort];
00100   }
00101   
00102   return nsnull;
00103 }
00104 
00105 
00106 //
00107 // DoScroll
00108 //
00109 // Called from the action proc of the scrollbar, adjust the control's
00110 // value as well as the value in the content node which communicates
00111 // to gecko that the document is scrolling.
00112 // 
00113 void
00114 nsNativeScrollbar::DoScroll(NSScrollerPart inPart)
00115 {
00116   PRUint32 oldPos, newPos;
00117   PRUint32 incr;
00118   PRUint32 visibleImageSize;
00119   GetPosition(&oldPos);
00120   GetLineIncrement(&incr);
00121   GetViewSize(&visibleImageSize);
00122   switch ( inPart ) {
00123 
00124     //
00125     // For the up/down buttons, scroll up or down by the line height and 
00126     // update the attributes on the content node (the scroll frame listens
00127     // for these attributes and will scroll accordingly). However,
00128     // if we have a mediator, we're in an outliner and we have to scroll by
00129     // lines. Outliner ignores the params to ScrollbarButtonPressed() except
00130     // to check if one is greater than the other to indicate direction.
00131     //
00132 
00133     case NSScrollerDecrementLine:           // scroll up/left
00134       newPos = oldPos - (mLineIncrement ? mLineIncrement : 1);
00135       UpdateContentPosition(newPos);
00136       if ( mMediator ) {
00137         BoundsCheck(0, newPos, mMaxValue);
00138         mMediator->ScrollbarButtonPressed(mScrollbar, oldPos, newPos);
00139       }
00140       break;
00141     
00142     case NSScrollerIncrementLine:           // scroll down/right
00143       newPos = oldPos + (mLineIncrement ? mLineIncrement : 1);
00144       UpdateContentPosition(newPos); 
00145       if ( mMediator ) {
00146         BoundsCheck(0, newPos, mMaxValue);
00147         mMediator->ScrollbarButtonPressed(mScrollbar, oldPos, newPos);
00148       }
00149       break;
00150   
00151     //
00152     // For page up/down, scroll by the page height and update the attributes
00153     // on the content node (as above). If we have a mediator, we're in an
00154     // outliner so tell it directly that the position has changed. Note that
00155     // outliner takes signed values, so we have to convert our unsigned to 
00156     // signed values first.
00157     //
00158 
00159     case NSScrollerDecrementPage:           // scroll up a page
00160       newPos = oldPos - visibleImageSize;
00161       UpdateContentPosition(newPos);
00162       if ( mMediator ) {
00163         PRInt32 op = oldPos, np = mValue;
00164         if ( np < 0 )
00165           np = 0;
00166         mMediator->PositionChanged(mScrollbar, op, np);
00167       }
00168       break;
00169     
00170     case NSScrollerIncrementPage:           // scroll down a page
00171       newPos = oldPos + visibleImageSize;
00172       UpdateContentPosition(newPos);
00173       if ( mMediator ) {
00174         PRInt32 op = oldPos, np = mValue;
00175         if ( np < 0 )
00176           np = 0;
00177         mMediator->PositionChanged(mScrollbar, op, np);
00178       }
00179       break;
00180     
00181     //
00182     // The scroller handles changing the value on the thumb for
00183     // us, so read it, convert it back to the range gecko is expecting,
00184     // and tell the content.
00185     //
00186     case NSScrollerKnob:
00187     case NSScrollerKnobSlot:
00188       newPos = (int) ([ScrollbarView() floatValue] * mMaxValue);
00189       UpdateContentPosition(newPos);
00190       if ( mMediator ) {
00191         PRInt32 op = oldPos, np = mValue;
00192         if ( np < 0 )
00193           np = 0;
00194         mMediator->PositionChanged(mScrollbar, op, np);
00195       }
00196       break;
00197     
00198     default:
00199       ; // do nothing
00200   }
00201 }
00202 
00203 
00204 //
00205 // UpdateContentPosition
00206 //
00207 // Tell the content node that the scrollbar has changed value and
00208 // then update the scrollbar's position
00209 //
00210 void
00211 nsNativeScrollbar::UpdateContentPosition(PRUint32 inNewPos)
00212 {
00213   if ( inNewPos == mValue || !mContent )   // break any possible recursion
00214     return;
00215   
00216   // guarantee |inNewPos| is in the range of [0, mMaxValue] so it's correctly unsigned
00217   BoundsCheck(0, inNewPos, mMaxValue);
00218     
00219   // convert the int to a string
00220   nsAutoString buffer;
00221   buffer.AppendInt(inNewPos);
00222   
00223   mContent->SetAttr(kNameSpaceID_None, nsWidgetAtoms::curpos, buffer, PR_TRUE);
00224   SetPosition(inNewPos);
00225 }
00226 
00227 
00228 
00229 //
00230 // DispatchMouseEvent
00231 //
00232 // We don't need to do much here, cocoa will handle tracking the mouse for us. Returning
00233 // true means that the event is handled.
00234 //
00235 PRBool
00236 nsNativeScrollbar::DispatchMouseEvent(nsMouseEvent &aEvent)
00237 {
00238   return PR_TRUE;
00239 }
00240 
00241 
00242 //
00243 // SetMaxRange
00244 //
00245 // Set the maximum range of a scroll bar. This should be set to the
00246 // full scrollable area minus the visible area.
00247 //
00248 NS_IMETHODIMP
00249 nsNativeScrollbar::SetMaxRange(PRUint32 aEndRange)
00250 {
00251   if ((PRInt32)aEndRange < 0)
00252     aEndRange = 0;
00253 
00254   mMaxValue = aEndRange;
00255   UpdateScroller();
00256   return NS_OK;
00257 }
00258 
00259 
00260 //
00261 // GetMaxRange
00262 //
00263 // Get the maximum range of a scroll bar
00264 //
00265 NS_IMETHODIMP
00266 nsNativeScrollbar::GetMaxRange(PRUint32* aMaxRange)
00267 {
00268   *aMaxRange = mMaxValue;
00269   return NS_OK;
00270 }
00271 
00272 
00273 //
00274 // SetPosition
00275 //
00276 // Set the current position of the slider and redraw the scrollbar. We have
00277 // to convert between the integer values gecko uses (0,mMaxValue) to the float
00278 // values that cocoa uses (0,1).
00279 //
00280 NS_IMETHODIMP
00281 nsNativeScrollbar::SetPosition(PRUint32 aPos)
00282 {
00283   NativeScrollbarView* scrollbarView = ScrollbarView();
00284 
00285   if ((PRInt32)aPos < 0)
00286     aPos = 0;
00287 
00288   // while we _should_ be ensuring that we don't set our value higher
00289   // than our max value, the gfx scrollview code plays fast and loose
00290   // with the rules while going back/forward and adjusts the value to the
00291   // previous value long before it sets the max. As a result, we would
00292   // lose the given value (since max would most likely be 0). The only
00293   // way around that is to relax our restrictions a little bit. (bug 135191)
00294   //   mValue = ((PRInt32)aPos) > mMaxValue ? mMaxValue : ((int)aPos);
00295   mValue = aPos;
00296   if ( mMaxValue )
00297     [scrollbarView setFloatValue:(mValue / (float)mMaxValue)];
00298   else
00299     [scrollbarView setFloatValue:0.0];
00300 
00301   return NS_OK;
00302 }
00303 
00304 
00305 //
00306 // GetPosition
00307 //
00308 // Get the current position of the slider
00309 //
00310 NS_IMETHODIMP
00311 nsNativeScrollbar::GetPosition(PRUint32* aPos)
00312 {
00313   *aPos = mValue;
00314   return NS_OK;
00315 }
00316 
00317 
00318 //
00319 // SetViewSize
00320 //
00321 // Change the knob proportion to be the ratio of the size of the visible image (given in |aSize|)
00322 // to the total area (visible + max). Recall that the max size is the total minus the
00323 // visible area.
00324 //
00325 NS_IMETHODIMP
00326 nsNativeScrollbar::SetViewSize(PRUint32 aSize)
00327 {
00328   if ((PRInt32)aSize < 0)
00329     aSize = 0;
00330 
00331   mVisibleImageSize = aSize;
00332   
00333   UpdateScroller();
00334   return NS_OK;
00335 }
00336 
00337 
00338 //
00339 // GetViewSize
00340 //
00341 // Get the height of the visible view area.
00342 //
00343 NS_IMETHODIMP
00344 nsNativeScrollbar::GetViewSize(PRUint32* aSize)
00345 {
00346   *aSize = mVisibleImageSize;
00347   return NS_OK;
00348 }
00349 
00350 
00351 //
00352 // SetLineIncrement
00353 //
00354 // Set the line increment of the scroll bar
00355 //
00356 NS_IMETHODIMP
00357 nsNativeScrollbar::SetLineIncrement(PRUint32 aLineIncrement)
00358 {
00359   mLineIncrement  = (((int)aLineIncrement) > 0 ? aLineIncrement : 1);
00360   return NS_OK;
00361 }
00362 
00363 
00364 //
00365 // GetLineIncrement
00366 //
00367 // Get the line increment of the scroll bar
00368 //
00369 NS_IMETHODIMP
00370 nsNativeScrollbar::GetLineIncrement(PRUint32* aLineIncrement)
00371 {
00372   *aLineIncrement = mLineIncrement;
00373   return NS_OK;
00374 }
00375 
00376 
00377 //
00378 // GetNarrowSize
00379 //
00380 // Ask the appearance manager for the dimensions of the narrow axis
00381 // of the scrollbar. We cheat and assume the width of a vertical scrollbar
00382 // is the same as the height of a horizontal scrollbar. *shrug*. Shoot me.
00383 //
00384 NS_IMETHODIMP
00385 nsNativeScrollbar::GetNarrowSize(PRInt32* outSize)
00386 {
00387   if ( *outSize )
00388     return NS_ERROR_FAILURE;
00389   SInt32 width = 0;
00390   ::GetThemeMetric(kThemeMetricScrollBarWidth, &width);
00391   *outSize = width;
00392   return NS_OK;
00393 }
00394 
00395 
00396 //
00397 // SetContent
00398 //
00399 // Hook up this native scrollbar to the rest of gecko. We care about
00400 // the content so we can set attributes on it to affect the scrollview. We
00401 // care about the mediator for <outliner> so we can do row-based scrolling.
00402 //
00403 NS_IMETHODIMP
00404 nsNativeScrollbar::SetContent(nsIContent* inContent, nsISupports* inScrollbar, 
00405                               nsIScrollbarMediator* inMediator)
00406 {
00407   mContent = inContent;
00408   mMediator = inMediator;
00409   mScrollbar = inScrollbar;
00410   
00411   if ( mContent ) {
00412     // we may have to re-create the scrollbar view as horizontal. Check the
00413     // 'orient' attribute and rebuild the view with all the settings
00414     // present in the current view
00415     nsAutoString orient;
00416     mContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::orient, orient);
00417     if ( orient.Equals(NS_LITERAL_STRING("horizontal")) )
00418       RecreateHorizontalScrollbar();
00419   }
00420   
00421   return NS_OK;
00422 }
00423 
00424 
00425 //
00426 // RecreateHorizontalScrollbar
00427 //
00428 // Replace the vertical scroller we created earlier with a horizontal scroller
00429 // of the same dimensions and values
00430 //
00431 void
00432 nsNativeScrollbar::RecreateHorizontalScrollbar()
00433 {
00434   // set framerect so that cocoa thinks it's a horizontal scroller
00435   NSRect orientation;
00436   orientation.origin.x = orientation.origin.y = 0;
00437   orientation.size.width = 100;
00438   orientation.size.height = 16;
00439   
00440   NativeScrollbarView* scrollbarView = ScrollbarView();
00441 
00442   // save off the old values and get rid of the previous view. Hiding
00443   // it removes it from the parent hierarchy.
00444   NSRect oldBounds = [scrollbarView bounds];
00445   float oldValue = [scrollbarView floatValue];
00446   float oldProportion = [scrollbarView knobProportion];
00447   mVisible = PR_TRUE;           // ensure that hide does the work
00448   Show(PR_FALSE);
00449   scrollbarView = nil;
00450   [mView release];
00451   
00452   // create the new horizontal scroller, init it, hook it up to the
00453   // view hierarchy and reset the values.
00454   mView = [[NativeScrollbarView alloc] initWithFrame:orientation geckoChild:this];
00455   [mView setNativeWindow: [mParentView getNativeWindow]];
00456   [mView setFrame:oldBounds];
00457   
00458   scrollbarView = ScrollbarView();
00459   [scrollbarView setFloatValue:oldValue knobProportion:oldProportion];
00460   Show(PR_TRUE);
00461   Enable(PR_TRUE);
00462 }
00463 
00464 
00465 //
00466 // Show
00467 //
00468 // Hide or show the scrollbar
00469 //
00470 NS_IMETHODIMP
00471 nsNativeScrollbar::Show(PRBool bState)
00472 {
00473   // the only way to get the scrollbar view to not draw is to remove it
00474   // from the view hierarchy. cache the parent view so that we can
00475   // hook it up later if we're told to show.
00476   if ( mVisible && !bState ) {
00477     mParentView = [mView superview];
00478     [mView removeFromSuperview];
00479   }
00480   else if ( !mVisible && bState ) {
00481     if ( mParentView )
00482       [mParentView addSubview:mView];
00483   }
00484 
00485   mVisible = bState;
00486   return NS_OK;
00487 }
00488 
00489 
00490 //
00491 // Enable
00492 //
00493 // Enable/disable this scrollbar
00494 //
00495 NS_IMETHODIMP
00496 nsNativeScrollbar::Enable(PRBool bState)
00497 {
00498   mIsEnabled = bState;
00499   UpdateScroller();
00500   return NS_OK;
00501 }
00502 
00503 
00504 NS_IMETHODIMP
00505 nsNativeScrollbar::IsEnabled(PRBool *aState)
00506 {
00507   if (aState)
00508    *aState = mIsEnabled;
00509   return NS_OK;
00510 }
00511 
00512 
00513 void
00514 nsNativeScrollbar::UpdateScroller()
00515 {
00516   NativeScrollbarView* scrollbarView = ScrollbarView();
00517 
00518   // Update the current value based on the new range. We need to recompute the
00519   // float value in case we had to set the value to 0 because gecko cheated
00520   // and set the position before it set the max value.
00521   float knobProp = 1.0f;
00522   if ((mVisibleImageSize + mMaxValue) > 0)
00523     knobProp = (float)mVisibleImageSize / (float)(mVisibleImageSize + mMaxValue);
00524   [scrollbarView setFloatValue:(mValue / (float)mMaxValue) knobProportion:knobProp];
00525   
00526   BOOL enableScrollbar = (mIsEnabled && (mMaxValue > 0));
00527   [scrollbarView setEnabled:enableScrollbar];
00528   
00529   Invalidate(FALSE);
00530 }
00531 
00532 
00533 #pragma mark -
00534 
00535 @interface NativeScrollbarView(Private)
00536 
00537 - (void)processPendingRedraws;
00538 
00539 @end
00540 
00541 @implementation NativeScrollbarView
00542 
00543 //
00544 // -initWithFrame:geckoChild
00545 // Designated Initializer
00546 //
00547 // Init our superclass and make the connection to the gecko nsIWidget we're
00548 // mirroring
00549 //
00550 - (id)initWithFrame:(NSRect)frameRect geckoChild:(nsNativeScrollbar*)inChild
00551 {
00552   if ((self = [super initWithFrame:frameRect]))
00553   {
00554     NS_ASSERTION(inChild, "Need to provide a tether between this and a nsChildView class");
00555     mGeckoChild = inChild;
00556     
00557     // make ourselves the target of the scroll and set the action message
00558     [self setTarget:self];
00559     [self setAction:@selector(scroll:)];
00560   }
00561   return self;
00562 }
00563 
00564 
00565 //
00566 // -initWithFrame
00567 //
00568 // overridden parent class initializer
00569 //
00570 - (id)initWithFrame:(NSRect)frameRect
00571 {
00572   NS_WARNING("You're calling the wrong initializer. You really want -initWithFrame:geckoChild");
00573   if ((self = [self initWithFrame:frameRect geckoChild:nsnull]))
00574   {
00575   }
00576   return self;
00577 }
00578 
00579 
00580 - (NSWindow*) getNativeWindow
00581 {
00582   NSWindow* currWin = [self window];
00583   if (currWin)
00584      return currWin;
00585   else
00586      return mWindow;
00587 }
00588 
00589 - (void) setNativeWindow: (NSWindow*)aWindow
00590 {
00591   mWindow = aWindow;
00592 }
00593 
00594 
00595 - (BOOL)isFlipped
00596 {
00597   return YES;
00598 }
00599 
00600 
00601 //
00602 // -widget
00603 //
00604 // return our gecko child view widget. Note this does not AddRef.
00605 //
00606 - (nsIWidget*) widget
00607 {
00608   return NS_STATIC_CAST(nsIWidget*, mGeckoChild);
00609 }
00610 
00611 - (void)setNeedsPendingDisplay
00612 {
00613   mPendingFullDisplay = YES;
00614   [self performSelector:@selector(processPendingRedraws) withObject:nil afterDelay:0];
00615 }
00616 
00617 - (void)setNeedsPendingDisplayInRect:(NSRect)invalidRect
00618 {
00619   if (!mPendingDirtyRects)
00620     mPendingDirtyRects = [[NSMutableArray alloc] initWithCapacity:1];
00621   [mPendingDirtyRects addObject:[NSValue valueWithRect:invalidRect]];
00622   [self performSelector:@selector(processPendingRedraws) withObject:nil afterDelay:0];
00623 }
00624 
00625 //
00626 // -processPendingRedraws
00627 //
00628 // Clears the queue of any pending invalides
00629 //
00630 - (void)processPendingRedraws
00631 {
00632   if (mPendingFullDisplay) {
00633     [self setNeedsDisplay:YES];
00634   }
00635   else {
00636     unsigned int count = [mPendingDirtyRects count];
00637     for (unsigned int i = 0; i < count; ++i) {
00638       [self setNeedsDisplayInRect:[[mPendingDirtyRects objectAtIndex:i] rectValue]];
00639     }
00640   }
00641   mPendingFullDisplay = NO;
00642   [mPendingDirtyRects release];
00643   mPendingDirtyRects = nil;
00644 }
00645 
00646 - (void)scrollRect:(NSRect)aRect by:(NSSize)offset
00647 {
00648   // Update any pending dirty rects to reflect the new scroll position
00649   if (mPendingDirtyRects) {
00650     unsigned int count = [mPendingDirtyRects count];
00651     for (unsigned int i = 0; i < count; ++i) {
00652       NSRect oldRect = [[mPendingDirtyRects objectAtIndex:i] rectValue];
00653       NSRect newRect = NSOffsetRect(oldRect, offset.width, offset.height);
00654       [mPendingDirtyRects replaceObjectAtIndex:i
00655                                     withObject:[NSValue valueWithRect:newRect]];
00656     }
00657   }
00658   [super scrollRect:aRect by:offset];
00659 }
00660 
00661 //
00662 // -mouseMoved
00663 //
00664 // our parent view will try to forward this message down to us. The
00665 // default behavior for NSResponder is to forward it up the chain. Can you
00666 // say "infinite recursion"? I thought so. Just stub out the action to
00667 // break the cycle of madness.
00668 //
00669 - (void)mouseMoved:(NSEvent*)theEvent
00670 {
00671   // do nothing
00672 }
00673 
00674 //
00675 // -widgetDestroyed
00676 //
00677 // the gecko nsNativeScrollbar is being destroyed.
00678 //
00679 - (void)widgetDestroyed
00680 {
00681   mGeckoChild = nsnull;
00682 
00683   if (mInTracking)
00684   {
00685     // To get out of the NSScroller tracking loop, we post a fake mouseup event.
00686     // We have to do this here, before we are ripped out of the view hierarchy.
00687     [NSApp postEvent:[NSEvent mouseEventWithType:NSLeftMouseUp
00688                                         location:[NSEvent mouseLocation]
00689                                    modifierFlags:0
00690                                        timestamp:[[NSApp currentEvent] timestamp]
00691                                     windowNumber:[[self window] windowNumber]
00692                                          context:NULL
00693                                      eventNumber:0
00694                                       clickCount:0
00695                                         pressure:1.0]
00696              atStart:YES];
00697 
00698     mInTracking = NO;
00699   }
00700 }
00701 
00702 // getContextMenu, from mozView protocol
00703 - (NSMenu*)getContextMenu
00704 {
00705   return nil;
00706 }
00707 
00708 //
00709 // -scroll
00710 //
00711 // the action message we've set up to be called when the scrollbar needs
00712 // to adjust its value. Feed back into the owning widget to process
00713 // how much to scroll and adjust the correct attributes.
00714 //
00715 - (IBAction)scroll:(NSScroller*)sender
00716 {
00717   if ( mGeckoChild )
00718     mGeckoChild->DoScroll([sender hitPart]);
00719 }
00720 
00721 
00722 //
00723 // -trackKnob:
00724 //
00725 // overridden to toggle mInTracking on and off
00726 //
00727 - (void)trackKnob:(NSEvent *)theEvent
00728 {
00729   mInTracking = YES;
00730   NS_DURING   // be sure we always turn mInTracking off.
00731     [super trackKnob:theEvent];
00732   NS_HANDLER
00733   NS_ENDHANDLER
00734   mInTracking = NO;
00735 }
00736 
00737 //
00738 // -trackScrollButtons:
00739 //
00740 // overridden to toggle mInTracking on and off
00741 //
00742 - (void)trackScrollButtons:(NSEvent *)theEvent
00743 {
00744   mInTracking = YES;
00745   NS_DURING   // be sure we always turn mInTracking off.
00746     [super trackScrollButtons:theEvent];
00747   NS_HANDLER
00748   NS_ENDHANDLER
00749   mInTracking = NO;
00750 }
00751 
00752 //
00753 // -trackPagingArea:
00754 //
00755 // this method is not documented, but was seen in sampling. We have
00756 // to override it to toggle mInTracking.
00757 //
00758 - (void)trackPagingArea:(id)theEvent
00759 {
00760   mInTracking = YES;
00761   NS_DURING   // be sure we always turn mInTracking off.
00762     [super trackPagingArea:theEvent];
00763   NS_HANDLER
00764   NS_ENDHANDLER
00765   mInTracking = NO;
00766 }
00767 
00768 @end
00769