2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
5 * FILE: win32ss/user/ntuser/scrollbar.c
6 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
7 * Jason Filby (jasonfilby@yahoo.com)
11 DBG_DEFAULT_CHANNEL(UserScrollbar
);
13 /* Definitions for scrollbar hit testing [See SCROLLBARINFO in MSDN] */
14 #define SCROLL_NOWHERE 0x00 /* Outside the scroll bar */
15 #define SCROLL_TOP_ARROW 0x01 /* Top or left arrow */
16 #define SCROLL_TOP_RECT 0x02 /* Rectangle between the top arrow and the thumb */
17 #define SCROLL_THUMB 0x03 /* Thumb rectangle */
18 #define SCROLL_BOTTOM_RECT 0x04 /* Rectangle between the thumb and the bottom arrow */
19 #define SCROLL_BOTTOM_ARROW 0x05 /* Bottom or right arrow */
21 #define SCROLL_FIRST_DELAY 200 /* Delay (in ms) before first repetition when
22 holding the button down */
23 #define SCROLL_REPEAT_DELAY 50 /* Delay (in ms) between scroll repetitions */
25 #define SCROLL_TIMER 0 /* Scroll timer id */
27 /* Minimum size of the rectangle between the arrows */
28 #define SCROLL_MIN_RECT 4
30 /* Minimum size of the thumb in pixels */
31 #define SCROLL_MIN_THUMB 6
33 /* Overlap between arrows and thumb */
34 #define SCROLL_ARROW_THUMB_OVERLAP 0
39 #define MINTRACKTHUMB 8 /* Minimum size of the rectangle between the arrows */
41 /* What to do after SetScrollInfo() */
42 #define SA_SSI_HIDE 0x0001
43 #define SA_SSI_SHOW 0x0002
44 #define SA_SSI_REFRESH 0x0004
45 #define SA_SSI_REPAINT_ARROWS 0x0008
47 #define SBRG_SCROLLBAR 0 /* The scrollbar itself */
48 #define SBRG_TOPRIGHTBTN 1 /* The top or right button */
49 #define SBRG_PAGEUPRIGHT 2 /* The page up or page right region */
50 #define SBRG_SCROLLBOX 3 /* The scroll box */
51 #define SBRG_PAGEDOWNLEFT 4 /* The page down or page left region */
52 #define SBRG_BOTTOMLEFTBTN 5 /* The bottom or left button */
54 #define CHANGERGSTATE(item, status) \
55 if(Info->rgstate[(item)] != (status)) \
57 Info->rgstate[(item)] = (status);
59 /* FUNCTIONS *****************************************************************/
62 IntEnableScrollBar(BOOL Horz
, PSCROLLBARINFO Info
, UINT wArrows
);
65 /* Ported from WINE20020904 */
66 /* Compute the scroll bar rectangle, in drawing coordinates (i.e. client coords for SB_CTL, window coords for SB_VERT and
67 * SB_HORZ). 'arrowSize' returns the width or height of an arrow (depending on * the orientation of the scrollbar),
68 * 'thumbSize' returns the size of the thumb, and 'thumbPos' returns the position of the thumb relative to the left or to
69 * the top. Return TRUE if the scrollbar is vertical, FALSE if horizontal.
71 static inline void mirror_rect( const RECT
*window_rect
, RECT
*rect
)
73 int width
= window_rect
->right
- window_rect
->left
;
75 rect
->left
= width
- rect
->right
;
76 rect
->right
= width
- tmp
;
80 IntGetSBData(PWND pwnd
, INT Bar
)
85 pSBInfo
= pwnd
->pSBInfo
;
89 return &pSBInfo
->Horz
;
91 return &pSBInfo
->Vert
;
93 if ( pwnd
->cbwndExtra
!= (sizeof(SBWND
)-sizeof(WND
)) )
95 ERR("IntGetSBData Wrong Extra bytes for CTL Scrollbar!\n");
98 pSBWnd
= (PSBWND
)pwnd
;
99 return (PSBDATA
)&pSBWnd
->SBCalc
;
101 ERR("IntGetSBData Bad Bar!\n");
107 IntGetScrollBarRect (PWND Wnd
, INT nBar
, RECTL
*lprect
)
110 *lprect
= Wnd
->rcClient
;
112 RECTL_vOffsetRect( lprect
, -Wnd
->rcWindow
.left
, -Wnd
->rcWindow
.top
);
113 if (Wnd
->ExStyle
& WS_EX_LAYOUTRTL
)
114 mirror_rect( &Wnd
->rcWindow
, lprect
);
119 lprect
->top
= lprect
->bottom
;
120 lprect
->bottom
+= UserGetSystemMetrics (SM_CYHSCROLL
);
121 if (Wnd
->style
& WS_BORDER
)
126 else if (Wnd
->style
& WS_VSCROLL
)
134 if(Wnd
->ExStyle
& WS_EX_LEFTSCROLLBAR
)
136 lprect
->right
= lprect
->left
;
137 lprect
->left
-= UserGetSystemMetrics(SM_CXVSCROLL
);
141 lprect
->left
= lprect
->right
;
142 lprect
->right
+= UserGetSystemMetrics(SM_CXVSCROLL
);
144 if (Wnd
->style
& WS_BORDER
)
149 else if (Wnd
->style
& WS_HSCROLL
)
157 IntGetClientRect (Wnd
, lprect
);
158 vertical
= !!(Wnd
->style
& SBS_VERT
);
169 IntCalculateThumb(PWND Wnd
, LONG idObject
, PSCROLLBARINFO psbi
, PSBDATA pSBData
)
171 INT Thumb
, ThumbBox
, ThumbPos
, cxy
, mx
;
177 Thumb
= UserGetSystemMetrics(SM_CXHSCROLL
);
178 cxy
= psbi
->rcScrollBar
.right
- psbi
->rcScrollBar
.left
;
181 Thumb
= UserGetSystemMetrics(SM_CYVSCROLL
);
182 cxy
= psbi
->rcScrollBar
.bottom
- psbi
->rcScrollBar
.top
;
185 IntGetClientRect(Wnd
, &ClientRect
);
186 if(Wnd
->style
& SBS_VERT
)
188 Thumb
= UserGetSystemMetrics(SM_CYVSCROLL
);
189 cxy
= ClientRect
.bottom
- ClientRect
.top
;
193 Thumb
= UserGetSystemMetrics(SM_CXHSCROLL
);
194 cxy
= ClientRect
.right
- ClientRect
.left
;
202 /* Calculate Thumb */
203 if(cxy
<= (2 * Thumb
))
206 psbi
->xyThumbTop
= 0;
207 psbi
->xyThumbBottom
= 0;
210 else if (psbi
->rgstate
[SBRG_TOPRIGHTBTN
] == STATE_SYSTEM_UNAVAILABLE
&&
211 psbi
->rgstate
[SBRG_BOTTOMLEFTBTN
] == STATE_SYSTEM_UNAVAILABLE
&&
212 pSBData
->posMin
>= (int)(pSBData
->posMax
- max(pSBData
->page
- 1, 0)))
214 /* Nothing to scroll */
215 psbi
->xyThumbTop
= 0;
216 psbi
->xyThumbBottom
= 0;
220 ThumbBox
= pSBData
->page
? MINTRACKTHUMB
: UserGetSystemMetrics(SM_CXHTHUMB
);
226 ThumbBox
= max(EngMulDiv(cxy
, pSBData
->page
, pSBData
->posMax
- pSBData
->posMin
+ 1), ThumbBox
);
231 mx
= pSBData
->posMax
- max(pSBData
->page
- 1, 0);
232 if(pSBData
->posMin
< mx
)
233 ThumbPos
= Thumb
+ EngMulDiv(cxy
- ThumbBox
, pSBData
->pos
- pSBData
->posMin
, mx
- pSBData
->posMin
);
235 ThumbPos
= Thumb
+ ThumbBox
;
238 psbi
->xyThumbTop
= ThumbPos
;
239 psbi
->xyThumbBottom
= ThumbPos
+ ThumbBox
;
243 psbi
->xyThumbTop
= 0;
244 psbi
->xyThumbBottom
= 0;
247 psbi
->dxyLineButton
= Thumb
;
253 IntUpdateSBInfo(PWND Window, int wBar)
259 ASSERT(Window->pSBInfo);
260 ASSERT(Window->pSBInfoex);
262 sbi = IntGetScrollbarInfoFromWindow(Window, wBar);
263 pSBData = IntGetSBData(Window, wBar);
264 IntGetScrollBarRect(Window, wBar, &(sbi->rcScrollBar));
265 IntCalculateThumb(Window, wBar, sbi, pSBData);
269 co_IntGetScrollInfo(PWND Window
, INT nBar
, PSBDATA pSBData
, LPSCROLLINFO lpsi
)
274 ASSERT_REFS_CO(Window
);
276 if(!SBID_IS_VALID(nBar
))
278 EngSetLastError(ERROR_INVALID_PARAMETER
);
279 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar
);
283 if (!Window
->pSBInfo
)
285 ERR("IntGetScrollInfo No window scrollbar info!\n");
289 psi
= IntGetScrollInfoFromWindow(Window
, nBar
);
291 if (lpsi
->fMask
== SIF_ALL
)
293 Mask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
| SIF_TRACKPOS
;
300 if (0 != (Mask
& SIF_PAGE
))
302 lpsi
->nPage
= psi
->nPage
;
305 if (0 != (Mask
& SIF_POS
))
307 lpsi
->nPos
= psi
->nPos
;
310 if (0 != (Mask
& SIF_RANGE
))
312 lpsi
->nMin
= psi
->nMin
;
313 lpsi
->nMax
= psi
->nMax
;
316 if (0 != (Mask
& SIF_TRACKPOS
))
318 lpsi
->nTrackPos
= psi
->nTrackPos
;
325 NEWco_IntGetScrollInfo(
332 PSBTRACK pSBTrack
= pWnd
->head
.pti
->pSBTrack
;
334 if (!SBID_IS_VALID(nBar
))
336 EngSetLastError(ERROR_INVALID_PARAMETER
);
337 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar
);
341 if (!pWnd
->pSBInfo
|| !pSBTrack
) return FALSE
;
345 if (0 != (Mask
& SIF_PAGE
))
347 lpsi
->nPage
= pSBData
->page
;
350 if (0 != (Mask
& SIF_POS
))
352 lpsi
->nPos
= pSBData
->pos
;
355 if (0 != (Mask
& SIF_RANGE
))
357 lpsi
->nMin
= pSBData
->posMin
;
358 lpsi
->nMax
= pSBData
->posMax
;
361 if (0 != (Mask
& SIF_TRACKPOS
))
364 pSBTrack
->nBar
== nBar
&&
365 pSBTrack
->spwndTrack
== pWnd
)
366 lpsi
->nTrackPos
= pSBTrack
->posNew
;
368 lpsi
->nTrackPos
= pSBData
->pos
;
370 return (Mask
& SIF_ALL
) !=0;
373 /*************************************************************************
374 * SCROLL_GetScrollBarInfo
376 * Internal helper for the API function
379 * hwnd [I] Handle of window with scrollbar(s)
380 * idObject [I] One of OBJID_CLIENT, OBJID_HSCROLL, or OBJID_VSCROLL
381 * info [IO] cbSize specifies the size of the structure
387 static BOOL
SCROLL_GetScrollBarInfo(HWND hwnd
, LONG idObject
, LPSCROLLBARINFO info
)
389 LPSCROLLBAR_INFO infoPtr
;
392 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
398 case OBJID_CLIENT
: nBar
= SB_CTL
; break;
399 case OBJID_HSCROLL
: nBar
= SB_HORZ
; break;
400 case OBJID_VSCROLL
: nBar
= SB_VERT
; break;
401 default: return FALSE
;
404 /* handle invalid data structure */
405 if (info
->cbSize
!= sizeof(*info
))
408 SCROLL_GetScrollBarRect(hwnd
, nBar
, &info
->rcScrollBar
, &nDummy
,
409 &info
->dxyLineButton
, &info
->xyThumbTop
);
410 /* rcScrollBar needs to be in screen coordinates */
411 GetWindowRect(hwnd
, &rect
);
412 OffsetRect(&info
->rcScrollBar
, rect
.left
, rect
.top
);
414 info
->xyThumbBottom
= info
->xyThumbTop
+ info
->dxyLineButton
;
416 infoPtr
= SCROLL_GetInternalInfo(hwnd
, nBar
, TRUE
);
420 /* Scroll bar state */
421 info
->rgstate
[0] = 0;
422 if ((nBar
== SB_HORZ
&& !(style
& WS_HSCROLL
))
423 || (nBar
== SB_VERT
&& !(style
& WS_VSCROLL
)))
424 info
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
425 if (infoPtr
->minVal
>= infoPtr
->maxVal
- max(infoPtr
->page
- 1, 0))
427 if (!(info
->rgstate
[0] & STATE_SYSTEM_INVISIBLE
))
428 info
->rgstate
[0] |= STATE_SYSTEM_UNAVAILABLE
;
430 info
->rgstate
[0] |= STATE_SYSTEM_OFFSCREEN
;
432 if (nBar
== SB_CTL
&& !IsWindowEnabled(hwnd
))
433 info
->rgstate
[0] |= STATE_SYSTEM_UNAVAILABLE
;
435 pressed
= ((nBar
== SB_VERT
) == SCROLL_trackVertical
&& GetCapture() == hwnd
);
437 /* Top/left arrow button state. MSDN says top/right, but I don't believe it */
438 info
->rgstate
[1] = 0;
439 if (pressed
&& SCROLL_trackHitTest
== SCROLL_TOP_ARROW
)
440 info
->rgstate
[1] |= STATE_SYSTEM_PRESSED
;
441 if (infoPtr
->flags
& ESB_DISABLE_LTUP
)
442 info
->rgstate
[1] |= STATE_SYSTEM_UNAVAILABLE
;
444 /* Page up/left region state. MSDN says up/right, but I don't believe it */
445 info
->rgstate
[2] = 0;
446 if (infoPtr
->curVal
== infoPtr
->minVal
)
447 info
->rgstate
[2] |= STATE_SYSTEM_INVISIBLE
;
448 if (pressed
&& SCROLL_trackHitTest
== SCROLL_TOP_RECT
)
449 info
->rgstate
[2] |= STATE_SYSTEM_PRESSED
;
452 info
->rgstate
[3] = 0;
453 if (pressed
&& SCROLL_trackHitTest
== SCROLL_THUMB
)
454 info
->rgstate
[3] |= STATE_SYSTEM_PRESSED
;
456 /* Page down/right region state. MSDN says down/left, but I don't believe it */
457 info
->rgstate
[4] = 0;
458 if (infoPtr
->curVal
>= infoPtr
->maxVal
- 1)
459 info
->rgstate
[4] |= STATE_SYSTEM_INVISIBLE
;
460 if (pressed
&& SCROLL_trackHitTest
== SCROLL_BOTTOM_RECT
)
461 info
->rgstate
[4] |= STATE_SYSTEM_PRESSED
;
463 /* Bottom/right arrow button state. MSDN says bottom/left, but I don't believe it */
464 info
->rgstate
[5] = 0;
465 if (pressed
&& SCROLL_trackHitTest
== SCROLL_BOTTOM_ARROW
)
466 info
->rgstate
[5] |= STATE_SYSTEM_PRESSED
;
467 if (infoPtr
->flags
& ESB_DISABLE_RTDN
)
468 info
->rgstate
[5] |= STATE_SYSTEM_UNAVAILABLE
;
473 static DWORD FASTCALL
474 co_IntSetScrollInfo(PWND Window
, INT nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
)
477 * Update the scrollbar state and set action flags according to
478 * what has to be done graphics wise.
487 BOOL bChangeParams
= FALSE
; /* Don't show/hide scrollbar if params don't change */
491 ASSERT_REFS_CO(Window
);
493 if(!SBID_IS_VALID(nBar
))
495 EngSetLastError(ERROR_INVALID_PARAMETER
);
496 ERR("Trying to set scrollinfo for unknown scrollbar type %d", nBar
);
500 if(!co_IntCreateScrollBars(Window
))
505 if (lpsi
->cbSize
!= sizeof(SCROLLINFO
) &&
506 lpsi
->cbSize
!= (sizeof(SCROLLINFO
) - sizeof(lpsi
->nTrackPos
)))
508 EngSetLastError(ERROR_INVALID_PARAMETER
);
511 if (lpsi
->fMask
& ~(SIF_ALL
| SIF_DISABLENOSCROLL
| SIF_PREVIOUSPOS
))
513 EngSetLastError(ERROR_INVALID_PARAMETER
);
517 psbi
= IntGetScrollbarInfoFromWindow(Window
, nBar
);
518 Info
= IntGetScrollInfoFromWindow(Window
, nBar
);
519 pSBData
= IntGetSBData(Window
, nBar
);
521 /* Set the page size */
522 if (lpsi
->fMask
& SIF_PAGE
)
524 if (Info
->nPage
!= lpsi
->nPage
)
526 Info
->nPage
= lpsi
->nPage
;
527 pSBData
->page
= lpsi
->nPage
;
528 bChangeParams
= TRUE
;
532 /* Set the scroll pos */
533 if (lpsi
->fMask
& SIF_POS
)
535 if (Info
->nPos
!= lpsi
->nPos
)
538 Info
->nPos
= lpsi
->nPos
;
539 pSBData
->pos
= lpsi
->nPos
;
540 bChangeParams
= TRUE
;
544 /* Set the scroll range */
545 if (lpsi
->fMask
& SIF_RANGE
)
547 if (lpsi
->nMin
> lpsi
->nMax
)
549 Info
->nMin
= lpsi
->nMin
;
550 Info
->nMax
= lpsi
->nMin
;
551 pSBData
->posMin
= lpsi
->nMin
;
552 pSBData
->posMax
= lpsi
->nMin
;
553 bChangeParams
= TRUE
;
555 else if (Info
->nMin
!= lpsi
->nMin
|| Info
->nMax
!= lpsi
->nMax
)
557 Info
->nMin
= lpsi
->nMin
;
558 Info
->nMax
= lpsi
->nMax
;
559 pSBData
->posMin
= lpsi
->nMin
;
560 pSBData
->posMax
= lpsi
->nMax
;
561 bChangeParams
= TRUE
;
565 /* Make sure the page size is valid */
566 MaxPage
= abs(Info
->nMax
- Info
->nMin
) + 1;
567 if (Info
->nPage
> MaxPage
)
569 pSBData
->page
= Info
->nPage
= MaxPage
;
572 /* Make sure the pos is inside the range */
573 MaxPos
= Info
->nMax
+ 1 - (int)max(Info
->nPage
, 1);
574 ASSERT(MaxPos
>= Info
->nMin
);
575 if (Info
->nPos
< Info
->nMin
)
577 pSBData
->pos
= Info
->nPos
= Info
->nMin
;
579 else if (Info
->nPos
> MaxPos
)
581 pSBData
->pos
= Info
->nPos
= MaxPos
;
585 * Don't change the scrollbar state if SetScrollInfo is just called
586 * with SIF_DISABLENOSCROLL
588 if (!(lpsi
->fMask
& SIF_ALL
))
591 return lpsi
->fMask
& SIF_PREVIOUSPOS
? OldPos
: pSBData
->pos
;
594 /* Check if the scrollbar should be hidden or disabled */
595 if (lpsi
->fMask
& (SIF_RANGE
| SIF_PAGE
| SIF_DISABLENOSCROLL
))
597 new_flags
= Window
->pSBInfo
->WSBflags
;
598 if (Info
->nMin
>= (int)(Info
->nMax
- max(Info
->nPage
- 1, 0)))
600 /* Hide or disable scroll-bar */
601 if (lpsi
->fMask
& SIF_DISABLENOSCROLL
)
603 new_flags
= ESB_DISABLE_BOTH
;
604 bChangeParams
= TRUE
;
606 else if ((nBar
!= SB_CTL
) && bChangeParams
)
608 action
= SA_SSI_HIDE
;
611 else /* Show and enable scroll-bar only if no page only changed. */
612 if (lpsi
->fMask
!= SIF_PAGE
)
614 new_flags
= ESB_ENABLE_BOTH
;
615 if ((nBar
!= SB_CTL
) && bChangeParams
)
617 action
|= SA_SSI_SHOW
;
621 if (Window
->pSBInfo
->WSBflags
!= new_flags
) /* Check arrow flags */
623 Window
->pSBInfo
->WSBflags
= new_flags
;
624 action
|= SA_SSI_REPAINT_ARROWS
;
629 if ( action
& SA_SSI_HIDE
)
631 co_UserShowScrollBar(Window
, nBar
, FALSE
, FALSE
);
635 if ( action
& SA_SSI_SHOW
)
636 if ( co_UserShowScrollBar(Window
, nBar
, TRUE
, TRUE
) )
637 return lpsi
->fMask
& SIF_PREVIOUSPOS
? OldPos
: pSBData
->pos
; /* SetWindowPos() already did the painting */
639 { // FIXME: Arrows and interior.
640 RECTL UpdateRect
= psbi
->rcScrollBar
;
641 UpdateRect
.left
-= Window
->rcClient
.left
- Window
->rcWindow
.left
;
642 UpdateRect
.right
-= Window
->rcClient
.left
- Window
->rcWindow
.left
;
643 UpdateRect
.top
-= Window
->rcClient
.top
- Window
->rcWindow
.top
;
644 UpdateRect
.bottom
-= Window
->rcClient
.top
- Window
->rcWindow
.top
;
645 co_UserRedrawWindow(Window
, &UpdateRect
, 0, RDW_INVALIDATE
| RDW_FRAME
);
647 /* else if( action & SA_SSI_REPAINT_ARROWS )
649 RECTL UpdateRect = psbi->rcScrollBar;
650 UpdateRect.left -= Window->rcClient.left - Window->rcWindow.left;
651 UpdateRect.right -= Window->rcClient.left - Window->rcWindow.left;
652 UpdateRect.top -= Window->rcClient.top - Window->rcWindow.top;
653 UpdateRect.bottom -= Window->rcClient.top - Window->rcWindow.top;
654 co_UserRedrawWindow(Window, &UpdateRect, 0, RDW_INVALIDATE | RDW_FRAME);
658 if (bChangeParams
&& (nBar
== SB_HORZ
|| nBar
== SB_VERT
) && (lpsi
->fMask
& SIF_DISABLENOSCROLL
))
660 IntEnableScrollBar(nBar
== SB_HORZ
, psbi
, Window
->pSBInfo
->WSBflags
);
663 /* Return current position */
664 return lpsi
->fMask
& SIF_PREVIOUSPOS
? OldPos
: pSBData
->pos
;
668 co_IntGetScrollBarInfo(PWND Window
, LONG idObject
, PSCROLLBARINFO psbi
)
673 ASSERT_REFS_CO(Window
);
675 Bar
= SBOBJ_TO_SBID(idObject
);
677 if(!SBID_IS_VALID(Bar
))
679 EngSetLastError(ERROR_INVALID_PARAMETER
);
680 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar
);
684 if(!co_IntCreateScrollBars(Window
))
686 ERR("Failed to create scrollbars for window.\n");
690 sbi
= IntGetScrollbarInfoFromWindow(Window
, Bar
);
691 pSBData
= IntGetSBData(Window
, Bar
);
693 IntGetScrollBarRect(Window
, Bar
, &(sbi
->rcScrollBar
));
694 IntCalculateThumb(Window
, Bar
, sbi
, pSBData
);
696 /* Scroll bar state */
697 psbi
->rgstate
[0] = 0;
698 if ((Bar
== SB_HORZ
&& !(Window
->style
& WS_HSCROLL
))
699 || (Bar
== SB_VERT
&& !(Window
->style
& WS_VSCROLL
)))
700 psbi
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
701 if (pSBData
->posMin
>= pSBData
->posMax
- max(pSBData
->page
- 1, 0))
703 if (!(psbi
->rgstate
[0] & STATE_SYSTEM_INVISIBLE
))
704 psbi
->rgstate
[0] |= STATE_SYSTEM_UNAVAILABLE
;
706 psbi
->rgstate
[0] |= STATE_SYSTEM_OFFSCREEN
;
708 if (Bar
== SB_CTL
&& !(Window
->style
& WS_DISABLED
))
709 psbi
->rgstate
[0] |= STATE_SYSTEM_UNAVAILABLE
;
711 RtlCopyMemory(psbi
, sbi
, sizeof(SCROLLBARINFO
));
717 co_IntSetScrollBarInfo(PWND Window
, LONG idObject
, PSETSCROLLBARINFO psbi
)
722 ASSERT_REFS_CO(Window
);
724 Bar
= SBOBJ_TO_SBID(idObject
);
726 if(!SBID_IS_VALID(Bar
))
728 EngSetLastError(ERROR_INVALID_PARAMETER
);
729 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar
);
733 if(!co_IntCreateScrollBars(Window
))
735 ERR("Failed to create scrollbars for window.\n");
739 sbi
= IntGetScrollbarInfoFromWindow(Window
, Bar
);
740 psi
= IntGetScrollInfoFromWindow(Window
, Bar
);
742 psi
->nTrackPos
= psbi
->nTrackPos
;
743 sbi
->reserved
= psbi
->reserved
;
744 RtlCopyMemory(&sbi
->rgstate
, &psbi
->rgstate
, sizeof(psbi
->rgstate
));
750 co_IntCreateScrollBars(PWND Window
)
757 ASSERT_REFS_CO(Window
);
759 if (Window
->pSBInfo
&& Window
->pSBInfoex
)
761 /* No need to create it anymore */
765 /* Allocate memory for all scrollbars (HORZ, VERT, CONTROL) */
766 Size
= 3 * (sizeof(SBINFOEX
));
767 if(!(Window
->pSBInfoex
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_SBARINFO
)))
769 ERR("Unable to allocate memory for scrollbar information for window %p\n", Window
->head
.h
);
773 RtlZeroMemory(Window
->pSBInfoex
, Size
);
775 if(!(Window
->pSBInfo
= DesktopHeapAlloc( Window
->head
.rpdesk
, sizeof(SBINFO
))))
777 ERR("Unable to allocate memory for scrollbar information for window %p\n", Window
->head
.h
);
781 RtlZeroMemory(Window
->pSBInfo
, sizeof(SBINFO
));
782 Window
->pSBInfo
->Vert
.posMax
= 100;
783 Window
->pSBInfo
->Horz
.posMax
= 100;
785 co_WinPosGetNonClientSize(Window
,
789 for(s
= SB_HORZ
; s
<= SB_VERT
; s
++)
791 psbi
= IntGetScrollbarInfoFromWindow(Window
, s
);
792 psbi
->cbSize
= sizeof(SCROLLBARINFO
);
793 for (i
= 0; i
< CCHILDREN_SCROLLBAR
+ 1; i
++)
794 psbi
->rgstate
[i
] = 0;
796 pSBData
= IntGetSBData(Window
, s
);
798 IntGetScrollBarRect(Window
, s
, &(psbi
->rcScrollBar
));
799 IntCalculateThumb(Window
, s
, psbi
, pSBData
);
806 IntDestroyScrollBars(PWND Window
)
808 if (Window
->pSBInfo
&& Window
->pSBInfoex
)
810 DesktopHeapFree(Window
->head
.rpdesk
, Window
->pSBInfo
);
811 Window
->pSBInfo
= NULL
;
812 ExFreePoolWithTag(Window
->pSBInfoex
, TAG_SBARINFO
);
813 Window
->pSBInfoex
= NULL
;
820 IntEnableScrollBar(BOOL Horz
, PSCROLLBARINFO Info
, UINT wArrows
)
825 case ESB_DISABLE_BOTH
:
826 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
827 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
829 case ESB_DISABLE_RTDN
:
832 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
836 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
839 case ESB_DISABLE_LTUP
:
842 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
846 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
849 case ESB_ENABLE_BOTH
:
850 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, 0);
851 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, 0);
857 /* Ported from WINE20020904 (SCROLL_ShowScrollBar) */
859 co_UserShowScrollBar(PWND Wnd
, int nBar
, BOOL fShowH
, BOOL fShowV
)
861 ULONG old_style
, set_bits
= 0, clear_bits
= 0;
869 //IntUpdateSBInfo(Wnd, SB_CTL); // Is this needed? Was tested w/o!
871 co_WinPosShowWindow(Wnd
, fShowH
? SW_SHOW
: SW_HIDE
);
876 if (fShowH
) set_bits
|= WS_HSCROLL
;
877 else clear_bits
|= WS_HSCROLL
;
878 if( nBar
== SB_HORZ
) break;
881 if (fShowV
) set_bits
|= WS_VSCROLL
;
882 else clear_bits
|= WS_VSCROLL
;
885 EngSetLastError(ERROR_INVALID_PARAMETER
);
886 return FALSE
; /* Nothing to do! */
889 old_style
= IntSetStyle( Wnd
, set_bits
, clear_bits
);
890 if ((old_style
& clear_bits
) != 0 || (old_style
& set_bits
) != set_bits
)
892 ///// Is this needed? Was tested w/o!
893 //if (Wnd->style & WS_HSCROLL) IntUpdateSBInfo(Wnd, SB_HORZ);
894 //if (Wnd->style & WS_VSCROLL) IntUpdateSBInfo(Wnd, SB_VERT);
896 /* Frame has been changed, let the window redraw itself */
897 co_WinPosSetWindowPos( Wnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
898 | SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
901 return FALSE
; /* no frame changes */
905 IntDrawScrollInterior(PWND pWnd
, HDC hDC
, INT nBar
, BOOL Vertical
, PSCROLLBARINFO ScrollBarInfo
)
907 INT ThumbSize
= ScrollBarInfo
->xyThumbBottom
- ScrollBarInfo
->xyThumbTop
;
908 INT ThumbTop
= ScrollBarInfo
->xyThumbTop
;
910 HBRUSH hSaveBrush
, hBrush
;
911 BOOL TopSelected
= FALSE
, BottomSelected
= FALSE
;
913 if (ScrollBarInfo
->rgstate
[SCROLL_TOP_RECT
] & STATE_SYSTEM_PRESSED
)
915 if (ScrollBarInfo
->rgstate
[SCROLL_BOTTOM_RECT
] & STATE_SYSTEM_PRESSED
)
916 BottomSelected
= TRUE
;
919 * Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
920 * The window-owned scrollbars need to call DefWndControlColor
921 * to correctly setup default scrollbar colors
925 hBrush
= GetControlBrush( pWnd
, hDC
, WM_CTLCOLORSCROLLBAR
);
927 hBrush
= IntGetSysColorBrush(COLOR_SCROLLBAR
);
931 hBrush
= DefWndControlColor(hDC
, CTLCOLOR_SCROLLBAR
);
934 hSaveBrush
= NtGdiSelectBrush(hDC
, hBrush
);
936 /* Calculate the scroll rectangle */
939 Rect
.top
= ScrollBarInfo
->rcScrollBar
.top
+ ScrollBarInfo
->dxyLineButton
;
940 Rect
.bottom
= ScrollBarInfo
->rcScrollBar
.bottom
- ScrollBarInfo
->dxyLineButton
;
941 Rect
.left
= ScrollBarInfo
->rcScrollBar
.left
;
942 Rect
.right
= ScrollBarInfo
->rcScrollBar
.right
;
946 Rect
.top
= ScrollBarInfo
->rcScrollBar
.top
;
947 Rect
.bottom
= ScrollBarInfo
->rcScrollBar
.bottom
;
948 Rect
.left
= ScrollBarInfo
->rcScrollBar
.left
+ ScrollBarInfo
->dxyLineButton
;
949 Rect
.right
= ScrollBarInfo
->rcScrollBar
.right
- ScrollBarInfo
->dxyLineButton
;
952 /* Draw the scroll rectangles and thumb */
953 if (!ScrollBarInfo
->xyThumbBottom
)
955 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
- Rect
.left
,
956 Rect
.bottom
- Rect
.top
, PATCOPY
);
958 /* Cleanup and return */
959 NtGdiSelectBrush(hDC
, hSaveBrush
);
963 ThumbTop
-= ScrollBarInfo
->dxyLineButton
;
965 if (ScrollBarInfo
->dxyLineButton
)
971 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
- Rect
.left
,
972 ThumbTop
, TopSelected
? BLACKNESS
: PATCOPY
);
973 Rect
.top
+= ThumbTop
;
974 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
+ ThumbSize
, Rect
.right
- Rect
.left
,
975 Rect
.bottom
- Rect
.top
- ThumbSize
, BottomSelected
? BLACKNESS
: PATCOPY
);
976 Rect
.bottom
= Rect
.top
+ ThumbSize
;
982 NtGdiPatBlt(hDC
, Rect
.left
, ScrollBarInfo
->dxyLineButton
,
983 Rect
.right
- Rect
.left
, Rect
.bottom
- Rect
.top
, PATCOPY
);
991 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, ThumbTop
,
992 Rect
.bottom
- Rect
.top
, TopSelected
? BLACKNESS
: PATCOPY
);
993 Rect
.left
+= ThumbTop
;
994 NtGdiPatBlt(hDC
, Rect
.left
+ ThumbSize
, Rect
.top
,
995 Rect
.right
- Rect
.left
- ThumbSize
, Rect
.bottom
- Rect
.top
,
996 BottomSelected
? BLACKNESS
: PATCOPY
);
997 Rect
.right
= Rect
.left
+ ThumbSize
;
1003 NtGdiPatBlt(hDC
, ScrollBarInfo
->dxyLineButton
, Rect
.top
,
1004 Rect
.right
- Rect
.left
, Rect
.bottom
- Rect
.top
, PATCOPY
);
1010 /* Draw the thumb */
1012 DrawEdge(hDC
, &Rect
, EDGE_RAISED
, BF_RECT
| BF_MIDDLE
);
1015 NtGdiSelectBrush(hDC
, hSaveBrush
);
1019 static VOID FASTCALL
1020 IntDrawScrollArrows(HDC hDC
, PSCROLLBARINFO ScrollBarInfo
, BOOL Vertical
)
1022 RECT RectLT
, RectRB
;
1023 INT ScrollDirFlagLT
, ScrollDirFlagRB
;
1025 RectLT
= RectRB
= ScrollBarInfo
->rcScrollBar
;
1028 ScrollDirFlagLT
= DFCS_SCROLLUP
;
1029 ScrollDirFlagRB
= DFCS_SCROLLDOWN
;
1030 RectLT
.bottom
= RectLT
.top
+ ScrollBarInfo
->dxyLineButton
;
1031 RectRB
.top
= RectRB
.bottom
- ScrollBarInfo
->dxyLineButton
;
1035 ScrollDirFlagLT
= DFCS_SCROLLLEFT
;
1036 ScrollDirFlagRB
= DFCS_SCROLLRIGHT
;
1037 RectLT
.right
= RectLT
.left
+ ScrollBarInfo
->dxyLineButton
;
1038 RectRB
.left
= RectRB
.right
- ScrollBarInfo
->dxyLineButton
;
1041 if (ScrollBarInfo
->rgstate
[SCROLL_TOP_ARROW
] & STATE_SYSTEM_PRESSED
)
1043 ScrollDirFlagLT
|= DFCS_PUSHED
| DFCS_FLAT
;
1045 if (ScrollBarInfo
->rgstate
[SCROLL_TOP_ARROW
] & STATE_SYSTEM_UNAVAILABLE
)
1047 ScrollDirFlagLT
|= DFCS_INACTIVE
;
1049 if (ScrollBarInfo
->rgstate
[SCROLL_BOTTOM_ARROW
] & STATE_SYSTEM_PRESSED
)
1051 ScrollDirFlagRB
|= DFCS_PUSHED
| DFCS_FLAT
;
1053 if (ScrollBarInfo
->rgstate
[SCROLL_BOTTOM_ARROW
] & STATE_SYSTEM_UNAVAILABLE
)
1055 ScrollDirFlagRB
|= DFCS_INACTIVE
;
1058 DrawFrameControl(hDC
, &RectLT
, DFC_SCROLL
, ScrollDirFlagLT
);
1059 DrawFrameControl(hDC
, &RectRB
, DFC_SCROLL
, ScrollDirFlagRB
);
1062 static LONG FASTCALL
1063 IntScrollGetObjectId(INT SBType
)
1065 if (SBType
== SB_VERT
)
1066 return OBJID_VSCROLL
;
1067 if (SBType
== SB_HORZ
)
1068 return OBJID_HSCROLL
;
1069 return OBJID_CLIENT
;
1073 IntDrawScrollBar(PWND Wnd
, HDC DC
, INT Bar
)
1081 pti
= PsGetCurrentThreadWin32Thread();
1084 * Get scroll bar info.
1097 Vertical
= (Wnd
->style
& SBS_VERT
) != 0;
1104 if (!co_IntGetScrollBarInfo(Wnd
, IntScrollGetObjectId(Bar
), &Info
))
1109 if (RECTL_bIsEmptyRect(&Info
.rcScrollBar
))
1114 //ThumbSize = pSBWnd->pSBCalc->pxThumbBottom - pSBWnd->pSBCalc->pxThumbTop;
1119 if (Info
.dxyLineButton
)
1121 IntDrawScrollArrows(DC
, &Info
, Vertical
);
1125 * Draw the interior.
1127 IntDrawScrollInterior(Wnd
, DC
, Bar
, Vertical
, &Info
);
1130 * If scroll bar has focus, reposition the caret.
1132 if ( Wnd
== pti
->MessageQueue
->spwndFocus
&& Bar
== SB_CTL
)
1136 co_IntSetCaretPos(Info
.rcScrollBar
.top
+ 1, Info
.dxyLineButton
+ 1);
1140 co_IntSetCaretPos(Info
.dxyLineButton
+ 1, Info
.rcScrollBar
.top
+ 1);
1147 ScrollBarWndProc(HWND hWnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
1149 LRESULT lResult
= 0;
1151 pWnd
= UserGetWindowObject(hWnd
);
1152 if (!pWnd
) return 0;
1160 pWnd
->pSBInfo
->WSBflags
= wParam
? ESB_ENABLE_BOTH
: ESB_DISABLE_BOTH
;
1172 NtUserGetScrollBarInfo(HWND hWnd
, LONG idObject
, PSCROLLBARINFO psbi
)
1178 DECLARE_RETURN(BOOL
);
1179 USER_REFERENCE_ENTRY Ref
;
1181 TRACE("Enter NtUserGetScrollBarInfo\n");
1182 UserEnterExclusive();
1184 Status
= MmCopyFromCaller(&sbi
, psbi
, sizeof(SCROLLBARINFO
));
1185 if(!NT_SUCCESS(Status
) || (sbi
.cbSize
!= sizeof(SCROLLBARINFO
)))
1187 SetLastNtError(Status
);
1191 if(!(Window
= UserGetWindowObject(hWnd
)))
1196 UserRefObjectCo(Window
, &Ref
);
1197 Ret
= co_IntGetScrollBarInfo(Window
, idObject
, &sbi
);
1198 UserDerefObjectCo(Window
);
1200 Status
= MmCopyToCaller(psbi
, &sbi
, sizeof(SCROLLBARINFO
));
1201 if(!NT_SUCCESS(Status
))
1203 SetLastNtError(Status
);
1210 TRACE("Leave NtUserGetScrollBarInfo, ret=%i\n",_ret_
);
1228 DECLARE_RETURN(BOOL
);
1229 USER_REFERENCE_ENTRY Ref
;
1231 TRACE("Enter NtUserGetScrollInfo\n");
1236 RtlCopyMemory(&psi
, lpsi
, sizeof(SCROLLINFO
));
1239 RtlCopyMemory(&SBDataSafe
, pSBData
, sizeof(SBDATA
));
1242 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1244 ERR("NtUserGetScrollInfo Failed size.\n");
1245 SetLastNtError(_SEH2_GetExceptionCode());
1246 _SEH2_YIELD(RETURN(FALSE
));
1250 if(!(Window
= UserGetWindowObject(hWnd
)))
1252 ERR("NtUserGetScrollInfo Bad window.\n");
1256 UserRefObjectCo(Window
, &Ref
);
1257 Ret
= co_IntGetScrollInfo(Window
, fnBar
, &SBDataSafe
, &psi
);
1258 UserDerefObjectCo(Window
);
1262 RtlCopyMemory(lpsi
, &psi
, sizeof(SCROLLINFO
));
1264 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1266 ERR("NtUserGetScrollInfo Failed copy to user.\n");
1267 SetLastNtError(_SEH2_GetExceptionCode());
1268 _SEH2_YIELD(RETURN(FALSE
));
1275 TRACE("Leave NtUserGetScrollInfo, ret=%i\n",_ret_
);
1282 NtUserEnableScrollBar(
1289 PSCROLLBARINFO InfoV
= NULL
, InfoH
= NULL
;
1291 DECLARE_RETURN(BOOL
);
1292 USER_REFERENCE_ENTRY Ref
;
1294 TRACE("Enter NtUserEnableScrollBar\n");
1295 UserEnterExclusive();
1297 if (!(Window
= UserGetWindowObject(hWnd
)) ||
1298 UserIsDesktopWindow(Window
) || UserIsMessageWindow(Window
))
1302 UserRefObjectCo(Window
, &Ref
);
1304 if (!co_IntCreateScrollBars(Window
))
1309 OrigArrows
= Window
->pSBInfo
->WSBflags
;
1310 Window
->pSBInfo
->WSBflags
= wArrows
;
1312 if (wSBflags
== SB_CTL
)
1314 if ((wArrows
== ESB_DISABLE_BOTH
|| wArrows
== ESB_ENABLE_BOTH
))
1315 IntEnableWindow(hWnd
, (wArrows
== ESB_ENABLE_BOTH
));
1320 if(wSBflags
!= SB_BOTH
&& !SBID_IS_VALID(wSBflags
))
1322 EngSetLastError(ERROR_INVALID_PARAMETER
);
1323 ERR("Trying to set scrollinfo for unknown scrollbar type %u", wSBflags
);
1330 InfoV
= IntGetScrollbarInfoFromWindow(Window
, SB_VERT
);
1333 InfoH
= IntGetScrollbarInfoFromWindow(Window
, SB_HORZ
);
1336 InfoV
= IntGetScrollbarInfoFromWindow(Window
, SB_VERT
);
1343 Chg
= IntEnableScrollBar(FALSE
, InfoV
, wArrows
);
1346 Chg
= (IntEnableScrollBar(TRUE
, InfoH
, wArrows
) || Chg
);
1348 ERR("FIXME: EnableScrollBar wSBflags %u wArrows %u Chg %d\n", wSBflags
, wArrows
, Chg
);
1350 // SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE );
1353 if (OrigArrows
== wArrows
) RETURN( FALSE
);
1358 UserDerefObjectCo(Window
);
1360 TRACE("Leave NtUserEnableScrollBar, ret=%i\n",_ret_
);
1367 NtUserSetScrollInfo(
1375 SCROLLINFO ScrollInfo
;
1376 DECLARE_RETURN(DWORD
);
1377 USER_REFERENCE_ENTRY Ref
;
1379 TRACE("Enter NtUserSetScrollInfo\n");
1380 UserEnterExclusive();
1382 if(!(Window
= UserGetWindowObject(hWnd
)) ||
1383 UserIsDesktopWindow(Window
) || UserIsMessageWindow(Window
))
1387 UserRefObjectCo(Window
, &Ref
);
1389 Status
= MmCopyFromCaller(&ScrollInfo
, lpsi
, sizeof(SCROLLINFO
) - sizeof(ScrollInfo
.nTrackPos
));
1390 if(!NT_SUCCESS(Status
))
1392 SetLastNtError(Status
);
1396 RETURN(co_IntSetScrollInfo(Window
, fnBar
, &ScrollInfo
, bRedraw
));
1400 UserDerefObjectCo(Window
);
1402 TRACE("Leave NtUserSetScrollInfo, ret=%lu\n", _ret_
);
1409 NtUserShowScrollBar(HWND hWnd
, int nBar
, DWORD bShow
)
1412 DECLARE_RETURN(DWORD
);
1414 USER_REFERENCE_ENTRY Ref
;
1416 TRACE("Enter NtUserShowScrollBar\n");
1417 UserEnterExclusive();
1419 if (!(Window
= UserGetWindowObject(hWnd
)))
1424 UserRefObjectCo(Window
, &Ref
);
1425 ret
= co_UserShowScrollBar(Window
, nBar
, (nBar
== SB_VERT
) ? 0 : bShow
,
1426 (nBar
== SB_HORZ
) ? 0 : bShow
);
1427 UserDerefObjectCo(Window
);
1432 TRACE("Leave NtUserShowScrollBar, ret%lu\n", _ret_
);
1439 //// Ugly NtUser API ////
1443 NtUserSetScrollBarInfo(
1446 SETSCROLLBARINFO
*info
)
1449 SETSCROLLBARINFO Safeinfo
;
1454 DECLARE_RETURN(BOOL
);
1455 USER_REFERENCE_ENTRY Ref
;
1457 TRACE("Enter NtUserSetScrollBarInfo\n");
1458 UserEnterExclusive();
1460 if(!(Window
= UserGetWindowObject(hWnd
)))
1464 UserRefObjectCo(Window
, &Ref
);
1466 Obj
= SBOBJ_TO_SBID(idObject
);
1467 if(!SBID_IS_VALID(Obj
))
1469 EngSetLastError(ERROR_INVALID_PARAMETER
);
1470 ERR("Trying to set scrollinfo for unknown scrollbar type %d\n", Obj
);
1474 if(!co_IntCreateScrollBars(Window
))
1479 Status
= MmCopyFromCaller(&Safeinfo
, info
, sizeof(SETSCROLLBARINFO
));
1480 if(!NT_SUCCESS(Status
))
1482 SetLastNtError(Status
);
1486 sbi
= IntGetScrollbarInfoFromWindow(Window
, Obj
);
1487 psi
= IntGetScrollInfoFromWindow(Window
, Obj
);
1489 psi
->nTrackPos
= Safeinfo
.nTrackPos
;
1490 sbi
->reserved
= Safeinfo
.reserved
;
1491 RtlCopyMemory(&sbi
->rgstate
, &Safeinfo
.rgstate
, sizeof(Safeinfo
.rgstate
));
1497 UserDerefObjectCo(Window
);
1499 TRACE("Leave NtUserSetScrollBarInfo, ret=%i\n",_ret_
);