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.
19 /* $Id: scrollbar.c,v 1.25 2004/01/13 17:14:38 navaraf Exp $
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 ******************************************************************/
32 #include <ddk/ntddk.h>
33 #include <win32k/win32k.h>
34 #include <internal/safe.h>
35 #include <include/object.h>
36 #include <include/window.h>
37 #include <include/class.h>
38 #include <include/error.h>
39 #include <include/winsta.h>
40 #include <include/winpos.h>
41 #include <include/rect.h>
42 #include <include/scroll.h>
43 #include <include/painting.h>
48 #define MINTRACKTHUMB 8 /* Minimum size of the rectangle between the arrows */
50 #define SBRG_SCROLLBAR 0 /* the scrollbar itself */
51 #define SBRG_TOPRIGHTBTN 1 /* the top or right button */
52 #define SBRG_PAGEUPRIGHT 2 /* the page up or page right region */
53 #define SBRG_SCROLLBOX 3 /* the scroll box */
54 #define SBRG_PAGEDOWNLEFT 4 /* the page down or page left region */
55 #define SBRG_BOTTOMLEFTBTN 5 /* the bottom or left button */
57 /* FUNCTIONS *****************************************************************/
59 /* Ported from WINE20020904 */
60 /* Compute the scroll bar rectangle, in drawing coordinates (i.e. client coords for SB_CTL, window coords for SB_VERT and
61 * SB_HORZ). 'arrowSize' returns the width or height of an arrow (depending on * the orientation of the scrollbar),
62 * 'thumbSize' returns the size of the thumb, and 'thumbPos' returns the position of the thumb relative to the left or to
63 * the top. Return TRUE if the scrollbar is vertical, FALSE if horizontal.
66 IntGetScrollBarRect (PWINDOW_OBJECT Window
, INT nBar
, PRECT lprect
)
69 RECT ClientRect
= Window
->ClientRect
;
70 RECT WindowRect
= Window
->WindowRect
;
75 lprect
->left
= ClientRect
.left
- WindowRect
.left
;
76 lprect
->top
= ClientRect
.bottom
- WindowRect
.top
;
77 lprect
->right
= ClientRect
.right
- WindowRect
.left
;
78 lprect
->bottom
= lprect
->top
+ NtUserGetSystemMetrics (SM_CYHSCROLL
);
83 lprect
->left
= ClientRect
.right
- WindowRect
.left
;
84 lprect
->top
= ClientRect
.top
- WindowRect
.top
;
85 lprect
->right
= lprect
->left
+ NtUserGetSystemMetrics(SM_CXVSCROLL
);
86 lprect
->bottom
= ClientRect
.bottom
- WindowRect
.top
;
91 IntGetClientRect (Window
, lprect
);
92 vertical
= ((Window
->Style
& SBS_VERT
) != 0);
96 IntReleaseWindowObject(Window
);
104 IntCalculateThumb(PWINDOW_OBJECT Window
, LONG idObject
, PSCROLLBARINFO psbi
, LPSCROLLINFO psi
)
106 INT Thumb
, ThumbBox
, ThumbPos
, cxy
, mx
;
112 Thumb
= NtUserGetSystemMetrics(SM_CXHSCROLL
);
113 cxy
= psbi
->rcScrollBar
.right
- psbi
->rcScrollBar
.left
;
116 Thumb
= NtUserGetSystemMetrics(SM_CYVSCROLL
);
117 cxy
= psbi
->rcScrollBar
.bottom
- psbi
->rcScrollBar
.top
;
120 IntGetClientRect (Window
, &ClientRect
);
121 if(Window
->Style
& SBS_VERT
)
123 Thumb
= NtUserGetSystemMetrics(SM_CYVSCROLL
);
124 cxy
= ClientRect
.bottom
- ClientRect
.top
;
128 Thumb
= NtUserGetSystemMetrics(SM_CXHSCROLL
);
129 cxy
= ClientRect
.right
- ClientRect
.left
;
137 /* calculate Thumb */
138 if(cxy
<= (2 * Thumb
))
141 psbi
->xyThumbTop
= 0;
142 psbi
->xyThumbBottom
= 0;
147 ThumbBox
= psi
->nPage
? MINTRACKTHUMB
: NtUserGetSystemMetrics(SM_CXHTHUMB
);
153 ThumbBox
= max(EngMulDiv(cxy
, psi
->nPage
, psi
->nMax
- psi
->nMin
+ 1), ThumbBox
);
158 mx
= psi
->nMax
- max(psi
->nPage
- 1, 0);
160 ThumbPos
= Thumb
+ EngMulDiv(cxy
- ThumbBox
, psi
->nPos
- psi
->nMin
, mx
- psi
->nMin
);
162 ThumbPos
= Thumb
+ ThumbBox
;
165 psbi
->xyThumbTop
= ThumbPos
;
166 psbi
->xyThumbBottom
= ThumbPos
+ ThumbBox
;
170 psbi
->xyThumbTop
= 0;
171 psbi
->xyThumbBottom
= 0;
174 psbi
->dxyLineButton
= Thumb
;
180 IntGetScrollInfo(PWINDOW_OBJECT Window
, INT nBar
, LPSCROLLINFO lpsi
)
189 Info
= Window
->pHScroll
;
194 Info
= Window
->pVScroll
;
200 Send a SBM_GETSCROLLINFO message to the window. Fail if the window
201 doesn't handle the message
205 Info
= Window
->wExtra
;
213 psi
= (LPSCROLLINFO
)((PSCROLLBARINFO
)(Info
+ 1));
215 if(lpsi
->fMask
== SIF_ALL
)
216 Mask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
| SIF_TRACKPOS
;
222 lpsi
->nPage
= psi
->nPage
;
227 lpsi
->nPos
= psi
->nPos
;
232 lpsi
->nMin
= psi
->nMin
;
233 lpsi
->nMax
= psi
->nMax
;
240 IntSetScrollInfo(PWINDOW_OBJECT Window
, INT nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
)
243 * Update the scrollbar state and set action flags according to
244 * what has to be done graphics wise.
250 BOOL bChangeParams
= FALSE
; /* don't show/hide scrollbar if params don't change */
252 if (lpsi
->cbSize
!= sizeof(SCROLLINFO
) &&
253 lpsi
->cbSize
!= (sizeof(SCROLLINFO
) - sizeof(lpsi
->nTrackPos
)))
255 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
258 if (lpsi
->fMask
& ~(SIF_ALL
| SIF_DISABLENOSCROLL
))
260 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
266 if (Window
->pHScroll
== NULL
)
268 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
271 psbi
= Window
->pHScroll
;
272 Info
= (LPSCROLLINFO
)(Window
->pHScroll
+ 1);
275 if (Window
->pVScroll
== NULL
)
277 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
280 psbi
= Window
->pVScroll
;
281 Info
= (LPSCROLLINFO
)(Window
->pVScroll
+ 1);
287 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
291 /* Set the page size */
292 if (lpsi
->fMask
& SIF_PAGE
)
294 if (Info
->nPage
!= lpsi
->nPage
)
296 Info
->nPage
= lpsi
->nPage
;
298 *Action
|= SA_SSI_REFRESH
;
300 bChangeParams
= TRUE
;
304 /* Set the scroll pos */
305 if (lpsi
->fMask
& SIF_POS
)
307 if (Info
->nPos
!= lpsi
->nPos
)
309 Info
->nPos
= lpsi
->nPos
;
311 *Action
|= SA_SSI_REFRESH
;
316 /* Set the scroll range */
317 if (lpsi
->fMask
& SIF_RANGE
)
319 /* Invalid range -> range is set to (0,0) */
320 if (lpsi
->nMin
> lpsi
->nMax
||
321 (UINT
)(lpsi
->nMax
- lpsi
->nMin
) >= 0x80000000)
325 bChangeParams
= TRUE
;
329 if (Info
->nMin
!= lpsi
->nMin
|| Info
->nMax
!= lpsi
->nMax
)
332 *Action
|= SA_SSI_REFRESH
;
334 Info
->nMin
= lpsi
->nMin
;
335 Info
->nMax
= lpsi
->nMax
;
336 bChangeParams
= TRUE
;
341 /* Make sure the page size is valid */
346 else if (Info
->nPage
> Info
->nMax
- Info
->nMin
+ 1)
348 Info
->nPage
= Info
->nMax
- Info
->nMin
+ 1;
351 /* Make sure the pos is inside the range */
352 if (Info
->nPos
< Info
->nMin
)
354 Info
->nPos
= Info
->nMin
;
356 else if (Info
->nPos
> Info
->nMax
- max(Info
->nPage
- 1, 0))
358 Info
->nPos
= Info
->nMax
- max(Info
->nPage
- 1, 0);
362 * Don't change the scrollbar state if SetScrollInfo is just called
363 * with SIF_DISABLENOSCROLL
365 if (!(lpsi
->fMask
& SIF_ALL
))
370 /* Check if the scrollbar should be hidden or disabled */
371 if (lpsi
->fMask
& (SIF_RANGE
| SIF_PAGE
| SIF_DISABLENOSCROLL
))
373 /* new_flags = Info->flags;*/
374 if (Info
->nMin
>= Info
->nMax
- max(Info
->nPage
- 1, 0))
376 /* Hide or disable scroll-bar */
377 if (lpsi
->fMask
& SIF_DISABLENOSCROLL
)
379 /* new_flags = ESB_DISABLE_BOTH;*/
381 *Action
|= SA_SSI_REFRESH
;
384 else if ((nBar
!= SB_CTL
) && bChangeParams
)
386 NtUserShowScrollBar(Window
->Self
, nBar
, FALSE
);
390 else /* Show and enable scroll-bar */
393 if ((nBar
!= SB_CTL
) && bChangeParams
)
394 NtUserShowScrollBar(Window
->Self
, nBar
, TRUE
);
398 if (infoPtr
->flags
!= new_flags
) /* check arrow flags */
400 infoPtr
->flags
= new_flags
;
401 *Action
|= SA_SSI_REPAINT_ARROWS
;
408 RECT UpdateRect
= psbi
->rcScrollBar
;
409 UpdateRect
.left
-= Window
->ClientRect
.left
- Window
->WindowRect
.left
;
410 UpdateRect
.right
-= Window
->ClientRect
.left
- Window
->WindowRect
.left
;
411 UpdateRect
.top
-= Window
->ClientRect
.top
- Window
->WindowRect
.top
;
412 UpdateRect
.bottom
-= Window
->ClientRect
.top
- Window
->WindowRect
.top
;
413 IntRedrawWindow(Window
, &UpdateRect
, 0, RDW_INVALIDATE
| RDW_FRAME
);
416 /* Return current position */
421 IntGetScrollBarInfo(PWINDOW_OBJECT Window
, LONG idObject
, PSCROLLBARINFO psbi
)
433 sbi
= Window
->pHScroll
;
441 sbi
= Window
->pVScroll
;
448 Send a SBM_GETSCROLLBARINFO message if Window is not a system scrollbar.
449 If the window doesn't handle the message return FALSE.
456 sbi
= Window
->wExtra
;
461 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
465 psi
= (LPSCROLLINFO
)((PSCROLLBARINFO
)(sbi
+ 1));
467 IntGetScrollBarRect(Window
, Bar
, &(sbi
->rcScrollBar
));
468 IntCalculateThumb(Window
, Bar
, sbi
, psi
);
470 RtlCopyMemory(psbi
, sbi
, sizeof(SCROLLBARINFO
));
476 IntCreateScrollBar(PWINDOW_OBJECT Window
, LONG idObject
)
483 psbi
= ExAllocatePool(PagedPool
, sizeof(SCROLLBARINFO
) + sizeof(SCROLLINFO
));
487 psi
= (LPSCROLLINFO
)((PSCROLLBARINFO
)(psbi
+ 1));
489 psi
->cbSize
= sizeof(LPSCROLLINFO
);
496 Result
= WinPosGetNonClientSize(Window
->Self
,
498 &Window
->ClientRect
);
500 psbi
->cbSize
= sizeof(SCROLLBARINFO
);
502 for (i
= 0; i
< CCHILDREN_SCROLLBAR
+ 1; i
++)
503 psbi
->rgstate
[i
] = 0;
508 Window
->pHScroll
= psbi
;
511 Window
->pVScroll
= psbi
;
514 Window
->wExtra
= psbi
;
521 IntGetScrollBarRect(Window
, idObject
, &(psbi
->rcScrollBar
));
522 IntCalculateThumb(Window
, idObject
, psbi
, psi
);
528 IntDestroyScrollBar(PWINDOW_OBJECT Window
, LONG idObject
)
535 ExFreePool(Window
->pHScroll
);
536 Window
->pHScroll
= NULL
;
543 ExFreePool(Window
->pVScroll
);
544 Window
->pVScroll
= NULL
;
551 ExFreePool(Window
->wExtra
);
552 Window
->wExtra
= NULL
;
560 #define CHANGERGSTATE(item, status) \
561 if(Info->rgstate[(item)] != (status)) \
563 Info->rgstate[(item)] = (status);
567 IntEnableScrollBar(BOOL Horz
, PSCROLLBARINFO Info
, UINT wArrows
)
572 case ESB_DISABLE_BOTH
:
573 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
574 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
576 case ESB_DISABLE_RTDN
:
579 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
583 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
586 case ESB_DISABLE_LTUP
:
589 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
593 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
596 case ESB_ENABLE_BOTH
:
597 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, 0);
598 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, 0);
607 NtUserGetScrollBarInfo(HWND hWnd
, LONG idObject
, PSCROLLBARINFO psbi
)
611 PWINDOW_OBJECT Window
;
614 Status
= MmCopyFromCaller(&sbi
, psbi
, sizeof(SCROLLBARINFO
));
615 if(!NT_SUCCESS(Status
) || (sbi
.cbSize
!= sizeof(SCROLLBARINFO
)))
617 SetLastNtError(Status
);
621 Window
= IntGetWindowObject(hWnd
);
625 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
629 Ret
= IntGetScrollBarInfo(Window
, idObject
, &sbi
);
631 Status
= MmCopyToCaller(psbi
, &sbi
, sizeof(SCROLLBARINFO
));
632 if(!NT_SUCCESS(Status
))
634 SetLastNtError(Status
);
637 IntReleaseWindowObject(Window
);
644 NtUserGetScrollInfo(HWND hwnd
, int fnBar
, LPSCROLLINFO lpsi
)
647 PWINDOW_OBJECT Window
;
652 Status
= MmCopyFromCaller(&psi
, lpsi
, sizeof(SCROLLINFO
) - sizeof(psi
.nTrackPos
));
653 if(!NT_SUCCESS(Status
) ||
654 !((psi
.cbSize
== sizeof(SCROLLINFO
)) || (psi
.cbSize
== sizeof(SCROLLINFO
) - sizeof(psi
.nTrackPos
))))
656 SetLastNtError(Status
);
661 Window
= IntGetWindowObject(hwnd
);
665 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
669 Ret
= IntGetScrollInfo(Window
, fnBar
, &psi
);
671 IntReleaseWindowObject(Window
);
673 Status
= MmCopyToCaller(lpsi
, &psi
, sz
);
674 if(!NT_SUCCESS(Status
))
676 SetLastNtError(Status
);
686 NtUserEnableScrollBar(
691 PWINDOW_OBJECT Window
;
692 PSCROLLBARINFO InfoV
= NULL
, InfoH
= NULL
;
695 Window
= IntGetWindowObject(hWnd
);
699 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
706 InfoV
= Window
->pVScroll
;
709 InfoH
= Window
->pHScroll
;
712 InfoV
= Window
->pVScroll
;
715 InfoV
= Window
->wExtra
;
718 IntReleaseWindowObject(Window
);
723 Chg
= IntEnableScrollBar(FALSE
, InfoV
, wArrows
);
726 Chg
= (IntEnableScrollBar(TRUE
, InfoH
, wArrows
) || Chg
);
728 //if(Chg && (Window->Style & WS_VISIBLE))
729 /* FIXME - repaint scrollbars */
731 IntReleaseWindowObject(Window
);
737 NtUserSetScrollBarInfo(
740 SETSCROLLBARINFO
*info
)
742 PWINDOW_OBJECT Window
;
743 SETSCROLLBARINFO Safeinfo
;
744 PSCROLLBARINFO sbi
= NULL
;
748 Window
= IntGetWindowObject(hwnd
);
752 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
756 Status
= MmCopyFromCaller(&Safeinfo
, info
, sizeof(SETSCROLLBARINFO
));
757 if(!NT_SUCCESS(Status
))
759 IntReleaseWindowObject(Window
);
760 SetLastNtError(Status
);
767 sbi
= Window
->pHScroll
;
770 sbi
= Window
->pVScroll
;
774 IntReleaseWindowObject(Window
);
778 IntReleaseWindowObject(Window
);
779 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
785 DPRINT1("SCROLLBARINFO structure not allocated!\n");
786 IntReleaseWindowObject(Window
);
790 psi
= (LPSCROLLINFO
)((PSCROLLBARINFO
)(sbi
+ 1));
792 psi
->nTrackPos
= Safeinfo
.nTrackPos
;
793 sbi
->reserved
= Safeinfo
.reserved
;
794 RtlCopyMemory(&sbi
->rgstate
, &Safeinfo
.rgstate
, sizeof(Safeinfo
.rgstate
));
796 IntReleaseWindowObject(Window
);
808 PWINDOW_OBJECT Window
;
810 SCROLLINFO ScrollInfo
;
813 Window
= IntGetWindowObject(hwnd
);
817 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
821 Status
= MmCopyFromCaller(&ScrollInfo
, lpsi
, sizeof(SCROLLINFO
) - sizeof(ScrollInfo
.nTrackPos
));
822 if(!NT_SUCCESS(Status
))
824 IntReleaseWindowObject(Window
);
825 SetLastNtError(Status
);
829 Ret
= IntSetScrollInfo(Window
, fnBar
, &ScrollInfo
, bRedraw
);
830 IntReleaseWindowObject(Window
);
835 /* Ported from WINE20020904 (SCROLL_ShowScrollBar) */
837 NtUserShowScrollBar(HWND hWnd
, int wBar
, DWORD bShow
)
839 PWINDOW_OBJECT Window
= IntGetWindowObject(hWnd
);
843 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
849 WinPosShowWindow(hWnd
, bShow
? SW_SHOW
: SW_HIDE
);
850 IntReleaseWindowObject(Window
);
854 if (wBar
== SB_BOTH
|| wBar
== SB_HORZ
)
858 Window
->Style
|= WS_HSCROLL
;
859 if (!Window
->pHScroll
)
860 IntCreateScrollBar(Window
, SB_HORZ
);
864 Window
->Style
&= ~WS_HSCROLL
;
868 if (wBar
== SB_BOTH
|| wBar
== SB_VERT
)
872 Window
->Style
|= WS_VSCROLL
;
873 if (!Window
->pVScroll
)
874 IntCreateScrollBar(Window
, SB_VERT
);
878 Window
->Style
&= ~WS_VSCROLL
;
882 /* Frame has been changed, let the window redraw itself */
883 WinPosSetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
884 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
| SWP_NOSENDCHANGING
);
886 IntReleaseWindowObject(Window
);