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 IntRefeshScrollInterior(PWND pWnd
, INT nBar
, PSCROLLBARINFO psbi
);
68 /* Ported from WINE20020904 */
69 /* Compute the scroll bar rectangle, in drawing coordinates (i.e. client coords for SB_CTL, window coords for SB_VERT and
70 * SB_HORZ). 'arrowSize' returns the width or height of an arrow (depending on * the orientation of the scrollbar),
71 * 'thumbSize' returns the size of the thumb, and 'thumbPos' returns the position of the thumb relative to the left or to
72 * the top. Return TRUE if the scrollbar is vertical, FALSE if horizontal.
74 static inline void mirror_rect( const RECT
*window_rect
, RECT
*rect
)
76 int width
= window_rect
->right
- window_rect
->left
;
78 rect
->left
= width
- rect
->right
;
79 rect
->right
= width
- tmp
;
83 IntGetSBData(PWND pwnd
, INT Bar
)
88 pSBInfo
= pwnd
->pSBInfo
;
92 return &pSBInfo
->Horz
;
94 return &pSBInfo
->Vert
;
96 if ( pwnd
->cbwndExtra
< (sizeof(SBWND
)-sizeof(WND
)) )
98 ERR("IntGetSBData Wrong Extra bytes for CTL Scrollbar!\n");
101 pSBWnd
= (PSBWND
)pwnd
;
102 return (PSBDATA
)&pSBWnd
->SBCalc
;
104 ERR("IntGetSBData Bad Bar!\n");
110 IntGetScrollBarRect (PWND Wnd
, INT nBar
, RECTL
*lprect
)
113 *lprect
= Wnd
->rcClient
;
115 RECTL_vOffsetRect( lprect
, -Wnd
->rcWindow
.left
, -Wnd
->rcWindow
.top
);
116 if (Wnd
->ExStyle
& WS_EX_LAYOUTRTL
)
117 mirror_rect( &Wnd
->rcWindow
, lprect
);
122 lprect
->top
= lprect
->bottom
;
123 lprect
->bottom
+= UserGetSystemMetrics (SM_CYHSCROLL
);
124 if (Wnd
->style
& WS_BORDER
)
129 else if (Wnd
->style
& WS_VSCROLL
)
137 if(Wnd
->ExStyle
& WS_EX_LEFTSCROLLBAR
)
139 lprect
->right
= lprect
->left
;
140 lprect
->left
-= UserGetSystemMetrics(SM_CXVSCROLL
);
144 lprect
->left
= lprect
->right
;
145 lprect
->right
+= UserGetSystemMetrics(SM_CXVSCROLL
);
147 if (Wnd
->style
& WS_BORDER
)
152 else if (Wnd
->style
& WS_HSCROLL
)
160 IntGetClientRect (Wnd
, lprect
);
161 vertical
= !!(Wnd
->style
& SBS_VERT
);
172 IntCalculateThumb(PWND Wnd
, LONG idObject
, PSCROLLBARINFO psbi
, PSBDATA pSBData
)
174 INT Thumb
, ThumbBox
, ThumbPos
, cxy
, mx
;
180 Thumb
= UserGetSystemMetrics(SM_CXHSCROLL
);
181 cxy
= psbi
->rcScrollBar
.right
- psbi
->rcScrollBar
.left
;
184 Thumb
= UserGetSystemMetrics(SM_CYVSCROLL
);
185 cxy
= psbi
->rcScrollBar
.bottom
- psbi
->rcScrollBar
.top
;
188 IntGetClientRect(Wnd
, &ClientRect
);
189 if(Wnd
->style
& SBS_VERT
)
191 Thumb
= UserGetSystemMetrics(SM_CYVSCROLL
);
192 cxy
= ClientRect
.bottom
- ClientRect
.top
;
196 Thumb
= UserGetSystemMetrics(SM_CXHSCROLL
);
197 cxy
= ClientRect
.right
- ClientRect
.left
;
205 /* Calculate Thumb */
206 if(cxy
<= (2 * Thumb
))
209 psbi
->xyThumbTop
= 0;
210 psbi
->xyThumbBottom
= 0;
213 else if (psbi
->rgstate
[SBRG_TOPRIGHTBTN
] == STATE_SYSTEM_UNAVAILABLE
&&
214 psbi
->rgstate
[SBRG_BOTTOMLEFTBTN
] == STATE_SYSTEM_UNAVAILABLE
&&
215 pSBData
->posMin
>= (int)(pSBData
->posMax
- max(pSBData
->page
- 1, 0)))
217 /* Nothing to scroll */
218 psbi
->xyThumbTop
= 0;
219 psbi
->xyThumbBottom
= 0;
223 ThumbBox
= pSBData
->page
? MINTRACKTHUMB
: UserGetSystemMetrics(SM_CXHTHUMB
);
229 ThumbBox
= max(EngMulDiv(cxy
, pSBData
->page
, pSBData
->posMax
- pSBData
->posMin
+ 1), ThumbBox
);
234 mx
= pSBData
->posMax
- max(pSBData
->page
- 1, 0);
235 if(pSBData
->posMin
< mx
)
236 ThumbPos
= Thumb
+ EngMulDiv(cxy
- ThumbBox
, pSBData
->pos
- pSBData
->posMin
, mx
- pSBData
->posMin
);
238 ThumbPos
= Thumb
+ ThumbBox
;
241 psbi
->xyThumbTop
= ThumbPos
;
242 psbi
->xyThumbBottom
= ThumbPos
+ ThumbBox
;
246 psbi
->xyThumbTop
= 0;
247 psbi
->xyThumbBottom
= 0;
250 psbi
->dxyLineButton
= Thumb
;
256 IntUpdateSBInfo(PWND Window, int wBar)
262 ASSERT(Window->pSBInfo);
263 ASSERT(Window->pSBInfoex);
265 sbi = IntGetScrollbarInfoFromWindow(Window, wBar);
266 pSBData = IntGetSBData(Window, wBar);
267 IntGetScrollBarRect(Window, wBar, &(sbi->rcScrollBar));
268 IntCalculateThumb(Window, wBar, sbi, pSBData);
272 co_IntGetScrollInfo(PWND Window
, INT nBar
, PSBDATA pSBData
, LPSCROLLINFO lpsi
)
277 ASSERT_REFS_CO(Window
);
279 if(!SBID_IS_VALID(nBar
))
281 EngSetLastError(ERROR_INVALID_PARAMETER
);
282 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar
);
286 if (!Window
->pSBInfo
)
288 ERR("IntGetScrollInfo No window scrollbar info!\n");
292 psi
= IntGetScrollInfoFromWindow(Window
, nBar
);
294 if (lpsi
->fMask
== SIF_ALL
)
296 Mask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
| SIF_TRACKPOS
;
303 if (0 != (Mask
& SIF_PAGE
))
305 lpsi
->nPage
= psi
->nPage
;
308 if (0 != (Mask
& SIF_POS
))
310 lpsi
->nPos
= psi
->nPos
;
313 if (0 != (Mask
& SIF_RANGE
))
315 lpsi
->nMin
= psi
->nMin
;
316 lpsi
->nMax
= psi
->nMax
;
319 if (0 != (Mask
& SIF_TRACKPOS
))
321 lpsi
->nTrackPos
= psi
->nTrackPos
;
328 NEWco_IntGetScrollInfo(
335 PSBTRACK pSBTrack
= pWnd
->head
.pti
->pSBTrack
;
337 if (!SBID_IS_VALID(nBar
))
339 EngSetLastError(ERROR_INVALID_PARAMETER
);
340 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar
);
344 if (!pWnd
->pSBInfo
|| !pSBTrack
) return FALSE
;
348 if (0 != (Mask
& SIF_PAGE
))
350 lpsi
->nPage
= pSBData
->page
;
353 if (0 != (Mask
& SIF_POS
))
355 lpsi
->nPos
= pSBData
->pos
;
358 if (0 != (Mask
& SIF_RANGE
))
360 lpsi
->nMin
= pSBData
->posMin
;
361 lpsi
->nMax
= pSBData
->posMax
;
364 if (0 != (Mask
& SIF_TRACKPOS
))
367 pSBTrack
->nBar
== nBar
&&
368 pSBTrack
->spwndTrack
== pWnd
)
369 lpsi
->nTrackPos
= pSBTrack
->posNew
;
371 lpsi
->nTrackPos
= pSBData
->pos
;
373 return (Mask
& SIF_ALL
) !=0;
376 /*************************************************************************
377 * SCROLL_GetScrollBarInfo
379 * Internal helper for the API function
382 * hwnd [I] Handle of window with scrollbar(s)
383 * idObject [I] One of OBJID_CLIENT, OBJID_HSCROLL, or OBJID_VSCROLL
384 * info [IO] cbSize specifies the size of the structure
390 static BOOL
SCROLL_GetScrollBarInfo(HWND hwnd
, LONG idObject
, LPSCROLLBARINFO info
)
392 LPSCROLLBAR_INFO infoPtr
;
395 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
401 case OBJID_CLIENT
: nBar
= SB_CTL
; break;
402 case OBJID_HSCROLL
: nBar
= SB_HORZ
; break;
403 case OBJID_VSCROLL
: nBar
= SB_VERT
; break;
404 default: return FALSE
;
407 /* handle invalid data structure */
408 if (info
->cbSize
!= sizeof(*info
))
411 SCROLL_GetScrollBarRect(hwnd
, nBar
, &info
->rcScrollBar
, &nDummy
,
412 &info
->dxyLineButton
, &info
->xyThumbTop
);
413 /* rcScrollBar needs to be in screen coordinates */
414 GetWindowRect(hwnd
, &rect
);
415 OffsetRect(&info
->rcScrollBar
, rect
.left
, rect
.top
);
417 info
->xyThumbBottom
= info
->xyThumbTop
+ info
->dxyLineButton
;
419 infoPtr
= SCROLL_GetInternalInfo(hwnd
, nBar
, TRUE
);
423 /* Scroll bar state */
424 info
->rgstate
[0] = 0;
425 if ((nBar
== SB_HORZ
&& !(style
& WS_HSCROLL
))
426 || (nBar
== SB_VERT
&& !(style
& WS_VSCROLL
)))
427 info
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
428 if (infoPtr
->minVal
>= infoPtr
->maxVal
- max(infoPtr
->page
- 1, 0))
430 if (!(info
->rgstate
[0] & STATE_SYSTEM_INVISIBLE
))
431 info
->rgstate
[0] |= STATE_SYSTEM_UNAVAILABLE
;
433 info
->rgstate
[0] |= STATE_SYSTEM_OFFSCREEN
;
435 if (nBar
== SB_CTL
&& !IsWindowEnabled(hwnd
))
436 info
->rgstate
[0] |= STATE_SYSTEM_UNAVAILABLE
;
438 pressed
= ((nBar
== SB_VERT
) == SCROLL_trackVertical
&& GetCapture() == hwnd
);
440 /* Top/left arrow button state. MSDN says top/right, but I don't believe it */
441 info
->rgstate
[1] = 0;
442 if (pressed
&& SCROLL_trackHitTest
== SCROLL_TOP_ARROW
)
443 info
->rgstate
[1] |= STATE_SYSTEM_PRESSED
;
444 if (infoPtr
->flags
& ESB_DISABLE_LTUP
)
445 info
->rgstate
[1] |= STATE_SYSTEM_UNAVAILABLE
;
447 /* Page up/left region state. MSDN says up/right, but I don't believe it */
448 info
->rgstate
[2] = 0;
449 if (infoPtr
->curVal
== infoPtr
->minVal
)
450 info
->rgstate
[2] |= STATE_SYSTEM_INVISIBLE
;
451 if (pressed
&& SCROLL_trackHitTest
== SCROLL_TOP_RECT
)
452 info
->rgstate
[2] |= STATE_SYSTEM_PRESSED
;
455 info
->rgstate
[3] = 0;
456 if (pressed
&& SCROLL_trackHitTest
== SCROLL_THUMB
)
457 info
->rgstate
[3] |= STATE_SYSTEM_PRESSED
;
459 /* Page down/right region state. MSDN says down/left, but I don't believe it */
460 info
->rgstate
[4] = 0;
461 if (infoPtr
->curVal
>= infoPtr
->maxVal
- 1)
462 info
->rgstate
[4] |= STATE_SYSTEM_INVISIBLE
;
463 if (pressed
&& SCROLL_trackHitTest
== SCROLL_BOTTOM_RECT
)
464 info
->rgstate
[4] |= STATE_SYSTEM_PRESSED
;
466 /* Bottom/right arrow button state. MSDN says bottom/left, but I don't believe it */
467 info
->rgstate
[5] = 0;
468 if (pressed
&& SCROLL_trackHitTest
== SCROLL_BOTTOM_ARROW
)
469 info
->rgstate
[5] |= STATE_SYSTEM_PRESSED
;
470 if (infoPtr
->flags
& ESB_DISABLE_RTDN
)
471 info
->rgstate
[5] |= STATE_SYSTEM_UNAVAILABLE
;
476 static DWORD FASTCALL
477 co_IntSetScrollInfo(PWND Window
, INT nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
)
480 * Update the scrollbar state and set action flags according to
481 * what has to be done graphics wise.
490 BOOL bChangeParams
= FALSE
; /* Don't show/hide scrollbar if params don't change */
494 ASSERT_REFS_CO(Window
);
496 if(!SBID_IS_VALID(nBar
))
498 EngSetLastError(ERROR_INVALID_PARAMETER
);
499 ERR("Trying to set scrollinfo for unknown scrollbar type %d", nBar
);
503 if(!co_IntCreateScrollBars(Window
))
508 if (lpsi
->cbSize
!= sizeof(SCROLLINFO
) &&
509 lpsi
->cbSize
!= (sizeof(SCROLLINFO
) - sizeof(lpsi
->nTrackPos
)))
511 EngSetLastError(ERROR_INVALID_PARAMETER
);
514 if (lpsi
->fMask
& ~(SIF_ALL
| SIF_DISABLENOSCROLL
| SIF_PREVIOUSPOS
))
516 EngSetLastError(ERROR_INVALID_PARAMETER
);
520 psbi
= IntGetScrollbarInfoFromWindow(Window
, nBar
);
521 Info
= IntGetScrollInfoFromWindow(Window
, nBar
);
522 pSBData
= IntGetSBData(Window
, nBar
);
524 /* Set the page size */
525 if (lpsi
->fMask
& SIF_PAGE
)
527 if (Info
->nPage
!= lpsi
->nPage
)
529 Info
->nPage
= lpsi
->nPage
;
530 pSBData
->page
= lpsi
->nPage
;
531 bChangeParams
= TRUE
;
535 /* Set the scroll pos */
536 if (lpsi
->fMask
& SIF_POS
)
538 if (Info
->nPos
!= lpsi
->nPos
)
541 Info
->nPos
= lpsi
->nPos
;
542 pSBData
->pos
= lpsi
->nPos
;
543 bChangeParams
= TRUE
;
547 /* Set the scroll range */
548 if (lpsi
->fMask
& SIF_RANGE
)
550 if (lpsi
->nMin
> lpsi
->nMax
)
552 Info
->nMin
= lpsi
->nMin
;
553 Info
->nMax
= lpsi
->nMin
;
554 pSBData
->posMin
= lpsi
->nMin
;
555 pSBData
->posMax
= lpsi
->nMin
;
556 bChangeParams
= TRUE
;
558 else if (Info
->nMin
!= lpsi
->nMin
|| Info
->nMax
!= lpsi
->nMax
)
560 Info
->nMin
= lpsi
->nMin
;
561 Info
->nMax
= lpsi
->nMax
;
562 pSBData
->posMin
= lpsi
->nMin
;
563 pSBData
->posMax
= lpsi
->nMax
;
564 bChangeParams
= TRUE
;
568 /* Make sure the page size is valid */
569 MaxPage
= abs(Info
->nMax
- Info
->nMin
) + 1;
570 if (Info
->nPage
> MaxPage
)
572 pSBData
->page
= Info
->nPage
= MaxPage
;
575 /* Make sure the pos is inside the range */
576 MaxPos
= Info
->nMax
+ 1 - (int)max(Info
->nPage
, 1);
577 ASSERT(MaxPos
>= Info
->nMin
);
578 if (Info
->nPos
< Info
->nMin
)
580 pSBData
->pos
= Info
->nPos
= Info
->nMin
;
582 else if (Info
->nPos
> MaxPos
)
584 pSBData
->pos
= Info
->nPos
= MaxPos
;
588 * Don't change the scrollbar state if SetScrollInfo is just called
589 * with SIF_DISABLENOSCROLL
591 if (!(lpsi
->fMask
& SIF_ALL
))
594 return lpsi
->fMask
& SIF_PREVIOUSPOS
? OldPos
: pSBData
->pos
;
597 /* Check if the scrollbar should be hidden or disabled */
598 if (lpsi
->fMask
& (SIF_RANGE
| SIF_PAGE
| SIF_DISABLENOSCROLL
))
600 new_flags
= Window
->pSBInfo
->WSBflags
;
601 if (Info
->nMin
>= (int)(Info
->nMax
- max(Info
->nPage
- 1, 0)))
603 /* Hide or disable scroll-bar */
604 if (lpsi
->fMask
& SIF_DISABLENOSCROLL
)
606 new_flags
= ESB_DISABLE_BOTH
;
607 bChangeParams
= TRUE
;
609 else if ((nBar
!= SB_CTL
) && bChangeParams
)
611 action
= SA_SSI_HIDE
;
614 else /* Show and enable scroll-bar only if no page only changed. */
615 if (lpsi
->fMask
!= SIF_PAGE
)
617 new_flags
= ESB_ENABLE_BOTH
;
618 if ((nBar
!= SB_CTL
) && bChangeParams
)
620 action
|= SA_SSI_SHOW
;
624 if (Window
->pSBInfo
->WSBflags
!= new_flags
) /* Check arrow flags */
626 Window
->pSBInfo
->WSBflags
= new_flags
;
627 action
|= SA_SSI_REPAINT_ARROWS
;
632 if ( action
& SA_SSI_HIDE
)
634 co_UserShowScrollBar(Window
, nBar
, FALSE
, FALSE
);
638 if ( action
& SA_SSI_SHOW
)
639 if ( co_UserShowScrollBar(Window
, nBar
, TRUE
, TRUE
) )
640 return lpsi
->fMask
& SIF_PREVIOUSPOS
? OldPos
: pSBData
->pos
; /* SetWindowPos() already did the painting */
643 if (action
& SA_SSI_REPAINT_ARROWS
)
644 { // Redraw the entire bar.
645 RECTL UpdateRect
= psbi
->rcScrollBar
;
646 UpdateRect
.left
-= Window
->rcClient
.left
- Window
->rcWindow
.left
;
647 UpdateRect
.right
-= Window
->rcClient
.left
- Window
->rcWindow
.left
;
648 UpdateRect
.top
-= Window
->rcClient
.top
- Window
->rcWindow
.top
;
649 UpdateRect
.bottom
-= Window
->rcClient
.top
- Window
->rcWindow
.top
;
650 co_UserRedrawWindow(Window
, &UpdateRect
, 0, RDW_INVALIDATE
| RDW_FRAME
);
654 // Redraw only the interior part of the bar.
655 IntRefeshScrollInterior(Window
, nBar
, psbi
);
658 /* else if( action & SA_SSI_REPAINT_ARROWS )
660 RECTL UpdateRect = psbi->rcScrollBar;
661 UpdateRect.left -= Window->rcClient.left - Window->rcWindow.left;
662 UpdateRect.right -= Window->rcClient.left - Window->rcWindow.left;
663 UpdateRect.top -= Window->rcClient.top - Window->rcWindow.top;
664 UpdateRect.bottom -= Window->rcClient.top - Window->rcWindow.top;
665 co_UserRedrawWindow(Window, &UpdateRect, 0, RDW_INVALIDATE | RDW_FRAME);
669 if (bChangeParams
&& (nBar
== SB_HORZ
|| nBar
== SB_VERT
) && (lpsi
->fMask
& SIF_DISABLENOSCROLL
))
671 IntEnableScrollBar(nBar
== SB_HORZ
, psbi
, Window
->pSBInfo
->WSBflags
);
674 /* Return current position */
675 return lpsi
->fMask
& SIF_PREVIOUSPOS
? OldPos
: pSBData
->pos
;
679 co_IntGetScrollBarInfo(PWND Window
, LONG idObject
, PSCROLLBARINFO psbi
)
684 ASSERT_REFS_CO(Window
);
686 Bar
= SBOBJ_TO_SBID(idObject
);
688 if(!SBID_IS_VALID(Bar
))
690 EngSetLastError(ERROR_INVALID_PARAMETER
);
691 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar
);
695 if(!co_IntCreateScrollBars(Window
))
697 ERR("Failed to create scrollbars for window.\n");
701 sbi
= IntGetScrollbarInfoFromWindow(Window
, Bar
);
702 pSBData
= IntGetSBData(Window
, Bar
);
704 IntGetScrollBarRect(Window
, Bar
, &(sbi
->rcScrollBar
));
705 IntCalculateThumb(Window
, Bar
, sbi
, pSBData
);
707 /* Scroll bar state */
708 psbi
->rgstate
[0] = 0;
709 if ((Bar
== SB_HORZ
&& !(Window
->style
& WS_HSCROLL
))
710 || (Bar
== SB_VERT
&& !(Window
->style
& WS_VSCROLL
)))
711 psbi
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
712 if (pSBData
->posMin
>= pSBData
->posMax
- max(pSBData
->page
- 1, 0))
714 if (!(psbi
->rgstate
[0] & STATE_SYSTEM_INVISIBLE
))
715 psbi
->rgstate
[0] |= STATE_SYSTEM_UNAVAILABLE
;
717 psbi
->rgstate
[0] |= STATE_SYSTEM_OFFSCREEN
;
719 if (Bar
== SB_CTL
&& !(Window
->style
& WS_DISABLED
))
720 psbi
->rgstate
[0] |= STATE_SYSTEM_UNAVAILABLE
;
722 RtlCopyMemory(psbi
, sbi
, sizeof(SCROLLBARINFO
));
728 co_IntSetScrollBarInfo(PWND Window
, LONG idObject
, PSETSCROLLBARINFO psbi
)
733 ASSERT_REFS_CO(Window
);
735 Bar
= SBOBJ_TO_SBID(idObject
);
737 if(!SBID_IS_VALID(Bar
))
739 EngSetLastError(ERROR_INVALID_PARAMETER
);
740 ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar
);
744 if(!co_IntCreateScrollBars(Window
))
746 ERR("Failed to create scrollbars for window.\n");
750 sbi
= IntGetScrollbarInfoFromWindow(Window
, Bar
);
751 psi
= IntGetScrollInfoFromWindow(Window
, Bar
);
753 psi
->nTrackPos
= psbi
->nTrackPos
;
754 sbi
->reserved
= psbi
->reserved
;
755 RtlCopyMemory(&sbi
->rgstate
, &psbi
->rgstate
, sizeof(psbi
->rgstate
));
761 co_IntCreateScrollBars(PWND Window
)
768 ASSERT_REFS_CO(Window
);
770 if (Window
->pSBInfo
&& Window
->pSBInfoex
)
772 /* No need to create it anymore */
776 /* Allocate memory for all scrollbars (HORZ, VERT, CONTROL) */
777 Size
= 3 * (sizeof(SBINFOEX
));
778 if(!(Window
->pSBInfoex
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_SBARINFO
)))
780 ERR("Unable to allocate memory for scrollbar information for window %p\n", Window
->head
.h
);
784 RtlZeroMemory(Window
->pSBInfoex
, Size
);
786 if(!(Window
->pSBInfo
= DesktopHeapAlloc( Window
->head
.rpdesk
, sizeof(SBINFO
))))
788 ERR("Unable to allocate memory for scrollbar information for window %p\n", Window
->head
.h
);
792 RtlZeroMemory(Window
->pSBInfo
, sizeof(SBINFO
));
793 Window
->pSBInfo
->Vert
.posMax
= 100;
794 Window
->pSBInfo
->Horz
.posMax
= 100;
796 co_WinPosGetNonClientSize(Window
,
800 for(s
= SB_HORZ
; s
<= SB_VERT
; s
++)
802 psbi
= IntGetScrollbarInfoFromWindow(Window
, s
);
803 psbi
->cbSize
= sizeof(SCROLLBARINFO
);
804 for (i
= 0; i
< CCHILDREN_SCROLLBAR
+ 1; i
++)
805 psbi
->rgstate
[i
] = 0;
807 pSBData
= IntGetSBData(Window
, s
);
809 IntGetScrollBarRect(Window
, s
, &(psbi
->rcScrollBar
));
810 IntCalculateThumb(Window
, s
, psbi
, pSBData
);
817 IntDestroyScrollBars(PWND Window
)
819 if (Window
->pSBInfo
&& Window
->pSBInfoex
)
821 DesktopHeapFree(Window
->head
.rpdesk
, Window
->pSBInfo
);
822 Window
->pSBInfo
= NULL
;
823 ExFreePoolWithTag(Window
->pSBInfoex
, TAG_SBARINFO
);
824 Window
->pSBInfoex
= NULL
;
831 IntEnableScrollBar(BOOL Horz
, PSCROLLBARINFO Info
, UINT wArrows
)
836 case ESB_DISABLE_BOTH
:
837 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
838 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
840 case ESB_DISABLE_RTDN
:
843 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
847 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
850 case ESB_DISABLE_LTUP
:
853 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
857 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
860 case ESB_ENABLE_BOTH
:
861 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, 0);
862 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, 0);
868 /* Ported from WINE20020904 (SCROLL_ShowScrollBar) */
870 co_UserShowScrollBar(PWND Wnd
, int nBar
, BOOL fShowH
, BOOL fShowV
)
872 ULONG old_style
, set_bits
= 0, clear_bits
= 0;
880 //IntUpdateSBInfo(Wnd, SB_CTL); // Is this needed? Was tested w/o!
882 co_WinPosShowWindow(Wnd
, fShowH
? SW_SHOW
: SW_HIDE
);
887 if (fShowH
) set_bits
|= WS_HSCROLL
;
888 else clear_bits
|= WS_HSCROLL
;
889 if( nBar
== SB_HORZ
) break;
892 if (fShowV
) set_bits
|= WS_VSCROLL
;
893 else clear_bits
|= WS_VSCROLL
;
896 EngSetLastError(ERROR_INVALID_PARAMETER
);
897 return FALSE
; /* Nothing to do! */
900 old_style
= IntSetStyle( Wnd
, set_bits
, clear_bits
);
901 if ((old_style
& clear_bits
) != 0 || (old_style
& set_bits
) != set_bits
)
903 ///// Is this needed? Was tested w/o!
904 //if (Wnd->style & WS_HSCROLL) IntUpdateSBInfo(Wnd, SB_HORZ);
905 //if (Wnd->style & WS_VSCROLL) IntUpdateSBInfo(Wnd, SB_VERT);
907 /* Frame has been changed, let the window redraw itself */
908 co_WinPosSetWindowPos( Wnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
909 | SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
912 return FALSE
; /* no frame changes */
916 IntDrawScrollInterior(PWND pWnd
, HDC hDC
, INT nBar
, BOOL Vertical
, PSCROLLBARINFO ScrollBarInfo
)
918 INT ThumbSize
= ScrollBarInfo
->xyThumbBottom
- ScrollBarInfo
->xyThumbTop
;
919 INT ThumbTop
= ScrollBarInfo
->xyThumbTop
;
921 HBRUSH hSaveBrush
, hBrush
;
922 BOOL TopSelected
= FALSE
, BottomSelected
= FALSE
;
924 if (ScrollBarInfo
->rgstate
[SCROLL_TOP_RECT
] & STATE_SYSTEM_PRESSED
)
926 if (ScrollBarInfo
->rgstate
[SCROLL_BOTTOM_RECT
] & STATE_SYSTEM_PRESSED
)
927 BottomSelected
= TRUE
;
930 * Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
931 * The window-owned scrollbars need to call DefWndControlColor
932 * to correctly setup default scrollbar colors
936 hBrush
= GetControlBrush( pWnd
, hDC
, WM_CTLCOLORSCROLLBAR
);
938 hBrush
= IntGetSysColorBrush(COLOR_SCROLLBAR
);
942 hBrush
= DefWndControlColor(hDC
, CTLCOLOR_SCROLLBAR
);
945 hSaveBrush
= NtGdiSelectBrush(hDC
, hBrush
);
947 /* Calculate the scroll rectangle */
950 Rect
.top
= ScrollBarInfo
->rcScrollBar
.top
+ ScrollBarInfo
->dxyLineButton
;
951 Rect
.bottom
= ScrollBarInfo
->rcScrollBar
.bottom
- ScrollBarInfo
->dxyLineButton
;
952 Rect
.left
= ScrollBarInfo
->rcScrollBar
.left
;
953 Rect
.right
= ScrollBarInfo
->rcScrollBar
.right
;
957 Rect
.top
= ScrollBarInfo
->rcScrollBar
.top
;
958 Rect
.bottom
= ScrollBarInfo
->rcScrollBar
.bottom
;
959 Rect
.left
= ScrollBarInfo
->rcScrollBar
.left
+ ScrollBarInfo
->dxyLineButton
;
960 Rect
.right
= ScrollBarInfo
->rcScrollBar
.right
- ScrollBarInfo
->dxyLineButton
;
963 /* Draw the scroll rectangles and thumb */
964 if (!ScrollBarInfo
->xyThumbBottom
)
966 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
- Rect
.left
,
967 Rect
.bottom
- Rect
.top
, PATCOPY
);
969 /* Cleanup and return */
970 NtGdiSelectBrush(hDC
, hSaveBrush
);
974 ThumbTop
-= ScrollBarInfo
->dxyLineButton
;
976 if (ScrollBarInfo
->dxyLineButton
)
982 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
- Rect
.left
,
983 ThumbTop
, TopSelected
? BLACKNESS
: PATCOPY
);
984 Rect
.top
+= ThumbTop
;
985 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
+ ThumbSize
, Rect
.right
- Rect
.left
,
986 Rect
.bottom
- Rect
.top
- ThumbSize
, BottomSelected
? BLACKNESS
: PATCOPY
);
987 Rect
.bottom
= Rect
.top
+ ThumbSize
;
993 NtGdiPatBlt(hDC
, Rect
.left
, ScrollBarInfo
->dxyLineButton
,
994 Rect
.right
- Rect
.left
, Rect
.bottom
- Rect
.top
, PATCOPY
);
1002 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, ThumbTop
,
1003 Rect
.bottom
- Rect
.top
, TopSelected
? BLACKNESS
: PATCOPY
);
1004 Rect
.left
+= ThumbTop
;
1005 NtGdiPatBlt(hDC
, Rect
.left
+ ThumbSize
, Rect
.top
,
1006 Rect
.right
- Rect
.left
- ThumbSize
, Rect
.bottom
- Rect
.top
,
1007 BottomSelected
? BLACKNESS
: PATCOPY
);
1008 Rect
.right
= Rect
.left
+ ThumbSize
;
1014 NtGdiPatBlt(hDC
, ScrollBarInfo
->dxyLineButton
, Rect
.top
,
1015 Rect
.right
- Rect
.left
, Rect
.bottom
- Rect
.top
, PATCOPY
);
1021 /* Draw the thumb */
1023 DrawEdge(hDC
, &Rect
, EDGE_RAISED
, BF_RECT
| BF_MIDDLE
);
1026 NtGdiSelectBrush(hDC
, hSaveBrush
);
1030 static VOID FASTCALL
1031 IntDrawScrollArrows(HDC hDC
, PSCROLLBARINFO ScrollBarInfo
, BOOL Vertical
)
1033 RECT RectLT
, RectRB
;
1034 INT ScrollDirFlagLT
, ScrollDirFlagRB
;
1036 RectLT
= RectRB
= ScrollBarInfo
->rcScrollBar
;
1039 ScrollDirFlagLT
= DFCS_SCROLLUP
;
1040 ScrollDirFlagRB
= DFCS_SCROLLDOWN
;
1041 RectLT
.bottom
= RectLT
.top
+ ScrollBarInfo
->dxyLineButton
;
1042 RectRB
.top
= RectRB
.bottom
- ScrollBarInfo
->dxyLineButton
;
1046 ScrollDirFlagLT
= DFCS_SCROLLLEFT
;
1047 ScrollDirFlagRB
= DFCS_SCROLLRIGHT
;
1048 RectLT
.right
= RectLT
.left
+ ScrollBarInfo
->dxyLineButton
;
1049 RectRB
.left
= RectRB
.right
- ScrollBarInfo
->dxyLineButton
;
1052 if (ScrollBarInfo
->rgstate
[SCROLL_TOP_ARROW
] & STATE_SYSTEM_PRESSED
)
1054 ScrollDirFlagLT
|= DFCS_PUSHED
| DFCS_FLAT
;
1056 if (ScrollBarInfo
->rgstate
[SCROLL_TOP_ARROW
] & STATE_SYSTEM_UNAVAILABLE
)
1058 ScrollDirFlagLT
|= DFCS_INACTIVE
;
1060 if (ScrollBarInfo
->rgstate
[SCROLL_BOTTOM_ARROW
] & STATE_SYSTEM_PRESSED
)
1062 ScrollDirFlagRB
|= DFCS_PUSHED
| DFCS_FLAT
;
1064 if (ScrollBarInfo
->rgstate
[SCROLL_BOTTOM_ARROW
] & STATE_SYSTEM_UNAVAILABLE
)
1066 ScrollDirFlagRB
|= DFCS_INACTIVE
;
1069 DrawFrameControl(hDC
, &RectLT
, DFC_SCROLL
, ScrollDirFlagLT
);
1070 DrawFrameControl(hDC
, &RectRB
, DFC_SCROLL
, ScrollDirFlagRB
);
1073 static LONG FASTCALL
1074 IntScrollGetObjectId(INT SBType
)
1076 if (SBType
== SB_VERT
)
1077 return OBJID_VSCROLL
;
1078 if (SBType
== SB_HORZ
)
1079 return OBJID_HSCROLL
;
1080 return OBJID_CLIENT
;
1084 IntRefeshScrollInterior(PWND pWnd
, INT nBar
, PSCROLLBARINFO psbi
)
1087 BOOL Vertical
= ((nBar
== SB_CTL
) ? ((pWnd
->style
& SBS_VERT
) != 0) : (nBar
== SB_VERT
));
1089 hdc
= UserGetDCEx(pWnd
, NULL
, DCX_CACHE
| ((nBar
== SB_CTL
) ? 0 : DCX_WINDOW
));
1091 { /* Get updated info. */
1092 co_IntGetScrollBarInfo(pWnd
, IntScrollGetObjectId(nBar
), psbi
);
1093 IntDrawScrollInterior(pWnd
, hdc
, nBar
, Vertical
, psbi
);
1094 UserReleaseDC(pWnd
, hdc
, FALSE
);
1099 IntDrawScrollBar(PWND Wnd
, HDC DC
, INT Bar
)
1107 pti
= PsGetCurrentThreadWin32Thread();
1110 * Get scroll bar info.
1123 Vertical
= (Wnd
->style
& SBS_VERT
) != 0;
1130 if (!co_IntGetScrollBarInfo(Wnd
, IntScrollGetObjectId(Bar
), &Info
))
1135 if (RECTL_bIsEmptyRect(&Info
.rcScrollBar
))
1140 //ThumbSize = pSBWnd->pSBCalc->pxThumbBottom - pSBWnd->pSBCalc->pxThumbTop;
1145 if (Info
.dxyLineButton
)
1147 IntDrawScrollArrows(DC
, &Info
, Vertical
);
1151 * Draw the interior.
1153 IntDrawScrollInterior(Wnd
, DC
, Bar
, Vertical
, &Info
);
1156 * If scroll bar has focus, reposition the caret.
1158 if ( Wnd
== pti
->MessageQueue
->spwndFocus
&& Bar
== SB_CTL
)
1162 co_IntSetCaretPos(Info
.rcScrollBar
.top
+ 1, Info
.dxyLineButton
+ 1);
1166 co_IntSetCaretPos(Info
.dxyLineButton
+ 1, Info
.rcScrollBar
.top
+ 1);
1173 ScrollBarWndProc(HWND hWnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
1175 LRESULT lResult
= 0;
1177 pWnd
= UserGetWindowObject(hWnd
);
1178 if (!pWnd
) return 0;
1186 pWnd
->pSBInfo
->WSBflags
= wParam
? ESB_ENABLE_BOTH
: ESB_DISABLE_BOTH
;
1198 NtUserGetScrollBarInfo(HWND hWnd
, LONG idObject
, PSCROLLBARINFO psbi
)
1204 DECLARE_RETURN(BOOL
);
1205 USER_REFERENCE_ENTRY Ref
;
1207 TRACE("Enter NtUserGetScrollBarInfo\n");
1208 UserEnterExclusive();
1210 Status
= MmCopyFromCaller(&sbi
, psbi
, sizeof(SCROLLBARINFO
));
1211 if(!NT_SUCCESS(Status
) || (sbi
.cbSize
!= sizeof(SCROLLBARINFO
)))
1213 SetLastNtError(Status
);
1217 if(!(Window
= UserGetWindowObject(hWnd
)))
1222 UserRefObjectCo(Window
, &Ref
);
1223 Ret
= co_IntGetScrollBarInfo(Window
, idObject
, &sbi
);
1224 UserDerefObjectCo(Window
);
1226 Status
= MmCopyToCaller(psbi
, &sbi
, sizeof(SCROLLBARINFO
));
1227 if(!NT_SUCCESS(Status
))
1229 SetLastNtError(Status
);
1236 TRACE("Leave NtUserGetScrollBarInfo, ret=%i\n",_ret_
);
1254 DECLARE_RETURN(BOOL
);
1255 USER_REFERENCE_ENTRY Ref
;
1257 TRACE("Enter NtUserGetScrollInfo\n");
1262 RtlCopyMemory(&psi
, lpsi
, sizeof(SCROLLINFO
));
1265 RtlCopyMemory(&SBDataSafe
, pSBData
, sizeof(SBDATA
));
1268 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1270 ERR("NtUserGetScrollInfo Failed size.\n");
1271 SetLastNtError(_SEH2_GetExceptionCode());
1272 _SEH2_YIELD(RETURN(FALSE
));
1276 if(!(Window
= UserGetWindowObject(hWnd
)))
1278 ERR("NtUserGetScrollInfo Bad window.\n");
1282 UserRefObjectCo(Window
, &Ref
);
1283 Ret
= co_IntGetScrollInfo(Window
, fnBar
, &SBDataSafe
, &psi
);
1284 UserDerefObjectCo(Window
);
1288 RtlCopyMemory(lpsi
, &psi
, sizeof(SCROLLINFO
));
1290 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1292 ERR("NtUserGetScrollInfo Failed copy to user.\n");
1293 SetLastNtError(_SEH2_GetExceptionCode());
1294 _SEH2_YIELD(RETURN(FALSE
));
1301 TRACE("Leave NtUserGetScrollInfo, ret=%i\n",_ret_
);
1308 NtUserEnableScrollBar(
1315 PSCROLLBARINFO InfoV
= NULL
, InfoH
= NULL
;
1317 DECLARE_RETURN(BOOL
);
1318 USER_REFERENCE_ENTRY Ref
;
1320 TRACE("Enter NtUserEnableScrollBar\n");
1321 UserEnterExclusive();
1323 if (!(Window
= UserGetWindowObject(hWnd
)) ||
1324 UserIsDesktopWindow(Window
) || UserIsMessageWindow(Window
))
1328 UserRefObjectCo(Window
, &Ref
);
1330 if (!co_IntCreateScrollBars(Window
))
1335 OrigArrows
= Window
->pSBInfo
->WSBflags
;
1336 Window
->pSBInfo
->WSBflags
= wArrows
;
1338 if (wSBflags
== SB_CTL
)
1340 if ((wArrows
== ESB_DISABLE_BOTH
|| wArrows
== ESB_ENABLE_BOTH
))
1341 IntEnableWindow(hWnd
, (wArrows
== ESB_ENABLE_BOTH
));
1346 if(wSBflags
!= SB_BOTH
&& !SBID_IS_VALID(wSBflags
))
1348 EngSetLastError(ERROR_INVALID_PARAMETER
);
1349 ERR("Trying to set scrollinfo for unknown scrollbar type %u", wSBflags
);
1356 InfoV
= IntGetScrollbarInfoFromWindow(Window
, SB_VERT
);
1359 InfoH
= IntGetScrollbarInfoFromWindow(Window
, SB_HORZ
);
1362 InfoV
= IntGetScrollbarInfoFromWindow(Window
, SB_VERT
);
1369 Chg
= IntEnableScrollBar(FALSE
, InfoV
, wArrows
);
1372 Chg
= (IntEnableScrollBar(TRUE
, InfoH
, wArrows
) || Chg
);
1374 ERR("FIXME: EnableScrollBar wSBflags %u wArrows %u Chg %d\n", wSBflags
, wArrows
, Chg
);
1376 // SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE );
1379 if (OrigArrows
== wArrows
) RETURN( FALSE
);
1384 UserDerefObjectCo(Window
);
1386 TRACE("Leave NtUserEnableScrollBar, ret=%i\n",_ret_
);
1393 NtUserSetScrollInfo(
1401 SCROLLINFO ScrollInfo
;
1402 DECLARE_RETURN(DWORD
);
1403 USER_REFERENCE_ENTRY Ref
;
1405 TRACE("Enter NtUserSetScrollInfo\n");
1406 UserEnterExclusive();
1408 if(!(Window
= UserGetWindowObject(hWnd
)) ||
1409 UserIsDesktopWindow(Window
) || UserIsMessageWindow(Window
))
1413 UserRefObjectCo(Window
, &Ref
);
1415 Status
= MmCopyFromCaller(&ScrollInfo
, lpsi
, sizeof(SCROLLINFO
) - sizeof(ScrollInfo
.nTrackPos
));
1416 if(!NT_SUCCESS(Status
))
1418 SetLastNtError(Status
);
1422 RETURN(co_IntSetScrollInfo(Window
, fnBar
, &ScrollInfo
, bRedraw
));
1426 UserDerefObjectCo(Window
);
1428 TRACE("Leave NtUserSetScrollInfo, ret=%lu\n", _ret_
);
1435 NtUserShowScrollBar(HWND hWnd
, int nBar
, DWORD bShow
)
1438 DECLARE_RETURN(DWORD
);
1440 USER_REFERENCE_ENTRY Ref
;
1442 TRACE("Enter NtUserShowScrollBar\n");
1443 UserEnterExclusive();
1445 if (!(Window
= UserGetWindowObject(hWnd
)))
1450 UserRefObjectCo(Window
, &Ref
);
1451 ret
= co_UserShowScrollBar(Window
, nBar
, (nBar
== SB_VERT
) ? 0 : bShow
,
1452 (nBar
== SB_HORZ
) ? 0 : bShow
);
1453 UserDerefObjectCo(Window
);
1458 TRACE("Leave NtUserShowScrollBar, ret%lu\n", _ret_
);
1465 //// Ugly NtUser API ////
1469 NtUserSetScrollBarInfo(
1472 SETSCROLLBARINFO
*info
)
1475 SETSCROLLBARINFO Safeinfo
;
1480 DECLARE_RETURN(BOOL
);
1481 USER_REFERENCE_ENTRY Ref
;
1483 TRACE("Enter NtUserSetScrollBarInfo\n");
1484 UserEnterExclusive();
1486 if(!(Window
= UserGetWindowObject(hWnd
)))
1490 UserRefObjectCo(Window
, &Ref
);
1492 Obj
= SBOBJ_TO_SBID(idObject
);
1493 if(!SBID_IS_VALID(Obj
))
1495 EngSetLastError(ERROR_INVALID_PARAMETER
);
1496 ERR("Trying to set scrollinfo for unknown scrollbar type %d\n", Obj
);
1500 if(!co_IntCreateScrollBars(Window
))
1505 Status
= MmCopyFromCaller(&Safeinfo
, info
, sizeof(SETSCROLLBARINFO
));
1506 if(!NT_SUCCESS(Status
))
1508 SetLastNtError(Status
);
1512 sbi
= IntGetScrollbarInfoFromWindow(Window
, Obj
);
1513 psi
= IntGetScrollInfoFromWindow(Window
, Obj
);
1515 psi
->nTrackPos
= Safeinfo
.nTrackPos
;
1516 sbi
->reserved
= Safeinfo
.reserved
;
1517 RtlCopyMemory(&sbi
->rgstate
, &Safeinfo
.rgstate
, sizeof(Safeinfo
.rgstate
));
1523 UserDerefObjectCo(Window
);
1525 TRACE("Leave NtUserSetScrollBarInfo, ret=%i\n",_ret_
);