1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Mozilla Public License
6
* Version 1.1 (the "License"); you may not use this file except in
7
* compliance with the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/MPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is mozilla.org code.
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 2002
20
* the Initial Developer. All Rights Reserved.
24
* Alternatively, the contents of this file may be used under the terms of
25
* either the GNU General Public License Version 2 or later (the "GPL"), or
26
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27
* in which case the provisions of the GPL or the LGPL are applicable instead
28
* of those above. If you wish to allow use of your version of this file only
29
* under the terms of either the GPL or the LGPL, and not to allow others to
30
* use your version of this file under the terms of the MPL, indicate your
31
* decision by deleting the provisions above and replace them with the notice
32
* and other provisions required by the GPL or the LGPL. If you do not delete
33
* the provisions above, a recipient may use your version of this file under
34
* the terms of any one of the NPL, the GPL or the LGPL.
36
* ***** END LICENSE BLOCK ***** */
39
#include "nsNativeScrollbar.h"
40
#include "nsIDeviceContext.h"
41
#if TARGET_CARBON || (UNIVERSAL_INTERFACES_VERSION >= 0x0330)
42
#include <ControlDefinitions.h>
45
#include "nsWidgetAtoms.h"
46
#include "nsWatchTask.h"
47
#include "nsINameSpaceManager.h"
48
#include "nsIDOMElement.h"
49
#include "nsIScrollbarMediator.h"
53
inline void BoundsCheck(PRInt32 low, PRUint32& value, PRUint32 high)
55
if ((PRInt32) value < low)
62
// StControlActionProcOwner
64
// A class that wraps a control action proc so that it is disposed of
65
// correctly when the shared library shuts down
67
class StNativeControlActionProcOwner {
70
StNativeControlActionProcOwner ( )
72
sControlActionProc = NewControlActionUPP(nsNativeScrollbar::ScrollActionProc);
73
NS_ASSERTION(sControlActionProc, "Couldn't create live scrolling action proc");
75
~StNativeControlActionProcOwner ( )
77
if ( sControlActionProc )
78
DisposeControlActionUPP(sControlActionProc);
81
ControlActionUPP ActionProc() { return sControlActionProc; }
84
ControlActionUPP sControlActionProc;
88
static ControlActionUPP ScrollbarActionProc ( );
90
static ControlActionUPP
91
ScrollbarActionProc ( )
93
static StNativeControlActionProcOwner sActionProcOwner;
94
return sActionProcOwner.ActionProc();
98
NS_IMPL_ISUPPORTS_INHERITED1(nsNativeScrollbar, nsWindow, nsINativeScrollbar)
100
nsNativeScrollbar::nsNativeScrollbar()
106
, mVisibleImageSize(0)
107
, mMouseDownInScroll(PR_FALSE)
108
, mClickedPartCode(0)
110
WIDGET_SET_CLASSNAME("nsNativeScrollbar");
111
SetControlType(kControlScrollBarLiveProc);
115
nsNativeScrollbar::~nsNativeScrollbar()
124
// Called from the OS toolbox while the scrollbar is being tracked.
127
nsNativeScrollbar::ScrollActionProc(ControlHandle ctrl, ControlPartCode part)
129
nsNativeScrollbar* self = (nsNativeScrollbar*)(::GetControlReference(ctrl));
130
NS_ASSERTION(self, "NULL nsNativeScrollbar");
132
self->DoScrollAction(part);
139
// Called from the action proc of the scrollbar, adjust the control's
140
// value as well as the value in the content node which communicates
141
// to gecko that the document is scrolling.
144
nsNativeScrollbar::DoScrollAction(ControlPartCode part)
146
PRUint32 oldPos, newPos;
148
PRUint32 visibleImageSize;
149
PRInt32 scrollBarMessage = 0;
150
GetPosition(&oldPos);
151
GetLineIncrement(&incr);
152
GetViewSize(&visibleImageSize);
156
// For the up/down buttons, scroll up or down by the line height and
157
// update the attributes on the content node (the scroll frame listens
158
// for these attributes and will scroll accordingly). However,
159
// if we have a mediator, we're in an outliner and we have to scroll by
160
// lines. Outliner ignores the params to ScrollbarButtonPressed() except
161
// to check if one is greater than the other to indicate direction.
164
case kControlUpButtonPart:
165
newPos = oldPos - (mLineIncrement ? mLineIncrement : 1);
167
BoundsCheck(0, newPos, mMaxValue);
168
mMediator->ScrollbarButtonPressed(oldPos, newPos);
170
UpdateContentPosition(newPos);
174
case kControlDownButtonPart:
175
newPos = oldPos + (mLineIncrement ? mLineIncrement : 1);
177
BoundsCheck(0, newPos, mMaxValue);
178
mMediator->ScrollbarButtonPressed(oldPos, newPos);
180
UpdateContentPosition(newPos);
185
// For page up/down and dragging the thumb, scroll by the page height
186
// (or directly report the value of the scrollbar) and update the attributes
187
// on the content node (as above). If we have a mediator, we're in an
188
// outliner so tell it directly that the position has changed. Note that
189
// outliner takes signed values, so we have to convert our unsigned to
190
// signed values first.
193
case kControlPageUpPart:
194
newPos = oldPos - visibleImageSize;
195
UpdateContentPosition(newPos);
197
PRInt32 op = oldPos, np = mValue;
200
mMediator->PositionChanged(op, np);
204
case kControlPageDownPart:
205
newPos = oldPos + visibleImageSize;
206
UpdateContentPosition(newPos);
208
PRInt32 op = oldPos, np = mValue;
211
mMediator->PositionChanged(op, np);
215
case kControlIndicatorPart:
216
newPos = ::GetControl32BitValue(GetControl());
217
UpdateContentPosition(newPos);
219
PRInt32 op = oldPos, np = mValue;
222
mMediator->PositionChanged(op, np);
228
// update the area of the parent uncovered by the scrolling. Since
229
// we may be in a tight loop, we need to manually validate the area
230
// we just updated so the update rect doesn't continue to get bigger
231
// and bigger the more we scroll.
232
nsCOMPtr<nsIWidget> parent ( dont_AddRef(GetParent()) );
241
// UpdateContentPosition
243
// Tell the content node that the scrollbar has changed value and
244
// then update the scrollbar's position
247
nsNativeScrollbar::UpdateContentPosition(PRUint32 inNewPos)
249
if ( inNewPos == mValue || !mContent ) // break any possible recursion
252
// guarantee |inNewPos| is in the range of [0, mMaxValue] so it's correctly unsigned
253
BoundsCheck(0, inNewPos, mMaxValue);
255
// convert the int to a string
257
buffer.AppendInt(inNewPos);
259
mContent->SetAttr(kNameSpaceID_None, nsWidgetAtoms::curpos, buffer, PR_TRUE);
260
SetPosition(inNewPos);
264
/**-------------------------------------------------------------------------------
265
* DispatchMouseEvent handle an event for this scrollbar
266
* @update dc 08/31/98
267
* @Param aEvent -- The mouse event to respond to for this button
268
* @return -- True if the event was handled, PR_FALSE if we did not handle it.
271
nsNativeScrollbar::DispatchMouseEvent(nsMouseEvent &aEvent)
273
PRBool eatEvent = PR_FALSE;
274
switch (aEvent.message)
276
case NS_MOUSE_LEFT_DOUBLECLICK:
277
case NS_MOUSE_LEFT_BUTTON_DOWN:
278
NS_ASSERTION(this != 0, "NULL nsNativeScrollbar2");
279
::SetControlReference(mControl, (UInt32) this);
283
thePoint.h = aEvent.point.x;
284
thePoint.v = aEvent.point.y;
285
mClickedPartCode = ::TestControl(mControl, thePoint);
286
if (mClickedPartCode > 0)
287
::HiliteControl(mControl, mClickedPartCode);
289
switch (mClickedPartCode)
291
case kControlUpButtonPart:
292
case kControlDownButtonPart:
293
case kControlPageUpPart:
294
case kControlPageDownPart:
295
case kControlIndicatorPart:
296
// We are assuming Appearance 1.1 or later, so we
297
// have the "live scroll" variant of the scrollbar,
298
// which lets you pass the action proc to TrackControl
299
// for the thumb (this was illegal in previous
300
// versions of the defproc).
301
nsWatchTask::GetTask().Suspend();
302
::TrackControl(mControl, thePoint, ScrollbarActionProc());
303
nsWatchTask::GetTask().Resume();
304
::HiliteControl(mControl, 0);
305
// We don't dispatch the mouseDown event because mouseUp is eaten
306
// by TrackControl anyway and the only messages the app really
307
// cares about are the NS_SCROLLBAR_xxx messages.
317
case NS_MOUSE_LEFT_BUTTON_UP:
318
mClickedPartCode = 0;
325
::HiliteControl(mControl, 0);
334
::HiliteControl(mControl, mClickedPartCode);
342
return (Inherited::DispatchMouseEvent(aEvent));
350
// Set the maximum range of a scroll bar. This should be set to the
351
// full scrollable area minus the visible area.
354
nsNativeScrollbar::SetMaxRange(PRUint32 aEndRange)
356
mMaxValue = ((int)aEndRange) > 0 ? aEndRange : 10;
357
if ( GetControl() ) {
359
::SetControl32BitMaximum(GetControl(), mMaxValue);
369
// Get the maximum range of a scroll bar
372
nsNativeScrollbar::GetMaxRange(PRUint32* aMaxRange)
374
*aMaxRange = mMaxValue;
382
// Set the current position of the slider and redraw
385
nsNativeScrollbar::SetPosition(PRUint32 aPos)
387
if ((PRInt32)aPos < 0)
390
PRInt32 oldValue = mValue;
392
// while we _should_ be ensuring that we don't set our value higher
393
// than our max value, the gfx scrollview code plays fast and loose
394
// with the rules while going back/forward and adjusts the value to the
395
// previous value long before it sets the max. As a result, we would
396
// lose the given value (since max would most likely be 0). The only
397
// way around that is to relax our restrictions a little bit. (bug 135191)
398
// mValue = ((PRInt32)aPos) > mMaxValue ? mMaxValue : ((int)aPos);
401
// redraw the scrollbar. It needs to be synchronous otherwise we end
402
// up drawing at 0,0, probably because of the associated view.
403
if ( mValue != oldValue )
413
// Get the current position of the slider
416
nsNativeScrollbar::GetPosition(PRUint32* aPos)
426
// According to the toolbox docs, we pass the height of the
427
// visible view area to SetControlViewSize(). Assuming we've set
428
// the max to the total area - view height, this will give us a correct
429
// proportional scrollbar.
432
nsNativeScrollbar::SetViewSize(PRUint32 aSize)
434
mVisibleImageSize = ((int)aSize) > 0 ? aSize : 1;
436
if ( GetControl() ) {
438
SetControlViewSize(GetControl(), mVisibleImageSize);
448
// Get the height of the visible view area.
451
nsNativeScrollbar::GetViewSize(PRUint32* aSize)
453
*aSize = mVisibleImageSize;
461
// Set the line increment of the scroll bar
464
nsNativeScrollbar::SetLineIncrement(PRUint32 aLineIncrement)
466
mLineIncrement = (((int)aLineIncrement) > 0 ? aLineIncrement : 1);
474
// Get the line increment of the scroll bar
477
nsNativeScrollbar::GetLineIncrement(PRUint32* aLineIncrement)
479
*aLineIncrement = mLineIncrement;
487
// Ask the appearance manager for the dimensions of the narrow axis
488
// of the scrollbar. We cheat and assume the width of a vertical scrollbar
489
// is the same as the height of a horizontal scrollbar. *shrug*. Shoot me.
492
nsNativeScrollbar::GetNarrowSize(PRInt32* outSize)
495
return NS_ERROR_FAILURE;
498
::GetThemeMetric(kThemeMetricScrollBarWidth, &width);
510
// Hook up this native scrollbar to the rest of gecko. We care about
511
// the content so we can set attributes on it to affect the scrollview. We
512
// care about the mediator for <outliner> so we can do row-based scrolling.
515
nsNativeScrollbar::SetContent(nsIContent* inContent, nsIScrollbarMediator* inMediator)
517
mContent = inContent;
518
mMediator = inMediator;