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.30 2004/04/17 11:00:14 weiden 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>
44 #include <include/tags.h>
52 #define MINTRACKTHUMB 8 /* Minimum size of the rectangle between the arrows */
54 #define SBRG_SCROLLBAR 0 /* the scrollbar itself */
55 #define SBRG_TOPRIGHTBTN 1 /* the top or right button */
56 #define SBRG_PAGEUPRIGHT 2 /* the page up or page right region */
57 #define SBRG_SCROLLBOX 3 /* the scroll box */
58 #define SBRG_PAGEDOWNLEFT 4 /* the page down or page left region */
59 #define SBRG_BOTTOMLEFTBTN 5 /* the bottom or left button */
61 #define CHANGERGSTATE(item, status) \
62 if(Info->rgstate[(item)] != (status)) \
64 Info->rgstate[(item)] = (status);
66 /* FUNCTIONS *****************************************************************/
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.
75 IntGetScrollBarRect (PWINDOW_OBJECT Window
, INT nBar
, PRECT lprect
)
78 RECT ClientRect
= Window
->ClientRect
;
79 RECT WindowRect
= Window
->WindowRect
;
84 lprect
->left
= ClientRect
.left
- WindowRect
.left
;
85 lprect
->top
= ClientRect
.bottom
- WindowRect
.top
;
86 lprect
->right
= ClientRect
.right
- WindowRect
.left
;
87 lprect
->bottom
= lprect
->top
+ NtUserGetSystemMetrics (SM_CYHSCROLL
);
92 lprect
->left
= ClientRect
.right
- WindowRect
.left
;
93 lprect
->top
= ClientRect
.top
- WindowRect
.top
;
94 lprect
->right
= lprect
->left
+ NtUserGetSystemMetrics(SM_CXVSCROLL
);
95 lprect
->bottom
= ClientRect
.bottom
- WindowRect
.top
;
100 IntGetClientRect (Window
, lprect
);
101 vertical
= ((Window
->Style
& SBS_VERT
) != 0);
105 IntReleaseWindowObject(Window
);
113 IntCalculateThumb(PWINDOW_OBJECT Window
, LONG idObject
, PSCROLLBARINFO psbi
, LPSCROLLINFO psi
)
115 INT Thumb
, ThumbBox
, ThumbPos
, cxy
, mx
;
121 Thumb
= NtUserGetSystemMetrics(SM_CXHSCROLL
);
122 cxy
= psbi
->rcScrollBar
.right
- psbi
->rcScrollBar
.left
;
125 Thumb
= NtUserGetSystemMetrics(SM_CYVSCROLL
);
126 cxy
= psbi
->rcScrollBar
.bottom
- psbi
->rcScrollBar
.top
;
129 IntGetClientRect (Window
, &ClientRect
);
130 if(Window
->Style
& SBS_VERT
)
132 Thumb
= NtUserGetSystemMetrics(SM_CYVSCROLL
);
133 cxy
= ClientRect
.bottom
- ClientRect
.top
;
137 Thumb
= NtUserGetSystemMetrics(SM_CXHSCROLL
);
138 cxy
= ClientRect
.right
- ClientRect
.left
;
146 /* calculate Thumb */
147 if(cxy
<= (2 * Thumb
))
150 psbi
->xyThumbTop
= 0;
151 psbi
->xyThumbBottom
= 0;
156 ThumbBox
= psi
->nPage
? MINTRACKTHUMB
: NtUserGetSystemMetrics(SM_CXHTHUMB
);
162 ThumbBox
= max(EngMulDiv(cxy
, psi
->nPage
, psi
->nMax
- psi
->nMin
+ 1), ThumbBox
);
167 mx
= psi
->nMax
- max(psi
->nPage
- 1, 0);
169 ThumbPos
= Thumb
+ EngMulDiv(cxy
- ThumbBox
, psi
->nPos
- psi
->nMin
, mx
- psi
->nMin
);
171 ThumbPos
= Thumb
+ ThumbBox
;
174 psbi
->xyThumbTop
= ThumbPos
;
175 psbi
->xyThumbBottom
= ThumbPos
+ ThumbBox
;
179 psbi
->xyThumbTop
= 0;
180 psbi
->xyThumbBottom
= 0;
183 psbi
->dxyLineButton
= Thumb
;
189 IntUpdateSBInfo(PWINDOW_OBJECT Window
, int wBar
)
195 ASSERT(Window
->Scroll
);
197 sbi
= IntGetScrollbarInfoFromWindow(Window
, wBar
);
198 psi
= IntGetScrollInfoFromWindow(Window
, wBar
);
199 IntGetScrollBarRect(Window
, wBar
, &(sbi
->rcScrollBar
));
200 IntCalculateThumb(Window
, wBar
, sbi
, psi
);
204 IntGetScrollInfo(PWINDOW_OBJECT Window
, INT nBar
, LPSCROLLINFO lpsi
)
209 if(!SBID_IS_VAILD(nBar
))
211 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
212 DPRINT1("Trying to get scrollinfo for unknown scrollbar type %d", nBar
);
216 if(!IntCreateScrollBars(Window
))
221 psi
= IntGetScrollInfoFromWindow(Window
, nBar
);
223 if (lpsi
->fMask
== SIF_ALL
)
225 Mask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
| SIF_TRACKPOS
;
232 if (0 != (Mask
& SIF_PAGE
))
234 lpsi
->nPage
= psi
->nPage
;
237 if (0 != (Mask
& SIF_POS
))
239 lpsi
->nPos
= psi
->nPos
;
242 if (0 != (Mask
& SIF_RANGE
))
244 lpsi
->nMin
= psi
->nMin
;
245 lpsi
->nMax
= psi
->nMax
;
248 if (0 != (Mask
& SIF_TRACKPOS
))
250 lpsi
->nTrackPos
= psi
->nTrackPos
;
256 static DWORD FASTCALL
257 IntSetScrollInfo(PWINDOW_OBJECT Window
, INT nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
)
260 * Update the scrollbar state and set action flags according to
261 * what has to be done graphics wise.
267 BOOL bChangeParams
= FALSE
; /* don't show/hide scrollbar if params don't change */
269 if(!SBID_IS_VAILD(nBar
))
271 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
272 DPRINT1("Trying to set scrollinfo for unknown scrollbar type %d", nBar
);
276 if(!IntCreateScrollBars(Window
))
281 if (lpsi
->cbSize
!= sizeof(SCROLLINFO
) &&
282 lpsi
->cbSize
!= (sizeof(SCROLLINFO
) - sizeof(lpsi
->nTrackPos
)))
284 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
287 if (lpsi
->fMask
& ~(SIF_ALL
| SIF_DISABLENOSCROLL
))
289 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
293 psbi
= IntGetScrollbarInfoFromWindow(Window
, nBar
);
294 Info
= IntGetScrollInfoFromWindow(Window
, nBar
);
296 /* Set the page size */
297 if (0 != (lpsi
->fMask
& SIF_PAGE
))
299 if (Info
->nPage
!= lpsi
->nPage
)
301 Info
->nPage
= lpsi
->nPage
;
302 bChangeParams
= TRUE
;
306 /* Set the scroll pos */
307 if (0 != (lpsi
->fMask
& SIF_POS
))
309 if (Info
->nPos
!= lpsi
->nPos
)
311 Info
->nPos
= lpsi
->nPos
;
315 /* Set the scroll range */
316 if (0 != (lpsi
->fMask
& SIF_RANGE
))
318 /* Invalid range -> range is set to (0,0) */
319 if (lpsi
->nMin
> lpsi
->nMax
||
320 0x80000000 <= (UINT
)(lpsi
->nMax
- lpsi
->nMin
))
324 bChangeParams
= TRUE
;
326 else if (Info
->nMin
!= lpsi
->nMin
|| Info
->nMax
!= lpsi
->nMax
)
328 Info
->nMin
= lpsi
->nMin
;
329 Info
->nMax
= lpsi
->nMax
;
330 bChangeParams
= TRUE
;
334 /* Make sure the page size is valid */
339 else if (Info
->nMax
- Info
->nMin
+ 1 < Info
->nPage
)
341 Info
->nPage
= Info
->nMax
- Info
->nMin
+ 1;
344 /* Make sure the pos is inside the range */
345 if (Info
->nPos
< Info
->nMin
)
347 Info
->nPos
= Info
->nMin
;
349 else if (Info
->nPos
> Info
->nMax
- max(Info
->nPage
- 1, 0))
351 Info
->nPos
= Info
->nMax
- max(Info
->nPage
- 1, 0);
355 * Don't change the scrollbar state if SetScrollInfo is just called
356 * with SIF_DISABLENOSCROLL
358 if (0 == (lpsi
->fMask
& SIF_ALL
))
363 /* Check if the scrollbar should be hidden or disabled */
364 if (0 != (lpsi
->fMask
& (SIF_RANGE
| SIF_PAGE
| SIF_DISABLENOSCROLL
)))
366 if (Info
->nMin
>= Info
->nMax
- max(Info
->nPage
- 1, 0))
368 /* Hide or disable scroll-bar */
369 if (0 != (lpsi
->fMask
& SIF_DISABLENOSCROLL
))
371 /* new_flags = ESB_DISABLE_BOTH;*/
373 else if ((nBar
!= SB_CTL
) && bChangeParams
)
375 NtUserShowScrollBar(Window
->Self
, nBar
, FALSE
);
379 else /* Show and enable scroll-bar */
382 if ((nBar
!= SB_CTL
) && bChangeParams
)
384 NtUserShowScrollBar(Window
->Self
, nBar
, TRUE
);
389 if (infoPtr
->flags
!= new_flags
) /* check arrow flags */
391 infoPtr
->flags
= new_flags
;
392 *Action
|= SA_SSI_REPAINT_ARROWS
;
399 RECT UpdateRect
= psbi
->rcScrollBar
;
400 UpdateRect
.left
-= Window
->ClientRect
.left
- Window
->WindowRect
.left
;
401 UpdateRect
.right
-= Window
->ClientRect
.left
- Window
->WindowRect
.left
;
402 UpdateRect
.top
-= Window
->ClientRect
.top
- Window
->WindowRect
.top
;
403 UpdateRect
.bottom
-= Window
->ClientRect
.top
- Window
->WindowRect
.top
;
404 IntRedrawWindow(Window
, &UpdateRect
, 0, RDW_INVALIDATE
| RDW_FRAME
);
407 /* Return current position */
412 IntGetScrollBarInfo(PWINDOW_OBJECT Window
, LONG idObject
, PSCROLLBARINFO psbi
)
418 Bar
= SBOBJ_TO_SBID(idObject
);
420 if(!SBID_IS_VAILD(Bar
))
422 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
423 DPRINT1("Trying to get scrollinfo for unknown scrollbar type %d", Bar
);
427 if(!IntCreateScrollBars(Window
))
432 sbi
= IntGetScrollbarInfoFromWindow(Window
, Bar
);
433 psi
= IntGetScrollInfoFromWindow(Window
, Bar
);
435 IntGetScrollBarRect(Window
, Bar
, &(sbi
->rcScrollBar
));
436 IntCalculateThumb(Window
, Bar
, sbi
, psi
);
438 RtlCopyMemory(psbi
, sbi
, sizeof(SCROLLBARINFO
));
444 IntCreateScrollBars(PWINDOW_OBJECT Window
)
454 /* no need to create it anymore */
458 /* allocate memory for all scrollbars (HORZ, VERT, CONTROL) */
459 Size
= 2 * (sizeof(WINDOW_SCROLLINFO
));
460 if(!(Window
->Scroll
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_SBARINFO
)))
462 DPRINT1("Unable to allocate memory for scrollbar information for window 0x%x\n", Window
->Self
);
466 RtlZeroMemory(Window
->Scroll
, Size
);
468 Result
= WinPosGetNonClientSize(Window
->Self
,
470 &Window
->ClientRect
);
472 for(s
= SB_HORZ
; s
<= SB_VERT
; s
++)
474 psbi
= IntGetScrollbarInfoFromWindow(Window
, s
);
475 psbi
->cbSize
= sizeof(SCROLLBARINFO
);
476 for (i
= 0; i
< CCHILDREN_SCROLLBAR
+ 1; i
++)
477 psbi
->rgstate
[i
] = 0;
479 psi
= IntGetScrollInfoFromWindow(Window
, s
);
480 psi
->cbSize
= sizeof(LPSCROLLINFO
);
483 IntGetScrollBarRect(Window
, s
, &(psbi
->rcScrollBar
));
484 IntCalculateThumb(Window
, s
, psbi
, psi
);
491 IntDestroyScrollBars(PWINDOW_OBJECT Window
)
495 ExFreePool(Window
->Scroll
);
496 Window
->Scroll
= NULL
;
503 IntEnableScrollBar(BOOL Horz
, PSCROLLBARINFO Info
, UINT wArrows
)
508 case ESB_DISABLE_BOTH
:
509 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
510 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
512 case ESB_DISABLE_RTDN
:
515 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
519 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
522 case ESB_DISABLE_LTUP
:
525 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, STATE_SYSTEM_UNAVAILABLE
);
529 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, STATE_SYSTEM_UNAVAILABLE
);
532 case ESB_ENABLE_BOTH
:
533 CHANGERGSTATE(SBRG_TOPRIGHTBTN
, 0);
534 CHANGERGSTATE(SBRG_BOTTOMLEFTBTN
, 0);
543 NtUserGetScrollBarInfo(HWND hWnd
, LONG idObject
, PSCROLLBARINFO psbi
)
547 PWINDOW_OBJECT Window
;
550 Status
= MmCopyFromCaller(&sbi
, psbi
, sizeof(SCROLLBARINFO
));
551 if(!NT_SUCCESS(Status
) || (sbi
.cbSize
!= sizeof(SCROLLBARINFO
)))
553 SetLastNtError(Status
);
557 Window
= IntGetWindowObject(hWnd
);
561 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
565 Ret
= IntGetScrollBarInfo(Window
, idObject
, &sbi
);
567 Status
= MmCopyToCaller(psbi
, &sbi
, sizeof(SCROLLBARINFO
));
568 if(!NT_SUCCESS(Status
))
570 SetLastNtError(Status
);
573 IntReleaseWindowObject(Window
);
580 NtUserGetScrollInfo(HWND hwnd
, int fnBar
, LPSCROLLINFO lpsi
)
583 PWINDOW_OBJECT Window
;
588 Status
= MmCopyFromCaller(&psi
.cbSize
, &(lpsi
->cbSize
), sizeof(UINT
));
589 if(!NT_SUCCESS(Status
) ||
590 !((psi
.cbSize
== sizeof(SCROLLINFO
)) || (psi
.cbSize
== sizeof(SCROLLINFO
) - sizeof(psi
.nTrackPos
))))
592 SetLastNtError(Status
);
596 Status
= MmCopyFromCaller(&psi
, lpsi
, sz
);
597 if (!NT_SUCCESS(Status
))
599 SetLastNtError(Status
);
603 Window
= IntGetWindowObject(hwnd
);
607 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
613 IntSendMessage(Window
->Self
, SBM_GETSCROLLINFO
, 0, (LPARAM
)lpsi
);
617 Ret
= IntGetScrollInfo(Window
, fnBar
, &psi
);
619 IntReleaseWindowObject(Window
);
621 Status
= MmCopyToCaller(lpsi
, &psi
, sz
);
622 if(!NT_SUCCESS(Status
))
624 SetLastNtError(Status
);
634 NtUserEnableScrollBar(
639 PWINDOW_OBJECT Window
;
640 PSCROLLBARINFO InfoV
= NULL
, InfoH
= NULL
;
643 Window
= IntGetWindowObject(hWnd
);
647 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
651 if(wSBflags
== SB_CTL
)
654 IntReleaseWindowObject(Window
);
658 if(wSBflags
!= SB_BOTH
&& !SBID_IS_VAILD(wSBflags
))
660 IntReleaseWindowObject(Window
);
661 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
662 DPRINT1("Trying to set scrollinfo for unknown scrollbar type %d", wSBflags
);
666 if(!IntCreateScrollBars(Window
))
668 IntReleaseWindowObject(Window
);
675 InfoV
= IntGetScrollbarInfoFromWindow(Window
, SB_VERT
);
678 InfoH
= IntGetScrollbarInfoFromWindow(Window
, SB_HORZ
);
681 InfoV
= IntGetScrollbarInfoFromWindow(Window
, SB_VERT
);
684 IntReleaseWindowObject(Window
);
689 Chg
= IntEnableScrollBar(FALSE
, InfoV
, wArrows
);
692 Chg
= (IntEnableScrollBar(TRUE
, InfoH
, wArrows
) || Chg
);
694 //if(Chg && (Window->Style & WS_VISIBLE))
695 /* FIXME - repaint scrollbars */
697 IntReleaseWindowObject(Window
);
703 NtUserSetScrollBarInfo(
706 SETSCROLLBARINFO
*info
)
708 PWINDOW_OBJECT Window
;
709 SETSCROLLBARINFO Safeinfo
;
715 Window
= IntGetWindowObject(hwnd
);
719 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
723 Obj
= SBOBJ_TO_SBID(idObject
);
724 if(!SBID_IS_VAILD(Obj
))
726 IntReleaseWindowObject(Window
);
727 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
728 DPRINT1("Trying to set scrollinfo for unknown scrollbar type %d", Obj
);
732 if(!IntCreateScrollBars(Window
))
734 IntReleaseWindowObject(Window
);
738 Status
= MmCopyFromCaller(&Safeinfo
, info
, sizeof(SETSCROLLBARINFO
));
739 if(!NT_SUCCESS(Status
))
741 IntReleaseWindowObject(Window
);
742 SetLastNtError(Status
);
746 sbi
= IntGetScrollbarInfoFromWindow(Window
, Obj
);
747 psi
= IntGetScrollInfoFromWindow(Window
, Obj
);
749 psi
->nTrackPos
= Safeinfo
.nTrackPos
;
750 sbi
->reserved
= Safeinfo
.reserved
;
751 RtlCopyMemory(&sbi
->rgstate
, &Safeinfo
.rgstate
, sizeof(Safeinfo
.rgstate
));
753 IntReleaseWindowObject(Window
);
765 PWINDOW_OBJECT Window
;
767 SCROLLINFO ScrollInfo
;
770 Window
= IntGetWindowObject(hwnd
);
774 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
780 Ret
= IntSendMessage(hwnd
, SBM_SETSCROLLINFO
, (WPARAM
)bRedraw
, (LPARAM
)lpsi
);
781 IntReleaseWindowObject(Window
);
785 Status
= MmCopyFromCaller(&ScrollInfo
, lpsi
, sizeof(SCROLLINFO
) - sizeof(ScrollInfo
.nTrackPos
));
786 if(!NT_SUCCESS(Status
))
788 IntReleaseWindowObject(Window
);
789 SetLastNtError(Status
);
793 Ret
= IntSetScrollInfo(Window
, fnBar
, &ScrollInfo
, bRedraw
);
794 IntReleaseWindowObject(Window
);
799 /* Ported from WINE20020904 (SCROLL_ShowScrollBar) */
801 NtUserShowScrollBar(HWND hWnd
, int wBar
, DWORD bShow
)
803 DWORD Style
, OldStyle
;
804 PWINDOW_OBJECT Window
= IntGetWindowObject(hWnd
);
808 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
821 Style
= WS_HSCROLL
| WS_VSCROLL
;
826 IntReleaseWindowObject(Window
);
827 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
831 if(!IntCreateScrollBars(Window
))
833 IntReleaseWindowObject(Window
);
839 IntUpdateSBInfo(Window
, SB_CTL
);
841 WinPosShowWindow(hWnd
, bShow
? SW_SHOW
: SW_HIDE
);
842 IntReleaseWindowObject(Window
);
846 OldStyle
= Window
->Style
;
848 Window
->Style
|= Style
;
850 Window
->Style
&= ~Style
;
852 if(Window
->Style
!= OldStyle
)
854 if(Window
->Style
& WS_HSCROLL
)
855 IntUpdateSBInfo(Window
, SB_HORZ
);
856 if(Window
->Style
& WS_VSCROLL
)
857 IntUpdateSBInfo(Window
, SB_VERT
);
859 if(Window
->Style
& WS_VISIBLE
)
861 /* Frame has been changed, let the window redraw itself */
862 WinPosSetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
863 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
| SWP_NOSENDCHANGING
);
867 IntReleaseWindowObject(Window
);