2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
24 * FILE: subsys/win32k/ntuser/scrollbar.c
25 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
26 * Jason Filby (jasonfilby@yahoo.com)
28 * 16-11-2002 Jason Filby Created
30 /* INCLUDES ******************************************************************/
41 #define MINTRACKTHUMB 8 /* Minimum size of the rectangle between the arrows */
43 #define SBRG_SCROLLBAR 0 /* the scrollbar itself */
44 #define SBRG_TOPRIGHTBTN 1 /* the top or right button */
45 #define SBRG_PAGEUPRIGHT 2 /* the page up or page right region */
46 #define SBRG_SCROLLBOX 3 /* the scroll box */
47 #define SBRG_PAGEDOWNLEFT 4 /* the page down or page left region */
48 #define SBRG_BOTTOMLEFTBTN 5 /* the bottom or left button */
50 #define CHANGERGSTATE(item, status) \
51 if(Info->rgstate[(item)] != (status)) \
53 Info->rgstate[(item)] = (status);
55 /* FUNCTIONS *****************************************************************/
57 /* Ported from WINE20020904 */
58 /* Compute the scroll bar rectangle, in drawing coordinates (i.e. client coords for SB_CTL, window coords for SB_VERT and
59 * SB_HORZ). 'arrowSize' returns the width or height of an arrow (depending on * the orientation of the scrollbar),
60 * 'thumbSize' returns the size of the thumb, and 'thumbPos' returns the position of the thumb relative to the left or to
61 * the top. Return TRUE if the scrollbar is vertical, FALSE if horizontal.
64 IntGetScrollBarRect (PWINDOW_OBJECT Window
, INT nBar
, PRECT lprect
)
67 RECT ClientRect
= Window
->ClientRect
;
68 RECT WindowRect
= Window
->WindowRect
;
73 lprect
->left
= ClientRect
.left
- WindowRect
.left
;
74 lprect
->top
= ClientRect
.bottom
- WindowRect
.top
;
75 lprect
->right
= ClientRect
.right
- WindowRect
.left
;
76 lprect
->bottom
= lprect
->top
+ NtUserGetSystemMetrics (SM_CYHSCROLL
);
81 if(Window
->ExStyle
& WS_EX_LEFTSCROLLBAR
)
83 lprect
->right
= ClientRect
.left
- WindowRect
.left
;
84 lprect
->left
= lprect
->right
- NtUserGetSystemMetrics(SM_CXVSCROLL
);
88 lprect
->left
= ClientRect
.right
- WindowRect
.left
;
89 lprect
->right
= lprect
->left
+ NtUserGetSystemMetrics(SM_CXVSCROLL
);
91 lprect
->top
= ClientRect
.top
- WindowRect
.top
;
92 lprect
->bottom
= ClientRect
.bottom
- WindowRect
.top
;
97 IntGetClientRect (Window
, lprect
);
98 vertical
= ((Window
->Style
& SBS_VERT
) != 0);
102 IntReleaseWindowObject(Window
);
110 IntCalculateThumb(PWINDOW_OBJECT Window
, LONG idObject
, PSCROLLBARINFO psbi
, LPSCROLLINFO psi
)
112 INT Thumb
, ThumbBox
, ThumbPos
, cxy
, mx
;
118 Thumb
= NtUserGetSystemMetrics(SM_CXHSCROLL
);
119 cxy
= psbi
->rcScrollBar
.right
- psbi
->rcScrollBar
.left
;
122 Thumb
= NtUserGetSystemMetrics(SM_CYVSCROLL
);
123 cxy
= psbi
->rcScrollBar
.bottom
- psbi
->rcScrollBar
.top
;
126 IntGetClientRect (Window
, &ClientRect
);
127 if(Window
->Style
& SBS_VERT
)
129 Thumb
= NtUserGetSystemMetrics(SM_CYVSCROLL
);
130 cxy
= ClientRect
.bottom
- ClientRect
.top
;
134 Thumb
= NtUserGetSystemMetrics(SM_CXHSCROLL
);
135 cxy
= ClientRect
.right
- ClientRect
.left
;
143 /* calculate Thumb */
144 if(cxy
<= (2 * Thumb
))
147 psbi
->xyThumbTop
= 0;
148 psbi
->xyThumbBottom
= 0;
153 ThumbBox
= psi
->nPage
? MINTRACKTHUMB
: NtUserGetSystemMetrics(SM_CXHTHUMB
);
159 ThumbBox
= max(EngMulDiv(cxy
, psi
->nPage
, psi
->nMax
- psi
->nMin
+ 1), ThumbBox
);
164 mx
= psi
->nMax
- max(psi
->nPage
- 1, 0);
166 ThumbPos
= Thumb
+ EngMulDiv(cxy
- ThumbBox
, psi
->nPos
- psi
->nMin
, mx
- psi
->nMin
);
168 ThumbPos
= Thumb
+ ThumbBox
;
171 psbi
->xyThumbTop
= ThumbPos
;
172 psbi
->xyThumbBottom
= ThumbPos
+ ThumbBox
;
176 psbi
->xyThumbTop
= 0;
177 psbi
->xyThumbBottom
= 0;
180 psbi
->dxyLineButton
= Thumb
;
186 IntUpdateSBInfo(PWINDOW_OBJECT Window
, int wBar
)
192 ASSERT(Window
->Scroll
);
194 sbi
= IntGetScrollbarInfoFromWindow(Window
, wBar
);
195 psi
= IntGetScrollInfoFromWindow(Window
, wBar
);
196 IntGetScrollBarRect(Window
, wBar
, &(sbi
->rcScrollBar
));
197 IntCalculateThumb(Window
, wBar
, sbi
, psi
);
201 IntGetScrollInfo(PWINDOW_OBJECT Window
, INT nBar
, LPSCROLLINFO lpsi
)
206 if(!SBID_IS_VALID(nBar
))
208 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
209 DPRINT1("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar
);
213 if(!IntCreateScrollBars(Window
))
218 psi
= IntGetScrollInfoFromWindow(Window
, nBar
);
220 if (lpsi
->fMask
== SIF_ALL
)
222 Mask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
| SIF_TRACKPOS
;
229 if (0 != (Mask
& SIF_PAGE
))
231 lpsi
->nPage
= psi
->nPage
;
234 if (0 != (Mask
& SIF_POS
))
236 lpsi
->nPos
= psi
->nPos
;
239 if (0 != (Mask
& SIF_RANGE
))
241 lpsi
->nMin
= psi
->nMin
;
242 lpsi
->nMax
= psi
->nMax
;
245 if (0 != (Mask
& SIF_TRACKPOS
))
247 lpsi
->nTrackPos
= psi
->nTrackPos
;
253 static DWORD FASTCALL
254 IntSetScrollInfo(PWINDOW_OBJECT Window
, INT nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
)
257 * Update the scrollbar state and set action flags according to
258 * what has to be done graphics wise.
264 BOOL bChangeParams
= FALSE
; /* don't show/hide scrollbar if params don't change */
266 if(!SBID_IS_VALID(nBar
))
268 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
269 DPRINT1("Trying to set scrollinfo for unknown scrollbar type %d", nBar
);
273 if(!IntCreateScrollBars(Window
))
278 if (lpsi
->cbSize
!= sizeof(SCROLLINFO
) &&
279 lpsi
->cbSize
!= (sizeof(SCROLLINFO
) - sizeof(lpsi
->nTrackPos
)))
281 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
284 if (lpsi
->fMask
& ~(SIF_ALL
| SIF_DISABLENOSCROLL
))
286 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
290 psbi
= IntGetScrollbarInfoFromWindow(Window
, nBar
);
291 Info
= IntGetScrollInfoFromWindow(Window
, nBar
);
293 /* Set the page size */
294 if (0 != (lpsi
->fMask
& SIF_PAGE
))
296 if (Info
->nPage
!= lpsi
->nPage
)
298 Info
->nPage
= lpsi
->nPage
;
299 bChangeParams
= TRUE
;
303 /* Set the scroll pos */
304 if (0 != (lpsi
->fMask
& SIF_POS
))
306 if (Info
->nPos
!= lpsi
->nPos
)
308 Info
->nPos
= lpsi
->nPos
;
312 /* Set the scroll range */
313 if (0 != (lpsi
->fMask
& SIF_RANGE
))
315 /* Invalid range -> range is set to (0,0) */
316 if (lpsi
->nMin
> lpsi
->nMax
||
317 0x80000000 <= (UINT
)(lpsi
->nMax
- lpsi
->nMin
))
321 bChangeParams
= TRUE
;
323 else if (Info
->nMin
!= lpsi
->nMin
|| Info
->nMax
!= lpsi
->nMax
)
325 Info
->nMin
= lpsi
->nMin
;
326 Info
->nMax
= lpsi
->nMax
;
327 bChangeParams
= TRUE
;
331 /* Make sure the page size is valid */
336 else if (Info
->nMax
- Info
->nMin
+ 1 < Info
->nPage
)
338 Info
->nPage
= Info
->nMax
- Info
->nMin
+ 1;
341 /* Make sure the pos is inside the range */
342 if (Info
->nPos
< Info
->nMin
)
344 Info
->nPos
= Info
->nMin
;
346 else if (Info
->nPos
> Info
->nMax
- max(Info
->nPage
- 1, 0))
348 Info
->nPos
= Info
->nMax
- max(Info
->nPage
- 1, 0);
352 * Don't change the scrollbar state if SetScrollInfo is just called
353 * with SIF_DISABLENOSCROLL
355 if (0 == (lpsi
->fMask
& SIF_ALL
))
360 /* Check if the scrollbar should be hidden or disabled */
361 if (0 != (lpsi
->fMask
& (SIF_RANGE
| SIF_PAGE
| SIF_DISABLENOSCROLL
)))
363 if (Info
->nMin
>= (int)(Info
->nMax
- max(Info
->nPage
- 1, 0)))
365 /* Hide or disable scroll-bar */
366 if (0 != (lpsi
->fMask
& SIF_DISABLENOSCROLL
))
368 /* new_flags = ESB_DISABLE_BOTH;*/
370 else if ((nBar
!= SB_CTL
) && bChangeParams
)
372 NtUserShowScrollBar(Window
->Self
, nBar
, FALSE
);
376 else /* Show and enable scroll-bar */
379 if ((nBar
!= SB_CTL
) && bChangeParams
)
381 NtUserShowScrollBar(Window
->Self
, nBar
, TRUE
);
386 if (infoPtr
->flags
!= new_flags
) /* check arrow flags */
388 infoPtr
->flags
= new_flags
;
389 *Action
|= SA_SSI_REPAINT_ARROWS
;
396 RECT UpdateRect
= psbi
->rcScrollBar
;
397 UpdateRect
.left
-= Window
->ClientRect
.left
- Window
->WindowRect
.left
;
398 UpdateRect
.right
-= Window
->ClientRect
.left
- Window
->WindowRect
.left
;
399 UpdateRect
.top
-= Window
->ClientRect
.top
- Window
->WindowRect
.top
;
400 UpdateRect
.bottom
-= Window
->ClientRect
.top
- Window
->WindowRect
.top
;
401 IntRedrawWindow(Window
, &UpdateRect
, 0, RDW_INVALIDATE
| RDW_FRAME
);
404 /* Return current position */
409 IntGetScrollBarInfo(PWINDOW_OBJECT Window
, LONG idObject
, PSCROLLBARINFO psbi
)
415 Bar
= SBOBJ_TO_SBID(idObject
);
417 if(!SBID_IS_VALID(Bar
))
419 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
420 DPRINT1("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar
);
424 if(!IntCreateScrollBars(Window
))
429 sbi
= IntGetScrollbarInfoFromWindow(Window
, Bar
);
430 psi
= IntGetScrollInfoFromWindow(Window
, Bar
);
432 IntGetScrollBarRect(Window
, Bar
, &(sbi
->rcScrollBar
));
433 IntCalculateThumb(Window
, Bar
, sbi
, psi
);
435 RtlCopyMemory(psbi
, sbi
, sizeof(SCROLLBARINFO
));
441 IntCreateScrollBars(PWINDOW_OBJECT Window
)
451 /* no need to create it anymore */
455 /* allocate memory for all scrollbars (HORZ, VERT, CONTROL) */
456 Size
= 3 * (sizeof(WINDOW_SCROLLINFO
));
457 if(!(Window
->Scroll
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_SBARINFO
)))
459 DPRINT1("Unable to allocate memory for scrollbar information for window 0x%x\n", Window
->Self
);
463 RtlZeroMemory(Window
->Scroll
, Size
);
465 Result
= WinPosGetNonClientSize(Window
->Self
,
467 &Window
->ClientRect
);
469 for(s
= SB_HORZ
; s
<= SB_VERT
; s
++)
471 psbi
= IntGetScrollbarInfoFromWindow(Window
, s
);
472 psbi
->cbSize
= sizeof(SCROLLBARINFO
);
473 for (i
= 0; i
< CCHILDREN_SCROLLBAR
+ 1; i
++)
474 psbi
->rgstate
[i
] = 0;
476 psi
= IntGetScrollInfoFromWindow(Window
, s
);
477 psi
->cbSize
= sizeof(LPSCROLLINFO
);
480 IntGetScrollBarRect(Window
, s
, &(psbi
->rcScrollBar
));
481 IntCalculateThumb(Window
, s
, psbi
, psi
);
488 IntDestroyScrollBars(PWINDOW_OBJECT Window
)
492 ExFreePool(Window
->Scroll
);
493 Window
->Scroll
= NULL
;
500 IntEnableScrollBar(BOOL Horz
, PSCROLLBARINFO Info
, UINT wArrows
)
505 case ESB_DISABLE_BOTH
:
506 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
507 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
509 case ESB_DISABLE_RTDN
:
512 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
516 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
519 case ESB_DISABLE_LTUP
:
522 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
526 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
529 case ESB_ENABLE_BOTH
:
530 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, 0);
531 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, 0);
540 NtUserGetScrollBarInfo(HWND hWnd
, LONG idObject
, PSCROLLBARINFO psbi
)
544 PWINDOW_OBJECT Window
;
547 Status
= MmCopyFromCaller(&sbi
, psbi
, sizeof(SCROLLBARINFO
));
548 if(!NT_SUCCESS(Status
) || (sbi
.cbSize
!= sizeof(SCROLLBARINFO
)))
550 SetLastNtError(Status
);
554 Window
= IntGetWindowObject(hWnd
);
558 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
562 Ret
= IntGetScrollBarInfo(Window
, idObject
, &sbi
);
564 Status
= MmCopyToCaller(psbi
, &sbi
, sizeof(SCROLLBARINFO
));
565 if(!NT_SUCCESS(Status
))
567 SetLastNtError(Status
);
570 IntReleaseWindowObject(Window
);
577 NtUserGetScrollInfo(HWND hwnd
, int fnBar
, LPSCROLLINFO lpsi
)
580 PWINDOW_OBJECT Window
;
585 Status
= MmCopyFromCaller(&psi
.cbSize
, &(lpsi
->cbSize
), sizeof(UINT
));
586 if(!NT_SUCCESS(Status
) ||
587 !((psi
.cbSize
== sizeof(SCROLLINFO
)) || (psi
.cbSize
== sizeof(SCROLLINFO
) - sizeof(psi
.nTrackPos
))))
589 SetLastNtError(Status
);
593 Status
= MmCopyFromCaller(&psi
, lpsi
, sz
);
594 if (!NT_SUCCESS(Status
))
596 SetLastNtError(Status
);
600 Window
= IntGetWindowObject(hwnd
);
604 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
608 Ret
= IntGetScrollInfo(Window
, fnBar
, &psi
);
610 IntReleaseWindowObject(Window
);
612 Status
= MmCopyToCaller(lpsi
, &psi
, sz
);
613 if(!NT_SUCCESS(Status
))
615 SetLastNtError(Status
);
625 NtUserEnableScrollBar(
630 PWINDOW_OBJECT Window
;
631 PSCROLLBARINFO InfoV
= NULL
, InfoH
= NULL
;
634 Window
= IntGetWindowObject(hWnd
);
638 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
642 if(wSBflags
== SB_CTL
)
645 IntReleaseWindowObject(Window
);
649 if(wSBflags
!= SB_BOTH
&& !SBID_IS_VALID(wSBflags
))
651 IntReleaseWindowObject(Window
);
652 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
653 DPRINT1("Trying to set scrollinfo for unknown scrollbar type %d", wSBflags
);
657 if(!IntCreateScrollBars(Window
))
659 IntReleaseWindowObject(Window
);
666 InfoV
= IntGetScrollbarInfoFromWindow(Window
, SB_VERT
);
669 InfoH
= IntGetScrollbarInfoFromWindow(Window
, SB_HORZ
);
672 InfoV
= IntGetScrollbarInfoFromWindow(Window
, SB_VERT
);
675 IntReleaseWindowObject(Window
);
680 Chg
= IntEnableScrollBar(FALSE
, InfoV
, wArrows
);
683 Chg
= (IntEnableScrollBar(TRUE
, InfoH
, wArrows
) || Chg
);
685 //if(Chg && (Window->Style & WS_VISIBLE))
686 /* FIXME - repaint scrollbars */
688 IntReleaseWindowObject(Window
);
694 NtUserSetScrollBarInfo(
697 SETSCROLLBARINFO
*info
)
699 PWINDOW_OBJECT Window
;
700 SETSCROLLBARINFO Safeinfo
;
706 Window
= IntGetWindowObject(hwnd
);
710 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
714 Obj
= SBOBJ_TO_SBID(idObject
);
715 if(!SBID_IS_VALID(Obj
))
717 IntReleaseWindowObject(Window
);
718 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
719 DPRINT1("Trying to set scrollinfo for unknown scrollbar type %d", Obj
);
723 if(!IntCreateScrollBars(Window
))
725 IntReleaseWindowObject(Window
);
729 Status
= MmCopyFromCaller(&Safeinfo
, info
, sizeof(SETSCROLLBARINFO
));
730 if(!NT_SUCCESS(Status
))
732 IntReleaseWindowObject(Window
);
733 SetLastNtError(Status
);
737 sbi
= IntGetScrollbarInfoFromWindow(Window
, Obj
);
738 psi
= IntGetScrollInfoFromWindow(Window
, Obj
);
740 psi
->nTrackPos
= Safeinfo
.nTrackPos
;
741 sbi
->reserved
= Safeinfo
.reserved
;
742 RtlCopyMemory(&sbi
->rgstate
, &Safeinfo
.rgstate
, sizeof(Safeinfo
.rgstate
));
744 IntReleaseWindowObject(Window
);
756 PWINDOW_OBJECT Window
;
758 SCROLLINFO ScrollInfo
;
761 Window
= IntGetWindowObject(hwnd
);
765 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
769 Status
= MmCopyFromCaller(&ScrollInfo
, lpsi
, sizeof(SCROLLINFO
) - sizeof(ScrollInfo
.nTrackPos
));
770 if(!NT_SUCCESS(Status
))
772 IntReleaseWindowObject(Window
);
773 SetLastNtError(Status
);
777 Ret
= IntSetScrollInfo(Window
, fnBar
, &ScrollInfo
, bRedraw
);
778 IntReleaseWindowObject(Window
);
783 /* Ported from WINE20020904 (SCROLL_ShowScrollBar) */
785 NtUserShowScrollBar(HWND hWnd
, int wBar
, DWORD bShow
)
787 DWORD Style
, OldStyle
;
788 PWINDOW_OBJECT Window
= IntGetWindowObject(hWnd
);
792 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
805 Style
= WS_HSCROLL
| WS_VSCROLL
;
811 IntReleaseWindowObject(Window
);
812 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
816 if(!IntCreateScrollBars(Window
))
818 IntReleaseWindowObject(Window
);
824 IntUpdateSBInfo(Window
, SB_CTL
);
826 WinPosShowWindow(hWnd
, bShow
? SW_SHOW
: SW_HIDE
);
827 IntReleaseWindowObject(Window
);
831 OldStyle
= Window
->Style
;
833 Window
->Style
|= Style
;
835 Window
->Style
&= ~Style
;
837 if(Window
->Style
!= OldStyle
)
839 if(Window
->Style
& WS_HSCROLL
)
840 IntUpdateSBInfo(Window
, SB_HORZ
);
841 if(Window
->Style
& WS_VSCROLL
)
842 IntUpdateSBInfo(Window
, SB_VERT
);
844 if(Window
->Style
& WS_VISIBLE
)
846 /* Frame has been changed, let the window redraw itself */
847 WinPosSetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
848 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
| SWP_NOSENDCHANGING
);
852 IntReleaseWindowObject(Window
);