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 *****************************************************************/
61 /* Ported from WINE20020904 */
62 /* Compute the scroll bar rectangle, in drawing coordinates (i.e. client coords for SB_CTL, window coords for SB_VERT and
63 * SB_HORZ). 'arrowSize' returns the width or height of an arrow (depending on * the orientation of the scrollbar),
64 * 'thumbSize' returns the size of the thumb, and 'thumbPos' returns the position of the thumb relative to the left or to
65 * the top. Return TRUE if the scrollbar is vertical, FALSE if horizontal.
67 static inline void mirror_rect( const RECT
*window_rect
, RECT
*rect
)
69 int width
= window_rect
->right
- window_rect
->left
;
71 rect
->left
= width
- rect
->right
;
72 rect
->right
= width
- tmp
;
76 IntGetSBData(PWND pwnd
, INT Bar
)
81 pSBInfo
= pwnd
->pSBInfo
;
85 return &pSBInfo
->Horz
;
87 return &pSBInfo
->Vert
;
89 if ( pwnd
->cbwndExtra
!= (sizeof(SBWND
)-sizeof(WND
)) )
91 ERR("IntGetSBData Wrong Extra bytes for CTL Scrollbar!\n");
94 pSBWnd
= (PSBWND
)pwnd
;
95 return (PSBDATA
)&pSBWnd
->SBCalc
;
97 ERR("IntGetSBData Bad Bar!\n");
103 IntGetScrollBarRect (PWND Wnd
, INT nBar
, RECTL
*lprect
)
106 *lprect
= Wnd
->rcClient
;
108 RECTL_vOffsetRect( lprect
, -Wnd
->rcWindow
.left
, -Wnd
->rcWindow
.top
);
109 if (Wnd
->ExStyle
& WS_EX_LAYOUTRTL
)
110 mirror_rect( &Wnd
->rcWindow
, lprect
);
115 lprect
->top
= lprect
->bottom
;
116 lprect
->bottom
+= UserGetSystemMetrics (SM_CYHSCROLL
);
117 if (Wnd
->style
& WS_BORDER
)
122 else if (Wnd
->style
& WS_VSCROLL
)
130 if(Wnd
->ExStyle
& WS_EX_LEFTSCROLLBAR
)
132 lprect
->right
= lprect
->left
;
133 lprect
->left
-= UserGetSystemMetrics(SM_CXVSCROLL
);
137 lprect
->left
= lprect
->right
;
138 lprect
->right
+= UserGetSystemMetrics(SM_CXVSCROLL
);
140 if (Wnd
->style
& WS_BORDER
)
145 else if (Wnd
->style
& WS_HSCROLL
)
153 IntGetClientRect (Wnd
, lprect
);
154 vertical
= !!(Wnd
->style
& SBS_VERT
);
165 IntCalculateThumb(PWND Wnd
, LONG idObject
, PSCROLLBARINFO psbi
, PSBDATA pSBData
)
167 INT Thumb
, ThumbBox
, ThumbPos
, cxy
, mx
;
173 Thumb
= UserGetSystemMetrics(SM_CXHSCROLL
);
174 cxy
= psbi
->rcScrollBar
.right
- psbi
->rcScrollBar
.left
;
177 Thumb
= UserGetSystemMetrics(SM_CYVSCROLL
);
178 cxy
= psbi
->rcScrollBar
.bottom
- psbi
->rcScrollBar
.top
;
181 IntGetClientRect(Wnd
, &ClientRect
);
182 if(Wnd
->style
& SBS_VERT
)
184 Thumb
= UserGetSystemMetrics(SM_CYVSCROLL
);
185 cxy
= ClientRect
.bottom
- ClientRect
.top
;
189 Thumb
= UserGetSystemMetrics(SM_CXHSCROLL
);
190 cxy
= ClientRect
.right
- ClientRect
.left
;
198 /* Calculate Thumb */
199 if(cxy
<= (2 * Thumb
))
202 psbi
->xyThumbTop
= 0;
203 psbi
->xyThumbBottom
= 0;
208 ThumbBox
= pSBData
->page
? MINTRACKTHUMB
: UserGetSystemMetrics(SM_CXHTHUMB
);
214 ThumbBox
= max(EngMulDiv(cxy
, pSBData
->page
, pSBData
->posMax
- pSBData
->posMin
+ 1), ThumbBox
);
219 mx
= pSBData
->posMax
- max(pSBData
->page
- 1, 0);
220 if(pSBData
->posMin
< mx
)
221 ThumbPos
= Thumb
+ EngMulDiv(cxy
- ThumbBox
, pSBData
->pos
- pSBData
->posMin
, mx
- pSBData
->posMin
);
223 ThumbPos
= Thumb
+ ThumbBox
;
226 psbi
->xyThumbTop
= ThumbPos
;
227 psbi
->xyThumbBottom
= ThumbPos
+ ThumbBox
;
231 psbi
->xyThumbTop
= 0;
232 psbi
->xyThumbBottom
= 0;
235 psbi
->dxyLineButton
= Thumb
;
241 IntUpdateSBInfo(PWND Window, int wBar)
247 ASSERT(Window->pSBInfo);
248 ASSERT(Window->pSBInfoex);
250 sbi = IntGetScrollbarInfoFromWindow(Window, wBar);
251 pSBData = IntGetSBData(Window, wBar);
252 IntGetScrollBarRect(Window, wBar, &(sbi->rcScrollBar));
253 IntCalculateThumb(Window, wBar, sbi, pSBData);
257 co_IntGetScrollInfo(PWND Window
, INT nBar
, PSBDATA pSBData
, LPSCROLLINFO lpsi
)
262 ASSERT_REFS_CO(Window
);
264 if(!SBID_IS_VALID(nBar
))
266 EngSetLastError(ERROR_INVALID_PARAMETER
);
267 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar
);
271 if (!Window
->pSBInfo
)
273 ERR("IntGetScrollInfo No window scrollbar info!\n");
277 psi
= IntGetScrollInfoFromWindow(Window
, nBar
);
279 if (lpsi
->fMask
== SIF_ALL
)
281 Mask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
| SIF_TRACKPOS
;
288 if (0 != (Mask
& SIF_PAGE
))
290 lpsi
->nPage
= psi
->nPage
;
293 if (0 != (Mask
& SIF_POS
))
295 lpsi
->nPos
= psi
->nPos
;
298 if (0 != (Mask
& SIF_RANGE
))
300 lpsi
->nMin
= psi
->nMin
;
301 lpsi
->nMax
= psi
->nMax
;
304 if (0 != (Mask
& SIF_TRACKPOS
))
306 lpsi
->nTrackPos
= psi
->nTrackPos
;
313 NEWco_IntGetScrollInfo(
320 PSBTRACK pSBTrack
= pWnd
->head
.pti
->pSBTrack
;
322 if (!SBID_IS_VALID(nBar
))
324 EngSetLastError(ERROR_INVALID_PARAMETER
);
325 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar
);
329 if (!pWnd
->pSBInfo
|| !pSBTrack
) return FALSE
;
333 if (0 != (Mask
& SIF_PAGE
))
335 lpsi
->nPage
= pSBData
->page
;
338 if (0 != (Mask
& SIF_POS
))
340 lpsi
->nPos
= pSBData
->pos
;
343 if (0 != (Mask
& SIF_RANGE
))
345 lpsi
->nMin
= pSBData
->posMin
;
346 lpsi
->nMax
= pSBData
->posMax
;
349 if (0 != (Mask
& SIF_TRACKPOS
))
352 pSBTrack
->nBar
== nBar
&&
353 pSBTrack
->spwndTrack
== pWnd
)
354 lpsi
->nTrackPos
= pSBTrack
->posNew
;
356 lpsi
->nTrackPos
= pSBData
->pos
;
358 return (Mask
& SIF_ALL
) !=0;
361 /*************************************************************************
362 * SCROLL_GetScrollBarInfo
364 * Internal helper for the API function
367 * hwnd [I] Handle of window with scrollbar(s)
368 * idObject [I] One of OBJID_CLIENT, OBJID_HSCROLL, or OBJID_VSCROLL
369 * info [IO] cbSize specifies the size of the structure
375 static BOOL
SCROLL_GetScrollBarInfo(HWND hwnd
, LONG idObject
, LPSCROLLBARINFO info
)
377 LPSCROLLBAR_INFO infoPtr
;
380 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
386 case OBJID_CLIENT
: nBar
= SB_CTL
; break;
387 case OBJID_HSCROLL
: nBar
= SB_HORZ
; break;
388 case OBJID_VSCROLL
: nBar
= SB_VERT
; break;
389 default: return FALSE
;
392 /* handle invalid data structure */
393 if (info
->cbSize
!= sizeof(*info
))
396 SCROLL_GetScrollBarRect(hwnd
, nBar
, &info
->rcScrollBar
, &nDummy
,
397 &info
->dxyLineButton
, &info
->xyThumbTop
);
398 /* rcScrollBar needs to be in screen coordinates */
399 GetWindowRect(hwnd
, &rect
);
400 OffsetRect(&info
->rcScrollBar
, rect
.left
, rect
.top
);
402 info
->xyThumbBottom
= info
->xyThumbTop
+ info
->dxyLineButton
;
404 infoPtr
= SCROLL_GetInternalInfo(hwnd
, nBar
, TRUE
);
408 /* Scroll bar state */
409 info
->rgstate
[0] = 0;
410 if ((nBar
== SB_HORZ
&& !(style
& WS_HSCROLL
))
411 || (nBar
== SB_VERT
&& !(style
& WS_VSCROLL
)))
412 info
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
413 if (infoPtr
->minVal
>= infoPtr
->maxVal
- max(infoPtr
->page
- 1, 0))
415 if (!(info
->rgstate
[0] & STATE_SYSTEM_INVISIBLE
))
416 info
->rgstate
[0] |= STATE_SYSTEM_UNAVAILABLE
;
418 info
->rgstate
[0] |= STATE_SYSTEM_OFFSCREEN
;
420 if (nBar
== SB_CTL
&& !IsWindowEnabled(hwnd
))
421 info
->rgstate
[0] |= STATE_SYSTEM_UNAVAILABLE
;
423 pressed
= ((nBar
== SB_VERT
) == SCROLL_trackVertical
&& GetCapture() == hwnd
);
425 /* Top/left arrow button state. MSDN says top/right, but I don't believe it */
426 info
->rgstate
[1] = 0;
427 if (pressed
&& SCROLL_trackHitTest
== SCROLL_TOP_ARROW
)
428 info
->rgstate
[1] |= STATE_SYSTEM_PRESSED
;
429 if (infoPtr
->flags
& ESB_DISABLE_LTUP
)
430 info
->rgstate
[1] |= STATE_SYSTEM_UNAVAILABLE
;
432 /* Page up/left region state. MSDN says up/right, but I don't believe it */
433 info
->rgstate
[2] = 0;
434 if (infoPtr
->curVal
== infoPtr
->minVal
)
435 info
->rgstate
[2] |= STATE_SYSTEM_INVISIBLE
;
436 if (pressed
&& SCROLL_trackHitTest
== SCROLL_TOP_RECT
)
437 info
->rgstate
[2] |= STATE_SYSTEM_PRESSED
;
440 info
->rgstate
[3] = 0;
441 if (pressed
&& SCROLL_trackHitTest
== SCROLL_THUMB
)
442 info
->rgstate
[3] |= STATE_SYSTEM_PRESSED
;
444 /* Page down/right region state. MSDN says down/left, but I don't believe it */
445 info
->rgstate
[4] = 0;
446 if (infoPtr
->curVal
>= infoPtr
->maxVal
- 1)
447 info
->rgstate
[4] |= STATE_SYSTEM_INVISIBLE
;
448 if (pressed
&& SCROLL_trackHitTest
== SCROLL_BOTTOM_RECT
)
449 info
->rgstate
[4] |= STATE_SYSTEM_PRESSED
;
451 /* Bottom/right arrow button state. MSDN says bottom/left, but I don't believe it */
452 info
->rgstate
[5] = 0;
453 if (pressed
&& SCROLL_trackHitTest
== SCROLL_BOTTOM_ARROW
)
454 info
->rgstate
[5] |= STATE_SYSTEM_PRESSED
;
455 if (infoPtr
->flags
& ESB_DISABLE_RTDN
)
456 info
->rgstate
[5] |= STATE_SYSTEM_UNAVAILABLE
;
461 static DWORD FASTCALL
462 co_IntSetScrollInfo(PWND Window
, INT nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
)
465 * Update the scrollbar state and set action flags according to
466 * what has to be done graphics wise.
475 BOOL bChangeParams
= FALSE
; /* Don't show/hide scrollbar if params don't change */
479 ASSERT_REFS_CO(Window
);
481 if(!SBID_IS_VALID(nBar
))
483 EngSetLastError(ERROR_INVALID_PARAMETER
);
484 ERR("Trying to set scrollinfo for unknown scrollbar type %d", nBar
);
488 if(!co_IntCreateScrollBars(Window
))
493 if (lpsi
->cbSize
!= sizeof(SCROLLINFO
) &&
494 lpsi
->cbSize
!= (sizeof(SCROLLINFO
) - sizeof(lpsi
->nTrackPos
)))
496 EngSetLastError(ERROR_INVALID_PARAMETER
);
499 if (lpsi
->fMask
& ~(SIF_ALL
| SIF_DISABLENOSCROLL
| SIF_PREVIOUSPOS
))
501 EngSetLastError(ERROR_INVALID_PARAMETER
);
505 psbi
= IntGetScrollbarInfoFromWindow(Window
, nBar
);
506 Info
= IntGetScrollInfoFromWindow(Window
, nBar
);
507 pSBData
= IntGetSBData(Window
, nBar
);
509 /* Set the page size */
510 if (lpsi
->fMask
& SIF_PAGE
)
512 if (Info
->nPage
!= lpsi
->nPage
)
514 Info
->nPage
= lpsi
->nPage
;
515 pSBData
->page
= lpsi
->nPage
;
516 bChangeParams
= TRUE
;
520 /* Set the scroll pos */
521 if (lpsi
->fMask
& SIF_POS
)
523 if (Info
->nPos
!= lpsi
->nPos
)
526 Info
->nPos
= lpsi
->nPos
;
527 pSBData
->pos
= lpsi
->nPos
;
528 bChangeParams
= TRUE
;
532 /* Set the scroll range */
533 if (lpsi
->fMask
& SIF_RANGE
)
535 if (lpsi
->nMin
> lpsi
->nMax
)
537 Info
->nMin
= lpsi
->nMin
;
538 Info
->nMax
= lpsi
->nMin
;
539 pSBData
->posMin
= lpsi
->nMin
;
540 pSBData
->posMax
= lpsi
->nMin
;
541 bChangeParams
= TRUE
;
543 else if (Info
->nMin
!= lpsi
->nMin
|| Info
->nMax
!= lpsi
->nMax
)
545 Info
->nMin
= lpsi
->nMin
;
546 Info
->nMax
= lpsi
->nMax
;
547 pSBData
->posMin
= lpsi
->nMin
;
548 pSBData
->posMax
= lpsi
->nMax
;
549 bChangeParams
= TRUE
;
553 /* Make sure the page size is valid */
554 MaxPage
= abs(Info
->nMax
- Info
->nMin
) + 1;
555 if (Info
->nPage
> MaxPage
)
557 pSBData
->page
= Info
->nPage
= MaxPage
;
560 /* Make sure the pos is inside the range */
561 MaxPos
= Info
->nMax
+ 1 - (int)max(Info
->nPage
, 1);
562 ASSERT(MaxPos
>= Info
->nMin
);
563 if (Info
->nPos
< Info
->nMin
)
565 pSBData
->pos
= Info
->nPos
= Info
->nMin
;
567 else if (Info
->nPos
> MaxPos
)
569 pSBData
->pos
= Info
->nPos
= MaxPos
;
573 * Don't change the scrollbar state if SetScrollInfo is just called
574 * with SIF_DISABLENOSCROLL
576 if (!(lpsi
->fMask
& SIF_ALL
))
579 return lpsi
->fMask
& SIF_PREVIOUSPOS
? OldPos
: pSBData
->pos
;
582 /* Check if the scrollbar should be hidden or disabled */
583 if (lpsi
->fMask
& (SIF_RANGE
| SIF_PAGE
| SIF_DISABLENOSCROLL
))
585 new_flags
= Window
->pSBInfo
->WSBflags
;
586 if (Info
->nMin
>= (int)(Info
->nMax
- max(Info
->nPage
- 1, 0)))
588 /* Hide or disable scroll-bar */
589 if (lpsi
->fMask
& SIF_DISABLENOSCROLL
)
591 new_flags
= ESB_DISABLE_BOTH
;
592 bChangeParams
= TRUE
;
594 else if ((nBar
!= SB_CTL
) && bChangeParams
)
596 action
= SA_SSI_HIDE
;
599 else /* Show and enable scroll-bar only if no page only changed. */
600 if (lpsi
->fMask
!= SIF_PAGE
)
602 new_flags
= ESB_ENABLE_BOTH
;
603 if ((nBar
!= SB_CTL
) && bChangeParams
)
605 action
|= SA_SSI_SHOW
;
609 if (Window
->pSBInfo
->WSBflags
!= new_flags
) /* Check arrow flags */
611 Window
->pSBInfo
->WSBflags
= new_flags
;
612 action
|= SA_SSI_REPAINT_ARROWS
;
617 if ( action
& SA_SSI_HIDE
)
619 co_UserShowScrollBar(Window
, nBar
, FALSE
, FALSE
);
623 if ( action
& SA_SSI_SHOW
)
624 if ( co_UserShowScrollBar(Window
, nBar
, TRUE
, TRUE
) )
625 return lpsi
->fMask
& SIF_PREVIOUSPOS
? OldPos
: pSBData
->pos
; /* SetWindowPos() already did the painting */
627 { // FIXME: Arrows and interior.
628 RECTL UpdateRect
= psbi
->rcScrollBar
;
629 UpdateRect
.left
-= Window
->rcClient
.left
- Window
->rcWindow
.left
;
630 UpdateRect
.right
-= Window
->rcClient
.left
- Window
->rcWindow
.left
;
631 UpdateRect
.top
-= Window
->rcClient
.top
- Window
->rcWindow
.top
;
632 UpdateRect
.bottom
-= Window
->rcClient
.top
- Window
->rcWindow
.top
;
633 co_UserRedrawWindow(Window
, &UpdateRect
, 0, RDW_INVALIDATE
| RDW_FRAME
);
635 /* else if( action & SA_SSI_REPAINT_ARROWS )
637 RECTL UpdateRect = psbi->rcScrollBar;
638 UpdateRect.left -= Window->rcClient.left - Window->rcWindow.left;
639 UpdateRect.right -= Window->rcClient.left - Window->rcWindow.left;
640 UpdateRect.top -= Window->rcClient.top - Window->rcWindow.top;
641 UpdateRect.bottom -= Window->rcClient.top - Window->rcWindow.top;
642 co_UserRedrawWindow(Window, &UpdateRect, 0, RDW_INVALIDATE | RDW_FRAME);
645 /* Return current position */
646 return lpsi
->fMask
& SIF_PREVIOUSPOS
? OldPos
: pSBData
->pos
;
650 co_IntGetScrollBarInfo(PWND Window
, LONG idObject
, PSCROLLBARINFO psbi
)
655 ASSERT_REFS_CO(Window
);
657 Bar
= SBOBJ_TO_SBID(idObject
);
659 if(!SBID_IS_VALID(Bar
))
661 EngSetLastError(ERROR_INVALID_PARAMETER
);
662 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar
);
666 if(!co_IntCreateScrollBars(Window
))
668 ERR("Failed to create scrollbars for window.\n");
672 sbi
= IntGetScrollbarInfoFromWindow(Window
, Bar
);
673 pSBData
= IntGetSBData(Window
, Bar
);
675 IntGetScrollBarRect(Window
, Bar
, &(sbi
->rcScrollBar
));
676 IntCalculateThumb(Window
, Bar
, sbi
, pSBData
);
678 /* Scroll bar state */
679 psbi
->rgstate
[0] = 0;
680 if ((Bar
== SB_HORZ
&& !(Window
->style
& WS_HSCROLL
))
681 || (Bar
== SB_VERT
&& !(Window
->style
& WS_VSCROLL
)))
682 psbi
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
683 if (pSBData
->posMin
>= pSBData
->posMax
- max(pSBData
->page
- 1, 0))
685 if (!(psbi
->rgstate
[0] & STATE_SYSTEM_INVISIBLE
))
686 psbi
->rgstate
[0] |= STATE_SYSTEM_UNAVAILABLE
;
688 psbi
->rgstate
[0] |= STATE_SYSTEM_OFFSCREEN
;
690 if (Bar
== SB_CTL
&& !(Window
->style
& WS_DISABLED
))
691 psbi
->rgstate
[0] |= STATE_SYSTEM_UNAVAILABLE
;
693 RtlCopyMemory(psbi
, sbi
, sizeof(SCROLLBARINFO
));
699 co_IntSetScrollBarInfo(PWND Window
, LONG idObject
, PSETSCROLLBARINFO psbi
)
704 ASSERT_REFS_CO(Window
);
706 Bar
= SBOBJ_TO_SBID(idObject
);
708 if(!SBID_IS_VALID(Bar
))
710 EngSetLastError(ERROR_INVALID_PARAMETER
);
711 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar
);
715 if(!co_IntCreateScrollBars(Window
))
717 ERR("Failed to create scrollbars for window.\n");
721 sbi
= IntGetScrollbarInfoFromWindow(Window
, Bar
);
722 psi
= IntGetScrollInfoFromWindow(Window
, Bar
);
724 psi
->nTrackPos
= psbi
->nTrackPos
;
725 sbi
->reserved
= psbi
->reserved
;
726 RtlCopyMemory(&sbi
->rgstate
, &psbi
->rgstate
, sizeof(psbi
->rgstate
));
732 co_IntCreateScrollBars(PWND Window
)
739 ASSERT_REFS_CO(Window
);
741 if (Window
->pSBInfo
&& Window
->pSBInfoex
)
743 /* No need to create it anymore */
747 /* Allocate memory for all scrollbars (HORZ, VERT, CONTROL) */
748 Size
= 3 * (sizeof(SBINFOEX
));
749 if(!(Window
->pSBInfoex
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_SBARINFO
)))
751 ERR("Unable to allocate memory for scrollbar information for window %p\n", Window
->head
.h
);
755 RtlZeroMemory(Window
->pSBInfoex
, Size
);
757 if(!(Window
->pSBInfo
= DesktopHeapAlloc( Window
->head
.rpdesk
, sizeof(SBINFO
))))
759 ERR("Unable to allocate memory for scrollbar information for window %p\n", Window
->head
.h
);
763 RtlZeroMemory(Window
->pSBInfo
, sizeof(SBINFO
));
764 Window
->pSBInfo
->Vert
.posMax
= 100;
765 Window
->pSBInfo
->Horz
.posMax
= 100;
767 co_WinPosGetNonClientSize(Window
,
771 for(s
= SB_HORZ
; s
<= SB_VERT
; s
++)
773 psbi
= IntGetScrollbarInfoFromWindow(Window
, s
);
774 psbi
->cbSize
= sizeof(SCROLLBARINFO
);
775 for (i
= 0; i
< CCHILDREN_SCROLLBAR
+ 1; i
++)
776 psbi
->rgstate
[i
] = 0;
778 pSBData
= IntGetSBData(Window
, s
);
780 IntGetScrollBarRect(Window
, s
, &(psbi
->rcScrollBar
));
781 IntCalculateThumb(Window
, s
, psbi
, pSBData
);
788 IntDestroyScrollBars(PWND Window
)
790 if (Window
->pSBInfo
&& Window
->pSBInfoex
)
792 DesktopHeapFree(Window
->head
.rpdesk
, Window
->pSBInfo
);
793 Window
->pSBInfo
= NULL
;
794 ExFreePoolWithTag(Window
->pSBInfoex
, TAG_SBARINFO
);
795 Window
->pSBInfoex
= NULL
;
802 IntEnableScrollBar(BOOL Horz
, PSCROLLBARINFO Info
, UINT wArrows
)
807 case ESB_DISABLE_BOTH
:
808 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
809 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
811 case ESB_DISABLE_RTDN
:
814 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
818 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
821 case ESB_DISABLE_LTUP
:
824 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
828 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
831 case ESB_ENABLE_BOTH
:
832 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, 0);
833 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, 0);
839 /* Ported from WINE20020904 (SCROLL_ShowScrollBar) */
841 co_UserShowScrollBar(PWND Wnd
, int nBar
, BOOL fShowH
, BOOL fShowV
)
843 ULONG old_style
, set_bits
= 0, clear_bits
= 0;
851 //IntUpdateSBInfo(Wnd, SB_CTL); // Is this needed? Was tested w/o!
853 co_WinPosShowWindow(Wnd
, fShowH
? SW_SHOW
: SW_HIDE
);
858 if (fShowH
) set_bits
|= WS_HSCROLL
;
859 else clear_bits
|= WS_HSCROLL
;
860 if( nBar
== SB_HORZ
) break;
863 if (fShowV
) set_bits
|= WS_VSCROLL
;
864 else clear_bits
|= WS_VSCROLL
;
867 EngSetLastError(ERROR_INVALID_PARAMETER
);
868 return FALSE
; /* Nothing to do! */
871 old_style
= IntSetStyle( Wnd
, set_bits
, clear_bits
);
872 if ((old_style
& clear_bits
) != 0 || (old_style
& set_bits
) != set_bits
)
874 ///// Is this needed? Was tested w/o!
875 //if (Wnd->style & WS_HSCROLL) IntUpdateSBInfo(Wnd, SB_HORZ);
876 //if (Wnd->style & WS_VSCROLL) IntUpdateSBInfo(Wnd, SB_VERT);
878 /* Frame has been changed, let the window redraw itself */
879 co_WinPosSetWindowPos( Wnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
880 | SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
883 return FALSE
; /* no frame changes */
887 IntDrawScrollInterior(PWND pWnd
, HDC hDC
, INT nBar
, BOOL Vertical
, PSCROLLBARINFO ScrollBarInfo
)
889 INT ThumbSize
= ScrollBarInfo
->xyThumbBottom
- ScrollBarInfo
->xyThumbTop
;
890 INT ThumbTop
= ScrollBarInfo
->xyThumbTop
;
892 HBRUSH hSaveBrush
, hBrush
;
893 BOOL TopSelected
= FALSE
, BottomSelected
= FALSE
;
895 if (ScrollBarInfo
->rgstate
[SCROLL_TOP_RECT
] & STATE_SYSTEM_PRESSED
)
897 if (ScrollBarInfo
->rgstate
[SCROLL_BOTTOM_RECT
] & STATE_SYSTEM_PRESSED
)
898 BottomSelected
= TRUE
;
901 * Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
902 * The window-owned scrollbars need to call DefWndControlColor
903 * to correctly setup default scrollbar colors
907 hBrush
= GetControlBrush( pWnd
, hDC
, WM_CTLCOLORSCROLLBAR
);
909 hBrush
= IntGetSysColorBrush(COLOR_SCROLLBAR
);
913 hBrush
= DefWndControlColor(hDC
, CTLCOLOR_SCROLLBAR
);
916 hSaveBrush
= NtGdiSelectBrush(hDC
, hBrush
);
918 /* Calculate the scroll rectangle */
921 Rect
.top
= ScrollBarInfo
->rcScrollBar
.top
+ ScrollBarInfo
->dxyLineButton
;
922 Rect
.bottom
= ScrollBarInfo
->rcScrollBar
.bottom
- ScrollBarInfo
->dxyLineButton
;
923 Rect
.left
= ScrollBarInfo
->rcScrollBar
.left
;
924 Rect
.right
= ScrollBarInfo
->rcScrollBar
.right
;
928 Rect
.top
= ScrollBarInfo
->rcScrollBar
.top
;
929 Rect
.bottom
= ScrollBarInfo
->rcScrollBar
.bottom
;
930 Rect
.left
= ScrollBarInfo
->rcScrollBar
.left
+ ScrollBarInfo
->dxyLineButton
;
931 Rect
.right
= ScrollBarInfo
->rcScrollBar
.right
- ScrollBarInfo
->dxyLineButton
;
934 /* Draw the scroll rectangles and thumb */
935 if (!ScrollBarInfo
->xyThumbBottom
)
937 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
- Rect
.left
,
938 Rect
.bottom
- Rect
.top
, PATCOPY
);
940 /* Cleanup and return */
941 NtGdiSelectBrush(hDC
, hSaveBrush
);
945 ThumbTop
-= ScrollBarInfo
->dxyLineButton
;
947 if (ScrollBarInfo
->dxyLineButton
)
953 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
- Rect
.left
,
954 ThumbTop
, TopSelected
? BLACKNESS
: PATCOPY
);
955 Rect
.top
+= ThumbTop
;
956 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
+ ThumbSize
, Rect
.right
- Rect
.left
,
957 Rect
.bottom
- Rect
.top
- ThumbSize
, BottomSelected
? BLACKNESS
: PATCOPY
);
958 Rect
.bottom
= Rect
.top
+ ThumbSize
;
964 NtGdiPatBlt(hDC
, Rect
.left
, ScrollBarInfo
->dxyLineButton
,
965 Rect
.right
- Rect
.left
, Rect
.bottom
- Rect
.top
, PATCOPY
);
973 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, ThumbTop
,
974 Rect
.bottom
- Rect
.top
, TopSelected
? BLACKNESS
: PATCOPY
);
975 Rect
.left
+= ThumbTop
;
976 NtGdiPatBlt(hDC
, Rect
.left
+ ThumbSize
, Rect
.top
,
977 Rect
.right
- Rect
.left
- ThumbSize
, Rect
.bottom
- Rect
.top
,
978 BottomSelected
? BLACKNESS
: PATCOPY
);
979 Rect
.right
= Rect
.left
+ ThumbSize
;
985 NtGdiPatBlt(hDC
, ScrollBarInfo
->dxyLineButton
, Rect
.top
,
986 Rect
.right
- Rect
.left
, Rect
.bottom
- Rect
.top
, PATCOPY
);
994 DrawEdge(hDC
, &Rect
, EDGE_RAISED
, BF_RECT
| BF_MIDDLE
);
997 NtGdiSelectBrush(hDC
, hSaveBrush
);
1001 static VOID FASTCALL
1002 IntDrawScrollArrows(HDC hDC
, PSCROLLBARINFO ScrollBarInfo
, BOOL Vertical
)
1004 RECT RectLT
, RectRB
;
1005 INT ScrollDirFlagLT
, ScrollDirFlagRB
;
1007 RectLT
= RectRB
= ScrollBarInfo
->rcScrollBar
;
1010 ScrollDirFlagLT
= DFCS_SCROLLUP
;
1011 ScrollDirFlagRB
= DFCS_SCROLLDOWN
;
1012 RectLT
.bottom
= RectLT
.top
+ ScrollBarInfo
->dxyLineButton
;
1013 RectRB
.top
= RectRB
.bottom
- ScrollBarInfo
->dxyLineButton
;
1017 ScrollDirFlagLT
= DFCS_SCROLLLEFT
;
1018 ScrollDirFlagRB
= DFCS_SCROLLRIGHT
;
1019 RectLT
.right
= RectLT
.left
+ ScrollBarInfo
->dxyLineButton
;
1020 RectRB
.left
= RectRB
.right
- ScrollBarInfo
->dxyLineButton
;
1023 if (ScrollBarInfo
->rgstate
[SCROLL_TOP_ARROW
] & STATE_SYSTEM_PRESSED
)
1025 ScrollDirFlagLT
|= DFCS_PUSHED
| DFCS_FLAT
;
1027 if (ScrollBarInfo
->rgstate
[SCROLL_TOP_ARROW
] & STATE_SYSTEM_UNAVAILABLE
)
1029 ScrollDirFlagLT
|= DFCS_INACTIVE
;
1031 if (ScrollBarInfo
->rgstate
[SCROLL_BOTTOM_ARROW
] & STATE_SYSTEM_PRESSED
)
1033 ScrollDirFlagRB
|= DFCS_PUSHED
| DFCS_FLAT
;
1035 if (ScrollBarInfo
->rgstate
[SCROLL_BOTTOM_ARROW
] & STATE_SYSTEM_UNAVAILABLE
)
1037 ScrollDirFlagRB
|= DFCS_INACTIVE
;
1040 DrawFrameControl(hDC
, &RectLT
, DFC_SCROLL
, ScrollDirFlagLT
);
1041 DrawFrameControl(hDC
, &RectRB
, DFC_SCROLL
, ScrollDirFlagRB
);
1044 static LONG FASTCALL
1045 IntScrollGetObjectId(INT SBType
)
1047 if (SBType
== SB_VERT
)
1048 return OBJID_VSCROLL
;
1049 if (SBType
== SB_HORZ
)
1050 return OBJID_HSCROLL
;
1051 return OBJID_CLIENT
;
1055 IntDrawScrollBar(PWND Wnd
, HDC DC
, INT Bar
)
1063 pti
= PsGetCurrentThreadWin32Thread();
1066 * Get scroll bar info.
1079 Vertical
= (Wnd
->style
& SBS_VERT
) != 0;
1086 if (!co_IntGetScrollBarInfo(Wnd
, IntScrollGetObjectId(Bar
), &Info
))
1091 if (RECTL_bIsEmptyRect(&Info
.rcScrollBar
))
1096 //ThumbSize = pSBWnd->pSBCalc->pxThumbBottom - pSBWnd->pSBCalc->pxThumbTop;
1101 if (Info
.dxyLineButton
)
1103 IntDrawScrollArrows(DC
, &Info
, Vertical
);
1107 * Draw the interior.
1109 IntDrawScrollInterior(Wnd
, DC
, Bar
, Vertical
, &Info
);
1112 * If scroll bar has focus, reposition the caret.
1114 if ( Wnd
== pti
->MessageQueue
->spwndFocus
&& Bar
== SB_CTL
)
1118 co_IntSetCaretPos(Info
.rcScrollBar
.top
+ 1, Info
.dxyLineButton
+ 1);
1122 co_IntSetCaretPos(Info
.dxyLineButton
+ 1, Info
.rcScrollBar
.top
+ 1);
1129 ScrollBarWndProc(HWND hWnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
1131 LRESULT lResult
= 0;
1133 pWnd
= UserGetWindowObject(hWnd
);
1134 if (!pWnd
) return 0;
1142 pWnd
->pSBInfo
->WSBflags
= wParam
? ESB_ENABLE_BOTH
: ESB_DISABLE_BOTH
;
1154 NtUserGetScrollBarInfo(HWND hWnd
, LONG idObject
, PSCROLLBARINFO psbi
)
1160 DECLARE_RETURN(BOOL
);
1161 USER_REFERENCE_ENTRY Ref
;
1163 TRACE("Enter NtUserGetScrollBarInfo\n");
1164 UserEnterExclusive();
1166 Status
= MmCopyFromCaller(&sbi
, psbi
, sizeof(SCROLLBARINFO
));
1167 if(!NT_SUCCESS(Status
) || (sbi
.cbSize
!= sizeof(SCROLLBARINFO
)))
1169 SetLastNtError(Status
);
1173 if(!(Window
= UserGetWindowObject(hWnd
)))
1178 UserRefObjectCo(Window
, &Ref
);
1179 Ret
= co_IntGetScrollBarInfo(Window
, idObject
, &sbi
);
1180 UserDerefObjectCo(Window
);
1182 Status
= MmCopyToCaller(psbi
, &sbi
, sizeof(SCROLLBARINFO
));
1183 if(!NT_SUCCESS(Status
))
1185 SetLastNtError(Status
);
1192 TRACE("Leave NtUserGetScrollBarInfo, ret=%i\n",_ret_
);
1210 DECLARE_RETURN(BOOL
);
1211 USER_REFERENCE_ENTRY Ref
;
1213 TRACE("Enter NtUserGetScrollInfo\n");
1218 RtlCopyMemory(&psi
, lpsi
, sizeof(SCROLLINFO
));
1221 RtlCopyMemory(&SBDataSafe
, pSBData
, sizeof(SBDATA
));
1224 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1226 ERR("NtUserGetScrollInfo Failed size.\n");
1227 SetLastNtError(_SEH2_GetExceptionCode());
1228 _SEH2_YIELD(RETURN(FALSE
));
1232 if(!(Window
= UserGetWindowObject(hWnd
)))
1234 ERR("NtUserGetScrollInfo Bad window.\n");
1238 UserRefObjectCo(Window
, &Ref
);
1239 Ret
= co_IntGetScrollInfo(Window
, fnBar
, &SBDataSafe
, &psi
);
1240 UserDerefObjectCo(Window
);
1244 RtlCopyMemory(lpsi
, &psi
, sizeof(SCROLLINFO
));
1246 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1248 ERR("NtUserGetScrollInfo Failed copy to user.\n");
1249 SetLastNtError(_SEH2_GetExceptionCode());
1250 _SEH2_YIELD(RETURN(FALSE
));
1257 TRACE("Leave NtUserGetScrollInfo, ret=%i\n",_ret_
);
1264 NtUserEnableScrollBar(
1271 PSCROLLBARINFO InfoV
= NULL
, InfoH
= NULL
;
1273 DECLARE_RETURN(BOOL
);
1274 USER_REFERENCE_ENTRY Ref
;
1276 TRACE("Enter NtUserEnableScrollBar\n");
1277 UserEnterExclusive();
1279 if (!(Window
= UserGetWindowObject(hWnd
)) ||
1280 UserIsDesktopWindow(Window
) || UserIsMessageWindow(Window
))
1284 UserRefObjectCo(Window
, &Ref
);
1286 if (!co_IntCreateScrollBars(Window
))
1291 OrigArrows
= Window
->pSBInfo
->WSBflags
;
1292 Window
->pSBInfo
->WSBflags
= wArrows
;
1294 if (wSBflags
== SB_CTL
)
1296 if ((wArrows
== ESB_DISABLE_BOTH
|| wArrows
== ESB_ENABLE_BOTH
))
1297 IntEnableWindow(hWnd
, (wArrows
== ESB_ENABLE_BOTH
));
1302 if(wSBflags
!= SB_BOTH
&& !SBID_IS_VALID(wSBflags
))
1304 EngSetLastError(ERROR_INVALID_PARAMETER
);
1305 ERR("Trying to set scrollinfo for unknown scrollbar type %u", wSBflags
);
1312 InfoV
= IntGetScrollbarInfoFromWindow(Window
, SB_VERT
);
1315 InfoH
= IntGetScrollbarInfoFromWindow(Window
, SB_HORZ
);
1318 InfoV
= IntGetScrollbarInfoFromWindow(Window
, SB_VERT
);
1325 Chg
= IntEnableScrollBar(FALSE
, InfoV
, wArrows
);
1328 Chg
= (IntEnableScrollBar(TRUE
, InfoH
, wArrows
) || Chg
);
1330 ERR("FIXME: EnableScrollBar wSBflags %u wArrows %u Chg %d\n", wSBflags
, wArrows
, Chg
);
1332 // SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE );
1335 if (OrigArrows
== wArrows
) RETURN( FALSE
);
1340 UserDerefObjectCo(Window
);
1342 TRACE("Leave NtUserEnableScrollBar, ret=%i\n",_ret_
);
1349 NtUserSetScrollInfo(
1357 SCROLLINFO ScrollInfo
;
1358 DECLARE_RETURN(DWORD
);
1359 USER_REFERENCE_ENTRY Ref
;
1361 TRACE("Enter NtUserSetScrollInfo\n");
1362 UserEnterExclusive();
1364 if(!(Window
= UserGetWindowObject(hWnd
)) ||
1365 UserIsDesktopWindow(Window
) || UserIsMessageWindow(Window
))
1369 UserRefObjectCo(Window
, &Ref
);
1371 Status
= MmCopyFromCaller(&ScrollInfo
, lpsi
, sizeof(SCROLLINFO
) - sizeof(ScrollInfo
.nTrackPos
));
1372 if(!NT_SUCCESS(Status
))
1374 SetLastNtError(Status
);
1378 RETURN(co_IntSetScrollInfo(Window
, fnBar
, &ScrollInfo
, bRedraw
));
1382 UserDerefObjectCo(Window
);
1384 TRACE("Leave NtUserSetScrollInfo, ret=%lu\n", _ret_
);
1391 NtUserShowScrollBar(HWND hWnd
, int nBar
, DWORD bShow
)
1394 DECLARE_RETURN(DWORD
);
1396 USER_REFERENCE_ENTRY Ref
;
1398 TRACE("Enter NtUserShowScrollBar\n");
1399 UserEnterExclusive();
1401 if (!(Window
= UserGetWindowObject(hWnd
)))
1406 UserRefObjectCo(Window
, &Ref
);
1407 ret
= co_UserShowScrollBar(Window
, nBar
, (nBar
== SB_VERT
) ? 0 : bShow
,
1408 (nBar
== SB_HORZ
) ? 0 : bShow
);
1409 UserDerefObjectCo(Window
);
1414 TRACE("Leave NtUserShowScrollBar, ret%lu\n", _ret_
);
1421 //// Ugly NtUser API ////
1425 NtUserSetScrollBarInfo(
1428 SETSCROLLBARINFO
*info
)
1431 SETSCROLLBARINFO Safeinfo
;
1436 DECLARE_RETURN(BOOL
);
1437 USER_REFERENCE_ENTRY Ref
;
1439 TRACE("Enter NtUserSetScrollBarInfo\n");
1440 UserEnterExclusive();
1442 if(!(Window
= UserGetWindowObject(hWnd
)))
1446 UserRefObjectCo(Window
, &Ref
);
1448 Obj
= SBOBJ_TO_SBID(idObject
);
1449 if(!SBID_IS_VALID(Obj
))
1451 EngSetLastError(ERROR_INVALID_PARAMETER
);
1452 ERR("Trying to set scrollinfo for unknown scrollbar type %d\n", Obj
);
1456 if(!co_IntCreateScrollBars(Window
))
1461 Status
= MmCopyFromCaller(&Safeinfo
, info
, sizeof(SETSCROLLBARINFO
));
1462 if(!NT_SUCCESS(Status
))
1464 SetLastNtError(Status
);
1468 sbi
= IntGetScrollbarInfoFromWindow(Window
, Obj
);
1469 psi
= IntGetScrollInfoFromWindow(Window
, Obj
);
1471 psi
->nTrackPos
= Safeinfo
.nTrackPos
;
1472 sbi
->reserved
= Safeinfo
.reserved
;
1473 RtlCopyMemory(&sbi
->rgstate
, &Safeinfo
.rgstate
, sizeof(Safeinfo
.rgstate
));
1479 UserDerefObjectCo(Window
);
1481 TRACE("Leave NtUserSetScrollBarInfo, ret=%i\n",_ret_
);